Mercurial > pidgin
diff plugins/ssl/ssl-gnutls.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 | c18bd02be106 |
children | 7d513e44201b |
line wrap: on
line diff
--- a/plugins/ssl/ssl-gnutls.c Thu Feb 09 04:14:54 2006 +0000 +++ b/plugins/ssl/ssl-gnutls.c Thu Feb 09 04:17:56 2006 +0000 @@ -34,7 +34,7 @@ typedef struct { gnutls_session session; - + guint handshake_handler; } GaimSslGnutlsData; #define GAIM_SSL_GNUTLS_DATA(gsc) ((GaimSslGnutlsData *)gsc->private_data) @@ -48,7 +48,7 @@ gnutls_certificate_allocate_credentials(&xcred); gnutls_certificate_set_x509_trust_file(xcred, "ca.pem", - GNUTLS_X509_FMT_PEM); + GNUTLS_X509_FMT_PEM); } static gboolean @@ -65,15 +65,48 @@ gnutls_certificate_free_credentials(xcred); } + +static void ssl_gnutls_handshake_cb(gpointer data, gint source, + GaimInputCondition cond) +{ + GaimSslConnection *gsc = data; + GaimSslGnutlsData *gnutls_data = GAIM_SSL_GNUTLS_DATA(gsc); + ssize_t ret; + + gaim_debug_info("gnutls", "Handshaking\n"); + ret = gnutls_handshake(gnutls_data->session); + + if(ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED) + return; + + gaim_input_remove(gnutls_data->handshake_handler); + gnutls_data->handshake_handler = 0; + + if(ret != 0) { + gaim_debug_error("gnutls", "Handshake failed. Error %d\n", ret); + + if(gsc->error_cb != NULL) + gsc->error_cb(gsc, GAIM_SSL_HANDSHAKE_FAILED, + gsc->connect_cb_data); + + gaim_ssl_close(gsc); + } else { + gaim_debug_info("gnutls", "Handshake complete\n"); + + gsc->connect_cb(gsc->connect_cb_data, gsc, cond); + } + +} + + static void ssl_gnutls_connect_cb(gpointer data, gint source, GaimInputCondition cond) { GaimSslConnection *gsc = (GaimSslConnection *)data; GaimSslGnutlsData *gnutls_data; static const int cert_type_priority[2] = { GNUTLS_CRT_X509, 0 }; - int ret; - if (source < 0) { + if(source < 0) { if(gsc->error_cb != NULL) gsc->error_cb(gsc, GAIM_SSL_CONNECT_FAILED, gsc->connect_cb_data); @@ -90,37 +123,17 @@ gnutls_set_default_priority(gnutls_data->session); gnutls_certificate_type_set_priority(gnutls_data->session, - cert_type_priority); + cert_type_priority); gnutls_credentials_set(gnutls_data->session, GNUTLS_CRD_CERTIFICATE, - xcred); + xcred); gnutls_transport_set_ptr(gnutls_data->session, GINT_TO_POINTER(source)); - - do - { - gaim_debug_info("gnutls", "Handshaking\n"); - ret = gnutls_handshake(gnutls_data->session); - } - while ((ret == GNUTLS_E_AGAIN) || (ret == GNUTLS_E_INTERRUPTED)); - - if (ret < 0) - { - gaim_debug_error("gnutls", "Handshake failed. Error %d\n", ret); + gnutls_data->handshake_handler = gaim_input_add(gsc->fd, + GAIM_INPUT_READ, ssl_gnutls_handshake_cb, gsc); - if (gsc->error_cb != NULL) - gsc->error_cb(gsc, GAIM_SSL_HANDSHAKE_FAILED, - gsc->connect_cb_data); - - gaim_ssl_close(gsc); - } - else - { - gaim_debug_info("gnutls", "Handshake complete\n"); - - gsc->connect_cb(gsc->connect_cb_data, gsc, cond); - } + ssl_gnutls_handshake_cb(gsc, gsc->fd, GAIM_INPUT_READ); } static void @@ -131,27 +144,29 @@ if(!gnutls_data) return; + if(gnutls_data->handshake_handler) + gaim_input_remove(gnutls_data->handshake_handler); + gnutls_bye(gnutls_data->session, GNUTLS_SHUT_RDWR); gnutls_deinit(gnutls_data->session); g_free(gnutls_data); + gsc->private_data = NULL; } static size_t ssl_gnutls_read(GaimSslConnection *gsc, void *data, size_t len) { GaimSslGnutlsData *gnutls_data = GAIM_SSL_GNUTLS_DATA(gsc); - int s; + ssize_t s; + + s = gnutls_record_recv(gnutls_data->session, data, len); - do - { - s = gnutls_record_recv(gnutls_data->session, data, len); - } - while ((s == GNUTLS_E_AGAIN) || (s == GNUTLS_E_INTERRUPTED)); - - if (s < 0) - { + if(s == GNUTLS_E_AGAIN || s == GNUTLS_E_INTERRUPTED) { + s = -1; + errno = EAGAIN; + } else if(s < 0) { gaim_debug_error("gnutls", "receive failed: %d\n", s); s = 0; } @@ -163,11 +178,20 @@ ssl_gnutls_write(GaimSslConnection *gsc, const void *data, size_t len) { GaimSslGnutlsData *gnutls_data = GAIM_SSL_GNUTLS_DATA(gsc); - size_t s = 0; + ssize_t s = 0; + /* XXX: when will gnutls_data be NULL? */ if(gnutls_data) s = gnutls_record_send(gnutls_data->session, data, len); + if(s == GNUTLS_E_AGAIN || s == GNUTLS_E_INTERRUPTED) { + s = -1; + errno = EAGAIN; + } else if(s < 0) { + gaim_debug_error("gnutls", "send failed: %d\n", s); + s = 0; + } + return s; } @@ -187,7 +211,7 @@ plugin_load(GaimPlugin *plugin) { #ifdef HAVE_GNUTLS - if (!gaim_ssl_get_ops()) { + if(!gaim_ssl_get_ops()) { gaim_ssl_set_ops(&ssl_ops); } @@ -204,7 +228,7 @@ plugin_unload(GaimPlugin *plugin) { #ifdef HAVE_GNUTLS - if (gaim_ssl_get_ops() == &ssl_ops) { + if(gaim_ssl_get_ops() == &ssl_ops) { gaim_ssl_set_ops(NULL); } #endif