blob: 669038e6a1d1ad787d5cd70743cba6b9d32423c2 [file] [log] [blame]
Eric Salama8a9c6c22017-11-10 11:02:23 +01001#ifndef _SPOP_FUNCTIONS_H
2#define _SPOP_FUNCTIONS_H
3
Willy Tarreaua1bd1fa2019-03-29 17:26:33 +01004#include <inttypes.h>
Eric Salama8a9c6c22017-11-10 11:02:23 +01005#include <string.h>
6#include <spoe_types.h>
Eric Salama8a9c6c22017-11-10 11:02:23 +01007
8
9#ifndef MIN
10#define MIN(a, b) (((a) < (b)) ? (a) : (b))
11#endif
12
13#ifndef MAX
14#define MAX(a, b) (((a) > (b)) ? (a) : (b))
15#endif
16
17
18/* Encode the integer <i> into a varint (variable-length integer). The encoded
19 * value is copied in <*buf>. Here is the encoding format:
20 *
21 * 0 <= X < 240 : 1 byte (7.875 bits) [ XXXX XXXX ]
22 * 240 <= X < 2288 : 2 bytes (11 bits) [ 1111 XXXX ] [ 0XXX XXXX ]
23 * 2288 <= X < 264432 : 3 bytes (18 bits) [ 1111 XXXX ] [ 1XXX XXXX ] [ 0XXX XXXX ]
24 * 264432 <= X < 33818864 : 4 bytes (25 bits) [ 1111 XXXX ] [ 1XXX XXXX ]*2 [ 0XXX XXXX ]
25 * 33818864 <= X < 4328786160 : 5 bytes (32 bits) [ 1111 XXXX ] [ 1XXX XXXX ]*3 [ 0XXX XXXX ]
26 * ...
27 *
28 * On success, it returns the number of written bytes and <*buf> is moved after
29 * the encoded value. Otherwise, it returns -1. */
30static inline int
31encode_varint(uint64_t i, char **buf, char *end)
32{
33 unsigned char *p = (unsigned char *)*buf;
34 int r;
35
36 if (p >= (unsigned char *)end)
37 return -1;
38
39 if (i < 240) {
40 *p++ = i;
41 *buf = (char *)p;
42 return 1;
43 }
44
45 *p++ = (unsigned char)i | 240;
46 i = (i - 240) >> 4;
47 while (i >= 128) {
48 if (p >= (unsigned char *)end)
49 return -1;
50 *p++ = (unsigned char)i | 128;
51 i = (i - 128) >> 7;
52 }
53
54 if (p >= (unsigned char *)end)
55 return -1;
56 *p++ = (unsigned char)i;
57
58 r = ((char *)p - *buf);
59 *buf = (char *)p;
60 return r;
61}
62
63/* Decode a varint from <*buf> and save the decoded value in <*i>. See
64 * 'spoe_encode_varint' for details about varint.
65 * On success, it returns the number of read bytes and <*buf> is moved after the
66 * varint. Otherwise, it returns -1. */
67static inline int
68decode_varint(char **buf, char *end, uint64_t *i)
69{
70 unsigned char *p = (unsigned char *)*buf;
71 int r;
72
73 if (p >= (unsigned char *)end)
74 return -1;
75
76 *i = *p++;
77 if (*i < 240) {
78 *buf = (char *)p;
79 return 1;
80 }
81
82 r = 4;
83 do {
84 if (p >= (unsigned char *)end)
85 return -1;
86 *i += (uint64_t)*p << r;
87 r += 7;
88 } while (*p++ >= 128);
89
90 r = ((char *)p - *buf);
91 *buf = (char *)p;
92 return r;
93}
94
95/* Encode a buffer. Its length <len> is encoded as a varint, followed by a copy
96 * of <str>. It must have enough space in <*buf> to encode the buffer, else an
97 * error is triggered.
98 * On success, it returns <len> and <*buf> is moved after the encoded value. If
99 * an error occurred, it returns -1. */
100static inline int
101spoe_encode_buffer(const char *str, size_t len, char **buf, char *end)
102{
103 char *p = *buf;
104 int ret;
105
106 if (p >= end)
107 return -1;
108
109 if (!len) {
110 *p++ = 0;
111 *buf = p;
112 return 0;
113 }
114
115 ret = encode_varint(len, &p, end);
116 if (ret == -1 || p + len > end)
117 return -1;
118
119 memcpy(p, str, len);
120 *buf = p + len;
121 return len;
122}
123
124/* Encode a buffer, possibly partially. It does the same thing than
125 * 'spoe_encode_buffer', but if there is not enough space, it does not fail.
126 * On success, it returns the number of copied bytes and <*buf> is moved after
Joseph Herlantebe14bb2018-11-09 18:36:35 -0800127 * the encoded value. If an error occurred, it returns -1. */
Eric Salama8a9c6c22017-11-10 11:02:23 +0100128static inline int
129spoe_encode_frag_buffer(const char *str, size_t len, char **buf, char *end)
130{
131 char *p = *buf;
132 int ret;
133
134 if (p >= end)
135 return -1;
136
137 if (!len) {
138 *p++ = 0;
139 *buf = p;
140 return 0;
141 }
142
143 ret = encode_varint(len, &p, end);
144 if (ret == -1 || p >= end)
145 return -1;
146
147 ret = (p+len < end) ? len : (end - p);
148 memcpy(p, str, ret);
149 *buf = p + ret;
150 return ret;
151}
152
153/* Decode a buffer. The buffer length is decoded and saved in <*len>. <*str>
154 * points on the first byte of the buffer.
155 * On success, it returns the buffer length and <*buf> is moved after the
156 * encoded buffer. Otherwise, it returns -1. */
157static inline int
158spoe_decode_buffer(char **buf, char *end, char **str, uint64_t *len)
159{
160 char *p = *buf;
161 uint64_t sz;
162 int ret;
163
164 *str = NULL;
165 *len = 0;
166
167 ret = decode_varint(&p, end, &sz);
168 if (ret == -1 || p + sz > end)
169 return -1;
170
171 *str = p;
172 *len = sz;
173 *buf = p + sz;
174 return sz;
175}
176
Willy Tarreau75f42462017-11-14 15:01:22 +0100177/* Encode a typed data using value in <data> and type <type>. On success, it
178 * returns the number of copied bytes and <*buf> is moved after the encoded
Joseph Herlantebe14bb2018-11-09 18:36:35 -0800179 * value. If an error occurred, it returns -1.
Eric Salama8a9c6c22017-11-10 11:02:23 +0100180 *
181 * If the value is too big to be encoded, depending on its type, then encoding
182 * failed or the value is partially encoded. Only strings and binaries can be
183 * partially encoded. In this case, the offset <*off> is updated to known how
184 * many bytes has been encoded. If <*off> is zero at the end, it means that all
185 * data has been encoded. */
186static inline int
Willy Tarreau75f42462017-11-14 15:01:22 +0100187spoe_encode_data(union spoe_data *data, enum spoe_data_type type, unsigned int *off, char **buf, char *end)
Eric Salama8a9c6c22017-11-10 11:02:23 +0100188{
189 char *p = *buf;
190 int ret;
191
192 if (p >= end)
193 return -1;
194
Willy Tarreau75f42462017-11-14 15:01:22 +0100195 if (data == NULL) {
Eric Salama8a9c6c22017-11-10 11:02:23 +0100196 *p++ = SPOE_DATA_T_NULL;
197 goto end;
198 }
199
Willy Tarreau75f42462017-11-14 15:01:22 +0100200 *p++ = type;
201 switch (type) {
202 case SPOE_DATA_T_BOOL:
203 p[-1] |= (data->boolean ? SPOE_DATA_FL_TRUE : SPOE_DATA_FL_FALSE);
204 break;
205
206 case SPOE_DATA_T_INT32:
207 if (encode_varint(data->int32, &p, end) == -1)
208 return -1;
Eric Salama8a9c6c22017-11-10 11:02:23 +0100209 break;
210
Willy Tarreau75f42462017-11-14 15:01:22 +0100211 case SPOE_DATA_T_UINT32:
212 if (encode_varint(data->uint32, &p, end) == -1)
Eric Salama8a9c6c22017-11-10 11:02:23 +0100213 return -1;
214 break;
215
Willy Tarreau75f42462017-11-14 15:01:22 +0100216 case SPOE_DATA_T_INT64:
217 if (encode_varint(data->int64, &p, end) == -1)
218 return -1;
219 break;
220
221 case SPOE_DATA_T_UINT64:
222 if (encode_varint(data->uint64, &p, end) == -1)
223 return -1;
224 break;
225
226 case SPOE_DATA_T_IPV4:
227 if (p + 4 > end)
Eric Salama8a9c6c22017-11-10 11:02:23 +0100228 return -1;
Willy Tarreau75f42462017-11-14 15:01:22 +0100229 memcpy(p, &data->ipv4, 4);
Eric Salama8a9c6c22017-11-10 11:02:23 +0100230 p += 4;
231 break;
232
Willy Tarreau75f42462017-11-14 15:01:22 +0100233 case SPOE_DATA_T_IPV6:
234 if (p + 16 > end)
Eric Salama8a9c6c22017-11-10 11:02:23 +0100235 return -1;
Willy Tarreau75f42462017-11-14 15:01:22 +0100236 memcpy(p, &data->ipv6, 16);
Eric Salama8a9c6c22017-11-10 11:02:23 +0100237 p += 16;
238 break;
239
Willy Tarreau75f42462017-11-14 15:01:22 +0100240 case SPOE_DATA_T_STR:
241 case SPOE_DATA_T_BIN: {
Eric Salama8a9c6c22017-11-10 11:02:23 +0100242 /* Here, we need to know if the sample has already been
243 * partially encoded. If yes, we only need to encode the
244 * remaining, <*off> reprensenting the number of bytes
245 * already encoded. */
246 if (!*off) {
247 /* First evaluation of the sample : encode the
248 * type (string or binary), the buffer length
249 * (as a varint) and at least 1 byte of the
250 * buffer. */
Willy Tarreau75f42462017-11-14 15:01:22 +0100251 ret = spoe_encode_frag_buffer(data->chk.ptr, data->chk.len, &p, end);
Eric Salama8a9c6c22017-11-10 11:02:23 +0100252 if (ret == -1)
253 return -1;
254 }
255 else {
256 /* The sample has been fragmented, encode remaining data */
Willy Tarreau75f42462017-11-14 15:01:22 +0100257 ret = MIN(data->chk.len - *off, end - p);
258 memcpy(p, data->chk.ptr + *off, ret);
Eric Salama8a9c6c22017-11-10 11:02:23 +0100259 p += ret;
260 }
261 /* Now update <*off> */
Willy Tarreau75f42462017-11-14 15:01:22 +0100262 if (ret + *off != data->chk.len)
Eric Salama8a9c6c22017-11-10 11:02:23 +0100263 *off += ret;
264 else
265 *off = 0;
266 break;
267 }
268 /*
269 case SMP_T_METH: {
270 char *m;
271 size_t len;
272
273 *p++ = SPOE_DATA_T_STR;
274 switch (smp->data.u.meth.meth) {
275 case HTTP_METH_OPTIONS: m = "OPTIONS"; len = 7; break;
276 case HTTP_METH_GET : m = "GET"; len = 3; break;
277 case HTTP_METH_HEAD : m = "HEAD"; len = 4; break;
278 case HTTP_METH_POST : m = "POST"; len = 4; break;
279 case HTTP_METH_PUT : m = "PUT"; len = 3; break;
280 case HTTP_METH_DELETE : m = "DELETE"; len = 6; break;
281 case HTTP_METH_TRACE : m = "TRACE"; len = 5; break;
282 case HTTP_METH_CONNECT: m = "CONNECT"; len = 7; break;
283
284 default :
285 m = smp->data.u.meth.str.str;
286 len = smp->data.u.meth.str.len;
287 }
288 if (spoe_encode_buffer(m, len, &p, end) == -1)
289 return -1;
290 break;
291 }
292 */
293
294 default:
Willy Tarreau75f42462017-11-14 15:01:22 +0100295 /* send type NULL for unknown types */
296 p[-1] = SPOE_DATA_T_NULL;
Eric Salama8a9c6c22017-11-10 11:02:23 +0100297 break;
298 }
299
300 end:
301 ret = (p - *buf);
302 *buf = p;
303 return ret;
304}
305
306/* Skip a typed data. If an error occurred, -1 is returned, otherwise the number
307 * of skipped bytes is returned and the <*buf> is moved after skipped data.
308 *
309 * A types data is composed of a type (1 byte) and corresponding data:
310 * - boolean: non additional data (0 bytes)
311 * - integers: a variable-length integer (see decode_varint)
312 * - ipv4: 4 bytes
313 * - ipv6: 16 bytes
314 * - binary and string: a buffer prefixed by its size, a variable-length
315 * integer (see spoe_decode_buffer) */
316static inline int
317spoe_skip_data(char **buf, char *end)
318{
319 char *str, *p = *buf;
320 int type, ret;
321 uint64_t v, sz;
322
323 if (p >= end)
324 return -1;
325
326 type = *p++;
327 switch (type & SPOE_DATA_T_MASK) {
328 case SPOE_DATA_T_BOOL:
329 break;
330 case SPOE_DATA_T_INT32:
331 case SPOE_DATA_T_INT64:
332 case SPOE_DATA_T_UINT32:
333 case SPOE_DATA_T_UINT64:
334 if (decode_varint(&p, end, &v) == -1)
335 return -1;
336 break;
337 case SPOE_DATA_T_IPV4:
338 if (p+4 > end)
339 return -1;
340 p += 4;
341 break;
342 case SPOE_DATA_T_IPV6:
343 if (p+16 > end)
344 return -1;
345 p += 16;
346 break;
347 case SPOE_DATA_T_STR:
348 case SPOE_DATA_T_BIN:
349 /* All the buffer must be skipped */
350 if (spoe_decode_buffer(&p, end, &str, &sz) == -1)
351 return -1;
352 break;
353 }
354
355 ret = (p - *buf);
356 *buf = p;
357 return ret;
358}
359
360/* Decode a typed data and fill <smp>. If an error occurred, -1 is returned,
361 * otherwise the number of read bytes is returned and <*buf> is moved after the
362 * decoded data. See spoe_skip_data for details. */
363static inline int
Willy Tarreau75f42462017-11-14 15:01:22 +0100364spoe_decode_data(char **buf, char *end, union spoe_data *data, enum spoe_data_type *type)
Eric Salama8a9c6c22017-11-10 11:02:23 +0100365{
366 char *str, *p = *buf;
Willy Tarreau75f42462017-11-14 15:01:22 +0100367 int v, r = 0;
Eric Salama8a9c6c22017-11-10 11:02:23 +0100368 uint64_t sz;
369
370 if (p >= end)
371 return -1;
372
Willy Tarreau75f42462017-11-14 15:01:22 +0100373 v = *p++;
374 *type = v & SPOE_DATA_T_MASK;
375
376 switch (*type) {
Eric Salama8a9c6c22017-11-10 11:02:23 +0100377 case SPOE_DATA_T_BOOL:
Willy Tarreau75f42462017-11-14 15:01:22 +0100378 data->boolean = ((v & SPOE_DATA_FL_MASK) == SPOE_DATA_FL_TRUE);
Eric Salama8a9c6c22017-11-10 11:02:23 +0100379 break;
380 case SPOE_DATA_T_INT32:
Willy Tarreau75f42462017-11-14 15:01:22 +0100381 if (decode_varint(&p, end, &sz) == -1)
382 return -1;
383 data->int32 = sz;
384 break;
Eric Salama8a9c6c22017-11-10 11:02:23 +0100385 case SPOE_DATA_T_INT64:
Willy Tarreau75f42462017-11-14 15:01:22 +0100386 if (decode_varint(&p, end, &sz) == -1)
387 return -1;
388 data->int64 = sz;
389 break;
Eric Salama8a9c6c22017-11-10 11:02:23 +0100390 case SPOE_DATA_T_UINT32:
Willy Tarreau75f42462017-11-14 15:01:22 +0100391 if (decode_varint(&p, end, &sz) == -1)
392 return -1;
393 data->uint32 = sz;
394 break;
Eric Salama8a9c6c22017-11-10 11:02:23 +0100395 case SPOE_DATA_T_UINT64:
Willy Tarreau75f42462017-11-14 15:01:22 +0100396 if (decode_varint(&p, end, &sz) == -1)
Eric Salama8a9c6c22017-11-10 11:02:23 +0100397 return -1;
Willy Tarreau75f42462017-11-14 15:01:22 +0100398 data->uint64 = sz;
Eric Salama8a9c6c22017-11-10 11:02:23 +0100399 break;
400 case SPOE_DATA_T_IPV4:
401 if (p+4 > end)
402 return -1;
Willy Tarreau75f42462017-11-14 15:01:22 +0100403 memcpy(&data->ipv4, p, 4);
Eric Salama8a9c6c22017-11-10 11:02:23 +0100404 p += 4;
405 break;
406 case SPOE_DATA_T_IPV6:
407 if (p+16 > end)
408 return -1;
Willy Tarreau75f42462017-11-14 15:01:22 +0100409 memcpy(&data->ipv6, p, 16);
Eric Salama8a9c6c22017-11-10 11:02:23 +0100410 p += 16;
411 break;
412 case SPOE_DATA_T_STR:
413 case SPOE_DATA_T_BIN:
414 /* All the buffer must be decoded */
415 if (spoe_decode_buffer(&p, end, &str, &sz) == -1)
416 return -1;
Willy Tarreau75f42462017-11-14 15:01:22 +0100417 data->chk.ptr = str;
418 data->chk.len = sz;
419 break;
420 default: /* SPOE_DATA_T_NULL, unknown */
Eric Salama8a9c6c22017-11-10 11:02:23 +0100421 break;
422 }
423
424 r = (p - *buf);
425 *buf = p;
426 return r;
427}
428
429
430#endif