[glib/wip/namedpipe] Add named pipe abstraction
- From: Ignacio Casal Quinteiro <icq src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib/wip/namedpipe] Add named pipe abstraction
- Date: Tue, 23 Feb 2016 12:10:34 +0000 (UTC)
commit eee86ee9a7aa626cf436191224a0420e7ea2254b
Author: Ignacio Casal Quinteiro <icq gnome org>
Date: Mon Feb 22 12:00:17 2016 +0100
Add named pipe abstraction
https://bugzilla.gnome.org/show_bug.cgi?id=745410
gio/gwin32namedpipe.c | 330 ++++++++++++++++++++++++
gio/gwin32namedpipe.h | 65 +++++
gio/gwin32namedpipelistener.c | 554 +++++++++++++++++++++++++++++++++++++++++
gio/gwin32namedpipelistener.h | 70 +++++
4 files changed, 1019 insertions(+), 0 deletions(-)
---
diff --git a/gio/gwin32namedpipe.c b/gio/gwin32namedpipe.c
new file mode 100644
index 0000000..bbcda3b
--- /dev/null
+++ b/gio/gwin32namedpipe.c
@@ -0,0 +1,330 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright (C) 2011 Red Hat, Inc.
+ * Copyright (C) 2016 NICE s.r.l.
+ *
+ * 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.1 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include "gwin32namedpipe.h"
+
+#include <windows.h>
+
+#define DEFAULT_PIPE_BUF_SIZE 4096
+
+struct _GWin32NamedPipePrivate
+{
+ gchar *name;
+ gchar *namew;
+ HANDLE handle;
+};
+
+enum
+{
+ PROP_0,
+ PROP_NAME,
+ PROP_HANDLE,
+ LAST_PROP
+};
+
+static GParamSpec *props[LAST_PROP];
+
+static void g_win32_named_pipe_initable_iface_init (GInitableIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (GWin32NamedPipe, g_win32_named_pipe, G_TYPE_OBJECT,
+ G_ADD_PRIVATE (GWin32NamedPipe)
+ G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
+ g_win32_named_pipe_initable_iface_init))
+
+static void
+g_win32_named_pipe_finalize (GObject *object)
+{
+ GWin32NamedPipe *np = G_WIN32_NAMED_PIPE (object);
+ GWin32NamedPipePrivate *priv;
+
+ priv = g_win32_named_pipe_get_instance_private (np);
+
+ g_free (priv->name);
+ g_free (priv->namew);
+
+ if (priv->handle != NULL)
+ CloseHandle (priv->handle);
+
+ G_OBJECT_CLASS (g_win32_named_pipe_parent_class)->finalize (object);
+}
+
+static void
+g_win32_named_pipe_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GWin32NamedPipe *np = G_WIN32_NAMED_PIPE (object);
+ GWin32NamedPipePrivate *priv;
+
+ priv = g_win32_named_pipe_get_instance_private (np);
+
+ switch (prop_id)
+ {
+ case PROP_NAME:
+ g_value_set_string (value, priv->name);
+ break;
+ case PROP_HANDLE:
+ g_value_set_pointer (value, priv->handle);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+g_win32_named_pipe_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GWin32NamedPipe *np = G_WIN32_NAMED_PIPE (object);
+ GWin32NamedPipePrivate *priv;
+
+ priv = g_win32_named_pipe_get_instance_private (np);
+
+ switch (prop_id)
+ {
+ case PROP_NAME:
+ priv->name = g_value_dup_string (value);
+ priv->namew = g_utf8_to_utf16 (priv->name, -1, NULL, NULL, NULL);
+ break;
+ case PROP_HANDLE:
+ priv->handle = g_value_get_pointer (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+g_win32_named_pipe_class_init (GWin32NamedPipeClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->finalize = g_win32_named_pipe_finalize;
+ gobject_class->set_property = g_win32_named_pipe_set_property;
+ gobject_class->get_property = g_win32_named_pipe_get_property;
+
+ props[PROP_NAME] =
+ g_param_spec_string ("name",
+ P_("Pipe Name"),
+ P_("The named pipe name"),
+ NULL,
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
+
+ props[PROP_HANDLE] =
+ g_param_spec_pointer ("handle",
+ P_("Pipe handle"),
+ P_("The pipe handle"),
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties (object_class, LAST_PROP, props);
+}
+
+static void
+g_win32_named_pipe_init (GWin32NamedPipe *np)
+{
+}
+
+static gboolean
+g_win32_named_pipe_initable_init (GInitable *initable,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GWin32NamedPipe *np;
+ GWin32NamedPipePrivate *priv;
+
+ g_return_val_if_fail (G_IS_WIN32_NAMED_PIPE (initable), FALSE);
+
+ np = G_WIN32_NAMED_PIPE (initable);
+ priv = g_win32_named_pipe_get_instance_private (np);
+
+ if (cancellable != NULL)
+ {
+ g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
+ "Cancellable initialization not supported");
+ return FALSE;
+ }
+
+ if (priv->handle == NULL)
+ {
+ priv->handle = CreateWin32NamedPipeW (priv->namew,
+ PIPE_ACCESS_DUPLEX |
+ FILE_FLAG_OVERLAPPED,
+ PIPE_TYPE_BYTE |
+ PIPE_READMODE_BYTE |
+ PIPE_WAIT,
+ PIPE_UNLIMITED_INSTANCES,
+ DEFAULT_PIPE_BUF_SIZE,
+ DEFAULT_PIPE_BUF_SIZE,
+ 0, NULL);
+
+ if (priv->handle == INVALID_HANDLE_VALUE)
+ {
+ int errsv = GetLastError ();
+ gchar *emsg = g_win32_error_message (errsv);
+
+ g_set_error (error,
+ G_IO_ERROR,
+ g_io_error_from_win32_error (errsv),
+ _("Error creating named pipe: %s"),
+ emsg);
+
+ g_free (emsg);
+ return FALSE;
+ }
+ }
+ else
+ {
+ /* TODO: find a way to ensure user provided handle is a named
+ * pipe, in overlapped mode
+ */
+ if (priv->handle == INVALID_HANDLE_VALUE)
+ {
+ g_set_error_literal (error,
+ G_IO_ERROR,
+ G_IO_ERROR_FAILED,
+ _("Specified invalid named pipe handle"));
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+static void
+g_win32_named_pipe_initable_iface_init (GInitableIface *iface)
+{
+ iface->init = g_win32_named_pipe_initable_init;
+}
+
+/**
+ * g_win32_named_pipe_new:
+ * @name: the name of the pipe.
+ * @error: a %GError location to store the error occurring, or NULL to ignore.
+ *
+ * Gets a newly-allocated %GWin32NamedPipe.
+ *
+ * Returns: (transfer full): a newly-allocated %GWin32NamedPipe.
+ *
+ * Since: 2.48
+ */
+GWin32NamedPipe *
+g_win32_named_pipe_new (const gchar *name,
+ GError **error)
+{
+ return g_initable_new (G_TYPE_WIN32_NAMED_PIPE,
+ NULL, error,
+ "name", name,
+ NULL);
+}
+
+/**
+ * g_win32_named_pipe_get_name:
+ * @named_pipe: a #GWin32NamedPipe.
+ *
+ * Gets the name of the named pipe.
+ *
+ * Returns: (transfer none): the name of the named pipe.
+ *
+ * Since: 2.48
+ */
+const gchar *
+g_win32_named_pipe_get_name (GWin32NamedPipe *named_pipe)
+{
+ GWin32NamedPipePrivate *priv;
+
+ g_return_val_if_fail (G_IS_WIN32_NAMED_PIPE (named_pipe), NULL);
+
+ priv = g_win32_named_pipe_get_instance_private (named_pipe);
+
+ return priv->name;
+}
+
+/**
+ * g_win32_named_pipe_get_handle:
+ * @named_pipe: a #GWin32NamedPipe.
+ *
+ * Gets the handle to the named pipe.
+ *
+ * Returns: (transfer none): the handle to the named pipe.
+ *
+ * Since: 2.48
+ */
+void *
+g_win32_named_pipe_get_handle (GWin32NamedPipe *named_pipe)
+{
+ GWin32NamedPipePrivate *priv;
+
+ g_return_val_if_fail (G_IS_WIN32_NAMED_PIPE (named_pipe), NULL);
+
+ priv = g_win32_named_pipe_get_instance_private (named_pipe);
+
+ return priv->handle;
+}
+
+/**
+ * g_win32_named_pipe_close:
+ * @named_pipe: a %GWin32NamedPipe.
+ * @error: a %GError location to store the error occurring, or NULL to ignore.
+ *
+ * Closes the underlying handle. Note, once the pipe is closed it should not
+ * be used anymore.
+ *
+ * Returns: %FALSE in case an error happened when closing the pipe.
+ *
+ * Since: 2.48
+ */
+gboolean
+g_win32_named_pipe_close (GWin32NamedPipe *named_pipe,
+ GError **error)
+{
+ GWin32NamedPipePrivate *priv;
+ BOOL res;
+
+ g_return_val_if_fail (G_IS_WIN32_NAMED_PIPE (named_pipe), FALSE);
+
+ priv = g_win32_named_pipe_get_instance_private (named_pipe);
+
+ res = CloseHandle (priv->handle);
+ priv->handle = NULL;
+
+ if (!res)
+ {
+ int errsv = GetLastError ();
+ gchar *emsg = g_win32_error_message (errsv);
+
+ g_set_error (error, G_IO_ERROR,
+ g_io_error_from_win32_error (errsv),
+ _("Error closing named pipe: %s"),
+ emsg);
+ g_free (emsg);
+
+ return FALSE;
+ }
+
+ return TRUE;
+}
diff --git a/gio/gwin32namedpipe.h b/gio/gwin32namedpipe.h
new file mode 100644
index 0000000..ac48a41
--- /dev/null
+++ b/gio/gwin32namedpipe.h
@@ -0,0 +1,65 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright (C) 2011 Red Hat, Inc.
+ * Copyright (C) 2016 NICE s.r.l.
+ *
+ * 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.1 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __G_WIN32_NAMED_PIPE_H__
+#define __G_WIN32_NAMED_PIPE_H__
+
+#if !defined (__GIO_GIO_H_INSIDE__) && !defined (GIO_COMPILATION)
+#error "Only <gio/gio.h> can be included directly."
+#endif
+
+#include <gio/giotypes.h>
+
+G_BEGIN_DECLS
+
+#define G_TYPE_WIN32_NAMED_PIPE (g_win32_named_pipe_get_type ())
+#define G_WIN32_NAMED_PIPE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_WIN32_NAMED_PIPE,
GWin32NamedPipe))
+#define G_WIN32_NAMED_PIPE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), G_TYPE_WIN32_NAMED_PIPE,
GWin32NamedPipeClass))
+#define G_IS_WIN32_NAMED_PIPE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_WIN32_NAMED_PIPE))
+#define G_IS_WIN32_NAMED_PIPE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_WIN32_NAMED_PIPE))
+#define G_WIN32_NAMED_PIPE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_WIN32_NAMED_PIPE,
GWin32NamedPipeClass))
+
+typedef struct _GWin32NamedPipe GWin32NamedPipe;
+typedef struct _GWin32NamedPipeClass GWin32NamedPipeClass;
+
+struct _GWin32NamedPipeClass
+{
+ GObjectClass parent_class;
+};
+
+struct _GWin32NamedPipe
+{
+ GObject parent_instance;
+};
+
+GType g_win32_named_pipe_get_type (void) G_GNUC_CONST;
+
+GWin32NamedPipe *g_win32_named_pipe_new (const gchar *name,
+ GError **error);
+
+const gchar *g_win32_named_pipe_get_name (GWin32NamedPipe *named_pipe);
+
+void *g_win32_named_pipe_get_handle (GWin32NamedPipe *named_pipe);
+
+gboolean g_win32_named_pipe_close (GWin32NamedPipe *named_pipe,
+ GError **error);
+
+G_END_DECLS
+
+#endif /* __G_WIN32_NAMED_PIPE_H__ */
diff --git a/gio/gwin32namedpipelistener.c b/gio/gwin32namedpipelistener.c
new file mode 100644
index 0000000..9659811
--- /dev/null
+++ b/gio/gwin32namedpipelistener.c
@@ -0,0 +1,554 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright (C) 2011 Red Hat, Inc.
+ * Copyright (C) 2016 NICE s.r.l.
+ *
+ * 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.1 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include "gwin32namedpipelistener.h"
+
+#include <windows.h>
+
+struct _GWin32NamedPipeListenerPrivate
+{
+ GPtrArray *named_pipes;
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE (GWin32NamedPipeListener, g_win32_named_pipe_listener, G_TYPE_OBJECT)
+
+static GQuark source_quark = 0;
+
+typedef struct {
+ GSource source;
+ GPollFD pollfd;
+} GWin32HandleSource;
+
+static gboolean
+g_win32_handle_source_prepare (GSource *source,
+ gint *timeout)
+{
+ *timeout = -1;
+ return FALSE;
+}
+
+static gboolean
+g_win32_handle_source_check (GSource *source)
+{
+ GWin32HandleSource *hsource = (GWin32HandleSource *)source;
+
+ return hsource->pollfd.revents;
+}
+
+static gboolean
+g_win32_handle_source_dispatch (GSource *source,
+ GSourceFunc callback,
+ gpointer user_data)
+{
+ return (*callback) (user_data);
+}
+
+static void
+g_win32_handle_source_finalize (GSource *source)
+{
+}
+
+GSourceFuncs g_win32_handle_source_funcs = {
+ g_win32_handle_source_prepare,
+ g_win32_handle_source_check,
+ g_win32_handle_source_dispatch,
+ g_win32_handle_source_finalize
+};
+
+static GSource *
+g_win32_handle_create_source (HANDLE handle,
+ GCancellable *cancellable)
+{
+ GWin32HandleSource *hsource;
+ GSource *source;
+
+ source = g_source_new (&g_win32_handle_source_funcs, sizeof (GWin32HandleSource));
+ hsource = (GWin32HandleSource *)source;
+ g_source_set_name (source, "GWin32Handle");
+
+ if (cancellable)
+ {
+ GSource *cancellable_source;
+
+ cancellable_source = g_cancellable_source_new (cancellable);
+ g_source_add_child_source (source, cancellable_source);
+ g_source_set_dummy_callback (cancellable_source);
+ g_source_unref (cancellable_source);
+ }
+
+ hsource->pollfd.fd = (gint)handle;
+ hsource->pollfd.events = G_IO_IN;
+ hsource->pollfd.revents = 0;
+ g_source_add_poll (source, &hsource->pollfd);
+
+ return source;
+}
+
+static void
+g_win32_named_pipe_listener_finalize (GObject *object)
+{
+ GWin32NamedPipeListener *listener = G_WIN32_NAMED_PIPE_LISTENER (object);
+ GWin32NamedPipeListenerPrivate *priv;
+
+ priv = g_win32_named_pipe_listener_get_instance_private (listener);
+
+ g_ptr_array_free (priv->named_pipes, TRUE);
+
+ G_OBJECT_CLASS (g_win32_named_pipe_listener_parent_class)->finalize (object);
+}
+
+static void
+g_win32_named_pipe_listener_class_init (GWin32NamedPipeListenerClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->finalize = g_win32_named_pipe_listener_finalize;
+
+ source_quark = g_quark_from_static_string ("g-win32-named-pipe-listener-source");
+}
+
+static void
+g_win32_named_pipe_listener_init (GWin32NamedPipeListener *listener)
+{
+ GWin32NamedPipeListenerPrivate *priv;
+
+ priv = g_win32_named_pipe_listener_get_instance_private (listener);
+
+ priv->named_pipes = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
+}
+
+/**
+ * g_win32_named_pipe_listener_new:
+ *
+ * Creates a new #GWin32NamedPipeListener.
+ *
+ * Returns: (transfer full): a new #GWin32NamedPipeListener.
+ *
+ * Since: 2.48
+ */
+GWin32NamedPipeListener *
+g_win32_named_pipe_listener_new (void)
+{
+ return g_object_new (G_TYPE_WIN32_NAMED_PIPE_LISTENER, NULL);
+}
+
+/**
+ * g_win32_named_pipe_listener_add_named_pipe:
+ * @listener: a #GWin32NamedPipeListener.
+ * @named_pipe: a #GWin32NamedPipe.
+ * @source_object: (allow-none): Optional #GObject identifying this source
+ * @error: #GError for error reporting, or %NULL to ignore.
+ *
+ * Adds @named_pipe to the set of named pipes that we try to accept clients
+ * from.
+ *
+ * @source_object will be passed out in the various calls
+ * to accept to identify this particular source, which is
+ * useful if you're listening on multiple pipes and do
+ * different things depending on what pipe is connected to.
+ *
+ * Returns: %TRUE on success, %FALSE on error.
+ *
+ * Since: 2.48
+ */
+gboolean
+g_win32_named_pipe_listener_add_named_pipe (GWin32NamedPipeListener *listener,
+ GWin32NamedPipe *named_pipe,
+ GObject *source_object,
+ GError **error)
+{
+ GWin32NamedPipeListenerPrivate *priv;
+
+ g_return_if_fail (G_IS_WIN32_NAMED_PIPE_LISTENER (listener));
+ g_return_if_fail (G_IS_WIN32_NAMED_PIPE (named_pipe));
+
+ priv = g_win32_named_pipe_listener_get_instance_private (listener);
+
+ if (source_object)
+ g_object_set_qdata_full (G_OBJECT (named_pipe), source_quark,
+ g_object_ref (source_object), g_object_unref);
+
+ g_ptr_array_add (priv->named_pipes, g_object_ref (named_pipe));
+}
+
+static GIOStream *
+io_stream_new_from_named_pipe (GWin32NamedPipe *named_pipe)
+{
+ GIOStream *io_stream;
+ GInputStream *in;
+ GOutputStream *out;
+ void *handle;
+
+ handle = g_win32_named_pipe_get_handle (named_pipe);
+ in = g_win32_input_stream_new (named_pipe, FALSE);
+ out = g_win32_output_stream_new (named_pipe, FALSE);
+
+ io_stream = g_simple_io_stream_new (in, out);
+ g_object_unref (in);
+ g_object_unref (out);
+
+ return io_stream;
+}
+
+static void
+return_io_stream_from_named_pipe (GTask *task,
+ GWin32NamedPipe *np)
+{
+ GIOStream *io_stream;
+ GObject *source_object;
+
+ source_object = g_object_get_qdata (G_OBJECT (np), source_quark);
+ if (source_object)
+ g_object_set_qdata_full (G_OBJECT (task),
+ source_quark,
+ g_object_ref (source_object), g_object_unref);
+
+ io_stream = io_stream_new_from_handle (np);
+ g_task_return_pointer (c->task, io_stream, g_object_unref);
+}
+
+typedef struct {
+ GSource *source;
+ GTask *task;
+ GWin32NamedPipe *np;
+ OVERLAPPED overlapped;
+} ConnectData;
+
+static gboolean
+connect_ready (gpointer user_data)
+{
+ ConnectData *c = user_data;
+ gulong cbret;
+
+ /* Now complete the result (assuming it wasn't already completed) */
+ g_return_val_if_fail (c->task != NULL, FALSE);
+
+ if (GetOverlappedResult (c->np, &c->overlapped, &cbret, FALSE))
+ {
+ int errsv = GetLastError ();
+ gchar *emsg = g_win32_error_message (errsv);
+
+ g_task_return_new_error (c->task,
+ G_IO_ERROR,
+ G_IO_ERROR_INVALID_ARGUMENT,
+ _("There was an error querying the named pipe: %s"),
+ emsg);
+ g_free (emsg);
+ }
+ else
+ {
+ return_io_stream_from_named_pipe (c->task, c->np);
+ }
+
+ g_object_unref (c->task);
+
+ return FALSE;
+}
+
+static void
+connect_data_free (gpointer data)
+{
+ ConnectData *c = data;
+
+ if (c->source)
+ {
+ if (!g_source_is_destroyed (c->source))
+ g_source_destroy (c->source);
+ g_source_unref (c->source);
+ c->source = NULL;
+ }
+
+ if (c->overlapped.hEvent != NULL)
+ {
+ CloseHandle (c->overlapped.hEvent);
+ c->overlapped.hEvent = NULL;
+ }
+
+ g_clear_object (&c->np);
+
+ g_free (c);
+}
+
+static void
+add_sources (GWin32NamedPipeListener *listener,
+ GSourceFunc callback,
+ GTask *task,
+ GCancellable *cancellable,
+ GMainContext *context,
+ GPtrArray *sources)
+{
+ GWin32NamedPipeListenerPrivate *priv;
+ GWin32NamedPipe *named_pipe;
+ GSource *source;
+ int i;
+
+ priv = g_win32_named_pipe_listener_get_instance_private (listener);
+
+ sources = NULL;
+ for (i = 0; i < priv->named_pipes->len; i++)
+ {
+ ConnectData *c;
+ OVERLAPPED overlapped;
+
+ named_pipe = priv->named_pipes->pdata[i];
+
+ c = g_new0 (ConnectData, 1);
+ c->np = g_object_ref (named_pipe);
+ c->task = task;
+ c->overlapped.hEvent = CreateEvent (NULL, /* default security attribute */
+ TRUE, /* manual-reset event */
+ TRUE, /* initial state = signaled */
+ NULL); /* unnamed event object */
+
+ ConnectNamedPipe (g_win32_named_pipe_get_handle (named_pipe), &c->overlapped);
+
+ switch (GetLastError ())
+ {
+ case ERROR_SUCCESS:
+ case ERROR_IO_PENDING:
+ break;
+ case ERROR_PIPE_CONNECTED:
+ return_io_stream_from_named_pipe (task, named_pipe);
+ connect_data_free (c);
+ return;
+ default:
+ {
+ int errsv = GetLastError ();
+ gchar *emsg = g_win32_error_message (errsv);
+
+ g_task_return_new_error (G_OBJECT (listener),
+ callback, user_data,
+ G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
+ _("Failed to connect named pipe '%s': %s"),
+ g_win32_named_pipe_get_name (named_pipe),
+ emsg);
+ g_free (emsg);
+ connect_data_free (c);
+ g_object_unref (task);
+ return;
+ }
+ }
+
+ source = g_win32_handle_create_source (c->overlapped.hEvent,
+ cancellable);
+ c->source = source;
+
+ g_source_set_callback (source,
+ (GSourceFunc) callback,
+ c, connect_data_free);
+ g_source_attach (source, context);
+
+ g_ptr_array_add (sources, source);
+ }
+}
+
+static void
+free_source (gpointer user_data)
+{
+ GSource *source = user_data;
+
+ g_source_destroy (source);
+ g_source_unref (source);
+}
+
+static void
+free_sources (gpointer user_data)
+{
+ GPtrArray *sources = user_data;
+
+ g_ptr_array_free (sources, TRUE);
+}
+
+struct AcceptData {
+ GMainLoop *loop;
+ GSocket *socket;
+};
+
+static gboolean
+accept_callback (GSocket *socket,
+ GIOCondition condition,
+ gpointer user_data)
+{
+ struct AcceptData *data = user_data;
+
+ data->socket = socket;
+ g_main_loop_quit (data->loop);
+
+ return TRUE;
+}
+
+/**
+ * g_win32_named_pipe_listener_accept:
+ * @listener: a #GWin32NamedPipeListener
+ * @source_object: (out) (transfer none) (allow-none): location where #GObject pointer will be stored, or
%NULL.
+ * @cancellable: (allow-none): optional #GCancellable object, %NULL to ignore.
+ * @error: #GError for error reporting, or %NULL to ignore.
+ *
+ * Blocks waiting for a client to connect to any of the named pipes added
+ * to the listener. Returns the #GIOStream that was accepted.
+ *
+ * If @source_object is not %NULL it will be filled out with the source
+ * object specified when the corresponding socket or address was added
+ * to the listener.
+ *
+ * If @cancellable is not %NULL, then the operation can be cancelled by
+ * triggering the cancellable object from another thread. If the operation
+ * was cancelled, the error %G_IO_ERROR_CANCELLED will be returned.
+ *
+ * Returns: (transfer full): a #GIOStream on success, %NULL on error.
+ *
+ * Since: 2.48
+ */
+GIOStream *
+g_win32_named_pipe_listener_accept (GWin32NamedPipeListener *listener,
+ GObject **source_object,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GWin32NamedPipeListenerPrivate *priv;
+ GWin32NamedPipe *named_pipe;
+ GIOStream *io_stream = NULL;
+
+ g_return_val_if_fail (G_IS_WIN32_NAMED_PIPE_LISTENER (listener), NULL);
+
+ priv = g_win32_named_pipe_listener_get_instance_private (listener);
+
+ if (priv->named_pipes->len == 1)
+ {
+ OVERLAPPED overlapped;
+ gboolean success = FALSE;
+
+ named_pipe = priv->named_pipes->pdata[0];
+ overlapped.hEvent = CreateEvent (NULL, TRUE, TRUE, NULL);
+
+ if (!ConnectNamedPipe (g_win32_named_pipe_get_handle (named_pipe), &overlapped))
+ {
+ int err = GetLastError ();
+
+ if (err == ERROR_IO_PENDING)
+ {
+ success = WaitForSingleObject (overlapped.hEvent, INFINITE) == WAIT_OBJECT_0;
+ }
+ else if (err = ERROR_PIPE_CONNECTED)
+ success = TRUE;
+ }
+ else
+ sucess = TRUE;
+
+ CloseHandle (overlapped.hEvent);
+
+ if (success)
+ io_stream = io_stream_new_from_named_pipe (named_pipe);
+ }
+ else
+ {
+ GList *sources;
+ struct AcceptData data;
+ GMainLoop *loop;
+
+ if (priv->main_context == NULL)
+ priv->main_context = g_main_context_new ();
+
+ loop = g_main_loop_new (priv->main_context, FALSE);
+ data.loop = loop;
+
+ sources = g_ptr_array_new_with_free_func (free_source);
+ add_sources (listener,
+ accept_callback,
+ &data,
+ cancellable,
+ priv->main_context,
+ sources);
+ g_main_loop_run (loop);
+ named_pipe = data.socket;
+ free_sources (sources);
+ g_main_loop_unref (loop);
+ }
+
+ if (source_object)
+ *source_object = g_object_get_qdata (G_OBJECT (named_pipe), source_quark);
+
+ return io_stream;
+}
+
+/**
+ * g_win32_named_pipe_listener_accept_async:
+ * @listener: a #GWin32NamedPipeListener
+ * @cancellable: (allow-none): a #GCancellable, or %NULL
+ * @callback: (scope async): a #GAsyncReadyCallback
+ * @user_data: (closure): user data for the callback
+ *
+ * This is the asynchronous version of g_win32_named_pipe_listener_accept().
+ *
+ * When the operation is finished @callback will be
+ * called. You can then call g_win32_named_pipe_listener_accept_finish()
+ * to get the result of the operation.
+ *
+ * Since: 2.48
+ */
+void
+g_win32_named_pipe_listener_accept_async (GWin32NamedPipeListener *listener,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GTask *task;
+ GPtrArray *sources;
+
+ task = g_task_new (listener, cancellable, callback, user_data);
+
+ sources = g_ptr_array_new_with_free_func (free_source);
+ add_sources (listener,
+ connect_ready,
+ task,
+ cancellable,
+ g_main_context_get_thread_default (),
+ sources);
+ g_task_set_task_data (task, sources, free_sources);
+}
+
+/**
+ * g_win32_named_pipe_listener_accept_finish:
+ * @listener: a #GWin32NamedPipeListener.
+ * @result: a #GAsyncResult.
+ * @source_object: (out) (transfer none) (allow-none): Optional #GObject identifying this source
+ * @error: a #GError location to store the error occurring, or %NULL to ignore.
+ *
+ * Finishes an async accept operation. See g_win32_named_pipe_listener_accept_async()
+ *
+ * Returns: (transfer full): a #GIOStream on success, %NULL on error.
+ *
+ * Since: 2.48
+ */
+GIOStream *
+g_win32_named_pipe_listener_accept_finish (GWin32NamedPipeListener *listener,
+ GAsyncResult *result,
+ GObject **source_object,
+ GError **error)
+{
+ g_return_val_if_fail (G_IS_WIN32_NAMED_PIPE_LISTENER (listener), NULL);
+ g_return_val_if_fail (g_task_is_valid (result, listener), NULL);
+
+ if (source_object)
+ *source_object = g_object_get_qdata (G_OBJECT (result), source_quark);
+
+ return g_task_propagate_pointer (G_TASK (result), error);
+}
diff --git a/gio/gwin32namedpipelistener.h b/gio/gwin32namedpipelistener.h
new file mode 100644
index 0000000..39f71b9
--- /dev/null
+++ b/gio/gwin32namedpipelistener.h
@@ -0,0 +1,70 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright (C) 2011 Red Hat, Inc.
+ * Copyright (C) 2016 NICE s.r.l.
+ *
+ * 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.1 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __G_WIN32_NAMED_PIPE_LISTENER_H__
+#define __G_WIN32_NAMED_PIPE_LISTENER_H__
+
+#if !defined (__GIO_GIO_H_INSIDE__) && !defined (GIO_COMPILATION)
+#error "Only <gio/gio.h> can be included directly."
+#endif
+
+#include <gio/giotypes.h>
+
+G_BEGIN_DECLS
+
+#define G_TYPE_WIN32_NAMED_PIPE_LISTENER (g_win32_named_pipe_listener_get_type ())
+#define G_WIN32_NAMED_PIPE_LISTENER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o),
G_TYPE_WIN32_NAMED_PIPE_LISTENER, GWin32NamedPipeListener))
+#define G_WIN32_NAMED_PIPE_LISTENER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k),
G_TYPE_WIN32_NAMED_PIPE_LISTENER, GWin32NamedPipeListenerClass))
+#define G_IS_WIN32_NAMED_PIPE_LISTENER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o),
G_TYPE_WIN32_NAMED_PIPE_LISTENER))
+#define G_IS_WIN32_NAMED_PIPE_LISTENER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k),
G_TYPE_WIN32_NAMED_PIPE_LISTENER))
+#define G_WIN32_NAMED_PIPE_LISTENER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o),
G_TYPE_WIN32_NAMED_PIPE_LISTENER, GWin32NamedPipeListenerClass))
+
+typedef struct _GWin32NamedPipeListener GWin32NamedPipeListener;
+typedef struct _GWin32NamedPipeListenerClass GWin32NamedPipeListenerClass;
+
+struct _GWin32NamedPipeListenerClass
+{
+ GObjectClass parent_class;
+};
+
+struct _GWin32NamedPipeListener
+{
+ GObject parent_instance;
+};
+
+GType g_win32_named_pipe_listener_get_type (void) G_GNUC_CONST;
+
+GWin32NamedPipeListener *g_win32_named_pipe_listener_new (void);
+
+void g_win32_named_pipe_listener_add_named_pipe (GWin32NamedPipeListener *listener,
+ GWin32NamedPipe
*win32_namedpipe);
+
+void g_win32_named_pipe_listener_accept_async (GWin32NamedPipeListener *listener,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+GIOStream *g_win32_named_pipe_listener_accept_finish (GWin32NamedPipeListener *listener,
+ GAsyncResult *result,
+ GObject **source_object,
+ GError **error);
+
+G_END_DECLS
+
+#endif /* __G_WIN32_NAMED_PIPE_LISTENER_H__ */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]