From: Jonathan Bastien-Filiatrault Date: Wed, 8 Sep 2010 22:34:45 +0000 (-0400) Subject: mbuffers: make _gnutls_io_read_buffered use mbuffers. X-Git-Tag: gnutls_2_11_3~47 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=e545991e0bbd011706626b8fddf05dd3e2612bf8;p=thirdparty%2Fgnutls.git 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 Signed-off-by: Nikos Mavrogiannopoulos --- diff --git a/lib/gnutls_buffers.c b/lib/gnutls_buffers.c index 34ef9df5ac..c44765f52d 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 5352874b3d..bdd40f4a1a 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 4cdff88cdb..d8cd028389 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 4faa3ac6c6..27e5e56687 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 416c1ba0e6..b25d31b1ee 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);