an insecure level. If the %COMPAT priority flag is not specified
the TLS connection fails.
+** libgnutls: Correctly restore gnutls_record_recv() in DTLS mode
+if interrupted during the retrasmition of handshake data.
+
** libgnutls: Better mingw32 support (patch by LRN).
** libgnutls: The %COMPAT keyword, if specified, will tolerate
the DTLS protocol this requirement isn't true.
There are cases where a retransmission is required, which are indicated by
a received message and thus @funcref{gnutls_record_get_direction} must be called
-to decide which operation to restore, i.e., send or receive.
+to decide which direction to check prior to restoring a function call.
@showfuncdesc{gnutls_record_get_direction}
Moreover, to prevent blocking from DTLS' retransmission timers to block a
return 0;
}
-/* This function is to be called from record layer once
- * a handshake replay is detected. It will make sure
- * it transmits only once per few seconds. Otherwise
- * it is the same as _dtls_transmit().
- */
-int _dtls_retransmit(gnutls_session_t session)
-{
- return _dtls_transmit(session);
-}
/* Checks whether the received packet contains a handshake
* packet with sequence higher that the previously received.
#include <timespec.h>
int _dtls_transmit(gnutls_session_t session);
-int _dtls_retransmit(gnutls_session_t session);
int _dtls_record_check(struct record_parameters_st *rp, uint64 * _seq);
void _dtls_reset_hsk_state(gnutls_session_t session);
return session->internals.dtls.async_term;
}
+/* This function is to be called from record layer once
+ * a handshake replay is detected. It will make sure
+ * it transmits only once per few seconds. Otherwise
+ * it is the same as _dtls_transmit().
+ */
+inline static int _dtls_retransmit(gnutls_session_t session)
+{
+ return _dtls_transmit(session);
+}
+
#endif
SHB_RECV,
} heartbeat_state_t;
+typedef enum recv_state_t
+{
+ RECV_STATE_0 = 0,
+ RECV_STATE_DTLS_RETRANSMIT,
+} recv_state_t;
+
#include <gnutls_str.h>
/* This is the maximum number of algorithms (ciphers or macs etc).
heartbeat_state_t hb_state; /* for ping */
+ recv_state_t recv_state; /* state of the receive function */
+
/* If you add anything here, check _gnutls_handshake_internal_state_clear().
*/
} internals_st;
ret = gnutls_assert_val(GNUTLS_E_UNEXPECTED_PACKET);
goto unexpected_packet;
}
-
+
if (_dtls_is_async(session) && _dtls_async_timer_active(session))
{
if (session->security_parameters.entity == GNUTLS_SERVER &&
}
else
{
+ session->internals.recv_state = RECV_STATE_DTLS_RETRANSMIT;
ret = _dtls_retransmit(session);
if (ret == 0)
{
+ session->internals.recv_state = RECV_STATE_0;
ret = gnutls_assert_val(GNUTLS_E_AGAIN);
goto unexpected_packet;
}
gnutls_assert ();
return GNUTLS_E_INVALID_SESSION;
}
+
+ switch(session->internals.recv_state)
+ {
+ case RECV_STATE_DTLS_RETRANSMIT:
+ ret = _dtls_retransmit(session);
+ if (ret < 0)
+ return gnutls_assert_val(ret);
+
+ session->internals.recv_state = RECV_STATE_0;
+ case RECV_STATE_0:
+
+ _dtls_async_timer_check(session);
+ /* If we have enough data in the cache do not bother receiving
+ * a new packet. (in order to flush the cache)
+ */
+ ret = check_buffers (session, type, data, data_size, seq);
+ if (ret != 0)
+ return ret;
- _dtls_async_timer_check(session);
-
- /* If we have enough data in the cache do not bother receiving
- * a new packet. (in order to flush the cache)
- */
- ret = check_buffers (session, type, data, data_size, seq);
- if (ret != 0)
- return ret;
-
- ret = _gnutls_recv_in_buffers(session, type, htype, ms);
- if (ret < 0 && ret != GNUTLS_E_SESSION_EOF)
- return gnutls_assert_val(ret);
+ ret = _gnutls_recv_in_buffers(session, type, htype, ms);
+ if (ret < 0 && ret != GNUTLS_E_SESSION_EOF)
+ return gnutls_assert_val(ret);
- return check_buffers (session, type, data, data_size, seq);
+ return check_buffers (session, type, data, data_size, seq);
+ default:
+ return gnutls_assert_val(GNUTLS_E_INTERNAL_ERROR);
+ }
}
/**