[glib-networking/wip/pwithnall/dtls: 17/17] gnutls: Internally support per-operation timeouts
- From: Philip Withnall <pwithnall src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib-networking/wip/pwithnall/dtls: 17/17] gnutls: Internally support per-operation timeouts
- Date: Mon, 11 Jan 2016 15:14:35 +0000 (UTC)
commit c645852081f181d48b3615f37e8cfbcdaa5f0dae
Author: Philip Withnall <philip withnall collabora co uk>
Date: Thu Jul 30 15:56:00 2015 +0100
gnutls: Internally support per-operation timeouts
For every operation except handshaking (which is complex), convert the
per-operation blocking parameter to a timeout parameter, supporting
blocking, non-blocking and timeout behaviour. This can be used by the
GDatagramBased interface to support its per-operation timeouts.
https://bugzilla.gnome.org/show_bug.cgi?id=697908
tls/gnutls/gtlsconnection-gnutls.c | 102 ++++++++++++++++++++++------------
tls/gnutls/gtlsconnection-gnutls.h | 4 +-
tls/gnutls/gtlsinputstream-gnutls.c | 5 +-
tls/gnutls/gtlsoutputstream-gnutls.c | 5 +-
4 files changed, 74 insertions(+), 42 deletions(-)
---
diff --git a/tls/gnutls/gtlsconnection-gnutls.c b/tls/gnutls/gtlsconnection-gnutls.c
index 3381cdd..a12c9d0 100644
--- a/tls/gnutls/gtlsconnection-gnutls.c
+++ b/tls/gnutls/gtlsconnection-gnutls.c
@@ -115,7 +115,7 @@ static P11KitPin* on_pin_prompt_callback (const char *pinfile,
static void g_tls_connection_gnutls_init_priorities (void);
static gboolean do_implicit_handshake (GTlsConnectionGnutls *gnutls,
- gboolean blocking,
+ gint64 timeout,
GCancellable *cancellable,
GError **error);
static gboolean finish_handshake (GTlsConnectionGnutls *gnutls,
@@ -220,12 +220,12 @@ struct _GTlsConnectionGnutlsPrivate
GCancellable *waiting_for_op;
gboolean reading;
- gboolean read_blocking;
+ gint64 read_timeout;
GError *read_error;
GCancellable *read_cancellable;
gboolean writing;
- gboolean write_blocking;
+ gint64 write_timeout;
GError *write_error;
GCancellable *write_cancellable;
@@ -668,7 +668,7 @@ typedef enum {
static gboolean
claim_op (GTlsConnectionGnutls *gnutls,
GTlsConnectionGnutlsOp op,
- gboolean blocking,
+ gint64 timeout,
GCancellable *cancellable,
GError **error)
{
@@ -711,7 +711,7 @@ claim_op (GTlsConnectionGnutls *gnutls,
{
gnutls->priv->need_handshake = FALSE;
gnutls->priv->handshaking = TRUE;
- if (!do_implicit_handshake (gnutls, blocking, cancellable, error))
+ if (!do_implicit_handshake (gnutls, timeout, cancellable, error))
{
g_mutex_unlock (&gnutls->priv->op_mutex);
return FALSE;
@@ -751,12 +751,14 @@ claim_op (GTlsConnectionGnutls *gnutls,
{
GPollFD fds[2];
int nfds;
+ gint64 start_time;
+ gint result;
g_cancellable_reset (gnutls->priv->waiting_for_op);
g_mutex_unlock (&gnutls->priv->op_mutex);
- if (!blocking)
+ if (timeout == 0)
{
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK,
_("Operation would block"));
@@ -769,11 +771,39 @@ claim_op (GTlsConnectionGnutls *gnutls,
else
nfds = 1;
- g_poll (fds, nfds, -1);
+ /* Convert from microseconds to milliseconds. */
+ if (timeout != -1)
+ timeout = timeout / 1000;
+
+ /* Poll until cancellation or the timeout is reached. */
+ start_time = g_get_monotonic_time ();
+
+ while (!g_cancellable_is_cancelled (gnutls->priv->waiting_for_op) &&
+ !g_cancellable_is_cancelled (cancellable))
+ {
+ result = g_poll (fds, nfds, timeout);
+
+ if (result != -1 || errno != EINTR)
+ continue;
+
+ if (timeout != -1)
+ {
+ timeout -= (g_get_monotonic_time () - start_time) / 1000;
+ if (timeout < 0)
+ timeout = 0;
+ }
+ }
if (nfds > 1)
g_cancellable_release_fd (cancellable);
+ if (result == 0)
+ {
+ g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_TIMED_OUT,
+ _("Socket I/O timed out"));
+ return FALSE;
+ }
+
goto try_again;
}
@@ -825,21 +855,21 @@ yield_op (GTlsConnectionGnutls *gnutls,
static void
begin_gnutls_io (GTlsConnectionGnutls *gnutls,
GIOCondition direction,
- gboolean blocking,
+ gint64 timeout,
GCancellable *cancellable)
{
g_assert (direction & (G_IO_IN | G_IO_OUT));
if (direction & G_IO_IN)
{
- gnutls->priv->read_blocking = blocking;
+ gnutls->priv->read_timeout = timeout;
gnutls->priv->read_cancellable = cancellable;
g_clear_error (&gnutls->priv->read_error);
}
if (direction & G_IO_OUT)
{
- gnutls->priv->write_blocking = blocking;
+ gnutls->priv->write_timeout = timeout;
gnutls->priv->write_cancellable = cancellable;
g_clear_error (&gnutls->priv->write_error);
}
@@ -979,8 +1009,8 @@ end_gnutls_io (GTlsConnectionGnutls *gnutls,
return status;
}
-#define BEGIN_GNUTLS_IO(gnutls, direction, blocking, cancellable) \
- begin_gnutls_io (gnutls, direction, blocking, cancellable); \
+#define BEGIN_GNUTLS_IO(gnutls, direction, timeout, cancellable) \
+ begin_gnutls_io (gnutls, direction, timeout, cancellable); \
do {
#define END_GNUTLS_IO(gnutls, direction, ret, errmsg, err) \
@@ -1334,7 +1364,7 @@ g_tls_connection_gnutls_pull_func (gnutls_transport_ptr_t transport_data,
ret = g_datagram_based_receive_messages (gnutls->priv->base_socket,
&message, 1, 0,
- gnutls->priv->read_blocking ? -1 : 0,
+ gnutls->priv->read_timeout,
gnutls->priv->read_cancellable,
&gnutls->priv->read_error);
@@ -1345,7 +1375,7 @@ g_tls_connection_gnutls_pull_func (gnutls_transport_ptr_t transport_data,
{
ret = g_pollable_stream_read (G_INPUT_STREAM (gnutls->priv->base_istream),
buf, buflen,
- gnutls->priv->read_blocking,
+ (gnutls->priv->read_timeout != 0),
gnutls->priv->read_cancellable,
&gnutls->priv->read_error);
}
@@ -1378,7 +1408,7 @@ g_tls_connection_gnutls_push_func (gnutls_transport_ptr_t transport_data,
ret = g_datagram_based_send_messages (gnutls->priv->base_socket,
&message, 1, 0,
- gnutls->priv->write_blocking ? -1 : 0,
+ gnutls->priv->write_timeout,
gnutls->priv->write_cancellable,
&gnutls->priv->write_error);
@@ -1389,7 +1419,7 @@ g_tls_connection_gnutls_push_func (gnutls_transport_ptr_t transport_data,
{
ret = g_pollable_stream_write (G_OUTPUT_STREAM (gnutls->priv->base_ostream),
buf, buflen,
- gnutls->priv->write_blocking,
+ (gnutls->priv->write_timeout != 0),
gnutls->priv->write_cancellable,
&gnutls->priv->write_error);
}
@@ -1445,7 +1475,7 @@ g_tls_connection_gnutls_vec_push_func (gnutls_transport_ptr_t transport_data,
ret = g_datagram_based_send_messages (gnutls->priv->base_socket,
&message, 1, 0,
- gnutls->priv->write_blocking,
+ gnutls->priv->write_timeout,
gnutls->priv->write_cancellable,
&gnutls->priv->write_error);
@@ -1614,7 +1644,7 @@ handshake_thread (GTask *task,
gnutls->priv->started_handshake = FALSE;
if (!claim_op (gnutls, G_TLS_CONNECTION_GNUTLS_OP_HANDSHAKE,
- TRUE, cancellable, &error))
+ -1 /* blocking */, cancellable, &error))
{
g_task_return_error (task, error);
return;
@@ -1627,7 +1657,8 @@ 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, TRUE, cancellable);
+ BEGIN_GNUTLS_IO (gnutls, G_IO_IN | G_IO_OUT, -1 /* blocking */,
+ cancellable);
ret = gnutls_rehandshake (gnutls->priv->session);
END_GNUTLS_IO (gnutls, G_IO_IN | G_IO_OUT, ret,
_("Error performing TLS handshake: %s"), &error);
@@ -1646,7 +1677,7 @@ handshake_thread (GTask *task,
g_tls_connection_gnutls_set_handshake_priority (gnutls);
- BEGIN_GNUTLS_IO (gnutls, G_IO_IN | G_IO_OUT, TRUE, cancellable);
+ BEGIN_GNUTLS_IO (gnutls, G_IO_IN | G_IO_OUT, -1 /* blocking */, cancellable);
ret = gnutls_handshake (gnutls->priv->session);
if (ret == GNUTLS_E_GOT_APPLICATION_DATA)
{
@@ -1915,7 +1946,7 @@ g_tls_connection_gnutls_dtls_handshake_finish (GDtlsConnection *conn,
static gboolean
do_implicit_handshake (GTlsConnectionGnutls *gnutls,
- gboolean blocking,
+ gint64 timeout,
GCancellable *cancellable,
GError **error)
{
@@ -1927,7 +1958,8 @@ do_implicit_handshake (GTlsConnectionGnutls *gnutls,
begin_handshake (gnutls);
- if (blocking)
+ /* FIXME: Support (timeout > 0). */
+ if (timeout != 0)
{
GError *my_error = NULL;
gboolean success;
@@ -1962,7 +1994,7 @@ gssize
g_tls_connection_gnutls_read (GTlsConnectionGnutls *gnutls,
void *buffer,
gsize count,
- gboolean blocking,
+ gint64 timeout,
GCancellable *cancellable,
GError **error)
{
@@ -1981,10 +2013,10 @@ g_tls_connection_gnutls_read (GTlsConnectionGnutls *gnutls,
again:
if (!claim_op (gnutls, G_TLS_CONNECTION_GNUTLS_OP_READ,
- blocking, cancellable, error))
+ timeout, cancellable, error))
return -1;
- BEGIN_GNUTLS_IO (gnutls, G_IO_IN, blocking, cancellable);
+ BEGIN_GNUTLS_IO (gnutls, G_IO_IN, timeout, cancellable);
ret = gnutls_record_recv (gnutls->priv->session, buffer, count);
END_GNUTLS_IO (gnutls, G_IO_IN, ret, _("Error reading data from TLS socket: %s"), error);
@@ -2068,10 +2100,10 @@ g_tls_connection_gnutls_read_message (GTlsConnectionGnutls *gnutls,
again:
if (!claim_op (gnutls, G_TLS_CONNECTION_GNUTLS_OP_READ,
- timeout != 0, cancellable, error))
+ timeout, cancellable, error))
return -1;
- BEGIN_GNUTLS_IO (gnutls, G_IO_IN, timeout != 0, cancellable);
+ BEGIN_GNUTLS_IO (gnutls, G_IO_IN, timeout, cancellable);
/* Receive the entire datagram (zero-copy). */
ret = gnutls_record_recv_packet (gnutls->priv->session, &packet);
@@ -2172,7 +2204,7 @@ gssize
g_tls_connection_gnutls_write (GTlsConnectionGnutls *gnutls,
const void *buffer,
gsize count,
- gboolean blocking,
+ gint64 timeout,
GCancellable *cancellable,
GError **error)
{
@@ -2180,7 +2212,7 @@ g_tls_connection_gnutls_write (GTlsConnectionGnutls *gnutls,
again:
if (!claim_op (gnutls, G_TLS_CONNECTION_GNUTLS_OP_WRITE,
- blocking, cancellable, error))
+ timeout, cancellable, error))
return -1;
if (gnutls_dtls_get_data_mtu (gnutls->priv->session) < count)
@@ -2194,7 +2226,7 @@ g_tls_connection_gnutls_write (GTlsConnectionGnutls *gnutls,
goto done;
}
- BEGIN_GNUTLS_IO (gnutls, G_IO_OUT, blocking, cancellable);
+ BEGIN_GNUTLS_IO (gnutls, G_IO_OUT, timeout, cancellable);
ret = gnutls_record_send (gnutls->priv->session, buffer, count);
END_GNUTLS_IO (gnutls, G_IO_OUT, ret, _("Error writing data to TLS socket: %s"), error);
@@ -2223,7 +2255,7 @@ g_tls_connection_gnutls_write_message (GTlsConnectionGnutls *gnutls,
again:
if (!claim_op (gnutls, G_TLS_CONNECTION_GNUTLS_OP_WRITE,
- timeout != 0, cancellable, error))
+ timeout, cancellable, error))
return -1;
/* Calculate the total message size and check it’s not too big. */
@@ -2257,7 +2289,7 @@ g_tls_connection_gnutls_write_message (GTlsConnectionGnutls *gnutls,
}
}
- BEGIN_GNUTLS_IO (gnutls, G_IO_OUT, timeout != 0, cancellable);
+ BEGIN_GNUTLS_IO (gnutls, G_IO_OUT, timeout, cancellable);
ret = gnutls_record_uncork (gnutls->priv->session, 0 /* flags */);
END_GNUTLS_IO (gnutls, G_IO_OUT, ret, _("Error writing data to TLS socket: %s"), error);
@@ -2372,8 +2404,6 @@ g_tls_connection_gnutls_close_internal (GIOStream *stream,
* this class and how the underlying stream is closed.
*/
- /* FIXME: This does not properly support the @timeout parameter. */
-
g_return_val_if_fail (direction != G_TLS_DIRECTION_NONE, FALSE);
if (direction == G_TLS_DIRECTION_BOTH)
@@ -2383,13 +2413,13 @@ g_tls_connection_gnutls_close_internal (GIOStream *stream,
else
op = G_TLS_CONNECTION_GNUTLS_OP_CLOSE_WRITE;
- if (!claim_op (gnutls, op, TRUE, cancellable, error))
+ if (!claim_op (gnutls, op, timeout, cancellable, error))
return FALSE;
if (gnutls->priv->ever_handshaked && !gnutls->priv->write_closed &&
direction & G_TLS_DIRECTION_WRITE)
{
- BEGIN_GNUTLS_IO (gnutls, G_IO_IN | G_IO_OUT, TRUE, cancellable);
+ BEGIN_GNUTLS_IO (gnutls, G_IO_IN | G_IO_OUT, timeout, cancellable);
ret = gnutls_bye (gnutls->priv->session, GNUTLS_SHUT_WR);
END_GNUTLS_IO (gnutls, G_IO_IN | G_IO_OUT, ret,
_("Error performing TLS close: %s"), &gnutls_error);
diff --git a/tls/gnutls/gtlsconnection-gnutls.h b/tls/gnutls/gtlsconnection-gnutls.h
index b4a8480..1559b58 100644
--- a/tls/gnutls/gtlsconnection-gnutls.h
+++ b/tls/gnutls/gtlsconnection-gnutls.h
@@ -63,13 +63,13 @@ gboolean g_tls_connection_gnutls_request_certificate (GTlsConnectionGnutls *gnu
gssize g_tls_connection_gnutls_read (GTlsConnectionGnutls *gnutls,
void *buffer,
gsize size,
- gboolean blocking,
+ gint64 timeout,
GCancellable *cancellable,
GError **error);
gssize g_tls_connection_gnutls_write (GTlsConnectionGnutls *gnutls,
const void *buffer,
gsize size,
- gboolean blocking,
+ gint64 timeout,
GCancellable *cancellable,
GError **error);
diff --git a/tls/gnutls/gtlsinputstream-gnutls.c b/tls/gnutls/gtlsinputstream-gnutls.c
index 4b1685d..417f4af 100644
--- a/tls/gnutls/gtlsinputstream-gnutls.c
+++ b/tls/gnutls/gtlsinputstream-gnutls.c
@@ -69,7 +69,7 @@ g_tls_input_stream_gnutls_read (GInputStream *stream,
g_return_val_if_fail (conn != NULL, -1);
ret = g_tls_connection_gnutls_read (conn,
- buffer, count, TRUE,
+ buffer, count, -1 /* blocking */,
cancellable, error);
g_object_unref (conn);
return ret;
@@ -120,7 +120,8 @@ g_tls_input_stream_gnutls_pollable_read_nonblocking (GPollableInputStream *poll
conn = g_weak_ref_get (&tls_stream->priv->weak_conn);
g_return_val_if_fail (conn != NULL, -1);
- ret = g_tls_connection_gnutls_read (conn, buffer, size, FALSE, NULL, error);
+ ret = g_tls_connection_gnutls_read (conn, buffer, size,
+ 0 /* non-blocking */, NULL, error);
g_object_unref (conn);
return ret;
diff --git a/tls/gnutls/gtlsoutputstream-gnutls.c b/tls/gnutls/gtlsoutputstream-gnutls.c
index 4c7853b..b9bd638 100644
--- a/tls/gnutls/gtlsoutputstream-gnutls.c
+++ b/tls/gnutls/gtlsoutputstream-gnutls.c
@@ -68,7 +68,7 @@ g_tls_output_stream_gnutls_write (GOutputStream *stream,
conn = g_weak_ref_get (&tls_stream->priv->weak_conn);
g_return_val_if_fail (conn != NULL, -1);
- ret = g_tls_connection_gnutls_write (conn, buffer, count, TRUE,
+ ret = g_tls_connection_gnutls_write (conn, buffer, count, -1 /* blocking */,
cancellable, error);
g_object_unref (conn);
return ret;
@@ -122,7 +122,8 @@ g_tls_output_stream_gnutls_pollable_write_nonblocking (GPollableOutputStream *p
conn = g_weak_ref_get (&tls_stream->priv->weak_conn);
g_return_val_if_fail (conn != NULL, -1);
- ret = g_tls_connection_gnutls_write (conn, buffer, size, FALSE, NULL, error);
+ ret = g_tls_connection_gnutls_write (conn, buffer, size,
+ 0 /* non-blocking */, NULL, error);
g_object_unref (conn);
return ret;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]