commit 813ad67c5664019d198b5c0832c10142a20f2793 Author: Oswald Buddenhagen <o...@users.sf.net> Date: Mon Jul 27 22:48:41 2020 +0200
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. src/socket.c | 52 +++++++++++++++++++++++++++++----------------------- src/socket.h | 2 +- 2 files changed, 30 insertions(+), 24 deletions(-) diff --git a/src/socket.c b/src/socket.c index dbd781c..6078f99 100644 --- a/src/socket.c +++ b/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; } diff --git a/src/socket.h b/src/socket.h index f80c2ef..1fdd7aa 100644 --- a/src/socket.h +++ b/src/socket.h @@ -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 _______________________________________________ isync-devel mailing list isync-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/isync-devel