~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/stateful_proxy.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: stateful_proxy.c 3553 2011-05-05 06:14:19Z nanang $ */
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
 
#define THIS_FILE   "stateful_proxy.c"
21
 
 
22
 
/* Common proxy functions */
23
 
#define STATEFUL    1
24
 
#include "proxy.h"
25
 
 
26
 
 
27
 
/*
28
 
 * mod_stateful_proxy is the module to receive SIP request and
29
 
 * response message that is outside any transaction context.
30
 
 */
31
 
static pj_bool_t proxy_on_rx_request(pjsip_rx_data *rdata );
32
 
static pj_bool_t proxy_on_rx_response(pjsip_rx_data *rdata );
33
 
 
34
 
static pjsip_module mod_stateful_proxy =
35
 
{
36
 
    NULL, NULL,                         /* prev, next.          */
37
 
    { "mod-stateful-proxy", 18 },       /* Name.                */
38
 
    -1,                                 /* Id                   */
39
 
    PJSIP_MOD_PRIORITY_UA_PROXY_LAYER,  /* Priority             */
40
 
    NULL,                               /* load()               */
41
 
    NULL,                               /* start()              */
42
 
    NULL,                               /* stop()               */
43
 
    NULL,                               /* unload()             */
44
 
    &proxy_on_rx_request,               /* on_rx_request()      */
45
 
    &proxy_on_rx_response,              /* on_rx_response()     */
46
 
    NULL,                               /* on_tx_request.       */
47
 
    NULL,                               /* on_tx_response()     */
48
 
    NULL,                               /* on_tsx_state()       */
49
 
};
50
 
 
51
 
 
52
 
/*
53
 
 * mod_tu (tu=Transaction User) is the module to receive notification
54
 
 * from transaction when the transaction state has changed.
55
 
 */
56
 
static void tu_on_tsx_state(pjsip_transaction *tsx, pjsip_event *event);
57
 
 
58
 
static pjsip_module mod_tu =
59
 
{
60
 
    NULL, NULL,                         /* prev, next.          */
61
 
    { "mod-transaction-user", 20 },     /* Name.                */
62
 
    -1,                                 /* Id                   */
63
 
    PJSIP_MOD_PRIORITY_APPLICATION,     /* Priority             */
64
 
    NULL,                               /* load()               */
65
 
    NULL,                               /* start()              */
66
 
    NULL,                               /* stop()               */
67
 
    NULL,                               /* unload()             */
68
 
    NULL,                               /* on_rx_request()      */
69
 
    NULL,                               /* on_rx_response()     */
70
 
    NULL,                               /* on_tx_request.       */
71
 
    NULL,                               /* on_tx_response()     */
72
 
    &tu_on_tsx_state,                   /* on_tsx_state()       */
73
 
};
74
 
 
75
 
 
76
 
/* This is the data that is attached to the UAC transaction */
77
 
struct uac_data
78
 
{
79
 
    pjsip_transaction   *uas_tsx;
80
 
    pj_timer_entry       timer;
81
 
};
82
 
 
83
 
 
84
 
/* This is the data that is attached to the UAS transaction */
85
 
struct uas_data
86
 
{
87
 
    pjsip_transaction   *uac_tsx;
88
 
};
89
 
 
90
 
 
91
 
 
92
 
static pj_status_t init_stateful_proxy(void)
93
 
{
94
 
    pj_status_t status;
95
 
 
96
 
    status = pjsip_endpt_register_module( global.endpt, &mod_stateful_proxy);
97
 
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
98
 
 
99
 
    status = pjsip_endpt_register_module( global.endpt, &mod_tu);
100
 
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
101
 
 
102
 
    return PJ_SUCCESS;
103
 
}
104
 
 
105
 
 
106
 
/* Callback to be called to handle new incoming requests. */
107
 
static pj_bool_t proxy_on_rx_request( pjsip_rx_data *rdata )
108
 
