src/modules/topos/topos_mod.c
68717c2a
 /**
  * Copyright (C) 2016 Daniel-Constantin Mierla (asipto.com)
  *
  * This file is part of Kamailio, a free SIP server.
  *
  * This file 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 file 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
 /*!
  * \file
  * \brief Kamailio topos :: Module interface
  * \ingroup topos
  * Module: \ref topos
  */
 
5a3bce67
 /*! \defgroup topos Kamailio :: Topology stripping
68717c2a
  *
  * This module removes the SIP routing headers that show topology details.
  * The script interpreter gets the SIP messages with full content, so all
  * existing functionality is preserved.
5a3bce67
  * @{
68717c2a
  */
 
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
 #include <unistd.h>
 
cf83221d
 #include "../../core/sr_module.h"
 #include "../../core/events.h"
 #include "../../core/dprint.h"
 #include "../../core/tcp_options.h"
 #include "../../core/ut.h"
 #include "../../core/forward.h"
 #include "../../core/config.h"
 #include "../../core/parser/msg_parser.h"
 #include "../../core/parser/parse_uri.h"
 #include "../../core/parser/parse_to.h"
 #include "../../core/parser/parse_from.h"
ab714eb3
 #include "../../core/parser/parse_methods.h"
cf83221d
 #include "../../core/timer_proc.h"
f16c0433
 #include "../../core/fmsg.h"
 #include "../../core/onsend.h"
4eae7ee7
 #include "../../core/mod_fix.h"
f16c0433
 #include "../../core/kemi.h"
68717c2a
 
 #include "../../lib/srdb1/db.h"
525467f9
 #include "../../core/utils/sruid.h"
68717c2a
 
 #include "../../modules/sanity/api.h"
 
1a16f11f
 #include "tps_storage.h"
68717c2a
 #include "tps_msg.h"
9e6f94e0
 #include "api.h"
68717c2a
 
 MODULE_VERSION
 
 
 /* Database connection handle */
 db1_con_t* _tps_db_handle = NULL;
 /* DB functions */
56540799
 db_func_t _tpsdbf;
68717c2a
 /* sruid to get internal uid */
 sruid_t _tps_sruid;
 
 /** module parameters */
 static str _tps_db_url = str_init(DEFAULT_DB_URL);
 int _tps_param_mask_callid = 0;
 int _tps_sanity_checks = 0;
4f2a6628
 int _tps_rr_update = 0;
4fa7a93f
 str _tps_storage = str_init("db");
68717c2a
 
8502ebaf
 extern int _tps_branch_expire;
 extern int _tps_dialog_expire;
ab714eb3
 extern unsigned int _tps_methods_nocontact;
 str _tps_methods_nocontact_list = str_init("");
8502ebaf
 
becedd0b
 int _tps_clean_interval = 60;
 
40d971af
 #define TPS_EVENTRT_OUTGOING 1
 #define TPS_EVENTRT_SENDING  2
858fab6b
 #define TPS_EVENTRT_INCOMING  4
 #define TPS_EVENTRT_RECEIVING 8
 static int _tps_eventrt_mode = TPS_EVENTRT_OUTGOING | TPS_EVENTRT_SENDING
 				| TPS_EVENTRT_INCOMING | TPS_EVENTRT_RECEIVING;
f16c0433
 static int _tps_eventrt_outgoing = -1;
 static str _tps_eventrt_callback = STR_NULL;
40d971af
 static str _tps_eventrt_outgoing_name = str_init("topos:msg-outgoing");
 static int _tps_eventrt_sending = -1;
 static str _tps_eventrt_sending_name = str_init("topos:msg-sending");
858fab6b
 static int _tps_eventrt_incoming = -1;
 static str _tps_eventrt_incoming_name = str_init("topos:msg-incoming");
 static int _tps_eventrt_receiving = -1;
 static str _tps_eventrt_receiving_name = str_init("topos:msg-receiving");
 
