Line data Source code
1 : /* netinfo.c -- generated by Trunnel v1.5.3.
2 : * https://gitweb.torproject.org/trunnel.git
3 : * You probably shouldn't edit this file.
4 : */
5 : #include <stdlib.h>
6 : #include "trunnel-impl.h"
7 :
8 : #include "netinfo.h"
9 :
10 : #define TRUNNEL_SET_ERROR_CODE(obj) \
11 : do { \
12 : (obj)->trunnel_error_code_ = 1; \
13 : } while (0)
14 :
15 : #if defined(__COVERITY__) || defined(__clang_analyzer__)
16 : /* If we're running a static analysis tool, we don't want it to complain
17 : * that some of our remaining-bytes checks are dead-code. */
18 : int netinfo_deadcode_dummy__ = 0;
19 : #define OR_DEADCODE_DUMMY || netinfo_deadcode_dummy__
20 : #else
21 : #define OR_DEADCODE_DUMMY
22 : #endif
23 :
24 : #define CHECK_REMAINING(nbytes, label) \
25 : do { \
26 : if (remaining < (nbytes) OR_DEADCODE_DUMMY) { \
27 : goto label; \
28 : } \
29 : } while (0)
30 :
31 : netinfo_addr_t *
32 2 : netinfo_addr_new(void)
33 : {
34 2 : netinfo_addr_t *val = trunnel_calloc(1, sizeof(netinfo_addr_t));
35 2 : if (NULL == val)
36 0 : return NULL;
37 : return val;
38 : }
39 :
40 : /** Release all storage held inside 'obj', but do not free 'obj'.
41 : */
42 : static void
43 : netinfo_addr_clear(netinfo_addr_t *obj)
44 : {
45 : (void) obj;
46 : }
47 :
48 : void
49 2 : netinfo_addr_free(netinfo_addr_t *obj)
50 : {
51 2 : if (obj == NULL)
52 : return;
53 2 : netinfo_addr_clear(obj);
54 2 : trunnel_memwipe(obj, sizeof(netinfo_addr_t));
55 2 : trunnel_free_(obj);
56 : }
57 :
58 : uint8_t
59 1 : netinfo_addr_get_addr_type(const netinfo_addr_t *inp)
60 : {
61 1 : return inp->addr_type;
62 : }
63 : int
64 0 : netinfo_addr_set_addr_type(netinfo_addr_t *inp, uint8_t val)
65 : {
66 0 : inp->addr_type = val;
67 0 : return 0;
68 : }
69 : uint8_t
70 1 : netinfo_addr_get_len(const netinfo_addr_t *inp)
71 : {
72 1 : return inp->len;
73 : }
74 : int
75 0 : netinfo_addr_set_len(netinfo_addr_t *inp, uint8_t val)
76 : {
77 0 : inp->len = val;
78 0 : return 0;
79 : }
80 : uint32_t
81 0 : netinfo_addr_get_addr_ipv4(const netinfo_addr_t *inp)
82 : {
83 0 : return inp->addr_ipv4;
84 : }
85 : int
86 0 : netinfo_addr_set_addr_ipv4(netinfo_addr_t *inp, uint32_t val)
87 : {
88 0 : inp->addr_ipv4 = val;
89 0 : return 0;
90 : }
91 : size_t
92 0 : netinfo_addr_getlen_addr_ipv6(const netinfo_addr_t *inp)
93 : {
94 0 : (void)inp; return 16;
95 : }
96 :
97 : uint8_t
98 0 : netinfo_addr_get_addr_ipv6(netinfo_addr_t *inp, size_t idx)
99 : {
100 0 : trunnel_assert(idx < 16);
101 0 : return inp->addr_ipv6[idx];
102 : }
103 :
104 : uint8_t
105 0 : netinfo_addr_getconst_addr_ipv6(const netinfo_addr_t *inp, size_t idx)
106 : {
107 0 : return netinfo_addr_get_addr_ipv6((netinfo_addr_t*)inp, idx);
108 : }
109 : int
110 0 : netinfo_addr_set_addr_ipv6(netinfo_addr_t *inp, size_t idx, uint8_t elt)
111 : {
112 0 : trunnel_assert(idx < 16);
113 0 : inp->addr_ipv6[idx] = elt;
114 0 : return 0;
115 : }
116 :
117 : uint8_t *
118 0 : netinfo_addr_getarray_addr_ipv6(netinfo_addr_t *inp)
119 : {
120 0 : return inp->addr_ipv6;
121 : }
122 : const uint8_t *
123 0 : netinfo_addr_getconstarray_addr_ipv6(const netinfo_addr_t *inp)
124 : {
125 0 : return (const uint8_t *)netinfo_addr_getarray_addr_ipv6((netinfo_addr_t*)inp);
126 : }
127 : const char *
128 0 : netinfo_addr_check(const netinfo_addr_t *obj)
129 : {
130 0 : if (obj == NULL)
131 : return "Object was NULL";
132 0 : if (obj->trunnel_error_code_)
133 0 : return "A set function failed on this object";
134 : switch (obj->addr_type) {
135 :
136 : case NETINFO_ADDR_TYPE_IPV4:
137 : break;
138 :
139 : case NETINFO_ADDR_TYPE_IPV6:
140 : break;
141 :
142 : default:
143 : break;
144 : }
145 : return NULL;
146 : }
147 :
148 : ssize_t
149 0 : netinfo_addr_encoded_len(const netinfo_addr_t *obj)
150 : {
151 0 : ssize_t result = 0;
152 :
153 0 : if (NULL != netinfo_addr_check(obj))
154 : return -1;
155 :
156 :
157 : /* Length of u8 addr_type */
158 0 : result += 1;
159 :
160 : /* Length of u8 len */
161 0 : result += 1;
162 0 : switch (obj->addr_type) {
163 :
164 0 : case NETINFO_ADDR_TYPE_IPV4:
165 :
166 : /* Length of u32 addr_ipv4 */
167 0 : result += 4;
168 0 : break;
169 :
170 0 : case NETINFO_ADDR_TYPE_IPV6:
171 :
172 : /* Length of u8 addr_ipv6[16] */
173 0 : result += 16;
174 0 : break;
175 :
176 : default:
177 : break;
178 : }
179 : return result;
180 : }
181 : int
182 0 : netinfo_addr_clear_errors(netinfo_addr_t *obj)
183 : {
184 0 : int r = obj->trunnel_error_code_;
185 0 : obj->trunnel_error_code_ = 0;
186 0 : return r;
187 : }
188 : ssize_t
189 0 : netinfo_addr_encode(uint8_t *output, const size_t avail, const netinfo_addr_t *obj)
190 : {
191 0 : ssize_t result = 0;
192 0 : size_t written = 0;
193 0 : uint8_t *ptr = output;
194 0 : const char *msg;
195 : #ifdef TRUNNEL_CHECK_ENCODED_LEN
196 : const ssize_t encoded_len = netinfo_addr_encoded_len(obj);
197 : #endif
198 :
199 0 : uint8_t *backptr_len = NULL;
200 :
201 0 : if (NULL != (msg = netinfo_addr_check(obj)))
202 0 : goto check_failed;
203 :
204 : #ifdef TRUNNEL_CHECK_ENCODED_LEN
205 : trunnel_assert(encoded_len >= 0);
206 : #endif
207 :
208 : /* Encode u8 addr_type */
209 0 : trunnel_assert(written <= avail);
210 0 : if (avail - written < 1)
211 0 : goto truncated;
212 0 : trunnel_set_uint8(ptr, (obj->addr_type));
213 0 : written += 1; ptr += 1;
214 :
215 : /* Encode u8 len */
216 0 : backptr_len = ptr;
217 0 : trunnel_assert(written <= avail);
218 0 : if (avail - written < 1)
219 0 : goto truncated;
220 0 : trunnel_set_uint8(ptr, (obj->len));
221 0 : written += 1; ptr += 1;
222 : {
223 0 : size_t written_before_union = written;
224 :
225 : /* Encode union addr[addr_type] */
226 0 : trunnel_assert(written <= avail);
227 0 : switch (obj->addr_type) {
228 :
229 : case NETINFO_ADDR_TYPE_IPV4:
230 :
231 : /* Encode u32 addr_ipv4 */
232 0 : trunnel_assert(written <= avail);
233 0 : if (avail - written < 4)
234 0 : goto truncated;
235 0 : trunnel_set_uint32(ptr, trunnel_htonl(obj->addr_ipv4));
236 0 : written += 4; ptr += 4;
237 0 : break;
238 :
239 : case NETINFO_ADDR_TYPE_IPV6:
240 :
241 : /* Encode u8 addr_ipv6[16] */
242 0 : trunnel_assert(written <= avail);
243 0 : if (avail - written < 16)
244 0 : goto truncated;
245 0 : memcpy(ptr, obj->addr_ipv6, 16);
246 0 : written += 16; ptr += 16;
247 0 : break;
248 :
249 : default:
250 : break;
251 : }
252 : /* Write the length field back to len */
253 0 : trunnel_assert(written >= written_before_union);
254 : #if UINT8_MAX < SIZE_MAX
255 0 : if (written - written_before_union > UINT8_MAX)
256 : goto check_failed;
257 : #endif
258 0 : trunnel_set_uint8(backptr_len, (written - written_before_union));
259 : }
260 :
261 :
262 0 : trunnel_assert(ptr == output + written);
263 : #ifdef TRUNNEL_CHECK_ENCODED_LEN
264 : {
265 : trunnel_assert(encoded_len >= 0);
266 : trunnel_assert((size_t)encoded_len == written);
267 : }
268 :
269 : #endif
270 :
271 0 : return written;
272 :
273 0 : truncated:
274 0 : result = -2;
275 0 : goto fail;
276 0 : check_failed:
277 0 : (void)msg;
278 0 : result = -1;
279 0 : goto fail;
280 : fail:
281 : trunnel_assert(result < 0);
282 : return result;
283 : }
284 :
285 : /** As netinfo_addr_parse(), but do not allocate the output object.
286 : */
287 : static ssize_t
288 2 : netinfo_addr_parse_into(netinfo_addr_t *obj, const uint8_t *input, const size_t len_in)
289 : {
290 2 : const uint8_t *ptr = input;
291 2 : size_t remaining = len_in;
292 2 : ssize_t result = 0;
293 2 : (void)result;
294 :
295 : /* Parse u8 addr_type */
296 2 : CHECK_REMAINING(1, truncated);
297 2 : obj->addr_type = (trunnel_get_uint8(ptr));
298 2 : remaining -= 1; ptr += 1;
299 :
300 : /* Parse u8 len */
301 2 : CHECK_REMAINING(1, truncated);
302 2 : obj->len = (trunnel_get_uint8(ptr));
303 2 : remaining -= 1; ptr += 1;
304 : {
305 2 : size_t remaining_after;
306 2 : CHECK_REMAINING(obj->len, truncated);
307 2 : remaining_after = remaining - obj->len;
308 2 : remaining = obj->len;
309 :
310 : /* Parse union addr[addr_type] */
311 2 : switch (obj->addr_type) {
312 :
313 1 : case NETINFO_ADDR_TYPE_IPV4:
314 :
315 : /* Parse u32 addr_ipv4 */
316 1 : CHECK_REMAINING(4, fail);
317 1 : obj->addr_ipv4 = trunnel_ntohl(trunnel_get_uint32(ptr));
318 1 : remaining -= 4; ptr += 4;
319 1 : break;
320 :
321 0 : case NETINFO_ADDR_TYPE_IPV6:
322 :
323 : /* Parse u8 addr_ipv6[16] */
324 0 : CHECK_REMAINING(16, fail);
325 0 : memcpy(obj->addr_ipv6, ptr, 16);
326 0 : remaining -= 16; ptr += 16;
327 0 : break;
328 :
329 1 : default:
330 : /* Skip to end of union */
331 1 : ptr += remaining; remaining = 0;
332 1 : break;
333 : }
334 2 : if (remaining != 0)
335 0 : goto fail;
336 2 : remaining = remaining_after;
337 : }
338 2 : trunnel_assert(ptr + remaining == input + len_in);
339 2 : return len_in - remaining;
340 :
341 : truncated:
342 : return -2;
343 : fail:
344 2 : result = -1;
345 : return result;
346 : }
347 :
348 : ssize_t
349 2 : netinfo_addr_parse(netinfo_addr_t **output, const uint8_t *input, const size_t len_in)
350 : {
351 2 : ssize_t result;
352 2 : *output = netinfo_addr_new();
353 2 : if (NULL == *output)
354 : return -1;
355 2 : result = netinfo_addr_parse_into(*output, input, len_in);
356 2 : if (result < 0) {
357 0 : netinfo_addr_free(*output);
358 0 : *output = NULL;
359 : }
360 : return result;
361 : }
362 : netinfo_cell_t *
363 1 : netinfo_cell_new(void)
364 : {
365 1 : netinfo_cell_t *val = trunnel_calloc(1, sizeof(netinfo_cell_t));
366 1 : if (NULL == val)
367 0 : return NULL;
368 : return val;
369 : }
370 :
371 : /** Release all storage held inside 'obj', but do not free 'obj'.
372 : */
373 : static void
374 1 : netinfo_cell_clear(netinfo_cell_t *obj)
375 : {
376 1 : (void) obj;
377 1 : netinfo_addr_free(obj->other_addr);
378 1 : obj->other_addr = NULL;
379 : {
380 :
381 1 : unsigned idx;
382 2 : for (idx = 0; idx < TRUNNEL_DYNARRAY_LEN(&obj->my_addrs); ++idx) {
383 1 : netinfo_addr_free(TRUNNEL_DYNARRAY_GET(&obj->my_addrs, idx));
384 : }
385 : }
386 1 : TRUNNEL_DYNARRAY_WIPE(&obj->my_addrs);
387 1 : TRUNNEL_DYNARRAY_CLEAR(&obj->my_addrs);
388 1 : }
389 :
390 : void
391 1 : netinfo_cell_free(netinfo_cell_t *obj)
392 : {
393 1 : if (obj == NULL)
394 : return;
395 1 : netinfo_cell_clear(obj);
396 1 : trunnel_memwipe(obj, sizeof(netinfo_cell_t));
397 1 : trunnel_free_(obj);
398 : }
399 :
400 : uint32_t
401 0 : netinfo_cell_get_timestamp(const netinfo_cell_t *inp)
402 : {
403 0 : return inp->timestamp;
404 : }
405 : int
406 0 : netinfo_cell_set_timestamp(netinfo_cell_t *inp, uint32_t val)
407 : {
408 0 : inp->timestamp = val;
409 0 : return 0;
410 : }
411 : struct netinfo_addr_st *
412 0 : netinfo_cell_get_other_addr(netinfo_cell_t *inp)
413 : {
414 0 : return inp->other_addr;
415 : }
416 : const struct netinfo_addr_st *
417 0 : netinfo_cell_getconst_other_addr(const netinfo_cell_t *inp)
418 : {
419 0 : return netinfo_cell_get_other_addr((netinfo_cell_t*) inp);
420 : }
421 : int
422 0 : netinfo_cell_set_other_addr(netinfo_cell_t *inp, struct netinfo_addr_st *val)
423 : {
424 0 : if (inp->other_addr && inp->other_addr != val)
425 0 : netinfo_addr_free(inp->other_addr);
426 0 : return netinfo_cell_set0_other_addr(inp, val);
427 : }
428 : int
429 0 : netinfo_cell_set0_other_addr(netinfo_cell_t *inp, struct netinfo_addr_st *val)
430 : {
431 0 : inp->other_addr = val;
432 0 : return 0;
433 : }
434 : uint8_t
435 0 : netinfo_cell_get_n_my_addrs(const netinfo_cell_t *inp)
436 : {
437 0 : return inp->n_my_addrs;
438 : }
439 : int
440 0 : netinfo_cell_set_n_my_addrs(netinfo_cell_t *inp, uint8_t val)
441 : {
442 0 : inp->n_my_addrs = val;
443 0 : return 0;
444 : }
445 : size_t
446 0 : netinfo_cell_getlen_my_addrs(const netinfo_cell_t *inp)
447 : {
448 0 : return TRUNNEL_DYNARRAY_LEN(&inp->my_addrs);
449 : }
450 :
451 : struct netinfo_addr_st *
452 1 : netinfo_cell_get_my_addrs(netinfo_cell_t *inp, size_t idx)
453 : {
454 1 : return TRUNNEL_DYNARRAY_GET(&inp->my_addrs, idx);
455 : }
456 :
457 : const struct netinfo_addr_st *
458 0 : netinfo_cell_getconst_my_addrs(const netinfo_cell_t *inp, size_t idx)
459 : {
460 0 : return netinfo_cell_get_my_addrs((netinfo_cell_t*)inp, idx);
461 : }
462 : int
463 0 : netinfo_cell_set_my_addrs(netinfo_cell_t *inp, size_t idx, struct netinfo_addr_st * elt)
464 : {
465 0 : netinfo_addr_t *oldval = TRUNNEL_DYNARRAY_GET(&inp->my_addrs, idx);
466 0 : if (oldval && oldval != elt)
467 0 : netinfo_addr_free(oldval);
468 0 : return netinfo_cell_set0_my_addrs(inp, idx, elt);
469 : }
470 : int
471 0 : netinfo_cell_set0_my_addrs(netinfo_cell_t *inp, size_t idx, struct netinfo_addr_st * elt)
472 : {
473 0 : TRUNNEL_DYNARRAY_SET(&inp->my_addrs, idx, elt);
474 0 : return 0;
475 : }
476 : int
477 0 : netinfo_cell_add_my_addrs(netinfo_cell_t *inp, struct netinfo_addr_st * elt)
478 : {
479 : #if SIZE_MAX >= UINT8_MAX
480 0 : if (inp->my_addrs.n_ == UINT8_MAX)
481 0 : goto trunnel_alloc_failed;
482 : #endif
483 0 : TRUNNEL_DYNARRAY_ADD(struct netinfo_addr_st *, &inp->my_addrs, elt, {});
484 0 : return 0;
485 0 : trunnel_alloc_failed:
486 0 : TRUNNEL_SET_ERROR_CODE(inp);
487 0 : return -1;
488 : }
489 :
490 : struct netinfo_addr_st * *
491 0 : netinfo_cell_getarray_my_addrs(netinfo_cell_t *inp)
492 : {
493 0 : return inp->my_addrs.elts_;
494 : }
495 : const struct netinfo_addr_st * const *
496 0 : netinfo_cell_getconstarray_my_addrs(const netinfo_cell_t *inp)
497 : {
498 0 : return (const struct netinfo_addr_st * const *)netinfo_cell_getarray_my_addrs((netinfo_cell_t*)inp);
499 : }
500 : int
501 0 : netinfo_cell_setlen_my_addrs(netinfo_cell_t *inp, size_t newlen)
502 : {
503 0 : struct netinfo_addr_st * *newptr;
504 : #if UINT8_MAX < SIZE_MAX
505 0 : if (newlen > UINT8_MAX)
506 0 : goto trunnel_alloc_failed;
507 : #endif
508 0 : newptr = trunnel_dynarray_setlen(&inp->my_addrs.allocated_,
509 0 : &inp->my_addrs.n_, inp->my_addrs.elts_, newlen,
510 : sizeof(inp->my_addrs.elts_[0]), (trunnel_free_fn_t) netinfo_addr_free,
511 : &inp->trunnel_error_code_);
512 0 : if (newlen != 0 && newptr == NULL)
513 0 : goto trunnel_alloc_failed;
514 0 : inp->my_addrs.elts_ = newptr;
515 0 : return 0;
516 0 : trunnel_alloc_failed:
517 0 : TRUNNEL_SET_ERROR_CODE(inp);
518 0 : return -1;
519 : }
520 : const char *
521 0 : netinfo_cell_check(const netinfo_cell_t *obj)
522 : {
523 0 : if (obj == NULL)
524 : return "Object was NULL";
525 0 : if (obj->trunnel_error_code_)
526 : return "A set function failed on this object";
527 : {
528 0 : const char *msg;
529 0 : if (NULL != (msg = netinfo_addr_check(obj->other_addr)))
530 : return msg;
531 : }
532 : {
533 : const char *msg;
534 :
535 : unsigned idx;
536 0 : for (idx = 0; idx < TRUNNEL_DYNARRAY_LEN(&obj->my_addrs); ++idx) {
537 0 : if (NULL != (msg = netinfo_addr_check(TRUNNEL_DYNARRAY_GET(&obj->my_addrs, idx))))
538 0 : return msg;
539 : }
540 : }
541 0 : if (TRUNNEL_DYNARRAY_LEN(&obj->my_addrs) != obj->n_my_addrs)
542 0 : return "Length mismatch for my_addrs";
543 : return NULL;
544 : }
545 :
546 : ssize_t
547 0 : netinfo_cell_encoded_len(const netinfo_cell_t *obj)
548 : {
549 0 : ssize_t result = 0;
550 :
551 0 : if (NULL != netinfo_cell_check(obj))
552 : return -1;
553 :
554 :
555 : /* Length of u32 timestamp */
556 0 : result += 4;
557 :
558 : /* Length of struct netinfo_addr other_addr */
559 0 : result += netinfo_addr_encoded_len(obj->other_addr);
560 :
561 : /* Length of u8 n_my_addrs */
562 0 : result += 1;
563 :
564 : /* Length of struct netinfo_addr my_addrs[n_my_addrs] */
565 : {
566 :
567 0 : unsigned idx;
568 0 : for (idx = 0; idx < TRUNNEL_DYNARRAY_LEN(&obj->my_addrs); ++idx) {
569 0 : result += netinfo_addr_encoded_len(TRUNNEL_DYNARRAY_GET(&obj->my_addrs, idx));
570 : }
571 : }
572 : return result;
573 : }
574 : int
575 0 : netinfo_cell_clear_errors(netinfo_cell_t *obj)
576 : {
577 0 : int r = obj->trunnel_error_code_;
578 0 : obj->trunnel_error_code_ = 0;
579 0 : return r;
580 : }
581 : ssize_t
582 0 : netinfo_cell_encode(uint8_t *output, const size_t avail, const netinfo_cell_t *obj)
583 : {
584 0 : ssize_t result = 0;
585 0 : size_t written = 0;
586 0 : uint8_t *ptr = output;
587 0 : const char *msg;
588 : #ifdef TRUNNEL_CHECK_ENCODED_LEN
589 : const ssize_t encoded_len = netinfo_cell_encoded_len(obj);
590 : #endif
591 :
592 0 : if (NULL != (msg = netinfo_cell_check(obj)))
593 0 : goto check_failed;
594 :
595 : #ifdef TRUNNEL_CHECK_ENCODED_LEN
596 : trunnel_assert(encoded_len >= 0);
597 : #endif
598 :
599 : /* Encode u32 timestamp */
600 0 : trunnel_assert(written <= avail);
601 0 : if (avail - written < 4)
602 0 : goto truncated;
603 0 : trunnel_set_uint32(ptr, trunnel_htonl(obj->timestamp));
604 0 : written += 4; ptr += 4;
605 :
606 : /* Encode struct netinfo_addr other_addr */
607 0 : trunnel_assert(written <= avail);
608 0 : result = netinfo_addr_encode(ptr, avail - written, obj->other_addr);
609 0 : if (result < 0)
610 0 : goto fail; /* XXXXXXX !*/
611 0 : written += result; ptr += result;
612 :
613 : /* Encode u8 n_my_addrs */
614 0 : trunnel_assert(written <= avail);
615 0 : if (avail - written < 1)
616 0 : goto truncated;
617 0 : trunnel_set_uint8(ptr, (obj->n_my_addrs));
618 0 : written += 1; ptr += 1;
619 :
620 : /* Encode struct netinfo_addr my_addrs[n_my_addrs] */
621 : {
622 :
623 0 : unsigned idx;
624 0 : for (idx = 0; idx < TRUNNEL_DYNARRAY_LEN(&obj->my_addrs); ++idx) {
625 0 : trunnel_assert(written <= avail);
626 0 : result = netinfo_addr_encode(ptr, avail - written, TRUNNEL_DYNARRAY_GET(&obj->my_addrs, idx));
627 0 : if (result < 0)
628 0 : goto fail; /* XXXXXXX !*/
629 0 : written += result; ptr += result;
630 : }
631 : }
632 :
633 :
634 0 : trunnel_assert(ptr == output + written);
635 : #ifdef TRUNNEL_CHECK_ENCODED_LEN
636 : {
637 : trunnel_assert(encoded_len >= 0);
638 : trunnel_assert((size_t)encoded_len == written);
639 : }
640 :
641 : #endif
642 :
643 0 : return written;
644 :
645 0 : truncated:
646 0 : result = -2;
647 0 : goto fail;
648 0 : check_failed:
649 0 : (void)msg;
650 0 : result = -1;
651 0 : goto fail;
652 : fail:
653 0 : trunnel_assert(result < 0);
654 : return result;
655 : }
656 :
657 : /** As netinfo_cell_parse(), but do not allocate the output object.
658 : */
659 : static ssize_t
660 1 : netinfo_cell_parse_into(netinfo_cell_t *obj, const uint8_t *input, const size_t len_in)
661 : {
662 1 : const uint8_t *ptr = input;
663 1 : size_t remaining = len_in;
664 1 : ssize_t result = 0;
665 1 : (void)result;
666 :
667 : /* Parse u32 timestamp */
668 1 : CHECK_REMAINING(4, truncated);
669 1 : obj->timestamp = trunnel_ntohl(trunnel_get_uint32(ptr));
670 1 : remaining -= 4; ptr += 4;
671 :
672 : /* Parse struct netinfo_addr other_addr */
673 1 : result = netinfo_addr_parse(&obj->other_addr, ptr, remaining);
674 1 : if (result < 0)
675 0 : goto relay_fail;
676 1 : trunnel_assert((size_t)result <= remaining);
677 1 : remaining -= result; ptr += result;
678 :
679 : /* Parse u8 n_my_addrs */
680 1 : CHECK_REMAINING(1, truncated);
681 1 : obj->n_my_addrs = (trunnel_get_uint8(ptr));
682 1 : remaining -= 1; ptr += 1;
683 :
684 : /* Parse struct netinfo_addr my_addrs[n_my_addrs] */
685 1 : TRUNNEL_DYNARRAY_EXPAND(netinfo_addr_t *, &obj->my_addrs, obj->n_my_addrs, {});
686 : {
687 1 : netinfo_addr_t * elt;
688 1 : unsigned idx;
689 2 : for (idx = 0; idx < obj->n_my_addrs; ++idx) {
690 1 : result = netinfo_addr_parse(&elt, ptr, remaining);
691 1 : if (result < 0)
692 0 : goto relay_fail;
693 1 : trunnel_assert((size_t)result <= remaining);
694 1 : remaining -= result; ptr += result;
695 1 : TRUNNEL_DYNARRAY_ADD(netinfo_addr_t *, &obj->my_addrs, elt, {netinfo_addr_free(elt);});
696 : }
697 : }
698 1 : trunnel_assert(ptr + remaining == input + len_in);
699 1 : return len_in - remaining;
700 :
701 : truncated:
702 : return -2;
703 : relay_fail:
704 : trunnel_assert(result < 0);
705 : return result;
706 : trunnel_alloc_failed:
707 : return -1;
708 : }
709 :
710 : ssize_t
711 1 : netinfo_cell_parse(netinfo_cell_t **output, const uint8_t *input, const size_t len_in)
712 : {
713 1 : ssize_t result;
714 1 : *output = netinfo_cell_new();
715 1 : if (NULL == *output)
716 : return -1;
717 1 : result = netinfo_cell_parse_into(*output, input, len_in);
718 1 : if (result < 0) {
719 0 : netinfo_cell_free(*output);
720 0 : *output = NULL;
721 : }
722 : return result;
723 : }
|