SoupMessage: add network-event signal
authorDan Winship <danw@gnome.org>
Thu, 8 Dec 2011 16:34:20 +0000 (11:34 -0500)
committerDan Winship <danw@gnome.org>
Thu, 22 Dec 2011 18:55:44 +0000 (13:55 -0500)
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
libsoup/soup-message-private.h
libsoup/soup-message-queue.c
libsoup/soup-message-queue.h
libsoup/soup-message.c
libsoup/soup-misc-private.h
libsoup/soup-session-async.c
libsoup/soup-session-sync.c
libsoup/soup-session.c
libsoup/soup-socket.c

index af54e88..199be73 100644 (file)
@@ -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);
 }
index 1bb2aab..5625354 100644 (file)
@@ -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 */
index 0fc655f..7b1e5dd 100644 (file)
@@ -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
index 5fb14c4..a1ae663 100644 (file)
@@ -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
 
index 6186087..cdc4392 100644 (file)
@@ -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)
 {
index 1d472f9..e935168 100644 (file)
@@ -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 */
index edb6239..e872102 100644 (file)
@@ -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);
index e0d023e..c54975c 100644 (file)
@@ -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);
index e0d540c..eb5dd6e 100644 (file)
@@ -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) {
index b4396c5..452fada 100644 (file)
@@ -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,