diff options
-rw-r--r-- | protocols/oscar/conn.c | 4 | ||||
-rw-r--r-- | protocols/proxy.c | 14 | ||||
-rw-r--r-- | protocols/ssl_bogus.c | 2 | ||||
-rw-r--r-- | protocols/ssl_client.h | 6 | ||||
-rw-r--r-- | protocols/ssl_gnutls.c | 81 | ||||
-rw-r--r-- | protocols/ssl_nss.c | 2 | ||||
-rw-r--r-- | protocols/ssl_openssl.c | 2 | ||||
-rw-r--r-- | sock.h | 2 |
8 files changed, 84 insertions, 29 deletions
diff --git a/protocols/oscar/conn.c b/protocols/oscar/conn.c index 0155e5bc..77ffd50f 100644 --- a/protocols/oscar/conn.c +++ b/protocols/oscar/conn.c @@ -626,9 +626,7 @@ int aim_conn_completeconnect(aim_session_t *sess, aim_conn_t *conn) return -1; } -#ifndef _WIN32 - fcntl(conn->fd, F_SETFL, 0); /* XXX should restore original flags */ -#endif + sock_make_blocking(conn->fd); conn->status &= ~AIM_CONN_STATUS_INPROGRESS; diff --git a/protocols/proxy.c b/protocols/proxy.c index 0546f2d7..c658a163 100644 --- a/protocols/proxy.c +++ b/protocols/proxy.c @@ -132,8 +132,8 @@ static void gaim_io_connected(gpointer data, gint source, GaimInputCondition con } return; } - fcntl(source, F_SETFL, 0); #endif + sock_make_blocking(source); gaim_input_remove(phb->inpa); if( phb->proxy_func ) phb->proxy_func(phb->proxy_data, source, GAIM_INPUT_READ); @@ -228,9 +228,7 @@ static void http_canwrite(gpointer data, gint source, GaimInputCondition cond) g_free(phb); return; } -#ifdef F_SETFL - fcntl(source, F_SETFL, 0); -#endif + sock_make_blocking(source); g_snprintf(cmd, sizeof(cmd), "CONNECT %s:%d HTTP/1.1\r\nHost: %s:%d\r\n", phb->host, phb->port, phb->host, phb->port); @@ -321,9 +319,7 @@ static void s4_canwrite(gpointer data, gint source, GaimInputCondition cond) g_free(phb); return; } -#ifdef F_SETFL - fcntl(source, F_SETFL, 0); -#endif + sock_make_blocking(source); /* XXX does socks4 not support host name lookups by the proxy? */ if (!(hp = gethostbyname(phb->host))) { @@ -508,9 +504,7 @@ static void s5_canwrite(gpointer data, gint source, GaimInputCondition cond) g_free(phb); return; } -#ifdef F_SETFL - fcntl(source, F_SETFL, 0); -#endif + sock_make_blocking(source); i = 0; buf[0] = 0x05; /* SOCKS version 5 */ diff --git a/protocols/ssl_bogus.c b/protocols/ssl_bogus.c index 226997db..1ee0df4c 100644 --- a/protocols/ssl_bogus.c +++ b/protocols/ssl_bogus.c @@ -25,6 +25,8 @@ #include "ssl_client.h" +int ssl_errno; + void *ssl_connect( char *host, int port, SslInputFunction func, gpointer data ) { return( NULL ); diff --git a/protocols/ssl_client.h b/protocols/ssl_client.h index a829a7b1..719cd0c4 100644 --- a/protocols/ssl_client.h +++ b/protocols/ssl_client.h @@ -26,6 +26,12 @@ #include <glib.h> #include "proxy.h" +#define SSL_OK 0 +#define SSL_NOHANDSHAKE 1 +#define SSL_AGAIN 2 + +extern int ssl_errno; + typedef void (*SslInputFunction)(gpointer, void*, GaimInputCondition); G_MODULE_EXPORT void *ssl_connect( char *host, int port, SslInputFunction func, gpointer data ); diff --git a/protocols/ssl_gnutls.c b/protocols/ssl_gnutls.c index 535d126e..c2eb6906 100644 --- a/protocols/ssl_gnutls.c +++ b/protocols/ssl_gnutls.c @@ -24,11 +24,15 @@ */ #include <gnutls/gnutls.h> +#include <fcntl.h> +#include <unistd.h> #include "proxy.h" #include "ssl_client.h" #include "sock.h" #include "stdlib.h" +int ssl_errno = 0; + static gboolean initialized = FALSE; struct scd @@ -37,6 +41,7 @@ struct scd gpointer data; int fd; gboolean established; + int inpa; gnutls_session session; gnutls_certificate_credentials xcred; @@ -45,7 +50,6 @@ struct scd static void ssl_connected( gpointer data, gint source, GaimInputCondition cond ); - void *ssl_connect( char *host, int port, SslInputFunction func, gpointer data ) { struct scd *conn = g_new0( struct scd, 1 ); @@ -53,6 +57,7 @@ void *ssl_connect( char *host, int port, SslInputFunction func, gpointer data ) conn->fd = proxy_connect( host, port, ssl_connected, conn ); conn->func = func; conn->data = data; + conn->inpa = -1; if( conn->fd < 0 ) { @@ -75,43 +80,87 @@ void *ssl_connect( char *host, int port, SslInputFunction func, gpointer data ) return( conn ); } +static void ssl_handshake( gpointer data, gint source, GaimInputCondition cond ); + static void ssl_connected( gpointer data, gint source, GaimInputCondition cond ) { struct scd *conn = data; if( source == -1 ) - goto ssl_connected_failure; + { + conn->func( conn->data, NULL, cond ); + + gnutls_deinit( conn->session ); + gnutls_certificate_free_credentials( conn->xcred ); + + g_free( conn ); + + return; + } + sock_make_nonblocking( conn->fd ); gnutls_transport_set_ptr( conn->session, (gnutls_transport_ptr) conn->fd ); - if( gnutls_handshake( conn->session ) < 0 ) - goto ssl_connected_failure; - - conn->established = TRUE; - conn->func( conn->data, conn, cond ); - return; + ssl_handshake( data, source, cond ); +} + +static void ssl_handshake( gpointer data, gint source, GaimInputCondition cond ) +{ + struct scd *conn = data; + int st; -ssl_connected_failure: - conn->func( conn->data, NULL, cond ); + if( conn->inpa != -1 ) + gaim_input_remove( conn->inpa ); - gnutls_deinit( conn->session ); - gnutls_certificate_free_credentials( conn->xcred ); - if( source >= 0 ) closesocket( source ); - g_free( conn ); + if( ( st = gnutls_handshake( conn->session ) ) < 0 ) + { + if( st == GNUTLS_E_AGAIN || st == GNUTLS_E_INTERRUPTED ) + { + conn->inpa = gaim_input_add( conn->fd, + gnutls_record_get_direction( conn->session ) ? + GAIM_INPUT_WRITE : GAIM_INPUT_READ, + ssl_handshake, data ); + } + else + { + conn->func( conn->data, NULL, cond ); + + gnutls_deinit( conn->session ); + gnutls_certificate_free_credentials( conn->xcred ); + closesocket( conn->fd ); + + g_free( conn ); + } + } + else + { + /* For now we can't handle non-blocking perfectly everywhere... */ + sock_make_blocking( conn->fd ); + + conn->established = TRUE; + conn->func( conn->data, conn, cond ); + } } int ssl_read( void *conn, char *buf, int len ) { if( !((struct scd*)conn)->established ) - return( 0 ); + { + ssl_errno = SSL_NOHANDSHAKE; + return( -1 ); + } return( gnutls_record_recv( ((struct scd*)conn)->session, buf, len ) ); + } int ssl_write( void *conn, const char *buf, int len ) { if( !((struct scd*)conn)->established ) - return( 0 ); + { + ssl_errno = SSL_NOHANDSHAKE; + return( -1 ); + } return( gnutls_record_send( ((struct scd*)conn)->session, buf, len ) ); } diff --git a/protocols/ssl_nss.c b/protocols/ssl_nss.c index 7c5f5637..d28983fc 100644 --- a/protocols/ssl_nss.c +++ b/protocols/ssl_nss.c @@ -38,6 +38,8 @@ #include <secerr.h> #include <sslerr.h> +int ssl_errno = 0; + static gboolean initialized = FALSE; struct scd diff --git a/protocols/ssl_openssl.c b/protocols/ssl_openssl.c index d2a7e1fe..bf87ab73 100644 --- a/protocols/ssl_openssl.c +++ b/protocols/ssl_openssl.c @@ -34,6 +34,8 @@ #include "ssl_client.h" #include "sock.h" +int ssl_errno = 0; + static gboolean initialized = FALSE; struct scd @@ -5,6 +5,7 @@ #include <arpa/inet.h> #include <netdb.h> #define sock_make_nonblocking(fd) fcntl(fd, F_SETFL, O_NONBLOCK) +#define sock_make_blocking(fd) fcntl(fd, F_SETFL, 0) #define sockerr_again() (errno == EINPROGRESS || errno == EINTR) #define closesocket(a) close(a) #else @@ -21,6 +22,7 @@ # define umask _umask # define mode_t int # define sock_make_nonblocking(fd) { int non_block = 1; ioctlsocket(fd, FIONBIO, &non_block); } +# define sock_make_blocking(fd) { int non_block = 0; ioctlsocket(fd, FIONBIO, &non_block); } # define sockerr_again() (WSAGetLastError() == WSAEINTR || WSAGetLastError() == WSAEINPROGRESS || WSAGetLastError() == WSAEWOULDBLOCK) # define ETIMEDOUT WSAETIMEDOUT # define sleep(a) Sleep(a*1000) |