blob: 17011d04858efa951b08248a01355f63b1374a8a [file] [log] [blame]
Eric Salama8a9c6c22017-11-10 11:02:23 +01001#ifndef _SPOP_FUNCTIONS_H
2#define _SPOP_FUNCTIONS_H
3
4#include <stdint.h>
5#include <string.h>
6#include <spoe_types.h>
7#include <mini-sample.h>
8
9
10#ifndef MIN
11#define MIN(a, b) (((a) < (b)) ? (a) : (b))
12#endif
13
14#ifndef MAX
15#define MAX(a, b) (((a) > (b)) ? (a) : (b))
16#endif
17
18
19/* Encode the integer <i> into a varint (variable-length integer). The encoded
20 * value is copied in <*buf>. Here is the encoding format:
21 *
22 * 0 <= X < 240 : 1 byte (7.875 bits) [ XXXX XXXX ]
23 * 240 <= X < 2288 : 2 bytes (11 bits) [ 1111 XXXX ] [ 0XXX XXXX ]
24 * 2288 <= X < 264432 : 3 bytes (18 bits) [ 1111 XXXX ] [ 1XXX XXXX ] [ 0XXX XXXX ]
25 * 264432 <= X < 33818864 : 4 bytes (25 bits) [ 1111 XXXX ] [ 1XXX XXXX ]*2 [ 0XXX XXXX ]
26 * 33818864 <= X < 4328786160 : 5 bytes (32 bits) [ 1111 XXXX ] [ 1XXX XXXX ]*3 [ 0XXX XXXX ]
27 * ...
28 *
29 * On success, it returns the number of written bytes and <*buf> is moved after
30 * the encoded value. Otherwise, it returns -1. */
31static inline int
32encode_varint(uint64_t i, char **buf, char *end)
33{
34 unsigned char *p = (unsigned char *)*buf;
35 int r;
36
37 if (p >= (unsigned char *)end)
38 return -1;
39
40 if (i < 240) {
41 *p++ = i;
42 *buf = (char *)p;
43 return 1;
44 }
45
46 *p++ = (unsigned char)i | 240;
47 i = (i - 240) >> 4;
48 while (i >= 128) {
49 if (p >= (unsigned char *)end)
50 return -1;
51 *p++ = (unsigned char)i | 128;
52 i = (i - 128) >> 7;
53 }
54
55 if (p >= (unsigned char *)end)
56 return -1;
57 *p++ = (unsigned char)i;
58
59 r = ((char *)p - *buf);
60 *buf = (char *)p;
61 return r;
62}
63
64/* Decode a varint from <*buf> and save the decoded value in <*i>. See
65 * 'spoe_encode_varint' for details about varint.
66 * On success, it returns the number of read bytes and <*buf> is moved after the
67 * varint. Otherwise, it returns -1. */
68static inline int
69decode_varint(char **buf, char *end, uint64_t *i)
70{
71 unsigned char *p = (unsigned char *)*buf;
72 int r;
73
74 if (p >= (unsigned char *)end)
75 return -1;
76
77 *i = *p++;
78 if (*i < 240) {
79 *buf = (char *)p;
80 return 1;
81 }
82
83 r = 4;
84 do {
85 if (p >= (unsigned char *)end)
86 return -1;
87 *i += (uint64_t)*p << r;
88 r += 7;
89 } while (*p++ >= 128);
90
91 r = ((char *)p - *buf);
92 *buf = (char *)p;
93 return r;
94}
95
96/* Encode a buffer. Its length <len> is encoded as a varint, followed by a copy
97 * of <str>. It must have enough space in <*buf> to encode the buffer, else an
98 * error is triggered.
99 * On success, it returns <len> and <*buf> is moved after the encoded value. If
100 * an error occurred, it returns -1. */
101static inline int
102spoe_encode_buffer(const char *str, size_t len, char **buf, char *end)
103{
104 char *p = *buf;
105 int ret;
106
107 if (p >= end)
108 return -1;
109
110 if (!len) {
111 *p++ = 0;
112 *buf = p;
113 return 0;
114 }
115
116 ret = encode_varint(len, &p, end);
117 if (ret == -1 || p + len > end)
118 return -1;
119
120 memcpy(p, str, len);
121 *buf = p + len;
122 return len;
123}
124
125/* Encode a buffer, possibly partially. It does the same thing than
126 * 'spoe_encode_buffer', but if there is not enough space, it does not fail.
127 * On success, it returns the number of copied bytes and <*buf> is moved after
128 * the encoded value. If an error occured, it returns -1. */
129static inline int
130spoe_encode_frag_buffer(const char *str, size_t len, char **buf, char *end)
131{
132 char *p = *buf;
133 int ret;
134
135 if (p >= end)
136 return -1;
137
138 if (!len) {
139 *p++ = 0;
140 *buf = p;
141 return 0;
142 }
143
144 ret = encode_varint(len, &p, end);
145 if (ret == -1 || p >= end)
146 return -1;
147
148 ret = (p+len < end) ? len : (end - p);
149 memcpy(p, str, ret);
150 *buf = p + ret;
151 return ret;
152}
153
154/* Decode a buffer. The buffer length is decoded and saved in <*len>. <*str>
155 * points on the first byte of the buffer.
156 * On success, it returns the buffer length and <*buf> is moved after the
157 * encoded buffer. Otherwise, it returns -1. */
158static inline int
159spoe_decode_buffer(char **buf, char *end, char **str, uint64_t *len)
160{
161 char *p = *buf;
162 uint64_t sz;
163 int ret;
164
165 *str = NULL;
166 *len = 0;
167
168 ret = decode_varint(&p, end, &sz);
169 if (ret == -1 || p + sz > end)
170 return -1;
171
172 *str = p;
173 *len = sz;
174 *buf = p + sz;
175 return sz;
176}
177
178/* Encode a typed data using value in <smp>. On success, it returns the number
179 * of copied bytes and <*buf> is moved after the encoded value. If an error
180 * occured, it returns -1.
181 *
182 * If the value is too big to be encoded, depending on its type, then encoding
183 * failed or the value is partially encoded. Only strings and binaries can be
184 * partially encoded. In this case, the offset <*off> is updated to known how
185 * many bytes has been encoded. If <*off> is zero at the end, it means that all
186 * data has been encoded. */
187static inline int
188spoe_encode_data(struct sample *smp, unsigned int *off, char **buf, char *end)
189{
190 char *p = *buf;
191 int ret;
192
193 if (p >= end)
194 return -1;
195
196 if (smp == NULL) {
197 *p++ = SPOE_DATA_T_NULL;
198 goto end;
199 }
200
201 switch (smp->data.type) {
202 case SMP_T_BOOL:
203 *p = SPOE_DATA_T_BOOL;
204 *p++ |= ((!smp->data.u.sint) ? SPOE_DATA_FL_FALSE : SPOE_DATA_FL_TRUE);
205 break;
206
207 case SMP_T_SINT:
208 *p++ = SPOE_DATA_T_INT64;
209 if (encode_varint(smp->data.u.sint, &p, end) == -1)
210 return -1;
211 break;
212
213 case SMP_T_IPV4:
214 if (p + 5 > end)
215 return -1;
216 *p++ = SPOE_DATA_T_IPV4;
217 memcpy(p, &smp->data.u.ipv4, 4);
218 p += 4;
219 break;
220
221 case SMP_T_IPV6:
222 if (p + 17 > end)
223 return -1;
224 *p++ = SPOE_DATA_T_IPV6;
225 memcpy(p, &smp->data.u.ipv6, 16);
226 p += 16;
227 break;
228
229 case SMP_T_STR:
230 case SMP_T_BIN: {
231 struct chunk *chk = &smp->data.u.str;
232
233 /* Here, we need to know if the sample has already been
234 * partially encoded. If yes, we only need to encode the
235 * remaining, <*off> reprensenting the number of bytes
236 * already encoded. */
237 if (!*off) {
238 /* First evaluation of the sample : encode the
239 * type (string or binary), the buffer length
240 * (as a varint) and at least 1 byte of the
241 * buffer. */
242 struct chunk *chk = &smp->data.u.str;
243
244 *p++ = (smp->data.type == SMP_T_STR)
245 ? SPOE_DATA_T_STR
246 : SPOE_DATA_T_BIN;
247 ret = spoe_encode_frag_buffer(chk->str, chk->len, &p, end);
248 if (ret == -1)
249 return -1;
250 }
251 else {
252 /* The sample has been fragmented, encode remaining data */
253 ret = MIN(chk->len - *off, end - p);
254 memcpy(p, chk->str + *off, ret);
255 p += ret;
256 }
257 /* Now update <*off> */
258 if (ret + *off != chk->len)
259 *off += ret;
260 else
261 *off = 0;
262 break;
263 }
264 /*
265 case SMP_T_METH: {
266 char *m;
267 size_t len;
268
269 *p++ = SPOE_DATA_T_STR;
270 switch (smp->data.u.meth.meth) {
271 case HTTP_METH_OPTIONS: m = "OPTIONS"; len = 7; break;
272 case HTTP_METH_GET : m = "GET"; len = 3; break;
273 case HTTP_METH_HEAD : m = "HEAD"; len = 4; break;
274 case HTTP_METH_POST : m = "POST"; len = 4; break;
275 case HTTP_METH_PUT : m = "PUT"; len = 3; break;
276 case HTTP_METH_DELETE : m = "DELETE"; len = 6; break;
277 case HTTP_METH_TRACE : m = "TRACE"; len = 5; break;
278 case HTTP_METH_CONNECT: m = "CONNECT"; len = 7; break;
279
280 default :
281 m = smp->data.u.meth.str.str;
282 len = smp->data.u.meth.str.len;
283 }
284 if (spoe_encode_buffer(m, len, &p, end) == -1)
285 return -1;
286 break;
287 }
288 */
289
290 default:
291 *p++ = SPOE_DATA_T_NULL;
292 break;
293 }
294
295 end:
296 ret = (p - *buf);
297 *buf = p;
298 return ret;
299}
300
301/* Skip a typed data. If an error occurred, -1 is returned, otherwise the number
302 * of skipped bytes is returned and the <*buf> is moved after skipped data.
303 *
304 * A types data is composed of a type (1 byte) and corresponding data:
305 * - boolean: non additional data (0 bytes)
306 * - integers: a variable-length integer (see decode_varint)
307 * - ipv4: 4 bytes
308 * - ipv6: 16 bytes
309 * - binary and string: a buffer prefixed by its size, a variable-length
310 * integer (see spoe_decode_buffer) */
311static inline int
312spoe_skip_data(char **buf, char *end)
313{
314 char *str, *p = *buf;
315 int type, ret;
316 uint64_t v, sz;
317
318 if (p >= end)
319 return -1;
320
321 type = *p++;
322 switch (type & SPOE_DATA_T_MASK) {
323 case SPOE_DATA_T_BOOL:
324 break;
325 case SPOE_DATA_T_INT32:
326 case SPOE_DATA_T_INT64:
327 case SPOE_DATA_T_UINT32:
328 case SPOE_DATA_T_UINT64:
329 if (decode_varint(&p, end, &v) == -1)
330 return -1;
331 break;
332 case SPOE_DATA_T_IPV4:
333 if (p+4 > end)
334 return -1;
335 p += 4;
336 break;
337 case SPOE_DATA_T_IPV6:
338 if (p+16 > end)
339 return -1;
340 p += 16;
341 break;
342 case SPOE_DATA_T_STR:
343 case SPOE_DATA_T_BIN:
344 /* All the buffer must be skipped */
345 if (spoe_decode_buffer(&p, end, &str, &sz) == -1)
346 return -1;
347 break;
348 }
349
350 ret = (p - *buf);
351 *buf = p;
352 return ret;
353}
354
355/* Decode a typed data and fill <smp>. If an error occurred, -1 is returned,
356 * otherwise the number of read bytes is returned and <*buf> is moved after the
357 * decoded data. See spoe_skip_data for details. */
358static inline int
359spoe_decode_data(char **buf, char *end, struct sample *smp)
360{
361 char *str, *p = *buf;
362 int type, r = 0;
363 uint64_t sz;
364
365 if (p >= end)
366 return -1;
367
368 type = *p++;
369 switch (type & SPOE_DATA_T_MASK) {
370 case SPOE_DATA_T_BOOL:
371 smp->data.u.sint = ((type & SPOE_DATA_FL_MASK) == SPOE_DATA_FL_TRUE);
372 smp->data.type = SMP_T_BOOL;
373 break;
374 case SPOE_DATA_T_INT32:
375 case SPOE_DATA_T_INT64:
376 case SPOE_DATA_T_UINT32:
377 case SPOE_DATA_T_UINT64:
378 if (decode_varint(&p, end, (uint64_t *)&smp->data.u.sint) == -1)
379 return -1;
380 smp->data.type = SMP_T_SINT;
381 break;
382 case SPOE_DATA_T_IPV4:
383 if (p+4 > end)
384 return -1;
385 smp->data.type = SMP_T_IPV4;
386 memcpy(&smp->data.u.ipv4, p, 4);
387 p += 4;
388 break;
389 case SPOE_DATA_T_IPV6:
390 if (p+16 > end)
391 return -1;
392 memcpy(&smp->data.u.ipv6, p, 16);
393 smp->data.type = SMP_T_IPV6;
394 p += 16;
395 break;
396 case SPOE_DATA_T_STR:
397 case SPOE_DATA_T_BIN:
398 /* All the buffer must be decoded */
399 if (spoe_decode_buffer(&p, end, &str, &sz) == -1)
400 return -1;
401 smp->data.u.str.str = str;
402 smp->data.u.str.len = sz;
403 smp->data.type = (type == SPOE_DATA_T_STR) ? SMP_T_STR : SMP_T_BIN;
404 break;
405 }
406
407 r = (p - *buf);
408 *buf = p;
409 return r;
410}
411
412
413#endif