[glib-networking/mcatanzaro/tls-thread: 1/19] progress



commit 3d31fee6d7fe7de9bb00991d3e103b1f8dd95a8c
Author: Michael Catanzaro <mcatanzaro igalia com>
Date:   Mon Jul 8 10:12:18 2019 -0500

    progress

 tls/base/gtlsconnection-base.c     |   1 +
 tls/base/gtlsconnection-base.h     |   1 +
 tls/base/gtlsthread-base.c         | 219 +++++++++++++++++++++++++++++++++++++
 tls/base/gtlsthread-base.h         | 118 ++++++++++++++++++++
 tls/base/meson.build               |   1 +
 tls/gnutls/gtlsconnection-gnutls.c |   1 +
 6 files changed, 341 insertions(+)
---
diff --git a/tls/base/gtlsconnection-base.c b/tls/base/gtlsconnection-base.c
index f6b499a..6dad5a3 100644
--- a/tls/base/gtlsconnection-base.c
+++ b/tls/base/gtlsconnection-base.c
@@ -3,6 +3,7 @@
  * GIO - GLib Input, Output and Streaming Library
  *
  * Copyright 2009-2011 Red Hat, Inc
+ * Copyright 2019 Igalia S.L.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
diff --git a/tls/base/gtlsconnection-base.h b/tls/base/gtlsconnection-base.h
index aa56d64..fb854eb 100644
--- a/tls/base/gtlsconnection-base.h
+++ b/tls/base/gtlsconnection-base.h
@@ -3,6 +3,7 @@
  * GIO - GLib Input, Output and Streaming Library
  *
  * Copyright 2009-2011 Red Hat, Inc
