LCOV - code coverage report
Current view: top level - builds/gnutls/coverage/gnutls-git/lib - buffers.c (source / functions) Hit Total Coverage
Test: GnuTLS-3.6.14 Code Coverage Lines: 583 648 90.0 %
Date: 2020-10-30 04:50:48 Functions: 23 24 95.8 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (C) 2000-2012 Free Software Foundation, Inc.
       3             :  *
       4             :  * Author: Nikos Mavrogiannopoulos
       5             :  *
       6             :  * This file is part of GnuTLS.
       7             :  *
       8             :  * The GnuTLS is free software; you can redistribute it and/or
       9             :  * modify it under the terms of the GNU Lesser General Public License
      10             :  * as published by the Free Software Foundation; either version 2.1 of
      11             :  * the License, or (at your option) any later version.
      12             :  *
      13             :  * This library is distributed in the hope that it will be useful, but
      14             :  * WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      16             :  * Lesser General Public License for more details.
      17             :  *
      18             :  * You should have received a copy of the GNU Lesser General Public License
      19             :  * along with this program.  If not, see <https://www.gnu.org/licenses/>
      20             :  *
      21             :  */
      22             : 
      23             : /*
      24             :  * This file holds all the buffering code used in gnutls.
      25             :  * The buffering code works as:
      26             :  *
      27             :  * RECORD LAYER:
      28             :  *  1. uses a buffer to hold data (application/handshake),
      29             :  *    we got but they were not requested, yet.
      30             :  *  (see gnutls_record_buffer_put(), gnutls_record_buffer_get_size() etc.)
      31             :  *
      32             :  *  2. uses a buffer to hold data that were incomplete (ie the read/write
      33             :  *    was interrupted)
      34             :  *  (see _gnutls_io_read_buffered(), _gnutls_io_write_buffered() etc.)
      35             :  *
      36             :  * HANDSHAKE LAYER:
      37             :  *  1. Uses buffer to hold the last received handshake message.
      38             :  *  (see _gnutls_handshake_hash_buffer_put() etc.)
      39             :  *
      40             :  */
      41             : 
      42             : #include "gnutls_int.h"
      43             : #include "errors.h"
      44             : #include <num.h>
      45             : #include <record.h>
      46             : #include <buffers.h>
      47             : #include <mbuffers.h>
      48             : #include <state.h>
      49             : #include <dtls.h>
      50             : #include <system.h>
      51             : #include <constate.h>     /* gnutls_epoch_get */
      52             : #include <handshake.h>    /* remaining_time() */
      53             : #include <errno.h>
      54             : #include <system.h>
      55             : #include "debug.h"
      56             : 
      57             : #ifndef EAGAIN
      58             : #define EAGAIN EWOULDBLOCK
      59             : #endif
      60             : 
      61             : /* this is the maximum number of messages allowed to queue.
      62             :  */
      63             : #define MAX_QUEUE 32
      64             : 
      65             : /* Buffers received packets of type APPLICATION DATA,
      66             :  * HANDSHAKE DATA and HEARTBEAT.
      67             :  */
      68             : void
      69     3174840 : _gnutls_record_buffer_put(gnutls_session_t session,
      70             :                           content_type_t type, uint64_t seq,
      71             :                           mbuffer_st * bufel)
      72             : {
      73             : 
      74     3174840 :         bufel->type = type;
      75     3174840 :         bufel->record_sequence = seq;
      76             : 
      77     3174840 :         _mbuffer_enqueue(&session->internals.record_buffer, bufel);
      78     3174840 :         _gnutls_buffers_log("BUF[REC]: Inserted %d bytes of Data(%d)\n",
      79             :                             (int) bufel->msg.size, (int) type);
      80             : 
      81     3174840 :         return;
      82             : }
      83             : 
      84             : /**
      85             :  * gnutls_record_check_pending:
      86             :  * @session: is a #gnutls_session_t type.
      87             :  *
      88             :  * This function checks if there are unread data
      89             :  * in the gnutls buffers. If the return value is
      90             :  * non-zero the next call to gnutls_record_recv()
      91             :  * is guaranteed not to block.
      92             :  *
      93             :  * Returns: Returns the size of the data or zero.
      94             :  **/
      95      519307 : size_t gnutls_record_check_pending(gnutls_session_t session)
      96             : {
      97      519307 :         return _gnutls_record_buffer_get_size(session);
      98             : }
      99             : 
     100             : /**
     101             :  * gnutls_record_check_corked:
     102             :  * @session: is a #gnutls_session_t type.
     103             :  *
     104             :  * This function checks if there pending corked
     105             :  * data in the gnutls buffers --see gnutls_record_cork().
     106             :  *
     107             :  * Returns: Returns the size of the corked data or zero.
     108             :  *
     109             :  * Since: 3.2.8
     110             :  **/
     111           0 : size_t gnutls_record_check_corked(gnutls_session_t session)
     112             : {
     113           0 :         return session->internals.record_presend_buffer.length;
     114             : }
     115             : 
     116             : int
     117     2405840 : _gnutls_record_buffer_get(content_type_t type,
     118             :                           gnutls_session_t session, uint8_t * data,
     119             :                           size_t length, uint8_t seq[8])
     120             : {
     121     2405840 :         gnutls_datum_t msg;
     122     2405840 :         mbuffer_st *bufel;
     123             : 
     124     2405840 :         if (length == 0 || data == NULL) {
     125           0 :                 gnutls_assert();
     126           0 :                 return GNUTLS_E_INVALID_REQUEST;
     127             :         }
     128             : 
     129     2405840 :         bufel =
     130     2405840 :             _mbuffer_head_get_first(&session->internals.record_buffer,
     131             :                                     &msg);
     132     2405840 :         if (bufel == NULL)
     133           0 :                 return
     134           0 :                     gnutls_assert_val
     135             :                     (GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);
     136             : 
     137     2405840 :         if (type != bufel->type) {
     138          17 :                 if (IS_DTLS(session))
     139          12 :                         _gnutls_audit_log(session,
     140             :                                           "Discarded unexpected %s (%d) packet (expecting: %s (%d))\n",
     141             :                                           _gnutls_packet2str(bufel->type),
     142           6 :                                           (int) bufel->type,
     143             :                                           _gnutls_packet2str(type),
     144             :                                           (int) type);
     145             :                 else
     146          11 :                         _gnutls_debug_log("received unexpected packet: %s(%d)\n",
     147             :                                                 _gnutls_packet2str(bufel->type), (int)bufel->type);
     148             : 
     149          17 :                 _mbuffer_head_remove_bytes(&session->internals.
     150          17 :                                            record_buffer, msg.size);
     151          17 :                 return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET);
     152             :         }
     153             : 
     154     2405830 :         if (msg.size <= length)
     155     2405720 :                 length = msg.size;
     156             : 
     157     2405830 :         if (seq)
     158         165 :                 _gnutls_write_uint64(bufel->record_sequence, seq);
     159             : 
     160     2405830 :         memcpy(data, msg.data, length);
     161     2405830 :         _mbuffer_head_remove_bytes(&session->internals.record_buffer,
     162             :                                    length);
     163             : 
     164     2405830 :         return length;
     165             : }
     166             : 
     167             : int
     168          21 : _gnutls_record_buffer_get_packet(content_type_t type, gnutls_session_t session, gnutls_packet_t *packet)
     169             : {
     170          21 :         mbuffer_st *bufel;
     171             : 
     172          21 :         bufel =
     173          21 :             _mbuffer_head_pop_first(&session->internals.record_buffer);
     174          21 :         if (bufel == NULL)
     175           0 :                 return
     176           0 :                     gnutls_assert_val
     177             :                     (GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);
     178             : 
     179          21 :         if (type != bufel->type) {
     180           0 :                 if (IS_DTLS(session))
     181           0 :                         _gnutls_audit_log(session,
     182             :                                           "Discarded unexpected %s (%d) packet (expecting: %s)\n",
     183             :                                           _gnutls_packet2str(bufel->type),
     184           0 :                                           (int) bufel->type,
     185             :                                           _gnutls_packet2str(type));
     186           0 :                 _mbuffer_head_remove_bytes(&session->internals.
     187           0 :                                            record_buffer, bufel->msg.size);
     188           0 :                 return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET);
     189             :         }
     190             : 
     191          21 :         *packet = bufel;
     192             : 
     193          21 :         return bufel->msg.size - bufel->mark;
     194             : }
     195             : 
     196   105242000 : inline static void reset_errno(gnutls_session_t session)
     197             : {
     198   105242000 :         session->internals.errnum = 0;
     199             : }
     200             : 
     201    87564600 : inline static int get_errno(gnutls_session_t session)
     202             : {
     203    87564600 :         int ret;
     204             : 
     205    87564600 :         if (session->internals.errnum != 0)
     206             :                 ret = session->internals.errnum;
     207             :         else
     208     1448380 :                 ret =
     209     1448380 :                     session->internals.errno_func(session->internals.
     210             :                                                   transport_recv_ptr);
     211    87564600 :         return ret;
     212             : }
     213             : 
     214             : inline static
     215    87564500 : int errno_to_gerr(int err, unsigned dtls)
     216             : {
     217    87564500 :         switch (err) {
     218             :         case EAGAIN:
     219             :                 return GNUTLS_E_AGAIN;
     220           0 :         case EINTR:
     221           0 :                 return GNUTLS_E_INTERRUPTED;
     222           2 :         case EMSGSIZE:
     223           2 :                 if (dtls != 0)
     224             :                         return GNUTLS_E_LARGE_PACKET;
     225             :                 else
     226           0 :                         return GNUTLS_E_PUSH_ERROR;
     227           0 :         case ECONNRESET:
     228           0 :                 return GNUTLS_E_PREMATURE_TERMINATION;
     229         218 :         default:
     230         218 :                 gnutls_assert();
     231             :                 return GNUTLS_E_PUSH_ERROR;
     232             :         }
     233             : }
     234             : 
     235             : static ssize_t
     236     8068740 : _gnutls_dgram_read(gnutls_session_t session, mbuffer_st ** bufel,
     237             :                    gnutls_pull_func pull_func, unsigned int *ms)
     238             : {
     239     8068740 :         ssize_t i, ret;
     240     8068740 :         uint8_t *ptr;
     241     8068740 :         struct timespec t1, t2;
     242     8068740 :         size_t max_size, recv_size;
     243     8068740 :         gnutls_transport_ptr_t fd = session->internals.transport_recv_ptr;
     244     8068740 :         unsigned int diff;
     245             : 
     246     8068740 :         max_size = max_record_recv_size(session);
     247     8068740 :         recv_size = max_size;
     248             : 
     249     8068740 :         session->internals.direction = 0;
     250             : 
     251     8068740 :         if (ms && *ms > 0) {
     252        2747 :                 ret = _gnutls_io_check_recv(session, *ms);
     253        2747 :                 if (ret < 0)
     254           2 :                         return gnutls_assert_val(ret);
     255        2745 :                 gnutls_gettime(&t1);
     256             :         }
     257             : 
     258     8068740 :         *bufel = _mbuffer_alloc_align16(max_size, get_total_headers(session));
     259     8068740 :         if (*bufel == NULL)
     260           0 :                 return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
     261             : 
     262     8068740 :         ptr = (*bufel)->msg.data;
     263             : 
     264     8068740 :         reset_errno(session);
     265     8068740 :         i = pull_func(fd, ptr, recv_size);
     266             : 
     267     8068740 :         if (i < 0) {
     268     8062060 :                 int err = get_errno(session);
     269             : 
     270     8062060 :                 _gnutls_read_log("READ: %d returned from %p, errno=%d\n",
     271             :                                  (int) i, fd, err);
     272             : 
     273     8062060 :                 ret = errno_to_gerr(err, 1);
     274     8062060 :                 goto cleanup;
     275             :         } else {
     276        6678 :                 _gnutls_read_log("READ: Got %d bytes from %p\n", (int) i,
     277             :                                  fd);
     278        6678 :                 if (i == 0) {
     279             :                         /* If we get here, we likely have a stream socket.
     280             :                          * That assumption may not work on DCCP. */
     281           0 :                         gnutls_assert();
     282           0 :                         ret = 0;
     283           0 :                         goto cleanup;
     284             :                 }
     285             : 
     286        6678 :                 _mbuffer_set_udata_size(*bufel, i);
     287             :         }
     288             : 
     289        6678 :         if (ms && *ms > 0) {
     290        2745 :                 gnutls_gettime(&t2);
     291        2745 :                 diff = timespec_sub_ms(&t2, &t1);
     292        2745 :                 if (diff < *ms)
     293        2745 :                         *ms -= diff;
     294             :                 else {
     295           0 :                         ret = gnutls_assert_val(GNUTLS_E_TIMEDOUT);
     296           0 :                         goto cleanup;
     297             :                 }
     298             :         }
     299             : 
     300        6678 :         _gnutls_read_log("READ: read %d bytes from %p\n", (int) i, fd);
     301             : 
     302             :         return i;
     303             : 
     304     8062060 :       cleanup:
     305     8062060 :         _mbuffer_xfree(bufel);
     306     8062060 :         return ret;
     307             : }
     308             : 
     309             : static ssize_t
     310    18437500 : _gnutls_stream_read(gnutls_session_t session, mbuffer_st ** bufel,
     311             :                     size_t size, gnutls_pull_func pull_func,
     312             :                     unsigned int *ms)
     313             : {
     314    18437500 :         size_t left;
     315    18437500 :         ssize_t i = 0;
     316    18437500 :         size_t max_size = max_record_recv_size(session);
     317    18437500 :         uint8_t *ptr;
     318    18437500 :         gnutls_transport_ptr_t fd = session->internals.transport_recv_ptr;
     319    18437500 :         int ret;
     320    18437500 :         struct timespec t1, t2;
     321    18437500 :         unsigned int diff;
     322             : 
     323    18437500 :         session->internals.direction = 0;
     324             : 
     325    18437500 :         *bufel = _mbuffer_alloc_align16(MAX(max_size, size), get_total_headers(session));
     326    18437500 :         if (!*bufel) {
     327           0 :                 gnutls_assert();
     328           0 :                 return GNUTLS_E_MEMORY_ERROR;
     329             :         }
     330    18437500 :         ptr = (*bufel)->msg.data;
     331             : 
     332    18437500 :         left = size;
     333    24662000 :         while (left > 0) {
     334    18438000 :                 if (ms && *ms > 0) {
     335      922971 :                         ret = _gnutls_io_check_recv(session, *ms);
     336      922971 :                         if (ret < 0) {
     337           7 :                                 gnutls_assert();
     338           7 :                                 goto cleanup;
     339             :                         }
     340             : 
     341      922964 :                         gnutls_gettime(&t1);
     342             :                 }
     343             : 
     344    18438000 :                 reset_errno(session);
     345             : 
     346    18438000 :                 i = pull_func(fd, &ptr[size - left], left);
     347             : 
     348    18438000 :                 if (i < 0) {
     349    12211100 :                         int err = get_errno(session);
     350             : 
     351    12211100 :                         _gnutls_read_log
     352             :                             ("READ: %d returned from %p, errno=%d gerrno=%d\n",
     353             :                              (int) i, fd, errno,
     354             :                              session->internals.errnum);
     355             : 
     356    12211100 :                         if (err == EAGAIN || err == EINTR) {
     357    12211000 :                                 if (size - left > 0) {
     358             : 
     359           0 :                                         _gnutls_read_log
     360             :                                             ("READ: returning %d bytes from %p\n",
     361             :                                              (int) (size - left), fd);
     362             : 
     363           0 :                                         goto finish;
     364             :                                 }
     365             : 
     366    12211000 :                                 ret = errno_to_gerr(err, 0);
     367    12211000 :                                 goto cleanup;
     368             :                         } else {
     369         102 :                                 gnutls_assert();
     370         102 :                                 ret = GNUTLS_E_PULL_ERROR;
     371         102 :                                 goto cleanup;
     372             :                         }
     373             :                 } else {
     374             : 
     375     6226920 :                         _gnutls_read_log("READ: Got %d bytes from %p\n",
     376             :                                          (int) i, fd);
     377             : 
     378     6226920 :                         if (i == 0)
     379             :                                 break;  /* EOF */
     380             :                 }
     381             : 
     382     6224480 :                 left -= i;
     383     6224480 :                 (*bufel)->msg.size += i;
     384             : 
     385     6224480 :                 if (ms && *ms > 0 && *ms != GNUTLS_INDEFINITE_TIMEOUT) {
     386      922277 :                         gnutls_gettime(&t2);
     387      922277 :                         diff = timespec_sub_ms(&t2, &t1);
     388      922277 :                         if (diff < *ms)
     389      922277 :                                 *ms -= diff;
     390             :                         else {
     391           0 :                                 ret = gnutls_assert_val(GNUTLS_E_TIMEDOUT);
     392           0 :                                 goto cleanup;
     393             :                         }
     394             :                 }
     395             :         }
     396             : 
     397     6226400 :       finish:
     398             : 
     399     6226400 :         _gnutls_read_log("READ: read %d bytes from %p\n",
     400             :                          (int) (size - left), fd);
     401             : 
     402     6226400 :         if (size - left == 0)
     403        1955 :                 _mbuffer_xfree(bufel);
     404             : 
     405     6226400 :         return (size - left);
     406             : 
     407    12211100 :       cleanup:
     408    12211100 :         _mbuffer_xfree(bufel);
     409    12211100 :         return ret;
     410             : }
     411             : 
     412             : 
     413             : /* This function is like read. But it does not return -1 on error.
     414             :  * It does return gnutls_errno instead.
     415             :  *
     416             :  * Flags are only used if the default recv() function is being used.
     417             :  */
     418             : static ssize_t
     419    26506200 : _gnutls_read(gnutls_session_t session, mbuffer_st ** bufel,
     420             :              size_t size, gnutls_pull_func pull_func, unsigned int *ms)
     421             : {
     422    26506200 :         if (IS_DTLS(session))
     423             :                 /* Size is not passed, since a whole datagram will be read. */
     424     8068740 :                 return _gnutls_dgram_read(session, bufel, pull_func, ms);
     425             :         else
     426    18437500 :                 return _gnutls_stream_read(session, bufel, size, pull_func,
     427             :                                            ms);
     428             : }
     429             : 
     430             : /* @vec: if non-zero then the vector function will be used to
     431             :  *       push the data.
     432             :  */
     433             : static ssize_t
     434    67630700 : _gnutls_writev_emu(gnutls_session_t session, gnutls_transport_ptr_t fd,
     435             :                    const giovec_t * giovec, unsigned int giovec_cnt, unsigned vec)
     436             : {
     437    67630700 :         unsigned int j = 0;
     438    67630700 :         size_t total = 0;
     439    67630700 :         ssize_t ret = 0;
     440             : 
     441    67979100 :         for (j = 0; j < giovec_cnt; j++) {
     442    67639700 :                 if (vec) {
     443         118 :                         ret = session->internals.vec_push_func(fd, &giovec[j], 1);
     444             :                 } else {
     445    67639500 :                         size_t sent = 0;
     446    67639500 :                         ssize_t left = giovec[j].iov_len;
     447    67639500 :                         char *p = giovec[j].iov_base;
     448    67639500 :                         do {
     449    67639500 :                                 ret =
     450    67639500 :                                     session->internals.push_func(fd, p,
     451             :                                                                  left);
     452    67639500 :                                 if (ret > 0) {
     453      348320 :                                         sent += ret;
     454      348320 :                                         left -= ret;
     455      348320 :                                         p += ret;
     456             :                                 }
     457    67639500 :                         } while(ret > 0 && left > 0);
     458             : 
     459    67639500 :                         if (sent > 0)
     460      348320 :                                 ret = sent;
     461             :                 }
     462             : 
     463    67639700 :                 if (ret == -1) {
     464    67291200 :                         gnutls_assert();
     465             :                         break;
     466             :                 }
     467             : 
     468      348438 :                 total += ret;
     469             : 
     470      348438 :                 if ((size_t) ret != giovec[j].iov_len)
     471             :                         break;
     472             :         }
     473             : 
     474    67630700 :         if (total > 0)
     475      339468 :                 return total;
     476             : 
     477             :         return ret;
     478             : }
     479             : 
     480             : /* @total: The sum of the data in giovec
     481             :  */
     482             : static ssize_t
     483    69745100 : _gnutls_writev(gnutls_session_t session, const giovec_t * giovec,
     484             :                unsigned giovec_cnt, unsigned total)
     485             : {
     486    69745100 :         int i;
     487    69745100 :         bool is_dtls = IS_DTLS(session);
     488    69745100 :         unsigned no_writev = 0;
     489    69745100 :         gnutls_transport_ptr_t fd = session->internals.transport_send_ptr;
     490             : 
     491    69745100 :         reset_errno(session);
     492             : 
     493    69745100 :         if (session->internals.vec_push_func != NULL) {
     494     2114470 :                 if (is_dtls && giovec_cnt > 1) {
     495         216 :                         if (total > session->internals.dtls.mtu) {
     496          19 :                                 no_writev = 1;
     497             :                         }
     498             :                 }
     499             : 
     500          19 :                 if (no_writev == 0) {
     501     2114450 :                         i = session->internals.vec_push_func(fd, giovec, giovec_cnt);
     502             :                 } else {
     503          19 :                         i = _gnutls_writev_emu(session, fd, giovec, giovec_cnt, 1);
     504             :                 }
     505    67630600 :         } else if (session->internals.push_func != NULL) {
     506    67630600 :                 i = _gnutls_writev_emu(session, fd, giovec, giovec_cnt, 0);
     507             :         } else
     508           0 :                 return gnutls_assert_val(GNUTLS_E_PUSH_ERROR);
     509             : 
     510    69745100 :         if (i == -1) {
     511    67291400 :                 int err = get_errno(session);
     512    67291400 :                 _gnutls_debug_log("WRITE: %d returned from %p, errno: %d\n",
     513             :                                   i, fd, err);
     514             : 
     515    67291400 :                 return errno_to_gerr(err, is_dtls);
     516             :         }
     517     2453710 :         return i;
     518             : }
     519             : 
     520             : /*
     521             :  * @ms: a pointer to the number of milliseconds to wait for data. Use zero or NULL for indefinite.
     522             :  *
     523             :  * This function is like recv(with MSG_PEEK). But it does not return -1 on error.
     524             :  * It does return gnutls_errno instead.
     525             :  * This function reads data from the socket and keeps them in a buffer, of up to
     526             :  * max_record_recv_size.
     527             :  *
     528             :  * This is not a general purpose function. It returns EXACTLY the data requested,
     529             :  * which are stored in a local (in the session) buffer.
     530             :  *
     531             :  * If the @ms parameter is non zero then this function will return before
     532             :  * the given amount of milliseconds or return GNUTLS_E_TIMEDOUT.
     533             :  *
     534             :  */
     535             : ssize_t
     536    26652900 : _gnutls_io_read_buffered(gnutls_session_t session, size_t total,
     537             :                          content_type_t recv_type, unsigned int *ms)
     538             : {
     539    26652900 :         ssize_t ret;
     540    26652900 :         size_t min;
     541    26652900 :         mbuffer_st *bufel = NULL;
     542    26652900 :         size_t recvdata, readsize;
     543             : 
     544    47780700 :         if (total > max_record_recv_size(session) || total == 0) {
     545          10 :                 gnutls_assert();
     546          10 :                 return GNUTLS_E_RECORD_OVERFLOW;
     547             :         }
     548             : 
     549             :         /* calculate the actual size, ie. get the minimum of the
     550             :          * buffered data and the requested data.
     551             :          */
     552    26652900 :         min =
     553    26652900 :             MIN(session->internals.record_recv_buffer.byte_length, total);
     554    26652900 :         if (min > 0) {
     555             :                 /* if we have enough buffered data
     556             :                  * then just return them.
     557             :                  */
     558     3225450 :                 if (min == total) {
     559      146656 :                         return min;
     560             :                 }
     561             :         }
     562             : 
     563             :         /* min is over zero. recvdata is the data we must
     564             :          * receive in order to return the requested data.
     565             :          */
     566    26506200 :         recvdata = total - min;
     567    26506200 :         readsize = recvdata;
     568             : 
     569             :         /* Check if the previously read data plus the new data to
     570             :          * receive are longer than the maximum receive buffer size.
     571             :          */
     572    26506200 :         if ((session->internals.record_recv_buffer.byte_length +
     573    26506200 :              recvdata) > max_record_recv_size(session)) {
     574           0 :                 gnutls_assert();        /* internal error */
     575           0 :                 return GNUTLS_E_INVALID_REQUEST;
     576             :         }
     577             : 
     578             :         /* READ DATA
     579             :          */
     580    26506200 :         if (readsize > 0) {
     581    26506200 :                 ret =
     582    26506200 :                     _gnutls_read(session, &bufel, readsize,
     583             :                                  session->internals.pull_func, ms);
     584             : 
     585             :                 /* return immediately if we got an interrupt or eagain
     586             :                  * error.
     587             :                  */
     588    26506200 :                 if (ret < 0) {
     589    20279200 :                         return gnutls_assert_val(ret);
     590             :                 }
     591             : 
     592     6233080 :                 if (ret == 0)   /* EOF */
     593        1966 :                         return gnutls_assert_val(0);
     594             : 
     595             :                 /* copy fresh data to our buffer.
     596             :                  */
     597     6231120 :                 _gnutls_read_log
     598             :                     ("RB: Have %d bytes into buffer. Adding %d bytes.\n",
     599             :                      (int) session->internals.record_recv_buffer.
     600             :                      byte_length, (int) ret);
     601     6231120 :                 _gnutls_read_log("RB: Requested %d bytes\n", (int) total);
     602             : 
     603     6231120 :                 _mbuffer_enqueue(&session->internals.record_recv_buffer,
     604             :                                  bufel);
     605             : 
     606     6231120 :                 if (IS_DTLS(session))
     607        6678 :                         ret =
     608        6678 :                             MIN(total,
     609             :                                 session->internals.record_recv_buffer.
     610             :                                 byte_length);
     611             :                 else
     612     6224440 :                         ret =
     613     6224440 :                             session->internals.record_recv_buffer.
     614             :                             byte_length;
     615             : 
     616     6231120 :                 if ((ret > 0) && ((size_t) ret < total))  /* Short Read */
     617         495 :                         return gnutls_assert_val(GNUTLS_E_AGAIN);
     618             :                 else
     619             :                         return ret;
     620             :         } else
     621           0 :                 return gnutls_assert_val(0);
     622             : }
     623             : 
     624             : /* This function is like write. But it does not return -1 on error.
     625             :  * It does return gnutls_errno instead.
     626             :  *
     627             :  * This function takes full responsibility of freeing msg->data.
     628             :  *
     629             :  * In case of E_AGAIN and E_INTERRUPTED errors, you must call
     630             :  * gnutls_write_flush(), until it returns ok (0).
     631             :  *
     632             :  * We need to push exactly the data in msg->size, since we cannot send
     633             :  * less data. In TLS the peer must receive the whole packet in order
     634             :  * to decrypt and verify the integrity.
     635             :  *
     636             :  */
     637             : ssize_t
     638     2514730 : _gnutls_io_write_buffered(gnutls_session_t session,
     639             :                           mbuffer_st * bufel, unsigned int mflag)
     640             : {
     641     2514730 :         mbuffer_head_st *const send_buffer =
     642             :             &session->internals.record_send_buffer;
     643             : 
     644             :         /* to know where the procedure was interrupted.
     645             :          */
     646     2514730 :         session->internals.direction = 1;
     647             : 
     648     2514730 :         _mbuffer_enqueue(send_buffer, bufel);
     649             : 
     650     2514730 :         _gnutls_write_log
     651             :             ("WRITE: enqueued %d bytes for %p. Total %d bytes.\n",
     652             :              (int) bufel->msg.size, session->internals.transport_recv_ptr,
     653             :              (int) send_buffer->byte_length);
     654             : 
     655     2514730 :         if (mflag == MBUFFER_FLUSH)
     656     2415960 :                 return _gnutls_io_write_flush(session);
     657             :         else
     658       98774 :                 return bufel->msg.size;
     659             : }
     660             : 
     661             : typedef ssize_t(*send_func) (gnutls_session_t, const giovec_t *, int);
     662             : 
     663             : /* This function writes the data that are left in the
     664             :  * TLS write buffer (ie. because the previous write was
     665             :  * interrupted.
     666             :  */
     667    77302600 : ssize_t _gnutls_io_write_flush(gnutls_session_t session)
     668             : {
     669    77302600 :         gnutls_datum_t msg;
     670    77302600 :         mbuffer_head_st *send_buffer =
     671             :             &session->internals.record_send_buffer;
     672    77302600 :         int ret;
     673    77302600 :         ssize_t sent = 0, tosend = 0;
     674    77302600 :         giovec_t iovec[MAX_QUEUE];
     675    77302600 :         int i = 0;
     676    77302600 :         mbuffer_st *cur;
     677             : 
     678    77302600 :         session->internals.direction = 1;
     679    77302600 :         _gnutls_write_log("WRITE FLUSH: %d bytes in buffer.\n",
     680             :                           (int) send_buffer->byte_length);
     681             : 
     682    77302600 :         for (cur = _mbuffer_head_get_first(send_buffer, &msg);
     683   147109000 :              cur != NULL; cur = _mbuffer_head_get_next(cur, &msg)) {
     684    69806000 :                 iovec[i].iov_base = msg.data;
     685    69806000 :                 iovec[i++].iov_len = msg.size;
     686    69806000 :                 tosend += msg.size;
     687             : 
     688             :                 /* we buffer up to MAX_QUEUE messages */
     689    69806000 :                 if (i >= MAX_QUEUE) {
     690           0 :                         gnutls_assert();
     691           0 :                         return GNUTLS_E_INTERNAL_ERROR;
     692             :                 }
     693             :         }
     694             : 
     695    77302600 :         if (tosend == 0) {
     696     7557470 :                 gnutls_assert();
     697     7557470 :                 return 0;
     698             :         }
     699             : 
     700    69745100 :         ret = _gnutls_writev(session, iovec, i, tosend);
     701    69745100 :         if (ret >= 0) {
     702     2453710 :                 _mbuffer_head_remove_bytes(send_buffer, ret);
     703     2453710 :                 _gnutls_write_log
     704             :                     ("WRITE: wrote %d bytes, %d bytes left.\n", ret,
     705             :                      (int) send_buffer->byte_length);
     706             : 
     707     2453710 :                 sent += ret;
     708    67291400 :         } else if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN) {
     709    67291200 :                 _gnutls_write_log("WRITE interrupted: %d bytes left.\n",
     710             :                                   (int) send_buffer->byte_length);
     711    67291200 :                 return ret;
     712         220 :         } else if (ret == GNUTLS_E_LARGE_PACKET) {
     713           2 :                 _mbuffer_head_remove_bytes(send_buffer, tosend);
     714           2 :                 _gnutls_write_log
     715             :                     ("WRITE cannot send large packet (%u bytes).\n",
     716             :                      (unsigned int) tosend);
     717           2 :                 return ret;
     718             :         } else {
     719         218 :                 _gnutls_write_log("WRITE error: code %d, %d bytes left.\n",
     720             :                                   ret, (int) send_buffer->byte_length);
     721             : 
     722         218 :                 gnutls_assert();
     723         218 :                 return ret;
     724             :         }
     725             : 
     726     2453710 :         if (sent < tosend) {
     727          21 :                 return gnutls_assert_val(GNUTLS_E_AGAIN);
     728             :         }
     729             : 
     730             :         return sent;
     731             : }
     732             : 
     733             : /* Checks whether there are received data within
     734             :  * a timeframe.
     735             :  *
     736             :  * Returns 0 if data were received, GNUTLS_E_TIMEDOUT
     737             :  * on timeout and a negative error code on error.
     738             :  */
     739     8989690 : int _gnutls_io_check_recv(gnutls_session_t session, unsigned int ms)
     740             : {
     741     8989690 :         gnutls_transport_ptr_t fd = session->internals.transport_recv_ptr;
     742     8989690 :         int ret = 0, err;
     743             : 
     744     8989690 :         if (NO_TIMEOUT_FUNC_SET(session)) {
     745           0 :                 _gnutls_debug_log("The pull function has been replaced but not the pull timeout.\n");
     746           0 :                 return gnutls_assert_val(GNUTLS_E_PULL_ERROR);
     747             :         }
     748             : 
     749     8989690 :         reset_errno(session);
     750             : 
     751     8989690 :         ret = session->internals.pull_timeout_func(fd, ms);
     752     8989690 :         if (ret == -1) {
     753           0 :                 err = get_errno(session);
     754           0 :                 _gnutls_read_log
     755             :                     ("READ_TIMEOUT: %d returned from %p, errno=%d (timeout: %u)\n",
     756             :                      (int) ret, fd, err, ms);
     757           0 :                 return errno_to_gerr(err, IS_DTLS(session));
     758             :         }
     759             : 
     760     8989690 :         if (ret > 0)
     761             :                 return 0;
     762             :         else
     763     6979580 :                 return GNUTLS_E_TIMEDOUT;
     764             : }
     765             : 
     766             : /* HANDSHAKE buffers part
     767             :  */
     768             : 
     769             : /* This function writes the data that are left in the
     770             :  * Handshake write buffer (ie. because the previous write was
     771             :  * interrupted.
     772             :  *
     773             :  */
     774    74873700 : ssize_t _gnutls_handshake_io_write_flush(gnutls_session_t session)
     775             : {
     776    74873700 :         mbuffer_head_st *const send_buffer =
     777             :             &session->internals.handshake_send_buffer;
     778    74873700 :         gnutls_datum_t msg;
     779    74873700 :         int ret;
     780    74873700 :         uint16_t epoch;
     781    74873700 :         ssize_t total = 0;
     782    74873700 :         mbuffer_st *cur;
     783             : 
     784    74873700 :         _gnutls_write_log("HWRITE FLUSH: %d bytes in buffer.\n",
     785             :                           (int) send_buffer->byte_length);
     786             : 
     787    74873700 :         if (IS_DTLS(session))
     788     7546000 :                 return _dtls_transmit(session);
     789             : 
     790    67327700 :         for (cur = _mbuffer_head_get_first(send_buffer, &msg);
     791    67422600 :              cur != NULL; cur = _mbuffer_head_get_first(send_buffer, &msg))
     792             :         {
     793       94867 :                 epoch = cur->epoch;
     794             : 
     795      189734 :                 ret = _gnutls_send_int(session, cur->type,
     796             :                                        cur->htype,
     797       94867 :                                        epoch, msg.data, msg.size, 0);
     798             : 
     799       94867 :                 if (ret >= 0) {
     800       94865 :                         total += ret;
     801             : 
     802       94865 :                         ret = _mbuffer_head_remove_bytes(send_buffer, ret);
     803             :                         /* for each queued message we send, ensure that
     804             :                          * we drop the epoch refcount set in _gnutls_handshake_io_cache_int(). */
     805       94865 :                         if (ret == 1)
     806       94422 :                                 _gnutls_epoch_refcount_dec(session, epoch);
     807             : 
     808       94865 :                         _gnutls_write_log
     809             :                             ("HWRITE: wrote %d bytes, %d bytes left.\n",
     810             :                              ret, (int) send_buffer->byte_length);
     811             : 
     812             :                 } else {
     813           2 :                         _gnutls_write_log
     814             :                             ("HWRITE error: code %d, %d bytes left.\n",
     815             :                              ret, (int) send_buffer->byte_length);
     816             : 
     817           2 :                         gnutls_assert();
     818           2 :                         return ret;
     819             :                 }
     820             :         }
     821             : 
     822    67327700 :         return _gnutls_io_write_flush(session);
     823             : }
     824             : 
     825             : 
     826             : /* This is a send function for the gnutls handshake
     827             :  * protocol. Just makes sure that all data have been sent.
     828             :  *
     829             :  */
     830             : int
     831       97482 : _gnutls_handshake_io_cache_int(gnutls_session_t session,
     832             :                                gnutls_handshake_description_t htype,
     833             :                                mbuffer_st * bufel)
     834             : {
     835       97482 :         mbuffer_head_st *send_buffer;
     836             : 
     837       97482 :         if (IS_DTLS(session)) {
     838        2973 :                 bufel->handshake_sequence =
     839        2973 :                     session->internals.dtls.hsk_write_seq - 1;
     840             :         }
     841             : 
     842       97482 :         send_buffer = &session->internals.handshake_send_buffer;
     843             : 
     844             :         /* ensure that our epoch does not get garbage collected
     845             :          * before we send all queued messages with it */
     846      194964 :         bufel->epoch =
     847       97482 :             (uint16_t) _gnutls_epoch_refcount_inc(session,
     848             :                                                   EPOCH_WRITE_CURRENT);
     849       97482 :         bufel->htype = htype;
     850       97482 :         if (bufel->htype == GNUTLS_HANDSHAKE_CHANGE_CIPHER_SPEC)
     851       14679 :                 bufel->type = GNUTLS_CHANGE_CIPHER_SPEC;
     852             :         else
     853       82803 :                 bufel->type = GNUTLS_HANDSHAKE;
     854             : 
     855       97482 :         _mbuffer_enqueue(send_buffer, bufel);
     856             : 
     857       97482 :         _gnutls_write_log
     858             :             ("HWRITE: enqueued [%s] %d. Total %d bytes.\n",
     859             :              _gnutls_handshake2str(bufel->htype), (int) bufel->msg.size,
     860             :              (int) send_buffer->byte_length);
     861             : 
     862       97482 :         return 0;
     863             : }
     864             : 
     865          66 : static int handshake_compare(const void *_e1, const void *_e2)
     866             : {
     867          66 :         const handshake_buffer_st *e1 = _e1;
     868          66 :         const handshake_buffer_st *e2 = _e2;
     869             : 
     870          66 :         if (e1->sequence <= e2->sequence)
     871             :                 return 1;
     872             :         else
     873          63 :                 return -1;
     874             : }
     875             : 
     876             : #define SSL2_HEADERS 1
     877             : static int
     878       56991 : parse_handshake_header(gnutls_session_t session, mbuffer_st * bufel,
     879             :                        handshake_buffer_st * hsk)
     880             : {
     881       56991 :         uint8_t *dataptr = NULL;        /* for realloc */
     882      113982 :         size_t handshake_header_size =
     883       56991 :             HANDSHAKE_HEADER_SIZE(session), data_size, frag_size;
     884             : 
     885             :         /* Note: SSL2_HEADERS == 1 */
     886       56991 :         if (_mbuffer_get_udata_size(bufel) < handshake_header_size)
     887           0 :                 return
     888           0 :                     gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
     889             : 
     890       56991 :         dataptr = _mbuffer_get_udata_ptr(bufel);
     891             : 
     892             :         /* if reading a client hello of SSLv2 */
     893             : #ifdef ENABLE_SSL2
     894       56991 :         if (unlikely
     895             :             (!IS_DTLS(session)
     896             :              && bufel->htype == GNUTLS_HANDSHAKE_CLIENT_HELLO_V2)) {
     897         738 :                 handshake_header_size = SSL2_HEADERS;   /* we've already read one byte */
     898             : 
     899         738 :                 frag_size = _mbuffer_get_udata_size(bufel) - handshake_header_size;     /* we've read the first byte */
     900             : 
     901         738 :                 if (dataptr[0] != GNUTLS_HANDSHAKE_CLIENT_HELLO)
     902           3 :                         return
     903           3 :                             gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET);
     904             : 
     905         735 :                 hsk->rtype = hsk->htype = GNUTLS_HANDSHAKE_CLIENT_HELLO_V2;
     906             : 
     907         735 :                 hsk->sequence = 0;
     908         735 :                 hsk->start_offset = 0;
     909         735 :                 hsk->length = frag_size;
     910             :         } else
     911             : #endif
     912             :         {       /* TLS or DTLS handshake headers */
     913             : 
     914             : 
     915       56253 :                 hsk->rtype = hsk->htype = dataptr[0];
     916             : 
     917             :                 /* we do not use DECR_LEN because we know
     918             :                  * that the packet has enough data.
     919             :                  */
     920       56253 :                 hsk->length = _gnutls_read_uint24(&dataptr[1]);
     921             : 
     922       56253 :                 if (IS_DTLS(session)) {
     923        3094 :                         hsk->sequence = _gnutls_read_uint16(&dataptr[4]);
     924        3094 :                         hsk->start_offset =
     925        3094 :                             _gnutls_read_uint24(&dataptr[6]);
     926        3094 :                         frag_size =
     927        3094 :                             _gnutls_read_uint24(&dataptr[9]);
     928             :                 } else {
     929       53159 :                         hsk->sequence = 0;
     930       53159 :                         hsk->start_offset = 0;
     931       53159 :                         frag_size =
     932       53159 :                             MIN((_mbuffer_get_udata_size(bufel) -
     933             :                                  handshake_header_size), hsk->length);
     934             :                 }
     935             : 
     936             :                 /* TLS1.3: distinguish server hello versus hello retry request.
     937             :                  * The epitome of slick protocol design. */
     938       56253 :                 if (hsk->htype == GNUTLS_HANDSHAKE_SERVER_HELLO && hsk->start_offset == 0 && !IS_DTLS(session)) {
     939        2950 :                         if (_mbuffer_get_udata_size(bufel) > handshake_header_size+2+GNUTLS_RANDOM_SIZE &&
     940        2847 :                             memcmp(dataptr+handshake_header_size+2, HRR_RANDOM, GNUTLS_RANDOM_SIZE) == 0) {
     941          24 :                                 hsk->htype = GNUTLS_HANDSHAKE_HELLO_RETRY_REQUEST;
     942             :                         }
     943             :                 }
     944             :         }
     945       56988 :         data_size = _mbuffer_get_udata_size(bufel) - handshake_header_size;
     946             : 
     947       56988 :         if (frag_size > 0)
     948       55430 :                 hsk->end_offset = hsk->start_offset + frag_size - 1;
     949             :         else
     950        1558 :                 hsk->end_offset = 0;
     951             : 
     952       78569 :         _gnutls_handshake_log
     953             :             ("HSK[%p]: %s (%u) was received. Length %d[%d], frag offset %d, frag length: %d, sequence: %d\n",
     954             :              session, _gnutls_handshake2str(hsk->htype),
     955             :              (unsigned) hsk->htype, (int) hsk->length, (int) data_size,
     956             :              hsk->start_offset, (int) frag_size,
     957             :              (int) hsk->sequence);
     958             : 
     959       56988 :         hsk->header_size = handshake_header_size;
     960       56988 :         memcpy(hsk->header, _mbuffer_get_udata_ptr(bufel),
     961             :                handshake_header_size);
     962             : 
     963       56988 :         if (hsk->length > 0 && (frag_size > data_size ||
     964       55430 :                                 (frag_size > 0 &&
     965       55430 :                                  hsk->end_offset >= hsk->length))) {
     966           0 :                 return
     967           0 :                     gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
     968             :         }
     969       56988 :         else if (hsk->length == 0 && hsk->end_offset != 0
     970           0 :                  && hsk->start_offset != 0)
     971           0 :                 return
     972           0 :                     gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
     973             : 
     974             :         return handshake_header_size;
     975             : }
     976             : 
     977       58212 : static void _gnutls_handshake_buffer_move(handshake_buffer_st * dst,
     978             :                                           handshake_buffer_st * src)
     979             : {
     980       58212 :         memcpy(dst, src, sizeof(*dst));
     981       58212 :         memset(src, 0, sizeof(*src));
     982       58212 :         src->htype = -1;
     983       58212 : }
     984             : 
     985             : /* will merge the given handshake_buffer_st to the handshake_recv_buffer
     986             :  * list. The given hsk packet will be released in any case (success or failure).
     987             :  * Only used in DTLS.
     988             :  */
     989        3094 : static int merge_handshake_packet(gnutls_session_t session,
     990             :                                   handshake_buffer_st * hsk)
     991             : {
     992        3094 :         int exists = 0, i, pos = 0;
     993        3094 :         int ret;
     994             : 
     995        3150 :         for (i = 0; i < session->internals.handshake_recv_buffer_size; i++) {
     996         553 :                 if (session->internals.handshake_recv_buffer[i].htype ==
     997         553 :                     hsk->htype) {
     998             :                         exists = 1;
     999             :                         pos = i;
    1000             :                         break;
    1001             :                 }
    1002             :         }
    1003             : 
    1004             :         if (!exists)
    1005             :                 pos = session->internals.handshake_recv_buffer_size;
    1006             : 
    1007        3094 :         if (pos >= MAX_HANDSHAKE_MSGS)
    1008           0 :                 return
    1009           0 :                     gnutls_assert_val(GNUTLS_E_TOO_MANY_HANDSHAKE_PACKETS);
    1010             : 
    1011        3094 :         if (!exists) {
    1012        2597 :                 if (hsk->length > 0 && hsk->end_offset > 0
    1013        2315 :                     && hsk->end_offset - hsk->start_offset + 1 !=
    1014             :                     hsk->length) {
    1015         340 :                         ret =
    1016         340 :                             _gnutls_buffer_resize(&hsk->data, hsk->length);
    1017         340 :                         if (ret < 0)
    1018           0 :                                 return gnutls_assert_val(ret);
    1019             : 
    1020         340 :                         hsk->data.length = hsk->length;
    1021             : 
    1022         340 :                         memmove(&hsk->data.data[hsk->start_offset],
    1023         340 :                                 hsk->data.data,
    1024         340 :                                 hsk->end_offset - hsk->start_offset + 1);
    1025             :                 }
    1026             : 
    1027        2597 :                 session->internals.handshake_recv_buffer_size++;
    1028             : 
    1029             :                 /* rewrite headers to make them look as each packet came as a single fragment */
    1030        2597 :                 _gnutls_write_uint24(hsk->length, &hsk->header[1]);
    1031        2597 :                 _gnutls_write_uint24(0, &hsk->header[6]);
    1032        2597 :                 _gnutls_write_uint24(hsk->length, &hsk->header[9]);
    1033             : 
    1034        2597 :                 _gnutls_handshake_buffer_move(&session->internals.
    1035             :                                               handshake_recv_buffer[pos],
    1036             :                                               hsk);
    1037             : 
    1038             :         } else {
    1039         497 :                 if (hsk->start_offset <
    1040         497 :                     session->internals.handshake_recv_buffer[pos].
    1041             :                     start_offset
    1042           1 :                     && hsk->end_offset + 1 >=
    1043             :                     session->internals.handshake_recv_buffer[pos].
    1044             :                     start_offset) {
    1045           1 :                         memcpy(&session->internals.
    1046           1 :                                handshake_recv_buffer[pos].data.data[hsk->
    1047             :                                                                     start_offset],
    1048           1 :                                hsk->data.data, hsk->data.length);
    1049           1 :                         session->internals.handshake_recv_buffer[pos].
    1050           1 :                             start_offset = hsk->start_offset;
    1051           1 :                         session->internals.handshake_recv_buffer[pos].
    1052           1 :                             end_offset =
    1053           1 :                             MIN(hsk->end_offset,
    1054             :                                 session->internals.
    1055             :                                 handshake_recv_buffer[pos].end_offset);
    1056         496 :                 } else if (hsk->end_offset >
    1057         496 :                            session->internals.handshake_recv_buffer[pos].
    1058             :                            end_offset
    1059         468 :                            && hsk->start_offset <=
    1060             :                            session->internals.handshake_recv_buffer[pos].
    1061         468 :                            end_offset + 1) {
    1062         468 :                         memcpy(&session->internals.
    1063         468 :                                handshake_recv_buffer[pos].data.data[hsk->
    1064             :                                                                     start_offset],
    1065         468 :                                hsk->data.data, hsk->data.length);
    1066             : 
    1067         468 :                         session->internals.handshake_recv_buffer[pos].
    1068         468 :                             end_offset = hsk->end_offset;
    1069         468 :                         session->internals.handshake_recv_buffer[pos].
    1070         468 :                             start_offset =
    1071         468 :                             MIN(hsk->start_offset,
    1072             :                                 session->internals.
    1073             :                                 handshake_recv_buffer[pos].start_offset);
    1074             :                 }
    1075         497 :                 _gnutls_handshake_buffer_clear(hsk);
    1076             :         }
    1077             : 
    1078             :         return 0;
    1079             : }
    1080             : 
    1081             : /* returns non-zero on match and zero on mismatch
    1082             :  */
    1083       57114 : inline static int cmp_hsk_types(gnutls_handshake_description_t expected,
    1084             :                                 gnutls_handshake_description_t recvd)
    1085             : {
    1086       57114 :         if (expected == GNUTLS_HANDSHAKE_ANY)
    1087             :                 return 1;
    1088             : 
    1089             : #ifdef ENABLE_SSL2
    1090       56731 :         if (expected == GNUTLS_HANDSHAKE_CLIENT_HELLO
    1091       56731 :              && recvd == GNUTLS_HANDSHAKE_CLIENT_HELLO_V2)
    1092             :                 return 1;
    1093             : #endif
    1094       55996 :         if (expected != recvd)
    1095        3875 :                 return 0;
    1096             : 
    1097             :         return 1;
    1098             : }
    1099             : 
    1100             : #define LAST_ELEMENT (session->internals.handshake_recv_buffer_size-1)
    1101             : 
    1102             : /* returns the last stored handshake packet.
    1103             :  */
    1104    19892900 : static int get_last_packet(gnutls_session_t session,
    1105             :                            gnutls_handshake_description_t htype,
    1106             :                            handshake_buffer_st * hsk,
    1107             :                            unsigned int optional)
    1108             : {
    1109    19892900 :         handshake_buffer_st *recv_buf =
    1110             :             session->internals.handshake_recv_buffer;
    1111             : 
    1112    19892900 :         if (IS_DTLS(session)) {
    1113     6984810 :                 if (session->internals.handshake_recv_buffer_size == 0 ||
    1114        3720 :                     (session->internals.dtls.hsk_read_seq !=
    1115        3720 :                      recv_buf[LAST_ELEMENT].sequence))
    1116     6981230 :                         goto timeout;
    1117             : 
    1118        3582 :                 if (htype != recv_buf[LAST_ELEMENT].htype) {
    1119         449 :                         if (optional == 0)
    1120           0 :                                 _gnutls_audit_log(session,
    1121             :                                                   "Received unexpected handshake message '%s' (%d). Expected '%s' (%d)\n",
    1122             :                                                   _gnutls_handshake2str
    1123           0 :                                                   (recv_buf[0].htype),
    1124           0 :                                                   (int) recv_buf[0].htype,
    1125             :                                                   _gnutls_handshake2str
    1126             :                                                   (htype), (int) htype);
    1127             : 
    1128         449 :                         return
    1129         449 :                             gnutls_assert_val
    1130             :                             (GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET);
    1131             :                 }
    1132             : 
    1133        3133 :                 else if ((recv_buf[LAST_ELEMENT].start_offset == 0 &&
    1134        3131 :                           recv_buf[LAST_ELEMENT].end_offset ==
    1135        3131 :                           recv_buf[LAST_ELEMENT].length - 1)
    1136        1024 :                          || recv_buf[LAST_ELEMENT].length == 0) {
    1137        2376 :                         session->internals.dtls.hsk_read_seq++;
    1138        2376 :                         _gnutls_handshake_buffer_move(hsk,
    1139             :                                                       &recv_buf
    1140             :                                                       [LAST_ELEMENT]);
    1141        2376 :                         session->internals.handshake_recv_buffer_size--;
    1142        2376 :                         return 0;
    1143             :                 } else {
    1144             :                         /* if we don't have a complete handshake message, but we
    1145             :                          * have queued data waiting, try again to reconstruct the
    1146             :                          * handshake packet, using the queued */
    1147         757 :                         if (recv_buf[LAST_ELEMENT].end_offset != recv_buf[LAST_ELEMENT].length - 1 &&
    1148         755 :                             record_check_unprocessed(session) > 0)
    1149         186 :                                 return gnutls_assert_val(GNUTLS_E_INT_CHECK_AGAIN);
    1150             :                         else
    1151         571 :                                 goto timeout;
    1152             :                 }
    1153             :         } else {                /* TLS */
    1154             : 
    1155    12908100 :                 if (session->internals.handshake_recv_buffer_size > 0
    1156      769777 :                     && recv_buf[0].length == recv_buf[0].data.length) {
    1157       57114 :                         if (cmp_hsk_types(htype, recv_buf[0].htype) == 0) {
    1158        3875 :                                 return
    1159        3875 :                                     gnutls_assert_val
    1160             :                                     (GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET);
    1161             :                         }
    1162             : 
    1163       53239 :                         _gnutls_handshake_buffer_move(hsk, &recv_buf[0]);
    1164       53239 :                         session->internals.handshake_recv_buffer_size--;
    1165       53239 :                         return 0;
    1166             :                 } else
    1167    12851000 :                         return
    1168    12851000 :                             gnutls_assert_val
    1169             :                             (GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);
    1170             :         }
    1171             : 
    1172     6981800 :       timeout:
    1173     6983920 :         RETURN_DTLS_EAGAIN_OR_TIMEOUT(session, 0);
    1174             : }
    1175             : 
    1176             : /* This is a receive function for the gnutls handshake
    1177             :  * protocol. Makes sure that we have received all data.
    1178             :  *
    1179             :  * htype is the next handshake packet expected.
    1180             :  */
    1181    20599800 : int _gnutls_parse_record_buffered_msgs(gnutls_session_t session)
    1182             : {
    1183    20599800 :         gnutls_datum_t msg;
    1184    20599800 :         mbuffer_st *bufel = NULL, *prev = NULL;
    1185    20599800 :         int ret;
    1186    20599800 :         size_t data_size;
    1187    20599800 :         handshake_buffer_st *recv_buf =
    1188             :             session->internals.handshake_recv_buffer;
    1189             : 
    1190    20599800 :         bufel =
    1191    20599800 :             _mbuffer_head_get_first(&session->internals.record_buffer,
    1192             :                                     &msg);
    1193    20599800 :         if (bufel == NULL)
    1194             :                 return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
    1195             : 
    1196      768496 :         if (!IS_DTLS(session)) {
    1197      765373 :                 ssize_t append, header_size;
    1198             : 
    1199      765373 :                 do {
    1200      765373 :                         if (bufel->type != GNUTLS_HANDSHAKE)
    1201           7 :                                 return
    1202           7 :                                     gnutls_assert_val
    1203             :                                     (GNUTLS_E_UNEXPECTED_PACKET);
    1204             : 
    1205      819307 :                         if (unlikely
    1206             :                             (session->internals.handshake_recv_buffer_size == 0 &&
    1207             :                              msg.size < HANDSHAKE_HEADER_SIZE(session) &&
    1208             :                              session->internals.handshake_header_recv_buffer.byte_length <
    1209             :                              HANDSHAKE_HEADER_SIZE(session) - msg.size)) {
    1210          44 :                                 bufel = _mbuffer_head_pop_first(&session->internals.record_buffer);
    1211          44 :                                 _mbuffer_enqueue(&session->internals.handshake_header_recv_buffer,
    1212             :                                                  bufel);
    1213          44 :                                 break;
    1214      765322 :                         } else if (session->internals.handshake_recv_buffer_size >
    1215      711425 :                                    0 && recv_buf[0].length > recv_buf[0].data.length) {
    1216             :                                 /* this is the rest of a previous message */
    1217      711425 :                                 append = MIN(msg.size,
    1218             :                                              recv_buf[0].length -
    1219             :                                              recv_buf[0].data.length);
    1220             : 
    1221      711425 :                                 ret =
    1222     1422850 :                                     _gnutls_buffer_append_data(&recv_buf
    1223             :                                                                [0].data,
    1224      711425 :                                                                msg.data,
    1225             :                                                                append);
    1226      711425 :                                 if (ret < 0)
    1227           0 :                                         return gnutls_assert_val(ret);
    1228             : 
    1229      711425 :                                 _mbuffer_head_remove_bytes(&session->
    1230             :                                                            internals.
    1231             :                                                            record_buffer,
    1232             :                                                            append);
    1233             :                         } else {        /* received new message */
    1234       53897 :                                 if (unlikely
    1235             :                                     (session->internals.
    1236             :                                      handshake_header_recv_buffer.length > 0)) {
    1237           8 :                                         bufel = _mbuffer_head_pop_first(&session->internals.
    1238             :                                                                         record_buffer);
    1239           8 :                                         _mbuffer_enqueue(&session->internals.
    1240             :                                                          handshake_header_recv_buffer,
    1241             :                                                          bufel);
    1242           8 :                                         ret = _mbuffer_linearize_align16(&session->internals.
    1243             :                                                                          handshake_header_recv_buffer,
    1244             :                                                                          get_total_headers(session));
    1245           8 :                                         if (ret < 0)
    1246           0 :                                                 return gnutls_assert_val(ret);
    1247           8 :                                         bufel = _mbuffer_head_pop_first(&session->internals.
    1248             :                                                                         handshake_header_recv_buffer);
    1249           8 :                                         _mbuffer_head_push_first(&session->internals.
    1250             :                                                                  record_buffer,
    1251             :                                                                  bufel);
    1252             :                                 }
    1253             : 
    1254       53897 :                                 ret =
    1255       53897 :                                     parse_handshake_header(session, bufel,
    1256             :                                                            &recv_buf[0]);
    1257       53897 :                                 if (ret < 0)
    1258           3 :                                         return gnutls_assert_val(ret);
    1259             : 
    1260       53894 :                                 header_size = ret;
    1261       53894 :                                 session->internals.
    1262       53894 :                                     handshake_recv_buffer_size = 1;
    1263             : 
    1264       53894 :                                 _mbuffer_set_uhead_size(bufel,
    1265             :                                                         header_size);
    1266             : 
    1267      107788 :                                 data_size =
    1268       53894 :                                     MIN(recv_buf[0].length,
    1269             :                                         _mbuffer_get_udata_size(bufel));
    1270       53894 :                                 ret =
    1271      107788 :                                     _gnutls_buffer_append_data(&recv_buf
    1272             :                                                                [0].data,
    1273       53894 :                                                                _mbuffer_get_udata_ptr
    1274             :                                                                (bufel),
    1275             :                                                                data_size);
    1276       53894 :                                 if (ret < 0)
    1277           0 :                                         return gnutls_assert_val(ret);
    1278       53894 :                                 _mbuffer_set_uhead_size(bufel, 0);
    1279       53894 :                                 _mbuffer_head_remove_bytes(&session->
    1280             :                                                            internals.
    1281             :                                                            record_buffer,
    1282             :                                                            data_size +
    1283             :                                                            header_size);
    1284             :                         }
    1285             : 
    1286             :                         /* if packet is complete then return it
    1287             :                          */
    1288      765319 :                         if (recv_buf[0].length == recv_buf[0].data.length) {
    1289             :                                 return 0;
    1290             :                         }
    1291      711992 :                         bufel =
    1292      711992 :                             _mbuffer_head_get_first(&session->internals.
    1293             :                                                     record_buffer, &msg);
    1294             :                 }
    1295      711992 :                 while (bufel != NULL);
    1296             : 
    1297             :                 /* if we are here it means that the received packets were not
    1298             :                  * enough to complete the handshake packet.
    1299             :                  */
    1300      712529 :                 return gnutls_assert_val(GNUTLS_E_AGAIN);
    1301             :         } else {                /* DTLS */
    1302             : 
    1303        3161 :                 handshake_buffer_st tmp;
    1304             : 
    1305        3161 :                 do {
    1306             :                         /* we now
    1307             :                          * 0. parse headers
    1308             :                          * 1. insert to handshake_recv_buffer
    1309             :                          * 2. sort handshake_recv_buffer on sequence numbers
    1310             :                          * 3. return first packet if completed or GNUTLS_E_AGAIN.
    1311             :                          */
    1312        3161 :                         do {
    1313        3161 :                                 if (bufel->type != GNUTLS_HANDSHAKE) {
    1314          67 :                                         gnutls_assert();
    1315          67 :                                         goto next;      /* ignore packet */
    1316             :                                 }
    1317             : 
    1318        3094 :                                 _gnutls_handshake_buffer_init(&tmp);
    1319             : 
    1320        3094 :                                 ret =
    1321        3094 :                                     parse_handshake_header(session, bufel,
    1322             :                                                            &tmp);
    1323        3094 :                                 if (ret < 0) {
    1324           0 :                                         gnutls_assert();
    1325           0 :                                         _gnutls_audit_log(session,
    1326             :                                                           "Invalid handshake packet headers. Discarding.\n");
    1327           0 :                                         break;
    1328             :                                 }
    1329             : 
    1330        3094 :                                 _mbuffer_consume(&session->internals.
    1331             :                                                  record_buffer, bufel,
    1332             :                                                  ret);
    1333             : 
    1334        3094 :                                 data_size =
    1335        3094 :                                     MIN(tmp.length,
    1336             :                                         tmp.end_offset - tmp.start_offset +
    1337             :                                         1);
    1338             : 
    1339        3094 :                                 ret =
    1340        6188 :                                     _gnutls_buffer_append_data(&tmp.data,
    1341        3094 :                                                                _mbuffer_get_udata_ptr
    1342             :                                                                (bufel),
    1343             :                                                                data_size);
    1344        3094 :                                 if (ret < 0)
    1345           0 :                                         return gnutls_assert_val(ret);
    1346             : 
    1347        3094 :                                 _mbuffer_consume(&session->internals.
    1348             :                                                  record_buffer, bufel,
    1349             :                                                  data_size);
    1350             : 
    1351        3094 :                                 ret =
    1352        3094 :                                     merge_handshake_packet(session, &tmp);
    1353        3094 :                                 if (ret < 0)
    1354           0 :                                         return gnutls_assert_val(ret);
    1355             : 
    1356             :                         }
    1357        3094 :                         while (_mbuffer_get_udata_size(bufel) > 0);
    1358             : 
    1359        3094 :                         prev = bufel;
    1360        3094 :                         bufel =
    1361        3094 :                             _mbuffer_dequeue(&session->internals.
    1362             :                                              record_buffer, bufel);
    1363             : 
    1364        3094 :                         _mbuffer_xfree(&prev);
    1365        3094 :                         continue;
    1366             : 
    1367          67 :                       next:
    1368          67 :                         bufel = _mbuffer_head_get_next(bufel, NULL);
    1369             :                 }
    1370        3161 :                 while (bufel != NULL);
    1371             : 
    1372             :                 /* sort in descending order */
    1373        3123 :                 if (session->internals.handshake_recv_buffer_size > 1)
    1374          39 :                         qsort(recv_buf,
    1375             :                               session->internals.
    1376             :                               handshake_recv_buffer_size,
    1377             :                               sizeof(recv_buf[0]), handshake_compare);
    1378             : 
    1379        3343 :                 while (session->internals.handshake_recv_buffer_size > 0 &&
    1380        3113 :                        recv_buf[LAST_ELEMENT].sequence <
    1381        3113 :                        session->internals.dtls.hsk_read_seq) {
    1382         220 :                         _gnutls_audit_log(session,
    1383             :                                           "Discarded replayed handshake packet with sequence %d\n",
    1384             :                                           recv_buf[LAST_ELEMENT].sequence);
    1385         440 :                         _gnutls_handshake_buffer_clear(&recv_buf
    1386         220 :                                                        [LAST_ELEMENT]);
    1387         220 :                         session->internals.handshake_recv_buffer_size--;
    1388             :                 }
    1389             : 
    1390             :                 return 0;
    1391             :         }
    1392             : }
    1393             : 
    1394             : /* This is a receive function for the gnutls handshake
    1395             :  * protocol. Makes sure that we have received all data.
    1396             :  */
    1397             : ssize_t
    1398    19837000 : _gnutls_handshake_io_recv_int(gnutls_session_t session,
    1399             :                               gnutls_handshake_description_t htype,
    1400             :                               handshake_buffer_st * hsk,
    1401             :                               unsigned int optional)
    1402             : {
    1403    19837000 :         int ret;
    1404    19837000 :         unsigned int tleft = 0;
    1405    19837000 :         int retries = 7;
    1406             : 
    1407    19837000 :         ret = get_last_packet(session, htype, hsk, optional);
    1408    19837000 :         if (ret != GNUTLS_E_AGAIN && ret != GNUTLS_E_INTERRUPTED &&
    1409    12855800 :             ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE &&
    1410    12855800 :             ret != GNUTLS_E_INT_CHECK_AGAIN) {
    1411        4841 :                 return gnutls_assert_val(ret);
    1412             :         }
    1413             : 
    1414             :         /* try using the already existing records before
    1415             :          * trying to receive.
    1416             :          */
    1417    19832200 :         ret = _gnutls_parse_record_buffered_msgs(session);
    1418             : 
    1419    19832200 :         if (ret == 0) {
    1420         758 :                 ret = get_last_packet(session, htype, hsk, optional);
    1421             :         }
    1422             : 
    1423    19832200 :         if (IS_DTLS(session)) {
    1424     6981250 :                 if (ret >= 0)
    1425           6 :                         return ret;
    1426             :         } else {
    1427    12851000 :                 if ((ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
    1428    12851000 :                      && ret < 0) || ret >= 0)
    1429         899 :                         return gnutls_assert_val(ret);
    1430             :         }
    1431             : 
    1432    19831300 :         if (htype != (gnutls_handshake_description_t) -1) {
    1433    19831300 :                 ret = handshake_remaining_time(session);
    1434    19831300 :                 if (ret < 0)
    1435           0 :                         return gnutls_assert_val(ret);
    1436    19831300 :                 tleft = ret;
    1437             :         }
    1438             : 
    1439    19831500 :         do {
    1440             :                 /* if we don't have a complete message waiting for us, try
    1441             :                  * receiving more */
    1442    39663000 :                 ret =
    1443    19831500 :                     _gnutls_recv_in_buffers(session, GNUTLS_HANDSHAKE, htype,
    1444             :                                             tleft);
    1445    19831500 :                 if (ret < 0)
    1446    19067600 :                         return gnutls_assert_val_fatal(ret);
    1447             : 
    1448      766986 :                 ret = _gnutls_parse_record_buffered_msgs(session);
    1449      766986 :                 if (ret == 0) {
    1450       55084 :                         ret = get_last_packet(session, htype, hsk, optional);
    1451             :                 }
    1452             :                 /* we put an upper limit (retries) to the number of partial handshake
    1453             :                  * messages in a record packet. */
    1454      766986 :         } while(IS_DTLS(session) && ret == GNUTLS_E_INT_CHECK_AGAIN && retries-- > 0);
    1455             : 
    1456      766801 :         if (unlikely(IS_DTLS(session) && ret == GNUTLS_E_INT_CHECK_AGAIN)) {
    1457           0 :                 ret = gnutls_assert_val(GNUTLS_E_TOO_MANY_HANDSHAKE_PACKETS);
    1458             :         }
    1459             : 
    1460      766801 :         return ret;
    1461             : }

Generated by: LCOV version 1.14