Add support for ICE/STUN/TURN in res_rtp_asterisk and chan_sip.
[asterisk/asterisk.git] / res / pjproject / pjsip / src / test / inv_offer_answer_test.c
1 /* $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
31 static 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
126 typedef enum oa_t
127 {
128     OFFERER_NONE,
129     OFFERER_UAC,
130     OFFERER_UAS
131 } oa_t;
132
133 typedef 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
142 typedef 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 ******************/
159 static inv_test_t   inv_test;
160 static unsigned     job_cnt;
161
162 typedef enum job_type
163 {
164     SEND_OFFER,
165     ESTABLISH_CALL
166 } job_type;
167
168 typedef struct job_t
169 {
170     job_type        type;
171     pjsip_role_e    who;
172 } job_t;
173
174 static job_t jobs[128];
175
176
177 /**************** UTILS ******************/
178 static 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 ******************/
192 static 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
212 static 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
221 static 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
263 static 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
296 static 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
343 static 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 ******************/
362 static 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
397 static 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
476 static 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. */
499 static 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
516 static 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
621 static 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
630 static 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
637 int 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
688 on_return:
689     return rc;
690 }
691