Skip to content

Commit bc4bb2b

Browse files
committed
libplugin: use jsonrpc_io logic for sync requests too.
It's a little overkill, but it's clear. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
1 parent 4958cd3 commit bc4bb2b

File tree

3 files changed

+106
-106
lines changed

3 files changed

+106
-106
lines changed

common/jsonrpc_io.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
#include <ccan/tal/str/str.h>
66
#include <common/jsonrpc_io.h>
77
#include <common/utils.h>
8+
#include <errno.h>
9+
#include <unistd.h>
810

911
#define READ_CHUNKSIZE 64
1012

@@ -126,3 +128,24 @@ struct io_plan *jsonrpc_io_read_(struct io_conn *conn,
126128
&json_in->bytes_read,
127129
next, arg);
128130
}
131+
132+
bool jsonrpc_sync_read(struct jsonrpc_io *json_in, int infd)
133+
{
134+
int r;
135+
136+
/* Make sure there's more room */
137+
membuf_prepare_space(&json_in->membuf, READ_CHUNKSIZE);
138+
139+
/* Try to read more. */
140+
r = read(infd,
141+
membuf_space(&json_in->membuf),
142+
membuf_num_space(&json_in->membuf));
143+
if (r < 0)
144+
return false;
145+
if (r == 0) {
146+
errno = 0;
147+
return false;
148+
}
149+
json_in->bytes_read = r;
150+
return true;
151+
}

