~ubuntu-branches/ubuntu/wily/sflphone/wily

« back to all changes in this revision

Viewing changes to daemon/libs/pjproject-2.0.1/pjsip-apps/src/samples/sipecho.c

  • Committer: Package Import Robot
  • Author(s): Mark Purcell
  • Date: 2014-01-28 18:23:36 UTC
  • mfrom: (1.1.11)
  • mto: This revision was merged to the branch mainline in revision 24.
  • Revision ID: package-import@ubuntu.com-20140128182336-3xenud1kbnwmf3mz
* New upstream release 
  - Fixes "New Upstream Release" (Closes: #735846)
  - Fixes "Ringtone does not stop" (Closes: #727164)
  - Fixes "[sflphone-kde] crash on startup" (Closes: #718178)
  - Fixes "sflphone GUI crashes when call is hung up" (Closes: #736583)
* Build-Depends: ensure GnuTLS 2.6
  - libucommon-dev (>= 6.0.7-1.1), libccrtp-dev (>= 2.0.6-3)
  - Fixes "FTBFS Build-Depends libgnutls{26,28}-dev" (Closes: #722040)
* Fix "boost 1.49 is going away" unversioned Build-Depends: (Closes: #736746)
* Add Build-Depends: libsndfile-dev, nepomuk-core-dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* $Id: sipecho.c 4148 2012-05-31 12:21:59Z bennylp $ */
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
 
 
22
 
/**
23
 
 * sipecho.c
24
 
 *
25
 
 * - Accepts incoming calls and echoes back SDP and any media.
26
 
 * - Specify URI in cmdline argument to make call
27
 
 * - Accepts registration too!
28
 
 */
29
 
 
30
 
/* Include all headers. */
31
 
#include <pjsip.h>
32
 
#include <pjmedia/sdp.h>
33
 
#include <pjsip_ua.h>
34
 
#include <pjlib-util.h>
35
 
#include <pjlib.h>
36
 
 
37
 
/* For logging purpose. */
38
 
#define THIS_FILE   "sipecho.c"
39
 
 
40
 
#include "util.h"
41
 
 
42
 
 
43
 
/* Settings */
44
 
#define MAX_CALLS       8
45
 
 
46
 
typedef struct call_t
47
 
{
48
 
    pjsip_inv_session   *inv;
49
 
} call_t;
50
 
 
51
 
static struct app_t
52
 
{
53
 
    pj_caching_pool      cp;
54
 
    pj_pool_t           *pool;
55
 
 
56
 
    pjsip_endpoint      *sip_endpt;
57
 
    //pjmedia_endpt     *med_endpt;
58
 
 
59
 
    call_t               call[MAX_CALLS];
60
 
 
61
 
    pj_bool_t            quit;
62
 
    pj_thread_t         *worker_thread;
63
 
 
64
 
    pj_bool_t            enable_msg_logging;
65
 
} app;
66
 
 
67
 
/*
68
 
 * Prototypes:
69
 
 */
70
 
 
71
 
static void call_on_media_update(pjsip_inv_session *inv, pj_status_t status);
72
 
static void call_on_state_changed(pjsip_inv_session *inv, pjsip_event *e);
73
 
static void call_on_rx_offer(pjsip_inv_session *inv, const pjmedia_sdp_session *offer);
74
 
static void call_on_forked(pjsip_inv_session *inv, pjsip_event *e);
75
 
static pj_bool_t on_rx_request( pjsip_rx_data *rdata );
76
 
 
77
 
/* Globals */
78
 
static int sip_af;
79
 
static int sip_port = 5060;
80
 
static pj_bool_t sip_tcp;
81
 
 
82
 
/* This is a PJSIP module to be registered by application to handle
83
 
 * incoming requests outside any dialogs/transactions. The main purpose
84
 
 * here is to handle incoming INVITE request message, where we will
85
 
 * create a dialog and INVITE session for it.
86
 
 */
87
 
static pjsip_module mod_sipecho =
88
 
{
89
 
    NULL, NULL,                     /* prev, next.              */
90
 
    { "mod-sipecho", 11 },          /* Name.                    */
91
 
    -1,                             /* Id                       */
92
 
    PJSIP_MOD_PRIORITY_APPLICATION, /* Priority                 */
93
 
    NULL,                           /* load()                   */
94
 
    NULL,                           /* start()                  */
95
 
    NULL,                           /* stop()                   */
96
 
    NULL,                           /* unload()                 */
97
 
    &on_rx_request,                 /* on_rx_request()          */
98
 
    NULL,                           /* on_rx_response()         */
99
 
    NULL,                           /* on_tx_request.           */
100
 
    NULL,                           /* on_tx_response()         */
101
 
    NULL,                           /* on_tsx_state()           */
102
 
};
103
 
 
104
 
/* Notification on incoming messages */
105
 
static pj_bool_t logging_on_rx_msg(pjsip_rx_data *rdata)
106
 
{
107
 
    if (!app.enable_msg_logging)
108
 
        return PJ_FALSE;
109
 
 
110
 
    PJ_LOG(3,(THIS_FILE, "RX %d bytes %s from %s %s:%d:\n"
111
 
                         "%.*s\n"
112
 
                         "--end msg--",
113
 
                         rdata->msg_info.len,
114
 
                         pjsip_rx_data_get_info(rdata),
115
 
                         rdata->tp_info.transport->type_name,
116
 
                         rdata->pkt_info.src_name,
117
 
                         rdata->pkt_info.src_port,
118
 
                         (int)rdata->msg_info.len,
119
 
                         rdata->msg_info.msg_buf));
120
 
    return PJ_FALSE;
121
 
}
122
 
 
123
 
/* Notification on outgoing messages */
124
 
static pj_status_t logging_on_tx_msg(pjsip_tx_data *tdata)
125
 
{
126
 
    if (!app.enable_msg_logging)
127
 
        return PJ_SUCCESS;
128
 
 
129
 
    PJ_LOG(3,(THIS_FILE, "TX %d bytes %s to %s %s:%d:\n"
130
 
                         "%.*s\n"
131
 
                         "--end msg--",
132
 
                         (tdata->buf.cur - tdata->buf.start),
133
 
                         pjsip_tx_data_get_info(tdata),
134
 
                         tdata->tp_info.transport->type_name,
135
 
                         tdata->tp_info.dst_name,
136
 
                         tdata->tp_info.dst_port,
137
 
                         (int)(tdata->buf.cur - tdata->buf.start),
138
 
                         tdata->buf.start));
139
 
    return PJ_SUCCESS;
140
 
}
141
 
 
142
 
/* The module instance. */
143
 
static pjsip_module msg_logger =
144
 
{
145
 
    NULL, NULL,                         /* prev, next.          */
146
 
    { "mod-msg-log", 13 },              /* Name.                */
147
 
    -1,                                 /* Id                   */
148
 
    PJSIP_MOD_PRIORITY_TRANSPORT_LAYER-1,/* Priority            */
149
 
    NULL,                               /* load()               */
150
 
    NULL,                               /* start()              */
151
 
    NULL,                               /* stop()               */
152
 
    NULL,                               /* unload()             */
153
 
    &logging_on_rx_msg,                 /* on_rx_request()      */
154
 
    &logging_on_rx_msg,                 /* on_rx_response()     */
155
 
    &logging_on_tx_msg,                 /* on_tx_request.       */
156
 
    &logging_on_tx_msg,                 /* on_tx_response()     */
157
 
    NULL,                               /* on_tsx_state()       */
158
 
 
159
 
};
160
 
 
161
 
static int worker_proc(void *arg)
162
 
{
163
 
    PJ_UNUSED_ARG(arg);
164
 
 
165
 
    while (!app.quit) {
166
 
        pj_time_val interval = { 0, 20 };
167
 
        pjsip_endpt_handle_events(app.sip_endpt, &interval);
168
 
    }
169
 
 
170
 
    return 0;
171
 
}
172
 
 
173
 
static void hangup_all(void)
174
 
{
175
 
    unsigned i;
176
 
    for (i=0; i<MAX_CALLS; ++i) {
177
 
        call_t *call = &app.call[i];
178
 
 
179
 
        if (call->inv && call->inv->state <= PJSIP_INV_STATE_CONFIRMED) {
180
 
            pj_status_t status;
181
 
            pjsip_tx_data *tdata;
182
 
 
183
 
            status = pjsip_inv_end_session(call->inv, PJSIP_SC_BUSY_HERE, NULL, &tdata);
184
 
            if (status==PJ_SUCCESS && tdata)
185
 
                pjsip_inv_send_msg(call->inv, tdata);
186
 
        }
187
 
    }
188
 
}
189
 
 
190
 
static void destroy_stack(void)
191
 
{
192
 
    enum { WAIT_CLEAR = 5000, WAIT_INTERVAL = 500 };
193
 
    unsigned i;
194
 
 
195
 
    PJ_LOG(3,(THIS_FILE, "Shutting down.."));
196
 
 
197
 
    /* Wait until all clear */
198
 
    hangup_all();
199
 
    for (i=0; i<WAIT_CLEAR/WAIT_INTERVAL; ++i) {
200
 
        unsigned j;
201
 
 
202
 
        for (j=0; j<MAX_CALLS; ++j) {
203
 
            call_t *call = &app.call[j];
204
 
            if (call->inv && call->inv->state <= PJSIP_INV_STATE_CONFIRMED)
205
 
                break;
206
 
        }
207
 
 
208
 
        if (j==MAX_CALLS)
209
 
            return;
210
 
 
211
 
        pj_thread_sleep(WAIT_INTERVAL);
212
 
    }
213
 
 
214
 
    app.quit = PJ_TRUE;
215
 
    if (app.worker_thread) {
216
 
        pj_thread_join(app.worker_thread);
217
 
        app.worker_thread = NULL;
218
 
    }
219
 
 
220
 
    //if (app.med_endpt)
221
 
        //pjmedia_endpt_destroy(app.med_endpt);
222
 
 
223
 
    if (app.sip_endpt)
224
 
        pjsip_endpt_destroy(app.sip_endpt);
225
 
 
226
 
    if (app.pool)
227
 
        pj_pool_release(app.pool);
228
 
 
229
 
    dump_pool_usage(THIS_FILE, &app.cp);
230
 
    pj_caching_pool_destroy(&app.cp);
231
 
}
232
 
 
233
 
#define CHECK_STATUS()  do { if (status != PJ_SUCCESS) return status; } while (0)
234
 
 
235
 
static pj_status_t init_stack()
236
 
{
237
 
    pj_sockaddr addr;
238
 
    pjsip_inv_callback inv_cb;
239
 
    pj_status_t status;
240
 
 
241
 
    pj_log_set_level(3);
242
 
 
243
 
    status = pjlib_util_init();
244
 
    CHECK_STATUS();
245
 
 
246
 
    pj_caching_pool_init(&app.cp, NULL, 0);
247
 
    app.pool = pj_pool_create( &app.cp.factory, "sipecho", 512, 512, 0);
248
 
 
249
 
    status = pjsip_endpt_create(&app.cp.factory, NULL, &app.sip_endpt);
250
 
    CHECK_STATUS();
251
 
 
252
 
    pj_log_set_level(4);
253
 
    pj_sockaddr_init((pj_uint16_t)sip_af, &addr, NULL, (pj_uint16_t)sip_port);
254
 
    if (sip_af == pj_AF_INET()) {
255
 
        if (sip_tcp) {
256
 
            status = pjsip_tcp_transport_start( app.sip_endpt, &addr.ipv4, 1,
257
 
                                                NULL);
258
 
        } else {
259
 
            status = pjsip_udp_transport_start( app.sip_endpt, &addr.ipv4,
260
 
                                                NULL, 1, NULL);
261
 
        }
262
 
    } else if (sip_af == pj_AF_INET6()) {
263
 
            status = pjsip_udp_transport_start6(app.sip_endpt, &addr.ipv6,
264
 
                                                NULL, 1, NULL);
265
 
    } else {
266
 
        status = PJ_EAFNOTSUP;
267
 
    }
268
 
 
269
 
    pj_log_set_level(3);
270
 
    CHECK_STATUS();
271
 
 
272
 
    status = pjsip_tsx_layer_init_module(app.sip_endpt) ||
273
 
             pjsip_ua_init_module( app.sip_endpt, NULL );
274
 
    CHECK_STATUS();
275
 
 
276
 
    pj_bzero(&inv_cb, sizeof(inv_cb));
277
 
    inv_cb.on_state_changed = &call_on_state_changed;
278
 
    inv_cb.on_new_session = &call_on_forked;
279
 
    inv_cb.on_media_update = &call_on_media_update;
280
 
    inv_cb.on_rx_offer = &call_on_rx_offer;
281
 
 
282
 
    status = pjsip_inv_usage_init(app.sip_endpt, &inv_cb) ||
283
 
             pjsip_100rel_init_module(app.sip_endpt) ||
284
 
             pjsip_endpt_register_module( app.sip_endpt, &mod_sipecho) ||
285
 
             pjsip_endpt_register_module( app.sip_endpt, &msg_logger) ||
286
 
             //pjmedia_endpt_create(&app.cp.factory,
287
 
                //                pjsip_endpt_get_ioqueue(app.sip_endpt),
288
 
                //                0, &app.med_endpt) ||
289
 
             pj_thread_create(app.pool, "sipecho", &worker_proc, NULL, 0, 0,
290
 
                              &app.worker_thread);
291
 
    CHECK_STATUS();
292
 
 
293
 
    return PJ_SUCCESS;
294
 
}
295
 
 
296
 
static void destroy_call(call_t *call)
297
 
{
298
 
    call->inv = NULL;
299
 
}
300
 
 
301
 
static pjmedia_sdp_attr * find_remove_sdp_attrs(unsigned *cnt,
302
 
                                                pjmedia_sdp_attr *attr[],
303
 
                                                unsigned cnt_attr_to_remove,
304
 
                                                const char* attr_to_remove[])
305
 
{
306
 
    pjmedia_sdp_attr *found_attr = NULL;
307
 
    int i;
308
 
 
309
 
    for (i=0; i<(int)*cnt; ++i) {
310
 
        unsigned j;
311
 
        for (j=0; j<cnt_attr_to_remove; ++j) {
312
 
            if (pj_strcmp2(&attr[i]->name, attr_to_remove[j])==0) {
313
 
                if (!found_attr) found_attr = attr[i];
314
 
                pj_array_erase(attr, sizeof(attr[0]), *cnt, i);
315
 
                --(*cnt);
316
 
                --i;
317
 
                break;
318
 
            }
319
 
        }
320
 
    }
321
 
 
322
 
    return found_attr;
323
 
}
324
 
 
325
 
static pjmedia_sdp_session *create_answer(int call_num, pj_pool_t *pool,
326
 
                                          const pjmedia_sdp_session *offer)
327
 
{
328
 
    const char* dir_attrs[] = { "sendrecv", "sendonly", "recvonly", "inactive" };
329
 
    const char *ice_attrs[] = {"ice-pwd", "ice-ufrag", "candidate"};
330
 
    pjmedia_sdp_session *answer = pjmedia_sdp_session_clone(pool, offer);
331
 
    pjmedia_sdp_attr *sess_dir_attr = NULL;
332
 
    unsigned mi;
333
 
 
334
 
    PJ_LOG(3,(THIS_FILE, "Call %d: creating answer:", call_num));
335
 
 
336
 
    answer->name = pj_str("sipecho");
337
 
    sess_dir_attr = find_remove_sdp_attrs(&answer->attr_count, answer->attr,
338
 
                                          PJ_ARRAY_SIZE(dir_attrs),
339
 
                                          dir_attrs);
340
 
 
341
 
    for (mi=0; mi<answer->media_count; ++mi) {
342
 
        pjmedia_sdp_media *m = answer->media[mi];
343
 
        pjmedia_sdp_attr *m_dir_attr;
344
 
        pjmedia_sdp_attr *dir_attr;
345
 
        const char *our_dir = NULL;
346
 
        pjmedia_sdp_conn *c;
347
 
 
348
 
        /* Match direction */
349
 
        m_dir_attr = find_remove_sdp_attrs(&m->attr_count, m->attr,
350
 
                                           PJ_ARRAY_SIZE(dir_attrs),
351
 
                                           dir_attrs);
352
 
        dir_attr = m_dir_attr ? m_dir_attr : sess_dir_attr;
353
 
 
354
 
        if (dir_attr) {
355
 
            if (pj_strcmp2(&dir_attr->name, "sendonly")==0)
356
 
                our_dir = "recvonly";
357
 
            else if (pj_strcmp2(&dir_attr->name, "inactive")==0)
358
 
                our_dir = "inactive";
359
 
            else if (pj_strcmp2(&dir_attr->name, "recvonly")==0)
360
 
                our_dir = "inactive";
361
 
 
362
 
            if (our_dir) {
363
 
                dir_attr = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_attr);
364
 
                dir_attr->name = pj_str((char*)our_dir);
365
 
                m->attr[m->attr_count++] = dir_attr;
366
 
            }
367
 
        }
368
 
 
369
 
        /* Remove ICE attributes */
370
 
        find_remove_sdp_attrs(&m->attr_count, m->attr, PJ_ARRAY_SIZE(ice_attrs), ice_attrs);
371
 
 
372
 
        /* Done */
373
 
        c = m->conn ? m->conn : answer->conn;
374
 
        PJ_LOG(3,(THIS_FILE, "  Media %d, %.*s: %s <--> %.*s:%d",
375
 
                  mi, (int)m->desc.media.slen, m->desc.media.ptr,
376
 
                  (our_dir ? our_dir : "sendrecv"),
377
 
                  (int)c->addr.slen, c->addr.ptr, m->desc.port));
378
 
    }
379
 
 
380
 
    return answer;
381
 
}
382
 
 
383
 
static void call_on_state_changed( pjsip_inv_session *inv,
384
 
                                   pjsip_event *e)
385
 
{
386
 
    call_t *call = (call_t*)inv->mod_data[mod_sipecho.id];
387
 
    if (!call)
388
 
        return;
389
 
 
390
 
    PJ_UNUSED_ARG(e);
391
 
    if (inv->state == PJSIP_INV_STATE_DISCONNECTED) {
392
 
        PJ_LOG(3,(THIS_FILE, "Call %d: DISCONNECTED [reason=%d (%s)]",
393
 
                  call - app.call, inv->cause,
394
 
                  pjsip_get_status_text(inv->cause)->ptr));
395
 
        destroy_call(call);
396
 
    } else {
397
 
        PJ_LOG(3,(THIS_FILE, "Call %d: state changed to %s",
398
 
                  call - app.call, pjsip_inv_state_name(inv->state)));
399
 
    }
400
 
}
401
 
 
402
 
static void call_on_rx_offer(pjsip_inv_session *inv, const pjmedia_sdp_session *offer)
403
 
{
404
 
    call_t *call = (call_t*) inv->mod_data[mod_sipecho.id];
405
 
    pjsip_inv_set_sdp_answer(inv, create_answer(call - app.call, inv->pool_prov, offer));
406
 
}
407
 
 
408
 
static void call_on_forked(pjsip_inv_session *inv, pjsip_event *e)
409
 
{
410
 
    PJ_UNUSED_ARG(inv);
411
 
    PJ_UNUSED_ARG(e);
412
 
}
413
 
 
414
 
static pj_bool_t on_rx_request( pjsip_rx_data *rdata )
415
 
{
416
 
    pj_sockaddr hostaddr;
417
 
    char temp[80], hostip[PJ_INET6_ADDRSTRLEN];
418
 
    pj_str_t local_uri;
419
 
    pjsip_dialog *dlg;
420
 
    pjsip_rdata_sdp_info *sdp_info;
421
 
    pjmedia_sdp_session *answer = NULL;
422
 
    pjsip_tx_data *tdata = NULL;
423
 
    call_t *call = NULL;
424
 
    unsigned i;
425
 
    pj_status_t status;
426
 
 
427
 
    PJ_LOG(3,(THIS_FILE, "RX %.*s from %s",
428
 
              (int)rdata->msg_info.msg->line.req.method.name.slen,
429
 
              rdata->msg_info.msg->line.req.method.name.ptr,
430
 
              rdata->pkt_info.src_name));
431
 
 
432
 
    if (rdata->msg_info.msg->line.req.method.id == PJSIP_REGISTER_METHOD) {
433
 
        /* Let me be a registrar! */
434
 
        pjsip_hdr hdr_list, *h;
435
 
        pjsip_msg *msg;
436
 
        int expires = -1;
437
 
 
438
 
        pj_list_init(&hdr_list);
439
 
        msg = rdata->msg_info.msg;
440
 
        h = (pjsip_hdr*)pjsip_msg_find_hdr(msg, PJSIP_H_EXPIRES, NULL);
441
 
        if (h) {
442
 
            expires = ((pjsip_expires_hdr*)h)->ivalue;
443
 
            pj_list_push_back(&hdr_list, pjsip_hdr_clone(rdata->tp_info.pool, h));
444
 
            PJ_LOG(3,(THIS_FILE, " Expires=%d", expires));
445
 
        }
446
 
        if (expires != 0) {
447
 
            h = (pjsip_hdr*)pjsip_msg_find_hdr(msg, PJSIP_H_CONTACT, NULL);
448
 
            if (h)
449
 
                pj_list_push_back(&hdr_list, pjsip_hdr_clone(rdata->tp_info.pool, h));
450
 
        }
451
 
 
452
 
        pjsip_endpt_respond(app.sip_endpt, &mod_sipecho, rdata, 200, NULL,
453
 
                            &hdr_list, NULL, NULL);
454
 
        return PJ_TRUE;
455
 
    }
456
 
 
457
 
    if (rdata->msg_info.msg->line.req.method.id != PJSIP_INVITE_METHOD) {
458
 
        if (rdata->msg_info.msg->line.req.method.id != PJSIP_ACK_METHOD) {
459
 
            pj_str_t reason = pj_str("Go away");
460
 
            pjsip_endpt_respond_stateless( app.sip_endpt, rdata,
461
 
                                           400, &reason,
462
 
                                           NULL, NULL);
463
 
        }
464
 
        return PJ_TRUE;
465
 
    }
466
 
 
467
 
    sdp_info = pjsip_rdata_get_sdp_info(rdata);
468
 
    if (!sdp_info || !sdp_info->sdp) {
469
 
        pj_str_t reason = pj_str("Require valid offer");
470
 
        pjsip_endpt_respond_stateless( app.sip_endpt, rdata,
471
 
                                       400, &reason,
472
 
                                       NULL, NULL);
473
 
    }
474
 
 
475
 
    for (i=0; i<MAX_CALLS; ++i) {
476
 
        if (app.call[i].inv == NULL) {
477
 
            call = &app.call[i];
478
 
            break;
479
 
        }
480
 
    }
481
 
 
482
 
    if (i==MAX_CALLS) {
483
 
        pj_str_t reason = pj_str("We're full");
484
 
        pjsip_endpt_respond_stateless( app.sip_endpt, rdata,
485
 
                                       PJSIP_SC_BUSY_HERE, &reason,
486
 
                                       NULL, NULL);
487
 
        return PJ_TRUE;
488
 
    }
489
 
 
490
 
    /* Generate Contact URI */
491
 
    status = pj_gethostip(sip_af, &hostaddr);
492
 
    if (status != PJ_SUCCESS) {
493
 
        app_perror(THIS_FILE, "Unable to retrieve local host IP", status);
494
 
        return PJ_TRUE;
495
 
    }
496
 
    pj_sockaddr_print(&hostaddr, hostip, sizeof(hostip), 2);
497
 
    pj_ansi_sprintf(temp, "<sip:sipecho@%s:%d>", hostip, sip_port);
498
 
    local_uri = pj_str(temp);
499
 
 
500
 
    status = pjsip_dlg_create_uas( pjsip_ua_instance(), rdata,
501
 
                                   &local_uri, &dlg);
502
 
 
503
 
    if (status == PJ_SUCCESS)
504
 
        answer = create_answer(call-app.call, dlg->pool, sdp_info->sdp);
505
 
    if (status == PJ_SUCCESS)
506
 
        status = pjsip_inv_create_uas( dlg, rdata, answer, 0, &call->inv);
507
 
    if (status == PJ_SUCCESS)
508
 
        status = pjsip_inv_initial_answer(call->inv, rdata, 100,
509
 
                                          NULL, NULL, &tdata);
510
 
    if (status == PJ_SUCCESS)
511
 
        status = pjsip_inv_send_msg(call->inv, tdata);
512
 
 
513
 
    if (status == PJ_SUCCESS)
514
 
        status = pjsip_inv_answer(call->inv, 180, NULL,
515
 
                                  NULL, &tdata);
516
 
    if (status == PJ_SUCCESS)
517
 
        status = pjsip_inv_send_msg(call->inv, tdata);
518
 
 
519
 
    if (status == PJ_SUCCESS)
520
 
        status = pjsip_inv_answer(call->inv, 200, NULL,
521
 
                                  NULL, &tdata);
522
 
    if (status == PJ_SUCCESS)
523
 
        status = pjsip_inv_send_msg(call->inv, tdata);
524
 
 
525
 
    if (status != PJ_SUCCESS) {
526
 
        pjsip_endpt_respond_stateless( app.sip_endpt, rdata,
527
 
                                       500, NULL, NULL, NULL);
528
 
        destroy_call(call);
529
 
    } else {
530
 
        call->inv->mod_data[mod_sipecho.id] = call;
531
 
    }
532
 
 
533
 
    return PJ_TRUE;
534
 
}
535
 
 
536
 
static void call_on_media_update( pjsip_inv_session *inv,
537
 
                                  pj_status_t status)
538
 
{
539
 
    PJ_UNUSED_ARG(inv);
540
 
    PJ_UNUSED_ARG(status);
541
 
}
542
 
 
543
 
 
544
 
static void usage()
545
 
{
546
 
    printf("\nUsage: sipecho OPTIONS\n");
547
 
    printf("\n");
548
 
    printf("where OPTIONS:\n");
549
 
    printf("  --local-port, -p PORT        Bind to port PORT.\n");
550
 
    printf("  --tcp, -t                    Listen to TCP instead.\n");
551
 
    printf("  --ipv6, -6                   Use IPv6 instead.\n");
552
 
    printf("  --help, -h                   Show this help page.\n");
553
 
}
554
 
 
555
 
/* main()
556
 
 *
557
 
 * If called with argument, treat argument as SIP URL to be called.
558
 
 * Otherwise wait for incoming calls.
559
 
 */
560
 
int main(int argc, char *argv[])
561
 
{
562
 
    struct pj_getopt_option long_options[] = {
563
 
        { "local-port", 1, 0, 'p' },
564
 
        { "tcp",        0, 0, 't' },
565
 
        { "ipv6",       0, 0, '6' },
566
 
        { "help",       0, 0, 'h' }
567
 
    };
568
 
    int c, option_index;
569
 
 
570
 
    pj_log_set_level(5);
571
 
 
572
 
    pj_init();
573
 
 
574
 
    sip_af = pj_AF_INET();
575
 
 
576
 
    pj_optind = 0;
577
 
    while ((c = pj_getopt_long(argc, argv, "p:t6h", long_options,
578
 
                               &option_index)) != -1)
579
 
    {
580
 
        switch (c) {
581
 
        case 'p':
582
 
            sip_port = atoi(pj_optarg);
583
 
            break;
584
 
        case 't':
585
 
            sip_tcp = PJ_TRUE;
586
 
            break;
587
 
        case 'h':
588
 
            usage();
589
 
            return 0;
590
 
        case '6':
591
 
            sip_af = pj_AF_INET6();
592
 
            break;
593
 
        default:
594
 
            PJ_LOG(1,(THIS_FILE,
595
 
                      "Argument \"%s\" is not valid. Use --help to see help",
596
 
                      argv[pj_optind-1]));
597
 
            return -1;
598
 
        }
599
 
    }
600
 
 
601
 
    if (init_stack())
602
 
        goto on_error;
603
 
 
604
 
    /* If URL is specified, then make call immediately. */
605
 
    if (pj_optind != argc) {
606
 
        pj_sockaddr hostaddr;
607
 
        char hostip[PJ_INET6_ADDRSTRLEN+2];
608
 
        char temp[80];
609
 
        call_t *call;
610
 
        pj_str_t dst_uri = pj_str(argv[pj_optind]);
611
 
        pj_str_t local_uri;
612
 
        pjsip_dialog *dlg;
613
 
        pj_status_t status;
614
 
        pjsip_tx_data *tdata;
615
 
 
616
 
        if (pj_gethostip(sip_af, &hostaddr) != PJ_SUCCESS) {
617
 
            PJ_LOG(1,(THIS_FILE, "Unable to retrieve local host IP"));
618
 
            goto on_error;
619
 
        }
620
 
        pj_sockaddr_print(&hostaddr, hostip, sizeof(hostip), 2);
621
 
 
622
 
        pj_ansi_sprintf(temp, "<sip:sipecho@%s:%d>",
623
 
                        hostip, sip_port);
624
 
        local_uri = pj_str(temp);
625
 
 
626
 
        call = &app.call[0];
627
 
 
628
 
        status = pjsip_dlg_create_uac( pjsip_ua_instance(),
629
 
                                       &local_uri,  /* local URI */
630
 
                                       &local_uri,  /* local Contact */
631
 
                                       &dst_uri,    /* remote URI */
632
 
                                       &dst_uri,    /* remote target */
633
 
                                       &dlg);       /* dialog */
634
 
        if (status != PJ_SUCCESS) {
635
 
            app_perror(THIS_FILE, "Unable to create UAC dialog", status);
636
 
            return 1;
637
 
        }
638
 
 
639
 
        status = pjsip_inv_create_uac( dlg, NULL, 0, &call->inv);
640
 
        if (status != PJ_SUCCESS) goto on_error;
641
 
 
642
 
        call->inv->mod_data[mod_sipecho.id] = call;
643
 
 
644
 
        status = pjsip_inv_invite(call->inv, &tdata);
645
 
        if (status != PJ_SUCCESS) goto on_error;
646
 
 
647
 
        status = pjsip_inv_send_msg(call->inv, tdata);
648
 
        if (status != PJ_SUCCESS) goto on_error;
649
 
 
650
 
        puts("Press ENTER to quit...");
651
 
    } else {
652
 
        puts("Ready for incoming calls. Press ENTER to quit...");
653
 
    }
654
 
 
655
 
    for (;;) {
656
 
        char s[10];
657
 
 
658
 
        printf("\nMenu:\n"
659
 
               "  h    Hangup all calls\n"
660
 
               "  l    %s message logging\n"
661
 
               "  q    Quit\n",
662
 
               (app.enable_msg_logging? "Disable" : "Enable"));
663
 
 
664
 
        if (fgets(s, sizeof(s), stdin) == NULL)
665
 
            continue;
666
 
 
667
 
        if (s[0]=='q')
668
 
            break;
669
 
        switch (s[0]) {
670
 
        case 'l':
671
 
            app.enable_msg_logging = !app.enable_msg_logging;
672
 
            break;
673
 
        case 'h':
674
 
            hangup_all();
675
 
            break;
676
 
        }
677
 
    }
678
 
 
679
 
    destroy_stack();
680
 
 
681
 
    puts("Bye bye..");
682
 
    return 0;
683
 
 
684
 
on_error:
685
 
    puts("An error has occurred. run a debugger..");
686
 
    return 1;
687
 
}