bump version to 2.2.90. This will not be officially released, but once
authorDan Winship <danw@src.gnome.org>
Thu, 10 Nov 2005 16:48:42 +0000 (16:48 +0000)
committerDan Winship <danw@src.gnome.org>
Thu, 10 Nov 2005 16:48:42 +0000 (16:48 +0000)
* configure.in: bump version to 2.2.90. This will not be
officially released, but once these patches have gotten some
testing they may be pulled up to the gnome-2-12 branch.

* libsoup/soup-connection.c:
* libsoup/soup-server.c:
* libsoup/soup-session.c:
* libsoup/soup-socket.c: add an "async-context" property,
which gets passed from server to socket, and session to connection
to socket, allowing async usage outside the main thread. Based on
patches from Armin Bauer and Jürg Billeter.

* libsoup/soup-misc.c (soup_add_io_watch, soup_add_idle,
soup_add_timeout): utility routines to add watches, idles, and
timeouts to non-default GMainContexts.

* libsoup/soup-message-io.c (io_write): set the read state
appropriately after writing a "100 Continue" response
(io_read): More 100-Continue stuff. I don't think this is quite
right so it will probably change again later.

13 files changed:
ChangeLog
configure.in
libsoup/soup-connection.c
libsoup/soup-connection.h
libsoup/soup-message-io.c
libsoup/soup-misc.c
libsoup/soup-misc.h
libsoup/soup-server.c
libsoup/soup-server.h
libsoup/soup-session.c
libsoup/soup-session.h
libsoup/soup-socket.c
libsoup/soup-socket.h

index 6c14b9c..1a921f2 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,26 @@
+2005-11-10  Dan Winship  <danw@novell.com>
+
+       * configure.in: bump version to 2.2.90. This will not be
+       officially released, but once these patches have gotten some
+       testing they may be pulled up to the gnome-2-12 branch.
+
+       * libsoup/soup-connection.c:
+       * libsoup/soup-server.c: 
+       * libsoup/soup-session.c: 
+       * libsoup/soup-socket.c: add an "async-context" property,
+       which gets passed from server to socket, and session to connection
+       to socket, allowing async usage outside the main thread. Based on
+       patches from Armin Bauer and Jürg Billeter.
+
+       * libsoup/soup-misc.c (soup_add_io_watch, soup_add_idle,
+       soup_add_timeout): utility routines to add watches, idles, and
+       timeouts to non-default GMainContexts.
+
+       * libsoup/soup-message-io.c (io_write): set the read state
+       appropriately after writing a "100 Continue" response
+       (io_read): More 100-Continue stuff. I don't think this is quite
+       right so it will probably change again later.
+
 2005-11-01  Dan Winship  <danw@novell.com>
 
        * docs/reference/libsoup-docs.sgml: tell it to generate an index
index 61d759e..3db8069 100644 (file)
@@ -3,7 +3,7 @@ dnl *** Initialize automake and set version ***
 dnl *******************************************
 
 AC_PREREQ(2.53)
-AC_INIT(libsoup, 2.2.6.1)
+AC_INIT(libsoup, 2.2.90)
 AC_CONFIG_SRCDIR(libsoup.pc.in)
 AM_INIT_AUTOMAKE(AC_PACKAGE_NAME, AC_PACKAGE_VERSION)
 
@@ -15,10 +15,10 @@ SOUP_API_VERSION=2.2
 AC_SUBST(SOUP_API_VERSION)
 
 # Increment on interface addition. Reset on removal.
-SOUP_AGE=1
+SOUP_AGE=2
 
 # Increment on interface add, remove, or change.
-SOUP_CURRENT=9
+SOUP_CURRENT=10
 
 # Increment on source change. Reset when CURRENT changes.
 SOUP_REVISION=0
index 5302768..0169e13 100644 (file)
@@ -41,6 +41,7 @@ typedef struct {
        gpointer     ssl_creds;
 
        SoupMessageFilter *filter;
+       GMainContext      *async_context;
 
        SoupMessage *cur_req;
        time_t       last_used;
@@ -67,6 +68,7 @@ enum {
        PROP_PROXY_URI,
        PROP_SSL_CREDS,
        PROP_MESSAGE_FILTER,
+       PROP_ASYNC_CONTEXT,
 
        LAST_PROP
 };
@@ -96,6 +98,8 @@ finalize (GObject *object)
 
        if (priv->filter)
                g_object_unref (priv->filter);
+       if (priv->async_context)
+               g_main_context_unref (priv->async_context);
 
        G_OBJECT_CLASS (soup_connection_parent_class)->finalize (object);
 }
