pull in gasynchelper (won't need this once gnio is merged into gio)
authorSamuel Cormier-Iijima <sciyoshi@gmail.com>
Wed, 27 Feb 2008 04:40:00 +0000 (23:40 -0500)
committerSamuel Cormier-Iijima <sciyoshi@gmail.com>
Wed, 27 Feb 2008 04:40:00 +0000 (23:40 -0500)
gnio/Makefile.am
gnio/gasynchelper.c [new file with mode: 0644]
gnio/gasynchelper.h [new file with mode: 0644]
gnio/gsocket.c
gnio/gsocket.h

index 17f5a64..e911e78 100644 (file)
@@ -37,6 +37,7 @@ libgnio_la_SOURCES =        \
        gsocket.c \
        gnetworkinputstream.c \
        gnetworkoutputstream.c \
+       gasynchelper.c \
         $(NULL)
 
 
diff --git a/gnio/gasynchelper.c b/gnio/gasynchelper.c
new file mode 100644 (file)
index 0000000..cbcecdd
--- /dev/null
@@ -0,0 +1,173 @@
+/* GIO - GLib Input, Output and Streaming Library
+ * 
+ * Copyright (C) 2006-2007 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Alexander Larsson <alexl@redhat.com>
+ */
+
+#include <config.h>
+
+#include "gasynchelper.h"
+
+/**
+ * SECTION:gasynchelper
+ * @short_description: Asynchronous Helper Functions
+ * @include: gio/gio.h
+ * @see_also: #GAsyncReady
+ * 
+ * Provides helper functions for asynchronous operations.
+ *
+ **/
+
+static void
+async_result_free (gpointer data)
+{
+  GAsyncResultData *res = data;
+
+  if (res->error)
+    g_error_free (res->error);
+
+  g_object_unref (res->async_object);
+  
+  g_free (res);
+}
+
+void
+_g_queue_async_result (GAsyncResultData *result,
+                      gpointer          async_object,
+                      GError           *error,
+                      gpointer          user_data,
+                      GSourceFunc       source_func)
+{
+  GSource *source;
+
+  g_return_if_fail (G_IS_OBJECT (async_object));
+  
+  result->async_object = g_object_ref (async_object);
+  result->user_data = user_data;
+  result->error = error;
+
+  source = g_idle_source_new ();
+  g_source_set_priority (source, G_PRIORITY_DEFAULT);
+  g_source_set_callback (source, source_func, result, async_result_free);
+  g_source_attach (source, NULL);
+  g_source_unref (source);
+}
+
+/*************************************************************************
+ *             fd source                                                 *
+ ************************************************************************/
+
+typedef struct 
+{
+  GSource source;
+  GPollFD pollfd;
+  GCancellable *cancellable;
+  gulong cancelled_tag;
+} FDSource;
+
+static gboolean 
+fd_source_prepare (GSource *source,
+                  gint    *timeout)
+{
+  FDSource *fd_source = (FDSource *)source;
+  *timeout = -1;
+  
+  return g_cancellable_is_cancelled (fd_source->cancellable);
+}
+
+static gboolean 
+fd_source_check (GSource *source)
+{
+  FDSource *fd_source = (FDSource *)source;
+
+  return
+    g_cancellable_is_cancelled  (fd_source->cancellable) ||
+    fd_source->pollfd.revents != 0;
+}
+
+static gboolean
+fd_source_dispatch (GSource     *source,
+                   GSourceFunc  callback,
+                   gpointer     user_data)
+
+{
+  GFDSourceFunc func = (GFDSourceFunc)callback;
+  FDSource *fd_source = (FDSource *)source;
+
+  g_warn_if_fail (func != NULL);
+
+  return (*func) (user_data, fd_source->pollfd.revents, fd_source->pollfd.fd);
+}
+
+static void 
+fd_source_finalize (GSource *source)
+{
+  FDSource *fd_source = (FDSource *)source;
+
+  if (fd_source->cancelled_tag)
+    g_signal_handler_disconnect (fd_source->cancellable,
+                                fd_source->cancelled_tag);
+
+  if (fd_source->cancellable)
+    g_object_unref (fd_source->cancellable);
+}
+
+static GSourceFuncs fd_source_funcs = {
+  fd_source_prepare,
+  fd_source_check,
+  fd_source_dispatch,
+  fd_source_finalize
+};
+
+/* Might be called on another thread */
+static void
+fd_source_cancelled_cb (GCancellable *cancellable,
+                       gpointer      data)
+{
+  /* Wake up the mainloop in case we're waiting on async calls with FDSource */
+  g_main_context_wakeup (NULL);
+}
+
+GSource *
+_g_fd_source_new (int           fd,
+                 gushort       events,
+                 GCancellable *cancellable)
+{
+  GSource *source;
+  FDSource *fd_source;
+
+  source = g_source_new (&fd_source_funcs, sizeof (FDSource));
+  fd_source = (FDSource *)source;
+
+  if (cancellable)
+    fd_source->cancellable = g_object_ref (cancellable);
+  
+  fd_source->pollfd.fd = fd;
+  fd_source->pollfd.events = events;
+  g_source_add_poll (source, &fd_source->pollfd);
+
+  if (cancellable)
+    fd_source->cancelled_tag =
+      g_signal_connect_data (cancellable, "cancelled",
+                            (GCallback)fd_source_cancelled_cb,
+                            NULL, NULL,
+                            0);
+  
+  return source;
+}
diff --git a/gnio/gasynchelper.h b/gnio/gasynchelper.h
new file mode 100644 (file)
index 0000000..2448bca
--- /dev/null
@@ -0,0 +1,53 @@
+/* GIO - GLib Input, Output and Streaming Library
+ * 
+ * Copyright (C) 2006-2007 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Alexander Larsson <alexl@redhat.com>
+ */
+
+#ifndef __G_ASYNC_HELPER_H__
+#define __G_ASYNC_HELPER_H__
+
+#include <glib-object.h>
+#include <gio/gio.h>
+
+G_BEGIN_DECLS
+
+typedef struct {
+  gpointer       async_object;
+  GError *       error;
+  gpointer       user_data;
+} GAsyncResultData;
+
+typedef gboolean (*GFDSourceFunc) (gpointer user_data,
+                                  GIOCondition condition,
+                                  int fd);
+
+void     _g_queue_async_result (GAsyncResultData *result,
+                               gpointer         async_object,
+                               GError          *error,
+                               gpointer         user_data,
+                               GSourceFunc      source_func);
+
+GSource *_g_fd_source_new      (int              fd,
+                               gushort          events,
+                               GCancellable    *cancellable);
+
+G_END_DECLS
+
+#endif /* __G_ASYNC_HELPER_H__ */
index fe93ca8..9a61e11 100644 (file)
@@ -24,6 +24,7 @@
 #include <config.h>
 #include <glib.h>
 #include <gio/gio.h>
+#include <gio/gasynchelper.h>
 
 #include <string.h>
 #ifndef G_OS_WIN32
@@ -142,7 +143,7 @@ g_socket_class_init (GSocketClass *klass)
                                    g_param_spec_boolean ("blocking",
                                                          "blocking",
                                                          "whether or not this socket is blocking",
-                                                         FALSE,
+                                                         TRUE,
                                                          G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB | G_PARAM_STATIC_NICK));
 }
 
