Implement timeout back-off (fixed range for now)

This commit is contained in:
Manuel Pégourié-Gonnard 2014-09-30 22:21:31 +02:00 committed by Paul Bakker
parent ce8588c9ef
commit 0ac247fd88
2 changed files with 67 additions and 17 deletions

View file

@ -261,6 +261,13 @@
#define SSL_RETRANS_WAITING 2
#define SSL_RETRANS_FINISHED 3
/*
* Default range for DTLS retransmission timer value, in milliseconds.
* RFC 6347 4.2.4.1 says from 1 second to 60 seconds.
*/
#define SSL_DTLS_TIMEOUT_DFL_MIN 1000
#define SSL_DTLS_TIMEOUT_DFL_MAX 60000
/**
* \name SECTION: Module settings
*
@ -652,6 +659,7 @@ struct _ssl_handshake_params
unsigned char *hs_msg; /*!< Reassembled handshake message */
uint32_t retransmit_timeout; /*!< Current value of timeout */
unsigned char retransmit_state; /*!< Retransmission state */
ssl_flight_item *flight; /*!< Current outgoing flight */
ssl_flight_item *cur_msg; /*!< Current message in flight */

View file

@ -88,7 +88,7 @@ static inline size_t ssl_ep_len( const ssl_context *ssl )
* Passing millisecs = 0 cancels a running timer.
* The timer is already running iff time_limit != 0.
*/
void ssl_set_timer( ssl_context *ssl, unsigned long millisecs )
void ssl_set_timer( ssl_context *ssl, uint32_t millisecs )
{
ssl->time_limit = millisecs;
get_timer( &ssl->time_info, 1 );
@ -109,6 +109,40 @@ int ssl_check_timer( ssl_context *ssl )
}
#endif
/*
* Double the retransmit timeout value, within the allowed range,
* returning -1 if the maximum value has already been reached.
*/
static int ssl_double_retransmit_timeout( ssl_context *ssl )
{
uint32_t new_timeout;
if( ssl->handshake->retransmit_timeout >= SSL_DTLS_TIMEOUT_DFL_MAX )
return( -1 );
new_timeout = 2 * ssl->handshake->retransmit_timeout;
/* Avoid arithmetic overflow and range overflow */
if( new_timeout < ssl->handshake->retransmit_timeout ||
new_timeout > SSL_DTLS_TIMEOUT_DFL_MAX )
{
new_timeout = SSL_DTLS_TIMEOUT_DFL_MAX;
}
ssl->handshake->retransmit_timeout = new_timeout;
SSL_DEBUG_MSG( 3, ( "update timeout value to %d millisecs",
ssl->handshake->retransmit_timeout ) );
return( 0 );
}
static void ssl_reset_retransmit_timeout( ssl_context *ssl )
{
ssl->handshake->retransmit_timeout = SSL_DTLS_TIMEOUT_DFL_MIN;
SSL_DEBUG_MSG( 3, ( "update timeout value to %d millisecs",
ssl->handshake->retransmit_timeout ) );
}
#if defined(POLARSSL_SSL_MAX_FRAGMENT_LENGTH)
/*
* Convert max_fragment_length codes to length.
@ -1951,12 +1985,12 @@ int ssl_fetch_input( ssl_context *ssl, size_t nb_want )
return( POLARSSL_ERR_SSL_INTERNAL_ERROR );
}
// TODO-DTLS: for now, use constant timeout = 1 sec/datagram
len = SSL_BUFFER_LEN - ( ssl->in_hdr - ssl->in_buf );
if( ssl->f_recv_timeout != NULL &&
ssl->handshake != NULL ) /* No resend outside handshake */
ssl->handshake != NULL ) /* No timeout outside handshake */
{
ret = ssl->f_recv_timeout( ssl->p_bio, ssl->in_hdr, len, 1 );
ret = ssl->f_recv_timeout( ssl->p_bio, ssl->in_hdr, len,
ssl->handshake->retransmit_timeout / 1000 );
}
else
ret = ssl->f_recv( ssl->p_bio, ssl->in_hdr, len );
@ -1972,6 +2006,12 @@ int ssl_fetch_input( ssl_context *ssl, size_t nb_want )
{
SSL_DEBUG_MSG( 2, ( "recv timeout" ) );
if( ssl_double_retransmit_timeout( ssl ) != 0 )
{
SSL_DEBUG_MSG( 1, ( "handshake timeout" ) );
return( POLARSSL_ERR_NET_TIMEOUT );
}
if( ( ret = ssl_resend( ssl ) ) != 0 )
{
SSL_DEBUG_RET( 1, "ssl_resend", ret );
@ -2247,8 +2287,7 @@ int ssl_resend( ssl_context *ssl )
else
ssl->handshake->retransmit_state = SSL_RETRANS_WAITING;
/* WIP: hardcoded 1 sec will be replaced */
ssl_set_timer( ssl, 1000 );
ssl_set_timer( ssl, ssl->handshake->retransmit_timeout );
SSL_DEBUG_MSG( 2, ( "<= ssl_resend" ) );
@ -2268,8 +2307,9 @@ void ssl_recv_flight_completed( ssl_context *ssl )
/* The next incoming flight will start with this msg_seq */
ssl->handshake->in_flight_start_seq = ssl->handshake->in_msg_seq;
/* Cancel timer */
/* Cancel timer and reset timeout value */
ssl_set_timer( ssl, 0 );
ssl_reset_retransmit_timeout( ssl );
if( ssl->in_msgtype == SSL_MSG_HANDSHAKE &&
ssl->in_msg[0] == SSL_HS_FINISHED )
@ -2285,8 +2325,7 @@ void ssl_recv_flight_completed( ssl_context *ssl )
*/
void ssl_send_flight_completed( ssl_context *ssl )
{
/* WIP: hardcoded 1 sec is temporary */
ssl_set_timer( ssl, 1000 );
ssl_set_timer( ssl, ssl->handshake->retransmit_timeout );
if( ssl->in_msgtype == SSL_MSG_HANDSHAKE &&
ssl->in_msg[0] == SSL_HS_FINISHED )
@ -4489,16 +4528,19 @@ static int ssl_handshake_init( ssl_context *ssl )
ssl->handshake->key_cert = ssl->key_cert;
#endif
/*
* We may not know yet if we're using DTLS,
* so always initiliase DTLS-specific fields.
*/
#if defined(POLARSSL_SSL_PROTO_DTLS)
if( ssl->transport == SSL_TRANSPORT_DATAGRAM )
{
ssl->handshake->alt_transform_out = ssl->transform_out;
ssl->handshake->alt_transform_out = ssl->transform_out;
if( ssl->endpoint == SSL_IS_CLIENT )
ssl->handshake->retransmit_state = SSL_RETRANS_PREPARING;
else
ssl->handshake->retransmit_state = SSL_RETRANS_WAITING;
}
ssl->handshake->retransmit_timeout = SSL_DTLS_TIMEOUT_DFL_MIN;
if( ssl->endpoint == SSL_IS_CLIENT )
ssl->handshake->retransmit_state = SSL_RETRANS_PREPARING;
else
ssl->handshake->retransmit_state = SSL_RETRANS_WAITING;
#endif
return( 0 );