Blame libsoup/soup-socket.c

Packit Service ca3877
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
Packit Service ca3877
/*
Packit Service ca3877
 * soup-socket.c: Socket networking code.
Packit Service ca3877
 *
Packit Service ca3877
 * Copyright (C) 2000-2003, Ximian, Inc.
Packit Service ca3877
 */
Packit Service ca3877
Packit Service ca3877
#ifdef HAVE_CONFIG_H
Packit Service ca3877
#include <config.h>
Packit Service ca3877
#endif
Packit Service ca3877
Packit Service ca3877
#include <string.h>
Packit Service ca3877
Packit Service ca3877
#include <glib/gi18n-lib.h>
Packit Service ca3877
#include <gio/gnetworking.h>
Packit Service ca3877
Packit Service ca3877
#include "soup-socket.h"
Packit Service ca3877
#include "soup-socket-private.h"
Packit Service ca3877
#include "soup.h"
Packit Service ca3877
#include "soup-filter-input-stream.h"
Packit Service ca3877
#include "soup-io-stream.h"
Packit Service ca3877
Packit Service ca3877
/**
Packit Service ca3877
 * SECTION:soup-socket
Packit Service ca3877
 * @short_description: A network socket
Packit Service ca3877
 *
Packit Service ca3877
 * #SoupSocket is libsoup's TCP socket type. While it is primarily
Packit Service ca3877
 * intended for internal use, #SoupSockets are exposed in the
Packit Service ca3877
 * API in various places, and some of their methods (eg,
Packit Service ca3877
 * soup_socket_get_remote_address()) may be useful to applications.
Packit Service ca3877
 **/
Packit Service ca3877
Packit Service ca3877
enum {
Packit Service ca3877
	READABLE,
Packit Service ca3877
	WRITABLE,
Packit Service ca3877
	DISCONNECTED,
Packit Service ca3877
	NEW_CONNECTION,
Packit Service ca3877
	EVENT,
Packit Service ca3877
	LAST_SIGNAL
Packit Service ca3877
};
Packit Service ca3877
Packit Service ca3877
static guint signals[LAST_SIGNAL] = { 0 };
Packit Service ca3877
Packit Service ca3877
enum {
Packit Service ca3877
	PROP_0,
Packit Service ca3877
Packit Service ca3877
	PROP_FD,
Packit Service ca3877
	PROP_GSOCKET,
Packit Service ca3877
	PROP_IOSTREAM,
Packit Service ca3877
	PROP_LOCAL_ADDRESS,
Packit Service ca3877
	PROP_REMOTE_ADDRESS,
Packit Service ca3877
	PROP_NON_BLOCKING,
Packit Service ca3877
	PROP_IPV6_ONLY,
Packit Service ca3877
	PROP_IS_SERVER,
Packit Service ca3877
	PROP_SSL_CREDENTIALS,
Packit Service ca3877
	PROP_SSL_STRICT,
Packit Service ca3877
	PROP_SSL_FALLBACK,
Packit Service ca3877
	PROP_ASYNC_CONTEXT,
Packit Service ca3877
	PROP_USE_THREAD_CONTEXT,
Packit Service ca3877
	PROP_TIMEOUT,
Packit Service ca3877
	PROP_TRUSTED_CERTIFICATE,
Packit Service ca3877
	PROP_TLS_CERTIFICATE,
Packit Service ca3877
	PROP_TLS_ERRORS,
Packit Service ca3877
	PROP_SOCKET_PROPERTIES,
Packit Service ca3877
Packit Service ca3877
	LAST_PROP
Packit Service ca3877
};
Packit Service ca3877
Packit Service ca3877
typedef struct {
Packit Service ca3877
	SoupAddress *local_addr, *remote_addr;
Packit Service ca3877
	GIOStream *conn, *iostream;
Packit Service ca3877
	GSocket *gsock;
Packit Service ca3877
	GInputStream *istream;
Packit Service ca3877
	GOutputStream *ostream;
Packit Service ca3877
	GTlsCertificateFlags tls_errors;
Packit Service ca3877
	GTlsInteraction *tls_interaction;
Packit Service ca3877
	GProxyResolver *proxy_resolver;
Packit Service ca3877
Packit Service ca3877
	guint non_blocking:1;
Packit Service ca3877
	guint ipv6_only:1;
Packit Service ca3877
	guint is_server:1;
Packit Service ca3877
	guint ssl:1;
Packit Service ca3877
	guint ssl_strict:1;
Packit Service ca3877
	guint ssl_fallback:1;
Packit Service ca3877
	guint clean_dispose:1;
Packit Service ca3877
	guint use_thread_context:1;
Packit Service ca3877
	gpointer ssl_creds;
Packit Service ca3877
Packit Service ca3877
	GMainContext   *async_context;
Packit Service ca3877
	GSource        *watch_src;
Packit Service ca3877
	GSource        *read_src, *write_src;
Packit Service ca3877
Packit Service ca3877
	GMutex iolock, addrlock;
Packit Service ca3877
	guint timeout;
Packit Service ca3877
Packit Service ca3877
	GCancellable *connect_cancel;
Packit Service ca3877
	int fd;
Packit Service ca3877
} SoupSocketPrivate;
Packit Service ca3877
Packit Service ca3877
static void soup_socket_initable_interface_init (GInitableIface *initable_interface);
Packit Service ca3877
Packit Service ca3877
G_DEFINE_TYPE_WITH_CODE (SoupSocket, soup_socket, G_TYPE_OBJECT,
Packit Service ca3877
                         G_ADD_PRIVATE (SoupSocket)
Packit Service ca3877
			 G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
Packit Service ca3877
						soup_socket_initable_interface_init))
Packit Service ca3877
Packit Service ca3877
static void soup_socket_peer_certificate_changed (GObject *conn,
Packit Service ca3877
						  GParamSpec *pspec,
Packit Service ca3877
						  gpointer user_data);
Packit Service ca3877
static void finish_socket_setup (SoupSocket *sock);
Packit Service ca3877
static void finish_listener_setup (SoupSocket *sock);
Packit Service ca3877
Packit Service ca3877
static void
Packit Service ca3877
soup_socket_init (SoupSocket *sock)
Packit Service ca3877
{
Packit Service ca3877
	SoupSocketPrivate *priv = soup_socket_get_instance_private (sock);
Packit Service ca3877
Packit Service ca3877
	priv->non_blocking = TRUE;
Packit Service ca3877
	priv->fd = -1;
Packit Service ca3877
	g_mutex_init (&priv->addrlock);
Packit Service ca3877
	g_mutex_init (&priv->iolock);
Packit Service ca3877
}
Packit Service ca3877
Packit Service ca3877
static gboolean
Packit Service ca3877
soup_socket_initable_init (GInitable     *initable,
Packit Service ca3877
			   GCancellable  *cancellable,
Packit Service ca3877
			   GError       **error)
Packit Service ca3877
{
Packit Service ca3877
	SoupSocket *sock = SOUP_SOCKET (initable);
Packit Service ca3877
	SoupSocketPrivate *priv = soup_socket_get_instance_private (sock);
Packit Service ca3877
Packit Service ca3877
	if (priv->conn) {
Packit Service ca3877
		g_warn_if_fail (priv->gsock == NULL);
Packit Service ca3877
		g_warn_if_fail (priv->fd == -1);
Packit Service ca3877
Packit Service ca3877
		finish_socket_setup (sock);
Packit Service ca3877
	}
Packit Service ca3877
Packit Service ca3877
	if (priv->fd != -1) {
Packit Service ca3877
		guint type, len = sizeof (type);
Packit Service ca3877
Packit Service ca3877
		g_warn_if_fail (priv->gsock == NULL);
Packit Service ca3877
Packit Service ca3877
		/* GSocket will g_error() this, so we have to check ourselves. */
Packit Service ca3877
		if (getsockopt (priv->fd, SOL_SOCKET, SO_TYPE,
Packit Service ca3877
				(gpointer)&type, (gpointer)&len) == -1) {
Packit Service ca3877
			g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
Packit Service ca3877
					     _("Can’t import non-socket as SoupSocket"));
Packit Service ca3877
			return FALSE;
Packit Service ca3877
		}
Packit Service ca3877
Packit Service ca3877
		priv->gsock = g_socket_new_from_fd (priv->fd, error);
Packit Service ca3877
		if (!priv->gsock)
Packit Service ca3877
			return FALSE;
Packit Service ca3877
	}
Packit Service ca3877
Packit Service ca3877
	if (priv->gsock != NULL) {
Packit Service ca3877
		int listening;
Packit Service ca3877
Packit Service ca3877
		g_warn_if_fail (priv->local_addr == NULL);
Packit Service ca3877
		g_warn_if_fail (priv->remote_addr == NULL);
Packit Service ca3877
Packit Service ca3877
		if (!g_socket_get_option (priv->gsock,
Packit Service ca3877
					  SOL_SOCKET, SO_ACCEPTCONN,
Packit Service ca3877
					  &listening, error)) {
Packit Service ca3877
			g_prefix_error (error, _("Could not import existing socket: "));
Packit Service ca3877
			return FALSE;
Packit Service ca3877
		}
Packit Service ca3877
Packit Service ca3877
		finish_socket_setup (sock);
Packit Service ca3877
		if (listening)
Packit Service ca3877
			finish_listener_setup (sock);
Packit Service ca3877
		else if (!g_socket_is_connected (priv->gsock)) {
Packit Service ca3877
			g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
Packit Service ca3877
					     _("Can’t import unconnected socket"));
Packit Service ca3877
			return FALSE;
Packit Service ca3877
		}
Packit Service ca3877
	}
Packit Service ca3877
Packit Service ca3877
	return TRUE;
Packit Service ca3877
}
Packit Service ca3877
Packit Service ca3877
static void
Packit Service ca3877
disconnect_internal (SoupSocket *sock, gboolean close)
Packit Service ca3877
{
Packit Service ca3877
	SoupSocketPrivate *priv = soup_socket_get_instance_private (sock);
Packit Service ca3877
Packit Service ca3877
	g_clear_object (&priv->gsock);
Packit Service ca3877
	if (priv->conn && close) {
Packit Service ca3877
		g_io_stream_close (priv->conn, NULL, NULL);
Packit Service ca3877
		g_signal_handlers_disconnect_by_data (priv->conn, sock);
Packit Service ca3877
		g_clear_object (&priv->conn);
Packit Service ca3877
	}
Packit Service ca3877
Packit Service ca3877
	if (priv->read_src) {
Packit Service ca3877
		g_source_destroy (priv->read_src);
Packit Service ca3877
		priv->read_src = NULL;
Packit Service ca3877
	}
Packit Service ca3877
	if (priv->write_src) {
Packit Service ca3877
		g_source_destroy (priv->write_src);
Packit Service ca3877
		priv->write_src = NULL;
Packit Service ca3877
	}
Packit Service ca3877
}
Packit Service ca3877
Packit Service ca3877
static void
Packit Service ca3877
soup_socket_finalize (GObject *object)
Packit Service ca3877
{
Packit Service ca3877
	SoupSocket *sock = SOUP_SOCKET (object);
Packit Service ca3877
	SoupSocketPrivate *priv = soup_socket_get_instance_private (sock);
Packit Service ca3877
Packit Service ca3877
	if (priv->connect_cancel) {
Packit Service ca3877
		if (priv->clean_dispose)
Packit Service ca3877
			g_warning ("Disposing socket %p during connect", object);
Packit Service ca3877
		g_object_unref (priv->connect_cancel);
Packit Service ca3877
	}
Packit Service ca3877
	if (priv->conn) {
Packit Service ca3877
		if (priv->clean_dispose)
Packit Service ca3877
			g_warning ("Disposing socket %p while still connected", object);
Packit Service ca3877
		disconnect_internal (SOUP_SOCKET (object), TRUE);
Packit Service ca3877
	}
Packit Service ca3877
Packit Service ca3877
	g_clear_object (&priv->conn);
Packit Service ca3877
	g_clear_object (&priv->iostream);
Packit Service ca3877
	g_clear_object (&priv->istream);
Packit Service ca3877
	g_clear_object (&priv->ostream);
Packit Service ca3877
Packit Service ca3877
	g_clear_object (&priv->local_addr);
Packit Service ca3877
	g_clear_object (&priv->remote_addr);
Packit Service ca3877
Packit Service ca3877
	g_clear_object (&priv->tls_interaction);
Packit Service ca3877
	g_clear_object (&priv->proxy_resolver);
Packit Service ca3877
	g_clear_object (&priv->ssl_creds);
Packit Service ca3877
Packit Service ca3877
	if (priv->watch_src) {
Packit Service ca3877
		if (priv->clean_dispose && !priv->is_server)
Packit Service ca3877
			g_warning ("Disposing socket %p during async op", object);
Packit Service ca3877
		g_source_destroy (priv->watch_src);
Packit Service ca3877
	}
Packit Service ca3877
	g_clear_pointer (&priv->async_context, g_main_context_unref);
Packit Service ca3877
Packit Service ca3877
	g_mutex_clear (&priv->addrlock);
Packit Service ca3877
	g_mutex_clear (&priv->iolock);
Packit Service ca3877
Packit Service ca3877
	G_OBJECT_CLASS (soup_socket_parent_class)->finalize (object);
Packit Service ca3877
}
Packit Service ca3877
Packit Service ca3877
static void
Packit Service ca3877
finish_socket_setup (SoupSocket *sock)
Packit Service ca3877
{
Packit Service ca3877
	SoupSocketPrivate *priv = soup_socket_get_instance_private (sock);
Packit Service ca3877
Packit Service ca3877
	if (priv->gsock) {
Packit Service ca3877
		if (!priv->conn)
Packit Service ca3877
			priv->conn = (GIOStream *)g_socket_connection_factory_create_connection (priv->gsock);
Packit Service ca3877
Packit Service ca3877
		g_socket_set_timeout (priv->gsock, priv->timeout);
Packit Service ca3877
		g_socket_set_option (priv->gsock, IPPROTO_TCP, TCP_NODELAY, TRUE, NULL);
Packit Service ca3877
	}
Packit Service ca3877
Packit Service ca3877
	if (!priv->conn)
Packit Service ca3877
		return;
Packit Service ca3877
Packit Service ca3877
	if (!priv->iostream)
Packit Service ca3877
		priv->iostream = soup_io_stream_new (priv->conn, FALSE);
Packit Service ca3877
	if (!priv->istream)
Packit Service ca3877
		priv->istream = g_object_ref (g_io_stream_get_input_stream (priv->iostream));
Packit Service ca3877
	if (!priv->ostream)
Packit Service ca3877
		priv->ostream = g_object_ref (g_io_stream_get_output_stream (priv->iostream));
Packit Service ca3877
}
Packit Service ca3877
Packit Service ca3877
static void
Packit Service ca3877
soup_socket_set_property (GObject *object, guint prop_id,
Packit Service ca3877
			  const GValue *value, GParamSpec *pspec)
