📄 sip_xfer.c
字号:
/* $Id: sip_xfer.c 974 2007-02-19 01:13:53Z bennylp $ */
/*
* Copyright (C) 2003-2007 Benny Prijono <benny@prijono.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <pjsip-ua/sip_xfer.h>
#include <pjsip-simple/evsub_msg.h>
#include <pjsip/sip_dialog.h>
#include <pjsip/sip_errno.h>
#include <pjsip/sip_endpoint.h>
#include <pjsip/sip_module.h>
#include <pjsip/sip_transport.h>
#include <pj/assert.h>
#include <pj/pool.h>
#include <pj/string.h>
/*
* Refer module (mod-refer)
*/
static struct pjsip_module mod_xfer =
{
NULL, NULL, /* prev, next. */
{ "mod-refer", 9 }, /* Name. */
-1, /* Id */
PJSIP_MOD_PRIORITY_DIALOG_USAGE, /* Priority */
NULL, /* load() */
NULL, /* start() */
NULL, /* stop() */
NULL, /* unload() */
NULL, /* on_rx_request() */
NULL, /* on_rx_response() */
NULL, /* on_tx_request. */
NULL, /* on_tx_response() */
NULL, /* on_tsx_state() */
};
/* Declare PJSIP_REFER_METHOD, so that if somebody declares this in
* sip_msg.h we can catch the error here.
*/
enum
{
PJSIP_REFER_METHOD = PJSIP_OTHER_METHOD
};
const pjsip_method pjsip_refer_method = {
PJSIP_REFER_METHOD,
{ "REFER", 5}
};
/*
* String constants
*/
const pj_str_t STR_REFER = { "refer", 5 };
const pj_str_t STR_MESSAGE = { "message", 7 };
const pj_str_t STR_SIPFRAG = { "sipfrag", 7 };
const pj_str_t STR_SIPFRAG_VERSION = {";version=2.0", 12 };
/*
* Transfer struct.
*/
struct pjsip_xfer
{
pjsip_evsub *sub; /**< Event subscribtion record. */
pjsip_dialog *dlg; /**< The dialog. */
pjsip_evsub_user user_cb; /**< The user callback. */
pj_str_t refer_to_uri; /**< The full Refer-To URI. */
int last_st_code; /**< st_code sent in last NOTIFY */
pj_str_t last_st_text; /**< st_text sent in last NOTIFY */
};
typedef struct pjsip_xfer pjsip_xfer;
/*
* Forward decl for evsub callback.
*/
static void xfer_on_evsub_state( pjsip_evsub *sub, pjsip_event *event);
static void xfer_on_evsub_tsx_state( pjsip_evsub *sub, pjsip_transaction *tsx,
pjsip_event *event);
static void xfer_on_evsub_rx_refresh( pjsip_evsub *sub,
pjsip_rx_data *rdata,
int *p_st_code,
pj_str_t **p_st_text,
pjsip_hdr *res_hdr,
pjsip_msg_body **p_body);
static void xfer_on_evsub_rx_notify( pjsip_evsub *sub,
pjsip_rx_data *rdata,
int *p_st_code,
pj_str_t **p_st_text,
pjsip_hdr *res_hdr,
pjsip_msg_body **p_body);
static void xfer_on_evsub_client_refresh(pjsip_evsub *sub);
static void xfer_on_evsub_server_timeout(pjsip_evsub *sub);
/*
* Event subscription callback for xference.
*/
static pjsip_evsub_user xfer_user =
{
&xfer_on_evsub_state,
&xfer_on_evsub_tsx_state,
&xfer_on_evsub_rx_refresh,
&xfer_on_evsub_rx_notify,
&xfer_on_evsub_client_refresh,
&xfer_on_evsub_server_timeout,
};
/*
* Initialize the REFER subsystem.
*/
PJ_DEF(pj_status_t) pjsip_xfer_init_module(pjsip_endpoint *endpt)
{
const pj_str_t accept = { "message/sipfrag;version=2.0", 27 };
pj_status_t status;
PJ_ASSERT_RETURN(endpt != NULL, PJ_EINVAL);
PJ_ASSERT_RETURN(mod_xfer.id == -1, PJ_EINVALIDOP);
status = pjsip_endpt_register_module(endpt, &mod_xfer);
if (status != PJ_SUCCESS)
return status;
status = pjsip_endpt_add_capability( endpt, &mod_xfer, PJSIP_H_ALLOW,
NULL, 1, &pjsip_refer_method.name);
if (status != PJ_SUCCESS)
return status;
status = pjsip_evsub_register_pkg( &mod_xfer, &STR_REFER, 300, 1, &accept);
if (status != PJ_SUCCESS)
return status;
return PJ_SUCCESS;
}
/*
* Create transferer (sender of REFER request).
*
*/
PJ_DEF(pj_status_t) pjsip_xfer_create_uac( pjsip_dialog *dlg,
const pjsip_evsub_user *user_cb,
pjsip_evsub **p_evsub )
{
pj_status_t status;
pjsip_xfer *xfer;
pjsip_evsub *sub;
PJ_ASSERT_RETURN(dlg && p_evsub, PJ_EINVAL);
pjsip_dlg_inc_lock(dlg);
/* Create event subscription */
status = pjsip_evsub_create_uac( dlg, &xfer_user, &STR_REFER,
PJSIP_EVSUB_NO_EVENT_ID, &sub);
if (status != PJ_SUCCESS)
goto on_return;
/* Create xfer session */
xfer = pj_pool_zalloc(dlg->pool, sizeof(pjsip_xfer));
xfer->dlg = dlg;
xfer->sub = sub;
if (user_cb)
pj_memcpy(&xfer->user_cb, user_cb, sizeof(pjsip_evsub_user));
/* Attach to evsub */
pjsip_evsub_set_mod_data(sub, mod_xfer.id, xfer);
*p_evsub = sub;
on_return:
pjsip_dlg_dec_lock(dlg);
return status;
}
/*
* Create transferee (receiver of REFER request).
*
*/
PJ_DEF(pj_status_t) pjsip_xfer_create_uas( pjsip_dialog *dlg,
const pjsip_evsub_user *user_cb,
pjsip_rx_data *rdata,
pjsip_evsub **p_evsub )
{
pjsip_evsub *sub;
pjsip_xfer *xfer;
const pj_str_t STR_EVENT = {"Event", 5 };
pjsip_event_hdr *event_hdr;
pj_status_t status;
/* Check arguments */
PJ_ASSERT_RETURN(dlg && rdata && p_evsub, PJ_EINVAL);
/* Must be request message */
PJ_ASSERT_RETURN(rdata->msg_info.msg->type == PJSIP_REQUEST_MSG,
PJSIP_ENOTREQUESTMSG);
/* Check that request is REFER */
PJ_ASSERT_RETURN(pjsip_method_cmp(&rdata->msg_info.msg->line.req.method,
&pjsip_refer_method)==0,
PJSIP_ENOTREFER);
/* Lock dialog */
pjsip_dlg_inc_lock(dlg);
/* The evsub framework expects an Event header in the request,
* while a REFER request conveniently doesn't have one (pun intended!).
* So create a dummy Event header.
*/
if (pjsip_msg_find_hdr_by_name(rdata->msg_info.msg,
&STR_EVENT, NULL)==NULL)
{
event_hdr = pjsip_event_hdr_create(rdata->tp_info.pool);
event_hdr->event_type = STR_REFER;
pjsip_msg_add_hdr(rdata->msg_info.msg, (pjsip_hdr*)event_hdr);
}
/* Create server subscription */
status = pjsip_evsub_create_uas( dlg, &xfer_user, rdata,
PJSIP_EVSUB_NO_EVENT_ID, &sub);
if (status != PJ_SUCCESS)
goto on_return;
/* Create server xfer subscription */
xfer = pj_pool_zalloc(dlg->pool, sizeof(pjsip_xfer));
xfer->dlg = dlg;
xfer->sub = sub;
if (user_cb)
pj_memcpy(&xfer->user_cb, user_cb, sizeof(pjsip_evsub_user));
/* Attach to evsub */
pjsip_evsub_set_mod_data(sub, mod_xfer.id, xfer);
/* Done: */
*p_evsub = sub;
on_return:
pjsip_dlg_dec_lock(dlg);
return status;
}
/*
* Call this function to create request to initiate REFER subscription.
*
*/
PJ_DEF(pj_status_t) pjsip_xfer_initiate( pjsip_evsub *sub,
const pj_str_t *refer_to_uri,
pjsip_tx_data **p_tdata)
{
pjsip_xfer *xfer;
const pj_str_t refer_to = { "Refer-To", 8};
pjsip_tx_data *tdata;
pjsip_generic_string_hdr *hdr;
pj_status_t status;
/* sub and p_tdata argument must be valid. */
PJ_ASSERT_RETURN(sub && p_tdata, PJ_EINVAL);
/* Get the xfer object. */
xfer = pjsip_evsub_get_mod_data(sub, mod_xfer.id);
PJ_ASSERT_RETURN(xfer != NULL, PJSIP_ENOREFERSESSION);
/* refer_to_uri argument MAY be NULL for subsequent REFER requests,
* but it MUST be specified in the first REFER.
*/
PJ_ASSERT_RETURN((refer_to_uri || xfer->refer_to_uri.slen), PJ_EINVAL);
/* Lock dialog. */
pjsip_dlg_inc_lock(xfer->dlg);
/* Create basic REFER request */
status = pjsip_evsub_initiate(sub, &pjsip_refer_method, -1,
&tdata);
if (status != PJ_SUCCESS)
goto on_return;
/* Save Refer-To URI. */
if (refer_to_uri == NULL) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -