PR: 1997
authorDr. Stephen Henson <steve@openssl.org>
Wed, 12 Aug 2009 13:19:54 +0000 (13:19 +0000)
committerDr. Stephen Henson <steve@openssl.org>
Wed, 12 Aug 2009 13:19:54 +0000 (13:19 +0000)
Submitted by: Robin Seggelmann <seggelmann@fh-muenster.de>
Approved by: steve@openssl.org

DTLS timeout handling fix.

apps/s_client.c
apps/s_server.c
ssl/d1_both.c
ssl/d1_lib.c
ssl/d1_pkt.c
ssl/ssl.h
ssl/ssl_locl.h

index a41a915ed4d5a8e849054e104e2cc2d968e929b7..c97597d448a1bdb426f903ac20d97481348c4414 100644 (file)
@@ -411,6 +411,7 @@ int MAIN(int argc, char **argv)
        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;
@@ -979,7 +980,6 @@ re_start:
 
        if ( SSL_version(con) == DTLS1_VERSION)
                {
-               struct timeval timeout;
 
                sbio=BIO_new_dgram(s,BIO_NOCLOSE);
                if (getsockname(s, &peer, (void *)&peerlen) < 0)
@@ -1196,6 +1196,12 @@ SSL_set_tlsext_status_ids(con, ids);
                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 +1306,7 @@ SSL_set_tlsext_status_ids(con, ids);
                                        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 +1316,7 @@ SSL_set_tlsext_status_ids(con, ids);
                                        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 +1334,12 @@ SSL_set_tlsext_status_ids(con, ids);
                                        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 +1350,11 @@ SSL_set_tlsext_status_ids(con, ids);
                                }
                        }
 
+               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]),
index 5ebbf6b8765160bfdb0884f2f4ac8850bc84bf74..9ccf2f0a44193045c5e9c648a79f56d952757bbc 100644 (file)
@@ -1750,6 +1750,7 @@ static int sv_body(char *hostname, int s, unsigned char *context)
        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
@@ -1808,7 +1809,6 @@ static int sv_body(char *hostname, int s, unsigned char *context)
 
        if (SSL_version(con) == DTLS1_VERSION)
                {
-               struct timeval timeout;
 
                sbio=BIO_new_dgram(s,BIO_NOCLOSE);
 
@@ -1919,7 +1919,19 @@ static int sv_body(char *hostname, int s, unsigned char *context)
                                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;
index d11d6d5888281165e4b5b12ed1223a9dab891347..5bb0a4ff6ce1f02e2b54c0f4b638dee97ff5602a 100644 (file)
@@ -890,9 +890,6 @@ unsigned long dtls1_output_cert_chain(SSL *s, X509 *x)
 
 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 @@ int dtls1_read_failed(SSL *s, int code)
                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 @@ int dtls1_read_failed(SSL *s, int code)
 #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
index 6450c1de850b2d3e63b7b1dac2e902c43b9f7153..8039740555f2b388168a3250a277da20e237a62d 100644 (file)
@@ -188,6 +188,29 @@ void dtls1_clear(SSL *s)
                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 @@ void dtls1_stop_timer(SSL *s)
        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
index d9a81140ea536a04e844729bcc571ec339d7c14f..0664636b521a3ccf810a952abccb1faf18a88f18 100644 (file)
@@ -773,11 +773,8 @@ start:
                }
 
        /* 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))
index 7ed8226b2470c08fb64ffcac17b7181206604536..117071c30a97fb411319a074b3dffc66ddda7805 100644 (file)
--- a/ssl/ssl.h
+++ b/ssl/ssl.h
@@ -1396,6 +1396,14 @@ DECLARE_PEM_rw(SSL_SESSION, SSL_SESSION)
 #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) \
index 2b362a48ea1cd602f09c51619a6e1eb3187fa84e..74fc972908bc79a67e19b1e619f61b7ca8c0cee6 100644 (file)
@@ -759,7 +759,7 @@ const SSL_METHOD *func_name(void)  \
                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_get_ccs_header(unsigned char *data, struct ccs_header_st *ccs_hdr);
 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);