]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
More robust behavior against packet loss
authorNikos Mavrogiannopoulos <nmav@gnutls.org>
Fri, 10 Feb 2012 00:05:18 +0000 (01:05 +0100)
committerNikos Mavrogiannopoulos <nmav@gnutls.org>
Fri, 10 Feb 2012 00:05:18 +0000 (01:05 +0100)
lib/gnutls_dtls.c
lib/gnutls_record.c

index f6dcfac9ac9f759ebc7092cda7cfd0c24032c66b..666906480ef77ef8ac12bf7b5a282d20cf2ac233 100644 (file)
@@ -157,9 +157,13 @@ int ret;
 
 }
 
-#define UPDATE_TIMER \
+#define UPDATE_TIMER \
       session->internals.dtls.actual_retrans_timeout_ms *= 2; \
-      session->internals.dtls.actual_retrans_timeout_ms %= MAX_DTLS_TIMEOUT
+      session->internals.dtls.actual_retrans_timeout_ms %= MAX_DTLS_TIMEOUT; \
+    }
+
+#define RESET_TIMER \
+      session->internals.dtls.actual_retrans_timeout_ms = session->internals.dtls.retrans_timeout_ms
 
 /* This function transmits the flight that has been previously
  * buffered.
@@ -172,6 +176,7 @@ _dtls_transmit (gnutls_session_t session)
 {
 int ret;
 uint8_t* buf = NULL;
+unsigned int timeout;
 
   /* PREPARING -> SENDING state transition */
   mbuffer_head_st *const send_buffer =
@@ -184,13 +189,17 @@ uint8_t* buf = NULL;
    * non blocking way, check if it is time to retransmit or just
    * return.
    */
