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/>
24 * This file holds all the buffering code used in gnutls.
25 * The buffering code works as:
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
34 * (see _gnutls_io_read_buffered(), _gnutls_io_write_buffered() etc.)
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>
51 #include <gnutls_constate.h> /* gnutls_epoch_get */
52 #include <gnutls_handshake.h> /* remaining_time() */
58 #define EAGAIN EWOULDBLOCK
61 /* this is the maximum number of messages allowed to queue.
65 /* Buffers received packets of type APPLICATION DATA,
66 * HANDSHAKE DATA and HEARTBEAT.
69 _gnutls_record_buffer_put (gnutls_session_t session
,
70 content_type_t type
, uint64
* seq
, mbuffer_st
* bufel
)
74 memcpy(&bufel
->record_sequence
, seq
, sizeof(*seq
));
76 _mbuffer_enqueue(&session
->internals
.record_buffer
, bufel
);
77 _gnutls_buffers_log ("BUF[REC]: Inserted %d bytes of Data(%d)\n",
78 (int) bufel
->msg
.size
, (int) type
);
84 * gnutls_record_check_pending:
85 * @session: is a #gnutls_session_t structure.
87 * This function checks if there are unread data
88 * in the gnutls buffers. If the return value is
89 * non-zero the next call to gnutls_record_recv()
90 * is guarranteed not to block.
92 * Returns: Returns the size of the data or zero.
95 gnutls_record_check_pending (gnutls_session_t session
)
97 return _gnutls_record_buffer_get_size (session
);
101 _gnutls_record_buffer_get (content_type_t type
,
102 gnutls_session_t session
, uint8_t * data
,
103 size_t length
, uint8_t seq
[8])
108 if (length
== 0 || data
== NULL
)
111 return GNUTLS_E_INVALID_REQUEST
;
114 bufel
= _mbuffer_head_get_first(&session
->internals
.record_buffer
, &msg
);
116 return gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
);
118 if (type
!= bufel
->type
)
120 if (IS_DTLS(session
))
121 _gnutls_audit_log(session
, "Discarded unexpected %s (%d) packet (expecting: %s (%d))\n",
122 _gnutls_packet2str(bufel
->type
), (int)bufel
->type
,
123 _gnutls_packet2str(type
), (int)type
);
124 _mbuffer_head_remove_bytes(&session
->internals
.record_buffer
, msg
.size
);
125 return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET
);
128 if (msg
.size
<= length
)
132 memcpy(seq
, bufel
->record_sequence
.i
, 8);
134 memcpy(data
, msg
.data
, length
);
135 _mbuffer_head_remove_bytes(&session
->internals
.record_buffer
, length
);
141 reset_errno (gnutls_session_t session
)
143 session
->internals
.errnum
= 0;
147 get_errno (gnutls_session_t session
)
151 if (session
->internals
.errnum
!= 0)
152 ret
= session
->internals
.errnum
;
154 ret
= session
->internals
.errno_func (session
->
155 internals
.transport_recv_ptr
);
160 int errno_to_gerr(int err
)
165 return GNUTLS_E_AGAIN
;
167 return GNUTLS_E_INTERRUPTED
;
169 return GNUTLS_E_LARGE_PACKET
;
172 return GNUTLS_E_PUSH_ERROR
;
177 _gnutls_dgram_read (gnutls_session_t session
, mbuffer_st
**bufel
,
178 gnutls_pull_func pull_func
, unsigned int *ms
)
182 struct timespec t1
, t2
;
183 size_t max_size
= _gnutls_get_max_decrypted_data(session
);
184 size_t recv_size
= MAX_RECV_SIZE(session
);
185 gnutls_transport_ptr_t fd
= session
->internals
.transport_recv_ptr
;
188 if (recv_size
> max_size
)
189 recv_size
= max_size
;
191 session
->internals
.direction
= 0;
195 ret
= _gnutls_io_check_recv(session
, *ms
);
197 return gnutls_assert_val(ret
);
201 *bufel
= _mbuffer_alloc (0, max_size
);
203 return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR
);
205 ptr
= (*bufel
)->msg
.data
;
207 reset_errno (session
);
208 i
= pull_func (fd
, ptr
, recv_size
);
212 int err
= get_errno (session
);
214 _gnutls_read_log ("READ: %d returned from %p, errno=%d gerrno=%d\n",
215 (int) i
, fd
, errno
, session
->internals
.errnum
);
217 ret
= errno_to_gerr(err
);
222 _gnutls_read_log ("READ: Got %d bytes from %p\n", (int) i
, fd
);
225 /* If we get here, we likely have a stream socket.
226 * FIXME: this probably breaks DCCP. */
232 _mbuffer_set_udata_size (*bufel
, i
);
238 diff
= _dtls_timespec_sub_ms(&t2
, &t1
);
242 return gnutls_assert_val(GNUTLS_E_TIMEDOUT
);
245 _gnutls_read_log ("READ: read %d bytes from %p\n", (int) i
, fd
);
250 _mbuffer_xfree(bufel
);
255 _gnutls_stream_read (gnutls_session_t session
, mbuffer_st
**bufel
,
256 size_t size
, gnutls_pull_func pull_func
, unsigned int *ms
)
260 size_t max_size
= _gnutls_get_max_decrypted_data(session
);
262 gnutls_transport_ptr_t fd
= session
->internals
.transport_recv_ptr
;
264 struct timespec t1
, t2
;
267 session
->internals
.direction
= 0;
269 *bufel
= _mbuffer_alloc (0, MAX(max_size
, size
));
273 return GNUTLS_E_MEMORY_ERROR
;
275 ptr
= (*bufel
)->msg
.data
;
282 ret
= _gnutls_io_check_recv(session
, *ms
);
284 return gnutls_assert_val(ret
);
289 reset_errno (session
);
291 i
= pull_func (fd
, &ptr
[size
- left
], left
);
295 int err
= get_errno (session
);
297 _gnutls_read_log ("READ: %d returned from %p, errno=%d gerrno=%d\n",
298 (int) i
, fd
, errno
, session
->internals
.errnum
);
300 if (err
== EAGAIN
|| err
== EINTR
)
305 _gnutls_read_log ("READ: returning %d bytes from %p\n",
306 (int) (size
- left
), fd
);
311 return errno_to_gerr(err
);
316 return GNUTLS_E_PULL_ERROR
;
322 _gnutls_read_log ("READ: Got %d bytes from %p\n", (int) i
, fd
);
329 (*bufel
)->msg
.size
+= i
;
334 diff
= _dtls_timespec_sub_ms(&t2
, &t1
);
338 return gnutls_assert_val(GNUTLS_E_TIMEDOUT
);
344 _gnutls_read_log ("READ: read %d bytes from %p\n",
345 (int) (size
- left
), fd
);
347 return (size
- left
);
351 /* This function is like read. But it does not return -1 on error.
352 * It does return gnutls_errno instead.
354 * Flags are only used if the default recv() function is being used.
357 _gnutls_read (gnutls_session_t session
, mbuffer_st
**bufel
,
358 size_t size
, gnutls_pull_func pull_func
, unsigned int *ms
)
360 if (IS_DTLS (session
))
361 /* Size is not passed, since a whole datagram will be read. */
362 return _gnutls_dgram_read (session
, bufel
, pull_func
, ms
);
364 return _gnutls_stream_read (session
, bufel
, size
, pull_func
, ms
);
368 _gnutls_writev_emu (gnutls_session_t session
, gnutls_transport_ptr_t fd
, const giovec_t
* giovec
,
369 unsigned int giovec_cnt
)
375 for (j
= 0; j
< giovec_cnt
; j
++)
377 ret
= session
->internals
.push_func (fd
, giovec
[j
].iov_base
, giovec
[j
].iov_len
);
384 if ((size_t)ret
!= giovec
[j
].iov_len
)
396 _gnutls_writev (gnutls_session_t session
, const giovec_t
* giovec
,
400 gnutls_transport_ptr_t fd
= session
->internals
.transport_send_ptr
;
402 reset_errno (session
);
404 if (session
->internals
.push_func
!= NULL
)
405 i
= _gnutls_writev_emu (session
, fd
, giovec
, giovec_cnt
);
407 i
= session
->internals
.vec_push_func (fd
, giovec
, giovec_cnt
);
411 int err
= get_errno (session
);
412 _gnutls_debug_log ("errno: %d\n", err
);
414 return errno_to_gerr(err
);
420 * @ms: a pointer to the number of milliseconds to wait for data. Use zero or NULL for indefinite.
422 * This function is like recv(with MSG_PEEK). But it does not return -1 on error.
423 * It does return gnutls_errno instead.
424 * This function reads data from the socket and keeps them in a buffer, of up to
427 * This is not a general purpose function. It returns EXACTLY the data requested,
428 * which are stored in a local (in the session) buffer.
430 * If the @ms parameter is non zero then this function will return before
431 * the given amount of milliseconds or return GNUTLS_E_TIMEDOUT.
435 _gnutls_io_read_buffered (gnutls_session_t session
, size_t total
,
436 content_type_t recv_type
, unsigned int *ms
)
440 mbuffer_st
*bufel
= NULL
;
441 size_t recvdata
, readsize
;
443 if (total
> MAX_RECV_SIZE(session
) || total
== 0)
445 gnutls_assert (); /* internal error */
446 return GNUTLS_E_INVALID_REQUEST
;
449 /* calculate the actual size, ie. get the minimum of the
450 * buffered data and the requested data.
452 min
= MIN (session
->internals
.record_recv_buffer
.byte_length
, total
);
455 /* if we have enough buffered data
456 * then just return them.
464 /* min is over zero. recvdata is the data we must
465 * receive in order to return the requested data.
467 recvdata
= total
- min
;
470 /* Check if the previously read data plus the new data to
471 * receive are longer than the maximum receive buffer size.
473 if ((session
->internals
.record_recv_buffer
.byte_length
+ recvdata
) >
474 MAX_RECV_SIZE(session
))
476 gnutls_assert (); /* internal error */
477 return GNUTLS_E_INVALID_REQUEST
;
485 _gnutls_read (session
, &bufel
, readsize
,
486 session
->internals
.pull_func
, ms
);
488 /* return immediately if we got an interrupt or eagain
491 if (ret
< 0 && gnutls_error_is_fatal (ret
) == 0)
493 _mbuffer_xfree (&bufel
);
498 /* copy fresh data to our buffer.
503 ("RB: Have %d bytes into buffer. Adding %d bytes.\n",
504 (int) session
->internals
.record_recv_buffer
.byte_length
, (int) ret
);
505 _gnutls_read_log ("RB: Requested %d bytes\n", (int) total
);
507 _mbuffer_enqueue (&session
->internals
.record_recv_buffer
, bufel
);
510 _mbuffer_xfree (&bufel
);
525 ret
= MIN(total
, session
->internals
.record_recv_buffer
.byte_length
);
527 ret
= session
->internals
.record_recv_buffer
.byte_length
;
529 if ((ret
> 0) && ((size_t) ret
< total
))
532 return gnutls_assert_val(GNUTLS_E_AGAIN
);
540 /* This function is like write. But it does not return -1 on error.
541 * It does return gnutls_errno instead.
543 * This function takes full responsibility of freeing msg->data.
545 * In case of E_AGAIN and E_INTERRUPTED errors, you must call
546 * gnutls_write_flush(), until it returns ok (0).
548 * We need to push exactly the data in msg->size, since we cannot send
549 * less data. In TLS the peer must receive the whole packet in order
550 * to decrypt and verify the integrity.
554 _gnutls_io_write_buffered (gnutls_session_t session
,
555 mbuffer_st
* bufel
, unsigned int mflag
)
557 mbuffer_head_st
*const send_buffer
= &session
->internals
.record_send_buffer
;
559 /* to know where the procedure was interrupted.
561 session
->internals
.direction
= 1;
563 _mbuffer_enqueue (send_buffer
, bufel
);
566 ("WRITE: enqueued %d bytes for %p. Total %d bytes.\n",
567 (int) bufel
->msg
.size
, session
->internals
.transport_recv_ptr
,
568 (int) send_buffer
->byte_length
);
570 if (mflag
== MBUFFER_FLUSH
)
571 return _gnutls_io_write_flush (session
);
573 return bufel
->msg
.size
;
576 typedef ssize_t (*send_func
) (gnutls_session_t
, const giovec_t
*, int);
578 /* This function writes the data that are left in the
579 * TLS write buffer (ie. because the previous write was
583 _gnutls_io_write_flush (gnutls_session_t session
)
586 mbuffer_head_st
*send_buffer
= &session
->internals
.record_send_buffer
;
588 ssize_t sent
= 0, tosend
= 0;
589 giovec_t iovec
[MAX_QUEUE
];
593 _gnutls_write_log ("WRITE FLUSH: %d bytes in buffer.\n",
594 (int) send_buffer
->byte_length
);
596 for (cur
= _mbuffer_head_get_first (send_buffer
, &msg
);
597 cur
!= NULL
; cur
= _mbuffer_head_get_next (cur
, &msg
))
599 iovec
[i
].iov_base
= msg
.data
;
600 iovec
[i
++].iov_len
= msg
.size
;
603 /* we buffer up to MAX_QUEUE messages */
607 return GNUTLS_E_INTERNAL_ERROR
;
617 ret
= _gnutls_writev (session
, iovec
, i
);
620 _mbuffer_head_remove_bytes (send_buffer
, ret
);
621 _gnutls_write_log ("WRITE: wrote %d bytes, %d bytes left.\n",
622 ret
, (int) send_buffer
->byte_length
);
626 else if (ret
== GNUTLS_E_INTERRUPTED
|| ret
== GNUTLS_E_AGAIN
)
628 _gnutls_write_log ("WRITE interrupted: %d bytes left.\n",
629 (int) send_buffer
->byte_length
);
632 else if (ret
== GNUTLS_E_LARGE_PACKET
)
634 _mbuffer_head_remove_bytes (send_buffer
, tosend
);
635 _gnutls_write_log ("WRITE cannot send large packet (%u bytes).\n",
636 (unsigned int) tosend
);
641 _gnutls_write_log ("WRITE error: code %d, %d bytes left.\n",
642 ret
, (int) send_buffer
->byte_length
);
650 return gnutls_assert_val(GNUTLS_E_AGAIN
);
656 /* Checks whether there are received data within
659 * Returns 0 if data were received, GNUTLS_E_TIMEDOUT
660 * on timeout and a negative error code on error.
663 _gnutls_io_check_recv (gnutls_session_t session
, unsigned int ms
)
665 gnutls_transport_ptr_t fd
= session
->internals
.transport_send_ptr
;
668 if (session
->internals
.pull_timeout_func
== system_recv_timeout
&&
669 session
->internals
.pull_func
!= system_read
)
670 return gnutls_assert_val(GNUTLS_E_PULL_ERROR
);
672 reset_errno (session
);
674 ret
= session
->internals
.pull_timeout_func(fd
, ms
);
677 err
= get_errno (session
);
678 _gnutls_read_log ("READ_TIMEOUT: %d returned from %p, errno=%d (timeout: %u)\n",
679 (int) ret
, fd
, err
, ms
);
680 return errno_to_gerr(err
);
685 else return GNUTLS_E_TIMEDOUT
;
688 /* HANDSHAKE buffers part
691 /* This function writes the data that are left in the
692 * Handshake write buffer (ie. because the previous write was
697 _gnutls_handshake_io_write_flush (gnutls_session_t session
)
699 mbuffer_head_st
*const send_buffer
=
700 &session
->internals
.handshake_send_buffer
;
707 _gnutls_write_log ("HWRITE FLUSH: %d bytes in buffer.\n",
708 (int) send_buffer
->byte_length
);
710 if (IS_DTLS(session
))
711 return _dtls_transmit(session
);
713 for (cur
= _mbuffer_head_get_first (send_buffer
, &msg
);
714 cur
!= NULL
; cur
= _mbuffer_head_get_first (send_buffer
, &msg
))
718 ret
= _gnutls_send_int (session
, cur
->type
,
721 msg
.data
, msg
.size
, 0);
727 ret
= _mbuffer_head_remove_bytes (send_buffer
, ret
);
729 _gnutls_epoch_refcount_dec(session
, epoch
);
731 _gnutls_write_log ("HWRITE: wrote %d bytes, %d bytes left.\n",
732 ret
, (int) send_buffer
->byte_length
);
737 _gnutls_write_log ("HWRITE error: code %d, %d bytes left.\n",
738 ret
, (int) send_buffer
->byte_length
);
745 return _gnutls_io_write_flush (session
);
749 /* This is a send function for the gnutls handshake
750 * protocol. Just makes sure that all data have been sent.
754 _gnutls_handshake_io_cache_int (gnutls_session_t session
,
755 gnutls_handshake_description_t htype
,
758 mbuffer_head_st
* send_buffer
;
760 if (IS_DTLS(session
))
762 bufel
->handshake_sequence
= session
->internals
.dtls
.hsk_write_seq
-1;
766 &session
->internals
.handshake_send_buffer
;
768 bufel
->epoch
= (uint16_t)_gnutls_epoch_refcount_inc(session
, EPOCH_WRITE_CURRENT
);
769 bufel
->htype
= htype
;
770 if (bufel
->htype
== GNUTLS_HANDSHAKE_CHANGE_CIPHER_SPEC
)
771 bufel
->type
= GNUTLS_CHANGE_CIPHER_SPEC
;
773 bufel
->type
= GNUTLS_HANDSHAKE
;
775 _mbuffer_enqueue (send_buffer
, bufel
);
778 ("HWRITE: enqueued [%s] %d. Total %d bytes.\n",
779 _gnutls_handshake2str (bufel
->htype
), (int) bufel
->msg
.size
, (int) send_buffer
->byte_length
);
784 static int handshake_compare(const void* _e1
, const void* _e2
)
786 const handshake_buffer_st
* e1
= _e1
;
787 const handshake_buffer_st
* e2
= _e2
;
789 if (e1
->sequence
<= e2
->sequence
)
795 #define SSL2_HEADERS 1
797 parse_handshake_header (gnutls_session_t session
, mbuffer_st
* bufel
,
798 handshake_buffer_st
* hsk
)
800 uint8_t *dataptr
= NULL
; /* for realloc */
801 size_t handshake_header_size
= HANDSHAKE_HEADER_SIZE(session
), data_size
;
803 /* Note: SSL2_HEADERS == 1 */
804 if (_mbuffer_get_udata_size(bufel
) < handshake_header_size
)
805 return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH
);
807 dataptr
= _mbuffer_get_udata_ptr(bufel
);
809 /* if reading a client hello of SSLv2 */
810 if (unlikely(!IS_DTLS(session
) && bufel
->htype
== GNUTLS_HANDSHAKE_CLIENT_HELLO_V2
))
812 handshake_header_size
= SSL2_HEADERS
; /* we've already read one byte */
814 hsk
->length
= _mbuffer_get_udata_size(bufel
) - handshake_header_size
; /* we've read the first byte */
816 if (dataptr
[0] != GNUTLS_HANDSHAKE_CLIENT_HELLO
)
817 return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET
);
819 hsk
->htype
= GNUTLS_HANDSHAKE_CLIENT_HELLO_V2
;
822 hsk
->start_offset
= 0;
823 hsk
->end_offset
= hsk
->length
;
825 else /* TLS or DTLS handshake headers */
828 hsk
->htype
= dataptr
[0];
830 /* we do not use DECR_LEN because we know
831 * that the packet has enough data.
833 hsk
->length
= _gnutls_read_uint24 (&dataptr
[1]);
834 handshake_header_size
= HANDSHAKE_HEADER_SIZE(session
);
836 if (IS_DTLS(session
))
838 hsk
->sequence
= _gnutls_read_uint16 (&dataptr
[4]);
839 hsk
->start_offset
= _gnutls_read_uint24 (&dataptr
[6]);
840 hsk
->end_offset
= hsk
->start_offset
+ _gnutls_read_uint24 (&dataptr
[9]);
845 hsk
->start_offset
= 0;
846 hsk
->end_offset
= MIN((_mbuffer_get_udata_size(bufel
) - handshake_header_size
), hsk
->length
);
849 data_size
= _mbuffer_get_udata_size(bufel
) - handshake_header_size
;
851 /* make the length offset */
852 if (hsk
->end_offset
> 0) hsk
->end_offset
--;
854 _gnutls_handshake_log ("HSK[%p]: %s (%u) was received. Length %d[%d], frag offset %d, frag length: %d, sequence: %d\n",
855 session
, _gnutls_handshake2str (hsk
->htype
), (unsigned)hsk
->htype
,
856 (int) hsk
->length
, (int)data_size
, hsk
->start_offset
, hsk
->end_offset
-hsk
->start_offset
+1, (int)hsk
->sequence
);
858 hsk
->header_size
= handshake_header_size
;
859 memcpy(hsk
->header
, _mbuffer_get_udata_ptr(bufel
), handshake_header_size
);
861 if (hsk
->length
> 0 &&
862 (hsk
->end_offset
-hsk
->start_offset
>= data_size
))
863 return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH
);
865 if (hsk
->length
> 0 && (hsk
->start_offset
>= hsk
->end_offset
||
866 hsk
->end_offset
-hsk
->start_offset
>= data_size
||
867 hsk
->end_offset
>= hsk
->length
))
868 return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH
);
869 else if (hsk
->length
== 0 && hsk
->end_offset
!= 0 && hsk
->start_offset
!= 0)
870 return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET_LENGTH
);
872 return handshake_header_size
;
875 static void _gnutls_handshake_buffer_move(handshake_buffer_st
* dst
, handshake_buffer_st
* src
)
877 memcpy(dst
, src
, sizeof(*dst
));
878 memset(src
, 0, sizeof(*src
));
882 /* will merge the given handshake_buffer_st to the handshake_recv_buffer
883 * list. The given hsk packet will be released in any case (success or failure).
886 static int merge_handshake_packet(gnutls_session_t session
, handshake_buffer_st
* hsk
)
888 int exists
= 0, i
, pos
= 0;
891 for (i
=0;i
<session
->internals
.handshake_recv_buffer_size
;i
++)
893 if (session
->internals
.handshake_recv_buffer
[i
].htype
== hsk
->htype
)
902 pos
= session
->internals
.handshake_recv_buffer_size
;
904 if (pos
> MAX_HANDSHAKE_MSGS
)
905 return gnutls_assert_val(GNUTLS_E_TOO_MANY_HANDSHAKE_PACKETS
);
909 if (hsk
->length
> 0 && hsk
->end_offset
> 0 && hsk
->end_offset
-hsk
->start_offset
+1 != hsk
->length
)
911 ret
= _gnutls_buffer_resize(&hsk
->data
, hsk
->length
);
913 return gnutls_assert_val(ret
);
915 hsk
->data
.length
= hsk
->length
;
917 memmove(&hsk
->data
.data
[hsk
->start_offset
], hsk
->data
.data
, hsk
->end_offset
-hsk
->start_offset
+1);
920 session
->internals
.handshake_recv_buffer_size
++;
922 /* rewrite headers to make them look as each packet came as a single fragment */
923 _gnutls_write_uint24(hsk
->length
, &hsk
->header
[1]);
924 _gnutls_write_uint24(0, &hsk
->header
[6]);
925 _gnutls_write_uint24(hsk
->length
, &hsk
->header
[9]);
927 _gnutls_handshake_buffer_move(&session
->internals
.handshake_recv_buffer
[pos
], hsk
);
932 if (hsk
->start_offset
< session
->internals
.handshake_recv_buffer
[pos
].start_offset
&&
933 hsk
->end_offset
>= session
->internals
.handshake_recv_buffer
[pos
].start_offset
)
935 memcpy(&session
->internals
.handshake_recv_buffer
[pos
].data
.data
[hsk
->start_offset
],
936 hsk
->data
.data
, hsk
->data
.length
);
937 session
->internals
.handshake_recv_buffer
[pos
].start_offset
= hsk
->start_offset
;
938 session
->internals
.handshake_recv_buffer
[pos
].end_offset
=
939 MIN(hsk
->end_offset
, session
->internals
.handshake_recv_buffer
[pos
].end_offset
);
941 else if (hsk
->end_offset
> session
->internals
.handshake_recv_buffer
[pos
].end_offset
&&
942 hsk
->start_offset
<= session
->internals
.handshake_recv_buffer
[pos
].end_offset
+1)
944 memcpy(&session
->internals
.handshake_recv_buffer
[pos
].data
.data
[hsk
->start_offset
],
945 hsk
->data
.data
, hsk
->data
.length
);
947 session
->internals
.handshake_recv_buffer
[pos
].end_offset
= hsk
->end_offset
;
948 session
->internals
.handshake_recv_buffer
[pos
].start_offset
=
949 MIN(hsk
->start_offset
, session
->internals
.handshake_recv_buffer
[pos
].start_offset
);
951 _gnutls_handshake_buffer_clear(hsk
);
957 /* returns non-zero on match and zero on mismatch
959 inline static int cmp_hsk_types(gnutls_handshake_description_t expected
, gnutls_handshake_description_t recvd
)
961 if ((expected
!= GNUTLS_HANDSHAKE_CLIENT_HELLO
|| recvd
!= GNUTLS_HANDSHAKE_CLIENT_HELLO_V2
) &&
968 #define LAST_ELEMENT (session->internals.handshake_recv_buffer_size-1)
970 /* returns the last stored handshake packet.
972 static int get_last_packet(gnutls_session_t session
, gnutls_handshake_description_t htype
,
973 handshake_buffer_st
* hsk
, unsigned int optional
)
975 handshake_buffer_st
* recv_buf
= session
->internals
.handshake_recv_buffer
;
977 if (IS_DTLS(session
))
979 if (session
->internals
.handshake_recv_buffer_size
== 0 ||
980 (session
->internals
.dtls
.hsk_read_seq
!= recv_buf
[LAST_ELEMENT
].sequence
))
983 if (htype
!= recv_buf
[LAST_ELEMENT
].htype
)
986 _gnutls_audit_log(session
, "Received unexpected handshake message '%s' (%d). Expected '%s' (%d)\n",
987 _gnutls_handshake2str(recv_buf
[0].htype
), (int)recv_buf
[0].htype
, _gnutls_handshake2str(htype
), (int)htype
);
989 return gnutls_assert_val(GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET
);
992 else if ((recv_buf
[LAST_ELEMENT
].start_offset
== 0 &&
993 recv_buf
[LAST_ELEMENT
].end_offset
== recv_buf
[LAST_ELEMENT
].length
-1) ||
994 recv_buf
[LAST_ELEMENT
].length
== 0)
996 session
->internals
.dtls
.hsk_read_seq
++;
997 _gnutls_handshake_buffer_move(hsk
, &recv_buf
[LAST_ELEMENT
]);
998 session
->internals
.handshake_recv_buffer_size
--;
1006 if (session
->internals
.handshake_recv_buffer_size
> 0 && recv_buf
[0].length
== recv_buf
[0].data
.length
)
1008 if (cmp_hsk_types(htype
, recv_buf
[0].htype
) == 0)
1010 return gnutls_assert_val(GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET
);
1013 _gnutls_handshake_buffer_move(hsk
, &recv_buf
[0]);
1014 session
->internals
.handshake_recv_buffer_size
--;
1018 return gnutls_assert_val(GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
);
1022 RETURN_DTLS_EAGAIN_OR_TIMEOUT(session
, 0);
1025 /* This is a receive function for the gnutls handshake
1026 * protocol. Makes sure that we have received all data.
1028 * htype is the next handshake packet expected.
1031 _gnutls_parse_record_buffered_msgs (gnutls_session_t session
)
1034 mbuffer_st
* bufel
= NULL
, *prev
= NULL
;
1037 handshake_buffer_st
* recv_buf
= session
->internals
.handshake_recv_buffer
;
1039 bufel
= _mbuffer_head_get_first(&session
->internals
.record_buffer
, &msg
);
1041 return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
;
1043 if (!IS_DTLS(session
))
1045 ssize_t remain
, append
, header_size
;
1049 if (bufel
->type
!= GNUTLS_HANDSHAKE
)
1050 return gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET
);
1052 /* if we have a half received message the complete it.
1054 remain
= recv_buf
[0].length
-
1055 recv_buf
[0].data
.length
;
1057 /* this is the rest of a previous message */
1058 if (session
->internals
.handshake_recv_buffer_size
> 0 && recv_buf
[0].length
> 0 && remain
> 0)
1060 if ((ssize_t
)msg
.size
<= remain
)
1065 ret
= _gnutls_buffer_append_data(&recv_buf
[0].data
, msg
.data
, append
);
1067 return gnutls_assert_val(ret
);
1069 _mbuffer_head_remove_bytes(&session
->internals
.record_buffer
, append
);
1071 else /* received new message */
1073 ret
= parse_handshake_header(session
, bufel
, &recv_buf
[0]);
1075 return gnutls_assert_val(ret
);
1078 session
->internals
.handshake_recv_buffer_size
= 1;
1080 _mbuffer_set_uhead_size(bufel
, header_size
);
1082 data_size
= MIN(recv_buf
[0].length
, _mbuffer_get_udata_size(bufel
));
1083 ret
= _gnutls_buffer_append_data(&recv_buf
[0].data
, _mbuffer_get_udata_ptr(bufel
), data_size
);
1085 return gnutls_assert_val(ret
);
1086 _mbuffer_set_uhead_size(bufel
, 0);
1087 _mbuffer_head_remove_bytes(&session
->internals
.record_buffer
, data_size
+header_size
);
1090 /* if packet is complete then return it
1092 if (recv_buf
[0].length
==
1093 recv_buf
[0].data
.length
)
1097 bufel
= _mbuffer_head_get_first(&session
->internals
.record_buffer
, &msg
);
1099 while(bufel
!= NULL
);
1101 /* if we are here it means that the received packets were not
1102 * enough to complete the handshake packet.
1104 return gnutls_assert_val(GNUTLS_E_AGAIN
);
1108 handshake_buffer_st tmp
;
1114 * 1. insert to handshake_recv_buffer
1115 * 2. sort handshake_recv_buffer on sequence numbers
1116 * 3. return first packet if completed or GNUTLS_E_AGAIN.
1120 if (bufel
->type
!= GNUTLS_HANDSHAKE
)
1123 goto next
; /* ignore packet */
1126 _gnutls_handshake_buffer_init(&tmp
);
1128 ret
= parse_handshake_header(session
, bufel
, &tmp
);
1132 _gnutls_audit_log(session
, "Invalid handshake packet headers. Discarding.\n");
1136 _mbuffer_consume(&session
->internals
.record_buffer
, bufel
, ret
);
1138 data_size
= MIN(tmp
.length
, tmp
.end_offset
-tmp
.start_offset
+1);
1140 ret
= _gnutls_buffer_append_data(&tmp
.data
, _mbuffer_get_udata_ptr(bufel
), data_size
);
1142 return gnutls_assert_val(ret
);
1144 _mbuffer_consume(&session
->internals
.record_buffer
, bufel
, data_size
);
1146 ret
= merge_handshake_packet(session
, &tmp
);
1148 return gnutls_assert_val(ret
);
1151 while(_mbuffer_get_udata_size(bufel
) > 0);
1154 bufel
= _mbuffer_dequeue(&session
->internals
.record_buffer
, bufel
);
1156 _mbuffer_xfree(&prev
);
1160 bufel
= _mbuffer_head_get_next(bufel
, NULL
);
1162 while(bufel
!= NULL
);
1164 /* sort in descending order */
1165 if (session
->internals
.handshake_recv_buffer_size
> 1)
1166 qsort(recv_buf
, session
->internals
.handshake_recv_buffer_size
,
1167 sizeof(recv_buf
[0]), handshake_compare
);
1169 while(session
->internals
.handshake_recv_buffer_size
> 0 &&
1170 recv_buf
[LAST_ELEMENT
].sequence
< session
->internals
.dtls
.hsk_read_seq
)
1172 _gnutls_audit_log(session
, "Discarded replayed handshake packet with sequence %d\n", recv_buf
[LAST_ELEMENT
].sequence
);
1173 _gnutls_handshake_buffer_clear(&recv_buf
[LAST_ELEMENT
]);
1174 session
->internals
.handshake_recv_buffer_size
--;
1181 /* This is a receive function for the gnutls handshake
1182 * protocol. Makes sure that we have received all data.
1185 _gnutls_handshake_io_recv_int (gnutls_session_t session
,
1186 gnutls_handshake_description_t htype
,
1187 handshake_buffer_st
* hsk
, unsigned int optional
)
1190 unsigned int tleft
= 0;
1192 ret
= get_last_packet(session
, htype
, hsk
, optional
);
1193 if (ret
!= GNUTLS_E_AGAIN
&& ret
!= GNUTLS_E_INTERRUPTED
&& ret
!= GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
)
1195 return gnutls_assert_val(ret
);
1198 /* try using the already existing records before
1199 * trying to receive.
1201 ret
= _gnutls_parse_record_buffered_msgs(session
);
1203 if (ret
== 0) ret
= get_last_packet(session
, htype
, hsk
, optional
);
1205 if (IS_DTLS(session
))
1212 if ((ret
!= GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE
&& ret
< 0) || ret
>= 0)
1213 return gnutls_assert_val(ret
);
1216 if (htype
!= (unsigned)-1)
1218 ret
= handshake_remaining_time(session
);
1220 return gnutls_assert_val(ret
);
1224 /* if we don't have a complete message waiting for us, try
1226 ret
= _gnutls_recv_in_buffers(session
, GNUTLS_HANDSHAKE
, htype
, tleft
);
1228 return gnutls_assert_val_fatal(ret
);
1230 ret
= _gnutls_parse_record_buffered_msgs(session
);
1231 if (ret
== 0) ret
= get_last_packet(session
, htype
, hsk
, optional
);