On Aug 11, 2009, at 7:40 PM, Stephen Henson via RT wrote: >> [[email protected] - Mon Jul 27 17:03:25 2009]: >> >> This patch fixes the timeout handling. The method dtls1_get_timeout() >> was intended to determine the next handshake message timeout when >> using select() calls, to set their timeout. This method is renamed to >> DTLSv1_get_timeout(), to fit the common naming scheme and the >> declaration is moved. It was declared in the wrong file, so the user >> was unable to use it. Additionally, the timeout handling is moved to >> the method DTLSv1_handle_timeout(), which can be called by the user >> when a select() timer expires. Until now expired timers were handled >> not until a SSL_read() is called. This is a problem when using >> select() on the reading socket, because no call of SSL_read() is done >> before data from the peer arrived. >> > > Actually now I think of it perhaps the ctrl() mechanism would be a > better way to implement this. > > Steve.
Ok, here's an updated version. Internally is dtls1_get_timeout() and
dtls1_handle_timeout() used. They can be called externally using
SSL_ctrl() with DTLS_CTRL_GET_TIMEOUT and DTLS_CTRL_HANDLE_TIMEOUT or
with the corresponding macros DTLSv1_get_timeout() and
DTLSv1_handle_timeout() for simplicity.
--- apps/s_client.c 30 Jun 2009 16:10:24 -0000 1.123.2.2
+++ apps/s_client.c 12 Aug 2009 06:20:30 -0000
@@ -411,6 +411,7 @@
BIO *sbio;
char *inrand=NULL;
int mbuf_len=0;
+ struct timeval timeout, *timeoutp;
#ifndef OPENSSL_NO_ENGINE
char *engine_id=NULL;
char *ssl_client_engine_id=NULL;
@@ -1196,6 +1197,12 @@
FD_ZERO(&readfds);
FD_ZERO(&writefds);
+ if ((SSL_version(con) == DTLS1_VERSION) &&
+ DTLSv1_get_timeout(con, &timeout))
+ timeoutp = &timeout;
+ else
+ timeoutp = NULL;
+
if (SSL_in_init(con) && !SSL_total_renegotiations(con))
{
in_init=1;
@@ -1300,7 +1307,7 @@
if(!i && (!((_kbhit()) ||
(WAIT_OBJECT_0 ==
WaitForSingleObject(GetStdHandle(STD_INPUT_HANDLE), 0))) || !
read_tty) ) continue;
#endif
} else i=select(width,(void *)&readfds,(void
*)&writefds,
- NULL,NULL);
+ NULL,timeoutp);
}
#elif defined(OPENSSL_SYS_NETWARE)
if(!write_tty) {
@@ -1310,7 +1317,7 @@
i=select(width,(void *)&readfds,(void
*)&writefds,
NULL,&tv);
} else i=select(width,(void *)&readfds,(void
*)&writefds,
- NULL,NULL);
+ NULL,timeoutp);
}
#elif defined(OPENSSL_SYS_BEOS_R5)
/* Under BeOS-R5 the situation is similar to DOS */
@@ -1328,12 +1335,12 @@
if (!i && (stdin_set != 1 || !read_tty))
continue;
} else i=select(width,(void *)&readfds,(void
*)&writefds,
- NULL,NULL);
+ NULL,timeoutp);
}
(void)fcntl(fileno(stdin), F_SETFL, 0);
#else
i=select(width,(void *)&readfds,(void *)&writefds,
- NULL,NULL);
+ NULL,timeoutp);
#endif
if ( i < 0)
{
@@ -1344,6 +1351,11 @@
}
}
+ if ((SSL_version(con) == DTLS1_VERSION) &&
DTLSv1_handle_timeout(con) > 0)
+ {
+ BIO_printf(bio_err,"TIMEOUT occured\n");
+ }
+
if (!ssl_pending && FD_ISSET(SSL_get_fd(con),&writefds))
{
k=SSL_write(con,&(cbuf[cbuf_off]),
--- apps/s_server.c 27 Jul 2009 21:08:46 -0000 1.136.2.5
+++ apps/s_server.c 12 Aug 2009 06:20:30 -0000
@@ -1750,6 +1750,7 @@
unsigned long l;
SSL *con=NULL;
BIO *sbio;
+ struct timeval timeout, *timeoutp;
#if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_MSDOS) ||
defined(OPENSSL_SYS_NETWARE) || defined(OPENSSL_SYS_BEOS_R5)
struct timeval tv;
#endif
@@ -1919,7 +1920,19 @@
read_from_terminal = 1;
(void)fcntl(fileno(stdin), F_SETFL, 0);
#else
- i=select(width,(void *)&readfds,NULL,NULL,NULL);
+ if ((SSL_version(con) == DTLS1_VERSION) &&
+ DTLSv1_get_timeout(con, &timeout))
+ timeoutp = &timeout;
+ else
+ timeoutp = NULL;
+
+ i=select(width,(void *)&readfds,NULL,NULL,timeoutp);
+
+ if ((SSL_version(con) == DTLS1_VERSION) &&
DTLSv1_handle_timeout(con) > 0)
+ {
+ BIO_printf(bio_err,"TIMEOUT occured\n");
+ }
+
if (i <= 0) continue;
if (FD_ISSET(fileno(stdin),&readfds))
read_from_terminal = 1;
--- ssl/d1_both.c 15 Jul 2009 11:32:57 -0000 1.14.2.13
+++ ssl/d1_both.c 12 Aug 2009 06:20:31 -0000
@@ -890,9 +890,6 @@
int dtls1_read_failed(SSL *s, int code)
{
- DTLS1_STATE *state;
- int send_alert = 0;
-
if ( code > 0)
{
fprintf( stderr, "invalid state reached %s:%d", __FILE__,
__LINE__);
@@ -912,24 +909,6 @@
return code;
}
- dtls1_double_timeout(s);
- state = s->d1;
- state->timeout.num_alerts++;
- if ( state->timeout.num_alerts > DTLS1_TMO_ALERT_COUNT)
- {
- /* fail the connection, enough alerts have been sent */
- SSLerr(SSL_F_DTLS1_READ_FAILED,SSL_R_READ_TIMEOUT_EXPIRED);
- return 0;
- }
-
- state->timeout.read_timeouts++;
- if ( state->timeout.read_timeouts > DTLS1_TMO_READ_COUNT)
- {
- send_alert = 1;
- state->timeout.read_timeouts = 1;
- }
-
-
#if 0 /* for now, each alert contains only one record number */
item = pqueue_peek(state->rcvd_records);
if ( item )
@@ -940,12 +919,12 @@
#endif
#if 0 /* no more alert sending, just retransmit the last set of
messages */
- if ( send_alert)
- ssl3_send_alert(s,SSL3_AL_WARNING,
- DTLS1_AD_MISSING_HANDSHAKE_MESSAGE);
+ if ( state->timeout.read_timeouts >= DTLS1_TMO_READ_COUNT)
+ ssl3_send_alert(s,SSL3_AL_WARNING,
+ DTLS1_AD_MISSING_HANDSHAKE_MESSAGE);
#endif
- return dtls1_retransmit_buffered_messages(s) ;
+ return dtls1_handle_timeout(s);
}
int
--- ssl/d1_lib.c 31 May 2009 17:11:24 -0000 1.8.2.6
+++ ssl/d1_lib.c 12 Aug 2009 06:20:31 -0000
@@ -188,6 +188,29 @@
s->version=DTLS1_VERSION;
}
+long dtls1_ctrl(SSL *s, int cmd, long larg, void *parg)
+ {
+ int ret=0;
+
+ switch (cmd)
+ {
+ case DTLS_CTRL_GET_TIMEOUT:
+ if (dtls1_get_timeout(s, (struct timeval*) parg) != NULL)
+ {
+ ret = 1;
+ }
+ break;
+ case DTLS_CTRL_HANDLE_TIMEOUT:
+ ret = dtls1_handle_timeout(s);
+ break;
+
+ default:
+ ret = ssl3_ctrl(s, cmd, larg, parg);
+ break;
+ }
+ return(ret);
+ }
+
/*
* As it's impossible to use stream ciphers in "datagram" mode, this
* simple filter is designed to disengage them in DTLS. Unfortunately
@@ -295,6 +318,36 @@
BIO_ctrl(SSL_get_rbio(s), BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT, 0, &(s-
>d1->next_timeout));
}
+int dtls1_handle_timeout(SSL *s)
+ {
+ DTLS1_STATE *state;
+
+ /* if no timer is expired, don't do anything */
+ if (!dtls1_is_timer_expired(s))
+ {
+ return 0;
+ }
+
+ dtls1_double_timeout(s);
+ state = s->d1;
+ state->timeout.num_alerts++;
+ if ( state->timeout.num_alerts > DTLS1_TMO_ALERT_COUNT)
+ {
+ /* fail the connection, enough alerts have been sent */
+ SSLerr(SSL_F_DTLS1_READ_FAILED,SSL_R_READ_TIMEOUT_EXPIRED);
+ return 0;
+ }
+
+ state->timeout.read_timeouts++;
+ if ( state->timeout.read_timeouts > DTLS1_TMO_READ_COUNT)
+ {
+ state->timeout.read_timeouts = 1;
+ }
+
+ dtls1_start_timer(s);
+ return dtls1_retransmit_buffered_messages(s);
+ }
+
static void get_current_time(struct timeval *t)
{
#ifdef OPENSSL_SYS_WIN32
--- ssl/d1_pkt.c 24 Jul 2009 11:52:32 -0000 1.27.2.14
+++ ssl/d1_pkt.c 12 Aug 2009 06:20:31 -0000
@@ -773,11 +773,8 @@
}
/* Check for timeout */
- if (dtls1_is_timer_expired(s))
- {
- if (dtls1_read_failed(s, -1) > 0)
- goto start;
- }
+ if (dtls1_handle_timeout(s) > 0)
+ goto start;
/* get new packet if necessary */
if ((rr->length == 0) || (s->rstate == SSL_ST_READ_BODY))
--- ssl/ssl.h 15 Jul 2009 11:32:57 -0000 1.221.2.7
+++ ssl/ssl.h 12 Aug 2009 06:20:31 -0000
@@ -1396,6 +1396,14 @@
#define SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB 72
#endif
+#define DTLS_CTRL_GET_TIMEOUT 73
+#define DTLS_CTRL_HANDLE_TIMEOUT 74
+
+#define DTLSv1_get_timeout(ssl, arg) \
+ SSL_ctrl(ssl,DTLS_CTRL_GET_TIMEOUT,0, (void *)arg)
+#define DTLSv1_handle_timeout(ssl) \
+ SSL_ctrl(ssl,DTLS_CTRL_HANDLE_TIMEOUT,0, NULL)
+
#define SSL_session_reused(ssl) \
SSL_ctrl((ssl),SSL_CTRL_GET_SESSION_REUSED,0,NULL)
#define SSL_num_renegotiations(ssl) \
--- ssl/ssl_locl.h 16 May 2009 11:14:55 -0000 1.100.2.6
+++ ssl/ssl_locl.h 12 Aug 2009 06:20:31 -0000
@@ -759,7 +759,7 @@
dtls1_read_bytes, \
dtls1_write_app_data_bytes, \
dtls1_dispatch_alert, \
- ssl3_ctrl, \
+ dtls1_ctrl, \
ssl3_ctx_ctrl, \
ssl3_get_cipher_by_char, \
ssl3_put_cipher_by_char, \
@@ -943,6 +943,7 @@
void dtls1_reset_seq_numbers(SSL *s, int rw);
long dtls1_default_timeout(void);
struct timeval* dtls1_get_timeout(SSL *s, struct timeval* timeleft);
+int dtls1_handle_timeout(SSL *s);
const SSL_CIPHER *dtls1_get_cipher(unsigned int u);
void dtls1_start_timer(SSL *s);
void dtls1_stop_timer(SSL *s);
dtls-timeout-handling-bug.patch
Description: Binary data
