# HG changeset patch # User Evan Schoenberg # Date 1172207840 0 # Node ID 14d85ee22d78c419ec4608d8b5c29edd4ba5b7cd # Parent 868c9d2cb818ef0cc55b2817112e8bbb377abf8b Added a new GaimEventLoopUiOps item, input_get_error(). This function allows the UI to return the current error status on a socket/input. If the UI does not implement it (as Pidgin and gntgaim do not, since glib's handling of sockets is sane), it is just a wrapper around getsockopt(). Implemented or not, its return values should match those of getsockopt() with a level of SOL_SOCKET and an option of SO_ERROR. For curious souls, Adium will be using this to provide a working version of getsockopt(); the CoreFoundation CFSocket class which is used for socket read/write calls getsockopt() with SO_ERROR itself, thereby clearing the error flag [as documented in getsockopt()'s behavior], so depending upon it for determining if an error occurred leads to significant misbehavior. diff -r 868c9d2cb818 -r 14d85ee22d78 console/gntgaim.c --- a/console/gntgaim.c Fri Feb 23 05:12:54 2007 +0000 +++ b/console/gntgaim.c Fri Feb 23 05:17:20 2007 +0000 @@ -148,7 +148,8 @@ g_timeout_add, g_source_remove, gnt_input_add, - g_source_remove + g_source_remove, + NULL /* input_get_error */ }; static GaimEventLoopUiOps * diff -r 868c9d2cb818 -r 14d85ee22d78 libpurple/eventloop.c --- a/libpurple/eventloop.c Fri Feb 23 05:12:54 2007 +0000 +++ b/libpurple/eventloop.c Fri Feb 23 05:17:20 2007 +0000 @@ -23,6 +23,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "eventloop.h" +#include "internal.h" static GaimEventLoopUiOps *eventloop_ui_ops = NULL; @@ -58,6 +59,27 @@ return ops->input_remove(tag); } +int +gaim_input_get_error(int fd, int *error) +{ + GaimEventLoopUiOps *ops = gaim_eventloop_get_ui_ops(); + + if (ops->input_get_error) + { + errno = 0; + int ret = ops->input_get_error(fd, error); + errno = *error; + return ret; + } + else + { + socklen_t len; + len = sizeof(*error); + + return getsockopt(fd, SOL_SOCKET, SO_ERROR, error, &len); + } +} + void gaim_eventloop_set_ui_ops(GaimEventLoopUiOps *ops) { diff -r 868c9d2cb818 -r 14d85ee22d78 libpurple/eventloop.h --- a/libpurple/eventloop.h Fri Feb 23 05:12:54 2007 +0000 +++ b/libpurple/eventloop.h Fri Feb 23 05:17:20 2007 +0000 @@ -71,6 +71,16 @@ * @see gaim_input_remove, g_source_remove */ gboolean (*input_remove)(guint handle); + + + /** + * Get the current error status for an input. + * Implementation of this UI op is optional. Implement it if the UI's sockets + * or event loop needs to customize determination of socket error status. + * @see gaim_input_get_error, getsockopt + */ + int (*input_get_error)(int fd, int *error); + }; /**************************************************************************/ @@ -119,7 +129,22 @@ * @param handle The handle of the input handler. Note that this is the return * value from gaim_input_add, not the file descriptor. */ -gboolean gaim_input_remove(guint handle); +guint gaim_input_remove(guint handle); + +/** + * Get the current error status for an input. + * The return value and error follow getsockopt() with a level of SOL_SOCKET and an + * option name of SO_ERROR, and this is how the error is determined if the UI does not + * implement the input_get_error UI op. + * + * @param fd The input file descriptor. + * @param errno A pointer to an int which on return will have the error, or 0 if no error. + * + * @return 0 if there is no error; -1 if there is an error, in which case errno will be set. + */ +int +gaim_input_get_error(int fd, int *errno); + /*@}*/ diff -r 868c9d2cb818 -r 14d85ee22d78 libpurple/proxy.c --- a/libpurple/proxy.c Fri Feb 23 05:12:54 2007 +0000 +++ b/libpurple/proxy.c Fri Feb 23 05:17:20 2007 +0000 @@ -386,14 +386,14 @@ socket_ready_cb(gpointer data, gint source, GaimInputCondition cond) { GaimProxyConnectData *connect_data = data; - socklen_t len; int error = 0; int ret; - gaim_debug_info("proxy", "Connected.\n"); + gaim_debug_info("proxy", "Connected to %s:%d.\n", + connect_data->host, connect_data->port); /* - * getsockopt after a non-blocking connect returns -1 if something is + * gaim_input_get_error after a non-blocking connect returns -1 if something is * really messed up (bad descriptor, usually). Otherwise, it returns 0 and * error holds what connect would have returned if it blocked until now. * Thus, error == 0 is success, error == EINPROGRESS means "try again", @@ -403,17 +403,21 @@ * be overly optimistic sometimes. select is just a hint that you might be * able to do something.) */ - len = sizeof(error); - ret = getsockopt(connect_data->fd, SOL_SOCKET, SO_ERROR, &error, &len); + ret = gaim_input_get_error(connect_data->fd, &error); - if (ret == 0 && error == EINPROGRESS) + if (ret == 0 && error == EINPROGRESS) { /* No worries - we'll be called again later */ /* TODO: Does this ever happen? */ + gaim_debug_info("proxy", "(ret == 0 && error == EINPROGRESS)"); return; + } if (ret != 0 || error != 0) { if (ret != 0) error = errno; + gaim_debug_info("proxy", "Error connecting to %s:%d (%s).\n", + connect_data->host, connect_data->port, strerror(error)); + gaim_proxy_connect_data_disconnect(connect_data, strerror(error)); return; } @@ -466,14 +470,12 @@ /* * The connection happened IMMEDIATELY... strange, but whatever. */ - socklen_t len; int error = ETIMEDOUT; int ret; gaim_debug_info("proxy", "Connected immediately.\n"); - len = sizeof(error); - ret = getsockopt(connect_data->fd, SOL_SOCKET, SO_ERROR, &error, &len); + ret = gaim_input_get_error(connect_data->fd, &error); if ((ret != 0) || (error != 0)) { if (ret != 0) @@ -783,13 +785,13 @@ { GString *request; GaimProxyConnectData *connect_data; - socklen_t len; int error = ETIMEDOUT; int ret; - gaim_debug_info("proxy", "Connected.\n"); + connect_data = data; - connect_data = data; + gaim_debug_info("proxy", "Connected to %s:%d.\n", + connect_data->host, connect_data->port); if (connect_data->inpa > 0) { @@ -797,8 +799,7 @@ connect_data->inpa = 0; } - len = sizeof(error); - ret = getsockopt(connect_data->fd, SOL_SOCKET, SO_ERROR, &error, &len); + ret = gaim_input_get_error(connect_data->fd, &error); if ((ret != 0) || (error != 0)) { if (ret != 0) @@ -947,7 +948,6 @@ unsigned char packet[9]; struct hostent *hp; GaimProxyConnectData *connect_data = data; - socklen_t len; int error = ETIMEDOUT; int ret; @@ -959,8 +959,7 @@ connect_data->inpa = 0; } - len = sizeof(error); - ret = getsockopt(connect_data->fd, SOL_SOCKET, SO_ERROR, &error, &len); + ret = gaim_input_get_error(connect_data->fd, &error); if ((ret != 0) || (error != 0)) { if (ret != 0) @@ -1515,7 +1514,6 @@ unsigned char buf[5]; int i; GaimProxyConnectData *connect_data = data; - socklen_t len; int error = ETIMEDOUT; int ret; @@ -1527,8 +1525,7 @@ connect_data->inpa = 0; } - len = sizeof(error); - ret = getsockopt(connect_data->fd, SOL_SOCKET, SO_ERROR, &error, &len); + ret = gaim_input_get_error(connect_data->fd, &error); if ((ret != 0) || (error != 0)) { if (ret != 0) diff -r 868c9d2cb818 -r 14d85ee22d78 pidgin/gtkeventloop.c --- a/pidgin/gtkeventloop.c Fri Feb 23 05:12:54 2007 +0000 +++ b/pidgin/gtkeventloop.c Fri Feb 23 05:17:20 2007 +0000 @@ -118,7 +118,8 @@ g_timeout_add, g_source_remove, pidgin_input_add, - g_source_remove + g_source_remove, + NULL /* input_get_error */ }; GaimEventLoopUiOps *