diff options
author | Xavier Claessens <xclaesse@gmail.com> | 2010-12-16 14:08:53 +0100 |
---|---|---|
committer | Xavier Claessens <xclaesse@gmail.com> | 2010-12-16 14:08:53 +0100 |
commit | ca9a35429e173abedb0408cfe18a0bd57af7af59 (patch) | |
tree | 64da52badea4c24e5c24dde2e3234da0f3fa8254 | |
parent | 67129bd663c7ed84fc478acc3fcd5aaef40c4e53 (diff) |
Copy the updated version of g_io_stream_splice that got merged into GLib 2.27.6
-rw-r--r-- | configure.ac | 2 | ||||
-rw-r--r-- | src/client.c | 3 | ||||
-rw-r--r-- | src/common.c | 160 | ||||
-rw-r--r-- | src/common.h | 21 | ||||
-rw-r--r-- | src/service.c | 3 | ||||
-rw-r--r-- | src/vinagre/tab.c | 3 |
6 files changed, 162 insertions, 30 deletions
diff --git a/configure.ac b/configure.ac index 7edbbe6..7b8c158 100644 --- a/configure.ac +++ b/configure.ac @@ -27,7 +27,7 @@ IT_PROG_INTLTOOL([0.35.0]) PKG_CHECK_MODULES(SSH_CONTACT, [ - telepathy-glib >= 0.13.2 + telepathy-glib >= 0.13.9 glib-2.0 >= 2.24 gio-2.0 ]) diff --git a/src/client.c b/src/client.c index f891555..5478547 100644 --- a/src/client.c +++ b/src/client.c @@ -135,7 +135,8 @@ ssh_socket_connected_cb (GObject *source_object, /* Splice tube and ssh connections */ _g_io_stream_splice_async (G_IO_STREAM (context->tube_connection), - G_IO_STREAM (context->ssh_connection), splice_cb, context); + G_IO_STREAM (context->ssh_connection), _G_IO_STREAM_SPLICE_NONE, + G_PRIORITY_DEFAULT, NULL, splice_cb, context); } static void diff --git a/src/common.c b/src/common.c index 0965114..54f18b3 100644 --- a/src/common.c +++ b/src/common.c @@ -26,9 +26,14 @@ typedef struct { GIOStream *stream1; GIOStream *stream2; + _GIOStreamSpliceFlags flags; + gint io_priority; + GCancellable *cancellable; + gulong cancelled_id; GCancellable *op1_cancellable; GCancellable *op2_cancellable; - gboolean completed:1; + guint completed; + GError *error; } SpliceContext; static void @@ -36,79 +41,191 @@ splice_context_free (SpliceContext *ctx) { g_object_unref (ctx->stream1); g_object_unref (ctx->stream2); + if (ctx->cancellable != NULL) + g_object_unref (ctx->cancellable); g_object_unref (ctx->op1_cancellable); g_object_unref (ctx->op2_cancellable); + g_clear_error (&ctx->error); g_slice_free (SpliceContext, ctx); } static void -splice_cb (GObject *ostream, - GAsyncResult *res, - gpointer user_data) +splice_complete (GSimpleAsyncResult *simple, + SpliceContext *ctx) +{ + if (ctx->cancelled_id != 0) + g_cancellable_disconnect (ctx->cancellable, ctx->cancelled_id); + ctx->cancelled_id = 0; + + if (ctx->error != NULL) + g_simple_async_result_set_from_error (simple, ctx->error); + g_simple_async_result_complete (simple); +} + +static void +splice_close_cb (GObject *iostream, + GAsyncResult *res, + gpointer user_data) { GSimpleAsyncResult *simple = user_data; SpliceContext *ctx; GError *error = NULL; - g_output_stream_splice_finish (G_OUTPUT_STREAM (ostream), res, &error); + g_io_stream_close_finish (G_IO_STREAM (iostream), res, &error); ctx = g_simple_async_result_get_op_res_gpointer (simple); - if (!ctx->completed) - { - ctx->completed = TRUE; + ctx->completed++; + + /* Keep the first error that occured */ + if (error != NULL && ctx->error == NULL) + ctx->error = error; + else + g_clear_error (&error); - if (error != NULL) - g_simple_async_result_set_from_error (simple, error); - g_simple_async_result_complete_in_idle (simple); + /* If all operations are done, complete now */ + if (ctx->completed == 4) + splice_complete (simple, ctx); + + g_object_unref (simple); +} + +static void +splice_cb (GObject *ostream, + GAsyncResult *res, + gpointer user_data) +{ + GSimpleAsyncResult *simple = user_data; + SpliceContext *ctx; + GError *error = NULL; + + g_output_stream_splice_finish (G_OUTPUT_STREAM (ostream), res, &error); + ctx = g_simple_async_result_get_op_res_gpointer (simple); + ctx->completed++; + + /* ignore cancellation error if it was not requested by the user */ + if (error != NULL && + g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED) && + (ctx->cancellable == NULL || + !g_cancellable_is_cancelled (ctx->cancellable))) + g_clear_error (&error); + + /* Keep the first error that occured */ + if (error != NULL && ctx->error == NULL) + ctx->error = error; + else + g_clear_error (&error); + + if (ctx->completed == 1 && + (ctx->flags & _G_IO_STREAM_SPLICE_WAIT_FOR_BOTH) == 0) + { + /* We don't want to wait for the 2nd operation to finish, cancel it */ g_cancellable_cancel (ctx->op1_cancellable); g_cancellable_cancel (ctx->op2_cancellable); } + else if (ctx->completed == 2) + { + if (ctx->cancellable == NULL || + !g_cancellable_is_cancelled (ctx->cancellable)) + { + g_cancellable_reset (ctx->op1_cancellable); + g_cancellable_reset (ctx->op2_cancellable); + } + + /* Close the IO streams if needed */ + if ((ctx->flags & _G_IO_STREAM_SPLICE_CLOSE_STREAM1) != 0) + g_io_stream_close_async (ctx->stream1, ctx->io_priority, + ctx->op1_cancellable, splice_close_cb, g_object_ref (simple)); + else + ctx->completed++; + + if ((ctx->flags & _G_IO_STREAM_SPLICE_CLOSE_STREAM2) != 0) + g_io_stream_close_async (ctx->stream2, ctx->io_priority, + ctx->op2_cancellable, splice_close_cb, g_object_ref (simple)); + else + ctx->completed++; + + /* If all operations are done, complete now */ + if (ctx->completed == 4) + splice_complete (simple, ctx); + } - g_clear_error (&error); g_object_unref (simple); } +static void +splice_cancelled_cb (GCancellable *cancellable, + GSimpleAsyncResult *simple) +{ + SpliceContext *ctx; + + ctx = g_simple_async_result_get_op_res_gpointer (simple); + g_cancellable_cancel (ctx->op1_cancellable); + g_cancellable_cancel (ctx->op2_cancellable); +} + void -_g_io_stream_splice_async (GIOStream *stream1, - GIOStream *stream2, - GAsyncReadyCallback callback, - gpointer user_data) +_g_io_stream_splice_async (GIOStream *stream1, + GIOStream *stream2, + _GIOStreamSpliceFlags flags, + gint io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) { GSimpleAsyncResult *simple; SpliceContext *ctx; GInputStream *istream; GOutputStream *ostream; + if (cancellable != NULL && g_cancellable_is_cancelled (cancellable)) + { + g_simple_async_report_error_in_idle (NULL, callback, + user_data, G_IO_ERROR, G_IO_ERROR_CANCELLED, + "Operation has been cancelled"); + return; + } + ctx = g_slice_new0 (SpliceContext); ctx->stream1 = g_object_ref (stream1); ctx->stream2 = g_object_ref (stream2); + ctx->flags = flags; + ctx->io_priority = io_priority; ctx->op1_cancellable = g_cancellable_new (); ctx->op2_cancellable = g_cancellable_new (); + ctx->completed = 0; simple = g_simple_async_result_new (NULL, callback, user_data, _g_io_stream_splice_finish); g_simple_async_result_set_op_res_gpointer (simple, ctx, (GDestroyNotify) splice_context_free); + if (cancellable != NULL) + { + ctx->cancellable = g_object_ref (cancellable); + ctx->cancelled_id = g_cancellable_connect (cancellable, + G_CALLBACK (splice_cancelled_cb), g_object_ref (simple), + g_object_unref); + } + istream = g_io_stream_get_input_stream (stream1); ostream = g_io_stream_get_output_stream (stream2); g_output_stream_splice_async (ostream, istream, G_OUTPUT_STREAM_SPLICE_NONE, - G_PRIORITY_DEFAULT, ctx->op1_cancellable, splice_cb, + io_priority, ctx->op1_cancellable, splice_cb, g_object_ref (simple)); - + istream = g_io_stream_get_input_stream (stream2); ostream = g_io_stream_get_output_stream (stream1); g_output_stream_splice_async (ostream, istream, G_OUTPUT_STREAM_SPLICE_NONE, - G_PRIORITY_DEFAULT, ctx->op2_cancellable, splice_cb, + io_priority, ctx->op2_cancellable, splice_cb, g_object_ref (simple)); g_object_unref (simple); } gboolean -_g_io_stream_splice_finish (GAsyncResult *result, - GError **error) +_g_io_stream_splice_finish (GAsyncResult *result, + GError **error) { GSimpleAsyncResult *simple; @@ -124,4 +241,3 @@ _g_io_stream_splice_finish (GAsyncResult *result, return TRUE; } - diff --git a/src/common.h b/src/common.h index f238ce7..f05e3ab 100644 --- a/src/common.h +++ b/src/common.h @@ -27,10 +27,23 @@ G_BEGIN_DECLS -void _g_io_stream_splice_async (GIOStream *stream1, GIOStream *stream2, - GAsyncReadyCallback callback, gpointer user_data); - -gboolean _g_io_stream_splice_finish (GAsyncResult *result, GError **error); +typedef enum { + _G_IO_STREAM_SPLICE_NONE = 0, + _G_IO_STREAM_SPLICE_CLOSE_STREAM1 = (1 << 0), + _G_IO_STREAM_SPLICE_CLOSE_STREAM2 = (1 << 1), + _G_IO_STREAM_SPLICE_WAIT_FOR_BOTH = (1 << 2), +} _GIOStreamSpliceFlags; + +void _g_io_stream_splice_async (GIOStream *stream1, + GIOStream *stream2, + _GIOStreamSpliceFlags flags, + int io_priority, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +gboolean _g_io_stream_splice_finish (GAsyncResult *result, + GError **error); G_END_DECLS diff --git a/src/service.c b/src/service.c index f85ca93..1ca5975 100644 --- a/src/service.c +++ b/src/service.c @@ -102,7 +102,8 @@ accept_tube_cb (GObject *object, /* Splice tube and ssh connections */ _g_io_stream_splice_async (G_IO_STREAM (tube_connection), - G_IO_STREAM (sshd_connection), splice_cb, channel); + G_IO_STREAM (sshd_connection), _G_IO_STREAM_SPLICE_NONE, + G_PRIORITY_DEFAULT, NULL, splice_cb, channel); OUT: diff --git a/src/vinagre/tab.c b/src/vinagre/tab.c index 61940e5..bcccb56 100644 --- a/src/vinagre/tab.c +++ b/src/vinagre/tab.c @@ -175,7 +175,8 @@ ssh_socket_connected_cb (GObject *source_object, /* Splice tube and ssh connections */ _g_io_stream_splice_async (G_IO_STREAM (self->priv->tube_connection), - G_IO_STREAM (self->priv->ssh_connection), splice_cb, self); + G_IO_STREAM (self->priv->ssh_connection), _G_IO_STREAM_SPLICE_NONE, + G_PRIORITY_DEFAULT, NULL, splice_cb, self); } static void |