summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Larsson <alexl@redhat.com>2009-05-12 10:10:52 (GMT)
committerAlexander Larsson <alexl@redhat.com>2009-05-12 10:10:52 (GMT)
commit0aa6353353e2070ec21f21d16c264c39cea64d61 (patch)
treed0bb85fcdfc567446a870e7eb010cd75ca6028d4
parent79f43d3f6602ccb44db444251236b6a94fbf7ba8 (diff)
downloadgnio-0aa6353353e2070ec21f21d16c264c39cea64d61.tar.gz
gnio-0aa6353353e2070ec21f21d16c264c39cea64d61.tar.xz
Turn GIOStream to a base class
Makes GIOStream a class, same as GInput/OutputStream Moves close to GIOStream, add close_async Make stream getters not ref
-rw-r--r--examples/server.c3
-rw-r--r--gio/giostream.c510
-rw-r--r--gio/giostream.h99
-rw-r--r--gio/gsocketconnection.c125
-rw-r--r--gio/gsocketconnection.h8
-rw-r--r--gio/gtcpconnection.h5
-rw-r--r--gio/gtls.c66
7 files changed, 649 insertions, 167 deletions
diff --git a/examples/server.c b/examples/server.c
index 597b581..adf380e 100644
--- a/examples/server.c
+++ b/examples/server.c
@@ -32,9 +32,6 @@ handler (GThreadedSocketService *service,
sizeof buffer, NULL, NULL)))
g_output_stream_write (out, buffer, size, NULL, NULL);
- g_object_unref (out);
- g_object_unref (in);
-
return TRUE;
}
diff --git a/gio/giostream.c b/gio/giostream.c
index 950c4a8..0b00eff 100644
--- a/gio/giostream.c
+++ b/gio/giostream.c
@@ -1,6 +1,7 @@
-/* GNIO - GLib Network Layer of GIO
+/* GIO - GLib Input, Output and Streaming Library
*
* Copyright © 2008 codethink
+ * Copyright © 2009 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
@@ -18,85 +19,506 @@
* Boston, MA 02111-1307, USA.
*
* Authors: Ryan Lortie <desrt@desrt.ca>
+ * Alexander Larsson <alexl@redhat.com>
*/
+#include "config.h"
#include "giostream.h"
+#include <gio/gsimpleasyncresult.h>
+#include <gio/gasyncresult.h>
+
+G_DEFINE_TYPE (GIOStream, g_io_stream, G_TYPE_OBJECT);
+
+enum
+{
+ PROP_0,
+ PROP_INPUT_STREAM,
+ PROP_OUTPUT_STREAM,
+ PROP_CLOSED
+};
+
+struct _GIOStreamPrivate {
+ guint closed : 1;
+ guint pending : 1;
+ GAsyncReadyCallback outstanding_callback;
+};
+
+static gboolean g_io_stream_real_close (GIOStream *stream,
+ GCancellable *cancellable,
+ GError **error);
+static void g_io_stream_real_close_async (GIOStream *stream,
+ int io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+static gboolean g_io_stream_real_close_finish (GIOStream *stream,
+ GAsyncResult *result,
+ GError **error);
static void
-g_io_stream_class_init (GIOStreamIface *iface)
+g_io_stream_finalize (GObject *object)
{
- GParamSpec *pspec;
+ GIOStream *stream;
- pspec = g_param_spec_object ("input-stream", "input stream",
- "The GInputStream to read from",
- G_TYPE_INPUT_STREAM,
- G_PARAM_READABLE | G_PARAM_STATIC_NAME |
- G_PARAM_STATIC_BLURB | G_PARAM_STATIC_NICK);
- g_object_interface_install_property (iface, pspec);
+ stream = G_IO_STREAM (object);
- pspec = g_param_spec_object ("output-stream", "output stream",
- "The GOutputStream to read from",
- G_TYPE_OUTPUT_STREAM,
- G_PARAM_READABLE | G_PARAM_STATIC_NAME |
- G_PARAM_STATIC_BLURB | G_PARAM_STATIC_NICK);
- g_object_interface_install_property (iface, pspec);
+ if (!stream->priv->closed)
+ g_io_stream_close (stream, NULL, NULL);
+
+ G_OBJECT_CLASS (g_io_stream_parent_class)->finalize (object);
}
-GType
-g_io_stream_get_type (void)
+static void
+g_io_stream_dispose (GObject *object)
{
- static GType my_type;
+ GIOStream *stream;
+
+ stream = G_IO_STREAM (object);
+
+ if (!stream->priv->closed)
+ g_io_stream_close (stream, NULL, NULL);
- if G_UNLIKELY (g_once_init_enter (&my_type))
+ G_OBJECT_CLASS (g_io_stream_parent_class)->dispose (object);
+}
+
+static void
+g_io_stream_init (GIOStream *stream)
+{
+ stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (stream,
+ G_TYPE_IO_STREAM,
+ GIOStreamPrivate);
+}
+
+static void
+g_io_stream_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GIOStream *stream = G_IO_STREAM (object);
+
+ switch (prop_id)
{
- GType tmp;
+ case PROP_CLOSED:
+ g_value_set_boolean (value, stream->priv->closed);
+ break;
+
+ case PROP_INPUT_STREAM:
+ g_value_set_object (value, g_io_stream_get_input_stream (stream));
+ break;
- tmp = g_type_register_static_simple (G_TYPE_INTERFACE,
- "GIOStream", sizeof (GIOStreamIface),
- (GClassInitFunc) g_io_stream_class_init, 0, NULL, 0);
- g_type_interface_add_prerequisite (tmp, G_TYPE_OBJECT);
+ case PROP_OUTPUT_STREAM:
+ g_value_set_object (value, g_io_stream_get_output_stream (stream));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
- g_once_init_leave (&my_type, tmp);
+static void
+g_io_stream_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (prop_id)
+ {
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
+}
+
+static void
+g_io_stream_class_init (GIOStreamClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (GIOStreamPrivate));
+
+ gobject_class->finalize = g_io_stream_finalize;
+ gobject_class->dispose = g_io_stream_dispose;
+ gobject_class->set_property = g_io_stream_set_property;
+ gobject_class->get_property = g_io_stream_get_property;
+
+ klass->close_fn = g_io_stream_real_close;
+ klass->close_async = g_io_stream_real_close_async;
+ klass->close_finish = g_io_stream_real_close_finish;
+
+ g_object_class_install_property (gobject_class, PROP_CLOSED,
+ g_param_spec_boolean ("closed",
+ P_("Closed"),
+ P_("Is the stream closed"),
+ FALSE,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- return my_type;
+ g_object_class_install_property (gobject_class, PROP_INPUT_STREAM,
+ g_param_spec_object ("input-stream",
+ P_("Input stream"),
+ P_("The GInputStream to read from"),
+ G_TYPE_INPUT_STREAM,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (gobject_class, PROP_OUTPUT_STREAM,
+ g_param_spec_object ("output-stream",
+ P_("Output stream"),
+ P_("The GOutputStream to write to"),
+ G_TYPE_OUTPUT_STREAM,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
}
GInputStream *
g_io_stream_get_input_stream (GIOStream *io_stream)
{
- GIOStreamIface *iface;
+ GIOStreamClass *klass;
- iface = G_IO_STREAM_GET_INTERFACE (io_stream);
+ klass = G_IO_STREAM_GET_CLASS (io_stream);
- if (iface->get_input_stream == NULL)
+ g_assert (klass->get_input_stream != NULL);
+
+ return klass->get_input_stream (io_stream);
+}
+
+GOutputStream *
+g_io_stream_get_output_stream (GIOStream *io_stream)
+{
+ GIOStreamClass *klass;
+
+ klass = G_IO_STREAM_GET_CLASS (io_stream);
+
+ g_assert (klass->get_output_stream != NULL);
+ return klass->get_output_stream (io_stream);
+}
+
+/**
+ * g_io_stream_has_pending:
+ * @stream: a #GIOStream.
+ *
+ * Checks if a stream has pending actions.
+ *
+ * Returns: %TRUE if @stream has pending actions.
+ **/
+gboolean
+g_io_stream_has_pending (GIOStream *stream)
+{
+ g_return_val_if_fail (G_IS_IO_STREAM (stream), FALSE);
+
+ return stream->priv->pending;
+}
+
+/**
+ * g_io_stream_set_pending:
+ * @stream: a #GIOStream.
+ * @error: a #GError location to store the error occuring, or %NULL to
+ * ignore.
+ *
+ * Sets @stream to have actions pending. If the pending flag is
+ * already set or @stream is closed, it will return %FALSE and set
+ * @error.
+ *
+ * Return value: %TRUE if pending was previously unset and is now set.
+ **/
+gboolean
+g_io_stream_set_pending (GIOStream *stream,
+ GError **error)
+{
+ g_return_val_if_fail (G_IS_IO_STREAM (stream), FALSE);
+
+ if (stream->priv->closed)
{
- GInputStream *input = NULL;
+ g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_CLOSED,
+ _("Stream is already closed"));
+ return FALSE;
+ }
+
+ if (stream->priv->pending)
+ {
+ g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_PENDING,
+ /* Translators: This is an error you get if there is
+ * already an operation running against this stream when
+ * you try to start one */
+ _("Stream has outstanding operation"));
+ return FALSE;
+ }
- g_object_get (io_stream, "input-stream", &input, NULL);
+ stream->priv->pending = TRUE;
+ return TRUE;
+}
+
+/**
+ * g_io_stream_clear_pending:
+ * @stream: output stream
+ *
+ * Clears the pending flag on @stream.
+ **/
+void
+g_io_stream_clear_pending (GIOStream *stream)
+{
+ g_return_if_fail (G_IS_IO_STREAM (stream));
+
+ stream->priv->pending = FALSE;
+}
+
+static gboolean
+g_io_stream_real_close (GIOStream *stream,
+ GCancellable *cancellable,
+ GError **error)
+{
+ gboolean res;
- return input;
+ res = g_output_stream_close (g_io_stream_get_output_stream (stream),
+ cancellable, error);
+
+ /* If this errored out, unset error so that we don't report
+ further errors, but still do the following ops */
+ if (error != NULL && *error != NULL)
+ error = NULL;
+
+ res &= g_input_stream_close (g_io_stream_get_input_stream (stream),
+ cancellable, error);
+
+ return res;
+}
+
+/**
+ * g_io_stream_close:
+ * @stream: A #GIOStream.
+ * @cancellable: optional #GCancellable object, %NULL to ignore.
+ * @error: location to store the error occuring, or %NULL to ignore
+ *
+ * Closes the stream, releasing resources related to it. This will also
+ * closes the individual input and output streams, if they are not already
+ * closed.
+ *
+ * Once the stream is closed, all other operations will return %G_IO_ERROR_CLOSED.
+ * Closing a stream multiple times will not return an error.
+ *
+ * Closing a stream will automatically flush any outstanding buffers in the
+ * stream.
+ *
+ * Streams will be automatically closed when the last reference
+ * is dropped, but you might want to call this function to make sure
+ * resources are released as early as possible.
+ *
+ * Some streams might keep the backing store of the stream (e.g. a file descriptor)
+ * open after the stream is closed. See the documentation for the individual
+ * stream for details.
+ *
+ * On failure the first error that happened will be reported, but the close
+ * operation will finish as much as possible. A stream that failed to
+ * close will still return %G_IO_ERROR_CLOSED for all operations. Still, it
+ * is important to check and report the error to the user, otherwise
+ * there might be a loss of data as all data might not be written.
+ *
+ * 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.
+ * Cancelling a close will still leave the stream closed, but some streams
+ * can use a faster close that doesn't block to e.g. check errors.
+ *
+ * The default implementation of this method just calls close on the
+ * individual input/output streams.
+ *
+ * Return value: %TRUE on success, %FALSE on failure
+ **/
+gboolean
+g_io_stream_close (GIOStream *stream,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GIOStreamClass *class;
+ gboolean res;
+
+ g_return_val_if_fail (G_IS_IO_STREAM (stream), FALSE);
+
+ class = G_IO_STREAM_GET_CLASS (stream);
+
+ if (stream->priv->closed)
+ return TRUE;
+
+ if (!g_io_stream_set_pending (stream, error))
+ return FALSE;
+
+ if (cancellable)
+ g_cancellable_push_current (cancellable);
+
+ res = TRUE;
+ if (class->close_fn)
+ res = class->close_fn (stream, cancellable, error);
+
+ if (cancellable)
+ g_cancellable_pop_current (cancellable);
+
+ stream->priv->closed = TRUE;
+ g_io_stream_clear_pending (stream);
+
+ return res;
+}
+
+static void
+async_ready_close_callback_wrapper (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GIOStream *stream = G_IO_STREAM (source_object);
+
+ stream->priv->closed = TRUE;
+ g_io_stream_clear_pending (stream);
+ if (stream->priv->outstanding_callback)
+ (*stream->priv->outstanding_callback) (source_object, res, user_data);
+ g_object_unref (stream);
+}
+
+/**
+ * g_io_stream_close_async:
+ * @stream: A #GIOStream.
+ * @io_priority: the io priority of the request.
+ * @callback: callback to call when the request is satisfied
+ * @user_data: the data to pass to callback function
+ * @cancellable: optional cancellable object
+ *
+ * Requests an asynchronous close of the stream, releasing resources
+ * related to it. When the operation is finished @callback will be
+ * called. You can then call g_io_stream_close_finish() to get
+ * the result of the operation.
+ *
+ * For behaviour details see g_io_stream_close().
+ *
+ * The asyncronous methods have a default fallback that uses threads
+ * to implement asynchronicity, so they are optional for inheriting
+ * classes. However, if you override one you must override all.
+ **/
+void
+g_io_stream_close_async (GIOStream *stream,
+ int io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GIOStreamClass *class;
+ GSimpleAsyncResult *simple;
+ GError *error = NULL;
+
+ g_return_if_fail (G_IS_IO_STREAM (stream));
+
+ if (stream->priv->closed)
+ {
+ simple = g_simple_async_result_new (G_OBJECT (stream),
+ callback,
+ user_data,
+ g_io_stream_close_async);
+ g_simple_async_result_complete_in_idle (simple);
+ g_object_unref (simple);
+ return;
+ }
+
+ if (!g_io_stream_set_pending (stream, &error))
+ {
+ g_simple_async_report_gerror_in_idle (G_OBJECT (stream),
+ callback,
+ user_data,
+ error);
+ g_error_free (error);
+ return;
}
- else
- return iface->get_input_stream (io_stream);
+
+ class = G_IO_STREAM_GET_CLASS (stream);
+ stream->priv->outstanding_callback = callback;
+ g_object_ref (stream);
+ class->close_async (stream, io_priority, cancellable,
+ async_ready_close_callback_wrapper, user_data);
}
-GOutputStream *
-g_io_stream_get_output_stream (GIOStream *io_stream)
+/**
+ * g_io_stream_close_finish:
+ * @stream: a #GIOStream.
+ * @result: a #GAsyncResult.
+ * @error: a #GError location to store the error occuring, or %NULL to
+ * ignore.
+ *
+ * Closes a stream.
+ *
+ * Returns: %TRUE if stream was successfully closed, %FALSE otherwise.
+ **/
+gboolean
+g_io_stream_close_finish (GIOStream *stream,
+ GAsyncResult *result,
+ GError **error)
{
- GIOStreamIface *iface;
+ GSimpleAsyncResult *simple;
+ GIOStreamClass *class;
- iface = G_IO_STREAM_GET_INTERFACE (io_stream);
+ g_return_val_if_fail (G_IS_IO_STREAM (stream), FALSE);
+ g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
- if (iface->get_output_stream == NULL)
+ if (G_IS_SIMPLE_ASYNC_RESULT (result))
{
- GOutputStream *output = NULL;
+ simple = G_SIMPLE_ASYNC_RESULT (result);
+ if (g_simple_async_result_propagate_error (simple, error))
+ return FALSE;
+
+ /* Special case already closed */
+ if (g_simple_async_result_get_source_tag (simple) == g_io_stream_close_async)
+ return TRUE;
+ }
- g_object_get (io_stream, "output-stream", &output, NULL);
+ class = G_IO_STREAM_GET_CLASS (stream);
+ return class->close_finish (stream, result, error);
+}
+
+
+static void
+close_async_thread (GSimpleAsyncResult *res,
+ GObject *object,
+ GCancellable *cancellable)
+{
+ GIOStreamClass *class;
+ GError *error = NULL;
+ gboolean result;
+
+ /* Auto handling of cancelation disabled, and ignore
+ cancellation, since we want to close things anyway, although
+ possibly in a quick-n-dirty way. At least we never want to leak
+ open handles */
- return output;
+ class = G_IO_STREAM_GET_CLASS (object);
+ result = class->close_fn (G_IO_STREAM (object), cancellable, &error);
+ if (!result)
+ {
+ g_simple_async_result_set_from_error (res, error);
+ g_error_free (error);
}
- else
- return iface->get_output_stream (io_stream);
}
+static void
+g_io_stream_real_close_async (GIOStream *stream,
+ int io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *res;
+
+ res = g_simple_async_result_new (G_OBJECT (stream),
+ callback,
+ user_data,
+ g_io_stream_real_close_async);
+
+ g_simple_async_result_set_handle_cancellation (res, FALSE);
+
+ g_simple_async_result_run_in_thread (res,
+ close_async_thread,
+ io_priority,
+ cancellable);
+ g_object_unref (res);
+}
+
+static gboolean
+g_io_stream_real_close_finish (GIOStream *stream,
+ GAsyncResult *result,
+ GError **error)
+{
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result);
+ g_warn_if_fail (g_simple_async_result_get_source_tag (simple) ==
+ g_io_stream_real_close_async);
+ return TRUE;
+}
diff --git a/gio/giostream.h b/gio/giostream.h
index 0800aa8..679d94d 100644
--- a/gio/giostream.h
+++ b/gio/giostream.h
@@ -1,5 +1,7 @@
-/*
+/* GIO - GLib Input, Output and Streaming Library
+ *
* Copyright © 2008, 2009 Codethink Limited
+ * Copyright © 2009 Red Hat, Inc.
*
* 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
@@ -9,44 +11,103 @@
* See the included COPYING file for more information.
*
* Authors: Ryan Lortie <desrt@desrt.ca>
+ * Alexander Larsson <alexl@redhat.com>
*/
#if !defined (__GIO_GIO_H_INSIDE__) && !defined (GIO_COMPILATION)
#error "Only <gio/gio.h> can be included directly."
#endif
-#ifndef _giostream_h_
-#define _giostream_h_
+#ifndef __G_IO_STREAM_H__
+#define __G_IO_STREAM_H__
#include <gio/ginputstream.h>
#include <gio/goutputstream.h>
+#include <gio/gcancellable.h>
+#include <gio/gioerror.h>
G_BEGIN_DECLS
-#define G_TYPE_IO_STREAM (g_io_stream_get_type ())
-#define G_IO_STREAM(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), \
- G_TYPE_IO_STREAM, GIOStream))
-#define G_IS_IO_STREAM(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), \
- G_TYPE_IO_STREAM))
-#define G_IO_STREAM_GET_INTERFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), \
- G_TYPE_IO_STREAM, GIOStreamIface))
+#define G_TYPE_IO_STREAM (g_io_stream_get_type ())
+#define G_IO_STREAM(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_IO_STREAM, GIOStream))
+#define G_IO_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_IO_STREAM, GIOStreamClass))
+#define G_IS_IO_STREAM(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_IO_STREAM))
+#define G_IS_IO_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_IO_STREAM))
+#define G_IO_STREAM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_IO_STREAM, GIOStreamClass))
-typedef struct _GIOStreamIface GIOStreamIface;
typedef struct _GIOStream GIOStream;
+typedef struct _GIOStreamPrivate GIOStreamPrivate;
+typedef struct _GIOStreamClass GIOStreamClass;
+
+/**
+ * GIOStream:
+ *
+ * Base class for read-write streams.
+ **/
+struct _GIOStream
+{
+ GObject parent_instance;
+
+ /*< private >*/
+ GIOStreamPrivate *priv;
+};
-struct _GIOStreamIface
+struct _GIOStreamClass
{
- GTypeInterface g_iface;
+ GObjectClass parent_class;
+
+ GInputStream * (*get_input_stream) (GIOStream *stream);
+ GOutputStream * (*get_output_stream) (GIOStream *stream);
- GInputStream * (*get_input_stream) (GIOStream *io_stream);
- GOutputStream * (*get_output_stream) (GIOStream *io_stream);
+ gboolean (* close_fn) (GIOStream *stream,
+ GCancellable *cancellable,
+ GError **error);
+ void (* close_async) (GIOStream *stream,
+ int io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+ gboolean (* close_finish) (GIOStream *stream,
+ GAsyncResult *result,
+ GError **error);
+ /*< private >*/
+ /* Padding for future expansion */
+ void (*_g_reserved1) (void);
+ void (*_g_reserved2) (void);
+ void (*_g_reserved3) (void);
+ void (*_g_reserved4) (void);
+ void (*_g_reserved5) (void);
+ void (*_g_reserved6) (void);
+ void (*_g_reserved7) (void);
+ void (*_g_reserved8) (void);
+ void (*_g_reserved9) (void);
+ void (*_g_reserved10) (void);
};
-GType g_io_stream_get_type (void);
-GInputStream * g_io_stream_get_input_stream (GIOStream *io_stream);
-GOutputStream * g_io_stream_get_output_stream (GIOStream *io_stream);
+GType g_io_stream_get_type (void);
+
+GInputStream * g_io_stream_get_input_stream (GIOStream *stream);
+GOutputStream *g_io_stream_get_output_stream (GIOStream *stream);
+
+gboolean g_io_stream_close (GIOStream *stream,
+ GCancellable *cancellable,
+ GError **error);
+
+void g_io_stream_close_async (GIOStream *stream,
+ int io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean g_io_stream_close_finish (GIOStream *stream,
+ GAsyncResult *result,
+ GError **error);
+gboolean g_io_stream_is_closed (GIOStream *stream);
+gboolean g_io_stream_has_pending (GIOStream *stream);
+gboolean g_io_stream_set_pending (GIOStream *stream,
+ GError **error);
+void g_io_stream_clear_pending (GIOStream *stream);
G_END_DECLS
-#endif /* _giostream_h_ */
+#endif /* __G_IO_STREAM_H__ */
diff --git a/gio/gsocketconnection.c b/gio/gsocketconnection.c
index 3d9a7c1..b45e2dc 100644
--- a/gio/gsocketconnection.c
+++ b/gio/gsocketconnection.c
@@ -24,8 +24,8 @@
*/
/* TODO: On glib merge, switch this */
-#if 0
#include "config.h"
+#if 0
#include "glibintl.h"
#else
#include <glib/gi18n-lib.h>
@@ -36,39 +36,47 @@
#include "gsocketoutputstream.h"
#include "gsocketinputstream.h"
-#include "giostream.h"
+#include <gio/giostream.h>
+#include <gio/gsimpleasyncresult.h>
-static void g_socket_connection_iface_init (GIOStreamIface *iface);
-G_DEFINE_TYPE_WITH_CODE (GSocketConnection,
- g_socket_connection, G_TYPE_OBJECT,
- G_IMPLEMENT_INTERFACE (G_TYPE_IO_STREAM,
- g_socket_connection_iface_init));
+G_DEFINE_TYPE (GSocketConnection,
+ g_socket_connection, G_TYPE_IO_STREAM);
enum
{
PROP_NONE,
PROP_SOCKET,
- PROP_INPUT_STREAM,
- PROP_OUTPUT_STREAM
};
struct _GSocketConnectionPrivate
{
- GSocket *socket;
- GSocketInputStream *input_stream;
- GSocketOutputStream *output_stream;
+ GSocket *socket;
+ GInputStream *input_stream;
+ GOutputStream *output_stream;
};
+static gboolean g_socket_connection_close (GIOStream *stream,
+ GCancellable *cancellable,
+ GError **error);
+static void g_socket_connection_close_async (GIOStream *stream,
+ int io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+static gboolean g_socket_connection_close_finish (GIOStream *stream,
+ GAsyncResult *result,
+ GError **error);
+
static GInputStream *
g_socket_connection_get_input_stream (GIOStream *io_stream)
{
GSocketConnection *connection = G_SOCKET_CONNECTION (io_stream);
if (connection->priv->input_stream == NULL)
- connection->priv->input_stream =
+ connection->priv->input_stream = (GInputStream *)
_g_socket_input_stream_new (connection->priv->socket);
- return g_object_ref (connection->priv->input_stream);
+ return connection->priv->input_stream;
}
static GOutputStream *
@@ -77,10 +85,10 @@ g_socket_connection_get_output_stream (GIOStream *io_stream)
GSocketConnection *connection = G_SOCKET_CONNECTION (io_stream);
if (connection->priv->output_stream == NULL)
- connection->priv->output_stream =
+ connection->priv->output_stream = (GOutputStream *)
_g_socket_output_stream_new (connection->priv->socket);
- return g_object_ref (connection->priv->output_stream);
+ return connection->priv->output_stream;
}
static void
@@ -95,16 +103,6 @@ g_socket_connection_get_property (GObject *object, guint prop_id,
g_value_set_object (value, connection->priv->socket);
break;
- case PROP_INPUT_STREAM:
- g_value_take_object (value,
- g_socket_connection_get_input_stream (G_IO_STREAM (connection)));
- break;
-
- case PROP_OUTPUT_STREAM:
- g_value_take_object (value,
- g_socket_connection_get_output_stream (G_IO_STREAM (connection)));
- break;
-
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
@@ -132,9 +130,7 @@ g_socket_connection_constructed (GObject *object)
{
GSocketConnection *connection = G_SOCKET_CONNECTION (object);
- if (connection->priv->socket == NULL)
- g_error ("ya... so, uh.. you just constructed a GSocketConnection"
- " without an underlying GSocket. don't do that.");
+ g_assert (connection->priv->socket != NULL);
}
static void
@@ -158,6 +154,7 @@ static void
g_socket_connection_class_init (GSocketConnectionClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ GIOStreamClass *stream_class = G_IO_STREAM_CLASS (klass);
g_type_class_add_private (klass, sizeof (GSocketConnectionPrivate));
@@ -166,18 +163,18 @@ g_socket_connection_class_init (GSocketConnectionClass *klass)
gobject_class->constructed = g_socket_connection_constructed;
gobject_class->finalize = g_socket_connection_finalize;
+ stream_class->get_input_stream = g_socket_connection_get_input_stream;
+ stream_class->get_output_stream = g_socket_connection_get_output_stream;
+ stream_class->close_fn = g_socket_connection_close;
+ stream_class->close_async = g_socket_connection_close_async;
+ stream_class->close_finish = g_socket_connection_close_finish;
+
g_object_class_install_property (gobject_class, PROP_SOCKET,
g_param_spec_object ("socket",
P_("Socket"),
P_("The underlying GSocket"),
G_TYPE_SOCKET, G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_READWRITE | G_PARAM_STATIC_NAME |
- G_PARAM_STATIC_BLURB | G_PARAM_STATIC_NICK));
-
- g_object_class_override_property (gobject_class, PROP_INPUT_STREAM,
- "input-stream");
- g_object_class_override_property (gobject_class, PROP_OUTPUT_STREAM,
- "output-stream");
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
}
static void
@@ -188,19 +185,57 @@ g_socket_connection_init (GSocketConnection *connection)
GSocketConnectionPrivate);
}
-gboolean
-g_socket_connection_close (GSocketConnection *connection,
- GError **error)
+static gboolean
+g_socket_connection_close (GIOStream *stream,
+ GCancellable *cancellable,
+ GError **error)
{
- g_return_val_if_fail (G_IS_SOCKET_CONNECTION (connection), TRUE);
+ GSocketConnection *connection = G_SOCKET_CONNECTION (stream);
+
+ if (connection->priv->output_stream)
+ g_output_stream_close (connection->priv->output_stream,
+ cancellable, NULL);
+ if (connection->priv->input_stream)
+ g_input_stream_close (connection->priv->input_stream,
+ cancellable, NULL);
- return g_socket_close (connection->priv->socket,
- error);
+ return g_socket_close (connection->priv->socket, error);
}
+
static void
-g_socket_connection_iface_init (GIOStreamIface *iface)
+g_socket_connection_close_async (GIOStream *stream,
+ int io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *res;
+ GError *error;
+
+ /* socket close is not blocked, just do it! */
+ error = NULL;
+ if (!g_io_stream_close (stream, cancellable, &error))
+ {
+ g_simple_async_report_gerror_in_idle (G_OBJECT (stream),
+ callback, user_data,
+ error);
+ g_error_free (error);
+ return;
+ }
+
+ res = g_simple_async_result_new (G_OBJECT (stream),
+ callback,
+ user_data,
+ g_socket_connection_close_async);
+ g_simple_async_result_complete_in_idle (res);
+ g_object_unref (res);
+}
+
+static gboolean
+g_socket_connection_close_finish (GIOStream *stream,
+ GAsyncResult *result,
+ GError **error)
{
- iface->get_input_stream = g_socket_connection_get_input_stream;
- iface->get_output_stream = g_socket_connection_get_output_stream;
+ return TRUE;
}
diff --git a/gio/gsocketconnection.h b/gio/gsocketconnection.h
index 40ed737..e32f0dd 100644
--- a/gio/gsocketconnection.h
+++ b/gio/gsocketconnection.h
@@ -22,6 +22,7 @@
#define _gsocketconnection_h_
#include <glib-object.h>
+#include <gio/giostream.h>
G_BEGIN_DECLS
@@ -43,20 +44,17 @@ typedef struct _GSocketConnection GSocketConnection;
struct _GSocketConnectionClass
{
- GObjectClass parent_class;
+ GIOStreamClass parent_class;
};
struct _GSocketConnection
{
- GObject parent_instance;
+ GIOStream parent_instance;
GSocketConnectionPrivate *priv;
};
GType g_socket_connection_get_type (void);
-gboolean g_socket_connection_close (GSocketConnection *connection,
- GError **error);
-
G_END_DECLS
#endif /* _gsocketconnection_h_ */
diff --git a/gio/gtcpconnection.h b/gio/gtcpconnection.h
index 2e19d50..f7a123d 100644
--- a/gio/gtcpconnection.h
+++ b/gio/gtcpconnection.h
@@ -19,6 +19,7 @@
#define _gtcpconnection_h_
#include <glib-object.h>
+#include <gio/gsocketconnection.h>
G_BEGIN_DECLS
@@ -40,12 +41,12 @@ typedef struct _GTcpConnection GTcpConnection;
struct _GTcpConnectionClass
{
- GObjectClass parent_class;
+ GSocketConnectionClass parent_class;
};
struct _GTcpConnection
{
- GObject parent_instance;
+ GSocketConnection parent_instance;
GTcpConnectionPrivate *priv;
};
diff --git a/gio/gtls.c b/gio/gtls.c
index 3eb910f..a18466c 100644
--- a/gio/gtls.c
+++ b/gio/gtls.c
@@ -16,8 +16,6 @@ enum
{
PROP_C_NONE,
PROP_C_SESSION,
- PROP_C_INPUT,
- PROP_C_OUTPUT
};
enum
@@ -89,7 +87,7 @@ typedef struct
GError *error;
} GTLSOp;
-typedef GObjectClass GTLSConnectionClass;
+typedef GIOStreamClass GTLSConnectionClass;
typedef GObjectClass GTLSSessionClass;
typedef GInputStreamClass GTLSInputStreamClass;
typedef GOutputStreamClass GTLSOutputStreamClass;
@@ -131,7 +129,7 @@ typedef struct
struct OPAQUE_TYPE__GTLSConnection
{
- GObject parent;
+ GIOStream parent;
GTLSSession *session;
GTLSInputStream *input;
@@ -140,9 +138,7 @@ struct OPAQUE_TYPE__GTLSConnection
static GType g_tls_input_stream_get_type (void);
static GType g_tls_output_stream_get_type (void);
-static void g_tls_connection_iface_init (GIOStreamIface *iface);
-G_DEFINE_TYPE_WITH_CODE (GTLSConnection, g_tls_connection, G_TYPE_OBJECT,
- G_IMPLEMENT_INTERFACE (G_TYPE_IO_STREAM, g_tls_connection_iface_init));
+G_DEFINE_TYPE (GTLSConnection, g_tls_connection, G_TYPE_IO_STREAM);
G_DEFINE_TYPE (GTLSSession, g_tls_session, G_TYPE_OBJECT);
G_DEFINE_TYPE (GTLSInputStream, g_tls_input_stream, G_TYPE_INPUT_STREAM);
G_DEFINE_TYPE (GTLSOutputStream, g_tls_output_stream, G_TYPE_OUTPUT_STREAM);
@@ -750,21 +746,18 @@ g_tls_session_push_func (gpointer user_data,
{
active_job->error = session->write_op.error;
gnutls_transport_set_errno (session->session, EIO);
- g_object_unref (stream);
return -1;
}
else
{
g_assert_cmpint (session->write_op.result, <=, count);
- g_object_unref (stream);
return session->write_op.result;
}
}
gnutls_transport_set_errno (session->session, EAGAIN);
- g_object_unref (stream);
return -1;
}
@@ -779,8 +772,6 @@ g_tls_session_push_func (gpointer user_data,
if (result < 0)
gnutls_transport_set_errno (session->session, EIO);
- g_object_unref (stream);
-
return result;
}
}
@@ -846,7 +837,6 @@ g_tls_session_pull_func (gpointer user_data,
g_free (session->read_op.buffer);
active_job->error = session->read_op.error;
gnutls_transport_set_errno (session->session, EIO);
- g_object_unref (stream);
return -1;
}
@@ -858,14 +848,12 @@ g_tls_session_pull_func (gpointer user_data,
session->read_op.buffer,
session->read_op.result);
g_free (session->read_op.buffer);
- g_object_unref (stream);
return session->read_op.result;
}
}
gnutls_transport_set_errno (session->session, EAGAIN);
- g_object_unref (stream);
return -1;
}
@@ -880,8 +868,6 @@ g_tls_session_pull_func (gpointer user_data,
if (result < 0)
gnutls_transport_set_errno (session->session, EIO);
- g_object_unref (stream);
-
return result;
}
}
@@ -991,7 +977,7 @@ g_tls_connection_get_input_stream (GIOStream *io_stream)
"session", connection->session,
NULL);
- return g_object_ref (connection->input);
+ return (GInputStream *)connection->input;
}
static GOutputStream *
@@ -1004,27 +990,15 @@ g_tls_connection_get_output_stream (GIOStream *io_stream)
"session", connection->session,
NULL);
- return g_object_ref (connection->output);
+ return (GOutputStream *)connection->output;
}
static void
g_tls_connection_get_property (GObject *object, guint prop_id,
GValue *value, GParamSpec *pspec)
{
- GTLSConnection *connection = G_TLS_CONNECTION (object);
-
switch (prop_id)
{
- case PROP_C_INPUT:
- g_value_take_object (value,
- g_tls_connection_get_input_stream (G_IO_STREAM (connection)));
- break;
-
- case PROP_C_OUTPUT:
- g_value_take_object (value,
- g_tls_connection_get_output_stream (G_IO_STREAM (connection)));
- break;
-
default:
g_assert_not_reached ();
}
@@ -1056,22 +1030,23 @@ g_tls_connection_finalize (GObject *object)
}
static void
-g_tls_connection_class_init (GObjectClass *class)
+g_tls_connection_class_init (GTLSConnectionClass *class)
{
- class->get_property = g_tls_connection_get_property;
- class->set_property = g_tls_connection_set_property;
- class->constructed = g_tls_connection_constructed;
- class->finalize = g_tls_connection_finalize;
+ GObjectClass *gobject_class = G_OBJECT_CLASS (class);
+ GIOStreamClass *stream_class = G_IO_STREAM_CLASS (class);
- g_object_class_install_property (class, PROP_C_SESSION,
+ gobject_class->get_property = g_tls_connection_get_property;
+ gobject_class->set_property = g_tls_connection_set_property;
+ gobject_class->constructed = g_tls_connection_constructed;
+ gobject_class->finalize = g_tls_connection_finalize;
+
+ g_object_class_install_property (gobject_class, PROP_C_SESSION,
g_param_spec_object ("session", "TLS session",
"the TLS session object for this connection",
G_TYPE_TLS_SESSION, G_PARAM_WRITABLE |
- G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_NAME |
- G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
-
- g_object_class_override_property (class, PROP_C_INPUT, "input-stream");
- g_object_class_override_property (class, PROP_C_OUTPUT, "output-stream");
+ G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
+ stream_class->get_input_stream = g_tls_connection_get_input_stream;
+ stream_class->get_output_stream = g_tls_connection_get_output_stream;
}
GTLSSession *
@@ -1079,10 +1054,3 @@ g_tls_session_new (GIOStream *stream)
{
return g_object_new (G_TYPE_TLS_SESSION, "base-stream", stream, NULL);
}
-
-static void
-g_tls_connection_iface_init (GIOStreamIface *iface)
-{
- iface->get_input_stream = g_tls_connection_get_input_stream;
- iface->get_output_stream = g_tls_connection_get_output_stream;
-}