diff options
Diffstat (limited to 'protocols/ssl_gnutls.c')
| -rw-r--r-- | protocols/ssl_gnutls.c | 81 | 
1 files changed, 65 insertions, 16 deletions
| 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 ) );  } | 
