Branch data Line data Source code
1 : : /*
2 : : * Copyright (C) 2026 by Thun Lu. All rights reserved.
3 : : * Author: Thun Lu <thun.lu@zohomail.cn>
4 : : * Repo: https://github.com/thun-res/vlink
5 : : * _ __ __ _ __
6 : : * | | / / / / (_) ____ / /__
7 : : * | | / / / / / / / __ \ / //_/
8 : : * | |/ / / /___ / / / / / / / ,<
9 : : * |___/ /_____/ /_/ /_/ /_/ /_/|_|
10 : : *
11 : : * Licensed under the Apache License, Version 2.0 (the "License");
12 : : * you may not use this file except in compliance with the License.
13 : : * You may obtain a copy of the License at
14 : : *
15 : : * http://www.apache.org/licenses/LICENSE-2.0
16 : : *
17 : : * Unless required by applicable law or agreed to in writing, software
18 : : * distributed under the License is distributed on an "AS IS" BASIS,
19 : : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 : : * See the License for the specific language governing permissions and
21 : : * limitations under the License.
22 : : */
23 : :
24 : : #include "./zerocopy/proxy_data.h"
25 : :
26 : : #include <cstdint>
27 : : #include <limits>
28 : : #include <string_view>
29 : :
30 : : #include "./zerocopy/header.h"
31 : :
32 : : namespace vlink {
33 : :
34 : : namespace zerocopy {
35 : :
36 : : // ProxyData
37 : 65 : ProxyData::ProxyData() noexcept {
38 : : #if defined(__arm__) || defined(__x86__) || defined(__i386__)
39 : : #ifndef __ANDROID__
40 : : #warning "[ProxyData] No support for 32-bit architecture."
41 : : #endif
42 : : #else
43 : : static_assert(sizeof(ProxyData) == 80, "Sizeof must be 80 bytes.");
44 : : #endif
45 : 65 : }
46 : :
47 : 68 : ProxyData::~ProxyData() noexcept {
48 [ + + + - : 68 : if (is_owner_ && data_ && size_ != 0) {
+ - ]
49 : 41 : Bytes::bytes_free(data_, size_);
50 : : }
51 : 68 : }
52 : :
53 : 2 : ProxyData::ProxyData(const ProxyData& target) noexcept { deep_copy(target); }
54 : :
55 : 1 : ProxyData::ProxyData(ProxyData&& target) noexcept { move_copy(target); }
56 : :
57 : 2 : ProxyData& ProxyData::operator=(const ProxyData& target) noexcept {
58 [ + + ]: 2 : if VUNLIKELY (this == &target) {
59 : 1 : return *this;
60 : : }
61 : :
62 : 1 : deep_copy(target);
63 : :
64 : 1 : return *this;
65 : : }
66 : :
67 : 2 : ProxyData& ProxyData::operator=(ProxyData&& target) noexcept {
68 [ + + ]: 2 : if VUNLIKELY (this == &target) {
69 : 1 : return *this;
70 : : }
71 : :
72 : 1 : move_copy(target);
73 : :
74 : 1 : return *this;
75 : : }
76 : :
77 : 16 : bool ProxyData::operator<<(const Bytes& bytes) noexcept {
78 : : static constexpr size_t kMagicNumberBeginSize = sizeof(kMagicNumberBegin);
79 : : static constexpr size_t kVersionSize = sizeof(kWireVersion);
80 : : // static constexpr size_t kMagicNumberEndSize = sizeof(kMagicNumberEnd);
81 : :
82 [ + + ]: 16 : if VUNLIKELY (bytes.empty()) {
83 : 1 : return false;
84 : : }
85 : :
86 [ + + ]: 15 : if VUNLIKELY (!check_valid(bytes)) {
87 : 1 : return false;
88 : : }
89 : :
90 : 14 : uint32_t wire_version = 0;
91 : 14 : std::memcpy(&wire_version, bytes.data() + kMagicNumberBeginSize, kVersionSize);
92 : :
93 [ - + ]: 14 : if VUNLIKELY (version_major(wire_version) != version_major(kWireVersion)) {
94 : 0 : return false;
95 : : }
96 : :
97 [ + + + - : 14 : if (is_owner_ && data_ && size_ != 0) {
+ - ]
98 : 1 : Bytes::bytes_free(data_, size_);
99 : : }
100 : :
101 : : #if defined(__GNUC__) && !defined(__clang__)
102 : : #pragma GCC diagnostic push
103 : : #pragma GCC diagnostic ignored "-Wclass-memaccess"
104 : : #if __GNUC__ >= 11
105 : : #pragma GCC diagnostic ignored "-Wstringop-overread"
106 : : #endif
107 : : #endif
108 : :
109 : 14 : auto* target_ptr = reinterpret_cast<uint8_t*>(this);
110 : :
111 : 14 : std::memcpy(target_ptr, bytes.data() + kMagicNumberBeginSize + kVersionSize, sizeof(ProxyData));
112 : :
113 : : #if defined(__GNUC__) && !defined(__clang__)
114 : : #pragma GCC diagnostic pop
115 : : #endif
116 : :
117 : 14 : data_ = const_cast<uint8_t*>(bytes.data() + kMagicNumberBeginSize + kVersionSize + sizeof(ProxyData));
118 : 14 : is_owner_ = false;
119 : :
120 [ + + ]: 14 : if VUNLIKELY (bytes.size() != get_serialized_size()) {
121 : 1 : clear();
122 : 1 : return false;
123 : : }
124 : :
125 [ + + ]: 13 : if VUNLIKELY (static_cast<uint64_t>(data_pos_) + data_size_ != url_pos_) {
126 : 1 : clear();
127 : 1 : return false;
128 : : }
129 : :
130 [ + + ]: 12 : if VUNLIKELY (static_cast<uint64_t>(url_pos_) + url_size_ != ser_pos_) {
131 : 1 : clear();
132 : 1 : return false;
133 : : }
134 : :
135 [ + + ]: 11 : if VUNLIKELY (static_cast<uint64_t>(ser_pos_) + ser_size_ != hostname_pos_) {
136 : 1 : clear();
137 : 1 : return false;
138 : : }
139 : :
140 [ + + ]: 10 : if VUNLIKELY (static_cast<uint64_t>(hostname_pos_) + hostname_size_ != size_) {
141 : 1 : clear();
142 : 1 : return false;
143 : : }
144 : :
145 : 9 : return true;
146 : : }
147 : :
148 : 19 : bool ProxyData::operator>>(Bytes& bytes) const noexcept {
149 : : static constexpr size_t kMagicNumberBeginSize = sizeof(kMagicNumberBegin);
150 : : static constexpr size_t kVersionSize = sizeof(kWireVersion);
151 : : static constexpr size_t kMagicNumberEndSize = sizeof(kMagicNumberEnd);
152 : :
153 [ + + - + : 19 : if (bytes.empty() || bytes.size() != get_serialized_size()) {
+ + ]
154 : 18 : bytes = Bytes::create(get_serialized_size());
155 : : }
156 : :
157 : 19 : std::memcpy(bytes.data(), &kMagicNumberBegin, kMagicNumberBeginSize);
158 : :
159 : 19 : std::memcpy(bytes.data() + kMagicNumberBeginSize, &kWireVersion, kVersionSize);
160 : :
161 : : // NOLINTNEXTLINE(bugprone-undefined-memory-manipulation)
162 : 19 : std::memcpy(bytes.data() + kMagicNumberBeginSize + kVersionSize, this, sizeof(ProxyData));
163 : :
164 [ + - + - : 19 : if VLIKELY (data_ != nullptr && size_ != 0) {
+ - ]
165 : 19 : std::memcpy(bytes.data() + kMagicNumberBeginSize + kVersionSize + sizeof(ProxyData), data_, size_);
166 : : }
167 : :
168 : 19 : std::memcpy(bytes.data() + kMagicNumberBeginSize + kVersionSize + sizeof(ProxyData) + size_, &kMagicNumberEnd,
169 : : kMagicNumberEndSize);
170 : :
171 : 19 : return true;
172 : : }
173 : :
174 : 5 : uint32_t ProxyData::control_id() const noexcept { return control_id_; }
175 : :
176 : 3 : uint32_t ProxyData::mode() const noexcept { return mode_; }
177 : :
178 : 3 : int64_t ProxyData::timestamp() const noexcept { return timestamp_; }
179 : :
180 : 3 : int64_t ProxyData::seq() const noexcept { return seq_; }
181 : :
182 : 17 : uint32_t ProxyData::schema() const noexcept { return schema_; }
183 : :
184 : 3 : Bytes ProxyData::raw() const noexcept {
185 [ + + - + : 3 : if VUNLIKELY (!data_ || size_ == 0 || data_size_ == 0) {
+ + - + +
+ ]
186 : 1 : return Bytes();
187 : : }
188 : :
189 : 2 : return Bytes::shallow_copy(data_ + data_pos_, data_size_);
190 : : }
191 : :
192 : 21 : std::string_view ProxyData::url() const noexcept {
193 [ + + - + : 21 : if VUNLIKELY (!data_ || size_ == 0 || url_size_ == 0) {
+ + - + +
+ ]
194 : 2 : return std::string_view();
195 : : }
196 : :
197 : 19 : return std::string_view(reinterpret_cast<char*>(data_) + url_pos_, url_size_);
198 : : }
199 : :
200 : 9 : std::string_view ProxyData::ser() const noexcept {
201 [ + + - + : 9 : if VUNLIKELY (!data_ || size_ == 0 || ser_size_ == 0) {
+ + - + +
+ ]
202 : 2 : return std::string_view();
203 : : }
204 : :
205 : 7 : return std::string_view(reinterpret_cast<char*>(data_) + ser_pos_, ser_size_);
206 : : }
207 : :
208 : 16 : std::string_view ProxyData::hostname() const noexcept {
209 [ + + - + : 16 : if VUNLIKELY (!data_ || size_ == 0 || hostname_size_ == 0) {
+ + + + +
+ ]
210 : 3 : return std::string_view();
211 : : }
212 : :
213 : 13 : return std::string_view(reinterpret_cast<char*>(data_) + hostname_pos_, hostname_size_);
214 : : }
215 : :
216 : 5 : void ProxyData::set_control_id(uint32_t control_id) noexcept { control_id_ = control_id; }
217 : :
218 : 2 : void ProxyData::set_mode(uint32_t mode) noexcept { mode_ = mode; }
219 : :
220 : 3 : void ProxyData::set_timestamp(int64_t timestamp) noexcept { timestamp_ = timestamp; }
221 : :
222 : 2 : void ProxyData::set_seq(int64_t seq) noexcept { seq_ = seq; }
223 : :
224 : 1 : void ProxyData::set_schema(uint32_t schema) noexcept { schema_ = schema; }
225 : :
226 : 22 : bool ProxyData::check_valid(const Bytes& bytes) noexcept {
227 : : static constexpr size_t kMagicNumberBeginSize = sizeof(kMagicNumberBegin);
228 : : static constexpr size_t kVersionSize = sizeof(kWireVersion);
229 : : static constexpr size_t kMagicNumberEndSize = sizeof(kMagicNumberEnd);
230 : :
231 [ + + ]: 22 : if VUNLIKELY (bytes.size() < kMagicNumberBeginSize + kVersionSize + sizeof(ProxyData) + kMagicNumberEndSize) {
232 : 1 : return false;
233 : : }
234 : :
235 : 21 : uint32_t check_magic = 0;
236 : :
237 : 21 : std::memcpy(&check_magic, bytes.begin(), kMagicNumberBeginSize);
238 : :
239 [ + + ]: 21 : if VUNLIKELY (check_magic != kMagicNumberBegin) {
240 : 1 : return false;
241 : : }
242 : :
243 : 20 : uint32_t wire_version = 0;
244 : 20 : std::memcpy(&wire_version, bytes.data() + kMagicNumberBeginSize, kVersionSize);
245 : :
246 [ + + ]: 20 : if VUNLIKELY (version_major(wire_version) != version_major(kWireVersion)) {
247 : 2 : return false;
248 : : }
249 : :
250 : 18 : std::memcpy(&check_magic, bytes.end() - kMagicNumberEndSize, kMagicNumberEndSize);
251 : :
252 [ + + ]: 18 : if VUNLIKELY (check_magic != kMagicNumberEnd) {
253 : 1 : return false;
254 : : }
255 : :
256 : 17 : return true;
257 : : }
258 : :
259 : 36 : size_t ProxyData::get_serialized_size() const noexcept {
260 : : static constexpr size_t kMagicNumberBeginSize = sizeof(kMagicNumberBegin);
261 : : static constexpr size_t kVersionSize = sizeof(kWireVersion);
262 : : static constexpr size_t kMagicNumberEndSize = sizeof(kMagicNumberEnd);
263 : :
264 : 36 : return kMagicNumberBeginSize + kVersionSize + sizeof(ProxyData) + size_ + kMagicNumberEndSize;
265 : : }
266 : :
267 : 24 : bool ProxyData::is_valid() const noexcept {
268 [ - + ]: 24 : if VUNLIKELY (static_cast<uint64_t>(data_pos_) + data_size_ != url_pos_) {
269 : 0 : return false;
270 : : }
271 : :
272 [ - + ]: 24 : if VUNLIKELY (static_cast<uint64_t>(url_pos_) + url_size_ != ser_pos_) {
273 : 0 : return false;
274 : : }
275 : :
276 [ - + ]: 24 : if VUNLIKELY (static_cast<uint64_t>(ser_pos_) + ser_size_ != hostname_pos_) {
277 : 0 : return false;
278 : : }
279 : :
280 [ - + ]: 24 : if VUNLIKELY (static_cast<uint64_t>(hostname_pos_) + hostname_size_ != size_) {
281 : 0 : return false;
282 : : }
283 : :
284 [ + + + - ]: 24 : return data_ != nullptr && size_ != 0;
285 : : }
286 : :
287 : 13 : bool ProxyData::shallow_copy(const ProxyData& target) noexcept {
288 [ + + ]: 13 : if VUNLIKELY (this == &target) {
289 : 2 : return false;
290 : : }
291 : :
292 [ + + + - : 11 : if (is_owner_ && data_ && size_ != 0) {
+ - ]
293 : 2 : Bytes::bytes_free(data_, size_);
294 : : }
295 : :
296 : 11 : control_id_ = target.control_id_;
297 : 11 : mode_ = target.mode_;
298 : 11 : timestamp_ = target.timestamp_;
299 : 11 : seq_ = target.seq_;
300 : 11 : schema_ = target.schema_;
301 : :
302 : 11 : data_pos_ = target.data_pos_;
303 : 11 : data_size_ = target.data_size_;
304 : :
305 : 11 : url_pos_ = target.url_pos_;
306 : 11 : url_size_ = target.url_size_;
307 : :
308 : 11 : ser_pos_ = target.ser_pos_;
309 : 11 : ser_size_ = target.ser_size_;
310 : :
311 : 11 : hostname_pos_ = target.hostname_pos_;
312 : 11 : hostname_size_ = target.hostname_size_;
313 : :
314 : 11 : reserved_buf_ = target.reserved_buf_;
315 : 11 : reserved_buf2_ = target.reserved_buf2_;
316 : :
317 : 11 : size_ = target.size_;
318 : 11 : data_ = target.data_;
319 : :
320 : 11 : is_owner_ = false;
321 : :
322 : 11 : return true;
323 : : }
324 : :
325 : 7 : bool ProxyData::deep_copy(const ProxyData& target) noexcept {
326 [ + + + - : 7 : if VLIKELY (data_ && is_owner_ && target.data_ && size_ != 0 && size_ == target.size_) {
+ + + - +
+ + - + +
+ - + + ]
327 [ + + ]: 2 : if VUNLIKELY (this == &target) {
328 : 1 : return false;
329 : : }
330 : :
331 : 1 : control_id_ = target.control_id_;
332 : 1 : mode_ = target.mode_;
333 : 1 : timestamp_ = target.timestamp_;
334 : 1 : seq_ = target.seq_;
335 : 1 : schema_ = target.schema_;
336 : :
337 : 1 : data_pos_ = target.data_pos_;
338 : 1 : data_size_ = target.data_size_;
339 : :
340 : 1 : url_pos_ = target.url_pos_;
341 : 1 : url_size_ = target.url_size_;
342 : :
343 : 1 : ser_pos_ = target.ser_pos_;
344 : 1 : ser_size_ = target.ser_size_;
345 : :
346 : 1 : hostname_pos_ = target.hostname_pos_;
347 : 1 : hostname_size_ = target.hostname_size_;
348 : :
349 : 1 : reserved_buf_ = target.reserved_buf_;
350 : 1 : reserved_buf2_ = target.reserved_buf2_;
351 : :
352 : 1 : std::memcpy(data_, target.data_, size_);
353 : :
354 : 1 : return true;
355 : : }
356 : :
357 [ - + ]: 5 : if VUNLIKELY (!shallow_copy(target)) {
358 : 0 : return false;
359 : : }
360 : :
361 [ + - + - ]: 5 : if (data_ && size_ != 0) {
362 : 5 : data_ = Bytes::bytes_malloc(size_);
363 : :
364 : 5 : std::memcpy(data_, target.data_, size_);
365 : :
366 : 5 : is_owner_ = true;
367 : : }
368 : :
369 : 5 : return true;
370 : : }
371 : :
372 : 5 : bool ProxyData::move_copy(ProxyData& target) noexcept {
373 [ + + ]: 5 : if VUNLIKELY (!shallow_copy(target)) {
374 : 1 : return false;
375 : : }
376 : :
377 : 4 : is_owner_ = target.is_owner_;
378 : :
379 : 4 : target.control_id_ = 0;
380 : 4 : target.mode_ = 0;
381 : 4 : target.timestamp_ = 0;
382 : 4 : target.seq_ = 0;
383 : 4 : target.schema_ = 0;
384 : :
385 : 4 : target.data_pos_ = 0;
386 : 4 : target.data_size_ = 0;
387 : :
388 : 4 : target.url_pos_ = 0;
389 : 4 : target.url_size_ = 0;
390 : :
391 : 4 : target.ser_pos_ = 0;
392 : 4 : target.ser_size_ = 0;
393 : :
394 : 4 : target.hostname_pos_ = 0;
395 : 4 : target.hostname_size_ = 0;
396 : :
397 : 4 : target.reserved_buf_ = 0;
398 : 4 : target.reserved_buf2_ = 0;
399 : :
400 : 4 : target.size_ = 0;
401 : 4 : target.data_ = nullptr;
402 : 4 : target.is_owner_ = false;
403 : :
404 : 4 : return true;
405 : : }
406 : :
407 : 42 : void ProxyData::create(const Bytes& raw, std::string_view url, std::string_view ser, uint32_t schema,
408 : : std::string_view hostname) noexcept {
409 [ - + - - : 42 : if (is_owner_ && data_ && size_ != 0) {
- - ]
410 : 0 : Bytes::bytes_free(data_, size_);
411 : : }
412 : :
413 : : static constexpr uint64_t kMax = std::numeric_limits<uint32_t>::max();
414 : :
415 [ + - - + : 42 : if VUNLIKELY (raw.size() > kMax || url.size() > kMax || ser.size() > kMax || hostname.size() > kMax) {
+ - - + +
- - + -
+ ]
416 : : clear(); // LCOV_EXCL_LINE GCOVR_EXCL_LINE
417 : : return; // LCOV_EXCL_LINE GCOVR_EXCL_LINE
418 : : }
419 : :
420 : 42 : const uint64_t total = static_cast<uint64_t>(raw.size()) + url.size() + ser.size() + hostname.size();
421 : :
422 [ - + ]: 42 : if VUNLIKELY (total > kMax) {
423 : : clear(); // LCOV_EXCL_LINE GCOVR_EXCL_LINE
424 : : return; // LCOV_EXCL_LINE GCOVR_EXCL_LINE
425 : : }
426 : :
427 : 42 : schema_ = schema;
428 : :
429 : 42 : data_pos_ = 0;
430 : 42 : data_size_ = static_cast<uint32_t>(raw.size());
431 : :
432 : 42 : url_pos_ = data_pos_ + data_size_;
433 : 42 : url_size_ = static_cast<uint32_t>(url.size());
434 : :
435 : 42 : ser_pos_ = url_pos_ + url_size_;
436 : 42 : ser_size_ = static_cast<uint32_t>(ser.size());
437 : :
438 : 42 : hostname_pos_ = ser_pos_ + ser_size_;
439 : 42 : hostname_size_ = static_cast<uint32_t>(hostname.size());
440 : :
441 : 42 : size_ = total;
442 : 42 : data_ = Bytes::bytes_malloc(size_);
443 : :
444 [ + + ]: 42 : if VLIKELY (data_size_ > 0) {
445 : 41 : std::memcpy(data_ + data_pos_, raw.data(), data_size_);
446 : : }
447 : :
448 : 42 : std::memcpy(data_ + url_pos_, url.data(), url_size_);
449 : :
450 : 42 : std::memcpy(data_ + ser_pos_, ser.data(), ser_size_);
451 : :
452 : 42 : std::memcpy(data_ + hostname_pos_, hostname.data(), hostname_size_);
453 : :
454 : 42 : is_owner_ = true;
455 : : }
456 : :
457 : 8 : void ProxyData::clear() noexcept {
458 [ + + + - : 8 : if (is_owner_ && data_ && size_ != 0) {
+ - ]
459 : 3 : Bytes::bytes_free(data_, size_);
460 : : }
461 : :
462 : 8 : control_id_ = 0;
463 : 8 : mode_ = 0;
464 : 8 : timestamp_ = 0;
465 : 8 : seq_ = 0;
466 : 8 : schema_ = 0;
467 : :
468 : 8 : data_pos_ = 0;
469 : 8 : data_size_ = 0;
470 : :
471 : 8 : url_pos_ = 0;
472 : 8 : url_size_ = 0;
473 : :
474 : 8 : ser_pos_ = 0;
475 : 8 : ser_size_ = 0;
476 : :
477 : 8 : hostname_pos_ = 0;
478 : 8 : hostname_size_ = 0;
479 : :
480 : 8 : reserved_buf_ = 0;
481 : 8 : reserved_buf2_ = 0;
482 : :
483 : 8 : size_ = 0;
484 : 8 : data_ = nullptr;
485 : 8 : is_owner_ = false;
486 : 8 : }
487 : :
488 : 7 : size_t ProxyData::size() const noexcept { return size_; }
489 : :
490 : 19 : bool ProxyData::is_owner() const noexcept { return is_owner_; }
491 : :
492 : 5 : uint8_t& ProxyData::get_reserved() noexcept { return reserved_buf_; }
493 : :
494 : 5 : uint16_t& ProxyData::get_reserved2() noexcept { return reserved_buf2_; }
495 : :
496 : : } // namespace zerocopy
497 : :
498 : : } // namespace vlink
|