8454dac6
 str _tps_contact_host = str_init("");
2ffc26aa
 int _tps_contact_mode = 0;
 str _tps_cparam_name = str_init("tps");
c030fc52
 
5e3f7e15
 str _tps_xavu_cfg = STR_NULL;
 str _tps_xavu_field_acontact = STR_NULL;
 str _tps_xavu_field_bcontact = STR_NULL;
 str _tps_xavu_field_contact_host = STR_NULL;
f16c0433
 
5e3f7e15
 str _tps_context_param = STR_NULL;
 str _tps_context_value = STR_NULL;
4eae7ee7
 
68717c2a
 sanity_api_t scb;
 
2407bb9b
 int tps_msg_received(sr_event_param_t *evp);
 int tps_msg_sent(sr_event_param_t *evp);
68717c2a
 
40d971af
 static int tps_execute_event_route(sip_msg_t *msg, sr_event_param_t *evp,
 		int evtype, int evidx, str *evname);
f16c0433
 
68717c2a
 /** module functions */
 /* Module init function prototype */
 static int mod_init(void);
 /* Module child-init function prototype */
 static int child_init(int rank);
 /* Module destroy function prototype */
 static void destroy(void);
 
4eae7ee7
 static int w_tps_set_context(sip_msg_t* msg, char* pctx, char* p2);
 
9e6f94e0
 int bind_topos(topos_api_t *api);
 
 static cmd_export_t cmds[]={
4eae7ee7
 	{"tps_set_context", (cmd_function)w_tps_set_context,
858fab6b
 		1, fixup_spve_null, fixup_free_spve_null,
 		ANY_ROUTE},
4eae7ee7
 
9e6f94e0
 	{"bind_topos",  (cmd_function)bind_topos,  0,
 		0, 0, 0},
 
 	{0, 0, 0, 0, 0, 0}
 };
 
68717c2a
 static param_export_t params[]={
d9c603d3
 	{"storage",		PARAM_STR, &_tps_storage},
 	{"db_url",		PARAM_STR, &_tps_db_url},
68717c2a
 	{"mask_callid",		PARAM_INT, &_tps_param_mask_callid},
 	{"sanity_checks",	PARAM_INT, &_tps_sanity_checks},
8502ebaf
 	{"branch_expire",	PARAM_INT, &_tps_branch_expire},
 	{"dialog_expire",	PARAM_INT, &_tps_dialog_expire},
becedd0b
 	{"clean_interval",	PARAM_INT, &_tps_clean_interval},
f16c0433
 	{"event_callback",	PARAM_STR, &_tps_eventrt_callback},
d9c603d3
 	{"event_mode",		PARAM_INT, &_tps_eventrt_mode},
8454dac6
 	{"contact_host",	PARAM_STR, &_tps_contact_host},
2ffc26aa
 	{"contact_mode",	PARAM_INT, &_tps_contact_mode},
 	{"cparam_name",		PARAM_STR, &_tps_cparam_name},
c030fc52
 	{"xavu_cfg",		PARAM_STR, &_tps_xavu_cfg},
 	{"xavu_field_a_contact",	PARAM_STR, &_tps_xavu_field_acontact},
 	{"xavu_field_b_contact",	PARAM_STR, &_tps_xavu_field_bcontact},
 	{"xavu_field_contact_host", PARAM_STR, &_tps_xavu_field_contact_host},
c9702415
 	{"rr_update",		PARAM_INT, &_tps_rr_update},
4eae7ee7
 	{"context",			PARAM_STR, &_tps_context_param},
ab714eb3
 	{"methods_nocontact",		PARAM_STR, &_tps_methods_nocontact_list},
 
68717c2a
 	{0,0,0}
 };
 
 
 /** module exports */
 struct module_exports exports= {
7c957bb6
 	"topos",    /* module name */
68717c2a
 	DEFAULT_DLFLAGS, /* dlopen flags */
7c957bb6
 	cmds,       /* exported  functions */
 	params,     /* exported parameters */
 	0,          /* exported rpc functions */
68717c2a
 	0,          /* exported pseudo-variables */
7c957bb6
 	0,          /* response handling function */
68717c2a
 	mod_init,   /* module initialization function */
7c957bb6
 	child_init, /* child initialization function */
 	destroy     /* destroy function */
68717c2a
 };
 
 /**
  * init module function
  */
 static int mod_init(void)
 {
40d971af
 	_tps_eventrt_outgoing = route_lookup(&event_rt, _tps_eventrt_outgoing_name.s);
f16c0433
 	if(_tps_eventrt_outgoing<0
 			|| event_rt.rlist[_tps_eventrt_outgoing]==NULL) {
 		_tps_eventrt_outgoing = -1;
 	}
40d971af
 	_tps_eventrt_sending = route_lookup(&event_rt, _tps_eventrt_sending_name.s);
 	if(_tps_eventrt_sending<0
 			|| event_rt.rlist[_tps_eventrt_sending]==NULL) {
 		_tps_eventrt_sending = -1;
 	}
858fab6b
 	_tps_eventrt_incoming = route_lookup(&event_rt, _tps_eventrt_incoming_name.s);
 	if(_tps_eventrt_incoming<0
 			|| event_rt.rlist[_tps_eventrt_incoming]==NULL) {
 		_tps_eventrt_incoming = -1;
 	}
 	_tps_eventrt_receiving = route_lookup(&event_rt, _tps_eventrt_receiving_name.s);
 	if(_tps_eventrt_receiving<0
 			|| event_rt.rlist[_tps_eventrt_receiving]==NULL) {
 		_tps_eventrt_receiving = -1;
 	}
f16c0433
 
 	if(faked_msg_init()<0) {
 		LM_ERR("failed to init fmsg\n");
 		return -1;
 	}
 
ab714eb3
 	if(_tps_methods_nocontact_list.len>0) {
 		if(parse_methods(&_tps_methods_nocontact_list, &_tps_methods_nocontact)<0) {
 			LM_ERR("failed to parse methods_nocontact parameter\n");
 			return -1;
 		}
 	}
4fa7a93f
 	if(_tps_storage.len==2 && strncmp(_tps_storage.s, "db", 2)==0) {
 		/* Find a database module */
 		if (db_bind_mod(&_tps_db_url, &_tpsdbf)) {
 			LM_ERR("unable to bind database module\n");
 			return -1;
 		}
 		if (!DB_CAPABILITY(_tpsdbf, DB_CAP_ALL)) {
 			LM_CRIT("database modules does not "
 				"provide all functions needed\n");
 			return -1;
 		}
58c1ab8f
 	} else {
 		if(_tps_storage.len!=7 && strncmp(_tps_storage.s, "redis", 5)!=0) {
 			LM_ERR("unknown storage type: %.*s\n",
 					_tps_storage.len, _tps_storage.s);
 			return -1;
 		}
68717c2a
 	}
 
 	if(_tps_sanity_checks!=0) {
 		if(sanity_load_api(&scb)<0) {
 			LM_ERR("cannot bind to sanity module\n");
 			goto error;
 		}
 	}
1a16f11f
 	if(tps_storage_lock_set_init()<0) {
 		LM_ERR("failed to initialize locks set\n");
 		return -1;
 	}
68717c2a
 
 	if(sruid_init(&_tps_sruid, '-', "tpsh", SRUID_INC)<0)
 		return -1;
 
5e3f7e15
 	if (_tps_contact_mode == 2 && (_tps_xavu_cfg.len <= 0
 				|| _tps_xavu_field_acontact.len <= 0
c030fc52
 				|| _tps_xavu_field_bcontact.len <= 0)) {
 		LM_ERR("contact_mode parameter is 2,"
 				" but a_contact or b_contact xavu fields not defined\n");
2ffc26aa
 		return -1;
 	}
c9702415
 
68717c2a
 	sr_event_register_cb(SREV_NET_DATA_IN,  tps_msg_received);
 	sr_event_register_cb(SREV_NET_DATA_OUT, tps_msg_sent);
 
 #ifdef USE_TCP
 	tcp_set_clone_rcvbuf(1);
 #endif
 
becedd0b
 	if(sr_wtimer_add(tps_storage_clean, NULL, _tps_clean_interval)<0)
 		return -1;
 
68717c2a
 	return 0;
 error:
 	return -1;
 }
 
 /**
  *
  */
 static int child_init(int rank)
 {
 	if(sruid_init(&_tps_sruid, '-', "tpsh", SRUID_INC)<0)
 		return -1;
 
 	if (rank==PROC_INIT || rank==PROC_MAIN || rank==PROC_TCP_MAIN)
 		return 0; /* do nothing for the main process */
 
4fa7a93f
 	if(_tps_storage.len==2 && strncmp(_tps_storage.s, "db", 2)==0) {
 		_tps_db_handle = _tpsdbf.init(&_tps_db_url);
 		if (!_tps_db_handle) {
 			LM_ERR("unable to connect database\n");
 			return -1;
 		}
68717c2a
 	}
 	return 0;
 
 }
 
 /**
  *
  */
 static void destroy(void)
 {
4fa7a93f
 	if(_tps_storage.len==2 && strncmp(_tps_storage.s, "db", 2)==0) {
 		if (_tps_db_handle) {
 			_tpsdbf.close(_tps_db_handle);
 			_tps_db_handle = 0;
 		}
68717c2a
 	}
1a16f11f
 	tps_storage_lock_set_destroy();
68717c2a
 }
 
