From 3599146d59b50c18c3304e05fc2da5b2c30d86e5 Mon Sep 17 00:00:00 2001
From: Simon Arlott <sa.me.uk>
Date: Mon, 27 Aug 2012 21:48:09 +0100
Subject: [PATCH 2/2] automatically connect using IPv6 or IPv4

A failed server will cause the next group of hosts in
an address family to be used, until there are no more
groups of hosts and it starts again from the beginning.

The list of hosts within a group of the same address
family is randomly shuffled so that a different IP is
used if the resolver library returns the IPs in the
same order each time.

Under Cygwin a pool of sockets is used when making
connection attempts, otherwise the child process passes
the socket to the parent when connected.

The connect API is changed:
  Removed parameter "sock"
  Added parameter "retry"
  Added callback value "sock"
---
 doc/de/weechat_scripting.de.txt         |    3 +-
 doc/en/weechat_plugin_api.en.txt        |   13 +-
 doc/en/weechat_scripting.en.txt         |    3 +-
 doc/fr/weechat_plugin_api.fr.txt        |   11 +-
 doc/fr/weechat_scripting.fr.txt         |    3 +-
 doc/it/weechat_plugin_api.it.txt        |   11 +-
 doc/it/weechat_scripting.it.txt         |    3 +-
 doc/pl/weechat_scripting.pl.txt         |    3 +-
 src/core/wee-hook.c                     |   46 ++-
 src/core/wee-hook.h                     |   27 +-
 src/core/wee-network.c                  |  663 ++++++++++++++++++++-----------
 src/plugins/guile/weechat-guile-api.c   |   27 +-
 src/plugins/irc/irc-server.c            |  124 +++---
 src/plugins/irc/irc-server.h            |    5 +-
 src/plugins/lua/weechat-lua-api.c       |   35 ++-
 src/plugins/perl/weechat-perl-api.c     |   20 +-
 src/plugins/plugin-script-api.c         |    9 +-
 src/plugins/plugin-script-api.h         |    3 +-
 src/plugins/python/weechat-python-api.c |   26 +-
 src/plugins/python/weechat-python.c     |    1 +
 src/plugins/ruby/weechat-ruby-api.c     |   31 +-
 src/plugins/tcl/weechat-tcl-api.c       |   25 +-
 src/plugins/weechat-plugin.h            |   14 +-
 23 files changed, 718 insertions(+), 388 deletions(-)

diff --git a/doc/de/weechat_scripting.de.txt b/doc/de/weechat_scripting.de.txt
index 3f4c70f..fe27bd0 100644
--- a/doc/de/weechat_scripting.de.txt
+++ b/doc/de/weechat_scripting.de.txt
@@ -391,7 +391,8 @@ Liste der Konstanten in Skript API:
   WEECHAT_HOOK_CONNECT_IP_ADDRESS_NOT_FOUND, WEECHAT_HOOK_CONNECT_CONNECTION_REFUSED,
   WEECHAT_HOOK_CONNECT_PROXY_ERROR, WEECHAT_HOOK_CONNECT_LOCAL_HOSTNAME_ERROR,
   WEECHAT_HOOK_CONNECT_GNUTLS_INIT_ERROR, WEECHAT_HOOK_CONNECT_GNUTLS_HANDSHAKE_ERROR,
-  WEECHAT_HOOK_CONNECT_MEMORY_ERROR, WEECHAT_HOOK_CONNECT_TIMEOUT
+  WEECHAT_HOOK_CONNECT_MEMORY_ERROR, WEECHAT_HOOK_CONNECT_TIMEOUT,
+  WEECHAT_HOOK_CONNECT_SOCKET_ERROR
 | hook Signal         |
   WEECHAT_HOOK_SIGNAL_STRING, WEECHAT_HOOK_SIGNAL_INT, WEECHAT_HOOK_SIGNAL_POINTER
 |========================================
diff --git a/doc/en/weechat_plugin_api.en.txt b/doc/en/weechat_plugin_api.en.txt
index 572cd3d..d8a2277 100644
--- a/doc/en/weechat_plugin_api.en.txt
+++ b/doc/en/weechat_plugin_api.en.txt
@@ -7106,8 +7106,8 @@ Prototype:
 struct t_hook *weechat_hook_connect (const char *proxy,
                                      const char *address,
                                      int port,
-                                     int sock,
                                      int ipv6,
+                                     unsigned int retry,
                                      void *gnutls_sess,
                                      void *gnutls_cb,
                                      int gnutls_dhkey_size,
@@ -7116,6 +7116,7 @@ struct t_hook *weechat_hook_connect (const char *proxy,
                                      int (*callback)(void *data,
                                                      int status,
                                                      int gnutls_rc,
+                                                     int sock,
                                                      const char *error,
                                                      const char *ip_address),
                                      void *callback_data);
@@ -7127,8 +7128,9 @@ Arguments:
   without proxy)
 * 'address': name or IP address to connect to
 * 'port': port number
-* 'sock': socket used to connect
 * 'ipv6': 1 to use IPv6, 0 to use IPv4
+* 'retry': retry count, used to fallback to IPv4 hosts if IPv6 hosts connect
+  but then fail to accept the client
 * 'gnutls_sess': GnuTLS session (optional)
 * 'gnutls_cb': GnuTLS callback (optional)
 * 'gnutls_dhkey_size': size of the key used during the Diffie-Hellman Key
@@ -7156,7 +7158,9 @@ Arguments:
 *** 'WEECHAT_HOOK_CONNECT_GNUTLS_HANDSHAKE_ERROR': GnuTLS handshake error
 *** 'WEECHAT_HOOK_CONNECT_MEMORY_ERROR': insufficient memory
 *** 'WEECHAT_HOOK_CONNECT_TIMEOUT': timeout
+*** 'WEECHAT_HOOK_CONNECT_SOCKET_ERROR': unable to create socket
 ** 'gnutls_rc': result value of 'gnutls_handshake()'
+** 'sock': connection socket
 ** 'const char *error': result value of 'gnutls_strerror(gnutls_rc)'
 ** 'const char *ip_address': IP address found
 ** return value:
@@ -7208,6 +7212,9 @@ my_connect_cb (void *data, int status, int gnutls_rc, const char *error,
         case WEECHAT_HOOK_CONNECT_TIMEOUT:
             /* ... */
             break;
+        case WEECHAT_HOOK_CONNECT_SOCKET_ERROR:
+            /* ... */
+            break;
     }
     return WEECHAT_RC_OK;
 }
@@ -7250,6 +7257,8 @@ def my_connect_cb(data, status, gnutls_rc, error, ip_address):
         # ...
     elif status == WEECHAT_HOOK_CONNECT_TIMEOUT:
         # ...
+    elif status == WEECHAT_HOOK_CONNECT_SOCKET_ERROR:
+        # ...
     return weechat.WEECHAT_RC_OK
 
 hook = weechat.hook_connect("", "my.server.org", 1234, sock, 0, "",
diff --git a/doc/en/weechat_scripting.en.txt b/doc/en/weechat_scripting.en.txt
index e64962e..3ae2676 100644
--- a/doc/en/weechat_scripting.en.txt
+++ b/doc/en/weechat_scripting.en.txt
@@ -385,7 +385,8 @@ List of constants in script API:
   WEECHAT_HOOK_CONNECT_IP_ADDRESS_NOT_FOUND, WEECHAT_HOOK_CONNECT_CONNECTION_REFUSED,
   WEECHAT_HOOK_CONNECT_PROXY_ERROR, WEECHAT_HOOK_CONNECT_LOCAL_HOSTNAME_ERROR,
   WEECHAT_HOOK_CONNECT_GNUTLS_INIT_ERROR, WEECHAT_HOOK_CONNECT_GNUTLS_HANDSHAKE_ERROR,
-  WEECHAT_HOOK_CONNECT_MEMORY_ERROR, WEECHAT_HOOK_CONNECT_TIMEOUT
+  WEECHAT_HOOK_CONNECT_MEMORY_ERROR, WEECHAT_HOOK_CONNECT_TIMEOUT,
+  WEECHAT_HOOK_CONNECT_SOCKET_ERROR
 | hook signal         |
   WEECHAT_HOOK_SIGNAL_STRING, WEECHAT_HOOK_SIGNAL_INT, WEECHAT_HOOK_SIGNAL_POINTER
 |========================================
diff --git a/doc/fr/weechat_plugin_api.fr.txt b/doc/fr/weechat_plugin_api.fr.txt
index fde2236..4e5419b 100644
--- a/doc/fr/weechat_plugin_api.fr.txt
+++ b/doc/fr/weechat_plugin_api.fr.txt
@@ -7210,8 +7210,8 @@ Prototype :
 struct t_hook *weechat_hook_connect (const char *proxy,
                                      const char *address,
                                      int port,
-                                     int sock,
                                      int ipv6,
+                                     unsigned int retry,
                                      void *gnutls_sess,
                                      void *gnutls_cb,
                                      int gnutls_dhkey_size,
@@ -7220,6 +7220,7 @@ struct t_hook *weechat_hook_connect (const char *proxy,
                                      int (*callback)(void *data,
                                                      int status,
                                                      int gnutls_rc,
+                                                     int sock,
                                                      const char *error,
                                                      const char *ip_address),
                                      void *callback_data);
@@ -7231,7 +7232,6 @@ Paramètres :
   une connexion sans proxy)
 * 'address' : nom ou adresse IP de la machine à laquelle se connecter
 * 'port' : numéro de port
-* 'sock' : socket utilisée pour la connexion
 * 'ipv6' : 1 pour utiliser IPv6, 0 pour utiliser IPv4
 * 'gnutls_sess' : GnuTLS session (optionnel)
 * 'gnutls_cb' : callback pour GnuTLS (optionnel)
@@ -7263,7 +7263,9 @@ Paramètres :
     "poignée de main" GnuTLS
 *** 'WEECHAT_HOOK_CONNECT_MEMORY_ERROR' : mémoire insuffisante
 *** 'WEECHAT_HOOK_CONNECT_TIMEOUT' : temps maximum dépassé
+*** 'WEECHAT_HOOK_CONNECT_SOCKET_ERROR' : erreur de création socket
 ** 'gnutls_rc' : valeur retour de 'gnutls_handshake()'
+** 'sock' : socket utilisée pour la connexion
 ** 'const char *error' : valeur retour de 'gnutls_strerror(gnutls_rc)'
 ** 'const char *ip_address' : adresse IP trouvée
 ** valeur de retour :
@@ -7316,6 +7318,9 @@ my_connect_cb (void *data, int status, int gnutls_rc, const char *error,
         case WEECHAT_HOOK_CONNECT_TIMEOUT:
             /* ... */
             break;
+        case WEECHAT_HOOK_CONNECT_SOCKET_ERROR:
+            /* ... */
+            break;
     }
     return WEECHAT_RC_OK;
 }
@@ -7358,6 +7363,8 @@ def my_connect_cb(data, status, gnutls_rc, error, ip_address):
         # ...
     elif status == WEECHAT_HOOK_CONNECT_TIMEOUT:
         # ...
+    elif status == WEECHAT_HOOK_CONNECT_SOCKET_ERROR:
+        # ...
     return weechat.WEECHAT_RC_OK
 
 hook = weechat.hook_connect("", "my.server.org", 1234, sock, 0, "",
diff --git a/doc/fr/weechat_scripting.fr.txt b/doc/fr/weechat_scripting.fr.txt
index 235aeee..c03b9de 100644
--- a/doc/fr/weechat_scripting.fr.txt
+++ b/doc/fr/weechat_scripting.fr.txt
@@ -394,7 +394,8 @@ Liste des constantes de l'API script :
   WEECHAT_HOOK_CONNECT_IP_ADDRESS_NOT_FOUND, WEECHAT_HOOK_CONNECT_CONNECTION_REFUSED,
   WEECHAT_HOOK_CONNECT_PROXY_ERROR, WEECHAT_HOOK_CONNECT_LOCAL_HOSTNAME_ERROR,
   WEECHAT_HOOK_CONNECT_GNUTLS_INIT_ERROR, WEECHAT_HOOK_CONNECT_GNUTLS_HANDSHAKE_ERROR,
-  WEECHAT_HOOK_CONNECT_MEMORY_ERROR, WEECHAT_HOOK_CONNECT_TIMEOUT
+  WEECHAT_HOOK_CONNECT_MEMORY_ERROR, WEECHAT_HOOK_CONNECT_TIMEOUT,
+  WEECHAT_HOOK_CONNECT_SOCKET_ERROR
 | hook signal               |
   WEECHAT_HOOK_SIGNAL_STRING, WEECHAT_HOOK_SIGNAL_INT, WEECHAT_HOOK_SIGNAL_POINTER
 |========================================
diff --git a/doc/it/weechat_plugin_api.it.txt b/doc/it/weechat_plugin_api.it.txt
index a9c582f..c135656 100644
--- a/doc/it/weechat_plugin_api.it.txt
+++ b/doc/it/weechat_plugin_api.it.txt
@@ -7138,8 +7138,8 @@ Prototipo:
 struct t_hook *weechat_hook_connect (const char *proxy,
                                      const char *address,
                                      int port,
-                                     int sock,
                                      int ipv6,
+                                     unsigned int retry,
                                      void *gnutls_sess,
                                      void *gnutls_cb,
                                      int gnutls_dhkey_size,
@@ -7148,6 +7148,7 @@ struct t_hook *weechat_hook_connect (const char *proxy,
                                      int (*callback)(void *data,
                                                      int status,
                                                      int gnutls_rc,
+                                                     int sock,
                                                      const char *error,
                                                      const char *ip_address),
                                      void *callback_data);
@@ -7159,7 +7160,6 @@ Argomenti:
   NULL significa connessione senza proxy)
 * 'address': nome o indirizzo IP al quale connettersi
 * 'port': numero della porta
-* 'sock': socket utilizzato per la connessione
 * 'ipv6': 1 per usare IPv6, 0 per usare IPv4
 * 'gnutls_sess': sessione GnuTLS (opzionale)
 * 'gnutls_cb' callback GnuTLS (opzionale)
@@ -7190,7 +7190,9 @@ Argomenti:
 *** 'WEECHAT_HOOK_CONNECT_GNUTLS_HANDSHAKE_ERROR': errore di handshake GnuTLS
 *** 'WEECHAT_HOOK_CONNECT_MEMORY_ERROR': memoria insufficiente
 *** 'WEECHAT_HOOK_CONNECT_TIMEOUT': timeout
+*** 'WEECHAT_HOOK_CONNECT_SOCKET_ERROR': errore nella creazione socket
 ** 'gnutls_rc': valore del risultato di 'gnutls_handshake()'
+** 'sock': socket utilizzato per la connessione
 ** 'const char *error': valore del risultato di 'gnutls_strerror(gnutls_rc)'
 ** 'const char *ip_address': indirizzo IP trovato
 ** valore restituito:
@@ -7242,6 +7244,9 @@ my_connect_cb (void *data, int status, int gnutls_rc, const char *error,
         case WEECHAT_HOOK_CONNECT_TIMEOUT:
             /* ... */
             break;
+        case WEECHAT_HOOK_CONNECT_SOCKET_ERROR:
+            /* ... */
+            break;
     }
     return WEECHAT_RC_OK;
 }
