Coverage Report

Created: 2026-05-30 06:56

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/tor/src/trunnel/netinfo.c
Line
Count
Source
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
0
  do {                              \
12
0
    (obj)->trunnel_error_code_ = 1; \
13
0
  } 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
0
  do {                                                           \
26
0
    if (remaining < (nbytes) OR_DEADCODE_DUMMY) {                \
27
0
      goto label;                                                \
28
0
    }                                                            \
29
0
  } while (0)
30
31
netinfo_addr_t *
32
netinfo_addr_new(void)
33
0
{
34
0
  netinfo_addr_t *val = trunnel_calloc(1, sizeof(netinfo_addr_t));
35
0
  if (NULL == val)
36
0
    return NULL;
37
0
  return val;
38
0
}
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
0
{
45
0
  (void) obj;
46
0
}
47
48
void
49
netinfo_addr_free(netinfo_addr_t *obj)
50
0
{
51
0
  if (obj == NULL)
52
0
    return;
53
0
  netinfo_addr_clear(obj);
54
0
  trunnel_memwipe(obj, sizeof(netinfo_addr_t));
55
0
  trunnel_free_(obj);
56
0
}
57
58
uint8_t
59
netinfo_addr_get_addr_type(const netinfo_addr_t *inp)
60
0
{
61
0
  return inp->addr_type;
62
0
}
63
int
64
netinfo_addr_set_addr_type(netinfo_addr_t *inp, uint8_t val)
65
0
{
66
0
  inp->addr_type = val;
67
0
  return 0;
68
0
}
69
uint8_t
70
netinfo_addr_get_len(const netinfo_addr_t *inp)
71
0
{
72
0
  return inp->len;
73
0
}
74
int
75
netinfo_addr_set_len(netinfo_addr_t *inp, uint8_t val)
76
0
{
77
0
  inp->len = val;
78
0
  return 0;
79
0
}
80
uint32_t
81
netinfo_addr_get_addr_ipv4(const netinfo_addr_t *inp)
82
0
{
83
0
  return inp->addr_ipv4;
84
0
}
85
int
86
netinfo_addr_set_addr_ipv4(netinfo_addr_t *inp, uint32_t val)
87
0
{
88
0
  inp->addr_ipv4 = val;
89
0
  return 0;
90
0
}
91
size_t
92
netinfo_addr_getlen_addr_ipv6(const netinfo_addr_t *inp)
93
0
{
94
0
  (void)inp;  return 16;
95
0
}
96
97
uint8_t
98
netinfo_addr_get_addr_ipv6(netinfo_addr_t *inp, size_t idx)
99
0
{
100
0
  trunnel_assert(idx < 16);
101
0
  return inp->addr_ipv6[idx];
102
0
}
103
104
uint8_t
105
netinfo_addr_getconst_addr_ipv6(const netinfo_addr_t *inp, size_t idx)
106
0
{
107
0
  return netinfo_addr_get_addr_ipv6((netinfo_addr_t*)inp, idx);
108
0
}
109
int
110
netinfo_addr_set_addr_ipv6(netinfo_addr_t *inp, size_t idx, uint8_t elt)
111
0
{
112
0
  trunnel_assert(idx < 16);
113
0
  inp->addr_ipv6[idx] = elt;
114
0
  return 0;
115
0
}
116
117
uint8_t *
118
netinfo_addr_getarray_addr_ipv6(netinfo_addr_t *inp)
119
0
{
120
0
  return inp->addr_ipv6;
121
0
}
122
const uint8_t  *
123
netinfo_addr_getconstarray_addr_ipv6(const netinfo_addr_t *inp)
124
0
{
125
0
  return (const uint8_t  *)netinfo_addr_getarray_addr_ipv6((netinfo_addr_t*)inp);
126
0
}
127
const char *
128
netinfo_addr_check(const netinfo_addr_t *obj)
129
0
{
130
0
  if (obj == NULL)
131
0
    return "Object was NULL";
132
0
  if (obj->trunnel_error_code_)
133
0
    return "A set function failed on this object";
134
0
  switch (obj->addr_type) {
135
136
0
    case NETINFO_ADDR_TYPE_IPV4:
137
0
      break;
138
139
0
    case NETINFO_ADDR_TYPE_IPV6:
140
0
      break;
141
142
0
    default:
143
0
      break;
144
0
  }
145
0
  return NULL;
146
0
}
147
148
ssize_t
149
netinfo_addr_encoded_len(const netinfo_addr_t *obj)
150
0
{
151
0
  ssize_t result = 0;
152
153
0
  if (NULL != netinfo_addr_check(obj))
154
0
     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
0
    default:
177
0
      break;
178
0
  }
179
0
  return result;
