]> git.sesse.net Git - vlc/commitdiff
- Non blocking TLS handshaking
authorRémi Denis-Courmont <rem@videolan.org>
Sat, 25 Dec 2004 21:35:09 +0000 (21:35 +0000)
committerRémi Denis-Courmont <rem@videolan.org>
Sat, 25 Dec 2004 21:35:09 +0000 (21:35 +0000)
include/vlc_tls.h
modules/misc/gnutls.c
src/misc/httpd.c
src/misc/tls.c

index 98c465b5cc3e6a7ed55336c793953d96627970a6..2982f9553317f1533e15b546ca45230ee193cdda 100644 (file)
@@ -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))
 
index 74c3f0374bf6e943b1aa1c23dc6a7fc45c169487..b55f59345b57ce20951e99f9918e3121abcc40a5 100644 (file)
@@ -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;
index ad29f62c7c9287426c0c706c39bd944da3ca5045..97f433126e9f677b1ae6ddb2a3989f7aae5c1f2e 100644 (file)
@@ -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 &&
index ce16b02734a223b39cc66614b96a9e34ea5a022d..689c8b8991de155302ad59e060e40899f5698bb8 100644 (file)
@@ -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;