Skip to content

Commit c88c8ea

Browse files
committed
lightningd: use jsonrpc_io for reading JSON commands.
This is more efficient if we have lots of incoming commands, too. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
1 parent cbdffe0 commit c88c8ea

File tree

2 files changed

+34
-76
lines changed

2 files changed

+34
-76
lines changed

lightningd/jsonrpc.c

Lines changed: 30 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include <common/codex32.h>
2626
#include <common/json_command.h>
2727
#include <common/json_filter.h>
28+
#include <common/jsonrpc_io.h>
2829
#include <common/memleak.h>
2930
#include <common/timeout.h>
3031
#include <common/trace.h>
@@ -78,18 +79,8 @@ struct json_connection {
7879
/* Logging for this json connection. */
7980
struct logger *log;
8081

81-
/* The buffer (required to interpret tokens). */
82-
char *buffer;
83-
84-
/* Internal state: */
85-
/* How much is already filled. */
86-
size_t used;
87-
/* How much has just been filled. */
88-
size_t len_read;
89-
90-
/* JSON parsing state. */
91-
jsmn_parser input_parser;
92-
jsmntok_t *input_toks;
82+
/* The buffer and state reading in the JSON commands */
83+
struct jsonrpc_io *json_in;
9384

9485
/* Local deprecated support? */
9586
bool deprecated_ok;
@@ -1210,93 +1201,61 @@ static struct io_plan *stream_out_complete(struct io_conn *conn,
12101201
static struct io_plan *read_json(struct io_conn *conn,
12111202
struct json_connection *jcon)
12121203
{
1213-
bool complete;
12141204
bool in_transaction = false;
12151205
struct timemono start_time = time_mono();
1206+
size_t len_read;
1207+
const jsmntok_t *toks;
1208+
const char *buffer, *error;
12161209

1217-
if (jcon->len_read)
1218-
log_io(jcon->log, LOG_IO_IN, NULL, "",
1219-
jcon->buffer + jcon->used, jcon->len_read);
1220-
1221-
/* Resize larger if we're full. */
1222-
jcon->used += jcon->len_read;
1223-
if (jcon->used == tal_count(jcon->buffer))
1224-
tal_resize(&jcon->buffer, jcon->used * 2);
1210+
buffer = jsonrpc_newly_read(jcon->json_in, &len_read);
1211+
if (len_read)
1212+
log_io(jcon->log, LOG_IO_IN, NULL, "", buffer, len_read);
12251213

12261214
/* We wait for pending output to be consumed, to avoid DoS */
12271215
if (tal_count(jcon->js_arr) != 0) {
1228-
jcon->len_read = 0;
12291216
return io_wait(conn, conn, read_json, jcon);
12301217
}
12311218

12321219
again:
1233-
if (!json_parse_input(&jcon->input_parser, &jcon->input_toks,
1234-
jcon->buffer, jcon->used,
1235-
&complete)) {
1236-
json_command_malformed(
1237-
jcon, "null",
1238-
tal_fmt(tmpctx, "Invalid token in json input: '%s'",
1239-
tal_hexstr(tmpctx, jcon->buffer, jcon->used)));
1220+
error = jsonrpc_io_parse(tmpctx, jcon->json_in, &toks, &buffer);
1221+
if (error) {
1222+
json_command_malformed(jcon, "null", error);
12401223
if (in_transaction)
12411224
db_commit_transaction(jcon->ld->wallet->db);
12421225
return io_halfclose(conn);
12431226
}
12441227

1245-
if (!complete)
1246-
goto read_more;
1247-
1248-
/* Empty buffer? (eg. just whitespace). */
1249-
if (tal_count(jcon->input_toks) == 1) {
1250-
jcon->used = 0;
1251-
1252-
/* Reset parser. */
1253-
jsmn_init(&jcon->input_parser);
1254-
toks_reset(jcon->input_toks);
1228+
if (!toks)
12551229
goto read_more;
1256-
}
12571230

12581231
if (!in_transaction) {
12591232
db_begin_transaction(jcon->ld->wallet->db);
12601233
in_transaction = true;
12611234
}
1262-
parse_request(jcon, jcon->buffer, jcon->input_toks);
1263-
1264-
/* Remove first {}. */
1265-
memmove(jcon->buffer, jcon->buffer + jcon->input_toks[0].end,
1266-
tal_count(jcon->buffer) - jcon->input_toks[0].end);
1267-
jcon->used -= jcon->input_toks[0].end;
1268-
1269-
/* Reset parser. */
1270-
jsmn_init(&jcon->input_parser);
1271-
toks_reset(jcon->input_toks);
1235+
parse_request(jcon, buffer, toks);
1236+
jsonrpc_io_parse_done(jcon->json_in);
12721237

1273-
/* Do we have more already read? */
1274-
if (jcon->used) {
1275-
if (!jcon->db_batching) {
1238+
if (!jcon->db_batching) {
1239+
db_commit_transaction(jcon->ld->wallet->db);
1240+
in_transaction = false;
1241+
} else {
1242+
/* FIXME: io_always() should interleave with
1243+
* real IO, and then we should rotate order we
1244+
* service fds in, to avoid starvation. */
1245+
if (time_greater(timemono_between(time_mono(),
1246+
start_time),
1247+
time_from_msec(250))) {
12761248
db_commit_transaction(jcon->ld->wallet->db);
1277-
in_transaction = false;
1278-
} else {
1279-
/* FIXME: io_always() should interleave with
1280-
* real IO, and then we should rotate order we
1281-
* service fds in, to avoid starvation. */
1282-
if (time_greater(timemono_between(time_mono(),
1283-
start_time),
1284-
time_from_msec(250))) {
1285-
db_commit_transaction(jcon->ld->wallet->db);
1286-
/* Call us back, as if we read nothing new */
1287-
jcon->len_read = 0;
1288-
return io_always(conn, read_json, jcon);
1289-
}
1249+
/* Call us back, as if we read nothing new */
1250+
return io_always(conn, read_json, jcon);
12901251
}
1291-
goto again;
12921252
}
1253+
goto again;
12931254

12941255
read_more:
12951256
if (in_transaction)
12961257
db_commit_transaction(jcon->ld->wallet->db);
1297-
return io_read_partial(conn, jcon->buffer + jcon->used,
1298-
tal_count(jcon->buffer) - jcon->used,
1299-
&jcon->len_read, read_json, jcon);
1258+
return jsonrpc_io_read(conn, jcon->json_in, read_json, jcon);
13001259
}
13011260

13021261
static struct io_plan *jcon_connected(struct io_conn *conn,
@@ -1308,12 +1267,8 @@ static struct io_plan *jcon_connected(struct io_conn *conn,
13081267
jcon = notleak(tal(conn, struct json_connection));
13091268
jcon->conn = conn;
13101269
jcon->ld = ld;
1311-
jcon->used = 0;
1312-
jcon->buffer = tal_arr(jcon, char, 64);
13131270
jcon->js_arr = tal_arr(jcon, struct json_stream *, 0);
1314-
jcon->len_read = 0;
1315-
jsmn_init(&jcon->input_parser);
1316-
jcon->input_toks = toks_alloc(jcon);
1271+
jcon->json_in = jsonrpc_io_new(jcon);
13171272
jcon->notifications_enabled = false;
13181273
jcon->db_batching = false;
13191274
jcon->deprecated_ok = ld->deprecated_ok;

tests/test_misc.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -951,11 +951,14 @@ def test_malformed_rpc(node_factory):
951951
obj, _ = l1.rpc._readobj(sock, b'')
952952
assert obj['error']['code'] == -32600
953953

954-
# Complete crap
954+
# Complete crap (this makes it hang up!)
955955
sock.sendall(b'[]')
956956
obj, _ = l1.rpc._readobj(sock, b'')
957957
assert obj['error']['code'] == -32600
958958

959+
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
960+
sock.connect(l1.rpc.socket_path)
961+
959962
# Bad ID
960963
sock.sendall(b'{"id":{}, "jsonrpc":"2.0","method":"getinfo","params":[]}')
961964
obj, _ = l1.rpc._readobj(sock, b'')

0 commit comments

Comments
 (0)