*** empty log message ***
[gnutls.git] / lib / gnutls_buffers.c
blobbcdec363ce25ada3d723162468e8d0d755eaca75
1 /*
2 * Copyright (C) 2000,2001,2002 Nikos Mavroyanopoulos
4 * This file is part of GNUTLS.
6 * The GNUTLS library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library 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 GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include <gnutls_int.h>
23 #include <gnutls_errors.h>
24 #include <gnutls_num.h>
25 #include <gnutls_record.h>
26 #include <gnutls_buffers.h>
27 #include <gnutls_datum.h>
29 /* This is the only file that uses the berkeley sockets API.
31 * Also holds all the buffering code used in gnutls.
32 * The buffering code works as:
34 * RECORD LAYER:
35 * 1. uses a buffer to hold data (application/handshake),
36 * we got but they were not requested, yet.
37 * (see gnutls_record_buffer_put(), gnutls_record_buffer_get_size() etc.)
39 * 2. uses a buffer to hold data that were incomplete (ie the read/write
40 * was interrupted)
41 * (see _gnutls_io_read_buffered(), _gnutls_io_write_buffered() etc.)
43 * HANDSHAKE LAYER:
44 * 1. Uses a buffer to hold data that was not sent or received
45 * complete. (Ie. sent 10 bytes of a handshake packet that is 20 bytes
46 * long).
47 * (see _gnutls_handshake_send_int(), _gnutls_handshake_recv_int())
49 * 2. Uses buffer to hold the last received handshake message.
50 * (see _gnutls_handshake_buffer_put() etc.)
54 #ifdef HAVE_ERRNO_H
55 # include <errno.h>
56 #endif
58 #ifndef EAGAIN
59 # define EAGAIN EWOULDBLOCK
60 #endif
62 inline
63 static int RET( int err) {
64 if (err==EAGAIN) return GNUTLS_E_AGAIN;
65 return GNUTLS_E_INTERRUPTED;
68 #ifdef IO_DEBUG
69 # include <io_debug.h>
70 #endif
72 /* Buffers received packets of type APPLICATION DATA and
73 * HANDSHAKE DATA.
75 int _gnutls_record_buffer_put(ContentType type, GNUTLS_STATE state, char *data, int length)
77 if (length==0) return 0;
78 switch( type) {
79 case GNUTLS_APPLICATION_DATA:
81 if ( gnutls_datum_append( &state->gnutls_internals.application_data_buffer,
82 data, length) < 0) {
83 gnutls_assert();
84 return GNUTLS_E_MEMORY_ERROR;
86 _gnutls_buffers_log( "BUF[REC]: Inserted %d bytes of Data(%d)\n", length, type);
88 break;
89 case GNUTLS_HANDSHAKE:
90 if ( gnutls_datum_append( &state->gnutls_internals.handshake_data_buffer,
91 data, length) < 0) {
92 gnutls_assert();
93 return GNUTLS_E_MEMORY_ERROR;
96 _gnutls_buffers_log( "BUF[HSK]: Inserted %d bytes of Data(%d)\n", length, type);
98 break;
100 default:
101 gnutls_assert();
102 return GNUTLS_E_INVALID_PARAMETERS;
105 return 0;
109 int _gnutls_record_buffer_get_size(ContentType type, GNUTLS_STATE state)
111 switch( type) {
112 case GNUTLS_APPLICATION_DATA:
113 return state->gnutls_internals.application_data_buffer.size;
115 case GNUTLS_HANDSHAKE:
116 return state->gnutls_internals.handshake_data_buffer.size;
118 default:
119 return GNUTLS_E_INVALID_PARAMETERS;
121 return 0;
125 * gnutls_record_check_pending - checks if there are any data to receive in gnutls buffers.
126 * @state: is a &GNUTLS_STATE structure.
128 * This function checks if there are any data to receive
129 * in the gnutls buffers. Returns the size of that data or 0.
130 * Notice that you may also use select() to check for data in
131 * the TCP connection, instead of this function.
132 * (gnutls leaves some data in the tcp buffer in order for select
133 * to work).
135 size_t gnutls_record_check_pending(GNUTLS_STATE state) {
136 return _gnutls_record_buffer_get_size(GNUTLS_APPLICATION_DATA, state);
139 int _gnutls_record_buffer_get(ContentType type, GNUTLS_STATE state, char *data, int length)
141 if (length < 0 || data==NULL) {
142 gnutls_assert();
143 return GNUTLS_E_INVALID_PARAMETERS;
146 switch(type) {
147 case GNUTLS_APPLICATION_DATA:
149 if (length > state->gnutls_internals.application_data_buffer.size) {
150 length = state->gnutls_internals.application_data_buffer.size;
153 _gnutls_buffers_log( "BUFFER[REC][AD]: Read %d bytes of Data(%d)\n", length, type);
155 state->gnutls_internals.application_data_buffer.size -= length;
156 memcpy(data, state->gnutls_internals.application_data_buffer.data, length);
158 /* overwrite buffer */
159 memmove(state->gnutls_internals.application_data_buffer.data,
160 &state->gnutls_internals.application_data_buffer.data[length],
161 state->gnutls_internals.application_data_buffer.size);
163 /* this does not fail */
164 state->gnutls_internals.application_data_buffer.data =
165 gnutls_realloc_fast(state->gnutls_internals.application_data_buffer.data,
166 state->gnutls_internals.application_data_buffer.size);
167 break;
169 case GNUTLS_HANDSHAKE:
170 if (length > state->gnutls_internals.handshake_data_buffer.size) {
171 length = state->gnutls_internals.handshake_data_buffer.size;
174 _gnutls_buffers_log( "BUF[REC][HD]: Read %d bytes of Data(%d)\n", length, type);
176 state->gnutls_internals.handshake_data_buffer.size -= length;
177 memcpy(data, state->gnutls_internals.handshake_data_buffer.data, length);
179 /* overwrite buffer */
180 memmove(state->gnutls_internals.handshake_data_buffer.data,
181 &state->gnutls_internals.handshake_data_buffer.data[length],
182 state->gnutls_internals.handshake_data_buffer.size);
184 /* does not fail */
185 state->gnutls_internals.handshake_data_buffer.data =
186 gnutls_realloc_fast(state->gnutls_internals.handshake_data_buffer.data,
187 state->gnutls_internals.handshake_data_buffer.size);
188 break;
189 default:
190 gnutls_assert();
191 return GNUTLS_E_INVALID_PARAMETERS;
195 return length;
199 /* This function is like read. But it does not return -1 on error.
200 * It does return gnutls_errno instead.
202 * Flags are only used if the default recv() function is being used.
204 static ssize_t _gnutls_read( GNUTLS_STATE state, void *iptr, size_t sizeOfPtr, int flags)
206 size_t left;
207 ssize_t i=0;
208 char *ptr = iptr;
209 #ifdef READ_DEBUG
210 int j,x, sum=0;
211 #endif
212 GNUTLS_TRANSPORT_PTR fd = state->gnutls_internals.transport_ptr;
214 left = sizeOfPtr;
215 while (left > 0) {
217 if (state->gnutls_internals._gnutls_pull_func==NULL)
218 i = recv(fd, &ptr[sizeOfPtr-left], left, flags);
219 else
220 i = state->gnutls_internals._gnutls_pull_func(fd, &ptr[sizeOfPtr-left], left);
222 if (i < 0) {
223 _gnutls_read_log( "READ: %d returned from %d, errno=%d\n", i, fd, errno);
225 if (errno == EAGAIN || errno == EINTR) {
226 if (sizeOfPtr-left > 0) {
228 _gnutls_read_log( "READ: returning %d bytes from %d\n", sizeOfPtr-left, fd);
230 goto finish;
232 gnutls_assert();
234 return RET(errno);
235 } else {
236 gnutls_assert();
237 return GNUTLS_E_PULL_ERROR;
239 } else {
241 _gnutls_read_log( "READ: Got %d bytes from %d\n", i, fd);
243 if (i == 0)
244 break; /* EOF */
247 left -= i;
251 finish:
253 #ifdef READ_DEBUG
254 _gnutls_read_log( "READ: read %d bytes from %d\n", (sizeOfPtr-left), fd);
255 for (x=0;x<((sizeOfPtr-left)/16)+1;x++) {
256 _gnutls_read_log( "%.4x - ",x);
257 for (j=0;j<16;j++) {
258 if (sum<(sizeOfPtr-left)) {
259 _gnutls_read_log( "%.2x ", ((unsigned char*)ptr)[sum++]);
262 _gnutls_read_log( "\n");
265 #endif
268 return (sizeOfPtr - left);
272 #define RCVLOWAT state->gnutls_internals.lowat
274 /* This function is only used with berkeley style sockets.
275 * Clears the peeked data (read with MSG_PEEK).
277 int _gnutls_io_clear_peeked_data( GNUTLS_STATE state) {
278 char *peekdata = NULL;
279 int ret, sum;
281 if (state->gnutls_internals.have_peeked_data==0 || RCVLOWAT==0)
282 return 0;
284 peekdata = gnutls_alloca( RCVLOWAT);
285 if (peekdata==NULL) {
286 gnutls_assert();
287 return GNUTLS_E_MEMORY_ERROR;
290 /* this was already read by using MSG_PEEK - so it shouldn't fail */
291 sum = 0;
292 do { /* we need this to finish now */
293 ret = _gnutls_read( state, peekdata, RCVLOWAT-sum, 0);
294 if (ret > 0) sum+=ret;
295 } while( ret==GNUTLS_E_INTERRUPTED || ret==GNUTLS_E_AGAIN || sum < RCVLOWAT);
297 gnutls_afree(peekdata);
299 if (ret < 0) {
300 gnutls_assert();
301 return ret;
304 state->gnutls_internals.have_peeked_data=0;
306 return 0;
310 void _gnutls_io_clear_read_buffer( GNUTLS_STATE state) {
311 state->gnutls_internals.record_recv_buffer.size = 0;
314 /* This function is like recv(with MSG_PEEK). But it does not return -1 on error.
315 * It does return gnutls_errno instead.
316 * This function reads data from the socket and keeps them in a buffer, of up to
317 * MAX_RECV_SIZE.
319 * sizeOfPtr should be unsigned.
321 * This is not a general purpose function. It returns EXACTLY the data requested,
322 * which are stored in a local (in the state) buffer. A pointer (iptr) to this buffer is returned.
325 ssize_t _gnutls_io_read_buffered( GNUTLS_STATE state, opaque **iptr, size_t sizeOfPtr, ContentType recv_type)
327 ssize_t ret=0, ret2=0;
328 int min, buf_pos;
329 char *buf;
330 int recvlowat = RCVLOWAT;
331 int recvdata, alloc_size;
333 *iptr = state->gnutls_internals.record_recv_buffer.data;
335 if ( sizeOfPtr > MAX_RECV_SIZE || sizeOfPtr == 0
336 || (state->gnutls_internals.record_recv_buffer.size+sizeOfPtr) > MAX_RECV_SIZE) {
337 gnutls_assert(); /* internal error */
338 return GNUTLS_E_INVALID_PARAMETERS;
341 /* leave peeked data to the kernel space only if application data
342 * is received and we don't have any peeked
343 * data in gnutls state.
345 if ( recv_type != GNUTLS_APPLICATION_DATA
346 && state->gnutls_internals.have_peeked_data==0)
347 recvlowat = 0;
350 /* calculate the actual size, ie. get the minimum of the
351 * buffered data and the requested data.
353 min = GMIN( state->gnutls_internals.record_recv_buffer.size, sizeOfPtr);
354 if ( min > 0) {
355 /* if we have enough buffered data
356 * then just return them.
358 if ( min == sizeOfPtr) {
359 return min;
363 /* min is over zero. recvdata is the data we must
364 * receive in order to return the requested data.
366 recvdata = sizeOfPtr - min;
368 /* Allocate the data required to store the new packet.
371 alloc_size = recvdata+state->gnutls_internals.record_recv_buffer.size;
372 state->gnutls_internals.record_recv_buffer.data = gnutls_realloc_fast(
373 state->gnutls_internals.record_recv_buffer.data, alloc_size);
374 if ( state->gnutls_internals.record_recv_buffer.data==NULL) {
375 gnutls_assert();
376 return GNUTLS_E_MEMORY_ERROR;
379 buf_pos = state->gnutls_internals.record_recv_buffer.size;
380 buf = state->gnutls_internals.record_recv_buffer.data;
381 *iptr = buf;
383 /* READ DATA - but leave RCVLOWAT bytes in the kernel buffer.
385 if ( recvdata - recvlowat > 0) {
386 ret = _gnutls_read( state, &buf[buf_pos], recvdata - recvlowat, 0);
388 /* return immediately if we got an interrupt or eagain
389 * error.
391 if (ret < 0 && gnutls_error_is_fatal(ret)==0) {
392 return ret;
396 /* copy fresh data to our buffer.
398 if (ret > 0) {
399 _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);
400 state->gnutls_internals.record_recv_buffer.size += ret;
403 buf_pos = state->gnutls_internals.record_recv_buffer.size;
405 /* This is hack in order for select to work. Just leave recvlowat data,
406 * into the kernel buffer (using a read with MSG_PEEK), thus making
407 * select think, that the socket is ready for reading.
408 * MSG_PEEK is only used with berkeley style sockets.
410 if (ret == (recvdata - recvlowat) && recvlowat > 0) {
411 ret2 = _gnutls_read( state, &buf[buf_pos], recvlowat, MSG_PEEK);
413 if (ret2 < 0 && gnutls_error_is_fatal(ret2)==0) {
414 return ret2;
417 if (ret2 > 0) {
418 _gnutls_read_log("RB-PEEK: Read %d bytes in PEEK MODE.\n", ret2);
419 _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);
420 state->gnutls_internals.have_peeked_data = 1;
421 state->gnutls_internals.record_recv_buffer.size += ret2;
426 if (ret < 0 || ret2 < 0) {
427 gnutls_assert();
428 /* that's because they are initilized to 0 */
429 return GMIN(ret, ret2);
432 ret += ret2;
434 if (ret > 0 && ret < recvlowat) {
435 gnutls_assert();
436 return GNUTLS_E_AGAIN;
439 if (ret==0) { /* EOF */
440 gnutls_assert();
441 return 0;
444 ret = state->gnutls_internals.record_recv_buffer.size;
446 if ((ret > 0) && (ret < sizeOfPtr)) {
447 /* Short Read */
448 gnutls_assert();
449 return GNUTLS_E_AGAIN;
450 } else {
451 return ret;
456 /* These two functions are used to insert data to the send buffer of the handshake or
457 * record protocol. The send buffer is kept if a send is interrupted and we need to keep
458 * the data left to sent, in order to send them later.
461 #define MEMSUB(x,y) (x-y)
463 inline
464 static int _gnutls_buffer_insert( gnutls_datum * buffer, const opaque* _data, int data_size) {
466 if ( ( MEMSUB(_data, buffer->data) >= 0) && (MEMSUB(_data, buffer->data) < buffer->size) ) {
467 /* the given _data is part of the buffer.
469 if (data_size > buffer->size) {
470 gnutls_assert();
471 /* this shouldn't have happened */
472 return GNUTLS_E_UNKNOWN_ERROR;
475 if (_data==buffer->data) { /* then don't even memmove */
476 buffer->size = data_size;
477 return 0;
480 memmove( buffer->data, _data, data_size);
481 buffer->size = data_size;
483 return 0;
487 buffer->data = gnutls_realloc_fast( buffer->data, data_size);
488 buffer->size = data_size;
490 if (buffer->data == NULL) {
491 gnutls_assert();
492 return GNUTLS_E_MEMORY_ERROR;
495 memcpy( buffer->data, _data, data_size);
497 return 0;
500 inline
501 static int _gnutls_buffer_get( gnutls_datum * buffer, const opaque ** ptr, size_t *ptr_size) {
502 *ptr_size = buffer->size;
503 *ptr = buffer->data;
505 return 0;
509 /* This function is like write. But it does not return -1 on error.
510 * It does return gnutls_errno instead.
512 * In case of E_AGAIN and E_INTERRUPTED errors, you must call gnutls_write_flush(),
513 * until it returns ok (0).
515 * We need to push exactly the data in n, since we cannot send less
516 * data. In TLS the peer must receive the whole packet in order
517 * to decrypt and verify the integrity.
520 ssize_t _gnutls_io_write_buffered( GNUTLS_STATE state, const void *iptr, size_t n)
522 size_t left;
523 #ifdef WRITE_DEBUG
524 int j,x, sum=0;
525 #endif
526 ssize_t retval, i;
527 const opaque * ptr;
528 int ret;
529 GNUTLS_TRANSPORT_PTR fd = state->gnutls_internals.transport_ptr;
531 ptr = iptr;
533 /* In case the previous write was interrupted, check if the
534 * iptr != NULL and we have data in the buffer.
535 * If this is true then return an error.
537 if (state->gnutls_internals.record_send_buffer.size > 0 && iptr != NULL) {
538 gnutls_assert();
539 return GNUTLS_E_INVALID_PARAMETERS;
542 /* If data in the buffer exist
544 if (iptr == NULL) {
545 /* checking is handled above */
546 ret = _gnutls_buffer_get( &state->gnutls_internals.record_send_buffer, &ptr, &n);
547 if (ret < 0) {
548 gnutls_assert();
549 return retval;
552 _gnutls_write_log( "WRITE: Restoring old write. (%d bytes to send)\n", n);
555 _gnutls_write_log( "WRITE: Will write %d bytes to %d.\n", n, fd);
557 i = 0;
558 left = n;
559 while (left > 0) {
561 if (state->gnutls_internals._gnutls_push_func==NULL)
562 i = send(fd, &ptr[n-left], left, 0);
563 else
564 i = state->gnutls_internals._gnutls_push_func(fd, &ptr[n-left], left);
566 if (i == -1) {
567 if (errno == EAGAIN || errno == EINTR) {
568 state->gnutls_internals.record_send_buffer_prev_size += n - left;
570 retval = _gnutls_buffer_insert( &state->gnutls_internals.record_send_buffer, &ptr[n-left], left);
571 if (retval < 0) {
572 gnutls_assert();
573 return retval;
576 _gnutls_write_log( "WRITE: Interrupted. Stored %d bytes to buffer. Already sent %d bytes.\n", left, n-left);
578 retval = RET(errno);
580 return retval;
581 } else {
582 gnutls_assert();
583 return GNUTLS_E_PUSH_ERROR;
586 left -= i;
588 #ifdef WRITE_DEBUG
589 _gnutls_write_log( "WRITE: wrote %d bytes to %d. Left %d bytes. Total %d bytes.\n", i, fd, left, n);
590 for (x=0;x<((i)/16)+1;x++) {
591 if (sum>n-left)
592 break;
594 _gnutls_write_log( "%.4x - ",x);
595 for (j=0;j<16;j++) {
596 if (sum<n-left) {
597 _gnutls_write_log( "%.2x ", ((unsigned char*)ptr)[sum++]);
598 } else break;
600 _gnutls_write_log( "\n");
602 _gnutls_write_log( "\n");
603 #endif
607 retval = n + state->gnutls_internals.record_send_buffer_prev_size;
609 state->gnutls_internals.record_send_buffer.size = 0;
610 state->gnutls_internals.record_send_buffer_prev_size = 0;
612 return retval;
616 /* This is exactly like write_buffered, but will use two buffers to read
617 * from.
619 ssize_t _gnutls_io_write_buffered2( GNUTLS_STATE state, const void *iptr, size_t n, const void* iptr2, size_t n2)
622 if (n==0) {
623 return _gnutls_io_write_buffered( state, iptr2, n2);
624 } else {
625 opaque* sptr;
626 ssize_t ret;
628 sptr = gnutls_alloca( n+n2);
629 if (sptr==NULL) {
630 gnutls_assert();
631 return GNUTLS_E_MEMORY_ERROR;
634 memcpy( sptr, iptr, n);
635 memcpy( &sptr[n], iptr2, n2);
637 ret = _gnutls_io_write_buffered( state, sptr, n+n2);
638 gnutls_afree( sptr);
640 return ret;
645 /* This function writes the data that are left in the
646 * TLS write buffer (ie. because the previous write was
647 * interrupted.
649 ssize_t _gnutls_io_write_flush( GNUTLS_STATE state)
651 ssize_t ret;
653 if (state->gnutls_internals.record_send_buffer.size == 0)
654 return 0; /* done */
656 ret = _gnutls_io_write_buffered( state, NULL, 0);
657 _gnutls_write_log("WRITE FLUSH: %d [buffer: %d]\n", ret, state->gnutls_internals.record_send_buffer.size);
659 return ret;
662 /* This function writes the data that are left in the
663 * Handshake write buffer (ie. because the previous write was
664 * interrupted.
666 ssize_t _gnutls_handshake_io_write_flush( GNUTLS_STATE state)
668 ssize_t ret;
669 ret = _gnutls_handshake_io_send_int( state, 0, 0, NULL, 0);
670 if (ret < 0) {
671 gnutls_assert();
672 return ret;
675 _gnutls_write_log("HANDSHAKE_FLUSH: written[1] %d bytes\n", ret);
677 if (state->gnutls_internals.handshake_send_buffer.size == 0) {
678 ret = state->gnutls_internals.handshake_send_buffer_prev_size; /* done */
679 state->gnutls_internals.handshake_send_buffer_prev_size = 0;
680 state->gnutls_internals.handshake_send_buffer.size = 0;
682 return ret;
685 return ret;
689 /* This is a send function for the gnutls handshake
690 * protocol. Just makes sure that all data have been sent.
692 ssize_t _gnutls_handshake_io_send_int( GNUTLS_STATE state, ContentType type, HandshakeType htype, const void *iptr, size_t n)
694 size_t left;
695 ssize_t i = 0, ret=0;
696 const opaque *ptr;
697 ssize_t retval = 0;
699 ptr = iptr;
701 if (state->gnutls_internals.handshake_send_buffer.size > 0 && ptr==NULL && n == 0) {
702 /* resuming previously interrupted write
704 gnutls_assert();
705 ret = _gnutls_buffer_get( &state->gnutls_internals.handshake_send_buffer, &ptr, &n);
706 if (ret < 0) {
707 gnutls_assert();
708 return retval;
711 type = state->gnutls_internals.handshake_send_buffer_type;
712 htype = state->gnutls_internals.handshake_send_buffer_htype;
714 } else if (state->gnutls_internals.handshake_send_buffer.size > 0) {
715 gnutls_assert();
716 return GNUTLS_E_UNKNOWN_ERROR;
717 } else {
718 #ifdef WRITE_DEBUG
719 size_t sum=0, x, j;
721 _gnutls_write_log( "HWRITE: will write %d bytes to %d.\n", n, gnutls_transport_get_ptr(state));
722 for (x=0;x<((n)/16)+1;x++) {
723 if (sum>n)
724 break;
726 _gnutls_write_log( "%.4x - ",x);
727 for (j=0;j<16;j++) {
728 if (sum<n) {
729 _gnutls_write_log( "%.2x ", ((unsigned char*)ptr)[sum++]);
730 } else break;
732 _gnutls_write_log( "\n");
734 _gnutls_write_log( "\n");
735 #endif
740 if (n==0) { /* if we have no data to send */
741 gnutls_assert();
742 return 0;
743 } else if (ptr==NULL) {
744 gnutls_assert();
745 return GNUTLS_E_UNKNOWN_ERROR;
749 left = n;
750 while (left > 0) {
751 ret = gnutls_send_int( state, type, htype, &ptr[n-left], left);
753 if (ret <= 0) {
754 if (ret==0) {
755 gnutls_assert();
756 ret = GNUTLS_E_UNKNOWN_ERROR;
759 if ( left > 0 && (ret==GNUTLS_E_INTERRUPTED || ret==GNUTLS_E_AGAIN)) {
760 gnutls_assert();
762 retval = _gnutls_buffer_insert( &state->gnutls_internals.handshake_send_buffer, &ptr[n-left], left);
763 if (retval < 0) {
764 gnutls_assert();
765 return retval;
768 state->gnutls_internals.handshake_send_buffer_prev_size += n-left;
770 state->gnutls_internals.handshake_send_buffer_type = type;
771 state->gnutls_internals.handshake_send_buffer_htype = htype;
773 } else {
774 state->gnutls_internals.handshake_send_buffer_prev_size = 0;
775 state->gnutls_internals.handshake_send_buffer.size = 0;
778 gnutls_assert();
779 return ret;
781 i = ret;
782 left -= i;
785 retval = n + state->gnutls_internals.handshake_send_buffer_prev_size;
787 state->gnutls_internals.handshake_send_buffer.size = 0;
788 state->gnutls_internals.handshake_send_buffer_prev_size = 0;
790 return retval;
794 /* This is a receive function for the gnutls handshake
795 * protocol. Makes sure that we have received all data.
797 ssize_t _gnutls_handshake_io_recv_int( GNUTLS_STATE state, ContentType type, HandshakeType htype, void *iptr, size_t sizeOfPtr)
799 size_t left;
800 ssize_t i;
801 char *ptr;
802 size_t dsize;
804 ptr = iptr;
805 left = sizeOfPtr;
807 if (sizeOfPtr == 0 || iptr == NULL) {
808 gnutls_assert();
809 return GNUTLS_E_INVALID_PARAMETERS;
812 if (state->gnutls_internals.handshake_recv_buffer.size > 0) {
813 /* if we have already received some data */
814 if (sizeOfPtr <= state->gnutls_internals.handshake_recv_buffer.size) {
815 /* if requested less data then return it.
817 gnutls_assert();
818 memcpy( iptr, state->gnutls_internals.handshake_recv_buffer.data, sizeOfPtr);
820 state->gnutls_internals.handshake_recv_buffer.size -= sizeOfPtr;
822 memmove( state->gnutls_internals.handshake_recv_buffer.data,
823 &state->gnutls_internals.handshake_recv_buffer.data[sizeOfPtr],
824 state->gnutls_internals.handshake_recv_buffer.size);
826 return sizeOfPtr;
828 gnutls_assert();
829 memcpy( iptr, state->gnutls_internals.handshake_recv_buffer.data, state->gnutls_internals.handshake_recv_buffer.size);
831 htype = state->gnutls_internals.handshake_recv_buffer_htype;
832 type = state->gnutls_internals.handshake_recv_buffer_type;
834 left -= state->gnutls_internals.handshake_recv_buffer.size;
836 state->gnutls_internals.handshake_recv_buffer.size = 0;
839 while (left > 0) {
840 dsize = sizeOfPtr - left;
841 i = gnutls_recv_int( state, type, htype, &ptr[dsize], left);
842 if (i < 0) {
844 if (dsize > 0 && (i==GNUTLS_E_INTERRUPTED || i==GNUTLS_E_AGAIN)) {
845 gnutls_assert();
847 state->gnutls_internals.handshake_recv_buffer.data = gnutls_realloc_fast(
848 state->gnutls_internals.handshake_recv_buffer.data, dsize);
849 if (state->gnutls_internals.handshake_recv_buffer.data==NULL) {
850 gnutls_assert();
851 return GNUTLS_E_MEMORY_ERROR;
854 memcpy( state->gnutls_internals.handshake_recv_buffer.data, iptr, dsize);
856 state->gnutls_internals.handshake_recv_buffer_htype = htype;
857 state->gnutls_internals.handshake_recv_buffer_type = type;
859 state->gnutls_internals.handshake_recv_buffer.size = dsize;
860 } else
861 state->gnutls_internals.handshake_recv_buffer.size = 0;
863 gnutls_assert();
865 return i;
866 } else {
867 if (i == 0)
868 break; /* EOF */
871 left -= i;
875 state->gnutls_internals.handshake_recv_buffer.size = 0;
877 return sizeOfPtr - left;
880 /* Buffer for handshake packets. Keeps the packets in order
881 * for finished messages to use them. Used in HMAC calculation
882 * and finished messages.
884 int _gnutls_handshake_buffer_put( GNUTLS_STATE state, char *data, int length)
887 if (length==0) return 0;
889 if ( (state->gnutls_internals.max_handshake_data_buffer_size > 0) &&
890 ((length+state->gnutls_internals.handshake_hash_buffer.size) >
891 state->gnutls_internals.max_handshake_data_buffer_size)) {
892 gnutls_assert();
893 return GNUTLS_E_MEMORY_ERROR;
896 _gnutls_buffers_log( "BUF[HSK]: Inserted %d bytes of Data\n", length);
898 if ( gnutls_datum_append( &state->gnutls_internals.handshake_hash_buffer,
899 data, length) < 0) {
900 gnutls_assert();
901 return GNUTLS_E_MEMORY_ERROR;
904 return 0;
907 int _gnutls_handshake_buffer_get_size( GNUTLS_STATE state)
910 return state->gnutls_internals.handshake_hash_buffer.size;
913 /* this function does not touch the buffer
914 * and returns data from it (peek mode!)
916 int _gnutls_handshake_buffer_peek( GNUTLS_STATE state, char *data, int length)
918 if (length > state->gnutls_internals.handshake_hash_buffer.size) {
919 length = state->gnutls_internals.handshake_hash_buffer.size;
922 _gnutls_buffers_log( "BUF[HSK]: Peeked %d bytes of Data\n", length);
924 memcpy(data, state->gnutls_internals.handshake_hash_buffer.data, length);
925 return length;
928 /* this function does not touch the buffer
929 * and returns data from it (peek mode!)
931 int _gnutls_handshake_buffer_get_ptr( GNUTLS_STATE state, char **data_ptr, int *length)
933 if (length!=NULL)
934 *length = state->gnutls_internals.handshake_hash_buffer.size;
936 _gnutls_buffers_log( "BUF[HSK]: Peeded %d bytes of Data\n", length);
938 if (data_ptr!=NULL)
939 *data_ptr = state->gnutls_internals.handshake_hash_buffer.data;
941 return 0;
944 /* Does not free the buffer
946 int _gnutls_handshake_buffer_empty( GNUTLS_STATE state)
949 _gnutls_buffers_log( "BUF[HSK]: Emptied buffer\n");
951 state->gnutls_internals.handshake_hash_buffer.size = 0;
953 return 0;
957 int _gnutls_handshake_buffer_clear( GNUTLS_STATE state)
960 _gnutls_buffers_log( "BUF[HSK]: Cleared Data from buffer\n");
962 state->gnutls_internals.handshake_hash_buffer.size = 0;
963 if (state->gnutls_internals.handshake_hash_buffer.data!=NULL)
964 gnutls_free(state->gnutls_internals.handshake_hash_buffer.data);
965 state->gnutls_internals.handshake_hash_buffer.data = NULL;
967 return 0;