@@ -244,6 +248,12 @@ soup_connection_class_init (SoupConnectionClass *connection_class)
                                      "Message filter",
                                      "Message filter object for this connection",
                                      G_PARAM_READWRITE));
+       g_object_class_install_property (
+               object_class, PROP_ASYNC_CONTEXT,
+               g_param_spec_pointer (SOUP_CONNECTION_ASYNC_CONTEXT,
+                                     "Async GMainContext",
+                                     "GMainContext to dispatch this connection's async I/O in",
+                                     G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 }
 
 
@@ -304,7 +314,16 @@ set_property (GObject *object, guint prop_id,
                priv->ssl_creds = g_value_get_pointer (value);
                break;
        case PROP_MESSAGE_FILTER:
-               priv->filter = g_object_ref (g_value_get_pointer (value));
+               if (priv->filter)
+                       g_object_unref (priv->filter);
+               priv->filter = g_value_get_pointer (value);
+               if (priv->filter)
+                       g_object_ref (priv->filter);
+               break;
+       case PROP_ASYNC_CONTEXT:
+               priv->async_context = g_value_get_pointer (value);
+               if (priv->async_context)
+                       g_main_context_ref (priv->async_context);
                break;
        default:
                break;
@@ -331,7 +350,10 @@ get_property (GObject *object, guint prop_id,
                g_value_set_pointer (value, priv->ssl_creds);
                break;
        case PROP_MESSAGE_FILTER:
-               g_value_set_pointer (value, g_object_ref (priv->filter));
+               g_value_set_pointer (value, priv->filter ? g_object_ref (priv->filter) : NULL);
+               break;
+       case PROP_ASYNC_CONTEXT:
+               g_value_set_pointer (value, priv->async_context ? g_main_context_ref (priv->async_context) : NULL);
                break;
        default:
                break;
@@ -513,10 +535,13 @@ soup_connection_connect_async (SoupConnection *conn,
        }
 
        priv->socket =
-               soup_socket_client_new_async (priv->conn_uri->host,
-                                             priv->conn_uri->port,
-                                             priv->ssl_creds,
-                                             socket_connect_result, conn);
+               soup_socket_new (SOUP_SOCKET_SSL_CREDENTIALS, priv->ssl_creds,
+                                SOUP_SOCKET_ASYNC_CONTEXT, priv->async_context,
+                                NULL);
+       soup_socket_connect (priv->socket, soup_address_new (priv->conn_uri->host,
+                                                            priv->conn_uri->port));
+       soup_signal_connect_once (priv->socket, "connect_result",
+                                 G_CALLBACK (socket_connect_result), conn);
        g_signal_connect (priv->socket, "disconnected",
                          G_CALLBACK (socket_disconnected), conn);
 }
index 0c191b9..5bfb6aa 100644 (file)
@@ -60,6 +60,7 @@ typedef void  (*SoupConnectionCallback)        (SoupConnection   *conn,
 #define SOUP_CONNECTION_PROXY_URI       "proxy-uri"
 #define SOUP_CONNECTION_SSL_CREDENTIALS "ssl-creds"
 #define SOUP_CONNECTION_MESSAGE_FILTER  "message-filter"
+#define SOUP_CONNECTION_ASYNC_CONTEXT   "async-context"
 
 SoupConnection *soup_connection_new            (const char       *propname1,
                                                ...) G_GNUC_NULL_TERMINATED;
index b06d350..7e59f16 100644 (file)
@@ -373,6 +373,7 @@ io_write (SoupSocket *sock, SoupMessage *msg)
                                /* Stop and wait for the body now */
                                io->write_state =
                                        SOUP_MESSAGE_IO_STATE_BLOCKING;
+                               io->read_state = io_body_state (io->read_encoding);
                        } else {
                                /* We just wrote a 1xx response
                                 * header, so stay in STATE_HEADERS.
@@ -570,13 +571,16 @@ io_read (SoupSocket *sock, SoupMessage *msg)
                } else if (io->mode == SOUP_MESSAGE_IO_SERVER &&
                           (priv->msg_flags & SOUP_MESSAGE_EXPECT_CONTINUE)) {
                        /* The client requested a Continue response. */
+                       soup_message_set_status (msg, SOUP_STATUS_CONTINUE);
+                       
                        io->write_state = SOUP_MESSAGE_IO_STATE_HEADERS;
                        io->read_state = SOUP_MESSAGE_IO_STATE_BLOCKING;
                } else
                        io->read_state = io_body_state (io->read_encoding);
 
                SOUP_MESSAGE_IO_PREPARE_FOR_CALLBACK;
-               if (SOUP_STATUS_IS_INFORMATIONAL (msg->status_code)) {
+               if (SOUP_STATUS_IS_INFORMATIONAL (msg->status_code) &&
+                   !(priv->msg_flags & SOUP_MESSAGE_EXPECT_CONTINUE)) {
                        soup_message_got_informational (msg);
                        soup_message_cleanup_response (msg);
                } else
index 500caad..7f19d5d 100644 (file)
@@ -392,3 +392,81 @@ soup_signal_connect_once (gpointer instance, const char *detailed_signal,
                                                    closure, FALSE);
        return ssod->signal_id;
 }
+
+/**
+ * soup_add_io_watch:
+ * @async_context: the #GMainContext to dispatch the I/O watch in, or
+ * %NULL for the default context
+ * @chan: the #GIOChannel to watch
+ * @condition: the condition to watch for
+ * @function: the callback to invoke when @condition occurs
+ * @data: user data to pass to @function
+ *
+ * Adds an I/O watch as with g_io_add_watch(), but using the given
+ * @async_context.
+ *
+ * Return value: a #GSource, which can be removed from @async_context
+ * with g_source_destroy().
+ **/
+GSource *
+soup_add_io_watch (GMainContext *async_context,
+                  GIOChannel *chan, GIOCondition condition,
+                  GIOFunc function, gpointer data)
+{
+       GSource *watch = g_io_create_watch (chan, condition);
+       g_source_set_callback (watch, (GSourceFunc) function, data, NULL);
+       g_source_attach (watch, async_context);
+       g_source_unref (watch);
+       return watch;
+}
+
+/**
+ * soup_add_idle:
+ * @async_context: the #GMainContext to dispatch the idle event in, or
+ * %NULL for the default context
+ * @function: the callback to invoke at idle time
+ * @data: user data to pass to @function
+ *
+ * Adds an idle event as with g_idle_add(), but using the given
+ * @async_context.
+ *
+ * Return value: a #GSource, which can be removed from @async_context
+ * with g_source_destroy().
+ **/
+GSource *
+soup_add_idle (GMainContext *async_context,
+              GSourceFunc function, gpointer data)
+{
+       GSource *source = g_idle_source_new ();
+       g_source_set_callback (source, function, data, NULL);
+       g_source_attach (source, async_context);
+       g_source_unref (watch);
+       return source;
+}
+
+/**
+ * soup_add_timeout:
+ * @async_context: the #GMainContext to dispatch the timeout in, or
+ * %NULL for the default context
+ * @interval: the timeout interval, in milliseconds
+ * @function: the callback to invoke at timeout time
+ * @data: user data to pass to @function
+ *
+ * Adds a timeout as with g_timeout_add(), but using the given
+ * @async_context.
+ *
+ * Return value: a #GSource, which can be removed from @async_context
+ * with g_source_destroy().
+ **/
+GSource *
+soup_add_timeout (GMainContext *async_context,
+                 guint interval,
+                 GSourceFunc function, gpointer data)
+{
+       GSource *source = g_timeout_source_new (interval);
+       g_source_set_callback (source, function, data, NULL);
+       g_source_attach (source, async_context);
+       g_source_unref (watch);
+       return source;
+}
+
index 0962813..0398abe 100644 (file)
@@ -36,6 +36,20 @@ int                soup_base64_decode_step   (const guchar *in,
                                              int          *state, 
                                              guint        *save);
 
+/* Non-default-GMainContext operations */
+GSource           *soup_add_io_watch         (GMainContext *async_context,
+                                             GIOChannel   *chan,
+                                             GIOCondition  condition,
+                                             GIOFunc       function,
+                                             gpointer      data);
+GSource           *soup_add_idle             (GMainContext *async_context,
+                                             GSourceFunc   function,
+                                             gpointer      data);
+GSource           *soup_add_timeout          (GMainContext *async_context,
+                                             guint         interval,
+                                             GSourceFunc   function,
+                                             gpointer      data);
+
 /* Misc utils */
 
 guint              soup_signal_connect_once  (gpointer      instance,
index 22f6205..f64d7d3 100644 (file)
@@ -42,6 +42,8 @@ typedef struct {
 
        GHashTable        *handlers; /* KEY: path, VALUE: SoupServerHandler */
        SoupServerHandler *default_handler;
+       
+       GMainContext      *async_context;
 } SoupServerPrivate;
 #define SOUP_SERVER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SOUP_TYPE_SERVER, SoupServerPrivate))
 
@@ -52,6 +54,7 @@ enum {
        PROP_INTERFACE,
        PROP_SSL_CERT_FILE,
        PROP_SSL_KEY_FILE,
+       PROP_ASYNC_CONTEXT,
 
        LAST_PROP
 };
@@ -124,6 +127,8 @@ finalize (GObject *object)
 
        if (priv->loop)
                g_main_loop_unref (priv->loop);
+       if (priv->async_context)
+               g_main_context_unref (priv->async_context);
 
        G_OBJECT_CLASS (soup_server_parent_class)->finalize (object);
 }
@@ -169,6 +174,12 @@ soup_server_class_init (SoupServerClass *server_class)
                                     "File containing server SSL key",
                                     NULL,
                                     G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+       g_object_class_install_property (
+               object_class, PROP_ASYNC_CONTEXT,
+               g_param_spec_pointer (SOUP_SERVER_ASYNC_CONTEXT,
+                                     "Async GMainContext",
+                                     "The GMainContext to dispatch async I/O in",
+                                     G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 }
 
 
@@ -197,6 +208,11 @@ set_property (GObject *object, guint prop_id,
                priv->ssl_key_file =
                        g_strdup (g_value_get_string (value));
                break;
+       case PROP_ASYNC_CONTEXT:
+               priv->async_context = g_value_get_pointer (value);
+               if (priv->async_context)
+                       g_main_context_ref (priv->async_context);
+               break;
        default:
                break;
        }
@@ -221,6 +237,9 @@ get_property (GObject *object, guint prop_id,
        case PROP_SSL_KEY_FILE:
                g_value_set_string (value, g_strdup (priv->ssl_key_file));
                break;
+       case PROP_ASYNC_CONTEXT:
+               g_value_set_pointer (value, priv->async_context ? g_main_context_ref (priv->async_context) : NULL);
+               break;
        default:
                break;
        }
@@ -259,10 +278,10 @@ soup_server_new (const char *optname1, ...)
        }
 
        priv->listen_sock =
-               soup_socket_server_new (priv->interface,
-                                       priv->ssl_creds,
-                                       NULL, NULL);
-       if (!priv->listen_sock) {
+               soup_socket_new (SOUP_SOCKET_SSL_CREDENTIALS, priv->ssl_creds,
+                                SOUP_SOCKET_ASYNC_CONTEXT, priv->async_context,
+                                NULL);
+       if (!soup_socket_listen (priv->listen_sock, priv->interface)) {
                g_object_unref (server);
                return NULL;
        }
@@ -486,7 +505,7 @@ soup_server_run (SoupServer *server)
        priv = SOUP_SERVER_GET_PRIVATE (server);
 
        if (!priv->loop) {
-               priv->loop = g_main_loop_new (NULL, TRUE);
+               priv->loop = g_main_loop_new (priv->async_context, TRUE);
                soup_server_run_async (server);
        }
 
@@ -502,7 +521,9 @@ soup_server_quit (SoupServer *server)
        g_return_if_fail (SOUP_IS_SERVER (server));
        priv = SOUP_SERVER_GET_PRIVATE (server);
 
-       g_main_loop_quit (priv->loop);
+       if (priv->loop)
+               g_main_loop_quit (priv->loop);
+
        g_object_unref (server);
 }
 
index 40f7fad..c530a15 100644 (file)
@@ -64,6 +64,7 @@ struct SoupServerHandler {
 #define SOUP_SERVER_INTERFACE     "interface"
 #define SOUP_SERVER_SSL_CERT_FILE "ssl-cert-file"
 #define SOUP_SERVER_SSL_KEY_FILE  "ssl-key-file"
+#define SOUP_SERVER_ASYNC_CONTEXT "async-context"
 
 SoupServer        *soup_server_new            (const char            *optname1,
                                               ...) G_GNUC_NULL_TERMINATED;
index e9d3266..6381939 100644 (file)
@@ -54,6 +54,8 @@ typedef struct {
         * Must not emit signals or destroy objects while holding it.
         */
        GMutex *host_lock;
+
+       GMainContext *async_context;
 } SoupSessionPrivate;
 #define SOUP_SESSION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), SOUP_TYPE_SESSION, SoupSessionPrivate))
 
@@ -94,6 +96,7 @@ enum {
        PROP_MAX_CONNS_PER_HOST,
        PROP_USE_NTLM,
        PROP_SSL_CA_FILE,
+       PROP_ASYNC_CONTEXT,
 
        LAST_PROP
 };
@@ -165,6 +168,9 @@ finalize (GObject *object)
        g_hash_table_destroy (priv->hosts);
        g_hash_table_destroy (priv->conns);
 
+       if (priv->async_context)
+               g_main_context_unref (priv->async_context);
+
        G_OBJECT_CLASS (soup_session_parent_class)->finalize (object);
 }
 
@@ -307,6 +313,12 @@ soup_session_class_init (SoupSessionClass *session_class)
                                     "File containing SSL CA certificates",
                                     NULL,
                                     G_PARAM_READWRITE));
