diff options
| author | Wilmer van der Gaast <wilmer@gaast.net> | 2005-12-18 02:02:29 +0100 | 
|---|---|---|
| committer | Wilmer van der Gaast <wilmer@gaast.net> | 2005-12-18 02:02:29 +0100 | 
| commit | a03a9f376fe2fd1737ba7af6a87d99fe43a2a72e (patch) | |
| tree | e91c630b2f1a5ec48bd692c1ab6f54136adf5829 | |
| parent | 7c0a4975a538ab75405e64919bbdfee51b898b2e (diff) | |
Non-blocking I/O for OpenSSL, plus some extra (important) cleanup code for GnuTLS.
| -rw-r--r-- | protocols/ssl_gnutls.c | 6 | ||||
| -rw-r--r-- | protocols/ssl_openssl.c | 80 | 
2 files changed, 79 insertions, 7 deletions
| diff --git a/protocols/ssl_gnutls.c b/protocols/ssl_gnutls.c index 2e307aab..f2cb3e08 100644 --- a/protocols/ssl_gnutls.c +++ b/protocols/ssl_gnutls.c @@ -110,7 +110,10 @@ static void ssl_handshake( gpointer data, gint source, GaimInputCondition cond )  	int st;  	if( conn->inpa != -1 ) +	{  		gaim_input_remove( conn->inpa ); +		conn->inpa = -1; +	}  	if( ( st = gnutls_handshake( conn->session ) ) < 0 )  	{ @@ -182,6 +185,9 @@ void ssl_disconnect( void *conn_ )  {  	struct scd *conn = conn_; +	if( conn->inpa != -1 ) +		gaim_input_remove( conn->inpa ); +	  	if( conn->established )  		gnutls_bye( conn->session, GNUTLS_SHUT_WR ); diff --git a/protocols/ssl_openssl.c b/protocols/ssl_openssl.c index 5a107fc5..ae55f3f9 100644 --- a/protocols/ssl_openssl.c +++ b/protocols/ssl_openssl.c @@ -45,6 +45,8 @@ struct scd  	int fd;  	gboolean established; +	int inpa; +	int lasterr;		/* Necessary for SSL_get_error */  	SSL *ssl;  	SSL_CTX *ssl_ctx;  }; @@ -92,19 +94,45 @@ void *ssl_connect( char *host, int port, ssl_input_function 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; +		return ssl_handshake( data, -1, cond ); +	/* Make it non-blocking at least during the handshake... */ +	sock_make_nonblocking( conn->fd );  	SSL_set_fd( conn->ssl, conn->fd ); -	if( SSL_connect( conn->ssl ) < 0 ) -		goto ssl_connected_failure; +	return ssl_handshake( data, source, cond ); +}	 + +static void ssl_handshake( gpointer data, gint source, GaimInputCondition cond ) +{ +	struct scd *conn = data; +	int st; +	 +	if( conn->inpa != -1 ) +	{ +		gaim_input_remove( conn->inpa ); +		conn->inpa = -1; +	} +	 +	if( ( st = SSL_connect( conn->ssl ) ) < 0 ) +	{ +		conn->lasterr = SSL_get_error( conn->ssl, st ); +		if( conn->lasterr != SSL_ERROR_WANT_READ && conn->lasterr != SSL_ERROR_WANT_WRITE ) +			goto ssl_connected_failure; +		 +		conn->inpa = gaim_input_add( conn->fd, ssl_getdirection( conn ), ssl_handshake, data ); +		return; +	}  	conn->established = TRUE; +	sock_make_blocking( conn->fd );		/* For now... */  	conn->func( conn->data, conn, cond );  	return; @@ -126,24 +154,57 @@ ssl_connected_failure:  int ssl_read( void *conn, char *buf, int len )  { +	int st; +	  	if( !((struct scd*)conn)->established ) -		return( 0 ); +	{ +		ssl_errno = SSL_NOHANDSHAKE; +		return -1; +	} +	 +	st = SSL_read( ((struct scd*)conn)->ssl, buf, len ); -	return( SSL_read( ((struct scd*)conn)->ssl, buf, len ) ); +	ssl_errno = SSL_OK; +	if( st <= 0 ) +	{ +		((struct scd*)conn)->lasterr = SSL_get_error( ((struct scd*)conn)->ssl, st ); +		if( ((struct scd*)conn)->lasterr == SSL_ERROR_WANT_READ || ((struct scd*)conn)->lasterr == SSL_ERROR_WANT_WRITE ) +			ssl_errno = SSL_AGAIN; +	} +	 +	return st;  }  int ssl_write( void *conn, const char *buf, int len )  { +	int st; +	  	if( !((struct scd*)conn)->established ) -		return( 0 ); +	{ +		ssl_errno = SSL_NOHANDSHAKE; +		return -1; +	} +	 +	st = SSL_write( ((struct scd*)conn)->ssl, buf, len ); -	return( SSL_write( ((struct scd*)conn)->ssl, buf, len ) ); +	ssl_errno = SSL_OK; +	if( st <= 0 ) +	{ +		((struct scd*)conn)->lasterr = SSL_get_error( ((struct scd*)conn)->ssl, st ); +		if( ((struct scd*)conn)->lasterr == SSL_ERROR_WANT_READ || ((struct scd*)conn)->lasterr == SSL_ERROR_WANT_WRITE ) +			ssl_errno = SSL_AGAIN; +	} +	 +	return st;  }  void ssl_disconnect( void *conn_ )  {  	struct scd *conn = conn_; +	if( conn->inpa != -1 ) +		gaim_input_remove( conn->inpa ); +	  	if( conn->established )  		SSL_shutdown( conn->ssl ); @@ -158,3 +219,8 @@ int ssl_getfd( void *conn )  {  	return( ((struct scd*)conn)->fd );  } + +GaimInputCondition ssl_getdirection( void *conn ) +{ +	return( ((struct scd*)conn)->lasterr == SSL_ERROR_WANT_WRITE ? GAIM_INPUT_WRITE : GAIM_INPUT_READ ); +} | 
