/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 | } |