Commit 1c672a3d authored by Rémi Denis-Courmont's avatar Rémi Denis-Courmont

- Non blocking TLS handshaking

parent c818ae89
......@@ -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))
......
......@@ -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 <fd>.
* 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;
......
......@@ -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 &&
......
......@@ -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;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment