1 /*
2  *  Example debug transport with a local debug message encoder/decoder.
3  *
4  *  Provides a "received dvalue" callback for a fully parsed dvalue (user
5  *  code frees dvalue) and a "cooperate" callback for e.g. UI integration.
6  *  There are a few other callbacks.  See test.c for usage examples.
7  *
8  *  This transport implementation is not multithreaded which means that:
9  *
10  *    - Callbacks to "received dvalue" callback come from the Duktape thread,
11  *      either during normal execution or from duk_debugger_cooperate().
12  *
13  *    - Calls into duk_trans_dvalue_send() must be made from the callbacks
14  *      provided (e.g. "received dvalue" or "cooperate") which use the active
15  *      Duktape thread.
16  *
17  *    - The only exception to this is when Duktape is idle: you can then call
18  *      duk_trans_dvalue_send() from any thread (only one thread at a time).
19  *      When you next call into Duktape or call duk_debugger_cooperate(), the
20  *      queued data will be read and processed by Duktape.
21  *
22  *  There are functions for creating and freeing values; internally they use
23  *  malloc() and free() for memory management.  Duktape heap alloc functions
24  *  are not used to minimize disturbances to the Duktape heap under debugging.
25  *
26  *  Doesn't depend on C99 types; assumes "int" is at least 32 bits, and makes
27  *  a few assumptions about format specifiers.
28  */
29 
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 
34 #include "duktape.h"
35 #include "duk_trans_dvalue.h"
36 
37 /* Define to enable debug prints to stderr. */
38 #if 0
39 #define DEBUG_PRINTS
40 #endif
41 
42 /* Define to enable error prints to stderr. */
43 #if 1
44 #define ERROR_PRINTS
45 #endif
46 
47 /*
48  *  Dvalue handling
49  */
50 
duk_dvalue_alloc(void)51 duk_dvalue *duk_dvalue_alloc(void) {
52 	duk_dvalue *dv = (duk_dvalue *) malloc(sizeof(duk_dvalue));
53 	if (dv) {
54 		memset((void *) dv, 0, sizeof(duk_dvalue));
55 		dv->buf = NULL;
56 	}
57 	return dv;
58 }
59 
duk_dvalue_free(duk_dvalue * dv)60 void duk_dvalue_free(duk_dvalue *dv) {
61 	if (dv) {
62 		free(dv->buf);  /* tolerates NULL */
63 		dv->buf = NULL;
64 		free(dv);
65 	}
66 }
67 
duk__dvalue_bufesc(duk_dvalue * dv,char * buf,size_t maxbytes,int stresc)68 static void duk__dvalue_bufesc(duk_dvalue *dv, char *buf, size_t maxbytes, int stresc) {
69 	size_t i, limit;
70 
71 	*buf = (char) 0;
72 	limit = dv->len > maxbytes ? maxbytes : dv->len;
73 	for (i = 0; i < limit; i++) {
74 		unsigned char c = dv->buf[i];
75 		if (stresc) {
76 			if (c >= 0x20 && c <= 0x7e && c != (char) '"' && c != (char) '\'') {
77 				sprintf(buf, "%c", c);
78 				buf++;
79 			} else {
80 				sprintf(buf, "\\x%02x", (unsigned int) c);
81 				buf += 4;
82 			}
83 		} else {
84 			sprintf(buf, "%02x", (unsigned int) c);
85 			buf += 2;
86 		}
87 	}
88 	if (dv->len > maxbytes) {
89 		sprintf(buf, "...");
90 		buf += 3;
91 	}
92 }
93 
94 /* Caller must provide a buffer at least DUK_DVALUE_TOSTRING_BUFLEN in size. */
duk_dvalue_to_string(duk_dvalue * dv,char * buf)95 void duk_dvalue_to_string(duk_dvalue *dv, char *buf) {
96 	char hexbuf[32 * 4 + 4];  /* 32 hex encoded or \xXX escaped bytes, possible "...", NUL */
97 
98 	if (!dv) {
99 		sprintf(buf, "NULL");
100 		return;
101 	}
102 
103 	switch (dv->tag) {
104 	case DUK_DVALUE_EOM:
105 		sprintf(buf, "EOM");
106 		break;
107 	case DUK_DVALUE_REQ:
108 		sprintf(buf, "REQ");
109 		break;
110 	case DUK_DVALUE_REP:
111 		sprintf(buf, "REP");
112 		break;
113 	case DUK_DVALUE_ERR:
114 		sprintf(buf, "ERR");
115 		break;
116 	case DUK_DVALUE_NFY:
117 		sprintf(buf, "NFY");
118 		break;
119 	case DUK_DVALUE_INTEGER:
120 		sprintf(buf, "%d", dv->i);
121 		break;
122 	case DUK_DVALUE_STRING:
123 		duk__dvalue_bufesc(dv, hexbuf, 32, 1);
124 		sprintf(buf, "str:%ld:\"%s\"", (long) dv->len, hexbuf);
125 		break;
126 	case DUK_DVALUE_BUFFER:
127 		duk__dvalue_bufesc(dv, hexbuf, 32, 0);
128 		sprintf(buf, "buf:%ld:%s", (long) dv->len, hexbuf);
129 		break;
130 	case DUK_DVALUE_UNUSED:
131 		sprintf(buf, "undefined");
132 		break;
133 	case DUK_DVALUE_UNDEFINED:
134 		sprintf(buf, "undefined");
135 		break;
136 	case DUK_DVALUE_NULL:
137 		sprintf(buf, "null");
138 		break;
139 	case DUK_DVALUE_TRUE:
140 		sprintf(buf, "true");
141 		break;
142 	case DUK_DVALUE_FALSE:
143 		sprintf(buf, "false");
144 		break;
145 	case DUK_DVALUE_NUMBER:
146 		if (fpclassify(dv->d) == FP_ZERO) {
147 			if (signbit(dv->d)) {
148 				sprintf(buf, "-0");
149 			} else {
150 				sprintf(buf, "0");
151 			}
152 		} else {
153 			sprintf(buf, "%lg", dv->d);
154 		}
155 		break;
156 	case DUK_DVALUE_OBJECT:
157 		duk__dvalue_bufesc(dv, hexbuf, 32, 0);
158 		sprintf(buf, "obj:%d:%s", (int) dv->i, hexbuf);
159 		break;
160 	case DUK_DVALUE_POINTER:
161 		duk__dvalue_bufesc(dv, hexbuf, 32, 0);
162 		sprintf(buf, "ptr:%s", hexbuf);
163 		break;
164 	case DUK_DVALUE_LIGHTFUNC:
165 		duk__dvalue_bufesc(dv, hexbuf, 32, 0);
166 		sprintf(buf, "lfunc:%04x:%s", (unsigned int) dv->i, hexbuf);
167 		break;
168 	case DUK_DVALUE_HEAPPTR:
169 		duk__dvalue_bufesc(dv, hexbuf, 32, 0);
170 		sprintf(buf, "heapptr:%s", hexbuf);
171 		break;
172 	default:
173 		sprintf(buf, "unknown:%d", (int) dv->tag);
174 	}
175 }
176 
duk_dvalue_make_tag(int tag)177 duk_dvalue *duk_dvalue_make_tag(int tag) {
178 	duk_dvalue *dv = duk_dvalue_alloc();
179 	if (!dv) { return NULL; }
180 	dv->tag = tag;
181 	return dv;
182 }
183 
duk_dvalue_make_tag_int(int tag,int intval)184 duk_dvalue *duk_dvalue_make_tag_int(int tag, int intval) {
185 	duk_dvalue *dv = duk_dvalue_alloc();
186 	if (!dv) { return NULL; }
187 	dv->tag = tag;
188 	dv->i = intval;
189 	return dv;
190 }
191 
duk_dvalue_make_tag_double(int tag,double dblval)192 duk_dvalue *duk_dvalue_make_tag_double(int tag, double dblval) {
193 	duk_dvalue *dv = duk_dvalue_alloc();
194 	if (!dv) { return NULL; }
195 	dv->tag = tag;
196 	dv->d = dblval;
197 	return dv;
198 }
199 
duk_dvalue_make_tag_data(int tag,const char * buf,size_t len)200 duk_dvalue *duk_dvalue_make_tag_data(int tag, const char *buf, size_t len) {
201 	unsigned char *p;
202 	duk_dvalue *dv = duk_dvalue_alloc();
203 	if (!dv) { return NULL; }
204 	/* Alloc size is len + 1 so that a NUL terminator is always
205 	 * guaranteed which is convenient, e.g. you can printf() the
206 	 * value safely.
207 	 */
208 	p = (unsigned char *) malloc(len + 1);
209 	if (!p) {
210 		free(dv);
211 		return NULL;
212 	}
213 	memcpy((void *) p, (const void *) buf, len);
214 	p[len] = (unsigned char) 0;
215 	dv->tag = tag;
216 	dv->buf = p;
217 	dv->len = len;
218 	return dv;
219 }
220 
duk_dvalue_make_tag_int_data(int tag,int intval,const char * buf,size_t len)221 duk_dvalue *duk_dvalue_make_tag_int_data(int tag, int intval, const char *buf, size_t len) {
222 	duk_dvalue *dv = duk_dvalue_make_tag_data(tag, buf, len);
223 	if (!dv) { return NULL; }
224 	dv->i = intval;
225 	return dv;
226 }
227 
228 /*
229  *  Dvalue transport handling
230  */
231 
duk__trans_dvalue_double_byteswap(duk_trans_dvalue_ctx * ctx,volatile unsigned char * p)232 static void duk__trans_dvalue_double_byteswap(duk_trans_dvalue_ctx *ctx, volatile unsigned char *p) {
233 	unsigned char t;
234 
235 	/* Portable IEEE double byteswap.  Relies on runtime detection of
236 	 * host endianness.
237 	 */
238 
239 	if (ctx->double_byteorder == 0) {
240 		/* little endian */
241 		t = p[0]; p[0] = p[7]; p[7] = t;
242 		t = p[1]; p[1] = p[6]; p[6] = t;
243 		t = p[2]; p[2] = p[5]; p[5] = t;
244 		t = p[3]; p[3] = p[4]; p[4] = t;
245 	} else if (ctx->double_byteorder == 1) {
246 		/* big endian: ok as is */
247 		;
248 	} else {
249 		/* mixed endian */
250 		t = p[0]; p[0] = p[3]; p[3] = t;
251 		t = p[1]; p[1] = p[2]; p[2] = t;
252 		t = p[4]; p[4] = p[7]; p[7] = t;
253 		t = p[5]; p[5] = p[6]; p[6] = t;
254 	}
255 }
256 
duk__trans_dvalue_parse_u32(duk_trans_dvalue_ctx * ctx,unsigned char * p)257 static unsigned int duk__trans_dvalue_parse_u32(duk_trans_dvalue_ctx *ctx, unsigned char *p) {
258 	/* Integers are network endian, read back into host format in
259 	 * a portable manner.
260 	 */
261 	(void) ctx;
262 	return (((unsigned int) p[0]) << 24) +
263 	       (((unsigned int) p[1]) << 16) +
264 	       (((unsigned int) p[2]) << 8) +
265 	       (((unsigned int) p[3]) << 0);
266 }
267 
duk__trans_dvalue_parse_i32(duk_trans_dvalue_ctx * ctx,unsigned char * p)268 static int duk__trans_dvalue_parse_i32(duk_trans_dvalue_ctx *ctx, unsigned char *p) {
269 	/* Portable sign handling, doesn't assume 'int' is exactly 32 bits
270 	 * like a direct cast would.
271 	 */
272 	unsigned int tmp = duk__trans_dvalue_parse_u32(ctx, p);
273 	if (tmp & 0x80000000UL) {
274 		return -((int) ((tmp ^ 0xffffffffUL) + 1UL));
275 	} else {
276 		return tmp;
277 	}
278 }
279 
duk__trans_dvalue_parse_u16(duk_trans_dvalue_ctx * ctx,unsigned char * p)280 static unsigned int duk__trans_dvalue_parse_u16(duk_trans_dvalue_ctx *ctx, unsigned char *p) {
281 	/* Integers are network endian, read back into host format. */
282 	(void) ctx;
283 	return (((unsigned int) p[0]) << 8) +
284 	       (((unsigned int) p[1]) << 0);
285 }
286 
duk__trans_dvalue_parse_double(duk_trans_dvalue_ctx * ctx,unsigned char * p)287 static double duk__trans_dvalue_parse_double(duk_trans_dvalue_ctx *ctx, unsigned char *p) {
288 	/* IEEE doubles are network endian, read back into host format. */
289 	volatile union {
290 		double d;
291 		unsigned char b[8];
292 	} u;
293 	memcpy((void *) u.b, (const void *) p, 8);
294 	duk__trans_dvalue_double_byteswap(ctx, u.b);
295 	return u.d;
296 }
297 
duk__trans_dvalue_encode_u32(duk_trans_dvalue_ctx * ctx,unsigned char * p,unsigned int val)298 static unsigned char *duk__trans_dvalue_encode_u32(duk_trans_dvalue_ctx *ctx, unsigned char *p, unsigned int val) {
299 	/* Integers are written in network endian format. */
300 	(void) ctx;
301 	*p++ = (unsigned char) ((val >> 24) & 0xff);
302 	*p++ = (unsigned char) ((val >> 16) & 0xff);
303 	*p++ = (unsigned char) ((val >> 8) & 0xff);
304 	*p++ = (unsigned char) (val & 0xff);
305 	return p;
306 }
307 
duk__trans_dvalue_encode_i32(duk_trans_dvalue_ctx * ctx,unsigned char * p,int val)308 static unsigned char *duk__trans_dvalue_encode_i32(duk_trans_dvalue_ctx *ctx, unsigned char *p, int val) {
309 	return duk__trans_dvalue_encode_u32(ctx, p, (unsigned int) val & 0xffffffffUL);
310 }
311 
duk__trans_dvalue_encode_u16(duk_trans_dvalue_ctx * ctx,unsigned char * p,unsigned int val)312 static unsigned char *duk__trans_dvalue_encode_u16(duk_trans_dvalue_ctx *ctx, unsigned char *p, unsigned int val) {
313 	/* Integers are written in network endian format. */
314 	(void) ctx;
315 	*p++ = (unsigned char) ((val >> 8) & 0xff);
316 	*p++ = (unsigned char) (val & 0xff);
317 	return p;
318 }
319 
duk__trans_dvalue_encode_double(duk_trans_dvalue_ctx * ctx,unsigned char * p,double val)320 static unsigned char *duk__trans_dvalue_encode_double(duk_trans_dvalue_ctx *ctx, unsigned char *p, double val) {
321 	/* IEEE doubles are written in network endian format. */
322 	volatile union {
323 		double d;
324 		unsigned char b[8];
325 	} u;
326 	u.d = val;
327 	duk__trans_dvalue_double_byteswap(ctx, u.b);
328 	memcpy((void *) p, (const void *) u.b, 8);
329 	p += 8;
330 	return p;
331 }
332 
duk__trans_buffer_ensure(duk_trans_buffer * dbuf,size_t space)333 static unsigned char *duk__trans_buffer_ensure(duk_trans_buffer *dbuf, size_t space) {
334 	size_t avail;
335 	size_t used;
336 	size_t new_size;
337 	void *new_alloc;
338 
339 	used = dbuf->write_offset;
340 	avail = dbuf->alloc_size - dbuf->write_offset;
341 
342 	if (avail >= space) {
343 		if (avail - space > 256) {
344 			/* Too big, resize so that we reclaim memory if we have just
345 			 * received a large string/buffer value.
346 			 */
347 			goto do_realloc;
348 		}
349 	} else {
350 		/* Too small, resize. */
351 		goto do_realloc;
352 	}
353 
354 	return dbuf->base + dbuf->write_offset;
355 
356  do_realloc:
357 	new_size = used + space + 256;  /* some extra to reduce resizes */
358 	new_alloc = realloc(dbuf->base, new_size);
359 	if (new_alloc) {
360 		dbuf->base = (unsigned char *) new_alloc;
361 		dbuf->alloc_size = new_size;
362 #if defined(DEBUG_PRINTS)
363 		fprintf(stderr, "%s: resized buffer %p to %ld bytes, read_offset=%ld, write_offset=%ld\n",
364 		        __func__, (void *) dbuf, (long) new_size, (long) dbuf->read_offset, (long) dbuf->write_offset);
365 		fflush(stderr);
366 #endif
367 		return dbuf->base + dbuf->write_offset;
368 	} else {
369 		return NULL;
370 	}
371 }
372 
373 /* When read_offset is large enough, "rebase" buffer by deleting already
374  * read data and updating offsets.
375  */
duk__trans_buffer_rebase(duk_trans_buffer * dbuf)376 static void duk__trans_buffer_rebase(duk_trans_buffer *dbuf) {
377 	if (dbuf->read_offset > 64) {
378 #if defined(DEBUG_PRINTS)
379 		fprintf(stderr, "%s: rebasing buffer %p, read_offset=%ld, write_offset=%ld\n",
380 		        __func__, (void *) dbuf, (long) dbuf->read_offset, (long) dbuf->write_offset);
381 		fflush(stderr);
382 #endif
383 		if (dbuf->write_offset > dbuf->read_offset) {
384 			memmove((void *) dbuf->base, (const void *) (dbuf->base + dbuf->read_offset), dbuf->write_offset - dbuf->read_offset);
385 		}
386 		dbuf->write_offset -= dbuf->read_offset;
387 		dbuf->read_offset = 0;
388 	}
389 }
390 
duk_trans_dvalue_init(void)391 duk_trans_dvalue_ctx *duk_trans_dvalue_init(void) {
392 	volatile union {
393 		double d;
394 		unsigned char b[8];
395 	} u;
396 	duk_trans_dvalue_ctx *ctx = NULL;
397 
398 	ctx = (duk_trans_dvalue_ctx *) malloc(sizeof(duk_trans_dvalue_ctx));
399 	if (!ctx) { goto fail; }
400 	memset((void *) ctx, 0, sizeof(duk_trans_dvalue_ctx));
401 	ctx->received = NULL;
402 	ctx->cooperate = NULL;
403 	ctx->handshake = NULL;
404 	ctx->detached = NULL;
405 	ctx->send_buf.base = NULL;
406 	ctx->recv_buf.base = NULL;
407 
408 	ctx->send_buf.base = malloc(256);
409 	if (!ctx->send_buf.base) { goto fail; }
410 	ctx->send_buf.alloc_size = 256;
411 
412 	ctx->recv_buf.base = malloc(256);
413 	if (!ctx->recv_buf.base) { goto fail; }
414 	ctx->recv_buf.alloc_size = 256;
415 
416 	/* IEEE double byte order, detect at run time (could also use
417 	 * preprocessor defines but that's verbose to make portable).
418 	 *
419 	 * >>> struct.unpack('>d', '1122334455667788'.decode('hex'))
420 	 * (3.841412024471731e-226,)
421 	 * >>> struct.unpack('>d', '8877665544332211'.decode('hex'))
422 	 * (-7.086876636573014e-268,)
423 	 * >>> struct.unpack('>d', '4433221188776655'.decode('hex'))
424 	 * (3.5294303071877444e+20,)
425 	 */
426 	u.b[0] = 0x11; u.b[1] = 0x22; u.b[2] = 0x33; u.b[3] = 0x44;
427 	u.b[4] = 0x55; u.b[5] = 0x66; u.b[6] = 0x77; u.b[7] = 0x88;
428 	if (u.d < 0.0) {
429 		ctx->double_byteorder = 0;  /* little endian */
430 	} else if (u.d < 1.0) {
431 		ctx->double_byteorder = 1;  /* big endian */
432 	} else {
433 		ctx->double_byteorder = 2;  /* mixed endian (arm) */
434 	}
435 #if defined(DEBUG_PRINTS)
436 	fprintf(stderr, "double endianness test value is %lg -> byteorder %d\n",
437 	        u.d, ctx->double_byteorder);
438 	fflush(stderr);
439 #endif
440 
441 	return ctx;
442 
443  fail:
444 	if (ctx) {
445 		free(ctx->recv_buf.base);  /* tolerates NULL */
446 		free(ctx->send_buf.base);  /* tolerates NULL */
447 		free(ctx);
448 	}
449 	return NULL;
450 }
451 
duk_trans_dvalue_free(duk_trans_dvalue_ctx * ctx)452 void duk_trans_dvalue_free(duk_trans_dvalue_ctx *ctx) {
453 	if (ctx) {
454 		free(ctx->send_buf.base);  /* tolerates NULL */
455 		free(ctx->recv_buf.base);  /* tolerates NULL */
456 		free(ctx);
457 	}
458 }
459 
duk_trans_dvalue_send(duk_trans_dvalue_ctx * ctx,duk_dvalue * dv)460 void duk_trans_dvalue_send(duk_trans_dvalue_ctx *ctx, duk_dvalue *dv) {
461 	unsigned char *p;
462 
463 	/* Convert argument dvalue into Duktape debug protocol format.
464 	 * Literal constants are used here for the debug protocol,
465 	 * e.g. initial byte 0x02 is REP, see doc/debugger.rst.
466 	 */
467 
468 #if defined(DEBUG_PRINTS)
469 	{
470 		char buf[DUK_DVALUE_TOSTRING_BUFLEN];
471 		duk_dvalue_to_string(dv, buf);
472 		fprintf(stderr, "%s: sending dvalue: %s\n", __func__, buf);
473 		fflush(stderr);
474 	}
475 #endif
476 
477 	switch (dv->tag) {
478 	case DUK_DVALUE_EOM: {
479 		p = duk__trans_buffer_ensure(&ctx->send_buf, 1);
480 		if (!p) { goto alloc_error; }
481 		*p++ = 0x00;
482 		ctx->send_buf.write_offset += 1;
483 		break;
484 	}
485 	case DUK_DVALUE_REQ: {
486 		p = duk__trans_buffer_ensure(&ctx->send_buf, 1);
487 		if (!p) { goto alloc_error; }
488 		*p++ = 0x01;
489 		ctx->send_buf.write_offset += 1;
490 		break;
491 	}
492 	case DUK_DVALUE_REP: {
493 		p = duk__trans_buffer_ensure(&ctx->send_buf, 1);
494 		if (!p) { goto alloc_error; }
495 		*p++ = 0x02;
496 		ctx->send_buf.write_offset += 1;
497 		break;
498 	}
499 	case DUK_DVALUE_ERR: {
500 		p = duk__trans_buffer_ensure(&ctx->send_buf, 1);
501 		if (!p) { goto alloc_error; }
502 		*p++ = 0x03;
503 		ctx->send_buf.write_offset += 1;
504 		break;
505 	}
506 	case DUK_DVALUE_NFY: {
507 		p = duk__trans_buffer_ensure(&ctx->send_buf, 1);
508 		if (!p) { goto alloc_error; }
509 		*p++ = 0x04;
510 		ctx->send_buf.write_offset += 1;
511 		break;
512 	}
513 	case DUK_DVALUE_INTEGER: {
514 		int i = dv->i;
515 		if (i >= 0 && i <= 63) {
516 			p = duk__trans_buffer_ensure(&ctx->send_buf, 1);
517 			if (!p) { goto alloc_error; }
518 			*p++ = (unsigned char) (0x80 + i);
519 			ctx->send_buf.write_offset += 1;
520 		} else if (i >= 0 && i <= 16383L) {
521 			p = duk__trans_buffer_ensure(&ctx->send_buf, 2);
522 			if (!p) { goto alloc_error; }
523 			*p++ = (unsigned char) (0xc0 + (i >> 8));
524 			*p++ = (unsigned char) (i & 0xff);
525 			ctx->send_buf.write_offset += 2;
526 		} else if (i >= -0x80000000L && i <= 0x7fffffffL) {  /* Harmless warning on some platforms (re: range) */
527 			p = duk__trans_buffer_ensure(&ctx->send_buf, 5);
528 			if (!p) { goto alloc_error; }
529 			*p++ = 0x10;
530 			p = duk__trans_dvalue_encode_i32(ctx, p, i);
531 			ctx->send_buf.write_offset += 5;
532 		} else {
533 			goto dvalue_error;
534 		}
535 		break;
536 	}
537 	case DUK_DVALUE_STRING: {
538 		size_t i = dv->len;
539 		if (i <= 0x1fUL) {
540 			p = duk__trans_buffer_ensure(&ctx->send_buf, 1 + i);
541 			if (!p) { goto alloc_error; }
542 			*p++ = (unsigned char) (0x60 + i);
543 			memcpy((void *) p, (const void *) dv->buf, i);
544 			p += i;
545 			ctx->send_buf.write_offset += 1 + i;
546 		} else if (i <= 0xffffUL) {
547 			p = duk__trans_buffer_ensure(&ctx->send_buf, 3 + i);
548 			if (!p) { goto alloc_error; }
549 			*p++ = 0x12;
550 			p = duk__trans_dvalue_encode_u16(ctx, p, (unsigned int) i);
551 			memcpy((void *) p, (const void *) dv->buf, i);
552 			p += i;
553 			ctx->send_buf.write_offset += 3 + i;
554 		} else if (i <= 0xffffffffUL) {
555 			p = duk__trans_buffer_ensure(&ctx->send_buf, 5 + i);
556 			if (!p) { goto alloc_error; }
557 			*p++ = 0x11;
558 			p = duk__trans_dvalue_encode_u32(ctx, p, (unsigned int) i);
559 			memcpy((void *) p, (const void *) dv->buf, i);
560 			p += i;
561 			ctx->send_buf.write_offset += 5 + i;
562 		} else {
563 			goto dvalue_error;
564 		}
565 		break;
566 	}
567 	case DUK_DVALUE_BUFFER: {
568 		size_t i = dv->len;
569 		if (i <= 0xffffUL) {
570 			p = duk__trans_buffer_ensure(&ctx->send_buf, 3 + i);
571 			if (!p) { goto alloc_error; }
572 			*p++ = 0x14;
573 			p = duk__trans_dvalue_encode_u16(ctx, p, (unsigned int) i);
574 			memcpy((void *) p, (const void *) dv->buf, i);
575 			p += i;
576 			ctx->send_buf.write_offset += 3 + i;
577 		} else if (i <= 0xffffffffUL) {
578 			p = duk__trans_buffer_ensure(&ctx->send_buf, 5 + i);
579 			if (!p) { goto alloc_error; }
580 			*p++ = 0x13;
581 			p = duk__trans_dvalue_encode_u32(ctx, p, (unsigned int) i);
582 			memcpy((void *) p, (const void *) dv->buf, i);
583 			p += i;
584 			ctx->send_buf.write_offset += 5 + i;
585 		} else {
586 			goto dvalue_error;
587 		}
588 		break;
589 	}
590 	case DUK_DVALUE_UNUSED: {
591 		p = duk__trans_buffer_ensure(&ctx->send_buf, 1);
592 		if (!p) { goto alloc_error; }
593 		*p++ = 0x15;
594 		ctx->send_buf.write_offset += 1;
595 		break;
596 	}
597 	case DUK_DVALUE_UNDEFINED: {
598 		p = duk__trans_buffer_ensure(&ctx->send_buf, 1);
599 		if (!p) { goto alloc_error; }
600 		*p++ = 0x16;
601 		ctx->send_buf.write_offset += 1;
602 		break;
603 	}
604 	case DUK_DVALUE_NULL: {
605 		p = duk__trans_buffer_ensure(&ctx->send_buf, 1);
606 		if (!p) { goto alloc_error; }
607 		*p++ = 0x17;
608 		ctx->send_buf.write_offset += 1;
609 		break;
610 	}
611 	case DUK_DVALUE_TRUE: {
612 		p = duk__trans_buffer_ensure(&ctx->send_buf, 1);
613 		if (!p) { goto alloc_error; }
614 		*p++ = 0x18;
615 		ctx->send_buf.write_offset += 1;
616 		break;
617 	}
618 	case DUK_DVALUE_FALSE: {
619 		p = duk__trans_buffer_ensure(&ctx->send_buf, 1);
620 		if (!p) { goto alloc_error; }
621 		*p++ = 0x19;
622 		ctx->send_buf.write_offset += 1;
623 		break;
624 	}
625 	case DUK_DVALUE_NUMBER: {
626 		p = duk__trans_buffer_ensure(&ctx->send_buf, 9);
627 		if (!p) { goto alloc_error; }
628 		*p++ = 0x1a;
629 		p = duk__trans_dvalue_encode_double(ctx, p, dv->d);
630 		ctx->send_buf.write_offset += 9;
631 		break;
632 	}
633 	case DUK_DVALUE_OBJECT: {
634 		size_t i = dv->len;
635 		if (i <= 0xffUL && dv->i >= 0 && dv->i <= 0xffL) {
636 			p = duk__trans_buffer_ensure(&ctx->send_buf, 3 + i);
637 			if (!p) { goto alloc_error; }
638 			*p++ = 0x1b;
639 			*p++ = (unsigned char) dv->i;
640 			*p++ = (unsigned char) i;
641 			memcpy((void *) p, (const void *) dv->buf, i);
642 			ctx->send_buf.write_offset += 3 + i;
643 		} else {
644 			goto dvalue_error;
645 		}
646 		break;
647 	}
648 	case DUK_DVALUE_POINTER: {
649 		size_t i = dv->len;
650 		if (i <= 0xffUL) {
651 			p = duk__trans_buffer_ensure(&ctx->send_buf, 2 + i);
652 			if (!p) { goto alloc_error; }
653 			*p++ = 0x1c;
654 			*p++ = (unsigned char) i;
655 			memcpy((void *) p, (const void *) dv->buf, i);
656 			ctx->send_buf.write_offset += 2 + i;
657 		} else {
658 			goto dvalue_error;
659 		}
660 		break;
661 	}
662 	case DUK_DVALUE_LIGHTFUNC: {
663 		size_t i = dv->len;
664 		if (i <= 0xffUL && dv->i >= 0 && dv->i <= 0xffffL) {
665 			p = duk__trans_buffer_ensure(&ctx->send_buf, 4 + i);
666 			if (!p) { goto alloc_error; }
667 			*p++ = 0x1d;
668 			p = duk__trans_dvalue_encode_u16(ctx, p, (unsigned int) dv->i);
669 			*p++ = (unsigned char) i;
670 			memcpy((void *) p, (const void *) dv->buf, i);
671 			ctx->send_buf.write_offset += 4 + i;
672 		} else {
673 			goto dvalue_error;
674 		}
675 		break;
676 	}
677 	case DUK_DVALUE_HEAPPTR: {
678 		size_t i = dv->len;
679 		if (i <= 0xffUL) {
680 			p = duk__trans_buffer_ensure(&ctx->send_buf, 2 + i);
681 			if (!p) { goto alloc_error; }
682 			*p++ = 0x1e;
683 			*p++ = (unsigned char) i;
684 			memcpy((void *) p, (const void *) dv->buf, i);
685 			ctx->send_buf.write_offset += 2 + i;
686 		} else {
687 			goto dvalue_error;
688 		}
689 		break;
690 	}
691 	default: {
692 		goto dvalue_error;
693 	}
694 	}  /* end switch */
695 
696 	return;
697 
698  dvalue_error:
699 #if defined(ERROR_PRINTS)
700 	fprintf(stderr, "%s: internal error, argument dvalue is invalid\n", __func__);
701 	fflush(stdout);
702 #endif
703 	return;
704 
705  alloc_error:
706 #if defined(ERROR_PRINTS)
707 	fprintf(stderr, "%s: internal error, failed to allocate space for write\n", __func__);
708 	fflush(stdout);
709 #endif
710 	return;
711 }
712 
duk__trans_dvalue_send_and_free(duk_trans_dvalue_ctx * ctx,duk_dvalue * dv)713 static void duk__trans_dvalue_send_and_free(duk_trans_dvalue_ctx *ctx, duk_dvalue *dv) {
714 	if (!dv) { return; }
715 	duk_trans_dvalue_send(ctx, dv);
716 	duk_dvalue_free(dv);
717 }
718 
duk_trans_dvalue_send_eom(duk_trans_dvalue_ctx * ctx)719 void duk_trans_dvalue_send_eom(duk_trans_dvalue_ctx *ctx) {
720 	duk__trans_dvalue_send_and_free(ctx, duk_dvalue_make_tag(DUK_DVALUE_EOM));
721 }
722 
duk_trans_dvalue_send_req(duk_trans_dvalue_ctx * ctx)723 void duk_trans_dvalue_send_req(duk_trans_dvalue_ctx *ctx) {
724 	duk__trans_dvalue_send_and_free(ctx, duk_dvalue_make_tag(DUK_DVALUE_REQ));
725 }
726 
duk_trans_dvalue_send_rep(duk_trans_dvalue_ctx * ctx)727 void duk_trans_dvalue_send_rep(duk_trans_dvalue_ctx *ctx) {
728 	duk__trans_dvalue_send_and_free(ctx, duk_dvalue_make_tag(DUK_DVALUE_REP));
729 }
730 
duk_trans_dvalue_send_err(duk_trans_dvalue_ctx * ctx)731 void duk_trans_dvalue_send_err(duk_trans_dvalue_ctx *ctx) {
732 	duk__trans_dvalue_send_and_free(ctx, duk_dvalue_make_tag(DUK_DVALUE_ERR));
733 }
734 
duk_trans_dvalue_send_nfy(duk_trans_dvalue_ctx * ctx)735 void duk_trans_dvalue_send_nfy(duk_trans_dvalue_ctx *ctx) {
736 	duk__trans_dvalue_send_and_free(ctx, duk_dvalue_make_tag(DUK_DVALUE_NFY));
737 }
738 
duk_trans_dvalue_send_integer(duk_trans_dvalue_ctx * ctx,int val)739 void duk_trans_dvalue_send_integer(duk_trans_dvalue_ctx *ctx, int val) {
740 	duk__trans_dvalue_send_and_free(ctx, duk_dvalue_make_tag_int(DUK_DVALUE_INTEGER, val));
741 }
742 
duk_trans_dvalue_send_string(duk_trans_dvalue_ctx * ctx,const char * str)743 void duk_trans_dvalue_send_string(duk_trans_dvalue_ctx *ctx, const char *str) {
744 	duk__trans_dvalue_send_and_free(ctx, duk_dvalue_make_tag_data(DUK_DVALUE_STRING, str, strlen(str)));
745 }
746 
duk_trans_dvalue_send_lstring(duk_trans_dvalue_ctx * ctx,const char * str,size_t len)747 void duk_trans_dvalue_send_lstring(duk_trans_dvalue_ctx *ctx, const char *str, size_t len) {
748 	duk__trans_dvalue_send_and_free(ctx, duk_dvalue_make_tag_data(DUK_DVALUE_STRING, str, len));
749 }
750 
duk_trans_dvalue_send_buffer(duk_trans_dvalue_ctx * ctx,const char * buf,size_t len)751 void duk_trans_dvalue_send_buffer(duk_trans_dvalue_ctx *ctx, const char *buf, size_t len) {
752 	duk__trans_dvalue_send_and_free(ctx, duk_dvalue_make_tag_data(DUK_DVALUE_BUFFER, buf, len));
753 }
754 
duk_trans_dvalue_send_unused(duk_trans_dvalue_ctx * ctx)755 void duk_trans_dvalue_send_unused(duk_trans_dvalue_ctx *ctx) {
756 	duk__trans_dvalue_send_and_free(ctx, duk_dvalue_make_tag(DUK_DVALUE_UNUSED));
757 }
758 
duk_trans_dvalue_send_undefined(duk_trans_dvalue_ctx * ctx)759 void duk_trans_dvalue_send_undefined(duk_trans_dvalue_ctx *ctx) {
760 	duk__trans_dvalue_send_and_free(ctx, duk_dvalue_make_tag(DUK_DVALUE_UNDEFINED));
761 }
762 
duk_trans_dvalue_send_null(duk_trans_dvalue_ctx * ctx)763 void duk_trans_dvalue_send_null(duk_trans_dvalue_ctx *ctx) {
764 	duk__trans_dvalue_send_and_free(ctx, duk_dvalue_make_tag(DUK_DVALUE_NULL));
765 }
766 
duk_trans_dvalue_send_true(duk_trans_dvalue_ctx * ctx)767 void duk_trans_dvalue_send_true(duk_trans_dvalue_ctx *ctx) {
768 	duk__trans_dvalue_send_and_free(ctx, duk_dvalue_make_tag(DUK_DVALUE_TRUE));
769 }
770 
duk_trans_dvalue_send_false(duk_trans_dvalue_ctx * ctx)771 void duk_trans_dvalue_send_false(duk_trans_dvalue_ctx *ctx) {
772 	duk__trans_dvalue_send_and_free(ctx, duk_dvalue_make_tag(DUK_DVALUE_FALSE));
773 }
774 
duk_trans_dvalue_send_number(duk_trans_dvalue_ctx * ctx,double val)775 void duk_trans_dvalue_send_number(duk_trans_dvalue_ctx *ctx, double val) {
776 	duk__trans_dvalue_send_and_free(ctx, duk_dvalue_make_tag_double(DUK_DVALUE_NUMBER, val));
777 }
778 
duk_trans_dvalue_send_object(duk_trans_dvalue_ctx * ctx,int classnum,const char * ptr_data,size_t ptr_len)779 void duk_trans_dvalue_send_object(duk_trans_dvalue_ctx *ctx, int classnum, const char *ptr_data, size_t ptr_len) {
780 	duk__trans_dvalue_send_and_free(ctx, duk_dvalue_make_tag_int_data(DUK_DVALUE_OBJECT, classnum, ptr_data, ptr_len));
781 }
782 
duk_trans_dvalue_send_pointer(duk_trans_dvalue_ctx * ctx,const char * ptr_data,size_t ptr_len)783 void duk_trans_dvalue_send_pointer(duk_trans_dvalue_ctx *ctx, const char *ptr_data, size_t ptr_len) {
784 	duk__trans_dvalue_send_and_free(ctx, duk_dvalue_make_tag_data(DUK_DVALUE_POINTER, ptr_data, ptr_len));
785 }
786 
duk_trans_dvalue_send_lightfunc(duk_trans_dvalue_ctx * ctx,int lf_flags,const char * ptr_data,size_t ptr_len)787 void duk_trans_dvalue_send_lightfunc(duk_trans_dvalue_ctx *ctx, int lf_flags, const char *ptr_data, size_t ptr_len) {
788 	duk__trans_dvalue_send_and_free(ctx, duk_dvalue_make_tag_int_data(DUK_DVALUE_LIGHTFUNC, lf_flags, ptr_data, ptr_len));
789 }
790 
duk_trans_dvalue_send_heapptr(duk_trans_dvalue_ctx * ctx,const char * ptr_data,size_t ptr_len)791 void duk_trans_dvalue_send_heapptr(duk_trans_dvalue_ctx *ctx, const char *ptr_data, size_t ptr_len) {
792 	duk__trans_dvalue_send_and_free(ctx, duk_dvalue_make_tag_data(DUK_DVALUE_HEAPPTR, ptr_data, ptr_len));
793 }
794 
duk_trans_dvalue_send_req_cmd(duk_trans_dvalue_ctx * ctx,int cmd)795 void duk_trans_dvalue_send_req_cmd(duk_trans_dvalue_ctx *ctx, int cmd) {
796 	duk_trans_dvalue_send_req(ctx);
797 	duk_trans_dvalue_send_integer(ctx, cmd);
798 }
799 
duk__trans_trial_parse_dvalue(duk_trans_dvalue_ctx * ctx)800 static duk_dvalue *duk__trans_trial_parse_dvalue(duk_trans_dvalue_ctx *ctx) {
801 	unsigned char *p;
802 	size_t len;
803 	unsigned char ib;
804 	duk_dvalue *dv;
805 	size_t datalen;
806 
807 	p = ctx->recv_buf.base + ctx->recv_buf.read_offset;
808 	len = ctx->recv_buf.write_offset - ctx->recv_buf.read_offset;
809 
810 	if (len == 0) {
811 		return NULL;
812 	}
813 	ib = p[0];
814 
815 #if defined(DEBUG_PRINTS)
816 	{
817 		size_t i;
818 		fprintf(stderr, "%s: parsing dvalue, window:", __func__);
819 		for (i = 0; i < 16; i++) {
820 			if (i < len) {
821 				fprintf(stderr, " %02x", (unsigned int) p[i]);
822 			} else {
823 				fprintf(stderr, " ??");
824 			}
825 		}
826 		fprintf(stderr, " (length %ld, read_offset %ld, write_offset %ld, alloc_size %ld)\n",
827 		        (long) len, (long) ctx->recv_buf.read_offset, (long) ctx->recv_buf.write_offset,
828 		        (long) ctx->recv_buf.alloc_size);
829 		fflush(stderr);
830 	}
831 #endif
832 
833 	if (ib <= 0x1fU) {
834 		/* 0x00 ... 0x1f */
835 		switch (ib) {
836 		case 0x00: {
837 			ctx->recv_buf.read_offset += 1;
838 			dv = duk_dvalue_make_tag(DUK_DVALUE_EOM);
839 			if (!dv) { goto alloc_error; }
840 			return dv;
841 		}
842 		case 0x01: {
843 			ctx->recv_buf.read_offset += 1;
844 			dv = duk_dvalue_make_tag(DUK_DVALUE_REQ);
845 			if (!dv) { goto alloc_error; }
846 			return dv;
847 		}
848 		case 0x02: {
849 			ctx->recv_buf.read_offset += 1;
850 			dv = duk_dvalue_make_tag(DUK_DVALUE_REP);
851 			if (!dv) { goto alloc_error; }
852 			return dv;
853 		}
854 		case 0x03: {
855 			ctx->recv_buf.read_offset += 1;
856 			dv = duk_dvalue_make_tag(DUK_DVALUE_ERR);
857 			if (!dv) { goto alloc_error; }
858 			return dv;
859 		}
860 		case 0x04: {
861 			ctx->recv_buf.read_offset += 1;
862 			dv = duk_dvalue_make_tag(DUK_DVALUE_NFY);
863 			if (!dv) { goto alloc_error; }
864 			return dv;
865 		}
866 		case 0x10: {
867 			int intval;
868 			if (len < 5) { goto partial; }
869 			intval = duk__trans_dvalue_parse_i32(ctx, p + 1);
870 			ctx->recv_buf.read_offset += 5;
871 			dv = duk_dvalue_make_tag_int(DUK_DVALUE_INTEGER, intval);
872 			if (!dv) { goto alloc_error; }
873 			return dv;
874 		}
875 		case 0x11: {
876 			if (len < 5) { goto partial; }
877 			datalen = (size_t) duk__trans_dvalue_parse_u32(ctx, p + 1);
878 			if (len < 5 + datalen) { goto partial; }
879 			ctx->recv_buf.read_offset += 5 + datalen;
880 			dv = duk_dvalue_make_tag_data(DUK_DVALUE_STRING, (const char *) (p + 5), datalen);
881 			if (!dv) { goto alloc_error; }
882 			return dv;
883 		}
884 		case 0x12: {
885 			if (len < 3) { goto partial; }
886 			datalen = (size_t) duk__trans_dvalue_parse_u16(ctx, p + 1);
887 			if (len < 3 + datalen) { goto partial; }
888 			ctx->recv_buf.read_offset += 3 + datalen;
889 			dv = duk_dvalue_make_tag_data(DUK_DVALUE_STRING, (const char *) (p + 3), datalen);
890 			if (!dv) { goto alloc_error; }
891 			return dv;
892 		}
893 		case 0x13: {
894 			if (len < 5) { goto partial; }
895 			datalen = (size_t) duk__trans_dvalue_parse_u32(ctx, p + 1);
896 			if (len < 5 + datalen) { goto partial; }
897 			ctx->recv_buf.read_offset += 5 + datalen;
898 			dv = duk_dvalue_make_tag_data(DUK_DVALUE_BUFFER, (const char *) (p + 5), datalen);
899 			if (!dv) { goto alloc_error; }
900 			return dv;
901 		}
902 		case 0x14: {
903 			if (len < 3) { goto partial; }
904 			datalen = (size_t) duk__trans_dvalue_parse_u16(ctx, p + 1);
905 			if (len < 3 + datalen) { goto partial; }
906 			ctx->recv_buf.read_offset += 3 + datalen;
907 			dv = duk_dvalue_make_tag_data(DUK_DVALUE_BUFFER, (const char *) (p + 3), datalen);
908 			if (!dv) { goto alloc_error; }
909 			return dv;
910 		}
911 		case 0x15: {
912 			ctx->recv_buf.read_offset += 1;
913 			dv = duk_dvalue_make_tag(DUK_DVALUE_UNUSED);
914 			if (!dv) { goto alloc_error; }
915 			return dv;
916 		}
917 		case 0x16: {
918 			ctx->recv_buf.read_offset += 1;
919 			dv = duk_dvalue_make_tag(DUK_DVALUE_UNDEFINED);
920 			if (!dv) { goto alloc_error; }
921 			return dv;
922 		}
923 		case 0x17: {
924 			ctx->recv_buf.read_offset += 1;
925 			dv = duk_dvalue_make_tag(DUK_DVALUE_NULL);
926 			if (!dv) { goto alloc_error; }
927 			return dv;
928 		}
929 		case 0x18: {
930 			ctx->recv_buf.read_offset += 1;
931 			dv = duk_dvalue_make_tag(DUK_DVALUE_TRUE);
932 			if (!dv) { goto alloc_error; }
933 			return dv;
934 		}
935 		case 0x19: {
936 			ctx->recv_buf.read_offset += 1;
937 			dv = duk_dvalue_make_tag(DUK_DVALUE_FALSE);
938 			if (!dv) { goto alloc_error; }
939 			return dv;
940 		}
941 		case 0x1a: {
942 			double dblval;
943 			if (len < 9) { goto partial; }
944 			dblval = duk__trans_dvalue_parse_double(ctx, p + 1);
945 			ctx->recv_buf.read_offset += 9;
946 			dv = duk_dvalue_make_tag_double(DUK_DVALUE_NUMBER, dblval);
947 			if (!dv) { goto alloc_error; }
948 			return dv;
949 		}
950 		case 0x1b: {
951 			int classnum;
952 			if (len < 3) { goto partial; }
953 			datalen = (size_t) p[2];
954 			if (len < 3 + datalen) { goto partial; }
955 			classnum = (int) p[1];
956 			ctx->recv_buf.read_offset += 3 + datalen;
957 			dv = duk_dvalue_make_tag_int_data(DUK_DVALUE_OBJECT, classnum, (const char *) (p + 3), datalen);
958 			if (!dv) { goto alloc_error; }
959 			return dv;
960 		}
961 		case 0x1c: {
962 			if (len < 2) { goto partial; }
963 			datalen = (size_t) p[1];
964 			if (len < 2 + datalen) { goto partial; }
965 			ctx->recv_buf.read_offset += 2 + datalen;
966 			dv = duk_dvalue_make_tag_data(DUK_DVALUE_POINTER, (const char *) (p + 2), datalen);
967 			if (!dv) { goto alloc_error; }
968 			return dv;
969 		}
970 		case 0x1d: {
971 			int lf_flags;
972 			if (len < 4) { goto partial; }
973 			datalen = (size_t) p[3];
974 			if (len < 4 + datalen) { goto partial; }
975 			lf_flags = (int) duk__trans_dvalue_parse_u16(ctx, p + 1);
976 			ctx->recv_buf.read_offset += 4 + datalen;
977 			dv = duk_dvalue_make_tag_int_data(DUK_DVALUE_LIGHTFUNC, lf_flags, (const char *) (p + 4), datalen);
978 			if (!dv) { goto alloc_error; }
979 			return dv;
980 		}
981 		case 0x1e: {
982 			if (len < 2) { goto partial; }
983 			datalen = (size_t) p[1];
984 			if (len < 2 + datalen) { goto partial; }
985 			ctx->recv_buf.read_offset += 2 + datalen;
986 			dv = duk_dvalue_make_tag_data(DUK_DVALUE_HEAPPTR, (const char *) (p + 2), datalen);
987 			if (!dv) { goto alloc_error; }
988 			return dv;
989 		}
990 		default: {
991 			goto format_error;
992 		}
993 		}  /* end switch */
994 	} else if (ib <= 0x5fU) {
995 		/* 0x20 ... 0x5f */
996 		goto format_error;
997 	} else if (ib <= 0x7fU) {
998 		/* 0x60 ... 0x7f */
999 		datalen = (size_t) (ib - 0x60U);
1000 		if (len < 1 + datalen) { goto partial; }
1001 		ctx->recv_buf.read_offset += 1 + datalen;
1002 		dv = duk_dvalue_make_tag_data(DUK_DVALUE_STRING, (const char *) (p + 1), datalen);
1003 		if (!dv) { goto alloc_error; }
1004 		return dv;
1005 	} else if (ib <= 0xbfU) {
1006 		/* 0x80 ... 0xbf */
1007 		int intval;
1008 		intval = (int) (ib - 0x80U);
1009 		ctx->recv_buf.read_offset += 1;
1010 		dv = duk_dvalue_make_tag_int(DUK_DVALUE_INTEGER, intval);
1011 		if (!dv) { goto alloc_error; }
1012 		return dv;
1013 	} else {
1014 		/* 0xc0 ... 0xff */
1015 		int intval;
1016 		if (len < 2) { goto partial; }
1017 		intval = (((int) (ib - 0xc0U)) << 8) + (int) p[1];
1018 		ctx->recv_buf.read_offset += 2;
1019 		dv = duk_dvalue_make_tag_int(DUK_DVALUE_INTEGER, intval);
1020 		if (!dv) { goto alloc_error; }
1021 		return dv;
1022 	}
1023 
1024 	/* never here */
1025 
1026  partial:
1027 	return NULL;
1028 
1029  alloc_error:
1030 #if defined(ERROR_PRINTS)
1031 	fprintf(stderr, "%s: internal error, cannot allocate space for dvalue\n", __func__);
1032 	fflush(stdout);
1033 #endif
1034 	return NULL;
1035 
1036  format_error:
1037 #if defined(ERROR_PRINTS)
1038 	fprintf(stderr, "%s: internal error, dvalue format error\n", __func__);
1039 	fflush(stdout);
1040 #endif
1041 	return NULL;
1042 }
1043 
duk__trans_trial_parse_handshake(duk_trans_dvalue_ctx * ctx)1044 static duk_dvalue *duk__trans_trial_parse_handshake(duk_trans_dvalue_ctx *ctx) {
1045 	unsigned char *p;
1046 	size_t len;
1047 	duk_dvalue *dv;
1048 	size_t i;
1049 
1050 	p = ctx->recv_buf.base + ctx->recv_buf.read_offset;
1051 	len = ctx->recv_buf.write_offset - ctx->recv_buf.read_offset;
1052 
1053 	for (i = 0; i < len; i++) {
1054 		if (p[i] == 0x0a) {
1055 			/* Handshake line is returned as a dvalue for convenience; it's
1056 			 * not actually a part of the dvalue phase of the protocol.
1057 			 */
1058 			ctx->recv_buf.read_offset += i + 1;
1059 			dv = duk_dvalue_make_tag_data(DUK_DVALUE_STRING, (const char *) p, i);
1060 			if (!dv) { goto alloc_error; }
1061 			return dv;
1062 		}
1063 	}
1064 
1065 	return NULL;
1066 
1067  alloc_error:
1068 #if defined(ERROR_PRINTS)
1069 	fprintf(stderr, "%s: internal error, cannot allocate space for handshake line\n", __func__);
1070 	fflush(stdout);
1071 #endif
1072 	return NULL;
1073 }
1074 
duk__trans_call_cooperate(duk_trans_dvalue_ctx * ctx,int block)1075 static void duk__trans_call_cooperate(duk_trans_dvalue_ctx *ctx, int block) {
1076 	if (ctx->cooperate) {
1077 		ctx->cooperate(ctx, block);
1078 	}
1079 }
1080 
duk__trans_call_received(duk_trans_dvalue_ctx * ctx,duk_dvalue * dv)1081 static void duk__trans_call_received(duk_trans_dvalue_ctx *ctx, duk_dvalue *dv) {
1082 	if (ctx->received) {
1083 		ctx->received(ctx, dv);
1084 	}
1085 }
1086 
duk__trans_call_handshake(duk_trans_dvalue_ctx * ctx,const char * line)1087 static void duk__trans_call_handshake(duk_trans_dvalue_ctx *ctx, const char *line) {
1088 	if (ctx->handshake) {
1089 		ctx->handshake(ctx, line);
1090 	}
1091 }
1092 
duk__trans_call_detached(duk_trans_dvalue_ctx * ctx)1093 static void duk__trans_call_detached(duk_trans_dvalue_ctx *ctx) {
1094 	if (ctx->detached) {
1095 		ctx->detached(ctx);
1096 	}
1097 }
1098 
1099 /*
1100  *  Duktape callbacks
1101  */
1102 
duk_trans_dvalue_read_cb(void * udata,char * buffer,duk_size_t length)1103 duk_size_t duk_trans_dvalue_read_cb(void *udata, char *buffer, duk_size_t length) {
1104 	duk_trans_dvalue_ctx *ctx = (duk_trans_dvalue_ctx *) udata;
1105 
1106 #if defined(DEBUG_PRINTS)
1107 	fprintf(stderr, "%s: %p %p %ld\n", __func__, udata, (void *) buffer, (long) length);
1108 	fflush(stderr);
1109 #endif
1110 
1111 	duk__trans_call_cooperate(ctx, 0);
1112 
1113 	for (;;) {
1114 		size_t avail, now;
1115 
1116 		avail = (size_t) (ctx->send_buf.write_offset - ctx->send_buf.read_offset);
1117 		if (avail == 0) {
1118 			/* Must cooperate until user callback provides data.  From
1119 			 * Duktape's perspective we MUST block until data is received.
1120 			 */
1121 			duk__trans_call_cooperate(ctx, 1);
1122 		} else {
1123 			now = avail;
1124 			if (now > length) {
1125 				now = length;
1126 			}
1127 			memcpy((void *) buffer, (const void *) (ctx->send_buf.base + ctx->send_buf.read_offset), now);
1128 			duk__trans_buffer_rebase(&ctx->send_buf);
1129 			ctx->send_buf.read_offset += now;
1130 			return now;
1131 		}
1132 	}
1133 }
1134 
duk_trans_dvalue_write_cb(void * udata,const char * buffer,duk_size_t length)1135 duk_size_t duk_trans_dvalue_write_cb(void *udata, const char *buffer, duk_size_t length) {
1136 	duk_trans_dvalue_ctx *ctx = (duk_trans_dvalue_ctx *) udata;
1137 	unsigned char *p;
1138 
1139 #if defined(DEBUG_PRINTS)
1140 	fprintf(stderr, "%s: %p %p %ld\n", __func__, udata, (void *) buffer, (long) length);
1141 	fflush(stderr);
1142 #endif
1143 
1144 	duk__trans_call_cooperate(ctx, 0);
1145 
1146 	/* Append data. */
1147 	duk__trans_buffer_rebase(&ctx->recv_buf);
1148 	p = duk__trans_buffer_ensure(&ctx->recv_buf, length);
1149 	memcpy((void *) p, (const void *) buffer, (size_t) length);
1150 	ctx->recv_buf.write_offset += length;
1151 
1152 	/* Trial parse handshake line or dvalue(s). */
1153 	if (!ctx->handshake_done) {
1154 		duk_dvalue *dv = duk__trans_trial_parse_handshake(ctx);
1155 		if (dv) {
1156 			/* Handshake line is available for caller for the
1157 			 * duration of the callback, and must not be freed
1158 			 * by the caller.
1159 			 */
1160 			duk__trans_call_handshake(ctx, (const char *) dv->buf);
1161 #if defined(DEBUG_PRINTS)
1162 			fprintf(stderr, "%s: handshake ok\n", __func__);
1163 			fflush(stderr);
1164 #endif
1165 			duk_dvalue_free(dv);
1166 			ctx->handshake_done = 1;
1167 		}
1168 	}
1169 	if (ctx->handshake_done) {
1170 		for (;;) {
1171 			duk_dvalue *dv = duk__trans_trial_parse_dvalue(ctx);
1172 			if (dv) {
1173 #if defined(DEBUG_PRINTS)
1174 				{
1175 					char buf[DUK_DVALUE_TOSTRING_BUFLEN];
1176 					duk_dvalue_to_string(dv, buf);
1177 					fprintf(stderr, "%s: received dvalue: %s\n", __func__, buf);
1178 					fflush(stderr);
1179 				}
1180 #endif
1181 
1182 				duk__trans_call_received(ctx, dv);
1183 			} else {
1184 				break;
1185 			}
1186 		}
1187 	}
1188 
1189 	duk__trans_call_cooperate(ctx, 0);  /* just in case, if dvalues changed something */
1190 
1191 	return length;
1192 }
1193 
duk_trans_dvalue_peek_cb(void * udata)1194 duk_size_t duk_trans_dvalue_peek_cb(void *udata) {
1195 	duk_trans_dvalue_ctx *ctx = (duk_trans_dvalue_ctx *) udata;
1196 	size_t avail;
1197 
1198 #if defined(DEBUG_PRINTS)
1199 	fprintf(stderr, "%s: %p\n", __func__, udata);
1200 	fflush(stderr);
1201 #endif
1202 
1203 	duk__trans_call_cooperate(ctx, 0);
1204 	avail = (size_t) (ctx->send_buf.write_offset - ctx->send_buf.read_offset);
1205 	return (duk_size_t) avail;
1206 }
1207 
duk_trans_dvalue_read_flush_cb(void * udata)1208 void duk_trans_dvalue_read_flush_cb(void *udata) {
1209 	duk_trans_dvalue_ctx *ctx = (duk_trans_dvalue_ctx *) udata;
1210 
1211 #if defined(DEBUG_PRINTS)
1212 	fprintf(stderr, "%s: %p\n", __func__, udata);
1213 	fflush(stderr);
1214 #endif
1215 
1216 	duk__trans_call_cooperate(ctx, 0);
1217 }
1218 
duk_trans_dvalue_write_flush_cb(void * udata)1219 void duk_trans_dvalue_write_flush_cb(void *udata) {
1220 	duk_trans_dvalue_ctx *ctx = (duk_trans_dvalue_ctx *) udata;
1221 
1222 #if defined(DEBUG_PRINTS)
1223 	fprintf(stderr, "%s: %p\n", __func__, udata);
1224 	fflush(stderr);
1225 #endif
1226 
1227 	duk__trans_call_cooperate(ctx, 0);
1228 }
1229 
duk_trans_dvalue_detached_cb(duk_context * duk_ctx,void * udata)1230 void duk_trans_dvalue_detached_cb(duk_context *duk_ctx, void *udata) {
1231 	duk_trans_dvalue_ctx *ctx = (duk_trans_dvalue_ctx *) udata;
1232 
1233 	(void) duk_ctx;
1234 
1235 #if defined(DEBUG_PRINTS)
1236 	fprintf(stderr, "%s: %p\n", __func__, udata);
1237 	fflush(stderr);
1238 #endif
1239 
1240 	duk__trans_call_detached(ctx);
1241 }
1242