Imported Upstream version 0.1.17
[platform/upstream/libnice.git] / tests / test-thread.c
1 /*
2  * This file is part of the Nice GLib ICE library.
3  *
4  * Unit test for ICE full-mode related features.
5  *
6  * (C) 2007 Nokia Corporation. All rights reserved.
7  *  Contact: Kai Vehmanen
8  *
9  * The contents of this file are subject to the Mozilla Public License Version
10  * 1.1 (the "License"); you may not use this file except in compliance with
11  * the License. You may obtain a copy of the License at
12  * http://www.mozilla.org/MPL/
13  *
14  * Software distributed under the License is distributed on an "AS IS" basis,
15  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
16  * for the specific language governing rights and limitations under the
17  * License.
18  *
19  * The Original Code is the Nice GLib ICE library.
20  *
21  * The Initial Developers of the Original Code are Collabora Ltd and Nokia
22  * Corporation. All Rights Reserved.
23  *
24  * Contributors:
25  *   Kai Vehmanen, Nokia
26  *
27  * Alternatively, the contents of this file may be used under the terms of the
28  * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which
29  * case the provisions of LGPL are applicable instead of those above. If you
30  * wish to allow use of your version of this file only under the terms of the
31  * LGPL and not to allow others to use your version of this file under the
32  * MPL, indicate your decision by deleting the provisions above and replace
33  * them with the notice and other provisions required by the LGPL. If you do
34  * not delete the provisions above, a recipient may use your version of this
35  * file under either the MPL or the LGPL.
36  */
37 #ifdef HAVE_CONFIG_H
38 # include <config.h>
39 #endif
40
41 #include "agent.h"
42
43 #include <stdlib.h>
44 #include <string.h>
45 #ifndef G_OS_WIN32
46 #include <unistd.h>
47 #endif
48
49 volatile gint global_lagent_cands = 0;
50 volatile gint global_ragent_cands = 0;
51
52 GMutex buffers_mutex;
53 GCond buffers_cond;
54 gint global_lagent_buffers = 0;
55 gint global_ragent_buffers = 0;
56
57 /* Waits about 10 seconds for @var to be NULL/FALSE */
58 #define WAIT_UNTIL_UNSET(var, context)                  \
59   if (var)                                              \
60     {                                                   \
61       int _i;                                           \
62                                                         \
63       for (_i = 0; _i < 13 && (var); _i++)              \
64         {                                               \
65           g_usleep (1000 * (1 << _i));                  \
66           g_main_context_iteration (context, FALSE);    \
67         }                                               \
68                                                         \
69       g_assert (!(var));                                \
70     }
71
72 static gpointer
73 mainloop_thread (gpointer data)
74 {
75   GMainLoop *loop = data;
76
77   g_main_loop_run (loop);
78
79   return NULL;
80 }
81
82
83 static void
84 cb_new_selected_pair(NiceAgent *agent,
85     guint stream_id,
86     guint component_id,
87     gchar *lfoundation,
88     gchar* rfoundation,
89     gpointer data)
90 {
91   g_debug ("test-thread:%s: %p", G_STRFUNC, data);
92
93   if (GPOINTER_TO_UINT (data) == 1)
94     g_atomic_int_inc (&global_lagent_cands);
95   else if (GPOINTER_TO_UINT (data) == 2)
96     g_atomic_int_inc (&global_ragent_cands);
97 }
98
99
100 static void cb_candidate_gathering_done(NiceAgent *agent, guint stream_id, gpointer data)
101 {
102   NiceAgent *other = g_object_get_data (G_OBJECT (agent), "other-agent");
103   gchar *ufrag = NULL, *password = NULL;
104   GSList *cands, *i;
105   guint id, other_id;
106   gpointer tmp;
107
108   g_debug ("test-thread:%s", G_STRFUNC);
109
110   tmp = g_object_get_data (G_OBJECT (agent), "id");
111   id = GPOINTER_TO_UINT (tmp);
112   tmp = g_object_get_data (G_OBJECT (other), "id");
113   other_id = GPOINTER_TO_UINT (tmp);
114
115   nice_agent_get_local_credentials(agent, id, &ufrag, &password);
116   nice_agent_set_remote_credentials (other,
117       other_id, ufrag, password);
118   g_free (ufrag);
119   g_free (password);
120
121   cands = nice_agent_get_local_candidates(agent, id, 1);
122   g_assert (cands != NULL);
123
124   nice_agent_set_remote_candidates (other, other_id, 1, cands);
125
126   for (i = cands; i; i = i->next)
127     nice_candidate_free ((NiceCandidate *) i->data);
128   g_slist_free (cands);
129 }
130
131
132 static void cb_nice_recv (NiceAgent *agent, guint stream_id, guint component_id, guint len, gchar *buf, gpointer user_data)
133 {
134   gchar data[10];
135   gint *count = NULL;
136
137   g_debug ("Agent %p Stream %d Component: %d Received %u bytes", agent,
138       stream_id, component_id, len);
139
140   g_mutex_lock (&buffers_mutex);
141   if (GPOINTER_TO_UINT (user_data) == 1)
142     count = &global_lagent_buffers;
143   else if (GPOINTER_TO_UINT (user_data) == 2)
144     count = &global_ragent_buffers;
145   else
146     g_error ("Invalid agent ?");
147
148   if (*count == 10)
149     return;
150
151
152   memset (data, *count + '1', 10);
153
154   g_assert_cmpmem (buf, len, data, 10);
155   g_assert_cmpuint (len, ==, 10);
156
157   (*count)++;
158
159   g_cond_signal (&buffers_cond);
160   g_mutex_unlock (&buffers_mutex);
161 }
162
163
164 static void cb_component_state_changed (NiceAgent *agent,
165     guint stream_id,
166     guint component_id,
167     guint state,
168     gpointer user_data)
169 {
170   int i;
171   gchar data[10];
172
173   g_debug("Agent %p Stream %d Component %d state %s", agent, stream_id,
174       component_id, nice_component_state_to_string (state));
175
176   if (state != NICE_COMPONENT_STATE_READY)
177     return;
178
179   for (i=0; i<10; i++)
180     {
181       memset (data, i+'1', 10);
182
183       g_debug ("Agent %p Stream: %d Component: %d Sending 10 bytes", agent, stream_id,
184           component_id);
185
186       nice_agent_send (agent, stream_id, component_id, 10, data);
187     }
188 }
189
190
191 int main (void)
192 {
193   NiceAgent *lagent, *ragent;      /* agent's L and R */
194   NiceAddress baseaddr;
195   const char *stun_server = NULL, *stun_server_port = NULL;
196   GMainContext *lmainctx, *rmainctx;
197   GMainLoop *lmainloop, *rmainloop;
198   GThread *lthread, *rthread;
199   guint ls_id, rs_id;
200   GMainContext *ldmainctx, *rdmainctx;
201   GMainLoop *ldmainloop, *rdmainloop;
202   GThread *ldthread, *rdthread;
203
204 #ifdef G_OS_WIN32
205   WSADATA w;
206   WSAStartup(0x0202, &w);
207 #endif
208
209   lmainctx = g_main_context_new ();
210   rmainctx = g_main_context_new ();
211   lmainloop = g_main_loop_new (lmainctx, FALSE);
212   rmainloop = g_main_loop_new (rmainctx, FALSE);
213
214   ldmainctx = g_main_context_new ();
215   rdmainctx = g_main_context_new ();
216   ldmainloop = g_main_loop_new (ldmainctx, FALSE);
217   rdmainloop = g_main_loop_new (rdmainctx, FALSE);
218
219   /* step: create the agents L and R */
220   lagent = nice_agent_new (lmainctx, NICE_COMPATIBILITY_MSN);
221   ragent = nice_agent_new (rmainctx, NICE_COMPATIBILITY_MSN);
222
223   g_object_set_data (G_OBJECT (lagent), "other-agent", ragent);
224   g_object_set_data (G_OBJECT (ragent), "other-agent", lagent);
225
226   g_object_set (G_OBJECT (lagent), "controlling-mode", TRUE, NULL);
227   g_object_set (G_OBJECT (ragent), "controlling-mode", FALSE, NULL);
228   g_object_set (G_OBJECT (lagent), "upnp", FALSE, NULL);
229   g_object_set (G_OBJECT (ragent), "upnp", FALSE, NULL);
230
231   /* step: specify which local interface to use */
232   if (!nice_address_set_from_string (&baseaddr, "127.0.0.1"))
233     g_assert_not_reached ();
234   nice_agent_add_local_address (lagent, &baseaddr);
235   nice_agent_add_local_address (ragent, &baseaddr);
236
237   g_signal_connect (G_OBJECT (lagent), "candidate-gathering-done",
238       G_CALLBACK (cb_candidate_gathering_done), GUINT_TO_POINTER(1));
239   g_signal_connect (G_OBJECT (ragent), "candidate-gathering-done",
240       G_CALLBACK (cb_candidate_gathering_done), GUINT_TO_POINTER(2));
241   g_signal_connect (G_OBJECT (lagent), "component-state-changed",
242       G_CALLBACK (cb_component_state_changed), GUINT_TO_POINTER(1));
243   g_signal_connect (G_OBJECT (ragent), "component-state-changed",
244       G_CALLBACK (cb_component_state_changed), GUINT_TO_POINTER(2));
245   g_signal_connect (G_OBJECT (lagent), "new-selected-pair",
246       G_CALLBACK (cb_new_selected_pair), GUINT_TO_POINTER(1));
247   g_signal_connect (G_OBJECT (ragent), "new-selected-pair",
248       G_CALLBACK (cb_new_selected_pair), GUINT_TO_POINTER(2));
249
250   stun_server = getenv ("NICE_STUN_SERVER");
251   stun_server_port = getenv ("NICE_STUN_SERVER_PORT");
252   if (stun_server) {
253     g_object_set (G_OBJECT (lagent), "stun-server", stun_server,  NULL);
254     g_object_set (G_OBJECT (lagent), "stun-server-port", atoi (stun_server_port),  NULL);
255     g_object_set (G_OBJECT (ragent), "stun-server", stun_server,  NULL);
256     g_object_set (G_OBJECT (ragent), "stun-server-port", atoi (stun_server_port),  NULL);
257   }
258
259   /* step: test setter/getter functions for properties */
260   {
261     guint max_checks = 0;
262     gchar *string = NULL;
263     guint port = 0;
264     gboolean mode = FALSE;
265     g_object_get (G_OBJECT (lagent), "stun-server", &string, NULL);
266     g_assert (stun_server == NULL || strcmp (string, stun_server) == 0);
267     g_free (string);
268     g_object_get (G_OBJECT (lagent), "stun-server-port", &port, NULL);
269     g_assert (stun_server_port == NULL || port == (guint)atoi (stun_server_port));
270     g_object_get (G_OBJECT (lagent), "controlling-mode", &mode, NULL);
271     g_assert (mode == TRUE);
272     g_object_set (G_OBJECT (lagent), "max-connectivity-checks", 300, NULL);
273     g_object_get (G_OBJECT (lagent), "max-connectivity-checks", &max_checks, NULL);
274     g_assert_cmpuint (max_checks, ==, 300);
275   }
276
277   /* step: run test the first time */
278   g_debug ("test-thread: TEST STARTS / running test for the 1st time");
279
280   lthread = g_thread_new ("lthread libnice", mainloop_thread, lmainloop);
281   rthread = g_thread_new ("rthread libnice", mainloop_thread, rmainloop);
282
283   g_assert (lthread);
284   g_assert (rthread);
285
286   ls_id = nice_agent_add_stream (lagent, 2);
287   rs_id = nice_agent_add_stream (ragent, 2);
288   g_assert_cmpuint (ls_id, >, 0);
289   g_assert_cmpuint (rs_id, >, 0);
290
291   g_object_set_data (G_OBJECT (lagent), "id", GUINT_TO_POINTER (ls_id));
292   g_object_set_data (G_OBJECT (ragent), "id", GUINT_TO_POINTER (rs_id));
293
294   nice_agent_gather_candidates (lagent, ls_id);
295   nice_agent_gather_candidates (ragent, rs_id);
296
297   nice_agent_attach_recv (lagent, ls_id, 1, ldmainctx, cb_nice_recv,
298       GUINT_TO_POINTER (1));
299   nice_agent_attach_recv (ragent, rs_id, 1, rdmainctx, cb_nice_recv,
300       GUINT_TO_POINTER (2));
301
302   ldthread = g_thread_new ("ldthread libnice", mainloop_thread, ldmainloop);
303   rdthread = g_thread_new ("rdthread libnice", mainloop_thread, rdmainloop);
304
305   g_assert (ldthread);
306   g_assert (rdthread);
307
308   g_debug ("ragent_buffers: %d lagent_buffers: %d", global_lagent_buffers,
309       global_ragent_buffers);
310   g_mutex_lock (&buffers_mutex);
311   while (global_ragent_buffers < 10 ||
312       global_lagent_buffers < 10) {
313     g_cond_wait (&buffers_cond, &buffers_mutex);
314     g_debug ("ragent_buffers: %d lagent_buffers: %d", global_lagent_buffers,
315         global_ragent_buffers);
316   }
317   g_mutex_unlock (&buffers_mutex);
318
319
320   while (!g_main_loop_is_running (ldmainloop));
321   while (g_main_loop_is_running (ldmainloop))
322     g_main_loop_quit (ldmainloop);
323   while (!g_main_loop_is_running (rdmainloop));
324   while (g_main_loop_is_running (rdmainloop))
325     g_main_loop_quit (rdmainloop);
326   while (!g_main_loop_is_running (lmainloop));
327   while (g_main_loop_is_running (lmainloop))
328     g_main_loop_quit (lmainloop);
329   while (!g_main_loop_is_running (rmainloop));
330   while (g_main_loop_is_running (rmainloop))
331     g_main_loop_quit (rmainloop);
332
333   g_thread_join (ldthread);
334   g_thread_join (rdthread);
335   g_thread_join (lthread);
336   g_thread_join (rthread);
337
338   /* note: verify that correct number of local candidates were reported */
339   g_assert_cmpint (g_atomic_int_get (&global_lagent_cands), ==, 1);
340   g_assert_cmpint (g_atomic_int_get (&global_ragent_cands), ==, 1);
341
342   g_object_add_weak_pointer (G_OBJECT (lagent), (gpointer *) &lagent);
343   g_object_add_weak_pointer (G_OBJECT (ragent), (gpointer *) &ragent);
344
345   g_object_unref (lagent);
346   g_object_unref (ragent);
347
348   WAIT_UNTIL_UNSET (lagent, lmainctx);
349   WAIT_UNTIL_UNSET (ragent, rmainctx);
350
351   g_main_loop_unref (lmainloop);
352   g_main_loop_unref (rmainloop);
353   g_main_loop_unref (ldmainloop);
354   g_main_loop_unref (rdmainloop);
355
356 #ifdef G_OS_WIN32
357   WSACleanup();
358 #endif
359   return 0;
360 }