[glib/wip/namedpipe] Add named pipe high level api
- From: Ignacio Casal Quinteiro <icq src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib/wip/namedpipe] Add named pipe high level api
- Date: Wed, 24 Feb 2016 16:00:03 +0000 (UTC)
commit 3059c745fa542ba05d70aa7acd827eb55e9cde02
Author: Ignacio Casal Quinteiro <icq gnome org>
Date: Mon Feb 22 12:00:17 2016 +0100
Add named pipe high level api
It provides a GSocketListener/Client like api using named pipes
https://bugzilla.gnome.org/show_bug.cgi?id=745410
docs/reference/gio/gio-docs.xml | 6 +
docs/reference/gio/gio-sections.txt | 54 ++++
gio/Makefile.am | 9 +
gio/gasynchelper.c | 98 ++++++
gio/gasynchelper.h | 7 +
gio/giotypes.h | 4 +
gio/gwin32namedpipeclient.c | 304 +++++++++++++++++++
gio/gwin32namedpipeclient.h | 80 +++++
gio/gwin32namedpipeconnection.c | 234 +++++++++++++++
gio/gwin32namedpipeconnection.h | 45 +++
gio/gwin32namedpipelistener.c | 557 +++++++++++++++++++++++++++++++++++
gio/gwin32namedpipelistener.h | 87 ++++++
gio/tests/Makefile.am | 2 +-
gio/tests/win32-named-pipe.c | 58 ++++
14 files changed, 1544 insertions(+), 1 deletions(-)
---
diff --git a/docs/reference/gio/gio-docs.xml b/docs/reference/gio/gio-docs.xml
index a2e62e0..e014938 100644
--- a/docs/reference/gio/gio-docs.xml
+++ b/docs/reference/gio/gio-docs.xml
@@ -145,6 +145,12 @@
<xi:include href="xml/gthreadedsocketservice.xml"/>
<xi:include href="xml/gnetworkmonitor.xml"/>
</chapter>
+ <chapter id="highlevel-named-pipes">
+ <title>High-level named pipes functionality</title>
+ <xi:include href="xml/gwin32namedpipeclient.xml"/>
+ <xi:include href="xml/gwin32namedpipelistener.xml"/>
+ <xi:include href="xml/gwin32namedpipeconnection.xml"/>
+ </chapter>
<chapter id="tls">
<title>TLS (SSL) support</title>
<xi:include href="xml/gtls.xml"/>
diff --git a/docs/reference/gio/gio-sections.txt b/docs/reference/gio/gio-sections.txt
index 6010a0f..d3e1a39 100644
--- a/docs/reference/gio/gio-sections.txt
+++ b/docs/reference/gio/gio-sections.txt
@@ -2337,6 +2337,60 @@ g_threaded_socket_service_get_type
</SECTION>
<SECTION>
+<FILE>gwin32namedpipeclient</FILE>
+<TITLE>GWin32NamedPipeClient</TITLE>
+GWin32NamedPipeClient
+g_win32_named_pipe_client_new
+g_win32_named_pipe_client_connect
+g_win32_named_pipe_client_connect_async
+g_win32_named_pipe_client_connect_finish
+<SUBSECTION Standard>
+GWin32NamedPipeClientClass
+G_IS_WIN32_NAMED_PIPE_CLIENT
+G_IS_WIN32_NAMED_PIPE_CLIENT_CLASS
+G_WIN32_NAMED_PIPE_CLIENT
+G_WIN32_NAMED_PIPE_CLIENT_CLASS
+G_WIN32_NAMED_PIPE_CLIENT_GET_CLASS
+G_TYPE_WIN32_NAMED_PIPE_CLIENT
+<SUBSECTION Private>
+g_win32_named_pipe_client_get_type
+</SECTION>
+
+<SECTION>
+<FILE>gwin32namedpipelistener</FILE>
+<TITLE>GWin32NamedPipeListener</TITLE>
+GWin32NamedPipeListener
+g_win32_named_pipe_listener_new
+g_win32_named_pipe_listener_add_named_pipe
+g_win32_named_pipe_listener_accept
+g_win32_named_pipe_listener_accept_async
+g_win32_named_pipe_listener_accept_finish
+<SUBSECTION Standard>
+GWin32NamedPipeListenerClass
+G_IS_WIN32_NAMED_PIPE_LISTENER
+G_IS_WIN32_NAMED_PIPE_LISTENER_CLASS
+G_WIN32_NAMED_PIPE_LISTENER
+G_WIN32_NAMED_PIPE_LISTENER_CLASS
+G_WIN32_NAMED_PIPE_LISTENER_GET_CLASS
+G_TYPE_WIN32_NAMED_PIPE_LISTENER
+<SUBSECTION Private>
+g_win32_named_pipe_listener_get_type
+</SECTION>
+
+<SECTION>
+<FILE>gwin32namedpipeconnection</FILE>
+<TITLE>GWin32NamedPipeConnection</TITLE>
+GWin32NamedPipeConnection
+g_win32_named_pipe_connection_new
+<SUBSECTION Standard>
+G_IS_WIN32_NAMED_PIPE_CONNECTION
+G_WIN32_NAMED_PIPE_CONNECTION
+G_TYPE_WIN32_NAMED_PIPE_CONNECTION
+<SUBSECTION Private>
+g_win32_named_pipe_connection_get_type
+</SECTION>
+
+<SECTION>
<FILE>gunixfdmessage</FILE>
<TITLE>GUnixFDMessage</TITLE>
GUnixFDMessage
diff --git a/gio/Makefile.am b/gio/Makefile.am
index e911d91..161a654 100644
--- a/gio/Makefile.am
+++ b/gio/Makefile.am
@@ -313,6 +313,12 @@ win32_actual_sources = \
gwin32outputstream.c \
gwin32outputstream.h \
gwin32networking.h \
+ gwin32namedpipelistener.c \
+ gwin32namedpipelistener.h \
+ gwin32namedpipeclient.c \
+ gwin32namedpipeclient.h \
+ gwin32namedpipeconnection.c \
+ gwin32namedpipeconnection.h \
$(NULL)
win32_more_sources_for_vcproj = \
@@ -334,6 +340,9 @@ giowin32includedir=$(includedir)/gio-win32-2.0/gio
giowin32include_HEADERS = \
gwin32inputstream.h \
gwin32outputstream.h \
+ gwin32namedpipelistener.h \
+ gwin32namedpipeclient.h \
+ gwin32namedpipeconnection.h \
$(NULL)
endif
diff --git a/gio/gasynchelper.c b/gio/gasynchelper.c
index 7cf86f1..76aaf6c 100644
--- a/gio/gasynchelper.c
+++ b/gio/gasynchelper.c
@@ -80,4 +80,102 @@ end:
return result;
}
+
+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)
+{
+ GWin32HandleSourceFunc func = (GWin32HandleSourceFunc)callback;
+ GWin32HandleSource *hsource = (GWin32HandleSource *)source;
+
+ return func (hsource->pollfd.fd, user_data);
+}
+
+static void
+g_win32_handle_source_finalize (GSource *source)
+{
+}
+
+static gboolean
+g_win32_handle_source_closure_callback (HANDLE handle,
+ gpointer data)
+{
+ GClosure *closure = data;
+
+ GValue param = G_VALUE_INIT;
+ GValue result_value = G_VALUE_INIT;
+ gboolean result;
+
+ g_value_init (&result_value, G_TYPE_BOOLEAN);
+
+ g_value_init (¶m, G_TYPE_POINTER);
+ g_value_set_pointer (¶m, handle);
+
+ g_closure_invoke (closure, &result_value, 1, ¶m, NULL);
+
+ result = g_value_get_boolean (&result_value);
+ g_value_unset (&result_value);
+ g_value_unset (¶m);
+
+ return result;
+}
+
+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,
+ (GSourceFunc)g_win32_handle_source_closure_callback,
+};
+
+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;
+}
#endif
diff --git a/gio/gasynchelper.h b/gio/gasynchelper.h
index 5f7f5a3..1cbd12a 100644
--- a/gio/gasynchelper.h
+++ b/gio/gasynchelper.h
@@ -30,10 +30,17 @@
G_BEGIN_DECLS
#ifdef G_OS_WIN32
+typedef gboolean (* GWin32HandleSourceFunc) (HANDLE handle,
+ gpointer user_data);
+
gboolean _g_win32_overlap_wait_result (HANDLE hfile,
OVERLAPPED *overlap,
DWORD *transferred,
GCancellable *cancellable);
+
+GSource *_g_win32_handle_create_source (HANDLE handle,
+ GCancellable *cancellable);
+
#endif
G_END_DECLS
diff --git a/gio/giotypes.h b/gio/giotypes.h
index d98ec4a..0b2ad4d 100644
--- a/gio/giotypes.h
+++ b/gio/giotypes.h
@@ -257,6 +257,10 @@ typedef struct _GProxyAddressEnumerator GProxyAddressEnumerator;
typedef struct _GVolume GVolume; /* Dummy typedef */
typedef struct _GVolumeMonitor GVolumeMonitor;
+#ifdef G_OS_WIN32
+typedef struct _GWin32NamedPipeConnection GWin32NamedPipeConnection;
+#endif
+
/**
* GAsyncReadyCallback:
* @source_object: the object the asynchronous operation was started with.
diff --git a/gio/gwin32namedpipeclient.c b/gio/gwin32namedpipeclient.c
new file mode 100644
index 0000000..935b224
--- /dev/null
+++ b/gio/gwin32namedpipeclient.c
@@ -0,0 +1,304 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * 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 "gwin32namedpipeclient.h"
+#include "gwin32namedpipeconnection.h"
+
+#include "gtask.h"
+#include "glibintl.h"
+
+#include <Windows.h>
+
+/**
+ * SECTION:gwin32namedpipeclient
+ * @short_description: Helper for connecting to a named pipe
+ * @include: gio/gio.h
+ * @see_also: #GWin32NamedPipeListener
+ *
+ * #GWin32NamedPipeClient is a lightweight high-level utility class for
+ * connecting to a named pipe.
+ *
+ * You create a #GWin32NamedPipeClient object, set any options you want, and then
+ * call a sync or async connect operation, which returns a #GWin32NamedPipeConnection
+ * on success.
+ *
+ * As #GWin32NamedPipeClient is a lightweight object, you don't need to
+ * cache it. You can just create a new one any time you need one.
+ *
+ * Since: 2.48
+ */
+
+typedef struct
+{
+ guint timeout;
+} GWin32NamedPipeClientPrivate;
+
+enum
+{
+ PROP_0,
+ PROP_TIMEOUT,
+ LAST_PROP
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE (GWin32NamedPipeClient, g_win32_named_pipe_client, G_TYPE_OBJECT)
+
+static GParamSpec *props[LAST_PROP];
+
+static void
+g_win32_named_pipe_client_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GWin32NamedPipeClient *client = G_WIN32_NAMED_PIPE_CLIENT (object);
+ GWin32NamedPipeClientPrivate *priv;
+
+ priv = g_win32_named_pipe_client_get_instance_private (client);
+
+ switch (prop_id)
+ {
+ case PROP_TIMEOUT:
+ g_value_set_uint (value, priv->timeout);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+g_win32_named_pipe_client_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GWin32NamedPipeClient *client = G_WIN32_NAMED_PIPE_CLIENT (object);
+ GWin32NamedPipeClientPrivate *priv;
+
+ priv = g_win32_named_pipe_client_get_instance_private (client);
+
+ switch (prop_id)
+ {
+ case PROP_TIMEOUT:
+ priv->timeout = g_value_get_uint (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+g_win32_named_pipe_client_class_init (GWin32NamedPipeClientClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->get_property = g_win32_named_pipe_client_get_property;
+ object_class->set_property = g_win32_named_pipe_client_set_property;
+
+ props[PROP_TIMEOUT] =
+ g_param_spec_uint ("timeout",
+ P_("Timeout"),
+ P_("The timeout in milliseconds to wait"),
+ 0,
+ NMPWAIT_WAIT_FOREVER,
+ NMPWAIT_WAIT_FOREVER,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS);
+
+ g_object_class_install_properties (object_class, LAST_PROP, props);
+}
+
+static void
+g_win32_named_pipe_client_init (GWin32NamedPipeClient *self)
+{
+}
+
+/**
+ * g_win32_named_pipe_client_new:
+ *
+ * Creates a new #GWin32NamedPipeClient.
+ *
+ * Returns: a #GWin32NamedPipeClient.
+ * Free the returned object with g_object_unref().
+ *
+ * Since: 2.48
+ */
+GWin32NamedPipeClient *
+g_win32_named_pipe_client_new (void)
+{
+ return g_object_new (G_TYPE_WIN32_NAMED_PIPE_CLIENT, NULL);
+}
+
+/**
+ * g_win32_named_pipe_client_connect:
+ * @client: a #GWin32NamedPipeClient.
+ * @pipe_name: a pipe name.
+ * @cancellable: (allow-none): optional #GCancellable object, %NULL to ignore.
+ * @error: #GError for error reporting, or %NULL to ignore.
+ *
+ * Waits until the pipe is available or the default timeout experies.
+ *
+ * When the pipe is available, a new #GWin32NamedPipeConnection is constructed
+ * and returned. The caller owns this new object and must drop their
+ * reference to it when finished with it.
+ *
+ * Returns: (transfer full): a #GWin32NamedPipeConnection on success, %NULL on error.
+ *
+ * Since: 2.48
+ */
+GWin32NamedPipeConnection *
+g_win32_named_pipe_client_connect (GWin32NamedPipeClient *client,
+ const gchar *pipe_name,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GWin32NamedPipeClientPrivate *priv;
+ DWORD timeout;
+ HANDLE handle = INVALID_HANDLE_VALUE;
+ GWin32NamedPipeConnection *connection = NULL;
+ gunichar2 *pipe_namew;
+
+ g_return_val_if_fail (G_IS_WIN32_NAMED_PIPE_CLIENT (client), NULL);
+ g_return_val_if_fail (pipe_name != NULL, NULL);
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+ priv = g_win32_named_pipe_client_get_instance_private (client);
+
+ timeout = priv->timeout == 0 ? NMPWAIT_WAIT_FOREVER : priv->timeout;
+
+ if (g_cancellable_set_error_if_cancelled (cancellable, error))
+ return NULL;
+
+ pipe_namew = g_utf8_to_utf16 (pipe_name, -1, NULL, NULL, NULL);
+
+ if (WaitNamedPipeW (pipe_namew, timeout))
+ {
+ handle = CreateFileW (pipe_namew,
+ GENERIC_READ | GENERIC_WRITE,
+ 0,
+ NULL,
+ OPEN_EXISTING,
+ 0,
+ NULL);
+
+ if (g_cancellable_set_error_if_cancelled (cancellable, error))
+ goto end;
+
+ connection = g_win32_named_pipe_connection_new (handle, TRUE);
+ }
+ else
+ {
+ int errsv;
+ gchar *err;
+
+ errsv = GetLastError ();
+ err = g_win32_error_message (errsv);
+ g_set_error_literal (error, G_IO_ERROR,
+ g_io_error_from_win32_error (errsv),
+ err);
+ g_free (err);
+ }
+
+end:
+ g_free (pipe_namew);
+
+ return connection;
+}
+
+static void
+client_connect_thread (GTask *task,
+ gpointer source_object,
+ gpointer task_data,
+ GCancellable *cancellable)
+{
+ GWin32NamedPipeClient *client = G_WIN32_NAMED_PIPE_CLIENT (source_object);
+ const gchar *pipe_name = (const gchar *)task_data;
+ GWin32NamedPipeConnection *connection;
+ GError *error = NULL;
+
+ connection = g_win32_named_pipe_client_connect (client, pipe_name,
+ cancellable, &error);
+
+ if (connection == NULL)
+ g_task_return_error (task, error);
+ else
+ g_task_return_pointer (task, connection, (GDestroyNotify)g_object_unref);
+
+ g_object_unref(task);
+}
+
+/**
+ * g_win32_named_pipe_client_connect_async:
+ * @client: a #GWin32NamedPipeClient
+ * @pipe_name: a pipe name.
+ * @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_client_connect().
+ *
+ * When the operation is finished @callback will be
+ * called. You can then call g_win32_named_pipe_client_connect_finish() to get
+ * the result of the operation.
+ *
+ * Since: 2.48
+ */
+void
+g_win32_named_pipe_client_connect_async (GWin32NamedPipeClient *client,
+ const gchar *pipe_name,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GTask *task;
+
+ g_return_if_fail (G_IS_WIN32_NAMED_PIPE_CLIENT (client));
+ g_return_if_fail (pipe_name != NULL);
+
+ task = g_task_new (client, cancellable, callback, user_data);
+ g_task_set_task_data (task, g_strdup (pipe_name), g_free);
+
+ g_task_run_in_thread (task, client_connect_thread);
+}
+
+/**
+ * g_win32_named_pipe_client_connect_finish:
+ * @client: a #GWin32NamedPipeClient.
+ * @result: a #GAsyncResult.
+ * @error: a #GError location to store the error occurring, or %NULL to
+ * ignore.
+ *
+ * Finishes an async connect operation. See g_win32_named_pipe_client_connect_async()
+ *
+ * Returns: (transfer full): a #GWin32NamedPipeConnection on success, %NULL on error.
+ *
+ * Since: 2.48
+ */
+GWin32NamedPipeConnection *
+g_win32_named_pipe_client_connect_finish (GWin32NamedPipeClient *client,
+ GAsyncResult *result,
+ GError **error)
+{
+ g_return_val_if_fail (G_IS_WIN32_NAMED_PIPE_CLIENT (client), NULL);
+ g_return_val_if_fail (g_task_is_valid (result, client), NULL);
+
+ return g_task_propagate_pointer (G_TASK (result), error);
+}
diff --git a/gio/gwin32namedpipeclient.h b/gio/gwin32namedpipeclient.h
new file mode 100644
index 0000000..160fc8e
--- /dev/null
+++ b/gio/gwin32namedpipeclient.h
@@ -0,0 +1,80 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * 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_CLIENT_H__
+#define __G_WIN32_NAMED_PIPE_CLIENT_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_CLIENT (g_win32_named_pipe_client_get_type ())
+#define G_WIN32_NAMED_PIPE_CLIENT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o),
G_TYPE_WIN32_NAMED_PIPE_CLIENT, GWin32NamedPipeClient))
+#define G_WIN32_NAMED_PIPE_CLIENT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k),
G_TYPE_WIN32_NAMED_PIPE_CLIENT, GWin32NamedPipeClientClass))
+#define G_IS_WIN32_NAMED_PIPE_CLIENT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o),
G_TYPE_WIN32_NAMED_PIPE_CLIENT))
+#define G_IS_WIN32_NAMED_PIPE_CLIENT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k),
G_TYPE_WIN32_NAMED_PIPE_CLIENT))
+#define G_WIN32_NAMED_PIPE_CLIENT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o),
G_TYPE_WIN32_NAMED_PIPE_CLIENT, GWin32NamedPipeClientClass))
+
+typedef struct _GWin32NamedPipeClient GWin32NamedPipeClient;
+typedef struct _GWin32NamedPipeClientClass GWin32NamedPipeClientClass;
+
+struct _GWin32NamedPipeClient
+{
+ /*< private >*/
+ GObject parent_instance;
+};
+
+struct _GWin32NamedPipeClientClass
+{
+ GObjectClass parent_class;
+
+ /*< private >*/
+ gpointer padding[10];
+};
+
+GLIB_AVAILABLE_IN_2_48
+GType g_win32_named_pipe_client_get_type (void) G_GNUC_CONST;
+
+GLIB_AVAILABLE_IN_2_48
+GWin32NamedPipeClient *g_win32_named_pipe_client_new (void);
+
+GLIB_AVAILABLE_IN_2_48
+GWin32NamedPipeConnection *g_win32_named_pipe_client_connect (GWin32NamedPipeClient *client,
+ const gchar *pipe_name,
+ GCancellable *cancellable,
+ GError **error);
+
+GLIB_AVAILABLE_IN_2_48
+void g_win32_named_pipe_client_connect_async (GWin32NamedPipeClient *client,
+ const gchar *pipe_name,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+GLIB_AVAILABLE_IN_2_48
+GWin32NamedPipeConnection *g_win32_named_pipe_client_connect_finish (GWin32NamedPipeClient *client,
+ GAsyncResult *result,
+ GError **error);
+
+G_END_DECLS
+
+#endif /* __G_WIN32_NAMED_PIPE_CLIENT_H__ */
diff --git a/gio/gwin32namedpipeconnection.c b/gio/gwin32namedpipeconnection.c
new file mode 100644
index 0000000..87d524c
--- /dev/null
+++ b/gio/gwin32namedpipeconnection.c
@@ -0,0 +1,234 @@
+/*
+ * Copyright © 2016 NICE s.r.l.
+ *
+ * This program 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 licence 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/>.
+ *
+ * Authors: Ignacio Casal Quinteiro <ignacio casal nice-software com>
+ */
+
+
+#include "config.h"
+
+#include "gwin32namedpipeconnection.h"
+#include "gwin32inputstream.h"
+#include "gwin32outputstream.h"
+
+#include "glibintl.h"
+
+#include <windows.h>
+
+/**
+ * SECTION:gwin32namedpipeconnection
+ * @short_description: A wrapper around a Windows pipe handle.
+ * @include: gio/gio.h
+ * @see_also: #GIOStream
+ *
+ * GWin32NamedPipeConnection creates a #GIOStream from an arbitrary handle.
+ *
+ * Since: 2.48
+ */
+
+/**
+ * GWin32NamedPipeConnection:
+ *
+ * A wrapper around a Windows pipe handle.
+ *
+ * Since: 2.48
+ */
+struct _GWin32NamedPipeConnection
+{
+ GIOStream parent;
+
+ void *handle;
+ gboolean close_handle;
+
+ GInputStream *input_stream;
+ GOutputStream *output_stream;
+};
+
+struct _GWin32NamedPipeConnectionClass
+{
+ GIOStreamClass parent;
+};
+
+typedef struct _GWin32NamedPipeConnectionClass GWin32NamedPipeConnectionClass;
+
+enum
+{
+ PROP_0,
+ PROP_HANDLE,
+ PROP_CLOSE_HANDLE
+};
+
+G_DEFINE_TYPE (GWin32NamedPipeConnection, g_win32_named_pipe_connection, G_TYPE_IO_STREAM)
+
+static void
+g_win32_named_pipe_connection_finalize (GObject *object)
+{
+ GWin32NamedPipeConnection *connection = G_WIN32_NAMED_PIPE_CONNECTION (object);
+
+ if (connection->input_stream)
+ g_object_unref (connection->input_stream);
+
+ if (connection->output_stream)
+ g_object_unref (connection->output_stream);
+
+ if (connection->close_handle && connection->handle != INVALID_HANDLE_VALUE)
+ CloseHandle (connection->handle);
+
+ G_OBJECT_CLASS (g_win32_named_pipe_connection_parent_class)->finalize (object);
+}
+
+static void
+g_win32_named_pipe_connection_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GWin32NamedPipeConnection *connection = G_WIN32_NAMED_PIPE_CONNECTION (object);
+
+ switch (prop_id)
+ {
+ case PROP_HANDLE:
+ connection->handle = g_value_get_pointer (value);
+ if (connection->handle != NULL && connection->handle != INVALID_HANDLE_VALUE)
+ {
+ connection->input_stream = g_win32_input_stream_new (connection->handle, FALSE);
+ connection->output_stream = g_win32_output_stream_new (connection->handle, FALSE);
+ }
+ break;
+
+ case PROP_CLOSE_HANDLE:
+ connection->close_handle = g_value_get_boolean (value);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+g_win32_named_pipe_connection_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GWin32NamedPipeConnection *connection = G_WIN32_NAMED_PIPE_CONNECTION (object);
+
+ switch (prop_id)
+ {
+ case PROP_HANDLE:
+ g_value_set_pointer (value, connection->handle);
+ break;
+
+ case PROP_CLOSE_HANDLE:
+ g_value_set_boolean (value, connection->close_handle);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static GInputStream *
+g_win32_named_pipe_connection_get_input_stream (GIOStream *stream)
+{
+ GWin32NamedPipeConnection *connection = G_WIN32_NAMED_PIPE_CONNECTION (stream);
+
+ return connection->input_stream;
+}
+
+static GOutputStream *
+g_win32_named_pipe_connection_get_output_stream (GIOStream *stream)
+{
+ GWin32NamedPipeConnection *connection = G_WIN32_NAMED_PIPE_CONNECTION (stream);
+
+ return connection->output_stream;
+}
+
+static void
+g_win32_named_pipe_connection_class_init (GWin32NamedPipeConnectionClass *class)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (class);
+ GIOStreamClass *io_class = G_IO_STREAM_CLASS (class);
+
+ gobject_class->finalize = g_win32_named_pipe_connection_finalize;
+ gobject_class->get_property = g_win32_named_pipe_connection_get_property;
+ gobject_class->set_property = g_win32_named_pipe_connection_set_property;
+
+ io_class->get_input_stream = g_win32_named_pipe_connection_get_input_stream;
+ io_class->get_output_stream = g_win32_named_pipe_connection_get_output_stream;
+
+ /**
+ * GWin32NamedPipeConnection:handle:
+ *
+ * The handle for the connection.
+ *
+ * Since: 2.48
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_HANDLE,
+ g_param_spec_pointer ("handle",
+ P_("File handle"),
+ P_("The file handle to read from"),
+ G_PARAM_READABLE |
+ G_PARAM_WRITABLE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+
+ /**
+ * GWin32NamedPipeConnection:close-handle:
+ *
+ * Whether to close the file handle when the pipe connection is disposed.
+ *
+ * Since: 2.48
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_CLOSE_HANDLE,
+ g_param_spec_boolean ("close-handle",
+ P_("Close file handle"),
+ P_("Whether to close the file handle when the
stream is closed"),
+ TRUE,
+ G_PARAM_READABLE |
+ G_PARAM_WRITABLE |
+ G_PARAM_STATIC_STRINGS));
+}
+
+static void
+g_win32_named_pipe_connection_init (GWin32NamedPipeConnection *stream)
+{
+}
+
+/**
+ * g_win32_named_pipe_connection_new:
+ * @handle: a Win32 file handle.
+ * @close_handle: %TRUE to close the handle when done.
+ *
+ * Creates a new #GWin32NamedPipeConnection.
+ *
+ * Returns: a new #GWin32NamedPipeConnection instance.
+ *
+ * Since: 2.48
+ */
+GWin32NamedPipeConnection *
+g_win32_named_pipe_connection_new (void *handle,
+ gboolean close_handle)
+{
+ return g_object_new (G_TYPE_WIN32_NAMED_PIPE_CONNECTION,
+ "handle", handle,
+ "close-handle", close_handle,
+ NULL);
+}
diff --git a/gio/gwin32namedpipeconnection.h b/gio/gwin32namedpipeconnection.h
new file mode 100644
index 0000000..7137444
--- /dev/null
+++ b/gio/gwin32namedpipeconnection.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright © 2016 NICE s.r.l.
+ *
+ * This program 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 licence 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/>.
+ *
+ * Authors: Ignacio Casal Quinteiro <ignacio casal nice-software com>
+ */
+
+#ifndef __G_WIN32_NAMED_PIPE_CONNECTION_H__
+#define __G_WIN32_NAMED_PIPE_CONNECTION_H__
+
+#if !defined (__GIO_GIO_H_INSIDE__) && !defined (GIO_COMPILATION)
+#error "Only <gio/gio.h> can be included directly."
+#endif
+
+#include <gio/giotypes.h>
+#include <gio/giostream.h>
+
+G_BEGIN_DECLS
+
+#define G_TYPE_WIN32_NAMED_PIPE_CONNECTION (g_win32_named_pipe_connection_get_type ())
+#define G_WIN32_NAMED_PIPE_CONNECTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj),
G_TYPE_WIN32_NAMED_PIPE_CONNECTION, GWin32NamedPipeConnection))
+#define G_IS_WIN32_NAMED_PIPE_CONNECTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj),
G_TYPE_WIN32_NAMED_PIPE_CONNECTION))
+
+GLIB_AVAILABLE_IN_2_48
+GType g_win32_named_pipe_connection_get_type (void) G_GNUC_CONST;
+
+GLIB_AVAILABLE_IN_2_48
+GWin32NamedPipeConnection *g_win32_named_pipe_connection_new (void *handle,
+ gboolean close_handle);
+
+G_END_DECLS
+
+#endif /* __G_WIN32_NAMED_PIPE_CONNECTION_H__ */
diff --git a/gio/gwin32namedpipelistener.c b/gio/gwin32namedpipelistener.c
new file mode 100644
index 0000000..81e563f
--- /dev/null
+++ b/gio/gwin32namedpipelistener.c
@@ -0,0 +1,557 @@
+/* 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 "gwin32namedpipeconnection.h"
+#include "gasynchelper.h"
+
+#include "glibintl.h"
+
+#include <windows.h>
+
+#define DEFAULT_PIPE_BUF_SIZE 4096
+
+typedef struct
+{
+ gchar *pipe_name;
+ HANDLE handle;
+ OVERLAPPED overlapped;
+ GObject *source_object;
+ gboolean already_connected;
+} PipeData;
+
+typedef struct
+{
+ GPtrArray *named_pipes;
+ GMainContext *main_context;
+} GWin32NamedPipeListenerPrivate;
+
+G_DEFINE_TYPE_WITH_PRIVATE (GWin32NamedPipeListener, g_win32_named_pipe_listener, G_TYPE_OBJECT)
+
+static GQuark source_quark = 0;
+
+static PipeData *
+pipe_data_new (const gchar *pipe_name,
+ HANDLE handle,
+ GObject *source_object)
+{
+ PipeData *data;
+
+ data = g_slice_new0 (PipeData);
+ data->pipe_name = g_strdup (pipe_name);
+ data->handle = handle;
+ data->overlapped.hEvent = CreateEvent (NULL, /* default security attribute */
+ TRUE, /* manual-reset event */
+ TRUE, /* initial state = signaled */
+ NULL); /* unnamed event object */
+ if (source_object)
+ data->source_object = g_object_ref (source_object);
+
+ return data;
+}
+
+static void
+pipe_data_free (PipeData *data)
+{
+ g_free (data->pipe_name);
+ CloseHandle (data->handle);
+ CloseHandle (data->overlapped.hEvent);
+ g_clear_object (&data->source_object);
+ g_slice_free (PipeData, data);
+}
+
+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);
+
+ if (priv->main_context)
+ g_main_context_unref (priv->main_context);
+
+ 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) pipe_data_free);
+}
+
+/**
+ * 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.
+ * @pipe_name: a name for the pipe.
+ * @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,
+ const gchar *pipe_name,
+ GObject *source_object,
+ GError **error)
+{
+ GWin32NamedPipeListenerPrivate *priv;
+ gunichar2 *pipe_namew;
+ PipeData *pipe_data;
+ HANDLE handle;
+
+ g_return_val_if_fail (G_IS_WIN32_NAMED_PIPE_LISTENER (listener), FALSE);
+ g_return_val_if_fail (pipe_name != NULL, FALSE);
+
+ priv = g_win32_named_pipe_listener_get_instance_private (listener);
+
+ pipe_namew = g_utf8_to_utf16 (pipe_name, -1, NULL, NULL, NULL);
+
+ handle = CreateNamedPipeW (pipe_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);
+ g_free (pipe_namew);
+
+ if (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': %s"),
+ pipe_name, emsg);
+
+ g_free (emsg);
+ return FALSE;
+ }
+
+ pipe_data = pipe_data_new (pipe_name, handle, source_object);
+
+ if (!ConnectNamedPipe (handle, &pipe_data->overlapped))
+ {
+ switch (GetLastError ())
+ {
+ case ERROR_IO_PENDING:
+ break;
+ case ERROR_PIPE_CONNECTED:
+ pipe_data->already_connected = TRUE;
+ break;
+ default:
+ {
+ int errsv = GetLastError ();
+ gchar *emsg = g_win32_error_message (errsv);
+
+ g_set_error (error,
+ G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
+ _("Failed to connect named pipe '%s': %s"),
+ pipe_name, emsg);
+ g_free (emsg);
+ pipe_data_free (pipe_data);
+
+ return FALSE;
+ }
+ }
+ }
+
+ g_ptr_array_add (priv->named_pipes, pipe_data);
+
+ return TRUE;
+}
+
+static gboolean
+connect_ready (HANDLE handle,
+ gpointer user_data)
+{
+ GTask *task = user_data;
+ GWin32NamedPipeListener *listener = g_task_get_source_object (task);
+ GWin32NamedPipeListenerPrivate *priv;
+ PipeData *pipe_data = NULL;
+ gulong cbret;
+ int i;
+
+ priv = g_win32_named_pipe_listener_get_instance_private (listener);
+
+ for (i = 0; i < priv->named_pipes->len; i++)
+ {
+ PipeData *pdata;
+
+ pdata = priv->named_pipes->pdata[i];
+ if (pdata->overlapped.hEvent == handle)
+ {
+ pipe_data = pdata;
+ break;
+ }
+ }
+
+ g_return_val_if_fail (pipe_data != NULL, FALSE);
+
+ if (GetOverlappedResult (pipe_data->handle, &pipe_data->overlapped, &cbret, FALSE))
+ {
+ int errsv = GetLastError ();
+ gchar *emsg = g_win32_error_message (errsv);
+
+ g_task_return_new_error (task,
+ G_IO_ERROR,
+ G_IO_ERROR_INVALID_ARGUMENT,
+ _("There was an error querying the named pipe: %s"),
+ emsg);
+ g_free (emsg);
+ }
+ else
+ {
+ GWin32NamedPipeConnection *connection;
+
+ if (pipe_data->source_object != NULL)
+ g_object_set_qdata_full (G_OBJECT (task),
+ source_quark,
+ g_object_ref (pipe_data->source_object),
+ g_object_unref);
+
+ connection = g_win32_named_pipe_connection_new (pipe_data->handle, FALSE);
+ g_task_return_pointer (task, connection, g_object_unref);
+ }
+
+ g_object_unref (task);
+
+ return FALSE;
+}
+
+static GList *
+add_sources (GWin32NamedPipeListener *listener,
+ GWin32HandleSourceFunc callback,
+ gpointer callback_data,
+ GCancellable *cancellable,
+ GMainContext *context)
+{
+ GWin32NamedPipeListenerPrivate *priv;
+ PipeData *data;
+ GSource *source;
+ GList *sources;
+ int i;
+
+ priv = g_win32_named_pipe_listener_get_instance_private (listener);
+
+ sources = NULL;
+ for (i = 0; i < priv->named_pipes->len; i++)
+ {
+ data = priv->named_pipes->pdata[i];
+
+ source = _g_win32_handle_create_source (data->overlapped.hEvent,
+ cancellable);
+ g_source_set_callback (source,
+ (GSourceFunc) callback,
+ callback_data, NULL);
+ g_source_attach (source, context);
+
+ sources = g_list_prepend (sources, source);
+ }
+
+ return sources;
+}
+
+static void
+free_sources (GList *sources)
+{
+ GSource *source;
+ while (sources != NULL)
+ {
+ source = sources->data;
+ sources = g_list_delete_link (sources, sources);
+ g_source_destroy (source);
+ g_source_unref (source);
+ }
+}
+
+struct AcceptData {
+ GWin32NamedPipeListener *listener;
+ GMainLoop *loop;
+ PipeData *pipe_data;
+};
+
+static gboolean
+accept_callback (HANDLE handle,
+ gpointer user_data)
+{
+ struct AcceptData *data = user_data;
+ GWin32NamedPipeListenerPrivate *priv;
+ PipeData *pipe_data = NULL;
+ int i;
+
+ priv = g_win32_named_pipe_listener_get_instance_private (data->listener);
+
+ for (i = 0; i < priv->named_pipes->len; i++)
+ {
+ PipeData *pdata;
+
+ pdata = priv->named_pipes->pdata[i];
+ if (pdata->overlapped.hEvent == handle)
+ {
+ pipe_data = pdata;
+ break;
+ }
+ }
+
+ data->pipe_data = pipe_data;
+ 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 #GWin32NamedPipeConnection that was accepted.
+ *
+ * If @source_object is not %NULL it will be filled out with the source
+ * object specified when the corresponding named pipe 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 #GWin32NamedPipeConnection on success, %NULL on error.
+ *
+ * Since: 2.48
+ */
+GWin32NamedPipeConnection *
+g_win32_named_pipe_listener_accept (GWin32NamedPipeListener *listener,
+ GObject **source_object,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GWin32NamedPipeListenerPrivate *priv;
+ PipeData *pipe_data = NULL;
+ GWin32NamedPipeConnection *connection = 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)
+ {
+ gboolean success;
+
+ pipe_data = priv->named_pipes->pdata[0];
+ success = pipe_data->already_connected;
+
+ if (!success)
+ success = WaitForSingleObject (pipe_data->overlapped.hEvent, INFINITE) == WAIT_OBJECT_0;
+
+ if (!success)
+ pipe_data = NULL;
+ }
+ else
+ {
+ int i;
+
+ /* First we check if any of the named pipes is already connected and
+ * pick the the first one.
+ */
+ for (i = 0; i < priv->named_pipes->len; i++)
+ {
+ PipeData *pdata = priv->named_pipes->pdata[i];
+
+ if (pdata->already_connected)
+ pipe_data = pdata;
+ }
+
+ if (pipe_data == NULL)
+ {
+ 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;
+ data.listener = listener;
+
+ sources = add_sources (listener,
+ accept_callback,
+ &data,
+ cancellable,
+ priv->main_context);
+ g_main_loop_run (loop);
+ pipe_data = data.pipe_data;
+ free_sources (sources);
+ g_main_loop_unref (loop);
+ }
+ }
+
+ if (pipe_data != NULL)
+ {
+ connection = g_win32_named_pipe_connection_new (pipe_data->handle, FALSE);
+
+ if (source_object)
+ *source_object = pipe_data->source_object;
+ }
+
+ return connection;
+}
+
+/**
+ * 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)
+{
+ GWin32NamedPipeListenerPrivate *priv;
+ PipeData *pipe_data;
+ GTask *task;
+ GList *sources;
+ int i;
+
+ task = g_task_new (listener, cancellable, callback, user_data);
+
+ priv = g_win32_named_pipe_listener_get_instance_private (listener);
+
+ /* First we check if any of the named pipes is already connected and pick the
+ * the first one.
+ */
+ for (i = 0; i < priv->named_pipes->len; i++)
+ {
+ pipe_data = priv->named_pipes->pdata[i];
+
+ if (pipe_data->already_connected)
+ {
+ GWin32NamedPipeConnection *connection;
+
+ if (pipe_data->source_object)
+ g_object_set_qdata_full (G_OBJECT (task),
+ source_quark,
+ g_object_ref (pipe_data->source_object),
+ g_object_unref);
+
+ connection = g_win32_named_pipe_connection_new (pipe_data->handle, FALSE);
+ g_task_return_pointer (task, connection, g_object_unref);
+
+ return;
+ }
+ }
+
+ sources = add_sources (listener,
+ connect_ready,
+ task,
+ cancellable,
+ g_main_context_get_thread_default ());
+ g_task_set_task_data (task, sources, (GDestroyNotify) 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 #GWin32NamedPipeConnection on success, %NULL on error.
+ *
+ * Since: 2.48
+ */
+GWin32NamedPipeConnection *
+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..c8d324c
--- /dev/null
+++ b/gio/gwin32namedpipelistener.h
@@ -0,0 +1,87 @@
+/* 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 _GWin32NamedPipeListener
+{
+ /*< private >*/
+ GObject parent_instance;
+};
+
+struct _GWin32NamedPipeListenerClass
+{
+ GObjectClass parent_class;
+
+ /*< private >*/
+ gpointer padding[10];
+};
+
+GLIB_AVAILABLE_IN_2_48
+GType g_win32_named_pipe_listener_get_type (void) G_GNUC_CONST;
+
+GLIB_AVAILABLE_IN_2_48
+GWin32NamedPipeListener *g_win32_named_pipe_listener_new (void);
+
+GLIB_AVAILABLE_IN_2_48
+gboolean g_win32_named_pipe_listener_add_named_pipe (GWin32NamedPipeListener *listener,
+ const gchar *pipe_name,
+ GObject
*source_object,
+ GError **error);
+
+GLIB_AVAILABLE_IN_2_48
+GWin32NamedPipeConnection *g_win32_named_pipe_listener_accept (GWin32NamedPipeListener *listener,
+ GObject
**source_object,
+ GCancellable
*cancellable,
+ GError **error);
+
+GLIB_AVAILABLE_IN_2_48
+void g_win32_named_pipe_listener_accept_async (GWin32NamedPipeListener *listener,
+ GCancellable
*cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+GLIB_AVAILABLE_IN_2_48
+GWin32NamedPipeConnection *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__ */
diff --git a/gio/tests/Makefile.am b/gio/tests/Makefile.am
index 0553fdf..363fe92 100644
--- a/gio/tests/Makefile.am
+++ b/gio/tests/Makefile.am
@@ -481,7 +481,7 @@ tls_interaction_SOURCES = tls-interaction.c gtesttlsbackend.c gtesttlsbackend.h
# -----------------------------------------------------------------------------
if OS_WIN32
-test_programs += win32-streams
+test_programs += win32-streams win32-named-pipe
endif
if PLATFORM_WIN32
diff --git a/gio/tests/win32-named-pipe.c b/gio/tests/win32-named-pipe.c
new file mode 100644
index 0000000..07d701d
--- /dev/null
+++ b/gio/tests/win32-named-pipe.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright © 2016 NICE s.r.l.
+ *
+ * This program 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 licence 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/>.
+ *
+ * Authors: Ignacio Casal Quinteiro <ignacio casal nice-software com>
+ */
+
+#include <gio/gio.h>
+#include <gio/gwin32namedpipelistener.h>
+
+static void
+test_add_named_pipe (void)
+{
+ gboolean success = FALSE;
+ GWin32NamedPipeListener *listener;
+ GError *error = NULL;
+
+ listener = g_win32_named_pipe_listener_new ();
+
+ g_win32_named_pipe_listener_add_named_pipe (listener,
+ "\\\\.\\pipe\\gtest-good-named-pipe-name",
+ NULL,
+ &error);
+ g_assert_no_error (error);
+
+ g_win32_named_pipe_listener_add_named_pipe (listener,
+ "\\\\.\\gtest-bad-named-pipe-name",
+ NULL,
+ &error);
+ g_assert_error (error);
+
+ g_object_unref (listener);
+}
+
+int
+main (int argc,
+ char *argv[])
+{
+ g_test_init (&argc, &argv, NULL);
+
+ g_test_bug_base ("http://bugzilla.gnome.org/");
+
+ g_test_add_func ("/named-pipes/add-named-pipe", test_add_named_pipe);
+
+ return g_test_run ();
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]