Browse Source

jsonrpc: use tal destructor to remove json commands when required.

This fixes a bug with a plugin duplicating an existing name
where we'd crash, too.

This doesn't work for builtins, which aren't tal objects, so
create a separate path for them.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
fix-test_pay_direct-flake
Rusty Russell 6 years ago
parent
commit
cc76416447
  1. 33
      lightningd/jsonrpc.c
  2. 10
      lightningd/jsonrpc.h
  3. 7
      lightningd/plugin.c

33
lightningd/jsonrpc.c

@ -769,7 +769,20 @@ static struct io_plan *incoming_jcon_connected(struct io_conn *conn,
return jcon_connected(notleak(conn), ld); return jcon_connected(notleak(conn), ld);
} }
bool jsonrpc_command_add(struct jsonrpc *rpc, struct json_command *command) static void destroy_json_command(struct json_command *command, struct jsonrpc *rpc)
{
for (size_t i = 0; i < tal_count(rpc->commands); i++) {
if (rpc->commands[i] == command) {
tal_arr_remove(&rpc->commands, i);
return;
}
}
abort();
}
/* For built-in ones, they're not tal objects, so no destructor */
static bool jsonrpc_command_add_perm(struct jsonrpc *rpc,
struct json_command *command)
{ {
size_t count = tal_count(rpc->commands); size_t count = tal_count(rpc->commands);
@ -782,16 +795,12 @@ bool jsonrpc_command_add(struct jsonrpc *rpc, struct json_command *command)
return true; return true;
} }
void jsonrpc_command_remove(struct jsonrpc *rpc, const char *method) bool jsonrpc_command_add(struct jsonrpc *rpc, struct json_command *command)
{ {
for (size_t i=0; i<tal_count(rpc->commands); i++) { if (!jsonrpc_command_add_perm(rpc, command))
struct json_command *cmd = rpc->commands[i]; return false;
if (streq(cmd->name, method)) { tal_add_destructor2(command, destroy_json_command, rpc);
tal_arr_remove(&rpc->commands, i); return true;
tal_free(cmd);
break;
}
}
} }
struct jsonrpc *jsonrpc_new(const tal_t *ctx, struct lightningd *ld) struct jsonrpc *jsonrpc_new(const tal_t *ctx, struct lightningd *ld)
@ -802,7 +811,9 @@ struct jsonrpc *jsonrpc_new(const tal_t *ctx, struct lightningd *ld)
jsonrpc->commands = tal_arr(jsonrpc, struct json_command *, 0); jsonrpc->commands = tal_arr(jsonrpc, struct json_command *, 0);
jsonrpc->log = new_log(jsonrpc, ld->log_book, "jsonrpc"); jsonrpc->log = new_log(jsonrpc, ld->log_book, "jsonrpc");
for (size_t i=0; i<num_cmdlist; i++) { for (size_t i=0; i<num_cmdlist; i++) {
jsonrpc_command_add(jsonrpc, commands[i]); if (!jsonrpc_command_add_perm(jsonrpc, commands[i]))
fatal("Cannot add duplicate command %s",
commands[i]->name);
} }
jsonrpc->rpc_listener = NULL; jsonrpc->rpc_listener = NULL;
return jsonrpc; return jsonrpc;

10
lightningd/jsonrpc.h

@ -168,16 +168,10 @@ void jsonrpc_listen(struct jsonrpc *rpc, struct lightningd *ld);
* *
* Returns true if the command was added correctly, false if adding * Returns true if the command was added correctly, false if adding
* this would clobber a command name. * this would clobber a command name.
*/
bool jsonrpc_command_add(struct jsonrpc *rpc, struct json_command *command);
/**
* Remove a command/method from the JSON-RPC.
* *
* Used to dynamically remove a `struct json_command` from the * Free @command to remove it.
* JSON-RPC dispatch table by its name.
*/ */
void jsonrpc_command_remove(struct jsonrpc *rpc, const char *method); bool jsonrpc_command_add(struct jsonrpc *rpc, struct json_command *command);
/** /**
* Begin a JSON-RPC notification with the specified topic. * Begin a JSON-RPC notification with the specified topic.

7
lightningd/plugin.c

@ -547,12 +547,6 @@ static bool plugin_opts_add(struct plugin *plugin,
return true; return true;
} }
static void plugin_rpcmethod_destroy(struct json_command *cmd,
struct jsonrpc *rpc)
{
jsonrpc_command_remove(rpc, cmd->name);
}
static void json_stream_forward_change_id(struct json_stream *stream, static void json_stream_forward_change_id(struct json_stream *stream,
const char *buffer, const char *buffer,
const jsmntok_t *toks, const jsmntok_t *toks,
@ -685,7 +679,6 @@ static bool plugin_rpcmethod_add(struct plugin *plugin,
cmd->deprecated = false; cmd->deprecated = false;
cmd->dispatch = plugin_rpcmethod_dispatch; cmd->dispatch = plugin_rpcmethod_dispatch;
tal_add_destructor2(cmd, plugin_rpcmethod_destroy, plugin->plugins->rpc);
if (!jsonrpc_command_add(plugin->plugins->rpc, cmd)) { if (!jsonrpc_command_add(plugin->plugins->rpc, cmd)) {
log_broken(plugin->log, log_broken(plugin->log,
"Could not register method \"%s\", a method with " "Could not register method \"%s\", a method with "

Loading…
Cancel
Save