1
/* $Id: sip_xfer.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
20
#include <pjsip-ua/sip_xfer.h>
21
#include <pjsip-simple/evsub_msg.h>
22
#include <pjsip/sip_dialog.h>
23
#include <pjsip/sip_errno.h>
24
#include <pjsip/sip_endpoint.h>
25
#include <pjsip/sip_module.h>
26
#include <pjsip/sip_transport.h>
27
#include <pj/assert.h>
29
#include <pj/string.h>
31
/* Subscription expiration */
32
#ifndef PJSIP_XFER_EXPIRES
33
# define PJSIP_XFER_EXPIRES 600
38
* Refer module (mod-refer)
40
static struct pjsip_module mod_xfer =
42
NULL, NULL, /* prev, next. */
43
{ "mod-refer", 9 }, /* Name. */
45
PJSIP_MOD_PRIORITY_DIALOG_USAGE, /* Priority */
50
NULL, /* on_rx_request() */
51
NULL, /* on_rx_response() */
52
NULL, /* on_tx_request. */
53
NULL, /* on_tx_response() */
54
NULL, /* on_tsx_state() */
58
/* Declare PJSIP_REFER_METHOD, so that if somebody declares this in
59
* sip_msg.h we can catch the error here.
63
PJSIP_REFER_METHOD = PJSIP_OTHER_METHOD
66
PJ_DEF_DATA(const pjsip_method) pjsip_refer_method = {
67
(pjsip_method_e) PJSIP_REFER_METHOD,
71
PJ_DEF(const pjsip_method*) pjsip_get_refer_method()
73
return &pjsip_refer_method;
79
const pj_str_t STR_REFER = { "refer", 5 };
80
const pj_str_t STR_MESSAGE = { "message", 7 };
81
const pj_str_t STR_SIPFRAG = { "sipfrag", 7 };
82
const pj_str_t STR_SIPFRAG_VERSION = {";version=2.0", 12 };
90
pjsip_evsub *sub; /**< Event subscribtion record. */
91
pjsip_dialog *dlg; /**< The dialog. */
92
pjsip_evsub_user user_cb; /**< The user callback. */
93
pj_str_t refer_to_uri; /**< The full Refer-To URI. */
94
int last_st_code; /**< st_code sent in last NOTIFY */
95
pj_str_t last_st_text; /**< st_text sent in last NOTIFY */
99
typedef struct pjsip_xfer pjsip_xfer;
104
* Forward decl for evsub callback.
106
static void xfer_on_evsub_state( pjsip_evsub *sub, pjsip_event *event);
107
static void xfer_on_evsub_tsx_state( pjsip_evsub *sub, pjsip_transaction *tsx,
109
static void xfer_on_evsub_rx_refresh( pjsip_evsub *sub,
110
pjsip_rx_data *rdata,
112
pj_str_t **p_st_text,
114
pjsip_msg_body **p_body);
115
static void xfer_on_evsub_rx_notify( pjsip_evsub *sub,
116
pjsip_rx_data *rdata,
118
pj_str_t **p_st_text,
120
pjsip_msg_body **p_body);
121
static void xfer_on_evsub_client_refresh(pjsip_evsub *sub);
122
static void xfer_on_evsub_server_timeout(pjsip_evsub *sub);
126
* Event subscription callback for xference.
128
static pjsip_evsub_user xfer_user =
130
&xfer_on_evsub_state,
131
&xfer_on_evsub_tsx_state,
132
&xfer_on_evsub_rx_refresh,
133
&xfer_on_evsub_rx_notify,
134
&xfer_on_evsub_client_refresh,
135
&xfer_on_evsub_server_timeout,
142
* Initialize the REFER subsystem.
144
PJ_DEF(pj_status_t) pjsip_xfer_init_module(pjsip_endpoint *endpt)
146
const pj_str_t accept = { "message/sipfrag;version=2.0", 27 };
149
PJ_ASSERT_RETURN(endpt != NULL, PJ_EINVAL);
150
PJ_ASSERT_RETURN(mod_xfer.id == -1, PJ_EINVALIDOP);
152
status = pjsip_endpt_register_module(endpt, &mod_xfer);
153
if (status != PJ_SUCCESS)
156
status = pjsip_endpt_add_capability( endpt, &mod_xfer, PJSIP_H_ALLOW,
158
&pjsip_get_refer_method()->name);
159
if (status != PJ_SUCCESS)
162
status = pjsip_evsub_register_pkg(&mod_xfer, &STR_REFER,
163
PJSIP_XFER_EXPIRES, 1, &accept);
164
if (status != PJ_SUCCESS)
172
* Create transferer (sender of REFER request).
175
PJ_DEF(pj_status_t) pjsip_xfer_create_uac( pjsip_dialog *dlg,
176
const pjsip_evsub_user *user_cb,
177
pjsip_evsub **p_evsub )
183
PJ_ASSERT_RETURN(dlg && p_evsub, PJ_EINVAL);
185
pjsip_dlg_inc_lock(dlg);
187
/* Create event subscription */
188
status = pjsip_evsub_create_uac( dlg, &xfer_user, &STR_REFER,
189
PJSIP_EVSUB_NO_EVENT_ID, &sub);
190
if (status != PJ_SUCCESS)
193
/* Create xfer session */
194
xfer = PJ_POOL_ZALLOC_T(dlg->pool, pjsip_xfer);
198
pj_memcpy(&xfer->user_cb, user_cb, sizeof(pjsip_evsub_user));
200
/* Attach to evsub */
201
pjsip_evsub_set_mod_data(sub, mod_xfer.id, xfer);
206
pjsip_dlg_dec_lock(dlg);
215
* Create transferee (receiver of REFER request).
218
PJ_DEF(pj_status_t) pjsip_xfer_create_uas( pjsip_dialog *dlg,
219
const pjsip_evsub_user *user_cb,
220
pjsip_rx_data *rdata,
221
pjsip_evsub **p_evsub )
225
const pj_str_t STR_EVENT = {"Event", 5 };
226
pjsip_event_hdr *event_hdr;
229
/* Check arguments */
230
PJ_ASSERT_RETURN(dlg && rdata && p_evsub, PJ_EINVAL);
232
/* Must be request message */
233
PJ_ASSERT_RETURN(rdata->msg_info.msg->type == PJSIP_REQUEST_MSG,
234
PJSIP_ENOTREQUESTMSG);
236
/* Check that request is REFER */
237
PJ_ASSERT_RETURN(pjsip_method_cmp(&rdata->msg_info.msg->line.req.method,
238
pjsip_get_refer_method())==0,
242
pjsip_dlg_inc_lock(dlg);
244
/* The evsub framework expects an Event header in the request,
245
* while a REFER request conveniently doesn't have one (pun intended!).
246
* So create a dummy Event header.
248
if (pjsip_msg_find_hdr_by_name(rdata->msg_info.msg,
249
&STR_EVENT, NULL)==NULL)
251
event_hdr = pjsip_event_hdr_create(rdata->tp_info.pool);
252
event_hdr->event_type = STR_REFER;
253
pjsip_msg_add_hdr(rdata->msg_info.msg, (pjsip_hdr*)event_hdr);
256
/* Create server subscription */
257
status = pjsip_evsub_create_uas( dlg, &xfer_user, rdata,
258
PJSIP_EVSUB_NO_EVENT_ID, &sub);
259
if (status != PJ_SUCCESS)
262
/* Create server xfer subscription */
263
xfer = PJ_POOL_ZALLOC_T(dlg->pool, pjsip_xfer);
267
pj_memcpy(&xfer->user_cb, user_cb, sizeof(pjsip_evsub_user));
269
/* Attach to evsub */
270
pjsip_evsub_set_mod_data(sub, mod_xfer.id, xfer);
276
pjsip_dlg_dec_lock(dlg);
283
* Call this function to create request to initiate REFER subscription.
286
PJ_DEF(pj_status_t) pjsip_xfer_initiate( pjsip_evsub *sub,
287
const pj_str_t *refer_to_uri,
288
pjsip_tx_data **p_tdata)
291
const pj_str_t refer_to = { "Refer-To", 8};
292
pjsip_tx_data *tdata;
293
pjsip_generic_string_hdr *hdr;
296
/* sub and p_tdata argument must be valid. */
297
PJ_ASSERT_RETURN(sub && p_tdata, PJ_EINVAL);
300
/* Get the xfer object. */
301
xfer = (pjsip_xfer*) pjsip_evsub_get_mod_data(sub, mod_xfer.id);
302
PJ_ASSERT_RETURN(xfer != NULL, PJSIP_ENOREFERSESSION);
304
/* refer_to_uri argument MAY be NULL for subsequent REFER requests,
305
* but it MUST be specified in the first REFER.
307
PJ_ASSERT_RETURN((refer_to_uri || xfer->refer_to_uri.slen), PJ_EINVAL);
310
pjsip_dlg_inc_lock(xfer->dlg);
312
/* Create basic REFER request */
313
status = pjsip_evsub_initiate(sub, pjsip_get_refer_method(), -1,
315
if (status != PJ_SUCCESS)
318
/* Save Refer-To URI. */
319
if (refer_to_uri == NULL) {
320
refer_to_uri = &xfer->refer_to_uri;
322
pj_strdup(xfer->dlg->pool, &xfer->refer_to_uri, refer_to_uri);
325
/* Create and add Refer-To header. */
326
hdr = pjsip_generic_string_hdr_create(tdata->pool, &refer_to,
329
pjsip_tx_data_dec_ref(tdata);
334
pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)hdr);
343
pjsip_dlg_dec_lock(xfer->dlg);
349
* Accept the incoming REFER request by sending 2xx response.
352
PJ_DEF(pj_status_t) pjsip_xfer_accept( pjsip_evsub *sub,
353
pjsip_rx_data *rdata,
355
const pjsip_hdr *hdr_list )
358
* Don't need to add custom headers, so just call basic
361
return pjsip_evsub_accept( sub, rdata, st_code, hdr_list );
366
* For notifier, create NOTIFY request to subscriber, and set the state
367
* of the subscription.
369
PJ_DEF(pj_status_t) pjsip_xfer_notify( pjsip_evsub *sub,
370
pjsip_evsub_state state,
372
const pj_str_t *xfer_st_text,
373
pjsip_tx_data **p_tdata)
375
pjsip_tx_data *tdata;
378
const pj_str_t reason = { "noresource", 10 };
381
pjsip_msg_body *msg_body;
385
/* Check arguments. */
386
PJ_ASSERT_RETURN(sub, PJ_EINVAL);
388
/* Get the xfer object. */
389
xfer = (pjsip_xfer*) pjsip_evsub_get_mod_data(sub, mod_xfer.id);
390
PJ_ASSERT_RETURN(xfer != NULL, PJSIP_ENOREFERSESSION);
394
pjsip_dlg_inc_lock(xfer->dlg);
396
/* Create the NOTIFY request.
397
* Note that reason is only used when state is TERMINATED, and
398
* the defined termination reason for REFER is "noresource".
400
status = pjsip_evsub_notify( sub, state, NULL, &reason, &tdata);
401
if (status != PJ_SUCCESS)
405
/* Check status text */
406
if (xfer_st_text==NULL || xfer_st_text->slen==0)
407
xfer_st_text = pjsip_get_status_text(xfer_st_code);
409
/* Save st_code and st_text, for current_notify() */
410
xfer->last_st_code = xfer_st_code;
411
pj_strdup(xfer->dlg->pool, &xfer->last_st_text, xfer_st_text);
413
/* Create sipfrag content. */
414
body = (char*) pj_pool_alloc(tdata->pool, 128);
415
bodylen = pj_ansi_snprintf(body, 128, "SIP/2.0 %u %.*s\r\n",
417
(int)xfer_st_text->slen,
419
PJ_ASSERT_ON_FAIL(bodylen > 0 && bodylen < 128,
420
{status=PJ_EBUG; pjsip_tx_data_dec_ref(tdata);
424
/* Create SIP message body. */
425
msg_body = PJ_POOL_ZALLOC_T(tdata->pool, pjsip_msg_body);
426
pjsip_media_type_init(&msg_body->content_type, (pj_str_t*)&STR_MESSAGE,
427
(pj_str_t*)&STR_SIPFRAG);
428
msg_body->data = body;
429
msg_body->len = bodylen;
430
msg_body->print_body = &pjsip_print_text_body;
431
msg_body->clone_data = &pjsip_clone_text_data;
433
param = PJ_POOL_ALLOC_T(tdata->pool, pjsip_param);
434
param->name = pj_str("version");
435
param->value = pj_str("2.0");
436
pj_list_push_back(&msg_body->content_type.param, param);
438
/* Attach sipfrag body. */
439
tdata->msg->body = msg_body;
447
pjsip_dlg_dec_lock(xfer->dlg);
454
* Send current state and the last sipfrag body.
456
PJ_DEF(pj_status_t) pjsip_xfer_current_notify( pjsip_evsub *sub,
457
pjsip_tx_data **p_tdata )
463
/* Check arguments. */
464
PJ_ASSERT_RETURN(sub, PJ_EINVAL);
466
/* Get the xfer object. */
467
xfer = (pjsip_xfer*) pjsip_evsub_get_mod_data(sub, mod_xfer.id);
468
PJ_ASSERT_RETURN(xfer != NULL, PJSIP_ENOREFERSESSION);
470
pjsip_dlg_inc_lock(xfer->dlg);
472
status = pjsip_xfer_notify(sub, pjsip_evsub_get_state(sub),
473
xfer->last_st_code, &xfer->last_st_text,
476
pjsip_dlg_dec_lock(xfer->dlg);
483
* Send request message.
485
PJ_DEF(pj_status_t) pjsip_xfer_send_request( pjsip_evsub *sub,
486
pjsip_tx_data *tdata)
488
return pjsip_evsub_send_request(sub, tdata);
493
* This callback is called by event subscription when subscription
496
static void xfer_on_evsub_state( pjsip_evsub *sub, pjsip_event *event)
500
xfer = (pjsip_xfer*) pjsip_evsub_get_mod_data(sub, mod_xfer.id);
501
PJ_ASSERT_ON_FAIL(xfer!=NULL, {return;});
503
if (xfer->user_cb.on_evsub_state)
504
(*xfer->user_cb.on_evsub_state)(sub, event);
509
* Called when transaction state has changed.
511
static void xfer_on_evsub_tsx_state( pjsip_evsub *sub, pjsip_transaction *tsx,
516
xfer = (pjsip_xfer*) pjsip_evsub_get_mod_data(sub, mod_xfer.id);
517
PJ_ASSERT_ON_FAIL(xfer!=NULL, {return;});
519
if (xfer->user_cb.on_tsx_state)
520
(*xfer->user_cb.on_tsx_state)(sub, tsx, event);
524
* Called when REFER is received to refresh subscription.
526
static void xfer_on_evsub_rx_refresh( pjsip_evsub *sub,
527
pjsip_rx_data *rdata,
529
pj_str_t **p_st_text,
531
pjsip_msg_body **p_body)
535
xfer = (pjsip_xfer*) pjsip_evsub_get_mod_data(sub, mod_xfer.id);
536
PJ_ASSERT_ON_FAIL(xfer!=NULL, {return;});
538
if (xfer->user_cb.on_rx_refresh) {
539
(*xfer->user_cb.on_rx_refresh)(sub, rdata, p_st_code, p_st_text,
543
/* Implementors MUST send NOTIFY if it implements on_rx_refresh
544
* (implementor == "us" from evsub point of view.
546
pjsip_tx_data *tdata;
549
if (pjsip_evsub_get_state(sub)==PJSIP_EVSUB_STATE_TERMINATED) {
550
status = pjsip_xfer_notify( sub, PJSIP_EVSUB_STATE_TERMINATED,
555
status = pjsip_xfer_current_notify(sub, &tdata);
558
if (status == PJ_SUCCESS)
559
pjsip_xfer_send_request(sub, tdata);
565
* Called when NOTIFY is received.
567
static void xfer_on_evsub_rx_notify( pjsip_evsub *sub,
568
pjsip_rx_data *rdata,
570
pj_str_t **p_st_text,
572
pjsip_msg_body **p_body)
576
xfer = (pjsip_xfer*) pjsip_evsub_get_mod_data(sub, mod_xfer.id);
577
PJ_ASSERT_ON_FAIL(xfer!=NULL, {return;});
579
if (xfer->user_cb.on_rx_notify)
580
(*xfer->user_cb.on_rx_notify)(sub, rdata, p_st_code, p_st_text,
585
* Called when it's time to send SUBSCRIBE.
587
static void xfer_on_evsub_client_refresh(pjsip_evsub *sub)
591
xfer = (pjsip_xfer*) pjsip_evsub_get_mod_data(sub, mod_xfer.id);
592
PJ_ASSERT_ON_FAIL(xfer!=NULL, {return;});
594
if (xfer->user_cb.on_client_refresh) {
595
(*xfer->user_cb.on_client_refresh)(sub);
598
pjsip_tx_data *tdata;
600
status = pjsip_evsub_initiate(sub, NULL, PJSIP_XFER_EXPIRES, &tdata);
601
if (status == PJ_SUCCESS)
602
pjsip_xfer_send_request(sub, tdata);
608
* Called when no refresh is received after the interval.
610
static void xfer_on_evsub_server_timeout(pjsip_evsub *sub)
614
xfer = (pjsip_xfer*) pjsip_evsub_get_mod_data(sub, mod_xfer.id);
615
PJ_ASSERT_ON_FAIL(xfer!=NULL, {return;});
617
if (xfer->user_cb.on_server_timeout) {
618
(*xfer->user_cb.on_server_timeout)(sub);
621
pjsip_tx_data *tdata;
623
status = pjsip_xfer_notify(sub, PJSIP_EVSUB_STATE_TERMINATED,
625
&xfer->last_st_text, &tdata);
626
if (status == PJ_SUCCESS)
627
pjsip_xfer_send_request(sub, tdata);