commando: always use proper responses for commands.

All `struct command` should be terminated properly.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell 2024-11-06 21:23:36 +10:30
parent 7ce30e2873
commit b1e2be3c89

View file

@ -32,6 +32,7 @@ enum commando_msgtype {
};
struct commando {
/* Only non-NULL for outgoing cmds */
struct command *cmd;
struct node_id peer;
u64 id;
@ -116,7 +117,7 @@ struct reply {
};
/* Calls itself repeatedly: first time, result is NULL */
static struct command_result *send_response(struct command *command UNUSED,
static struct command_result *send_response(struct command *cmd,
const char *buf UNUSED,
const jsmntok_t *result,
struct reply *reply)
@ -133,7 +134,7 @@ static struct command_result *send_response(struct command *command UNUSED,
} else {
if (msglen == 0) {
tal_free(reply);
return command_done();
return command_hook_success(cmd);
}
msgtype = COMMANDO_MSG_REPLY_TERM;
}
@ -144,7 +145,7 @@ static struct command_result *send_response(struct command *command UNUSED,
towire(&cmd_msg, reply->buf + reply->off, msglen);
reply->off += msglen;
req = jsonrpc_request_start(plugin, NULL, "sendcustommsg",
req = jsonrpc_request_start(plugin, cmd, "sendcustommsg",
send_response, send_response,
reply);
json_add_node_id(req->js, "node_id", &reply->incoming->peer);
@ -152,7 +153,7 @@ static struct command_result *send_response(struct command *command UNUSED,
tal_free(cmd_msg);
send_outreq(plugin, req);
return command_done();
return command_still_pending(cmd);
}
static struct command_result *cmd_done(struct command *command,
@ -192,12 +193,14 @@ static struct command_result *cmd_done(struct command *command,
return send_response(command, NULL, NULL, reply);
}
static void commando_error(struct commando *incoming,
static struct command_result *commando_error(struct command *cmd,
struct commando *incoming,
int ecode,
const char *fmt, ...)
PRINTF_FMT(3,4);
PRINTF_FMT(4, 5);
static void commando_error(struct commando *incoming,
static struct command_result *commando_error(struct command *cmd,
struct commando *incoming,
int ecode,
const char *fmt, ...)
{
@ -213,7 +216,7 @@ static void commando_error(struct commando *incoming,
reply->off = 0;
reply->len = tal_bytelen(reply->buf) - 1;
send_response(NULL, NULL, NULL, reply);
return send_response(cmd, NULL, NULL, reply);
}
struct cond_info {
@ -270,12 +273,13 @@ static struct cond_info *new_cond_info(const tal_t *ctx,
return cinfo;
}
static struct command_result *execute_command(struct cond_info *cinfo)
static struct command_result *execute_command(struct command *cmd,
struct cond_info *cinfo)
{
struct out_req *req;
/* We handle success and failure the same */
req = jsonrpc_request_whole_object_start(plugin, NULL,
req = jsonrpc_request_whole_object_start(plugin, cmd,
json_strdup(tmpctx, cinfo->buf, cinfo->method),
cinfo->cmdid_prefix,
cmd_done, cinfo->incoming);
@ -336,12 +340,12 @@ static struct command_result *checkrune_done(struct command *cmd,
/* Shouldn't happen! */
if (!valid) {
commando_error(cinfo->incoming, COMMANDO_ERROR_REMOTE,
return commando_error(cmd, cinfo->incoming,
COMMANDO_ERROR_REMOTE,
"Invalid rune");
return command_done();
}
return execute_command(cinfo);
return execute_command(cmd, cinfo);
}
static struct command_result *checkrune_failed(struct command *cmd,
@ -357,13 +361,14 @@ static struct command_result *checkrune_failed(struct command *cmd,
json_tok_full(buf, result));
}
commando_error(cinfo->incoming, COMMANDO_ERROR_REMOTE_AUTH,
return commando_error(cmd, cinfo->incoming,
COMMANDO_ERROR_REMOTE_AUTH,
"Invalid rune: %.*s",
msg->end - msg->start, buf + msg->start);
return command_done();
}
static void try_command(struct commando *incoming STEALS)
static struct command_result *try_command(struct command *cmd,
struct commando *incoming STEALS)
{
const jsmntok_t *toks, *method, *params, *runetok, *id, *filter;
const char *buf = (const char *)incoming->contents;
@ -373,45 +378,40 @@ static void try_command(struct commando *incoming STEALS)
toks = json_parse_simple(incoming, buf, tal_bytelen(buf));
if (!toks) {
commando_error(incoming, COMMANDO_ERROR_REMOTE,
return commando_error(cmd, incoming, COMMANDO_ERROR_REMOTE,
"Invalid JSON");
return;
}
if (toks[0].type != JSMN_OBJECT) {
commando_error(incoming, COMMANDO_ERROR_REMOTE,
return commando_error(cmd, incoming, COMMANDO_ERROR_REMOTE,
"Not a JSON object");
return;
}
method = json_get_member(buf, toks, "method");
if (!method) {
commando_error(incoming, COMMANDO_ERROR_REMOTE,
return commando_error(cmd, incoming, COMMANDO_ERROR_REMOTE,
"No method");
return;
}
params = json_get_member(buf, toks, "params");
if (params && (params->type != JSMN_OBJECT && params->type != JSMN_ARRAY)) {
commando_error(incoming, COMMANDO_ERROR_REMOTE,
return commando_error(cmd, incoming, COMMANDO_ERROR_REMOTE,
"Params must be object or array");
return;
}
filter = json_get_member(buf, toks, "filter");
id = json_get_member(buf, toks, "id");
if (!id) {
commando_error(incoming, COMMANDO_ERROR_REMOTE,
return commando_error(cmd, incoming, COMMANDO_ERROR_REMOTE,
"missing id field");
return;
}
runetok = json_get_member(buf, toks, "rune");
if (!runetok) {
commando_error(incoming, COMMANDO_ERROR_REMOTE, "Missing rune");
return;
return commando_error(cmd, incoming, COMMANDO_ERROR_REMOTE,
"Missing rune");
}
rune = rune_from_base64n(tmpctx, buf + runetok->start,
runetok->end - runetok->start);
if (!rune) {
commando_error(incoming, COMMANDO_ERROR_REMOTE, "Invalid rune");
return;
return commando_error(cmd, incoming, COMMANDO_ERROR_REMOTE,
"Invalid rune");
}
/* Gather all the info we need to execute this command (steals toks). */
cinfo = new_cond_info(incoming, incoming, toks, method, params, id, filter);
@ -420,7 +420,7 @@ static void try_command(struct commando *incoming STEALS)
destroy_commando(incoming, &incoming_commands);
tal_del_destructor2(incoming, destroy_commando, &incoming_commands);
req = jsonrpc_request_start(plugin, NULL, "checkrune",
req = jsonrpc_request_start(plugin, cmd, "checkrune",
checkrune_done, checkrune_failed,
cinfo);
json_add_node_id(req->js, "nodeid", &incoming->peer);
@ -428,10 +428,10 @@ static void try_command(struct commando *incoming STEALS)
json_add_tok(req->js, "method", method, cinfo->buf);
if (params)
json_add_tok(req->js, "params", params, cinfo->buf);
send_outreq(plugin, req);
return send_outreq(plugin, req);
}
static void handle_incmd(struct command *cmd,
static struct command_result *handle_incmd(struct command *cmd,
struct node_id *peer,
u64 idnum,
const u8 *msg, size_t msglen,
@ -462,15 +462,15 @@ static void handle_incmd(struct command *cmd,
append_contents(incmd, msg, msglen, 1024*1024);
if (!terminal)
return;
return command_hook_success(cmd);
if (!incmd->contents) {
plugin_log(plugin, LOG_UNUSUAL, "%s: ignoring oversize request",
fmt_node_id(tmpctx, peer));
return;
return command_hook_success(cmd);
}
try_command(incmd);
return try_command(cmd, incmd);
}
static struct command_result *handle_reply(struct node_id *peer,
@ -592,9 +592,8 @@ static struct command_result *handle_custommsg(struct command *cmd,
switch (mtype) {
case COMMANDO_MSG_CMD_CONTINUES:
case COMMANDO_MSG_CMD_TERM:
handle_incmd(cmd, &peer, idnum, msg, len,
return handle_incmd(cmd, &peer, idnum, msg, len,
mtype == COMMANDO_MSG_CMD_TERM);
break;
case COMMANDO_MSG_REPLY_CONTINUES:
case COMMANDO_MSG_REPLY_TERM:
handle_reply(&peer, idnum, msg, len,