Mercurial > pidgin.yaz
diff plugins/ssl/ssl-nss.c @ 13200:33bef17125c2
[gaim-migrate @ 15563]
This is the soon-to-be-infamous nonblocking network activity patch that I've been working on. Feel free to yell at me if this makes you unhappy.
committer: Tailor Script <tailor@pidgin.im>
author | Daniel Atallah <daniel.atallah@gmail.com> |
---|---|
date | Thu, 09 Feb 2006 04:17:56 +0000 |
parents | 8f8087bc9732 |
children | a587a6c6149c |
line wrap: on
line diff
--- a/plugins/ssl/ssl-nss.c Thu Feb 09 04:14:54 2006 +0000 +++ b/plugins/ssl/ssl-nss.c Thu Feb 09 04:17:56 2006 +0000 @@ -46,6 +46,7 @@ { PRFileDesc *fd; PRFileDesc *in; + guint handshake_handler; } GaimSslNssData; @@ -54,6 +55,54 @@ static const PRIOMethods *_nss_methods = NULL; static PRDescIdentity _identity; +/* Thank you, Evolution */ +static void +set_errno(int code) +{ + /* FIXME: this should handle more. */ + switch (code) { + case PR_INVALID_ARGUMENT_ERROR: + errno = EINVAL; + break; + case PR_PENDING_INTERRUPT_ERROR: + errno = EINTR; + break; + case PR_IO_PENDING_ERROR: + errno = EAGAIN; + break; + case PR_WOULD_BLOCK_ERROR: + errno = EAGAIN; + /*errno = EWOULDBLOCK; */ + break; + case PR_IN_PROGRESS_ERROR: + errno = EINPROGRESS; + break; + case PR_ALREADY_INITIATED_ERROR: + errno = EALREADY; + break; + case PR_NETWORK_UNREACHABLE_ERROR: + errno = EHOSTUNREACH; + break; + case PR_CONNECT_REFUSED_ERROR: + errno = ECONNREFUSED; + break; + case PR_CONNECT_TIMEOUT_ERROR: + case PR_IO_TIMEOUT_ERROR: + errno = ETIMEDOUT; + break; + case PR_NOT_CONNECTED_ERROR: + errno = ENOTCONN; + break; + case PR_CONNECT_RESET_ERROR: + errno = ECONNRESET; + break; + case PR_IO_ERROR: + default: + errno = EIO; + break; + } +} + static void ssl_nss_init_nss(void) { @@ -158,6 +207,36 @@ } static void +ssl_nss_handshake_cb(gpointer data, int fd, GaimInputCondition cond) +{ + GaimSslConnection *gsc = (GaimSslConnection *)data; + GaimSslNssData *nss_data = gsc->private_data; + + /* I don't think this the best way to do this... + * It seems to work because it'll eventually use the cached value + */ + if(SSL_ForceHandshake(nss_data->in) != SECSuccess) { + set_errno(PR_GetError()); + if (errno == EAGAIN || errno == EWOULDBLOCK) + return; + + gaim_debug_error("nss", "Handshake failed %u\n", PR_GetError()); + + if (gsc->error_cb != NULL) + gsc->error_cb(gsc, GAIM_SSL_HANDSHAKE_FAILED, gsc->connect_cb_data); + + gaim_ssl_close(gsc); + + return; + } + + gaim_input_remove(nss_data->handshake_handler); + nss_data->handshake_handler = 0; + + gsc->connect_cb(gsc->connect_cb_data, gsc, cond); +} + +static void ssl_nss_connect_cb(gpointer data, gint source, GaimInputCondition cond) { GaimSslConnection *gsc = (GaimSslConnection *)data; @@ -183,9 +262,10 @@ } socket_opt.option = PR_SockOpt_Nonblocking; - socket_opt.value.non_blocking = PR_FALSE; + socket_opt.value.non_blocking = PR_TRUE; - PR_SetSocketOption(nss_data->fd, &socket_opt); + if (PR_SetSocketOption(nss_data->fd, &socket_opt) != PR_SUCCESS) + gaim_debug_warning("nss", "unable to set socket into non-blocking mode: %u\n", PR_GetError()); nss_data->in = SSL_ImportFD(NULL, nss_data->fd); @@ -212,21 +292,17 @@ if(gsc->host) SSL_SetURL(nss_data->in, gsc->host); +#if 0 /* This seems like it'd the be the correct way to implement the nonblocking stuff, + but it doesn't seem to work */ + SSL_HandshakeCallback(nss_data->in, + (SSLHandshakeCallback) ssl_nss_handshake_cb, gsc); +#endif SSL_ResetHandshake(nss_data->in, PR_FALSE); - if (SSL_ForceHandshake(nss_data->in)) - { - gaim_debug_error("nss", "Handshake failed\n"); - - if (gsc->error_cb != NULL) - gsc->error_cb(gsc, GAIM_SSL_HANDSHAKE_FAILED, gsc->connect_cb_data); + nss_data->handshake_handler = gaim_input_add(gsc->fd, + GAIM_INPUT_READ, ssl_nss_handshake_cb, gsc); - gaim_ssl_close(gsc); - - return; - } - - gsc->connect_cb(gsc->connect_cb_data, gsc, cond); + ssl_nss_handshake_cb(gsc, gsc->fd, GAIM_INPUT_READ); } static void @@ -240,26 +316,42 @@ if (nss_data->in) PR_Close(nss_data->in); /* if (nss_data->fd) PR_Close(nss_data->fd); */ + if (nss_data->handshake_handler) + gaim_input_remove(nss_data->handshake_handler); + g_free(nss_data); + gsc->private_data = NULL; } static size_t ssl_nss_read(GaimSslConnection *gsc, void *data, size_t len) { + ssize_t ret; GaimSslNssData *nss_data = GAIM_SSL_NSS_DATA(gsc); - return PR_Read(nss_data->in, data, len); + ret = PR_Read(nss_data->in, data, len); + + if (ret == -1) + set_errno(PR_GetError()); + + return ret; } static size_t ssl_nss_write(GaimSslConnection *gsc, const void *data, size_t len) { + ssize_t ret; GaimSslNssData *nss_data = GAIM_SSL_NSS_DATA(gsc); if(!nss_data) return 0; - return PR_Write(nss_data->in, data, len); + ret = PR_Write(nss_data->in, data, len); + + if (ret == -1) + set_errno(PR_GetError()); + + return ret; } static GaimSslOps ssl_ops =