*** empty log message ***
[gnutls.git] / lib / gnutls_buffers.c
blobe360867b95d2cf9927efd8afd00e9260da79c1c9
1 /*
2 * Copyright (C) 2000,2001,2002 Nikos Mavroyanopoulos
4 * This file is part of GNUTLS.
6 * GNUTLS is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * GNUTLS is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
21 #include <gnutls_int.h>
22 #include <gnutls_errors.h>
23 #include <gnutls_num.h>
24 #include <gnutls_record.h>
25 #include <gnutls_buffers.h>
26 #include <gnutls_datum.h>
28 /* This is the only file that uses the berkeley sockets API.
30 * Also holds all the buffering code used in gnutls.
31 * The buffering code works as:
33 * RECORD LAYER:
34 * 1. uses a buffer to hold data (application/handshake),
35 * we got but they were not requested, yet.
36 * (see gnutls_record_buffer_put(), gnutls_record_buffer_get_size() etc.)
38 * 2. uses a buffer to hold data that were incomplete (ie the read/write
39 * was interrupted)
40 * (see _gnutls_io_read_buffered(), _gnutls_io_write_buffered() etc.)
42 * HANDSHAKE LAYER:
43 * 1. Uses a buffer to hold data that was not sent or received
44 * complete. (Ie. sent 10 bytes of a handshake packet that is 20 bytes
45 * long).
46 * (see _gnutls_handshake_send_int(), _gnutls_handshake_recv_int())
48 * 2. Uses buffer to hold the last received handshake message.
49 * (see _gnutls_handshake_buffer_put() etc.)
53 #ifdef HAVE_ERRNO_H
54 # include <errno.h>
55 #endif
57 #ifndef EAGAIN
58 # define EAGAIN EWOULDBLOCK
59 #endif
61 inline
62 static int RET( int err) {
63 if (err==EAGAIN) return GNUTLS_E_AGAIN;
64 return GNUTLS_E_INTERRUPTED;
67 #ifdef IO_DEBUG
68 # include <io_debug.h>
69 #endif
71 /* Buffers received packets of type APPLICATION DATA and
72 * HANDSHAKE DATA.
74 int _gnutls_record_buffer_put(ContentType type, GNUTLS_STATE state, char *data, int length)
76 if (length==0) return 0;
77 switch( type) {
78 case GNUTLS_APPLICATION_DATA:
80 if ( gnutls_datum_append( &state->gnutls_internals.application_data_buffer,
81 data, length) < 0) {
82 gnutls_assert();
83 return GNUTLS_E_MEMORY_ERROR;
85 _gnutls_buffers_log( "BUF[REC]: Inserted %d bytes of Data(%d)\n", length, type);
87 break;
88 case GNUTLS_HANDSHAKE:
89 if ( gnutls_datum_append( &state->gnutls_internals.handshake_data_buffer,
90 data, length) < 0) {
91 gnutls_assert();
92 return GNUTLS_E_MEMORY_ERROR;
95 _gnutls_buffers_log( "BUF[HSK]: Inserted %d bytes of Data(%d)\n", length, type);
97 break;
99 default:
100 gnutls_assert();
101 return GNUTLS_E_INVALID_PARAMETERS;
104 return 0;
108 int _gnutls_record_buffer_get_size(ContentType type, GNUTLS_STATE state)
110 switch( type) {
111 case GNUTLS_APPLICATION_DATA:
112 return state->gnutls_internals.application_data_buffer.size;
114 case GNUTLS_HANDSHAKE:
115 return state->gnutls_internals.handshake_data_buffer.size;
117 default:
118 return GNUTLS_E_INVALID_PARAMETERS;
120 return 0;
124 * gnutls_record_check_pending - checks if there are any data to receive in gnutls buffers.
125 * @state: is a &GNUTLS_STATE structure.
127 * This function checks if there are any data to receive
128 * in the gnutls buffers. Returns the size of that data or 0.
129 * Notice that you may also use select() to check for data in
130 * the TCP connection, instead of this function.
131 * (gnutls leaves some data in the tcp buffer in order for select
132 * to work).
134 size_t gnutls_record_check_pending(GNUTLS_STATE state) {
135 return _gnutls_record_buffer_get_size(GNUTLS_APPLICATION_DATA, state);
138 int _gnutls_record_buffer_get(ContentType type, GNUTLS_STATE state, char *data, int length)
140 if (length < 0 || data==NULL) {
141 gnutls_assert();
142 return GNUTLS_E_INVALID_PARAMETERS;
145 switch(type) {
146 case GNUTLS_APPLICATION_DATA:
148 if (length > state->gnutls_internals.application_data_buffer.size) {
149 length = state->gnutls_internals.application_data_buffer.size;
152 _gnutls_buffers_log( "BUFFER[REC][AD]: Read %d bytes of Data(%d)\n", length, type);
154 state->gnutls_internals.application_data_buffer.size -= length;
155 memcpy(data, state->gnutls_internals.application_data_buffer.data, length);
157 /* overwrite buffer */
158 memmove(state->gnutls_internals.application_data_buffer.data,
159 &state->gnutls_internals.application_data_buffer.data[length],
160 state->gnutls_internals.application_data_buffer.size);
161 /* this does not fail */
162 state->gnutls_internals.application_data_buffer.data =
163 gnutls_realloc_fast(state->gnutls_internals.application_data_buffer.data,
164 state->gnutls_internals.application_data_buffer.size);
165 break;
167 case GNUTLS_HANDSHAKE:
168 if (length > state->gnutls_internals.handshake_data_buffer.size) {
169 length = state->gnutls_internals.handshake_data_buffer.size;
172 _gnutls_buffers_log( "BUF[REC][HD]: Read %d bytes of Data(%d)\n", length, type);
174 state->gnutls_internals.handshake_data_buffer.size -= length;
175 memcpy(data, state->gnutls_internals.handshake_data_buffer.data, length);
177 /* overwrite buffer */
178 memmove(state->gnutls_internals.handshake_data_buffer.data,
179 &state->gnutls_internals.handshake_data_buffer.data[length],
180 state->gnutls_internals.handshake_data_buffer.size);
182 /* does not fail */
183 state->gnutls_internals.handshake_data_buffer.data =
184 gnutls_realloc_fast(state->gnutls_internals.handshake_data_buffer.data,
185 state->gnutls_internals.handshake_data_buffer.size);
186 break;
187 default:
188 gnutls_assert();
189 return GNUTLS_E_INVALID_PARAMETERS;
193 return length;
197 /* This function is like read. But it does not return -1 on error.
198 * It does return gnutls_errno instead.
200 * Flags are only used if the default recv() function is being used.
202 static ssize_t _gnutls_read( GNUTLS_STATE state, void *iptr, size_t sizeOfPtr, int flags)
204 size_t left;
205 ssize_t i=0;
206 char *ptr = iptr;
207 #ifdef READ_DEBUG
208 int j,x, sum=0;
209 #endif
210 GNUTLS_TRANSPORT_PTR fd = state->gnutls_internals.transport_ptr;
212 left = sizeOfPtr;
213 while (left > 0) {
215 if (state->gnutls_internals._gnutls_pull_func==NULL)
216 i = recv(fd, &ptr[sizeOfPtr-left], left, flags);
217 else
218 i = state->gnutls_internals._gnutls_pull_func(fd, &ptr[sizeOfPtr-left], left);
220 if (i < 0) {
221 _gnutls_read_log( "READ: %d returned from %d, errno=%d\n", i, fd, errno);
223 if (errno == EAGAIN || errno == EINTR) {
224 if (sizeOfPtr-left > 0) {
226 _gnutls_read_log( "READ: returning %d bytes from %d\n", sizeOfPtr-left, fd);
228 goto finish;
230 gnutls_assert();
232 return RET(errno);
233 } else {
234 gnutls_assert();
235 return GNUTLS_E_PULL_ERROR;
237 } else {
239 _gnutls_read_log( "READ: Got %d bytes from %d\n", i, fd);
241 if (i == 0)
242 break; /* EOF */
245 left -= i;
249 finish:
251 #ifdef READ_DEBUG
252 _gnutls_read_log( "READ: read %d bytes from %d\n", (sizeOfPtr-left), fd);
253 for (x=0;x<((sizeOfPtr-left)/16)+1;x++) {
254 _gnutls_read_log( "%.4x - ",x);
255 for (j=0;j<16;j++) {
256 if (sum<(sizeOfPtr-left)) {
257 _gnutls_read_log( "%.2x ", ((unsigned char*)ptr)[sum++]);
260 _gnutls_read_log( "\n");
263 #endif
266 return (sizeOfPtr - left);
270 #define RCVLOWAT state->gnutls_internals.lowat
272 /* This function is only used with berkeley style sockets.
273 * Clears the peeked data (read with MSG_PEEK).
275 int _gnutls_io_clear_peeked_data( GNUTLS_STATE state) {
276 char peekdata1[10];
277 char *peekdata2;
278 char * peek;
279 int ret, sum;
281 if (state->gnutls_internals.have_peeked_data==0 || RCVLOWAT==0)
282 return 0;
284 if (RCVLOWAT > sizeof(peekdata1)) {
285 peekdata2 = gnutls_malloc( RCVLOWAT);
286 if (peekdata2==NULL) {
287 gnutls_assert();
288 return GNUTLS_E_MEMORY_ERROR;
291 peek = peekdata2;
293 } else {
294 peek = peekdata1;
297 /* this was already read by using MSG_PEEK - so it shouldn't fail */
298 sum = 0;
299 do { /* we need this to finish now */
300 ret = _gnutls_read( state, peek, RCVLOWAT-sum, 0);
301 if (ret > 0) sum+=ret;
302 } while( ret==GNUTLS_E_INTERRUPTED || ret==GNUTLS_E_AGAIN || sum < RCVLOWAT);
304 if (peek==peekdata2) {
305 gnutls_free(peekdata2);
308 if (ret < 0) {
309 gnutls_assert();
310 return ret;
313 state->gnutls_internals.have_peeked_data=0;
315 return 0;
319 void _gnutls_io_clear_read_buffer( GNUTLS_STATE state) {
320 state->gnutls_internals.record_recv_buffer.size = 0;
323 /* This function is like recv(with MSG_PEEK). But it does not return -1 on error.
324 * It does return gnutls_errno instead.
325 * This function reads data from the socket and keeps them in a buffer, of up to
326 * MAX_RECV_SIZE.
328 * sizeOfPtr should be unsigned.
330 * This is not a general purpose function. It returns EXACTLY the data requested.
333 ssize_t _gnutls_io_read_buffered( GNUTLS_STATE state, opaque **iptr, size_t sizeOfPtr, ContentType recv_type)
335 ssize_t ret=0, ret2=0;
336 int min, buf_pos;
337 char *buf;
338 int recvlowat = RCVLOWAT;
339 int recvdata;
341 *iptr = state->gnutls_internals.record_recv_buffer.data;
343 if ( sizeOfPtr > MAX_RECV_SIZE || sizeOfPtr == 0
344 || (state->gnutls_internals.record_recv_buffer.size+sizeOfPtr) > MAX_RECV_SIZE) {
345 gnutls_assert(); /* internal error */
346 return GNUTLS_E_INVALID_PARAMETERS;
349 /* leave peeked data to the kernel space only if application data
350 * is received and we don't have any peeked
351 * data in gnutls state.
353 if ( recv_type != GNUTLS_APPLICATION_DATA
354 && state->gnutls_internals.have_peeked_data==0)
355 recvlowat = 0;
358 /* calculate the actual size, ie. get the minimum of the
359 * buffered data and the requested data.
361 min = GMIN( state->gnutls_internals.record_recv_buffer.size, sizeOfPtr);
362 if ( min > 0) {
363 /* if we have enough buffered data
364 * then just return them.
366 if ( min == sizeOfPtr) {
367 return min;
371 /* min is over zero. recvdata is the data we must
372 * receive in order to return the requested data.
374 recvdata = sizeOfPtr - min;
376 /* Allocate the data required to store the new packet.
378 state->gnutls_internals.record_recv_buffer.data = gnutls_realloc_fast(
379 state->gnutls_internals.record_recv_buffer.data, recvdata+state->gnutls_internals.record_recv_buffer.size);
380 if ( state->gnutls_internals.record_recv_buffer.data==NULL) {
381 gnutls_assert();
382 return GNUTLS_E_MEMORY_ERROR;
385 buf_pos = state->gnutls_internals.record_recv_buffer.size;
386 buf = state->gnutls_internals.record_recv_buffer.data;
387 *iptr = buf;
389 /* READ DATA - but leave RCVLOWAT bytes in the kernel buffer.
391 if ( recvdata - recvlowat > 0) {
392 ret = _gnutls_read( state, &buf[buf_pos], recvdata - recvlowat, 0);
394 /* return immediately if we got an interrupt or eagain
395 * error.
397 if (ret < 0 && gnutls_error_is_fatal(ret)==0) {
398 return ret;
402 /* copy fresh data to our buffer.
404 if (ret > 0) {
405 _gnutls_read_log("RB: Have %d bytes into buffer. Adding %d bytes.\nRB: Requested %d bytes\n", state->gnutls_internals.record_recv_buffer.size, ret, sizeOfPtr);
406 state->gnutls_internals.record_recv_buffer.size += ret;
409 buf_pos = state->gnutls_internals.record_recv_buffer.size;
411 /* This is hack in order for select to work. Just leave recvlowat data,
412 * into the kernel buffer (using a read with MSG_PEEK), thus making
413 * select think, that the socket is ready for reading.
414 * MSG_PEEK is only used with berkeley style sockets.
416 if (ret == (recvdata - recvlowat) && recvlowat > 0) {
417 ret2 = _gnutls_read( state, &buf[buf_pos], recvlowat, MSG_PEEK);
419 if (ret2 < 0 && gnutls_error_is_fatal(ret2)==0) {
420 return ret2;
423 if (ret2 > 0) {
424 _gnutls_read_log("RB-PEEK: Read %d bytes in PEEK MODE.\n", ret2);
425 _gnutls_read_log("RB-PEEK: Have %d bytes into buffer. Adding %d bytes.\nRB: Requested %d bytes\n", state->gnutls_internals.record_recv_buffer.size, ret2, sizeOfPtr);
426 state->gnutls_internals.have_peeked_data = 1;
427 state->gnutls_internals.record_recv_buffer.size += ret2;
432 if (ret < 0 || ret2 < 0) {
433 gnutls_assert();
434 /* that's because they are initilized to 0 */
435 return GMIN(ret, ret2);
438 ret += ret2;
440 if (ret > 0 && ret < recvlowat) {
441 gnutls_assert();
442 return GNUTLS_E_AGAIN;
445 if (ret==0) { /* EOF */
446 gnutls_assert();
447 return 0;
450 ret = state->gnutls_internals.record_recv_buffer.size;
452 if ((ret > 0) && (ret < sizeOfPtr)) {
453 /* Short Read */
454 gnutls_assert();
455 return GNUTLS_E_AGAIN;
456 } else {
457 return ret;
462 /* These two functions are used to insert data to the send buffer of the handshake or
463 * record protocol. The send buffer is kept if a send is interrupted and we need to keep
464 * the data left to sent, in order to send them later.
467 #define MEMSUB(x,y) (x-y)
469 inline
470 static int _gnutls_buffer_insert( gnutls_datum * buffer, const opaque* _data, int data_size) {
472 if ( ( MEMSUB(_data, buffer->data) >= 0) && (MEMSUB(_data, buffer->data) < buffer->size) ) {
473 /* the given _data is part of the buffer.
475 if (data_size > buffer->size) {
476 gnutls_assert();
477 /* this shouldn't have happened */
478 return GNUTLS_E_UNKNOWN_ERROR;
481 if (_data==buffer->data) { /* then don't even memmove */
482 buffer->size = data_size;
483 return 0;
486 memmove( buffer->data, _data, data_size);
487 buffer->size = data_size;
489 return 0;
493 buffer->data = gnutls_realloc_fast( buffer->data, data_size);
494 buffer->size = data_size;
496 if (buffer->data == NULL) {
497 gnutls_assert();
498 return GNUTLS_E_MEMORY_ERROR;
501 memcpy( buffer->data, _data, data_size);
503 return 0;
506 inline
507 static int _gnutls_buffer_get( gnutls_datum * buffer, const opaque ** ptr, size_t *ptr_size) {
508 *ptr_size = buffer->size;
509 *ptr = buffer->data;
511 return 0;
515 /* This function is like write. But it does not return -1 on error.
516 * It does return gnutls_errno instead.
518 * In case of E_AGAIN and E_INTERRUPTED errors, you must call gnutls_write_flush(),
519 * until it returns ok (0).
521 * We need to push exactly the data in n, since we cannot send less
522 * data. In TLS the peer must receive the whole packet in order
523 * to decrypt and verify the integrity.
526 ssize_t _gnutls_io_write_buffered( GNUTLS_STATE state, const void *iptr, size_t n)
528 size_t left;
529 #ifdef WRITE_DEBUG
530 int j,x, sum=0;
531 #endif
532 ssize_t retval, i;
533 const opaque * ptr;
534 int ret;
535 GNUTLS_TRANSPORT_PTR fd = state->gnutls_internals.transport_ptr;
537 ptr = iptr;
539 /* In case the previous write was interrupted, check if the
540 * iptr != NULL and we have data in the buffer.
541 * If this is true then return an error.
543 if (state->gnutls_internals.record_send_buffer.size > 0 && iptr != NULL) {
544 gnutls_assert();
545 return GNUTLS_E_INVALID_PARAMETERS;
548 /* If data in the buffer exist
550 if (iptr == NULL) {
551 /* checking is handled above */
552 ret = _gnutls_buffer_get( &state->gnutls_internals.record_send_buffer, &ptr, &n);
553 if (ret < 0) {
554 gnutls_assert();
555 return retval;
558 _gnutls_write_log( "WRITE: Restoring old write. (%d bytes to send)\n", n);
561 _gnutls_write_log( "WRITE: Will write %d bytes to %d.\n", n, fd);
563 i = 0;
564 left = n;
565 while (left > 0) {
567 if (state->gnutls_internals._gnutls_push_func==NULL)
568 i = send(fd, &ptr[n-left], left, 0);
569 else
570 i = state->gnutls_internals._gnutls_push_func(fd, &ptr[n-left], left);
572 if (i == -1) {
573 if (errno == EAGAIN || errno == EINTR) {
574 state->gnutls_internals.record_send_buffer_prev_size += n - left;
576 retval = _gnutls_buffer_insert( &state->gnutls_internals.record_send_buffer, &ptr[n-left], left);
577 if (retval < 0) {
578 gnutls_assert();
579 return retval;
582 _gnutls_write_log( "WRITE: Interrupted. Stored %d bytes to buffer. Already sent %d bytes.\n", left, n-left);
584 retval = RET(errno);
586 return retval;
587 } else {
588 gnutls_assert();
589 return GNUTLS_E_PUSH_ERROR;
592 left -= i;
594 #ifdef WRITE_DEBUG
595 _gnutls_write_log( "WRITE: wrote %d bytes to %d. Left %d bytes. Total %d bytes.\n", i, fd, left, n);
596 for (x=0;x<((i)/16)+1;x++) {
597 if (sum>n-left)
598 break;
600 _gnutls_write_log( "%.4x - ",x);
601 for (j=0;j<16;j++) {
602 if (sum<n-left) {
603 _gnutls_write_log( "%.2x ", ((unsigned char*)ptr)[sum++]);
604 } else break;
606 _gnutls_write_log( "\n");
608 _gnutls_write_log( "\n");
609 #endif
613 retval = n + state->gnutls_internals.record_send_buffer_prev_size;
615 state->gnutls_internals.record_send_buffer.size = 0;
616 state->gnutls_internals.record_send_buffer_prev_size = 0;
618 return retval;
622 /* This is exactly like write_buffered, but will use two buffers to read
623 * from.
625 ssize_t _gnutls_io_write_buffered2( GNUTLS_STATE state, const void *iptr, size_t n, const void* iptr2, size_t n2)
628 if (n==0) {
629 return _gnutls_io_write_buffered( state, iptr2, n2);
630 } else {
631 opaque* sptr;
632 ssize_t ret;
634 sptr = gnutls_malloc( n+n2);
635 if (sptr==NULL) {
636 gnutls_assert();
637 return GNUTLS_E_MEMORY_ERROR;
640 memcpy( sptr, iptr, n);
641 memcpy( &sptr[n], iptr2, n2);
643 ret = _gnutls_io_write_buffered( state, sptr, n+n2);
644 gnutls_free( sptr);
646 return ret;
651 /* This function writes the data that are left in the
652 * TLS write buffer (ie. because the previous write was
653 * interrupted.
655 ssize_t _gnutls_io_write_flush( GNUTLS_STATE state)
657 ssize_t ret;
659 if (state->gnutls_internals.record_send_buffer.size == 0)
660 return 0; /* done */
662 ret = _gnutls_io_write_buffered( state, NULL, 0);
663 _gnutls_write_log("WRITE FLUSH: %d [buffer: %d]\n", ret, state->gnutls_internals.record_send_buffer.size);
665 return ret;
668 /* This function writes the data that are left in the
669 * Handshake write buffer (ie. because the previous write was
670 * interrupted.
672 ssize_t _gnutls_handshake_io_write_flush( GNUTLS_STATE state)
674 ssize_t ret;
675 ret = _gnutls_handshake_io_send_int( state, 0, 0, NULL, 0);
676 if (ret < 0) {
677 gnutls_assert();
678 return ret;
681 _gnutls_write_log("HANDSHAKE_FLUSH: written[1] %d bytes\n", ret);
683 if (state->gnutls_internals.handshake_send_buffer.size == 0) {
684 ret = state->gnutls_internals.handshake_send_buffer_prev_size; /* done */
685 state->gnutls_internals.handshake_send_buffer_prev_size = 0;
686 state->gnutls_internals.handshake_send_buffer.size = 0;
688 return ret;
691 return ret;
695 /* This is a send function for the gnutls handshake
696 * protocol. Just makes sure that all data have been sent.
698 ssize_t _gnutls_handshake_io_send_int( GNUTLS_STATE state, ContentType type, HandshakeType htype, const void *iptr, size_t n)
700 size_t left;
701 ssize_t i = 0, ret=0;
702 const opaque *ptr;
703 ssize_t retval = 0;
705 ptr = iptr;
707 if (state->gnutls_internals.handshake_send_buffer.size > 0 && ptr==NULL && n == 0) {
708 /* resuming previously interrupted write
710 gnutls_assert();
711 ret = _gnutls_buffer_get( &state->gnutls_internals.handshake_send_buffer, &ptr, &n);
712 if (ret < 0) {
713 gnutls_assert();
714 return retval;
717 type = state->gnutls_internals.handshake_send_buffer_type;
718 htype = state->gnutls_internals.handshake_send_buffer_htype;
720 } else if (state->gnutls_internals.handshake_send_buffer.size > 0) {
721 gnutls_assert();
722 return GNUTLS_E_UNKNOWN_ERROR;
723 } else {
724 #ifdef WRITE_DEBUG
725 size_t sum=0, x, j;
727 _gnutls_write_log( "HWRITE: will write %d bytes to %d.\n", n, gnutls_transport_get_ptr(state));
728 for (x=0;x<((n)/16)+1;x++) {
729 if (sum>n)
730 break;
732 _gnutls_write_log( "%.4x - ",x);
733 for (j=0;j<16;j++) {
734 if (sum<n) {
735 _gnutls_write_log( "%.2x ", ((unsigned char*)ptr)[sum++]);
736 } else break;
738 _gnutls_write_log( "\n");
740 _gnutls_write_log( "\n");
741 #endif
746 if (n==0) { /* if we have no data to send */
747 gnutls_assert();
748 return 0;
749 } else if (ptr==NULL) {
750 gnutls_assert();
751 return GNUTLS_E_UNKNOWN_ERROR;
755 left = n;
756 while (left > 0) {
757 ret = gnutls_send_int( state, type, htype, &ptr[n-left], left);
759 if (ret <= 0) {
760 if (ret==0) {
761 gnutls_assert();
762 ret = GNUTLS_E_UNKNOWN_ERROR;
765 if ( left > 0 && (ret==GNUTLS_E_INTERRUPTED || ret==GNUTLS_E_AGAIN)) {
766 gnutls_assert();
768 retval = _gnutls_buffer_insert( &state->gnutls_internals.handshake_send_buffer, &ptr[n-left], left);
769 if (retval < 0) {
770 gnutls_assert();
771 return retval;
774 state->gnutls_internals.handshake_send_buffer_prev_size += n-left;
776 state->gnutls_internals.handshake_send_buffer_type = type;
777 state->gnutls_internals.handshake_send_buffer_htype = htype;
779 } else {
780 state->gnutls_internals.handshake_send_buffer_prev_size = 0;
781 state->gnutls_internals.handshake_send_buffer.size = 0;
784 gnutls_assert();
785 return ret;
787 i = ret;
788 left -= i;
791 retval = n + state->gnutls_internals.handshake_send_buffer_prev_size;
793 state->gnutls_internals.handshake_send_buffer.size = 0;
794 state->gnutls_internals.handshake_send_buffer_prev_size = 0;
796 return retval;
800 /* This is a receive function for the gnutls handshake
801 * protocol. Makes sure that we have received all data.
803 ssize_t _gnutls_handshake_io_recv_int( GNUTLS_STATE state, ContentType type, HandshakeType htype, void *iptr, size_t sizeOfPtr)
805 size_t left;
806 ssize_t i;
807 char *ptr;
808 size_t dsize;
810 ptr = iptr;
811 left = sizeOfPtr;
813 if (sizeOfPtr == 0 || iptr == NULL) {
814 gnutls_assert();
815 return GNUTLS_E_INVALID_PARAMETERS;
818 if (state->gnutls_internals.handshake_recv_buffer.size > 0) {
819 /* if we have already received some data */
820 if (sizeOfPtr <= state->gnutls_internals.handshake_recv_buffer.size) {
821 /* if requested less data then return it.
823 gnutls_assert();
824 memcpy( iptr, state->gnutls_internals.handshake_recv_buffer.data, sizeOfPtr);
826 state->gnutls_internals.handshake_recv_buffer.size -= sizeOfPtr;
828 memmove( state->gnutls_internals.handshake_recv_buffer.data,
829 &state->gnutls_internals.handshake_recv_buffer.data[sizeOfPtr],
830 state->gnutls_internals.handshake_recv_buffer.size);
832 return sizeOfPtr;
834 gnutls_assert();
835 memcpy( iptr, state->gnutls_internals.handshake_recv_buffer.data, state->gnutls_internals.handshake_recv_buffer.size);
837 htype = state->gnutls_internals.handshake_recv_buffer_htype;
838 type = state->gnutls_internals.handshake_recv_buffer_type;
840 left -= state->gnutls_internals.handshake_recv_buffer.size;
842 state->gnutls_internals.handshake_recv_buffer.size = 0;
845 while (left > 0) {
846 dsize = sizeOfPtr - left;
847 i = gnutls_recv_int( state, type, htype, &ptr[dsize], left);
848 if (i < 0) {
850 if (dsize > 0 && (i==GNUTLS_E_INTERRUPTED || i==GNUTLS_E_AGAIN)) {
851 gnutls_assert();
853 state->gnutls_internals.handshake_recv_buffer.data = gnutls_realloc_fast(
854 state->gnutls_internals.handshake_recv_buffer.data, dsize);
855 if (state->gnutls_internals.handshake_recv_buffer.data==NULL) {
856 gnutls_assert();
857 return GNUTLS_E_MEMORY_ERROR;
860 memcpy( state->gnutls_internals.handshake_recv_buffer.data, iptr, dsize);
862 state->gnutls_internals.handshake_recv_buffer_htype = htype;
863 state->gnutls_internals.handshake_recv_buffer_type = type;
865 state->gnutls_internals.handshake_recv_buffer.size = dsize;
866 } else
867 state->gnutls_internals.handshake_recv_buffer.size = 0;
869 gnutls_assert();
871 return i;
872 } else {
873 if (i == 0)
874 break; /* EOF */
877 left -= i;
881 state->gnutls_internals.handshake_recv_buffer.size = 0;
883 return sizeOfPtr - left;
886 /* Buffer for handshake packets. Keeps the packets in order
887 * for finished messages to use them. Used in HMAC calculation
888 * and finished messages.
890 int _gnutls_handshake_buffer_put( GNUTLS_STATE state, char *data, int length)
893 if (length==0) return 0;
895 if ( (state->gnutls_internals.max_handshake_data_buffer_size > 0) &&
896 ((length+state->gnutls_internals.handshake_hash_buffer.size) >
897 state->gnutls_internals.max_handshake_data_buffer_size)) {
898 gnutls_assert();
899 return GNUTLS_E_MEMORY_ERROR;
902 _gnutls_buffers_log( "BUF[HSK]: Inserted %d bytes of Data\n", length);
904 if ( gnutls_datum_append( &state->gnutls_internals.handshake_hash_buffer,
905 data, length) < 0) {
906 gnutls_assert();
907 return GNUTLS_E_MEMORY_ERROR;
910 return 0;
913 int _gnutls_handshake_buffer_get_size( GNUTLS_STATE state)
916 return state->gnutls_internals.handshake_hash_buffer.size;
919 /* this function does not touch the buffer
920 * and returns data from it (peek mode!)
922 int _gnutls_handshake_buffer_peek( GNUTLS_STATE state, char *data, int length)
924 if (length > state->gnutls_internals.handshake_hash_buffer.size) {
925 length = state->gnutls_internals.handshake_hash_buffer.size;
928 _gnutls_buffers_log( "BUF[HSK]: Peeked %d bytes of Data\n", length);
930 memcpy(data, state->gnutls_internals.handshake_hash_buffer.data, length);
931 return length;
934 /* this function does not touch the buffer
935 * and returns data from it (peek mode!)
937 int _gnutls_handshake_buffer_get_ptr( GNUTLS_STATE state, char **data_ptr, int *length)
939 if (length!=NULL)
940 *length = state->gnutls_internals.handshake_hash_buffer.size;
942 _gnutls_buffers_log( "BUF[HSK]: Peeded %d bytes of Data\n", length);
944 if (data_ptr!=NULL)
945 *data_ptr = state->gnutls_internals.handshake_hash_buffer.data;
947 return 0;
950 /* Does not free the buffer
952 int _gnutls_handshake_buffer_empty( GNUTLS_STATE state)
955 _gnutls_buffers_log( "BUF[HSK]: Emptied buffer\n");
957 state->gnutls_internals.handshake_hash_buffer.size = 0;
959 return 0;
963 int _gnutls_handshake_buffer_clear( GNUTLS_STATE state)
966 _gnutls_buffers_log( "BUF[HSK]: Cleared Data from buffer\n");
968 state->gnutls_internals.handshake_hash_buffer.size = 0;
969 if (state->gnutls_internals.handshake_hash_buffer.data!=NULL)
970 gnutls_free(state->gnutls_internals.handshake_hash_buffer.data);
971 state->gnutls_internals.handshake_hash_buffer.data = NULL;
973 return 0;