tor

The Tor anonymity network
git clone https://git.dasho.dev/tor.git
Log | Files | Refs | README | LICENSE

netinfo.c (16970B)


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