commit 1eb206600d47b3eb1aadaaa4090f0a4c8d19077b
parent cd612be67e9c79e2d66d879dd6c0a65944694896
Author: William Casarin <jb55@jb55.com>
Date: Sat, 22 Jan 2022 12:30:49 -0800
lnrpc + commando support
Diffstat:
9 files changed, 185 insertions(+), 7 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -1,4 +1,5 @@
.build-result
+/lnrpc
.buildcmd
/.direnv
/tags
diff --git a/Makefile b/Makefile
@@ -54,6 +54,10 @@ test: test.o $(DEPS) $(ARS)
@echo "ld test"
@$(CC) $(CFLAGS) $^ $(LDFLAGS) -o $@
+lnrpc: rpc.o commando.o $(DEPS) $(ARS)
+ @echo "ld lnrpc"
+ @$(CC) $(CFLAGS) $^ $(LDFLAGS) -o $@
+
tags: fake
find . -name '*.c' -or -name '*.h' | xargs ctags
diff --git a/TODO b/TODO
@@ -1,3 +1,6 @@
pull only what is needed from secp and sodium
static lib
dynamic lib
+automatic towire/fromwire serialization
+better helpers for building tlvs
+(A) getinfo request
diff --git a/commando.c b/commando.c
@@ -0,0 +1,41 @@
+
+#include "lnsocket.h"
+#include "cursor.h"
+#include "endian.h"
+
+#define COMMANDO_CMD 0x4c4f
+#define COMMANDO_REPLY_CONTINUES 0x594b
+#define COMMANDO_REPLY_TERM 0x594d
+
+int commando_make_rpc_msg(const char *method, const char *params,
+ const char *rune, uint64_t req_id, unsigned char *buf,
+ int buflen, unsigned short *outlen)
+{
+ struct cursor msgbuf;
+ int ok;
+
+ make_cursor(buf, buf+buflen, &msgbuf);
+
+ params = (params == NULL || params[0] == '\0') ? "[]" : params;
+
+ if (!cursor_push_u16(&msgbuf, COMMANDO_CMD))
+ return 0;
+
+ if (!cursor_push_u64(&msgbuf, req_id))
+ return 0;
+
+ ok = cursor_push_str(&msgbuf, "{\"method\":\"") &&
+ cursor_push_str(&msgbuf, method) &&
+ cursor_push_str(&msgbuf, "\",\"params\":") &&
+ cursor_push_str(&msgbuf, params) &&
+ cursor_push_str(&msgbuf, ",\"rune\":\"") &&
+ cursor_push_str(&msgbuf, rune) &&
+ cursor_push_str(&msgbuf, "\"}");
+
+ if (!ok)
+ return 0;
+
+ *outlen = msgbuf.p - msgbuf.start;
+
+ return 1;
+}
diff --git a/commando.h b/commando.h
@@ -0,0 +1,9 @@
+
+#ifndef LNSOCKET_COMMANDO
+#define LNSOCKET_COMMANDO
+
+#include <inttypes.h>
+
+int commando_make_rpc_msg(const char *method, const char *params, const char *rune, uint64_t req_id, unsigned char *buf, int buflen, unsigned short *outlen);
+
+#endif /* LNSOCKET_COMMANDO */
diff --git a/endian.h b/endian.h
@@ -365,6 +365,15 @@ static inline int cursor_push_u16(struct cursor *cursor, u16 i)
return cursor_push(cursor, &v, sizeof(v));
}
+static inline int cursor_pull_u16(struct cursor *cursor, u16 *i)
+{
+ be16 ret;
+ if (!cursor_pull(cursor, (u8*)&ret, sizeof(ret)))
+ return 0;
+ *i = be16_to_cpu(ret);
+ return 1;
+}
+
static inline int cursor_push_u64(struct cursor *cur, u64 v)
{
be64 l = cpu_to_be64(v);
diff --git a/lnsocket.c b/lnsocket.c
@@ -107,7 +107,7 @@ int lnsocket_perform_init(struct lnsocket *ln)
u8 global_features[2] = {0};
u8 features[5] = {0};
struct tlv network_tlv;
- int len;
+ u16 len;
u8 *buf;
if (!lnsocket_read(ln, &buf, &len))
@@ -140,7 +140,45 @@ int lnsocket_perform_init(struct lnsocket *ln)
return 1;
}
-int lnsocket_read(struct lnsocket *ln, unsigned char **buf, int *len)
+// simple helper that pushes a message type and payload
+int lnsocket_send(struct lnsocket *ln, unsigned short msg_type, const unsigned char *payload, unsigned short payload_len)
+{
+ reset_cursor(&ln->msgbuf);
+
+ if (!cursor_push_u16(&ln->msgbuf, msg_type))
+ return note_error(&ln->errs, "could not write type to msgbuf?");
+
+ if (!cursor_push(&ln->msgbuf, payload, payload_len))
+ return note_error(&ln->errs, "payload too big");
+
+ return lnsocket_write(ln, ln->msgbuf.start, ln->msgbuf.p - ln->msgbuf.start);
+}
+
+// simple helper that receives a message type and payload
+int lnsocket_recv(struct lnsocket *ln, u16 *msg_type, unsigned char **payload, u16 *payload_len)
+{
+ struct cursor cur;
+ u8 *msg;
+ u16 msglen;
+
+ if (!lnsocket_read(ln, &msg, &msglen))
+ return 0;
+
+ make_cursor(msg, msg + msglen, &cur);
+
+ if (!cursor_pull_u16(&cur, msg_type))
+ return note_error(&ln->errs, "could not read msgtype");
+
+ *payload_len = msglen - 2;
+ *payload = cur.p;
+
+ if (*payload + *payload_len > cur.end)
+ return note_error(&ln->errs, "recv buffer overflow?");
+
+ return 1;
+}
+
+int lnsocket_read(struct lnsocket *ln, unsigned char **buf, unsigned short *len)
{
struct cursor enc, dec;
u8 hdr[18];
@@ -280,7 +318,7 @@ int lnsocket_make_init_msg(unsigned char *buf, int buflen,
const unsigned char *features, u16 flen,
const struct tlv **tlvs,
unsigned short num_tlvs,
- int *outlen)
+ unsigned short *outlen)
{
struct cursor msg;
@@ -309,7 +347,7 @@ int lnsocket_make_init_msg(unsigned char *buf, int buflen,
return 1;
}
-int lnsocket_write(struct lnsocket *ln, const u8 *msg, int msglen)
+int lnsocket_write(struct lnsocket *ln, const u8 *msg, unsigned short msglen)
{
ssize_t writelen, outcap;
size_t outlen;
diff --git a/lnsocket.h b/lnsocket.h
@@ -64,13 +64,18 @@ struct lnsocket *lnsocket_create();
int lnsocket_make_network_tlv(unsigned char *buf, int buflen, const unsigned char **blockids, int num_blockids, struct tlv *tlv_out);
int lnsocket_make_ping_msg(unsigned char *buf, int buflen, unsigned short num_pong_bytes, unsigned short ignored_bytes, int *outlen);
-int lnsocket_make_init_msg(unsigned char *buf, int buflen, const unsigned char *globalfeatures, unsigned short gflen, const unsigned char *features, unsigned short flen, const struct tlv **tlvs, unsigned short num_tlvs, int *outlen);
+int lnsocket_make_init_msg(unsigned char *buf, int buflen, const unsigned char *globalfeatures, unsigned short gflen, const unsigned char *features, unsigned short flen, const struct tlv **tlvs, unsigned short num_tlvs, unsigned short *outlen);
int lnsocket_perform_init(struct lnsocket *ln);
int lnsocket_connect(struct lnsocket *, const char *node_id, const char *host);
-int lnsocket_write(struct lnsocket *, const unsigned char *msg, int msg_len);
-int lnsocket_read(struct lnsocket *, unsigned char **buf, int *len);
+
+int lnsocket_write(struct lnsocket *, const unsigned char *msg, unsigned short msg_len);
+int lnsocket_read(struct lnsocket *, unsigned char **buf, unsigned short *len);
+
+int lnsocket_send(struct lnsocket *, unsigned short msg_type, const unsigned char *payload, unsigned short payload_len);
+int lnsocket_recv(struct lnsocket *, unsigned short *msg_type, unsigned char **payload, unsigned short *payload_len);
+
void lnsocket_genkey(struct lnsocket *);
void lnsocket_destroy(struct lnsocket *);
void lnsocket_print_errors(struct lnsocket *);
diff --git a/rpc.c b/rpc.c
@@ -0,0 +1,68 @@
+
+#include <stdlib.h>
+
+#include "lnsocket.h"
+#include "endian.h"
+#include "typedefs.h"
+#include "commando.h"
+
+#include <stdio.h>
+#include <assert.h>
+
+int usage()
+{
+ printf("lnrpc <nodeid> <ip/hostname> <method> <params> <rune>\n\n");
+ return 0;
+}
+
+int main(int argc, const char *argv[])
+{
+ static u8 msgbuf[4096];
+ u8 *buf;
+ struct lnsocket *ln;
+ u16 len, msgtype;
+ int ok = 1;
+ int verbose = getenv("VERBOSE") != 0;
+ //int verbose = 1;
+
+ if (argc < 6)
+ return usage();
+
+ ln = lnsocket_create();
+ assert(ln);
+
+ lnsocket_genkey(ln);
+
+ const char *nodeid = argv[1];
+ const char *host = argv[2];
+ const char *method = argv[3];
+ const char *params = argv[4];
+ const char *rune = argv[5];
+
+ if (!(ok = lnsocket_connect(ln, nodeid, host)))
+ goto done;
+
+ if (!(ok = lnsocket_perform_init(ln)))
+ goto done;
+
+ if (verbose)
+ fprintf(stderr, "init success\n");
+
+ if (!(ok = commando_make_rpc_msg(method, params, rune, 1, msgbuf, sizeof(msgbuf), &len)))
+ goto done;
+
+ if (!(ok = lnsocket_write(ln, msgbuf, len)))
+ goto done;
+
+ if (verbose)
+ fprintf(stderr, "waiting for response...\n");
+
+ if (!(ok = lnsocket_recv(ln, &msgtype, &buf, &len)))
+ goto done;
+
+ printf("%.*s\n", len - 8, buf + 8);
+done:
+ lnsocket_print_errors(ln);
+ lnsocket_destroy(ln);
+ return !ok;
+}