/*
Copyright (C) 2011 Red Hat, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.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 .
*/
#include "namedpipeconnection.h"
#include
#include
#include
#include
#include
#include
G_DEFINE_TYPE (SpiceNamedPipeConnection, spice_named_pipe_connection,
G_TYPE_IO_STREAM)
enum
{
PROP_0,
PROP_NAMED_PIPE,
};
struct _SpiceNamedPipeConnectionPrivate
{
GInputStream *input_stream;
GOutputStream *output_stream;
SpiceNamedPipe *namedpipe;
gboolean in_dispose;
};
static void
spice_named_pipe_connection_init (SpiceNamedPipeConnection *connection)
{
connection->priv = G_TYPE_INSTANCE_GET_PRIVATE (connection,
SPICE_TYPE_NAMED_PIPE_CONNECTION,
SpiceNamedPipeConnectionPrivate);
}
static void
spice_named_pipe_connection_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
SpiceNamedPipeConnection *c = SPICE_NAMED_PIPE_CONNECTION (object);
switch (prop_id)
{
case PROP_NAMED_PIPE:
g_return_if_fail (c->priv->namedpipe == NULL);
g_value_set_object (value, c->priv->namedpipe);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static void
spice_named_pipe_connection_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
SpiceNamedPipeConnection *c = SPICE_NAMED_PIPE_CONNECTION (object);
switch (prop_id)
{
case PROP_NAMED_PIPE:
c->priv->namedpipe = g_value_get_object (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
}
static GInputStream *
spice_named_pipe_connection_get_input_stream (GIOStream *io_stream)
{
SpiceNamedPipeConnection *c = SPICE_NAMED_PIPE_CONNECTION (io_stream);
HANDLE h = spice_named_pipe_get_handle (c->priv->namedpipe);
g_return_val_if_fail (h != NULL, NULL);
if (c->priv->input_stream == NULL)
c->priv->input_stream = g_win32_input_stream_new (h, FALSE);
return c->priv->input_stream;
}
static GOutputStream *
spice_named_pipe_connection_get_output_stream (GIOStream *io_stream)
{
SpiceNamedPipeConnection *c = SPICE_NAMED_PIPE_CONNECTION (io_stream);
HANDLE h = spice_named_pipe_get_handle (c->priv->namedpipe);
g_return_val_if_fail (h != NULL, NULL);
if (c->priv->output_stream == NULL)
c->priv->output_stream = g_win32_output_stream_new (h, FALSE);
return c->priv->output_stream;
}
static void
spice_named_pipe_connection_dispose (GObject *object)
{
SpiceNamedPipeConnection *c = SPICE_NAMED_PIPE_CONNECTION (object);
c->priv->in_dispose = TRUE;
if (G_OBJECT_CLASS (spice_named_pipe_connection_parent_class)->dispose)
G_OBJECT_CLASS (spice_named_pipe_connection_parent_class)->dispose (object);
c->priv->in_dispose = FALSE;
}
static void
spice_named_pipe_connection_finalize (GObject *object)
{
SpiceNamedPipeConnection *c = SPICE_NAMED_PIPE_CONNECTION (object);
if (c->priv->output_stream)
{
g_object_unref (c->priv->output_stream);
c->priv->output_stream = NULL;
}
if (c->priv->input_stream)
{
g_object_unref (c->priv->input_stream);
c->priv->input_stream = NULL;
}
g_object_unref (c->priv->namedpipe);
if (G_OBJECT_CLASS (spice_named_pipe_connection_parent_class)->finalize)
G_OBJECT_CLASS (spice_named_pipe_connection_parent_class)->finalize (object);
}
static gboolean
spice_named_pipe_connection_close (GIOStream *stream,
GCancellable *cancellable,
GError **error)
{
SpiceNamedPipeConnection *c = SPICE_NAMED_PIPE_CONNECTION (stream);
if (c->priv->output_stream)
g_output_stream_close (c->priv->output_stream, cancellable, NULL);
if (c->priv->input_stream)
g_input_stream_close (c->priv->input_stream, cancellable, NULL);
/* Don't close the underlying socket if this is being called
* as part of dispose(); when destroying the GSocketConnection,
* we only want to close the socket if we're holding the last
* reference on it, and in that case it will close itself when
* we unref namedpipe in finalize().
*/
if (c->priv->in_dispose)
return TRUE;
return spice_named_pipe_close (c->priv->namedpipe, error);
}
static void
spice_named_pipe_connection_close_async (GIOStream *stream,
int io_priority,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
GSimpleAsyncResult *res;
GIOStreamClass *class;
GError *error;
class = G_IO_STREAM_GET_CLASS (stream);
/* namedpipe close is not blocking, just do it! */
error = NULL;
if (class->close_fn &&
!class->close_fn (stream, cancellable, &error))
{
g_simple_async_report_take_gerror_in_idle (G_OBJECT (stream),
callback, user_data,
error);
return;
}
res = g_simple_async_result_new (G_OBJECT (stream),
callback,
user_data,
spice_named_pipe_connection_close_async);
g_simple_async_result_complete_in_idle (res);
g_object_unref (res);
}
static gboolean
spice_named_pipe_connection_close_finish (GIOStream *stream,
GAsyncResult *result,
GError **error)
{
return TRUE;
}
static void
spice_named_pipe_connection_class_init (SpiceNamedPipeConnectionClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GIOStreamClass *stream_class = G_IO_STREAM_CLASS (klass);
g_type_class_add_private (klass, sizeof (SpiceNamedPipeConnectionPrivate));
gobject_class->set_property = spice_named_pipe_connection_set_property;
gobject_class->get_property = spice_named_pipe_connection_get_property;
gobject_class->dispose = spice_named_pipe_connection_dispose;
gobject_class->finalize = spice_named_pipe_connection_finalize;
stream_class->get_input_stream = spice_named_pipe_connection_get_input_stream;
stream_class->get_output_stream = spice_named_pipe_connection_get_output_stream;
stream_class->close_fn = spice_named_pipe_connection_close;
stream_class->close_async = spice_named_pipe_connection_close_async;
stream_class->close_finish = spice_named_pipe_connection_close_finish;
g_object_class_install_property (gobject_class, PROP_NAMED_PIPE,
g_param_spec_object ("namedpipe",
"NamedPipe",
"The associated NamedPipe",
SPICE_TYPE_NAMED_PIPE,
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS));
}