mirror of
https://github.com/aljazceru/lightning.git
synced 2026-01-10 09:34:22 +01:00
plugin: handle corner case where rpc_command is to stop the plugin.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
committed by
Christian Decker
parent
d8fc5332c3
commit
f6ed7f2e89
@@ -233,6 +233,7 @@ static void plugin_response_handle(struct plugin *plugin,
|
||||
const jsmntok_t *toks,
|
||||
const jsmntok_t *idtok)
|
||||
{
|
||||
struct plugin_destroyed *pd;
|
||||
struct jsonrpc_request *request;
|
||||
u64 id;
|
||||
/* We only send u64 ids, so if this fails it's a critical error (note
|
||||
@@ -253,9 +254,13 @@ static void plugin_response_handle(struct plugin *plugin,
|
||||
}
|
||||
|
||||
/* We expect the request->cb to copy if needed */
|
||||
pd = plugin_detect_destruction(plugin);
|
||||
request->response_cb(plugin->buffer, toks, idtok, request->response_cb_arg);
|
||||
|
||||
tal_free(request);
|
||||
/* Note that in the case of 'plugin stop' this can free request (since
|
||||
* plugin is parent), so detect that case */
|
||||
if (!was_plugin_destroyed(pd))
|
||||
tal_free(request);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -264,10 +269,15 @@ static void plugin_response_handle(struct plugin *plugin,
|
||||
* Internally calls the handler if it was able to fully parse a JSON message,
|
||||
* and returns true in that case.
|
||||
*/
|
||||
static bool plugin_read_json_one(struct plugin *plugin)
|
||||
static bool plugin_read_json_one(struct plugin *plugin, bool *destroyed)
|
||||
{
|
||||
bool valid;
|
||||
const jsmntok_t *toks, *jrtok, *idtok;
|
||||
struct plugin_destroyed *pd;
|
||||
|
||||
*destroyed = false;
|
||||
/* Note that in the case of 'plugin stop' this can free request (since
|
||||
* plugin is parent), so detect that case */
|
||||
|
||||
/* FIXME: This could be done more efficiently by storing the
|
||||
* toks and doing an incremental parse, like lightning-cli
|
||||
@@ -300,6 +310,7 @@ static bool plugin_read_json_one(struct plugin *plugin)
|
||||
return false;
|
||||
}
|
||||
|
||||
pd = plugin_detect_destruction(plugin);
|
||||
if (!idtok) {
|
||||
/* A Notification is a Request object without an "id"
|
||||
* member. A Request object that is a Notification
|
||||
@@ -345,15 +356,21 @@ static bool plugin_read_json_one(struct plugin *plugin)
|
||||
plugin_response_handle(plugin, toks, idtok);
|
||||
}
|
||||
|
||||
/* Move this object out of the buffer */
|
||||
memmove(plugin->buffer, plugin->buffer + toks[0].end,
|
||||
tal_count(plugin->buffer) - toks[0].end);
|
||||
plugin->used -= toks[0].end;
|
||||
tal_free(toks);
|
||||
/* Corner case: rpc_command hook can destroy plugin for 'plugin
|
||||
* stop'! */
|
||||
if (was_plugin_destroyed(pd)) {
|
||||
*destroyed = true;
|
||||
} else {
|
||||
/* Move this object out of the buffer */
|
||||
memmove(plugin->buffer, plugin->buffer + toks[0].end,
|
||||
tal_count(plugin->buffer) - toks[0].end);
|
||||
plugin->used -= toks[0].end;
|
||||
tal_free(toks);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static struct io_plan *plugin_read_json(struct io_conn *conn UNUSED,
|
||||
static struct io_plan *plugin_read_json(struct io_conn *conn,
|
||||
struct plugin *plugin)
|
||||
{
|
||||
bool success;
|
||||
@@ -367,7 +384,12 @@ static struct io_plan *plugin_read_json(struct io_conn *conn UNUSED,
|
||||
|
||||
/* Read and process all messages from the connection */
|
||||
do {
|
||||
success = plugin_read_json_one(plugin);
|
||||
bool destroyed;
|
||||
success = plugin_read_json_one(plugin, &destroyed);
|
||||
|
||||
/* If it's destroyed, conn is already freed! */
|
||||
if (destroyed)
|
||||
return io_close(NULL);
|
||||
|
||||
/* Processing the message from the plugin might have
|
||||
* resulted in it stopping, so let's check. */
|
||||
@@ -1203,3 +1225,32 @@ struct log *plugin_get_log(struct plugin *plugin)
|
||||
{
|
||||
return plugin->log;
|
||||
}
|
||||
|
||||
struct plugin_destroyed {
|
||||
const struct plugin *plugin;
|
||||
};
|
||||
|
||||
static void mark_plugin_destroyed(const struct plugin *unused,
|
||||
struct plugin_destroyed *pd)
|
||||
{
|
||||
pd->plugin = NULL;
|
||||
}
|
||||
|
||||
struct plugin_destroyed *plugin_detect_destruction(const struct plugin *plugin)
|
||||
{
|
||||
struct plugin_destroyed *pd = tal(NULL, struct plugin_destroyed);
|
||||
pd->plugin = plugin;
|
||||
tal_add_destructor2(plugin, mark_plugin_destroyed, pd);
|
||||
return pd;
|
||||
}
|
||||
|
||||
bool was_plugin_destroyed(struct plugin_destroyed *pd)
|
||||
{
|
||||
if (pd->plugin) {
|
||||
tal_del_destructor2(pd->plugin, mark_plugin_destroyed, pd);
|
||||
tal_free(pd);
|
||||
return false;
|
||||
}
|
||||
tal_free(pd);
|
||||
return true;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user