[glib-networking/wip/pwithnall/dtls: 9/13] gnutls: Support timeouts for implicit handshakes
- From: Philip Withnall <pwithnall src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib-networking/wip/pwithnall/dtls: 9/13] gnutls: Support timeouts for implicit handshakes
- Date: Thu, 2 Nov 2017 13:33:01 +0000 (UTC)
commit 2df840bc88dc6c8d5c23497cde2495d10b5a8a46
Author: Philip Withnall <philip withnall collabora co uk>
Date: Sat Apr 2 14:47:02 2016 +0100
gnutls: Support timeouts for implicit handshakes
Add support for timeouts on the implicit handshake; previously it always
blocked. This fixes per-operation timeout parameters for operations
which trigger an implicit handshake.
https://bugzilla.gnome.org/show_bug.cgi?id=697908
tls/gnutls/gtlsconnection-gnutls.c | 94 ++++++++++++++++++++++++++++++++---
1 files changed, 86 insertions(+), 8 deletions(-)
---
diff --git a/tls/gnutls/gtlsconnection-gnutls.c b/tls/gnutls/gtlsconnection-gnutls.c
index 0968a15..805f3ea 100644
--- a/tls/gnutls/gtlsconnection-gnutls.c
+++ b/tls/gnutls/gtlsconnection-gnutls.c
@@ -995,6 +995,12 @@ end_gnutls_io (GTlsConnectionGnutls *gnutls,
gnutls_dtls_get_data_mtu (gnutls->priv->session));
return status;
}
+ else if (status == GNUTLS_E_TIMEDOUT)
+ {
+ g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_TIMED_OUT,
+ _("The operation timed out"));
+ return status;
+ }
if (error)
{
@@ -1718,11 +1724,18 @@ handshake_thread (GTask *task,
gboolean is_client;
GError *error = NULL;
int ret;
+ gint64 start_time;
+ gint64 timeout;
+
+ /* A timeout, in microseconds, must be provided as a gint64* task_data. */
+ g_assert (task_data != NULL);
+ timeout = *((gint64 *) task_data);
+ start_time = g_get_monotonic_time ();
gnutls->priv->started_handshake = FALSE;
if (!claim_op (gnutls, G_TLS_CONNECTION_GNUTLS_OP_HANDSHAKE,
- -1 /* blocking */, cancellable, &error))
+ timeout, cancellable, &error))
{
g_task_return_error (task, error);
return;
@@ -1735,8 +1748,25 @@ handshake_thread (GTask *task,
if (!is_client && gnutls->priv->ever_handshaked &&
!gnutls->priv->implicit_handshake)
{
- BEGIN_GNUTLS_IO (gnutls, G_IO_IN | G_IO_OUT, -1 /* blocking */,
- cancellable);
+ /* Adjust the timeout for the next operation in the sequence. */
+ if (timeout > 0)
+ {
+ unsigned int timeout_ms;
+
+ timeout -= (g_get_monotonic_time () - start_time);
+ if (timeout <= 0)
+ timeout = 1;
+
+ /* Convert from microseconds to milliseconds, but ensure the timeout
+ * remains positive. */
+ timeout_ms = (timeout + 999) / 1000;
+
+ gnutls_handshake_set_timeout (gnutls->priv->session, timeout_ms);
+ gnutls_dtls_set_timeouts (gnutls->priv->session, 1000 /* default */,
+ timeout_ms);
+ }
+
+ BEGIN_GNUTLS_IO (gnutls, G_IO_IN | G_IO_OUT, timeout, cancellable);
ret = gnutls_rehandshake (gnutls->priv->session);
END_GNUTLS_IO (gnutls, G_IO_IN | G_IO_OUT, ret,
_("Error performing TLS handshake: %s"), &error);
@@ -1755,7 +1785,25 @@ handshake_thread (GTask *task,
g_tls_connection_gnutls_set_handshake_priority (gnutls);
- BEGIN_GNUTLS_IO (gnutls, G_IO_IN | G_IO_OUT, -1 /* blocking */, cancellable);
+ /* Adjust the timeout for the next operation in the sequence. */
+ if (timeout > 0)
+ {
+ unsigned int timeout_ms;
+
+ timeout -= (g_get_monotonic_time () - start_time);
+ if (timeout <= 0)
+ timeout = 1;
+
+ /* Convert from microseconds to milliseconds, but ensure the timeout
+ * remains positive. */
+ timeout_ms = (timeout + 999) / 1000;
+
+ gnutls_handshake_set_timeout (gnutls->priv->session, timeout_ms);
+ gnutls_dtls_set_timeouts (gnutls->priv->session, 1000 /* default */,
+ timeout_ms);
+ }
+
+ BEGIN_GNUTLS_IO (gnutls, G_IO_IN | G_IO_OUT, timeout, cancellable);
ret = gnutls_handshake (gnutls->priv->session);
if (ret == GNUTLS_E_GOT_APPLICATION_DATA)
{
@@ -1881,10 +1929,16 @@ g_tls_connection_gnutls_handshake (GTlsConnection *conn,
GTlsConnectionGnutls *gnutls = G_TLS_CONNECTION_GNUTLS (conn);
GTask *task;
gboolean success;
+ gint64 *timeout = NULL;
GError *my_error = NULL;
task = g_task_new (conn, cancellable, NULL, NULL);
g_task_set_source_tag (task, g_tls_connection_gnutls_handshake);
+
+ timeout = g_new0 (gint64, 1);
+ *timeout = -1; /* blocking */
+ g_task_set_task_data (task, timeout, g_free);
+
begin_handshake (gnutls);
g_task_run_in_thread_sync (task, handshake_thread);
success = finish_handshake (gnutls, task, &my_error);
@@ -1977,6 +2031,7 @@ g_tls_connection_gnutls_handshake_async (GTlsConnection *conn,
gpointer user_data)
{
GTask *thread_task, *caller_task;
+ gint64 *timeout = NULL;
caller_task = g_task_new (conn, cancellable, callback, user_data);
g_task_set_source_tag (caller_task, g_tls_connection_gnutls_handshake_async);
@@ -1988,6 +2043,11 @@ g_tls_connection_gnutls_handshake_async (GTlsConnection *conn,
handshake_thread_completed, caller_task);
g_task_set_source_tag (thread_task, g_tls_connection_gnutls_handshake_async);
g_task_set_priority (thread_task, io_priority);
+
+ timeout = g_new0 (gint64, 1);
+ *timeout = -1; /* blocking */
+ g_task_set_task_data (thread_task, timeout, g_free);
+
g_task_run_in_thread (thread_task, async_handshake_thread);
g_object_unref (thread_task);
}
@@ -2028,20 +2088,33 @@ do_implicit_handshake (GTlsConnectionGnutls *gnutls,
GCancellable *cancellable,
GError **error)
{
+ gint64 *thread_timeout = NULL;
+
/* We have op_mutex */
+ g_assert (gnutls->priv->implicit_handshake == NULL);
gnutls->priv->implicit_handshake = g_task_new (gnutls, cancellable, NULL, NULL);
g_task_set_source_tag (gnutls->priv->implicit_handshake,
do_implicit_handshake);
+ thread_timeout = g_new0 (gint64, 1);
+ g_task_set_task_data (gnutls->priv->implicit_handshake,
+ thread_timeout, g_free);
+
begin_handshake (gnutls);
- /* FIXME: Support (timeout > 0). */
if (timeout != 0)
{
GError *my_error = NULL;
gboolean success;
+ /* In the blocking case, run the handshake operation synchronously in
+ * another thread, and delegate handling the timeout to that thread; it
+ * should return G_IO_ERROR_TIMED_OUT iff (timeout > 0) and the operation
+ * times out. If (timeout < 0) it should block indefinitely until the
+ * operation is complete or errors. */
+ *thread_timeout = timeout;
+
g_mutex_unlock (&gnutls->priv->op_mutex);
g_task_run_in_thread_sync (gnutls->priv->implicit_handshake,
handshake_thread);
@@ -2058,12 +2131,17 @@ do_implicit_handshake (GTlsConnectionGnutls *gnutls,
}
else
{
+ /* In the non-blocking case, start the asynchronous handshake operation
+ * and return EWOULDBLOCK to the caller, who will handle polling for
+ * completion of the handshake and whatever operation they actually cared
+ * about. Run the actual operation as blocking in its thread. */
+ *thread_timeout = -1; /* blocking */
+
g_task_run_in_thread (gnutls->priv->implicit_handshake,
- async_handshake_thread);
+ async_handshake_thread);
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK,
- _("Operation would block"));
-
+ _("Operation would block"));
return FALSE;
}
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]