rtpsession: Drop packet if trying to send from non-internal source
authorStian Selnes <stian@pexip.com>
Tue, 13 Dec 2016 09:13:52 +0000 (10:13 +0100)
committerTim-Philipp Müller <tim@centricular.com>
Tue, 15 May 2018 09:34:29 +0000 (10:34 +0100)
If obtain_internal_source() returns a source that is not internal it
means there exists a non-internal source with the same ssrc. Such an
ssrc collision should be handled by sending a GstRTPCollision event
upstream and choose a new ssrc, but for now we simply drop the packet.
Trying to process the packet further will cause it to be pushed
usptream (!) since the source is not internal (see source_push_rtp()).

https://bugzilla.gnome.org/show_bug.cgi?id=795139

gst/rtpmanager/rtpsession.c
tests/check/elements/rtpsession.c

index 7b5aca0..18258c3 100644 (file)
@@ -3019,6 +3019,10 @@ rtp_session_send_rtp (RTPSession * sess, gpointer data, gboolean is_list,
   if (created)
     on_new_sender_ssrc (sess, source);
 
+  if (!source->internal)
+    /* FIXME: Send GstRTPCollision upstream  */
+    goto collision;
+
   prevsender = RTP_SOURCE_IS_SENDER (source);
   oldrate = source->bitrate;
 
@@ -3043,6 +3047,15 @@ invalid_packet:
     GST_DEBUG ("invalid RTP packet received");
     return GST_FLOW_OK;
   }
+collision:
+  {
+    g_object_unref (source);
+    gst_mini_object_unref (GST_MINI_OBJECT_CAST (data));
+    RTP_SESSION_UNLOCK (sess);
+    GST_WARNING ("non-internal source with same ssrc %08x, drop packet",
+        pinfo.ssrc);
+    return GST_FLOW_OK;
+  }
 }
 
 static void
index bc02fc2..b5ac097 100644 (file)
@@ -889,6 +889,48 @@ GST_START_TEST (test_receive_pli_no_sender_ssrc)
 
 GST_END_TEST;
 
+static void
+add_rtcp_sdes_packet (GstBuffer * gstbuf, guint32 ssrc, const char *cname)
+{
+  GstRTCPPacket packet;
+  GstRTCPBuffer buffer = GST_RTCP_BUFFER_INIT;
+
+  gst_rtcp_buffer_map (gstbuf, GST_MAP_READWRITE, &buffer);
+
+  fail_unless (gst_rtcp_buffer_add_packet (&buffer, GST_RTCP_TYPE_SDES,
+          &packet) == TRUE);
+  fail_unless (gst_rtcp_packet_sdes_add_item (&packet, ssrc) == TRUE);
+  fail_unless (gst_rtcp_packet_sdes_add_entry (&packet, GST_RTCP_SDES_CNAME,
+          strlen (cname), (const guint8 *) cname));
+
+  gst_rtcp_buffer_unmap (&buffer);
+}
+
+GST_START_TEST (test_ssrc_collision_when_sending)
+{
+  SessionHarness *h = session_harness_new ();
+  GstBuffer *buf = gst_rtcp_buffer_new (1400);
+
+/* Push SDES with identical SSRC as what we will use for sending RTP,
+   establishing this as a non-internal SSRC */
+  add_rtcp_sdes_packet (buf, 0x12345678, "test@foo.bar");
+  session_harness_recv_rtcp (h, buf);
+
+  /* Push RTP buffer making our internal SSRC=0x12345678 */
+  fail_unless_equals_int (GST_FLOW_OK,
+      session_harness_send_rtp (h, generate_test_buffer (0, 0x12345678)));
+
+  /* Verify the packet we just sent is not being boomeranged back to us
+     as a received packet! */
+  fail_unless_equals_int (0, gst_harness_buffers_in_queue (h->recv_rtp_h));
+
+  /* FIXME: verify a Collision event coming upstream! */
+
+  session_harness_free (h);
+}
+
+GST_END_TEST;
+
 GST_START_TEST (test_illegal_rtcp_fb_packet)
 {
   SessionHarness *h = session_harness_new ();
@@ -1007,6 +1049,7 @@ rtpsession_suite (void)
   tcase_add_test (tc_chain, test_receive_rtcp_app_packet);
   tcase_add_test (tc_chain, test_dont_lock_on_stats);
   tcase_add_test (tc_chain, test_ignore_suspicious_bye);
+  tcase_add_test (tc_chain, test_ssrc_collision_when_sending);
   tcase_add_test (tc_chain, test_illegal_rtcp_fb_packet);
   tcase_add_test (tc_chain, test_feedback_rtcp_race);
   tcase_add_test (tc_chain, test_receive_regular_pli);