Use GTask for async connecting

Previously a child process was used on Unix and
a thread on Windows and they each communicated
with the main thread via pipes which includeded
platform specific code and upon closure on Windows
could result in crash.

Now a thread is used on all platforms with safer
ways of cancellation.

Little behavior should have been changed though timing
of print events are now after connecting finished which
might be a minor issue.
This commit is contained in:
TingPing 2014-12-29 01:42:49 -05:00
parent 086d4e3962
commit eb08bcfacf
8 changed files with 257 additions and 357 deletions

View File

@ -175,11 +175,11 @@ dnl *********************************************************************
dnl ** GLIB *************************************************************
dnl *********************************************************************
AM_PATH_GLIB_2_0([2.32.0], [], [AC_MSG_ERROR([Glib not found!])], [gmodule gobject gio])
AM_PATH_GLIB_2_0([2.36.0], [], [AC_MSG_ERROR([Glib not found!])], [gmodule gobject gio])
COMMON_CFLAGS="$GLIB_CFLAGS -DG_DISABLE_SINGLE_INCLUDES"
COMMON_LIBS="$GLIB_LIBS"
AC_DEFINE([GLIB_VERSION_MIN_REQUIRED], [GLIB_VERSION_2_32], [Dont warn using older APIs])
AC_DEFINE([GLIB_VERSION_MAX_ALLOWED], [GLIB_VERSION_2_32], [Prevents using newer APIs])
AC_DEFINE([GLIB_VERSION_MIN_REQUIRED], [GLIB_VERSION_2_36], [Dont warn using older APIs])
AC_DEFINE([GLIB_VERSION_MAX_ALLOWED], [GLIB_VERSION_2_36], [Prevents using newer APIs])
dnl *********************************************************************
dnl ** GTK **************************************************************

View File

@ -529,9 +529,7 @@ const struct prefs vars[] =
{"irc_whois_front", P_OFFINT (hex_irc_whois_front), TYPE_BOOL},
{"net_auto_reconnect", P_OFFINT (hex_net_auto_reconnect), TYPE_BOOL},
#ifndef WIN32 /* FIXME fix reconnect crashes and remove this ifdef! */
{"net_auto_reconnectonfail", P_OFFINT (hex_net_auto_reconnectonfail), TYPE_BOOL},
#endif
{"net_bind_host", P_OFFSET (hex_net_bind_host), TYPE_STR},
{"net_ping_timeout", P_OFFINT (hex_net_ping_timeout), TYPE_INT},
{"net_proxy_auth", P_OFFINT (hex_net_proxy_auth), TYPE_BOOL},

View File

@ -487,9 +487,7 @@ typedef struct server
#else
void *ssl;
#endif
int childread;
int childwrite;
int childpid;
GCancellable *cancellable; /* to cancel connecting thread */
int iotag;
int recondelay_tag; /* reconnect delay timeout */
int joindelay_tag; /* waiting before we send JOIN */

View File

@ -120,10 +120,13 @@ net_resolve (netstore * ns, char *hostname, int port, char **real_host)
getnameinfo (ns->ip6_hostent->ai_addr, ns->ip6_hostent->ai_addrlen,
ipstring, sizeof (ipstring), NULL, 0, NI_NUMERICHOST);
if (real_host)
{
if (ns->ip6_hostent->ai_canonname)
*real_host = g_strdup (ns->ip6_hostent->ai_canonname);
else
*real_host = g_strdup (hostname);
}
return g_strdup (ipstring);
}

View File