{
109
 
    pjsip_transaction *uas_tsx, *uac_tsx;
110
 
    struct uac_data *uac_data;
111
 
    struct uas_data *uas_data;
112
 
    pjsip_tx_data *tdata;
113
 
    pj_status_t status;
114
 
 
115
 
    if (rdata->msg_info.msg->line.req.method.id != PJSIP_CANCEL_METHOD) {
116
 
 
117
 
        /* Verify incoming request */
118
 
        status = proxy_verify_request(rdata);
119
 
        if (status != PJ_SUCCESS) {
120
 
            app_perror("RX invalid request", status);
121
 
            return PJ_TRUE;
122
 
        }
123
 
 
124
 
        /*
125
 
         * Request looks sane, next clone the request to create transmit data.
126
 
         */
127
 
        status = pjsip_endpt_create_request_fwd(global.endpt, rdata, NULL,
128
 
                                                NULL, 0, &tdata);
129
 
        if (status != PJ_SUCCESS) {
130
 
            pjsip_endpt_respond_stateless(global.endpt, rdata,
131
 
                                          PJSIP_SC_INTERNAL_SERVER_ERROR,
132
 
                                          NULL, NULL, NULL);
133
 
            return PJ_TRUE;
134
 
        }
135
 
 
136
 
 
137
 
        /* Process routing */
138
 
        status = proxy_process_routing(tdata);
139
 
        if (status != PJ_SUCCESS) {
140
 
            app_perror("Error processing route", status);
141
 
            return PJ_TRUE;
142
 
        }
143
 
 
144
 
        /* Calculate target */
145
 
        status = proxy_calculate_target(rdata, tdata);
146
 
        if (status != PJ_SUCCESS) {
147
 
            app_perror("Error calculating target", status);
148
 
            return PJ_TRUE;
149
 
        }
150
 
 
151
 
        /* Everything is set to forward the request. */
152
 
 
153
 
        /* If this is an ACK request, forward statelessly.
154
 
         * This happens if the proxy records route and this ACK
155
 
         * is sent for 2xx response. An ACK that is sent for non-2xx
156
 
         * final response will be absorbed by transaction layer, and
157
 
         * it will not be received by on_rx_request() callback.
158
 
         */
159
 
        if (tdata->msg->line.req.method.id == PJSIP_ACK_METHOD) {
160
 
            status = pjsip_endpt_send_request_stateless(global.endpt, tdata,
161
 
                                                        NULL, NULL);
162
 
            if (status != PJ_SUCCESS) {
163
 
                app_perror("Error forwarding request", status);
164
 
                return PJ_TRUE;
165
 
            }
166
 
 
167
 
            return PJ_TRUE;
168
 
        }
169
 
 
170
 
        /* Create UAC transaction for forwarding the request.
171
 
         * Set our module as the transaction user to receive further
172
 
         * events from this transaction.
173
 
         */
174
 
        status = pjsip_tsx_create_uac(&mod_tu, tdata, &uac_tsx);
175
 
        if (status != PJ_SUCCESS) {
176
 
            pjsip_tx_data_dec_ref(tdata);
177
 
            pjsip_endpt_respond_stateless(global.endpt, rdata,
178
 
                                          PJSIP_SC_INTERNAL_SERVER_ERROR,
179
 
                                          NULL, NULL, NULL);
180
 
            return PJ_TRUE;
181
 
        }
182
 
 
183
 
        /* Create UAS transaction to handle incoming request */
184
 
        status = pjsip_tsx_create_uas(&mod_tu, rdata, &uas_tsx);
185
 
        if (status != PJ_SUCCESS) {
186
 
            pjsip_tx_data_dec_ref(tdata);
187
 
            pjsip_endpt_respond_stateless(global.endpt, rdata,
188
 
                                          PJSIP_SC_INTERNAL_SERVER_ERROR,
189
 
                                          NULL, NULL, NULL);
190
 
            pjsip_tsx_terminate(uac_tsx, PJSIP_SC_INTERNAL_SERVER_ERROR);
191
 
            return PJ_TRUE;
192
 
        }
193
 
 
194
 
        /* Feed the request to the UAS transaction to drive it's state
195
 
         * out of NULL state.
196
 
         */
197
 
        pjsip_tsx_recv_msg(uas_tsx, rdata);
198
 
 
199
 
        /* Attach a data to the UAC transaction, to be used to find the
200
 
         * UAS transaction when we receive response in the UAC side.
201
 
         */
202
 
        uac_data = (struct uac_data*)
203
 
                   pj_pool_alloc(uac_tsx->pool, sizeof(struct uac_data));
204
 
        uac_data->uas_tsx = uas_tsx;
205
 
        uac_tsx->mod_data[mod_tu.id] = (void*)uac_data;
206
 
 
207
 
        /* Attach data to the UAS transaction, to find the UAC transaction
208
 
         * when cancelling INVITE request.
209
 
         */
210
 
        uas_data = (struct uas_data*)
211
 
                    pj_pool_alloc(uas_tsx->pool, sizeof(struct uas_data));
212
 
        uas_data->uac_tsx = uac_tsx;
213
 
        uas_tsx->mod_data[mod_tu.id] = (void*)uas_data;
214
 
 
215
 
        /* Everything is setup, forward the request */
216
 
        status = pjsip_tsx_send_msg(uac_tsx, tdata);
217
 
        if (status != PJ_SUCCESS) {
218
 
            pjsip_tx_data *err_res;
219
 
 
220
 
            /* Fail to send request, for some reason */
221
 
 
222
 
            /* Destroy transmit data */
223
 
            pjsip_tx_data_dec_ref(tdata);
224
 
 
225
 
            /* I think UAC transaction should have been destroyed when
226
 
             * it fails to send request, so no need to destroy it.
227
 
            pjsip_tsx_terminate(uac_tsx, PJSIP_SC_INTERNAL_SERVER_ERROR);
228
 
             */
229
 
 
230
 
            /* Send 500/Internal Server Error to UAS transaction */
231
 
            pjsip_endpt_create_response(global.endpt, rdata,
232
 
                                        500, NULL, &err_res);
233
 
            pjsip_tsx_send_msg(uas_tsx, err_res);
234
 
 
235
 
            return PJ_TRUE;
236
 
        }
237
 
 
238
 
        /* Send 100/Trying if this is an INVITE */
239
 
        if (rdata->msg_info.msg->line.req.method.id == PJSIP_INVITE_METHOD) {
240
 
            pjsip_tx_data *res100;
241
 
 
242
 
            pjsip_endpt_create_response(global.endpt, rdata, 100, NULL,
243
 
                                        &res100);
244
 
            pjsip_tsx_send_msg(uas_tsx, res100);
245
 
        }
246
 
 
247
 
    } else {
248
 
        /* This is CANCEL request */
249
 
        pjsip_transaction *invite_uas;
250
 
        struct uas_data *uas_data;
251
 
        pj_str_t key;
252
 
 
253
 
        /* Find the UAS INVITE transaction */
254
 
        pjsip_tsx_create_key(rdata->tp_info.pool, &key, PJSIP_UAS_ROLE,
255
 
                             pjsip_get_invite_method(), rdata);
256
 
        invite_uas = pjsip_tsx_layer_find_tsx(&key, PJ_TRUE);
257
 
        if (!invite_uas) {
258
 
            /* Invite transaction not found, respond CANCEL with 481 */
259
 
            pjsip_endpt_respond_stateless(global.endpt, rdata, 481, NULL,
260
 
                                          NULL, NULL);
261
 
            return PJ_TRUE;
262
 
        }
263
 
 
264
 
        /* Respond 200 OK to CANCEL */
265
 
        pjsip_endpt_respond(global.endpt, NULL, rdata, 200, NULL, NULL,
266
 
                            NULL, NULL);
267
 
 
268
 
        /* Send CANCEL to cancel the UAC transaction.
269
 
         * The UAS INVITE transaction will get final response when
270
 
         * we receive final response from the UAC INVITE transaction.
271
 
         */
272
 
        uas_data = (struct uas_data*) invite_uas->mod_data[mod_tu.id];
273
 
        if (uas_data->uac_tsx && uas_data->uac_tsx->status_code < 200) {
274
 
            pjsip_tx_data *cancel;
275
 
 
276
 
            pj_mutex_lock(uas_data->uac_tsx->mutex);
277
 
 
278
 
            pjsip_endpt_create_cancel(global.endpt, uas_data->uac_tsx->last_tx,
279
 
                                      &cancel);
280
 
            pjsip_endpt_send_request(global.endpt, cancel, -1, NULL, NULL);
281
 
 
282
 
            pj_mutex_unlock(uas_data->uac_tsx->mutex);
283
 
        }
284
 
 
285
 
        /* Unlock UAS tsx because it is locked in find_tsx() */
286
 
        pj_mutex_unlock(invite_uas->mutex);
287
 
    }
288
 
 
289
 
    return PJ_TRUE;
290
 
}
291
 
 
292
 
 
293
 
