2 * Example debug transport with a local debug message encoder/decoder.
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.
8 * This transport implementation is not multithreaded which means that:
10 * - Callbacks to "received dvalue" callback come from the Duktape thread,
11 * either during normal execution or from duk_debugger_cooperate().
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
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.
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.
26 * Doesn't depend on C99 types; assumes "int" is at least 32 bits, and makes
27 * a few assumptions about format specifiers.
35 #include "duk_trans_dvalue.h"
37 /* Define to enable debug prints to stderr. */
42 /* Define to enable error prints to stderr. */
51 duk_dvalue
*duk_dvalue_alloc(void) {
52 duk_dvalue
*dv
= (duk_dvalue
*) malloc(sizeof(duk_dvalue
));
54 memset((void *) dv
, 0, sizeof(duk_dvalue
));
60 void duk_dvalue_free(duk_dvalue
*dv
) {
62 free(dv
->buf
); /* tolerates NULL */
68 static void duk__dvalue_bufesc(duk_dvalue
*dv
, char *buf
, size_t maxbytes
, int stresc
) {
72 limit
= dv
->len
> maxbytes
? maxbytes
: dv
->len
;
73 for (i
= 0; i
< limit
; i
++) {
74 unsigned char c
= dv
->buf
[i
];
76 if (c
>= 0x20 && c
<= 0x7e && c
!= (char) '"' && c
!= (char) '\'') {
77 sprintf(buf
, "%c", c
);
80 sprintf(buf
, "\\x%02x", (unsigned int) c
);
84 sprintf(buf
, "%02x", (unsigned int) c
);
88 if (dv
->len
> maxbytes
) {
94 /* Caller must provide a buffer at least DUK_DVALUE_TOSTRING_BUFLEN in size. */
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 */
119 case DUK_DVALUE_INTEGER
:
120 sprintf(buf
, "%d", dv
->i
);
122 case DUK_DVALUE_STRING
:
123 duk__dvalue_bufesc(dv
, hexbuf
, 32, 1);
124 sprintf(buf
, "str:%ld:\"%s\"", (long) dv
->len
, hexbuf
);
126 case DUK_DVALUE_BUFFER
:
127 duk__dvalue_bufesc(dv
, hexbuf
, 32, 0);
128 sprintf(buf
, "buf:%ld:%s", (long) dv
->len
, hexbuf
);
130 case DUK_DVALUE_UNUSED
:
131 sprintf(buf
, "undefined");
133 case DUK_DVALUE_UNDEFINED
:
134 sprintf(buf
, "undefined");
136 case DUK_DVALUE_NULL
:
137 sprintf(buf
, "null");
139 case DUK_DVALUE_TRUE
:
140 sprintf(buf
, "true");
142 case DUK_DVALUE_FALSE
:
143 sprintf(buf
, "false");
145 case DUK_DVALUE_NUMBER
:
146 if (fpclassify(dv
->d
) == FP_ZERO
) {
147 if (signbit(dv
->d
)) {
153 sprintf(buf
, "%lg", dv
->d
);
156 case DUK_DVALUE_OBJECT
:
157 duk__dvalue_bufesc(dv
, hexbuf
, 32, 0);
158 sprintf(buf
, "obj:%d:%s", (int) dv
->i
, hexbuf
);
160 case DUK_DVALUE_POINTER
:
161 duk__dvalue_bufesc(dv
, hexbuf
, 32, 0);
162 sprintf(buf
, "ptr:%s", hexbuf
);
164 case DUK_DVALUE_LIGHTFUNC
:
165 duk__dvalue_bufesc(dv
, hexbuf
, 32, 0);
166 sprintf(buf
, "lfunc:%04x:%s", (unsigned int) dv
->i
, hexbuf
);
168 case DUK_DVALUE_HEAPPTR
:
169 duk__dvalue_bufesc(dv
, hexbuf
, 32, 0);
170 sprintf(buf
, "heapptr:%s", hexbuf
);
173 sprintf(buf
, "unknown:%d", (int) dv
->tag
);
177 duk_dvalue
*duk_dvalue_make_tag(int tag
) {
178 duk_dvalue
*dv
= duk_dvalue_alloc();
179 if (!dv
) { return NULL
; }
184 duk_dvalue
*duk_dvalue_make_tag_int(int tag
, int intval
) {
185 duk_dvalue
*dv
= duk_dvalue_alloc();
186 if (!dv
) { return NULL
; }
192 duk_dvalue
*duk_dvalue_make_tag_double(int tag
, double dblval
) {
193 duk_dvalue
*dv
= duk_dvalue_alloc();
194 if (!dv
) { return NULL
; }
200 duk_dvalue
*duk_dvalue_make_tag_data(int tag
, const char *buf
, size_t len
) {
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
208 p
= (unsigned char *) malloc(len
+ 1);
213 memcpy((void *) p
, (const void *) buf
, len
);
214 p
[len
] = (unsigned char) 0;
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
; }
229 * Dvalue transport handling
232 static void duk__trans_dvalue_double_byteswap(duk_trans_dvalue_ctx
*ctx
, volatile unsigned char *p
) {
235 /* Portable IEEE double byteswap. Relies on runtime detection of
239 if (ctx
->double_byteorder
== 0) {
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 */
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
;
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
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);
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.
272 unsigned int tmp
= duk__trans_dvalue_parse_u32(ctx
, p
);
273 if (tmp
& 0x80000000UL
) {
274 return -((int) ((tmp
^ 0xffffffffUL
) + 1UL));
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. */
283 return (((unsigned int) p
[0]) << 8) +
284 (((unsigned int) p
[1]) << 0);
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. */
293 memcpy((void *) u
.b
, (const void *) p
, 8);
294 duk__trans_dvalue_double_byteswap(ctx
, u
.b
);
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. */
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);
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
);
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. */
315 *p
++ = (unsigned char) ((val
>> 8) & 0xff);
316 *p
++ = (unsigned char) (val
& 0xff);
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. */
327 duk__trans_dvalue_double_byteswap(ctx
, u
.b
);
328 memcpy((void *) p
, (const void *) u
.b
, 8);
333 static unsigned char *duk__trans_buffer_ensure(duk_trans_buffer
*dbuf
, size_t space
) {
339 used
= dbuf
->write_offset
;
340 avail
= dbuf
->alloc_size
- dbuf
->write_offset
;
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.
350 /* Too small, resize. */
354 return dbuf
->base
+ dbuf
->write_offset
;
357 new_size
= used
+ space
+ 256; /* some extra to reduce resizes */
358 new_alloc
= realloc(dbuf
->base
, new_size
);
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
);
367 return dbuf
->base
+ dbuf
->write_offset
;
373 /* When read_offset is large enough, "rebase" buffer by deleting already
374 * read data and updating offsets.
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
);
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
);
386 dbuf
->write_offset
-= dbuf
->read_offset
;
387 dbuf
->read_offset
= 0;
391 duk_trans_dvalue_ctx
*duk_trans_dvalue_init(void) {
396 duk_trans_dvalue_ctx
*ctx
= NULL
;
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
;
408 ctx
->send_buf
.base
= malloc(256);
409 if (!ctx
->send_buf
.base
) { goto fail
; }
410 ctx
->send_buf
.alloc_size
= 256;
412 ctx
->recv_buf
.base
= malloc(256);
413 if (!ctx
->recv_buf
.base
) { goto fail
; }
414 ctx
->recv_buf
.alloc_size
= 256;
416 /* IEEE double byte order, detect at run time (could also use
417 * preprocessor defines but that's verbose to make portable).
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,)
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;
429 ctx
->double_byteorder
= 0; /* little endian */
430 } else if (u
.d
< 1.0) {
431 ctx
->double_byteorder
= 1; /* big endian */
433 ctx
->double_byteorder
= 2; /* mixed endian (arm) */
435 #if defined(DEBUG_PRINTS)
436 fprintf(stderr
, "double endianness test value is %lg -> byteorder %d\n",
437 u
.d
, ctx
->double_byteorder
);
445 free(ctx
->recv_buf
.base
); /* tolerates NULL */
446 free(ctx
->send_buf
.base
); /* tolerates NULL */
452 void duk_trans_dvalue_free(duk_trans_dvalue_ctx
*ctx
) {
454 free(ctx
->send_buf
.base
); /* tolerates NULL */
455 free(ctx
->recv_buf
.base
); /* tolerates NULL */
460 void duk_trans_dvalue_send(duk_trans_dvalue_ctx
*ctx
, duk_dvalue
*dv
) {
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.
468 #if defined(DEBUG_PRINTS)
470 char buf
[DUK_DVALUE_TOSTRING_BUFLEN
];
471 duk_dvalue_to_string(dv
, buf
);
472 fprintf(stderr
, "%s: sending dvalue: %s\n", __func__
, buf
);
478 case DUK_DVALUE_EOM
: {
479 p
= duk__trans_buffer_ensure(&ctx
->send_buf
, 1);
480 if (!p
) { goto alloc_error
; }
482 ctx
->send_buf
.write_offset
+= 1;
485 case DUK_DVALUE_REQ
: {
486 p
= duk__trans_buffer_ensure(&ctx
->send_buf
, 1);
487 if (!p
) { goto alloc_error
; }
489 ctx
->send_buf
.write_offset
+= 1;
492 case DUK_DVALUE_REP
: {
493 p
= duk__trans_buffer_ensure(&ctx
->send_buf
, 1);
494 if (!p
) { goto alloc_error
; }
496 ctx
->send_buf
.write_offset
+= 1;
499 case DUK_DVALUE_ERR
: {
500 p
= duk__trans_buffer_ensure(&ctx
->send_buf
, 1);
501 if (!p
) { goto alloc_error
; }
503 ctx
->send_buf
.write_offset
+= 1;
506 case DUK_DVALUE_NFY
: {
507 p
= duk__trans_buffer_ensure(&ctx
->send_buf
, 1);
508 if (!p
) { goto alloc_error
; }
510 ctx
->send_buf
.write_offset
+= 1;
513 case DUK_DVALUE_INTEGER
: {
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
; }
530 p
= duk__trans_dvalue_encode_i32(ctx
, p
, i
);
531 ctx
->send_buf
.write_offset
+= 5;
537 case DUK_DVALUE_STRING
: {
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
);
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
; }
550 p
= duk__trans_dvalue_encode_u16(ctx
, p
, (unsigned int) i
);
551 memcpy((void *) p
, (const void *) dv
->buf
, 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
; }
558 p
= duk__trans_dvalue_encode_u32(ctx
, p
, (unsigned int) i
);
559 memcpy((void *) p
, (const void *) dv
->buf
, i
);
561 ctx
->send_buf
.write_offset
+= 5 + i
;
567 case DUK_DVALUE_BUFFER
: {
570 p
= duk__trans_buffer_ensure(&ctx
->send_buf
, 3 + i
);
571 if (!p
) { goto alloc_error
; }
573 p
= duk__trans_dvalue_encode_u16(ctx
, p
, (unsigned int) i
);
574 memcpy((void *) p
, (const void *) dv
->buf
, 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
; }
581 p
= duk__trans_dvalue_encode_u32(ctx
, p
, (unsigned int) i
);
582 memcpy((void *) p
, (const void *) dv
->buf
, i
);
584 ctx
->send_buf
.write_offset
+= 5 + i
;
590 case DUK_DVALUE_UNUSED
: {
591 p
= duk__trans_buffer_ensure(&ctx
->send_buf
, 1);
592 if (!p
) { goto alloc_error
; }
594 ctx
->send_buf
.write_offset
+= 1;
597 case DUK_DVALUE_UNDEFINED
: {
598 p
= duk__trans_buffer_ensure(&ctx
->send_buf
, 1);
599 if (!p
) { goto alloc_error
; }
601 ctx
->send_buf
.write_offset
+= 1;
604 case DUK_DVALUE_NULL
: {
605 p
= duk__trans_buffer_ensure(&ctx
->send_buf
, 1);
606 if (!p
) { goto alloc_error
; }
608 ctx
->send_buf
.write_offset
+= 1;
611 case DUK_DVALUE_TRUE
: {
612 p
= duk__trans_buffer_ensure(&ctx
->send_buf
, 1);
613 if (!p
) { goto alloc_error
; }
615 ctx
->send_buf
.write_offset
+= 1;
618 case DUK_DVALUE_FALSE
: {
619 p
= duk__trans_buffer_ensure(&ctx
->send_buf
, 1);
620 if (!p
) { goto alloc_error
; }
622 ctx
->send_buf
.write_offset
+= 1;
625 case DUK_DVALUE_NUMBER
: {
626 p
= duk__trans_buffer_ensure(&ctx
->send_buf
, 9);
627 if (!p
) { goto alloc_error
; }
629 p
= duk__trans_dvalue_encode_double(ctx
, p
, dv
->d
);
630 ctx
->send_buf
.write_offset
+= 9;
633 case DUK_DVALUE_OBJECT
: {
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
; }
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
;
648 case DUK_DVALUE_POINTER
: {
651 p
= duk__trans_buffer_ensure(&ctx
->send_buf
, 2 + i
);
652 if (!p
) { goto alloc_error
; }
654 *p
++ = (unsigned char) i
;
655 memcpy((void *) p
, (const void *) dv
->buf
, i
);
656 ctx
->send_buf
.write_offset
+= 2 + i
;
662 case DUK_DVALUE_LIGHTFUNC
: {
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
; }
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
;
677 case DUK_DVALUE_HEAPPTR
: {
680 p
= duk__trans_buffer_ensure(&ctx
->send_buf
, 2 + i
);
681 if (!p
) { goto alloc_error
; }
683 *p
++ = (unsigned char) i
;
684 memcpy((void *) p
, (const void *) dv
->buf
, i
);
685 ctx
->send_buf
.write_offset
+= 2 + i
;
699 #if defined(ERROR_PRINTS)
700 fprintf(stderr
, "%s: internal error, argument dvalue is invalid\n", __func__
);
706 #if defined(ERROR_PRINTS)
707 fprintf(stderr
, "%s: internal error, failed to allocate space for write\n", __func__
);
713 static void duk__trans_dvalue_send_and_free(duk_trans_dvalue_ctx
*ctx
, duk_dvalue
*dv
) {
715 duk_trans_dvalue_send(ctx
, dv
);
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
));
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
));
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
));
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
));
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
));
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
));
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
)));
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
));
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
));
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
));
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
));
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
));
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
));
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
));
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
));
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
));
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
));
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
));
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
));
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
);
800 static duk_dvalue
*duk__trans_trial_parse_dvalue(duk_trans_dvalue_ctx
*ctx
) {
807 p
= ctx
->recv_buf
.base
+ ctx
->recv_buf
.read_offset
;
808 len
= ctx
->recv_buf
.write_offset
- ctx
->recv_buf
.read_offset
;
815 #if defined(DEBUG_PRINTS)
818 fprintf(stderr
, "%s: parsing dvalue, window:", __func__
);
819 for (i
= 0; i
< 16; i
++) {
821 fprintf(stderr
, " %02x", (unsigned int) p
[i
]);
823 fprintf(stderr
, " ??");
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
);
837 ctx
->recv_buf
.read_offset
+= 1;
838 dv
= duk_dvalue_make_tag(DUK_DVALUE_EOM
);
839 if (!dv
) { goto alloc_error
; }
843 ctx
->recv_buf
.read_offset
+= 1;
844 dv
= duk_dvalue_make_tag(DUK_DVALUE_REQ
);
845 if (!dv
) { goto alloc_error
; }
849 ctx
->recv_buf
.read_offset
+= 1;
850 dv
= duk_dvalue_make_tag(DUK_DVALUE_REP
);
851 if (!dv
) { goto alloc_error
; }
855 ctx
->recv_buf
.read_offset
+= 1;
856 dv
= duk_dvalue_make_tag(DUK_DVALUE_ERR
);
857 if (!dv
) { goto alloc_error
; }
861 ctx
->recv_buf
.read_offset
+= 1;
862 dv
= duk_dvalue_make_tag(DUK_DVALUE_NFY
);
863 if (!dv
) { goto alloc_error
; }
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
; }
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
; }
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
; }
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
; }
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
; }
912 ctx
->recv_buf
.read_offset
+= 1;
913 dv
= duk_dvalue_make_tag(DUK_DVALUE_UNUSED
);
914 if (!dv
) { goto alloc_error
; }
918 ctx
->recv_buf
.read_offset
+= 1;
919 dv
= duk_dvalue_make_tag(DUK_DVALUE_UNDEFINED
);
920 if (!dv
) { goto alloc_error
; }
924 ctx
->recv_buf
.read_offset
+= 1;
925 dv
= duk_dvalue_make_tag(DUK_DVALUE_NULL
);
926 if (!dv
) { goto alloc_error
; }
930 ctx
->recv_buf
.read_offset
+= 1;
931 dv
= duk_dvalue_make_tag(DUK_DVALUE_TRUE
);
932 if (!dv
) { goto alloc_error
; }
936 ctx
->recv_buf
.read_offset
+= 1;
937 dv
= duk_dvalue_make_tag(DUK_DVALUE_FALSE
);
938 if (!dv
) { goto alloc_error
; }
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
; }
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
; }
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
; }
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
; }
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
; }
994 } else if (ib
<= 0x5fU
) {
997 } else if (ib
<= 0x7fU
) {
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
; }
1005 } else if (ib
<= 0xbfU
) {
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
; }
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
; }
1030 #if defined(ERROR_PRINTS)
1031 fprintf(stderr
, "%s: internal error, cannot allocate space for dvalue\n", __func__
);
1037 #if defined(ERROR_PRINTS)
1038 fprintf(stderr
, "%s: internal error, dvalue format error\n", __func__
);
1044 static duk_dvalue
*duk__trans_trial_parse_handshake(duk_trans_dvalue_ctx
*ctx
) {
1050 p
= ctx
->recv_buf
.base
+ ctx
->recv_buf
.read_offset
;
1051 len
= ctx
->recv_buf
.write_offset
- ctx
->recv_buf
.read_offset
;
1053 for (i
= 0; i
< len
; i
++) {
1055 /* Handshake line is returned as a dvalue for convenience; it's
1056 * not actually a part of the dvalue phase of the protocol.
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
; }
1068 #if defined(ERROR_PRINTS)
1069 fprintf(stderr
, "%s: internal error, cannot allocate space for handshake line\n", __func__
);
1075 static void duk__trans_call_cooperate(duk_trans_dvalue_ctx
*ctx
, int block
) {
1076 if (ctx
->cooperate
) {
1077 ctx
->cooperate(ctx
, block
);
1081 static void duk__trans_call_received(duk_trans_dvalue_ctx
*ctx
, duk_dvalue
*dv
) {
1082 if (ctx
->received
) {
1083 ctx
->received(ctx
, dv
);
1087 static void duk__trans_call_handshake(duk_trans_dvalue_ctx
*ctx
, const char *line
) {
1088 if (ctx
->handshake
) {
1089 ctx
->handshake(ctx
, line
);
1093 static void duk__trans_call_detached(duk_trans_dvalue_ctx
*ctx
) {
1094 if (ctx
->detached
) {
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
;
1106 #if defined(DEBUG_PRINTS)
1107 fprintf(stderr
, "%s: %p %p %ld\n", __func__
, udata
, (void *) buffer
, (long) length
);
1111 duk__trans_call_cooperate(ctx
, 0);
1116 avail
= (size_t) (ctx
->send_buf
.write_offset
- ctx
->send_buf
.read_offset
);
1118 /* Must cooperate until user callback provides data. From
1119 * Duktape's perspective we MUST block until data is received.
1121 duk__trans_call_cooperate(ctx
, 1);
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
;
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
;
1139 #if defined(DEBUG_PRINTS)
1140 fprintf(stderr
, "%s: %p %p %ld\n", __func__
, udata
, (void *) buffer
, (long) length
);
1144 duk__trans_call_cooperate(ctx
, 0);
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
;
1152 /* Trial parse handshake line or dvalue(s). */
1153 if (!ctx
->handshake_done
) {
1154 duk_dvalue
*dv
= duk__trans_trial_parse_handshake(ctx
);
1156 /* Handshake line is available for caller for the
1157 * duration of the callback, and must not be freed
1160 duk__trans_call_handshake(ctx
, (const char *) dv
->buf
);
1161 #if defined(DEBUG_PRINTS)
1162 fprintf(stderr
, "%s: handshake ok\n", __func__
);
1165 duk_dvalue_free(dv
);
1166 ctx
->handshake_done
= 1;
1169 if (ctx
->handshake_done
) {
1171 duk_dvalue
*dv
= duk__trans_trial_parse_dvalue(ctx
);
1173 #if defined(DEBUG_PRINTS)
1175 char buf
[DUK_DVALUE_TOSTRING_BUFLEN
];
1176 duk_dvalue_to_string(dv
, buf
);
1177 fprintf(stderr
, "%s: received dvalue: %s\n", __func__
, buf
);
1182 duk__trans_call_received(ctx
, dv
);
1189 duk__trans_call_cooperate(ctx
, 0); /* just in case, if dvalues changed something */
1194 duk_size_t
duk_trans_dvalue_peek_cb(void *udata
) {
1195 duk_trans_dvalue_ctx
*ctx
= (duk_trans_dvalue_ctx
*) udata
;
1198 #if defined(DEBUG_PRINTS)
1199 fprintf(stderr
, "%s: %p\n", __func__
, udata
);
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
;
1208 void duk_trans_dvalue_read_flush_cb(void *udata
) {
1209 duk_trans_dvalue_ctx
*ctx
= (duk_trans_dvalue_ctx
*) udata
;
1211 #if defined(DEBUG_PRINTS)
1212 fprintf(stderr
, "%s: %p\n", __func__
, udata
);
1216 duk__trans_call_cooperate(ctx
, 0);
1219 void duk_trans_dvalue_write_flush_cb(void *udata
) {
1220 duk_trans_dvalue_ctx
*ctx
= (duk_trans_dvalue_ctx
*) udata
;
1222 #if defined(DEBUG_PRINTS)
1223 fprintf(stderr
, "%s: %p\n", __func__
, udata
);
1227 duk__trans_call_cooperate(ctx
, 0);
1230 void duk_trans_dvalue_detached_cb(void *udata
) {
1231 duk_trans_dvalue_ctx
*ctx
= (duk_trans_dvalue_ctx
*) udata
;
1233 #if defined(DEBUG_PRINTS)
1234 fprintf(stderr
, "%s: %p\n", __func__
, udata
);
1238 duk__trans_call_detached(ctx
);