Changes to SoupConnection and SoupSession for debugging
authorDan Winship <danw@gnome.org>
Sun, 22 Nov 2009 13:41:09 +0000 (08:41 -0500)
committerDan Winship <danw@gnome.org>
Sun, 22 Nov 2009 13:41:09 +0000 (08:41 -0500)
Specifically, to help epiphany's soup-fly extension track connection
usage.

Patch from José Millán Soto,
https://bugzilla.gnome.org/show_bug.cgi?id=598163

libsoup/soup-connection.c
libsoup/soup-connection.h
libsoup/soup-misc.h
libsoup/soup-session-async.c
libsoup/soup-session-sync.c
libsoup/soup-session.c

index 9f59816..8cb110c 100644 (file)
@@ -26,6 +26,7 @@
 #include "soup-socket.h"
 #include "soup-ssl.h"
 #include "soup-uri.h"
+#include "soup-enum-types.h"
 
 typedef struct {
        SoupSocket  *socket;
@@ -63,6 +64,8 @@ enum {
        PROP_ASYNC_CONTEXT,
        PROP_TIMEOUT,
        PROP_IDLE_TIMEOUT,
+       PROP_STATE,
+       PROP_MESSAGE,
 
        LAST_PROP
 };
@@ -191,6 +194,20 @@ soup_connection_class_init (SoupConnectionClass *connection_class)
                                   "Connection lifetime when idle",
                                   0, G_MAXUINT, 0,
                                   G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+       g_object_class_install_property (
+               object_class, PROP_STATE,
+               g_param_spec_enum (SOUP_CONNECTION_STATE,
+                                  "Connection state",
+                                  "Current state of connection",
+                                  SOUP_TYPE_CONNECTION_STATE, SOUP_CONNECTION_NEW,
+                                  G_PARAM_READWRITE));
+       g_object_class_install_property (
+               object_class, PROP_MESSAGE,
+               g_param_spec_object (SOUP_CONNECTION_MESSAGE,
+                                    "Message",
+                                    "Message being processed",
+                                    SOUP_TYPE_MESSAGE,
+                                    G_PARAM_READABLE));
 }
 
 
