]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
Correctly restore gnutls_record_recv() in DTLS mode if interrupted during the retrasm...
authorNikos Mavrogiannopoulos <nmav@gnutls.org>
Fri, 21 Sep 2012 17:05:29 +0000 (19:05 +0200)
committerNikos Mavrogiannopoulos <nmav@gnutls.org>
Fri, 21 Sep 2012 17:05:29 +0000 (19:05 +0200)
NEWS
doc/cha-gtls-app.texi
lib/gnutls_dtls.c
lib/gnutls_dtls.h
lib/gnutls_int.h
lib/gnutls_record.c

diff --git a/NEWS b/NEWS
index 1e67f0b58cdb38e69b2c8659211cfac28215b29b..71466897afa7202f397c41693f56eda0b7e547f8 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -21,6 +21,9 @@ does not override it).
 an insecure level. If the %COMPAT priority flag is not specified
 the TLS connection fails.
 
+** libgnutls: Correctly restore gnutls_record_recv() in DTLS mode
+if interrupted during the retrasmition of handshake data.
+
 ** libgnutls: Better mingw32 support (patch by LRN).
 
 ** libgnutls: The %COMPAT keyword, if specified, will tolerate
index 3e84ba2cb02713911e964846108b798d99c235df..7b249153801120e5843dafabdd21aa2cc1e5550b 100644 (file)
@@ -686,7 +686,7 @@ function implies to restoring the same function that was interrupted, in
 the DTLS protocol this requirement isn't true.
 There are cases where a retransmission is required, which are indicated by
 a received message and thus @funcref{gnutls_record_get_direction} must be called 
-to decide which operation to restore, i.e., send or receive.
+to decide which direction to check prior to restoring a function call.
 @showfuncdesc{gnutls_record_get_direction}
 
 Moreover, to prevent blocking from DTLS' retransmission timers to block a
index 54c56815e8f2cf1e2f7de8d0b44c9776a0a4c41f..78e21fbf74a261393a3caef0ae6ab6efa2be8643 100644 (file)
@@ -157,15 +157,6 @@ static int drop_usage_count(gnutls_session_t session, mbuffer_head_st *const sen
   return 0;
 }
 
-/* This function is to be called from record layer once
- * a handshake replay is detected. It will make sure
- * it transmits only once per few seconds. Otherwise
- * it is the same as _dtls_transmit().
- */
-int _dtls_retransmit(gnutls_session_t session)
-{
-  return _dtls_transmit(session);
-}
 
 /* Checks whether the received packet contains a handshake
  * packet with sequence higher that the previously received.
index cd15f89643a2089139104dbd346889f79fc03bef..c97d470421ae55aa41cb77b388632453bad9cf7b 100644 (file)
@@ -31,7 +31,6 @@
 #include <timespec.h>
 
 int _dtls_transmit(gnutls_session_t session);
-int _dtls_retransmit(gnutls_session_t session);
 int _dtls_record_check(struct record_parameters_st *rp, uint64 * _seq);
 void _dtls_reset_hsk_state(gnutls_session_t session);
 
@@ -122,4 +121,14 @@ inline static int _dtls_async_timer_active(gnutls_session_t session)
   return session->internals.dtls.async_term;
 }
 
+/* This function is to be called from record layer once
+ * a handshake replay is detected. It will make sure
+ * it transmits only once per few seconds. Otherwise
+ * it is the same as _dtls_transmit().
+ */
+inline static int _dtls_retransmit(gnutls_session_t session)
+{
+  return _dtls_transmit(session);
+}
+
 #endif
index bf5280f51af950580631a465d6aaf8624b88a1bb..19494029536584a78c49198e8f8c1e92944d7552 100644 (file)
@@ -237,6 +237,12 @@ typedef enum heartbeat_state_t
   SHB_RECV, 
 } heartbeat_state_t;
 
+typedef enum recv_state_t
+{  
+  RECV_STATE_0 = 0, 
+  RECV_STATE_DTLS_RETRANSMIT,
+} recv_state_t;
+
 #include <gnutls_str.h>
 
 /* This is the maximum number of algorithms (ciphers or macs etc).
@@ -911,6 +917,8 @@ typedef struct
 
   heartbeat_state_t hb_state; /* for ping */
   
+  recv_state_t recv_state; /* state of the receive function */
+  
   /* If you add anything here, check _gnutls_handshake_internal_state_clear().
    */
 } internals_st;
index 79b49040300cdeafe797e478eb0c0d1917ce4c93..a361e054211b581830c107f66e0ef1d4ae9d9e73 100644 (file)
@@ -703,7 +703,7 @@ record_add_to_buffers (gnutls_session_t session,
                   ret = gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET);
                   goto unexpected_packet;
                 }
-                
+
               if (_dtls_is_async(session) && _dtls_async_timer_active(session))
                 {
                   if (session->security_parameters.entity == GNUTLS_SERVER &&
@@ -714,9 +714,11 @@ record_add_to_buffers (gnutls_session_t session,
                     }
                   else
                     {
+                      session->internals.recv_state = RECV_STATE_DTLS_RETRANSMIT;
                       ret = _dtls_retransmit(session);
                       if (ret == 0) 
                         {
+                          session->internals.recv_state = RECV_STATE_0;
                           ret = gnutls_assert_val(GNUTLS_E_AGAIN);
                           goto unexpected_packet;
                         }
@@ -1211,21 +1213,33 @@ _gnutls_recv_int (gnutls_session_t session, content_type_t type,
       gnutls_assert ();
       return GNUTLS_E_INVALID_SESSION;
     }
+    
+  switch(session->internals.recv_state)
+    {
+      case RECV_STATE_DTLS_RETRANSMIT:
+        ret = _dtls_retransmit(session);
+        if (ret < 0)
+          return gnutls_assert_val(ret);
+        
+        session->internals.recv_state = RECV_STATE_0;
+      case RECV_STATE_0:
+
+        _dtls_async_timer_check(session);
+        /* If we have enough data in the cache do not bother receiving
+         * a new packet. (in order to flush the cache)
+         */ 
+        ret = check_buffers (session, type, data, data_size, seq);
+        if (ret != 0)
+          return ret;
 
-  _dtls_async_timer_check(session);
-  
-  /* If we have enough data in the cache do not bother receiving
-   * a new packet. (in order to flush the cache)
-   */
-  ret = check_buffers (session, type, data, data_size, seq);
-  if (ret != 0)
-    return ret;
-
-  ret = _gnutls_recv_in_buffers(session, type, htype, ms);
-  if (ret < 0 && ret != GNUTLS_E_SESSION_EOF)
-    return gnutls_assert_val(ret);
+        ret = _gnutls_recv_in_buffers(session, type, htype, ms);
+        if (ret < 0 && ret != GNUTLS_E_SESSION_EOF)
+          return gnutls_assert_val(ret);
 
-  return check_buffers (session, type, data, data_size, seq);
+        return check_buffers (session, type, data, data_size, seq);
+      default:
+        return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
+    }
 }
 
 /**