From 1dc7f62613ce0bf9fbb2d04f05aa62b874278ebb Mon Sep 17 00:00:00 2001 From: Dan Winship Date: Tue, 9 Sep 2003 15:33:48 +0000 Subject: [PATCH] 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. --- ChangeLog | 57 +++++++ libsoup/soup-address.c | 136 +++++++++------- libsoup/soup-address.h | 3 +- libsoup/soup-connection.c | 260 ++++++++++++++++------------- libsoup/soup-connection.h | 41 +++-- libsoup/soup-dns.c | 405 +++++++++++++++++++++++----------------------- libsoup/soup-dns.h | 25 ++- libsoup/soup-misc.c | 13 -- libsoup/soup-private.h | 27 ---- libsoup/soup-session.c | 23 ++- libsoup/soup-socket.c | 289 +++++++++++++++++++-------------- libsoup/soup-socket.h | 27 ++-- libsoup/soup-uri.c | 15 ++ libsoup/soup-uri.h | 1 + tests/Makefile.am | 4 +- tests/auth-test.c | 3 +- tests/get.c | 2 +- tests/revserver.c | 41 +++-- tests/simple-proxy.c | 2 +- 19 files changed, 750 insertions(+), 624 deletions(-) diff --git a/ChangeLog b/ChangeLog index ab34f5e..e4b216b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,60 @@ +2003-09-09 Dan Winship + + 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 * libsoup/soup-session.c: Move a bunch of logic here from diff --git a/libsoup/soup-address.c b/libsoup/soup-address.c index b4baf20..a59a4c4 100644 --- a/libsoup/soup-address.c +++ b/libsoup/soup-address.c @@ -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); } diff --git a/libsoup/soup-address.h b/libsoup/soup-address.h index 2a1ed38..b9946f5 100644 --- a/libsoup/soup-address.h +++ b/libsoup/soup-address.h @@ -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, diff --git a/libsoup/soup-connection.c b/libsoup/soup-connection.c index fd9182d..8e9a7e8 100644 --- a/libsoup/soup-connection.c +++ b/libsoup/soup-connection.c @@ -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); } diff --git a/libsoup/soup-connection.h b/libsoup/soup-connection.h index 8dd7762..449743e 100644 --- a/libsoup/soup-connection.h +++ b/libsoup/soup-connection.h @@ -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 */ diff --git a/libsoup/soup-dns.c b/libsoup/soup-dns.c index 31e473d..77d132d 100644 --- a/libsoup/soup-dns.c +++ b/libsoup/soup-dns.c @@ -15,8 +15,8 @@ #include #include #include +#include #include -#include #include #include @@ -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); } diff --git a/libsoup/soup-dns.h b/libsoup/soup-dns.h index eba700e..2162e65 100644 --- a/libsoup/soup-dns.h +++ b/libsoup/soup-dns.h @@ -11,24 +11,19 @@ #include #include -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 */ diff --git a/libsoup/soup-misc.c b/libsoup/soup-misc.c index 13a6f62..c25950f 100644 --- a/libsoup/soup-misc.c +++ b/libsoup/soup-misc.c @@ -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) diff --git a/libsoup/soup-private.h b/libsoup/soup-private.h index 7cd8959..af8229c 100644 --- a/libsoup/soup-private.h +++ b/libsoup/soup-private.h @@ -14,10 +14,6 @@ #include #include -#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*/ diff --git a/libsoup/soup-session.c b/libsoup/soup-session.c index 3d01605..7576f61 100644 --- a/libsoup/soup-session.c +++ b/libsoup/soup-session.c @@ -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); diff --git a/libsoup/soup-socket.c b/libsoup/soup-socket.c index 2c5b56b..27454e9 100644 --- a/libsoup/soup-socket.c +++ b/libsoup/soup-socket.c @@ -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) { diff --git a/libsoup/soup-socket.h b/libsoup/soup-socket.h index fd21fb8..5b3e49f 100644 --- a/libsoup/soup-socket.h +++ b/libsoup/soup-socket.h @@ -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); diff --git a/libsoup/soup-uri.c b/libsoup/soup-uri.c index f3bcb4a..faf3ef2 100644 --- a/libsoup/soup-uri.c +++ b/libsoup/soup-uri.c @@ -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) { diff --git a/libsoup/soup-uri.h b/libsoup/soup-uri.h index 0d737ae..1afe6bc 100644 --- a/libsoup/soup-uri.h +++ b/libsoup/soup-uri.h @@ -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); diff --git a/tests/Makefile.am b/tests/Makefile.am index aa8dcc5..ec1d275 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -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 diff --git a/tests/auth-test.c b/tests/auth-test.c index 4448845..9ece051 100644 --- a/tests/auth-test.c +++ b/tests/auth-test.c @@ -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); diff --git a/tests/get.c b/tests/get.c index efb9b9d..ec1ee7b 100644 --- a/tests/get.c +++ b/tests/get.c @@ -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) { diff --git a/tests/revserver.c b/tests/revserver.c index 3620887..deecf81 100644 --- a/tests/revserver.c +++ b/tests/revserver.c @@ -3,6 +3,7 @@ #endif #include +#include #include #include #include @@ -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); } diff --git a/tests/simple-proxy.c b/tests/simple-proxy.c index 3af0a75..b5b21a4 100644 --- a/tests/simple-proxy.c +++ b/tests/simple-proxy.c @@ -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"); -- 2.7.4