[libsoup/carlosgc/server-http2: 2/13] server: split SoupSocket into SoupListener and SoupServerConnection




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]