blob: f6f9c2fe3aa0c1387667cd7fbca48fe264a29e0a [file] [log] [blame]
Benny Prijonofa73e3e2006-01-05 23:35:46 +00001/* $Id$ */
2/*
Benny Prijono844653c2008-12-23 17:27:53 +00003 * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com)
Benny Prijono32177c02008-06-20 22:44:47 +00004 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
Benny Prijonofa73e3e2006-01-05 23:35:46 +00005 *
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
21#include "test.h"
Benny Prijono40f2f642006-01-30 18:40:05 +000022#include <pjsip.h>
Benny Prijonofa73e3e2006-01-05 23:35:46 +000023#include <pjlib.h>
24
Benny Prijono85598d92006-01-07 18:44:25 +000025#define THIS_FILE "tsx_uac_test.c"
26
27
Benny Prijonofa73e3e2006-01-05 23:35:46 +000028/*****************************************************************************
29 **
Benny Prijono85598d92006-01-07 18:44:25 +000030 ** UAC tests.
Benny Prijonofa73e3e2006-01-05 23:35:46 +000031 **
Benny Prijono85598d92006-01-07 18:44:25 +000032 ** This file performs various tests for UAC transactions. Each test will have
33 ** a different Via branch param so that message receiver module and
34 ** transaction user module can identify which test is being carried out.
Benny Prijonofa73e3e2006-01-05 23:35:46 +000035 **
Benny Prijono85598d92006-01-07 18:44:25 +000036 ** TEST1_BRANCH_ID
37 ** Perform basic retransmission and timeout test. Message receiver will
38 ** verify that retransmission is received at correct time.
39 ** This test verifies the following requirements:
40 ** - retransmit timer doubles for INVITE
41 ** - retransmit timer doubles and caps off for non-INVITE
42 ** - retransmit timer timer is precise
43 ** - correct timeout and retransmission count
44 ** Requirements not tested:
45 ** - retransmit timer only starts after resolving has completed.
46 **
47 ** TEST2_BRANCH_ID
48 ** Test scenario where resolver is unable to resolve destination host.
49 **
50 ** TEST3_BRANCH_ID
51 ** Test scenario where transaction is terminated while resolver is still
52 ** running.
53 **
54 ** TEST4_BRANCH_ID
55 ** Test scenario where transport failed after several retransmissions.
56 **
57 ** TEST5_BRANCH_ID
58 ** Test scenario where transaction is terminated by user after several
59 ** retransmissions.
60 **
61 ** TEST6_BRANCH_ID
62 ** Test successfull non-INVITE transaction.
63 ** It tests the following requirements:
64 ** - transaction correctly moves to COMPLETED state.
65 ** - retransmission must cease.
66 ** - tx_data must be maintained until state is terminated.
67 **
68 ** TEST7_BRANCH_ID
69 ** Test successfull non-INVITE transaction, with provisional response.
70 **
71 ** TEST8_BRANCH_ID
72 ** Test failed INVITE transaction (e.g. ACK must be received)
73 **
74 ** TEST9_BRANCH_ID
75 ** Test failed INVITE transaction with provisional response.
76 **
77 **
Benny Prijonofa73e3e2006-01-05 23:35:46 +000078 *****************************************************************************
79 */
80
Benny Prijonodbe337a2006-01-08 23:57:52 +000081static char *TEST1_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAC-Test1";
82static char *TEST2_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAC-Test2";
83static char *TEST3_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAC-Test3";
84static char *TEST4_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAC-Test4";
85static char *TEST5_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAC-Test5";
86static char *TEST6_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAC-Test6";
87static char *TEST7_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAC-Test7";
88static char *TEST8_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAC-Test8";
89static char *TEST9_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAC-Test9";
Benny Prijono85598d92006-01-07 18:44:25 +000090
91#define TEST1_ALLOWED_DIFF (150)
92#define TEST4_RETRANSMIT_CNT 3
93#define TEST5_RETRANSMIT_CNT 3
94
Benny Prijonoe93e2872006-06-28 16:46:49 +000095static char TARGET_URI[128];
96static char FROM_URI[128];
97static unsigned tp_flag;
98static struct tsx_test_param *test_param;
Benny Prijono85598d92006-01-07 18:44:25 +000099
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000100static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e);
101static pj_bool_t msg_receiver_on_rx_request(pjsip_rx_data *rdata);
102
103/* UAC transaction user module. */
104static pjsip_module tsx_user =
105{
106 NULL, NULL, /* prev and next */
Benny Prijonodbe337a2006-01-08 23:57:52 +0000107 { "Tsx-UAC-User", 12}, /* Name. */
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000108 -1, /* Id */
109 PJSIP_MOD_PRIORITY_APPLICATION-1, /* Priority */
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000110 NULL, /* load() */
111 NULL, /* start() */
112 NULL, /* stop() */
113 NULL, /* unload() */
114 NULL, /* on_rx_request() */
115 NULL, /* on_rx_response() */
Benny Prijono85598d92006-01-07 18:44:25 +0000116 NULL, /* on_tx_request() */
117 NULL, /* on_tx_response() */
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000118 &tsx_user_on_tsx_state, /* on_tsx_state() */
119};
120
121/* Module to receive the loop-backed request. */
122static pjsip_module msg_receiver =
123{
124 NULL, NULL, /* prev and next */
Benny Prijonodbe337a2006-01-08 23:57:52 +0000125 { "Msg-Receiver", 12}, /* Name. */
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000126 -1, /* Id */
127 PJSIP_MOD_PRIORITY_APPLICATION-1, /* Priority */
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000128 NULL, /* load() */
129 NULL, /* start() */
130 NULL, /* stop() */
131 NULL, /* unload() */
132 &msg_receiver_on_rx_request, /* on_rx_request() */
133 NULL, /* on_rx_response() */
Benny Prijono85598d92006-01-07 18:44:25 +0000134 NULL, /* on_tx_request() */
135 NULL, /* on_tx_response() */
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000136 NULL, /* on_tsx_state() */
137};
138
Benny Prijono85598d92006-01-07 18:44:25 +0000139/* Static vars, which will be reset on each test. */
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000140static int recv_count;
141static pj_time_val recv_last;
142static pj_bool_t test_complete;
143
Benny Prijono85598d92006-01-07 18:44:25 +0000144/* Loop transport instance. */
145static pjsip_transport *loop;
146
Benny Prijono9c1d9f52006-01-07 23:01:56 +0000147/* General timer entry to be used by tests. */
Benny Prijonoe93e2872006-06-28 16:46:49 +0000148static struct my_timer
149{
150 pj_timer_entry entry;
151 char key_buf[1024];
152 pj_str_t tsx_key;
153} timer;
Benny Prijono9c1d9f52006-01-07 23:01:56 +0000154
Benny Prijono85598d92006-01-07 18:44:25 +0000155/*
156 * This is the handler to receive state changed notification from the
157 * transaction. It is used to verify that the transaction behaves according
158 * to the test scenario.
159 */
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000160static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e)
161{
Benny Prijono85598d92006-01-07 18:44:25 +0000162 if (pj_strcmp2(&tsx->branch, TEST1_BRANCH_ID)==0) {
163 /*
164 * Transaction with TEST1_BRANCH_ID should terminate with transaction
165 * timeout status.
166 */
167 if (tsx->state == PJSIP_TSX_STATE_TERMINATED) {
168
169 if (test_complete == 0)
170 test_complete = 1;
171
172 /* Test the status code. */
173 if (tsx->status_code != PJSIP_SC_TSX_TIMEOUT) {
174 PJ_LOG(3,(THIS_FILE,
175 " error: status code is %d instead of %d",
176 tsx->status_code, PJSIP_SC_TSX_TIMEOUT));
177 test_complete = -710;
178 }
Benny Prijonoe93e2872006-06-28 16:46:49 +0000179
180
181 /* If transport is reliable, then there must not be any
182 * retransmissions.
183 */
184 if (tp_flag & PJSIP_TRANSPORT_RELIABLE) {
185 if (recv_count != 1) {
186 PJ_LOG(3,(THIS_FILE,
187 " error: there were %d (re)transmissions",
188 recv_count));
189 test_complete = -715;
190 }
191 } else {
192 /* Check the number of transmissions, which must be
193 * 6 for INVITE and 10 for non-INVITE
194 */
195 if (tsx->method.id==PJSIP_INVITE_METHOD && recv_count != 7) {
196 PJ_LOG(3,(THIS_FILE,
197 " error: there were %d (re)transmissions",
198 recv_count));
199 test_complete = -716;
200 } else
201 if (tsx->method.id==PJSIP_OPTIONS_METHOD && recv_count != 11) {
202 PJ_LOG(3,(THIS_FILE,
203 " error: there were %d (re)transmissions",
204 recv_count));
205 test_complete = -717;
206 } else
207 if (tsx->method.id!=PJSIP_INVITE_METHOD &&
208 tsx->method.id!=PJSIP_OPTIONS_METHOD)
209 {
210 PJ_LOG(3,(THIS_FILE, " error: unexpected method"));
211 test_complete = -718;
212 }
213 }
Benny Prijono85598d92006-01-07 18:44:25 +0000214 }
215
216 } else if (pj_strcmp2(&tsx->branch, TEST2_BRANCH_ID)==0) {
217 /*
218 * Transaction with TEST2_BRANCH_ID should terminate with transport error.
219 */
220 if (tsx->state == PJSIP_TSX_STATE_TERMINATED) {
221
222 /* Test the status code. */
223 if (tsx->status_code != PJSIP_SC_TSX_TRANSPORT_ERROR) {
224 PJ_LOG(3,(THIS_FILE,
225 " error: status code is %d instead of %d",
226 tsx->status_code, PJSIP_SC_TSX_TRANSPORT_ERROR));
227 test_complete = -720;
228 }
229
230 if (test_complete == 0)
231 test_complete = 1;
232 }
233
234 } else if (pj_strcmp2(&tsx->branch, TEST3_BRANCH_ID)==0) {
235 /*
236 * This test terminates the transaction while resolver is still
237 * running.
238 */
239 if (tsx->state == PJSIP_TSX_STATE_CALLING) {
240
241 /* Terminate the transaction. */
242 pjsip_tsx_terminate(tsx, PJSIP_SC_REQUEST_TERMINATED);
243
244 } else if (tsx->state == PJSIP_TSX_STATE_TERMINATED) {
245
246 /* Check if status code is correct. */
247 if (tsx->status_code != PJSIP_SC_REQUEST_TERMINATED) {
248 PJ_LOG(3,(THIS_FILE,
249 " error: status code is %d instead of %d",
250 tsx->status_code, PJSIP_SC_REQUEST_TERMINATED));
251 test_complete = -730;
252 }
253
254 if (test_complete == 0)
255 test_complete = 1;
256
257 }
258
259 } else if (pj_strcmp2(&tsx->branch, TEST4_BRANCH_ID)==0) {
260 /*
261 * This test simulates transport failure after several
262 * retransmissions.
263 */
264 if (tsx->state == PJSIP_TSX_STATE_TERMINATED) {
265
266 /* Status code must be transport error. */
267 if (tsx->status_code != PJSIP_SC_TSX_TRANSPORT_ERROR) {
268 PJ_LOG(3,(THIS_FILE,
269 " error: status code is %d instead of %d",
270 tsx->status_code, PJSIP_SC_TSX_TRANSPORT_ERROR));
271 test_complete = -730;
272 }
273
274 /* Must have correct retransmission count. */
275 if (tsx->retransmit_count != TEST4_RETRANSMIT_CNT) {
276 PJ_LOG(3,(THIS_FILE,
277 " error: retransmit cnt is %d instead of %d",
278 tsx->retransmit_count, TEST4_RETRANSMIT_CNT));
279 test_complete = -731;
280 }
281
282 if (test_complete == 0)
283 test_complete = 1;
284 }
285
286
287 } else if (pj_strcmp2(&tsx->branch, TEST5_BRANCH_ID)==0) {
288 /*
289 * This test simulates transport failure after several
290 * retransmissions.
291 */
292 if (tsx->state == PJSIP_TSX_STATE_TERMINATED) {
293
294 /* Status code must be PJSIP_SC_REQUEST_TERMINATED. */
295 if (tsx->status_code != PJSIP_SC_REQUEST_TERMINATED) {
296 PJ_LOG(3,(THIS_FILE,
297 " error: status code is %d instead of %d",
298 tsx->status_code, PJSIP_SC_REQUEST_TERMINATED));
299 test_complete = -733;
300 }
301
302 /* Must have correct retransmission count. */
303 if (tsx->retransmit_count != TEST5_RETRANSMIT_CNT) {
304 PJ_LOG(3,(THIS_FILE,
305 " error: retransmit cnt is %d instead of %d",
306 tsx->retransmit_count, TEST5_RETRANSMIT_CNT));
307 test_complete = -734;
308 }
309
310 if (test_complete == 0)
311 test_complete = 1;
312 }
313
314
315 } else if (pj_strcmp2(&tsx->branch, TEST6_BRANCH_ID)==0) {
316 /*
317 * Successfull non-INVITE transaction.
318 */
319 if (tsx->state == PJSIP_TSX_STATE_COMPLETED) {
320
321 /* Status code must be 202. */
322 if (tsx->status_code != 202) {
323 PJ_LOG(3,(THIS_FILE,
324 " error: status code is %d instead of %d",
325 tsx->status_code, 202));
326 test_complete = -736;
327 }
328
329 /* Must have correct retransmission count. */
330 if (tsx->retransmit_count != 0) {
331 PJ_LOG(3,(THIS_FILE,
332 " error: retransmit cnt is %d instead of %d",
333 tsx->retransmit_count, 0));
334 test_complete = -737;
335 }
336
337 /* Must still keep last_tx */
338 if (tsx->last_tx == NULL) {
339 PJ_LOG(3,(THIS_FILE,
340 " error: transaction lost last_tx"));
341 test_complete = -738;
342 }
343
344 if (test_complete == 0) {
345 test_complete = 1;
346 pjsip_tsx_terminate(tsx, 202);
347 }
Benny Prijono9c1d9f52006-01-07 23:01:56 +0000348
349 } else if (tsx->state == PJSIP_TSX_STATE_TERMINATED) {
350
351 /* Previous state must be COMPLETED. */
352 if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_COMPLETED) {
353 test_complete = -7381;
354 }
355
Benny Prijono85598d92006-01-07 18:44:25 +0000356 }
Benny Prijono9c1d9f52006-01-07 23:01:56 +0000357
358 } else if (pj_strcmp2(&tsx->branch, TEST7_BRANCH_ID)==0) {
359 /*
360 * Successfull non-INVITE transaction.
361 */
362 if (tsx->state == PJSIP_TSX_STATE_COMPLETED) {
363
364 /* Check prev state. */
365 if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_PROCEEDING) {
366 PJ_LOG(3,(THIS_FILE,
367 " error: prev state is %s instead of %s",
Benny Prijonoa1e69682007-05-11 15:14:34 +0000368 pjsip_tsx_state_str((pjsip_tsx_state_e)e->body.tsx_state.prev_state),
Benny Prijono9c1d9f52006-01-07 23:01:56 +0000369 pjsip_tsx_state_str(PJSIP_TSX_STATE_PROCEEDING)));
370 test_complete = -739;
371 }
372
373 /* Status code must be 202. */
374 if (tsx->status_code != 202) {
375 PJ_LOG(3,(THIS_FILE,
376 " error: status code is %d instead of %d",
377 tsx->status_code, 202));
378 test_complete = -740;
379 }
380
381 /* Must have correct retransmission count. */
382 if (tsx->retransmit_count != 0) {
383 PJ_LOG(3,(THIS_FILE,
384 " error: retransmit cnt is %d instead of %d",
385 tsx->retransmit_count, 0));
386 test_complete = -741;
387 }
388
389 /* Must still keep last_tx */
390 if (tsx->last_tx == NULL) {
391 PJ_LOG(3,(THIS_FILE,
392 " error: transaction lost last_tx"));
393 test_complete = -741;
394 }
395
396 if (test_complete == 0) {
397 test_complete = 1;
398 pjsip_tsx_terminate(tsx, 202);
399 }
400
401 } else if (tsx->state == PJSIP_TSX_STATE_TERMINATED) {
402
403 /* Previous state must be COMPLETED. */
404 if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_COMPLETED) {
405 test_complete = -742;
406 }
407
408 }
409
410
411 } else if (pj_strcmp2(&tsx->branch, TEST8_BRANCH_ID)==0) {
412 /*
413 * Failed INVITE transaction.
414 */
415 if (tsx->state == PJSIP_TSX_STATE_COMPLETED) {
416
417 /* Status code must be 301. */
418 if (tsx->status_code != 301) {
419 PJ_LOG(3,(THIS_FILE,
420 " error: status code is %d instead of %d",
421 tsx->status_code, 301));
422 test_complete = -745;
423 }
424
425 /* Must have correct retransmission count. */
426 if (tsx->retransmit_count != 0) {
427 PJ_LOG(3,(THIS_FILE,
428 " error: retransmit cnt is %d instead of %d",
429 tsx->retransmit_count, 0));
430 test_complete = -746;
431 }
432
433 /* Must still keep last_tx */
434 if (tsx->last_tx == NULL) {
435 PJ_LOG(3,(THIS_FILE,
436 " error: transaction lost last_tx"));
437 test_complete = -747;
438 }
439
Benny Prijono728a9052006-01-18 23:34:15 +0000440 /* last_tx MUST be the INVITE request
441 * (authorization depends on this behavior)
442 */
Benny Prijono9c1d9f52006-01-07 23:01:56 +0000443 if (tsx->last_tx && tsx->last_tx->msg->line.req.method.id !=
Benny Prijono728a9052006-01-18 23:34:15 +0000444 PJSIP_INVITE_METHOD)
Benny Prijono9c1d9f52006-01-07 23:01:56 +0000445 {
446 PJ_LOG(3,(THIS_FILE,
Benny Prijono728a9052006-01-18 23:34:15 +0000447 " error: last_tx is not INVITE"));
Benny Prijono9c1d9f52006-01-07 23:01:56 +0000448 test_complete = -748;
449 }
450 }
451 else if (tsx->state == PJSIP_TSX_STATE_TERMINATED) {
452
453 test_complete = 1;
454
455 /* Previous state must be COMPLETED. */
456 if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_COMPLETED) {
457 test_complete = -750;
458 }
459
460 /* Status code must be 301. */
461 if (tsx->status_code != 301) {
462 PJ_LOG(3,(THIS_FILE,
463 " error: status code is %d instead of %d",
464 tsx->status_code, 301));
465 test_complete = -751;
466 }
467
468 }
469
470
471 } else if (pj_strcmp2(&tsx->branch, TEST9_BRANCH_ID)==0) {
472 /*
473 * Failed INVITE transaction with provisional response.
474 */
475 if (tsx->state == PJSIP_TSX_STATE_COMPLETED) {
476
477 /* Previous state must be PJSIP_TSX_STATE_PROCEEDING. */
478 if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_PROCEEDING) {
479 test_complete = -760;
480 }
481
482 /* Status code must be 302. */
483 if (tsx->status_code != 302) {
484 PJ_LOG(3,(THIS_FILE,
485 " error: status code is %d instead of %d",
486 tsx->status_code, 302));
487 test_complete = -761;
488 }
489
490 /* Must have correct retransmission count. */
491 if (tsx->retransmit_count != 0) {
492 PJ_LOG(3,(THIS_FILE,
493 " error: retransmit cnt is %d instead of %d",
494 tsx->retransmit_count, 0));
495 test_complete = -762;
496 }
497
498 /* Must still keep last_tx */
499 if (tsx->last_tx == NULL) {
500 PJ_LOG(3,(THIS_FILE,
501 " error: transaction lost last_tx"));
502 test_complete = -763;
503 }
504
Benny Prijono728a9052006-01-18 23:34:15 +0000505 /* last_tx MUST be INVITE.
506 * (authorization depends on this behavior)
507 */
Benny Prijono9c1d9f52006-01-07 23:01:56 +0000508 if (tsx->last_tx && tsx->last_tx->msg->line.req.method.id !=
Benny Prijono728a9052006-01-18 23:34:15 +0000509 PJSIP_INVITE_METHOD)
Benny Prijono9c1d9f52006-01-07 23:01:56 +0000510 {
511 PJ_LOG(3,(THIS_FILE,
Benny Prijono728a9052006-01-18 23:34:15 +0000512 " error: last_tx is not INVITE"));
Benny Prijono9c1d9f52006-01-07 23:01:56 +0000513 test_complete = -764;
514 }
515
516 }
517 else if (tsx->state == PJSIP_TSX_STATE_TERMINATED) {
518
519 test_complete = 1;
520
521 /* Previous state must be COMPLETED. */
522 if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_COMPLETED) {
523 test_complete = -767;
524 }
525
526 /* Status code must be 302. */
527 if (tsx->status_code != 302) {
528 PJ_LOG(3,(THIS_FILE,
529 " error: status code is %d instead of %d",
530 tsx->status_code, 302));
531 test_complete = -768;
532 }
533
534 }
535
Benny Prijono85598d92006-01-07 18:44:25 +0000536 }
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000537}
538
Benny Prijono9c1d9f52006-01-07 23:01:56 +0000539/*
540 * This timer callback is called to send delayed response.
541 */
542struct response
543{
544 pjsip_response_addr res_addr;
545 pjsip_tx_data *tdata;
546};
547
548static void send_response_callback( pj_timer_heap_t *timer_heap,
549 struct pj_timer_entry *entry)
550{
Benny Prijonoa1e69682007-05-11 15:14:34 +0000551 struct response *r = (struct response*) entry->user_data;
Benny Prijono9c1d9f52006-01-07 23:01:56 +0000552 pjsip_transport *tp = r->res_addr.transport;
553
Nanang Izzuddin2e4f03f2009-04-27 19:18:38 +0000554 PJ_UNUSED_ARG(timer_heap);
555
Benny Prijono9c1d9f52006-01-07 23:01:56 +0000556 pjsip_endpt_send_response(endpt, &r->res_addr, r->tdata, NULL, NULL);
557 if (tp)
558 pjsip_transport_dec_ref(tp);
559}
560
561/* Timer callback to terminate a transaction. */
562static void terminate_tsx_callback( pj_timer_heap_t *timer_heap,
563 struct pj_timer_entry *entry)
564{
Benny Prijonoe93e2872006-06-28 16:46:49 +0000565 struct my_timer *m = (struct my_timer *)entry;
566 pjsip_transaction *tsx = pjsip_tsx_layer_find_tsx(&m->tsx_key, PJ_FALSE);
Benny Prijono9c1d9f52006-01-07 23:01:56 +0000567 int status_code = entry->id;
568
Nanang Izzuddin2e4f03f2009-04-27 19:18:38 +0000569 PJ_UNUSED_ARG(timer_heap);
570
Benny Prijono9c1d9f52006-01-07 23:01:56 +0000571 if (tsx) {
572 pjsip_tsx_terminate(tsx, status_code);
573 }
574}
575
576
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000577#define DIFF(a,b) ((a<b) ? (b-a) : (a-b))
578
Benny Prijono85598d92006-01-07 18:44:25 +0000579/*
580 * This is the handler to receive message for this test. It is used to
581 * control and verify the behavior of the message transmitted by the
582 * transaction.
583 */
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000584static pj_bool_t msg_receiver_on_rx_request(pjsip_rx_data *rdata)
585{
Benny Prijono85598d92006-01-07 18:44:25 +0000586 if (pj_strcmp2(&rdata->msg_info.via->branch_param, TEST1_BRANCH_ID) == 0) {
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000587 /*
Benny Prijono85598d92006-01-07 18:44:25 +0000588 * The TEST1_BRANCH_ID test performs the verifications for transaction
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000589 * retransmission mechanism. It will not answer the incoming request
590 * with any response.
591 */
592 pjsip_msg *msg = rdata->msg_info.msg;
593
Benny Prijono85598d92006-01-07 18:44:25 +0000594 PJ_LOG(4,(THIS_FILE, " received request"));
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000595
596 /* Only wants to take INVITE or OPTIONS method. */
597 if (msg->line.req.method.id != PJSIP_INVITE_METHOD &&
598 msg->line.req.method.id != PJSIP_OPTIONS_METHOD)
599 {
Benny Prijono85598d92006-01-07 18:44:25 +0000600 PJ_LOG(3,(THIS_FILE, " error: received unexpected method %.*s",
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000601 msg->line.req.method.name.slen,
602 msg->line.req.method.name.ptr));
603 test_complete = -600;
604 return PJ_TRUE;
605 }
606
607 if (recv_count == 0) {
608 recv_count++;
Benny Prijono85598d92006-01-07 18:44:25 +0000609 //pj_gettimeofday(&recv_last);
610 recv_last = rdata->pkt_info.timestamp;
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000611 } else {
612 pj_time_val now;
613 unsigned msec_expected, msec_elapsed;
Benny Prijono85598d92006-01-07 18:44:25 +0000614 int max_received;
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000615
Benny Prijono85598d92006-01-07 18:44:25 +0000616 //pj_gettimeofday(&now);
617 now = rdata->pkt_info.timestamp;
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000618 PJ_TIME_VAL_SUB(now, recv_last);
619 msec_elapsed = now.sec*1000 + now.msec;
620
621 ++recv_count;
Benny Prijono4768c3c2008-02-22 11:10:17 +0000622 msec_expected = (1<<(recv_count-2))*pjsip_cfg()->tsx.t1;
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000623
624 if (msg->line.req.method.id != PJSIP_INVITE_METHOD) {
Benny Prijono4768c3c2008-02-22 11:10:17 +0000625 if (msec_expected > pjsip_cfg()->tsx.t2)
626 msec_expected = pjsip_cfg()->tsx.t2;
Benny Prijono85598d92006-01-07 18:44:25 +0000627 max_received = 11;
628 } else {
629 max_received = 7;
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000630 }
631
Benny Prijono85598d92006-01-07 18:44:25 +0000632 if (DIFF(msec_expected, msec_elapsed) > TEST1_ALLOWED_DIFF) {
633 PJ_LOG(3,(THIS_FILE,
634 " error: expecting retransmission no. %d in %d "
635 "ms, received in %d ms",
636 recv_count-1, msec_expected, msec_elapsed));
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000637 test_complete = -610;
638 }
639
Benny Prijono85598d92006-01-07 18:44:25 +0000640
641 if (recv_count > max_received) {
642 PJ_LOG(3,(THIS_FILE,
643 " error: too many messages (%d) received",
644 recv_count));
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000645 test_complete = -620;
646 }
647
Benny Prijono85598d92006-01-07 18:44:25 +0000648 //pj_gettimeofday(&recv_last);
649 recv_last = rdata->pkt_info.timestamp;
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000650 }
651 return PJ_TRUE;
Benny Prijono85598d92006-01-07 18:44:25 +0000652
653 } else
654 if (pj_strcmp2(&rdata->msg_info.via->branch_param, TEST4_BRANCH_ID) == 0) {
655 /*
656 * The TEST4_BRANCH_ID test simulates transport failure after several
657 * retransmissions.
658 */
659 recv_count++;
660
661 if (recv_count == TEST4_RETRANSMIT_CNT) {
662 /* Simulate transport failure. */
663 pjsip_loop_set_failure(loop, 2, NULL);
664
665 } else if (recv_count > TEST4_RETRANSMIT_CNT) {
666 PJ_LOG(3,(THIS_FILE," error: not expecting %d-th packet!",
667 recv_count));
668 test_complete = -631;
669 }
670
671 return PJ_TRUE;
672
673
674 } else
675 if (pj_strcmp2(&rdata->msg_info.via->branch_param, TEST5_BRANCH_ID) == 0) {
676 /*
677 * The TEST5_BRANCH_ID test simulates user terminating the transaction
678 * after several retransmissions.
679 */
680 recv_count++;
681
682 if (recv_count == TEST5_RETRANSMIT_CNT+1) {
683 pj_str_t key;
684 pjsip_transaction *tsx;
685
686 pjsip_tsx_create_key( rdata->tp_info.pool, &key, PJSIP_ROLE_UAC,
687 &rdata->msg_info.msg->line.req.method, rdata);
688 tsx = pjsip_tsx_layer_find_tsx(&key, PJ_TRUE);
689 if (tsx) {
690 pjsip_tsx_terminate(tsx, PJSIP_SC_REQUEST_TERMINATED);
691 pj_mutex_unlock(tsx->mutex);
692 } else {
693 PJ_LOG(3,(THIS_FILE, " error: uac transaction not found!"));
694 test_complete = -633;
695 }
696
697 } else if (recv_count > TEST5_RETRANSMIT_CNT+1) {
698 PJ_LOG(3,(THIS_FILE," error: not expecting %d-th packet!",
699 recv_count));
700 test_complete = -634;
701 }
702
703 return PJ_TRUE;
704
705 } else
706 if (pj_strcmp2(&rdata->msg_info.via->branch_param, TEST6_BRANCH_ID) == 0) {
707 /*
Benny Prijono9c1d9f52006-01-07 23:01:56 +0000708 * The TEST6_BRANCH_ID test successfull non-INVITE transaction.
Benny Prijono85598d92006-01-07 18:44:25 +0000709 */
Benny Prijono85598d92006-01-07 18:44:25 +0000710 pj_status_t status;
711
712 recv_count++;
713
714 if (recv_count > 1) {
715 PJ_LOG(3,(THIS_FILE," error: not expecting %d-th packet!",
716 recv_count));
717 test_complete = -635;
718 }
719
Benny Prijono9c1d9f52006-01-07 23:01:56 +0000720 status = pjsip_endpt_respond_stateless(endpt, rdata, 202, NULL,
721 NULL, NULL);
Benny Prijono85598d92006-01-07 18:44:25 +0000722 if (status != PJ_SUCCESS) {
Benny Prijono9c1d9f52006-01-07 23:01:56 +0000723 app_perror(" error: unable to send response", status);
Benny Prijono85598d92006-01-07 18:44:25 +0000724 test_complete = -636;
725 }
726
Benny Prijono9c1d9f52006-01-07 23:01:56 +0000727 return PJ_TRUE;
728
729
730 } else
731 if (pj_strcmp2(&rdata->msg_info.via->branch_param, TEST7_BRANCH_ID) == 0) {
732 /*
733 * The TEST7_BRANCH_ID test successfull non-INVITE transaction
734 * with provisional response.
735 */
736 pj_status_t status;
737 pjsip_response_addr res_addr;
738 struct response *r;
739 pjsip_tx_data *tdata;
740 pj_time_val delay = { 2, 0 };
741
742 recv_count++;
743
744 if (recv_count > 1) {
745 PJ_LOG(3,(THIS_FILE," error: not expecting %d-th packet!",
746 recv_count));
747 test_complete = -640;
748 return PJ_TRUE;
Benny Prijono85598d92006-01-07 18:44:25 +0000749 }
750
Benny Prijono9c1d9f52006-01-07 23:01:56 +0000751 /* Respond with provisional response */
752 status = pjsip_endpt_create_response(endpt, rdata, 100, NULL, &tdata);
753 pj_assert(status == PJ_SUCCESS);
754
755 status = pjsip_get_response_addr(tdata->pool, rdata, &res_addr);
756 pj_assert(status == PJ_SUCCESS);
757
758 status = pjsip_endpt_send_response(endpt, &res_addr, tdata,
759 NULL, NULL);
760 pj_assert(status == PJ_SUCCESS);
761
762 /* Create the final response. */
763 status = pjsip_endpt_create_response(endpt, rdata, 202, NULL, &tdata);
764 pj_assert(status == PJ_SUCCESS);
765
766 /* Schedule sending final response in couple of of secs. */
Benny Prijonoa1e69682007-05-11 15:14:34 +0000767 r = PJ_POOL_ALLOC_T(tdata->pool, struct response);
Benny Prijono9c1d9f52006-01-07 23:01:56 +0000768 r->res_addr = res_addr;
769 r->tdata = tdata;
770 if (r->res_addr.transport)
771 pjsip_transport_add_ref(r->res_addr.transport);
772
Benny Prijonoe93e2872006-06-28 16:46:49 +0000773 timer.entry.cb = &send_response_callback;
774 timer.entry.user_data = r;
775 pjsip_endpt_schedule_timer(endpt, &timer.entry, &delay);
Benny Prijono9c1d9f52006-01-07 23:01:56 +0000776
777 return PJ_TRUE;
778
779
780 } else
781 if (pj_strcmp2(&rdata->msg_info.via->branch_param, TEST8_BRANCH_ID) == 0) {
782 /*
783 * The TEST8_BRANCH_ID test failed INVITE transaction.
784 */
785 pjsip_method *method;
786 pj_status_t status;
787
788 method = &rdata->msg_info.msg->line.req.method;
789
790 recv_count++;
791
792 if (method->id == PJSIP_INVITE_METHOD) {
793
794 if (recv_count > 1) {
795 PJ_LOG(3,(THIS_FILE," error: not expecting %d-th packet!",
796 recv_count));
797 test_complete = -635;
798 }
799
800 status = pjsip_endpt_respond_stateless(endpt, rdata, 301, NULL,
801 NULL, NULL);
802 if (status != PJ_SUCCESS) {
803 app_perror(" error: unable to send response", status);
804 test_complete = -636;
805 }
806
807 } else if (method->id == PJSIP_ACK_METHOD) {
808
809 if (recv_count == 2) {
810 pj_str_t key;
811 pj_time_val delay = { 5, 0 };
812
813 /* Schedule timer to destroy transaction after 5 seconds.
814 * This is to make sure that transaction does not
815 * retransmit ACK.
816 */
817 pjsip_tsx_create_key(rdata->tp_info.pool, &key,
818 PJSIP_ROLE_UAC, &pjsip_invite_method,
819 rdata);
820
Benny Prijonoe93e2872006-06-28 16:46:49 +0000821 pj_strcpy(&timer.tsx_key, &key);
822 timer.entry.id = 301;
823 timer.entry.cb = &terminate_tsx_callback;
Benny Prijono9c1d9f52006-01-07 23:01:56 +0000824
Benny Prijonoe93e2872006-06-28 16:46:49 +0000825 pjsip_endpt_schedule_timer(endpt, &timer.entry, &delay);
Benny Prijono9c1d9f52006-01-07 23:01:56 +0000826 }
827
828 if (recv_count > 2) {
829 PJ_LOG(3,(THIS_FILE," error: not expecting %d-th packet!",
830 recv_count));
831 test_complete = -638;
832 }
833
834
835 } else {
836 PJ_LOG(3,(THIS_FILE," error: not expecting %s",
837 pjsip_rx_data_get_info(rdata)));
838 test_complete = -639;
839
840 }
841
842
843 } else
844 if (pj_strcmp2(&rdata->msg_info.via->branch_param, TEST9_BRANCH_ID) == 0) {
845 /*
846 * The TEST9_BRANCH_ID test failed INVITE transaction with
847 * provisional response.
848 */
849 pjsip_method *method;
850 pj_status_t status;
851
852 method = &rdata->msg_info.msg->line.req.method;
853
854 recv_count++;
855
856 if (method->id == PJSIP_INVITE_METHOD) {
857
858 pjsip_response_addr res_addr;
859 struct response *r;
860 pjsip_tx_data *tdata;
861 pj_time_val delay = { 2, 0 };
862
863 if (recv_count > 1) {
864 PJ_LOG(3,(THIS_FILE," error: not expecting %d-th packet!",
865 recv_count));
866 test_complete = -650;
867 return PJ_TRUE;
868 }
869
870 /* Respond with provisional response */
871 status = pjsip_endpt_create_response(endpt, rdata, 100, NULL,
872 &tdata);
873 pj_assert(status == PJ_SUCCESS);
874
875 status = pjsip_get_response_addr(tdata->pool, rdata, &res_addr);
876 pj_assert(status == PJ_SUCCESS);
877
878 status = pjsip_endpt_send_response(endpt, &res_addr, tdata,
879 NULL, NULL);
880 pj_assert(status == PJ_SUCCESS);
881
882 /* Create the final response. */
883 status = pjsip_endpt_create_response(endpt, rdata, 302, NULL,
884 &tdata);
885 pj_assert(status == PJ_SUCCESS);
886
887 /* Schedule sending final response in couple of of secs. */
Benny Prijonoa1e69682007-05-11 15:14:34 +0000888 r = PJ_POOL_ALLOC_T(tdata->pool, struct response);
Benny Prijono9c1d9f52006-01-07 23:01:56 +0000889 r->res_addr = res_addr;
890 r->tdata = tdata;
891 if (r->res_addr.transport)
892 pjsip_transport_add_ref(r->res_addr.transport);
893
Benny Prijonoe93e2872006-06-28 16:46:49 +0000894 timer.entry.cb = &send_response_callback;
895 timer.entry.user_data = r;
896 pjsip_endpt_schedule_timer(endpt, &timer.entry, &delay);
Benny Prijono9c1d9f52006-01-07 23:01:56 +0000897
898 } else if (method->id == PJSIP_ACK_METHOD) {
899
900 if (recv_count == 2) {
901 pj_str_t key;
902 pj_time_val delay = { 5, 0 };
903
904 /* Schedule timer to destroy transaction after 5 seconds.
905 * This is to make sure that transaction does not
906 * retransmit ACK.
907 */
908 pjsip_tsx_create_key(rdata->tp_info.pool, &key,
909 PJSIP_ROLE_UAC, &pjsip_invite_method,
910 rdata);
911
Benny Prijonoe93e2872006-06-28 16:46:49 +0000912 pj_strcpy(&timer.tsx_key, &key);
913 timer.entry.id = 302;
914 timer.entry.cb = &terminate_tsx_callback;
Benny Prijono9c1d9f52006-01-07 23:01:56 +0000915
Benny Prijonoe93e2872006-06-28 16:46:49 +0000916 pjsip_endpt_schedule_timer(endpt, &timer.entry, &delay);
Benny Prijono9c1d9f52006-01-07 23:01:56 +0000917 }
918
919 if (recv_count > 2) {
920 PJ_LOG(3,(THIS_FILE," error: not expecting %d-th packet!",
921 recv_count));
922 test_complete = -638;
923 }
924
925
926 } else {
927 PJ_LOG(3,(THIS_FILE," error: not expecting %s",
928 pjsip_rx_data_get_info(rdata)));
929 test_complete = -639;
930
Benny Prijono85598d92006-01-07 18:44:25 +0000931 }
932
933 return PJ_TRUE;
Benny Prijono9c1d9f52006-01-07 23:01:56 +0000934
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000935 }
Benny Prijono85598d92006-01-07 18:44:25 +0000936
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000937 return PJ_FALSE;
938}
939
Benny Prijono85598d92006-01-07 18:44:25 +0000940/*
941 * The generic test framework, used by most of the tests.
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000942 */
Benny Prijono85598d92006-01-07 18:44:25 +0000943static int perform_tsx_test(int dummy, char *target_uri, char *from_uri,
944 char *branch_param, int test_time,
945 const pjsip_method *method)
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000946{
947 pjsip_tx_data *tdata;
948 pjsip_transaction *tsx;
Benny Prijono85598d92006-01-07 18:44:25 +0000949 pj_str_t target, from, tsx_key;
950 pjsip_via_hdr *via;
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000951 pj_time_val timeout;
952 pj_status_t status;
953
Nanang Izzuddin2e4f03f2009-04-27 19:18:38 +0000954 PJ_UNUSED_ARG(dummy);
955
Benny Prijono85598d92006-01-07 18:44:25 +0000956 PJ_LOG(3,(THIS_FILE,
957 " please standby, this will take at most %d seconds..",
958 test_time));
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000959
Benny Prijono85598d92006-01-07 18:44:25 +0000960 /* Reset test. */
961 recv_count = 0;
962 test_complete = 0;
963
964 /* Init headers. */
965 target = pj_str(target_uri);
966 from = pj_str(from_uri);
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000967
968 /* Create request. */
969 status = pjsip_endpt_create_request( endpt, method, &target,
Benny Prijono85598d92006-01-07 18:44:25 +0000970 &from, &target, NULL, NULL, -1,
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000971 NULL, &tdata);
972 if (status != PJ_SUCCESS) {
973 app_perror(" Error: unable to create request", status);
Benny Prijono85598d92006-01-07 18:44:25 +0000974 return -100;
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000975 }
976
Benny Prijono85598d92006-01-07 18:44:25 +0000977 /* Set the branch param for test 1. */
Benny Prijonoa1e69682007-05-11 15:14:34 +0000978 via = (pjsip_via_hdr*) pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL);
Benny Prijono85598d92006-01-07 18:44:25 +0000979 via->branch_param = pj_str(branch_param);
980
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000981 /* Add additional reference to tdata to prevent transaction from
982 * deleting it.
983 */
984 pjsip_tx_data_add_ref(tdata);
985
986 /* Create transaction. */
987 status = pjsip_tsx_create_uac( &tsx_user, tdata, &tsx);
988 if (status != PJ_SUCCESS) {
989 app_perror(" Error: unable to create UAC transaction", status);
Benny Prijono85598d92006-01-07 18:44:25 +0000990 pjsip_tx_data_dec_ref(tdata);
991 return -110;
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000992 }
993
994 /* Get transaction key. */
995 pj_strdup(tdata->pool, &tsx_key, &tsx->transaction_key);
996
997 /* Send the message. */
998 status = pjsip_tsx_send_msg(tsx, NULL);
Benny Prijono85598d92006-01-07 18:44:25 +0000999 // Ignore send result. Some tests do deliberately triggers error
1000 // when sending message.
Benny Prijono02b8fd82006-06-26 15:12:55 +00001001 if (status != PJ_SUCCESS) {
1002 // app_perror(" Error: unable to send request", status);
1003 pjsip_tx_data_dec_ref(tdata);
1004 // return -120;
1005 }
Benny Prijono85598d92006-01-07 18:44:25 +00001006
Benny Prijonofa73e3e2006-01-05 23:35:46 +00001007
1008 /* Set test completion time. */
1009 pj_gettimeofday(&timeout);
Benny Prijono85598d92006-01-07 18:44:25 +00001010 timeout.sec += test_time;
Benny Prijonofa73e3e2006-01-05 23:35:46 +00001011
1012 /* Wait until test complete. */
1013 while (!test_complete) {
Benny Prijono85598d92006-01-07 18:44:25 +00001014 pj_time_val now, poll_delay = {0, 10};
Benny Prijonofa73e3e2006-01-05 23:35:46 +00001015
Benny Prijono85598d92006-01-07 18:44:25 +00001016 pjsip_endpt_handle_events(endpt, &poll_delay);
Benny Prijonofa73e3e2006-01-05 23:35:46 +00001017
1018 pj_gettimeofday(&now);
1019 if (now.sec > timeout.sec) {
Benny Prijono85598d92006-01-07 18:44:25 +00001020 PJ_LOG(3,(THIS_FILE, " Error: test has timed out"));
1021 pjsip_tx_data_dec_ref(tdata);
1022 return -130;
Benny Prijonofa73e3e2006-01-05 23:35:46 +00001023 }
1024 }
1025
Benny Prijono85598d92006-01-07 18:44:25 +00001026 if (test_complete < 0) {
1027 tsx = pjsip_tsx_layer_find_tsx(&tsx_key, PJ_TRUE);
1028 if (tsx) {
1029 pjsip_tsx_terminate(tsx, PJSIP_SC_REQUEST_TERMINATED);
1030 pj_mutex_unlock(tsx->mutex);
1031 flush_events(1000);
1032 }
1033 pjsip_tx_data_dec_ref(tdata);
1034 return test_complete;
Benny Prijono85598d92006-01-07 18:44:25 +00001035
Benny Prijonoe93e2872006-06-28 16:46:49 +00001036 } else {
1037 pj_time_val now;
1038
1039 /* Allow transaction to destroy itself */
1040 flush_events(500);
1041
1042 /* Wait until test completes */
1043 pj_gettimeofday(&now);
1044
1045 if (PJ_TIME_VAL_LT(now, timeout)) {
1046 pj_time_val interval;
1047 interval = timeout;
1048 PJ_TIME_VAL_SUB(interval, now);
1049 flush_events(PJ_TIME_VAL_MSEC(interval));
1050 }
1051 }
Benny Prijonofa73e3e2006-01-05 23:35:46 +00001052
1053 /* Make sure transaction has been destroyed. */
1054 if (pjsip_tsx_layer_find_tsx(&tsx_key, PJ_FALSE) != NULL) {
Benny Prijono85598d92006-01-07 18:44:25 +00001055 PJ_LOG(3,(THIS_FILE, " Error: transaction has not been destroyed"));
1056 pjsip_tx_data_dec_ref(tdata);
1057 return -140;
Benny Prijonofa73e3e2006-01-05 23:35:46 +00001058 }
1059
1060 /* Check tdata reference counter. */
1061 if (pj_atomic_get(tdata->ref_cnt) != 1) {
Benny Prijono85598d92006-01-07 18:44:25 +00001062 PJ_LOG(3,(THIS_FILE, " Error: tdata reference counter is %d",
Benny Prijonofa73e3e2006-01-05 23:35:46 +00001063 pj_atomic_get(tdata->ref_cnt)));
Benny Prijono85598d92006-01-07 18:44:25 +00001064 pjsip_tx_data_dec_ref(tdata);
1065 return -150;
Benny Prijonofa73e3e2006-01-05 23:35:46 +00001066 }
1067
1068 /* Destroy txdata */
1069 pjsip_tx_data_dec_ref(tdata);
1070
1071 return PJ_SUCCESS;
1072}
1073
1074/*****************************************************************************
1075 **
Benny Prijono85598d92006-01-07 18:44:25 +00001076 ** TEST1_BRANCH_ID: UAC basic retransmission and timeout test.
1077 **
1078 ** This will test the retransmission of the UAC transaction. Remote will not
1079 ** answer the transaction, so the transaction should fail. The Via branch prm
1080 ** TEST1_BRANCH_ID will be used for this test.
1081 **
1082 *****************************************************************************
1083 */
1084static int tsx_uac_retransmit_test(void)
1085{
Nanang Izzuddin2e4f03f2009-04-27 19:18:38 +00001086 int status = 0, enabled;
Benny Prijono85598d92006-01-07 18:44:25 +00001087 int i;
1088 struct {
1089 const pjsip_method *method;
1090 unsigned delay;
1091 } sub_test[] =
1092 {
1093 { &pjsip_invite_method, 0},
1094 { &pjsip_invite_method, TEST1_ALLOWED_DIFF*2},
1095 { &pjsip_options_method, 0},
1096 { &pjsip_options_method, TEST1_ALLOWED_DIFF*2}
1097 };
1098
1099 PJ_LOG(3,(THIS_FILE, " test1: basic uac retransmit and timeout test"));
1100
1101
1102 /* For this test. message printing shound be disabled because it makes
1103 * incorrect timing.
1104 */
1105 enabled = msg_logger_set_enabled(0);
1106
Benny Prijonoa1e69682007-05-11 15:14:34 +00001107 for (i=0; i<(int)PJ_ARRAY_SIZE(sub_test); ++i) {
Benny Prijono85598d92006-01-07 18:44:25 +00001108
1109 PJ_LOG(3,(THIS_FILE,
1110 " variant %c: %s with %d ms network delay",
1111 ('a' + i),
1112 sub_test[i].method->name.ptr,
1113 sub_test[i].delay));
1114
1115 /* Configure transport */
1116 pjsip_loop_set_failure(loop, 0, NULL);
1117 pjsip_loop_set_recv_delay(loop, sub_test[i].delay, NULL);
1118
1119 /* Do the test. */
Benny Prijonoe93e2872006-06-28 16:46:49 +00001120 status = perform_tsx_test(-500, TARGET_URI, FROM_URI,
Benny Prijono85598d92006-01-07 18:44:25 +00001121 TEST1_BRANCH_ID,
1122 35, sub_test[i].method);
1123 if (status != 0)
1124 break;
1125 }
1126
1127 /* Restore transport. */
1128 pjsip_loop_set_recv_delay(loop, 0, NULL);
1129
1130 /* Restore msg logger. */
1131 msg_logger_set_enabled(enabled);
1132
1133 /* Done. */
1134 return status;
1135}
1136
1137/*****************************************************************************
1138 **
1139 ** TEST2_BRANCH_ID: UAC resolve error test.
1140 **
1141 ** Test the scenario where destination host is unresolvable. There are
1142 ** two variants:
1143 ** (a) resolver returns immediate error
1144 ** (b) resolver returns error via the callback.
1145 **
1146 *****************************************************************************
1147 */
1148static int tsx_resolve_error_test(void)
1149{
Nanang Izzuddin2e4f03f2009-04-27 19:18:38 +00001150 int status = 0;
Benny Prijono85598d92006-01-07 18:44:25 +00001151
1152 PJ_LOG(3,(THIS_FILE, " test2: resolve error test"));
1153
1154 /*
1155 * Variant (a): immediate resolve error.
1156 */
1157 PJ_LOG(3,(THIS_FILE, " variant a: immediate resolving error"));
1158
1159 status = perform_tsx_test(-800,
Benny Prijonoe93e2872006-06-28 16:46:49 +00001160 "sip:bob@unresolved-host",
Benny Prijonod4791af2007-06-19 08:46:02 +00001161 FROM_URI, TEST2_BRANCH_ID, 20,
Benny Prijono85598d92006-01-07 18:44:25 +00001162 &pjsip_options_method);
1163 if (status != 0)
1164 return status;
1165
1166 /*
1167 * Variant (b): error via callback.
1168 */
1169 PJ_LOG(3,(THIS_FILE, " variant b: error via callback"));
1170
Benny Prijonoe93e2872006-06-28 16:46:49 +00001171 /* This only applies to "loop-dgram" transport */
1172 if (test_param->type == PJSIP_TRANSPORT_LOOP_DGRAM) {
1173 /* Set loop transport to return delayed error. */
1174 pjsip_loop_set_failure(loop, 2, NULL);
1175 pjsip_loop_set_send_callback_delay(loop, 10, NULL);
Benny Prijono85598d92006-01-07 18:44:25 +00001176
Benny Prijonoe93e2872006-06-28 16:46:49 +00001177 status = perform_tsx_test(-800, TARGET_URI, FROM_URI,
1178 TEST2_BRANCH_ID, 2,
1179 &pjsip_options_method);
1180 if (status != 0)
1181 return status;
Benny Prijono85598d92006-01-07 18:44:25 +00001182
Benny Prijonoe93e2872006-06-28 16:46:49 +00001183 /* Restore loop transport settings. */
1184 pjsip_loop_set_failure(loop, 0, NULL);
1185 pjsip_loop_set_send_callback_delay(loop, 0, NULL);
1186 }
Benny Prijono85598d92006-01-07 18:44:25 +00001187
1188 return status;
1189}
1190
1191
1192/*****************************************************************************
1193 **
1194 ** TEST3_BRANCH_ID: UAC terminate while resolving test.
1195 **
1196 ** Terminate the transaction while resolver is still running.
1197 **
1198 *****************************************************************************
1199 */
1200static int tsx_terminate_resolving_test(void)
1201{
1202 unsigned prev_delay;
1203 pj_status_t status;
1204
1205 PJ_LOG(3,(THIS_FILE, " test3: terminate while resolving test"));
1206
1207 /* Configure transport delay. */
1208 pjsip_loop_set_send_callback_delay(loop, 100, &prev_delay);
1209
1210 /* Start the test. */
Benny Prijonoe93e2872006-06-28 16:46:49 +00001211 status = perform_tsx_test(-900, TARGET_URI, FROM_URI,
Benny Prijono85598d92006-01-07 18:44:25 +00001212 TEST3_BRANCH_ID, 2, &pjsip_options_method);
1213
1214 /* Restore delay. */
1215 pjsip_loop_set_send_callback_delay(loop, prev_delay, NULL);
1216
1217 return status;
1218}
1219
1220
1221/*****************************************************************************
1222 **
1223 ** TEST4_BRANCH_ID: Transport failed after several retransmissions
1224 **
1225 ** There are two variants of this test: (a) failure occurs immediately when
1226 ** transaction calls pjsip_transport_send() or (b) failure is reported via
1227 ** transport callback.
1228 **
1229 *****************************************************************************
1230 */
1231static int tsx_retransmit_fail_test(void)
1232{
1233 int i;
1234 unsigned delay[] = {0, 10};
Nanang Izzuddin2e4f03f2009-04-27 19:18:38 +00001235 pj_status_t status = PJ_SUCCESS;
Benny Prijono85598d92006-01-07 18:44:25 +00001236
1237 PJ_LOG(3,(THIS_FILE,
1238 " test4: transport fails after several retransmissions test"));
1239
1240
Benny Prijonoa1e69682007-05-11 15:14:34 +00001241 for (i=0; i<(int)PJ_ARRAY_SIZE(delay); ++i) {
Benny Prijono85598d92006-01-07 18:44:25 +00001242
1243 PJ_LOG(3,(THIS_FILE,
1244 " variant %c: transport delay %d ms", ('a'+i), delay[i]));
1245
1246 /* Configure transport delay. */
1247 pjsip_loop_set_send_callback_delay(loop, delay[i], NULL);
1248
1249 /* Restore transport failure mode. */
1250 pjsip_loop_set_failure(loop, 0, 0);
1251
1252 /* Start the test. */
Benny Prijonoe93e2872006-06-28 16:46:49 +00001253 status = perform_tsx_test(-1000, TARGET_URI, FROM_URI,
Benny Prijono85598d92006-01-07 18:44:25 +00001254 TEST4_BRANCH_ID, 6, &pjsip_options_method);
1255
1256 if (status != 0)
1257 break;
1258
1259 }
1260
1261 /* Restore delay. */
1262 pjsip_loop_set_send_callback_delay(loop, 0, NULL);
1263
1264 /* Restore transport failure mode. */
1265 pjsip_loop_set_failure(loop, 0, 0);
1266
1267 return status;
1268}
1269
1270
1271/*****************************************************************************
1272 **
1273 ** TEST5_BRANCH_ID: Terminate transaction after several retransmissions
1274 **
1275 *****************************************************************************
1276 */
1277static int tsx_terminate_after_retransmit_test(void)
1278{
1279 int status;
1280
1281 PJ_LOG(3,(THIS_FILE, " test5: terminate after retransmissions"));
1282
1283 /* Do the test. */
Benny Prijonoe93e2872006-06-28 16:46:49 +00001284 status = perform_tsx_test(-1100, TARGET_URI, FROM_URI,
Benny Prijono85598d92006-01-07 18:44:25 +00001285 TEST5_BRANCH_ID,
1286 6, &pjsip_options_method);
1287
1288 /* Done. */
1289 return status;
1290}
1291
1292
1293/*****************************************************************************
1294 **
1295 ** TEST6_BRANCH_ID: Successfull non-invite transaction
Benny Prijono9c1d9f52006-01-07 23:01:56 +00001296 ** TEST7_BRANCH_ID: Successfull non-invite transaction with provisional
1297 ** TEST8_BRANCH_ID: Failed invite transaction
1298 ** TEST9_BRANCH_ID: Failed invite transaction with provisional
Benny Prijono85598d92006-01-07 18:44:25 +00001299 **
1300 *****************************************************************************
1301 */
Benny Prijono9c1d9f52006-01-07 23:01:56 +00001302static int perform_generic_test( const char *title,
1303 char *branch_id,
1304 const pjsip_method *method)
Benny Prijono85598d92006-01-07 18:44:25 +00001305{
Nanang Izzuddin2e4f03f2009-04-27 19:18:38 +00001306 int i, status = 0;
Benny Prijono85598d92006-01-07 18:44:25 +00001307 unsigned delay[] = { 1, 200 };
1308
Benny Prijonoe8a2ff52006-01-07 23:36:57 +00001309 PJ_LOG(3,(THIS_FILE, " %s", title));
Benny Prijono85598d92006-01-07 18:44:25 +00001310
1311 /* Do the test. */
Benny Prijonoa1e69682007-05-11 15:14:34 +00001312 for (i=0; i<(int)PJ_ARRAY_SIZE(delay); ++i) {
Benny Prijono85598d92006-01-07 18:44:25 +00001313
Benny Prijonoe93e2872006-06-28 16:46:49 +00001314 if (test_param->type == PJSIP_TRANSPORT_LOOP_DGRAM) {
1315 PJ_LOG(3,(THIS_FILE, " variant %c: with %d ms transport delay",
1316 ('a'+i), delay[i]));
Benny Prijono85598d92006-01-07 18:44:25 +00001317
Benny Prijonoe93e2872006-06-28 16:46:49 +00001318 pjsip_loop_set_delay(loop, delay[i]);
1319 }
Benny Prijono85598d92006-01-07 18:44:25 +00001320
Benny Prijonoe93e2872006-06-28 16:46:49 +00001321 status = perform_tsx_test(-1200, TARGET_URI, FROM_URI,
1322 branch_id, 10, method);
Benny Prijono85598d92006-01-07 18:44:25 +00001323 if (status != 0)
1324 return status;
Benny Prijonoe93e2872006-06-28 16:46:49 +00001325
1326 if (test_param->type != PJSIP_TRANSPORT_LOOP_DGRAM)
1327 break;
Benny Prijono85598d92006-01-07 18:44:25 +00001328 }
1329
1330 pjsip_loop_set_delay(loop, 0);
1331
1332 /* Done. */
1333 return status;
1334}
1335
1336
1337/*****************************************************************************
1338 **
Benny Prijonofa73e3e2006-01-05 23:35:46 +00001339 ** UAC Transaction Test.
1340 **
1341 *****************************************************************************
1342 */
Benny Prijonoe93e2872006-06-28 16:46:49 +00001343int tsx_uac_test(struct tsx_test_param *param)
Benny Prijonofa73e3e2006-01-05 23:35:46 +00001344{
1345 pj_sockaddr_in addr;
Benny Prijonofa73e3e2006-01-05 23:35:46 +00001346 pj_status_t status;
1347
Benny Prijonoe93e2872006-06-28 16:46:49 +00001348 timer.tsx_key.ptr = timer.key_buf;
1349
1350 test_param = param;
1351
1352 /* Get transport flag */
Benny Prijonoa1e69682007-05-11 15:14:34 +00001353 tp_flag = pjsip_transport_get_flag_from_type((pjsip_transport_type_e)test_param->type);
Benny Prijonoe93e2872006-06-28 16:46:49 +00001354
1355 pj_ansi_sprintf(TARGET_URI, "sip:bob@127.0.0.1:%d;transport=%s",
1356 param->port, param->tp_type);
1357 pj_ansi_sprintf(FROM_URI, "sip:alice@127.0.0.1:%d;transport=%s",
1358 param->port, param->tp_type);
1359
Benny Prijono85598d92006-01-07 18:44:25 +00001360 /* Check if loop transport is configured. */
1361 status = pjsip_endpt_acquire_transport(endpt, PJSIP_TRANSPORT_LOOP_DGRAM,
Benny Prijonodf2b71e2007-01-20 19:17:47 +00001362 &addr, sizeof(addr), NULL, &loop);
Benny Prijonofa73e3e2006-01-05 23:35:46 +00001363 if (status != PJ_SUCCESS) {
Benny Prijono85598d92006-01-07 18:44:25 +00001364 PJ_LOG(3,(THIS_FILE, " Error: loop transport is not configured!"));
1365 return -10;
Benny Prijonofa73e3e2006-01-05 23:35:46 +00001366 }
1367
1368 /* Register modules. */
1369 status = pjsip_endpt_register_module(endpt, &tsx_user);
1370 if (status != PJ_SUCCESS) {
1371 app_perror(" Error: unable to register module", status);
1372 return -30;
1373 }
1374 status = pjsip_endpt_register_module(endpt, &msg_receiver);
1375 if (status != PJ_SUCCESS) {
1376 app_perror(" Error: unable to register module", status);
Benny Prijono85598d92006-01-07 18:44:25 +00001377 return -40;
Benny Prijonofa73e3e2006-01-05 23:35:46 +00001378 }
1379
Benny Prijono85598d92006-01-07 18:44:25 +00001380 /* TEST1_BRANCH_ID: Basic retransmit and timeout test. */
1381 status = tsx_uac_retransmit_test();
Benny Prijonofa73e3e2006-01-05 23:35:46 +00001382 if (status != 0)
1383 return status;
1384
Benny Prijono85598d92006-01-07 18:44:25 +00001385 /* TEST2_BRANCH_ID: Resolve error test. */
1386 status = tsx_resolve_error_test();
Benny Prijonofa73e3e2006-01-05 23:35:46 +00001387 if (status != 0)
1388 return status;
1389
Benny Prijono85598d92006-01-07 18:44:25 +00001390 /* TEST3_BRANCH_ID: UAC terminate while resolving test. */
1391 status = tsx_terminate_resolving_test();
1392 if (status != 0)
1393 return status;
1394
Benny Prijonoe93e2872006-06-28 16:46:49 +00001395 /* TEST4_BRANCH_ID: Transport failed after several retransmissions.
1396 * Only applies to loop transport.
1397 */
1398 if (test_param->type == PJSIP_TRANSPORT_LOOP_DGRAM) {
1399 status = tsx_retransmit_fail_test();
1400 if (status != 0)
1401 return status;
1402 }
Benny Prijono85598d92006-01-07 18:44:25 +00001403
Benny Prijonoe93e2872006-06-28 16:46:49 +00001404 /* TEST5_BRANCH_ID: Terminate transaction after several retransmissions
1405 * Only applicable to non-reliable transports.
1406 */
1407 if ((tp_flag & PJSIP_TRANSPORT_RELIABLE) == 0) {
1408 status = tsx_terminate_after_retransmit_test();
1409 if (status != 0)
1410 return status;
1411 }
Benny Prijono85598d92006-01-07 18:44:25 +00001412
1413 /* TEST6_BRANCH_ID: Successfull non-invite transaction */
Benny Prijonoe8a2ff52006-01-07 23:36:57 +00001414 status = perform_generic_test("test6: successfull non-invite transaction",
Benny Prijono9c1d9f52006-01-07 23:01:56 +00001415 TEST6_BRANCH_ID, &pjsip_options_method);
1416 if (status != 0)
1417 return status;
1418
1419 /* TEST7_BRANCH_ID: Successfull non-invite transaction */
Benny Prijonoe8a2ff52006-01-07 23:36:57 +00001420 status = perform_generic_test("test7: successfull non-invite transaction "
Benny Prijono9c1d9f52006-01-07 23:01:56 +00001421 "with provisional response",
1422 TEST7_BRANCH_ID, &pjsip_options_method);
1423 if (status != 0)
1424 return status;
1425
1426 /* TEST8_BRANCH_ID: Failed invite transaction */
Benny Prijonoe8a2ff52006-01-07 23:36:57 +00001427 status = perform_generic_test("test8: failed invite transaction",
Benny Prijono9c1d9f52006-01-07 23:01:56 +00001428 TEST8_BRANCH_ID, &pjsip_invite_method);
1429 if (status != 0)
1430 return status;
1431
1432 /* TEST9_BRANCH_ID: Failed invite transaction with provisional response */
Benny Prijonoe8a2ff52006-01-07 23:36:57 +00001433 status = perform_generic_test("test9: failed invite transaction with "
Benny Prijono9c1d9f52006-01-07 23:01:56 +00001434 "provisional response",
1435 TEST9_BRANCH_ID, &pjsip_invite_method);
Benny Prijono85598d92006-01-07 18:44:25 +00001436 if (status != 0)
1437 return status;
1438
Benny Prijono85598d92006-01-07 18:44:25 +00001439 pjsip_transport_dec_ref(loop);
Benny Prijonoe93e2872006-06-28 16:46:49 +00001440 flush_events(500);
1441
1442 /* Unregister modules. */
1443 status = pjsip_endpt_unregister_module(endpt, &tsx_user);
1444 if (status != PJ_SUCCESS) {
1445 app_perror(" Error: unable to unregister module", status);
1446 return -31;
1447 }
1448 status = pjsip_endpt_unregister_module(endpt, &msg_receiver);
1449 if (status != PJ_SUCCESS) {
1450 app_perror(" Error: unable to unregister module", status);
1451 return -41;
1452 }
1453
Benny Prijonofa73e3e2006-01-05 23:35:46 +00001454 return 0;
1455}
Benny Prijono85598d92006-01-07 18:44:25 +00001456