blob: a6c194140eed720ac110c5a99008e91bc3e71656 [file] [log] [blame]
Benny Prijonofb9d9872007-03-21 22:05:58 +00001/* $Id$ */
2/*
3 * Copyright (C) 2003-2007 Benny Prijono <benny@prijono.org>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19#include "test.h"
20
21#define THIS_FILE "ice.c"
22
23
24struct ice_data
25{
26 pj_bool_t complete;
27 pj_status_t err_code;
28 unsigned rx_rtp_cnt;
29 unsigned rx_rtcp_cnt;
30};
31
32static pj_stun_config stun_cfg;
33
34static void on_ice_complete(pj_icemt *icemt,
35 pj_status_t status)
36{
37 struct ice_data *id = (struct ice_data*) icemt->user_data;
38 id->complete = PJ_TRUE;
39 id->err_code = status;
40}
41
42
43static void on_rx_rtp(pj_icemt *icemt,
44 void *pkt, pj_size_t size,
45 const pj_sockaddr_t *src_addr,
46 unsigned src_addr_len)
47{
48 struct ice_data *id = (struct ice_data*) icemt->user_data;
49 id->rx_rtp_cnt++;
50}
51
52
53static void on_rx_rtcp(pj_icemt *icemt,
54 void *pkt, pj_size_t size,
55 const pj_sockaddr_t *src_addr,
56 unsigned src_addr_len)
57{
58 struct ice_data *id = (struct ice_data*) icemt->user_data;
59 id->rx_rtcp_cnt++;
60}
61
62
63static void handle_events(unsigned msec_timeout)
64{
65 pj_time_val delay;
66
67 pj_timer_heap_poll(stun_cfg.timer_heap, NULL);
68
69 delay.sec = 0;
70 delay.msec = msec_timeout;
71 pj_time_val_normalize(&delay);
72
73 pj_ioqueue_poll(stun_cfg.ioqueue, &delay);
74}
75
76
77/* Basic create and destroy test */
78static int ice_basic_create_destroy_test()
79{
80 pj_icemt *im;
81 pj_ice *ice;
82 pj_icemt_cb icemt_cb;
83 pj_status_t status;
84
85 PJ_LOG(3,(THIS_FILE, "...basic create/destroy"));
86
87 pj_bzero(&icemt_cb, sizeof(icemt_cb));
88 icemt_cb.on_ice_complete = &on_ice_complete;
89 icemt_cb.on_rx_rtcp = &on_rx_rtp;
90 icemt_cb.on_rx_rtcp = &on_rx_rtcp;
91
92 status = pj_icemt_create(&stun_cfg, NULL, PJ_ICE_ROLE_CONTROLLING,
93 &icemt_cb, 0, PJ_FALSE, PJ_FALSE, NULL, &im);
94 if (status != PJ_SUCCESS)
95 return -10;
96
97 ice = im->ice;
98
99 pj_icemt_destroy(im);
100
101 return 0;
102}
103
104
105static pj_status_t set_remote_list(pj_icemt *src, pj_icemt *dst)
106{
107 unsigned i, count;
108 unsigned cand_id[PJ_ICE_MAX_CAND];
109 pj_ice_cand cand[PJ_ICE_MAX_CAND];
110 pj_status_t status;
111
112 count = PJ_ARRAY_SIZE(cand_id);
113 status = pj_ice_enum_cands(src->ice, &count, cand_id);
114 if (status != PJ_SUCCESS)
115 return status;
116
117 for (i=0; i<count; ++i) {
118 pj_ice_cand *p_cand;
119 status = pj_ice_get_cand(src->ice, cand_id[i], &p_cand);
120 if (status != PJ_SUCCESS)
121 return status;
122
123 pj_memcpy(&cand[i], p_cand, sizeof(pj_ice_cand));
124 }
125
126 status = pj_ice_create_check_list(dst->ice, count, cand);
127 return status;
128}
129
130
131/* Direct agent to agent communication */
132static int ice_direct_test()
133{
134 pj_icemt *im1, *im2;
135 pj_icemt_cb icemt_cb;
136 struct ice_data *id1, *id2;
137 pj_status_t status;
138
139 PJ_LOG(3,(THIS_FILE, "...direct communication"));
140
141 pj_bzero(&icemt_cb, sizeof(icemt_cb));
142 icemt_cb.on_ice_complete = &on_ice_complete;
143 icemt_cb.on_rx_rtcp = &on_rx_rtp;
144 icemt_cb.on_rx_rtcp = &on_rx_rtcp;
145
146 /* Create first ICE */
147 status = pj_icemt_create(&stun_cfg, NULL, PJ_ICE_ROLE_CONTROLLING,
148 &icemt_cb, 0, PJ_FALSE, PJ_FALSE, NULL, &im1);
149 if (status != PJ_SUCCESS)
150 return -20;
151
152 id1 = PJ_POOL_ZALLOC_T(im1->pool, struct ice_data);
153 im1->user_data = id1;
154
155 /* Create second ICE */
156 status = pj_icemt_create(&stun_cfg, NULL, PJ_ICE_ROLE_CONTROLLED,
157 &icemt_cb, 0, PJ_FALSE, PJ_FALSE, NULL, &im2);
158 if (status != PJ_SUCCESS)
159 return -25;
160
161 id2 = PJ_POOL_ZALLOC_T(im2->pool, struct ice_data);
162 im2->user_data = id2;
163
164 {
165 pj_str_t u1 = pj_str("uname1");
166 pj_str_t p1 = pj_str("pass1");
167 pj_str_t u2 = pj_str("uname2");
168 pj_str_t p2 = pj_str("pass2");
169
170 pj_ice_set_credentials(im1->ice, &u1, &p1, &u2, &p2);
171 pj_ice_set_credentials(im2->ice, &u2, &p2, &u1, &p1);
172 }
173
174 /* Send offer to im2 */
175 status = set_remote_list(im1, im2);
176 if (status != PJ_SUCCESS)
177 return -30;
178
179 /* Send answer to im1 */
180 status = set_remote_list(im2, im1);
181 if (status != PJ_SUCCESS)
182 return -35;
183
184 /* Both can start now */
185 status = pj_ice_start_check(im1->ice);
186 if (status != PJ_SUCCESS)
187 return -40;
188
189#if 0
190 status = pj_ice_start_check(im2->ice);
191 if (status != PJ_SUCCESS)
192 return -40;
193#endif
194
195 /* Just wait until both completes, or timed out */
196 while (!id1->complete || !id2->complete)
197 handle_events(1);
198
199 return 0;
200
201}
202
203
204int ice_test(void)
205{
206 int rc = 0;
207 pj_pool_t *pool;
208 pj_ioqueue_t *ioqueue;
209 pj_timer_heap_t *timer_heap;
210
211 pool = pj_pool_create(mem, NULL, 4000, 4000, NULL);
212 pj_ioqueue_create(pool, 12, &ioqueue);
213 pj_timer_heap_create(pool, 100, &timer_heap);
214
215 pj_stun_config_init(&stun_cfg, mem, 0, ioqueue, timer_heap);
216
217 pj_log_set_level(5);
218
219 rc = ice_basic_create_destroy_test();
220 if (rc != 0)
221 goto on_return;
222
223 rc = ice_direct_test();
224 if (rc != 0)
225 goto on_return;
226
227on_return:
228 pj_log_set_level(3);
229 pj_ioqueue_destroy(stun_cfg.ioqueue);
230 pj_pool_release(pool);
231 return rc;
232}
233