Initial work using Gio for server connections

This commit is contained in:
TingPing 2015-01-02 11:31:29 -05:00
parent eb08bcfacf
commit 480fa3cefc
11 changed files with 293 additions and 322 deletions

View File

@ -38,7 +38,6 @@ AH_VERBATIM([OLD_PERL],[#undef OLD_PERL])
AH_VERBATIM([PREFIX],[#undef PREFIX]) AH_VERBATIM([PREFIX],[#undef PREFIX])
AH_VERBATIM([HEXCHATLIBDIR],[#undef HEXCHATLIBDIR]) AH_VERBATIM([HEXCHATLIBDIR],[#undef HEXCHATLIBDIR])
AH_VERBATIM([HEXCHATSHAREDIR],[#undef HEXCHATSHAREDIR]) AH_VERBATIM([HEXCHATSHAREDIR],[#undef HEXCHATSHAREDIR])
AH_VERBATIM([USE_LIBPROXY],[#undef USE_LIBPROXY])
AH_VERBATIM([HAVE_ISO_CODES],[#undef HAVE_ISO_CODES]) AH_VERBATIM([HAVE_ISO_CODES],[#undef HAVE_ISO_CODES])
AH_VERBATIM([HAVE_GTK_MAC],[#undef HAVE_GTK_MAC]) AH_VERBATIM([HAVE_GTK_MAC],[#undef HAVE_GTK_MAC])
AH_VERBATIM([USE_LIBNOTIFY],[#undef USE_LIBNOTIFY]) AH_VERBATIM([USE_LIBNOTIFY],[#undef USE_LIBNOTIFY])
@ -139,10 +138,6 @@ AC_ARG_ENABLE(libcanberra,
[AS_HELP_STRING([--disable-libcanberra],[disable libcanberra support])], [AS_HELP_STRING([--disable-libcanberra],[disable libcanberra support])],
libcanberra=$enableval, libcanberra=yes) libcanberra=$enableval, libcanberra=yes)
AC_ARG_ENABLE(libproxy,
[AS_HELP_STRING([--disable-libproxy],[disable libproxy support (default: auto)])],
libproxy=$enableval, libproxy=auto)
AC_ARG_ENABLE(isocodes, AC_ARG_ENABLE(isocodes,
[AS_HELP_STRING([--disable-isocodes],[disable iso-codes with spell-check])], [AS_HELP_STRING([--disable-isocodes],[disable iso-codes with spell-check])],
isocodes=$enableval, isocodes=yes) isocodes=$enableval, isocodes=yes)
@ -400,26 +395,6 @@ if test "$retry" = "yes"; then
LIBS=$SAVED_LIBS LIBS=$SAVED_LIBS
fi fi
dnl *********************************************************************
dnl ** LIBPROXY *********************************************************
dnl *********************************************************************
if test "x$libproxy" = "xyes" -o "x$libproxy" = "xauto" ; then
PKG_CHECK_MODULES([LIBPROXY], [libproxy-1.0], [
COMMON_LIBS="$COMMON_LIBS $LIBPROXY_LIBS"
COMMON_CFLAGS="$COMMON_CFLAGS $LIBPROXY_CFLAGS"
AC_DEFINE(USE_LIBPROXY)
libproxy=yes
], [
if test "x$libproxy" = "xyes" ; then
AC_MSG_ERROR(Cannot find libproxy!)
fi
libproxy=no
])
else
libproxy=no
fi
dnl ********************************************************************* dnl *********************************************************************
dnl ** PLUGIN *********************************************************** dnl ** PLUGIN ***********************************************************
dnl ********************************************************************* dnl *********************************************************************
@ -817,7 +792,6 @@ echo D-Bus support ......... : $dbus
echo libnotify support ..... : $libnotify echo libnotify support ..... : $libnotify
echo libcanberra support ... : $libcanberra echo libcanberra support ... : $libcanberra
echo Plugin interface ...... : $plugin echo Plugin interface ...... : $plugin
echo libproxy support ...... : $libproxy
echo echo
echo Perl .................. : $perl echo Perl .................. : $perl
echo Python ................ : $python echo Python ................ : $python

View File

@ -63,7 +63,6 @@ libhexchatcommon_a_SOURCES = cfgfiles.c chanopt.c ctcp.c dcc.c hexchat.c \
history.c ignore.c inbound.c marshal.c modes.c network.c notify.c \ history.c ignore.c inbound.c marshal.c modes.c network.c notify.c \
outbound.c plugin.c plugin-identd.c plugin-timer.c proto-irc.c server.c servlist.c \ outbound.c plugin.c plugin-identd.c plugin-timer.c proto-irc.c server.c servlist.c \
$(ssl_c) text.c tree.c url.c userlist.c util.c $(ssl_c) text.c tree.c url.c userlist.c util.c
libhexchatcommon_a_CFLAGS = $(LIBPROXY_CFLAGS)
textenums.h: textevents.h textenums.h: textevents.h

View File

@ -83,6 +83,15 @@ static gboolean dcc_send_data (GIOChannel *, GIOCondition, struct DCC *);
static gboolean dcc_read (GIOChannel *, GIOCondition, struct DCC *); static gboolean dcc_read (GIOChannel *, GIOCondition, struct DCC *);
static gboolean dcc_read_ack (GIOChannel *source, GIOCondition condition, struct DCC *dcc); static gboolean dcc_read_ack (GIOChannel *source, GIOCondition condition, struct DCC *dcc);
char *
net_ip (guint32 addr)
{
struct in_addr ia;
ia.s_addr = htonl (addr);
return inet_ntoa (ia);
}
static int new_id() static int new_id()
{ {
static int id = 0; static int id = 0;
@ -1668,6 +1677,7 @@ dcc_listen_init (struct DCC *dcc, session *sess)
if (dcc->sok == -1) if (dcc->sok == -1)
return FALSE; return FALSE;
#if 0
memset (&SAddr, 0, sizeof (struct sockaddr_in)); memset (&SAddr, 0, sizeof (struct sockaddr_in));
len = sizeof (SAddr); len = sizeof (SAddr);
@ -1704,6 +1714,7 @@ dcc_listen_init (struct DCC *dcc, session *sess)
setsockopt (dcc->sok, SOL_SOCKET, SO_REUSEADDR, (char *) &len, sizeof (len)); setsockopt (dcc->sok, SOL_SOCKET, SO_REUSEADDR, (char *) &len, sizeof (len));
} else } else
#endif
{ {
/* try random port */ /* try random port */
SAddr.sin_port = 0; SAddr.sin_port = 0;

View File

@ -123,5 +123,6 @@ void handle_dcc (session *sess, char *nick, char *word[], char *word_eol[],
void dcc_show_list (session *sess); void dcc_show_list (session *sess);
guint32 dcc_get_my_address (void); guint32 dcc_get_my_address (void);
void dcc_get_with_destfile (struct DCC *dcc, char *utf8file); void dcc_get_with_destfile (struct DCC *dcc, char *utf8file);
char *net_ip (guint32 addr);
#endif #endif

View File

@ -56,10 +56,6 @@
#include <glib-object.h> /* for g_type_init() */ #include <glib-object.h> /* for g_type_init() */
#endif #endif
#ifdef USE_LIBPROXY
#include <proxy.h>
#endif
GSList *popup_list = 0; GSList *popup_list = 0;
GSList *button_list = 0; GSList *button_list = 0;
GSList *dlgbutton_list = 0; GSList *dlgbutton_list = 0;
@ -110,10 +106,6 @@ struct session *current_tab;
struct session *current_sess = 0; struct session *current_sess = 0;
struct hexchatprefs prefs; struct hexchatprefs prefs;
#ifdef USE_LIBPROXY
pxProxyFactory *libproxy_factory;
#endif
/* /*
* Update the priority queue of the "interesting sessions" * Update the priority queue of the "interesting sessions"
* (sess_list_by_lastact). * (sess_list_by_lastact).
@ -1048,10 +1040,6 @@ main (int argc, char *argv[])
hexchat_remote (); hexchat_remote ();
#endif #endif
#ifdef USE_LIBPROXY
libproxy_factory = px_proxy_factory_new();
#endif
fe_init (); fe_init ();
/* This is done here because cfgfiles.c is too early in /* This is done here because cfgfiles.c is too early in
@ -1079,10 +1067,6 @@ main (int argc, char *argv[])
fe_main (); fe_main ();
#ifdef USE_LIBPROXY
px_proxy_factory_free(libproxy_factory);
#endif
#ifdef WIN32 #ifdef WIN32
WSACleanup (); WSACleanup ();
#endif #endif

View File

@ -471,14 +471,10 @@ typedef struct server
int (*p_raw)(struct server *, char *raw); int (*p_raw)(struct server *, char *raw);
int (*p_cmp)(const char *s1, const char *s2); int (*p_cmp)(const char *s1, const char *s2);
int port; guint16 port;
int sok; /* is equal to sok4 or sok6 (the one we are using) */ GSocket *sok; /* is equal to sok4 or sok6 (the one we are using) */
int sok4; /* tcp4 socket */ GSocket *sok4; /* tcp4 socket */
int sok6; /* tcp6 socket */ GSocket *sok6; /* tcp6 socket */
int proxy_type;
int proxy_sok; /* Additional information for MS Proxy beast */
int proxy_sok4;
int proxy_sok6;
int id; /* unique ID number (for plugin API) */ int id; /* unique ID number (for plugin API) */
#ifdef USE_OPENSSL #ifdef USE_OPENSSL
SSL_CTX *ctx; SSL_CTX *ctx;

View File

@ -20,53 +20,18 @@
#include "config.h" #include "config.h"
#include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdio.h>
#include <glib.h> #include <glib.h>
#include <gio/gio.h>
#ifndef WIN32
#include <unistd.h>
#endif
#define WANTSOCKET
#define WANTARPA
#define WANTDNS
#include "inet.h"
#define NETWORK_PRIVATE
#include "network.h" #include "network.h"
#define RAND_INT(n) ((int)(rand() / (RAND_MAX + 1.0) * (n)))
/* ================== COMMON ================= */
static void
net_set_socket_options (int sok)
{
socklen_t sw;
sw = 1;
setsockopt (sok, SOL_SOCKET, SO_REUSEADDR, (char *) &sw, sizeof (sw));
sw = 1;
setsockopt (sok, SOL_SOCKET, SO_KEEPALIVE, (char *) &sw, sizeof (sw));
}
char *
net_ip (guint32 addr)
{
struct in_addr ia;
ia.s_addr = htonl (addr);
return inet_ntoa (ia);
}
void void
net_store_destroy (netstore * ns) net_store_destroy (netstore *ns)
{ {
if (ns->ip6_hostent) g_return_if_fail (ns != NULL);
freeaddrinfo (ns->ip6_hostent);
g_resolver_free_addresses (ns->addrs);
g_free (ns); g_free (ns);
} }
@ -76,118 +41,208 @@ net_store_new (void)
return g_new0 (netstore, 1); return g_new0 (netstore, 1);
} }
/* =================== IPV6 ================== */
char * char *
net_resolve (netstore * ns, char *hostname, int port, char **real_host) net_resolve (netstore *ns, char *hostname, char **real_host, GError **error)
{ {
struct addrinfo hints; GResolver *res;
char ipstring[MAX_HOSTNAME]; GList *addrs;
char portstring[MAX_HOSTNAME]; GInetAddress *addr;
int ret; char *ipstring;
/* if (ns->ip6_hostent) res = g_resolver_get_default ();
freeaddrinfo (ns->ip6_hostent);*/
sprintf (portstring, "%d", port); // todo: lookup by irc service?
addrs = g_resolver_lookup_by_name (res, hostname, NULL, error);
memset (&hints, 0, sizeof (struct addrinfo)); if (!addrs)
hints.ai_family = PF_UNSPEC; /* support ipv6 and ipv4 */ {
hints.ai_flags = AI_CANONNAME | AI_ADDRCONFIG; g_object_unref (res);
hints.ai_socktype = SOCK_STREAM;
if (port == 0)
ret = getaddrinfo (hostname, NULL, &hints, &ns->ip6_hostent);
else
ret = getaddrinfo (hostname, portstring, &hints, &ns->ip6_hostent);
if (ret != 0)
return NULL; return NULL;
}
#ifdef LOOKUPD /* See note about lookupd above the IPv4 version of net_resolve. */ ns->addrs = addrs;
struct addrinfo *tmp; addr = G_INET_ADDRESS(addrs->data);
int count = 0; ipstring = g_inet_address_to_string (addr);
for (tmp = ns->ip6_hostent; tmp; tmp = tmp->ai_next)
count ++;
count = RAND_INT(count);
while (count--) ns->ip6_hostent = ns->ip6_hostent->ai_next;
#endif
/* find the numeric IP number */
ipstring[0] = 0;
getnameinfo (ns->ip6_hostent->ai_addr, ns->ip6_hostent->ai_addrlen,
ipstring, sizeof (ipstring), NULL, 0, NI_NUMERICHOST);
if (real_host) if (real_host)
{ {
if (ns->ip6_hostent->ai_canonname) if (!(*real_host = g_resolver_lookup_by_address (res, addr, NULL, NULL)))
*real_host = g_strdup (ns->ip6_hostent->ai_canonname);
else
*real_host = g_strdup (hostname); *real_host = g_strdup (hostname);
} }
return g_strdup (ipstring); g_object_unref (res);
return ipstring;
} }
/* the only thing making this interface unclean, this shitty sok4, sok6 business */ /* the only thing making this interface unclean, this shitty sok4, sok6 business */
int GSocket *
net_connect (netstore * ns, int sok4, int sok6, int *sok_return) net_connect (netstore *ns, guint16 port, GSocket *sok4, GSocket *sok6, GError **error)
{ {
struct addrinfo *res, *res0; GSocket *sok;
int error = -1; GList *addrs;
gboolean success;
res0 = ns->ip6_hostent; for (addrs = ns->addrs; addrs; addrs = g_list_next (addrs))
for (res = res0; res; res = res->ai_next)
{ {
/* sok = socket (res->ai_family, res->ai_socktype, res->ai_protocol); GInetAddress *inet_addr = G_INET_ADDRESS(addrs->data);
if (sok < 0) GSocketAddress *sok_addr;
continue;*/
switch (res->ai_family)
{
case AF_INET:
error = connect (sok4, res->ai_addr, res->ai_addrlen);
*sok_return = sok4;
break;
case AF_INET6:
error = connect (sok6, res->ai_addr, res->ai_addrlen);
*sok_return = sok6;
break;
default:
error = 1;
}
if (error == 0) g_clear_error (error); /* Last failed attempt set */
break;
sok_addr = g_inet_socket_address_new (inet_addr, port);
if (g_socket_address_get_family (sok_addr) == G_SOCKET_FAMILY_IPV4)
sok = sok4;
else
sok = sok6;
success = g_socket_connect (sok, sok_addr, NULL, error);
g_object_unref (sok_addr);
if (success)
return sok;
}
return NULL;
}
gboolean
net_bind (netstore *ns, GSocket *sok4, GSocket *sok6, GError **error4, GError **error6)
{
GInetAddress *inet_addr = G_INET_ADDRESS(ns->addrs->data);
GSocketAddress *sok_addr;
gboolean success;
sok_addr = g_inet_socket_address_new (inet_addr, 0);
success = g_socket_bind (sok4, sok_addr, TRUE, error4);
success &= g_socket_bind (sok6, sok_addr, TRUE, error6);
g_object_unref (sok_addr);
return success;
}
void
net_sockets (GSocket **sok4, GSocket **sok6, GError **error4, GError **error6)
{
*sok4 = g_socket_new (G_SOCKET_FAMILY_IPV4, G_SOCKET_TYPE_STREAM, G_SOCKET_PROTOCOL_TCP, error4);
*sok6 = g_socket_new (G_SOCKET_FAMILY_IPV6, G_SOCKET_TYPE_STREAM, G_SOCKET_PROTOCOL_TCP, error6);
if (!*sok4 || !*sok6)
{
g_warning ("Creating sockets failed\n");
return;
} }
return error; g_socket_set_keepalive (*sok4, TRUE);
g_socket_set_keepalive (*sok6, TRUE);
}
char *
net_resolve_proxy (const char *hostname, guint16 port, GError **error)
{
GProxyResolver *res;
char *uri;
char **proxies;
char *proxy = NULL;
guint i;
res = g_proxy_resolver_get_default ();
if (!res)
return NULL;
// FIXME: ircs also
uri = g_strdup_printf ("irc://%s:%d", hostname, port);
proxies = g_proxy_resolver_lookup (res, uri, NULL, error);
g_free (uri);
if (g_strv_length (proxies) == 0)
return NULL;
for (i = 0; i < g_strv_length (proxies); i++)
{
int type;
net_parse_proxy_uri (proxies[i], NULL, NULL, &type);
if (type != -1)
{
proxy = g_strdup (proxies[i]);
break;
}
}
g_strfreev (proxies);
if (!proxy) /* FIXME: error code */
*error = g_error_new_literal (0, 0, "No system proxy found that is supported");
return proxy;
} }
void void
net_bind (netstore * tobindto, int sok4, int sok6) net_parse_proxy_uri (const char *proxy_uri, char **host, guint16 *port, int *type)
{ {
bind (sok4, tobindto->ip6_hostent->ai_addr, if (type)
tobindto->ip6_hostent->ai_addrlen); {
bind (sok6, tobindto->ip6_hostent->ai_addr, char *scheme = g_uri_parse_scheme (proxy_uri);
tobindto->ip6_hostent->ai_addrlen);
if (!strcmp (scheme, "direct"))
*type = 0;
else if (!strcmp (scheme, "http"))
*type = 4;
else if (!strcmp (scheme, "socks5"))
*type = 3;
else if (!strcmp (scheme, "socks"))
*type = 2;
else
*type = -1;
g_free (scheme);
}
if (host)
{
char *c1, *c2;
c1 = strchr (proxy_uri, ':') + 3;
if (c1)
{
c2 = strrchr (c1, ':');
if (c2)
*host = g_strndup (c1, c2 - c1);
else
*host = g_strdup (c1);
}
else
*host = NULL;
}
if (port)
{
char *c;
guint64 p;
c = strrchr (proxy_uri, ':');
if (c)
{
p = g_ascii_strtoull (c + 1, NULL, 0);
if (p <= G_MAXUINT16)
*port = (guint16)p;
}
else
*port = 0;
}
} }
void guint16
net_sockets (int *sok4, int *sok6) net_get_local_port (GSocket *sok)
{ {
*sok4 = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); GSocketAddress *addr;
*sok6 = socket (AF_INET6, SOCK_STREAM, IPPROTO_TCP); guint16 port;
net_set_socket_options (*sok4);
net_set_socket_options (*sok6);
}
void addr = g_socket_get_local_address (sok, NULL);
udp_sockets (int *sok4, int *sok6) if (!addr)
{ return 0;
*sok4 = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
*sok6 = socket (AF_INET6, SOCK_DGRAM, IPPROTO_UDP); port = g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS(addr));
g_object_unref (addr);
return port;
} }

View File

@ -22,21 +22,18 @@
typedef struct netstore_ typedef struct netstore_
{ {
#ifdef NETWORK_PRIVATE GList *addrs;
struct addrinfo *ip6_hostent;
#else
int _dummy; /* some compilers don't like empty structs */
#endif
} netstore; } netstore;
#define MAX_HOSTNAME 128 #define MAX_HOSTNAME 128
netstore *net_store_new (void); netstore *net_store_new (void);
void net_store_destroy (netstore *ns); void net_store_destroy (netstore *ns);
int net_connect (netstore *ns, int sok4, int sok6, int *sok_return); GSocket *net_connect (netstore *ns, guint16 port, GSocket *sok4, GSocket *sok6, GError **error);
char *net_resolve (netstore *ns, char *hostname, int port, char **real_host); char *net_resolve (netstore *ns, char *hostname, char **real_host, GError **error);
void net_bind (netstore *tobindto, int sok4, int sok6); char * net_resolve_proxy (const char *hostname, guint16 port, GError **error);
char *net_ip (guint32 addr); gboolean net_bind (netstore *ns, GSocket *sok4, GSocket *sok6, GError **error4, GError **error6);
void net_sockets (int *sok4, int *sok6); void net_sockets (GSocket **sok4, GSocket **sok6, GError **error4, GError **error6);
void net_parse_proxy_uri (const char *proxy_uri, char **host, guint16 *port, int *type);
guint16 net_get_local_port (GSocket *sok);
#endif #endif

View File

@ -907,7 +907,7 @@ cmd_debug (struct session *sess, char *tbuf, char *word[], char *word_eol[])
{ {
v = (struct server *) list->data; v = (struct server *) list->data;
sprintf (tbuf, "%p %-5d %s\n", sprintf (tbuf, "%p %-5d %s\n",
v, v->sok, v->servername); v, g_socket_get_fd (v->sok), v->servername);
PrintText (sess, tbuf); PrintText (sess, tbuf);
list = list->next; list = list->next;
} }
@ -3205,7 +3205,7 @@ cmd_send (struct session *sess, char *tbuf, char *word[], char *word_eol[])
if (!word[2][0]) if (!word[2][0])
return FALSE; return FALSE;
#if 0
addr = dcc_get_my_address (); addr = dcc_get_my_address ();
if (addr == 0) if (addr == 0)
{ {
@ -3223,7 +3223,7 @@ cmd_send (struct session *sess, char *tbuf, char *word[], char *word_eol[])
g_snprintf (tbuf, 512, "DCC PSEND %s", word_eol[2]); g_snprintf (tbuf, 512, "DCC PSEND %s", word_eol[2]);
else else
g_snprintf (tbuf, 512, "DCC SEND %s", word_eol[2]); g_snprintf (tbuf, 512, "DCC SEND %s", word_eol[2]);
#endif
handle_command (sess, tbuf, FALSE); handle_command (sess, tbuf, FALSE);
return TRUE; return TRUE;

View File

@ -61,10 +61,6 @@
#include "ssl.h" #include "ssl.h"
#endif #endif
#ifdef USE_LIBPROXY
#include <proxy.h>
#endif
#define HEXCHAT_CONNECTION_ERROR g_quark_from_static_string("hexchat-connection-error") #define HEXCHAT_CONNECTION_ERROR g_quark_from_static_string("hexchat-connection-error")
#ifdef USE_OPENSSL #ifdef USE_OPENSSL
@ -80,10 +76,6 @@ static void server_disconnect (session * sess, int sendquit, int err);
static int server_cleanup (server * serv); static int server_cleanup (server * serv);
static void server_connect (server *serv, char *hostname, int port, int no_login); static void server_connect (server *serv, char *hostname, int port, int no_login);
#ifdef USE_LIBPROXY
extern pxProxyFactory *libproxy_factory;
#endif
enum enum
{ {
RESOLVE_FAILED = 1, RESOLVE_FAILED = 1,
@ -158,7 +150,7 @@ server_send_real (server *serv, char *buf, int len)
url_check_line (buf); url_check_line (buf);
return tcp_send_real (serv->ssl, serv->sok, serv->encoding, serv->using_irc, return tcp_send_real (serv->ssl, g_socket_get_fd (serv->sok), serv->encoding, serv->using_irc,
buf, len); buf, len);
} }
@ -294,15 +286,15 @@ tcp_sendf (server *serv, const char *fmt, ...)
static int static int
close_socket_cb (gpointer sok) close_socket_cb (gpointer sok)
{ {
closesocket (GPOINTER_TO_INT (sok)); g_object_unref (sok);
return 0; return 0;
} }
static void static void
close_socket (int sok) close_socket (GSocket *sok)
{ {
/* close the socket in 5 seconds so the QUIT message is not lost */ /* close the socket in 5 seconds so the QUIT message is not lost */
fe_timeout_add (5000, close_socket_cb, GINT_TO_POINTER (sok)); fe_timeout_add (5000, close_socket_cb, sok);
} }
/* handle 1 line of text received from the server */ /* handle 1 line of text received from the server */
@ -411,7 +403,7 @@ server_inline (server *serv, char *line, gssize len)
static gboolean static gboolean
server_read (GIOChannel *source, GIOCondition condition, server *serv) server_read (GIOChannel *source, GIOCondition condition, server *serv)
{ {
int sok = serv->sok; int sok = g_socket_get_fd (serv->sok);
int error, i, len; int error, i, len;
char lbuf[2050]; char lbuf[2050];
@ -489,8 +481,8 @@ server_connected (server * serv)
serv->ping_recv = time (0); serv->ping_recv = time (0);
serv->lag_sent = 0; serv->lag_sent = 0;
serv->connected = TRUE; serv->connected = TRUE;
set_nonblocking (serv->sok); g_socket_set_blocking (serv->sok, FALSE);
serv->iotag = fe_input_add (serv->sok, FIA_READ|FIA_EX, server_read, serv); serv->iotag = fe_input_add (g_socket_get_fd(serv->sok), G_IO_OUT|G_IO_ERR|G_IO_PRI, server_read, serv);
if (!serv->no_login) if (!serv->no_login)
{ {
EMIT_SIGNAL (XP_TE_CONNECTED, serv->server_session, NULL, NULL, NULL, EMIT_SIGNAL (XP_TE_CONNECTED, serv->server_session, NULL, NULL, NULL,
@ -860,7 +852,7 @@ server_connect_success (server *serv)
/* it'll be a memory leak, if connection isn't terminated by /* it'll be a memory leak, if connection isn't terminated by
server_cleanup() */ server_cleanup() */
serv->ssl = _SSL_socket (serv->ctx, serv->sok); serv->ssl = _SSL_socket (serv->ctx, g_socket_get_fd (serv->sok));
if ((err = _SSL_set_verify (serv->ctx, ssl_cb_verify, NULL))) if ((err = _SSL_set_verify (serv->ctx, ssl_cb_verify, NULL)))
{ {
EMIT_SIGNAL (XP_TE_CONNFAIL, serv->server_session, err, NULL, EMIT_SIGNAL (XP_TE_CONNFAIL, serv->server_session, err, NULL,
@ -870,7 +862,7 @@ server_connect_success (server *serv)
} }
/* FIXME: it'll be needed by new servers */ /* FIXME: it'll be needed by new servers */
/* send(serv->sok, "STLS\r\n", 6, 0); sleep(1); */ /* send(serv->sok, "STLS\r\n", 6, 0); sleep(1); */
set_nonblocking (serv->sok); g_socket_set_blocking (serv->sok, FALSE);
serv->ssl_do_connect_tag = fe_timeout_add (SSLDOCONNTMOUT, serv->ssl_do_connect_tag = fe_timeout_add (SSLDOCONNTMOUT,
ssl_do_connect, serv); ssl_do_connect, serv);
return; return;
@ -915,21 +907,16 @@ server_cleanup (server * serv)
if (serv->connecting) if (serv->connecting)
{ {
server_stopconnecting (serv); server_stopconnecting (serv);
closesocket (serv->sok4); if (serv->sok4)
if (serv->proxy_sok4 != -1) g_object_unref (serv->sok4);
closesocket (serv->proxy_sok4); if (serv->sok6)
if (serv->sok6 != -1) g_object_unref (serv->sok6);
closesocket (serv->sok6);
if (serv->proxy_sok6 != -1)
closesocket (serv->proxy_sok6);
return 1; return 1;
} }
if (serv->connected) if (serv->connected)
{ {
close_socket (serv->sok); close_socket (serv->sok);
if (serv->proxy_sok)
close_socket (serv->proxy_sok);
serv->connected = FALSE; serv->connected = FALSE;
serv->end_of_motd = FALSE; serv->end_of_motd = FALSE;
return 2; return 2;
@ -1265,8 +1252,9 @@ traverse_http (int sok, char *serverAddr, int port, GError **error)
} }
static int static int
traverse_proxy (int proxy_type, int sok, char *ip, int port, GError **error) traverse_proxy (int proxy_type, GSocket *sok_r, char *ip, int port, GError **error)
{ {
int sok = g_socket_get_fd (sok_r);
switch (proxy_type) switch (proxy_type)
{ {
case 1: case 1:
@ -1337,40 +1325,22 @@ server_connect_finish (GObject *source, GAsyncResult *res, gpointer user_data)
if (data->local_ip) if (data->local_ip)
prefs.local_ip = inet_addr (data->local_ip); prefs.local_ip = inet_addr (data->local_ip);
serv->sok = g_task_propagate_int (G_TASK(res), &error); serv->sok = g_task_propagate_pointer (G_TASK(res), &error);
if (!error) if (!error)
{ {
if (serv->sok == serv->sok4) if (serv->sok == serv->sok4)
closesocket (serv->sok6); g_object_unref (serv->sok6);
else else
closesocket (serv->sok4); g_object_unref (serv->sok4);
if (serv->proxy_sok != -1)
{ {
if (serv->proxy_sok == serv->proxy_sok4) guint16 port = net_get_local_port (serv->sok);
closesocket (serv->proxy_sok6); 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 else
closesocket (serv->proxy_sok4); g_strlcat (buf, prefs.hex_irc_user_name, sizeof (buf));
}
{
struct sockaddr addr;
int addr_len = sizeof (addr);
guint16 port;
if (!getsockname (serv->sok, &addr, &addr_len)) handle_command (serv->server_session, buf, FALSE);
{
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); server_connect_success (serv);
return; return;
@ -1410,13 +1380,10 @@ server_connect_finish (GObject *source, GAsyncResult *res, gpointer user_data)
close_connection: close_connection:
server_stopconnecting (serv); server_stopconnecting (serv);
closesocket (serv->sok4); if (serv->sok4)
if (serv->proxy_sok4 != -1) g_object_unref (serv->sok4);
closesocket (serv->proxy_sok4); if (serv->sok6)
if (serv->sok6 != -1) g_object_unref (serv->sok6);
closesocket (serv->sok6);
if (serv->proxy_sok6 != -1)
closesocket (serv->proxy_sok6);
if (retry && !servlist_cycle (serv) && prefs.hex_net_auto_reconnectonfail) if (retry && !servlist_cycle (serv) && prefs.hex_net_auto_reconnectonfail)
auto_reconnect (serv, FALSE, -1); auto_reconnect (serv, FALSE, -1);
@ -1428,36 +1395,51 @@ server_connect_thread (GTask *task, gpointer source, gpointer task_data, GCancel
netstore *ns_server; netstore *ns_server;
struct connect_data *data = (struct connect_data*)task_data; struct connect_data *data = (struct connect_data*)task_data;
server *serv = data->serv; server *serv = data->serv;
int port = serv->port; GSocket *sok = NULL, *psok;
int error;
int sok = -1, psok;
char *hostname = serv->hostname;
char *proxy_ip = NULL; char *proxy_ip = NULL;
int connect_port;
int proxy_type = 0; int proxy_type = 0;
char *proxy_host = NULL; char *proxy_host = NULL, *hostname;
int proxy_port; guint16 proxy_port, connect_port, port;
GError *err = NULL, *err4 = NULL, *err6 = NULL;
if (!is_server(serv)) if (!is_server(serv))
{ {
g_warning ("Server destroyed before connection started!\n"); g_warning ("Server destroyed before connection started!\n");
return; return;
} }
port = serv->port;
hostname = serv->hostname;
ns_server = net_store_new (); ns_server = net_store_new ();
/* Bind local address if configured */
if (prefs.hex_net_bind_host[0]) if (prefs.hex_net_bind_host[0])
{ {
netstore *ns_local = net_store_new (); netstore *ns_local = net_store_new ();
data->local_ip = net_resolve (ns_local, prefs.hex_net_bind_host, 0, NULL); data->local_ip = net_resolve (ns_local, prefs.hex_net_bind_host, NULL, &err);
if (data->local_ip != NULL) if (!err)
{ {
net_bind (ns_local, serv->sok4, serv->sok6); net_bind (ns_local, serv->sok4, serv->sok6, &err4, &err6);
} else if (err4 || err6)
{
net_store_destroy (ns_local);
if (err4) /* TODO: could handle this better? */
{
g_task_return_error (task, err4);
g_clear_error (&err6);
goto error_cleanup;
}
else
{
g_task_return_error (task, err4);
goto error_cleanup;
}
}
}
else
{ {
g_task_return_new_error (task, HEXCHAT_CONNECTION_ERROR, BIND_FAILED, g_task_return_error (task, err);
"Cannot resolve hostname %s\nCheck your IP Settings!\n", prefs.hex_net_bind_host);
net_store_destroy (ns_local); net_store_destroy (ns_local);
goto error_cleanup; goto error_cleanup;
} }
@ -1465,77 +1447,57 @@ server_connect_thread (GTask *task, gpointer source, gpointer task_data, GCancel
net_store_destroy (ns_local); net_store_destroy (ns_local);
} }
if (!serv->dont_use_proxy) /* blocked in serverlist? */ /* Connect to proxy if configured */
if (!serv->dont_use_proxy && prefs.hex_net_proxy_use != 2 && prefs.hex_net_proxy_type > 0)
{ {
#ifdef USE_LIBPROXY
if (prefs.hex_net_proxy_type == 5) if (prefs.hex_net_proxy_type == 5)
{ {
char **proxy_list; char *proxy;
char *url, *proxy;
url = g_strdup_printf ("irc://%s:%d", hostname, port); proxy = net_resolve_proxy (hostname, port, &err);
proxy_list = px_proxy_factory_get_proxies (libproxy_factory, url); if (err)
{
if (proxy_list) { g_task_return_error (task, err);
/* can use only one */ goto error_cleanup;
proxy = proxy_list[0];
if (!strncmp (proxy, "direct", 6))
proxy_type = 0;
else if (!strncmp (proxy, "http", 4))
proxy_type = 4;
else if (!strncmp (proxy, "socks5", 6))
proxy_type = 3;
else if (!strncmp (proxy, "socks", 5))
proxy_type = 2;
} }
if (proxy_type) { if (proxy)
char *c; {
c = strchr (proxy, ':') + 3; net_parse_proxy_uri (proxy, &proxy_host, &proxy_port, &proxy_type);
proxy_host = g_strdup (c); g_free (proxy);
c = strchr (proxy_host, ':');
*c = '\0';
proxy_port = atoi (c + 1);
} }
else
g_strfreev (proxy_list); proxy_type = 0;
g_free (url);
} }
#endif else if (prefs.hex_net_proxy_host[0])
if (prefs.hex_net_proxy_host[0] &&
prefs.hex_net_proxy_type > 0 &&
prefs.hex_net_proxy_use != 2) /* proxy is NOT dcc-only */
{ {
proxy_type = prefs.hex_net_proxy_type; proxy_type = prefs.hex_net_proxy_type;
proxy_host = g_strdup (prefs.hex_net_proxy_host); proxy_host = g_strdup (prefs.hex_net_proxy_host);
proxy_port = prefs.hex_net_proxy_port; proxy_port = prefs.hex_net_proxy_port;
} }
} }
serv->proxy_type = proxy_type;
data->proxy_hostname = proxy_host; data->proxy_hostname = proxy_host;
if (proxy_type > 0) if (proxy_type > 0)
{ {
data->ip = net_resolve (ns_server, proxy_host, proxy_port, &data->hostname); data->ip = net_resolve (ns_server, proxy_host, &data->hostname, &err);
if (!data->ip) if (!data->ip)
{ {
g_task_return_new_error (task, HEXCHAT_CONNECTION_ERROR, RESOLVE_FAILED, g_task_return_error (task, err);
"Unknown hostname %s\n", proxy_host);
goto error_cleanup; goto error_cleanup;
} }
connect_port = proxy_port; connect_port = proxy_port;
/* if using socks4, attempt to resolve ip for irc server */ /* if using socks4, attempt to resolve ip for irc server */
if ((proxy_type == 2) || (proxy_type == 5)) if (proxy_type == 2)
{ {
netstore *ns_proxy = net_store_new (); netstore *ns_proxy = net_store_new ();
g_free (data->hostname); g_free (data->hostname);
proxy_ip = net_resolve (ns_proxy, hostname, port, &data->hostname); proxy_ip = net_resolve (ns_proxy, hostname, &data->hostname, &err);
net_store_destroy (ns_proxy); net_store_destroy (ns_proxy);
if (!proxy_ip) if (err)
{ {
g_task_return_new_error (task, HEXCHAT_CONNECTION_ERROR, RESOLVE_FAILED, g_task_return_error (task, err);
"Unknown hostname %s\n", hostname);
goto error_cleanup; goto error_cleanup;
} }
} else /* otherwise we can just use the hostname */ } else /* otherwise we can just use the hostname */
@ -1543,11 +1505,10 @@ server_connect_thread (GTask *task, gpointer source, gpointer task_data, GCancel
} }
else else
{ {
data->ip = net_resolve (ns_server, hostname, port, &data->hostname); data->ip = net_resolve (ns_server, hostname, &data->hostname, &err);
if (!data->ip) if (err)
{ {
g_task_return_new_error (task, HEXCHAT_CONNECTION_ERROR, RESOLVE_FAILED, g_task_return_error (task, err);
"Unknown hostname %s\n", hostname);
goto error_cleanup; goto error_cleanup;
} }
connect_port = port; connect_port = port;
@ -1555,22 +1516,21 @@ server_connect_thread (GTask *task, gpointer source, gpointer task_data, GCancel
data->port = g_strdup_printf ("%d", connect_port); data->port = g_strdup_printf ("%d", connect_port);
if (!serv->dont_use_proxy && (proxy_type == 5)) if (!serv->dont_use_proxy)
error = net_connect (ns_server, serv->proxy_sok4, serv->proxy_sok6, &psok); psok = net_connect (ns_server, connect_port, serv->sok4, serv->sok6, &err);
else else
{ {
error = net_connect (ns_server, serv->sok4, serv->sok6, &sok); sok = net_connect (ns_server, connect_port, serv->sok4, serv->sok6, &err);
psok = sok; psok = sok;
} }
if (error != 0) if (err)
{ {
g_task_return_new_error (task, HEXCHAT_CONNECTION_ERROR, CONNECTION_FAILED, "%s", errorstring (sock_error())); g_task_return_error (task, err);
goto error_cleanup; goto error_cleanup;
} }
else else
{ {
GError *err = NULL;
/* connect succeeded */ /* connect succeeded */
if (proxy_ip && traverse_proxy (proxy_type, psok, proxy_ip, port, &err)) if (proxy_ip && traverse_proxy (proxy_type, psok, proxy_ip, port, &err))
{ {
@ -1582,7 +1542,7 @@ server_connect_thread (GTask *task, gpointer source, gpointer task_data, GCancel
error_cleanup: error_cleanup:
net_store_destroy (ns_server); net_store_destroy (ns_server);
g_free (proxy_ip); g_free (proxy_ip);
g_task_return_int (task, sok); /* Does nothing if error'd */ g_task_return_pointer (task, sok, g_object_unref); /* Does nothing if error'd */
return; return;
} }
@ -1667,10 +1627,7 @@ server_connect (server *serv, char *hostname, int port, int no_login)
fe_set_away (serv); fe_set_away (serv);
server_flush_queue (serv); server_flush_queue (serv);
/* create both sockets now, drop one later */ net_sockets (&serv->sok4, &serv->sok6, NULL, NULL);
net_sockets (&serv->sok4, &serv->sok6);
serv->proxy_sok4 = -1;
serv->proxy_sok6 = -1;
/* start the connection in a thread */ /* start the connection in a thread */
data = g_new0 (struct connect_data, 1); data = g_new0 (struct connect_data, 1);
@ -1739,7 +1696,6 @@ server_new (void)
server_fill_her_up (serv); server_fill_her_up (serv);
serv->id = id++; serv->id = id++;
serv->sok = -1;
strcpy (serv->nick, prefs.hex_irc_nick1); strcpy (serv->nick, prefs.hex_irc_nick1);
server_set_defaults (serv); server_set_defaults (serv);

View File

@ -560,9 +560,7 @@ static const char *const proxytypes[] =
N_("Socks4"), N_("Socks4"),
N_("Socks5"), N_("Socks5"),
N_("HTTP"), N_("HTTP"),
#ifdef USE_LIBPROXY
N_("Auto"), N_("Auto"),
#endif
NULL NULL
}; };