180
0
}
181
int
182
netinfo_addr_clear_errors(netinfo_addr_t *obj)
183
0
{
184
0
  int r = obj->trunnel_error_code_;
185
0
  obj->trunnel_error_code_ = 0;
186
0
  return r;
187
0
}
188
ssize_t
189
netinfo_addr_encode(uint8_t *output, const size_t avail, const netinfo_addr_t *obj)
190
0
{
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
0
  {
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
0
      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
0
      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
0
      default:
250
0
        break;
251
0
    }
252
    /* Write the length field back to len */
253
0
    trunnel_assert(written >= written_before_union);
254
0
#if UINT8_MAX < SIZE_MAX
255
0
    if (written - written_before_union > UINT8_MAX)
256
0
      goto check_failed;
257
0
#endif
258
0
    trunnel_set_uint8(backptr_len, (written - written_before_union));
259
0
  }
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
0
 fail:
281
0
  trunnel_assert(result < 0);
282
0
  return result;
283
0
}
284
285
/** As netinfo_addr_parse(), but do not allocate the output object.
286
 */
287
static ssize_t
288
netinfo_addr_parse_into(netinfo_addr_t *obj, const uint8_t *input, const size_t len_in)
289
0
{
290
0
  const uint8_t *ptr = input;
291
0
  size_t remaining = len_in;
292
0
  ssize_t result = 0;
293
0
  (void)result;
294
295
  /* Parse u8 addr_type */
296
0
  CHECK_REMAINING(1, truncated);
297
0
  obj->addr_type = (trunnel_get_uint8(ptr));
298
0
  remaining -= 1; ptr += 1;
299
300
  /* Parse u8 len */
301
0
  CHECK_REMAINING(1, truncated);
302
0
  obj->len = (trunnel_get_uint8(ptr));
303
0
  remaining -= 1; ptr += 1;
304
0
  {
305
0
    size_t remaining_after;
306
0
    CHECK_REMAINING(obj->len, truncated);
307
0
    remaining_after = remaining - obj->len;
308
0
    remaining = obj->len;
309
310
    /* Parse union addr[addr_type] */
311
0
    switch (obj->addr_type) {
312
313
0
      case NETINFO_ADDR_TYPE_IPV4:
314
315
        /* Parse u32 addr_ipv4 */
316
0
        CHECK_REMAINING(4, fail);
317
0
        obj->addr_ipv4 = trunnel_ntohl(trunnel_get_uint32(ptr));
318
0
        remaining -= 4; ptr += 4;
319
0
        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
0
      default:
330
        /* Skip to end of union */
331
0
        ptr += remaining; remaining = 0;
332
0
        break;
333
0
    }
334
0
    if (remaining != 0)
335
0
      goto fail;
336
0
    remaining = remaining_after;
337
0
  }
338
0
  trunnel_assert(ptr + remaining == input + len_in);
339
0
  return len_in - remaining;
340
341
0
 truncated:
342
0
  return -2;
343
0
 fail:
344
0
  result = -1;
345
0
  return result;
346
0
}
347
348
ssize_t
349
netinfo_addr_parse(netinfo_addr_t **output, const uint8_t *input, const size_t len_in)
350
0
{
351
0
  ssize_t result;
352
0
  *output = netinfo_addr_new();
353
0
  if (NULL == *output)
354
0
    return -1;
355
0
  result = netinfo_addr_parse_into(*output, input, len_in);
356
0
  if (result < 0) {
357
0
    netinfo_addr_free(*output);
358
0
    *output = NULL;
359
0
  }
360
0
  return result;
361
0
}
362
netinfo_cell_t *
363
netinfo_cell_new(void)
364
0
{
365
0
  netinfo_cell_t *val = trunnel_calloc(1, sizeof(netinfo_cell_t));
366
0
  if (NULL == val)
367
0
    return NULL;
368
0
  return val;
369
0
}
370
371
/** Release all storage held inside 'obj', but do not free 'obj'.
372
 */
