Browse Source

daemon: lightning-cli

Minimal possible implementation; not real parsing or pretty printing.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
ppa-0.6.1
Rusty Russell 9 years ago
parent
commit
c28a9ce6c7
  1. 22
      daemon/Makefile
  2. 172
      daemon/lightning-cli.c

22
daemon/Makefile

@ -4,18 +4,24 @@
daemon-wrongdir:
$(MAKE) -C .. daemon-all
daemon-all: daemon/lightningd
daemon-all: daemon/lightningd daemon/lightning-cli
DAEMON_SRC := \
DAEMON_LIB_SRC := \
daemon/configdir.c \
daemon/json.c \
daemon/log.c \
daemon/pseudorand.c
DAEMON_LIB_OBJS := $(DAEMON_LIB_SRC:.c=.o)
DAEMON_SRC := \
daemon/jsonrpc.c \
daemon/lightningd.c \
daemon/log.c \
daemon/pseudorand.c \
daemon/timeout.c
DAEMON_OBJS := $(DAEMON_SRC:.c=.o)
DAEMON_CLI_SRC := daemon/lightning-cli.c
DAEMON_CLI_OBJS := $(DAEMON_CLI_SRC:.c=.o)
DAEMON_JSMN_OBJS := daemon/jsmn.o
DAEMON_JSMN_HEADERS := daemon/jsmn/jsmn.h
@ -28,10 +34,12 @@ DAEMON_HEADERS := \
daemon/pseudorand.h \
daemon/timeout.h
$(DAEMON_OBJS): $(DAEMON_HEADERS) $(DAEMON_JSMN_HEADERS) $(BITCOIN_HEADERS) $(CORE_HEADERS) $(GEN_HEADERS) $(CCAN_HEADERS)
$(DAEMON_OBJS) $(DAEMON_LIB_OBJS) $(DAEMON_CLI_OBJS): $(DAEMON_HEADERS) $(DAEMON_JSMN_HEADERS) $(BITCOIN_HEADERS) $(CORE_HEADERS) $(GEN_HEADERS) $(CCAN_HEADERS)
$(DAEMON_JSMN_OBJS): $(DAEMON_JSMN_HEADERS)
check-source: $(DAEMON_SRC:%=check-src-include-order/%)
check-source: $(DAEMON_LIB_SRC:%=check-src-include-order/%)
check-source: $(DAEMON_CLI_SRC:%=check-src-include-order/%)
check-source: $(DAEMON_HEADERS:%=check-hdr-include-order/%)
check-daemon-makefile:
@if [ "`echo daemon/*.h`" != "$(DAEMON_HEADERS)" ]; then echo DAEMON_HEADERS incorrect; exit 1; fi
@ -44,4 +52,6 @@ daemon/jsmn/jsmn.c:
daemon/jsmn.o: daemon/jsmn/jsmn.c
$(COMPILE.c) -DJSMN_STRICT=1 $(OUTPUT_OPTION) $<
daemon/lightningd: $(DAEMON_OBJS) $(DAEMON_JSMN_OBJS) $(CORE_OBJS) $(BITCOIN_OBJS) $(CCAN_OBJS) libsecp256k1.a
daemon/lightningd: $(DAEMON_OBJS) $(DAEMON_LIB_OBJS) $(DAEMON_JSMN_OBJS) $(CORE_OBJS) $(BITCOIN_OBJS) $(CCAN_OBJS) libsecp256k1.a
daemon/lightning-cli: $(DAEMON_CLI_OBJS) $(DAEMON_LIB_OBJS) $(DAEMON_JSMN_OBJS) $(CORE_OBJS) $(BITCOIN_OBJS) $(CCAN_OBJS) libsecp256k1.a

172
daemon/lightning-cli.c

