cleaned up errno handling.
[gnutls.git] / lib / gnutls_buffers.c
blob74e2d92da6f191a7448d286aadbede4e1f043d3e
1 /*
2 * Copyright (C) 2000-2012 Free Software Foundation, Inc.
4 * Author: Nikos Mavrogiannopoulos
6 * This file is part of GnuTLS.
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 3 of
11 * the License, or (at your option) any later version.
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.
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/>
23 /*
24 * This file holds all the buffering code used in gnutls.
25 * The buffering code works as:
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.)
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.)
36 * HANDSHAKE LAYER:
37 * 1. Uses buffer to hold the last received handshake message.
38 * (see _gnutls_handshake_hash_buffer_put() etc.)
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 <errno.h>
53 #include <system.h>
54 #include "debug.h"
56 #ifndef EAGAIN
57 #define EAGAIN EWOULDBLOCK
58 #endif
60 /* this is the maximum number of messages allowed to queue.
62 #define MAX_QUEUE 32
64 /* Buffers received packets of type APPLICATION DATA and
65 * HANDSHAKE DATA.
67 int
68 _gnutls_record_buffer_put (gnutls_session_t session,
69 content_type_t type, uint64* seq, mbuffer_st* bufel)
72 bufel->type = type;
73 memcpy(&bufel->record_sequence, seq, sizeof(*seq));
75 _mbuffer_enqueue(&session->internals.record_buffer, bufel);
76 _gnutls_buffers_log ("BUF[REC]: Inserted %d bytes of Data(%d)\n",
77 (int) bufel->msg.size, (int) type);
79 return 0;
82 /**
83 * gnutls_record_check_pending:
84 * @session: is a #gnutls_session_t structure.
86 * This function checks if there are unread data
87 * in the gnutls buffers. If the return value is
88 * non-zero the next call to gnutls_record_recv()
89 * is guarranteed not to block.
91 * Returns: Returns the size of the data or zero.
92 **/
93 size_t
94 gnutls_record_check_pending (gnutls_session_t session)
96 return _gnutls_record_buffer_get_size (session);
99 int
100 _gnutls_record_buffer_get (content_type_t type,
101 gnutls_session_t session, uint8_t * data,
102 size_t length, uint8_t seq[8])
104 gnutls_datum_t msg;
105 mbuffer_st* bufel;
107 if (length == 0 || data == NULL)
109 gnutls_assert ();
110 return GNUTLS_E_INVALID_REQUEST;
113 bufel = _mbuffer_head_get_first(&session->internals.record_buffer, &msg);
114 if (bufel == NULL)
115 return gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);
117 if (type != bufel->type)
119 if (IS_DTLS(session))
120 _gnutls_audit_log(session, "Discarded unexpected %s (%d) packet (expecting: %s (%d))\n",
121 _gnutls_packet2str(bufel->type), (int)bufel->type,
122 _gnutls_packet2str(type), (int)type);
123 _mbuffer_head_remove_bytes(&session->internals.record_buffer, msg.size);
124 return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET);
127 if (msg.size <= length)
128 length = msg.size;
130 if (seq)
131 memcpy(seq, bufel->record_sequence.i, 8);
133 memcpy(data, msg.data, length);
134 _mbuffer_head_remove_bytes(&session->internals.record_buffer, length);
136 return length;
139 inline static void
140 reset_errno (gnutls_session_t session)
142 session->internals.errnum = 0;
145 inline static int
146 get_errno (gnutls_session_t session)
148 int ret;
150 if (session->internals.errnum != 0)
151 ret = session->internals.errnum;
152 else
153 ret = session->internals.errno_func (session->
154 internals.transport_recv_ptr);
155 return ret;
158 inline static
159 int errno_to_gerr(int err)
161 switch(err)
163 case EAGAIN:
164 return GNUTLS_E_AGAIN;
165 case EINTR:
166 return GNUTLS_E_INTERRUPTED;
167 case EMSGSIZE:
168 return GNUTLS_E_LARGE_PACKET;
169 default:
170 gnutls_assert ();
171 return GNUTLS_E_PUSH_ERROR;
175 static ssize_t
176 _gnutls_dgram_read (gnutls_session_t session, mbuffer_st **bufel,
177 gnutls_pull_func pull_func)
179 ssize_t i, ret;
180 uint8_t *ptr;
181 size_t max_size = _gnutls_get_max_decrypted_data(session);
182 size_t recv_size = MAX_RECV_SIZE(session);
183 gnutls_transport_ptr_t fd = session->internals.transport_recv_ptr;
185 if (recv_size > max_size)
186 recv_size = max_size;
188 *bufel = _mbuffer_alloc (0, max_size);
189 if (*bufel == NULL)
190 return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
192 ptr = (*bufel)->msg.data;
194 session->internals.direction = 0;
196 reset_errno (session);
197 i = pull_func (fd, ptr, recv_size);
199 if (i < 0)
201 int err = get_errno (session);
203 _gnutls_read_log ("READ: %d returned from %p, errno=%d gerrno=%d\n",
204 (int) i, fd, errno, session->internals.errnum);
206 ret = errno_to_gerr(err);
207 goto cleanup;
209 else
211 _gnutls_read_log ("READ: Got %d bytes from %p\n", (int) i, fd);
212 if (i == 0)
214 /* If we get here, we likely have a stream socket.
215 * FIXME: this probably breaks DCCP. */
216 gnutls_assert ();
217 ret = 0;
218 goto cleanup;
221 _mbuffer_set_udata_size (*bufel, i);
224 _gnutls_read_log ("READ: read %d bytes from %p\n", (int) i, fd);
226 return i;
228 cleanup:
229 _mbuffer_xfree(bufel);
230 return ret;
233 static ssize_t
234 _gnutls_stream_read (gnutls_session_t session, mbuffer_st **bufel,
235 size_t size, gnutls_pull_func pull_func)
237 size_t left;
238 ssize_t i = 0;
239 size_t max_size = _gnutls_get_max_decrypted_data(session);
240 uint8_t *ptr;
241 gnutls_transport_ptr_t fd = session->internals.transport_recv_ptr;
243 *bufel = _mbuffer_alloc (0, MAX(max_size, size));
244 if (!*bufel)
246 gnutls_assert ();
247 return GNUTLS_E_MEMORY_ERROR;
249 ptr = (*bufel)->msg.data;
251 session->internals.direction = 0;
253 left = size;
254 while (left > 0)
256 reset_errno (session);
258 i = pull_func (fd, &ptr[size - left], left);
260 if (i < 0)
262 int err = get_errno (session);
264 _gnutls_read_log ("READ: %d returned from %p, errno=%d gerrno=%d\n",
265 (int) i, fd, errno, session->internals.errnum);
267 if (err == EAGAIN || err == EINTR)
269 if (size - left > 0)
272 _gnutls_read_log ("READ: returning %d bytes from %p\n",
273 (int) (size - left), fd);
275 goto finish;
278 return errno_to_gerr(err);
280 else
282 gnutls_assert ();
283 return GNUTLS_E_PULL_ERROR;
286 else
289 _gnutls_read_log ("READ: Got %d bytes from %p\n", (int) i, fd);
291 if (i == 0)
292 break; /* EOF */
295 left -= i;
296 (*bufel)->msg.size += i;
299 finish:
301 _gnutls_read_log ("READ: read %d bytes from %p\n",
302 (int) (size - left), fd);
304 return (size - left);
308 /* This function is like read. But it does not return -1 on error.
309 * It does return gnutls_errno instead.
311 * Flags are only used if the default recv() function is being used.
313 static ssize_t
314 _gnutls_read (gnutls_session_t session, mbuffer_st **bufel,
315 size_t size, gnutls_pull_func pull_func)
317 if (IS_DTLS (session))
318 /* Size is not passed, since a whole datagram will be read. */
319 return _gnutls_dgram_read (session, bufel, pull_func);
320 else
321 return _gnutls_stream_read (session, bufel, size, pull_func);
324 static ssize_t
325 _gnutls_writev_emu (gnutls_session_t session, gnutls_transport_ptr_t fd, const giovec_t * giovec,
326 unsigned int giovec_cnt)
328 unsigned int j = 0;
329 size_t total = 0;
330 ssize_t ret = 0;
332 for (j = 0; j < giovec_cnt; j++)
334 ret = session->internals.push_func (fd, giovec[j].iov_base, giovec[j].iov_len);
336 if (ret == -1)
337 break;
339 total += ret;
341 if ((size_t)ret != giovec[j].iov_len)
342 break;
345 if (total > 0)
346 return total;
348 return ret;
352 static ssize_t
353 _gnutls_writev (gnutls_session_t session, const giovec_t * giovec,
354 int giovec_cnt)
356 int i;
357 gnutls_transport_ptr_t fd = session->internals.transport_send_ptr;
359 reset_errno (session);
361 if (session->internals.push_func != NULL)
362 i = _gnutls_writev_emu (session, fd, giovec, giovec_cnt);
363 else
364 i = session->internals.vec_push_func (fd, giovec, giovec_cnt);
366 if (i == -1)
368 int err = get_errno (session);
369 _gnutls_debug_log ("errno: %d\n", err);
371 return errno_to_gerr(err);
373 return i;
376 /* This function is like recv(with MSG_PEEK). But it does not return -1 on error.
377 * It does return gnutls_errno instead.
378 * This function reads data from the socket and keeps them in a buffer, of up to
379 * MAX_RECV_SIZE.
381 * This is not a general purpose function. It returns EXACTLY the data requested,
382 * which are stored in a local (in the session) buffer.
385 ssize_t
386 _gnutls_io_read_buffered (gnutls_session_t session, size_t total,
387 content_type_t recv_type)
389 ssize_t ret = 0;
390 size_t min;
391 mbuffer_st *bufel = NULL;
392 size_t recvdata, readsize;
394 if (total > MAX_RECV_SIZE(session) || total == 0)
396 gnutls_assert (); /* internal error */
397 return GNUTLS_E_INVALID_REQUEST;
400 /* calculate the actual size, ie. get the minimum of the
401 * buffered data and the requested data.
403 min = MIN (session->internals.record_recv_buffer.byte_length, total);
404 if (min > 0)
406 /* if we have enough buffered data
407 * then just return them.
409 if (min == total)
411 return min;
415 /* min is over zero. recvdata is the data we must
416 * receive in order to return the requested data.
418 recvdata = total - min;
419 readsize = recvdata;
421 /* Check if the previously read data plus the new data to
422 * receive are longer than the maximum receive buffer size.
424 if ((session->internals.record_recv_buffer.byte_length + recvdata) >
425 MAX_RECV_SIZE(session))
427 gnutls_assert (); /* internal error */
428 return GNUTLS_E_INVALID_REQUEST;
431 if (ret < 0)
433 gnutls_assert ();
434 return ret;
437 /* READ DATA
439 if (readsize > 0)
441 ret =
442 _gnutls_read (session, &bufel, readsize,
443 session->internals.pull_func);
445 /* return immediately if we got an interrupt or eagain
446 * error.
448 if (ret < 0 && gnutls_error_is_fatal (ret) == 0)
450 _mbuffer_xfree (&bufel);
451 return ret;
455 /* copy fresh data to our buffer.
457 if (ret > 0)
459 _gnutls_read_log
460 ("RB: Have %d bytes into buffer. Adding %d bytes.\n",
461 (int) session->internals.record_recv_buffer.byte_length, (int) ret);
462 _gnutls_read_log ("RB: Requested %d bytes\n", (int) total);
464 _mbuffer_enqueue (&session->internals.record_recv_buffer, bufel);
466 else
467 _mbuffer_xfree (&bufel);
469 if (ret < 0)
471 gnutls_assert ();
472 return ret;
475 if (ret == 0)
476 { /* EOF */
477 gnutls_assert ();
478 return 0;
481 if(IS_DTLS(session))
482 ret = MIN(total, session->internals.record_recv_buffer.byte_length);
483 else
484 ret = session->internals.record_recv_buffer.byte_length;
486 if ((ret > 0) && ((size_t) ret < total))
488 /* Short Read */
489 return gnutls_assert_val(GNUTLS_E_AGAIN);
491 else
493 return ret;
497 /* This function is like write. But it does not return -1 on error.
498 * It does return gnutls_errno instead.
500 * This function takes full responsibility of freeing msg->data.
502 * In case of E_AGAIN and E_INTERRUPTED errors, you must call
503 * gnutls_write_flush(), until it returns ok (0).
505 * We need to push exactly the data in msg->size, since we cannot send
506 * less data. In TLS the peer must receive the whole packet in order
507 * to decrypt and verify the integrity.
510 ssize_t
511 _gnutls_io_write_buffered (gnutls_session_t session,
512 mbuffer_st * bufel, unsigned int mflag)
514 mbuffer_head_st *const send_buffer = &session->internals.record_send_buffer;
516 /* to know where the procedure was interrupted.
518 session->internals.direction = 1;
520 _mbuffer_enqueue (send_buffer, bufel);
522 _gnutls_write_log
523 ("WRITE: enqueued %d bytes for %p. Total %d bytes.\n",
524 (int) bufel->msg.size, session->internals.transport_recv_ptr,
525 (int) send_buffer->byte_length);
527 if (mflag == MBUFFER_FLUSH)
528 return _gnutls_io_write_flush (session);
529 else
530 return bufel->msg.size;
533 typedef ssize_t (*send_func) (gnutls_session_t, const giovec_t *, int);
535 /* This function writes the data that are left in the
536 * TLS write buffer (ie. because the previous write was
537 * interrupted.
539 ssize_t
540 _gnutls_io_write_flush (gnutls_session_t session)
542 gnutls_datum_t msg;
543 mbuffer_head_st *send_buffer = &session->internals.record_send_buffer;
544 int ret;
545 ssize_t sent = 0, tosend = 0;
546 giovec_t iovec[MAX_QUEUE];
547 int i = 0;
548 mbuffer_st *cur;
550 _gnutls_write_log ("WRITE FLUSH: %d bytes in buffer.\n",
551 (int) send_buffer->byte_length);
553 for (cur = _mbuffer_head_get_first (send_buffer, &msg);
554 cur != NULL; cur = _mbuffer_head_get_next (cur, &msg))
556 iovec[i].iov_base = msg.data;
557 iovec[i++].iov_len = msg.size;
558 tosend += msg.size;
560 /* we buffer up to MAX_QUEUE messages */
561 if (i >= MAX_QUEUE)
563 gnutls_assert ();
564 return GNUTLS_E_INTERNAL_ERROR;
568 if (tosend == 0)
570 gnutls_assert();
571 return 0;
574 ret = _gnutls_writev (session, iovec, i);
575 if (ret >= 0)
577 _mbuffer_head_remove_bytes (send_buffer, ret);
578 _gnutls_write_log ("WRITE: wrote %d bytes, %d bytes left.\n",
579 ret, (int) send_buffer->byte_length);
581 sent += ret;
583 else if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN)
585 _gnutls_write_log ("WRITE interrupted: %d bytes left.\n",
586 (int) send_buffer->byte_length);
587 return ret;
589 else if (ret == GNUTLS_E_LARGE_PACKET)
591 _mbuffer_head_remove_bytes (send_buffer, tosend);
592 _gnutls_write_log ("WRITE cannot send large packet (%u bytes).\n",
593 (unsigned int) tosend);
594 return ret;
596 else
598 _gnutls_write_log ("WRITE error: code %d, %d bytes left.\n",
599 ret, (int) send_buffer->byte_length);
601 gnutls_assert ();
602 return ret;
605 if (sent < tosend)
607 return gnutls_assert_val(GNUTLS_E_AGAIN);
610 return sent;
613 /* Checks whether there are received data within
614 * a timeframe.
616 * Returns 0 if data were received, GNUTLS_E_TIMEDOUT
617 * on timeout and a negative error code on error.
620 _gnutls_io_check_recv (gnutls_session_t session, unsigned int ms)
622 gnutls_transport_ptr_t fd = session->internals.transport_send_ptr;
623 int ret = 0, err;
625 if (session->internals.pull_timeout_func == system_recv_timeout &&
626 session->internals.pull_func != system_read)
627 return gnutls_assert_val(GNUTLS_E_PULL_ERROR);
629 reset_errno (session);
631 ret = session->internals.pull_timeout_func(fd, ms);
633 err = get_errno (session);
634 if (ret == -1 && err == EINTR)
635 return GNUTLS_E_INTERRUPTED;
636 else if (ret == -1 && err == EAGAIN)
637 return GNUTLS_E_AGAIN;
638 else if (ret == -1)
639 return gnutls_assert_val(GNUTLS_E_PULL_ERROR);
641 if (ret > 0)
642 return 0;
643 else return GNUTLS_E_TIMEDOUT;
646 /* HANDSHAKE buffers part
649 /* This function writes the data that are left in the
650 * Handshake write buffer (ie. because the previous write was
651 * interrupted.
654 ssize_t
655 _gnutls_handshake_io_write_flush (gnutls_session_t session)
657 mbuffer_head_st *const send_buffer =
658 &session->internals.handshake_send_buffer;
659 gnutls_datum_t msg;
660 int ret;
661 uint16_t epoch;
662 ssize_t total = 0;
663 mbuffer_st *cur;
665 _gnutls_write_log ("HWRITE FLUSH: %d bytes in buffer.\n",
666 (int) send_buffer->byte_length);
668 if (IS_DTLS(session))
669 return _dtls_transmit(session);
671 for (cur = _mbuffer_head_get_first (send_buffer, &msg);
672 cur != NULL; cur = _mbuffer_head_get_first (send_buffer, &msg))
674 epoch = cur->epoch;
676 ret = _gnutls_send_int (session, cur->type,
677 cur->htype,
678 epoch,
679 msg.data, msg.size, 0);
681 if (ret >= 0)
683 total += ret;
685 ret = _mbuffer_head_remove_bytes (send_buffer, ret);
686 if (ret == 1)
687 _gnutls_epoch_refcount_dec(session, epoch);
689 _gnutls_write_log ("HWRITE: wrote %d bytes, %d bytes left.\n",
690 ret, (int) send_buffer->byte_length);
693 else
695 _gnutls_write_log ("HWRITE error: code %d, %d bytes left.\n",
696 ret, (int) send_buffer->byte_length);
698 gnutls_assert ();
699 return ret;
703 return _gnutls_io_write_flush (session);
707 /* This is a send function for the gnutls handshake
708 * protocol. Just makes sure that all data have been sent.
712 _gnutls_handshake_io_cache_int (gnutls_session_t session,
713 gnutls_handshake_description_t htype,
714 mbuffer_st * bufel)
716 mbuffer_head_st * send_buffer;
718 if (IS_DTLS(session))
720 bufel->handshake_sequence = session->internals.dtls.hsk_write_seq-1;
723 send_buffer =
724 &session->internals.handshake_send_buffer;
726 bufel->epoch = (uint16_t)_gnutls_epoch_refcount_inc(session, EPOCH_WRITE_CURRENT);
727 bufel->htype = htype;
728 if (bufel->htype == GNUTLS_HANDSHAKE_CHANGE_CIPHER_SPEC)
729 bufel->type = GNUTLS_CHANGE_CIPHER_SPEC;
730 else
731 bufel->type = GNUTLS_HANDSHAKE;
733 _mbuffer_enqueue (send_buffer, bufel);
735 _gnutls_write_log
736 ("HWRITE: enqueued [%s] %d. Total %d bytes.\n",
737 _gnutls_handshake2str (bufel->htype), (int) bufel->msg.size, (int) send_buffer->byte_length);
739 return 0;
742 static int handshake_compare(const void* _e1, const void* _e2)
744 const handshake_buffer_st* e1 = _e1;
745 const handshake_buffer_st* e2 = _e2;
747 if (e1->sequence <= e2->sequence)
748 return 1;
749 else
750 return -1;
753 #define SSL2_HEADERS 1
754 static int
755 parse_handshake_header (gnutls_session_t session, mbuffer_st* bufel,
756 handshake_buffer_st* hsk)
758 uint8_t *dataptr = NULL; /* for realloc */
759 size_t handshake_header_size = HANDSHAKE_HEADER_SIZE(session), data_size;
761 /* Note: SSL2_HEADERS == 1 */
762 if (_mbuffer_get_udata_size(bufel) < handshake_header_size)
763 return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
765 dataptr = _mbuffer_get_udata_ptr(bufel);
767 /* if reading a client hello of SSLv2 */
768 if (!IS_DTLS(session) && bufel->htype == GNUTLS_HANDSHAKE_CLIENT_HELLO_V2)
770 handshake_header_size = SSL2_HEADERS; /* we've already read one byte */
772 hsk->length = _mbuffer_get_udata_size(bufel) - handshake_header_size; /* we've read the first byte */
774 if (dataptr[0] != GNUTLS_HANDSHAKE_CLIENT_HELLO)
775 return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET);
777 hsk->htype = GNUTLS_HANDSHAKE_CLIENT_HELLO_V2;
779 hsk->sequence = 0;
780 hsk->start_offset = 0;
781 hsk->end_offset = hsk->length;
783 else /* TLS handshake headers */
786 hsk->htype = dataptr[0];
788 /* we do not use DECR_LEN because we know
789 * that the packet has enough data.
791 hsk->length = _gnutls_read_uint24 (&dataptr[1]);
792 handshake_header_size = HANDSHAKE_HEADER_SIZE(session);
794 if (IS_DTLS(session))
796 hsk->sequence = _gnutls_read_uint16 (&dataptr[4]);
797 hsk->start_offset = _gnutls_read_uint24 (&dataptr[6]);
798 hsk->end_offset = hsk->start_offset + _gnutls_read_uint24 (&dataptr[9]);
800 else
802 hsk->sequence = 0;
803 hsk->start_offset = 0;
804 hsk->end_offset = MIN((_mbuffer_get_udata_size(bufel) - handshake_header_size), hsk->length);
807 data_size = _mbuffer_get_udata_size(bufel) - handshake_header_size;
809 /* make the length offset */
810 if (hsk->end_offset > 0) hsk->end_offset--;
812 _gnutls_handshake_log ("HSK[%p]: %s was received. Length %d[%d], frag offset %d, frag length: %d, sequence: %d\n",
813 session, _gnutls_handshake2str (hsk->htype),
814 (int) hsk->length, (int)data_size, hsk->start_offset, hsk->end_offset-hsk->start_offset+1, (int)hsk->sequence);
816 hsk->header_size = handshake_header_size;
817 memcpy(hsk->header, _mbuffer_get_udata_ptr(bufel), handshake_header_size);
819 if (hsk->length > 0 &&
820 (hsk->end_offset-hsk->start_offset >= data_size))
821 return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
823 if (hsk->length > 0 && (hsk->start_offset >= hsk->end_offset ||
824 hsk->end_offset-hsk->start_offset >= data_size ||
825 hsk->end_offset >= hsk->length))
826 return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
827 else if (hsk->length == 0 && hsk->end_offset != 0 && hsk->start_offset != 0)
828 return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH);
830 return handshake_header_size;
833 static void _gnutls_handshake_buffer_move(handshake_buffer_st* dst, handshake_buffer_st* src)
835 memcpy(dst, src, sizeof(*dst));
836 memset(src, 0, sizeof(*src));
837 src->htype = -1;
840 /* will merge the given handshake_buffer_st to the handshake_recv_buffer
841 * list. The given hsk packet will be released in any case (success or failure).
842 * Only used in DTLS.
844 static int merge_handshake_packet(gnutls_session_t session, handshake_buffer_st* hsk)
846 int exists = 0, i, pos = 0;
847 int ret;
849 for (i=0;i<session->internals.handshake_recv_buffer_size;i++)
851 if (session->internals.handshake_recv_buffer[i].htype == hsk->htype)
853 exists = 1;
854 pos = i;
855 break;
859 if (exists == 0)
860 pos = session->internals.handshake_recv_buffer_size;
862 if (pos > MAX_HANDSHAKE_MSGS)
863 return gnutls_assert_val(GNUTLS_E_TOO_MANY_HANDSHAKE_PACKETS);
865 if (exists == 0)
867 if (hsk->length > 0 && hsk->end_offset > 0 && hsk->end_offset-hsk->start_offset+1 != hsk->length)
869 ret = _gnutls_buffer_resize(&hsk->data, hsk->length);
870 if (ret < 0)
871 return gnutls_assert_val(ret);
873 hsk->data.length = hsk->length;
875 memmove(&hsk->data.data[hsk->start_offset], hsk->data.data, hsk->end_offset-hsk->start_offset+1);
878 session->internals.handshake_recv_buffer_size++;
880 /* rewrite headers to make them look as each packet came as a single fragment */
881 _gnutls_write_uint24(hsk->length, &hsk->header[1]);
882 _gnutls_write_uint24(0, &hsk->header[6]);
883 _gnutls_write_uint24(hsk->length, &hsk->header[9]);
885 _gnutls_handshake_buffer_move(&session->internals.handshake_recv_buffer[pos], hsk);
888 else
890 if (hsk->start_offset < session->internals.handshake_recv_buffer[pos].start_offset &&
891 hsk->end_offset >= session->internals.handshake_recv_buffer[pos].start_offset)
893 memcpy(&session->internals.handshake_recv_buffer[pos].data.data[hsk->start_offset],
894 hsk->data.data, hsk->data.length);
895 session->internals.handshake_recv_buffer[pos].start_offset = hsk->start_offset;
896 session->internals.handshake_recv_buffer[pos].end_offset =
897 MIN(hsk->end_offset, session->internals.handshake_recv_buffer[pos].end_offset);
899 else if (hsk->end_offset > session->internals.handshake_recv_buffer[pos].end_offset &&
900 hsk->start_offset <= session->internals.handshake_recv_buffer[pos].end_offset+1)
902 memcpy(&session->internals.handshake_recv_buffer[pos].data.data[hsk->start_offset],
903 hsk->data.data, hsk->data.length);
905 session->internals.handshake_recv_buffer[pos].end_offset = hsk->end_offset;
906 session->internals.handshake_recv_buffer[pos].start_offset =
907 MIN(hsk->start_offset, session->internals.handshake_recv_buffer[pos].start_offset);
909 _gnutls_handshake_buffer_clear(hsk);
912 return 0;
915 /* returns non-zero on match and zero on mismatch
917 inline static int cmp_hsk_types(gnutls_handshake_description_t expected, gnutls_handshake_description_t recvd)
919 if ((expected != GNUTLS_HANDSHAKE_CLIENT_HELLO || recvd != GNUTLS_HANDSHAKE_CLIENT_HELLO_V2) &&
920 (expected != recvd))
921 return 0;
923 return 1;
926 #define LAST_ELEMENT (session->internals.handshake_recv_buffer_size-1)
928 /* returns the last stored handshake packet.
930 static int get_last_packet(gnutls_session_t session, gnutls_handshake_description_t htype,
931 handshake_buffer_st * hsk, unsigned int optional)
933 handshake_buffer_st* recv_buf = session->internals.handshake_recv_buffer;
935 if (IS_DTLS(session))
937 if (session->internals.handshake_recv_buffer_size == 0 ||
938 (session->internals.dtls.hsk_read_seq != recv_buf[LAST_ELEMENT].sequence))
939 goto timeout;
941 if (htype != recv_buf[LAST_ELEMENT].htype)
943 if (optional == 0)
944 _gnutls_audit_log(session, "Received unexpected handshake message '%s' (%d). Expected '%s' (%d)\n",
945 _gnutls_handshake2str(recv_buf[0].htype), (int)recv_buf[0].htype, _gnutls_handshake2str(htype), (int)htype);
947 return gnutls_assert_val(GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET);
950 else if ((recv_buf[LAST_ELEMENT].start_offset == 0 &&
951 recv_buf[LAST_ELEMENT].end_offset == recv_buf[LAST_ELEMENT].length -1) ||
952 recv_buf[LAST_ELEMENT].length == 0)
954 session->internals.dtls.hsk_read_seq++;
955 _gnutls_handshake_buffer_move(hsk, &recv_buf[LAST_ELEMENT]);
956 session->internals.handshake_recv_buffer_size--;
957 return 0;
959 else
960 goto timeout;
962 else /* TLS */
964 if (session->internals.handshake_recv_buffer_size > 0 && recv_buf[0].length == recv_buf[0].data.length)
966 if (cmp_hsk_types(htype, recv_buf[0].htype) == 0)
968 return gnutls_assert_val(GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET);
971 _gnutls_handshake_buffer_move(hsk, &recv_buf[0]);
972 session->internals.handshake_recv_buffer_size--;
973 return 0;
975 else
976 return gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE);
979 timeout:
980 RETURN_DTLS_EAGAIN_OR_TIMEOUT(session, 0);
983 /* This is a receive function for the gnutls handshake
984 * protocol. Makes sure that we have received all data.
986 * htype is the next handshake packet expected.
989 _gnutls_parse_record_buffered_msgs (gnutls_session_t session)
991 gnutls_datum_t msg;
992 mbuffer_st* bufel = NULL, *prev = NULL;
993 int ret;
994 size_t data_size;
995 handshake_buffer_st* recv_buf = session->internals.handshake_recv_buffer;
997 bufel = _mbuffer_head_get_first(&session->internals.record_buffer, &msg);
998 if (bufel == NULL)
999 return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE;
1001 if (!IS_DTLS(session))
1003 ssize_t remain, append, header_size;
1007 if (bufel->type != GNUTLS_HANDSHAKE)
1008 return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET);
1010 /* if we have a half received message the complete it.
1012 remain = recv_buf[0].length -
1013 recv_buf[0].data.length;
1015 /* this is the rest of a previous message */
1016 if (session->internals.handshake_recv_buffer_size > 0 && recv_buf[0].length > 0 && remain > 0)
1018 if (msg.size <= remain)
1019 append = msg.size;
1020 else
1021 append = remain;
1023 ret = _gnutls_buffer_append_data(&recv_buf[0].data, msg.data, append);
1024 if (ret < 0)
1025 return gnutls_assert_val(ret);
1027 _mbuffer_head_remove_bytes(&session->internals.record_buffer, append);
1029 else /* received new message */
1031 ret = parse_handshake_header(session, bufel, &recv_buf[0]);
1032 if (ret < 0)
1033 return gnutls_assert_val(ret);
1035 header_size = ret;
1036 session->internals.handshake_recv_buffer_size = 1;
1038 _mbuffer_set_uhead_size(bufel, header_size);
1040 data_size = MIN(recv_buf[0].length, _mbuffer_get_udata_size(bufel));
1041 ret = _gnutls_buffer_append_data(&recv_buf[0].data, _mbuffer_get_udata_ptr(bufel), data_size);
1042 if (ret < 0)
1043 return gnutls_assert_val(ret);
1044 _mbuffer_set_uhead_size(bufel, 0);
1045 _mbuffer_head_remove_bytes(&session->internals.record_buffer, data_size+header_size);
1048 /* if packet is complete then return it
1050 if (recv_buf[0].length ==
1051 recv_buf[0].data.length)
1053 return 0;
1055 bufel = _mbuffer_head_get_first(&session->internals.record_buffer, &msg);
1057 while(bufel != NULL);
1059 /* if we are here it means that the received packets were not
1060 * enough to complete the handshake packet.
1062 return gnutls_assert_val(GNUTLS_E_AGAIN);
1064 else /* DTLS */
1066 handshake_buffer_st tmp;
1070 /* we now
1071 * 0. parse headers
1072 * 1. insert to handshake_recv_buffer
1073 * 2. sort handshake_recv_buffer on sequence numbers
1074 * 3. return first packet if completed or GNUTLS_E_AGAIN.
1078 if (bufel->type != GNUTLS_HANDSHAKE)
1080 gnutls_assert();
1081 goto next; /* ignore packet */
1084 _gnutls_handshake_buffer_init(&tmp);
1086 ret = parse_handshake_header(session, bufel, &tmp);
1087 if (ret < 0)
1089 gnutls_assert();
1090 _gnutls_audit_log(session, "Invalid handshake packet headers. Discarding.\n");
1091 break;
1094 _mbuffer_consume(&session->internals.record_buffer, bufel, ret);
1096 data_size = MIN(tmp.length, tmp.end_offset-tmp.start_offset+1);
1098 ret = _gnutls_buffer_append_data(&tmp.data, _mbuffer_get_udata_ptr(bufel), data_size);
1099 if (ret < 0)
1100 return gnutls_assert_val(ret);
1102 _mbuffer_consume(&session->internals.record_buffer, bufel, data_size);
1104 ret = merge_handshake_packet(session, &tmp);
1105 if (ret < 0)
1106 return gnutls_assert_val(ret);
1109 while(_mbuffer_get_udata_size(bufel) > 0);
1111 prev = bufel;
1112 bufel = _mbuffer_dequeue(&session->internals.record_buffer, bufel);
1114 _mbuffer_xfree(&prev);
1115 continue;
1117 next:
1118 bufel = _mbuffer_head_get_next(bufel, NULL);
1120 while(bufel != NULL);
1122 /* sort in descending order */
1123 if (session->internals.handshake_recv_buffer_size > 1)
1124 qsort(recv_buf, session->internals.handshake_recv_buffer_size,
1125 sizeof(recv_buf[0]), handshake_compare);
1127 while(session->internals.handshake_recv_buffer_size > 0 &&
1128 recv_buf[LAST_ELEMENT].sequence < session->internals.dtls.hsk_read_seq)
1130 _gnutls_audit_log(session, "Discarded replayed handshake packet with sequence %d\n", recv_buf[LAST_ELEMENT].sequence);
1131 _gnutls_handshake_buffer_clear(&recv_buf[LAST_ELEMENT]);
1132 session->internals.handshake_recv_buffer_size--;
1135 return 0;
1139 /* This is a receive function for the gnutls handshake
1140 * protocol. Makes sure that we have received all data.
1142 ssize_t
1143 _gnutls_handshake_io_recv_int (gnutls_session_t session,
1144 gnutls_handshake_description_t htype,
1145 handshake_buffer_st * hsk, unsigned int optional)
1147 int ret;
1149 ret = get_last_packet(session, htype, hsk, optional);
1150 if (ret != GNUTLS_E_AGAIN && ret != GNUTLS_E_INTERRUPTED && ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
1152 return gnutls_assert_val(ret);
1155 /* try using the already existing records before
1156 * trying to receive.
1158 ret = _gnutls_parse_record_buffered_msgs(session);
1160 if (ret == 0) ret = get_last_packet(session, htype, hsk, optional);
1162 if (IS_DTLS(session))
1164 if (ret >= 0)
1165 return ret;
1167 else
1169 if ((ret != GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE && ret < 0) || ret >= 0)
1170 return gnutls_assert_val(ret);
1173 /* if we don't have a complete message waiting for us, try
1174 * receiving more */
1175 ret = _gnutls_recv_in_buffers(session, GNUTLS_HANDSHAKE, htype);
1176 if (ret < 0)
1177 return gnutls_assert_val_fatal(ret);
1179 ret = _gnutls_parse_record_buffered_msgs(session);
1180 if (ret == 0) ret = get_last_packet(session, htype, hsk, optional);
1182 return ret;