4eae7ee7
 /**
  *
  */
 static int ki_tps_set_context(sip_msg_t* msg, str* ctx)
 {
 	if(ctx==NULL || ctx->len<=0) {
 		if(_tps_context_value.s) {
 			pkg_free(_tps_context_value.s);
 		}
 		_tps_context_value.s = NULL;
 		_tps_context_value.len = 0;
 		return 1;
 	}
 
 	if(_tps_context_value.len>=ctx->len) {
 		memcpy(_tps_context_value.s, ctx->s, ctx->len);
 		_tps_context_value.len = ctx->len;
 		return 1;
 	}
 
 	if(_tps_context_value.s) {
 		pkg_free(_tps_context_value.s);
 	}
 	_tps_context_value.len = 0;
 
 	_tps_context_value.s = (char*)pkg_mallocxz(ctx->len + 1);
 	if(_tps_context_value.s==NULL) {
 		PKG_MEM_ERROR;
 		return -1;
 	}
 
 	memcpy(_tps_context_value.s, ctx->s, ctx->len);
 	_tps_context_value.len = ctx->len;
 
 	return 1;
 }
 
 /**
  *
  */
 static int w_tps_set_context(sip_msg_t* msg, char* pctx, char* p2)
 {
 	str sctx = STR_NULL;
 
 	if(fixup_get_svalue(msg, (gparam_t*)pctx, &sctx)<0) {
 		LM_ERR("failed to get context parameter\n");
 		return -1;
 	}
 
 	return ki_tps_set_context(msg, &sctx);
 }
 
