blob: ecc174c49b8d1f3915b2d4011473d19b54c93d83 [file] [log] [blame]
Benny Prijonodbe337a2006-01-08 23:57:52 +00001/* $Id$ */
2/*
3 * Copyright (C) 2003-2006 Benny Prijono <benny@prijono.org>
4 *
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"
21#include <pjsip_core.h>
22#include <pjlib.h>
23
24#define THIS_FILE "tsx_uas_test.c"
25
26
27/*****************************************************************************
28 **
29 ** UAS tests.
30 **
31 ** 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.
34 **
35 ** TEST1_BRANCH_ID
36 ** Test that non-INVITE transaction returns 2xx response to the correct
37 ** transport and correctly terminates the transaction.
38 **
39 ** TEST2_BRANCH_ID
40 ** As above, for non-2xx final response.
41 **
42 ** TEST3_BRANCH_ID
43 ** Transaction correctly progressing to PROCEEDING state when provisional
44 ** response is sent.
45 **
46 ** TEST4_BRANCH_ID
47 ** Transaction retransmits last response (if any) without notifying
Benny Prijono0c2bc612006-01-10 13:31:40 +000048 ** transaction user upon receiving request retransmissions on TRYING
49 ** state
Benny Prijonodbe337a2006-01-08 23:57:52 +000050 **
51 ** TEST5_BRANCH_ID
Benny Prijono0c2bc612006-01-10 13:31:40 +000052 ** As above, in PROCEEDING state.
Benny Prijonodbe337a2006-01-08 23:57:52 +000053 **
54 ** TEST6_BRANCH_ID
Benny Prijono0c2bc612006-01-10 13:31:40 +000055 ** As above, in COMPLETED state, with first sending provisional response.
Benny Prijonodbe337a2006-01-08 23:57:52 +000056 **
57 ** TEST7_BRANCH_ID
Benny Prijono0c2bc612006-01-10 13:31:40 +000058 ** INVITE transaction MUST retransmit non-2xx final response.
Benny Prijonodbe337a2006-01-08 23:57:52 +000059 **
60 ** TEST8_BRANCH_ID
Benny Prijono0c2bc612006-01-10 13:31:40 +000061 ** As above, for INVITE's 2xx final response (this is PJSIP specific).
62 **
63 ** TEST9_BRANCH_ID
64 ** INVITE transaction MUST cease retransmission of final response when
65 ** ACK is received. (Note: PJSIP also retransmit 2xx final response
66 ** until it's terminated by user).
67 ** Transaction also MUST terminate in T4 seconds.
68 **
Benny Prijono0c2bc612006-01-10 13:31:40 +000069 ** TEST11_BRANCH_ID
Benny Prijono728a9052006-01-18 23:34:15 +000070 ** Test scenario where transport fails before response is sent (i.e.
71 ** in TRYING state).
72 **
73 ** TEST12_BRANCH_ID
74 ** As above, after provisional response is sent but before final
75 ** response is sent (i.e. in PROCEEDING state).
76 **
77 ** TEST13_BRANCH_ID
78 ** As above, for INVITE, after final response has been sent but before
79 ** ACK is received (i.e. in CONNECTED state).
80 **
81 ** TEST14_BRANCH_ID
Benny Prijonodbe337a2006-01-08 23:57:52 +000082 ** When UAS failed to deliver the response with the selected transport,
83 ** it should try contacting the client with other transport or begin
84 ** RFC 3263 server resolution procedure.
85 ** This should be tested on:
86 ** a. TRYING state (when delivering first response).
87 ** b. PROCEEDING state (when failed to retransmit last response
88 ** upon receiving request retransmission).
89 ** c. COMPLETED state.
90 **
Benny Prijonodbe337a2006-01-08 23:57:52 +000091 **/
92
93static char *TEST1_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAS-Test1";
94static char *TEST2_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAS-Test2";
95static char *TEST3_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAS-Test3";
96static char *TEST4_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAS-Test4";
97static char *TEST5_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAS-Test5";
98static char *TEST6_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAS-Test6";
99static char *TEST7_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAS-Test7";
Benny Prijono0c2bc612006-01-10 13:31:40 +0000100static char *TEST8_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAS-Test8";
101static char *TEST9_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAS-Test9";
102static char *TEST10_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAS-Test10";
103static char *TEST11_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAS-Test11";
104static char *TEST12_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAS-Test12";
Benny Prijono728a9052006-01-18 23:34:15 +0000105static char *TEST13_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-UAS-Test13";
Benny Prijonodbe337a2006-01-08 23:57:52 +0000106
107#define TEST1_STATUS_CODE 200
108#define TEST2_STATUS_CODE 301
109#define TEST3_PROVISIONAL_CODE PJSIP_SC_QUEUED
110#define TEST3_STATUS_CODE 202
Benny Prijono0c2bc612006-01-10 13:31:40 +0000111#define TEST4_STATUS_CODE 200
112#define TEST4_REQUEST_COUNT 2
113#define TEST5_PROVISIONAL_CODE 100
114#define TEST5_STATUS_CODE 200
115#define TEST5_REQUEST_COUNT 2
116#define TEST5_RESPONSE_COUNT 2
117#define TEST6_PROVISIONAL_CODE 100
118#define TEST6_STATUS_CODE 200 /* Must be final */
119#define TEST6_REQUEST_COUNT 2
120#define TEST6_RESPONSE_COUNT 3
121#define TEST7_STATUS_CODE 301
122#define TEST8_STATUS_CODE 302
Benny Prijono728a9052006-01-18 23:34:15 +0000123#define TEST9_STATUS_CODE 301
Benny Prijonodbe337a2006-01-08 23:57:52 +0000124
125
Benny Prijono0c2bc612006-01-10 13:31:40 +0000126#define TEST4_TITLE "test4: absorbing request retransmission"
127#define TEST5_TITLE "test5: retransmit last response in PROCEEDING state"
128#define TEST6_TITLE "test6: retransmit last response in COMPLETED state"
129
130
131#define TEST_TIMEOUT_ERROR -30
132#define MAX_ALLOWED_DIFF 150
133
Benny Prijonodbe337a2006-01-08 23:57:52 +0000134static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e);
135static pj_bool_t on_rx_message(pjsip_rx_data *rdata);
136
137/* UAC transaction user module. */
138static pjsip_module tsx_user =
139{
140 NULL, NULL, /* prev and next */
141 { "Tsx-UAS-User", 12}, /* Name. */
142 -1, /* Id */
143 PJSIP_MOD_PRIORITY_APPLICATION-1, /* Priority */
144 NULL, /* User data. */
145 0, /* Number of methods supported (=0). */
146 { 0 }, /* Array of methods (none) */
147 NULL, /* load() */
148 NULL, /* start() */
149 NULL, /* stop() */
150 NULL, /* unload() */
151 NULL, /* on_rx_request() */
152 NULL, /* on_rx_response() */
153 NULL, /* on_tx_request() */
154 NULL, /* on_tx_response() */
155 &tsx_user_on_tsx_state, /* on_tsx_state() */
156};
157
158/* Module to send request. */
159static pjsip_module msg_sender =
160{
161 NULL, NULL, /* prev and next */
162 { "Msg-Sender", 10}, /* Name. */
163 -1, /* Id */
164 PJSIP_MOD_PRIORITY_APPLICATION-1, /* Priority */
165 NULL, /* User data. */
166 0, /* Number of methods supported (=0). */
167 { 0 }, /* Array of methods (none) */
168 NULL, /* load() */
169 NULL, /* start() */
170 NULL, /* stop() */
171 NULL, /* unload() */
172 &on_rx_message, /* on_rx_request() */
173 &on_rx_message, /* on_rx_response() */
174 NULL, /* on_tx_request() */
175 NULL, /* on_tx_response() */
176 NULL, /* on_tsx_state() */
177};
178
179/* Static vars, which will be reset on each test. */
180static int recv_count;
181static pj_time_val recv_last;
182static pj_bool_t test_complete;
183
184/* Loop transport instance. */
185static pjsip_transport *loop;
186
187/* UAS transaction key. */
188static char key_buf[64];
189static pj_str_t tsx_key = { key_buf, 0 };
190
191
192/* General timer entry to be used by tests. */
193static pj_timer_entry timer;
194
195/* Timer to send response via transaction. */
196struct response
197{
198 pj_str_t tsx_key;
199 pjsip_tx_data *tdata;
200};
201
Benny Prijono0c2bc612006-01-10 13:31:40 +0000202/* Timer callback to send response. */
Benny Prijonodbe337a2006-01-08 23:57:52 +0000203static void send_response_timer( pj_timer_heap_t *timer_heap,
204 struct pj_timer_entry *entry)
205{
206 pjsip_transaction *tsx;
207 struct response *r = entry->user_data;
208 pj_status_t status;
209
210 tsx = pjsip_tsx_layer_find_tsx(&r->tsx_key, PJ_TRUE);
211 if (!tsx) {
212 PJ_LOG(3,(THIS_FILE," error: timer unable to find transaction"));
213 pjsip_tx_data_dec_ref(r->tdata);
214 return;
215 }
216
217 status = pjsip_tsx_send_msg(tsx, r->tdata);
218 if (status != PJ_SUCCESS) {
Benny Prijono728a9052006-01-18 23:34:15 +0000219 // Some tests do expect failure!
220 //PJ_LOG(3,(THIS_FILE," error: timer unable to send response"));
221 pj_mutex_unlock(tsx->mutex);
Benny Prijonodbe337a2006-01-08 23:57:52 +0000222 pjsip_tx_data_dec_ref(r->tdata);
223 return;
224 }
Benny Prijono728a9052006-01-18 23:34:15 +0000225
226 pj_mutex_unlock(tsx->mutex);
Benny Prijonodbe337a2006-01-08 23:57:52 +0000227}
228
Benny Prijono0c2bc612006-01-10 13:31:40 +0000229/* Utility to send response. */
230static void send_response( pjsip_rx_data *rdata,
231 pjsip_transaction *tsx,
232 int status_code )
233{
234 pj_status_t status;
235 pjsip_tx_data *tdata;
236
237 status = pjsip_endpt_create_response( endpt, rdata, status_code, NULL,
238 &tdata);
239 if (status != PJ_SUCCESS) {
240 app_perror(" error: unable to create response", status);
241 test_complete = -196;
242 return;
243 }
244
245 status = pjsip_tsx_send_msg(tsx, tdata);
246 if (status != PJ_SUCCESS) {
Benny Prijono0c2bc612006-01-10 13:31:40 +0000247 pjsip_tx_data_dec_ref(tdata);
Benny Prijono728a9052006-01-18 23:34:15 +0000248 // Some tests do expect failure!
249 //app_perror(" error: unable to send response", status);
250 //test_complete = -197;
Benny Prijono0c2bc612006-01-10 13:31:40 +0000251 return;
252 }
253}
254
Benny Prijonodbe337a2006-01-08 23:57:52 +0000255/* Schedule timer to send response for the specified UAS transaction */
256static void schedule_send_response( pjsip_rx_data *rdata,
257 const pj_str_t *tsx_key,
258 int status_code,
259 int msec_delay )
260{
261 pj_status_t status;
262 pjsip_tx_data *tdata;
Benny Prijono728a9052006-01-18 23:34:15 +0000263 pj_timer_entry *t;
Benny Prijonodbe337a2006-01-08 23:57:52 +0000264 struct response *r;
265 pj_time_val delay;
266
267 status = pjsip_endpt_create_response( endpt, rdata, status_code, NULL,
268 &tdata);
269 if (status != PJ_SUCCESS) {
270 app_perror(" error: unable to create response", status);
271 test_complete = -198;
272 return;
273 }
274
275 r = pj_pool_alloc(tdata->pool, sizeof(*r));
276 pj_strdup(tdata->pool, &r->tsx_key, tsx_key);
277 r->tdata = tdata;
278
279 delay.sec = 0;
280 delay.msec = msec_delay;
281 pj_time_val_normalize(&delay);
282
Benny Prijono728a9052006-01-18 23:34:15 +0000283 t = pj_pool_zalloc(tdata->pool, sizeof(*t));
284 t->user_data = r;
285 t->cb = &send_response_timer;
Benny Prijonodbe337a2006-01-08 23:57:52 +0000286
Benny Prijono728a9052006-01-18 23:34:15 +0000287 status = pjsip_endpt_schedule_timer(endpt, t, &delay);
Benny Prijonodbe337a2006-01-08 23:57:52 +0000288 if (status != PJ_SUCCESS) {
Benny Prijono728a9052006-01-18 23:34:15 +0000289 pjsip_tx_data_dec_ref(tdata);
Benny Prijonodbe337a2006-01-08 23:57:52 +0000290 app_perror(" error: unable to schedule timer", status);
291 test_complete = -199;
Benny Prijonodbe337a2006-01-08 23:57:52 +0000292 return;
293 }
294}
295
Benny Prijono0c2bc612006-01-10 13:31:40 +0000296
297/* Find and terminate tsx with the specified key. */
298static void terminate_our_tsx(int status_code)
299{
300 pjsip_transaction *tsx;
301
302 tsx = pjsip_tsx_layer_find_tsx(&tsx_key, PJ_TRUE);
303 if (!tsx) {
304 PJ_LOG(3,(THIS_FILE," error: timer unable to find transaction"));
305 return;
306 }
307
308 pjsip_tsx_terminate(tsx, status_code);
309 pj_mutex_unlock(tsx->mutex);
310}
311
312/* Timer callback to terminate transaction. */
313static void terminate_tsx_timer( pj_timer_heap_t *timer_heap,
314 struct pj_timer_entry *entry)
315{
316 terminate_our_tsx(entry->id);
317}
318
319
320/* Schedule timer to terminate transaction. */
321static void schedule_terminate_tsx( pjsip_transaction *tsx,
322 int status_code,
323 int msec_delay )
324{
325 pj_time_val delay;
326
327 delay.sec = 0;
328 delay.msec = msec_delay;
329 pj_time_val_normalize(&delay);
330
331 pj_assert(pj_strcmp(&tsx->transaction_key, &tsx_key)==0);
332 timer.user_data = NULL;
333 timer.id = status_code;
334 timer.cb = &terminate_tsx_timer;
335 pjsip_endpt_schedule_timer(endpt, &timer, &delay);
336}
337
338
Benny Prijonodbe337a2006-01-08 23:57:52 +0000339/*
340 * This is the handler to receive state changed notification from the
341 * transaction. It is used to verify that the transaction behaves according
342 * to the test scenario.
343 */
344static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e)
345{
346 if (pj_strcmp2(&tsx->branch, TEST1_BRANCH_ID)==0 ||
347 pj_strcmp2(&tsx->branch, TEST2_BRANCH_ID)==0)
348 {
349 /*
350 * TEST1_BRANCH_ID tests that non-INVITE transaction transmits final
351 * response using correct transport and terminates transaction after
352 * T4 (PJSIP_T4_TIMEOUT, 5 seconds).
353 *
354 * TEST2_BRANCH_ID does similar test for non-2xx final response.
355 */
356 int status_code = (pj_strcmp2(&tsx->branch, TEST1_BRANCH_ID)==0) ?
357 TEST1_STATUS_CODE : TEST2_STATUS_CODE;
358
359 if (tsx->state == PJSIP_TSX_STATE_TERMINATED) {
360
361 test_complete = 1;
362
363 /* Check that status code is status_code. */
364 if (tsx->status_code != status_code) {
365 PJ_LOG(3,(THIS_FILE, " error: incorrect status code"));
366 test_complete = -100;
367 }
368
369 /* Previous state must be completed. */
370 if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_COMPLETED) {
371 PJ_LOG(3,(THIS_FILE, " error: incorrect prev_state"));
372 test_complete = -101;
373 }
374
375 } else if (tsx->state == PJSIP_TSX_STATE_COMPLETED) {
376
377 /* Previous state must be TRYING. */
378 if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_TRYING) {
379 PJ_LOG(3,(THIS_FILE, " error: incorrect prev_state"));
380 test_complete = -102;
381 }
382 }
383
384 }
385 else
386 if (pj_strcmp2(&tsx->branch, TEST3_BRANCH_ID)==0) {
387 /*
388 * TEST3_BRANCH_ID tests sending provisional response.
389 */
390 if (tsx->state == PJSIP_TSX_STATE_TERMINATED) {
391
392 test_complete = 1;
393
394 /* Check that status code is status_code. */
395 if (tsx->status_code != TEST3_STATUS_CODE) {
396 PJ_LOG(3,(THIS_FILE, " error: incorrect status code"));
397 test_complete = -110;
398 }
399
400 /* Previous state must be completed. */
401 if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_COMPLETED) {
402 PJ_LOG(3,(THIS_FILE, " error: incorrect prev_state"));
403 test_complete = -111;
404 }
405
406 } else if (tsx->state == PJSIP_TSX_STATE_PROCEEDING) {
407
408 /* Previous state must be TRYING. */
409 if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_TRYING) {
410 PJ_LOG(3,(THIS_FILE, " error: incorrect prev_state"));
411 test_complete = -112;
412 }
413
414 /* Check that status code is status_code. */
415 if (tsx->status_code != TEST3_PROVISIONAL_CODE) {
416 PJ_LOG(3,(THIS_FILE, " error: incorrect status code"));
417 test_complete = -113;
418 }
419
420 /* Check that event must be TX_MSG */
421 if (e->body.tsx_state.type != PJSIP_EVENT_TX_MSG) {
422 PJ_LOG(3,(THIS_FILE, " error: incorrect event"));
423 test_complete = -114;
424 }
425
426 } else if (tsx->state == PJSIP_TSX_STATE_COMPLETED) {
427
428 /* Previous state must be PROCEEDING. */
429 if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_PROCEEDING) {
430 PJ_LOG(3,(THIS_FILE, " error: incorrect prev_state"));
431 test_complete = -115;
432 }
433
434 /* Check that status code is status_code. */
435 if (tsx->status_code != TEST3_STATUS_CODE) {
436 PJ_LOG(3,(THIS_FILE, " error: incorrect status code"));
437 test_complete = -116;
438 }
439
440 /* Check that event must be TX_MSG */
441 if (e->body.tsx_state.type != PJSIP_EVENT_TX_MSG) {
442 PJ_LOG(3,(THIS_FILE, " error: incorrect event"));
443 test_complete = -117;
444 }
445
446 }
447
Benny Prijono0c2bc612006-01-10 13:31:40 +0000448 } else
449 if (pj_strcmp2(&tsx->branch, TEST4_BRANCH_ID)==0) {
450 /*
451 * TEST4_BRANCH_ID tests receiving retransmissions in TRYING state.
452 */
453 if (tsx->state == PJSIP_TSX_STATE_TERMINATED) {
454
455 /* Check that status code is status_code. */
456 if (tsx->status_code != TEST4_STATUS_CODE) {
457 PJ_LOG(3,(THIS_FILE, " error: incorrect status code"));
458 test_complete = -120;
459 }
460
461 /* Previous state. */
462 if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_TRYING) {
463 PJ_LOG(3,(THIS_FILE, " error: incorrect prev_state"));
464 test_complete = -121;
465 }
466
467 } else if (tsx->state != PJSIP_TSX_STATE_DESTROYED)
468 {
469 PJ_LOG(3,(THIS_FILE, " error: unexpected state"));
470 test_complete = -122;
471
472 }
473
474
475 } else
476 if (pj_strcmp2(&tsx->branch, TEST5_BRANCH_ID)==0) {
477 /*
478 * TEST5_BRANCH_ID tests receiving retransmissions in PROCEEDING state
479 */
480 if (tsx->state == PJSIP_TSX_STATE_TERMINATED) {
481
482 /* Check that status code is status_code. */
483 if (tsx->status_code != TEST5_STATUS_CODE) {
484 PJ_LOG(3,(THIS_FILE, " error: incorrect status code"));
485 test_complete = -130;
486 }
487
488 /* Previous state. */
489 if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_PROCEEDING) {
490 PJ_LOG(3,(THIS_FILE, " error: incorrect prev_state"));
491 test_complete = -131;
492 }
493
494 } else if (tsx->state == PJSIP_TSX_STATE_PROCEEDING) {
495
496 /* Check status code. */
497 if (tsx->status_code != TEST5_PROVISIONAL_CODE) {
498 PJ_LOG(3,(THIS_FILE, " error: incorrect status code"));
499 test_complete = -132;
500 }
501
502 } else if (tsx->state != PJSIP_TSX_STATE_DESTROYED) {
503 PJ_LOG(3,(THIS_FILE, " error: unexpected state"));
504 test_complete = -133;
505
506 }
507
508 } else
509 if (pj_strcmp2(&tsx->branch, TEST6_BRANCH_ID)==0) {
510 /*
511 * TEST6_BRANCH_ID tests receiving retransmissions in COMPLETED state
512 */
513 if (tsx->state == PJSIP_TSX_STATE_TERMINATED) {
514
515 /* Check that status code is status_code. */
516 if (tsx->status_code != TEST6_STATUS_CODE) {
517 PJ_LOG(3,(THIS_FILE, " error: incorrect status code"));
518 test_complete = -140;
519 }
520
521 /* Previous state. */
522 if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_COMPLETED) {
523 PJ_LOG(3,(THIS_FILE, " error: incorrect prev_state"));
524 test_complete = -141;
525 }
526
527 } else if (tsx->state != PJSIP_TSX_STATE_PROCEEDING &&
528 tsx->state != PJSIP_TSX_STATE_COMPLETED &&
529 tsx->state != PJSIP_TSX_STATE_DESTROYED)
530 {
531 PJ_LOG(3,(THIS_FILE, " error: unexpected state"));
532 test_complete = -142;
533
534 }
535
536
537 } else
538 if (pj_strcmp2(&tsx->branch, TEST7_BRANCH_ID)==0 ||
539 pj_strcmp2(&tsx->branch, TEST8_BRANCH_ID)==0)
540 {
541 /*
542 * TEST7_BRANCH_ID and TEST8_BRANCH_ID test retransmission of
543 * INVITE final response
544 */
545 int code;
546
547 if (pj_strcmp2(&tsx->branch, TEST7_BRANCH_ID) == 0)
548 code = TEST7_STATUS_CODE;
549 else
550 code = TEST8_STATUS_CODE;
551
552 if (tsx->state == PJSIP_TSX_STATE_TERMINATED) {
553
554 if (test_complete == 0)
555 test_complete = 1;
556
557 /* Check status code. */
558 if (tsx->status_code != PJSIP_SC_TSX_TIMEOUT) {
559 PJ_LOG(3,(THIS_FILE, " error: incorrect status code"));
560 test_complete = -150;
561 }
562
563 /* Previous state. */
564 if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_COMPLETED) {
565 PJ_LOG(3,(THIS_FILE, " error: incorrect prev_state"));
566 test_complete = -151;
567 }
568
569 } else if (tsx->state == PJSIP_TSX_STATE_COMPLETED) {
570
571 /* Check that status code is status_code. */
572 if (tsx->status_code != code) {
573 PJ_LOG(3,(THIS_FILE, " error: incorrect status code"));
574 test_complete = -152;
575 }
576
577 /* Previous state. */
578 if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_TRYING) {
579 PJ_LOG(3,(THIS_FILE, " error: incorrect prev_state"));
580 test_complete = -153;
581 }
582
583 } else if (tsx->state != PJSIP_TSX_STATE_DESTROYED) {
584
585 PJ_LOG(3,(THIS_FILE, " error: unexpected state"));
586 test_complete = -154;
587
588 }
589
Benny Prijono728a9052006-01-18 23:34:15 +0000590
591 } else
592 if (pj_strcmp2(&tsx->branch, TEST9_BRANCH_ID)==0) {
593 /*
594 * TEST9_BRANCH_ID tests that retransmission of INVITE final response
595 * must cease when ACK is received.
596 */
597
598 if (tsx->state == PJSIP_TSX_STATE_TERMINATED) {
599
600 if (test_complete == 0)
601 test_complete = 1;
602
603 /* Check status code. */
604 if (tsx->status_code != TEST9_STATUS_CODE) {
605 PJ_LOG(3,(THIS_FILE, " error: incorrect status code"));
606 test_complete = -160;
607 }
608
609 /* Previous state. */
610 if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_CONFIRMED) {
611 PJ_LOG(3,(THIS_FILE, " error: incorrect prev_state"));
612 test_complete = -161;
613 }
614
615 } else if (tsx->state == PJSIP_TSX_STATE_COMPLETED) {
616
617 /* Check that status code is status_code. */
618 if (tsx->status_code != TEST9_STATUS_CODE) {
619 PJ_LOG(3,(THIS_FILE, " error: incorrect status code"));
620 test_complete = -162;
621 }
622
623 /* Previous state. */
624 if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_TRYING) {
625 PJ_LOG(3,(THIS_FILE, " error: incorrect prev_state"));
626 test_complete = -163;
627 }
628
629
630 } else if (tsx->state == PJSIP_TSX_STATE_CONFIRMED) {
631
632 /* Check that status code is status_code. */
633 if (tsx->status_code != TEST9_STATUS_CODE) {
634 PJ_LOG(3,(THIS_FILE, " error: incorrect status code"));
635 test_complete = -164;
636 }
637
638 /* Previous state. */
639 if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_COMPLETED) {
640 PJ_LOG(3,(THIS_FILE, " error: incorrect prev_state"));
641 test_complete = -165;
642 }
643
644 } else if (tsx->state != PJSIP_TSX_STATE_DESTROYED) {
645
646 PJ_LOG(3,(THIS_FILE, " error: unexpected state"));
647 test_complete = -166;
648
649 }
650
651
652 } else
653 if (pj_strcmp2(&tsx->branch, TEST10_BRANCH_ID)==0 ||
654 pj_strcmp2(&tsx->branch, TEST11_BRANCH_ID)==0 ||
655 pj_strcmp2(&tsx->branch, TEST12_BRANCH_ID)==0)
656 {
657 if (tsx->state == PJSIP_TSX_STATE_TERMINATED) {
658
659 if (!test_complete)
660 test_complete = 1;
661
662 if (tsx->status_code != PJSIP_SC_TSX_TRANSPORT_ERROR) {
663 PJ_LOG(3,(THIS_FILE," error: incorrect status code"));
664 test_complete = -170;
665 }
666 }
Benny Prijonodbe337a2006-01-08 23:57:52 +0000667 }
668
669}
670
671/* Save transaction key to global variables. */
672static void save_key(pjsip_transaction *tsx)
673{
674 pj_str_t key;
675
676 pj_strdup(tsx->pool, &key, &tsx->transaction_key);
677 pj_strcpy(&tsx_key, &key);
678}
679
Benny Prijono0c2bc612006-01-10 13:31:40 +0000680#define DIFF(a,b) ((a<b) ? (b-a) : (a-b))
681
Benny Prijonodbe337a2006-01-08 23:57:52 +0000682/*
683 * Message receiver handler.
684 */
685static pj_bool_t on_rx_message(pjsip_rx_data *rdata)
686{
687 pjsip_msg *msg = rdata->msg_info.msg;
688 pj_str_t branch_param = rdata->msg_info.via->branch_param;
689 pj_status_t status;
690
691 if (pj_strcmp2(&branch_param, TEST1_BRANCH_ID) == 0 ||
692 pj_strcmp2(&branch_param, TEST2_BRANCH_ID) == 0)
693 {
694 /*
695 * TEST1_BRANCH_ID tests that non-INVITE transaction transmits 2xx
696 * final response using correct transport and terminates transaction
697 * after 32 seconds.
698 *
699 * TEST2_BRANCH_ID performs similar test for non-2xx final response.
700 */
701 int status_code = (pj_strcmp2(&branch_param, TEST1_BRANCH_ID) == 0) ?
702 TEST1_STATUS_CODE : TEST2_STATUS_CODE;
703
704 if (msg->type == PJSIP_REQUEST_MSG) {
Benny Prijono728a9052006-01-18 23:34:15 +0000705 /* On received request, create UAS and respond with final
Benny Prijonodbe337a2006-01-08 23:57:52 +0000706 * response.
707 */
708 pjsip_transaction *tsx;
Benny Prijonodbe337a2006-01-08 23:57:52 +0000709
710 status = pjsip_tsx_create_uas(&tsx_user, rdata, &tsx);
711 if (status != PJ_SUCCESS) {
712 app_perror(" error: unable to create transaction", status);
713 test_complete = -110;
714 return PJ_TRUE;
715 }
716
717 save_key(tsx);
Benny Prijono0c2bc612006-01-10 13:31:40 +0000718 send_response(rdata, tsx, status_code);
Benny Prijonodbe337a2006-01-08 23:57:52 +0000719
720 } else {
721 /* Verify the response received. */
722
723 ++recv_count;
724
725 /* Verify status code. */
726 if (msg->line.status.code != status_code) {
727 PJ_LOG(3,(THIS_FILE, " error: incorrect status code"));
728 test_complete = -113;
729 }
730
731 /* Verify that no retransmissions is received. */
732 if (recv_count > 1) {
733 PJ_LOG(3,(THIS_FILE, " error: retransmission received"));
734 test_complete = -114;
735 }
736
737 }
738 return PJ_TRUE;
739
740 } else if (pj_strcmp2(&branch_param, TEST3_BRANCH_ID) == 0) {
741
742 /* TEST3_BRANCH_ID tests provisional response. */
743
744 if (msg->type == PJSIP_REQUEST_MSG) {
Benny Prijono728a9052006-01-18 23:34:15 +0000745 /* On received request, create UAS and respond with provisional
Benny Prijonodbe337a2006-01-08 23:57:52 +0000746 * response, then schedule timer to send final response.
747 */
748 pjsip_transaction *tsx;
Benny Prijonodbe337a2006-01-08 23:57:52 +0000749
750 status = pjsip_tsx_create_uas(&tsx_user, rdata, &tsx);
751 if (status != PJ_SUCCESS) {
752 app_perror(" error: unable to create transaction", status);
753 test_complete = -120;
754 return PJ_TRUE;
755 }
756
757 save_key(tsx);
758
Benny Prijono0c2bc612006-01-10 13:31:40 +0000759 send_response(rdata, tsx, TEST3_PROVISIONAL_CODE);
Benny Prijonodbe337a2006-01-08 23:57:52 +0000760 schedule_send_response(rdata, &tsx->transaction_key,
761 TEST3_STATUS_CODE, 2000);
762
763 } else {
764 /* Verify the response received. */
765
766 ++recv_count;
767
768 if (recv_count == 1) {
769 /* Verify status code. */
770 if (msg->line.status.code != TEST3_PROVISIONAL_CODE) {
771 PJ_LOG(3,(THIS_FILE, " error: incorrect status code"));
772 test_complete = -123;
773 }
774 } else if (recv_count == 2) {
775 /* Verify status code. */
776 if (msg->line.status.code != TEST3_STATUS_CODE) {
777 PJ_LOG(3,(THIS_FILE, " error: incorrect status code"));
778 test_complete = -124;
779 }
780 } else {
781 PJ_LOG(3,(THIS_FILE, " error: retransmission received"));
782 test_complete = -125;
783 }
784
785 }
786 return PJ_TRUE;
787
Benny Prijono0c2bc612006-01-10 13:31:40 +0000788 } else if (pj_strcmp2(&branch_param, TEST4_BRANCH_ID) == 0 ||
789 pj_strcmp2(&branch_param, TEST5_BRANCH_ID) == 0 ||
790 pj_strcmp2(&branch_param, TEST6_BRANCH_ID) == 0)
791 {
792
793 /* TEST4_BRANCH_ID: absorbs retransmissions in TRYING state. */
794 /* TEST5_BRANCH_ID: retransmit last response in PROCEEDING state. */
795 /* TEST6_BRANCH_ID: retransmit last response in COMPLETED state. */
796
797 if (msg->type == PJSIP_REQUEST_MSG) {
Benny Prijono728a9052006-01-18 23:34:15 +0000798 /* On received request, create UAS. */
Benny Prijono0c2bc612006-01-10 13:31:40 +0000799 pjsip_transaction *tsx;
800
801 status = pjsip_tsx_create_uas(&tsx_user, rdata, &tsx);
802 if (status != PJ_SUCCESS) {
803 app_perror(" error: unable to create transaction", status);
804 test_complete = -130;
805 return PJ_TRUE;
806 }
807
808 save_key(tsx);
809
810 if (pj_strcmp2(&branch_param, TEST4_BRANCH_ID) == 0) {
811
812 } else if (pj_strcmp2(&branch_param, TEST5_BRANCH_ID) == 0) {
813 send_response(rdata, tsx, TEST5_PROVISIONAL_CODE);
814
815 } else if (pj_strcmp2(&branch_param, TEST6_BRANCH_ID) == 0) {
816 send_response(rdata, tsx, TEST6_PROVISIONAL_CODE);
817 send_response(rdata, tsx, TEST6_STATUS_CODE);
818 }
819
820 } else {
821 /* Verify the response received. */
822
823 ++recv_count;
824
825 if (pj_strcmp2(&branch_param, TEST4_BRANCH_ID) == 0) {
826 PJ_LOG(3,(THIS_FILE, " error: not expecting response!"));
827 test_complete = -132;
828
829 } else if (pj_strcmp2(&branch_param, TEST5_BRANCH_ID) == 0) {
830
831 if (rdata->msg_info.msg->line.status.code!=TEST5_PROVISIONAL_CODE) {
832 PJ_LOG(3,(THIS_FILE, " error: incorrect status code!"));
833 test_complete = -133;
834
835 }
836 if (recv_count > TEST5_RESPONSE_COUNT) {
837 PJ_LOG(3,(THIS_FILE, " error: not expecting response!"));
838 test_complete = -134;
839 }
840
841 } else if (pj_strcmp2(&branch_param, TEST6_BRANCH_ID) == 0) {
842
843 int code = rdata->msg_info.msg->line.status.code;
844
845 switch (recv_count) {
846 case 1:
847 if (code != TEST6_PROVISIONAL_CODE) {
848 PJ_LOG(3,(THIS_FILE, " error: invalid code!"));
849 test_complete = -135;
850 }
851 break;
852 case 2:
853 case 3:
854 if (code != TEST6_STATUS_CODE) {
855 PJ_LOG(3,(THIS_FILE, " error: invalid code!"));
856 test_complete = -136;
857 }
858 break;
859 default:
860 PJ_LOG(3,(THIS_FILE, " error: not expecting response"));
861 test_complete = -137;
862 break;
863 }
864 }
865 }
866 return PJ_TRUE;
867
868
869 } else if (pj_strcmp2(&branch_param, TEST7_BRANCH_ID) == 0 ||
870 pj_strcmp2(&branch_param, TEST8_BRANCH_ID) == 0)
871 {
872
873 /*
874 * TEST7_BRANCH_ID and TEST8_BRANCH_ID test the retransmission
875 * of INVITE final response
876 */
877 if (msg->type == PJSIP_REQUEST_MSG) {
878
Benny Prijono728a9052006-01-18 23:34:15 +0000879 /* On received request, create UAS. */
Benny Prijono0c2bc612006-01-10 13:31:40 +0000880 pjsip_transaction *tsx;
881
882 status = pjsip_tsx_create_uas(&tsx_user, rdata, &tsx);
883 if (status != PJ_SUCCESS) {
884 app_perror(" error: unable to create transaction", status);
885 test_complete = -140;
886 return PJ_TRUE;
887 }
888
889 save_key(tsx);
890
891 if (pj_strcmp2(&branch_param, TEST7_BRANCH_ID) == 0) {
892
893 send_response(rdata, tsx, TEST7_STATUS_CODE);
894
895 } else {
896
897 send_response(rdata, tsx, TEST8_STATUS_CODE);
898
899 }
900
901 } else {
902 int code;
903
904 ++recv_count;
905
906 if (pj_strcmp2(&branch_param, TEST7_BRANCH_ID) == 0)
907 code = TEST7_STATUS_CODE;
908 else
909 code = TEST8_STATUS_CODE;
910
911 if (recv_count==1) {
912
913 if (rdata->msg_info.msg->line.status.code != code) {
914 PJ_LOG(3,(THIS_FILE," error: invalid status code"));
915 test_complete = -141;
916 }
917
918 recv_last = rdata->pkt_info.timestamp;
919
920 } else {
921
922 pj_time_val now;
923 unsigned msec, msec_expected;
924
925 now = rdata->pkt_info.timestamp;
926
927 PJ_TIME_VAL_SUB(now, recv_last);
928
929 msec = now.sec*1000 + now.msec;
930 msec_expected = (1 << (recv_count-2)) * PJSIP_T1_TIMEOUT;
931 if (msec_expected > PJSIP_T2_TIMEOUT)
932 msec_expected = PJSIP_T2_TIMEOUT;
933
934 if (DIFF(msec, msec_expected) > MAX_ALLOWED_DIFF) {
935 PJ_LOG(3,(THIS_FILE,
936 " error: incorrect retransmission "
937 "time (%d ms expected, %d ms received",
938 msec_expected, msec));
939 test_complete = -142;
940 }
941
942 if (recv_count > 11) {
943 PJ_LOG(3,(THIS_FILE," error: too many responses (%d)",
944 recv_count));
945 test_complete = -143;
946 }
947
948 recv_last = rdata->pkt_info.timestamp;
949 }
950
951 }
952 return PJ_TRUE;
953
Benny Prijono728a9052006-01-18 23:34:15 +0000954 } else if (pj_strcmp2(&branch_param, TEST9_BRANCH_ID) == 0) {
Benny Prijono0c2bc612006-01-10 13:31:40 +0000955
956 /*
957 * TEST9_BRANCH_ID tests that the retransmission of INVITE final
958 * response should cease when ACK is received. Transaction also MUST
959 * terminate in T4 seconds.
960 */
961 if (msg->type == PJSIP_REQUEST_MSG) {
962
Benny Prijono728a9052006-01-18 23:34:15 +0000963 /* On received request, create UAS. */
Benny Prijono0c2bc612006-01-10 13:31:40 +0000964 pjsip_transaction *tsx;
965
966 status = pjsip_tsx_create_uas(&tsx_user, rdata, &tsx);
967 if (status != PJ_SUCCESS) {
968 app_perror(" error: unable to create transaction", status);
Benny Prijono728a9052006-01-18 23:34:15 +0000969 test_complete = -150;
Benny Prijono0c2bc612006-01-10 13:31:40 +0000970 return PJ_TRUE;
971 }
972
973 save_key(tsx);
Benny Prijono728a9052006-01-18 23:34:15 +0000974 send_response(rdata, tsx, TEST9_STATUS_CODE);
Benny Prijono0c2bc612006-01-10 13:31:40 +0000975
Benny Prijono0c2bc612006-01-10 13:31:40 +0000976
977 } else {
Benny Prijono0c2bc612006-01-10 13:31:40 +0000978
979 ++recv_count;
980
Benny Prijono728a9052006-01-18 23:34:15 +0000981 if (rdata->msg_info.msg->line.status.code != TEST9_STATUS_CODE) {
982 PJ_LOG(3,(THIS_FILE," error: invalid status code"));
983 test_complete = -151;
984 }
Benny Prijono0c2bc612006-01-10 13:31:40 +0000985
986 if (recv_count==1) {
Benny Prijono0c2bc612006-01-10 13:31:40 +0000987
988 recv_last = rdata->pkt_info.timestamp;
989
Benny Prijono728a9052006-01-18 23:34:15 +0000990 } else if (recv_count < 5) {
Benny Prijono0c2bc612006-01-10 13:31:40 +0000991
Benny Prijono728a9052006-01-18 23:34:15 +0000992 /* Let UAS retransmit some messages before we send ACK. */
Benny Prijono0c2bc612006-01-10 13:31:40 +0000993 pj_time_val now;
994 unsigned msec, msec_expected;
995
996 now = rdata->pkt_info.timestamp;
997
998 PJ_TIME_VAL_SUB(now, recv_last);
999
1000 msec = now.sec*1000 + now.msec;
1001 msec_expected = (1 << (recv_count-2)) * PJSIP_T1_TIMEOUT;
1002 if (msec_expected > PJSIP_T2_TIMEOUT)
1003 msec_expected = PJSIP_T2_TIMEOUT;
1004
1005 if (DIFF(msec, msec_expected) > MAX_ALLOWED_DIFF) {
1006 PJ_LOG(3,(THIS_FILE,
1007 " error: incorrect retransmission "
1008 "time (%d ms expected, %d ms received",
1009 msec_expected, msec));
Benny Prijono728a9052006-01-18 23:34:15 +00001010 test_complete = -152;
Benny Prijono0c2bc612006-01-10 13:31:40 +00001011 }
1012
1013 recv_last = rdata->pkt_info.timestamp;
Benny Prijono728a9052006-01-18 23:34:15 +00001014
1015 } else if (recv_count == 5) {
1016 pjsip_tx_data *tdata;
1017 pjsip_sip_uri *uri;
1018 pjsip_via_hdr *via;
1019
1020 status = pjsip_endpt_create_request_from_hdr(
1021 endpt, &pjsip_ack_method,
1022 rdata->msg_info.to->uri,
1023 rdata->msg_info.from,
1024 rdata->msg_info.to,
1025 NULL,
1026 rdata->msg_info.cid,
1027 rdata->msg_info.cseq->cseq,
1028 NULL,
1029 &tdata);
1030 if (status != PJ_SUCCESS) {
1031 app_perror(" error: unable to create ACK", status);
1032 test_complete = -153;
1033 return PJ_TRUE;
1034 }
1035
1036 uri=(pjsip_sip_uri*)pjsip_uri_get_uri(tdata->msg->line.req.uri);
1037 uri->transport_param = pj_str("loop-dgram");
1038
1039 via = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL);
1040 via->branch_param = pj_str(TEST9_BRANCH_ID);
1041
1042 status = pjsip_endpt_send_request_stateless(endpt, tdata,
1043 NULL, NULL);
1044 if (status != PJ_SUCCESS) {
1045 app_perror(" error: unable to send ACK", status);
1046 test_complete = -154;
1047 }
1048
1049 } else {
1050 PJ_LOG(3,(THIS_FILE," error: too many responses (%d)",
1051 recv_count));
1052 test_complete = -155;
Benny Prijono0c2bc612006-01-10 13:31:40 +00001053 }
1054
1055 }
1056 return PJ_TRUE;
Benny Prijono728a9052006-01-18 23:34:15 +00001057
1058 } else if (pj_strcmp2(&branch_param, TEST10_BRANCH_ID) == 0 ||
1059 pj_strcmp2(&branch_param, TEST11_BRANCH_ID) == 0 ||
1060 pj_strcmp2(&branch_param, TEST12_BRANCH_ID) == 0)
1061 {
1062 int test_num, code1, code2;
1063
1064 if (pj_strcmp2(&branch_param, TEST10_BRANCH_ID) == 0)
1065 test_num=10, code1 = 100, code2 = 0;
1066 else if (pj_strcmp2(&branch_param, TEST11_BRANCH_ID) == 0)
1067 test_num=11, code1 = 100, code2 = 200;
1068 else
1069 test_num=12, code1 = 200, code2 = 0;
1070
1071 if (rdata->msg_info.msg->type == PJSIP_REQUEST_MSG) {
1072
1073 /* On received response, create UAS. */
1074 pjsip_transaction *tsx;
1075
1076 status = pjsip_tsx_create_uas(&tsx_user, rdata, &tsx);
1077 if (status != PJ_SUCCESS) {
1078 app_perror(" error: unable to create transaction", status);
1079 test_complete = -150;
1080 return PJ_TRUE;
1081 }
1082
1083 save_key(tsx);
1084
1085 schedule_send_response(rdata, &tsx_key, code1, 1000);
1086
1087 if (code2)
1088 schedule_send_response(rdata, &tsx_key, code2, 2000);
1089
1090 } else {
1091
1092 }
1093
1094 return PJ_TRUE;
Benny Prijonodbe337a2006-01-08 23:57:52 +00001095 }
1096
1097 return PJ_FALSE;
1098}
1099
1100/*
1101 * The generic test framework, used by most of the tests.
1102 */
1103static int perform_test( char *target_uri, char *from_uri,
1104 char *branch_param, int test_time,
Benny Prijono0c2bc612006-01-10 13:31:40 +00001105 const pjsip_method *method,
1106 int request_cnt, int request_interval_msec,
1107 int expecting_timeout)
Benny Prijonodbe337a2006-01-08 23:57:52 +00001108{
1109 pjsip_tx_data *tdata;
1110 pj_str_t target, from;
1111 pjsip_via_hdr *via;
Benny Prijono0c2bc612006-01-10 13:31:40 +00001112 pj_time_val timeout, next_send;
1113 int sent_cnt;
Benny Prijonodbe337a2006-01-08 23:57:52 +00001114 pj_status_t status;
1115
1116 PJ_LOG(3,(THIS_FILE,
1117 " please standby, this will take at most %d seconds..",
1118 test_time));
1119
1120 /* Reset test. */
1121 recv_count = 0;
1122 test_complete = 0;
1123 tsx_key.slen = 0;
1124
1125 /* Init headers. */
1126 target = pj_str(target_uri);
1127 from = pj_str(from_uri);
1128
1129 /* Create request. */
1130 status = pjsip_endpt_create_request( endpt, method, &target,
1131 &from, &target, NULL, NULL, -1,
1132 NULL, &tdata);
1133 if (status != PJ_SUCCESS) {
1134 app_perror(" Error: unable to create request", status);
1135 return -10;
1136 }
1137
1138 /* Set the branch param for test 1. */
1139 via = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL);
1140 via->branch_param = pj_str(branch_param);
1141
Benny Prijono0c2bc612006-01-10 13:31:40 +00001142 /* Schedule first send. */
1143 sent_cnt = 0;
1144 pj_gettimeofday(&next_send);
1145 pj_time_val_normalize(&next_send);
Benny Prijonodbe337a2006-01-08 23:57:52 +00001146
1147 /* Set test completion time. */
1148 pj_gettimeofday(&timeout);
1149 timeout.sec += test_time;
1150
1151 /* Wait until test complete. */
1152 while (!test_complete) {
1153 pj_time_val now, poll_delay = {0, 10};
1154
1155 pjsip_endpt_handle_events(endpt, &poll_delay);
1156
1157 pj_gettimeofday(&now);
Benny Prijono0c2bc612006-01-10 13:31:40 +00001158
1159 if (sent_cnt < request_cnt && PJ_TIME_VAL_GTE(now, next_send)) {
1160 /* Add additional reference to tdata to prevent transaction from
1161 * deleting it.
1162 */
1163 pjsip_tx_data_add_ref(tdata);
1164
1165 /* (Re)Send the request. */
1166 status = pjsip_endpt_send_request_stateless(endpt, tdata, 0, 0);
1167 if (status != PJ_SUCCESS) {
1168 app_perror(" Error: unable to send request", status);
1169 pjsip_tx_data_dec_ref(tdata);
1170 return -20;
1171 }
1172
1173 /* Schedule next send, if any. */
1174 sent_cnt++;
1175 if (sent_cnt < request_cnt) {
1176 pj_gettimeofday(&next_send);
1177 next_send.msec += request_interval_msec;
1178 pj_time_val_normalize(&next_send);
1179 }
1180 }
1181
Benny Prijonodbe337a2006-01-08 23:57:52 +00001182 if (now.sec > timeout.sec) {
Benny Prijono0c2bc612006-01-10 13:31:40 +00001183 if (!expecting_timeout)
1184 PJ_LOG(3,(THIS_FILE, " Error: test has timed out"));
Benny Prijonodbe337a2006-01-08 23:57:52 +00001185 pjsip_tx_data_dec_ref(tdata);
Benny Prijono0c2bc612006-01-10 13:31:40 +00001186 return TEST_TIMEOUT_ERROR;
Benny Prijonodbe337a2006-01-08 23:57:52 +00001187 }
1188 }
1189
1190 if (test_complete < 0) {
1191 pjsip_transaction *tsx;
1192
1193 tsx = pjsip_tsx_layer_find_tsx(&tsx_key, PJ_TRUE);
1194 if (tsx) {
1195 pjsip_tsx_terminate(tsx, PJSIP_SC_REQUEST_TERMINATED);
1196 pj_mutex_unlock(tsx->mutex);
1197 flush_events(1000);
1198 }
1199 pjsip_tx_data_dec_ref(tdata);
1200 return test_complete;
1201 }
1202
1203 /* Allow transaction to destroy itself */
1204 flush_events(500);
1205
1206 /* Make sure transaction has been destroyed. */
1207 if (pjsip_tsx_layer_find_tsx(&tsx_key, PJ_FALSE) != NULL) {
1208 PJ_LOG(3,(THIS_FILE, " Error: transaction has not been destroyed"));
1209 pjsip_tx_data_dec_ref(tdata);
1210 return -40;
1211 }
1212
1213 /* Check tdata reference counter. */
1214 if (pj_atomic_get(tdata->ref_cnt) != 1) {
1215 PJ_LOG(3,(THIS_FILE, " Error: tdata reference counter is %d",
1216 pj_atomic_get(tdata->ref_cnt)));
1217 pjsip_tx_data_dec_ref(tdata);
1218 return -50;
1219 }
1220
1221 /* Destroy txdata */
1222 pjsip_tx_data_dec_ref(tdata);
1223
1224 return PJ_SUCCESS;
1225
1226}
1227
1228
1229/*****************************************************************************
1230 **
1231 ** TEST1_BRANCH_ID: Basic 2xx final response
1232 ** TEST2_BRANCH_ID: Basic non-2xx final response
1233 **
1234 *****************************************************************************
1235 */
1236static int tsx_basic_final_response_test(void)
1237{
1238 int status;
1239
1240 PJ_LOG(3,(THIS_FILE," test1: basic sending 2xx final response"));
1241
1242 status = perform_test("sip:129.0.0.1;transport=loop-dgram",
1243 "sip:129.0.0.1;transport=loop-dgram",
1244 TEST1_BRANCH_ID,
1245 33, /* Test duration must be greater than 32 secs */
Benny Prijono0c2bc612006-01-10 13:31:40 +00001246 &pjsip_options_method, 1, 0, 0);
Benny Prijonodbe337a2006-01-08 23:57:52 +00001247 if (status != 0)
1248 return status;
1249
1250 PJ_LOG(3,(THIS_FILE," test2: basic sending non-2xx final response"));
1251
1252 status = perform_test("sip:129.0.0.1;transport=loop-dgram",
1253 "sip:129.0.0.1;transport=loop-dgram",
1254 TEST2_BRANCH_ID,
1255 33, /* Test duration must be greater than 32 secs */
Benny Prijono0c2bc612006-01-10 13:31:40 +00001256 &pjsip_options_method, 1, 0, 0);
Benny Prijonodbe337a2006-01-08 23:57:52 +00001257 if (status != 0)
1258 return status;
1259
1260 return 0;
1261}
1262
1263
1264/*****************************************************************************
1265 **
1266 ** TEST3_BRANCH_ID: Sending provisional response
1267 **
1268 *****************************************************************************
1269 */
1270static int tsx_basic_provisional_response_test(void)
1271{
1272 int status;
1273
1274 PJ_LOG(3,(THIS_FILE," test1: basic sending 2xx final response"));
1275
1276 status = perform_test("sip:129.0.0.1;transport=loop-dgram",
1277 "sip:129.0.0.1;transport=loop-dgram",
1278 TEST3_BRANCH_ID,
1279 35,
Benny Prijono0c2bc612006-01-10 13:31:40 +00001280 &pjsip_options_method, 1, 0, 0);
1281
Benny Prijonodbe337a2006-01-08 23:57:52 +00001282 return status;
1283}
1284
1285
1286/*****************************************************************************
1287 **
Benny Prijono0c2bc612006-01-10 13:31:40 +00001288 ** TEST4_BRANCH_ID: Absorbs retransmissions in TRYING state
1289 ** TEST5_BRANCH_ID: Absorbs retransmissions in PROCEEDING state
1290 ** TEST6_BRANCH_ID: Absorbs retransmissions in COMPLETED state
1291 **
1292 *****************************************************************************
1293 */
1294static int tsx_retransmit_last_response_test(const char *title,
1295 char *branch_id,
1296 int request_cnt,
1297 int status_code)
1298{
1299 int status;
1300
1301 PJ_LOG(3,(THIS_FILE," %s", title));
1302
1303 status = perform_test("sip:129.0.0.1;transport=loop-dgram",
1304 "sip:129.0.0.1;transport=loop-dgram",
1305 branch_id,
1306 5,
1307 &pjsip_options_method,
1308 request_cnt, 1000, 1);
1309 if (status && status != TEST_TIMEOUT_ERROR)
1310 return status;
1311 if (!status) {
1312 PJ_LOG(3,(THIS_FILE, " error: expecting timeout"));
1313 return -31;
1314 }
1315
1316 terminate_our_tsx(status_code);
1317 flush_events(100);
1318
1319 if (test_complete != 1)
1320 return test_complete;
1321
1322 flush_events(100);
1323 return 0;
1324}
1325
1326/*****************************************************************************
1327 **
1328 ** TEST7_BRANCH_ID: INVITE non-2xx final response retransmission test
1329 ** TEST8_BRANCH_ID: INVITE 2xx final response retransmission test
1330 **
1331 *****************************************************************************
1332 */
1333static int tsx_final_response_retransmission_test(void)
1334{
1335 int status;
1336
1337 PJ_LOG(3,(THIS_FILE,
1338 " test7: INVITE non-2xx final response retransmission"));
1339
1340 status = perform_test("sip:129.0.0.1;transport=loop-dgram",
1341 "sip:129.0.0.1;transport=loop-dgram",
1342 TEST7_BRANCH_ID,
1343 33, /* Test duration must be greater than 32 secs */
1344 &pjsip_invite_method, 1, 0, 0);
1345 if (status != 0)
1346 return status;
1347
1348 PJ_LOG(3,(THIS_FILE,
1349 " test8: INVITE 2xx final response retransmission"));
1350
1351 status = perform_test("sip:129.0.0.1;transport=loop-dgram",
1352 "sip:129.0.0.1;transport=loop-dgram",
1353 TEST8_BRANCH_ID,
1354 33, /* Test duration must be greater than 32 secs */
1355 &pjsip_invite_method, 1, 0, 0);
1356 if (status != 0)
1357 return status;
1358
1359 return 0;
1360}
1361
1362
Benny Prijono728a9052006-01-18 23:34:15 +00001363/*****************************************************************************
1364 **
1365 ** TEST9_BRANCH_ID: retransmission of non-2xx INVITE final response must
1366 ** cease when ACK is received
1367 **
1368 *****************************************************************************
1369 */
1370static int tsx_ack_test(void)
1371{
1372 int status;
1373
1374 PJ_LOG(3,(THIS_FILE,
1375 " test9: receiving ACK for non-2xx final response"));
1376
1377 status = perform_test("sip:129.0.0.1;transport=loop-dgram",
1378 "sip:129.0.0.1;transport=loop-dgram",
1379 TEST9_BRANCH_ID,
1380 20, /* allow 5 retransmissions */
1381 &pjsip_invite_method, 1, 0, 0);
1382 if (status != 0)
1383 return status;
1384
1385
1386 return 0;
1387}
1388
1389
1390
1391/*****************************************************************************
1392 **
1393 ** TEST10_BRANCH_ID: test transport failure in TRYING state.
1394 ** TEST11_BRANCH_ID: test transport failure in PROCEEDING state.
1395 ** TEST12_BRANCH_ID: test transport failure in CONNECTED state.
1396 ** TEST13_BRANCH_ID: test transport failure in CONFIRMED state.
1397 **
1398 *****************************************************************************
1399 */
1400static int tsx_transport_failure_test(void)
1401{
1402 struct test_desc
1403 {
1404 int transport_delay;
1405 int fail_delay;
1406 char *branch_id;
1407 char *title;
1408 } tests[] =
1409 {
1410 { 0, 10, TEST10_BRANCH_ID, "test10: failed transport in TRYING state (no delay)" },
1411 { 50, 10, TEST10_BRANCH_ID, "test10: failed transport in TRYING state (50 ms delay)" },
1412 { 0, 1500, TEST11_BRANCH_ID, "test11: failed transport in PROCEEDING state (no delay)" },
1413 { 50, 1500, TEST11_BRANCH_ID, "test11: failed transport in PROCEEDING state (50 ms delay)" },
1414 { 0, 2500, TEST12_BRANCH_ID, "test12: failed transport in COMPLETED state (no delay)" },
1415 { 50, 2500, TEST12_BRANCH_ID, "test12: failed transport in COMPLETED state (50 ms delay)" },
1416 };
1417 int i, status;
1418
1419 for (i=0; i<PJ_ARRAY_SIZE(tests); ++i) {
1420 pj_time_val fail_time, end_test, now;
1421
1422 PJ_LOG(3,(THIS_FILE, " %s", tests[i].title));
1423 pjsip_loop_set_failure(loop, 0, NULL);
1424 pjsip_loop_set_delay(loop, tests[i].transport_delay);
1425
1426 status = perform_test("sip:129.0.0.1;transport=loop-dgram",
1427 "sip:129.0.0.1;transport=loop-dgram",
1428 tests[i].branch_id,
1429 0,
1430 &pjsip_invite_method, 1, 0, 1);
1431 if (status && status != TEST_TIMEOUT_ERROR)
1432 return status;
1433 if (!status) {
1434 PJ_LOG(3,(THIS_FILE, " error: expecting timeout"));
1435 return -40;
1436 }
1437
1438 pj_gettimeofday(&fail_time);
1439 fail_time.msec += tests[i].fail_delay;
1440 pj_time_val_normalize(&fail_time);
1441
1442 do {
1443 pj_time_val interval = { 0, 1 };
1444 pj_gettimeofday(&now);
1445 pjsip_endpt_handle_events(endpt, &interval);
1446 } while (PJ_TIME_VAL_LT(now, fail_time));
1447
1448 pjsip_loop_set_failure(loop, 1, NULL);
1449
1450 end_test = now;
1451 end_test.sec += 5;
1452
1453 do {
1454 pj_time_val interval = { 0, 1 };
1455 pj_gettimeofday(&now);
1456 pjsip_endpt_handle_events(endpt, &interval);
1457 } while (!test_complete && PJ_TIME_VAL_LT(now, end_test));
1458
1459 if (test_complete == 0) {
1460 PJ_LOG(3,(THIS_FILE, " error: test has timed out"));
1461 return -41;
1462 }
1463
1464 if (test_complete != 1)
1465 return test_complete;
1466 }
1467
1468 return 0;
1469}
Benny Prijono0c2bc612006-01-10 13:31:40 +00001470
1471/*****************************************************************************
1472 **
Benny Prijonodbe337a2006-01-08 23:57:52 +00001473 ** UAS Transaction Test.
1474 **
1475 *****************************************************************************
1476 */
1477int tsx_uas_test(void)
1478{
1479 pj_sockaddr_in addr;
1480 pj_status_t status;
1481
1482 /* Check if loop transport is configured. */
1483 status = pjsip_endpt_acquire_transport(endpt, PJSIP_TRANSPORT_LOOP_DGRAM,
1484 &addr, sizeof(addr), &loop);
1485 if (status != PJ_SUCCESS) {
1486 PJ_LOG(3,(THIS_FILE, " Error: loop transport is not configured!"));
1487 return -1;
1488 }
1489
1490 /* Register modules. */
1491 status = pjsip_endpt_register_module(endpt, &tsx_user);
1492 if (status != PJ_SUCCESS) {
1493 app_perror(" Error: unable to register module", status);
1494 return -3;
1495 }
1496 status = pjsip_endpt_register_module(endpt, &msg_sender);
1497 if (status != PJ_SUCCESS) {
1498 app_perror(" Error: unable to register module", status);
1499 return -4;
1500 }
1501
Benny Prijonodbe337a2006-01-08 23:57:52 +00001502 /* TEST1_BRANCH_ID: Basic 2xx final response.
1503 * TEST2_BRANCH_ID: Basic non-2xx final response.
1504 */
1505 status = tsx_basic_final_response_test();
1506 if (status != 0)
1507 return status;
Benny Prijonodbe337a2006-01-08 23:57:52 +00001508
1509 /* TEST3_BRANCH_ID: with provisional response
1510 */
1511 status = tsx_basic_provisional_response_test();
1512 if (status != 0)
1513 return status;
1514
Benny Prijono0c2bc612006-01-10 13:31:40 +00001515 /* TEST4_BRANCH_ID: absorbs retransmissions in TRYING state
1516 */
1517 status = tsx_retransmit_last_response_test(TEST4_TITLE,
1518 TEST4_BRANCH_ID,
1519 TEST4_REQUEST_COUNT,
1520 TEST4_STATUS_CODE);
1521 if (status != 0)
1522 return status;
1523
1524 /* TEST5_BRANCH_ID: retransmit last response in PROCEEDING state
1525 */
1526 status = tsx_retransmit_last_response_test(TEST5_TITLE,
1527 TEST5_BRANCH_ID,
1528 TEST5_REQUEST_COUNT,
1529 TEST5_STATUS_CODE);
1530 if (status != 0)
1531 return status;
1532
1533 /* TEST6_BRANCH_ID: retransmit last response in PROCEEDING state
1534 */
1535 status = tsx_retransmit_last_response_test(TEST6_TITLE,
1536 TEST6_BRANCH_ID,
1537 TEST6_REQUEST_COUNT,
1538 TEST6_STATUS_CODE);
1539 if (status != 0)
1540 return status;
1541
1542 /* TEST7_BRANCH_ID: INVITE non-2xx final response retransmission test
1543 * TEST8_BRANCH_ID: INVITE 2xx final response retransmission test
1544 */
1545
1546 status = tsx_final_response_retransmission_test();
1547 if (status != 0)
1548 return status;
1549
Benny Prijono728a9052006-01-18 23:34:15 +00001550 /* TEST9_BRANCH_ID: retransmission of non-2xx INVITE final response must
1551 * cease when ACK is received
1552 */
1553 status = tsx_ack_test();
1554 if (status != 0)
1555 return status;
1556
1557 /* TEST10_BRANCH_ID: test transport failure in TRYING state.
1558 * TEST11_BRANCH_ID: test transport failure in PROCEEDING state.
1559 * TEST12_BRANCH_ID: test transport failure in CONNECTED state.
1560 * TEST13_BRANCH_ID: test transport failure in CONFIRMED state.
1561 */
1562 status = tsx_transport_failure_test();
1563 if (status != 0)
1564 return status;
1565
Benny Prijonodbe337a2006-01-08 23:57:52 +00001566
1567 pjsip_transport_dec_ref(loop);
1568 return 0;
1569
1570}
1571