@@ -7284,6 +7289,8 @@ def my_connect_cb(data, status, gnutls_rc, error, ip_address):
         # ...
     elif status == WEECHAT_HOOK_CONNECT_TIMEOUT:
         # ...
+    elif status == WEECHAT_HOOK_CONNECT_SOCKET_ERROR:
+        # ...
     return weechat.WEECHAT_RC_OK
 
 hook = weechat.hook_connect("", "my.server.org", 1234, sock, 0, "",
diff --git a/doc/it/weechat_scripting.it.txt b/doc/it/weechat_scripting.it.txt
index c1e291b..c643e5a 100644
--- a/doc/it/weechat_scripting.it.txt
+++ b/doc/it/weechat_scripting.it.txt
@@ -393,7 +393,8 @@ Elenco di costanti nelle API per gli script:
   WEECHAT_HOOK_CONNECT_IP_ADDRESS_NOT_FOUND, WEECHAT_HOOK_CONNECT_CONNECTION_REFUSED,
   WEECHAT_HOOK_CONNECT_PROXY_ERROR, WEECHAT_HOOK_CONNECT_LOCAL_HOSTNAME_ERROR,
   WEECHAT_HOOK_CONNECT_GNUTLS_INIT_ERROR, WEECHAT_HOOK_CONNECT_GNUTLS_HANDSHAKE_ERROR,
-  WEECHAT_HOOK_CONNECT_MEMORY_ERROR, WEECHAT_HOOK_CONNECT_TIMEOUT
+  WEECHAT_HOOK_CONNECT_MEMORY_ERROR, WEECHAT_HOOK_CONNECT_TIMEOUT,
+  WEECHAT_HOOK_CONNECT_SOCKET_ERROR
 | hook su segnale        |
   WEECHAT_HOOK_SIGNAL_STRING, WEECHAT_HOOK_SIGNAL_INT, WEECHAT_HOOK_SIGNAL_POINTER
 |========================================
diff --git a/doc/pl/weechat_scripting.pl.txt b/doc/pl/weechat_scripting.pl.txt
index bd48a3b..931d649 100644
--- a/doc/pl/weechat_scripting.pl.txt
+++ b/doc/pl/weechat_scripting.pl.txt
@@ -384,7 +384,8 @@ Lista stałych w API skryptów:
   WEECHAT_HOOK_CONNECT_IP_ADDRESS_NOT_FOUND, WEECHAT_HOOK_CONNECT_CONNECTION_REFUSED,
   WEECHAT_HOOK_CONNECT_PROXY_ERROR, WEECHAT_HOOK_CONNECT_LOCAL_HOSTNAME_ERROR,
   WEECHAT_HOOK_CONNECT_GNUTLS_INIT_ERROR, WEECHAT_HOOK_CONNECT_GNUTLS_HANDSHAKE_ERROR,
-  WEECHAT_HOOK_CONNECT_MEMORY_ERROR, WEECHAT_HOOK_CONNECT_TIMEOUT
+  WEECHAT_HOOK_CONNECT_MEMORY_ERROR, WEECHAT_HOOK_CONNECT_TIMEOUT,
+  WEECHAT_HOOK_CONNECT_SOCKET_ERROR
 | hook signal         |
   WEECHAT_HOOK_SIGNAL_STRING, WEECHAT_HOOK_SIGNAL_INT, WEECHAT_HOOK_SIGNAL_POINTER
 |========================================
diff --git a/src/core/wee-hook.c b/src/core/wee-hook.c
index 5080e7f..e5e19fd 100644
--- a/src/core/wee-hook.c
+++ b/src/core/wee-hook.c
@@ -1713,13 +1713,16 @@ hook_process_run (struct t_hook *hook_process)
 
 struct t_hook *
 hook_connect (struct t_weechat_plugin *plugin, const char *proxy,
-              const char *address, int port, int sock, int ipv6,
+              const char *address, int port, int ipv6, unsigned int retry,
               void *gnutls_sess, void *gnutls_cb, int gnutls_dhkey_size,
               const char *gnutls_priorities, const char *local_hostname,
               t_hook_callback_connect *callback, void *callback_data)
 {
     struct t_hook *new_hook;
     struct t_hook_connect *new_hook_connect;
+#ifdef HOOK_CONNECT_MAX_SOCKETS
+    int i;
+#endif
 
 #ifndef HAVE_GNUTLS
     /* make C compiler happy */
@@ -1729,7 +1732,7 @@ hook_connect (struct t_weechat_plugin *plugin, const char *proxy,
     (void) gnutls_priorities;
 #endif
 
-    if ((sock < 0) || !address || (port <= 0) || !callback)
+    if (!address || (port <= 0) || !callback)
         return NULL;
 
     new_hook = malloc (sizeof (*new_hook));
@@ -1750,8 +1753,9 @@ hook_connect (struct t_weechat_plugin *plugin, const char *proxy,
     new_hook_connect->proxy = (proxy) ? strdup (proxy) : NULL;
     new_hook_connect->address = strdup (address);
     new_hook_connect->port = port;
-    new_hook_connect->sock = sock;
+    new_hook_connect->sock = -1;
     new_hook_connect->ipv6 = ipv6;
+    new_hook_connect->retry = retry;
 #ifdef HAVE_GNUTLS
     new_hook_connect->gnutls_sess = gnutls_sess;
     new_hook_connect->gnutls_cb = gnutls_cb;
@@ -1763,6 +1767,8 @@ hook_connect (struct t_weechat_plugin *plugin, const char *proxy,
         strdup (local_hostname) : NULL;
     new_hook_connect->child_read = -1;
     new_hook_connect->child_write = -1;
+    new_hook_connect->child_recv = -1;
+    new_hook_connect->child_send = -1;
     new_hook_connect->child_pid = 0;
     new_hook_connect->hook_child_timer = NULL;
     new_hook_connect->hook_fd = NULL;
@@ -1770,6 +1776,13 @@ hook_connect (struct t_weechat_plugin *plugin, const char *proxy,
     new_hook_connect->handshake_hook_timer = NULL;
     new_hook_connect->handshake_fd_flags = 0;
     new_hook_connect->handshake_ip_address = NULL;
+#ifdef HOOK_CONNECT_MAX_SOCKETS
+    for (i = 0; i < HOOK_CONNECT_MAX_SOCKETS; i++)
+    {
+        new_hook_connect->sock_v4[i] = -1;
+        new_hook_connect->sock_v6[i] = -1;
+    }
+#endif
 
     hook_add_to_list (new_hook);
 
@@ -3166,6 +3179,19 @@ unhook (struct t_hook *hook)
                     close (HOOK_CONNECT(hook, child_read));
                 if (HOOK_CONNECT(hook, child_write) != -1)
                     close (HOOK_CONNECT(hook, child_write));
+                if (HOOK_CONNECT(hook, child_recv) != -1)
+                    close (HOOK_CONNECT(hook, child_recv));
+                if (HOOK_CONNECT(hook, child_send) != -1)
+                    close (HOOK_CONNECT(hook, child_send));
+#ifdef HOOK_CONNECT_MAX_SOCKETS
+                for (i = 0; i < HOOK_CONNECT_MAX_SOCKETS; i++)
+                {
+                    if (HOOK_CONNECT(hook, sock_v4[i]) != -1)
+                        close (HOOK_CONNECT(hook, sock_v4[i]));
+                    if (HOOK_CONNECT(hook, sock_v6[i]) != -1)
+                        close (HOOK_CONNECT(hook, sock_v6[i]));
+                }
+#endif
                 break;
             case HOOK_TYPE_PRINT:
                 if (HOOK_PRINT(hook, message))
@@ -3478,6 +3504,8 @@ hook_add_to_infolist_type (struct t_infolist *infolist, int type,
                         return 0;
                     if (!infolist_new_var_integer (ptr_item, "ipv6", HOOK_CONNECT(ptr_hook, ipv6)))
                         return 0;
+                    if (!infolist_new_var_integer (ptr_item, "retry", HOOK_CONNECT(ptr_hook, retry)))
+                        return 0;
 #ifdef HAVE_GNUTLS
                     if (!infolist_new_var_pointer (ptr_item, "gnutls_sess", HOOK_CONNECT(ptr_hook, gnutls_sess)))
                         return 0;
@@ -3492,6 +3520,10 @@ hook_add_to_infolist_type (struct t_infolist *infolist, int type,
                         return 0;
                     if (!infolist_new_var_integer (ptr_item, "child_write", HOOK_CONNECT(ptr_hook, child_write)))
                         return 0;
+                    if (!infolist_new_var_integer (ptr_item, "child_recv", HOOK_CONNECT(ptr_hook, child_recv)))
+                        return 0;
+                    if (!infolist_new_var_integer (ptr_item, "child_send", HOOK_CONNECT(ptr_hook, child_send)))
+                        return 0;
                     if (!infolist_new_var_integer (ptr_item, "child_pid", HOOK_CONNECT(ptr_hook, child_pid)))
                         return 0;
                     if (!infolist_new_var_pointer (ptr_item, "hook_child_timer", HOOK_CONNECT(ptr_hook, hook_child_timer)))
@@ -3886,12 +3918,20 @@ hook_print_log ()
                         log_printf ("    port. . . . . . . . . : %d",    HOOK_CONNECT(ptr_hook, port));
                         log_printf ("    sock. . . . . . . . . : %d",    HOOK_CONNECT(ptr_hook, sock));
                         log_printf ("    ipv6. . . . . . . . . : %d",    HOOK_CONNECT(ptr_hook, ipv6));
+                        log_printf ("    retry . . . . . . . . : %u",    HOOK_CONNECT(ptr_hook, retry));
 #ifdef HAVE_GNUTLS
                         log_printf ("    gnutls_sess . . . . . : 0x%lx", HOOK_CONNECT(ptr_hook, gnutls_sess));
                         log_printf ("    gnutls_cb . . . . . . : 0x%lx", HOOK_CONNECT(ptr_hook, gnutls_cb));
                         log_printf ("    gnutls_dhkey_size . . : %d",    HOOK_CONNECT(ptr_hook, gnutls_dhkey_size));
                         log_printf ("    gnutls_priorities . . : '%s'",  HOOK_CONNECT(ptr_hook, gnutls_priorities));
 #endif
+#ifdef HOOK_CONNECT_MAX_SOCKETS
+                        for (i = 0; i < HOOK_CONNECT_MAX_SOCKETS; i++)
+                        {
+                            log_printf ("    sock_v4[%d] . . . . . : '%d'",  HOOK_CONNECT(ptr_hook, sock_v4[i]));
+                            log_printf ("    sock_v6[%d] . . . . . : '%d'",  HOOK_CONNECT(ptr_hook, sock_v6[i]));
+                        }
+#endif
                         log_printf ("    local_hostname. . . . : '%s'",  HOOK_CONNECT(ptr_hook, local_hostname));
                         log_printf ("    child_read. . . . . . : %d",    HOOK_CONNECT(ptr_hook, child_read));
                         log_printf ("    child_write . . . . . : %d",    HOOK_CONNECT(ptr_hook, child_write));
diff --git a/src/core/wee-hook.h b/src/core/wee-hook.h
index c1375d3..f47b5df 100644
--- a/src/core/wee-hook.h
+++ b/src/core/wee-hook.h
@@ -26,6 +26,18 @@
 #include <gnutls/gnutls.h>
 #endif
 
+#ifdef __CYGWIN__
+/*
+ * For the connect hook, when this is defined an array of sockets will
+ * be passed from the parent process to the child process instead of using
+ * SCM_RIGHTS to pass a socket back from the child process to parent process.
+ *
+ * This allows connections to work on Windows but it limits the number of
+ * IPs that can be attempted each time.
+ */
+#define HOOK_CONNECT_MAX_SOCKETS 4
+#endif
+
 struct t_gui_bar;
 struct t_gui_buffer;
 struct t_gui_line;
@@ -212,7 +224,7 @@ struct t_hook_process
 /* hook connect */
 
 typedef int (t_hook_callback_connect)(void *data, int status,
-                                      int gnutls_rc,
+                                      int gnutls_rc, int sock,
                                       const char *error,
                                       const char *ip_address);
 
@@ -235,8 +247,9 @@ struct t_hook_connect
     char *proxy;                       /* proxy (optional)                  */
     char *address;                     /* peer address                      */
     int port;                          /* peer port                         */
-    int sock;                          /* socket (created by caller)        */
-    int ipv6;                          /* IPv6 connection ?                 */
+    int ipv6;                          /* use IPv6                          */
+    int sock;                          /* socket (set when connected)       */
+    unsigned int retry;                /* retry count                       */
 #ifdef HAVE_GNUTLS
     gnutls_session_t *gnutls_sess;     /* GnuTLS session (SSL connection)   */
     gnutls_callback_t *gnutls_cb;      /* GnuTLS callback during handshake  */
@@ -246,6 +259,8 @@ struct t_hook_connect
     char *local_hostname;              /* force local hostname (optional)   */
     int child_read;                    /* to read data in pipe from child   */
     int child_write;                   /* to write data in pipe for child   */
+    int child_recv;                    /* to read data from child socket    */
+    int child_send;                    /* to write data to child socket     */
     pid_t child_pid;                   /* pid of child process (connecting) */
     struct t_hook *hook_child_timer;   /* timer for child process timeout   */
     struct t_hook *hook_fd;            /* pointer to fd hook                */
@@ -253,6 +268,10 @@ struct t_hook_connect
     struct t_hook *handshake_hook_timer; /* timer for handshake timeout     */
     int handshake_fd_flags;            /* socket flags saved for handshake  */
     char *handshake_ip_address;        /* ip address (used for handshake)   */
+#ifdef HOOK_CONNECT_MAX_SOCKETS
+    int sock_v4[HOOK_CONNECT_MAX_SOCKETS];  /* IPv4 sockets for connecting  */
+    int sock_v6[HOOK_CONNECT_MAX_SOCKETS];  /* IPv6 sockets for connecting  */
+#endif
 };
 
 /* hook print */
@@ -457,7 +476,7 @@ extern struct t_hook *hook_process_hashtable (struct t_weechat_plugin *plugin,
                                               void *callback_data);
 extern struct t_hook *hook_connect (struct t_weechat_plugin *plugin,
                                     const char *proxy, const char *address,
-                                    int port, int sock, int ipv6,
+                                    int port, int ipv6, unsigned int retry,
                                     void *gnutls_session, void *gnutls_cb,
                                     int gnutls_dhkey_size,
                                     const char *gnutls_priorities,
diff --git a/src/core/wee-network.c b/src/core/wee-network.c
index a37be51..e6e98e6 100644
--- a/src/core/wee-network.c
+++ b/src/core/wee-network.c
@@ -38,6 +38,7 @@
 #include <netdb.h>
 #include <errno.h>
 #include <gcrypt.h>
+#include <sys/time.h>
 
 #ifdef HAVE_GNUTLS
 #include <gnutls/gnutls.h>
@@ -645,20 +646,45 @@ void
 network_connect_child (struct t_hook *hook_connect)
 {
     struct t_proxy *ptr_proxy;
-    struct addrinfo hints, *res, *res_local, *ptr_res;
+    struct addrinfo hints, *res_local, *res_remote, *ptr_res, *ptr_loc;
+    char port[NI_MAXSERV + 1];
     char status_str[2], *ptr_address, *status_with_string;
-    char ipv4_address[INET_ADDRSTRLEN + 1], ipv6_address[INET6_ADDRSTRLEN + 1];
+    char remote_address[NI_MAXHOST + 1];
     char status_without_string[1 + 5 + 1];
     const char *error;
     int rc, length, num_written;
+    int sock, set, flags;
+#ifdef HOOK_CONNECT_MAX_SOCKETS
+    int j;
+#else
+    struct msghdr msg;
+    struct cmsghdr *cmsg;
+    char msg_buf[CMSG_SPACE(sizeof (sock))];
+#endif
+    /*
+     * indicates that something is wrong with whichever group of
+     * servers is being tried first after connecting, so start at
+     * a different offset to increase the chance of success
+     */
+    unsigned int retry, rand_num, i;
+    unsigned int num_groups, tmp_num_groups, num_hosts, tmp_host;
+    struct addrinfo **res_reorder;
+    int last_af;
+    struct timeval tv_time;
 
-    res = NULL;
     res_local = NULL;
+    res_remote = NULL;
+    res_reorder = NULL;
+    port[0] = '\0';
 
     status_str[1] = '\0';
+    status_with_string = NULL;
 
     ptr_address = NULL;
 
+    gettimeofday (&tv_time, NULL);
+    srand ((tv_time.tv_sec * tv_time.tv_usec) ^ getpid ());
+
     ptr_proxy = NULL;
     if (HOOK_CONNECT(hook_connect, proxy)
         && HOOK_CONNECT(hook_connect, proxy)[0])
@@ -672,18 +698,86 @@ network_connect_child (struct t_hook *hook_connect)
             num_written = write (HOOK_CONNECT(hook_connect, child_write),
                                  status_without_string, strlen (status_without_string));
             (void) num_written;
-            return;
+            goto end;
         }
     }
 
+    /* get info about peer */
+    memset (&hints, 0, sizeof (hints));
+    hints.ai_socktype = SOCK_STREAM;
+#ifdef AI_ADDRCONFIG
+    hints.ai_flags = AI_ADDRCONFIG;
+#endif
     if (ptr_proxy)
     {
-        /* get info about peer */
-        memset (&hints, 0, sizeof (hints));
         hints.ai_family = (CONFIG_BOOLEAN(ptr_proxy->options[PROXY_OPTION_IPV6])) ?
-            AF_INET6 : AF_INET;
+            AF_UNSPEC : AF_INET;
+        snprintf (port, sizeof (port), "%u", CONFIG_INTEGER(ptr_proxy->options[PROXY_OPTION_PORT]));
+        rc = getaddrinfo (CONFIG_STRING(ptr_proxy->options[PROXY_OPTION_ADDRESS]),
+                          port, &hints, &res_remote);
+    }
+    else
+    {
+        hints.ai_family = HOOK_CONNECT(hook_connect, ipv6) ? AF_UNSPEC : AF_INET;
+        snprintf (port, sizeof (port), "%u", HOOK_CONNECT(hook_connect, port));
+        rc = getaddrinfo (HOOK_CONNECT(hook_connect, address), port, &hints, &res_remote);
+    }
+
+    if (rc != 0)
+    {
+        /* address not found */
+        status_with_string = NULL;
+        error = gai_strerror (rc);
+        if (error)
+        {
+            length = 1 + 5 + strlen (error) + 1;
+            status_with_string = malloc (length);
+            if (status_with_string)
+            {
+                snprintf (status_with_string, length, "%c%05d%s",
+                          '0' + WEECHAT_HOOK_CONNECT_ADDRESS_NOT_FOUND,
+                          (int)strlen (error), error);
+            }
+        }
+        if (status_with_string)
+        {
+            num_written = write (HOOK_CONNECT(hook_connect, child_write),
+                                 status_with_string, strlen (status_with_string));
+        }
+        else
+        {
+            snprintf (status_without_string, sizeof (status_without_string),
+                      "%c00000", '0' + WEECHAT_HOOK_CONNECT_ADDRESS_NOT_FOUND);
+            num_written = write (HOOK_CONNECT(hook_connect, child_write),
+                                 status_without_string, strlen (status_without_string));
+        }
+        (void) num_written;
+        goto end;
+    }
+
+    if (!res_remote)
+    {
+        /* address not found */
+        snprintf (status_without_string, sizeof (status_without_string),
+                  "%c00000", '0' + WEECHAT_HOOK_CONNECT_ADDRESS_NOT_FOUND);
+        num_written = write (HOOK_CONNECT(hook_connect, child_write),
+                             status_without_string, strlen (status_without_string));
+        (void) num_written;
+        goto end;
+    }
+
+    /* set local hostname/IP if asked by user */
+    if (HOOK_CONNECT(hook_connect, local_hostname)
+        && HOOK_CONNECT(hook_connect, local_hostname[0]))
+    {
+        memset (&hints, 0, sizeof (hints));
+        hints.ai_family = AF_UNSPEC;
         hints.ai_socktype = SOCK_STREAM;
-        rc = getaddrinfo (CONFIG_STRING(ptr_proxy->options[PROXY_OPTION_ADDRESS]), NULL, &hints, &res);
+#ifdef AI_ADDRCONFIG
+        hints.ai_flags = AI_ADDRCONFIG;
+#endif
+        rc = getaddrinfo (HOOK_CONNECT(hook_connect, local_hostname),
+                          NULL, &hints, &res_local);
         if (rc != 0)
         {
             /* address not found */
@@ -696,7 +790,7 @@ network_connect_child (struct t_hook *hook_connect)
                 if (status_with_string)
                 {
                     snprintf (status_with_string, length, "%c%05d%s",
-                              '0' + WEECHAT_HOOK_CONNECT_ADDRESS_NOT_FOUND,
+                              '0' + WEECHAT_HOOK_CONNECT_LOCAL_HOSTNAME_ERROR,
                               (int)strlen (error), error);
                 }
             }
@@ -708,254 +802,256 @@ network_connect_child (struct t_hook *hook_connect)
             else
             {
                 snprintf (status_without_string, sizeof (status_without_string),
-                          "%c00000", '0' + WEECHAT_HOOK_CONNECT_ADDRESS_NOT_FOUND);
+                          "%c00000", '0' + WEECHAT_HOOK_CONNECT_LOCAL_HOSTNAME_ERROR);
                 num_written = write (HOOK_CONNECT(hook_connect, child_write),
                                      status_without_string, strlen (status_without_string));
             }
-            if (status_with_string)
-                free (status_with_string);
             (void) num_written;
-            return;
-        }
-        if (!res)
-        {
-            /* adddress not found */
-            snprintf (status_without_string, sizeof (status_without_string),
-                      "%c00000", '0' + WEECHAT_HOOK_CONNECT_ADDRESS_NOT_FOUND);
-            num_written = write (HOOK_CONNECT(hook_connect, child_write),
-                                 status_without_string, strlen (status_without_string));
-            (void) num_written;
-            return;
+            goto end;
         }
-        if ((CONFIG_BOOLEAN(ptr_proxy->options[PROXY_OPTION_IPV6]) && (res->ai_family != AF_INET6))
-            || ((!CONFIG_BOOLEAN(ptr_proxy->options[PROXY_OPTION_IPV6]) && (res->ai_family != AF_INET))))
+
+        if (!res_local)
         {
-            /* IP address not found */
+            /* address not found */
             snprintf (status_without_string, sizeof (status_without_string),
-                      "%c00000", '0' + WEECHAT_HOOK_CONNECT_IP_ADDRESS_NOT_FOUND);
+                      "%c00000", '0' + WEECHAT_HOOK_CONNECT_LOCAL_HOSTNAME_ERROR);
             num_written = write (HOOK_CONNECT(hook_connect, child_write),
                                  status_without_string, strlen (status_without_string));
             (void) num_written;
-            freeaddrinfo (res);
-            return;
+            goto end;
         }
+    }
 
-        if (CONFIG_BOOLEAN(ptr_proxy->options[PROXY_OPTION_IPV6]))
-            ((struct sockaddr_in6 *)(res->ai_addr))->sin6_port = htons (CONFIG_INTEGER(ptr_proxy->options[PROXY_OPTION_PORT]));
-        else
-            ((struct sockaddr_in *)(res->ai_addr))->sin_port = htons (CONFIG_INTEGER(ptr_proxy->options[PROXY_OPTION_PORT]));
+    /* res_local != NULL now indicates that bind() is required */
 
-        /* connect to peer */
-        if (!network_connect (HOOK_CONNECT(hook_connect, sock),
-                              res->ai_addr, res->ai_addrlen))
-        {
-            /* connection refused */
-            snprintf (status_without_string, sizeof (status_without_string),
-                      "%c00000", '0' + WEECHAT_HOOK_CONNECT_CONNECTION_REFUSED);
-            num_written = write (HOOK_CONNECT(hook_connect, child_write),
-                                 status_without_string, strlen (status_without_string));
-            (void) num_written;
-            freeaddrinfo (res);
-            return;
-        }
+    /*
+     * count all the groups of hosts by tracking family, e.g.
+     * 0 = [2001:db8::1, 2001:db8::2,
+     * 1 =  192.0.2.1, 192.0.2.2,
+     * 2 =  2002:c000:201::1, 2002:c000:201::2]
+     */
+    last_af = AF_UNSPEC;
+    num_groups = 0;
+    num_hosts = 0;
+    for (ptr_res = res_remote; ptr_res; ptr_res = ptr_res->ai_next)
+    {
+        if (ptr_res->ai_family != last_af)
+            if (last_af != AF_UNSPEC)
+                num_groups++;
 
-        if (!network_pass_proxy (HOOK_CONNECT(hook_connect, proxy),
-                                 HOOK_CONNECT(hook_connect, sock),
-                                 HOOK_CONNECT(hook_connect, address),
-                                 HOOK_CONNECT(hook_connect, port)))
-        {
-            /* proxy fails to connect to peer */
-            snprintf (status_without_string, sizeof (status_without_string),
-                      "%c00000", '0' + WEECHAT_HOOK_CONNECT_PROXY_ERROR);
-            num_written = write (HOOK_CONNECT(hook_connect, child_write),
-                                 status_without_string, strlen (status_without_string));
-            (void) num_written;
-            freeaddrinfo (res);
-            return;
-        }
+        num_hosts++;
+        last_af = ptr_res->ai_family;
+    }
+    if (last_af != AF_UNSPEC)
+        num_groups++;
 
-        status_str[0] = '0' + WEECHAT_HOOK_CONNECT_OK;
+    res_reorder = malloc (sizeof (*res_reorder) * num_hosts);
+    if (!res_reorder)
+    {
+        snprintf (status_without_string, sizeof (status_without_string),
+                  "%c00000", '0' + WEECHAT_HOOK_CONNECT_MEMORY_ERROR);
+        num_written = write (HOOK_CONNECT(hook_connect, child_write),
+                             status_without_string, strlen (status_without_string));
+        (void) num_written;
+        goto end;
     }
-    else
+
+    /* reorder groups */
+    retry = HOOK_CONNECT(hook_connect, retry);
+    if (num_groups > 0)
     {
-        /* set local hostname/IP if asked by user */
-        if (HOOK_CONNECT(hook_connect, local_hostname)
-            && HOOK_CONNECT(hook_connect, local_hostname[0]))
+        retry %= num_groups;
+        i = 0;
+
+        last_af = AF_UNSPEC;
+        tmp_num_groups = 0;
+        tmp_host = i; /* start of current group */
+
+        /* top of list */
+        for (ptr_res = res_remote; ptr_res; ptr_res = ptr_res->ai_next)
         {
-            memset (&hints, 0, sizeof(hints));
-            hints.ai_family = (HOOK_CONNECT(hook_connect, ipv6)) ? AF_INET6 : AF_INET;
-            hints.ai_socktype = SOCK_STREAM;
-            rc = getaddrinfo (HOOK_CONNECT(hook_connect, local_hostname),
-                              NULL, &hints, &res_local);
-            if (rc != 0)
+            if (ptr_res->ai_family != last_af)
             {
-                /* fails to set local hostname/IP */
-                status_with_string = NULL;
-                error = gai_strerror (rc);
-                if (error)
-                {
-                    length = 1 + 5 + strlen (error) + 1;
-                    status_with_string = malloc (length);
-                    if (status_with_string)
-                    {
-                        snprintf (status_with_string, length, "%c%05d%s",
-                                  '0' + WEECHAT_HOOK_CONNECT_LOCAL_HOSTNAME_ERROR,
-                                  (int)strlen (error), error);
-                    }
-                }
-                if (status_with_string)
-                {
-                    num_written = write (HOOK_CONNECT(hook_connect, child_write),
-                                         status_with_string, strlen (status_with_string));
-                }
+                if (last_af != AF_UNSPEC)
+                    tmp_num_groups++;
+
+                tmp_host = i;
+            }
+
+            if (tmp_num_groups >= retry)
+            {
+                /* shuffle while adding */
+                rand_num = tmp_host + (rand() % ((i + 1) - tmp_host));
+                if (rand_num == i)
+                    res_reorder[i++] = ptr_res;
                 else
                 {
-                    snprintf (status_without_string, sizeof (status_without_string),
-                              "%c00000", '0' + WEECHAT_HOOK_CONNECT_LOCAL_HOSTNAME_ERROR);
-                    num_written = write (HOOK_CONNECT(hook_connect, child_write),
-                                         status_without_string, strlen (status_without_string));
+                    res_reorder[i++] = res_reorder[rand_num];
+                    res_reorder[rand_num] = ptr_res;
                 }
-                if (status_with_string)
-                    free (status_with_string);
-                (void) num_written;
-                if (res_local)
-                    freeaddrinfo (res_local);
-                return;
             }
-            else if (!res_local
-                     || (HOOK_CONNECT(hook_connect, ipv6)
-                         && (res_local->ai_family != AF_INET6))
-                     || ((!HOOK_CONNECT(hook_connect, ipv6)
-                          && (res_local->ai_family != AF_INET))))
+
+            last_af = ptr_res->ai_family;
+        }
+
+        last_af = AF_UNSPEC;
+        tmp_num_groups = 0;
+        tmp_host = i; /* start of current group */
+
+        /* remainder of list */
+        for (ptr_res = res_remote; ptr_res; ptr_res = ptr_res->ai_next)
+        {
+            if (ptr_res->ai_family != last_af)
             {
-                /* fails to set local hostname/IP */
-                snprintf (status_without_string, sizeof (status_without_string),
-                          "%c00000", '0' + WEECHAT_HOOK_CONNECT_LOCAL_HOSTNAME_ERROR);
-                num_written = write (HOOK_CONNECT(hook_connect, child_write),
-                                     status_without_string, strlen (status_without_string));
-                (void) num_written;
-                if (res_local)
-                    freeaddrinfo (res_local);
-                return;
+                if (last_af != AF_UNSPEC)
+                    tmp_num_groups++;
+
+                tmp_host = i;
             }
-            if (bind (HOOK_CONNECT(hook_connect, sock),
-                      res_local->ai_addr, res_local->ai_addrlen) < 0)
+
+            if (tmp_num_groups < retry)
             {
-                /* fails to set local hostname/IP */
-                snprintf (status_without_string, sizeof (status_without_string),
-                          "%c00000", '0' + WEECHAT_HOOK_CONNECT_LOCAL_HOSTNAME_ERROR);
-                num_written = write (HOOK_CONNECT(hook_connect, child_write),
-                                     status_without_string, strlen (status_without_string));
-                (void) num_written;
-                if (res_local)
-                    freeaddrinfo (res_local);
-                return;
+                /* shuffle while adding */
+                rand_num = tmp_host + (rand() % ((i + 1) - tmp_host));
+                if (rand_num == i)
+                    res_reorder[i++] = ptr_res;
+                else
+                {
+                    res_reorder[i++] = res_reorder[rand_num];
+                    res_reorder[rand_num] = ptr_res;
+                }
             }
+            else
+                break;
+
+            last_af = ptr_res->ai_family;
         }
+    }
+    else
+    {
+        /* no IP addresses found (all AF_UNSPEC) */
+        snprintf (status_without_string, sizeof (status_without_string),
+                  "%c00000", '0' + WEECHAT_HOOK_CONNECT_IP_ADDRESS_NOT_FOUND);
+        num_written = write (HOOK_CONNECT(hook_connect, child_write),
+                             status_without_string, strlen (status_without_string));
+        (void) num_written;
+        goto end;
+    }
 
-        /* get info about peer */
-        memset (&hints, 0, sizeof(hints));
-        hints.ai_family = (HOOK_CONNECT(hook_connect, ipv6)) ? AF_INET6 : AF_INET;
-        hints.ai_socktype = SOCK_STREAM;
-        rc = getaddrinfo (HOOK_CONNECT(hook_connect, address),
-                          NULL, &hints, &res);
-        if (rc != 0)
+    status_str[0] = '0' + WEECHAT_HOOK_CONNECT_IP_ADDRESS_NOT_FOUND;
+
+    /* try all IP addresses found, stop when connection is ok */
+    sock = -1;
+    for (i = 0; i < num_hosts; i++)
+    {
+        ptr_res = res_reorder[i];
+
+#ifdef HOOK_CONNECT_MAX_SOCKETS
+        /* use pre-created socket pool */
+        sock = -1;
+        for (j = 0; j < HOOK_CONNECT_MAX_SOCKETS; j++)
         {
-            status_with_string = NULL;
-            error = gai_strerror (rc);
-            if (error)
+            if (ptr_res->ai_family == AF_INET)
             {
-                length = 1 + 5 + strlen (error) + 1;
-                status_with_string = malloc (length);
-                if (status_with_string)
+                sock = HOOK_CONNECT(hook_connect, sock_v4[j]);
+                if (sock != -1)
                 {
-                    snprintf (status_with_string, length, "%c%05d%s",
-                              '0' + WEECHAT_HOOK_CONNECT_ADDRESS_NOT_FOUND,
-                              (int)strlen (error), error);
+                    HOOK_CONNECT(hook_connect, sock_v4[j]) = -1;
+                    break;
                 }
             }
-            if (status_with_string)
-            {
-                num_written = write (HOOK_CONNECT(hook_connect, child_write),
-                                     status_with_string, strlen (status_with_string));
-            }
-            else
+            else if (ptr_res->ai_family == AF_INET6)
             {
-                snprintf (status_without_string, sizeof (status_without_string),
-                          "%c00000", '0' + WEECHAT_HOOK_CONNECT_ADDRESS_NOT_FOUND);
-                num_written = write (HOOK_CONNECT(hook_connect, child_write),
-                                     status_without_string, strlen (status_without_string));
+                sock = HOOK_CONNECT(hook_connect, sock_v6[j]);
+                if (sock != -1)
+                {
+                    HOOK_CONNECT(hook_connect, sock_v6[j]) = -1;
+                    break;
+                }
             }
-            if (status_with_string)
-                free (status_with_string);
-            (void) num_written;
-            if (res)
-                freeaddrinfo (res);
-            if (res_local)
-                freeaddrinfo (res_local);
-            return;
         }
-        else if (!res)
+        if (sock < 0)
+            continue;
+#else
+        /* create a socket */
+        sock = socket (ptr_res->ai_family,
+                       ptr_res->ai_socktype,
+                       ptr_res->ai_protocol);
+#endif
+        if (sock < 0)
         {
-            /* address not found */
-            snprintf (status_without_string, sizeof (status_without_string),
-                      "%c00000", '0' + WEECHAT_HOOK_CONNECT_ADDRESS_NOT_FOUND);
-            num_written = write (HOOK_CONNECT(hook_connect, child_write),
-                                 status_without_string, strlen (status_without_string));
-            (void) num_written;
-            if (res)
-                freeaddrinfo (res);
-            if (res_local)
-                freeaddrinfo (res_local);
-            return;
+            status_str[0] = '0' + WEECHAT_HOOK_CONNECT_SOCKET_ERROR;
+            continue;
         }
 
-        status_str[0] = '0' + WEECHAT_HOOK_CONNECT_IP_ADDRESS_NOT_FOUND;
+        /* set SO_REUSEADDR option for socket */
+        set = 1;
+        setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, (void *) &set, sizeof (set));
 
-        /* try all IP addresses found, stop when connection is ok */
-        for (ptr_res = res; ptr_res; ptr_res = ptr_res->ai_next)
+        /* set SO_KEEPALIVE option for socket */
+        set = 1;
+        setsockopt (sock, SOL_SOCKET, SO_KEEPALIVE, (void *) &set, sizeof (set));
+
+        /* set flag O_NONBLOCK on socket */
+        flags = fcntl (sock, F_GETFL);
+        if (flags == -1)
+            flags = 0;
+        fcntl (sock, F_SETFL, flags | O_NONBLOCK);
+
+        if (res_local)
         {
-            /* skip IP address if it's not good family */
-            if ((HOOK_CONNECT(hook_connect, ipv6) && (ptr_res->ai_family != AF_INET6))
-                || ((!HOOK_CONNECT(hook_connect, ipv6) && (ptr_res->ai_family != AF_INET))))
-                continue;
+            rc = -1;
 
-            /* connect to peer */
-            if (HOOK_CONNECT(hook_connect, ipv6))
-                ((struct sockaddr_in6 *)(ptr_res->ai_addr))->sin6_port =
-                    htons (HOOK_CONNECT(hook_connect, port));
-            else
-                ((struct sockaddr_in *)(ptr_res->ai_addr))->sin_port =
-                    htons (HOOK_CONNECT(hook_connect, port));
+            /* bind local hostname/IP if asked by user */
+            for (ptr_loc = res_local; ptr_loc; ptr_loc = ptr_loc->ai_next)
+            {
+                if (ptr_loc->ai_family != ptr_res->ai_family)
+                    continue;
+
+                rc = bind (sock, ptr_loc->ai_addr, ptr_loc->ai_addrlen);
+                if (rc < 0)
+                    continue;
+            }
 
-            if (network_connect (HOOK_CONNECT(hook_connect, sock),
-                                 ptr_res->ai_addr, ptr_res->ai_addrlen))
+            if (rc < 0)
             {
-                status_str[0] = '0' + WEECHAT_HOOK_CONNECT_OK;
-                if (HOOK_CONNECT(hook_connect, ipv6))
-                {
-                    if (inet_ntop (AF_INET6,
-                                   &((struct sockaddr_in6 *)(ptr_res->ai_addr))->sin6_addr,
-                                   ipv6_address,
-                                   INET6_ADDRSTRLEN))
-                    {
-                        ptr_address = ipv6_address;
-                    }
-                }
-                else
-                {
-                    if (inet_ntop (AF_INET,
-                                   &((struct sockaddr_in *)(ptr_res->ai_addr))->sin_addr,
-                                   ipv4_address,
-                                   INET_ADDRSTRLEN))
-                    {
-                        ptr_address = ipv4_address;
-                    }
-                }
-                break;
+                status_str[0] = '0' + WEECHAT_HOOK_CONNECT_LOCAL_HOSTNAME_ERROR;
+                close (sock);
+                sock = -1;
+                continue;
             }
-            else
-                status_str[0] = '0' + WEECHAT_HOOK_CONNECT_CONNECTION_REFUSED;
+        }
+
+        /* connect to peer */
+        if (network_connect (sock, ptr_res->ai_addr, ptr_res->ai_addrlen))
+        {
+            status_str[0] = '0' + WEECHAT_HOOK_CONNECT_OK;
+            rc = getnameinfo (ptr_res->ai_addr, ptr_res->ai_addrlen,
+                              remote_address, sizeof (remote_address),
+                              NULL, 0, NI_NUMERICHOST);
+            if (rc == 0)
+                ptr_address = remote_address;
+            break;
+        }
+        else
+        {
+            status_str[0] = '0' + WEECHAT_HOOK_CONNECT_CONNECTION_REFUSED;
+            close (sock);
+            sock = -1;
+        }
+    }
+
+    HOOK_CONNECT(hook_connect, sock) = sock;
+
+    if (ptr_proxy && status_str[0] == '0' + WEECHAT_HOOK_CONNECT_OK)
+    {
+        if (!network_pass_proxy (HOOK_CONNECT(hook_connect, proxy),
+                                 HOOK_CONNECT(hook_connect, sock),
+                                 HOOK_CONNECT(hook_connect, address),
+                                 HOOK_CONNECT(hook_connect, port)))
+        {
+            /* proxy fails to connect to peer */
+            status_str[0] = '0' + WEECHAT_HOOK_CONNECT_PROXY_ERROR;
         }
     }
 
@@ -978,7 +1074,6 @@ network_connect_child (struct t_hook *hook_connect)
             num_written = write (HOOK_CONNECT(hook_connect, child_write),
                                  status_with_string, strlen (status_with_string));
             (void) num_written;
-            free (status_with_string);
         }
         else
         {
@@ -988,6 +1083,24 @@ network_connect_child (struct t_hook *hook_connect)
                                  status_without_string, strlen (status_without_string));
             (void) num_written;
         }
+
+        /* send the socket to the parent process */
+#ifndef HOOK_CONNECT_MAX_SOCKETS
+        memset (&msg, 0, sizeof (msg));
+        msg.msg_control = msg_buf;
+        msg.msg_controllen = sizeof (msg_buf);
+        cmsg = CMSG_FIRSTHDR(&msg);
+        cmsg->cmsg_level = SOL_SOCKET;
+        cmsg->cmsg_type = SCM_RIGHTS;
+        cmsg->cmsg_len = CMSG_LEN(sizeof (sock));
+        memcpy(CMSG_DATA(cmsg), &sock, sizeof (sock));
+        msg.msg_controllen = cmsg->cmsg_len;
+        num_written = sendmsg (HOOK_CONNECT(hook_connect, child_send), &msg, 0);
+        (void) num_written;
+#else
+        num_written = write (HOOK_CONNECT(hook_connect, child_write), &sock, sizeof (sock));
+        (void) num_written;
+#endif
     }
     else
     {
@@ -998,10 +1111,15 @@ network_connect_child (struct t_hook *hook_connect)
         (void) num_written;
     }
 
