[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH v3 19/31] libxl_qmp_ev: Parse JSON input from QMP
Signed-off-by: Anthony PERARD <anthony.perard@xxxxxxxxxx> --- tools/libxl/libxl_qmp.c | 98 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) diff --git a/tools/libxl/libxl_qmp.c b/tools/libxl/libxl_qmp.c index 48dc376307..e4441f76f4 100644 --- a/tools/libxl/libxl_qmp.c +++ b/tools/libxl/libxl_qmp.c @@ -1383,7 +1383,9 @@ static int ev_qmp_callback_readable(libxl__egc *egc, libxl__ev_qmp_state *qmp, { EGC_GC; ssize_t r; + char *end = NULL; libxl__qmp_rx_buf *buf; + int rc; /* Check if last buffer still have space, or alloc a new one */ buf = LIBXL_TAILQ_LAST(&qmp->bufs, libxl__qmp_bufs); @@ -1425,6 +1427,102 @@ static int ev_qmp_callback_readable(libxl__egc *egc, libxl__ev_qmp_state *qmp, buf->used += r; assert(buf->used < sizeof(buf->buf)); + /* workaround strstr limitation */ + buf->buf[buf->used] = '\0'; + + /* + * Search for the end of a QMP message: "\r\n". + * - First check if those two chr were received accross 2 read. + * - Then, look for them within the newly read data. + * + * end: This point to the address right after \r\n + */ + if (buf->buf[buf->used - r] == '\n') { + /* First new chr read is \n, look if the previous one is \r. */ + + if (buf->used - r == 0) { + libxl__qmp_rx_buf *prev_buf; + + prev_buf = LIBXL_TAILQ_PREV(buf, libxl__qmp_bufs, entry); + if (prev_buf && + prev_buf->buf[prev_buf->used - 1] == '\r') { + end = buf->buf + 1; + } + } else if (buf->buf[buf->used - r - 1] == '\r') { + end = buf->buf + buf->used - r - 1; + end += 2; + } + } + if (!end) { + end = strstr(buf->buf + buf->used - r, "\r\n"); + if (end) + end += 2; + } + + while (end) { + libxl__json_object *o; + libxl__yajl_ctx *yajl_ctx; + libxl__qmp_rx_buf *parse_buf, *tbuf; + + yajl_ctx = libxl__json_parse_alloc(gc); + + LIBXL_TAILQ_FOREACH_SAFE(parse_buf, &qmp->bufs, entry, tbuf) { + size_t len; + char *s; + + /* Start parsing from s */ + s = parse_buf->buf + parse_buf->consumed; + /* Findout how much can be parsed */ + if (buf == parse_buf) { + /* this is the last buffer to parse, stop at end */ + len = end - parse_buf->buf - parse_buf->consumed; + } else { + /* parse all the buffer */ + len = parse_buf->used - parse_buf->consumed; + } + + LOG_QMP("parsing %luB: '%.*s'", len, (int)len, s); + + rc = libxl__json_parse_partial(gc, yajl_ctx, s, len); + if (rc) + break; + + parse_buf->consumed += len; + + if (parse_buf->consumed >= parse_buf->used) { + LIBXL_TAILQ_REMOVE(&qmp->bufs, parse_buf, entry); + free(parse_buf); + if (buf == parse_buf) { + buf = NULL; + break; + } + } + + /* Last buffer to parse, will call complete */ + if (buf == parse_buf) + break; + } + + if (rc) + return rc; + + o = libxl__json_complete_parse(gc, yajl_ctx); + + if (!o) { + LOGD(ERROR, qmp->domid, "Parse error"); + return ERROR_FAIL; + } + + LOG_QMP("JSON object received: %s", libxl__json_object_to_json(gc, o)); + + /* check if there is another message received at the same time */ + if (buf) { + end = strstr(buf->buf + buf->consumed, "\r\n"); + if (end) + end += 2; + } else + end = NULL; + } return 0; } -- Anthony PERARD _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxxxxxxxxx https://lists.xenproject.org/mailman/listinfo/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |