gnutls-commit
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[SCM] GNU gnutls branch, master, updated. gnutls_2_9_10-359-g3774e81


From: Nikos Mavrogiannopoulos
Subject: [SCM] GNU gnutls branch, master, updated. gnutls_2_9_10-359-g3774e81
Date: Thu, 09 Sep 2010 17:05:15 +0000

This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GNU gnutls".

http://git.savannah.gnu.org/cgit/gnutls.git/commit/?id=3774e819df961ce146526d9c9e688ff0f62e0987

The branch, master has been updated
       via  3774e819df961ce146526d9c9e688ff0f62e0987 (commit)
       via  0410e1330971d8230c915b92f8e4a2f96426506d (commit)
       via  e545991e0bbd011706626b8fddf05dd3e2612bf8 (commit)
       via  74f6fb83e2801986c83e461fa15ef8b3479af20d (commit)
       via  7f1ea52b58b42541b11b10166ed5c733732d2bea (commit)
       via  1611c5a47d2fb7a7d8bce376c758ef0173141768 (commit)
       via  363ad5cf711bd56d268e70c298bd7be4fbd8ef28 (commit)
       via  da915da4235c3e0745a956fd9630853d2722b935 (commit)
      from  3f4118800df875bf957636550ceb6b60cb6de869 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 3774e819df961ce146526d9c9e688ff0f62e0987
Author: Jonathan Bastien-Filiatrault <address@hidden>
Date:   Wed Sep 8 18:34:47 2010 -0400

    Fully mbufferize _gnutls_read and _gnutls_read_buffered.
    
    Signed-off-by: Jonathan Bastien-Filiatrault <address@hidden>
    Signed-off-by: Nikos Mavrogiannopoulos <address@hidden>

commit 0410e1330971d8230c915b92f8e4a2f96426506d
Author: Jonathan Bastien-Filiatrault <address@hidden>
Date:   Wed Sep 8 18:34:46 2010 -0400

    mbuffers: Add _mbuffer_xfree operation.
    
    Signed-off-by: Jonathan Bastien-Filiatrault <address@hidden>
    Signed-off-by: Nikos Mavrogiannopoulos <address@hidden>

commit e545991e0bbd011706626b8fddf05dd3e2612bf8
Author: Jonathan Bastien-Filiatrault <address@hidden>
Date:   Wed Sep 8 18:34:45 2010 -0400

    mbuffers: make _gnutls_io_read_buffered use mbuffers.
    
    This will be needed by the DTLS code to make sure reads are stored in
    segments that correspond to datagram boundaries.
    
    Signed-off-by: Jonathan Bastien-Filiatrault <address@hidden>
    Signed-off-by: Nikos Mavrogiannopoulos <address@hidden>

commit 74f6fb83e2801986c83e461fa15ef8b3479af20d
Author: Jonathan Bastien-Filiatrault <address@hidden>
Date:   Wed Sep 8 18:34:44 2010 -0400

    Parenthesize size calculations.
    
    This is standard practice and the DTLS code got bit by this.
    
    Signed-off-by: Jonathan Bastien-Filiatrault <address@hidden>
    Signed-off-by: Nikos Mavrogiannopoulos <address@hidden>

commit 7f1ea52b58b42541b11b10166ed5c733732d2bea
Author: Jonathan Bastien-Filiatrault <address@hidden>
Date:   Wed Sep 8 18:34:43 2010 -0400

    mbuffers: Add mbuffer_linearize.
    
    Signed-off-by: Jonathan Bastien-Filiatrault <address@hidden>
    Signed-off-by: Nikos Mavrogiannopoulos <address@hidden>

commit 1611c5a47d2fb7a7d8bce376c758ef0173141768
Author: Jonathan Bastien-Filiatrault <address@hidden>
Date:   Wed Sep 8 18:34:42 2010 -0400

    mbuffers: fix wrong size calculation.
    
    maximum_size is the maximum size of the payload, not including
    overhead.
    
    Signed-off-by: Jonathan Bastien-Filiatrault <address@hidden>
    Signed-off-by: Nikos Mavrogiannopoulos <address@hidden>

commit 363ad5cf711bd56d268e70c298bd7be4fbd8ef28
Author: Jonathan Bastien-Filiatrault <address@hidden>
Date:   Wed Sep 8 18:34:41 2010 -0400

    mbuffers: Make _mbuffer_remove_bytes return a meaningful error code.
    
    Signed-off-by: Jonathan Bastien-Filiatrault <address@hidden>
    Signed-off-by: Nikos Mavrogiannopoulos <address@hidden>

commit da915da4235c3e0745a956fd9630853d2722b935
Author: Jonathan Bastien-Filiatrault <address@hidden>
Date:   Wed Sep 8 18:34:40 2010 -0400

    mbuffers: Document the internal mbuffer API.
    
    After a year of not hacking GnuTLS, I needed to look at the code to
    know how mbuffers work. This will make it much easier for anybody not
    familiar with this code.
    
    Signed-off-by: Jonathan Bastien-Filiatrault <address@hidden>
    Signed-off-by: Nikos Mavrogiannopoulos <address@hidden>

-----------------------------------------------------------------------

Summary of changes:
 lib/gnutls_buffers.c  |  124 +++++++++++++++++++++-------------------------
 lib/gnutls_buffers.h  |    5 +-
 lib/gnutls_int.h      |    6 +-
 lib/gnutls_mbuffers.c |  131 ++++++++++++++++++++++++++++++++++++++++++++++++-
 lib/gnutls_mbuffers.h |   18 ++++++-
 lib/gnutls_record.c   |   30 ++++++++---
 lib/gnutls_state.c    |   16 +-----
 7 files changed, 231 insertions(+), 99 deletions(-)

diff --git a/lib/gnutls_buffers.c b/lib/gnutls_buffers.c
index 34ef9df..be84e90 100644
--- a/lib/gnutls_buffers.c
+++ b/lib/gnutls_buffers.c
@@ -269,23 +269,36 @@ inline static int get_errno(gnutls_session_t session)
  * Flags are only used if the default recv() function is being used.
  */
 static ssize_t
-_gnutls_read (gnutls_session_t session, void *iptr,
-             size_t sizeOfPtr, gnutls_pull_func pull_func)
+_gnutls_read (gnutls_session_t session, mbuffer_st **bufel,
+             size_t size, gnutls_pull_func pull_func)
 {
   size_t left;
   ssize_t i = 0;
-  char *ptr = iptr;
+  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);
+  if (!*bufel)
+    {
+      gnutls_assert ();
+      return GNUTLS_E_MEMORY_ERROR;
+    }
+  ptr = (*bufel)->msg.data;
+
   session->internals.direction = 0;
 
-  left = sizeOfPtr;
+  left = size;
   while (left > 0)
     {
-
       reset_errno(session);
 
-      i = pull_func (fd, &ptr[sizeOfPtr - left], left);
+      i = pull_func (fd, &ptr[size - left], left);
 
       if (i < 0)
        {
@@ -296,11 +309,11 @@ _gnutls_read (gnutls_session_t session, void *iptr,
 
          if (err == EAGAIN || err == EINTR)
            {
-             if (sizeOfPtr - left > 0)
+             if (size - left > 0)
                {
 
                  _gnutls_read_log ("READ: returning %d bytes from %p\n",
-                                   (int) (sizeOfPtr - left), fd);
+                                   (int) (size - left), fd);
 
                  goto finish;
                }
@@ -325,7 +338,7 @@ _gnutls_read (gnutls_session_t session, void *iptr,
        }
 
       left -= i;
-
+      (*bufel)->msg.size += i;
     }
 
 finish:
@@ -333,11 +346,11 @@ finish:
   if (_gnutls_log_level >= 7)
     {
       _gnutls_read_log ("READ: read %d bytes from %p\n",
-                       (int) (sizeOfPtr - left), fd);
+                       (int) (size - left), fd);
 
     }
 
-  return (sizeOfPtr - left);
+  return (size - left);
 }
 
 
@@ -408,32 +421,24 @@ _gnutls_debug_log("errno: %d\n", err);
 int
 _gnutls_io_clear_peeked_data (gnutls_session_t session)
 {
-  char *peekdata;
+  mbuffer_st *peekdata;
   int ret, sum;
 
   if (session->internals.have_peeked_data == 0 || RCVLOWAT == 0)
     return 0;
 
-  peekdata = gnutls_malloc (RCVLOWAT);
-  if (peekdata == NULL)
-    {
-      gnutls_assert ();
-      return GNUTLS_E_MEMORY_ERROR;
-    }
-
   /* this was already read by using MSG_PEEK - so it shouldn't fail */
   sum = 0;
   do
     {                          /* we need this to finish now */
-      ret = _gnutls_read (session, peekdata, RCVLOWAT - sum, 
session->internals.pull_func);
+      ret = _gnutls_read (session, &peekdata, RCVLOWAT - sum, 
session->internals.pull_func);
       if (ret > 0)
        sum += ret;
+      _mbuffer_xfree (&peekdata);
     }
   while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN
         || sum < RCVLOWAT);
 
-  gnutls_free (peekdata);
-
   if (ret < 0)
     {
       gnutls_assert ();
@@ -445,36 +450,25 @@ _gnutls_io_clear_peeked_data (gnutls_session_t session)
   return 0;
 }
 
-
-void
-_gnutls_io_clear_read_buffer (gnutls_session_t session)
-{
-  session->internals.record_recv_buffer.length = 0;
-}
-
 /* This function is like recv(with MSG_PEEK). But it does not return -1 on 
error.
  * It does return gnutls_errno instead.
  * This function reads data from the socket and keeps them in a buffer, of up 
to
  * MAX_RECV_SIZE. 
  *
  * This is not a general purpose function. It returns EXACTLY the data 
requested,
- * which are stored in a local (in the session) buffer. A pointer (iptr) to 
this buffer is returned.
+ * which are stored in a local (in the session) buffer.
  *
  */
 ssize_t
-_gnutls_io_read_buffered (gnutls_session_t session, opaque ** iptr,
-                         size_t sizeOfPtr, content_type_t recv_type)
+_gnutls_io_read_buffered (gnutls_session_t session, size_t total,
+                         content_type_t recv_type)
 {
   ssize_t ret = 0, ret2 = 0;
   size_t min;
-  int buf_pos;
-  opaque *buf;
-  int recvlowat;
-  int recvdata;
-
-  *iptr = session->internals.record_recv_buffer.data;
+  mbuffer_st *bufel=NULL;
+  size_t recvlowat, recvdata, readsize;
 
-  if (sizeOfPtr > MAX_RECV_SIZE || sizeOfPtr == 0)
+  if (total > MAX_RECV_SIZE || total == 0)
     {
       gnutls_assert ();                /* internal error */
       return GNUTLS_E_INVALID_REQUEST;
@@ -505,13 +499,13 @@ _gnutls_io_read_buffered (gnutls_session_t session, 
opaque ** iptr,
   /* calculate the actual size, ie. get the minimum of the
    * buffered data and the requested data.
    */
-  min = MIN (session->internals.record_recv_buffer.length, sizeOfPtr);
+  min = MIN (session->internals.record_recv_buffer.byte_length, total);
   if (min > 0)
     {
       /* if we have enough buffered data
        * then just return them.
        */
-      if (min == sizeOfPtr)
+      if (min == total)
        {
          return min;
        }
@@ -520,45 +514,37 @@ _gnutls_io_read_buffered (gnutls_session_t session, 
opaque ** iptr,
   /* min is over zero. recvdata is the data we must
    * receive in order to return the requested data.
    */
-  recvdata = sizeOfPtr - min;
+  recvdata = total - min;
+  readsize = recvdata - recvlowat;
 
   /* Check if the previously read data plus the new data to
    * receive are longer than the maximum receive buffer size.
    */
-  if ((session->internals.record_recv_buffer.length + recvdata) >
+  if ((session->internals.record_recv_buffer.byte_length + recvdata) >
       MAX_RECV_SIZE)
     {
       gnutls_assert ();                /* internal error */
       return GNUTLS_E_INVALID_REQUEST;
     }
 
-  /* Allocate the data required to store the new packet.
-   */
-  ret = _gnutls_buffer_resize (&session->internals.record_recv_buffer,
-                              recvdata +
-                              session->internals.record_recv_buffer.length);
-
   if (ret < 0)
     {
       gnutls_assert ();
       return ret;
     }
 
-  buf_pos = session->internals.record_recv_buffer.length;
-  buf = session->internals.record_recv_buffer.data;
-  *iptr = buf;
-
   /* READ DATA - but leave RCVLOWAT bytes in the kernel buffer.
    */
-  if (recvdata - recvlowat > 0)
+  if (readsize > 0)
     {
-      ret = _gnutls_read (session, &buf[buf_pos], recvdata - recvlowat, 
session->internals.pull_func);
+      ret = _gnutls_read (session, &bufel, readsize, 
session->internals.pull_func);
 
       /* return immediately if we got an interrupt or eagain
        * error.
        */
       if (ret < 0 && gnutls_error_is_fatal (ret) == 0)
        {
+         _mbuffer_xfree(&bufel);
          return ret;
        }
     }
@@ -569,24 +555,27 @@ _gnutls_io_read_buffered (gnutls_session_t session, 
opaque ** iptr,
     {
       _gnutls_read_log
        ("RB: Have %d bytes into buffer. Adding %d bytes.\n",
-        (int) session->internals.record_recv_buffer.length, (int) ret);
-      _gnutls_read_log ("RB: Requested %d bytes\n", (int) sizeOfPtr);
-      session->internals.record_recv_buffer.length += ret;
+        (int) session->internals.record_recv_buffer.byte_length, (int) ret);
+      _gnutls_read_log ("RB: Requested %d bytes\n", (int) total);
+
+      _mbuffer_enqueue (&session->internals.record_recv_buffer, bufel);
     }
+  else
+    _mbuffer_xfree(&bufel);
 
-  buf_pos = session->internals.record_recv_buffer.length;
 
   /* This is hack in order for select to work. Just leave recvlowat data,
    * into the kernel buffer (using a read with MSG_PEEK), thus making
    * select think, that the socket is ready for reading.
    * MSG_PEEK is only used with berkeley style sockets.
    */
-  if (ret == (recvdata - recvlowat) && recvlowat > 0)
+  if (ret == readsize && recvlowat > 0)
     {
-      ret2 = _gnutls_read (session, &buf[buf_pos], recvlowat, 
system_read_peek);
+      ret2 = _gnutls_read (session, &bufel, recvlowat, system_read_peek);
 
       if (ret2 < 0 && gnutls_error_is_fatal (ret2) == 0)
        {
+         _mbuffer_xfree(&bufel);
          return ret2;
        }
 
@@ -596,12 +585,13 @@ _gnutls_io_read_buffered (gnutls_session_t session, 
opaque ** iptr,
                            (int) ret2);
          _gnutls_read_log
            ("RB-PEEK: Have %d bytes into buffer. Adding %d bytes.\nRB: 
Requested %d bytes\n",
-            (int) session->internals.record_recv_buffer.length, (int) ret2,
-            (int) sizeOfPtr);
+            (int) session->internals.record_recv_buffer.byte_length, (int) 
ret2,
+            (int) total);
          session->internals.have_peeked_data = 1;
-         session->internals.record_recv_buffer.length += ret2;
-
+         _mbuffer_enqueue (&session->internals.record_recv_buffer, bufel);
        }
+      else
+       _mbuffer_xfree(&bufel);
     }
 
   if (ret < 0 || ret2 < 0)
@@ -625,9 +615,9 @@ _gnutls_io_read_buffered (gnutls_session_t session, opaque 
** iptr,
       return 0;
     }
 
-  ret = session->internals.record_recv_buffer.length;
+  ret = session->internals.record_recv_buffer.byte_length;
 
-  if ((ret > 0) && ((size_t) ret < sizeOfPtr))
+  if ((ret > 0) && ((size_t) ret < total))
     {
       /* Short Read */
       gnutls_assert ();
diff --git a/lib/gnutls_buffers.h b/lib/gnutls_buffers.h
index 5352874..bdd40f4 100644
--- a/lib/gnutls_buffers.h
+++ b/lib/gnutls_buffers.h
@@ -35,9 +35,8 @@ int _gnutls_record_buffer_get_size (content_type_t type,
 int _gnutls_record_buffer_get (content_type_t type,
                               gnutls_session_t session, opaque * data,
                               size_t length);
-ssize_t _gnutls_io_read_buffered (gnutls_session_t, opaque ** iptr,
-                                 size_t n, content_type_t);
-void _gnutls_io_clear_read_buffer (gnutls_session_t);
+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);
 
 ssize_t _gnutls_io_write_buffered (gnutls_session_t session,
diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h
index 2d37678..d8cd028 100644
--- a/lib/gnutls_int.h
+++ b/lib/gnutls_int.h
@@ -115,8 +115,8 @@ typedef struct
 #define MAX_RECORD_RECV_SIZE 
(size_t)session->security_parameters.max_record_recv_size
 #define MAX_PAD_SIZE 255
 #define EXTRA_COMP_SIZE 2048
-#define MAX_RECORD_OVERHEAD MAX_PAD_SIZE+EXTRA_COMP_SIZE
-#define MAX_RECV_SIZE 
MAX_RECORD_OVERHEAD+MAX_RECORD_RECV_SIZE+RECORD_HEADER_SIZE
+#define MAX_RECORD_OVERHEAD (MAX_PAD_SIZE+EXTRA_COMP_SIZE)
+#define MAX_RECV_SIZE 
(MAX_RECORD_OVERHEAD+MAX_RECORD_RECV_SIZE+RECORD_HEADER_SIZE)
 
 #define HANDSHAKE_HEADER_SIZE 4
 
@@ -544,7 +544,7 @@ typedef struct
   /* this buffer holds a record packet -mostly used for
    * non blocking IO.
    */
-  gnutls_buffer_st record_recv_buffer;
+  mbuffer_head_st record_recv_buffer;
   mbuffer_head_st record_send_buffer;  /* holds cached data
                                         * for the gnutls_io_write_buffered()
                                         * function.
diff --git a/lib/gnutls_mbuffers.c b/lib/gnutls_mbuffers.c
index de06324..c9af21d 100644
--- a/lib/gnutls_mbuffers.c
+++ b/lib/gnutls_mbuffers.c
@@ -27,6 +27,32 @@
 
 /* Here be mbuffers */
 
+/* A note on terminology:
+ *
+ * Variables named bufel designate a single buffer segment (mbuffer_st
+ * type). This type is textually referred to as a "segment" or a
+ * "buffer element".
+ *
+ * Variables named buf desigate a chain of buffer segments
+ * (mbuffer_head_st type).  This type is textually referred to as a
+ * "buffer head" or simply as "buffer".
+ *
+ * Design objectives:
+ *
+ * - Make existing code easier to understand.
+ * - Make common operations more efficient by avoiding unnecessary
+ *    copying.
+ * - Provide a common datatype with a well-known interface to move
+ *    data around and through the multiple protocol layers.
+ * - Enable a future implementation of DTLS, which needs the concept
+ *    of record boundaries.
+ */
+
+
+/* Initialize a buffer head.
+ *
+ * Cost: O(1)
+ */
 void
 _mbuffer_init (mbuffer_head_st *buf)
 {
@@ -37,6 +63,11 @@ _mbuffer_init (mbuffer_head_st *buf)
   buf->byte_length = 0;
 }
 
+/* Deallocate all buffer segments and reset the buffer head.
+ *
+ * Cost: O(n)
+ * n: Number of segments currently in the buffer.
+ */
 void
 _mbuffer_clear (mbuffer_head_st *buf)
 {
@@ -51,6 +82,10 @@ _mbuffer_clear (mbuffer_head_st *buf)
   _mbuffer_init (buf);
 }
 
+/* Append a segment to the end of this buffer.
+ *
+ * Cost: O(1)
+ */
 void
 _mbuffer_enqueue (mbuffer_head_st *buf, mbuffer_st *bufel)
 {
@@ -63,6 +98,12 @@ _mbuffer_enqueue (mbuffer_head_st *buf, mbuffer_st *bufel)
   buf->tail = &bufel->next;
 }
 
+/* Get a reference to the first segment of the buffer and its data.
+ *
+ * Used to start iteration or to peek at the data.
+ *
+ * Cost: O(1)
+ */
 mbuffer_st* _mbuffer_get_first (mbuffer_head_st *buf, gnutls_datum_t *msg)
 {
   mbuffer_st *bufel = buf->head;
@@ -80,6 +121,12 @@ mbuffer_st* _mbuffer_get_first (mbuffer_head_st *buf, 
gnutls_datum_t *msg)
   return bufel;
 }
 
+/* Get a reference to the next segment of the buffer and its data.
+ *
+ * Used to iterate over the buffer segments.
+ *
+ * Cost: O(1)
+ */
 mbuffer_st* _mbuffer_get_next (mbuffer_st * cur, gnutls_datum_t *msg)
 {
   mbuffer_st *bufel = cur->next;
@@ -97,6 +144,13 @@ mbuffer_st* _mbuffer_get_next (mbuffer_st * cur, 
gnutls_datum_t *msg)
   return bufel;
 }
 
+/* Remove the first segment from the buffer.
+ *
+ * Used to dequeue data from the buffer. Not yet exposed in the
+ * internal interface since it is not yet needed outside of this unit.
+ *
+ * Cost: O(1)
+ */
 static inline void
 remove_front (mbuffer_head_st *buf)
 {
@@ -116,6 +170,15 @@ remove_front (mbuffer_head_st *buf)
     buf->tail = &buf->head;
 }
 
+/* Remove a specified number of bytes from the start of the buffer.
+ *
+ * Useful for uses that treat the buffer as a simple array of bytes.
+ *
+ * Returns 0 on success or an error code otherwise.
+ *
+ * Cost: O(n)
+ * n: Number of segments needed to remove the specified amount of data.
+ */
 int
 _mbuffer_remove_bytes (mbuffer_head_st *buf, size_t bytes)
 {
@@ -123,7 +186,10 @@ _mbuffer_remove_bytes (mbuffer_head_st *buf, size_t bytes)
   mbuffer_st *bufel, *next;
 
   if (bytes > buf->byte_length)
-    return -1;
+    {
+      gnutls_assert ();
+      return GNUTLS_E_INVALID_REQUEST;
+    }
 
   for (bufel = buf->head; bufel != NULL && left > 0; bufel = next)
     {
@@ -145,6 +211,18 @@ _mbuffer_remove_bytes (mbuffer_head_st *buf, size_t bytes)
   return 0;
 }
 
+/* Allocate a buffer segment. The segment is not initially "owned" by
+ * any buffer.
+ *
+ * maximum_size: Amount of data that this segment can contain.
+ * size: Amount of useful data that is contained in this
+ *  buffer. Generally 0, but this is a shortcut when a fixed amount of
+ *  data will immediately be added to this segment.
+ *
+ * Returns the segment or NULL on error.
+ *
+ * Cost: O(1)
+ */
 mbuffer_st *
 _mbuffer_alloc (size_t payload_size, size_t maximum_size)
 {
@@ -168,10 +246,20 @@ _mbuffer_alloc (size_t payload_size, size_t maximum_size)
   return st;
 }
 
+/* Copy data into a segment. The segment must not be part of a buffer
+ * head when using this function.
+ *
+ * Bounds checking is performed by this function.
+ *
+ * Returns 0 on success or an error code otherwise.
+ *
+ * Cost: O(n)
+ * n: number of bytes to copy
+ */
 int
 _mbuffer_append_data (mbuffer_st *bufel, void* newdata, size_t newdata_size)
 {
-  if (sizeof(mbuffer_st)+bufel->msg.size+newdata_size < bufel->maximum_size)
+  if (bufel->msg.size+newdata_size <= bufel->maximum_size)
     {
       memcpy(&bufel->msg.data[bufel->msg.size], newdata, newdata_size);
       bufel->msg.size+=newdata_size;
@@ -184,3 +272,42 @@ _mbuffer_append_data (mbuffer_st *bufel, void* newdata, 
size_t newdata_size)
 
   return 0;
 }
+
+/* Takes a buffer in multiple chunks and puts all the data in a single
+ * contiguous segment.
+ *
+ * Returns 0 on success or an error code otherwise.
+ *
+ * Cost: O(n)
+ * n: number of segments initially in the buffer
+ */
+int
+_mbuffer_linearize (mbuffer_head_st *buf)
+{
+  mbuffer_st *bufel, *cur;
+  gnutls_datum_t msg;
+  size_t pos=0;
+
+  if (buf->length <= 1)
+    /* Nothing to do */
+    return 0;
+
+  bufel = _mbuffer_alloc (buf->byte_length, buf->byte_length);
+  if (!bufel) {
+    gnutls_assert ();
+    return GNUTLS_E_MEMORY_ERROR;
+  }
+
+  for (cur = _mbuffer_get_first(buf, &msg);
+       msg.data != NULL;
+       cur = _mbuffer_get_next(cur, &msg))
+    {
+      memcpy (&bufel->msg.data[pos], msg.data, cur->msg.size);
+      pos += cur->msg.size;
+    }
+
+  _mbuffer_clear (buf);
+  _mbuffer_enqueue (buf, bufel);
+
+  return 0;
+}
diff --git a/lib/gnutls_mbuffers.h b/lib/gnutls_mbuffers.h
index ed94824..beb1eab 100644
--- a/lib/gnutls_mbuffers.h
+++ b/lib/gnutls_mbuffers.h
@@ -25,7 +25,8 @@
 #ifndef GNUTLS_MBUFFERS_H
 # define GNUTLS_MBUFFERS_H
 
-#include "gnutls_int.h"
+#include <gnutls_int.h>
+#include <gnutls_errors.h>
 
 void _mbuffer_init (mbuffer_head_st *buf);
 void _mbuffer_clear (mbuffer_head_st *buf);
@@ -40,6 +41,7 @@ mbuffer_st* _mbuffer_get_next (mbuffer_st * cur, 
gnutls_datum_t *msg);
  * one.
  */
 int _mbuffer_append_data (mbuffer_st *bufel, void* newdata, size_t 
newdata_size);
+int _mbuffer_linearize (mbuffer_head_st *buf);
 
 
 /* For "user" use. One can have buffer data and header.
@@ -94,4 +96,18 @@ inline static mbuffer_st* _gnutls_handshake_alloc(size_t 
size, size_t maximum)
   return ret;
 }
 
+/* Free a segment, if the pointer is not NULL
+ *
+ * We take a ** to detect and fix double free bugs (the dangling
+ * pointer case). It also makes sure the pointer has a known value
+ * after freeing.
+ */
+inline static void _mbuffer_xfree(mbuffer_st **bufel)
+{
+  if(*bufel)
+    gnutls_free(*bufel);
+
+  *bufel = NULL;
+}
+
 #endif
diff --git a/lib/gnutls_record.c b/lib/gnutls_record.c
index 4faa3ac..27e5e56 100644
--- a/lib/gnutls_record.c
+++ b/lib/gnutls_record.c
@@ -848,17 +848,15 @@ _gnutls_recv_int (gnutls_session_t session, 
content_type_t type,
                  gnutls_handshake_description_t htype, opaque * data,
                  size_t sizeofdata)
 {
-  gnutls_datum_t tmp;
   int decrypted_length;
   opaque version[2];
-  uint8_t *headers;
   content_type_t recv_type;
   uint16_t length;
   uint8_t *ciphertext;
-  uint8_t *recv_data;
   int ret, ret2;
   uint16_t header_size;
   int empty_packet = 0;
+  gnutls_datum_t data_enc, tmp;
 
   if (type != GNUTLS_ALERT && (sizeofdata == 0 || data == NULL))
     {
@@ -899,7 +897,7 @@ begin:
   header_size = RECORD_HEADER_SIZE;
 
   if ((ret =
-       _gnutls_io_read_buffered (session, &headers, header_size,
+       _gnutls_io_read_buffered (session, header_size,
                                 -1)) != header_size)
     {
       if (ret < 0 && gnutls_error_is_fatal (ret) == 0)
@@ -916,8 +914,16 @@ begin:
       return GNUTLS_E_UNEXPECTED_PACKET_LENGTH;
     }
 
+  ret = _mbuffer_linearize (&session->internals.record_recv_buffer);
+  if (ret != 0) {
+    gnutls_assert ();
+    return ret;
+  }
+
+  _mbuffer_get_first (&session->internals.record_recv_buffer, &data_enc);
+
   if ((ret =
-       record_check_headers (session, headers, type, htype, &recv_type,
+       record_check_headers (session, data_enc.data, type, htype, &recv_type,
                             version, &length, &header_size)) < 0)
     {
       gnutls_assert ();
@@ -969,8 +975,7 @@ begin:
 /* check if we have that data into buffer. 
  */
   if ((ret =
-       _gnutls_io_read_buffered (session, &recv_data,
-                                header_size + length,
+       _gnutls_io_read_buffered (session, header_size + length,
                                 recv_type)) != header_size + length)
     {
       if (ret < 0 && gnutls_error_is_fatal (ret) == 0)
@@ -985,8 +990,14 @@ begin:
 /* ok now we are sure that we can read all the data - so
  * move on !
  */
-  _gnutls_io_clear_read_buffer (session);
-  ciphertext = &recv_data[header_size];
+
+  ret = _mbuffer_linearize (&session->internals.record_recv_buffer);
+  if (ret != 0) {
+    gnutls_assert ();
+    return ret;
+  }
+  _mbuffer_get_first (&session->internals.record_recv_buffer, &data_enc);
+  ciphertext = &data_enc.data[header_size];
 
   ret = get_temp_recv_buffer (session, &tmp);
   if (ret < 0)
@@ -1007,6 +1018,7 @@ begin:
       gnutls_assert ();
       return ret;
     }
+  _mbuffer_remove_bytes (&session->internals.record_recv_buffer, header_size + 
length);
   decrypted_length = ret;
 
 /* Check if this is a CHANGE_CIPHER_SPEC
diff --git a/lib/gnutls_state.c b/lib/gnutls_state.c
index 416c1ba..b25d31b 100644
--- a/lib/gnutls_state.c
+++ b/lib/gnutls_state.c
@@ -296,7 +296,7 @@ gnutls_init (gnutls_session_t * session, 
gnutls_connection_end_t con_end)
   _gnutls_buffer_init (&(*session)->internals.ia_data_buffer);
 
   _mbuffer_init (&(*session)->internals.record_send_buffer);
-  _gnutls_buffer_init (&(*session)->internals.record_recv_buffer);
+  _mbuffer_init (&(*session)->internals.record_recv_buffer);
 
   _mbuffer_init (&(*session)->internals.handshake_send_buffer);
   _gnutls_buffer_init (&(*session)->internals.handshake_recv_buffer);
@@ -304,7 +304,6 @@ gnutls_init (gnutls_session_t * session, 
gnutls_connection_end_t con_end)
   (*session)->key = gnutls_calloc (1, sizeof (struct gnutls_key_st));
   if ((*session)->key == NULL)
     {
-    cleanup_session:
       gnutls_free (*session);
       *session = NULL;
       return GNUTLS_E_MEMORY_ERROR;
@@ -319,17 +318,6 @@ gnutls_init (gnutls_session_t * session, 
gnutls_connection_end_t con_end)
   gnutls_handshake_set_max_packet_length ((*session),
                                          MAX_HANDSHAKE_PACKET_SIZE);
 
-  /* Allocate a minimum size for recv_data
-   * This is allocated in order to avoid small messages, making
-   * the receive procedure slow.
-   */
-  if (_gnutls_buffer_resize (&(*session)->internals.record_recv_buffer,
-                            INITIAL_RECV_BUFFER_SIZE))
-    {
-      gnutls_free ((*session)->key);
-      goto cleanup_session;
-    }
-
   /* set the socket pointers to -1;
    */
   (*session)->internals.transport_recv_ptr = (gnutls_transport_ptr_t) - 1;
@@ -402,7 +390,7 @@ 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);
-  _gnutls_buffer_clear (&session->internals.record_recv_buffer);
+  _mbuffer_clear (&session->internals.record_recv_buffer);
   _mbuffer_clear (&session->internals.record_send_buffer);
 
   gnutls_credentials_clear (session);


hooks/post-receive
-- 
GNU gnutls



reply via email to

[Prev in Thread] Current Thread [Next in Thread]