373
static void
374
netinfo_cell_clear(netinfo_cell_t *obj)
375
0
{
376
0
  (void) obj;
377
0
  netinfo_addr_free(obj->other_addr);
378
0
  obj->other_addr = NULL;
379
0
  {
380
381
0
    unsigned idx;
382
0
    for (idx = 0; idx < TRUNNEL_DYNARRAY_LEN(&obj->my_addrs); ++idx) {
383
0
      netinfo_addr_free(TRUNNEL_DYNARRAY_GET(&obj->my_addrs, idx));
384
0
    }
385
0
  }
386
0
  TRUNNEL_DYNARRAY_WIPE(&obj->my_addrs);
387
0
  TRUNNEL_DYNARRAY_CLEAR(&obj->my_addrs);
388
0
}
389
390
void
391
netinfo_cell_free(netinfo_cell_t *obj)
392
0
{
393
0
  if (obj == NULL)
394
0
    return;
395
0
  netinfo_cell_clear(obj);
396
0
  trunnel_memwipe(obj, sizeof(netinfo_cell_t));
397
0
  trunnel_free_(obj);
398
0
}
399
400
uint32_t
401
netinfo_cell_get_timestamp(const netinfo_cell_t *inp)
402
0
{
403
0
  return inp->timestamp;
404
0
}
405
int
406
netinfo_cell_set_timestamp(netinfo_cell_t *inp, uint32_t val)
407
0
{
408
0
  inp->timestamp = val;
409
0
  return 0;
410
0
}
411
struct netinfo_addr_st *
412
netinfo_cell_get_other_addr(netinfo_cell_t *inp)
413
0
{
414
0
  return inp->other_addr;
415
0
}
416
const struct netinfo_addr_st *
417
netinfo_cell_getconst_other_addr(const netinfo_cell_t *inp)
418
0
{
419
0
  return netinfo_cell_get_other_addr((netinfo_cell_t*) inp);
420
0
}
421
int
422
netinfo_cell_set_other_addr(netinfo_cell_t *inp, struct netinfo_addr_st *val)
423
0
{
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
0
}
428
int
429
netinfo_cell_set0_other_addr(netinfo_cell_t *inp, struct netinfo_addr_st *val)
430
0
{
431
0
  inp->other_addr = val;
432
0
  return 0;
433
0
}
434
uint8_t
435
netinfo_cell_get_n_my_addrs(const netinfo_cell_t *inp)
436
0
{
437
0
  return inp->n_my_addrs;
438
0
}
439
int
440
netinfo_cell_set_n_my_addrs(netinfo_cell_t *inp, uint8_t val)
441
0
{
442
0
  inp->n_my_addrs = val;
443
0
  return 0;
444
0
}
445
size_t
446
netinfo_cell_getlen_my_addrs(const netinfo_cell_t *inp)
447
0
{
448
0
  return TRUNNEL_DYNARRAY_LEN(&inp->my_addrs);
449
0
}
450
451
struct netinfo_addr_st *
452
netinfo_cell_get_my_addrs(netinfo_cell_t *inp, size_t idx)
453
0
{
454
0
  return TRUNNEL_DYNARRAY_GET(&inp->my_addrs, idx);
455
0
}
456
457
 const struct netinfo_addr_st *
458
netinfo_cell_getconst_my_addrs(const netinfo_cell_t *inp, size_t idx)
459
0
{
460
0
  return netinfo_cell_get_my_addrs((netinfo_cell_t*)inp, idx);
461
0
}
462
int
463
netinfo_cell_set_my_addrs(netinfo_cell_t *inp, size_t idx, struct netinfo_addr_st * elt)
464
0
{
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
0
}
470
int
471
netinfo_cell_set0_my_addrs(netinfo_cell_t *inp, size_t idx, struct netinfo_addr_st * elt)
472
0
{
473
0
  TRUNNEL_DYNARRAY_SET(&inp->my_addrs, idx, elt);
474
0
  return 0;
475
0
}
476
int
477
netinfo_cell_add_my_addrs(netinfo_cell_t *inp, struct netinfo_addr_st * elt)
478
0
{
479
0
#if SIZE_MAX >= UINT8_MAX
480
0
  if (inp->my_addrs.n_ == UINT8_MAX)
481
0
    goto trunnel_alloc_failed;
482
0
#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
0
}
489
490
struct netinfo_addr_st * *
491
netinfo_cell_getarray_my_addrs(netinfo_cell_t *inp)
492
0
{
493
0
  return inp->my_addrs.elts_;
494
0
}
495
const struct netinfo_addr_st *  const  *
496
netinfo_cell_getconstarray_my_addrs(const netinfo_cell_t *inp)
497
0
{
498
0
  return (const struct netinfo_addr_st *  const  *)netinfo_cell_getarray_my_addrs((netinfo_cell_t*)inp);
499
0
}
500
int
501
netinfo_cell_setlen_my_addrs(netinfo_cell_t *inp, size_t newlen)
502
0
{
503
0
  struct netinfo_addr_st * *newptr;
504
0
#if UINT8_MAX < SIZE_MAX
505
0
  if (newlen > UINT8_MAX)
506
0
    goto trunnel_alloc_failed;
507
0
#endif
508
0
  newptr = trunnel_dynarray_setlen(&inp->my_addrs.allocated_,
509
0
                 &inp->my_addrs.n_, inp->my_addrs.elts_, newlen,
510
0
                 sizeof(inp->my_addrs.elts_[0]), (trunnel_free_fn_t) netinfo_addr_free,
511
0
                 &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
0
}
520
const char *
521
netinfo_cell_check(const netinfo_cell_t *obj)
522
0
{
523
0
  if (obj == NULL)
524
0
    return "Object was NULL";
525
0
  if (obj->trunnel_error_code_)
526
0
    return "A set function failed on this object";
527
0
  {
528
0
    const char *msg;
529
0
    if (NULL != (msg = netinfo_addr_check(obj->other_addr)))
530
0
      return msg;
531
0
  }
532
0
  {
533
0
    const char *msg;
534
535
0
    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
0
    }
540
0
  }
541
0
  if (TRUNNEL_DYNARRAY_LEN(&obj->my_addrs) != obj->n_my_addrs)
542
0
    return "Length mismatch for my_addrs";
543
0
  return NULL;
544
0
}
545
546
ssize_t
547
netinfo_cell_encoded_len(const netinfo_cell_t *obj)
548
0
{
549
0
  ssize_t result = 0;
550
551
0
  if (NULL != netinfo_cell_check(obj))
552
0
     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
0
  {
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
0
    }
571
0
  }
