]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
internal buffering for record and handshake data changed from gnutls_buffers to gnutl...
authorNikos Mavrogiannopoulos <nmav@gnutls.org>
Sat, 26 Feb 2011 10:27:13 +0000 (11:27 +0100)
committerNikos Mavrogiannopoulos <nmav@gnutls.org>
Wed, 2 Mar 2011 17:45:59 +0000 (18:45 +0100)
lib/gnutls_buffers.c
lib/gnutls_buffers.h
lib/gnutls_dtls.c
lib/gnutls_int.h
lib/gnutls_mbuffers.c
lib/gnutls_mbuffers.h
lib/gnutls_record.c
lib/gnutls_record.h
lib/gnutls_state.c

index a5b7eedd221194fa2a662254f34f06d3b93bcb1f..490b40cc7a62091af6859b160fcd959ebb0be28e 100644 (file)
  * HANDSHAKE DATA.
  */
 int
-_gnutls_record_buffer_put (content_type_t type,
-                           gnutls_session_t session, opaque * data,
-                           size_t length)
+_gnutls_record_buffer_put (gnutls_session_t session,
+  content_type_t type, uint64* seq, mbuffer_st* bufel)
 {
-  gnutls_buffer_st *buf;
 
-  if (length == 0)
-    return 0;
+  bufel->type = type;
+  memcpy(&bufel->record_sequence, seq, sizeof(*seq));
 
   switch (type)
     {
     case GNUTLS_APPLICATION_DATA:
-      buf = &session->internals.application_data_buffer;
+      _mbuffer_enqueue(&session->internals.application_data_buffer, bufel);
       _gnutls_buffers_log ("BUF[REC]: Inserted %d bytes of Data(%d)\n",
-                           (int) length, (int) type);
+                           (int) bufel->msg.size, (int) type);
       break;
 
     case GNUTLS_HANDSHAKE:
-      buf = &session->internals.handshake_data_buffer;
+      _mbuffer_enqueue(&session->internals.handshake_data_buffer, bufel);
       _gnutls_buffers_log ("BUF[HSK]: Inserted %d bytes of Data(%d)\n",
-                           (int) length, (int) type);
+                           (int) bufel->msg.size, (int) type);
       break;
 
     default:
-      gnutls_assert ();
-      return GNUTLS_E_INVALID_REQUEST;
-    }
-
-  if (_gnutls_buffer_append_data (buf, data, length) < 0)
-    {
-      gnutls_assert ();
-      return GNUTLS_E_MEMORY_ERROR;
+      return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST);
     }
 
   return 0;
