Browse Source

dns: add failure callback.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
ppa-0.6.1
Rusty Russell 9 years ago
parent
commit
366f8a5f3f
  1. 44
      daemon/dns.c
  2. 18
      daemon/dns.h
  3. 25
      daemon/peer.c
  4. 5
      daemon/peer.h

44
daemon/dns.c

@ -16,11 +16,13 @@
#include <sys/wait.h> #include <sys/wait.h>
struct dns_async { struct dns_async {
size_t use;
struct lightningd_state *state; struct lightningd_state *state;
struct io_plan *(*init)(struct io_conn *, struct io_plan *(*init)(struct io_conn *, struct lightningd_state *,
struct lightningd_state *, void *);
const char *name, const char *port); void (*fail)(struct lightningd_state *, void *arg);
const char *name, *port; const char *name;
void *arg;
int pid; int pid;
size_t num_addresses; size_t num_addresses;
struct netaddr *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. */ /* No longer need to try more connections. */
io_set_finish(conn, NULL, NULL); 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); 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 */ /* Now we can warn if it's overlength */
if (a->addrlen > sizeof(a->saddr)) { if (a->addrlen > sizeof(a->saddr)) {
log_broken(d->state->base_log, 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", " for family %u, len=%u",
d->name, d->port, d->name, a->saddr.s.sa_family, a->addrlen);
a->saddr.s.sa_family, a->addrlen);
} else { } else {
/* Might not even be able to create eg. IPv6 sockets */ /* Might not even be able to create eg. IPv6 sockets */
fd = socket(a->saddr.s.sa_family, a->type, a->protocol); fd = socket(a->saddr.s.sa_family, a->type, a->protocol);
if (fd >= 0) { if (fd >= 0) {
io_new_conn(d->state, fd, init_conn, d); 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, static struct io_plan *start_connecting(struct io_conn *conn,
struct dns_async *d) struct dns_async *d)
{ {
assert(d->num_addresses); assert(d->num_addresses);
/* reap_child and our connections can race: only last one should call
* fail. */
d->use++;
try_connect_one(d); try_connect_one(d);
return io_close(conn); 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) static void reap_child(struct io_conn *conn, struct dns_async *d)
{ {
waitpid(d->pid, NULL, 0); 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, const char *name, const char *port,
struct io_plan *(*init)(struct io_conn *, struct io_plan *(*init)(struct io_conn *,
struct lightningd_state *, struct lightningd_state *,
const char *name, const char *port)) void *arg),
void (*fail)(struct lightningd_state *, void *arg),
void *arg)
{ {
int pfds[2]; int pfds[2];
struct dns_async *d = tal(NULL, struct dns_async); 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->state = state;
d->init = init; d->init = init;
d->name = tal_strdup(d, name); d->fail = fail;
d->port = tal_strdup(d, port); d->arg = arg;
d->name = tal_fmt(d, "%s:%s", name, port);
/* First fork child to get addresses. */ /* First fork child to get addresses. */
if (pipe(pfds) != 0) { if (pipe(pfds) != 0) {
@ -184,6 +201,7 @@ struct dns_async *dns_resolve_and_connect(struct lightningd_state *state,
} }
close(pfds[1]); close(pfds[1]);
d->use = 1;
conn = io_new_conn(state, pfds[0], init_dns_conn, d); conn = io_new_conn(state, pfds[0], init_dns_conn, d);
io_set_finish(conn, reap_child, d); io_set_finish(conn, reap_child, d);
tal_steal(conn, d); tal_steal(conn, d);

18
daemon/dns.h

@ -3,14 +3,28 @@
#include "config.h" #include "config.h"
#include <ccan/io/io.h> #include <ccan/io/io.h>
#include <ccan/tal/tal.h> #include <ccan/tal/tal.h>
#include <ccan/typesafe_cb/typesafe_cb.h>
#include <stdbool.h> #include <stdbool.h>
struct lightningd_state; struct lightningd_state;
struct netaddr; 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, const char *name, const char *port,
struct io_plan *(*init)(struct io_conn *, struct io_plan *(*init)(struct io_conn *,
struct lightningd_state *, struct lightningd_state *,
const char *name, const char *port)); void *arg),
void (*fail)(struct lightningd_state *, void *arg),
void *arg);
#endif /* PETTYCOIN_DNS_H */ #endif /* PETTYCOIN_DNS_H */

25
daemon/peer.c

@ -80,18 +80,17 @@ static struct peer *new_peer(struct lightningd_state *state,
return peer; return peer;
} }
struct io_plan *peer_connected_out(struct io_conn *conn, static struct io_plan *peer_connected_out(struct io_conn *conn,
struct lightningd_state *state, struct lightningd_state *state,
const char *name, const char *port) char *dest)
{ {
struct peer *peer = new_peer(state, conn, SOCK_STREAM, IPPROTO_TCP, struct peer *peer = new_peer(state, conn, SOCK_STREAM, IPPROTO_TCP,
"out"); "out");
if (!peer) { if (!peer) {
log_unusual(peer->log, "Failed to make peer for %s:%s", log_unusual(peer->log, "Failed to make peer for %s", dest);
name, port);
return io_close(conn); 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); 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"); 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, static void json_connect(struct command *cmd,
const char *buffer, const jsmntok_t *params) const char *buffer, const jsmntok_t *params)
{ {
struct json_result *response; struct json_result *response;
jsmntok_t *host, *port; jsmntok_t *host, *port;
const char *hoststr, *portstr; const char *hoststr, *portstr;
char *dest;
json_get_params(buffer, params, "host", &host, "port", &port, NULL); json_get_params(buffer, params, "host", &host, "port", &port, NULL);
@ -205,12 +211,13 @@ static void json_connect(struct command *cmd,
return; return;
} }
hoststr = tal_strndup(cmd, buffer + host->start, hoststr = tal_strndup(cmd->state, buffer + host->start,
host->end - 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); port->end - port->start);
dest = tal_fmt(cmd->state, "%s:%s", hoststr, portstr);
if (!dns_resolve_and_connect(cmd->state, 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"); command_fail(cmd, "DNS failed");
return; return;
} }

5
daemon/peer.h

@ -25,11 +25,6 @@ struct peer {
struct log *log; 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); void setup_listeners(struct lightningd_state *state, unsigned int portnum);
#endif /* LIGHTNING_DAEMON_PEER_H */ #endif /* LIGHTNING_DAEMON_PEER_H */

Loading…
Cancel
Save