Browse Source

libplugin: include the rpc conn into the global state

And rename the struct name, as it's now only used for RPC.
travis-debug
darosior 5 years ago
committed by Rusty Russell
parent
commit
499dce1c38
  1. 6
      plugins/autoclean.c
  2. 6
      plugins/fundchannel.c
  3. 153
      plugins/libplugin.c
  4. 58
      plugins/libplugin.h
  5. 10
      plugins/pay.c

6
plugins/autoclean.c

@ -8,7 +8,7 @@
static u64 cycle_seconds = 0, expired_by = 86400;
static struct plugin_timer *cleantimer;
static struct plugin_conn *rpc;
static struct rpc_conn *rpc;
static struct command_result *do_clean(void);
@ -65,10 +65,10 @@ static struct command_result *json_autocleaninvoice(struct command *cmd,
expired_by, cycle_seconds));
}
static void init(struct plugin_conn *prpc,
static void init(struct plugin *p,
const char *buf UNUSED, const jsmntok_t *config UNUSED)
{
rpc = prpc;
rpc = &p->rpc_conn;
if (cycle_seconds) {
plugin_log(LOG_INFORM, "autocleaning every %"PRIu64" seconds", cycle_seconds);

6
plugins/fundchannel.c

@ -485,17 +485,17 @@ static struct command_result *json_fundchannel(struct command *cmd,
return connect_to_peer(cmd, fr);
}
static void init(struct plugin_conn *rpc,
static void init(struct plugin *p,
const char *buf UNUSED, const jsmntok_t *config UNUSED)
{
/* Figure out what the 'placeholder' addr is */
const char *network_name;
u8 *placeholder = tal_hexdata(tmpctx, placeholder_script, strlen(placeholder_script));
network_name = rpc_delve(tmpctx, "listconfigs",
network_name = rpc_delve(tmpctx, p, "listconfigs",
take(json_out_obj(NULL, "config",
"network")),
rpc, ".network");
".network");
chainparams = chainparams_for_network(network_name);
placeholder_funding_addr = encode_scriptpubkey_to_addr(NULL, chainparams,
placeholder);

153
plugins/libplugin.c

@ -3,7 +3,6 @@
#include <ccan/intmap/intmap.h>
#include <ccan/io/io.h>
#include <ccan/json_out/json_out.h>
#include <ccan/membuf/membuf.h>
#include <ccan/read_write_all/read_write_all.h>
#include <ccan/strmap/strmap.h>
#include <ccan/tal/str/str.h>
@ -39,56 +38,11 @@ bool deprecated_apis;
extern const struct chainparams *chainparams;
struct plugin {
/* lightningd interaction */
struct io_conn *stdin_conn;
struct io_conn *stdout_conn;
/* To read from lightningd */
char *buffer;
size_t used, len_read;
/* To write to lightningd */
struct json_stream **js_arr;
enum plugin_restartability restartability;
const struct plugin_command *commands;
size_t num_commands;
const struct plugin_notification *notif_subs;
size_t num_notif_subs;
const struct plugin_hook *hook_subs;
size_t num_hook_subs;
struct plugin_option *opts;
/* Anything special to do at init ? */
void (*init)(struct plugin_conn *,
const char *buf, const jsmntok_t *);
/* Has the manifest been sent already ? */
bool manifested;
/* Has init been received ? */
bool initialized;
};
struct plugin_timer {
struct timer timer;
struct command_result *(*cb)(void);
};
struct plugin_conn {
int fd;
MEMBUF(char) mb;
};
/* Connection to make RPC requests. */
static struct plugin_conn rpc_conn;
struct command {
u64 *id;
const char *methodname;
bool usage_only;
struct plugin *plugin;
};
struct out_req {
/* The unique id of this request. */
u64 id;
@ -109,7 +63,7 @@ struct out_req {
/* command_result is mainly used as a compile-time check to encourage you
* to return as soon as you get one (and not risk use-after-free of command).
* Here we use two values: complete (cmd freed) an pending (still going) */
* Here we use two values: complete (cmd freed) and pending (still going) */
struct command_result {
char c;
};
@ -177,30 +131,30 @@ static void *membuf_tal_realloc(struct membuf *mb, void *rawelems,
return p;
}
static int read_json(struct plugin_conn *conn)
static int read_json_from_rpc(struct plugin *p)
{
char *end;
/* We rely on the double-\n marker which only terminates JSON top
* levels. Thanks lightningd! */
while ((end = memmem(membuf_elems(&conn->mb),
membuf_num_elems(&conn->mb), "\n\n", 2))
while ((end = memmem(membuf_elems(&p->rpc_conn.mb),
membuf_num_elems(&p->rpc_conn.mb), "\n\n", 2))
== NULL) {
ssize_t r;
/* Make sure we've room for at least READ_CHUNKSIZE. */
membuf_prepare_space(&conn->mb, READ_CHUNKSIZE);
r = read(conn->fd, membuf_space(&conn->mb),
membuf_num_space(&conn->mb));
membuf_prepare_space(&p->rpc_conn.mb, READ_CHUNKSIZE);
r = read(p->rpc_conn.fd, membuf_space(&p->rpc_conn.mb),
membuf_num_space(&p->rpc_conn.mb));
/* lightningd goes away, we go away. */
if (r == 0)
exit(0);
if (r < 0)
plugin_err("Reading JSON input: %s", strerror(errno));
membuf_added(&conn->mb, r);
membuf_added(&p->rpc_conn.mb, r);
}
return end + 2 - membuf_elems(&conn->mb);
return end + 2 - membuf_elems(&p->rpc_conn.mb);
}
/* This starts a JSON RPC message with boilerplate */
@ -355,7 +309,7 @@ void command_set_usage(struct command *cmd, const char *usage TAKES)
/* Reads rpc reply and returns tokens, setting contents to 'error' or
* 'result' (depending on *error). */
static const jsmntok_t *read_rpc_reply(const tal_t *ctx,
struct plugin_conn *rpc,
struct plugin *plugin,
const jsmntok_t **contents,
bool *error,
int *reqlen)
@ -363,22 +317,22 @@ static const jsmntok_t *read_rpc_reply(const tal_t *ctx,
const jsmntok_t *toks;
bool valid;
*reqlen = read_json(rpc);
*reqlen = read_json_from_rpc(plugin);
toks = json_parse_input(ctx, membuf_elems(&rpc->mb), *reqlen, &valid);
toks = json_parse_input(ctx, membuf_elems(&plugin->rpc_conn.mb), *reqlen, &valid);
if (!valid)
plugin_err("Malformed JSON reply '%.*s'",
*reqlen, membuf_elems(&rpc->mb));
*reqlen, membuf_elems(&plugin->rpc_conn.mb));
*contents = json_get_member(membuf_elems(&rpc->mb), toks, "error");
*contents = json_get_member(membuf_elems(&plugin->rpc_conn.mb), toks, "error");
if (*contents)
*error = true;
else {
*contents = json_get_member(membuf_elems(&rpc->mb), toks,
*contents = json_get_member(membuf_elems(&plugin->rpc_conn.mb), toks,
"result");
if (!*contents)
plugin_err("JSON reply with no 'result' nor 'error'? '%.*s'",
*reqlen, membuf_elems(&rpc->mb));
*reqlen, membuf_elems(&plugin->rpc_conn.mb));
*error = false;
}
return toks;
@ -402,9 +356,10 @@ static struct json_out *start_json_request(const tal_t *ctx,
/* Synchronous routine to send command and extract single field from response */
const char *rpc_delve(const tal_t *ctx,
struct plugin *plugin,
const char *method,
const struct json_out *params TAKES,
struct plugin_conn *rpc, const char *guide)
const char *guide)
{
bool error;
const jsmntok_t *contents, *t;
@ -413,24 +368,24 @@ const char *rpc_delve(const tal_t *ctx,
struct json_out *jout;
jout = start_json_request(tmpctx, 0, method, params);
finish_and_send_json(rpc->fd, jout);
finish_and_send_json(plugin->rpc_conn.fd, jout);
read_rpc_reply(tmpctx, rpc, &contents, &error, &reqlen);
read_rpc_reply(tmpctx, plugin, &contents, &error, &reqlen);
if (error)
plugin_err("Got error reply to %s: '%.*s'",
method, reqlen, membuf_elems(&rpc->mb));
method, reqlen, membuf_elems(&plugin->rpc_conn.mb));
t = json_delve(membuf_elems(&rpc->mb), contents, guide);
t = json_delve(membuf_elems(&plugin->rpc_conn.mb), contents, guide);
if (!t)
plugin_err("Could not find %s in reply to %s: '%.*s'",
guide, method, reqlen, membuf_elems(&rpc->mb));
guide, method, reqlen, membuf_elems(&plugin->rpc_conn.mb));
ret = json_strdup(ctx, membuf_elems(&rpc->mb), t);
membuf_consume(&rpc->mb, reqlen);
ret = json_strdup(ctx, membuf_elems(&plugin->rpc_conn.mb), t);
membuf_consume(&plugin->rpc_conn.mb, reqlen);
return ret;
}
static void handle_rpc_reply(struct plugin_conn *rpc)
static void handle_rpc_reply(struct plugin *plugin)
{
int reqlen;
const jsmntok_t *toks, *contents, *t;
@ -439,33 +394,33 @@ static void handle_rpc_reply(struct plugin_conn *rpc)
u64 id;
bool error;
toks = read_rpc_reply(tmpctx, rpc, &contents, &error, &reqlen);
toks = read_rpc_reply(tmpctx, plugin, &contents, &error, &reqlen);
t = json_get_member(membuf_elems(&rpc->mb), toks, "id");
t = json_get_member(membuf_elems(&plugin->rpc_conn.mb), toks, "id");
if (!t)
plugin_err("JSON reply without id '%.*s'",
reqlen, membuf_elems(&rpc->mb));
if (!json_to_u64(membuf_elems(&rpc->mb), t, &id))
reqlen, membuf_elems(&plugin->rpc_conn.mb));
if (!json_to_u64(membuf_elems(&plugin->rpc_conn.mb), t, &id))
plugin_err("JSON reply without numeric id '%.*s'",
reqlen, membuf_elems(&rpc->mb));
reqlen, membuf_elems(&plugin->rpc_conn.mb));
out = uintmap_get(&out_reqs, id);
if (!out)
plugin_err("JSON reply with unknown id '%.*s' (%"PRIu64")",
reqlen, membuf_elems(&rpc->mb), id);
reqlen, membuf_elems(&plugin->rpc_conn.mb), id);
/* We want to free this if callback doesn't. */
tal_steal(tmpctx, out);
uintmap_del(&out_reqs, out->id);
if (error)
res = out->errcb(out->cmd, membuf_elems(&rpc->mb), contents,
out->arg);
res = out->errcb(out->cmd, membuf_elems(&plugin->rpc_conn.mb),
contents, out->arg);
else
res = out->cb(out->cmd, membuf_elems(&rpc->mb), contents,
out->arg);
res = out->cb(out->cmd, membuf_elems(&plugin->rpc_conn.mb),
contents, out->arg);
assert(res == &pending || res == &complete);
membuf_consume(&rpc->mb, reqlen);
membuf_consume(&plugin->rpc_conn.mb, reqlen);
}
struct command_result *
@ -494,7 +449,7 @@ send_outreq_(struct command *cmd,
uintmap_add(&out_reqs, out->id, out);
jout = start_json_request(tmpctx, out->id, method, params);
finish_and_send_json(rpc_conn.fd, jout);
finish_and_send_json(cmd->plugin->rpc_conn.fd, jout);
return &pending;
}
@ -572,7 +527,7 @@ static struct command_result *handle_init(struct command *cmd,
chainparams = chainparams_for_network(network);
rpctok = json_delve(buf, configtok, ".rpc-file");
rpc_conn.fd = socket(AF_UNIX, SOCK_STREAM, 0);
p->rpc_conn.fd = socket(AF_UNIX, SOCK_STREAM, 0);
if (rpctok->end - rpctok->start + 1 > sizeof(addr.sun_path))
plugin_err("rpc filename '%.*s' too long",
rpctok->end - rpctok->start,
@ -581,15 +536,14 @@ static struct command_result *handle_init(struct command *cmd,
addr.sun_path[rpctok->end - rpctok->start] = '\0';
addr.sun_family = AF_UNIX;
if (connect(rpc_conn.fd, (struct sockaddr *)&addr, sizeof(addr)) != 0)
if (connect(p->rpc_conn.fd, (struct sockaddr *)&addr, sizeof(addr)) != 0)
plugin_err("Connecting to '%.*s': %s",
rpctok->end - rpctok->start, buf + rpctok->start,
strerror(errno));
param_obj = json_out_obj(NULL, "config", "allow-deprecated-apis");
deprecated_apis = streq(rpc_delve(tmpctx, "listconfigs",
deprecated_apis = streq(rpc_delve(tmpctx, p, "listconfigs",
take(param_obj),
&rpc_conn,
".allow-deprecated-apis"),
"true");
opttok = json_get_member(buf, params, "options");
@ -610,7 +564,7 @@ static struct command_result *handle_init(struct command *cmd,
}
if (p->init)
p->init(&rpc_conn, buf, configtok);
p->init(p, buf, configtok);
return command_success_str(cmd, NULL);
}
@ -652,7 +606,7 @@ static void setup_command_usage(const struct plugin_command *commands,
}
}
static void call_plugin_timer(struct plugin_conn *rpc, struct timer *timer)
static void call_plugin_timer(struct rpc_conn *rpc, struct timer *timer)
{
struct plugin_timer *t = container_of(timer, struct plugin_timer, timer);
@ -667,7 +621,7 @@ static void destroy_plugin_timer(struct plugin_timer *timer)
timer_del(&timers, &timer->timer);
}
struct plugin_timer *plugin_timer(struct plugin_conn *rpc, struct timerel t,
struct plugin_timer *plugin_timer(struct rpc_conn *rpc, struct timerel t,
struct command_result *(*cb)(void))
{
struct plugin_timer *timer = tal(NULL, struct plugin_timer);
@ -927,7 +881,7 @@ static struct io_plan *stdout_conn_init(struct io_conn *conn,
}
static struct plugin *new_plugin(const tal_t *ctx,
void (*init)(struct plugin_conn *rpc,
void (*init)(struct plugin *p,
const char *buf, const jsmntok_t *),
const enum plugin_restartability restartability,
const struct plugin_command *commands,
@ -945,6 +899,10 @@ static struct plugin *new_plugin(const tal_t *ctx,
p->js_arr = tal_arr(p, struct json_stream *, 0);
p->used = 0;
p->len_read = 0;
/* rpc. TODO: use ccan/io also for RPC */
membuf_init(&p->rpc_conn.mb,
tal_arr(p, char, READ_CHUNKSIZE), READ_CHUNKSIZE,
membuf_tal_realloc);
p->init = init;
p->manifested = p->initialized = false;
@ -972,7 +930,7 @@ static struct plugin *new_plugin(const tal_t *ctx,
}
void plugin_main(char *argv[],
void (*init)(struct plugin_conn *rpc,
void (*init)(struct plugin *p,
const char *buf, const jsmntok_t *),
const enum plugin_restartability restartability,
const struct plugin_command *commands,
@ -1000,12 +958,9 @@ void plugin_main(char *argv[],
notif_subs, num_notif_subs, hook_subs,
num_hook_subs, ap);
va_end(ap);
uintmap_init(&out_reqs);
timers_init(&timers, time_mono());
membuf_init(&rpc_conn.mb,
tal_arr(plugin, char, READ_CHUNKSIZE), READ_CHUNKSIZE,
membuf_tal_realloc);
uintmap_init(&out_reqs);
io_new_conn(plugin, STDIN_FILENO, stdin_conn_init, plugin);
io_new_conn(plugin, STDOUT_FILENO, stdout_conn_init, plugin);
@ -1015,14 +970,14 @@ void plugin_main(char *argv[],
clean_tmpctx();
if (membuf_num_elems(&rpc_conn.mb) != 0) {
handle_rpc_reply(&rpc_conn);
if (membuf_num_elems(&plugin->rpc_conn.mb) != 0) {
handle_rpc_reply(plugin);
continue;
}
/* Will only exit if a timer has expired. */
io_loop(&timers, &expired);
call_plugin_timer(&rpc_conn, expired);
call_plugin_timer(&plugin->rpc_conn, expired);
}
tal_free(plugin);

58
plugins/libplugin.h

@ -3,6 +3,7 @@
#define LIGHTNING_PLUGINS_LIBPLUGIN_H
#include "config.h"
#include <ccan/ccan/membuf/membuf.h>
#include <ccan/time/time.h>
#include <common/errcode.h>
#include <common/json.h>
@ -12,17 +13,59 @@
#include <common/param.h>
#include <common/status_levels.h>
struct command;
struct json_out;
struct plugin_conn;
extern bool deprecated_apis;
enum plugin_restartability {
PLUGIN_STATIC,
PLUGIN_RESTARTABLE
};
struct rpc_conn {
int fd;
MEMBUF(char) mb;
};
struct plugin {
/* lightningd interaction */
struct io_conn *stdin_conn;
struct io_conn *stdout_conn;
/* To read from lightningd */
char *buffer;
size_t used, len_read;
/* To write to lightningd */
struct json_stream **js_arr;
struct rpc_conn rpc_conn;
enum plugin_restartability restartability;
const struct plugin_command *commands;
size_t num_commands;
const struct plugin_notification *notif_subs;
size_t num_notif_subs;
const struct plugin_hook *hook_subs;
size_t num_hook_subs;
struct plugin_option *opts;
/* Anything special to do at init ? */
void (*init)(struct plugin *p,
const char *buf, const jsmntok_t *);
/* Has the manifest been sent already ? */
bool manifested;
/* Has init been received ? */
bool initialized;
};
struct command {
u64 *id;
const char *methodname;
bool usage_only;
struct plugin *plugin;
};
extern bool deprecated_apis;
/* Create an array of these, one for each command you support. */
struct plugin_command {
const char *name;
@ -96,9 +139,10 @@ command_success_str(struct command *cmd, const char *str);
/* Synchronous helper to send command and extract single field from
* response; can only be used in init callback. */
const char *rpc_delve(const tal_t *ctx,
struct plugin *plugin,
const char *method,
const struct json_out *params TAKES,
struct plugin_conn *rpc, const char *guide);
const char *guide);
/* Async rpc request.
* @cmd can be NULL if we're coming from a timer callback.
@ -154,7 +198,7 @@ struct command_result *timer_complete(void);
* Freeing this releases the timer, otherwise it's freed after @cb
* if it hasn't been freed already.
*/
struct plugin_timer *plugin_timer(struct plugin_conn *rpc,
struct plugin_timer *plugin_timer(struct rpc_conn *rpc,
struct timerel t,
struct command_result *(*cb)(void));
@ -175,7 +219,7 @@ char *charp_option(const char *arg, char **p);
/* The main plugin runner: append with 0 or more plugin_option(), then NULL. */
void NORETURN LAST_ARG_NULL plugin_main(char *argv[],
void (*init)(struct plugin_conn *rpc,
void (*init)(struct plugin *p,
const char *buf, const jsmntok_t *),
const enum plugin_restartability restartability,
const struct plugin_command *commands,

10
plugins/pay.c

@ -1666,20 +1666,20 @@ static struct command_result *json_listpays(struct command *cmd,
take(json_out_obj(NULL, "bolt11", b11str)));
}
static void init(struct plugin_conn *rpc,
static void init(struct plugin *p,
const char *buf UNUSED, const jsmntok_t *config UNUSED)
{
const char *field;
field = rpc_delve(tmpctx, "getinfo",
take(json_out_obj(NULL, NULL, NULL)), rpc, ".id");
field = rpc_delve(tmpctx, p, "getinfo",
take(json_out_obj(NULL, NULL, NULL)), ".id");
if (!node_id_from_hexstr(field, strlen(field), &my_id))
plugin_err("getinfo didn't contain valid id: '%s'", field);
field = rpc_delve(tmpctx, "listconfigs",
field = rpc_delve(tmpctx, p, "listconfigs",
take(json_out_obj(NULL,
"config", "max-locktime-blocks")),
rpc, ".max-locktime-blocks");
".max-locktime-blocks");
maxdelay_default = atoi(field);
}

Loading…
Cancel
Save