On Aug 11, 2009, at 7:40 PM, Stephen Henson via RT wrote: >> [seggelm...@fh-muenster.de - 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