blob: 3ff2e18eec87d9498e66e9bea9e53ab9db51d886 [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"
Benny Prijono40f2f642006-01-30 18:40:05 +000021#include <pjsip.h>
Benny Prijonodbe337a2006-01-08 23:57:52 +000022#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 */
Benny Prijonodbe337a2006-01-08 23:57:52 +0000144 NULL, /* load() */
145 NULL, /* start() */
146 NULL, /* stop() */
147 NULL, /* unload() */
148 NULL, /* on_rx_request() */
149 NULL, /* on_rx_response() */
150 NULL, /* on_tx_request() */
151 NULL, /* on_tx_response() */
152 &tsx_user_on_tsx_state, /* on_tsx_state() */
153};
154
155/* Module to send request. */
156static pjsip_module msg_sender =
157{
158 NULL, NULL, /* prev and next */
159 { "Msg-Sender", 10}, /* Name. */
160 -1, /* Id */
161 PJSIP_MOD_PRIORITY_APPLICATION-1, /* Priority */
Benny Prijonodbe337a2006-01-08 23:57:52 +0000162 NULL, /* load() */
163 NULL, /* start() */
164 NULL, /* stop() */
165 NULL, /* unload() */
166 &on_rx_message, /* on_rx_request() */
167 &on_rx_message, /* on_rx_response() */
168 NULL, /* on_tx_request() */
169 NULL, /* on_tx_response() */
170 NULL, /* on_tsx_state() */
171};
172
173/* Static vars, which will be reset on each test. */
174static int recv_count;
175static pj_time_val recv_last;
176static pj_bool_t test_complete;
177
178/* Loop transport instance. */
179static pjsip_transport *loop;
180
181/* UAS transaction key. */
182static char key_buf[64];
183static pj_str_t tsx_key = { key_buf, 0 };
184
185
186/* General timer entry to be used by tests. */
187static pj_timer_entry timer;
188
189/* Timer to send response via transaction. */
190struct response
191{
192 pj_str_t tsx_key;
193 pjsip_tx_data *tdata;
194};
195
Benny Prijono0c2bc612006-01-10 13:31:40 +0000196/* Timer callback to send response. */
Benny Prijonodbe337a2006-01-08 23:57:52 +0000197static void send_response_timer( pj_timer_heap_t *timer_heap,
198 struct pj_timer_entry *entry)
199{
200 pjsip_transaction *tsx;
201 struct response *r = entry->user_data;
202 pj_status_t status;
203
204 tsx = pjsip_tsx_layer_find_tsx(&r->tsx_key, PJ_TRUE);
205 if (!tsx) {
206 PJ_LOG(3,(THIS_FILE," error: timer unable to find transaction"));
207 pjsip_tx_data_dec_ref(r->tdata);
208 return;
209 }
210
211 status = pjsip_tsx_send_msg(tsx, r->tdata);
212 if (status != PJ_SUCCESS) {
Benny Prijono728a9052006-01-18 23:34:15 +0000213 // Some tests do expect failure!
214 //PJ_LOG(3,(THIS_FILE," error: timer unable to send response"));
215 pj_mutex_unlock(tsx->mutex);
Benny Prijonodbe337a2006-01-08 23:57:52 +0000216 pjsip_tx_data_dec_ref(r->tdata);
217 return;
218 }
Benny Prijono728a9052006-01-18 23:34:15 +0000219
220 pj_mutex_unlock(tsx->mutex);
Benny Prijonodbe337a2006-01-08 23:57:52 +0000221}
222
Benny Prijono0c2bc612006-01-10 13:31:40 +0000223/* Utility to send response. */
224static void send_response( pjsip_rx_data *rdata,
225 pjsip_transaction *tsx,
226 int status_code )
227{
228 pj_status_t status;
229 pjsip_tx_data *tdata;
230
231 status = pjsip_endpt_create_response( endpt, rdata, status_code, NULL,
232 &tdata);
233 if (status != PJ_SUCCESS) {
234 app_perror(" error: unable to create response", status);
235 test_complete = -196;
236 return;
237 }
238
239 status = pjsip_tsx_send_msg(tsx, tdata);
240 if (status != PJ_SUCCESS) {
Benny Prijono0c2bc612006-01-10 13:31:40 +0000241 pjsip_tx_data_dec_ref(tdata);
Benny Prijono728a9052006-01-18 23:34:15 +0000242 // Some tests do expect failure!
243 //app_perror(" error: unable to send response", status);
244 //test_complete = -197;
Benny Prijono0c2bc612006-01-10 13:31:40 +0000245 return;
246 }
247}
248
Benny Prijonodbe337a2006-01-08 23:57:52 +0000249/* Schedule timer to send response for the specified UAS transaction */
250static void schedule_send_response( pjsip_rx_data *rdata,
251 const pj_str_t *tsx_key,
252 int status_code,
253 int msec_delay )
254{
255 pj_status_t status;
256 pjsip_tx_data *tdata;
Benny Prijono728a9052006-01-18 23:34:15 +0000257 pj_timer_entry *t;
Benny Prijonodbe337a2006-01-08 23:57:52 +0000258 struct response *r;
259 pj_time_val delay;
260
261 status = pjsip_endpt_create_response( endpt, rdata, status_code, NULL,
262 &tdata);
263 if (status != PJ_SUCCESS) {
264 app_perror(" error: unable to create response", status);
265 test_complete = -198;
266 return;
267 }
268
269 r = pj_pool_alloc(tdata->pool, sizeof(*r));
270 pj_strdup(tdata->pool, &r->tsx_key, tsx_key);
271 r->tdata = tdata;
272
273 delay.sec = 0;
274 delay.msec = msec_delay;
275 pj_time_val_normalize(&delay);
276
Benny Prijono728a9052006-01-18 23:34:15 +0000277 t = pj_pool_zalloc(tdata->pool, sizeof(*t));
278 t->user_data = r;
279 t->cb = &send_response_timer;
Benny Prijonodbe337a2006-01-08 23:57:52 +0000280
Benny Prijono728a9052006-01-18 23:34:15 +0000281 status = pjsip_endpt_schedule_timer(endpt, t, &delay);
Benny Prijonodbe337a2006-01-08 23:57:52 +0000282 if (status != PJ_SUCCESS) {
Benny Prijono728a9052006-01-18 23:34:15 +0000283 pjsip_tx_data_dec_ref(tdata);
Benny Prijonodbe337a2006-01-08 23:57:52 +0000284 app_perror(" error: unable to schedule timer", status);
285 test_complete = -199;
Benny Prijonodbe337a2006-01-08 23:57:52 +0000286 return;
287 }
288}
289
Benny Prijono0c2bc612006-01-10 13:31:40 +0000290
291/* Find and terminate tsx with the specified key. */
292static void terminate_our_tsx(int status_code)
293{
294 pjsip_transaction *tsx;
295
296 tsx = pjsip_tsx_layer_find_tsx(&tsx_key, PJ_TRUE);
297 if (!tsx) {
298 PJ_LOG(3,(THIS_FILE," error: timer unable to find transaction"));
299 return;
300 }
301
302 pjsip_tsx_terminate(tsx, status_code);
303 pj_mutex_unlock(tsx->mutex);
304}
305
306/* Timer callback to terminate transaction. */
307static void terminate_tsx_timer( pj_timer_heap_t *timer_heap,
308 struct pj_timer_entry *entry)
309{
310 terminate_our_tsx(entry->id);
311}
312
313
314/* Schedule timer to terminate transaction. */
315static void schedule_terminate_tsx( pjsip_transaction *tsx,
316 int status_code,
317 int msec_delay )
318{
319 pj_time_val delay;
320
321 delay.sec = 0;
322 delay.msec = msec_delay;
323 pj_time_val_normalize(&delay);
324
325 pj_assert(pj_strcmp(&tsx->transaction_key, &tsx_key)==0);
326 timer.user_data = NULL;
327 timer.id = status_code;
328 timer.cb = &terminate_tsx_timer;
329 pjsip_endpt_schedule_timer(endpt, &timer, &delay);
330}
331
332
Benny Prijonodbe337a2006-01-08 23:57:52 +0000333/*
334 * This is the handler to receive state changed notification from the
335 * transaction. It is used to verify that the transaction behaves according
336 * to the test scenario.
337 */
338static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e)
339{
340 if (pj_strcmp2(&tsx->branch, TEST1_BRANCH_ID)==0 ||
341 pj_strcmp2(&tsx->branch, TEST2_BRANCH_ID)==0)
342 {
343 /*
344 * TEST1_BRANCH_ID tests that non-INVITE transaction transmits final
345 * response using correct transport and terminates transaction after
346 * T4 (PJSIP_T4_TIMEOUT, 5 seconds).
347 *
348 * TEST2_BRANCH_ID does similar test for non-2xx final response.
349 */
350 int status_code = (pj_strcmp2(&tsx->branch, TEST1_BRANCH_ID)==0) ?
351 TEST1_STATUS_CODE : TEST2_STATUS_CODE;
352
353 if (tsx->state == PJSIP_TSX_STATE_TERMINATED) {
354
355 test_complete = 1;
356
357 /* Check that status code is status_code. */
358 if (tsx->status_code != status_code) {
359 PJ_LOG(3,(THIS_FILE, " error: incorrect status code"));
360 test_complete = -100;
361 }
362
363 /* Previous state must be completed. */
364 if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_COMPLETED) {
365 PJ_LOG(3,(THIS_FILE, " error: incorrect prev_state"));
366 test_complete = -101;
367 }
368
369 } else if (tsx->state == PJSIP_TSX_STATE_COMPLETED) {
370
371 /* Previous state must be TRYING. */
372 if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_TRYING) {
373 PJ_LOG(3,(THIS_FILE, " error: incorrect prev_state"));
374 test_complete = -102;
375 }
376 }
377
378 }
379 else
380 if (pj_strcmp2(&tsx->branch, TEST3_BRANCH_ID)==0) {
381 /*
382 * TEST3_BRANCH_ID tests sending provisional response.
383 */
384 if (tsx->state == PJSIP_TSX_STATE_TERMINATED) {
385
386 test_complete = 1;
387
388 /* Check that status code is status_code. */
389 if (tsx->status_code != TEST3_STATUS_CODE) {
390 PJ_LOG(3,(THIS_FILE, " error: incorrect status code"));
391 test_complete = -110;
392 }
393
394 /* Previous state must be completed. */
395 if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_COMPLETED) {
396 PJ_LOG(3,(THIS_FILE, " error: incorrect prev_state"));
397 test_complete = -111;
398 }
399
400 } else if (tsx->state == PJSIP_TSX_STATE_PROCEEDING) {
401
402 /* Previous state must be TRYING. */
403 if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_TRYING) {
404 PJ_LOG(3,(THIS_FILE, " error: incorrect prev_state"));
405 test_complete = -112;
406 }
407
408 /* Check that status code is status_code. */
409 if (tsx->status_code != TEST3_PROVISIONAL_CODE) {
410 PJ_LOG(3,(THIS_FILE, " error: incorrect status code"));
411 test_complete = -113;
412 }
413
414 /* Check that event must be TX_MSG */
415 if (e->body.tsx_state.type != PJSIP_EVENT_TX_MSG) {
416 PJ_LOG(3,(THIS_FILE, " error: incorrect event"));
417 test_complete = -114;
418 }
419
420 } else if (tsx->state == PJSIP_TSX_STATE_COMPLETED) {
421
422 /* Previous state must be PROCEEDING. */
423 if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_PROCEEDING) {
424 PJ_LOG(3,(THIS_FILE, " error: incorrect prev_state"));
425 test_complete = -115;
426 }
427
428 /* Check that status code is status_code. */
429 if (tsx->status_code != TEST3_STATUS_CODE) {
430 PJ_LOG(3,(THIS_FILE, " error: incorrect status code"));
431 test_complete = -116;
432 }
433
434 /* Check that event must be TX_MSG */
435 if (e->body.tsx_state.type != PJSIP_EVENT_TX_MSG) {
436 PJ_LOG(3,(THIS_FILE, " error: incorrect event"));
437 test_complete = -117;
438 }
439
440 }
441
Benny Prijono0c2bc612006-01-10 13:31:40 +0000442 } else
443 if (pj_strcmp2(&tsx->branch, TEST4_BRANCH_ID)==0) {
444 /*
445 * TEST4_BRANCH_ID tests receiving retransmissions in TRYING state.
446 */
Benny Prijono02b8fd82006-06-26 15:12:55 +0000447 if (tsx->state == PJSIP_TSX_STATE_TRYING) {
448 /* Request is received. */
449 } else if (tsx->state == PJSIP_TSX_STATE_TERMINATED) {
Benny Prijono0c2bc612006-01-10 13:31:40 +0000450
451 /* Check that status code is status_code. */
452 if (tsx->status_code != TEST4_STATUS_CODE) {
Benny Prijono02b8fd82006-06-26 15:12:55 +0000453 PJ_LOG(3,(THIS_FILE,
454 " error: incorrect status code %d "
455 "(expecting %d)", tsx->status_code,
456 TEST4_STATUS_CODE));
Benny Prijono0c2bc612006-01-10 13:31:40 +0000457 test_complete = -120;
458 }
459
460 /* Previous state. */
461 if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_TRYING) {
462 PJ_LOG(3,(THIS_FILE, " error: incorrect prev_state"));
463 test_complete = -121;
464 }
465
466 } else if (tsx->state != PJSIP_TSX_STATE_DESTROYED)
467 {
Benny Prijono02b8fd82006-06-26 15:12:55 +0000468 PJ_LOG(3,(THIS_FILE, " error: unexpected state %s (122)",
469 pjsip_tsx_state_str(tsx->state)));
Benny Prijono0c2bc612006-01-10 13:31:40 +0000470 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 */
Benny Prijono02b8fd82006-06-26 15:12:55 +0000480 if (tsx->state == PJSIP_TSX_STATE_TRYING) {
481 /* Request is received. */
482
483 } else if (tsx->state == PJSIP_TSX_STATE_TERMINATED) {
Benny Prijono0c2bc612006-01-10 13:31:40 +0000484
485 /* Check that status code is status_code. */
486 if (tsx->status_code != TEST5_STATUS_CODE) {
487 PJ_LOG(3,(THIS_FILE, " error: incorrect status code"));
488 test_complete = -130;
489 }
490
491 /* Previous state. */
492 if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_PROCEEDING) {
493 PJ_LOG(3,(THIS_FILE, " error: incorrect prev_state"));
494 test_complete = -131;
495 }
496
497 } else if (tsx->state == PJSIP_TSX_STATE_PROCEEDING) {
498
499 /* Check status code. */
500 if (tsx->status_code != TEST5_PROVISIONAL_CODE) {
501 PJ_LOG(3,(THIS_FILE, " error: incorrect status code"));
502 test_complete = -132;
503 }
504
505 } else if (tsx->state != PJSIP_TSX_STATE_DESTROYED) {
Benny Prijono02b8fd82006-06-26 15:12:55 +0000506 PJ_LOG(3,(THIS_FILE, " error: unexpected state %s (133)",
507 pjsip_tsx_state_str(tsx->state)));
Benny Prijono0c2bc612006-01-10 13:31:40 +0000508 test_complete = -133;
509
510 }
511
512 } else
513 if (pj_strcmp2(&tsx->branch, TEST6_BRANCH_ID)==0) {
514 /*
515 * TEST6_BRANCH_ID tests receiving retransmissions in COMPLETED state
516 */
Benny Prijono02b8fd82006-06-26 15:12:55 +0000517 if (tsx->state == PJSIP_TSX_STATE_TRYING) {
518 /* Request is received. */
519
520 } else if (tsx->state == PJSIP_TSX_STATE_TERMINATED) {
Benny Prijono0c2bc612006-01-10 13:31:40 +0000521
522 /* Check that status code is status_code. */
523 if (tsx->status_code != TEST6_STATUS_CODE) {
524 PJ_LOG(3,(THIS_FILE, " error: incorrect status code"));
525 test_complete = -140;
526 }
527
528 /* Previous state. */
529 if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_COMPLETED) {
530 PJ_LOG(3,(THIS_FILE, " error: incorrect prev_state"));
531 test_complete = -141;
532 }
533
534 } else if (tsx->state != PJSIP_TSX_STATE_PROCEEDING &&
535 tsx->state != PJSIP_TSX_STATE_COMPLETED &&
536 tsx->state != PJSIP_TSX_STATE_DESTROYED)
537 {
Benny Prijono02b8fd82006-06-26 15:12:55 +0000538 PJ_LOG(3,(THIS_FILE, " error: unexpected state %s (142)",
539 pjsip_tsx_state_str(tsx->state)));
Benny Prijono0c2bc612006-01-10 13:31:40 +0000540 test_complete = -142;
541
542 }
543
544
545 } else
546 if (pj_strcmp2(&tsx->branch, TEST7_BRANCH_ID)==0 ||
547 pj_strcmp2(&tsx->branch, TEST8_BRANCH_ID)==0)
548 {
549 /*
550 * TEST7_BRANCH_ID and TEST8_BRANCH_ID test retransmission of
551 * INVITE final response
552 */
553 int code;
554
555 if (pj_strcmp2(&tsx->branch, TEST7_BRANCH_ID) == 0)
556 code = TEST7_STATUS_CODE;
557 else
558 code = TEST8_STATUS_CODE;
559
Benny Prijono02b8fd82006-06-26 15:12:55 +0000560 if (tsx->state == PJSIP_TSX_STATE_TRYING) {
561 /* Request is received. */
562
563 } else if (tsx->state == PJSIP_TSX_STATE_TERMINATED) {
Benny Prijono0c2bc612006-01-10 13:31:40 +0000564
565 if (test_complete == 0)
566 test_complete = 1;
567
568 /* Check status code. */
569 if (tsx->status_code != PJSIP_SC_TSX_TIMEOUT) {
570 PJ_LOG(3,(THIS_FILE, " error: incorrect status code"));
571 test_complete = -150;
572 }
573
574 /* Previous state. */
575 if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_COMPLETED) {
576 PJ_LOG(3,(THIS_FILE, " error: incorrect prev_state"));
577 test_complete = -151;
578 }
579
580 } else if (tsx->state == PJSIP_TSX_STATE_COMPLETED) {
581
582 /* Check that status code is status_code. */
583 if (tsx->status_code != code) {
584 PJ_LOG(3,(THIS_FILE, " error: incorrect status code"));
585 test_complete = -152;
586 }
587
588 /* Previous state. */
589 if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_TRYING) {
590 PJ_LOG(3,(THIS_FILE, " error: incorrect prev_state"));
591 test_complete = -153;
592 }
593
594 } else if (tsx->state != PJSIP_TSX_STATE_DESTROYED) {
595
Benny Prijono02b8fd82006-06-26 15:12:55 +0000596 PJ_LOG(3,(THIS_FILE, " error: unexpected state (154)"));
Benny Prijono0c2bc612006-01-10 13:31:40 +0000597 test_complete = -154;
598
599 }
600
Benny Prijono728a9052006-01-18 23:34:15 +0000601
602 } else
603 if (pj_strcmp2(&tsx->branch, TEST9_BRANCH_ID)==0) {
604 /*
605 * TEST9_BRANCH_ID tests that retransmission of INVITE final response
606 * must cease when ACK is received.
607 */
608
Benny Prijono02b8fd82006-06-26 15:12:55 +0000609 if (tsx->state == PJSIP_TSX_STATE_TRYING) {
610 /* Request is received. */
611
612 } else if (tsx->state == PJSIP_TSX_STATE_TERMINATED) {
Benny Prijono728a9052006-01-18 23:34:15 +0000613
614 if (test_complete == 0)
615 test_complete = 1;
616
617 /* Check status code. */
618 if (tsx->status_code != TEST9_STATUS_CODE) {
619 PJ_LOG(3,(THIS_FILE, " error: incorrect status code"));
620 test_complete = -160;
621 }
622
623 /* Previous state. */
624 if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_CONFIRMED) {
625 PJ_LOG(3,(THIS_FILE, " error: incorrect prev_state"));
626 test_complete = -161;
627 }
628
629 } else if (tsx->state == PJSIP_TSX_STATE_COMPLETED) {
630
631 /* Check that status code is status_code. */
632 if (tsx->status_code != TEST9_STATUS_CODE) {
633 PJ_LOG(3,(THIS_FILE, " error: incorrect status code"));
634 test_complete = -162;
635 }
636
637 /* Previous state. */
638 if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_TRYING) {
639 PJ_LOG(3,(THIS_FILE, " error: incorrect prev_state"));
640 test_complete = -163;
641 }
642
643
644 } else if (tsx->state == PJSIP_TSX_STATE_CONFIRMED) {
645
646 /* Check that status code is status_code. */
647 if (tsx->status_code != TEST9_STATUS_CODE) {
648 PJ_LOG(3,(THIS_FILE, " error: incorrect status code"));
649 test_complete = -164;
650 }
651
652 /* Previous state. */
653 if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_COMPLETED) {
654 PJ_LOG(3,(THIS_FILE, " error: incorrect prev_state"));
655 test_complete = -165;
656 }
657
658 } else if (tsx->state != PJSIP_TSX_STATE_DESTROYED) {
659
Benny Prijono02b8fd82006-06-26 15:12:55 +0000660 PJ_LOG(3,(THIS_FILE, " error: unexpected state (166)"));
Benny Prijono728a9052006-01-18 23:34:15 +0000661 test_complete = -166;
662
663 }
664
665
666 } else
667 if (pj_strcmp2(&tsx->branch, TEST10_BRANCH_ID)==0 ||
668 pj_strcmp2(&tsx->branch, TEST11_BRANCH_ID)==0 ||
669 pj_strcmp2(&tsx->branch, TEST12_BRANCH_ID)==0)
670 {
671 if (tsx->state == PJSIP_TSX_STATE_TERMINATED) {
672
673 if (!test_complete)
674 test_complete = 1;
675
676 if (tsx->status_code != PJSIP_SC_TSX_TRANSPORT_ERROR) {
677 PJ_LOG(3,(THIS_FILE," error: incorrect status code"));
678 test_complete = -170;
679 }
680 }
Benny Prijonodbe337a2006-01-08 23:57:52 +0000681 }
682
683}
684
685/* Save transaction key to global variables. */
686static void save_key(pjsip_transaction *tsx)
687{
688 pj_str_t key;
689
690 pj_strdup(tsx->pool, &key, &tsx->transaction_key);
691 pj_strcpy(&tsx_key, &key);
692}
693
Benny Prijono0c2bc612006-01-10 13:31:40 +0000694#define DIFF(a,b) ((a<b) ? (b-a) : (a-b))
695
Benny Prijonodbe337a2006-01-08 23:57:52 +0000696/*
697 * Message receiver handler.
698 */
699static pj_bool_t on_rx_message(pjsip_rx_data *rdata)
700{
701 pjsip_msg *msg = rdata->msg_info.msg;
702 pj_str_t branch_param = rdata->msg_info.via->branch_param;
703 pj_status_t status;
704
705 if (pj_strcmp2(&branch_param, TEST1_BRANCH_ID) == 0 ||
706 pj_strcmp2(&branch_param, TEST2_BRANCH_ID) == 0)
707 {
708 /*
709 * TEST1_BRANCH_ID tests that non-INVITE transaction transmits 2xx
710 * final response using correct transport and terminates transaction
711 * after 32 seconds.
712 *
713 * TEST2_BRANCH_ID performs similar test for non-2xx final response.
714 */
715 int status_code = (pj_strcmp2(&branch_param, TEST1_BRANCH_ID) == 0) ?
716 TEST1_STATUS_CODE : TEST2_STATUS_CODE;
717
718 if (msg->type == PJSIP_REQUEST_MSG) {
Benny Prijono728a9052006-01-18 23:34:15 +0000719 /* On received request, create UAS and respond with final
Benny Prijonodbe337a2006-01-08 23:57:52 +0000720 * response.
721 */
722 pjsip_transaction *tsx;
Benny Prijonodbe337a2006-01-08 23:57:52 +0000723
724 status = pjsip_tsx_create_uas(&tsx_user, rdata, &tsx);
725 if (status != PJ_SUCCESS) {
726 app_perror(" error: unable to create transaction", status);
727 test_complete = -110;
728 return PJ_TRUE;
729 }
Benny Prijono38998232006-02-08 22:44:25 +0000730 pjsip_tsx_recv_msg(tsx, rdata);
Benny Prijonodbe337a2006-01-08 23:57:52 +0000731
732 save_key(tsx);
Benny Prijono0c2bc612006-01-10 13:31:40 +0000733 send_response(rdata, tsx, status_code);
Benny Prijonodbe337a2006-01-08 23:57:52 +0000734
735 } else {
736 /* Verify the response received. */
737
738 ++recv_count;
739
740 /* Verify status code. */
741 if (msg->line.status.code != status_code) {
742 PJ_LOG(3,(THIS_FILE, " error: incorrect status code"));
743 test_complete = -113;
744 }
745
746 /* Verify that no retransmissions is received. */
747 if (recv_count > 1) {
748 PJ_LOG(3,(THIS_FILE, " error: retransmission received"));
749 test_complete = -114;
750 }
751
752 }
753 return PJ_TRUE;
754
755 } else if (pj_strcmp2(&branch_param, TEST3_BRANCH_ID) == 0) {
756
757 /* TEST3_BRANCH_ID tests provisional response. */
758
759 if (msg->type == PJSIP_REQUEST_MSG) {
Benny Prijono728a9052006-01-18 23:34:15 +0000760 /* On received request, create UAS and respond with provisional
Benny Prijonodbe337a2006-01-08 23:57:52 +0000761 * response, then schedule timer to send final response.
762 */
763 pjsip_transaction *tsx;
Benny Prijonodbe337a2006-01-08 23:57:52 +0000764
765 status = pjsip_tsx_create_uas(&tsx_user, rdata, &tsx);
766 if (status != PJ_SUCCESS) {
767 app_perror(" error: unable to create transaction", status);
Benny Prijono02b8fd82006-06-26 15:12:55 +0000768 test_complete = -116;
Benny Prijonodbe337a2006-01-08 23:57:52 +0000769 return PJ_TRUE;
770 }
Benny Prijono38998232006-02-08 22:44:25 +0000771 pjsip_tsx_recv_msg(tsx, rdata);
Benny Prijonodbe337a2006-01-08 23:57:52 +0000772
773 save_key(tsx);
774
Benny Prijono0c2bc612006-01-10 13:31:40 +0000775 send_response(rdata, tsx, TEST3_PROVISIONAL_CODE);
Benny Prijonodbe337a2006-01-08 23:57:52 +0000776 schedule_send_response(rdata, &tsx->transaction_key,
777 TEST3_STATUS_CODE, 2000);
778
779 } else {
780 /* Verify the response received. */
781
782 ++recv_count;
783
784 if (recv_count == 1) {
785 /* Verify status code. */
786 if (msg->line.status.code != TEST3_PROVISIONAL_CODE) {
787 PJ_LOG(3,(THIS_FILE, " error: incorrect status code"));
788 test_complete = -123;
789 }
790 } else if (recv_count == 2) {
791 /* Verify status code. */
792 if (msg->line.status.code != TEST3_STATUS_CODE) {
793 PJ_LOG(3,(THIS_FILE, " error: incorrect status code"));
794 test_complete = -124;
795 }
796 } else {
797 PJ_LOG(3,(THIS_FILE, " error: retransmission received"));
798 test_complete = -125;
799 }
800
801 }
802 return PJ_TRUE;
803
Benny Prijono0c2bc612006-01-10 13:31:40 +0000804 } else if (pj_strcmp2(&branch_param, TEST4_BRANCH_ID) == 0 ||
805 pj_strcmp2(&branch_param, TEST5_BRANCH_ID) == 0 ||
806 pj_strcmp2(&branch_param, TEST6_BRANCH_ID) == 0)
807 {
808
809 /* TEST4_BRANCH_ID: absorbs retransmissions in TRYING state. */
810 /* TEST5_BRANCH_ID: retransmit last response in PROCEEDING state. */
811 /* TEST6_BRANCH_ID: retransmit last response in COMPLETED state. */
812
813 if (msg->type == PJSIP_REQUEST_MSG) {
Benny Prijono728a9052006-01-18 23:34:15 +0000814 /* On received request, create UAS. */
Benny Prijono0c2bc612006-01-10 13:31:40 +0000815 pjsip_transaction *tsx;
816
817 status = pjsip_tsx_create_uas(&tsx_user, rdata, &tsx);
818 if (status != PJ_SUCCESS) {
819 app_perror(" error: unable to create transaction", status);
820 test_complete = -130;
821 return PJ_TRUE;
822 }
823
Benny Prijono38998232006-02-08 22:44:25 +0000824 pjsip_tsx_recv_msg(tsx, rdata);
Benny Prijono0c2bc612006-01-10 13:31:40 +0000825 save_key(tsx);
826
827 if (pj_strcmp2(&branch_param, TEST4_BRANCH_ID) == 0) {
828
829 } else if (pj_strcmp2(&branch_param, TEST5_BRANCH_ID) == 0) {
830 send_response(rdata, tsx, TEST5_PROVISIONAL_CODE);
831
832 } else if (pj_strcmp2(&branch_param, TEST6_BRANCH_ID) == 0) {
833 send_response(rdata, tsx, TEST6_PROVISIONAL_CODE);
834 send_response(rdata, tsx, TEST6_STATUS_CODE);
835 }
836
837 } else {
838 /* Verify the response received. */
839
840 ++recv_count;
841
842 if (pj_strcmp2(&branch_param, TEST4_BRANCH_ID) == 0) {
843 PJ_LOG(3,(THIS_FILE, " error: not expecting response!"));
844 test_complete = -132;
845
846 } else if (pj_strcmp2(&branch_param, TEST5_BRANCH_ID) == 0) {
847
848 if (rdata->msg_info.msg->line.status.code!=TEST5_PROVISIONAL_CODE) {
849 PJ_LOG(3,(THIS_FILE, " error: incorrect status code!"));
850 test_complete = -133;
851
852 }
853 if (recv_count > TEST5_RESPONSE_COUNT) {
854 PJ_LOG(3,(THIS_FILE, " error: not expecting response!"));
855 test_complete = -134;
856 }
857
858 } else if (pj_strcmp2(&branch_param, TEST6_BRANCH_ID) == 0) {
859
860 int code = rdata->msg_info.msg->line.status.code;
861
862 switch (recv_count) {
863 case 1:
864 if (code != TEST6_PROVISIONAL_CODE) {
865 PJ_LOG(3,(THIS_FILE, " error: invalid code!"));
866 test_complete = -135;
867 }
868 break;
869 case 2:
870 case 3:
871 if (code != TEST6_STATUS_CODE) {
872 PJ_LOG(3,(THIS_FILE, " error: invalid code!"));
873 test_complete = -136;
874 }
875 break;
876 default:
877 PJ_LOG(3,(THIS_FILE, " error: not expecting response"));
878 test_complete = -137;
879 break;
880 }
881 }
882 }
883 return PJ_TRUE;
884
885
886 } else if (pj_strcmp2(&branch_param, TEST7_BRANCH_ID) == 0 ||
887 pj_strcmp2(&branch_param, TEST8_BRANCH_ID) == 0)
888 {
889
890 /*
891 * TEST7_BRANCH_ID and TEST8_BRANCH_ID test the retransmission
892 * of INVITE final response
893 */
894 if (msg->type == PJSIP_REQUEST_MSG) {
895
Benny Prijono728a9052006-01-18 23:34:15 +0000896 /* On received request, create UAS. */
Benny Prijono0c2bc612006-01-10 13:31:40 +0000897 pjsip_transaction *tsx;
898
899 status = pjsip_tsx_create_uas(&tsx_user, rdata, &tsx);
900 if (status != PJ_SUCCESS) {
901 app_perror(" error: unable to create transaction", status);
902 test_complete = -140;
903 return PJ_TRUE;
904 }
905
Benny Prijono38998232006-02-08 22:44:25 +0000906 pjsip_tsx_recv_msg(tsx, rdata);
Benny Prijono0c2bc612006-01-10 13:31:40 +0000907 save_key(tsx);
908
909 if (pj_strcmp2(&branch_param, TEST7_BRANCH_ID) == 0) {
910
911 send_response(rdata, tsx, TEST7_STATUS_CODE);
912
913 } else {
914
915 send_response(rdata, tsx, TEST8_STATUS_CODE);
916
917 }
918
919 } else {
920 int code;
921
922 ++recv_count;
923
924 if (pj_strcmp2(&branch_param, TEST7_BRANCH_ID) == 0)
925 code = TEST7_STATUS_CODE;
926 else
927 code = TEST8_STATUS_CODE;
928
929 if (recv_count==1) {
930
931 if (rdata->msg_info.msg->line.status.code != code) {
932 PJ_LOG(3,(THIS_FILE," error: invalid status code"));
933 test_complete = -141;
934 }
935
936 recv_last = rdata->pkt_info.timestamp;
937
938 } else {
939
940 pj_time_val now;
941 unsigned msec, msec_expected;
942
943 now = rdata->pkt_info.timestamp;
944
945 PJ_TIME_VAL_SUB(now, recv_last);
946
947 msec = now.sec*1000 + now.msec;
948 msec_expected = (1 << (recv_count-2)) * PJSIP_T1_TIMEOUT;
949 if (msec_expected > PJSIP_T2_TIMEOUT)
950 msec_expected = PJSIP_T2_TIMEOUT;
951
952 if (DIFF(msec, msec_expected) > MAX_ALLOWED_DIFF) {
953 PJ_LOG(3,(THIS_FILE,
954 " error: incorrect retransmission "
955 "time (%d ms expected, %d ms received",
956 msec_expected, msec));
957 test_complete = -142;
958 }
959
960 if (recv_count > 11) {
961 PJ_LOG(3,(THIS_FILE," error: too many responses (%d)",
962 recv_count));
963 test_complete = -143;
964 }
965
966 recv_last = rdata->pkt_info.timestamp;
967 }
968
969 }
970 return PJ_TRUE;
971
Benny Prijono728a9052006-01-18 23:34:15 +0000972 } else if (pj_strcmp2(&branch_param, TEST9_BRANCH_ID) == 0) {
Benny Prijono0c2bc612006-01-10 13:31:40 +0000973
974 /*
975 * TEST9_BRANCH_ID tests that the retransmission of INVITE final
976 * response should cease when ACK is received. Transaction also MUST
977 * terminate in T4 seconds.
978 */
979 if (msg->type == PJSIP_REQUEST_MSG) {
980
Benny Prijono728a9052006-01-18 23:34:15 +0000981 /* On received request, create UAS. */
Benny Prijono0c2bc612006-01-10 13:31:40 +0000982 pjsip_transaction *tsx;
983
984 status = pjsip_tsx_create_uas(&tsx_user, rdata, &tsx);
985 if (status != PJ_SUCCESS) {
986 app_perror(" error: unable to create transaction", status);
Benny Prijono728a9052006-01-18 23:34:15 +0000987 test_complete = -150;
Benny Prijono0c2bc612006-01-10 13:31:40 +0000988 return PJ_TRUE;
989 }
990
Benny Prijono38998232006-02-08 22:44:25 +0000991 pjsip_tsx_recv_msg(tsx, rdata);
Benny Prijono0c2bc612006-01-10 13:31:40 +0000992 save_key(tsx);
Benny Prijono728a9052006-01-18 23:34:15 +0000993 send_response(rdata, tsx, TEST9_STATUS_CODE);
Benny Prijono0c2bc612006-01-10 13:31:40 +0000994
Benny Prijono0c2bc612006-01-10 13:31:40 +0000995
996 } else {
Benny Prijono0c2bc612006-01-10 13:31:40 +0000997
998 ++recv_count;
999
Benny Prijono728a9052006-01-18 23:34:15 +00001000 if (rdata->msg_info.msg->line.status.code != TEST9_STATUS_CODE) {
1001 PJ_LOG(3,(THIS_FILE," error: invalid status code"));
1002 test_complete = -151;
1003 }
Benny Prijono0c2bc612006-01-10 13:31:40 +00001004
1005 if (recv_count==1) {
Benny Prijono0c2bc612006-01-10 13:31:40 +00001006
1007 recv_last = rdata->pkt_info.timestamp;
1008
Benny Prijono728a9052006-01-18 23:34:15 +00001009 } else if (recv_count < 5) {
Benny Prijono0c2bc612006-01-10 13:31:40 +00001010
Benny Prijono728a9052006-01-18 23:34:15 +00001011 /* Let UAS retransmit some messages before we send ACK. */
Benny Prijono0c2bc612006-01-10 13:31:40 +00001012 pj_time_val now;
1013 unsigned msec, msec_expected;
1014
1015 now = rdata->pkt_info.timestamp;
1016
1017 PJ_TIME_VAL_SUB(now, recv_last);
1018
1019 msec = now.sec*1000 + now.msec;
1020 msec_expected = (1 << (recv_count-2)) * PJSIP_T1_TIMEOUT;
1021 if (msec_expected > PJSIP_T2_TIMEOUT)
1022 msec_expected = PJSIP_T2_TIMEOUT;
1023
1024 if (DIFF(msec, msec_expected) > MAX_ALLOWED_DIFF) {
1025 PJ_LOG(3,(THIS_FILE,
1026 " error: incorrect retransmission "
1027 "time (%d ms expected, %d ms received",
1028 msec_expected, msec));
Benny Prijono728a9052006-01-18 23:34:15 +00001029 test_complete = -152;
Benny Prijono0c2bc612006-01-10 13:31:40 +00001030 }
1031
1032 recv_last = rdata->pkt_info.timestamp;
Benny Prijono728a9052006-01-18 23:34:15 +00001033
1034 } else if (recv_count == 5) {
1035 pjsip_tx_data *tdata;
1036 pjsip_sip_uri *uri;
1037 pjsip_via_hdr *via;
1038
1039 status = pjsip_endpt_create_request_from_hdr(
1040 endpt, &pjsip_ack_method,
1041 rdata->msg_info.to->uri,
1042 rdata->msg_info.from,
1043 rdata->msg_info.to,
1044 NULL,
1045 rdata->msg_info.cid,
1046 rdata->msg_info.cseq->cseq,
1047 NULL,
1048 &tdata);
1049 if (status != PJ_SUCCESS) {
1050 app_perror(" error: unable to create ACK", status);
1051 test_complete = -153;
1052 return PJ_TRUE;
1053 }
1054
1055 uri=(pjsip_sip_uri*)pjsip_uri_get_uri(tdata->msg->line.req.uri);
1056 uri->transport_param = pj_str("loop-dgram");
1057
1058 via = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL);
1059 via->branch_param = pj_str(TEST9_BRANCH_ID);
1060
1061 status = pjsip_endpt_send_request_stateless(endpt, tdata,
1062 NULL, NULL);
1063 if (status != PJ_SUCCESS) {
1064 app_perror(" error: unable to send ACK", status);
1065 test_complete = -154;
1066 }
1067
1068 } else {
1069 PJ_LOG(3,(THIS_FILE," error: too many responses (%d)",
1070 recv_count));
1071 test_complete = -155;
Benny Prijono0c2bc612006-01-10 13:31:40 +00001072 }
1073
1074 }
1075 return PJ_TRUE;
Benny Prijono728a9052006-01-18 23:34:15 +00001076
1077 } else if (pj_strcmp2(&branch_param, TEST10_BRANCH_ID) == 0 ||
1078 pj_strcmp2(&branch_param, TEST11_BRANCH_ID) == 0 ||
1079 pj_strcmp2(&branch_param, TEST12_BRANCH_ID) == 0)
1080 {
1081 int test_num, code1, code2;
1082
1083 if (pj_strcmp2(&branch_param, TEST10_BRANCH_ID) == 0)
1084 test_num=10, code1 = 100, code2 = 0;
1085 else if (pj_strcmp2(&branch_param, TEST11_BRANCH_ID) == 0)
1086 test_num=11, code1 = 100, code2 = 200;
1087 else
1088 test_num=12, code1 = 200, code2 = 0;
1089
1090 if (rdata->msg_info.msg->type == PJSIP_REQUEST_MSG) {
1091
1092 /* On received response, create UAS. */
1093 pjsip_transaction *tsx;
1094
1095 status = pjsip_tsx_create_uas(&tsx_user, rdata, &tsx);
1096 if (status != PJ_SUCCESS) {
1097 app_perror(" error: unable to create transaction", status);
1098 test_complete = -150;
1099 return PJ_TRUE;
1100 }
1101
Benny Prijono38998232006-02-08 22:44:25 +00001102 pjsip_tsx_recv_msg(tsx, rdata);
Benny Prijono728a9052006-01-18 23:34:15 +00001103 save_key(tsx);
1104
1105 schedule_send_response(rdata, &tsx_key, code1, 1000);
1106
1107 if (code2)
1108 schedule_send_response(rdata, &tsx_key, code2, 2000);
1109
1110 } else {
1111
1112 }
1113
1114 return PJ_TRUE;
Benny Prijonodbe337a2006-01-08 23:57:52 +00001115 }
1116
1117 return PJ_FALSE;
1118}
1119
1120/*
1121 * The generic test framework, used by most of the tests.
1122 */
1123static int perform_test( char *target_uri, char *from_uri,
1124 char *branch_param, int test_time,
Benny Prijono0c2bc612006-01-10 13:31:40 +00001125 const pjsip_method *method,
1126 int request_cnt, int request_interval_msec,
1127 int expecting_timeout)
Benny Prijonodbe337a2006-01-08 23:57:52 +00001128{
1129 pjsip_tx_data *tdata;
1130 pj_str_t target, from;
1131 pjsip_via_hdr *via;
Benny Prijono0c2bc612006-01-10 13:31:40 +00001132 pj_time_val timeout, next_send;
1133 int sent_cnt;
Benny Prijonodbe337a2006-01-08 23:57:52 +00001134 pj_status_t status;
1135
1136 PJ_LOG(3,(THIS_FILE,
1137 " please standby, this will take at most %d seconds..",
1138 test_time));
1139
1140 /* Reset test. */
1141 recv_count = 0;
1142 test_complete = 0;
1143 tsx_key.slen = 0;
1144
1145 /* Init headers. */
1146 target = pj_str(target_uri);
1147 from = pj_str(from_uri);
1148
1149 /* Create request. */
1150 status = pjsip_endpt_create_request( endpt, method, &target,
1151 &from, &target, NULL, NULL, -1,
1152 NULL, &tdata);
1153 if (status != PJ_SUCCESS) {
1154 app_perror(" Error: unable to create request", status);
1155 return -10;
1156 }
1157
1158 /* Set the branch param for test 1. */
1159 via = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL);
1160 via->branch_param = pj_str(branch_param);
1161
Benny Prijono0c2bc612006-01-10 13:31:40 +00001162 /* Schedule first send. */
1163 sent_cnt = 0;
1164 pj_gettimeofday(&next_send);
1165 pj_time_val_normalize(&next_send);
Benny Prijonodbe337a2006-01-08 23:57:52 +00001166
1167 /* Set test completion time. */
1168 pj_gettimeofday(&timeout);
1169 timeout.sec += test_time;
1170
1171 /* Wait until test complete. */
1172 while (!test_complete) {
1173 pj_time_val now, poll_delay = {0, 10};
1174
1175 pjsip_endpt_handle_events(endpt, &poll_delay);
1176
1177 pj_gettimeofday(&now);
Benny Prijono0c2bc612006-01-10 13:31:40 +00001178
1179 if (sent_cnt < request_cnt && PJ_TIME_VAL_GTE(now, next_send)) {
1180 /* Add additional reference to tdata to prevent transaction from
1181 * deleting it.
1182 */
1183 pjsip_tx_data_add_ref(tdata);
1184
1185 /* (Re)Send the request. */
1186 status = pjsip_endpt_send_request_stateless(endpt, tdata, 0, 0);
1187 if (status != PJ_SUCCESS) {
1188 app_perror(" Error: unable to send request", status);
1189 pjsip_tx_data_dec_ref(tdata);
1190 return -20;
1191 }
1192
1193 /* Schedule next send, if any. */
1194 sent_cnt++;
1195 if (sent_cnt < request_cnt) {
1196 pj_gettimeofday(&next_send);
1197 next_send.msec += request_interval_msec;
1198 pj_time_val_normalize(&next_send);
1199 }
1200 }
1201
Benny Prijonodbe337a2006-01-08 23:57:52 +00001202 if (now.sec > timeout.sec) {
Benny Prijono0c2bc612006-01-10 13:31:40 +00001203 if (!expecting_timeout)
1204 PJ_LOG(3,(THIS_FILE, " Error: test has timed out"));
Benny Prijonodbe337a2006-01-08 23:57:52 +00001205 pjsip_tx_data_dec_ref(tdata);
Benny Prijono0c2bc612006-01-10 13:31:40 +00001206 return TEST_TIMEOUT_ERROR;
Benny Prijonodbe337a2006-01-08 23:57:52 +00001207 }
1208 }
1209
1210 if (test_complete < 0) {
1211 pjsip_transaction *tsx;
1212
1213 tsx = pjsip_tsx_layer_find_tsx(&tsx_key, PJ_TRUE);
1214 if (tsx) {
1215 pjsip_tsx_terminate(tsx, PJSIP_SC_REQUEST_TERMINATED);
1216 pj_mutex_unlock(tsx->mutex);
1217 flush_events(1000);
1218 }
1219 pjsip_tx_data_dec_ref(tdata);
1220 return test_complete;
1221 }
1222
1223 /* Allow transaction to destroy itself */
1224 flush_events(500);
1225
1226 /* Make sure transaction has been destroyed. */
1227 if (pjsip_tsx_layer_find_tsx(&tsx_key, PJ_FALSE) != NULL) {
1228 PJ_LOG(3,(THIS_FILE, " Error: transaction has not been destroyed"));
1229 pjsip_tx_data_dec_ref(tdata);
1230 return -40;
1231 }
1232
1233 /* Check tdata reference counter. */
1234 if (pj_atomic_get(tdata->ref_cnt) != 1) {
1235 PJ_LOG(3,(THIS_FILE, " Error: tdata reference counter is %d",
1236 pj_atomic_get(tdata->ref_cnt)));
1237 pjsip_tx_data_dec_ref(tdata);
1238 return -50;
1239 }
1240
1241 /* Destroy txdata */
1242 pjsip_tx_data_dec_ref(tdata);
1243
1244 return PJ_SUCCESS;
1245
1246}
1247
1248
1249/*****************************************************************************
1250 **
1251 ** TEST1_BRANCH_ID: Basic 2xx final response
1252 ** TEST2_BRANCH_ID: Basic non-2xx final response
1253 **
1254 *****************************************************************************
1255 */
1256static int tsx_basic_final_response_test(void)
1257{
1258 int status;
1259
1260 PJ_LOG(3,(THIS_FILE," test1: basic sending 2xx final response"));
1261
1262 status = perform_test("sip:129.0.0.1;transport=loop-dgram",
1263 "sip:129.0.0.1;transport=loop-dgram",
1264 TEST1_BRANCH_ID,
1265 33, /* Test duration must be greater than 32 secs */
Benny Prijono0c2bc612006-01-10 13:31:40 +00001266 &pjsip_options_method, 1, 0, 0);
Benny Prijonodbe337a2006-01-08 23:57:52 +00001267 if (status != 0)
1268 return status;
1269
1270 PJ_LOG(3,(THIS_FILE," test2: basic sending non-2xx final response"));
1271
1272 status = perform_test("sip:129.0.0.1;transport=loop-dgram",
1273 "sip:129.0.0.1;transport=loop-dgram",
1274 TEST2_BRANCH_ID,
1275 33, /* Test duration must be greater than 32 secs */
Benny Prijono0c2bc612006-01-10 13:31:40 +00001276 &pjsip_options_method, 1, 0, 0);
Benny Prijonodbe337a2006-01-08 23:57:52 +00001277 if (status != 0)
1278 return status;
1279
1280 return 0;
1281}
1282
1283
1284/*****************************************************************************
1285 **
1286 ** TEST3_BRANCH_ID: Sending provisional response
1287 **
1288 *****************************************************************************
1289 */
1290static int tsx_basic_provisional_response_test(void)
1291{
1292 int status;
1293
Benny Prijono02b8fd82006-06-26 15:12:55 +00001294 PJ_LOG(3,(THIS_FILE," test3: basic sending 2xx final response"));
Benny Prijonodbe337a2006-01-08 23:57:52 +00001295
1296 status = perform_test("sip:129.0.0.1;transport=loop-dgram",
1297 "sip:129.0.0.1;transport=loop-dgram",
1298 TEST3_BRANCH_ID,
1299 35,
Benny Prijono0c2bc612006-01-10 13:31:40 +00001300 &pjsip_options_method, 1, 0, 0);
1301
Benny Prijonodbe337a2006-01-08 23:57:52 +00001302 return status;
1303}
1304
1305
1306/*****************************************************************************
1307 **
Benny Prijono0c2bc612006-01-10 13:31:40 +00001308 ** TEST4_BRANCH_ID: Absorbs retransmissions in TRYING state
1309 ** TEST5_BRANCH_ID: Absorbs retransmissions in PROCEEDING state
1310 ** TEST6_BRANCH_ID: Absorbs retransmissions in COMPLETED state
1311 **
1312 *****************************************************************************
1313 */
1314static int tsx_retransmit_last_response_test(const char *title,
1315 char *branch_id,
1316 int request_cnt,
1317 int status_code)
1318{
1319 int status;
1320
1321 PJ_LOG(3,(THIS_FILE," %s", title));
1322
1323 status = perform_test("sip:129.0.0.1;transport=loop-dgram",
1324 "sip:129.0.0.1;transport=loop-dgram",
1325 branch_id,
1326 5,
1327 &pjsip_options_method,
1328 request_cnt, 1000, 1);
1329 if (status && status != TEST_TIMEOUT_ERROR)
1330 return status;
1331 if (!status) {
1332 PJ_LOG(3,(THIS_FILE, " error: expecting timeout"));
1333 return -31;
1334 }
1335
1336 terminate_our_tsx(status_code);
1337 flush_events(100);
1338
1339 if (test_complete != 1)
1340 return test_complete;
1341
1342 flush_events(100);
1343 return 0;
1344}
1345
1346/*****************************************************************************
1347 **
1348 ** TEST7_BRANCH_ID: INVITE non-2xx final response retransmission test
1349 ** TEST8_BRANCH_ID: INVITE 2xx final response retransmission test
1350 **
1351 *****************************************************************************
1352 */
1353static int tsx_final_response_retransmission_test(void)
1354{
1355 int status;
1356
1357 PJ_LOG(3,(THIS_FILE,
1358 " test7: INVITE non-2xx final response retransmission"));
1359
1360 status = perform_test("sip:129.0.0.1;transport=loop-dgram",
1361 "sip:129.0.0.1;transport=loop-dgram",
1362 TEST7_BRANCH_ID,
1363 33, /* Test duration must be greater than 32 secs */
1364 &pjsip_invite_method, 1, 0, 0);
1365 if (status != 0)
1366 return status;
1367
1368 PJ_LOG(3,(THIS_FILE,
1369 " test8: INVITE 2xx final response retransmission"));
1370
1371 status = perform_test("sip:129.0.0.1;transport=loop-dgram",
1372 "sip:129.0.0.1;transport=loop-dgram",
1373 TEST8_BRANCH_ID,
1374 33, /* Test duration must be greater than 32 secs */
1375 &pjsip_invite_method, 1, 0, 0);
1376 if (status != 0)
1377 return status;
1378
1379 return 0;
1380}
1381
1382
Benny Prijono728a9052006-01-18 23:34:15 +00001383/*****************************************************************************
1384 **
1385 ** TEST9_BRANCH_ID: retransmission of non-2xx INVITE final response must
1386 ** cease when ACK is received
1387 **
1388 *****************************************************************************
1389 */
1390static int tsx_ack_test(void)
1391{
1392 int status;
1393
1394 PJ_LOG(3,(THIS_FILE,
1395 " test9: receiving ACK for non-2xx final response"));
1396
1397 status = perform_test("sip:129.0.0.1;transport=loop-dgram",
1398 "sip:129.0.0.1;transport=loop-dgram",
1399 TEST9_BRANCH_ID,
1400 20, /* allow 5 retransmissions */
1401 &pjsip_invite_method, 1, 0, 0);
1402 if (status != 0)
1403 return status;
1404
1405
1406 return 0;
1407}
1408
1409
1410
1411/*****************************************************************************
1412 **
1413 ** TEST10_BRANCH_ID: test transport failure in TRYING state.
1414 ** TEST11_BRANCH_ID: test transport failure in PROCEEDING state.
1415 ** TEST12_BRANCH_ID: test transport failure in CONNECTED state.
1416 ** TEST13_BRANCH_ID: test transport failure in CONFIRMED state.
1417 **
1418 *****************************************************************************
1419 */
1420static int tsx_transport_failure_test(void)
1421{
1422 struct test_desc
1423 {
1424 int transport_delay;
1425 int fail_delay;
1426 char *branch_id;
1427 char *title;
1428 } tests[] =
1429 {
1430 { 0, 10, TEST10_BRANCH_ID, "test10: failed transport in TRYING state (no delay)" },
1431 { 50, 10, TEST10_BRANCH_ID, "test10: failed transport in TRYING state (50 ms delay)" },
1432 { 0, 1500, TEST11_BRANCH_ID, "test11: failed transport in PROCEEDING state (no delay)" },
1433 { 50, 1500, TEST11_BRANCH_ID, "test11: failed transport in PROCEEDING state (50 ms delay)" },
1434 { 0, 2500, TEST12_BRANCH_ID, "test12: failed transport in COMPLETED state (no delay)" },
1435 { 50, 2500, TEST12_BRANCH_ID, "test12: failed transport in COMPLETED state (50 ms delay)" },
1436 };
1437 int i, status;
1438
1439 for (i=0; i<PJ_ARRAY_SIZE(tests); ++i) {
1440 pj_time_val fail_time, end_test, now;
1441
1442 PJ_LOG(3,(THIS_FILE, " %s", tests[i].title));
1443 pjsip_loop_set_failure(loop, 0, NULL);
1444 pjsip_loop_set_delay(loop, tests[i].transport_delay);
1445
1446 status = perform_test("sip:129.0.0.1;transport=loop-dgram",
1447 "sip:129.0.0.1;transport=loop-dgram",
1448 tests[i].branch_id,
1449 0,
1450 &pjsip_invite_method, 1, 0, 1);
1451 if (status && status != TEST_TIMEOUT_ERROR)
1452 return status;
1453 if (!status) {
1454 PJ_LOG(3,(THIS_FILE, " error: expecting timeout"));
1455 return -40;
1456 }
1457
1458 pj_gettimeofday(&fail_time);
1459 fail_time.msec += tests[i].fail_delay;
1460 pj_time_val_normalize(&fail_time);
1461
1462 do {
1463 pj_time_val interval = { 0, 1 };
1464 pj_gettimeofday(&now);
1465 pjsip_endpt_handle_events(endpt, &interval);
1466 } while (PJ_TIME_VAL_LT(now, fail_time));
1467
1468 pjsip_loop_set_failure(loop, 1, NULL);
1469
1470 end_test = now;
1471 end_test.sec += 5;
1472
1473 do {
1474 pj_time_val interval = { 0, 1 };
1475 pj_gettimeofday(&now);
1476 pjsip_endpt_handle_events(endpt, &interval);
1477 } while (!test_complete && PJ_TIME_VAL_LT(now, end_test));
1478
1479 if (test_complete == 0) {
1480 PJ_LOG(3,(THIS_FILE, " error: test has timed out"));
1481 return -41;
1482 }
1483
1484 if (test_complete != 1)
1485 return test_complete;
1486 }
1487
1488 return 0;
1489}
Benny Prijono0c2bc612006-01-10 13:31:40 +00001490
1491/*****************************************************************************
1492 **
Benny Prijonodbe337a2006-01-08 23:57:52 +00001493 ** UAS Transaction Test.
1494 **
1495 *****************************************************************************
1496 */
1497int tsx_uas_test(void)
1498{
1499 pj_sockaddr_in addr;
1500 pj_status_t status;
1501
1502 /* Check if loop transport is configured. */
1503 status = pjsip_endpt_acquire_transport(endpt, PJSIP_TRANSPORT_LOOP_DGRAM,
1504 &addr, sizeof(addr), &loop);
1505 if (status != PJ_SUCCESS) {
1506 PJ_LOG(3,(THIS_FILE, " Error: loop transport is not configured!"));
1507 return -1;
1508 }
1509
1510 /* Register modules. */
1511 status = pjsip_endpt_register_module(endpt, &tsx_user);
1512 if (status != PJ_SUCCESS) {
1513 app_perror(" Error: unable to register module", status);
1514 return -3;
1515 }
1516 status = pjsip_endpt_register_module(endpt, &msg_sender);
1517 if (status != PJ_SUCCESS) {
1518 app_perror(" Error: unable to register module", status);
1519 return -4;
1520 }
1521
Benny Prijonodbe337a2006-01-08 23:57:52 +00001522 /* TEST1_BRANCH_ID: Basic 2xx final response.
1523 * TEST2_BRANCH_ID: Basic non-2xx final response.
1524 */
1525 status = tsx_basic_final_response_test();
1526 if (status != 0)
1527 return status;
Benny Prijonodbe337a2006-01-08 23:57:52 +00001528
1529 /* TEST3_BRANCH_ID: with provisional response
1530 */
1531 status = tsx_basic_provisional_response_test();
1532 if (status != 0)
1533 return status;
1534
Benny Prijono0c2bc612006-01-10 13:31:40 +00001535 /* TEST4_BRANCH_ID: absorbs retransmissions in TRYING state
1536 */
1537 status = tsx_retransmit_last_response_test(TEST4_TITLE,
1538 TEST4_BRANCH_ID,
1539 TEST4_REQUEST_COUNT,
1540 TEST4_STATUS_CODE);
1541 if (status != 0)
1542 return status;
1543
1544 /* TEST5_BRANCH_ID: retransmit last response in PROCEEDING state
1545 */
1546 status = tsx_retransmit_last_response_test(TEST5_TITLE,
1547 TEST5_BRANCH_ID,
1548 TEST5_REQUEST_COUNT,
1549 TEST5_STATUS_CODE);
1550 if (status != 0)
1551 return status;
1552
1553 /* TEST6_BRANCH_ID: retransmit last response in PROCEEDING state
1554 */
1555 status = tsx_retransmit_last_response_test(TEST6_TITLE,
1556 TEST6_BRANCH_ID,
1557 TEST6_REQUEST_COUNT,
1558 TEST6_STATUS_CODE);
1559 if (status != 0)
1560 return status;
1561
1562 /* TEST7_BRANCH_ID: INVITE non-2xx final response retransmission test
1563 * TEST8_BRANCH_ID: INVITE 2xx final response retransmission test
1564 */
1565
1566 status = tsx_final_response_retransmission_test();
1567 if (status != 0)
1568 return status;
1569
Benny Prijono728a9052006-01-18 23:34:15 +00001570 /* TEST9_BRANCH_ID: retransmission of non-2xx INVITE final response must
1571 * cease when ACK is received
1572 */
1573 status = tsx_ack_test();
1574 if (status != 0)
1575 return status;
1576
1577 /* TEST10_BRANCH_ID: test transport failure in TRYING state.
1578 * TEST11_BRANCH_ID: test transport failure in PROCEEDING state.
1579 * TEST12_BRANCH_ID: test transport failure in CONNECTED state.
1580 * TEST13_BRANCH_ID: test transport failure in CONFIRMED state.
1581 */
1582 status = tsx_transport_failure_test();
1583 if (status != 0)
1584 return status;
1585
Benny Prijonodbe337a2006-01-08 23:57:52 +00001586
1587 pjsip_transport_dec_ref(loop);
1588 return 0;
1589
1590}
1591