rtspsrc: Fix usage of IPv6 connections in SETUP
authorNirbheek Chauhan <nirbheek@centricular.com>
Tue, 1 Mar 2022 11:00:10 +0000 (16:30 +0530)
committerGStreamer Marge Bot <gitlab-merge-bot@gstreamer-foundation.org>
Tue, 27 Sep 2022 18:59:59 +0000 (18:59 +0000)
If the SETUP request returns an IPv6 server address in the Transport
field, we would generate an incorrect URI, and multiudpsink would fail
to initialize:

```
     rtspsrc gstrtspsrc.c:9780:dump_key_value:<source>    key: 'Transport', value: 'RTP/AVP;unicast;source=fe80::dc27:25ff:fe5e:bd13:8080;client_port=62696-62697;server_port=4000-4001'
...
     rtspsrc gstrtspsrc.c:4595:gst_rtspsrc_stream_configure_udp_sinks:<source> configure RTP UDP sink for fe80::dc27:25ff:fe5e:bd13:8080:4000
...
multiudpsink gstmultiudpsink.c:1229:gst_multiudpsink_configure_client:<udpsink0> error: Invalid address family (got 23)
```

We can't look at stream->is_ipv6 because we can't rely on the server
returning the right value there. In the issue reported about this,
server reported itself as `KuP RTSP Server/0.1`, and the SDP was:

```
c=IN IP4
m=video 54608 RTP/AVP 96
a=rtpmap:96 H264/90000
```

So we need to parse the string value and figure out the family
ourselves.

Fixes https://gitlab.freedesktop.org/gstreamer/gstreamer/-/issues/1058

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/1819>

subprojects/gst-plugins-good/gst/rtsp/gstrtspsrc.c

index b1afb33..a6eec43 100644 (file)
@@ -4383,12 +4383,43 @@ gst_rtspsrc_get_transport_info (GstRTSPSrc * src, GstRTSPStream * stream,
   }
 }
 
+static GstElement *
+element_make_from_addr (const GstURIType type, const char *addr_s,
+    int port, const char *name, GError ** error)
+{
+  GInetAddress *addr;
+  GstElement *element = NULL;
+  char *uri = NULL;
+
+  addr = g_inet_address_new_from_string (addr_s);
+
+  switch (g_inet_address_get_family (addr)) {
+    case G_SOCKET_FAMILY_IPV6:
+      uri = g_strdup_printf ("udp://[%s]:%i", addr_s, port);
+      break;
+    case G_SOCKET_FAMILY_INVALID:
+      GST_ERROR ("Unknown family type for %s", addr_s);
+      goto out;
+    case G_SOCKET_FAMILY_UNIX:
+      GST_ERROR ("Unexpected family type UNIX for %s", addr_s);
+      goto out;
+    case G_SOCKET_FAMILY_IPV4:
+      uri = g_strdup_printf ("udp://%s:%i", addr_s, port);
+      break;
+  }
+
+  element = gst_element_make_from_uri (type, uri, name, error);
+out:
+  g_object_unref (addr);
+  g_free (uri);
+  return element;
+}
+
 /* For multicast create UDP sources and join the multicast group. */
 static gboolean
 gst_rtspsrc_stream_configure_mcast (GstRTSPSrc * src, GstRTSPStream * stream,
     GstRTSPTransport * transport, GstPad ** outpad)
 {
-  gchar *uri;
   const gchar *destination;
   gint min, max;
 
@@ -4413,10 +4444,8 @@ gst_rtspsrc_stream_configure_mcast (GstRTSPSrc * src, GstRTSPStream * stream,
 
   /* creating UDP source for RTP */
   if (min != -1) {
-    uri = g_strdup_printf ("udp://%s:%d", destination, min);
     stream->udpsrc[0] =
-        gst_element_make_from_uri (GST_URI_SRC, uri, NULL, NULL);
-    g_free (uri);
+        element_make_from_addr (GST_URI_SRC, destination, min, NULL, NULL);
     if (stream->udpsrc[0] == NULL)
       goto no_element;
 
@@ -4440,10 +4469,8 @@ gst_rtspsrc_stream_configure_mcast (GstRTSPSrc * src, GstRTSPStream * stream,
   if (max != -1) {
     GstCaps *caps;
 
-    uri = g_strdup_printf ("udp://%s:%d", destination, max);
     stream->udpsrc[1] =
-        gst_element_make_from_uri (GST_URI_SRC, uri, NULL, NULL);
-    g_free (uri);
+        element_make_from_addr (GST_URI_SRC, destination, max, NULL, NULL);
     if (stream->udpsrc[1] == NULL)
       goto no_element;
 
@@ -4583,7 +4610,7 @@ gst_rtspsrc_stream_configure_udp_sinks (GstRTSPSrc * src,
   gint rtp_port, rtcp_port;
   gboolean do_rtp, do_rtcp;
   const gchar *destination;
-  gchar *uri, *name;
+  gchar *name;
   guint ttl = 0;
   GSocket *socket;
 
@@ -4607,10 +4634,8 @@ gst_rtspsrc_stream_configure_udp_sinks (GstRTSPSrc * src,
     GST_DEBUG_OBJECT (src, "configure RTP UDP sink for %s:%d", destination,
         rtp_port);
 
-    uri = g_strdup_printf ("udp://%s:%d", destination, rtp_port);
-    stream->udpsink[0] =
-        gst_element_make_from_uri (GST_URI_SINK, uri, NULL, NULL);
-    g_free (uri);
+    stream->udpsink[0] = element_make_from_addr (GST_URI_SINK, destination,
+        rtp_port, NULL, NULL);
     if (stream->udpsink[0] == NULL)
       goto no_sink_element;
 
@@ -4672,10 +4697,8 @@ gst_rtspsrc_stream_configure_udp_sinks (GstRTSPSrc * src,
     GST_DEBUG_OBJECT (src, "configure RTCP UDP sink for %s:%d", destination,
         rtcp_port);
 
-    uri = g_strdup_printf ("udp://%s:%d", destination, rtcp_port);
-    stream->udpsink[1] =
-        gst_element_make_from_uri (GST_URI_SINK, uri, NULL, NULL);
-    g_free (uri);
+    stream->udpsink[1] = element_make_from_addr (GST_URI_SINK, destination,
+        rtcp_port, NULL, NULL);
     if (stream->udpsink[1] == NULL)
       goto no_sink_element;