@@ -115,10 +106,10 @@ _gnutls_record_buffer_get_size (content_type_t type, gnutls_session_t session)
   switch (type)
     {
     case GNUTLS_APPLICATION_DATA:
-      return session->internals.application_data_buffer.length;
+      return session->internals.application_data_buffer.byte_length;
 
     case GNUTLS_HANDSHAKE:
-      return session->internals.handshake_data_buffer.length;
+      return session->internals.handshake_data_buffer.byte_length;
 
     default:
       return GNUTLS_E_INVALID_REQUEST;
@@ -149,8 +140,12 @@ gnutls_record_check_pending (gnutls_session_t session)
 int
 _gnutls_record_buffer_get (content_type_t type,
                            gnutls_session_t session, opaque * data,
-                           size_t length)
+                           size_t length, opaque seq[8])
 {
+gnutls_datum_t msg;
+mbuffer_head_st* head;
+mbuffer_st* bufel;
+
   if (length == 0 || data == NULL)
     {
       gnutls_assert ();
@@ -160,17 +155,11 @@ _gnutls_record_buffer_get (content_type_t type,
   switch (type)
     {
     case GNUTLS_APPLICATION_DATA:
-      _gnutls_buffer_pop_data (&session->internals.application_data_buffer,
-                               data, &length);
-      _gnutls_buffers_log ("BUFFER[REC][AD]: Read %d bytes of Data(%d)\n",
-                           (int) length, (int) type);
+      head = &session->internals.application_data_buffer;
       break;
 
     case GNUTLS_HANDSHAKE:
-      _gnutls_buffer_pop_data (&session->internals.handshake_data_buffer,
-                               data, &length);
-      _gnutls_buffers_log ("BUF[REC][HD]: Read %d bytes of Data(%d)\n",
-                           (int) length, (int) type);
+      head = &session->internals.handshake_data_buffer;
       break;
 
     default:
@@ -178,7 +167,19 @@ _gnutls_record_buffer_get (content_type_t type,
       return GNUTLS_E_INVALID_REQUEST;
     }
 
+  bufel = _mbuffer_get_first(head, &msg);
+  if (bufel == NULL)
+    return gnutls_assert_val(GNUTLS_E_AGAIN);
+
+  if (msg.size <= length)
+    length = msg.size;
+
+  if (seq)
+    memcpy(seq, bufel->record_sequence.i, 8);
 
+  memcpy(data, msg.data, length);
+  _mbuffer_remove_bytes(head, length);
+  
   return length;
 }
 
@@ -205,23 +206,24 @@ _gnutls_dgram_read (gnutls_session_t session, mbuffer_st **bufel,
 {
   ssize_t i, ret;
   char *ptr;
+  size_t max_size = _gnutls_get_max_decrypted_data(session);
+  size_t recv_size = MAX_RECV_SIZE(session);
   gnutls_transport_ptr_t fd = session->internals.transport_recv_ptr;
 
-  if (!bufel)
-    {
-      gnutls_assert ();
-      return GNUTLS_E_INTERNAL_ERROR;
-    }
+  if (recv_size > max_size)
+    return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
 
-  ptr = gnutls_malloc(MAX_RECV_SIZE(session));
-  if (ptr == NULL)
+  *bufel = _mbuffer_alloc (0, _gnutls_get_max_decrypted_data(session));
+  if (*bufel == NULL)
     return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
 
+  ptr = (*bufel)->msg.data;
+
   session->internals.direction = 0;
 
   reset_errno (session);
 
-  i = pull_func (fd, ptr, MAX_RECV_SIZE(session));
+  i = pull_func (fd, ptr, recv_size);
 
   if (i < 0)
     {
@@ -232,49 +234,42 @@ _gnutls_dgram_read (gnutls_session_t session, mbuffer_st **bufel,
 
       if (err == EAGAIN)
         {
-         ret = GNUTLS_E_AGAIN;
-         goto cleanup;
+          ret = GNUTLS_E_AGAIN;
+          goto cleanup;
         }
       else if (err == EINTR)
         {
-         ret = GNUTLS_E_INTERRUPTED;
-         goto cleanup;
+          ret = GNUTLS_E_INTERRUPTED;
+          goto cleanup;
         }
       else
-       {
-         gnutls_assert ();
-         ret = GNUTLS_E_PULL_ERROR;
-         goto cleanup;
-       }
+        {
+          gnutls_assert ();
+          ret = GNUTLS_E_PULL_ERROR;
+          goto cleanup;
+        }
     }
   else
     {
       _gnutls_read_log ("READ: Got %d bytes from %p\n", (int) i, fd);
-      if (i == 0) {
-       /* If we get here, we likely have a stream socket.
-        * FIXME: this probably breaks DCCP. */
-       gnutls_assert ();
-       ret = GNUTLS_E_INTERNAL_ERROR;
-       goto cleanup;
-      }
-
-      *bufel = _mbuffer_alloc (0, i);
-      if (!*bufel)
-       {
-         gnutls_assert ();
-         ret = GNUTLS_E_MEMORY_ERROR;
-         goto cleanup;
-       }
-
-      _mbuffer_append_data (*bufel, ptr, i);
+      if (i == 0) 
+        {
+          /* If we get here, we likely have a stream socket.
+           * FIXME: this probably breaks DCCP. */
+          gnutls_assert ();
+          ret = GNUTLS_E_INTERNAL_ERROR;
+          goto cleanup;
+        }
+
+      _mbuffer_set_udata_size (*bufel, i);
     }
 
   _gnutls_read_log ("READ: read %d bytes from %p\n", (int) i, fd);
   
-  ret = i;
+  return i;
   
 cleanup:
-  gnutls_free(ptr);
+  _mbuffer_xfree(bufel);
   return ret;
 }
 
@@ -284,16 +279,11 @@ _gnutls_stream_read (gnutls_session_t session, mbuffer_st **bufel,
 {
   size_t left;
   ssize_t i = 0;
+  size_t max_size = _gnutls_get_max_decrypted_data(session);
   char *ptr;
   gnutls_transport_ptr_t fd = session->internals.transport_recv_ptr;
 
-  if (!bufel)
-    {
-      gnutls_assert ();
-      return GNUTLS_E_INTERNAL_ERROR;
-    }
-
-  *bufel = _mbuffer_alloc (0, size);
+  *bufel = _mbuffer_alloc (0, GMAX(max_size, size));
   if (!*bufel)
     {
       gnutls_assert ();
@@ -861,7 +851,7 @@ _gnutls_handshake_io_cache_int (gnutls_session_t session,
 
   if (IS_DTLS(session))
     {
-      bufel->sequence = session->internals.dtls.hsk_write_seq-1;
+      bufel->handshake_sequence = session->internals.dtls.hsk_write_seq-1;
     }
   
   send_buffer =
index 6e1b9012728dfdeb74a15da33f2ab580df07e266..ff762c31f1455e38bdd705459be345ee191d579f 100644 (file)
 
 #define MBUFFER_FLUSH 1
 
-int _gnutls_record_buffer_put (content_type_t type,
-                               gnutls_session_t session, opaque * data,
-                               size_t length);
+int
+_gnutls_record_buffer_put (gnutls_session_t session,
+  content_type_t type, uint64* seq, mbuffer_st* bufel);
+
 int _gnutls_record_buffer_get_size (content_type_t type,
                                     gnutls_session_t session);
 int _gnutls_record_buffer_get (content_type_t type,
                                gnutls_session_t session, opaque * data,
-                               size_t length);
+                               size_t length, opaque seq[8]);
 ssize_t _gnutls_io_read_buffered (gnutls_session_t, size_t n, content_type_t);
 int _gnutls_io_clear_peeked_data (gnutls_session_t session);
 
index a1cbcf1004b215f769baaadad0c54a7fe80d97e2..f5d692961371fdb4d14547aa07b8d6316802c3ba 100644 (file)
@@ -52,7 +52,7 @@ transmit_message (gnutls_session_t session,
     {
       _gnutls_dtls_log ("DTLS[%p]: Sending Packet[%u] fragment %s(%d) with "
                        "length: %u, offset: %u, fragment length: %u\n",
-                       session, bufel->sequence,
+                       session, bufel->handshake_sequence,
                        _gnutls_handshake2str (bufel->htype),
                        bufel->htype, data_size, offset, frag_len);
 
@@ -79,7 +79,7 @@ transmit_message (gnutls_session_t session,
   _gnutls_write_uint24 (data_size, &mtu_data[1]);
 
   /* Handshake sequence */
-  _gnutls_write_uint16 (bufel->sequence, &mtu_data[4]);
+  _gnutls_write_uint16 (bufel->handshake_sequence, &mtu_data[4]);
 
   /* Chop up and send handshake message into mtu-size pieces. */
   for (offset=0; offset <= data_size; offset += mtu)
@@ -100,7 +100,7 @@ transmit_message (gnutls_session_t session,
 
       _gnutls_dtls_log ("DTLS[%p]: Sending Packet[%u] fragment %s(%d) with "
                        "length: %u, offset: %u, fragment length: %u\n",
-                       session, bufel->sequence,
+                       session, bufel->handshake_sequence,
                        _gnutls_handshake2str (bufel->htype),
                        bufel->htype, data_size, offset, frag_len);
 
index 29691246645c90214ad3182f00616248875919ef..92696bf632d20e88529dfab21a2a4f0584c570ca 100644 (file)
@@ -71,6 +71,8 @@ typedef struct
 #define DEBUG
 */
 
+#define GMAX(x,y) ((x>y)?(x):(y))
+
 /* The size of a handshake message should not
  * be larger than this value.
  */
@@ -127,12 +129,6 @@ typedef struct
   } gnutls_ext_parse_type_t;
 
 
-/* The initial size of the receive
- * buffer size. This will grow if larger
- * packets are received.
- */
-#define INITIAL_RECV_BUFFER_SIZE 256
-
 /* the default for TCP */
 #define DEFAULT_LOWAT 0
 
@@ -263,16 +259,19 @@ typedef struct mbuffer_st
   size_t mark;
   unsigned int user_mark;       /* only used during fill in */
   size_t maximum_size;
-  
+
   /* record layer content type */
   content_type_t type;
 
   /* Record layer epoch of message */
   uint16_t epoch;
 
+  /* record layer sequence */
+  uint64 record_sequence;
+
   /* Handshake layer type and sequence of message */
   gnutls_handshake_description_t htype;
-  uint16_t sequence;
+  uint16_t handshake_sequence;
 } mbuffer_st;
 
 typedef struct mbuffer_head_st
@@ -587,7 +586,9 @@ typedef union
 
 typedef struct
 {
-  gnutls_buffer_st application_data_buffer;     /* holds data to be delivered to application layer */
+  mbuffer_head_st application_data_buffer;     /* holds data to be delivered to application layer */ 
+  mbuffer_head_st handshake_data_buffer;       /* this is a buffer that holds the current handshake message */
+
   gnutls_buffer_st handshake_hash_buffer;       /* used to keep the last received handshake 
                                                  * message */
   union
@@ -605,7 +606,6 @@ typedef struct
   } handshake_mac_handle;
   int handshake_mac_handle_init;        /* 1 when the previous union and type were initialized */
 
-  gnutls_buffer_st handshake_data_buffer;       /* this is a buffer that holds the current handshake message */
   int resumable:1;              /* TRUE or FALSE - if we can resume that session */
   handshake_state_t handshake_state;    /* holds
                                          * a number which indicates where
@@ -780,11 +780,6 @@ typedef struct
    */
   internal_params_st params;
 
-  /* This buffer is used by the record recv functions,
-   * as a temporary store buffer.
-   */
-  gnutls_datum_t recv_buffer;
-
   /* To avoid using global variables, and especially on Windows where
    * the application may use a different errno variable than GnuTLS,
    * it is possible to use gnutls_transport_set_errno to set a
index e58a3c3165fa50cce66df3b462359ce3cb6b278e..297c9b286fcadcf646ff480714d111b951b85590 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009 Free Software Foundation
+ * Copyright (C) 2009,2011 Free Software Foundation
  *
  * Author: Jonathan Bastien-Filiatrault
  *
@@ -98,6 +98,29 @@ _mbuffer_enqueue (mbuffer_head_st * buf, mbuffer_st * bufel)
   buf->tail = &bufel->next;
 }
 
+/* Get a reference to the first segment of the buffer and
+ * remove it from the list.
+ *
+ * Used to start iteration.
+ *
+ * Cost: O(1)
+ */
+mbuffer_st *
+_mbuffer_pop_first (mbuffer_head_st * buf)
+{
+  mbuffer_st *bufel = buf->head;
+
+  buf->head = bufel->next;
+
+  buf->byte_length -= (bufel->msg.size - bufel->mark);
+  buf->length -= 1;
+
+  if (!buf->head)
+    buf->tail = &buf->head;
+    
+  return bufel;
+}
+
 /* Get a reference to the first segment of the buffer and its data.
  *
  * Used to start iteration or to peek at the data.
@@ -109,15 +132,18 @@ _mbuffer_get_first (mbuffer_head_st * buf, gnutls_datum_t * msg)
 {
   mbuffer_st *bufel = buf->head;
 
-  if (bufel)
+  if (msg)
     {
-      msg->data = bufel->msg.data + bufel->mark;
-      msg->size = bufel->msg.size - bufel->mark;
-    }
-  else
-    {
-      msg->data = NULL;
-      msg->size = 0;
+      if (bufel)
+        {
+          msg->data = bufel->msg.data + bufel->mark;
+          msg->size = bufel->msg.size - bufel->mark;
+      }
+    else
+      {
+        msg->data = NULL;
+        msg->size = 0;
+      }
     }
   return bufel;
 }
index 571e46729e3b3ae8a47fdd2398083d4947ce09d2..8330acb7cbf0325fe60c8d43433947600d16ccbf 100644 (file)
@@ -37,6 +37,9 @@ mbuffer_st *_mbuffer_alloc (size_t payload_size, size_t maximum_size);
 mbuffer_st *_mbuffer_get_first (mbuffer_head_st * buf, gnutls_datum_t * msg);
 mbuffer_st *_mbuffer_get_next (mbuffer_st * cur, gnutls_datum_t * msg);
 
+mbuffer_st *
+_mbuffer_pop_first (mbuffer_head_st * buf);
+
 /* This is dangerous since it will replace bufel with a new
  * one.
  */
@@ -52,6 +55,7 @@ inline static void
 _mbuffer_set_udata (mbuffer_st * bufel, void *data, size_t data_size)
 {
   memcpy (bufel->msg.data + bufel->user_mark, data, data_size);
+  bufel->msg.size = data_size + bufel->user_mark;
 }
 
 inline static void *
index 409420867f9b138f062e680896d30a1572323ab2..b85cef3f42f52b8e4f6a3c037118f72f2946aab7 100644 (file)
@@ -535,14 +535,14 @@ check_recv_type (content_type_t recv_type)
  */
 static int
 check_buffers (gnutls_session_t session, content_type_t type,
-               opaque * data, int data_size)
+               opaque * data, int data_size, void* seq)
 {
   if ((type == GNUTLS_APPLICATION_DATA ||
        type == GNUTLS_HANDSHAKE)
       && _gnutls_record_buffer_get_size (type, session) > 0)
     {
       int ret, ret2;
-      ret = _gnutls_record_buffer_get (type, session, data, data_size);
+      ret = _gnutls_record_buffer_get (type, session, data, data_size, seq);
       if (ret < 0)
         {
           gnutls_assert ();
@@ -607,13 +607,15 @@ record_check_version (gnutls_session_t session,
 
 /* This function will check if the received record type is
  * the one we actually expect and adds it to the proper
- * buffer.
+ * buffer. The bufel will be deinitialized after calling
+ * this function, even if it fails.
  */
 static int
 record_add_to_buffers (gnutls_session_t session,
                    content_type_t recv_type, content_type_t type,
                    gnutls_handshake_description_t htype, 
-                   gnutls_datum_t* data)
+                   uint64* seq,
+                   mbuffer_st* bufel)
 {
 
   int ret;
@@ -622,7 +624,7 @@ record_add_to_buffers (gnutls_session_t session,
       && (type == GNUTLS_APPLICATION_DATA ||
           type == GNUTLS_HANDSHAKE))
     {
-      _gnutls_record_buffer_put (type, session, (void *) data->data, data->size);
+      _gnutls_record_buffer_put (session, type, seq, bufel);
     }
   else
     {
@@ -631,42 +633,45 @@ record_add_to_buffers (gnutls_session_t session,
       switch (recv_type)
         {
         case GNUTLS_ALERT:
-          if (data->size < 2)
-            return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
+          if (bufel->msg.size < 2)
+            {
+              ret = gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
+              goto cleanup;
+            }
 
           _gnutls_record_log
             ("REC[%p]: Alert[%d|%d] - %s - was received\n", session,
-             data->data[0], data->data[1], gnutls_alert_get_name ((int) data->data[1]));
+             bufel->msg.data[0], bufel->msg.data[1], gnutls_alert_get_name ((int) bufel->msg.data[1]));
 
-          session->internals.last_alert = data->data[1];
+          session->internals.last_alert = bufel->msg.data[1];
 
           /* if close notify is received and
            * the alert is not fatal
            */
-          if (data->data[1] == GNUTLS_A_CLOSE_NOTIFY && data->data[0] != GNUTLS_AL_FATAL)
+          if (bufel->msg.data[1] == GNUTLS_A_CLOSE_NOTIFY && bufel->msg.data[0] != GNUTLS_AL_FATAL)
             {
               /* If we have been expecting for an alert do 
                */
               session->internals.read_eof = 1;
-              return GNUTLS_E_INT_RET_0;        /* EOF */
+              ret = GNUTLS_E_INT_RET_0;        /* EOF */
+              goto cleanup;
             }
           else
             {
-
               /* if the alert is FATAL or WARNING
                * return the apropriate message
                */
 
               gnutls_assert ();
               ret = GNUTLS_E_WARNING_ALERT_RECEIVED;
-              if (data->data[0] == GNUTLS_AL_FATAL)
+              if (bufel->msg.data[0] == GNUTLS_AL_FATAL)
                 {
                   session_unresumable (session);
                   session_invalidate (session);
                   ret = GNUTLS_E_FATAL_ALERT_RECEIVED;
                 }
 
-              return ret;
+              goto cleanup;
             }
           break;
 
@@ -681,11 +686,11 @@ record_add_to_buffers (gnutls_session_t session,
         case GNUTLS_APPLICATION_DATA:
           /* even if data is unexpected put it into the buffer */
           if ((ret =
-               _gnutls_record_buffer_put (recv_type, session,
-                                          (void *) data->data, data->size)) < 0)
+               _gnutls_record_buffer_put (session, recv_type, seq,
+                                          bufel)) < 0)
             {
               gnutls_assert ();
-              return ret;
+              goto cleanup;
             }
 
           /* the got_application data is only returned
@@ -694,11 +699,15 @@ record_add_to_buffers (gnutls_session_t session,
            */
           if (type == GNUTLS_ALERT || (htype == GNUTLS_HANDSHAKE_CLIENT_HELLO
                                        && type == GNUTLS_HANDSHAKE))
-            return GNUTLS_E_GOT_APPLICATION_DATA;
+            {
+              ret = GNUTLS_E_GOT_APPLICATION_DATA;
+              goto cleanup;
+            }
           else
             {
               gnutls_assert ();
-              return GNUTLS_E_UNEXPECTED_PACKET;
+              ret = GNUTLS_E_UNEXPECTED_PACKET;
+              goto cleanup;
             }
 
           break;
@@ -710,12 +719,11 @@ record_add_to_buffers (gnutls_session_t session,
             {
               gnutls_assert ();
               ret =
-                _gnutls_record_buffer_put (recv_type, session, (void *) data->data,
-                                           data->size);
+                _gnutls_record_buffer_put (session, recv_type, seq, bufel);
               if (ret < 0)
                 {
                   gnutls_assert ();
-                  return ret;
+                  goto cleanup;
                 }
               return GNUTLS_E_REHANDSHAKE;
             }
@@ -726,7 +734,8 @@ record_add_to_buffers (gnutls_session_t session,
            */
 
           /* So we accept it */
-          return _gnutls_recv_hello_request (session, data->data, data->size);
+          ret = _gnutls_recv_hello_request (session, bufel->msg.data, bufel->msg.size);
+          goto cleanup;
 
           break;
         default:
@@ -736,56 +745,30 @@ record_add_to_buffers (gnutls_session_t session,
              session, recv_type, type);
 
           gnutls_assert ();
-          return GNUTLS_E_INTERNAL_ERROR;
+          ret = GNUTLS_E_INTERNAL_ERROR;
+          goto cleanup;
         }
     }
 
   return 0;
 
-}
+cleanup:
+  _mbuffer_xfree(&bufel);
+  return ret;
 
+}
 
-/* This function will return the internal (per session) temporary
- * recv buffer. If the buffer was not initialized before it will
- * also initialize it.
- */
-inline static int
-get_temp_recv_buffer (gnutls_session_t session, gnutls_datum_t ** tmp)
+int _gnutls_get_max_decrypted_data(gnutls_session_t session)
 {
-  size_t max_record_size;
+int ret;
 
   if (gnutls_compression_get (session) != GNUTLS_COMP_NULL ||
       session->internals.priorities.allow_large_records != 0)
-    max_record_size = MAX_RECORD_RECV_SIZE(session) + EXTRA_COMP_SIZE;
+    ret = MAX_RECORD_RECV_SIZE(session) + EXTRA_COMP_SIZE;
   else
-    max_record_size = MAX_RECORD_RECV_SIZE(session);
-
-  /* We allocate MAX_RECORD_RECV_SIZE length
-   * because we cannot predict the output data by the record
-   * packet length (due to compression).
-   */
-
-  if (max_record_size > session->internals.recv_buffer.size ||
-      session->internals.recv_buffer.data == NULL)
-    {
-
-      /* Initialize the internal buffer.
-       */
-      session->internals.recv_buffer.data =
-        gnutls_realloc (session->internals.recv_buffer.data, max_record_size);
-
-      if (session->internals.recv_buffer.data == NULL)
-        {
-          gnutls_assert ();
-          return GNUTLS_E_MEMORY_ERROR;
-        }
-
-      session->internals.recv_buffer.size = max_record_size;
-    }
-
-  *tmp = &session->internals.recv_buffer;
+    ret = MAX_RECORD_RECV_SIZE(session);
 
-  return 0;
+  return ret;
 }
 
 struct tls_record_st {
@@ -796,7 +779,6 @@ struct tls_record_st {
   uint16_t packet_size; /* header_size + length */
   content_type_t type;
   /* the data */
-  gnutls_datum_t data;
 };
 
 /* Checks the record headers and returns the length, version and
@@ -864,6 +846,7 @@ static int recv_headers( gnutls_session_t session, content_type_t type,
   gnutls_handshake_description_t htype, struct tls_record_st* record)
 {
 int ret;
+gnutls_datum_t raw; /* raw headers */
   /* Read the headers.
    */
   record->header_size = record->packet_size = RECORD_HEADER_SIZE(session);
@@ -882,9 +865,9 @@ int ret;
       return ret;
     }
 
-  _mbuffer_get_first (&session->internals.record_recv_buffer, &record->data);
+  _mbuffer_get_first (&session->internals.record_recv_buffer, &raw);
 
-  record_read_headers (session, record->data.data, type, htype, record);
+  record_read_headers (session, raw.data, type, htype, record);
 
   /* Check if the DTLS epoch is valid */
   if (IS_DTLS(session)) 
@@ -955,9 +938,9 @@ _gnutls_recv_int (gnutls_session_t session, content_type_t type,
 {
   uint64 *packet_sequence;
   uint8_t *ciphertext;
+  mbuffer_st* bufel = NULL;
   int ret, ret2;
   int empty_packet = 0;
-  gnutls_datum_t *decrypted;
   record_parameters_st *record_params;
   record_state_st *record_state;
   struct tls_record_st record;
@@ -993,7 +976,7 @@ begin:
   /* 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);
+  ret = check_buffers (session, type, data, data_size, seq);
   if (ret != 0)
     return ret;
 
@@ -1021,9 +1004,6 @@ begin:
   else
     packet_sequence = &record_state->sequence_number;
 
-  if (seq)
-    memcpy(seq, packet_sequence, 8);
-
   /* Read the packet data and insert it to record_recv_buffer.
    */
   ret =
@@ -1044,22 +1024,15 @@ begin:
       gnutls_assert ();
       return ret;
     }
-  _mbuffer_get_first (&session->internals.record_recv_buffer, &record.data);
-  ciphertext = &record.data.data[record.header_size];
-
-  ret = get_temp_recv_buffer (session, &decrypted);
-  if (ret < 0)
-    {
-      gnutls_assert ();
-      return ret;
-    }
+  bufel = _mbuffer_pop_first (&session->internals.record_recv_buffer);
+  ciphertext = &bufel->msg.data[record.header_size];
 
   /* decrypt the data we got. 
    */
   ret =
-    _gnutls_decrypt (session, ciphertext, record.length, decrypted->data, decrypted->size,
+    _gnutls_decrypt (session, ciphertext, record.length, bufel->msg.data, bufel->maximum_size,
                     record.type, record_params, packet_sequence);
-  decrypted->size = ret;
+  bufel->msg.size = ret;
 
   if (ret < 0)
     {
@@ -1067,9 +1040,8 @@ begin:
       goto sanity_check_error;
     }
 
-  /* remove the decrypted packet from buffers */
-  _mbuffer_remove_bytes (&session->internals.record_recv_buffer,
-                         record.packet_size);
+  /* bufel now holds the decrypted data
+   */
 
   /* check for duplicates. We check after the message
    * is processed and authenticated to avoid someone
@@ -1082,7 +1054,7 @@ begin:
         {
           _gnutls_audit_log("Discarded duplicate message[%u]\n",
             (unsigned int) _gnutls_uint64touint32 (packet_sequence));
-          goto discard2;
+          goto sanity_check_error;
         }
     }
 
@@ -1094,21 +1066,22 @@ begin:
       _gnutls_record_log
         ("REC[%p]: ChangeCipherSpec Packet was received\n", session);
 
-      if ((size_t) decrypted->size != data_size)
+      if ((size_t) bufel->msg.size != data_size)
         {                       /* data_size should be 1 */
           gnutls_assert ();
           ret = GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
           goto sanity_check_error;
         }
-      data[0] = decrypted->data[0];
+      data[0] = bufel->msg.data[0];
       
-      return 1;
+      ret = 1; 
+      goto cleanup;
     }
 
   _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, decrypted->size);
+     _gnutls_packet2str (record.type), record.type, bufel->msg.size);
 
   /* increase sequence number 
    */
@@ -1116,15 +1089,22 @@ begin:
     {
       session_invalidate (session);
       gnutls_assert ();
-      return GNUTLS_E_RECORD_LIMIT_REACHED;
+      ret = GNUTLS_E_RECORD_LIMIT_REACHED;
+      goto sanity_check_error;
     }
 
   ret =
-    record_add_to_buffers (session, record.type, type, htype, decrypted);
+    record_add_to_buffers (session, record.type, type, htype, 
+      packet_sequence, bufel);
+
+  /* bufel is now either deinitialized or buffered somewhere else */
+
   if (ret < 0)
     {
       if (ret == GNUTLS_E_INT_RET_0)
-        return 0;
+        {
+          return 0;
+        }
       gnutls_assert ();
       return ret;
     }
@@ -1136,7 +1116,7 @@ begin:
        type == GNUTLS_HANDSHAKE))
     {
 
-      ret = _gnutls_record_buffer_get (type, session, data, data_size);
+      ret = _gnutls_record_buffer_get (type, session, data, data_size, seq);
       if (ret < 0)
         {
           gnutls_assert ();
@@ -1178,9 +1158,8 @@ begin:
   return ret;
 
 discard:
-  _mbuffer_remove_bytes (&session->internals.record_recv_buffer,
-                         record.packet_size);
-discard2:
+  bufel = _mbuffer_pop_first(&session->internals.record_recv_buffer);
+  _mbuffer_xfree(&bufel);
   return GNUTLS_E_AGAIN;
 
 sanity_check_error:
@@ -1188,10 +1167,15 @@ sanity_check_error:
     {
       _gnutls_audit_log("Discarded message[%u] due to invalid decryption\n", 
             (unsigned int)_gnutls_uint64touint32 (packet_sequence));
-      goto discard2;
+      ret = GNUTLS_E_AGAIN;
+      goto cleanup;
     }
+
   session_unresumable (session);
   session_invalidate (session);
+
+cleanup:
+  _mbuffer_xfree(&bufel);
   return ret;
 
 recv_error:
index f41347170487c3328c16f7147a24d41932aaf614..d1099ea28e863a358c18153073d2a3339d04073f 100644 (file)
@@ -37,4 +37,6 @@ ssize_t _gnutls_recv_int (gnutls_session_t session, content_type_t type,
                           gnutls_handshake_description_t, opaque * data,
                           size_t sizeofdata, void* seq);
 
+int _gnutls_get_max_decrypted_data(gnutls_session_t session);
+
 #endif
index 18c9479d32b7648973e69720376f2b9abed025d2..bcb32717c84c9ef9ce73f278dd7826ae39209aa3 100644 (file)
@@ -268,8 +268,6 @@ _gnutls_handshake_internal_state_clear (gnutls_session_t session)
 {
   _gnutls_handshake_internal_state_init (session);
 
-  _gnutls_free_datum (&session->internals.recv_buffer);
-
   deinit_internal_params (session);
   
   _gnutls_epoch_gc(session);
@@ -318,10 +316,10 @@ gnutls_init (gnutls_session_t * session, gnutls_connection_end_t con_end)
   (*session)->security_parameters.cert_type = DEFAULT_CERT_TYPE;
 
   /* Initialize buffers */
-  _gnutls_buffer_init (&(*session)->internals.application_data_buffer);
-  _gnutls_buffer_init (&(*session)->internals.handshake_data_buffer);
   _gnutls_buffer_init (&(*session)->internals.handshake_hash_buffer);
 
+  _mbuffer_init (&(*session)->internals.application_data_buffer);
+  _mbuffer_init (&(*session)->internals.handshake_data_buffer);
   _mbuffer_init (&(*session)->internals.record_send_buffer);
   _mbuffer_init (&(*session)->internals.record_recv_buffer);
 
@@ -456,8 +454,8 @@ gnutls_deinit (gnutls_session_t session)
       }
 
   _gnutls_buffer_clear (&session->internals.handshake_hash_buffer);
-  _gnutls_buffer_clear (&session->internals.handshake_data_buffer);
-  _gnutls_buffer_clear (&session->internals.application_data_buffer);
+  _mbuffer_clear (&session->internals.handshake_data_buffer);
+  _mbuffer_clear (&session->internals.application_data_buffer);
   _mbuffer_clear (&session->internals.record_recv_buffer);
   _mbuffer_clear (&session->internals.record_send_buffer);