/* Callback to be called to handle incoming response outside
294
 
 * any transactions. This happens for example when 2xx/OK
295
 
 * for INVITE is received and transaction will be destroyed
296
 
 * immediately, so we need to forward the subsequent 2xx/OK
297
 
 * retransmission statelessly.
298
 
 */
299
 
static pj_bool_t proxy_on_rx_response( pjsip_rx_data *rdata )
300
 
{
301
 
    pjsip_tx_data *tdata;
302
 
    pjsip_response_addr res_addr;
303
 
    pjsip_via_hdr *hvia;
304
 
    pj_status_t status;
305
 
 
306
 
    /* Create response to be forwarded upstream (Via will be stripped here) */
307
 
    status = pjsip_endpt_create_response_fwd(global.endpt, rdata, 0, &tdata);
308
 
    if (status != PJ_SUCCESS) {
309
 
        app_perror("Error creating response", status);
310
 
        return PJ_TRUE;
311
 
    }
312
 
 
313
 
    /* Get topmost Via header */
314
 
    hvia = (pjsip_via_hdr*) pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL);
315
 
    if (hvia == NULL) {
316
 
        /* Invalid response! Just drop it */
317
 
        pjsip_tx_data_dec_ref(tdata);
318
 
        return PJ_TRUE;
319
 
    }
