Merge branch 'maint-0.4.5' into release-0.4.5
[tor.git] / src / trunnel / sendme_cell.c
blobb9f8fe967f41323150b6ac5edb43f6e00d226468
1 /* sendme_cell.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"
8 #include "sendme_cell.h"
10 #define TRUNNEL_SET_ERROR_CODE(obj) \
11 do { \
12 (obj)->trunnel_error_code_ = 1; \
13 } while (0)
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 sendmecell_deadcode_dummy__ = 0;
19 #define OR_DEADCODE_DUMMY || sendmecell_deadcode_dummy__
20 #else
21 #define OR_DEADCODE_DUMMY
22 #endif
24 #define CHECK_REMAINING(nbytes, label) \
25 do { \
26 if (remaining < (nbytes) OR_DEADCODE_DUMMY) { \
27 goto label; \
28 } \
29 } while (0)
31 sendme_cell_t *
32 sendme_cell_new(void)
34 sendme_cell_t *val = trunnel_calloc(1, sizeof(sendme_cell_t));
35 if (NULL == val)
36 return NULL;
37 return val;
40 /** Release all storage held inside 'obj', but do not free 'obj'.
42 static void
43 sendme_cell_clear(sendme_cell_t *obj)
45 (void) obj;
48 void
49 sendme_cell_free(sendme_cell_t *obj)
51 if (obj == NULL)
52 return;
53 sendme_cell_clear(obj);
54 trunnel_memwipe(obj, sizeof(sendme_cell_t));
55 trunnel_free_(obj);
58 uint8_t
59 sendme_cell_get_version(const sendme_cell_t *inp)
61 return inp->version;
63 int
64 sendme_cell_set_version(sendme_cell_t *inp, uint8_t val)
66 if (! ((val == 0 || val == 1))) {
67 TRUNNEL_SET_ERROR_CODE(inp);
68 return -1;
70 inp->version = val;
71 return 0;
73 uint16_t
74 sendme_cell_get_data_len(const sendme_cell_t *inp)
76 return inp->data_len;
78 int
79 sendme_cell_set_data_len(sendme_cell_t *inp, uint16_t val)
81 inp->data_len = val;
82 return 0;
84 size_t
85 sendme_cell_getlen_data_v1_digest(const sendme_cell_t *inp)
87 (void)inp; return TRUNNEL_SENDME_V1_DIGEST_LEN;
90 uint8_t
91 sendme_cell_get_data_v1_digest(sendme_cell_t *inp, size_t idx)
93 trunnel_assert(idx < TRUNNEL_SENDME_V1_DIGEST_LEN);
94 return inp->data_v1_digest[idx];
97 uint8_t
98 sendme_cell_getconst_data_v1_digest(const sendme_cell_t *inp, size_t idx)
100 return sendme_cell_get_data_v1_digest((sendme_cell_t*)inp, idx);
103 sendme_cell_set_data_v1_digest(sendme_cell_t *inp, size_t idx, uint8_t elt)
105 trunnel_assert(idx < TRUNNEL_SENDME_V1_DIGEST_LEN);
106 inp->data_v1_digest[idx] = elt;
107 return 0;
110 uint8_t *
111 sendme_cell_getarray_data_v1_digest(sendme_cell_t *inp)
113 return inp->data_v1_digest;
115 const uint8_t *
116 sendme_cell_getconstarray_data_v1_digest(const sendme_cell_t *inp)
118 return (const uint8_t *)sendme_cell_getarray_data_v1_digest((sendme_cell_t*)inp);
120 const char *
121 sendme_cell_check(const sendme_cell_t *obj)
123 if (obj == NULL)
124 return "Object was NULL";
125 if (obj->trunnel_error_code_)
126 return "A set function failed on this object";
127 if (! (obj->version == 0 || obj->version == 1))
128 return "Integer out of bounds";
129 switch (obj->version) {
131 case 0:
132 break;
134 case 1:
135 break;
137 default:
138 return "Bad tag for union";
139 break;
141 return NULL;
144 ssize_t
145 sendme_cell_encoded_len(const sendme_cell_t *obj)
147 ssize_t result = 0;
149 if (NULL != sendme_cell_check(obj))
150 return -1;
153 /* Length of u8 version IN [0, 1] */
154 result += 1;
156 /* Length of u16 data_len */
157 result += 2;
158 switch (obj->version) {
160 case 0:
161 break;
163 case 1:
165 /* Length of u8 data_v1_digest[TRUNNEL_SENDME_V1_DIGEST_LEN] */
166 result += TRUNNEL_SENDME_V1_DIGEST_LEN;
167 break;
169 default:
170 trunnel_assert(0);
171 break;
173 return result;
176 sendme_cell_clear_errors(sendme_cell_t *obj)
178 int r = obj->trunnel_error_code_;
179 obj->trunnel_error_code_ = 0;
180 return r;
182 ssize_t
183 sendme_cell_encode(uint8_t *output, const size_t avail, const sendme_cell_t *obj)
185 ssize_t result = 0;
186 size_t written = 0;
187 uint8_t *ptr = output;
188 const char *msg;
189 #ifdef TRUNNEL_CHECK_ENCODED_LEN
190 const ssize_t encoded_len = sendme_cell_encoded_len(obj);
191 #endif
193 uint8_t *backptr_data_len = NULL;
195 if (NULL != (msg = sendme_cell_check(obj)))
196 goto check_failed;
198 #ifdef TRUNNEL_CHECK_ENCODED_LEN
199 trunnel_assert(encoded_len >= 0);
200 #endif
202 /* Encode u8 version IN [0, 1] */
203 trunnel_assert(written <= avail);
204 if (avail - written < 1)
205 goto truncated;
206 trunnel_set_uint8(ptr, (obj->version));
207 written += 1; ptr += 1;
209 /* Encode u16 data_len */
210 backptr_data_len = ptr;
211 trunnel_assert(written <= avail);
212 if (avail - written < 2)
213 goto truncated;
214 trunnel_set_uint16(ptr, trunnel_htons(obj->data_len));
215 written += 2; ptr += 2;
217 size_t written_before_union = written;
219 /* Encode union data[version] */
220 trunnel_assert(written <= avail);
221 switch (obj->version) {
223 case 0:
224 break;
226 case 1:
228 /* Encode u8 data_v1_digest[TRUNNEL_SENDME_V1_DIGEST_LEN] */
229 trunnel_assert(written <= avail);
230 if (avail - written < TRUNNEL_SENDME_V1_DIGEST_LEN)
231 goto truncated;
232 memcpy(ptr, obj->data_v1_digest, TRUNNEL_SENDME_V1_DIGEST_LEN);
233 written += TRUNNEL_SENDME_V1_DIGEST_LEN; ptr += TRUNNEL_SENDME_V1_DIGEST_LEN;
234 break;
236 default:
237 trunnel_assert(0);
238 break;
240 /* Write the length field back to data_len */
241 trunnel_assert(written >= written_before_union);
242 #if UINT16_MAX < SIZE_MAX
243 if (written - written_before_union > UINT16_MAX)
244 goto check_failed;
245 #endif
246 trunnel_set_uint16(backptr_data_len, trunnel_htons(written - written_before_union));
250 trunnel_assert(ptr == output + written);
251 #ifdef TRUNNEL_CHECK_ENCODED_LEN
253 trunnel_assert(encoded_len >= 0);
254 trunnel_assert((size_t)encoded_len == written);
257 #endif
259 return written;
261 truncated:
262 result = -2;
263 goto fail;
264 check_failed:
265 (void)msg;
266 result = -1;
267 goto fail;
268 fail:
269 trunnel_assert(result < 0);
270 return result;
273 /** As sendme_cell_parse(), but do not allocate the output object.
275 static ssize_t
276 sendme_cell_parse_into(sendme_cell_t *obj, const uint8_t *input, const size_t len_in)
278 const uint8_t *ptr = input;
279 size_t remaining = len_in;
280 ssize_t result = 0;
281 (void)result;
283 /* Parse u8 version IN [0, 1] */
284 CHECK_REMAINING(1, truncated);
285 obj->version = (trunnel_get_uint8(ptr));
286 remaining -= 1; ptr += 1;
287 if (! (obj->version == 0 || obj->version == 1))
288 goto fail;
290 /* Parse u16 data_len */
291 CHECK_REMAINING(2, truncated);
292 obj->data_len = trunnel_ntohs(trunnel_get_uint16(ptr));
293 remaining -= 2; ptr += 2;
295 size_t remaining_after;
296 CHECK_REMAINING(obj->data_len, truncated);
297 remaining_after = remaining - obj->data_len;
298 remaining = obj->data_len;
300 /* Parse union data[version] */
301 switch (obj->version) {
303 case 0:
304 /* Skip to end of union */
305 ptr += remaining; remaining = 0;
306 break;
308 case 1:
310 /* Parse u8 data_v1_digest[TRUNNEL_SENDME_V1_DIGEST_LEN] */
311 CHECK_REMAINING(TRUNNEL_SENDME_V1_DIGEST_LEN, fail);
312 memcpy(obj->data_v1_digest, ptr, TRUNNEL_SENDME_V1_DIGEST_LEN);
313 remaining -= TRUNNEL_SENDME_V1_DIGEST_LEN; ptr += TRUNNEL_SENDME_V1_DIGEST_LEN;
314 break;
316 default:
317 goto fail;
318 break;
320 if (remaining != 0)
321 goto fail;
322 remaining = remaining_after;
324 trunnel_assert(ptr + remaining == input + len_in);
325 return len_in - remaining;
327 truncated:
328 return -2;
329 fail:
330 result = -1;
331 return result;
334 ssize_t
335 sendme_cell_parse(sendme_cell_t **output, const uint8_t *input, const size_t len_in)
337 ssize_t result;
338 *output = sendme_cell_new();
339 if (NULL == *output)
340 return -1;
341 result = sendme_cell_parse_into(*output, input, len_in);
342 if (result < 0) {
343 sendme_cell_free(*output);
344 *output = NULL;
346 return result;