diff options
author | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2001-10-22 12:51:54 +0000 |
---|---|---|
committer | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2001-10-22 12:51:54 +0000 |
commit | fd4bc2464998bf9118523c03158a2e3f658f89b5 (patch) | |
tree | dbb0efba16af8302b2c9c44b899897288f54c1ea | |
parent | 77e5bcb42d91f612ae049469184e6b66291d2982 (diff) | |
download | gnutls-fd4bc2464998bf9118523c03158a2e3f658f89b5.tar.gz |
updated/fixed the handling of interrupted writes
-rw-r--r-- | lib/gnutls_buffers.c | 57 | ||||
-rw-r--r-- | lib/gnutls_buffers.h | 2 | ||||
-rw-r--r-- | lib/gnutls_int.h | 12 | ||||
-rw-r--r-- | lib/gnutls_record.c | 109 | ||||
-rw-r--r-- | src/serv.c | 4 |
5 files changed, 102 insertions, 82 deletions
diff --git a/lib/gnutls_buffers.c b/lib/gnutls_buffers.c index 91b6913f4c..2b0d05099a 100644 --- a/lib/gnutls_buffers.c +++ b/lib/gnutls_buffers.c @@ -360,7 +360,6 @@ ssize_t _gnutls_read_buffered( int fd, GNUTLS_STATE state, opaque **iptr, size_t } } - /* This function is like write. But it does not return -1 on error. * It does return gnutls_errno instead. * @@ -372,43 +371,58 @@ ssize_t _gnutls_read_buffered( int fd, GNUTLS_STATE state, opaque **iptr, size_t * to decrypt and verify the integrity. * */ -ssize_t _gnutls_write(int fd, GNUTLS_STATE state, const void *iptr, size_t n, int flags) +ssize_t _gnutls_write_buffered(int fd, GNUTLS_STATE state, const void *iptr, size_t n) { size_t left; #ifdef WRITE_DEBUG int j,x, sum=0; #endif - ssize_t i = 0; - size_t start_pos = 0; - const char *ptr = iptr; + ssize_t retval, i; + const opaque * ptr; + ptr = iptr; + /* In case the previous write was interrupted, check if the - * current data have the same size with the previous. - * If they haven't return an error. + * iptr != NULL and we have data in the buffer. + * If this is true then return an error. */ - if (state->gnutls_internals.send_buffer_ind[1] > 0 && state->gnutls_internals.send_buffer_ind[1] != n) { + if (state->gnutls_internals.send_buffer.size > 0 && iptr != NULL) { gnutls_assert(); return GNUTLS_E_INVALID_PARAMETERS; - } else if (state->gnutls_internals.send_buffer_ind[1] > 0) { - /* send only the data we haven't send before. - */ - n -= state->gnutls_internals.send_buffer_ind[0]; - start_pos = state->gnutls_internals.send_buffer_ind[0]; } + /* If data in the buffer exist + */ + if (iptr == NULL) { + if ( state->gnutls_internals.send_buffer.size == 0) { + gnutls_assert(); + return GNUTLS_E_INVALID_PARAMETERS; + } else { + ptr = state->gnutls_internals.send_buffer.data; + n = state->gnutls_internals.send_buffer.size; + } + } + + i = 0; left = n; while (left > 0) { if (_gnutls_push_func==NULL) - i = send(fd, &ptr[start_pos+i], left, flags); + i = send(fd, &ptr[i], left, 0); else - i = _gnutls_push_func(fd, &ptr[start_pos+i], left); + i = _gnutls_push_func(fd, &ptr[i], left); if (i == -1) { if (errno == EAGAIN || errno == EINTR) { - state->gnutls_internals.send_buffer_ind[0] = n - left; - state->gnutls_internals.send_buffer_ind[1] = n; - gnutls_assert(); + 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) { + gnutls_assert(); + return GNUTLS_E_MEMORY_ERROR; + } + state->gnutls_internals.send_buffer.size = left; + memcpy( state->gnutls_internals.send_buffer.data, &ptr[n-left], left); #ifdef WRITE_DEBUG _gnutls_log( "WRITE: Interrupted. wrote %d bytes to %d. Left %d\n", n-left, fd, left); #endif @@ -423,7 +437,10 @@ ssize_t _gnutls_write(int fd, GNUTLS_STATE state, const void *iptr, size_t n, in left -= i; } - state->gnutls_internals.send_buffer_ind[0] = state->gnutls_internals.send_buffer_ind[1] = 0; + retval = n + state->gnutls_internals.send_buffer_prev_size; + + state->gnutls_internals.send_buffer.size = 0; + state->gnutls_internals.send_buffer_prev_size = 0; #ifdef WRITE_DEBUG _gnutls_log( "WRITE: wrote %d bytes to %d\n", n, fd); @@ -438,7 +455,7 @@ ssize_t _gnutls_write(int fd, GNUTLS_STATE state, const void *iptr, size_t n, in } #endif - return n; + return retval; } diff --git a/lib/gnutls_buffers.h b/lib/gnutls_buffers.h index 9297b6b182..e32ba97c87 100644 --- a/lib/gnutls_buffers.h +++ b/lib/gnutls_buffers.h @@ -25,7 +25,7 @@ ssize_t _gnutls_read_buffered(int fd, GNUTLS_STATE, opaque **iptr, size_t n, Con void _gnutls_read_clear_buffer( GNUTLS_STATE); int _gnutls_clear_peeked_data( SOCKET cd, GNUTLS_STATE state); -ssize_t _gnutls_write(int fd, GNUTLS_STATE, const void *iptr, size_t n, int ); +ssize_t _gnutls_write_buffered(int fd, GNUTLS_STATE, const void *iptr, size_t n ); /* used in SSL3 */ int gnutls_getHashDataFromBuffer( GNUTLS_STATE state, char *data, int length); diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h index c5460688f1..a8748d306e 100644 --- a/lib/gnutls_int.h +++ b/lib/gnutls_int.h @@ -25,8 +25,8 @@ #include <defines.h> /* -#define WRITE_DEBUG #define BUFFERS_DEBUG +#define WRITE_DEBUG #define HARD_DEBUG #define HANDSHAKE_DEBUG #define RECORD_DEBUG @@ -360,10 +360,12 @@ typedef struct { */ opaque recv_buffer_data[MAX_RECV_SIZE]; int recv_buffer_data_size; - int send_buffer_ind[2]; /* 0 holds the - * position last write was interrupted, - * and 1 holds the size of the last - * data requested to send. + gnutls_datum send_buffer; /* holds cached data + * for the gnutls_write_buffered() + * function. + */ + int send_buffer_prev_size; /* holds the + * data written in the previous runs. */ /* 0 if no peeked data was kept, 1 otherwise. diff --git a/lib/gnutls_record.c b/lib/gnutls_record.c index 472b78a854..730253f1e8 100644 --- a/lib/gnutls_record.c +++ b/lib/gnutls_record.c @@ -147,6 +147,7 @@ int gnutls_deinit(GNUTLS_STATE state) GNUTLS_FREE(state->gnutls_internals.buffer.data); GNUTLS_FREE(state->gnutls_internals.buffer_handshake.data); GNUTLS_FREE(state->gnutls_internals.hash_buffer.data); + GNUTLS_FREE(state->gnutls_internals.send_buffer.data); gnutls_clear_creds( state); @@ -407,10 +408,10 @@ int gnutls_bye(SOCKET cd, GNUTLS_STATE state, CloseRequest how) ssize_t gnutls_send_int(SOCKET cd, GNUTLS_STATE state, ContentType type, HandshakeType htype, const void *_data, size_t sizeofdata) { uint8 *cipher; - int i, cipher_size; - int ret = 0; - int iterations; - int Size; + const uint8 *ptr; + int cipher_size; + int ret = 0, retval = 0; + int Size, data2send; uint8 headers[5]; const uint8 *data=_data; GNUTLS_Version lver; @@ -423,14 +424,6 @@ ssize_t gnutls_send_int(SOCKET cd, GNUTLS_STATE state, ContentType type, Handsha return GNUTLS_E_INVALID_SESSION; } - if (sizeofdata < MAX_ENC_LEN) { - iterations = 1; - Size = sizeofdata; - } else { - iterations = sizeofdata / MAX_ENC_LEN; - Size = MAX_ENC_LEN; - } - headers[0]=type; if (htype==GNUTLS_CLIENT_HELLO) { /* then send the lowest @@ -454,22 +447,61 @@ ssize_t gnutls_send_int(SOCKET cd, GNUTLS_STATE state, ContentType type, Handsha (int) uint64touint32(&state->connection_state.write_sequence_number), _gnutls_packet2str(type), type, sizeofdata); #endif - for (i = 0; i < iterations; i++) { - cipher_size = _gnutls_encrypt( state, headers, RECORD_HEADER_SIZE, &data[i*Size], Size, &cipher, type); - if (cipher_size <= 0) { - gnutls_assert(); - if (cipher_size==0) cipher_size = GNUTLS_E_ENCRYPTION_FAILED; - return cipher_size; /* error */ + /* in this loop we encrypt all data that are a multiple + * of the MAC_ENC_LEN; + */ + data2send = sizeofdata; + ptr = data; + retval = 0; + + while( data2send != 0) { + + if (data2send - MAX_ENC_LEN >= 0) { + data2send -= MAX_ENC_LEN; + Size = MAX_ENC_LEN; + } else { + Size = data2send; + data2send = 0; } - - if (_gnutls_write(cd, state, cipher, cipher_size, 0) != cipher_size) { + + /* Only encrypt if we don't have data to send + * from the previous run. - probably interrupted. + */ + if (state->gnutls_internals.send_buffer.size == 0) { + cipher_size = _gnutls_encrypt( state, headers, RECORD_HEADER_SIZE, ptr, Size, &cipher, type); + if (cipher_size <= 0) { + gnutls_assert(); + if (cipher_size==0) cipher_size = GNUTLS_E_ENCRYPTION_FAILED; + return cipher_size; /* error */ + } + } else { + /* order write buffered to write + * the buffered data. + */ + cipher = NULL; + cipher_size = state->gnutls_internals.send_buffer.size + + state->gnutls_internals.send_buffer_prev_size; + } + + ptr += Size; + + if ( (ret=_gnutls_write_buffered(cd, state, cipher, cipher_size)) != cipher_size) { gnutls_free( cipher); + if ( ret<0 && gnutls_is_fatal_error(ret)==0) { + /* If we have sent any data then return + * that value. + */ + gnutls_assert(); + if (retval > 0) return retval; + return ret; + } state->gnutls_internals.valid_connection = VALID_FALSE; state->gnutls_internals.resumable = RESUME_FALSE; gnutls_assert(); - return GNUTLS_E_UNABLE_SEND_DATA; + return ret; } + retval += Size; gnutls_free(cipher); #ifdef RECORD_DEBUG @@ -487,40 +519,7 @@ ssize_t gnutls_send_int(SOCKET cd, GNUTLS_STATE state, ContentType type, Handsha } - - /* rest of data - */ - if (iterations > 1) { - Size = sizeofdata % MAX_ENC_LEN; - cipher_size = _gnutls_encrypt( state, headers, RECORD_HEADER_SIZE, &data[i*Size], Size, &cipher, type); - if (cipher_size<=0) { - if (cipher_size == 0) cipher_size = GNUTLS_E_ENCRYPTION_FAILED; - gnutls_assert(); - return cipher_size; - } - - if (_gnutls_write(cd, state, cipher, cipher_size, 0) != cipher_size) { - gnutls_free(cipher); - state->gnutls_internals.valid_connection = VALID_FALSE; - state->gnutls_internals.resumable = RESUME_FALSE; - gnutls_assert(); - return GNUTLS_E_UNABLE_SEND_DATA; - } - - gnutls_free(cipher); - - /* increase sequence number - */ - if (uint64pp( &state->connection_state.write_sequence_number)!=0) { - state->gnutls_internals.valid_connection = VALID_FALSE; - gnutls_assert(); - return GNUTLS_E_RECORD_LIMIT_REACHED; - } - } - - ret += sizeofdata; - - return ret; + return retval; } /* This function is to be called if the handshake was successfully diff --git a/src/serv.c b/src/serv.c index 0ccde3d8cf..b8011ac056 100644 --- a/src/serv.c +++ b/src/serv.c @@ -444,8 +444,10 @@ int main(int argc, char **argv) if (ret > 0) { if (http == 0) { - gnutls_write(sd, state, buffer, + do { + ret = gnutls_write(sd, state, buffer, strlen(buffer)); + } while( ret==GNUTLS_E_INTERRUPTED || ret==GNUTLS_E_AGAIN); } else { strcpy( http_buffer, HTTP_BEGIN); peer_print_info(sd, state); |