blob: 2131ae6f1c23db1f0113a9c7e887b19a6d078d9c [file] [log] [blame]
Alexandre Lision8af73cb2013-12-10 14:11:20 -05001/* $Id$ */
2/*
3 * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
4 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21#include "test.h"
22#include <pjsip_ua.h>
23#include <pjsip.h>
24#include <pjlib.h>
25
26#define THIS_FILE "inv_offer_answer_test.c"
27#define PORT 5068
28#define CONTACT "sip:127.0.0.1:5068"
29#define TRACE_(x) PJ_LOG(3,x)
30
31static struct oa_sdp_t
32{
33 const char *offer;
34 const char *answer;
35 unsigned pt_result;
36} oa_sdp[] =
37{
38 {
39 /* Offer: */
40 "v=0\r\n"
41 "o=alice 1 1 IN IP4 host.anywhere.com\r\n"
42 "s= \r\n"
43 "c=IN IP4 host.anywhere.com\r\n"
44 "t=0 0\r\n"
45 "m=audio 49170 RTP/AVP 0\r\n"
46 "a=rtpmap:0 PCMU/8000\r\n",
47
48 /* Answer: */
49 "v=0\r\n"
50 "o=bob 1 1 IN IP4 host.example.com\r\n"
51 "s= \r\n"
52 "c=IN IP4 host.example.com\r\n"
53 "t=0 0\r\n"
54 "m=audio 49920 RTP/AVP 0\r\n"
55 "a=rtpmap:0 PCMU/8000\r\n"
56 "m=video 0 RTP/AVP 31\r\n",
57
58 0
59 },
60
61 {
62 /* Offer: */
63 "v=0\r\n"
64 "o=alice 2 2 IN IP4 host.anywhere.com\r\n"
65 "s= \r\n"
66 "c=IN IP4 host.anywhere.com\r\n"
67 "t=0 0\r\n"
68 "m=audio 49170 RTP/AVP 8\r\n"
69 "a=rtpmap:0 PCMA/8000\r\n",
70
71 /* Answer: */
72 "v=0\r\n"
73 "o=bob 2 2 IN IP4 host.example.com\r\n"
74 "s= \r\n"
75 "c=IN IP4 host.example.com\r\n"
76 "t=0 0\r\n"
77 "m=audio 49920 RTP/AVP 8\r\n"
78 "a=rtpmap:0 PCMA/8000\r\n",
79
80 8
81 },
82
83 {
84 /* Offer: */
85 "v=0\r\n"
86 "o=alice 3 3 IN IP4 host.anywhere.com\r\n"
87 "s= \r\n"
88 "c=IN IP4 host.anywhere.com\r\n"
89 "t=0 0\r\n"
90 "m=audio 49170 RTP/AVP 3\r\n",
91
92 /* Answer: */
93 "v=0\r\n"
94 "o=bob 3 3 IN IP4 host.example.com\r\n"
95 "s= \r\n"
96 "c=IN IP4 host.example.com\r\n"
97 "t=0 0\r\n"
98 "m=audio 49920 RTP/AVP 3\r\n",
99
100 3
101 },
102
103 {
104 /* Offer: */
105 "v=0\r\n"
106 "o=alice 4 4 IN IP4 host.anywhere.com\r\n"
107 "s= \r\n"
108 "c=IN IP4 host.anywhere.com\r\n"
109 "t=0 0\r\n"
110 "m=audio 49170 RTP/AVP 4\r\n",
111
112 /* Answer: */
113 "v=0\r\n"
114 "o=bob 4 4 IN IP4 host.example.com\r\n"
115 "s= \r\n"
116 "c=IN IP4 host.example.com\r\n"
117 "t=0 0\r\n"
118 "m=audio 49920 RTP/AVP 4\r\n",
119
120 4
121 }
122};
123
124
125
126typedef enum oa_t
127{
128 OFFERER_NONE,
129 OFFERER_UAC,
130 OFFERER_UAS
131} oa_t;
132
133typedef struct inv_test_param_t
134{
135 char *title;
136 unsigned inv_option;
137 pj_bool_t need_established;
138 unsigned count;
139 oa_t oa[4];
140} inv_test_param_t;
141
142typedef struct inv_test_t
143{
144 inv_test_param_t param;
145 pjsip_inv_session *uac;
146 pjsip_inv_session *uas;
147
148 pj_bool_t complete;
149 pj_bool_t uas_complete,
150 uac_complete;
151
152 unsigned oa_index;
153 unsigned uac_update_cnt,
154 uas_update_cnt;
155} inv_test_t;
156
157
158/**************** GLOBALS ******************/
159static inv_test_t inv_test;
160static unsigned job_cnt;
161
162typedef enum job_type
163{
164 SEND_OFFER,
165 ESTABLISH_CALL
166} job_type;
167
168typedef struct job_t
169{
170 job_type type;
171 pjsip_role_e who;
172} job_t;
173
174static job_t jobs[128];
175
176
177/**************** UTILS ******************/
178static pjmedia_sdp_session *create_sdp(pj_pool_t *pool, const char *body)
179{
180 pjmedia_sdp_session *sdp;
181 pj_str_t dup;
182 pj_status_t status;
183
184 pj_strdup2_with_null(pool, &dup, body);
185 status = pjmedia_sdp_parse(pool, dup.ptr, dup.slen, &sdp);
186 pj_assert(status == PJ_SUCCESS);
187
188 return sdp;
189}
190
191/**************** INVITE SESSION CALLBACKS ******************/
192static void on_rx_offer(pjsip_inv_session *inv,
193 const pjmedia_sdp_session *offer)
194{
195 pjmedia_sdp_session *sdp;
196
197 PJ_UNUSED_ARG(offer);
198
199 sdp = create_sdp(inv->dlg->pool, oa_sdp[inv_test.oa_index].answer);
200 pjsip_inv_set_sdp_answer(inv, sdp);
201
202 if (inv_test.oa_index == inv_test.param.count-1 &&
203 inv_test.param.need_established)
204 {
205 jobs[job_cnt].type = ESTABLISH_CALL;
206 jobs[job_cnt].who = PJSIP_ROLE_UAS;
207 job_cnt++;
208 }
209}
210
211
212static void on_create_offer(pjsip_inv_session *inv,
213 pjmedia_sdp_session **p_offer)
214{
215 PJ_UNUSED_ARG(inv);
216 PJ_UNUSED_ARG(p_offer);
217
218 pj_assert(!"Should not happen");
219}
220
221static void on_media_update(pjsip_inv_session *inv_ses,
222 pj_status_t status)
223{
224 PJ_UNUSED_ARG(status);
225
226 if (inv_ses == inv_test.uas) {
227 inv_test.uas_update_cnt++;
228 pj_assert(inv_test.uas_update_cnt - inv_test.uac_update_cnt <= 1);
229 TRACE_((THIS_FILE, " Callee media is established"));
230 } else if (inv_ses == inv_test.uac) {
231 inv_test.uac_update_cnt++;
232 pj_assert(inv_test.uac_update_cnt - inv_test.uas_update_cnt <= 1);
233 TRACE_((THIS_FILE, " Caller media is established"));
234
235 } else {
236 pj_assert(!"Unknown session!");
237 }
238
239 if (inv_test.uac_update_cnt == inv_test.uas_update_cnt) {
240 inv_test.oa_index++;
241
242 if (inv_test.oa_index < inv_test.param.count) {
243 switch (inv_test.param.oa[inv_test.oa_index]) {
244 case OFFERER_UAC:
245 jobs[job_cnt].type = SEND_OFFER;
246 jobs[job_cnt].who = PJSIP_ROLE_UAC;
247 job_cnt++;
248 break;
249 case OFFERER_UAS:
250 jobs[job_cnt].type = SEND_OFFER;
251 jobs[job_cnt].who = PJSIP_ROLE_UAS;
252 job_cnt++;
253 break;
254 default:
255 pj_assert(!"Invalid oa");
256 }
257 }
258
259 pj_assert(job_cnt <= PJ_ARRAY_SIZE(jobs));
260 }
261}
262
263static void on_state_changed(pjsip_inv_session *inv, pjsip_event *e)
264{
265 const char *who = NULL;
266
267 PJ_UNUSED_ARG(e);
268
269 if (inv->state == PJSIP_INV_STATE_DISCONNECTED) {
270 TRACE_((THIS_FILE, " %s call disconnected",
271 (inv==inv_test.uas ? "Callee" : "Caller")));
272 return;
273 }
274
275 if (inv->state != PJSIP_INV_STATE_CONFIRMED)
276 return;
277
278 if (inv == inv_test.uas) {
279 inv_test.uas_complete = PJ_TRUE;
280 who = "Callee";
281 } else if (inv == inv_test.uac) {
282 inv_test.uac_complete = PJ_TRUE;
283 who = "Caller";
284 } else
285 pj_assert(!"No session");
286
287 TRACE_((THIS_FILE, " %s call is confirmed", who));
288
289 if (inv_test.uac_complete && inv_test.uas_complete)
290 inv_test.complete = PJ_TRUE;
291}
292
293
294/**************** MODULE TO RECEIVE INITIAL INVITE ******************/
295
296static pj_bool_t on_rx_request(pjsip_rx_data *rdata)
297{
298 if (rdata->msg_info.msg->type == PJSIP_REQUEST_MSG &&
299 rdata->msg_info.msg->line.req.method.id == PJSIP_INVITE_METHOD)
300 {
301 pjsip_dialog *dlg;
302 pjmedia_sdp_session *sdp = NULL;
303 pj_str_t uri;
304 pjsip_tx_data *tdata;
305 pj_status_t status;
306
307 /*
308 * Create UAS
309 */
310 uri = pj_str(CONTACT);
311 status = pjsip_dlg_create_uas(pjsip_ua_instance(), rdata,
312 &uri, &dlg);
313 pj_assert(status == PJ_SUCCESS);
314
315 if (inv_test.param.oa[0] == OFFERER_UAC)
316 sdp = create_sdp(rdata->tp_info.pool, oa_sdp[0].answer);
317 else if (inv_test.param.oa[0] == OFFERER_UAS)
318 sdp = create_sdp(rdata->tp_info.pool, oa_sdp[0].offer);
319 else
320 pj_assert(!"Invalid offerer type");
321
322 status = pjsip_inv_create_uas(dlg, rdata, sdp, inv_test.param.inv_option, &inv_test.uas);
323 pj_assert(status == PJ_SUCCESS);
324
325 TRACE_((THIS_FILE, " Sending 183 with SDP"));
326
327 /*
328 * Answer with 183
329 */
330 status = pjsip_inv_initial_answer(inv_test.uas, rdata, 183, NULL,
331 NULL, &tdata);
332 pj_assert(status == PJ_SUCCESS);
333
334 status = pjsip_inv_send_msg(inv_test.uas, tdata);
335 pj_assert(status == PJ_SUCCESS);
336
337 return PJ_TRUE;
338 }
339
340 return PJ_FALSE;
341}
342
343static pjsip_module mod_inv_oa_test =
344{
345 NULL, NULL, /* prev, next. */
346 { "mod-inv-oa-test", 15 }, /* Name. */
347 -1, /* Id */
348 PJSIP_MOD_PRIORITY_APPLICATION, /* Priority */
349 NULL, /* load() */
350 NULL, /* start() */
351 NULL, /* stop() */
352 NULL, /* unload() */
353 &on_rx_request, /* on_rx_request() */
354 NULL, /* on_rx_response() */
355 NULL, /* on_tx_request. */
356 NULL, /* on_tx_response() */
357 NULL, /* on_tsx_state() */
358};
359
360
361/**************** THE TEST ******************/
362static void run_job(job_t *j)
363{
364 pjsip_inv_session *inv;
365 pjsip_tx_data *tdata;
366 pjmedia_sdp_session *sdp;
367 pj_status_t status;
368
369 if (j->who == PJSIP_ROLE_UAC)
370 inv = inv_test.uac;
371 else
372 inv = inv_test.uas;
373
374 switch (j->type) {
375 case SEND_OFFER:
376 sdp = create_sdp(inv->dlg->pool, oa_sdp[inv_test.oa_index].offer);
377
378 TRACE_((THIS_FILE, " Sending UPDATE with offer"));
379 status = pjsip_inv_update(inv, NULL, sdp, &tdata);
380 pj_assert(status == PJ_SUCCESS);
381
382 status = pjsip_inv_send_msg(inv, tdata);
383 pj_assert(status == PJ_SUCCESS);
384 break;
385 case ESTABLISH_CALL:
386 TRACE_((THIS_FILE, " Sending 200/OK"));
387 status = pjsip_inv_answer(inv, 200, NULL, NULL, &tdata);
388 pj_assert(status == PJ_SUCCESS);
389
390 status = pjsip_inv_send_msg(inv, tdata);
391 pj_assert(status == PJ_SUCCESS);
392 break;
393 }
394}
395
396
397static int perform_test(inv_test_param_t *param)
398{
399 pj_str_t uri;
400 pjsip_dialog *dlg;
401 pjmedia_sdp_session *sdp;
402 pjsip_tx_data *tdata;
403 pj_status_t status;
404
405 PJ_LOG(3,(THIS_FILE, " %s", param->title));
406
407 pj_bzero(&inv_test, sizeof(inv_test));
408 pj_memcpy(&inv_test.param, param, sizeof(*param));
409 job_cnt = 0;
410
411 uri = pj_str(CONTACT);
412
413 /*
414 * Create UAC
415 */
416 status = pjsip_dlg_create_uac(pjsip_ua_instance(),
417 &uri, &uri, &uri, &uri, &dlg);
418 PJ_ASSERT_RETURN(status==PJ_SUCCESS, -10);
419
420 if (inv_test.param.oa[0] == OFFERER_UAC)
421 sdp = create_sdp(dlg->pool, oa_sdp[0].offer);
422 else
423 sdp = NULL;
424
425 status = pjsip_inv_create_uac(dlg, sdp, inv_test.param.inv_option, &inv_test.uac);
426 PJ_ASSERT_RETURN(status==PJ_SUCCESS, -20);
427
428 TRACE_((THIS_FILE, " Sending INVITE %s offer", (sdp ? "with" : "without")));
429
430 /*
431 * Make call!
432 */
433 status = pjsip_inv_invite(inv_test.uac, &tdata);
434 PJ_ASSERT_RETURN(status==PJ_SUCCESS, -30);
435
436 status = pjsip_inv_send_msg(inv_test.uac, tdata);
437 PJ_ASSERT_RETURN(status==PJ_SUCCESS, -30);
438
439 /*
440 * Wait until test completes
441 */
442 while (!inv_test.complete) {
443 pj_time_val delay = {0, 20};
444
445 pjsip_endpt_handle_events(endpt, &delay);
446
447 while (job_cnt) {
448 job_t j;
449
450 j = jobs[0];
451 pj_array_erase(jobs, sizeof(jobs[0]), job_cnt, 0);
452 --job_cnt;
453
454 run_job(&j);
455 }
456 }
457
458 flush_events(100);
459
460 /*
461 * Hangup
462 */
463 TRACE_((THIS_FILE, " Disconnecting call"));
464 status = pjsip_inv_end_session(inv_test.uas, PJSIP_SC_DECLINE, 0, &tdata);
465 pj_assert(status == PJ_SUCCESS);
466
467 status = pjsip_inv_send_msg(inv_test.uas, tdata);
468 pj_assert(status == PJ_SUCCESS);
469
470 flush_events(500);
471
472 return 0;
473}
474
475
476static pj_bool_t log_on_rx_msg(pjsip_rx_data *rdata)
477{
478 pjsip_msg *msg = rdata->msg_info.msg;
479 char info[80];
480
481 if (msg->type == PJSIP_REQUEST_MSG)
482 pj_ansi_snprintf(info, sizeof(info), "%.*s",
483 (int)msg->line.req.method.name.slen,
484 msg->line.req.method.name.ptr);
485 else
486 pj_ansi_snprintf(info, sizeof(info), "%d/%.*s",
487 msg->line.status.code,
488 (int)rdata->msg_info.cseq->method.name.slen,
489 rdata->msg_info.cseq->method.name.ptr);
490
491 TRACE_((THIS_FILE, " Received %s %s sdp", info,
492 (msg->body ? "with" : "without")));
493
494 return PJ_FALSE;
495}
496
497
498/* Message logger module. */
499static pjsip_module mod_msg_logger =
500{
501 NULL, NULL, /* prev and next */
502 { "mod-msg-loggee", 14}, /* Name. */
503 -1, /* Id */
504 PJSIP_MOD_PRIORITY_TRANSPORT_LAYER-1,/* Priority */
505 NULL, /* load() */
506 NULL, /* start() */
507 NULL, /* stop() */
508 NULL, /* unload() */
509 &log_on_rx_msg, /* on_rx_request() */
510 &log_on_rx_msg, /* on_rx_response() */
511 NULL, /* on_tx_request() */
512 NULL, /* on_tx_response() */
513 NULL, /* on_tsx_state() */
514};
515
516static inv_test_param_t test_params[] =
517{
518/* Normal scenario:
519
520 UAC UAS
521 INVITE (offer) -->
522 200/INVITE (answer) <--
523 ACK -->
524 */
525#if 0
526 {
527 "Standard INVITE with offer",
528 0,
529 PJ_TRUE,
530 1,
531 { OFFERER_UAC }
532 },
533
534 {
535 "Standard INVITE with offer, with 100rel",
536 PJSIP_INV_REQUIRE_100REL,
537 PJ_TRUE,
538 1,
539 { OFFERER_UAC }
540 },
541#endif
542
543/* Delayed offer:
544 UAC UAS
545 INVITE (no SDP) -->
546 200/INVITE (offer) <--
547 ACK (answer) -->
548 */
549#if 1
550 {
551 "INVITE with no offer",
552 0,
553 PJ_TRUE,
554 1,
555 { OFFERER_UAS }
556 },
557
558 {
559 "INVITE with no offer, with 100rel",
560 PJSIP_INV_REQUIRE_100REL,
561 PJ_TRUE,
562 1,
563 { OFFERER_UAS }
564 },
565#endif
566
567/* Subsequent UAC offer with UPDATE:
568
569 UAC UAS
570 INVITE (offer) -->
571 180/rel (answer) <--
572 UPDATE (offer) --> inv_update() on_rx_offer()
573 set_sdp_answer()
574 200/UPDATE (answer) <--
575 200/INVITE <--
576 ACK -->
577*/
578#if 1
579 {
580 "INVITE and UPDATE by UAC",
581 0,
582 PJ_TRUE,
583 2,
584 { OFFERER_UAC, OFFERER_UAC }
585 },
586 {
587 "INVITE and UPDATE by UAC, with 100rel",
588 PJSIP_INV_REQUIRE_100REL,
589 PJ_TRUE,
590 2,
591 { OFFERER_UAC, OFFERER_UAC }
592 },
593#endif
594
595/* Subsequent UAS offer with UPDATE:
596
597 INVITE (offer -->
598 180/rel (answer) <--
599 UPDATE (offer) <-- inv_update()
600 on_rx_offer()
601 set_sdp_answer()
602 200/UPDATE (answer) -->
603 UPDATE (offer) --> on_rx_offer()
604 set_sdp_answer()
605 200/UPDATE (answer) <--
606 200/INVITE <--
607 ACK -->
608
609 */
610 {
611 "INVITE and many UPDATE by UAC and UAS",
612 0,
613 PJ_TRUE,
614 4,
615 { OFFERER_UAC, OFFERER_UAS, OFFERER_UAC, OFFERER_UAS }
616 },
617
618};
619
620
621static pjsip_dialog* on_dlg_forked(pjsip_dialog *first_set, pjsip_rx_data *res)
622{
623 PJ_UNUSED_ARG(first_set);
624 PJ_UNUSED_ARG(res);
625
626 return NULL;
627}
628
629
630static void on_new_session(pjsip_inv_session *inv, pjsip_event *e)
631{
632 PJ_UNUSED_ARG(inv);
633 PJ_UNUSED_ARG(e);
634}
635
636
637int inv_offer_answer_test(void)
638{
639 unsigned i;
640 int rc = 0;
641
642 /* Init UA layer */
643 if (pjsip_ua_instance()->id == -1) {
644 pjsip_ua_init_param ua_param;
645 pj_bzero(&ua_param, sizeof(ua_param));
646 ua_param.on_dlg_forked = &on_dlg_forked;
647 pjsip_ua_init_module(endpt, &ua_param);
648 }
649
650 /* Init inv-usage */
651 if (pjsip_inv_usage_instance()->id == -1) {
652 pjsip_inv_callback inv_cb;
653 pj_bzero(&inv_cb, sizeof(inv_cb));
654 inv_cb.on_media_update = &on_media_update;
655 inv_cb.on_rx_offer = &on_rx_offer;
656 inv_cb.on_create_offer = &on_create_offer;
657 inv_cb.on_state_changed = &on_state_changed;
658 inv_cb.on_new_session = &on_new_session;
659 pjsip_inv_usage_init(endpt, &inv_cb);
660 }
661
662 /* 100rel module */
663 pjsip_100rel_init_module(endpt);
664
665 /* Our module */
666 pjsip_endpt_register_module(endpt, &mod_inv_oa_test);
667 pjsip_endpt_register_module(endpt, &mod_msg_logger);
668
669 /* Create SIP UDP transport */
670 {
671 pj_sockaddr_in addr;
672 pjsip_transport *tp;
673 pj_status_t status;
674
675 pj_sockaddr_in_init(&addr, NULL, PORT);
676 status = pjsip_udp_transport_start(endpt, &addr, NULL, 1, &tp);
677 pj_assert(status == PJ_SUCCESS);
678 }
679
680 /* Do tests */
681 for (i=0; i<PJ_ARRAY_SIZE(test_params); ++i) {
682 rc = perform_test(&test_params[i]);
683 if (rc != 0)
684 goto on_return;
685 }
686
687
688on_return:
689 return rc;
690}
691