Imported Upstream version 0.1.17
[platform/upstream/libnice.git] / tests / test-icetcp.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
46 static NiceComponentState global_lagent_state[2] = { NICE_COMPONENT_STATE_LAST, NICE_COMPONENT_STATE_LAST };
47 static NiceComponentState global_ragent_state[2] = { NICE_COMPONENT_STATE_LAST, NICE_COMPONENT_STATE_LAST };
48 static guint global_components_ready = 0;
49 static guint global_components_ready_exit = 0;
50 static guint global_components_failed = 0;
51 static guint global_components_failed_exit = 0;
52 static GMainLoop *global_mainloop = NULL;
53 static gboolean global_lagent_gathering_done = FALSE;
54 static gboolean global_ragent_gathering_done = FALSE;
55 static gboolean global_lagent_ibr_received = FALSE;
56 static gboolean global_ragent_ibr_received = FALSE;
57 static gboolean global_ready_reached = FALSE;
58 static int global_lagent_cands = 0;
59 static int global_ragent_cands = 0;
60 static gint global_ragent_read = 0;
61 static guint global_exit_when_ibr_received = 0;
62
63 static void priv_print_global_status (void)
64 {
65   g_debug ("\tgathering_done=%d", global_lagent_gathering_done && global_ragent_gathering_done);
66   g_debug ("\tlstate[rtp]=%d [rtcp]=%d", global_lagent_state[0], global_lagent_state[1]);
67   g_debug ("\trstate[rtp]=%d [rtcp]=%d", global_ragent_state[0], global_ragent_state[1]);
68   g_debug ("\tL cands=%d R cands=%d", global_lagent_cands, global_ragent_cands);
69 }
70
71 static gboolean timer_cb (gpointer pointer)
72 {
73   g_debug ("test-icetcp:%s: %p", G_STRFUNC, pointer);
74
75   /* signal status via a global variable */
76
77   /* note: should not be reached, abort */
78   g_error ("ERROR: test has got stuck, aborting...");
79
80   return FALSE;
81 }
82
83 static void cb_writable (NiceAgent*agent, guint stream_id, guint component_id)
84 {
85     g_debug ("Transport is now writable, stopping mainloop");
86     g_main_loop_quit (global_mainloop);
87 }
88
89 static void cb_nice_recv (NiceAgent *agent, guint stream_id, guint component_id, guint len, gchar *buf, gpointer user_data)
90 {
91   g_debug ("test-icetcp:%s: %p", G_STRFUNC, user_data);
92
93   /* XXX: dear compiler, these are for you: */
94   (void)agent; (void)stream_id; (void)component_id; (void)buf;
95
96   /*
97    * Lets ignore stun packets that got through
98    */
99   if (len < 8)
100     return;
101   if (strncmp ("12345678", buf, 8))
102     return;
103
104   if (GPOINTER_TO_UINT (user_data) == 2) {
105     g_debug ("right agent received %d bytes, stopping mainloop", len);
106     global_ragent_read = len;
107     g_main_loop_quit (global_mainloop);
108   }
109 }
110
111 static void cb_candidate_gathering_done(NiceAgent *agent, guint stream_id, gpointer data)
112 {
113   g_debug ("test-icetcp:%s: %p", G_STRFUNC, data);
114
115   if (GPOINTER_TO_UINT (data) == 1)
116     global_lagent_gathering_done = TRUE;
117   else if (GPOINTER_TO_UINT (data) == 2)
118     global_ragent_gathering_done = TRUE;
119
120   if (global_lagent_gathering_done &&
121       global_ragent_gathering_done)
122     g_main_loop_quit (global_mainloop);
123
124   /* XXX: dear compiler, these are for you: */
125   (void)agent;
126 }
127
128 static void check_loop_quit_condition (void)
129 {
130   if (global_ready_reached &&
131       global_lagent_cands >= 2 && global_ragent_cands >= 2) {
132     g_main_loop_quit (global_mainloop);
133   }
134 }
135
136 static void cb_component_state_changed (NiceAgent *agent, guint stream_id, guint component_id, guint state, gpointer data)
137 {
138   gboolean ready_to_connected = FALSE;
139   g_debug ("test-icetcp:%s: %p", G_STRFUNC, data);
140
141   if (GPOINTER_TO_UINT (data) == 1) {
142     if (global_lagent_state[component_id - 1] == NICE_COMPONENT_STATE_READY &&
143         state == NICE_COMPONENT_STATE_CONNECTED)
144       ready_to_connected = TRUE;
145     global_lagent_state[component_id - 1] = state;
146   } else if (GPOINTER_TO_UINT (data) == 2) {
147     if (global_ragent_state[component_id - 1] == NICE_COMPONENT_STATE_READY &&
148         state == NICE_COMPONENT_STATE_CONNECTED)
149       ready_to_connected = TRUE;
150     global_ragent_state[component_id - 1] = state;
151   }
152
153   if (state == NICE_COMPONENT_STATE_READY)
154     global_components_ready++;
155   else if (state == NICE_COMPONENT_STATE_CONNECTED && ready_to_connected)
156     global_components_ready--;
157   if (state == NICE_COMPONENT_STATE_FAILED)
158     global_components_failed++;
159
160   g_debug ("test-icetcp: checks READY/EXIT-AT %u/%u.", global_components_ready, global_components_ready_exit);
161   g_debug ("test-icetcp: checks FAILED/EXIT-AT %u/%u.", global_components_failed, global_components_failed_exit);
162
163   /* signal status via a global variable */
164   if (global_components_ready == global_components_ready_exit &&
165       global_components_failed == global_components_failed_exit &&
166       global_ready_reached == FALSE) {
167     g_debug ("Components ready/failed achieved. Stopping mailoop");
168     global_ready_reached = TRUE;
169   }
170
171   check_loop_quit_condition ();
172
173 #if 0
174   /* signal status via a global variable */
175   if (global_components_failed == global_components_failed_exit) {
176     g_main_loop_quit (global_mainloop); 
177     return;
178   }
179 #endif
180
181   /* XXX: dear compiler, these are for you: */
182   (void)agent; (void)stream_id; (void)data; (void)component_id;
183 }
184
185 static void cb_new_selected_pair(NiceAgent *agent, guint stream_id, guint component_id, 
186                                  gchar *lfoundation, gchar* rfoundation, gpointer data)
187 {
188   g_debug ("test-icetcp:%s: %p", G_STRFUNC, data);
189
190   if (GPOINTER_TO_UINT (data) == 1)
191     ++global_lagent_cands;
192   else if (GPOINTER_TO_UINT (data) == 2)
193     ++global_ragent_cands;
194
195   check_loop_quit_condition ();
196
197   /* XXX: dear compiler, these are for you: */
198   (void)agent; (void)stream_id; (void)component_id; (void)lfoundation; (void)rfoundation;
199 }
200
201 static void cb_new_candidate(NiceAgent *agent, guint stream_id, guint component_id, 
202                              gchar *foundation, gpointer data)
203 {
204   g_debug ("test-icetcp:%s: %p", G_STRFUNC, data);
205
206   /* XXX: dear compiler, these are for you: */
207   (void)agent; (void)stream_id; (void)data; (void)component_id; (void)foundation;
208 }
209
210 static void cb_initial_binding_request_received(NiceAgent *agent, guint stream_id, gpointer data)
211 {
212   g_debug ("test-icetcp:%s: %p", G_STRFUNC, data);
213
214   if (GPOINTER_TO_UINT (data) == 1)
215     global_lagent_ibr_received = TRUE;
216   else if (GPOINTER_TO_UINT (data) == 2)
217     global_ragent_ibr_received = TRUE;
218
219   if (global_exit_when_ibr_received) {
220     g_debug ("Received initial binding request. Stopping mailoop");
221     g_main_loop_quit (global_mainloop);
222   }
223
224   /* XXX: dear compiler, these are for you: */
225   (void)agent; (void)stream_id; (void)data;
226 }
227
228 static void set_candidates (NiceAgent *from, guint from_stream,
229     NiceAgent *to, guint to_stream, guint component)
230 {
231   GSList *cands = NULL, *i;
232
233   cands = nice_agent_get_local_candidates (from, from_stream, component);
234
235  restart:
236   for (i = cands; i; i = i->next) {
237     NiceCandidate *cand = i->data;
238     if (cand->transport == NICE_CANDIDATE_TRANSPORT_UDP) {
239       cands = g_slist_remove (cands, cand);
240       nice_candidate_free (cand);
241       goto restart;
242     }
243   }
244
245
246   nice_agent_set_remote_candidates (to, to_stream, component, cands);
247
248   for (i = cands; i; i = i->next)
249     nice_candidate_free ((NiceCandidate *) i->data);
250   g_slist_free (cands);
251 }
252
253 static void set_credentials (NiceAgent *lagent, guint lstream,
254     NiceAgent *ragent, guint rstream)
255 {
256   gchar *ufrag = NULL, *password = NULL;
257
258   nice_agent_get_local_credentials(lagent, lstream, &ufrag, &password);
259   nice_agent_set_remote_credentials (ragent, rstream, ufrag, password);
260   g_free (ufrag);
261   g_free (password);
262   nice_agent_get_local_credentials(ragent, rstream, &ufrag, &password);
263   nice_agent_set_remote_credentials (lagent, lstream, ufrag, password);
264   g_free (ufrag);
265   g_free (password);
266 }
267
268 static int run_full_test (NiceAgent *lagent, NiceAgent *ragent, NiceAddress *baseaddr, guint ready, guint failed)
269 {
270   guint ls_id, rs_id;
271   gint ret;
272
273   /* XXX: dear compiler, this is for you */
274   (void)baseaddr;
275
276   /* step: initialize variables modified by the callbacks */
277   global_components_ready = 0;
278   global_components_ready_exit = ready;
279   global_components_failed = 0;
280   global_components_failed_exit = failed;
281   global_lagent_gathering_done = FALSE;
282   global_ragent_gathering_done = FALSE;
283   global_lagent_ibr_received =
284     global_ragent_ibr_received = FALSE;
285   global_lagent_cands =
286     global_ragent_cands = 0;
287   global_ready_reached = FALSE;
288
289   g_object_set (G_OBJECT (lagent), "controlling-mode", TRUE, NULL);
290   g_object_set (G_OBJECT (ragent), "controlling-mode", FALSE, NULL);
291
292   /* step: add one stream, with RTP+RTCP components, to each agent */
293   ls_id = nice_agent_add_stream (lagent, 2);
294
295   rs_id = nice_agent_add_stream (ragent, 2);
296   g_assert_cmpuint (ls_id, >, 0);
297   g_assert_cmpuint (rs_id, >, 0);
298
299   /* Gather candidates */
300   g_assert (nice_agent_gather_candidates (lagent, ls_id) == TRUE);
301   g_assert (nice_agent_gather_candidates (ragent, rs_id) == TRUE);
302
303   {
304     GSList *cands = NULL, *i;
305     NiceCandidate *cand = NULL;
306
307     cands = nice_agent_get_local_candidates (lagent, ls_id, 1);
308     g_assert_cmpuint (g_slist_length (cands), ==, 2);
309     cand = cands->data;
310     g_assert_cmpint (cand->type, ==, NICE_CANDIDATE_TYPE_HOST);
311     g_assert (cand->transport == NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE ||
312               cand->transport == NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE);
313     cand = cands->next->data;
314     g_assert_cmpint (cand->type, ==, NICE_CANDIDATE_TYPE_HOST);
315     g_assert (cand->transport == NICE_CANDIDATE_TRANSPORT_TCP_ACTIVE ||
316               cand->transport == NICE_CANDIDATE_TRANSPORT_TCP_PASSIVE);
317     for (i = cands; i; i = i->next)
318       nice_candidate_free ((NiceCandidate *) i->data);
319     g_slist_free (cands);
320   }
321
322   /* step: attach to mainloop (needed to register the fds) */
323   nice_agent_attach_recv (lagent, ls_id, NICE_COMPONENT_TYPE_RTP,
324       g_main_loop_get_context (global_mainloop), cb_nice_recv,
325       GUINT_TO_POINTER (1));
326   nice_agent_attach_recv (lagent, ls_id, NICE_COMPONENT_TYPE_RTCP,
327       g_main_loop_get_context (global_mainloop), cb_nice_recv,
328       GUINT_TO_POINTER (1));
329   nice_agent_attach_recv (ragent, rs_id, NICE_COMPONENT_TYPE_RTP,
330       g_main_loop_get_context (global_mainloop), cb_nice_recv,
331       GUINT_TO_POINTER (2));
332   nice_agent_attach_recv (ragent, rs_id, NICE_COMPONENT_TYPE_RTCP,
333       g_main_loop_get_context (global_mainloop), cb_nice_recv,
334       GUINT_TO_POINTER (2));
335
336   /* step: run mainloop until local candidates are ready
337    *       (see timer_cb() above) */
338   if (global_lagent_gathering_done != TRUE ||
339       global_ragent_gathering_done != TRUE) {
340     g_debug ("test-icetcp: Added streams, running mainloop until 'candidate-gathering-done'...");
341     g_main_loop_run (global_mainloop);
342     g_assert (global_lagent_gathering_done == TRUE);
343     g_assert (global_ragent_gathering_done == TRUE);
344   }
345
346   set_credentials (lagent, ls_id, ragent, rs_id);
347
348   /* step: pass the remote candidates to agents  */
349   set_candidates (ragent, rs_id, lagent, ls_id, NICE_COMPONENT_TYPE_RTP);
350   set_candidates (ragent, rs_id, lagent, ls_id, NICE_COMPONENT_TYPE_RTCP);
351   set_candidates (lagent, ls_id, ragent, rs_id, NICE_COMPONENT_TYPE_RTP);
352   set_candidates (lagent, ls_id, ragent, rs_id, NICE_COMPONENT_TYPE_RTCP);
353
354   g_debug ("test-icetcp: Set properties, next running mainloop until connectivity checks succeed...");
355
356   /* step: run the mainloop until connectivity checks succeed
357    *       (see timer_cb() above) */
358   g_main_loop_run (global_mainloop);
359
360   /* note: verify that STUN binding requests were sent */
361   g_assert (global_lagent_ibr_received == TRUE);
362   g_assert (global_ragent_ibr_received == TRUE);
363
364   /* note: test payload send and receive */
365   global_ragent_read = 0;
366   ret = nice_agent_send (lagent, ls_id, 1, 16, "1234567812345678");
367   if (ret == -1)
368   {
369     gboolean reliable = FALSE;
370     g_object_get (G_OBJECT (lagent), "reliable", &reliable, NULL);
371     g_debug ("Sending data returned -1 in %s mode", reliable?"Reliable":"Non-reliable");
372     if (reliable) {
373       gulong signal_handler;
374       signal_handler = g_signal_connect (G_OBJECT (lagent),
375           "reliable-transport-writable", G_CALLBACK (cb_writable), NULL);
376       g_debug ("Running mainloop until transport is writable");
377       g_main_loop_run (global_mainloop);
378       g_signal_handler_disconnect(G_OBJECT (lagent), signal_handler);
379
380       ret = nice_agent_send (lagent, ls_id, 1, 16, "1234567812345678");
381     }
382   }
383   g_debug ("Sent %d bytes", ret);
384   g_assert_cmpint (ret, ==, 16);
385   g_main_loop_run (global_mainloop);
386   g_assert_cmpint (global_ragent_read, ==, 16);
387
388   g_debug ("test-icetcp: Ran mainloop, removing streams...");
389
390   /* step: clean up resources and exit */
391
392   nice_agent_remove_stream (lagent, ls_id);
393   nice_agent_remove_stream (ragent, rs_id);
394
395   return 0;
396 }
397
398 int main (void)
399 {
400   NiceAgent *lagent, *ragent;      /* agent's L and R */
401   NiceAddress baseaddr;
402   int result;
403   guint timer_id;
404
405 #ifdef G_OS_WIN32
406   WSADATA w;
407
408   WSAStartup(0x0202, &w);
409 #endif
410
411   global_mainloop = g_main_loop_new (NULL, FALSE);
412
413   /* step: create the agents L and R */
414   lagent = nice_agent_new (g_main_loop_get_context (global_mainloop),
415       NICE_COMPATIBILITY_RFC5245);
416   ragent = nice_agent_new (g_main_loop_get_context (global_mainloop),
417       NICE_COMPATIBILITY_RFC5245);
418
419   g_object_set (G_OBJECT (lagent), "ice-udp", FALSE,  NULL);
420   g_object_set (G_OBJECT (ragent), "ice-udp", FALSE,  NULL);
421   g_object_set (G_OBJECT (lagent), "upnp", FALSE, NULL);
422   g_object_set (G_OBJECT (ragent), "upnp", FALSE, NULL);
423   nice_agent_set_software (lagent, "Test-icetcp, Left Agent");
424   nice_agent_set_software (ragent, "Test-icetcp, Right Agent");
425
426   /* step: add a timer to catch state changes triggered by signals */
427   timer_id = g_timeout_add (30000, timer_cb, NULL);
428
429   /* step: specify which local interface to use */
430   if (!nice_address_set_from_string (&baseaddr, "127.0.0.1"))
431     g_assert_not_reached ();
432   nice_agent_add_local_address (lagent, &baseaddr);
433   nice_agent_add_local_address (ragent, &baseaddr);
434
435   g_signal_connect (G_OBJECT (lagent), "candidate-gathering-done",
436       G_CALLBACK (cb_candidate_gathering_done), GUINT_TO_POINTER(1));
437   g_signal_connect (G_OBJECT (ragent), "candidate-gathering-done",
438       G_CALLBACK (cb_candidate_gathering_done), GUINT_TO_POINTER (2));
439   g_signal_connect (G_OBJECT (lagent), "component-state-changed",
440       G_CALLBACK (cb_component_state_changed), GUINT_TO_POINTER (1));
441   g_signal_connect (G_OBJECT (ragent), "component-state-changed",
442       G_CALLBACK (cb_component_state_changed), GUINT_TO_POINTER (2));
443   g_signal_connect (G_OBJECT (lagent), "new-selected-pair",
444       G_CALLBACK (cb_new_selected_pair), GUINT_TO_POINTER(1));
445   g_signal_connect (G_OBJECT (ragent), "new-selected-pair",
446       G_CALLBACK (cb_new_selected_pair), GUINT_TO_POINTER (2));
447   g_signal_connect (G_OBJECT (lagent), "new-candidate",
448       G_CALLBACK (cb_new_candidate), GUINT_TO_POINTER (1));
449   g_signal_connect (G_OBJECT (ragent), "new-candidate",
450       G_CALLBACK (cb_new_candidate), GUINT_TO_POINTER (2));
451   g_signal_connect (G_OBJECT (lagent), "initial-binding-request-received",
452       G_CALLBACK (cb_initial_binding_request_received),
453       GUINT_TO_POINTER (1));
454   g_signal_connect (G_OBJECT (ragent), "initial-binding-request-received",
455       G_CALLBACK (cb_initial_binding_request_received),
456       GUINT_TO_POINTER (2));
457
458   /* step: run test the first time */
459   g_debug ("test-icetcp: TEST STARTS / running test for the 1st time");
460   result = run_full_test (lagent, ragent, &baseaddr, 4 ,0);
461   priv_print_global_status ();
462   g_assert_cmpint (result, ==, 0);
463   g_assert_cmpint (global_lagent_state[0], ==, NICE_COMPONENT_STATE_READY);
464   g_assert_cmpint (global_lagent_state[1], ==, NICE_COMPONENT_STATE_READY);
465   g_assert_cmpint (global_ragent_state[0], ==, NICE_COMPONENT_STATE_READY);
466   g_assert_cmpint (global_ragent_state[1], ==, NICE_COMPONENT_STATE_READY);
467   /* note: verify that correct number of local candidates were reported */
468   g_assert_cmpint (global_lagent_cands, >=, 2);
469   g_assert_cmpint (global_ragent_cands, >=, 2);
470
471
472   /* step: run test again without unref'ing agents */
473   g_debug ("test-icetcp: TEST STARTS / running test for the 2nd time");
474   result = run_full_test (lagent, ragent, &baseaddr, 4, 0);
475   priv_print_global_status ();
476   g_assert_cmpint (result, ==, 0);
477   g_assert_cmpint (global_lagent_state[0], ==, NICE_COMPONENT_STATE_READY);
478   g_assert_cmpint (global_lagent_state[1], ==, NICE_COMPONENT_STATE_READY);
479   g_assert_cmpint (global_ragent_state[0], ==, NICE_COMPONENT_STATE_READY);
480   g_assert_cmpint (global_ragent_state[1], ==, NICE_COMPONENT_STATE_READY);
481   /* note: verify that correct number of local candidates were reported */
482   g_assert_cmpint (global_lagent_cands, >=, 2);
483   g_assert_cmpint (global_ragent_cands, >=, 2);
484
485   g_object_unref (lagent);
486   g_object_unref (ragent);
487
488   g_main_loop_unref (global_mainloop);
489   global_mainloop = NULL;
490
491   g_source_remove (timer_id);
492 #ifdef G_OS_WIN32
493   WSACleanup();
494 #endif
495   return result;
496 }