/* GStreamer unit tests for the GstRTSPConnection API (RTSP support * library) * * Copyright (C) 2014 Ognyan Tonchev * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include static const gchar *get_msg = "GET /example/url HTTP/1.0\r\n" "Host: 127.0.0.1\r\n" "x-sessioncookie: 805849328\r\n\r\n"; static const gchar *post_msg = "POST /example/url HTTP/1.0\r\n" "Host: 127.0.0.1\r\n" "x-sessioncookie: 805849328\r\n" "Content-Length: 0\r\n" "Content-Type: application/x-rtsp-tunnelled\r\n\r\n"; static guint tunnel_get_count; static guint tunnel_post_count; static guint tunnel_lost_count; static guint closed_count; static guint message_sent_count; typedef struct { GMainLoop *loop; guint16 port; GSocketConnection *conn; GMutex mutex; GCond cond; gboolean started; } ServiceData; static gboolean incoming_callback (GSocketService * service, GSocketConnection * connection, GObject * source_object, gpointer user_data) { ServiceData *data = user_data; GST_DEBUG ("new incoming connection"); data->conn = g_object_ref (connection); g_main_loop_quit (data->loop); return FALSE; } static gpointer service_thread_func (gpointer user_data) { ServiceData *data = user_data; GMainContext *service_context; GSocketService *service; service_context = g_main_context_new (); g_main_context_push_thread_default (service_context); data->loop = g_main_loop_new (service_context, FALSE); /* find available port and start service */ service = g_socket_service_new (); data->port = g_socket_listener_add_any_inet_port ((GSocketListener *) service, NULL, NULL); fail_unless (data->port != 0); /* get notified upon new connection */ g_signal_connect (service, "incoming", G_CALLBACK (incoming_callback), data); g_socket_service_start (service); /* service is started */ g_mutex_lock (&data->mutex); data->started = TRUE; g_cond_signal (&data->cond); g_mutex_unlock (&data->mutex); /* our service will run in the main context of this main loop */ g_main_loop_run (data->loop); g_main_context_pop_thread_default (service_context); g_main_loop_unref (data->loop); data->loop = NULL; return NULL; } static void create_connection (GSocketConnection ** client_conn, GSocketConnection ** server_conn) { ServiceData *data; GThread *service_thread; GSocketClient *client = g_socket_client_new (); data = g_new0 (ServiceData, 1); g_mutex_init (&data->mutex); g_cond_init (&data->cond); service_thread = g_thread_new ("service thread", service_thread_func, data); fail_unless (service_thread != NULL); /* wait for the service to start */ g_mutex_lock (&data->mutex); while (!data->started) { g_cond_wait (&data->cond, &data->mutex); } g_mutex_unlock (&data->mutex); /* create the tcp link */ *client_conn = g_socket_client_connect_to_host (client, (gchar *) "localhost", data->port, NULL, NULL); fail_unless (*client_conn != NULL); fail_unless (g_socket_connection_is_connected (*client_conn)); g_thread_join (service_thread); *server_conn = data->conn; data->conn = NULL; fail_unless (g_socket_connection_is_connected (*server_conn)); g_mutex_clear (&data->mutex); g_cond_clear (&data->cond); g_free (data); g_object_unref (client); } static GstRTSPStatusCode tunnel_get (GstRTSPWatch * watch, gpointer user_data) { tunnel_get_count++; return GST_RTSP_STS_OK; } static GstRTSPResult tunnel_post (GstRTSPWatch * watch, gpointer user_data) { tunnel_post_count++; return GST_RTSP_OK; } static GstRTSPResult tunnel_lost (GstRTSPWatch * watch, gpointer user_data) { tunnel_lost_count++; return GST_RTSP_OK; } static GstRTSPResult closed (GstRTSPWatch * watch, gpointer user_data) { closed_count++; return GST_RTSP_OK; } static GstRTSPResult message_sent (GstRTSPWatch * watch, guint id, gpointer user_data) { message_sent_count++; return GST_RTSP_OK; } static GstRTSPWatchFuncs watch_funcs = { NULL, message_sent, closed, NULL, tunnel_get, tunnel_post, NULL, tunnel_lost }; /* sets up a new tunnel, then disconnects the read connection and creates it * again */ GST_START_TEST (test_rtspconnection_tunnel_setup) { GstRTSPConnection *rtsp_conn1 = NULL; GstRTSPConnection *rtsp_conn2 = NULL; GstRTSPWatch *watch1; GstRTSPWatch *watch2; GstRTSPResult res; GSocketConnection *client_get = NULL; GSocketConnection *server_get = NULL; GSocketConnection *client_post = NULL; GSocketConnection *server_post = NULL; GSocket *server_sock; GOutputStream *ostream_get; GInputStream *istream_get; GOutputStream *ostream_post; gsize size = 0; gchar buffer[1024]; /* create GET connection */ create_connection (&client_get, &server_get); server_sock = g_socket_connection_get_socket (server_get); fail_unless (server_sock != NULL); res = gst_rtsp_connection_create_from_socket (server_sock, "127.0.0.1", 4444, NULL, &rtsp_conn1); fail_unless (res == GST_RTSP_OK); fail_unless (rtsp_conn1 != NULL); watch1 = gst_rtsp_watch_new (rtsp_conn1, &watch_funcs, NULL, NULL); fail_unless (watch1 != NULL); fail_unless (gst_rtsp_watch_attach (watch1, NULL) > 0); g_source_unref ((GSource *) watch1); ostream_get = g_io_stream_get_output_stream (G_IO_STREAM (client_get)); fail_unless (ostream_get != NULL); istream_get = g_io_stream_get_input_stream (G_IO_STREAM (client_get)); fail_unless (istream_get != NULL); /* initiate the tunnel by sending HTTP GET */ fail_unless (g_output_stream_write_all (ostream_get, get_msg, strlen (get_msg), &size, NULL, NULL)); fail_unless (size == strlen (get_msg)); while (!g_main_context_iteration (NULL, TRUE)); fail_unless (tunnel_get_count == 1); fail_unless (tunnel_post_count == 0); fail_unless (tunnel_lost_count == 0); fail_unless (closed_count == 0); /* read the HTTP GET response */ size = g_input_stream_read (istream_get, buffer, 1024, NULL, NULL); fail_unless (size > 0); buffer[size] = 0; fail_unless (g_strrstr (buffer, "HTTP/1.0 200 OK") != NULL); /* create POST channel */ create_connection (&client_post, &server_post); server_sock = g_socket_connection_get_socket (server_post); fail_unless (server_sock != NULL); res = gst_rtsp_connection_create_from_socket (server_sock, "127.0.0.1", 4444, NULL, &rtsp_conn2); fail_unless (res == GST_RTSP_OK); fail_unless (rtsp_conn2 != NULL); watch2 = gst_rtsp_watch_new (rtsp_conn2, &watch_funcs, NULL, NULL); fail_unless (watch2 != NULL); fail_unless (gst_rtsp_watch_attach (watch2, NULL) > 0); g_source_unref ((GSource *) watch2); ostream_post = g_io_stream_get_output_stream (G_IO_STREAM (client_post)); fail_unless (ostream_post != NULL); /* complete the tunnel by sending HTTP POST */ fail_unless (g_output_stream_write_all (ostream_post, post_msg, strlen (post_msg), &size, NULL, NULL)); fail_unless (size == strlen (post_msg)); while (!g_main_context_iteration (NULL, TRUE)); fail_unless (tunnel_get_count == 1); fail_unless (tunnel_post_count == 1); fail_unless (tunnel_lost_count == 0); fail_unless (closed_count == 0); /* merge the two connections together */ fail_unless (gst_rtsp_connection_do_tunnel (rtsp_conn1, rtsp_conn2) == GST_RTSP_OK); gst_rtsp_watch_reset (watch1); g_source_destroy ((GSource *) watch2); gst_rtsp_connection_free (rtsp_conn2); rtsp_conn2 = NULL; /* it must be possible to reconnect the POST channel */ g_object_unref (client_post); while (!g_main_context_iteration (NULL, TRUE)); fail_unless (tunnel_get_count == 1); fail_unless (tunnel_post_count == 1); fail_unless (tunnel_lost_count == 1); fail_unless (closed_count == 0); g_object_unref (server_post); /* no other source should get dispatched */ fail_if (g_main_context_iteration (NULL, FALSE)); /* create new POST connection */ create_connection (&client_post, &server_post); server_sock = g_socket_connection_get_socket (server_post); fail_unless (server_sock != NULL); res = gst_rtsp_connection_create_from_socket (server_sock, "127.0.0.1", 4444, NULL, &rtsp_conn2); fail_unless (res == GST_RTSP_OK); fail_unless (rtsp_conn2 != NULL); watch2 = gst_rtsp_watch_new (rtsp_conn2, &watch_funcs, NULL, NULL); fail_unless (watch2 != NULL); fail_unless (gst_rtsp_watch_attach (watch2, NULL) > 0); g_source_unref ((GSource *) watch2); ostream_post = g_io_stream_get_output_stream (G_IO_STREAM (client_post)); fail_unless (ostream_post != NULL); /* complete the tunnel by sending HTTP POST */ fail_unless (g_output_stream_write_all (ostream_post, post_msg, strlen (post_msg), &size, NULL, NULL)); fail_unless (size == strlen (post_msg)); while (!g_main_context_iteration (NULL, TRUE)); fail_unless (tunnel_get_count == 1); fail_unless (tunnel_post_count == 2); fail_unless (tunnel_lost_count == 1); fail_unless (closed_count == 0); /* merge the two connections together */ fail_unless (gst_rtsp_connection_do_tunnel (rtsp_conn1, rtsp_conn2) == GST_RTSP_OK); gst_rtsp_watch_reset (watch1); g_source_destroy ((GSource *) watch2); gst_rtsp_connection_free (rtsp_conn2); rtsp_conn2 = NULL; /* check if rtspconnection can detect close of the get channel */ g_object_unref (client_get); while (!g_main_context_iteration (NULL, TRUE)); fail_unless (tunnel_get_count == 1); fail_unless (tunnel_post_count == 2); fail_unless (tunnel_lost_count == 1); fail_unless (closed_count == 1); fail_unless (gst_rtsp_connection_close (rtsp_conn1) == GST_RTSP_OK); fail_unless (gst_rtsp_connection_free (rtsp_conn1) == GST_RTSP_OK); g_object_unref (client_post); g_object_unref (server_post); g_object_unref (server_get); } GST_END_TEST; /* sets up a new tunnel, starting with the read channel, * then disconnects the read connection and creates it again * ideally this test should be merged with test_rtspconnection_tunnel_setup but * but it became quite messy */ GST_START_TEST (test_rtspconnection_tunnel_setup_post_first) { GstRTSPConnection *rtsp_conn1 = NULL; GstRTSPConnection *rtsp_conn2 = NULL; GstRTSPWatch *watch1; GstRTSPWatch *watch2; GstRTSPResult res; GSocketConnection *client_get = NULL; GSocketConnection *server_get = NULL; GSocketConnection *client_post = NULL; GSocketConnection *server_post = NULL; GSocket *server_sock; GOutputStream *ostream_get; GInputStream *istream_get; GOutputStream *ostream_post; gsize size = 0; gchar buffer[1024]; /* create POST channel */ create_connection (&client_post, &server_post); server_sock = g_socket_connection_get_socket (server_post); fail_unless (server_sock != NULL); res = gst_rtsp_connection_create_from_socket (server_sock, "127.0.0.1", 4444, NULL, &rtsp_conn1); fail_unless (res == GST_RTSP_OK); fail_unless (rtsp_conn1 != NULL); watch1 = gst_rtsp_watch_new (rtsp_conn1, &watch_funcs, NULL, NULL); fail_unless (watch1 != NULL); fail_unless (gst_rtsp_watch_attach (watch1, NULL) > 0); g_source_unref ((GSource *) watch1); ostream_post = g_io_stream_get_output_stream (G_IO_STREAM (client_post)); fail_unless (ostream_post != NULL); /* initiate the tunnel by sending HTTP POST */ fail_unless (g_output_stream_write_all (ostream_post, post_msg, strlen (post_msg), &size, NULL, NULL)); fail_unless (size == strlen (post_msg)); while (!g_main_context_iteration (NULL, TRUE)); fail_unless (tunnel_get_count == 0); fail_unless (tunnel_post_count == 1); fail_unless (tunnel_lost_count == 0); fail_unless (closed_count == 0); /* create GET connection */ create_connection (&client_get, &server_get); server_sock = g_socket_connection_get_socket (server_get); fail_unless (server_sock != NULL); res = gst_rtsp_connection_create_from_socket (server_sock, "127.0.0.1", 4444, NULL, &rtsp_conn2); fail_unless (res == GST_RTSP_OK); fail_unless (rtsp_conn2 != NULL); watch2 = gst_rtsp_watch_new (rtsp_conn2, &watch_funcs, NULL, NULL); fail_unless (watch2 != NULL); fail_unless (gst_rtsp_watch_attach (watch2, NULL) > 0); g_source_unref ((GSource *) watch2); ostream_get = g_io_stream_get_output_stream (G_IO_STREAM (client_get)); fail_unless (ostream_get != NULL); istream_get = g_io_stream_get_input_stream (G_IO_STREAM (client_get)); fail_unless (istream_get != NULL); /* complete the tunnel by sending HTTP GET */ fail_unless (g_output_stream_write_all (ostream_get, get_msg, strlen (get_msg), &size, NULL, NULL)); fail_unless (size == strlen (get_msg)); while (!g_main_context_iteration (NULL, TRUE)); fail_unless (tunnel_get_count == 1); fail_unless (tunnel_post_count == 1); fail_unless (tunnel_lost_count == 0); fail_unless (closed_count == 0); /* read the HTTP GET response */ size = g_input_stream_read (istream_get, buffer, 1024, NULL, NULL); fail_unless (size > 0); buffer[size] = 0; fail_unless (g_strrstr (buffer, "HTTP/1.0 200 OK") != NULL); /* merge the two connections together */ fail_unless (gst_rtsp_connection_do_tunnel (rtsp_conn1, rtsp_conn2) == GST_RTSP_OK); gst_rtsp_watch_reset (watch1); g_source_destroy ((GSource *) watch2); gst_rtsp_connection_free (rtsp_conn2); rtsp_conn2 = NULL; /* it must be possible to reconnect the POST channel */ g_object_unref (client_post); while (!g_main_context_iteration (NULL, TRUE)); fail_unless (tunnel_get_count == 1); fail_unless (tunnel_post_count == 1); fail_unless (tunnel_lost_count == 1); fail_unless (closed_count == 0); g_object_unref (server_post); /* no other source should get dispatched */ fail_if (g_main_context_iteration (NULL, FALSE)); /* create new POST connection */ create_connection (&client_post, &server_post); server_sock = g_socket_connection_get_socket (server_post); fail_unless (server_sock != NULL); res = gst_rtsp_connection_create_from_socket (server_sock, "127.0.0.1", 4444, NULL, &rtsp_conn2); fail_unless (res == GST_RTSP_OK); fail_unless (rtsp_conn2 != NULL); watch2 = gst_rtsp_watch_new (rtsp_conn2, &watch_funcs, NULL, NULL); fail_unless (watch2 != NULL); fail_unless (gst_rtsp_watch_attach (watch2, NULL) > 0); g_source_unref ((GSource *) watch2); ostream_post = g_io_stream_get_output_stream (G_IO_STREAM (client_post)); fail_unless (ostream_post != NULL); /* complete the tunnel by sending HTTP POST */ fail_unless (g_output_stream_write_all (ostream_post, post_msg, strlen (post_msg), &size, NULL, NULL)); fail_unless (size == strlen (post_msg)); while (!g_main_context_iteration (NULL, TRUE)); fail_unless (tunnel_get_count == 1); fail_unless (tunnel_post_count == 2); fail_unless (tunnel_lost_count == 1); fail_unless (closed_count == 0); /* merge the two connections together */ fail_unless (gst_rtsp_connection_do_tunnel (rtsp_conn1, rtsp_conn2) == GST_RTSP_OK); gst_rtsp_watch_reset (watch1); g_source_destroy ((GSource *) watch2); gst_rtsp_connection_free (rtsp_conn2); rtsp_conn2 = NULL; /* check if rtspconnection can detect close of the get channel */ g_object_unref (client_get); while (!g_main_context_iteration (NULL, TRUE)); fail_unless (tunnel_get_count == 1); fail_unless (tunnel_post_count == 2); fail_unless (tunnel_lost_count == 1); fail_unless (closed_count == 1); fail_unless (gst_rtsp_connection_close (rtsp_conn1) == GST_RTSP_OK); fail_unless (gst_rtsp_connection_free (rtsp_conn1) == GST_RTSP_OK); g_object_unref (client_post); g_object_unref (server_post); g_object_unref (server_get); } GST_END_TEST; GST_START_TEST (test_rtspconnection_send_receive) { GSocketConnection *input_conn = NULL; GSocketConnection *output_conn = NULL; GSocket *input_sock; GSocket *output_sock; GstRTSPConnection *rtsp_output_conn; GstRTSPConnection *rtsp_input_conn; GstRTSPMessage *msg; gchar body[] = "message body"; gchar *recv_body; guint recv_body_len; create_connection (&input_conn, &output_conn); input_sock = g_socket_connection_get_socket (input_conn); fail_unless (input_sock != NULL); output_sock = g_socket_connection_get_socket (output_conn); fail_unless (output_sock != NULL); fail_unless (gst_rtsp_connection_create_from_socket (input_sock, "127.0.0.1", 4444, NULL, &rtsp_input_conn) == GST_RTSP_OK); fail_unless (rtsp_input_conn != NULL); fail_unless (gst_rtsp_connection_create_from_socket (output_sock, "127.0.0.1", 4444, NULL, &rtsp_output_conn) == GST_RTSP_OK); fail_unless (rtsp_output_conn != NULL); /* send data message */ fail_unless (gst_rtsp_message_new_data (&msg, 1) == GST_RTSP_OK); fail_unless (gst_rtsp_message_set_body (msg, (guint8 *) body, sizeof (body)) == GST_RTSP_OK); fail_unless (gst_rtsp_connection_send (rtsp_output_conn, msg, NULL) == GST_RTSP_OK); fail_unless (gst_rtsp_message_free (msg) == GST_RTSP_OK); msg = NULL; /* receive data message and make sure it is correct */ fail_unless (gst_rtsp_message_new (&msg) == GST_RTSP_OK); fail_unless (gst_rtsp_connection_receive (rtsp_input_conn, msg, NULL) == GST_RTSP_OK); fail_unless (gst_rtsp_message_get_type (msg) == GST_RTSP_MESSAGE_DATA); fail_unless (gst_rtsp_message_get_body (msg, (guint8 **) & recv_body, &recv_body_len) == GST_RTSP_OK); /* RTSPConnection adds an extra byte for the trailing '\0' */ fail_unless_equals_int (recv_body_len, sizeof (body) + 1); fail_unless_equals_string (recv_body, body); fail_unless (gst_rtsp_message_free (msg) == GST_RTSP_OK); msg = NULL; /* send request message */ fail_unless (gst_rtsp_message_new_request (&msg, GST_RTSP_OPTIONS, "example.org") == GST_RTSP_OK); fail_unless (gst_rtsp_message_set_body (msg, (guint8 *) body, sizeof (body)) == GST_RTSP_OK); fail_unless (gst_rtsp_connection_send (rtsp_output_conn, msg, NULL) == GST_RTSP_OK); fail_unless (gst_rtsp_message_free (msg) == GST_RTSP_OK); msg = NULL; /* receive request message and make sure it is correct */ fail_unless (gst_rtsp_message_new (&msg) == GST_RTSP_OK); fail_unless (gst_rtsp_connection_receive (rtsp_input_conn, msg, NULL) == GST_RTSP_OK); fail_unless (gst_rtsp_message_get_type (msg) == GST_RTSP_MESSAGE_REQUEST); fail_unless (gst_rtsp_message_get_body (msg, (guint8 **) & recv_body, &recv_body_len) == GST_RTSP_OK); /* RTSPConnection adds an extra byte for the trailing '\0' */ fail_unless_equals_int (recv_body_len, sizeof (body) + 1); fail_unless_equals_string (recv_body, body); fail_unless (gst_rtsp_message_free (msg) == GST_RTSP_OK); msg = NULL; fail_unless (gst_rtsp_connection_close (rtsp_input_conn) == GST_RTSP_OK); fail_unless (gst_rtsp_connection_free (rtsp_input_conn) == GST_RTSP_OK); fail_unless (gst_rtsp_connection_close (rtsp_output_conn) == GST_RTSP_OK); fail_unless (gst_rtsp_connection_free (rtsp_output_conn) == GST_RTSP_OK); g_object_unref (input_conn); g_object_unref (output_conn); } GST_END_TEST; GST_START_TEST (test_rtspconnection_send_receive_check_headers) { GSocketConnection *input_conn = NULL; GSocketConnection *output_conn = NULL; GSocket *input_sock; GSocket *output_sock; GstRTSPConnection *rtsp_output_conn; GstRTSPConnection *rtsp_input_conn; GstRTSPMessage *msg; gchar *header_val; create_connection (&input_conn, &output_conn); input_sock = g_socket_connection_get_socket (input_conn); fail_unless (input_sock != NULL); output_sock = g_socket_connection_get_socket (output_conn); fail_unless (output_sock != NULL); fail_unless (gst_rtsp_connection_create_from_socket (input_sock, "127.0.0.1", 4444, NULL, &rtsp_input_conn) == GST_RTSP_OK); fail_unless (rtsp_input_conn != NULL); fail_unless (gst_rtsp_connection_create_from_socket (output_sock, "127.0.0.1", 4444, NULL, &rtsp_output_conn) == GST_RTSP_OK); fail_unless (rtsp_output_conn != NULL); /* send request message */ fail_unless (gst_rtsp_message_new_request (&msg, GST_RTSP_SETUP, "rtsp://example.com/") == GST_RTSP_OK); fail_unless (gst_rtsp_message_add_header (msg, GST_RTSP_HDR_BLOCKSIZE, "1024") == GST_RTSP_OK); fail_unless (gst_rtsp_message_add_header_by_name (msg, "Custom-Header", "lol") == GST_RTSP_OK); fail_unless (gst_rtsp_connection_send (rtsp_output_conn, msg, NULL) == GST_RTSP_OK); fail_unless (gst_rtsp_message_free (msg) == GST_RTSP_OK); msg = NULL; /* receive request message and make sure it is correct */ fail_unless (gst_rtsp_message_new (&msg) == GST_RTSP_OK); fail_unless (gst_rtsp_connection_receive (rtsp_input_conn, msg, NULL) == GST_RTSP_OK); fail_unless (gst_rtsp_message_get_type (msg) == GST_RTSP_MESSAGE_REQUEST); /* check headers */ fail_unless (gst_rtsp_message_get_header (msg, GST_RTSP_HDR_BLOCKSIZE, &header_val, 0) == GST_RTSP_OK); fail_unless (!g_strcmp0 (header_val, "1024")); fail_unless (gst_rtsp_message_get_header_by_name (msg, "Custom-Header", &header_val, 0) == GST_RTSP_OK); fail_unless (!g_strcmp0 (header_val, "lol")); fail_unless (gst_rtsp_message_free (msg) == GST_RTSP_OK); msg = NULL; fail_unless (gst_rtsp_connection_close (rtsp_input_conn) == GST_RTSP_OK); fail_unless (gst_rtsp_connection_free (rtsp_input_conn) == GST_RTSP_OK); fail_unless (gst_rtsp_connection_close (rtsp_output_conn) == GST_RTSP_OK); fail_unless (gst_rtsp_connection_free (rtsp_output_conn) == GST_RTSP_OK); g_object_unref (input_conn); g_object_unref (output_conn); } GST_END_TEST; GST_START_TEST (test_rtspconnection_connect) { ServiceData *data; GThread *service_thread; GSocketConnection *socket_conn; GstRTSPConnection *rtsp_conn = NULL; GstRTSPUrl *url = NULL; gchar *path; data = g_new0 (ServiceData, 1); g_mutex_init (&data->mutex); g_cond_init (&data->cond); /* create socket service */ service_thread = g_thread_new ("service thread", service_thread_func, data); fail_unless (service_thread != NULL); /* wait for the service to start */ g_mutex_lock (&data->mutex); while (!data->started) { g_cond_wait (&data->cond, &data->mutex); } g_mutex_unlock (&data->mutex); /* connect to our service using the RTSPConnection API */ path = g_strdup_printf ("rtsp://localhost:%d", data->port); fail_unless (gst_rtsp_url_parse (path, &url) == GST_RTSP_OK); fail_unless (gst_rtsp_connection_create (url, &rtsp_conn) == GST_RTSP_OK); fail_unless (gst_rtsp_connection_connect (rtsp_conn, NULL) == GST_RTSP_OK); g_free (path); gst_rtsp_url_free (url); /* wait for the other end and check whether it is connected */ g_thread_join (service_thread); socket_conn = data->conn; data->conn = NULL; fail_unless (g_socket_connection_is_connected (socket_conn)); fail_unless (gst_rtsp_connection_close (rtsp_conn) == GST_RTSP_OK); fail_unless (gst_rtsp_connection_free (rtsp_conn) == GST_RTSP_OK); g_object_unref (socket_conn); g_mutex_clear (&data->mutex); g_cond_clear (&data->cond); g_free (data); } GST_END_TEST; GST_START_TEST (test_rtspconnection_poll) { GSocketConnection *conn1 = NULL; GSocketConnection *conn2 = NULL; GSocket *sock; GstRTSPConnection *rtsp_conn; GstRTSPEvent event; GOutputStream *ostream; gsize size; gint64 timeout; create_connection (&conn1, &conn2); sock = g_socket_connection_get_socket (conn1); fail_unless (sock != NULL); ostream = g_io_stream_get_output_stream (G_IO_STREAM (conn2)); fail_unless (ostream != NULL); fail_unless (gst_rtsp_connection_create_from_socket (sock, "127.0.0.1", 4444, NULL, &rtsp_conn) == GST_RTSP_OK); fail_unless (rtsp_conn != NULL); /* should be possible to write on socket */ fail_unless (gst_rtsp_connection_poll (rtsp_conn, GST_RTSP_EV_WRITE, &event, NULL) == GST_RTSP_OK); fail_unless (event & GST_RTSP_EV_WRITE); /* but not read, add timeout so that we don't block forever */ timeout = G_USEC_PER_SEC; fail_unless (gst_rtsp_connection_poll_usec (rtsp_conn, GST_RTSP_EV_READ, &event, timeout) == GST_RTSP_ETIMEOUT); fail_if (event & GST_RTSP_EV_READ); /* write on the other end and make sure socket can be read */ fail_unless (g_output_stream_write_all (ostream, "data", 5, &size, NULL, NULL)); fail_unless (gst_rtsp_connection_poll (rtsp_conn, GST_RTSP_EV_READ, &event, NULL) == GST_RTSP_OK); fail_unless (event & GST_RTSP_EV_READ); fail_unless (gst_rtsp_connection_close (rtsp_conn) == GST_RTSP_OK); fail_unless (gst_rtsp_connection_free (rtsp_conn) == GST_RTSP_OK); g_object_unref (conn1); g_object_unref (conn2); } GST_END_TEST; GST_START_TEST (test_rtspconnection_backlog) { GSocketConnection *conn1 = NULL; GSocketConnection *conn2 = NULL; GSocket *sock; GstRTSPConnection *rtsp_conn = NULL; GstRTSPWatch *watch; GInputStream *istream; guint8 *buffer; guint8 recv[1024]; gsize count; GstRTSPResult res = GST_RTSP_OK; guint num_queued; guint num_sent; create_connection (&conn1, &conn2); sock = g_socket_connection_get_socket (conn1); fail_unless (sock != NULL); fail_unless (gst_rtsp_connection_create_from_socket (sock, "127.0.0.1", 4444, NULL, &rtsp_conn) == GST_RTSP_OK); fail_unless (rtsp_conn != NULL); watch = gst_rtsp_watch_new (rtsp_conn, &watch_funcs, NULL, NULL); fail_unless (watch != NULL); fail_unless (gst_rtsp_watch_attach (watch, NULL) > 0); g_source_unref ((GSource *) watch); gst_rtsp_watch_set_send_backlog (watch, 1024, 0); /* write until we fill tcp window and writes result in would_block, * data will then start getting queued until the backlog also gets full */ num_queued = 0; num_sent = 0; while (res == GST_RTSP_OK) { guint id = 0; buffer = malloc (1024); memset (buffer, 0, 1024); res = gst_rtsp_watch_write_data (watch, buffer, 1024, &id); if (id > 0) num_queued++; if (res == GST_RTSP_OK) num_sent++; } /* make sure we got enomem and at least 1 message got queued */ fail_unless (res == GST_RTSP_ENOMEM); fail_unless (num_queued > 0); istream = g_io_stream_get_input_stream (G_IO_STREAM (conn2)); fail_unless (istream != NULL); /* read a bit from the socket and make sure queued data gets sent */ while (num_queued > 0) { fail_unless (g_input_stream_read_all (istream, recv, 1024, &count, NULL, NULL)); num_sent--; g_main_context_iteration (NULL, FALSE); num_queued -= message_sent_count; fail_unless (num_queued >= 0); } /* make sure we can read the rest of the data */ while (num_sent > 0) { fail_unless (g_input_stream_read_all (istream, recv, 1024, &count, NULL, NULL)); num_sent--; } g_source_destroy ((GSource *) watch); fail_unless (gst_rtsp_connection_close (rtsp_conn) == GST_RTSP_OK); fail_unless (gst_rtsp_connection_free (rtsp_conn) == GST_RTSP_OK); g_object_unref (conn1); g_object_unref (conn2); } GST_END_TEST; GST_START_TEST (test_rtspconnection_ip) { GstRTSPConnection *conn = NULL; GstRTSPUrl *url = NULL; fail_unless (gst_rtsp_url_parse ("rtsp://127.0.0.1:42", &url) == GST_RTSP_OK); fail_unless (url != NULL); fail_unless (gst_rtsp_connection_create (url, &conn) == GST_RTSP_OK); fail_unless (conn != NULL); gst_rtsp_connection_set_ip (conn, "127.0.0.1"); fail_unless_equals_string (gst_rtsp_connection_get_ip (conn), "127.0.0.1"); gst_rtsp_url_free (url); fail_unless (gst_rtsp_connection_free (conn) == GST_RTSP_OK); } GST_END_TEST; GST_START_TEST (test_rtspconnection_send_receive_content_length) { GSocketConnection *input_conn = NULL; GSocketConnection *output_conn = NULL; GSocket *input_sock; GSocket *output_sock; GstRTSPConnection *rtsp_output_conn; GstRTSPConnection *rtsp_input_conn; GstRTSPMessage *msg; create_connection (&input_conn, &output_conn); input_sock = g_socket_connection_get_socket (input_conn); fail_unless (input_sock != NULL); output_sock = g_socket_connection_get_socket (output_conn); fail_unless (output_sock != NULL); fail_unless (gst_rtsp_connection_create_from_socket (input_sock, "127.0.0.1", 4444, NULL, &rtsp_input_conn) == GST_RTSP_OK); fail_unless (rtsp_input_conn != NULL); fail_unless (gst_rtsp_connection_create_from_socket (output_sock, "127.0.0.1", 4444, NULL, &rtsp_output_conn) == GST_RTSP_OK); fail_unless (rtsp_output_conn != NULL); /* send request message with to big payload */ fail_unless (gst_rtsp_message_new_request (&msg, GST_RTSP_SETUP, "rtsp://example.com/") == GST_RTSP_OK); fail_unless (gst_rtsp_message_add_header (msg, GST_RTSP_HDR_CONTENT_LENGTH, "2000") == GST_RTSP_OK); fail_unless (gst_rtsp_connection_send (rtsp_output_conn, msg, NULL) == GST_RTSP_OK); fail_unless (gst_rtsp_message_free (msg) == GST_RTSP_OK); msg = NULL; /* receive request message, expect ENOMEM */ gst_rtsp_connection_set_content_length_limit (rtsp_input_conn, 1000); fail_unless (gst_rtsp_message_new (&msg) == GST_RTSP_OK); fail_unless (gst_rtsp_connection_receive (rtsp_input_conn, msg, NULL) == GST_RTSP_ENOMEM); fail_unless (gst_rtsp_message_free (msg) == GST_RTSP_OK); msg = NULL; /* send request message with negative payload */ fail_unless (gst_rtsp_message_new_request (&msg, GST_RTSP_SETUP, "rtsp://example.com/") == GST_RTSP_OK); fail_unless (gst_rtsp_message_add_header (msg, GST_RTSP_HDR_CONTENT_LENGTH, "-2000") == GST_RTSP_OK); fail_unless (gst_rtsp_connection_send (rtsp_output_conn, msg, NULL) == GST_RTSP_OK); fail_unless (gst_rtsp_message_free (msg) == GST_RTSP_OK); msg = NULL; /* receive request message, expect EPARSE */ fail_unless (gst_rtsp_message_new (&msg) == GST_RTSP_OK); fail_unless (gst_rtsp_connection_receive (rtsp_input_conn, msg, NULL) == GST_RTSP_EPARSE); fail_unless (gst_rtsp_message_free (msg) == GST_RTSP_OK); msg = NULL; fail_unless (gst_rtsp_connection_close (rtsp_input_conn) == GST_RTSP_OK); fail_unless (gst_rtsp_connection_free (rtsp_input_conn) == GST_RTSP_OK); fail_unless (gst_rtsp_connection_close (rtsp_output_conn) == GST_RTSP_OK); fail_unless (gst_rtsp_connection_free (rtsp_output_conn) == GST_RTSP_OK); g_object_unref (input_conn); g_object_unref (output_conn); } GST_END_TEST; static Suite * rtspconnection_suite (void) { Suite *s = suite_create ("rtsp support library(rtspconnection)"); TCase *tc_chain = tcase_create ("general"); suite_add_tcase (s, tc_chain); tcase_add_test (tc_chain, test_rtspconnection_tunnel_setup); tcase_add_test (tc_chain, test_rtspconnection_tunnel_setup_post_first); tcase_add_test (tc_chain, test_rtspconnection_send_receive); tcase_add_test (tc_chain, test_rtspconnection_send_receive_check_headers); tcase_add_test (tc_chain, test_rtspconnection_connect); tcase_add_test (tc_chain, test_rtspconnection_poll); tcase_add_test (tc_chain, test_rtspconnection_backlog); tcase_add_test (tc_chain, test_rtspconnection_ip); tcase_add_test (tc_chain, test_rtspconnection_send_receive_content_length); return s; } GST_CHECK_MAIN (rtspconnection);