68717c2a
 /**
  *
  */
 int tps_prepare_msg(sip_msg_t *msg)
 {
 	if (parse_msg(msg->buf, msg->len, msg)!=0) {
 		LM_DBG("outbuf buffer parsing failed!");
 		return 1;
 	}
 
 	if(msg->first_line.type==SIP_REQUEST) {
 		if(!IS_SIP(msg)) {
 			LM_DBG("non sip request message\n");
 			return 1;
 		}
fad79564
 	} else if(msg->first_line.type==SIP_REPLY) {
 		if(!IS_SIP_REPLY(msg)) {
 			LM_DBG("non sip reply message\n");
 			return 1;
 		}
 	} else {
 		LM_DBG("unknown sip message type %d\n", msg->first_line.type);
68717c2a
 		return 1;
 	}
 
35d2d50c
 	if(parse_headers(msg, HDR_VIA2_F, 0)<0) {
 		LM_DBG("no via2 has been parsed\n");
68717c2a
 	}
 
1c7f3938
 	if(parse_headers(msg, HDR_CSEQ_F, 0)!=0 || msg->cseq==NULL) {
 		LM_ERR("cannot parse cseq header\n");
 		return -1;
 	}
 
35d2d50c
 	if (parse_headers(msg, HDR_EOH_F, 0)==-1) {
 		LM_DBG("parsing headers failed [[%.*s]]\n",
 				msg->len, msg->buf);
 		return 2;
 	}
 
68717c2a
 	if(parse_from_header(msg)<0) {
 		LM_ERR("cannot parse FROM header\n");
 		return 3;
 	}
 
 	if(parse_to_header(msg)<0 || msg->to==NULL) {
 		LM_ERR("cannot parse TO header\n");
 		return 3;
 	}
 
 	if(get_to(msg)==NULL) {
 		LM_ERR("cannot get TO header\n");
 		return 3;
 	}
 
93e40d5b
 	if(msg->via1==NULL || msg->callid==NULL) {
 		LM_ERR("mandatory headers missing - via1: %p callid: %p\n",
 				msg->via1, msg->callid);
 		return 4;
 	}
 
68717c2a
 	return 0;
 }
 
 /**
  *
  */
2407bb9b
 int tps_msg_received(sr_event_param_t *evp)
68717c2a
 {
 	sip_msg_t msg;
 	str *obuf;
 	char *nbuf = NULL;
 	int dialog;
5613130b
 	int ret;
68717c2a
 
fb777b0e
 	ki_tps_set_context(NULL, NULL);
 
2407bb9b
 	obuf = (str*)evp->data;
858fab6b
 
 	if(tps_execute_event_route(NULL, evp, TPS_EVENTRT_INCOMING,
 				_tps_eventrt_incoming, &_tps_eventrt_incoming_name)==1) {
 		return 0;
 	}
 
68717c2a
 	memset(&msg, 0, sizeof(sip_msg_t));
 	msg.buf = obuf->s;
 	msg.len = obuf->len;
 
5613130b
 	ret = 0;
68717c2a
 	if(tps_prepare_msg(&msg)!=0) {
 		goto done;
 	}
 
 	if(tps_skip_msg(&msg)) {
 		goto done;
 	}
 
858fab6b
 	if(tps_execute_event_route(&msg, evp, TPS_EVENTRT_RECEIVING,
 				_tps_eventrt_receiving, &_tps_eventrt_receiving_name)==1) {
 		goto done;
 	}
 
68717c2a
 	if(msg.first_line.type==SIP_REQUEST) {
 		if(_tps_sanity_checks!=0) {
 			if(scb.check_defaults(&msg)<1) {
 				LM_ERR("sanity checks failed\n");
 				goto done;
 			}
 		}
 		dialog = (get_to(&msg)->tag_value.len>0)?1:0;
 		if(dialog) {
 			/* dialog request */
ca4494d4
 			tps_request_received(&msg, dialog);
68717c2a
 		}
 	} else {
 		/* reply */
 		tps_response_received(&msg);
 	}
 
 	nbuf = tps_msg_update(&msg, (unsigned int*)&obuf->len);
 
5613130b
 	if(nbuf==NULL) {
 		LM_ERR("not enough pkg memory for new message\n");
 		ret = -1;
 		goto done;
 	}
68717c2a
 	if(obuf->len>=BUF_SIZE) {
 		LM_ERR("new buffer overflow (%d)\n", obuf->len);
5613130b
 		ret = -1;
 		goto done;
68717c2a
 	}
 	memcpy(obuf->s, nbuf, obuf->len);
 	obuf->s[obuf->len] = '\0';
 
 done:
 	if(nbuf!=NULL)
 		pkg_free(nbuf);
 	free_sip_msg(&msg);
5613130b
 	return ret;
68717c2a
 }
 
 /**
  *
  */
