/*
* $Id: tm.c,v 1.118.2.1 2005/02/16 23:24:14 bogdan Exp $
*
* TM module
*
*
* ***************************************************
* * Jiri's Source Memorial *
* * *
* * Welcome, pilgrim ! This is the greatest place *
* * where dramatic changes happend. There are not *
* * many places with a history like this, as there *
* * are not so many people like Jiri, one of the *
* * ser's fathers, who brought everywhere the wind *
* * of change, the flood of clean-up. We all felt *
* * his fatherly eye watching over us day and night.*
* * *
* * Please, preserve this codework heritage, as *
* * it's unlikely for fresh, juicy pieces of code to *
* * arise to give him the again the chance to *
* * demonstrate his clean-up and improvement skills.*
* * *
* * Hereby, we solicit you to adopt this historical *
* * piece of code. For $100, your name will be *
* * be printed in this banner and we will use *
* * collected funds to create and display an ASCII *
* * statue of Jiri . *
* ***************************************************
*
*
* Copyright (C) 2001-2003 FhG Fokus
*
* This file is part of ser, a free SIP server.
*
* ser 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
*
* For a license to use the ser software under conditions
* other than those described here, or to purchase support for this
* software, please contact iptel.org by e-mail at the following addresses:
* info@iptel.org
*
* ser 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
*/
/*
* History:
* --------
* 2003-02-18 added t_forward_nonack_{udp, tcp}, t_relay_to_{udp,tcp},
* t_replicate_{udp, tcp} (andrei)
* 2003-02-19 added t_rely_{udp, tcp} (andrei)
* 2003-03-06 voicemail changes accepted (jiri)
* 2003-03-10 module export interface updated to the new format (andrei)
* 2003-03-16 flags export parameter added (janakj)
* 2003-03-19 replaced all mallocs/frees w/ pkg_malloc/pkg_free (andrei)
* 2003-03-30 set_kr for requests only (jiri)
* 2003-04-05 s/reply_route/failure_route, onreply_route introduced (jiri)
* 2003-04-14 use protocol from uri (jiri)
* 2003-07-07 added t_relay_to_tls, t_replicate_tls, t_forward_nonack_tls
* added #ifdef USE_TCP, USE_TLS
* removed t_relay_{udp,tcp,tls} (andrei)
* 2003-09-26 added t_forward_nonack_uri() - same as t_forward_nonack() but
* takes no parameters -> forwards to uri (bogdan)
* 2004-02-11 FIFO/CANCEL + alignments (hash=f(callid,cseq)) (uli+jiri)
* 2004-02-18 t_reply exported via FIFO - imported from VM (bogdan)
* 2004-10-01 added a new param.: restart_fr_on_each_reply (andrei)
*/
#include "defs.h"
#include <stdio.h>
#include <string.h>
#include <netdb.h>
#include "../../sr_module.h"
#include "../../dprint.h"
#include "../../error.h"
#include "../../ut.h"
#include "../../script_cb.h"
#include "../../fifo_server.h"
#include "../../usr_avp.h"
#include "../../mem/mem.h"
#include "../../unixsock_server.h"
#include "sip_msg.h"
#include "h_table.h"
#include "t_hooks.h"
#include "tm_load.h"
#include "ut.h"
#include "t_reply.h"
#include "uac.h"
#include "uac_fifo.h"
#include "uac_unixsock.h"
#include "t_fwd.h"
#include "t_lookup.h"
#include "t_stats.h"
#include "callid.h"
#include "t_cancel.h"
#include "t_fifo.h"
MODULE_VERSION
/* fixup functions */
static int fixup_t_send_reply(void** param, int param_no);
static int fixup_str2int( void** param, int param_no);
static int fixup_hostport2proxy(void** param, int param_no);
static int fixup_str2regexp(void** param, int param_no);
/* init functions */
static int mod_init(void);
static int child_init(int rank);
/* exported functions */
inline static int w_t_check(struct sip_msg* msg, char* str, char* str2);
inline static int w_t_reply(struct sip_msg* msg, char* str, char* str2);
inline static int w_t_release(struct sip_msg* msg, char* str, char* str2);
inline static int w_t_retransmit_reply(struct sip_msg* p_msg, char* foo,
char* bar );
inline static int w_t_newtran(struct sip_msg* p_msg, char* foo, char* bar );
inline static int w_t_relay( struct sip_msg *p_msg , char *_foo, char *_bar);
inline static int w_t_relay_to_udp( struct sip_msg *p_msg , char *proxy,
char *);
#ifdef USE_TCP
inline static int w_t_relay_to_tcp( struct sip_msg *p_msg , char *proxy,
char *);
#endif
#ifdef USE_TLS
inline static int w_t_relay_to_tls( struct sip_msg *p_msg , char *proxy,
char *);
#endif
inline static int w_t_replicate( struct sip_msg *p_msg ,
char *proxy, /* struct proxy_l *proxy expected */
char *_foo /* nothing expected */ );
inline static int w_t_replicate_udp( struct sip_msg *p_msg ,
char *proxy, /* struct proxy_l *proxy expected */
char *_foo /* nothing expected */ );
#ifdef USE_TCP
inline static int w_t_replicate_tcp( struct sip_msg *p_msg ,
char *proxy, /* struct proxy_l *proxy expected */
char *_foo /* nothing expected */ );
#endif
#ifdef USE_TLS
inline static int w_t_replicate_tls( struct sip_msg *p_msg ,
char *proxy, /* struct proxy_l *proxy expected */
char *_foo /* nothing expected */ );
#endif
inline static int w_t_forward_nonack(struct sip_msg* msg, char* str, char* );
inline static int w_t_forward_nonack_uri(struct sip_msg* msg, char* str,char*);
inline static int w_t_forward_nonack_udp(struct sip_msg* msg, char* str,char*);
#ifdef USE_TCP
inline static int w_t_forward_nonack_tcp(struct sip_msg* msg, char* str,char*);
#endif
#ifdef USE_TLS
inline static int w_t_forward_nonack_tls(struct sip_msg* msg, char* str,char*);
#endif
inline static int w_t_on_negative(struct sip_msg* msg, char *go_to, char *foo);
inline static int w_t_on_reply(struct sip_msg* msg, char *go_to, char *foo );
inline static int t_check_status(struct sip_msg* msg, char *regexp, char *foo);
static char *fr_timer_param = FR_TIMER_AVP;
static char *fr_inv_timer_param = FR_INV_TIMER_AVP;
static cmd_export_t cmds[]={
{"t_newtran", w_t_newtran, 0, 0,
REQUEST_ROUTE},
{"t_lookup_request", w_t_check, 0, 0,
REQUEST_ROUTE},
{T_REPLY, w_t_reply, 2, fixup_t_send_reply,
REQUEST_ROUTE | FAILURE_ROUTE },
{"t_retransmit_reply", w_t_retransmit_reply, 0, 0,
REQUEST_ROUTE},
{"t_release", w_t_release, 0, 0,
REQUEST_ROUTE},
{T_RELAY_TO_UDP, w_t_relay_to_udp, 2, fixup_hostport2proxy,
REQUEST_ROUTE|FAILURE_ROUTE},
#ifdef USE_TCP
{T_RELAY_TO_TCP, w_t_relay_to_tcp, 2, fixup_hostport2proxy,
REQUEST_ROUTE|FAILURE_ROUTE},
#endif
#ifdef USE_TLS
{T_RELAY_TO_TLS, w_t_relay_to_tls, 2, fixup_hostport2proxy,
REQUEST_ROUTE|FAILURE_ROUTE},
#endif
{"t_replicate", w_t_replicate, 2, fixup_hostport2proxy,
REQUEST_ROUTE},
{"t_replicate_udp", w_t_replicate_udp, 2, fixup_hostport2proxy,
REQUEST_ROUTE},
#ifdef USE_TCP
{"t_replicate_tcp", w_t_replicate_tcp, 2, fixup_hostport2proxy,
REQUEST_ROUTE},
#endif
#ifdef USE_TLS
{"t_replicate_tls", w_t_replicate_tls, 2, fixup_hostport2proxy,
REQUEST_ROUTE},
#endif
{T_RELAY, w_t_relay, 0, 0,
REQUEST_ROUTE | FAILURE_ROUTE },
{T_FORWARD_NONACK, w_t_forward_nonack, 2, fixup_hostport2proxy,
REQUEST_ROUTE},
{T_FORWARD_NONACK_URI, w_t_forward_nonack_uri, 0, 0,
REQUEST_ROUTE},
{T_FORWARD_NONACK_UDP, w_t_forward_nonack_udp, 2, fixup_hostport2proxy,
REQUEST_ROUTE},
#ifdef USE_TCP
{T_FORWARD_NONACK_TCP, w_t_forward_nonack_tcp, 2, fixup_hostport2proxy,
REQUEST_ROUTE},
#endif
#ifdef USE_TLS
{T_FORWARD_NONACK_TLS, w_t_forward_nonack_tls, 2, fixup_hostport2proxy,
REQUEST_ROUTE},
#endif
{"t_on_failure", w_t_on_negative, 1, fixup_str2int,
REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE },
{"t_on_reply", w_t_on_reply, 1, fixup_str2int,
REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE },
{"t_check_status", t_check_status, 1, fixup_str2regexp,
REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE },
{"t_write_req", t_write_req, 2, fixup_t_write,
REQUEST_ROUTE | FAILURE_ROUTE },
{"t_write_unix", t_write_unix, 2, fixup_t_write,
REQUEST_ROUTE | FAILURE_ROUTE },
/* not applicable from the script */
{"register_tmcb", (cmd_function)register_tmcb, NO_SCRIPT, 0, 0},
{"load_tm", (cmd_function)load_tm, NO_SCRIPT, 0, 0},
{T_REPLY_WB, (cmd_function)t_reply_with_body, NO_SCRIPT, 0, 0},
{T_IS_LOCAL, (cmd_function)t_is_local, NO_SCRIPT, 0, 0},
{T_GET_TI, (cmd_function)t_get_trans_ident, NO_SCRIPT, 0, 0},
{T_LOOKUP_IDENT, (cmd_function)t_lookup_ident, NO_SCRIPT, 0, 0},
{T_ADDBLIND, (cmd_function)add_blind_uac, NO_SCRIPT, 0, 0},
{"t_request_within", (cmd_function)req_within, NO_SCRIPT, 0, 0},
{"t_request_outside", (cmd_function)req_outside, NO_SCRIPT, 0, 0},
{"t_request", (cmd_function)request, NO_SCRIPT, 0, 0},
{"new_dlg_uac", (cmd_function)new_dlg_uac, NO_SCRIPT, 0, 0},
{"dlg_response_uac", (cmd_function)dlg_response_uac, NO_SCRIPT, 0, 0},
{"new_dlg_uas", (cmd_function)new_dlg_uas, NO_SCRIPT, 0, 0},
{"dlg_request_uas", (cmd_function)dlg_request_uas, NO_SCRIPT, 0, 0},
{"free_dlg", (cmd_function)free_dlg, NO_SCRIPT, 0, 0},
{"print_dlg", (cmd_function)print_dlg, NO_SCRIPT, 0, 0},
{T_GETT, (cmd_function)get_t, NO_SCRIPT, 0,0},
{0,0,0,0,0}
};
static param_export_t params[]={
{"ruri_matching", INT_PARAM, &ruri_matching },
{"via1_matching", INT_PARAM, &via1_matching },
{"fr_timer", INT_PARAM, &(timer_id2timeout[FR_TIMER_LIST]) },
{"fr_inv_timer", INT_PARAM, &(timer_id2timeout[FR_INV_TIMER_LIST])},
{"wt_timer", INT_PARAM, &(timer_id2timeout[WT_TIMER_LIST]) },
{"delete_timer", INT_PARAM, &(timer_id2timeout[DELETE_LIST]) },
{"retr_timer1p1", INT_PARAM, &(timer_id2timeout[RT_T1_TO_1]) },
{"retr_timer1p2", INT_PARAM, &(timer_id2timeout[RT_T1_TO_2]) },
{"retr_timer1p3", INT_PARAM, &(timer_id2timeout[RT_T1_TO_3]) },
{"retr_timer2", INT_PARAM, &(timer_id2timeout[RT_T2]) },
{"noisy_ctimer", INT_PARAM, &noisy_ctimer },
{"uac_from", STR_PARAM, &uac_from },
{"unix_tx_timeout", INT_PARAM, &tm_unix_tx_timeout },
{"restart_fr_on_each_reply", INT_PARAM, &restart_fr_on_each_reply },
{"fr_timer_avp", STR_PARAM, &fr_timer_param },
{"fr_inv_timer_avp", STR_PARAM, &fr_inv_timer_param },
{"tw_append", STR_PARAM|USE_FUNC_PARAM, (void*)parse_tw_append },
{0,0,0}
};
#ifdef STATIC_TM
struct module_exports tm_exports = {
#else
struct module_exports exports= {
#endif
"tm",
/* -------- exported functions ----------- */
cmds,
/* ------------ exported variables ---------- */
params,
mod_init, /* module initialization function */
(response_function) reply_received,
(destroy_function) tm_shutdown,
0, /* w_onbreak, */
child_init /* per-child init function */
};
/**************************** fixup functions ******************************/
static int fixup_str2int( void** param, int param_no)
{
unsigned long go_to;
int err;
if (param_no==1) {
go_to=str2s(*param, strlen(*param), &err );
if (err==0) {
pkg_free(*param);
*param=(void *)go_to;
return 0;
} else {
LOG(L_ERR, "ERROR: fixup_str2int: bad number <%s>\n",
(char *)(*param));
return E_CFG;
}
}
return 0;
}
/* (char *hostname, char *port_nr) ==> (struct proxy_l *, -) */
static int fixup_hostport2proxy(void** param, int param_no)
{
unsigned int port;
char *host;
int err;
struct proxy_l *proxy;
str s;
DBG("TM module: fixup_hostport2proxy(%s, %d)\n", (char*)*param, param_no);
if (param_no==1){
DBG("TM module: fixup_hostport2proxy: param 1.. do nothing, wait for #2\n");
return 0;
} else if (param_no==2) {
host=(char *) (*(param-1));
port=str2s(*param, strlen(*param), &err);
if (err!=0) {
LOG(L_ERR, "TM module:fixup_hostport2proxy: bad port number <%s>\n",
(char*)(*param));
return E_UNSPEC;
}
s.s = host;
s.len = strlen(host);
proxy=mk_proxy(&s, port, 0); /* FIXME: udp or tcp? */
if (proxy==0) {
LOG(L_ERR, "ERROR: fixup_hostport2proxy: bad host name in URI <%s>\n",
host );
return E_BAD_ADDRESS;
}
/* success -- fix the first parameter to proxy now ! */
/* FIXME: janakj, mk_proxy doesn't make copy of host !! */
/*pkg_free( *(param-1)); you're right --andrei*/
*(param-1)=proxy;
return 0;
} else {
LOG(L_ERR,"ERROR: fixup_hostport2proxy called with parameter #<>{1,2}\n");
return E_BUG;
}
}
/* (char *code, char *reason_phrase)==>(int code, r_p as is) */
static int fixup_t_send_reply(void** param, int param_no)
{
unsigned long code;
int err;
if (param_no==1){
code=str2s(*param, strlen(*param), &err);
if (err==0){
pkg_free(*param);
*param=(void*)code;
return 0;
}else{
LOG(L_ERR, "TM module:fixup_t_send_reply: bad number <%s>\n",
(char*)(*param));
return E_UNSPEC;
}
}
/* second param => no conversion*/
return 0;
}
static int fixup_str2regexp(void** param, int param_no)
{
regex_t* re;
if (param_no==1) {
if ((re=pkg_malloc(sizeof(regex_t)))==0)
return E_OUT_OF_MEM;
if (regcomp(re, *param, REG_EXTENDED|REG_ICASE|REG_NEWLINE) ) {
pkg_free(re);
LOG(L_ERR,"ERROR: %s : bad re %s\n", exports.name, (char*)*param);
return E_BAD_RE;
}
/* free string */
pkg_free(*param);
/* replace it with the compiled re */
*param=re;
} else {
LOG(L_ERR,"ERROR: fixup_str2regexp called with parameter != 1\n");
return E_BUG;
}
return 0;
}
/***************************** init functions *****************************/
static int w_t_unref( struct sip_msg *foo, void *bar)
{
return t_unref(foo);
}
static int script_init( struct sip_msg *foo, void *bar)
{
/* we primarily reset all private memory here to make sure
* private values left over from previous message will
* not be used again */
if (foo->first_line.type==SIP_REQUEST){
/* make sure the new message will not inherit previous
message's t_on_negative value
*/
t_on_negative( 0 );
t_on_reply(0);
/* reset the kr status */
set_kr(0);
/* set request mode so that multiple-mode actions know
* how to behave */
rmode=MODE_REQUEST;
}
return 1;
}
static int mod_init(void)
{
DBG( "TM - (size of cell=%ld, sip_msg=%ld) initializing...\n",
(long)sizeof(struct cell), (long)sizeof(struct sip_msg));
/* checking if we have sufficient bitmap capacity for given
maximum number of branches */
if (MAX_BRANCHES+1>31) {
LOG(L_CRIT, "Too many max UACs for UAC branch_bm_t bitmap: %d\n",
MAX_BRANCHES );
return -1;
}
if (init_callid() < 0) {
LOG(L_CRIT, "Error while initializing Call-ID generator\n");
return -1;
}
if (register_fifo_cmd(fifo_uac, "t_uac_dlg", 0) < 0) {
LOG(L_CRIT, "cannot register fifo t_uac\n");
return -1;
}
if (register_fifo_cmd(fifo_uac_cancel, "t_uac_cancel", 0) < 0) {
LOG(L_CRIT, "cannot register fifo t_uac_cancel\n");
return -1;
}
if (register_fifo_cmd(fifo_hash, "t_hash", 0)<0) {
LOG(L_CRIT, "cannot register hash\n");
return -1;
}
if (register_fifo_cmd(fifo_t_reply, "t_reply", 0)<0) {
LOG(L_CRIT, "cannot register t_reply\n");
return -1;
}
if (unixsock_register_cmd("t_uac_dlg", unixsock_uac) < 0) {
LOG(L_CRIT, "cannot register t_uac with the unix server\n");
return -1;
}
if (unixsock_register_cmd("t_uac_cancel", unixsock_uac_cancel) < 0) {
LOG(L_CRIT, "cannot register t_uac_cancel with the unix server\n");
return -1;
}
if (unixsock_register_cmd("t_hash", unixsock_hash) < 0) {
LOG(L_CRIT, "cannot register t_hash with the unix server\n");
return -1;
}
if (unixsock_register_cmd("t_reply", unixsock_t_reply) < 0) {
LOG(L_CRIT, "cannot register t_reply with the unix server\n");
return -1;
}
/* building the hash table*/
if (!init_hash_table()) {
LOG(L_ERR, "ERROR: mod_init: initializing hash_table failed\n");
return -1;
}
/* init static hidden values */
init_t();
if (!tm_init_timers()) {
LOG(L_ERR, "ERROR: mod_init: timer init failed\n");
return -1;
}
/* register the timer function */
register_timer( timer_routine , 0 /* empty attr */, 1 );
/* init_tm_stats calls process_count, which should
* NOT be called from mod_init, because one does not
* now, if a timer is used and thus how many processes
* will be started; however we started already our
* timers, so we know and process_count should not
* change any more
*/
if (init_tm_stats()<0) {
LOG(L_CRIT, "ERROR: mod_init: failed to init stats\n");
return -1;
}
if (uac_init()==-1) {
LOG(L_ERR, "ERROR: mod_init: uac_init failed\n");
return -1;
}
if (init_tmcb_lists()!=1) {
LOG(L_CRIT, "ERROR:tm:mod_init: failed to init tmcb lists\n");
return -1;
}
tm_init_tags();
init_twrite_lines();
if (init_twrite_sock() < 0) {
LOG(L_ERR, "ERROR:tm:mod_init: Unable to create socket\n");
return -1;
}
/* register post-script clean-up function */
register_script_cb( w_t_unref, POST_SCRIPT_CB,
0 /* empty param */ );
register_script_cb( script_init, PRE_SCRIPT_CB ,
0 /* empty param */ );
if (init_avp_params( fr_timer_param, fr_inv_timer_param)<0 ){
LOG(L_ERR,"ERROR:tm:mod_init: failed to process timer AVPs\n");
return -1;
}
return 0;
}
static int child_init(int rank) {
if (child_init_callid(rank) < 0) {
LOG(L_ERR, "ERROR: child_init: Error while initializing Call-ID generator\n");
return -2;
}
return 0;
}
/**************************** wrapper functions ***************************/
static int t_check_status(struct sip_msg* msg, char *regexp, char *foo)
{
regmatch_t pmatch;
struct cell *t;
char *status;
char backup;
int lowest_status;
int n;
/* first get the transaction */
if (t_check( msg , 0 )==-1) return -1;
if ( (t=get_t())==0) {
LOG(L_ERR, "ERROR: t_check_status: cannot check status for a reply "
"which has no T-state established\n");
return -1;
}
backup = 0;
switch (rmode) {
case MODE_REQUEST:
/* use the status of the last sent reply */
status = int2str( t->uas.status, 0);
break;
case MODE_ONREPLY:
/* use the status of the current reply */
status = msg->first_line.u.reply.status.s;
backup = status[msg->first_line.u.reply.status.len];
status[msg->first_line.u.reply.status.len] = 0;
break;
case MODE_ONFAILURE:
/* use the status of the winning reply */
if (t_pick_branch( -1, 0, t, &lowest_status)<0 ) {
LOG(L_CRIT,"BUG:t_check_status: t_pick_branch failed to get "
" a final response in MODE_ONFAILURE\n");
return -1;
}
status = int2str( lowest_status , 0);
break;
default:
LOG(L_ERR,"ERROR:t_check_status: unsupported mode %d\n",rmode);
return -1;
}
DBG("DEBUG:t_check_status: checked status is <%s>\n",status);
/* do the checking */
n = regexec((regex_t*)regexp, status, 1, &pmatch, 0);
if (backup) status[msg->first_line.u.reply.status.len] = backup;
if (n!=0) return -1;
return 1;
}
inline static int w_t_check(struct sip_msg* msg, char* str, char* str2)
{
return t_check( msg , 0 ) ? 1 : -1;
}
inline static int _w_t_forward_nonack(struct sip_msg* msg, char* proxy,
int proto)
{
struct cell *t;
if (t_check( msg , 0 )==-1) {
LOG(L_ERR, "ERROR: forward_nonack: "
"can't forward when no transaction was set up\n");
return -1;
}
t=get_t();
if ( t && t!=T_UNDEFINED ) {
if (msg->REQ_METHOD==METHOD_ACK) {
LOG(L_WARN,"WARNING: you don't really want to fwd hbh ACK\n");
return -1;
}
return t_forward_nonack(t, msg, ( struct proxy_l *) proxy, proto );
} else {
DBG("DEBUG: forward_nonack: no transaction found\n");
return -1;
}
}
inline static int w_t_forward_nonack( struct sip_msg* msg, char* proxy,
char* foo)
{
return _w_t_forward_nonack(msg, proxy, PROTO_NONE);
}
inline static int w_t_forward_nonack_uri(struct sip_msg* msg, char *foo,
char *bar)
{
return _w_t_forward_nonack(msg, 0, PROTO_NONE);
}
inline static int w_t_forward_nonack_udp( struct sip_msg* msg, char* proxy,
char* foo)
{
return _w_t_forward_nonack(msg, proxy, PROTO_UDP);
}
#ifdef USE_TCP
inline static int w_t_forward_nonack_tcp( struct sip_msg* msg, char* proxy,
char* foo)
{
return _w_t_forward_nonack(msg, proxy, PROTO_TCP);
}
#endif
#ifdef USE_TLS
inline static int w_t_forward_nonack_tls( struct sip_msg* msg, char* proxy,
char* foo)
{
return _w_t_forward_nonack(msg, proxy, PROTO_TLS);
}
#endif
inline static int w_t_reply(struct sip_msg* msg, char* str, char* str2)
{
struct cell *t;
if (msg->REQ_METHOD==METHOD_ACK) {
LOG(L_WARN, "WARNING: t_reply: ACKs are not replied\n");
return -1;
}
if (t_check( msg , 0 )==-1) return -1;
t=get_t();
if (!t) {
LOG(L_ERR, "ERROR: t_reply: cannot send a t_reply to a message "
"for which no T-state has been established\n");
return -1;
}
/* if called from reply_route, make sure that unsafe version
* is called; we are already in a mutex and another mutex in
* the safe version would lead to a deadlock
*/
if (rmode==MODE_ONFAILURE) {
DBG("DEBUG: t_reply_unsafe called from w_t_reply\n");
return t_reply_unsafe(t, msg, (unsigned int)(long) str, str2);
} else if (rmode==MODE_REQUEST) {
return t_reply( t, msg, (unsigned int)(long) str, str2);
} else {
LOG(L_CRIT, "BUG: w_t_reply entered in unsupported mode\n");
return -1;
}
}
inline static int w_t_release(struct sip_msg* msg, char* str, char* str2)
{
struct cell *t;
if (t_check( msg , 0 )==-1) return -1;
t=get_t();
if ( t && t!=T_UNDEFINED )
return t_release_transaction( t );
return 1;
}
inline static int w_t_retransmit_reply( struct sip_msg* p_msg, char* foo, char* bar)
{
struct cell *t;
if (t_check( p_msg , 0 )==-1)
return 1;
t=get_t();
if (t) {
if (p_msg->REQ_METHOD==METHOD_ACK) {
LOG(L_WARN, "WARNING: : ACKs transmit_replies not replied\n");
return -1;
}
return t_retransmit_reply( t );
} else
return -1;
}
inline static int w_t_newtran( struct sip_msg* p_msg, char* foo, char* bar )
{
/* t_newtran returns 0 on error (negative value means
'transaction exists' */
return t_newtran( p_msg );
}
inline static int w_t_on_negative( struct sip_msg* msg, char *go_to, char *foo)
{
t_on_negative( (unsigned int )(long) go_to );
return 1;
}
inline static int w_t_on_reply( struct sip_msg* msg, char *go_to, char *foo )
{
t_on_reply( (unsigned int )(long) go_to );
return 1;
}
inline static int _w_t_relay_to( struct sip_msg *p_msg ,
struct proxy_l *proxy )
{
struct cell *t;
if (rmode==MODE_ONFAILURE) {
t=get_t();
if (!t || t==T_UNDEFINED) {
LOG(L_CRIT, "BUG: w_t_relay_to: undefined T\n");
return -1;
}
if (t_forward_nonack(t, p_msg, proxy, PROTO_NONE)<=0 ) {
LOG(L_ERR, "ERROR: w_t_relay_to: t_relay_to failed\n");
return -1;
}
return 1;
}
if (rmode==MODE_REQUEST)
return t_relay_to( p_msg, proxy, PROTO_NONE,
0 /* no replication */ );
LOG(L_CRIT, "ERROR: w_t_relay_to: unsupported mode: %d\n", rmode);
return 0;
}
inline static int w_t_relay_to_udp( struct sip_msg *p_msg ,
char *proxy, /* struct proxy_l *proxy expected */
char *_foo /* nothing expected */ )
{
((struct proxy_l *)proxy)->proto=PROTO_UDP;
return _w_t_relay_to( p_msg, ( struct proxy_l *) proxy);
}
#ifdef USE_TCP
inline static int w_t_relay_to_tcp( struct sip_msg *p_msg ,
char *proxy, /* struct proxy_l *proxy expected */
char *_foo /* nothing expected */ )
{
((struct proxy_l *)proxy)->proto=PROTO_TCP;
return _w_t_relay_to( p_msg, ( struct proxy_l *) proxy);
}
#endif
#ifdef USE_TLS
inline static int w_t_relay_to_tls( struct sip_msg *p_msg ,
char *proxy, /* struct proxy_l *proxy expected */
char *_foo /* nothing expected */ )
{
((struct proxy_l *)proxy)->proto=PROTO_TLS;
return _w_t_relay_to( p_msg, ( struct proxy_l *) proxy);
}
#endif
inline static int w_t_replicate( struct sip_msg *p_msg ,
char *proxy, /* struct proxy_l *proxy expected */
char *_foo /* nothing expected */ )
{
return t_replicate(p_msg, ( struct proxy_l *) proxy, p_msg->rcv.proto );
}
inline static int w_t_replicate_udp( struct sip_msg *p_msg ,
char *proxy, /* struct proxy_l *proxy expected */
char *_foo /* nothing expected */ )
{
return t_replicate(p_msg, ( struct proxy_l *) proxy, PROTO_UDP );
}
#ifdef USE_TCP
inline static int w_t_replicate_tcp( struct sip_msg *p_msg ,
char *proxy, /* struct proxy_l *proxy expected */
char *_foo /* nothing expected */ )
{
return t_replicate(p_msg, ( struct proxy_l *) proxy, PROTO_TCP );
}
#endif
#ifdef USE_TLS
inline static int w_t_replicate_tls( struct sip_msg *p_msg ,
char *proxy, /* struct proxy_l *proxy expected */
char *_foo /* nothing expected */ )
{
return t_replicate(p_msg, ( struct proxy_l *) proxy, PROTO_TLS );
}
#endif
inline static int w_t_relay( struct sip_msg *p_msg ,
char *_foo, char *_bar)
{
struct cell *t;
if (rmode==MODE_ONFAILURE) {
t=get_t();
if (!t || t==T_UNDEFINED) {
LOG(L_CRIT, "BUG: w_t_relay: undefined T\n");
return -1;
}
if (t_forward_nonack(t, p_msg, ( struct proxy_l *) 0, PROTO_NONE)<=0) {
LOG(L_ERR, "ERROR: w_t_relay (failure mode): forwarding failed\n");
return -1;
}
return 1;
}
if (rmode==MODE_REQUEST)
return t_relay_to( p_msg,
(struct proxy_l *) 0 /* no proxy */, PROTO_NONE,
0 /* no replication */ );
LOG(L_CRIT, "ERROR: w_t_relay_to: unsupported mode: %d\n", rmode);
return 0;
}
syntax highlighted by Code2HTML, v. 0.9.1