rtsp-client: Avoid reuse of channel numbers for interleaved
[platform/upstream/gstreamer.git] / gst / rtsp-server / rtsp-client.c
index 92135f2..2e124f8 100644 (file)
@@ -1972,8 +1972,13 @@ default_configure_client_transport (GstRTSPClient * client,
 
     if ((ct->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) &&
         gst_rtsp_auth_check (GST_RTSP_AUTH_CHECK_TRANSPORT_CLIENT_SETTINGS) &&
-        (ct->destination != NULL))
+        (ct->destination != NULL)) {
+
+      if (!gst_rtsp_stream_verify_mcast_ttl (ctx->stream, ct->ttl))
+        goto error_ttl;
+
       use_client_settings = TRUE;
+    }
 
     /* We need to allocate the sockets for both families before starting
      * multiudpsink, otherwise multiudpsink won't accept new clients with
@@ -1981,26 +1986,42 @@ default_configure_client_transport (GstRTSPClient * client,
      */
     /* FIXME: could be more adequately solved by making it possible
      * to set a socket on multiudpsink after it has already been started */
-    if (!gst_rtsp_stream_allocate_udp_sockets (ctx->stream, G_SOCKET_FAMILY_IPV4, ct,
-            use_client_settings) && family == G_SOCKET_FAMILY_IPV4)
+    if (!gst_rtsp_stream_allocate_udp_sockets (ctx->stream,
+            G_SOCKET_FAMILY_IPV4, ct, use_client_settings)
+        && family == G_SOCKET_FAMILY_IPV4)
       goto error_allocating_ports;
 
-    if (!gst_rtsp_stream_allocate_udp_sockets (ctx->stream, G_SOCKET_FAMILY_IPV6, ct,
-            use_client_settings) && family == G_SOCKET_FAMILY_IPV6)
+    if (!gst_rtsp_stream_allocate_udp_sockets (ctx->stream,
+            G_SOCKET_FAMILY_IPV6, ct, use_client_settings)
+        && family == G_SOCKET_FAMILY_IPV6)
       goto error_allocating_ports;
 
     if (ct->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) {
-      GstRTSPAddress *addr = NULL;
-
       if (use_client_settings) {
-        /* the address has been successfully allocated, let's check if it's
-         * the one requested by the client */
-        addr = gst_rtsp_stream_reserve_address (ctx->stream, ct->destination,
-            ct->port.min, ct->port.max - ct->port.min + 1, ct->ttl);
+        /* FIXME: the address has been successfully allocated, however, in
+         * the use_client_settings case we need to verify that the allocated
+         * address is the one requested by the client and if this address is
+         * an allowed destination. Verifying this via the address pool in not
+         * the proper way as the address pool should only be used for choosing
+         * the server-selected address/port pairs. */
+        GSocket *rtp_socket;
+        guint ttl;
+
+        rtp_socket =
+            gst_rtsp_stream_get_rtp_multicast_socket (ctx->stream, family);
+        if (rtp_socket == NULL)
+          goto no_socket;
+        ttl = g_socket_get_multicast_ttl (rtp_socket);
+        g_object_unref (rtp_socket);
+        if (ct->ttl < ttl) {
+          /* use the maximum ttl that is requested by multicast clients */
+          GST_DEBUG ("requested ttl %u, but keeping ttl %u", ct->ttl, ttl);
+          ct->ttl = ttl;
+        }
 
-        if (addr == NULL)
-          goto no_address;
       } else {
+        GstRTSPAddress *addr = NULL;
+
         g_free (ct->destination);
         addr = gst_rtsp_stream_get_multicast_address (ctx->stream, family);
         if (addr == NULL)
@@ -2009,9 +2030,13 @@ default_configure_client_transport (GstRTSPClient * client,
         ct->port.min = addr->port;
         ct->port.max = addr->port + addr->n_ports - 1;
         ct->ttl = addr->ttl;
+        gst_rtsp_address_free (addr);
       }
 
-      gst_rtsp_address_free (addr);
+      if (!gst_rtsp_stream_add_multicast_client_address (ctx->stream,
+              ct->destination, ct->port.min, ct->port.max, family))
+        goto error_mcast_transport;
+
     } else {
       GstRTSPUrl *url;
 
@@ -2059,11 +2084,27 @@ default_configure_client_transport (GstRTSPClient * client,
         gst_rtsp_session_media_alloc_channels (ctx->sessmedia,
             &ct->interleaved);
       }
+      /* alloc new channels if they are already taken */
+      while (g_hash_table_contains (priv->transports,
+              GINT_TO_POINTER (ct->interleaved.min))
+          || g_hash_table_contains (priv->transports,
+              GINT_TO_POINTER (ct->interleaved.max))) {
+        gst_rtsp_session_media_alloc_channels (ctx->sessmedia,
+            &ct->interleaved);
+        if (ct->interleaved.max > 255)
+          goto error_allocating_channels;
+      }
     }
   }
   return TRUE;
 
   /* ERRORS */
+error_ttl:
+  {
+    GST_ERROR_OBJECT (client,
+        "Failed to allocate UDP ports: invalid ttl value");
+    return FALSE;
+  }
 error_allocating_ports:
   {
     GST_ERROR_OBJECT (client, "Failed to allocate UDP ports");
@@ -2074,6 +2115,21 @@ no_address:
     GST_ERROR_OBJECT (client, "Failed to acquire address for stream");
     return FALSE;
   }
+no_socket:
+  {
+    GST_ERROR_OBJECT (client, "Failed to get UDP socket");
+    return FALSE;
+  }
+error_mcast_transport:
+  {
+    GST_ERROR_OBJECT (client, "Failed to add multicast client transport");
+    return FALSE;
+  }
+error_allocating_channels:
+  {
+    GST_ERROR_OBJECT (client, "Failed to allocate interleaved channels");
+    return FALSE;
+  }
 }
 
 static GstRTSPTransport *