Packit Service ca3877
{
Packit Service ca3877
	SoupSocket *sock = SOUP_SOCKET (object);
Packit Service ca3877
	SoupSocketPrivate *priv = soup_socket_get_instance_private (sock);
Packit Service ca3877
	SoupSocketProperties *props;
Packit Service ca3877
Packit Service ca3877
	switch (prop_id) {
Packit Service ca3877
	case PROP_FD:
Packit Service ca3877
		priv->fd = g_value_get_int (value);
Packit Service ca3877
		break;
Packit Service ca3877
	case PROP_GSOCKET:
Packit Service ca3877
		priv->gsock = g_value_dup_object (value);
Packit Service ca3877
		break;
Packit Service ca3877
	case PROP_IOSTREAM:
Packit Service ca3877
		priv->conn = g_value_dup_object (value);
Packit Service ca3877
		break;
Packit Service ca3877
	case PROP_LOCAL_ADDRESS:
Packit Service ca3877
		priv->local_addr = g_value_dup_object (value);
Packit Service ca3877
		break;
Packit Service ca3877
	case PROP_REMOTE_ADDRESS:
Packit Service ca3877
		priv->remote_addr = g_value_dup_object (value);
Packit Service ca3877
		break;
Packit Service ca3877
	case PROP_NON_BLOCKING:
Packit Service ca3877
		priv->non_blocking = g_value_get_boolean (value);
Packit Service ca3877
		break;
Packit Service ca3877
	case PROP_IPV6_ONLY:
Packit Service ca3877
		priv->ipv6_only = g_value_get_boolean (value);
Packit Service ca3877
		break;
Packit Service ca3877
	case PROP_SSL_CREDENTIALS:
Packit Service ca3877
		priv->ssl_creds = g_value_get_pointer (value);
Packit Service ca3877
		if (priv->ssl_creds)
Packit Service ca3877
			g_object_ref (priv->ssl_creds);
Packit Service ca3877
		break;
Packit Service ca3877
	case PROP_SSL_STRICT:
Packit Service ca3877
		priv->ssl_strict = g_value_get_boolean (value);
Packit Service ca3877
		break;
Packit Service ca3877
	case PROP_SSL_FALLBACK:
Packit Service ca3877
		priv->ssl_fallback = g_value_get_boolean (value);
Packit Service ca3877
		break;
Packit Service ca3877
	case PROP_ASYNC_CONTEXT:
Packit Service ca3877
		if (!priv->use_thread_context) {
Packit Service ca3877
			priv->async_context = g_value_get_pointer (value);
Packit Service ca3877
			if (priv->async_context)
Packit Service ca3877
				g_main_context_ref (priv->async_context);
Packit Service ca3877
		}
Packit Service ca3877
		break;
Packit Service ca3877
	case PROP_USE_THREAD_CONTEXT:
Packit Service ca3877
		priv->use_thread_context = g_value_get_boolean (value);
Packit Service ca3877
		if (priv->use_thread_context) {
Packit Service ca3877
			g_clear_pointer (&priv->async_context, g_main_context_unref);
Packit Service ca3877
			priv->async_context = g_main_context_ref_thread_default ();
Packit Service ca3877
		}
Packit Service ca3877
		break;
Packit Service ca3877
	case PROP_TIMEOUT:
Packit Service ca3877
		priv->timeout = g_value_get_uint (value);
Packit Service ca3877
		if (priv->conn)
Packit Service ca3877
			g_socket_set_timeout (priv->gsock, priv->timeout);
Packit Service ca3877
		break;
Packit Service ca3877
	case PROP_SOCKET_PROPERTIES:
Packit Service ca3877
		props = g_value_get_boxed (value);
Packit Service ca3877
		if (props) {
Packit Service ca3877
			g_clear_pointer (&priv->async_context, g_main_context_unref);
Packit Service ca3877
			if (props->use_thread_context) {
Packit Service ca3877
				priv->use_thread_context = TRUE;
Packit Service ca3877
				priv->async_context = g_main_context_ref_thread_default ();
Packit Service ca3877
			} else {
Packit Service ca3877
				priv->use_thread_context = FALSE;
Packit Service ca3877
				if (props->async_context)
Packit Service ca3877
					priv->async_context = g_main_context_ref (props->async_context);
Packit Service ca3877
			}
Packit Service ca3877
Packit Service ca3877
			g_clear_object (&priv->proxy_resolver);
Packit Service ca3877
			if (props->proxy_resolver)
Packit Service ca3877
				priv->proxy_resolver = g_object_ref (props->proxy_resolver);
Packit Service ca3877
Packit Service ca3877
			g_clear_object (&priv->local_addr);
Packit Service ca3877
			if (props->local_addr)
Packit Service ca3877
				priv->local_addr = g_object_ref (props->local_addr);
Packit Service ca3877
Packit Service ca3877
			g_clear_object (&priv->ssl_creds);
Packit Service ca3877
			if (props->tlsdb)
Packit Service ca3877
				priv->ssl_creds = g_object_ref (props->tlsdb);
Packit Service ca3877
			g_clear_object (&priv->tls_interaction);
Packit Service ca3877
			if (props->tls_interaction)
Packit Service ca3877
				priv->tls_interaction = g_object_ref (props->tls_interaction);
Packit Service ca3877
			priv->ssl_strict = props->ssl_strict;
Packit Service ca3877
Packit Service ca3877
			priv->timeout = props->io_timeout;
Packit Service ca3877
			if (priv->conn)
Packit Service ca3877
				g_socket_set_timeout (priv->gsock, priv->timeout);
Packit Service ca3877
Packit Service ca3877
			priv->clean_dispose = TRUE;
Packit Service ca3877
		}
Packit Service ca3877
		break;
Packit Service ca3877
	default:
Packit Service ca3877
		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
Packit Service ca3877
		break;
Packit Service ca3877
	}
Packit Service ca3877
}
Packit Service ca3877
Packit Service ca3877
static void
Packit Service ca3877
soup_socket_get_property (GObject *object, guint prop_id,
Packit Service ca3877
			  GValue *value, GParamSpec *pspec)
