From a71208b2a0c436643fe5cf399beeb935030caea8 Mon Sep 17 00:00:00 2001 From: Christian Decker Date: Thu, 22 Nov 2018 23:11:26 +0100 Subject: [PATCH] plugin: Remove added JSON-RPC methods if a plugin gets killed Removes the method from the dispatch table, leaving a NULL entry currently. Signed-off-by: Christian Decker <@cdecker> --- lightningd/jsonrpc.c | 23 ++++++++++++++++++----- lightningd/jsonrpc.h | 8 ++++++++ lightningd/lightningd.c | 3 ++- lightningd/plugin.c | 8 ++++++-- 4 files changed, 34 insertions(+), 8 deletions(-) diff --git a/lightningd/jsonrpc.c b/lightningd/jsonrpc.c index cdfc9b2cd..17b88550e 100644 --- a/lightningd/jsonrpc.c +++ b/lightningd/jsonrpc.c @@ -347,11 +347,12 @@ static const struct json_command *find_cmd(const struct jsonrpc *rpc, { struct json_command **commands = rpc->commands; - /* commands[i]->name can be NULL in test code. */ - for (size_t i=0; iname && - json_tok_streq(buffer, tok, commands[i]->name)) - return commands[i]; + /* commands[i] can be NULL if the plugin that registered it + * was killed, commands[i]->name can be NULL in test code. */ + for (size_t i = 0; i < tal_count(commands); i++) + if (commands[i] && commands[i]->name && + json_tok_streq(buffer, tok, commands[i]->name)) + return commands[i]; return NULL; } @@ -738,6 +739,18 @@ bool jsonrpc_command_add(struct jsonrpc *rpc, struct json_command *command) return true; } +void jsonrpc_command_remove(struct jsonrpc *rpc, const char *method) +{ + // FIXME: Currently leaves NULL entries in the table, if we + // restart plugins we should shift them out. + for (size_t i=0; icommands); i++) { + struct json_command *cmd = rpc->commands[i]; + if (cmd && streq(cmd->name, method)) { + rpc->commands[i] = tal_free(cmd); + } + } +} + struct jsonrpc *jsonrpc_new(const tal_t *ctx, struct lightningd *ld) { struct jsonrpc *jsonrpc = tal(ctx, struct jsonrpc); diff --git a/lightningd/jsonrpc.h b/lightningd/jsonrpc.h index 71e7edc09..63b23768d 100644 --- a/lightningd/jsonrpc.h +++ b/lightningd/jsonrpc.h @@ -117,5 +117,13 @@ void jsonrpc_listen(struct jsonrpc *rpc, struct lightningd *ld); */ 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 + * JSON-RPC dispatch table by its name. + */ +void jsonrpc_command_remove(struct jsonrpc *rpc, const char *method); + AUTODATA_TYPE(json_command, struct json_command); #endif /* LIGHTNING_LIGHTNINGD_JSONRPC_H */ diff --git a/lightningd/lightningd.c b/lightningd/lightningd.c index 66eeed417..15f205550 100644 --- a/lightningd/lightningd.c +++ b/lightningd/lightningd.c @@ -781,6 +781,8 @@ int main(int argc, char *argv[]) shutdown_subdaemons(ld); + tal_free(ld->plugins); + /* Clean up the JSON-RPC. This needs to happen in a DB transaction since * it might actually be touching the DB in some destructors, e.g., * unreserving UTXOs (see #1737) */ @@ -788,7 +790,6 @@ int main(int argc, char *argv[]) tal_free(ld->jsonrpc); db_commit_transaction(ld->wallet->db); - tal_free(ld->plugins); remove(ld->pidfile); /* FIXME: pay can have children off tmpctx which unlink from diff --git a/lightningd/plugin.c b/lightningd/plugin.c index a1c3a144a..b85d7559d 100644 --- a/lightningd/plugin.c +++ b/lightningd/plugin.c @@ -118,6 +118,8 @@ static void plugin_kill(struct plugin *plugin, char *msg) plugin->stop = true; io_wake(plugin); kill(plugin->pid, SIGKILL); + list_del(&plugin->list); + tal_free(plugin); } /** @@ -384,8 +386,10 @@ static bool plugin_opts_add(const struct plugin_request *req) return true; } -static void plugin_rpcmethod_destroy(struct json_command *cmd) +static void plugin_rpcmethod_destroy(struct json_command *cmd, + struct jsonrpc *rpc) { + jsonrpc_command_remove(rpc, cmd->name); } static void plugin_rpcmethod_dispatch(struct command *cmd, const char *buffer, @@ -448,7 +452,7 @@ static bool plugin_rpcmethod_add(struct plugin *plugin, const char *buffer, cmd->deprecated = false; cmd->dispatch = plugin_rpcmethod_dispatch; - tal_add_destructor(cmd, plugin_rpcmethod_destroy); + tal_add_destructor2(cmd, plugin_rpcmethod_destroy, plugin->plugins->rpc); if (!jsonrpc_command_add(plugin->plugins->rpc, cmd)) { log_broken(plugin->log, "Could not register method \"%s\", a method with "