2 * This file is part of the Nice GLib ICE library.
4 * (C) 2007 Nokia Corporation. All rights reserved.
5 * Contact: Kai Vehmanen
7 * The contents of this file are subject to the Mozilla Public License Version
8 * 1.1 (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at
10 * http://www.mozilla.org/MPL/
12 * Software distributed under the License is distributed on an "AS IS" basis,
13 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 * for the specific language governing rights and limitations under the
17 * The Original Code is the Nice GLib ICE library.
19 * The Initial Developers of the Original Code are Collabora Ltd and Nokia
20 * Corporation. All Rights Reserved.
25 * Alternatively, the contents of this file may be used under the terms of the
26 * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which
27 * case the provisions of LGPL are applicable instead of those above. If you
28 * wish to allow use of your version of this file only under the terms of the
29 * LGPL and not to allow others to use your version of this file under the
30 * MPL, indicate your decision by deleting the provisions above and replace
31 * them with the notice and other provisions required by the LGPL. If you do
32 * not delete the provisions above, a recipient may use your version of this
33 * file under either the MPL or the LGPL.
40 #include "agent-priv.h" /* for testing purposes */
45 static NiceComponentState global_lagent_state
= NICE_COMPONENT_STATE_LAST
;
46 static NiceComponentState global_ragent_state
= NICE_COMPONENT_STATE_LAST
;
47 static guint global_components_ready
= 0;
48 static guint global_components_ready_exit
= 0;
49 static guint global_components_failed
= 0;
50 static guint global_components_failed_exit
= 0;
51 static GMainLoop
*global_mainloop
= NULL
;
52 static gboolean global_lagent_gathering_done
= FALSE
;
53 static gboolean global_ragent_gathering_done
= FALSE
;
54 static gboolean global_lagent_ibr_received
= FALSE
;
55 static gboolean global_ragent_ibr_received
= FALSE
;
56 static int global_lagent_cands
= 0;
57 static int global_ragent_cands
= 0;
58 static gint global_ragent_read
= 0;
59 static gint global_ragent_read_exit
= 0;
61 static void priv_print_global_status (void)
63 g_debug ("\tgathering_done=%d", global_lagent_gathering_done
&& global_ragent_gathering_done
);
64 g_debug ("\tlstate=%d", global_lagent_state
);
65 g_debug ("\trstate=%d", global_ragent_state
);
68 static gboolean
timer_cb (gpointer pointer
)
70 g_debug ("test-restart:%s: %p", G_STRFUNC
, pointer
);
72 /* signal status via a global variable */
74 /* note: should not be reached, abort */
75 g_debug ("ERROR: test has got stuck, aborting...");
80 static void cb_nice_recv (NiceAgent
*agent
, guint stream_id
, guint component_id
, guint len
, gchar
*buf
, gpointer user_data
)
82 g_debug ("test-restart:%s: %p", G_STRFUNC
, user_data
);
84 /* XXX: dear compiler, these are for you: */
85 (void)agent
; (void)stream_id
; (void)component_id
; (void)buf
;
87 if ((intptr_t)user_data
== 2) {
88 global_ragent_read
+= len
;
90 if (global_ragent_read
== global_ragent_read_exit
)
91 g_main_loop_quit (global_mainloop
);
95 static void cb_candidate_gathering_done(NiceAgent
*agent
, guint stream_id
, gpointer data
)
97 g_debug ("test-restart:%s: %p", G_STRFUNC
, data
);
99 if ((intptr_t)data
== 1)
100 global_lagent_gathering_done
= TRUE
;
101 else if ((intptr_t)data
== 2)
102 global_ragent_gathering_done
= TRUE
;
104 if (global_lagent_gathering_done
&&
105 global_ragent_gathering_done
)
106 g_main_loop_quit (global_mainloop
);
108 /* XXX: dear compiler, these are for you: */
112 static void cb_component_state_changed (NiceAgent
*agent
, guint stream_id
, guint component_id
, guint state
, gpointer data
)
114 g_debug ("test-restart:%s: %p", __func__
, data
);
116 if ((intptr_t)data
== 1)
117 global_lagent_state
= state
;
118 else if ((intptr_t)data
== 2)
119 global_ragent_state
= state
;
121 if (state
== NICE_COMPONENT_STATE_READY
)
122 global_components_ready
++;
123 if (state
== NICE_COMPONENT_STATE_FAILED
)
124 global_components_failed
++;
126 g_debug ("test-restart: READY %u exit at %u.", global_components_ready
, global_components_ready_exit
);
128 /* signal status via a global variable */
129 if (global_components_ready
== global_components_ready_exit
) {
130 g_main_loop_quit (global_mainloop
);
134 /* signal status via a global variable */
135 if (global_components_failed
== global_components_failed_exit
) {
136 g_main_loop_quit (global_mainloop
);
140 /* XXX: dear compiler, these are for you: */
141 (void)agent
; (void)stream_id
; (void)data
; (void)component_id
;
144 static void cb_new_selected_pair(NiceAgent
*agent
, guint stream_id
, guint component_id
,
145 gchar
*lfoundation
, gchar
* rfoundation
, gpointer data
)
147 g_debug ("test-restart:%s: %p", __func__
, data
);
149 if ((intptr_t)data
== 1)
150 ++global_lagent_cands
;
151 else if ((intptr_t)data
== 2)
152 ++global_ragent_cands
;
154 /* XXX: dear compiler, these are for you: */
155 (void)agent
; (void)stream_id
; (void)component_id
; (void)lfoundation
; (void)rfoundation
;
158 static void cb_new_candidate(NiceAgent
*agent
, guint stream_id
, guint component_id
,
159 gchar
*foundation
, gpointer data
)
161 g_debug ("test-restart:%s: %p", __func__
, data
);
163 /* XXX: dear compiler, these are for you: */
164 (void)agent
; (void)stream_id
; (void)data
; (void)component_id
; (void)foundation
;
167 static void cb_initial_binding_request_received(NiceAgent
*agent
, guint stream_id
, gpointer data
)
169 g_debug ("test-restart:%s: %p", __func__
, data
);
171 if ((intptr_t)data
== 1)
172 global_lagent_ibr_received
= TRUE
;
173 else if ((intptr_t)data
== 2)
174 global_ragent_ibr_received
= TRUE
;
176 /* XXX: dear compiler, these are for you: */
177 (void)agent
; (void)stream_id
; (void)data
;
180 static void priv_get_local_addr (NiceAgent
*agent
, guint stream_id
, guint component_id
, NiceAddress
*dstaddr
)
183 cands
= nice_agent_get_local_candidates(agent
, stream_id
, component_id
);
184 for (i
= cands
; i
; i
= i
->next
) {
185 NiceCandidate
*cand
= i
->data
;
188 *dstaddr
= cand
->addr
;
191 for (i
= cands
; i
; i
= i
->next
)
192 nice_candidate_free ((NiceCandidate
*) i
->data
);
193 g_slist_free (cands
);
196 static int run_restart_test (NiceAgent
*lagent
, NiceAgent
*ragent
, NiceAddress
*baseaddr
)
198 NiceAddress laddr
, raddr
, laddr_rtcp
, raddr_rtcp
;
204 /* XXX: dear compiler, these are for you: */
207 memset (&cdes
, 0, sizeof(NiceCandidate
));
208 cdes
.priority
= 10000;
209 strcpy (cdes
.foundation
, "1");
210 cdes
.type
= NICE_CANDIDATE_TYPE_HOST
;
211 cdes
.transport
= NICE_CANDIDATE_TRANSPORT_UDP
;
213 /* step: initialize variables modified by the callbacks */
214 global_components_ready
= 0;
215 global_components_ready_exit
= 4;
216 global_components_failed
= 0;
217 global_components_failed_exit
= 4;
218 global_lagent_gathering_done
= FALSE
;
219 global_ragent_gathering_done
= FALSE
;
220 global_lagent_ibr_received
=
221 global_ragent_ibr_received
= FALSE
;
222 global_lagent_cands
=
223 global_ragent_cands
= 0;
224 global_ragent_read_exit
= -1;
226 g_object_set (G_OBJECT (lagent
), "controlling-mode", TRUE
, NULL
);
227 g_object_set (G_OBJECT (ragent
), "controlling-mode", FALSE
, NULL
);
229 /* step: add one stream, with RTP+RTCP components, to each agent */
230 ls_id
= nice_agent_add_stream (lagent
, 2);
231 rs_id
= nice_agent_add_stream (ragent
, 2);
232 g_assert (ls_id
> 0);
233 g_assert (rs_id
> 0);
235 nice_agent_gather_candidates (lagent
, ls_id
);
236 nice_agent_gather_candidates (ragent
, rs_id
);
238 /* step: attach to mainloop (needed to register the fds) */
239 nice_agent_attach_recv (lagent
, ls_id
, NICE_COMPONENT_TYPE_RTP
,
240 g_main_loop_get_context (global_mainloop
), cb_nice_recv
, (gpointer
)1);
241 nice_agent_attach_recv (lagent
, ls_id
, NICE_COMPONENT_TYPE_RTCP
,
242 g_main_loop_get_context (global_mainloop
), cb_nice_recv
, (gpointer
)1);
243 nice_agent_attach_recv (ragent
, rs_id
, NICE_COMPONENT_TYPE_RTP
,
244 g_main_loop_get_context (global_mainloop
), cb_nice_recv
, (gpointer
)2);
245 nice_agent_attach_recv (ragent
, rs_id
, NICE_COMPONENT_TYPE_RTCP
,
246 g_main_loop_get_context (global_mainloop
), cb_nice_recv
, (gpointer
)2);
248 /* step: run mainloop until local candidates are ready
249 * (see timer_cb() above) */
250 if (global_lagent_gathering_done
!= TRUE
||
251 global_ragent_gathering_done
!= TRUE
) {
252 g_debug ("test-restart: Added streams, running mainloop until 'candidate-gathering-done'...");
253 g_main_loop_run (global_mainloop
);
254 g_assert (global_lagent_gathering_done
== TRUE
);
255 g_assert (global_ragent_gathering_done
== TRUE
);
258 /* step: find out the local candidates of each agent */
260 priv_get_local_addr (ragent
, rs_id
, NICE_COMPONENT_TYPE_RTP
, &raddr
);
261 g_debug ("test-restart: local RTP port R %u",
262 nice_address_get_port (&raddr
));
264 priv_get_local_addr (lagent
, ls_id
, NICE_COMPONENT_TYPE_RTP
, &laddr
);
265 g_debug ("test-restart: local RTP port L %u",
266 nice_address_get_port (&laddr
));
268 priv_get_local_addr (ragent
, rs_id
, NICE_COMPONENT_TYPE_RTCP
, &raddr_rtcp
);
269 g_debug ("test-restart: local RTCP port R %u",
270 nice_address_get_port (&raddr_rtcp
));
272 priv_get_local_addr (lagent
, ls_id
, NICE_COMPONENT_TYPE_RTCP
, &laddr_rtcp
);
273 g_debug ("test-restart: local RTCP port L %u",
274 nice_address_get_port (&laddr_rtcp
));
276 /* step: pass the remote candidates to agents */
277 cands
= g_slist_append (NULL
, &cdes
);
279 gchar
*ufrag
= NULL
, *password
= NULL
;
280 nice_agent_get_local_credentials(lagent
, ls_id
, &ufrag
, &password
);
281 nice_agent_set_remote_credentials (ragent
,
282 rs_id
, ufrag
, password
);
285 nice_agent_get_local_credentials(ragent
, rs_id
, &ufrag
, &password
);
286 nice_agent_set_remote_credentials (lagent
,
287 ls_id
, ufrag
, password
);
291 cdes
.component_id
= NICE_COMPONENT_TYPE_RTP
;
293 nice_agent_set_remote_candidates (lagent
, ls_id
, NICE_COMPONENT_TYPE_RTP
, cands
);
295 nice_agent_set_remote_candidates (ragent
, rs_id
, NICE_COMPONENT_TYPE_RTP
, cands
);
296 cdes
.component_id
= NICE_COMPONENT_TYPE_RTCP
;
297 cdes
.addr
= raddr_rtcp
;
298 nice_agent_set_remote_candidates (lagent
, ls_id
, NICE_COMPONENT_TYPE_RTCP
, cands
);
299 cdes
.addr
= laddr_rtcp
;
300 nice_agent_set_remote_candidates (ragent
, rs_id
, NICE_COMPONENT_TYPE_RTCP
, cands
);
302 g_debug ("test-restart: Set properties, next running mainloop until connectivity checks succeed...");
304 /* step: run the mainloop until connectivity checks succeed
305 * (see timer_cb() above) */
306 g_main_loop_run (global_mainloop
);
308 /* note: verify that STUN binding requests were sent */
309 g_assert (global_lagent_ibr_received
== TRUE
);
310 g_assert (global_ragent_ibr_received
== TRUE
);
311 /* note: verify that correct number of local candidates were reported */
312 g_assert (global_lagent_cands
== 2);
313 g_assert (global_ragent_cands
== 2);
314 /* note: verify that agents are in correct state */
315 g_assert (global_lagent_state
== NICE_COMPONENT_STATE_READY
);
316 g_assert (global_ragent_state
== NICE_COMPONENT_STATE_READY
);
318 /* step: next send a packet (should work during restart) and
319 * then request an ICE restart by resetting the remote
320 * candidates for agent R */
322 g_debug ("-------------------------------------------\n"
323 "test-restart: Requesting a RESTART...");
325 /* step: send a new test packet from L ot R */
326 global_ragent_read
= 0;
327 g_assert (nice_agent_send (lagent
, ls_id
, 1, 16, "1234567812345678") == 16);
329 /* step: restart agents, exchange updated credentials */
330 tie_breaker
= ragent
->tie_breaker
;
331 nice_agent_restart (ragent
);
332 g_assert (tie_breaker
!= ragent
->tie_breaker
);
333 nice_agent_restart (lagent
);
335 gchar
*ufrag
= NULL
, *password
= NULL
;
336 nice_agent_get_local_credentials(lagent
, ls_id
, &ufrag
, &password
);
337 nice_agent_set_remote_credentials (ragent
,
338 rs_id
, ufrag
, password
);
341 nice_agent_get_local_credentials(ragent
, rs_id
, &ufrag
, &password
);
342 nice_agent_set_remote_credentials (lagent
,
343 ls_id
, ufrag
, password
);
348 /* send another packet after restart */
349 g_assert (nice_agent_send (lagent
, ls_id
, 1, 16, "1234567812345678") == 16);
351 /* step: reset state variables */
352 global_lagent_ibr_received
= FALSE
;
353 global_ragent_ibr_received
= FALSE
;
354 global_components_ready
= 0;
355 global_ragent_read_exit
= 32;
357 /* step: exchange remote candidates */
358 cdes
.component_id
= NICE_COMPONENT_TYPE_RTP
;
360 nice_agent_set_remote_candidates (lagent
, ls_id
, NICE_COMPONENT_TYPE_RTP
, cands
);
362 nice_agent_set_remote_candidates (ragent
, rs_id
, NICE_COMPONENT_TYPE_RTP
, cands
);
363 cdes
.component_id
= NICE_COMPONENT_TYPE_RTCP
;
364 cdes
.addr
= raddr_rtcp
;
365 nice_agent_set_remote_candidates (lagent
, ls_id
, NICE_COMPONENT_TYPE_RTCP
, cands
);
366 cdes
.addr
= laddr_rtcp
;
367 nice_agent_set_remote_candidates (ragent
, rs_id
, NICE_COMPONENT_TYPE_RTCP
, cands
);
369 g_main_loop_run (global_mainloop
);
371 /* note: verify that payload was succesfully received */
372 g_assert (global_ragent_read
== 32);
373 /* note: verify binding requests were resent after restart */
374 g_assert (global_lagent_ibr_received
== TRUE
);
375 g_assert (global_ragent_ibr_received
== TRUE
);
377 g_debug ("test-restart: Ran mainloop, removing streams...");
379 /* step: clean up resources and exit */
381 g_slist_free (cands
);
382 nice_agent_remove_stream (lagent
, ls_id
);
383 nice_agent_remove_stream (ragent
, rs_id
);
390 NiceAgent
*lagent
, *ragent
; /* agent's L and R */
391 NiceAddress baseaddr
;
394 const char *stun_server
= NULL
, *stun_server_port
= NULL
;
397 g_thread_init (NULL
);
398 global_mainloop
= g_main_loop_new (NULL
, FALSE
);
400 /* Note: impl limits ...
401 * - no multi-stream support
406 /* step: create the agents L and R */
407 lagent
= nice_agent_new (g_main_loop_get_context (global_mainloop
), NICE_COMPATIBILITY_RFC5245
);
408 ragent
= nice_agent_new (g_main_loop_get_context (global_mainloop
), NICE_COMPATIBILITY_RFC5245
);
411 /* step: add a timer to catch state changes triggered by signals */
412 timer_id
= g_timeout_add (30000, timer_cb
, NULL
);
414 /* step: specify which local interface to use */
415 if (!nice_address_set_from_string (&baseaddr
, "127.0.0.1"))
416 g_assert_not_reached ();
417 nice_agent_add_local_address (lagent
, &baseaddr
);
418 nice_agent_add_local_address (ragent
, &baseaddr
);
420 g_signal_connect (G_OBJECT (lagent
), "candidate-gathering-done",
421 G_CALLBACK (cb_candidate_gathering_done
), (gpointer
)1);
422 g_signal_connect (G_OBJECT (ragent
), "candidate-gathering-done",
423 G_CALLBACK (cb_candidate_gathering_done
), (gpointer
)2);
424 g_signal_connect (G_OBJECT (lagent
), "component-state-changed",
425 G_CALLBACK (cb_component_state_changed
), (gpointer
)1);
426 g_signal_connect (G_OBJECT (ragent
), "component-state-changed",
427 G_CALLBACK (cb_component_state_changed
), (gpointer
)2);
428 g_signal_connect (G_OBJECT (lagent
), "new-selected-pair",
429 G_CALLBACK (cb_new_selected_pair
), (gpointer
)1);
430 g_signal_connect (G_OBJECT (ragent
), "new-selected-pair",
431 G_CALLBACK (cb_new_selected_pair
), (gpointer
)2);
432 g_signal_connect (G_OBJECT (lagent
), "new-candidate",
433 G_CALLBACK (cb_new_candidate
), (gpointer
)1);
434 g_signal_connect (G_OBJECT (ragent
), "new-candidate",
435 G_CALLBACK (cb_new_candidate
), (gpointer
)2);
436 g_signal_connect (G_OBJECT (lagent
), "initial-binding-request-received",
437 G_CALLBACK (cb_initial_binding_request_received
), (gpointer
)1);
438 g_signal_connect (G_OBJECT (ragent
), "initial-binding-request-received",
439 G_CALLBACK (cb_initial_binding_request_received
), (gpointer
)2);
441 stun_server
= getenv ("NICE_STUN_SERVER");
442 stun_server_port
= getenv ("NICE_STUN_SERVER_PORT");
444 g_object_set (G_OBJECT (lagent
), "stun-server", stun_server
, NULL
);
445 g_object_set (G_OBJECT (lagent
), "stun-server-port", atoi (stun_server_port
), NULL
);
446 g_object_set (G_OBJECT (ragent
), "stun-server", stun_server
, NULL
);
447 g_object_set (G_OBJECT (ragent
), "stun-server-port", atoi (stun_server_port
), NULL
);
450 /* step: run test the first time */
451 g_debug ("test-restart: TEST STARTS / restart test");
452 result
= run_restart_test (lagent
, ragent
, &baseaddr
);
453 priv_print_global_status ();
454 g_assert (result
== 0);
455 g_assert (global_lagent_state
== NICE_COMPONENT_STATE_READY
);
456 g_assert (global_ragent_state
== NICE_COMPONENT_STATE_READY
);
458 g_object_unref (lagent
);
459 g_object_unref (ragent
);
462 g_main_loop_unref (global_mainloop
);
463 global_mainloop
= NULL
;
465 g_source_remove (timer_id
);