[libsoup/carlosgc/server-http2: 2/13] server: split SoupSocket into SoupListener and SoupServerConnection
- From: Carlos Garcia Campos <carlosgc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libsoup/carlosgc/server-http2: 2/13] server: split SoupSocket into SoupListener and SoupServerConnection
- Date: Mon, 1 Aug 2022 10:08:23 +0000 (UTC)
commit aca35a4abe878f60ce387f1489b686c03f099310
Author: Carlos Garcia Campos <cgarcia igalia com>
Date: Fri May 6 09:23:43 2022 +0200
server: split SoupSocket into SoupListener and SoupServerConnection
libsoup/meson.build | 3 +-
libsoup/server/soup-listener.c | 378 ++++++++++++
libsoup/server/soup-listener.h | 26 +
libsoup/server/soup-server-connection.c | 656 ++++++++++++++++++++
libsoup/server/soup-server-connection.h | 42 ++
libsoup/server/soup-server-io.c | 21 +-
libsoup/server/soup-server-message-private.h | 6 +-
libsoup/server/soup-server-message.c | 61 +-
libsoup/server/soup-server.c | 206 +++----
libsoup/server/soup-socket.c | 865 ---------------------------
libsoup/server/soup-socket.h | 36 --
tests/connection-test.c | 43 +-
tests/meson.build | 1 -
tests/socket-test.c | 274 ---------
14 files changed, 1274 insertions(+), 1344 deletions(-)
---
diff --git a/libsoup/meson.build b/libsoup/meson.build
index 332aceef..ed811397 100644
--- a/libsoup/meson.build
+++ b/libsoup/meson.build
@@ -45,12 +45,13 @@ soup_sources = [
'server/soup-auth-domain.c',
'server/soup-auth-domain-basic.c',
'server/soup-auth-domain-digest.c',
+ 'server/soup-listener.c',
'server/soup-message-body.c',
'server/soup-path-map.c',
'server/soup-server.c',
+ 'server/soup-server-connection.c',
'server/soup-server-io.c',
'server/soup-server-message.c',
- 'server/soup-socket.c',
'websocket/soup-websocket.c',
'websocket/soup-websocket-connection.c',
diff --git a/libsoup/server/soup-listener.c b/libsoup/server/soup-listener.c
new file mode 100644
index 00000000..841887ce
--- /dev/null
+++ b/libsoup/server/soup-listener.c
@@ -0,0 +1,378 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/*
+ * soup-listener.c: Socket listening networking code.
+ *
+ * Copyright (C) 2022 Igalia S.L.
+ * Copyright (C) 2000-2003, Ximian, Inc.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#include <glib/gi18n-lib.h>
+#include <gio/gnetworking.h>
+
+#include "soup-listener.h"
+#include "soup.h"
+#include "soup-io-stream.h"
+#include "soup-server-connection.h"
+
+enum {
+ NEW_CONNECTION,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+enum {
+ PROP_0,
+
+ PROP_SOCKET,
+ PROP_TLS_CERTIFICATE,
+ PROP_TLS_DATABASE,
+ PROP_TLS_AUTH_MODE,
+
+ LAST_PROPERTY
+};
+
+static GParamSpec *properties[LAST_PROPERTY] = { NULL, };
+
+struct _SoupListener {
+ GObject parent_instance;
+};
+
+typedef struct {
+ GSocket *socket;
+ GIOStream *conn;
+ GIOStream *iostream;
+ GInetSocketAddress *local_addr;
+
+ GTlsCertificate *tls_certificate;
+ GTlsDatabase *tls_database;
+ GTlsAuthenticationMode tls_auth_mode;
+
+ GSource *source;
+} SoupListenerPrivate;
+
+G_DEFINE_FINAL_TYPE_WITH_PRIVATE (SoupListener, soup_listener, G_TYPE_OBJECT)
+
+static void
+soup_listener_init (SoupListener *listener)
+{
+}
+
+static gboolean
+listen_watch (GObject *pollable,
+ SoupListener *listener)
+{
+ SoupListenerPrivate *priv = soup_listener_get_instance_private (listener);
+ GSocket *socket;
+ SoupServerConnection *conn;
+
+ socket = g_socket_accept (priv->socket, NULL, NULL);
+ if (!socket)
+ return G_SOURCE_REMOVE;
+
+ conn = soup_server_connection_new (socket, priv->tls_certificate, priv->tls_database,
priv->tls_auth_mode);
+ g_signal_emit (listener, signals[NEW_CONNECTION], 0, conn);
+ g_object_unref (conn);
+
+ return G_SOURCE_CONTINUE;
+}
+
+static void
+soup_listener_constructed (GObject *object)
+{
+ SoupListener *listener = SOUP_LISTENER (object);
+ SoupListenerPrivate *priv = soup_listener_get_instance_private (listener);
+
+ g_socket_set_option (priv->socket, IPPROTO_TCP, TCP_NODELAY, TRUE, NULL);
+
+ priv->conn = (GIOStream *)g_socket_connection_factory_create_connection (priv->socket);
+ priv->iostream = soup_io_stream_new (priv->conn, FALSE);
+ priv->source = g_pollable_input_stream_create_source (G_POLLABLE_INPUT_STREAM
(g_io_stream_get_input_stream (priv->iostream)), NULL);
+ g_source_set_callback (priv->source, (GSourceFunc)listen_watch, listener, NULL);
+ g_source_attach (priv->source, g_main_context_get_thread_default ());
+
+ G_OBJECT_CLASS (soup_listener_parent_class)->constructed (object);
+}
+
+static void
+soup_listener_finalize (GObject *object)
+{
+ SoupListener *listener = SOUP_LISTENER (object);
+ SoupListenerPrivate *priv = soup_listener_get_instance_private (listener);
+
+ if (priv->conn) {
+ g_io_stream_close (priv->conn, NULL, NULL);
+ g_clear_object (&priv->conn);
+ }
+
+ g_clear_object (&priv->socket);
+ g_clear_object (&priv->iostream);
+
+ g_clear_object (&priv->tls_certificate);
+ g_clear_object (&priv->tls_database);
+
+ if (priv->source) {
+ g_source_destroy (priv->source);
+ g_source_unref (priv->source);
+ }
+
+ G_OBJECT_CLASS (soup_listener_parent_class)->finalize (object);
+}
+
+static void
+soup_listener_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ SoupListener *listener = SOUP_LISTENER (object);
+ SoupListenerPrivate *priv = soup_listener_get_instance_private (listener);
+
+ switch (prop_id) {
+ case PROP_SOCKET:
+ priv->socket = g_value_dup_object (value);
+ break;
+ case PROP_TLS_CERTIFICATE:
+ priv->tls_certificate = g_value_dup_object (value);
+ break;
+ case PROP_TLS_DATABASE:
+ priv->tls_database = g_value_dup_object (value);
+ break;
+ case PROP_TLS_AUTH_MODE:
+ priv->tls_auth_mode = g_value_get_enum (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+soup_listener_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ SoupListener *listener = SOUP_LISTENER (object);
+ SoupListenerPrivate *priv = soup_listener_get_instance_private (listener);
+
+ switch (prop_id) {
+ case PROP_SOCKET:
+ g_value_set_object (value, priv->socket);
+ break;
+ case PROP_TLS_CERTIFICATE:
+ g_value_set_object (value, priv->tls_certificate);
+ break;
+ case PROP_TLS_DATABASE:
+ g_value_set_object (value, priv->tls_database);
+ break;
+ case PROP_TLS_AUTH_MODE:
+ g_value_set_enum (value, priv->tls_auth_mode);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+soup_listener_class_init (SoupListenerClass *listener_class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (listener_class);
+
+ object_class->constructed = soup_listener_constructed;
+ object_class->finalize = soup_listener_finalize;
+ object_class->set_property = soup_listener_set_property;
+ object_class->get_property = soup_listener_get_property;
+
+ /**
+ * SoupListener::new-connection:
+ * @listener: the listener
+ * @conn: the new connection
+ *
+ * Emitted when a listening socket receives a new connection.
+ *
+ * You must ref the @new if you want to keep it; otherwise it
+ * will be destroyed after the signal is emitted.
+ **/
+ signals[NEW_CONNECTION] =
+ g_signal_new ("new-connection",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST,
+ 0,
+ NULL, NULL,
+ NULL,
+ G_TYPE_NONE, 1,
+ SOUP_TYPE_SERVER_CONNECTION);
+
+ /* properties */
+ properties[PROP_SOCKET] =
+ g_param_spec_object ("socket",
+ "Socket",
+ "The underlying GSocket",
+ G_TYPE_SOCKET,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_TLS_CERTIFICATE] =
+ g_param_spec_object ("tls-certificate",
+ "TLS Certificate",
+ "The server TLS certificate",
+ G_TYPE_TLS_CERTIFICATE,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_TLS_DATABASE] =
+ g_param_spec_object ("tls-database",
+ "TLS Database",
+ "The server TLS database",
+ G_TYPE_TLS_DATABASE,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_TLS_AUTH_MODE] =
+ g_param_spec_enum ("tls-auth-mode",
+ "TLS Authentication Mode",
+ "The server TLS authentication mode",
+ G_TYPE_TLS_AUTHENTICATION_MODE,
+ G_TLS_AUTHENTICATION_NONE,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties (object_class, LAST_PROPERTY, properties);
+}
+
+SoupListener *
+soup_listener_new (GSocket *socket,
+ GError **error)
+{
+ int listening;
+
+ g_return_val_if_fail (G_IS_SOCKET (socket), NULL);
+ g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+ if (!g_socket_get_option (socket, SOL_SOCKET, SO_ACCEPTCONN, &listening, error)) {
+ g_prefix_error (error, _("Could not import existing socket: "));
+ return NULL;
+ }
+
+ if (!listening && !g_socket_is_connected (socket)) {
+ g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ _("Can’t import unconnected socket"));
+ return NULL;
+ }
+
+ return g_object_new (SOUP_TYPE_LISTENER, "socket", socket, NULL);
+}
+
+SoupListener *
+soup_listener_new_for_address (GSocketAddress *address,
+ GError **error)
+{
+ GSocket *socket;
+ GSocketFamily family;
+ SoupListener *listener;
+
+ g_return_val_if_fail (G_IS_SOCKET_ADDRESS (address), NULL);
+ g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+ family = g_socket_address_get_family (address);
+ socket = g_socket_new (family, G_SOCKET_TYPE_STREAM, G_SOCKET_PROTOCOL_DEFAULT, error);
+ if (!socket)
+ return NULL;
+
+ if (family == G_SOCKET_FAMILY_IPV6) {
+ GError *option_error = NULL;
+
+ g_socket_set_option (socket, IPPROTO_IPV6, IPV6_V6ONLY, TRUE, &option_error);
+ if (option_error) {
+ g_warning ("Failed to set IPv6 only on socket: %s", option_error->message);
+ g_error_free (option_error);
+ }
+ }
+
+ if (!g_socket_bind (socket, address, TRUE, error)) {
+ g_object_unref (socket);
+
+ return NULL;
+ }
+
+ if (!g_socket_listen (socket, error)) {
+ g_object_unref (socket);
+
+ return NULL;
+ }
+
+ listener = g_object_new (SOUP_TYPE_LISTENER, "socket", socket, NULL);
+ g_object_unref (socket);
+
+ return listener;
+}
+
+GSocket *
+soup_listener_get_socket (SoupListener *listener)
+{
+ SoupListenerPrivate *priv;
+
+ g_return_val_if_fail (SOUP_IS_LISTENER (listener), NULL);
+
+ priv = soup_listener_get_instance_private (listener);
+
+ return priv->socket;
+}
+
+void
+soup_listener_disconnect (SoupListener *listener)
+{
+ SoupListenerPrivate *priv;
+
+ g_return_if_fail (SOUP_IS_LISTENER (listener));
+
+ priv = soup_listener_get_instance_private (listener);
+ g_clear_object (&priv->socket);
+ if (priv->conn) {
+ g_io_stream_close (priv->conn, NULL, NULL);
+ g_clear_object (&priv->conn);
+ }
+}
+
+gboolean
+soup_listener_is_ssl (SoupListener *listener)
+{
+ SoupListenerPrivate *priv;
+
+ g_return_val_if_fail (SOUP_IS_LISTENER (listener), FALSE);
+
+ priv = soup_listener_get_instance_private (listener);
+
+ return priv->tls_certificate != NULL;
+}
+
+GInetSocketAddress *
+soup_listener_get_address (SoupListener *listener)
+{
+ SoupListenerPrivate *priv;
+
+ g_return_val_if_fail (SOUP_IS_LISTENER (listener), NULL);
+
+ priv = soup_listener_get_instance_private (listener);
+
+ if (!priv->local_addr) {
+ GError *error = NULL;
+
+ priv->local_addr = G_INET_SOCKET_ADDRESS (g_socket_get_local_address (priv->socket, &error));
+ if (priv->local_addr == NULL) {
+ g_warning ("%s: %s", G_STRLOC, error->message);
+ g_error_free (error);
+ return NULL;
+ }
+ }
+
+ return priv->local_addr;
+}
diff --git a/libsoup/server/soup-listener.h b/libsoup/server/soup-listener.h
new file mode 100644
index 00000000..cf2d73ac
--- /dev/null
+++ b/libsoup/server/soup-listener.h
@@ -0,0 +1,26 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2022 Igalia S.L.
+ * Copyright (C) 2000-2003, Ximian, Inc.
+ */
+
+#pragma once
+
+#include "soup-types.h"
+
+G_BEGIN_DECLS
+
+#define SOUP_TYPE_LISTENER (soup_listener_get_type ())
+G_DECLARE_FINAL_TYPE (SoupListener, soup_listener, SOUP, LISTENER, GObject)
+
+SoupListener *soup_listener_new (GSocket *socket,
+ GError **error);
+SoupListener *soup_listener_new_for_address (GSocketAddress *address,
+ GError **error);
+
+void soup_listener_disconnect (SoupListener *listener);
+gboolean soup_listener_is_ssl (SoupListener *listener);
+GSocket *soup_listener_get_socket (SoupListener *listener);
+GInetSocketAddress *soup_listener_get_address (SoupListener *listener);
+
+G_END_DECLS
diff --git a/libsoup/server/soup-server-connection.c b/libsoup/server/soup-server-connection.c
new file mode 100644
index 00000000..8dbaad96
--- /dev/null
+++ b/libsoup/server/soup-server-connection.c
@@ -0,0 +1,656 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/*
+ * soup-server-connection.c: Connection networking code.
+ *
+ * Copyright (C) 2022 Igalia S.L.
+ * Copyright (C) 2000-2003, Ximian, Inc.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#include <glib/gi18n-lib.h>
+#include <gio/gnetworking.h>
+
+#include "soup-server-connection.h"
+#include "soup.h"
+#include "soup-io-stream.h"
+
+enum {
+ DISCONNECTED,
+ ACCEPT_CERTIFICATE,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+enum {
+ PROP_0,
+
+ PROP_SOCKET,
+ PROP_CONNECTION,
+ PROP_LOCAL_ADDRESS,
+ PROP_REMOTE_ADDRESS,
+ PROP_TLS_CERTIFICATE,
+ PROP_TLS_DATABASE,
+ PROP_TLS_AUTH_MODE,
+ PROP_TLS_PEER_CERTIFICATE,
+ PROP_TLS_PEER_CERTIFICATE_ERRORS,
+
+ LAST_PROPERTY
+};
+
+static GParamSpec *properties[LAST_PROPERTY] = { NULL, };
+
+struct _SoupServerConnection {
+ GObject parent_instance;
+};
+
+typedef struct {
+ GSocket *socket;
+ GIOStream *conn;
+ GIOStream *iostream;
+
+ GSocketAddress *local_addr;
+ GSocketAddress *remote_addr;
+
+ GTlsCertificate *tls_certificate;
+ GTlsDatabase *tls_database;
+ GTlsAuthenticationMode tls_auth_mode;
+} SoupServerConnectionPrivate;
+
+G_DEFINE_FINAL_TYPE_WITH_PRIVATE (SoupServerConnection, soup_server_connection, G_TYPE_OBJECT)
+
+static void
+soup_server_connection_init (SoupServerConnection *conn)
+{
+}
+
+static void
+disconnect_internal (SoupServerConnection *conn)
+{
+ SoupServerConnectionPrivate *priv = soup_server_connection_get_instance_private (conn);
+
+ g_clear_object (&priv->socket);
+
+ g_io_stream_close (priv->conn, NULL, NULL);
+ g_signal_handlers_disconnect_by_data (priv->conn, conn);
+ g_clear_object (&priv->conn);
+}
+
+static void
+soup_server_connection_finalize (GObject *object)
+{
+ SoupServerConnection *conn = SOUP_SERVER_CONNECTION (object);
+ SoupServerConnectionPrivate *priv = soup_server_connection_get_instance_private (conn);
+
+ if (priv->conn)
+ disconnect_internal (conn);
+
+ g_clear_object (&priv->iostream);
+
+ g_clear_object (&priv->local_addr);
+ g_clear_object (&priv->remote_addr);
+
+ g_clear_object (&priv->tls_certificate);
+ g_clear_object (&priv->tls_database);
+
+ G_OBJECT_CLASS (soup_server_connection_parent_class)->finalize (object);
+}
+
+static void
+soup_server_connection_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ SoupServerConnection *conn = SOUP_SERVER_CONNECTION (object);
+ SoupServerConnectionPrivate *priv = soup_server_connection_get_instance_private (conn);
+
+ switch (prop_id) {
+ case PROP_SOCKET:
+ priv->socket = g_value_dup_object (value);
+ break;
+ case PROP_CONNECTION:
+ priv->conn = g_value_dup_object (value);
+ if (priv->conn)
+ priv->iostream = soup_io_stream_new (priv->conn, FALSE);
+ break;
+ case PROP_LOCAL_ADDRESS:
+ priv->local_addr = g_value_dup_object (value);
+ break;
+ case PROP_REMOTE_ADDRESS:
+ priv->remote_addr = g_value_dup_object (value);
+ break;
+ case PROP_TLS_CERTIFICATE:
+ priv->tls_certificate = g_value_dup_object (value);
+ break;
+ case PROP_TLS_DATABASE:
+ priv->tls_database = g_value_dup_object (value);
+ break;
+ case PROP_TLS_AUTH_MODE:
+ priv->tls_auth_mode = g_value_get_enum (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+soup_server_connection_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ SoupServerConnection *conn = SOUP_SERVER_CONNECTION (object);
+ SoupServerConnectionPrivate *priv = soup_server_connection_get_instance_private (conn);
+
+ switch (prop_id) {
+ case PROP_SOCKET:
+ g_value_set_object (value, priv->socket);
+ break;
+ case PROP_CONNECTION:
+ g_value_set_object (value, priv->conn);
+ break;
+ case PROP_LOCAL_ADDRESS:
+ g_value_set_object (value, soup_server_connection_get_local_address (conn));
+ break;
+ case PROP_REMOTE_ADDRESS:
+ g_value_set_object (value, soup_server_connection_get_remote_address (conn));
+ break;
+ case PROP_TLS_CERTIFICATE:
+ g_value_set_object (value, priv->tls_certificate);
+ break;
+ case PROP_TLS_DATABASE:
+ g_value_set_object (value, priv->tls_database);
+ break;
+ case PROP_TLS_AUTH_MODE:
+ g_value_set_enum (value, priv->tls_auth_mode);
+ break;
+ case PROP_TLS_PEER_CERTIFICATE:
+ g_value_set_object (value, soup_server_connection_get_tls_peer_certificate (conn));
+ break;
+ case PROP_TLS_PEER_CERTIFICATE_ERRORS:
+ g_value_set_flags (value, soup_server_connection_get_tls_peer_certificate_errors (conn));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+soup_server_connection_class_init (SoupServerConnectionClass *conn_class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (conn_class);
+
+ object_class->finalize = soup_server_connection_finalize;
+ object_class->set_property = soup_server_connection_set_property;
+ object_class->get_property = soup_server_connection_get_property;
+
+ /**
+ * SoupServerConnection::disconnected:
+ * @conn: the connection
+ *
+ * Emitted when the connection is disconnected, for whatever reason.
+ **/
+ signals[DISCONNECTED] =
+ g_signal_new ("disconnected",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ NULL, NULL,
+ NULL,
+ G_TYPE_NONE, 0);
+
+ signals[ACCEPT_CERTIFICATE] =
+ g_signal_new ("accept-certificate",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ g_signal_accumulator_true_handled, NULL,
+ NULL,
+ G_TYPE_BOOLEAN, 2,
+ G_TYPE_TLS_CERTIFICATE,
+ G_TYPE_TLS_CERTIFICATE_FLAGS);
+
+ /* properties */
+ properties[PROP_SOCKET] =
+ g_param_spec_object ("socket",
+ "Socket",
+ "The connection underlying GSocket",
+ G_TYPE_SOCKET,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS);
+ properties[PROP_CONNECTION] =
+ g_param_spec_object ("connection",
+ "GIOStream",
+ "The socket's underlying GIOStream",
+ G_TYPE_IO_STREAM,
+ G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_LOCAL_ADDRESS] =
+ g_param_spec_object ("local-address",
+ "Local address",
+ "Address of local end of socket",
+ G_TYPE_SOCKET_ADDRESS,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_REMOTE_ADDRESS] =
+ g_param_spec_object ("remote-address",
+ "Remote address",
+ "Address of remote end of socket",
+ G_TYPE_SOCKET_ADDRESS,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_TLS_CERTIFICATE] =
+ g_param_spec_object ("tls-certificate",
+ "TLS Certificate",
+ "The server TLS certificate",
+ G_TYPE_TLS_CERTIFICATE,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_TLS_DATABASE] =
+ g_param_spec_object ("tls-database",
+ "TLS Database",
+ "The server TLS database",
+ G_TYPE_TLS_DATABASE,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_TLS_AUTH_MODE] =
+ g_param_spec_enum ("tls-auth-mode",
+ "TLS Authentication Mode",
+ "The server TLS authentication mode",
+ G_TYPE_TLS_AUTHENTICATION_MODE,
+ G_TLS_AUTHENTICATION_NONE,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_TLS_PEER_CERTIFICATE] =
+ g_param_spec_object ("tls-peer-certificate",
+ "TLS Peer Certificate",
+ "The TLS peer certificate associated with the message",
+ G_TYPE_TLS_CERTIFICATE,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS);
+
+ properties[PROP_TLS_PEER_CERTIFICATE_ERRORS] =
+ g_param_spec_flags ("tls-peer-certificate-errors",
+ "TLS Peer Certificate Errors",
+ "The verification errors on the message's TLS peer certificate",
+ G_TYPE_TLS_CERTIFICATE_FLAGS, 0,
+ G_PARAM_READABLE |
+ G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties (object_class, LAST_PROPERTY, properties);
+}
+
+SoupServerConnection *
+soup_server_connection_new (GSocket *socket,
+ GTlsCertificate *tls_certificate,
+ GTlsDatabase *tls_database,
+ GTlsAuthenticationMode tls_auth_mode)
+{
+ g_return_val_if_fail (G_IS_SOCKET (socket), NULL);
+ g_return_val_if_fail (!tls_certificate || G_IS_TLS_CERTIFICATE (tls_certificate), NULL);
+ g_return_val_if_fail (!tls_database || G_IS_TLS_DATABASE (tls_database), NULL);
+
+ return g_object_new (SOUP_TYPE_SERVER_CONNECTION,
+ "socket", socket,
+ "tls-certificate", tls_certificate,
+ "tls-database", tls_database,
+ "tls-auth-mode", tls_auth_mode,
+ NULL);
+}
+
+SoupServerConnection *
+soup_server_connection_new_for_connection (GIOStream *connection,
+ GSocketAddress *local_addr,
+ GSocketAddress *remote_addr)
+{
+ g_return_val_if_fail (G_IS_IO_STREAM (connection), NULL);
+ g_return_val_if_fail (G_IS_SOCKET_ADDRESS (local_addr), NULL);
+ g_return_val_if_fail (G_IS_SOCKET_ADDRESS (remote_addr), NULL);
+
+ return g_object_new (SOUP_TYPE_SERVER_CONNECTION,
+ "connection", connection,
+ "local-address", local_addr,
+ "remote-address", remote_addr,
+ NULL);
+}
+
+static gboolean
+tls_connection_accept_certificate (SoupServerConnection *conn,
+ GTlsCertificate *tls_certificate,
+ GTlsCertificateFlags tls_errors)
+{
+ gboolean accept = FALSE;
+
+ g_signal_emit (conn, signals[ACCEPT_CERTIFICATE], 0,
+ tls_certificate, tls_errors, &accept);
+ return accept;
+}
+
+static void
+tls_connection_peer_certificate_changed (SoupServerConnection *conn)
+{
+ g_object_notify_by_pspec (G_OBJECT (conn), properties[PROP_TLS_CERTIFICATE]);
+}
+
+static void
+tls_connection_handshake_ready_cb (GTlsConnection *conn,
+ GAsyncResult *result,
+ GTask *task)
+{
+ GError *error = NULL;
+
+ if (g_tls_connection_handshake_finish (conn, result, &error))
+ g_task_return_boolean (task, TRUE);
+ else
+ g_task_return_error (task, error);
+ g_object_unref (task);
+}
+
+void
+soup_server_connection_setup_async (SoupServerConnection *conn,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GTask *task;
+ SoupServerConnectionPrivate *priv;
+ GIOStream *connection;
+
+ g_return_if_fail (SOUP_IS_SERVER_CONNECTION (conn));
+ g_return_if_fail (!cancellable || G_IS_CANCELLABLE (cancellable));
+
+ priv = soup_server_connection_get_instance_private (conn);
+
+ task = g_task_new (conn, cancellable, callback, user_data);
+ if (priv->conn || !priv->socket) {
+ g_task_return_boolean (task, TRUE);
+ g_object_unref (task);
+
+ return;
+ }
+
+ connection = (GIOStream *)g_socket_connection_factory_create_connection (priv->socket);
+ g_socket_set_option (priv->socket, IPPROTO_TCP, TCP_NODELAY, TRUE, NULL);
+
+ if (priv->tls_certificate) {
+ GPtrArray *advertised_protocols;
+ GError *error = NULL;
+
+ advertised_protocols = g_ptr_array_sized_new (3);
+ g_ptr_array_add (advertised_protocols, "http/1.1");
+ g_ptr_array_add (advertised_protocols, "http/1.0");
+ g_ptr_array_add (advertised_protocols, NULL);
+
+ priv->conn = g_initable_new (g_tls_backend_get_server_connection_type
(g_tls_backend_get_default ()),
+ cancellable, &error,
+ "base-io-stream", connection,
+ "certificate", priv->tls_certificate,
+ "database", priv->tls_database,
+ "authentication-mode", priv->tls_auth_mode,
+ "require-close-notify", FALSE,
+ "advertised-protocols", advertised_protocols->pdata,
+ NULL);
+ g_ptr_array_unref (advertised_protocols);
+ g_object_unref (connection);
+ if (!priv->conn) {
+ g_task_return_error (task, error);
+ g_object_unref (task);
+
+ return;
+ }
+
+ priv->iostream = soup_io_stream_new (priv->conn, FALSE);
+
+ g_signal_connect_object (priv->conn, "accept-certificate",
+ G_CALLBACK (tls_connection_accept_certificate),
+ conn, G_CONNECT_SWAPPED);
+ g_signal_connect_object (priv->conn, "notify::peer-certificate",
+ G_CALLBACK (tls_connection_peer_certificate_changed),
+ conn, G_CONNECT_SWAPPED);
+
+ g_tls_connection_handshake_async (G_TLS_CONNECTION (priv->conn),
+ G_PRIORITY_DEFAULT, NULL,
+ (GAsyncReadyCallback)tls_connection_handshake_ready_cb,
+ task);
+ return;
+ }
+
+ priv->conn = connection;
+ priv->iostream = soup_io_stream_new (priv->conn, FALSE);
+
+ g_task_return_boolean (task, TRUE);
+ g_object_unref (task);
+}
+
+gboolean
+soup_server_connection_setup_finish (SoupServerConnection *conn,
+ GAsyncResult *result,
+ GError **error)
+{
+ return g_task_propagate_boolean (G_TASK (result), error);
+}
+
+GSocket *
+soup_server_connection_get_socket (SoupServerConnection *conn)
+{
+ SoupServerConnectionPrivate *priv;
+
+ g_return_val_if_fail (SOUP_IS_SERVER_CONNECTION (conn), NULL);
+
+ priv = soup_server_connection_get_instance_private (conn);
+
+ return priv->socket;
+}
+
+GSocket *
+soup_server_connection_steal_socket (SoupServerConnection *conn)
+{
+ SoupServerConnectionPrivate *priv;
+ GSocket *socket;
+
+ g_return_val_if_fail (SOUP_IS_SERVER_CONNECTION (conn), NULL);
+
+ priv = soup_server_connection_get_instance_private (conn);
+
+ socket = g_steal_pointer (&priv->socket);
+ g_clear_object (&priv->conn);
+ g_clear_object (&priv->iostream);
+
+ return socket;
+}
+
+GIOStream *
+soup_server_connection_get_iostream (SoupServerConnection *conn)
+{
+ SoupServerConnectionPrivate *priv;
+
+ g_return_val_if_fail (SOUP_IS_SERVER_CONNECTION (conn), NULL);
+
+ priv = soup_server_connection_get_instance_private (conn);
+
+ return priv->iostream;
+}
+
+/**
+ * soup_server_connection_is_ssl:
+ * @conn: a #SoupServerConnection
+ *
+ * Tests if @sock is doing (or has attempted to do) SSL.
+ *
+ * Returns: %TRUE if @conn has SSL credentials set
+ **/
+gboolean
+soup_server_connection_is_ssl (SoupServerConnection *conn)
+{
+ SoupServerConnectionPrivate *priv;
+
+ g_return_val_if_fail (SOUP_IS_SERVER_CONNECTION (conn), FALSE);
+
+ priv = soup_server_connection_get_instance_private (conn);
+
+ return G_IS_TLS_CONNECTION (priv->conn) || priv->tls_certificate;
+}
+
+/**
+ * soup_server_connection_disconnect:
+ * @sock: a #SoupServerConnection
+ *
+ * Disconnects @conn. Any further read or write attempts on it will fail.
+ **/
+void
+soup_server_connection_disconnect (SoupServerConnection *conn)
+{
+ SoupServerConnectionPrivate *priv;
+
+ g_return_if_fail (SOUP_IS_SERVER_CONNECTION (conn));
+
+ priv = soup_server_connection_get_instance_private (conn);
+
+ if (!priv->conn)
+ return;
+
+ disconnect_internal (conn);
+
+ /* Keep ref around signals in case the object is unreferenced
+ * in a handler
+ */
+ g_object_ref (conn);
+
+ /* FIXME: can't disconnect until all data is read */
+
+ /* Then let everyone know we're disconnected */
+ g_signal_emit (conn, signals[DISCONNECTED], 0);
+
+ g_object_unref (conn);
+}
+
+/**
+ * soup_server_connection_is_connected:
+ * @conn: a #SoupServerConnection
+ *
+ * Tests if @conn is connected to another host
+ *
+ * Returns: %TRUE or %FALSE.
+ **/
+gboolean
+soup_server_connection_is_connected (SoupServerConnection *conn)
+{
+ SoupServerConnectionPrivate *priv;
+
+ g_return_val_if_fail (SOUP_IS_SERVER_CONNECTION (conn), FALSE);
+
+ priv = soup_server_connection_get_instance_private (conn);
+
+ return priv->conn && !g_io_stream_is_closed (priv->conn);
+}
+
+/**
+ * soup_server_connection_get_local_address:
+ * @conn: a #SoupServerConnection
+ *
+ * Returns the #GInetSocketAddress corresponding to the local end of @conn.
+ *
+ * Calling this method on an unconnected socket is considered to be
+ * an error, and produces undefined results.
+ *
+ * Returns: (transfer none): the #GSocketAddress
+ **/
+GSocketAddress *
+soup_server_connection_get_local_address (SoupServerConnection *conn)
+{
+ SoupServerConnectionPrivate *priv;
+
+ g_return_val_if_fail (SOUP_IS_SERVER_CONNECTION (conn), NULL);
+
+ priv = soup_server_connection_get_instance_private (conn);
+ if (!priv->local_addr) {
+ GError *error = NULL;
+
+ priv->local_addr = g_socket_get_local_address (priv->socket, &error);
+ if (priv->local_addr == NULL) {
+ g_warning ("%s: %s", G_STRLOC, error->message);
+ g_error_free (error);
+ return NULL;
+ }
+ }
+
+ return priv->local_addr;
+}
+
+/**
+ * soup_server_connection_get_remote_address:
+ * @conn: a #SoupServerConnection
+ *
+ * Returns the #GInetSocketAddress corresponding to the remote end of @conn.
+ *
+ * Calling this method on an unconnected socket is considered to be
+ * an error, and produces undefined results.
+ *
+ * Returns: (transfer none): the #GSocketAddress
+ **/
+GSocketAddress *
+soup_server_connection_get_remote_address (SoupServerConnection *conn)
+{
+ SoupServerConnectionPrivate *priv;
+
+ g_return_val_if_fail (SOUP_IS_SERVER_CONNECTION (conn), NULL);
+
+ priv = soup_server_connection_get_instance_private (conn);
+
+ if (!priv->remote_addr) {
+ GError *error = NULL;
+
+ priv->remote_addr = g_socket_get_remote_address (priv->socket, &error);
+ if (priv->remote_addr == NULL) {
+ g_warning ("%s: %s", G_STRLOC, error->message);
+ g_error_free (error);
+ return NULL;
+ }
+ }
+
+ return priv->remote_addr;
+}
+
+GTlsCertificate *
+soup_server_connection_get_tls_peer_certificate (SoupServerConnection *conn)
+{
+ SoupServerConnectionPrivate *priv;
+
+ g_return_val_if_fail (SOUP_IS_SERVER_CONNECTION (conn), NULL);
+
+ priv = soup_server_connection_get_instance_private (conn);
+
+ if (!G_IS_TLS_CONNECTION (priv->conn))
+ return NULL;
+
+ return g_tls_connection_get_peer_certificate (G_TLS_CONNECTION (priv->conn));
+}
+
+GTlsCertificateFlags
+soup_server_connection_get_tls_peer_certificate_errors (SoupServerConnection *conn)
+{
+ SoupServerConnectionPrivate *priv;
+
+ g_return_val_if_fail (SOUP_IS_SERVER_CONNECTION (conn), 0);
+
+ priv = soup_server_connection_get_instance_private (conn);
+
+ if (!G_IS_TLS_CONNECTION (priv->conn))
+ return 0;
+
+ return g_tls_connection_get_peer_certificate_errors (G_TLS_CONNECTION (priv->conn));
+}
diff --git a/libsoup/server/soup-server-connection.h b/libsoup/server/soup-server-connection.h
new file mode 100644
index 00000000..bebd3edd
--- /dev/null
+++ b/libsoup/server/soup-server-connection.h
@@ -0,0 +1,42 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2022 Igalia S.L.
+ * Copyright (C) 2000-2003, Ximian, Inc.
+ */
+
+#pragma once
+
+#include "soup-types.h"
+#include <gio/gio.h>
+
+G_BEGIN_DECLS
+
+#define SOUP_TYPE_SERVER_CONNECTION (soup_server_connection_get_type ())
+G_DECLARE_FINAL_TYPE (SoupServerConnection, soup_server_connection, SOUP, SERVER_CONNECTION, GObject)
+
+SoupServerConnection *soup_server_connection_new (GSocket *socket,
+ GTlsCertificate
*tls_certificate,
+ GTlsDatabase
*tls_database,
+ GTlsAuthenticationMode
tls_auth_mode);
+SoupServerConnection *soup_server_connection_new_for_connection (GIOStream
*connection,
+ GSocketAddress
*local_addr,
+ GSocketAddress
*remote_addr);
+void soup_server_connection_setup_async (SoupServerConnection *conn,
+ GCancellable
*cancellable,
+ GAsyncReadyCallback
callback,
+ gpointer
user_data);
+gboolean soup_server_connection_setup_finish (SoupServerConnection *conn,
+ GAsyncResult *result,
+ GError **error);
+gboolean soup_server_connection_is_ssl (SoupServerConnection *conn);
+void soup_server_connection_disconnect (SoupServerConnection *conn);
+gboolean soup_server_connection_is_connected (SoupServerConnection *conn);
+GSocket *soup_server_connection_get_socket (SoupServerConnection *conn);
+GSocket *soup_server_connection_steal_socket (SoupServerConnection *conn);
+GIOStream *soup_server_connection_get_iostream (SoupServerConnection *conn);
+GSocketAddress *soup_server_connection_get_local_address (SoupServerConnection *conn);
+GSocketAddress *soup_server_connection_get_remote_address (SoupServerConnection *conn);
+GTlsCertificate *soup_server_connection_get_tls_peer_certificate (SoupServerConnection *conn);
+GTlsCertificateFlags soup_server_connection_get_tls_peer_certificate_errors (SoupServerConnection *conn);
+
+G_END_DECLS
diff --git a/libsoup/server/soup-server-io.c b/libsoup/server/soup-server-io.c
index d1af115b..03438da7 100644
--- a/libsoup/server/soup-server-io.c
+++ b/libsoup/server/soup-server-io.c
@@ -18,7 +18,6 @@
#include "soup-server-message-private.h"
#include "soup-message-headers-private.h"
#include "soup-misc.h"
-#include "soup-socket.h"
struct _SoupServerMessageIOData {
SoupMessageIOData base;
@@ -570,7 +569,7 @@ parse_headers (SoupServerMessage *msg,
{
char *req_method, *req_path, *url;
SoupHTTPVersion version;
- SoupSocket *sock;
+ SoupServerConnection *conn;
const char *req_host;
guint status;
GUri *uri;
@@ -606,12 +605,12 @@ parse_headers (SoupServerMessage *msg,
return SOUP_STATUS_BAD_REQUEST;
}
- sock = soup_server_message_get_soup_socket (msg);
+ conn = soup_server_message_get_connection (msg);
if (!strcmp (req_path, "*") && req_host) {
/* Eg, "OPTIONS * HTTP/1.1" */
url = g_strdup_printf ("%s://%s/",
- soup_socket_is_ssl (sock) ? "https" : "http",
+ soup_server_connection_is_ssl (conn) ? "https" : "http",
req_host);
uri = g_uri_parse (url, SOUP_HTTP_URI_FLAGS, NULL);
soup_server_message_set_options_ping (msg, TRUE);
@@ -624,21 +623,21 @@ parse_headers (SoupServerMessage *msg,
uri = g_uri_parse (req_path, SOUP_HTTP_URI_FLAGS, NULL);
} else if (req_host) {
url = g_strdup_printf ("%s://%s%s",
- soup_socket_is_ssl (sock) ? "https" : "http",
+ soup_server_connection_is_ssl (conn) ? "https" : "http",
req_host, req_path);
uri = g_uri_parse (url, SOUP_HTTP_URI_FLAGS, NULL);
g_free (url);
} else if (soup_server_message_get_http_version (msg) == SOUP_HTTP_1_0) {
/* No Host header, no AbsoluteUri */
- GInetSocketAddress *addr = soup_socket_get_local_address (sock);
+ GInetSocketAddress *addr = G_INET_SOCKET_ADDRESS (soup_server_connection_get_local_address
(conn));
GInetAddress *inet_addr = g_inet_socket_address_get_address (addr);
char *local_ip = g_inet_address_to_string (inet_addr);
int port = g_inet_socket_address_get_port (addr);
if (port == 0)
port = -1;
- uri = g_uri_build (SOUP_HTTP_URI_FLAGS,
- soup_socket_is_ssl (sock) ? "https" : "http",
+ uri = g_uri_build (SOUP_HTTP_URI_FLAGS,
+ soup_server_connection_is_ssl (conn) ? "https" : "http",
NULL, local_ip, port, req_path, NULL, NULL);
g_free (local_ip);
} else
@@ -886,14 +885,14 @@ soup_server_message_read_request (SoupServerMessage *msg,
gpointer user_data)
{
SoupServerMessageIOData *io;
- SoupSocket *sock;
+ SoupServerConnection *conn;
io = g_slice_new0 (SoupServerMessageIOData);
io->base.completion_cb = completion_cb;
io->base.completion_data = user_data;
- sock = soup_server_message_get_soup_socket (msg);
- io->iostream = g_object_ref (soup_socket_get_iostream (sock));
+ conn = soup_server_message_get_connection (msg);
+ io->iostream = g_object_ref (soup_server_connection_get_iostream (conn));
io->istream = g_io_stream_get_input_stream (io->iostream);
io->ostream = g_io_stream_get_output_stream (io->iostream);
diff --git a/libsoup/server/soup-server-message-private.h b/libsoup/server/soup-server-message-private.h
index 55ef608c..d1efd645 100644
--- a/libsoup/server/soup-server-message-private.h
+++ b/libsoup/server/soup-server-message-private.h
@@ -8,14 +8,14 @@
#include "soup-server-message.h"
#include "soup-auth-domain.h"
#include "soup-message-io-data.h"
-#include "soup-socket.h"
+#include "soup-server-connection.h"
-SoupServerMessage *soup_server_message_new (SoupSocket *sock);
+SoupServerMessage *soup_server_message_new (SoupServerConnection *conn);
void soup_server_message_set_uri (SoupServerMessage *msg,
GUri *uri);
void soup_server_message_set_method (SoupServerMessage *msg,
const char *method);
-SoupSocket *soup_server_message_get_soup_socket (SoupServerMessage *msg);
+SoupServerConnection *soup_server_message_get_connection (SoupServerMessage *msg);
void soup_server_message_set_auth (SoupServerMessage *msg,
SoupAuthDomain *domain,
char *user);
diff --git a/libsoup/server/soup-server-message.c b/libsoup/server/soup-server-message.c
index 9a3388c7..c7943b78 100644
--- a/libsoup/server/soup-server-message.c
+++ b/libsoup/server/soup-server-message.c
@@ -15,7 +15,6 @@
#include "soup-connection.h"
#include "soup-server-message-private.h"
#include "soup-message-headers-private.h"
-#include "soup-socket.h"
#include "soup-uri-utils-private.h"
/**
@@ -38,7 +37,7 @@
struct _SoupServerMessage {
GObject parent;
- SoupSocket *sock;
+ SoupServerConnection *conn;
GSocket *gsock;
SoupAuthDomain *auth_domain;
char *auth_user;
@@ -130,9 +129,9 @@ soup_server_message_finalize (GObject *object)
g_clear_object (&msg->remote_addr);
g_clear_object (&msg->local_addr);
- if (msg->sock) {
- g_signal_handlers_disconnect_by_data (msg->sock, msg);
- g_object_unref (msg->sock);
+ if (msg->conn) {
+ g_signal_handlers_disconnect_by_data (msg->conn, msg);
+ g_object_unref (msg->conn);
}
g_clear_object (&msg->gsock);
g_clear_pointer (&msg->remote_ip, g_free);
@@ -403,15 +402,15 @@ soup_server_message_class_init (SoupServerMessageClass *klass)
}
static void
-socket_disconnected (SoupServerMessage *msg)
+connection_disconnected (SoupServerMessage *msg)
{
g_signal_emit (msg, signals[DISCONNECTED], 0);
}
static gboolean
-socket_accept_certificate (SoupServerMessage *msg,
- GTlsCertificate *tls_certificate,
- GTlsCertificateFlags *tls_errors)
+connection_accept_certificate (SoupServerMessage *msg,
+ GTlsCertificate *tls_certificate,
+ GTlsCertificateFlags *tls_errors)
{
gboolean accept = FALSE;
@@ -436,33 +435,33 @@ soup_server_message_set_tls_peer_certificate (SoupServerMessage *msg,
}
static void
-re_emit_tls_certificate_changed (SoupServerMessage *msg,
- GParamSpec *pspec,
- SoupSocket *sock)
+re_emit_tls_certificate_changed (SoupServerMessage *msg,
+ GParamSpec *pspec,
+ SoupServerConnection *conn)
{
soup_server_message_set_tls_peer_certificate (msg,
- soup_socket_get_tls_certificate (sock),
- soup_socket_get_tls_certificate_errors (sock));
+ soup_server_connection_get_tls_peer_certificate (conn),
+ soup_server_connection_get_tls_peer_certificate_errors
(conn));
}
SoupServerMessage *
-soup_server_message_new (SoupSocket *sock)
+soup_server_message_new (SoupServerConnection *conn)
{
SoupServerMessage *msg;
msg = g_object_new (SOUP_TYPE_SERVER_MESSAGE, NULL);
- msg->sock = g_object_ref (sock);
- msg->gsock = soup_socket_get_gsocket (sock);
+ msg->conn = g_object_ref (conn);
+ msg->gsock = soup_server_connection_get_socket (conn);
if (msg->gsock)
g_object_ref (msg->gsock);
- g_signal_connect_object (sock, "disconnected",
- G_CALLBACK (socket_disconnected),
+ g_signal_connect_object (conn, "disconnected",
+ G_CALLBACK (connection_disconnected),
msg, G_CONNECT_SWAPPED);
- g_signal_connect_object (sock, "accept-certificate",
- G_CALLBACK (socket_accept_certificate),
+ g_signal_connect_object (conn, "accept-certificate",
+ G_CALLBACK (connection_accept_certificate),
msg, G_CONNECT_SWAPPED);
- g_signal_connect_object (sock, "notify::tls-certificate",
+ g_signal_connect_object (conn, "notify::tls-certificate",
G_CALLBACK (re_emit_tls_certificate_changed),
msg, G_CONNECT_SWAPPED);
@@ -478,10 +477,10 @@ soup_server_message_set_uri (SoupServerMessage *msg,
msg->uri = soup_uri_copy_with_normalized_flags (uri);
}
-SoupSocket *
-soup_server_message_get_soup_socket (SoupServerMessage *msg)
+SoupServerConnection *
+soup_server_message_get_connection (SoupServerMessage *msg)
{
- return msg->sock;
+ return msg->conn;
}
void
@@ -954,7 +953,7 @@ soup_server_message_get_remote_address (SoupServerMessage *msg)
msg->remote_addr = msg->gsock ?
g_socket_get_remote_address (msg->gsock, NULL) :
- G_SOCKET_ADDRESS (g_object_ref (soup_socket_get_remote_address (msg->sock)));
+ G_SOCKET_ADDRESS (g_object_ref (soup_server_connection_get_remote_address (msg->conn)));
return msg->remote_addr;
}
@@ -980,7 +979,7 @@ soup_server_message_get_local_address (SoupServerMessage *msg)
msg->local_addr = msg->gsock ?
g_socket_get_local_address (msg->gsock, NULL) :
- G_SOCKET_ADDRESS (g_object_ref (soup_socket_get_local_address (msg->sock)));
+ G_SOCKET_ADDRESS (g_object_ref (soup_server_connection_get_local_address (msg->conn)));
return msg->local_addr;
}
@@ -1013,7 +1012,7 @@ soup_server_message_get_remote_host (SoupServerMessage *msg)
iaddr = g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (addr));
msg->remote_ip = g_inet_address_to_string (iaddr);
} else {
- GInetSocketAddress *addr = G_INET_SOCKET_ADDRESS (soup_socket_get_remote_address
(msg->sock));
+ GInetSocketAddress *addr = G_INET_SOCKET_ADDRESS (soup_server_connection_get_remote_address
(msg->conn));
GInetAddress *inet_addr = g_inet_socket_address_get_address (addr);
msg->remote_ip = g_inet_address_to_string (inet_addr);
}
@@ -1050,13 +1049,13 @@ soup_server_message_steal_connection (SoupServerMessage *msg)
stream = soup_server_message_io_steal (msg);
if (stream) {
g_object_set_data_full (G_OBJECT (stream), "GSocket",
- soup_socket_steal_gsocket (msg->sock),
+ soup_server_connection_steal_socket (msg->conn),
g_object_unref);
}
- g_signal_handlers_disconnect_by_data (msg, msg->sock);
+ g_signal_handlers_disconnect_by_data (msg, msg->conn);
- socket_disconnected (msg);
+ connection_disconnected (msg);
g_object_unref (msg);
return stream;
diff --git a/libsoup/server/soup-server.c b/libsoup/server/soup-server.c
index ebb1841b..b0f948eb 100644
--- a/libsoup/server/soup-server.c
+++ b/libsoup/server/soup-server.c
@@ -19,7 +19,7 @@
#include "soup.h"
#include "soup-misc.h"
#include "soup-path-map.h"
-#include "soup-socket.h"
+#include "soup-listener.h"
#include "soup-uri-utils-private.h"
#include "websocket/soup-websocket.h"
#include "websocket/soup-websocket-connection.h"
@@ -185,8 +185,10 @@ static GParamSpec *properties[LAST_PROPERTY] = { NULL, };
G_DEFINE_TYPE_WITH_PRIVATE (SoupServer, soup_server, G_TYPE_OBJECT)
-static void start_request (SoupServer *server,
- SoupServerMessage *msg);
+static void request_finished (SoupServerMessage *msg,
+ SoupMessageIOCompletion completion,
+ SoupServer *server);
+
static void
free_handler (SoupServerHandler *handler)
{
@@ -746,7 +748,7 @@ soup_server_get_listeners (SoupServer *server)
listeners = NULL;
for (iter = priv->listeners; iter; iter = iter->next)
- listeners = g_slist_prepend (listeners, soup_socket_get_gsocket (iter->data));
+ listeners = g_slist_prepend (listeners, soup_listener_get_socket (iter->data));
/* priv->listeners has the sockets in reverse order from how
* they were added, so listeners now has them back in the
@@ -831,7 +833,7 @@ got_headers (SoupServer *server,
gboolean rejected = FALSE;
char *auth_user;
SoupMessageHeaders *headers;
- SoupSocket *sock;
+ SoupServerConnection *conn;
/* Add required response headers */
headers = soup_server_message_get_response_headers (msg);
@@ -845,10 +847,10 @@ got_headers (SoupServer *server,
if (soup_server_message_get_status (msg) != 0)
return;
- sock = soup_server_message_get_soup_socket (msg);
+ conn = soup_server_message_get_connection (msg);
uri = soup_server_message_get_uri (msg);
- if ((soup_socket_is_ssl (sock) && !soup_uri_is_https (uri)) ||
- (!soup_socket_is_ssl (sock) && !soup_uri_is_http (uri))) {
+ if ((soup_server_connection_is_ssl (conn) && !soup_uri_is_https (uri)) ||
+ (!soup_server_connection_is_ssl (conn) && !soup_uri_is_http (uri))) {
soup_server_message_set_status (msg, SOUP_STATUS_BAD_REQUEST, NULL);
return;
}
@@ -996,19 +998,74 @@ client_disconnected (SoupServer *server,
soup_server_message_io_finished (msg);
}
+typedef struct {
+ SoupServer *server;
+ SoupServerMessage *msg;
+} SetupConnectionData;
+
+static void
+connection_setup_ready (SoupServerConnection *conn,
+ GAsyncResult *result,
+ SetupConnectionData *data)
+{
+ SoupServerPrivate *priv = soup_server_get_instance_private (data->server);
+
+ if (soup_server_connection_setup_finish (conn, result, NULL)) {
+ if (g_slist_find (priv->clients, data->msg)) {
+ soup_server_message_read_request (data->msg,
+ (SoupMessageIOCompletionFn)request_finished,
+ data->server);
+ }
+ } else {
+ soup_server_connection_disconnect (conn);
+ }
+
+ g_object_unref (data->msg);
+ g_object_unref (data->server);
+ g_free (data);
+}
+
static void
-soup_server_accept_socket (SoupServer *server,
- SoupSocket *sock)
+soup_server_accept_connection (SoupServer *server,
+ SoupServerConnection *conn)
{
SoupServerPrivate *priv = soup_server_get_instance_private (server);
SoupServerMessage *msg;
+ SetupConnectionData *data;
- msg = soup_server_message_new (sock);
+ msg = soup_server_message_new (conn);
g_signal_connect_object (msg, "disconnected",
G_CALLBACK (client_disconnected),
server, G_CONNECT_SWAPPED);
+ g_signal_connect_object (msg, "got-headers",
+ G_CALLBACK (got_headers),
+ server, G_CONNECT_SWAPPED);
+ g_signal_connect_object (msg, "got-body",
+ G_CALLBACK (got_body),
+ server, G_CONNECT_SWAPPED);
+ if (priv->server_header) {
+ SoupMessageHeaders *headers;
+
+ headers = soup_server_message_get_response_headers (msg);
+ soup_message_headers_append_common (headers, SOUP_HEADER_SERVER,
+ priv->server_header);
+ }
+
priv->clients = g_slist_prepend (priv->clients, msg);
- start_request (server, msg);
+
+ g_signal_emit (server, signals[REQUEST_STARTED], 0, msg);
+
+ if (soup_server_connection_is_connected (conn)) {
+ soup_server_message_read_request (msg,
+ (SoupMessageIOCompletionFn)request_finished,
+ server);
+ return;
+ }
+
+ data = g_new (SetupConnectionData, 1);
+ data->server = g_object_ref (server);
+ data->msg = g_object_ref (msg);
+ soup_server_connection_setup_async (conn, NULL, (GAsyncReadyCallback)connection_setup_ready, data);
}
static void
@@ -1017,7 +1074,7 @@ request_finished (SoupServerMessage *msg,
SoupServer *server)
{
SoupServerPrivate *priv = soup_server_get_instance_private (server);
- SoupSocket *sock = soup_server_message_get_soup_socket (msg);
+ SoupServerConnection *conn = soup_server_message_get_connection (msg);
gboolean failed;
if (completion == SOUP_MESSAGE_IO_STOLEN) {
@@ -1037,50 +1094,22 @@ request_finished (SoupServerMessage *msg,
}
if (completion == SOUP_MESSAGE_IO_COMPLETE &&
- soup_socket_is_connected (sock) &&
+ soup_server_connection_is_connected (conn) &&
soup_server_message_is_keepalive (msg) &&
priv->listeners) {
- g_object_ref (sock);
+ g_object_ref (conn);
priv->clients = g_slist_remove (priv->clients, msg);
g_object_unref (msg);
- soup_server_accept_socket (server, sock);
- g_object_unref (sock);
+ soup_server_accept_connection (server, conn);
+ g_object_unref (conn);
return;
}
- soup_socket_disconnect (sock);
+ soup_server_connection_disconnect (conn);
g_object_unref (msg);
}
-static void
-start_request (SoupServer *server,
- SoupServerMessage *msg)
-{
- SoupServerPrivate *priv = soup_server_get_instance_private (server);
-
- if (priv->server_header) {
- SoupMessageHeaders *headers;
-
- headers = soup_server_message_get_response_headers (msg);
- soup_message_headers_append_common (headers, SOUP_HEADER_SERVER,
- priv->server_header);
- }
-
- g_signal_connect_object (msg, "got-headers",
- G_CALLBACK (got_headers),
- server, G_CONNECT_SWAPPED);
- g_signal_connect_object (msg, "got-body",
- G_CALLBACK (got_body),
- server, G_CONNECT_SWAPPED);
-
- g_signal_emit (server, signals[REQUEST_STARTED], 0, msg);
-
- soup_server_message_read_request (msg,
- (SoupMessageIOCompletionFn)request_finished,
- server);
-}
-
/**
* soup_server_accept_iostream:
* @server: a #SoupServer
@@ -1104,29 +1133,21 @@ soup_server_accept_iostream (SoupServer *server,
GSocketAddress *remote_addr,
GError **error)
{
- SoupSocket *sock;
-
- sock = g_initable_new (SOUP_TYPE_SOCKET, NULL, error,
- "iostream", stream,
- "local-address", local_addr,
- "remote-connectable", remote_addr,
- NULL);
-
- if (!sock)
- return FALSE;
+ SoupServerConnection *conn;
- soup_server_accept_socket (server, sock);
- g_object_unref (sock);
+ conn = soup_server_connection_new_for_connection (stream, local_addr, remote_addr);
+ soup_server_accept_connection (server, conn);
+ g_object_unref (conn);
return TRUE;
}
static void
-new_connection (SoupSocket *listener, SoupSocket *sock, gpointer user_data)
+new_connection (SoupListener *listener,
+ SoupServerConnection *conn,
+ SoupServer *server)
{
- SoupServer *server = user_data;
-
- soup_server_accept_socket (server, sock);
+ soup_server_accept_connection (server, conn);
}
/**
@@ -1147,7 +1168,7 @@ soup_server_disconnect (SoupServer *server)
{
SoupServerPrivate *priv;
GSList *listeners, *clients, *iter;
- SoupSocket *listener;
+ SoupListener *listener;
g_return_if_fail (SOUP_IS_SERVER (server));
priv = soup_server_get_instance_private (server);
@@ -1160,13 +1181,13 @@ soup_server_disconnect (SoupServer *server)
for (iter = clients; iter; iter = iter->next) {
SoupServerMessage *msg = iter->data;
- soup_socket_disconnect (soup_server_message_get_soup_socket (msg));
+ soup_server_connection_disconnect (soup_server_message_get_connection (msg));
}
g_slist_free (clients);
for (iter = listeners; iter; iter = iter->next) {
listener = iter->data;
- soup_socket_disconnect (listener);
+ soup_listener_disconnect (listener);
g_object_unref (listener);
}
g_slist_free (listeners);
@@ -1189,9 +1210,10 @@ soup_server_disconnect (SoupServer *server)
*/
static gboolean
-soup_server_listen_internal (SoupServer *server, SoupSocket *listener,
+soup_server_listen_internal (SoupServer *server,
+ SoupListener *listener,
SoupServerListenOptions options,
- GError **error)
+ GError **error)
{
SoupServerPrivate *priv = soup_server_get_instance_private (server);
@@ -1215,23 +1237,9 @@ soup_server_listen_internal (SoupServer *server, SoupSocket *listener,
G_BINDING_SYNC_CREATE);
}
- if (soup_socket_get_gsocket (listener) == NULL) {
- if (!soup_socket_listen (listener, error)) {
- GInetSocketAddress *addr = soup_socket_get_local_address (listener);
- GInetAddress *inet_addr = g_inet_socket_address_get_address (addr);
- char *local_ip = g_inet_address_to_string (inet_addr);
-
- g_prefix_error (error,
- _("Could not listen on address %s, port %d: "),
- local_ip,
- g_inet_socket_address_get_port (addr));
- g_free (local_ip);
- return FALSE;
- }
- }
-
- g_signal_connect (listener, "new_connection",
- G_CALLBACK (new_connection), server);
+ g_signal_connect (listener, "new-connection",
+ G_CALLBACK (new_connection),
+ server);
/* Note: soup_server_listen_ipv4_ipv6() below relies on the
* fact that this does g_slist_prepend().
@@ -1274,8 +1282,8 @@ soup_server_listen (SoupServer *server, GSocketAddress *address,
GError **error)
{
SoupServerPrivate *priv;
- SoupSocket *listener;
- gboolean success, ipv6_only;
+ SoupListener *listener;
+ gboolean success;
g_return_val_if_fail (SOUP_IS_SERVER (server), FALSE);
g_return_val_if_fail (!(options & SOUP_SERVER_LISTEN_IPV4_ONLY) &&
@@ -1284,10 +1292,9 @@ soup_server_listen (SoupServer *server, GSocketAddress *address,
priv = soup_server_get_instance_private (server);
g_return_val_if_fail (priv->disposed == FALSE, FALSE);
- ipv6_only = g_socket_address_get_family (address) == G_SOCKET_FAMILY_IPV6;
- listener = soup_socket_new ("local-address", address,
- "ipv6-only", ipv6_only,
- NULL);
+ listener = soup_listener_new_for_address (address, error);
+ if (!listener)
+ return FALSE;
success = soup_server_listen_internal (server, listener, options, error);
g_object_unref (listener);
@@ -1306,7 +1313,7 @@ soup_server_listen_ipv4_ipv6 (SoupServer *server,
SoupServerPrivate *priv = soup_server_get_instance_private (server);
GSocketAddress *addr4, *addr6;
GError *my_error = NULL;
- SoupSocket *v4sock;
+ SoupListener *v4sock;
guint v4port;
g_return_val_if_fail (iaddr4 != NULL || iaddr6 != NULL, FALSE);
@@ -1323,7 +1330,7 @@ soup_server_listen_ipv4_ipv6 (SoupServer *server,
g_object_unref (addr4);
v4sock = priv->listeners->data;
- v4port = g_inet_socket_address_get_port (soup_socket_get_local_address (v4sock));
+ v4port = g_inet_socket_address_get_port (soup_listener_get_address (v4sock));
} else {
v4sock = NULL;
v4port = port;
@@ -1355,7 +1362,7 @@ soup_server_listen_ipv4_ipv6 (SoupServer *server,
if (v4sock) {
priv->listeners = g_slist_remove (priv->listeners, v4sock);
- soup_socket_disconnect (v4sock);
+ soup_listener_disconnect (v4sock);
g_object_unref (v4sock);
}
@@ -1493,7 +1500,7 @@ soup_server_listen_socket (SoupServer *server, GSocket *socket,
GError **error)
{
SoupServerPrivate *priv;
- SoupSocket *listener;
+ SoupListener *listener;
gboolean success;
g_return_val_if_fail (SOUP_IS_SERVER (server), FALSE);
@@ -1504,10 +1511,7 @@ soup_server_listen_socket (SoupServer *server, GSocket *socket,
priv = soup_server_get_instance_private (server);
g_return_val_if_fail (priv->disposed == FALSE, FALSE);
- listener = g_initable_new (SOUP_TYPE_SOCKET, NULL, error,
- "gsocket", socket,
- "ipv6-only", TRUE,
- NULL);
+ listener = soup_listener_new (socket, error);
if (!listener)
return FALSE;
@@ -1539,7 +1543,7 @@ soup_server_get_uris (SoupServer *server)
{
SoupServerPrivate *priv;
GSList *uris, *l;
- SoupSocket *listener;
+ SoupListener *listener;
GInetSocketAddress *addr;
GInetAddress *inet_addr;
char *ip;
@@ -1551,7 +1555,7 @@ soup_server_get_uris (SoupServer *server)
for (l = priv->listeners, uris = NULL; l; l = l->next) {
listener = l->data;
- addr = soup_socket_get_local_address (listener);
+ addr = soup_listener_get_address (listener);
inet_addr = g_inet_socket_address_get_address (addr);
ip = g_inet_address_to_string (inet_addr);
port = g_inet_socket_address_get_port (addr);
@@ -1560,7 +1564,7 @@ soup_server_get_uris (SoupServer *server)
port = -1;
uri = g_uri_build (SOUP_HTTP_URI_FLAGS,
- soup_socket_is_ssl (listener) ? "https" : "http",
+ soup_listener_is_ssl (listener) ? "https" : "http",
NULL, ip, port, "/", NULL, NULL);
uris = g_slist_prepend (uris, uri);
diff --git a/tests/connection-test.c b/tests/connection-test.c
index 4f454f39..6b07d6bd 100644
--- a/tests/connection-test.c
+++ b/tests/connection-test.c
@@ -6,7 +6,7 @@
#include "test-utils.h"
#include "soup-connection.h"
-#include "soup-socket.h"
+#include "soup-server-connection.h"
#include "soup-server-message-private.h"
#include <gio/gnetworking.h>
@@ -24,17 +24,17 @@ forget_close (SoupServerMessage *msg,
}
static void
-close_socket (SoupServerMessage *msg,
- SoupSocket *sock)
+close_socket (SoupServerMessage *msg,
+ SoupServerConnection *conn)
{
- GSocket *gsocket;
+ GSocket *socket;
int sockfd;
/* Actually calling soup_socket_disconnect() here would cause
* us to leak memory, so just shutdown the socket instead.
*/
- gsocket = soup_socket_get_gsocket (sock);
- sockfd = g_socket_get_fd (gsocket);
+ socket = soup_server_connection_get_socket (conn);
+ sockfd = g_socket_get_fd (socket);
#ifdef G_OS_WIN32
shutdown (sockfd, SD_SEND);
#else
@@ -50,10 +50,10 @@ close_socket (SoupServerMessage *msg,
}
static gboolean
-timeout_socket (GObject *pollable,
- SoupSocket *sock)
+timeout_socket (GObject *pollable,
+ SoupServerConnection *conn)
{
- soup_socket_disconnect (sock);
+ soup_server_connection_disconnect (conn);
return FALSE;
}
@@ -62,7 +62,7 @@ timeout_request_started (SoupServer *server,
SoupServerMessage *msg,
gpointer user_data)
{
- SoupSocket *sock;
+ SoupServerConnection *conn;
GMainContext *context = g_main_context_get_thread_default ();
GIOStream *iostream;
GInputStream *istream;
@@ -70,21 +70,22 @@ timeout_request_started (SoupServer *server,
g_signal_handlers_disconnect_by_func (server, timeout_request_started, NULL);
- sock = soup_server_message_get_soup_socket (msg);
- iostream = soup_socket_get_iostream (sock);
+ conn = soup_server_message_get_connection (msg);
+ iostream = soup_server_connection_get_iostream (conn);
istream = g_io_stream_get_input_stream (iostream);
source = g_pollable_input_stream_create_source (G_POLLABLE_INPUT_STREAM (istream), NULL);
- g_source_set_callback (source, (GSourceFunc)timeout_socket, sock, NULL);
+ g_source_set_callback (source, (GSourceFunc)timeout_socket, conn, NULL);
g_source_attach (source, g_main_context_get_thread_default ());
g_source_unref (source);
g_mutex_unlock (&server_mutex);
- while (soup_socket_is_connected (sock))
+ while (soup_server_connection_is_connected (conn))
g_main_context_iteration (context, TRUE);
}
static void
-setup_timeout_persistent (SoupServer *server, SoupSocket *sock)
+setup_timeout_persistent (SoupServer *server,
+ SoupServerConnection *conn)
{
/* In order for the test to work correctly, we have to
* close the connection *after* the client side writes
@@ -143,16 +144,16 @@ server_callback (SoupServer *server,
"Connection", "close");
if (too_long) {
- SoupSocket *sock;
+ SoupServerConnection *conn;
/* soup-message-io will wait for us to add
* another chunk after the first, to fill out
* the declared Content-Length. Instead, we
* forcibly close the socket at that point.
*/
- sock = soup_server_message_get_soup_socket (msg);
+ conn = soup_server_message_get_connection (msg);
g_signal_connect (msg, "wrote-chunk",
- G_CALLBACK (close_socket), sock);
+ G_CALLBACK (close_socket), conn);
} else if (no_close) {
/* Remove the 'Connection: close' after writing
* the headers, so that when we check it after
@@ -166,10 +167,10 @@ server_callback (SoupServer *server,
}
if (!strcmp (path, "/timeout-persistent")) {
- SoupSocket *sock;
+ SoupServerConnection *conn;
- sock = soup_server_message_get_soup_socket (msg);
- setup_timeout_persistent (server, sock);
+ conn = soup_server_message_get_connection (msg);
+ setup_timeout_persistent (server, conn);
}
soup_server_message_set_status (msg, SOUP_STATUS_OK, NULL);
diff --git a/tests/meson.build b/tests/meson.build
index bd76bab9..9f1d7aeb 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -94,7 +94,6 @@ tests = [
{'name': 'server-auth'},
{'name': 'server'},
{'name': 'sniffing'},
- {'name': 'socket'},
{'name': 'ssl',
'dependencies': [gnutls_dep],
'depends': mock_pkcs11_module,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]