mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-02-23 18:52:09 +01:00
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
This commit is contained in:
parent
f3334b47ec
commit
6f49770e56
@ -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"/>
|
||||
|
@ -2336,6 +2336,60 @@ GThreadedSocketServicePrivate
|
||||
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>
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -168,6 +168,12 @@
|
||||
#include <gio/glistmodel.h>
|
||||
#include <gio/gliststore.h>
|
||||
|
||||
#ifdef G_OS_WIN32
|
||||
#include <gio/gwin32namedpipeclient.h>
|
||||
#include <gio/gwin32namedpipelistener.h>
|
||||
#include <gio/gwin32namedpipeconnection.h>
|
||||
#endif
|
||||
|
||||
#include <gio/gio-autocleanups.h>
|
||||
|
||||
#undef __GIO_GIO_H_INSIDE__
|
||||
|
@ -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.
|
||||
|
304
gio/gwin32namedpipeclient.c
Normal file
304
gio/gwin32namedpipeclient.c
Normal file
@ -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;
|
||||
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);
|
||||
|
||||
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, priv->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_object_new (G_TYPE_WIN32_NAMED_PIPE_CONNECTION,
|
||||
"handle", handle,
|
||||
"close-handle", TRUE,
|
||||
NULL);
|
||||
}
|
||||
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);
|
||||
}
|
80
gio/gwin32namedpipeclient.h
Normal file
80
gio/gwin32namedpipeclient.h
Normal file
@ -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__ */
|
213
gio/gwin32namedpipeconnection.c
Normal file
213
gio/gwin32namedpipeconnection.c
Normal file
@ -0,0 +1,213 @@
|
||||
/*
|
||||
* 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)
|
||||
{
|
||||
}
|
41
gio/gwin32namedpipeconnection.h
Normal file
41
gio/gwin32namedpipeconnection.h
Normal file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __G_WIN32_NAMED_PIPE_CONNECTION_H__ */
|
566
gio/gwin32namedpipelistener.c
Normal file
566
gio/gwin32namedpipelistener.c
Normal file
@ -0,0 +1,566 @@
|
||||
/* 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_object_new (G_TYPE_WIN32_NAMED_PIPE_CONNECTION,
|
||||
"handle", pipe_data->handle,
|
||||
"close-handle", FALSE,
|
||||
NULL);
|
||||
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_object_new (G_TYPE_WIN32_NAMED_PIPE_CONNECTION,
|
||||
"handle", pipe_data->handle,
|
||||
"close-handle", FALSE,
|
||||
NULL);
|
||||
|
||||
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_object_new (G_TYPE_WIN32_NAMED_PIPE_CONNECTION,
|
||||
"handle", pipe_data->handle,
|
||||
"close-handle", FALSE,
|
||||
NULL);
|
||||
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);
|
||||
}
|
87
gio/gwin32namedpipelistener.h
Normal file
87
gio/gwin32namedpipelistener.h
Normal file
@ -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__ */
|
@ -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
|
||||
|
215
gio/tests/win32-named-pipe.c
Normal file
215
gio/tests/win32-named-pipe.c
Normal file
@ -0,0 +1,215 @@
|
||||
/*
|
||||
* 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>
|
||||
|
||||
static void
|
||||
test_add_named_pipe (void)
|
||||
{
|
||||
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_IO_ERROR, G_IO_ERROR_FAILED);
|
||||
|
||||
g_object_unref (listener);
|
||||
}
|
||||
|
||||
static void
|
||||
accepted_cb (GObject *source,
|
||||
GAsyncResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
GWin32NamedPipeListener *listener = G_WIN32_NAMED_PIPE_LISTENER (source);
|
||||
GWin32NamedPipeConnection *conn;
|
||||
gboolean *sucess = user_data;
|
||||
GError *error = NULL;
|
||||
|
||||
conn = g_win32_named_pipe_listener_accept_finish (listener, result, NULL, &error);
|
||||
g_assert_no_error (error);
|
||||
g_object_unref (conn);
|
||||
|
||||
*sucess = TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
connected_cb (GObject *source,
|
||||
GAsyncResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
GWin32NamedPipeClient *client = G_WIN32_NAMED_PIPE_CLIENT (source);
|
||||
GWin32NamedPipeConnection *conn;
|
||||
gboolean *sucess = user_data;
|
||||
GError *error = NULL;
|
||||
|
||||
conn = g_win32_named_pipe_client_connect_finish (client, result, &error);
|
||||
g_assert_no_error (error);
|
||||
g_object_unref (conn);
|
||||
|
||||
*sucess = TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
test_connect_basic (void)
|
||||
{
|
||||
GWin32NamedPipeListener *listener;
|
||||
GWin32NamedPipeClient *client;
|
||||
gboolean success_accepted = FALSE;
|
||||
gboolean success_connected = FALSE;
|
||||
GError *error = NULL;
|
||||
|
||||
listener = g_win32_named_pipe_listener_new ();
|
||||
|
||||
g_win32_named_pipe_listener_add_named_pipe (listener,
|
||||
"\\\\.\\pipe\\gtest-named-pipe-name",
|
||||
NULL,
|
||||
&error);
|
||||
g_assert_no_error (error);
|
||||
|
||||
g_win32_named_pipe_listener_accept_async (listener,
|
||||
NULL,
|
||||
accepted_cb,
|
||||
&success_accepted);
|
||||
|
||||
client = g_win32_named_pipe_client_new ();
|
||||
g_win32_named_pipe_client_connect_async (client,
|
||||
"\\\\.\\pipe\\gtest-named-pipe-name",
|
||||
NULL,
|
||||
connected_cb,
|
||||
&success_connected);
|
||||
|
||||
do
|
||||
g_main_context_iteration (NULL, TRUE);
|
||||
while (!success_accepted || !success_connected);
|
||||
|
||||
g_object_unref (client);
|
||||
g_object_unref (listener);
|
||||
}
|
||||
|
||||
static void
|
||||
test_connect_before_accept (void)
|
||||
{
|
||||
GWin32NamedPipeListener *listener;
|
||||
GWin32NamedPipeClient *client;
|
||||
gboolean success_accepted = FALSE;
|
||||
gboolean success_connected = FALSE;
|
||||
GError *error = NULL;
|
||||
|
||||
listener = g_win32_named_pipe_listener_new ();
|
||||
|
||||
g_win32_named_pipe_listener_add_named_pipe (listener,
|
||||
"\\\\.\\pipe\\gtest-named-pipe-name",
|
||||
NULL,
|
||||
&error);
|
||||
g_assert_no_error (error);
|
||||
|
||||
client = g_win32_named_pipe_client_new ();
|
||||
g_win32_named_pipe_client_connect_async (client,
|
||||
"\\\\.\\pipe\\gtest-named-pipe-name",
|
||||
NULL,
|
||||
connected_cb,
|
||||
&success_connected);
|
||||
|
||||
g_win32_named_pipe_listener_accept_async (listener,
|
||||
NULL,
|
||||
accepted_cb,
|
||||
&success_accepted);
|
||||
|
||||
do
|
||||
g_main_context_iteration (NULL, TRUE);
|
||||
while (!success_accepted || !success_connected);
|
||||
|
||||
g_object_unref (client);
|
||||
g_object_unref (listener);
|
||||
}
|
||||
|
||||
static void
|
||||
test_connect_sync (void)
|
||||
{
|
||||
GWin32NamedPipeListener *listener;
|
||||
GWin32NamedPipeClient *client;
|
||||
GWin32NamedPipeConnection *connection;
|
||||
GError *error = NULL;
|
||||
|
||||
listener = g_win32_named_pipe_listener_new ();
|
||||
|
||||
g_win32_named_pipe_listener_add_named_pipe (listener,
|
||||
"\\\\.\\pipe\\gtest-connect-sync",
|
||||
NULL,
|
||||
&error);
|
||||
g_assert_no_error (error);
|
||||
|
||||
client = g_win32_named_pipe_client_new ();
|
||||
connection = g_win32_named_pipe_client_connect (client,
|
||||
"\\\\.\\pipe\\gtest-connect-sync",
|
||||
NULL,
|
||||
&error);
|
||||
|
||||
g_assert_no_error (error);
|
||||
|
||||
g_object_unref (client);
|
||||
g_object_unref (listener);
|
||||
}
|
||||
|
||||
static void
|
||||
test_connect_sync_fails (void)
|
||||
{
|
||||
GWin32NamedPipeClient *client;
|
||||
GWin32NamedPipeConnection *connection;
|
||||
GError *error = NULL;
|
||||
|
||||
client = g_win32_named_pipe_client_new ();
|
||||
connection = g_win32_named_pipe_client_connect (client,
|
||||
"\\\\.\\pipe\\gtest-connect-sync-fails",
|
||||
NULL,
|
||||
&error);
|
||||
|
||||
g_assert (connection == NULL);
|
||||
g_assert_error (error, G_IO_ERROR, G_IO_ERROR_FAILED);
|
||||
|
||||
g_object_unref (client);
|
||||
}
|
||||
|
||||
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);
|
||||
g_test_add_func ("/named-pipes/connect-basic", test_connect_basic);
|
||||
g_test_add_func ("/named-pipes/connect-before-accept", test_connect_before_accept);
|
||||
g_test_add_func ("/named-pipes/connect-sync", test_connect_sync);
|
||||
g_test_add_func ("/named-pipes/connect-sync-fails", test_connect_sync_fails);
|
||||
|
||||
return g_test_run ();
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user