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_WAITING 2
#define SSL_RETRANS_FINISHED 3 #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 * \name SECTION: Module settings
* *
@ -652,6 +659,7 @@ struct _ssl_handshake_params
unsigned char *hs_msg; /*!< Reassembled handshake message */ unsigned char *hs_msg; /*!< Reassembled handshake message */
uint32_t retransmit_timeout; /*!< Current value of timeout */
unsigned char retransmit_state; /*!< Retransmission state */ unsigned char retransmit_state; /*!< Retransmission state */
ssl_flight_item *flight; /*!< Current outgoing flight */ ssl_flight_item *flight; /*!< Current outgoing flight */
ssl_flight_item *cur_msg; /*!< Current message in 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. * Passing millisecs = 0 cancels a running timer.
* The timer is already running iff time_limit != 0. * 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; ssl->time_limit = millisecs;
get_timer( &ssl->time_info, 1 ); get_timer( &ssl->time_info, 1 );
@ -109,6 +109,40 @@ int ssl_check_timer( ssl_context *ssl )
} }
#endif #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) #if defined(POLARSSL_SSL_MAX_FRAGMENT_LENGTH)
/* /*
* Convert max_fragment_length codes to 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 ); 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 ); len = SSL_BUFFER_LEN - ( ssl->in_hdr - ssl->in_buf );
if( ssl->f_recv_timeout != NULL && 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 else
ret = ssl->f_recv( ssl->p_bio, ssl->in_hdr, len ); 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" ) ); 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 ) if( ( ret = ssl_resend( ssl ) ) != 0 )
{ {
SSL_DEBUG_RET( 1, "ssl_resend", ret ); SSL_DEBUG_RET( 1, "ssl_resend", ret );
@ -2247,8 +2287,7 @@ int ssl_resend( ssl_context *ssl )
else else
ssl->handshake->retransmit_state = SSL_RETRANS_WAITING; ssl->handshake->retransmit_state = SSL_RETRANS_WAITING;
/* WIP: hardcoded 1 sec will be replaced */ ssl_set_timer( ssl, ssl->handshake->retransmit_timeout );
ssl_set_timer( ssl, 1000 );
SSL_DEBUG_MSG( 2, ( "<= ssl_resend" ) ); 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 */ /* The next incoming flight will start with this msg_seq */
ssl->handshake->in_flight_start_seq = ssl->handshake->in_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_set_timer( ssl, 0 );
ssl_reset_retransmit_timeout( ssl );
if( ssl->in_msgtype == SSL_MSG_HANDSHAKE && if( ssl->in_msgtype == SSL_MSG_HANDSHAKE &&
ssl->in_msg[0] == SSL_HS_FINISHED ) 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 ) void ssl_send_flight_completed( ssl_context *ssl )
{ {
/* WIP: hardcoded 1 sec is temporary */ ssl_set_timer( ssl, ssl->handshake->retransmit_timeout );
ssl_set_timer( ssl, 1000 );
if( ssl->in_msgtype == SSL_MSG_HANDSHAKE && if( ssl->in_msgtype == SSL_MSG_HANDSHAKE &&
ssl->in_msg[0] == SSL_HS_FINISHED ) 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; ssl->handshake->key_cert = ssl->key_cert;
#endif #endif
/*
* We may not know yet if we're using DTLS,
* so always initiliase DTLS-specific fields.
*/
#if defined(POLARSSL_SSL_PROTO_DTLS) #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;
ssl->handshake->retransmit_timeout = SSL_DTLS_TIMEOUT_DFL_MIN;
if( ssl->endpoint == SSL_IS_CLIENT ) if( ssl->endpoint == SSL_IS_CLIENT )
ssl->handshake->retransmit_state = SSL_RETRANS_PREPARING; ssl->handshake->retransmit_state = SSL_RETRANS_PREPARING;
else else
ssl->handshake->retransmit_state = SSL_RETRANS_WAITING; ssl->handshake->retransmit_state = SSL_RETRANS_WAITING;
}
#endif #endif
return( 0 ); return( 0 );