@@ -240,6 +257,9 @@ set_property (GObject *object, guint prop_id,
        case PROP_IDLE_TIMEOUT:
                priv->idle_timeout = g_value_get_uint (value);
                break;
+       case PROP_STATE:
+               soup_connection_set_state (SOUP_CONNECTION (object), g_value_get_uint (value));
+               break;
        default:
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
                break;
@@ -274,6 +294,12 @@ get_property (GObject *object, guint prop_id,
        case PROP_IDLE_TIMEOUT:
                g_value_set_uint (value, priv->idle_timeout);
                break;
+       case PROP_STATE:
+               g_value_set_enum (value, priv->state);
+               break;
+       case PROP_MESSAGE:
+               g_value_set_object (value, priv->cur_req);
+               break;
        default:
                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
                break;
@@ -310,19 +336,28 @@ stop_idle_timer (SoupConnectionPrivate *priv)
 }
 
 static void
-set_current_request (SoupConnectionPrivate *priv, SoupMessage *req)
+set_current_request (SoupConnection *conn, SoupMessage *req)
 {
+       SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (conn);
+
        g_return_if_fail (priv->cur_req == NULL);
 
+       g_object_freeze_notify (G_OBJECT (conn));
+
        stop_idle_timer (priv);
        priv->unused_timeout = 0;
 
        soup_message_set_io_status (req, SOUP_MESSAGE_IO_STATUS_RUNNING);
        priv->cur_req = req;
+       g_object_notify (G_OBJECT (conn), "message");
+
        if (priv->state == SOUP_CONNECTION_IDLE ||
            req->method != SOUP_METHOD_CONNECT)
-               priv->state = SOUP_CONNECTION_IN_USE;
+               soup_connection_set_state (conn, SOUP_CONNECTION_IN_USE);
+
        g_object_add_weak_pointer (G_OBJECT (req), (gpointer)&priv->cur_req);
+
+       g_object_thaw_notify (G_OBJECT (conn));
 }
 
 static void
@@ -330,8 +365,15 @@ clear_current_request (SoupConnection *conn)
 {
        SoupConnectionPrivate *priv = SOUP_CONNECTION_GET_PRIVATE (conn);
 
-       if (priv->state == SOUP_CONNECTION_IN_USE)
+       g_object_freeze_notify (G_OBJECT (conn));
+
+       if (priv->state == SOUP_CONNECTION_IN_USE) {
+               /* We don't use soup_connection_set_state here since
+                * it may call clear_current_request()...
+                */
                priv->state = SOUP_CONNECTION_IDLE;
+               g_object_notify (G_OBJECT (conn), "state");
+       }
        start_idle_timer (conn);
        if (priv->cur_req) {
                SoupMessage *cur_req = priv->cur_req;
@@ -339,12 +381,15 @@ clear_current_request (SoupConnection *conn)
                g_object_remove_weak_pointer (G_OBJECT (priv->cur_req),
                                              (gpointer)&priv->cur_req);
                priv->cur_req = NULL;
+               g_object_notify (G_OBJECT (conn), "message");
 
                if (!soup_message_is_keepalive (cur_req))
                        soup_connection_disconnect (conn);
                else
                        soup_message_io_stop (cur_req);
        }
+
+       g_object_thaw_notify (G_OBJECT (conn));
 }
 
 static void
@@ -378,7 +423,7 @@ socket_connect_result (SoupSocket *sock, guint status, gpointer user_data)
        g_signal_connect (priv->socket, "disconnected",
                          G_CALLBACK (socket_disconnected), data->conn);
 
-       priv->state = SOUP_CONNECTION_IDLE;
+       soup_connection_set_state (data->conn, SOUP_CONNECTION_IDLE);
        priv->unused_timeout = time (NULL) + SOUP_CONNECTION_UNUSED_TIMEOUT;
        start_idle_timer (data->conn);
 
@@ -411,7 +456,7 @@ soup_connection_connect_async (SoupConnection *conn,
        priv = SOUP_CONNECTION_GET_PRIVATE (conn);
        g_return_if_fail (priv->socket == NULL);
 
-       priv->state = SOUP_CONNECTION_CONNECTING;
+       soup_connection_set_state (conn, SOUP_CONNECTION_CONNECTING);
 
        data = g_slice_new (SoupConnectionAsyncConnectData);
        data->conn = conn;
@@ -446,7 +491,7 @@ soup_connection_connect_sync (SoupConnection *conn)
        priv = SOUP_CONNECTION_GET_PRIVATE (conn);
        g_return_val_if_fail (priv->socket == NULL, SOUP_STATUS_MALFORMED);
 
-       priv->state = SOUP_CONNECTION_CONNECTING;
+       soup_connection_set_state (conn, SOUP_CONNECTION_CONNECTING);
 
        priv->socket =
                soup_socket_new (SOUP_SOCKET_REMOTE_ADDRESS, priv->remote_addr,
@@ -471,7 +516,7 @@ soup_connection_connect_sync (SoupConnection *conn)
        }
 
        if (SOUP_STATUS_IS_SUCCESSFUL (status)) {
-               priv->state = SOUP_CONNECTION_IDLE;
+               soup_connection_set_state (conn, SOUP_CONNECTION_IDLE);
                priv->unused_timeout = time (NULL) + SOUP_CONNECTION_UNUSED_TIMEOUT;
                start_idle_timer (conn);
        } else {
@@ -541,7 +586,7 @@ soup_connection_disconnect (SoupConnection *conn)
        if (priv->state < SOUP_CONNECTION_IDLE)
                return;
 
-       priv->state = SOUP_CONNECTION_DISCONNECTED;
+       soup_connection_set_state (conn, SOUP_CONNECTION_DISCONNECTED);
        /* NB: this might cause conn to be destroyed. */
        g_signal_emit (conn, signals[DISCONNECTED], 0);
 }
@@ -579,12 +624,12 @@ soup_connection_get_state (SoupConnection *conn)
                pfd.events = G_IO_IN;
                pfd.revents = 0;
                if (g_poll (&pfd, 1, 0) == 1)
-                       priv->state = SOUP_CONNECTION_REMOTE_DISCONNECTED;
+                       soup_connection_set_state (conn, SOUP_CONNECTION_REMOTE_DISCONNECTED);
        }
 #endif
        if (priv->state == SOUP_CONNECTION_IDLE &&
            priv->unused_timeout && priv->unused_timeout < time (NULL))
-               priv->state = SOUP_CONNECTION_REMOTE_DISCONNECTED;
+               soup_connection_set_state (conn, SOUP_CONNECTION_REMOTE_DISCONNECTED);
 
        return priv->state;
 }
