fix simultaneously connecting to multiple hosts in non-IPv6 builds
we need to deep-copy the struct hostent data, as otherwise the concurrent connects will overwrite each other's lookup results. this is a rather hypothetical fix, as the bug currently affects only channels connecting two IMAP accounts, and only if the first host's first address asynchronously fails to connect.
This commit is contained in:
parent
3651c30296
commit
813ad67c56
52
src/socket.c
52
src/socket.c
|
@ -430,6 +430,32 @@ socket_close_internal( conn_t *sock )
|
|||
sock->fd = -1;
|
||||
}
|
||||
|
||||
#ifndef HAVE_IPV6
|
||||
struct addr_info {
|
||||
struct addr_info *ai_next;
|
||||
struct sockaddr_in ai_addr[1];
|
||||
};
|
||||
|
||||
#define freeaddrinfo(ai) free( ai )
|
||||
|
||||
static struct addr_info *
|
||||
init_addrinfo( struct hostent *he )
|
||||
{
|
||||
uint naddr = 0;
|
||||
for (char **addr = he->h_addr_list; *addr; addr++)
|
||||
naddr++;
|
||||
struct addr_info *caddr = nfcalloc( naddr * sizeof(struct addrinfo) );
|
||||
struct addr_info *ret, **caddrp = &ret;
|
||||
for (char **addr = he->h_addr_list; *addr; addr++, caddr++) {
|
||||
caddr->ai_addr->sin_family = AF_INET;
|
||||
memcpy( &caddr->ai_addr->sin_addr.s_addr, *addr, sizeof(struct in_addr) );
|
||||
*caddrp = caddr;
|
||||
caddrp = &caddr->ai_next;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
socket_connect( conn_t *sock, void (*cb)( int ok, void *aux ) )
|
||||
{
|
||||
|
@ -479,8 +505,6 @@ socket_connect( conn_t *sock, void (*cb)( int ok, void *aux ) )
|
|||
return;
|
||||
}
|
||||
info( "\vok\n" );
|
||||
|
||||
sock->curr_addr = sock->addrs;
|
||||
#else
|
||||
struct hostent *he;
|
||||
|
||||
|
@ -493,8 +517,9 @@ socket_connect( conn_t *sock, void (*cb)( int ok, void *aux ) )
|
|||
}
|
||||
info( "\vok\n" );
|
||||
|
||||
sock->curr_addr = he->h_addr_list;
|
||||
sock->addrs = init_addrinfo( he );
|
||||
#endif
|
||||
sock->curr_addr = sock->addrs;
|
||||
socket_connect_one( sock );
|
||||
}
|
||||
}
|
||||
|
@ -506,16 +531,10 @@ socket_connect_one( conn_t *sock )
|
|||
#ifdef HAVE_IPV6
|
||||
struct addrinfo *ai;
|
||||
#else
|
||||
struct {
|
||||
struct sockaddr_in ai_addr[1];
|
||||
} ai[1];
|
||||
struct addr_info *ai;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_IPV6
|
||||
if (!(ai = sock->curr_addr)) {
|
||||
#else
|
||||
if (!*sock->curr_addr) {
|
||||
#endif
|
||||
error( "No working address found for %s\n", sock->conf->host );
|
||||
socket_connect_bail( sock );
|
||||
return;
|
||||
|
@ -532,11 +551,6 @@ socket_connect_one( conn_t *sock )
|
|||
#endif
|
||||
{
|
||||
struct sockaddr_in *in = ((struct sockaddr_in *)ai->ai_addr);
|
||||
#ifndef HAVE_IPV6
|
||||
memset( in, 0, sizeof(*in) );
|
||||
in->sin_family = AF_INET;
|
||||
in->sin_addr.s_addr = *((int *)*sock->curr_addr);
|
||||
#endif
|
||||
in->sin_port = htons( sock->conf->port );
|
||||
nfasprintf( &sock->name, "%s (%s:%hu)",
|
||||
sock->conf->host, inet_ntoa( in->sin_addr ), sock->conf->port );
|
||||
|
@ -579,11 +593,7 @@ socket_connect_next( conn_t *conn )
|
|||
sys_error( "Cannot connect to %s", conn->name );
|
||||
free( conn->name );
|
||||
conn->name = 0;
|
||||
#ifdef HAVE_IPV6
|
||||
conn->curr_addr = conn->curr_addr->ai_next;
|
||||
#else
|
||||
conn->curr_addr++;
|
||||
#endif
|
||||
socket_connect_one( conn );
|
||||
}
|
||||
|
||||
|
@ -597,12 +607,10 @@ socket_connect_failed( conn_t *conn )
|
|||
static void
|
||||
socket_connected( conn_t *conn )
|
||||
{
|
||||
#ifdef HAVE_IPV6
|
||||
if (conn->addrs) {
|
||||
freeaddrinfo( conn->addrs );
|
||||
conn->addrs = 0;
|
||||
}
|
||||
#endif
|
||||
conf_notifier( &conn->notify, 0, POLLIN );
|
||||
socket_expect_read( conn, 0 );
|
||||
conn->state = SCK_READY;
|
||||
|
@ -612,12 +620,10 @@ socket_connected( conn_t *conn )
|
|||
static void
|
||||
socket_cleanup_names( conn_t *conn )
|
||||
{
|
||||
#ifdef HAVE_IPV6
|
||||
if (conn->addrs) {
|
||||
freeaddrinfo( conn->addrs );
|
||||
conn->addrs = 0;
|
||||
}
|
||||
#endif
|
||||
free( conn->name );
|
||||
conn->name = 0;
|
||||
}
|
||||
|
|
|
@ -73,7 +73,7 @@ typedef struct {
|
|||
#ifdef HAVE_IPV6
|
||||
struct addrinfo *addrs, *curr_addr; /* needed during connect */
|
||||
#else
|
||||
char **curr_addr; /* needed during connect */
|
||||
struct addr_info *addrs, *curr_addr; /* needed during connect */
|
||||
#endif
|
||||
char *name;
|
||||
#ifdef HAVE_LIBSSL
|
||||
|
|
Loading…
Reference in New Issue
Block a user