From 2bdedf55828fdf54aa1f6dbe1355497207b30a94 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 28 Sep 2018 12:53:36 +0930 Subject: [PATCH] connectd: reorder functions again for better grouping (MOVEONLY) Signed-off-by: Rusty Russell --- connectd/connectd.c | 522 ++++++++++++++++++++++---------------------- 1 file changed, 261 insertions(+), 261 deletions(-) diff --git a/connectd/connectd.c b/connectd/connectd.c index 4ee11bc13..adf6b7d73 100644 --- a/connectd/connectd.c +++ b/connectd/connectd.c @@ -315,54 +315,6 @@ struct io_plan *peer_connected(struct io_conn *conn, return io_close_taken_fd(conn); } -struct listen_fd { - int fd; - /* If we bind() IPv6 then IPv4 to same port, we *may* fail to listen() - * on the IPv4 socket: under Linux, by default, the IPv6 listen() - * covers IPv4 too. Normally we'd consider failing to listen on a - * port to be fatal, so we note this when setting up addresses. */ - bool mayfail; -}; - -static int make_listen_fd(int domain, void *addr, socklen_t len, bool mayfail) -{ - int fd = socket(domain, SOCK_STREAM, 0); - if (fd < 0) { - if (!mayfail) - status_failed(STATUS_FAIL_INTERNAL_ERROR, - "Failed to create %u socket: %s", - domain, strerror(errno)); - status_trace("Failed to create %u socket: %s", - domain, strerror(errno)); - return -1; - } - - if (addr) { - int on = 1; - - /* Re-use, please.. */ - if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on))) - status_unusual("Failed setting socket reuse: %s", - strerror(errno)); - - if (bind(fd, addr, len) != 0) { - if (!mayfail) - status_failed(STATUS_FAIL_INTERNAL_ERROR, - "Failed to bind on %u socket: %s", - domain, strerror(errno)); - status_trace("Failed to create %u socket: %s", - domain, strerror(errno)); - goto fail; - } - } - - return fd; - -fail: - close_noerr(fd); - return -1; -} - static struct io_plan *handshake_in_success(struct io_conn *conn, const struct pubkey *id, const struct wireaddr_internal *addr, @@ -411,6 +363,228 @@ static struct io_plan *connection_in(struct io_conn *conn, struct daemon *daemon handshake_in_success, daemon); } +static struct io_plan *handshake_out_success(struct io_conn *conn, + const struct pubkey *id, + const struct wireaddr_internal *addr, + const struct crypto_state *cs, + struct connecting *connect) +{ + connect->connstate = "Exchanging init messages"; + status_trace("Connect OUT to %s", + type_to_string(tmpctx, struct pubkey, id)); + return peer_exchange_initmsg(conn, connect->daemon, cs, id, addr); +} + +struct io_plan *connection_out(struct io_conn *conn, struct connecting *connect) +{ + /* FIXME: Timeout */ + status_trace("Connected out for %s", + type_to_string(tmpctx, struct pubkey, &connect->id)); + + connect->connstate = "Cryptographic handshake"; + return initiator_handshake(conn, &connect->daemon->id, &connect->id, + &connect->addrs[connect->addrnum], + handshake_out_success, connect); +} + +static void PRINTF_FMT(5,6) + connect_failed(struct daemon *daemon, + const struct pubkey *id, + u32 seconds_waited, + const struct wireaddr_internal *addrhint, + const char *errfmt, ...) +{ + u8 *msg; + va_list ap; + char *err; + u32 wait_seconds; + + va_start(ap, errfmt); + err = tal_vfmt(tmpctx, errfmt, ap); + va_end(ap); + + /* Wait twice as long to reconnect, between min and max. */ + wait_seconds = seconds_waited * 2; + if (wait_seconds > MAX_WAIT_SECONDS) + wait_seconds = MAX_WAIT_SECONDS; + if (wait_seconds < INITIAL_WAIT_SECONDS) + wait_seconds = INITIAL_WAIT_SECONDS; + + /* Tell any connect command what happened. */ + msg = towire_connectctl_connect_failed(NULL, id, err, wait_seconds, + addrhint); + daemon_conn_send(&daemon->master, take(msg)); + + status_trace("Failed connected out for %s: %s", + type_to_string(tmpctx, struct pubkey, id), + err); +} + +static void destroy_io_conn(struct io_conn *conn, struct connecting *connect) +{ + tal_append_fmt(&connect->errors, + "%s: %s: %s. ", + type_to_string(tmpctx, struct wireaddr_internal, + &connect->addrs[connect->addrnum]), + connect->connstate, strerror(errno)); + connect->addrnum++; + try_connect_one_addr(connect); +} + +static struct io_plan *conn_init(struct io_conn *conn, + struct connecting *connect) +{ + struct addrinfo *ai = NULL; + const struct wireaddr_internal *addr = &connect->addrs[connect->addrnum]; + + switch (addr->itype) { + case ADDR_INTERNAL_SOCKNAME: + ai = wireaddr_internal_to_addrinfo(tmpctx, addr); + break; + case ADDR_INTERNAL_ALLPROTO: + status_failed(STATUS_FAIL_INTERNAL_ERROR, + "Can't connect to all protocols"); + break; + case ADDR_INTERNAL_AUTOTOR: + status_failed(STATUS_FAIL_INTERNAL_ERROR, + "Can't connect to autotor address"); + break; + case ADDR_INTERNAL_FORPROXY: + status_failed(STATUS_FAIL_INTERNAL_ERROR, + "Can't connect to forproxy address"); + break; + case ADDR_INTERNAL_WIREADDR: + /* If it was a Tor address, we wouldn't be here. */ + ai = wireaddr_to_addrinfo(tmpctx, &addr->u.wireaddr); + break; + } + assert(ai); + + io_set_finish(conn, destroy_io_conn, connect); + return io_connect(conn, ai, connection_out, connect); +} + +static struct io_plan *conn_proxy_init(struct io_conn *conn, + struct connecting *connect) +{ + const char *host = NULL; + u16 port; + const struct wireaddr_internal *addr = &connect->addrs[connect->addrnum]; + + switch (addr->itype) { + case ADDR_INTERNAL_FORPROXY: + host = addr->u.unresolved.name; + port = addr->u.unresolved.port; + break; + case ADDR_INTERNAL_WIREADDR: + host = fmt_wireaddr_without_port(tmpctx, &addr->u.wireaddr); + port = addr->u.wireaddr.port; + break; + case ADDR_INTERNAL_SOCKNAME: + case ADDR_INTERNAL_ALLPROTO: + case ADDR_INTERNAL_AUTOTOR: + break; + } + + if (!host) + status_failed(STATUS_FAIL_INTERNAL_ERROR, + "Can't connect to %u address", addr->itype); + + io_set_finish(conn, destroy_io_conn, connect); + return io_tor_connect(conn, connect->daemon->proxyaddr, host, port, + connect); +} + +static void try_connect_one_addr(struct connecting *connect) +{ + int fd, af; + bool use_proxy = connect->daemon->use_proxy_always; + const struct wireaddr_internal *addr = &connect->addrs[connect->addrnum]; + + if (connect->addrnum == tal_count(connect->addrs)) { + connect_failed(connect->daemon, &connect->id, + connect->seconds_waited, + connect->addrhint, "%s", connect->errors); + tal_free(connect); + return; + } + + /* Might not even be able to create eg. IPv6 sockets */ + af = -1; + + switch (addr->itype) { + case ADDR_INTERNAL_SOCKNAME: + af = AF_LOCAL; + /* Local sockets don't use tor proxy */ + use_proxy = false; + break; + case ADDR_INTERNAL_ALLPROTO: + status_failed(STATUS_FAIL_INTERNAL_ERROR, + "Can't connect ALLPROTO"); + case ADDR_INTERNAL_AUTOTOR: + status_failed(STATUS_FAIL_INTERNAL_ERROR, + "Can't connect AUTOTOR"); + case ADDR_INTERNAL_FORPROXY: + use_proxy = true; + break; + case ADDR_INTERNAL_WIREADDR: + switch (addr->u.wireaddr.type) { + case ADDR_TYPE_TOR_V2: + case ADDR_TYPE_TOR_V3: + use_proxy = true; + break; + case ADDR_TYPE_IPV4: + af = AF_INET; + break; + case ADDR_TYPE_IPV6: + af = AF_INET6; + break; + case ADDR_TYPE_PADDING: + break; + } + } + + /* If we have to use proxy but we don't have one, we fail. */ + if (use_proxy) { + if (!connect->daemon->proxyaddr) { + status_debug("Need proxy"); + af = -1; + } else + af = connect->daemon->proxyaddr->ai_family; + } + + if (af == -1) { + fd = -1; + errno = EPROTONOSUPPORT; + } else + fd = socket(af, SOCK_STREAM, 0); + + if (fd < 0) { + tal_append_fmt(&connect->errors, + "%s: opening %i socket gave %s. ", + type_to_string(tmpctx, struct wireaddr_internal, + addr), + af, strerror(errno)); + connect->addrnum++; + try_connect_one_addr(connect); + return; + } + + if (use_proxy) + io_new_conn(connect, fd, conn_proxy_init, connect); + else + io_new_conn(connect, fd, conn_init, connect); +} + +struct listen_fd { + int fd; + /* If we bind() IPv6 then IPv4 to same port, we *may* fail to listen() + * on the IPv4 socket: under Linux, by default, the IPv6 listen() + * covers IPv4 too. Normally we'd consider failing to listen on a + * port to be fatal, so we note this when setting up addresses. */ + bool mayfail; +}; + static void add_listen_fd(struct daemon *daemon, int fd, bool mayfail) { struct listen_fd *l = tal_arr_expand(&daemon->listen_fds); @@ -418,6 +592,45 @@ static void add_listen_fd(struct daemon *daemon, int fd, bool mayfail) l->mayfail = mayfail; } +static int make_listen_fd(int domain, void *addr, socklen_t len, bool mayfail) +{ + int fd = socket(domain, SOCK_STREAM, 0); + if (fd < 0) { + if (!mayfail) + status_failed(STATUS_FAIL_INTERNAL_ERROR, + "Failed to create %u socket: %s", + domain, strerror(errno)); + status_trace("Failed to create %u socket: %s", + domain, strerror(errno)); + return -1; + } + + if (addr) { + int on = 1; + + /* Re-use, please.. */ + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on))) + status_unusual("Failed setting socket reuse: %s", + strerror(errno)); + + if (bind(fd, addr, len) != 0) { + if (!mayfail) + status_failed(STATUS_FAIL_INTERNAL_ERROR, + "Failed to bind on %u socket: %s", + domain, strerror(errno)); + status_trace("Failed to create %u socket: %s", + domain, strerror(errno)); + goto fail; + } + } + + return fd; + +fail: + close_noerr(fd); + return -1; +} + /* Return true if it created socket successfully. */ static bool handle_wireaddr_listen(struct daemon *daemon, const struct wireaddr *wireaddr, @@ -736,138 +949,6 @@ static struct io_plan *connect_activate(struct daemon_conn *master, return daemon_conn_read_next(master->conn, master); } -static struct io_plan *handshake_out_success(struct io_conn *conn, - const struct pubkey *id, - const struct wireaddr_internal *addr, - const struct crypto_state *cs, - struct connecting *connect) -{ - connect->connstate = "Exchanging init messages"; - status_trace("Connect OUT to %s", - type_to_string(tmpctx, struct pubkey, id)); - return peer_exchange_initmsg(conn, connect->daemon, cs, id, addr); -} - -struct io_plan *connection_out(struct io_conn *conn, struct connecting *connect) -{ - /* FIXME: Timeout */ - status_trace("Connected out for %s", - type_to_string(tmpctx, struct pubkey, &connect->id)); - - connect->connstate = "Cryptographic handshake"; - return initiator_handshake(conn, &connect->daemon->id, &connect->id, - &connect->addrs[connect->addrnum], - handshake_out_success, connect); -} - -static void PRINTF_FMT(5,6) - connect_failed(struct daemon *daemon, - const struct pubkey *id, - u32 seconds_waited, - const struct wireaddr_internal *addrhint, - const char *errfmt, ...) -{ - u8 *msg; - va_list ap; - char *err; - u32 wait_seconds; - - va_start(ap, errfmt); - err = tal_vfmt(tmpctx, errfmt, ap); - va_end(ap); - - /* Wait twice as long to reconnect, between min and max. */ - wait_seconds = seconds_waited * 2; - if (wait_seconds > MAX_WAIT_SECONDS) - wait_seconds = MAX_WAIT_SECONDS; - if (wait_seconds < INITIAL_WAIT_SECONDS) - wait_seconds = INITIAL_WAIT_SECONDS; - - /* Tell any connect command what happened. */ - msg = towire_connectctl_connect_failed(NULL, id, err, wait_seconds, - addrhint); - daemon_conn_send(&daemon->master, take(msg)); - - status_trace("Failed connected out for %s: %s", - type_to_string(tmpctx, struct pubkey, id), - err); -} - -static void destroy_io_conn(struct io_conn *conn, struct connecting *connect) -{ - tal_append_fmt(&connect->errors, - "%s: %s: %s. ", - type_to_string(tmpctx, struct wireaddr_internal, - &connect->addrs[connect->addrnum]), - connect->connstate, strerror(errno)); - connect->addrnum++; - try_connect_one_addr(connect); -} - -static struct io_plan *conn_init(struct io_conn *conn, - struct connecting *connect) -{ - struct addrinfo *ai = NULL; - const struct wireaddr_internal *addr = &connect->addrs[connect->addrnum]; - - switch (addr->itype) { - case ADDR_INTERNAL_SOCKNAME: - ai = wireaddr_internal_to_addrinfo(tmpctx, addr); - break; - case ADDR_INTERNAL_ALLPROTO: - status_failed(STATUS_FAIL_INTERNAL_ERROR, - "Can't connect to all protocols"); - break; - case ADDR_INTERNAL_AUTOTOR: - status_failed(STATUS_FAIL_INTERNAL_ERROR, - "Can't connect to autotor address"); - break; - case ADDR_INTERNAL_FORPROXY: - status_failed(STATUS_FAIL_INTERNAL_ERROR, - "Can't connect to forproxy address"); - break; - case ADDR_INTERNAL_WIREADDR: - /* If it was a Tor address, we wouldn't be here. */ - ai = wireaddr_to_addrinfo(tmpctx, &addr->u.wireaddr); - break; - } - assert(ai); - - io_set_finish(conn, destroy_io_conn, connect); - return io_connect(conn, ai, connection_out, connect); -} - -static struct io_plan *conn_proxy_init(struct io_conn *conn, - struct connecting *connect) -{ - const char *host = NULL; - u16 port; - const struct wireaddr_internal *addr = &connect->addrs[connect->addrnum]; - - switch (addr->itype) { - case ADDR_INTERNAL_FORPROXY: - host = addr->u.unresolved.name; - port = addr->u.unresolved.port; - break; - case ADDR_INTERNAL_WIREADDR: - host = fmt_wireaddr_without_port(tmpctx, &addr->u.wireaddr); - port = addr->u.wireaddr.port; - break; - case ADDR_INTERNAL_SOCKNAME: - case ADDR_INTERNAL_ALLPROTO: - case ADDR_INTERNAL_AUTOTOR: - break; - } - - if (!host) - status_failed(STATUS_FAIL_INTERNAL_ERROR, - "Can't connect to %u address", addr->itype); - - io_set_finish(conn, destroy_io_conn, connect); - return io_tor_connect(conn, connect->daemon->proxyaddr, host, port, - connect); -} - static const char *seedname(const tal_t *ctx, const struct pubkey *id) { char bech32[100]; @@ -930,87 +1011,6 @@ static void add_gossip_addrs(struct wireaddr_internal **addrs, } } -static void try_connect_one_addr(struct connecting *connect) -{ - int fd, af; - bool use_proxy = connect->daemon->use_proxy_always; - const struct wireaddr_internal *addr = &connect->addrs[connect->addrnum]; - - if (connect->addrnum == tal_count(connect->addrs)) { - connect_failed(connect->daemon, &connect->id, - connect->seconds_waited, - connect->addrhint, "%s", connect->errors); - tal_free(connect); - return; - } - - /* Might not even be able to create eg. IPv6 sockets */ - af = -1; - - switch (addr->itype) { - case ADDR_INTERNAL_SOCKNAME: - af = AF_LOCAL; - /* Local sockets don't use tor proxy */ - use_proxy = false; - break; - case ADDR_INTERNAL_ALLPROTO: - status_failed(STATUS_FAIL_INTERNAL_ERROR, - "Can't connect ALLPROTO"); - case ADDR_INTERNAL_AUTOTOR: - status_failed(STATUS_FAIL_INTERNAL_ERROR, - "Can't connect AUTOTOR"); - case ADDR_INTERNAL_FORPROXY: - use_proxy = true; - break; - case ADDR_INTERNAL_WIREADDR: - switch (addr->u.wireaddr.type) { - case ADDR_TYPE_TOR_V2: - case ADDR_TYPE_TOR_V3: - use_proxy = true; - break; - case ADDR_TYPE_IPV4: - af = AF_INET; - break; - case ADDR_TYPE_IPV6: - af = AF_INET6; - break; - case ADDR_TYPE_PADDING: - break; - } - } - - /* If we have to use proxy but we don't have one, we fail. */ - if (use_proxy) { - if (!connect->daemon->proxyaddr) { - status_debug("Need proxy"); - af = -1; - } else - af = connect->daemon->proxyaddr->ai_family; - } - - if (af == -1) { - fd = -1; - errno = EPROTONOSUPPORT; - } else - fd = socket(af, SOCK_STREAM, 0); - - if (fd < 0) { - tal_append_fmt(&connect->errors, - "%s: opening %i socket gave %s. ", - type_to_string(tmpctx, struct wireaddr_internal, - addr), - af, strerror(errno)); - connect->addrnum++; - try_connect_one_addr(connect); - return; - } - - if (use_proxy) - io_new_conn(connect, fd, conn_proxy_init, connect); - else - io_new_conn(connect, fd, conn_init, connect); -} - /* Consumes addrhint if not NULL */ static void try_connect_peer(struct daemon *daemon, const struct pubkey *id,