-    if (res)
-        freeaddrinfo (res);
+end:
+    if (status_with_string)
+        free (status_with_string);
+    if (res_reorder)
+        free (res_reorder);
     if (res_local)
         freeaddrinfo (res_local);
+    if (res_remote)
+        freeaddrinfo (res_remote);
 }
 
 /*
@@ -1023,7 +1141,7 @@ network_connect_child_timer_cb (void *arg_hook_connect, int remaining_calls)
     (void) (HOOK_CONNECT(hook_connect, callback))
         (hook_connect->callback_data,
          WEECHAT_HOOK_CONNECT_TIMEOUT,
-         0, NULL, NULL);
+         0, -1, NULL, NULL);
     unhook (hook_connect);
 
     return WEECHAT_RC_OK;
@@ -1066,8 +1184,8 @@ network_connect_gnutls_handshake_fd_cb (void *arg_hook_connect, int fd)
     {
         (void) (HOOK_CONNECT(hook_connect, callback))
             (hook_connect->callback_data,
-             WEECHAT_HOOK_CONNECT_GNUTLS_HANDSHAKE_ERROR,
-             rc,
+             WEECHAT_HOOK_CONNECT_GNUTLS_HANDSHAKE_ERROR, rc,
+             HOOK_CONNECT(hook_connect, sock),
              gnutls_strerror (rc),
              HOOK_CONNECT(hook_connect, handshake_ip_address));
         unhook (hook_connect);
@@ -1086,8 +1204,8 @@ network_connect_gnutls_handshake_fd_cb (void *arg_hook_connect, int fd)
         {
             (void) (HOOK_CONNECT(hook_connect, callback))
                 (hook_connect->callback_data,
-                 WEECHAT_HOOK_CONNECT_GNUTLS_HANDSHAKE_ERROR,
-                 rc,
+                 WEECHAT_HOOK_CONNECT_GNUTLS_HANDSHAKE_ERROR, rc,
+                 HOOK_CONNECT(hook_connect, sock),
                  "Error in the certificate.",
                  HOOK_CONNECT(hook_connect, handshake_ip_address));
             unhook (hook_connect);
@@ -1096,8 +1214,10 @@ network_connect_gnutls_handshake_fd_cb (void *arg_hook_connect, int fd)
 #endif
         unhook (HOOK_CONNECT(hook_connect, handshake_hook_fd));
         (void) (HOOK_CONNECT(hook_connect, callback))
-                (hook_connect->callback_data, WEECHAT_HOOK_CONNECT_OK, 0, NULL,
-                 HOOK_CONNECT(hook_connect, handshake_ip_address));
+                (hook_connect->callback_data,
+                 WEECHAT_HOOK_CONNECT_OK, 0,
+                 HOOK_CONNECT(hook_connect, sock),
+                 NULL, HOOK_CONNECT(hook_connect, handshake_ip_address));
         unhook (hook_connect);
     }
 
@@ -1127,6 +1247,7 @@ network_connect_gnutls_handshake_timer_cb (void *arg_hook_connect,
             (hook_connect->callback_data,
              WEECHAT_HOOK_CONNECT_GNUTLS_HANDSHAKE_ERROR,
              GNUTLS_E_EXPIRED,
+             HOOK_CONNECT(hook_connect, sock),
              gnutls_strerror (GNUTLS_E_EXPIRED),
              HOOK_CONNECT(hook_connect, handshake_ip_address));
     unhook (hook_connect);
@@ -1149,6 +1270,14 @@ network_connect_child_read_cb (void *arg_hook_connect, int fd)
 #ifdef HAVE_GNUTLS
     int rc, direction;
 #endif
+    int sock;
+#ifdef HOOK_CONNECT_MAX_SOCKETS
+    int i;
+#else
+    struct msghdr msg;
+    struct cmsghdr *cmsg;
+    char msg_buf[CMSG_SPACE(sizeof (sock))];
+#endif
 
     /* make C compiler happy */
     (void) fd;
