summaryrefslogtreecommitdiff
path: root/lib/gnutls_buffers.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/gnutls_buffers.c')
-rw-r--r--lib/gnutls_buffers.c156
1 files changed, 108 insertions, 48 deletions
diff --git a/lib/gnutls_buffers.c b/lib/gnutls_buffers.c
index 64a9ee9775..e5c712a8ef 100644
--- a/lib/gnutls_buffers.c
+++ b/lib/gnutls_buffers.c
@@ -1,4 +1,3 @@
-#define IO_DEBUG 5
/*
* Copyright (C) 2000,2001 Nikos Mavroyanopoulos
*
@@ -38,6 +37,12 @@
# define EAGAIN EWOULDBLOCK
#endif
+inline
+static int RET( int err) {
+ if (err==EAGAIN) return GNUTLS_E_AGAIN;
+ return GNUTLS_E_INTERRUPTED;
+}
+
#ifdef IO_DEBUG
# include <io_debug.h>
#endif
@@ -206,8 +211,8 @@ static ssize_t _gnutls_read( SOCKET fd, GNUTLS_STATE state, void *iptr, size_t s
goto finish;
}
gnutls_assert();
- if (errno==EAGAIN) return GNUTLS_E_AGAIN;
- else return GNUTLS_E_INTERRUPTED;
+
+ return RET(errno);
} else {
gnutls_assert();
return GNUTLS_E_PULL_ERROR;
@@ -440,6 +445,58 @@ ssize_t _gnutls_read_buffered( int fd, GNUTLS_STATE state, opaque **iptr, size_t
}
}
+
+/* These two functions are used to insert data to the send buffer of the handshake or
+ * record protocol. The send buffer is kept if a send is interrupted and we need to keep
+ * the data left to sent, in order to send them later.
+ */
+
+#define MEMSUB(x,y) (x-y)
+
+inline
+static int _gnutls_buffer_insert( gnutls_datum * buffer, const opaque* _data, int data_size) {
+
+ if ( ( MEMSUB(_data, buffer->data) >= 0) && (MEMSUB(_data, buffer->data) < buffer->size) ) {
+ /* the given _data is part of the buffer.
+ */
+ if (data_size > buffer->size) {
+ gnutls_assert();
+ /* this shouldn't have happened */
+ return GNUTLS_E_UNKNOWN_ERROR;
+ }
+
+ if (_data==buffer->data) { /* then don't even memmove */
+ buffer->size = data_size;
+ return 0;
+ }
+
+ memmove( buffer->data, _data, data_size);
+ buffer->size = data_size;
+
+ return 0;
+ }
+
+ buffer->data = gnutls_realloc_fast( buffer->data, data_size);
+ buffer->size = data_size;
+
+ if (buffer->data == NULL) {
+ gnutls_assert();
+ return GNUTLS_E_MEMORY_ERROR;
+ }
+
+ memcpy( buffer->data, _data, data_size);
+
+ return 0;
+}
+
+inline
+static int _gnutls_buffer_get( gnutls_datum * buffer, const opaque ** ptr, size_t *ptr_size) {
+ *ptr_size = buffer->size;
+ *ptr = buffer->data;
+
+ return 0;
+}
+
/* This function is like write. But it does not return -1 on error.
* It does return gnutls_errno instead.
*
@@ -459,8 +516,8 @@ ssize_t _gnutls_write_buffered(SOCKET fd, GNUTLS_STATE state, const void *iptr,
#endif
ssize_t retval, i;
const opaque * ptr;
- int ptrcopy; /* indicates whether to copy from the ptr */
-
+ int ret;
+
ptr = iptr;
/* In case the previous write was interrupted, check if the
@@ -474,12 +531,13 @@ ssize_t _gnutls_write_buffered(SOCKET fd, GNUTLS_STATE state, const void *iptr,
/* If data in the buffer exist
*/
- ptrcopy = 1;
if (iptr == NULL) {
/* checking is handled above */
- ptr = state->gnutls_internals.send_buffer.data;
- n = state->gnutls_internals.send_buffer.size;
- ptrcopy = 0;
+ ret = _gnutls_buffer_get( &state->gnutls_internals.send_buffer, &ptr, &n);
+ if (ret < 0) {
+ gnutls_assert();
+ return retval;
+ }
#ifdef WRITE_DEBUG
_gnutls_log( "WRITE: Restoring old write. (%d bytes to send)\n", n);
#endif
@@ -502,25 +560,16 @@ ssize_t _gnutls_write_buffered(SOCKET fd, GNUTLS_STATE state, const void *iptr,
if (errno == EAGAIN || errno == EINTR) {
state->gnutls_internals.send_buffer_prev_size += n - left;
- state->gnutls_internals.send_buffer.data = gnutls_realloc_fast(
- state->gnutls_internals.send_buffer.data, left);
-
- if (state->gnutls_internals.send_buffer.data == NULL) {
+ retval = _gnutls_buffer_insert( &state->gnutls_internals.send_buffer, &ptr[n-left], left);
+ if (retval < 0) {
gnutls_assert();
- return GNUTLS_E_MEMORY_ERROR;
+ return retval;
}
- state->gnutls_internals.send_buffer.size = left;
-
- if (ptrcopy != 0)
- memcpy( state->gnutls_internals.send_buffer.data, &ptr[n-left], left);
- else
- memmove( state->gnutls_internals.send_buffer.data, &state->gnutls_internals.send_buffer.data[n-left], left);
-
+
#ifdef WRITE_DEBUG
_gnutls_log( "WRITE: Interrupted. Stored %d bytes to buffer. Already sent %d bytes.\n", left, n-left);
#endif
- if (errno==EAGAIN) retval = GNUTLS_E_AGAIN;
- else retval = GNUTLS_E_INTERRUPTED;
+ retval = RET(errno);
return retval;
} else {
@@ -584,7 +633,6 @@ ssize_t _gnutls_write_flush(SOCKET fd, GNUTLS_STATE state)
ssize_t _gnutls_handshake_write_flush(SOCKET fd, GNUTLS_STATE state)
{
ssize_t ret;
-
ret = _gnutls_handshake_send_int(fd, state, 0, 0, NULL, 0);
if (ret < 0) {
gnutls_assert();
@@ -609,41 +657,63 @@ ssize_t _gnutls_handshake_write_flush(SOCKET fd, GNUTLS_STATE state)
/* This is a send function for the gnutls handshake
* protocol. Just makes sure that all data have been sent.
*/
-ssize_t _gnutls_handshake_send_int( SOCKET fd, GNUTLS_STATE state, ContentType type, HandshakeType htype, void *iptr, size_t n)
+ssize_t _gnutls_handshake_send_int( SOCKET fd, GNUTLS_STATE state, ContentType type, HandshakeType htype, const void *iptr, size_t n)
{
size_t left;
ssize_t i = 0, ret=0;
- opaque *ptr;
- int ptrcopy;
+ const opaque *ptr;
ssize_t retval = 0;
+
+ ptr = iptr;
- ptrcopy = 1;
- if (state->gnutls_internals.handshake_send_buffer.size > 0 && iptr==NULL && n == 0) {
+ if (state->gnutls_internals.handshake_send_buffer.size > 0 && ptr==NULL && n == 0) {
/* resuming previously interrupted write
*/
gnutls_assert();
- n = state->gnutls_internals.handshake_send_buffer.size;
- iptr = state->gnutls_internals.handshake_send_buffer.data;
+ ret = _gnutls_buffer_get( &state->gnutls_internals.handshake_send_buffer, &ptr, &n);
+ if (ret < 0) {
+ gnutls_assert();
+ return retval;
+ }
type = state->gnutls_internals.handshake_send_buffer_type;
htype = state->gnutls_internals.handshake_send_buffer_htype;
- ptrcopy = 0;
} else if (state->gnutls_internals.handshake_send_buffer.size > 0) {
gnutls_assert();
return GNUTLS_E_UNKNOWN_ERROR;
+ } else {
+#ifdef WRITE_DEBUG
+ size_t sum=0, x, j;
+
+ _gnutls_log( "HWRITE: will write %d bytes to %d.\n", n, fd);
+ for (x=0;x<((n)/16)+1;x++) {
+ if (sum>n)
+ break;
+
+ _gnutls_log( "%.4x - ",x);
+ for (j=0;j<16;j++) {
+ if (sum<n) {
+ _gnutls_log( "%.2x ", ((unsigned char*)ptr)[sum++]);
+ } else break;
+ }
+ _gnutls_log( "\n");
+ }
+ _gnutls_log( "\n");
+#endif
+
+
}
if (n==0) { /* if we have no data to send */
gnutls_assert();
return 0;
- } else if (iptr==NULL) {
+ } else if (ptr==NULL) {
gnutls_assert();
return GNUTLS_E_UNKNOWN_ERROR;
}
- ptr = iptr;
left = n;
while (left > 0) {
ret = gnutls_send_int(fd, state, type, htype, &ptr[n-left], left);
@@ -657,22 +727,12 @@ ssize_t _gnutls_handshake_send_int( SOCKET fd, GNUTLS_STATE state, ContentType t
if ( left > 0 && (ret==GNUTLS_E_INTERRUPTED || ret==GNUTLS_E_AGAIN)) {
gnutls_assert();
- state->gnutls_internals.handshake_send_buffer.data = gnutls_realloc_fast(
- state->gnutls_internals.handshake_send_buffer.data, left);
-
- if (state->gnutls_internals.handshake_send_buffer.data==NULL) {
+ retval = _gnutls_buffer_insert( &state->gnutls_internals.handshake_send_buffer, &ptr[n-left], left);
+ if (retval < 0) {
gnutls_assert();
- return GNUTLS_E_MEMORY_ERROR;
+ return retval;
}
-
- if (ptrcopy!=0)
- memcpy( state->gnutls_internals.handshake_send_buffer.data, &ptr[n-left], left);
- else
- if (n-left > 0)
- memmove( state->gnutls_internals.handshake_send_buffer.data,
- &state->gnutls_internals.handshake_send_buffer.data[n-left], left);
-
- state->gnutls_internals.handshake_send_buffer.size = left;
+
state->gnutls_internals.handshake_send_buffer_prev_size += n-left;
state->gnutls_internals.handshake_send_buffer_type = type;