commit 4a39cae8c4ccb16b3eb4cb11da1ed356f310038b
parent 0b59ee0df3aaa16b92bd8f48edfdacc9f55b2922
Author: Oswald Buddenhagen <ossi@users.sf.net>
Date: Sun, 1 Sep 2013 16:32:45 +0200
support multi-homed servers
Diffstat:
M | src/isync.h | | | 1 | + |
M | src/socket.c | | | 91 | +++++++++++++++++++++++++++++++++++++++++++++++++++---------------------------- |
2 files changed, 60 insertions(+), 32 deletions(-)
diff --git a/src/isync.h b/src/isync.h
@@ -85,6 +85,7 @@ typedef struct {
int fd;
int state;
const server_conf_t *conf; /* needed during connect */
+ char **curr_addr; /* needed during connect */
char *name;
#ifdef HAVE_LIBSSL
SSL *ssl;
diff --git a/src/socket.c b/src/socket.c
@@ -296,6 +296,7 @@ static void start_tls_p3( conn_t *conn, int ok )
static void socket_fd_cb( int, void * );
+static void socket_connect_one( conn_t * );
static void socket_connect_failed( conn_t * );
static void socket_connected( conn_t * );
static void socket_connect_bail( conn_t * );
@@ -312,14 +313,13 @@ void
socket_connect( conn_t *sock, void (*cb)( int ok, void *aux ) )
{
const server_conf_t *conf = sock->conf;
- struct hostent *he;
- struct sockaddr_in addr;
- int s, a[2];
sock->callbacks.connect = cb;
/* open connection to IMAP server */
if (conf->tunnel) {
+ int a[2];
+
nfasprintf( &sock->name, "tunnel '%s'", conf->tunnel );
infon( "Starting %s... ", sock->name );
@@ -343,14 +343,10 @@ socket_connect( conn_t *sock, void (*cb)( int ok, void *aux ) )
fcntl( a[1], F_SETFL, O_NONBLOCK );
add_fd( a[1], socket_fd_cb, sock );
+ info( "\vok\n" );
+ socket_connected( sock );
} else {
- memset( &addr, 0, sizeof(addr) );
- addr.sin_port = conf->port ? htons( conf->port ) :
-#ifdef HAVE_LIBSSL
- conf->use_imaps ? htons( 993 ) :
-#endif
- htons( 143 );
- addr.sin_family = AF_INET;
+ struct hostent *he;
infon( "Resolving %s... ", conf->host );
he = gethostbyname( conf->host );
@@ -361,35 +357,63 @@ socket_connect( conn_t *sock, void (*cb)( int ok, void *aux ) )
}
info( "\vok\n" );
- addr.sin_addr.s_addr = *((int *)he->h_addr_list[0]);
+ sock->curr_addr = he->h_addr_list;
+ socket_connect_one( sock );
+ }
+}
- s = socket( PF_INET, SOCK_STREAM, 0 );
- if (s < 0) {
- perror( "socket" );
- exit( 1 );
- }
- sock->fd = s;
- fcntl( s, F_SETFL, O_NONBLOCK );
- add_fd( s, socket_fd_cb, sock );
+static void
+socket_connect_one( conn_t *sock )
+{
+ int s;
+ ushort port;
+ struct {
+ struct sockaddr_in ai_addr[1];
+ } ai[1];
+
+ if (!*sock->curr_addr) {
+ error( "No working address found for %s\n", sock->conf->host );
+ socket_connect_bail( sock );
+ return;
+ }
+ port = sock->conf->port ? sock->conf->port :
+#ifdef HAVE_LIBSSL
+ sock->conf->use_imaps ? 993 :
+#endif
+ 143;
+ {
+ struct sockaddr_in *in = ((struct sockaddr_in *)ai->ai_addr);
+ memset( in, 0, sizeof(*in) );
+ in->sin_family = AF_INET;
+ in->sin_addr.s_addr = *((int *)*sock->curr_addr);
+ in->sin_port = htons( port );
nfasprintf( &sock->name, "%s (%s:%hu)",
- conf->host, inet_ntoa( addr.sin_addr ), ntohs( addr.sin_port ) );
- infon( "Connecting to %s... ", sock->name );
- if (connect( s, (struct sockaddr *)&addr, sizeof(addr) )) {
- if (errno != EINPROGRESS) {
- socket_connect_failed( sock );
- return;
- }
- conf_fd( s, 0, POLLOUT );
- sock->state = SCK_CONNECTING;
- info( "\v\n" );
+ sock->conf->host, inet_ntoa( in->sin_addr ), port );
+ }
+
+ s = socket( PF_INET, SOCK_STREAM, 0 );
+ if (s < 0) {
+ perror( "socket" );
+ exit( 1 );
+ }
+ sock->fd = s;
+ fcntl( s, F_SETFL, O_NONBLOCK );
+ add_fd( s, socket_fd_cb, sock );
+
+ infon( "Connecting to %s... ", sock->name );
+ if (connect( s, ai->ai_addr, sizeof(*ai->ai_addr) )) {
+ if (errno != EINPROGRESS) {
+ socket_connect_failed( sock );
return;
}
-
+ conf_fd( s, 0, POLLOUT );
+ sock->state = SCK_CONNECTING;
+ info( "\v\n" );
+ return;
}
info( "\vok\n" );
socket_connected( sock );
- return;
}
static void
@@ -397,7 +421,10 @@ socket_connect_failed( conn_t *conn )
{
sys_error( "Cannot connect to %s", conn->name );
socket_close_internal( conn );
- socket_connect_bail( conn );
+ free( conn->name );
+ conn->name = 0;
+ conn->curr_addr++;
+ socket_connect_one( conn );
}
static void