summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarlos Garcia Campos <cgarcia@igalia.com>2022-05-06 09:23:43 +0200
committerCarlos Garcia Campos <cgarcia@igalia.com>2022-08-12 09:22:54 +0200
commit25e96cad913cde650ca56ff76c3924fd97eb7125 (patch)
treea152bc18f58c196c79ecc8d8263b8df1f2c17cc4
parent36770e8b8265add935b8d530f3207bab12fc9188 (diff)
downloadlibsoup-25e96cad913cde650ca56ff76c3924fd97eb7125.tar.gz
server: split SoupSocket into SoupListener and SoupServerConnection
-rw-r--r--libsoup/meson.build3
-rw-r--r--libsoup/server/soup-listener.c378
-rw-r--r--libsoup/server/soup-listener.h26
-rw-r--r--libsoup/server/soup-server-connection.c656
-rw-r--r--libsoup/server/soup-server-connection.h42
-rw-r--r--libsoup/server/soup-server-io.c21
-rw-r--r--libsoup/server/soup-server-message-private.h6
-rw-r--r--libsoup/server/soup-server-message.c61
-rw-r--r--libsoup/server/soup-server.c206
-rw-r--r--libsoup/server/soup-socket.c865
-rw-r--r--libsoup/server/soup-socket.h36
-rw-r--r--tests/connection-test.c43
-rw-r--r--tests/meson.build1
-rw-r--r--tests/socket-test.c274
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/libsoup/server/soup-socket.c b/libsoup/server/soup-socket.c
deleted file mode 100644
index 74ccacac..00000000
--- a/libsoup/server/soup-socket.c
+++ /dev/null
@@ -1,865 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
-/*
- * soup-socket.c: Socket networking code.
- *
- * 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-socket.h"
-#include "soup.h"
-#include "soup-io-stream.h"
-
-/*<private>
- * SECTION:soup-socket
- * @short_description: A network socket
- *
- * #SoupSocket is libsoup's TCP socket type. While it is primarily
- * intended for internal use, #SoupSocket<!-- -->s are exposed in the
- * API in various places, and some of their methods (eg,
- * soup_socket_get_remote_address()) may be useful to applications.
- **/
-
-enum {
- DISCONNECTED,
- NEW_CONNECTION,
- ACCEPT_CERTIFICATE,
- LAST_SIGNAL
-};
-
-static guint signals[LAST_SIGNAL] = { 0 };
-
-enum {
- PROP_0,
-
- PROP_GSOCKET,
- PROP_IOSTREAM,
- PROP_LOCAL_ADDRESS,
- PROP_REMOTE_ADDRESS,
- PROP_REMOTE_CONNECTABLE,
- PROP_IPV6_ONLY,
- 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 _SoupSocket {
- GObject parent_instance;
-};
-
-typedef struct {
- GInetSocketAddress *local_addr, *remote_addr;
- GSocketConnectable *remote_connectable;
- GIOStream *conn, *iostream;
- GSocket *gsock;
- GInputStream *istream;
- GOutputStream *ostream;
-
- guint ipv6_only:1;
- guint ssl:1;
- GTlsCertificate *tls_certificate;
- GTlsDatabase *tls_database;
- GTlsAuthenticationMode tls_auth_mode;
-
- GMainContext *async_context;
- GSource *watch_src;
-} SoupSocketPrivate;
-
-static void soup_socket_initable_interface_init (GInitableIface *initable_interface);
-
-G_DEFINE_FINAL_TYPE_WITH_CODE (SoupSocket, soup_socket, G_TYPE_OBJECT,
- G_ADD_PRIVATE (SoupSocket)
- G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
- soup_socket_initable_interface_init))
-
-static void finish_socket_setup (SoupSocket *sock);
-static void finish_listener_setup (SoupSocket *sock);
-
-static void
-soup_socket_init (SoupSocket *sock)
-{
- SoupSocketPrivate *priv = soup_socket_get_instance_private (sock);
-
- priv->async_context = g_main_context_ref_thread_default ();
-}
-
-static gboolean
-soup_socket_initable_init (GInitable *initable,
- GCancellable *cancellable,
- GError **error)
-{
- SoupSocket *sock = SOUP_SOCKET (initable);
- SoupSocketPrivate *priv = soup_socket_get_instance_private (sock);
-
- if (priv->conn) {
- g_warn_if_fail (priv->gsock == NULL);
-
- finish_socket_setup (sock);
- }
-
- if (priv->gsock != NULL) {
- int listening;
-
- g_warn_if_fail (priv->local_addr == NULL);
- g_warn_if_fail (priv->remote_addr == NULL);
-
- if (!g_socket_get_option (priv->gsock,
- SOL_SOCKET, SO_ACCEPTCONN,
- &listening, error)) {
- g_prefix_error (error, _("Could not import existing socket: "));
- return FALSE;
- }
-
- finish_socket_setup (sock);
- if (listening)
- finish_listener_setup (sock);
- else if (!g_socket_is_connected (priv->gsock)) {
- g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
- _("Can’t import unconnected socket"));
- return FALSE;
- }
- }
-
- return TRUE;
-}
-
-static void
-disconnect_internal (SoupSocket *sock)
-{
- SoupSocketPrivate *priv = soup_socket_get_instance_private (sock);
-
- g_clear_object (&priv->gsock);
- if (priv->conn) {
- g_io_stream_close (priv->conn, NULL, NULL);
- g_signal_handlers_disconnect_by_data (priv->conn, sock);
- g_clear_object (&priv->conn);
- }
-}
-
-static void
-soup_socket_finalize (GObject *object)
-{
- SoupSocket *sock = SOUP_SOCKET (object);
- SoupSocketPrivate *priv = soup_socket_get_instance_private (sock);
-
- if (priv->conn)
- disconnect_internal (SOUP_SOCKET (object));
-
- g_clear_object (&priv->conn);
- g_clear_object (&priv->iostream);
- g_clear_object (&priv->istream);
- g_clear_object (&priv->ostream);
-
- g_clear_object (&priv->local_addr);
- g_clear_object (&priv->remote_addr);
- g_clear_object (&priv->remote_connectable);
-
- g_clear_object (&priv->tls_certificate);
- g_clear_object (&priv->tls_database);
-
- if (priv->watch_src) {
- g_source_destroy (priv->watch_src);
- g_source_unref (priv->watch_src);
- }
- g_clear_pointer (&priv->async_context, g_main_context_unref);
-
- G_OBJECT_CLASS (soup_socket_parent_class)->finalize (object);
-}
-
-static void
-finish_socket_setup (SoupSocket *sock)
-{
- SoupSocketPrivate *priv = soup_socket_get_instance_private (sock);
-
- if (priv->gsock) {
- if (!priv->conn)
- priv->conn = (GIOStream *)g_socket_connection_factory_create_connection (priv->gsock);
-
- g_socket_set_option (priv->gsock, IPPROTO_TCP, TCP_NODELAY, TRUE, NULL);
- }
-
- if (!priv->conn)
- return;
-
- if (!priv->iostream)
- priv->iostream = soup_io_stream_new (priv->conn, FALSE);
- if (!priv->istream)
- priv->istream = g_object_ref (g_io_stream_get_input_stream (priv->iostream));
- if (!priv->ostream)
- priv->ostream = g_object_ref (g_io_stream_get_output_stream (priv->iostream));
-}
-
-static void
-soup_socket_set_property (GObject *object, guint prop_id,
- const GValue *value, GParamSpec *pspec)
-{
- SoupSocket *sock = SOUP_SOCKET (object);
- SoupSocketPrivate *priv = soup_socket_get_instance_private (sock);
-
- switch (prop_id) {
- case PROP_GSOCKET:
- priv->gsock = g_value_dup_object (value);
- break;
- case PROP_IOSTREAM:
- priv->conn = g_value_dup_object (value);
- 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_REMOTE_CONNECTABLE:
- priv->remote_connectable = g_value_dup_object (value);
- break;
- case PROP_IPV6_ONLY:
- priv->ipv6_only = g_value_get_boolean (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_socket_get_property (GObject *object, guint prop_id,
- GValue *value, GParamSpec *pspec)
-{
- SoupSocket *sock = SOUP_SOCKET (object);
- SoupSocketPrivate *priv = soup_socket_get_instance_private (sock);
-
- switch (prop_id) {
- case PROP_LOCAL_ADDRESS:
- g_value_set_object (value, soup_socket_get_local_address (sock));
- break;
- case PROP_REMOTE_ADDRESS:
- g_value_set_object (value, soup_socket_get_remote_address (sock));
- break;
- case PROP_REMOTE_CONNECTABLE:
- g_value_set_object (value, priv->remote_connectable);
- break;
- case PROP_IPV6_ONLY:
- g_value_set_boolean (value, priv->ipv6_only);
- 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_socket_class_init (SoupSocketClass *socket_class)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (socket_class);
-
- /* virtual method override */
- object_class->finalize = soup_socket_finalize;
- object_class->set_property = soup_socket_set_property;
- object_class->get_property = soup_socket_get_property;
-
- /* signals */
-
- /**
- * SoupSocket::disconnected:
- * @sock: the socket
- *
- * Emitted when the socket 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);
-
- /**
- * SoupSocket::new-connection:
- * @sock: the socket
- * @new: the new socket
- *
- * Emitted when a listening socket receives a new connection.
- *
- * Has to be set up with [func@soup_socket_listen].
- *
- * 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_SOCKET);
-
- 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_GSOCKET] =
- g_param_spec_object ("gsocket",
- "GSocket",
- "The socket's underlying GSocket",
- G_TYPE_SOCKET,
- G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_STATIC_STRINGS);
- properties[PROP_IOSTREAM] =
- g_param_spec_object ("iostream",
- "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_INET_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_READABLE |
- G_PARAM_STATIC_STRINGS);
-
- properties[PROP_REMOTE_CONNECTABLE] =
- g_param_spec_object ("remote-connectable",
- "Remote address",
- "Address to connect to",
- G_TYPE_SOCKET_CONNECTABLE,
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_STATIC_STRINGS);
-
- properties[PROP_IPV6_ONLY] =
- g_param_spec_boolean ("ipv6-only",
- "IPv6 only",
- "IPv6 only",
- FALSE,
- G_PARAM_READWRITE |
- 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);
-
- 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);
-}
-
-static void
-soup_socket_initable_interface_init (GInitableIface *initable_interface)
-{
- initable_interface->init = soup_socket_initable_init;
-}
-
-
-/**
- * soup_socket_new:
- * @optname1: name of first property to set (or %NULL)
- * @...: value of @optname1, followed by additional property/value pairs
- *
- * Creates a new (disconnected) socket
- *
- * Returns: the new socket
- **/
-SoupSocket *
-soup_socket_new (const char *optname1, ...)
-{
- SoupSocket *sock;
- va_list ap;
-
- va_start (ap, optname1);
- sock = (SoupSocket *)g_object_new_valist (SOUP_TYPE_SOCKET,
- optname1, ap);
- va_end (ap);
-
- return sock;
-}
-
-GSocket *
-soup_socket_get_gsocket (SoupSocket *sock)
-{
- SoupSocketPrivate *priv;
-
- g_return_val_if_fail (SOUP_IS_SOCKET (sock), NULL);
-
- priv = soup_socket_get_instance_private (sock);
-
- return priv->gsock;
-}
-
-GSocket *
-soup_socket_steal_gsocket (SoupSocket *sock)
-{
- SoupSocketPrivate *priv;
- GSocket *gsock;
-
- g_return_val_if_fail (SOUP_IS_SOCKET (sock), NULL);
- priv = soup_socket_get_instance_private (sock);
-
- gsock = g_steal_pointer (&priv->gsock);
- g_clear_object (&priv->conn);
- g_clear_object (&priv->iostream);
-
- return gsock;
-}
-
-GIOStream *
-soup_socket_get_iostream (SoupSocket *sock)
-{
- SoupSocketPrivate *priv;
-
- g_return_val_if_fail (SOUP_IS_SOCKET (sock), NULL);
-
- priv = soup_socket_get_instance_private (sock);
-
- return priv->iostream;
-}
-
-static gboolean
-tls_connection_accept_certificate (SoupSocket *sock,
- GTlsCertificate *tls_certificate,
- GTlsCertificateFlags tls_errors)
-{
- gboolean accept = FALSE;
-
- g_signal_emit (sock, signals[ACCEPT_CERTIFICATE], 0,
- tls_certificate, tls_errors, &accept);
- return accept;
-}
-
-static void
-tls_connection_peer_certificate_changed (SoupSocket *sock)
-{
- g_object_notify_by_pspec (G_OBJECT (sock), properties[PROP_TLS_CERTIFICATE]);
-}
-
-static gboolean
-soup_socket_setup_ssl (SoupSocket *sock)
-{
- SoupSocketPrivate *priv = soup_socket_get_instance_private (sock);
- GTlsBackend *backend = g_tls_backend_get_default ();
- GTlsServerConnection *conn;
-
- if (G_IS_TLS_CONNECTION (priv->conn))
- return TRUE;
-
- priv->ssl = TRUE;
-
- conn = g_initable_new (g_tls_backend_get_server_connection_type (backend),
- NULL, NULL,
- "base-io-stream", priv->conn,
- "certificate", priv->tls_certificate,
- "database", priv->tls_database,
- "authentication-mode", priv->tls_auth_mode,
- "require-close-notify", FALSE,
- NULL);
- if (!conn)
- return FALSE;
-
- g_object_unref (priv->conn);
- priv->conn = G_IO_STREAM (conn);
-
- g_signal_connect_object (priv->conn, "accept-certificate",
- G_CALLBACK (tls_connection_accept_certificate),
- sock, G_CONNECT_SWAPPED);
- g_signal_connect_object (priv->conn, "notify::peer-certificate",
- G_CALLBACK (tls_connection_peer_certificate_changed),
- sock, G_CONNECT_SWAPPED);
-
- g_clear_object (&priv->istream);
- g_clear_object (&priv->ostream);
- g_clear_object (&priv->iostream);
- priv->iostream = soup_io_stream_new (priv->conn, FALSE);
- priv->istream = g_object_ref (g_io_stream_get_input_stream (priv->iostream));
- priv->ostream = g_object_ref (g_io_stream_get_output_stream (priv->iostream));
-
- return TRUE;
-}
-
-static gboolean
-listen_watch (GObject *pollable, gpointer data)
-{
- SoupSocket *sock = data, *new;
- SoupSocketPrivate *priv = soup_socket_get_instance_private (sock), *new_priv;
- GSocket *new_gsock;
-
- new_gsock = g_socket_accept (priv->gsock, NULL, NULL);
- if (!new_gsock)
- return FALSE;
-
- new = g_object_new (SOUP_TYPE_SOCKET, NULL);
- new_priv = soup_socket_get_instance_private (new);
- new_priv->gsock = new_gsock;
- new_priv->async_context = g_main_context_ref (priv->async_context);
- new_priv->ssl = priv->ssl;
- if (priv->tls_certificate)
- new_priv->tls_certificate = g_object_ref (priv->tls_certificate);
- if (priv->tls_database)
- new_priv->tls_database = g_object_ref (priv->tls_database);
- new_priv->tls_auth_mode = priv->tls_auth_mode;
- finish_socket_setup (new);
-
- if (new_priv->tls_certificate) {
- if (!soup_socket_setup_ssl (new)) {
- g_object_unref (new);
- return TRUE;
- }
- }
-
- g_signal_emit (sock, signals[NEW_CONNECTION], 0, new);
- g_object_unref (new);
-
- return TRUE;
-}
-
-static void
-finish_listener_setup (SoupSocket *sock)
-{
- SoupSocketPrivate *priv = soup_socket_get_instance_private (sock);
-
- priv->watch_src = g_pollable_input_stream_create_source (G_POLLABLE_INPUT_STREAM (priv->istream), NULL);
- g_source_set_callback (priv->watch_src, (GSourceFunc)listen_watch, sock, NULL);
- g_source_attach (priv->watch_src, priv->async_context);
-}
-
-/**
- * soup_socket_listen:
- * @sock: a server #SoupSocket (which must not already be connected or listening)
- * @error: error pointer
- *
- * Makes @sock start listening on its local address.
- *
- * When connections come in, @sock will emit #SoupSocket::new_connection.
- *
- * Returns: whether or not @sock is now listening.
- **/
-gboolean
-soup_socket_listen (SoupSocket *sock,
- GError **error)
-
-{
- SoupSocketPrivate *priv;
-
- g_return_val_if_fail (SOUP_IS_SOCKET (sock), FALSE);
- priv = soup_socket_get_instance_private (sock);
- g_return_val_if_fail (priv->gsock == NULL, FALSE);
- g_return_val_if_fail (priv->local_addr != NULL, FALSE);
-
- /* @local_addr may have its port set to 0. So we intentionally
- * don't store it in priv->local_addr, so that if the
- * caller calls soup_socket_get_local_address() later, we'll
- * have to make a new addr by calling getsockname(), which
- * will have the right port number.
- */
- g_return_val_if_fail (priv->local_addr != NULL, FALSE);
-
- priv->gsock = g_socket_new (g_socket_address_get_family (G_SOCKET_ADDRESS (priv->local_addr)),
- G_SOCKET_TYPE_STREAM,
- G_SOCKET_PROTOCOL_DEFAULT,
- error);
- if (!priv->gsock)
- goto cant_listen;
- finish_socket_setup (sock);
-
- if (priv->ipv6_only) {
- GError *error = NULL;
- g_socket_set_option (priv->gsock, IPPROTO_IPV6, IPV6_V6ONLY, TRUE, &error);
- if (error) {
- g_warning ("Failed to set IPv6 only on socket: %s", error->message);
- g_error_free (error);
- }
- }
-
- /* Bind */
- if (!g_socket_bind (priv->gsock, G_SOCKET_ADDRESS (priv->local_addr), TRUE, error))
- goto cant_listen;
- /* Force local_addr to be re-resolved now */
- g_clear_object (&priv->local_addr);
-
- /* Listen */
- if (!g_socket_listen (priv->gsock, error))
- goto cant_listen;
- finish_listener_setup (sock);
- return TRUE;
-
- cant_listen:
- if (priv->conn)
- disconnect_internal (sock);
-
- return FALSE;
-}
-
-/**
- * soup_socket_is_ssl:
- * @sock: a #SoupSocket
- *
- * Tests if @sock is doing (or has attempted to do) SSL.
- *
- * Returns: %TRUE if @sock has SSL credentials set
- **/
-gboolean
-soup_socket_is_ssl (SoupSocket *sock)
-{
- SoupSocketPrivate *priv = soup_socket_get_instance_private (sock);
-
- return priv->ssl || priv->tls_certificate;
-}
-
-/**
- * soup_socket_disconnect:
- * @sock: a #SoupSocket
- *
- * Disconnects @sock. Any further read or write attempts on it will
- * fail.
- **/
-void
-soup_socket_disconnect (SoupSocket *sock)
-{
- SoupSocketPrivate *priv;
-
- g_return_if_fail (SOUP_IS_SOCKET (sock));
- priv = soup_socket_get_instance_private (sock);
-
- if (!priv->conn)
- return;
-
- disconnect_internal (sock);
-
- /* Keep ref around signals in case the object is unreferenced
- * in a handler
- */
- g_object_ref (sock);
-
- /* FIXME: can't disconnect until all data is read */
-
- /* Then let everyone know we're disconnected */
- g_signal_emit (sock, signals[DISCONNECTED], 0);
-
- g_object_unref (sock);
-}
-
-/**
- * soup_socket_is_connected:
- * @sock: a #SoupSocket
- *
- * Tests if @sock is connected to another host
- *
- * Returns: %TRUE or %FALSE.
- **/
-gboolean
-soup_socket_is_connected (SoupSocket *sock)
-{
- SoupSocketPrivate *priv;
-
- g_return_val_if_fail (SOUP_IS_SOCKET (sock), FALSE);
- priv = soup_socket_get_instance_private (sock);
-
- return priv->conn && !g_io_stream_is_closed (priv->conn);
-}
-
-/**
- * soup_socket_get_local_address:
- * @sock: a #SoupSocket
- *
- * Returns the #GInetSocketAddress corresponding to the local end of @sock.
- *
- * Calling this method on an unconnected socket is considered to be
- * an error, and produces undefined results.
- *
- * Returns: (transfer none): the #GInetSocketAddress
- **/
-GInetSocketAddress *
-soup_socket_get_local_address (SoupSocket *sock)
-{
- SoupSocketPrivate *priv;
-
- g_return_val_if_fail (SOUP_IS_SOCKET (sock), NULL);
- priv = soup_socket_get_instance_private (sock);
-
- if (!priv->local_addr) {
- GError *error = NULL;
-
- if (priv->gsock == NULL) {
- g_warning ("%s: socket not connected", G_STRLOC);
- return NULL;
- }
-
- priv->local_addr = G_INET_SOCKET_ADDRESS (g_socket_get_local_address (priv->gsock, &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_socket_get_remote_address:
- * @sock: a #SoupSocket
- *
- * Returns the #GInetSocketAddress corresponding to the remote end of @sock.
- *
- * Calling this method on an unconnected socket is considered to be
- * an error, and produces undefined results.
- *
- * Returns: (transfer none): the #GInetSocketAddress
- **/
-GInetSocketAddress *
-soup_socket_get_remote_address (SoupSocket *sock)
-{
- SoupSocketPrivate *priv;
-
- g_return_val_if_fail (SOUP_IS_SOCKET (sock), NULL);
- priv = soup_socket_get_instance_private (sock);
-
- if (!priv->remote_addr) {
- GError *error = NULL;
-
- // We may be conencting to a socket address rather than a network address
- if (G_IS_INET_SOCKET_ADDRESS (priv->remote_connectable)) {
- priv->remote_addr = g_object_ref (G_INET_SOCKET_ADDRESS (priv->remote_connectable));
- return priv->remote_addr;
- }
-
- if (priv->gsock == NULL) {
- g_warning ("%s: socket not connected", G_STRLOC);
- return NULL;
- }
-
- priv->remote_addr = G_INET_SOCKET_ADDRESS (g_socket_get_remote_address (priv->gsock, &error));
- if (priv->remote_addr == NULL) {
- g_warning ("%s: %s", G_STRLOC, error->message);
- g_error_free (error);
- return NULL;
- }
- }
-
- return priv->remote_addr;
-}
-
-GIOStream *
-soup_socket_get_connection (SoupSocket *sock)
-{
- SoupSocketPrivate *priv = soup_socket_get_instance_private (sock);
-
- return priv->conn;
-}
-
-GTlsCertificate *
-soup_socket_get_tls_certificate (SoupSocket *sock)
-{
- SoupSocketPrivate *priv;
-
- g_return_val_if_fail (SOUP_IS_SOCKET (sock), NULL);
-
- priv = soup_socket_get_instance_private (sock);
-
- if (!G_IS_TLS_CONNECTION (priv->conn))
- return NULL;
-
- return g_tls_connection_get_peer_certificate (G_TLS_CONNECTION (priv->conn));
-}
-
-GTlsCertificateFlags
-soup_socket_get_tls_certificate_errors (SoupSocket *sock)
-{
- SoupSocketPrivate *priv;
-
- g_return_val_if_fail (SOUP_IS_SOCKET (sock), 0);
-
- priv = soup_socket_get_instance_private (sock);
-
- 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-socket.h b/libsoup/server/soup-socket.h
deleted file mode 100644
index 051b3dcb..00000000
--- a/libsoup/server/soup-socket.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
-/*
- * Copyright (C) 2000-2003, Ximian, Inc.
- */
-
-#pragma once
-
-#include "soup-types.h"
-
-G_BEGIN_DECLS
-
-#define SOUP_TYPE_SOCKET (soup_socket_get_type ())
-G_DECLARE_FINAL_TYPE (SoupSocket, soup_socket, SOUP, SOCKET, GObject)
-
-SoupSocket *soup_socket_new (const char *optname1,
- ...) G_GNUC_NULL_TERMINATED;
-
-gboolean soup_socket_listen (SoupSocket *sock,
- GError **error);
-
-gboolean soup_socket_is_ssl (SoupSocket *sock);
-
-void soup_socket_disconnect (SoupSocket *sock);
-gboolean soup_socket_is_connected (SoupSocket *sock);
-GIOStream *soup_socket_get_connection (SoupSocket *sock);
-GSocket *soup_socket_get_gsocket (SoupSocket *sock);
-GSocket *soup_socket_steal_gsocket (SoupSocket *sock);
-GIOStream *soup_socket_get_iostream (SoupSocket *sock);
-
-GInetSocketAddress *soup_socket_get_local_address (SoupSocket *sock);
-GInetSocketAddress *soup_socket_get_remote_address (SoupSocket *sock);
-
-GTlsCertificate *soup_socket_get_tls_certificate (SoupSocket *sock);
-GTlsCertificateFlags soup_socket_get_tls_certificate_errors (SoupSocket *sock);
-
-G_END_DECLS
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,
diff --git a/tests/socket-test.c b/tests/socket-test.c
deleted file mode 100644
index 059f0005..00000000
--- a/tests/socket-test.c
+++ /dev/null
@@ -1,274 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
-/*
- * Copyright 2007-2012 Red Hat, Inc.
- * Copyright 2012 Nokia Corporation
- */
-
-#include "test-utils.h"
-#include "libsoup/server/soup-socket.h"
-
-#include <fcntl.h>
-#include <gio/gnetworking.h>
-
-#ifdef G_OS_WIN32
-#include <io.h>
-#endif
-
-static void
-assert_host_equals (GInetSocketAddress *addr, const char *host)
-{
- char *addr_host = g_inet_address_to_string (g_inet_socket_address_get_address (addr));
- g_assert_cmpstr (addr_host, ==, host);
- g_free (addr_host);
-}
-
-static void
-do_unconnected_socket_test (void)
-{
- GInetSocketAddress *addr;
- GSocketAddress *localhost;
- SoupSocket *sock;
- GSocketClient *client;
- GSocketConnectable *remote_connectable;
- GSocketConnection *conn;
- GSocket *client_socket;
- guint res;
-
- g_test_bug ("673083");
-
- localhost = g_inet_socket_address_new_from_string ("127.0.0.1", 0);
-
- sock = soup_socket_new ("local-address", localhost,
- NULL);
- g_assert_true (sock != NULL);
-
- addr = soup_socket_get_local_address (sock);
- g_assert_true (addr != NULL);
- assert_host_equals (addr, "127.0.0.1");
- g_assert_cmpuint (g_inet_socket_address_get_port (addr), ==, 0);
-
- /* fails with ENOTCONN */
- g_test_expect_message ("libsoup", G_LOG_LEVEL_WARNING,
- "*socket not connected*");
- addr = soup_socket_get_remote_address (sock);
- g_test_assert_expected_messages ();
- g_assert_null (addr);
-
- res = soup_socket_listen (sock, NULL);
- g_assert_true (res);
-
- addr = soup_socket_get_local_address (sock);
- g_assert_true (addr != NULL);
- assert_host_equals (addr, "127.0.0.1");
- g_assert_cmpuint (g_inet_socket_address_get_port (addr), >, 0);
-
- client = g_socket_client_new ();
- remote_connectable = G_SOCKET_CONNECTABLE (soup_socket_get_local_address (sock));
- conn = g_socket_client_connect (client, remote_connectable, NULL, NULL);
- g_assert_true (conn != NULL);
- client_socket = g_socket_connection_get_socket (conn);
- g_assert_true (client_socket != NULL);
- addr = G_INET_SOCKET_ADDRESS (g_socket_get_local_address (client_socket, NULL));
- g_assert_true (addr != NULL);
- g_object_unref (addr);
- addr = G_INET_SOCKET_ADDRESS (g_socket_get_remote_address (client_socket, NULL));
- g_assert_true (addr != NULL);
- assert_host_equals (addr, "127.0.0.1");
- g_assert_cmpuint (g_inet_socket_address_get_port (addr), >, 0);
- g_object_unref (addr);
- g_object_unref (conn);
- g_object_unref (client);
-
- client = g_socket_client_new ();
- remote_connectable = G_SOCKET_CONNECTABLE (soup_socket_get_local_address (sock));
- /* save it for later */
-
- /* listening socket fails with ENOTCONN */
- g_test_expect_message ("libsoup", G_LOG_LEVEL_WARNING,
- /* We can't check the error message since it comes from
- * libc and is locale-dependent.
- */
- "*");
- addr = soup_socket_get_remote_address (sock);
- g_test_assert_expected_messages ();
- g_assert_null (addr);
-
- soup_socket_disconnect (sock);
-
- g_test_expect_message ("libsoup", G_LOG_LEVEL_WARNING,
- /* This error message comes from soup-socket.c though */
- "*socket not connected*");
- addr = soup_socket_get_remote_address (sock);
- g_test_assert_expected_messages ();
- g_assert_null (addr);
-
- conn = g_socket_client_connect (client, remote_connectable, NULL, NULL);
- g_assert_false (conn != NULL);
-
- g_object_unref (localhost);
- g_object_unref (client);
- g_object_unref (sock);
-}
-
-static int
-socket_get_fd (SoupSocket *socket)
-{
- return g_socket_get_fd (soup_socket_get_gsocket (socket));
-}
-
-static void
-do_socket_from_fd_server_test (void)
-{
- GSocket *gsock;
- SoupSocket *sock;
- GInetSocketAddress *local;
- GSocketAddress *gaddr;
- GError *error = NULL;
-
- gsock = g_socket_new (G_SOCKET_FAMILY_IPV4,
- G_SOCKET_TYPE_STREAM,
- G_SOCKET_PROTOCOL_DEFAULT,
- &error);
- g_assert_no_error (error);
-
- gaddr = g_inet_socket_address_new_from_string ("127.0.0.1", 0);
- g_socket_bind (gsock, gaddr, TRUE, &error);
- g_object_unref (gaddr);
- g_assert_no_error (error);
- g_socket_listen (gsock, &error);
- g_assert_no_error (error);
- g_assert_false (g_socket_is_connected (gsock));
-
- gaddr = g_socket_get_local_address (gsock, &error);
- g_assert_no_error (error);
-
- sock = g_initable_new (SOUP_TYPE_SOCKET, NULL, &error,
- "gsocket", gsock,
- NULL);
- g_assert_no_error (error);
- g_assert_nonnull (sock);
-
- g_object_get (G_OBJECT (sock),
- "local-address", &local,
- NULL);
- g_assert_cmpint (socket_get_fd (sock), ==, g_socket_get_fd (gsock));
- g_assert_true (soup_socket_is_connected (sock));
-
- assert_host_equals (local, "127.0.0.1");
- g_assert_cmpint (g_inet_socket_address_get_port (local), ==, g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (gaddr)));
- g_object_unref (local);
- g_object_unref (gaddr);
-
- g_object_unref (sock);
-
- /* Closing the SoupSocket should have closed the GSocket */
- g_assert_true (g_socket_is_closed (gsock));
-
- g_object_unref (gsock);
-}
-
-static void
-do_socket_from_fd_bad_test (void)
-{
- GSocket *gsock, *gsock2, *gsockcli;
- SoupSocket *sock, *sock2;
- GInetSocketAddress *local, *remote;
- GSocketAddress *gaddr;
- GError *error = NULL;
-
- /* Importing an unconnected socket gives an error */
- gsock = g_socket_new (G_SOCKET_FAMILY_IPV4,
- G_SOCKET_TYPE_STREAM,
- G_SOCKET_PROTOCOL_DEFAULT,
- &error);
- g_assert_no_error (error);
- g_assert_false (g_socket_is_connected (gsock));
-
- sock = g_initable_new (SOUP_TYPE_SOCKET, NULL, &error,
- "gsocket", gsock,
- NULL);
- g_assert_error (error, G_IO_ERROR, G_IO_ERROR_FAILED);
- g_clear_error (&error);
- g_assert_null (sock);
- g_object_unref (gsock);
-
- gsock = g_socket_new (G_SOCKET_FAMILY_IPV4,
- G_SOCKET_TYPE_STREAM,
- G_SOCKET_PROTOCOL_DEFAULT,
- &error);
- g_assert_no_error (error);
-
- gaddr = g_inet_socket_address_new_from_string ("127.0.0.1", 0);
- g_socket_bind (gsock, gaddr, TRUE, &error);
- g_object_unref (gaddr);
- g_assert_no_error (error);
- g_socket_listen (gsock, &error);
- g_assert_no_error (error);
- g_assert_false (g_socket_is_connected (gsock));
-
- gaddr = g_socket_get_local_address (gsock, &error);
- g_assert_no_error (error);
-
- gsockcli = g_socket_new (G_SOCKET_FAMILY_IPV4,
- G_SOCKET_TYPE_STREAM,
- G_SOCKET_PROTOCOL_DEFAULT,
- &error);
- g_assert_no_error (error);
-
- g_socket_connect (gsockcli, gaddr, NULL, &error);
- g_assert_no_error (error);
- g_assert_true (g_socket_is_connected (gsockcli));
-
- gsock2 = g_socket_accept (gsock, NULL, &error);
- g_assert_no_error (error);
- g_assert_nonnull (gsock2);
-
- sock2 = g_initable_new (SOUP_TYPE_SOCKET, NULL, &error,
- "gsocket", gsock2,
- NULL);
- g_assert_no_error (error);
- g_assert_nonnull (sock2);
-
- g_object_get (G_OBJECT (sock2),
- "local-address", &local,
- "remote-address", &remote,
- NULL);
- g_assert_cmpint (socket_get_fd (sock2), ==, g_socket_get_fd (gsock2));
- g_assert_true (soup_socket_is_connected (sock2));
-
- assert_host_equals (local, "127.0.0.1");
- g_assert_cmpint (g_inet_socket_address_get_port (local), ==, g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (gaddr)));
- g_object_unref (gaddr);
-
- gaddr = g_socket_get_local_address (gsockcli, &error);
- g_assert_no_error (error);
- assert_host_equals (remote, "127.0.0.1");
- g_assert_cmpint (g_inet_socket_address_get_port (remote), ==, g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (gaddr)));
- g_object_unref (gaddr);
-
- g_object_unref (local);
- g_object_unref (remote);
-
- g_object_unref (sock2);
-
- g_object_unref (gsock);
- g_object_unref (gsock2);
- g_object_unref (gsockcli);
-}
-
-int
-main (int argc, char **argv)
-{
- int ret;
-
- test_init (argc, argv, NULL);
-
- g_test_add_func ("/sockets/unconnected", do_unconnected_socket_test);
- g_test_add_func ("/sockets/from-fd/server", do_socket_from_fd_server_test);
- g_test_add_func ("/sockets/from-fd/bad", do_socket_from_fd_bad_test);
-
- ret = g_test_run ();
-
- test_cleanup ();
- return ret;
-}