@@ -1157,10 +1286,11 @@ network_connect_child_read_cb (void *arg_hook_connect, int fd)
 
     cb_error = NULL;
     cb_ip_address = NULL;
+    sock = -1;
 
     num_read = read (HOOK_CONNECT(hook_connect, child_read),
                      buffer, sizeof (buffer));
-    if (num_read > 0)
+    if (num_read == sizeof (buffer))
     {
         if (buffer[0] - '0' == WEECHAT_HOOK_CONNECT_OK)
         {
@@ -1189,6 +1319,41 @@ network_connect_child_read_cb (void *arg_hook_connect, int fd)
                     }
                 }
             }
+
+#ifndef HOOK_CONNECT_MAX_SOCKETS
+            /* receive the socket from the child process */
+            memset (&msg, 0, sizeof (msg));
+            msg.msg_control = msg_buf;
+            msg.msg_controllen = sizeof (msg_buf);
+
+            if (recvmsg (HOOK_CONNECT(hook_connect, child_recv), &msg, 0) >= 0)
+            {
+                cmsg = CMSG_FIRSTHDR(&msg);
+                if (cmsg != NULL
+                    && cmsg->cmsg_level == SOL_SOCKET
+                    && cmsg->cmsg_type == SCM_RIGHTS
+                    && cmsg->cmsg_len >= sizeof (sock))
+                {
+                    memcpy(&sock, CMSG_DATA(cmsg), sizeof (sock));
+                }
+            }
+#else
+            num_read = read (HOOK_CONNECT(hook_connect, child_read), &sock, sizeof (sock));
+            (void) num_read;
+
+            /* prevent unhook process from closing the socket */
+            for (i = 0; i < HOOK_CONNECT_MAX_SOCKETS; i++)
+            {
+                if (HOOK_CONNECT(hook_connect, sock_v4[i]) == sock)
+                    HOOK_CONNECT(hook_connect, sock_v4[i]) = -1;
+
+                if (HOOK_CONNECT(hook_connect, sock_v6[i]) == sock)
+                    HOOK_CONNECT(hook_connect, sock_v6[i]) = -1;
+            }
+#endif
+
+            HOOK_CONNECT(hook_connect, sock) = sock;
+
 #ifdef HAVE_GNUTLS
             if (HOOK_CONNECT(hook_connect, gnutls_sess))
             {
@@ -1240,7 +1405,7 @@ network_connect_child_read_cb (void *arg_hook_connect, int fd)
                     (void) (HOOK_CONNECT(hook_connect, callback))
                         (hook_connect->callback_data,
                          WEECHAT_HOOK_CONNECT_GNUTLS_HANDSHAKE_ERROR,
-                         rc,
+                         rc, sock,
                          gnutls_strerror (rc),
                          cb_ip_address);
                     unhook (hook_connect);
@@ -1261,7 +1426,7 @@ network_connect_child_read_cb (void *arg_hook_connect, int fd)
                     (void) (HOOK_CONNECT(hook_connect, callback))
                         (hook_connect->callback_data,
                          WEECHAT_HOOK_CONNECT_GNUTLS_HANDSHAKE_ERROR,
-                         rc,
+                         rc, sock,
                          "Error in the certificate.",
                          cb_ip_address);
                     unhook (hook_connect);
@@ -1303,7 +1468,14 @@ network_connect_child_read_cb (void *arg_hook_connect, int fd)
         }
         (void) (HOOK_CONNECT(hook_connect, callback))
             (hook_connect->callback_data, buffer[0] - '0', 0,
-             cb_error, cb_ip_address);
+             sock, cb_error, cb_ip_address);
+        unhook (hook_connect);
+    }
+    else
+    {
+        (void) (HOOK_CONNECT(hook_connect, callback))
+            (hook_connect->callback_data, WEECHAT_HOOK_CONNECT_MEMORY_ERROR,
+             0, sock, cb_error, cb_ip_address);
         unhook (hook_connect);
     }
 
