1
/* $Id: inv_offer_answer_test.c 3553 2011-05-05 06:14:19Z nanang $ */
3
* Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
4
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
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.
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.
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
26
#define THIS_FILE "inv_offer_answer_test.c"
28
#define CONTACT "sip:127.0.0.1:5068"
29
#define TRACE_(x) PJ_LOG(3,x)
31
static struct oa_sdp_t
41
"o=alice 1 1 IN IP4 host.anywhere.com\r\n"
43
"c=IN IP4 host.anywhere.com\r\n"
45
"m=audio 49170 RTP/AVP 0\r\n"
46
"a=rtpmap:0 PCMU/8000\r\n",
50
"o=bob 1 1 IN IP4 host.example.com\r\n"
52
"c=IN IP4 host.example.com\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",
64
"o=alice 2 2 IN IP4 host.anywhere.com\r\n"
66
"c=IN IP4 host.anywhere.com\r\n"
68
"m=audio 49170 RTP/AVP 8\r\n"
69
"a=rtpmap:0 PCMA/8000\r\n",
73
"o=bob 2 2 IN IP4 host.example.com\r\n"
75
"c=IN IP4 host.example.com\r\n"
77
"m=audio 49920 RTP/AVP 8\r\n"
78
"a=rtpmap:0 PCMA/8000\r\n",
86
"o=alice 3 3 IN IP4 host.anywhere.com\r\n"
88
"c=IN IP4 host.anywhere.com\r\n"
90
"m=audio 49170 RTP/AVP 3\r\n",
94
"o=bob 3 3 IN IP4 host.example.com\r\n"
96
"c=IN IP4 host.example.com\r\n"
98
"m=audio 49920 RTP/AVP 3\r\n",
106
"o=alice 4 4 IN IP4 host.anywhere.com\r\n"
108
"c=IN IP4 host.anywhere.com\r\n"
110
"m=audio 49170 RTP/AVP 4\r\n",
114
"o=bob 4 4 IN IP4 host.example.com\r\n"
116
"c=IN IP4 host.example.com\r\n"
118
"m=audio 49920 RTP/AVP 4\r\n",
133
typedef struct inv_test_param_t
137
pj_bool_t need_established;
142
typedef struct inv_test_t
144
inv_test_param_t param;
145
pjsip_inv_session *uac;
146
pjsip_inv_session *uas;
149
pj_bool_t uas_complete,
153
unsigned uac_update_cnt,
158
/**************** GLOBALS ******************/
159
static inv_test_t inv_test;
160
static unsigned job_cnt;
162
typedef enum job_type
174
static job_t jobs[128];
177
/**************** UTILS ******************/
178
static pjmedia_sdp_session *create_sdp(pj_pool_t *pool, const char *body)
180
pjmedia_sdp_session *sdp;
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);
191
/**************** INVITE SESSION CALLBACKS ******************/
192
static void on_rx_offer(pjsip_inv_session *inv,
193
const pjmedia_sdp_session *offer)
195
pjmedia_sdp_session *sdp;
197
PJ_UNUSED_ARG(offer);
199
sdp = create_sdp(inv->dlg->pool, oa_sdp[inv_test.oa_index].answer);
200
pjsip_inv_set_sdp_answer(inv, sdp);
202
if (inv_test.oa_index == inv_test.param.count-1 &&
203
inv_test.param.need_established)
205
jobs[job_cnt].type = ESTABLISH_CALL;
206
jobs[job_cnt].who = PJSIP_ROLE_UAS;
212
static void on_create_offer(pjsip_inv_session *inv,
213
pjmedia_sdp_session **p_offer)
216
PJ_UNUSED_ARG(p_offer);
218
pj_assert(!"Should not happen");
221
static void on_media_update(pjsip_inv_session *inv_ses,
224
PJ_UNUSED_ARG(status);
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"));
236
pj_assert(!"Unknown session!");
239
if (inv_test.uac_update_cnt == inv_test.uas_update_cnt) {
242
if (inv_test.oa_index < inv_test.param.count) {
243
switch (inv_test.param.oa[inv_test.oa_index]) {
245
jobs[job_cnt].type = SEND_OFFER;
246
jobs[job_cnt].who = PJSIP_ROLE_UAC;
250
jobs[job_cnt].type = SEND_OFFER;
251
jobs[job_cnt].who = PJSIP_ROLE_UAS;
255
pj_assert(!"Invalid oa");
259
pj_assert(job_cnt <= PJ_ARRAY_SIZE(jobs));
263
static void on_state_changed(pjsip_inv_session *inv, pjsip_event *e)
265
const char *who = NULL;
269
if (inv->state == PJSIP_INV_STATE_DISCONNECTED) {
270
TRACE_((THIS_FILE, " %s call disconnected",
271
(inv==inv_test.uas ? "Callee" : "Caller")));
275
if (inv->state != PJSIP_INV_STATE_CONFIRMED)
278
if (inv == inv_test.uas) {
279
inv_test.uas_complete = PJ_TRUE;
281
} else if (inv == inv_test.uac) {
282
inv_test.uac_complete = PJ_TRUE;
285
pj_assert(!"No session");
287
TRACE_((THIS_FILE, " %s call is confirmed", who));
289
if (inv_test.uac_complete && inv_test.uas_complete)
290
inv_test.complete = PJ_TRUE;
294
/**************** MODULE TO RECEIVE INITIAL INVITE ******************/
296
static pj_bool_t on_rx_request(pjsip_rx_data *rdata)
298
if (rdata->msg_info.msg->type == PJSIP_REQUEST_MSG &&
299
rdata->msg_info.msg->line.req.method.id == PJSIP_INVITE_METHOD)
302
pjmedia_sdp_session *sdp = NULL;
304
pjsip_tx_data *tdata;
310
uri = pj_str(CONTACT);
311
status = pjsip_dlg_create_uas(pjsip_ua_instance(), rdata,
313
pj_assert(status == PJ_SUCCESS);
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);
320
pj_assert(!"Invalid offerer type");
322
status = pjsip_inv_create_uas(dlg, rdata, sdp, inv_test.param.inv_option, &inv_test.uas);
323
pj_assert(status == PJ_SUCCESS);
325
TRACE_((THIS_FILE, " Sending 183 with SDP"));
330
status = pjsip_inv_initial_answer(inv_test.uas, rdata, 183, NULL,
332
pj_assert(status == PJ_SUCCESS);
334
status = pjsip_inv_send_msg(inv_test.uas, tdata);
335
pj_assert(status == PJ_SUCCESS);
343
static pjsip_module mod_inv_oa_test =
345
NULL, NULL, /* prev, next. */
346
{ "mod-inv-oa-test", 15 }, /* Name. */
348
PJSIP_MOD_PRIORITY_APPLICATION, /* Priority */
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() */
361
/**************** THE TEST ******************/
362
static void run_job(job_t *j)
364
pjsip_inv_session *inv;
365
pjsip_tx_data *tdata;
366
pjmedia_sdp_session *sdp;
369
if (j->who == PJSIP_ROLE_UAC)
376
sdp = create_sdp(inv->dlg->pool, oa_sdp[inv_test.oa_index].offer);
378
TRACE_((THIS_FILE, " Sending UPDATE with offer"));
379
status = pjsip_inv_update(inv, NULL, sdp, &tdata);
380
pj_assert(status == PJ_SUCCESS);
382
status = pjsip_inv_send_msg(inv, tdata);
383
pj_assert(status == PJ_SUCCESS);
386
TRACE_((THIS_FILE, " Sending 200/OK"));
387
status = pjsip_inv_answer(inv, 200, NULL, NULL, &tdata);
388
pj_assert(status == PJ_SUCCESS);
390
status = pjsip_inv_send_msg(inv, tdata);
391
pj_assert(status == PJ_SUCCESS);
397
static int perform_test(inv_test_param_t *param)
401
pjmedia_sdp_session *sdp;
402
pjsip_tx_data *tdata;
405
PJ_LOG(3,(THIS_FILE, " %s", param->title));
407
pj_bzero(&inv_test, sizeof(inv_test));
408
pj_memcpy(&inv_test.param, param, sizeof(*param));
411
uri = pj_str(CONTACT);
416
status = pjsip_dlg_create_uac(pjsip_ua_instance(),
417
&uri, &uri, &uri, &uri, &dlg);
418
PJ_ASSERT_RETURN(status==PJ_SUCCESS, -10);
420
if (inv_test.param.oa[0] == OFFERER_UAC)
421
sdp = create_sdp(dlg->pool, oa_sdp[0].offer);
425
status = pjsip_inv_create_uac(dlg, sdp, inv_test.param.inv_option, &inv_test.uac);
426
PJ_ASSERT_RETURN(status==PJ_SUCCESS, -20);
428
TRACE_((THIS_FILE, " Sending INVITE %s offer", (sdp ? "with" : "without")));
433
status = pjsip_inv_invite(inv_test.uac, &tdata);
434
PJ_ASSERT_RETURN(status==PJ_SUCCESS, -30);
436
status = pjsip_inv_send_msg(inv_test.uac, tdata);
437
PJ_ASSERT_RETURN(status==PJ_SUCCESS, -30);
440
* Wait until test completes
442
while (!inv_test.complete) {
443
pj_time_val delay = {0, 20};
445
pjsip_endpt_handle_events(endpt, &delay);
451
pj_array_erase(jobs, sizeof(jobs[0]), job_cnt, 0);
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);
467
status = pjsip_inv_send_msg(inv_test.uas, tdata);
468
pj_assert(status == PJ_SUCCESS);
476
static pj_bool_t log_on_rx_msg(pjsip_rx_data *rdata)
478
pjsip_msg *msg = rdata->msg_info.msg;
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);
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);
491
TRACE_((THIS_FILE, " Received %s %s sdp", info,
492
(msg->body ? "with" : "without")));
498
/* Message logger module. */
499
static pjsip_module mod_msg_logger =
501
NULL, NULL, /* prev and next */
502
{ "mod-msg-loggee", 14}, /* Name. */
504
PJSIP_MOD_PRIORITY_TRANSPORT_LAYER-1,/* Priority */
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() */
516
static inv_test_param_t test_params[] =
522
200/INVITE (answer) <--
527
"Standard INVITE with offer",
535
"Standard INVITE with offer, with 100rel",
536
PJSIP_INV_REQUIRE_100REL,
546
200/INVITE (offer) <--
551
"INVITE with no offer",
559
"INVITE with no offer, with 100rel",
560
PJSIP_INV_REQUIRE_100REL,
567
/* Subsequent UAC offer with UPDATE:
572
UPDATE (offer) --> inv_update() on_rx_offer()
574
200/UPDATE (answer) <--
580
"INVITE and UPDATE by UAC",
584
{ OFFERER_UAC, OFFERER_UAC }
587
"INVITE and UPDATE by UAC, with 100rel",
588
PJSIP_INV_REQUIRE_100REL,
591
{ OFFERER_UAC, OFFERER_UAC }
595
/* Subsequent UAS offer with UPDATE:
599
UPDATE (offer) <-- inv_update()
602
200/UPDATE (answer) -->
603
UPDATE (offer) --> on_rx_offer()
605
200/UPDATE (answer) <--
611
"INVITE and many UPDATE by UAC and UAS",
615
{ OFFERER_UAC, OFFERER_UAS, OFFERER_UAC, OFFERER_UAS }
621
static pjsip_dialog* on_dlg_forked(pjsip_dialog *first_set, pjsip_rx_data *res)
623
PJ_UNUSED_ARG(first_set);
630
static void on_new_session(pjsip_inv_session *inv, pjsip_event *e)
637
int inv_offer_answer_test(void)
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);
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);
663
pjsip_100rel_init_module(endpt);
666
pjsip_endpt_register_module(endpt, &mod_inv_oa_test);
667
pjsip_endpt_register_module(endpt, &mod_msg_logger);
669
/* Create SIP UDP transport */
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);
681
for (i=0; i<PJ_ARRAY_SIZE(test_params); ++i) {
682
rc = perform_test(&test_params[i]);