1 /*
2  * This file is part of the Sofia-SIP package
3  *
4  * Copyright (C) 2005 Nokia Corporation.
5  *
6  * Contact: Pekka Pessi <pekka.pessi@nokia.com>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public License
10  * as published by the Free Software Foundation; either version 2.1 of
11  * the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21  * 02110-1301 USA
22  *
23  */
24 
25 /**@CFILE test_nua.c
26  * @brief High-level tester for Sofia SIP User Agent Engine
27  *
28  * @author Pekka Pessi <Pekka.Pessi@nokia.com>
29  * @author Martti Mela <Martti Mela@nokia.com>
30  *
31  * @date Created: Wed Aug 17 12:12:12 EEST 2005 ppessi
32  */
33 
34 #include "config.h"
35 
36 #include "test_nua.h"
37 
38 #if HAVE_ALARM
39 #include <signal.h>
40 #endif
41 
42 #if defined(_WIN32)
43 #include <fcntl.h>
44 #endif
45 
46 SOFIAPUBVAR su_log_t nua_log[];
47 SOFIAPUBVAR su_log_t soa_log[];
48 SOFIAPUBVAR su_log_t nea_log[];
49 SOFIAPUBVAR su_log_t nta_log[];
50 SOFIAPUBVAR su_log_t tport_log[];
51 SOFIAPUBVAR su_log_t su_log_default[];
52 
53 char const name[] = "test_nua";
54 int print_headings = 1;
55 int tstflags = 0;
56 
57 #if HAVE_FUNC
58 #elif HAVE_FUNCTION
59 #define __func__ __FUNCTION__
60 #else
61 #define __func__ name
62 #endif
63 
64 #if HAVE_ALARM
sig_alarm(int s)65 static RETSIGTYPE sig_alarm(int s)
66 {
67   fprintf(stderr, "%s: FAIL! test timeout!\n", name);
68   if (tstflags & tst_abort)
69     abort();
70   exit(1);
71 }
72 #endif
73 
74 static char const options_usage[] =
75   "   -v | --verbose    be verbose\n"
76   "   -q | --quiet      be quiet\n"
77   "   -a | --abort      abort on error\n"
78   "   -s                use only single thread\n"
79   "   -l level          set logging level (0 by default)\n"
80   "   -e | --events     print nua events\n"
81   "   -A                print nua events for A\n"
82   "   -B                print nua events for B\n"
83   "   -C                print nua events for C\n"
84   "   --log=a           log messages for A\n"
85   "   --log=b           log messages for B\n"
86   "   --log=c           log messages for C\n"
87   "   --log=proxy       log messages for proxy\n"
88   "   --attach          print pid, wait for a debugger to be attached\n"
89   "   --no-proxy        do not use internal proxy\n"
90   "   --no-nat          do not use internal \"nat\"\n"
91   "   --symmetric       run internal \"nat\" in symmetric mode\n"
92   "   -N                print events from internal \"nat\"\n"
93   "   --loop            loop main tests for ever\n"
94   "   --no-alarm        don't ask for guard ALARM\n"
95   "   -p uri            specify uri of outbound proxy (implies --no-proxy)\n"
96   "   --proxy-tests     run tests involving proxy, too\n"
97 #if SU_HAVE_OSX_CF_API /* If compiled with CoreFoundation events */
98   "   --osx-runloop     use OSX CoreFoundation runloop instead of poll() loop\n"
99 #endif
100   "   -k                do not exit after first error\n"
101   ;
102 
usage(int exitcode)103 static void usage(int exitcode)
104 {
105   fprintf(stderr, "usage: %s OPTIONS\n   where OPTIONS are\n%s",
106 	    name, options_usage);
107   exit(exitcode);
108 }
109 
main(int argc,char * argv[])110 int main(int argc, char *argv[])
111 {
112   int retval = 0;
113   int i, o_quiet = 0, o_attach = 0, o_alarm = 1, o_loop = 0;
114   int o_events_init = 0, o_events_a = 0, o_events_b = 0, o_events_c = 0;
115   int o_iproxy = 1, o_inat = 1;
116   int o_inat_symmetric = 0, o_inat_logging = 0, o_expensive = 0;
117   url_t const *o_proxy = NULL;
118   int level = 0;
119 
120   struct context ctx[1] = {{{ SU_HOME_INIT(ctx) }}};
121 
122 #if HAVE_OPEN_C
123   dup2(1, 2);
124 #endif
125 
126   if (getenv("EXPENSIVE_CHECKS"))
127     o_expensive = 1;
128 
129   ctx->threading = 1;
130   ctx->quit_on_single_failure = 1;
131 
132   endpoint_init(ctx, &ctx->a, 'a');
133   endpoint_init(ctx, &ctx->b, 'b');
134   endpoint_init(ctx, &ctx->c, 'c');
135 
136   for (i = 1; argv[i]; i++) {
137     if (strcmp(argv[i], "-v") == 0 || strcmp(argv[i], "--verbose") == 0)
138       tstflags |= tst_verbatim;
139     else if (strcmp(argv[i], "-a") == 0 || strcmp(argv[i], "--abort") == 0)
140       tstflags |= tst_abort;
141     else if (strcmp(argv[i], "-q") == 0 || strcmp(argv[i], "--quiet") == 0)
142       tstflags &= ~tst_verbatim, o_quiet = 1;
143     else if (strcmp(argv[i], "-k") == 0)
144       ctx->quit_on_single_failure = 0;
145     else if (strncmp(argv[i], "-l", 2) == 0) {
146       char *rest = NULL;
147 
148       if (argv[i][2])
149 	level = strtol(argv[i] + 2, &rest, 10);
150       else if (argv[i + 1])
151 	level = strtol(argv[i + 1], &rest, 10), i++;
152       else
153 	level = 3, rest = "";
154 
155       if (rest == NULL || *rest)
156 	usage(1);
157 
158       su_log_set_level(nua_log, level);
159       su_log_soft_set_level(soa_log, level);
160       su_log_soft_set_level(nea_log, level);
161       su_log_soft_set_level(nta_log, level);
162       su_log_soft_set_level(tport_log, level);
163     }
164     else if (strcmp(argv[i], "-e") == 0 || strcmp(argv[i], "--events") == 0) {
165       o_events_init = o_events_a = o_events_b = o_events_c = 1;
166     }
167     else if (strcmp(argv[i], "-I") == 0) {
168       o_events_init = 1;
169     }
170     else if (strcmp(argv[i], "-A") == 0) {
171       o_events_a = 1;
172     }
173     else if (strcmp(argv[i], "-B") == 0) {
174       o_events_b = 1;
175     }
176     else if (strcmp(argv[i], "-C") == 0) {
177       o_events_c = 1;
178     }
179     else if (strcmp(argv[i], "-s") == 0) {
180       ctx->threading = 0;
181     }
182     else if (strcmp(argv[i], "--attach") == 0) {
183       o_attach = 1;
184     }
185     else if (strncmp(argv[i], "-p", 2) == 0) {
186       if (argv[i][2])
187 	o_proxy = URL_STRING_MAKE(argv[i] + 2)->us_url;
188       else if (!argv[++i] || argv[i][0] == '-')
189 	usage(1);
190       else
191 	o_proxy = URL_STRING_MAKE(argv[i])->us_url;
192     }
193     else if (strcmp(argv[i], "--proxy-tests") == 0) {
194       ctx->proxy_tests = 1;
195     }
196     else if (strcmp(argv[i], "--no-proxy") == 0) {
197       o_iproxy = 0;
198     }
199     else if (strcmp(argv[i], "--no-nat") == 0) {
200       o_inat = 0;
201     }
202     else if (strcmp(argv[i], "--nat") == 0) {
203       o_inat = 1;
204     }
205     else if (strcmp(argv[i], "--symmetric") == 0) {
206       o_inat_symmetric = 1;
207     }
208     else if (strcmp(argv[i], "-N") == 0) {
209       o_inat_logging = 1;
210     }
211     else if (strcmp(argv[i], "--expensive") == 0) {
212       o_expensive = 1;
213     }
214     else if (strcmp(argv[i], "--no-alarm") == 0) {
215       o_alarm = 0;
216     }
217     else if (strcmp(argv[i], "--loop") == 0) {
218       o_alarm = 0, o_loop = 1;
219     }
220     else if (strcmp(argv[i], "--print-tags") == 0) {
221       ctx->print_tags = 1;
222     }
223     else if (strcmp(argv[i], "--tags=a") == 0) {
224       ctx->a.print_tags = 1;
225     }
226     else if (strcmp(argv[i], "--tags=b") == 0) {
227       ctx->b.print_tags = 1;
228     }
229     else if (strcmp(argv[i], "--tags=c") == 0) {
230       ctx->c.print_tags = 1;
231     }
232     else if (strcmp(argv[i], "--log=a") == 0) {
233       ctx->a.logging = 1;
234     }
235     else if (strcmp(argv[i], "--log=b") == 0) {
236       ctx->b.logging = 1;
237     }
238     else if (strcmp(argv[i], "--log=c") == 0) {
239       ctx->c.logging = 1;
240     }
241     else if (strcmp(argv[i], "--log=proxy") == 0) {
242       ctx->proxy_logging = 1;
243     }
244 #if SU_HAVE_OSX_CF_API /* If compiled with CoreFoundation events */
245     else if (strcmp(argv[i], "--osx-runloop") == 0) {
246       ctx->osx_runloop = 1;
247     }
248 #endif
249     else if (strcmp(argv[i], "-") == 0) {
250       i++; break;
251     }
252     else if (argv[i][0] != '-') {
253       break;
254     }
255     else {
256       fprintf(stderr, "test_nua: unknown argument \"%s\"\n\n", argv[i]);
257       usage(1);
258     }
259   }
260 
261   if (o_attach) {
262     char line[10], *l;
263     printf("%s: pid %lu\n", name, (unsigned long)getpid());
264     printf("<Press RETURN to continue>\n");
265     l = fgets(line, sizeof line, stdin);
266   }
267 #if HAVE_ALARM
268   else if (o_alarm) {
269     signal(SIGALRM, sig_alarm);
270     if (o_expensive) {
271       printf("%s: extending timeout to %u because expensive tests\n",
272 	     name, 240);
273       alarm(240);
274     }
275     else {
276       alarm(120);
277     }
278   }
279 #endif
280 
281 #if HAVE_OPEN_C
282   tstflags |= tst_verbatim;
283   level = 9;
284   o_inat = 1; /* No NATs */
285   ctx->threading = 1;
286   ctx->quit_on_single_failure = 1;
287   su_log_soft_set_level(nua_log, level);
288   su_log_soft_set_level(soa_log, level);
289   su_log_soft_set_level(su_log_default, level);
290   su_log_soft_set_level(nea_log, level);
291   su_log_soft_set_level(nta_log, level);
292   su_log_soft_set_level(tport_log, level);
293   setenv("SU_DEBUG", "9", 1);
294   setenv("NUA_DEBUG", "9", 1);
295   setenv("NTA_DEBUG", "9", 1);
296   setenv("TPORT_DEBUG", "9", 1);
297   o_events_a = o_events_b = 1;
298 #endif
299 
300   su_init();
301 
302   if (!(TSTFLAGS & tst_verbatim)) {
303     if (level == 0 && !o_quiet)
304       level = 1;
305     su_log_soft_set_level(nua_log, level);
306     su_log_soft_set_level(soa_log, level);
307     su_log_soft_set_level(su_log_default, level);
308     su_log_soft_set_level(nea_log, level);
309     su_log_soft_set_level(nta_log, level);
310     su_log_soft_set_level(tport_log, level);
311   }
312 
313   if (!o_quiet || (TSTFLAGS & tst_verbatim)
314       || o_events_a || o_events_b || o_events_c)
315     print_headings = 1;
316 
317 #if !HAVE_OPEN_C
318 #define SINGLE_FAILURE_CHECK()						\
319   do { fflush(stdout);							\
320     if (retval && ctx->quit_on_single_failure) {			\
321       su_deinit(); return retval; }					\
322   } while(0)
323 #else
324 #define SINGLE_FAILURE_CHECK()						\
325   do { fflush(stdout);							\
326     if (retval && ctx->quit_on_single_failure) {			\
327       su_deinit(); sleep(10); return retval; }					\
328   } while(0)
329 #endif
330 
331   ctx->a.printer = o_events_init ? print_event : NULL;
332 
333   retval |= test_nua_api_errors(ctx); SINGLE_FAILURE_CHECK();
334 
335   retval |= test_tag_filter(); SINGLE_FAILURE_CHECK();
336 
337   retval |= test_nua_params(ctx); SINGLE_FAILURE_CHECK();
338 
339   retval |= test_nua_destroy(ctx); SINGLE_FAILURE_CHECK();
340 
341   retval |= test_stack_errors(ctx); SINGLE_FAILURE_CHECK();
342 
343   retval |= test_nua_init(ctx, o_iproxy, o_proxy, o_inat,
344 			  TESTNATTAG_SYMMETRIC(o_inat_symmetric),
345 			  TESTNATTAG_LOGGING(o_inat_logging),
346 			  TAG_END());
347 
348   ctx->expensive = o_expensive;
349 
350   if (retval == 0) {
351     ctx->a.printer = o_events_a ? print_event : NULL;
352     if (o_events_b)
353       ctx->b.printer = print_event;
354     if (o_events_c)
355       ctx->c.printer = print_event;
356 
357     retval |= test_register(ctx);
358 
359     if (retval == 0)
360       retval |= test_connectivity(ctx);
361 
362     if (retval == 0 && o_inat)
363       retval |= test_nat_timeout(ctx);
364 
365     while (retval == 0) {
366       retval |= test_basic_call(ctx); SINGLE_FAILURE_CHECK();
367       retval |= test_rejects(ctx); SINGLE_FAILURE_CHECK();
368       retval |= test_call_cancel(ctx); SINGLE_FAILURE_CHECK();
369       retval |= test_call_destroy(ctx); SINGLE_FAILURE_CHECK();
370       retval |= test_early_bye(ctx); SINGLE_FAILURE_CHECK();
371       retval |= test_offer_answer(ctx); SINGLE_FAILURE_CHECK();
372       retval |= test_reinvites(ctx); SINGLE_FAILURE_CHECK();
373       retval |= test_session_timer(ctx); SINGLE_FAILURE_CHECK();
374       retval |= test_refer(ctx); SINGLE_FAILURE_CHECK();
375       retval |= test_100rel(ctx); SINGLE_FAILURE_CHECK();
376       retval |= test_simple(ctx); SINGLE_FAILURE_CHECK();
377       retval |= test_events(ctx); SINGLE_FAILURE_CHECK();
378       retval |= test_extension(ctx); SINGLE_FAILURE_CHECK();
379       if (!o_loop)
380 	break;
381     }
382 
383     if (ctx->proxy_tests && (retval == 0 || !ctx->p))
384       retval |= test_unregister(ctx); SINGLE_FAILURE_CHECK();
385   }
386   retval |= test_deinit(ctx);
387 
388   su_home_deinit(ctx->home);
389 
390   su_deinit();
391 
392 #if HAVE_OPEN_C
393   sleep(7);
394 #endif
395 
396   return retval;
397 }
398