@@ -197,6 +198,16 @@ g_socket_set_blocking (GSocket  *socket,
 
   if (fcntl (socket->priv->fd, F_SETFL, arg) < 0)
     g_warning ("Error setting socket status flags: %s", g_strerror (errno));
+
+  socket->priv->blocking = blocking;
+}
+
+gboolean
+g_socket_get_blocking (GSocket *socket)
+{
+  g_return_val_if_fail (G_IS_SOCKET (socket), FALSE);
+
+  return socket->priv->blocking;
 }
 
 GSocketAddress *
@@ -206,6 +217,8 @@ g_socket_get_peer_address (GSocket  *socket,
   gchar buffer[128];
   gsize len;
 
+  g_return_val_if_fail (G_IS_SOCKET (socket), NULL);
+
   if (getpeername (socket->priv->fd, (struct sockaddr *) buffer, &len) < 0)
     {
       g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno), "could not get peer address");
@@ -274,13 +287,72 @@ g_socket_accept (GSocket       *socket,
   return g_socket_new_from_fd (ret);
 }
 
+typedef struct {
+  GAsyncReadyCallback callback;
+  GCancellable *cancellable;
+  gpointer user_data;
+  GSocket *socket;
+} AcceptData;
+
+static gboolean
+accept_callback (AcceptData *data,
+                 GIOCondition condition,
+                 gint fd)
+{
+  if (condition & G_IO_IN)
+    {
+      g_print ("WE COULD ACCEPT HERE\n");
+    }
+
+  return FALSE;
+}
+
 void
 g_socket_accept_async (GSocket             *socket,
                        GCancellable        *cancellable,
-                       GAsyncReadyCallback *callback,
+                       GAsyncReadyCallback  callback,
                        gpointer             user_data)
 {
-  
+  GSource *source;
+  GSimpleAsyncResult *result;
+  AcceptData *data;
+  gint ret;
+
+  g_return_if_fail (G_IS_SOCKET (socket));
+
+  if (g_socket_get_blocking (socket))
+    g_socket_set_blocking (socket, FALSE);
+
+  if ((ret = accept (socket->priv->fd, NULL, 0)) < 0)
+    {
+      if (errno == EAGAIN)
+        {
+          source = _g_fd_source_new (socket->priv->fd, G_IO_IN | G_IO_HUP | G_IO_ERR, cancellable);
+
+          data = g_new (AcceptData, 1);
+
+          data->socket = socket;
+          data->callback = callback;
+          data->cancellable = cancellable;
+          data->user_data = user_data;
+
+          g_source_set_callback (source, (GSourceFunc) accept_callback, data, g_free);
+
+          g_source_attach (source, NULL);
+        }
+      else
+        {
+          g_simple_async_report_error_in_idle (G_OBJECT (socket), callback, user_data, G_IO_ERROR, g_io_error_from_errno (errno), "error accepting connection");
+        }
+    }
+  else
+    {
+      result = g_simple_async_result_new (G_OBJECT (socket), callback, user_data, g_socket_accept_async);
+
+      g_simple_async_result_complete_in_idle (result);
+
+      g_object_unref (result);
+    }
 }
 
 GSocket *
index 97ac900..678ef03 100644 (file)
@@ -66,6 +66,8 @@ GSocketAddress * g_socket_get_peer_address (GSocket *socket, GError **error);
 void             g_socket_set_blocking     (GSocket  *socket,
                                             gboolean  blocking);
 
+gboolean         g_socket_get_blocking     (GSocket  *socket);
+
 gboolean         g_socket_bind             (GSocket         *socket,
                                             GSocketAddress  *address,
                                             GError         **error);
@@ -91,7 +93,7 @@ GSocket *        g_socket_accept           (GSocket       *socket,
 
 void             g_socket_accept_async     (GSocket             *socket,
                                             GCancellable        *cancellable,
-                                            GAsyncReadyCallback *callback,
+                                            GAsyncReadyCallback  callback,
                                             gpointer             user_data);
 
 GSocket *        g_socket_accept_finish    (GSocket       *socket,