remove hack to look at internals of GNET by using the new forked GNET :)
authorAlex Graveley <alex@ximian.com>
Thu, 22 Mar 2001 00:32:40 +0000 (00:32 +0000)
committeralex <alex>
Thu, 22 Mar 2001 00:32:40 +0000 (00:32 +0000)
2001-03-21  Alex Graveley  <alex@ximian.com>

* src/soup-core/soup-socks.c: remove hack to look at internals of
GNET by using the new forked GNET :)

* tests/stress-test.c: use soup_message_queue ().

* tests/simple-test.c: use soup_message_queue ().

* src/soup-core/soup-private.h: Added SoupAddress and SoupSocket.

* src/soup-core/soup-misc.c (soup_shutdown): Added, just calls
soup_queue_shutdown.

* src/soup-core/soup-queue.h: Removed. Added to soup-message.h.

* src/soup-core/soup-queue.c (soup_queue_message): rename to
(soup_message_queue): this.

* src/soup-core/soup-message.h: move SoupErrorCode,
SoupCallbackFn, and soup_message_queue() here.

* src/soup-core/soup-message.c (soup_message_free): Free
msg->response if buffer is system owned.
(soup_message_issue_callback): set msg->priv->errorcode so
syncronous soup_message_send can check for completion.
(soup_message_send): Added: Synchronous message send. Queues the
message as per usual, then call g_main_iteration() until them
essage returns.

* src/soup-core/soup-context.c: API Document. Switch gnet calls to
their soup-socket replacement.
(soup_context_get_connection): Remove environment check for
syncronous connect method.

* src/soup-core/Makefile.am (INCLUDES): replace GNET_CFLAGS with
GLIB_CFLAGS.
(libsoup_la_LIBADD): replace GNET_LIBS with GLIB_LIBS.
(soupinclude_HEADERS): Remove soup-queue.h. Add soup-socket.h.
(libsoup_la_SOURCES): Add soup-socket.c.

* soup.spec.in (Requires): remove GNET. Add libxml.

* soup.pc.in (Libs): remove GNET.
(Cflags): ditto.

* soup-config.in (depend_libs): remove GNET.
(depend_cflags): ditto.

* configure.in: remove gnet references, look for libnsl and
libresolv, add checking to determine gethostbyname_r possibility.

* acconfig.h: Add undefs for all the gethostbyname_r variants.

* src/soup-core/soup-socket.[ch]: Fork of GNET, minus synchronous
bits. Removes dependency on GNET; we now only rely on Glib and
libXml.

20 files changed:
ChangeLog
configure.in
libsoup/Makefile.am
libsoup/soup-context.c
libsoup/soup-context.h
libsoup/soup-message.c
libsoup/soup-message.h
libsoup/soup-misc.c
libsoup/soup-misc.h
libsoup/soup-private.h
libsoup/soup-queue.c
libsoup/soup-queue.h [deleted file]
libsoup/soup-server.c
libsoup/soup-server.h
libsoup/soup-socket.c [new file with mode: 0644]
libsoup/soup-socket.h [new file with mode: 0644]
libsoup/soup-socks.c
libsoup/soup-socks.h
libsoup/soup.h
soup-2.0.pc.in

index 76bf687..1d0bfb6 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,61 @@
+2001-03-21  Alex Graveley  <alex@ximian.com>
+
+       * src/soup-core/soup-socks.c: remove hack to look at internals of
+       GNET by using the new forked GNET :)
+
+       * tests/stress-test.c: use soup_message_queue ().
+
+       * tests/simple-test.c: use soup_message_queue ().
+
+       * src/soup-core/soup-private.h: Added SoupAddress and SoupSocket.
+
+       * src/soup-core/soup-misc.c (soup_shutdown): Added, just calls
+       soup_queue_shutdown.
+
+       * src/soup-core/soup-queue.h: Removed. Added to soup-message.h.
+
+       * src/soup-core/soup-queue.c (soup_queue_message): rename to
+       (soup_message_queue): this.
+
+       * src/soup-core/soup-message.h: move SoupErrorCode,
+       SoupCallbackFn, and soup_message_queue() here.
+
+       * src/soup-core/soup-message.c (soup_message_free): Free
+       msg->response if buffer is system owned.
+       (soup_message_issue_callback): set msg->priv->errorcode so
+       syncronous soup_message_send can check for completion.
+       (soup_message_send): Added: Synchronous message send. Queues the
+       message as per usual, then call g_main_iteration() until them
+       essage returns.
+
+       * src/soup-core/soup-context.c: API Document. Switch gnet calls to
+       their soup-socket replacement.
+       (soup_context_get_connection): Remove environment check for
+       syncronous connect method. 
+
+       * src/soup-core/Makefile.am (INCLUDES): replace GNET_CFLAGS with
+       GLIB_CFLAGS.
+       (libsoup_la_LIBADD): replace GNET_LIBS with GLIB_LIBS.
+       (soupinclude_HEADERS): Remove soup-queue.h. Add soup-socket.h.
+       (libsoup_la_SOURCES): Add soup-socket.c.
+
+       * soup.spec.in (Requires): remove GNET. Add libxml.
+
+       * soup.pc.in (Libs): remove GNET.
+       (Cflags): ditto.
+
+       * soup-config.in (depend_libs): remove GNET.
+       (depend_cflags): ditto.
+
+       * configure.in: remove gnet references, look for libnsl and
+       libresolv, add checking to determine gethostbyname_r possibility.
+
+       * acconfig.h: Add undefs for all the gethostbyname_r variants.
+
+       * src/soup-core/soup-socket.[ch]: Fork of GNET, minus synchronous
+       bits. Removes dependency on GNET; we now only rely on Glib and
+       libXml.
+
 2001-03-20  Dick Porter  <dick@ximian.com>
 
        * src/soup-wsdl/wsdl-types-glib.c: Parse a simple glib schema.
index 1c70305..0c3db69 100644 (file)
@@ -72,17 +72,6 @@ AC_SUBST(GLIB_CFLAGS)
 AC_SUBST(GLIB_LIBS)
 
 
-# Need GNET
-AM_PATH_GNET(1.0.4,,
-             AC_MSG_ERROR([Cannot find GNET: Is gnet-config in path?]))
-
-GNET_CFLAGS=`gnet-config --cflags gnet`
-GNET_LIBS=`gnet-config --libs gnet`
-
-AC_SUBST(GNET_CFLAGS)
-AC_SUBST(GNET_LIBS)
-
-
 # Need gnome-xml 1
 AC_PATH_PROG(XML_CONFIG,xml-config,no)
 if test x$XML_CONFIG = xno; then
@@ -115,25 +104,113 @@ LIBS=$save_LIBS
 
 # For proper var substitution in soupConf.sh and soup-apacheConf.sh
 SOUP_LIBDIR='-L${libdir}'
-SOUP_INCLUDEDIR=" -I${includedir} $GNET_CFLAGS $XML_CFLAGS"
-SOUP_LIBS="-lsoup $GNET_LIBS $XML_LIBS"
+SOUP_INCLUDEDIR=" -I${includedir} $XML_CFLAGS"
+SOUP_LIBS="-lsoup $XML_LIBS"
 
 AC_SUBST(SOUP_LIBDIR)
 AC_SUBST(SOUP_INCLUDEDIR)
 AC_SUBST(SOUP_LIBS)
 
 SOUP_APACHE_LIBDIR='-L${libdir}'
-SOUP_APACHE_INCLUDEDIR=" -I${includedir} $APACHE_CFLAGS $GNET_CFLAGS $XML_CFLAGS"
-SOUP_APACHE_LIBS="-lsoup -lsoup-apache $APACHE_LIBS $GNET_LIBS $XML_LIBS"
+SOUP_APACHE_INCLUDEDIR=" -I${includedir} $APACHE_CFLAGS $XML_CFLAGS"
+SOUP_APACHE_LIBS="-lsoup -lsoup-apache $APACHE_LIBS $XML_LIBS"
 
 AC_SUBST(SOUP_APACHE_LIBDIR)
 AC_SUBST(SOUP_APACHE_INCLUDEDIR)
 AC_SUBST(SOUP_APACHE_LIBS)
 
-# Need in.h and tcp.h for setting of TCP_NODELAY
+
+
+# Networking needs
 AC_CHECK_HEADERS(netinet/in.h netinet/tcp.h)
+AC_CHECK_HEADERS(sys/sockio.h sys/poll.h sys/param.h)
+
+AC_CHECK_LIB(nsl, main)
+AC_CHECK_LIB(resolv, main)
+
+# Check if we have gethostbyname_r (if so, assume gethostbyaddr_r).
+AC_CHECK_FUNC(gethostbyname_r,
+  [
+  dnl  First check for the glibc variant of gethostbyname_r
+
+  AC_MSG_CHECKING(for glibc gethostbyname_r)
+  AC_TRY_LINK([        #include <netdb.h>],[
+         struct hostent result_buf;
+         char buf[1024];
+         struct hostent* result;
+         int h_errnop;
+
+         gethostbyname_r("localhost", &result_buf, buf, sizeof(buf),
+                         &result, &h_errnop);
+       ], [
+
+         dnl Have glibc gethostbyname_r
+
+         AC_MSG_RESULT(yes)
+         AC_DEFINE(HAVE_GETHOSTBYNAME_R_GLIBC)
+         HAVE_GETHOSTBYNAME_R=yes
+
+        ], [
+
+  dnl  If we don't have glibc gethostbyname_r, check
+  dnl  for Solaris/Irix gethostbyname_r
+
+  AC_MSG_RESULT(no)
+  AC_MSG_CHECKING(for Solaris/Irix gethostbyname_r)
+  AC_TRY_LINK([ #include <netdb.h>],[
+         struct hostent result;
+         char buf[1024];
+         int h_errnop;
+
+         gethostbyname_r("localhost", &result, buf, sizeof(buf), &h_errnop);
+
+       ], [
+
+         dnl Have Solaris/Irix gethostbyname_r
+
+         AC_MSG_RESULT(yes)
+         AC_DEFINE(HAVE_GETHOSTBYNAME_R_SOLARIS)
+         HAVE_GETHOSTBYNAME_R=yes
+
+       ], [
+  dnl  If don't have Solaris/Irix gethostbyname_r, check
+  dnl  for HP-UX gethostbyname_r
+
+  AC_MSG_RESULT(no)
+  AC_MSG_CHECKING(for HP-UX gethostbyname_r)
+  AC_TRY_LINK([ #include <netdb.h>],[
+         struct hostent result;
+         char buf[1024];
+          gethostbyname_r("localhost", &result, buf);
+        ], [
+        
+          dnl Have HP-UX gethostbyname_r
+
+          AC_MSG_RESULT(yes)
+         AC_DEFINE(HAVE_GETHOSTBYNAME_R_HPUX)
+         HAVE_GETHOSTBYNAME_R=yes
+
+       ]
+     )]
+  )]
+)])
+
+# If we don't have gethostbyname_r, try to use Glib mutexes
+if test -z "$HAVE_GETHOSTBYNAME_R"; then
+       AM_PATH_GLIB(1.2.0, 
+                    AC_DEFINE(HAVE_GETHOSTBYNAME_R_GLIB_MUTEX), [
+                    AC_MSG_WARN(You have neither Glib threads nor the function
+                               gethostbyname_r.  This means that calls to
+                               gethostbyname (called by the Soup address
+                               functions) will not be thread safe so could
+                               malfunction in programs that use threads.)
+                    ])
+fi
+
 
 
+# SSL Library Handling
+
 AC_ARG_ENABLE(ssl, 
              [  --enable-ssl            Turn on Secure Sockets Layer support [default=yes]],,
              enable_ssl=yes)
@@ -197,6 +274,8 @@ if test "x$enable_ssl" = xyes; then
 fi
 
 
+enable_apache="no"
+
 AC_PATH_PROG(APXS,apxs,no)
 if test x$APXS != xno; then
        APACHE_CFLAGS="-I`apxs -q INCLUDEDIR`"
index 1a8ae73..13b2ea1 100644 (file)
@@ -7,7 +7,7 @@ INCLUDES =                              \
        -DSYSCONFDIR=\"$(sysconfdir)\"  \
        -DBINDIR=\"$(bindir)\"          \
        $(SOUP_DEBUG_FLAGS)             \
-       $(GNET_CFLAGS)                  \
+       $(GLIB_CFLAGS)                  \
        $(XML_CFLAGS)                   \
        $(OPENSSL_CFLAGS)               \
        $(NSS_CFLAGS)                   \
@@ -20,9 +20,9 @@ soupinclude_HEADERS =         \
        soup-context.h          \
        soup-message.h          \
        soup-misc.h             \
-       soup-queue.h            \
        soup-serializer.h       \
        soup-server.h           \
+       soup-socket.h           \
        soup-uri.h
 
 lib_LTLIBRARIES = libsoup.la libsoup-apache.la
@@ -30,7 +30,7 @@ lib_LTLIBRARIES = libsoup.la libsoup-apache.la
 libsoup_la_LDFLAGS = -version-info $(SOUP_CURRENT):$(SOUP_REVISION):$(SOUP_AGE)
 
 libsoup_la_LIBADD =            \
-       $(GNET_LIBS)            \
+       $(GLIB_LIBS)            \
        $(XML_LIBS)
 
 libsoup_la_SOURCES =           \