@@ -592,13 +637,21 @@ soup_connection_get_state (SoupConnection *conn)
 void
 soup_connection_set_state (SoupConnection *conn, SoupConnectionState state)
 {
+       SoupConnectionPrivate *priv;
+       SoupConnectionState old_state;
+
        g_return_if_fail (SOUP_IS_CONNECTION (conn));
-       g_return_if_fail (state > SOUP_CONNECTION_NEW &&
-                         state < SOUP_CONNECTION_DISCONNECTED);
+       g_return_if_fail (state >= SOUP_CONNECTION_NEW &&
+                         state <= SOUP_CONNECTION_DISCONNECTED);
 
-       SOUP_CONNECTION_GET_PRIVATE (conn)->state = state;
-       if (state == SOUP_CONNECTION_IDLE)
+       priv = SOUP_CONNECTION_GET_PRIVATE (conn);
+       old_state = priv->state;
+       priv->state = state;
+       if (state == SOUP_CONNECTION_IDLE &&
+           old_state == SOUP_CONNECTION_IN_USE)
                clear_current_request (conn);
+
+       g_object_notify (G_OBJECT (conn), "state");
 }
 
 /**
@@ -620,7 +673,7 @@ soup_connection_send_request (SoupConnection *conn, SoupMessage *req)
        g_return_if_fail (priv->state != SOUP_CONNECTION_NEW && priv->state != SOUP_CONNECTION_DISCONNECTED);
 
        if (req != priv->cur_req)
-               set_current_request (priv, req);
+               set_current_request (conn, req);
        soup_message_send_request (req, priv->socket, conn,
                                   priv->proxy_uri != NULL);
 }
index aa261d2..ae8973e 100644 (file)
@@ -9,6 +9,7 @@
 #include <time.h>
 
 #include "soup-types.h"
+#include "soup-misc.h"
 
 G_BEGIN_DECLS
 
@@ -39,15 +40,6 @@ typedef void  (*SoupConnectionCallback)        (SoupConnection   *conn,
                                                guint             status,
                                                gpointer          data);
 
-typedef enum {
-       SOUP_CONNECTION_NEW,
-       SOUP_CONNECTION_CONNECTING,
-       SOUP_CONNECTION_IDLE,
-       SOUP_CONNECTION_IN_USE,
-       SOUP_CONNECTION_REMOTE_DISCONNECTED,
-       SOUP_CONNECTION_DISCONNECTED
-} SoupConnectionState;
-
 #define SOUP_CONNECTION_REMOTE_ADDRESS  "remote-address"
 #define SOUP_CONNECTION_TUNNEL_ADDRESS  "tunnel-address"
 #define SOUP_CONNECTION_PROXY_URI       "proxy-uri"
@@ -55,6 +47,8 @@ typedef enum {
 #define SOUP_CONNECTION_ASYNC_CONTEXT   "async-context"
 #define SOUP_CONNECTION_TIMEOUT         "timeout"
 #define SOUP_CONNECTION_IDLE_TIMEOUT    "idle-timeout"
+#define SOUP_CONNECTION_STATE           "state"
+#define SOUP_CONNECTION_MESSAGE         "message"
 
 SoupConnection *soup_connection_new            (const char       *propname1,
                                                ...) G_GNUC_NULL_TERMINATED;
index e40fa91..8802340 100644 (file)
@@ -49,6 +49,15 @@ typedef enum {
        SOUP_SSL_ERROR_CERTIFICATE
 } SoupSSLError;
 
+typedef enum {
+       SOUP_CONNECTION_NEW,
+       SOUP_CONNECTION_CONNECTING,
+       SOUP_CONNECTION_IDLE,
+       SOUP_CONNECTION_IN_USE,
+       SOUP_CONNECTION_REMOTE_DISCONNECTED,
+       SOUP_CONNECTION_DISCONNECTED
+} SoupConnectionState;
+
 G_END_DECLS
 
 #endif /* SOUP_MISC_H */
index 731138c..89af696 100644 (file)
@@ -264,6 +264,7 @@ got_connection (SoupConnection *conn, guint status, gpointer session)
                        data->session = session;
                        data->conn = conn;
                        data->item = soup_session_make_connect_message (session, tunnel_addr);
+                       g_signal_emit_by_name (session, "tunneling", conn);
                        g_signal_connect (data->item->msg, "finished",
                                          G_CALLBACK (tunnel_connected), data);
                        g_signal_connect (data->item->msg, "restarted",
index eba77e4..e1ba325 100644 (file)
@@ -142,6 +142,7 @@ tunnel_connect (SoupSession *session, SoupConnection *conn,
        SoupMessageQueueItem *item;
        guint status;
 
+       g_signal_emit_by_name (session, "tunneling", conn);
        item = soup_session_make_connect_message (session, tunnel_addr);
        do
                soup_session_send_queue_item (session, item, conn);
index 9c3efdb..c4d3044 100644 (file)
@@ -123,6 +123,8 @@ enum {
        REQUEST_STARTED,
        REQUEST_UNQUEUED,
        AUTHENTICATE,
+       CONNECTION_CREATED,
+       TUNNELING,
        LAST_SIGNAL
 };
 
@@ -380,6 +382,27 @@ soup_session_class_init (SoupSessionClass *session_class)
                              SOUP_TYPE_AUTH,
                              G_TYPE_BOOLEAN);
 
+       signals[CONNECTION_CREATED] =
+               g_signal_new ("connection-created",
+                             G_OBJECT_CLASS_TYPE (object_class),
+                             G_SIGNAL_RUN_FIRST,
+                             0,
+                             NULL, NULL,
+                             soup_marshal_NONE__OBJECT,
+                             G_TYPE_NONE, 1,
+                             SOUP_TYPE_CONNECTION);
+
+       signals[TUNNELING] =
+               g_signal_new ("tunneling",
+                             G_OBJECT_CLASS_TYPE (object_class),
+                             G_SIGNAL_RUN_FIRST,
+                             0,
+                             NULL, NULL,
+                             soup_marshal_NONE__OBJECT,
+                             G_TYPE_NONE, 1,
+                             SOUP_TYPE_CONNECTION);
+
+
        /* properties */
        /**
         * SOUP_SESSION_PROXY_URI:
@@ -1217,6 +1240,8 @@ soup_session_get_connection (SoupSession *session,
                          G_CALLBACK (connection_disconnected),
                          session);
 
+       g_signal_emit (session, signals[CONNECTION_CREATED], 0, conn);
+
        g_hash_table_insert (priv->conns, conn, host);
 
        priv->num_conns++;