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