2003-08-12 Dan Winship <danw@ximian.com>
+ * configure.in (GLIB): add gobject-2.0 to the PKG_CHECK_MODULES
+ call
+
+ * libsoup/soup-address.c: Make this a GObject.
+ (soup_address_ref, soup_address_unref): Gone.
+ (soup_address_copy): Gone. Wasn't being used anyway.
+
+ * libsoup/soup-dns.c: Move all of the DNS code and caching stuff
+ here from soup-address.c, so that soup-address doesn't need to
+ worry about trying to cache zero-ref addresses.
+
+ * libsoup/soup-socket.c: Make this a GObject. Use "guint"
+ consistently for port numbers.
+ (soup_socket_ref, soup_socket_unref): Gone.
+
+ * libsoup/soup-private.h: Change the SoupSocket definition to be
+ SoupSocketPrivate. (Still need to keep this here since soup-server
+ pokes around in its internals.)
+ (SOUP_MAKE_TYPE): Copied from gal's E_MAKE_TYPE.
+
+ * libsoup/soup-server.c (read_done_cb, write_done_cb): Unref the
+ reader/writer rather than leaking them.
+
+ * libsoup/*: Use GObject methods for socket/address refcounting
+
+ * tests/auth-test.c (main)
+ * tests/timeserver.c (main): Call g_type_init.
+
+ * tests/get.c (main): Call g_type_init.
+ (get_url, got_url): Fix some bugs that could make -r mode get into
+ infinite loops downloading the same files over and over. Plug some
+ memory leaks to make this more useful for valgrinding libsoup.
+
+ * tests/simple-httpd.c (main): Call g_type_init. Set up a signal
+ handler for SIGINT so we can exit cleanly, since valgrind won't
+ give a leak report if you don't. Plug a few memory leaks.
+
+ * tests/simple-proxy.c (main): Likewise
+
+2003-08-12 Dan Winship <danw@ximian.com>
+
Pull over some new test programs from the soup-refactoring branch,
along with the SoupUri changes they depend on.
dnl *** Checks for glib ***
dnl ***********************
-PKG_CHECK_MODULES(GLIB, glib-2.0)
+PKG_CHECK_MODULES(GLIB, glib-2.0 gobject-2.0)
AC_SUBST(GLIB_CFLAGS)
AC_SUBST(GLIB_LIBS)
soup-auth.h \
soup-auth.c \
soup-context.c \
+ soup-dns.h \
+ soup-dns.c \
soup-error.c \
soup-gnutls.h \
soup-gnutls.c \
/*
* soup-address.c: Internet address handing
*
- * Authors:
- * David Helder (dhelder@umich.edu)
- * Alex Graveley (alex@ximian.com)
- *
- * Original code compliments of David Helder's GNET Networking Library, and is
- * Copyright (C) 2000 David Helder & Andrew Lanoix.
- *
- * All else Copyright (C) 2000-2002, Ximian, Inc.
+ * Copyright (C) 2000-2003, Ximian, Inc.
*/
#ifdef HAVE_CONFIG_H
#include "soup-private.h"
#include "soup-address.h"
+#include "soup-dns.h"
-struct _SoupAddress {
- gchar* name;
- int family;
+struct SoupAddressPrivate {
+ char *name;
+ int family;
union {
struct in_addr in;
#ifdef HAVE_IPV6
struct in6_addr in6;
#endif
} addr;
-
- gint ref_count;
- gint cached;
};
#include <unistd.h>
#define INADDR_NONE -1
#endif
+#define PARENT_TYPE G_TYPE_OBJECT
+static GObjectClass *parent_class;
+
+static void
+init (GObject *object)
+{
+ SoupAddress *addr = SOUP_ADDRESS (object);
+
+ addr->priv = g_new0 (SoupAddressPrivate, 1);
+}
+
+static void
+finalize (GObject *object)
+{
+ SoupAddress *addr = SOUP_ADDRESS (object);
+
+ if (addr->priv->name)
+ g_free (addr->priv->name);
+
+ g_free (addr->priv);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+class_init (GObjectClass *object_class)
+{
+ parent_class = g_type_class_ref (PARENT_TYPE);
+
+ /* virtual method override */
+ object_class->finalize = finalize;
+}
+
+SOUP_MAKE_TYPE (soup_address, SoupAddress, class_init, init, PARENT_TYPE)
+
+
static void
soup_address_new_sync_cb (SoupAddress *addr,
SoupAddressStatus status,
return ret;
}
+static SoupAddress *
+new_address (const char *name, int family, gpointer addr_data)
+{
+ SoupAddress *addr;
+
+ addr = g_object_new (SOUP_TYPE_ADDRESS, NULL);
+ if (name)
+ addr->priv->name = g_strdup (name);
+ addr->priv->family = family;
+
+ switch (family) {
+ case AF_INET:
+ memcpy (&addr->priv->addr.in, addr_data,
+ sizeof (addr->priv->addr.in));
+ break;
+
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ memcpy (&addr->priv->addr.in6, addr_data,
+ sizeof (addr->priv->addr.in6));
+ break;
+#endif
+
+ default:
+ g_object_unref (addr);
+ addr = NULL;
+ }
+
+ return addr;
+}
+
/**
* soup_address_new_from_sockaddr:
* @sa: a pointer to a sockaddr
* Return value: a #SoupAddress, or %NULL if the lookup fails.
**/
SoupAddress *
-soup_address_new_from_sockaddr (struct sockaddr *sa,
- guint *port)
+soup_address_new_from_sockaddr (struct sockaddr *sa, guint *port)
{
- SoupAddress *ia;
-
- ia = g_new0 (SoupAddress, 1);
- ia->ref_count = 1;
- ia->family = sa->sa_family;
-
- switch (ia->family) {
+ switch (sa->sa_family) {
case AF_INET:
{
struct sockaddr_in *sa_in = (struct sockaddr_in *)sa;
- memcpy (&ia->addr.in, &sa_in->sin_addr, sizeof (ia->addr.in));
if (port)
*port = g_ntohs (sa_in->sin_port);
- break;
+ return new_address (NULL, AF_INET, &sa_in->sin_addr);
}
#ifdef HAVE_IPV6
{
struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *)sa;
- memcpy (&ia->addr.in6, &sa_in6->sin6_addr, sizeof (ia->addr.in6));
if (port)
*port = g_ntohs (sa_in6->sin6_port);
- break;
+ return new_address (NULL, AF_INET6, &sa_in6->sin6_addr);
}
#endif
default:
- g_free (ia);
- ia = NULL;
- break;
+ return NULL;
}
-
- return ia;
}
/**
ipv4_any = soup_address_new_from_sockaddr ((struct sockaddr *)&sa_in, NULL);
}
- soup_address_ref (ipv4_any);
+ g_object_ref (ipv4_any);
return ipv4_any;
}
ipv6_any = soup_address_new_from_sockaddr ((struct sockaddr *)&sa_in6, NULL);
}
- soup_address_ref (ipv6_any);
+ g_object_ref (ipv6_any);
#endif
return ipv6_any;
}
-/**
- * soup_address_ref
- * @ia: SoupAddress to reference
- *
- * Increment the reference counter of the SoupAddress.
- **/
-void
-soup_address_ref (SoupAddress* ia)
-{
- g_return_if_fail (ia != NULL);
-
- ++ia->ref_count;
-}
-
-/**
- * soup_address_copy
- * @ia: SoupAddress to copy
- *
- * Creates a copy of the given SoupAddress
- **/
-SoupAddress *
-soup_address_copy (SoupAddress* ia)
-{
- SoupAddress* new_ia;
- g_return_val_if_fail (ia != NULL, NULL);
-
- new_ia = g_new0 (SoupAddress, 1);
- new_ia->ref_count = 1;
-
- new_ia->name = g_strdup (ia->name);
- new_ia->family = ia->family;
- memcpy (&new_ia->addr, &ia->addr, sizeof (new_ia->addr));
-
- return new_ia;
-}
-
static void
soup_address_get_name_sync_cb (SoupAddress *addr,
SoupAddressStatus status,
/**
* soup_address_get_name_sync:
- * @ia: a #SoupAddress
+ * @addr: a #SoupAddress
*
- * Return value: the hostname associated with @ia, as with
+ * Return value: the hostname associated with @addr, as with
* soup_address_get_name().
**/
const char *
-soup_address_get_name_sync (SoupAddress *ia)
+soup_address_get_name_sync (SoupAddress *addr)
{
const char *ret = (const char *) 0xdeadbeef;
- soup_address_get_name (ia, soup_address_get_name_sync_cb, &ret);
+ soup_address_get_name (addr, soup_address_get_name_sync_cb, &ret);
while (1) {
g_main_iteration (TRUE);
/**
* soup_address_get_canonical_name:
- * @ia: Address to get the canonical name of.
+ * @addr: Address to get the canonical name of.
*
* Get the "canonical" name of an address (eg, for IP4 the dotted
* decimal name 141.213.8.59).
* Returns: %NULL if there was an error. The caller is responsible
* for deleting the returned string.
**/
-char*
-soup_address_get_canonical_name (SoupAddress* ia)
+char *
+soup_address_get_canonical_name (SoupAddress *addr)
{
- switch (ia->family) {
+ switch (addr->priv->family) {
case AF_INET:
{
#ifdef HAVE_INET_NTOP
char buffer[INET_ADDRSTRLEN];
- inet_ntop (ia->family, &ia->addr.in, buffer, sizeof (buffer));
+ inet_ntop (addr->priv->family, &addr->priv->addr.in,
+ buffer, sizeof (buffer));
return g_strdup (buffer);
#else
- return g_strdup (inet_ntoa (ia->addr.in));
+ return g_strdup (inet_ntoa (addr->priv->addr.in));
#endif
}
{
char buffer[INET6_ADDRSTRLEN];
- inet_ntop (ia->family, &ia->addr.in6, buffer, sizeof (buffer));
+ inet_ntop (addr->priv->family, &addr->priv->addr.in6,
+ buffer, sizeof (buffer));
return g_strdup (buffer);
}
#endif
/**
* soup_address_make_sockaddr:
- * @ia: The %SoupAddress.
+ * @addr: The %SoupAddress.
* @port: The port number
* @sa: Pointer to struct sockaddr * to output the sockaddr into
* @len: Pointer to int to return the size of the sockaddr into
*
- * This creates an appropriate struct sockaddr for @ia and @port
+ * This creates an appropriate struct sockaddr for @addr and @port
* and outputs it into *@sa. The caller must free *@sa with g_free().
**/
void
-soup_address_make_sockaddr (SoupAddress *ia, guint port,
+soup_address_make_sockaddr (SoupAddress *addr, guint port,
struct sockaddr **sa, int *len)
{
- switch (ia->family) {
+ switch (addr->priv->family) {
case AF_INET:
{
struct sockaddr_in sa_in;
memset (&sa_in, 0, sizeof (sa_in));
sa_in.sin_family = AF_INET;
- memcpy (&sa_in.sin_addr, &ia->addr.in, sizeof (sa_in.sin_addr));
+ memcpy (&sa_in.sin_addr, &addr->priv->addr.in,
+ sizeof (sa_in.sin_addr));
sa_in.sin_port = g_htons (port);
*sa = g_memdup (&sa_in, sizeof (sa_in));
memset (&sa_in6, 0, sizeof (sa_in6));
sa_in6.sin6_family = AF_INET6;
- memcpy (&sa_in6.sin6_addr, &ia->addr.in6, sizeof (sa_in6.sin6_addr));
+ memcpy (&sa_in6.sin6_addr, &addr->priv->addr.in6,
+ sizeof (sa_in6.sin6_addr));
sa_in6.sin6_port = g_htons (port);
*sa = g_memdup (&sa_in6, sizeof (sa_in6));
guint
soup_address_hash (const gpointer p)
{
- const SoupAddress* ia;
+ const SoupAddress *addr;
- g_assert(p != NULL);
+ g_return_val_if_fail (p != NULL, 0);
- ia = (const SoupAddress*) p;
+ addr = (const SoupAddress*) p;
/* This isn't network byte-order transparent... (Not sure how
* that works in the v6 case.)
*/
- switch (ia->family) {
+ switch (addr->priv->family) {
case AF_INET:
- return ia->addr.in.s_addr;
+ return addr->priv->addr.in.s_addr;
#ifdef HAVE_IPV6
case AF_INET6:
{
- guint32 *addr = (guint32 *)&(ia->addr.in6.s6_addr);
- return (addr[0] ^ addr[1] ^ addr[2] ^ addr[3]);
+ guint32 *bytes = (guint32 *)&(addr->priv->addr.in6.s6_addr);
+ return (bytes[0] ^ bytes[1] ^ bytes[2] ^ bytes[3]);
}
#endif
default:
gint
soup_address_equal (const gpointer p1, const gpointer p2)
{
- const SoupAddress* ia1 = (const SoupAddress*) p1;
- const SoupAddress* ia2 = (const SoupAddress*) p2;
+ const SoupAddress *addr1 = (const SoupAddress*) p1;
+ const SoupAddress *addr2 = (const SoupAddress*) p2;
- g_assert (p1 != NULL && p2 != NULL);
+ g_return_val_if_fail (p1 != NULL && p2 != NULL, TRUE);
/* Note network byte order doesn't matter */
- return memcmp (&ia1->addr, &ia2->addr, sizeof (ia1->addr)) == 0;
+ return memcmp (&addr1->priv->addr, &addr2->priv->addr,
+ sizeof (addr1->priv->addr)) == 0;
}
-#ifdef G_ENABLE_DEBUG
-# include <sys/ptrace.h>
-# ifndef PTRACE_ATTACH
-# ifdef PT_ATTACH
-# define SOUP_PTRACE_ATTACH PT_ATTACH
-# define SOUP_PTRACE_DETACH PT_DETACH
-# endif
-# else
-# define SOUP_PTRACE_ATTACH PTRACE_ATTACH
-# define SOUP_PTRACE_DETACH PTRACE_DETACH
-# endif
-#endif
-
-/* this generally causes problems, so remove from build atm */
-#ifdef SOUP_PTRACE_ATTACH
-#undef SOUP_PTRACE_ATTACH
-#endif
-
-GHashTable *address_hash = NULL, *lookup_hash = NULL;
typedef struct {
- char *name;
-
- GSList *cb_list; /* CONTAINS: SoupAddressCbData */
- pid_t pid;
- int fd;
- guint watch;
- guchar buffer [256];
- int len;
+ SoupDNSHandle handle;
+ SoupAddressNewFn func;
+ gpointer data;
} SoupAddressLookupState;
typedef struct {
- SoupAddressLookupState *state;
- SoupAddressNewFn func;
- gpointer data;
-} SoupAddressCbData;
-
-typedef struct {
- SoupAddress *ia;
+ SoupAddress *addr;
+ SoupDNSHandle handle;
SoupAddressGetNameFn func;
gpointer data;
-
- pid_t pid;
- int fd;
- guint watch;
- guchar buffer [256 + 1];
- int len;
} SoupAddressReverseState;
-
-/* 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 gboolean
-soup_gethostbyname (const char *hostname,
- struct sockaddr **sa,
- int *sa_len)
-{
- struct hostent result_buf, *result = &result_buf;
- char *buf = NULL;
-
-#if defined(HAVE_GETHOSTBYNAME_R_GLIBC)
- {
- size_t len;
- int herr, res;
-
- len = 1024;
- buf = g_new (char, len);
-
- while ((res = gethostbyname_r (hostname,
- &result_buf,
- buf,
- len,
- &result,
- &herr)) == ERANGE) {
- len *= 2;
- buf = g_renew (char, buf, len);
- }
-
- if (res || result == NULL || result->h_addr_list [0] == NULL)
- result = NULL;
- }
-#elif defined(HAVE_GETHOSTBYNAME_R_SOLARIS)
- {
- size_t len;
- int herr;
-
- len = 1024;
- buf = g_new (char, len);
-
- while ((result = gethostbyname_r (hostname,
- &result_buf,
- buf,
- len,
- &herr)) == ERANGE) {
- len *= 2;
- buf = g_renew (char, buf, len);
- }
- }
-#elif defined(HAVE_GETHOSTBYNAME_R_HPUX)
- {
- struct hostent_data hdbuf;
-
- if (!gethostbyname_r (hostname, &result_buf, &hdbuf))
- result = NULL;
- }
-#else
- {
-#if defined(HAVE_GETHOSTBYNAME_R_GLIB_MUTEX)
- G_LOCK (gethostbyname);
-#endif
- result = gethostbyname (hostname);
- }
-#endif
-
- if (result) {
- switch (result->h_addrtype) {
- case AF_INET:
- {
- struct sockaddr_in *sa_in;
-
- sa_in = g_new0 (struct sockaddr_in, 1);
- sa_in->sin_family = AF_INET;
- memcpy (&sa_in->sin_addr, result->h_addr_list[0],
- sizeof (sa_in->sin_addr));
-
- *sa = (struct sockaddr *)sa_in;
- *sa_len = sizeof (struct sockaddr_in);
- break;
- }
-#ifdef HAVE_IPV6
- case AF_INET6:
- {
- struct sockaddr_in6 *sa_in6;
-
- sa_in6 = g_new0 (struct sockaddr_in6, 1);
- sa_in6->sin6_family = AF_INET6;
- memcpy (&sa_in6->sin6_addr, result->h_addr_list[0],
- sizeof (sa_in6->sin6_addr));
-
- *sa = (struct sockaddr *)sa_in6;
- *sa_len = sizeof (struct sockaddr_in6);
- break;
- }
-#endif
- default:
- result = NULL;
- }
- }
-
- if (buf)
- g_free (buf);
-#if defined(HAVE_GETHOSTBYNAME_R_GLIB_MUTEX)
- G_UNLOCK (gethostbyname);
-#endif
-
- return (result != NULL);
-}
-
-/*
- * Thread safe gethostbyaddr (we assume that gethostbyaddr_r follows
- * the same pattern as gethostbyname_r, so we don't have special
- * checks for it in configure.in.
- *
- * Returns the hostname, NULL if there was an error.
- */
-static char *
-soup_gethostbyaddr (SoupAddress *ia)
-{
- struct hostent result_buf, *result = &result_buf;
- char *buf = NULL, *addr;
- int length;
- char *rv;
-
- switch (ia->family) {
- case AF_INET:
- addr = (char *)&ia->addr.in;
- length = sizeof (ia->addr.in);
- break;
-#ifdef HAVE_IPV6
- case AF_INET6:
- addr = (char *)&ia->addr.in6;
- length = sizeof (ia->addr.in6);
- break;
-#endif
- default:
- return NULL;
- }
-
-#if defined(HAVE_GETHOSTBYNAME_R_GLIBC)
- {
- size_t len;
- int herr, res;
-
- len = 1024;
- buf = g_new (char, len);
-
- while ((res = gethostbyaddr_r (addr,
- length,
- ia->family,
- &result_buf,
- buf,
- len,
- &result,
- &herr)) == ERANGE) {
- len *= 2;
- buf = g_renew (char, buf, len);
- }
-
- if (res || result == NULL || result->h_name == NULL)
- result = NULL;
- }
-#elif defined(HAVE_GETHOSTBYNAME_R_SOLARIS)
- {
- size_t len;
- int herr, res;
-
- len = 1024;
- buf = g_new (char, len);
-
- while ((res = gethostbyaddr_r (addr,
- length,
- ia->family,
- &result_buf,
- buf,
- len,
- &herr)) == ERANGE) {
- len *= 2;
- buf = g_renew (char, buf, len);
- }
-
- if (res)
- result = NULL;
- }
-#elif defined(HAVE_GETHOSTBYNAME_R_HPUX)
- {
- struct hostent_data hdbuf;
-
- if (!gethostbyaddr_r (addr, length, ia->family, &result_buf, &hdbuf))
- result = NULL;
- }
-#else
- {
-#if defined(HAVE_GETHOSTBYNAME_R_GLIB_MUTEX)
- G_LOCK (gethostbyname);
-#endif
- result = gethostbyaddr (addr, length, ia->family);
- }
-#endif
-
- if (result)
- rv = g_strdup (result->h_name);
- else
- rv = NULL;
- if (buf)
- g_free (buf);
-#if defined(HAVE_GETHOSTBYNAME_R_GLIB_MUTEX)
- G_UNLOCK (gethostbyname);
-#endif
-
- return rv;
-}
-
-#define NOT_CACHED 0
-#define CACHE_OK 1
-#define MARKED_FOR_DELETE 2
-
-static gboolean
-soup_address_new_cb (GIOChannel* iochannel,
- GIOCondition condition,
- gpointer data)
+static void
+soup_address_new_cb (SoupDNSHandle handle, SoupKnownErrorCode status,
+ struct hostent *h, gpointer data)
{
SoupAddressLookupState *state = (SoupAddressLookupState*) data;
- SoupAddress *ia;
- struct sockaddr *sa;
- int sa_len;
- GSList *iter;
-
- if (!(condition & G_IO_IN)) {
- int ret;
-
- g_source_remove (state->watch);
- close (state->fd);
- while (waitpid (state->pid, &ret, 0) == -1 && errno == EINTR)
- ;
-
- if (WIFSIGNALED (ret) || WEXITSTATUS (ret) != 1)
- goto ERROR;
-
- /*
- * Exit status of one means we are inside a debugger.
- * Resolve the name synchronously.
- */
- if (!soup_gethostbyname (state->name, &sa, &sa_len))
- g_warning ("Problem resolving host name");
- } else {
- int rv;
- char* buf;
- int length;
-
- buf = &state->buffer [state->len];
- length = sizeof (state->buffer) - state->len;
- if (length == 0) goto ERROR;
-
- rv = read (state->fd, buf, length);
- if (rv < 0) goto ERROR;
-
- state->len += rv;
-
- /* Return true if there's more to read */
- if ((state->len - 1) != state->buffer [0]) return TRUE;
-
- if (state->len < 2)
- goto ERROR;
-
- /* Success. Copy resolved address. */
- sa = g_malloc (state->len - 1);
- memcpy (sa, state->buffer + 1, state->len - 1);
-
- /* Cleanup state */
- g_source_remove (state->watch);
- close (state->fd);
-
- /* FIXME: Wait for HUP signal before doing this */
- while (waitpid (state->pid, NULL, 0) == -1 && errno == EINTR)
- ;
- }
+ SoupAddress *addr = NULL;
- g_hash_table_remove (lookup_hash, state->name);
+ if (status == SOUP_ERROR_OK)
+ addr = new_address (h->h_name, h->h_addrtype, h->h_addr);
- ia = soup_address_new_from_sockaddr (sa, NULL);
- g_free (sa);
- ia->name = state->name;
- ia->cached = CACHE_OK;
- g_hash_table_insert (address_hash, ia->name, ia);
-
- for (iter = state->cb_list; iter; iter = iter->next) {
- SoupAddressCbData *cb = iter->data;
-
- soup_address_ref (ia);
- (*cb->func) (ia, SOUP_ADDRESS_STATUS_OK, cb->data);
-
- g_free (cb);
- }
- g_slist_free (state->cb_list);
+ state->func (addr,
+ addr ? SOUP_ADDRESS_STATUS_OK : SOUP_ADDRESS_STATUS_ERROR,
+ state->data);
g_free (state);
-
- /* Each callback got its own ref, but we still own the
- * original ref.
- */
- soup_address_unref (ia);
- return FALSE;
-
- ERROR:
- /* Remove the watch now in case we don't return immediately */
- g_source_remove (state->watch);
-
- /* Error out and cancel each pending lookup. When the
- * last one is canceled, state will be freed.
- */
- for (iter = state->cb_list; iter; ) {
- SoupAddressCbData *cb_data = iter->data;
-
- (*cb_data->func) (NULL,
- SOUP_ADDRESS_STATUS_ERROR,
- cb_data->data);
-
- iter = iter->next;
- soup_address_new_cancel (cb_data);
- }
-
- return FALSE;
}
/**
* soup_address_new:
* @name: a nice name (eg, mofo.eecs.umich.edu) or a dotted decimal name
- * (eg, 141.213.8.59). You can delete the after the function is called.
+ * (eg, 141.213.8.59).
* @func: Callback function.
* @data: User data passed when callback function is called.
*
- * Create a SoupAddress from a name asynchronously. Once the
- * structure is created, it will call the callback. It may call the
- * callback before the function returns. It will call the callback
- * if there is a failure.
+ * Create a SoupAddress from a name asynchronously. Once the structure
+ * is created, it will call the callback. It will call the callback if
+ * there is a failure.
*
* Currently this routine forks and does the lookup, which can cause
* some problems. In general, this will work ok for most programs most
* explosion of processes.
*
* Returns: ID of the lookup which can be used with
- * soup_address_new_cancel() to cancel it; NULL on immediate
- * success or failure.
+ * soup_address_new_cancel() to cancel it;
**/
SoupAddressNewId
-soup_address_new (const gchar* name, SoupAddressNewFn func, gpointer data)
+soup_address_new (const char *name, SoupAddressNewFn func, gpointer data)
{
- pid_t pid = -1;
- int pipes [2];
- struct in_addr inaddr;
-#ifdef HAVE_IPV6
- struct in6_addr inaddr6;
-#endif
- struct sockaddr *sa;
- int sa_len;
- SoupAddress *ia;
SoupAddressLookupState *state;
- SoupAddressCbData *cb_data;
- GIOChannel *chan;
- int inaddr_ok;
g_return_val_if_fail (name != NULL, NULL);
g_return_val_if_fail (func != NULL, NULL);
- /* Try to read the name as if were dotted decimal */
- inaddr_ok = FALSE;
+ state = g_new0 (SoupAddressLookupState, 1);
+ state->func = func;
+ state->data = data;
+ state->handle = soup_gethostbyname (name, soup_address_new_cb, state);
-#if defined(HAVE_INET_PTON)
-#ifdef HAVE_IPV6
- if (inet_pton (AF_INET6, name, &inaddr6) != 0)
- inaddr_ok = AF_INET6;
- else
-#endif
- if (inet_pton (AF_INET, name, &inaddr) != 0)
- inaddr_ok = AF_INET;
-#elif defined(HAVE_INET_ATON)
- if (inet_aton (name, &inaddr) != 0)
- inaddr_ok = AF_INET;
-#else
- inaddr.s_addr = inet_addr (name);
- if (inaddr.s_addr == INADDR_NONE)
- inaddr_ok = FALSE;
- else
- inaddr_ok = AF_INET;
-#endif
-
- if (inaddr_ok) {
- ia = g_new0 (SoupAddress, 1);
- ia->ref_count = 1;
-
- ia->family = inaddr_ok;
- switch (ia->family) {
- case AF_INET:
- memcpy (&ia->addr.in, &inaddr, sizeof (ia->addr.in));
- break;
-#ifdef HAVE_IPV6
- case AF_INET6:
- memcpy (&ia->addr.in6, &inaddr6, sizeof (ia->addr.in6));
- break;
-#endif
- }
-
- (*func) (ia, SOUP_ADDRESS_STATUS_OK, data);
- return NULL;
- }
-
- if (!address_hash) {
- address_hash = g_hash_table_new (soup_str_case_hash,
- soup_str_case_equal);
- } else {
- ia = g_hash_table_lookup (address_hash, name);
- if (ia) {
- soup_address_ref (ia);
- (*func) (ia, SOUP_ADDRESS_STATUS_OK, data);
- return NULL;
- }
- }
-
- if (!lookup_hash) {
- lookup_hash = g_hash_table_new (soup_str_case_hash,
- soup_str_case_equal);
- } else {
- state = g_hash_table_lookup (lookup_hash, name);
- if (state) {
- cb_data = g_new0 (SoupAddressCbData, 1);
- cb_data->state = state;
- cb_data->func = func;
- cb_data->data = data;
-
- state->cb_list = g_slist_prepend (state->cb_list,
- cb_data);
- return cb_data;
- }
- }
-
- /* Check to see if we are doing synchronous DNS lookups */
- if (getenv ("SOUP_SYNC_DNS")) {
- if (!soup_gethostbyname (name, &sa, &sa_len)) {
- g_warning ("Problem resolving host name");
- (*func) (NULL, SOUP_ADDRESS_STATUS_ERROR, data);
- return NULL;
- }
-
- ia = soup_address_new_from_sockaddr (sa, NULL);
- g_free (sa);
-
- (*func) (ia, SOUP_ADDRESS_STATUS_OK, data);
- return NULL;
- }
-
- /* That didn't work - we need to fork */
-
- /* Open a pipe */
- if (pipe (pipes) == -1) {
- (*func) (NULL, SOUP_ADDRESS_STATUS_ERROR, data);
- return NULL;
- }
-
- FORK_AGAIN:
- errno = 0;
- pid = fork ();
-
- switch (pid) {
- case -1:
- if (errno == EAGAIN) {
- /* Yield the processor */
- sleep(0);
- goto FORK_AGAIN;
- }
-
- /* Else there was a goofy error */
- g_warning ("Fork error: %s (%d)\n",
- g_strerror (errno),
- errno);
- close (pipes [0]);
- close (pipes [1]);
-
- (*func) (NULL, SOUP_ADDRESS_STATUS_ERROR, data);
-
- return NULL;
- case 0:
- close (pipes [0]);
-
-#ifdef SOUP_PTRACE_ATTACH
- signal (SIGCHLD, SIG_IGN);
-
- if (ptrace (SOUP_PTRACE_ATTACH, getppid (), NULL, NULL) == -1) {
- /*
- * Attach failed; it's probably already being
- * debugged.
- */
- if (errno != EPERM)
- g_warning ("ptrace: Unexpected error: %s",
- strerror(errno));
-
- _exit (1);
- }
-
- /*
- * Wait for the SIGSTOP from PTRACE_ATTACH to arrive at the
- * parent.
- */
- while (waitpid (getppid (), NULL, WUNTRACED) == -1 && errno == EINTR)
- ;
-
- if (ptrace (SOUP_PTRACE_DETACH, getppid (), NULL, NULL) == -1)
- g_warning ("ptrace: Detach failed: %s",
- strerror(errno));
-
- kill (getppid(), SIGCONT);
-#endif /*SOUP_PTRACE_ATTACH*/
-
- /*
- * Try to get the host by name (ie, DNS)
- */
- if (soup_gethostbyname (name, &sa, &sa_len)) {
- guchar size = sa_len;
-
- if ((write (pipes [1], &size, sizeof(guchar)) == -1) ||
- (write (pipes [1], sa, sa_len) == -1))
- g_warning ("Problem writing to pipe\n");
- } else {
- /* Write a zero */
- guchar zero = 0;
-
- if (write (pipes [1], &zero, sizeof(zero)) == -1)
- g_warning ("Problem writing to pipe\n");
- }
-
- /* Close the socket */
- close (pipes [1]);
-
- /* Exit (we don't want atexit called, so do _exit instead) */
- _exit (EXIT_SUCCESS);
- default:
- close (pipes [1]);
-
- /* Create a structure for the call back */
- state = g_new0 (SoupAddressLookupState, 1);
- state->name = g_strdup (name);
- state->pid = pid;
- state->fd = pipes [0];
-
- cb_data = g_new0 (SoupAddressCbData, 1);
- cb_data->state = state;
- cb_data->func = func;
- cb_data->data = data;
- state->cb_list = g_slist_prepend (state->cb_list, cb_data);
-
- g_hash_table_insert (lookup_hash, state->name, state);
-
- /* Set up a watch to read from the pipe */
- chan = g_io_channel_unix_new (pipes [0]);
- state->watch =
- g_io_add_watch(
- chan,
- G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
- soup_address_new_cb,
- state);
- g_io_channel_unref (chan);
-
- return cb_data;
- }
+ return state;
}
/**
void
soup_address_new_cancel (SoupAddressNewId id)
{
- SoupAddressCbData *cb_data = (SoupAddressCbData *)id;
- SoupAddressLookupState *state;
- GSList *iter;
-
- g_return_if_fail (cb_data != NULL);
-
- state = cb_data->state;
-
- for (iter = state->cb_list; iter; iter = iter->next) {
- if (iter->data == cb_data)
- break;
- }
- g_return_if_fail (iter != NULL);
-
- state->cb_list = g_slist_remove_link (state->cb_list, iter);
- g_slist_free_1 (iter);
- g_free (cb_data);
-
- if (!state->cb_list) {
- g_hash_table_remove (lookup_hash, state->name);
- g_free (state->name);
-
- g_source_remove (state->watch);
- close (state->fd);
- kill (state->pid, SIGKILL);
- while (waitpid (state->pid, NULL, 0) == -1 && errno == EINTR)
- ;
-
- g_free (state);
- }
-}
-
-static gboolean
-prune_zeroref_addresses_foreach (gchar *hostname,
- SoupAddress *ia,
- gint *remaining)
-{
- /*
- * References exist, clear mark.
- */
- if (ia->ref_count != 0) {
- ia->cached = CACHE_OK;
- return FALSE;
- }
-
- /*
- * Kill if marked. Otherwise mark.
- */
- if (ia->cached == MARKED_FOR_DELETE) {
- g_free (ia->name);
- g_free (ia);
- return TRUE;
- } else
- ia->cached = MARKED_FOR_DELETE;
-
- /*
- * Make sure the timeout stays around
- */
- (*remaining)++;
+ SoupAddressLookupState *state = id;
- return FALSE;
-}
-
-static guint zeroref_address_timeout_tag = 0;
-
-static gboolean
-prune_zeroref_addresses_timeout (gpointer not_used)
-{
- gint remaining = 0;
-
- if (!address_hash)
- goto REMOVE_SOURCE;
-
- /*
- * Remove all marked addresses, mark zero references.
- */
- g_hash_table_foreach_remove (address_hash,
- (GHRFunc) prune_zeroref_addresses_foreach,
- &remaining);
-
- /*
- * No new marks, so remove timeout handler
- */
- if (remaining == 0)
- goto REMOVE_SOURCE;
-
- return TRUE;
-
- REMOVE_SOURCE:
- zeroref_address_timeout_tag = 0;
- return FALSE;
+ soup_gethostby_cancel (state->handle);
+ g_free (state);
}
-/**
- * soup_address_unref
- * @ia: SoupAddress to unreference
- *
- * Remove a reference from the SoupAddress. When reference count
- * reaches 0, the address is deleted.
- **/
-void
-soup_address_unref (SoupAddress* ia)
+static void
+soup_address_get_name_cb (SoupDNSHandle handle, SoupKnownErrorCode status,
+ struct hostent *h, gpointer data)
{
- g_return_if_fail (ia != NULL);
-
- --ia->ref_count;
-
- if (ia->ref_count == 0) {
- if (ia->cached == NOT_CACHED) {
- g_free (ia->name);
- g_free (ia);
- }
- else if (!zeroref_address_timeout_tag) {
- /*
- * Cleanup zero reference addresses every 2 minutes.
- *
- * This involves an initial sweep to mark zero reference
- * addresses, then on the next sweep marked addresses
- * still not referenced are freed.
- */
- zeroref_address_timeout_tag =
- g_timeout_add (120000,
- (GSourceFunc)
- prune_zeroref_addresses_timeout,
- NULL);
- }
- }
-}
+ SoupAddressReverseState *state = data;
-static gboolean
-soup_address_get_name_cb (GIOChannel* iochannel,
- GIOCondition condition,
- gpointer data)
-{
- SoupAddressReverseState* state = data;
-
- g_return_val_if_fail (state != NULL, FALSE);
-
- /* Read from the pipe */
- if (condition & G_IO_IN) {
- int rv;
- char* buf;
- int length;
-
- buf = &state->buffer [state->len];
- length = sizeof(state->buffer) - state->len;
-
- if ((rv = read (state->fd, buf, length)) >= 0) {
- state->len += rv;
-
- /* Return true if there's more to read */
- if ((state->len - 1) != state->buffer [0])
- return TRUE;
-
- /* Copy the name */
- state->ia->name = g_strndup (&state->buffer [1],
- state->buffer [0]);
-
- /* Remove the watch now in case we don't return
- immediately */
- g_source_remove (state->watch);
-
- /* Call back */
- (*state->func) (state->ia,
- SOUP_ADDRESS_STATUS_OK,
- state->ia->name,
- state->data);
-
- close (state->fd);
- while (waitpid (state->pid, NULL, 0) == -1 && errno == EINTR)
- ;
- g_free (state);
- return FALSE;
- }
- }
+ if (status == SOUP_ERROR_OK && !state->addr->priv->name)
+ state->addr->priv->name = g_strdup (h->h_name);
- /* Remove the watch now in case we don't return immediately */
- g_source_remove (state->watch);
+ state->func (state->addr,
+ state->addr->priv->name ? SOUP_ADDRESS_STATUS_OK : SOUP_ADDRESS_STATUS_ERROR,
+ state->addr->priv->name,
+ state->data);
- /* Call back */
- (*state->func) (state->ia,
- SOUP_ADDRESS_STATUS_ERROR,
- NULL,
- state->data);
- soup_address_get_name_cancel (state);
- return FALSE;
+ g_object_unref (state->addr);
+ g_free (state);
}
/**
* soup_address_get_name:
- * @ia: Address to get the name of.
+ * @addr: Address to get the name of.
* @func: Callback function.
* @data: User data passed when callback function is called.
*
* Get the nice name of the address (eg, "mofo.eecs.umich.edu").
- * This function will use the callback once it knows the nice name.
- * It may even call the callback before it returns. The callback
- * will be called if there is an error.
+ * This function will use the callback once it knows the nice name
+ * or if there is an error.
*
* As with soup_address_new(), this forks to do the lookup.
*
* Returns: ID of the lookup which can be used with
- * soup_address_get_name_cancel() to cancel it; NULL on
- * immediate success or failure.
+ * soup_address_get_name_cancel() to cancel it;
**/
SoupAddressGetNameId
-soup_address_get_name (SoupAddress* ia,
- SoupAddressGetNameFn func,
- gpointer data)
+soup_address_get_name (SoupAddress *addr,
+ SoupAddressGetNameFn func,
+ gpointer data)
{
- SoupAddressReverseState* state;
- gchar* name;
- guchar len;
- pid_t pid = -1;
- int pipes [2], lenint;
+ SoupAddressReverseState *state;
- g_return_val_if_fail (ia != NULL, NULL);
+ g_return_val_if_fail (SOUP_IS_ADDRESS (addr), NULL);
g_return_val_if_fail (func != NULL, NULL);
- if (ia->name) {
- (func) (ia, SOUP_ADDRESS_STATUS_OK, ia->name, data);
- return NULL;
- }
-
- /* FIXME: should check SOUP_SYNC_DNS here */
-
- /* Open a pipe */
- if (pipe (pipes) != 0) {
- (func) (ia, SOUP_ADDRESS_STATUS_ERROR, NULL, data);
- return NULL;
- }
-
- FORK_AGAIN:
- errno = 0;
- pid = fork ();
-
- switch (pid) {
- case -1:
- if (errno == EAGAIN) {
- /* Yield the processor */
- sleep(0);
- goto FORK_AGAIN;
- }
+ state = g_new0 (SoupAddressReverseState, 1);
+ state->addr = g_object_ref (addr);
+ state->func = func;
+ state->data = data;
+ state->handle = soup_gethostbyaddr (&addr->priv->addr,
+ addr->priv->family,
+ soup_address_get_name_cb,
+ state);
- close(pipes[0]);
- close(pipes[1]);
-
- /* Else there was a goofy error */
- g_warning ("Fork error: %s (%d)\n",
- g_strerror(errno),
- errno);
-
- (*func) (ia, SOUP_ADDRESS_STATUS_ERROR, NULL, data);
-
- return NULL;
- case 0:
- close(pipes[0]);
-
- /* Write the name to the pipe. If we didn't get a name,
- we just write the canonical name. */
- name = soup_gethostbyaddr (ia);
- if (!name)
- name = soup_address_get_canonical_name (ia);
-
- lenint = strlen (name);
- if (lenint > 255) {
- g_warning ("Truncating domain name: %s\n", name);
- name [256] = '\0';
- lenint = 255;
- }
-
- len = lenint;
-
- if ((write (pipes [1], &len, sizeof(len)) == -1) ||
- (write (pipes [1], name, len) == -1) )
- g_warning ("Problem writing to pipe\n");
-
- g_free(name);
-
- /* Close the socket */
- close(pipes [1]);
-
- /* Exit (we don't want atexit called, so do _exit instead) */
- _exit(EXIT_SUCCESS);
- default:
- close(pipes[1]);
-
- soup_address_ref (ia);
-
- state = g_new0 (SoupAddressReverseState, 1);
- state->ia = ia;
- state->func = func;
- state->data = data;
- state->pid = pid;
- state->fd = pipes [0];
-
- /* Add a watch */
- state->watch =
- g_io_add_watch(g_io_channel_unix_new (pipes [0]),
- G_IO_IN|G_IO_ERR|G_IO_HUP|G_IO_NVAL,
- soup_address_get_name_cb,
- state);
- return state;
- }
+ return state;
}
/**
void
soup_address_get_name_cancel (SoupAddressGetNameId id)
{
- SoupAddressReverseState* state;
- state = (SoupAddressReverseState*) id;
-
- g_return_if_fail(state != NULL);
-
- soup_address_unref (state->ia);
- g_source_remove (state->watch);
+ SoupAddressReverseState *state = id;
- close (state->fd);
- kill (state->pid, SIGKILL);
- while (waitpid (state->pid, NULL, 0) == -1 && errno == EINTR)
- ;
+ g_return_if_fail (state != NULL);
+ soup_gethostby_cancel (state->handle);
+ g_object_unref (state->addr);
g_free(state);
}
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
- * Authors:
- * David Helder (dhelder@umich.edu)
- * Alex Graveley (alex@ximian.com)
- *
- * Original code compliments of David Helder's GNET Networking Library.
- *
- * Copyright (C) 2000-2002, Ximian, Inc.
+ * Copyright (C) 2000-2003, Ximian, Inc.
*/
#ifndef SOUP_ADDRESS_H
#define SOUP_ADDRESS_H
-#include <glib.h>
+#include <glib-object.h>
#include <sys/types.h>
#include <sys/socket.h>
-typedef struct _SoupAddress SoupAddress;
+#define SOUP_TYPE_ADDRESS (soup_address_get_type ())
+#define SOUP_ADDRESS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SOUP_TYPE_ADDRESS, SoupAddress))
+#define SOUP_ADDRESS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SOUP_TYPE_ADDRESS, SoupAddressClass))
+#define SOUP_IS_ADDRESS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SOUP_TYPE_ADDRESS))
+#define SOUP_IS_ADDRESS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), SOUP_TYPE_ADDRESS))
+#define SOUP_ADDRESS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SOUP_TYPE_ADDRESS, SoupAddressClass))
+
+typedef struct SoupAddressPrivate SoupAddressPrivate;
+
+typedef struct {
+ GObject parent;
+
+ SoupAddressPrivate *priv;
+} SoupAddress;
+
+typedef struct {
+ GObjectClass parent_class;
+
+} SoupAddressClass;
+
+GType soup_address_get_type (void);
+
typedef gpointer SoupAddressNewId;
SoupAddressStatus status,
gpointer user_data);
-SoupAddressNewId soup_address_new (const gchar* name,
+SoupAddressNewId soup_address_new (const char *name,
SoupAddressNewFn func,
gpointer data);
void soup_address_new_cancel (SoupAddressNewId id);
-SoupAddress *soup_address_new_sync (const gchar *name);
+SoupAddress *soup_address_new_sync (const char *name);
SoupAddress *soup_address_ipv4_any (void);
SoupAddress *soup_address_ipv6_any (void);
-void soup_address_ref (SoupAddress* ia);
-
-void soup_address_unref (SoupAddress* ia);
-
-SoupAddress * soup_address_copy (SoupAddress* ia);
-
typedef gpointer SoupAddressGetNameId;
typedef void (*SoupAddressGetNameFn) (SoupAddress *inetaddr,
SoupAddressStatus status,
- const gchar *name,
+ const char *name,
gpointer user_data);
-SoupAddressGetNameId soup_address_get_name (SoupAddress* ia,
- SoupAddressGetNameFn func,
- gpointer data);
+SoupAddressGetNameId
+ soup_address_get_name (SoupAddress *addr,
+ SoupAddressGetNameFn func,
+ gpointer data);
-void soup_address_get_name_cancel (SoupAddressGetNameId id);
+void soup_address_get_name_cancel (SoupAddressGetNameId id);
-const gchar *soup_address_get_name_sync (SoupAddress *addr);
+const char *soup_address_get_name_sync (SoupAddress *addr);
-gchar* soup_address_get_canonical_name (SoupAddress* ia);
+char *soup_address_get_canonical_name (SoupAddress *addr);
-SoupAddress *soup_address_new_from_sockaddr (struct sockaddr *sa,
- guint *port);
+SoupAddress *soup_address_new_from_sockaddr (struct sockaddr *sa,
+ guint *port);
-void soup_address_make_sockaddr (SoupAddress *ia,
- guint port,
- struct sockaddr **sa,
- int *len);
+void soup_address_make_sockaddr (SoupAddress *addr,
+ guint port,
+ struct sockaddr **sa,
+ int *len);
-guint soup_address_hash (const gpointer p);
+guint soup_address_hash (const gpointer p);
-gint soup_address_equal (const gpointer p1,
- const gpointer p2);
+gint soup_address_equal (const gpointer p1,
+ const gpointer p2);
#endif /* SOUP_ADDRESS_H */
g_io_channel_unref (conn->channel);
soup_context_unref (conn->context);
- soup_socket_unref (conn->socket);
+ g_object_unref (conn->socket);
if (conn->death_tag)
g_source_remove (conn->death_tag);
g_free (conn);
--- /dev/null
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * soup-dns.c: Async DNS code
+ *
+ * Copyright (C) 2000-2003, Ximian, Inc.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/uio.h>
+#include <sys/wait.h>
+
+#include <arpa/inet.h>
+#include <netinet/in.h>
+
+#include "soup-dns.h"
+#include "soup-private.h"
+
+#ifndef socklen_t
+# define socklen_t int
+#endif
+
+#ifndef INET_ADDRSTRLEN
+# define INET_ADDRSTRLEN 16
+# define INET6_ADDRSTRLEN 46
+#endif
+
+#ifndef INADDR_NONE
+#define INADDR_NONE -1
+#endif
+
+static struct hostent *
+new_hostent (const char *name, int type, int length, gpointer addr)
+{
+ struct hostent *h;
+
+ h = g_new0 (struct hostent, 1);
+ h->h_name = g_strdup (name);
+ h->h_aliases = NULL;
+ h->h_addrtype = type;
+ h->h_length = length;
+ h->h_addr_list = g_new (char *, 2);
+ h->h_addr_list[0] = g_memdup (addr, length);
+ h->h_addr_list[1] = NULL;
+
+ return h;
+}
+
+static struct hostent *
+copy_hostent (struct hostent *h)
+{
+ return new_hostent (h->h_name, h->h_addrtype,
+ h->h_length, h->h_addr_list[0]);
+}
+
+static void
+free_hostent (struct hostent *h)
+{
+ g_free (h->h_name);
+ g_free (h->h_addr_list[0]);
+ g_free (h->h_addr_list);
+ g_free (h);
+}
+
+static void
+write_hostent (struct hostent *h, int fd)
+{
+ guchar namelen = strlen (h->h_name) + 1;
+ guchar addrlen = h->h_length;
+ guchar addrtype = h->h_addrtype;
+ struct iovec iov[5];
+
+ iov[0].iov_base = &namelen;
+ iov[0].iov_len = 1;
+ iov[1].iov_base = h->h_name;
+ iov[1].iov_len = namelen;
+ iov[2].iov_base = &addrtype;
+ iov[2].iov_len = 1;
+ iov[3].iov_base = &addrlen;
+ iov[3].iov_len = 1;
+ iov[4].iov_base = h->h_addr_list[0];
+ iov[4].iov_len = addrlen;
+
+ if (writev (fd, iov, 5) == -1)
+ g_warning ("Problem writing to pipe");
+}
+
+static struct hostent *
+new_hostent_from_phys (const char *addr)
+{
+ struct in_addr inaddr;
+#ifdef HAVE_IPV6
+ struct in6_addr inaddr6;
+#endif
+
+#if defined(HAVE_INET_PTON)
+#ifdef HAVE_IPV6
+ if (inet_pton (AF_INET6, addr, &inaddr6) != 0)
+ return new_hostent (addr, AF_INET6, sizeof (inaddr6), &inaddr6);
+ else
+#endif
+ if (inet_pton (AF_INET, addr, &inaddr) != 0)
+ return new_hostent (addr, AF_INET, sizeof (inaddr), &inaddr);
+#elif defined(HAVE_INET_ATON)
+ if (inet_aton (addr, &inaddr) != 0)
+ return new_hostent (addr, AF_INET, sizeof (inaddr), &inaddr);
+#else
+ inaddr.s_addr = inet_addr (addr);
+ if (inaddr.s_addr != INADDR_NONE)
+ return new_hostent (addr, AF_INET, sizeof (inaddr), &inaddr);
+#endif
+
+ return NULL;
+}
+
+char *
+soup_ntop (gpointer addr, int family)
+{
+ switch (family) {
+ case AF_INET:
+ {
+#ifdef HAVE_INET_NTOP
+ char buffer[INET_ADDRSTRLEN];
+
+ inet_ntop (family, addr, buffer, sizeof (buffer));
+ return g_strdup (buffer);
+#else
+ return g_strdup (inet_ntoa (*(struct in_addr *)addr));
+#endif
+ }
+
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ {
+ char buffer[INET6_ADDRSTRLEN];
+
+ inet_ntop (family, addr, buffer, sizeof (buffer));
+ return g_strdup (buffer);
+ }
+#endif
+
+ default:
+ return NULL;
+ }
+}
+
+
+/* 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)
+{
+ struct hostent result_buf, *result = &result_buf, *out;
+ char *buf = NULL;
+
+#if defined(HAVE_GETHOSTBYNAME_R_GLIBC)
+ {
+ size_t len;
+ int herr, res;
+
+ len = 1024;
+ buf = g_new (char, len);
+
+ while ((res = gethostbyname_r (hostname,
+ &result_buf,
+ buf,
+ len,
+ &result,
+ &herr)) == ERANGE) {
+ len *= 2;
+ buf = g_renew (char, buf, len);
+ }
+
+ if (res || result == NULL || result->h_addr_list [0] == NULL)
+ result = NULL;
+ }
+#elif defined(HAVE_GETHOSTBYNAME_R_SOLARIS)
+ {
+ size_t len;
+ int herr, res;
+
+ len = 1024;
+ buf = g_new (char, len);
+
+ while ((res = gethostbyname_r (hostname,
+ &result_buf,
+ buf,
+ len,
+ &herr)) == ERANGE) {
+ len *= 2;
+ buf = g_renew (char, buf, len);
+ }
+
+ if (res)
+ result = NULL;
+ }
+#elif defined(HAVE_GETHOSTBYNAME_R_HPUX)
+ {
+ struct hostent_data hdbuf;
+
+ if (!gethostbyname_r (hostname, &result_buf, &hdbuf))
+ result = NULL;
+ }
+#else
+ {
+#if defined(HAVE_GETHOSTBYNAME_R_GLIB_MUTEX)
+ G_LOCK (gethostbyname);
+#endif
+ result = gethostbyname (hostname);
+ }
+#endif
+
+ if (result)
+ out = copy_hostent (result);
+ else
+ out = NULL;
+
+ 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)
+{
+ struct hostent result_buf, *result = &result_buf, *out;
+ char *buf = NULL;
+ int length;
+
+ switch (family) {
+ case AF_INET:
+ length = sizeof (struct in_addr);
+ break;
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ length = sizeof (struct in6_addr);
+ break;
+#endif
+ default:
+ return NULL;
+ }
+
+#if defined(HAVE_GETHOSTBYNAME_R_GLIBC)
+ {
+ size_t len;
+ int herr, res;
+
+ len = 1024;
+ buf = g_new (char, len);
+
+ while ((res = gethostbyaddr_r (addr,
+ length,
+ family,
+ &result_buf,
+ buf,
+ len,
+ &result,
+ &herr)) == ERANGE) {
+ len *= 2;
+ buf = g_renew (char, buf, len);
+ }
+
+ if (res || result == NULL || result->h_name == NULL)
+ result = NULL;
+ }
+#elif defined(HAVE_GETHOSTBYNAME_R_SOLARIS)
+ {
+ size_t len;
+ int herr, res;
+
+ len = 1024;
+ buf = g_new (char, len);
+
+ while ((res = gethostbyaddr_r (addr,
+ length,
+ family,
+ &result_buf,
+ buf,
+ len,
+ &herr)) == ERANGE) {
+ len *= 2;
+ buf = g_renew (char, buf, len);
+ }
+
+ if (res)
+ result = NULL;
+ }
+#elif defined(HAVE_GETHOSTBYNAME_R_HPUX)
+ {
+ struct hostent_data hdbuf;
+
+ if (!gethostbyaddr_r (addr, length, family, &result_buf, &hdbuf))
+ result = NULL;
+ }
+#else
+ {
+#if defined(HAVE_GETHOSTBYNAME_R_GLIB_MUTEX)
+ G_LOCK (gethostbyname);
+#endif
+ result = gethostbyaddr (addr, length, family);
+ }
+#endif
+
+ if (result)
+ out = copy_hostent (result);
+ else
+ out = NULL;
+
+ if (buf)
+ g_free (buf);
+#if defined(HAVE_GETHOSTBYNAME_R_GLIB_MUTEX)
+ G_UNLOCK (gethostbyname);
+#endif
+
+ return out;
+}
+
+
+/* Cache */
+
+typedef struct {
+ char *name;
+ struct hostent *h;
+ time_t expires;
+
+ GSList *lookups;
+
+ guint source_id;
+ pid_t lookup_pid;
+ int fd;
+} SoupDNSEntry;
+
+static GHashTable *soup_dns_entries;
+#define SOUP_DNS_ENTRIES_MAX 20
+
+static void
+free_entry (SoupDNSEntry *entry)
+{
+ g_hash_table_remove (soup_dns_entries, entry->name);
+ g_free (entry->name);
+ free_hostent (entry->h);
+ g_free (entry);
+}
+
+static void
+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)
+{
+ if (!soup_dns_entries) {
+ soup_dns_entries = g_hash_table_new (soup_str_case_hash,
+ soup_str_case_equal);
+ } else if (g_hash_table_size (soup_dns_entries) == SOUP_DNS_ENTRIES_MAX) {
+ SoupDNSEntry *prune_entry = NULL;
+
+ g_hash_table_foreach (soup_dns_entries, prune_cache_cb,
+ &prune_entry);
+ if (prune_entry)
+ free_entry (prune_entry);
+ }
+
+ entry->expires = time (0) + 60 * 60;
+ g_hash_table_insert (soup_dns_entries, entry->name, entry);
+}
+
+static SoupDNSEntry *
+lookup_entry (const char *name)
+{
+ 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);
+
+ /* FIXME: add a CANT_RESOLVE error */
+ (*info->func) (info, entry->h ? SOUP_ERROR_OK : SOUP_ERROR_CANT_CONNECT, 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;
+}
+
+/**
+ * soup_gethostbyname:
+ * @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).
+ *
+ * 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.
+ **/
+SoupDNSHandle
+soup_gethostbyname (const char *name, SoupGetHostByFn func, gpointer data)
+{
+ SoupDNSEntry *entry;
+ int pipes[2];
+ GIOChannel *chan;
+
+ /* Try the cache */
+ entry = lookup_entry (name);
+ if (entry) {
+ if (entry->expires < time (0) && !entry->source_id)
+ free_entry (entry);
+ else
+ return lookup_info (entry, func, data);
+ }
+
+ entry = g_new0 (SoupDNSEntry, 1);
+ entry->name = g_strdup (name);
+ cache_entry (entry);
+
+ /* 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);
+
+ /* 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);
+ }
+
+ /* Ok, we need to start a new lookup */
+
+ if (pipe (pipes) == -1)
+ return lookup_info (entry, func, data);
+
+ entry->lookup_pid = fork ();
+ switch (entry->lookup_pid) {
+ case -1:
+ g_warning ("Fork error: %s (%d)\n", g_strerror (errno), errno);
+ close (pipes[0]);
+ close (pipes[1]);
+
+ return lookup_info (entry, func, data);
+
+ case 0:
+ /* Child */
+ close (pipes[0]);
+
+ entry->h = soup_gethostbyname_internal (name);
+ if (entry->h)
+ write_hostent (entry->h, pipes[1]);
+
+ /* Close the socket */
+ close (pipes[1]);
+
+ /* Exit (we don't want atexit called, so do _exit instead) */
+ _exit (EXIT_SUCCESS);
+
+ default:
+ /* Parent */
+ 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);
+ }
+}
+
+SoupDNSHandle
+soup_gethostbyaddr (gpointer addr, int family,
+ SoupGetHostByFn func, gpointer data)
+{
+ SoupDNSEntry *entry;
+ int pipes[2];
+ GIOChannel *chan;
+ char *name;
+
+ name = soup_ntop (addr, family);
+ g_return_val_if_fail (name != NULL, NULL);
+
+ /* Try the cache */
+ entry = lookup_entry (name);
+ if (entry) {
+ if (entry->expires > time (0))
+ free_entry (entry);
+ else {
+ g_free (name);
+ return lookup_info (entry, func, data);
+ }
+ }
+
+ entry = g_new0 (SoupDNSEntry, 1);
+ entry->name = name;
+ cache_entry (entry);
+
+ /* 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);
+ }
+
+ if (pipe (pipes) != 0)
+ return lookup_info (entry, func, data);
+
+ entry->lookup_pid = fork ();
+ switch (entry->lookup_pid) {
+ case -1:
+ close (pipes[0]);
+ close (pipes[1]);
+
+ g_warning ("Fork error: %s (%d)\n", g_strerror(errno), errno);
+ return lookup_info (entry, func, data);
+
+ case 0:
+ /* Child */
+ close (pipes[0]);
+
+ entry->h = soup_gethostbyaddr_internal (addr, family);
+ if (entry->h)
+ write_hostent (entry->h, pipes[1]);
+
+ /* Close the socket */
+ close (pipes[1]);
+
+ /* Exit (we don't want atexit called, so do _exit instead) */
+ _exit (EXIT_SUCCESS);
+
+ default:
+ /* Parent */
+ 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);
+ }
+}
+
+void
+soup_gethostby_cancel (SoupDNSHandle id)
+{
+ SoupDNSLookupInfo *info = id;
+ SoupDNSEntry *entry = info->entry;
+
+ entry->lookups = g_slist_remove (entry->lookups, info);
+ g_free (info);
+
+ 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);
+ }
+ }
+}
--- /dev/null
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2000-2003, Ximian, Inc.
+ */
+
+#ifndef SOUP_DNS_H
+#define SOUP_DNS_H
+
+#include <glib.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+
+#include <libsoup/soup-error.h>
+
+typedef gpointer SoupDNSHandle;
+typedef void (*SoupGetHostByFn) (SoupDNSHandle handle,
+ SoupKnownErrorCode status,
+ struct hostent *h,
+ gpointer user_data);
+
+SoupDNSHandle soup_gethostbyname (const char *name,
+ SoupGetHostByFn func,
+ gpointer data);
+
+SoupDNSHandle soup_gethostbyaddr (gpointer addr,
+ int family,
+ SoupGetHostByFn func,
+ gpointer data);
+
+void soup_gethostby_cancel (SoupDNSHandle id);
+
+char *soup_ntop (gpointer addr,
+ int family);
+
+#endif /* SOUP_DNS_H */
GHashTable *auths; /* KEY: scheme:realm, VALUE: SoupAuth */
} SoupHost;
-struct _SoupSocket {
- gint sockfd;
+struct SoupSocketPrivate {
+ int sockfd;
SoupAddress *addr;
guint port;
- guint ref_count;
GIOChannel *iochannel;
};
gint len,
gchar *substr);
+
+#define SOUP_MAKE_TYPE(l,t,ci,i,parent) \
+GType l##_get_type(void)\
+{\
+ static GType type = 0; \
+ if (!type){ \
+ static GTypeInfo const object_info = { \
+ sizeof (t##Class), \
+ \
+ (GBaseInitFunc) NULL, \
+ (GBaseFinalizeFunc) NULL, \
+ \
+ (GClassInitFunc) ci, \
+ (GClassFinalizeFunc) NULL, \
+ NULL, /* class_data */ \
+ \
+ sizeof (t), \
+ 0, /* n_preallocs */ \
+ (GInstanceInitFunc) i, \
+ }; \
+ type = g_type_register_static (parent, #t, &object_info, 0); \
+ } \
+ return type; \
+}
+
#ifdef __cplusplus
}
#endif
g_source_remove (serv->accept_tag);
if (serv->listen_sock)
- soup_socket_unref (serv->listen_sock);
+ g_object_unref (serv->listen_sock);
if (serv->cgi_read_chan)
g_io_channel_unref (serv->cgi_read_chan);
*/
if (check_close_connection (msg)) {
g_io_channel_close (chan);
- soup_socket_unref (server_sock);
+ g_object_unref (server_sock);
}
else {
/*
{
SoupMessage *msg = user_data;
+ soup_transfer_write_unref (msg->priv->write_tag);
msg->priv->write_tag = 0;
destroy_message (msg);
}
SoupSocket *server_sock = msg->priv->server_sock;
gchar *host;
- host = get_server_sockname (server_sock->sockfd);
+ host = get_server_sockname (server_sock->priv->sockfd);
url =
g_strdup_printf (
"%s%s:%d%s",
SoupSocket *server_sock = req->priv->server_sock;
GIOChannel *channel;
+ soup_transfer_read_unref (req->priv->read_tag);
req->priv->read_tag = 0;
call_handler (req, data, soup_context_get_uri (req->context)->path);
if (!(condition & G_IO_IN) ||
ioctl (fd, FIONREAD, &cnt) < 0 ||
cnt <= 0)
- soup_socket_unref (data->server_sock);
+ g_object_unref (data->server_sock);
else {
msg = message_new (data->server);
if (!msg) {
g_warning ("Unable to create new incoming message\n");
- soup_socket_unref (data->server_sock);
+ g_object_unref (data->server_sock);
} else {
msg->priv->server_sock = data->server_sock;
msg->priv->read_tag =
chan = soup_socket_get_iochannel (sock);
if (server->proto == SOUP_PROTOCOL_HTTPS)
- sock->iochannel = soup_ssl_get_server_iochannel (chan);
+ sock->priv->iochannel = soup_ssl_get_server_iochannel (chan);
msg->priv->server_sock = sock;
msg->priv->read_tag =
- soup_transfer_read (sock->iochannel,
+ soup_transfer_read (sock->priv->iochannel,
FALSE,
read_headers_cb,
NULL,
address = soup_server_context_get_client_address (context);
host = g_strdup (soup_address_get_canonical_name (address));
- soup_address_unref (address);
+ g_object_unref (address);
return host;
}
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
- * soup-socket.c: Platform neutral socket networking code.
+ * soup-socket.c: Socket networking code.
*
- * Authors:
- * David Helder (dhelder@umich.edu)
- * Alex Graveley (alex@ximian.com)
- *
- * Original code compliments of David Helder's GNET Networking Library, and is
+ * Based on code in David Helder's GNET Networking Library,
* Copyright (C) 2000 David Helder & Andrew Lanoix.
*
- * All else Copyright (C) 2000-2002, Ximian, Inc.
+ * All else Copyright (C) 2000-2003, Ximian, Inc.
*/
#ifdef HAVE_CONFIG_H
# define socklen_t size_t
#endif
+#define PARENT_TYPE G_TYPE_OBJECT
+static GObjectClass *parent_class;
+
+static void
+init (GObject *object)
+{
+ SoupSocket *sock = SOUP_SOCKET (object);
+
+ sock->priv = g_new0 (SoupSocketPrivate, 1);
+ sock->priv->sockfd = -1;
+}
+
+static void
+finalize (GObject *object)
+{
+ SoupSocket *sock = SOUP_SOCKET (object);
+
+ if (sock->priv->sockfd != -1)
+ close (sock->priv->sockfd);
+
+ if (sock->priv->addr)
+ g_object_unref (sock->priv->addr);
+
+ if (sock->priv->iochannel)
+ g_io_channel_unref (sock->priv->iochannel);
+
+ g_free (sock->priv);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+class_init (GObjectClass *object_class)
+{
+ parent_class = g_type_class_ref (PARENT_TYPE);
+
+ /* virtual method override */
+ object_class->finalize = finalize;
+}
+
+SOUP_MAKE_TYPE (soup_socket, SoupSocket, class_init, init, PARENT_TYPE)
+
+
typedef struct {
SoupSocketConnectFn func;
gpointer data;
} SoupSocketConnectState;
static void
-soup_socket_connect_tcp_cb (SoupSocket* socket,
+soup_socket_connect_tcp_cb (SoupSocket *socket,
SoupSocketConnectStatus status,
gpointer data)
{
- SoupSocketConnectState* state = (SoupSocketConnectState*) data;
+ SoupSocketConnectState *state = (SoupSocketConnectState*) data;
SoupSocketConnectFn func = state->func;
gpointer user_data = state->data;
}
static void
-soup_socket_connect_inetaddr_cb (SoupAddress* inetaddr,
+soup_socket_connect_inetaddr_cb (SoupAddress *inetaddr,
SoupAddressStatus status,
gpointer data)
{
- SoupSocketConnectState* state = (SoupSocketConnectState*) data;
+ SoupSocketConnectState *state = (SoupSocketConnectState*) data;
if (status == SOUP_ADDRESS_STATUS_OK) {
state->tcp_id = soup_socket_new (inetaddr, state->port,
soup_socket_connect_tcp_cb,
state);
- soup_address_unref (inetaddr);
+ g_object_unref (inetaddr);
} else {
SoupSocketConnectFn func = state->func;
gpointer user_data = state->data;
* or fails immediately.
**/
SoupSocketConnectId
-soup_socket_connect (const gchar* hostname,
- const gint port,
+soup_socket_connect (const char *hostname,
+ guint port,
SoupSocketConnectFn func,
gpointer data)
{
- SoupSocketConnectState* state;
+ SoupSocketConnectState *state;
g_return_val_if_fail (hostname != NULL, NULL);
g_return_val_if_fail (func != NULL, NULL);
void
soup_socket_connect_cancel (SoupSocketConnectId id)
{
- SoupSocketConnectState* state = (SoupSocketConnectState*) id;
+ SoupSocketConnectState *state = (SoupSocketConnectState*) id;
g_return_if_fail (state != NULL);
}
SoupSocket *
-soup_socket_connect_sync (const gchar *name,
- const gint port)
+soup_socket_connect_sync (const char *name, guint port)
{
SoupSocket *ret = (SoupSocket *) 0xdeadbeef;
}
static void
-soup_socket_new_sync_cb (SoupSocket* socket,
- SoupSocketNewStatus status,
- gpointer data)
+soup_socket_new_sync_cb (SoupSocket *socket,
+ SoupSocketNewStatus status,
+ gpointer data)
{
SoupSocket **ret = data;
*ret = socket;
}
/**
- * soup_socket_ref
- * @s: SoupSocket to reference
- *
- * Increment the reference counter of the SoupSocket.
- **/
-void
-soup_socket_ref (SoupSocket* s)
-{
- g_return_if_fail (s != NULL);
-
- ++s->ref_count;
-}
-
-/**
- * soup_socket_unref
- * @s: #SoupSocket to unreference
- *
- * Remove a reference from the #SoupSocket. When reference count
- * reaches 0, the socket is deleted.
- **/
-void
-soup_socket_unref (SoupSocket* s)
-{
- g_return_if_fail(s != NULL);
-
- --s->ref_count;
-
- if (s->ref_count == 0) {
- close (s->sockfd);
- if (s->addr) soup_address_unref (s->addr);
- if (s->iochannel) g_io_channel_unref (s->iochannel);
-
- g_free(s);
- }
-}
-
-/**
* soup_socket_get_iochannel:
* @socket: SoupSocket to get GIOChannel from.
*
*
**/
GIOChannel*
-soup_socket_get_iochannel (SoupSocket* socket)
+soup_socket_get_iochannel (SoupSocket *socket)
{
- g_return_val_if_fail (socket != NULL, NULL);
+ g_return_val_if_fail (SOUP_IS_SOCKET (socket), NULL);
- if (socket->iochannel == NULL) {
- socket->iochannel = g_io_channel_unix_new (socket->sockfd);
- g_io_channel_set_encoding (socket->iochannel, NULL, NULL);
- g_io_channel_set_buffered (socket->iochannel, FALSE);
+ if (socket->priv->iochannel == NULL) {
+ socket->priv->iochannel = g_io_channel_unix_new (socket->priv->sockfd);
+ g_io_channel_set_encoding (socket->priv->iochannel, NULL, NULL);
+ g_io_channel_set_buffered (socket->priv->iochannel, FALSE);
}
- g_io_channel_ref (socket->iochannel);
+ g_io_channel_ref (socket->priv->iochannel);
- return socket->iochannel;
+ return socket->priv->iochannel;
}
/**
* Returns: #SoupAddress of socket; NULL on failure.
**/
SoupAddress *
-soup_socket_get_address (const SoupSocket* socket)
+soup_socket_get_address (const SoupSocket *socket)
{
- g_return_val_if_fail (socket != NULL, NULL);
- g_return_val_if_fail (socket->addr != NULL, NULL);
-
- soup_address_ref (socket->addr);
+ g_return_val_if_fail (SOUP_IS_SOCKET (socket), NULL);
+ g_return_val_if_fail (socket->priv->addr != NULL, NULL);
- return socket->addr;
+ return g_object_ref (socket->priv->addr);
}
/**
*
* Returns: Port number of the socket.
**/
-gint
-soup_socket_get_port(const SoupSocket* socket)
+guint
+soup_socket_get_port (const SoupSocket *socket)
{
- g_return_val_if_fail (socket != NULL, 0);
+ g_return_val_if_fail (SOUP_IS_SOCKET (socket), 0);
- return socket->port;
+ return socket->priv->port;
}
/**
SoupSocket *
soup_socket_server_new (SoupAddress *local_addr, guint local_port)
{
- SoupSocket* s;
+ SoupSocket *s;
struct sockaddr *sa = NULL;
struct soup_sockaddr_max bound_sa;
int sa_len;
const int on = 1;
- gint flags;
+ int flags;
g_return_val_if_fail (local_addr != NULL, NULL);
soup_address_make_sockaddr (local_addr, local_port, &sa, &sa_len);
/* Create socket */
- s = g_new0 (SoupSocket, 1);
- s->ref_count = 1;
+ s = g_object_new (SOUP_TYPE_SOCKET, NULL);
- if ((s->sockfd = socket (sa->sa_family, SOCK_STREAM, 0)) < 0) {
- g_free (s);
+ if ((s->priv->sockfd = socket (sa->sa_family, SOCK_STREAM, 0)) < 0) {
+ g_object_unref (s);
g_free (sa);
return NULL;
}
/* Set REUSEADDR so we can reuse the port */
- if (setsockopt (s->sockfd,
+ if (setsockopt (s->priv->sockfd,
SOL_SOCKET,
SO_REUSEADDR,
&on,
g_warning("Can't set reuse on tcp socket\n");
/* Get the flags (should all be 0?) */
- flags = fcntl (s->sockfd, F_GETFL, 0);
+ flags = fcntl (s->priv->sockfd, F_GETFL, 0);
if (flags == -1) goto SETUP_ERROR;
/* Make the socket non-blocking */
- if (fcntl (s->sockfd, F_SETFL, flags | O_NONBLOCK) == -1)
+ if (fcntl (s->priv->sockfd, F_SETFL, flags | O_NONBLOCK) == -1)
goto SETUP_ERROR;
/* Bind */
- if (bind (s->sockfd, sa, sa_len) != 0)
+ if (bind (s->priv->sockfd, sa, sa_len) != 0)
goto SETUP_ERROR;
g_free (sa);
sa_len = sizeof (bound_sa);
- getsockname (s->sockfd, (struct sockaddr *)&bound_sa, &sa_len);
- s->addr = soup_address_new_from_sockaddr ((struct sockaddr *)&bound_sa,
- &s->port);
+ getsockname (s->priv->sockfd, (struct sockaddr *)&bound_sa, &sa_len);
+ s->priv->addr =
+ soup_address_new_from_sockaddr ((struct sockaddr *)&bound_sa,
+ &s->priv->port);
/* Listen */
- if (listen (s->sockfd, 10) != 0) goto SETUP_ERROR;
+ if (listen (s->priv->sockfd, 10) != 0) goto SETUP_ERROR;
return s;
SETUP_ERROR:
- close (s->sockfd);
- g_free (s);
+ g_object_unref (s);
g_free (sa);
return NULL;
}
G_IO_ERR | G_IO_HUP | G_IO_NVAL)
typedef struct {
- gint sockfd;
+ int sockfd;
SoupAddress *addr;
guint port;
SoupSocketNewFn func;
gpointer data;
- gint flags;
+ int flags;
guint connect_watch;
} SoupSocketState;
static gboolean
-soup_socket_new_cb (GIOChannel* iochannel,
+soup_socket_new_cb (GIOChannel *iochannel,
GIOCondition condition,
gpointer data)
{
- SoupSocketState* state = (SoupSocketState*) data;
- SoupSocket* s;
- gint error = 0;
- gint len = sizeof (gint);
+ SoupSocketState *state = (SoupSocketState*) data;
+ SoupSocket *s;
+ int error = 0;
+ int len = sizeof (int);
/* Remove the watch now in case we don't return immediately */
g_source_remove (state->connect_watch);
if (fcntl (state->sockfd, F_SETFL, state->flags) != 0)
goto ERROR;
- s = g_new0 (SoupSocket, 1);
- s->ref_count = 1;
- s->sockfd = state->sockfd;
- s->addr = state->addr;
- s->port = state->port;
+ s = g_object_new (SOUP_TYPE_SOCKET, NULL);
+ s->priv->sockfd = state->sockfd;
+ s->priv->addr = state->addr;
+ s->priv->port = state->port;
(*state->func) (s, SOUP_SOCKET_NEW_STATUS_OK, state->data);
return FALSE;
ERROR:
- soup_address_unref (state->addr);
+ g_object_unref (state->addr);
(*state->func) (NULL, SOUP_SOCKET_NEW_STATUS_ERROR, state->data);
g_free (state);
SoupSocketNewFn func,
gpointer data)
{
- gint sockfd;
- gint flags;
- SoupSocketState* state;
+ int sockfd;
+ int flags;
+ SoupSocketState *state;
GIOChannel *chan;
struct sockaddr *sa;
int len;
g_free (sa);
/* Unref in soup_socket_new_cb if failure */
- soup_address_ref (addr);
+ g_object_ref (addr);
/* Connect succeeded, return immediately */
if (!errno) {
- SoupSocket *s = g_new0 (SoupSocket, 1);
- s->ref_count = 1;
- s->sockfd = sockfd;
- s->addr = addr;
+ SoupSocket *s = g_object_new (SOUP_TYPE_SOCKET, NULL);
+ s->priv->sockfd = sockfd;
+ s->priv->addr = addr;
(*func) (s, SOUP_SOCKET_NEW_STATUS_OK, data);
return NULL;
void
soup_socket_new_cancel (SoupSocketNewId id)
{
- SoupSocketState* state = (SoupSocketState*) id;
+ SoupSocketState *state = (SoupSocketState*) id;
g_source_remove (state->connect_watch);
- soup_address_unref (state->addr);
+ g_object_unref (state->addr);
g_free (state);
}
struct soup_sockaddr_max sa;
socklen_t n;
fd_set fdset;
- SoupSocket* s;
+ SoupSocket *s;
- g_return_val_if_fail (socket != NULL, NULL);
+ g_return_val_if_fail (SOUP_IS_SOCKET (socket), NULL);
try_again:
FD_ZERO (&fdset);
- FD_SET (socket->sockfd, &fdset);
+ FD_SET (socket->priv->sockfd, &fdset);
- if (select (socket->sockfd + 1, &fdset, NULL, NULL, NULL) == -1) {
+ if (select (socket->priv->sockfd + 1, &fdset, NULL, NULL, NULL) == -1) {
if (errno == EINTR) goto try_again;
return NULL;
}
n = sizeof(sa);
- if ((sockfd = accept (socket->sockfd, (struct sockaddr *)&sa, &n)) == -1) {
+ if ((sockfd = accept (socket->priv->sockfd, (struct sockaddr *)&sa, &n)) == -1) {
if (!block)
return NULL;
if (errno == EWOULDBLOCK ||
if (fcntl (sockfd, F_SETFL, flags | O_NONBLOCK) == -1)
return NULL;
- s = g_new0 (SoupSocket, 1);
- s->ref_count = 1;
- s->sockfd = sockfd;
- s->addr = soup_address_new_from_sockaddr ((struct sockaddr *)&sa,
- &s->port);
+ s = g_object_new (SOUP_TYPE_SOCKET, NULL);
+ s->priv->sockfd = sockfd;
+ s->priv->addr = soup_address_new_from_sockaddr ((struct sockaddr *)&sa,
+ &s->priv->port);
return s;
}
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
- * soup-socket.c: ronous Callback-based HTTP Request Queue.
- *
- * Authors:
- * David Helder (dhelder@umich.edu)
- * Alex Graveley (alex@ximian.com)
- *
- * Original code compliments of David Helder's GNET Networking Library.
- *
- * Copyright (C) 2000-2002, Ximian, Inc.
+ * Copyright (C) 2000-2003, Ximian, Inc.
*/
#ifndef SOUP_SOCKET_H
#define SOUP_SOCKET_H 1
-#include <glib.h>
+#include <glib-object.h>
#include <libsoup/soup-address.h>
-typedef struct _SoupSocket SoupSocket;
+#define SOUP_TYPE_SOCKET (soup_socket_get_type ())
+#define SOUP_SOCKET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SOUP_TYPE_SOCKET, SoupSocket))
+#define SOUP_SOCKET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SOUP_TYPE_SOCKET, SoupSocketClass))
+#define SOUP_IS_SOCKET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SOUP_TYPE_SOCKET))
+#define SOUP_IS_SOCKET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), SOUP_TYPE_SOCKET))
+#define SOUP_SOCKET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SOUP_TYPE_SOCKET, SoupSocketClass))
+
+typedef struct SoupSocketPrivate SoupSocketPrivate;
+
+typedef struct {
+ GObject parent;
+
+ SoupSocketPrivate *priv;
+} SoupSocket;
+
+typedef struct {
+ GObjectClass parent_class;
+
+} SoupSocketClass;
+
+GType soup_socket_get_type (void);
+
typedef gpointer SoupSocketConnectId;
SoupSocketConnectStatus status,
gpointer data);
-SoupSocketConnectId soup_socket_connect (const gchar* hostname,
- const gint port,
+SoupSocketConnectId soup_socket_connect (const char *hostname,
+ guint port,
SoupSocketConnectFn func,
gpointer data);
void soup_socket_connect_cancel (SoupSocketConnectId id);
-SoupSocket *soup_socket_connect_sync (const gchar *hostname,
- const gint port);
+SoupSocket *soup_socket_connect_sync (const char *hostname,
+ guint port);
typedef gpointer SoupSocketNewId;
guint port);
-void soup_socket_ref (SoupSocket* s);
-
-void soup_socket_unref (SoupSocket* s);
-
GIOChannel *soup_socket_get_iochannel (SoupSocket* socket);
SoupAddress *soup_socket_get_address (const SoupSocket* socket);
-gint soup_socket_get_port (const SoupSocket* socket);
+guint soup_socket_get_port (const SoupSocket* socket);
#define SOUP_SERVER_ANY_PORT 0
soup_context_unref (sd->dest_ctx);
if (sd->dest_addr)
- soup_address_unref (sd->dest_addr);
+ g_object_unref (sd->dest_addr);
while (g_source_remove_by_user_data (sd))
continue;
char *expected;
int i;
+ g_type_init ();
+
for (i = 0; i < ntests; i++) {
printf ("Test %d: %s\n", i + 1, tests[i].explanation);
goto DONE;
}
printf ("%s: %d %s\n", name, msg->errorcode, msg->errorphrase);
+
+ name += strlen (base_uri->path);
+ if (*name == '/')
+ name++;
+
if (SOUP_ERROR_IS_REDIRECTION (msg->errorcode)) {
+ unlink (name);
header = soup_message_get_header (msg->response_headers, "Location");
if (header) {
printf (" -> %s\n", header);
if (!SOUP_ERROR_IS_SUCCESSFUL (msg->errorcode))
goto DONE;
- name += strlen (base_uri->path);
- if (*name == '/')
- name++;
-
if (recurse)
fd = open (name, O_WRONLY | O_CREAT | O_TRUNC, 0644);
else
g_ptr_array_free (hrefs, TRUE);
DONE:
+ soup_uri_free (uri);
if (!--pending)
g_main_quit (loop);
}
*/
name = url_to_get + strlen (base);
+ if (*name == '/')
+ name++;
if (access (name, F_OK) == 0) {
g_free (url_to_get);
return;
{
int opt;
+ g_type_init ();
while ((opt = getopt (argc, argv, "r")) != -1) {
switch (opt) {
case 'r':
loop = g_main_loop_new (NULL, TRUE);
g_main_run (loop);
+ g_main_loop_unref (loop);
+
+ soup_uri_free (base_uri);
return 0;
}
#include <ctype.h>
#include <fcntl.h>
#include <errno.h>
+#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
goto DONE;
}
} else
- path = "";
+ path = g_strdup ("");
path_to_open = g_strdup_printf (".%s", path);
soup_message_set_error (msg, SOUP_ERROR_OK);
DONE:
+ g_free (path);
printf (" -> %d %s\n\n", msg->errorcode, msg->errorphrase);
}
+static void
+quit (int sig)
+{
+ /* Exit cleanly on ^C in case we're valgrinding. */
+ exit (0);
+}
+
int
main (int argc, char **argv)
{
GMainLoop *loop;
+ SoupServer *server, *ssl_server;
int opt;
int port = SOUP_SERVER_ANY_PORT;
int ssl_port = SOUP_SERVER_ANY_PORT;
- SoupServer *server, *ssl_server;
+
+ g_type_init ();
+ signal (SIGINT, quit);
while ((opt = getopt (argc, argv, "p:s:")) != -1) {
switch (opt) {
#include <ctype.h>
#include <fcntl.h>
#include <errno.h>
+#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
soup_message_send (msg);
}
+static void
+quit (int sig)
+{
+ /* Exit cleanly on ^C in case we're valgrinding. */
+ exit (0);
+}
+
int
main (int argc, char **argv)
{
int port = SOUP_SERVER_ANY_PORT;
SoupServer *server;
+ g_type_init ();
+ signal (SIGINT, quit);
+
while ((opt = getopt (argc, argv, "p:s:")) != -1) {
switch (opt) {
case 'p':
loop = g_main_loop_new (NULL, TRUE);
g_main_loop_run (loop);
+ g_main_loop_unref (loop);
return 0;
}
GIOChannel *chan;
gsize wrote;
+ g_type_init ();
+
if (argc >=2 && !strcmp (argv[1], "-6")) {
addr = soup_address_ipv6_any ();
if (!addr) {
else
port = SOUP_SERVER_ANY_PORT;
listener = soup_socket_server_new (addr, port);
+ g_object_unref (addr);
if (!listener) {
fprintf (stderr, "Could not create listening socket\n");
exit (1);
printf ("got connection from %s port %d\n",
soup_address_get_name_sync (addr),
soup_socket_get_port (client));
+ g_object_unref (addr);
now = time (NULL);
timebuf = ctime (&now);
g_io_channel_write (chan, timebuf, strlen (timebuf), &wrote);
g_io_channel_unref (chan);
- soup_socket_unref (client);
+ g_object_unref (client);
}
+ g_object_unref (listener);
return 0;
}