summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/wee-hook.c49
-rw-r--r--src/core/wee-hook.h28
-rw-r--r--src/core/wee-network.c664
-rw-r--r--src/plugins/guile/weechat-guile-api.c28
-rw-r--r--src/plugins/irc/irc-config.c3
-rw-r--r--src/plugins/irc/irc-server.c130
-rw-r--r--src/plugins/irc/irc-server.h6
-rw-r--r--src/plugins/lua/weechat-lua-api.c35
-rw-r--r--src/plugins/perl/weechat-perl-api.c21
-rw-r--r--src/plugins/plugin-script-api.c10
-rw-r--r--src/plugins/plugin-script-api.h4
-rw-r--r--src/plugins/python/weechat-python-api.c26
-rw-r--r--src/plugins/python/weechat-python.c2
-rw-r--r--src/plugins/ruby/weechat-ruby-api.c31
-rw-r--r--src/plugins/tcl/weechat-tcl-api.c26
-rw-r--r--src/plugins/weechat-plugin.h23
16 files changed, 704 insertions, 382 deletions
diff --git a/src/core/wee-hook.c b/src/core/wee-hook.c
index 5080e7f53..d2d77da31 100644
--- a/src/core/wee-hook.c
+++ b/src/core/wee-hook.c
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2003-2012 Sebastien Helleu <flashcode@flashtux.org>
+ * Copyright (C) 2012 Simon Arlott
*
* This file is part of WeeChat, the extensible chat client.
*
@@ -1713,13 +1714,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, 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 +1733,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 +1754,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 +1768,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 +1777,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 +3180,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 +3505,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 +3521,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,6 +3919,7 @@ 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 . . . . . . . . : %d", 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));
@@ -3895,6 +3929,8 @@ hook_print_log ()
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));
+ log_printf (" child_recv. . . . . . : %d", HOOK_CONNECT(ptr_hook, child_recv));
+ log_printf (" child_send. . . . . . : %d", HOOK_CONNECT(ptr_hook, child_send));
log_printf (" child_pid . . . . . . : %d", HOOK_CONNECT(ptr_hook, child_pid));
log_printf (" hook_child_timer. . . : 0x%lx", HOOK_CONNECT(ptr_hook, hook_child_timer));
log_printf (" hook_fd . . . . . . . : 0x%lx", HOOK_CONNECT(ptr_hook, hook_fd));
@@ -3902,6 +3938,13 @@ hook_print_log ()
log_printf (" handshake_hook_timer. : 0x%lx", HOOK_CONNECT(ptr_hook, handshake_hook_timer));
log_printf (" handshake_fd_flags. . : %d", HOOK_CONNECT(ptr_hook, handshake_fd_flags));
log_printf (" handshake_ip_address. : '%s'", HOOK_CONNECT(ptr_hook, handshake_ip_address));
+#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
}
break;
case HOOK_TYPE_PRINT:
diff --git a/src/core/wee-hook.h b/src/core/wee-hook.h
index c1375d391..1ad0b6e1e 100644
--- a/src/core/wee-hook.h
+++ b/src/core/wee-hook.h
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2003-2012 Sebastien Helleu <flashcode@flashtux.org>
+ * Copyright (C) 2012 Simon Arlott
*
* This file is part of WeeChat, the extensible chat client.
*
@@ -26,6 +27,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 +225,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 +248,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) */
+ 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 +260,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 +269,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 +477,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, 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 a37be51d3..0f2a98739 100644
--- a/src/core/wee-network.c
+++ b/src/core/wee-network.c
@@ -2,6 +2,7 @@
* Copyright (C) 2003-2012 Sebastien Helleu <flashcode@flashtux.org>
* Copyright (C) 2005-2010 Emmanuel Bouthenot <kolter@openics.org>
* Copyright (C) 2010 Gu1ll4um3r0m41n <aeroxteam@gmail.com>
+ * Copyright (C) 2012 Simon Arlott
*
* This file is part of WeeChat, the extensible chat client.
*
@@ -38,6 +39,7 @@
#include <netdb.h>
#include <errno.h>
#include <gcrypt.h>
+#include <sys/time.h>
#ifdef HAVE_GNUTLS
#include <gnutls/gnutls.h>
@@ -645,20 +647,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
+ */
+ int retry, rand_num, i;
+ 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 +699,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), "%d", 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), "%d", 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 +791,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 +803,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 +1075,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 +1084,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 +1112,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 +1142,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 +1185,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 +1205,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 +1215,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 +1248,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 +1271,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 +1287,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 +1320,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 +1406,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 +1427,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 +1469,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 +1496,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 +1516,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 +1528,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 +1546,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 +1581,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 +1598,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 071b3a0ff..378fb7e0f 100644
--- a/src/plugins/guile/weechat-guile-api.c
+++ b/src/plugins/guile/weechat-guile-api.c
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2011-2012 Sebastien Helleu <flashcode@flashtux.org>
+ * Copyright (C) 2012 Simon Arlott
*
* This file is part of WeeChat, the extensible chat client.
*
@@ -2476,11 +2477,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 +2492,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 +2525,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 +2534,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 +2544,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 +5571,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 +5613,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-config.c b/src/plugins/irc/irc-config.c
index ff4773a53..e51290145 100644
--- a/src/plugins/irc/irc-config.c
+++ b/src/plugins/irc/irc-config.c
@@ -1347,7 +1347,8 @@ irc_config_server_new_option (struct t_config_file *config_file,
new_option = weechat_config_new_option (
config_file, section,
option_name, "boolean",
- N_("use IPv6 protocol for server communication"),
+ N_("use IPv6 protocol for server communication (try IPv6 then "
+ "fallback to IPv4); if disabled, only IPv4 is used"),
NULL, 0, 0,
default_value, value,
null_value_allowed,
diff --git a/src/plugins/irc/irc-server.c b/src/plugins/irc/irc-server.c
index 6c7100fd8..2b331171e 100644
--- a/src/plugins/irc/irc-server.c
+++ b/src/plugins/irc/irc-server.c
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2003-2012 Sebastien Helleu <flashcode@flashtux.org>
* Copyright (C) 2005-2010 Emmanuel Bouthenot <kolter@openics.org>
+ * Copyright (C) 2012 Simon Arlott
*
* This file is part of WeeChat, the extensible chat client.
*
@@ -82,7 +83,7 @@ char *irc_server_option_string[IRC_SERVER_NUM_OPTIONS] =
};
char *irc_server_option_default[IRC_SERVER_NUM_OPTIONS] =
-{ "", "", "off",
+{ "", "", "on",
"off", "", "NORMAL", "2048", "on",
"", "",
"plain", "", "", "15",
@@ -362,6 +363,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 +376,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 +393,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,8 +409,13 @@ 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;
if (server->addresses_count > 0)
{
@@ -410,6 +423,7 @@ irc_server_set_index_current_address (struct t_irc_server *server, int index)
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];
}
}
@@ -860,10 +874,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;
@@ -1331,6 +1347,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)
@@ -3022,7 +3040,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;
@@ -3037,7 +3055,8 @@ irc_server_connect_cb (void *data, int status, int gnutls_rc,
switch (status)
{
case WEECHAT_HOOK_CONNECT_OK:
- /* login to server */
+ /* set socket and IP */
+ server->sock = sock;
if (server->current_ip)
free (server->current_ip);
server->current_ip = (ip_address) ? strdup (ip_address) : NULL;
@@ -3052,6 +3071,7 @@ irc_server_connect_cb (void *data, int status, int gnutls_rc,
1, 0, 0,
&irc_server_recv_cb,
server);
+ /* login to server */
irc_server_login (server);
break;
case WEECHAT_HOOK_CONNECT_ADDRESS_NOT_FOUND:
@@ -3101,6 +3121,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:
@@ -3147,6 +3168,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:
@@ -3176,6 +3198,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:
@@ -3204,8 +3227,24 @@ 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_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;
}
return WEECHAT_RC_OK;
@@ -3618,7 +3657,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;
@@ -3737,26 +3776,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,
@@ -3767,22 +3802,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)" : "");
}
@@ -3790,55 +3821,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
@@ -3847,8 +3829,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),
@@ -3860,7 +3843,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),
@@ -3966,6 +3951,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
@@ -4444,10 +4432,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");
@@ -4647,6 +4637,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))
@@ -4962,10 +4954,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. . . . : %d", 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 ea2dd8b4d..c8911c3a2 100644
--- a/src/plugins/irc/irc-server.h
+++ b/src/plugins/irc/irc-server.h
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2003-2012 Sebastien Helleu <flashcode@flashtux.org>
+ * Copyright (C) 2012 Simon Arlott
*
* This file is part of WeeChat, the extensible chat client.
*
@@ -140,11 +141,14 @@ struct t_irc_server
int addresses_count; /* number of addresses */
char **addresses_array; /* addresses (after split) */
int *ports_array; /* ports for addresses */
+ 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) */
+ 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 618cc3cd3..ce8a1e61f 100644
--- a/src/plugins/lua/weechat-lua-api.c
+++ b/src/plugins/lua/weechat-lua-api.c
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2006-2007 Emmanuel Bouthenot <kolter@openics.org>
* Copyright (C) 2006-2012 Sebastien Helleu <flashcode@flashtux.org>
+ * Copyright (C) 2012 Simon Arlott
*
* This file is part of WeeChat, the extensible chat client.
*
@@ -2727,11 +2728,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 +2743,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 +2779,7 @@ 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, 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 c0e05ac8e..3d0cb645e 100644
--- a/src/plugins/perl/weechat-perl-api.c
+++ b/src/plugins/perl/weechat-perl-api.c
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2003-2012 Sebastien Helleu <flashcode@flashtux.org>
* Copyright (C) 2005-2008 Emmanuel Bouthenot <kolter@openics.org>
+ * Copyright (C) 2012 Simon Arlott
*
* This file is part of WeeChat, the extensible chat client.
*
@@ -2561,11 +2562,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 +2577,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 +2629,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 +5844,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 8cc9555c4..567ae43e5 100644
--- a/src/plugins/plugin-script-api.c
+++ b/src/plugins/plugin-script-api.c
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2003-2012 Sebastien Helleu <flashcode@flashtux.org>
+ * Copyright (C) 2012 Simon Arlott
*
* This file is part of WeeChat, the extensible chat client.
*
@@ -694,12 +695,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, 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 +714,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 af5bd3e85..6e33c36d6 100644
--- a/src/plugins/plugin-script-api.h
+++ b/src/plugins/plugin-script-api.h
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2003-2012 Sebastien Helleu <flashcode@flashtux.org>
+ * Copyright (C) 2012 Simon Arlott
*
* This file is part of WeeChat, the extensible chat client.
*
@@ -180,8 +181,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,
+ int retry,
void *gnutls_sess,
void *gnutls_cb,
int gnutls_dhkey_size,
@@ -190,6 +191,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 291d2b4e6..cc8f2a4e1 100644
--- a/src/plugins/python/weechat-python-api.c
+++ b/src/plugins/python/weechat-python-api.c
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2003-2012 Sebastien Helleu <flashcode@flashtux.org>
* Copyright (C) 2005-2007 Emmanuel Bouthenot <kolter@openics.org>
+ * Copyright (C) 2012 Simon Arlott
*
* This file is part of WeeChat, the extensible chat client.
*
@@ -2674,11 +2675,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 +2689,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 +2725,20 @@ 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, 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 a3218dbfd..2eba42de4 100644
--- a/src/plugins/python/weechat-python.c
+++ b/src/plugins/python/weechat-python.c
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2003-2012 Sebastien Helleu <flashcode@flashtux.org>
* Copyright (C) 2005-2007 Emmanuel Bouthenot <kolter@openics.org>
+ * Copyright (C) 2012 Simon Arlott
*
* This file is part of WeeChat, the extensible chat client.
*
@@ -547,6 +548,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 6d5978e10..23420282e 100644
--- a/src/plugins/ruby/weechat-ruby-api.c
+++ b/src/plugins/ruby/weechat-ruby-api.c
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2003-2012 Sebastien Helleu <flashcode@flashtux.org>
* Copyright (C) 2005-2007 Emmanuel Bouthenot <kolter@openics.org>
+ * Copyright (C) 2012 Simon Arlott
*
* This file is part of WeeChat, the extensible chat client.
*
@@ -3056,11 +3057,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 +3072,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 +3106,25 @@ 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, 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 1ea448691..0738fc39e 100644
--- a/src/plugins/tcl/weechat-tcl-api.c
+++ b/src/plugins/tcl/weechat-tcl-api.c
@@ -2,6 +2,7 @@
* Copyright (C) 2008-2010 Dmitry Kobylin <fnfal@academ.tsc.ru>
* Copyright (C) 2008 Julien Louis <ptitlouis@sysif.net>
* Copyright (C) 2008-2012 Sebastien Helleu <flashcode@flashtux.org>
+ * Copyright (C) 2012 Simon Arlott
*
* This file is part of WeeChat, the extensible chat client.
*
@@ -2997,11 +2998,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;
@@ -3011,17 +3013,19 @@ weechat_tcl_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_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 +3051,15 @@ 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, 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 +3073,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 +6468,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 08ed8cd40..b70c75de4 100644
--- a/src/plugins/weechat-plugin.h
+++ b/src/plugins/weechat-plugin.h
@@ -45,8 +45,12 @@ struct timeval;
* some functions in this file, then please update API version below.
*/
-/* API version (used to check that plugin has same API and can be loaded) */
-#define WEECHAT_PLUGIN_API_VERSION "20120827-01"
+/*
+ * API version (used to check that plugin has same API and can be loaded):
+ * please change the date with current one; for a second change at same
+ * date, increment the 01, otherwise please keep 01.
+ */
+#define WEECHAT_PLUGIN_API_VERSION "20121014-01"
/* macros for defining plugin infos */
#define WEECHAT_PLUGIN_NAME(__name) \
@@ -138,6 +142,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 +540,8 @@ struct t_weechat_plugin
const char *proxy,
const char *address,
int port,
- int sock,
int ipv6,
+ int retry,
void *gnutls_sess, void *gnutls_cb,
int gnutls_dhkey_size,
const char *gnutls_priorities,
@@ -544,6 +549,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,13 +1336,14 @@ 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, \
- __gnutls_cb, __gnutls_dhkey_size, \
+ __port, __ipv6, __retry, \
+ __gnutls_sess, __gnutls_cb, \
+ __gnutls_dhkey_size, \
__gnutls_priorities, __local_hostname, \
__callback, __data)
#define weechat_hook_print(__buffer, __tags, __msg, __strip__colors, \