@@ -1323,6 +1495,11 @@ void
 network_connect_with_fork (struct t_hook *hook_connect)
 {
     int child_pipe[2];
+#ifdef HOOK_CONNECT_MAX_SOCKETS
+    int i;
+#else
+    int child_socket[2];
+#endif
 #ifdef HAVE_GNUTLS
     int rc;
     const char *pos_error;
@@ -1338,7 +1515,7 @@ network_connect_with_fork (struct t_hook *hook_connect)
             (void) (HOOK_CONNECT(hook_connect, callback))
                 (hook_connect->callback_data,
                  WEECHAT_HOOK_CONNECT_GNUTLS_INIT_ERROR,
-                 0, NULL, NULL);
+                 0, -1, NULL, NULL);
             unhook (hook_connect);
             return;
         }
@@ -1350,7 +1527,7 @@ network_connect_with_fork (struct t_hook *hook_connect)
             (void) (HOOK_CONNECT(hook_connect, callback))
                 (hook_connect->callback_data,
                  WEECHAT_HOOK_CONNECT_GNUTLS_INIT_ERROR,
-                 0, _("invalid priorities"), NULL);
+                 0, -1, _("invalid priorities"), NULL);
             unhook (hook_connect);
             return;
         }
@@ -1368,13 +1545,34 @@ network_connect_with_fork (struct t_hook *hook_connect)
         (void) (HOOK_CONNECT(hook_connect, callback))
             (hook_connect->callback_data,
              WEECHAT_HOOK_CONNECT_MEMORY_ERROR,
-             0, NULL, NULL);
+             0, -1, NULL, NULL);
         unhook (hook_connect);
         return;
     }
     HOOK_CONNECT(hook_connect, child_read) = child_pipe[0];
     HOOK_CONNECT(hook_connect, child_write) = child_pipe[1];
 
+#ifndef HOOK_CONNECT_MAX_SOCKETS
+    /* create socket for child process */
+    if (socketpair (AF_LOCAL, SOCK_DGRAM, 0, child_socket) < 0)
+    {
+        (void) (HOOK_CONNECT(hook_connect, callback))
+            (hook_connect->callback_data,
+             WEECHAT_HOOK_CONNECT_MEMORY_ERROR,
+             0, -1, NULL, NULL);
+        unhook (hook_connect);
+        return;
+    }
+    HOOK_CONNECT(hook_connect, child_recv) = child_socket[0];
+    HOOK_CONNECT(hook_connect, child_send) = child_socket[1];
+#else
+    for (i = 0; i < HOOK_CONNECT_MAX_SOCKETS; i++)
+    {
+        HOOK_CONNECT(hook_connect, sock_v4[i]) = socket (AF_INET, SOCK_STREAM, 0);
+        HOOK_CONNECT(hook_connect, sock_v6[i]) = socket (AF_INET6, SOCK_STREAM, 0);
+    }
+#endif
+
     switch (pid = fork ())
     {
         /* fork failed */
@@ -1382,13 +1580,16 @@ network_connect_with_fork (struct t_hook *hook_connect)
             (void) (HOOK_CONNECT(hook_connect, callback))
                 (hook_connect->callback_data,
                  WEECHAT_HOOK_CONNECT_MEMORY_ERROR,
-                 0, NULL, NULL);
+                 0, -1, NULL, NULL);
             unhook (hook_connect);
             return;
         /* child process */
         case 0:
             setuid (getuid ());
             close (HOOK_CONNECT(hook_connect, child_read));
+#ifndef HOOK_CONNECT_MAX_SOCKETS
+            close (HOOK_CONNECT(hook_connect, child_recv));
+#endif
             network_connect_child (hook_connect);
             _exit (EXIT_SUCCESS);
     }
@@ -1396,6 +1597,10 @@ network_connect_with_fork (struct t_hook *hook_connect)
     HOOK_CONNECT(hook_connect, child_pid) = pid;
     close (HOOK_CONNECT(hook_connect, child_write));
     HOOK_CONNECT(hook_connect, child_write) = -1;
