From ce2943ed9b80f86ca8d49dea8207634785eef69c Mon Sep 17 00:00:00 2001 From: Samuel Cormier-Iijima Date: Tue, 26 Feb 2008 23:40:00 -0500 Subject: [PATCH] pull in gasynchelper (won't need this once gnio is merged into gio) --- gnio/Makefile.am | 1 + gnio/gasynchelper.c | 173 ++++++++++++++++++++++++++++++++++++++++++++ gnio/gasynchelper.h | 53 ++++++++++++++ gnio/gsocket.c | 78 +++++++++++++++++++- gnio/gsocket.h | 4 +- 5 files changed, 305 insertions(+), 4 deletions(-) create mode 100644 gnio/gasynchelper.c create mode 100644 gnio/gasynchelper.h diff --git a/gnio/Makefile.am b/gnio/Makefile.am index 17f5a64..e911e78 100644 --- a/gnio/Makefile.am +++ b/gnio/Makefile.am @@ -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 index 0000000..cbcecdd --- /dev/null +++ b/gnio/gasynchelper.c @@ -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 + */ + +#include + +#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 index 0000000..2448bca --- /dev/null +++ b/gnio/gasynchelper.h @@ -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 + */ + +#ifndef __G_ASYNC_HELPER_H__ +#define __G_ASYNC_HELPER_H__ + +#include +#include + +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__ */ diff --git a/gnio/gsocket.c b/gnio/gsocket.c index fe93ca8..9a61e11 100644 --- a/gnio/gsocket.c +++ b/gnio/gsocket.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #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 * diff --git a/gnio/gsocket.h b/gnio/gsocket.h index 97ac900..678ef03 100644 --- a/gnio/gsocket.h +++ b/gnio/gsocket.h @@ -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, -- 2.20.1