diff options
author | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2001-10-22 20:14:40 +0000 |
---|---|---|
committer | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2001-10-22 20:14:40 +0000 |
commit | 74db0d2cc9e48309eacf1bb911c8cba00f83d4c6 (patch) | |
tree | 099a2d4722103e77217593d6a1cfc434a1097224 | |
parent | fd4bc2464998bf9118523c03158a2e3f658f89b5 (diff) | |
download | gnutls-74db0d2cc9e48309eacf1bb911c8cba00f83d4c6.tar.gz |
corrections for the gnutls_read_buffered() function.
-rw-r--r-- | lib/gnutls_buffers.c | 58 | ||||
-rw-r--r-- | lib/gnutls_record.c | 32 |
2 files changed, 61 insertions, 29 deletions
diff --git a/lib/gnutls_buffers.c b/lib/gnutls_buffers.c index 2b0d05099a..72f957b818 100644 --- a/lib/gnutls_buffers.c +++ b/lib/gnutls_buffers.c @@ -259,27 +259,28 @@ void _gnutls_read_clear_buffer( GNUTLS_STATE state) { ssize_t _gnutls_read_buffered( int fd, GNUTLS_STATE state, opaque **iptr, size_t sizeOfPtr, ContentType recv_type) { ssize_t ret=0, ret2=0; - int min; + int min, buf_pos; char *buf; int recvlowat = RCVLOWAT; int recvdata; *iptr = NULL; - if ( sizeOfPtr > MAX_RECV_SIZE || sizeOfPtr == 0) { + if ( sizeOfPtr > MAX_RECV_SIZE || sizeOfPtr == 0 || (state->gnutls_internals.recv_buffer_data_size+sizeOfPtr) > MAX_RECV_SIZE) { gnutls_assert(); /* internal error */ - return GNUTLS_E_UNKNOWN_ERROR; + return GNUTLS_E_INVALID_PARAMETERS; } /* leave peeked data to the kernel space only if application data * is received and we don't have any peeked * data in gnutls state. */ - if ( (recv_type != GNUTLS_APPLICATION_DATA) + if ( recv_type != GNUTLS_APPLICATION_DATA && state->gnutls_internals.have_peeked_data==0) recvlowat = 0; buf = state->gnutls_internals.recv_buffer_data; + buf_pos = state->gnutls_internals.recv_buffer_data_size; *iptr = buf; @@ -301,26 +302,55 @@ ssize_t _gnutls_read_buffered( int fd, GNUTLS_STATE state, opaque **iptr, size_t */ recvdata = sizeOfPtr - min; - /* read fresh data - but leave RCVLOWAT bytes in the kernel buffer. + + /* READ DATA - but leave RCVLOWAT bytes in the kernel buffer. */ if ( recvdata - recvlowat > 0) { - ret = _gnutls_read( fd, &buf[min], recvdata - recvlowat, 0); + ret = _gnutls_read( fd, &buf[buf_pos], recvdata - recvlowat, 0); /* return immediately if we got an interrupt or eagain * error. */ - if (ret < 0 && gnutls_is_fatal_error(ret)==0) + if (ret < 0 && gnutls_is_fatal_error(ret)==0) { return ret; + } } +#ifdef READ_DEBUG + if (ret > 0) + _gnutls_log("RB: Have %d bytes into buffer. Adding %d bytes.\nRB: Requested %d bytes\n", state->gnutls_internals.recv_buffer_data_size, ret, sizeOfPtr); +#endif + /* copy fresh data to our buffer. + */ + if (ret > 0) + state->gnutls_internals.recv_buffer_data_size += ret; + + + buf_pos = state->gnutls_internals.recv_buffer_data_size; + + /* This is hack in order for select to work. Just leave recvlowat data, + * into the kernel buffer (using a read with MSG_PEEK), thus making + * select think, that the socket is ready for reading + */ if (ret >= 0 && recvlowat > 0) { - ret2 = _gnutls_read( fd, &buf[min+ret], recvlowat, MSG_PEEK); + ret2 = _gnutls_read( fd, &buf[buf_pos], recvlowat, MSG_PEEK); - if (ret2 < 0 && gnutls_is_fatal_error(ret2)==0) + if (ret2 < 0 && gnutls_is_fatal_error(ret2)==0) { return ret2; + } - if (ret2 > 0) +#ifdef READ_DEBUG + if (ret2 > 0) { + _gnutls_log("RB-PEEK: Read %d bytes in PEEK MODE.\n", ret2); + _gnutls_log("RB-PEEK: Have %d bytes into buffer. Adding %d bytes.\nRB: Requested %d bytes\n", state->gnutls_internals.recv_buffer_data_size, ret2, sizeOfPtr); + } +#endif + + if (ret2 > 0) { state->gnutls_internals.have_peeked_data = 1; + state->gnutls_internals.recv_buffer_data_size += ret2; + + } } if (ret < 0 || ret2 < 0) { @@ -331,19 +361,11 @@ ssize_t _gnutls_read_buffered( int fd, GNUTLS_STATE state, opaque **iptr, size_t ret += ret2; -#ifdef READ_DEBUG - _gnutls_log("RB: Have %d bytes into buffer. Adding %d bytes.\nRB: Requested %d bytes\n", state->gnutls_internals.recv_buffer_data_size, ret, sizeOfPtr); -#endif - if (ret > 0 && ret < recvlowat) { gnutls_assert(); return GNUTLS_E_AGAIN; } - /* copy fresh data to our buffer. - */ - state->gnutls_internals.recv_buffer_data_size += ret; - if (ret==0) { /* EOF */ gnutls_assert(); return 0; diff --git a/lib/gnutls_record.c b/lib/gnutls_record.c index 730253f1e8..d741d21f96 100644 --- a/lib/gnutls_record.c +++ b/lib/gnutls_record.c @@ -366,6 +366,26 @@ int gnutls_send_alert(SOCKET cd, GNUTLS_STATE state, AlertLevel level, AlertDesc return ret; } +/* Sends the appropriate alert, depending + * on the error message. + */ +int _gnutls_send_appropriate_alert( SOCKET cd, GNUTLS_STATE state, int err) { +int ret; + switch (err) { /* send appropriate alert */ + case GNUTLS_E_MAC_FAILED: + ret = gnutls_send_alert(cd, state, GNUTLS_FATAL, GNUTLS_BAD_RECORD_MAC); + break; + case GNUTLS_E_DECRYPTION_FAILED: + ret = gnutls_send_alert(cd, state, GNUTLS_FATAL, GNUTLS_DECRYPTION_FAILED); + break; + case GNUTLS_E_DECOMPRESSION_FAILED: + ret = gnutls_send_alert(cd, state, GNUTLS_FATAL, GNUTLS_DECOMPRESSION_FAILURE); + break; + } + + return ret; +} + /** * gnutls_bye - This function terminates the current TLS/SSL connection. * @cd: is a connection descriptor. @@ -712,17 +732,7 @@ ssize_t gnutls_recv_int(SOCKET cd, GNUTLS_STATE state, ContentType type, Handsha */ tmplen = _gnutls_decrypt( state, ciphertext, length, &tmpdata, recv_type); if (tmplen < 0) { - switch (tmplen) { /* send appropriate alert */ - case GNUTLS_E_MAC_FAILED: - gnutls_send_alert(cd, state, GNUTLS_FATAL, GNUTLS_BAD_RECORD_MAC); - break; - case GNUTLS_E_DECRYPTION_FAILED: - gnutls_send_alert(cd, state, GNUTLS_FATAL, GNUTLS_DECRYPTION_FAILED); - break; - case GNUTLS_E_DECOMPRESSION_FAILED: - gnutls_send_alert(cd, state, GNUTLS_FATAL, GNUTLS_DECOMPRESSION_FAILURE); - break; - } + _gnutls_send_appropriate_alert( cd, state, tmplen); state->gnutls_internals.valid_connection = VALID_FALSE; state->gnutls_internals.resumable = RESUME_FALSE; gnutls_assert(); |