diff --git a/daemon/dns.c b/daemon/dns.c index b1d2091b5..501ef87c3 100644 --- a/daemon/dns.c +++ b/daemon/dns.c @@ -16,11 +16,13 @@ #include struct dns_async { + size_t use; struct lightningd_state *state; - struct io_plan *(*init)(struct io_conn *, - struct lightningd_state *, - const char *name, const char *port); - const char *name, *port; + struct io_plan *(*init)(struct io_conn *, struct lightningd_state *, + void *); + void (*fail)(struct lightningd_state *, void *arg); + const char *name; + void *arg; int pid; size_t num_addresses; struct netaddr *addresses; @@ -67,7 +69,9 @@ static struct io_plan *connected(struct io_conn *conn, struct dns_async *d) { /* No longer need to try more connections. */ io_set_finish(conn, NULL, NULL); - return d->init(conn, d->state, d->name, d->port); + + /* Keep use count, so reap_child won't fail. */ + return d->init(conn, d->state, d->arg); } static void try_connect_one(struct dns_async *d); @@ -104,25 +108,32 @@ static void try_connect_one(struct dns_async *d) /* Now we can warn if it's overlength */ if (a->addrlen > sizeof(a->saddr)) { log_broken(d->state->base_log, - "DNS lookup gave overlength address for %s:%s" + "DNS lookup gave overlength address for %s" " for family %u, len=%u", - d->name, d->port, - a->saddr.s.sa_family, a->addrlen); + d->name, a->saddr.s.sa_family, a->addrlen); } else { /* Might not even be able to create eg. IPv6 sockets */ fd = socket(a->saddr.s.sa_family, a->type, a->protocol); if (fd >= 0) { io_new_conn(d->state, fd, init_conn, d); - break; + return; } } } + + /* We're out of things to try. Fail. */ + if (--d->use == 0) + d->fail(d->state, d->arg); } static struct io_plan *start_connecting(struct io_conn *conn, struct dns_async *d) { assert(d->num_addresses); + + /* reap_child and our connections can race: only last one should call + * fail. */ + d->use++; try_connect_one(d); return io_close(conn); } @@ -144,13 +155,18 @@ static struct io_plan *init_dns_conn(struct io_conn *conn, struct dns_async *d) static void reap_child(struct io_conn *conn, struct dns_async *d) { waitpid(d->pid, NULL, 0); + /* Last user calls fail. */ + if (--d->use == 0) + d->fail(d->state, d->arg); } -struct dns_async *dns_resolve_and_connect(struct lightningd_state *state, +struct dns_async *dns_resolve_and_connect_(struct lightningd_state *state, const char *name, const char *port, struct io_plan *(*init)(struct io_conn *, struct lightningd_state *, - const char *name, const char *port)) + void *arg), + void (*fail)(struct lightningd_state *, void *arg), + void *arg) { int pfds[2]; struct dns_async *d = tal(NULL, struct dns_async); @@ -158,8 +174,9 @@ struct dns_async *dns_resolve_and_connect(struct lightningd_state *state, d->state = state; d->init = init; - d->name = tal_strdup(d, name); - d->port = tal_strdup(d, port); + d->fail = fail; + d->arg = arg; + d->name = tal_fmt(d, "%s:%s", name, port); /* First fork child to get addresses. */ if (pipe(pfds) != 0) { @@ -184,6 +201,7 @@ struct dns_async *dns_resolve_and_connect(struct lightningd_state *state, } close(pfds[1]); + d->use = 1; conn = io_new_conn(state, pfds[0], init_dns_conn, d); io_set_finish(conn, reap_child, d); tal_steal(conn, d); diff --git a/daemon/dns.h b/daemon/dns.h index 66d154b52..875d9c1b5 100644 --- a/daemon/dns.h +++ b/daemon/dns.h @@ -3,14 +3,28 @@ #include "config.h" #include #include +#include #include struct lightningd_state; struct netaddr; -struct dns_async *dns_resolve_and_connect(struct lightningd_state *state, + +#define dns_resolve_and_connect(state, name, port, initfn, failfn, arg) \ + dns_resolve_and_connect_((state), (name), (port), \ + typesafe_cb_preargs(struct io_plan *, void *, \ + (initfn), (arg), \ + struct io_conn *, \ + struct lightningd_state *), \ + typesafe_cb_preargs(void, void *, (failfn), (arg), \ + struct lightningd_state *), \ + (arg)) + +struct dns_async *dns_resolve_and_connect_(struct lightningd_state *state, const char *name, const char *port, struct io_plan *(*init)(struct io_conn *, struct lightningd_state *, - const char *name, const char *port)); + void *arg), + void (*fail)(struct lightningd_state *, void *arg), + void *arg); #endif /* PETTYCOIN_DNS_H */ diff --git a/daemon/peer.c b/daemon/peer.c index 80d27221c..14fa342cd 100644 --- a/daemon/peer.c +++ b/daemon/peer.c @@ -80,18 +80,17 @@ static struct peer *new_peer(struct lightningd_state *state, return peer; } -struct io_plan *peer_connected_out(struct io_conn *conn, - struct lightningd_state *state, - const char *name, const char *port) +static struct io_plan *peer_connected_out(struct io_conn *conn, + struct lightningd_state *state, + char *dest) { struct peer *peer = new_peer(state, conn, SOCK_STREAM, IPPROTO_TCP, "out"); if (!peer) { - log_unusual(peer->log, "Failed to make peer for %s:%s", - name, port); + log_unusual(peer->log, "Failed to make peer for %s", dest); return io_close(conn); } - log_info(peer->log, "Connected out to %s:%s", name, port); + log_info(peer->log, "Connected out to %s", dest); return peer_crypto_setup(conn, peer, peer_test); } @@ -191,12 +190,19 @@ void setup_listeners(struct lightningd_state *state, unsigned int portnum) fatal("Could not bind to a network address"); } +static void peer_failed(struct lightningd_state *state, char *dest) +{ + /* FIXME: Better diagnostics! */ + log_unusual(state->base_log, "Connect to %s failed", dest); +} + static void json_connect(struct command *cmd, const char *buffer, const jsmntok_t *params) { struct json_result *response; jsmntok_t *host, *port; const char *hoststr, *portstr; + char *dest; json_get_params(buffer, params, "host", &host, "port", &port, NULL); @@ -205,12 +211,13 @@ static void json_connect(struct command *cmd, return; } - hoststr = tal_strndup(cmd, buffer + host->start, + hoststr = tal_strndup(cmd->state, buffer + host->start, host->end - host->start); - portstr = tal_strndup(cmd, buffer + port->start, + portstr = tal_strndup(cmd->state, buffer + port->start, port->end - port->start); + dest = tal_fmt(cmd->state, "%s:%s", hoststr, portstr); if (!dns_resolve_and_connect(cmd->state, hoststr, portstr, - peer_connected_out)) { + peer_connected_out, peer_failed, dest)) { command_fail(cmd, "DNS failed"); return; } diff --git a/daemon/peer.h b/daemon/peer.h index c39f943af..705b7ba0e 100644 --- a/daemon/peer.h +++ b/daemon/peer.h @@ -25,11 +25,6 @@ struct peer { struct log *log; }; -struct io_conn; -struct io_plan *peer_connected_out(struct io_conn *conn, - struct lightningd_state *state, - const char *name, const char *port); - void setup_listeners(struct lightningd_state *state, unsigned int portnum); #endif /* LIGHTNING_DAEMON_PEER_H */