2 * This file is part of the Nice GLib ICE library.
4 * Unit test for ICE full-mode related features.
6 * (C) 2007 Nokia Corporation. All rights reserved.
7 * Contact: Kai Vehmanen
8 * (C) 2017 Collabora Ltd
9 * Contact: Olivier Crete <olivier.crete@collabora.com>
11 * The contents of this file are subject to the Mozilla Public License Version
12 * 1.1 (the "License"); you may not use this file except in compliance with
13 * the License. You may obtain a copy of the License at
14 * http://www.mozilla.org/MPL/
16 * Software distributed under the License is distributed on an "AS IS" basis,
17 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
18 * for the specific language governing rights and limitations under the
21 * The Original Code is the Nice GLib ICE library.
23 * The Initial Developers of the Original Code are Collabora Ltd and Nokia
24 * Corporation. All Rights Reserved.
29 * Alternatively, the contents of this file may be used under the terms of the
30 * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which
31 * case the provisions of LGPL are applicable instead of those above. If you
32 * wish to allow use of your version of this file only under the terms of the
33 * LGPL and not to allow others to use your version of this file under the
34 * MPL, indicate your decision by deleting the provisions above and replace
35 * them with the notice and other provisions required by the LGPL. If you do
36 * not delete the provisions above, a recipient may use your version of this
37 * file under either the MPL or the LGPL.
45 #include "socket/socket.h"
52 static NiceComponentState global_lagent_state[2] = { NICE_COMPONENT_STATE_LAST, NICE_COMPONENT_STATE_LAST };
53 static NiceComponentState global_ragent_state[2] = { NICE_COMPONENT_STATE_LAST, NICE_COMPONENT_STATE_LAST };
54 static guint global_components_ready = 0;
55 static guint global_components_ready_exit = 0;
56 static guint global_components_failed = 0;
57 static guint global_components_failed_exit = 0;
58 static GMainLoop *global_mainloop = NULL;
59 static gboolean global_lagent_gathering_done = FALSE;
60 static gboolean global_ragent_gathering_done = FALSE;
61 static gboolean global_lagent_ibr_received = FALSE;
62 static gboolean global_ragent_ibr_received = FALSE;
63 static int global_lagent_cands = 0;
64 static int global_ragent_cands = 0;
65 static gint global_ragent_read = 0;
66 static guint global_exit_when_ibr_received = 0;
68 static void priv_print_global_status (void)
70 g_debug ("\tgathering_done=%d", global_lagent_gathering_done && global_ragent_gathering_done);
71 g_debug ("\tlstate[rtp]=%d [rtcp]=%d", global_lagent_state[0], global_lagent_state[1]);
72 g_debug ("\trstate[rtp]=%d [rtcp]=%d", global_ragent_state[0], global_ragent_state[1]);
73 g_debug ("\tL cands=%d R cands=%d", global_lagent_cands, global_ragent_cands);
76 static gboolean timer_cb (gpointer pointer)
78 g_debug ("test-drop-invalid:%s: %p", G_STRFUNC, pointer);
80 /* signal status via a global variable */
82 /* note: should not be reached, abort */
83 g_error ("ERROR: test has got stuck, aborting...");
88 static void cb_nice_recv (NiceAgent *agent, guint stream_id, guint component_id, guint len, gchar *buf, gpointer user_data)
90 g_debug ("test-drop-invalid:%s: %p", G_STRFUNC, user_data);
92 /* XXX: dear compiler, these are for you: */
93 (void)agent; (void)stream_id; (void)component_id; (void)buf;
96 * Assert on any unreleated packet received. This would include anything
97 * send before the negotiation is over.
99 g_assert_cmpuint (len, ==, 16);
100 g_assert (strncmp ("1234567812345678", buf, 16) == 0);
102 if (component_id == 2)
105 if (GPOINTER_TO_UINT (user_data) == 2) {
106 g_debug ("right agent received %d bytes, stopping mainloop", len);
107 global_ragent_read = len;
108 g_main_loop_quit (global_mainloop);
112 static void cb_candidate_gathering_done(NiceAgent *agent, guint stream_id, gpointer data)
114 g_debug ("test-drop-invalid:%s: %p", G_STRFUNC, data);
116 if (GPOINTER_TO_UINT (data) == 1)
117 global_lagent_gathering_done = TRUE;
118 else if (GPOINTER_TO_UINT (data) == 2)
119 global_ragent_gathering_done = TRUE;
121 if (global_lagent_gathering_done &&
122 global_ragent_gathering_done)
123 g_main_loop_quit (global_mainloop);
125 /* XXX: dear compiler, these are for you: */
129 static void cb_component_state_changed (NiceAgent *agent, guint stream_id, guint component_id, guint state, gpointer data)
131 gboolean ready_to_connected = FALSE;
132 g_debug ("test-drop-invalid:%s: %p", G_STRFUNC, data);
134 if (GPOINTER_TO_UINT (data) == 1) {
135 if (global_lagent_state[component_id - 1] == NICE_COMPONENT_STATE_READY &&
136 state == NICE_COMPONENT_STATE_CONNECTED)
137 ready_to_connected = TRUE;
138 global_lagent_state[component_id - 1] = state;
139 } else if (GPOINTER_TO_UINT (data) == 2) {
140 if (global_ragent_state[component_id - 1] == NICE_COMPONENT_STATE_READY &&
141 state == NICE_COMPONENT_STATE_CONNECTED)
142 ready_to_connected = TRUE;
143 global_ragent_state[component_id - 1] = state;
146 if (state == NICE_COMPONENT_STATE_READY)
147 global_components_ready++;
148 else if (state == NICE_COMPONENT_STATE_CONNECTED && ready_to_connected)
149 global_components_ready--;
150 if (state == NICE_COMPONENT_STATE_FAILED)
151 global_components_failed++;
153 g_debug ("test-drop-invalid: checks READY/EXIT-AT %u/%u.", global_components_ready, global_components_ready_exit);
154 g_debug ("test-drop-invalid: checks FAILED/EXIT-AT %u/%u.", global_components_failed, global_components_failed_exit);
156 /* signal status via a global variable */
157 if (global_components_ready == global_components_ready_exit &&
158 global_components_failed == global_components_failed_exit) {
159 g_debug ("Components ready/failed achieved. Stopping mailoop");
160 g_main_loop_quit (global_mainloop);
164 /* XXX: dear compiler, these are for you: */
165 (void)agent; (void)stream_id; (void)data; (void)component_id;
168 static void cb_new_selected_pair(NiceAgent *agent, guint stream_id, guint component_id,
169 gchar *lfoundation, gchar* rfoundation, gpointer data)
171 g_debug ("test-drop-invalid:%s: %p", G_STRFUNC, data);
173 if (GPOINTER_TO_UINT (data) == 1)
174 ++global_lagent_cands;
175 else if (GPOINTER_TO_UINT (data) == 2)
176 ++global_ragent_cands;
178 /* XXX: dear compiler, these are for you: */
179 (void)agent; (void)stream_id; (void)component_id; (void)lfoundation; (void)rfoundation;
182 static void cb_new_candidate(NiceAgent *agent, guint stream_id, guint component_id,
183 gchar *foundation, gpointer data)
185 g_debug ("test-drop-invalid:%s: %p", G_STRFUNC, data);
187 /* XXX: dear compiler, these are for you: */
188 (void)agent; (void)stream_id; (void)data; (void)component_id; (void)foundation;
191 static void cb_initial_binding_request_received(NiceAgent *agent, guint stream_id, gpointer data)
193 g_debug ("test-drop-invalid:%s: %p", G_STRFUNC, data);
195 if (GPOINTER_TO_UINT (data) == 1)
196 global_lagent_ibr_received = TRUE;
197 else if (GPOINTER_TO_UINT (data) == 2)
198 global_ragent_ibr_received = TRUE;
200 if (global_exit_when_ibr_received) {
201 g_debug ("Received initial binding request. Stopping mailoop");
202 g_main_loop_quit (global_mainloop);
205 /* XXX: dear compiler, these are for you: */
206 (void)agent; (void)stream_id; (void)data;
209 static void set_candidates (NiceAgent *from, guint from_stream,
210 NiceAgent *to, guint to_stream, guint component)
212 GSList *cands = NULL;
213 GSList *peer_cands = NULL;
214 GSList *item1, *item2;
216 cands = nice_agent_get_local_candidates (from, from_stream, component);
217 peer_cands = nice_agent_get_local_candidates (to, to_stream, component);
222 * Send packets that shoudl be dropped.
225 for (item1 = cands; item1; item1 = item1->next) {
226 NiceCandidate *cand = item1->data;
227 NiceSocket *nicesock = cand->sockptr;
231 for (item2 = peer_cands; item2; item2 = item2->next) {
232 NiceCandidate *target_cand = item2->data;
234 nice_socket_send (nicesock, &target_cand->addr, 12, "123456789AB");
239 nice_agent_set_remote_candidates (to, to_stream, component, cands);
241 g_slist_free_full (cands, (GDestroyNotify) nice_candidate_free);
242 g_slist_free_full (peer_cands, (GDestroyNotify) nice_candidate_free);
245 static void set_credentials (NiceAgent *lagent, guint lstream,
246 NiceAgent *ragent, guint rstream)
248 gchar *ufrag = NULL, *password = NULL;
250 nice_agent_get_local_credentials(lagent, lstream, &ufrag, &password);
251 nice_agent_set_remote_credentials (ragent, rstream, ufrag, password);
254 nice_agent_get_local_credentials(ragent, rstream, &ufrag, &password);
255 nice_agent_set_remote_credentials (lagent, lstream, ufrag, password);
261 get_port (NiceAgent *agent, guint stream_id, guint component_id)
263 GSList *cands = nice_agent_get_local_candidates (agent, stream_id,
268 g_assert (cands != NULL);
270 for (item = cands; item; item = item->next) {
271 NiceCandidate *cand = item->data;
272 port = nice_address_get_port (&cand->addr);
275 g_assert (port != 0);
277 g_slist_free_full (cands, (GDestroyNotify) nice_candidate_free);
282 static int run_full_test (NiceAgent *lagent, NiceAgent *ragent, NiceAddress *baseaddr, guint ready, guint failed)
288 /* XXX: dear compiler, this is for you */
291 /* step: initialize variables modified by the callbacks */
292 global_components_ready = 0;
293 global_components_ready_exit = ready;
294 global_components_failed = 0;
295 global_components_failed_exit = failed;
296 global_lagent_gathering_done = FALSE;
297 global_ragent_gathering_done = FALSE;
298 global_lagent_ibr_received =
299 global_ragent_ibr_received = FALSE;
300 global_lagent_cands =
301 global_ragent_cands = 0;
303 g_object_set (G_OBJECT (lagent), "controlling-mode", TRUE, NULL);
304 g_object_set (G_OBJECT (ragent), "controlling-mode", FALSE, NULL);
306 /* step: add one stream, with RTP+RTCP components, to each agent */
307 ls_id = nice_agent_add_stream (lagent, 2);
309 rs_id = nice_agent_add_stream (ragent, 2);
310 g_assert_cmpuint (ls_id, >, 0);
311 g_assert_cmpuint (rs_id, >, 0);
313 /* Gather candidates and test nice_agent_set_port_range */
314 nice_agent_set_port_range (lagent, ls_id, 1, 10000, 11000);
315 nice_agent_set_port_range (lagent, ls_id, 2, 11000, 12000);
316 g_assert (nice_agent_gather_candidates (lagent, ls_id) == TRUE);
318 port = get_port (lagent, ls_id, 1);
319 nice_agent_set_port_range (ragent, rs_id, 1, 12000, 13000);
320 nice_agent_set_port_range (ragent, rs_id, 2, port, port);
321 g_assert (nice_agent_gather_candidates (ragent, rs_id) == FALSE);
322 g_assert (nice_agent_get_local_candidates (ragent, rs_id, 1) == NULL);
323 g_assert (nice_agent_get_local_candidates (ragent, rs_id, 2) == NULL);
324 nice_agent_set_port_range (ragent, rs_id, 2, 13000, 14000);
325 g_assert (nice_agent_gather_candidates (ragent, rs_id) == TRUE);
328 GSList *cands = NULL, *i;
329 NiceCandidate *cand = NULL;
331 cands = nice_agent_get_local_candidates (lagent, ls_id, 1);
332 g_assert_cmpuint (g_slist_length (cands), ==, 1);
334 g_assert_cmpint (cand->type, ==, NICE_CANDIDATE_TYPE_HOST);
335 g_assert_cmpuint (nice_address_get_port (&cand->addr), >=, 10000);
336 g_assert_cmpuint (nice_address_get_port (&cand->addr), <=, 11000);
337 for (i = cands; i; i = i->next)
338 nice_candidate_free ((NiceCandidate *) i->data);
339 g_slist_free (cands);
341 cands = nice_agent_get_local_candidates (lagent, ls_id, 2);
342 g_assert_cmpuint (g_slist_length (cands), ==, 1);
344 g_assert_cmpuint (cand->type, ==, NICE_CANDIDATE_TYPE_HOST);
345 g_assert_cmpuint (nice_address_get_port (&cand->addr), >=, 11000);
346 g_assert_cmpuint (nice_address_get_port (&cand->addr), <=, 12000);
347 for (i = cands; i; i = i->next)
348 nice_candidate_free ((NiceCandidate *) i->data);
349 g_slist_free (cands);
351 cands = nice_agent_get_local_candidates (ragent, rs_id, 1);
352 g_assert_cmpuint (g_slist_length (cands), ==, 1);
354 g_assert_cmpint (cand->type, ==, NICE_CANDIDATE_TYPE_HOST);
355 g_assert_cmpuint (nice_address_get_port (&cand->addr), >=, 12000);
356 g_assert_cmpuint (nice_address_get_port (&cand->addr), <=, 13000);
357 for (i = cands; i; i = i->next)
358 nice_candidate_free ((NiceCandidate *) i->data);
359 g_slist_free (cands);
361 cands = nice_agent_get_local_candidates (ragent, rs_id, 2);
362 g_assert_cmpuint (g_slist_length (cands), ==, 1);
364 g_assert_cmpint (cand->type, ==, NICE_CANDIDATE_TYPE_HOST);
365 g_assert_cmpuint (nice_address_get_port (&cand->addr), >=, 13000);
366 g_assert_cmpuint (nice_address_get_port (&cand->addr), <=, 14000);
367 for (i = cands; i; i = i->next)
368 nice_candidate_free ((NiceCandidate *) i->data);
369 g_slist_free (cands);
373 /* step: attach to mainloop (needed to register the fds) */
374 nice_agent_attach_recv (lagent, ls_id, NICE_COMPONENT_TYPE_RTP,
375 g_main_loop_get_context (global_mainloop), cb_nice_recv,
376 GUINT_TO_POINTER (1));
377 nice_agent_attach_recv (lagent, ls_id, NICE_COMPONENT_TYPE_RTCP,
378 g_main_loop_get_context (global_mainloop), cb_nice_recv,
379 GUINT_TO_POINTER (1));
380 nice_agent_attach_recv (ragent, rs_id, NICE_COMPONENT_TYPE_RTP,
381 g_main_loop_get_context (global_mainloop), cb_nice_recv,
382 GUINT_TO_POINTER (2));
383 nice_agent_attach_recv (ragent, rs_id, NICE_COMPONENT_TYPE_RTCP,
384 g_main_loop_get_context (global_mainloop), cb_nice_recv,
385 GUINT_TO_POINTER (2));
387 /* step: run mainloop until local candidates are ready
388 * (see timer_cb() above) */
389 if (global_lagent_gathering_done != TRUE ||
390 global_ragent_gathering_done != TRUE) {
391 g_debug ("test-drop-invalid: Added streams, running mainloop until 'candidate-gathering-done'...");
392 g_main_loop_run (global_mainloop);
393 g_assert (global_lagent_gathering_done == TRUE);
394 g_assert (global_ragent_gathering_done == TRUE);
397 set_credentials (lagent, ls_id, ragent, rs_id);
399 /* step: pass the remote candidates to agents */
400 set_candidates (ragent, rs_id, lagent, ls_id, NICE_COMPONENT_TYPE_RTP);
401 set_candidates (ragent, rs_id, lagent, ls_id, NICE_COMPONENT_TYPE_RTCP);
402 set_candidates (lagent, ls_id, ragent, rs_id, NICE_COMPONENT_TYPE_RTP);
403 set_candidates (lagent, ls_id, ragent, rs_id, NICE_COMPONENT_TYPE_RTCP);
405 g_debug ("test-drop-invalid: Set properties, next running mainloop until connectivity checks succeed...");
407 /* step: run the mainloop until connectivity checks succeed
408 * (see timer_cb() above) */
409 g_main_loop_run (global_mainloop);
411 /* note: verify that STUN binding requests were sent */
412 g_assert (global_lagent_ibr_received == TRUE);
413 g_assert (global_ragent_ibr_received == TRUE);
415 /* note: Send a packet from another address */
416 /* These should also be ignored */
418 NiceCandidate *local_cand = NULL;
419 NiceCandidate *remote_cand = NULL;
422 g_assert (nice_agent_get_selected_pair (lagent, ls_id, 1, &local_cand,
424 g_assert (local_cand);
425 g_assert (remote_cand);
427 tmpsock = nice_udp_bsd_socket_new (NULL);
428 nice_socket_send (tmpsock, &remote_cand->addr, 4, "ABCD");
429 nice_socket_send (tmpsock, &local_cand->addr, 5, "ABCDE");
430 nice_socket_free (tmpsock);
433 /* note: test payload send and receive */
434 global_ragent_read = 0;
435 ret = nice_agent_send (lagent, ls_id, 1, 16, "1234567812345678");
436 g_assert (ret != -1);
437 g_debug ("Sent %d bytes", ret);
438 g_assert_cmpint (ret, ==, 16);
439 while (global_ragent_read != 16)
440 g_main_context_iteration (NULL, TRUE);
441 g_assert_cmpint (global_ragent_read, ==, 16);
443 g_debug ("test-drop-invalid: Ran mainloop, removing streams...");
445 /* step: clean up resources and exit */
447 nice_agent_remove_stream (lagent, ls_id);
448 nice_agent_remove_stream (ragent, rs_id);
455 NiceAgent *lagent, *ragent; /* agent's L and R */
456 NiceAddress baseaddr;
463 WSAStartup(0x0202, &w);
466 global_mainloop = g_main_loop_new (NULL, FALSE);
468 /* step: create the agents L and R */
469 lagent = nice_agent_new (g_main_loop_get_context (global_mainloop),
470 NICE_COMPATIBILITY_RFC5245);
471 ragent = nice_agent_new (g_main_loop_get_context (global_mainloop),
472 NICE_COMPATIBILITY_RFC5245);
474 g_object_set (G_OBJECT (lagent), "ice-tcp", FALSE, NULL);
475 g_object_set (G_OBJECT (ragent), "ice-tcp", FALSE, NULL);
477 g_object_set (G_OBJECT (lagent), "upnp", FALSE, NULL);
478 g_object_set (G_OBJECT (ragent), "upnp", FALSE, NULL);
480 nice_agent_set_software (lagent, "test-drop-invalid, Left Agent");
481 nice_agent_set_software (ragent, "test-drop-invalid, Right Agent");
483 /* step: add a timer to catch state changes triggered by signals */
484 timer_id = g_timeout_add (30000, timer_cb, NULL);
486 /* step: specify which local interface to use */
487 if (!nice_address_set_from_string (&baseaddr, "127.0.0.1"))
488 g_assert_not_reached ();
489 nice_agent_add_local_address (lagent, &baseaddr);
490 nice_agent_add_local_address (ragent, &baseaddr);
492 g_signal_connect (G_OBJECT (lagent), "candidate-gathering-done",
493 G_CALLBACK (cb_candidate_gathering_done), GUINT_TO_POINTER(1));
494 g_signal_connect (G_OBJECT (ragent), "candidate-gathering-done",
495 G_CALLBACK (cb_candidate_gathering_done), GUINT_TO_POINTER (2));
496 g_signal_connect (G_OBJECT (lagent), "component-state-changed",
497 G_CALLBACK (cb_component_state_changed), GUINT_TO_POINTER (1));
498 g_signal_connect (G_OBJECT (ragent), "component-state-changed",
499 G_CALLBACK (cb_component_state_changed), GUINT_TO_POINTER (2));
500 g_signal_connect (G_OBJECT (lagent), "new-selected-pair",
501 G_CALLBACK (cb_new_selected_pair), GUINT_TO_POINTER(1));
502 g_signal_connect (G_OBJECT (ragent), "new-selected-pair",
503 G_CALLBACK (cb_new_selected_pair), GUINT_TO_POINTER (2));
504 g_signal_connect (G_OBJECT (lagent), "new-candidate",
505 G_CALLBACK (cb_new_candidate), GUINT_TO_POINTER (1));
506 g_signal_connect (G_OBJECT (ragent), "new-candidate",
507 G_CALLBACK (cb_new_candidate), GUINT_TO_POINTER (2));
508 g_signal_connect (G_OBJECT (lagent), "initial-binding-request-received",
509 G_CALLBACK (cb_initial_binding_request_received),
510 GUINT_TO_POINTER (1));
511 g_signal_connect (G_OBJECT (ragent), "initial-binding-request-received",
512 G_CALLBACK (cb_initial_binding_request_received),
513 GUINT_TO_POINTER (2));
515 g_object_set (G_OBJECT (lagent), "upnp", FALSE, NULL);
516 g_object_set (G_OBJECT (ragent), "upnp", FALSE, NULL);
519 /* step: run test the first time */
520 g_debug ("test-drop-invalid: TEST STARTS / running test for the 1st time");
521 result = run_full_test (lagent, ragent, &baseaddr, 4 ,0);
522 priv_print_global_status ();
523 g_assert_cmpint (result, ==, 0);
524 g_assert_cmpint (global_lagent_state[0], ==, NICE_COMPONENT_STATE_READY);
525 g_assert_cmpint (global_lagent_state[1], ==, NICE_COMPONENT_STATE_READY);
526 g_assert_cmpint (global_ragent_state[0], ==, NICE_COMPONENT_STATE_READY);
527 g_assert_cmpint (global_ragent_state[1], ==, NICE_COMPONENT_STATE_READY);
528 /* When using TURN, we get peer reflexive candidates for the host cands
529 that we removed so we can get another new_selected_pair signal later
530 depending on timing/racing, we could double (or not) the amount we expected
533 /* note: verify that correct number of local candidates were reported */
534 g_assert_cmpint (global_lagent_cands, ==, 2);
535 g_assert_cmpint (global_ragent_cands, ==, 2);
537 g_object_unref (lagent);
538 g_object_unref (ragent);
540 g_main_loop_unref (global_mainloop);
541 global_mainloop = NULL;
543 g_source_remove (timer_id);