@@ -44,6 +44,7 @@ libsoup_la_SOURCES =          \
        soup-queue.c            \
        soup-serializer.c       \
        soup-server.c           \
+       soup-socket.c           \
        soup-socks.h            \
        soup-socks.c            \
        soup-ssl.h              \
index 2c3349f..8361fcf 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
 /*
- * soup-queue.c: Asyncronous Callback-based SOAP Request Queue.
+ * soup-context.c: Asyncronous Callback-based SOAP Request Queue.
  *
  * Authors:
  *      Alex Graveley (alex@helixcode.com)
@@ -12,7 +12,6 @@
 #include <string.h>
 #include <stdlib.h>
 #include <glib.h>
-#include <gnet/gnet.h>
 
 #include <unistd.h>
 #include <fcntl.h>
@@ -29,6 +28,7 @@
 #include "soup-context.h"
 #include "soup-private.h"
 #include "soup-misc.h"
+#include "soup-socket.h"
 #include "soup-ssl.h"
 
 GHashTable *soup_servers;  /* KEY: hostname, VALUE: SoupServer */
@@ -59,6 +59,16 @@ soup_context_new (SoupServer *server, SoupUri *uri)
        return ctx;
 }
 
+/**
+ * soup_context_get:
+ * @uri: the stringified URI.
+ *
+ * Returns a pointer to the %SoupContext representing @uri. If a context
+ * already exists for the URI, it is returned with an added reference.
+ * Otherwise, a new context is created with a reference count of one.
+ *
+ * Return value: a %SoupContext representing @uri.  
+ */
 SoupContext *
 soup_context_get (gchar *uri) 
 {
@@ -98,6 +108,12 @@ soup_context_get (gchar *uri)
        return ret;
 }
 
+/**
+ * soup_context_ref:
+ * @ctx: a %SoupContext.
+ *
+ * Adds a reference to @ctx.
+ */
 void
 soup_context_ref (SoupContext *ctx)
 {
@@ -106,6 +122,14 @@ soup_context_ref (SoupContext *ctx)
        ctx->refcnt++;
 }
 