2407bb9b
 int tps_msg_sent(sr_event_param_t *evp)
68717c2a
 {
 	sip_msg_t msg;
 	str *obuf;
 	int dialog;
 	int local;
21816a11
 	str nbuf = STR_NULL;
68717c2a
 
2407bb9b
 	obuf = (str*)evp->data;
f16c0433
 
40d971af
 	if(tps_execute_event_route(NULL, evp, TPS_EVENTRT_OUTGOING,
 				_tps_eventrt_outgoing, &_tps_eventrt_outgoing_name)==1) {
f16c0433
 		return 0;
 	}
 
68717c2a
 	memset(&msg, 0, sizeof(sip_msg_t));
 	msg.buf = obuf->s;
 	msg.len = obuf->len;
 
 	if(tps_prepare_msg(&msg)!=0) {
 		goto done;
 	}
 
 	if(tps_skip_msg(&msg)) {
 		goto done;
 	}
 
40d971af
 	if(tps_execute_event_route(&msg, evp, TPS_EVENTRT_SENDING,
 				_tps_eventrt_sending, &_tps_eventrt_sending_name)==1) {
 		goto done;
 	}
 
68717c2a
 	if(msg.first_line.type==SIP_REQUEST) {
40d971af
 
 
68717c2a
 		dialog = (get_to(&msg)->tag_value.len>0)?1:0;
 
 		local = 0;
 		if(msg.via2==0) {
 			local = 1;
 		}
 
6d2312b8
 		if(local==1 && dialog==0) {
6eedbab9
 			if((get_cseq(&msg)->method_id)
 						& (METHOD_OPTIONS|METHOD_NOTIFY|METHOD_KDMQ)) {
 				/* skip local out-of-dialog requests (e.g., keepalive, dmq) */
7ff8d428
 				goto done;
 			}
6d2312b8
 		}
 
ca4494d4
 		tps_request_sent(&msg, dialog, local);
68717c2a
 	} else {
787c41c0
 		/* reply */
 		if(msg.first_line.u.reply.statuscode==100) {
 			/* nothing to do - it should be locally generated */
5613130b
 			goto done;
787c41c0
 		}
68717c2a
 		tps_response_sent(&msg);
 	}
 
21816a11
 	nbuf.s = tps_msg_update(&msg, (unsigned int*)&nbuf.len);
 	if(nbuf.s!=NULL) {
 		LM_DBG("new outbound buffer generated\n");
 		pkg_free(obuf->s);
 		obuf->s = nbuf.s;
 		obuf->len = nbuf.len;
 	} else {
 		LM_ERR("failed to generate new outbound buffer\n");
 	}
68717c2a
 
 done:
 	free_sip_msg(&msg);
 	return 0;
 }
 
83a8c977
 /**
  *
  */
 int tps_get_dialog_expire(void)
 {
 	return _tps_dialog_expire;
 }
 
 /**
  *
  */
 int tps_get_branch_expire(void)
 {
 	return _tps_branch_expire;
 }
 
f16c0433
 /**
  *
  */
40d971af
 static int tps_execute_event_route(sip_msg_t *msg, sr_event_param_t *evp,
 		int evtype, int evidx, str *evname)
