aboutsummaryrefslogtreecommitdiffstats
path: root/lib/proxy.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/proxy.c')
-rw-r--r--lib/proxy.c187
1 files changed, 104 insertions, 83 deletions
diff --git a/lib/proxy.c b/lib/proxy.c
index e52837fe..e7d35351 100644
--- a/lib/proxy.c
+++ b/lib/proxy.c
@@ -48,6 +48,11 @@ int proxytype = PROXY_NONE;
char proxyuser[128] = "";
char proxypass[128] = "";
+/* Some systems don't know this one. It's not essential, so set it to 0 then. */
+#ifndef AI_NUMERICSERV
+#define AI_NUMERICSERV 0
+#endif
+
struct PHB {
b_event_handler func, proxy_func;
gpointer data, proxy_data;
@@ -55,28 +60,10 @@ struct PHB {
int port;
int fd;
gint inpa;
+ struct addrinfo *gai, *gai_cur;
};
-
-
-static struct sockaddr_in *gaim_gethostbyname(const char *host, int port)
-{
- static struct sockaddr_in sin;
-
- if (!inet_aton(host, &sin.sin_addr)) {
- struct hostent *hp;
- if (!(hp = gethostbyname(host))) {
- return NULL;
- }
- memset(&sin, 0, sizeof(struct sockaddr_in));
- memcpy(&sin.sin_addr.s_addr, hp->h_addr, hp->h_length);
- sin.sin_family = hp->h_addrtype;
- } else
- sin.sin_family = AF_INET;
- sin.sin_port = htons(port);
-
- return &sin;
-}
+static int proxy_connect_none(const char *host, unsigned short port_, struct PHB *phb);
static gboolean gaim_io_connected(gpointer data, gint source, b_input_condition cond)
{
@@ -86,71 +73,105 @@ static gboolean gaim_io_connected(gpointer data, gint source, b_input_condition
len = sizeof(error);
#ifndef _WIN32
- if (getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len) < 0) {
+ if (getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len) < 0 || error) {
+ if ((phb->gai_cur = phb->gai_cur->ai_next)) {
+ int new_fd;
+ b_event_remove(phb->inpa);
+ if ((new_fd = proxy_connect_none(NULL, 0, phb))) {
+ b_event_remove(phb->inpa);
+ closesocket(source);
+ dup2(new_fd, source);
+ phb->inpa = b_input_add(source, B_EV_IO_WRITE, gaim_io_connected, phb);
+ return FALSE;
+ }
+ }
+ freeaddrinfo(phb->gai);
closesocket(source);
b_event_remove(phb->inpa);
if( phb->proxy_func )
- phb->proxy_func(phb->proxy_data, -1, GAIM_INPUT_READ);
+ phb->proxy_func(phb->proxy_data, -1, B_EV_IO_READ);
else {
- phb->func(phb->data, -1, GAIM_INPUT_READ);
+ phb->func(phb->data, -1, B_EV_IO_READ);
g_free(phb);
}
return FALSE;
}
#endif
+ freeaddrinfo(phb->gai);
sock_make_blocking(source);
b_event_remove(phb->inpa);
if( phb->proxy_func )
- phb->proxy_func(phb->proxy_data, source, GAIM_INPUT_READ);
+ phb->proxy_func(phb->proxy_data, source, B_EV_IO_READ);
else {
- phb->func(phb->data, source, GAIM_INPUT_READ);
+ phb->func(phb->data, source, B_EV_IO_READ);
g_free(phb);
}
return FALSE;
}
-static int proxy_connect_none(const char *host, unsigned short port, struct PHB *phb)
+static int proxy_connect_none(const char *host, unsigned short port_, struct PHB *phb)
{
- struct sockaddr_in *sin;
struct sockaddr_in me;
int fd = -1;
-
- if (!(sin = gaim_gethostbyname(host, port))) {
- g_free(phb);
- return -1;
+
+ if (phb->gai_cur == NULL)
+ {
+ int ret;
+ char port[6];
+ struct addrinfo hints;
+
+ g_snprintf(port, sizeof(port), "%d", port_);
+
+ memset(&hints, 0, sizeof(struct addrinfo));
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICSERV;
+
+ if (!(ret = getaddrinfo(host, port, &hints, &phb->gai)))
+ phb->gai_cur = phb->gai;
+ else
+ event_debug("gai(): %s\n", gai_strerror(ret));
}
+
+ for (; phb->gai_cur; phb->gai_cur = phb->gai_cur->ai_next)
+ {
+ if ((fd = socket(phb->gai_cur->ai_family, phb->gai_cur->ai_socktype, phb->gai_cur->ai_protocol)) < 0) {
+ event_debug( "socket failed: %d\n", errno);
+ continue;
+ }
- if ((fd = socket(sin->sin_family, SOCK_STREAM, 0)) < 0) {
- g_free(phb);
- return -1;
- }
+ sock_make_nonblocking(fd);
+
+ if (global.conf->iface_out)
+ {
+ me.sin_family = AF_INET;
+ me.sin_port = 0;
+ me.sin_addr.s_addr = inet_addr( global.conf->iface_out );
+
+ if (bind(fd, (struct sockaddr *) &me, sizeof(me)) != 0)
+ event_debug("bind( %d, \"%s\" ) failure\n", fd, global.conf->iface_out);
+ }
- sock_make_nonblocking(fd);
+ event_debug("proxy_connect_none( \"%s\", %d ) = %d\n", host, port, fd);
- if( global.conf->iface_out )
- {
- me.sin_family = AF_INET;
- me.sin_port = 0;
- me.sin_addr.s_addr = inet_addr( global.conf->iface_out );
-
- if( bind( fd, (struct sockaddr *) &me, sizeof( me ) ) != 0 )
- event_debug( "bind( %d, \"%s\" ) failure\n", fd, global.conf->iface_out );
+ if (connect(fd, phb->gai_cur->ai_addr, phb->gai_cur->ai_addrlen) < 0 && !sockerr_again()) {
+ event_debug( "connect failed: %s\n", strerror(errno));
+ closesocket(fd);
+ fd = -1;
+ continue;
+ } else {
+ phb->inpa = b_input_add(fd, B_EV_IO_WRITE, gaim_io_connected, phb);
+ phb->fd = fd;
+
+ break;
+ }
}
- event_debug("proxy_connect_none( \"%s\", %d ) = %d\n", host, port, fd);
-
- if (connect(fd, (struct sockaddr *)sin, sizeof(*sin)) < 0 && !sockerr_again()) {
- closesocket(fd);
+ if(fd < 0 && host)
g_free(phb);
-
- return -1;
- } else {
- phb->inpa = b_input_add(fd, GAIM_INPUT_WRITE, gaim_io_connected, phb);
- phb->fd = fd;
-
- return fd;
- }
+
+ return fd;
}
@@ -178,14 +199,14 @@ static gboolean http_canread(gpointer data, gint source, b_input_condition cond)
if ((memcmp(HTTP_GOODSTRING, inputline, strlen(HTTP_GOODSTRING)) == 0) ||
(memcmp(HTTP_GOODSTRING2, inputline, strlen(HTTP_GOODSTRING2)) == 0)) {
- phb->func(phb->data, source, GAIM_INPUT_READ);
+ phb->func(phb->data, source, B_EV_IO_READ);
g_free(phb->host);
g_free(phb);
return FALSE;
}
close(source);
- phb->func(phb->data, -1, GAIM_INPUT_READ);
+ phb->func(phb->data, -1, B_EV_IO_READ);
g_free(phb->host);
g_free(phb);
@@ -203,7 +224,7 @@ static gboolean http_canwrite(gpointer data, gint source, b_input_condition cond
len = sizeof(error);
if (getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len) < 0) {
close(source);
- phb->func(phb->data, -1, GAIM_INPUT_READ);
+ phb->func(phb->data, -1, B_EV_IO_READ);
g_free(phb->host);
g_free(phb);
return FALSE;
@@ -214,7 +235,7 @@ static gboolean http_canwrite(gpointer data, gint source, b_input_condition cond
phb->host, phb->port);
if (send(source, cmd, strlen(cmd), 0) < 0) {
close(source);
- phb->func(phb->data, -1, GAIM_INPUT_READ);
+ phb->func(phb->data, -1, B_EV_IO_READ);
g_free(phb->host);
g_free(phb);
return FALSE;
@@ -229,7 +250,7 @@ static gboolean http_canwrite(gpointer data, gint source, b_input_condition cond
g_free(t2);
if (send(source, cmd, strlen(cmd), 0) < 0) {
close(source);
- phb->func(phb->data, -1, GAIM_INPUT_READ);
+ phb->func(phb->data, -1, B_EV_IO_READ);
g_free(phb->host);
g_free(phb);
return FALSE;
@@ -239,13 +260,13 @@ static gboolean http_canwrite(gpointer data, gint source, b_input_condition cond
g_snprintf(cmd, sizeof(cmd), "\r\n");
if (send(source, cmd, strlen(cmd), 0) < 0) {
close(source);
- phb->func(phb->data, -1, GAIM_INPUT_READ);
+ phb->func(phb->data, -1, B_EV_IO_READ);
g_free(phb->host);
g_free(phb);
return FALSE;
}
- phb->inpa = b_input_add(source, GAIM_INPUT_READ, http_canread, phb);
+ phb->inpa = b_input_add(source, B_EV_IO_READ, http_canread, phb);
return FALSE;
}
@@ -272,14 +293,14 @@ static gboolean s4_canread(gpointer data, gint source, b_input_condition cond)
memset(packet, 0, sizeof(packet));
if (read(source, packet, 9) >= 4 && packet[1] == 90) {
- phb->func(phb->data, source, GAIM_INPUT_READ);
+ phb->func(phb->data, source, B_EV_IO_READ);
g_free(phb->host);
g_free(phb);
return FALSE;
}
close(source);
- phb->func(phb->data, -1, GAIM_INPUT_READ);
+ phb->func(phb->data, -1, B_EV_IO_READ);
g_free(phb->host);
g_free(phb);
@@ -298,7 +319,7 @@ static gboolean s4_canwrite(gpointer data, gint source, b_input_condition cond)
len = sizeof(error);
if (getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len) < 0) {
close(source);
- phb->func(phb->data, -1, GAIM_INPUT_READ);
+ phb->func(phb->data, -1, B_EV_IO_READ);
g_free(phb->host);
g_free(phb);
return FALSE;
@@ -308,7 +329,7 @@ static gboolean s4_canwrite(gpointer data, gint source, b_input_condition cond)
/* XXX does socks4 not support host name lookups by the proxy? */
if (!(hp = gethostbyname(phb->host))) {
close(source);
- phb->func(phb->data, -1, GAIM_INPUT_READ);
+ phb->func(phb->data, -1, B_EV_IO_READ);
g_free(phb->host);
g_free(phb);
return FALSE;
@@ -325,13 +346,13 @@ static gboolean s4_canwrite(gpointer data, gint source, b_input_condition cond)
packet[8] = 0;
if (write(source, packet, 9) != 9) {
close(source);
- phb->func(phb->data, -1, GAIM_INPUT_READ);
+ phb->func(phb->data, -1, B_EV_IO_READ);
g_free(phb->host);
g_free(phb);
return FALSE;
}
- phb->inpa = b_input_add(source, GAIM_INPUT_READ, s4_canread, phb);
+ phb->inpa = b_input_add(source, B_EV_IO_READ, s4_canread, phb);
return FALSE;
}
@@ -358,20 +379,20 @@ static gboolean s5_canread_again(gpointer data, gint source, b_input_condition c
if (read(source, buf, 10) < 10) {
close(source);
- phb->func(phb->data, -1, GAIM_INPUT_READ);
+ phb->func(phb->data, -1, B_EV_IO_READ);
g_free(phb->host);
g_free(phb);
return FALSE;
}
if ((buf[0] != 0x05) || (buf[1] != 0x00)) {
close(source);
- phb->func(phb->data, -1, GAIM_INPUT_READ);
+ phb->func(phb->data, -1, B_EV_IO_READ);
g_free(phb->host);
g_free(phb);
return FALSE;
}
- phb->func(phb->data, source, GAIM_INPUT_READ);
+ phb->func(phb->data, source, B_EV_IO_READ);
g_free(phb->host);
g_free(phb);
@@ -395,13 +416,13 @@ static void s5_sendconnect(gpointer data, gint source)
if (write(source, buf, (5 + strlen(phb->host) + 2)) < (5 + strlen(phb->host) + 2)) {
close(source);
- phb->func(phb->data, -1, GAIM_INPUT_READ);
+ phb->func(phb->data, -1, B_EV_IO_READ);
g_free(phb->host);
g_free(phb);
return;
}
- phb->inpa = b_input_add(source, GAIM_INPUT_READ, s5_canread_again, phb);
+ phb->inpa = b_input_add(source, B_EV_IO_READ, s5_canread_again, phb);
}
static gboolean s5_readauth(gpointer data, gint source, b_input_condition cond)
@@ -413,7 +434,7 @@ static gboolean s5_readauth(gpointer data, gint source, b_input_condition cond)
if (read(source, buf, 2) < 2) {
close(source);
- phb->func(phb->data, -1, GAIM_INPUT_READ);
+ phb->func(phb->data, -1, B_EV_IO_READ);
g_free(phb->host);
g_free(phb);
return FALSE;
@@ -421,7 +442,7 @@ static gboolean s5_readauth(gpointer data, gint source, b_input_condition cond)
if ((buf[0] != 0x01) || (buf[1] != 0x00)) {
close(source);
- phb->func(phb->data, -1, GAIM_INPUT_READ);
+ phb->func(phb->data, -1, B_EV_IO_READ);
g_free(phb->host);
g_free(phb);
return FALSE;
@@ -441,7 +462,7 @@ static gboolean s5_canread(gpointer data, gint source, b_input_condition cond)
if (read(source, buf, 2) < 2) {
close(source);
- phb->func(phb->data, -1, GAIM_INPUT_READ);
+ phb->func(phb->data, -1, B_EV_IO_READ);
g_free(phb->host);
g_free(phb);
return FALSE;
@@ -449,7 +470,7 @@ static gboolean s5_canread(gpointer data, gint source, b_input_condition cond)
if ((buf[0] != 0x05) || (buf[1] == 0xff)) {
close(source);
- phb->func(phb->data, -1, GAIM_INPUT_READ);
+ phb->func(phb->data, -1, B_EV_IO_READ);
g_free(phb->host);
g_free(phb);
return FALSE;
@@ -464,13 +485,13 @@ static gboolean s5_canread(gpointer data, gint source, b_input_condition cond)
memcpy(buf + 2 + i + 1, proxypass, j);
if (write(source, buf, 3 + i + j) < 3 + i + j) {
close(source);
- phb->func(phb->data, -1, GAIM_INPUT_READ);
+ phb->func(phb->data, -1, B_EV_IO_READ);
g_free(phb->host);
g_free(phb);
return FALSE;
}
- phb->inpa = b_input_add(source, GAIM_INPUT_READ, s5_readauth, phb);
+ phb->inpa = b_input_add(source, B_EV_IO_READ, s5_readauth, phb);
} else {
s5_sendconnect(phb, source);
}
@@ -490,7 +511,7 @@ static gboolean s5_canwrite(gpointer data, gint source, b_input_condition cond)
len = sizeof(error);
if (getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len) < 0) {
close(source);
- phb->func(phb->data, -1, GAIM_INPUT_READ);
+ phb->func(phb->data, -1, B_EV_IO_READ);
g_free(phb->host);
g_free(phb);
return FALSE;
@@ -512,13 +533,13 @@ static gboolean s5_canwrite(gpointer data, gint source, b_input_condition cond)
if (write(source, buf, i) < i) {
close(source);
- phb->func(phb->data, -1, GAIM_INPUT_READ);
+ phb->func(phb->data, -1, B_EV_IO_READ);
g_free(phb->host);
g_free(phb);
return FALSE;
}
- phb->inpa = b_input_add(source, GAIM_INPUT_READ, s5_canread, phb);
+ phb->inpa = b_input_add(source, B_EV_IO_READ, s5_canread, phb);
return FALSE;
}