Merge commit 'scormi3/master'
authorThadeu Lima de Souza Cascardo <cascardo@minaslivre.org>
Mon, 10 Mar 2008 12:38:45 +0000 (09:38 -0300)
committerThadeu Lima de Souza Cascardo <cascardo@minaslivre.org>
Mon, 10 Mar 2008 12:38:45 +0000 (09:38 -0300)
Conflicts:

gnio/gsocket.c
gnio/gsocket.h

13 files changed:
gnio/ginet6address.c
gnio/ginetsocketaddress.c
gnio/gnetworkinputstream.c
gnio/gnetworkinputstream.h
gnio/gnetworkoutputstream.c
gnio/gnetworkoutputstream.h
gnio/gsocket.c
gnio/gsocket.h
gnio/gsocketaddress.c
gnio/gtcpclient.c
test/test-server.c
test/test-stuff.c
test/test-tcp-client.c

index 6598572..1efcba5 100644 (file)
@@ -138,5 +138,7 @@ g_inet6_address_new_loopback (void)
 GInet6Address *
 g_inet6_address_new_any (void)
 {
-  return NULL; 
+  guint8 bytes[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+  return g_inet6_address_from_bytes (bytes);
 }
index 040064a..0bb6196 100644 (file)
@@ -151,7 +151,12 @@ g_inet_socket_address_to_native (GSocketAddress *address,
     }
   else if (G_IS_INET6_ADDRESS (addr->priv->address))
     {
-      return FALSE;
+      struct sockaddr_in6 *sock = (struct sockaddr_in6 *) dest;
+      memset (sock, 0, sizeof (sock));
+      sock->sin6_family = AF_INET6;
+      sock->sin6_port = g_htons (addr->priv->port);
+      memcpy (&(sock->sin6_addr.s6_addr), g_inet6_address_to_bytes (G_INET6_ADDRESS (addr->priv->address)), sizeof (sock->sin6_addr));
+      return TRUE;
     }
   else
     return FALSE;
index a7bdbb6..48ecf8c 100644 (file)
 #include <glib.h>
 #include <gio/gio.h>
 
+#include "gsocket.h"
 #include "gnetworkinputstream.h"
 
 G_DEFINE_TYPE (GNetworkInputStream, g_network_input_stream, G_TYPE_INPUT_STREAM);
 
+enum
+{
+  PROP_0,
+  PROP_SOCKET
+};
+
+struct _GNetworkInputStreamPrivate
+{
+  GSocket *socket;
+};
+
+static void
+g_network_input_stream_get_property (GObject    *object,
+                                     guint       prop_id,
+                                     GValue     *value,
+                                     GParamSpec *pspec)
+{
+  GNetworkInputStream *stream = G_NETWORK_INPUT_STREAM (object);
+
+  switch (prop_id)
+    {
+      case PROP_SOCKET:
+        g_value_set_object (value, stream->priv->socket);
+        break;
+
+      default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+g_network_input_stream_set_property (GObject      *object,
+                                     guint         prop_id,
+                                     const GValue *value,
+                                     GParamSpec   *pspec)
+{
+  GNetworkInputStream *stream = G_NETWORK_INPUT_STREAM (object);
+
+  switch (prop_id)
+    {
+      case PROP_SOCKET:
+        stream->priv->socket = g_value_dup_object (value);
+        break;
+
+      default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+g_network_input_stream_finalize (GObject *object)
+{
+  if (G_OBJECT_CLASS (g_network_input_stream_parent_class)->finalize)
+    (*G_OBJECT_CLASS (g_network_input_stream_parent_class)->finalize) (object);
+}
+
+static void
+g_network_input_stream_dispose (GObject *object)
+{
+  if (G_OBJECT_CLASS (g_network_input_stream_parent_class)->dispose)
+    (*G_OBJECT_CLASS (g_network_input_stream_parent_class)->dispose) (object);
+}
+
+static gssize
+g_network_input_stream_read (GInputStream  *stream,
+                             void          *buffer,
+                             gsize          count,
+                             GCancellable  *cancellable,
+                             GError       **error)
+{
+  GNetworkInputStream *input_stream = G_NETWORK_INPUT_STREAM (stream);
+
+  return g_socket_receive (input_stream->priv->socket, (gchar *) buffer, count, error);
+}
+
 static void
 g_network_input_stream_class_init (GNetworkInputStreamClass *klass)
 {
-  GObjectClass *gobject_class G_GNUC_UNUSED = G_OBJECT_CLASS (klass);
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  GInputStreamClass *ginputstream_class = G_INPUT_STREAM_CLASS (klass);
+
+  g_type_class_add_private (klass, sizeof (GNetworkInputStreamPrivate));
+
+  gobject_class->finalize = g_network_input_stream_finalize;
+  gobject_class->dispose = g_network_input_stream_dispose;
+  gobject_class->get_property = g_network_input_stream_get_property;
+  gobject_class->set_property = g_network_input_stream_set_property;
+
+  ginputstream_class->read_fn = g_network_input_stream_read;
+
+  g_object_class_install_property (gobject_class, PROP_SOCKET,
+                                   g_param_spec_object ("socket",
+                                                        "socket",
+                                                        "the socket that this stream wraps",
+                                                        G_TYPE_SOCKET,
+                                                        G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB | G_PARAM_STATIC_NICK));
 }
 
 static void
-g_network_input_stream_init (GNetworkInputStream *address)
+g_network_input_stream_init (GNetworkInputStream *stream)
 {
+  stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (stream, G_TYPE_NETWORK_INPUT_STREAM, GNetworkInputStreamPrivate);
+
+  stream->priv->socket = NULL;
+}
 
+GNetworkInputStream *
+_g_network_input_stream_new (GSocket *socket)
+{
+  return G_NETWORK_INPUT_STREAM (g_object_new (G_TYPE_NETWORK_INPUT_STREAM, "socket", socket, NULL));
 }
index 9d6d42e..db44e86 100644 (file)
 #include <glib-object.h>
 #include <gio/gio.h>
 
+#include <gnio/gsocket.h>
+
 G_BEGIN_DECLS
 
-#define G_TYPE_NETWORK_INPUT_STREAM         (g_socket_get_type ())
+#define G_TYPE_NETWORK_INPUT_STREAM         (g_network_input_stream_get_type ())
 #define G_NETWORK_INPUT_STREAM(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_NETWORK_INPUT_STREAM, GNetworkInputStream))
 #define G_NETWORK_INPUT_STREAM_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_NETWORK_INPUT_STREAM, GNetworkInputStreamClass))
 #define G_IS_NETWORK_INPUT_STREAM(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_NETWORK_INPUT_STREAM))
@@ -38,10 +40,13 @@ G_BEGIN_DECLS
 
 typedef struct _GNetworkInputStream        GNetworkInputStream;
 typedef struct _GNetworkInputStreamClass   GNetworkInputStreamClass;
+typedef struct _GNetworkInputStreamPrivate GNetworkInputStreamPrivate;
 
 struct _GNetworkInputStream
 {
   GInputStream parent;
+
+  GNetworkInputStreamPrivate *priv;
 };
 
 struct _GNetworkInputStreamClass
@@ -51,7 +56,7 @@ struct _GNetworkInputStreamClass
 
 GType                 g_network_input_stream_get_type (void) G_GNUC_CONST;
 
-GNetworkInputStream * g_network_input_stream_new      (void);
+GNetworkInputStream * _g_network_input_stream_new     (GSocket *socket);
 
 G_END_DECLS
 
index c32a470..b7e9ea6 100644 (file)
 #include <glib.h>
 #include <gio/gio.h>
 
+#include "gsocket.h"
 #include "gnetworkoutputstream.h"
 
 G_DEFINE_TYPE (GNetworkOutputStream, g_network_output_stream, G_TYPE_OUTPUT_STREAM);
 
+enum
+{
+  PROP_0,
+  PROP_SOCKET
+};
+
+struct _GNetworkOutputStreamPrivate
+{
+  GSocket *socket;
+};
+
+static void
+g_network_output_stream_get_property (GObject    *object,
+                                      guint       prop_id,
+                                      GValue     *value,
+                                      GParamSpec *pspec)
+{
+  GNetworkOutputStream *stream = G_NETWORK_OUTPUT_STREAM (object);
+
+  switch (prop_id)
+    {
+      case PROP_SOCKET:
+        g_value_set_object (value, stream->priv->socket);
+        break;
+
+      default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+g_network_output_stream_set_property (GObject      *object,
+                                      guint         prop_id,
+                                      const GValue *value,
+                                      GParamSpec   *pspec)
+{
+  GNetworkOutputStream *stream = G_NETWORK_OUTPUT_STREAM (object);
+
+  switch (prop_id)
+    {
+      case PROP_SOCKET:
+        stream->priv->socket = g_value_dup_object (value);
+        break;
+
+      default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    }
+}
+
+static void
+g_network_output_stream_finalize (GObject *object)
+{
+  if (G_OBJECT_CLASS (g_network_output_stream_parent_class)->finalize)
+    (*G_OBJECT_CLASS (g_network_output_stream_parent_class)->finalize) (object);
+}
+
+static void
+g_network_output_stream_dispose (GObject *object)
+{
+  if (G_OBJECT_CLASS (g_network_output_stream_parent_class)->dispose)
+    (*G_OBJECT_CLASS (g_network_output_stream_parent_class)->dispose) (object);
+}
+
+static gssize
+g_network_output_stream_write (GOutputStream  *stream,
+                               const void     *buffer,
+                               gsize           count,
+                               GCancellable   *cancellable,
+                               GError        **error)
+{
+  GNetworkOutputStream *output_stream = G_NETWORK_OUTPUT_STREAM (stream);
+
+  return g_socket_send (output_stream->priv->socket, (const gchar *) buffer, count, error);
+}
+
 static void
 g_network_output_stream_class_init (GNetworkOutputStreamClass *klass)
 {
-  GObjectClass *gobject_class G_GNUC_UNUSED = G_OBJECT_CLASS (klass);
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  GOutputStreamClass *goutputstream_class = G_OUTPUT_STREAM_CLASS (klass);
+
+  g_type_class_add_private (klass, sizeof (GNetworkOutputStreamPrivate));
+
+  gobject_class->finalize = g_network_output_stream_finalize;
+  gobject_class->dispose = g_network_output_stream_dispose;
+  gobject_class->get_property = g_network_output_stream_get_property;
+  gobject_class->set_property = g_network_output_stream_set_property;
+
+  goutputstream_class->write_fn = g_network_output_stream_write;
+
+  g_object_class_install_property (gobject_class, PROP_SOCKET,
+                                   g_param_spec_object ("socket",
+                                                        "socket",
+                                                        "the socket that this stream wraps",
+                                                        G_TYPE_SOCKET,
+                                                        G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB | G_PARAM_STATIC_NICK));
 }
 
 static void
-g_network_output_stream_init (GNetworkOutputStream *address)
+g_network_output_stream_init (GNetworkOutputStream *stream)
 {
+  stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (stream, G_TYPE_NETWORK_OUTPUT_STREAM, GNetworkOutputStreamPrivate);
+
+  stream->priv->socket = NULL;
+}
 
+GNetworkOutputStream *
+_g_network_output_stream_new (GSocket *socket)
+{
+  return G_NETWORK_OUTPUT_STREAM (g_object_new (G_TYPE_NETWORK_OUTPUT_STREAM, "socket", socket, NULL));
 }
index 84615e8..02d2146 100644 (file)
@@ -29,7 +29,7 @@
 
 G_BEGIN_DECLS
 
-#define G_TYPE_NETWORK_OUTPUT_STREAM         (g_socket_get_type ())
+#define G_TYPE_NETWORK_OUTPUT_STREAM         (g_network_output_stream_get_type ())
 #define G_NETWORK_OUTPUT_STREAM(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_NETWORK_OUTPUT_STREAM, GNetworkOutputStream))
 #define G_NETWORK_OUTPUT_STREAM_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_NETWORK_OUTPUT_STREAM, GNetworkOutputStreamClass))
 #define G_IS_NETWORK_OUTPUT_STREAM(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_NETWORK_OUTPUT_STREAM))
@@ -38,10 +38,13 @@ G_BEGIN_DECLS
 
 typedef struct _GNetworkOutputStream        GNetworkOutputStream;
 typedef struct _GNetworkOutputStreamClass   GNetworkOutputStreamClass;
+typedef struct _GNetworkOutputStreamPrivate GNetworkOutputStreamPrivate;
 
 struct _GNetworkOutputStream
 {
   GOutputStream parent;
+
+  GNetworkOutputStreamPrivate *priv;
 };
 
 struct _GNetworkOutputStreamClass
@@ -51,7 +54,7 @@ struct _GNetworkOutputStreamClass
 
 GType                  g_network_output_stream_get_type (void) G_GNUC_CONST;
 
-GNetworkOutputStream * g_network_output_stream_new      (void);
+GNetworkOutputStream * _g_network_output_stream_new     (GSocket *socket);
 
 G_END_DECLS
 
index 3b9671e..c89d10b 100644 (file)
@@ -24,9 +24,7 @@
 #include <config.h>
 #include <glib.h>
 #include <gio/gio.h>
-#include <gnio/gnio.h>
 #include "gasynchelper.h"
-#include "gnioenumtypes.h"
 
 #include <string.h>
 #ifndef G_OS_WIN32
@@ -420,6 +418,8 @@ g_socket_set_blocking (GSocket  *socket,
     g_warning ("Error setting socket status flags: %s", g_strerror (errno));
 
   socket->priv->blocking = blocking;
+
+  g_object_notify (G_OBJECT (socket), "blocking");
 }
 
 gboolean
@@ -442,6 +442,8 @@ g_socket_set_reuse_address (GSocket  *socket,
     g_warning ("error setting reuse address: %s", g_strerror (errno));
 
   socket->priv->reuse_address = reuse;
+
+  g_object_notify (G_OBJECT (socket), "reuse-address");
 }
 
 gboolean
@@ -452,12 +454,36 @@ g_socket_get_reuse_address (GSocket *socket)
   return socket->priv->reuse_address;
 }
 
+gboolean
+g_socket_has_socket_error (GSocket  *socket,
+                           GError  **error)
+{
+  gint sockerr;
+  guint32 sockerr_size = sizeof (sockerr);
+
+  g_return_val_if_fail (G_IS_SOCKET (socket), FALSE);
+
+  if (getsockopt (socket->priv->fd, SOL_SOCKET, SO_ERROR, (gpointer) &sockerr, &sockerr_size) < 0)
+    {
+      g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno), "could not get socket error: %s", g_strerror (errno));
+      return TRUE;
+    }
+
+  if (sockerr != 0)
+    {
+      g_set_error (error, G_IO_ERROR, g_io_error_from_errno (sockerr), "error connecting: %s", g_strerror (sockerr));
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
 GSocketAddress *
 g_socket_get_local_address (GSocket  *socket,
                             GError  **error)
 {
   gchar buffer[256];
-  gsize len = 256;
+  guint32 len = 256;
 
   g_return_val_if_fail (G_IS_SOCKET (socket), NULL);
 
@@ -478,7 +504,7 @@ g_socket_get_remote_address (GSocket  *socket,
                              GError  **error)
 {
   gchar buffer[256];
-  gsize len = 256;
+  guint32 len = 256;
 
   g_return_val_if_fail (G_IS_SOCKET (socket), NULL);
 
@@ -623,7 +649,7 @@ g_socket_receive (GSocket       *socket,
 
 gssize
 g_socket_send (GSocket       *socket,
-               gchar         *buffer,
+               const gchar   *buffer,
                gsize          size,
                GError       **error)
 {
@@ -659,5 +685,5 @@ g_socket_create_source (GSocket      *socket,
 {
   g_return_val_if_fail (G_IS_SOCKET (socket) && (cancellable == NULL || G_IS_CANCELLABLE (cancellable)), NULL);
 
-  return _g_fd_source_new (socket->priv->fd, G_IO_IN | G_IO_HUP | G_IO_ERR, cancellable);
+  return _g_fd_source_new (socket->priv->fd, condition, cancellable);
 }
index 350ff8b..72b565f 100644 (file)
@@ -90,7 +90,7 @@ void             g_socket_set_reuse_address  (GSocket  *socket,
 
 gboolean         g_socket_get_reuse_address  (GSocket  *socket);
 
-gboolean         g_socket_has_error          (GSocket  *socket,
+gboolean         g_socket_has_socket_error   (GSocket  *socket,
                                               GError  **error);
 
 gboolean         g_socket_bind               (GSocket         *socket,
@@ -113,7 +113,7 @@ gssize           g_socket_receive            (GSocket       *socket,
                                               GError       **error);
 
 gssize           g_socket_send               (GSocket       *socket,
-                                              gchar         *buffer,
+                                              const gchar   *buffer,
                                               gsize          size,
                                               GError       **error);
 
index cd77127..2421108 100644 (file)
@@ -30,6 +30,7 @@
 #include "gsocketaddress.h"
 #include "ginetsocketaddress.h"
 #include "ginet4address.h"
+#include "ginet6address.h"
 
 G_DEFINE_ABSTRACT_TYPE (GSocketAddress, g_socket_address, G_TYPE_INITIALLY_UNOWNED);
 
@@ -80,7 +81,15 @@ g_socket_address_from_native (gpointer native, gsize len)
 
       return G_SOCKET_ADDRESS (g_inet_socket_address_new (G_INET_ADDRESS (g_inet4_address_from_bytes ((guint8 *) &(addr->sin_addr))), g_ntohs (addr->sin_port)));
     }
-  // TODO: handle AF_INET6 and AF_UNIX
+
+  if (family == AF_INET6)
+    {
+      struct sockaddr_in6 *addr = (struct sockaddr_in6 *) native;
+
+      return G_SOCKET_ADDRESS (g_inet_socket_address_new (G_INET_ADDRESS (g_inet6_address_from_bytes ((guint8 *) &(addr->sin6_addr))), g_ntohs (addr->sin6_port)));
+    }
+
+  // TODO: handle AF_UNIX
 
   return NULL;
 }
index 60822a3..8978897 100644 (file)
@@ -36,15 +36,19 @@ enum
   PROP_0,
   PROP_ADDRESS,
   PROP_HOSTNAME,
-  PROP_PORT
+  PROP_PORT,
+  PROP_INPUT_STREAM,
+  PROP_OUTPUT_STREAM
 };
 
 struct _GTcpClientPrivate
 {
-  GInetSocketAddress *address;
-  gchar              *hostname;
-  gushort             port;
-  GSocket            *socket;
+  GInetSocketAddress   *address;
+  gchar                *hostname;
+  gushort               port;
+  GSocket              *socket;
+  GNetworkInputStream  *input;
+  GNetworkOutputStream *output;
 };
 
 static void
@@ -83,6 +87,14 @@ g_tcp_client_get_property (GObject    *object,
         g_value_set_uint (value, client->priv->port);
         break;
 
+      case PROP_INPUT_STREAM:
+        g_value_set_object (value, g_tcp_client_get_input_stream (client));
+        break;
+
+      case PROP_OUTPUT_STREAM:
+        g_value_set_object (value, g_tcp_client_get_output_stream (client));
+        break;
+
       default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
     }
@@ -175,6 +187,20 @@ g_tcp_client_class_init (GTcpClientClass *klass)
                                                       G_MAXUSHORT,
                                                       0,
                                                       G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB | G_PARAM_STATIC_NICK));
+
+  g_object_class_install_property (gobject_class, PROP_INPUT_STREAM,
+                                   g_param_spec_object ("input-stream",
+                                                        "input stream",
+                                                        "the GNetworkInputStream for reading from this socket",
+                                                        G_TYPE_NETWORK_INPUT_STREAM,
+                                                        G_PARAM_READABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB | G_PARAM_STATIC_NICK));
+
+  g_object_class_install_property (gobject_class, PROP_OUTPUT_STREAM,
+                                   g_param_spec_object ("output-stream",
+                                                        "output stream",
+                                                        "the GNetworkOutputStream for writing to this socket",
+                                                        G_TYPE_NETWORK_OUTPUT_STREAM,
+                                                        G_PARAM_READABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB | G_PARAM_STATIC_NICK));
 }
 
 static void
@@ -186,6 +212,8 @@ g_tcp_client_init (GTcpClient *client)
   client->priv->hostname = NULL;
   client->priv->port = 0;
   client->priv->socket = NULL;
+  client->priv->input = NULL;
+  client->priv->output = NULL;
 }
 
 GTcpClient *
@@ -201,6 +229,34 @@ g_tcp_client_new_from_address (GInetSocketAddress *address)
   return G_TCP_CLIENT (g_object_new (G_TYPE_TCP_CLIENT, "address", address, NULL));
 }
 
+GNetworkInputStream *
+g_tcp_client_get_input_stream (GTcpClient *client)
+{
+  if (!client->priv->socket)
+    return NULL;
+
+  if (client->priv->input)
+    return client->priv->input;
+
+  // TODO: should we set g_object_notify here, or just create both these streams earlier?
+
+  return (client->priv->input = _g_network_input_stream_new (client->priv->socket));
+}
+
+GNetworkOutputStream *
+g_tcp_client_get_output_stream (GTcpClient *client)
+{
+  if (!client->priv->socket)
+    return NULL;
+
+  if (client->priv->output)
+    return client->priv->output;
+
+  // TODO: should we set g_object_notify here, or just create both these streams earlier?
+
+  return (client->priv->output = _g_network_output_stream_new (client->priv->socket));
+}
+
 gboolean
 g_tcp_client_connect (GTcpClient    *client,
                       GCancellable  *cancellable,
@@ -228,7 +284,7 @@ g_tcp_client_connect (GTcpClient    *client,
     }
   else
     {
-     address = g_inet_socket_address_get_address (client->priv->address);
+      address = g_inet_socket_address_get_address (client->priv->address);
     }
 
   if (G_IS_INET4_ADDRESS (address))
@@ -258,8 +314,6 @@ typedef struct {
   GCancellable        *cancellable;
   gpointer             user_data;
   GTcpClient          *client;
-  gchar                address_buffer[256];
-  gsize                address_length;
 } ConnectData;
 
 static gboolean
@@ -267,16 +321,149 @@ connect_callback (ConnectData *data,
                   GIOCondition condition,
                   gint fd)
 {
+  GTcpClient *client;
+  GSimpleAsyncResult *result;
+  GError *error = NULL;
+
+  client = data->client;
+
+  if (condition & G_IO_OUT)
+    {
+      result = g_simple_async_result_new (G_OBJECT (client), data->callback, data->user_data, g_tcp_client_connect_async);
+    }
+  else
+    {
+      if (!g_socket_has_socket_error (client->priv->socket, &error))
+        g_warning ("got G_IO_ERR but socket does not have error");
+
+      result = g_simple_async_result_new_from_error (G_OBJECT (client), data->callback, data->user_data, error);
+    }
+
+  g_simple_async_result_complete (result);
+
+  g_object_unref (result);
+
   return FALSE;
 }
 
+static void
+resolve_callback (GObject      *source,
+                  GAsyncResult *result,
+                  gpointer      user_data)
+{
+  ConnectData *data = (ConnectData *) user_data;
+  GInetAddress *address;
+  GSimpleAsyncResult *error_result;
+  GError *error = NULL;
+
+  address = g_resolver_resolve_finish (G_RESOLVER (source), result, &error);
+
+  g_object_unref (G_RESOLVER (source));
+
+  if (!address)
+    {
+      error_result = g_simple_async_result_new_from_error (G_OBJECT (data->client), data->callback, data->user_data, error);
+
+      g_simple_async_result_complete (error_result);
+
+      g_object_unref (error_result);
+    }
+  else
+    {
+      data->client->priv->address = g_inet_socket_address_new (address, data->client->priv->port);
+
+      g_object_ref_sink (data->client->priv->address);
+
+      // at this point, the address has been resolved, so connect_async again
+      g_tcp_client_connect_async (data->client, data->cancellable, data->callback, data->user_data);
+    }
+
+  g_free (data);
+}
+
 void
 g_tcp_client_connect_async (GTcpClient          *client,
                             GCancellable        *cancellable,
                             GAsyncReadyCallback  callback,
                             gpointer             user_data)
 {
+  GInetAddress *address;
+  GSimpleAsyncResult *result;
+  GSource *source;
+  ConnectData *data;
+  GError *error = NULL;
+
+  g_return_if_fail (G_IS_TCP_CLIENT (client));
+
+  if (!client->priv->address)
+    {
+      // we've been constructed with just hostname+port, resolve
+      GResolver *resolver = g_resolver_new ();
+
+      data = g_new (ConnectData, 1);
+
+      data->client = client;
+      data->callback = callback;
+      data->cancellable = cancellable;
+      data->user_data = user_data;
+
+      g_resolver_resolve_async (resolver, client->priv->hostname, cancellable, resolve_callback, data);
+
+      return;
+    }
+
+  address = g_inet_socket_address_get_address (client->priv->address);
 
+  if (G_IS_INET4_ADDRESS (address))
+    client->priv->socket = g_socket_new (G_SOCKET_DOMAIN_INET, G_SOCKET_TYPE_STREAM, NULL, &error);
+  else if (G_IS_INET6_ADDRESS (address))
+    client->priv->socket = g_socket_new (G_SOCKET_DOMAIN_INET6, G_SOCKET_TYPE_STREAM, NULL, &error);
+  else
+    {
+      g_simple_async_report_error_in_idle (G_OBJECT (client), callback, user_data, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, "unsupported address domain");
+      return;
+    }
+
+  if (!client->priv->socket)
+    {
+      g_simple_async_report_gerror_in_idle (G_OBJECT (client), callback, user_data, error);
+      return;
+    }
+
+  g_socket_set_blocking (client->priv->socket, FALSE);
+
+  if (!g_socket_connect (client->priv->socket, G_SOCKET_ADDRESS (client->priv->address), &error))
+    {
+      if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_PENDING))
+        {
+          // the connection is in progress
+          source = g_socket_create_source (client->priv->socket, G_IO_OUT | G_IO_ERR | G_IO_HUP, cancellable);
+
+          data = g_new (ConnectData, 1);
+
+          data->client = client;
+          data->callback = callback;
+          data->cancellable = cancellable;
+          data->user_data = user_data;
+
+          g_source_set_callback (source, (GSourceFunc) connect_callback, data, g_free);
+
+          g_source_attach (source, NULL);
+        }
+      else
+        {
+          g_simple_async_report_gerror_in_idle (G_OBJECT (client), callback, user_data, error);
+        }
+    }
+  else
+    {
+      // the connection is already completed
+      result = g_simple_async_result_new (G_OBJECT (client), callback, user_data, g_tcp_client_connect_async);
+
+      g_simple_async_result_complete_in_idle (result);
+
+      g_object_unref (result);
+    }
 }
 
 gboolean
index 0c2a787..24ff123 100644 (file)
@@ -104,7 +104,7 @@ int main (int argc, char *argv[])
                if (size == 0)
                        break;
 
-               g_print ("received %d bytes of data: %s\n", size, buffer);
+               g_print ("received %" G_GSSIZE_FORMAT " bytes of data: %s\n", size, buffer);
 
                if ((size = g_socket_send (new_socket, buffer, size, &error)) < 0) {
                        g_error (error->message);
index 4209e86..791748e 100644 (file)
@@ -11,9 +11,9 @@
 
 GMainLoop *loop;
 
-void print_address (GInetAddress *address, gpointer data);
+static void print_address (GInetAddress *address, gpointer data);
 
-void
+static void
 print_address (GInetAddress *address, gpointer data)
 {
        gchar *string = g_inet_address_to_string (G_INET_ADDRESS (address));
@@ -23,7 +23,7 @@ print_address (GInetAddress *address, gpointer data)
        g_free (string);
 }
 
-void
+static void
 resolve_callback (GObject *source, GAsyncResult *result, gpointer data)
 {
        GError *error = NULL;
index f13aae8..771da64 100644 (file)
@@ -3,25 +3,47 @@
 
 GMainLoop *loop;
 
-/*
-void
-accept_callback (GSocket *socket, GAsyncResult *result, gpointer data)
+static void
+connect_callback (GObject *source, GAsyncResult *result, gpointer data)
 {
+       GTcpClient *client = G_TCP_CLIENT (source);
+       GInputStream *input;
+       GOutputStream *output;
+       gchar buffer[512] = {0};
+       gssize count;
        GError *error = NULL;
 
-       if (!g_socket_connect_finish (socket, result, &error)) {
+       if (!g_tcp_client_connect_finish (client, result, &error)) {
                g_warning (error->message);
                return;
        }
 
        g_print ("successfully connected\n");
+
+       output = G_OUTPUT_STREAM (g_tcp_client_get_output_stream (client));
+
+       input = G_INPUT_STREAM (g_tcp_client_get_input_stream (client));
+
+       g_print ("writing...\n");
+
+       if ((count = g_output_stream_write (output, "GET / HTTP/1.0\r\n\r\n", 19, NULL, &error)) < 0) {
+               g_warning (error->message);
+               return;
+       }
+
+       g_print ("wrote %" G_GSSIZE_FORMAT " bytes\n", count);
+
+       if ((count = g_input_stream_read (input, buffer, 512, NULL, &error)) < 0) {
+               g_warning (error->message);
+               return;
+       }
+
+       g_print ("read %" G_GSSIZE_FORMAT " bytes: %s\n", count, buffer);
 }
-*/
 
 int main (int argc, char *argv[])
 {
        GTcpClient *client;
-       GError *error = NULL;
 
        g_thread_init (NULL);
 
@@ -29,10 +51,14 @@ int main (int argc, char *argv[])
 
        loop = g_main_loop_new (NULL, FALSE);
 
-       client = g_tcp_client_new ("localhost", 90);
+       client = g_tcp_client_new ("localhost", 31882);
 
        g_print ("connecting to www.google.com:80\n");
 
+       g_tcp_client_connect_async (client, NULL, connect_callback, NULL);
+
+       g_print ("connecting seems to have begun\n");
+/*
        if (!g_tcp_client_connect (client, NULL, &error)) {
                g_warning (error->message);
                return 1;
@@ -41,8 +67,10 @@ int main (int argc, char *argv[])
        g_print ("connected!\n");
 
        g_object_unref (G_OBJECT (client));
+*/
 
-//     g_main_loop_run (loop);
+       g_main_loop_run (loop);
 
        return 0;
 }
+