|
|
@ -16,11 +16,13 @@ |
|
|
|
#include <sys/wait.h> |
|
|
|
|
|
|
|
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); |
|
|
|