summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@gnutls.org>2001-08-19 20:11:48 +0000
committerNikos Mavrogiannopoulos <nmav@gnutls.org>2001-08-19 20:11:48 +0000
commit31d47097d6d0d9cd817562597ce6f724abee31c5 (patch)
tree47dedc8fc333f0337431c536698da1f713cbe7c0
parent3a792ad38fe34d5fa860f85fa9c45f67ce3faa36 (diff)
downloadgnutls-31d47097d6d0d9cd817562597ce6f724abee31c5.tar.gz
several fixes in gnutls_bye() function, and in gnutls_recv_int()
-rw-r--r--lib/gnutls.h.in3
-rw-r--r--lib/gnutls_buffers.c9
-rw-r--r--lib/gnutls_int.h6
-rw-r--r--lib/gnutls_record.c78
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 */