aboutsummaryrefslogtreecommitdiffstats
path: root/protocols/ssl_gnutls.c
diff options
context:
space:
mode:
authorJelmer Vernooij <jelmer@samba.org>2005-12-17 02:25:58 +0100
committerJelmer Vernooij <jelmer@samba.org>2005-12-17 02:25:58 +0100
commit643dfc4be2e84dc4acb1a446867705e150480210 (patch)
tree90fe517fcac9490972f64b8cd99ec2f658c71359 /protocols/ssl_gnutls.c
parent4146a07de5f44f3ea00a3ef0026098b28e7451de (diff)
parent32c632fb46e58043a2d437c44cad783a59b7aea9 (diff)
Merge integration
Diffstat (limited to 'protocols/ssl_gnutls.c')
-rw-r--r--protocols/ssl_gnutls.c81
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 ) );
}