[PATCH 6/8] mbuffers: make _gnutls_io_read_buffered use mbuffers.

Jonathan Bastien-Filiatrault joe at x2a.org
Thu Sep 9 00:34:45 CEST 2010


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 <joe at x2a.org>

diff --git a/lib/gnutls_buffers.c b/lib/gnutls_buffers.c
index 34ef9df..c44765f 100644
--- a/lib/gnutls_buffers.c
+++ b/lib/gnutls_buffers.c
@@ -445,36 +445,26 @@ _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;
+  opaque buf[MAX_RECV_SIZE];
+  mbuffer_st *bufel;
+  size_t recvlowat, recvdata, readsize;
 
-  *iptr = session->internals.record_recv_buffer.data;
-
-  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 +495,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,39 +510,30 @@ _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, buf, readsize, session->internals.pull_func);
 
       /* return immediately if we got an interrupt or eagain
        * error.
@@ -569,21 +550,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);
 
-  buf_pos = session->internals.record_recv_buffer.length;
+      bufel = _mbuffer_alloc (0, ret);
+      if (!bufel)
+	{
+	  gnutls_assert ();
+	  return GNUTLS_E_MEMORY_ERROR;
+	}
+      _mbuffer_append_data (bufel, buf, ret);
+      _mbuffer_enqueue (&session->internals.record_recv_buffer, bufel);
+    }
 
   /* 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, buf, recvlowat, system_read_peek);
 
       if (ret2 < 0 && gnutls_error_is_fatal (ret2) == 0)
 	{
@@ -596,11 +583,17 @@ _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;
-
+	  bufel = _mbuffer_alloc (0, ret2);
+	  if (!bufel)
+	    {
+	      gnutls_assert ();
+	      return GNUTLS_E_INVALID_REQUEST;
+	    }
+	  _mbuffer_append_data (bufel, buf, ret2);
+	  _mbuffer_enqueue (&session->internals.record_recv_buffer, bufel);
 	}
     }
 
@@ -625,9 +618,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 4cdff88..d8cd028 100644
--- a/lib/gnutls_int.h
+++ b/lib/gnutls_int.h
@@ -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_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);
-- 
1.7.1





More information about the Gnutls-devel mailing list