Packit Service ca3877
{
Packit Service ca3877
	SoupSocket *sock = SOUP_SOCKET (object);
Packit Service ca3877
	SoupSocketPrivate *priv = soup_socket_get_instance_private (sock);
Packit Service ca3877
Packit Service ca3877
	switch (prop_id) {
Packit Service ca3877
	case PROP_FD:
Packit Service ca3877
		g_value_set_int (value, priv->fd);
Packit Service ca3877
		break;
Packit Service ca3877
	case PROP_LOCAL_ADDRESS:
Packit Service ca3877
		g_value_set_object (value, soup_socket_get_local_address (SOUP_SOCKET (object)));
Packit Service ca3877
		break;
Packit Service ca3877
	case PROP_REMOTE_ADDRESS:
Packit Service ca3877
		g_value_set_object (value, soup_socket_get_remote_address (SOUP_SOCKET (object)));
Packit Service ca3877
		break;
Packit Service ca3877
	case PROP_NON_BLOCKING:
Packit Service ca3877
		g_value_set_boolean (value, priv->non_blocking);
Packit Service ca3877
		break;
Packit Service ca3877
	case PROP_IPV6_ONLY:
Packit Service ca3877
		g_value_set_boolean (value, priv->ipv6_only);
Packit Service ca3877
		break;
Packit Service ca3877
	case PROP_IS_SERVER:
Packit Service ca3877
		g_value_set_boolean (value, priv->is_server);
Packit Service ca3877
		break;
Packit Service ca3877
	case PROP_SSL_CREDENTIALS:
Packit Service ca3877
		g_value_set_pointer (value, priv->ssl_creds);
Packit Service ca3877
		break;
Packit Service ca3877
	case PROP_SSL_STRICT:
Packit Service ca3877
		g_value_set_boolean (value, priv->ssl_strict);
Packit Service ca3877
		break;
Packit Service ca3877
	case PROP_SSL_FALLBACK:
Packit Service ca3877
		g_value_set_boolean (value, priv->ssl_fallback);
Packit Service ca3877
		break;
Packit Service ca3877
	case PROP_TRUSTED_CERTIFICATE:
Packit Service ca3877
		g_value_set_boolean (value, priv->tls_errors == 0);
Packit Service ca3877
		break;
Packit Service ca3877
	case PROP_ASYNC_CONTEXT:
Packit Service ca3877
		g_value_set_pointer (value, priv->async_context ? g_main_context_ref (priv->async_context) : NULL);
Packit Service ca3877
		break;
Packit Service ca3877
	case PROP_USE_THREAD_CONTEXT:
Packit Service ca3877
		g_value_set_boolean (value, priv->use_thread_context);
Packit Service ca3877
		break;
Packit Service ca3877
	case PROP_TIMEOUT:
Packit Service ca3877
		g_value_set_uint (value, priv->timeout);
Packit Service ca3877
		break;
Packit Service ca3877
	case PROP_TLS_CERTIFICATE:
Packit Service ca3877
		if (G_IS_TLS_CONNECTION (priv->conn))
Packit Service ca3877
			g_value_set_object (value, g_tls_connection_get_peer_certificate (G_TLS_CONNECTION (priv->conn)));
Packit Service ca3877
		else
Packit Service ca3877
			g_value_set_object (value, NULL);
Packit Service ca3877
		break;
Packit Service ca3877
	case PROP_TLS_ERRORS:
Packit Service ca3877
		g_value_set_flags (value, priv->tls_errors);
Packit Service ca3877
		break;
Packit Service ca3877
	default:
Packit Service ca3877
		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
Packit Service ca3877
		break;
Packit Service ca3877
	}
Packit Service ca3877
}
Packit Service ca3877
Packit Service ca3877
static void
Packit Service ca3877
soup_socket_class_init (SoupSocketClass *socket_class)
Packit Service ca3877
{
Packit Service ca3877
	GObjectClass *object_class = G_OBJECT_CLASS (socket_class);
Packit Service ca3877
Packit Service ca3877
	/* virtual method override */
Packit Service ca3877
	object_class->finalize = soup_socket_finalize;
Packit Service ca3877
	object_class->set_property = soup_socket_set_property;
Packit Service ca3877
	object_class->get_property = soup_socket_get_property;
Packit Service ca3877
Packit Service ca3877
	/* signals */
Packit Service ca3877
Packit Service ca3877
	/**
Packit Service ca3877
	 * SoupSocket::readable:
Packit Service ca3877
	 * @sock: the socket
Packit Service ca3877
	 *
Packit Service ca3877
	 * Emitted when an async socket is readable. See
Packit Service ca3877
	 * soup_socket_read(), soup_socket_read_until() and
Packit Service ca3877
	 * #SoupSocket:non-blocking.
Packit Service ca3877
	 **/
Packit Service ca3877
	signals[READABLE] =
Packit Service ca3877
		g_signal_new ("readable",
Packit Service ca3877
			      G_OBJECT_CLASS_TYPE (object_class),
Packit Service ca3877
			      G_SIGNAL_RUN_LAST,
Packit Service ca3877
			      G_STRUCT_OFFSET (SoupSocketClass, readable),
Packit Service ca3877
			      NULL, NULL,
Packit Service ca3877
			      NULL,
Packit Service ca3877
			      G_TYPE_NONE, 0);
Packit Service ca3877
Packit Service ca3877
	/**
Packit Service ca3877
	 * SoupSocket::writable:
Packit Service ca3877
	 * @sock: the socket
Packit Service ca3877
	 *
Packit Service ca3877
	 * Emitted when an async socket is writable. See
Packit Service ca3877
	 * soup_socket_write() and #SoupSocket:non-blocking.
Packit Service ca3877
	 **/
Packit Service ca3877
	signals[WRITABLE] =
Packit Service ca3877
		g_signal_new ("writable",
Packit Service ca3877
			      G_OBJECT_CLASS_TYPE (object_class),
Packit Service ca3877
			      G_SIGNAL_RUN_LAST,
Packit Service ca3877
			      G_STRUCT_OFFSET (SoupSocketClass, writable),
Packit Service ca3877
			      NULL, NULL,
Packit Service ca3877
			      NULL,
Packit Service ca3877
			      G_TYPE_NONE, 0);
Packit Service ca3877
Packit Service ca3877
	/**
Packit Service ca3877
	 * SoupSocket::disconnected:
Packit Service ca3877
	 * @sock: the socket
Packit Service ca3877
	 *
Packit Service ca3877
	 * Emitted when the socket is disconnected, for whatever
Packit Service ca3877
	 * reason.
Packit Service ca3877
	 **/
Packit Service ca3877
	signals[DISCONNECTED] =
Packit Service ca3877
		g_signal_new ("disconnected",
Packit Service ca3877
			      G_OBJECT_CLASS_TYPE (object_class),
Packit Service ca3877
			      G_SIGNAL_RUN_LAST,
Packit Service ca3877
			      G_STRUCT_OFFSET (SoupSocketClass, disconnected),
Packit Service ca3877
			      NULL, NULL,
Packit Service ca3877
			      NULL,
Packit Service ca3877
			      G_TYPE_NONE, 0);
Packit Service ca3877
Packit Service ca3877
	/**
Packit Service ca3877
	 * SoupSocket::new-connection:
Packit Service ca3877
	 * @sock: the socket
Packit Service ca3877
	 * @new: the new socket
Packit Service ca3877
	 *
Packit Service ca3877
	 * Emitted when a listening socket (set up with
Packit Service ca3877
	 * soup_socket_listen()) receives a new connection.
Packit Service ca3877
	 *
Packit Service ca3877
	 * You must ref the @new if you want to keep it; otherwise it
Packit Service ca3877
	 * will be destroyed after the signal is emitted.
Packit Service ca3877
	 **/
Packit Service ca3877
	signals[NEW_CONNECTION] =
Packit Service ca3877
		g_signal_new ("new_connection",
Packit Service ca3877
			      G_OBJECT_CLASS_TYPE (object_class),
Packit Service ca3877
			      G_SIGNAL_RUN_FIRST,
Packit Service ca3877
			      G_STRUCT_OFFSET (SoupSocketClass, new_connection),
Packit Service ca3877
			      NULL, NULL,
Packit Service ca3877
			      NULL,
Packit Service ca3877
			      G_TYPE_NONE, 1,
Packit Service ca3877
			      SOUP_TYPE_SOCKET);
Packit Service ca3877
	/**
Packit Service ca3877
	 * SoupSocket::event:
Packit Service ca3877
	 * @sock: the socket
Packit Service ca3877
	 * @event: the event that occurred
Packit Service ca3877
	 * @connection: the current connection state
Packit Service ca3877
	 *
Packit Service ca3877
	 * Emitted when a network-related event occurs. See
Packit Service ca3877
	 * #GSocketClient::event for more details.
Packit Service ca3877
	 *
Packit Service ca3877
	 * Since: 2.38
Packit Service ca3877
	 **/
Packit Service ca3877
	signals[EVENT] =
Packit Service ca3877
		g_signal_new ("event",
Packit Service ca3877
			      G_OBJECT_CLASS_TYPE (object_class),
Packit Service ca3877
			      G_SIGNAL_RUN_LAST,
Packit Service ca3877
			      0,
Packit Service ca3877
			      NULL, NULL,
Packit Service ca3877
			      NULL,
Packit Service ca3877
			      G_TYPE_NONE, 2,
Packit Service ca3877
			      G_TYPE_SOCKET_CLIENT_EVENT,
Packit Service ca3877
			      G_TYPE_IO_STREAM);
Packit Service ca3877
Packit Service ca3877
Packit Service ca3877
	/* properties */
Packit Service ca3877
	g_object_class_install_property (
Packit Service ca3877
		 object_class, PROP_FD,
Packit Service ca3877
		 g_param_spec_int (SOUP_SOCKET_FD,
Packit Service ca3877
				   "FD",
Packit Service ca3877
				   "The socket's file descriptor",
Packit Service ca3877
				   -1, G_MAXINT, -1,
Packit Service ca3877
				   G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
Packit Service ca3877
	g_object_class_install_property (
Packit Service ca3877
		 object_class, PROP_GSOCKET,
Packit Service ca3877
		 g_param_spec_object (SOUP_SOCKET_GSOCKET,
Packit Service ca3877
				      "GSocket",
Packit Service ca3877
				      "The socket's underlying GSocket",
Packit Service ca3877
				      G_TYPE_SOCKET,
Packit Service ca3877
				      G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
Packit Service ca3877
	g_object_class_install_property (
Packit Service ca3877
		 object_class, PROP_IOSTREAM,
Packit Service ca3877
		 g_param_spec_object (SOUP_SOCKET_IOSTREAM,
Packit Service ca3877
				      "GIOStream",
Packit Service ca3877
				      "The socket's underlying GIOStream",
Packit Service ca3877
				      G_TYPE_IO_STREAM,
Packit Service ca3877
				      G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
Packit Service ca3877
Packit Service ca3877
	/**
Packit Service ca3877
	 * SOUP_SOCKET_LOCAL_ADDRESS:
Packit Service ca3877
	 *
Packit Service ca3877
	 * Alias for the #SoupSocket:local-address property. (Address
Packit Service ca3877
	 * of local end of socket.)
Packit Service ca3877
	 **/
Packit Service ca3877
	g_object_class_install_property (
Packit Service ca3877
		object_class, PROP_LOCAL_ADDRESS,
Packit Service ca3877
		g_param_spec_object (SOUP_SOCKET_LOCAL_ADDRESS,
Packit Service ca3877
				     "Local address",
Packit Service ca3877
				     "Address of local end of socket",
Packit Service ca3877
				     SOUP_TYPE_ADDRESS,
Packit Service ca3877
				     G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
Packit Service ca3877
	/**
Packit Service ca3877
	 * SOUP_SOCKET_REMOTE_ADDRESS:
Packit Service ca3877
	 *
Packit Service ca3877
	 * Alias for the #SoupSocket:remote-address property. (Address
Packit Service ca3877
	 * of remote end of socket.)
Packit Service ca3877
	 **/
Packit Service ca3877
	g_object_class_install_property (
Packit Service ca3877
		object_class, PROP_REMOTE_ADDRESS,
Packit Service ca3877
		g_param_spec_object (SOUP_SOCKET_REMOTE_ADDRESS,
Packit Service ca3877
				     "Remote address",
Packit Service ca3877
				     "Address of remote end of socket",
Packit Service ca3877
				     SOUP_TYPE_ADDRESS,
Packit Service ca3877
				     G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
Packit Service ca3877
	/**
Packit Service ca3877
	 * SoupSocket:non-blocking:
Packit Service ca3877
	 *
Packit Service ca3877
	 * Whether or not the socket uses non-blocking I/O.
Packit Service ca3877
	 *
Packit Service ca3877
	 * #SoupSocket's I/O methods are designed around the idea of
Packit Service ca3877
	 * using a single codepath for both synchronous and
Packit Service ca3877
	 * asynchronous I/O. If you want to read off a #SoupSocket,
Packit Service ca3877
	 * the "correct" way to do it is to call soup_socket_read() or
Packit Service ca3877
	 * soup_socket_read_until() repeatedly until you have read
Packit Service ca3877
	 * everything you want. If it returns %SOUP_SOCKET_WOULD_BLOCK
Packit Service ca3877
	 * at any point, stop reading and wait for it to emit the
Packit Service ca3877
	 * #SoupSocket::readable signal. Then go back to the
Packit Service ca3877
	 * reading-as-much-as-you-can loop. Likewise, for writing to a
Packit Service ca3877
	 * #SoupSocket, you should call soup_socket_write() either
Packit Service ca3877
	 * until you have written everything, or it returns
Packit Service ca3877
	 * %SOUP_SOCKET_WOULD_BLOCK (in which case you wait for
Packit Service ca3877
	 * #SoupSocket::writable and then go back into the loop).
Packit Service ca3877
	 *
Packit Service ca3877
	 * Code written this way will work correctly with both
Packit Service ca3877
	 * blocking and non-blocking sockets; blocking sockets will
Packit Service ca3877
	 * simply never return %SOUP_SOCKET_WOULD_BLOCK, and so the
Packit Service ca3877
	 * code that handles that case just won't get used for them.
Packit Service ca3877
	 **/
Packit Service ca3877
	/**
Packit Service ca3877
	 * SOUP_SOCKET_FLAG_NONBLOCKING:
Packit Service ca3877
	 *
Packit Service ca3877
	 * Alias for the #SoupSocket:non-blocking property. (Whether
Packit Service ca3877
	 * or not the socket uses non-blocking I/O.)
Packit Service ca3877
	 **/
Packit Service ca3877
	g_object_class_install_property (
Packit Service ca3877
		object_class, PROP_NON_BLOCKING,
Packit Service ca3877
		g_param_spec_boolean (SOUP_SOCKET_FLAG_NONBLOCKING,
Packit Service ca3877
				      "Non-blocking",
Packit Service ca3877
				      "Whether or not the socket uses non-blocking I/O",
Packit Service ca3877
				      TRUE,
Packit Service ca3877
				      G_PARAM_READWRITE));
Packit Service ca3877
	g_object_class_install_property (
Packit Service ca3877
		object_class, PROP_IPV6_ONLY,
Packit Service ca3877
		g_param_spec_boolean (SOUP_SOCKET_IPV6_ONLY,
Packit Service ca3877
				      "IPv6 only",
Packit Service ca3877
				      "IPv6 only",
Packit Service ca3877
				      FALSE,
Packit Service ca3877
				      G_PARAM_READWRITE));
Packit Service ca3877
	/**
Packit Service ca3877
	 * SOUP_SOCKET_IS_SERVER:
Packit Service ca3877
	 *
Packit Service ca3877
	 * Alias for the #SoupSocket:is-server property, qv.
Packit Service ca3877
	 **/
Packit Service ca3877
	/**
Packit Service ca3877
	 * SoupSocket:is-server:
Packit Service ca3877
	 *
Packit Service ca3877
	 * Whether or not the socket is a server socket.
Packit Service ca3877
	 *
Packit Service ca3877
	 * Note that for "ordinary" #SoupSockets this will be set for
Packit Service ca3877
	 * both listening sockets and the sockets emitted by
Packit Service ca3877
	 * #SoupSocket::new-connection, but for sockets created by
Packit Service ca3877
	 * setting #SoupSocket:fd, it will only be set for listening
Packit Service ca3877
	 * sockets.
Packit Service ca3877
	 **/
Packit Service ca3877
	g_object_class_install_property (
Packit Service ca3877
		object_class, PROP_IS_SERVER,
Packit Service ca3877
		g_param_spec_boolean (SOUP_SOCKET_IS_SERVER,
Packit Service ca3877
				      "Server",
Packit Service ca3877
				      "Whether or not the socket is a server socket",
Packit Service ca3877
				      FALSE,
Packit Service ca3877
				      G_PARAM_READABLE));
Packit Service ca3877
	/**
Packit Service ca3877
	 * SOUP_SOCKET_SSL_CREDENTIALS:
Packit Service ca3877
	 *
Packit Service ca3877
	 * Alias for the #SoupSocket:ssl-creds property.
Packit Service ca3877
	 * (SSL credential information.)
Packit Service ca3877
	 **/
Packit Service ca3877
	/* For historical reasons, there's only a single property
Packit Service ca3877
	 * here, which is a GTlsDatabase for client sockets, and
Packit Service ca3877
	 * a GTlsCertificate for server sockets. Whee!
Packit Service ca3877
	 */
Packit Service ca3877
	g_object_class_install_property (
Packit Service ca3877
		object_class, PROP_SSL_CREDENTIALS,
Packit Service ca3877
		g_param_spec_pointer (SOUP_SOCKET_SSL_CREDENTIALS,
Packit Service ca3877
				      "SSL credentials",
Packit Service ca3877
				      "SSL credential information, passed from the session to the SSL implementation",
Packit Service ca3877
				      G_PARAM_READWRITE));
Packit Service ca3877
	/**
Packit Service ca3877
	 * SOUP_SOCKET_SSL_STRICT:
Packit Service ca3877
	 *
Packit Service ca3877
	 * Alias for the #SoupSocket:ssl-strict property.
Packit Service ca3877
	 **/
Packit Service ca3877
	g_object_class_install_property (
Packit Service ca3877
		object_class, PROP_SSL_STRICT,
Packit Service ca3877
		g_param_spec_boolean (SOUP_SOCKET_SSL_STRICT,
Packit Service ca3877
				      "Strictly validate SSL certificates",
Packit Service ca3877
				      "Whether certificate errors should be considered a connection error",
Packit Service ca3877
				      TRUE,
Packit Service ca3877
				      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
Packit Service ca3877
	/**
Packit Service ca3877
	 * SOUP_SOCKET_SSL_FALLBACK:
Packit Service ca3877
	 *
Packit Service ca3877
	 * Alias for the #SoupSocket:ssl-fallback property.
Packit Service ca3877
	 **/
Packit Service ca3877
	g_object_class_install_property (
Packit Service ca3877
		object_class, PROP_SSL_FALLBACK,
Packit Service ca3877
		g_param_spec_boolean (SOUP_SOCKET_SSL_FALLBACK,
Packit Service ca3877
				      "SSLv3 fallback",
Packit Service ca3877
				      "Use SSLv3 instead of TLS (client-side only)",
Packit Service ca3877
				      FALSE,
Packit Service ca3877
				      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
Packit Service ca3877
	/**
Packit Service ca3877
	 * SOUP_SOCKET_TRUSTED_CERTIFICATE:
Packit Service ca3877
	 *
Packit Service ca3877
	 * Alias for the #SoupSocket:trusted-certificate
Packit Service ca3877
	 * property.
Packit Service ca3877
	 **/
Packit Service ca3877
	g_object_class_install_property (
Packit Service ca3877
		object_class, PROP_TRUSTED_CERTIFICATE,
Packit Service ca3877
		g_param_spec_boolean (SOUP_SOCKET_TRUSTED_CERTIFICATE,
Packit Service ca3877
				     "Trusted Certificate",
Packit Service ca3877
				     "Whether the server certificate is trusted, if this is an SSL socket",
Packit Service ca3877
				     FALSE,
Packit Service ca3877
				     G_PARAM_READABLE));
Packit Service ca3877
	/**
Packit Service ca3877
	 * SOUP_SOCKET_ASYNC_CONTEXT:
Packit Service ca3877
	 *
Packit Service ca3877
	 * Alias for the #SoupSocket:async-context property. (The
Packit Service ca3877
	 * socket's #GMainContext.)
Packit Service ca3877
	 **/
Packit Service ca3877
	g_object_class_install_property (
Packit Service ca3877
		object_class, PROP_ASYNC_CONTEXT,
Packit Service ca3877
		g_param_spec_pointer (SOUP_SOCKET_ASYNC_CONTEXT,
Packit Service ca3877
				      "Async GMainContext",
Packit Service ca3877
				      "The GMainContext to dispatch this socket's async I/O in",
Packit Service ca3877
				      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
Packit Service ca3877
Packit Service ca3877
	/**
Packit Service ca3877
	 * SOUP_SOCKET_USE_THREAD_CONTEXT:
Packit Service ca3877
	 *
Packit Service ca3877
	 * Alias for the #SoupSocket:use-thread-context property. (Use
Packit Service ca3877
	 * g_main_context_get_thread_default())
Packit Service ca3877
	 *
Packit Service ca3877
	 * Since: 2.38
Packit Service ca3877
	 */
Packit Service ca3877
	/**
Packit Service ca3877
	 * SoupSocket:use-thread-context:
Packit Service ca3877
	 *
Packit Service ca3877
	 * Use g_main_context_get_thread_default().
Packit Service ca3877
	 *
Packit Service ca3877
	 * Since: 2.38
Packit Service ca3877
	 */
Packit Service ca3877
	g_object_class_install_property (
Packit Service ca3877
		object_class, PROP_USE_THREAD_CONTEXT,
Packit Service ca3877
		g_param_spec_boolean (SOUP_SOCKET_USE_THREAD_CONTEXT,
Packit Service ca3877
				      "Use thread context",
Packit Service ca3877
				      "Use g_main_context_get_thread_default",
Packit Service ca3877
				      FALSE,
Packit Service ca3877
				      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
Packit Service ca3877
Packit Service ca3877
	/**
Packit Service ca3877
	 * SOUP_SOCKET_TIMEOUT:
Packit Service ca3877
	 *
Packit Service ca3877
	 * Alias for the #SoupSocket:timeout property. (The timeout
Packit Service ca3877
	 * in seconds for blocking socket I/O operations.)
Packit Service ca3877
	 **/
Packit Service ca3877
	g_object_class_install_property (
Packit Service ca3877
		object_class, PROP_TIMEOUT,
Packit Service ca3877
		g_param_spec_uint (SOUP_SOCKET_TIMEOUT,
Packit Service ca3877
				   "Timeout value",
Packit Service ca3877
				   "Value in seconds to timeout a blocking I/O",
Packit Service ca3877
				   0, G_MAXUINT, 0,
Packit Service ca3877
				   G_PARAM_READWRITE));
Packit Service ca3877
Packit Service ca3877
	/**
Packit Service ca3877
	 * SOUP_SOCKET_TLS_CERTIFICATE:
Packit Service ca3877
	 *
Packit Service ca3877
	 * Alias for the #SoupSocket:tls-certificate
Packit Service ca3877
	 * property. Note that this property's value is only useful
Packit Service ca3877
	 * if the socket is for a TLS connection, and only reliable
Packit Service ca3877
	 * after some data has been transferred to or from it.
Packit Service ca3877
	 *
Packit Service ca3877
	 * Since: 2.34
Packit Service ca3877
	 **/
Packit Service ca3877
	g_object_class_install_property (
Packit Service ca3877
		object_class, PROP_TLS_CERTIFICATE,
Packit Service ca3877
		g_param_spec_object (SOUP_SOCKET_TLS_CERTIFICATE,
Packit Service ca3877
				     "TLS certificate",
Packit Service ca3877
				     "The peer's TLS certificate",
Packit Service ca3877
				     G_TYPE_TLS_CERTIFICATE,
Packit Service ca3877
				     G_PARAM_READABLE));
Packit Service ca3877
	/**
Packit Service ca3877
	 * SOUP_SOCKET_TLS_ERRORS:
Packit Service ca3877
	 *
Packit Service ca3877
	 * Alias for the #SoupSocket:tls-errors
Packit Service ca3877
	 * property. Note that this property's value is only useful
Packit Service ca3877
	 * if the socket is for a TLS connection, and only reliable
Packit Service ca3877
	 * after some data has been transferred to or from it.
Packit Service ca3877
	 *
Packit Service ca3877
	 * Since: 2.34
Packit Service ca3877
	 **/
Packit Service ca3877
	g_object_class_install_property (
Packit Service ca3877
		object_class, PROP_TLS_ERRORS,
Packit Service ca3877
		g_param_spec_flags (SOUP_SOCKET_TLS_ERRORS,
Packit Service ca3877
				    "TLS errors",
Packit Service ca3877
				    "Errors with the peer's TLS certificate",
Packit Service ca3877
				    G_TYPE_TLS_CERTIFICATE_FLAGS, 0,
Packit Service ca3877
				    G_PARAM_READABLE));
Packit Service ca3877
Packit Service ca3877
	g_object_class_install_property (
Packit Service ca3877
		 object_class, PROP_SOCKET_PROPERTIES,
Packit Service ca3877
		 g_param_spec_boxed (SOUP_SOCKET_SOCKET_PROPERTIES,
Packit Service ca3877
				     "Socket properties",
Packit Service ca3877
				     "Socket properties",
Packit Service ca3877
				     SOUP_TYPE_SOCKET_PROPERTIES,
Packit Service ca3877
				     G_PARAM_WRITABLE));
Packit Service ca3877
}
Packit Service ca3877
Packit Service ca3877
static void
Packit Service ca3877
soup_socket_initable_interface_init (GInitableIface *initable_interface)
Packit Service ca3877
{
Packit Service ca3877
	initable_interface->init = soup_socket_initable_init;
Packit Service ca3877
}
Packit Service ca3877
Packit Service ca3877
Packit Service ca3877
/**
Packit Service ca3877
 * soup_socket_new:
Packit Service ca3877
 * @optname1: name of first property to set (or %NULL)
Packit Service ca3877
 * @...: value of @optname1, followed by additional property/value pairs
Packit Service ca3877
 *
Packit Service ca3877
 * Creates a new (disconnected) socket
Packit Service ca3877
 *
Packit Service ca3877
 * Return value: the new socket
Packit Service ca3877
 **/
Packit Service ca3877
SoupSocket *
Packit Service ca3877
soup_socket_new (const char *optname1, ...)
Packit Service ca3877
{
Packit Service ca3877
	SoupSocket *sock;
Packit Service ca3877
	va_list ap;
Packit Service ca3877
Packit Service ca3877
	va_start (ap, optname1);
Packit Service ca3877
	sock = (SoupSocket *)g_object_new_valist (SOUP_TYPE_SOCKET,
Packit Service ca3877
						  optname1, ap);
Packit Service ca3877
	va_end (ap);
Packit Service ca3877
Packit Service ca3877
	return sock;
Packit Service ca3877
}
Packit Service ca3877
Packit Service ca3877
static void
Packit Service ca3877
soup_socket_event (SoupSocket         *sock,
Packit Service ca3877
		   GSocketClientEvent  event,
Packit Service ca3877
		   GIOStream          *connection)
Packit Service ca3877
{
Packit Service ca3877
	g_signal_emit (sock, signals[EVENT], 0,
Packit Service ca3877
		       event, connection);
Packit Service ca3877
}
Packit Service ca3877
Packit Service ca3877
static void
Packit Service ca3877
re_emit_socket_client_event (GSocketClient       *client,
Packit Service ca3877
			     GSocketClientEvent   event,
Packit Service ca3877
			     GSocketConnectable  *connectable,
Packit Service ca3877
			     GIOStream           *connection,
Packit Service ca3877
			     gpointer             user_data)
Packit Service ca3877
{
Packit Service ca3877
	SoupSocket *sock = user_data;
Packit Service ca3877
Packit Service ca3877
	soup_socket_event (sock, event, connection);
Packit Service ca3877
}
Packit Service ca3877
Packit Service ca3877
static gboolean
Packit Service ca3877
socket_connect_finish (SoupSocket *sock, GSocketConnection *conn)
Packit Service ca3877
{
Packit Service ca3877
	SoupSocketPrivate *priv = soup_socket_get_instance_private (sock);
Packit Service ca3877
Packit Service ca3877
	g_clear_object (&priv->connect_cancel);
Packit Service ca3877
Packit Service ca3877
	if (conn) {
Packit Service ca3877
		priv->conn = (GIOStream *)conn;
Packit Service ca3877
		priv->gsock = g_object_ref (g_socket_connection_get_socket (conn));
Packit Service ca3877
		finish_socket_setup (sock);
Packit Service ca3877
		return TRUE;
Packit Service ca3877
	} else
Packit Service ca3877
		return FALSE;
Packit Service ca3877
}
Packit Service ca3877
Packit Service ca3877
static guint
Packit Service ca3877
socket_legacy_error (SoupSocket *sock, GError *error)
Packit Service ca3877
{
Packit Service ca3877
	guint status;
Packit Service ca3877
Packit Service ca3877
	if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
Packit Service ca3877
		status = SOUP_STATUS_CANCELLED;
Packit Service ca3877
	else if (error->domain == G_RESOLVER_ERROR)
Packit Service ca3877
		status = SOUP_STATUS_CANT_RESOLVE;
Packit Service ca3877
	else
Packit Service ca3877
		status = SOUP_STATUS_CANT_CONNECT;
Packit Service ca3877
Packit Service ca3877
	g_error_free (error);
Packit Service ca3877
	return status;
Packit Service ca3877
}
Packit Service ca3877
Packit Service ca3877
static GSocketClient *
Packit Service ca3877
new_socket_client (SoupSocket *sock)
Packit Service ca3877
{
Packit Service ca3877
	SoupSocketPrivate *priv = soup_socket_get_instance_private (sock);
Packit Service ca3877
	GSocketClient *client = g_socket_client_new ();
Packit Service ca3877
Packit Service ca3877
	g_signal_connect (client, "event",
Packit Service ca3877
			  G_CALLBACK (re_emit_socket_client_event), sock);
Packit Service ca3877
	if (priv->proxy_resolver) {
Packit Service ca3877
		g_socket_client_set_proxy_resolver (client, priv->proxy_resolver);
Packit Service ca3877
		g_socket_client_add_application_proxy (client, "http");
Packit Service ca3877
	} else
Packit Service ca3877
		g_socket_client_set_enable_proxy (client, FALSE);
Packit Service ca3877
	if (priv->timeout)
Packit Service ca3877
		g_socket_client_set_timeout (client, priv->timeout);
Packit Service ca3877
Packit Service ca3877
	if (priv->local_addr) {
Packit Service ca3877
		GSocketAddress *addr;
Packit Service ca3877
Packit Service ca3877
		addr = soup_address_get_gsockaddr (priv->local_addr);
Packit Service ca3877
		g_socket_client_set_local_address (client, addr);
Packit Service ca3877
		g_object_unref (addr);
Packit Service ca3877
	}
Packit Service ca3877
Packit Service ca3877
	return client;
Packit Service ca3877
}
Packit Service ca3877
Packit Service ca3877
static void
Packit Service ca3877
async_connected (GObject *client, GAsyncResult *result, gpointer data)
Packit Service ca3877
{
Packit Service ca3877
	GTask *task = data;
Packit Service ca3877
	SoupSocket *sock = g_task_get_source_object (task);
Packit Service ca3877
	GSocketConnection *conn;
Packit Service ca3877
	GError *error = NULL;
Packit Service ca3877
Packit Service ca3877
	conn = g_socket_client_connect_finish (G_SOCKET_CLIENT (client),
Packit Service ca3877
					       result, &error);
Packit Service ca3877
	if (socket_connect_finish (sock, conn))
Packit Service ca3877
		g_task_return_boolean (task, TRUE);
Packit Service ca3877
	else
Packit Service ca3877
		g_task_return_error (task, error);
Packit Service ca3877
	g_object_unref (task);
Packit Service ca3877
}
Packit Service ca3877
Packit Service ca3877
gboolean
Packit Service ca3877
soup_socket_connect_finish_internal (SoupSocket    *sock,
Packit Service ca3877
				     GAsyncResult  *result,
Packit Service ca3877
				     GError       **error)
Packit Service ca3877
{
Packit Service ca3877
	return g_task_propagate_boolean (G_TASK (result), error);
Packit Service ca3877
}
Packit Service ca3877
Packit Service ca3877
void
Packit Service ca3877
soup_socket_connect_async_internal (SoupSocket          *sock,
Packit Service ca3877
				    GCancellable        *cancellable,
Packit Service ca3877
				    GAsyncReadyCallback  callback,
Packit Service ca3877
				    gpointer             user_data)
Packit Service ca3877
{
Packit Service ca3877
	SoupSocketPrivate *priv;
Packit Service ca3877
	GSocketClient *client;
Packit Service ca3877
	GTask *task;
Packit Service ca3877
Packit Service ca3877
	g_return_if_fail (SOUP_IS_SOCKET (sock));
Packit Service ca3877
	priv = soup_socket_get_instance_private (sock);
Packit Service ca3877
	g_return_if_fail (!priv->is_server);
Packit Service ca3877
	g_return_if_fail (priv->gsock == NULL);
Packit Service ca3877
	g_return_if_fail (priv->remote_addr != NULL);
Packit Service ca3877
Packit Service ca3877
	priv->connect_cancel = cancellable ? g_object_ref (cancellable) : g_cancellable_new ();
Packit Service ca3877
	task = g_task_new (sock, priv->connect_cancel, callback, user_data);
Packit Service ca3877
Packit Service ca3877
	client = new_socket_client (sock);
Packit Service ca3877
	g_socket_client_connect_async (client,
Packit Service ca3877
				       G_SOCKET_CONNECTABLE (priv->remote_addr),
Packit Service ca3877
				       priv->connect_cancel,
Packit Service ca3877
				       async_connected, task);
Packit Service ca3877
	g_object_unref (client);
Packit Service ca3877
}
Packit Service ca3877
Packit Service ca3877
/**
Packit Service ca3877
 * SoupSocketCallback:
Packit Service ca3877
 * @sock: the #SoupSocket
Packit Service ca3877
 * @status: an HTTP status code indicating success or failure
Packit Service ca3877
 * @user_data: the data passed to soup_socket_connect_async()
Packit Service ca3877
 *
Packit Service ca3877
 * The callback function passed to soup_socket_connect_async().
Packit Service ca3877
 **/
Packit Service ca3877
Packit Service ca3877
typedef struct {
Packit Service ca3877
	SoupSocket *sock;
Packit Service ca3877
	SoupSocketCallback callback;
Packit Service ca3877
	gpointer user_data;
Packit Service ca3877
} SoupSocketAsyncConnectData;
Packit Service ca3877
Packit Service ca3877
static void
Packit Service ca3877
legacy_connect_async_cb (GObject       *object,
Packit Service ca3877
			 GAsyncResult  *result,
Packit Service ca3877
			 gpointer       user_data)
Packit Service ca3877
{
Packit Service ca3877
	SoupSocket *sock = SOUP_SOCKET (object);
Packit Service ca3877
	SoupSocketAsyncConnectData *sacd = user_data;
Packit Service ca3877
	GError *error = NULL;
Packit Service ca3877
	guint status;
Packit Service ca3877
Packit Service ca3877
	if (soup_socket_connect_finish_internal (sock, result, &error))
Packit Service ca3877
		status = SOUP_STATUS_OK;
Packit Service ca3877
	else
Packit Service ca3877
		status = socket_legacy_error (sock, error);
Packit Service ca3877
Packit Service ca3877
	sacd->callback (sock, status, sacd->user_data);
Packit Service ca3877
	g_object_unref (sacd->sock);
Packit Service ca3877
	g_slice_free (SoupSocketAsyncConnectData, sacd);
Packit Service ca3877
}
Packit Service ca3877
Packit Service ca3877
/**
Packit Service ca3877
 * soup_socket_connect_async:
Packit Service ca3877
 * @sock: a client #SoupSocket (which must not already be connected)
Packit Service ca3877
 * @cancellable: a #GCancellable, or %NULL
Packit Service ca3877
 * @callback: (scope async): callback to call after connecting
Packit Service ca3877
 * @user_data: data to pass to @callback
Packit Service ca3877
 *
Packit Service ca3877
 * Begins asynchronously connecting to @sock's remote address. The
Packit Service ca3877
 * socket will call @callback when it succeeds or fails (but not
Packit Service ca3877
 * before returning from this function).
Packit Service ca3877
 *
Packit Service ca3877
 * If @cancellable is non-%NULL, it can be used to cancel the
Packit Service ca3877
 * connection. @callback will still be invoked in this case, with a
Packit Service ca3877
 * status of %SOUP_STATUS_CANCELLED.
Packit Service ca3877
 **/
Packit Service ca3877
void
Packit Service ca3877
soup_socket_connect_async (SoupSocket *sock, GCancellable *cancellable,
Packit Service ca3877
			   SoupSocketCallback callback, gpointer user_data)
Packit Service ca3877
{
Packit Service ca3877
	SoupSocketPrivate *priv;
Packit Service ca3877
	SoupSocketAsyncConnectData *sacd;
Packit Service ca3877
Packit Service ca3877
	g_return_if_fail (SOUP_IS_SOCKET (sock));
Packit Service ca3877
	priv = soup_socket_get_instance_private (sock);
Packit Service ca3877
	g_return_if_fail (!priv->is_server);
Packit Service ca3877
	g_return_if_fail (priv->gsock == NULL);
Packit Service ca3877
	g_return_if_fail (priv->remote_addr != NULL);
Packit Service ca3877
Packit Service ca3877
	sacd = g_slice_new0 (SoupSocketAsyncConnectData);
Packit Service ca3877
	sacd->sock = g_object_ref (sock);
Packit Service ca3877
	sacd->callback = callback;
Packit Service ca3877
	sacd->user_data = user_data;
Packit Service ca3877
Packit Service ca3877
	if (priv->async_context && !priv->use_thread_context)
Packit Service ca3877
		g_main_context_push_thread_default (priv->async_context);
Packit Service ca3877
Packit Service ca3877
	soup_socket_connect_async_internal (sock, cancellable,
Packit Service ca3877
					    legacy_connect_async_cb,
Packit Service ca3877
					    sacd);
Packit Service ca3877
Packit Service ca3877
	if (priv->async_context && !priv->use_thread_context)
Packit Service ca3877
		g_main_context_pop_thread_default (priv->async_context);
Packit Service ca3877
}
Packit Service ca3877
Packit Service ca3877
gboolean
Packit Service ca3877
soup_socket_connect_sync_internal (SoupSocket    *sock,
Packit Service ca3877
				   GCancellable  *cancellable,
Packit Service ca3877
				   GError       **error)
Packit Service ca3877
{
Packit Service ca3877
	SoupSocketPrivate *priv;
Packit Service ca3877
	GSocketClient *client;
Packit Service ca3877
	GSocketConnection *conn;
Packit Service ca3877
Packit Service ca3877
	g_return_val_if_fail (SOUP_IS_SOCKET (sock), SOUP_STATUS_MALFORMED);
Packit Service ca3877
	priv = soup_socket_get_instance_private (sock);
Packit Service ca3877
	g_return_val_if_fail (!priv->is_server, SOUP_STATUS_MALFORMED);
Packit Service ca3877
	g_return_val_if_fail (priv->gsock == NULL, SOUP_STATUS_MALFORMED);
Packit Service ca3877
	g_return_val_if_fail (priv->remote_addr != NULL, SOUP_STATUS_MALFORMED);
Packit Service ca3877
Packit Service ca3877
	priv->connect_cancel = cancellable ? g_object_ref (cancellable) : g_cancellable_new ();
Packit Service ca3877
Packit Service ca3877
	client = new_socket_client (sock);
Packit Service ca3877
	conn = g_socket_client_connect (client,
Packit Service ca3877
					G_SOCKET_CONNECTABLE (priv->remote_addr),
Packit Service ca3877
					priv->connect_cancel, error);
Packit Service ca3877
	g_object_unref (client);
Packit Service ca3877
Packit Service ca3877
	return socket_connect_finish (sock, conn);
Packit Service ca3877
}
Packit Service ca3877
Packit Service ca3877
/**
Packit Service ca3877
 * soup_socket_connect_sync:
Packit Service ca3877
 * @sock: a client #SoupSocket (which must not already be connected)
Packit Service ca3877
 * @cancellable: a #GCancellable, or %NULL
Packit Service ca3877
 *
Packit Service ca3877
 * Attempt to synchronously connect @sock to its remote address.
Packit Service ca3877
 *
Packit Service ca3877
 * If @cancellable is non-%NULL, it can be used to cancel the
Packit Service ca3877
 * connection, in which case soup_socket_connect_sync() will return
Packit Service ca3877
 * %SOUP_STATUS_CANCELLED.
Packit Service ca3877
 *
Packit Service ca3877
 * Return value: a success or failure code.
Packit Service ca3877
 **/
Packit Service ca3877
guint
Packit Service ca3877
soup_socket_connect_sync (SoupSocket *sock, GCancellable *cancellable)
Packit Service ca3877
{
Packit Service ca3877
	SoupSocketPrivate *priv;
Packit Service ca3877
	GError *error = NULL;
Packit Service ca3877
Packit Service ca3877
	g_return_val_if_fail (SOUP_IS_SOCKET (sock), SOUP_STATUS_MALFORMED);
Packit Service ca3877
	priv = soup_socket_get_instance_private (sock);
Packit Service ca3877
	g_return_val_if_fail (!priv->is_server, SOUP_STATUS_MALFORMED);
Packit Service ca3877
	g_return_val_if_fail (priv->gsock == NULL, SOUP_STATUS_MALFORMED);
Packit Service ca3877
	g_return_val_if_fail (priv->remote_addr != NULL, SOUP_STATUS_MALFORMED);
Packit Service ca3877
Packit Service ca3877
	if (soup_socket_connect_sync_internal (sock, cancellable, &error))
Packit Service ca3877
		return SOUP_STATUS_OK;
Packit Service ca3877
	else
Packit Service ca3877
		return socket_legacy_error (sock, error);
Packit Service ca3877
}
Packit Service ca3877
Packit Service ca3877
/**
Packit Service ca3877
 * soup_socket_get_fd:
Packit Service ca3877
 * @sock: a #SoupSocket
Packit Service ca3877
 *
Packit Service ca3877
 * Gets @sock's underlying file descriptor.
Packit Service ca3877
 *
Packit Service ca3877
 * Note that fiddling with the file descriptor may break the
Packit Service ca3877
 * #SoupSocket.
Packit Service ca3877
 *
Packit Service ca3877
 * Return value: @sock's file descriptor.
Packit Service ca3877
 */
Packit Service ca3877
int
Packit Service ca3877
soup_socket_get_fd (SoupSocket *sock)
Packit Service ca3877
{
Packit Service ca3877
	SoupSocketPrivate *priv;
Packit Service ca3877
Packit Service ca3877
	g_return_val_if_fail (SOUP_IS_SOCKET (sock), -1);
Packit Service ca3877
Packit Service ca3877
	priv = soup_socket_get_instance_private (sock);
Packit Service ca3877
Packit Service ca3877
	return g_socket_get_fd (priv->gsock);
Packit Service ca3877
}
Packit Service ca3877
Packit Service ca3877
GSocket *
Packit Service ca3877
soup_socket_get_gsocket (SoupSocket *sock)
Packit Service ca3877
{
Packit Service ca3877
	SoupSocketPrivate *priv;
Packit Service ca3877
Packit Service ca3877
	g_return_val_if_fail (SOUP_IS_SOCKET (sock), NULL);
Packit Service ca3877
Packit Service ca3877
	priv = soup_socket_get_instance_private (sock);
Packit Service ca3877
Packit Service ca3877
	return priv->gsock;
Packit Service ca3877
}
Packit Service ca3877
Packit Service ca3877
GSocket *
Packit Service ca3877
soup_socket_steal_gsocket (SoupSocket *sock)
Packit Service ca3877
{
Packit Service ca3877
	SoupSocketPrivate *priv;
Packit Service ca3877
	GSocket *gsock;
Packit Service ca3877
Packit Service ca3877
	g_return_val_if_fail (SOUP_IS_SOCKET (sock), NULL);
Packit Service ca3877
	priv = soup_socket_get_instance_private (sock);
Packit Service ca3877
Packit Service ca3877
	gsock = priv->gsock;
Packit Service ca3877
	priv->gsock = NULL;
Packit Service ca3877
	g_clear_object (&priv->conn);
Packit Service ca3877
	g_clear_object (&priv->iostream);
Packit Service ca3877
Packit Service ca3877
	return gsock;
Packit Service ca3877
}
Packit Service ca3877
Packit Service ca3877
gboolean
Packit Service ca3877
soup_socket_is_readable (SoupSocket *sock)
Packit Service ca3877
{
Packit Service ca3877
	SoupSocketPrivate *priv;
Packit Service ca3877
Packit Service ca3877
	g_return_val_if_fail (SOUP_IS_SOCKET (sock), FALSE);
Packit Service ca3877
	priv = soup_socket_get_instance_private (sock);
Packit Service ca3877
Packit Service ca3877
	return g_pollable_input_stream_is_readable (G_POLLABLE_INPUT_STREAM (priv->istream));
Packit Service ca3877
}
Packit Service ca3877
Packit Service ca3877
GIOStream *
Packit Service ca3877
soup_socket_get_connection (SoupSocket *sock)
Packit Service ca3877
{
Packit Service ca3877
	SoupSocketPrivate *priv;
Packit Service ca3877
Packit Service ca3877
	g_return_val_if_fail (SOUP_IS_SOCKET (sock), NULL);
Packit Service ca3877
Packit Service ca3877
	priv = soup_socket_get_instance_private (sock);
Packit Service ca3877
Packit Service ca3877
	return priv->conn;
Packit Service ca3877
}
Packit Service ca3877
Packit Service ca3877
GIOStream *
Packit Service ca3877
soup_socket_get_iostream (SoupSocket *sock)
Packit Service ca3877
{
Packit Service ca3877
	SoupSocketPrivate *priv;
Packit Service ca3877
Packit Service ca3877
	g_return_val_if_fail (SOUP_IS_SOCKET (sock), NULL);
Packit Service ca3877
Packit Service ca3877
	priv = soup_socket_get_instance_private (sock);
Packit Service ca3877
Packit Service ca3877
	return priv->iostream;
Packit Service ca3877
}
Packit Service ca3877
Packit Service ca3877
static GSource *
Packit Service ca3877
soup_socket_create_watch (SoupSocketPrivate *priv, GIOCondition cond,
Packit Service ca3877
			  GPollableSourceFunc callback, gpointer user_data,
Packit Service ca3877
			  GCancellable *cancellable)
Packit Service ca3877
{
Packit Service ca3877
	GSource *watch;
Packit Service ca3877
Packit Service ca3877
	if (cond == G_IO_IN)
Packit Service ca3877
		watch = g_pollable_input_stream_create_source (G_POLLABLE_INPUT_STREAM (priv->istream), cancellable);
Packit Service ca3877
	else
Packit Service ca3877
		watch = g_pollable_output_stream_create_source (G_POLLABLE_OUTPUT_STREAM (priv->ostream), cancellable);
Packit Service ca3877
	g_source_set_callback (watch, (GSourceFunc)callback, user_data, NULL);
Packit Service ca3877
Packit Service ca3877
	g_source_attach (watch, priv->async_context);
Packit Service ca3877
	g_source_unref (watch);
Packit Service ca3877
Packit Service ca3877
	return watch;
Packit Service ca3877
}
Packit Service ca3877
Packit Service ca3877
static gboolean
Packit Service ca3877
listen_watch (GObject *pollable, gpointer data)
Packit Service ca3877
{
Packit Service ca3877
	SoupSocket *sock = data, *new;
Packit Service ca3877
	SoupSocketPrivate *priv = soup_socket_get_instance_private (sock), *new_priv;
Packit Service ca3877
	GSocket *new_gsock;
Packit Service ca3877
Packit Service ca3877
	new_gsock = g_socket_accept (priv->gsock, NULL, NULL);
Packit Service ca3877
	if (!new_gsock)
Packit Service ca3877
		return FALSE;
Packit Service ca3877
Packit Service ca3877
	new = g_object_new (SOUP_TYPE_SOCKET, NULL);
Packit Service ca3877
	new_priv = soup_socket_get_instance_private (new);
Packit Service ca3877
	new_priv->gsock = new_gsock;
Packit Service ca3877
	if (priv->async_context)
Packit Service ca3877
		new_priv->async_context = g_main_context_ref (priv->async_context);
Packit Service ca3877
	new_priv->use_thread_context = priv->use_thread_context;
Packit Service ca3877
	new_priv->non_blocking = priv->non_blocking;
Packit Service ca3877
	new_priv->clean_dispose = priv->clean_dispose;
Packit Service ca3877
	new_priv->is_server = TRUE;
Packit Service ca3877
	new_priv->ssl = priv->ssl;
Packit Service ca3877
	if (priv->ssl_creds)
Packit Service ca3877
		new_priv->ssl_creds = g_object_ref (priv->ssl_creds);
Packit Service ca3877
	finish_socket_setup (new);
Packit Service ca3877
Packit Service ca3877
	if (new_priv->ssl_creds) {
Packit Service ca3877
		if (!soup_socket_start_proxy_ssl (new, NULL, NULL)) {
Packit Service ca3877
			g_object_unref (new);
Packit Service ca3877
			return TRUE;
Packit Service ca3877
		}
Packit Service ca3877
	}
Packit Service ca3877
Packit Service ca3877
	g_signal_emit (sock, signals[NEW_CONNECTION], 0, new);
Packit Service ca3877
	g_object_unref (new);
Packit Service ca3877
Packit Service ca3877
	return TRUE;
Packit Service ca3877
}
Packit Service ca3877
Packit Service ca3877
static void
Packit Service ca3877
finish_listener_setup (SoupSocket *sock)
Packit Service ca3877
{
Packit Service ca3877
	SoupSocketPrivate *priv = soup_socket_get_instance_private (sock);
Packit Service ca3877
Packit Service ca3877
	priv->is_server = TRUE;
Packit Service ca3877
	priv->watch_src = soup_socket_create_watch (priv, G_IO_IN,
Packit Service ca3877
						    listen_watch, sock,
Packit Service ca3877
						    NULL);
Packit Service ca3877
}
Packit Service ca3877
Packit Service ca3877
/**
Packit Service ca3877
 * soup_socket_listen:
Packit Service ca3877
 * @sock: a server #SoupSocket (which must not already be connected or
Packit Service ca3877
 * listening)
Packit Service ca3877
 *
Packit Service ca3877
 * Makes @sock start listening on its local address. When connections
Packit Service ca3877
 * come in, @sock will emit #SoupSocket::new_connection.
Packit Service ca3877
 *
Packit Service ca3877
 * Return value: whether or not @sock is now listening.
Packit Service ca3877
 **/
Packit Service ca3877
gboolean
Packit Service ca3877
soup_socket_listen (SoupSocket *sock)
Packit Service ca3877
{
Packit Service ca3877
	return soup_socket_listen_full (sock, NULL);
Packit Service ca3877
}
Packit Service ca3877
Packit Service ca3877
/**
Packit Service ca3877
 * soup_socket_listen_full:
Packit Service ca3877
 * @sock: a server #SoupSocket (which must not already be connected or listening)
Packit Service ca3877
 * @error: error pointer
Packit Service ca3877
 *
Packit Service ca3877
 * Makes @sock start listening on its local address. When connections
Packit Service ca3877
 * come in, @sock will emit #SoupSocket::new_connection.
Packit Service ca3877
 *
Packit Service ca3877
 * Return value: whether or not @sock is now listening.
Packit Service ca3877
 **/
Packit Service ca3877
gboolean
Packit Service ca3877
soup_socket_listen_full (SoupSocket *sock,
Packit Service ca3877
                         GError **error)
Packit Service ca3877
Packit Service ca3877
{
Packit Service ca3877
	SoupSocketPrivate *priv;
Packit Service ca3877
	GSocketAddress *addr;
Packit Service ca3877
Packit Service ca3877
	g_return_val_if_fail (SOUP_IS_SOCKET (sock), FALSE);
Packit Service ca3877
	priv = soup_socket_get_instance_private (sock);
Packit Service ca3877
	g_return_val_if_fail (priv->gsock == NULL, FALSE);
Packit Service ca3877
	g_return_val_if_fail (priv->local_addr != NULL, FALSE);
Packit Service ca3877
Packit Service ca3877
	/* @local_addr may have its port set to 0. So we intentionally
Packit Service ca3877
	 * don't store it in priv->local_addr, so that if the
Packit Service ca3877
	 * caller calls soup_socket_get_local_address() later, we'll
Packit Service ca3877
	 * have to make a new addr by calling getsockname(), which
Packit Service ca3877
	 * will have the right port number.
Packit Service ca3877
	 */
Packit Service ca3877
	addr = soup_address_get_gsockaddr (priv->local_addr);
Packit Service ca3877
	g_return_val_if_fail (addr != NULL, FALSE);
Packit Service ca3877
Packit Service ca3877
	priv->gsock = g_socket_new (g_socket_address_get_family (addr),
Packit Service ca3877
				    G_SOCKET_TYPE_STREAM,
Packit Service ca3877
				    G_SOCKET_PROTOCOL_DEFAULT,
Packit Service ca3877
				    error);
Packit Service ca3877
	if (!priv->gsock)
Packit Service ca3877
		goto cant_listen;
Packit Service ca3877
	finish_socket_setup (sock);
Packit Service ca3877
Packit Service ca3877
#if defined (IPPROTO_IPV6) && defined (IPV6_V6ONLY)
Packit Service ca3877
	if (priv->ipv6_only) {
Packit Service ca3877
		int fd, v6_only;
Packit Service ca3877
Packit Service ca3877
		fd = g_socket_get_fd (priv->gsock);
Packit Service ca3877
		v6_only = TRUE;
Packit Service ca3877
		setsockopt (fd, IPPROTO_IPV6, IPV6_V6ONLY,
Packit Service ca3877
			    &v6_only, sizeof (v6_only));
Packit Service ca3877
	}
Packit Service ca3877
#endif
Packit Service ca3877
Packit Service ca3877
	/* Bind */
Packit Service ca3877
	if (!g_socket_bind (priv->gsock, addr, TRUE, error))
Packit Service ca3877
		goto cant_listen;
Packit Service ca3877
	/* Force local_addr to be re-resolved now */
Packit Service ca3877
	g_object_unref (priv->local_addr);
Packit Service ca3877
	priv->local_addr = NULL;
Packit Service ca3877
Packit Service ca3877
	/* Listen */
Packit Service ca3877
	if (!g_socket_listen (priv->gsock, error))
Packit Service ca3877
		goto cant_listen;
Packit Service ca3877
	finish_listener_setup (sock);
Packit Service ca3877
Packit Service ca3877
	g_object_unref (addr);
Packit Service ca3877
	return TRUE;
Packit Service ca3877
Packit Service ca3877
 cant_listen:
Packit Service ca3877
	if (priv->conn)
Packit Service ca3877
		disconnect_internal (sock, TRUE);
Packit Service ca3877
	g_object_unref (addr);
Packit Service ca3877
Packit Service ca3877
	return FALSE;
Packit Service ca3877
}
Packit Service ca3877
Packit Service ca3877
static void
Packit Service ca3877
soup_socket_peer_certificate_changed (GObject *conn, GParamSpec *pspec,
Packit Service ca3877
				      gpointer sock)
Packit Service ca3877
{
Packit Service ca3877
	SoupSocketPrivate *priv = soup_socket_get_instance_private (sock);
Packit Service ca3877
Packit Service ca3877
	priv->tls_errors = g_tls_connection_get_peer_certificate_errors (G_TLS_CONNECTION (priv->conn));
Packit Service ca3877
Packit Service ca3877
	g_object_notify (sock, "tls-certificate");
Packit Service ca3877
	g_object_notify (sock, "tls-errors");
Packit Service ca3877
}
Packit Service ca3877
Packit Service ca3877
static gboolean
Packit Service ca3877
soup_socket_accept_certificate (GTlsConnection *conn, GTlsCertificate *cert,
Packit Service ca3877
				GTlsCertificateFlags errors, gpointer sock)
Packit Service ca3877
{
Packit Service ca3877
	return TRUE;
Packit Service ca3877
}
Packit Service ca3877
Packit Service ca3877
static gboolean
Packit Service ca3877
soup_socket_setup_ssl (SoupSocket    *sock,
Packit Service ca3877
		       const char    *ssl_host,
Packit Service ca3877
		       GCancellable  *cancellable,
Packit Service ca3877
		       GError       **error)
Packit Service ca3877
{
Packit Service ca3877
	SoupSocketPrivate *priv = soup_socket_get_instance_private (sock);
Packit Service ca3877
	GTlsBackend *backend = g_tls_backend_get_default ();
Packit Service ca3877
Packit Service ca3877
	if (G_IS_TLS_CONNECTION (priv->conn))
Packit Service ca3877
		return TRUE;
Packit Service ca3877
Packit Service ca3877
	if (g_cancellable_set_error_if_cancelled (cancellable, error))
Packit Service ca3877
		return FALSE;
Packit Service ca3877
Packit Service ca3877
	priv->ssl = TRUE;
Packit Service ca3877
Packit Service ca3877
	if (!priv->is_server) {
Packit Service ca3877
		GTlsClientConnection *conn;
Packit Service ca3877
		GSocketConnectable *identity;
Packit Service ca3877
Packit Service ca3877
		identity = g_network_address_new (ssl_host, 0);
Packit Service ca3877
		conn = g_initable_new (g_tls_backend_get_client_connection_type (backend),
Packit Service ca3877
				       cancellable, error,
Packit Service ca3877
				       "base-io-stream", priv->conn,
Packit Service ca3877
				       "server-identity", identity,
Packit Service ca3877
				       "database", priv->ssl_creds,
Packit Service ca3877
				       "require-close-notify", FALSE,
Packit Service ca3877
				       "use-ssl3", priv->ssl_fallback,
Packit Service ca3877
				       NULL);
Packit Service ca3877
		g_object_unref (identity);
Packit Service ca3877
Packit Service ca3877
		if (!conn)
Packit Service ca3877
			return FALSE;
Packit Service ca3877
Packit Service ca3877
		/* GLib < 2.41 mistakenly doesn't implement this property in the
Packit Service ca3877
		 * dummy TLS backend, so we don't include it in the g_initable_new()
Packit Service ca3877
		 * call above.
Packit Service ca3877
		 */
Packit Service ca3877
		g_object_set (G_OBJECT (conn),
Packit Service ca3877
			      "interaction", priv->tls_interaction,
Packit Service ca3877
			      NULL);
Packit Service ca3877
Packit Service ca3877
		g_object_unref (priv->conn);
Packit Service ca3877
		priv->conn = G_IO_STREAM (conn);
Packit Service ca3877
Packit Service ca3877
		if (!priv->ssl_strict) {
Packit Service ca3877
			g_signal_connect (conn, "accept-certificate",
Packit Service ca3877
					  G_CALLBACK (soup_socket_accept_certificate),
Packit Service ca3877
					  sock);
Packit Service ca3877
		}
Packit Service ca3877
	} else {
Packit Service ca3877
		GTlsServerConnection *conn;
Packit Service ca3877
Packit Service ca3877
		conn = g_initable_new (g_tls_backend_get_server_connection_type (backend),
Packit Service ca3877
				       cancellable, error,
Packit Service ca3877
				       "base-io-stream", priv->conn,
Packit Service ca3877
				       "certificate", priv->ssl_creds,
Packit Service ca3877
				       "use-system-certdb", FALSE,
Packit Service ca3877
				       "require-close-notify", FALSE,
Packit Service ca3877
				       NULL);
Packit Service ca3877
		if (!conn)
Packit Service ca3877
			return FALSE;
Packit Service ca3877
Packit Service ca3877
		g_object_unref (priv->conn);
Packit Service ca3877
		priv->conn = G_IO_STREAM (conn);
Packit Service ca3877
	}
Packit Service ca3877
Packit Service ca3877
	g_signal_connect (priv->conn, "notify::peer-certificate",
Packit Service ca3877
			  G_CALLBACK (soup_socket_peer_certificate_changed), sock);
Packit Service ca3877
Packit Service ca3877
	g_clear_object (&priv->istream);
Packit Service ca3877
	g_clear_object (&priv->ostream);
Packit Service ca3877
	g_clear_object (&priv->iostream);
Packit Service ca3877
	priv->iostream = soup_io_stream_new (priv->conn, FALSE);
Packit Service ca3877
	priv->istream = g_object_ref (g_io_stream_get_input_stream (priv->iostream));
Packit Service ca3877
	priv->ostream = g_object_ref (g_io_stream_get_output_stream (priv->iostream));
Packit Service ca3877
Packit Service ca3877
	return TRUE;
Packit Service ca3877
}
Packit Service ca3877
Packit Service ca3877
/**
Packit Service ca3877
 * soup_socket_start_ssl:
Packit Service ca3877
 * @sock: the socket
Packit Service ca3877
 * @cancellable: a #GCancellable
Packit Service ca3877
 *
Packit Service ca3877
 * Starts using SSL on @socket.
Packit Service ca3877
 *
Packit Service ca3877
 * Return value: success or failure
Packit Service ca3877
 **/
Packit Service ca3877
gboolean
Packit Service ca3877
soup_socket_start_ssl (SoupSocket *sock, GCancellable *cancellable)
Packit Service ca3877
{
Packit Service ca3877
	SoupSocketPrivate *priv = soup_socket_get_instance_private (sock);
Packit Service ca3877
Packit Service ca3877
	return soup_socket_setup_ssl (sock, soup_address_get_name (priv->remote_addr),
Packit Service ca3877
				      cancellable, NULL);
Packit Service ca3877
}
Packit Service ca3877
Packit Service ca3877
/**
Packit Service ca3877
 * soup_socket_start_proxy_ssl:
Packit Service ca3877
 * @sock: the socket
Packit Service ca3877
 * @ssl_host: hostname of the SSL server
Packit Service ca3877
 * @cancellable: a #GCancellable
Packit Service ca3877
 *
Packit Service ca3877
 * Starts using SSL on @socket, expecting to find a host named
Packit Service ca3877
 * @ssl_host.
Packit Service ca3877
 *
Packit Service ca3877
 * Return value: success or failure
Packit Service ca3877
 **/
Packit Service ca3877
gboolean
Packit Service ca3877
soup_socket_start_proxy_ssl (SoupSocket *sock, const char *ssl_host,
Packit Service ca3877
			     GCancellable *cancellable)
Packit Service ca3877
{
Packit Service ca3877
	return soup_socket_setup_ssl (sock, ssl_host, cancellable, NULL);
Packit Service ca3877
}
Packit Service ca3877
Packit Service ca3877
gboolean
Packit Service ca3877
soup_socket_handshake_sync (SoupSocket    *sock,
Packit Service ca3877
			    const char    *ssl_host,
Packit Service ca3877
			    GCancellable  *cancellable,
Packit Service ca3877
			    GError       **error)
Packit Service ca3877
{
Packit Service ca3877
	SoupSocketPrivate *priv = soup_socket_get_instance_private (sock);
Packit Service ca3877
Packit Service ca3877
	if (!soup_socket_setup_ssl (sock, ssl_host, cancellable, error))
Packit Service ca3877
		return FALSE;
Packit Service ca3877
Packit Service ca3877
	soup_socket_event (sock, G_SOCKET_CLIENT_TLS_HANDSHAKING, priv->conn);
Packit Service ca3877
Packit Service ca3877
	if (!g_tls_connection_handshake (G_TLS_CONNECTION (priv->conn),
Packit Service ca3877
					 cancellable, error))
Packit Service ca3877
		return FALSE;
Packit Service ca3877
Packit Service ca3877
	soup_socket_event (sock, G_SOCKET_CLIENT_TLS_HANDSHAKED, priv->conn);
Packit Service ca3877
	return TRUE;
Packit Service ca3877
}
Packit Service ca3877
Packit Service ca3877
static void
Packit Service ca3877
handshake_async_ready (GObject *source, GAsyncResult *result, gpointer user_data)
Packit Service ca3877
{
Packit Service ca3877
	GTask *task = user_data;
Packit Service ca3877
	GError *error = NULL;
Packit Service ca3877
Packit Service ca3877
	if (g_tls_connection_handshake_finish (G_TLS_CONNECTION (source),
Packit Service ca3877
					       result, &error)) {
Packit Service ca3877
		SoupSocket *sock = g_task_get_source_object (task);
Packit Service ca3877
		SoupSocketPrivate *priv = soup_socket_get_instance_private (sock);
Packit Service ca3877
Packit Service ca3877
		soup_socket_event (sock, G_SOCKET_CLIENT_TLS_HANDSHAKED, priv->conn);
Packit Service ca3877
		g_task_return_boolean (task, TRUE);
Packit Service ca3877
	} else
Packit Service ca3877
		g_task_return_error (task, error);
Packit Service ca3877
	g_object_unref (task);
Packit Service ca3877
}
Packit Service ca3877
Packit Service ca3877
void
Packit Service ca3877
soup_socket_handshake_async (SoupSocket          *sock,
Packit Service ca3877
			     const char          *ssl_host,
Packit Service ca3877
			     GCancellable        *cancellable,
Packit Service ca3877
			     GAsyncReadyCallback  callback,
Packit Service ca3877
			     gpointer             user_data)
Packit Service ca3877
{
Packit Service ca3877
	SoupSocketPrivate *priv = soup_socket_get_instance_private (sock);
Packit Service ca3877
	GTask *task;
Packit Service ca3877
	GError *error = NULL;
Packit Service ca3877
Packit Service ca3877
	task = g_task_new (sock, cancellable, callback, user_data);
Packit Service ca3877
Packit Service ca3877
	if (!soup_socket_setup_ssl (sock, ssl_host, cancellable, &error)) {
Packit Service ca3877
		g_task_return_error (task, error);
Packit Service ca3877
		g_object_unref (task);
Packit Service ca3877
		return;
Packit Service ca3877
	}
Packit Service ca3877
Packit Service ca3877
	soup_socket_event (sock, G_SOCKET_CLIENT_TLS_HANDSHAKING, priv->conn);
Packit Service ca3877
Packit Service ca3877
	g_tls_connection_handshake_async (G_TLS_CONNECTION (priv->conn),
Packit Service ca3877
					  G_PRIORITY_DEFAULT,
Packit Service ca3877
					  cancellable, handshake_async_ready,
Packit Service ca3877
					  task);
Packit Service ca3877
}
Packit Service ca3877
Packit Service ca3877
gboolean
Packit Service ca3877
soup_socket_handshake_finish (SoupSocket    *sock,
Packit Service ca3877
			      GAsyncResult  *result,
Packit Service ca3877
			      GError       **error)
Packit Service ca3877
{
Packit Service ca3877
	return g_task_propagate_boolean (G_TASK (result), error);
Packit Service ca3877
}
Packit Service ca3877
Packit Service ca3877
/**
Packit Service ca3877
 * soup_socket_is_ssl:
Packit Service ca3877
 * @sock: a #SoupSocket
Packit Service ca3877
 *
Packit Service ca3877
 * Tests if @sock is doing (or has attempted to do) SSL.
Packit Service ca3877
 *
Packit Service ca3877
 * Return value: %TRUE if @sock has SSL credentials set
Packit Service ca3877
 **/
Packit Service ca3877
gboolean
Packit Service ca3877
soup_socket_is_ssl (SoupSocket *sock)
Packit Service ca3877
{
Packit Service ca3877
	SoupSocketPrivate *priv = soup_socket_get_instance_private (sock);
Packit Service ca3877
Packit Service ca3877
	return priv->ssl;
Packit Service ca3877
}
Packit Service ca3877
Packit Service ca3877
/**
Packit Service ca3877
 * soup_socket_disconnect:
Packit Service ca3877
 * @sock: a #SoupSocket
Packit Service ca3877
 *
Packit Service ca3877
 * Disconnects @sock. Any further read or write attempts on it will
Packit Service ca3877
 * fail.
Packit Service ca3877
 **/
Packit Service ca3877
void
Packit Service ca3877
soup_socket_disconnect (SoupSocket *sock)
Packit Service ca3877
{
Packit Service ca3877
	SoupSocketPrivate *priv;
Packit Service ca3877
	gboolean already_disconnected = FALSE;
Packit Service ca3877
Packit Service ca3877
	g_return_if_fail (SOUP_IS_SOCKET (sock));
Packit Service ca3877
	priv = soup_socket_get_instance_private (sock);
Packit Service ca3877
Packit Service ca3877
	if (priv->connect_cancel) {
Packit Service ca3877
		disconnect_internal (sock, FALSE);
Packit Service ca3877
		g_cancellable_cancel (priv->connect_cancel);
Packit Service ca3877
		return;
Packit Service ca3877
	} else if (g_mutex_trylock (&priv->iolock)) {
Packit Service ca3877
		if (priv->conn)
Packit Service ca3877
			disconnect_internal (sock, TRUE);
Packit Service ca3877
		else
Packit Service ca3877
			already_disconnected = TRUE;
Packit Service ca3877
		g_mutex_unlock (&priv->iolock);
Packit Service ca3877
	} else {
Packit Service ca3877
		/* Another thread is currently doing IO, so
Packit Service ca3877
		 * we can't close the socket. So just shutdown
Packit Service ca3877
		 * the file descriptor to force the I/O to fail.
Packit Service ca3877
		 * (It will actually be closed when the socket
Packit Service ca3877
		 * is destroyed.)
Packit Service ca3877
		 */
Packit Service ca3877
		g_socket_shutdown (priv->gsock, TRUE, TRUE, NULL);
Packit Service ca3877
	}
Packit Service ca3877
Packit Service ca3877
	if (already_disconnected)
Packit Service ca3877
		return;
Packit Service ca3877
Packit Service ca3877
	/* Keep ref around signals in case the object is unreferenced
Packit Service ca3877
	 * in a handler
Packit Service ca3877
	 */
Packit Service ca3877
	g_object_ref (sock);
Packit Service ca3877
Packit Service ca3877
	if (priv->non_blocking) {
Packit Service ca3877
		/* Give all readers a chance to notice the connection close */
Packit Service ca3877
		g_signal_emit (sock, signals[READABLE], 0);
Packit Service ca3877
	}
Packit Service ca3877
Packit Service ca3877
	/* FIXME: can't disconnect until all data is read */
Packit Service ca3877
Packit Service ca3877
	/* Then let everyone know we're disconnected */
Packit Service ca3877
	g_signal_emit (sock, signals[DISCONNECTED], 0);
Packit Service ca3877
Packit Service ca3877
	g_object_unref (sock);
Packit Service ca3877
}
Packit Service ca3877
Packit Service ca3877
/**
Packit Service ca3877
 * soup_socket_is_connected:
Packit Service ca3877
 * @sock: a #SoupSocket
Packit Service ca3877
 *
Packit Service ca3877
 * Tests if @sock is connected to another host
Packit Service ca3877
 *
Packit Service ca3877
 * Return value: %TRUE or %FALSE.
Packit Service ca3877
 **/
Packit Service ca3877
gboolean
Packit Service ca3877
soup_socket_is_connected (SoupSocket *sock)
Packit Service ca3877
{
Packit Service ca3877
	SoupSocketPrivate *priv;
Packit Service ca3877
Packit Service ca3877
	g_return_val_if_fail (SOUP_IS_SOCKET (sock), FALSE);
Packit Service ca3877
	priv = soup_socket_get_instance_private (sock);
Packit Service ca3877
Packit Service ca3877
	return priv->conn && !g_io_stream_is_closed (priv->conn);
Packit Service ca3877
}
Packit Service ca3877
Packit Service ca3877
/**
Packit Service ca3877
 * soup_socket_get_local_address:
Packit Service ca3877
 * @sock: a #SoupSocket
Packit Service ca3877
 *
Packit Service ca3877
 * Returns the #SoupAddress corresponding to the local end of @sock.
Packit Service ca3877
 *
Packit Service ca3877
 * Calling this method on an unconnected socket is considered to be
Packit Service ca3877
 * an error, and produces undefined results.
Packit Service ca3877
 *
Packit Service ca3877
 * Return value: (transfer none): the #SoupAddress
Packit Service ca3877
 **/
Packit Service ca3877
SoupAddress *
Packit Service ca3877
soup_socket_get_local_address (SoupSocket *sock)
Packit Service ca3877
{
Packit Service ca3877
	SoupSocketPrivate *priv;
Packit Service ca3877
Packit Service ca3877
	g_return_val_if_fail (SOUP_IS_SOCKET (sock), NULL);
Packit Service ca3877
	priv = soup_socket_get_instance_private (sock);
Packit Service ca3877
Packit Service ca3877
	g_mutex_lock (&priv->addrlock);
Packit Service ca3877
	if (!priv->local_addr) {
Packit Service ca3877
		GSocketAddress *addr;
Packit Service ca3877
		struct sockaddr_storage sa;
Packit Service ca3877
		gssize sa_len;
Packit Service ca3877
		GError *error = NULL;
Packit Service ca3877
Packit Service ca3877
		if (priv->gsock == NULL) {
Packit Service ca3877
			g_warning ("%s: socket not connected", G_STRLOC);
Packit Service ca3877
			goto unlock;
Packit Service ca3877
		}
Packit Service ca3877
Packit Service ca3877
		addr = g_socket_get_local_address (priv->gsock, &error);
Packit Service ca3877
		if (addr == NULL) {
Packit Service ca3877
			g_warning ("%s: %s", G_STRLOC, error->message);
Packit Service ca3877
			g_error_free (error);
Packit Service ca3877
			goto unlock;
Packit Service ca3877
		}
Packit Service ca3877
		sa_len = g_socket_address_get_native_size (addr);
Packit Service ca3877
		g_socket_address_to_native (addr, &sa, sa_len, NULL);
Packit Service ca3877
		priv->local_addr = soup_address_new_from_sockaddr ((struct sockaddr *)&sa, sa_len);
Packit Service ca3877
		g_object_unref (addr);
Packit Service ca3877
	}
Packit Service ca3877
unlock:
Packit Service ca3877
	g_mutex_unlock (&priv->addrlock);
Packit Service ca3877
Packit Service ca3877
	return priv->local_addr;
Packit Service ca3877
}
Packit Service ca3877
Packit Service ca3877
/**
Packit Service ca3877
 * soup_socket_get_remote_address:
Packit Service ca3877
 * @sock: a #SoupSocket
Packit Service ca3877
 *
Packit Service ca3877
 * Returns the #SoupAddress corresponding to the remote end of @sock.
Packit Service ca3877
 *
Packit Service ca3877
 * Calling this method on an unconnected socket is considered to be
Packit Service ca3877
 * an error, and produces undefined results.
Packit Service ca3877
 *
Packit Service ca3877
 * Return value: (transfer none): the #SoupAddress
Packit Service ca3877
 **/
Packit Service ca3877
SoupAddress *
Packit Service ca3877
soup_socket_get_remote_address (SoupSocket *sock)
Packit Service ca3877
{
Packit Service ca3877
	SoupSocketPrivate *priv;
Packit Service ca3877
Packit Service ca3877
	g_return_val_if_fail (SOUP_IS_SOCKET (sock), NULL);
Packit Service ca3877
	priv = soup_socket_get_instance_private (sock);
Packit Service ca3877
Packit Service ca3877
	g_mutex_lock (&priv->addrlock);
Packit Service ca3877
	if (!priv->remote_addr) {
Packit Service ca3877
		GSocketAddress *addr;
Packit Service ca3877
		struct sockaddr_storage sa;
Packit Service ca3877
		gssize sa_len;
Packit Service ca3877
		GError *error = NULL;
Packit Service ca3877
Packit Service ca3877
		if (priv->gsock == NULL) {
Packit Service ca3877
			g_warning ("%s: socket not connected", G_STRLOC);
Packit Service ca3877
			goto unlock;
Packit Service ca3877
		}
Packit Service ca3877
Packit Service ca3877
		addr = g_socket_get_remote_address (priv->gsock, &error);
Packit Service ca3877
		if (addr == NULL) {
Packit Service ca3877
			g_warning ("%s: %s", G_STRLOC, error->message);
Packit Service ca3877
			g_error_free (error);
Packit Service ca3877
			goto unlock;
Packit Service ca3877
		}
Packit Service ca3877
		sa_len = g_socket_address_get_native_size (addr);
Packit Service ca3877
		g_socket_address_to_native (addr, &sa, sa_len, NULL);
Packit Service ca3877
		priv->remote_addr = soup_address_new_from_sockaddr ((struct sockaddr *)&sa, sa_len);
Packit Service ca3877
		g_object_unref (addr);
Packit Service ca3877
	}
Packit Service ca3877
unlock:
Packit Service ca3877
	g_mutex_unlock (&priv->addrlock);
Packit Service ca3877
Packit Service ca3877
	return priv->remote_addr;
Packit Service ca3877
}
Packit Service ca3877
Packit Service ca3877
SoupURI *
Packit Service ca3877
soup_socket_get_http_proxy_uri (SoupSocket *sock)
Packit Service ca3877
{
Packit Service ca3877
	SoupSocketPrivate *priv = soup_socket_get_instance_private (sock);
Packit Service ca3877
	GSocketAddress *addr;
Packit Service ca3877
	GProxyAddress *paddr;
Packit Service ca3877
	SoupURI *uri;
Packit Service ca3877
Packit Service ca3877
	if (!priv->gsock)
Packit Service ca3877
		return NULL;
Packit Service ca3877
	addr = g_socket_get_remote_address (priv->gsock, NULL);
Packit Service ca3877
	if (!addr || !G_IS_PROXY_ADDRESS (addr)) {
Packit Service ca3877
		if (addr)
Packit Service ca3877
			g_object_unref (addr);
Packit Service ca3877
		return NULL;
Packit Service ca3877
	}
Packit Service ca3877
Packit Service ca3877
	paddr = G_PROXY_ADDRESS (addr);
Packit Service ca3877
	if (strcmp (g_proxy_address_get_protocol (paddr), "http") != 0)
Packit Service ca3877
		return NULL;
Packit Service ca3877
Packit Service ca3877
	uri = soup_uri_new (g_proxy_address_get_uri (paddr));
Packit Service ca3877
	g_object_unref (addr);
Packit Service ca3877
	return uri;
Packit Service ca3877
}
Packit Service ca3877
Packit Service ca3877
static gboolean
Packit Service ca3877
socket_read_watch (GObject *pollable, gpointer user_data)
Packit Service ca3877
{
Packit Service ca3877
	SoupSocket *sock = user_data;
Packit Service ca3877
	SoupSocketPrivate *priv = soup_socket_get_instance_private (sock);
Packit Service ca3877
Packit Service ca3877
	priv->read_src = NULL;
Packit Service ca3877
	g_signal_emit (sock, signals[READABLE], 0);
Packit Service ca3877
	return FALSE;
Packit Service ca3877
}
Packit Service ca3877
Packit Service ca3877
static SoupSocketIOStatus
Packit Service ca3877
translate_read_status (SoupSocket *sock, GCancellable *cancellable,
Packit Service ca3877
		       gssize my_nread, gsize *nread,
Packit Service ca3877
		       GError *my_err, GError **error)
Packit Service ca3877
{
Packit Service ca3877
	SoupSocketPrivate *priv = soup_socket_get_instance_private (sock);
Packit Service ca3877
Packit Service ca3877
	if (my_nread > 0) {
Packit Service ca3877
		g_assert_no_error (my_err);
Packit Service ca3877
		*nread = my_nread;
Packit Service ca3877
		return SOUP_SOCKET_OK;
Packit Service ca3877
	} else if (my_nread == 0) {
Packit Service ca3877
		g_assert_no_error (my_err);
Packit Service ca3877
		*nread = my_nread;
Packit Service ca3877
		return SOUP_SOCKET_EOF;
Packit Service ca3877
	} else if (g_error_matches (my_err, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) {
Packit Service ca3877
		g_clear_error (&my_err);
Packit Service ca3877
		if (!priv->read_src) {
Packit Service ca3877
			priv->read_src =
Packit Service ca3877
				soup_socket_create_watch (priv, G_IO_IN,
Packit Service ca3877
							  socket_read_watch, sock,
Packit Service ca3877
							  cancellable);
Packit Service ca3877
		}
Packit Service ca3877
		return SOUP_SOCKET_WOULD_BLOCK;
Packit Service ca3877
	}
Packit Service ca3877
Packit Service ca3877
	g_propagate_error (error, my_err);
Packit Service ca3877
	return SOUP_SOCKET_ERROR;
Packit Service ca3877
}
Packit Service ca3877
Packit Service ca3877
/**
Packit Service ca3877
 * SoupSocketIOStatus:
Packit Service ca3877
 * @SOUP_SOCKET_OK: Success
Packit Service ca3877
 * @SOUP_SOCKET_WOULD_BLOCK: Cannot read/write any more at this time
Packit Service ca3877
 * @SOUP_SOCKET_EOF: End of file
Packit Service ca3877
 * @SOUP_SOCKET_ERROR: Other error
Packit Service ca3877
 *
Packit Service ca3877
 * Return value from the #SoupSocket IO methods.
Packit Service ca3877
 **/
Packit Service ca3877
Packit Service ca3877
/**
Packit Service ca3877
 * soup_socket_read:
Packit Service ca3877
 * @sock: the socket
Packit Service ca3877
 * @buffer: (array length=len) (element-type guint8): buffer to read
Packit Service ca3877
 *   into
Packit Service ca3877
 * @len: size of @buffer in bytes
Packit Service ca3877
 * @nread: (out): on return, the number of bytes read into @buffer
Packit Service ca3877
 * @cancellable: a #GCancellable, or %NULL
Packit Service ca3877
 * @error: error pointer
Packit Service ca3877
 *
Packit Service ca3877
 * Attempts to read up to @len bytes from @sock into @buffer. If some
Packit Service ca3877
 * data is successfully read, soup_socket_read() will return
Packit Service ca3877
 * %SOUP_SOCKET_OK, and *@nread will contain the number of bytes
Packit Service ca3877
 * actually read (which may be less than @len).
Packit Service ca3877
 *
Packit Service ca3877
 * If @sock is non-blocking, and no data is available, the return
Packit Service ca3877
 * value will be %SOUP_SOCKET_WOULD_BLOCK. In this case, the caller
Packit Service ca3877
 * can connect to the #SoupSocket::readable signal to know when there
Packit Service ca3877
 * is more data to read. (NB: You MUST read all available data off the
Packit Service ca3877
 * socket first. #SoupSocket::readable is only emitted after
Packit Service ca3877
 * soup_socket_read() returns %SOUP_SOCKET_WOULD_BLOCK, and it is only
Packit Service ca3877
 * emitted once. See the documentation for #SoupSocket:non-blocking.)
Packit Service ca3877
 *
Packit Service ca3877
 * Return value: a #SoupSocketIOStatus, as described above (or
Packit Service ca3877
 * %SOUP_SOCKET_EOF if the socket is no longer connected, or
Packit Service ca3877
 * %SOUP_SOCKET_ERROR on any other error, in which case @error will
Packit Service ca3877
 * also be set).
Packit Service ca3877
 **/
Packit Service ca3877
SoupSocketIOStatus
Packit Service ca3877
soup_socket_read (SoupSocket *sock, gpointer buffer, gsize len,
Packit Service ca3877
		  gsize *nread, GCancellable *cancellable, GError **error)
Packit Service ca3877
{
Packit Service ca3877
	SoupSocketPrivate *priv;
Packit Service ca3877
	SoupSocketIOStatus status;
Packit Service ca3877
	gssize my_nread;
Packit Service ca3877
	GError *my_err = NULL;
Packit Service ca3877
Packit Service ca3877
	g_return_val_if_fail (SOUP_IS_SOCKET (sock), SOUP_SOCKET_ERROR);
Packit Service ca3877
	g_return_val_if_fail (nread != NULL, SOUP_SOCKET_ERROR);
Packit Service ca3877
Packit Service ca3877
	priv = soup_socket_get_instance_private (sock);
Packit Service ca3877
Packit Service ca3877
	g_mutex_lock (&priv->iolock);
Packit Service ca3877
Packit Service ca3877
	if (!priv->istream) {
Packit Service ca3877
		status = SOUP_SOCKET_EOF;
Packit Service ca3877
		goto out;
Packit Service ca3877
	}
Packit Service ca3877
Packit Service ca3877
	if (!priv->non_blocking) {
Packit Service ca3877
		my_nread = g_input_stream_read (priv->istream, buffer, len,
Packit Service ca3877
						cancellable, &my_err);
Packit Service ca3877
	} else {
Packit Service ca3877
		my_nread = g_pollable_input_stream_read_nonblocking (G_POLLABLE_INPUT_STREAM (priv->istream),
Packit Service ca3877
								     buffer, len,
Packit Service ca3877
								     cancellable, &my_err);
Packit Service ca3877
	}
Packit Service ca3877
	status = translate_read_status (sock, cancellable,
Packit Service ca3877
					my_nread, nread, my_err, error);
Packit Service ca3877
Packit Service ca3877
out:
Packit Service ca3877
	g_mutex_unlock (&priv->iolock);
Packit Service ca3877
Packit Service ca3877
	return status;
Packit Service ca3877
}
Packit Service ca3877
Packit Service ca3877
/**
Packit Service ca3877
 * soup_socket_read_until:
Packit Service ca3877
 * @sock: the socket
Packit Service ca3877
 * @buffer: (array length=len) (element-type guint8): buffer to read
Packit Service ca3877
 *   into
Packit Service ca3877
 * @len: size of @buffer in bytes
Packit Service ca3877
 * @boundary: boundary to read until
Packit Service ca3877
 * @boundary_len: length of @boundary in bytes
Packit Service ca3877
 * @nread: (out): on return, the number of bytes read into @buffer
Packit Service ca3877
 * @got_boundary: on return, whether or not the data in @buffer
Packit Service ca3877
 * ends with the boundary string
Packit Service ca3877
 * @cancellable: a #GCancellable, or %NULL
Packit Service ca3877
 * @error: error pointer
Packit Service ca3877
 *
Packit Service ca3877
 * Like soup_socket_read(), but reads no further than the first
Packit Service ca3877
 * occurrence of @boundary. (If the boundary is found, it will be
Packit Service ca3877
 * included in the returned data, and *@got_boundary will be set to
Packit Service ca3877
 * %TRUE.) Any data after the boundary will returned in future reads.
Packit Service ca3877
 *
Packit Service ca3877
 * soup_socket_read_until() will almost always return fewer than @len
Packit Service ca3877
 * bytes: if the boundary is found, then it will only return the bytes
Packit Service ca3877
 * up until the end of the boundary, and if the boundary is not found,
Packit Service ca3877
 * then it will leave the last <literal>(boundary_len - 1)</literal>
Packit Service ca3877
 * bytes in its internal buffer, in case they form the start of the
Packit Service ca3877
 * boundary string. Thus, @len normally needs to be at least 1 byte
Packit Service ca3877
 * longer than @boundary_len if you want to make any progress at all.
Packit Service ca3877
 *
Packit Service ca3877
 * Return value: as for soup_socket_read()
Packit Service ca3877
 **/
Packit Service ca3877
SoupSocketIOStatus
Packit Service ca3877
soup_socket_read_until (SoupSocket *sock, gpointer buffer, gsize len,
Packit Service ca3877
			gconstpointer boundary, gsize boundary_len,
Packit Service ca3877
			gsize *nread, gboolean *got_boundary,
Packit Service ca3877
			GCancellable *cancellable, GError **error)
Packit Service ca3877
{
Packit Service ca3877
	SoupSocketPrivate *priv;
Packit Service ca3877
	SoupSocketIOStatus status;
Packit Service ca3877
	gssize my_nread;
Packit Service ca3877
	GError *my_err = NULL;
Packit Service ca3877
Packit Service ca3877
	g_return_val_if_fail (SOUP_IS_SOCKET (sock), SOUP_SOCKET_ERROR);
Packit Service ca3877
	g_return_val_if_fail (nread != NULL, SOUP_SOCKET_ERROR);
Packit Service ca3877
	g_return_val_if_fail (len >= boundary_len, SOUP_SOCKET_ERROR);
Packit Service ca3877
Packit Service ca3877
	priv = soup_socket_get_instance_private (sock);
Packit Service ca3877
Packit Service ca3877
	g_mutex_lock (&priv->iolock);
Packit Service ca3877
Packit Service ca3877
	*got_boundary = FALSE;
Packit Service ca3877
Packit Service ca3877
	if (!priv->istream)
Packit Service ca3877
		status = SOUP_SOCKET_EOF;
Packit Service ca3877
	else {
Packit Service ca3877
		my_nread = soup_filter_input_stream_read_until (
Packit Service ca3877
			SOUP_FILTER_INPUT_STREAM (priv->istream),
Packit Service ca3877
			buffer, len, boundary, boundary_len,
Packit Service ca3877
			!priv->non_blocking,
Packit Service ca3877
			TRUE, got_boundary, cancellable, &my_err);
Packit Service ca3877
		status = translate_read_status (sock, cancellable,
Packit Service ca3877
						my_nread, nread, my_err, error);
Packit Service ca3877
	}
Packit Service ca3877
Packit Service ca3877
	g_mutex_unlock (&priv->iolock);
Packit Service ca3877
	return status;
Packit Service ca3877
}
Packit Service ca3877
Packit Service ca3877
static gboolean
Packit Service ca3877
socket_write_watch (GObject *pollable, gpointer user_data)
Packit Service ca3877
{
Packit Service ca3877
	SoupSocket *sock = user_data;
Packit Service ca3877
	SoupSocketPrivate *priv = soup_socket_get_instance_private (sock);
Packit Service ca3877
Packit Service ca3877
	priv->write_src = NULL;
Packit Service ca3877
	g_signal_emit (sock, signals[WRITABLE], 0);
Packit Service ca3877
	return FALSE;
Packit Service ca3877
}
Packit Service ca3877
Packit Service ca3877
/**
Packit Service ca3877
 * soup_socket_write:
Packit Service ca3877
 * @sock: the socket
Packit Service ca3877
 * @buffer: (array length=len) (element-type guint8): data to write
Packit Service ca3877
 * @len: size of @buffer, in bytes
Packit Service ca3877
 * @nwrote: (out): on return, number of bytes written
Packit Service ca3877
 * @cancellable: a #GCancellable, or %NULL
Packit Service ca3877
 * @error: error pointer
Packit Service ca3877
 *
Packit Service ca3877
 * Attempts to write @len bytes from @buffer to @sock. If some data is
Packit Service ca3877
 * successfully written, the return status will be %SOUP_SOCKET_OK,
Packit Service ca3877
 * and *@nwrote will contain the number of bytes actually written
Packit Service ca3877
 * (which may be less than @len).
Packit Service ca3877
 *
Packit Service ca3877
 * If @sock is non-blocking, and no data could be written right away,
Packit Service ca3877
 * the return value will be %SOUP_SOCKET_WOULD_BLOCK. In this case,
Packit Service ca3877
 * the caller can connect to the #SoupSocket::writable signal to know
Packit Service ca3877
 * when more data can be written. (NB: #SoupSocket::writable is only
Packit Service ca3877
 * emitted after soup_socket_write() returns %SOUP_SOCKET_WOULD_BLOCK,
Packit Service ca3877
 * and it is only emitted once. See the documentation for
Packit Service ca3877
 * #SoupSocket:non-blocking.)
Packit Service ca3877
 *
Packit Service ca3877
 * Return value: a #SoupSocketIOStatus, as described above (or
Packit Service ca3877
 * %SOUP_SOCKET_EOF or %SOUP_SOCKET_ERROR. @error will be set if the
Packit Service ca3877
 * return value is %SOUP_SOCKET_ERROR.)
Packit Service ca3877
 **/
Packit Service ca3877
SoupSocketIOStatus
Packit Service ca3877
soup_socket_write (SoupSocket *sock, gconstpointer buffer,
Packit Service ca3877
		   gsize len, gsize *nwrote,
Packit Service ca3877
		   GCancellable *cancellable, GError **error)
Packit Service ca3877
{
Packit Service ca3877
	SoupSocketPrivate *priv;
Packit Service ca3877
	GError *my_err = NULL;
Packit Service ca3877
	gssize my_nwrote;
Packit Service ca3877
Packit Service ca3877
	g_return_val_if_fail (SOUP_IS_SOCKET (sock), SOUP_SOCKET_ERROR);
Packit Service ca3877
	g_return_val_if_fail (nwrote != NULL, SOUP_SOCKET_ERROR);
Packit Service ca3877
Packit Service ca3877
	priv = soup_socket_get_instance_private (sock);
Packit Service ca3877
Packit Service ca3877
	g_mutex_lock (&priv->iolock);
Packit Service ca3877
Packit Service ca3877
	if (!priv->conn) {
Packit Service ca3877
		g_mutex_unlock (&priv->iolock);
Packit Service ca3877
		return SOUP_SOCKET_EOF;
Packit Service ca3877
	}
Packit Service ca3877
	if (priv->write_src) {
Packit Service ca3877
		g_mutex_unlock (&priv->iolock);
Packit Service ca3877
		return SOUP_SOCKET_WOULD_BLOCK;
Packit Service ca3877
	}
Packit Service ca3877
Packit Service ca3877
	if (!priv->non_blocking) {
Packit Service ca3877
		my_nwrote = g_output_stream_write (priv->ostream,
Packit Service ca3877
						   buffer, len,
Packit Service ca3877
						   cancellable, &my_err);
Packit Service ca3877
	} else {
Packit Service ca3877
		my_nwrote = g_pollable_output_stream_write_nonblocking (
Packit Service ca3877
			G_POLLABLE_OUTPUT_STREAM (priv->ostream),
Packit Service ca3877
			buffer, len, cancellable, &my_err);
Packit Service ca3877
	}
Packit Service ca3877
Packit Service ca3877
	if (my_nwrote > 0) {
Packit Service ca3877
		g_mutex_unlock (&priv->iolock);
Packit Service ca3877
		g_clear_error (&my_err);
Packit Service ca3877
		*nwrote = my_nwrote;
Packit Service ca3877
		return SOUP_SOCKET_OK;
Packit Service ca3877
	}
Packit Service ca3877
Packit Service ca3877
	if (g_error_matches (my_err, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) {
Packit Service ca3877
		g_mutex_unlock (&priv->iolock);
Packit Service ca3877
		g_clear_error (&my_err);
Packit Service ca3877
Packit Service ca3877
		priv->write_src =
Packit Service ca3877
			soup_socket_create_watch (priv,
Packit Service ca3877
						  G_IO_OUT,
Packit Service ca3877
						  socket_write_watch, sock, cancellable);
Packit Service ca3877
		return SOUP_SOCKET_WOULD_BLOCK;
Packit Service ca3877
	}
Packit Service ca3877
Packit Service ca3877
	g_mutex_unlock (&priv->iolock);
Packit Service ca3877
	g_propagate_error (error, my_err);
Packit Service ca3877
	return SOUP_SOCKET_ERROR;
Packit Service ca3877
}