[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