Beginnings of improved synchronous API support
authorDan Winship <danw@src.gnome.org>
Tue, 9 Sep 2003 15:33:48 +0000 (15:33 +0000)
committerDan Winship <danw@src.gnome.org>
Tue, 9 Sep 2003 15:33:48 +0000 (15:33 +0000)
* libsoup/soup-dns.c: Simplify this by making it not automatically
return the result: force the caller to poll. (This isn't really a
performance issue: the results should come back quickly anyway.)
Also, make the cache thread-safe.
(soup_dns_entry_from_name): Was soup_gethostbyname
(soup_dns_entry_from_addr): Was soup_gethostbyaddr
(soup_dns_entry_check_lookup): Used to poll to see if DNS is done
(soup_dns_entry_get_hostent): Gets the hostent from an entry (and
blocks if it's not resolved yet).

* libsoup/soup-address.c: Update for soup-dns changes.
(soup_address_new): Don't automatically start resolving the
hostname now, since we don't know if the caller is going to want
it resolved synchronously or asynchronously.
(soup_address_resolve_async): Renamed from soup_address_resolve.
(soup_address_resolve_sync): New routine to do blocking
synchronous DNS.

* libsoup/soup-socket.c (soup_socket_connect): Now returns a
status value directly when connecting synchronously.
(soup_socket_client_new_async, soup_socket_client_new_sync):
Separate async/sync client socket functions.
(soup_socket_get_iochannel): Made static since it was not used
outside soup-socket.

* libsoup/soup-connection.c (soup_connection_new,
soup_connection_new_proxy, soup_connection_new_tunnel): Just set
up the data, don't actually start connecting.
(soup_connection_connect_async, soup_connection_connect_sync): New
async and sync SoupConnection connecting routines.
(soup_connection_get_socket): Remove this since it wasn't being
used.

* libsoup/soup-session.c (final_finished): Run the queue since a
connection is now freed up.
(run_queue): Update for soup_connection_new* changes.

* libsoup/soup-misc.c (soup_substring_index): Remove, since it
wasn't being used any more.

* libsoup/soup-private.h: Remove some prototypes for functions
that no longer exist.

* libsoup/soup-uri.c (soup_uri_copy_root): New utility function
(copies the protocol, host, and port of a SoupUri).

* tests/auth-test.c:
* tests/get.c:
* tests/simple-proxy.c: belatedly update for soup-session change

* tests/revserver.c: Handle each new connection in its own thread,
using synchronous SoupSocket calls.

19 files changed:
ChangeLog
libsoup/soup-address.c
libsoup/soup-address.h
libsoup/soup-connection.c
libsoup/soup-connection.h
libsoup/soup-dns.c
libsoup/soup-dns.h
libsoup/soup-misc.c
libsoup/soup-private.h
libsoup/soup-session.c
libsoup/soup-socket.c
libsoup/soup-socket.h
libsoup/soup-uri.c
libsoup/soup-uri.h
tests/Makefile.am
tests/auth-test.c
tests/get.c
tests/revserver.c
tests/simple-proxy.c

index ab34f5e..e4b216b 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,60 @@
+2003-09-09  Dan Winship  <danw@ximian.com>
+
+       Beginnings of improved synchronous API support
+
+       * libsoup/soup-dns.c: Simplify this by making it not automatically
+       return the result: force the caller to poll. (This isn't really a
+       performance issue: the results should come back quickly anyway.)
+       Also, make the cache thread-safe.
+       (soup_dns_entry_from_name): Was soup_gethostbyname
+       (soup_dns_entry_from_addr): Was soup_gethostbyaddr
+       (soup_dns_entry_check_lookup): Used to poll to see if DNS is done
+       (soup_dns_entry_get_hostent): Gets the hostent from an entry (and
+       blocks if it's not resolved yet).
+
+       * libsoup/soup-address.c: Update for soup-dns changes.
+       (soup_address_new): Don't automatically start resolving the
+       hostname now, since we don't know if the caller is going to want
+       it resolved synchronously or asynchronously.
+       (soup_address_resolve_async): Renamed from soup_address_resolve.
+       (soup_address_resolve_sync): New routine to do blocking
+       synchronous DNS.
+
+       * libsoup/soup-socket.c (soup_socket_connect): Now returns a
+       status value directly when connecting synchronously.
+       (soup_socket_client_new_async, soup_socket_client_new_sync):
+       Separate async/sync client socket functions.
+       (soup_socket_get_iochannel): Made static since it was not used
+       outside soup-socket.
+
+       * libsoup/soup-connection.c (soup_connection_new,
+       soup_connection_new_proxy, soup_connection_new_tunnel): Just set
+       up the data, don't actually start connecting.
+       (soup_connection_connect_async, soup_connection_connect_sync): New
+       async and sync SoupConnection connecting routines.
+       (soup_connection_get_socket): Remove this since it wasn't being
+       used.
+
+       * libsoup/soup-session.c (final_finished): Run the queue since a
+       connection is now freed up.
+       (run_queue): Update for soup_connection_new* changes.
+
+       * libsoup/soup-misc.c (soup_substring_index): Remove, since it
+       wasn't being used any more.
+
+       * libsoup/soup-private.h: Remove some prototypes for functions
+       that no longer exist.
+
+       * libsoup/soup-uri.c (soup_uri_copy_root): New utility function
+       (copies the protocol, host, and port of a SoupUri).
+
+       * tests/auth-test.c:
+       * tests/get.c:
+       * tests/simple-proxy.c: belatedly update for soup-session change
+
+       * tests/revserver.c: Handle each new connection in its own thread,
+       using synchronous SoupSocket calls.
+
 2003-09-05  Dan Winship  <danw@ximian.com>
 
        * libsoup/soup-session.c: Move a bunch of logic here from
index b4baf20..a59a4c4 100644 (file)
@@ -46,7 +46,7 @@ struct SoupAddressPrivate {
        char *name, *physical;
        guint port;
 
-       SoupDNSHandle lookup;
+       SoupDNSEntry *lookup;
        guint idle_id;
 };
 
@@ -119,7 +119,7 @@ finalize (GObject *object)
                g_free (addr->priv->physical);
 
        if (addr->priv->lookup)
-               soup_gethostby_cancel (addr->priv->lookup);
+               soup_dns_entry_cancel_lookup (addr->priv->lookup);
        if (addr->priv->idle_id)
                g_source_remove (addr->priv->idle_id);
 
@@ -158,10 +158,9 @@ SOUP_MAKE_TYPE (soup_address, SoupAddress, class_init, init, PARENT_TYPE)
  * @port: a port number
  *
  * Creates a #SoupAddress from @name and @port. The #SoupAddress's IP
- * address will not be available right away; the caller can listen for
- * a #dns_result signal to know when @name has been resolved.
- *
- * The DNS lookup can be cancelled by destroying the address object.
+ * address may not be available right away; the caller can call
+ * soup_address_resolve_async() or soup_address_resolve_sync() to
+ * force a DNS resolution.
  *
  * Return value: a #SoupAddress
  **/
@@ -177,9 +176,6 @@ soup_address_new (const char *name, guint port)
        addr->priv->name = g_strdup (name);
        addr->priv->port = port;
 
-       /* Start a lookup */
-       soup_address_resolve (addr, NULL, NULL);
-
        return addr;
 }
 
@@ -288,8 +284,9 @@ soup_address_get_physical (SoupAddress *addr)
                return NULL;
 
        if (!addr->priv->physical) {
-               addr->priv->physical = soup_ntop (SOUP_ADDRESS_DATA (addr),
-                                                 SOUP_ADDRESS_FAMILY (addr));
+               addr->priv->physical =
+                       soup_dns_ntop (SOUP_ADDRESS_DATA (addr),
+                                      SOUP_ADDRESS_FAMILY (addr));
        }
 
        return addr->priv->physical;
@@ -310,72 +307,70 @@ soup_address_get_port (SoupAddress *addr)
 }
 
 
