/* * This file is part of the Nice GLib ICE library. * * Unit test for ICE full-mode related features. * * (C) 2007 Nokia Corporation. All rights reserved. * Contact: Kai Vehmanen * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is the Nice GLib ICE library. * * The Initial Developers of the Original Code are Collabora Ltd and Nokia * Corporation. All Rights Reserved. * * Contributors: * Kai Vehmanen, Nokia * * Alternatively, the contents of this file may be used under the terms of the * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which * case the provisions of LGPL are applicable instead of those above. If you * wish to allow use of your version of this file only under the terms of the * LGPL and not to allow others to use your version of this file under the * MPL, indicate your decision by deleting the provisions above and replace * them with the notice and other provisions required by the LGPL. If you do * not delete the provisions above, a recipient may use your version of this * file under either the MPL or the LGPL. */ #ifdef HAVE_CONFIG_H # include #endif #include "agent.h" #include #include #ifndef G_OS_WIN32 #include #endif volatile gint global_lagent_cands = 0; volatile gint global_ragent_cands = 0; GMutex buffers_mutex; GCond buffers_cond; gint global_lagent_buffers = 0; gint global_ragent_buffers = 0; /* Waits about 10 seconds for @var to be NULL/FALSE */ #define WAIT_UNTIL_UNSET(var, context) \ if (var) \ { \ int _i; \ \ for (_i = 0; _i < 13 && (var); _i++) \ { \ g_usleep (1000 * (1 << _i)); \ g_main_context_iteration (context, FALSE); \ } \ \ g_assert_true (!(var)); \ } static gpointer mainloop_thread (gpointer data) { GMainLoop *loop = data; g_main_loop_run (loop); return NULL; } static void cb_new_selected_pair(NiceAgent *agent, guint stream_id, guint component_id, gchar *lfoundation, gchar* rfoundation, gpointer data) { g_debug ("test-thread:%s: %p", G_STRFUNC, data); if (GPOINTER_TO_UINT (data) == 1) g_atomic_int_inc (&global_lagent_cands); else if (GPOINTER_TO_UINT (data) == 2) g_atomic_int_inc (&global_ragent_cands); } static void cb_candidate_gathering_done(NiceAgent *agent, guint stream_id, gpointer data) { NiceAgent *other = g_object_get_data (G_OBJECT (agent), "other-agent"); gchar *ufrag = NULL, *password = NULL; GSList *cands, *i; guint id, other_id; gpointer tmp; g_debug ("test-thread:%s", G_STRFUNC); tmp = g_object_get_data (G_OBJECT (agent), "id"); id = GPOINTER_TO_UINT (tmp); tmp = g_object_get_data (G_OBJECT (other), "id"); other_id = GPOINTER_TO_UINT (tmp); nice_agent_get_local_credentials(agent, id, &ufrag, &password); nice_agent_set_remote_credentials (other, other_id, ufrag, password); g_free (ufrag); g_free (password); cands = nice_agent_get_local_candidates(agent, id, 1); g_assert_true (cands != NULL); nice_agent_set_remote_candidates (other, other_id, 1, cands); for (i = cands; i; i = i->next) nice_candidate_free ((NiceCandidate *) i->data); g_slist_free (cands); } static void cb_nice_recv (NiceAgent *agent, guint stream_id, guint component_id, guint len, gchar *buf, gpointer user_data) { gchar data[10]; gint *count = NULL; g_debug ("Agent %p Stream %d Component: %d Received %u bytes", agent, stream_id, component_id, len); g_mutex_lock (&buffers_mutex); if (GPOINTER_TO_UINT (user_data) == 1) count = &global_lagent_buffers; else if (GPOINTER_TO_UINT (user_data) == 2) count = &global_ragent_buffers; else g_error ("Invalid agent ?"); if (*count == 10) return; memset (data, *count + '1', 10); g_assert_cmpmem (buf, len, data, 10); g_assert_cmpuint (len, ==, 10); (*count)++; g_cond_signal (&buffers_cond); g_mutex_unlock (&buffers_mutex); } static void cb_component_state_changed (NiceAgent *agent, guint stream_id, guint component_id, guint state, gpointer user_data) { int i; gchar data[10]; g_debug("Agent %p Stream %d Component %d state %s", agent, stream_id, component_id, nice_component_state_to_string (state)); if (state != NICE_COMPONENT_STATE_READY) return; for (i=0; i<10; i++) { memset (data, i+'1', 10); g_debug ("Agent %p Stream: %d Component: %d Sending 10 bytes", agent, stream_id, component_id); nice_agent_send (agent, stream_id, component_id, 10, data); } } int main (void) { NiceAgent *lagent, *ragent; /* agent's L and R */ NiceAddress baseaddr; const char *stun_server = NULL, *stun_server_port = NULL; GMainContext *lmainctx, *rmainctx; GMainLoop *lmainloop, *rmainloop; GThread *lthread, *rthread; guint ls_id, rs_id; GMainContext *ldmainctx, *rdmainctx; GMainLoop *ldmainloop, *rdmainloop; GThread *ldthread, *rdthread; #ifdef G_OS_WIN32 WSADATA w; WSAStartup(0x0202, &w); #endif lmainctx = g_main_context_new (); rmainctx = g_main_context_new (); lmainloop = g_main_loop_new (lmainctx, FALSE); rmainloop = g_main_loop_new (rmainctx, FALSE); ldmainctx = g_main_context_new (); rdmainctx = g_main_context_new (); ldmainloop = g_main_loop_new (ldmainctx, FALSE); rdmainloop = g_main_loop_new (rdmainctx, FALSE); /* step: create the agents L and R */ lagent = nice_agent_new (lmainctx, NICE_COMPATIBILITY_MSN); ragent = nice_agent_new (rmainctx, NICE_COMPATIBILITY_MSN); g_object_set_data (G_OBJECT (lagent), "other-agent", ragent); g_object_set_data (G_OBJECT (ragent), "other-agent", lagent); g_object_set (G_OBJECT (lagent), "controlling-mode", TRUE, NULL); g_object_set (G_OBJECT (ragent), "controlling-mode", FALSE, NULL); g_object_set (G_OBJECT (lagent), "upnp", FALSE, NULL); g_object_set (G_OBJECT (ragent), "upnp", FALSE, NULL); /* step: specify which local interface to use */ if (!nice_address_set_from_string (&baseaddr, "127.0.0.1")) g_assert_not_reached (); nice_agent_add_local_address (lagent, &baseaddr); nice_agent_add_local_address (ragent, &baseaddr); g_signal_connect (G_OBJECT (lagent), "candidate-gathering-done", G_CALLBACK (cb_candidate_gathering_done), GUINT_TO_POINTER(1)); g_signal_connect (G_OBJECT (ragent), "candidate-gathering-done", G_CALLBACK (cb_candidate_gathering_done), GUINT_TO_POINTER(2)); g_signal_connect (G_OBJECT (lagent), "component-state-changed", G_CALLBACK (cb_component_state_changed), GUINT_TO_POINTER(1)); g_signal_connect (G_OBJECT (ragent), "component-state-changed", G_CALLBACK (cb_component_state_changed), GUINT_TO_POINTER(2)); g_signal_connect (G_OBJECT (lagent), "new-selected-pair", G_CALLBACK (cb_new_selected_pair), GUINT_TO_POINTER(1)); g_signal_connect (G_OBJECT (ragent), "new-selected-pair", G_CALLBACK (cb_new_selected_pair), GUINT_TO_POINTER(2)); stun_server = getenv ("NICE_STUN_SERVER"); stun_server_port = getenv ("NICE_STUN_SERVER_PORT"); if (stun_server) { g_object_set (G_OBJECT (lagent), "stun-server", stun_server, NULL); g_object_set (G_OBJECT (lagent), "stun-server-port", atoi (stun_server_port), NULL); g_object_set (G_OBJECT (ragent), "stun-server", stun_server, NULL); g_object_set (G_OBJECT (ragent), "stun-server-port", atoi (stun_server_port), NULL); } /* step: test setter/getter functions for properties */ { guint max_checks = 0; gchar *string = NULL; guint port = 0; gboolean mode = FALSE; g_object_get (G_OBJECT (lagent), "stun-server", &string, NULL); g_assert_true (stun_server == NULL || strcmp (string, stun_server) == 0); g_free (string); g_object_get (G_OBJECT (lagent), "stun-server-port", &port, NULL); g_assert_true (stun_server_port == NULL || port == (guint)atoi (stun_server_port)); g_object_get (G_OBJECT (lagent), "controlling-mode", &mode, NULL); g_assert_true (mode == TRUE); g_object_set (G_OBJECT (lagent), "max-connectivity-checks", 300, NULL); g_object_get (G_OBJECT (lagent), "max-connectivity-checks", &max_checks, NULL); g_assert_cmpuint (max_checks, ==, 300); } /* step: run test the first time */ g_debug ("test-thread: TEST STARTS / running test for the 1st time"); lthread = g_thread_new ("lthread libnice", mainloop_thread, lmainloop); rthread = g_thread_new ("rthread libnice", mainloop_thread, rmainloop); g_assert_true (lthread); g_assert_true (rthread); ls_id = nice_agent_add_stream (lagent, 2); rs_id = nice_agent_add_stream (ragent, 2); g_assert_cmpuint (ls_id, >, 0); g_assert_cmpuint (rs_id, >, 0); g_object_set_data (G_OBJECT (lagent), "id", GUINT_TO_POINTER (ls_id)); g_object_set_data (G_OBJECT (ragent), "id", GUINT_TO_POINTER (rs_id)); nice_agent_gather_candidates (lagent, ls_id); nice_agent_gather_candidates (ragent, rs_id); nice_agent_attach_recv (lagent, ls_id, 1, ldmainctx, cb_nice_recv, GUINT_TO_POINTER (1)); nice_agent_attach_recv (ragent, rs_id, 1, rdmainctx, cb_nice_recv, GUINT_TO_POINTER (2)); ldthread = g_thread_new ("ldthread libnice", mainloop_thread, ldmainloop); rdthread = g_thread_new ("rdthread libnice", mainloop_thread, rdmainloop); g_assert_true (ldthread); g_assert_true (rdthread); g_debug ("ragent_buffers: %d lagent_buffers: %d", global_lagent_buffers, global_ragent_buffers); g_mutex_lock (&buffers_mutex); while (global_ragent_buffers < 10 || global_lagent_buffers < 10) { g_cond_wait (&buffers_cond, &buffers_mutex); g_debug ("ragent_buffers: %d lagent_buffers: %d", global_lagent_buffers, global_ragent_buffers); } g_mutex_unlock (&buffers_mutex); while (!g_main_loop_is_running (ldmainloop)); while (g_main_loop_is_running (ldmainloop)) g_main_loop_quit (ldmainloop); while (!g_main_loop_is_running (rdmainloop)); while (g_main_loop_is_running (rdmainloop)) g_main_loop_quit (rdmainloop); while (!g_main_loop_is_running (lmainloop)); while (g_main_loop_is_running (lmainloop)) g_main_loop_quit (lmainloop); while (!g_main_loop_is_running (rmainloop)); while (g_main_loop_is_running (rmainloop)) g_main_loop_quit (rmainloop); g_thread_join (ldthread); g_thread_join (rdthread); g_thread_join (lthread); g_thread_join (rthread); /* note: verify that correct number of local candidates were reported */ g_assert_cmpint (g_atomic_int_get (&global_lagent_cands), ==, 1); g_assert_cmpint (g_atomic_int_get (&global_ragent_cands), ==, 1); g_object_add_weak_pointer (G_OBJECT (lagent), (gpointer *) &lagent); g_object_add_weak_pointer (G_OBJECT (ragent), (gpointer *) &ragent); g_object_unref (lagent); g_object_unref (ragent); WAIT_UNTIL_UNSET (lagent, lmainctx); WAIT_UNTIL_UNSET (ragent, rmainctx); g_main_loop_unref (lmainloop); g_main_loop_unref (rmainloop); g_main_loop_unref (ldmainloop); g_main_loop_unref (rdmainloop); #ifdef G_OS_WIN32 WSACleanup(); #endif return 0; }