diff --git a/cli/lightning-cli.c b/cli/lightning-cli.c index 4cc8fb763..bcc006f45 100644 --- a/cli/lightning-cli.c +++ b/cli/lightning-cli.c @@ -52,16 +52,16 @@ int main(int argc, char *argv[]) int fd, i, off; const char *method; char *cmd, *resp, *idstr, *rpc_filename; - char *result_end; struct sockaddr_un addr; jsmntok_t *toks; const jsmntok_t *result, *error, *id; char *lightning_dir; const tal_t *ctx = tal(NULL, char); - size_t num_opens, num_closes; - bool valid; + jsmn_parser parser; + jsmnerr_t parserr; err_set_progname(argv[0]); + jsmn_init(&parser); opt_set_alloc(opt_allocfn, tal_reallocfn, tal_freefn); configdir_register_opts(ctx, &lightning_dir, &rpc_filename); @@ -117,43 +117,41 @@ int main(int argc, char *argv[]) if (!write_all(fd, cmd, strlen(cmd))) err(ERROR_TALKING_TO_LIGHTNINGD, "Writing command"); - resp = tal_arr(cmd, char, 100); + /* Start with 1000 characters, 100 tokens. */ + resp = tal_arr(ctx, char, 1000); + toks = tal_arr(ctx, jsmntok_t, 100); off = 0; - num_opens = num_closes = 0; - while ((i = read(fd, resp + off, tal_count(resp) - 1 - off)) > 0) { - resp[off + i] = '\0'; - num_opens += strcount(resp + off, "{"); - num_closes += strcount(resp + off, "}"); - - off += i; - if (off == tal_count(resp) - 1) - tal_resize(&resp, tal_count(resp) * 2); - - /* parsing huge outputs is slow: do quick check first. */ - if (num_opens == num_closes) + parserr = 0; + while (parserr <= 0) { + /* Read more if parser says, or we have 0 tokens. */ + if (parserr == 0 || parserr == JSMN_ERROR_PART) { + i = read(fd, resp + off, tal_count(resp) - 1 - off); + if (i <= 0) + err(ERROR_TALKING_TO_LIGHTNINGD, + "reading response"); + off += i; + /* NUL terminate */ + resp[off] = '\0'; + } + + /* (Continue) parsing */ + parserr = jsmn_parse(&parser, resp, off, toks, tal_count(toks)); + + switch (parserr) { + case JSMN_ERROR_INVAL: + errx(ERROR_TALKING_TO_LIGHTNINGD, + "Malformed response '%s'", resp); + case JSMN_ERROR_NOMEM: + /* Need more tokens, double it */ + tal_resize(&toks, tal_count(toks) * 2); break; + case JSMN_ERROR_PART: + /* Need more data: make room if necessary */ + if (off == tal_count(resp) - 1) + tal_resize(&resp, tal_count(resp) * 2); + break; + } } - if (i < 0) - err(ERROR_TALKING_TO_LIGHTNINGD, "reading response"); - - resp[off] = '\0'; - - /* Parsing huge results is too slow, so hack fastpath common case */ - result_end = tal_fmt(ctx, ", \"error\" : null, \"id\" : \"%s\" }\n", - idstr); - - if (strstarts(resp, "{ \"result\" : ") && strends(resp, result_end)) { - /* Result is OK, so dump it */ - resp += strlen("{ \"result\" : "); - printf("%.*s\n", (int)(strlen(resp) - strlen(result_end)), resp); - tal_free(ctx); - return 0; - } - - toks = json_parse_input(resp, off, &valid); - if (!toks || !valid) - errx(ERROR_TALKING_TO_LIGHTNINGD, - "Malformed response '%s'", resp); if (toks->type != JSMN_OBJECT) errx(ERROR_TALKING_TO_LIGHTNINGD,