-
   if (session->internals.dtls.flight_init != 0 && session->internals.dtls.blocking == 0)
     {
       /* just in case previous run was interrupted */
       ret = _gnutls_io_write_flush (session);
+      if (ret < 0)
+        {
+          gnutls_assert();
+          goto cleanup;
+        }
 
-      if (session->internals.dtls.last_flight == 0)
+      if (session->internals.dtls.last_flight == 0 || !_dtls_is_async(session))
         {
           /* check for ACK */
           ret = _gnutls_io_check_recv(session, 0);
@@ -198,8 +207,8 @@ uint8_t* buf = NULL;
             {
               /* if no retransmission is required yet just return 
                */
-              if (now-session->internals.dtls.handshake_start_time < 
-                  session->internals.dtls.actual_retrans_timeout_ms/1000)
+              if (1000*(now-session->internals.dtls.handshake_start_time) < 
+                  session->internals.dtls.actual_retrans_timeout_ms)
                 {
                   session->internals.dtls.handshake_last_call = now;
                   goto nb_timeout;
@@ -215,55 +224,49 @@ uint8_t* buf = NULL;
 
   do 
     {
-      if (now-session->internals.dtls.handshake_start_time >= session->internals.dtls.total_timeout_ms/1000
+      if (1000*(now-session->internals.dtls.handshake_start_time) >= session->internals.dtls.total_timeout_ms
         {
           ret = gnutls_assert_val(GNUTLS_E_TIMEDOUT);
           goto cleanup;
         }
-        
-      if ((session->internals.dtls.flight_init == 0) ||
-          (now - session->internals.dtls.last_retransmit > RETRANSMIT_WINDOW))
-        {
-          session->internals.dtls.last_retransmit = now;
 
-          _gnutls_dtls_log ("DTLS[%p]: %sStart of flight transmission.\n", session,  (session->internals.dtls.flight_init == 0)?"":"re-");
+      _gnutls_dtls_log ("DTLS[%p]: %sStart of flight transmission.\n", session,  (session->internals.dtls.flight_init == 0)?"":"re-");
 
-          for (cur = send_buffer->head;
-               cur != NULL; cur = cur->next)
+      for (cur = send_buffer->head;
+           cur != NULL; cur = cur->next)
+        {
+          ret = transmit_message (session, cur, &buf);
+          if (ret < 0)
             {
-              ret = transmit_message (session, cur, &buf);
-              if (ret < 0)
-                {
-                  gnutls_assert();
-                  goto cleanup;
-                }
-
-              last_type = cur->htype;
+              gnutls_assert();
+              goto cleanup;
             }
 
-          if (buf != NULL)
-            {
-              gnutls_free(buf);
-              buf = NULL;
-            }
+          last_type = cur->htype;
+        }
 
-          if (session->internals.dtls.flight_init == 0)
-            {
-              session->internals.dtls.flight_init = 1;
-              session->internals.dtls.handshake_last_call = now;
-              session->internals.dtls.actual_retrans_timeout_ms = session->internals.dtls.retrans_timeout_ms;
+      if (session->internals.dtls.flight_init == 0)
+        {
+          session->internals.dtls.flight_init = 1;
+          session->internals.dtls.handshake_last_call = now;
+          RESET_TIMER;
+          timeout = session->internals.dtls.actual_retrans_timeout_ms;
 
-              if (last_type == GNUTLS_HANDSHAKE_FINISHED)
-                {
-                  /* On the last flight we cannot ensure retransmission
-                   * from here. _dtls_wait_and_retransmit() is being called
-                   * by handshake.
-                   */
-                  session->internals.dtls.last_flight = 1;
-                }
-              else
-                session->internals.dtls.last_flight = 0;
-           }
+          if (last_type == GNUTLS_HANDSHAKE_FINISHED)
+            {
+              /* On the last flight we cannot ensure retransmission
+               * from here. _dtls_wait_and_retransmit() is being called
+               * by handshake.
+               */
+              session->internals.dtls.last_flight = 1;
+            }
+          else
+            session->internals.dtls.last_flight = 0;
+        }
+      else
+        {
+          timeout = session->internals.dtls.actual_retrans_timeout_ms;
+          UPDATE_TIMER;
         }
 
       ret = _gnutls_io_write_flush (session);
@@ -283,19 +286,17 @@ uint8_t* buf = NULL;
       else /* all other messages -> implicit ack (receive of next flight) */
         {
           if (session->internals.dtls.blocking != 0)
-            ret = _gnutls_io_check_recv(session, session->internals.dtls.actual_retrans_timeout_ms);
+            ret = _gnutls_io_check_recv(session, timeout);
           else
             {
               ret = _gnutls_io_check_recv(session, 0);
               if (ret == GNUTLS_E_TIMEDOUT)
                 {
-                  UPDATE_TIMER;
                   goto nb_timeout;
                 }
             }
         }
 
-      UPDATE_TIMER;
       now = gnutls_time (0);
     } while(ret == GNUTLS_E_TIMEDOUT);
 
@@ -320,6 +321,9 @@ cleanup:
   return ret;
 
 nb_timeout:
+  if (buf != NULL)
+    gnutls_free(buf);
+
   RETURN_DTLS_EAGAIN_OR_TIMEOUT(session);
 }
 
@@ -335,8 +339,6 @@ int ret;
   else
     ret = _gnutls_io_check_recv(session, 0);
 
-  UPDATE_TIMER;
-      
   if (ret == GNUTLS_E_TIMEDOUT)
     {
       ret = _dtls_retransmit(session);
@@ -344,6 +346,8 @@ int ret;
         {
           RETURN_DTLS_EAGAIN_OR_TIMEOUT(session);
         }
+      else
+        return gnutls_assert_val(ret);
     }
 
   return 0;
@@ -404,28 +408,19 @@ unsigned int i, offset = 0;
       if (diff >= window_size) 
         {
           /* Probably an epoch change. Check if we can fit it */
-          if (window_table[0] == 0)
+          if (window_table[0] == 0 || window_table[0]+1 == seq)
             {
               window_table[0] = seq;
               return 0;
             }
           
-          for (i=0;i<window_size-1;i++)
-            {
-              if (seq == window_table[i])
-                return -1;
-              if (seq == window_table[i] + 1)
-                {
-                  if (seq == window_table[i+1])
-                    return -1;
-                  window_table[i+1] = seq;
-                  return 0;
-                }
-            }
-          return -1;
-        }
+          if ((window_size-2)/2 < 2)
+            return -1;
 
-      offset = window_size-1-diff;
+          offset = 1 + seq % ((window_size-2)/2);
+        }
+      else
+        offset = window_size-1-diff;
 
       if (window_table[offset] == seq)
         return -1;
index b33b0fb8ced79a0569f43f67ca919467f03c9018..d55fb049b6fb8557e529b510ab0e6515e7e7a0d1 100644 (file)
@@ -865,9 +865,9 @@ gnutls_datum_t raw; /* raw headers */
     {
       if (_gnutls_epoch_is_valid(session, record->epoch) == 0)
         {
-          _gnutls_audit_log(session, "Discarded message[%u] with invalid epoch 0x%.2x%.2x.\n",
-            (unsigned int)_gnutls_uint64touint32 (&record->sequence), (int)record->sequence.i[0], 
-            (int)record->sequence.i[1]);
+          _gnutls_audit_log(session, "Discarded message[%u] with invalid epoch %u.\n",
+            (unsigned int)_gnutls_uint64touint32 (&record->sequence), 
+            (unsigned int)record->sequence.i[0]*256+(unsigned int)record->sequence.i[1]);
           gnutls_assert();
           /* doesn't matter, just a fatal error */
           return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
@@ -1028,12 +1028,19 @@ begin:
             (unsigned int) _gnutls_uint64touint32 (packet_sequence), _gnutls_packet2str (record.type));
           goto sanity_check_error;
         }
+      _gnutls_record_log
+        ("REC[%p]: Decrypted Packet[%u.%u] %s(%d) with length: %d\n", session,
+        (unsigned int)record.sequence.i[0]*256 +(unsigned int)record.sequence.i[1],
+        (unsigned int) _gnutls_uint64touint32 (packet_sequence),
+        _gnutls_packet2str (record.type), record.type, (int)_mbuffer_get_udata_size(decrypted));
+    }
+  else
+    {
+      _gnutls_record_log
+        ("REC[%p]: Decrypted Packet[%u] %s(%d) with length: %d\n", session,
+        (unsigned int) _gnutls_uint64touint32 (packet_sequence),
+        _gnutls_packet2str (record.type), record.type, (int)_mbuffer_get_udata_size(decrypted));
     }
-
-  _gnutls_record_log
-    ("REC[%p]: Decrypted Packet[%d] %s(%d) with length: %d\n", session,
-     (int) _gnutls_uint64touint32 (packet_sequence),
-     _gnutls_packet2str (record.type), record.type, (int)_mbuffer_get_udata_size(decrypted));
 
   /* increase sequence number 
    */