@ -65,6 +65,8 @@
#include <proxy.h>
#endif
#define HEXCHAT_CONNECTION_ERROR g_quark_from_static_string("hexchat-connection-error")
#ifdef USE_OPENSSL
/* local variables */
static struct session *g_sess = NULL;
@ -82,6 +84,14 @@ static void server_connect (server *serv, char *hostname, int port, int no_login
extern pxProxyFactory *libproxy_factory;
#endif
enum
{
RESOLVE_FAILED = 1,
CONNECTION_FAILED,
BIND_FAILED,
PROXY_FAILED
};
/* actually send to the socket. This might do a character translation or
send via SSL. server/dcc both use this function. */
@ -538,25 +548,6 @@ server_stopconnecting (server * serv)
serv->joindelay_tag = 0;
}
#ifndef WIN32
/* kill the child process trying to connect */
kill (serv->childpid, SIGKILL);
waitpid (serv->childpid, NULL, 0);
close (serv->childwrite);
close (serv->childread);
#else
PostThreadMessage (serv->childpid, WM_QUIT, 0, 0);
{
/* if we close the pipe now, giowin32 will crash. */
int *pipefd = g_new (int, 2);
pipefd[0] = serv->childwrite;
pipefd[1] = serv->childread;
g_idle_add ((GSourceFunc)server_close_pipe, pipefd);
}
#endif
#ifdef USE_OPENSSL
if (serv->ssl_do_connect_tag)
{
@ -565,6 +556,12 @@ server_stopconnecting (server * serv)
}
#endif
if (serv->cancellable)
{
g_object_unref (serv->cancellable);
serv->cancellable = NULL;
}
fe_progressbar_end (serv);
serv->connecting = FALSE;
@ -886,124 +883,6 @@ server_connect_success (server *serv)
server_connected (serv);
}
/* receive info from the child-process about connection progress */
static gboolean
server_read_child (GIOChannel *source, GIOCondition condition, server *serv)
{
session *sess = serv->server_session;
char tbuf[128];
char outbuf[512];
char host[100];
char ip[100];
waitline2 (source, tbuf, sizeof tbuf);
switch (tbuf[0])
{
case '0': /* print some text */
waitline2 (source, tbuf, sizeof tbuf);
PrintText (serv->server_session, tbuf);
break;
case '1': /* unknown host */
server_stopconnecting (serv);
closesocket (serv->sok4);
if (serv->proxy_sok4 != -1)
closesocket (serv->proxy_sok4);
if (serv->sok6 != -1)
closesocket (serv->sok6);
if (serv->proxy_sok6 != -1)
closesocket (serv->proxy_sok6);
EMIT_SIGNAL (XP_TE_UKNHOST, sess, NULL, NULL, NULL, NULL, 0);
if (!servlist_cycle (serv))
if (prefs.hex_net_auto_reconnectonfail)
auto_reconnect (serv, FALSE, -1);
break;
case '2': /* connection failed */
waitline2 (source, tbuf, sizeof tbuf);
server_stopconnecting (serv);
closesocket (serv->sok4);
if (serv->proxy_sok4 != -1)
closesocket (serv->proxy_sok4);
if (serv->sok6 != -1)
closesocket (serv->sok6);
if (serv->proxy_sok6 != -1)
closesocket (serv->proxy_sok6);
EMIT_SIGNAL (XP_TE_CONNFAIL, sess, errorstring (atoi (tbuf)), NULL,
NULL, NULL, 0);
if (!servlist_cycle (serv))
if (prefs.hex_net_auto_reconnectonfail)
auto_reconnect (serv, FALSE, -1);
break;
case '3': /* gethostbyname finished */
waitline2 (source, host, sizeof host);
waitline2 (source, ip, sizeof ip);
waitline2 (source, outbuf, sizeof outbuf);
EMIT_SIGNAL (XP_TE_CONNECT, sess, host, ip, outbuf, NULL, 0);
break;
case '4': /* success */
waitline2 (source, tbuf, sizeof (tbuf));
serv->sok = atoi (tbuf);
/* close the one we didn't end up using */
if (serv->sok == serv->sok4)
closesocket (serv->sok6);
else
closesocket (serv->sok4);
if (serv->proxy_sok != -1)
{
if (serv->proxy_sok == serv->proxy_sok4)
closesocket (serv->proxy_sok6);
else
closesocket (serv->proxy_sok4);
}
{
struct sockaddr addr;
int addr_len = sizeof (addr);
guint16 port;
if (!getsockname (serv->sok, &addr, &addr_len))
{
if (addr.sa_family == AF_INET)
port = ntohs(((struct sockaddr_in *)&addr)->sin_port);
else
port = ntohs(((struct sockaddr_in6 *)&addr)->sin6_port);
g_snprintf (outbuf, sizeof (outbuf), "IDENTD %"G_GUINT16_FORMAT" ", port);
if (serv->network && ((ircnet *)serv->network)->user)
g_strlcat (outbuf, ((ircnet *)serv->network)->user, sizeof (outbuf));
else
g_strlcat (outbuf, prefs.hex_irc_user_name, sizeof (outbuf));
handle_command (serv->server_session, outbuf, FALSE);
}
}
server_connect_success (serv);
break;
case '5': /* prefs ip discovered */
waitline2 (source, tbuf, sizeof tbuf);
prefs.local_ip = inet_addr (tbuf);
break;
case '7': /* gethostbyname (prefs.hex_net_bind_host) failed */
sprintf (outbuf,
_("Cannot resolve hostname %s\nCheck your IP Settings!\n"),
prefs.hex_net_bind_host);
PrintText (sess, outbuf);
break;
case '8':
PrintText (sess, _("Proxy traversal failed.\n"));
server_disconnect (sess, FALSE, -1);
break;
case '9':
waitline2 (source, tbuf, sizeof tbuf);
EMIT_SIGNAL (XP_TE_SERVERLOOKUP, sess, tbuf, NULL, NULL, NULL, 0);
break;
}
return TRUE;
}
/* kill all sockets & iotags of a server. Stop a connection attempt, or
disconnect if already connected. */
@ -1072,7 +951,6 @@ server_disconnect (session * sess, int sendquit, int err)
{
server *serv = sess->server;
GSList *list;
char tbuf[64];
gboolean shutup = FALSE;
/* send our QUIT reason */
@ -1090,8 +968,8 @@ server_disconnect (session * sess, int sendquit, int err)
notc_msg (sess);
return;
case 1: /* it was in the process of connecting */
sprintf (tbuf, "%d", sess->server->childpid);
EMIT_SIGNAL (XP_TE_STOPCONNECT, sess, tbuf, NULL, NULL, NULL, 0);
EMIT_SIGNAL (XP_TE_STOPCONNECT, sess, NULL, NULL, NULL, NULL, 0);
g_cancellable_cancel (serv->cancellable);
return;
case 3:
shutup = TRUE; /* won't print "disconnected" in channels */
@ -1124,15 +1002,6 @@ server_disconnect (session * sess, int sendquit, int err)
notify_cleanup ();
}
/* send a "print text" command to the parent process - MUST END IN \n! */
static void
proxy_error (int fd, char *msg)
{
write (fd, "0\n", 2);
write (fd, msg, strlen (msg));
}
struct sock_connect
{
char version;
@ -1147,7 +1016,7 @@ struct sock_connect
* 1 socks traversal failed */
static int
traverse_socks (int print_fd, int sok, char *serverAddr, int port)
traverse_socks (int sok, char *serverAddr, int port, GError **error)
{
struct sock_connect sc;
unsigned char buf[256];
@ -1165,7 +1034,7 @@ traverse_socks (int print_fd, int sok, char *serverAddr, int port)
return 0;
g_snprintf (buf, sizeof (buf), "SOCKS\tServer reported error %d,%d.\n", buf[0], buf[1]);
proxy_error (print_fd, buf);
*error = g_error_new_literal (HEXCHAT_CONNECTION_ERROR, PROXY_FAILED, buf);
return 1;
}
@ -1177,7 +1046,7 @@ struct sock5_connect1
};
static int
traverse_socks5 (int print_fd, int sok, char *serverAddr, int port)
traverse_socks5 (int sok, char *serverAddr, int port, GError **error)
{
struct sock5_connect1 sc1;
unsigned char *sc2;
@ -1197,7 +1066,7 @@ traverse_socks5 (int print_fd, int sok, char *serverAddr, int port)
if (buf[0] != 5)
{
proxy_error (print_fd, "SOCKS\tServer is not socks version 5.\n");
*error = g_error_new_literal (HEXCHAT_CONNECTION_ERROR, PROXY_FAILED, "SOCKS\tServer is not socks version 5.\n");
return 1;
}
@ -1212,7 +1081,7 @@ traverse_socks5 (int print_fd, int sok, char *serverAddr, int port)
/* authentication sub-negotiation (RFC1929) */
if (buf[1] != 2) /* UPA not supported by server */
{
proxy_error (print_fd, "SOCKS\tServer doesn't support UPA authentication.\n");
*error = g_error_new_literal (HEXCHAT_CONNECTION_ERROR, PROXY_FAILED, "SOCKS\tServer doesn't support UPA authentication.\n");
return 1;
}
@ -1232,7 +1101,7 @@ traverse_socks5 (int print_fd, int sok, char *serverAddr, int port)
goto read_error;
if ( buf[1] != 0 )
{
proxy_error (print_fd, "SOCKS\tAuthentication failed. "
*error = g_error_new_literal (HEXCHAT_CONNECTION_ERROR, PROXY_FAILED, "SOCKS\tAuthentication failed. "
"Is username and password correct?\n");
return 1; /* UPA failed! */
}
@ -1241,7 +1110,7 @@ traverse_socks5 (int print_fd, int sok, char *serverAddr, int port)
{
if (buf[1] != 0)
{
proxy_error (print_fd, "SOCKS\tAuthentication required but disabled in settings.\n");
*error = g_error_new_literal (HEXCHAT_CONNECTION_ERROR, PROXY_FAILED, "SOCKS\tAuthentication required but disabled in settings.\n");
return 1;
}
}
@ -1268,7 +1137,7 @@ traverse_socks5 (int print_fd, int sok, char *serverAddr, int port)
g_snprintf (buf, sizeof (buf), "SOCKS\tProxy refused to connect to host (not allowed).\n");
else
g_snprintf (buf, sizeof (buf), "SOCKS\tProxy failed to connect to host (error %d).\n", buf[1]);
proxy_error (print_fd, buf);
*error = g_error_new_literal (HEXCHAT_CONNECTION_ERROR, PROXY_FAILED, buf);
return 1;
}
if (buf[3] == 1) /* IPV4 32bit address */
@ -1291,12 +1160,12 @@ traverse_socks5 (int print_fd, int sok, char *serverAddr, int port)
return 0; /* success */
read_error:
proxy_error (print_fd, "SOCKS\tRead error from server.\n");
*error = g_error_new_literal (HEXCHAT_CONNECTION_ERROR, PROXY_FAILED, "SOCKS\tRead error from server.\n");
return 1;
}
static int
traverse_wingate (int print_fd, int sok, char *serverAddr, int port)
traverse_wingate (int sok, char *serverAddr, int port, GError **error)
{
char buf[128];
@ -1358,30 +1227,7 @@ base64_encode (char *to, char *from, unsigned int len)
}
static int
http_read_line (int print_fd, int sok, char *buf, int len)
{
len = waitline (sok, buf, len, TRUE);
if (len >= 1)
{
/* print the message out (send it to the parent process) */
write (print_fd, "0\n", 2);
if (buf[len-1] == '\r')
{
buf[len-1] = '\n';
write (print_fd, buf, len);
} else
{
write (print_fd, buf, len);
write (print_fd, "\n", 1);
}
}
return len;
}
static int
traverse_http (int print_fd, int sok, char *serverAddr, int port)
traverse_http (int sok, char *serverAddr, int port, GError **error)
{
char buf[512];
char auth_data[256];
@ -1400,16 +1246,18 @@ traverse_http (int print_fd, int sok, char *serverAddr, int port)
n += g_snprintf (buf+n, sizeof (buf)-n, "\r\n");
send (sok, buf, n, 0);
n = http_read_line (print_fd, sok, buf, sizeof (buf));
n = waitline (sok, buf, sizeof(buf), TRUE);
/* "HTTP/1.0 200 OK" */
if (n < 12)
return 1;
if (memcmp (buf, "HTTP/", 5) || memcmp (buf + 9, "200", 3))
if (n < 12 || (memcmp (buf, "HTTP/", 5) || memcmp (buf + 9, "200", 3)))
{
*error = g_error_new_literal (HEXCHAT_CONNECTION_ERROR, PROXY_FAILED, buf);
return 1;
}
while (1)
{
/* read until blank line */
n = http_read_line (print_fd, sok, buf, sizeof (buf));
n = waitline (sok, buf, sizeof(buf), TRUE);
if (n < 1 || (n == 1 && buf[0] == '\n'))
break;
}
@ -1417,63 +1265,203 @@ traverse_http (int print_fd, int sok, char *serverAddr, int port)
}
static int
traverse_proxy (int proxy_type, int print_fd, int sok, char *ip, int port, netstore *ns_proxy, int csok4, int csok6, int *csok, char bound)
traverse_proxy (int proxy_type, int sok, char *ip, int port, GError **error)
{
switch (proxy_type)
{
case 1:
return traverse_wingate (print_fd, sok, ip, port);
return traverse_wingate (sok, ip, port, error);
case 2:
return traverse_socks (print_fd, sok, ip, port);
return traverse_socks (sok, ip, port, error);
case 3:
return traverse_socks5 (print_fd, sok, ip, port);
return traverse_socks5 (sok, ip, port, error);
case 4:
return traverse_http (print_fd, sok, ip, port);
return traverse_http (sok, ip, port, error);
}
return 1;
}
/* this is the child process making the connection attempt */
struct connect_data
{
server *serv;
char *local_ip;
char *hostname;
char *proxy_hostname;
char *ip;
char *port;
};
static int
server_child (server * serv)
static void
connect_data_free (struct connect_data *data)
{
if (data)
{
g_free (data->local_ip);
g_free (data->hostname);
g_free (data->proxy_hostname);
g_free (data->ip);
g_free (data->port);
g_free (data);
}
}
static void
server_connect_finish (GObject *source, GAsyncResult *res, gpointer user_data)
{
GError *error = NULL;
server *serv;
session *sess;
struct connect_data *data;
gboolean retry = FALSE;
char buf[256];
data = (struct connect_data*)g_task_get_task_data (G_TASK(res));
serv = data->serv;
if (!is_server(serv))
{
g_warning ("Server destroyed before connection finished!\n");
return;
}
sess = serv->server_session;
/* These print after the fact, but should be good enough */
if (data->proxy_hostname)
EMIT_SIGNAL (XP_TE_SERVERLOOKUP, sess, data->proxy_hostname, NULL, NULL, NULL, 0);
EMIT_SIGNAL (XP_TE_CONNECT, sess, data->hostname, data->ip, data->port, NULL, 0);
/* Update local ip for dcc */
if (data->local_ip)
prefs.local_ip = inet_addr (data->local_ip);
serv->sok = g_task_propagate_int (G_TASK(res), &error);
if (!error)
{
if (serv->sok == serv->sok4)
closesocket (serv->sok6);
else
closesocket (serv->sok4);
if (serv->proxy_sok != -1)
{
if (serv->proxy_sok == serv->proxy_sok4)
closesocket (serv->proxy_sok6);
else
closesocket (serv->proxy_sok4);
}
{
struct sockaddr addr;
int addr_len = sizeof (addr);
guint16 port;
if (!getsockname (serv->sok, &addr, &addr_len))
{
if (addr.sa_family == AF_INET)
port = ntohs(((struct sockaddr_in *)&addr)->sin_port);
else
port = ntohs(((struct sockaddr_in6 *)&addr)->sin6_port);
g_snprintf (buf, sizeof (buf), "IDENTD %"G_GUINT16_FORMAT" ", port);
if (serv->network && ((ircnet *)serv->network)->user)
g_strlcat (buf, ((ircnet *)serv->network)->user, sizeof (buf));
else
g_strlcat (buf, prefs.hex_irc_user_name, sizeof (buf));
handle_command (serv->server_session, buf, FALSE);
}
}
server_connect_success (serv);
return;
}
g_warning ("%s\n", error->message);
switch (error->code)
{
case RESOLVE_FAILED:
retry = TRUE;
EMIT_SIGNAL (XP_TE_UKNHOST, sess, NULL, NULL, NULL, NULL, 0);
goto close_connection;
case CONNECTION_FAILED:
retry = TRUE;
EMIT_SIGNAL (XP_TE_CONNFAIL, sess, error->message, NULL, NULL, NULL, 0);
goto close_connection;
case BIND_FAILED:
PrintText (sess, error->message);
break;
case PROXY_FAILED:
PrintTextf (sess, _("Proxy Traveral Failed: %s\n"), error->message);
server_disconnect (sess, FALSE, -1);
break;
case 9:
EMIT_SIGNAL (XP_TE_SERVERLOOKUP, sess, error->message, NULL, NULL, NULL, 0);
break;
case G_IO_ERROR_CANCELLED:
EMIT_SIGNAL (XP_TE_STOPCONNECT, sess, NULL, NULL, NULL, NULL, 0);
goto close_connection;
default:
g_warning ("%d\n", error->code);
g_assert_not_reached ();
}
return;
close_connection:
server_stopconnecting (serv);
closesocket (serv->sok4);
if (serv->proxy_sok4 != -1)
closesocket (serv->proxy_sok4);
if (serv->sok6 != -1)
closesocket (serv->sok6);
if (serv->proxy_sok6 != -1)
closesocket (serv->proxy_sok6);
if (retry && !servlist_cycle (serv) && prefs.hex_net_auto_reconnectonfail)
auto_reconnect (serv, FALSE, -1);
}
static void
server_connect_thread (GTask *task, gpointer source, gpointer task_data, GCancellable *cancellable)
{
netstore *ns_server;
netstore *ns_proxy = NULL;
netstore *ns_local;
struct connect_data *data = (struct connect_data*)task_data;
server *serv = data->serv;
int port = serv->port;
int error;
int sok, psok;
int sok = -1, psok;
char *hostname = serv->hostname;
char *real_hostname = NULL;
char *ip;
char *proxy_ip = NULL;
char *local_ip;
int connect_port;
char buf[512];
char bound = 0;
int proxy_type = 0;
char *proxy_host = NULL;
int proxy_port;
if (!is_server(serv))
{
g_warning ("Server destroyed before connection started!\n");
return;
}
ns_server = net_store_new ();
/* is a hostname set? - bind to it */
if (prefs.hex_net_bind_host[0])
{
ns_local = net_store_new ();
local_ip = net_resolve (ns_local, prefs.hex_net_bind_host, 0, &real_hostname);
if (local_ip != NULL)
netstore *ns_local = net_store_new ();
data->local_ip = net_resolve (ns_local, prefs.hex_net_bind_host, 0, NULL);
if (data->local_ip != NULL)
{
g_snprintf (buf, sizeof (buf), "5\n%s\n", local_ip);
write (serv->childwrite, buf, strlen (buf));
net_bind (ns_local, serv->sok4, serv->sok6);
bound = 1;
} else
{
write (serv->childwrite, "7\n", 2);
g_task_return_new_error (task, HEXCHAT_CONNECTION_ERROR, BIND_FAILED,
"Cannot resolve hostname %s\nCheck your IP Settings!\n", prefs.hex_net_bind_host);
net_store_destroy (ns_local);
goto error_cleanup;
}
net_store_destroy (ns_local);
}
@ -1523,49 +1511,49 @@ server_child (server * serv)
proxy_port = prefs.hex_net_proxy_port;
}
}
serv->proxy_type = proxy_type;
data->proxy_hostname = proxy_host;
/* first resolve where we want to connect to */
if (proxy_type > 0)
{
g_snprintf (buf, sizeof (buf), "9\n%s\n", proxy_host);
write (serv->childwrite, buf, strlen (buf));
ip = net_resolve (ns_server, proxy_host, proxy_port, &real_hostname);
g_free (proxy_host);
if (!ip)
data->ip = net_resolve (ns_server, proxy_host, proxy_port, &data->hostname);
if (!data->ip)
{
write (serv->childwrite, "1\n", 2);
goto xit;
g_task_return_new_error (task, HEXCHAT_CONNECTION_ERROR, RESOLVE_FAILED,
"Unknown hostname %s\n", proxy_host);
goto error_cleanup;
}
connect_port = proxy_port;
/* if using socks4 or MS Proxy, attempt to resolve ip for irc server */
/* if using socks4, attempt to resolve ip for irc server */
if ((proxy_type == 2) || (proxy_type == 5))
{
ns_proxy = net_store_new ();
proxy_ip = net_resolve (ns_proxy, hostname, port, &real_hostname);
netstore *ns_proxy = net_store_new ();
g_free (data->hostname);
proxy_ip = net_resolve (ns_proxy, hostname, port, &data->hostname);
net_store_destroy (ns_proxy);
if (!proxy_ip)
{
write (serv->childwrite, "1\n", 2);
goto xit;
g_task_return_new_error (task, HEXCHAT_CONNECTION_ERROR, RESOLVE_FAILED,
"Unknown hostname %s\n", hostname);
goto error_cleanup;
}
} else /* otherwise we can just use the hostname */
proxy_ip = g_strdup (hostname);
} else
}
else
{
ip = net_resolve (ns_server, hostname, port, &real_hostname);
if (!ip)
data->ip = net_resolve (ns_server, hostname, port, &data->hostname);
if (!data->ip)
{
write (serv->childwrite, "1\n", 2);
goto xit;
g_task_return_new_error (task, HEXCHAT_CONNECTION_ERROR, RESOLVE_FAILED,
"Unknown hostname %s\n", hostname);
goto error_cleanup;
}
connect_port = port;
}
g_snprintf (buf, sizeof (buf), "3\n%s\n%s\n%d\n",
real_hostname, ip, connect_port);
write (serv->childwrite, buf, strlen (buf));
data->port = g_strdup_printf ("%d", connect_port);
if (!serv->dont_use_proxy && (proxy_type == 5))
error = net_connect (ns_server, serv->proxy_sok4, serv->proxy_sok6, &psok);
@ -1577,54 +1565,33 @@ server_child (server * serv)
if (error != 0)
{
g_snprintf (buf, sizeof (buf), "2\n%d\n", sock_error ());
write (serv->childwrite, buf, strlen (buf));
} else
g_task_return_new_error (task, HEXCHAT_CONNECTION_ERROR, CONNECTION_FAILED, "%s", errorstring (sock_error()));
goto error_cleanup;
}
else
{
GError *err = NULL;
/* connect succeeded */
if (proxy_ip)
if (proxy_ip && traverse_proxy (proxy_type, psok, proxy_ip, port, &err))
{
switch (traverse_proxy (proxy_type, serv->childwrite, psok, proxy_ip, port, ns_proxy, serv->sok4, serv->sok6, &sok, bound))
{
case 0: /* success */
g_snprintf (buf, sizeof (buf), "4\n%d\n", sok); /* success */
write (serv->childwrite, buf, strlen (buf));
break;
case 1: /* socks traversal failed */
write (serv->childwrite, "8\n", 2);
break;
}
} else
{
g_snprintf (buf, sizeof (buf), "4\n%d\n", sok); /* success */
write (serv->childwrite, buf, strlen (buf));
g_task_return_error (task, err);
goto error_cleanup;
}
}
xit:
/* this is probably not needed */
error_cleanup:
net_store_destroy (ns_server);
if (ns_proxy)
net_store_destroy (ns_proxy);
/* no need to free ip/real_hostname, this process is exiting */
#ifdef WIN32
/* under win32 we use a thread -> shared memory, must free! */
g_free (proxy_ip);
g_free (ip);
g_free (real_hostname);
#endif
return 0;
/* cppcheck-suppress memleak */
g_task_return_int (task, sok); /* Does nothing if error'd */
return;
}
static void
server_connect (server *serv, char *hostname, int port, int no_login)
{
int pid, read_des[2];
session *sess = serv->server_session;
GTask *task;
struct connect_data *data;
#ifdef USE_OPENSSL
if (!serv->ctx && serv->use_ssl)
@ -1700,55 +1667,20 @@ server_connect (server *serv, char *hostname, int port, int no_login)
fe_set_away (serv);
server_flush_queue (serv);
#ifdef WIN32
if (_pipe (read_des, 4096, _O_BINARY) < 0)
#else
if (pipe (read_des) < 0)
#endif
return;
#ifdef __EMX__ /* os/2 */
setmode (read_des[0], O_BINARY);
setmode (read_des[1], O_BINARY);
#endif
serv->childread = read_des[0];
serv->childwrite = read_des[1];
/* create both sockets now, drop one later */
net_sockets (&serv->sok4, &serv->sok6);
serv->proxy_sok4 = -1;
serv->proxy_sok6 = -1;
#ifdef WIN32
CloseHandle (CreateThread (NULL, 0,
(LPTHREAD_START_ROUTINE)server_child,
serv, 0, (DWORD *)&pid));
#else
#ifdef LOOKUPD
/* CL: net_resolve calls rand() when LOOKUPD is set, so prepare a different
* seed for each child. This method gives a bigger variation in seed values
* than calling srand(time(0)) in the child itself.
*/
rand();
#endif
switch (pid = fork ())
{
case -1:
return;
case 0:
/* this is the child */
setuid (getuid ());
server_child (serv);
_exit (0);
}
#endif
serv->childpid = pid;
#ifdef WIN32
serv->iotag = fe_input_add (serv->childread, FIA_READ|FIA_FD, server_read_child,
#else
serv->iotag = fe_input_add (serv->childread, FIA_READ, server_read_child,
#endif
serv);
/* start the connection in a thread */
data = g_new0 (struct connect_data, 1);
data->serv = serv;
serv->cancellable = g_cancellable_new ();
task = g_task_new (NULL, serv->cancellable, server_connect_finish, NULL);
g_task_set_task_data (task, data, (GDestroyNotify)connect_data_free);
g_task_set_return_on_cancel (task, TRUE);
g_task_run_in_thread (task, server_connect_thread);
g_object_unref (task);
}
void

View File

@ -751,8 +751,8 @@ n2
Stop Connection
XP_TE_STOPCONNECT
pevt_sconnect_help
%C23*%O$tStopped previous connection attempt (%C24$1%O)
1
%C23*%O$tStopped previous connection attempt
0
Topic
XP_TE_TOPIC

View File

@ -207,34 +207,6 @@ waitline (int sok, char *buf, int bufsize, int use_recv)
}
}
#ifdef WIN32
/* waitline2 using win32 file descriptor and glib instead of _read. win32 can't _read() sok! */
int
waitline2 (GIOChannel *source, char *buf, int bufsize)
{
int i = 0;
gsize len;
GError *error = NULL;
while (1)
{
g_io_channel_set_buffered (source, FALSE);
g_io_channel_set_encoding (source, NULL, &error);
if (g_io_channel_read_chars (source, &buf[i], 1, &len, &error) != G_IO_STATUS_NORMAL)
{
return -1;
}
if (buf[i] == '\n' || bufsize == i + 1)
{
buf[i] = 0;
return i;
}
i++;
}
}
#endif
/* checks for "~" in a file and expands */
char *

View File

@ -61,10 +61,7 @@ int strip_hidden_attribute (char *src, char *dst);
char *errorstring (int err);
int waitline (int sok, char *buf, int bufsize, int);
#ifdef WIN32
int waitline2 (GIOChannel *source, char *buf, int bufsize);
int get_cpu_arch (void);
#else
#define waitline2(source,buf,size) waitline(serv->childread,buf,size,0)
#endif
unsigned long make_ping_time (void);
void move_file (char *src_dir, char *dst_dir, char *fname, int dccpermissions);