diff options
author | Alexander Larsson <alexl@redhat.com> | 2009-05-15 21:26:24 +0200 |
---|---|---|
committer | Alexander Larsson <alexl@redhat.com> | 2009-05-15 21:26:24 +0200 |
commit | ce8361217c1c9bd458eab55554a77d24210235cc (patch) | |
tree | 3659b510033ab50971381a42cbdb57a667eed75e /gio/gsocketoutputstream.c | |
parent | 2597e3adc37ce342972e995444f4417e0aa6fb5d (diff) | |
download | glib-ce8361217c1c9bd458eab55554a77d24210235cc.tar.gz |
Import all the highlevel socket classes from gnio
Diffstat (limited to 'gio/gsocketoutputstream.c')
-rw-r--r-- | gio/gsocketoutputstream.c | 259 |
1 files changed, 259 insertions, 0 deletions
diff --git a/gio/gsocketoutputstream.c b/gio/gsocketoutputstream.c new file mode 100644 index 000000000..0e53a5788 --- /dev/null +++ b/gio/gsocketoutputstream.c @@ -0,0 +1,259 @@ +/* GIO - GLib Input, Output and Streaming Library + * + * Copyright © 2008 Christian Kellner, Samuel Cormier-Iijima + * © 2009 codethink + * + * 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 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, write to the + * Free Software Foundation, Inc., 59 Temple Place, Suite 330, + * Boston, MA 02111-1307, USA. + * + * Authors: Christian Kellner <gicmo@gnome.org> + * Samuel Cormier-Iijima <sciyoshi@gmail.com> + * Ryan Lortie <desrt@desrt.ca> + */ + +#include "config.h" +#include "gsocketoutputstream.h" + +#include <gio/gsimpleasyncresult.h> +#include <gio/gcancellable.h> +#include "glibintl.h" + +#define g_socket_output_stream_get_type _g_socket_output_stream_get_type +G_DEFINE_TYPE (GSocketOutputStream, g_socket_output_stream, G_TYPE_OUTPUT_STREAM); + +enum +{ + PROP_0, + PROP_SOCKET +}; + +struct _GSocketOutputStreamPrivate +{ + GSocket *socket; + + /* pending operation metadata */ + GSimpleAsyncResult *result; + GCancellable *cancellable; + gboolean from_mainloop; + gconstpointer buffer; + gsize count; +}; + +static void +g_socket_output_stream_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GSocketOutputStream *stream = G_SOCKET_OUTPUT_STREAM (object); + + switch (prop_id) + { + case PROP_SOCKET: + g_value_set_object (value, stream->priv->socket); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +g_socket_output_stream_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GSocketOutputStream *stream = G_SOCKET_OUTPUT_STREAM (object); + + switch (prop_id) + { + case PROP_SOCKET: + stream->priv->socket = g_value_dup_object (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + } +} + +static void +g_socket_output_stream_finalize (GObject *object) +{ + GSocketOutputStream *stream = G_SOCKET_OUTPUT_STREAM (object); + + if (stream->priv->socket) + g_object_unref (stream->priv->socket); + + if (G_OBJECT_CLASS (g_socket_output_stream_parent_class)->finalize) + (*G_OBJECT_CLASS (g_socket_output_stream_parent_class)->finalize) (object); +} + +static gssize +g_socket_output_stream_write (GOutputStream *stream, + const void *buffer, + gsize count, + GCancellable *cancellable, + GError **error) +{ + GSocketOutputStream *onput_stream = G_SOCKET_OUTPUT_STREAM (stream); + + if (!g_socket_condition_wait (onput_stream->priv->socket, + G_IO_OUT, cancellable, error)) + return -1; + + return g_socket_send (onput_stream->priv->socket, buffer, count, error); +} + +static gboolean +g_socket_output_stream_write_ready (GSocket *socket, + GIOCondition condition, + GSocketOutputStream *stream) +{ + GSimpleAsyncResult *simple; + GError *error = NULL; + + simple = stream->priv->result; + stream->priv->result = NULL; + + if (!g_cancellable_set_error_if_cancelled (stream->priv->cancellable, + &error)) + { + gssize result; + + result = g_socket_send (stream->priv->socket, + stream->priv->buffer, + stream->priv->count, + &error); + if (result >= 0) + g_simple_async_result_set_op_res_gssize (simple, result); + } + + if (error) + { + g_simple_async_result_set_from_error (simple, error); + g_error_free (error); + } + + if (stream->priv->cancellable) + g_object_unref (stream->priv->cancellable); + + if (stream->priv->from_mainloop) + g_simple_async_result_complete (simple); + else + g_simple_async_result_complete_in_idle (simple); + + g_object_unref (simple); + + return FALSE; +} + +static void +g_socket_output_stream_write_async (GOutputStream *stream, + const void *buffer, + gsize count, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GSocketOutputStream *output_stream = G_SOCKET_OUTPUT_STREAM (stream); + + g_assert (output_stream->priv->result == NULL); + + output_stream->priv->result = + g_simple_async_result_new (G_OBJECT (stream), callback, user_data, + g_socket_output_stream_write_async); + if (cancellable) + g_object_ref (cancellable); + output_stream->priv->cancellable = cancellable; + output_stream->priv->buffer = buffer; + output_stream->priv->count = count; + + if (!g_socket_condition_check (output_stream->priv->socket, G_IO_OUT)) + { + GSource *source; + + output_stream->priv->from_mainloop = TRUE; + source = g_socket_create_source (output_stream->priv->socket, + G_IO_OUT | G_IO_HUP | G_IO_ERR, + cancellable); + g_source_set_callback (source, + (GSourceFunc) g_socket_output_stream_write_ready, + g_object_ref (output_stream), g_object_unref); + g_source_attach (source, NULL); + g_source_unref (source); + } + else + { + output_stream->priv->from_mainloop = FALSE; + g_socket_output_stream_write_ready (output_stream->priv->socket, G_IO_OUT, output_stream); + } +} + +static gssize +g_socket_output_stream_write_finish (GOutputStream *stream, + GAsyncResult *result, + GError **error) +{ + GSimpleAsyncResult *simple; + gssize count; + + g_return_val_if_fail (G_IS_SOCKET_OUTPUT_STREAM (stream), -1); + + simple = G_SIMPLE_ASYNC_RESULT (result); + + g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == g_socket_output_stream_write_async); + + count = g_simple_async_result_get_op_res_gssize (simple); + + return count; +} + +static void +g_socket_output_stream_class_init (GSocketOutputStreamClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GOutputStreamClass *goutputstream_class = G_OUTPUT_STREAM_CLASS (klass); + + g_type_class_add_private (klass, sizeof (GSocketOutputStreamPrivate)); + + gobject_class->finalize = g_socket_output_stream_finalize; + gobject_class->get_property = g_socket_output_stream_get_property; + gobject_class->set_property = g_socket_output_stream_set_property; + + goutputstream_class->write_fn = g_socket_output_stream_write; + goutputstream_class->write_async = g_socket_output_stream_write_async; + goutputstream_class->write_finish = g_socket_output_stream_write_finish; + + g_object_class_install_property (gobject_class, PROP_SOCKET, + g_param_spec_object ("socket", + P_("socket"), + P_("The socket that this stream wraps"), + G_TYPE_SOCKET, G_PARAM_CONSTRUCT_ONLY | + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); +} + +static void +g_socket_output_stream_init (GSocketOutputStream *stream) +{ + stream->priv = G_TYPE_INSTANCE_GET_PRIVATE (stream, G_TYPE_SOCKET_OUTPUT_STREAM, GSocketOutputStreamPrivate); +} + +GSocketOutputStream * +_g_socket_output_stream_new (GSocket *socket) +{ + return G_SOCKET_OUTPUT_STREAM (g_object_new (G_TYPE_SOCKET_OUTPUT_STREAM, "socket", socket, NULL)); +} |