1 /* $Id$ */
2 /*
3  * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
4  * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20 #include "test.h"
21 #include <pjlib.h>
22 #include <pj/compat/socket.h>
23 
app_perror_dbg(const char * msg,pj_status_t rc,const char * file,int line)24 void app_perror_dbg(const char *msg, pj_status_t rc,
25 		    const char *file, int line)
26 {
27     char errbuf[256];
28 
29     PJ_CHECK_STACK();
30 
31     pj_strerror(rc, errbuf, sizeof(errbuf));
32     PJ_LOG(1,("test", "%s:%d: %s: [pj_status_t=%d] %s", file, line, msg,
33 	      rc, errbuf));
34 }
35 
36 /* Set socket to nonblocking. */
app_set_sock_nb(pj_sock_t sock)37 void app_set_sock_nb(pj_sock_t sock)
38 {
39 #if defined(PJ_WIN32) && PJ_WIN32!=0 || \
40     defined(PJ_WIN64) && PJ_WIN64 != 0 || \
41     defined(PJ_WIN32_WINCE) && PJ_WIN32_WINCE!=0
42     u_long value = 1;
43     ioctlsocket(sock, FIONBIO, &value);
44 #else
45     pj_uint32_t value = 1;
46     ioctl(sock, FIONBIO, &value);
47 #endif
48 }
49 
create_stun_config(pj_pool_t * pool,pj_stun_config * stun_cfg)50 pj_status_t create_stun_config(pj_pool_t *pool, pj_stun_config *stun_cfg)
51 {
52     pj_ioqueue_t *ioqueue;
53     pj_timer_heap_t *timer_heap;
54     pj_lock_t *lock;
55     pj_status_t status;
56 
57     status = pj_ioqueue_create(pool, 64, &ioqueue);
58     if (status != PJ_SUCCESS) {
59 	app_perror("   pj_ioqueue_create()", status);
60 	return status;
61     }
62 
63     status = pj_timer_heap_create(pool, 256, &timer_heap);
64     if (status != PJ_SUCCESS) {
65 	app_perror("   pj_timer_heap_create()", status);
66 	pj_ioqueue_destroy(ioqueue);
67 	return status;
68     }
69 
70     pj_lock_create_recursive_mutex(pool, NULL, &lock);
71     pj_timer_heap_set_lock(timer_heap, lock, PJ_TRUE);
72 
73     pj_stun_config_init(stun_cfg, mem, 0, ioqueue, timer_heap);
74 
75     return PJ_SUCCESS;
76 }
77 
destroy_stun_config(pj_stun_config * stun_cfg)78 void destroy_stun_config(pj_stun_config *stun_cfg)
79 {
80     if (stun_cfg->timer_heap) {
81 	pj_timer_heap_destroy(stun_cfg->timer_heap);
82 	stun_cfg->timer_heap = NULL;
83     }
84     if (stun_cfg->ioqueue) {
85 	pj_ioqueue_destroy(stun_cfg->ioqueue);
86 	stun_cfg->ioqueue = NULL;
87     }
88 }
89 
poll_events(pj_stun_config * stun_cfg,unsigned msec,pj_bool_t first_event_only)90 void poll_events(pj_stun_config *stun_cfg, unsigned msec,
91 		 pj_bool_t first_event_only)
92 {
93     pj_time_val stop_time;
94     int count = 0;
95 
96     pj_gettimeofday(&stop_time);
97     stop_time.msec += msec;
98     pj_time_val_normalize(&stop_time);
99 
100     /* Process all events for the specified duration. */
101     for (;;) {
102 	pj_time_val timeout = {0, 1}, now;
103 	int c;
104 
105 	c = pj_timer_heap_poll( stun_cfg->timer_heap, NULL );
106 	if (c > 0)
107 	    count += c;
108 
109 	//timeout.sec = timeout.msec = 0;
110 	c = pj_ioqueue_poll( stun_cfg->ioqueue, &timeout);
111 	if (c > 0)
112 	    count += c;
113 
114 	pj_gettimeofday(&now);
115 	if (PJ_TIME_VAL_GTE(now, stop_time))
116 	    break;
117 
118 	if (first_event_only && count >= 0)
119 	    break;
120     }
121 }
122 
capture_pjlib_state(pj_stun_config * cfg,struct pjlib_state * st)123 void capture_pjlib_state(pj_stun_config *cfg, struct pjlib_state *st)
124 {
125     pj_caching_pool *cp;
126 
127     st->timer_cnt = (unsigned)pj_timer_heap_count(cfg->timer_heap);
128 
129     cp = (pj_caching_pool*)cfg->pf;
130     st->pool_used_cnt = (unsigned)cp->used_count;
131 }
132 
check_pjlib_state(pj_stun_config * cfg,const struct pjlib_state * initial_st)133 int check_pjlib_state(pj_stun_config *cfg,
134 		      const struct pjlib_state *initial_st)
135 {
136     struct pjlib_state current_state;
137     int rc = 0;
138 
139     capture_pjlib_state(cfg, &current_state);
140 
141     if (current_state.timer_cnt > initial_st->timer_cnt) {
142 	PJ_LOG(3,("", "    error: possibly leaking timer"));
143 	rc |= ERR_TIMER_LEAK;
144 
145 #if PJ_TIMER_DEBUG
146 	pj_timer_heap_dump(cfg->timer_heap);
147 #endif
148     }
149 
150     if (current_state.pool_used_cnt > initial_st->pool_used_cnt) {
151 	PJ_LOG(3,("", "    error: possibly leaking memory"));
152 	PJ_LOG(3,("", "    dumping memory pool:"));
153 	pj_pool_factory_dump(mem, PJ_TRUE);
154 	rc |= ERR_MEMORY_LEAK;
155     }
156 
157     return rc;
158 }
159 
160 
161 #define DO_TEST(test)	do { \
162 			    PJ_LOG(3, ("test", "Running %s...", #test));  \
163 			    rc = test; \
164 			    PJ_LOG(3, ("test",  \
165 				       "%s(%d)",  \
166 				       (char*)(rc ? "..ERROR" : "..success"), rc)); \
167 			    if (rc!=0) goto on_return; \
168 			} while (0)
169 
170 
171 pj_pool_factory *mem;
172 
173 int param_log_decor = PJ_LOG_HAS_NEWLINE | PJ_LOG_HAS_TIME | PJ_LOG_HAS_SENDER |
174 		      PJ_LOG_HAS_MICRO_SEC;
175 
176 pj_log_func *orig_log_func;
177 FILE *log_file;
178 
test_log_func(int level,const char * data,int len)179 static void test_log_func(int level, const char *data, int len)
180 {
181     if (log_file) {
182 	fwrite(data, len, 1, log_file);
183     }
184     if (level <= 3)
185 	orig_log_func(level, data, len);
186 }
187 
test_inner(void)188 static int test_inner(void)
189 {
190     pj_caching_pool caching_pool;
191     int rc = 0;
192 
193     mem = &caching_pool.factory;
194 
195 #if 1
196     pj_log_set_level(3);
197     pj_log_set_decor(param_log_decor);
198     PJ_UNUSED_ARG(test_log_func);
199 #elif 1
200     log_file = fopen("pjnath-test.log", "wt");
201     pj_log_set_level(5);
202     orig_log_func = pj_log_get_log_func();
203     pj_log_set_log_func(&test_log_func);
204 #endif
205 
206     rc = pj_init();
207     if (rc != 0) {
208 	app_perror("pj_init() error!!", rc);
209 	return rc;
210     }
211 
212     pj_dump_config();
213     pj_caching_pool_init( &caching_pool, &pj_pool_factory_default_policy, 0 );
214 
215     pjlib_util_init();
216     pjnath_init();
217 
218 #if INCLUDE_STUN_TEST
219     DO_TEST(stun_test());
220     DO_TEST(sess_auth_test());
221 #endif
222 
223 #if INCLUDE_ICE_TEST
224     DO_TEST(ice_test());
225 #endif
226 
227 #if INCLUDE_TRICKLE_ICE_TEST
228     DO_TEST(trickle_ice_test());
229 #endif
230 
231 #if INCLUDE_STUN_SOCK_TEST
232     DO_TEST(stun_sock_test());
233 #endif
234 
235 #if INCLUDE_TURN_SOCK_TEST
236     DO_TEST(turn_sock_test());
237 #endif
238 
239 #if INCLUDE_CONCUR_TEST
240     DO_TEST(concur_test());
241 #endif
242 
243 on_return:
244     if (log_file)
245 	fclose(log_file);
246     return rc;
247 }
248 
test_main(void)249 int test_main(void)
250 {
251     PJ_USE_EXCEPTION;
252 
253     PJ_TRY {
254         return test_inner();
255     }
256     PJ_CATCH_ANY {
257         int id = PJ_GET_EXCEPTION();
258         PJ_LOG(3,("test", "FATAL: unhandled exception id %d (%s)",
259                   id, pj_exception_id_name(id)));
260     }
261     PJ_END;
262 
263     return -1;
264 }
265 
266