[Telepathy-commits] [telepathy-gabble/master] Ignore Google relay responses when session dies

Will Thompson will.thompson at collabora.co.uk
Fri Mar 20 06:11:53 PDT 2009


This fixes fd.o #20764.

Reviewed-by: Simon McVittie <simon.mcvittie at collabora.co.uk>
---
 src/media-channel.c                  |   28 ++++++++++++++++++++++
 tests/twisted/jingle/google-relay.py |   42 +++++++++++++++++++++++++++++-----
 2 files changed, 64 insertions(+), 6 deletions(-)

diff --git a/src/media-channel.c b/src/media-channel.c
index f76a913..8baf9db 100644
--- a/src/media-channel.c
+++ b/src/media-channel.c
@@ -152,6 +152,9 @@ struct _GabbleMediaChannelPrivate
   /* list of PendingStreamRequest* in no particular order */
   GList *pending_stream_requests;
 
+  /* list of StreamCreationData* in no particular order */
+  GList *stream_creation_datas;
+
   guint next_stream_id;
 
   TpLocalHoldState hold_state;
@@ -202,6 +205,7 @@ static void create_stream_from_content (GabbleMediaChannel *chan,
     GabbleJingleContent *c);
 static gboolean contact_is_media_capable (GabbleMediaChannel *chan, TpHandle peer,
     gboolean *wait);
+static void stream_creation_data_cancel (gpointer p, gpointer unused);
 
 static void
 _create_streams (GabbleMediaChannel *chan)
@@ -735,6 +739,11 @@ gabble_media_channel_dispose (GObject *object)
 
   priv->dispose_has_run = TRUE;
 
+  /* StreamCreationData * holds a reference to the media channel; thus, we
+   * shouldn't be disposed till they've all gone away.
+   */
+  g_assert (priv->stream_creation_datas == NULL);
+
   if (priv->delayed_request_streams != NULL)
     {
       g_ptr_array_foreach (priv->delayed_request_streams,
@@ -2051,6 +2060,10 @@ session_terminated_cb (GabbleJingleSession *session,
       TP_CHANNEL_GROUP_FLAG_CAN_ADD,
       TP_CHANNEL_GROUP_FLAG_CAN_REMOVE);
 
+  /* Ignore any Google relay session responses we're waiting for. */
+  g_list_foreach (priv->stream_creation_datas, stream_creation_data_cancel,
+      NULL);
+
   /* any contents that we were waiting for have now lost */
   g_list_foreach (priv->pending_stream_requests,
       (GFunc) pending_stream_request_free, NULL);
@@ -2548,9 +2561,19 @@ typedef struct {
 } StreamCreationData;
 
 static void
+stream_creation_data_cancel (gpointer p,
+                             gpointer unused)
+{
+  StreamCreationData *d = p;
+
+  d->content = NULL;
+}
+
+static void
 stream_creation_data_free (gpointer p)
 {
   StreamCreationData *d = p;
+  GabbleMediaChannelPrivate *priv = d->self->priv;
 
   g_free (d->name);
   g_free (d->nat_traversal);
@@ -2561,6 +2584,8 @@ stream_creation_data_free (gpointer p)
       g_object_unref (d->content);
     }
 
+  priv->stream_creation_datas = g_list_remove (priv->stream_creation_datas, d);
+
   g_object_unref (d->self);
   g_slice_free (StreamCreationData, d);
 }
@@ -2675,6 +2700,9 @@ create_stream_from_content (GabbleMediaChannel *self,
       g_idle_add_full (G_PRIORITY_DEFAULT, construct_stream_later_cb,
           d, stream_creation_data_free);
     }
+
+  self->priv->stream_creation_datas = g_list_prepend (
+      self->priv->stream_creation_datas, d);
 }
 
 static void
diff --git a/tests/twisted/jingle/google-relay.py b/tests/twisted/jingle/google-relay.py
index 078a253..519ad0e 100644
--- a/tests/twisted/jingle/google-relay.py
+++ b/tests/twisted/jingle/google-relay.py
@@ -4,8 +4,8 @@ Test getting relay from Google jingleinfo
 
 from gabbletest import exec_test, make_result_iq, sync_stream, \
         GoogleXmlStream