320
 
 
321
 
    /* Calculate the address to forward the response */
322
 
    pj_bzero(&res_addr, sizeof(res_addr));
323
 
    res_addr.dst_host.type = PJSIP_TRANSPORT_UDP;
324
 
    res_addr.dst_host.flag =
325
 
        pjsip_transport_get_flag_from_type(PJSIP_TRANSPORT_UDP);
326
 
 
327
 
    /* Destination address is Via's received param */
328
 
    res_addr.dst_host.addr.host = hvia->recvd_param;
329
 
    if (res_addr.dst_host.addr.host.slen == 0) {
330
 
        /* Someone has messed up our Via header! */
331
 
        res_addr.dst_host.addr.host = hvia->sent_by.host;
332
 
    }
333
 
 
334
 
    /* Destination port is the rport */
335
 
    if (hvia->rport_param != 0 && hvia->rport_param != -1)
336
 
        res_addr.dst_host.addr.port = hvia->rport_param;
337
 
 
338
 
    if (res_addr.dst_host.addr.port == 0) {
339
 
        /* Ugh, original sender didn't put rport!
340
 
         * At best, can only send the response to the port in Via.
341
 
         */
342
 
        res_addr.dst_host.addr.port = hvia->sent_by.port;
343
 
    }
344
 
 
345
 
    /* Forward response */
346
 
    status = pjsip_endpt_send_response(global.endpt, &res_addr, tdata,
347
 
                                       NULL, NULL);
348
 
    if (status != PJ_SUCCESS) {
349
 
        app_perror("Error forwarding response", status);
350
 
        return PJ_TRUE;
351
 
    }
352
 
 
353
 
    return PJ_TRUE;
354
 
}
355
 
 
356
 
 
357
 
/* Callback to be called to handle transaction state changed. */
358
 
static void tu_on_tsx_state(pjsip_transaction *tsx, pjsip_event *event)
359
 
