From 1c672a3d5cead318809db9b030f928e9fc4a8c72 Mon Sep 17 00:00:00 2001 From: =?utf8?q?R=C3=A9mi=20Denis-Courmont?= Date: Sat, 25 Dec 2004 21:35:09 +0000 Subject: [PATCH] - Non blocking TLS handshaking --- include/vlc_tls.h | 4 ++- modules/misc/gnutls.c | 38 +++++++++++++-------- src/misc/httpd.c | 77 ++++++++++++++++++++++++++++++++++++++----- src/misc/tls.c | 3 +- 4 files changed, 98 insertions(+), 24 deletions(-) diff --git a/include/vlc_tls.h b/include/vlc_tls.h index 98c465b5cc..2982f95533 100644 --- a/include/vlc_tls.h +++ b/include/vlc_tls.h @@ -59,7 +59,8 @@ struct tls_session_t void *p_sys; struct virtual_socket_t sock; - tls_session_t * (*pf_handshake) ( tls_session_t *, int ); + int (*pf_handshake) ( tls_session_t *, int ); + int (*pf_handshake2) ( tls_session_t * ); void (*pf_close) ( tls_session_t * ); }; @@ -102,6 +103,7 @@ VLC_EXPORT( tls_session_t *, tls_ClientCreate, ( vlc_object_t *, const char *, i VLC_EXPORT( void, tls_ClientDelete, ( tls_session_t * ) ); # define tls_SessionHandshake( a, b ) (((tls_session_t *)a)->pf_handshake (a, b)) +# define tls_SessionContinueHandshake( a ) (((tls_session_t *)a)->pf_handshake2 (a)) # define tls_SessionClose( a ) (((tls_session_t *)a)->pf_close (a)) diff --git a/modules/misc/gnutls.c b/modules/misc/gnutls.c index 74c3f0374b..b55f59345b 100644 --- a/modules/misc/gnutls.c +++ b/modules/misc/gnutls.c @@ -128,26 +128,25 @@ gnutls_Recv( void *p_session, void *buf, int i_length ) /***************************************************************************** - * tls_SessionHandshake: + * tls_Session(Continue)?Handshake: ***************************************************************************** * Establishes TLS session with a peer through socket . - * Returns NULL on error (do NOT call tls_SessionClose in case of error or - * re-use the session structure). + * Returns -1 on error (you need not and must not call tls_SessionClose) + * 0 on succesful handshake completion, 1 if more would-be blocking recv is + * needed, 2 if more would-be blocking send is required. *****************************************************************************/ -static tls_session_t * -gnutls_SessionHandshake( tls_session_t *p_session, int fd ) +static int +gnutls_SessionContinueHandshake( tls_session_t *p_session) { tls_session_sys_t *p_sys; int val; p_sys = (tls_session_sys_t *)(p_session->p_sys); - gnutls_transport_set_ptr (p_sys->session, (gnutls_transport_ptr)fd); - - do - /* TODO: handle fatal error */ - val = gnutls_handshake( p_sys->session ); - while( ( val == GNUTLS_E_AGAIN ) || ( val == GNUTLS_E_INTERRUPTED ) ); + /* TODO: handle fatal error */ + val = gnutls_handshake( p_sys->session ); + if( ( val == GNUTLS_E_AGAIN ) || ( val == GNUTLS_E_INTERRUPTED ) ) + return 1 + gnutls_record_get_direction( p_sys->session ); if( val < 0 ) { @@ -156,10 +155,22 @@ gnutls_SessionHandshake( tls_session_t *p_session, int fd ) gnutls_strerror( val ) ); free( p_sys ); free( p_session ); - return NULL; + return -1; } - return p_session; + return 0; +} + +static int +gnutls_SessionHandshake( tls_session_t *p_session, int fd ) +{ + tls_session_sys_t *p_sys; + + p_sys = (tls_session_sys_t *)(p_session->p_sys); + + gnutls_transport_set_ptr (p_sys->session, (gnutls_transport_ptr)fd); + + return gnutls_SessionContinueHandshake( p_session ); } @@ -376,6 +387,7 @@ gnutls_ServerSessionPrepare( tls_server_t *p_server ) p_session->sock.pf_send = gnutls_Send; p_session->sock.pf_recv = gnutls_Recv; p_session->pf_handshake = gnutls_SessionHandshake; + p_session->pf_handshake2 = gnutls_SessionContinueHandshake; p_session->pf_close = gnutls_SessionClose; return p_session; diff --git a/src/misc/httpd.c b/src/misc/httpd.c index ad29f62c7c..97f433126e 100644 --- a/src/misc/httpd.c +++ b/src/misc/httpd.c @@ -264,6 +264,9 @@ enum HTTPD_CLIENT_WAITING, HTTPD_CLIENT_DEAD, + + HTTPD_CLIENT_TLS_HS_IN, + HTTPD_CLIENT_TLS_HS_OUT }; /* mode */ enum @@ -2020,6 +2023,41 @@ static void httpd_ClientSend( httpd_client_t *cl ) } } +static void httpd_ClientTlsHsIn( httpd_client_t *cl ) +{ + switch( tls_SessionContinueHandshake( cl->p_tls ) ) + { + case 0: + cl->i_state = HTTPD_CLIENT_RECEIVING; + break; + + case -1: + cl->i_state = HTTPD_CLIENT_DEAD; + break; + + case 2: + cl->i_state = HTTPD_CLIENT_TLS_HS_OUT; + } +} + +static void httpd_ClientTlsHsOut( httpd_client_t *cl ) +{ + switch( tls_SessionContinueHandshake( cl->p_tls ) ) + { + case 0: + cl->i_state = HTTPD_CLIENT_RECEIVING; + break; + + case -1: + cl->i_state = HTTPD_CLIENT_DEAD; + break; + + case 1: + cl->i_state = HTTPD_CLIENT_TLS_HS_IN; + break; + } +} + static void httpd_HostThread( httpd_host_t *host ) { tls_session_t *p_tls = NULL; @@ -2077,12 +2115,14 @@ static void httpd_HostThread( httpd_host_t *host ) i_client--; continue; } - else if( cl->i_state == HTTPD_CLIENT_RECEIVING ) + else if( ( cl->i_state == HTTPD_CLIENT_RECEIVING ) + || ( cl->i_state == HTTPD_CLIENT_TLS_HS_IN ) ) { FD_SET( cl->fd, &fds_read ); i_handle_max = __MAX( i_handle_max, cl->fd ); } - else if( cl->i_state == HTTPD_CLIENT_SENDING ) + else if( ( cl->i_state == HTTPD_CLIENT_SENDING ) + || ( cl->i_state == HTTPD_CLIENT_TLS_HS_OUT ) ) { FD_SET( cl->fd, &fds_write ); i_handle_max = __MAX( i_handle_max, cl->fd ); @@ -2422,6 +2462,8 @@ static void httpd_HostThread( httpd_host_t *host ) fd = accept( host->fd, (struct sockaddr *)&sock, &i_sock_size ); if( fd >= 0 ) { + int i_state = 0; + /* set this new socket non-block */ #if defined( WIN32 ) || defined( UNDER_CE ) { @@ -2435,12 +2477,21 @@ static void httpd_HostThread( httpd_host_t *host ) /* FIXME: that MUST be non-blocking */ if( p_tls != NULL) { - p_tls = tls_SessionHandshake( p_tls, fd ); - if ( p_tls == NULL ) + switch ( tls_SessionHandshake( p_tls, fd ) ) { - msg_Err( host, "Rejecting TLS connection" ); - net_Close( fd ); - fd = -1; + case -1: + msg_Err( host, "Rejecting TLS connection" ); + net_Close( fd ); + fd = -1; + break; + + case 1: /* missing input - most likely */ + i_state = HTTPD_CLIENT_TLS_HS_IN; + break; + + case 2: /* missing output */ + i_state = HTTPD_CLIENT_TLS_HS_OUT; + break; } } @@ -2455,7 +2506,9 @@ static void httpd_HostThread( httpd_host_t *host ) TAB_APPEND( host->i_client, host->client, cl ); vlc_mutex_unlock( &host->lock ); - + if( i_state != 0 ) + cl->i_state = i_state; // override state for TLS + // FIXME: it sucks to allocate memory for debug ip = httpd_ClientIP( cl ); msg_Dbg( host, "new connection (%s)", @@ -2478,6 +2531,14 @@ static void httpd_HostThread( httpd_host_t *host ) { httpd_ClientSend( cl ); } + else if( cl->i_state == HTTPD_CLIENT_TLS_HS_IN ) + { + httpd_ClientTlsHsIn( cl ); + } + else if( cl->i_state == HTTPD_CLIENT_TLS_HS_OUT ) + { + httpd_ClientTlsHsOut( cl ); + } if( cl->i_mode == HTTPD_CLIENT_BIDIR && cl->i_state == HTTPD_CLIENT_SENDING && diff --git a/src/misc/tls.c b/src/misc/tls.c index ce16b02734..689c8b8991 100644 --- a/src/misc/tls.c +++ b/src/misc/tls.c @@ -114,8 +114,7 @@ tls_ClientCreate( vlc_object_t *p_this, const char *psz_ca, int fd ) p_session = __tls_ClientCreate( p_tls, psz_ca ); if( p_session != NULL ) { - p_session = tls_SessionHandshake( p_session, fd ); - if( p_session != NULL ) + if( tls_SessionHandshake( p_session, fd ) ) { msg_Dbg( p_this, "TLS/SSL provider initialized" ); return p_session; -- 2.39.2