common/jsonrpc_io.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,15 @@ struct io_plan *jsonrpc_io_read_(struct io_conn *conn,
4343
const char *jsonrpc_newly_read(struct jsonrpc_io *json_in,
4444
size_t *len);
4545

46+
/**
47+
* jsonrpc_sync_read: read from fd into buffer.
48+
* @json_in: buffer to read into.
49+
* @infd: file descriptort to read.
50+
*
51+
* Returns false on error or EOF; for EOF errno will be 0.
52+
*/
53+
bool jsonrpc_sync_read(struct jsonrpc_io *json_in, int infd);
54+
4655
/**
4756
* jsonrpc_io_parse: try to parse more of the buffer.
4857
* @ctx: context to allocate error message off.

plugins/libplugin.c

Lines changed: 74 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
#include "config.h"
22
#include <ccan/io/io.h>
33
#include <ccan/json_out/json_out.h>
4-
#include <ccan/membuf/membuf.h>
54
#include <ccan/read_write_all/read_write_all.h>
65
#include <ccan/tal/path/path.h>
76
#include <ccan/tal/str/str.h>
@@ -31,11 +30,6 @@ struct plugin_timer {
3130
void *cb_arg;
3231
};
3332

34-
struct rpc_conn {
35-
int fd;
36-
MEMBUF(char) mb;
37-
};
38-
3933
/* We can have more than one of these pending at once. */
4034
struct jstream {
4135
struct list_node list;
@@ -93,7 +87,7 @@ struct plugin {
9387
/* To write to lightningd */
9488
struct list_head js_list;
9589

96-
/* Asynchronous RPC interaction */
90+
/* Asynchronous RPC interaction. */
9791
struct io_conn *io_rpc_conn;
9892
struct list_head rpc_js_list;
9993
struct jsonrpc_io *jsonrpc_in;
@@ -102,8 +96,9 @@ struct plugin {
10296
STRMAP(struct out_req *) out_reqs;
10397
u64 next_outreq_id;
10498

105-
/* Synchronous RPC interaction */
106-
struct rpc_conn *rpc_conn;
99+
/* Synchronous RPC interaction: sync_io is NULL if they didn't want it. */
100+
int sync_fd;
101+
struct jsonrpc_io *sync_io;
107102

108103
/* Plugin information details */
109104
enum plugin_restartability restartability;
@@ -534,32 +529,6 @@ struct json_out *json_out_obj(const tal_t *ctx,
534529
return jout;
535530
}
536531

537-
static int read_json_from_rpc(struct plugin *p)
538-
{
539-
char *end;
540-
541-
/* We rely on the double-\n marker which only terminates JSON top
542-
* levels. Thanks lightningd! */
543-
while ((end = memmem(membuf_elems(&p->rpc_conn->mb),
544-
membuf_num_elems(&p->rpc_conn->mb), "\n\n", 2))
545-
== NULL) {
546-
ssize_t r;
547-
548-
/* Make sure we've room for at least READ_CHUNKSIZE. */
549-
membuf_prepare_space(&p->rpc_conn->mb, READ_CHUNKSIZE);
550-
r = read(p->rpc_conn->fd, membuf_space(&p->rpc_conn->mb),
551-
membuf_num_space(&p->rpc_conn->mb));
552-
/* lightningd goes away, we go away. */
553-
if (r == 0)
554-
exit(0);
555-
if (r < 0)
556-
plugin_err(p, "Reading JSON input: %s", strerror(errno));
557-
membuf_added(&p->rpc_conn->mb, r);
558-
}
559-
560-
return end + 2 - membuf_elems(&p->rpc_conn->mb);
561-
}
562-
563532
/* This closes a JSON response and writes it out. */
564533
static void finish_and_send_json(int fd, struct json_out *jout)
565534
{
@@ -719,40 +688,63 @@ void command_set_usage(struct command *cmd, const char *usage TAKES)
719688
cmd->methodname);
720689
}
721690

722-
/* Reads rpc reply and returns tokens, setting contents to 'error' or
723-
- * 'result' (depending on *error). */
724-
static jsmntok_t *read_rpc_reply(const tal_t *ctx,
725-
struct plugin *plugin,
726-
const jsmntok_t **contents,
727-
bool *error,
728-
int *reqlen)
691+
static const char *read_one_json_sync(struct plugin *p, const jsmntok_t **toks)
729692
{
730-
jsmntok_t *toks;
693+
for (;;) {
694+
const char *buf, *error;
731695

732-
do {
733-
*reqlen = read_json_from_rpc(plugin);
696+
error = jsonrpc_io_parse(tmpctx, p->sync_io, toks, &buf);
697+
if (error)
698+
plugin_err(p, "Parsing sync lightningd: %s", error);
699+
if (*toks)
700+
return buf;
734701

735-
toks = json_parse_simple(ctx,
736-
membuf_elems(&plugin->rpc_conn->mb),
737-
*reqlen);
738-
if (!toks)
739-
plugin_err(plugin, "Malformed JSON reply '%.*s'",
740-
*reqlen, membuf_elems(&plugin->rpc_conn->mb));
702+
/* lightningd goes away, we go away. */
703+
if (!jsonrpc_sync_read(p->sync_io, p->sync_fd)) {
704+
if (errno == 0)
705+
exit(0);
706+
else
707+
plugin_err(p, "Reading sync lightningd: %s",
708+
strerror(errno));
709+
}
710+
}
711+
}
712+
713+
/* Reads rpc reply and returns result tokens */
714+
static const jsmntok_t *read_sync_rpc_reply(const tal_t *ctx,
715+
struct plugin *plugin,
716+
const char *method,
717+
const char **final_buffer)
718+
{
719+
const jsmntok_t *errtok, *resulttok, *toks;
720+
const char *buffer;
721+
722+
for (;;) {
723+
buffer = read_one_json_sync(plugin, &toks);
741724
/* FIXME: Don't simply ignore notifications here! */
742-
} while (!json_get_member(membuf_elems(&plugin->rpc_conn->mb), toks,
743-
"id"));
725+
if (json_get_member(buffer, toks, "id"))
726+
break;
727+
jsonrpc_io_parse_done(plugin->sync_io);
728+
}
744729

745-
*contents = json_get_member(membuf_elems(&plugin->rpc_conn->mb), toks, "error");
746-
if (*contents)
747-
*error = true;
748-
else {
749-
*contents = json_get_member(membuf_elems(&plugin->rpc_conn->mb), toks,
750-
"result");
751-
if (!*contents)
752-
plugin_err(plugin, "JSON reply with no 'result' nor 'error'? '%.*s'",
753-
*reqlen, membuf_elems(&plugin->rpc_conn->mb));
754-
*error = false;
730+
errtok = json_get_member(buffer, toks, "error");
731+
if (errtok) {
732+
plugin_err(plugin, "Got error result to %s: '%.*s'",
733+
method,
734+
json_tok_full_len(toks),
735+
json_tok_full(buffer, toks));
755736
}
737+
resulttok = json_get_member(buffer, toks, "result");
738+
if (!resulttok) {
739+
plugin_err(plugin, "JSON reply with no 'result' nor 'error'? '%.*s'",
740+
json_tok_full_len(toks),
741+
json_tok_full(buffer, toks));
742+
}
743+
744+
/* Make the returned pointers valid tal object */
745+
json_dup_contents(ctx, buffer, resulttok, final_buffer, &toks);
746+
jsonrpc_io_parse_done(plugin->sync_io);
747+
756748
return toks;
757749
}
758750

@@ -763,13 +755,8 @@ static const jsmntok_t *sync_req(const tal_t *ctx,
763755
const struct json_out *params TAKES,
764756
const char **resp)
765757
{
766-
bool error;
767-
jsmntok_t *toks;
768-
const jsmntok_t *contents;
769-
int reqlen;
770758
struct json_out *jout = json_out_new(tmpctx);
771759
const char *id = json_id(tmpctx, plugin, "init/", method);
772-
size_t num_toks;
773760

774761
json_out_start(jout, NULL, '{');
775762
json_out_addstr(jout, "jsonrpc", "2.0");
@@ -787,23 +774,15 @@ static const jsmntok_t *sync_req(const tal_t *ctx,
787774

788775
/* If we're past init, we may need a new fd (the old one
789776
* is being used for async comms). */
790-
if (plugin->rpc_conn->fd == -1)
791-
plugin->rpc_conn->fd = rpc_open(plugin);
792-
793-
finish_and_send_json(plugin->rpc_conn->fd, jout);
794-
795-
toks = read_rpc_reply(ctx, plugin, &contents, &error, &reqlen);
796-
if (error)
797-
plugin_err(plugin, "Got error reply to %s: '%.*s'",
798-
method, reqlen, membuf_elems(&plugin->rpc_conn->mb));
777+
if (plugin->sync_fd == -1) {
778+
plugin->sync_fd = rpc_open(plugin);
779+
if (!plugin->sync_io)
780+
plugin->sync_io = jsonrpc_io_new(plugin);
781+
}
799782

800-
*resp = membuf_consume(&plugin->rpc_conn->mb, reqlen);
783+
finish_and_send_json(plugin->sync_fd, jout);
801784

802-
/* Make the returned pointer the valid tal object of minimal length */
803-
num_toks = json_next(contents) - contents;
804-
memmove(toks, contents, num_toks * sizeof(*toks));
805-
tal_resize(&toks, num_toks);
806-
return toks;
785+
return read_sync_rpc_reply(ctx, plugin, method, resp);
807786
}
808787

809788
const jsmntok_t *jsonrpc_request_sync(const tal_t *ctx,
@@ -812,7 +791,6 @@ const jsmntok_t *jsonrpc_request_sync(const tal_t *ctx,
812791
const struct json_out *params TAKES,
813792
const char **resp)
814793
{
815-
816794
return sync_req(ctx, cmd->plugin, method, params, resp);
817795
}
818796

@@ -1508,7 +1486,6 @@ static struct command_result *handle_init(struct command *cmd,
15081486
size_t i;
15091487
char *dir, *network;
15101488
struct plugin *p = cmd->plugin;
1511-
bool with_rpc;
15121489
const char *err;
15131490

15141491
configtok = json_get_member(buf, params, "configuration");
@@ -1535,17 +1512,10 @@ static struct command_result *handle_init(struct command *cmd,
15351512
/* Only attempt to connect if the plugin has configured the rpc_conn
15361513
* already, if that's not the case we were told to run without an RPC
15371514
* connection, so don't even log an error. */
1538-
if (p->rpc_conn != NULL) {
1539-
p->rpc_conn->fd = rpc_open(p);
1540-
if (p->rpc_conn->fd == -1)
1541-
with_rpc = false;
1542-
else
1543-
with_rpc = true;
1544-
1545-
membuf_init(&p->rpc_conn->mb, tal_arr(p, char, READ_CHUNKSIZE),
1546-
READ_CHUNKSIZE, membuf_tal_resize);
1547-
} else
1548-
with_rpc = false;
1515+
if (p->sync_io)
1516+
p->sync_fd = rpc_open(p);
1517+
else
1518+
p->sync_fd = -1;
15491519

15501520
opttok = json_get_member(buf, params, "options");
15511521
json_for_each_obj(i, t, opttok) {
@@ -1569,19 +1539,20 @@ static struct command_result *handle_init(struct command *cmd,
15691539
disable));
15701540
}
15711541

1572-
if (with_rpc) {
1542+
/* Now set up async. */
1543+
if (p->sync_fd != -1) {
15731544
struct out_req *req;
15741545
struct command *aux_cmd = aux_command(cmd);
15751546

1576-
io_new_conn(p, p->rpc_conn->fd, rpc_conn_init, p);
1547+
io_new_conn(p, p->sync_fd, rpc_conn_init, p);
15771548
/* In case they intercept rpc_command, we can't do this sync. */
15781549
req = jsonrpc_request_start(aux_cmd, "listconfigs",
15791550
get_beglist, plugin_broken_cb, NULL);
15801551
json_add_string(req->js, "config", "i-promise-to-fix-broken-api-user");
15811552
send_outreq(req);
15821553

15831554
/* We will open a new one if we want to be sync. */
1584-
p->rpc_conn->fd = -1;
1555+
p->sync_fd = -1;
15851556
}
15861557

15871558
return command_success(cmd, json_out_obj(cmd, NULL, NULL));
@@ -2341,13 +2312,10 @@ static struct plugin *new_plugin(const tal_t *ctx,
23412312
p->beglist = NULL;
23422313

23432314
p->desired_features = tal_steal(p, features);
2344-
if (init_rpc) {
2345-
/* Sync RPC FIXME: maybe go full async ? */
2346-
p->rpc_conn = tal(p, struct rpc_conn);
2347-
} else {
2348-
p->rpc_conn = NULL;
2349-
}
2350-
2315+
if (init_rpc)
2316+
p->sync_io = jsonrpc_io_new(p);
2317+
else
2318+
p->sync_io = NULL;
23512319
p->init = init;
23522320
p->manifested = p->initialized = p->exiting = false;
23532321
p->restartability = restartability;

0 commit comments

Comments
 (0)