From: Patricia Muscalu Date: Wed, 25 Jul 2018 13:33:18 +0000 (+0200) Subject: stream: Choose the maximum ttl value provided by multicast clients X-Git-Tag: 1.19.3~495^2~231 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=4c6cecf5d659fc194f86e115737b3df1120d3914;p=platform%2Fupstream%2Fgstreamer.git stream: Choose the maximum ttl value provided by multicast clients The maximum ttl value provided so far by the multicast clients will be chosen and reported in the response to the current client request. Change-Id: I5408646e3b5a0a224d907ae215bdea60c4f1905f https://bugzilla.gnome.org/show_bug.cgi?id=793441 --- diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c index 01e63bf..e89203d 100644 --- a/gst/rtsp-server/rtsp-client.c +++ b/gst/rtsp-server/rtsp-client.c @@ -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 @@ -1990,14 +1995,29 @@ default_configure_client_transport (GstRTSPClient * client, goto error_allocating_ports; if (ct->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) { - /* 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. */ - - if (!use_client_settings) { + if (use_client_settings) { + /* 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; + } + + } else { GstRTSPAddress *addr = NULL; g_free (ct->destination); @@ -2062,6 +2082,12 @@ default_configure_client_transport (GstRTSPClient * client, 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"); @@ -2072,6 +2098,11 @@ 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; + } } static GstRTSPTransport * diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c index 0d17718..33b6ff1 100644 --- a/gst/rtsp-server/rtsp-stream.c +++ b/gst/rtsp-server/rtsp-stream.c @@ -1497,6 +1497,12 @@ again: g_clear_object (&inetaddr); + if (multicast && (ct->ttl > 0) && (ct->ttl <= priv->max_mcast_ttl)) { + GST_DEBUG ("setting mcast ttl to %d", ct->ttl); + g_socket_set_multicast_ttl (rtp_socket, ct->ttl); + g_socket_set_multicast_ttl (rtcp_socket, ct->ttl); + } + socket_out[0] = rtp_socket; socket_out[1] = rtcp_socket; *server_addr_out = addr; @@ -2006,6 +2012,29 @@ gst_rtsp_stream_get_max_mcast_ttl (GstRTSPStream * stream) return ttl; } +/** + * gst_rtsp_stream_verify_mcast_ttl: + * @stream: a #GstRTSPStream + * @ttl: a requested multicast ttl + * + * Check if the requested multicast ttl value is allowed. + * + * Returns: TRUE if the requested ttl value is allowed. + * + */ +gboolean +gst_rtsp_stream_verify_mcast_ttl (GstRTSPStream * stream, guint ttl) +{ + gboolean res = FALSE; + + g_mutex_lock (&stream->priv->lock); + if ((ttl > 0) && (ttl <= stream->priv->max_mcast_ttl)) + res = TRUE; + g_mutex_unlock (&stream->priv->lock); + + return res; +} + /* executed from streaming thread */ static void caps_notify (GstPad * pad, GParamSpec * unused, GstRTSPStream * stream) @@ -4058,7 +4087,6 @@ update_transport (GstRTSPStream * stream, GstRTSPStreamTransport * trans, if (!check_mcast_part_for_transport (stream, tr)) goto mcast_error; - /* FIXME: Is it ok to set ttl-mc if media is shared? */ if (tr->ttl > 0) { GST_INFO ("setting ttl-mc %d", tr->ttl); if (priv->mcast_udpsink[0]) diff --git a/gst/rtsp-server/rtsp-stream.h b/gst/rtsp-server/rtsp-stream.h index 1ee146d..ea21858 100644 --- a/gst/rtsp-server/rtsp-stream.h +++ b/gst/rtsp-server/rtsp-stream.h @@ -299,6 +299,9 @@ GST_RTSP_SERVER_API guint gst_rtsp_stream_get_max_mcast_ttl (GstRTSPStream *stream); GST_RTSP_SERVER_API +gboolean gst_rtsp_stream_verify_mcast_ttl (GstRTSPStream *stream, guint ttl); + +GST_RTSP_SERVER_API gboolean gst_rtsp_stream_complete_stream (GstRTSPStream * stream, const GstRTSPTransport * transport); GST_RTSP_SERVER_API diff --git a/tests/check/gst/client.c b/tests/check/gst/client.c index d4fdd9e..a420f65 100644 --- a/tests/check/gst/client.c +++ b/tests/check/gst/client.c @@ -542,6 +542,35 @@ test_setup_response_200_multicast (GstRTSPClient * client, } static gboolean +test_setup_response_461 (GstRTSPClient * client, + GstRTSPMessage * response, gboolean close, gpointer user_data) +{ + GstRTSPStatusCode code; + const gchar *reason; + GstRTSPVersion version; + gchar *str; + + fail_unless (expected_transport == NULL); + + fail_unless (gst_rtsp_message_get_type (response) == + GST_RTSP_MESSAGE_RESPONSE); + + fail_unless (gst_rtsp_message_parse_response (response, &code, &reason, + &version) + == GST_RTSP_OK); + fail_unless (code == GST_RTSP_STS_UNSUPPORTED_TRANSPORT); + fail_unless (g_str_equal (reason, "Unsupported transport")); + fail_unless (version == GST_RTSP_VERSION_1_0); + + fail_unless (gst_rtsp_message_get_header (response, GST_RTSP_HDR_CSEQ, &str, + 0) == GST_RTSP_OK); + fail_unless (atoi (str) == cseq++); + + + return TRUE; +} + +static gboolean test_teardown_response_200 (GstRTSPClient * client, GstRTSPMessage * response, gboolean close, gpointer user_data) { @@ -584,7 +613,7 @@ send_teardown (GstRTSPClient * client) } static GstRTSPClient * -setup_multicast_client (void) +setup_multicast_client (guint max_ttl) { GstRTSPClient *client; GstRTSPSessionPool *session_pool; @@ -611,6 +640,7 @@ setup_multicast_client (void) "media.factory.construct", G_TYPE_BOOLEAN, TRUE, NULL); gst_rtsp_mount_points_add_factory (mount_points, "/test", factory); gst_rtsp_client_set_mount_points (client, mount_points); + gst_rtsp_media_factory_set_max_mcast_ttl (factory, max_ttl); thread_pool = gst_rtsp_thread_pool_new (); gst_rtsp_client_set_thread_pool (client, thread_pool); @@ -629,7 +659,7 @@ GST_START_TEST (test_client_multicast_transport_404) GstRTSPMessage request = { 0, }; gchar *str; - client = setup_multicast_client (); + client = setup_multicast_client (1); /* simple SETUP for non-existing url */ fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_SETUP, @@ -662,7 +692,7 @@ GST_START_TEST (test_client_multicast_transport) GstRTSPMessage request = { 0, }; gchar *str; - client = setup_multicast_client (); + client = setup_multicast_client (1); expected_session_timeout = 20; g_signal_connect (G_OBJECT (client), "new-session", @@ -699,7 +729,7 @@ GST_START_TEST (test_client_multicast_ignore_transport_specific) GstRTSPMessage request = { 0, }; gchar *str; - client = setup_multicast_client (); + client = setup_multicast_client (1); /* simple SETUP with a valid URI and multicast and a specific dest, * but ignore it */ @@ -735,7 +765,7 @@ multicast_transport_specific (void) GstRTSPSessionPool *session_pool; GstRTSPContext ctx = { NULL }; - client = setup_multicast_client (); + client = setup_multicast_client (1); ctx.client = client; ctx.auth = gst_rtsp_auth_new (); @@ -950,9 +980,11 @@ GST_START_TEST (test_client_sdp_with_no_bitrate_tags) GST_END_TEST; static void -mcast_transport_specific_two_clients (gboolean shared) +mcast_transport_specific_two_clients (gboolean shared, const gchar * transport1, + const gchar * expected_transport1, const gchar * transport2, + const gchar * expected_transport2) { - GstRTSPClient *client, *client2; + GstRTSPClient *client1, *client2; GstRTSPMessage request = { 0, }; gchar *str; GstRTSPSessionPool *session_pool; @@ -983,12 +1015,12 @@ mcast_transport_specific_two_clients (gboolean shared) thread_pool = gst_rtsp_thread_pool_new (); /* first multicast client with transport specific request */ - client = gst_rtsp_client_new (); - gst_rtsp_client_set_session_pool (client, session_pool); - gst_rtsp_client_set_mount_points (client, mount_points); - gst_rtsp_client_set_thread_pool (client, thread_pool); + client1 = gst_rtsp_client_new (); + gst_rtsp_client_set_session_pool (client1, session_pool); + gst_rtsp_client_set_mount_points (client1, mount_points); + gst_rtsp_client_set_thread_pool (client1, thread_pool); - ctx.client = client; + ctx.client = client1; ctx.auth = gst_rtsp_auth_new (); ctx.token = gst_rtsp_token_new (GST_RTSP_TOKEN_TRANSPORT_CLIENT_SETTINGS, @@ -996,20 +1028,18 @@ mcast_transport_specific_two_clients (gboolean shared) "user", NULL); gst_rtsp_context_push_current (&ctx); - expected_transport = "RTP/AVP;multicast;destination=233.252.0.1;" - "ttl=1;port=5000-5001;mode=\"PLAY\""; + expected_transport = expected_transport1; /* send SETUP request */ fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_SETUP, "rtsp://localhost/test/stream=0") == GST_RTSP_OK); str = g_strdup_printf ("%d", cseq); gst_rtsp_message_take_header (&request, GST_RTSP_HDR_CSEQ, str); - gst_rtsp_message_add_header (&request, GST_RTSP_HDR_TRANSPORT, - expected_transport); + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_TRANSPORT, transport1); - gst_rtsp_client_set_send_func (client, test_setup_response_200_multicast, + gst_rtsp_client_set_send_func (client1, test_setup_response_200_multicast, NULL, NULL); - fail_unless (gst_rtsp_client_handle_message (client, + fail_unless (gst_rtsp_client_handle_message (client1, &request) == GST_RTSP_OK); gst_rtsp_message_unset (&request); expected_transport = NULL; @@ -1020,8 +1050,8 @@ mcast_transport_specific_two_clients (gboolean shared) str = g_strdup_printf ("%d", cseq); gst_rtsp_message_take_header (&request, GST_RTSP_HDR_CSEQ, str); gst_rtsp_message_add_header (&request, GST_RTSP_HDR_SESSION, session_id); - gst_rtsp_client_set_send_func (client, test_response_200, NULL, NULL); - fail_unless (gst_rtsp_client_handle_message (client, + gst_rtsp_client_set_send_func (client1, test_response_200, NULL, NULL); + fail_unless (gst_rtsp_client_handle_message (client1, &request) == GST_RTSP_OK); gst_rtsp_message_unset (&request); gst_rtsp_context_pop_current (&ctx); @@ -1042,16 +1072,14 @@ mcast_transport_specific_two_clients (gboolean shared) "user", NULL); gst_rtsp_context_push_current (&ctx2); - expected_transport = "RTP/AVP;multicast;destination=233.252.0.2;" - "ttl=1;port=5002-5003;mode=\"PLAY\""; + expected_transport = expected_transport2; /* send SETUP request */ fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_SETUP, "rtsp://localhost/test/stream=0") == GST_RTSP_OK); str = g_strdup_printf ("%d", cseq); gst_rtsp_message_take_header (&request, GST_RTSP_HDR_CSEQ, str); - gst_rtsp_message_add_header (&request, GST_RTSP_HDR_TRANSPORT, - expected_transport); + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_TRANSPORT, transport2); gst_rtsp_client_set_send_func (client2, test_setup_response_200_multicast, NULL, NULL); @@ -1076,10 +1104,10 @@ mcast_transport_specific_two_clients (gboolean shared) gst_rtsp_context_push_current (&ctx); session_id = session_id1; - send_teardown (client); + send_teardown (client1); gst_rtsp_context_pop_current (&ctx); - teardown_client (client); + teardown_client (client1); teardown_client (client2); g_object_unref (ctx.auth); g_object_unref (ctx2.auth); @@ -1095,7 +1123,16 @@ mcast_transport_specific_two_clients (gboolean shared) * CASE: media is shared */ GST_START_TEST (test_client_multicast_transport_specific_two_clients_shared_media) { - mcast_transport_specific_two_clients (TRUE); + const gchar *transport_client_1 = "RTP/AVP;multicast;destination=233.252.0.1;" + "ttl=1;port=5000-5001;mode=\"PLAY\""; + const gchar *expected_transport_1 = transport_client_1; + + const gchar *transport_client_2 = "RTP/AVP;multicast;destination=233.252.0.2;" + "ttl=1;port=5002-5003;mode=\"PLAY\""; + const gchar *expected_transport_2 = transport_client_2; + + mcast_transport_specific_two_clients (TRUE, transport_client_1, + expected_transport_1, transport_client_2, expected_transport_2); } GST_END_TEST; @@ -1104,7 +1141,97 @@ GST_END_TEST; * CASE: media is not shared */ GST_START_TEST (test_client_multicast_transport_specific_two_clients) { - mcast_transport_specific_two_clients (FALSE); + const gchar *transport_client_1 = "RTP/AVP;multicast;destination=233.252.0.1;" + "ttl=1;port=5000-5001;mode=\"PLAY\""; + const gchar *expected_transport_1 = transport_client_1; + + const gchar *transport_client_2 = "RTP/AVP;multicast;destination=233.252.0.2;" + "ttl=1;port=5002-5003;mode=\"PLAY\""; + const gchar *expected_transport_2 = transport_client_2; + + mcast_transport_specific_two_clients (FALSE, transport_client_1, + expected_transport_1, transport_client_2, expected_transport_2); +} + +GST_END_TEST; + +/* test if the maximum ttl multicast value is chosen by the server + * CASE: the first client provides the highest ttl value */ +GST_START_TEST (test_client_multicast_max_ttl_first_client) +{ + const gchar *transport_client_1 = "RTP/AVP;multicast;destination=233.252.0.1;" + "ttl=3;port=5000-5001;mode=\"PLAY\""; + const gchar *expected_transport_1 = transport_client_1; + + const gchar *transport_client_2 = "RTP/AVP;multicast;destination=233.252.0.2;" + "ttl=1;port=5002-5003;mode=\"PLAY\""; + const gchar *expected_transport_2 = + "RTP/AVP;multicast;destination=233.252.0.2;" + "ttl=3;port=5002-5003;mode=\"PLAY\""; + + mcast_transport_specific_two_clients (TRUE, transport_client_1, + expected_transport_1, transport_client_2, expected_transport_2); +} + +GST_END_TEST; + +/* test if the maximum ttl multicast value is chosen by the server + * CASE: the second client provides the highest ttl value */ +GST_START_TEST (test_client_multicast_max_ttl_second_client) +{ + const gchar *transport_client_1 = "RTP/AVP;multicast;destination=233.252.0.1;" + "ttl=2;port=5000-5001;mode=\"PLAY\""; + const gchar *expected_transport_1 = transport_client_1; + + const gchar *transport_client_2 = "RTP/AVP;multicast;destination=233.252.0.2;" + "ttl=4;port=5002-5003;mode=\"PLAY\""; + const gchar *expected_transport_2 = transport_client_2; + + mcast_transport_specific_two_clients (TRUE, transport_client_1, + expected_transport_1, transport_client_2, expected_transport_2); +} + +GST_END_TEST; +GST_START_TEST (test_client_multicast_invalid_ttl) +{ + GstRTSPClient *client; + GstRTSPMessage request = { 0, }; + gchar *str; + GstRTSPSessionPool *session_pool; + GstRTSPContext ctx = { NULL }; + + client = setup_multicast_client (3); + + ctx.client = client; + ctx.auth = gst_rtsp_auth_new (); + ctx.token = + gst_rtsp_token_new (GST_RTSP_TOKEN_TRANSPORT_CLIENT_SETTINGS, + G_TYPE_BOOLEAN, TRUE, GST_RTSP_TOKEN_MEDIA_FACTORY_ROLE, G_TYPE_STRING, + "user", NULL); + gst_rtsp_context_push_current (&ctx); + + /* simple SETUP with an invalid ttl=0 */ + fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_SETUP, + "rtsp://localhost/test/stream=0") == GST_RTSP_OK); + str = g_strdup_printf ("%d", cseq); + gst_rtsp_message_take_header (&request, GST_RTSP_HDR_CSEQ, str); + gst_rtsp_message_add_header (&request, GST_RTSP_HDR_TRANSPORT, + "RTP/AVP;multicast;destination=233.252.0.1;ttl=0;port=5000-5001;"); + + gst_rtsp_client_set_send_func (client, test_setup_response_461, NULL, NULL); + fail_unless (gst_rtsp_client_handle_message (client, + &request) == GST_RTSP_OK); + gst_rtsp_message_unset (&request); + + session_pool = gst_rtsp_client_get_session_pool (client); + fail_unless (session_pool != NULL); + fail_unless (gst_rtsp_session_pool_get_n_sessions (session_pool) == 0); + g_object_unref (session_pool); + + teardown_client (client); + g_object_unref (ctx.auth); + gst_rtsp_token_unref (ctx.token); + gst_rtsp_context_pop_current (&ctx); } GST_END_TEST; @@ -1134,6 +1261,9 @@ rtspclient_suite (void) tcase_add_test (tc, test_client_multicast_transport_specific_two_clients); tcase_add_test (tc, test_client_multicast_transport_specific_no_address_in_pool); + tcase_add_test (tc, test_client_multicast_max_ttl_first_client); + tcase_add_test (tc, test_client_multicast_max_ttl_second_client); + tcase_add_test (tc, test_client_multicast_invalid_ttl); return s; }