+       g_object_class_install_property (
+               object_class, PROP_ASYNC_CONTEXT,
+               g_param_spec_pointer (SOUP_SESSION_ASYNC_CONTEXT,
+                                     "Async GMainContext",
+                                     "The GMainContext to dispatch async I/O in",
+                                     G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 }
 
 static void
@@ -398,6 +410,11 @@ set_property (GObject *object, guint prop_id,
                }
 
                break;
+       case PROP_ASYNC_CONTEXT:
+               priv->async_context = g_value_get_pointer (value);
+               if (priv->async_context)
+                       g_main_context_ref (priv->async_context);
+               break;
        default:
                break;
        }
@@ -428,6 +445,9 @@ get_property (GObject *object, guint prop_id,
        case PROP_SSL_CA_FILE:
                g_value_set_string (value, priv->ssl_ca_file);
                break;
+       case PROP_ASYNC_CONTEXT:
+               g_value_set_pointer (value, priv->async_context ? g_main_context_ref (priv->async_context) : NULL);
+               break;
        default:
                break;
        }
@@ -1142,6 +1162,7 @@ soup_session_get_connection (SoupSession *session, SoupMessage *msg,
                SOUP_CONNECTION_PROXY_URI, priv->proxy_uri,
                SOUP_CONNECTION_SSL_CREDENTIALS, priv->ssl_creds,
                SOUP_CONNECTION_MESSAGE_FILTER, session,
+               SOUP_CONNECTION_ASYNC_CONTEXT, priv->async_context,
                NULL);
        g_signal_connect (conn, "connect_result",
                          G_CALLBACK (connect_result),
index cdafd96..b19f783 100644 (file)
@@ -53,6 +53,7 @@ GType soup_session_get_type (void);
 #define SOUP_SESSION_MAX_CONNS_PER_HOST "max-conns-per-host"
 #define SOUP_SESSION_USE_NTLM           "use-ntlm"
 #define SOUP_SESSION_SSL_CA_FILE        "ssl-ca-file"
+#define SOUP_SESSION_ASYNC_CONTEXT      "async-context"
 
 void            soup_session_add_filter       (SoupSession           *session,
                                               SoupMessageFilter     *filter);
index 1bd9869..a958af9 100644 (file)
@@ -45,6 +45,7 @@ enum {
        PROP_CLOEXEC,
        PROP_IS_SERVER,
        PROP_SSL_CREDENTIALS,
+       PROP_ASYNC_CONTEXT,
 
        LAST_PROP
 };
@@ -61,8 +62,9 @@ typedef struct {
        guint is_server:1;
        gpointer ssl_creds;
 
-       guint           watch;
-       guint           read_tag, write_tag, error_tag;
+       GMainContext   *async_context;
+       GSource        *watch_src;
+       GSource        *read_src, *write_src;
        GByteArray     *read_buf;
 
        GMutex *iolock, *addrlock;
@@ -112,17 +114,13 @@ disconnect_internal (SoupSocketPrivate *priv)
        priv->iochannel = NULL;
        priv->sockfd = -1;
 
-       if (priv->read_tag) {
-               g_source_remove (priv->read_tag);
-               priv->read_tag = 0;
+       if (priv->read_src) {
+               g_source_destroy (priv->read_src);
+               priv->read_src = NULL;
        }
-       if (priv->write_tag) {
-               g_source_remove (priv->write_tag);
-               priv->write_tag = 0;
-       }
-       if (priv->error_tag) {
-               g_source_remove (priv->error_tag);
-               priv->error_tag = 0;
+       if (priv->write_src) {
+               g_source_destroy (priv->write_src);
+               priv->write_src = NULL;
        }
 }
 
@@ -139,8 +137,10 @@ finalize (GObject *object)
        if (priv->remote_addr)
                g_object_unref (priv->remote_addr);
 
-       if (priv->watch)
-               g_source_remove (priv->watch);
+       if (priv->watch_src)
+               g_source_destroy (priv->watch_src);
+       if (priv->async_context)
+               g_main_context_unref (priv->async_context);
 
        if (priv->read_buf)
                g_byte_array_free (priv->read_buf, TRUE);
@@ -292,6 +292,12 @@ soup_socket_class_init (SoupSocketClass *socket_class)
                                      "SSL credentials",
                                      "SSL credential information, passed from the session to the SSL implementation",
                                      G_PARAM_READWRITE));
+       g_object_class_install_property (
+               object_class, PROP_ASYNC_CONTEXT,
+               g_param_spec_pointer (SOUP_SOCKET_ASYNC_CONTEXT,
+                                     "Async GMainContext",
+                                     "The GMainContext to dispatch this socket's async I/O in",
+                                     G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 
 #ifdef G_OS_WIN32
        /* Make sure WSAStartup() gets called. */
@@ -374,6 +380,11 @@ set_property (GObject *object, guint prop_id,
        case PROP_SSL_CREDENTIALS:
                priv->ssl_creds = g_value_get_pointer (value);
                break;
+       case PROP_ASYNC_CONTEXT:
+               priv->async_context = g_value_get_pointer (value);
+               if (priv->async_context)
+                       g_main_context_ref (priv->async_context);
+               break;
        default:
                break;
        }
@@ -404,6 +415,9 @@ get_property (GObject *object, guint prop_id,
        case PROP_SSL_CREDENTIALS:
                g_value_set_pointer (value, priv->ssl_creds);
                break;
+       case PROP_ASYNC_CONTEXT:
+               g_value_set_pointer (value, priv->async_context ? g_main_context_ref (priv->async_context) : NULL);
+               break;
        default:
                break;
        }
@@ -459,7 +473,7 @@ idle_connect_result (gpointer user_data)
        SoupSocket *sock = user_data;
        SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock);
 
-       priv->watch = 0;
+       priv->watch_src = NULL;
 
        g_signal_emit (sock, signals[CONNECT_RESULT], 0,
                       priv->sockfd != -1 ? SOUP_STATUS_OK : SOUP_STATUS_CANT_CONNECT);
@@ -475,8 +489,8 @@ connect_watch (GIOChannel* iochannel, GIOCondition condition, gpointer data)
        int len = sizeof (error);
 
        /* Remove the watch now in case we don't return immediately */
-       g_source_remove (priv->watch);
-       priv->watch = 0;
+       g_source_destroy (priv->watch_src);
+       priv->watch_src = NULL;
 
        if (condition & ~(G_IO_IN | G_IO_OUT))
                goto cant_connect;
@@ -570,12 +584,13 @@ soup_socket_connect (SoupSocket *sock, SoupAddress *remote_addr)
        if (SOUP_IS_SOCKET_ERROR (status)) {
                if (SOUP_IS_CONNECT_STATUS_INPROGRESS ()) {
                        /* Wait for connect to succeed or fail */
-                       priv->watch =
-                               g_io_add_watch (get_iochannel (priv),
-                                               G_IO_IN | G_IO_OUT |
-                                               G_IO_PRI | G_IO_ERR |
-                                               G_IO_HUP | G_IO_NVAL,
-                                               connect_watch, sock);
+                       priv->watch_src =
+                               soup_add_io_watch (priv->async_context,
+                                                  get_iochannel (priv),
+                                                  G_IO_IN | G_IO_OUT |
+                                                  G_IO_PRI | G_IO_ERR |
+                                                  G_IO_HUP | G_IO_NVAL,
+                                                  connect_watch, sock);
                        return SOUP_STATUS_CONTINUE;
                } else {
                        SOUP_CLOSE_SOCKET (priv->sockfd);
@@ -586,7 +601,8 @@ soup_socket_connect (SoupSocket *sock, SoupAddress *remote_addr)
 
  done:
        if (priv->non_blocking) {
-               priv->watch = g_idle_add (idle_connect_result, sock);
+               priv->watch_src = soup_add_idle (priv->async_context,
+                                                idle_connect_result, sock);
                return SOUP_STATUS_CONTINUE;
        } else if (SOUP_IS_INVALID_SOCKET (priv->sockfd))
                return SOUP_STATUS_CANT_CONNECT;
@@ -603,8 +619,8 @@ listen_watch (GIOChannel* iochannel, GIOCondition condition, gpointer data)
        int sa_len, sockfd;
 
        if (condition & (G_IO_HUP | G_IO_ERR)) {
-               g_source_remove (priv->watch);
-               priv->watch = 0;
+               g_source_destroy (priv->watch_src);
+               priv->watch_src = NULL;
                return FALSE;
        }
 
@@ -616,6 +632,8 @@ listen_watch (GIOChannel* iochannel, GIOCondition condition, gpointer data)
        new = g_object_new (SOUP_TYPE_SOCKET, NULL);
        new_priv = SOUP_SOCKET_GET_PRIVATE (new);
        new_priv->sockfd = sockfd;
+       if (priv->async_context)
+               new_priv->async_context = g_main_context_ref (priv->async_context);
        new_priv->non_blocking = priv->non_blocking;
        new_priv->nodelay = priv->nodelay;
        new_priv->is_server = TRUE;
@@ -658,10 +676,11 @@ soup_socket_listen (SoupSocket *sock, SoupAddress *local_addr)
 
        g_return_val_if_fail (SOUP_IS_SOCKET (sock), FALSE);
        priv = SOUP_SOCKET_GET_PRIVATE (sock);
-       g_return_val_if_fail (priv->is_server, FALSE);
        g_return_val_if_fail (priv->sockfd == -1, FALSE);
        g_return_val_if_fail (SOUP_IS_ADDRESS (local_addr), FALSE);
 
+       priv->is_server = TRUE;
+
        /* @local_addr may have its port set to 0. So we intentionally
         * don't store it in priv->local_addr, so that if the
         * caller calls soup_socket_get_local_address() later, we'll
@@ -684,9 +703,10 @@ soup_socket_listen (SoupSocket *sock, SoupAddress *local_addr)
        if (listen (priv->sockfd, 10) != 0)
                goto cant_listen;
 
-       priv->watch = g_io_add_watch (get_iochannel (priv),
-                                     G_IO_IN | G_IO_ERR | G_IO_HUP,
-                                     listen_watch, sock);
+       priv->watch_src = soup_add_io_watch (priv->async_context,
+                                            get_iochannel (priv),
+                                            G_IO_IN | G_IO_ERR | G_IO_HUP,
+                                            listen_watch, sock);
        return TRUE;
 
  cant_listen:
@@ -755,6 +775,9 @@ soup_socket_start_proxy_ssl (SoupSocket *sock, const char *ssl_host)
  * Creates a connection to @hostname and @port. @callback will be
  * called when the connection completes (or fails).
  *
+ * Uses the default #GMainContext. If you need to use an alternate
+ * context, use soup_socket_new() and soup_socket_connect() directly.
+ *
  * Return value: the new socket (not yet ready for use).
  **/
 SoupSocket *
@@ -835,6 +858,9 @@ soup_socket_client_new_sync (const char *hostname, guint port,
  * address. @callback will be called each time a client connects,
  * with a new #SoupSocket.
  *
+ * Uses the default #GMainContext. If you need to use an alternate
+ * context, use soup_socket_new() and soup_socket_listen() directly.
+ *
  * Returns: a new #SoupSocket, or NULL if there was a failure.
  **/
 SoupSocket *
@@ -851,7 +877,6 @@ soup_socket_server_new (SoupAddress *local_addr, gpointer ssl_creds,
                             SOUP_SOCKET_SSL_CREDENTIALS, ssl_creds,
                             NULL);
        priv = SOUP_SOCKET_GET_PRIVATE (sock);
-       priv->is_server = TRUE;
        if (!soup_socket_listen (sock, local_addr)) {
                g_object_unref (sock);
                return NULL;
@@ -1007,7 +1032,7 @@ socket_read_watch (GIOChannel *chan, GIOCondition cond, gpointer user_data)
        SoupSocket *sock = user_data;
        SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock);
 
-       priv->read_tag = 0;
+       priv->read_src = NULL;
 
        if (cond & (G_IO_ERR | G_IO_HUP))
                soup_socket_disconnect (sock);
@@ -1049,11 +1074,12 @@ read_from_network (SoupSocket *sock, gpointer buffer, gsize len, gsize *nread)
                if (*nread > 0)
                        return SOUP_SOCKET_OK;
 
-               if (!priv->read_tag) {
-                       priv->read_tag =
-                               g_io_add_watch (priv->iochannel,
-                                               cond | G_IO_HUP | G_IO_ERR,
-                                               socket_read_watch, sock);
+               if (!priv->read_src) {
+                       priv->read_src =
+                               soup_add_io_watch (priv->async_context,
+                                                  priv->iochannel,
+                                                  cond | G_IO_HUP | G_IO_ERR,
+                                                  socket_read_watch, sock);
                }
                return SOUP_SOCKET_WOULD_BLOCK;
 
@@ -1210,7 +1236,7 @@ socket_write_watch (GIOChannel *chan, GIOCondition cond, gpointer user_data)
        SoupSocket *sock = user_data;
        SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock);
 
-       priv->write_tag = 0;
+       priv->write_src = NULL;
 
        if (cond & (G_IO_ERR | G_IO_HUP))
                soup_socket_disconnect (sock);
@@ -1262,7 +1288,7 @@ soup_socket_write (SoupSocket *sock, gconstpointer buffer,
                g_mutex_unlock (priv->iolock);
                return SOUP_SOCKET_EOF;
        }
-       if (priv->write_tag) {
+       if (priv->write_src) {
                g_mutex_unlock (priv->iolock);
                return SOUP_SOCKET_WOULD_BLOCK;
        }
@@ -1298,10 +1324,11 @@ soup_socket_write (SoupSocket *sock, gconstpointer buffer,
                return SOUP_SOCKET_OK;
        }
 
-       priv->write_tag =
-               g_io_add_watch (priv->iochannel,
-                               cond | G_IO_HUP | G_IO_ERR, 
-                               socket_write_watch, sock);
+       priv->write_src =
+               soup_add_io_watch (priv->async_context,
+                                  priv->iochannel,
+                                  cond | G_IO_HUP | G_IO_ERR, 
+                                  socket_write_watch, sock);
        g_mutex_unlock (priv->iolock);
        return SOUP_SOCKET_WOULD_BLOCK;
 }
index ba7ccae..0f95dc6 100644 (file)
@@ -38,6 +38,7 @@ typedef struct {
 #define SOUP_SOCKET_FLAG_CLOEXEC     "cloexec"
 #define SOUP_SOCKET_IS_SERVER        "is-server"
 #define SOUP_SOCKET_SSL_CREDENTIALS  "ssl-creds"
+#define SOUP_SOCKET_ASYNC_CONTEXT    "async-context"
 
 /**
  * SoupSocketCallback: