Browse Source

daemon/subdaemon: remove in favor of daemon/subd.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
ppa-0.6.1
Rusty Russell 8 years ago
parent
commit
da5c7e0a08
  1. 4
      lightningd/Makefile
  2. 4
      lightningd/gossip_control.c
  3. 1
      lightningd/lightningd.c
  4. 58
      lightningd/peer_control.c
  5. 2
      lightningd/peer_control.h
  6. 415
      lightningd/subdaemon.c
  7. 101
      lightningd/subdaemon.h

4
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) \

4
lightningd/gossip_control.c

@ -2,7 +2,6 @@
#include "lightningd.h"
#include "peer_control.h"
#include "subd.h"
#include "subdaemon.h"
#include <ccan/err/err.h>
#include <ccan/take/take.h>
#include <daemon/jsonrpc.h>
@ -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)");

1
lightningd/lightningd.c

@ -3,7 +3,6 @@
#include "lightningd.h"
#include "peer_control.h"
#include "subd.h"
#include "subdaemon.h"
#include <ccan/array_size/array_size.h>
#include <ccan/crypto/hkdf_sha256/hkdf_sha256.h>
#include <ccan/err/err.h>

58
lightningd/peer_control.c

@ -1,7 +1,6 @@
#include "lightningd.h"
#include "peer_control.h"
#include "subd.h"
#include "subdaemon.h"
#include <bitcoin/script.h>
#include <bitcoin/tx.h>
#include <ccan/io/io.h>
@ -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;
}

2
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;

415
lightningd/subdaemon.c

@ -1,415 +0,0 @@
#include <ccan/io/fdpass/fdpass.h>
#include <ccan/io/io.h>
#include <ccan/noerr/noerr.h>
#include <ccan/tal/path/path.h>
#include <daemon/log.h>
#include <errno.h>
#include <fcntl.h>
#include <lightningd/lightningd.h>
#include <lightningd/subdaemon.h>
#include <status.h>
#include <stdarg.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <wire/wire.h>
#include <wire/wire_io.h>
/* 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);
}

101
lightningd/subdaemon.h

@ -1,101 +0,0 @@
#ifndef LIGHTNING_LIGHTNINGD_SUBDAEMON_H
#define LIGHTNING_LIGHTNINGD_SUBDAEMON_H
#include "config.h"
#include <ccan/endian/endian.h>
#include <ccan/list/list.h>
#include <ccan/short_types/short_types.h>
#include <ccan/tal/tal.h>
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 */
Loading…
Cancel
Save