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. */
4034struct 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. */
564533static 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
809788const 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