+/**
+ * soup_context_unref:
+ * @ctx: a %SoupContext.
+ *
+ * Decrement the reference count on @ctx. If the reference count reaches
+ * zero, the %SoupContext is freed. If this is the last context for a
+ * given server address, any open connections are closed.
+ */
 void
 soup_context_unref (SoupContext *ctx)
 {
@@ -123,7 +147,7 @@ soup_context_unref (SoupContext *ctx)
                        
                        while (conns) {
                                SoupConnection *conn = conns->data;
-                               gnet_tcp_socket_unref (conn->socket);
+                               soup_socket_unref (conn->socket);
                                g_free (conn);
                                connection_count--;
 
@@ -147,14 +171,14 @@ struct SoupConnectData {
        gpointer               user_data;
 
        guint                  timeout_tag;
-       gpointer               gnet_connect_tag;
+       gpointer               connect_tag;
 };
 
 static void 
-soup_context_connect_cb (GTcpSocket                   *socket, 
-                        GInetAddr                    *addr,
-                        GTcpSocketConnectAsyncStatus  status,
-                        gpointer                      user_data)
+soup_context_connect_cb (SoupSocket              *socket, 
+                        SoupAddress             *addr,
+                        SoupSocketConnectStatus  status,
+                        gpointer                 user_data)
 {
        struct SoupConnectData *data = user_data;
        SoupContext            *ctx = data->ctx;
@@ -164,10 +188,10 @@ soup_context_connect_cb (GTcpSocket                   *socket,
 
        g_free (data);
 
-       if (addr) gnet_inetaddr_unref(addr);
+       if (addr) soup_address_unref(addr);
 
        switch (status) {
-       case GTCP_SOCKET_CONNECT_ASYNC_STATUS_OK:
+       case SOUP_SOCKET_CONNECT_ERROR_NONE:
                new_conn = g_new0 (SoupConnection, 1);
                new_conn->server = ctx->server;
                new_conn->context = ctx;
@@ -185,10 +209,10 @@ soup_context_connect_cb (GTcpSocket                   *socket,
 
                (*cb) (ctx, SOUP_CONNECT_ERROR_NONE, new_conn, cb_data); 
                break;
-       case GTCP_SOCKET_CONNECT_ASYNC_STATUS_INETADDR_ERROR:
+       case SOUP_SOCKET_CONNECT_ERROR_ADDR_RESOLVE:
                (*cb) (ctx, SOUP_CONNECT_ERROR_ADDR_RESOLVE, NULL, cb_data); 
                break;
-       case GTCP_SOCKET_CONNECT_ASYNC_STATUS_TCP_ERROR:
+       case SOUP_SOCKET_CONNECT_ERROR_NETWORK:
                (*cb) (ctx, SOUP_CONNECT_ERROR_NETWORK, NULL, cb_data); 
                break;
        }
@@ -250,7 +274,7 @@ soup_prune_least_used_connection (void)
        if (last.conn) {
                last.serv->connections = 
                        g_slist_remove (last.serv->connections, last.conn);
-               gnet_tcp_socket_unref (last.conn->socket);
+               soup_socket_unref (last.conn->socket);
                g_free (last.conn);
 
                connection_count--;
@@ -278,6 +302,27 @@ soup_prune_timeout (struct SoupConnectData *data)
        return FALSE;
 }
 
+/**
+ * soup_context_get_connection:
+ * @ctx: a %SoupContext.
+ * @cb: a %SoupConnectCallbackFn to be called when a valid connection is
+ * available.
+ * @user_data: the user_data passed to @cb.
+ *
+ * Initiates the process of establishing a network connection to the
+ * server referenced in @ctx. If an existing connection is available and
+ * not in use, @cb is called immediately, and a %SoupConnectId of 0 is
+ * returned. Otherwise, a new connection is established. If the current
+ * connection count exceeds that set in @soup_set_connection_limit, the
+ * new connection is not created until an existing connection is closed.
+ *
+ * Once a network connection is successfully established, or an existing
+ * connection becomes available for use, @cb is called, passing the
+ * %SoupConnection representing it.
+ *
+ * Return value: a %SoupConnectId which can be used to cancel a connection
+ * attempt using %soup_context_cancel_connect.
+ */
 SoupConnectId
 soup_context_get_connection (SoupContext           *ctx,
                             SoupConnectCallbackFn  cb,
@@ -302,44 +347,28 @@ soup_context_get_connection (SoupContext           *ctx,
 
        if (conn_limit && 
            connection_count >= conn_limit && 
-           !soup_prune_least_used_connection ()) {
+           !soup_prune_least_used_connection ())
                data->timeout_tag = 
                        g_timeout_add (500, 
                                       (GSourceFunc) soup_prune_timeout,
                                       data);
-       } else {
-               static gint sync_name_lookup = -1;
-
-               if (sync_name_lookup == -1) {
-                       if (getenv ("SOUP_NO_ASYNC_CONNECT")) {
-                               sync_name_lookup = TRUE;
-                               g_warning ("Using synchronous connect method");
-                       } else 
-                               sync_name_lookup = FALSE;
-               }
-               
-               if (sync_name_lookup == FALSE)
-                       data->gnet_connect_tag =
-                               gnet_tcp_socket_connect_async (
-                                       ctx->uri->host, 
-                                       ctx->uri->port,
-                                       soup_context_connect_cb,
-                                       data);
-               else {
-                       /* Syncronous Version -- Use for debugging */
-                       soup_context_connect_cb (
-                               gnet_tcp_socket_connect (ctx->uri->host, 
-                                                        ctx->uri->port),
-                               NULL, 
-                               GTCP_SOCKET_CONNECT_ASYNC_STATUS_OK,
-                               data);
-                       return NULL;
-               }
-       }
+       else data->connect_tag =
+                    soup_socket_connect (ctx->uri->host, 
+                                         ctx->uri->port,
+                                         soup_context_connect_cb,
+                                         data);
 
        return data;
 }
 
+/**
+ * soup_context_cancel_connect:
+ * @tag: a %SoupConnextId representing a connection in progress.
+ *
+ * Cancels the connection attempt represented by @tag. The
+ * %SoupConnectCallbackFn passed in %soup_context_get_connection is not
+ * called.
+ */
 void 
 soup_context_cancel_connect (SoupConnectId tag) 
 {
@@ -349,12 +378,20 @@ soup_context_cancel_connect (SoupConnectId tag)
 
        if (data->timeout_tag)
                g_source_remove (data->timeout_tag);
-       else if (data->gnet_connect_tag)
-               gnet_tcp_socket_connect_async_cancel (data->gnet_connect_tag);
+       else if (data->connect_tag)
+               soup_socket_connect_cancel (data->connect_tag);
 
        g_free (data);
 }
 
+/**
+ * soup_context_get_uri:
+ * @ctx: a %SoupContext.
+ * 
+ * Returns a pointer to the %SoupUri represented by @ctx.
+ *
+ * Return value: the %SoupUri for @ctx.
+ */
 SoupUri *
 soup_context_get_uri (SoupContext *ctx)
 {
@@ -362,6 +399,14 @@ soup_context_get_uri (SoupContext *ctx)
        return ctx->uri;
 }
 
+/**
+ * soup_context_get_protocol:
+ * @ctx: a %SoupContext.
+ * 
+ * Returns the %SoupProtocol used for connections created for %ctx.
+ *
+ * Return value: the %SoupProtocol used for connections to %ctx.
+ */
 SoupProtocol
 soup_context_get_protocol (SoupContext *ctx)
 {
@@ -369,6 +414,15 @@ soup_context_get_protocol (SoupContext *ctx)
        return ctx->protocol;
 }
 
+/**
+ * soup_connection_release:
+ * @conn: a %SoupConnection currently in use.
+ * 
+ * Mark the connection represented by @conn as being unused. If the
+ * keep-alive flag is not set on the connection, the connection is closed
+ * and its resources freed, otherwise the connection is returned to the
+ * unused connection pool for the server. 
+ */
 void
 soup_connection_release (SoupConnection *conn)
 {
@@ -380,7 +434,7 @@ soup_connection_release (SoupConnection *conn)
        } else {
                conn->server->connections = 
                        g_slist_remove (conn->server->connections, conn);
-               gnet_tcp_socket_unref (conn->socket);
+               soup_socket_unref (conn->socket);
                g_free (conn);
                connection_count--;
        }
@@ -399,13 +453,22 @@ soup_connection_setup_socket (GIOChannel *channel)
 #endif
 }
 
+/**
+ * soup_connection_get_iochannel:
+ * @conn: a %SoupConnection.
+ * 
+ * Returns a GIOChannel used for IO operations on the network connection
+ * represented by @conn.
+ *
+ * Return value: a pointer to the GIOChannel used for IO on %conn. 
+ */
 GIOChannel *
 soup_connection_get_iochannel (SoupConnection *conn)
 {
        g_return_val_if_fail (conn != NULL, NULL);
 
        if (!conn->channel) {
-               conn->channel = gnet_tcp_socket_get_iochannel (conn->socket);
+               conn->channel = soup_socket_get_iochannel (conn->socket);
 
                soup_connection_setup_socket (conn->channel);
 
@@ -417,6 +480,13 @@ soup_connection_get_iochannel (SoupConnection *conn)
        return conn->channel;
 }
 
+/**
+ * soup_connection_set_keepalive:
+ * @conn: a %SoupConnection.
+ * @keep_alive: boolean keep-alive value.
+ * 
+ * Sets the keep-alive flag on the %SoupConnection pointed to by %conn.
+ */
 void 
 soup_connection_set_keep_alive (SoupConnection *conn, gboolean keep_alive)
 {
@@ -424,6 +494,17 @@ soup_connection_set_keep_alive (SoupConnection *conn, gboolean keep_alive)
        conn->keep_alive = keep_alive;
 }
 
+/**
+ * soup_connection_set_keepalive:
+ * @conn: a %SoupConnection.
+ *
+ * Returns the keep-alive flag for the %SoupConnection pointed to by
+ * %conn. If this flag is TRUE, the connection will be returned to the pool
+ * of unused connections when next %soup_connection_release is called,
+ * otherwise the connection will be closed and resources freed.
+ *
+ * Return value: the keep-alive flag for @conn.
+ */
 gboolean 
 soup_connection_is_keep_alive (SoupConnection *conn)
 {
@@ -431,6 +512,14 @@ soup_connection_is_keep_alive (SoupConnection *conn)
        return conn->keep_alive;
 }
 
+/**
+ * soup_connection_get_context:
+ * @conn: a %SoupConnection.
+ * 
+ * Returns the %SoupContext from which @conn was created.
+ *
+ * Return value: the %SoupContext associated with @conn.
+ */
 SoupContext *
 soup_connection_get_context (SoupConnection *conn) 
 {
@@ -438,6 +527,16 @@ soup_connection_get_context (SoupConnection *conn)
        return conn->context;
 }
 
+/**
+ * soup_connection_is_new:
+ * @conn: a %SoupConnection.
+ * 
+ * Returns TRUE if this is the first use of @conn
+ * (I.E. %soup_connection_release has not yet been called on it).
+ *
+ * Return value: boolean representing whether this is the first time a
+ * connection has been used.
+ */
 gboolean 
 soup_connection_is_new (SoupConnection *conn)
 {
index 215fbdc..0c4412f 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
 /*
- * soup-queue.h: Asyncronous Callback-based SOAP Request Queue.
+ * soup-context.h: Asyncronous Callback-based SOAP Request Queue.
  *
  * Authors:
  *      Alex Graveley (alex@helixcode.com)
index 397fde9..4351d0d 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
 /*
- * soup-queue.c: Asyncronous Callback-based SOAP Request Queue.
+ * soup-message.c: Asyncronous Callback-based SOAP Request Queue.
  *
  * Authors:
  *      Alex Graveley (alex@helixcode.com)
@@ -9,7 +9,6 @@
  */
 
 #include "soup-message.h"
-#include "soup-queue.h"
 #include "soup-context.h"
 #include "soup-private.h"
 
@@ -83,6 +82,8 @@ soup_message_free (SoupMessage *req)
 
        if (req->request.owner == SOUP_BUFFER_SYSTEM_OWNED)
                g_free (req->request.body);
+       if (req->response.owner == SOUP_BUFFER_SYSTEM_OWNED)
+               g_free (req->response.body);
 
        if (req->priv->req_header) 
                g_string_free (req->priv->req_header, TRUE);
@@ -108,6 +109,8 @@ soup_message_issue_callback (SoupMessage *req, SoupErrorCode error)
           which causes the callback to be run again */
        soup_message_cleanup (req);
 
+       req->priv->errorcode = error;
+
        if (req->priv->callback)
                (*req->priv->callback) (req, 
                                        error, 
@@ -140,3 +143,18 @@ soup_message_add_header (SoupMessage *req,
 
        g_hash_table_insert (req->request_headers, name, value);
 }
+
+SoupErrorCode 
+soup_message_send (SoupMessage *msg)
+{
+       soup_message_queue (msg, NULL, NULL);
+
+       while (1) {
+               g_main_iteration (TRUE); 
+               if (msg->status == SOUP_STATUS_FINISHED ||
+                   msg->priv->errorcode != SOUP_ERROR_NONE)
+                       return msg->priv->errorcode;
+       }
+
+       return SOUP_ERROR_NONE;
+}
index c49aa9b..cbbf1f0 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
 /*
- * soup-queue.h: Asyncronous Callback-based SOAP Request Queue.
+ * soup-message.h: Asyncronous Callback-based SOAP Request Queue.
  *
  * Authors:
  *      Alex Graveley (alex@helixcode.com)
 #include "soup-context.h"
 
 typedef enum {
+       SOUP_ERROR_NONE = 0,
+       SOUP_ERROR_CANCELLED,
+       SOUP_ERROR_CANT_CONNECT,
+       SOUP_ERROR_IO,
+       SOUP_ERROR_MALFORMED_HEADER,
+       SOUP_ERROR_HANDLER
+} SoupErrorCode;
+
+typedef enum {
        SOUP_STATUS_IDLE = 0,
        SOUP_STATUS_QUEUED,
         SOUP_STATUS_CONNECTING,
@@ -57,6 +66,10 @@ struct _SoupMessage {
        GHashTable         *response_headers;
 };
 
+typedef void (*SoupCallbackFn) (SoupMessage   *req,
+                               SoupErrorCode  err,
+                               gpointer       user_data);
+
 SoupMessage       *soup_message_new        (SoupContext       *context,
                                            SoupAction         action);
 
@@ -66,11 +79,23 @@ SoupMessage       *soup_message_new_full   (SoupContext       *context,
                                            gchar             *req_body,
                                            gulong             req_length);
 
-void               soup_message_free       (SoupMessage       *req);
+void               soup_message_free       (SoupMessage       *msg);
 
-void               soup_message_cancel     (SoupMessage       *req);
+void               soup_message_cancel     (SoupMessage       *msg);
 
-void               soup_message_add_header (SoupMessage       *req,
+void               soup_message_add_header (SoupMessage       *msg,
                                            gchar             *name,
                                            gchar             *value);
+
+SoupErrorCode      soup_message_send       (SoupMessage       *msg);
+
+void               soup_message_queue      (SoupMessage       *req, 
+                                           SoupCallbackFn     callback, 
+                                           gpointer           user_data);
+
+/* 
+ * soup_queue_message() is deprecated. Replace with soup_message_queue.
+ */
+#define soup_queue_message soup_message_queue
+
 #endif /*SOUP_MESSAGE_H*/
index cf1f629..4be30aa 100644 (file)
@@ -354,3 +354,9 @@ soup_load_config (gchar *config_file)
 
        soup_initialized = TRUE;
 }
+
+void 
+soup_shutdown ()
+{
+       soup_queue_shutdown ();
+}
index a2b3ac4..e584d24 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
 /*
- * soup-queue.h: Asyncronous Callback-based SOAP Request Queue.
+ * soup-misc.h: Asyncronous Callback-based SOAP Request Queue.
  *
  * Authors:
  *      Alex Graveley (alex@helixcode.com)
@@ -19,6 +19,8 @@
 
 void               soup_load_config          (gchar       *config_file);
 
+void               soup_shutdown             (void);
+
 void               soup_set_proxy            (SoupContext *ctx);
 
 SoupContext       *soup_get_proxy            (void);
index a034eda..3b73f4c 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
 /*
- * soup-queue.h: Asyncronous Callback-based SOAP Request Queue.
+ * soup-private.h: Asyncronous Callback-based SOAP Request Queue.
  *
  * Authors:
  *      Alex Graveley (alex@helixcode.com)
 #ifndef SOAP_PRIVATE_H
 #define SOAP_PRIVATE_H 1
 
-#include <gnet/gnet.h>
+#include <netinet/in.h>
 
 #include "soup-context.h"
-#include "soup-queue.h"
 #include "soup-server.h"
+#include "soup-socket.h"
 #include "soup-uri.h"
 
 #ifdef __cplusplus
@@ -39,6 +39,19 @@ typedef struct {
        GHashTable *contexts;           /* KEY: uri->path, VALUE: SoupContext */
 } SoupServer;
 
+struct _SoupAddress {
+       gchar*          name;
+       struct sockaddr sa;
+       guint           ref_count;
+};
+
+struct _SoupSocket {
+       gint            sockfd;
+       struct sockaddr sa; /* Why not an InetAddr? */
+       guint           ref_count;
+       GIOChannel     *iochannel;
+};
+
 struct _SoupContext {
        SoupProtocol  protocol;
        SoupUri      *uri;
@@ -50,7 +63,7 @@ struct _SoupConnection {
        SoupServer   *server;
        SoupContext  *context;
        GIOChannel   *channel;
-       GTcpSocket   *socket;
+       SoupSocket   *socket;
        guint         port;
        gboolean      in_use;
        guint         last_used_id;
@@ -79,6 +92,8 @@ struct _SoupMessagePrivate {
 
        SoupCallbackFn  callback;
        gpointer        user_data;
+       
+       SoupErrorCode   errorcode;
 };
 
 typedef struct {
@@ -111,6 +126,10 @@ gint      soup_substring_index        (gchar         *str,
 gchar    *soup_base64_encode          (const gchar   *text,
                                       gint           len);
 
+/* from soup-queue.c */
+
+void      soup_queue_shutdown         ();
+
 /* from soup-server.c */
 
 SoupServerHandler *soup_server_get_handler (const gchar *methodname);
index 4902aec..81de67b 100644 (file)
@@ -16,7 +16,7 @@
 #include <signal.h>
 #include <errno.h>
 
-#include "soup-queue.h"
+#include "soup-message.h"
 #include "soup-context.h"
 #include "soup-headers.h"
 #include "soup-misc.h"
@@ -27,6 +27,18 @@ GSList *soup_active_requests = NULL;
 
 static guint soup_queue_idle_tag = 0;
 
+void 
+soup_queue_shutdown ()
+{
+        GSList *iter;
+
+       g_source_remove (soup_queue_idle_tag);
+       soup_queue_idle_tag = 0;
+
+       for (iter = soup_active_requests; iter; iter = iter->next)
+               soup_message_cancel (iter->data);
+}
+
 static gboolean
 soup_parse_headers (SoupMessage *req)
 {
@@ -254,7 +266,7 @@ soup_queue_error_async (GIOChannel* iochannel,
                    req->priv->req_header->len >= req->priv->write_len) {
                        g_warning ("Requeueing request which failed in "
                                   "the sending headers phase");
-                       soup_queue_message (req, 
+                       soup_message_queue (req, 
                                            req->priv->callback, 
                                            req->priv->user_data);
                        break;
@@ -569,7 +581,7 @@ soup_idle_handle_new_requests (gpointer unused)
 }
 
 void 
-soup_queue_message (SoupMessage    *req,
+soup_message_queue (SoupMessage    *req,
                    SoupCallbackFn  callback, 
                    gpointer        user_data)
 {
@@ -612,15 +624,3 @@ soup_queue_message (SoupMessage    *req,
 
        soup_active_requests = g_slist_prepend (soup_active_requests, req);
 }
-
-void 
-soup_queue_shutdown ()
-{
-        GSList *iter;
-
-       g_source_remove (soup_queue_idle_tag);
-       soup_queue_idle_tag = 0;
-
-       for (iter = soup_active_requests; iter; iter = iter->next)
-               soup_message_cancel (iter->data);
-}
diff --git a/libsoup/soup-queue.h b/libsoup/soup-queue.h
deleted file mode 100644 (file)
index fdb2e35..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
-/*
- * soup-queue.h: Asyncronous Callback-based SOAP Request Queue.
- *
- * Authors:
- *      Alex Graveley (alex@helixcode.com)
- *
- * Copyright (C) 2000, Helix Code, Inc.
- */
-
-#ifndef SOUP_QUEUE_H
-#define SOUP_QUEUE_H 1
-
-#include <glib.h>
-
-#include "soup-message.h"
-#include "soup-context.h"
-
-typedef enum {
-       SOUP_ERROR_NONE = 0,
-       SOUP_ERROR_CANCELLED,
-       SOUP_ERROR_CANT_CONNECT,
-       SOUP_ERROR_IO,
-       SOUP_ERROR_MALFORMED_HEADER,
-       SOUP_ERROR_HANDLER
-} SoupErrorCode;
-
-typedef void (*SoupCallbackFn) (SoupMessage   *req,
-                               SoupErrorCode  err,
-                               gpointer       user_data);
-
-void         soup_queue_message  (SoupMessage       *req, 
-                                 SoupCallbackFn     callback, 
-                                 gpointer           user_data);
-
-void         soup_queue_shutdown (void);
-
-#endif /* SOUP_QUEUE_H */
index 32d0494..c0ab949 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
 /*
- * soup-queue.c: Asyncronous Callback-based SOAP Request Queue.
+ * soup-server.c: Asyncronous Callback-based SOAP Request Queue.
  *
  * Authors:
  *      Alex Graveley (alex@ximian.com)
index b90d750..1e952c9 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
 /*
- * soup-queue.h: Asyncronous Callback-based SOAP Request Queue.
+ * soup-server.h: Asyncronous Callback-based SOAP Request Queue.
  *
  * Authors:
  *      Alex Graveley (alex@helixcode.com)
diff --git a/libsoup/soup-socket.c b/libsoup/soup-socket.c
new file mode 100644 (file)
index 0000000..afd40ce
--- /dev/null
@@ -0,0 +1,2159 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * soup-socket.c: Asyncronous Callback-based SOAP Request Queue.
+ *
+ * Authors:
+ *      David Helder  (dhelder@umich.edu)
+ *      Alex Graveley (alex@helixcode.com)
+ * 
+ * Original code compliments of David Helder's GNET Networking Library.
+ *
+ * Copyright (C) 2000, Helix Code, Inc.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <sys/types.h>
+#include <errno.h>
+#include <signal.h>
+#include <fcntl.h>
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+#include <glib.h>
+
+#include "soup-private.h"
+#include "soup-socket.h"
+
+#ifndef SOUP_WIN32  /*********** Unix specific ***********/
+
+#include <unistd.h>
+#include <sys/ioctl.h>
+#ifdef HAVE_SYS_POLL_H
+#include <sys/poll.h>
+#endif
+#include <sys/socket.h>
+#ifdef HAVE_SYS_SOCKIO_H
+#include <sys/sockio.h>
+#endif
+#include <sys/time.h>
+
+#include <sys/utsname.h>
+#include <sys/wait.h>
+
+#include <net/if.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <arpa/nameser.h>
+#include <resolv.h>
+#include <netdb.h>
+
+#ifndef socklen_t
+#define socklen_t size_t
+#endif
+
+#define SOUP_CLOSE_SOCKET(SOCKFD) close(SOCKFD)
+#define SOUP_SOCKET_IOCHANNEL_NEW(SOCKFD) g_io_channel_unix_new(SOCKFD)
+
+#else  /*********** Windows specific ***********/
+
+#include <windows.h>
+#include <winbase.h>
+#include <winuser.h>
+#include <ws2tcpip.h>
+
+#define socklen_t gint32
+
+#define SOUP_CLOSE_SOCKET(SOCKFD) closesocket(SOCKFD)
+#define SOUP_SOCKET_IOCHANNEL_NEW(SOCKFD) g_io_channel_win32_new_stream_socket(SOCKFD)
+
+WNDCLASSEX soupWndClass;
+HWND  soup_hWnd; 
+guint soup_io_watch_ID;
+GIOChannel *soup_iochannel;
+       
+GHashTable *soup_hash;
+GHashTable *soup_select_hash; /* soup_socket_new needs its own hash */
+HANDLE soup_Mutex; 
+HANDLE soup_select_Mutex;
+HANDLE soup_hostent_Mutex;
+       
+#define IA_NEW_MSG 100         /* soup_address_new */
+#define GET_NAME_MSG 101       /* soup_address_get_name */
+#define TCP_SOCK_MSG 102       /* soup_socket_new  */
+
+/* Windows does not have inet_aton, but it does have inet_addr.  TODO:
+   We should write a better inet_aton because inet_addr doesn't catch
+   255.255.255.255 properly. */
+
+static int
+inet_aton(const char *cp, struct in_addr *inp)
+{
+  inp->s_addr = inet_addr(cp);
+  if (inp->s_addr == INADDR_NONE)
+    return 0;
+  return 1;
+}
+
+#endif /*********** End Windows specific ***********/
+
+#ifndef INET_ADDRSTRLEN
+#define INET_ADDRSTRLEN 16
+#define INET6_ADDRSTRLEN 46
+#endif
+
+#define SOUP_SOCKADDR_IN(s) (*((struct sockaddr_in*) &s))
+#define SOUP_ANY_IO_CONDITION  (G_IO_IN | G_IO_OUT | G_IO_PRI | \
+                                G_IO_ERR | G_IO_HUP | G_IO_NVAL)
+
+typedef struct {
+       SoupAddress* ia;
+       SoupAddressNewFn func;
+       gpointer data;
+#ifndef SOUP_WIN32
+       pid_t pid;
+       int fd;
+       guint watch;
+       guchar buffer[16];
+       int len;
+#else
+       int WSAhandle;
+       char hostentBuffer[MAXGETHOSTSTRUCT];
+       int errorcode;
+#endif
+} SoupAddressState;
+
+
+typedef struct {
+       SoupAddress* ia;
+       SoupAddressGetNameFn func;
+       gpointer data;
+#ifndef SOUP_WIN32
+       pid_t pid;
+       int fd;
+       guint watch;
+       guchar buffer[256 + 1];
+       int len;
+#else
+       int WSAhandle;
+       char hostentBuffer[MAXGETHOSTSTRUCT];
+       int errorcode;
+#endif
+} SoupAddressReverseState;
+
+
+typedef struct {
+       SoupSocket*            socket;
+       SoupSocketNewFn func;
+       gpointer               data;
+       gint                   flags;
+       guint                  connect_watch;
+#ifdef SOUP_WIN32
+       gint                   errorcode;
+#endif
+} SoupSocketState;
+
+
+typedef struct {
+       SoupAddress*                 ia;
+       SoupSocketConnectFn func;
+       gpointer                   data;
+
+       gpointer                   inetaddr_id;
+       gpointer                   tcp_id;
+} SoupSocketConnectState;
+
+
+/* Testing Defines */
+/*  #undef   HAVE_GETHOSTBYNAME_R_GLIBC */
+/*  #define  HAVE_GETHOSTBYNAME_R_GLIB_MUTEX */
+
+#ifdef HAVE_GETHOSTBYNAME_R_GLIB_MUTEX
+G_LOCK_DEFINE (gethostbyname);
+#endif
+
+/**
+ * soup_gethostbyname:
+ *
+ * Thread safe gethostbyname.  The only valid fields are sin_len,
+ * sin_family, and sin_addr.
+ */
+static gboolean
+soup_gethostbyname(const char*         hostname, 
+                  struct sockaddr_in* sa, 
+                  gchar**             nicename)
+{
+       gboolean rv = FALSE;
+
+#ifdef HAVE_GETHOSTBYNAME_R_GLIBC
+       {
+               struct hostent result_buf, *result;
+               size_t len;
+               char* buf;
+               int herr;
+               int res;
+
+               len = 1024;
+               buf = g_new (gchar, len);
+
+               while ((res = gethostbyname_r (hostname, 
+                                              &result_buf, 
+                                              buf, 
+                                              len, 
+                                              &result, 
+                                              &herr)) == ERANGE) {
+                       len *= 2;
+                       buf = g_renew (gchar, buf, len);
+               }
+
+               if (res || result == NULL || result->h_addr_list[0] == NULL)
+                       goto done;
+
+               if (sa) {
+                       sa->sin_family = result->h_addrtype;
+                       memcpy (&sa->sin_addr, 
+                               result->h_addr_list[0], 
+                               result->h_length);
+               }
+
+               if (nicename && result->h_name)
+                       *nicename = g_strdup (result->h_name);
+
+               rv = TRUE;
+
+       done:
+               g_free(buf);
+       }
+#else
+#ifdef HAVE_GET_HOSTBYNAME_R_SOLARIS
+       {
+               struct hostent result;
+               size_t len;
+               char* buf;
+               int herr;
+               int res;
+
+               len = 1024;
+               buf = g_new (gchar, len);
+
+               while ((res = gethostbyname_r (hostname, 
+                                              &result, 
+                                              buf, 
+                                              len, 
+                                              &herr)) == ERANGE) {
+                       len *= 2;
+                       buf = g_renew (gchar, buf, len);
+               }
+
+               if (res || hp == NULL || hp->h_addr_list[0] == NULL)
+                       goto done;
+
+               if (sa) {
+                       sa->sin_family = result->h_addrtype;
+                       memcpy (&sa->sin_addr, 
+                               result->h_addr_list[0], 
+                               result->h_length);
+               }
+
+               if (nicename && result->h_name)
+                       *nicename = g_strdup (result->h_name);
+
+               rv = TRUE;
+
+       done:
+               g_free(buf);
+       }
+#else
+#ifdef HAVE_GETHOSTBYNAME_R_HPUX
+       {
+               struct hostent result;
+               struct hostent_data buf;
+               int res;
+
+               res = gethostbyname_r (hostname, &result, &buf);
+
+               if (res == 0) {
+                       if (sa) {
+                               sa->sin_family = result.h_addrtype;
+                               memcpy (&sa->sin_addr, 
+                                       result.h_addr_list[0], 
+                                       result.h_length);
+                       }
+
+                       if (nicename && result.h_name)
+                               *nicename = g_strdup(result.h_name);
+
+                       rv = TRUE;
+               }
+       }
+#else 
+#ifdef HAVE_GETHOSTBYNAME_R_GLIB_MUTEX
+       {
+               struct hostent* he;
+
+               G_LOCK (gethostbyname);
+               he = gethostbyname (hostname);
+               G_UNLOCK (gethostbyname);
+
+               if (he != NULL && he->h_addr_list[0] != NULL) {
+                       if (sa) {
+                               sa->sin_family = he->h_addrtype;
+                               memcpy (&sa->sin_addr, 
+                                       he->h_addr_list[0], 
+                                       he->h_length);
+                       }
+
+                       if (nicename && he->h_name)
+                               *nicename = g_strdup (he->h_name);
+
+                       rv = TRUE;
+               }
+       }
+#else
+#ifdef SOUP_WIN32
+       {
+               struct hostent *result;
+
+               WaitForSingleObject (soup_hostent_Mutex, INFINITE);
+               result = gethostbyname (hostname);
+
+               if (result != NULL) {
+                       if (sa) {
+                               sa->sin_family = result->h_addrtype;
+                               memcpy (&sa->sin_addr, 
+                                       result->h_addr_list[0], 
+                                       result->h_length);
+                       }
+       
+                       if (nicename && result->h_name)
+                               *nicename = g_strdup(result->h_name);
+
+                       ReleaseMutex(soup_hostent_Mutex);
+                       rv = TRUE;
+               }
+       }
+#else
+       {
+               struct hostent* he;
+
+               he = gethostbyname (hostname);
+               if (he != NULL && he->h_addr_list[0] != NULL) {
+                       if (sa) {
+                               sa->sin_family = he->h_addrtype;
+                               memcpy (&sa->sin_addr, 
+                                       he->h_addr_list[0], 
+                                       he->h_length);
+                       }
+
+                       if (nicename && he->h_name)
+                               *nicename = g_strdup (he->h_name);
+
+                       rv = TRUE;
+               }
+       }
+#endif
+#endif
+#endif
+#endif
+#endif
+
+       return rv;
+}
+
+/* 
+   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 gchar *
+soup_gethostbyaddr (const char* addr, size_t length, int type)
+{
+       gchar* rv = NULL;
+
+#ifdef HAVE_GETHOSTBYNAME_R_GLIBC
+       {
+               struct hostent result_buf, *result;
+               size_t len;
+               char* buf;
+               int herr;
+               int res;
+
+               len = 1024;
+               buf = g_new (gchar, len);
+
+               while ((res = gethostbyaddr_r (addr, 
+                                              length, 
+                                              type, 
+                                              &result_buf, 
+                                              buf, 
+                                              len, 
+                                              &result, 
+                                              &herr)) == ERANGE) {
+                       len *= 2;
+                       buf = g_renew (gchar, buf, len);
+               }
+
+               if (res || result == NULL || result->h_name == NULL)
+                       goto done;
+
+               rv = g_strdup(result->h_name);
+
+       done:
+               g_free(buf);
+       }
+#else
+#ifdef HAVE_GET_HOSTBYNAME_R_SOLARIS
+       {
+               struct hostent result;
+               size_t len;
+               char* buf;
+               int herr;
+               int res;
+               
+               len = 1024;
+               buf = g_new (gchar, len);
+
+               while ((res = gethostbyaddr_r (addr, 
+                                              length, 
+                                              type, 
+                                              &result, 
+                                              buf, 
+                                              len, 
+                                              &herr)) == ERANGE) {
+                       len *= 2;
+                       buf = g_renew (gchar, buf, len);
+               }
+
+               if (res || hp == NULL || hp->h_name == NULL)
+                       goto done;
+
+               rv = g_strdup(result->h_name);
+
+       done:
+               g_free(buf);
+       }
+#else
+#ifdef HAVE_GETHOSTBYNAME_R_HPUX
+       {
+               struct hostent result;
+               struct hostent_data buf;
+               int res;
+
+               res = gethostbyaddr_r (addr, length, type, &result, &buf);
+
+               if (res == 0) rv = g_strdup (result.h_name);
+       }
+#else 
+#ifdef HAVE_GETHOSTBYNAME_R_GLIB_MUTEX
+       {
+               struct hostent* he;
+
+               G_LOCK (gethostbyname);
+               he = gethostbyaddr (addr, length, type);
+               G_UNLOCK (gethostbyname);
+               if (he != NULL && he->h_name != NULL)
+                       rv = g_strdup (he->h_name);
+       }
+#else
+#ifdef SOUP_WIN32
+       {
+               struct hostent* he;
+
+               WaitForSingleObject (soup_hostent_Mutex, INFINITE);
+               he = gethostbyaddr (addr, length, type);
+               if (he != NULL && he->h_name != NULL)
+                       rv = g_strdup (he->h_name);
+               ReleaseMutex (soup_hostent_Mutex);
+       }
+#else
+       {
+               struct hostent* he;
+
+               he = gethostbyaddr (addr, length, type);
+               if (he != NULL && he->h_name != NULL)
+                       rv = g_strdup (he->h_name);
+       }
+#endif
+#endif
+#endif
+#endif
+#endif
+
+       return rv;
+}
+
+#ifndef SOUP_WIN32  /*********** Unix code ***********/
+
+static gboolean 
+soup_address_new_cb (GIOChannel* iochannel, 
+                    GIOCondition condition, 
+                    gpointer data)
+{
+       SoupAddressState* state = (SoupAddressState*) data;
+
+       /* 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;
+
+                       /* We're done reading.  Copy into the addr if we were
+                          successful. Otherwise, we got a 0 because there was
+                          an error */
+                       if (state->len > 1) {
+                               struct sockaddr_in* sa_in;
+
+                               sa_in = (struct sockaddr_in*) &state->ia->sa;
+                               memcpy (&sa_in->sin_addr, 
+                                       &state->buffer[1], 
+                                       (state->len - 1));
+                       } else goto error;
+
+                       /* 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->data);
+                       close (state->fd);
+                       waitpid (state->pid, NULL, 0);
+                       g_free(state);
+                       return FALSE;
+               }
+       }
+
+ error:
+       /* Remove the watch now in case we don't return immediately */
+       g_source_remove (state->watch);
+
+       (*state->func) (NULL, SOUP_ADDRESS_STATUS_ERROR, state->data);
+       soup_address_new_cancel (state);
+       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.
+ *  @port: port number (0 if the port doesn't matter)
+ *  @func: Callback function.
+ *  @data: User data passed when callback function is called.
+ * 
+ *  Create a SoupAddress from a name and port 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.
+ *
+ *  The Unix version 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, we recommend calling
+ *  g_main_iteration(FALSE) between calls.  This will help prevent an
+ *  explosion of processes.
+ *
+ *  If you need a more robust library for Unix, look at <ulink
+ *  url="http://www.gnu.org/software/adns/adns.html">GNU ADNS</ulink>.
+ *  GNU ADNS is under the GNU GPL.
+ *
+ *  The Windows version should work fine.  Windows has an asynchronous
+ *  DNS lookup function.
+ *
+ *  Returns: ID of the lookup which can be used with
+ *  soup_address_new_cancel() to cancel it; NULL on immediate
+ *  success or failure.
+ **/
+SoupAddressNewId
+soup_address_new (const gchar* name, 
+                 const gint port, 
+                 SoupAddressNewFn func, 
+                 gpointer data)
+{
+       pid_t pid = -1;
+       int pipes[2];
+       struct in_addr inaddr;
+
+       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 */
+       if (inet_aton (name, &inaddr) != 0) {
+               SoupAddress* ia = NULL;
+               struct sockaddr_in* sa_in;
+
+               ia = g_new0(SoupAddress, 1);
+               ia->ref_count = 1;
+
+               sa_in = (struct sockaddr_in*) &ia->sa;
+               sa_in->sin_family = AF_INET;
+               sa_in->sin_port = g_htons(port);
+               memcpy (&sa_in->sin_addr, 
+                       (char*) &inaddr, 
+                       sizeof(struct in_addr));
+
+               (*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 to do the look up. */
+ fork_again:
+       errno = 0;
+
+       if ((pid = fork()) == 0) {
+               struct sockaddr_in sa;
+
+               /* Try to get the host by name (ie, DNS) */
+               if (soup_gethostbyname (name, &sa, NULL)) {
+                       guchar size = 4;        /* FIX for IPv6 */
+
+                       if ((write (pipes[1], &size, sizeof(guchar)) == -1) ||
+                           (write (pipes[1], &sa.sin_addr, size) == -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);
+       } else if (pid > 0) {
+               /* Set up an IOChannel to read from the pipe */
+               SoupAddress* ia;
+               struct sockaddr_in* sa_in;
+               SoupAddressState* state;
+
+               /* Create a new SoupAddress */
+               ia = g_new0(SoupAddress, 1);
+               ia->name = g_strdup(name);
+               ia->ref_count = 1;
+
+               sa_in = (struct sockaddr_in*) &ia->sa;
+               sa_in->sin_family = AF_INET;
+               sa_in->sin_port = g_htons (port);
+
+               /* Create a structure for the call back */
+               state = g_new0 (SoupAddressState, 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_new_cb, 
+                               state);
+
+               return state;
+       } else if (errno == EAGAIN) {
+               /* Try again */
+               /* Yield the processor */
+               sleep(0);
+               goto fork_again;
+       } else {
+               /* Else there was a goofy error */
+               g_warning ("Fork error: %s (%d)\n", g_strerror (errno), errno);
+               (*func) (NULL, SOUP_ADDRESS_STATUS_ERROR, data);
+       }
+
+       return NULL;
+}
+
+/**
+ *  soup_address_new_cancel:
+ *  @id: ID of the lookup
+ *
+ *  Cancel an asynchronous SoupAddress creation that was started with
+ *  soup_address_new().
+ */
+void
+soup_address_new_cancel (SoupAddressNewId id)
+{
+       SoupAddressState* state = (SoupAddressState*) id;
+
+       g_return_if_fail(state != NULL);
+
+       soup_address_unref (state->ia);
+       g_source_remove (state->watch);
+
+       close (state->fd);
+       kill (state->pid, SIGKILL);
+       waitpid (state->pid, NULL, 0);
+
+       g_free(state);
+}
+
+#else  /*********** Windows code ***********/
+
+static gboolean
+soup_address_new_cb (GIOChannel* iochannel,
+                    GIOCondition condition,
+                    gpointer data)
+{
+       SoupAddressState* state = (SoupAddressState*) data;
+       struct hostent *result;
+       struct sockaddr_in *sa_in;
+
+       if (state->errorcode) {
+               (*state->func) (state->ia, 
+                               SOUP_ADDRESS_STATUS_ERROR, 
+                               state->data);
+               g_free (state);
+               return FALSE;
+       }
+
+       result = (struct hostent*) state->hostentBuffer;
+
+       sa_in = (struct sockaddr_in*) &state->ia->sa;
+       memcpy (&sa_in->sin_addr, result->h_addr_list[0], result->h_length);
+
+       state->ia->name = g_strdup (result->h_name);
+
+       (*state->func) (state->ia, SOUP_ADDRESS_STATUS_OK, state->data);
+       g_free (state);
+
+       return FALSE;
+}
+
+SoupAddressNewId
+soup_address_new (const gchar* name, 
+                 const gint port,
+                 SoupAddressNewFn func, 
+                 gpointer data)
+{
+       struct in_addr inaddr;
+       SoupAddress* ia;
+       struct sockaddr_in* sa_in;
+       SoupAddressState* state;
+
+       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.s_addr = inet_addr(name);
+       if (inaddr.s_addr != INADDR_NONE) {
+               SoupAddress* ia = NULL;
+               struct sockaddr_in* sa_in;
+
+               ia = g_new0(SoupAddress, 1);
+               ia->ref_count = 1;
+
+               sa_in = (struct sockaddr_in*) &ia->sa;
+               sa_in->sin_family = AF_INET;
+               sa_in->sin_port = g_htons (port);
+               memcpy (&sa_in->sin_addr, 
+                       (char*) &inaddr, 
+                       sizeof (struct in_addr));
+
+               (*func) (ia, SOUP_ADDRESS_STATUS_OK, data);
+               return NULL;
+       }
+       
+       /* Create a new SoupAddress */
+       ia = g_new0 (SoupAddress, 1);
+       ia->name = g_strdup (name);
+       ia->ref_count = 1;
+
+       sa_in = (struct sockaddr_in*) &ia->sa;
+       sa_in->sin_family = AF_INET;
+       sa_in->sin_port = g_htons (port);
+
+       /* Create a structure for the call back */
+       state = g_new0 (SoupAddressState, 1);
+       state->ia = ia;
+       state->func = func;
+       state->data = data;
+
+       state->WSAhandle = (int) 
+               WSAAsyncGetHostByName (soup_hWnd, 
+                                      IA_NEW_MSG, 
+                                      name, 
+                                      state->hostentBuffer, 
+                                      sizeof (state->hostentBuffer));
+
+       if (!state->WSAhandle) {
+               g_free (state);
+               (*func) (NULL, SOUP_ADDRESS_STATUS_ERROR, data);
+               return NULL;
+       }
+
+       /*get a lock and insert the state into the hash */
+       WaitForSingleObject (soup_Mutex, INFINITE);
+       g_hash_table_insert (soup_hash, 
+                            (gpointer) state->WSAhandle, 
+                            (gpointer) state);
+       ReleaseMutex (soup_Mutex);
+
+       return state;
+}
+
+void
+soup_address_new_cancel (SoupAddressNewId id)
+{
+       SoupAddressState* state = (SoupAddressState*) id;
+
+       g_return_if_fail(state != NULL);
+
+       soup_address_delete (state->ia);
+       WSACancelAsyncRequest ((HANDLE)state->WSAhandle);
+
+       /*get a lock and remove the hash entry */
+       WaitForSingleObject (soup_Mutex, INFINITE);
+       g_hash_table_remove (soup_hash, (gpointer) state->WSAhandle);
+       ReleaseMutex (soup_Mutex);
+       g_free (state);
+}
+
+#endif         /*********** End Windows code ***********/
+
+/**
+ *   soup_address_clone:
+ *   @ia: Address to clone
+ *
+ *   Create an internet address from another one.  
+ *
+ *   Returns: a new SoupAddress, or NULL if there was a failure.
+ **/
+SoupAddress* 
+soup_address_clone (const SoupAddress* ia)
+{
+       SoupAddress* cia;
+
+       g_return_val_if_fail (ia != NULL, NULL);
+
+       cia = g_new0(SoupAddress, 1);
+       cia->ref_count = 1;
+       cia->sa = ia->sa;
+       if (ia->name != NULL) cia->name = g_strdup (ia->name);
+
+       return cia;
+}
+
+/**
+ *  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_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)
+{
+       g_return_if_fail(ia != NULL);
+
+       --ia->ref_count;
+
+       if (ia->ref_count == 0) {
+               if (ia->name != NULL) g_free (ia->name);
+               g_free (ia);
+       }
+}
+
+#ifndef SOUP_WIN32  /*********** Unix code ***********/
+
+static gboolean 
+soup_address_get_name_cb (GIOChannel* iochannel, 
+                         GIOCondition condition, 
+                         gpointer data)
+{
+       SoupAddressReverseState* state;
+       gchar* name = NULL;
+
+       state = (SoupAddressReverseState*) 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 */
+                       name = g_new (gchar, state->buffer[0] + 1);
+                       strncpy (name, &state->buffer[1], state->buffer[0]);
+                       name[state->buffer[0]] = '\0';
+                       state->ia->name = g_strdup (name);
+
+                       /* 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, 
+                                       name, 
+                                       state->data);
+                       close (state->fd);
+                       waitpid (state->pid, NULL, 0);
+                       g_free (state);
+                       return FALSE;
+               }
+       }
+
+       /* 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_ERROR, 
+                       NULL, 
+                       state->data);
+       soup_address_get_name_cancel(state);
+       return FALSE;
+}
+
+/**
+ *  soup_address_get_name:
+ *  @ia: 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.
+ *
+ *  The Unix version forks and does the reverse lookup.  This has
+ *  problems.  See the notes for soup_address_new().  The
+ *  Windows version should work fine.
+ *
+ *  Returns: ID of the lookup which can be used with
+ *  soup_addressr_get_name_cancel() to cancel it; NULL on
+ *  immediate success or failure.
+ **/
+SoupAddressGetNameId
+soup_address_get_name (SoupAddress* ia, 
+                      SoupAddressGetNameFn func,
+                      gpointer data)
+{
+       g_return_val_if_fail(ia != NULL, NULL);
+       g_return_val_if_fail(func != NULL, NULL);
+
+       /* If we already know the name, just copy that */
+       /* Otherwise, fork and look it up */
+       if (ia->name != NULL)
+               (func) (ia, 
+                       SOUP_ADDRESS_STATUS_OK, 
+                       g_strdup (ia->name), 
+                       data);
+       else {
+               pid_t pid = -1;
+               int pipes[2];
+
+               /* Open a pipe */
+               if (pipe(pipes) == -1) {
+                       (func) (ia, SOUP_ADDRESS_STATUS_ERROR, NULL, data);
+                       return NULL;
+               }
+
+               /* Fork to do the look up. */
+       fork_again:
+               if ((pid = fork()) == 0) {
+                       gchar* name;
+                       guchar len;
+
+                       /* Write the name to the pipe.  If we didn't get a name,
+                          we just write the canonical name. */
+                       if ((name = soup_gethostbyaddr ((char*) &((struct sockaddr_in*)&ia->sa)->sin_addr, 
+                                       sizeof (struct in_addr), AF_INET)) != NULL) {
+                               guint 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);
+                       } else {
+                               gchar buffer[INET_ADDRSTRLEN];  /* defined in netinet/in.h */
+                               guchar* p = (guchar*) &(SOUP_SOCKADDR_IN (ia->sa).sin_addr);
+
+                               g_snprintf(buffer, 
+                                          sizeof (buffer), 
+                                          "%d.%d.%d.%d", 
+                                          p[0], 
+                                          p[1], 
+                                          p[2], 
+                                          p[3]);
+                               len = strlen (buffer);
+
+                               if ((write (pipes[1], &len, sizeof(len)) == -1) ||
+                                   (write (pipes[1], buffer, len) == -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);
+
+               } else if (pid > 0) {
+                       /* Set up an IOChannel to read from the pipe */
+                       SoupAddressReverseState* state;
+
+                       /* Create a structure for the call back */
+                       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;
+               } else if (errno == EAGAIN) {
+                       /* Try again */
+                       /* Yield the processor */
+                       sleep(0);       
+                       goto fork_again;
+               } else {
+                       /* 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;
+}
+
+/**
+ *  soup_address_get_name_cancel:
+ *  @id: ID of the lookup
+ *
+ *  Cancel an asynchronous nice name lookup that was started with
+ *  soup_address_get_name().
+ */
+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);
+
+       close (state->fd);
+       kill (state->pid, SIGKILL);
+       waitpid (state->pid, NULL, 0);
+
+       g_free(state);
+}
+
+#else  /*********** Windows code ***********/
+
+static gboolean
+soup_address_get_name_cb (GIOChannel* iochannel,
+                         GIOCondition condition,
+                         gpointer data)
+{
+       SoupAddressReverseState* state;
+       gchar* name;
+       struct hostent* result;
+       state = (SoupAddressReverseState*) data;
+
+       result = (struct hostent*) state->hostentBuffer;
+
+       if (state->errorcode) {
+               (*state->func)(state->ia, 
+                              SOUP_ADDRESS_STATUS_ERROR, 
+                              NULL, 
+                              state->data);
+               return FALSE;
+       }
+
+       state->ia->name = g_strdup (result->h_name);
+       name = NULL;
+       name = g_strdup (state->ia->name);
+
+       (*state->func) (state->ia, 
+                       SOUP_ADDRESS_STATUS_OK, 
+                       name, 
+                       state->data);
+
+       g_free(state);
+       return FALSE;
+}
+
+SoupAddressGetNameId
+soup_address_get_name (SoupAddress* ia,
+                      SoupAddressGetNameFn func,
+                      gpointer data)
+{
+       SoupAddressReverseState* state;
+       struct sockaddr_in* sa_in;
+
+       g_return_val_if_fail(ia != NULL, NULL);
+       g_return_val_if_fail(func != NULL, NULL);
+
+       /* If we already know the name, just copy that */
+       if (ia->name != NULL) {
+               (func) (ia, 
+                       SOUP_ADDRESS_STATUS_OK, 
+                       g_strdup (ia->name), 
+                       data);
+       }
+
+       /* Create a structure for the call back */
+       state = g_new0 (SoupAddressReverseState, 1);
+       state->ia = ia;
+       state->func = func;
+       state->data = data;
+
+       sa_in = (struct sockaddr_in*)&ia->sa;
+       
+       state->WSAhandle = (int) 
+               WSAAsyncGetHostByAddr(soup_hWnd, GET_NAME_MSG,
+                                     (const char*) &sa_in->sin_addr,
+                                     (int) (sizeof (&sa_in->sin_addr)),
+                                     (int) &sa_in->sin_family,
+                                     state->hostentBuffer,
+                                     sizeof (state->hostentBuffer));
+
+       if (!state->WSAhandle) {
+               g_free (state);
+               (func) (ia, SOUP_ADDRESS_STATUS_ERROR, NULL, data);
+               return NULL;
+       }
+       
+       /*get a lock and insert the state into the hash */
+       WaitForSingleObject (soup_Mutex, INFINITE);
+       g_hash_table_insert (soup_hash, 
+                            (gpointer) state->WSAhandle, 
+                            (gpointer) state);
+       ReleaseMutex (soup_Mutex);
+
+       return state;
+}
+
+void
+soup_address_get_name_cancel (SoupAddressGetNameId id)
+{
+       SoupAddressReverseState* state;
+       state = (SoupAddressReverseState*) id;
+
+       g_return_if_fail(state != NULL);
+
+       soup_address_delete (state->ia);
+       WSACancelAsyncRequest ((HANDLE) state->WSAhandle);
+
+       /*get a lock and remove the hash entry */
+       WaitForSingleObject (soup_Mutex, INFINITE);
+       g_hash_table_remove (soup_hash, (gpointer) state->WSAhandle);
+       ReleaseMutex (soup_Mutex);
+
+       g_free (state);
+}
+
+#endif         /*********** End Windows code ***********/
+
+/**
+ *  soup_address_get_canonical_name:
+ *  @ia: 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.
+ **/
+gchar* 
+soup_address_get_canonical_name (SoupAddress* ia)
+{
+       gchar buffer[INET_ADDRSTRLEN];  /* defined in netinet/in.h */
+       guchar* p = (guchar*) &(SOUP_SOCKADDR_IN(ia->sa).sin_addr);
+  
+       g_return_val_if_fail (ia != NULL, NULL);
+
+       g_snprintf(buffer, 
+                  sizeof (buffer), 
+                  "%d.%d.%d.%d", 
+                  p[0], 
+                  p[1], 
+                  p[2], 
+                  p[3]);
+  
+       return g_strdup (buffer);
+}
+
+/**
+ *  soup_address_get_port:
+ *  @ia: Address to get the port number of.
+ *
+ *  Get the port number.
+ *  Returns: the port number.
+ */
+gint
+soup_address_get_port (const SoupAddress* ia)
+{
+       g_return_val_if_fail(ia != NULL, -1);
+
+       return (gint) g_ntohs (((struct sockaddr_in*) &ia->sa)->sin_port);
+}
+
+/**
+ *  soup_address_set_port:
+ *  @ia: Address to set the port number of.
+ *  @port: New port number
+ *
+ *  Set the port number.
+ **/
+void
+soup_address_set_port (const SoupAddress* ia, guint port)
+{
+       g_return_if_fail (ia != NULL);
+
+       ((struct sockaddr_in*) &ia->sa)->sin_port = g_htons (port);
+}
+
+/**
+ *  soup_address_hash:
+ *  @p: Pointer to an #SoupAddress.
+ *
+ *  Hash the address.  This is useful for glib containers.
+ *
+ *  Returns: hash value.
+ **/
+guint 
+soup_address_hash (const gpointer p)
+{
+       const SoupAddress* ia;
+       guint32 port;
+       guint32 addr;
+
+       g_assert(p != NULL);
+
+       ia = (const SoupAddress*) p;
+       /* We do pay attention to network byte order just in case the hash
+          result is saved or sent to a different host.  */
+       port = (guint32) g_ntohs (((struct sockaddr_in*) &ia->sa)->sin_port);
+       addr = g_ntohl (((struct sockaddr_in*) &ia->sa)->sin_addr.s_addr);
+
+       return (port ^ addr);
+}
+
+/**
+ *  soup_address_equal:
+ *  @p1: Pointer to first #SoupAddress.
+ *  @p2: Pointer to second #SoupAddress.
+ *
+ *  Compare two #SoupAddress's.  
+ *
+ *  Returns: 1 if they are the same; 0 otherwise.
+ **/
+gint 
+soup_address_equal (const gpointer p1, const gpointer p2)
+{
+       const SoupAddress* ia1 = (const SoupAddress*) p1;
+       const SoupAddress* ia2 = (const SoupAddress*) p2;
+
+       g_assert(p1 != NULL && p2 != NULL);
+
+       /* Note network byte order doesn't matter */
+       return ((SOUP_SOCKADDR_IN(ia1->sa).sin_addr.s_addr ==
+                SOUP_SOCKADDR_IN(ia2->sa).sin_addr.s_addr) &&
+               (SOUP_SOCKADDR_IN(ia1->sa).sin_port ==
+                SOUP_SOCKADDR_IN(ia2->sa).sin_port));
+}
+
+/**
+ *  soup_address_noport_equal:
+ *  @p1: Pointer to first SoupAddress.
+ *  @p2: Pointer to second SoupAddress.
+ *
+ *  Compare two #SoupAddress's, but does not compare the port numbers.
+ *
+ *  Returns: 1 if they are the same; 0 otherwise.
+ **/
+gint 
+soup_address_noport_equal (const gpointer p1, const gpointer p2)
+{
+       const SoupAddress* ia1 = (const SoupAddress*) p1;
+       const SoupAddress* ia2 = (const SoupAddress*) p2;
+
+       g_assert (p1 != NULL && p2 != NULL);
+
+       /* Note network byte order doesn't matter */
+       return (SOUP_SOCKADDR_IN(ia1->sa).sin_addr.s_addr ==
+               SOUP_SOCKADDR_IN(ia2->sa).sin_addr.s_addr);
+}
+
+#ifndef SOUP_WIN32  /*********** Unix code ***********/
+
+/**
+ *  soup_address_gethostname:
+ * 
+ *  Get the primary host's name.
+ *
+ *  Returns: the name of the host; NULL if there was an error.  The
+ *  caller is responsible for deleting the returned string.
+ **/
+gchar*
+soup_address_gethostname (void)
+{
+       gchar* name = NULL;
+       struct utsname myname;
+
+       if (uname (&myname) < 0) return NULL;
+
+       if (!soup_gethostbyname (myname.nodename, NULL, &name)) return NULL;
+
+       return name;
+}
+
+#else  /*********** Windows code ***********/
+
+gchar*
+soup_address_gethostname (void)
+{
+       gchar* name = NULL;
+       int error = 0;
+
+       name = g_new0 (char, 256);
+       error = gethostname (name, 256);
+       if (error) {
+               g_free(name);
+               return NULL;
+       }
+
+       return name;
+}
+
+#endif         /*********** End Windows code ***********/
+
+/**
+ *  soup_address_gethostaddr:
+ * 
+ *  Get the primary host's #SoupAddress.
+ *
+ *  Returns: the #SoupAddress of the host; NULL if there was an error.
+ *  The caller is responsible for deleting the returned #SoupAddress.
+ **/
+SoupAddress * 
+soup_address_gethostaddr (void)
+{
+       gchar* name;
+       struct sockaddr_in* sa_in, sa;
+       SoupAddress* ia = NULL;
+
+       name = soup_address_gethostname ();
+
+       if (name && soup_gethostbyname(name, &sa, NULL)) {
+               ia = g_new0 (SoupAddress, 1);
+               ia->name = g_strdup (name);
+               ia->ref_count = 1;
+
+               sa_in = (struct sockaddr_in*) &ia->sa;
+               sa_in->sin_family = AF_INET;
+               sa_in->sin_port = 0;
+               memcpy (&sa_in->sin_addr, &sa.sin_addr, 4);
+        }
+
+       return ia;
+}
+
+static void 
+soup_socket_connect_tcp_cb (SoupSocket* socket, 
+                           SoupSocketConnectStatus status, 
+                           gpointer data)
+{
+       SoupSocketConnectState* state = (SoupSocketConnectState*) data;
+
+       if (status == SOUP_SOCKET_NEW_STATUS_OK)
+               (*state->func) (socket, 
+                               state->ia, 
+                               SOUP_SOCKET_CONNECT_ERROR_NONE, 
+                               state->data);
+       else
+               (*state->func) (NULL, 
+                               NULL, 
+                               SOUP_SOCKET_CONNECT_ERROR_NETWORK, 
+                               state->data);
+
+       g_free(state);
+}
+
+static void
+soup_socket_connect_inetaddr_cb (SoupAddress* inetaddr, 
+                                SoupAddressStatus status, 
+                                gpointer data)
+{
+       SoupSocketConnectState* state = (SoupSocketConnectState*) data;
+
+       if (status == SOUP_ADDRESS_STATUS_OK) {
+               state->ia = inetaddr;
+
+               state->inetaddr_id = NULL;
+               state->tcp_id = 
+                       soup_socket_new (inetaddr, 
+                                        soup_socket_connect_tcp_cb, 
+                                        state);
+               /* Note that this call may delete the state. */
+       } else {
+               (*state->func) (NULL, 
+                               NULL, 
+                               SOUP_SOCKET_CONNECT_ERROR_ADDR_RESOLVE, 
+                               state->data);
+               g_free(state);
+       }
+}
+
+/**
+ *  soup_socket_connect:
+ *  @hostname: Name of host to connect to
+ *  @port: Port to connect to
+ *  @func: Callback function
+ *  @data: User data passed when callback function is called.
+ *
+ *  A quick and easy non-blocking #SoupSocket constructor.  This
+ *  connects to the specified address and port and then calls the
+ *  callback with the data.  Use this function when you're a client
+ *  connecting to a server and you don't want to block or mess with
+ *  #SoupAddress's.  It may call the callback before the function
+ *  returns.  It will call the callback if there is a failure.
+ *
+ *  Returns: ID of the connection which can be used with
+ *  soup_socket_connect_cancel() to cancel it; NULL on
+ *  failure.
+ **/
+SoupSocketConnectId
+soup_socket_connect (gchar*                     hostname, 
+                    gint                       port, 
+                    SoupSocketConnectFn func, 
+                    gpointer                   data)
+{
+       SoupSocketConnectState* state;
+       gpointer id;
+
+       g_return_val_if_fail(hostname != NULL, NULL);
+       g_return_val_if_fail(func != NULL, NULL);
+
+       state = g_new0(SoupSocketConnectState, 1);
+       state->func = func;
+       state->data = data;
+
+       id = soup_address_new (hostname, 
+                              port,  
+                              soup_socket_connect_inetaddr_cb, 
+                              state);
+
+       /* Note that soup_address_new can fail immediately and call
+          our callback which will delete the state.  The users callback
+          would be called in the process. */
+
+       if (id == NULL) return NULL;
+
+       state->inetaddr_id = id;
+
+       return state;
+}
+
+/**
+ *  soup_socket_connect_cancel:
+ *  @id: Id of the connection.
+ *
+ *  Cancel an asynchronous connection that was started with
+ *  soup_socket_connect().
+ */
+void
+soup_socket_connect_cancel (SoupSocketConnectId id)
+{
+       SoupSocketConnectState* state = (SoupSocketConnectState*) id;
+
+       g_return_if_fail (state != NULL);
+  
+       if (state->inetaddr_id)
+               soup_address_new_cancel(state->inetaddr_id);
+       else if (state->tcp_id) {
+               soup_address_unref (state->ia);
+               soup_socket_new_cancel (state->tcp_id);
+       }
+
+       g_free (state);
+}
+
+
+#ifndef SOUP_WIN32  /*********** Unix code ***********/
+
+static gboolean 
+soup_socket_new_cb (GIOChannel* iochannel, 
+                   GIOCondition condition, 
+                   gpointer data)
+{
+       SoupSocketState* state = (SoupSocketState*) data;
+
+       /* Remove the watch now in case we don't return immediately */
+       g_source_remove (state->connect_watch);
+
+       errno = 0;
+       if ((condition & G_IO_IN) || (condition & G_IO_OUT)) {
+               gint error, len;
+               len = sizeof (error);
+
+               /* Get the error option */
+               if (getsockopt (state->socket->sockfd, 
+                               SOL_SOCKET, 
+                               SO_ERROR, 
+                               &error, 
+                               &len) >= 0) {
+                       /* Check if there is an error */
+                       if (!error) {
+                               /* Reset the flags */
+                               if (fcntl (state->socket->sockfd, 
+                                          F_SETFL, 
+                                          state->flags) == 0) {
+                                       (*state->func) (state->socket, 
+                                                       SOUP_SOCKET_NEW_STATUS_OK, 
+                                                       state->data);
+                                       g_free (state);
+                                       return FALSE;
+                               }
+                       }
+               }
+       }
+
+       /* Otherwise, there was an error */
+       (*state->func) (NULL, SOUP_SOCKET_NEW_STATUS_ERROR, state->data);
+       soup_socket_unref (state->socket);
+       g_free (state);
+
+       return FALSE;
+}
+
+/**
+ *  soup_socket_new:
+ *  @addr: Address to connect to.
+ *  @func: Callback function.
+ *  @data: User data passed when callback function is called.
+ *
+ *  Connect to a specifed address asynchronously.  When the connection
+ *  is complete or there is an error, it will call the callback.  It
+ *  may call the callback before the function returns.  It will call
+ *  the callback if there is a failure.
+ *
+ *  Returns: ID of the connection which can be used with
+ *  soup_socket_connect_cancel() to cancel it; NULL on
+ *  failure.
+ **/
+SoupSocketNewId
+soup_socket_new (const SoupAddress* addr, 
+                SoupSocketNewFn func,
+                gpointer data)
+{
+       gint sockfd;
+       gint flags;
+       SoupSocket* s;
+       struct sockaddr_in* sa_in;
+       SoupSocketState* state;
+
+       g_return_val_if_fail(addr != NULL, NULL);
+       g_return_val_if_fail(func != NULL, NULL);
+
+       /* Create socket */
+       sockfd = socket (AF_INET, SOCK_STREAM, 0);
+       if (sockfd < 0) {
+               (func)(NULL, SOUP_SOCKET_NEW_STATUS_ERROR, data);
+               return NULL;
+       }
+
+       /* Get the flags (should all be 0?) */
+       flags = fcntl (sockfd, F_GETFL, 0);
+       if (flags == -1) {
+               (func)(NULL, SOUP_SOCKET_NEW_STATUS_ERROR, data);
+               return NULL;
+       }
+
+       if (fcntl (sockfd, F_SETFL, flags | O_NONBLOCK) == -1) {
+               (func)(NULL, SOUP_SOCKET_NEW_STATUS_ERROR, data);
+               return NULL;
+       }
+
+       /* Create our structure */
+       s = g_new0 (SoupSocket, 1);
+       s->ref_count = 1;
+       s->sockfd = sockfd;
+
+       /* Set up address and port for connection */
+       memcpy (&s->sa, &addr->sa, sizeof(s->sa));
+       sa_in = (struct sockaddr_in*) &s->sa;
+       sa_in->sin_family = AF_INET;
+
+       /* Connect (but non-blocking!) */
+       if (connect (s->sockfd, &s->sa, sizeof(s->sa)) < 0) {
+               if (errno != EINPROGRESS) {
+                       g_free(s);
+                       (func)(NULL, SOUP_SOCKET_NEW_STATUS_ERROR, data);
+                       return NULL;
+               }
+       }
+
+       /* Note that if connect returns 0, then we're already connected and
+          we could call the call back immediately.  But, it would probably
+          make things too complicated for the user if we could call the
+          callback before we returned from this function.  */
+
+       /* Wait for the connection */
+       state = g_new0 (SoupSocketState, 1);
+       state->socket = s;
+       state->func = func;
+       state->data = data;
+       state->flags = flags;
+       state->connect_watch = 
+               g_io_add_watch (g_io_channel_unix_new (s->sockfd),
+                               SOUP_ANY_IO_CONDITION,
+                               soup_socket_new_cb, 
+                               state);
+
+       return state;
+}
+
+/**
+ *  soup_socket_new_cancel:
+ *  @id: ID of the connection.
+ *
+ *  Cancel an asynchronous connection that was started with
+ *  soup_socket_new().
+ **/
+void
+soup_socket_new_cancel (SoupSocketNewId id)
+{
+       SoupSocketState* state = (SoupSocketState*) id;
+
+       g_source_remove (state->connect_watch);
+       soup_socket_unref (state->socket);
+       g_free (state);
+}
+
+
+#else  /*********** Windows code ***********/
+
+static gboolean
+soup_socket_new_cb (GIOChannel* iochannel,
+                   GIOCondition condition,
+                   gpointer data)
+{
+       SoupSocketState* state = (SoupSocketState*) data;
+
+       if (state->errorcode) {
+               (*state->func)(state->socket, 
+                              SOUP_SOCKET_NEW_STATUS_OK, 
+                              state->data);
+               g_free(state);
+               return FALSE;
+       }
+
+       (*state->func) (state->socket, 
+                       SOUP_SOCKET_NEW_STATUS_OK, 
+                       state->data);
+       g_free(state);
+       return FALSE;
+}
+
+SoupSocketNewId
+soup_socket_new (const SoupAddress* addr,
+                SoupSocketNewFn func,
+                gpointer data)
+{
+       gint sockfd;
+       gint status;
+       SoupSocket* s;
+       struct sockaddr_in* sa_in;
+       SoupSocketState* state;
+
+       g_return_val_if_fail(addr != NULL, NULL);
+       g_return_val_if_fail(func != NULL, NULL);
+
+       /* Create socket */
+       sockfd = socket(AF_INET, SOCK_STREAM, 0);
+       if (sockfd == INVALID_SOCKET) {
+               (func)(NULL, SOUP_SOCKET_NEW_STATUS_ERROR, data);
+               return NULL;
+       }
+       
+       /* Note: WSAAsunc automatically sets the socket to noblocking mode */
+       status = WSAAsyncSelect(sockfd, soup_hWnd, TCP_SOCK_MSG, FD_CONNECT);
+
+       if (status == SOCKET_ERROR) {
+               (func)(NULL, SOUP_SOCKET_NEW_STATUS_ERROR, data);
+               return NULL;
+       }
+
+       /* Create our structure */
+       s = g_new0(SoupSocket, 1);
+       s->ref_count = 1;
+       s->sockfd = sockfd;
+
+       /* Set up address and port for connection */
+       memcpy(&s->sa, &addr->sa, sizeof(s->sa));
+       sa_in = (struct sockaddr_in*) &s->sa;
+       sa_in->sin_family = AF_INET;
+
+       status = connect(s->sockfd, &s->sa, sizeof(s->sa));
+       /* Returning an error is ok, unless.. */
+       if (status == SOCKET_ERROR) {
+               status = WSAGetLastError();
+               if (status != WSAEWOULDBLOCK) {
+                       (func)(NULL, SOUP_SOCKET_NEW_STATUS_ERROR, data);
+                       g_free(s);
+                       return NULL;
+               }
+       }
+
+       /* Wait for the connection */
+       state = g_new0(SoupSocketState, 1);
+       state->socket = s;
+       state->func = func;
+       state->data = data;
+       state->socket->sockfd = sockfd;
+
+       WaitForSingleObject(soup_select_Mutex, INFINITE);
+       /*using sockfd as the key into the 'select' hash */
+       g_hash_table_insert(soup_select_hash, 
+                           (gpointer) state->socket->sockfd, 
+                           (gpointer) state);
+       ReleaseMutex(soup_select_Mutex);
+
+       return state;
+}
+
+void
+soup_socket_new_cancel(SoupSocketNewId id)
+{
+       SoupSocketState* state = (SoupSocketState*) id;
+       
+       /* Cancel event posting on the socket */
+       WSAAsyncSelect(state->socket->sockfd, soup_hWnd, 0, 0);
+       soup_socket_delete(state->socket);
+       g_free (state);
+}
+
+#endif         /*********** End Windows code ***********/
+
+/**
+ *  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) {
+               /* Don't care if this fails... */
+               SOUP_CLOSE_SOCKET(s->sockfd);
+
+               if (s->iochannel) g_io_channel_unref(s->iochannel);
+
+               g_free(s);
+       }
+}
+
+/**
+ *  soup_socket_get_iochannel:
+ *  @socket: SoupSocket to get GIOChannel from.
+ *
+ *  Get the #GIOChannel for the #SoupSocket.
+ *
+ *  For a client socket, the #GIOChannel represents the data stream.
+ *  Use it like you would any other #GIOChannel.
+ *
+ *  For a server socket however, the #GIOChannel represents incoming
+ *  connections.  If you can read from it, there's a connection
+ *  waiting.
+ *
+ *  There is one channel for every socket.  This function refs the
+ *  channel before returning it.  You should unref the channel when
+ *  you are done with it.  However, you should not close the channel -
+ *  this is done when you delete the socket.
+ *
+ *  Returns: A #GIOChannel; NULL on failure.
+ *
+ **/
+GIOChannel* 
+soup_socket_get_iochannel (SoupSocket* socket)
+{
+  g_return_val_if_fail (socket != NULL, NULL);
+
+  if (socket->iochannel == NULL)
+    socket->iochannel = SOUP_SOCKET_IOCHANNEL_NEW(socket->sockfd);
+  
+  g_io_channel_ref (socket->iochannel);
+
+  return socket->iochannel;
+}
+
+/**
+ *  soup_socket_get_address:
+ *  @socket: #SoupSocket to get address of.
+ *
+ *  Get the address of the socket.  If the socket is client socket,
+ *  the address is the address of the remote host it is connected to.
+ *  If the socket is a server socket, the address is the address of
+ *  the local host.  (Though you should use
+ *  soup_address_gethostaddr() to get the #SoupAddress of the local
+ *  host.)
+ *
+ *  Returns: #SoupAddress of socket; NULL on failure.
+ **/
+SoupAddress * 
+soup_socket_get_address (const SoupSocket* socket)
+{
+       SoupAddress* ia;
+
+       g_return_val_if_fail (socket != NULL, NULL);
+
+       ia = g_new0 (SoupAddress, 1);
+       ia->sa = socket->sa;
+
+       return ia;
+}
+
+/**
+ *  soup_socket_get_port:
+ *  @socket: SoupSocket to get the port number of.
+ *
+ *  Get the port number the socket is bound to.
+ *
+ *  Returns: Port number of the socket.
+ **/
+gint
+soup_socket_get_port(const SoupSocket* socket)
+{
+       g_return_val_if_fail (socket != NULL, 0);
+
+       return g_ntohs (SOUP_SOCKADDR_IN (socket->sa).sin_port);
+}
+
+
+#ifdef SOUP_WIN32  /*********** Windows code ***********/
+
+int 
+soup_MainCallBack (GIOChannel   *iochannel, 
+                  GIOCondition  condition, 
+                  void         *nodata)
+{
+       MSG msg;
+
+       gpointer data;
+       SoupSocketState *IAstate;
+       SoupAddressReverseState *IARstate;
+       SoupSocketState *TCPNEWstate;
+
+       /*Take the msg off the message queue */
+       GetMessage (&msg, NULL, 0, 0);
+       switch (msg.message) {
+       case IA_NEW_MSG:
+               WaitForSingleObject (soup_Mutex, INFINITE);
+               data = g_hash_table_lookup (soup_hash, (gpointer) msg.wParam);
+               g_hash_table_remove (soup_hash, (gpointer) msg.wParam);
+               ReleaseMutex (soup_Mutex);
+               
+               IAstate = (SoupAddressState*) data;
+               /* NULL if OK */
+               IAstate->errorcode = WSAGETASYNCERROR(msg.lParam); 
+
+               /* Now call the callback function */
+               soup_address_new_cb (NULL, G_IO_IN, (gpointer) IAstate);
+
+               break;
+       case GET_NAME_MSG:
+               WaitForSingleObject (soup_Mutex, INFINITE);
+               data = g_hash_table_lookup (soup_hash, (gpointer) msg.wParam);
+               g_hash_table_remove (soup_hash, (gpointer) msg.wParam);
+               ReleaseMutex (soup_Mutex);
+
+               IARstate = (SoupAddressReverseState*) data;
+               /* NULL if OK */
+               IARstate->errorcode = WSAGETASYNCERROR(msg.lParam); 
+                       
+               /* Now call the callback function */
+               soup_address_get_name_cb (NULL, 
+                                               G_IO_IN, 
+                                               (gpointer) IARstate);
+               break;
+       case TCP_SOCK_MSG:
+               WaitForSingleObject (soup_select_Mutex, INFINITE);
+               data = g_hash_table_lookup (soup_select_hash, 
+                                           (gpointer) msg.wParam);
+               g_hash_table_remove (soup_select_hash, (gpointer) msg.wParam);
+               ReleaseMutex (soup_select_Mutex);
+                       
+               TCPNEWstate = (SoupSocketState*) data;
+               TCPNEWstate->errorcode = WSAGETSELECTERROR (msg.lParam);
+               soup_tcp_socket_new_cb (NULL, 
+                                             G_IO_IN, 
+                                             (gpointer) TCPNEWstate);
+               break;
+       }
+
+       return 1;
+}
+
+LRESULT CALLBACK
+SoupWndProc (HWND hwnd,        /* handle to window */
+            UINT uMsg,        /* message identifier */
+            WPARAM wParam,    /* first message parameter */
+            LPARAM lParam)    /* second message parameter */
+{
+       switch (uMsg) { 
+        case WM_CREATE:  /* Initialize the window. */
+               return 0; 
+        case WM_PAINT:   /* Paint the window's client area. */ 
+               return 0; 
+        case WM_SIZE:    /* Set the size and position of the window. */ 
+               return 0; 
+        case WM_DESTROY: /* Clean up window-specific data objects. */
+               return 0; 
+        default: 
+               return DefWindowProc(hwnd, uMsg, wParam, lParam); 
+       } 
+} 
+
+gboolean
+RemoveHashEntry(gpointer key, gpointer value, gpointer user_data)
+{
+       g_free (value);
+       return TRUE;
+}
+
+
+BOOL WINAPI 
+DllMain (HINSTANCE hinstDLL,  /* handle to DLL module */
+        DWORD fdwReason,     /* reason for calling functionm */
+        LPVOID lpvReserved   /* reserved */)
+{
+       WORD wVersionRequested;
+       WSADATA wsaData;
+       int err;
+
+       switch(fdwReason) {
+       case DLL_PROCESS_ATTACH:
+               /* The DLL is being mapped into process's address space */
+               /* Do any required initialization on a per application basis,
+                  return FALSE if failed */
+               wVersionRequested = MAKEWORD( 2, 0 );
+               err = WSAStartup (wVersionRequested, &wsaData);
+               if (err != 0) {
+                       /* Tell the user that we could not find a usable
+                          WinSock DLL.  */
+                       return FALSE;
+               }
+               /* Confirm that the WinSock DLL supports 2.0.*/
+               /* Note that if the DLL supports versions greater    */
+               /* than 2.0 in addition to 2.0, it will still return */
+               /* 2.0 in wVersion since that is the version we      */
+               /* requested.                                        */
+               if ( LOBYTE( wsaData.wVersion ) != 2 ||
+                    HIBYTE( wsaData.wVersion ) != 0 ) {
+                       /* Tell the user that we could not find a usable */
+                       /* WinSock DLL.                                  */
+                       WSACleanup();
+                       return FALSE; 
+               }
+               /* The WinSock DLL is acceptable. Proceed. */
+               
+               /* Setup and register a windows class that we use for out
+                   GIOchannel */
+               soupWndClass.cbSize = sizeof (WNDCLASSEX); 
+               soupWndClass.style = CS_SAVEBITS; 
+               soupWndClass.lpfnWndProc = (WNDPROC) SoupWndProc; 
+               soupWndClass.cbClsExtra = 0; 
+               soupWndClass.cbWndExtra = 0; 
+               soupWndClass.hInstance = hinstDLL; 
+               soupWndClass.hIcon = NULL; 
+               soupWndClass.hCursor = NULL; 
+               soupWndClass.hbrBackground = NULL; 
+               soupWndClass.lpszMenuName = NULL; 
+               soupWndClass.lpszClassName = "Soup"; 
+               soupWndClass.hIconSm = NULL; 
+
+               if (!RegisterClassEx (&soupWndClass)) return FALSE;
+
+               soup_hWnd  = CreateWindowEx (0,
+                                            "Soup", 
+                                            "none",
+                                            WS_OVERLAPPEDWINDOW, 
+                                            CW_USEDEFAULT, 
+                                            CW_USEDEFAULT, 
+                                            CW_USEDEFAULT, 
+                                            CW_USEDEFAULT, 
+                                            (HWND) NULL, 
+                                            (HMENU) NULL, 
+                                            hinstDLL, 
+                                            (LPVOID) NULL);
+
+               if (!soup_hWnd) return FALSE;
+
+               soup_iochannel = 
+                       g_io_channel_win32_new_messages (
+                               (unsigned int) soup_hWnd);
+
+               /* Add a watch */
+               soup_io_watch_ID = 
+                       g_io_add_watch (soup_iochannel,
+                                       G_IO_IN|G_IO_ERR|G_IO_HUP|G_IO_NVAL,
+                                       soup_MainCallBack, 
+                                       NULL);
+
+               soup_hash = g_hash_table_new (NULL, NULL);
+               soup_select_hash = g_hash_table_new (NULL, NULL);
+       
+
+               soup_Mutex = CreateMutex(NULL, FALSE, "soup_Mutex");
+
+               if (soup_Mutex == NULL) return FALSE;
+
+               soup_select_Mutex = CreateMutex(NULL, 
+                                               FALSE, 
+                                               "soup_select_Mutex");
+
+               if (soup_select_Mutex == NULL) return FALSE;
+
+               soup_hostent_Mutex = CreateMutex(NULL,
+                                                FALSE,
+                                                "soup_hostent_Mutex");
+
+               if (soup_hostent_Mutex == NULL) return FALSE;
+
+               break;
+       case DLL_THREAD_ATTACH:
+               break;
+       case DLL_THREAD_DETACH:
+               break;
+       case DLL_PROCESS_DETACH:
+               /* The DLL unmapped from process's address space. Do necessary
+                   cleanup */
+               g_source_remove (soup_io_watch_ID);
+               g_free (soup_iochannel);
+               DestroyWindow (soup_hWnd);
+
+               WaitForSingleObject (soup_Mutex, INFINITE);
+               WaitForSingleObject (soup_select_Mutex, INFINITE);
+               g_hash_table_foreach_remove (soup_hash, RemoveHashEntry, NULL);
+               g_hash_table_foreach_remove (soup_select_hash, 
+                                            RemoveHashEntry, 
+                                            NULL);
+               g_hash_table_destroy (soup_select_hash);
+               g_hash_table_destroy (soup_hash);
+               ReleaseMutex (soup_Mutex);
+               ReleaseMutex (soup_select_Mutex);
+               ReleaseMutex (soup_hostent_Mutex);
+
+               WSACleanup();
+
+               break;
+       }
+
+       return TRUE;
+}
+
+#endif         /*********** End Windows code ***********/
diff --git a/libsoup/soup-socket.h b/libsoup/soup-socket.h
new file mode 100644 (file)
index 0000000..33537ed
--- /dev/null
@@ -0,0 +1,130 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * soup-socket.c: ronous Callback-based SOAP Request Queue.
+ *
+ * Authors:
+ *      David Helder  (dhelder@umich.edu)
+ *      Alex Graveley (alex@helixcode.com)
+ * 
+ * Original code compliments of David Helder's GNET Networking Library.
+ *
+ * Copyright (C) 2000, Helix Code, Inc.
+ */
+
+#ifndef SOUP_SOCKET_H
+#define SOUP_SOCKET_H 1
+
+#include <glib.h>
+
+typedef struct _SoupAddress SoupAddress;
+
+typedef gpointer SoupAddressNewId;
+
+typedef enum {
+       SOUP_ADDRESS_STATUS_OK,
+       SOUP_ADDRESS_STATUS_ERROR
+} SoupAddressStatus;
+
+typedef void (*SoupAddressNewFn) (SoupAddress       *inetaddr, 
+                                 SoupAddressStatus  status, 
+                                 gpointer           user_data);
+
+SoupAddressNewId     soup_address_new                (const gchar*       name, 
+                                                     const gint         port, 
+                                                     SoupAddressNewFn   func, 
+                                                     gpointer           data);
+
+void                 soup_address_new_cancel         (SoupAddressNewId   id);
+
+SoupAddress*         soup_address_clone              (const SoupAddress* ia);
+
+void                 soup_address_ref                (SoupAddress*       ia);
+
+void                 soup_address_unref              (SoupAddress*       ia);
+
+
+typedef gpointer SoupAddressGetNameId;
+
+typedef void (*SoupAddressGetNameFn) (SoupAddress       *inetaddr, 
+                                     SoupAddressStatus  status, 
+                                     gchar             *name,
+                                     gpointer           user_data);
+
+SoupAddressGetNameId soup_address_get_name           (SoupAddress*         ia, 
+                                                     SoupAddressGetNameFn func,
+                                                     gpointer             data);
+
+void                 soup_address_get_name_cancel    (SoupAddressGetNameId id);
+
+gchar*               soup_address_get_canonical_name (SoupAddress*         ia);
+
+gint                 soup_address_get_port           (const SoupAddress*   ia);
+
+void                 soup_address_set_port           (const SoupAddress*   ia, 
+                                                     guint                port);
+
+guint                soup_address_hash               (const gpointer       p);
+
+gint                 soup_address_equal              (const gpointer       p1, 
+                                                     const gpointer       p2);
+
+gint                 soup_address_noport_equal       (const gpointer       p1, 
+                                                     const gpointer       p2);
+
+gchar*               soup_address_gethostname        (void);
+
+SoupAddress*         soup_address_gethostaddr        (void);
+
+
+typedef struct _SoupSocket SoupSocket;
+
+typedef gpointer SoupSocketConnectId;
+
+typedef enum {
+       SOUP_SOCKET_CONNECT_ERROR_NONE,
+       SOUP_SOCKET_CONNECT_ERROR_ADDR_RESOLVE,
+       SOUP_SOCKET_CONNECT_ERROR_NETWORK
+} SoupSocketConnectStatus;
+
+typedef void (*SoupSocketConnectFn) (SoupSocket* socket, 
+                                    SoupAddress* ia,
+                                    SoupSocketConnectStatus status, 
+                                    gpointer data);
+
+SoupSocketConnectId soup_socket_connect        (gchar*              hostname,
+                                               gint                port, 
+                                               SoupSocketConnectFn func, 
+                                               gpointer            user_data);
+
+void                soup_socket_connect_cancel (SoupSocketConnectId id);
+
+
+typedef gpointer SoupSocketNewId;
+
+typedef enum {
+       SOUP_SOCKET_NEW_STATUS_OK,
+       SOUP_SOCKET_NEW_STATUS_ERROR
+} SoupSocketNewStatus;
+
+typedef void (*SoupSocketNewFn) (SoupSocket*         socket, 
+                                SoupSocketNewStatus status, 
+                                gpointer            data);
+
+SoupSocketNewId     soup_socket_new            (const SoupAddress*  addr, 
+                                               SoupSocketNewFn     func,
+                                               gpointer            user_data);
+
+void                soup_socket_new_cancel     (SoupSocketNewId     id);
+
+
+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);
+
+#endif /* SOUP_SOCKET_H */
index cf19c5a..4e2d42b 100644 (file)
 
 #include <glib.h>
 #include <string.h>
-#include <gnet/gnet.h>
-#include <netinet/in.h>
 
 #include "soup-socks.h"
 #include "soup-context.h"
-
-struct _GInetAddr {
-       gchar* name;
-       struct sockaddr_in sa;
-       guint ref_count;
-};
+#include "soup-socket.h"
+#include "soup-private.h"
 
 typedef struct {
        SoupConnection        *src_conn;
@@ -38,7 +32,7 @@ typedef struct {
                SOCKS_5_VERIFY_SUCCESS  
        } phase;
 
-       struct _GInetAddr     *dest_addr;
+       SoupAddress           *dest_addr;
        SoupContext           *dest_ctx;
        SoupConnectCallbackFn  cb;
        gpointer               user_data;
@@ -210,14 +204,14 @@ soup_socks_read (GIOChannel* iochannel,
 }
 
 static void
-soup_lookup_dest_addr_cb (GInetAddr*           inetaddr, 
-                         GInetAddrAsyncStatus status, 
+soup_lookup_dest_addr_cb (SoupAddress*         inetaddr, 
+                         SoupAddressStatus    status, 
                          gpointer             data)
 {
        SoupSocksData *sd = data;
        GIOChannel *channel;
 
-       if (status != GINETADDR_ASYNC_STATUS_OK) {
+       if (status != SOUP_ADDRESS_STATUS_OK) {
                (*sd->cb) (sd->dest_ctx, 
                           SOUP_CONNECT_ERROR_ADDR_RESOLVE, 
                           NULL, 
@@ -257,10 +251,10 @@ soup_connect_socks_proxy (SoupConnection        *conn,
        
        switch (soup_context_get_protocol (proxy_ctx)) {
        case SOUP_PROTOCOL_SOCKS4:
-               gnet_inetaddr_new_async (dest_uri->host, 
-                                        dest_uri->port, 
-                                        soup_lookup_dest_addr_cb,
-                                        sd);
+               soup_address_new (dest_uri->host, 
+                                 dest_uri->port, 
+                                 soup_lookup_dest_addr_cb,
+                                 sd);
                sd->phase = SOCKS_4_DEST_ADDR_LOOKUP;
                break;
 
index bf5a465..c2a9642 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
 /*
- * soup-queue.h: Asyncronous Callback-based SOAP Request Queue.
+ * soup-socks.h: Asyncronous Callback-based SOAP Request Queue.
  *
  * Authors:
  *      Alex Graveley (alex@helixcode.com)
index 361a103..bd094ab 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
 /*
- * soup-queue.h: Asyncronous Callback-based SOAP Request Queue.
+ * soup.h: Asyncronous Callback-based SOAP Request Queue.
  *
  * Authors:
  *      Alex Graveley (alex@helixcode.com)
 extern "C" {
 #endif
 
-#include <soup/soup-queue.h>
 #include <soup/soup-context.h>
 #include <soup/soup-message.h>
-#include <soup/soup-uri.h>
 #include <soup/soup-misc.h>
 #include <soup/soup-serializer.h>
+#include <soup/soup-socket.h>
+#include <soup/soup-uri.h>
 
 #ifdef __cplusplus
 }
index ebbaba2..92f96b7 100644 (file)
@@ -7,5 +7,5 @@ Name: Soup
 Description: a SOAP client library in C.
 Version: @VERSION@
 Requires: glib
-Libs: -L${libdir} -lsoup @GNET_LIBS@ @XML_LIBS@
-Cflags: -I${includedir} @GNET_CFLAGS@ @XML_CFLAGS@
\ No newline at end of file
+Libs: -L${libdir} -lsoup @XML_LIBS@
+Cflags: -I${includedir} @XML_CFLAGS@
\ No newline at end of file