blob: 682082e4875f1a41bf0bb98de31355e50f0f9f9c [file] [log] [blame]
Benny Prijonofa73e3e2006-01-05 23:35:46 +00001/* $Id$ */
2/*
Benny Prijono32177c02008-06-20 22:44:47 +00003 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
Benny Prijonofa73e3e2006-01-05 23:35:46 +00004 *
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
20#include "test.h"
Benny Prijono40f2f642006-01-30 18:40:05 +000021#include <pjsip.h>
Benny Prijonofa73e3e2006-01-05 23:35:46 +000022#include <pjlib.h>
23
Benny Prijono85598d92006-01-07 18:44:25 +000024#define THIS_FILE "tsx_uac_test.c"
25
26
Benny Prijonofa73e3e2006-01-05 23:35:46 +000027/*****************************************************************************
28 **
Benny Prijono85598d92006-01-07 18:44:25 +000029 ** UAC tests.
Benny Prijonofa73e3e2006-01-05 23:35:46 +000030 **
Benny Prijono85598d92006-01-07 18:44:25 +000031 ** This file performs various tests for UAC transactions. Each test will have
32 ** a different Via branch param so that message receiver module and
33 ** transaction user module can identify which test is being carried out.
Benny Prijonofa73e3e2006-01-05 23:35:46 +000034 **
Benny Prijono85598d92006-01-07 18:44:25 +000035 ** TEST1_BRANCH_ID
36 ** Perform basic retransmission and timeout test. Message receiver will
37 ** verify that retransmission is received at correct time.
38 ** This test verifies the following requirements:
39 ** - retransmit timer doubles for INVITE
40 ** - retransmit timer doubles and caps off for non-INVITE
41 ** - retransmit timer timer is precise
42 ** - correct timeout and retransmission count
43 ** Requirements not tested:
44 ** - retransmit timer only starts after resolving has completed.
45 **
46 ** TEST2_BRANCH_ID
47 ** Test scenario where resolver is unable to resolve destination host.
48 **
49 ** TEST3_BRANCH_ID
50 ** Test scenario where transaction is terminated while resolver is still
51 ** running.
52 **
53 ** TEST4_BRANCH_ID
54 ** Test scenario where transport failed after several retransmissions.
55 **
56 ** TEST5_BRANCH_ID
57 ** Test scenario where transaction is terminated by user after several
58 ** retransmissions.
59 **
60 ** TEST6_BRANCH_ID
61 ** Test successfull non-INVITE transaction.
62 ** It tests the following requirements:
63 ** - transaction correctly moves to COMPLETED state.
64 ** - retransmission must cease.
65 ** - tx_data must be maintained until state is terminated.
66 **
67 ** TEST7_BRANCH_ID
68 ** Test successfull non-INVITE transaction, with provisional response.
69 **
70 ** TEST8_BRANCH_ID
71 ** Test failed INVITE transaction (e.g. ACK must be received)
72 **
73 ** TEST9_BRANCH_ID
74 ** Test failed INVITE transaction with provisional response.
75 **
76 **
Benny Prijonofa73e3e2006-01-05 23:35:46 +000077 *****************************************************************************
78 */
79
Benny Prijonodbe337a2006-01-08 23:57:52 +000080static char *TEST1_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAC-Test1";
81static char *TEST2_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAC-Test2";
82static char *TEST3_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAC-Test3";
83static char *TEST4_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAC-Test4";
84static char *TEST5_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAC-Test5";
85static char *TEST6_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAC-Test6";
86static char *TEST7_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAC-Test7";
87static char *TEST8_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAC-Test8";
88static char *TEST9_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAC-Test9";
Benny Prijono85598d92006-01-07 18:44:25 +000089
90#define TEST1_ALLOWED_DIFF (150)
91#define TEST4_RETRANSMIT_CNT 3
92#define TEST5_RETRANSMIT_CNT 3
93
Benny Prijonoe93e2872006-06-28 16:46:49 +000094static char TARGET_URI[128];
95static char FROM_URI[128];
96static unsigned tp_flag;
97static struct tsx_test_param *test_param;
Benny Prijono85598d92006-01-07 18:44:25 +000098
Benny Prijonofa73e3e2006-01-05 23:35:46 +000099static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e);
100static pj_bool_t msg_receiver_on_rx_request(pjsip_rx_data *rdata);
101
102/* UAC transaction user module. */
103static pjsip_module tsx_user =
104{
105 NULL, NULL, /* prev and next */
Benny Prijonodbe337a2006-01-08 23:57:52 +0000106 { "Tsx-UAC-User", 12}, /* Name. */
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000107 -1, /* Id */
108 PJSIP_MOD_PRIORITY_APPLICATION-1, /* Priority */
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000109 NULL, /* load() */
110 NULL, /* start() */
111 NULL, /* stop() */
112 NULL, /* unload() */
113 NULL, /* on_rx_request() */
114 NULL, /* on_rx_response() */
Benny Prijono85598d92006-01-07 18:44:25 +0000115 NULL, /* on_tx_request() */
116 NULL, /* on_tx_response() */
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000117 &tsx_user_on_tsx_state, /* on_tsx_state() */
118};
119
120/* Module to receive the loop-backed request. */
121static pjsip_module msg_receiver =
122{
123 NULL, NULL, /* prev and next */
Benny Prijonodbe337a2006-01-08 23:57:52 +0000124 { "Msg-Receiver", 12}, /* Name. */
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000125 -1, /* Id */
126 PJSIP_MOD_PRIORITY_APPLICATION-1, /* Priority */
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000127 NULL, /* load() */
128 NULL, /* start() */
129 NULL, /* stop() */
130 NULL, /* unload() */
131 &msg_receiver_on_rx_request, /* on_rx_request() */
132 NULL, /* on_rx_response() */
Benny Prijono85598d92006-01-07 18:44:25 +0000133 NULL, /* on_tx_request() */
134 NULL, /* on_tx_response() */
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000135 NULL, /* on_tsx_state() */
136};
137
Benny Prijono85598d92006-01-07 18:44:25 +0000138/* Static vars, which will be reset on each test. */
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000139static int recv_count;
140static pj_time_val recv_last;
141static pj_bool_t test_complete;
142
Benny Prijono85598d92006-01-07 18:44:25 +0000143/* Loop transport instance. */
144static pjsip_transport *loop;
145
Benny Prijono9c1d9f52006-01-07 23:01:56 +0000146/* General timer entry to be used by tests. */
Benny Prijonoe93e2872006-06-28 16:46:49 +0000147static struct my_timer
148{
149 pj_timer_entry entry;
150 char key_buf[1024];
151 pj_str_t tsx_key;
152} timer;
Benny Prijono9c1d9f52006-01-07 23:01:56 +0000153
Benny Prijono85598d92006-01-07 18:44:25 +0000154/*
155 * This is the handler to receive state changed notification from the
156 * transaction. It is used to verify that the transaction behaves according
157 * to the test scenario.
158 */
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000159static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e)
160{
Benny Prijono85598d92006-01-07 18:44:25 +0000161 if (pj_strcmp2(&tsx->branch, TEST1_BRANCH_ID)==0) {
162 /*
163 * Transaction with TEST1_BRANCH_ID should terminate with transaction
164 * timeout status.
165 */
166 if (tsx->state == PJSIP_TSX_STATE_TERMINATED) {
167
168 if (test_complete == 0)
169 test_complete = 1;
170
171 /* Test the status code. */
172 if (tsx->status_code != PJSIP_SC_TSX_TIMEOUT) {
173 PJ_LOG(3,(THIS_FILE,
174 " error: status code is %d instead of %d",
175 tsx->status_code, PJSIP_SC_TSX_TIMEOUT));
176 test_complete = -710;
177 }
Benny Prijonoe93e2872006-06-28 16:46:49 +0000178
179
180 /* If transport is reliable, then there must not be any
181 * retransmissions.
182 */
183 if (tp_flag & PJSIP_TRANSPORT_RELIABLE) {
184 if (recv_count != 1) {
185 PJ_LOG(3,(THIS_FILE,
186 " error: there were %d (re)transmissions",
187 recv_count));
188 test_complete = -715;
189 }
190 } else {
191 /* Check the number of transmissions, which must be
192 * 6 for INVITE and 10 for non-INVITE
193 */
194 if (tsx->method.id==PJSIP_INVITE_METHOD && recv_count != 7) {
195 PJ_LOG(3,(THIS_FILE,
196 " error: there were %d (re)transmissions",
197 recv_count));
198 test_complete = -716;
199 } else
200 if (tsx->method.id==PJSIP_OPTIONS_METHOD && recv_count != 11) {
201 PJ_LOG(3,(THIS_FILE,
202 " error: there were %d (re)transmissions",
203 recv_count));
204 test_complete = -717;
205 } else
206 if (tsx->method.id!=PJSIP_INVITE_METHOD &&
207 tsx->method.id!=PJSIP_OPTIONS_METHOD)
208 {
209 PJ_LOG(3,(THIS_FILE, " error: unexpected method"));
210 test_complete = -718;
211 }
212 }
Benny Prijono85598d92006-01-07 18:44:25 +0000213 }
214
215 } else if (pj_strcmp2(&tsx->branch, TEST2_BRANCH_ID)==0) {
216 /*
217 * Transaction with TEST2_BRANCH_ID should terminate with transport error.
218 */
219 if (tsx->state == PJSIP_TSX_STATE_TERMINATED) {
220
221 /* Test the status code. */
222 if (tsx->status_code != PJSIP_SC_TSX_TRANSPORT_ERROR) {
223 PJ_LOG(3,(THIS_FILE,
224 " error: status code is %d instead of %d",
225 tsx->status_code, PJSIP_SC_TSX_TRANSPORT_ERROR));
226 test_complete = -720;
227 }
228
229 if (test_complete == 0)
230 test_complete = 1;
231 }
232
233 } else if (pj_strcmp2(&tsx->branch, TEST3_BRANCH_ID)==0) {
234 /*
235 * This test terminates the transaction while resolver is still
236 * running.
237 */
238 if (tsx->state == PJSIP_TSX_STATE_CALLING) {
239
240 /* Terminate the transaction. */
241 pjsip_tsx_terminate(tsx, PJSIP_SC_REQUEST_TERMINATED);
242
243 } else if (tsx->state == PJSIP_TSX_STATE_TERMINATED) {
244
245 /* Check if status code is correct. */
246 if (tsx->status_code != PJSIP_SC_REQUEST_TERMINATED) {
247 PJ_LOG(3,(THIS_FILE,
248 " error: status code is %d instead of %d",
249 tsx->status_code, PJSIP_SC_REQUEST_TERMINATED));
250 test_complete = -730;
251 }
252
253 if (test_complete == 0)
254 test_complete = 1;
255
256 }
257
258 } else if (pj_strcmp2(&tsx->branch, TEST4_BRANCH_ID)==0) {
259 /*
260 * This test simulates transport failure after several
261 * retransmissions.
262 */
263 if (tsx->state == PJSIP_TSX_STATE_TERMINATED) {
264
265 /* Status code must be transport error. */
266 if (tsx->status_code != PJSIP_SC_TSX_TRANSPORT_ERROR) {
267 PJ_LOG(3,(THIS_FILE,
268 " error: status code is %d instead of %d",
269 tsx->status_code, PJSIP_SC_TSX_TRANSPORT_ERROR));
270 test_complete = -730;
271 }
272
273 /* Must have correct retransmission count. */
274 if (tsx->retransmit_count != TEST4_RETRANSMIT_CNT) {
275 PJ_LOG(3,(THIS_FILE,
276 " error: retransmit cnt is %d instead of %d",
277 tsx->retransmit_count, TEST4_RETRANSMIT_CNT));
278 test_complete = -731;
279 }
280
281 if (test_complete == 0)
282 test_complete = 1;
283 }
284
285
286 } else if (pj_strcmp2(&tsx->branch, TEST5_BRANCH_ID)==0) {
287 /*
288 * This test simulates transport failure after several
289 * retransmissions.
290 */
291 if (tsx->state == PJSIP_TSX_STATE_TERMINATED) {
292
293 /* Status code must be PJSIP_SC_REQUEST_TERMINATED. */
294 if (tsx->status_code != PJSIP_SC_REQUEST_TERMINATED) {
295 PJ_LOG(3,(THIS_FILE,
296 " error: status code is %d instead of %d",
297 tsx->status_code, PJSIP_SC_REQUEST_TERMINATED));
298 test_complete = -733;
299 }
300
301 /* Must have correct retransmission count. */
302 if (tsx->retransmit_count != TEST5_RETRANSMIT_CNT) {
303 PJ_LOG(3,(THIS_FILE,
304 " error: retransmit cnt is %d instead of %d",
305 tsx->retransmit_count, TEST5_RETRANSMIT_CNT));
306 test_complete = -734;
307 }
308
309 if (test_complete == 0)
310 test_complete = 1;
311 }
312
313
314 } else if (pj_strcmp2(&tsx->branch, TEST6_BRANCH_ID)==0) {
315 /*
316 * Successfull non-INVITE transaction.
317 */
318 if (tsx->state == PJSIP_TSX_STATE_COMPLETED) {
319
320 /* Status code must be 202. */
321 if (tsx->status_code != 202) {
322 PJ_LOG(3,(THIS_FILE,
323 " error: status code is %d instead of %d",
324 tsx->status_code, 202));
325 test_complete = -736;
326 }
327
328 /* Must have correct retransmission count. */
329 if (tsx->retransmit_count != 0) {
330 PJ_LOG(3,(THIS_FILE,
331 " error: retransmit cnt is %d instead of %d",
332 tsx->retransmit_count, 0));
333 test_complete = -737;
334 }
335
336 /* Must still keep last_tx */
337 if (tsx->last_tx == NULL) {
338 PJ_LOG(3,(THIS_FILE,
339 " error: transaction lost last_tx"));
340 test_complete = -738;
341 }
342
343 if (test_complete == 0) {
344 test_complete = 1;
345 pjsip_tsx_terminate(tsx, 202);
346 }
Benny Prijono9c1d9f52006-01-07 23:01:56 +0000347
348 } else if (tsx->state == PJSIP_TSX_STATE_TERMINATED) {
349
350 /* Previous state must be COMPLETED. */
351 if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_COMPLETED) {
352 test_complete = -7381;
353 }
354
Benny Prijono85598d92006-01-07 18:44:25 +0000355 }
Benny Prijono9c1d9f52006-01-07 23:01:56 +0000356
357 } else if (pj_strcmp2(&tsx->branch, TEST7_BRANCH_ID)==0) {
358 /*
359 * Successfull non-INVITE transaction.
360 */
361 if (tsx->state == PJSIP_TSX_STATE_COMPLETED) {
362
363 /* Check prev state. */
364 if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_PROCEEDING) {
365 PJ_LOG(3,(THIS_FILE,
366 " error: prev state is %s instead of %s",
Benny Prijonoa1e69682007-05-11 15:14:34 +0000367 pjsip_tsx_state_str((pjsip_tsx_state_e)e->body.tsx_state.prev_state),
Benny Prijono9c1d9f52006-01-07 23:01:56 +0000368 pjsip_tsx_state_str(PJSIP_TSX_STATE_PROCEEDING)));
369 test_complete = -739;
370 }
371
372 /* Status code must be 202. */
373 if (tsx->status_code != 202) {
374 PJ_LOG(3,(THIS_FILE,
375 " error: status code is %d instead of %d",
376 tsx->status_code, 202));
377 test_complete = -740;
378 }
379
380 /* Must have correct retransmission count. */
381 if (tsx->retransmit_count != 0) {
382 PJ_LOG(3,(THIS_FILE,
383 " error: retransmit cnt is %d instead of %d",
384 tsx->retransmit_count, 0));
385 test_complete = -741;
386 }
387
388 /* Must still keep last_tx */
389 if (tsx->last_tx == NULL) {
390 PJ_LOG(3,(THIS_FILE,
391 " error: transaction lost last_tx"));
392 test_complete = -741;
393 }
394
395 if (test_complete == 0) {
396 test_complete = 1;
397 pjsip_tsx_terminate(tsx, 202);
398 }
399
400 } else if (tsx->state == PJSIP_TSX_STATE_TERMINATED) {
401
402 /* Previous state must be COMPLETED. */
403 if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_COMPLETED) {
404 test_complete = -742;
405 }
406
407 }
408
409
410 } else if (pj_strcmp2(&tsx->branch, TEST8_BRANCH_ID)==0) {
411 /*
412 * Failed INVITE transaction.
413 */
414 if (tsx->state == PJSIP_TSX_STATE_COMPLETED) {
415
416 /* Status code must be 301. */
417 if (tsx->status_code != 301) {
418 PJ_LOG(3,(THIS_FILE,
419 " error: status code is %d instead of %d",
420 tsx->status_code, 301));
421 test_complete = -745;
422 }
423
424 /* Must have correct retransmission count. */
425 if (tsx->retransmit_count != 0) {
426 PJ_LOG(3,(THIS_FILE,
427 " error: retransmit cnt is %d instead of %d",
428 tsx->retransmit_count, 0));
429 test_complete = -746;
430 }
431
432 /* Must still keep last_tx */
433 if (tsx->last_tx == NULL) {
434 PJ_LOG(3,(THIS_FILE,
435 " error: transaction lost last_tx"));
436 test_complete = -747;
437 }
438
Benny Prijono728a9052006-01-18 23:34:15 +0000439 /* last_tx MUST be the INVITE request
440 * (authorization depends on this behavior)
441 */
Benny Prijono9c1d9f52006-01-07 23:01:56 +0000442 if (tsx->last_tx && tsx->last_tx->msg->line.req.method.id !=
Benny Prijono728a9052006-01-18 23:34:15 +0000443 PJSIP_INVITE_METHOD)
Benny Prijono9c1d9f52006-01-07 23:01:56 +0000444 {
445 PJ_LOG(3,(THIS_FILE,
Benny Prijono728a9052006-01-18 23:34:15 +0000446 " error: last_tx is not INVITE"));
Benny Prijono9c1d9f52006-01-07 23:01:56 +0000447 test_complete = -748;
448 }
449 }
450 else if (tsx->state == PJSIP_TSX_STATE_TERMINATED) {
451
452 test_complete = 1;
453
454 /* Previous state must be COMPLETED. */
455 if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_COMPLETED) {
456 test_complete = -750;
457 }
458
459 /* Status code must be 301. */
460 if (tsx->status_code != 301) {
461 PJ_LOG(3,(THIS_FILE,
462 " error: status code is %d instead of %d",
463 tsx->status_code, 301));
464 test_complete = -751;
465 }
466
467 }
468
469
470 } else if (pj_strcmp2(&tsx->branch, TEST9_BRANCH_ID)==0) {
471 /*
472 * Failed INVITE transaction with provisional response.
473 */
474 if (tsx->state == PJSIP_TSX_STATE_COMPLETED) {
475
476 /* Previous state must be PJSIP_TSX_STATE_PROCEEDING. */
477 if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_PROCEEDING) {
478 test_complete = -760;
479 }
480
481 /* Status code must be 302. */
482 if (tsx->status_code != 302) {
483 PJ_LOG(3,(THIS_FILE,
484 " error: status code is %d instead of %d",
485 tsx->status_code, 302));
486 test_complete = -761;
487 }
488
489 /* Must have correct retransmission count. */
490 if (tsx->retransmit_count != 0) {
491 PJ_LOG(3,(THIS_FILE,
492 " error: retransmit cnt is %d instead of %d",
493 tsx->retransmit_count, 0));
494 test_complete = -762;
495 }
496
497 /* Must still keep last_tx */
498 if (tsx->last_tx == NULL) {
499 PJ_LOG(3,(THIS_FILE,
500 " error: transaction lost last_tx"));
501 test_complete = -763;
502 }
503
Benny Prijono728a9052006-01-18 23:34:15 +0000504 /* last_tx MUST be INVITE.
505 * (authorization depends on this behavior)
506 */
Benny Prijono9c1d9f52006-01-07 23:01:56 +0000507 if (tsx->last_tx && tsx->last_tx->msg->line.req.method.id !=
Benny Prijono728a9052006-01-18 23:34:15 +0000508 PJSIP_INVITE_METHOD)
Benny Prijono9c1d9f52006-01-07 23:01:56 +0000509 {
510 PJ_LOG(3,(THIS_FILE,
Benny Prijono728a9052006-01-18 23:34:15 +0000511 " error: last_tx is not INVITE"));
Benny Prijono9c1d9f52006-01-07 23:01:56 +0000512 test_complete = -764;
513 }
514
515 }
516 else if (tsx->state == PJSIP_TSX_STATE_TERMINATED) {
517
518 test_complete = 1;
519
520 /* Previous state must be COMPLETED. */
521 if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_COMPLETED) {
522 test_complete = -767;
523 }
524
525 /* Status code must be 302. */
526 if (tsx->status_code != 302) {
527 PJ_LOG(3,(THIS_FILE,
528 " error: status code is %d instead of %d",
529 tsx->status_code, 302));
530 test_complete = -768;
531 }
532
533 }
534
Benny Prijono85598d92006-01-07 18:44:25 +0000535 }
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000536}
537
Benny Prijono9c1d9f52006-01-07 23:01:56 +0000538/*
539 * This timer callback is called to send delayed response.
540 */
541struct response
542{
543 pjsip_response_addr res_addr;
544 pjsip_tx_data *tdata;
545};
546
547static void send_response_callback( pj_timer_heap_t *timer_heap,
548 struct pj_timer_entry *entry)
549{
Benny Prijonoa1e69682007-05-11 15:14:34 +0000550 struct response *r = (struct response*) entry->user_data;
Benny Prijono9c1d9f52006-01-07 23:01:56 +0000551 pjsip_transport *tp = r->res_addr.transport;
552
553 pjsip_endpt_send_response(endpt, &r->res_addr, r->tdata, NULL, NULL);
554 if (tp)
555 pjsip_transport_dec_ref(tp);
556}
557
558/* Timer callback to terminate a transaction. */
559static void terminate_tsx_callback( pj_timer_heap_t *timer_heap,
560 struct pj_timer_entry *entry)
561{
Benny Prijonoe93e2872006-06-28 16:46:49 +0000562 struct my_timer *m = (struct my_timer *)entry;
563 pjsip_transaction *tsx = pjsip_tsx_layer_find_tsx(&m->tsx_key, PJ_FALSE);
Benny Prijono9c1d9f52006-01-07 23:01:56 +0000564 int status_code = entry->id;
565
566 if (tsx) {
567 pjsip_tsx_terminate(tsx, status_code);
568 }
569}
570
571
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000572#define DIFF(a,b) ((a<b) ? (b-a) : (a-b))
573
Benny Prijono85598d92006-01-07 18:44:25 +0000574/*
575 * This is the handler to receive message for this test. It is used to
576 * control and verify the behavior of the message transmitted by the
577 * transaction.
578 */
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000579static pj_bool_t msg_receiver_on_rx_request(pjsip_rx_data *rdata)
580{
Benny Prijono85598d92006-01-07 18:44:25 +0000581 if (pj_strcmp2(&rdata->msg_info.via->branch_param, TEST1_BRANCH_ID) == 0) {
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000582 /*
Benny Prijono85598d92006-01-07 18:44:25 +0000583 * The TEST1_BRANCH_ID test performs the verifications for transaction
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000584 * retransmission mechanism. It will not answer the incoming request
585 * with any response.
586 */
587 pjsip_msg *msg = rdata->msg_info.msg;
588
Benny Prijono85598d92006-01-07 18:44:25 +0000589 PJ_LOG(4,(THIS_FILE, " received request"));
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000590
591 /* Only wants to take INVITE or OPTIONS method. */
592 if (msg->line.req.method.id != PJSIP_INVITE_METHOD &&
593 msg->line.req.method.id != PJSIP_OPTIONS_METHOD)
594 {
Benny Prijono85598d92006-01-07 18:44:25 +0000595 PJ_LOG(3,(THIS_FILE, " error: received unexpected method %.*s",
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000596 msg->line.req.method.name.slen,
597 msg->line.req.method.name.ptr));
598 test_complete = -600;
599 return PJ_TRUE;
600 }
601
602 if (recv_count == 0) {
603 recv_count++;
Benny Prijono85598d92006-01-07 18:44:25 +0000604 //pj_gettimeofday(&recv_last);
605 recv_last = rdata->pkt_info.timestamp;
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000606 } else {
607 pj_time_val now;
608 unsigned msec_expected, msec_elapsed;
Benny Prijono85598d92006-01-07 18:44:25 +0000609 int max_received;
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000610
Benny Prijono85598d92006-01-07 18:44:25 +0000611 //pj_gettimeofday(&now);
612 now = rdata->pkt_info.timestamp;
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000613 PJ_TIME_VAL_SUB(now, recv_last);
614 msec_elapsed = now.sec*1000 + now.msec;
615
616 ++recv_count;
Benny Prijono4768c3c2008-02-22 11:10:17 +0000617 msec_expected = (1<<(recv_count-2))*pjsip_cfg()->tsx.t1;
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000618
619 if (msg->line.req.method.id != PJSIP_INVITE_METHOD) {
Benny Prijono4768c3c2008-02-22 11:10:17 +0000620 if (msec_expected > pjsip_cfg()->tsx.t2)
621 msec_expected = pjsip_cfg()->tsx.t2;
Benny Prijono85598d92006-01-07 18:44:25 +0000622 max_received = 11;
623 } else {
624 max_received = 7;
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000625 }
626
Benny Prijono85598d92006-01-07 18:44:25 +0000627 if (DIFF(msec_expected, msec_elapsed) > TEST1_ALLOWED_DIFF) {
628 PJ_LOG(3,(THIS_FILE,
629 " error: expecting retransmission no. %d in %d "
630 "ms, received in %d ms",
631 recv_count-1, msec_expected, msec_elapsed));
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000632 test_complete = -610;
633 }
634
Benny Prijono85598d92006-01-07 18:44:25 +0000635
636 if (recv_count > max_received) {
637 PJ_LOG(3,(THIS_FILE,
638 " error: too many messages (%d) received",
639 recv_count));
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000640 test_complete = -620;
641 }
642
Benny Prijono85598d92006-01-07 18:44:25 +0000643 //pj_gettimeofday(&recv_last);
644 recv_last = rdata->pkt_info.timestamp;
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000645 }
646 return PJ_TRUE;
Benny Prijono85598d92006-01-07 18:44:25 +0000647
648 } else
649 if (pj_strcmp2(&rdata->msg_info.via->branch_param, TEST4_BRANCH_ID) == 0) {
650 /*
651 * The TEST4_BRANCH_ID test simulates transport failure after several
652 * retransmissions.
653 */
654 recv_count++;
655
656 if (recv_count == TEST4_RETRANSMIT_CNT) {
657 /* Simulate transport failure. */
658 pjsip_loop_set_failure(loop, 2, NULL);
659
660 } else if (recv_count > TEST4_RETRANSMIT_CNT) {
661 PJ_LOG(3,(THIS_FILE," error: not expecting %d-th packet!",
662 recv_count));
663 test_complete = -631;
664 }
665
666 return PJ_TRUE;
667
668
669 } else
670 if (pj_strcmp2(&rdata->msg_info.via->branch_param, TEST5_BRANCH_ID) == 0) {
671 /*
672 * The TEST5_BRANCH_ID test simulates user terminating the transaction
673 * after several retransmissions.
674 */
675 recv_count++;
676
677 if (recv_count == TEST5_RETRANSMIT_CNT+1) {
678 pj_str_t key;
679 pjsip_transaction *tsx;
680
681 pjsip_tsx_create_key( rdata->tp_info.pool, &key, PJSIP_ROLE_UAC,
682 &rdata->msg_info.msg->line.req.method, rdata);
683 tsx = pjsip_tsx_layer_find_tsx(&key, PJ_TRUE);
684 if (tsx) {
685 pjsip_tsx_terminate(tsx, PJSIP_SC_REQUEST_TERMINATED);
686 pj_mutex_unlock(tsx->mutex);
687 } else {
688 PJ_LOG(3,(THIS_FILE, " error: uac transaction not found!"));
689 test_complete = -633;
690 }
691
692 } else if (recv_count > TEST5_RETRANSMIT_CNT+1) {
693 PJ_LOG(3,(THIS_FILE," error: not expecting %d-th packet!",
694 recv_count));
695 test_complete = -634;
696 }
697
698 return PJ_TRUE;
699
700 } else
701 if (pj_strcmp2(&rdata->msg_info.via->branch_param, TEST6_BRANCH_ID) == 0) {
702 /*
Benny Prijono9c1d9f52006-01-07 23:01:56 +0000703 * The TEST6_BRANCH_ID test successfull non-INVITE transaction.
Benny Prijono85598d92006-01-07 18:44:25 +0000704 */
Benny Prijono85598d92006-01-07 18:44:25 +0000705 pj_status_t status;
706
707 recv_count++;
708
709 if (recv_count > 1) {
710 PJ_LOG(3,(THIS_FILE," error: not expecting %d-th packet!",
711 recv_count));
712 test_complete = -635;
713 }
714
Benny Prijono9c1d9f52006-01-07 23:01:56 +0000715 status = pjsip_endpt_respond_stateless(endpt, rdata, 202, NULL,
716 NULL, NULL);
Benny Prijono85598d92006-01-07 18:44:25 +0000717 if (status != PJ_SUCCESS) {
Benny Prijono9c1d9f52006-01-07 23:01:56 +0000718 app_perror(" error: unable to send response", status);
Benny Prijono85598d92006-01-07 18:44:25 +0000719 test_complete = -636;
720 }
721
Benny Prijono9c1d9f52006-01-07 23:01:56 +0000722 return PJ_TRUE;
723
724
725 } else
726 if (pj_strcmp2(&rdata->msg_info.via->branch_param, TEST7_BRANCH_ID) == 0) {
727 /*
728 * The TEST7_BRANCH_ID test successfull non-INVITE transaction
729 * with provisional response.
730 */
731 pj_status_t status;
732 pjsip_response_addr res_addr;
733 struct response *r;
734 pjsip_tx_data *tdata;
735 pj_time_val delay = { 2, 0 };
736
737 recv_count++;
738
739 if (recv_count > 1) {
740 PJ_LOG(3,(THIS_FILE," error: not expecting %d-th packet!",
741 recv_count));
742 test_complete = -640;
743 return PJ_TRUE;
Benny Prijono85598d92006-01-07 18:44:25 +0000744 }
745
Benny Prijono9c1d9f52006-01-07 23:01:56 +0000746 /* Respond with provisional response */
747 status = pjsip_endpt_create_response(endpt, rdata, 100, NULL, &tdata);
748 pj_assert(status == PJ_SUCCESS);
749
750 status = pjsip_get_response_addr(tdata->pool, rdata, &res_addr);
751 pj_assert(status == PJ_SUCCESS);
752
753 status = pjsip_endpt_send_response(endpt, &res_addr, tdata,
754 NULL, NULL);
755 pj_assert(status == PJ_SUCCESS);
756
757 /* Create the final response. */
758 status = pjsip_endpt_create_response(endpt, rdata, 202, NULL, &tdata);
759 pj_assert(status == PJ_SUCCESS);
760
761 /* Schedule sending final response in couple of of secs. */
Benny Prijonoa1e69682007-05-11 15:14:34 +0000762 r = PJ_POOL_ALLOC_T(tdata->pool, struct response);
Benny Prijono9c1d9f52006-01-07 23:01:56 +0000763 r->res_addr = res_addr;
764 r->tdata = tdata;
765 if (r->res_addr.transport)
766 pjsip_transport_add_ref(r->res_addr.transport);
767
Benny Prijonoe93e2872006-06-28 16:46:49 +0000768 timer.entry.cb = &send_response_callback;
769 timer.entry.user_data = r;
770 pjsip_endpt_schedule_timer(endpt, &timer.entry, &delay);
Benny Prijono9c1d9f52006-01-07 23:01:56 +0000771
772 return PJ_TRUE;
773
774
775 } else
776 if (pj_strcmp2(&rdata->msg_info.via->branch_param, TEST8_BRANCH_ID) == 0) {
777 /*
778 * The TEST8_BRANCH_ID test failed INVITE transaction.
779 */
780 pjsip_method *method;
781 pj_status_t status;
782
783 method = &rdata->msg_info.msg->line.req.method;
784
785 recv_count++;
786
787 if (method->id == PJSIP_INVITE_METHOD) {
788
789 if (recv_count > 1) {
790 PJ_LOG(3,(THIS_FILE," error: not expecting %d-th packet!",
791 recv_count));
792 test_complete = -635;
793 }
794
795 status = pjsip_endpt_respond_stateless(endpt, rdata, 301, NULL,
796 NULL, NULL);
797 if (status != PJ_SUCCESS) {
798 app_perror(" error: unable to send response", status);
799 test_complete = -636;
800 }
801
802 } else if (method->id == PJSIP_ACK_METHOD) {
803
804 if (recv_count == 2) {
805 pj_str_t key;
806 pj_time_val delay = { 5, 0 };
807
808 /* Schedule timer to destroy transaction after 5 seconds.
809 * This is to make sure that transaction does not
810 * retransmit ACK.
811 */
812 pjsip_tsx_create_key(rdata->tp_info.pool, &key,
813 PJSIP_ROLE_UAC, &pjsip_invite_method,
814 rdata);
815
Benny Prijonoe93e2872006-06-28 16:46:49 +0000816 pj_strcpy(&timer.tsx_key, &key);
817 timer.entry.id = 301;
818 timer.entry.cb = &terminate_tsx_callback;
Benny Prijono9c1d9f52006-01-07 23:01:56 +0000819
Benny Prijonoe93e2872006-06-28 16:46:49 +0000820 pjsip_endpt_schedule_timer(endpt, &timer.entry, &delay);
Benny Prijono9c1d9f52006-01-07 23:01:56 +0000821 }
822
823 if (recv_count > 2) {
824 PJ_LOG(3,(THIS_FILE," error: not expecting %d-th packet!",
825 recv_count));
826 test_complete = -638;
827 }
828
829
830 } else {
831 PJ_LOG(3,(THIS_FILE," error: not expecting %s",
832 pjsip_rx_data_get_info(rdata)));
833 test_complete = -639;
834
835 }
836
837
838 } else
839 if (pj_strcmp2(&rdata->msg_info.via->branch_param, TEST9_BRANCH_ID) == 0) {
840 /*
841 * The TEST9_BRANCH_ID test failed INVITE transaction with
842 * provisional response.
843 */
844 pjsip_method *method;
845 pj_status_t status;
846
847 method = &rdata->msg_info.msg->line.req.method;
848
849 recv_count++;
850
851 if (method->id == PJSIP_INVITE_METHOD) {
852
853 pjsip_response_addr res_addr;
854 struct response *r;
855 pjsip_tx_data *tdata;
856 pj_time_val delay = { 2, 0 };
857
858 if (recv_count > 1) {
859 PJ_LOG(3,(THIS_FILE," error: not expecting %d-th packet!",
860 recv_count));
861 test_complete = -650;
862 return PJ_TRUE;
863 }
864
865 /* Respond with provisional response */
866 status = pjsip_endpt_create_response(endpt, rdata, 100, NULL,
867 &tdata);
868 pj_assert(status == PJ_SUCCESS);
869
870 status = pjsip_get_response_addr(tdata->pool, rdata, &res_addr);
871 pj_assert(status == PJ_SUCCESS);
872
873 status = pjsip_endpt_send_response(endpt, &res_addr, tdata,
874 NULL, NULL);
875 pj_assert(status == PJ_SUCCESS);
876
877 /* Create the final response. */
878 status = pjsip_endpt_create_response(endpt, rdata, 302, NULL,
879 &tdata);
880 pj_assert(status == PJ_SUCCESS);
881
882 /* Schedule sending final response in couple of of secs. */
Benny Prijonoa1e69682007-05-11 15:14:34 +0000883 r = PJ_POOL_ALLOC_T(tdata->pool, struct response);
Benny Prijono9c1d9f52006-01-07 23:01:56 +0000884 r->res_addr = res_addr;
885 r->tdata = tdata;
886 if (r->res_addr.transport)
887 pjsip_transport_add_ref(r->res_addr.transport);
888
Benny Prijonoe93e2872006-06-28 16:46:49 +0000889 timer.entry.cb = &send_response_callback;
890 timer.entry.user_data = r;
891 pjsip_endpt_schedule_timer(endpt, &timer.entry, &delay);
Benny Prijono9c1d9f52006-01-07 23:01:56 +0000892
893 } else if (method->id == PJSIP_ACK_METHOD) {
894
895 if (recv_count == 2) {
896 pj_str_t key;
897 pj_time_val delay = { 5, 0 };
898
899 /* Schedule timer to destroy transaction after 5 seconds.
900 * This is to make sure that transaction does not
901 * retransmit ACK.
902 */
903 pjsip_tsx_create_key(rdata->tp_info.pool, &key,
904 PJSIP_ROLE_UAC, &pjsip_invite_method,
905 rdata);
906
Benny Prijonoe93e2872006-06-28 16:46:49 +0000907 pj_strcpy(&timer.tsx_key, &key);
908 timer.entry.id = 302;
909 timer.entry.cb = &terminate_tsx_callback;
Benny Prijono9c1d9f52006-01-07 23:01:56 +0000910
Benny Prijonoe93e2872006-06-28 16:46:49 +0000911 pjsip_endpt_schedule_timer(endpt, &timer.entry, &delay);
Benny Prijono9c1d9f52006-01-07 23:01:56 +0000912 }
913
914 if (recv_count > 2) {
915 PJ_LOG(3,(THIS_FILE," error: not expecting %d-th packet!",
916 recv_count));
917 test_complete = -638;
918 }
919
920
921 } else {
922 PJ_LOG(3,(THIS_FILE," error: not expecting %s",
923 pjsip_rx_data_get_info(rdata)));
924 test_complete = -639;
925
Benny Prijono85598d92006-01-07 18:44:25 +0000926 }
927
928 return PJ_TRUE;
Benny Prijono9c1d9f52006-01-07 23:01:56 +0000929
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000930 }
Benny Prijono85598d92006-01-07 18:44:25 +0000931
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000932 return PJ_FALSE;
933}
934
Benny Prijono85598d92006-01-07 18:44:25 +0000935/*
936 * The generic test framework, used by most of the tests.
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000937 */
Benny Prijono85598d92006-01-07 18:44:25 +0000938static int perform_tsx_test(int dummy, char *target_uri, char *from_uri,
939 char *branch_param, int test_time,
940 const pjsip_method *method)
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000941{
942 pjsip_tx_data *tdata;
943 pjsip_transaction *tsx;
Benny Prijono85598d92006-01-07 18:44:25 +0000944 pj_str_t target, from, tsx_key;
945 pjsip_via_hdr *via;
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000946 pj_time_val timeout;
947 pj_status_t status;
948
Benny Prijono85598d92006-01-07 18:44:25 +0000949 PJ_LOG(3,(THIS_FILE,
950 " please standby, this will take at most %d seconds..",
951 test_time));
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000952
Benny Prijono85598d92006-01-07 18:44:25 +0000953 /* Reset test. */
954 recv_count = 0;
955 test_complete = 0;
956
957 /* Init headers. */
958 target = pj_str(target_uri);
959 from = pj_str(from_uri);
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000960
961 /* Create request. */
962 status = pjsip_endpt_create_request( endpt, method, &target,
Benny Prijono85598d92006-01-07 18:44:25 +0000963 &from, &target, NULL, NULL, -1,
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000964 NULL, &tdata);
965 if (status != PJ_SUCCESS) {
966 app_perror(" Error: unable to create request", status);
Benny Prijono85598d92006-01-07 18:44:25 +0000967 return -100;
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000968 }
969
Benny Prijono85598d92006-01-07 18:44:25 +0000970 /* Set the branch param for test 1. */
Benny Prijonoa1e69682007-05-11 15:14:34 +0000971 via = (pjsip_via_hdr*) pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL);
Benny Prijono85598d92006-01-07 18:44:25 +0000972 via->branch_param = pj_str(branch_param);
973
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000974 /* Add additional reference to tdata to prevent transaction from
975 * deleting it.
976 */
977 pjsip_tx_data_add_ref(tdata);
978
979 /* Create transaction. */
980 status = pjsip_tsx_create_uac( &tsx_user, tdata, &tsx);
981 if (status != PJ_SUCCESS) {
982 app_perror(" Error: unable to create UAC transaction", status);
Benny Prijono85598d92006-01-07 18:44:25 +0000983 pjsip_tx_data_dec_ref(tdata);
984 return -110;
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000985 }
986
987 /* Get transaction key. */
988 pj_strdup(tdata->pool, &tsx_key, &tsx->transaction_key);
989
990 /* Send the message. */
991 status = pjsip_tsx_send_msg(tsx, NULL);
Benny Prijono85598d92006-01-07 18:44:25 +0000992 // Ignore send result. Some tests do deliberately triggers error
993 // when sending message.
Benny Prijono02b8fd82006-06-26 15:12:55 +0000994 if (status != PJ_SUCCESS) {
995 // app_perror(" Error: unable to send request", status);
996 pjsip_tx_data_dec_ref(tdata);
997 // return -120;
998 }
Benny Prijono85598d92006-01-07 18:44:25 +0000999
Benny Prijonofa73e3e2006-01-05 23:35:46 +00001000
1001 /* Set test completion time. */
1002 pj_gettimeofday(&timeout);
Benny Prijono85598d92006-01-07 18:44:25 +00001003 timeout.sec += test_time;
Benny Prijonofa73e3e2006-01-05 23:35:46 +00001004
1005 /* Wait until test complete. */
1006 while (!test_complete) {
Benny Prijono85598d92006-01-07 18:44:25 +00001007 pj_time_val now, poll_delay = {0, 10};
Benny Prijonofa73e3e2006-01-05 23:35:46 +00001008
Benny Prijono85598d92006-01-07 18:44:25 +00001009 pjsip_endpt_handle_events(endpt, &poll_delay);
Benny Prijonofa73e3e2006-01-05 23:35:46 +00001010
1011 pj_gettimeofday(&now);
1012 if (now.sec > timeout.sec) {
Benny Prijono85598d92006-01-07 18:44:25 +00001013 PJ_LOG(3,(THIS_FILE, " Error: test has timed out"));
1014 pjsip_tx_data_dec_ref(tdata);
1015 return -130;
Benny Prijonofa73e3e2006-01-05 23:35:46 +00001016 }
1017 }
1018
Benny Prijono85598d92006-01-07 18:44:25 +00001019 if (test_complete < 0) {
1020 tsx = pjsip_tsx_layer_find_tsx(&tsx_key, PJ_TRUE);
1021 if (tsx) {
1022 pjsip_tsx_terminate(tsx, PJSIP_SC_REQUEST_TERMINATED);
1023 pj_mutex_unlock(tsx->mutex);
1024 flush_events(1000);
1025 }
1026 pjsip_tx_data_dec_ref(tdata);
1027 return test_complete;
Benny Prijono85598d92006-01-07 18:44:25 +00001028
Benny Prijonoe93e2872006-06-28 16:46:49 +00001029 } else {
1030 pj_time_val now;
1031
1032 /* Allow transaction to destroy itself */
1033 flush_events(500);
1034
1035 /* Wait until test completes */
1036 pj_gettimeofday(&now);
1037
1038 if (PJ_TIME_VAL_LT(now, timeout)) {
1039 pj_time_val interval;
1040 interval = timeout;
1041 PJ_TIME_VAL_SUB(interval, now);
1042 flush_events(PJ_TIME_VAL_MSEC(interval));
1043 }
1044 }
Benny Prijonofa73e3e2006-01-05 23:35:46 +00001045
1046 /* Make sure transaction has been destroyed. */
1047 if (pjsip_tsx_layer_find_tsx(&tsx_key, PJ_FALSE) != NULL) {
Benny Prijono85598d92006-01-07 18:44:25 +00001048 PJ_LOG(3,(THIS_FILE, " Error: transaction has not been destroyed"));
1049 pjsip_tx_data_dec_ref(tdata);
1050 return -140;
Benny Prijonofa73e3e2006-01-05 23:35:46 +00001051 }
1052
1053 /* Check tdata reference counter. */
1054 if (pj_atomic_get(tdata->ref_cnt) != 1) {
Benny Prijono85598d92006-01-07 18:44:25 +00001055 PJ_LOG(3,(THIS_FILE, " Error: tdata reference counter is %d",
Benny Prijonofa73e3e2006-01-05 23:35:46 +00001056 pj_atomic_get(tdata->ref_cnt)));
Benny Prijono85598d92006-01-07 18:44:25 +00001057 pjsip_tx_data_dec_ref(tdata);
1058 return -150;
Benny Prijonofa73e3e2006-01-05 23:35:46 +00001059 }
1060
1061 /* Destroy txdata */
1062 pjsip_tx_data_dec_ref(tdata);
1063
1064 return PJ_SUCCESS;
1065}
1066
1067/*****************************************************************************
1068 **
Benny Prijono85598d92006-01-07 18:44:25 +00001069 ** TEST1_BRANCH_ID: UAC basic retransmission and timeout test.
1070 **
1071 ** This will test the retransmission of the UAC transaction. Remote will not
1072 ** answer the transaction, so the transaction should fail. The Via branch prm
1073 ** TEST1_BRANCH_ID will be used for this test.
1074 **
1075 *****************************************************************************
1076 */
1077static int tsx_uac_retransmit_test(void)
1078{
1079 int status, enabled;
1080 int i;
1081 struct {
1082 const pjsip_method *method;
1083 unsigned delay;
1084 } sub_test[] =
1085 {
1086 { &pjsip_invite_method, 0},
1087 { &pjsip_invite_method, TEST1_ALLOWED_DIFF*2},
1088 { &pjsip_options_method, 0},
1089 { &pjsip_options_method, TEST1_ALLOWED_DIFF*2}
1090 };
1091
1092 PJ_LOG(3,(THIS_FILE, " test1: basic uac retransmit and timeout test"));
1093
1094
1095 /* For this test. message printing shound be disabled because it makes
1096 * incorrect timing.
1097 */
1098 enabled = msg_logger_set_enabled(0);
1099
Benny Prijonoa1e69682007-05-11 15:14:34 +00001100 for (i=0; i<(int)PJ_ARRAY_SIZE(sub_test); ++i) {
Benny Prijono85598d92006-01-07 18:44:25 +00001101
1102 PJ_LOG(3,(THIS_FILE,
1103 " variant %c: %s with %d ms network delay",
1104 ('a' + i),
1105 sub_test[i].method->name.ptr,
1106 sub_test[i].delay));
1107
1108 /* Configure transport */
1109 pjsip_loop_set_failure(loop, 0, NULL);
1110 pjsip_loop_set_recv_delay(loop, sub_test[i].delay, NULL);
1111
1112 /* Do the test. */
Benny Prijonoe93e2872006-06-28 16:46:49 +00001113 status = perform_tsx_test(-500, TARGET_URI, FROM_URI,
Benny Prijono85598d92006-01-07 18:44:25 +00001114 TEST1_BRANCH_ID,
1115 35, sub_test[i].method);
1116 if (status != 0)
1117 break;
1118 }
1119
1120 /* Restore transport. */
1121 pjsip_loop_set_recv_delay(loop, 0, NULL);
1122
1123 /* Restore msg logger. */
1124 msg_logger_set_enabled(enabled);
1125
1126 /* Done. */
1127 return status;
1128}
1129
1130/*****************************************************************************
1131 **
1132 ** TEST2_BRANCH_ID: UAC resolve error test.
1133 **
1134 ** Test the scenario where destination host is unresolvable. There are
1135 ** two variants:
1136 ** (a) resolver returns immediate error
1137 ** (b) resolver returns error via the callback.
1138 **
1139 *****************************************************************************
1140 */
1141static int tsx_resolve_error_test(void)
1142{
1143 int status;
1144
1145 PJ_LOG(3,(THIS_FILE, " test2: resolve error test"));
1146
1147 /*
1148 * Variant (a): immediate resolve error.
1149 */
1150 PJ_LOG(3,(THIS_FILE, " variant a: immediate resolving error"));
1151
1152 status = perform_tsx_test(-800,
Benny Prijonoe93e2872006-06-28 16:46:49 +00001153 "sip:bob@unresolved-host",
Benny Prijonod4791af2007-06-19 08:46:02 +00001154 FROM_URI, TEST2_BRANCH_ID, 20,
Benny Prijono85598d92006-01-07 18:44:25 +00001155 &pjsip_options_method);
1156 if (status != 0)
1157 return status;
1158
1159 /*
1160 * Variant (b): error via callback.
1161 */
1162 PJ_LOG(3,(THIS_FILE, " variant b: error via callback"));
1163
Benny Prijonoe93e2872006-06-28 16:46:49 +00001164 /* This only applies to "loop-dgram" transport */
1165 if (test_param->type == PJSIP_TRANSPORT_LOOP_DGRAM) {
1166 /* Set loop transport to return delayed error. */
1167 pjsip_loop_set_failure(loop, 2, NULL);
1168 pjsip_loop_set_send_callback_delay(loop, 10, NULL);
Benny Prijono85598d92006-01-07 18:44:25 +00001169
Benny Prijonoe93e2872006-06-28 16:46:49 +00001170 status = perform_tsx_test(-800, TARGET_URI, FROM_URI,
1171 TEST2_BRANCH_ID, 2,
1172 &pjsip_options_method);
1173 if (status != 0)
1174 return status;
Benny Prijono85598d92006-01-07 18:44:25 +00001175
Benny Prijonoe93e2872006-06-28 16:46:49 +00001176 /* Restore loop transport settings. */
1177 pjsip_loop_set_failure(loop, 0, NULL);
1178 pjsip_loop_set_send_callback_delay(loop, 0, NULL);
1179 }
Benny Prijono85598d92006-01-07 18:44:25 +00001180
1181 return status;
1182}
1183
1184
1185/*****************************************************************************
1186 **
1187 ** TEST3_BRANCH_ID: UAC terminate while resolving test.
1188 **
1189 ** Terminate the transaction while resolver is still running.
1190 **
1191 *****************************************************************************
1192 */
1193static int tsx_terminate_resolving_test(void)
1194{
1195 unsigned prev_delay;
1196 pj_status_t status;
1197
1198 PJ_LOG(3,(THIS_FILE, " test3: terminate while resolving test"));
1199
1200 /* Configure transport delay. */
1201 pjsip_loop_set_send_callback_delay(loop, 100, &prev_delay);
1202
1203 /* Start the test. */
Benny Prijonoe93e2872006-06-28 16:46:49 +00001204 status = perform_tsx_test(-900, TARGET_URI, FROM_URI,
Benny Prijono85598d92006-01-07 18:44:25 +00001205 TEST3_BRANCH_ID, 2, &pjsip_options_method);
1206
1207 /* Restore delay. */
1208 pjsip_loop_set_send_callback_delay(loop, prev_delay, NULL);
1209
1210 return status;
1211}
1212
1213
1214/*****************************************************************************
1215 **
1216 ** TEST4_BRANCH_ID: Transport failed after several retransmissions
1217 **
1218 ** There are two variants of this test: (a) failure occurs immediately when
1219 ** transaction calls pjsip_transport_send() or (b) failure is reported via
1220 ** transport callback.
1221 **
1222 *****************************************************************************
1223 */
1224static int tsx_retransmit_fail_test(void)
1225{
1226 int i;
1227 unsigned delay[] = {0, 10};
1228 pj_status_t status;
1229
1230 PJ_LOG(3,(THIS_FILE,
1231 " test4: transport fails after several retransmissions test"));
1232
1233
Benny Prijonoa1e69682007-05-11 15:14:34 +00001234 for (i=0; i<(int)PJ_ARRAY_SIZE(delay); ++i) {
Benny Prijono85598d92006-01-07 18:44:25 +00001235
1236 PJ_LOG(3,(THIS_FILE,
1237 " variant %c: transport delay %d ms", ('a'+i), delay[i]));
1238
1239 /* Configure transport delay. */
1240 pjsip_loop_set_send_callback_delay(loop, delay[i], NULL);
1241
1242 /* Restore transport failure mode. */
1243 pjsip_loop_set_failure(loop, 0, 0);
1244
1245 /* Start the test. */
Benny Prijonoe93e2872006-06-28 16:46:49 +00001246 status = perform_tsx_test(-1000, TARGET_URI, FROM_URI,
Benny Prijono85598d92006-01-07 18:44:25 +00001247 TEST4_BRANCH_ID, 6, &pjsip_options_method);
1248
1249 if (status != 0)
1250 break;
1251
1252 }
1253
1254 /* Restore delay. */
1255 pjsip_loop_set_send_callback_delay(loop, 0, NULL);
1256
1257 /* Restore transport failure mode. */
1258 pjsip_loop_set_failure(loop, 0, 0);
1259
1260 return status;
1261}
1262
1263
1264/*****************************************************************************
1265 **
1266 ** TEST5_BRANCH_ID: Terminate transaction after several retransmissions
1267 **
1268 *****************************************************************************
1269 */
1270static int tsx_terminate_after_retransmit_test(void)
1271{
1272 int status;
1273
1274 PJ_LOG(3,(THIS_FILE, " test5: terminate after retransmissions"));
1275
1276 /* Do the test. */
Benny Prijonoe93e2872006-06-28 16:46:49 +00001277 status = perform_tsx_test(-1100, TARGET_URI, FROM_URI,
Benny Prijono85598d92006-01-07 18:44:25 +00001278 TEST5_BRANCH_ID,
1279 6, &pjsip_options_method);
1280
1281 /* Done. */
1282 return status;
1283}
1284
1285
1286/*****************************************************************************
1287 **
1288 ** TEST6_BRANCH_ID: Successfull non-invite transaction
Benny Prijono9c1d9f52006-01-07 23:01:56 +00001289 ** TEST7_BRANCH_ID: Successfull non-invite transaction with provisional
1290 ** TEST8_BRANCH_ID: Failed invite transaction
1291 ** TEST9_BRANCH_ID: Failed invite transaction with provisional
Benny Prijono85598d92006-01-07 18:44:25 +00001292 **
1293 *****************************************************************************
1294 */
Benny Prijono9c1d9f52006-01-07 23:01:56 +00001295static int perform_generic_test( const char *title,
1296 char *branch_id,
1297 const pjsip_method *method)
Benny Prijono85598d92006-01-07 18:44:25 +00001298{
1299 int i, status;
1300 unsigned delay[] = { 1, 200 };
1301
Benny Prijonoe8a2ff52006-01-07 23:36:57 +00001302 PJ_LOG(3,(THIS_FILE, " %s", title));
Benny Prijono85598d92006-01-07 18:44:25 +00001303
1304 /* Do the test. */
Benny Prijonoa1e69682007-05-11 15:14:34 +00001305 for (i=0; i<(int)PJ_ARRAY_SIZE(delay); ++i) {
Benny Prijono85598d92006-01-07 18:44:25 +00001306
Benny Prijonoe93e2872006-06-28 16:46:49 +00001307 if (test_param->type == PJSIP_TRANSPORT_LOOP_DGRAM) {
1308 PJ_LOG(3,(THIS_FILE, " variant %c: with %d ms transport delay",
1309 ('a'+i), delay[i]));
Benny Prijono85598d92006-01-07 18:44:25 +00001310
Benny Prijonoe93e2872006-06-28 16:46:49 +00001311 pjsip_loop_set_delay(loop, delay[i]);
1312 }
Benny Prijono85598d92006-01-07 18:44:25 +00001313
Benny Prijonoe93e2872006-06-28 16:46:49 +00001314 status = perform_tsx_test(-1200, TARGET_URI, FROM_URI,
1315 branch_id, 10, method);
Benny Prijono85598d92006-01-07 18:44:25 +00001316 if (status != 0)
1317 return status;
Benny Prijonoe93e2872006-06-28 16:46:49 +00001318
1319 if (test_param->type != PJSIP_TRANSPORT_LOOP_DGRAM)
1320 break;
Benny Prijono85598d92006-01-07 18:44:25 +00001321 }
1322
1323 pjsip_loop_set_delay(loop, 0);
1324
1325 /* Done. */
1326 return status;
1327}
1328
1329
1330/*****************************************************************************
1331 **
Benny Prijonofa73e3e2006-01-05 23:35:46 +00001332 ** UAC Transaction Test.
1333 **
1334 *****************************************************************************
1335 */
Benny Prijonoe93e2872006-06-28 16:46:49 +00001336int tsx_uac_test(struct tsx_test_param *param)
Benny Prijonofa73e3e2006-01-05 23:35:46 +00001337{
1338 pj_sockaddr_in addr;
Benny Prijonofa73e3e2006-01-05 23:35:46 +00001339 pj_status_t status;
1340
Benny Prijonoe93e2872006-06-28 16:46:49 +00001341 timer.tsx_key.ptr = timer.key_buf;
1342
1343 test_param = param;
1344
1345 /* Get transport flag */
Benny Prijonoa1e69682007-05-11 15:14:34 +00001346 tp_flag = pjsip_transport_get_flag_from_type((pjsip_transport_type_e)test_param->type);
Benny Prijonoe93e2872006-06-28 16:46:49 +00001347
1348 pj_ansi_sprintf(TARGET_URI, "sip:bob@127.0.0.1:%d;transport=%s",
1349 param->port, param->tp_type);
1350 pj_ansi_sprintf(FROM_URI, "sip:alice@127.0.0.1:%d;transport=%s",
1351 param->port, param->tp_type);
1352
Benny Prijono85598d92006-01-07 18:44:25 +00001353 /* Check if loop transport is configured. */
1354 status = pjsip_endpt_acquire_transport(endpt, PJSIP_TRANSPORT_LOOP_DGRAM,
Benny Prijonodf2b71e2007-01-20 19:17:47 +00001355 &addr, sizeof(addr), NULL, &loop);
Benny Prijonofa73e3e2006-01-05 23:35:46 +00001356 if (status != PJ_SUCCESS) {
Benny Prijono85598d92006-01-07 18:44:25 +00001357 PJ_LOG(3,(THIS_FILE, " Error: loop transport is not configured!"));
1358 return -10;
Benny Prijonofa73e3e2006-01-05 23:35:46 +00001359 }
1360
1361 /* Register modules. */
1362 status = pjsip_endpt_register_module(endpt, &tsx_user);
1363 if (status != PJ_SUCCESS) {
1364 app_perror(" Error: unable to register module", status);
1365 return -30;
1366 }
1367 status = pjsip_endpt_register_module(endpt, &msg_receiver);
1368 if (status != PJ_SUCCESS) {
1369 app_perror(" Error: unable to register module", status);
Benny Prijono85598d92006-01-07 18:44:25 +00001370 return -40;
Benny Prijonofa73e3e2006-01-05 23:35:46 +00001371 }
1372
Benny Prijono85598d92006-01-07 18:44:25 +00001373 /* TEST1_BRANCH_ID: Basic retransmit and timeout test. */
1374 status = tsx_uac_retransmit_test();
Benny Prijonofa73e3e2006-01-05 23:35:46 +00001375 if (status != 0)
1376 return status;
1377
Benny Prijono85598d92006-01-07 18:44:25 +00001378 /* TEST2_BRANCH_ID: Resolve error test. */
1379 status = tsx_resolve_error_test();
Benny Prijonofa73e3e2006-01-05 23:35:46 +00001380 if (status != 0)
1381 return status;
1382
Benny Prijono85598d92006-01-07 18:44:25 +00001383 /* TEST3_BRANCH_ID: UAC terminate while resolving test. */
1384 status = tsx_terminate_resolving_test();
1385 if (status != 0)
1386 return status;
1387
Benny Prijonoe93e2872006-06-28 16:46:49 +00001388 /* TEST4_BRANCH_ID: Transport failed after several retransmissions.
1389 * Only applies to loop transport.
1390 */
1391 if (test_param->type == PJSIP_TRANSPORT_LOOP_DGRAM) {
1392 status = tsx_retransmit_fail_test();
1393 if (status != 0)
1394 return status;
1395 }
Benny Prijono85598d92006-01-07 18:44:25 +00001396
Benny Prijonoe93e2872006-06-28 16:46:49 +00001397 /* TEST5_BRANCH_ID: Terminate transaction after several retransmissions
1398 * Only applicable to non-reliable transports.
1399 */
1400 if ((tp_flag & PJSIP_TRANSPORT_RELIABLE) == 0) {
1401 status = tsx_terminate_after_retransmit_test();
1402 if (status != 0)
1403 return status;
1404 }
Benny Prijono85598d92006-01-07 18:44:25 +00001405
1406 /* TEST6_BRANCH_ID: Successfull non-invite transaction */
Benny Prijonoe8a2ff52006-01-07 23:36:57 +00001407 status = perform_generic_test("test6: successfull non-invite transaction",
Benny Prijono9c1d9f52006-01-07 23:01:56 +00001408 TEST6_BRANCH_ID, &pjsip_options_method);
1409 if (status != 0)
1410 return status;
1411
1412 /* TEST7_BRANCH_ID: Successfull non-invite transaction */
Benny Prijonoe8a2ff52006-01-07 23:36:57 +00001413 status = perform_generic_test("test7: successfull non-invite transaction "
Benny Prijono9c1d9f52006-01-07 23:01:56 +00001414 "with provisional response",
1415 TEST7_BRANCH_ID, &pjsip_options_method);
1416 if (status != 0)
1417 return status;
1418
1419 /* TEST8_BRANCH_ID: Failed invite transaction */
Benny Prijonoe8a2ff52006-01-07 23:36:57 +00001420 status = perform_generic_test("test8: failed invite transaction",
Benny Prijono9c1d9f52006-01-07 23:01:56 +00001421 TEST8_BRANCH_ID, &pjsip_invite_method);
1422 if (status != 0)
1423 return status;
1424
1425 /* TEST9_BRANCH_ID: Failed invite transaction with provisional response */
Benny Prijonoe8a2ff52006-01-07 23:36:57 +00001426 status = perform_generic_test("test9: failed invite transaction with "
Benny Prijono9c1d9f52006-01-07 23:01:56 +00001427 "provisional response",
1428 TEST9_BRANCH_ID, &pjsip_invite_method);
Benny Prijono85598d92006-01-07 18:44:25 +00001429 if (status != 0)
1430 return status;
1431
Benny Prijono85598d92006-01-07 18:44:25 +00001432 pjsip_transport_dec_ref(loop);
Benny Prijonoe93e2872006-06-28 16:46:49 +00001433 flush_events(500);
1434
1435 /* Unregister modules. */
1436 status = pjsip_endpt_unregister_module(endpt, &tsx_user);
1437 if (status != PJ_SUCCESS) {
1438 app_perror(" Error: unable to unregister module", status);
1439 return -31;
1440 }
1441 status = pjsip_endpt_unregister_module(endpt, &msg_receiver);
1442 if (status != PJ_SUCCESS) {
1443 app_perror(" Error: unable to unregister module", status);
1444 return -41;
1445 }
1446
Benny Prijonofa73e3e2006-01-05 23:35:46 +00001447 return 0;
1448}
Benny Prijono85598d92006-01-07 18:44:25 +00001449