@ -0,0 +1,172 @@
/*
* Helper to submit via JSON-RPC and get back response.
*/
#include "configdir.h"
#include "json.h"
#include "version.h"
#include <ccan/err/err.h>
#include <ccan/opt/opt.h>
#include <ccan/read_write_all/read_write_all.h>
#include <ccan/str/str.h>
#include <ccan/tal/str/str.h>
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>
#include <unistd.h>
#define NO_ERROR 0
#define ERROR_FROM_LIGHTNINGD 1
#define ERROR_TALKING_TO_LIGHTNINGD 2
#define ERROR_USAGE 3
/* Tal wrappers for opt. */
static void *opt_allocfn(size_t size)
{
return tal_alloc_(NULL, size, false, TAL_LABEL("opt_allocfn", ""));
}
static void *tal_reallocfn(void *ptr, size_t size)
{
if (!ptr)
return opt_allocfn(size);
tal_resize_(&ptr, 1, size, false);
return ptr;
}
static void tal_freefn(void *ptr)
{
tal_free(ptr);
}
int main(int argc, char *argv[])
{
int fd, i, off;
const char *method;
char *cmd, *resp, *idstr, *rpc_filename;
char *result_end;
struct sockaddr_un addr;
jsmntok_t *toks;
const jsmntok_t *result, *error, *id;
char *lightning_dir;
const tal_t *ctx = tal(NULL, char);
size_t num_opens, num_closes;
bool valid;
err_set_progname(argv[0]);
opt_set_alloc(opt_allocfn, tal_reallocfn, tal_freefn);
configdir_register_opts(ctx, &lightning_dir, &rpc_filename);
opt_register_noarg("--help|-h", opt_usage_and_exit,
"<command> [<params>...]", "Show this message");
opt_register_version();
opt_early_parse(argc, argv, opt_log_stderr_exit);
opt_parse(&argc, argv, opt_log_stderr_exit);
method = argv[1];
if (!method)
errx(ERROR_USAGE, "Need at least one argument\n%s",
opt_usage(argv[0], NULL));
if (chdir(lightning_dir) != 0)
err(ERROR_TALKING_TO_LIGHTNINGD, "Moving into '%s'",
lightning_dir);
fd = socket(AF_UNIX, SOCK_STREAM, 0);
if (strlen(rpc_filename) + 1 > sizeof(addr.sun_path))
errx(ERROR_USAGE, "rpc filename '%s' too long", rpc_filename);
strcpy(addr.sun_path, rpc_filename);
addr.sun_family = AF_UNIX;
if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) != 0)
err(ERROR_TALKING_TO_LIGHTNINGD,
"Connecting to '%s'", rpc_filename);
idstr = tal_fmt(ctx, "lightning-cli-%i", getpid());
cmd = tal_fmt(ctx,
"{ \"method\" : \"%s\", \"id\" : \"%s\", \"params\" : [ ",
method, idstr);
for (i = 2; i < argc; i++) {
/* Numbers are left unquoted, and quoted things left alone. */
if (strspn(argv[i], "0123456789") == strlen(argv[i])
|| argv[i][0] == '"')
tal_append_fmt(&cmd, "%s", argv[i]);
else
tal_append_fmt(&cmd, "\"%s\"", argv[i]);
if (i != argc - 1)
tal_append_fmt(&cmd, ", ");
}
tal_append_fmt(&cmd, "] }");
if (!write_all(fd, cmd, strlen(cmd)))
err(ERROR_TALKING_TO_LIGHTNINGD, "Writing command");
resp = tal_arr(cmd, char, 100);
off = 0;
num_opens = num_closes = 0;
while ((i = read(fd, resp + off, tal_count(resp) - 1 - off)) > 0) {
resp[off + i] = '\0';
num_opens += strcount(resp + off, "{");
num_closes += strcount(resp + off, "}");
off += i;
if (off == tal_count(resp) - 1)
tal_resize(&resp, tal_count(resp) * 2);
/* parsing huge outputs is slow: do quick check first. */
if (num_opens == num_closes && strstr(resp, "\"result\""))
break;
}
if (i < 0)
err(ERROR_TALKING_TO_LIGHTNINGD, "reading response");
/* Parsing huge results is too slow, so hack fastpath common case */
result_end = tal_fmt(ctx, ", \"error\" : null, \"id\" : \"%s\" }\n",
idstr);
if (strstarts(resp, "{ \"result\" : ") && strends(resp, result_end)) {
/* Result is OK, so dump it */
resp += strlen("{ \"result\" : ");
printf("%.*s\n", (int)(strlen(resp) - strlen(result_end)), resp);
tal_free(ctx);
return 0;
}
toks = json_parse_input(resp, off, &valid);
if (!toks || !valid)
errx(ERROR_TALKING_TO_LIGHTNINGD,
"Malformed response '%s'", resp);
result = json_get_member(resp, toks, "result");
if (!result)
errx(ERROR_TALKING_TO_LIGHTNINGD,
"Missing 'result' in response '%s'", resp);
error = json_get_member(resp, toks, "error");
if (!error)
errx(ERROR_TALKING_TO_LIGHTNINGD,
"Missing 'error' in response '%s'", resp);
id = json_get_member(resp, toks, "id");
if (!id)
errx(ERROR_TALKING_TO_LIGHTNINGD,
"Missing 'id' in response '%s'", resp);
if (!json_tok_streq(resp, id, idstr))
errx(ERROR_TALKING_TO_LIGHTNINGD,
"Incorrect 'id' in response: %.*s",
json_tok_len(id), json_tok_contents(resp, id));
if (json_tok_is_null(resp, error)) {
printf("%.*s\n",
json_tok_len(result),
json_tok_contents(resp, result));
tal_free(ctx);
return 0;
}
printf("%.*s\n",
json_tok_len(error), json_tok_contents(resp, error));
tal_free(ctx);
return 1;
}
Loading…
Cancel
Save