{
360
 
    struct uac_data *uac_data;
361
 
    pj_status_t status;
362
 
 
363
 
    if (tsx->role == PJSIP_ROLE_UAS) {
364
 
        if (tsx->state == PJSIP_TSX_STATE_TERMINATED) {
365
 
            struct uas_data *uas_data;
366
 
 
367
 
            uas_data = (struct uas_data*) tsx->mod_data[mod_tu.id];
368
 
            if (uas_data->uac_tsx) {
369
 
                uac_data = (struct uac_data*)
370
 
                           uas_data->uac_tsx->mod_data[mod_tu.id];
371
 
                uac_data->uas_tsx = NULL;
372
 
            }
373
 
 
374
 
        }
375
 
        return;
376
 
    }
377
 
 
378
 
    /* Get the data that we attached to the UAC transaction previously */
379
 
    uac_data = (struct uac_data*) tsx->mod_data[mod_tu.id];
380
 
 
381
 
 
382
 
    /* Handle incoming response */
383
 
    if (event->body.tsx_state.type == PJSIP_EVENT_RX_MSG) {
384
 
 
385
 
        pjsip_rx_data *rdata;
386
 
        pjsip_response_addr res_addr;
387
 
        pjsip_via_hdr *hvia;
388
 
        pjsip_tx_data *tdata;
389
 
 
390
 
        rdata = event->body.tsx_state.src.rdata;
391
 
 
392
 
        /* Do not forward 100 response for INVITE (we already responded
393
 
         * INVITE with 100)
394
 
         */
395
 
        if (tsx->method.id == PJSIP_INVITE_METHOD &&
396
 
            rdata->msg_info.msg->line.status.code == 100)
397
 
        {
398
 
            return;
399
 
        }
400
 
 
401
 
        /* Create response to be forwarded upstream
402
 
         * (Via will be stripped here)
403
 
         */
404
 
        status = pjsip_endpt_create_response_fwd(global.endpt, rdata, 0,
405
 
                                                 &tdata);
406
 
        if (status != PJ_SUCCESS) {
407
 
            app_perror("Error creating response", status);
408
 
            return;
409
 
        }
410
 
 
411
 
        /* Get topmost Via header of the new response */
412
 
        hvia = (pjsip_via_hdr*) pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA,
413
 
                                                   NULL);
414
 
        if (hvia == NULL) {
415
 
            /* Invalid response! Just drop it */
416
 
            pjsip_tx_data_dec_ref(tdata);
417
 
            return;
418
 
        }
419
 
 
420
 
        /* Calculate the address to forward the response */
421
 
        pj_bzero(&res_addr, sizeof(res_addr));
422
 
        res_addr.dst_host.type = PJSIP_TRANSPORT_UDP;
423
 
        res_addr.dst_host.flag =
424
 
            pjsip_transport_get_flag_from_type(PJSIP_TRANSPORT_UDP);
425
 
 
426
 
        /* Destination address is Via's received param */
427
 
        res_addr.dst_host.addr.host = hvia->recvd_param;
428
 
        if (res_addr.dst_host.addr.host.slen == 0) {
429
 
            /* Someone has messed up our Via header! */
430
 
            res_addr.dst_host.addr.host = hvia->sent_by.host;
431
 
        }
432
 
 
433
 
        /* Destination port is the rport */
434
 
        if (hvia->rport_param != 0 && hvia->rport_param != -1)
435
 
            res_addr.dst_host.addr.port = hvia->rport_param;
436
 
 
437
 
        if (res_addr.dst_host.addr.port == 0) {
438
 
            /* Ugh, original sender didn't put rport!
439
 
             * At best, can only send the response to the port in Via.
440
 
             */
441
 
            res_addr.dst_host.addr.port = hvia->sent_by.port;
442
 
        }
443
 
 
444
 
        /* Forward response with the UAS transaction */
445
 
        pjsip_tsx_send_msg(uac_data->uas_tsx, tdata);
446
 
 
447
 
    }
448
 
 
449
 
    /* If UAC transaction is terminated, terminate the UAS as well.
450
 
     * This could happen because of:
451
 
     *  - timeout on the UAC side
452
 
     *  - receipt of 2xx response to INVITE
453
 
     */
454
 
    if (tsx->state == PJSIP_TSX_STATE_TERMINATED && uac_data &&
455
 
        uac_data->uas_tsx)
