diff --git a/lightningd/Makefile b/lightningd/Makefile index 9727997f6..92f5aa40e 100644 --- a/lightningd/Makefile +++ b/lightningd/Makefile @@ -59,8 +59,7 @@ LIGHTNINGD_SRC := \ lightningd/hsm_control.c \ lightningd/lightningd.c \ lightningd/peer_control.c \ - lightningd/subd.c \ - lightningd/subdaemon.c + lightningd/subd.c LIGHTNINGD_OBJS := $(LIGHTNINGD_SRC:.c=.o) @@ -75,7 +74,6 @@ LIGHTNINGD_HEADERS_NOGEN = \ lightningd/lightningd.h \ lightningd/peer_control.h \ lightningd/subd.h \ - lightningd/subdaemon.h \ $(LIGHTNINGD_OLD_LIB_HEADERS) \ $(LIGHTNINGD_LIB_HEADERS) \ $(WIRE_HEADERS) \ diff --git a/lightningd/gossip_control.c b/lightningd/gossip_control.c index e1e6f4516..c497315ac 100644 --- a/lightningd/gossip_control.c +++ b/lightningd/gossip_control.c @@ -2,7 +2,6 @@ #include "lightningd.h" #include "peer_control.h" #include "subd.h" -#include "subdaemon.h" #include #include #include @@ -58,8 +57,7 @@ static void peer_nongossip(struct subd *gossip, const u8 *msg, int fd) if (!peer) fatal("Gossip gave bad peerid %"PRIu64, unique_id); - /* FIXME! */ - if (peer->owner != (struct subdaemon *)gossip) + if (peer->owner != gossip) fatal("Gossip gave bad peerid %"PRIu64" (owner %s)", unique_id, peer->owner ? peer->owner->name : "(none)"); diff --git a/lightningd/lightningd.c b/lightningd/lightningd.c index 7e08072a1..72e837a1f 100644 --- a/lightningd/lightningd.c +++ b/lightningd/lightningd.c @@ -3,7 +3,6 @@ #include "lightningd.h" #include "peer_control.h" #include "subd.h" -#include "subdaemon.h" #include #include #include diff --git a/lightningd/peer_control.c b/lightningd/peer_control.c index 1d680b90d..8cf27d22e 100644 --- a/lightningd/peer_control.c +++ b/lightningd/peer_control.c @@ -1,7 +1,6 @@ #include "lightningd.h" #include "peer_control.h" #include "subd.h" -#include "subdaemon.h" #include #include #include @@ -130,8 +129,7 @@ static bool handshake_succeeded(struct subd *hs, const u8 *msg, /* FIXME: Look for peer duplicates! */ - /* FIXME! */ - peer->owner = (struct subdaemon *)peer->ld->gossip; + peer->owner = peer->ld->gossip; tal_steal(peer->owner, peer); peer_set_condition(peer, "Beginning gossip"); @@ -166,11 +164,11 @@ static bool peer_got_handshake_hsmfd(struct subd *hsm, const u8 *msg, /* Give handshake daemon the hsm fd. */ /* FIXME! */ - peer->owner = (struct subdaemon *)new_subd(peer->ld, peer->ld, - "lightningd_handshake", peer, - handshake_wire_type_name, - NULL, NULL, - peer->hsmfd, peer->fd, -1); + peer->owner = new_subd(peer->ld, peer->ld, + "lightningd_handshake", peer, + handshake_wire_type_name, + NULL, NULL, + peer->hsmfd, peer->fd, -1); if (!peer->owner) { log_unusual(peer->ld->log, "Could not subdaemon handshake: %s", strerror(errno)); @@ -192,8 +190,7 @@ static bool peer_got_handshake_hsmfd(struct subd *hsm, const u8 *msg, /* Now hand peer request to the handshake daemon: hands it * back on success */ - /* FIXME! subdaemon */ - subd_req((struct subd *)peer->owner, take(req), -1, &peer->fd, + subd_req(peer->owner, take(req), -1, &peer->fd, handshake_succeeded, peer); return true; @@ -549,9 +546,7 @@ static enum watch_result funding_depth_cb(struct peer *peer, } peer_set_condition(peer, "Funding tx reached depth %u", depth); - /* FIXME: subdaemon */ - subd_send_msg((struct subd *)peer->owner, - take(towire_channel_funding_locked(peer))); + subd_send_msg(peer->owner, take(towire_channel_funding_locked(peer))); return DELETE_WATCH; } @@ -638,11 +633,11 @@ static void peer_start_channeld(struct peer *peer, bool am_funder, u8 *msg; /* Normal channel daemon. */ - peer->owner = (struct subdaemon *)new_subd(peer->ld, peer->ld, - "lightningd_channel", peer, - channel_wire_type_name, - update_channel_status, NULL, - peer->fd, -1); + peer->owner = new_subd(peer->ld, peer->ld, + "lightningd_channel", peer, + channel_wire_type_name, + update_channel_status, NULL, + peer->fd, -1); if (!peer->owner) { log_unusual(peer->log, "Could not subdaemon channel: %s", strerror(errno)); @@ -673,8 +668,7 @@ static void peer_start_channeld(struct peer *peer, bool am_funder, peer->seed); /* We don't expect a response: we are triggered by funding_depth_cb. */ - /* FIXME: subdaemon */ - subd_send_msg((struct subd *)peer->owner, take(msg)); + subd_send_msg(peer->owner, take(msg)); } static bool opening_release_tx(struct subd *opening, const u8 *resp, @@ -760,8 +754,7 @@ static bool opening_gen_funding(struct subd *opening, const u8 *reply, msg = towire_opening_open_funding(fc, fc->peer->funding_txid, fc->peer->funding_outnum); - /* FIXME: subdaemon */ - subd_req((struct subd *)fc->peer->owner, take(msg), -1, &fc->peer->fd, + subd_req(fc->peer->owner, take(msg), -1, &fc->peer->fd, opening_release_tx, fc); return true; } @@ -884,7 +877,6 @@ void peer_accept_open(struct peer *peer, u32 max_to_self_delay, max_minimum_depth; u64 min_effective_htlc_capacity_msat; u8 *msg; - struct subd *opening; /* Note: gossipd handles unknown packets, so we don't have to worry * about ignoring odd ones here. */ @@ -897,12 +889,10 @@ void peer_accept_open(struct peer *peer, } peer_set_condition(peer, "Starting opening daemon"); - opening = new_subd(ld, ld, "lightningd_opening", peer, - opening_wire_type_name, - NULL, NULL, - peer->fd, -1); - - peer->owner = (struct subdaemon *)opening; + peer->owner = new_subd(ld, ld, "lightningd_opening", peer, + opening_wire_type_name, + NULL, NULL, + peer->fd, -1); if (!peer->owner) { log_unusual(ld->log, "Could not subdaemon opening: %s", strerror(errno)); @@ -924,8 +914,7 @@ void peer_accept_open(struct peer *peer, min_effective_htlc_capacity_msat, cs, peer->seed); - subd_send_msg(opening, take(msg)); - /* FIXME: Real feerates! */ + subd_send_msg(peer->owner, take(msg)); msg = towire_opening_accept(peer, 7500, 150000, from_peer); /* Careful here! Their message could push us overlength! */ @@ -934,7 +923,7 @@ void peer_accept_open(struct peer *peer, tal_free(peer); return; } - subd_req(opening, take(msg), -1, NULL, opening_accept_reply, peer); + subd_req(peer->owner, take(msg), -1, NULL, opening_accept_reply, peer); } /* Peer has been released from gossip. Start opening. */ @@ -971,7 +960,7 @@ static bool gossip_peer_released(struct subd *gossip, tal_free(fc->peer); return true; } - fc->peer->owner = (struct subdaemon *)opening; + fc->peer->owner = opening; /* They took our fd. */ fc->peer->fd = -1; @@ -1022,8 +1011,7 @@ static void json_fund_channel(struct command *cmd, command_fail(cmd, "Could not find peer with that peerid"); return; } - /* FIXME! */ - if (fc->peer->owner != (struct subdaemon *)ld->gossip) { + if (fc->peer->owner != ld->gossip) { command_fail(cmd, "Peer not ready for connection"); return; } diff --git a/lightningd/peer_control.h b/lightningd/peer_control.h index bda39cf84..e8ccde0b7 100644 --- a/lightningd/peer_control.h +++ b/lightningd/peer_control.h @@ -18,7 +18,7 @@ struct peer { struct list_node list; /* What stage is this in? NULL during first creation. */ - struct subdaemon *owner; + struct subd *owner; /* What's happening (doubles as error return for connect_cmd) */ const char *condition; diff --git a/lightningd/subdaemon.c b/lightningd/subdaemon.c deleted file mode 100644 index b067d268b..000000000 --- a/lightningd/subdaemon.c +++ /dev/null @@ -1,415 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* A single request/response for subdaemon. */ -struct subdaemon_req { - struct subdaemon *sd; - - /* In sd->reqs */ - struct list_node list; - - /* Request message. */ - const u8 *msg_out; - int fd_out; - - /* Response */ - u8 *req_in; - int *fd_in; - - /* Callback when response comes in. */ - void (*req)(struct subdaemon *, const u8 *msg_in, void *req_data); - void *req_data; -}; - -static bool move_fd(int from, int to) -{ - if (dup2(from, to) == -1) - return false; - close(from); - return true; -} - -/* FIXME: Expose the ccan/io version? */ -static void set_blocking(int fd, bool block) -{ - int flags = fcntl(fd, F_GETFL); - - if (block) - flags &= ~O_NONBLOCK; - else - flags |= O_NONBLOCK; - - fcntl(fd, F_SETFL, flags); -} - -/* We use sockets, not pipes, because fds are bidir. */ -static int subdaemon(const char *dir, const char *name, bool debug, - int *statusfd, int *reqfd, va_list ap) -{ - int childreq[2], childstatus[2], execfail[2]; - pid_t childpid; - int err, fd; - - if (socketpair(AF_LOCAL, SOCK_STREAM, 0, childstatus) != 0) - goto fail; - - if (reqfd) { - if (socketpair(AF_LOCAL, SOCK_STREAM, 0, childreq) != 0) - goto close_childstatus_fail; - } else { - childreq[0] = open("/dev/null", O_RDONLY); - if (childreq[0] < 0) - goto close_childstatus_fail; - } - - if (pipe(execfail) != 0) - goto close_reqfd_fail; - - if (fcntl(execfail[1], F_SETFD, fcntl(execfail[1], F_GETFD) - | FD_CLOEXEC) < 0) - goto close_execfail_fail; - - childpid = fork(); - if (childpid < 0) - goto close_execfail_fail; - - if (childpid == 0) { - int fdnum = 3; - long max; - const char *debug_arg = NULL; - - if (reqfd) - close(childreq[0]); - close(childstatus[0]); - close(execfail[0]); - - // Status = STDOUT - if (childstatus[1] != STDOUT_FILENO) { - if (!move_fd(childstatus[1], STDOUT_FILENO)) - goto child_errno_fail; - } - // Req = STDIN. - if (childreq[1] != STDIN_FILENO) { - if (!move_fd(childreq[1], STDIN_FILENO)) - goto child_errno_fail; - } - /* Dup any extra fds up first. */ - while ((fd = va_arg(ap, int)) != -1) { - /* If these were stdin or stdout, dup2 closed! */ - assert(fd != STDIN_FILENO); - assert(fd != STDOUT_FILENO); - if (!move_fd(fd, fdnum)) - goto child_errno_fail; - fdnum++; - } - - /* Make (fairly!) sure all other fds are closed. */ - max = sysconf(_SC_OPEN_MAX); - for (fd = fdnum; fd < max; fd++) - close(fd); - - if (debug) - debug_arg = "--debugger"; - execl(path_join(NULL, dir, name), name, debug_arg, NULL); - - child_errno_fail: - err = errno; - /* Gcc's warn-unused-result fail. */ - if (write(execfail[1], &err, sizeof(err))) { - ; - } - exit(127); - } - - if (reqfd) - close(childreq[1]); - close(childstatus[1]); - close(execfail[1]); - - while ((fd = va_arg(ap, int)) != -1) - close(fd); - - /* Child will close this without writing on successful exec. */ - if (read(execfail[0], &err, sizeof(err)) == sizeof(err)) { - close(execfail[0]); - waitpid(childpid, NULL, 0); - errno = err; - return -1; - } - close(execfail[0]); - *statusfd = childstatus[0]; - if (reqfd) - *reqfd = childreq[0]; - return childpid; - -close_execfail_fail: - close_noerr(execfail[0]); - close_noerr(execfail[1]); -close_reqfd_fail: - if (reqfd) - close_noerr(childreq[1]); - close_noerr(childreq[0]); -close_childstatus_fail: - close_noerr(childstatus[0]); - close_noerr(childstatus[1]); -fail: - return -1; -} - -static struct io_plan *status_read(struct io_conn *conn, struct subdaemon *sd); - -static struct io_plan *status_process_fd(struct io_conn *conn, - struct subdaemon *sd) -{ - const tal_t *tmpctx = tal_tmpctx(sd); - - /* Don't trust subdaemon to set it blocking. */ - set_blocking(sd->status_fd_in, true); - - /* Ensure we free it iff callback doesn't tal_steal it. */ - tal_steal(tmpctx, sd->status_in); - sd->statuscb(sd, sd->status_in, sd->status_fd_in); - tal_free(tmpctx); - sd->status_in = NULL; - return status_read(conn, sd); -} - -static struct io_plan *status_process(struct io_conn *conn, struct subdaemon *sd) -{ - int type = fromwire_peektype(sd->status_in); - const char *str; - int str_len; - const tal_t *tmpctx = tal_tmpctx(sd); - - if (type == -1) { - log_unusual(sd->log, "ERROR: Invalid status output"); - return io_close(conn); - } - - /* If not stolen, we'll free this below. */ - tal_steal(tmpctx, sd->status_in); - - /* If it's a string. */ - str_len = tal_count(sd->status_in) - sizeof(be16); - str = (const char *)sd->status_in + sizeof(be16); - - if (type == STATUS_TRACE) - log_debug(sd->log, "TRACE: %.*s", str_len, str); - else if (type & STATUS_FAIL) - log_unusual(sd->log, "FAILURE %s: %.*s", - sd->statusname(type), str_len, str); - else { - log_info(sd->log, "UPDATE %s", sd->statusname(type)); - if (sd->statuscb) { - enum subdaemon_status s = sd->statuscb(sd, - sd->status_in, - -1); - switch (s) { - case STATUS_NEED_FD: - tal_steal(sd, sd->status_in); - tal_free(tmpctx); - return io_recv_fd(conn, &sd->status_fd_in, - status_process_fd, sd); - case STATUS_COMPLETE: - break; - default: - fatal("Unknown statuscb return for %s:%s: %u", - sd->name, sd->statusname(type), s); - } - } - } - sd->status_in = NULL; - tal_free(tmpctx); - return status_read(conn, sd); -} - -static struct io_plan *status_read(struct io_conn *conn, struct subdaemon *sd) -{ - return io_read_wire(conn, sd, &sd->status_in, status_process, sd); -} - -static struct io_plan *req_next(struct io_conn *conn, struct subdaemon *sd); - -static void destroy_subdaemon(struct subdaemon *sd) -{ - int status; - - switch (waitpid(sd->pid, &status, WNOHANG)) { - case 0: - log_debug(sd->log, "Status closed, but not exited. Killing"); - kill(sd->pid, SIGKILL); - waitpid(sd->pid, &status, 0); - break; - case -1: - log_unusual(sd->log, "Status closed, but waitpid %i says %s", - sd->pid, strerror(errno)); - status = -1; - break; - } - if (sd->finished) - sd->finished(sd, status); -} - -struct subdaemon *new_subdaemon(const tal_t *ctx, - struct lightningd *ld, - const char *name, - struct peer *peer, - const char *(*statusname)(int status), - const char *(*reqname)(int req), - enum subdaemon_status (*statuscb) - (struct subdaemon *, const u8 *, int fd), - void (*finished)(struct subdaemon *, int), - ...) -{ - va_list ap; - struct subdaemon *sd = tal(ctx, struct subdaemon); - int req_fd, status_fd; - bool debug; - - debug = ld->dev_debug_subdaemon && strends(name,ld->dev_debug_subdaemon); - va_start(ap, finished); - sd->pid = subdaemon(ld->daemon_dir, name, debug, &status_fd, - reqname ? &req_fd : NULL, ap); - va_end(ap); - if (sd->pid == (pid_t)-1) { - log_unusual(ld->log, "subdaemon %s failed: %s", - name, strerror(errno)); - return tal_free(sd); - } - sd->ld = ld; - sd->log = new_log(sd, ld->dstate.log_book, "%s(%u):", name, sd->pid); - sd->name = name; - sd->finished = finished; - sd->statusname = statusname; - sd->statuscb = statuscb; - list_head_init(&sd->reqs); - tal_add_destructor(sd, destroy_subdaemon); - - /* Status conn actually owns daemon: we die when it does. */ - sd->status_conn = io_new_conn(ctx, status_fd, status_read, sd); - tal_steal(sd->status_conn, sd); - - sd->reqname = reqname; - if (reqname) - sd->req_conn = io_new_conn(sd, req_fd, req_next, sd); - else - sd->req_conn = NULL; - log_info(sd->log, "pid %u, statusfd %i, reqfd %i", - sd->pid, status_fd, req_fd); - - sd->peer = tal_steal(sd, peer); - return sd; -} - -static struct io_plan *req_finished_reply(struct io_conn *conn, - struct subdaemon_req *sr) -{ - struct subdaemon *sd = sr->sd; - - /* Don't trust subdaemon to set it blocking. */ - if (sr->fd_in) - set_blocking(*sr->fd_in, true); - - sr->req(sd, sr->req_in, sr->req_data); - tal_free(sr); - return req_next(conn, sd); -} - -static struct io_plan *req_process_replymsg(struct io_conn *conn, - struct subdaemon_req *sr) -{ - int type = fromwire_peektype(sr->req_in); - - if (type == -1) { - log_unusual(sr->sd->log, "ERROR: Invalid request output"); - return io_close(conn); - } - log_debug(sr->sd->log, "Received req response %s len %zu%s", - sr->sd->reqname(type), tal_count(sr->req_in), - sr->fd_in ? " (now getting fd)" : ""); - - /* If we're supposed to recv an fd, do it now. */ - if (sr->fd_in) - return io_recv_fd(conn, sr->fd_in, req_finished_reply, sr); - return req_finished_reply(conn, sr); -} - -static struct io_plan *req_read_reply(struct io_conn *conn, - struct subdaemon_req *sr) -{ - /* No callback? Don't expect reply. */ - if (!sr->req) { - struct subdaemon *sd = sr->sd; - tal_free(sr); - return req_next(conn, sd); - } - return io_read_wire(conn, sr, &sr->req_in, req_process_replymsg, sr); -} - -static struct io_plan *req_close_fd_out(struct io_conn *conn, - struct subdaemon_req *sr) -{ - close(sr->fd_out); - return req_read_reply(conn, sr); -} - -static struct io_plan *req_sent_msg(struct io_conn *conn, - struct subdaemon_req *sr) -{ - /* If we're supposed to pass an fd, do it now. */ - if (sr->fd_out >= 0) - return io_send_fd(conn, sr->fd_out, req_close_fd_out, sr); - return req_read_reply(conn, sr); -} - -static struct io_plan *req_next(struct io_conn *conn, struct subdaemon *sd) -{ - struct subdaemon_req *sr; - - sr = list_pop(&sd->reqs, struct subdaemon_req, list); - if (!sr) - return io_wait(conn, sd, req_next, sd); - log_debug(sd->log, "Sending req %s len %zu", - sd->reqname(fromwire_peektype(sr->msg_out)), - tal_count(sr->msg_out)); - - return io_write_wire(conn, sr->msg_out, req_sent_msg, sr); -} - -void subdaemon_req_(struct subdaemon *sd, - const u8 *msg_out, int fd_out, int *fd_in, - void (*reqcb)(struct subdaemon *, const u8 *, void *), - void *reqcb_data) -{ - struct subdaemon_req *sr = tal(sd, struct subdaemon_req); - - assert(sd->req_conn); - - sr->sd = sd; - if (msg_out) - sr->msg_out = tal_dup_arr(sr, u8, msg_out, tal_count(msg_out), 0); - else - sr->msg_out = NULL; - sr->fd_out = fd_out; - sr->fd_in = fd_in; - sr->req = reqcb; - sr->req_data = reqcb_data; - list_add_tail(&sd->reqs, &sr->list); - io_wake(sd); -} diff --git a/lightningd/subdaemon.h b/lightningd/subdaemon.h deleted file mode 100644 index 073bf74e4..000000000 --- a/lightningd/subdaemon.h +++ /dev/null @@ -1,101 +0,0 @@ -#ifndef LIGHTNING_LIGHTNINGD_SUBDAEMON_H -#define LIGHTNING_LIGHTNINGD_SUBDAEMON_H -#include "config.h" -#include -#include -#include -#include - -struct io_conn; - -enum subdaemon_status { - STATUS_NEED_FD, - STATUS_COMPLETE -}; - -/* One of our subdaemons. */ -struct subdaemon { - /* Name, like John, or "lightningd_hsm" */ - const char *name; - /* The Big Cheese. */ - struct lightningd *ld; - /* pid, for waiting for status when it dies. */ - int pid; - /* Connection for status (read, then write) */ - struct io_conn *status_conn; - /* Connection for requests if any (write, then read) */ - struct io_conn *req_conn; - - /* If we are associated with a single peer, this points to it. */ - struct peer *peer; - - /* For logging */ - struct log *log; - - /* Callback when status comes in. */ - enum subdaemon_status (*statuscb)(struct subdaemon *, const u8 *, int); - const char *(*statusname)(int status); - const char *(*reqname)(int req); - void (*finished)(struct subdaemon *sd, int status); - - /* Buffer for input. */ - u8 *status_in; - int status_fd_in; - - /* Requests queue up here. */ - struct list_head reqs; -}; - -/** - * new_subdaemon - create a new subdaemon. - * @ctx: context to allocate from - * @ld: global state - * @name: basename of daemon - * @peer: peer to take ownership of if non-NULL; - * @statusname: function to get name from status messages - * @reqname: function to get name from request messages, or NULL if no requests. - * @statuscb: function to call when status message received (or NULL) - * @finished: function to call when it's finished (with exit status). - * @...: the fds to hand as fd 3, 4... terminated with -1. - * - * @statuscb is called with fd == -1 when a status message is - * received; if it returns STATUS_NEED_FD, we read an fd from the - * daemon and call it again with that as the third arg. - * - * If this succeeds subdaemon owns @peer. - */ -struct subdaemon *new_subdaemon(const tal_t *ctx, - struct lightningd *ld, - const char *name, - struct peer *peer, - const char *(*statusname)(int status), - const char *(*reqname)(int req), - enum subdaemon_status (*statuscb) - (struct subdaemon *, const u8 *, int fd), - void (*finished)(struct subdaemon *, int), ...); - -/** - * subdaemon_req - add a request to the subdaemon. - * @sd: subdaemon to request - * @msg_out: request message (can be take, can be NULL for fd passing only) - * @fd_out: if >=0 fd to pass at the end of the message (closed after) - * @fd_in: if not NULL, where to put fd read in at end of reply. - * @reqcb: callback when reply comes in - * @reqcb_data: final arg to hand to @reqcb - * - * The subdaemon must take requests. - */ -#define subdaemon_req(sd, msg_out, fd_out, fd_in, reqcb, reqcb_data) \ - subdaemon_req_((sd), (msg_out), (fd_out), (fd_in), \ - typesafe_cb_preargs(void, void *, \ - (reqcb), (reqcb_data), \ - struct subdaemon *, \ - const u8 *), \ - (reqcb_data)) -void subdaemon_req_(struct subdaemon *sd, - const u8 *msg_out, - int fd_out, int *fd_in, - void (*reqcb)(struct subdaemon *, const u8 *, void *), - void *reqcb_data); - -#endif /* LIGHTNING_LIGHTNINGD_SUBDAEMON_H */