blob: 326f225688ec0575d1455a7fd5b91aebd09bc77c [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 */
144 NULL, /* User data. */
Benny Prijonodbe337a2006-01-08 23:57:52 +0000145 NULL, /* load() */
146 NULL, /* start() */
147 NULL, /* stop() */
148 NULL, /* unload() */
149 NULL, /* on_rx_request() */
150 NULL, /* on_rx_response() */
151 NULL, /* on_tx_request() */
152 NULL, /* on_tx_response() */
153 &tsx_user_on_tsx_state, /* on_tsx_state() */
154};
155
156/* Module to send request. */
157static pjsip_module msg_sender =
158{
159 NULL, NULL, /* prev and next */
160 { "Msg-Sender", 10}, /* Name. */
161 -1, /* Id */
162 PJSIP_MOD_PRIORITY_APPLICATION-1, /* Priority */
163 NULL, /* User data. */
Benny Prijonodbe337a2006-01-08 23:57:52 +0000164 NULL, /* load() */
165 NULL, /* start() */
166 NULL, /* stop() */
167 NULL, /* unload() */
168 &on_rx_message, /* on_rx_request() */
169 &on_rx_message, /* on_rx_response() */
170 NULL, /* on_tx_request() */
171 NULL, /* on_tx_response() */
172 NULL, /* on_tsx_state() */
173};
174
175/* Static vars, which will be reset on each test. */
176static int recv_count;
177static pj_time_val recv_last;
178static pj_bool_t test_complete;
179
180/* Loop transport instance. */
181static pjsip_transport *loop;
182
183/* UAS transaction key. */
184static char key_buf[64];
185static pj_str_t tsx_key = { key_buf, 0 };
186
187
188/* General timer entry to be used by tests. */
189static pj_timer_entry timer;
190
191/* Timer to send response via transaction. */
192struct response
193{
194 pj_str_t tsx_key;
195 pjsip_tx_data *tdata;
196};
197
Benny Prijono0c2bc612006-01-10 13:31:40 +0000198/* Timer callback to send response. */
Benny Prijonodbe337a2006-01-08 23:57:52 +0000199static void send_response_timer( pj_timer_heap_t *timer_heap,
200 struct pj_timer_entry *entry)
201{
202 pjsip_transaction *tsx;
203 struct response *r = entry->user_data;
204 pj_status_t status;
205
206 tsx = pjsip_tsx_layer_find_tsx(&r->tsx_key, PJ_TRUE);
207 if (!tsx) {
208 PJ_LOG(3,(THIS_FILE," error: timer unable to find transaction"));
209 pjsip_tx_data_dec_ref(r->tdata);
210 return;
211 }
212
213 status = pjsip_tsx_send_msg(tsx, r->tdata);
214 if (status != PJ_SUCCESS) {
Benny Prijono728a9052006-01-18 23:34:15 +0000215 // Some tests do expect failure!
216 //PJ_LOG(3,(THIS_FILE," error: timer unable to send response"));
217 pj_mutex_unlock(tsx->mutex);
Benny Prijonodbe337a2006-01-08 23:57:52 +0000218 pjsip_tx_data_dec_ref(r->tdata);
219 return;
220 }
Benny Prijono728a9052006-01-18 23:34:15 +0000221
222 pj_mutex_unlock(tsx->mutex);
Benny Prijonodbe337a2006-01-08 23:57:52 +0000223}
224
Benny Prijono0c2bc612006-01-10 13:31:40 +0000225/* Utility to send response. */
226static void send_response( pjsip_rx_data *rdata,
227 pjsip_transaction *tsx,
228 int status_code )
229{
230 pj_status_t status;
231 pjsip_tx_data *tdata;
232
233 status = pjsip_endpt_create_response( endpt, rdata, status_code, NULL,
234 &tdata);
235 if (status != PJ_SUCCESS) {
236 app_perror(" error: unable to create response", status);
237 test_complete = -196;
238 return;
239 }
240
241 status = pjsip_tsx_send_msg(tsx, tdata);
242 if (status != PJ_SUCCESS) {
Benny Prijono0c2bc612006-01-10 13:31:40 +0000243 pjsip_tx_data_dec_ref(tdata);
Benny Prijono728a9052006-01-18 23:34:15 +0000244 // Some tests do expect failure!
245 //app_perror(" error: unable to send response", status);
246 //test_complete = -197;
Benny Prijono0c2bc612006-01-10 13:31:40 +0000247 return;
248 }
249}
250
Benny Prijonodbe337a2006-01-08 23:57:52 +0000251/* Schedule timer to send response for the specified UAS transaction */
252static void schedule_send_response( pjsip_rx_data *rdata,
253 const pj_str_t *tsx_key,
254 int status_code,
255 int msec_delay )
256{
257 pj_status_t status;
258 pjsip_tx_data *tdata;
Benny Prijono728a9052006-01-18 23:34:15 +0000259 pj_timer_entry *t;
Benny Prijonodbe337a2006-01-08 23:57:52 +0000260 struct response *r;
261 pj_time_val delay;
262
263 status = pjsip_endpt_create_response( endpt, rdata, status_code, NULL,
264 &tdata);
265 if (status != PJ_SUCCESS) {
266 app_perror(" error: unable to create response", status);
267 test_complete = -198;
268 return;
269 }
270
271 r = pj_pool_alloc(tdata->pool, sizeof(*r));
272 pj_strdup(tdata->pool, &r->tsx_key, tsx_key);
273 r->tdata = tdata;
274
275 delay.sec = 0;
276 delay.msec = msec_delay;
277 pj_time_val_normalize(&delay);
278
Benny Prijono728a9052006-01-18 23:34:15 +0000279 t = pj_pool_zalloc(tdata->pool, sizeof(*t));
280 t->user_data = r;
281 t->cb = &send_response_timer;
Benny Prijonodbe337a2006-01-08 23:57:52 +0000282
Benny Prijono728a9052006-01-18 23:34:15 +0000283 status = pjsip_endpt_schedule_timer(endpt, t, &delay);
Benny Prijonodbe337a2006-01-08 23:57:52 +0000284 if (status != PJ_SUCCESS) {
Benny Prijono728a9052006-01-18 23:34:15 +0000285 pjsip_tx_data_dec_ref(tdata);
Benny Prijonodbe337a2006-01-08 23:57:52 +0000286 app_perror(" error: unable to schedule timer", status);
287 test_complete = -199;
Benny Prijonodbe337a2006-01-08 23:57:52 +0000288 return;
289 }
290}
291
Benny Prijono0c2bc612006-01-10 13:31:40 +0000292
293/* Find and terminate tsx with the specified key. */
294static void terminate_our_tsx(int status_code)
295{
296 pjsip_transaction *tsx;
297
298 tsx = pjsip_tsx_layer_find_tsx(&tsx_key, PJ_TRUE);
299 if (!tsx) {
300 PJ_LOG(3,(THIS_FILE," error: timer unable to find transaction"));
301 return;
302 }
303
304 pjsip_tsx_terminate(tsx, status_code);
305 pj_mutex_unlock(tsx->mutex);
306}
307
308/* Timer callback to terminate transaction. */
309static void terminate_tsx_timer( pj_timer_heap_t *timer_heap,
310 struct pj_timer_entry *entry)
311{
312 terminate_our_tsx(entry->id);
313}
314
315
316/* Schedule timer to terminate transaction. */
317static void schedule_terminate_tsx( pjsip_transaction *tsx,
318 int status_code,
319 int msec_delay )
320{
321 pj_time_val delay;
322
323 delay.sec = 0;
324 delay.msec = msec_delay;
325 pj_time_val_normalize(&delay);
326
327 pj_assert(pj_strcmp(&tsx->transaction_key, &tsx_key)==0);
328 timer.user_data = NULL;
329 timer.id = status_code;
330 timer.cb = &terminate_tsx_timer;
331 pjsip_endpt_schedule_timer(endpt, &timer, &delay);
332}
333
334
Benny Prijonodbe337a2006-01-08 23:57:52 +0000335/*
336 * This is the handler to receive state changed notification from the
337 * transaction. It is used to verify that the transaction behaves according
338 * to the test scenario.
339 */
340static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e)
341{
342 if (pj_strcmp2(&tsx->branch, TEST1_BRANCH_ID)==0 ||
343 pj_strcmp2(&tsx->branch, TEST2_BRANCH_ID)==0)
344 {
345 /*
346 * TEST1_BRANCH_ID tests that non-INVITE transaction transmits final
347 * response using correct transport and terminates transaction after
348 * T4 (PJSIP_T4_TIMEOUT, 5 seconds).
349 *
350 * TEST2_BRANCH_ID does similar test for non-2xx final response.
351 */
352 int status_code = (pj_strcmp2(&tsx->branch, TEST1_BRANCH_ID)==0) ?
353 TEST1_STATUS_CODE : TEST2_STATUS_CODE;
354
355 if (tsx->state == PJSIP_TSX_STATE_TERMINATED) {
356
357 test_complete = 1;
358
359 /* Check that status code is status_code. */
360 if (tsx->status_code != status_code) {
361 PJ_LOG(3,(THIS_FILE, " error: incorrect status code"));
362 test_complete = -100;
363 }
364
365 /* Previous state must be completed. */
366 if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_COMPLETED) {
367 PJ_LOG(3,(THIS_FILE, " error: incorrect prev_state"));
368 test_complete = -101;
369 }
370
371 } else if (tsx->state == PJSIP_TSX_STATE_COMPLETED) {
372
373 /* Previous state must be TRYING. */
374 if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_TRYING) {
375 PJ_LOG(3,(THIS_FILE, " error: incorrect prev_state"));
376 test_complete = -102;
377 }
378 }
379
380 }
381 else
382 if (pj_strcmp2(&tsx->branch, TEST3_BRANCH_ID)==0) {
383 /*
384 * TEST3_BRANCH_ID tests sending provisional response.
385 */
386 if (tsx->state == PJSIP_TSX_STATE_TERMINATED) {
387
388 test_complete = 1;
389
390 /* Check that status code is status_code. */
391 if (tsx->status_code != TEST3_STATUS_CODE) {
392 PJ_LOG(3,(THIS_FILE, " error: incorrect status code"));
393 test_complete = -110;
394 }
395
396 /* Previous state must be completed. */
397 if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_COMPLETED) {
398 PJ_LOG(3,(THIS_FILE, " error: incorrect prev_state"));
399 test_complete = -111;
400 }
401
402 } else if (tsx->state == PJSIP_TSX_STATE_PROCEEDING) {
403
404 /* Previous state must be TRYING. */
405 if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_TRYING) {
406 PJ_LOG(3,(THIS_FILE, " error: incorrect prev_state"));
407 test_complete = -112;
408 }
409
410 /* Check that status code is status_code. */
411 if (tsx->status_code != TEST3_PROVISIONAL_CODE) {
412 PJ_LOG(3,(THIS_FILE, " error: incorrect status code"));
413 test_complete = -113;
414 }
415
416 /* Check that event must be TX_MSG */
417 if (e->body.tsx_state.type != PJSIP_EVENT_TX_MSG) {
418 PJ_LOG(3,(THIS_FILE, " error: incorrect event"));
419 test_complete = -114;
420 }
421
422 } else if (tsx->state == PJSIP_TSX_STATE_COMPLETED) {
423
424 /* Previous state must be PROCEEDING. */
425 if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_PROCEEDING) {
426 PJ_LOG(3,(THIS_FILE, " error: incorrect prev_state"));
427 test_complete = -115;
428 }
429
430 /* Check that status code is status_code. */
431 if (tsx->status_code != TEST3_STATUS_CODE) {
432 PJ_LOG(3,(THIS_FILE, " error: incorrect status code"));
433 test_complete = -116;
434 }
435
436 /* Check that event must be TX_MSG */
437 if (e->body.tsx_state.type != PJSIP_EVENT_TX_MSG) {
438 PJ_LOG(3,(THIS_FILE, " error: incorrect event"));
439 test_complete = -117;
440 }
441
442 }
443
Benny Prijono0c2bc612006-01-10 13:31:40 +0000444 } else
445 if (pj_strcmp2(&tsx->branch, TEST4_BRANCH_ID)==0) {
446 /*
447 * TEST4_BRANCH_ID tests receiving retransmissions in TRYING state.
448 */
449 if (tsx->state == PJSIP_TSX_STATE_TERMINATED) {
450
451 /* Check that status code is status_code. */
452 if (tsx->status_code != TEST4_STATUS_CODE) {
453 PJ_LOG(3,(THIS_FILE, " error: incorrect status code"));
454 test_complete = -120;
455 }
456
457 /* Previous state. */
458 if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_TRYING) {
459 PJ_LOG(3,(THIS_FILE, " error: incorrect prev_state"));
460 test_complete = -121;
461 }
462
463 } else if (tsx->state != PJSIP_TSX_STATE_DESTROYED)
464 {
465 PJ_LOG(3,(THIS_FILE, " error: unexpected state"));
466 test_complete = -122;
467
468 }
469
470
471 } else
472 if (pj_strcmp2(&tsx->branch, TEST5_BRANCH_ID)==0) {
473 /*
474 * TEST5_BRANCH_ID tests receiving retransmissions in PROCEEDING state
475 */
476 if (tsx->state == PJSIP_TSX_STATE_TERMINATED) {
477
478 /* Check that status code is status_code. */
479 if (tsx->status_code != TEST5_STATUS_CODE) {
480 PJ_LOG(3,(THIS_FILE, " error: incorrect status code"));
481 test_complete = -130;
482 }
483
484 /* Previous state. */
485 if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_PROCEEDING) {
486 PJ_LOG(3,(THIS_FILE, " error: incorrect prev_state"));
487 test_complete = -131;
488 }
489
490 } else if (tsx->state == PJSIP_TSX_STATE_PROCEEDING) {
491
492 /* Check status code. */
493 if (tsx->status_code != TEST5_PROVISIONAL_CODE) {
494 PJ_LOG(3,(THIS_FILE, " error: incorrect status code"));
495 test_complete = -132;
496 }
497
498 } else if (tsx->state != PJSIP_TSX_STATE_DESTROYED) {
499 PJ_LOG(3,(THIS_FILE, " error: unexpected state"));
500 test_complete = -133;
501
502 }
503
504 } else
505 if (pj_strcmp2(&tsx->branch, TEST6_BRANCH_ID)==0) {
506 /*
507 * TEST6_BRANCH_ID tests receiving retransmissions in COMPLETED state
508 */
509 if (tsx->state == PJSIP_TSX_STATE_TERMINATED) {
510
511 /* Check that status code is status_code. */
512 if (tsx->status_code != TEST6_STATUS_CODE) {
513 PJ_LOG(3,(THIS_FILE, " error: incorrect status code"));
514 test_complete = -140;
515 }
516
517 /* Previous state. */
518 if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_COMPLETED) {
519 PJ_LOG(3,(THIS_FILE, " error: incorrect prev_state"));
520 test_complete = -141;
521 }
522
523 } else if (tsx->state != PJSIP_TSX_STATE_PROCEEDING &&
524 tsx->state != PJSIP_TSX_STATE_COMPLETED &&
525 tsx->state != PJSIP_TSX_STATE_DESTROYED)
526 {
527 PJ_LOG(3,(THIS_FILE, " error: unexpected state"));
528 test_complete = -142;
529
530 }
531
532
533 } else
534 if (pj_strcmp2(&tsx->branch, TEST7_BRANCH_ID)==0 ||
535 pj_strcmp2(&tsx->branch, TEST8_BRANCH_ID)==0)
536 {
537 /*
538 * TEST7_BRANCH_ID and TEST8_BRANCH_ID test retransmission of
539 * INVITE final response
540 */
541 int code;
542
543 if (pj_strcmp2(&tsx->branch, TEST7_BRANCH_ID) == 0)
544 code = TEST7_STATUS_CODE;
545 else
546 code = TEST8_STATUS_CODE;
547
548 if (tsx->state == PJSIP_TSX_STATE_TERMINATED) {
549
550 if (test_complete == 0)
551 test_complete = 1;
552
553 /* Check status code. */
554 if (tsx->status_code != PJSIP_SC_TSX_TIMEOUT) {
555 PJ_LOG(3,(THIS_FILE, " error: incorrect status code"));
556 test_complete = -150;
557 }
558
559 /* Previous state. */
560 if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_COMPLETED) {
561 PJ_LOG(3,(THIS_FILE, " error: incorrect prev_state"));
562 test_complete = -151;
563 }
564
565 } else if (tsx->state == PJSIP_TSX_STATE_COMPLETED) {
566
567 /* Check that status code is status_code. */
568 if (tsx->status_code != code) {
569 PJ_LOG(3,(THIS_FILE, " error: incorrect status code"));
570 test_complete = -152;
571 }
572
573 /* Previous state. */
574 if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_TRYING) {
575 PJ_LOG(3,(THIS_FILE, " error: incorrect prev_state"));
576 test_complete = -153;
577 }
578
579 } else if (tsx->state != PJSIP_TSX_STATE_DESTROYED) {
580
581 PJ_LOG(3,(THIS_FILE, " error: unexpected state"));
582 test_complete = -154;
583
584 }
585
Benny Prijono728a9052006-01-18 23:34:15 +0000586
587 } else
588 if (pj_strcmp2(&tsx->branch, TEST9_BRANCH_ID)==0) {
589 /*
590 * TEST9_BRANCH_ID tests that retransmission of INVITE final response
591 * must cease when ACK is received.
592 */
593
594 if (tsx->state == PJSIP_TSX_STATE_TERMINATED) {
595
596 if (test_complete == 0)
597 test_complete = 1;
598
599 /* Check status code. */
600 if (tsx->status_code != TEST9_STATUS_CODE) {
601 PJ_LOG(3,(THIS_FILE, " error: incorrect status code"));
602 test_complete = -160;
603 }
604
605 /* Previous state. */
606 if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_CONFIRMED) {
607 PJ_LOG(3,(THIS_FILE, " error: incorrect prev_state"));
608 test_complete = -161;
609 }
610
611 } else if (tsx->state == PJSIP_TSX_STATE_COMPLETED) {
612
613 /* Check that status code is status_code. */
614 if (tsx->status_code != TEST9_STATUS_CODE) {
615 PJ_LOG(3,(THIS_FILE, " error: incorrect status code"));
616 test_complete = -162;
617 }
618
619 /* Previous state. */
620 if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_TRYING) {
621 PJ_LOG(3,(THIS_FILE, " error: incorrect prev_state"));
622 test_complete = -163;
623 }
624
625
626 } else if (tsx->state == PJSIP_TSX_STATE_CONFIRMED) {
627
628 /* Check that status code is status_code. */
629 if (tsx->status_code != TEST9_STATUS_CODE) {
630 PJ_LOG(3,(THIS_FILE, " error: incorrect status code"));
631 test_complete = -164;
632 }
633
634 /* Previous state. */
635 if (e->body.tsx_state.prev_state != PJSIP_TSX_STATE_COMPLETED) {
636 PJ_LOG(3,(THIS_FILE, " error: incorrect prev_state"));
637 test_complete = -165;
638 }
639
640 } else if (tsx->state != PJSIP_TSX_STATE_DESTROYED) {
641
642 PJ_LOG(3,(THIS_FILE, " error: unexpected state"));
643 test_complete = -166;
644
645 }
646
647
648 } else
649 if (pj_strcmp2(&tsx->branch, TEST10_BRANCH_ID)==0 ||
650 pj_strcmp2(&tsx->branch, TEST11_BRANCH_ID)==0 ||
651 pj_strcmp2(&tsx->branch, TEST12_BRANCH_ID)==0)
652 {
653 if (tsx->state == PJSIP_TSX_STATE_TERMINATED) {
654
655 if (!test_complete)
656 test_complete = 1;
657
658 if (tsx->status_code != PJSIP_SC_TSX_TRANSPORT_ERROR) {
659 PJ_LOG(3,(THIS_FILE," error: incorrect status code"));
660 test_complete = -170;
661 }
662 }
Benny Prijonodbe337a2006-01-08 23:57:52 +0000663 }
664
665}
666
667/* Save transaction key to global variables. */
668static void save_key(pjsip_transaction *tsx)
669{
670 pj_str_t key;
671
672 pj_strdup(tsx->pool, &key, &tsx->transaction_key);
673 pj_strcpy(&tsx_key, &key);
674}
675
Benny Prijono0c2bc612006-01-10 13:31:40 +0000676#define DIFF(a,b) ((a<b) ? (b-a) : (a-b))
677
Benny Prijonodbe337a2006-01-08 23:57:52 +0000678/*
679 * Message receiver handler.
680 */
681static pj_bool_t on_rx_message(pjsip_rx_data *rdata)
682{
683 pjsip_msg *msg = rdata->msg_info.msg;
684 pj_str_t branch_param = rdata->msg_info.via->branch_param;
685 pj_status_t status;
686
687 if (pj_strcmp2(&branch_param, TEST1_BRANCH_ID) == 0 ||
688 pj_strcmp2(&branch_param, TEST2_BRANCH_ID) == 0)
689 {
690 /*
691 * TEST1_BRANCH_ID tests that non-INVITE transaction transmits 2xx
692 * final response using correct transport and terminates transaction
693 * after 32 seconds.
694 *
695 * TEST2_BRANCH_ID performs similar test for non-2xx final response.
696 */
697 int status_code = (pj_strcmp2(&branch_param, TEST1_BRANCH_ID) == 0) ?
698 TEST1_STATUS_CODE : TEST2_STATUS_CODE;
699
700 if (msg->type == PJSIP_REQUEST_MSG) {
Benny Prijono728a9052006-01-18 23:34:15 +0000701 /* On received request, create UAS and respond with final
Benny Prijonodbe337a2006-01-08 23:57:52 +0000702 * response.
703 */
704 pjsip_transaction *tsx;
Benny Prijonodbe337a2006-01-08 23:57:52 +0000705
706 status = pjsip_tsx_create_uas(&tsx_user, rdata, &tsx);
707 if (status != PJ_SUCCESS) {
708 app_perror(" error: unable to create transaction", status);
709 test_complete = -110;
710 return PJ_TRUE;
711 }
Benny Prijono38998232006-02-08 22:44:25 +0000712 pjsip_tsx_recv_msg(tsx, rdata);
Benny Prijonodbe337a2006-01-08 23:57:52 +0000713
714 save_key(tsx);
Benny Prijono0c2bc612006-01-10 13:31:40 +0000715 send_response(rdata, tsx, status_code);
Benny Prijonodbe337a2006-01-08 23:57:52 +0000716
717 } else {
718 /* Verify the response received. */
719
720 ++recv_count;
721
722 /* Verify status code. */
723 if (msg->line.status.code != status_code) {
724 PJ_LOG(3,(THIS_FILE, " error: incorrect status code"));
725 test_complete = -113;
726 }
727
728 /* Verify that no retransmissions is received. */
729 if (recv_count > 1) {
730 PJ_LOG(3,(THIS_FILE, " error: retransmission received"));
731 test_complete = -114;
732 }
733
734 }
735 return PJ_TRUE;
736
737 } else if (pj_strcmp2(&branch_param, TEST3_BRANCH_ID) == 0) {
738
739 /* TEST3_BRANCH_ID tests provisional response. */
740
741 if (msg->type == PJSIP_REQUEST_MSG) {
Benny Prijono728a9052006-01-18 23:34:15 +0000742 /* On received request, create UAS and respond with provisional
Benny Prijonodbe337a2006-01-08 23:57:52 +0000743 * response, then schedule timer to send final response.
744 */
745 pjsip_transaction *tsx;
Benny Prijonodbe337a2006-01-08 23:57:52 +0000746
747 status = pjsip_tsx_create_uas(&tsx_user, rdata, &tsx);
748 if (status != PJ_SUCCESS) {
749 app_perror(" error: unable to create transaction", status);
750 test_complete = -120;
751 return PJ_TRUE;
752 }
Benny Prijono38998232006-02-08 22:44:25 +0000753 pjsip_tsx_recv_msg(tsx, rdata);
Benny Prijonodbe337a2006-01-08 23:57:52 +0000754
755 save_key(tsx);
756
Benny Prijono0c2bc612006-01-10 13:31:40 +0000757 send_response(rdata, tsx, TEST3_PROVISIONAL_CODE);
Benny Prijonodbe337a2006-01-08 23:57:52 +0000758 schedule_send_response(rdata, &tsx->transaction_key,
759 TEST3_STATUS_CODE, 2000);
760
761 } else {
762 /* Verify the response received. */
763
764 ++recv_count;
765
766 if (recv_count == 1) {
767 /* Verify status code. */
768 if (msg->line.status.code != TEST3_PROVISIONAL_CODE) {
769 PJ_LOG(3,(THIS_FILE, " error: incorrect status code"));
770 test_complete = -123;
771 }
772 } else if (recv_count == 2) {
773 /* Verify status code. */
774 if (msg->line.status.code != TEST3_STATUS_CODE) {
775 PJ_LOG(3,(THIS_FILE, " error: incorrect status code"));
776 test_complete = -124;
777 }
778 } else {
779 PJ_LOG(3,(THIS_FILE, " error: retransmission received"));
780 test_complete = -125;
781 }
782
783 }
784 return PJ_TRUE;
785
Benny Prijono0c2bc612006-01-10 13:31:40 +0000786 } else if (pj_strcmp2(&branch_param, TEST4_BRANCH_ID) == 0 ||
787 pj_strcmp2(&branch_param, TEST5_BRANCH_ID) == 0 ||
788 pj_strcmp2(&branch_param, TEST6_BRANCH_ID) == 0)
789 {
790
791 /* TEST4_BRANCH_ID: absorbs retransmissions in TRYING state. */
792 /* TEST5_BRANCH_ID: retransmit last response in PROCEEDING state. */
793 /* TEST6_BRANCH_ID: retransmit last response in COMPLETED state. */
794
795 if (msg->type == PJSIP_REQUEST_MSG) {
Benny Prijono728a9052006-01-18 23:34:15 +0000796 /* On received request, create UAS. */
Benny Prijono0c2bc612006-01-10 13:31:40 +0000797 pjsip_transaction *tsx;
798
799 status = pjsip_tsx_create_uas(&tsx_user, rdata, &tsx);
800 if (status != PJ_SUCCESS) {
801 app_perror(" error: unable to create transaction", status);
802 test_complete = -130;
803 return PJ_TRUE;
804 }
805
Benny Prijono38998232006-02-08 22:44:25 +0000806 pjsip_tsx_recv_msg(tsx, rdata);
Benny Prijono0c2bc612006-01-10 13:31:40 +0000807 save_key(tsx);
808
809 if (pj_strcmp2(&branch_param, TEST4_BRANCH_ID) == 0) {
810
811 } else if (pj_strcmp2(&branch_param, TEST5_BRANCH_ID) == 0) {
812 send_response(rdata, tsx, TEST5_PROVISIONAL_CODE);
813
814 } else if (pj_strcmp2(&branch_param, TEST6_BRANCH_ID) == 0) {
815 send_response(rdata, tsx, TEST6_PROVISIONAL_CODE);
816 send_response(rdata, tsx, TEST6_STATUS_CODE);
817 }
818
819 } else {
820 /* Verify the response received. */
821
822 ++recv_count;
823
824 if (pj_strcmp2(&branch_param, TEST4_BRANCH_ID) == 0) {
825 PJ_LOG(3,(THIS_FILE, " error: not expecting response!"));
826 test_complete = -132;
827
828 } else if (pj_strcmp2(&branch_param, TEST5_BRANCH_ID) == 0) {
829
830 if (rdata->msg_info.msg->line.status.code!=TEST5_PROVISIONAL_CODE) {
831 PJ_LOG(3,(THIS_FILE, " error: incorrect status code!"));
832 test_complete = -133;
833
834 }
835 if (recv_count > TEST5_RESPONSE_COUNT) {
836 PJ_LOG(3,(THIS_FILE, " error: not expecting response!"));
837 test_complete = -134;
838 }
839
840 } else if (pj_strcmp2(&branch_param, TEST6_BRANCH_ID) == 0) {
841
842 int code = rdata->msg_info.msg->line.status.code;
843
844 switch (recv_count) {
845 case 1:
846 if (code != TEST6_PROVISIONAL_CODE) {
847 PJ_LOG(3,(THIS_FILE, " error: invalid code!"));
848 test_complete = -135;
849 }
850 break;
851 case 2:
852 case 3:
853 if (code != TEST6_STATUS_CODE) {
854 PJ_LOG(3,(THIS_FILE, " error: invalid code!"));
855 test_complete = -136;
856 }
857 break;
858 default:
859 PJ_LOG(3,(THIS_FILE, " error: not expecting response"));
860 test_complete = -137;
861 break;
862 }
863 }
864 }
865 return PJ_TRUE;
866
867
868 } else if (pj_strcmp2(&branch_param, TEST7_BRANCH_ID) == 0 ||
869 pj_strcmp2(&branch_param, TEST8_BRANCH_ID) == 0)
870 {
871
872 /*
873 * TEST7_BRANCH_ID and TEST8_BRANCH_ID test the retransmission
874 * of INVITE final response
875 */
876 if (msg->type == PJSIP_REQUEST_MSG) {
877
Benny Prijono728a9052006-01-18 23:34:15 +0000878 /* On received request, create UAS. */
Benny Prijono0c2bc612006-01-10 13:31:40 +0000879 pjsip_transaction *tsx;
880
881 status = pjsip_tsx_create_uas(&tsx_user, rdata, &tsx);
882 if (status != PJ_SUCCESS) {
883 app_perror(" error: unable to create transaction", status);
884 test_complete = -140;
885 return PJ_TRUE;
886 }
887
Benny Prijono38998232006-02-08 22:44:25 +0000888 pjsip_tsx_recv_msg(tsx, rdata);
Benny Prijono0c2bc612006-01-10 13:31:40 +0000889 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
Benny Prijono38998232006-02-08 22:44:25 +0000973 pjsip_tsx_recv_msg(tsx, rdata);
Benny Prijono0c2bc612006-01-10 13:31:40 +0000974 save_key(tsx);
Benny Prijono728a9052006-01-18 23:34:15 +0000975 send_response(rdata, tsx, TEST9_STATUS_CODE);
Benny Prijono0c2bc612006-01-10 13:31:40 +0000976
Benny Prijono0c2bc612006-01-10 13:31:40 +0000977
978 } else {
Benny Prijono0c2bc612006-01-10 13:31:40 +0000979
980 ++recv_count;
981
Benny Prijono728a9052006-01-18 23:34:15 +0000982 if (rdata->msg_info.msg->line.status.code != TEST9_STATUS_CODE) {
983 PJ_LOG(3,(THIS_FILE," error: invalid status code"));
984 test_complete = -151;
985 }
Benny Prijono0c2bc612006-01-10 13:31:40 +0000986
987 if (recv_count==1) {
Benny Prijono0c2bc612006-01-10 13:31:40 +0000988
989 recv_last = rdata->pkt_info.timestamp;
990
Benny Prijono728a9052006-01-18 23:34:15 +0000991 } else if (recv_count < 5) {
Benny Prijono0c2bc612006-01-10 13:31:40 +0000992
Benny Prijono728a9052006-01-18 23:34:15 +0000993 /* Let UAS retransmit some messages before we send ACK. */
Benny Prijono0c2bc612006-01-10 13:31:40 +0000994 pj_time_val now;
995 unsigned msec, msec_expected;
996
997 now = rdata->pkt_info.timestamp;
998
999 PJ_TIME_VAL_SUB(now, recv_last);
1000
1001 msec = now.sec*1000 + now.msec;
1002 msec_expected = (1 << (recv_count-2)) * PJSIP_T1_TIMEOUT;
1003 if (msec_expected > PJSIP_T2_TIMEOUT)
1004 msec_expected = PJSIP_T2_TIMEOUT;
1005
1006 if (DIFF(msec, msec_expected) > MAX_ALLOWED_DIFF) {
1007 PJ_LOG(3,(THIS_FILE,
1008 " error: incorrect retransmission "
1009 "time (%d ms expected, %d ms received",
1010 msec_expected, msec));
Benny Prijono728a9052006-01-18 23:34:15 +00001011 test_complete = -152;
Benny Prijono0c2bc612006-01-10 13:31:40 +00001012 }
1013
1014 recv_last = rdata->pkt_info.timestamp;
Benny Prijono728a9052006-01-18 23:34:15 +00001015
1016 } else if (recv_count == 5) {
1017 pjsip_tx_data *tdata;
1018 pjsip_sip_uri *uri;
1019 pjsip_via_hdr *via;
1020
1021 status = pjsip_endpt_create_request_from_hdr(
1022 endpt, &pjsip_ack_method,
1023 rdata->msg_info.to->uri,
1024 rdata->msg_info.from,
1025 rdata->msg_info.to,
1026 NULL,
1027 rdata->msg_info.cid,
1028 rdata->msg_info.cseq->cseq,
1029 NULL,
1030 &tdata);
1031 if (status != PJ_SUCCESS) {
1032 app_perror(" error: unable to create ACK", status);
1033 test_complete = -153;
1034 return PJ_TRUE;
1035 }
1036
1037 uri=(pjsip_sip_uri*)pjsip_uri_get_uri(tdata->msg->line.req.uri);
1038 uri->transport_param = pj_str("loop-dgram");
1039
1040 via = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL);
1041 via->branch_param = pj_str(TEST9_BRANCH_ID);
1042
1043 status = pjsip_endpt_send_request_stateless(endpt, tdata,
1044 NULL, NULL);
1045 if (status != PJ_SUCCESS) {
1046 app_perror(" error: unable to send ACK", status);
1047 test_complete = -154;
1048 }
1049
1050 } else {
1051 PJ_LOG(3,(THIS_FILE," error: too many responses (%d)",
1052 recv_count));
1053 test_complete = -155;
Benny Prijono0c2bc612006-01-10 13:31:40 +00001054 }
1055
1056 }
1057 return PJ_TRUE;
Benny Prijono728a9052006-01-18 23:34:15 +00001058
1059 } else if (pj_strcmp2(&branch_param, TEST10_BRANCH_ID) == 0 ||
1060 pj_strcmp2(&branch_param, TEST11_BRANCH_ID) == 0 ||
1061 pj_strcmp2(&branch_param, TEST12_BRANCH_ID) == 0)
1062 {
1063 int test_num, code1, code2;
1064
1065 if (pj_strcmp2(&branch_param, TEST10_BRANCH_ID) == 0)
1066 test_num=10, code1 = 100, code2 = 0;
1067 else if (pj_strcmp2(&branch_param, TEST11_BRANCH_ID) == 0)
1068 test_num=11, code1 = 100, code2 = 200;
1069 else
1070 test_num=12, code1 = 200, code2 = 0;
1071
1072 if (rdata->msg_info.msg->type == PJSIP_REQUEST_MSG) {
1073
1074 /* On received response, create UAS. */
1075 pjsip_transaction *tsx;
1076
1077 status = pjsip_tsx_create_uas(&tsx_user, rdata, &tsx);
1078 if (status != PJ_SUCCESS) {
1079 app_perror(" error: unable to create transaction", status);
1080 test_complete = -150;
1081 return PJ_TRUE;
1082 }
1083
Benny Prijono38998232006-02-08 22:44:25 +00001084 pjsip_tsx_recv_msg(tsx, rdata);
Benny Prijono728a9052006-01-18 23:34:15 +00001085 save_key(tsx);
1086
1087 schedule_send_response(rdata, &tsx_key, code1, 1000);
1088
1089 if (code2)
1090 schedule_send_response(rdata, &tsx_key, code2, 2000);
1091
1092 } else {
1093
1094 }
1095
1096 return PJ_TRUE;
Benny Prijonodbe337a2006-01-08 23:57:52 +00001097 }
1098
1099 return PJ_FALSE;
1100}
1101
1102/*
1103 * The generic test framework, used by most of the tests.
1104 */
1105static int perform_test( char *target_uri, char *from_uri,
1106 char *branch_param, int test_time,
Benny Prijono0c2bc612006-01-10 13:31:40 +00001107 const pjsip_method *method,
1108 int request_cnt, int request_interval_msec,
1109 int expecting_timeout)
Benny Prijonodbe337a2006-01-08 23:57:52 +00001110{
1111 pjsip_tx_data *tdata;
1112 pj_str_t target, from;
1113 pjsip_via_hdr *via;
Benny Prijono0c2bc612006-01-10 13:31:40 +00001114 pj_time_val timeout, next_send;
1115 int sent_cnt;
Benny Prijonodbe337a2006-01-08 23:57:52 +00001116 pj_status_t status;
1117
1118 PJ_LOG(3,(THIS_FILE,
1119 " please standby, this will take at most %d seconds..",
1120 test_time));
1121
1122 /* Reset test. */
1123 recv_count = 0;
1124 test_complete = 0;
1125 tsx_key.slen = 0;
1126
1127 /* Init headers. */
1128 target = pj_str(target_uri);
1129 from = pj_str(from_uri);
1130
1131 /* Create request. */
1132 status = pjsip_endpt_create_request( endpt, method, &target,
1133 &from, &target, NULL, NULL, -1,
1134 NULL, &tdata);
1135 if (status != PJ_SUCCESS) {
1136 app_perror(" Error: unable to create request", status);
1137 return -10;
1138 }
1139
1140 /* Set the branch param for test 1. */
1141 via = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL);
1142 via->branch_param = pj_str(branch_param);
1143
Benny Prijono0c2bc612006-01-10 13:31:40 +00001144 /* Schedule first send. */
1145 sent_cnt = 0;
1146 pj_gettimeofday(&next_send);
1147 pj_time_val_normalize(&next_send);
Benny Prijonodbe337a2006-01-08 23:57:52 +00001148
1149 /* Set test completion time. */
1150 pj_gettimeofday(&timeout);
1151 timeout.sec += test_time;
1152
1153 /* Wait until test complete. */
1154 while (!test_complete) {
1155 pj_time_val now, poll_delay = {0, 10};
1156
1157 pjsip_endpt_handle_events(endpt, &poll_delay);
1158
1159 pj_gettimeofday(&now);
Benny Prijono0c2bc612006-01-10 13:31:40 +00001160
1161 if (sent_cnt < request_cnt && PJ_TIME_VAL_GTE(now, next_send)) {
1162 /* Add additional reference to tdata to prevent transaction from
1163 * deleting it.
1164 */
1165 pjsip_tx_data_add_ref(tdata);
1166
1167 /* (Re)Send the request. */
1168 status = pjsip_endpt_send_request_stateless(endpt, tdata, 0, 0);
1169 if (status != PJ_SUCCESS) {
1170 app_perror(" Error: unable to send request", status);
1171 pjsip_tx_data_dec_ref(tdata);
1172 return -20;
1173 }
1174
1175 /* Schedule next send, if any. */
1176 sent_cnt++;
1177 if (sent_cnt < request_cnt) {
1178 pj_gettimeofday(&next_send);
1179 next_send.msec += request_interval_msec;
1180 pj_time_val_normalize(&next_send);
1181 }
1182 }
1183
Benny Prijonodbe337a2006-01-08 23:57:52 +00001184 if (now.sec > timeout.sec) {
Benny Prijono0c2bc612006-01-10 13:31:40 +00001185 if (!expecting_timeout)
1186 PJ_LOG(3,(THIS_FILE, " Error: test has timed out"));
Benny Prijonodbe337a2006-01-08 23:57:52 +00001187 pjsip_tx_data_dec_ref(tdata);
Benny Prijono0c2bc612006-01-10 13:31:40 +00001188 return TEST_TIMEOUT_ERROR;
Benny Prijonodbe337a2006-01-08 23:57:52 +00001189 }
1190 }
1191
1192 if (test_complete < 0) {
1193 pjsip_transaction *tsx;
1194
1195 tsx = pjsip_tsx_layer_find_tsx(&tsx_key, PJ_TRUE);
1196 if (tsx) {
1197 pjsip_tsx_terminate(tsx, PJSIP_SC_REQUEST_TERMINATED);
1198 pj_mutex_unlock(tsx->mutex);
1199 flush_events(1000);
1200 }
1201 pjsip_tx_data_dec_ref(tdata);
1202 return test_complete;
1203 }
1204
1205 /* Allow transaction to destroy itself */
1206 flush_events(500);
1207
1208 /* Make sure transaction has been destroyed. */
1209 if (pjsip_tsx_layer_find_tsx(&tsx_key, PJ_FALSE) != NULL) {
1210 PJ_LOG(3,(THIS_FILE, " Error: transaction has not been destroyed"));
1211 pjsip_tx_data_dec_ref(tdata);
1212 return -40;
1213 }
1214
1215 /* Check tdata reference counter. */
1216 if (pj_atomic_get(tdata->ref_cnt) != 1) {
1217 PJ_LOG(3,(THIS_FILE, " Error: tdata reference counter is %d",
1218 pj_atomic_get(tdata->ref_cnt)));
1219 pjsip_tx_data_dec_ref(tdata);
1220 return -50;
1221 }
1222
1223 /* Destroy txdata */
1224 pjsip_tx_data_dec_ref(tdata);
1225
1226 return PJ_SUCCESS;
1227
1228}
1229
1230
1231/*****************************************************************************
1232 **
1233 ** TEST1_BRANCH_ID: Basic 2xx final response
1234 ** TEST2_BRANCH_ID: Basic non-2xx final response
1235 **
1236 *****************************************************************************
1237 */
1238static int tsx_basic_final_response_test(void)
1239{
1240 int status;
1241
1242 PJ_LOG(3,(THIS_FILE," test1: basic sending 2xx final response"));
1243
1244 status = perform_test("sip:129.0.0.1;transport=loop-dgram",
1245 "sip:129.0.0.1;transport=loop-dgram",
1246 TEST1_BRANCH_ID,
1247 33, /* Test duration must be greater than 32 secs */
Benny Prijono0c2bc612006-01-10 13:31:40 +00001248 &pjsip_options_method, 1, 0, 0);
Benny Prijonodbe337a2006-01-08 23:57:52 +00001249 if (status != 0)
1250 return status;
1251
1252 PJ_LOG(3,(THIS_FILE," test2: basic sending non-2xx final response"));
1253
1254 status = perform_test("sip:129.0.0.1;transport=loop-dgram",
1255 "sip:129.0.0.1;transport=loop-dgram",
1256 TEST2_BRANCH_ID,
1257 33, /* Test duration must be greater than 32 secs */
Benny Prijono0c2bc612006-01-10 13:31:40 +00001258 &pjsip_options_method, 1, 0, 0);
Benny Prijonodbe337a2006-01-08 23:57:52 +00001259 if (status != 0)
1260 return status;
1261
1262 return 0;
1263}
1264
1265
1266/*****************************************************************************
1267 **
1268 ** TEST3_BRANCH_ID: Sending provisional response
1269 **
1270 *****************************************************************************
1271 */
1272static int tsx_basic_provisional_response_test(void)
1273{
1274 int status;
1275
1276 PJ_LOG(3,(THIS_FILE," test1: basic sending 2xx final response"));
1277
1278 status = perform_test("sip:129.0.0.1;transport=loop-dgram",
1279 "sip:129.0.0.1;transport=loop-dgram",
1280 TEST3_BRANCH_ID,
1281 35,
Benny Prijono0c2bc612006-01-10 13:31:40 +00001282 &pjsip_options_method, 1, 0, 0);
1283
Benny Prijonodbe337a2006-01-08 23:57:52 +00001284 return status;
1285}
1286
1287
1288/*****************************************************************************
1289 **
Benny Prijono0c2bc612006-01-10 13:31:40 +00001290 ** TEST4_BRANCH_ID: Absorbs retransmissions in TRYING state
1291 ** TEST5_BRANCH_ID: Absorbs retransmissions in PROCEEDING state
1292 ** TEST6_BRANCH_ID: Absorbs retransmissions in COMPLETED state
1293 **
1294 *****************************************************************************
1295 */
1296static int tsx_retransmit_last_response_test(const char *title,
1297 char *branch_id,
1298 int request_cnt,
1299 int status_code)
1300{
1301 int status;
1302
1303 PJ_LOG(3,(THIS_FILE," %s", title));
1304
1305 status = perform_test("sip:129.0.0.1;transport=loop-dgram",
1306 "sip:129.0.0.1;transport=loop-dgram",
1307 branch_id,
1308 5,
1309 &pjsip_options_method,
1310 request_cnt, 1000, 1);
1311 if (status && status != TEST_TIMEOUT_ERROR)
1312 return status;
1313 if (!status) {
1314 PJ_LOG(3,(THIS_FILE, " error: expecting timeout"));
1315 return -31;
1316 }
1317
1318 terminate_our_tsx(status_code);
1319 flush_events(100);
1320
1321 if (test_complete != 1)
1322 return test_complete;
1323
1324 flush_events(100);
1325 return 0;
1326}
1327
1328/*****************************************************************************
1329 **
1330 ** TEST7_BRANCH_ID: INVITE non-2xx final response retransmission test
1331 ** TEST8_BRANCH_ID: INVITE 2xx final response retransmission test
1332 **
1333 *****************************************************************************
1334 */
1335static int tsx_final_response_retransmission_test(void)
1336{
1337 int status;
1338
1339 PJ_LOG(3,(THIS_FILE,
1340 " test7: INVITE non-2xx final response retransmission"));
1341
1342 status = perform_test("sip:129.0.0.1;transport=loop-dgram",
1343 "sip:129.0.0.1;transport=loop-dgram",
1344 TEST7_BRANCH_ID,
1345 33, /* Test duration must be greater than 32 secs */
1346 &pjsip_invite_method, 1, 0, 0);
1347 if (status != 0)
1348 return status;
1349
1350 PJ_LOG(3,(THIS_FILE,
1351 " test8: INVITE 2xx final response retransmission"));
1352
1353 status = perform_test("sip:129.0.0.1;transport=loop-dgram",
1354 "sip:129.0.0.1;transport=loop-dgram",
1355 TEST8_BRANCH_ID,
1356 33, /* Test duration must be greater than 32 secs */
1357 &pjsip_invite_method, 1, 0, 0);
1358 if (status != 0)
1359 return status;
1360
1361 return 0;
1362}
1363
1364
Benny Prijono728a9052006-01-18 23:34:15 +00001365/*****************************************************************************
1366 **
1367 ** TEST9_BRANCH_ID: retransmission of non-2xx INVITE final response must
1368 ** cease when ACK is received
1369 **
1370 *****************************************************************************
1371 */
1372static int tsx_ack_test(void)
1373{
1374 int status;
1375
1376 PJ_LOG(3,(THIS_FILE,
1377 " test9: receiving ACK for non-2xx final response"));
1378
1379 status = perform_test("sip:129.0.0.1;transport=loop-dgram",
1380 "sip:129.0.0.1;transport=loop-dgram",
1381 TEST9_BRANCH_ID,
1382 20, /* allow 5 retransmissions */
1383 &pjsip_invite_method, 1, 0, 0);
1384 if (status != 0)
1385 return status;
1386
1387
1388 return 0;
1389}
1390
1391
1392
1393/*****************************************************************************
1394 **
1395 ** TEST10_BRANCH_ID: test transport failure in TRYING state.
1396 ** TEST11_BRANCH_ID: test transport failure in PROCEEDING state.
1397 ** TEST12_BRANCH_ID: test transport failure in CONNECTED state.
1398 ** TEST13_BRANCH_ID: test transport failure in CONFIRMED state.
1399 **
1400 *****************************************************************************
1401 */
1402static int tsx_transport_failure_test(void)
1403{
1404 struct test_desc
1405 {
1406 int transport_delay;
1407 int fail_delay;
1408 char *branch_id;
1409 char *title;
1410 } tests[] =
1411 {
1412 { 0, 10, TEST10_BRANCH_ID, "test10: failed transport in TRYING state (no delay)" },
1413 { 50, 10, TEST10_BRANCH_ID, "test10: failed transport in TRYING state (50 ms delay)" },
1414 { 0, 1500, TEST11_BRANCH_ID, "test11: failed transport in PROCEEDING state (no delay)" },
1415 { 50, 1500, TEST11_BRANCH_ID, "test11: failed transport in PROCEEDING state (50 ms delay)" },
1416 { 0, 2500, TEST12_BRANCH_ID, "test12: failed transport in COMPLETED state (no delay)" },
1417 { 50, 2500, TEST12_BRANCH_ID, "test12: failed transport in COMPLETED state (50 ms delay)" },
1418 };
1419 int i, status;
1420
1421 for (i=0; i<PJ_ARRAY_SIZE(tests); ++i) {
1422 pj_time_val fail_time, end_test, now;
1423
1424 PJ_LOG(3,(THIS_FILE, " %s", tests[i].title));
1425 pjsip_loop_set_failure(loop, 0, NULL);
1426 pjsip_loop_set_delay(loop, tests[i].transport_delay);
1427
1428 status = perform_test("sip:129.0.0.1;transport=loop-dgram",
1429 "sip:129.0.0.1;transport=loop-dgram",
1430 tests[i].branch_id,
1431 0,
1432 &pjsip_invite_method, 1, 0, 1);
1433 if (status && status != TEST_TIMEOUT_ERROR)
1434 return status;
1435 if (!status) {
1436 PJ_LOG(3,(THIS_FILE, " error: expecting timeout"));
1437 return -40;
1438 }
1439
1440 pj_gettimeofday(&fail_time);
1441 fail_time.msec += tests[i].fail_delay;
1442 pj_time_val_normalize(&fail_time);
1443
1444 do {
1445 pj_time_val interval = { 0, 1 };
1446 pj_gettimeofday(&now);
1447 pjsip_endpt_handle_events(endpt, &interval);
1448 } while (PJ_TIME_VAL_LT(now, fail_time));
1449
1450 pjsip_loop_set_failure(loop, 1, NULL);
1451
1452 end_test = now;
1453 end_test.sec += 5;
1454
1455 do {
1456 pj_time_val interval = { 0, 1 };
1457 pj_gettimeofday(&now);
1458 pjsip_endpt_handle_events(endpt, &interval);
1459 } while (!test_complete && PJ_TIME_VAL_LT(now, end_test));
1460
1461 if (test_complete == 0) {
1462 PJ_LOG(3,(THIS_FILE, " error: test has timed out"));
1463 return -41;
1464 }
1465
1466 if (test_complete != 1)
1467 return test_complete;
1468 }
1469
1470 return 0;
1471}
Benny Prijono0c2bc612006-01-10 13:31:40 +00001472
1473/*****************************************************************************
1474 **
Benny Prijonodbe337a2006-01-08 23:57:52 +00001475 ** UAS Transaction Test.
1476 **
1477 *****************************************************************************
1478 */
1479int tsx_uas_test(void)
1480{
1481 pj_sockaddr_in addr;
1482 pj_status_t status;
1483
1484 /* Check if loop transport is configured. */
1485 status = pjsip_endpt_acquire_transport(endpt, PJSIP_TRANSPORT_LOOP_DGRAM,
1486 &addr, sizeof(addr), &loop);
1487 if (status != PJ_SUCCESS) {
1488 PJ_LOG(3,(THIS_FILE, " Error: loop transport is not configured!"));
1489 return -1;
1490 }
1491
1492 /* Register modules. */
1493 status = pjsip_endpt_register_module(endpt, &tsx_user);
1494 if (status != PJ_SUCCESS) {
1495 app_perror(" Error: unable to register module", status);
1496 return -3;
1497 }
1498 status = pjsip_endpt_register_module(endpt, &msg_sender);
1499 if (status != PJ_SUCCESS) {
1500 app_perror(" Error: unable to register module", status);
1501 return -4;
1502 }
1503
Benny Prijonodbe337a2006-01-08 23:57:52 +00001504 /* TEST1_BRANCH_ID: Basic 2xx final response.
1505 * TEST2_BRANCH_ID: Basic non-2xx final response.
1506 */
1507 status = tsx_basic_final_response_test();
1508 if (status != 0)
1509 return status;
Benny Prijonodbe337a2006-01-08 23:57:52 +00001510
1511 /* TEST3_BRANCH_ID: with provisional response
1512 */
1513 status = tsx_basic_provisional_response_test();
1514 if (status != 0)
1515 return status;
1516
Benny Prijono0c2bc612006-01-10 13:31:40 +00001517 /* TEST4_BRANCH_ID: absorbs retransmissions in TRYING state
1518 */
1519 status = tsx_retransmit_last_response_test(TEST4_TITLE,
1520 TEST4_BRANCH_ID,
1521 TEST4_REQUEST_COUNT,
1522 TEST4_STATUS_CODE);
1523 if (status != 0)
1524 return status;
1525
1526 /* TEST5_BRANCH_ID: retransmit last response in PROCEEDING state
1527 */
1528 status = tsx_retransmit_last_response_test(TEST5_TITLE,
1529 TEST5_BRANCH_ID,
1530 TEST5_REQUEST_COUNT,
1531 TEST5_STATUS_CODE);
1532 if (status != 0)
1533 return status;
1534
1535 /* TEST6_BRANCH_ID: retransmit last response in PROCEEDING state
1536 */
1537 status = tsx_retransmit_last_response_test(TEST6_TITLE,
1538 TEST6_BRANCH_ID,
1539 TEST6_REQUEST_COUNT,
1540 TEST6_STATUS_CODE);
1541 if (status != 0)
1542 return status;
1543
1544 /* TEST7_BRANCH_ID: INVITE non-2xx final response retransmission test
1545 * TEST8_BRANCH_ID: INVITE 2xx final response retransmission test
1546 */
1547
1548 status = tsx_final_response_retransmission_test();
1549 if (status != 0)
1550 return status;
1551
Benny Prijono728a9052006-01-18 23:34:15 +00001552 /* TEST9_BRANCH_ID: retransmission of non-2xx INVITE final response must
1553 * cease when ACK is received
1554 */
1555 status = tsx_ack_test();
1556 if (status != 0)
1557 return status;
1558
1559 /* TEST10_BRANCH_ID: test transport failure in TRYING state.
1560 * TEST11_BRANCH_ID: test transport failure in PROCEEDING state.
1561 * TEST12_BRANCH_ID: test transport failure in CONNECTED state.
1562 * TEST13_BRANCH_ID: test transport failure in CONFIRMED state.
1563 */
1564 status = tsx_transport_failure_test();
1565 if (status != 0)
1566 return status;
1567
Benny Prijonodbe337a2006-01-08 23:57:52 +00001568
1569 pjsip_transport_dec_ref(loop);
1570 return 0;
1571
1572}
1573