From 407397e8bee0de3c1fbe73ff5623cf27bf87363c Mon Sep 17 00:00:00 2001 From: John Safranek Date: Thu, 6 Sep 2012 22:41:55 -0700 Subject: [PATCH] adding DTLS retry timeout, added CYASSL pointer to recv/send callbacks --- cyassl/internal.h | 11 ++++++++--- cyassl/ssl.h | 5 +++-- examples/client/client.c | 2 ++ src/internal.c | 11 +++++++++-- src/io.c | 28 ++++++++++++++++++++++++---- src/ssl.c | 30 ++++++++++++++++++++++++++++++ 6 files changed, 76 insertions(+), 11 deletions(-) diff --git a/cyassl/internal.h b/cyassl/internal.h index 9d1224706..967aa0c67 100644 --- a/cyassl/internal.h +++ b/cyassl/internal.h @@ -649,9 +649,9 @@ int SetCipherList(Suites*, const char* list); #ifndef CYASSL_USER_IO /* default IO callbacks */ CYASSL_LOCAL - int EmbedReceive(char *buf, int sz, void *ctx); + int EmbedReceive(CYASSL *ssl, char *buf, int sz, void *ctx); CYASSL_LOCAL - int EmbedSend(char *buf, int sz, void *ctx); + int EmbedSend(CYASSL *ssl, char *buf, int sz, void *ctx); #endif #ifdef CYASSL_DTLS @@ -1132,6 +1132,7 @@ typedef struct Options { byte quietShutdown; /* don't send close notify */ byte certOnly; /* stop once we get cert */ byte groupMessages; /* group handshake messages */ + byte usingNonblock; /* set when using nonblocking socket */ #ifndef NO_PSK byte havePSK; /* psk key set by user */ psk_client_callback client_psk_cb; @@ -1258,6 +1259,9 @@ struct CYASSL { z_stream d_stream; /* decompression stream */ byte didStreamInit; /* for stream init and end */ #endif +#ifdef CYASSL_DTLS + int dtls_timeout; +#endif #ifdef CYASSL_CALLBACKS HandShakeInfo handShakeInfo; /* info saved during handshake */ TimeoutInfo timeoutInfo; /* info saved during handshake */ @@ -1396,7 +1400,8 @@ enum IOerrors { IO_ERR_WANT_WRITE = -2, /* need to call write again */ IO_ERR_CONN_RST = -3, /* connection reset */ IO_ERR_ISR = -4, /* interrupt */ - IO_ERR_CONN_CLOSE = -5 /* connection closed or epipe */ + IO_ERR_CONN_CLOSE = -5, /* connection closed or epipe */ + IO_ERR_TIMEOUT = -6 /* socket timeout */ }; diff --git a/cyassl/ssl.h b/cyassl/ssl.h index b86181380..3ce8ed412 100644 --- a/cyassl/ssl.h +++ b/cyassl/ssl.h @@ -179,6 +179,7 @@ CYASSL_API CYASSL_CTX* CyaSSL_CTX_new(CYASSL_METHOD*); CYASSL_API CYASSL* CyaSSL_new(CYASSL_CTX*); CYASSL_API int CyaSSL_set_fd (CYASSL*, int); CYASSL_API int CyaSSL_get_fd(const CYASSL*); +CYASSL_API void CyaSSL_using_nonblock(CYASSL*); CYASSL_API int CyaSSL_connect(CYASSL*); /* please see note at top of README if you get an error from connect */ CYASSL_API int CyaSSL_write(CYASSL*, const void*, int); @@ -760,8 +761,8 @@ CYASSL_API int CyaSSL_use_certificate_chain_buffer(CYASSL*, CYASSL_API int CyaSSL_set_group_messages(CYASSL*); /* I/O callbacks */ -typedef int (*CallbackIORecv)(char *buf, int sz, void *ctx); -typedef int (*CallbackIOSend)(char *buf, int sz, void *ctx); +typedef int (*CallbackIORecv)(CYASSL *ssl, char *buf, int sz, void *ctx); +typedef int (*CallbackIOSend)(CYASSL *ssl, char *buf, int sz, void *ctx); CYASSL_API void CyaSSL_SetIORecv(CYASSL_CTX*, CallbackIORecv); CYASSL_API void CyaSSL_SetIOSend(CYASSL_CTX*, CallbackIOSend); diff --git a/examples/client/client.c b/examples/client/client.c index 84aab662e..512612673 100644 --- a/examples/client/client.c +++ b/examples/client/client.c @@ -337,6 +337,7 @@ void client_test(void* args) if (matchName && doPeerCheck) CyaSSL_check_domain_name(ssl, domain); #ifdef NON_BLOCKING + CyaSSL_using_nonblock(ssl); tcp_set_nonblocking(&sockfd); NonBlockingSSL_Connect(ssl); #else @@ -411,6 +412,7 @@ void client_test(void* args) showPeer(sslResume); #ifdef NON_BLOCKING + CyaSSL_using_nonblock(sslResume); tcp_set_nonblocking(&sockfd); NonBlockingSSL_Connect(sslResume); #else diff --git a/src/internal.c b/src/internal.c index 7ed29d6af..e22e32dac 100644 --- a/src/internal.c +++ b/src/internal.c @@ -923,6 +923,7 @@ int InitSSL(CYASSL* ssl, CYASSL_CTX* ctx) ssl->keys.dtls_peer_epoch = 0; ssl->keys.dtls_expected_peer_epoch = 0; ssl->arrays.cookieSz = 0; + ssl->dtls_timeout = 2; #endif ssl->keys.encryptionOn = 0; /* initially off */ ssl->options.sessionCacheOff = ctx->sessionCacheOff; @@ -944,6 +945,7 @@ int InitSSL(CYASSL* ssl, CYASSL_CTX* ctx) ssl->options.quietShutdown = ctx->quietShutdown; ssl->options.certOnly = 0; ssl->options.groupMessages = ctx->groupMessages; + ssl->options.usingNonblock = 0; /* ctx still owns certificate, certChain, key, dh, and cm */ ssl->buffers.certificate = ctx->certificate; @@ -1305,7 +1307,7 @@ static int Receive(CYASSL* ssl, byte* buf, word32 sz) int recvd; retry: - recvd = ssl->ctx->CBIORecv((char *)buf, (int)sz, ssl->IOCB_ReadCtx); + recvd = ssl->ctx->CBIORecv(ssl, (char *)buf, (int)sz, ssl->IOCB_ReadCtx); if (recvd < 0) switch (recvd) { case IO_ERR_GENERAL: /* general/unknown error */ @@ -1339,6 +1341,10 @@ retry: ssl->options.isClosed = 1; return -1; + case IO_ERR_TIMEOUT: + /* XXX More than retry. Need to resend. */ + goto retry; + default: return recvd; } @@ -1386,7 +1392,8 @@ void ShrinkInputBuffer(CYASSL* ssl, int forcedFree) int SendBuffered(CYASSL* ssl) { while (ssl->buffers.outputBuffer.length > 0) { - int sent = ssl->ctx->CBIOSend((char*)ssl->buffers.outputBuffer.buffer + + int sent = ssl->ctx->CBIOSend(ssl, + (char*)ssl->buffers.outputBuffer.buffer + ssl->buffers.outputBuffer.idx, (int)ssl->buffers.outputBuffer.length, ssl->IOCB_WriteCtx); diff --git a/src/io.c b/src/io.c index 1b8602227..30f38622e 100644 --- a/src/io.c +++ b/src/io.c @@ -134,12 +134,24 @@ static INLINE int LastError(void) /* The receive embedded callback * return : nb bytes read, or error */ -int EmbedReceive(char *buf, int sz, void *ctx) +int EmbedReceive(CYASSL *ssl, char *buf, int sz, void *ctx) { int recvd; int err; int sd = *(int*)ctx; +#ifdef CYASSL_DTLS + if (ssl->options.dtls + && !ssl->options.usingNonblock && ssl->dtls_timeout != 0) { + #if USE_WINDOWS_API + DWORD timeout = ssl->dtls_timeout; + #else + struct timeval timeout = {ssl->dtls_timeout, 0}; + #endif + setsockopt(sd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)); + } +#endif + recvd = RECV_FUNCTION(sd, (char *)buf, sz, 0); if (recvd < 0) { @@ -147,8 +159,14 @@ int EmbedReceive(char *buf, int sz, void *ctx) CYASSL_MSG("Embed Receive error"); if (err == SOCKET_EWOULDBLOCK || err == SOCKET_EAGAIN) { - CYASSL_MSG(" Would block"); - return IO_ERR_WANT_READ; + if (ssl->options.usingNonblock) { + CYASSL_MSG(" Would block"); + return IO_ERR_WANT_READ; + } + else { + CYASSL_MSG(" Socket timeout"); + return IO_ERR_TIMEOUT; + } } else if (err == SOCKET_ECONNRESET) { CYASSL_MSG(" Connection reset"); @@ -174,13 +192,15 @@ int EmbedReceive(char *buf, int sz, void *ctx) /* The send embedded callback * return : nb bytes sent, or error */ -int EmbedSend(char *buf, int sz, void *ctx) +int EmbedSend(CYASSL* ssl, char *buf, int sz, void *ctx) { int sd = *(int*)ctx; int sent; int len = sz; int err; + (void)ssl; + sent = SEND_FUNCTION(sd, &buf[sz - len], len, 0); if (sent < 0) { diff --git a/src/ssl.c b/src/ssl.c index 28c5f0cc4..6c6f0dcca 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -185,6 +185,13 @@ int CyaSSL_get_fd(const CYASSL* ssl) } +void CyaSSL_using_nonblock(CYASSL* ssl) +{ + CYASSL_ENTER("CyaSSL_using_nonblock"); + ssl->options.usingNonblock = 1; +} + + int CyaSSL_negotiate(CYASSL* ssl) { int err = SSL_FATAL_ERROR; @@ -2175,6 +2182,29 @@ int CyaSSL_set_cipher_list(CYASSL* ssl, const char* list) } +int CyaSSL_dtls_get_current_timeout(CYASSL* ssl) +{ + (void)ssl; + +#ifdef CYASSL_DTLS + return ssl->dtls_timeout; +#else + return 0; +#endif +} + + +void CyaSSL_dtls_got_timeout(CYASSL* ssl) +{ + (void)ssl; + +#ifdef CYASSL_DTLS + if (ssl->dtls_timeout < 64) + ssl->dtls_timeout *= 2; +#endif +} + + /* client only parts */ #ifndef NO_CYASSL_CLIENT