[gnio] Turn GIOStream to a base class



commit 0aa6353353e2070ec21f21d16c264c39cea64d61
Author: Alexander Larsson <alexl redhat com>
Date:   Tue May 12 12:10:52 2009 +0200

    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
---
 examples/server.c       |    3 -
 gio/giostream.c         |  510 +++++++++++++++++++++++++++++++++++++++++++----
 gio/giostream.h         |   99 ++++++++--
 gio/gsocketconnection.c |  125 ++++++++----
 gio/gsocketconnection.h |    8 +-
 gio/gtcpconnection.h    |    5 +-
 gio/gtls.c              |   66 ++-----
 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;
-}



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]