blob: cf40e5d55882cb5a8eb017b7f10f9f408d03d3ea [file] [log] [blame]
Benny Prijonofa73e3e2006-01-05 23:35:46 +00001/* $Id$ */
2/*
3 * Copyright (C) 2003-2006 Benny Prijono <benny@prijono.org>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19
20#include "test.h"
21#include <pjsip_core.h>
22#include <pjlib.h>
23
Benny Prijono85598d92006-01-07 18:44:25 +000024#define THIS_FILE "tsx_uac_test.c"
25
26
Benny Prijonofa73e3e2006-01-05 23:35:46 +000027/*****************************************************************************
28 **
Benny Prijono85598d92006-01-07 18:44:25 +000029 ** UAC tests.
Benny Prijonofa73e3e2006-01-05 23:35:46 +000030 **
Benny Prijono85598d92006-01-07 18:44:25 +000031 ** This file performs various tests for UAC transactions. Each test will have
32 ** a different Via branch param so that message receiver module and
33 ** transaction user module can identify which test is being carried out.
Benny Prijonofa73e3e2006-01-05 23:35:46 +000034 **
Benny Prijono85598d92006-01-07 18:44:25 +000035 ** TEST1_BRANCH_ID
36 ** Perform basic retransmission and timeout test. Message receiver will
37 ** verify that retransmission is received at correct time.
38 ** This test verifies the following requirements:
39 ** - retransmit timer doubles for INVITE
40 ** - retransmit timer doubles and caps off for non-INVITE
41 ** - retransmit timer timer is precise
42 ** - correct timeout and retransmission count
43 ** Requirements not tested:
44 ** - retransmit timer only starts after resolving has completed.
45 **
46 ** TEST2_BRANCH_ID
47 ** Test scenario where resolver is unable to resolve destination host.
48 **
49 ** TEST3_BRANCH_ID
50 ** Test scenario where transaction is terminated while resolver is still
51 ** running.
52 **
53 ** TEST4_BRANCH_ID
54 ** Test scenario where transport failed after several retransmissions.
55 **
56 ** TEST5_BRANCH_ID
57 ** Test scenario where transaction is terminated by user after several
58 ** retransmissions.
59 **
60 ** TEST6_BRANCH_ID
61 ** Test successfull non-INVITE transaction.
62 ** It tests the following requirements:
63 ** - transaction correctly moves to COMPLETED state.
64 ** - retransmission must cease.
65 ** - tx_data must be maintained until state is terminated.
66 **
67 ** TEST7_BRANCH_ID
68 ** Test successfull non-INVITE transaction, with provisional response.
69 **
70 ** TEST8_BRANCH_ID
71 ** Test failed INVITE transaction (e.g. ACK must be received)
72 **
73 ** TEST9_BRANCH_ID
74 ** Test failed INVITE transaction with provisional response.
75 **
76 **
Benny Prijonofa73e3e2006-01-05 23:35:46 +000077 *****************************************************************************
78 */
79
Benny Prijono85598d92006-01-07 18:44:25 +000080static char *TEST1_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-Test1";
81static char *TEST2_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-Test2";
82static char *TEST3_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-Test3";
83static char *TEST4_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-Test4";
84static char *TEST5_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-Test5";
85static char *TEST6_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-Test6";
86static char *TEST7_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-Test7";
87static char *TEST8_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-Test8";
88static char *TEST9_BRANCH_ID = PJSIP_RFC3261_BRANCH_ID "-Test9";
89
90#define TEST1_ALLOWED_DIFF (150)
91#define TEST4_RETRANSMIT_CNT 3
92#define TEST5_RETRANSMIT_CNT 3
93
94
Benny Prijonofa73e3e2006-01-05 23:35:46 +000095static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e);
96static pj_bool_t msg_receiver_on_rx_request(pjsip_rx_data *rdata);
97
98/* UAC transaction user module. */
99static pjsip_module tsx_user =
100{
101 NULL, NULL, /* prev and next */
102 { "Tsx-User", 8}, /* Name. */
103 -1, /* Id */
104 PJSIP_MOD_PRIORITY_APPLICATION-1, /* Priority */
105 NULL, /* User data. */
106 0, /* Number of methods supported (=0). */
107 { 0 }, /* Array of methods (none) */
108 NULL, /* load() */
109 NULL, /* start() */
110 NULL, /* stop() */
111 NULL, /* unload() */
112 NULL, /* on_rx_request() */
113 NULL, /* on_rx_response() */
Benny Prijono85598d92006-01-07 18:44:25 +0000114 NULL, /* on_tx_request() */
115 NULL, /* on_tx_response() */
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000116 &tsx_user_on_tsx_state, /* on_tsx_state() */
117};
118
119/* Module to receive the loop-backed request. */
120static pjsip_module msg_receiver =
121{
122 NULL, NULL, /* prev and next */
123 { "Test", 4}, /* Name. */
124 -1, /* Id */
125 PJSIP_MOD_PRIORITY_APPLICATION-1, /* Priority */
126 NULL, /* User data. */
127 0, /* Number of methods supported (=0). */
128 { 0 }, /* Array of methods (none) */
129 NULL, /* load() */
130 NULL, /* start() */
131 NULL, /* stop() */
132 NULL, /* unload() */
133 &msg_receiver_on_rx_request, /* on_rx_request() */
134 NULL, /* on_rx_response() */
Benny Prijono85598d92006-01-07 18:44:25 +0000135 NULL, /* on_tx_request() */
136 NULL, /* on_tx_response() */
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000137 NULL, /* on_tsx_state() */
138};
139
Benny Prijono85598d92006-01-07 18:44:25 +0000140/* Static vars, which will be reset on each test. */
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000141static int recv_count;
142static pj_time_val recv_last;
143static pj_bool_t test_complete;
144
Benny Prijono85598d92006-01-07 18:44:25 +0000145/* Loop transport instance. */
146static pjsip_transport *loop;
147
148/*
149 * This is the handler to receive state changed notification from the
150 * transaction. It is used to verify that the transaction behaves according
151 * to the test scenario.
152 */
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000153static void tsx_user_on_tsx_state(pjsip_transaction *tsx, pjsip_event *e)
154{
Benny Prijono85598d92006-01-07 18:44:25 +0000155 if (pj_strcmp2(&tsx->branch, TEST1_BRANCH_ID)==0) {
156 /*
157 * Transaction with TEST1_BRANCH_ID should terminate with transaction
158 * timeout status.
159 */
160 if (tsx->state == PJSIP_TSX_STATE_TERMINATED) {
161
162 if (test_complete == 0)
163 test_complete = 1;
164
165 /* Test the status code. */
166 if (tsx->status_code != PJSIP_SC_TSX_TIMEOUT) {
167 PJ_LOG(3,(THIS_FILE,
168 " error: status code is %d instead of %d",
169 tsx->status_code, PJSIP_SC_TSX_TIMEOUT));
170 test_complete = -710;
171 }
172 }
173
174 } else if (pj_strcmp2(&tsx->branch, TEST2_BRANCH_ID)==0) {
175 /*
176 * Transaction with TEST2_BRANCH_ID should terminate with transport error.
177 */
178 if (tsx->state == PJSIP_TSX_STATE_TERMINATED) {
179
180 /* Test the status code. */
181 if (tsx->status_code != PJSIP_SC_TSX_TRANSPORT_ERROR) {
182 PJ_LOG(3,(THIS_FILE,
183 " error: status code is %d instead of %d",
184 tsx->status_code, PJSIP_SC_TSX_TRANSPORT_ERROR));
185 test_complete = -720;
186 }
187
188 if (test_complete == 0)
189 test_complete = 1;
190 }
191
192 } else if (pj_strcmp2(&tsx->branch, TEST3_BRANCH_ID)==0) {
193 /*
194 * This test terminates the transaction while resolver is still
195 * running.
196 */
197 if (tsx->state == PJSIP_TSX_STATE_CALLING) {
198
199 /* Terminate the transaction. */
200 pjsip_tsx_terminate(tsx, PJSIP_SC_REQUEST_TERMINATED);
201
202 } else if (tsx->state == PJSIP_TSX_STATE_TERMINATED) {
203
204 /* Check if status code is correct. */
205 if (tsx->status_code != PJSIP_SC_REQUEST_TERMINATED) {
206 PJ_LOG(3,(THIS_FILE,
207 " error: status code is %d instead of %d",
208 tsx->status_code, PJSIP_SC_REQUEST_TERMINATED));
209 test_complete = -730;
210 }
211
212 if (test_complete == 0)
213 test_complete = 1;
214
215 }
216
217 } else if (pj_strcmp2(&tsx->branch, TEST4_BRANCH_ID)==0) {
218 /*
219 * This test simulates transport failure after several
220 * retransmissions.
221 */
222 if (tsx->state == PJSIP_TSX_STATE_TERMINATED) {
223
224 /* Status code must be transport error. */
225 if (tsx->status_code != PJSIP_SC_TSX_TRANSPORT_ERROR) {
226 PJ_LOG(3,(THIS_FILE,
227 " error: status code is %d instead of %d",
228 tsx->status_code, PJSIP_SC_TSX_TRANSPORT_ERROR));
229 test_complete = -730;
230 }
231
232 /* Must have correct retransmission count. */
233 if (tsx->retransmit_count != TEST4_RETRANSMIT_CNT) {
234 PJ_LOG(3,(THIS_FILE,
235 " error: retransmit cnt is %d instead of %d",
236 tsx->retransmit_count, TEST4_RETRANSMIT_CNT));
237 test_complete = -731;
238 }
239
240 if (test_complete == 0)
241 test_complete = 1;
242 }
243
244
245 } else if (pj_strcmp2(&tsx->branch, TEST5_BRANCH_ID)==0) {
246 /*
247 * This test simulates transport failure after several
248 * retransmissions.
249 */
250 if (tsx->state == PJSIP_TSX_STATE_TERMINATED) {
251
252 /* Status code must be PJSIP_SC_REQUEST_TERMINATED. */
253 if (tsx->status_code != PJSIP_SC_REQUEST_TERMINATED) {
254 PJ_LOG(3,(THIS_FILE,
255 " error: status code is %d instead of %d",
256 tsx->status_code, PJSIP_SC_REQUEST_TERMINATED));
257 test_complete = -733;
258 }
259
260 /* Must have correct retransmission count. */
261 if (tsx->retransmit_count != TEST5_RETRANSMIT_CNT) {
262 PJ_LOG(3,(THIS_FILE,
263 " error: retransmit cnt is %d instead of %d",
264 tsx->retransmit_count, TEST5_RETRANSMIT_CNT));
265 test_complete = -734;
266 }
267
268 if (test_complete == 0)
269 test_complete = 1;
270 }
271
272
273 } else if (pj_strcmp2(&tsx->branch, TEST6_BRANCH_ID)==0) {
274 /*
275 * Successfull non-INVITE transaction.
276 */
277 if (tsx->state == PJSIP_TSX_STATE_COMPLETED) {
278
279 /* Status code must be 202. */
280 if (tsx->status_code != 202) {
281 PJ_LOG(3,(THIS_FILE,
282 " error: status code is %d instead of %d",
283 tsx->status_code, 202));
284 test_complete = -736;
285 }
286
287 /* Must have correct retransmission count. */
288 if (tsx->retransmit_count != 0) {
289 PJ_LOG(3,(THIS_FILE,
290 " error: retransmit cnt is %d instead of %d",
291 tsx->retransmit_count, 0));
292 test_complete = -737;
293 }
294
295 /* Must still keep last_tx */
296 if (tsx->last_tx == NULL) {
297 PJ_LOG(3,(THIS_FILE,
298 " error: transaction lost last_tx"));
299 test_complete = -738;
300 }
301
302 if (test_complete == 0) {
303 test_complete = 1;
304 pjsip_tsx_terminate(tsx, 202);
305 }
306 }
307 }
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000308}
309
310#define DIFF(a,b) ((a<b) ? (b-a) : (a-b))
311
Benny Prijono85598d92006-01-07 18:44:25 +0000312/*
313 * This is the handler to receive message for this test. It is used to
314 * control and verify the behavior of the message transmitted by the
315 * transaction.
316 */
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000317static pj_bool_t msg_receiver_on_rx_request(pjsip_rx_data *rdata)
318{
Benny Prijono85598d92006-01-07 18:44:25 +0000319 if (pj_strcmp2(&rdata->msg_info.via->branch_param, TEST1_BRANCH_ID) == 0) {
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000320 /*
Benny Prijono85598d92006-01-07 18:44:25 +0000321 * The TEST1_BRANCH_ID test performs the verifications for transaction
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000322 * retransmission mechanism. It will not answer the incoming request
323 * with any response.
324 */
325 pjsip_msg *msg = rdata->msg_info.msg;
326
Benny Prijono85598d92006-01-07 18:44:25 +0000327 PJ_LOG(4,(THIS_FILE, " received request"));
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000328
329 /* Only wants to take INVITE or OPTIONS method. */
330 if (msg->line.req.method.id != PJSIP_INVITE_METHOD &&
331 msg->line.req.method.id != PJSIP_OPTIONS_METHOD)
332 {
Benny Prijono85598d92006-01-07 18:44:25 +0000333 PJ_LOG(3,(THIS_FILE, " error: received unexpected method %.*s",
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000334 msg->line.req.method.name.slen,
335 msg->line.req.method.name.ptr));
336 test_complete = -600;
337 return PJ_TRUE;
338 }
339
340 if (recv_count == 0) {
341 recv_count++;
Benny Prijono85598d92006-01-07 18:44:25 +0000342 //pj_gettimeofday(&recv_last);
343 recv_last = rdata->pkt_info.timestamp;
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000344 } else {
345 pj_time_val now;
346 unsigned msec_expected, msec_elapsed;
Benny Prijono85598d92006-01-07 18:44:25 +0000347 int max_received;
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000348
Benny Prijono85598d92006-01-07 18:44:25 +0000349 //pj_gettimeofday(&now);
350 now = rdata->pkt_info.timestamp;
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000351 PJ_TIME_VAL_SUB(now, recv_last);
352 msec_elapsed = now.sec*1000 + now.msec;
353
354 ++recv_count;
355 msec_expected = (1<<(recv_count-2))*PJSIP_T1_TIMEOUT;
356
357 if (msg->line.req.method.id != PJSIP_INVITE_METHOD) {
358 if (msec_expected > PJSIP_T2_TIMEOUT)
359 msec_expected = PJSIP_T2_TIMEOUT;
Benny Prijono85598d92006-01-07 18:44:25 +0000360 max_received = 11;
361 } else {
362 max_received = 7;
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000363 }
364
Benny Prijono85598d92006-01-07 18:44:25 +0000365 if (DIFF(msec_expected, msec_elapsed) > TEST1_ALLOWED_DIFF) {
366 PJ_LOG(3,(THIS_FILE,
367 " error: expecting retransmission no. %d in %d "
368 "ms, received in %d ms",
369 recv_count-1, msec_expected, msec_elapsed));
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000370 test_complete = -610;
371 }
372
Benny Prijono85598d92006-01-07 18:44:25 +0000373
374 if (recv_count > max_received) {
375 PJ_LOG(3,(THIS_FILE,
376 " error: too many messages (%d) received",
377 recv_count));
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000378 test_complete = -620;
379 }
380
Benny Prijono85598d92006-01-07 18:44:25 +0000381 //pj_gettimeofday(&recv_last);
382 recv_last = rdata->pkt_info.timestamp;
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000383 }
384 return PJ_TRUE;
Benny Prijono85598d92006-01-07 18:44:25 +0000385
386 } else
387 if (pj_strcmp2(&rdata->msg_info.via->branch_param, TEST4_BRANCH_ID) == 0) {
388 /*
389 * The TEST4_BRANCH_ID test simulates transport failure after several
390 * retransmissions.
391 */
392 recv_count++;
393
394 if (recv_count == TEST4_RETRANSMIT_CNT) {
395 /* Simulate transport failure. */
396 pjsip_loop_set_failure(loop, 2, NULL);
397
398 } else if (recv_count > TEST4_RETRANSMIT_CNT) {
399 PJ_LOG(3,(THIS_FILE," error: not expecting %d-th packet!",
400 recv_count));
401 test_complete = -631;
402 }
403
404 return PJ_TRUE;
405
406
407 } else
408 if (pj_strcmp2(&rdata->msg_info.via->branch_param, TEST5_BRANCH_ID) == 0) {
409 /*
410 * The TEST5_BRANCH_ID test simulates user terminating the transaction
411 * after several retransmissions.
412 */
413 recv_count++;
414
415 if (recv_count == TEST5_RETRANSMIT_CNT+1) {
416 pj_str_t key;
417 pjsip_transaction *tsx;
418
419 pjsip_tsx_create_key( rdata->tp_info.pool, &key, PJSIP_ROLE_UAC,
420 &rdata->msg_info.msg->line.req.method, rdata);
421 tsx = pjsip_tsx_layer_find_tsx(&key, PJ_TRUE);
422 if (tsx) {
423 pjsip_tsx_terminate(tsx, PJSIP_SC_REQUEST_TERMINATED);
424 pj_mutex_unlock(tsx->mutex);
425 } else {
426 PJ_LOG(3,(THIS_FILE, " error: uac transaction not found!"));
427 test_complete = -633;
428 }
429
430 } else if (recv_count > TEST5_RETRANSMIT_CNT+1) {
431 PJ_LOG(3,(THIS_FILE," error: not expecting %d-th packet!",
432 recv_count));
433 test_complete = -634;
434 }
435
436 return PJ_TRUE;
437
438 } else
439 if (pj_strcmp2(&rdata->msg_info.via->branch_param, TEST6_BRANCH_ID) == 0) {
440 /*
441 * The TEST5_BRANCH_ID test successfull non-INVITE transaction.
442 */
443 pjsip_tx_data *tdata;
444 pjsip_response_addr res_addr;
445 pj_status_t status;
446
447 recv_count++;
448
449 if (recv_count > 1) {
450 PJ_LOG(3,(THIS_FILE," error: not expecting %d-th packet!",
451 recv_count));
452 test_complete = -635;
453 }
454
455 status = pjsip_endpt_create_response(endpt, rdata, 202, NULL, &tdata);
456 if (status != PJ_SUCCESS) {
457 app_perror(" error: unable to create response", status);
458 test_complete = -636;
459 }
460
461 status = pjsip_get_response_addr(tdata->pool, rdata, &res_addr);
462 if (status != PJ_SUCCESS) {
463 app_perror(" error: unable to get response addr", status);
464 test_complete = -637;
465 }
466
467 status = pjsip_endpt_send_response(endpt, &res_addr, tdata, NULL,NULL);
468 if (status != PJ_SUCCESS) {
469 app_perror(" error: unable to send response", status);
470 test_complete = -638;
471 pjsip_tx_data_dec_ref(tdata);
472 }
473
474 return PJ_TRUE;
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000475 }
Benny Prijono85598d92006-01-07 18:44:25 +0000476
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000477 return PJ_FALSE;
478}
479
Benny Prijono85598d92006-01-07 18:44:25 +0000480/*
481 * The generic test framework, used by most of the tests.
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000482 */
Benny Prijono85598d92006-01-07 18:44:25 +0000483static int perform_tsx_test(int dummy, char *target_uri, char *from_uri,
484 char *branch_param, int test_time,
485 const pjsip_method *method)
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000486{
487 pjsip_tx_data *tdata;
488 pjsip_transaction *tsx;
Benny Prijono85598d92006-01-07 18:44:25 +0000489 pj_str_t target, from, tsx_key;
490 pjsip_via_hdr *via;
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000491 pj_time_val timeout;
492 pj_status_t status;
493
Benny Prijono85598d92006-01-07 18:44:25 +0000494 PJ_LOG(3,(THIS_FILE,
495 " please standby, this will take at most %d seconds..",
496 test_time));
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000497
Benny Prijono85598d92006-01-07 18:44:25 +0000498 /* Reset test. */
499 recv_count = 0;
500 test_complete = 0;
501
502 /* Init headers. */
503 target = pj_str(target_uri);
504 from = pj_str(from_uri);
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000505
506 /* Create request. */
507 status = pjsip_endpt_create_request( endpt, method, &target,
Benny Prijono85598d92006-01-07 18:44:25 +0000508 &from, &target, NULL, NULL, -1,
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000509 NULL, &tdata);
510 if (status != PJ_SUCCESS) {
511 app_perror(" Error: unable to create request", status);
Benny Prijono85598d92006-01-07 18:44:25 +0000512 return -100;
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000513 }
514
Benny Prijono85598d92006-01-07 18:44:25 +0000515 /* Set the branch param for test 1. */
516 via = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL);
517 via->branch_param = pj_str(branch_param);
518
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000519 /* Add additional reference to tdata to prevent transaction from
520 * deleting it.
521 */
522 pjsip_tx_data_add_ref(tdata);
523
524 /* Create transaction. */
525 status = pjsip_tsx_create_uac( &tsx_user, tdata, &tsx);
526 if (status != PJ_SUCCESS) {
527 app_perror(" Error: unable to create UAC transaction", status);
Benny Prijono85598d92006-01-07 18:44:25 +0000528 pjsip_tx_data_dec_ref(tdata);
529 return -110;
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000530 }
531
532 /* Get transaction key. */
533 pj_strdup(tdata->pool, &tsx_key, &tsx->transaction_key);
534
535 /* Send the message. */
536 status = pjsip_tsx_send_msg(tsx, NULL);
Benny Prijono85598d92006-01-07 18:44:25 +0000537 // Ignore send result. Some tests do deliberately triggers error
538 // when sending message.
539 //if (status != PJ_SUCCESS) {
540 // app_perror(" Error: unable to send request", status);
541 // pjsip_tx_data_dec_ref(tdata);
542 // return -120;
543 //}
544
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000545
546 /* Set test completion time. */
547 pj_gettimeofday(&timeout);
Benny Prijono85598d92006-01-07 18:44:25 +0000548 timeout.sec += test_time;
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000549
550 /* Wait until test complete. */
551 while (!test_complete) {
Benny Prijono85598d92006-01-07 18:44:25 +0000552 pj_time_val now, poll_delay = {0, 10};
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000553
Benny Prijono85598d92006-01-07 18:44:25 +0000554 pjsip_endpt_handle_events(endpt, &poll_delay);
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000555
556 pj_gettimeofday(&now);
557 if (now.sec > timeout.sec) {
Benny Prijono85598d92006-01-07 18:44:25 +0000558 PJ_LOG(3,(THIS_FILE, " Error: test has timed out"));
559 pjsip_tx_data_dec_ref(tdata);
560 return -130;
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000561 }
562 }
563
Benny Prijono85598d92006-01-07 18:44:25 +0000564 if (status < 0) {
565 pjsip_tx_data_dec_ref(tdata);
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000566 return status;
Benny Prijono85598d92006-01-07 18:44:25 +0000567 }
568
569 if (test_complete < 0) {
570 tsx = pjsip_tsx_layer_find_tsx(&tsx_key, PJ_TRUE);
571 if (tsx) {
572 pjsip_tsx_terminate(tsx, PJSIP_SC_REQUEST_TERMINATED);
573 pj_mutex_unlock(tsx->mutex);
574 flush_events(1000);
575 }
576 pjsip_tx_data_dec_ref(tdata);
577 return test_complete;
578 }
579
580 /* Allow transaction to destroy itself */
581 flush_events(500);
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000582
583 /* Make sure transaction has been destroyed. */
584 if (pjsip_tsx_layer_find_tsx(&tsx_key, PJ_FALSE) != NULL) {
Benny Prijono85598d92006-01-07 18:44:25 +0000585 PJ_LOG(3,(THIS_FILE, " Error: transaction has not been destroyed"));
586 pjsip_tx_data_dec_ref(tdata);
587 return -140;
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000588 }
589
590 /* Check tdata reference counter. */
591 if (pj_atomic_get(tdata->ref_cnt) != 1) {
Benny Prijono85598d92006-01-07 18:44:25 +0000592 PJ_LOG(3,(THIS_FILE, " Error: tdata reference counter is %d",
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000593 pj_atomic_get(tdata->ref_cnt)));
Benny Prijono85598d92006-01-07 18:44:25 +0000594 pjsip_tx_data_dec_ref(tdata);
595 return -150;
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000596 }
597
598 /* Destroy txdata */
599 pjsip_tx_data_dec_ref(tdata);
600
601 return PJ_SUCCESS;
602}
603
604/*****************************************************************************
605 **
Benny Prijono85598d92006-01-07 18:44:25 +0000606 ** TEST1_BRANCH_ID: UAC basic retransmission and timeout test.
607 **
608 ** This will test the retransmission of the UAC transaction. Remote will not
609 ** answer the transaction, so the transaction should fail. The Via branch prm
610 ** TEST1_BRANCH_ID will be used for this test.
611 **
612 *****************************************************************************
613 */
614static int tsx_uac_retransmit_test(void)
615{
616 int status, enabled;
617 int i;
618 struct {
619 const pjsip_method *method;
620 unsigned delay;
621 } sub_test[] =
622 {
623 { &pjsip_invite_method, 0},
624 { &pjsip_invite_method, TEST1_ALLOWED_DIFF*2},
625 { &pjsip_options_method, 0},
626 { &pjsip_options_method, TEST1_ALLOWED_DIFF*2}
627 };
628
629 PJ_LOG(3,(THIS_FILE, " test1: basic uac retransmit and timeout test"));
630
631
632 /* For this test. message printing shound be disabled because it makes
633 * incorrect timing.
634 */
635 enabled = msg_logger_set_enabled(0);
636
637 for (i=0; i<PJ_ARRAY_SIZE(sub_test); ++i) {
638
639 PJ_LOG(3,(THIS_FILE,
640 " variant %c: %s with %d ms network delay",
641 ('a' + i),
642 sub_test[i].method->name.ptr,
643 sub_test[i].delay));
644
645 /* Configure transport */
646 pjsip_loop_set_failure(loop, 0, NULL);
647 pjsip_loop_set_recv_delay(loop, sub_test[i].delay, NULL);
648
649 /* Do the test. */
650 status = perform_tsx_test(-500, "sip:bob@127.0.0.1;transport=loop-dgram",
651 "sip:alice@127.0.0.1;transport=loop-dgram",
652 TEST1_BRANCH_ID,
653 35, sub_test[i].method);
654 if (status != 0)
655 break;
656 }
657
658 /* Restore transport. */
659 pjsip_loop_set_recv_delay(loop, 0, NULL);
660
661 /* Restore msg logger. */
662 msg_logger_set_enabled(enabled);
663
664 /* Done. */
665 return status;
666}
667
668/*****************************************************************************
669 **
670 ** TEST2_BRANCH_ID: UAC resolve error test.
671 **
672 ** Test the scenario where destination host is unresolvable. There are
673 ** two variants:
674 ** (a) resolver returns immediate error
675 ** (b) resolver returns error via the callback.
676 **
677 *****************************************************************************
678 */
679static int tsx_resolve_error_test(void)
680{
681 int status;
682
683 PJ_LOG(3,(THIS_FILE, " test2: resolve error test"));
684
685 /*
686 * Variant (a): immediate resolve error.
687 */
688 PJ_LOG(3,(THIS_FILE, " variant a: immediate resolving error"));
689
690 status = perform_tsx_test(-800,
691 "sip:bob@unresolved-host;transport=loop-dgram",
692 "sip:alice@127.0.0.1;transport=loop-dgram",
693 TEST2_BRANCH_ID, 10,
694 &pjsip_options_method);
695 if (status != 0)
696 return status;
697
698 /*
699 * Variant (b): error via callback.
700 */
701 PJ_LOG(3,(THIS_FILE, " variant b: error via callback"));
702
703 /* Set loop transport to return delayed error. */
704 pjsip_loop_set_failure(loop, 2, NULL);
705 pjsip_loop_set_send_callback_delay(loop, 10, NULL);
706
707 status = perform_tsx_test(-800, "sip:bob@127.0.0.1;transport=loop-dgram",
708 "sip:alice@127.0.0.1;transport=loop-dgram",
709 TEST2_BRANCH_ID, 2,
710 &pjsip_options_method);
711 if (status != 0)
712 return status;
713
714 /* Restore loop transport settings. */
715 pjsip_loop_set_failure(loop, 0, NULL);
716 pjsip_loop_set_send_callback_delay(loop, 0, NULL);
717
718 return status;
719}
720
721
722/*****************************************************************************
723 **
724 ** TEST3_BRANCH_ID: UAC terminate while resolving test.
725 **
726 ** Terminate the transaction while resolver is still running.
727 **
728 *****************************************************************************
729 */
730static int tsx_terminate_resolving_test(void)
731{
732 unsigned prev_delay;
733 pj_status_t status;
734
735 PJ_LOG(3,(THIS_FILE, " test3: terminate while resolving test"));
736
737 /* Configure transport delay. */
738 pjsip_loop_set_send_callback_delay(loop, 100, &prev_delay);
739
740 /* Start the test. */
741 status = perform_tsx_test(-900, "sip:127.0.0.1;transport=loop-dgram",
742 "sip:127.0.0.1;transport=loop-dgram",
743 TEST3_BRANCH_ID, 2, &pjsip_options_method);
744
745 /* Restore delay. */
746 pjsip_loop_set_send_callback_delay(loop, prev_delay, NULL);
747
748 return status;
749}
750
751
752/*****************************************************************************
753 **
754 ** TEST4_BRANCH_ID: Transport failed after several retransmissions
755 **
756 ** There are two variants of this test: (a) failure occurs immediately when
757 ** transaction calls pjsip_transport_send() or (b) failure is reported via
758 ** transport callback.
759 **
760 *****************************************************************************
761 */
762static int tsx_retransmit_fail_test(void)
763{
764 int i;
765 unsigned delay[] = {0, 10};
766 pj_status_t status;
767
768 PJ_LOG(3,(THIS_FILE,
769 " test4: transport fails after several retransmissions test"));
770
771
772 for (i=0; i<PJ_ARRAY_SIZE(delay); ++i) {
773
774 PJ_LOG(3,(THIS_FILE,
775 " variant %c: transport delay %d ms", ('a'+i), delay[i]));
776
777 /* Configure transport delay. */
778 pjsip_loop_set_send_callback_delay(loop, delay[i], NULL);
779
780 /* Restore transport failure mode. */
781 pjsip_loop_set_failure(loop, 0, 0);
782
783 /* Start the test. */
784 status = perform_tsx_test(-1000, "sip:127.0.0.1;transport=loop-dgram",
785 "sip:127.0.0.1;transport=loop-dgram",
786 TEST4_BRANCH_ID, 6, &pjsip_options_method);
787
788 if (status != 0)
789 break;
790
791 }
792
793 /* Restore delay. */
794 pjsip_loop_set_send_callback_delay(loop, 0, NULL);
795
796 /* Restore transport failure mode. */
797 pjsip_loop_set_failure(loop, 0, 0);
798
799 return status;
800}
801
802
803/*****************************************************************************
804 **
805 ** TEST5_BRANCH_ID: Terminate transaction after several retransmissions
806 **
807 *****************************************************************************
808 */
809static int tsx_terminate_after_retransmit_test(void)
810{
811 int status;
812
813 PJ_LOG(3,(THIS_FILE, " test5: terminate after retransmissions"));
814
815 /* Do the test. */
816 status = perform_tsx_test(-1100, "sip:bob@127.0.0.1;transport=loop-dgram",
817 "sip:alice@127.0.0.1;transport=loop-dgram",
818 TEST5_BRANCH_ID,
819 6, &pjsip_options_method);
820
821 /* Done. */
822 return status;
823}
824
825
826/*****************************************************************************
827 **
828 ** TEST6_BRANCH_ID: Successfull non-invite transaction
829 **
830 *****************************************************************************
831 */
832static int tsx_successfull_non_invite_test(void)
833{
834 int i, status;
835 unsigned delay[] = { 1, 200 };
836
837 PJ_LOG(3,(THIS_FILE, " test6: successfull non-invite transaction"));
838
839 /* Do the test. */
840 for (i=0; i<PJ_ARRAY_SIZE(delay); ++i) {
841
842 PJ_LOG(3,(THIS_FILE, " variant %c: with %d ms transport delay",
843 ('a'+i), delay[i]));
844
845 pjsip_loop_set_delay(loop, delay[i]);
846
847 status = perform_tsx_test(-1200,
848 "sip:bob@127.0.0.1;transport=loop-dgram",
849 "sip:alice@127.0.0.1;transport=loop-dgram",
850 TEST6_BRANCH_ID,
851 2, &pjsip_options_method);
852 if (status != 0)
853 return status;
854 }
855
856 pjsip_loop_set_delay(loop, 0);
857
858 /* Done. */
859 return status;
860}
861
862
863/*****************************************************************************
864 **
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000865 ** UAC Transaction Test.
866 **
867 *****************************************************************************
868 */
869int tsx_uac_test(void)
870{
871 pj_sockaddr_in addr;
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000872 pj_status_t status;
873
Benny Prijono85598d92006-01-07 18:44:25 +0000874 /* Check if loop transport is configured. */
875 status = pjsip_endpt_acquire_transport(endpt, PJSIP_TRANSPORT_LOOP_DGRAM,
876 &addr, sizeof(addr), &loop);
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000877 if (status != PJ_SUCCESS) {
Benny Prijono85598d92006-01-07 18:44:25 +0000878 PJ_LOG(3,(THIS_FILE, " Error: loop transport is not configured!"));
879 return -10;
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000880 }
881
882 /* Register modules. */
883 status = pjsip_endpt_register_module(endpt, &tsx_user);
884 if (status != PJ_SUCCESS) {
885 app_perror(" Error: unable to register module", status);
886 return -30;
887 }
888 status = pjsip_endpt_register_module(endpt, &msg_receiver);
889 if (status != PJ_SUCCESS) {
890 app_perror(" Error: unable to register module", status);
Benny Prijono85598d92006-01-07 18:44:25 +0000891 return -40;
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000892 }
893
Benny Prijono85598d92006-01-07 18:44:25 +0000894#if 0
895 /* TEST1_BRANCH_ID: Basic retransmit and timeout test. */
896 status = tsx_uac_retransmit_test();
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000897 if (status != 0)
898 return status;
899
Benny Prijono85598d92006-01-07 18:44:25 +0000900 /* TEST2_BRANCH_ID: Resolve error test. */
901 status = tsx_resolve_error_test();
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000902 if (status != 0)
903 return status;
904
Benny Prijono85598d92006-01-07 18:44:25 +0000905 /* TEST3_BRANCH_ID: UAC terminate while resolving test. */
906 status = tsx_terminate_resolving_test();
907 if (status != 0)
908 return status;
909
910 /* TEST4_BRANCH_ID: Transport failed after several retransmissions */
911 status = tsx_retransmit_fail_test();
912 if (status != 0)
913 return status;
914
915 /* TEST5_BRANCH_ID: Terminate transaction after several retransmissions */
916 status = tsx_terminate_after_retransmit_test();
917 if (status != 0)
918 return status;
919#endif
920
921 /* TEST6_BRANCH_ID: Successfull non-invite transaction */
922 status = tsx_successfull_non_invite_test();
923 if (status != 0)
924 return status;
925
926
927 pjsip_transport_dec_ref(loop);
Benny Prijonofa73e3e2006-01-05 23:35:46 +0000928 return 0;
929}
Benny Prijono85598d92006-01-07 18:44:25 +0000930