From 31d47097d6d0d9cd817562597ce6f724abee31c5 Mon Sep 17 00:00:00 2001 From: Nikos Mavrogiannopoulos Date: Sun, 19 Aug 2001 20:11:48 +0000 Subject: several fixes in gnutls_bye() function, and in gnutls_recv_int() --- lib/gnutls.h.in | 3 +- lib/gnutls_buffers.c | 9 +++--- lib/gnutls_int.h | 6 ++++ lib/gnutls_record.c | 78 +++++++++++++++++++++++++++++----------------------- 4 files changed, 56 insertions(+), 40 deletions(-) diff --git a/lib/gnutls.h.in b/lib/gnutls.h.in index 4ea10a2bd9..820ac27354 100644 --- a/lib/gnutls.h.in +++ b/lib/gnutls.h.in @@ -43,6 +43,7 @@ typedef enum AlertDescription { GNUTLS_CLOSE_NOTIFY, GNUTLS_UNEXPECTED_MESSAGE=1 typedef enum CertificateStatus { GNUTLS_CERT_TRUSTED=1, GNUTLS_CERT_NOT_TRUSTED, GNUTLS_CERT_EXPIRED, GNUTLS_CERT_INVALID } CertificateStatus; typedef enum CertificateRequest { GNUTLS_CERT_REQUEST=1, GNUTLS_CERT_REQUIRE } CertificateRequest; +typedef enum CloseRequest { GNUTLS_BYE_RW=0, GNUTLS_BYE_W=1, GNUTLS_BYE_R=2 } CloseRequest; typedef enum GNUTLS_Version { GNUTLS_SSL3=1, GNUTLS_TLS1 } GNUTLS_Version; @@ -71,7 +72,7 @@ typedef struct gnutls_private_key gnutls_private_key; int gnutls_init(GNUTLS_STATE * state, ConnectionEnd con_end); int gnutls_deinit(GNUTLS_STATE state); -int gnutls_bye(SOCKET cd, GNUTLS_STATE state, int wait); +int gnutls_bye(SOCKET cd, GNUTLS_STATE state, CloseRequest how); int gnutls_handshake(SOCKET cd, GNUTLS_STATE state); int gnutls_check_pending(GNUTLS_STATE state); diff --git a/lib/gnutls_buffers.c b/lib/gnutls_buffers.c index 731c1ef83c..cc074a44f0 100644 --- a/lib/gnutls_buffers.c +++ b/lib/gnutls_buffers.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2000 Nikos Mavroyanopoulos + * Copyright (C) 2000,2001 Nikos Mavroyanopoulos * * This file is part of GNUTLS. * @@ -142,7 +142,7 @@ int gnutls_getDataFromBuffer(ContentType type, GNUTLS_STATE state, char *data, i /* This function is like read. But it does not return -1 on error. * It does return gnutls_errno instead. */ -ssize_t _gnutls_Read(int fd, void *iptr, size_t sizeOfPtr, int flag) +static ssize_t _gnutls_Read(int fd, void *iptr, size_t sizeOfPtr, int flag) { size_t left; ssize_t i=0; @@ -231,9 +231,9 @@ ssize_t _gnutls_read_buffered( int fd, GNUTLS_STATE state, void *iptr, size_t si int recvlowat = RCVLOWAT; /* leave peeked data to the kernel space only if application data - * is received. + * is received and we don't have any peeked data in there. */ - if (recv_type != GNUTLS_APPLICATION_DATA) + if (recv_type != GNUTLS_APPLICATION_DATA && state->gnutls_internals.have_peeked_data==0) recvlowat = 0; /* copy peeked data to given buffer @@ -268,7 +268,6 @@ ssize_t _gnutls_read_buffered( int fd, GNUTLS_STATE state, void *iptr, size_t si gnutls_assert(); return GNUTLS_E_AGAIN; } - /* copy fresh data to our buffer. */ diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h index ec7a0977f3..3b690b3b96 100644 --- a/lib/gnutls_int.h +++ b/lib/gnutls_int.h @@ -92,6 +92,7 @@ typedef enum AlertDescription { GNUTLS_CLOSE_NOTIFY, GNUTLS_UNEXPECTED_MESSAGE=1 } AlertDescription; typedef enum CertificateStatus { GNUTLS_CERT_TRUSTED=1, GNUTLS_CERT_NOT_TRUSTED, GNUTLS_CERT_EXPIRED, GNUTLS_CERT_INVALID } CertificateStatus; typedef enum CertificateRequest { GNUTLS_CERT_REQUEST=1, GNUTLS_CERT_REQUIRE } CertificateRequest; +typedef enum CloseRequest { GNUTLS_BYE_RW=0, GNUTLS_BYE_W=1, GNUTLS_BYE_R=2 } CloseRequest; typedef enum HandshakeType { GNUTLS_HELLO_REQUEST, GNUTLS_CLIENT_HELLO, GNUTLS_SERVER_HELLO, GNUTLS_CERTIFICATE=11, GNUTLS_SERVER_KEY_EXCHANGE, @@ -306,6 +307,11 @@ typedef struct { gnutls_datum buffer_handshake; /* this is a buffer that holds the current handshake message */ ResumableSession resumable; /* TRUE or FALSE - if we can resume that session */ ValidSession valid_connection; /* true or FALSE - if this session is valid */ + + int may_read; /* if it's 0 then we can read/write, otherwise it's forbiden to read/write + */ + int may_write; + AlertDescription last_alert; /* last alert received */ /* this is the compression method we are going to use */ CompressionMethod compression_method; diff --git a/lib/gnutls_record.c b/lib/gnutls_record.c index 22bdf2bd7d..afb37ade93 100644 --- a/lib/gnutls_record.c +++ b/lib/gnutls_record.c @@ -354,29 +354,32 @@ int gnutls_send_alert(SOCKET cd, GNUTLS_STATE state, AlertLevel level, AlertDesc * gnutls_bye - This function terminates the current TLS/SSL connection. * @cd: is a connection descriptor. * @state: is a &GNUTLS_STATE structure. - * @wait: is an integer + * @how: is an integer * - * Terminates the current TLS/SSL connection. If the return value is 0 - * you may continue using the TCP connection. The connection should + * Terminates the current TLS/SSL connection. The connection should * have been initiated using gnutls_handshake() or similar function. - * If 'wait' is non-zero then we will not wait for the other peer to - * close the TLS connection. + * 'how' is one of GNUTLS_BYE_R, GNUTLS_BYE_RW, GNUTLS_BYE_W. * - * This function actually sends the peer a closure alert, and if 'wait' - * is zero, will wait for the peer to reply (with a closure alert too). + * Note that if the return value is zero and 'how' was GNUTLS_BYE_RW, you + * may continue using the TCP connection. * **/ -int gnutls_bye(SOCKET cd, GNUTLS_STATE state, int wait) +int gnutls_bye(SOCKET cd, GNUTLS_STATE state, CloseRequest how) { - int ret; - - ret = gnutls_send_alert(cd, state, GNUTLS_WARNING, GNUTLS_CLOSE_NOTIFY); + int ret = 0; - /* receive the closure alert */ - if (wait==0) gnutls_recv_int(cd, state, GNUTLS_ALERT, -1, NULL, 0, 0); - state->gnutls_internals.valid_connection = VALID_FALSE; + if (how == GNUTLS_BYE_R || how == GNUTLS_BYE_RW) { + ret = gnutls_send_alert(cd, state, GNUTLS_WARNING, GNUTLS_CLOSE_NOTIFY); + state->gnutls_internals.may_read = 1; + gnutls_recv_int(cd, state, GNUTLS_ALERT, -1, NULL, 0, 0); + } + + if (how == GNUTLS_BYE_W || how == GNUTLS_BYE_RW) { + state->gnutls_internals.may_write = 1; + } + return ret; } @@ -398,7 +401,8 @@ ssize_t gnutls_send_int(SOCKET cd, GNUTLS_STATE state, ContentType type, Handsha if (sizeofdata == 0) return 0; - if (state->gnutls_internals.valid_connection == VALID_FALSE) { + + if (state->gnutls_internals.valid_connection == VALID_FALSE || state->gnutls_internals.may_write != 0) { gnutls_assert(); return GNUTLS_E_INVALID_SESSION; } @@ -531,11 +535,22 @@ ssize_t gnutls_recv_int(SOCKET cd, GNUTLS_STATE state, ContentType type, Handsha uint16 length; uint8 *ciphertext; uint8 *recv_data; - int ret = 0; - int header_size = RECORD_HEADER_SIZE; + int ret; + int header_size; + begin: + + header_size = RECORD_HEADER_SIZE; + ret = 0; + if (sizeofdata == 0) + return 0; + if (state->gnutls_internals.valid_connection == VALID_FALSE || state->gnutls_internals.may_read!=0) { + gnutls_assert(); + return GNUTLS_E_INVALID_SESSION; + } + /* If we have enough data in the cache do not bother receiving * a new packet. (in order to flush the cache) */ @@ -549,11 +564,7 @@ ssize_t gnutls_recv_int(SOCKET cd, GNUTLS_STATE state, ContentType type, Handsha return ret; } - - if (state->gnutls_internals.valid_connection == VALID_FALSE || sizeofdata==0) { - return 0; /* EOF */ - } - + /* in order for GNUTLS_E_AGAIN to be returned the socket * must be set to non blocking mode */ @@ -561,7 +572,10 @@ ssize_t gnutls_recv_int(SOCKET cd, GNUTLS_STATE state, ContentType type, Handsha if (ret==GNUTLS_E_AGAIN) return ret; state->gnutls_internals.valid_connection = VALID_FALSE; - if (type==GNUTLS_ALERT) return 0; /* we were expecting close notify */ + if (type==GNUTLS_ALERT) { + gnutls_assert(); + return 0; /* we were expecting close notify */ + } state->gnutls_internals.resumable = RESUME_FALSE; gnutls_assert(); return GNUTLS_E_UNEXPECTED_PACKET_LENGTH; @@ -762,21 +776,17 @@ ssize_t gnutls_recv_int(SOCKET cd, GNUTLS_STATE state, ContentType type, Handsha return GNUTLS_E_UNEXPECTED_PACKET; case GNUTLS_APPLICATION_DATA: -#if 0 /* even if data is unexpected put it into the buffer */ gnutls_insertDataBuffer(recv_type, state, (void *) tmpdata, tmplen); - /* no peeked data to clear since this packet was unexpected */ -#endif - /* We no longer assume this as normal, since - * in this case we don't leave data into kernel - * buffer, thus select() will not return. - * Return an error for now, and we'll handle - * it if there is a need for it. - */ + gnutls_assert(); gnutls_free(tmpdata); - return GNUTLS_E_UNEXPECTED_PACKET; - + + goto begin; /* ok we received the packet, + * and now we should get the one + * we expected. + */ + break; case GNUTLS_HANDSHAKE: /* This is only legal if HELLO_REQUEST is received - and we are a client */ -- cgit v1.2.1