-
-static void
-got_addr (SoupDNSHandle handle, guint status, struct hostent *h, gpointer data)
+static guint
+update_address_from_entry (SoupAddress *addr, SoupDNSEntry *entry)
 {
-       SoupAddress *addr = data;
+       struct hostent *h;
 
-       addr->priv->lookup = NULL;
+       h = soup_dns_entry_get_hostent (addr->priv->lookup);
 
-       if (status == SOUP_STATUS_OK) {
-               if (!SOUP_ADDRESS_FAMILY_IS_VALID (h->h_addrtype)) {
-                       status = SOUP_STATUS_CANT_RESOLVE;
-                       goto done;
-               }
-               if (SOUP_ADDRESS_FAMILY_DATA_SIZE (h->h_addrtype) != h->h_length) {
-                       status = SOUP_STATUS_MALFORMED;
-                       goto done;
-               }
+       if (!addr->priv->name)
+               addr->priv->name = g_strdup (h->h_name);
 
+       if (!addr->priv->sockaddr &&
+           SOUP_ADDRESS_FAMILY_IS_VALID (h->h_addrtype) &&
+           SOUP_ADDRESS_FAMILY_DATA_SIZE (h->h_addrtype) == h->h_length) {
                addr->priv->sockaddr = g_malloc0 (SOUP_ADDRESS_FAMILY_SOCKADDR_SIZE (h->h_addrtype));
                SOUP_ADDRESS_FAMILY (addr) = h->h_addrtype;
                SOUP_ADDRESS_PORT (addr) = htons (addr->priv->port);
                memcpy (SOUP_ADDRESS_DATA (addr), h->h_addr, h->h_length);
        }
 
- done:
-       g_signal_emit (addr, signals[DNS_RESULT], 0, status);
-}
-
-static void
-got_name (SoupDNSHandle handle, guint status, struct hostent *h, gpointer data)
-{
-       SoupAddress *addr = data;
-
-       addr->priv->lookup = NULL;
-
-       if (status == SOUP_STATUS_OK)
-               addr->priv->name = g_strdup (h->h_name);
-
-       g_signal_emit (addr, signals[DNS_RESULT], 0, status);
+       if (addr->priv->name && addr->priv->sockaddr)
+               return SOUP_STATUS_OK;
+       else
+               return SOUP_STATUS_CANT_RESOLVE;
 }
 
 static gboolean
-idle_dns_result (gpointer user_data)
+idle_check_lookup (gpointer user_data)
 {
        SoupAddress *addr = user_data;
+       guint status;
 
+       if (addr->priv->name && addr->priv->sockaddr) {
+               addr->priv->idle_id = 0;
+               g_signal_emit (addr, signals[DNS_RESULT], 0, SOUP_STATUS_OK);
+               return FALSE;
+       }
+
+       if (!soup_dns_entry_check_lookup (addr->priv->lookup))
+               return TRUE;
+
+       status = update_address_from_entry (addr, addr->priv->lookup);
+       addr->priv->lookup = NULL;
        addr->priv->idle_id = 0;
-       g_signal_emit (addr, signals[DNS_RESULT], 0, SOUP_STATUS_OK);
+
+       g_signal_emit (addr, signals[DNS_RESULT], 0, status);
        return FALSE;
 }
 
 /**
- * soup_address_resolve:
+ * soup_address_resolve_async:
  * @addr: a #SoupAddress
  * @callback: callback to call with the result
  * @user_data: data for @callback
  *
- * Asynchronously resolves the missing half of @addr. (It's IP address
- * if it was created with soup_address_new(), or it's hostname if it
+ * Asynchronously resolves the missing half of @addr. (Its IP address
+ * if it was created with soup_address_new(), or its hostname if it
  * was created with soup_address_new_from_sockaddr() or
  * soup_address_new_any().) @callback will be called when the
  * resolution finishes (successfully or not).
  **/
 void
-soup_address_resolve (SoupAddress *addr,
-                     SoupAddressCallback callback, gpointer user_data)
+soup_address_resolve_async (SoupAddress *addr,
+                           SoupAddressCallback callback,
+                           gpointer user_data)
 {
        g_return_if_fail (SOUP_IS_ADDRESS (addr));
 
@@ -384,22 +379,43 @@ soup_address_resolve (SoupAddress *addr,
                                          G_CALLBACK (callback), user_data);
        }
 
-       if (addr->priv->lookup)
-               return;
-
-       if (addr->priv->name && addr->priv->sockaddr) {
-               addr->priv->idle_id = g_idle_add (idle_dns_result, addr);
+       if (addr->priv->idle_id)
                return;
-       }
 
-       if (addr->priv->name) {
+       if (!addr->priv->sockaddr) {
                addr->priv->lookup =
-                       soup_gethostbyname (addr->priv->name,
-                                           got_addr, addr);
-       } else {
+                       soup_dns_entry_from_name (addr->priv->name);
+       } else if (!addr->priv->name) {
                addr->priv->lookup =
-                       soup_gethostbyaddr (SOUP_ADDRESS_DATA (addr),
-                                           SOUP_ADDRESS_FAMILY (addr),
-                                           got_name, addr);
+                       soup_dns_entry_from_addr (SOUP_ADDRESS_DATA (addr),
+                                                 SOUP_ADDRESS_FAMILY (addr));
+       }
+
+       addr->priv->idle_id = g_idle_add (idle_check_lookup, addr);
+}
+
+/**
+ * soup_address_resolve_sync:
+ * @addr: a #SoupAddress
+ *
+ * Synchronously resolves the missing half of @addr, as with
+ * soup_address_resolve_async().
+ *
+ * Return value: %SOUP_STATUS_OK or %SOUP_ERROR_CANT_RESOLVE
+ **/
+guint
+soup_address_resolve_sync (SoupAddress *addr)
+{
+       SoupDNSEntry *entry;
+
+       g_return_val_if_fail (SOUP_IS_ADDRESS (addr), SOUP_STATUS_MALFORMED);
+
+       if (addr->priv->name)
+               entry = soup_dns_entry_from_name (addr->priv->name);
+       else {
+               entry = soup_dns_entry_from_addr (SOUP_ADDRESS_DATA (addr),
+                                                 SOUP_ADDRESS_FAMILY (addr));
        }
+
+       return update_address_from_entry (addr, entry);
 }
index 2a1ed38..b9946f5 100644 (file)
@@ -56,9 +56,10 @@ SoupAddress     *soup_address_new_any            (SoupAddressFamily    family,
 typedef void   (*SoupAddressCallback)            (SoupAddress         *addr,
                                                  guint                status,
                                                  gpointer             data);
-void             soup_address_resolve            (SoupAddress         *addr,
+void             soup_address_resolve_async      (SoupAddress         *addr,
                                                  SoupAddressCallback  cb,
                                                  gpointer             data);
+guint            soup_address_resolve_sync       (SoupAddress         *addr);
 
 const char      *soup_address_get_name           (SoupAddress         *addr);
 struct sockaddr *soup_address_get_sockaddr       (SoupAddress         *addr,
index fd9182d..8e9a7e8 100644 (file)
@@ -30,8 +30,7 @@
 
 struct SoupConnectionPrivate {
        SoupSocket  *socket;
-       SoupUri     *dest_uri;
-       gboolean     is_proxy;
+       SoupUri     *proxy_uri, *dest_uri;
        time_t       last_used;
 
        SoupMessage *cur_req;
@@ -63,6 +62,8 @@ finalize (GObject *object)
 {
        SoupConnection *conn = SOUP_CONNECTION (object);
 
+       if (conn->priv->proxy_uri)
+               soup_uri_free (conn->priv->proxy_uri);
        if (conn->priv->dest_uri)
                soup_uri_free (conn->priv->dest_uri);
 
@@ -115,158 +116,215 @@ class_init (GObjectClass *object_class)
 SOUP_MAKE_TYPE (soup_connection, SoupConnection, class_init, init, PARENT_TYPE)
 
 
-static void
-socket_disconnected (SoupSocket *sock, gpointer conn)
-{
-       soup_connection_disconnect (conn);
-}
-
-static SoupConnection *
-connection_new (const SoupUri *uri, gboolean is_proxy,
-               SoupSocketCallback connect_callback,
-               SoupConnectionCallback user_callback,
-               gpointer user_data)
+/**
+ * soup_connection_new:
+ * @uri: remote machine to connect to
+ *
+ * Creates a connection to @uri. You must call
+ * soup_connection_connect_async() or soup_connection_connect_sync()
+ * to connect it after creating it.
+ *
+ * Return value: the new connection (not yet ready for use).
+ **/
+SoupConnection *
+soup_connection_new (const SoupUri *uri)
 {
        SoupConnection *conn;
 
        conn = g_object_new (SOUP_TYPE_CONNECTION, NULL);
-       conn->priv->is_proxy = is_proxy;
-
-       soup_signal_connect_once (conn, "connect_result",
-                                 G_CALLBACK (user_callback), user_data);
+       conn->priv->dest_uri = soup_uri_copy_root (uri);
 
-       conn->priv->socket = soup_socket_client_new (uri->host, uri->port,
-                                                    uri->protocol == SOUP_PROTOCOL_HTTPS,
-                                                    connect_callback, conn);
-       g_signal_connect (conn->priv->socket, "disconnected",
-                         G_CALLBACK (socket_disconnected), conn);
        return conn;
 }
 
-static void
-socket_connected (SoupSocket *sock, guint status, gpointer conn)
-{
-       g_signal_emit (conn, signals[CONNECT_RESULT], 0, status);
-}
-
 /**
- * soup_connection_new:
- * @uri: remote machine to connect to
- * @callback: callback to call after connecting
- * @user_data: data for @callback
+ * soup_connection_new_proxy:
+ * @proxy_uri: proxy to connect to
  *
- * Creates a connection to @uri. @callback will be called when the
- * connection completes (or fails).
+ * Creates a connection to @proxy_uri. As with soup_connection_new(),
+ * the returned object is not yet connected.
  *
  * Return value: the new connection (not yet ready for use).
  **/
 SoupConnection *
-soup_connection_new (const SoupUri *uri,
-                    SoupConnectionCallback callback, gpointer user_data)
+soup_connection_new_proxy (const SoupUri *proxy_uri)
 {
-       return connection_new (uri, FALSE, socket_connected,
-                              callback, user_data);
-}
+       SoupConnection *conn;
 
-static void
-proxy_socket_connected (SoupSocket *sock, guint status, gpointer conn)
-{
-       if (status == SOUP_STATUS_CANT_RESOLVE)
-               status = SOUP_STATUS_CANT_RESOLVE_PROXY;
-       else if (status == SOUP_STATUS_CANT_CONNECT)
-               status = SOUP_STATUS_CANT_CONNECT_PROXY;
+       conn = g_object_new (SOUP_TYPE_CONNECTION, NULL);
+       conn->priv->proxy_uri = soup_uri_copy_root (proxy_uri);
 
-       g_signal_emit (conn, signals[CONNECT_RESULT], 0, status);
+       return conn;
 }
 
 /**
- * soup_connection_new_proxy:
+ * soup_connection_new_tunnel:
  * @proxy_uri: proxy to connect to
- * @callback: callback to call after connecting
- * @user_data: data for @callback
+ * @dest_uri: remote machine to ask the proxy to connect to
  *
- * Creates a connection to @proxy_uri. @callback will be called when
- * the connection completes (or fails).
+ * Creates a connection to @uri via @proxy_uri. As with
+ * soup_connection_new(), the returned object is not yet connected.
  *
  * Return value: the new connection (not yet ready for use).
  **/
 SoupConnection *
-soup_connection_new_proxy (const SoupUri *proxy_uri,
-                          SoupConnectionCallback callback,
-                          gpointer user_data)
+soup_connection_new_tunnel (const SoupUri *proxy_uri, const SoupUri *dest_uri)
 {
-       return connection_new (proxy_uri, TRUE, proxy_socket_connected,
-                              callback, user_data);
+       SoupConnection *conn;
+
+       conn = g_object_new (SOUP_TYPE_CONNECTION, NULL);
+       conn->priv->dest_uri = soup_uri_copy_root (dest_uri);
+       conn->priv->proxy_uri = soup_uri_copy_root (proxy_uri);
+
+       return conn;
 }
 
+
 static void
-tunnel_connected (SoupMessage *msg, gpointer user_data)
+socket_disconnected (SoupSocket *sock, gpointer conn)
 {
-       SoupConnection *conn = user_data;
+       soup_connection_disconnect (conn);
+}
 
-       if (SOUP_STATUS_IS_SUCCESSFUL (msg->status_code))
-               soup_socket_start_ssl (conn->priv->socket);
+static inline guint
+proxified_status (SoupConnection *conn, guint status)
+{
+       if (!conn->priv->proxy_uri)
+               return status;
 
-       proxy_socket_connected (NULL, msg->status_code, conn);
-       g_object_unref (msg);
+       if (status == SOUP_STATUS_CANT_RESOLVE)
+               return SOUP_STATUS_CANT_RESOLVE_PROXY;
+       else if (status == SOUP_STATUS_CANT_CONNECT)
+               return SOUP_STATUS_CANT_CONNECT_PROXY;
+       else
+               return status;
 }
 
 static void
-tunnel_failed (SoupMessage *msg, gpointer conn)
+tunnel_connect_finished (SoupMessage *msg, gpointer user_data)
 {
+       SoupConnection *conn = user_data;
+
+       if (SOUP_STATUS_IS_SUCCESSFUL (msg->status_code))
+               soup_socket_start_ssl (conn->priv->socket);
+
        g_signal_emit (conn, signals[CONNECT_RESULT], 0,
-                      SOUP_STATUS_CANT_CONNECT);
+                      proxified_status (conn, msg->status_code));
        g_object_unref (msg);
 }
 
 static void
-tunnel_socket_connected (SoupSocket *sock, guint status, gpointer user_data)
+socket_connect_result (SoupSocket *sock, guint status, gpointer user_data)
 {
        SoupConnection *conn = user_data;
-       SoupMessage *connect_msg;
 
        if (!SOUP_STATUS_IS_SUCCESSFUL (status)) {
-               socket_connected (sock, status, conn);
+               g_signal_emit (conn, signals[CONNECT_RESULT], 0,
+                              proxified_status (conn, status));
                return;
        }
 
-       connect_msg = soup_message_new_from_uri (SOUP_METHOD_CONNECT,
-                                                conn->priv->dest_uri);
-       g_signal_connect (connect_msg, "read_body",
-                         G_CALLBACK (tunnel_connected), conn);
-       g_signal_connect (connect_msg, "write_error",
-                         G_CALLBACK (tunnel_failed), conn);
-       g_signal_connect (connect_msg, "read_error",
-                         G_CALLBACK (tunnel_failed), conn);
+       /* See if we need to tunnel */
+       if (conn->priv->proxy_uri && conn->priv->dest_uri) {
+               SoupMessage *connect_msg;
 
-       soup_connection_send_request (conn, connect_msg);
+               connect_msg = soup_message_new_from_uri (SOUP_METHOD_CONNECT,
+                                                        conn->priv->dest_uri);
+               g_signal_connect (connect_msg, "finished",
+                                 G_CALLBACK (tunnel_connect_finished), conn);
+
+               soup_connection_send_request (conn, connect_msg);
+               return;
+       }
+
+       g_signal_emit (conn, signals[CONNECT_RESULT], 0, status);
 }
 
 /**
- * soup_connection_new_tunnel:
- * @proxy_uri: proxy to connect to
- * @dest_uri: remote machine to ask the proxy to connect to
- * @callback: callback to call after connecting
+ * soup_connection_connect_async:
+ * @conn: the connection
+ * @ac: the async context to use
+ * @callback: callback to call when the connection succeeds or fails
  * @user_data: data for @callback
  *
- * Creates a connection to @uri via @proxy_uri. @callback will be
- * called when the connection completes (or fails).
+ * Asynchronously connects @conn.
+ **/
+void
+soup_connection_connect_async (SoupConnection *conn,
+                              SoupConnectionCallback callback,
+                              gpointer user_data)
+{
+       const SoupUri *uri;
+
+       g_return_if_fail (SOUP_IS_CONNECTION (conn));
+       g_return_if_fail (conn->priv->socket == NULL);
+
+       if (callback) {
+               soup_signal_connect_once (conn, "connect_result",
+                                         G_CALLBACK (callback), user_data);
+       }
+
+       if (conn->priv->proxy_uri)
+               uri = conn->priv->proxy_uri;
+       else
+               uri = conn->priv->dest_uri;
+
+       conn->priv->socket =
+               soup_socket_client_new_async (uri->host, uri->port,
+                                             uri->protocol == SOUP_PROTOCOL_HTTPS,
+                                             socket_connect_result, conn);
+       g_signal_connect (conn->priv->socket, "disconnected",
+                         G_CALLBACK (socket_disconnected), conn);
+}
+
+/**
+ * soup_connection_connect_sync:
+ * @conn: the connection
+ *
+ * Synchronously connects @conn.
  *
- * Return value: the new connection (not yet ready for use).
+ * Return value: the soup status
  **/
-SoupConnection *
-soup_connection_new_tunnel (const SoupUri *proxy_uri, const SoupUri *dest_uri,
-                           SoupConnectionCallback callback,
-                           gpointer user_data)
+guint
+soup_connection_connect_sync (SoupConnection *conn)
 {
-       SoupConnection *conn;
+       const SoupUri *uri;
+       guint status;
+
+       g_return_val_if_fail (SOUP_IS_CONNECTION (conn), SOUP_STATUS_MALFORMED);
+       g_return_val_if_fail (conn->priv->socket == NULL, SOUP_STATUS_MALFORMED);
+
+       if (conn->priv->proxy_uri)
+               uri = conn->priv->proxy_uri;
+       else
+               uri = conn->priv->dest_uri;
+
+       conn->priv->socket =
+               soup_socket_client_new_sync (uri->host, uri->port,
+                                            uri->protocol == SOUP_PROTOCOL_HTTPS,
+                                            &status);
+
+       if (SOUP_STATUS_IS_SUCCESSFUL (status) &&
+           conn->priv->proxy_uri && conn->priv->dest_uri) {
+               SoupMessage *connect_msg;
+
+               connect_msg = soup_message_new_from_uri (SOUP_METHOD_CONNECT,
+                                                        conn->priv->dest_uri);
+               soup_connection_send_request (conn, connect_msg);
+               status = connect_msg->status_code;
+               g_object_unref (connect_msg);
+       }
 
-       conn = connection_new (proxy_uri, TRUE, tunnel_socket_connected,
-                              callback, user_data);
-       conn->priv->dest_uri = soup_uri_copy (dest_uri);
-       return conn;
+       if (!SOUP_STATUS_IS_SUCCESSFUL (status)) {
+               if (conn->priv->socket)
+                       g_object_unref (conn->priv->socket);
+               conn->priv->socket = NULL;
+       }
+
+       return proxified_status (conn, status);
 }
 
+
 /**
  * soup_connection_disconnect:
  * @conn: a connection
@@ -297,20 +355,6 @@ soup_connection_is_connected (SoupConnection *conn)
        return conn->priv->socket != NULL;
 }
 
-/**
- * soup_connection_get_socket:
- * @conn: a #SoupConnection.
- *
- * Return value: @conn's socket
- */
-SoupSocket *
-soup_connection_get_socket (SoupConnection *conn)
-{
-       g_return_val_if_fail (SOUP_IS_CONNECTION (conn), NULL);
-
-       return conn->priv->socket;
-}
-
 
 /**
  * soup_connection_is_in_use:
@@ -388,5 +432,5 @@ soup_connection_send_request (SoupConnection *conn, SoupMessage *req)
        g_signal_connect (req, "finished", G_CALLBACK (request_done), conn);
 
        soup_message_send_request (req, conn->priv->socket,
-                                  conn->priv->is_proxy);
+                                  conn->priv->proxy_uri != NULL);
 }
index 8dd7762..449743e 100644 (file)
@@ -36,33 +36,28 @@ typedef struct {
 GType soup_connection_get_type (void);
 
 
-typedef void  (*SoupConnectionCallback)        (SoupConnection *sock,
-                                               guint           status,
-                                               gpointer        data);
+typedef void  (*SoupConnectionCallback)        (SoupConnection   *sock,
+                                               guint             status,
+                                               gpointer          data);
 
-SoupConnection *soup_connection_new            (const SoupUri  *uri,
-                                               SoupConnectionCallback,
-                                               gpointer        data);
-SoupConnection *soup_connection_new_proxy      (const SoupUri  *proxy_uri,
-                                               SoupConnectionCallback,
-                                               gpointer        data);
-SoupConnection *soup_connection_new_tunnel     (const SoupUri  *proxy_uri,
-                                               const SoupUri  *dest_uri,
-                                               SoupConnectionCallback,
-                                               gpointer        data);
+SoupConnection *soup_connection_new            (const SoupUri    *uri);
+SoupConnection *soup_connection_new_proxy      (const SoupUri    *proxy_uri);
+SoupConnection *soup_connection_new_tunnel     (const SoupUri    *proxy_uri,
+                                               const SoupUri    *dest_uri);
 
-gboolean        soup_connection_is_proxy       (SoupConnection *conn);
-
-void            soup_connection_disconnect     (SoupConnection *conn);
-gboolean        soup_connection_is_connected   (SoupConnection *conn);
+void            soup_connection_connect_async  (SoupConnection   *conn,
+                                               SoupConnectionCallback,
+                                               gpointer          user_data);
+guint           soup_connection_connect_sync   (SoupConnection   *conn);
 
-SoupSocket     *soup_connection_get_socket     (SoupConnection *conn);
+void            soup_connection_disconnect     (SoupConnection   *conn);
+gboolean        soup_connection_is_connected   (SoupConnection   *conn);
 
-gboolean        soup_connection_is_new         (SoupConnection *conn);
-gboolean        soup_connection_is_in_use      (SoupConnection *conn);
-time_t          soup_connection_last_used      (SoupConnection *conn);
+gboolean        soup_connection_is_new         (SoupConnection   *conn);
+gboolean        soup_connection_is_in_use      (SoupConnection   *conn);
+time_t          soup_connection_last_used      (SoupConnection   *conn);
 
-void            soup_connection_send_request   (SoupConnection *conn,
-                                               SoupMessage    *req);
+void            soup_connection_send_request   (SoupConnection   *conn,
+                                               SoupMessage      *req);
 
 #endif /* SOUP_CONNECTION_H */
index 31e473d..77d132d 100644 (file)
@@ -15,8 +15,8 @@
 #include <string.h>
 #include <time.h>
 #include <unistd.h>
+#include <sys/select.h>
 #include <sys/types.h>
-#include <sys/uio.h>
 #include <sys/wait.h>
 
 #include <arpa/inet.h>
@@ -62,8 +62,8 @@ copy_hostent (struct hostent *h)
                            h->h_length, h->h_addr_list[0]);
 }
 
-static void
-free_hostent (struct hostent *h)
+void
+soup_dns_free_hostent (struct hostent *h)
 {
        g_free (h->h_name);
        g_free (h->h_addr_list[0]);
@@ -123,7 +123,7 @@ new_hostent_from_phys (const char *addr)
 }
 
 char *
-soup_ntop (gconstpointer addr, int family)
+soup_dns_ntop (gconstpointer addr, int family)
 {
        switch (family) {
        case AF_INET:
@@ -154,14 +154,6 @@ soup_ntop (gconstpointer addr, int family)
 }
 
 
-/* Testing Defines */
-/*  #undef   HAVE_GETHOSTBYNAME_R_GLIBC */
-/*  #define  HAVE_GETHOSTBYNAME_R_GLIB_MUTEX */
-
-#ifdef HAVE_GETHOSTBYNAME_R_GLIB_MUTEX
-G_LOCK_DEFINE (gethostbyname);
-#endif
-
 static struct hostent *
 soup_gethostbyname_internal (const char *hostname)
 {
@@ -218,9 +210,6 @@ soup_gethostbyname_internal (const char *hostname)
        }
 #else
        {
-#if defined(HAVE_GETHOSTBYNAME_R_GLIB_MUTEX)
-               G_LOCK (gethostbyname);
-#endif
                result = gethostbyname (hostname);
        }
 #endif
@@ -232,15 +221,12 @@ soup_gethostbyname_internal (const char *hostname)
 
        if (buf)
                g_free (buf);
-#if defined(HAVE_GETHOSTBYNAME_R_GLIB_MUTEX)
-       G_UNLOCK (gethostbyname);
-#endif
 
        return out;
 }
 
 static struct hostent *
-soup_gethostbyaddr_internal (gpointer addr, int family)
+soup_gethostbyaddr_internal (gconstpointer addr, int family)
 {
        struct hostent result_buf, *result = &result_buf, *out;
        char *buf = NULL;
@@ -313,9 +299,6 @@ soup_gethostbyaddr_internal (gpointer addr, int family)
        }
 #else
        {
-#if defined(HAVE_GETHOSTBYNAME_R_GLIB_MUTEX)
-               G_LOCK (gethostbyname);
-#endif
                result = gethostbyaddr (addr, length, family);
        }
 #endif
@@ -327,9 +310,6 @@ soup_gethostbyaddr_internal (gpointer addr, int family)
 
        if (buf)
                g_free (buf);
-#if defined(HAVE_GETHOSTBYNAME_R_GLIB_MUTEX)
-       G_UNLOCK (gethostbyname);
-#endif
 
        return out;
 }
@@ -337,28 +317,55 @@ soup_gethostbyaddr_internal (gpointer addr, int family)
 
 /* Cache */
 
-typedef struct {
+struct SoupDNSEntry {
        char           *name;
        struct hostent *h;
-       time_t          expires;
+       gboolean        resolved;
 
-       GSList         *lookups;
+       time_t          expires;
+       guint           ref_count;
 
-       guint           source_id;
        pid_t           lookup_pid;
        int             fd;
-} SoupDNSEntry;
+};
 
 static GHashTable *soup_dns_entries;
+
 #define SOUP_DNS_ENTRIES_MAX 20
 
+static GStaticMutex soup_dns_mutex = G_STATIC_MUTEX_INIT;
+#define soup_dns_lock() g_static_mutex_lock (&soup_dns_mutex)
+#define soup_dns_unlock() g_static_mutex_unlock (&soup_dns_mutex)
+
+static void
+soup_dns_entry_ref (SoupDNSEntry *entry)
+{
+       entry->ref_count++;
+}
+
+static void
+soup_dns_entry_unref (SoupDNSEntry *entry)
+{
+       if (!--entry->ref_count) {
+               g_free (entry->name);
+               soup_dns_free_hostent (entry->h);
+
+               if (entry->fd)
+                       close (entry->fd);
+               if (entry->lookup_pid) {
+                       kill (entry->lookup_pid, SIGKILL);
+                       waitpid (entry->lookup_pid, NULL, 0);
+               }
+
+               g_free (entry);
+       }
+}
+
 static void
-free_entry (SoupDNSEntry *entry)
+uncache_entry (SoupDNSEntry *entry)
 {
        g_hash_table_remove (soup_dns_entries, entry->name);
-       g_free (entry->name);
-       free_hostent (entry->h);
-       g_free (entry);
+       soup_dns_entry_unref (entry);
 }
 
 static void
@@ -366,15 +373,19 @@ prune_cache_cb (gpointer key, gpointer value, gpointer data)
 {
        SoupDNSEntry *entry = value, **prune_entry = data; 
 
-       if (entry->lookups)
-               return;
        if (!*prune_entry || (*prune_entry)->expires > entry->expires)
                *prune_entry = entry;
 }
 
-static void
-cache_entry (SoupDNSEntry *entry)
+static SoupDNSEntry *
+soup_dns_entry_new (const char *name)
 {
+       SoupDNSEntry *entry;
+
+       entry = g_new0 (SoupDNSEntry, 1);
+       entry->name = g_strdup (name);
+       entry->ref_count = 2; /* One for the caller, one for the cache */
+
        if (!soup_dns_entries) {
                soup_dns_entries = g_hash_table_new (soup_str_case_hash,
                                                     soup_str_case_equal);
@@ -384,158 +395,87 @@ cache_entry (SoupDNSEntry *entry)
                g_hash_table_foreach (soup_dns_entries, prune_cache_cb,
                                      &prune_entry);
                if (prune_entry)
-                       free_entry (prune_entry);
+                       uncache_entry (prune_entry);
        }
 
        entry->expires = time (0) + 60 * 60;
        g_hash_table_insert (soup_dns_entries, entry->name, entry);
+
+       return entry;
 }
 
 static SoupDNSEntry *
-lookup_entry (const char *name)
+soup_dns_lookup_entry (const char *name)
 {
+       SoupDNSEntry *entry;
+
        if (!soup_dns_entries)
                return NULL;
-       return g_hash_table_lookup (soup_dns_entries, name);
-}
-
-
-typedef struct {
-       SoupGetHostByFn  func;
-       gpointer         data;
-
-       SoupDNSEntry    *entry;
-} SoupDNSLookupInfo;
-
-static gboolean
-soup_gothost (gpointer user_data)
-{
-       SoupDNSEntry *entry = user_data;
-       SoupDNSLookupInfo *info;
-
-       if (entry->source_id) {
-               g_source_remove (entry->source_id);
-               entry->source_id = 0;
-       }
-
-       while (entry->lookups) {
-               info = entry->lookups->data;
-               entry->lookups = g_slist_remove (entry->lookups, info);
-
-               (*info->func) (info, entry->h ? SOUP_STATUS_OK : SOUP_STATUS_CANT_RESOLVE, entry->h, info->data);
-               g_free (info);
-       }
-
-       return FALSE;
-}
-
-static gboolean
-soup_gethostby_cb (GIOChannel *iochannel,
-                  GIOCondition condition,
-                  gpointer data)
-{
-       SoupDNSEntry *entry = data;
-       char buf[256], *namelenp, *name, *typep, *addrlenp, *addr;
-       int nread;
-
-       if (condition & G_IO_IN)
-               nread = read (entry->fd, buf, sizeof (buf));
-       else
-               nread = 0;
-
-       close (entry->fd);
-       entry->fd = -1;
-       kill (entry->lookup_pid, SIGKILL);
-       waitpid (entry->lookup_pid, NULL, 0);
-       entry->lookup_pid = 0;
-
-       if (nread < 1)
-               return soup_gothost (entry);
-
-       namelenp = buf;
-       name = namelenp + 1;
-       typep = name + *namelenp;
-       addrlenp = typep + 1;
-       addr = addrlenp + 1;
 
-       if (addrlenp < buf + nread && (addr + *addrlenp) == buf + nread)
-               entry->h = new_hostent (name, *typep, *addrlenp, addr);
-       return soup_gothost (entry);
-}
-
-static SoupDNSLookupInfo *
-lookup_info (SoupDNSEntry *entry, SoupGetHostByFn func, gpointer data)
-{
-       SoupDNSLookupInfo *info;
-
-       info = g_new0 (SoupDNSLookupInfo, 1);
-       info->func = func;
-       info->data = data;
-       info->entry = entry;
-       entry->lookups = g_slist_prepend (entry->lookups, info);
-       if (!entry->source_id)
-               entry->source_id = g_idle_add (soup_gothost, entry);
-
-       return info;
+       entry = g_hash_table_lookup (soup_dns_entries, name);
+       if (entry)
+               soup_dns_entry_ref (entry);
+       return entry;
 }
 
 /**
- * soup_gethostbyname:
+ * soup_dns_entry_from_name:
  * @name: a nice name (eg, mofo.eecs.umich.edu) or a dotted decimal name
  *   (eg, 141.213.8.59).
- * @func: Callback function.
- * @data: User data passed when @func is called.
  *
- * Resolves a DNS name asynchronously. @func will be called with the
- * result (or an error).
+ * Begins asynchronous resolution of @name. The caller should
+ * periodically call soup_entry_check_lookup() to see if it is done,
+ * and call soup_entry_get_hostent() when soup_entry_check_lookup()
+ * returns %TRUE.
  *
- * Currently this routine forks and does the lookup, which can cause
+ * Currently, this routine forks and does the lookup, which can cause
  * some problems. In general, this will work ok for most programs most
  * of the time. It will be slow or even fail when using operating
  * systems that copy the entire process when forking.
  *
- * If you need to lookup a lot of addresses, you should call
- * g_main_iteration(%FALSE) between calls. This will help prevent an
- * explosion of processes.
- *
- * Returns: ID of the lookup which can be used with
- * soup_gethostbyname_cancel() to cancel it.
+ * Returns: a #SoupDNSEntry, which will be freed when you call
+ * soup_entry_get_hostent() or soup_entry_cancel_lookup().
  **/
-SoupDNSHandle
-soup_gethostbyname (const char *name, SoupGetHostByFn func, gpointer data)
+SoupDNSEntry *
+soup_dns_entry_from_name (const char *name)
 {
        SoupDNSEntry *entry;
        int pipes[2];
-       GIOChannel *chan;
+
+       soup_dns_lock ();
 
        /* Try the cache */
-       entry = lookup_entry (name);
+       entry = soup_dns_lookup_entry (name);
        if (entry) {
-               if (entry->expires < time (0) && !entry->source_id)
-                       free_entry (entry);
-               else
-                       return lookup_info (entry, func, data);
+               soup_dns_unlock ();
+               return entry;
        }
 
-       entry = g_new0 (SoupDNSEntry, 1);
-       entry->name = g_strdup (name);
-       cache_entry (entry);
+       entry = soup_dns_entry_new (name);
 
        /* Try to read the name as if it were dotted decimal */
        entry->h = new_hostent_from_phys (name);
-       if (entry->h)
-               return lookup_info (entry, func, data);
+       if (entry->h) {
+               entry->resolved = TRUE;
+               soup_dns_unlock ();
+               return entry;
+       }
 
        /* Check to see if we are doing synchronous DNS lookups */
        if (getenv ("SOUP_SYNC_DNS")) {
                entry->h = soup_gethostbyname_internal (name);
-               return lookup_info (entry, func, data);
+               entry->resolved = TRUE;
+               soup_dns_unlock ();
+               return entry;
        }
 
        /* Ok, we need to start a new lookup */
 
-       if (pipe (pipes) == -1)
-               return lookup_info (entry, func, data);
+       if (pipe (pipes) == -1) {
+               entry->resolved = TRUE;
+               soup_dns_unlock ();
+               return entry;
+       }
 
        entry->lookup_pid = fork ();
        switch (entry->lookup_pid) {
@@ -544,7 +484,9 @@ soup_gethostbyname (const char *name, SoupGetHostByFn func, gpointer data)
                close (pipes[0]);
                close (pipes[1]);
 
-               return lookup_info (entry, func, data);
+               entry->resolved = TRUE;
+               soup_dns_unlock ();
+               return entry;
 
        case 0:
                /* Child */
@@ -565,56 +507,64 @@ soup_gethostbyname (const char *name, SoupGetHostByFn func, gpointer data)
                close (pipes[1]);
 
                entry->fd = pipes[0];
-
-               /* Set up a watch to read from the pipe */
-               chan = g_io_channel_unix_new (pipes[0]);
-               entry->source_id =
-                       g_io_add_watch (
-                               chan,
-                               G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
-                               soup_gethostby_cb,
-                               entry);
-               g_io_channel_unref (chan);
-
-               return lookup_info (entry, func, data);
+               soup_dns_unlock ();
+               return entry;
        }
 }
 
-SoupDNSHandle
-soup_gethostbyaddr (gpointer addr, int family,
-                   SoupGetHostByFn func, gpointer data)
+/**
+ * soup_dns_entry_from_addr:
+ * @addr: pointer to address data (eg, an #in_addr_t)
+ * @family: address family of @addr
+ *
+ * Begins asynchronous resolution of @addr. The caller should
+ * periodically call soup_entry_check_lookup() to see if it is done,
+ * and call soup_entry_get_hostent() when soup_entry_check_lookup()
+ * returns %TRUE.
+ *
+ * Currently, this routine forks and does the lookup, which can cause
+ * some problems. In general, this will work ok for most programs most
+ * of the time. It will be slow or even fail when using operating
+ * systems that copy the entire process when forking.
+ *
+ * Returns: a #SoupDNSEntry, which will be freed when you call
+ * soup_entry_get_hostent() or soup_entry_cancel_lookup().
+ **/
+SoupDNSEntry *
+soup_dns_entry_from_addr (gconstpointer addr, int family)
 {
        SoupDNSEntry *entry;
        int pipes[2];
-       GIOChannel *chan;
        char *name;
 
-       name = soup_ntop (addr, family);
+       name = soup_dns_ntop (addr, family);
        g_return_val_if_fail (name != NULL, NULL);
 
+       soup_dns_lock ();
+
        /* Try the cache */
-       entry = lookup_entry (name);
+       entry = soup_dns_lookup_entry (name);
        if (entry) {
-               if (entry->expires > time (0))
-                       free_entry (entry);
-               else {
-                       g_free (name);
-                       return lookup_info (entry, func, data);
-               }
+               g_free (name);
+               soup_dns_unlock ();
+               return entry;
        }
 
-       entry = g_new0 (SoupDNSEntry, 1);
-       entry->name = name;
-       cache_entry (entry);
+       entry = soup_dns_entry_new (name);
 
        /* Check to see if we are doing synchronous DNS lookups */
        if (getenv ("SOUP_SYNC_DNS")) {
                entry->h = soup_gethostbyaddr_internal (addr, family);
-               return lookup_info (entry, func, data);
+               entry->resolved = TRUE;
+               soup_dns_unlock ();
+               return entry;
        }
 
-       if (pipe (pipes) != 0)
-               return lookup_info (entry, func, data);
+       if (pipe (pipes) != 0) {
+               entry->resolved = TRUE;
+               soup_dns_unlock ();
+               return entry;
+       }
 
        entry->lookup_pid = fork ();
        switch (entry->lookup_pid) {
@@ -623,7 +573,9 @@ soup_gethostbyaddr (gpointer addr, int family,
                close (pipes[1]);
 
                g_warning ("Fork error: %s (%d)\n", g_strerror(errno), errno);
-               return lookup_info (entry, func, data);
+               entry->resolved = TRUE;
+               soup_dns_unlock ();
+               return entry;
 
        case 0:
                /* Child */
@@ -644,37 +596,78 @@ soup_gethostbyaddr (gpointer addr, int family,
                close (pipes[1]);
 
                entry->fd = pipes[0];
-
-               /* Set up a watch to read from the pipe */
-               chan = g_io_channel_unix_new (pipes[0]);
-               entry->source_id =
-                       g_io_add_watch (
-                               chan,
-                               G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
-                               soup_gethostby_cb,
-                               entry);
-               g_io_channel_unref (chan);
-
-               return lookup_info (entry, func, data);
+               soup_dns_unlock ();
+               return entry;
        }
 }
 
-void
-soup_gethostby_cancel (SoupDNSHandle id)
+static void
+check_hostent (SoupDNSEntry *entry, gboolean block)
 {
-       SoupDNSLookupInfo *info = id;
-       SoupDNSEntry *entry = info->entry;
+       char buf[256], *namelenp, *name, *typep, *addrlenp, *addr;
+       int nread;
+       fd_set readfds;
+       struct timeval tv = { 0, 0 };
 
-       entry->lookups = g_slist_remove (entry->lookups, info);
-       g_free (info);
+       soup_dns_lock ();
 
-       if (!entry->lookups && entry->source_id) {
-               g_source_remove (entry->source_id);
-               if (entry->lookup_pid) {
-                       close (entry->fd);
-                       kill (entry->lookup_pid, SIGKILL);
-                       waitpid (entry->lookup_pid, NULL, 0);
-                       free_entry (entry);
-               }
+       if (entry->resolved || !entry->fd) {
+               soup_dns_unlock ();
+               return;
+       }
+
+       FD_ZERO (&readfds);
+       FD_SET (entry->fd, &readfds);
+       if (select (entry->fd + 1, &readfds, NULL, NULL, &tv) != 0) {
+               soup_dns_unlock ();
+               return;
+       }
+
+       nread = read (entry->fd, buf, sizeof (buf));
+       close (entry->fd);
+       entry->fd = -1;
+       kill (entry->lookup_pid, SIGKILL);
+       waitpid (entry->lookup_pid, NULL, 0);
+       entry->lookup_pid = 0;
+       entry->resolved = TRUE;
+
+       if (nread < 1) {
+               soup_dns_unlock ();
+               return;
        }
+
+       namelenp = buf;
+       name = namelenp + 1;
+       typep = name + *namelenp;
+       addrlenp = typep + 1;
+       addr = addrlenp + 1;
+
+       if (addrlenp < buf + nread && (addr + *addrlenp) == buf + nread)
+               entry->h = new_hostent (name, *typep, *addrlenp, addr);
+       soup_dns_unlock ();
+}
+
+gboolean
+soup_dns_entry_check_lookup (SoupDNSEntry *entry)
+{
+       check_hostent (entry, FALSE);
+       return entry->resolved;
+}
+
+struct hostent *
+soup_dns_entry_get_hostent (SoupDNSEntry *entry)
+{
+       struct hostent *h;
+
+       check_hostent (entry, TRUE);
+       h = copy_hostent (entry->h);
+       soup_dns_entry_unref (entry);
+
+       return h;
+}
+
+void
+soup_dns_entry_cancel_lookup (SoupDNSEntry *entry)
+{
+       soup_dns_entry_unref (entry);
 }
index eba700e..2162e65 100644 (file)
 #include <sys/socket.h>
 #include <netdb.h>
 
-typedef gpointer SoupDNSHandle;
-typedef void   (*SoupGetHostByFn)          (SoupDNSHandle       handle,
-                                           guint               status,
-                                           struct hostent     *h,
-                                           gpointer            user_data);
+typedef struct SoupDNSEntry SoupDNSEntry;
 
-SoupDNSHandle    soup_gethostbyname        (const char         *name, 
-                                           SoupGetHostByFn     func,
-                                           gpointer            data);
+SoupDNSEntry   *soup_dns_entry_from_name     (const char     *name);
+SoupDNSEntry   *soup_dns_entry_from_addr     (gconstpointer   addr,
+                                             int             family);
 
-SoupDNSHandle    soup_gethostbyaddr        (gpointer            addr,
-                                           int                 family,
-                                           SoupGetHostByFn     func,
-                                           gpointer            data);
+gboolean        soup_dns_entry_check_lookup  (SoupDNSEntry   *entry);
+void            soup_dns_entry_cancel_lookup (SoupDNSEntry   *entry);
 
-void             soup_gethostby_cancel     (SoupDNSHandle       id);
+struct hostent *soup_dns_entry_get_hostent   (SoupDNSEntry   *entry);
+void            soup_dns_free_hostent        (struct hostent *h);
 
-char            *soup_ntop                 (gconstpointer       addr,
-                                           int                 family);
+char           *soup_dns_ntop                (gconstpointer   addr,
+                                             int             family);
 
 #endif /* SOUP_DNS_H */
index 13a6f62..c25950f 100644 (file)
@@ -66,19 +66,6 @@ soup_str_case_equal (gconstpointer v1,
        return g_strcasecmp (string1, string2) == 0;
 }
 
-gint
-soup_substring_index (gchar *str, gint len, gchar *substr)
-{
-       int i, sublen = strlen (substr);
-
-       for (i = 0; i <= len - sublen; ++i)
-               if (str[i] == substr[0])
-                       if (memcmp (&str[i], substr, sublen) == 0)
-                               return i;
-
-       return -1;
-}
-
 /* Base64 utils (straight from camel-mime-utils.c) */
 #define d(x)
 
index 7cd8959..af8229c 100644 (file)
 #include <libsoup/soup-auth.h>
 #include <libsoup/soup-misc.h>
 
-#ifdef __cplusplus
-extern "C" {
-#endif
-
 #define RESPONSE_BLOCK_SIZE 8192
 
 extern gboolean    soup_initialized;
@@ -31,31 +27,12 @@ extern gpointer        soup_auth_fn_user_data;
 #define soup_sockaddr_max sockaddr_in
 #endif
 
-/* from soup-context.c */
-
-SoupAuth   *soup_context_lookup_auth       (SoupContext    *ctx,
-                                           SoupMessage    *msg);
-
-gboolean    soup_context_update_auth       (SoupContext    *ctx,
-                                           SoupMessage    *msg);
-
-gboolean    soup_context_authenticate_auth (SoupContext    *ctx,
-                                           SoupAuth       *auth);
-
-void        soup_context_invalidate_auth   (SoupContext    *ctx,
-                                           SoupAuth       *auth);
-                                         
 /* from soup-misc.c */
 
 guint     soup_str_case_hash   (gconstpointer  key);
 gboolean  soup_str_case_equal  (gconstpointer  v1,
                                gconstpointer  v2);
 
-gint      soup_substring_index (gchar         *str,
-                               gint           len,
-                               gchar         *substr);
-
-
 #define SOUP_MAKE_TYPE(l,t,ci,i,parent) \
 GType l##_get_type(void)\
 {\
@@ -80,8 +57,4 @@ GType l##_get_type(void)\
        return type;                                    \
 }
 
-#ifdef __cplusplus
-}
-#endif
-
 #endif /*SOUP_PRIVATE_H*/
index 3d01605..7576f61 100644 (file)
@@ -106,7 +106,7 @@ class_init (GObjectClass *object_class)
 SOUP_MAKE_TYPE (soup_session, SoupSession, class_init, init, PARENT_TYPE)
 
 SoupSession *
-soup_session_new (void)
+soup_session_new_default (void)
 {
        return g_object_new (SOUP_TYPE_SESSION, NULL);
 }
@@ -116,7 +116,7 @@ soup_session_new_with_proxy (const SoupUri *proxy_uri)
 {
        SoupSession *session;
 
-       session = soup_session_new ();
+       session = soup_session_new_default ();
        if (proxy_uri)
                session->priv->proxy_uri = soup_uri_copy (proxy_uri);
 
@@ -125,7 +125,7 @@ soup_session_new_with_proxy (const SoupUri *proxy_uri)
 
 SoupSession *
 soup_session_new_full (const SoupUri *proxy_uri,
-                      guint max_conns, guint max_per_host)
+                      guint max_conns, guint max_conns_per_host)
 {
        SoupSession *session;
 
@@ -171,10 +171,7 @@ get_host_for_message (SoupSession *session, SoupMessage *msg)
                return host;
 
        host = g_new0 (SoupSessionHost, 1);
-       host->root_uri = g_new0 (SoupUri, 1);
-       host->root_uri->protocol = source->protocol;
-       host->root_uri->host = g_strdup (source->host);
-       host->root_uri->port = source->port;
+       host->root_uri = soup_uri_copy_root (source);
 
        g_hash_table_insert (session->priv->hosts, host->root_uri, host);
        return host;
@@ -426,6 +423,8 @@ final_finished (SoupMessage *req, gpointer session)
                g_signal_handlers_disconnect_by_func (req, request_finished, session);
                g_signal_handlers_disconnect_by_func (req, final_finished, session);
                g_object_unref (req);
+
+               run_queue (session, FALSE);
        }
 }
 
@@ -620,17 +619,15 @@ run_queue (SoupSession *session, gboolean try_pruning)
                if (session->priv->proxy_uri &&
                    host->root_uri->protocol == SOUP_PROTOCOL_HTTPS) {
                        conn = soup_connection_new_tunnel (
-                               session->priv->proxy_uri, host->root_uri,
-                               got_connection, session);
+                               session->priv->proxy_uri, host->root_uri);
                } else if (session->priv->proxy_uri) {
                        conn = soup_connection_new_proxy (
-                               session->priv->proxy_uri,
-                               got_connection, session);
+                               session->priv->proxy_uri);
                } else {
-                       conn = soup_connection_new (host->root_uri,
-                                                   got_connection, session);
+                       conn = soup_connection_new (host->root_uri);
                }
 
+               soup_connection_connect_async (conn, got_connection, session);
                g_signal_connect (conn, "disconnected",
                                  G_CALLBACK (connection_closed), session);
                g_hash_table_insert (session->priv->conns, conn, host);
index 2c5b56b..27454e9 100644 (file)
@@ -46,12 +46,18 @@ struct SoupSocketPrivate {
        GIOChannel *iochannel;
 
        guint watch;
-       gboolean server, ssl;
+       guint flags;
 
        guint           read_tag, write_tag, error_tag;
        GByteArray     *read_buf;
 };
 
+#define SOUP_SOCKET_FLAG_SSL    (1<<8)
+
+#define SOUP_SOCKET_SET_FLAG(sock, flag) (sock)->priv->flags |= (flag)
+#define SOUP_SOCKET_CLEAR_FLAG(sock, flag) (sock)->priv->flags &= ~(flag)
+#define SOUP_SOCKET_CHECK_FLAG(sock, flag) ((sock)->priv->flags & (flag))
+
 static void
 init (GObject *object)
 {
@@ -169,39 +175,56 @@ soup_socket_new (void)
        return g_object_new (SOUP_TYPE_SOCKET, NULL);
 }
 
-void
-soup_socket_set_flag (SoupSocket *sock, SoupSocketFlag flag, gboolean value)
+static void
+update_fdflags (SoupSocket *sock, guint mask)
 {
-       int fdflags, opt;
+       int flags, opt;
+
+       if (mask & SOUP_SOCKET_FLAG_NONBLOCKING) {
+               flags = fcntl (sock->priv->sockfd, F_GETFL, 0);
+               g_return_if_fail (flags != -1);
+
+               if (sock->priv->flags & SOUP_SOCKET_FLAG_NONBLOCKING)
+                       flags |= O_NONBLOCK;
+               else
+                       flags &= ~O_NONBLOCK;
+               fcntl (sock->priv->sockfd, F_SETFL, flags);
+       }
+       if (mask & SOUP_SOCKET_FLAG_NODELAY) {
+               opt = (sock->priv->flags & SOUP_SOCKET_FLAG_NODELAY) != 0;
+               setsockopt (sock->priv->sockfd, IPPROTO_TCP,
+                           TCP_NODELAY, &opt, sizeof (opt));
+       }
+       if (mask & SOUP_SOCKET_FLAG_REUSEADDR) {
+               opt = (sock->priv->flags & SOUP_SOCKET_FLAG_REUSEADDR) != 0;
+               setsockopt (sock->priv->sockfd, SOL_SOCKET,
+                           SO_REUSEADDR, &opt, sizeof (opt));
+       }
+}
 
+void
+soup_socket_set_flags (SoupSocket *sock, guint mask, guint flags)
+{
        g_return_if_fail (SOUP_IS_SOCKET (sock));
-       g_return_if_fail (sock->priv->sockfd != -1);
 
-       switch (flag) {
-       case SOUP_SOCKET_FLAG_NONBLOCKING:
-               fdflags = fcntl (sock->priv->sockfd, F_GETFL, 0);
-               g_return_if_fail (fdflags != -1);
+       sock->priv->flags |= mask & flags;
+       sock->priv->flags &= ~(mask & ~flags);
 
-               if (value)
-                       fdflags |= O_NONBLOCK;
-               else
-                       fdflags &= ~O_NONBLOCK;
-
-               fcntl (sock->priv->sockfd, F_SETFL, fdflags);
-               break;
-
-       case SOUP_SOCKET_FLAG_NODELAY:
-               opt = (value != FALSE);
-               setsockopt (sock->priv->sockfd, IPPROTO_TCP, TCP_NODELAY,
-                           &opt, sizeof (opt));
-               break;
-
-       case SOUP_SOCKET_FLAG_REUSEADDR:
-               opt = (value != FALSE);
-               setsockopt (sock->priv->sockfd, SOL_SOCKET, SO_REUSEADDR,
-                           &opt, sizeof (opt));
-               break;
+       if (sock->priv->sockfd)
+               update_fdflags (sock, mask);
+}
+
+static GIOChannel *
+get_iochannel (SoupSocket *sock)
+{
+       if (!sock->priv->iochannel) {
+               sock->priv->iochannel =
+                       g_io_channel_unix_new (sock->priv->sockfd);
+               g_io_channel_set_close_on_unref (sock->priv->iochannel, TRUE);
+               g_io_channel_set_encoding (sock->priv->iochannel, NULL, NULL);
+               g_io_channel_set_buffered (sock->priv->iochannel, FALSE);
        }
+       return sock->priv->iochannel;
 }
 
 static gboolean
@@ -224,7 +247,7 @@ connect_watch (GIOChannel* iochannel, GIOCondition condition, gpointer data)
        if (error)
                goto cant_connect;
 
-       if (sock->priv->ssl)
+       if (SOUP_SOCKET_CHECK_FLAG (sock, SOUP_SOCKET_FLAG_SSL))
                soup_socket_start_ssl (sock);
 
        g_signal_emit (sock, signals[CONNECT_RESULT], 0, SOUP_STATUS_OK);
@@ -257,72 +280,91 @@ got_address (SoupAddress *addr, guint status, gpointer user_data)
                return;
        }
 
-       soup_socket_connect (sock, addr);
+       soup_socket_connect (sock, sock->priv->remote_addr);
        /* soup_socket_connect re-reffed addr */
        g_object_unref (addr);
 }
 
 /**
  * soup_socket_connect:
- * @sock: a #SoupSocket (which must not be connected or listening)
+ * @sock: a client #SoupSocket (which must not already be connected)
  * @remote_addr: address to connect to
  *
- * Starts connecting to the indicated remote address and port. The
- * socket will emit %connect_result when it succeeds or fails (but
- * not before returning from this function).
+ * If %SOUP_SOCKET_FLAG_NONBLOCKING has been set on the socket, this
+ * begins asynchronously connecting to the given address. The socket
+ * will emit %connect_result when it succeeds or fails (but not before
+ * returning from this function).
+ *
+ * If %SOUP_SOCKET_FLAG_NONBLOCKING has not been set, this will
+ * attempt to synchronously connect.
+ *
+ * Return value: %SOUP_STATUS_CONTINUE if connecting asynchronously,
+ * otherwise a success or failure code.
  **/
-void
+guint
 soup_socket_connect (SoupSocket *sock, SoupAddress *remote_addr)
 {
-       struct sockaddr *sa = NULL;
+       struct sockaddr *sa;
        int len, status;
+       gboolean sync;
 
-       g_return_if_fail (SOUP_IS_SOCKET (sock));
-       g_return_if_fail (SOUP_IS_ADDRESS (remote_addr));
-       g_return_if_fail (sock->priv->sockfd == -1);
+       g_return_val_if_fail (SOUP_IS_SOCKET (sock), SOUP_STATUS_MALFORMED);
+       g_return_val_if_fail (!SOUP_SOCKET_CHECK_FLAG (sock, SOUP_SOCKET_FLAG_SERVER), FALSE);
+       g_return_val_if_fail (sock->priv->sockfd == -1, SOUP_STATUS_MALFORMED);
+       g_return_val_if_fail (SOUP_IS_ADDRESS (remote_addr), SOUP_STATUS_MALFORMED);
+
+       sync = !(sock->priv->flags & SOUP_SOCKET_FLAG_NONBLOCKING);
 
        sock->priv->remote_addr = g_object_ref (remote_addr);
+       if (sync) {
+               status = soup_address_resolve_sync (remote_addr);
+               if (!SOUP_STATUS_IS_SUCCESSFUL (status))
+                       return status;
+       }
+
        sa = soup_address_get_sockaddr (sock->priv->remote_addr, &len);
        if (!sa) {
-               soup_address_resolve (sock->priv->remote_addr,
-                                     got_address, sock);
-               return;
+               if (sync)
+                       return SOUP_STATUS_CANT_RESOLVE;
+
+               soup_address_resolve_async (remote_addr, got_address, sock);
+               return SOUP_STATUS_CONTINUE;
        }
 
        sock->priv->sockfd = socket (sa->sa_family, SOCK_STREAM, 0);
-       if (sock->priv->sockfd < 0)
-               goto cant_connect;
-       soup_socket_set_flag (sock, SOUP_SOCKET_FLAG_NONBLOCKING, TRUE);
-       soup_socket_set_flag (sock, SOUP_SOCKET_FLAG_NODELAY, TRUE);
+       if (sock->priv->sockfd == -1) {
+               g_free (sa);
+               goto done;
+       }
+       update_fdflags (sock, SOUP_SOCKET_FLAG_ALL);
 
-       /* Connect (non-blocking) */
        status = connect (sock->priv->sockfd, sa, len);
        g_free (sa);
-       sa = NULL;
 
-       if (status == 0) {
-               /* Connect already succeeded */
-               sock->priv->watch = g_idle_add (idle_connect_result, sock);
-               return;
+       if (status == -1) {
+               if (errno == EINPROGRESS) {
+                       /* Wait for connect to succeed or fail */
+                       sock->priv->watch =
+                               g_io_add_watch (get_iochannel (sock),
+                                               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 {
+                       close (sock->priv->sockfd);
+                       sock->priv->sockfd = -1;
+               }
        }
-       if (errno != EINPROGRESS)
-               goto cant_connect;
-
-       soup_socket_get_iochannel (sock);
-       sock->priv->watch = g_io_add_watch (sock->priv->iochannel,
-                                           (G_IO_IN | G_IO_OUT | G_IO_PRI |
-                                            G_IO_ERR | G_IO_HUP | G_IO_NVAL),
-                                           connect_watch, sock);
-       return;
 
- cant_connect: 
-       if (sa)
-               g_free (sa);
-       if (sock->priv->sockfd != -1) {
-               close (sock->priv->sockfd);
-               sock->priv->sockfd = -1;
+ done:
+       if (sync) {
+               return sock->priv->sockfd != -1 ?
+                       SOUP_STATUS_OK : SOUP_STATUS_CANT_CONNECT;
+       } else {
+               sock->priv->watch = g_idle_add (idle_connect_result, sock);
+               return SOUP_STATUS_CONTINUE;
        }
-       sock->priv->watch = g_idle_add (idle_connect_result, sock);
 }
 
 static gboolean
@@ -345,17 +387,18 @@ listen_watch (GIOChannel* iochannel, GIOCondition condition, gpointer data)
 
        new = soup_socket_new ();
        new->priv->sockfd = sockfd;
-       soup_socket_set_flag (new, SOUP_SOCKET_FLAG_NONBLOCKING, TRUE);
-       soup_socket_set_flag (new, SOUP_SOCKET_FLAG_NODELAY, TRUE);
+       new->priv->flags = (SOUP_SOCKET_FLAG_NONBLOCKING |
+                           SOUP_SOCKET_FLAG_NODELAY |
+                           SOUP_SOCKET_FLAG_SERVER |
+                           (sock->priv->flags & SOUP_SOCKET_FLAG_SSL));
+       update_fdflags (new, SOUP_SOCKET_FLAG_ALL);
 
        new->priv->remote_addr = soup_address_new_from_sockaddr ((struct sockaddr *)&sa, sa_len);
 
-       new->priv->server = TRUE;
-       if (sock->priv->ssl) {
-               new->priv->ssl = TRUE;
+       if (SOUP_SOCKET_CHECK_FLAG (new, SOUP_SOCKET_FLAG_SSL))
                soup_socket_start_ssl (new);
-       else
-               soup_socket_get_iochannel (new);
+       else
+               get_iochannel (new);
 
        g_signal_emit (sock, signals[NEW_CONNECTION], 0, new);
        g_object_unref (new);
@@ -365,7 +408,8 @@ listen_watch (GIOChannel* iochannel, GIOCondition condition, gpointer data)
 
 /**
  * soup_socket_listen:
- * @sock: a #SoupSocket (which must not be connected or listening)
+ * @sock: a server #SoupSocket (which must not already be connected or
+ * listening)
  * @local_addr: Local address to bind to.
  *
  * Makes @sock start listening on the given interface and port. When
@@ -380,8 +424,9 @@ soup_socket_listen (SoupSocket *sock, SoupAddress *local_addr)
        int sa_len;
 
        g_return_val_if_fail (SOUP_IS_SOCKET (sock), FALSE);
-       g_return_val_if_fail (SOUP_IS_ADDRESS (local_addr), FALSE);
+       g_return_val_if_fail (SOUP_SOCKET_CHECK_FLAG (sock, SOUP_SOCKET_FLAG_SERVER), FALSE);
        g_return_val_if_fail (sock->priv->sockfd == -1, FALSE);
+       g_return_val_if_fail (SOUP_IS_ADDRESS (local_addr), FALSE);
 
        /* @local_addr may have its port set to 0. So we intentionally
         * don't store it in sock->priv->local_addr, so that if the
@@ -395,8 +440,7 @@ soup_socket_listen (SoupSocket *sock, SoupAddress *local_addr)
        sock->priv->sockfd = socket (sa->sa_family, SOCK_STREAM, 0);
        if (sock->priv->sockfd < 0)
                goto cant_listen;
-       soup_socket_set_flag (sock, SOUP_SOCKET_FLAG_NONBLOCKING, TRUE);
-       soup_socket_set_flag (sock, SOUP_SOCKET_FLAG_REUSEADDR, TRUE);
+       update_fdflags (sock, SOUP_SOCKET_FLAG_ALL);
 
        /* Bind */
        if (bind (sock->priv->sockfd, sa, sa_len) != 0)
@@ -406,10 +450,7 @@ soup_socket_listen (SoupSocket *sock, SoupAddress *local_addr)
        if (listen (sock->priv->sockfd, 10) != 0)
                goto cant_listen;
 
-       sock->priv->server = TRUE;
-
-       soup_socket_get_iochannel (sock);
-       sock->priv->watch = g_io_add_watch (sock->priv->iochannel,
+       sock->priv->watch = g_io_add_watch (get_iochannel (sock),
                                            G_IO_IN | G_IO_ERR | G_IO_HUP,
                                            listen_watch, sock);
        return TRUE;
@@ -435,16 +476,17 @@ soup_socket_start_ssl (SoupSocket *sock)
 {
        GIOChannel *chan;
 
-       chan = soup_socket_get_iochannel (sock);
-       sock->priv->iochannel = sock->priv->server ?
+       chan = get_iochannel (sock);
+       sock->priv->iochannel =
+               SOUP_SOCKET_CHECK_FLAG (sock, SOUP_SOCKET_FLAG_SERVER) ?
                soup_ssl_get_server_iochannel (chan) :
                soup_ssl_get_iochannel (chan);
-       sock->priv->ssl = TRUE;
+       SOUP_SOCKET_SET_FLAG (sock, SOUP_SOCKET_FLAG_SSL);
 }
        
 
 /**
- * soup_socket_client_new:
+ * soup_socket_client_new_async:
  * @hostname: remote machine to connect to
  * @port: remote port to connect to
  * @ssl: whether or not to use SSL
@@ -457,15 +499,16 @@ soup_socket_start_ssl (SoupSocket *sock)
  * Return value: the new socket (not yet ready for use).
  **/
 SoupSocket *
-soup_socket_client_new (const char *hostname, guint port, gboolean ssl,
-                       SoupSocketCallback callback, gpointer user_data)
+soup_socket_client_new_async (const char *hostname, guint port, gboolean ssl, 
+                             SoupSocketCallback callback, gpointer user_data)
 {
        SoupSocket *sock;
 
        g_return_val_if_fail (hostname != NULL, NULL);
 
        sock = soup_socket_new ();
-       sock->priv->ssl = ssl;
+       sock->priv->flags = (SOUP_SOCKET_FLAG_NONBLOCKING |
+                            (ssl ? SOUP_SOCKET_FLAG_SSL : 0));
        soup_socket_connect (sock, soup_address_new (hostname, port));
 
        if (callback) {
@@ -476,6 +519,41 @@ soup_socket_client_new (const char *hostname, guint port, gboolean ssl,
 }
 
 /**
+ * soup_socket_client_new_sync:
+ * @hostname: remote machine to connect to
+ * @port: remote port to connect to
+ * @ssl: whether or not to use SSL
+ * @status_ret: pointer to return the soup status in
+ *
+ * Creates a connection to @hostname and @port. If @status_ret is not
+ * %NULL, it will contain a status code on return.
+ *
+ * Return value: the new socket, or %NULL if it could not connect.
+ **/
+SoupSocket *
+soup_socket_client_new_sync (const char *hostname, guint port, gboolean ssl,
+                            guint *status_ret)
+{
+       SoupSocket *sock;
+       guint status;
+
+       g_return_val_if_fail (hostname != NULL, NULL);
+
+       sock = soup_socket_new ();
+       sock->priv->flags = ssl ? SOUP_SOCKET_FLAG_SSL : 0;
+       status = soup_socket_connect (sock, soup_address_new (hostname, port));
+
+       if (!SOUP_STATUS_IS_SUCCESSFUL (status)) {
+               g_object_unref (sock);
+               sock = NULL;
+       }
+
+       if (status_ret)
+               *status_ret = status;
+       return sock;
+}
+
+/**
  * soup_socket_server_new:
  * @local_addr: Local address to bind to. (Use soup_address_any_new() to
  * accept connections on any local address)
@@ -499,8 +577,9 @@ soup_socket_server_new (SoupAddress *local_addr, gboolean ssl,
        g_return_val_if_fail (SOUP_IS_ADDRESS (local_addr), NULL);
 
        sock = soup_socket_new ();
-       sock->priv->ssl = ssl;
-
+       sock->priv->flags = (SOUP_SOCKET_FLAG_SERVER |
+                            SOUP_SOCKET_FLAG_NONBLOCKING |
+                            (ssl ? SOUP_SOCKET_FLAG_SSL : 0));
        if (!soup_socket_listen (sock, local_addr)) {
                g_object_unref (sock);
                return NULL;
@@ -515,32 +594,6 @@ soup_socket_server_new (SoupAddress *local_addr, gboolean ssl,
 }
 
 
-/**
- * soup_socket_get_iochannel:
- * @sock: #SoupSocket to get #GIOChannel from.
- *
- * Get the #GIOChannel for the #SoupSocket.
- *
- * If you ref the iochannel, it will remain valid after @sock is
- * destroyed.
- *
- * Returns: A #GIOChannel; %NULL on failure.
- **/
-GIOChannel *
-soup_socket_get_iochannel (SoupSocket *sock)
-{
-       g_return_val_if_fail (SOUP_IS_SOCKET (sock), NULL);
-
-       if (!sock->priv->iochannel) {
-               sock->priv->iochannel =
-                       g_io_channel_unix_new (sock->priv->sockfd);
-               g_io_channel_set_close_on_unref (sock->priv->iochannel, TRUE);
-               g_io_channel_set_encoding (sock->priv->iochannel, NULL, NULL);
-               g_io_channel_set_buffered (sock->priv->iochannel, FALSE);
-       }
-       return sock->priv->iochannel;
-}
-
 void
 soup_socket_disconnect (SoupSocket *sock)
 {
index fd21fb8..5b3e49f 100644 (file)
@@ -35,20 +35,20 @@ typedef struct {
        void (*new_connection) (SoupSocket *, SoupSocket *);
 } SoupSocketClass;
 
-typedef enum {
-       SOUP_SOCKET_FLAG_NONBLOCKING,
-       SOUP_SOCKET_FLAG_NODELAY,
-       SOUP_SOCKET_FLAG_REUSEADDR,
-} SoupSocketFlag;
+#define SOUP_SOCKET_FLAG_NONBLOCKING (1<<0)
+#define SOUP_SOCKET_FLAG_NODELAY     (1<<1)
+#define SOUP_SOCKET_FLAG_SERVER      (1<<2)
+#define SOUP_SOCKET_FLAG_REUSEADDR   (1<<3)
+#define SOUP_SOCKET_FLAG_ALL         ( ~0 )
 
 GType soup_socket_get_type (void);
 
 SoupSocket    *soup_socket_new                (void);
-void           soup_socket_set_flag           (SoupSocket         *sock,
-                                              SoupSocketFlag      flag,
-                                              gboolean            value);
+void           soup_socket_set_flags          (SoupSocket         *sock,
+                                              guint               mask,
+                                              guint               flags);
 
-void           soup_socket_connect            (SoupSocket         *sock,
+guint          soup_socket_connect            (SoupSocket         *sock,
                                               SoupAddress        *rem_addr);
 gboolean       soup_socket_listen             (SoupSocket         *sock,
                                               SoupAddress        *local_addr);
@@ -64,19 +64,20 @@ typedef void (*SoupSocketListenerCallback)    (SoupSocket         *listener,
                                               SoupSocket         *sock,
                                               gpointer            user_data);
 
-SoupSocket    *soup_socket_client_new         (const char         *hostname,
+SoupSocket    *soup_socket_client_new_async   (const char         *hostname,
                                               guint               port,
                                               gboolean            ssl,
                                               SoupSocketCallback  callback,
                                               gpointer            user_data);
+SoupSocket    *soup_socket_client_new_sync    (const char         *hostname,
+                                              guint               port,
+                                              gboolean            ssl,
+                                              guint              *status);
 SoupSocket    *soup_socket_server_new         (SoupAddress        *local_addr,
                                               gboolean            ssl,
                                               SoupSocketListenerCallback,
                                               gpointer            user_data);
 
-
-GIOChannel    *soup_socket_get_iochannel      (SoupSocket         *sock);
-
 SoupAddress   *soup_socket_get_local_address  (SoupSocket         *sock);
 SoupAddress   *soup_socket_get_remote_address (SoupSocket         *sock);
 
index f3bcb4a..faf3ef2 100644 (file)
@@ -339,6 +339,21 @@ soup_uri_copy (const SoupUri *uri)
        return dup;
 }
 
+SoupUri *
+soup_uri_copy_root (const SoupUri *uri)
+{
+       SoupUri *dup;
+
+       g_return_val_if_fail (uri != NULL, NULL);
+
+       dup = g_new0 (SoupUri, 1);
+       dup->protocol = uri->protocol;
+       dup->host     = g_strdup (uri->host);
+       dup->port     = uri->port;
+
+       return dup;
+}
+
 static inline gboolean
 parts_equal (const char *one, const char *two)
 {
index 0d737ae..1afe6bc 100644 (file)
@@ -39,6 +39,7 @@ char     *soup_uri_to_string         (const SoupUri *uri,
                                      gboolean       just_path);
 
 SoupUri  *soup_uri_copy              (const SoupUri *uri);
+SoupUri  *soup_uri_copy_root         (const SoupUri *uri);
 
 gboolean  soup_uri_equal             (const SoupUri *uri1, 
                                      const SoupUri *uri2);
index aa8dcc5..ec1d275 100644 (file)
@@ -7,10 +7,12 @@ LIBS = $(top_builddir)/libsoup/libsoup-$(SOUP_API_VERSION).la
 noinst_PROGRAMS = get revserver simple-httpd simple-proxy
 
 get_SOURCES = get.c
-revserver_SOURCES = revserver.c
 simple_httpd_SOURCES = simple-httpd.c
 simple_proxy_SOURCES = simple-proxy.c
 
+revserver_SOURCES = revserver.c
+revserver_LDFLAGS = `pkg-config --libs gthread-2.0`
+
 check_PROGRAMS = auth-test uri-parsing
 
 auth_test_SOURCES = auth-test.c
index 4448845..9ece051 100644 (file)
@@ -160,7 +160,6 @@ static const char *auths[] = {
 static int
 identify_auth (SoupMessage *msg)
 {
-       SoupAuth *auth;
        const char *header;
        int num;
 
@@ -222,7 +221,7 @@ main (int argc, char **argv)
        int i;
 
        g_type_init ();
-       session = soup_session_new ();
+       session = soup_session_new_default ();
 
        for (i = 0; i < ntests; i++) {
                printf ("Test %d: %s\n", i + 1, tests[i].explanation);
index efb9b9d..ec1ee7b 100644 (file)
@@ -207,7 +207,7 @@ main (int argc, char **argv)
        int opt;
 
        g_type_init ();
-       session = soup_session_new ();
+       session = soup_session_new_default ();
 
        while ((opt = getopt (argc, argv, "r")) != -1) {
                switch (opt) {
index 3620887..deecf81 100644 (file)
@@ -3,6 +3,7 @@
 #endif
 
 #include <ctype.h>
+#include <pthread.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -14,8 +15,6 @@
 static void rev_read (SoupSocket *sock, GString *buf);
 static void rev_write (SoupSocket *sock, GString *buf);
 
-gboolean nonblocking = TRUE;
-
 static void
 reverse (GString *buf)
 {
@@ -37,8 +36,6 @@ reverse (GString *buf)
 static void
 rev_done (SoupSocket *sock, GString *buf)
 {
-       g_signal_handlers_disconnect_by_func (sock, rev_read, buf);
-       g_signal_handlers_disconnect_by_func (sock, rev_write, buf);
        g_object_unref (sock);
        g_string_free (buf, TRUE);
 }
@@ -61,7 +58,7 @@ rev_write (SoupSocket *sock, GString *buf)
                break;
 
        case SOUP_SOCKET_WOULD_BLOCK:
-               g_assert (nonblocking == TRUE);
+               g_error ("Can't happen");
                break;
 
        default:
@@ -96,7 +93,7 @@ rev_read (SoupSocket *sock, GString *buf)
                break;
 
        case SOUP_SOCKET_WOULD_BLOCK:
-               g_assert (nonblocking == TRUE);
+               g_error ("Can't happen");
                break;
 
        default:
@@ -109,23 +106,26 @@ rev_read (SoupSocket *sock, GString *buf)
        }
 }
 
+static void *
+start_thread (void *client)
+{
+       rev_read (client, g_string_new (NULL));
+
+       return NULL;
+}
+
 static void
 new_connection (SoupSocket *listener, SoupSocket *client, gpointer user_data)
 {
-       GString *buf;
+       pthread_t pth;
 
        g_object_ref (client);
-       buf = g_string_new (NULL);
-
-       if (nonblocking) {
-               g_signal_connect (client, "readable",
-                                 G_CALLBACK (rev_read), buf);
-               g_signal_connect (client, "writable",
-                                 G_CALLBACK (rev_write), buf);
-       } else
-               soup_socket_set_flag (client, SOUP_SOCKET_FLAG_NONBLOCKING, FALSE);
+       soup_socket_set_flags (client, SOUP_SOCKET_FLAG_NONBLOCKING, 0);
 
-       rev_read (client, buf);
+       if (pthread_create (&pth, NULL, start_thread, client) != 0) {
+               g_warning ("Could not start thread");
+               g_object_unref (client);
+       }
 }
 
 int
@@ -140,19 +140,16 @@ main (int argc, char **argv)
 
        g_type_init ();
 
-       while ((opt = getopt (argc, argv, "6bp:")) != -1) {
+       while ((opt = getopt (argc, argv, "6p:")) != -1) {
                switch (opt) {
                case '6':
                        family = SOUP_ADDRESS_FAMILY_IPV6;
                        break;
-               case 'b':
-                       nonblocking = FALSE;
-                       break;
                case 'p':
                        port = atoi (optarg);
                        break;
                default:
-                       fprintf (stderr, "Usage: %s [-6] [-b] [-p port]\n",
+                       fprintf (stderr, "Usage: %s [-6] [-p port]\n",
                                 argv[0]);
                        exit (1);
                }
index 3af0a75..b5b21a4 100644 (file)
@@ -159,7 +159,7 @@ main (int argc, char **argv)
                soup_server_get_port (server));
        soup_server_run_async (server);
 
-       session = soup_session_new ();
+       session = soup_session_new_default ();
 
        printf ("\nWaiting for requests...\n");