Imported Upstream version 0.1.17
[platform/upstream/libnice.git] / tests / test-new-trickle.c
1 /*
2  * This file is part of the Nice GLib ICE library.
3  *
4  * Unit test for ICE in trickle mode (adding remote candidates while gathering
5  * local candidates).
6  *
7  * (C) 2012 Collabora Ltd.
8  *  Contact: Rohan Garg
9  *           Youness Alaoui
10  *
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/
15  *
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
19  * License.
20  *
21  * The Original Code is the Nice GLib ICE library.
22  *
23  * The Initial Developers of the Original Code are Collabora Ltd and Nokia
24  * Corporation.
25  *
26  * Contributors:
27  *   Rohan Garg
28  *
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.
38  */
39
40 #include <glib.h>
41 #include <glib-object.h>
42 #include <string.h>
43 #include <errno.h>
44 #include <stdio.h>
45 #include <sys/types.h>
46 #include <arpa/inet.h>
47 #include <sys/socket.h>
48 #include <netdb.h>
49 #include <netinet/in.h>
50
51 #include "stunagent.h"
52 #include "agent-priv.h"
53 #include "agent.h"
54
55 #define USE_UPNP 0
56 #define LEFT_AGENT GINT_TO_POINTER(1)
57 #define RIGHT_AGENT GINT_TO_POINTER(2)
58
59 static GMutex stun_mutex;
60 static GMutex *stun_mutex_ptr = &stun_mutex;
61 static GCond stun_signal;
62 static GCond *stun_signal_ptr = &stun_signal;
63 static GMutex stun_thread_mutex;
64 static GMutex *stun_thread_mutex_ptr = &stun_thread_mutex;
65 static GCond stun_thread_signal;
66 static GCond *stun_thread_signal_ptr = &stun_thread_signal;
67
68 static NiceComponentState global_lagent_state = NICE_COMPONENT_STATE_LAST;
69 static NiceComponentState global_ragent_state = NICE_COMPONENT_STATE_LAST;
70 static GCancellable *global_cancellable;
71 static gboolean exit_stun_thread = FALSE;
72 static gboolean lagent_candidate_gathering_done = FALSE;
73 static gboolean ragent_candidate_gathering_done = FALSE;
74 static guint global_ls_id, global_rs_id;
75 static gboolean data_received = FALSE;
76 static gboolean drop_stun_packets = FALSE;
77 static gboolean got_stun_packet = FALSE;
78 static gboolean send_stun = FALSE;
79 static guint stun_port;
80
81 static const uint16_t known_attributes[] =  {
82   0
83 };
84
85 /* Waits about 10 seconds for @var to be NULL/FALSE */
86 #define WAIT_UNTIL_UNSET(var, context)                  \
87   if (var)                                              \
88     {                                                   \
89       int _i;                                           \
90                                                         \
91       for (_i = 0; _i < 13 && (var); _i++)              \
92         {                                               \
93           g_usleep (1000 * (1 << _i));                  \
94           g_main_context_iteration (context, FALSE);    \
95         }                                               \
96                                                         \
97       g_assert (!(var));                                \
98     }
99
100 /*
101  * Creates a listening socket
102  */
103 static int listen_socket (unsigned int *port)
104 {
105   union {
106     struct sockaddr_in in;
107     struct sockaddr addr;
108   } addr;
109   int fd = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);
110
111   if (fd == -1) {
112     perror ("Error opening IP port");
113     return -1;
114   }
115
116   memset (&addr, 0, sizeof (addr));
117   addr.in.sin_family = AF_INET;
118   inet_pton(AF_INET, "127.0.0.1", &addr.in.sin_addr);
119   addr.in.sin_port = 0;
120
121   if (bind (fd, &addr.addr, sizeof (struct sockaddr_in))) {
122     perror ("Error opening IP port");
123     goto error;
124   }
125
126   if (port) {
127     socklen_t socklen = sizeof(addr);
128
129     if (getsockname (fd, &addr.addr, &socklen) < 0)
130       g_error ("getsockname failed: %s", strerror (errno));
131
132     g_assert_cmpint (socklen, ==, sizeof(struct sockaddr_in));
133     *port = ntohs (addr.in.sin_port);
134     g_assert (*port != 0);
135   }
136
137   return fd;
138
139 error:
140   close (fd);
141   return -1;
142 }
143
144 static int dgram_process (int sock, StunAgent *oldagent, StunAgent *newagent)
145 {
146   union {
147     struct sockaddr_storage storage;
148     struct sockaddr addr;
149   } addr;
150   socklen_t addr_len;
151   uint8_t buf[STUN_MAX_MESSAGE_SIZE];
152   size_t buf_len = 0;
153   size_t len = 0;
154   StunMessage request;
155   StunMessage response;
156   StunValidationStatus validation;
157   StunAgent *agent = NULL;
158   gint ret;
159
160   addr_len = sizeof (struct sockaddr_in);
161
162 recv_packet:
163   len = recvfrom (sock, buf, sizeof(buf), 0,
164       &addr.addr, &addr_len);
165
166   if (drop_stun_packets) {
167     g_debug ("Dropping STUN packet as requested");
168     return -1;
169   }
170
171   if (len == (size_t)-1) {
172     return -1;
173   }
174
175   validation = stun_agent_validate (newagent, &request, buf, len, NULL, 0);
176
177   if (validation == STUN_VALIDATION_SUCCESS) {
178     agent = newagent;
179   } else {
180     validation = stun_agent_validate (oldagent, &request, buf, len, NULL, 0);
181     agent = oldagent;
182   }
183
184   /* Unknown attributes */
185   if (validation == STUN_VALIDATION_UNKNOWN_REQUEST_ATTRIBUTE) {
186     buf_len = stun_agent_build_unknown_attributes_error (agent, &response, buf,
187         sizeof (buf), &request);
188     goto send_buf;
189   }
190
191   /* Mal-formatted packets */
192   if (validation != STUN_VALIDATION_SUCCESS ||
193       stun_message_get_class (&request) != STUN_REQUEST) {
194     goto recv_packet;
195   }
196
197   switch (stun_message_get_method (&request)) {
198     case STUN_BINDING:
199       stun_agent_init_response (agent, &response, buf, sizeof (buf), &request);
200       if (stun_message_has_cookie (&request))
201         stun_message_append_xor_addr (&response,
202             STUN_ATTRIBUTE_XOR_MAPPED_ADDRESS,
203             &addr.storage, addr_len);
204       else
205          stun_message_append_addr (&response, STUN_ATTRIBUTE_MAPPED_ADDRESS,
206              &addr.addr, addr_len);
207       break;
208
209     case STUN_SHARED_SECRET:
210     case STUN_ALLOCATE:
211     case STUN_SET_ACTIVE_DST:
212     case STUN_CONNECT:
213     case STUN_OLD_SET_ACTIVE_DST:
214     case STUN_IND_DATA:
215     case STUN_IND_CONNECT_STATUS:
216     case STUN_CHANNELBIND:
217     default:
218       if (!stun_agent_init_error (agent, &response, buf, sizeof (buf),
219               &request, STUN_ERROR_BAD_REQUEST)) {
220         g_debug ("STUN error message not initialized properly");
221         g_assert_not_reached();
222       }
223   }
224
225   buf_len = stun_agent_finish_message (agent, &response, NULL, 0);
226
227 send_buf:
228   g_cancellable_cancel (global_cancellable);
229   g_debug ("Ready to send a STUN response");
230   g_assert (g_mutex_trylock (stun_mutex_ptr));
231   got_stun_packet = TRUE;
232   while (send_stun) {
233     g_debug ("Waiting for signal. State is %d", global_lagent_state);
234     g_cond_wait (stun_signal_ptr, stun_mutex_ptr);
235   }
236   g_mutex_unlock (stun_mutex_ptr);
237   len = sendto (sock, buf, buf_len, 0,
238       &addr.addr, addr_len);
239   g_debug ("STUN response sent");
240   drop_stun_packets = TRUE;
241   ret = (len < buf_len) ? -1 : 0;
242   return ret;
243 }
244
245
246 static gpointer stun_thread_func (const gpointer user_data)
247 {
248   StunAgent oldagent;
249   StunAgent newagent;
250   int sock = GPOINTER_TO_INT (user_data);
251   int exit_code = -1;
252
253   g_mutex_lock (stun_thread_mutex_ptr);
254   g_cond_signal (stun_thread_signal_ptr);
255   g_mutex_unlock (stun_thread_mutex_ptr);
256
257   stun_agent_init (&oldagent, known_attributes,
258       STUN_COMPATIBILITY_RFC3489, 0);
259   stun_agent_init (&newagent, known_attributes,
260       STUN_COMPATIBILITY_RFC5389, STUN_AGENT_USAGE_USE_FINGERPRINT);
261
262   while (!exit_stun_thread) {
263     g_debug ("Ready to process next datagram");
264     dgram_process (sock, &oldagent, &newagent);
265   }
266
267   exit_code = close (sock);
268   g_thread_exit (GINT_TO_POINTER (exit_code));
269   return NULL;
270 }
271
272 static void swap_credentials (NiceAgent *lagent, guint lstream,
273     NiceAgent *ragent, guint rstream)
274 {
275   gchar *ufrag = NULL, *password = NULL;
276
277   nice_agent_get_local_credentials (lagent, lstream, &ufrag, &password);
278   nice_agent_set_remote_credentials (ragent, rstream, ufrag, password);
279
280   g_free (ufrag);
281   g_free (password);
282 }
283
284 static void cb_candidate_gathering_done(NiceAgent *agent, guint stream_id, gpointer data)
285 {
286   g_debug ("test-tricklemode:%s: %p", G_STRFUNC, data);
287
288   if (GPOINTER_TO_UINT(data) == 1) {
289     g_debug ("lagent finished gathering candidates");
290     lagent_candidate_gathering_done = TRUE;
291   } else if (GPOINTER_TO_UINT(data) == 2) {
292     g_debug ("ragent finished gathering candidates");
293     ragent_candidate_gathering_done = TRUE;
294   }
295   g_cancellable_cancel (global_cancellable);
296 }
297
298 static void cb_nice_recv (NiceAgent *agent, guint stream_id, guint component_id, guint len, gchar *buf, gpointer user_data)
299 {
300   gint ret;
301
302   g_debug ("test-tricklemode:%s: %p", G_STRFUNC, user_data);
303
304   ret = strncmp ("0000", buf, 4);
305   if (ret == 0) {
306     ret = strncmp ("00001234567812345678", buf, 16);
307     g_assert_cmpint (ret, ==, 0);
308
309     g_debug ("test-tricklemode:%s: ragent recieved %d bytes : quit mainloop",
310              G_STRFUNC, len);
311     data_received = TRUE;
312     g_cancellable_cancel (global_cancellable);
313   }
314 }
315
316 static void cb_component_state_changed (NiceAgent *agent, guint stream_id, guint component_id, guint state, gpointer data)
317 {
318   gint ret;
319
320   g_debug ("test-tricklemode:%s: %p", G_STRFUNC, data);
321
322   if(GPOINTER_TO_UINT(data) == 1) {
323     global_lagent_state = state;
324     g_debug ("lagent state is %d", state);
325   } else if (GPOINTER_TO_UINT(data) == 2) {
326     g_debug ("ragent state is %d", state);
327     global_ragent_state = state;
328   }
329
330   if (GPOINTER_TO_UINT(data) == 1 && state == NICE_COMPONENT_STATE_FAILED) {
331     g_debug ("Signalling STUN response since connchecks failed");
332     g_mutex_lock (stun_mutex_ptr);
333     send_stun = TRUE;
334     g_cond_signal (stun_signal_ptr);
335     g_mutex_unlock (stun_mutex_ptr);
336     g_cancellable_cancel (global_cancellable);
337   }
338
339   if(GPOINTER_TO_UINT(data) == 1 && state == NICE_COMPONENT_STATE_READY) {
340     /* note: test payload send and receive */
341     ret = nice_agent_send (agent, stream_id, component_id,
342                            20, "00001234567812345678");
343     g_debug ("Sent %d bytes", ret);
344     g_assert_cmpint (ret, ==, 20);
345   }
346 }
347
348 static void swap_candidates(NiceAgent *local, guint local_id, NiceAgent *remote, guint remote_id, gboolean signal_stun_reply)
349 {
350   GSList *cands = NULL;
351
352   g_debug ("test-tricklemode:%s", G_STRFUNC);
353   cands = nice_agent_get_local_candidates(local, local_id,
354                                           NICE_COMPONENT_TYPE_RTP);
355   g_assert (nice_agent_set_remote_candidates(remote, remote_id,
356                                              NICE_COMPONENT_TYPE_RTP, cands));
357
358   if (signal_stun_reply) {
359     g_mutex_lock (stun_mutex_ptr);
360     send_stun = TRUE;
361     g_cond_signal (stun_signal_ptr);
362     g_mutex_unlock (stun_mutex_ptr);
363   }
364
365   g_slist_free_full (cands, (GDestroyNotify) nice_candidate_free);
366 }
367
368 static void cb_agent_new_candidate(NiceAgent *agent, guint stream_id, guint component_id, gchar *foundation, gpointer user_data)
369 {
370   NiceAgent *other = g_object_get_data (G_OBJECT (agent), "other-agent");
371   GSList *cands = nice_agent_get_local_candidates (agent, stream_id,
372                                                    component_id);
373   GSList *i = NULL;
374   GSList *remote_cands = NULL;
375   NiceCandidate* temp;
376   gpointer tmp;
377   guint id;
378
379   g_debug ("test-tricklemode:%s: %p", G_STRFUNC, user_data);
380
381   tmp = g_object_get_data (G_OBJECT (other), "id");
382   id = GPOINTER_TO_UINT (tmp);
383
384   for (i = cands; i; i = i->next) {
385     temp = (NiceCandidate*) i->data;
386     if (g_strcmp0(temp->foundation, foundation) == 0) {
387       g_debug ("Adding new local candidate to other agent's connchecks");
388       remote_cands = g_slist_prepend (remote_cands, nice_candidate_copy(temp));
389       g_assert (nice_agent_set_remote_candidates (other, id,
390                                                   NICE_COMPONENT_TYPE_RTP,
391                                                   remote_cands));
392     }
393   }
394
395   g_slist_free_full (remote_cands, (GDestroyNotify) nice_candidate_free);
396   g_slist_free_full (cands, (GDestroyNotify) nice_candidate_free);
397
398 }
399
400 static void add_bad_candidate (NiceAgent *agent, guint stream_id, NiceCandidate *cand)
401 {
402   NiceAddress bad_addr;
403   GSList *cand_list = NULL;
404
405   g_assert (nice_address_set_from_string (&bad_addr, "172.1.0.1"));
406
407   cand = nice_candidate_new (NICE_CANDIDATE_TYPE_HOST);
408   cand->stream_id = stream_id;
409   cand->component_id = NICE_COMPONENT_TYPE_RTP;
410   cand->addr = bad_addr;
411
412   nice_agent_get_local_credentials (agent, stream_id,
413                                     &cand->username, &cand->password);
414   cand_list = g_slist_prepend (cand_list, cand);
415
416   g_debug ("Adding buggy candidate to the agent %p", agent);
417   g_assert (nice_agent_set_remote_candidates (agent, stream_id,
418                                     NICE_COMPONENT_TYPE_RTP,
419                                     cand_list));
420
421   g_slist_free_full (cand_list, (GDestroyNotify) nice_candidate_free);
422
423 }
424
425 static void init_test(NiceAgent *lagent, NiceAgent *ragent, gboolean connect_new_candidate_signal)
426 {
427   global_lagent_state = NICE_COMPONENT_STATE_DISCONNECTED;
428   global_ragent_state = NICE_COMPONENT_STATE_DISCONNECTED;
429
430   lagent_candidate_gathering_done = FALSE;
431   ragent_candidate_gathering_done = FALSE;
432
433   global_ls_id = nice_agent_add_stream (lagent, 1);
434   global_rs_id = nice_agent_add_stream (ragent, 1);
435
436   g_assert_cmpuint (global_ls_id, >, 0);
437   g_assert_cmpuint (global_rs_id, >, 0);
438
439   g_debug ("lagent stream is : %d and ragent stream is %d",
440            global_ls_id,
441            global_rs_id);
442
443   g_object_set_data (G_OBJECT (lagent), "id", GUINT_TO_POINTER (global_ls_id));
444   g_object_set_data (G_OBJECT (ragent), "id", GUINT_TO_POINTER (global_rs_id));
445
446   if (connect_new_candidate_signal) {
447     g_signal_connect (G_OBJECT(lagent), "new-candidate",
448                       G_CALLBACK(cb_agent_new_candidate), LEFT_AGENT);
449     g_signal_connect (G_OBJECT(ragent), "new-candidate",
450                       G_CALLBACK(cb_agent_new_candidate), RIGHT_AGENT);
451   } else {
452     g_signal_handlers_disconnect_by_func (G_OBJECT(lagent), cb_agent_new_candidate,
453                                  LEFT_AGENT);
454     g_signal_handlers_disconnect_by_func (G_OBJECT(ragent), cb_agent_new_candidate,
455                                  RIGHT_AGENT);
456   }
457
458   data_received = FALSE;
459   got_stun_packet = FALSE;
460   send_stun = FALSE;
461
462   nice_agent_attach_recv (lagent, global_ls_id, NICE_COMPONENT_TYPE_RTP,
463                    g_main_context_default (),
464                    cb_nice_recv, LEFT_AGENT);
465   nice_agent_attach_recv (ragent, global_rs_id, NICE_COMPONENT_TYPE_RTP,
466                    g_main_context_default (),
467                    cb_nice_recv, RIGHT_AGENT);
468 }
469
470 static void cleanup(NiceAgent *lagent,  NiceAgent *ragent)
471 {
472   g_debug ("Cleaning up");
473   drop_stun_packets = FALSE;
474   nice_agent_remove_stream (lagent, global_ls_id);
475   nice_agent_remove_stream (ragent, global_rs_id);
476 }
477
478 static void standard_test(NiceAgent *lagent, NiceAgent *ragent)
479 {
480   g_debug ("test-tricklemode:%s", G_STRFUNC);
481
482   got_stun_packet = FALSE;
483   init_test (lagent, ragent, FALSE);
484
485   nice_agent_gather_candidates (lagent, global_ls_id);
486   while (!got_stun_packet)
487     g_main_context_iteration (NULL, TRUE);
488   g_assert (global_lagent_state == NICE_COMPONENT_STATE_GATHERING &&
489             !lagent_candidate_gathering_done);
490
491   nice_agent_gather_candidates (ragent, global_rs_id);
492   while (!ragent_candidate_gathering_done)
493     g_main_context_iteration (NULL, TRUE);
494   g_cancellable_reset (global_cancellable);
495   g_assert (ragent_candidate_gathering_done);
496   g_assert (nice_agent_peer_candidate_gathering_done (lagent, global_ls_id));
497
498
499   g_debug ("Setting local candidates of ragent as remote candidates of lagent");
500   swap_candidates (ragent, global_rs_id, lagent, global_ls_id, TRUE);
501   swap_credentials (ragent, global_rs_id, lagent, global_ls_id);
502
503   while (!data_received)
504     g_main_context_iteration (NULL, TRUE);
505   g_cancellable_reset (global_cancellable);
506   g_assert (global_lagent_state >= NICE_COMPONENT_STATE_CONNECTED &&
507             data_received);
508
509   g_debug ("Setting local candidates of lagent as remote candidates of ragent");
510   swap_candidates (lagent, global_ls_id, ragent, global_rs_id, FALSE);
511   swap_credentials (lagent, global_ls_id, ragent, global_rs_id);
512
513   while (!lagent_candidate_gathering_done)
514     g_main_context_iteration (NULL, TRUE);
515   g_cancellable_reset (global_cancellable);
516
517   g_assert (lagent_candidate_gathering_done);
518   g_assert (nice_agent_peer_candidate_gathering_done (ragent, global_rs_id));
519
520   while (global_ragent_state < NICE_COMPONENT_STATE_CONNECTED)
521     g_main_context_iteration (NULL, TRUE);
522   g_cancellable_reset (global_cancellable);
523
524   g_assert_cmpint (global_lagent_state, ==, NICE_COMPONENT_STATE_READY);
525   g_assert_cmpint (global_ragent_state, >=, NICE_COMPONENT_STATE_CONNECTED);
526
527   cleanup (lagent, ragent);
528 }
529
530 static void bad_credentials_test(NiceAgent *lagent, NiceAgent *ragent)
531 {
532   g_debug ("test-tricklemode:%s", G_STRFUNC);
533
534   init_test (lagent, ragent, FALSE);
535
536   nice_agent_set_remote_credentials (lagent, global_ls_id,
537                                      "wrong", "wrong");
538   nice_agent_set_remote_credentials (ragent, global_rs_id,
539                                      "wrong2", "wrong2");
540
541   nice_agent_gather_candidates (lagent, global_ls_id);
542   while (!got_stun_packet)
543     g_main_context_iteration (NULL, TRUE);
544   g_cancellable_reset (global_cancellable);
545   g_assert (global_lagent_state == NICE_COMPONENT_STATE_GATHERING &&
546             !lagent_candidate_gathering_done);
547
548   nice_agent_gather_candidates (ragent, global_rs_id);
549   while (!ragent_candidate_gathering_done)
550     g_main_context_iteration (NULL, TRUE);
551   g_cancellable_reset (global_cancellable);
552   g_assert (ragent_candidate_gathering_done);
553   g_assert (nice_agent_peer_candidate_gathering_done (lagent, global_ls_id));
554
555   g_debug ("Setting local candidates of ragent as remote candidates of lagent");
556   swap_candidates (ragent, global_rs_id, lagent, global_ls_id, FALSE);
557
558   while (global_lagent_state != NICE_COMPONENT_STATE_FAILED)
559     g_main_context_iteration (NULL, TRUE);
560   g_cancellable_reset (global_cancellable);
561
562   // Set the correct credentials and swap candidates
563   g_debug ("Setting local candidates of ragent as remote candidates of lagent");
564   swap_candidates (ragent, global_rs_id, lagent, global_ls_id, FALSE);
565   swap_credentials (lagent, global_ls_id, ragent, global_rs_id);
566
567   g_debug ("Setting local candidates of lagent as remote candidates of ragent");
568   swap_candidates (lagent, global_ls_id, ragent, global_rs_id, FALSE);
569   swap_credentials (ragent, global_rs_id, lagent, global_ls_id);
570
571   while (!data_received)
572     g_main_context_iteration (NULL, TRUE);
573   g_cancellable_reset (global_cancellable);
574
575   g_assert (data_received);
576   g_assert_cmpint (global_lagent_state, ==, NICE_COMPONENT_STATE_READY);
577   g_assert_cmpint (global_ragent_state, >=, NICE_COMPONENT_STATE_CONNECTED);
578
579   // Wait for lagent to finish gathering candidates
580   while (!lagent_candidate_gathering_done)
581     g_main_context_iteration (NULL, TRUE);
582   g_cancellable_reset (global_cancellable);
583
584   g_assert (lagent_candidate_gathering_done);
585   g_assert (nice_agent_peer_candidate_gathering_done (ragent, global_rs_id));
586
587   cleanup (lagent, ragent);
588 }
589
590 static void bad_candidate_test(NiceAgent *lagent,NiceAgent *ragent)
591 {
592   NiceCandidate *cand =  NULL;
593
594   g_debug ("test-tricklemode:%s", G_STRFUNC);
595
596   init_test (lagent, ragent, FALSE);
597
598   nice_agent_gather_candidates (lagent, global_ls_id);
599   while (!got_stun_packet)
600     g_main_context_iteration (NULL, TRUE);
601   g_cancellable_reset (global_cancellable);
602   g_assert (global_lagent_state == NICE_COMPONENT_STATE_GATHERING &&
603             !lagent_candidate_gathering_done);
604
605   nice_agent_gather_candidates (ragent, global_rs_id);
606   while (!ragent_candidate_gathering_done)
607       g_main_context_iteration (NULL, TRUE);
608   g_cancellable_reset (global_cancellable);
609
610   g_assert (ragent_candidate_gathering_done);
611   g_assert (nice_agent_peer_candidate_gathering_done (lagent, global_ls_id));
612
613   add_bad_candidate (lagent, global_ls_id, cand);
614
615   // lagent will finish candidate gathering causing this mainloop to quit
616   while (!lagent_candidate_gathering_done)
617     g_main_context_iteration (NULL, TRUE);
618   g_cancellable_reset (global_cancellable);
619
620   g_assert (nice_agent_peer_candidate_gathering_done (ragent, global_rs_id));
621
622   // connchecks will fail causing this mainloop to quit
623   while (global_lagent_state != NICE_COMPONENT_STATE_FAILED)
624     g_main_context_iteration (NULL, TRUE);
625   g_cancellable_reset (global_cancellable);
626
627   g_assert (global_lagent_state == NICE_COMPONENT_STATE_FAILED &&
628             !data_received);
629
630   g_debug ("Setting local candidates of ragent as remote candidates of lagent");
631   swap_candidates (ragent, global_rs_id, lagent, global_ls_id, FALSE);
632   swap_credentials (ragent, global_rs_id, lagent, global_ls_id);
633
634   g_debug ("Setting local candidates of lagent as remote candidates of ragent");
635   swap_candidates (lagent, global_ls_id, ragent, global_rs_id, FALSE);
636   swap_credentials (lagent, global_ls_id, ragent, global_rs_id);
637
638   while (!data_received)
639     g_main_context_iteration (NULL, TRUE);
640   g_cancellable_reset (global_cancellable);
641
642   g_assert (lagent_candidate_gathering_done);
643
644   g_assert_cmpint (global_lagent_state, >=, NICE_COMPONENT_STATE_CONNECTED);
645   g_assert_cmpint (global_ragent_state, >=, NICE_COMPONENT_STATE_CONNECTING);
646
647   cleanup (lagent, ragent);
648 }
649
650 static void new_candidate_test(NiceAgent *lagent, NiceAgent *ragent)
651 {
652   g_debug ("test-tricklemode:%s", G_STRFUNC);
653
654   init_test (lagent, ragent, TRUE);
655   swap_credentials (lagent, global_ls_id, ragent, global_rs_id);
656   swap_credentials (ragent, global_rs_id, lagent, global_ls_id);
657
658   nice_agent_gather_candidates (lagent, global_ls_id);
659   while (!got_stun_packet)
660     g_main_context_iteration (NULL, TRUE);
661   g_cancellable_reset (global_cancellable);
662   g_assert (global_lagent_state == NICE_COMPONENT_STATE_GATHERING &&
663             !lagent_candidate_gathering_done);
664
665   nice_agent_gather_candidates (ragent, global_rs_id);
666   while (!ragent_candidate_gathering_done)
667     g_main_context_iteration (NULL, TRUE);
668   g_cancellable_reset (global_cancellable);
669   g_assert (nice_agent_peer_candidate_gathering_done (lagent, global_ls_id));
670
671   // Wait for data
672   while (!data_received)
673       g_main_context_iteration (NULL, TRUE);
674   g_cancellable_reset (global_cancellable);
675   g_assert (data_received);
676
677   // Data arrived, signal STUN thread to send STUN response
678   g_mutex_lock (stun_mutex_ptr);
679   send_stun = TRUE;
680   g_cond_signal (stun_signal_ptr);
681   g_mutex_unlock (stun_mutex_ptr);
682
683   // Wait for lagent to finish gathering candidates
684   while (!lagent_candidate_gathering_done)
685     g_main_context_iteration (NULL, TRUE);
686   g_cancellable_reset (global_cancellable);
687   g_assert (nice_agent_peer_candidate_gathering_done (ragent, global_rs_id));
688
689   g_assert (lagent_candidate_gathering_done);
690   g_assert (ragent_candidate_gathering_done);
691
692   g_assert_cmpint (global_lagent_state, ==, NICE_COMPONENT_STATE_READY);
693   g_assert_cmpint (global_ragent_state, >=, NICE_COMPONENT_STATE_CONNECTED);
694
695   cleanup (lagent, ragent);
696 }
697
698 static void send_dummy_data(void)
699 {
700   int sockfd = listen_socket (NULL);
701   union {
702     struct sockaddr_in in;
703     struct sockaddr addr;
704   } addr;
705
706   memset (&addr, 0, sizeof (addr));
707   addr.in.sin_family = AF_INET;
708   inet_pton(AF_INET, "127.0.0.1", &addr.in.sin_addr);
709   addr.in.sin_port = htons (stun_port);
710
711   g_debug ("Sending dummy data to close STUN thread");
712   sendto (sockfd, "close socket", 12, 0,
713           &addr.addr, sizeof (addr));
714 }
715
716 int main(void)
717 {
718   NiceAgent *lagent = NULL, *ragent = NULL;
719   GThread *stun_thread = NULL;
720   NiceAddress baseaddr;
721   GSource *src;
722   int sock;
723
724   global_cancellable = g_cancellable_new ();
725   src = g_cancellable_source_new (global_cancellable);
726   g_source_set_dummy_callback (src);
727   g_source_attach (src, NULL);
728
729   sock = listen_socket (&stun_port);
730
731   if (sock == -1) {
732     g_assert_not_reached ();
733   }
734
735
736   stun_thread = g_thread_new ("listen for STUN requests",
737       stun_thread_func, GINT_TO_POINTER (sock));
738
739   // Once the the thread is forked, we want to listen for a signal 
740   // that the socket was opened successfully
741   g_mutex_lock (stun_thread_mutex_ptr);
742   g_cond_wait (stun_thread_signal_ptr, stun_thread_mutex_ptr); 
743
744   lagent = nice_agent_new (NULL, NICE_COMPATIBILITY_RFC5245);
745   ragent = nice_agent_new (NULL, NICE_COMPATIBILITY_RFC5245);
746
747   g_object_set (G_OBJECT (lagent), "ice-tcp", FALSE,  NULL);
748   g_object_set (G_OBJECT (ragent), "ice-tcp", FALSE,  NULL);
749
750   g_object_set (G_OBJECT (lagent), "ice-trickle", TRUE, NULL);
751   g_object_set (G_OBJECT (ragent), "ice-trickle", TRUE, NULL);
752
753   g_object_set (G_OBJECT (lagent), "controlling-mode", TRUE, NULL);
754   g_object_set (G_OBJECT (ragent), "controlling-mode", FALSE, NULL);
755
756   g_object_set (G_OBJECT (lagent), "upnp", USE_UPNP, NULL);
757   g_object_set (G_OBJECT (ragent), "upnp", USE_UPNP, NULL);
758
759   g_object_set (G_OBJECT (lagent), "stun-server", "127.0.0.1", NULL);
760   g_object_set (G_OBJECT (lagent), "stun-server-port", stun_port, NULL);
761
762   g_object_set_data (G_OBJECT (lagent), "other-agent", ragent);
763   g_object_set_data (G_OBJECT (ragent), "other-agent", lagent);
764
765   g_assert (nice_address_set_from_string (&baseaddr, "127.0.0.1"));
766   nice_agent_add_local_address (lagent, &baseaddr);
767   nice_agent_add_local_address (ragent, &baseaddr);
768
769   g_signal_connect(G_OBJECT(lagent), "candidate-gathering-done",
770                    G_CALLBACK(cb_candidate_gathering_done), LEFT_AGENT);
771   g_signal_connect(G_OBJECT(ragent), "candidate-gathering-done",
772                    G_CALLBACK(cb_candidate_gathering_done), RIGHT_AGENT);
773   g_signal_connect(G_OBJECT(lagent), "component-state-changed",
774                    G_CALLBACK(cb_component_state_changed), LEFT_AGENT);
775   g_signal_connect(G_OBJECT(ragent), "component-state-changed",
776                    G_CALLBACK(cb_component_state_changed), RIGHT_AGENT);
777
778   standard_test (lagent, ragent);
779   bad_credentials_test (lagent, ragent);
780   bad_candidate_test (lagent, ragent);
781   new_candidate_test (lagent, ragent);
782
783   // Do this to make sure the STUN thread exits
784   exit_stun_thread = TRUE;
785   drop_stun_packets = TRUE;
786   send_stun = FALSE;
787   send_dummy_data ();
788   g_cond_signal (stun_signal_ptr);
789
790   g_object_add_weak_pointer (G_OBJECT (lagent), (gpointer *) &lagent);
791   g_object_add_weak_pointer (G_OBJECT (ragent), (gpointer *) &ragent);
792
793   g_object_unref (lagent);
794   g_object_unref (ragent);
795
796   g_thread_join (stun_thread);
797   g_object_unref (global_cancellable);
798
799   g_source_destroy (src);
800   g_source_unref (src);
801
802   WAIT_UNTIL_UNSET (lagent, NULL);
803   WAIT_UNTIL_UNSET (ragent, NULL);
804
805   return 0;
806 }