summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Winship <danw@src.gnome.org>2008-01-14 20:10:51 +0000
committerDan Winship <danw@src.gnome.org>2008-01-14 20:10:51 +0000
commitb4ff33588a7fec58130fcf7295daf4cd6c192cb7 (patch)
tree1e5cfe3a0071f72261f2d70015ec990c523796f4
parentb29fa900c326c13c876021c4fae37f78d7ab1340 (diff)
downloadlibsoup-b4ff33588a7fec58130fcf7295daf4cd6c192cb7.tar.gz
require glib 2.15.0, and gio
* configure.in: require glib 2.15.0, and gio * libsoup/soup-dns.c (soup_dns_lookup_resolve) (soup_dns_lookup_resolve_async): Add GCancellables, and support cancellation of DNS lookups. (resolve_address, resolve_name): If we get a DNS failure (eg, because we're disconnected from the network), don't cache that result, just try again next time someone asks. [#508593] * libsoup/soup-address.c (soup_address_resolve_async) (soup_address_resolve_sync): Add GCancellables, pass them to soup-dns. * libsoup/soup-socket.c (soup_socket_connect_async) (soup_socket_connect_sync): Add GCancellables and implement cancellation. (soup_socket_start_ssl, soup_socket_start_proxy_ssl) (soup_socket_read, soup_socket_read_until, soup_socket_write): add GCancellables, though these routines don't actually implement cancellation yet. (soup_socket_disconnect): Don't close() the socket if someone is doing I/O on it, as that creates a race condition. (The fd number might be quickly recycled.) Instead, keep the socket open but dead, via shutdown(). svn path=/branches/libsoup-2.4/; revision=1032
-rw-r--r--ChangeLog27
-rw-r--r--configure.in2
-rw-r--r--libsoup/soup-address.c58
-rw-r--r--libsoup/soup-address.h6
-rw-r--r--libsoup/soup-connection.c15
-rw-r--r--libsoup/soup-dns.c189
-rw-r--r--libsoup/soup-dns.h8
-rw-r--r--libsoup/soup-message-io.c6
-rw-r--r--libsoup/soup-socket.c294
-rw-r--r--libsoup/soup-socket.h14
-rw-r--r--tests/Makefile.am2
-rw-r--r--tests/dns.c3
-rw-r--r--tests/revserver.c190
-rw-r--r--tests/ssl-test.c16
14 files changed, 408 insertions, 422 deletions
diff --git a/ChangeLog b/ChangeLog
index 4620afe9..23511fc4 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,30 @@
+2008-01-14 Dan Winship <danw@gnome.org>
+
+ * configure.in: require glib 2.15.0, and gio
+
+ * libsoup/soup-dns.c (soup_dns_lookup_resolve)
+ (soup_dns_lookup_resolve_async): Add GCancellables, and support
+ cancellation of DNS lookups.
+ (resolve_address, resolve_name): If we get a DNS failure (eg,
+ because we're disconnected from the network), don't cache that
+ result, just try again next time someone asks. [#508593]
+
+ * libsoup/soup-address.c (soup_address_resolve_async)
+ (soup_address_resolve_sync): Add GCancellables, pass them to
+ soup-dns.
+
+ * libsoup/soup-socket.c (soup_socket_connect_async)
+ (soup_socket_connect_sync): Add GCancellables and implement
+ cancellation.
+ (soup_socket_start_ssl, soup_socket_start_proxy_ssl)
+ (soup_socket_read, soup_socket_read_until, soup_socket_write): add
+ GCancellables, though these routines don't actually implement
+ cancellation yet.
+ (soup_socket_disconnect): Don't close() the socket if someone is
+ doing I/O on it, as that creates a race condition. (The fd number
+ might be quickly recycled.) Instead, keep the socket open but
+ dead, via shutdown().
+
2008-01-14 Benjamin Otte <otte@gnome.org>
* libsoup/soup-socket.c: (soup_socket_class_init): clarify docs for
diff --git a/configure.in b/configure.in
index a263de53..ac8c9df9 100644
--- a/configure.in
+++ b/configure.in
@@ -73,7 +73,7 @@ dnl ***********************
dnl *** Checks for glib ***
dnl ***********************
-AM_PATH_GLIB_2_0(2.12.0,,,gobject gthread)
+AM_PATH_GLIB_2_0(2.15.0,,,gobject gthread gio)
PKG_CHECK_MODULES(XML, libxml-2.0)
AC_SUBST(XML_CFLAGS)
diff --git a/libsoup/soup-address.c b/libsoup/soup-address.c
index 13509d4f..628f4ba2 100644
--- a/libsoup/soup-address.c
+++ b/libsoup/soup-address.c
@@ -374,39 +374,32 @@ typedef struct {
} SoupAddressResolveAsyncData;
static void
-free_res_data (gpointer res_data, GObject *ex_addr)
-{
- g_free (res_data);
-}
-
-static void
-lookup_resolved (SoupDNSLookup *lookup, gboolean success, gpointer user_data)
+lookup_resolved (SoupDNSLookup *lookup, guint status, gpointer user_data)
{
SoupAddressResolveAsyncData *res_data = user_data;
SoupAddress *addr;
SoupAddressCallback callback;
gpointer callback_data;
- guint status;
addr = res_data->addr;
callback = res_data->callback;
callback_data = res_data->callback_data;
- g_object_weak_unref (G_OBJECT (addr), free_res_data, res_data);
g_free (res_data);
- if (success)
+ if (status == SOUP_STATUS_OK)
update_address (addr, lookup);
- if (callback) {
- status = success ? SOUP_STATUS_OK : SOUP_STATUS_CANT_RESOLVE;
+ if (callback)
callback (addr, status, callback_data);
- }
+
+ g_object_unref (addr);
}
/**
* SoupAddressCallback:
* @addr: the #SoupAddress that was resolved
- * @status: %SOUP_STATUS_OK or %SOUP_STATUS_CANT_RESOLVE
+ * @status: %SOUP_STATUS_OK, %SOUP_STATUS_CANT_RESOLVE, or
+ * %SOUP_STATUS_CANCELLED
* @data: the user data that was passed to
* soup_address_resolve_async()
*
@@ -417,19 +410,23 @@ lookup_resolved (SoupDNSLookup *lookup, gboolean success, gpointer user_data)
* soup_address_resolve_async:
* @addr: a #SoupAddress
* @async_context: the #GMainContext to call @callback from
+ * @cancellable: a #GCancellable object, or %NULL
* @callback: callback to call with the result
* @user_data: data for @callback
*
* 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).
+ * soup_address_new_any().)
+ *
+ * If @cancellable is non-%NULL, it can be used to cancel the
+ * resolution. @callback will still be invoked in this case, with a
+ * status of %SOUP_STATUS_CANCELLED.
**/
void
soup_address_resolve_async (SoupAddress *addr, GMainContext *async_context,
- SoupAddressCallback callback,
- gpointer user_data)
+ GCancellable *cancellable,
+ SoupAddressCallback callback, gpointer user_data)
{
SoupAddressPrivate *priv;
SoupAddressResolveAsyncData *res_data;
@@ -442,30 +439,39 @@ soup_address_resolve_async (SoupAddress *addr, GMainContext *async_context,
res_data->callback = callback;
res_data->callback_data = user_data;
- g_object_weak_ref (G_OBJECT (addr), free_res_data, res_data);
- soup_dns_lookup_resolve_async (priv->lookup, async_context, lookup_resolved, res_data);
+ g_object_ref (addr);
+ soup_dns_lookup_resolve_async (priv->lookup, async_context, cancellable,
+ lookup_resolved, res_data);
}
/**
* soup_address_resolve_sync:
* @addr: a #SoupAddress
+ * @cancellable: a #GCancellable object, or %NULL
*
* Synchronously resolves the missing half of @addr, as with
* soup_address_resolve_async().
*
- * Return value: %SOUP_STATUS_OK or %SOUP_STATUS_CANT_RESOLVE
+ * If @cancellable is non-%NULL, it can be used to cancel the
+ * resolution. soup_address_resolve_sync() will then return a status
+ * of %SOUP_STATUS_CANCELLED.
+ *
+ * Return value: %SOUP_STATUS_OK, %SOUP_STATUS_CANT_RESOLVE, or
+ * %SOUP_STATUS_CANCELLED.
**/
guint
-soup_address_resolve_sync (SoupAddress *addr)
+soup_address_resolve_sync (SoupAddress *addr, GCancellable *cancellable)
{
SoupAddressPrivate *priv;
- gboolean success;
+ guint status;
g_return_val_if_fail (SOUP_IS_ADDRESS (addr), SOUP_STATUS_MALFORMED);
priv = SOUP_ADDRESS_GET_PRIVATE (addr);
- success = soup_dns_lookup_resolve (priv->lookup);
- if (success)
+ g_object_ref (addr);
+ status = soup_dns_lookup_resolve (priv->lookup, cancellable);
+ if (status == SOUP_STATUS_OK)
update_address (addr, priv->lookup);
- return success ? SOUP_STATUS_OK : SOUP_STATUS_CANT_RESOLVE;
+ g_object_unref (addr);
+ return status;
}
diff --git a/libsoup/soup-address.h b/libsoup/soup-address.h
index 6a2a1dcf..57aa9034 100644
--- a/libsoup/soup-address.h
+++ b/libsoup/soup-address.h
@@ -8,6 +8,8 @@
#include <sys/types.h>
+#include <gio/gio.h>
+
#include <libsoup/soup-portability.h>
#include <libsoup/soup-types.h>
@@ -61,9 +63,11 @@ SoupAddress *soup_address_new_any (SoupAddressFamily family,
void soup_address_resolve_async (SoupAddress *addr,
GMainContext *async_context,
+ GCancellable *cancellable,
SoupAddressCallback callback,
gpointer user_data);
-guint soup_address_resolve_sync (SoupAddress *addr);
+guint soup_address_resolve_sync (SoupAddress *addr,
+ GCancellable *cancellable);
const char *soup_address_get_name (SoupAddress *addr);
const char *soup_address_get_physical (SoupAddress *addr);
diff --git a/libsoup/soup-connection.c b/libsoup/soup-connection.c
index c7216277..aae7f12a 100644
--- a/libsoup/soup-connection.c
+++ b/libsoup/soup-connection.c
@@ -385,7 +385,8 @@ tunnel_connect_finished (SoupMessage *msg, gpointer user_data)
if (SOUP_STATUS_IS_SUCCESSFUL (status)) {
if (soup_socket_start_proxy_ssl (priv->socket,
- priv->origin_uri->host))
+ priv->origin_uri->host,
+ NULL))
priv->connected = TRUE;
else
status = SOUP_STATUS_SSL_FAILED;
@@ -440,7 +441,7 @@ socket_connect_result (SoupSocket *sock, guint status, gpointer user_data)
goto done;
if (soup_uri_is_https (priv->conn_uri)) {
- if (!soup_socket_start_ssl (sock)) {
+ if (!soup_socket_start_ssl (sock, NULL)) {
status = SOUP_STATUS_SSL_FAILED;
goto done;
}
@@ -499,7 +500,8 @@ soup_connection_connect_async (SoupConnection *conn,
SOUP_SOCKET_SSL_CREDENTIALS, priv->ssl_creds,
SOUP_SOCKET_ASYNC_CONTEXT, priv->async_context,
NULL);
- soup_socket_connect_async (priv->socket, socket_connect_result, conn);
+ soup_socket_connect_async (priv->socket, NULL,
+ socket_connect_result, conn);
g_signal_connect (priv->socket, "disconnected",
G_CALLBACK (socket_disconnected), conn);
@@ -534,7 +536,7 @@ soup_connection_connect_sync (SoupConnection *conn)
SOUP_SOCKET_TIMEOUT, priv->timeout,
NULL);
- status = soup_socket_connect_sync (priv->socket);
+ status = soup_socket_connect_sync (priv->socket, NULL);
g_object_unref (addr);
if (!SOUP_STATUS_IS_SUCCESSFUL (status))
@@ -544,7 +546,7 @@ soup_connection_connect_sync (SoupConnection *conn)
G_CALLBACK (socket_disconnected), conn);
if (soup_uri_is_https (priv->conn_uri)) {
- if (!soup_socket_start_ssl (priv->socket)) {
+ if (!soup_socket_start_ssl (priv->socket, NULL)) {
status = SOUP_STATUS_SSL_FAILED;
goto fail;
}
@@ -572,7 +574,8 @@ soup_connection_connect_sync (SoupConnection *conn)
if (SOUP_STATUS_IS_SUCCESSFUL (status)) {
if (!soup_socket_start_proxy_ssl (priv->socket,
- priv->origin_uri->host))
+ priv->origin_uri->host,
+ NULL))
status = SOUP_STATUS_SSL_FAILED;
}
}
diff --git a/libsoup/soup-dns.c b/libsoup/soup-dns.c
index 53262995..e0bb5df4 100644
--- a/libsoup/soup-dns.c
+++ b/libsoup/soup-dns.c
@@ -19,6 +19,7 @@
#include "soup-dns.h"
#include "soup-misc.h"
+#include "soup-status.h"
#ifndef INET_ADDRSTRLEN
# define INET_ADDRSTRLEN 16
@@ -122,7 +123,7 @@ typedef struct {
gboolean resolved;
GThread *resolver_thread;
- GSList *lookups;
+ GSList *async_lookups;
} SoupDNSCacheEntry;
static GHashTable *soup_dns_cache;
@@ -132,10 +133,9 @@ struct SoupDNSLookup {
SoupDNSCacheEntry *entry;
GMainContext *async_context;
+ GCancellable *cancellable;
SoupDNSCallback callback;
gpointer user_data;
-
- gboolean running;
};
static GMutex *soup_dns_lock;
@@ -320,8 +320,10 @@ resolve_address (SoupDNSCacheEntry *entry)
retval = getaddrinfo (entry->hostname, NULL, &hints, &res);
if (retval == 0) {
entry->sockaddr = g_memdup (res->ai_addr, res->ai_addrlen);
+ entry->resolved = TRUE;
freeaddrinfo (res);
- }
+ } else
+ entry->resolved = (retval != EAI_AGAIN);
#else /* !HAVE_GETADDRINFO */
@@ -336,7 +338,10 @@ resolve_address (SoupDNSCacheEntry *entry)
sin.sin_family = AF_INET;
memcpy (&sin.sin_addr, h->h_addr_list[0], sizeof (struct in_addr));
entry->sockaddr = g_memdup (&sin, sizeof (struct sockaddr_in));
- }
+ entry->resolved = TRUE;
+ } else
+ entry->resolved = (h || h_errno != TRY_AGAIN);
+
g_mutex_unlock (soup_gethost_lock);
@@ -363,10 +368,13 @@ resolve_name (SoupDNSCacheEntry *entry)
#endif
);
- if (retval == 0)
+ if (retval == 0) {
entry->hostname = name;
- else
+ entry->resolved = TRUE;
+ } else {
g_free (name);
+ entry->resolved = (retval != EAI_AGAIN);
+ }
#else /* !HAVE_GETNAMEINFO */
@@ -377,8 +385,11 @@ resolve_name (SoupDNSCacheEntry *entry)
if (sin->sin_family == AF_INET) {
h = gethostbyaddr (&sin->sin_addr, sizeof (sin->sin_addr), AF_INET);
- if (h)
+ if (h) {
entry->hostname = g_strdup (h->h_name);
+ entry->resolved = TRUE;
+ } else
+ entry->resolved = (h_errno != TRY_AGAIN);
}
g_mutex_unlock (soup_gethost_lock);
@@ -466,18 +477,30 @@ soup_dns_lookup_address (struct sockaddr *sockaddr)
return lookup;
}
+static inline guint
+resolve_status (SoupDNSCacheEntry *entry, GCancellable *cancellable)
+{
+ if (entry->resolved)
+ return SOUP_STATUS_OK;
+ else if (g_cancellable_is_cancelled (cancellable))
+ return SOUP_STATUS_CANCELLED;
+ else
+ return SOUP_STATUS_CANT_RESOLVE;
+}
+
+static void async_cancel (GCancellable *cancellable, gpointer user_data);
+
static gboolean
do_async_callback (gpointer user_data)
{
SoupDNSLookup *lookup = user_data;
+ SoupDNSCacheEntry *entry = lookup->entry;
+ GCancellable *cancellable = lookup->cancellable;
- if (lookup->running) {
- SoupDNSCacheEntry *entry = lookup->entry;
- gboolean success = (entry->hostname != NULL && entry->sockaddr != NULL);
-
- lookup->running = FALSE;
- lookup->callback (lookup, success, lookup->user_data);
- }
+ lookup->callback (lookup, resolve_status (entry, cancellable),
+ lookup->user_data);
+ if (cancellable)
+ g_signal_handlers_disconnect_by_func (cancellable, async_cancel, lookup);
return FALSE;
}
@@ -486,27 +509,26 @@ static gpointer
resolver_thread (gpointer user_data)
{
SoupDNSCacheEntry *entry = user_data;
- GSList *lookups;
+ GSList *async_lookups;
SoupDNSLookup *lookup;
if (entry->hostname == NULL)
resolve_name (entry);
- if (entry->sockaddr == NULL)
+ else if (entry->sockaddr == NULL)
resolve_address (entry);
- entry->resolved = TRUE;
entry->resolver_thread = NULL;
g_mutex_lock (soup_dns_lock);
- lookups = entry->lookups;
- entry->lookups = NULL;
+ async_lookups = entry->async_lookups;
+ entry->async_lookups = NULL;
g_mutex_unlock (soup_dns_lock);
g_cond_broadcast (soup_dns_cond);
- while (lookups) {
- lookup = lookups->data;
- lookups = g_slist_remove (lookups, lookup);
+ while (async_lookups) {
+ lookup = async_lookups->data;
+ async_lookups = g_slist_remove (async_lookups, lookup);
soup_add_idle (lookup->async_context, do_async_callback, lookup);
}
@@ -515,52 +537,100 @@ resolver_thread (gpointer user_data)
return NULL;
}
+static void
+sync_cancel (GCancellable *cancellable, gpointer user_data)
+{
+ /* We can't actually cancel the resolver thread. So we just
+ * wake up the blocking thread, which will see that
+ * @cancellable has been cancelled and then stop waiting for
+ * the result. If the resolver thread eventually finishes,
+ * its result will make it to the cache.
+ */
+ g_cond_broadcast (soup_dns_cond);
+}
+
/**
* soup_dns_lookup_resolve:
* @lookup: a #SoupDNSLookup
+ * @cancellable: a #GCancellable, or %NULL
*
- * Synchronously resolves @lookup. You can cancel a pending resolution
- * using soup_dns_lookup_cancel().
+ * Synchronously resolves @lookup.
*
- * Return value: success or failure.
+ * Return value: %SOUP_STATUS_OK, %SOUP_STATUS_CANT_RESOLVE, or
+ * %SOUP_STATUS_CANCELLED
**/
-gboolean
-soup_dns_lookup_resolve (SoupDNSLookup *lookup)
+guint
+soup_dns_lookup_resolve (SoupDNSLookup *lookup, GCancellable *cancellable)
{
SoupDNSCacheEntry *entry = lookup->entry;
+ guint cancel_id = 0;
g_mutex_lock (soup_dns_lock);
- lookup->running = TRUE;
+ if (!entry->resolved) {
+ if (!entry->resolver_thread) {
+ soup_dns_cache_entry_ref (entry);
+ entry->resolver_thread =
+ g_thread_create (resolver_thread, entry,
+ FALSE, NULL);
+ }
- if (!entry->resolved && !entry->resolver_thread) {
- soup_dns_cache_entry_ref (entry);
- entry->resolver_thread =
- g_thread_create (resolver_thread, entry, FALSE, NULL);
+ if (cancellable) {
+ cancel_id = g_signal_connect (cancellable, "cancelled",
+ G_CALLBACK (sync_cancel),
+ NULL);
+ }
}
- while (!entry->resolved && lookup->running)
+ while (entry->resolver_thread &&
+ !g_cancellable_is_cancelled (cancellable))
g_cond_wait (soup_dns_cond, soup_dns_lock);
- lookup->running = FALSE;
+ if (cancel_id)
+ g_signal_handler_disconnect (cancellable, cancel_id);
+
+ g_mutex_unlock (soup_dns_lock);
+
+ return resolve_status (entry, cancellable);
+}
+
+static void
+async_cancel (GCancellable *cancellable, gpointer user_data)
+{
+ SoupDNSLookup *lookup = user_data;
+ SoupDNSCacheEntry *entry = lookup->entry;
+
+ /* We can't actually cancel the resolver thread. So we just
+ * remove @lookup from the list of pending async lookups and
+ * invoke its callback now. If the resolver thread eventually
+ * finishes, its result will make it to the cache.
+ */
+ g_mutex_lock (soup_dns_lock);
+
+ if (g_slist_find (entry->async_lookups, lookup)) {
+ entry->async_lookups = g_slist_remove (entry->async_lookups,
+ lookup);
+ soup_add_idle (lookup->async_context, do_async_callback, lookup);
+ }
g_mutex_unlock (soup_dns_lock);
- return entry->hostname != NULL && entry->sockaddr != NULL;
}
/**
* soup_dns_lookup_resolve_async:
* @lookup: a #SoupDNSLookup
* @async_context: #GMainContext to call @callback in
+ * @cancellable: a #GCancellable, or %NULL
* @callback: callback to call when @lookup is resolved
* @user_data: data to pass to @callback;
*
* Tries to asynchronously resolve @lookup. Invokes @callback when it
- * has succeeded or failed. You can cancel a pending resolution using
- * soup_dns_lookup_cancel().
+ * has succeeded or failed.
**/
void
-soup_dns_lookup_resolve_async (SoupDNSLookup *lookup, GMainContext *async_context,
+soup_dns_lookup_resolve_async (SoupDNSLookup *lookup,
+ GMainContext *async_context,
+ GCancellable *cancellable,
SoupDNSCallback callback, gpointer user_data)
{
SoupDNSCacheEntry *entry = lookup->entry;
@@ -568,16 +638,23 @@ soup_dns_lookup_resolve_async (SoupDNSLookup *lookup, GMainContext *async_contex
g_mutex_lock (soup_dns_lock);
lookup->async_context = async_context;
+ lookup->cancellable = cancellable;
lookup->callback = callback;
lookup->user_data = user_data;
- lookup->running = TRUE;
if (!entry->resolved) {
- entry->lookups = g_slist_prepend (entry->lookups, lookup);
+ entry->async_lookups = g_slist_prepend (entry->async_lookups,
+ lookup);
+ if (cancellable) {
+ g_signal_connect (cancellable, "cancelled",
+ G_CALLBACK (async_cancel), lookup);
+ }
+
if (!entry->resolver_thread) {
soup_dns_cache_entry_ref (entry);
entry->resolver_thread =
- g_thread_create (resolver_thread, entry, FALSE, NULL);
+ g_thread_create (resolver_thread, entry,
+ FALSE, NULL);
}
} else
soup_add_idle (lookup->async_context, do_async_callback, lookup);
@@ -586,28 +663,6 @@ soup_dns_lookup_resolve_async (SoupDNSLookup *lookup, GMainContext *async_contex
}
/**
- * soup_dns_lookup_cancel:
- * @lookup: a #SoupDNSLookup
- *
- * Cancels @lookup. If @lookup was running synchronously in another
- * thread, it will immediately return %FALSE. If @lookup was running
- * asynchronously, its callback function will not be called.
- **/
-void
-soup_dns_lookup_cancel (SoupDNSLookup *lookup)
-{
- /* We never really cancel the DNS lookup itself (since GThread
- * doesn't have a kill function, and it might mess up
- * underlying resolver data anyway). But clearing lookup->running
- * and broadcasting on soup_dns_cond will immediately stop any
- * blocking synchronous lookups, and clearing lookup->running
- * will also make sure that its async callback is never invoked.
- */
- lookup->running = FALSE;
- g_cond_broadcast (soup_dns_cond);
-}
-
-/**
* soup_dns_lookup_get_hostname:
* @lookup: a #SoupDNSLookup
*
@@ -642,14 +697,12 @@ soup_dns_lookup_get_address (SoupDNSLookup *lookup)
* soup_dns_lookup_free:
* @lookup: a #SoupDNSLookup
*
- * Frees @lookup. If @lookup is still running, it will be canceled
- * first.
+ * Frees @lookup. It is an error to cancel a lookup while it is
+ * running.
**/
void
soup_dns_lookup_free (SoupDNSLookup *lookup)
{
- if (lookup->running)
- soup_dns_lookup_cancel (lookup);
soup_dns_cache_entry_unref (lookup->entry);
g_slice_free (SoupDNSLookup, lookup);
}
diff --git a/libsoup/soup-dns.h b/libsoup/soup-dns.h
index 6ff030c0..6519a9c5 100644
--- a/libsoup/soup-dns.h
+++ b/libsoup/soup-dns.h
@@ -7,6 +7,7 @@
#define SOUP_DNS_H
#include <glib.h>
+#include <gio/gio.h>
#include <sys/types.h>
#include <libsoup/soup-portability.h>
@@ -20,14 +21,15 @@ SoupDNSLookup *soup_dns_lookup_name (const char *name);
SoupDNSLookup *soup_dns_lookup_address (struct sockaddr *sockaddr);
void soup_dns_lookup_free (SoupDNSLookup *lookup);
-typedef void (*SoupDNSCallback) (SoupDNSLookup *lookup, gboolean success, gpointer user_data);
+typedef void (*SoupDNSCallback) (SoupDNSLookup *lookup, guint status, gpointer user_data);
-gboolean soup_dns_lookup_resolve (SoupDNSLookup *lookup);
+guint soup_dns_lookup_resolve (SoupDNSLookup *lookup,
+ GCancellable *cancellable);
void soup_dns_lookup_resolve_async (SoupDNSLookup *lookup,
GMainContext *async_context,
+ GCancellable *cancellable,
SoupDNSCallback callback,
gpointer user_data);
-void soup_dns_lookup_cancel (SoupDNSLookup *lookup);
char *soup_dns_lookup_get_hostname (SoupDNSLookup *lookup);
struct sockaddr *soup_dns_lookup_get_address (SoupDNSLookup *lookup);
diff --git a/libsoup/soup-message-io.c b/libsoup/soup-message-io.c
index 37fbdd65..f10d4c39 100644
--- a/libsoup/soup-message-io.c
+++ b/libsoup/soup-message-io.c
@@ -232,7 +232,7 @@ read_metadata (SoupMessage *msg, const char *boundary)
status = soup_socket_read_until (io->sock, read_buf,
sizeof (read_buf),
boundary, boundary_len,
- &nread, &done, &error);
+ &nread, &done, NULL, &error);
switch (status) {
case SOUP_SOCKET_OK:
g_byte_array_append (io->read_meta_buf, read_buf, nread);
@@ -278,7 +278,7 @@ read_body_chunk (SoupMessage *msg)
len = MIN (len, io->read_length);
status = soup_socket_read (io->sock, read_buf, len,
- &nread, &error);
+ &nread, NULL, &error);
switch (status) {
case SOUP_SOCKET_OK:
@@ -331,7 +331,7 @@ write_data (SoupMessage *msg, const char *data, guint len)
status = soup_socket_write (io->sock,
data + io->written,
len - io->written,
- &nwrote, &error);
+ &nwrote, NULL, &error);
switch (status) {
case SOUP_SOCKET_EOF:
case SOUP_SOCKET_ERROR:
diff --git a/libsoup/soup-socket.c b/libsoup/soup-socket.c
index 6d5d04d1..953c6f8e 100644
--- a/libsoup/soup-socket.c
+++ b/libsoup/soup-socket.c
@@ -87,12 +87,10 @@ static void get_property (GObject *object, guint prop_id,
GValue *value, GParamSpec *pspec);
#ifdef G_OS_WIN32
-#define SOUP_CLOSE_SOCKET(socket) closesocket (socket)
#define SOUP_IS_SOCKET_ERROR(status) ((status) == SOCKET_ERROR)
#define SOUP_IS_INVALID_SOCKET(socket) ((socket) == INVALID_SOCKET)
#define SOUP_IS_CONNECT_STATUS_INPROGRESS() (WSAGetLastError () == WSAEWOULDBLOCK)
#else
-#define SOUP_CLOSE_SOCKET(socket) close (socket)
#define SOUP_IS_SOCKET_ERROR(status) ((status) == -1)
#define SOUP_IS_INVALID_SOCKET(socket) ((socket) < 0)
#define SOUP_IS_CONNECT_STATUS_INPROGRESS() (errno == EINPROGRESS)
@@ -295,12 +293,12 @@ soup_socket_class_init (SoupSocketClass *socket_class)
static void
-update_fdflags (SoupSocketPrivate *priv)
+set_nonblocking (SoupSocketPrivate *priv)
{
- int opt;
- struct timeval timeout;
#ifndef G_OS_WIN32
int flags;
+#else
+ u_log val;
#endif
if (priv->sockfd == -1)
@@ -315,20 +313,32 @@ update_fdflags (SoupSocketPrivate *priv)
flags &= ~O_NONBLOCK;
fcntl (priv->sockfd, F_SETFL, flags);
}
- flags = fcntl (priv->sockfd, F_GETFD, 0);
- if (flags != -1) {
- flags |= FD_CLOEXEC;
- fcntl (priv->sockfd, F_SETFD, flags);
- }
-
#else
- if (priv->non_blocking) {
- u_long val = 1;
- ioctlsocket (priv->sockfd, FIONBIO, &val);
- } else {
- u_long val = 0;
- ioctlsocket (priv->sockfd, FIONBIO, &val);
- }
+ val = priv->non_blocking ? 1 : 0;
+ ioctlsocket (priv->sockfd, FIONBIO, &val);
+#endif
+}
+
+static void
+set_fdflags (SoupSocketPrivate *priv)
+{
+ int opt;
+ struct timeval timeout;
+#ifndef G_OS_WIN32
+ int flags;
+#endif
+
+ if (priv->sockfd == -1)
+ return;
+
+ set_nonblocking (priv);
+
+#ifndef G_OS_WIN32
+ flags = fcntl (priv->sockfd, F_GETFD, 0);
+ if (flags != -1) {
+ flags |= FD_CLOEXEC;
+ fcntl (priv->sockfd, F_SETFD, flags);
+ }
#endif
opt = 1;
@@ -346,6 +356,17 @@ update_fdflags (SoupSocketPrivate *priv)
timeout.tv_usec = 0;
setsockopt (priv->sockfd, SOL_SOCKET,
SO_SNDTIMEO, (void *) &timeout, sizeof (timeout));
+
+#ifndef G_OS_WIN32
+ priv->iochannel =
+ g_io_channel_unix_new (priv->sockfd);
+#else
+ priv->iochannel =
+ g_io_channel_win32_new_socket (priv->sockfd);
+#endif
+ g_io_channel_set_close_on_unref (priv->iochannel, TRUE);
+ g_io_channel_set_encoding (priv->iochannel, NULL, NULL);
+ g_io_channel_set_buffered (priv->iochannel, FALSE);
}
static void
@@ -363,7 +384,7 @@ set_property (GObject *object, guint prop_id,
break;
case PROP_NON_BLOCKING:
priv->non_blocking = g_value_get_boolean (value);
- update_fdflags (priv);
+ set_nonblocking (priv);
break;
case PROP_SSL_CREDENTIALS:
priv->ssl_creds = g_value_get_pointer (value);
@@ -438,28 +459,10 @@ soup_socket_new (const char *optname1, ...)
return sock;
}
-static GIOChannel *
-get_iochannel (SoupSocketPrivate *priv)
-{
- g_mutex_lock (priv->iolock);
- if (!priv->iochannel) {
-#ifndef G_OS_WIN32
- priv->iochannel =
- g_io_channel_unix_new (priv->sockfd);
-#else
- priv->iochannel =
- g_io_channel_win32_new_socket (priv->sockfd);
-#endif
- g_io_channel_set_close_on_unref (priv->iochannel, TRUE);
- g_io_channel_set_encoding (priv->iochannel, NULL, NULL);
- g_io_channel_set_buffered (priv->iochannel, FALSE);
- }
- g_mutex_unlock (priv->iolock);
- return priv->iochannel;
-}
-
typedef struct {
SoupSocket *sock;
+ GCancellable *cancellable;
+ guint cancel_id;
SoupSocketCallback callback;
gpointer user_data;
} SoupSocketAsyncConnectData;
@@ -469,12 +472,21 @@ idle_connect_result (gpointer user_data)
{
SoupSocketAsyncConnectData *sacd = user_data;
SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sacd->sock);
+ guint status;
priv->watch_src = NULL;
+ if (sacd->cancel_id)
+ g_signal_handler_disconnect (sacd->cancellable, sacd->cancel_id);
+
+ if (priv->sockfd == -1) {
+ if (g_cancellable_is_cancelled (sacd->cancellable))
+ status = SOUP_STATUS_CANCELLED;
+ else
+ status = SOUP_STATUS_CANT_CONNECT;
+ } else
+ status = SOUP_STATUS_OK;
- sacd->callback (sacd->sock,
- priv->sockfd != -1 ? SOUP_STATUS_OK : SOUP_STATUS_CANT_CONNECT,
- sacd->user_data);
+ sacd->callback (sacd->sock, status, sacd->user_data);
g_slice_free (SoupSocketAsyncConnectData, sacd);
return FALSE;
}
@@ -491,21 +503,13 @@ connect_watch (GIOChannel* iochannel, GIOCondition condition, gpointer data)
g_source_destroy (priv->watch_src);
priv->watch_src = NULL;
- if (condition & ~(G_IO_IN | G_IO_OUT))
- goto cant_connect;
-
- if (getsockopt (priv->sockfd, SOL_SOCKET, SO_ERROR,
- (void *)&error, (void *)&len) != 0)
- goto cant_connect;
- if (error)
- goto cant_connect;
+ if ((condition & ~(G_IO_IN | G_IO_OUT)) ||
+ (getsockopt (priv->sockfd, SOL_SOCKET, SO_ERROR,
+ (void *)&error, (void *)&len) != 0) ||
+ error)
+ disconnect_internal (priv);
return idle_connect_result (sacd);
-
- cant_connect:
- sacd->callback (sacd->sock, SOUP_STATUS_CANT_CONNECT, sacd->user_data);
- g_slice_free (SoupSocketAsyncConnectData, sacd);
- return FALSE;
}
static void
@@ -519,10 +523,52 @@ got_address (SoupAddress *addr, guint status, gpointer user_data)
return;
}
- soup_socket_connect_async (sacd->sock, sacd->callback, sacd->user_data);
+ soup_socket_connect_async (sacd->sock, sacd->cancellable,
+ sacd->callback, sacd->user_data);
g_slice_free (SoupSocketAsyncConnectData, sacd);
}
+static void
+async_cancel (GCancellable *cancellable, gpointer user_data)
+{
+ SoupSocketAsyncConnectData *sacd = user_data;
+ SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sacd->sock);
+
+ if (priv->watch_src)
+ g_source_destroy (priv->watch_src);
+ disconnect_internal (priv);
+ priv->watch_src = soup_add_idle (priv->async_context,
+ idle_connect_result, sacd);
+}
+
+static guint
+socket_connect_internal (SoupSocket *sock)
+{
+ SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock);
+ struct sockaddr *sa;
+ int len, status;
+
+ sa = soup_address_get_sockaddr (priv->remote_addr, &len);
+ if (!sa)
+ return SOUP_STATUS_CANT_RESOLVE;
+
+ priv->sockfd = socket (sa->sa_family, SOCK_STREAM, 0);
+ if (SOUP_IS_INVALID_SOCKET (priv->sockfd))
+ return SOUP_STATUS_CANT_CONNECT;
+ set_fdflags (priv);
+
+ status = connect (priv->sockfd, sa, len);
+
+ if (SOUP_IS_SOCKET_ERROR (status)) {
+ if (SOUP_IS_CONNECT_STATUS_INPROGRESS ())
+ return SOUP_STATUS_CONTINUE;
+
+ disconnect_internal (priv);
+ return SOUP_STATUS_CANT_CONNECT;
+ } else
+ return SOUP_STATUS_OK;
+}
+
/**
* SoupSocketCallback:
* @sock: the #SoupSocket
@@ -535,67 +581,92 @@ got_address (SoupAddress *addr, guint status, gpointer user_data)
/**
* soup_socket_connect_async:
* @sock: a client #SoupSocket (which must not already be connected)
+ * @cancellable: a #GCancellable, or %NULL
* @callback: callback to call after connecting
* @user_data: data to pass to @callback
*
* Begins asynchronously connecting to @sock's remote address. The
* socket will call @callback when it succeeds or fails (but not
* before returning from this function).
+ *
+ * If @cancellable is non-%NULL, it can be used to cancel the
+ * connection. @callback will still be invoked in this case, with a
+ * status of %SOUP_STATUS_CANCELLED.
**/
void
-soup_socket_connect_async (SoupSocket *sock, SoupSocketCallback callback,
- gpointer user_data)
+soup_socket_connect_async (SoupSocket *sock, GCancellable *cancellable,
+ SoupSocketCallback callback, gpointer user_data)
{
SoupSocketPrivate *priv;
SoupSocketAsyncConnectData *sacd;
- int status;
+ guint status;
g_return_if_fail (SOUP_IS_SOCKET (sock));
priv = SOUP_SOCKET_GET_PRIVATE (sock);
g_return_if_fail (priv->remote_addr != NULL);
- sacd = g_slice_new (SoupSocketAsyncConnectData);
+ sacd = g_slice_new0 (SoupSocketAsyncConnectData);
sacd->sock = sock;
+ sacd->cancellable = cancellable;
sacd->callback = callback;
sacd->user_data = user_data;
if (!soup_address_get_sockaddr (priv->remote_addr, NULL)) {
soup_address_resolve_async (priv->remote_addr,
priv->async_context,
+ cancellable,
got_address, sacd);
return;
}
- status = soup_socket_connect_sync (sock);
+ status = socket_connect_internal (sock);
if (status == SOUP_STATUS_CONTINUE) {
/* Wait for connect to succeed or fail */
priv->watch_src =
soup_add_io_watch (priv->async_context,
- get_iochannel (priv),
+ priv->iochannel,
G_IO_IN | G_IO_OUT |
G_IO_PRI | G_IO_ERR |
G_IO_HUP | G_IO_NVAL,
connect_watch, sacd);
+ if (cancellable) {
+ sacd->cancel_id =
+ g_signal_connect (cancellable, "cancelled",
+ G_CALLBACK (async_cancel),
+ sacd);
+ }
} else {
priv->watch_src = soup_add_idle (priv->async_context,
idle_connect_result, sacd);
}
}
+static void
+sync_cancel (GCancellable *cancellable, gpointer sock)
+{
+ SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock);
+
+ shutdown (priv->sockfd, SHUT_RDWR);
+}
+
/**
* soup_socket_connect_sync:
* @sock: a client #SoupSocket (which must not already be connected)
+ * @cancellable: a #GCancellable, or %NULL
*
* Attempt to synchronously connect @sock to its remote address.
*
+ * If @cancellable is non-%NULL, it can be used to cancel the
+ * connection, in which case soup_socket_connect_sync() will return
+ * %SOUP_STATUS_CANCELLED.
+ *
* Return value: a success or failure code.
**/
guint
-soup_socket_connect_sync (SoupSocket *sock)
+soup_socket_connect_sync (SoupSocket *sock, GCancellable *cancellable)
{
SoupSocketPrivate *priv;
- struct sockaddr *sa;
- int len, status;
+ guint status, cancel_id;
g_return_val_if_fail (SOUP_IS_SOCKET (sock), SOUP_STATUS_MALFORMED);
priv = SOUP_SOCKET_GET_PRIVATE (sock);
@@ -603,34 +674,30 @@ soup_socket_connect_sync (SoupSocket *sock)
g_return_val_if_fail (priv->sockfd == -1, SOUP_STATUS_MALFORMED);
g_return_val_if_fail (priv->remote_addr != NULL, SOUP_STATUS_MALFORMED);
- sa = soup_address_get_sockaddr (priv->remote_addr, &len);
- if (!sa) {
- status = soup_address_resolve_sync (priv->remote_addr);
+ if (!soup_address_get_sockaddr (priv->remote_addr, NULL)) {
+ status = soup_address_resolve_sync (priv->remote_addr,
+ cancellable);
if (!SOUP_STATUS_IS_SUCCESSFUL (status))
return status;
- sa = soup_address_get_sockaddr (priv->remote_addr, &len);
- if (!sa)
- return SOUP_STATUS_CANT_RESOLVE;
}
- priv->sockfd = socket (sa->sa_family, SOCK_STREAM, 0);
- if (SOUP_IS_INVALID_SOCKET (priv->sockfd))
- return SOUP_STATUS_CANT_CONNECT;
- update_fdflags (priv);
-
- status = connect (priv->sockfd, sa, len);
+ if (cancellable) {
+ cancel_id = g_signal_connect (cancellable, "cancelled",
+ G_CALLBACK (sync_cancel), sock);
+ }
- if (SOUP_IS_SOCKET_ERROR (status)) {
- if (SOUP_IS_CONNECT_STATUS_INPROGRESS ())
- return SOUP_STATUS_CONTINUE;
+ status = socket_connect_internal (sock);
- SOUP_CLOSE_SOCKET (priv->sockfd);
- priv->sockfd = -1;
- return SOUP_STATUS_CANT_CONNECT;
+ if (cancellable) {
+ if (status != SOUP_STATUS_OK &&
+ g_cancellable_is_cancelled (cancellable)) {
+ status = SOUP_STATUS_CANCELLED;
+ disconnect_internal (priv);
+ }
+ g_signal_handler_disconnect (cancellable, cancel_id);
}
- get_iochannel (priv);
- return SOUP_STATUS_OK;
+ return status;
}
static gboolean
@@ -660,17 +727,16 @@ listen_watch (GIOChannel* iochannel, GIOCondition condition, gpointer data)
new_priv->non_blocking = priv->non_blocking;
new_priv->is_server = TRUE;
new_priv->ssl_creds = priv->ssl_creds;
- update_fdflags (new_priv);
+ set_fdflags (new_priv);
new_priv->remote_addr = soup_address_new_from_sockaddr ((struct sockaddr *)&sa, sa_len);
if (new_priv->ssl_creds) {
- if (!soup_socket_start_ssl (new)) {
+ if (!soup_socket_start_ssl (new, NULL)) {
g_object_unref (new);
return TRUE;
}
- } else
- get_iochannel (new_priv);
+ }
g_signal_emit (sock, signals[NEW_CONNECTION], 0, new);
g_object_unref (new);
@@ -715,7 +781,7 @@ soup_socket_listen (SoupSocket *sock)
priv->sockfd = socket (sa->sa_family, SOCK_STREAM, 0);
if (SOUP_IS_INVALID_SOCKET (priv->sockfd))
goto cant_listen;
- update_fdflags (priv);
+ set_fdflags (priv);
/* Bind */
if (bind (priv->sockfd, sa, sa_len) != 0)
@@ -729,16 +795,14 @@ soup_socket_listen (SoupSocket *sock)
goto cant_listen;
priv->watch_src = soup_add_io_watch (priv->async_context,
- get_iochannel (priv),
+ priv->iochannel,
G_IO_IN | G_IO_ERR | G_IO_HUP,
listen_watch, sock);
return TRUE;
cant_listen:
- if (priv->sockfd != -1) {
- SOUP_CLOSE_SOCKET (priv->sockfd);
- priv->sockfd = -1;
- }
+ if (priv->iochannel)
+ disconnect_internal (priv);
return FALSE;
}
@@ -746,23 +810,25 @@ soup_socket_listen (SoupSocket *sock)
/**
* soup_socket_start_ssl:
* @sock: the socket
+ * @cancellable: a #GCancellable
*
* Starts using SSL on @socket.
*
* Return value: success or failure
**/
gboolean
-soup_socket_start_ssl (SoupSocket *sock)
+soup_socket_start_ssl (SoupSocket *sock, GCancellable *cancellable)
{
SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock);
- return soup_socket_start_proxy_ssl (sock, soup_address_get_name (priv->remote_addr));
+ return soup_socket_start_proxy_ssl (sock, soup_address_get_name (priv->remote_addr), cancellable);
}
/**
* soup_socket_start_proxy_ssl:
* @sock: the socket
* @ssl_host: hostname of the SSL server
+ * @cancellable: a #GCancellable
*
* Starts using SSL on @socket, expecting to find a host named
* @ssl_host.
@@ -770,13 +836,14 @@ soup_socket_start_ssl (SoupSocket *sock)
* Return value: success or failure
**/
gboolean
-soup_socket_start_proxy_ssl (SoupSocket *sock, const char *ssl_host)
+soup_socket_start_proxy_ssl (SoupSocket *sock, const char *ssl_host,
+ GCancellable *cancellable)
{
SoupSocketPrivate *priv = SOUP_SOCKET_GET_PRIVATE (sock);
GIOChannel *ssl_chan;
GIOChannel *real_chan;
- real_chan = get_iochannel (priv);
+ real_chan = priv->iochannel;
ssl_chan = soup_ssl_wrap_iochannel (
real_chan, priv->is_server ?
SOUP_SSL_TYPE_SERVER : SOUP_SSL_TYPE_CLIENT,
@@ -825,19 +892,18 @@ soup_socket_disconnect (SoupSocket *sock)
int sockfd;
/* Another thread is currently doing IO, so
- * we can't close the iochannel. So just kick
- * the file descriptor out from under it.
+ * we can't close the iochannel. So just shutdown
+ * the file descriptor to force the I/O to fail.
+ * (It will actually be closed when the socket is
+ * destroyed.)
*/
-
sockfd = priv->sockfd;
priv->sockfd = -1;
+
if (sockfd == -1)
already_disconnected = TRUE;
- else {
- g_io_channel_set_close_on_unref (priv->iochannel,
- FALSE);
- SOUP_CLOSE_SOCKET (sockfd);
- }
+ else
+ shutdown (sockfd, SHUT_RDWR);
}
if (already_disconnected)
@@ -1042,6 +1108,7 @@ read_from_buf (SoupSocket *sock, gpointer buffer, gsize len, gsize *nread)
* @buffer: buffer to read into
* @len: size of @buffer in bytes
* @nread: on return, the number of bytes read into @buffer
+ * @cancellable: a #GCancellable, or %NULL
* @error: error pointer
*
* Attempts to read up to @len bytes from @sock into @buffer. If some
@@ -1058,12 +1125,12 @@ read_from_buf (SoupSocket *sock, gpointer buffer, gsize len, gsize *nread)
*
* Return value: a #SoupSocketIOStatus, as described above (or
* %SOUP_SOCKET_EOF if the socket is no longer connected, or
- * %SOUP_SOCKET_ERROR on any other error, in which case @error
- * will also be set).
+ * %SOUP_SOCKET_ERROR on any other error, in which case @error will
+ * also be set).
**/
SoupSocketIOStatus
soup_socket_read (SoupSocket *sock, gpointer buffer, gsize len,
- gsize *nread, GError **error)
+ gsize *nread, GCancellable *cancellable, GError **error)
{
SoupSocketPrivate *priv;
SoupSocketIOStatus status;
@@ -1091,6 +1158,7 @@ soup_socket_read (SoupSocket *sock, gpointer buffer, gsize len,
* @nread: on return, the number of bytes read into @buffer
* @got_boundary: on return, whether or not the data in @buffer
* ends with the boundary string
+ * @cancellable: a #GCancellable, or %NULL
* @error: error pointer
*
* Like soup_socket_read(), but reads no further than the first
@@ -1104,7 +1172,7 @@ SoupSocketIOStatus
soup_socket_read_until (SoupSocket *sock, gpointer buffer, gsize len,
gconstpointer boundary, gsize boundary_len,
gsize *nread, gboolean *got_boundary,
- GError **error)
+ GCancellable *cancellable, GError **error)
{
SoupSocketPrivate *priv;
SoupSocketIOStatus status;
@@ -1181,6 +1249,7 @@ socket_write_watch (GIOChannel *chan, GIOCondition cond, gpointer user_data)
* @buffer: data to write
* @len: size of @buffer, in bytes
* @nwrote: on return, number of bytes written
+ * @cancellable: a #GCancellable, or %NULL
* @error: error pointer
*
* Attempts to write @len bytes from @buffer to @sock. If some data is
@@ -1200,7 +1269,8 @@ socket_write_watch (GIOChannel *chan, GIOCondition cond, gpointer user_data)
**/
SoupSocketIOStatus
soup_socket_write (SoupSocket *sock, gconstpointer buffer,
- gsize len, gsize *nwrote, GError **error)
+ gsize len, gsize *nwrote,
+ GCancellable *cancellable, GError **error)
{
SoupSocketPrivate *priv;
GIOStatus status;
diff --git a/libsoup/soup-socket.h b/libsoup/soup-socket.h
index 71e9545c..710f6fec 100644
--- a/libsoup/soup-socket.h
+++ b/libsoup/soup-socket.h
@@ -7,6 +7,7 @@
#define SOUP_SOCKET_H 1
#include <libsoup/soup-types.h>
+#include <gio/gio.h>
G_BEGIN_DECLS
@@ -51,15 +52,19 @@ SoupSocket *soup_socket_new (const char *optname1,
...) G_GNUC_NULL_TERMINATED;
void soup_socket_connect_async (SoupSocket *sock,
+ GCancellable *cancellable,
SoupSocketCallback callback,
gpointer user_data);
-guint soup_socket_connect_sync (SoupSocket *sock);
+guint soup_socket_connect_sync (SoupSocket *sock,
+ GCancellable *cancellable);
gboolean soup_socket_listen (SoupSocket *sock);
-gboolean soup_socket_start_ssl (SoupSocket *sock);
+gboolean soup_socket_start_ssl (SoupSocket *sock,
+ GCancellable *cancellable);
gboolean soup_socket_start_proxy_ssl (SoupSocket *sock,
- const char *ssl_host);
+ const char *ssl_host,
+ GCancellable *cancellable);
gboolean soup_socket_is_ssl (SoupSocket *sock);
void soup_socket_disconnect (SoupSocket *sock);
@@ -80,6 +85,7 @@ SoupSocketIOStatus soup_socket_read (SoupSocket *sock,
gpointer buffer,
gsize len,
gsize *nread,
+ GCancellable *cancellable,
GError **error);
SoupSocketIOStatus soup_socket_read_until (SoupSocket *sock,
gpointer buffer,
@@ -88,12 +94,14 @@ SoupSocketIOStatus soup_socket_read_until (SoupSocket *sock,
gsize boundary_len,
gsize *nread,
gboolean *got_boundary,
+ GCancellable *cancellable,
GError **error);
SoupSocketIOStatus soup_socket_write (SoupSocket *sock,
gconstpointer buffer,
gsize len,
gsize *nwrote,
+ GCancellable *cancellable,
GError **error);
G_END_DECLS
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 13d97590..3f9ce551 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -16,7 +16,6 @@ noinst_PROGRAMS = \
getbug \
header-parsing \
ntlm-test \
- revserver \
simple-httpd \
simple-proxy \
uri-parsing \
@@ -39,7 +38,6 @@ ntlm_test_SOURCES = ntlm-test.c $(TEST_SRCS)
proxy_test_SOURCES = proxy-test.c $(TEST_SRCS)
pull_api_SOURCES = pull-api.c $(TEST_SRCS)
query_test_SOURCES = query-test.c $(TEST_SRCS)
-revserver_SOURCES = revserver.c
server_auth_test_SOURCES = server-auth-test.c $(TEST_SRCS)
simple_httpd_SOURCES = simple-httpd.c
simple_proxy_SOURCES = simple-proxy.c
diff --git a/tests/dns.c b/tests/dns.c
index c9e3559b..10d6b98c 100644
--- a/tests/dns.c
+++ b/tests/dns.c
@@ -51,7 +51,8 @@ main (int argc, char **argv)
exit (1);
}
- soup_address_resolve_async (addr, NULL, resolve_callback, NULL);
+ soup_address_resolve_async (addr, NULL, NULL,
+ resolve_callback, NULL);
nlookups++;
}
diff --git a/tests/revserver.c b/tests/revserver.c
deleted file mode 100644
index 9be0cdf3..00000000
--- a/tests/revserver.c
+++ /dev/null
@@ -1,190 +0,0 @@
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <ctype.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <libsoup/soup-address.h>
-#include <libsoup/soup-socket.h>
-
-#include <glib/gthread.h>
-
-static void rev_read (SoupSocket *sock, GString *buf);
-static void rev_write (SoupSocket *sock, GString *buf);
-
-static void
-reverse (GString *buf)
-{
- char tmp, *a, *b;
-
- a = buf->str;
- b = buf->str + buf->len - 1;
-
- while (isspace ((unsigned char)*b) && b > a)
- b--;
-
- while (a < b) {
- tmp = *a;
- *a++ = *b;
- *b-- = tmp;
- }
-}
-
-static void
-rev_done (SoupSocket *sock, GString *buf)
-{
- g_object_unref (sock);
- g_string_free (buf, TRUE);
-}
-
-static void
-rev_write (SoupSocket *sock, GString *buf)
-{
- SoupSocketIOStatus status;
- gsize nwrote;
-
- do {
- status = soup_socket_write (sock, buf->str, buf->len,
- &nwrote, NULL);
- memmove (buf->str, buf->str + nwrote, buf->len - nwrote);
- buf->len -= nwrote;
- } while (status == SOUP_SOCKET_OK && buf->len);
-
- switch (status) {
- case SOUP_SOCKET_OK:
- rev_read (sock, buf);
- break;
-
- case SOUP_SOCKET_WOULD_BLOCK:
- g_error ("Can't happen");
- break;
-
- default:
- g_warning ("Socket error");
- /* fall through */
-
- case SOUP_SOCKET_EOF:
- rev_done (sock, buf);
- break;
- }
-}
-
-static void
-rev_read (SoupSocket *sock, GString *buf)
-{
- SoupSocketIOStatus status;
- char tmp[10];
- gsize nread;
- gboolean eol;
-
- do {
- status = soup_socket_read_until (sock, tmp, sizeof (tmp),
- "\n", 1, &nread, &eol, NULL);
- if (status == SOUP_SOCKET_OK)
- g_string_append_len (buf, tmp, nread);
- } while (status == SOUP_SOCKET_OK && !eol);
-
- switch (status) {
- case SOUP_SOCKET_OK:
- reverse (buf);
- rev_write (sock, buf);
- break;
-
- case SOUP_SOCKET_WOULD_BLOCK:
- g_error ("Can't happen");
- break;
-
- default:
- g_warning ("Socket error");
- /* fall through */
-
- case SOUP_SOCKET_EOF:
- rev_done (sock, buf);
- break;
- }
-}
-
-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)
-{
- GThread *thread;
- GError *error = NULL;
-
- g_object_ref (client);
- g_object_set (G_OBJECT (client),
- SOUP_SOCKET_FLAG_NONBLOCKING, FALSE,
- NULL);
-
- thread = g_thread_create (start_thread, client, FALSE, &error);
- if (thread == NULL) {
- g_warning ("Could not start thread: %s", error->message);
- g_error_free (error);
- g_object_unref (client);
- }
-}
-
-int
-main (int argc, char **argv)
-{
- SoupSocket *listener;
- SoupAddressFamily family = SOUP_ADDRESS_FAMILY_IPV4;
- guint port = SOUP_ADDRESS_ANY_PORT;
- SoupAddress *addr;
- GMainLoop *loop;
- int opt;
-
- g_type_init ();
- g_thread_init (NULL);
-
- while ((opt = getopt (argc, argv, "6p:")) != -1) {
- switch (opt) {
- case '6':
- family = SOUP_ADDRESS_FAMILY_IPV6;
- break;
- case 'p':
- port = atoi (optarg);
- break;
- default:
- fprintf (stderr, "Usage: %s [-6] [-p port]\n",
- argv[0]);
- exit (1);
- }
- }
-
- addr = soup_address_new_any (family, port);
- if (!addr) {
- fprintf (stderr, "Could not create listener address\n");
- exit (1);
- }
-
- listener = soup_socket_new (SOUP_SOCKET_LOCAL_ADDRESS, addr,
- NULL);
- g_object_unref (addr);
- if (!listener || !soup_socket_listen (listener)) {
- fprintf (stderr, "Could not create listening socket\n");
- exit (1);
- }
- g_signal_connect (listener, "new_connection",
- G_CALLBACK (new_connection), NULL);
- printf ("Listening on port %d\n",
- soup_address_get_port (
- soup_socket_get_local_address (listener)));
-
- loop = g_main_loop_new (NULL, TRUE);
- g_main_loop_run (loop);
-
- g_object_unref (listener);
- return 0;
-}
diff --git a/tests/ssl-test.c b/tests/ssl-test.c
index c773d707..13eed661 100644
--- a/tests/ssl-test.c
+++ b/tests/ssl-test.c
@@ -137,7 +137,8 @@ async_read (SoupSocket *sock, gpointer user_data)
do {
status = soup_socket_read (sock, data->readbuf + data->total,
- BUFSIZE - data->total, &n, &error);
+ BUFSIZE - data->total, &n,
+ NULL, &error);
if (status == SOUP_SOCKET_OK)
data->total += n;
} while (status == SOUP_SOCKET_OK && data->total < BUFSIZE);
@@ -165,7 +166,8 @@ async_write (SoupSocket *sock, gpointer user_data)
do {
status = soup_socket_write (sock, data->writebuf + data->total,
- BUFSIZE - data->total, &n, &error);
+ BUFSIZE - data->total, &n,
+ NULL, &error);
if (status == SOUP_SOCKET_OK)
data->total += n;
} while (status == SOUP_SOCKET_OK && data->total < BUFSIZE);
@@ -283,13 +285,13 @@ main (int argc, char **argv)
SOUP_SOCKET_SSL_CREDENTIALS, creds,
NULL);
g_object_unref (addr);
- status = soup_socket_connect_sync (sock);
+ status = soup_socket_connect_sync (sock, NULL);
if (status != SOUP_STATUS_OK) {
g_error ("Could not create client socket: %s",
soup_status_get_phrase (status));
}
- soup_socket_start_ssl (sock);
+ soup_socket_start_ssl (sock, NULL);
/* Now spawn server thread */
server = g_thread_create (server_thread, GINT_TO_POINTER (listener),
@@ -302,7 +304,8 @@ main (int argc, char **argv)
total = 0;
while (total < BUFSIZE) {
status = soup_socket_write (sock, writebuf + total,
- BUFSIZE - total, &n, &error);
+ BUFSIZE - total, &n,
+ NULL, &error);
if (status != SOUP_SOCKET_OK)
g_error ("Sync write got status %d: %s", status,
error ? error->message : "(unknown)");
@@ -312,7 +315,8 @@ main (int argc, char **argv)
total = 0;
while (total < BUFSIZE) {
status = soup_socket_read (sock, readbuf + total,
- BUFSIZE - total, &n, &error);
+ BUFSIZE - total, &n,
+ NULL, &error);
if (status != SOUP_SOCKET_OK)
g_error ("Sync read got status %d: %s", status,
error ? error->message : "(unknown)");