| 1181 | } |
| 1182 | |
| 1183 | static struct io_plan *read_json(struct io_conn *conn, |
| 1184 | struct json_connection *jcon) |
| 1185 | { |
| 1186 | bool in_transaction = false; |
| 1187 | struct timemono start_time = time_mono(); |
| 1188 | size_t len_read; |
| 1189 | const jsmntok_t *toks; |
| 1190 | const char *buffer, *error; |
| 1191 | size_t num_parsed = 0; |
| 1192 | const char *last_method = NULL; |
| 1193 | u64 msec; |
| 1194 | |
| 1195 | buffer = jsonrpc_newly_read(jcon->json_in, &len_read); |
| 1196 | if (len_read) |
| 1197 | log_io(jcon->log, LOG_IO_IN, NULL, "", buffer, len_read); |
| 1198 | |
| 1199 | /* We wait for pending output to be consumed, to avoid DoS */ |
| 1200 | if (!list_empty(&jcon->jsouts)) { |
| 1201 | return io_wait(conn, conn, read_json, jcon); |
| 1202 | } |
| 1203 | |
| 1204 | again: |
| 1205 | error = jsonrpc_io_parse(tmpctx, jcon->json_in, &toks, &buffer); |
| 1206 | if (error) { |
| 1207 | json_command_malformed(jcon, "null", error); |
| 1208 | if (in_transaction) |
| 1209 | db_commit_transaction(jcon->ld->wallet->db); |
| 1210 | return io_halfclose(conn); |
| 1211 | } |
| 1212 | |
| 1213 | if (!toks) |
| 1214 | goto read_more; |
| 1215 | |
| 1216 | if (!in_transaction) { |
| 1217 | db_begin_transaction(jcon->ld->wallet->db); |
| 1218 | in_transaction = true; |
| 1219 | } |
| 1220 | parse_request(jcon, buffer, toks, &last_method); |
| 1221 | jsonrpc_io_parse_done(jcon->json_in); |
| 1222 | |
| 1223 | /* Don't ever process for more than 100 commands or 250 msec |
| 1224 | * without giving others a chance */ |
| 1225 | msec = time_to_msec(timemono_between(time_mono(), start_time)); |
| 1226 | if (num_parsed++ == 100 || msec > 250) { |
| 1227 | static bool printed_once = false; |
| 1228 | db_commit_transaction(jcon->ld->wallet->db); |
| 1229 | log_debug(jcon->log, "Pausing parsing after %zu requests and %"PRIu64"msec (last method=%s)", |
| 1230 | num_parsed, |
| 1231 | msec, |
| 1232 | last_method ? last_method : "NONE"); |
| 1233 | if (msec > 5000 && last_method && !printed_once) { |
| 1234 | log_unusual(jcon->log, |
| 1235 | CI_UNEXPECTED "Request %s took %"PRIu64" milliseconds", |
| 1236 | last_method, msec); |
| 1237 | printed_once = true; |
| 1238 | } |
| 1239 | /* Call us back, as if we read nothing new */ |
| 1240 | return io_always(conn, read_json, jcon); |
no test coverage detected