+ * Copyright 2019 Igalia S.L.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
diff --git a/tls/base/gtlsthread-base.c b/tls/base/gtlsthread-base.c
new file mode 100644
index 0000000..eb75b86
--- /dev/null
+++ b/tls/base/gtlsthread-base.c
@@ -0,0 +1,219 @@
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright 2019 Igalia S.L.
+ * Copyright 2019 Metrological Group B.V.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * In addition, when the library is used with OpenSSL, a special
+ * exception applies. Refer to the LICENSE_EXCEPTION file for details.
+ */
+
+#include "config.h"
+
+#include "gtlsthread-base.h"
+
+/* The purpose of this class is to ensure the underlying TLS library is only
+ * ever used on a single thread. There are multiple benefits of this:
+ *
+ * - OpenSSL objects like the SSL* are not threadsafe and must only be accessed
+ *   from a single thread.
+ *
+ * - With GnuTLS, this dramatically simplifies implementation of post-handshake
+ *   authentication and alerts, which are hard to handle when the
+ *   gnutls_session_t may be used on multiple threads at once.
+ *
+ * - GTlsConnectionBase and its subclasses are very complicated, and it has
+ *   become difficult to ensure the correctness of the code considering that the
+ *   threadsafety semantics of its parent class, GIOStream, allow it to be used
+ *   from separate reader and writer threads simultaneously.
+ *
+ * While the TLS thread class is intended to simplify our code, it has one
+ * disadvantage: the TLS thread *must never block* because GIOStream users are
+ * allowed to do a sync read and a sync write simultaneously in separate threads
+ * threads. Consider a hypothetical scenario:
+ *
+ * (1) Application starts a read on thread A
+ * (2) Application starts a write on thread B
+ * (3) Application's peer waits for the write to complete before sending data.
+ *
+ * In this scenario, the read on thread A is stalled until the write on thread B
+ * is completed. The application is allowed to do this and expect it to work,
+ * because GIOStream says it will work. If our TLS thread were to block on the
+ * read, then the write would never start, and the read could never complete.
+ * This means that underlying TLS operations must use async I/O. To emulate
+ * blocking operations, we will have to use poll().
+ */
+typedef struct {
+  GThread *thread;
+  GAsyncQueue *queue;
+} GTlsThreadBasePrivate;
+
+typedef enum {
+  G_TLS_THREAD_OP_READ,
+  G_TLS_THREAD_OP_SHUTDOWN
+} GTlsThreadOperationType;
+
+typedef struct {
+  GTlsThreadOperationType type;
+  void *data; /* unowned */
+  gsize size;
+  gint64 timeout;
+  GCancellable *cancellable;
+  GMainLoop *main_loop;
+  gint result;
+} GTlsThreadOperation;
+
+G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GTlsThreadBase, g_tls_thread_base, G_TYPE_TLS_THREAD_BASE)
+
+static GTlsThreadOperation *
+g_tls_thread_operation_new (GTlsThreadOperationType  type,
+                            void                    *data,
+                            gsize                    size,
+                            gint64                   timeout,
+                            GCancellable            *cancellable,
+                            GMainLoop               *main_loop,
+                            gint                     result)
+{
+  GTlsThreadOperation *op;
+
+  op = g_new (GTlsThreadOperation, 1);
+  op->type = type;
+  op->data = data;
+  op->size = size;
+  op->timeout = timeout;
+  op->cancellable = g_object_ref (cancellable);
+  op->main_loop = g_main_loop_ref (main_loop);
+  op->result = 0;
+
+  return op;
+}
+
+static GTlsThreadOperation *
+g_tls_thread_shutdown_operation_new (void)
+{
+  GTlsThreadOperation *op;
+
+  op = g_new0 (GTlsThreadOperation, 1);
+  op->type = G_TLS_THREAD_OP_SHUTDOWN;
+
+  return op;
+}
+
+static void
+g_tls_thread_operation_free (GTlsThreadOperation *op)
+{
+  g_clear_pointer (&op->data, g_free);
+  g_clear_object (&op->cancellable);
+  g_clear_pointer (&op->main_context, g_main_loop_unref);
+  g_free (op);
+}
+
+gssize
+g_tls_thread_base_read (GTlsThreadBase  *tls,
+                        void            *buffer,
+                        gsize            size,
+                        gint64           timeout,
+                        GCancellable    *cancellable,
+                        GError         **error)
+{
+  GTlsThreadBasePrivate *priv = g_tls_thread_base_get_instance_private (tls);
+  GTlsThreadOperation *op;
+  GMainContext *main_context;
+  GMainLoop *main_loop;
+
+  main_context = g_main_context_new ();
+  main_loop = g_main_loop_new (main_context, FALSE);
+  op = g_tls_thread_operation_new (G_TLS_THREAD_OP_READ,
+                                   buffer, size, timeout,
+                                   cancellable, main_loop);
+  g_async_queue_push (priv->queue, op);
+
+  /* FIXME: must respect timeout somehow */
+  g_main_loop_run (main_loop);
+
+  /* FIXME: do something with result */
+
+  g_main_context_unref (main_context);
+  g_main_loop_unref (main_loop);
+}
+
+static gpointer
+tls_thread (gpointer data)
+{
+  GAsyncQueue *queue = g_object_ref (data);
+  gboolean done = FALSE;
+
+  while (!done)
+    {
+      GTlsThreadOperation *op;
+
+      op = g_async_queue_pop (queue);
+
+      switch (op->type)
+        {
+        case G_TLS_THREAD_OP_READ:
+          /* FIXME: handle this */
+          break;
+        case G_TLS_THREAD_OP_SHUTDOWN:
+          break;
+        }
+
+      if (op->type != G_TLS_THREAD_OP_SHUTDOWN)
+        g_main_loop_quit (op->main_loop);
+      else
+        done = TRUE;
+
+      g_tls_thread_operation_free (op);
+    }
+
+  g_object_unref (queue);
+}
+
+static void
+g_tls_thread_base_init (GTlsThreadBase *tls)
+{
+  GTlsThreadBasePrivate *priv = g_tls_thread_base_get_instance_private (tls);
+
+  priv->thread = g_thread_new ("[glib-networking] GTlsThreadBase TLS operations thread", tls_thread, 
priv->queue);
+  priv->async_queue = g_async_queue_new_full (g_tls_thread_operation_free);
+}
+
+static void
+g_tls_thread_base_dispose (GObject *object)
+{
+  GTlsThreadBase *thread = G_TLS_THREAD_BASE (object);
+  GTlsThreadBasePrivate *priv = g_tls_thread_base_get_instance_private (thread);
+  GTlsThreadOperation *op;
+
+  if (priv->queue)
+    {
+      g_async_queue_push (priv->queue, g_tls_thread_shutdown_operation_new ());
+      g_clear_pointer (&priv->thread, g_thread_join);
+      g_clear_pointer (&priv->queue, g_async_queue_unref);
+    }
+
+  G_OBJECT_CLASS (g_tls_thread_base_parent_class)->dispose (object);
+}
+
+static void
+g_tls_thread_base_class_init (GTlsThreadBaseClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+  gobject_class->dispose = g_tls_thread_base_dispose;
+}
diff --git a/tls/base/gtlsthread-base.h b/tls/base/gtlsthread-base.h
new file mode 100644
index 0000000..9b09f1b
--- /dev/null
+++ b/tls/base/gtlsthread-base.h
@@ -0,0 +1,118 @@
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/*
+ * GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright 2019 Igalia S.L.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * In addition, when the library is used with OpenSSL, a special
+ * exception applies. Refer to the LICENSE_EXCEPTION file for details.
+ */
+
+#pragma once
+
+#include <gio/gio.h>
+
+#include "GTlsConnectionBase.h"
+
+G_BEGIN_DECLS
+
+#define G_TYPE_TLS_THREAD_BASE            (g_tls_thread_base_get_type ())
+
+G_DECLARE_DERIVABLE_TYPE (GTlsThreadBase, g_tls_thread_base, G, TLS_THREAD_BASE, GObject)
+
+struct _GTlsThreadBaseClass
+{
+  GObjectClass parent_class;
+
+#if 0
+  void                        (*prepare_handshake)          (GTlsConnectionBase   *tls,
+                                                             gchar               **advertised_protocols);
+  GTlsSafeRenegotiationStatus (*handshake_thread_safe_renegotiation_status)
+                                                            (GTlsConnectionBase    *tls);
+  GTlsConnectionBaseStatus    (*handshake_thread_request_rehandshake)
+                                                            (GTlsConnectionBase   *tls,
+                                                             gint64                timeout,
+                                                             GCancellable         *cancellable,
+                                                             GError              **error);
+  GTlsConnectionBaseStatus    (*handshake_thread_handshake) (GTlsConnectionBase   *tls,
+                                                             gint64                timeout,
+                                                             GCancellable         *cancellable,
+                                                             GError              **error);
+  GTlsCertificate            *(*retrieve_peer_certificate)  (GTlsConnectionBase   *tls);
+  GTlsCertificateFlags        (*verify_peer_certificate)    (GTlsConnectionBase   *tls,
+                                                             GTlsCertificate      *certificate,
+                                                             GTlsCertificateFlags  flags);
+  void                        (*complete_handshake)         (GTlsConnectionBase   *tls,
+                                                             gchar               **negotiated_protocol,
+                                                             GError              **error);
+
+  gboolean                    (*is_session_resumed)         (GTlsConnectionBase   *tls);
+
+  void                        (*push_io)                    (GTlsConnectionBase   *tls,
+                                                             GIOCondition          direction,
+                                                             gint64                timeout,
+                                                             GCancellable         *cancellable);
+  GTlsConnectionBaseStatus    (*pop_io)                     (GTlsConnectionBase   *tls,
+                                                             GIOCondition          direction,
+                                                             gboolean              success,
+                                                             GError              **error);
+
+  GTlsConnectionBaseStatus    (*read_fn)                    (GTlsConnectionBase   *tls,
+                                                             void                 *buffer,
+                                                             gsize                 count,
+                                                             gint64                timeout,
+                                                             gssize               *nread,
+                                                             GCancellable         *cancellable,
+                                                             GError              **error);
+  GTlsConnectionBaseStatus    (*read_message_fn)            (GTlsConnectionBase   *tls,
+                                                             GInputVector         *vectors,
+                                                             guint                 num_vectors,
+                                                             gint64                timeout,
+                                                             gssize               *nread,
+                                                             GCancellable         *cancellable,
+                                                             GError              **error);
+
+  GTlsConnectionBaseStatus    (*write_fn)                   (GTlsConnectionBase   *tls,
+                                                             const void           *buffer,
+                                                             gsize                 count,
+                                                             gint64                timeout,
+                                                             gssize               *nwrote,
+                                                             GCancellable         *cancellable,
+                                                             GError              **error);
+  GTlsConnectionBaseStatus    (*write_message_fn)           (GTlsConnectionBase   *tls,
+                                                             GOutputVector        *vectors,
+                                                             guint                 num_vectors,
+                                                             gint64                timeout,
+                                                             gssize               *nwrote,
+                                                             GCancellable         *cancellable,
+                                                             GError              **error);
+
+  GTlsConnectionBaseStatus    (*close_fn)                   (GTlsConnectionBase   *tls,
+                                                             gint64                timeout,
+                                                             GCancellable         *cancellable,
+                                                             GError              **error);
+#endif
+};
+
+gssize g_tls_thread_base_read (GTlsThreadBase  *tls,
+                               void            *buffer,
+                               gsize            size,
+                               gint64           timeout,
+                               GCancellable    *cancellable,
+                               GError         **error);
+
+G_END_DECLS
diff --git a/tls/base/meson.build b/tls/base/meson.build
index 0fac433..fee0f37 100644
--- a/tls/base/meson.build
+++ b/tls/base/meson.build
@@ -2,6 +2,7 @@ tlsbase_sources = files(
   'gtlsconnection-base.c',
   'gtlsinputstream.c',
   'gtlsoutputstream.c',
+  'gtlsthread-base.c'
 )
 
 tlsbase = static_library('tlsbase',
diff --git a/tls/gnutls/gtlsconnection-gnutls.c b/tls/gnutls/gtlsconnection-gnutls.c
index 4e883a7..4a5b2c4 100644
--- a/tls/gnutls/gtlsconnection-gnutls.c
+++ b/tls/gnutls/gtlsconnection-gnutls.c
@@ -4,6 +4,7 @@
  *
  * Copyright 2009 Red Hat, Inc
  * Copyright 2015, 2016 Collabora, Ltd.
+ * Copyright 2019 Igalia S.L.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]