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, ¤t_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