e3737900e3d17d69301bd51f8f3dc90c35617d35
[platform/upstream/libnice.git] / tests / test-turn.c
1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <string.h>
4
5 #include <gio/gio.h>
6 #include <agent.h>
7
8 static NiceComponentState global_lagent_state[2] = { NICE_COMPONENT_STATE_LAST, NICE_COMPONENT_STATE_LAST };
9 static NiceComponentState global_ragent_state[2] = { NICE_COMPONENT_STATE_LAST, NICE_COMPONENT_STATE_LAST };
10 static guint global_components_ready = 0;
11 static gboolean global_lagent_gathering_done = FALSE;
12 static gboolean global_ragent_gathering_done = FALSE;
13 static int global_lagent_cands = 0;
14 static int global_ragent_cands = 0;
15
16 #define TURN_USER "toto"
17 #define TURN_PASS "password"
18
19 static gboolean timer_cb (gpointer pointer)
20 {
21   g_debug ("test-turn:%s: %p", G_STRFUNC, pointer);
22
23   /* signal status via a global variable */
24
25   /* note: should not be reached, abort */
26   g_error ("ERROR: test has got stuck, aborting...");
27
28   return FALSE;
29 }
30
31 static void cb_nice_recv (NiceAgent *agent, guint stream_id, guint component_id, guint len, gchar *buf, gpointer user_data)
32 {
33   g_debug ("test-fullmode:%s: %p", G_STRFUNC, user_data);
34
35   /* XXX: dear compiler, these are for you: */
36   (void)agent; (void)stream_id; (void)component_id; (void)buf;
37
38   /*
39    * Lets ignore stun packets that got through
40    */
41   if (len < 8)
42     return;
43   if (strncmp ("12345678", buf, 8))
44     return;
45
46   if (component_id != 1)
47     return;
48
49 #if 0
50   if (GPOINTER_TO_UINT (user_data) == 2) {
51     global_ragent_read += len;
52   }
53 #endif
54 }
55
56 static void cb_candidate_gathering_done(NiceAgent *agent, guint stream_id, gpointer data)
57 {
58   g_debug ("test-fullmode:%s: %p", G_STRFUNC, data);
59
60   if (GPOINTER_TO_UINT (data) == 1)
61     global_lagent_gathering_done = TRUE;
62   else if (GPOINTER_TO_UINT (data) == 2)
63     global_ragent_gathering_done = TRUE;
64 }
65
66
67 static void cb_component_state_changed (NiceAgent *agent, guint stream_id, guint component_id, guint state, gpointer data)
68 {
69   gboolean ready_to_connected = FALSE;
70   g_debug ("test-fullmode:%s: %p", G_STRFUNC, data);
71
72   if (GPOINTER_TO_UINT (data) == 1) {
73     if (global_lagent_state[component_id - 1] == NICE_COMPONENT_STATE_READY &&
74         state == NICE_COMPONENT_STATE_CONNECTED)
75       ready_to_connected = TRUE;
76     global_lagent_state[component_id - 1] = state;
77   } else if (GPOINTER_TO_UINT (data) == 2) {
78     if (global_ragent_state[component_id - 1] == NICE_COMPONENT_STATE_READY &&
79         state == NICE_COMPONENT_STATE_CONNECTED)
80       ready_to_connected = TRUE;
81     global_ragent_state[component_id - 1] = state;
82   }
83
84   if (state == NICE_COMPONENT_STATE_READY)
85     global_components_ready++;
86   else if (state == NICE_COMPONENT_STATE_CONNECTED && ready_to_connected)
87     global_components_ready--;
88   g_assert (state != NICE_COMPONENT_STATE_FAILED);
89
90   g_debug ("test-turn: checks READY %u.", global_components_ready);
91 }
92
93 static void cb_new_selected_pair(NiceAgent *agent, guint stream_id,
94     guint component_id, gchar *lfoundation, gchar* rfoundation, gpointer data)
95 {
96   g_debug ("test-turn:%s: %p", G_STRFUNC, data);
97
98   if (GPOINTER_TO_UINT (data) == 1)
99     ++global_lagent_cands;
100   else if (GPOINTER_TO_UINT (data) == 2)
101     ++global_ragent_cands;
102 }
103
104 static void cb_closed (GObject *src, GAsyncResult *res, gpointer data)
105 {
106   NiceAgent *agent = NICE_AGENT (src);
107   g_debug ("test-turn:%s: %p", G_STRFUNC, agent);
108
109   *((gboolean *)data) = TRUE;
110 }
111
112 static void set_candidates (NiceAgent *from, guint from_stream,
113     NiceAgent *to, guint to_stream, guint component, gboolean remove_non_relay,
114     gboolean force_relay)
115 {
116   GSList *cands = NULL, *i;
117
118   cands = nice_agent_get_local_candidates (from, from_stream, component);
119   if (remove_non_relay) {
120   restart:
121     for (i = cands; i; i = i->next) {
122       NiceCandidate *cand = i->data;
123       if (force_relay)
124         g_assert_cmpint (cand->type, ==, NICE_CANDIDATE_TYPE_RELAYED);
125       if (cand->type != NICE_CANDIDATE_TYPE_RELAYED) {
126         cands = g_slist_remove (cands, cand);
127         nice_candidate_free (cand);
128         goto restart;
129       }
130     }
131   }
132   nice_agent_set_remote_candidates (to, to_stream, component, cands);
133
134   for (i = cands; i; i = i->next)
135     nice_candidate_free ((NiceCandidate *) i->data);
136   g_slist_free (cands);
137 }
138
139 static void set_credentials (NiceAgent *lagent, guint lstream,
140     NiceAgent *ragent, guint rstream)
141 {
142   gchar *ufrag = NULL, *password = NULL;
143
144   nice_agent_get_local_credentials(lagent, lstream, &ufrag, &password);
145   nice_agent_set_remote_credentials (ragent, rstream, ufrag, password);
146   g_free (ufrag);
147   g_free (password);
148   nice_agent_get_local_credentials(ragent, rstream, &ufrag, &password);
149   nice_agent_set_remote_credentials (lagent, lstream, ufrag, password);
150   g_free (ufrag);
151   g_free (password);
152 }
153
154 static void
155 run_test(guint turn_port, gboolean is_ipv6,
156     gboolean ice_udp, gboolean ice_tcp, gboolean force_relay,
157     gboolean remove_non_relay,
158     NiceRelayType turn_type)
159 {
160   NiceAgent *lagent, *ragent;      /* agent's L and R */
161   const gchar *localhost;
162   NiceAddress localaddr;
163   guint ls_id, rs_id;
164   gulong timer_id;
165   gboolean lagent_closed = FALSE;
166   gboolean ragent_closed = FALSE;
167
168   if (is_ipv6)
169     localhost = "::1";
170   else
171     localhost = "127.0.0.1";
172
173   /* step: initialize variables modified by the callbacks */
174   global_components_ready = 0;
175   global_lagent_gathering_done = FALSE;
176   global_ragent_gathering_done = FALSE;
177   global_lagent_cands = global_ragent_cands = 0;
178
179   lagent = nice_agent_new (NULL, NICE_COMPATIBILITY_RFC5245);
180   ragent = nice_agent_new (NULL, NICE_COMPATIBILITY_RFC5245);
181
182   g_object_set (G_OBJECT (lagent), "ice-tcp", ice_tcp, "ice-udp", ice_udp,
183       "force-relay", force_relay, NULL);
184   g_object_set (G_OBJECT (ragent), "ice-tcp", ice_tcp, "ice-udp", ice_udp,
185       "force-relay", force_relay, NULL);
186
187   g_object_set (G_OBJECT (lagent), "upnp", FALSE,  NULL);
188   g_object_set (G_OBJECT (ragent), "upnp", FALSE,  NULL);
189   nice_agent_set_software (lagent, "Test-turn, Left Agent");
190   nice_agent_set_software (ragent, "Test-turn, Right Agent");
191
192   timer_id = g_timeout_add (30000, timer_cb, NULL);
193
194
195   if (!nice_address_set_from_string (&localaddr, localhost))
196     g_assert_not_reached ();
197   nice_agent_add_local_address (lagent, &localaddr);
198   nice_agent_add_local_address (ragent, &localaddr);
199
200   g_signal_connect (G_OBJECT (lagent), "candidate-gathering-done",
201       G_CALLBACK (cb_candidate_gathering_done), GUINT_TO_POINTER(1));
202   g_signal_connect (G_OBJECT (ragent), "candidate-gathering-done",
203       G_CALLBACK (cb_candidate_gathering_done), GUINT_TO_POINTER (2));
204   g_signal_connect (G_OBJECT (lagent), "component-state-changed",
205       G_CALLBACK (cb_component_state_changed), GUINT_TO_POINTER (1));
206   g_signal_connect (G_OBJECT (ragent), "component-state-changed",
207       G_CALLBACK (cb_component_state_changed), GUINT_TO_POINTER (2));
208   g_signal_connect (G_OBJECT (lagent), "new-selected-pair",
209       G_CALLBACK (cb_new_selected_pair), GUINT_TO_POINTER(1));
210   g_signal_connect (G_OBJECT (ragent), "new-selected-pair",
211       G_CALLBACK (cb_new_selected_pair), GUINT_TO_POINTER (2));
212
213   g_object_set (G_OBJECT (lagent), "controlling-mode", TRUE, NULL);
214   g_object_set (G_OBJECT (ragent), "controlling-mode", FALSE, NULL);
215
216   ls_id = nice_agent_add_stream (lagent, 1);
217   rs_id = nice_agent_add_stream (ragent, 1);
218   g_assert_cmpuint (ls_id, >, 0);
219   g_assert_cmpuint (rs_id, >, 0);
220   nice_agent_set_relay_info(lagent, ls_id, 1,
221       localhost, turn_port, TURN_USER, TURN_PASS, turn_type);
222   nice_agent_set_relay_info(ragent, rs_id, 1,
223       localhost, turn_port, TURN_USER, TURN_PASS, turn_type);
224
225   g_assert (global_lagent_gathering_done == FALSE);
226   g_assert (global_ragent_gathering_done == FALSE);
227   g_debug ("test-turn: Added streams, running context until 'candidate-gathering-done'...");
228
229   /* Gather candidates and test nice_agent_set_port_range */
230   g_assert (nice_agent_gather_candidates (lagent, ls_id) == TRUE);
231   g_assert (nice_agent_gather_candidates (ragent, rs_id) == TRUE);
232
233   nice_agent_attach_recv (lagent, ls_id, NICE_COMPONENT_TYPE_RTP,
234       g_main_context_default (), cb_nice_recv, GUINT_TO_POINTER (1));
235   nice_agent_attach_recv (ragent, rs_id, NICE_COMPONENT_TYPE_RTP,
236       g_main_context_default (), cb_nice_recv, GUINT_TO_POINTER (2));
237
238   while (!global_lagent_gathering_done)
239     g_main_context_iteration (NULL, TRUE);
240   g_assert (global_lagent_gathering_done == TRUE);
241   while (!global_ragent_gathering_done)
242     g_main_context_iteration (NULL, TRUE);
243   g_assert (global_ragent_gathering_done == TRUE);
244
245   set_credentials (lagent, ls_id, ragent, rs_id);
246
247   set_candidates (ragent, rs_id, lagent, ls_id, NICE_COMPONENT_TYPE_RTP,
248       remove_non_relay, force_relay);
249   set_candidates (lagent, ls_id, ragent, rs_id, NICE_COMPONENT_TYPE_RTP,
250       remove_non_relay, force_relay);
251
252   while (global_lagent_state[0] != NICE_COMPONENT_STATE_READY ||
253       global_ragent_state[0] != NICE_COMPONENT_STATE_READY)
254     g_main_context_iteration (NULL, TRUE);
255   g_assert_cmpint (global_lagent_state[0], ==, NICE_COMPONENT_STATE_READY);
256   g_assert_cmpint (global_ragent_state[0], ==, NICE_COMPONENT_STATE_READY);
257
258   nice_agent_remove_stream (lagent, ls_id);
259   nice_agent_remove_stream (ragent, rs_id);
260
261   nice_agent_close_async (lagent, cb_closed, &lagent_closed);
262   nice_agent_close_async (ragent, cb_closed, &ragent_closed);
263
264   g_clear_object(&lagent);
265   g_clear_object(&ragent);
266
267   while (!lagent_closed || !ragent_closed) {
268     g_main_context_iteration (NULL, TRUE);
269   }
270
271   g_source_remove (timer_id);
272
273 }
274
275 guint global_turn_port;
276
277 static void
278 udp_no_force_no_remove_udp (void)
279 {
280   run_test(global_turn_port, FALSE /* is_ipv6 */,
281       TRUE /* ice_udp */,
282       FALSE /* ice_tcp */,
283       FALSE /* force_relay */,
284       FALSE /* remove_non_relay */,
285       NICE_RELAY_TYPE_TURN_UDP);
286 }
287
288 static void
289 udp_no_force_remove_udp (void)
290 {
291   run_test(global_turn_port, FALSE /* is_ipv6 */,
292       TRUE /* ice_udp */,
293       FALSE /* ice_tcp */,
294       FALSE /* force_relay */,
295       TRUE /* remove_non_relay */,
296       NICE_RELAY_TYPE_TURN_UDP);
297 }
298
299 static void
300 udp_force_no_remove_udp (void)
301 {
302   run_test(global_turn_port, FALSE /* is_ipv6 */,
303       TRUE /* ice_udp */,
304       FALSE /* ice_tcp */,
305       TRUE /* force_relay */,
306       FALSE /* remove_non_relay */,
307       NICE_RELAY_TYPE_TURN_UDP);
308 }
309
310 static void
311 udp_no_force_no_remove_tcp (void)
312 {
313   run_test(global_turn_port, FALSE /* is_ipv6 */,
314       TRUE /* ice_udp */,
315       FALSE /* ice_tcp */,
316       FALSE /* force_relay */,
317       FALSE /* remove_non_relay */,
318       NICE_RELAY_TYPE_TURN_TCP);
319 }
320
321 static void
322 udp_no_force_remove_tcp (void)
323 {
324   run_test(global_turn_port, FALSE /* is_ipv6 */,
325       TRUE /* ice_udp */,
326       FALSE /* ice_tcp */,
327       FALSE /* force_relay */,
328       TRUE /* remove_non_relay */,
329       NICE_RELAY_TYPE_TURN_TCP);
330 }
331
332 static void
333 udp_force_no_remove_tcp (void)
334 {
335   run_test(global_turn_port, FALSE /* is_ipv6 */,
336       TRUE /* ice_udp */,
337       FALSE /* ice_tcp */,
338       TRUE /* force_relay */,
339       FALSE /* remove_non_relay */,
340       NICE_RELAY_TYPE_TURN_TCP);
341 }
342
343
344
345
346
347 int
348 main (int argc, char **argv)
349 {
350   GSubprocess *sp;
351   GError *error = NULL;
352   gchar portstr[10];
353   int ret;
354   gchar *out_str = NULL;
355   gchar *err_str = NULL;
356
357   g_test_init (&argc, &argv, NULL);
358
359   global_turn_port = g_random_int_range (10000, 60000);
360   snprintf(portstr, 9, "%u", global_turn_port);
361
362   if (g_spawn_command_line_sync ("turnserver --help", &out_str, &err_str, NULL,
363           NULL) && err_str) {
364     if (!strstr(err_str, "--user")) {
365       g_print ("rfc5766-turn-server not installed, skipping turn test\n");
366       return 0;
367     }
368   } else {
369     g_print ("rfc5766-turn-server not installed, skipping turn test\n");
370     return 0;
371   }
372   g_free (err_str);
373   g_free (out_str);
374
375   sp = g_subprocess_new (G_SUBPROCESS_FLAGS_STDOUT_SILENCE, &error,
376       "turnserver",
377       "--user", "toto:0xaae440b3348d50265b63703117c7bfd5",
378       "--realm", "realm",
379       "--listening-port", portstr,
380       NULL);
381
382   g_test_add_func ("/nice/turn/udp", udp_no_force_no_remove_udp);
383   g_test_add_func ("/nice/turn/udp/remove_non_turn",
384       udp_no_force_remove_udp);
385   g_test_add_func ("/nice/turn/udp/force_relay",
386       udp_force_no_remove_udp);
387   g_test_add_func ("/nice/turn/udp/over-tcp", udp_no_force_no_remove_tcp);
388   g_test_add_func ("/nice/turn/udp/over-tcp/remove_non_turn",
389       udp_no_force_remove_tcp);
390   g_test_add_func ("/nice/turn/udp/over-tcp/force_relay",
391       udp_force_no_remove_tcp);
392
393   ret = g_test_run ();
394
395   g_subprocess_force_exit (sp);
396   g_subprocess_wait (sp, NULL, NULL);
397   g_clear_object (&sp);
398
399   return ret;
400 }