+#ifndef HOOK_CONNECT_MAX_SOCKETS
+    close (HOOK_CONNECT(hook_connect, child_send));
+    HOOK_CONNECT(hook_connect, child_send) = -1;
+#endif
     HOOK_CONNECT(hook_connect, hook_child_timer) = hook_timer (hook_connect->plugin,
                                                                CONFIG_INTEGER(config_network_connection_timeout) * 1000,
                                                                0, 1,
diff --git a/src/plugins/guile/weechat-guile-api.c b/src/plugins/guile/weechat-guile-api.c
index 071b3a0..7e0616e 100644
--- a/src/plugins/guile/weechat-guile-api.c
+++ b/src/plugins/guile/weechat-guile-api.c
@@ -2476,11 +2476,12 @@ weechat_guile_api_hook_process_hashtable (SCM command, SCM options, SCM timeout,
 
 int
 weechat_guile_api_hook_connect_cb (void *data, int status, int gnutls_rc,
-                                   const char *error, const char *ip_address)
+                                   int sock, const char *error,
+                                   const char *ip_address)
 {
     struct t_plugin_script_cb *script_callback;
-    void *func_argv[5];
-    char str_status[32], str_gnutls_rc[32];
+    void *func_argv[6];
+    char str_status[32], str_gnutls_rc[32], str_sock[32];
     char empty_arg[1] = { '\0' };
     int *rc, ret;
 
@@ -2490,17 +2491,19 @@ weechat_guile_api_hook_connect_cb (void *data, int status, int gnutls_rc,
     {
         snprintf (str_status, sizeof (str_status), "%d", status);
         snprintf (str_gnutls_rc, sizeof (str_gnutls_rc), "%d", gnutls_rc);
+        snprintf (str_sock, sizeof (str_sock), "%d", sock);
 
         func_argv[0] = (script_callback->data) ? script_callback->data : empty_arg;
         func_argv[1] = str_status;
         func_argv[2] = str_gnutls_rc;
-        func_argv[3] = (ip_address) ? (char *)ip_address : empty_arg;
-        func_argv[4] = (error) ? (char *)error : empty_arg;
+        func_argv[3] = str_sock;
+        func_argv[4] = (ip_address) ? (char *)ip_address : empty_arg;
+        func_argv[5] = (error) ? (char *)error : empty_arg;
 
         rc = (int *) weechat_guile_exec (script_callback->script,
                                          WEECHAT_SCRIPT_EXEC_INT,
                                          script_callback->function,
-                                         "sssss", func_argv);
+                                         "ssssss", func_argv);
 
         if (!rc)
             ret = WEECHAT_RC_ERROR;
@@ -2521,8 +2524,8 @@ weechat_guile_api_hook_connect_cb (void *data, int status, int gnutls_rc,
  */
 
 SCM
-weechat_guile_api_hook_connect (SCM proxy, SCM address, SCM port, SCM sock,
-                                SCM ipv6, SCM local_hostname, SCM function,
+weechat_guile_api_hook_connect (SCM proxy, SCM address, SCM port, SCM ipv6,
+                                SCM retry, SCM local_hostname, SCM function,
                                 SCM data)
 {
     char *result;
@@ -2530,8 +2533,8 @@ weechat_guile_api_hook_connect (SCM proxy, SCM address, SCM port, SCM sock,
 
     API_FUNC(1, "hook_connect", API_RETURN_EMPTY);
     if (!scm_is_string (proxy) || !scm_is_string (address)
-        || !scm_is_integer (port) || !scm_is_integer (sock)
-        || !scm_is_integer (ipv6) || !scm_is_string (local_hostname)
+        || !scm_is_integer (port) || !scm_is_integer (ipv6)
+        || !scm_is_integer (retry) || !scm_is_string (local_hostname)
         || !scm_is_string (function) || !scm_is_string (data))
         API_WRONG_ARGS(API_RETURN_EMPTY);
 
@@ -2540,8 +2543,8 @@ weechat_guile_api_hook_connect (SCM proxy, SCM address, SCM port, SCM sock,
                                                          scm_i_string_chars (proxy),
                                                          scm_i_string_chars (address),
                                                          scm_to_int (port),
-                                                         scm_to_int (sock),
                                                          scm_to_int (ipv6),
+                                                         scm_to_int (retry),
                                                          NULL, /* gnutls session */
                                                          NULL, /* gnutls callback */
                                                          0,    /* gnutls DH key size */
@@ -5567,6 +5570,7 @@ weechat_guile_api_module_init (void *data)
     scm_c_define ("weechat:WEECHAT_HOOK_CONNECT_GNUTLS_HANDSHAKE_ERROR", scm_from_int (WEECHAT_HOOK_CONNECT_GNUTLS_HANDSHAKE_ERROR));
     scm_c_define ("weechat:WEECHAT_HOOK_CONNECT_MEMORY_ERROR", scm_from_int (WEECHAT_HOOK_CONNECT_MEMORY_ERROR));
     scm_c_define ("weechat:WEECHAT_HOOK_CONNECT_TIMEOUT", scm_from_int (WEECHAT_HOOK_CONNECT_TIMEOUT));
+    scm_c_define ("weechat:WEECHAT_HOOK_CONNECT_SOCKET_ERROR", scm_from_int (WEECHAT_HOOK_CONNECT_SOCKET_ERROR));
 
     scm_c_define ("weechat:WEECHAT_HOOK_SIGNAL_STRING", scm_from_locale_string (WEECHAT_HOOK_SIGNAL_STRING));
     scm_c_define ("weechat:WEECHAT_HOOK_SIGNAL_INT", scm_from_locale_string (WEECHAT_HOOK_SIGNAL_INT));
@@ -5608,6 +5612,7 @@ weechat_guile_api_module_init (void *data)
                   "weechat:WEECHAT_HOOK_CONNECT_GNUTLS_HANDSHAKE_ERROR",
                   "weechat:WEECHAT_HOOK_CONNECT_MEMORY_ERROR",
                   "weechat:WEECHAT_HOOK_CONNECT_TIMEOUT",
+                  "weechat:WEECHAT_HOOK_CONNECT_SOCKET_ERROR",
                   "weechat:WEECHAT_HOOK_SIGNAL_STRING",
                   "weechat:WEECHAT_HOOK_SIGNAL_INT",
                   "weechat:WEECHAT_HOOK_SIGNAL_POINTER",
diff --git a/src/plugins/irc/irc-server.c b/src/plugins/irc/irc-server.c
index 174dbd0..93a1dc4 100644
--- a/src/plugins/irc/irc-server.c
+++ b/src/plugins/irc/irc-server.c
@@ -362,6 +362,11 @@ irc_server_set_addresses (struct t_irc_server *server, const char *addresses)
         free (server->ports_array);
         server->ports_array = NULL;
     }
+    if (server->retry_array)
+    {
+        free (server->retry_array);
+        server->retry_array = NULL;
+    }
 
     /* set new addresses/ports */
     if (addresses && addresses[0])
@@ -370,6 +375,7 @@ irc_server_set_addresses (struct t_irc_server *server, const char *addresses)
                                                         ",", 0, 0,
                                                         &server->addresses_count);
         server->ports_array = malloc (server->addresses_count * sizeof (server->ports_array[0]));
+        server->retry_array = malloc (server->addresses_count * sizeof (server->retry_array[0]));
         for (i = 0; i < server->addresses_count; i++)
         {
             pos = strchr (server->addresses_array[i], '/');
@@ -386,6 +392,7 @@ irc_server_set_addresses (struct t_irc_server *server, const char *addresses)
             {
                 server->ports_array[i] = IRC_SERVER_DEFAULT_PORT;
             }
+            server->retry_array[i] = 0;
         }
     }
 }
@@ -401,13 +408,19 @@ irc_server_set_index_current_address (struct t_irc_server *server, int index)
     {
         free (server->current_address);
         server->current_address = NULL;
+
+        /* copy current retry value before loading next server */
+        if (server->index_current_address < server->addresses_count)
+            server->retry_array[server->index_current_address] = server->current_retry;
     }
     server->current_port = 0;
+    server->current_retry = 0;
 
     index %= server->addresses_count;
     server->index_current_address = index;
     server->current_address = strdup (server->addresses_array[index]);
     server->current_port = server->ports_array[index];
+    server->current_retry = server->retry_array[index];
 }
 
 /*
@@ -857,10 +870,12 @@ irc_server_alloc (const char *name)
     new_server->addresses_count = 0;
     new_server->addresses_array = NULL;
     new_server->ports_array = NULL;
+    new_server->retry_array = NULL;
     new_server->index_current_address = 0;
     new_server->current_address = NULL;
     new_server->current_ip = NULL;
     new_server->current_port = 0;
+    new_server->current_retry = 0;
     new_server->sock = -1;
     new_server->hook_connect = NULL;
     new_server->hook_fd = NULL;
@@ -1317,6 +1332,8 @@ irc_server_free_data (struct t_irc_server *server)
         weechat_string_free_split (server->addresses_array);
     if (server->ports_array)
         free (server->ports_array);
+    if (server->retry_array)
+        free (server->retry_array);
     if (server->current_address)
         free (server->current_address);
     if (server->current_ip)
@@ -2972,7 +2989,7 @@ irc_server_switch_address (struct t_irc_server *server, int connection)
  */
 
 int
-irc_server_connect_cb (void *data, int status, int gnutls_rc,
+irc_server_connect_cb (void *data, int status, int gnutls_rc, int sock,
                        const char *error, const char *ip_address)
 {
     struct t_irc_server *server;
@@ -2987,6 +3004,7 @@ irc_server_connect_cb (void *data, int status, int gnutls_rc,
     switch (status)
     {
         case WEECHAT_HOOK_CONNECT_OK:
+            server->sock = sock;
             /* login to server */
             if (server->current_ip)
                 free (server->current_ip);
@@ -3051,6 +3069,7 @@ irc_server_connect_cb (void *data, int status, int gnutls_rc,
                                 error);
             }
             irc_server_close_connection (server);
+server->current_retry++;
             irc_server_switch_address (server, 1);
             break;
         case WEECHAT_HOOK_CONNECT_PROXY_ERROR:
@@ -3097,6 +3116,7 @@ irc_server_connect_cb (void *data, int status, int gnutls_rc,
                                 error);
             }
             irc_server_close_connection (server);
+            server->current_retry++;
             irc_server_reconnect_schedule (server);
             break;
         case WEECHAT_HOOK_CONNECT_GNUTLS_HANDSHAKE_ERROR:
@@ -3126,6 +3146,7 @@ irc_server_connect_cb (void *data, int status, int gnutls_rc,
             (void) gnutls_rc;
 #endif
             irc_server_close_connection (server);
+            server->current_retry++;
             irc_server_switch_address (server, 1);
             break;
         case WEECHAT_HOOK_CONNECT_MEMORY_ERROR:
@@ -3154,6 +3175,22 @@ irc_server_connect_cb (void *data, int status, int gnutls_rc,
                                 error);
             }
             irc_server_close_connection (server);
+            server->current_retry++;
+            irc_server_reconnect_schedule (server);
+            break;
+        case WEECHAT_HOOK_CONNECT_SOCKET_ERROR:
+            weechat_printf (server->buffer,
+                            _("%s%s: unable to create socket"),
+                            weechat_prefix ("error"), IRC_PLUGIN_NAME);
+            if (error && error[0])
+            {
+                weechat_printf (server->buffer,
+                                _("%s%s: error: %s"),
+                                weechat_prefix ("error"), IRC_PLUGIN_NAME,
+                                error);
+            }
+            irc_server_close_connection (server);
+            server->current_retry++;
             irc_server_reconnect_schedule (server);
             break;
     }
@@ -3557,7 +3594,7 @@ irc_server_gnutls_callback (void *data, gnutls_session_t tls_session,
 int
 irc_server_connect (struct t_irc_server *server)
 {
-    int set, length, flags;
+    int length;
     char *option_name;
     struct t_config_option *proxy_type, *proxy_ipv6, *proxy_address, *proxy_port;
     const char *proxy, *str_proxy_type, *str_proxy_address;
@@ -3674,26 +3711,22 @@ irc_server_connect (struct t_irc_server *server)
     if (proxy_type)
     {
         weechat_printf (server->buffer,
-                        _("%s%s: connecting to server %s/%d%s%s via %s "
+                        _("%s%s: connecting to server %s/%d%s via %s "
                           "proxy %s/%d%s..."),
                         weechat_prefix ("network"),
                         IRC_PLUGIN_NAME,
                         server->current_address,
                         server->current_port,
-                        (IRC_SERVER_OPTION_BOOLEAN(server, IRC_SERVER_OPTION_IPV6)) ?
-                        " (IPv6)" : "",
                         (IRC_SERVER_OPTION_BOOLEAN(server, IRC_SERVER_OPTION_SSL)) ?
                         " (SSL)" : "",
                         str_proxy_type,
                         str_proxy_address,
                         weechat_config_integer (proxy_port),
                         (weechat_config_boolean (proxy_ipv6)) ? " (IPv6)" : "");
-        weechat_log_printf (_("Connecting to server %s/%d%s%s via %s proxy "
+        weechat_log_printf (_("Connecting to server %s/%d%s via %s proxy "
                               "%s/%d%s..."),
                             server->current_address,
                             server->current_port,
-                            (IRC_SERVER_OPTION_BOOLEAN(server, IRC_SERVER_OPTION_IPV6)) ?
-                            " (IPv6)" : "",
                             (IRC_SERVER_OPTION_BOOLEAN(server, IRC_SERVER_OPTION_SSL)) ?
                             " (SSL)" : "",
                             str_proxy_type,
@@ -3704,22 +3737,18 @@ irc_server_connect (struct t_irc_server *server)
     else
     {
         weechat_printf (server->buffer,
-                        _("%s%s: connecting to server %s/%d%s%s..."),
+                        _("%s%s: connecting to server %s/%d%s..."),
                         weechat_prefix ("network"),
                         IRC_PLUGIN_NAME,
                         server->current_address,
                         server->current_port,
-                        (IRC_SERVER_OPTION_BOOLEAN(server, IRC_SERVER_OPTION_IPV6)) ?
-                        " (IPv6)" : "",
                         (IRC_SERVER_OPTION_BOOLEAN(server, IRC_SERVER_OPTION_SSL)) ?
                         " (SSL)" : "");
-        weechat_log_printf (_("%s%s: connecting to server %s/%d%s%s..."),
+        weechat_log_printf (_("%s%s: connecting to server %s/%d%s..."),
                             "",
                             IRC_PLUGIN_NAME,
                             server->current_address,
                             server->current_port,
-                            (IRC_SERVER_OPTION_BOOLEAN(server, IRC_SERVER_OPTION_IPV6)) ?
-                            " (IPv6)" : "",
                             (IRC_SERVER_OPTION_BOOLEAN(server, IRC_SERVER_OPTION_SSL)) ?
                             " (SSL)" : "");
     }
@@ -3727,55 +3756,6 @@ irc_server_connect (struct t_irc_server *server)
     /* close connection if opened */
     irc_server_close_connection (server);
 
-    /* create socket and set options */
-    if (proxy_type)
-    {
-        server->sock = socket ((weechat_config_integer (proxy_ipv6)) ?
-                               AF_INET6 : AF_INET,
-                               SOCK_STREAM, 0);
-    }
-    else
-    {
-        server->sock = socket ((IRC_SERVER_OPTION_BOOLEAN(server, IRC_SERVER_OPTION_IPV6)) ?
-                               AF_INET6 : AF_INET,
-                               SOCK_STREAM, 0);
-    }
-    if (server->sock == -1)
-    {
-        weechat_printf (server->buffer,
-                        _("%s%s: cannot create socket"),
-                        weechat_prefix ("error"), IRC_PLUGIN_NAME);
-        return 0;
-    }
-
-    /* set SO_REUSEADDR option for socket */
-    set = 1;
-    if (setsockopt (server->sock, SOL_SOCKET, SO_REUSEADDR,
-        (void *) &set, sizeof (set)) == -1)
-    {
-        weechat_printf (server->buffer,
-                        _("%s%s: cannot set socket option "
-                          "\"SO_REUSEADDR\""),
-                        weechat_prefix ("error"), IRC_PLUGIN_NAME);
-    }
-
-    /* set SO_KEEPALIVE option for socket */
-    set = 1;
-    if (setsockopt (server->sock, SOL_SOCKET, SO_KEEPALIVE,
-        (void *) &set, sizeof (set)) == -1)
-    {
-        weechat_printf (server->buffer,
-                        _("%s%s: cannot set socket option "
-                          "\"SO_KEEPALIVE\""),
-                        weechat_prefix ("error"), IRC_PLUGIN_NAME);
-    }
-
-    /* set flag O_NONBLOCK on socket */
-    flags = fcntl (server->sock, F_GETFL);
-    if (flags == -1)
-        flags = 0;
-    fcntl (server->sock, F_SETFL, flags | O_NONBLOCK);
-
     /* init SSL if asked and connect */
     server->ssl_connected = 0;
 #ifdef HAVE_GNUTLS
@@ -3784,8 +3764,9 @@ irc_server_connect (struct t_irc_server *server)
     server->hook_connect = weechat_hook_connect (proxy,
                                                  server->current_address,
                                                  server->current_port,
-                                                 server->sock,
-                                                 IRC_SERVER_OPTION_BOOLEAN(server, IRC_SERVER_OPTION_IPV6),
+                                                 proxy_type ? weechat_config_integer (proxy_ipv6)
+                                                 : IRC_SERVER_OPTION_BOOLEAN(server, IRC_SERVER_OPTION_IPV6),
+                                                 server->current_retry,
                                                  (server->ssl_connected) ? &server->gnutls_sess : NULL,
                                                  (server->ssl_connected) ? irc_server_gnutls_callback : NULL,
                                                  IRC_SERVER_OPTION_INTEGER(server, IRC_SERVER_OPTION_SSL_DHKEY_SIZE),
@@ -3797,7 +3778,9 @@ irc_server_connect (struct t_irc_server *server)
     server->hook_connect = weechat_hook_connect (proxy,
                                                  server->current_address,
                                                  server->current_port,
-                                                 server->sock,
+                                                 proxy_type ? weechat_config_integer (proxy_ipv6)
+                                                 : IRC_SERVER_OPTION_BOOLEAN(server, IRC_SERVER_OPTION_IPV6),
+                                                 server->current_retry,
                                                  IRC_SERVER_OPTION_BOOLEAN(server, IRC_SERVER_OPTION_IPV6),
                                                  NULL, NULL, 0, NULL,
                                                  IRC_SERVER_OPTION_STRING(server, IRC_SERVER_OPTION_LOCAL_HOSTNAME),
@@ -3899,6 +3882,9 @@ irc_server_disconnect (struct t_irc_server *server, int switch_address,
                         IRC_PLUGIN_NAME);
     }
 
+    if (reconnect)
+        server->current_retry++;
+
     if (switch_address)
         irc_server_switch_address (server, 0);
     else
@@ -4375,10 +4361,12 @@ irc_server_hdata_server_cb (void *data, const char *hdata_name)
         WEECHAT_HDATA_VAR(struct t_irc_server, addresses_count, INTEGER, 0, NULL, NULL);
         WEECHAT_HDATA_VAR(struct t_irc_server, addresses_array, STRING, 0, "addresses_count", NULL);
         WEECHAT_HDATA_VAR(struct t_irc_server, ports_array, INTEGER, 0, "addresses_count", NULL);
+        WEECHAT_HDATA_VAR(struct t_irc_server, retry_array, INTEGER, 0, "addresses_count", NULL);
         WEECHAT_HDATA_VAR(struct t_irc_server, index_current_address, INTEGER, 0, NULL, NULL);
         WEECHAT_HDATA_VAR(struct t_irc_server, current_address, STRING, 0, NULL, NULL);
         WEECHAT_HDATA_VAR(struct t_irc_server, current_ip, STRING, 0, NULL, NULL);
         WEECHAT_HDATA_VAR(struct t_irc_server, current_port, INTEGER, 0, NULL, NULL);
+        WEECHAT_HDATA_VAR(struct t_irc_server, current_retry, INTEGER, 0, NULL, NULL);
         WEECHAT_HDATA_VAR(struct t_irc_server, sock, INTEGER, 0, NULL, NULL);
         WEECHAT_HDATA_VAR(struct t_irc_server, hook_connect, POINTER, 0, NULL, "hook");
         WEECHAT_HDATA_VAR(struct t_irc_server, hook_fd, POINTER, 0, NULL, "hook");
@@ -4575,6 +4563,8 @@ irc_server_add_to_infolist (struct t_infolist *infolist,
         return 0;
     if (!weechat_infolist_new_var_integer (ptr_item, "current_port", server->current_port))
         return 0;
+    if (!weechat_infolist_new_var_integer (ptr_item, "current_retry", server->current_retry))
+        return 0;
     if (!weechat_infolist_new_var_integer (ptr_item, "sock", server->sock))
         return 0;
     if (!weechat_infolist_new_var_integer (ptr_item, "is_connected", server->is_connected))
@@ -4888,10 +4878,12 @@ irc_server_print_log ()
         weechat_log_printf ("  addresses_count. . . : %d",    ptr_server->addresses_count);
         weechat_log_printf ("  addresses_array. . . : 0x%lx", ptr_server->addresses_array);
         weechat_log_printf ("  ports_array. . . . . : 0x%lx", ptr_server->ports_array);
+        weechat_log_printf ("  retry_array. . . . . : 0x%lx", ptr_server->retry_array);
         weechat_log_printf ("  index_current_address: %d",    ptr_server->index_current_address);
         weechat_log_printf ("  current_address. . . : '%s'",  ptr_server->current_address);
         weechat_log_printf ("  current_ip . . . . . : '%s'",  ptr_server->current_ip);
         weechat_log_printf ("  current_port . . . . : %d",    ptr_server->current_port);
+        weechat_log_printf ("  current_retry. . . . : %u",    ptr_server->current_retry);
         weechat_log_printf ("  sock . . . . . . . . : %d",    ptr_server->sock);
         weechat_log_printf ("  hook_connect . . . . : 0x%lx", ptr_server->hook_connect);
         weechat_log_printf ("  hook_fd. . . . . . . : 0x%lx", ptr_server->hook_fd);
diff --git a/src/plugins/irc/irc-server.h b/src/plugins/irc/irc-server.h
index 09856a1..fd2f604 100644
--- a/src/plugins/irc/irc-server.h
+++ b/src/plugins/irc/irc-server.h
@@ -140,11 +140,14 @@ struct t_irc_server
     int addresses_count;            /* number of addresses                   */
     char **addresses_array;         /* addresses (after split)               */
     int *ports_array;               /* ports for addresses                   */
+    unsigned int *retry_array;      /* retry count per address               */
     int index_current_address;      /* current address index in array        */
     char *current_address;          /* current address                       */
     char *current_ip;               /* current IP address                    */
     int current_port;               /* current port                          */
-    int sock;                       /* socket for server (IPv4 or IPv6)      */
+    unsigned int current_retry;     /* current retry count (increment if a   */
+                                    /* connected server fails in any way)    */
+    int sock;                       /* socket for server                     */
     struct t_hook *hook_connect;    /* connection hook                       */
     struct t_hook *hook_fd;         /* hook for server socket                */
     struct t_hook *hook_timer_connection; /* timer for connection            */
diff --git a/src/plugins/lua/weechat-lua-api.c b/src/plugins/lua/weechat-lua-api.c
index 618cc3c..a282df7 100644
--- a/src/plugins/lua/weechat-lua-api.c
+++ b/src/plugins/lua/weechat-lua-api.c
@@ -2727,11 +2727,12 @@ weechat_lua_api_hook_process_hashtable (lua_State *L)
 
 int
 weechat_lua_api_hook_connect_cb (void *data, int status, int gnutls_rc,
-                                 const char *error, const char *ip_address)
+                                 int sock, const char *error,
+                                 const char *ip_address)
 {
     struct t_plugin_script_cb *script_callback;
-    void *func_argv[5];
-    char str_status[32], str_gnutls_rc[32];
+    void *func_argv[6];
+    char str_status[32], str_gnutls_rc[32], str_sock[32];
     char empty_arg[1] = { '\0' };
     int *rc, ret;
 
@@ -2741,17 +2742,19 @@ weechat_lua_api_hook_connect_cb (void *data, int status, int gnutls_rc,
     {
         snprintf (str_status, sizeof (str_status), "%d", status);
         snprintf (str_gnutls_rc, sizeof (str_gnutls_rc), "%d", gnutls_rc);
+        snprintf (str_sock, sizeof (str_sock), "%d", sock);
 
         func_argv[0] = (script_callback->data) ? script_callback->data : empty_arg;
         func_argv[1] = str_status;
         func_argv[2] = str_gnutls_rc;
-        func_argv[3] = (ip_address) ? (char *)ip_address : empty_arg;
-        func_argv[4] = (error) ? (char *)error : empty_arg;
+        func_argv[3] = str_sock;
+        func_argv[4] = (ip_address) ? (char *)ip_address : empty_arg;
+        func_argv[5] = (error) ? (char *)error : empty_arg;
 
         rc = (int *) weechat_lua_exec (script_callback->script,
                                        WEECHAT_SCRIPT_EXEC_INT,
                                        script_callback->function,
-                                       "sssss", func_argv);
+                                       "ssssss", func_argv);
 
         if (!rc)
             ret = WEECHAT_RC_ERROR;
@@ -2775,7 +2778,8 @@ static int
 weechat_lua_api_hook_connect (lua_State *L)
 {
     const char *proxy, *address, *local_hostname, *function, *data;
-    int port, sock, ipv6;
+    int port, ipv6;
+    unsigned int retry;
     char *result;
 
     API_FUNC(1, "hook_connect", API_RETURN_EMPTY);
@@ -2785,8 +2789,8 @@ weechat_lua_api_hook_connect (lua_State *L)
     proxy = lua_tostring (lua_current_interpreter, -8);
     address = lua_tostring (lua_current_interpreter, -7);
     port = lua_tonumber (lua_current_interpreter, -6);
-    sock = lua_tonumber (lua_current_interpreter, -5);
-    ipv6 = lua_tonumber (lua_current_interpreter, -4);
+    ipv6 = lua_tonumber (lua_current_interpreter, -5);
+    retry = lua_tonumber (lua_current_interpreter, -4);
     local_hostname = lua_tostring (lua_current_interpreter, -3);
     function = lua_tostring (lua_current_interpreter, -2);
     data = lua_tostring (lua_current_interpreter, -1);
@@ -2796,8 +2800,8 @@ weechat_lua_api_hook_connect (lua_State *L)
                                                          proxy,
                                                          address,
                                                          port,
-                                                         sock,
                                                          ipv6,
+                                                         retry,
                                                          NULL, /* gnutls session */
                                                          NULL, /* gnutls callback */
                                                          0,    /* gnutls DH key size */
@@ -6234,6 +6238,16 @@ weechat_lua_api_constant_weechat_hook_connect_timeout (lua_State *L)
 }
 
 static int
+weechat_lua_api_constant_weechat_hook_connect_socket_error (lua_State *L)
+{
+    /* make C compiler happy */
+    (void) L;
+
+    lua_pushnumber (lua_current_interpreter, WEECHAT_HOOK_CONNECT_SOCKET_ERROR);
+    return 1;
+}
+
+static int
 weechat_lua_api_constant_weechat_hook_signal_string (lua_State *L)
 {
     /* make C compiler happy */
@@ -6496,6 +6510,7 @@ const struct luaL_Reg weechat_lua_api_funcs[] = {
     { "WEECHAT_HOOK_CONNECT_GNUTLS_HANDSHAKE_ERROR", &weechat_lua_api_constant_weechat_hook_connect_gnutls_handshake_error },
     { "WEECHAT_HOOK_CONNECT_MEMORY_ERROR", &weechat_lua_api_constant_weechat_hook_connect_memory_error },
     { "WEECHAT_HOOK_CONNECT_TIMEOUT", &weechat_lua_api_constant_weechat_hook_connect_timeout },
+    { "WEECHAT_HOOK_CONNECT_SOCKET_ERROR", &weechat_lua_api_constant_weechat_hook_connect_socket_error },
 
     { "WEECHAT_HOOK_SIGNAL_STRING", &weechat_lua_api_constant_weechat_hook_signal_string },
     { "WEECHAT_HOOK_SIGNAL_INT", &weechat_lua_api_constant_weechat_hook_signal_int },
diff --git a/src/plugins/perl/weechat-perl-api.c b/src/plugins/perl/weechat-perl-api.c
index c0e05ac..12e6611 100644
--- a/src/plugins/perl/weechat-perl-api.c
+++ b/src/plugins/perl/weechat-perl-api.c
@@ -2561,11 +2561,12 @@ XS (XS_weechat_api_hook_process_hashtable)
 
 int
 weechat_perl_api_hook_connect_cb (void *data, int status, int gnutls_rc,
-                                  const char *error, const char *ip_address)
+                                  int sock, const char *error,
+                                  const char *ip_address)
 {
     struct t_plugin_script_cb *script_callback;
-    void *func_argv[5];
-    char str_status[32], str_gnutls_rc[32];
+    void *func_argv[6];
+    char str_status[32], str_gnutls_rc[32], str_sock[32];
     char empty_arg[1] = { '\0' };
     int *rc, ret;
 
@@ -2575,17 +2576,19 @@ weechat_perl_api_hook_connect_cb (void *data, int status, int gnutls_rc,
     {
         snprintf (str_status, sizeof (str_status), "%d", status);
         snprintf (str_gnutls_rc, sizeof (str_gnutls_rc), "%d", gnutls_rc);
+        snprintf (str_sock, sizeof (str_sock), "%d", sock);
 
         func_argv[0] = (script_callback->data) ? script_callback->data : empty_arg;
         func_argv[1] = str_status;
         func_argv[2] = str_gnutls_rc;
-        func_argv[3] = (ip_address) ? (char *)ip_address : empty_arg;
-        func_argv[4] = (error) ? (char *)error : empty_arg;
+        func_argv[3] = str_sock;
+        func_argv[4] = (ip_address) ? (char *)ip_address : empty_arg;
+        func_argv[5] = (error) ? (char *)error : empty_arg;
 
         rc = (int *) weechat_perl_exec (script_callback->script,
                                         WEECHAT_SCRIPT_EXEC_INT,
                                         script_callback->function,
-                                        "sssss", func_argv);
+                                        "ssssss", func_argv);
 
         if (!rc)
             ret = WEECHAT_RC_ERROR;
@@ -2625,8 +2628,8 @@ XS (XS_weechat_api_hook_connect)
                                                          proxy,
                                                          address,
                                                          SvIV (ST (2)), /* port */
-                                                         SvIV (ST (3)), /* sock */
-                                                         SvIV (ST (4)), /* ipv6 */
+                                                         SvIV (ST (3)), /* ipv6 */
+                                                         SvIV (ST (4)), /* retry */
                                                          NULL, /* gnutls session */
                                                          NULL, /* gnutls callback */
                                                          0,    /* gnutls DH key size */
@@ -5840,6 +5843,7 @@ weechat_perl_api_init (pTHX)
     newCONSTSUB (stash, "weechat::WEECHAT_HOOK_CONNECT_GNUTLS_HANDSHAKE_ERROR", newSViv (WEECHAT_HOOK_CONNECT_GNUTLS_HANDSHAKE_ERROR));
     newCONSTSUB (stash, "weechat::WEECHAT_HOOK_CONNECT_MEMORY_ERROR", newSViv (WEECHAT_HOOK_CONNECT_MEMORY_ERROR));
     newCONSTSUB (stash, "weechat::WEECHAT_HOOK_CONNECT_TIMEOUT", newSViv (WEECHAT_HOOK_CONNECT_TIMEOUT));
+    newCONSTSUB (stash, "weechat::WEECHAT_HOOK_CONNECT_SOCKET_ERROR", newSViv (WEECHAT_HOOK_CONNECT_SOCKET_ERROR));
 
     newCONSTSUB (stash, "weechat::WEECHAT_HOOK_SIGNAL_STRING", newSVpv (WEECHAT_HOOK_SIGNAL_STRING, PL_na));
     newCONSTSUB (stash, "weechat::WEECHAT_HOOK_SIGNAL_INT", newSVpv (WEECHAT_HOOK_SIGNAL_INT, PL_na));
diff --git a/src/plugins/plugin-script-api.c b/src/plugins/plugin-script-api.c
index 8cc9555..9ab27f3 100644
--- a/src/plugins/plugin-script-api.c
+++ b/src/plugins/plugin-script-api.c
@@ -694,12 +694,13 @@ struct t_hook *
 plugin_script_api_hook_connect (struct t_weechat_plugin *weechat_plugin,
                                 struct t_plugin_script *script,
                                 const char *proxy, const char *address, int port,
-                                int sock, int ipv6, void *gnutls_sess,
-                                void *gnutls_cb, int gnutls_dhkey_size,
+                                int ipv6, unsigned int retry,
+                                void *gnutls_sess, void *gnutls_cb,
+                                int gnutls_dhkey_size,
                                 const char *gnutls_priorities,
                                 const char *local_hostname,
                                 int (*callback)(void *data, int status,
-                                                int gnutls_rc,
+                                                int gnutls_rc, int sock,
                                                 const char *error,
                                                 const char *ip_address),
                                 const char *function,
@@ -712,7 +713,7 @@ plugin_script_api_hook_connect (struct t_weechat_plugin *weechat_plugin,
     if (!script_cb)
         return NULL;
 
-    new_hook = weechat_hook_connect (proxy, address, port, sock, ipv6,
+    new_hook = weechat_hook_connect (proxy, address, port, ipv6, retry,
                                      gnutls_sess, gnutls_cb, gnutls_dhkey_size,
                                      gnutls_priorities, local_hostname,
                                      callback, script_cb);
diff --git a/src/plugins/plugin-script-api.h b/src/plugins/plugin-script-api.h
index af5bd3e..98f62b3 100644
--- a/src/plugins/plugin-script-api.h
+++ b/src/plugins/plugin-script-api.h
@@ -180,8 +180,8 @@ extern struct t_hook *plugin_script_api_hook_connect (struct t_weechat_plugin *w
                                                       const char *proxy,
                                                       const char *address,
                                                       int port,
-                                                      int sock,
                                                       int ipv6,
+                                                      unsigned int retry,
                                                       void *gnutls_sess,
                                                       void *gnutls_cb,
                                                       int gnutls_dhkey_size,
@@ -190,6 +190,7 @@ extern struct t_hook *plugin_script_api_hook_connect (struct t_weechat_plugin *w
                                                       int (*callback)(void *data,
                                                                       int status,
                                                                       int gnutls_rc,
+                                                                      int sock,
                                                                       const char *error,
                                                                       const char *ip_address),
                                                       const char *function,
diff --git a/src/plugins/python/weechat-python-api.c b/src/plugins/python/weechat-python-api.c
index 291d2b4..1c776c3 100644
--- a/src/plugins/python/weechat-python-api.c
+++ b/src/plugins/python/weechat-python-api.c
@@ -2674,11 +2674,12 @@ weechat_python_api_hook_process_hashtable (PyObject *self, PyObject *args)
 
 int
 weechat_python_api_hook_connect_cb (void *data, int status, int gnutls_rc,
-                                    const char *error, const char *ip_address)
+                                    int sock, const char *error,
+                                    const char *ip_address)
 {
     struct t_plugin_script_cb *script_callback;
-    void *func_argv[5];
-    char str_status[32], str_gnutls_rc[32], empty_arg[1] = { '\0' };
+    void *func_argv[6];
+    char str_status[32], str_gnutls_rc[32], str_sock[32], empty_arg[1] = { '\0' };
     int *rc, ret;
 
     script_callback = (struct t_plugin_script_cb *)data;
@@ -2687,17 +2688,19 @@ weechat_python_api_hook_connect_cb (void *data, int status, int gnutls_rc,
     {
         snprintf (str_status, sizeof (str_status), "%d", status);
         snprintf (str_gnutls_rc, sizeof (str_gnutls_rc), "%d", gnutls_rc);
+        snprintf (str_sock, sizeof (str_sock), "%d", sock);
 
         func_argv[0] = (script_callback->data) ? script_callback->data : empty_arg;
         func_argv[1] = str_status;
         func_argv[2] = str_gnutls_rc;
-        func_argv[3] = (ip_address) ? (char *)ip_address : empty_arg;
-        func_argv[4] = (error) ? (char *)error : empty_arg;
+        func_argv[3] = str_sock;
+        func_argv[4] = (ip_address) ? (char *)ip_address : empty_arg;
+        func_argv[5] = (error) ? (char *)error : empty_arg;
 
         rc = (int *) weechat_python_exec (script_callback->script,
                                           WEECHAT_SCRIPT_EXEC_INT,
                                           script_callback->function,
-                                          "sssss", func_argv);
+                                          "ssssss", func_argv);
 
         if (!rc)
             ret = WEECHAT_RC_ERROR;
@@ -2721,20 +2724,21 @@ static PyObject *
 weechat_python_api_hook_connect (PyObject *self, PyObject *args)
 {
     char *proxy, *address, *local_hostname, *function, *data, *result;
-    int port, sock, ipv6;
+    int port, ipv6;
+    unsigned int retry;
     PyObject *return_value;
 
     API_FUNC(1, "hook_connect", API_RETURN_EMPTY);
     proxy = NULL;
     address = NULL;
     port = 0;
-    sock = 0;
     ipv6 = 0;
+    retry = 0;
     local_hostname = NULL;
     function = NULL;
     data = NULL;
-    if (!PyArg_ParseTuple (args, "ssiiisss", &proxy, &address, &port, &sock,
-                           &ipv6, &local_hostname, &function, &data))
+    if (!PyArg_ParseTuple (args, "ssiiisss", &proxy, &address, &port, &ipv6,
+                           &retry, &local_hostname, &function, &data))
         API_WRONG_ARGS(API_RETURN_EMPTY);
 
     result = API_PTR2STR(plugin_script_api_hook_connect (weechat_python_plugin,
@@ -2742,8 +2746,8 @@ weechat_python_api_hook_connect (PyObject *self, PyObject *args)
                                                          proxy,
                                                          address,
                                                          port,
-                                                         sock,
                                                          ipv6,
+                                                         retry,
                                                          NULL, /* gnutls session */
                                                          NULL, /* gnutls callback */
                                                          0,    /* gnutls DH key size */
diff --git a/src/plugins/python/weechat-python.c b/src/plugins/python/weechat-python.c
index a3218db..8658d99 100644
--- a/src/plugins/python/weechat-python.c
+++ b/src/plugins/python/weechat-python.c
@@ -547,6 +547,7 @@ void weechat_python_init_module_weechat ()
     PyDict_SetItemString(weechat_dict, "WEECHAT_HOOK_CONNECT_GNUTLS_HANDSHAKE_ERROR", PyLong_FromLong((long) WEECHAT_HOOK_CONNECT_GNUTLS_HANDSHAKE_ERROR));
     PyDict_SetItemString(weechat_dict, "WEECHAT_HOOK_CONNECT_MEMORY_ERROR", PyLong_FromLong((long) WEECHAT_HOOK_CONNECT_MEMORY_ERROR));
     PyDict_SetItemString(weechat_dict, "WEECHAT_HOOK_CONNECT_TIMEOUT", PyLong_FromLong((long) WEECHAT_HOOK_CONNECT_TIMEOUT));
+    PyDict_SetItemString(weechat_dict, "WEECHAT_HOOK_CONNECT_SOCKET_ERROR", PyLong_FromLong((long) WEECHAT_HOOK_CONNECT_SOCKET_ERROR));
 
     PyDict_SetItemString(weechat_dict, "WEECHAT_HOOK_SIGNAL_STRING", PyUnicode_FromString(WEECHAT_HOOK_SIGNAL_STRING));
     PyDict_SetItemString(weechat_dict, "WEECHAT_HOOK_SIGNAL_INT", PyUnicode_FromString(WEECHAT_HOOK_SIGNAL_INT));
diff --git a/src/plugins/ruby/weechat-ruby-api.c b/src/plugins/ruby/weechat-ruby-api.c
index 6d5978e..35c88ac 100644
--- a/src/plugins/ruby/weechat-ruby-api.c
+++ b/src/plugins/ruby/weechat-ruby-api.c
@@ -3056,11 +3056,12 @@ weechat_ruby_api_hook_process_hashtable (VALUE class, VALUE command,
 
 int
 weechat_ruby_api_hook_connect_cb (void *data, int status, int gnutls_rc,
-                                  const char *error, const char *ip_address)
+                                  int sock, const char *error,
+                                  const char *ip_address)
 {
     struct t_plugin_script_cb *script_callback;
-    void *func_argv[5];
-    char str_status[32], str_gnutls_rc[32];
+    void *func_argv[6];
+    char str_status[32], str_gnutls_rc[32], str_sock[32];
     char empty_arg[1] = { '\0' };
     int *rc, ret;
 
@@ -3070,17 +3071,19 @@ weechat_ruby_api_hook_connect_cb (void *data, int status, int gnutls_rc,
     {
         snprintf (str_status, sizeof (str_status), "%d", status);
         snprintf (str_gnutls_rc, sizeof (str_gnutls_rc), "%d", gnutls_rc);
+        snprintf (str_sock, sizeof (str_sock), "%d", sock);
 
         func_argv[0] = (script_callback->data) ? script_callback->data : empty_arg;
         func_argv[1] = str_status;
         func_argv[2] = str_gnutls_rc;
-        func_argv[3] = (ip_address) ? (char *)ip_address : empty_arg;
-        func_argv[4] = (error) ? (char *)error : empty_arg;
+        func_argv[3] = str_sock;
+        func_argv[4] = (ip_address) ? (char *)ip_address : empty_arg;
+        func_argv[5] = (error) ? (char *)error : empty_arg;
 
         rc = (int *) weechat_ruby_exec (script_callback->script,
                                         WEECHAT_SCRIPT_EXEC_INT,
                                         script_callback->function,
-                                        "sssss", func_argv);
+                                        "ssssss", func_argv);
 
         if (!rc)
             ret = WEECHAT_RC_ERROR;
@@ -3102,25 +3105,26 @@ weechat_ruby_api_hook_connect_cb (void *data, int status, int gnutls_rc,
 
 static VALUE
 weechat_ruby_api_hook_connect (VALUE class, VALUE proxy, VALUE address,
-                               VALUE port, VALUE sock, VALUE ipv6,
+                               VALUE port, VALUE ipv6, VALUE retry,
                                VALUE local_hostname, VALUE function,
                                VALUE data)
 {
     char *c_proxy, *c_address, *c_local_hostname, *c_function, *c_data, *result;
-    int c_port, c_sock, c_ipv6;
+    int c_port, c_ipv6;
+    unsigned int c_retry;
     VALUE return_value;
 
     API_FUNC(1, "hook_connect", API_RETURN_EMPTY);
-    if (NIL_P (proxy) || NIL_P (address) || NIL_P (port) || NIL_P (sock)
-        || NIL_P (ipv6) || NIL_P (local_hostname) || NIL_P (function)
+    if (NIL_P (proxy) || NIL_P (address) || NIL_P (port) || NIL_P (ipv6)
+        || NIL_P (retry) || NIL_P (local_hostname) || NIL_P (function)
         || NIL_P (data))
         API_WRONG_ARGS(API_RETURN_EMPTY);
 
     Check_Type (proxy, T_STRING);
     Check_Type (address, T_STRING);
     Check_Type (port, T_FIXNUM);
-    Check_Type (sock, T_FIXNUM);
     Check_Type (ipv6, T_FIXNUM);
+    Check_Type (retry, T_FIXNUM);
     Check_Type (local_hostname, T_STRING);
     Check_Type (function, T_STRING);
     Check_Type (data, T_STRING);
@@ -3128,8 +3132,8 @@ weechat_ruby_api_hook_connect (VALUE class, VALUE proxy, VALUE address,
     c_proxy = StringValuePtr (proxy);
     c_address = StringValuePtr (address);
     c_port = FIX2INT (port);
-    c_sock = FIX2INT (sock);
     c_ipv6 = FIX2INT (ipv6);
+    c_retry = FIX2INT (retry);
     c_local_hostname = StringValuePtr (local_hostname);
     c_function = StringValuePtr (function);
     c_data = StringValuePtr (data);
@@ -3139,8 +3143,8 @@ weechat_ruby_api_hook_connect (VALUE class, VALUE proxy, VALUE address,
                                                          c_proxy,
                                                          c_address,
                                                          c_port,
-                                                         c_sock,
                                                          c_ipv6,
+                                                         c_retry,
                                                          NULL, /* gnutls session */
                                                          NULL, /* gnutls callback */
                                                          0,    /* gnutls DH key size */
@@ -6708,6 +6712,7 @@ weechat_ruby_api_init (VALUE ruby_mWeechat)
     rb_define_const(ruby_mWeechat, "WEECHAT_HOOK_CONNECT_GNUTLS_HANDSHAKE_ERROR", INT2NUM(WEECHAT_HOOK_CONNECT_GNUTLS_HANDSHAKE_ERROR));
     rb_define_const(ruby_mWeechat, "WEECHAT_HOOK_CONNECT_MEMORY_ERROR", INT2NUM(WEECHAT_HOOK_CONNECT_MEMORY_ERROR));
     rb_define_const(ruby_mWeechat, "WEECHAT_HOOK_CONNECT_TIMEOUT", INT2NUM(WEECHAT_HOOK_CONNECT_TIMEOUT));
+    rb_define_const(ruby_mWeechat, "WEECHAT_HOOK_CONNECT_SOCKET_ERROR", INT2NUM(WEECHAT_HOOK_CONNECT_SOCKET_ERROR));
 
     rb_define_const(ruby_mWeechat, "WEECHAT_HOOK_SIGNAL_STRING", rb_str_new2(WEECHAT_HOOK_SIGNAL_STRING));
     rb_define_const(ruby_mWeechat, "WEECHAT_HOOK_SIGNAL_INT", rb_str_new2(WEECHAT_HOOK_SIGNAL_INT));
diff --git a/src/plugins/tcl/weechat-tcl-api.c b/src/plugins/tcl/weechat-tcl-api.c
index 1ea4486..777b946 100644
--- a/src/plugins/tcl/weechat-tcl-api.c
+++ b/src/plugins/tcl/weechat-tcl-api.c
@@ -2997,11 +2997,12 @@ weechat_tcl_api_hook_process_hashtable (ClientData clientData,
 
 int
 weechat_tcl_api_hook_connect_cb (void *data, int status, int gnutls_rc,
-                                 const char *error, const char *ip_address)
+                                 int sock, const char *error,
+                                 const char *ip_address)
 {
     struct t_plugin_script_cb *script_callback;
-    void *func_argv[5];
-    char str_status[32], str_gnutls_rc[32];
+    void *func_argv[6];
+    char str_status[32], str_gnutls_rc[32], str_sock[32];
     char empty_arg[1] = { '\0' };
     int *rc, ret;
 
@@ -3015,13 +3016,14 @@ weechat_tcl_api_hook_connect_cb (void *data, int status, int gnutls_rc,
         func_argv[0] = (script_callback->data) ? script_callback->data : empty_arg;
         func_argv[1] = str_status;
         func_argv[2] = str_gnutls_rc;
-        func_argv[3] = (ip_address) ? (char *)ip_address : empty_arg;
-        func_argv[4] = (error) ? (char *)error : empty_arg;
+        func_argv[3] = str_sock;
+        func_argv[4] = (ip_address) ? (char *)ip_address : empty_arg;
+        func_argv[5] = (error) ? (char *)error : empty_arg;
 
         rc = (int *) weechat_tcl_exec (script_callback->script,
                                        WEECHAT_SCRIPT_EXEC_INT,
                                        script_callback->function,
-                                       "sssss", func_argv);
+                                       "ssssss", func_argv);
 
         if (!rc)
             ret = WEECHAT_RC_ERROR;
@@ -3047,15 +3049,16 @@ weechat_tcl_api_hook_connect (ClientData clientData, Tcl_Interp *interp,
 {
     Tcl_Obj *objp;
     char *proxy, *address, *local_hostname, *function, *data, *result;
-    int i, port, sock, ipv6;
+    int i, port, ipv6;
+    unsigned int retry;
 
     API_FUNC(1, "hook_connect", API_RETURN_EMPTY);
     if (objc < 9)
         API_WRONG_ARGS(API_RETURN_EMPTY);
 
     if ((Tcl_GetIntFromObj (interp, objv[3], &port) != TCL_OK)
-        || (Tcl_GetIntFromObj (interp, objv[4], &sock) != TCL_OK)
-        || (Tcl_GetIntFromObj (interp, objv[5], &ipv6) != TCL_OK))
+        || (Tcl_GetIntFromObj (interp, objv[4], &ipv6) != TCL_OK)
+        || (Tcl_GetIntFromObj (interp, objv[5], &retry) != TCL_OK))
         API_WRONG_ARGS(API_RETURN_EMPTY);
 
     proxy = Tcl_GetStringFromObj (objv[1], &i);
@@ -3069,8 +3072,8 @@ weechat_tcl_api_hook_connect (ClientData clientData, Tcl_Interp *interp,
                                                          proxy,
                                                          address,
                                                          port,
-                                                         sock,
                                                          ipv6,
+                                                         retry,
                                                          NULL, /* gnutls session */
                                                          NULL, /* gnutls callback */
                                                          0,    /* gnutls DH key size */
@@ -6464,6 +6467,8 @@ void weechat_tcl_api_init (Tcl_Interp *interp)
     Tcl_SetVar (interp, "weechat::WEECHAT_HOOK_CONNECT_MEMORY_ERROR", Tcl_GetStringFromObj (objp, &i), 0);
     Tcl_SetIntObj (objp, WEECHAT_HOOK_CONNECT_TIMEOUT);
     Tcl_SetVar (interp, "weechat::WEECHAT_HOOK_CONNECT_TIMEOUT", Tcl_GetStringFromObj (objp, &i), 0);
+    Tcl_SetIntObj (objp, WEECHAT_HOOK_CONNECT_SOCKET_ERROR);
+    Tcl_SetVar (interp, "weechat::WEECHAT_HOOK_CONNECT_SOCKET_ERROR", Tcl_GetStringFromObj (objp, &i), 0);
 
     Tcl_SetStringObj (objp, WEECHAT_HOOK_SIGNAL_STRING, -1);
     Tcl_SetVar (interp, "weechat::WEECHAT_HOOK_SIGNAL_STRING", Tcl_GetStringFromObj (objp, &i), 0);
diff --git a/src/plugins/weechat-plugin.h b/src/plugins/weechat-plugin.h
index 08ed8cd..382e421 100644
--- a/src/plugins/weechat-plugin.h
+++ b/src/plugins/weechat-plugin.h
@@ -46,7 +46,7 @@ struct timeval;
  */
 
 /* API version (used to check that plugin has same API and can be loaded) */
-#define WEECHAT_PLUGIN_API_VERSION "20120827-01"
+#define WEECHAT_PLUGIN_API_VERSION "20120827-02"
 
 /* macros for defining plugin infos */
 #define WEECHAT_PLUGIN_NAME(__name)                                     \
@@ -138,6 +138,7 @@ struct timeval;
 #define WEECHAT_HOOK_CONNECT_GNUTLS_HANDSHAKE_ERROR 7
 #define WEECHAT_HOOK_CONNECT_MEMORY_ERROR           8
 #define WEECHAT_HOOK_CONNECT_TIMEOUT                9
+#define WEECHAT_HOOK_CONNECT_SOCKET_ERROR           10
 
 /* action for gnutls callback: verify or set certificate */
 #define WEECHAT_HOOK_CONNECT_GNUTLS_CB_VERIFY_CERT  0
@@ -535,8 +536,8 @@ struct t_weechat_plugin
                                     const char *proxy,
                                     const char *address,
                                     int port,
-                                    int sock,
                                     int ipv6,
+                                    unsigned int retry,
                                     void *gnutls_sess, void *gnutls_cb,
                                     int gnutls_dhkey_size,
                                     const char *gnutls_priorities,
@@ -544,6 +545,7 @@ struct t_weechat_plugin
                                     int (*callback)(void *data,
                                                     int status,
                                                     int gnutls_rc,
+                                                    int sock,
                                                     const char *error,
                                                     const char *ip_address),
                                     void *callback_data);
@@ -1330,12 +1332,12 @@ extern int weechat_plugin_end (struct t_weechat_plugin *plugin);
     weechat_plugin->hook_process_hashtable(weechat_plugin, __command,   \
                                            __options, __timeout,        \
                                             __callback, __callback_data)
-#define weechat_hook_connect(__proxy, __address, __port, __sock,        \
-                            __ipv6, __gnutls_sess, __gnutls_cb,         \
+#define weechat_hook_connect(__proxy, __address, __port, __ipv6,        \
+                             __retry, __gnutls_sess, __gnutls_cb,       \
                              __gnutls_dhkey_size, __gnutls_priorities,  \
-                             __local_hostname,  __callback, __data)     \
+                             __local_hostname, __callback, __data)      \
     weechat_plugin->hook_connect(weechat_plugin, __proxy, __address,    \
-                                 __port, __sock, __ipv6, __gnutls_sess, \
+                                 __port, __ipv6, __retry, __gnutls_sess,\
                                  __gnutls_cb, __gnutls_dhkey_size,      \
                                  __gnutls_priorities, __local_hostname, \
                                  __callback, __data)
-- 
1.7.8.rc3

