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