[libsoup] SoupMessage: add network-event signal



commit f4478b4fbab0e94bef11042ed5ca3ab3e3145e8a
Author: Dan Winship <danw gnome org>
Date:   Thu Dec 8 11:34:20 2011 -0500

    SoupMessage: add network-event signal
    
    Proxy the new GSocketClient::event signal and emit it on SoupMessage,
    when relevant, to allow (a) debugging, (b) status messages, (c) request
    timing, (d) fiddling with sockets

 libsoup/soup-connection.c      |  105 +++++++++++++++++++++++++++++++++++++---
 libsoup/soup-message-private.h |    4 ++
 libsoup/soup-message-queue.c   |   35 ++++++++++++--
 libsoup/soup-message-queue.h   |    7 ++-
 libsoup/soup-message.c         |   43 ++++++++++++++++
 libsoup/soup-misc-private.h    |    3 +-
 libsoup/soup-session-async.c   |    6 +--
 libsoup/soup-session-sync.c    |    9 +--
 libsoup/soup-session.c         |    9 ++--
 libsoup/soup-socket.c          |   48 ++++++++++++++++++
 10 files changed, 238 insertions(+), 31 deletions(-)
---
diff --git a/libsoup/soup-connection.c b/libsoup/soup-connection.c
index af54e88..199be73 100644
--- a/libsoup/soup-connection.c
+++ b/libsoup/soup-connection.c
@@ -51,6 +51,7 @@ typedef struct {
 G_DEFINE_TYPE (SoupConnection, soup_connection, G_TYPE_OBJECT)
 
 enum {
+	EVENT,
 	DISCONNECTED,
 	LAST_SIGNAL
 };
@@ -150,6 +151,16 @@ soup_connection_class_init (SoupConnectionClass *connection_class)
 	object_class->get_property = get_property;
 
 	/* signals */
+	signals[EVENT] =
+		g_signal_new ("event",
+			      G_OBJECT_CLASS_TYPE (object_class),
+			      G_SIGNAL_RUN_FIRST,
+			      0,
+			      NULL, NULL,
+			      NULL,
+			      G_TYPE_NONE, 2,
+			      G_TYPE_SOCKET_CLIENT_EVENT,
+			      G_TYPE_IO_STREAM);
 	signals[DISCONNECTED] =
 		g_signal_new ("disconnected",
 			      G_OBJECT_CLASS_TYPE (object_class),
@@ -433,8 +444,11 @@ set_current_item (SoupConnection *conn, SoupMessageQueueItem *item)
 	g_signal_connect (item->msg, "restarted",
 			  G_CALLBACK (current_item_restarted), conn);
 
-	if (priv->state == SOUP_CONNECTION_IDLE ||
-	    item->msg->method != SOUP_METHOD_CONNECT)
+	if (item->msg->method == SOUP_METHOD_CONNECT) {
+		g_signal_emit (conn, signals[EVENT], 0,
+			       G_SOCKET_CLIENT_PROXY_NEGOTIATING,
+			       soup_socket_get_iostream (priv->socket));
+	} else if (priv->state == SOUP_CONNECTION_IDLE)
 		soup_connection_set_state (conn, SOUP_CONNECTION_IN_USE);
 
 	g_object_thaw_notify (G_OBJECT (conn));
@@ -461,6 +475,10 @@ clear_current_item (SoupConnection *conn)
 
 		if (item->msg->method == SOUP_METHOD_CONNECT &&
 		    SOUP_STATUS_IS_SUCCESSFUL (item->msg->status_code)) {
+			g_signal_emit (conn, signals[EVENT], 0,
+				       G_SOCKET_CLIENT_PROXY_NEGOTIATED,
+				       soup_socket_get_iostream (priv->socket));
+
 			/* We're now effectively no longer proxying */
 			soup_uri_free (priv->proxy_uri);
 			priv->proxy_uri = NULL;
@@ -474,6 +492,33 @@ clear_current_item (SoupConnection *conn)
 }
 
 static void
+soup_connection_event (SoupConnection      *conn,
+		       GSocketClientEvent   event,
+		       GIOStream           *connection)
+{
+	SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (conn);
+
+	if (!connection && priv->socket)
+		connection = soup_socket_get_iostream (priv->socket);
+
+	g_signal_emit (conn, signals[EVENT], 0,
+		       event, connection);
+}
+
+static void
+proxy_socket_event (SoupSocket          *socket,
+		    GSocketClientEvent   event,
+		    GIOStream           *connection,
+		    gpointer             user_data)
+{
+	SoupConnection *conn = user_data;
+
+	/* We handle COMPLETE ourselves */
+	if (event != G_SOCKET_CLIENT_COMPLETE)
+		soup_connection_event (conn, event, connection);
+}
+
+static void
 socket_disconnected (SoupSocket *sock, gpointer conn)
 {
 	soup_connection_disconnect (conn);
@@ -484,6 +529,8 @@ typedef struct {
 	SoupConnectionCallback callback;
 	gpointer callback_data;
 	GCancellable *cancellable;
+	guint event_id;
+	gboolean tls_handshake;
 } SoupConnectionAsyncConnectData;
 
 static void
@@ -492,10 +539,23 @@ socket_connect_finished (SoupSocket *socket, guint status, gpointer user_data)
 	SoupConnectionAsyncConnectData *data = user_data;
 	SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (data->conn);
 
+	g_signal_handler_disconnect (socket, data->event_id);
+
 	if (SOUP_STATUS_IS_SUCCESSFUL (status)) {
 		g_signal_connect (priv->socket, "disconnected",
 				  G_CALLBACK (socket_disconnected), data->conn);
 
+		if (data->tls_handshake) {
+			soup_connection_event (data->conn,
+					       G_SOCKET_CLIENT_TLS_HANDSHAKED,
+					       NULL);
+		}
+		if (!priv->ssl || !priv->tunnel_addr) {
+			soup_connection_event (data->conn,
+					       G_SOCKET_CLIENT_COMPLETE,
+					       NULL);
+		}
+
 		soup_connection_set_state (data->conn, SOUP_CONNECTION_IN_USE);
 		priv->unused_timeout = time (NULL) + SOUP_CONNECTION_UNUSED_TIMEOUT;
 		start_idle_timer (data->conn);
@@ -519,11 +579,13 @@ static void
 socket_connect_result (SoupSocket *sock, guint status, gpointer user_data)
 {
 	SoupConnectionAsyncConnectData *data = user_data;
-	SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (data->conn);
 
 	if (SOUP_STATUS_IS_SUCCESSFUL (status) &&
-	    priv->ssl && !priv->tunnel_addr) {
+	    data->tls_handshake) {
 		if (soup_socket_start_ssl (sock, data->cancellable)) {
+			soup_connection_event (data->conn,
+					       G_SOCKET_CLIENT_TLS_HANDSHAKING,
+					       NULL);
 			soup_socket_handshake_async (sock, data->cancellable,
 						     socket_connect_finished, data);
 			return;
@@ -555,6 +617,7 @@ soup_connection_connect_async (SoupConnection *conn,
 	data->callback = callback;
 	data->callback_data = user_data;
 	data->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
+	data->tls_handshake = (priv->ssl && !priv->tunnel_addr);
 
 	priv->socket =
 		soup_socket_new (SOUP_SOCKET_REMOTE_ADDRESS, priv->remote_addr,
@@ -566,6 +629,9 @@ soup_connection_connect_async (SoupConnection *conn,
 				 SOUP_SOCKET_TIMEOUT, priv->io_timeout,
 				 "clean-dispose", TRUE,
 				 NULL);
+	data->event_id = g_signal_connect (priv->socket, "event",
+					   G_CALLBACK (proxy_socket_event),
+					   conn);
 	soup_socket_connect_async (priv->socket, cancellable,
 				   socket_connect_result, data);
 }
@@ -574,7 +640,7 @@ guint
 soup_connection_connect_sync (SoupConnection *conn, GCancellable *cancellable)
 {
 	SoupConnectionPrivate *priv;
-	guint status;
+	guint status, event_id;
 
 	g_return_val_if_fail (SOUP_IS_CONNECTION (conn), SOUP_STATUS_MALFORMED);
 	priv = SOUP_CONNECTION_GET_PRIVATE (conn);
@@ -592,6 +658,8 @@ soup_connection_connect_sync (SoupConnection *conn, GCancellable *cancellable)
 				 "clean-dispose", TRUE,
 				 NULL);
 
+	event_id = g_signal_connect (priv->socket, "event",
+				     G_CALLBACK (proxy_socket_event), conn);
 	status = soup_socket_connect_sync (priv->socket, cancellable);
 
 	if (!SOUP_STATUS_IS_SUCCESSFUL (status))
@@ -601,8 +669,15 @@ soup_connection_connect_sync (SoupConnection *conn, GCancellable *cancellable)
 		if (!soup_socket_start_ssl (priv->socket, cancellable))
 			status = SOUP_STATUS_SSL_FAILED;
 		else {
+			soup_connection_event (conn,
+					       G_SOCKET_CLIENT_TLS_HANDSHAKING,
+					       NULL);
 			status = soup_socket_handshake_sync (priv->socket, cancellable);
-			if (status == SOUP_STATUS_TLS_FAILED) {
+			if (status == SOUP_STATUS_OK) {
+				soup_connection_event (conn,
+						       G_SOCKET_CLIENT_TLS_HANDSHAKED,
+						       NULL);
+			} else if (status == SOUP_STATUS_TLS_FAILED) {
 				priv->ssl_fallback = TRUE;
 				status = SOUP_STATUS_TRY_AGAIN;
 			}
@@ -613,6 +688,11 @@ soup_connection_connect_sync (SoupConnection *conn, GCancellable *cancellable)
 		g_signal_connect (priv->socket, "disconnected",
 				  G_CALLBACK (socket_disconnected), conn);
 
+		if (!priv->ssl || !priv->tunnel_addr) {
+			soup_connection_event (conn,
+					       G_SOCKET_CLIENT_COMPLETE,
+					       NULL);
+		}
 		soup_connection_set_state (conn, SOUP_CONNECTION_IN_USE);
 		priv->unused_timeout = time (NULL) + SOUP_CONNECTION_UNUSED_TIMEOUT;
 		start_idle_timer (conn);
@@ -625,6 +705,9 @@ soup_connection_connect_sync (SoupConnection *conn, GCancellable *cancellable)
 		}
 	}
 
+	if (priv->socket)
+		g_signal_handler_disconnect (priv->socket, event_id);
+
 	if (priv->proxy_uri != NULL)
 		status = soup_status_proxify (status);
 	return status;
@@ -659,8 +742,11 @@ soup_connection_start_ssl_sync (SoupConnection *conn,
 					  cancellable))
 		return SOUP_STATUS_SSL_FAILED;
 
+	soup_connection_event (conn, G_SOCKET_CLIENT_TLS_HANDSHAKING, NULL);
 	status = soup_socket_handshake_sync (priv->socket, cancellable);
-	if (status == SOUP_STATUS_TLS_FAILED) {
+	if (status == SOUP_STATUS_OK)
+		soup_connection_event (conn, G_SOCKET_CLIENT_TLS_HANDSHAKED, NULL);
+	else if (status == SOUP_STATUS_TLS_FAILED) {
 		priv->ssl_fallback = TRUE;
 		status = SOUP_STATUS_TRY_AGAIN;
 	}
@@ -674,7 +760,9 @@ start_ssl_completed (SoupSocket *socket, guint status, gpointer user_data)
 	SoupConnectionAsyncConnectData *data = user_data;
 	SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (data->conn);
 
-	if (status == SOUP_STATUS_TLS_FAILED) {
+	if (status == SOUP_STATUS_OK)
+		soup_connection_event (data->conn, G_SOCKET_CLIENT_TLS_HANDSHAKED, NULL);
+	else if (status == SOUP_STATUS_TLS_FAILED) {
 		priv->ssl_fallback = TRUE;
 		status = SOUP_STATUS_TRY_AGAIN;
 	}
@@ -727,6 +815,7 @@ soup_connection_start_ssl_async (SoupConnection   *conn,
 		return;
 	}
 
+	soup_connection_event (conn, G_SOCKET_CLIENT_TLS_HANDSHAKING, NULL);
 	soup_socket_handshake_async (priv->socket, cancellable,
 				     start_ssl_completed, data);
 }
diff --git a/libsoup/soup-message-private.h b/libsoup/soup-message-private.h
index 1bb2aab..5625354 100644
--- a/libsoup/soup-message-private.h
+++ b/libsoup/soup-message-private.h
@@ -100,4 +100,8 @@ gboolean soup_message_disables_feature (SoupMessage *msg,
 void soup_message_set_https_status (SoupMessage    *msg,
 				    SoupConnection *conn);
 
+void soup_message_network_event (SoupMessage         *msg,
+				 GSocketClientEvent   event,
+				 GIOStream           *connection);
+
 #endif /* SOUP_MESSAGE_PRIVATE_H */
diff --git a/libsoup/soup-message-queue.c b/libsoup/soup-message-queue.c
index 0fc655f..7b1e5dd 100644
--- a/libsoup/soup-message-queue.c
+++ b/libsoup/soup-message-queue.c
@@ -72,8 +72,7 @@ queue_message_restarted (SoupMessage *msg, gpointer user_data)
 	     SOUP_STATUS_IS_REDIRECTION (msg->status_code))) {
 		if (soup_connection_get_state (item->conn) == SOUP_CONNECTION_IN_USE)
 			soup_connection_set_state (item->conn, SOUP_CONNECTION_IDLE);
-		g_object_unref (item->conn);
-		item->conn = NULL;
+		soup_message_queue_item_set_connection (item, NULL);
 	}
 
 	soup_message_cleanup_response (msg);
@@ -185,11 +184,39 @@ soup_message_queue_item_unref (SoupMessageQueueItem *item)
 		g_object_unref (item->proxy_addr);
 	if (item->proxy_uri)
 		soup_uri_free (item->proxy_uri);
-	if (item->conn)
-		g_object_unref (item->conn);
+	soup_message_queue_item_set_connection (item, NULL);
 	g_slice_free (SoupMessageQueueItem, item);
 }
 
+static void
+proxy_connection_event (SoupConnection      *conn,
+			GSocketClientEvent   event,
+			GIOStream           *connection,
+			gpointer             user_data)
+{
+	SoupMessageQueueItem *item = user_data;
+
+	soup_message_network_event (item->msg, event, connection);
+}
+
+void
+soup_message_queue_item_set_connection (SoupMessageQueueItem *item,
+					SoupConnection       *conn)
+{
+	if (item->conn) {
+		g_signal_handlers_disconnect_by_func (item->conn, proxy_connection_event, item);
+		g_object_unref (item->conn);
+	}
+
+	item->conn = conn;
+
+	if (item->conn) {
+		g_object_ref (item->conn);
+		g_signal_connect (item->conn, "event",
+				  G_CALLBACK (proxy_connection_event), item);
+	}
+}
+
 /**
  * soup_message_queue_lookup:
  * @queue: a #SoupMessageQueue
diff --git a/libsoup/soup-message-queue.h b/libsoup/soup-message-queue.h
index 5fb14c4..a1ae663 100644
--- a/libsoup/soup-message-queue.h
+++ b/libsoup/soup-message-queue.h
@@ -74,11 +74,12 @@ SoupMessageQueueItem *soup_message_queue_next       (SoupMessageQueue     *queue
 void                  soup_message_queue_remove     (SoupMessageQueue     *queue,
 						     SoupMessageQueueItem *item);
 
-void                  soup_message_queue_item_ref   (SoupMessageQueueItem *item);
-void                  soup_message_queue_item_unref (SoupMessageQueueItem *item);
-
 void                  soup_message_queue_destroy    (SoupMessageQueue     *queue);
 
+void soup_message_queue_item_ref            (SoupMessageQueueItem *item);
+void soup_message_queue_item_unref          (SoupMessageQueueItem *item);
+void soup_message_queue_item_set_connection (SoupMessageQueueItem *item,
+					     SoupConnection       *conn);
 
 G_END_DECLS
 
diff --git a/libsoup/soup-message.c b/libsoup/soup-message.c
index 6186087..cdc4392 100644
--- a/libsoup/soup-message.c
+++ b/libsoup/soup-message.c
@@ -107,6 +107,8 @@ enum {
 	RESTARTED,
 	FINISHED,
 
+	NETWORK_EVENT,
+
 	LAST_SIGNAL
 };
 
@@ -493,6 +495,38 @@ soup_message_class_init (SoupMessageClass *message_class)
 			      soup_marshal_NONE__NONE,
 			      G_TYPE_NONE, 0);
 
+	/**
+	 * SoupMessage::network-event:
+	 * @msg: the message
+	 * @event: the network event
+	 * @connection: the current state of the network connection
+
+	 * Emitted to indicate that some network-related event
+	 * related to @msg has occurred. This essentially proxies the
+	 * #GSocketClient::event signal, but only for events that
+	 * occur while @msg "owns" the connection; if @msg is sent on
+	 * an existing persistent connection, then this signal will
+	 * not be emitted. (If you want to force the message to be
+	 * sent on a new connection, set the
+	 * %SOUP_MESSAGE_NEW_CONNECTION flag on it.)
+	 *
+	 * See #GSocketClient::event for more information on what
+	 * the different values of @event correspond to, and what
+	 * @connection will be in each case.
+	 *
+	 * Since: 2.38
+	 **/
+	signals[NETWORK_EVENT] =
+		g_signal_new ("network_event",
+			      G_OBJECT_CLASS_TYPE (object_class),
+			      G_SIGNAL_RUN_FIRST,
+			      0,
+			      NULL, NULL,
+			      NULL,
+			      G_TYPE_NONE, 2,
+			      G_TYPE_SOCKET_CLIENT_EVENT,
+			      G_TYPE_IO_STREAM);
+
 	/* properties */
 	/**
 	 * SOUP_MESSAGE_METHOD:
@@ -1125,6 +1159,15 @@ soup_message_finished (SoupMessage *msg)
 	g_signal_emit (msg, signals[FINISHED], 0);
 }
 
+void
+soup_message_network_event (SoupMessage         *msg,
+			    GSocketClientEvent   event,
+			    GIOStream           *connection)
+{
+	g_signal_emit (msg, signals[NETWORK_EVENT], 0,
+		       event, connection);
+}
+
 static void
 header_handler_free (gpointer header_name, GClosure *closure)
 {
diff --git a/libsoup/soup-misc-private.h b/libsoup/soup-misc-private.h
index 1d472f9..e935168 100644
--- a/libsoup/soup-misc-private.h
+++ b/libsoup/soup-misc-private.h
@@ -18,7 +18,8 @@ void  soup_socket_handshake_async (SoupSocket         *sock,
 				   SoupSocketCallback  callback,
 				   gpointer            user_data);
 
-GSocket *soup_socket_get_gsocket  (SoupSocket         *sock);
+GSocket   *soup_socket_get_gsocket  (SoupSocket *sock);
+GIOStream *soup_socket_get_iostream (SoupSocket *sock);
 
 
 #endif /* SOUP_URI_PRIVATE_H */
diff --git a/libsoup/soup-session-async.c b/libsoup/soup-session-async.c
index edb6239..e872102 100644
--- a/libsoup/soup-session-async.c
+++ b/libsoup/soup-session-async.c
@@ -299,8 +299,7 @@ tunnel_message_completed (SoupMessage *msg, gpointer user_data)
 			soup_connection_disconnect (item->conn);
 		if (msg->status_code == SOUP_STATUS_TRY_AGAIN) {
 			item->related->state = SOUP_MESSAGE_AWAITING_CONNECTION;
-			g_object_unref (item->related->conn);
-			item->related->conn = NULL;
+			soup_message_queue_item_set_connection (item->related, NULL);
 		} else
 			soup_message_set_status (item->related->msg, msg->status_code);
 
@@ -333,8 +332,7 @@ got_connection (SoupConnection *conn, guint status, gpointer user_data)
 		soup_connection_disconnect (conn);
 
 		if (status == SOUP_STATUS_TRY_AGAIN) {
-			g_object_unref (item->conn);
-			item->conn = NULL;
+			soup_message_queue_item_set_connection (item, NULL);
 			item->state = SOUP_MESSAGE_AWAITING_CONNECTION;
 		} else {
 			soup_session_set_item_status (session, item, status);
diff --git a/libsoup/soup-session-sync.c b/libsoup/soup-session-sync.c
index e0d023e..c54975c 100644
--- a/libsoup/soup-session-sync.c
+++ b/libsoup/soup-session-sync.c
@@ -209,8 +209,7 @@ try_again:
 	status = soup_connection_connect_sync (item->conn, item->cancellable);
 	if (status == SOUP_STATUS_TRY_AGAIN) {
 		soup_connection_disconnect (item->conn);
-		g_object_unref (item->conn);
-		item->conn = NULL;
+		soup_message_queue_item_set_connection (item, NULL);
 		goto try_again;
 	}
 
@@ -221,8 +220,7 @@ try_again:
 			soup_session_set_item_status (session, item, status);
 		item->state = SOUP_MESSAGE_FINISHING;
 		soup_connection_disconnect (item->conn);
-		g_object_unref (item->conn);
-		item->conn = NULL;
+		soup_message_queue_item_set_connection (item, NULL);
 		return;
 	}
 
@@ -230,8 +228,7 @@ try_again:
 		status = tunnel_connect (session, item);
 		if (!SOUP_STATUS_IS_SUCCESSFUL (status)) {
 			soup_connection_disconnect (item->conn);
-			g_object_unref (item->conn);
-			item->conn = NULL;
+			soup_message_queue_item_set_connection (item, NULL);
 			if (status == SOUP_STATUS_TRY_AGAIN)
 				goto try_again;
 			soup_session_set_item_status (session, item, status);
diff --git a/libsoup/soup-session.c b/libsoup/soup-session.c
index e0d540c..eb5dd6e 100644
--- a/libsoup/soup-session.c
+++ b/libsoup/soup-session.c
@@ -1842,7 +1842,7 @@ soup_session_make_connect_message (SoupSession    *session,
 	 */
 	queue_message (session, msg, NULL, NULL);
 	item = soup_message_queue_lookup (priv->queue, msg);
-	item->conn = g_object_ref (conn);
+	soup_message_queue_item_set_connection (item, conn);
 	g_object_unref (msg);
 
 	g_signal_emit (session, signals[TUNNELING], 0, conn);
@@ -1879,7 +1879,7 @@ soup_session_get_connection (SoupSession *session,
 		if (!need_new_connection && soup_connection_get_state (conns->data) == SOUP_CONNECTION_IDLE) {
 			soup_connection_set_state (conns->data, SOUP_CONNECTION_IN_USE);
 			g_mutex_unlock (&priv->host_lock);
-			item->conn = g_object_ref (conns->data);
+			soup_message_queue_item_set_connection (item, conns->data);
 			soup_message_set_https_status (item->msg, item->conn);
 			return TRUE;
 		} else if (soup_connection_get_state (conns->data) == SOUP_CONNECTION_CONNECTING)
@@ -1951,7 +1951,7 @@ soup_session_get_connection (SoupSession *session,
 	}
 
 	g_mutex_unlock (&priv->host_lock);
-	item->conn = g_object_ref (conn);
+	soup_message_queue_item_set_connection (item, conn);
 	return TRUE;
 }
 
@@ -1972,8 +1972,7 @@ soup_session_unqueue_item (SoupSession          *session,
 
 	if (item->conn) {
 		soup_connection_set_state (item->conn, SOUP_CONNECTION_IDLE);
-		g_object_unref (item->conn);
-		item->conn = NULL;
+		soup_message_queue_item_set_connection (item, NULL);
 	}
 
 	if (item->state != SOUP_MESSAGE_FINISHED) {
diff --git a/libsoup/soup-socket.c b/libsoup/soup-socket.c
index b4396c5..452fada 100644
--- a/libsoup/soup-socket.c
+++ b/libsoup/soup-socket.c
@@ -39,6 +39,7 @@ enum {
 	WRITABLE,
 	DISCONNECTED,
 	NEW_CONNECTION,
+	EVENT,
 	LAST_SIGNAL
 };
 
@@ -263,6 +264,28 @@ soup_socket_class_init (SoupSocketClass *socket_class)
 			      soup_marshal_NONE__OBJECT,
 			      G_TYPE_NONE, 1,
 			      SOUP_TYPE_SOCKET);
+	/**
+	 * SoupSocket::event:
+	 * @sock: the socket
+	 * @event: the event that occurred
+	 * @connection: the current connection state
+	 *
+	 * Emitted when a network-related event occurs. See
+	 * #GSocketClient::event for more details.
+	 *
+	 * Since: 2.38
+	 **/
+	signals[EVENT] =
+		g_signal_new ("event",
+			      G_OBJECT_CLASS_TYPE (object_class),
+			      G_SIGNAL_RUN_LAST,
+			      0,
+			      NULL, NULL,
+			      NULL,
+			      G_TYPE_NONE, 2,
+			      G_TYPE_SOCKET_CLIENT_EVENT,
+			      G_TYPE_IO_STREAM);
+
 
 	/* properties */
 	/**
@@ -630,6 +653,19 @@ soup_socket_new (const char *optname1, ...)
 	return sock;
 }
 
+static void
+proxy_socket_client_event (GSocketClient       *client,
+			   GSocketClientEvent   event,
+			   GSocketConnectable  *connectable,
+			   GIOStream           *connection,
+			   gpointer             user_data)
+{
+	SoupSocket *sock = user_data;
+
+	g_signal_emit (sock, signals[EVENT], 0,
+		       event, connection);
+}
+
 static guint
 socket_connected (SoupSocket *sock, GSocketConnection *conn, GError *error)
 {
@@ -729,6 +765,8 @@ soup_socket_connect_async (SoupSocket *sock, GCancellable *cancellable,
 		g_main_context_push_thread_default (priv->async_context);
 
 	client = g_socket_client_new ();
+	g_signal_connect (client, "event",
+			  G_CALLBACK (proxy_socket_client_event), sock);
 	if (priv->timeout)
 		g_socket_client_set_timeout (client, priv->timeout);
 	g_socket_client_connect_async (client,
@@ -772,6 +810,8 @@ soup_socket_connect_sync (SoupSocket *sock, GCancellable *cancellable)
 	priv->connect_cancel = cancellable;
 
 	client = g_socket_client_new ();
+	g_signal_connect (client, "event",
+			  G_CALLBACK (proxy_socket_client_event), sock);
 	if (priv->timeout)
 		g_socket_client_set_timeout (client, priv->timeout);
 	conn = g_socket_client_connect (client,
@@ -798,6 +838,14 @@ soup_socket_get_gsocket (SoupSocket *sock)
 	return SOUP_SOCKET_GET_PRIVATE (sock)->gsock;
 }
 
+GIOStream *
+soup_socket_get_iostream (SoupSocket *sock)
+{
+	g_return_val_if_fail (SOUP_IS_SOCKET (sock), NULL);
+
+	return SOUP_SOCKET_GET_PRIVATE (sock)->conn;
+}
+
 static GSource *
 soup_socket_create_watch (SoupSocketPrivate *priv, GIOCondition cond,
 			  GPollableSourceFunc callback, gpointer user_data,



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