f16c0433
 {
 	struct sip_msg *fmsg;
 	struct run_act_ctx ctx;
 	int rtb;
 	sr_kemi_eng_t *keng = NULL;
975a61c8
 	onsend_info_t onsnd_info = {0};
 	onsend_info_t *p_onsend_bak;
f16c0433
 
40d971af
 	if(!(_tps_eventrt_mode & evtype)) {
 		return 0;
 	}
 
975a61c8
 	p_onsend_bak = p_onsend;
 
40d971af
 	if(evidx<0) {
f16c0433
 		if(_tps_eventrt_callback.s!=NULL || _tps_eventrt_callback.len>0) {
 			keng = sr_kemi_eng_get();
 			if(keng==NULL) {
 				LM_DBG("event callback (%s) set, but no cfg engine\n",
 						_tps_eventrt_callback.s);
 				goto done;
 			}
 		}
 	}
 
40d971af
 	if(evidx<0 && keng==NULL) {
f16c0433
 		return 0;
 	}
 
40d971af
 	LM_DBG("executing event_route[topos:%.*s] (%d)\n", evname->len, evname->s,
 			evidx);
f16c0433
 	fmsg = faked_msg_next();
 
975a61c8
 	if(evp->dst) {
 		onsnd_info.to = &evp->dst->to;
 		onsnd_info.send_sock = evp->dst->send_sock;
 	}
f16c0433
 	if(msg!=NULL) {
 		onsnd_info.buf = msg->buf;
 		onsnd_info.len = msg->len;
 		onsnd_info.msg = msg;
 	} else {
 		onsnd_info.buf = fmsg->buf;
 		onsnd_info.len = fmsg->len;
 		onsnd_info.msg = fmsg;
 	}
 	p_onsend = &onsnd_info;
 
 	rtb = get_route_type();
 	set_route_type(REQUEST_ROUTE);
 	init_run_actions_ctx(&ctx);
40d971af
 	if(evidx>=0) {
 		run_top_route(event_rt.rlist[evidx], (msg)?msg:fmsg, &ctx);
f16c0433
 	} else {
 		if(keng!=NULL) {
a383027e
 			if(sr_kemi_ctx_route(keng, &ctx, (msg)?msg:fmsg, EVENT_ROUTE,
40d971af
 						&_tps_eventrt_callback, evname)<0) {
f16c0433
 				LM_ERR("error running event route kemi callback\n");
975a61c8
 				p_onsend=p_onsend_bak;
f16c0433
 				return -1;
 			}
 		}
 	}
 	set_route_type(rtb);
 	if(ctx.run_flags&DROP_R_F) {
 		LM_DBG("exit due to 'drop' in event route\n");
975a61c8
 		p_onsend=p_onsend_bak;
f16c0433
 		return 1;
 	}
 
 done:
975a61c8
 	p_onsend=p_onsend_bak;
f16c0433
 	return 0;
 }
 
9e6f94e0
 /**
  *
  */
 int bind_topos(topos_api_t *api)
 {
 	if (!api) {
 		ERR("Invalid parameter value\n");
 		return -1;
 	}
 	memset(api, 0, sizeof(topos_api_t));
 	api->set_storage_api = tps_set_storage_api;
83a8c977
 	api->get_dialog_expire = tps_get_dialog_expire;
 	api->get_branch_expire = tps_get_branch_expire;
9e6f94e0
 
 	return 0;
5a3bce67
 }
 
4eae7ee7
 /**
  *
  */
 /* clang-format off */
 static sr_kemi_t sr_kemi_topos_exports[] = {
 	{ str_init("topos"), str_init("tps_set_context"),
 		SR_KEMIP_INT, ki_tps_set_context,
 		{ SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
 
 	{ {0, 0}, {0, 0}, 0, NULL, { 0, 0, 0, 0, 0, 0 } }
 };
 /* clang-format on */
 
 /**
  *
  */
 int mod_register(char *path, int *dlflags, void *p1, void *p2)
 {
 	sr_kemi_modules_add(sr_kemi_topos_exports);
 
 	return 0;
 }
 
5a3bce67
 /** @} */