forked from ElementsProject/lightning
-
Notifications
You must be signed in to change notification settings - Fork 0
/
plugin.h
388 lines (328 loc) · 10.8 KB
/
plugin.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
#ifndef LIGHTNING_LIGHTNINGD_PLUGIN_H
#define LIGHTNING_LIGHTNINGD_PLUGIN_H
#include "config.h"
#include <ccan/intmap/intmap.h>
#include <ccan/io/io.h>
#include <ccan/pipecmd/pipecmd.h>
#include <ccan/take/take.h>
#include <ccan/tal/path/path.h>
#include <ccan/tal/tal.h>
#include <common/json_command.h>
#include <common/jsonrpc_errors.h>
#include <common/memleak.h>
#include <common/param.h>
#include <common/timeout.h>
#include <dirent.h>
#include <errno.h>
#include <lightningd/io_loop_with_timers.h>
#include <lightningd/jsonrpc.h>
#include <lightningd/lightningd.h>
#include <lightningd/log.h>
#include <stdarg.h>
#include <unistd.h>
enum plugin_state {
/* We have to ask getmanifest */
UNCONFIGURED,
/* We sent getmanifest, need response. */
AWAITING_GETMANIFEST_RESPONSE,
/* Got `getmanifest` reply, now we need to send `init`. */
NEEDS_INIT,
/* We have to get `init` response */
AWAITING_INIT_RESPONSE,
/* We have `init` response. */
INIT_COMPLETE
};
/**
* A plugin, exposed as a stub so we can pass it as an argument.
*/
struct plugin {
struct list_node list;
pid_t pid;
char *cmd;
struct io_conn *stdin_conn, *stdout_conn;
struct plugins *plugins;
const char **plugin_path;
/* If there's a json command which ordered this to start */
struct command *start_cmd;
enum plugin_state plugin_state;
/* Our unique index, which is default hook ordering. */
u64 index;
/* If this plugin can be restarted without restarting lightningd */
bool dynamic;
/* Stuff we read */
char *buffer;
size_t used, len_read;
jsmn_parser parser;
jsmntok_t *toks;
/* Our json_streams. Since multiple streams could start
* returning data at once, we always service these in order,
* freeing once empty. */
struct json_stream **js_arr;
struct log *log;
/* List of options that this plugin registered */
struct list_head plugin_opts;
const char **methods;
/* Timer to add a timeout to some plugin RPC calls. Used to
* guarantee that `getmanifest` doesn't block indefinitely. */
const struct oneshot *timeout_timer;
/* An array of subscribed topics */
char **subscriptions;
/* An array of currently pending RPC method calls, to be killed if the
* plugin exits. */
struct list_head pending_rpccalls;
/* If set, the plugin is so important that if it terminates early,
* C-lightning should terminate as well. */
bool important;
/* Parameters for dynamically-started plugins. */
const char *parambuf;
const jsmntok_t *params;
};
/**
* A collection of plugins, and some associated information.
*
* Mainly used as root context for calls in the plugin subsystem.
*/
struct plugins {
struct list_head plugins;
bool startup;
/* Currently pending requests by their request ID */
UINTMAP(struct jsonrpc_request *) pending_requests;
struct log *log;
struct log_book *log_book;
struct lightningd *ld;
const char *default_dir;
/* If there are json commands waiting for plugin resolutions. */
struct command **json_cmds;
/* Blacklist of plugins from --disable-plugin */
const char **blacklist;
/* Whether we are shutting down (`plugins_free` is called) */
bool shutdown;
/* Index to show what order they were added in */
u64 plugin_idx;
#if DEVELOPER
/* Whether builtin plugins should be overridden as unimportant. */
bool dev_builtin_plugins_unimportant;
#endif /* DEVELOPER */
};
/* The value of a plugin option, which can have different types.
* The presence of the integer and boolean values will depend of
* the option type, but the string value will always be filled.
*/
struct plugin_opt_value {
char *as_str;
s64 as_int;
bool as_bool;
};
/**
* Simple storage for plugin options inbetween registering them on the
* command line and passing them off to the plugin
*/
struct plugin_opt {
struct list_node list;
const char *name;
const char *type;
const char *description;
struct plugin_opt_value **values;
/* Might be NULL if no default */
struct plugin_opt_value *def;
bool multi;
bool deprecated;
};
/**
* Create a new plugins context.
*/
struct plugins *plugins_new(const tal_t *ctx, struct log_book *log_book,
struct lightningd *ld);
/**
* Recursively add all plugins from the default plugins directory.
*/
void plugins_add_default_dir(struct plugins *plugins);
/**
* Initialize the registered plugins.
*
* Initialization includes spinning up the plugins, reading their
* manifest, and registering the JSON-RPC passthrough and command line
* arguments. In order to read the getmanifest reply from the plugins
* we spin up our own io_loop that exits once all plugins have
* responded.
*/
void plugins_init(struct plugins *plugins);
/**
* Free all resources that are held by plugins in the correct order.
*
* This function ensures that the resources dangling off of the plugins struct
* are freed in the correct order. This is necessary since the struct manages
* two orthogonal sets of resources:
*
* - Plugins
* - Hook calls and notifications
*
* The tal hierarchy is organized in a plugin centric way, i.e., the plugins
* may exit in an arbitrary order and they'll unregister pointers in the other
* resources. However this will fail if `tal_free` decides to free one of the
* non-plugin resources (technically a sibling in the allocation tree) before
* the plugins we will get a use-after-free. This function fixes this by
* freeing in the correct order without adding additional child-relationships
* in the allocation structure and without adding destructors.
*/
void plugins_free(struct plugins *plugins);
/**
* Register a plugin for initialization and execution.
*
* @param plugins: Plugin context
* @param path: The path of the executable for this plugin
* @param start_cmd: The optional JSON command which caused this.
* @param important: The plugin is important.
* @param parambuf: NULL, or the JSON buffer for extra parameters.
* @param params: NULL, or the tokens for extra parameters.
*
* If @start_cmd, then plugin_cmd_killed or plugin_cmd_succeeded will be called
* on it eventually.
*/
struct plugin *plugin_register(struct plugins *plugins,
const char* path TAKES,
struct command *start_cmd,
bool important,
const char *parambuf STEALS,
const jsmntok_t *params STEALS);
/**
* Returns true if the provided name matches a plugin command
*/
bool plugin_paths_match(const char *cmd, const char *name);
/**
* Remove a plugin registered for initialization.
*
* @param plugins: Plugin context
* @param arg: The basename or fullname of the executable for this plugin
*/
void plugin_blacklist(struct plugins *plugins, const char *name);
/**
* Is a plugin disabled?.
*
* @param plugins: Plugin context
* @param arg: The basename or fullname of the executable for this plugin
*/
bool plugin_blacklisted(struct plugins *plugins, const char *name);
/**
* Kick off initialization of a plugin.
*
* Returns error string, or NULL.
*/
const char *plugin_send_getmanifest(struct plugin *p);
/**
* Kick of initialization of all plugins which need it/
*
* Return true if any were started.
*/
bool plugins_send_getmanifest(struct plugins *plugins);
/**
* Kill a plugin process and free @plugin, with an error message.
*/
void plugin_kill(struct plugin *plugin, enum log_level loglevel,
const char *fmt, ...);
/**
* Returns the plugin which registers the command with name {cmd_name}
*/
struct plugin *find_plugin_for_command(struct lightningd *ld,
const char *cmd_name);
/**
* Call plugin_cmd_all_complete once all plugins are init or killed.
*
* Returns NULL if it's still pending. otherwise, returns
* plugin_cmd_all_complete().
*/
struct command_result *plugin_register_all_complete(struct lightningd *ld,
struct command *cmd);
/**
* Send the configure message to all plugins.
*
* Once we've collected all the command line arguments we can go ahead
* and send them over to the plugin. This finalizes the initialization
* of the plugins and signals that lightningd is now ready to process
* incoming JSON-RPC calls and messages.
*/
void plugins_config(struct plugins *plugins);
/**
* Are any plugins at this state still?
*/
bool plugins_any_in_state(const struct plugins *plugins, enum plugin_state state);
/**
* Are all plugins at this state?
*/
bool plugins_all_in_state(const struct plugins *plugins, enum plugin_state state);
/**
* This populates the jsonrpc request with the plugin/lightningd specifications
*/
void plugin_populate_init_request(struct plugin *p, struct jsonrpc_request *req);
/**
* Add the plugin option and their respective options to listconfigs.
*
* This adds a dict that maps the plugin name to a dict of configuration options
* for the corresponding plugins.
*/
void json_add_opt_plugins(struct json_stream *response,
const struct plugins *plugins);
/**
* Add the disable-plugins options to listconfigs.
*/
void json_add_opt_disable_plugins(struct json_stream *response,
const struct plugins *plugins);
/**
* Used by db hooks which can't have any other I/O while talking to
* hooked plugins.
*
* @param plugins - a `tal`-allocated array of plugins that are the
* only ones we talk to.
*
* @return output of io_loop() (ie. whatever gets passed to io_break()
* to end exclusive loop).
*/
void *plugins_exclusive_loop(struct plugin **plugins);
/**
* Add a directory to the plugin path to automatically load plugins.
*/
char *add_plugin_dir(struct plugins *plugins, const char *dir,
bool error_ok);
/**
* Clear all plugins registered so far.
*/
void clear_plugins(struct plugins *plugins);
void plugins_notify(struct plugins *plugins,
const struct jsonrpc_notification *n TAKES);
/**
* Send a jsonrpc_request to the specified plugin
*/
void plugin_request_send(struct plugin *plugin,
struct jsonrpc_request *req TAKES);
/**
* Callback called when parsing options. It just stores the value in
* the plugin_opt
*/
char *plugin_opt_set(const char *arg, struct plugin_opt *popt);
/**
* Callback called when plugin flag-type options.It just stores
* the value in the plugin_opt
*/
char *plugin_opt_flag_set(struct plugin_opt *popt);
/**
* Helpers to initialize a connection to a plugin; we read from their
* stdout, and write to their stdin.
*/
struct io_plan *plugin_stdin_conn_init(struct io_conn *conn,
struct plugin *plugin);
struct io_plan *plugin_stdout_conn_init(struct io_conn *conn,
struct plugin *plugin);
/**
* Needed for I/O logging for plugin messages.
*/
struct log *plugin_get_log(struct plugin *plugin);
/**
* Tells the plugin system the directory for builtin plugins.
*/
void plugins_set_builtin_plugins_dir(struct plugins *plugins,
const char *dir);
/* Pair of functions to detect if plugin destroys itself: must always
* call both! */
struct plugin_destroyed *plugin_detect_destruction(const struct plugin *plugin);
bool was_plugin_destroyed(struct plugin_destroyed *destroyed);
#endif /* LIGHTNING_LIGHTNINGD_PLUGIN_H */