572
0
  return result;
573
0
}
574
int
575
netinfo_cell_clear_errors(netinfo_cell_t *obj)
576
0
{
577
0
  int r = obj->trunnel_error_code_;
578
0
  obj->trunnel_error_code_ = 0;
579
0
  return r;
580
0
}
581
ssize_t
582
netinfo_cell_encode(uint8_t *output, const size_t avail, const netinfo_cell_t *obj)
583
0
{
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
0
  {
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
0
    }
631
0
  }
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
0
 fail:
653
0
  trunnel_assert(result < 0);
654
0
  return result;
655
0
}
656
657
/** As netinfo_cell_parse(), but do not allocate the output object.
658
 */
659
static ssize_t
660
netinfo_cell_parse_into(netinfo_cell_t *obj, const uint8_t *input, const size_t len_in)
661
0
{
662
0
  const uint8_t *ptr = input;
663
0
  size_t remaining = len_in;
664
0
  ssize_t result = 0;
665
0
  (void)result;
666
667
  /* Parse u32 timestamp */
668
0
  CHECK_REMAINING(4, truncated);
669
0
  obj->timestamp = trunnel_ntohl(trunnel_get_uint32(ptr));
670
0
  remaining -= 4; ptr += 4;
671
672
  /* Parse struct netinfo_addr other_addr */
673
0
  result = netinfo_addr_parse(&obj->other_addr, ptr, remaining);
674
0
  if (result < 0)
675
0
    goto relay_fail;
676
0
  trunnel_assert((size_t)result <= remaining);
677
0
  remaining -= result; ptr += result;
678
679
  /* Parse u8 n_my_addrs */
680
0
  CHECK_REMAINING(1, truncated);
681
0
  obj->n_my_addrs = (trunnel_get_uint8(ptr));
682
0
  remaining -= 1; ptr += 1;
683
684
  /* Parse struct netinfo_addr my_addrs[n_my_addrs] */
685
0
  TRUNNEL_DYNARRAY_EXPAND(netinfo_addr_t *, &obj->my_addrs, obj->n_my_addrs, {});
686
0
  {
687
0
    netinfo_addr_t * elt;
688
0
    unsigned idx;
689
0
    for (idx = 0; idx < obj->n_my_addrs; ++idx) {
690
0
      result = netinfo_addr_parse(&elt, ptr, remaining);
691
0
      if (result < 0)
692
0
        goto relay_fail;
693
0
      trunnel_assert((size_t)result <= remaining);
694
0
      remaining -= result; ptr += result;
695
0
      TRUNNEL_DYNARRAY_ADD(netinfo_addr_t *, &obj->my_addrs, elt, {netinfo_addr_free(elt);});
696
0
    }
697
0
  }
698
0
  trunnel_assert(ptr + remaining == input + len_in);
699
0
  return len_in - remaining;
700
701
0
 truncated:
702
0
  return -2;
703
0
 relay_fail:
704
0
  trunnel_assert(result < 0);
705
0
  return result;
706
0
 trunnel_alloc_failed:
707
0
  return -1;
708
0
}
709
710
ssize_t
711
netinfo_cell_parse(netinfo_cell_t **output, const uint8_t *input, const size_t len_in)
712
0
{
713
0
  ssize_t result;
714
0
  *output = netinfo_cell_new();
715
0
  if (NULL == *output)
716
0
    return -1;
717
0
  result = netinfo_cell_parse_into(*output, input, len_in);
718
0
  if (result < 0) {
719
0
    netinfo_cell_free(*output);
720
    *output = NULL;
721
0
  }
722
0
  return result;
723
0
}