-from servicetest import make_channel_proxy, unwrap, tp_path_prefix, \
-        EventPattern, call_async
+from servicetest import make_channel_proxy, tp_path_prefix, \
+        EventPattern, call_async, sync_dbus
 import jingletest
 import gabbletest
 import constants as c
@@ -68,7 +68,7 @@ magic_cookie=MMMMMMMM
 """ % (http_req, http_req))
         http_req += 1
 
-def test(q, bus, conn, stream, incoming=True):
+def test(q, bus, conn, stream, incoming=True, too_slow=False):
     jt = jingletest.JingleTest(stream, 'test at localhost', 'foo at bar.com/Foo')
 
     # If we need to override remote caps, feats, codecs or caps,
@@ -154,6 +154,9 @@ def test(q, bus, conn, stream, incoming=True):
         # We're pending because of remote_handle
         e = q.expect('dbus-signal', signal='MembersChanged',
                  args=[u'', [], [], [1L], [], remote_handle, 0])
+
+        media_chan = make_channel_proxy(conn, tp_path_prefix + e.path,
+            'Channel.Interface.Group')
     else:
         call_async(q, conn.Requests, 'CreateChannel',
                 { 'org.freedesktop.Telepathy.Channel.ChannelType':
@@ -168,6 +171,7 @@ def test(q, bus, conn, stream, incoming=True):
             EventPattern('dbus-signal', signal='NewChannels'),
             )
         path = ret.value[0]
+        media_chan = make_channel_proxy(conn, path, 'Channel.Interface.Group')
         media_iface = make_channel_proxy(conn, path,
                 'Channel.Type.StreamedMedia')
         call_async(q, media_iface, 'RequestStreams',
@@ -177,6 +181,10 @@ def test(q, bus, conn, stream, incoming=True):
     e = q.expect('dbus-signal', signal='NewSessionHandler')
     assert e.args[1] == 'rtp'
 
+    if too_slow:
+        test_too_slow(q, bus, conn, stream, httpd, media_chan)
+        return
+
     # In response to the streams call, we now have two HTTP requests
     # (for RTP and RTCP)
     httpd.handle_request()
@@ -192,8 +200,6 @@ def test(q, bus, conn, stream, incoming=True):
     e = q.expect('dbus-signal', signal='NewStreamHandler')
     stream_handler = make_channel_proxy(conn, e.args[0], 'Media.StreamHandler')
 
-    media_chan = make_channel_proxy(conn, tp_path_prefix + e.path, 'Channel.Interface.Group')
-
     # Exercise channel properties
     channel_props = media_chan.GetAll(
             'org.freedesktop.Telepathy.Channel',
@@ -301,7 +307,25 @@ def test(q, bus, conn, stream, incoming=True):
     conn.Disconnect()
     q.expect('dbus-signal', signal='StatusChanged', args=[2, 1])
 
-    return True
+def test_too_slow(q, bus, conn, stream, httpd, media_chan):
+    """
+    Regression test for a bug where if the channel was closed before the HTTP
+    responses arrived, the responses finally arriving crashed Gabble.
+    """
+
+    # User gets bored, and closes the channel.
+    call_async(q, media_chan, 'Close', dbus_interface=c.CHANNEL)
+    q.expect('dbus-signal', signal='Closed')
+
+    # Now Google answers!
+    httpd.handle_request()
+    httpd.handle_request()
+
+    # Make a misc method call to check that Gabble's still alive.
+    sync_dbus(bus, q, conn)
+
+    conn.Disconnect()
+    q.expect('dbus-signal', signal='StatusChanged', args=[2, 1])
 
 
 if __name__ == '__main__':
@@ -309,3 +333,9 @@ if __name__ == '__main__':
             protocol=GoogleXmlStream)
     exec_test(lambda q, b, c, s: test(q, b, c, s, incoming=False),
             protocol=GoogleXmlStream)
+    exec_test(lambda q, b, c, s: test(q, b, c, s, incoming=True,
+                                      too_slow=True),
+            protocol=GoogleXmlStream)
+    exec_test(lambda q, b, c, s: test(q, b, c, s, incoming=False,
+                                      too_slow=True),
+            protocol=GoogleXmlStream)
-- 
1.5.6.5



More information about the telepathy-commits mailing list