Add `gnutls/dtls.h' to the distribution.
[gnutls.git] / lib / gnutls_buffers.c
blob33c6c6661e719868e3fc8e76a39636c780e0012e
1 /*
2 * Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
3 * 2009, 2010 Free Software Foundation, Inc.
5 * Author: Nikos Mavrogiannopoulos
7 * This file is part of GnuTLS.
9 * The GnuTLS is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public License
11 * as published by the Free Software Foundation; either version 2.1 of
12 * the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
22 * USA
26 /* This is the only file that uses the berkeley sockets API.
28 * Also holds all the buffering code used in gnutls.
29 * The buffering code works as:
31 * RECORD LAYER:
32 * 1. uses a buffer to hold data (application/handshake),
33 * we got but they were not requested, yet.
34 * (see gnutls_record_buffer_put(), gnutls_record_buffer_get_size() etc.)
36 * 2. uses a buffer to hold data that were incomplete (ie the read/write
37 * was interrupted)
38 * (see _gnutls_io_read_buffered(), _gnutls_io_write_buffered() etc.)
40 * HANDSHAKE LAYER:
41 * 1. Uses a buffer to hold data that was not sent or received
42 * complete. (E.g. sent 10 bytes of a handshake packet that is 20 bytes
43 * long).
44 * (see _gnutls_handshake_send_int(), _gnutls_handshake_recv_int())
46 * 2. Uses buffer to hold the last received handshake message.
47 * (see _gnutls_handshake_buffer_put() etc.)
51 #include <gnutls_int.h>
52 #include <gnutls_errors.h>
53 #include <gnutls_num.h>
54 #include <gnutls_record.h>
55 #include <gnutls_buffers.h>
56 #include <gnutls_mbuffers.h>
57 #include <gnutls_state.h>
58 #include <gnutls_dtls.h>
59 #include <system.h>
60 #include <gnutls_constate.h> /* gnutls_epoch_get */
61 #include <errno.h>
63 #ifndef EAGAIN
64 #define EAGAIN EWOULDBLOCK
65 #endif
67 /* this is the maximum number of messages allowed to queue.
69 #define MAX_QUEUE 16
71 /* Buffers received packets of type APPLICATION DATA and
72 * HANDSHAKE DATA.
74 int
75 _gnutls_record_buffer_put (content_type_t type,
76 gnutls_session_t session, opaque * data,
77 size_t length)
79 gnutls_buffer_st *buf;
81 if (length == 0)
82 return 0;
84 switch (type)
86 case GNUTLS_APPLICATION_DATA:
87 buf = &session->internals.application_data_buffer;
88 _gnutls_buffers_log ("BUF[REC]: Inserted %d bytes of Data(%d)\n",
89 (int) length, (int) type);
90 break;
92 case GNUTLS_HANDSHAKE:
93 buf = &session->internals.handshake_data_buffer;
94 _gnutls_buffers_log ("BUF[HSK]: Inserted %d bytes of Data(%d)\n",
95 (int) length, (int) type);
96 break;
98 case GNUTLS_INNER_APPLICATION:
99 buf = &session->internals.ia_data_buffer;
100 _gnutls_buffers_log ("BUF[IA]: Inserted %d bytes of Data(%d)\n",
101 (int) length, (int) type);
102 break;
104 default:
105 gnutls_assert ();
106 return GNUTLS_E_INVALID_REQUEST;
109 if (_gnutls_buffer_append_data (buf, data, length) < 0)
111 gnutls_assert ();
112 return GNUTLS_E_MEMORY_ERROR;
115 return 0;
119 _gnutls_record_buffer_get_size (content_type_t type, gnutls_session_t session)
121 switch (type)
123 case GNUTLS_APPLICATION_DATA:
124 return session->internals.application_data_buffer.length;
126 case GNUTLS_HANDSHAKE:
127 return session->internals.handshake_data_buffer.length;
129 case GNUTLS_INNER_APPLICATION:
130 return session->internals.ia_data_buffer.length;
132 default:
133 return GNUTLS_E_INVALID_REQUEST;
138 * gnutls_record_check_pending:
139 * @session: is a #gnutls_session_t structure.
141 * This function checks if there are any data to receive in the gnutls
142 * buffers.
144 * Note that you could also use select() to check for data in a TCP
145 * connection, instead of this function. GnuTLS leaves some data in
146 * the tcp buffer in order for select to work. However the select()
147 * alternative is not recommended and will be deprecated in later
148 * GnuTLS revisions.
150 * Returns: the size of that data or 0.
152 size_t
153 gnutls_record_check_pending (gnutls_session_t session)
155 return _gnutls_record_buffer_get_size (GNUTLS_APPLICATION_DATA, session);
159 _gnutls_record_buffer_get (content_type_t type,
160 gnutls_session_t session, opaque * data,
161 size_t length)
163 if (length == 0 || data == NULL)
165 gnutls_assert ();
166 return GNUTLS_E_INVALID_REQUEST;
169 switch (type)
171 case GNUTLS_APPLICATION_DATA:
172 _gnutls_buffer_pop_data (&session->internals.application_data_buffer,
173 data, &length);
174 _gnutls_buffers_log ("BUFFER[REC][AD]: Read %d bytes of Data(%d)\n",
175 (int) length, (int) type);
176 break;
178 case GNUTLS_HANDSHAKE:
179 _gnutls_buffer_pop_data (&session->internals.handshake_data_buffer,
180 data, &length);
181 _gnutls_buffers_log ("BUF[REC][HD]: Read %d bytes of Data(%d)\n",
182 (int) length, (int) type);
183 break;
185 case GNUTLS_INNER_APPLICATION:
187 _gnutls_buffer_pop_data (&session->internals.ia_data_buffer, data,
188 &length);
189 _gnutls_buffers_log ("BUF[REC][IA]: Read %d bytes of Data(%d)\n",
190 (int) length, (int) type);
191 break;
193 default:
194 gnutls_assert ();
195 return GNUTLS_E_INVALID_REQUEST;
199 return length;
202 inline static void
203 reset_errno (gnutls_session_t session)
205 session->internals.errnum = 0;
208 inline static int
209 get_errno (gnutls_session_t session)
211 if (session->internals.errnum != 0)
212 return session->internals.errnum;
213 else
214 return session->internals.errno_func (session->
215 internals.transport_recv_ptr);
219 static ssize_t
220 _gnutls_dgram_read (gnutls_session_t session, mbuffer_st **bufel,
221 gnutls_pull_func pull_func)
223 ssize_t i, ret;
224 char *ptr;
225 gnutls_transport_ptr_t fd = session->internals.transport_recv_ptr;
227 if (!bufel)
229 gnutls_assert ();
230 return GNUTLS_E_INTERNAL_ERROR;
233 ptr = gnutls_malloc(MAX_RECV_SIZE(session));
234 if (ptr == NULL)
235 return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
237 session->internals.direction = 0;
239 reset_errno (session);
241 i = pull_func (fd, ptr, MAX_RECV_SIZE(session));
243 if (i < 0)
245 int err = get_errno (session);
247 _gnutls_read_log ("READ: %d returned from %p, errno=%d gerrno=%d\n",
248 (int) i, fd, errno, session->internals.errnum);
250 if (err == EAGAIN)
252 ret = GNUTLS_E_AGAIN;
253 goto cleanup;
255 else if (err == EINTR)
257 ret = GNUTLS_E_INTERRUPTED;
258 goto cleanup;
260 else
262 gnutls_assert ();
263 ret = GNUTLS_E_PULL_ERROR;
264 goto cleanup;
267 else
269 _gnutls_read_log ("READ: Got %d bytes from %p\n", (int) i, fd);
270 if (i == 0) {
271 /* If we get here, we likely have a stream socket.
272 * FIXME: this probably breaks DCCP. */
273 gnutls_assert ();
274 ret = GNUTLS_E_INTERNAL_ERROR;
275 goto cleanup;
278 *bufel = _mbuffer_alloc (0, i);
279 if (!*bufel)
281 gnutls_assert ();
282 ret = GNUTLS_E_MEMORY_ERROR;
283 goto cleanup;
286 _mbuffer_append_data (*bufel, ptr, i);
289 _gnutls_read_log ("READ: read %d bytes from %p\n", (int) i, fd);
291 ret = i;
293 cleanup:
294 gnutls_free(ptr);
295 return ret;
298 static ssize_t
299 _gnutls_stream_read (gnutls_session_t session, mbuffer_st **bufel,
300 size_t size, gnutls_pull_func pull_func)
302 size_t left;
303 ssize_t i = 0;
304 char *ptr;
305 gnutls_transport_ptr_t fd = session->internals.transport_recv_ptr;
307 if (!bufel)
309 gnutls_assert ();
310 return GNUTLS_E_INTERNAL_ERROR;
313 *bufel = _mbuffer_alloc (0, size);
314 if (!*bufel)
316 gnutls_assert ();
317 return GNUTLS_E_MEMORY_ERROR;
319 ptr = (*bufel)->msg.data;
321 session->internals.direction = 0;
323 left = size;
324 while (left > 0)
326 reset_errno (session);
328 i = pull_func (fd, &ptr[size - left], left);
330 if (i < 0)
332 int err = get_errno (session);
334 _gnutls_read_log ("READ: %d returned from %p, errno=%d gerrno=%d\n",
335 (int) i, fd, errno, session->internals.errnum);
337 if (err == EAGAIN || err == EINTR)
339 if (size - left > 0)
342 _gnutls_read_log ("READ: returning %d bytes from %p\n",
343 (int) (size - left), fd);
345 goto finish;
348 if (err == EAGAIN)
349 return GNUTLS_E_AGAIN;
350 return GNUTLS_E_INTERRUPTED;
352 else
354 gnutls_assert ();
355 return GNUTLS_E_PULL_ERROR;
358 else
361 _gnutls_read_log ("READ: Got %d bytes from %p\n", (int) i, fd);
363 if (i == 0)
364 break; /* EOF */
367 left -= i;
368 (*bufel)->msg.size += i;
371 finish:
373 _gnutls_read_log ("READ: read %d bytes from %p\n",
374 (int) (size - left), fd);
376 return (size - left);
380 /* This function is like read. But it does not return -1 on error.
381 * It does return gnutls_errno instead.
383 * Flags are only used if the default recv() function is being used.
385 static ssize_t
386 _gnutls_read (gnutls_session_t session, mbuffer_st **bufel,
387 size_t size, gnutls_pull_func pull_func)
389 if (_gnutls_is_dtls (session))
390 /* Size is not passed, since a whole datagram will be read. */
391 return _gnutls_dgram_read (session, bufel, pull_func);
392 else
393 return _gnutls_stream_read (session, bufel, size, pull_func);
396 static ssize_t
397 _gnutls_writev_emu (gnutls_session_t session, const giovec_t * giovec,
398 int giovec_cnt)
400 int ret, j = 0;
401 gnutls_transport_ptr_t fd = session->internals.transport_send_ptr;
402 size_t total = 0;
404 for (j = 0; j < giovec_cnt; j++)
406 ret = session->internals.push_func (fd, giovec[j].iov_base, giovec[j].iov_len);
408 if (ret == -1)
409 break;
411 total += ret;
414 if (total > 0)
415 return total;
417 return ret;
420 static ssize_t
421 _gnutls_writev (gnutls_session_t session, const giovec_t * giovec,
422 int giovec_cnt)
424 int i;
425 gnutls_transport_ptr_t fd = session->internals.transport_send_ptr;
427 reset_errno (session);
429 if (session->internals.push_func != NULL)
430 i = _gnutls_writev_emu (session, giovec, giovec_cnt);
431 else
432 i = session->internals.vec_push_func (fd, giovec, giovec_cnt);
434 if (i == -1)
436 int err = get_errno (session);
437 _gnutls_debug_log ("errno: %d\n", err);
438 if (err == EAGAIN)
439 return GNUTLS_E_AGAIN;
440 else if (err == EINTR)
441 return GNUTLS_E_INTERRUPTED;
442 else
444 gnutls_assert ();
445 return GNUTLS_E_PUSH_ERROR;
448 return i;
451 #define RCVLOWAT session->internals.lowat
453 /* This function is only used with berkeley style sockets.
454 * Clears the peeked data (read with MSG_PEEK).
457 _gnutls_io_clear_peeked_data (gnutls_session_t session)
459 mbuffer_st *peekdata;
460 int ret, sum;
462 if (session->internals.have_peeked_data == 0 || RCVLOWAT == 0)
463 return 0;
465 /* this was already read by using MSG_PEEK - so it shouldn't fail */
466 sum = 0;
468 { /* we need this to finish now */
469 ret =
470 _gnutls_read (session, &peekdata, RCVLOWAT - sum,
471 session->internals.pull_func);
472 if (ret > 0)
473 sum += ret;
474 _mbuffer_xfree (&peekdata);
476 while (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN
477 || sum < RCVLOWAT);
479 if (ret < 0)
481 gnutls_assert ();
482 return ret;
485 session->internals.have_peeked_data = 0;
487 return 0;
490 /* This function is like recv(with MSG_PEEK). But it does not return -1 on error.
491 * It does return gnutls_errno instead.
492 * This function reads data from the socket and keeps them in a buffer, of up to
493 * MAX_RECV_SIZE.
495 * This is not a general purpose function. It returns EXACTLY the data requested,
496 * which are stored in a local (in the session) buffer.
499 ssize_t
500 _gnutls_io_read_buffered (gnutls_session_t session, size_t total,
501 content_type_t recv_type)
503 ssize_t ret = 0, ret2 = 0;
504 size_t min;
505 mbuffer_st *bufel = NULL;
506 size_t recvlowat, recvdata, readsize;
508 if (total > MAX_RECV_SIZE(session) || total == 0)
510 gnutls_assert (); /* internal error */
511 return GNUTLS_E_INVALID_REQUEST;
514 /* If an external pull function is used, then do not leave
515 * any data into the kernel buffer.
517 if (session->internals.pull_func != system_read)
519 recvlowat = 0;
521 else
523 /* leave peeked data to the kernel space only if application data
524 * is received and we don't have any peeked
525 * data in gnutls session.
527 if (recv_type != GNUTLS_APPLICATION_DATA
528 && session->internals.have_peeked_data == 0)
529 recvlowat = 0;
530 else
531 recvlowat = RCVLOWAT;
536 /* calculate the actual size, ie. get the minimum of the
537 * buffered data and the requested data.
539 min = MIN (session->internals.record_recv_buffer.byte_length, total);
540 if (min > 0)
542 /* if we have enough buffered data
543 * then just return them.
545 if (min == total)
547 return min;
551 if(_gnutls_is_dtls(session)
552 && session->internals.record_recv_buffer.byte_length != 0)
554 /* Attempt to read across records while using DTLS. */
555 gnutls_assert();
556 return GNUTLS_E_INVALID_REQUEST;
559 /* min is over zero. recvdata is the data we must
560 * receive in order to return the requested data.
562 recvdata = total - min;
563 readsize = recvdata - recvlowat;
565 /* Check if the previously read data plus the new data to
566 * receive are longer than the maximum receive buffer size.
568 if ((session->internals.record_recv_buffer.byte_length + recvdata) >
569 MAX_RECV_SIZE(session))
571 gnutls_assert (); /* internal error */
572 return GNUTLS_E_INVALID_REQUEST;
575 if (ret < 0)
577 gnutls_assert ();
578 return ret;
581 /* READ DATA - but leave RCVLOWAT bytes in the kernel buffer.
583 if (readsize > 0)
585 ret =
586 _gnutls_read (session, &bufel, readsize,
587 session->internals.pull_func);
589 /* return immediately if we got an interrupt or eagain
590 * error.
592 if (ret < 0 && gnutls_error_is_fatal (ret) == 0)
594 _mbuffer_xfree (&bufel);
595 return ret;
599 /* copy fresh data to our buffer.
601 if (ret > 0)
603 _gnutls_read_log
604 ("RB: Have %d bytes into buffer. Adding %d bytes.\n",
605 (int) session->internals.record_recv_buffer.byte_length, (int) ret);
606 _gnutls_read_log ("RB: Requested %d bytes\n", (int) total);
608 _mbuffer_enqueue (&session->internals.record_recv_buffer, bufel);
610 else
611 _mbuffer_xfree (&bufel);
614 /* This is hack in order for select to work. Just leave recvlowat data,
615 * into the kernel buffer (using a read with MSG_PEEK), thus making
616 * select think, that the socket is ready for reading.
617 * MSG_PEEK is only used with berkeley style sockets.
619 if (ret == readsize && recvlowat > 0 && !_gnutls_is_dtls(session) &&
620 session->internals.pull_func == system_read)
622 ret2 = _gnutls_read (session, &bufel, recvlowat, system_read_peek);
624 if (ret2 < 0 && gnutls_error_is_fatal (ret2) == 0)
626 _mbuffer_xfree (&bufel);
627 return ret2;
630 if (ret2 > 0)
632 _gnutls_read_log ("RB-PEEK: Read %d bytes in PEEK MODE.\n",
633 (int) ret2);
634 _gnutls_read_log
635 ("RB-PEEK: Have %d bytes into buffer. Adding %d bytes.\nRB: Requested %d bytes\n",
636 (int) session->internals.record_recv_buffer.byte_length,
637 (int) ret2, (int) total);
638 session->internals.have_peeked_data = 1;
639 _mbuffer_enqueue (&session->internals.record_recv_buffer, bufel);
641 else
642 _mbuffer_xfree (&bufel);
645 if (ret < 0 || ret2 < 0)
647 gnutls_assert ();
648 /* that's because they are initialized to 0 */
649 return MIN (ret, ret2);
652 ret += ret2;
654 if (ret > 0 && ret < recvlowat)
656 gnutls_assert ();
657 return GNUTLS_E_AGAIN;
660 if (ret == 0)
661 { /* EOF */
662 gnutls_assert ();
663 return 0;
666 if(_gnutls_is_dtls(session))
667 ret = MIN(total, session->internals.record_recv_buffer.byte_length);
668 else
669 ret = session->internals.record_recv_buffer.byte_length;
671 if ((ret > 0) && ((size_t) ret < total))
673 /* Short Read */
674 gnutls_assert ();
675 return GNUTLS_E_AGAIN;
677 else
679 return ret;
683 /* This function is like write. But it does not return -1 on error.
684 * It does return gnutls_errno instead.
686 * This function takes full responsibility of freeing msg->data.
688 * In case of E_AGAIN and E_INTERRUPTED errors, you must call
689 * gnutls_write_flush(), until it returns ok (0).
691 * We need to push exactly the data in msg->size, since we cannot send
692 * less data. In TLS the peer must receive the whole packet in order
693 * to decrypt and verify the integrity.
696 ssize_t
697 _gnutls_io_write_buffered (gnutls_session_t session,
698 mbuffer_st * bufel, unsigned int mflag)
700 mbuffer_head_st *const send_buffer = &session->internals.record_send_buffer;
702 _mbuffer_enqueue (send_buffer, bufel);
704 _gnutls_write_log
705 ("WRITE: enqueued %d bytes for %p. Total %d bytes.\n",
706 (int) bufel->msg.size, session->internals.transport_recv_ptr,
707 (int) send_buffer->byte_length);
709 if (mflag == MBUFFER_FLUSH)
710 return _gnutls_io_write_flush (session);
711 else
712 return bufel->msg.size;
715 typedef ssize_t (*send_func) (gnutls_session_t, const giovec_t *, int);
717 /* This function writes the data that are left in the
718 * TLS write buffer (ie. because the previous write was
719 * interrupted.
721 ssize_t
722 _gnutls_io_write_flush (gnutls_session_t session)
724 gnutls_datum_t msg;
725 mbuffer_head_st *send_buffer = &session->internals.record_send_buffer;
726 int ret;
727 ssize_t sent = 0, tosend = 0;
728 giovec_t iovec[MAX_QUEUE];
729 int i = 0;
730 mbuffer_st *cur;
732 _gnutls_write_log ("WRITE FLUSH: %d bytes in buffer.\n",
733 (int) send_buffer->byte_length);
735 for (cur = _mbuffer_get_first (send_buffer, &msg);
736 cur != NULL; cur = _mbuffer_get_next (cur, &msg))
738 iovec[i].iov_base = msg.data;
739 iovec[i++].iov_len = msg.size;
740 tosend += msg.size;
742 /* we buffer up to MAX_QUEUE messages */
743 if (i >= sizeof (iovec) / sizeof (iovec[0]))
745 gnutls_assert ();
746 return GNUTLS_E_INTERNAL_ERROR;
750 ret = _gnutls_writev (session, iovec, i);
751 if (ret >= 0)
753 _mbuffer_remove_bytes (send_buffer, ret);
754 _gnutls_write_log ("WRITE: wrote %d bytes, %d bytes left.\n",
755 ret, (int) send_buffer->byte_length);
757 sent += ret;
759 else if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN)
761 _gnutls_write_log ("WRITE interrupted: %d bytes left.\n",
762 (int) send_buffer->byte_length);
763 return ret;
765 else
767 _gnutls_write_log ("WRITE error: code %d, %d bytes left.\n",
768 ret, (int) send_buffer->byte_length);
770 gnutls_assert ();
771 return ret;
774 if (sent < tosend)
776 gnutls_assert ();
777 return GNUTLS_E_AGAIN;
780 return sent;
783 #include "debug.h"
784 /* Checks whether there are received data within
785 * a timeframe.
787 * Returns 0 if data were received, GNUTLS_E_TIMEDOUT
788 * on timeout and a negative value on error.
791 _gnutls_io_check_recv (gnutls_session_t session, void* data, size_t data_size, unsigned int ms)
793 gnutls_transport_ptr_t fd = session->internals.transport_send_ptr;
794 int ret;
796 if (session->internals.pull_timeout_func == system_recv_timeout &&
797 session->internals.pull_func != system_read)
798 return gnutls_assert_val(GNUTLS_E_PULL_ERROR);
800 ret = session->internals.pull_timeout_func(fd, data, data_size, ms);
801 if (ret == -1)
802 return gnutls_assert_val(GNUTLS_E_PULL_ERROR);
804 if (ret > 0)
805 return 0;
806 else return GNUTLS_E_TIMEDOUT;
809 /* This function writes the data that are left in the
810 * Handshake write buffer (ie. because the previous write was
811 * interrupted.
814 ssize_t
815 _gnutls_handshake_io_write_flush (gnutls_session_t session)
817 mbuffer_head_st *const send_buffer =
818 &session->internals.handshake_send_buffer;
819 gnutls_datum_t msg;
820 int ret;
821 uint16_t epoch;
822 ssize_t total = 0;
823 mbuffer_st *cur;
825 _gnutls_write_log ("HWRITE FLUSH: %d bytes in buffer.\n",
826 (int) send_buffer->byte_length);
828 if (IS_DTLS(session))
829 return _dtls_transmit(session);
831 for (cur = _mbuffer_get_first (send_buffer, &msg);
832 cur != NULL; cur = _mbuffer_get_first (send_buffer, &msg))
834 epoch = cur->epoch;
836 ret = _gnutls_send_int (session, cur->type,
837 cur->htype,
838 epoch,
839 msg.data, msg.size, 0);
841 if (ret >= 0)
843 total += ret;
845 ret = _mbuffer_remove_bytes (send_buffer, ret);
846 if (ret == 1)
847 _gnutls_epoch_refcount_dec(session, epoch);
849 _gnutls_write_log ("HWRITE: wrote %d bytes, %d bytes left.\n",
850 ret, (int) send_buffer->byte_length);
853 else
855 _gnutls_write_log ("HWRITE error: code %d, %d bytes left.\n",
856 ret, (int) send_buffer->byte_length);
858 gnutls_assert ();
859 return ret;
863 return _gnutls_io_write_flush (session);
868 /* This is a send function for the gnutls handshake
869 * protocol. Just makes sure that all data have been sent.
873 _gnutls_handshake_io_cache_int (gnutls_session_t session,
874 gnutls_handshake_description_t htype,
875 mbuffer_st * bufel)
877 mbuffer_head_st * send_buffer;
879 if (IS_DTLS(session))
881 bufel->sequence = session->internals.dtls.hsk_write_seq-1;
884 send_buffer =
885 &session->internals.handshake_send_buffer;
887 bufel->epoch = (uint16_t)_gnutls_epoch_refcount_inc(session, EPOCH_WRITE_CURRENT);
889 bufel->htype = htype;
890 if (bufel->htype == GNUTLS_HANDSHAKE_CHANGE_CIPHER_SPEC)
891 bufel->type = GNUTLS_CHANGE_CIPHER_SPEC;
892 else
893 bufel->type = GNUTLS_HANDSHAKE;
895 _mbuffer_enqueue (send_buffer, bufel);
897 _gnutls_write_log
898 ("HWRITE: enqueued [%s] %d. Total %d bytes.\n",
899 _gnutls_handshake2str (bufel->htype), (int) bufel->msg.size, (int) send_buffer->byte_length);
901 return 0;
904 /* Skips a handshake packet
907 _gnutls_handshake_io_recv_skip (gnutls_session_t session,
908 content_type_t type,
909 gnutls_handshake_description_t htype,
910 size_t ptr_size)
912 opaque * ptr;
913 int ret;
915 if (ptr_size == 0) return 0;
917 ptr = gnutls_malloc(ptr_size);
918 if (ptr == NULL)
919 return gnutls_assert_val(GNUTLS_E_MEMORY_ERROR);
921 ret = _gnutls_handshake_io_recv_int(session, type, htype, ptr, ptr_size);
922 gnutls_free(ptr);
924 if (ret < 0)
925 return gnutls_assert_val(ret);
927 return 0;
930 /* This is a receive function for the gnutls handshake
931 * protocol. Makes sure that we have received all data.
933 ssize_t
934 _gnutls_handshake_io_recv_int (gnutls_session_t session,
935 content_type_t type,
936 gnutls_handshake_description_t htype,
937 void *iptr, size_t ptr_size)
939 size_t left;
940 ssize_t i;
941 opaque *ptr;
942 size_t dsize;
944 ptr = iptr;
945 left = ptr_size;
947 if (ptr_size == 0 || iptr == NULL)
949 gnutls_assert ();
950 return GNUTLS_E_INVALID_REQUEST;
953 if (session->internals.handshake_recv_buffer.length > 0)
955 size_t tmp;
957 /* if we have already received some data */
958 if (ptr_size <= session->internals.handshake_recv_buffer.length)
960 /* if requested less data then return it.
962 gnutls_assert ();
964 tmp = ptr_size;
965 _gnutls_buffer_pop_data (&session->internals.handshake_recv_buffer,
966 iptr, &tmp);
967 return tmp;
969 gnutls_assert ();
971 tmp = ptr_size;
972 _gnutls_buffer_pop_data (&session->internals.handshake_recv_buffer,
973 iptr, &tmp);
974 left -= tmp;
977 while (left > 0)
979 dsize = ptr_size - left;
980 i = _gnutls_recv_int (session, type, htype, &ptr[dsize], left, NULL);
981 if (i < 0)
984 if (dsize > 0 && (i == GNUTLS_E_INTERRUPTED || i == GNUTLS_E_AGAIN))
986 gnutls_assert ();
988 _gnutls_buffer_append_data (&session->internals.
989 handshake_recv_buffer, iptr, dsize);
992 return i;
994 else
996 if (i == 0)
997 break; /* EOF */
1000 left -= i;
1004 session->internals.handshake_recv_buffer.length = 0;
1006 return ptr_size - left;
1009 /* Buffer for handshake packets. Keeps the packets in order
1010 * for finished messages to use them. Used in HMAC calculation
1011 * and finished messages.
1014 _gnutls_handshake_buffer_put (gnutls_session_t session, opaque * data,
1015 size_t length)
1018 if (length == 0)
1019 return 0;
1021 if ((session->internals.max_handshake_data_buffer_size > 0) &&
1022 ((length + session->internals.handshake_hash_buffer.length) >
1023 session->internals.max_handshake_data_buffer_size))
1025 gnutls_assert ();
1026 return GNUTLS_E_HANDSHAKE_TOO_LARGE;
1029 _gnutls_buffers_log ("BUF[HSK]: Inserted %d bytes of Data\n", (int) length);
1030 if (_gnutls_buffer_append_data (&session->internals.handshake_hash_buffer,
1031 data, length) < 0)
1033 gnutls_assert ();
1034 return GNUTLS_E_MEMORY_ERROR;
1037 return 0;
1041 _gnutls_handshake_buffer_get_size (gnutls_session_t session)
1044 return session->internals.handshake_hash_buffer.length;
1047 /* this function does not touch the buffer
1048 * and returns data from it (peek mode!)
1051 _gnutls_handshake_buffer_get_ptr (gnutls_session_t session,
1052 opaque ** data_ptr, size_t * length)
1054 if (length != NULL)
1055 *length = session->internals.handshake_hash_buffer.length;
1057 _gnutls_buffers_log ("BUF[HSK]: Peeked %d bytes of Data\n",
1058 (int) session->internals.handshake_hash_buffer.length);
1060 if (data_ptr != NULL)
1061 *data_ptr = session->internals.handshake_hash_buffer.data;
1063 return 0;
1066 /* Does not free the buffer
1069 _gnutls_handshake_buffer_empty (gnutls_session_t session)
1072 _gnutls_buffers_log ("BUF[HSK]: Emptied buffer\n");
1074 session->internals.handshake_hash_buffer.length = 0;
1076 return 0;
1081 _gnutls_handshake_buffer_clear (gnutls_session_t session)
1084 _gnutls_buffers_log ("BUF[HSK]: Cleared Data from buffer\n");
1085 _gnutls_buffer_clear (&session->internals.handshake_hash_buffer);
1087 return 0;