From: Nikos Mavrogiannopoulos Date: Fri, 21 Sep 2012 07:00:01 +0000 (+0200) Subject: Better handling of timeouts. X-Git-Tag: gnutls_3_1_2~27 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=cdacc0899faec8ec8a0cdb90bb0a2d28989a05dc;p=thirdparty%2Fgnutls.git Better handling of timeouts. --- diff --git a/doc/cha-intro-tls.texi b/doc/cha-intro-tls.texi index 581a52777c..33f6b16dca 100644 --- a/doc/cha-intro-tls.texi +++ b/doc/cha-intro-tls.texi @@ -464,7 +464,7 @@ Policy-related functions: @showfuncB{gnutls_heartbeat_allowed,gnutls_heartbeat_enable} Operational functions: -@showfuncB{gnutls_heartbeat_ping,gnutls_heartbeat_pong} +@showfuncD{gnutls_heartbeat_ping,gnutls_heartbeat_pong,gnutls_heartbeat_set_timeouts,gnutls_heartbeat_get_timeout} @node Safe renegotiation @subsection Safe renegotiation diff --git a/lib/ext/heartbeat.c b/lib/ext/heartbeat.c index 1cce81c32d..b2401c8841 100644 --- a/lib/ext/heartbeat.c +++ b/lib/ext/heartbeat.c @@ -35,6 +35,8 @@ * * This function will allow heartbeat messages to be * received. + * + * Since: 3.1.2 **/ void gnutls_heartbeat_enable (gnutls_session_t session, unsigned int type) @@ -72,6 +74,7 @@ _gnutls_heartbeat (unsigned policy) * * Returns: Non zero if heartbeats are allowed. * + * Since: 3.1.2 **/ int gnutls_heartbeat_allowed (gnutls_session_t session, unsigned int type) @@ -166,13 +169,16 @@ heartbeat_send_data (gnutls_session_t session, const void *data, * and timeouts manually. * * Returns: %GNUTLS_E_SUCCESS on success, otherwise a negative error code. + * + * Since: 3.1.2 **/ int gnutls_heartbeat_ping (gnutls_session_t session, size_t data_size, unsigned int max_tries, unsigned int flags) { int ret; - unsigned int retries = 1; + unsigned int retries = 1, diff; + struct timespec now; if (data_size > MAX_HEARTBEAT_LENGTH) return gnutls_assert_val (GNUTLS_E_UNEXPECTED_PACKET_LENGTH); @@ -196,10 +202,11 @@ gnutls_heartbeat_ping (gnutls_session_t session, size_t data_size, if (ret < 0) return gnutls_assert_val(ret); + gettime (&session->internals.hb_ping_start); session->internals.hb_local_data.length = data_size; session->internals.hb_state = SHB_SEND2; case SHB_SEND2: - session->internals.hb_timeout = HEARTBEAT_TIMEOUT; + session->internals.hb_actual_retrans_timeout_ms = session->internals.hb_retrans_timeout_ms; retry: ret = heartbeat_send_data (session, session->internals.hb_local_data.data, session->internals.hb_local_data.length, @@ -218,7 +225,7 @@ retry: session->internals.hb_state = SHB_RECV; case SHB_RECV: - ret = _gnutls_recv_int(session, GNUTLS_HEARTBEAT, -1, NULL, 0, NULL, session->internals.hb_timeout); + ret = _gnutls_recv_int(session, GNUTLS_HEARTBEAT, -1, NULL, 0, NULL, session->internals.hb_actual_retrans_timeout_ms); if (ret == GNUTLS_E_HEARTBEAT_PONG_RECEIVED) { session->internals.hb_state = SHB_SEND1; @@ -233,8 +240,15 @@ retry: return gnutls_assert_val(ret); } - session->internals.hb_timeout *= 2; - session->internals.hb_timeout %= MAX_DTLS_TIMEOUT; + diff = _dtls_timespec_sub_ms(&now, &session->internals.hb_ping_start); + if (diff > session->internals.hb_total_timeout_ms) + { + session->internals.hb_state = SHB_SEND1; + return gnutls_assert_val(GNUTLS_E_TIMEDOUT); + } + + session->internals.hb_actual_retrans_timeout_ms *= 2; + session->internals.hb_actual_retrans_timeout_ms %= MAX_DTLS_TIMEOUT; session->internals.hb_state = SHB_SEND2; goto retry; @@ -257,6 +271,8 @@ retry: * This function replies to a ping by sending a pong to the peer. * * Returns: %GNUTLS_E_SUCCESS on success, otherwise a negative error code. + * + * Since: 3.1.2 **/ int gnutls_heartbeat_pong (gnutls_session_t session, unsigned int flags) @@ -344,6 +360,60 @@ _gnutls_heartbeat_handle (gnutls_session_t session, mbuffer_st * bufel) } } +/** + * gnutls_heartbeat_get_timeout: + * @session: is a #gnutls_session_t structure. + * + * This function will return the milliseconds remaining + * for a retransmission of the previously sent ping + * message. This function is useful when ping is used in + * non-blocking mode, to estimate when to call gnutls_heartbeat_ping() + * if no packets have been received. + * + * Returns: the remaining time in milliseconds. + * + * Since: 3.1.2 + **/ +unsigned int gnutls_heartbeat_get_timeout (gnutls_session_t session) +{ +struct timespec now; +unsigned int diff; + + gettime(&now); + diff = _dtls_timespec_sub_ms(&now, &session->internals.hb_ping_sent); + if (diff >= session->internals.hb_actual_retrans_timeout_ms) + return 0; + else + return session->internals.hb_actual_retrans_timeout_ms - diff; +} + +/** + * gnutls_heartbeat_set_timeouts: + * @session: is a #gnutls_session_t structure. + * @retrans_timeout: The time at which a retransmission will occur in milliseconds + * @total_timeout: The time at which the connection will be aborted, in milliseconds. + * + * This function will set the timeouts required for the DTLS handshake + * protocol. The retransmission timeout is the time after which a + * message from the peer is not received, the previous messages will + * be retransmitted. The total timeout is the time after which the + * handshake will be aborted with %GNUTLS_E_TIMEDOUT. + * + * The DTLS protocol recommends the values of 1 sec and 60 seconds + * respectively. + * + * If the retransmission timeout is zero then the handshake will operate + * in a non-blocking way, i.e., return %GNUTLS_E_AGAIN. + * + * Since: 3.1.2 + **/ +void gnutls_heartbeat_set_timeouts (gnutls_session_t session, unsigned int retrans_timeout, + unsigned int total_timeout) +{ + session->internals.hb_retrans_timeout_ms = retrans_timeout; + session->internals.hb_total_timeout_ms = total_timeout; +} + static int _gnutls_heartbeat_recv_params (gnutls_session_t session, diff --git a/lib/ext/heartbeat.h b/lib/ext/heartbeat.h index 085d14c2a9..ee7a534ae6 100644 --- a/lib/ext/heartbeat.h +++ b/lib/ext/heartbeat.h @@ -29,8 +29,6 @@ #define HEARTBEAT_RESPONSE 2 #define MAX_HEARTBEAT_LENGTH DEFAULT_MAX_RECORD_SIZE -#define HEARTBEAT_TIMEOUT 1000 -#define MAX_HEARTBEAT_TIMEOUT 60000 #define LOCAL_ALLOWED_TO_SEND (1<<2) #define LOCAL_NOT_ALLOWED_TO_SEND (1<<3) diff --git a/lib/gnutls_int.h b/lib/gnutls_int.h index 5462789096..bf5280f51a 100644 --- a/lib/gnutls_int.h +++ b/lib/gnutls_int.h @@ -903,8 +903,11 @@ typedef struct gnutls_buffer_st hb_local_data; gnutls_buffer_st hb_remote_data; + struct timespec hb_ping_start; /* timestamp: when first HeartBeat ping was sent*/ struct timespec hb_ping_sent; /* timestamp: when last HeartBeat ping was sent*/ - unsigned int hb_timeout; /* current timeout, in milliseconds*/ + unsigned int hb_actual_retrans_timeout_ms; /* current timeout, in milliseconds*/ + unsigned int hb_retrans_timeout_ms; /* the default timeout, in milliseconds*/ + unsigned int hb_total_timeout_ms; /* the total timeout, in milliseconds*/ heartbeat_state_t hb_state; /* for ping */ diff --git a/lib/gnutls_state.c b/lib/gnutls_state.c index 6adfd417fa..5793c5c029 100644 --- a/lib/gnutls_state.c +++ b/lib/gnutls_state.c @@ -383,6 +383,9 @@ gnutls_init (gnutls_session_t * session, unsigned int flags) gnutls_transport_set_errno_function (*session, system_errno); gnutls_transport_set_pull_timeout_function (*session, system_recv_timeout); + (*session)->internals.hb_retrans_timeout_ms = 1000; + (*session)->internals.hb_total_timeout_ms = 60000; + if (flags & GNUTLS_DATAGRAM) { (*session)->internals.dtls.mtu = DTLS_DEFAULT_MTU; diff --git a/lib/includes/gnutls/gnutls.h.in b/lib/includes/gnutls/gnutls.h.in index 5ca00ae320..ef4f1269e7 100644 --- a/lib/includes/gnutls/gnutls.h.in +++ b/lib/includes/gnutls/gnutls.h.in @@ -915,6 +915,10 @@ gnutls_ecc_curve_t gnutls_ecc_curve_get(gnutls_session_t session); void *data, size_t * data_length, unsigned int *type, unsigned int indx); + unsigned int gnutls_heartbeat_get_timeout (gnutls_session_t session); + void gnutls_heartbeat_set_timeouts (gnutls_session_t session, unsigned int retrans_timeout, + unsigned int total_timeout); + #define GNUTLS_HB_PEER_ALLOWED_TO_SEND (1) #define GNUTLS_HB_PEER_NOT_ALLOWED_TO_SEND (1<<1) diff --git a/lib/libgnutls.map b/lib/libgnutls.map index 110209cff9..8df7823577 100644 --- a/lib/libgnutls.map +++ b/lib/libgnutls.map @@ -301,8 +301,6 @@ GNUTLS_1_4 gnutls_record_recv; gnutls_record_send; gnutls_record_set_max_size; - gnutls_heartbeat_ping; - gnutls_heartbeat_pong; gnutls_rehandshake; gnutls_rsa_export_get_modulus_bits; gnutls_rsa_export_get_pubkey; @@ -335,8 +333,6 @@ GNUTLS_1_4 gnutls_sign_get_id; gnutls_sign_get_name; gnutls_sign_list; - gnutls_heartbeat_enable; - gnutls_heartbeat_allowed; gnutls_srp_1024_group_generator; gnutls_srp_1024_group_prime; gnutls_srp_1536_group_generator; @@ -834,6 +830,12 @@ GNUTLS_3_1_0 { gnutls_sign_get_hash_algorithm; gnutls_sign_algorithm_get; gnutls_x509_privkey_get_pk_algorithm2; + gnutls_heartbeat_ping; + gnutls_heartbeat_pong; + gnutls_heartbeat_enable; + gnutls_heartbeat_allowed; + gnutls_heartbeat_get_timeout; + gnutls_heartbeat_set_timeouts; } GNUTLS_3_0_0; GNUTLS_PRIVATE {