📄 stateful_proxy.c
字号:
/* $Id: stateful_proxy.c 1123 2007-04-02 11:23:09Z 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
*/
#define THIS_FILE "stateful_proxy.c"
/* Common proxy functions */
#define STATEFUL 1
#include "proxy.h"
/*
* mod_stateful_proxy is the module to receive SIP request and
* response message that is outside any transaction context.
*/
static pj_bool_t proxy_on_rx_request(pjsip_rx_data *rdata );
static pj_bool_t proxy_on_rx_response(pjsip_rx_data *rdata );
static pjsip_module mod_stateful_proxy =
{
NULL, NULL, /* prev, next. */
{ "mod-stateful-proxy", 18 }, /* Name. */
-1, /* Id */
PJSIP_MOD_PRIORITY_UA_PROXY_LAYER, /* Priority */
NULL, /* load() */
NULL, /* start() */
NULL, /* stop() */
NULL, /* unload() */
&proxy_on_rx_request, /* on_rx_request() */
&proxy_on_rx_response, /* on_rx_response() */
NULL, /* on_tx_request. */
NULL, /* on_tx_response() */
NULL, /* on_tsx_state() */
};
/*
* mod_tu (tu=Transaction User) is the module to receive notification
* from transaction when the transaction state has changed.
*/
static void tu_on_tsx_state(pjsip_transaction *tsx, pjsip_event *event);
static pjsip_module mod_tu =
{
NULL, NULL, /* prev, next. */
{ "mod-transaction-user", 20 }, /* Name. */
-1, /* Id */
PJSIP_MOD_PRIORITY_APPLICATION, /* 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() */
&tu_on_tsx_state, /* on_tsx_state() */
};
/* This is the data that is attached to the UAC transaction */
struct uac_data
{
pjsip_transaction *uas_tsx;
pj_timer_entry timer;
};
/* This is the data that is attached to the UAS transaction */
struct uas_data
{
pjsip_transaction *uac_tsx;
};
static pj_status_t init_stateful_proxy(void)
{
pj_status_t status;
status = pjsip_endpt_register_module( global.endpt, &mod_stateful_proxy);
PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
status = pjsip_endpt_register_module( global.endpt, &mod_tu);
PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
return PJ_SUCCESS;
}
/* Callback to be called to handle new incoming requests. */
static pj_bool_t proxy_on_rx_request( pjsip_rx_data *rdata )
{
pjsip_transaction *uas_tsx, *uac_tsx;
struct uac_data *uac_data;
struct uas_data *uas_data;
pjsip_tx_data *tdata;
pj_status_t status;
if (rdata->msg_info.msg->line.req.method.id != PJSIP_CANCEL_METHOD) {
/* Verify incoming request */
status = proxy_verify_request(rdata);
if (status != PJ_SUCCESS) {
app_perror("RX invalid request", status);
return PJ_TRUE;
}
/*
* Request looks sane, next clone the request to create transmit data.
*/
status = pjsip_endpt_create_request_fwd(global.endpt, rdata, NULL,
NULL, 0, &tdata);
if (status != PJ_SUCCESS) {
pjsip_endpt_respond_stateless(global.endpt, rdata,
PJSIP_SC_INTERNAL_SERVER_ERROR,
NULL, NULL, NULL);
return PJ_TRUE;
}
/* Process routing */
status = proxy_process_routing(tdata);
if (status != PJ_SUCCESS) {
app_perror("Error processing route", status);
return PJ_TRUE;
}
/* Calculate target */
status = proxy_calculate_target(rdata, tdata);
if (status != PJ_SUCCESS) {
app_perror("Error calculating target", status);
return PJ_TRUE;
}
/* Everything is set to forward the request. */
/* If this is an ACK request, forward statelessly.
* This happens if the proxy records route and this ACK
* is sent for 2xx response. An ACK that is sent for non-2xx
* final response will be absorbed by transaction layer, and
* it will not be received by on_rx_request() callback.
*/
if (tdata->msg->line.req.method.id == PJSIP_ACK_METHOD) {
status = pjsip_endpt_send_request_stateless(global.endpt, tdata,
NULL, NULL);
if (status != PJ_SUCCESS) {
app_perror("Error forwarding request", status);
return PJ_TRUE;
}
return PJ_TRUE;
}
/* Create UAC transaction for forwarding the request.
* Set our module as the transaction user to receive further
* events from this transaction.
*/
status = pjsip_tsx_create_uac(&mod_tu, tdata, &uac_tsx);
if (status != PJ_SUCCESS) {
pjsip_tx_data_dec_ref(tdata);
pjsip_endpt_respond_stateless(global.endpt, rdata,
PJSIP_SC_INTERNAL_SERVER_ERROR,
NULL, NULL, NULL);
return PJ_TRUE;
}
/* Create UAS transaction to handle incoming request */
status = pjsip_tsx_create_uas(&mod_tu, rdata, &uas_tsx);
if (status != PJ_SUCCESS) {
pjsip_tx_data_dec_ref(tdata);
pjsip_endpt_respond_stateless(global.endpt, rdata,
PJSIP_SC_INTERNAL_SERVER_ERROR,
NULL, NULL, NULL);
pjsip_tsx_terminate(uac_tsx, PJSIP_SC_INTERNAL_SERVER_ERROR);
return PJ_TRUE;
}
/* Feed the request to the UAS transaction to drive it's state
* out of NULL state.
*/
pjsip_tsx_recv_msg(uas_tsx, rdata);
/* Attach a data to the UAC transaction, to be used to find the
* UAS transaction when we receive response in the UAC side.
*/
uac_data = (struct uac_data*)
pj_pool_alloc(uac_tsx->pool, sizeof(struct uac_data));
uac_data->uas_tsx = uas_tsx;
uac_tsx->mod_data[mod_tu.id] = (void*)uac_data;
/* Attach data to the UAS transaction, to find the UAC transaction
* when cancelling INVITE request.
*/
uas_data = (struct uas_data*)
pj_pool_alloc(uas_tsx->pool, sizeof(struct uas_data));
uas_data->uac_tsx = uac_tsx;
uas_tsx->mod_data[mod_tu.id] = (void*)uas_data;
/* Everything is setup, forward the request */
status = pjsip_tsx_send_msg(uac_tsx, tdata);
if (status != PJ_SUCCESS) {
pjsip_tx_data *err_res;
/* Fail to send request, for some reason */
/* Destroy transmit data */
pjsip_tx_data_dec_ref(tdata);
/* I think UAC transaction should have been destroyed when
* it fails to send request, so no need to destroy it.
pjsip_tsx_terminate(uac_tsx, PJSIP_SC_INTERNAL_SERVER_ERROR);
*/
/* Send 500/Internal Server Error to UAS transaction */
pjsip_endpt_create_response(global.endpt, rdata,
500, NULL, &err_res);
pjsip_tsx_send_msg(uas_tsx, err_res);
return PJ_TRUE;
}
/* Send 100/Trying if this is an INVITE */
if (rdata->msg_info.msg->line.req.method.id == PJSIP_INVITE_METHOD) {
pjsip_tx_data *res100;
pjsip_endpt_create_response(global.endpt, rdata, 100, NULL,
&res100);
pjsip_tsx_send_msg(uas_tsx, res100);
}
} else {
/* This is CANCEL request */
pjsip_transaction *invite_uas;
struct uas_data *uas_data;
pj_str_t key;
/* Find the UAS INVITE transaction */
pjsip_tsx_create_key(rdata->tp_info.pool, &key, PJSIP_UAS_ROLE,
&pjsip_invite_method, rdata);
invite_uas = pjsip_tsx_layer_find_tsx(&key, PJ_TRUE);
if (!invite_uas) {
/* Invite transaction not found, respond CANCEL with 481 */
pjsip_endpt_respond_stateless(global.endpt, rdata, 481, NULL,
NULL, NULL);
return PJ_TRUE;
}
/* Respond 200 OK to CANCEL */
pjsip_endpt_respond(global.endpt, NULL, rdata, 200, NULL, NULL,
NULL, NULL);
/* Send CANCEL to cancel the UAC transaction.
* The UAS INVITE transaction will get final response when
* we receive final response from the UAC INVITE transaction.
*/
uas_data = (struct uas_data*) invite_uas->mod_data[mod_tu.id];
if (uas_data->uac_tsx) {
pjsip_tx_data *cancel;
pj_mutex_lock(uas_data->uac_tsx->mutex);
pjsip_endpt_create_cancel(global.endpt, uas_data->uac_tsx->last_tx,
&cancel);
pjsip_endpt_send_request(global.endpt, cancel, -1, NULL, NULL);
pj_mutex_unlock(uas_data->uac_tsx->mutex);
}
/* Unlock UAS tsx because it is locked in find_tsx() */
pj_mutex_unlock(invite_uas->mutex);
}
return PJ_TRUE;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -