Discussion:
[PATCH] socket: use next addrinfo if opening socket fails
Patrick Steinhardt
2017-06-21 07:33:20 UTC
Permalink
The `socket_connect_one` function currently does an `exit(1)` when
encountering any errors with opening the socket. This in fact breaks
connecting to a host where multiple possible addrinfos are returned,
where the leading addrinfos are in fact impossible to connect to. E.g.
with a kernel configured without support for IPv6, the `getaddrinfo`
call may still return a hint containing an IPv6 address alongside
another hint with an IPv4 address. Creating the socket with the IPv6
address, which will cause an error, leads us to exiting early without
even trying remaining hints.

While one can argue that the user should have compiled without
HAVE_IPV6, we can do better by simply skipping over the current addrinfo
causing an error. To do so, we split out a new function
`socket_connect_next`, which selects the next available address info and
subsequently calls `socket_connect_one` again. When no hints remain,
`sock_connect_one` will error out at that point.
---
src/socket.c | 15 +++++++++++----
1 file changed, 11 insertions(+), 4 deletions(-)

diff --git a/src/socket.c b/src/socket.c
index 6ab3ce4..467723e 100644
--- a/src/socket.c
+++ b/src/socket.c
@@ -343,6 +343,7 @@ static void socket_fake_cb( void * );
static void socket_timeout_cb( void * );

static void socket_connect_one( conn_t * );
+static void socket_connect_next( conn_t * );
static void socket_connect_failed( conn_t * );
static void socket_connected( conn_t * );
static void socket_connect_bail( conn_t * );
@@ -485,8 +486,8 @@ socket_connect_one( conn_t *sock )
s = socket( PF_INET, SOCK_STREAM, 0 );
#endif
if (s < 0) {
- perror( "socket" );
- exit( 1 );
+ socket_connect_next( sock );
+ return;
}
socket_open_internal( sock, s );

@@ -511,10 +512,9 @@ socket_connect_one( conn_t *sock )
}

static void
-socket_connect_failed( conn_t *conn )
+socket_connect_next( conn_t *conn )
{
sys_error( "Cannot connect to %s", conn->name );
- socket_close_internal( conn );
free( conn->name );
conn->name = 0;
#ifdef HAVE_IPV6
@@ -526,6 +526,13 @@ socket_connect_failed( conn_t *conn )
}

static void
+socket_connect_failed( conn_t *conn )
+{
+ socket_close_internal( conn );
+ socket_connect_next( conn );
+}
+
+static void
socket_connected( conn_t *conn )
{
#ifdef HAVE_IPV6
--
2.13.1
Loading...