456
 
    {
457
 
 
458
 
        pjsip_transaction *uas_tsx;
459
 
        struct uas_data *uas_data;
460
 
 
461
 
        uas_tsx = uac_data->uas_tsx;
462
 
        uas_data = (struct uas_data*) uas_tsx->mod_data[mod_tu.id];
463
 
        uas_data->uac_tsx = NULL;
464
 
 
465
 
        if (event->body.tsx_state.type == PJSIP_EVENT_TIMER) {
466
 
 
467
 
            /* Send 408/Timeout if this is an INVITE transaction, since
468
 
             * we must have sent provisional response before. For non
469
 
             * INVITE transaction, just destroy it.
470
 
             */
471
 
            if (tsx->method.id == PJSIP_INVITE_METHOD) {
472
 
 
473
 
                pjsip_tx_data *tdata = uas_tsx->last_tx;
474
 
 
475
 
                tdata->msg->line.status.code = PJSIP_SC_REQUEST_TIMEOUT;
476
 
                tdata->msg->line.status.reason = pj_str("Request timed out");
477
 
                tdata->msg->body = NULL;
478
 
 
479
 
                pjsip_tx_data_add_ref(tdata);
480
 
                pjsip_tx_data_invalidate_msg(tdata);
481
 
 
482
 
                pjsip_tsx_send_msg(uas_tsx, tdata);
483
 
 
484
 
            } else {
485
 
                /* For non-INVITE, just destroy the UAS transaction */
486
 
                pjsip_tsx_terminate(uas_tsx, PJSIP_SC_REQUEST_TIMEOUT);
487
 
            }
488
 
 
489
 
        } else if (event->body.tsx_state.type == PJSIP_EVENT_RX_MSG) {
490
 
 
491
 
            if (uas_tsx->state < PJSIP_TSX_STATE_TERMINATED) {
492
 
                pjsip_msg *msg;
493
 
                int code;
494
 
 
495
 
                msg = event->body.tsx_state.src.rdata->msg_info.msg;
496
 
                code = msg->line.status.code;
497
 
 
498
 
                uac_data->uas_tsx = NULL;
499
 
                pjsip_tsx_terminate(uas_tsx, code);
500
 
            }
501
 
        }
502
 
    }
503
 
}
504
 
 
505
 
 
506
 
/*
507
 
 * main()
508
 
 */
509
 
int main(int argc, char *argv[])
510
 
{
511
 
    pj_status_t status;
512
 
 
513
 
    global.port = 5060;
514
 
    global.record_route = 0;
515
 
 
516
 
    pj_log_set_level(4);
517
 
 
518
 
    status = init_options(argc, argv);
519
 
    if (status != PJ_SUCCESS)
520
 
        return 1;
521
 
 
522
 
    status = init_stack();
523
 
    if (status != PJ_SUCCESS) {
524
 
        app_perror("Error initializing stack", status);
525
 
        return 1;
526
 
    }
527
 
 
528
 
    status = init_proxy();
529
 
    if (status != PJ_SUCCESS) {
530
 
        app_perror("Error initializing proxy", status);
531
 
        return 1;
532
 
    }
533
 
 
534
 
    status = init_stateful_proxy();
535
 
    if (status != PJ_SUCCESS) {
536
 
        app_perror("Error initializing stateful proxy", status);
537
 
        return 1;
538
 
    }
539
 
 
540
 
#if PJ_HAS_THREADS
541
 
    status = pj_thread_create(global.pool, "sproxy", &worker_thread,
542
 
                              NULL, 0, 0, &global.thread);
543
 
    if (status != PJ_SUCCESS) {
544
 
        app_perror("Error creating thread", status);
545
 
        return 1;
546
 
    }
547
 
 
548
 
    while (!global.quit_flag) {
549
 
        char line[10];
550
 
 
551
 
        puts("\n"
552
 
             "Menu:\n"
553
 
             "  q    quit\n"
554
 
             "  d    dump status\n"
555
 
             "  dd   dump detailed status\n"
556
 
             "");
557
 
 
558
 
        if (fgets(line, sizeof(line), stdin) == NULL) {
559
 
            puts("EOF while reading stdin, will quit now..");
560
 
            global.quit_flag = PJ_TRUE;
561
 
            break;
562
 
        }
563
 
 
564
 
        if (line[0] == 'q') {
565
 
            global.quit_flag = PJ_TRUE;
566
 
        } else if (line[0] == 'd') {
567
 
            pj_bool_t detail = (line[1] == 'd');
568
 
            pjsip_endpt_dump(global.endpt, detail);
569
 
            pjsip_tsx_layer_dump(detail);
570
 
        }
571
 
    }
572
 
 
573
 
    pj_thread_join(global.thread);
574
 
 
575
 
#else
576
 
    puts("\nPress Ctrl-C to quit\n");
577
 
    for (;;) {
578
 
        pj_time_val delay = {0, 0};
579
 
        pjsip_endpt_handle_events(global.endpt, &delay);
580
 
    }
581
 
#endif
582
 
 
583
 
    destroy_stack();
584
 
 
585
 
    return 0;
586
 
}