Mercurial > pidgin.yaz
diff src/proxy.c @ 14089:10e8eb6a4910
[gaim-migrate @ 16712]
Pretty large commit here. Basically I got sick of having to verify
that gc is still valid on all the callback functions for
gaim_proxy_connect(). The fix for this for gaim_proxy_connect() to
return something that allows the connection attempt to be canceled.
It's not quite there yet, but this is a good first step. I changed
gaim_proxy_connect() to return a reference to a new
GaimProxyConnectInfo (this used to be called PHB). Eventually this
can be passed to a function that'll cancel the connection attempt.
I also decided to add an error_cb instead of using connect_cb and
passing a file descriptor of -1. And proxy.c will also pass an
error message to callers which should explain the reason that the
connection attempt failed.
Oh, and proxy.c now never calls gaim_connection_error()
committer: Tailor Script <tailor@pidgin.im>
author | Mark Doliner <mark@kingant.net> |
---|---|
date | Sat, 12 Aug 2006 10:12:43 +0000 |
parents | 8bda65b88e49 |
children | 983fbec46eb0 |
line wrap: on
line diff
--- a/src/proxy.c Sat Aug 12 10:06:15 2006 +0000 +++ b/src/proxy.c Sat Aug 12 10:12:43 2006 +0000 @@ -38,16 +38,15 @@ #include "proxy.h" #include "util.h" -static GaimProxyInfo *global_proxy_info = NULL; - +/* Does anyone know what PHB stands for? */ struct PHB { - GaimInputFunction func; + GaimProxyConnectFunction connect_cb; + GaimProxyErrorFunction error_cb; gpointer data; char *host; int port; - gint inpa; + guint inpa; GaimProxyInfo *gpi; - GaimAccount *account; GSList *hosts; guchar *write_buffer; gsize write_buf_len; @@ -58,8 +57,6 @@ gsize read_len; }; -static void try_connect(struct PHB *); - static const char *socks5errors[] = { "succeeded\n", "general SOCKS server failure\n", @@ -72,6 +69,11 @@ "Address type not supported\n" }; +static GaimProxyInfo *global_proxy_info = NULL; +static GSList *phbs = NULL; + +static void try_connect(struct PHB *); + /************************************************************************** * Proxy structure API **************************************************************************/ @@ -255,6 +257,63 @@ * Proxy API **************************************************************************/ +static void +gaim_proxy_phb_destroy(struct PHB *phb) +{ + phbs = g_slist_remove(phbs, phb); + + if (phb->inpa > 0) + gaim_input_remove(phb->inpa); + + while (phb->hosts != NULL) + { + /* Discard the length... */ + phb->hosts = g_slist_remove(phb->hosts, phb->hosts->data); + /* Free the address... */ + g_free(phb->hosts->data); + phb->hosts = g_slist_remove(phb->hosts, phb->hosts->data); + } + + g_free(phb->host); + g_free(phb->write_buffer); + g_free(phb->read_buffer); + g_free(phb); +} + +static void +gaim_proxy_phb_connected(struct PHB *phb, int fd) +{ + phb->connect_cb(phb->data, fd); + gaim_proxy_phb_destroy(phb); +} + +/** + * @param error An error message explaining why the connection + * failed. This will be passed to the callback function + * specified in the call to gaim_proxy_connect(). + */ +static void +gaim_proxy_phb_error(struct PHB *phb, const gchar *error_message) +{ + if (phb->error_cb == NULL) + { + /* + * TODO + * While we're transitioning to the new gaim_proxy_connect() + * code, not all callers supply an error_cb. If this is the + * case then they're expecting connect_cb to be called with + * an fd of -1 in the case of an error. Once all callers have + * been changed this whole if statement should be removed. + */ + phb->connect_cb(phb->data, -1); + gaim_proxy_phb_destroy(phb); + return; + } + + phb->error_cb(phb->data, error_message); + gaim_proxy_phb_destroy(phb); +} + #if defined(__unix__) || defined(__APPLE__) /* @@ -264,9 +323,9 @@ typedef struct { char *host; int port; - dns_callback_t callback; + GaimProxyDnsConnectFunction callback; gpointer data; - gint inpa; + guint inpa; int fd_in, fd_out; pid_t dns_pid; } pending_dns_request_t; @@ -285,7 +344,7 @@ typedef struct { dns_params_t params; - dns_callback_t callback; + GaimProxyDnsConnectFunction callback; gpointer data; } queued_dns_request_t; @@ -694,7 +753,7 @@ */ int -gaim_gethostbyname_async(const char *hostname, int port, dns_callback_t callback, gpointer data) +gaim_gethostbyname_async(const char *hostname, int port, GaimProxyDnsConnectFunction callback, gpointer data) { pending_dns_request_t *req = NULL; dns_params_t dns_params; @@ -767,7 +826,7 @@ typedef struct _dns_tdata { char *hostname; int port; - dns_callback_t callback; + GaimProxyDnsConnectFunction callback; gpointer data; GSList *hosts; char *errmsg; @@ -843,7 +902,7 @@ int gaim_gethostbyname_async(const char *hostname, int port, - dns_callback_t callback, gpointer data) + GaimProxyDnsConnectFunction callback, gpointer data) { dns_tdata *td; struct sockaddr_in sin; @@ -882,7 +941,7 @@ gpointer data; size_t addrlen; struct sockaddr *addr; - dns_callback_t callback; + GaimProxyDnsConnectFunction callback; } pending_dns_request_t; static gboolean host_resolved(gpointer data) @@ -898,7 +957,7 @@ int gaim_gethostbyname_async(const char *hostname, int port, - dns_callback_t callback, gpointer data) + GaimProxyDnsConnectFunction callback, gpointer data) { struct sockaddr_in sin; pending_dns_request_t *req; @@ -955,9 +1014,11 @@ if (ret == 0 && error == EINPROGRESS) return; /* we'll be called again later */ if (ret < 0 || error != 0) { - if(ret!=0) error = errno; + if (ret!=0) + error = errno; close(source); gaim_input_remove(phb->inpa); + phb->inpa = 0; gaim_debug_error("proxy", "getsockopt SO_ERROR check: %s\n", strerror(error)); @@ -967,29 +1028,16 @@ } gaim_input_remove(phb->inpa); - - if (phb->account == NULL || - gaim_account_get_connection(phb->account) != NULL) { + phb->inpa = 0; - phb->func(phb->data, source, GAIM_INPUT_READ); - } - - g_free(phb->host); - g_free(phb); + gaim_proxy_phb_connected(phb, source); } static gboolean clean_connect(gpointer data) { struct PHB *phb = data; - if (phb->account == NULL || - gaim_account_get_connection(phb->account) != NULL) { - - phb->func(phb->data, phb->port, GAIM_INPUT_READ); - } - - g_free(phb->host); - g_free(phb); + gaim_proxy_phb_connected(phb, phb->port); return FALSE; } @@ -1037,8 +1085,9 @@ close(fd); return -1; } + /* TODO: Why is the following line so strange? */ phb->port = fd; /* bleh */ - gaim_timeout_add(50, clean_connect, phb); /* we do this because we never + gaim_timeout_add(10, clean_connect, phb); /* we do this because we never want to call our callback before we return. */ } @@ -1059,6 +1108,7 @@ return; else if(ret < 0) { gaim_input_remove(phb->inpa); + phb->inpa = 0; close(source); g_free(phb->write_buffer); phb->write_buffer = NULL; @@ -1080,18 +1130,6 @@ #define HTTP_GOODSTRING "HTTP/1.0 200" #define HTTP_GOODSTRING2 "HTTP/1.1 200" -static void -http_complete(struct PHB *phb, gint source) -{ - gaim_debug_info("http proxy", "proxy connection established\n"); - if(!phb->account || phb->account->gc) { - phb->func(phb->data, source, GAIM_INPUT_READ); - } - g_free(phb->host); - g_free(phb); -} - - /* read the response to the CONNECT request, if we are requesting a non-port-80 tunnel */ static void http_canread(gpointer data, gint source, GaimInputCondition cond) @@ -1101,6 +1139,7 @@ struct PHB *phb = data; guchar *p; gsize max_read; + gchar *msg; if(phb->read_buffer == NULL) { phb->read_buf_len = 8192; @@ -1116,12 +1155,7 @@ return; else if(len <= 0) { close(source); - source = -1; - g_free(phb->read_buffer); - phb->read_buffer = NULL; - gaim_input_remove(phb->inpa); - phb->inpa = 0; - http_complete(phb, source); + gaim_proxy_phb_error(phb, _("Lost connection with server for an unknown reason.")); return; } else { phb->read_len += len; @@ -1137,7 +1171,8 @@ return; error = strncmp((const char *)phb->read_buffer, "HTTP/", 5) != 0; - if(!error) { + if (!error) + { int major; p = phb->read_buffer + 5; major = strtol((const char *)p, (char **)&p, 10); @@ -1157,7 +1192,8 @@ /* Read the contents */ p = (guchar *)g_strrstr((const gchar *)phb->read_buffer, "Content-Length: "); - if(p != NULL) { + if (p != NULL) + { gchar *tmp; int len = 0; char tmpc; @@ -1180,25 +1216,22 @@ } } - if(error) { - gaim_debug_error("proxy", - "Unable to parse proxy's response: %s\n", - phb->read_buffer); + if (error) + { close(source); - source = -1; - g_free(phb->read_buffer); - phb->read_buffer = NULL; - gaim_input_remove(phb->inpa); - phb->inpa = 0; - http_complete(phb, source); + msg = g_strdup_printf("Unable to parse response from HTTP proxy: %s\n", + phb->read_buffer); + gaim_proxy_phb_error(phb, msg); + g_free(msg); return; - } else if(status != 200) { + } + else if (status != 200) + { gaim_debug_error("proxy", "Proxy server replied with:\n%s\n", phb->read_buffer); - /* XXX: why in the hell are we calling gaim_connection_error() here? */ if(status == 407 /* Proxy Auth */) { gchar *ntlm; if((ntlm = g_strrstr((const gchar *)phb->read_buffer, "Proxy-Authenticate: NTLM "))) { /* Check for Type-2 */ @@ -1208,19 +1241,13 @@ gchar *username; gchar *request; gchar *response; - if(!(username = strchr(domain, '\\'))) { - char *msg = g_strdup_printf(_("Proxy connection error %d"), status); + username = strchr(domain, '\\'); + if (username == NULL) + { close(source); - source = -1; - if(phb->account) - gaim_connection_error(phb->account->gc, msg); - else - gaim_debug_error("http proxy", "%s\n", msg); + msg = g_strdup_printf(_("HTTP proxy connection error %d"), status); + gaim_proxy_phb_error(phb, msg); g_free(msg); - gaim_input_remove(phb->inpa); - g_free(phb->read_buffer); - g_free(phb->host); - g_free(phb); return; } *username = '\0'; @@ -1264,19 +1291,13 @@ gchar *domain = (gchar*) gaim_proxy_info_get_username(phb->gpi); gchar *username; int request_len; - if(!(username = strchr(domain, '\\'))) { - char *msg = g_strdup_printf(_("Proxy connection error %d"), status); + username = strchr(domain, '\\'); + if (username == NULL) + { close(source); - source = -1; - if(phb->account) - gaim_connection_error(phb->account->gc, msg); - else - gaim_debug_error("http proxy", "%s\n", msg); + msg = g_strdup_printf(_("HTTP proxy connection error %d"), status); + gaim_proxy_phb_error(phb, msg); g_free(msg); - gaim_input_remove(phb->inpa); - g_free(phb->read_buffer); - g_free(phb->host); - g_free(phb); return; } *username = '\0'; @@ -1313,49 +1334,29 @@ proxy_do_write(phb, source, cond); return; } else { - char *msg = g_strdup_printf(_("Proxy connection error %d"), status); close(source); - source = -1; - if(phb->account) - gaim_connection_error(phb->account->gc, msg); - else - gaim_debug_error("http proxy", "%s\n", msg); + msg = g_strdup_printf(_("HTTP proxy connection error %d"), status); + gaim_proxy_phb_error(phb, msg); g_free(msg); - gaim_input_remove(phb->inpa); - g_free(phb->read_buffer); - g_free(phb->host); - g_free(phb); return; } } if(status == 403 /* Forbidden */ ) { - gchar *msg = g_strdup_printf(_("Access denied: proxy server forbids port %d tunnelling."), phb->port); - if(phb->account) - gaim_connection_error(phb->account->gc, msg); - else - gaim_debug_error("http proxy", "%s\n", msg); + msg = g_strdup_printf(_("Access denied: HTTP proxy server forbids port %d tunnelling."), phb->port); + gaim_proxy_phb_error(phb, msg); g_free(msg); - gaim_input_remove(phb->inpa); - g_free(phb->read_buffer); - g_free(phb->host); - g_free(phb); } else { - char *msg = g_strdup_printf(_("Proxy connection error %d"), status); - if(phb->account) - gaim_connection_error(phb->account->gc, msg); - else - gaim_debug_error("http proxy", "%s\n", msg); + msg = g_strdup_printf(_("HTTP proxy connection error %d"), status); + gaim_proxy_phb_error(phb, msg); g_free(msg); - gaim_input_remove(phb->inpa); - g_free(phb->read_buffer); - g_free(phb->host); - g_free(phb); } } else { gaim_input_remove(phb->inpa); + phb->inpa = 0; g_free(phb->read_buffer); phb->read_buffer = NULL; - http_complete(phb, source); + gaim_debug_info("proxy", "HTTP proxy connection established\n"); + gaim_proxy_phb_connected(phb, source); return; } } @@ -1374,7 +1375,10 @@ gaim_debug_info("http proxy", "Connected.\n"); if (phb->inpa > 0) + { gaim_input_remove(phb->inpa); + phb->inpa = 0; + } len = sizeof(error); @@ -1456,7 +1460,8 @@ phb->inpa = gaim_input_add(fd, GAIM_INPUT_WRITE, http_canwrite, phb); } else { - http_complete(phb, fd); + gaim_debug_info("proxy", "HTTP proxy connection established\n"); + gaim_proxy_phb_connected(phb, fd); } } else { close(fd); @@ -1507,21 +1512,13 @@ return; else if (len + phb->read_len >= 4) { if (phb->read_buffer[1] == 90) { - if (phb->account == NULL || - gaim_account_get_connection(phb->account) != NULL) { - - phb->func(phb->data, source, GAIM_INPUT_READ); - } - - gaim_input_remove(phb->inpa); - g_free(phb->read_buffer); - g_free(phb->host); - g_free(phb); + gaim_proxy_phb_connected(phb, source); return; } } gaim_input_remove(phb->inpa); + phb->inpa = 0; g_free(phb->read_buffer); phb->read_buffer = NULL; @@ -1542,7 +1539,10 @@ gaim_debug_info("socks4 proxy", "Connected.\n"); if (phb->inpa > 0) + { gaim_input_remove(phb->inpa); + phb->inpa = 0; + } len = sizeof(error); @@ -1662,6 +1662,7 @@ gaim_debug_warning("socks5 proxy", "or not...\n"); close(source); gaim_input_remove(phb->inpa); + phb->inpa = 0; g_free(phb->read_buffer); phb->read_buffer = NULL; try_connect(phb); @@ -1679,6 +1680,7 @@ gaim_debug_error("socks5 proxy", "Bad data.\n"); close(source); gaim_input_remove(phb->inpa); + phb->inpa = 0; g_free(phb->read_buffer); phb->read_buffer = NULL; try_connect(phb); @@ -1715,20 +1717,11 @@ /* Skip past BND.PORT */ buf += 2; - if (phb->account == NULL || - gaim_account_get_connection(phb->account) != NULL) { - - phb->func(phb->data, source, GAIM_INPUT_READ); - } - - gaim_input_remove(phb->inpa); - g_free(phb->read_buffer); - g_free(phb->host); - g_free(phb); + gaim_proxy_phb_connected(phb, source); } static void -s5_sendconnect(gpointer data, gint source) +s5_sendconnect(gpointer data, int source) { struct PHB *phb = data; int hlen = strlen(phb->host); @@ -1749,7 +1742,6 @@ phb->inpa = gaim_input_add(source, GAIM_INPUT_WRITE, proxy_do_write, phb); proxy_do_write(phb, source, GAIM_INPUT_WRITE); - } static void @@ -1773,6 +1765,7 @@ else if(len <= 0) { close(source); gaim_input_remove(phb->inpa); + phb->inpa = 0; g_free(phb->read_buffer); phb->read_buffer = NULL; try_connect(phb); @@ -1784,6 +1777,7 @@ return; gaim_input_remove(phb->inpa); + phb->inpa = 0; if ((phb->read_buffer[0] != 0x01) || (phb->read_buffer[1] != 0x00)) { close(source); @@ -1865,6 +1859,7 @@ else if(len <= 0) { close(source); gaim_input_remove(phb->inpa); + phb->inpa = 0; g_free(phb->read_buffer); phb->read_buffer = NULL; try_connect(phb); @@ -1880,6 +1875,7 @@ if (*cmdbuf != 0x01) { close(source); gaim_input_remove(phb->inpa); + phb->inpa = 0; g_free(phb->read_buffer); phb->read_buffer = NULL; try_connect(phb); @@ -1901,6 +1897,7 @@ /* Did auth work? */ if (buf[0] == 0x00) { gaim_input_remove(phb->inpa); + phb->inpa = 0; g_free(phb->read_buffer); phb->read_buffer = NULL; /* Success */ @@ -1913,6 +1910,7 @@ "failed. Disconnecting..."); close(source); gaim_input_remove(phb->inpa); + phb->inpa = 0; g_free(phb->read_buffer); phb->read_buffer = NULL; try_connect(phb); @@ -1957,6 +1955,7 @@ "Disconnecting..."); close(source); gaim_input_remove(phb->inpa); + phb->inpa = 0; g_free(phb->read_buffer); phb->read_buffer = NULL; try_connect(phb); @@ -1992,6 +1991,7 @@ else if(len <= 0) { close(source); gaim_input_remove(phb->inpa); + phb->inpa = 0; g_free(phb->read_buffer); phb->read_buffer = NULL; try_connect(phb); @@ -2003,6 +2003,7 @@ return; gaim_input_remove(phb->inpa); + phb->inpa = 0; if ((phb->read_buffer[0] != 0x05) || (phb->read_buffer[1] == 0xff)) { close(source); @@ -2094,7 +2095,10 @@ gaim_debug_info("socks5 proxy", "Connected.\n"); if (phb->inpa > 0) + { gaim_input_remove(phb->inpa); + phb->inpa = 0; + } len = sizeof(error); if (getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { @@ -2225,14 +2229,7 @@ } if (ret < 0) { - if (phb->account == NULL || - gaim_account_get_connection(phb->account) != NULL) { - - phb->func(phb->data, -1, GAIM_INPUT_READ); - } - - g_free(phb->host); - g_free(phb); + gaim_proxy_phb_error(phb, _("TODO")); } } @@ -2313,31 +2310,26 @@ return gpi; } -/* - * TODO: It would be really good if this returned some sort of handle - * that we could use to cancel the connection. As it is now, - * each callback has to check to make sure gc is still valid. - * And that is ugly. - */ -int +GaimProxyConnectInfo * gaim_proxy_connect(GaimAccount *account, const char *host, int port, - GaimInputFunction func, gpointer data) + GaimProxyConnectFunction connect_cb, + GaimProxyErrorFunction error_cb, gpointer data) { const char *connecthost = host; int connectport = port; struct PHB *phb; - g_return_val_if_fail(host != NULL, -1); - g_return_val_if_fail(port != 0 && port != -1, -1); - g_return_val_if_fail(func != NULL, -1); + g_return_val_if_fail(host != NULL, NULL); + g_return_val_if_fail(port > 0, NULL); + g_return_val_if_fail(connect_cb != NULL, NULL); + /* g_return_val_if_fail(error_cb != NULL, NULL); *//* TODO: Soon! */ phb = g_new0(struct PHB, 1); - - phb->func = func; + phb->connect_cb = connect_cb; + phb->error_cb = error_cb; phb->data = data; phb->host = g_strdup(host); phb->port = port; - phb->account = account; phb->gpi = gaim_proxy_get_setup(account); if ((gaim_proxy_info_get_type(phb->gpi) != GAIM_PROXY_NONE) && @@ -2345,9 +2337,8 @@ gaim_proxy_info_get_port(phb->gpi) <= 0)) { gaim_notify_error(NULL, NULL, _("Invalid proxy settings"), _("Either the host name or port number specified for your given proxy type is invalid.")); - g_free(phb->host); - g_free(phb); - return -1; + gaim_proxy_phb_destroy(phb); + return NULL; } switch (gaim_proxy_info_get_type(phb->gpi)) @@ -2364,30 +2355,55 @@ break; default: - g_free(phb->host); - g_free(phb); - return -1; + gaim_proxy_phb_destroy(phb); + return NULL; + } + + if (gaim_gethostbyname_async(connecthost, + connectport, connection_host_resolved, phb) != 0) + { + gaim_proxy_phb_destroy(phb); + return NULL; } - return gaim_gethostbyname_async(connecthost, connectport, - connection_host_resolved, phb); + phbs = g_slist_prepend(phbs, phb); + + return phb; } -int +/* + * Combine some of this code with gaim_proxy_connect() + */ +GaimProxyConnectInfo * gaim_proxy_connect_socks5(GaimProxyInfo *gpi, const char *host, int port, - GaimInputFunction func, gpointer data) + GaimProxyConnectFunction connect_cb, + GaimProxyErrorFunction error_cb, gpointer data) { struct PHB *phb; + g_return_val_if_fail(host != NULL, NULL); + g_return_val_if_fail(port > 0, NULL); + g_return_val_if_fail(connect_cb != NULL, NULL); + /* g_return_val_if_fail(error_cb != NULL, NULL); *//* TODO: Soon! */ + phb = g_new0(struct PHB, 1); - phb->gpi = gpi; - phb->func = func; + phb->connect_cb = connect_cb; + phb->error_cb = error_cb; phb->data = data; phb->host = g_strdup(host); phb->port = port; + phb->gpi = gpi; - return gaim_gethostbyname_async(gaim_proxy_info_get_host(gpi), - gaim_proxy_info_get_port(gpi), connection_host_resolved, phb); + if (gaim_gethostbyname_async(gaim_proxy_info_get_host(gpi), + gaim_proxy_info_get_port(gpi), connection_host_resolved, phb) != 0) + { + gaim_proxy_phb_destroy(phb); + return NULL; + } + + phbs = g_slist_prepend(phbs, phb); + + return phb; } @@ -2425,6 +2441,14 @@ gaim_proxy_info_set_password(info, value); } +void * +gaim_proxy_get_handle() +{ + static int handle; + + return &handle; +} + void gaim_proxy_init(void) { @@ -2459,10 +2483,9 @@ #endif } -void * -gaim_proxy_get_handle() +void +gaim_proxy_uninit(void) { - static int handle; - - return &handle; + while (phbs != NULL) + gaim_proxy_phb_destroy(phbs->data); }