1 #include <stddef.h>
2 #include <stdint.h>
3 #include <string.h>
4 #include <stdbool.h>
5
6 #include <msgpuck/msgpuck.h>
7
8 #include <tarantool/tnt_reply.h>
9 #include <tarantool/tnt_stream.h>
10 #include <tarantool/tnt_buf.h>
11 #include <tarantool/tnt_object.h>
12 #include <tarantool/tnt_mem.h>
13
14 static void
tnt_sbuf_object_free(struct tnt_stream * s)15 tnt_sbuf_object_free(struct tnt_stream *s)
16 {
17 struct tnt_sbuf_object *sbo = TNT_SOBJ_CAST(s);
18 if (sbo->stack) tnt_mem_free(sbo->stack);
19 sbo->stack = NULL;
20 tnt_mem_free(sbo);
21 }
22
23 int
tnt_object_type(struct tnt_stream * s,enum tnt_sbo_type type)24 tnt_object_type(struct tnt_stream *s, enum tnt_sbo_type type)
25 {
26 if (s->wrcnt > 0) return -1;
27 TNT_SOBJ_CAST(s)->type = type;
28 return 0;
29 };
30
31 static int
tnt_sbuf_object_grow_stack(struct tnt_sbuf_object * sbo)32 tnt_sbuf_object_grow_stack(struct tnt_sbuf_object *sbo)
33 {
34 if (sbo->stack_alloc == 128) return -1;
35 uint8_t new_stack_alloc = 2 * sbo->stack_alloc;
36 struct tnt_sbo_stack *stack = tnt_mem_alloc(new_stack_alloc * sizeof(
37 struct tnt_sbo_stack));
38 if (!stack) return -1;
39 sbo->stack_alloc = new_stack_alloc;
40 sbo->stack = stack;
41 return 0;
42 }
43
44 static char *
tnt_sbuf_object_resize(struct tnt_stream * s,size_t size)45 tnt_sbuf_object_resize(struct tnt_stream *s, size_t size) {
46 struct tnt_stream_buf *sb = TNT_SBUF_CAST(s);
47 if (sb->size + size > sb->alloc) {
48 size_t newsize = 2 * (sb->alloc);
49 if (newsize < sb->size + size)
50 newsize = sb->size + size;
51 char *nd = tnt_mem_realloc(sb->data, newsize);
52 if (nd == NULL) {
53 tnt_mem_free(sb->data);
54 return NULL;
55 }
56 sb->data = nd;
57 sb->alloc = newsize;
58 }
59 return sb->data + sb->size;
60 }
61
62 struct tnt_stream *
tnt_object(struct tnt_stream * s)63 tnt_object(struct tnt_stream *s)
64 {
65 int allocated = s == NULL;
66 s = tnt_buf(s);
67 struct tnt_stream_buf *sb = NULL;
68 struct tnt_sbuf_object *sbo = NULL;
69 if (s == NULL)
70 goto error;
71 sb = TNT_SBUF_CAST(s);
72 sb->subdata = tnt_mem_alloc(sizeof(struct tnt_sbuf_object));
73 sb->resize = tnt_sbuf_object_resize;
74 sb->free = tnt_sbuf_object_free;
75 if (sb->subdata == NULL)
76 goto error;
77 sbo = TNT_OBJ_CAST(sb);
78 sbo->stack_size = 0;
79 sbo->stack_alloc = 8;
80 sbo->stack = tnt_mem_alloc(sbo->stack_alloc *
81 sizeof(struct tnt_sbo_stack));
82 if (sbo->stack == NULL)
83 goto error;
84 tnt_object_type(s, TNT_SBO_SIMPLE);
85 return s;
86 error:
87 if (s && allocated)
88 tnt_stream_free(s);
89 return NULL;
90 }
91
92 ssize_t
tnt_object_add_nil(struct tnt_stream * s)93 tnt_object_add_nil (struct tnt_stream *s)
94 {
95 struct tnt_sbuf_object *sbo = TNT_SOBJ_CAST(s);
96 if (sbo->stack_size > 0)
97 sbo->stack[sbo->stack_size - 1].size += 1;
98 char data[2]; char *end = mp_encode_nil(data);
99 return s->write(s, data, end - data);
100 }
101
102 ssize_t
tnt_object_add_int(struct tnt_stream * s,int64_t value)103 tnt_object_add_int (struct tnt_stream *s, int64_t value)
104 {
105 struct tnt_sbuf_object *sbo = TNT_SOBJ_CAST(s);
106 if (sbo->stack_size > 0)
107 sbo->stack[sbo->stack_size - 1].size += 1;
108 char data[10], *end;
109 if (value < 0)
110 end = mp_encode_int(data, value);
111 else
112 end = mp_encode_uint(data, value);
113 return s->write(s, data, end - data);
114 }
115
116 ssize_t
tnt_object_add_str(struct tnt_stream * s,const char * str,uint32_t len)117 tnt_object_add_str (struct tnt_stream *s, const char *str, uint32_t len)
118 {
119 struct tnt_sbuf_object *sbo = TNT_SOBJ_CAST(s);
120 if (sbo->stack_size > 0)
121 sbo->stack[sbo->stack_size - 1].size += 1;
122 struct iovec v[2]; int v_sz = 2;
123 char data[6], *end;
124 end = mp_encode_strl(data, len);
125 v[0].iov_base = data;
126 v[0].iov_len = end - data;
127 v[1].iov_base = (void *)str;
128 v[1].iov_len = len;
129 return s->writev(s, v, v_sz);
130 }
131
132 ssize_t
tnt_object_add_strz(struct tnt_stream * s,const char * strz)133 tnt_object_add_strz (struct tnt_stream *s, const char *strz)
134 {
135 uint32_t len = strlen(strz);
136 return tnt_object_add_str(s, strz, len);
137 }
138
139 ssize_t
tnt_object_add_bin(struct tnt_stream * s,const void * bin,uint32_t len)140 tnt_object_add_bin (struct tnt_stream *s, const void *bin, uint32_t len)
141 {
142 struct tnt_sbuf_object *sbo = TNT_SOBJ_CAST(s);
143 if (sbo->stack_size > 0)
144 sbo->stack[sbo->stack_size - 1].size += 1;
145 struct iovec v[2]; int v_sz = 2;
146 char data[6], *end;
147 end = mp_encode_binl(data, len);
148 v[0].iov_base = data;
149 v[0].iov_len = end - data;
150 v[1].iov_base = (void *)bin;
151 v[1].iov_len = len;
152 return s->writev(s, v, v_sz);
153 }
154
155 ssize_t
tnt_object_add_bool(struct tnt_stream * s,char value)156 tnt_object_add_bool (struct tnt_stream *s, char value)
157 {
158 struct tnt_sbuf_object *sbo = TNT_SOBJ_CAST(s);
159 if (sbo->stack_size > 0)
160 sbo->stack[sbo->stack_size - 1].size += 1;
161 char data[2], *end;
162 end = mp_encode_bool(data, value != 0);
163 return s->write(s, data, end - data);
164 }
165
166 ssize_t
tnt_object_add_float(struct tnt_stream * s,float value)167 tnt_object_add_float (struct tnt_stream *s, float value)
168 {
169 struct tnt_sbuf_object *sbo = TNT_SOBJ_CAST(s);
170 if (sbo->stack_size > 0)
171 sbo->stack[sbo->stack_size - 1].size += 1;
172 char data[6], *end;
173 end = mp_encode_float(data, value);
174 return s->write(s, data, end - data);
175 }
176
177 ssize_t
tnt_object_add_double(struct tnt_stream * s,double value)178 tnt_object_add_double (struct tnt_stream *s, double value)
179 {
180 struct tnt_sbuf_object *sbo = TNT_SOBJ_CAST(s);
181 if (sbo->stack_size > 0)
182 sbo->stack[sbo->stack_size - 1].size += 1;
183 char data[6], *end;
184 end = mp_encode_double(data, value);
185 return s->write(s, data, end - data);
186 }
187
188 static char *
mp_encode_array32(char * data,uint32_t size)189 mp_encode_array32(char *data, uint32_t size)
190 {
191 data = mp_store_u8(data, 0xdd);
192 return mp_store_u32(data, size);
193 }
194
195 ssize_t
tnt_object_add_array(struct tnt_stream * s,uint32_t size)196 tnt_object_add_array (struct tnt_stream *s, uint32_t size)
197 {
198 struct tnt_sbuf_object *sbo = TNT_SOBJ_CAST(s);
199 if (sbo->stack_size > 0)
200 sbo->stack[sbo->stack_size - 1].size += 1;
201 char data[6], *end;
202 struct tnt_stream_buf *sb = TNT_SBUF_CAST(s);
203 if (sbo->stack_size == sbo->stack_alloc)
204 if (tnt_sbuf_object_grow_stack(sbo) == -1)
205 return -1;
206 sbo->stack[sbo->stack_size].size = 0;
207 sbo->stack[sbo->stack_size].offset = sb->size;
208 sbo->stack[sbo->stack_size].type = MP_ARRAY;
209 sbo->stack_size += 1;
210 if (TNT_SOBJ_CAST(s)->type == TNT_SBO_SIMPLE) {
211 end = mp_encode_array(data, size);
212 } else if (TNT_SOBJ_CAST(s)->type == TNT_SBO_SPARSE) {
213 end = mp_encode_array32(data, 0);
214 } else if (TNT_SOBJ_CAST(s)->type == TNT_SBO_PACKED) {
215 end = mp_encode_array(data, 0);
216 } else {
217 return -1;
218 }
219 ssize_t rv = s->write(s, data, end - data);
220 return rv;
221 }
222
223 static char *
mp_encode_map32(char * data,uint32_t size)224 mp_encode_map32(char *data, uint32_t size)
225 {
226 data = mp_store_u8(data, 0xdf);
227 return mp_store_u32(data, size);
228 }
229
230 ssize_t
tnt_object_add_map(struct tnt_stream * s,uint32_t size)231 tnt_object_add_map (struct tnt_stream *s, uint32_t size)
232 {
233 struct tnt_sbuf_object *sbo = TNT_SOBJ_CAST(s);
234 if (sbo->stack_size > 0)
235 sbo->stack[sbo->stack_size - 1].size += 1;
236 char data[6], *end;
237 struct tnt_stream_buf *sb = TNT_SBUF_CAST(s);
238 if (sbo->stack_size == sbo->stack_alloc)
239 if (tnt_sbuf_object_grow_stack(sbo) == -1)
240 return -1;
241 sbo->stack[sbo->stack_size].size = 0;
242 sbo->stack[sbo->stack_size].offset = sb->size;
243 sbo->stack[sbo->stack_size].type = MP_MAP;
244 sbo->stack_size += 1;
245 if (TNT_SOBJ_CAST(s)->type == TNT_SBO_SIMPLE) {
246 end = mp_encode_map(data, size);
247 } else if (TNT_SOBJ_CAST(s)->type == TNT_SBO_SPARSE) {
248 end = mp_encode_map32(data, 0);
249 } else if (TNT_SOBJ_CAST(s)->type == TNT_SBO_PACKED) {
250 end = mp_encode_map(data, 0);
251 } else {
252 return -1;
253 }
254 ssize_t rv = s->write(s, data, end - data);
255 return rv;
256 }
257
258 ssize_t
tnt_object_container_close(struct tnt_stream * s)259 tnt_object_container_close (struct tnt_stream *s)
260 {
261 struct tnt_stream_buf *sb = TNT_SBUF_CAST(s);
262 struct tnt_sbuf_object *sbo = TNT_SOBJ_CAST(s);
263 if (sbo->stack_size == 0) return -1;
264 size_t size = sbo->stack[sbo->stack_size - 1].size;
265 enum mp_type type = sbo->stack[sbo->stack_size - 1].type;
266 size_t offset = sbo->stack[sbo->stack_size - 1].offset;
267 if (type == MP_MAP && size % 2) return -1;
268 sbo->stack_size -= 1;
269 char *lenp = sb->data + offset;
270 if (sbo->type == TNT_SBO_SIMPLE) {
271 return 0;
272 } else if (sbo->type == TNT_SBO_SPARSE) {
273 if (type == MP_MAP)
274 mp_encode_map32(lenp, size/2);
275 else
276 mp_encode_array32(lenp, size);
277 return 0;
278 } else if (sbo->type == TNT_SBO_PACKED) {
279 size_t sz = 0;
280 if (type == MP_MAP)
281 sz = mp_sizeof_map(size);
282 else
283 sz = mp_sizeof_array(size);
284 if (sz > 1) {
285 if (!sb->resize(s, sz - 1))
286 return -1;
287 memmove(lenp + sz, lenp + 1, sb->size - offset - 1);
288 }
289 if (type == MP_MAP) {
290 mp_encode_map(sb->data + offset, size/2);
291 } else {
292 mp_encode_array(sb->data + offset, size);
293 }
294 sb->size += (sz - 1);
295 return 0;
296 }
297 return -1;
298 }
299
tnt_object_verify(struct tnt_stream * obj,int8_t type)300 int tnt_object_verify(struct tnt_stream *obj, int8_t type)
301 {
302 const char *pos = TNT_SBUF_DATA(obj);
303 const char *end = pos + TNT_SBUF_SIZE(obj);
304 if (type >= 0 && mp_typeof(*pos) != (uint8_t) type) return -1;
305 if (mp_check(&pos, end)) return -1;
306 if (pos < end) return -1;
307 return 0;
308 }
309
tnt_object_vformat(struct tnt_stream * s,const char * fmt,va_list vl)310 ssize_t tnt_object_vformat(struct tnt_stream *s, const char *fmt, va_list vl)
311 {
312 if (tnt_object_type(s, TNT_SBO_PACKED) == -1)
313 return -1;
314 ssize_t result = 0, rv = 0;
315
316 for (const char *f = fmt; *f; f++) {
317 if (f[0] == '[') {
318 if ((rv = tnt_object_add_array(s, 0)) == -1)
319 return -1;
320 result += rv;
321 } else if (f[0] == '{') {
322 if ((rv = tnt_object_add_map(s, 0)) == -1)
323 return -1;
324 result += rv;
325 } if (f[0] == ']' || f[0] == '}') {
326 if ((rv = tnt_object_container_close(s)) == -1)
327 return -1;
328 result += rv;
329 } else if (f[0] == '%') {
330 f++;
331 assert(f[0]);
332 int64_t int_value = 0;
333 int int_status = 0; /* 1 - signed, 2 - unsigned */
334
335 if (f[0] == 'd' || f[0] == 'i') {
336 int_value = va_arg(vl, int);
337 int_status = 1;
338 } else if (f[0] == 'u') {
339 int_value = va_arg(vl, unsigned int);
340 int_status = 2;
341 } else if (f[0] == 's') {
342 const char *str = va_arg(vl, const char *);
343 uint32_t len = (uint32_t)strlen(str);
344 if ((rv = tnt_object_add_str(s, str, len)) == -1)
345 return -1;
346 result += rv;
347 } else if (f[0] == '.' && f[1] == '*' && f[2] == 's') {
348 uint32_t len = va_arg(vl, uint32_t);
349 const char *str = va_arg(vl, const char *);
350 if ((rv = tnt_object_add_str(s, str, len)) == -1)
351 return -1;
352 result += rv;
353 f += 2;
354 } else if(f[0] == 'f') {
355 float v = (float)va_arg(vl, double);
356 if ((rv = tnt_object_add_float(s, v)) == -1)
357 return -1;
358 result += rv;
359 } else if(f[0] == 'l' && f[1] == 'f') {
360 double v = va_arg(vl, double);
361 if ((rv = tnt_object_add_double(s, v)) == -1)
362 return -1;
363 result += rv;
364 f++;
365 } else if(f[0] == 'b') {
366 bool v = (bool)va_arg(vl, int);
367 if ((rv = tnt_object_add_bool(s, v)) == -1)
368 return -1;
369 result += rv;
370 } else if (f[0] == 'l'
371 && (f[1] == 'd' || f[1] == 'i')) {
372 int_value = va_arg(vl, long);
373 int_status = 1;
374 f++;
375 } else if (f[0] == 'l' && f[1] == 'u') {
376 int_value = va_arg(vl, unsigned long);
377 int_status = 2;
378 f++;
379 } else if (f[0] == 'l' && f[1] == 'l'
380 && (f[2] == 'd' || f[2] == 'i')) {
381 int_value = va_arg(vl, long long);
382 int_status = 1;
383 f += 2;
384 } else if (f[0] == 'l' && f[1] == 'l' && f[2] == 'u') {
385 int_value = va_arg(vl, unsigned long long);
386 int_status = 2;
387 f += 2;
388 } else if (f[0] == 'h'
389 && (f[1] == 'd' || f[1] == 'i')) {
390 int_value = va_arg(vl, int);
391 int_status = 1;
392 f++;
393 } else if (f[0] == 'h' && f[1] == 'u') {
394 int_value = va_arg(vl, unsigned int);
395 int_status = 2;
396 f++;
397 } else if (f[0] == 'h' && f[1] == 'h'
398 && (f[2] == 'd' || f[2] == 'i')) {
399 int_value = va_arg(vl, int);
400 int_status = 1;
401 f += 2;
402 } else if (f[0] == 'h' && f[1] == 'h' && f[2] == 'u') {
403 int_value = va_arg(vl, unsigned int);
404 int_status = 2;
405 f += 2;
406 } else if (f[0] != '%') {
407 /* unexpected format specifier */
408 assert(false);
409 }
410
411 if (int_status) {
412 if ((rv = tnt_object_add_int(s, int_value)) == -1)
413 return -1;
414 result += rv;
415 }
416 } else if (f[0] == 'N' && f[1] == 'I' && f[2] == 'L') {
417 if ((rv = tnt_object_add_nil(s)) == -1)
418 return -1;
419 result += rv;
420 f += 2;
421 }
422 }
423 return result;
424 }
425
tnt_object_format(struct tnt_stream * s,const char * fmt,...)426 ssize_t tnt_object_format(struct tnt_stream *s, const char *fmt, ...)
427 {
428 va_list args;
429 va_start(args, fmt);
430 ssize_t res = tnt_object_vformat(s, fmt, args);
431 va_end(args);
432 return res;
433 }
434
tnt_object_as(struct tnt_stream * s,char * buf,size_t buf_len)435 struct tnt_stream *tnt_object_as(struct tnt_stream *s, char *buf,
436 size_t buf_len)
437 {
438 if (s == NULL) {
439 s = tnt_object(s);
440 if (s == NULL)
441 return NULL;
442 }
443 struct tnt_stream_buf *sb = TNT_SBUF_CAST(s);
444
445 sb->data = buf;
446 sb->size = buf_len;
447 sb->alloc = buf_len;
448 sb->as = 1;
449
450 return s;
451 }
452
tnt_object_reset(struct tnt_stream * s)453 int tnt_object_reset(struct tnt_stream *s)
454 {
455 struct tnt_stream_buf *sb = TNT_SBUF_CAST(s);
456 struct tnt_sbuf_object *sbo = TNT_SOBJ_CAST(s);
457
458 s->reqid = 0;
459 s->wrcnt = 0;
460 sb->size = 0;
461 sb->rdoff = 0;
462 sbo->stack_size = 0;
463 sbo->type = TNT_SBO_SIMPLE;
464
465 return 0;
466 }
467