summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXavier Claessens <xavier.claessens@collabora.co.uk>2013-12-04 14:09:18 -0500
committerXavier Claessens <xavier.claessens@collabora.co.uk>2014-01-03 10:37:58 -0500
commit4480d2b9f5bb72c8acf0e9f712c6f8346a174f91 (patch)
tree7b6adcbb0800a18f6e29c5bffa5b4604fef377ef
parent441fed1e0828b8fc6b94bd5f66c7cb222d09ef20 (diff)
downloadtelepathy-glib-4480d2b9f5bb72c8acf0e9f712c6f8346a174f91.tar.gz
TpFileTransferChannel: Fix possible crashes.
tp_file_transfer_channel_accept_file_async() and tp_file_transfer_channel_provide_file_async() operations are supposed to complete as soon as the CM returns from AcceptFile or ProvideFile. That means that we cannot call operation_failed() for streaming errors. We also have to keep a ref on self while streaming the file to avoid a crash in the callback when we dereference self. This means that the client app cannot cancel the ongoing streaming by unreffing the channel, replying on dispose calling g_cancellable_cancel(). It can still be doing using g_object_run_dispose() though. To make it cleaner we should probably add tp_file_transfer_channel_cancel(). The spec does not provide any way for the streaming client to inform the CM and other clients about the error occured while streaming. TpFileTransferChannel API does not even have a way to propagate that error to the user.
-rw-r--r--telepathy-glib/file-transfer-channel.c37
1 files changed, 16 insertions, 21 deletions
diff --git a/telepathy-glib/file-transfer-channel.c b/telepathy-glib/file-transfer-channel.c
index d3067da90..f74a297e4 100644
--- a/telepathy-glib/file-transfer-channel.c
+++ b/telepathy-glib/file-transfer-channel.c
@@ -184,6 +184,7 @@ static void
operation_failed (TpFileTransferChannel *self,
GError *error)
{
+ g_assert (self->priv->result != NULL);
g_simple_async_result_take_error (self->priv->result, error);
g_simple_async_result_complete_in_idle (self->priv->result);
tp_clear_object (&self->priv->result);
@@ -202,12 +203,11 @@ stream_close_cb (GObject *source,
{
DEBUG ("Failed to close stream: %s\n", error->message);
g_clear_error (&error);
- /* Don't fail the accept/provide operation as this is just a
- * close operation. */
}
/* Now that this is closed in both ways, let's just remove it. */
g_clear_object (&self->priv->stream);
+ g_object_unref (self);
}
static void
@@ -222,13 +222,13 @@ splice_stream_ready_cb (GObject *output,
&error);
if (error != NULL && !g_cancellable_is_cancelled (self->priv->cancellable))
- {
- DEBUG ("splice operation failed: %s", error->message);
- operation_failed (self, error);
- }
+ DEBUG ("splice operation failed: %s", error->message);
+ g_clear_error (&error);
g_io_stream_close_async (self->priv->stream, G_PRIORITY_DEFAULT,
- NULL, stream_close_cb, self);
+ NULL, stream_close_cb, g_object_ref (self));
+
+ g_object_unref (self);
}
static void
@@ -241,10 +241,7 @@ client_socket_connected (TpFileTransferChannel *self)
self->priv->client_socket);
if (conn == NULL)
{
- error = g_error_new (G_IO_ERROR, G_IO_ERROR_FAILED,
- "Failed to create client connection");
- DEBUG ("%s", error->message);
- operation_failed (self, error);
+ DEBUG ("Failed to create client connection");
return;
}
@@ -262,9 +259,8 @@ client_socket_connected (TpFileTransferChannel *self)
conn, byte, NULL, &error))
{
DEBUG ("Failed to send credentials: %s", error->message);
-
- operation_failed (self, error);
g_object_unref (conn);
+ g_clear_error (&error);
return;
}
}
@@ -282,7 +278,7 @@ client_socket_connected (TpFileTransferChannel *self)
G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE |
G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET,
G_PRIORITY_DEFAULT, self->priv->cancellable,
- splice_stream_ready_cb, self);
+ splice_stream_ready_cb, g_object_ref (self));
}
else
{
@@ -294,7 +290,7 @@ client_socket_connected (TpFileTransferChannel *self)
G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE |
G_OUTPUT_STREAM_SPLICE_CLOSE_TARGET,
G_PRIORITY_DEFAULT, self->priv->cancellable,
- splice_stream_ready_cb, self);
+ splice_stream_ready_cb, g_object_ref (self));
}
}
@@ -308,8 +304,7 @@ client_socket_cb (GSocket *socket,
if (!g_socket_check_connect_result (socket, &error))
{
DEBUG ("Failed to connect to socket: %s", error->message);
-
- operation_failed (self, error);
+ g_clear_error (&error);
return FALSE;
}
@@ -1122,8 +1117,8 @@ start_transfer (TpFileTransferChannel *self)
NULL);
g_source_attach (source, g_main_context_get_thread_default ());
- g_source_set_callback (source, (GSourceFunc) client_socket_cb, self,
- NULL);
+ g_source_set_callback (source, (GSourceFunc) client_socket_cb,
+ g_object_ref (self), g_object_unref);
g_error_free (error);
g_source_unref (source);
@@ -1131,8 +1126,7 @@ start_transfer (TpFileTransferChannel *self)
else
{
DEBUG ("Failed to connect to socket: %s:", error->message);
-
- operation_failed (self, error);
+ g_clear_error (&error);
}
}
@@ -1171,6 +1165,7 @@ accept_or_provide_file_cb (TpChannel *proxy,
}
g_simple_async_result_complete_in_idle (self->priv->result);
+ g_clear_object (&self->priv->result);
}
static gboolean