src/core/kemi.c
3af6fa66
 /**
  * Copyright (C) 2016 Daniel-Constantin Mierla (asipto.com)
  *
  * This file is part of Kamailio, a free SIP server.
  *
  * Kamailio 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
  *
  * Kamailio 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
  *
  */
 
 #include <stdio.h>
 #include <unistd.h>
 #include <stdlib.h>
 
 #include "dprint.h"
fb1e1d84
 #include "forward.h"
b0d8849b
 #include "locking.h"
0f54afd1
 #include "dset.h"
 #include "action.h"
ff8bb9df
 #include "data_lump.h"
 #include "data_lump_rpl.h"
0df40557
 #include "strutils.h"
6be53f64
 #include "select_buf.h"
64f744e9
 #include "pvar.h"
b84b67a0
 #include "trim.h"
b0d8849b
 #include "mem/shm.h"
fb1e1d84
 #include "parser/parse_uri.h"
03c3a04b
 #include "parser/parse_from.h"
0df40557
 #include "parser/parse_hname2.h"
aec6c31b
 #include "parser/parse_methods.h"
3af6fa66
 
 #include "kemi.h"
 
16a41dba
 
97f975fa
 #define SR_KEMI_HNAME_SIZE 128
 
77b0c935
 /* names for kemi callback functions */
b7ea6973
 str kemi_onsend_route_callback = str_init("ksr_onsend_route");
77b0c935
 str kemi_reply_route_callback = str_init("ksr_reply_route");
77beeb5d
 str kemi_event_route_callback = str_init("");
77b0c935
 
9d33196d
 /**
  *
  */
 static sr_kemi_xval_t _sr_kemi_xval = {0};
 
a6fc13d6
 /**
  *
  */
 static run_act_ctx_t *_sr_kemi_act_ctx = NULL;
 
 /**
  *
  */
 void sr_kemi_act_ctx_set(run_act_ctx_t *ctx)
 {
 	_sr_kemi_act_ctx = ctx;
 }
 
 /**
  *
  */
 run_act_ctx_t* sr_kemi_act_ctx_get(void)
 {
 	return _sr_kemi_act_ctx;
 }
 
16a41dba
 /**
  *
  */
1f8ab5a6
 static int sr_kemi_core_dbg(sip_msg_t *msg, str *txt)
16a41dba
 {
 	if(txt!=NULL && txt->s!=NULL)
 		LM_DBG("%.*s", txt->len, txt->s);
 	return 0;
 }
 
 /**
  *
  */
1f8ab5a6
 static int sr_kemi_core_err(sip_msg_t *msg, str *txt)
16a41dba
 {
 	if(txt!=NULL && txt->s!=NULL)
 		LM_ERR("%.*s", txt->len, txt->s);
 	return 0;
 }
 
 /**
  *
  */
1f8ab5a6
 static int sr_kemi_core_info(sip_msg_t *msg, str *txt)
16a41dba
 {
 	if(txt!=NULL && txt->s!=NULL)
 		LM_INFO("%.*s", txt->len, txt->s);
 	return 0;
 }
 
f854f2c2
 /**
  *
  */
 static int sr_kemi_core_warn(sip_msg_t *msg, str *txt)
 {
 	if(txt!=NULL && txt->s!=NULL)
 		LM_WARN("%.*s", txt->len, txt->s);
 	return 0;
 }
 
 /**
  *
  */
 static int sr_kemi_core_notice(sip_msg_t *msg, str *txt)
 {
 	if(txt!=NULL && txt->s!=NULL)
 		LM_NOTICE("%.*s", txt->len, txt->s);
 	return 0;
 }
 
 /**
  *
  */
 static int sr_kemi_core_crit(sip_msg_t *msg, str *txt)
 {
 	if(txt!=NULL && txt->s!=NULL)
 		LM_CRIT("%.*s", txt->len, txt->s);
 	return 0;
 }
 
0f54afd1
 /**
  *
  */
 static int sr_kemi_core_log(sip_msg_t *msg, str *level, str *txt)
 {
 	if(txt!=NULL && txt->s!=NULL) {
 		if(level==NULL || level->s==NULL) {
 			LM_ERR("%s", txt->s);
 		} else {
 			if(strcasecmp(level->s, "dbg")==0) {
 				LM_DBG("%s", txt->s);
 			} else if(strcasecmp(level->s, "info")==0) {
 				LM_INFO("%s", txt->s);
73088fd8
 			} else if(strcasecmp(level->s, "notice")==0) {
 				LM_NOTICE("%s", txt->s);
0f54afd1
 			} else if(strcasecmp(level->s, "warn")==0) {
 				LM_WARN("%s", txt->s);
73088fd8
 			} else if(strcasecmp(level->s, "err")==0) {
 				LM_ERR("%s", txt->s);
0f54afd1
 			} else if(strcasecmp(level->s, "crit")==0) {
 				LM_CRIT("%s", txt->s);
 			} else {
 				LM_ERR("%s", txt->s);
 			}
 		}
 	}
 	return 0;
 }
 
a6fc13d6
 /**
  *
  */
ed87ecb6
 int sr_kemi_core_set_drop(sip_msg_t *msg)
a6fc13d6
 {
 	if(_sr_kemi_act_ctx==NULL)
 		return 0;
ed87ecb6
 	LM_DBG("set drop action executed inside embedded interpreter\n");
a6fc13d6
 	_sr_kemi_act_ctx->run_flags |= EXIT_R_F|DROP_R_F;
 	return 0;
 }
 
fb1e1d84
 /**
  *
  */
 static int sr_kemi_core_is_myself(sip_msg_t *msg, str *uri)
 {
 	struct sip_uri puri;
 	int ret;
 
 	if(uri==NULL || uri->s==NULL) {
 		return SR_KEMI_FALSE;
 	}
 	if(uri->len>4 && (strncmp(uri->s, "sip:", 4)==0
 				|| strncmp(uri->s, "sips:", 5)==0)) {
 		if(parse_uri(uri->s, uri->len, &puri)!=0) {
 			LM_ERR("failed to parse uri [%.*s]\n", uri->len, uri->s);
 			return SR_KEMI_FALSE;
 		}
 		ret = check_self(&puri.host, (puri.port.s)?puri.port_no:0,
 				(puri.transport_val.s)?puri.proto:0);
 	} else {
 		ret = check_self(uri, 0, 0);
 	}
 	if(ret==1) {
 		return SR_KEMI_TRUE;
 	}
 	return SR_KEMI_FALSE;
 }
 
03c3a04b
 /**
  *
  */
 static int sr_kemi_core_is_myself_ruri(sip_msg_t *msg)
 {
 	if(msg==NULL) {
 		LM_WARN("invalid msg parameter\n");
 		return SR_KEMI_FALSE;
 	}
 
 	if(msg->first_line.type == SIP_REPLY)	/* REPLY doesn't have a ruri */
 		return SR_KEMI_FALSE;
 
 	if (msg->new_uri.s!=NULL)
 		return sr_kemi_core_is_myself(msg, &msg->new_uri);
 	return sr_kemi_core_is_myself(msg, &msg->first_line.u.request.uri);
 }
 
2c4deee6
 /**
  *
  */
 static int sr_kemi_core_is_myself_duri(sip_msg_t *msg)
 {
 	if(msg==NULL) {
 		LM_WARN("invalid msg parameter\n");
 		return SR_KEMI_FALSE;
 	}
 
 	if (msg->dst_uri.s!=NULL)
 		return sr_kemi_core_is_myself(msg, &msg->dst_uri);
 
 	return SR_KEMI_FALSE;
 }
 
 /**
  *
  */
 static int sr_kemi_core_is_myself_nhuri(sip_msg_t *msg)
 {
 	if(msg==NULL) {
 		LM_WARN("invalid msg parameter\n");
 		return SR_KEMI_FALSE;
 	}
 
 	if (msg->dst_uri.s!=NULL)
 		return sr_kemi_core_is_myself(msg, &msg->dst_uri);
 
 	return sr_kemi_core_is_myself_ruri(msg);
 }
 
03c3a04b
 /**
  *
  */
 static int sr_kemi_core_is_myself_furi(sip_msg_t *msg)
 {
 	to_body_t *xfrom;
 
 	if(msg==NULL) {
 		LM_WARN("invalid msg parameter\n");
 		return SR_KEMI_FALSE;
 	}
 
 	if(parse_from_header(msg)<0) {
 		LM_ERR("cannot parse From header\n");
 		return SR_KEMI_FALSE;
 	}
 
 	if(msg->from==NULL || get_from(msg)==NULL) {
 		LM_DBG("no From header\n");
 		return SR_KEMI_FALSE;
 	}
 
 	xfrom = get_from(msg);
 
 	return sr_kemi_core_is_myself(msg, &xfrom->uri);
 }
 
 /**
  *
  */
 static int sr_kemi_core_is_myself_turi(sip_msg_t *msg)
 {
 	to_body_t *xto;
 
 	if(msg==NULL) {
 		LM_WARN("invalid msg parameter\n");
 		return SR_KEMI_FALSE;
 	}
 
 	if(parse_to_header(msg)<0) {
 		LM_ERR("cannot parse To header\n");
 		return SR_KEMI_FALSE;
 	}
 
 	if(msg->to==NULL || get_to(msg)==NULL) {
 		LM_DBG("no To header\n");
 		return SR_KEMI_FALSE;
 	}
 
 	xto = get_to(msg);
 
 	return sr_kemi_core_is_myself(msg, &xto->uri);
 }
 
e4f6a39b
 /**
  *
  */
 static int sr_kemi_core_is_myself_suri(sip_msg_t *msg)
 {
 	str suri;
 
 	if(get_src_uri(msg, 0, &suri)<0) {
 		LM_ERR("cannot src address uri\n");
929823cd
 		return SR_KEMI_FALSE;
e4f6a39b
 	}
 
 	return sr_kemi_core_is_myself(msg, &suri);
 }
 
929823cd
 /**
  *
  */
 static int sr_kemi_core_is_myself_srcip(sip_msg_t *msg)
 {
 	str srcip;
 	int ret;
 
 	srcip.s = ip_addr2a(&msg->rcv.src_ip);
 	srcip.len = strlen(srcip.s);
 
 	ret = check_self(&srcip, 0, 0);
 	if(ret==1) {
 		return SR_KEMI_TRUE;
 	}
 	return SR_KEMI_FALSE;
 }
 
0f54afd1
 /**
  *
  */
 static int sr_kemi_core_setflag(sip_msg_t *msg, int flag)
 {
 	if(msg==NULL) {
 		LM_WARN("invalid msg parameter\n");
 		return SR_KEMI_FALSE;
 	}
 
 	if (!flag_in_range(flag)) {
 		LM_ERR("invalid flag parameter %d\n", flag);
 		return SR_KEMI_FALSE;
 	}
 
 	setflag(msg, flag);
 	return SR_KEMI_TRUE;
 }
 
 /**
  *
  */
 static int sr_kemi_core_resetflag(sip_msg_t *msg, int flag)
 {
 	if(msg==NULL) {
 		LM_WARN("invalid msg parameter\n");
 		return SR_KEMI_FALSE;
 	}
 
 	if (!flag_in_range(flag)) {
 		LM_ERR("invalid flag parameter %d\n", flag);
 		return SR_KEMI_FALSE;
 	}
 
 	resetflag(msg, flag);
 	return SR_KEMI_TRUE;
 }
 
 /**
  *
  */
 static int sr_kemi_core_isflagset(sip_msg_t *msg, int flag)
 {
 	int ret;
 
 	if(msg==NULL) {
 		LM_WARN("invalid msg parameter\n");
 		return SR_KEMI_FALSE;
 	}
 
 	if (!flag_in_range(flag)) {
 		LM_ERR("invalid flag parameter %d\n", flag);
 		return SR_KEMI_FALSE;
 	}
 
 	ret = isflagset(msg, flag);
 	if(ret>0)
 		return SR_KEMI_TRUE;
 	return SR_KEMI_FALSE;
 }
 
 /**
  *
  */
 static int sr_kemi_core_setbiflag(sip_msg_t *msg, int flag, int branch)
 {
 	if(msg==NULL) {
 		LM_WARN("invalid msg parameter\n");
 		return SR_KEMI_FALSE;
 	}
 
 	if (!flag_in_range(flag)) {
 		LM_ERR("invalid flag parameter %d\n", flag);
 		return SR_KEMI_FALSE;
 	}
 
 	setbflag(branch, flag);
 	return SR_KEMI_TRUE;
 }
 
 /**
  *
  */
 static int sr_kemi_core_resetbiflag(sip_msg_t *msg, int flag, int branch)
 {
 	if(msg==NULL) {
 		LM_WARN("invalid msg parameter\n");
 		return SR_KEMI_FALSE;
 	}
 
 	if (!flag_in_range(flag)) {
 		LM_ERR("invalid flag parameter %d\n", flag);
 		return SR_KEMI_FALSE;
 	}
 
 	resetbflag(branch, flag);
 	return SR_KEMI_TRUE;
 }
 
 /**
  *
  */
 static int sr_kemi_core_isbiflagset(sip_msg_t *msg, int flag, int branch)
 {
 	int ret;
 
 	if(msg==NULL) {
 		LM_WARN("invalid msg parameter\n");
 		return SR_KEMI_FALSE;
 	}
 
 	if (!flag_in_range(flag)) {
 		LM_ERR("invalid flag parameter %d\n", flag);
 		return SR_KEMI_FALSE;
 	}
 
 	ret = isbflagset(branch, flag);
 	if(ret>0)
 		return SR_KEMI_TRUE;
 	return SR_KEMI_FALSE;
 }
 
 /**
  *
  */
 static int sr_kemi_core_setbflag(sip_msg_t *msg, int flag)
 {
 	return sr_kemi_core_setbiflag(msg, flag, 0);
 }
 
 /**
  *
  */
 static int sr_kemi_core_resetbflag(sip_msg_t *msg, int flag)
 {
 	return sr_kemi_core_resetbiflag(msg, flag, 0);
 }
 
 /**
  *
  */
 static int sr_kemi_core_isbflagset(sip_msg_t *msg, int flag)
 {
 	return sr_kemi_core_isbiflagset(msg, flag, 0);
 }
 
46334c18
 /**
  *
  */
 static int sr_kemi_core_setsflag(sip_msg_t *msg, int flag)
 {
 	if (!flag_in_range(flag)) {
 		LM_ERR("invalid flag parameter %d\n", flag);
 		return SR_KEMI_FALSE;
 	}
 
 	setsflag(flag);
 	return SR_KEMI_TRUE;
 }
 
 /**
  *
  */
 static int sr_kemi_core_resetsflag(sip_msg_t *msg, int flag)
 {
 	if (!flag_in_range(flag)) {
 		LM_ERR("invalid flag parameter %d\n", flag);
 		return SR_KEMI_FALSE;
 	}
 
 	resetsflag(flag);
 	return SR_KEMI_TRUE;
 }
 
 /**
  *
  */
 static int sr_kemi_core_issflagset(sip_msg_t *msg, int flag)
 {
 	int ret;
 
 	if (!flag_in_range(flag)) {
 		LM_ERR("invalid flag parameter %d\n", flag);
 		return SR_KEMI_FALSE;
 	}
 
 	ret = issflagset(flag);
 	if(ret>0)
 		return SR_KEMI_TRUE;
 	return SR_KEMI_FALSE;
 }
 
0f54afd1
 /**
  *
  */
 static int sr_kemi_core_seturi(sip_msg_t *msg, str *uri)
 {
 	if(uri==NULL || uri->s==NULL) {
 		LM_ERR("invalid uri parameter\n");
 		return SR_KEMI_FALSE;
 	}
 
 	if(msg==NULL) {
 		LM_WARN("invalid msg parameter\n");
 		return SR_KEMI_FALSE;
 	}
 
 	if(rewrite_uri(msg, uri)<0) {
 		LM_ERR("updating r-uri failed\n");
 		return SR_KEMI_FALSE;
 	}
 	return SR_KEMI_TRUE;
 }
 
 /**
  *
  */
 static int sr_kemi_core_setuser(sip_msg_t *msg, str *user)
 {
 	struct action  act;
 	struct run_act_ctx h;
 
 	if(user==NULL || user->s==NULL) {
 		LM_ERR("invalid user parameter\n");
 		return SR_KEMI_FALSE;
 	}
 
 	if(msg==NULL) {
 		LM_WARN("invalid user parameter\n");
 		return SR_KEMI_FALSE;
 	}
 
 	memset(&act, 0, sizeof(act));
 	act.val[0].type = STRING_ST;
 	act.val[0].u.string = user->s;
 	act.type = SET_USER_T;
 	init_run_actions_ctx(&h);
 	if (do_action(&h, &act, msg)<0) {
 		LM_ERR("do action failed\n");
 		return SR_KEMI_FALSE;
 	}
 	return SR_KEMI_TRUE;
 }
 
 /**
  *
  */
 static int sr_kemi_core_sethost(sip_msg_t *msg, str *host)
 {
 	struct action  act;
 	struct run_act_ctx h;
 
 	if(host==NULL || host->s==NULL) {
 		LM_ERR("invalid host parameter\n");
 		return SR_KEMI_FALSE;
 	}
 
 	if(msg==NULL) {
 		LM_WARN("invalid msg parameter\n");
 		return SR_KEMI_FALSE;
 	}
 
 	memset(&act, 0, sizeof(act));
 	act.val[0].type = STRING_ST;
 	act.val[0].u.string = host->s;
 	act.type = SET_HOST_T;
 	init_run_actions_ctx(&h);
 	if (do_action(&h, &act, msg)<0)
 	{
 		LM_ERR("do action failed\n");
 		return SR_KEMI_FALSE;
 	}
 	return SR_KEMI_TRUE;
 }
 
 /**
  *
  */
 static int sr_kemi_core_setdsturi(sip_msg_t *msg, str *uri)
 {
 	if(uri==NULL || uri->s==NULL) {
 		LM_ERR("invalid uri parameter\n");
 		return SR_KEMI_FALSE;
 	}
 
 	if(msg==NULL) {
 		LM_WARN("invalid msg parameter\n");
 		return SR_KEMI_FALSE;
 	}
 
 	if(set_dst_uri(msg, uri)<0) {
 		LM_ERR("setting dst uri failed\n");
 		return SR_KEMI_TRUE;
 	}
 	return SR_KEMI_TRUE;
 }
 
 /**
  *
  */
 static int sr_kemi_core_resetdsturi(sip_msg_t *msg)
 {
 	if(msg==NULL) {
2c593481
 		LM_WARN("invalid msg parameter\n");
0f54afd1
 		return SR_KEMI_FALSE;
 	}
 
 	reset_dst_uri(msg);
 	return SR_KEMI_TRUE;
 }
 
b97a8f46
 /**
  *
  */
 static int sr_kemi_core_isdsturiset(sip_msg_t *msg)
 {
 	if(msg==NULL) {
 		LM_WARN("invalid msg parameter\n");
 		return SR_KEMI_FALSE;
 	}
 
 	if(msg->dst_uri.s!=NULL && msg->dst_uri.len>0) {
 		return SR_KEMI_TRUE;
 	}
 	return SR_KEMI_FALSE;
 }
 
2c593481
 /**
  *
  */
 static int sr_kemi_core_force_rport(sip_msg_t *msg)
 {
 	if(msg==NULL) {
 		LM_WARN("invalid msg parameter\n");
 		return SR_KEMI_FALSE;
 	}
 
 	msg->msg_flags|=FL_FORCE_RPORT;
 	return SR_KEMI_TRUE;
 }
0f54afd1
 
136f0b6a
 /**
  *
  */
 static int sr_kemi_core_add_local_rport(sip_msg_t *msg)
 {
 	if(msg==NULL) {
 		LM_WARN("invalid msg parameter\n");
 		return SR_KEMI_FALSE;
 	}
 
 	msg->msg_flags|=FL_ADD_LOCAL_RPORT;
 	return SR_KEMI_TRUE;
 }
 
aec6c31b
 /**
  *
  */
 static int sr_kemi_core_match_method_id(str *rmethod, str *vmethod, int mid)
 {
 	char mbuf[SR_KEMI_HNAME_SIZE];
 	int i;
 	unsigned int method;
 	str s;
 
 	if(memchr(vmethod->s, '|', vmethod->len)==NULL) {
 		if(rmethod->len!=vmethod->len) {
 			return SR_KEMI_FALSE;
 		}
 		if(strncasecmp(rmethod->s, vmethod->s, vmethod->len)!=0) {
 			return SR_KEMI_FALSE;
 		}
 		return SR_KEMI_TRUE;
 	}
 	if(vmethod->len>=SR_KEMI_HNAME_SIZE-1) {
 		LM_ERR("methods parameter is too long\n");
 		return SR_KEMI_FALSE;
 	}
 	memcpy(mbuf, vmethod->s, vmethod->len);
 	mbuf[vmethod->len] = '\0';
 	for(i=0; i<vmethod->len; i++) {
 		if(mbuf[i]=='|') {
 			mbuf[i] = ',';
 		}
 	}
 	s.s = mbuf;
 	s.len = vmethod->len;
 	if(parse_methods(&s, &method)!=0) {
 		LM_ERR("failed to parse methods string [%.*s]\n", s.len, s.s);
 		return SR_KEMI_FALSE;
 	}
 	if((method==METHOD_UNDEF) || (method&METHOD_OTHER)) {
 		LM_ERR("unknown method in list [%.*s] - use only standard SIP methods\n",
 				s.len, s.s);
 		return SR_KEMI_FALSE;
 	}
 	if((int)method & mid) {
 		return SR_KEMI_TRUE;
 	}
 	return SR_KEMI_FALSE;
 }
 
 /**
  *
  */
 static int sr_kemi_core_is_method(sip_msg_t *msg, str *vmethod)
 {
 	if(msg==NULL || vmethod==NULL || vmethod->s==NULL || vmethod->len<=0) {
 		LM_WARN("invalid parameters\n");
 		return SR_KEMI_FALSE;
 	}
 
 	if(msg->first_line.type==SIP_REQUEST) {
 		if(msg->first_line.u.request.method_value==METHOD_OTHER) {
 			if(msg->first_line.u.request.method.len!=vmethod->len) {
 				return SR_KEMI_FALSE;
 			}
 			if(strncasecmp(msg->first_line.u.request.method.s, vmethod->s,
 						vmethod->len)!=0) {
 				return SR_KEMI_FALSE;
 			}
 			return SR_KEMI_TRUE;
 		}
 		return sr_kemi_core_match_method_id(&msg->first_line.u.request.method,
 				vmethod, msg->first_line.u.request.method_value);
 	}
 
 	if(parse_headers(msg, HDR_CSEQ_F, 0)!=0 || msg->cseq==NULL) {
 		LM_ERR("cannot parse cseq header\n");
 		return SR_KEMI_FALSE;
 	}
 	if(get_cseq(msg)->method_id==METHOD_OTHER) {
 		if(get_cseq(msg)->method.len!=vmethod->len) {
 			return SR_KEMI_FALSE;
 		}
 		if(strncasecmp(get_cseq(msg)->method.s, vmethod->s,
 					vmethod->len)!=0) {
 			return SR_KEMI_FALSE;
 		}
 		return SR_KEMI_TRUE;
 	}
 	return sr_kemi_core_match_method_id(&get_cseq(msg)->method, vmethod,
 			get_cseq(msg)->method_id);
 }
 
acf46dec
 /**
  *
  */
 static int sr_kemi_core_is_method_in(sip_msg_t *msg, str *vmethod)
 {
 	int imethod;
 	int i;
 
 	if(msg==NULL || vmethod==NULL || vmethod->s==NULL || vmethod->len<=0) {
 		LM_WARN("invalid parameters\n");
 		return SR_KEMI_FALSE;
 	}
 
 	if(msg->first_line.type==SIP_REQUEST) {
 		imethod = msg->first_line.u.request.method_value;
 	} else {
 		if(parse_headers(msg, HDR_CSEQ_F, 0)!=0 || msg->cseq==NULL) {
 			LM_ERR("cannot parse cseq header\n");
 			return SR_KEMI_FALSE;
 		}
 		imethod = get_cseq(msg)->method_id;
 	}
 
 	if(imethod==METHOD_OTHER) {
 		return SR_KEMI_FALSE;
 	}
 
 	for(i=0; i<vmethod->len; i++) {
 		switch(vmethod->s[i]) {
 			case 'I':
 			case 'i':
 				if(imethod==METHOD_INVITE) {
 					return SR_KEMI_TRUE;
 				}
 			break;
 			case 'A':
 			case 'a':
 				if(imethod==METHOD_ACK) {
 					return SR_KEMI_TRUE;
 				}
 			break;
 			case 'B':
 			case 'b':
 				if(imethod==METHOD_BYE) {
 					return SR_KEMI_TRUE;
 				}
 			break;
 			case 'C':
 			case 'c':
 				if(imethod==METHOD_CANCEL) {
 					return SR_KEMI_TRUE;
 				}
 			break;
bbef7d81
 			case 'M':
 			case 'm':
 				if(imethod==METHOD_MESSAGE) {
 					return SR_KEMI_TRUE;
 				}
 			break;
acf46dec
 			case 'R':
 			case 'r':
 				if(imethod==METHOD_REGISTER) {
 					return SR_KEMI_TRUE;
 				}
 			break;
b04111b5
 			case 'E':
 			case 'e':
 				if(imethod==METHOD_PRACK) {
 					return SR_KEMI_TRUE;
 				}
 			break;
acf46dec
 			case 'P':
 			case 'p':
 				if(imethod==METHOD_PUBLISH) {
 					return SR_KEMI_TRUE;
 				}
 			break;
 			case 'S':
 			case 's':
 				if(imethod==METHOD_SUBSCRIBE) {
 					return SR_KEMI_TRUE;
 				}
 			break;
 			case 'N':
 			case 'n':
 				if(imethod==METHOD_NOTIFY) {
 					return SR_KEMI_TRUE;
 				}
 			break;
 			case 'O':
 			case 'o':
 				if(imethod==METHOD_OPTIONS) {
 					return SR_KEMI_TRUE;
 				}
 			break;
840e29d7
 			case 'F':
 			case 'f':
 				if(imethod==METHOD_REFER) {
 					return SR_KEMI_TRUE;
 				}
 			break;
657d2699
 			case 'G':
 			case 'g':
 				if(imethod==METHOD_GET) {
 					return SR_KEMI_TRUE;
 				}
 			break;
e876770e
 			case 'U':
 			case 'u':
 				if(imethod==METHOD_UPDATE) {
 					return SR_KEMI_TRUE;
 				}
 			break;
657d2699
 			case 'K':
 			case 'k':
 				if(imethod==METHOD_KDMQ) {
 					return SR_KEMI_TRUE;
 				}
 			break;
 			case 'D':
 			case 'd':
 				if(imethod==METHOD_DELETE) {
 					return SR_KEMI_TRUE;
 				}
 			break;
 			case 'T':
 			case 't':
 				if(imethod==METHOD_POST) {
 					return SR_KEMI_TRUE;
 				}
 			break;
 			case 'V':
 			case 'v':
 				if(imethod==METHOD_PUT) {
 					return SR_KEMI_TRUE;
 				}
 			break;
7dc45000
 			default:
 				LM_WARN("unsupported method flag: %c\n", vmethod->s[i]);
acf46dec
 		}
 	}
 	return SR_KEMI_FALSE;
 }
 
d63638d4
 /**
  *
  */
 static int sr_kemi_core_is_method_type(sip_msg_t *msg, int mtype)
 {
 	int imethod;
 
 	if(msg==NULL) {
 		LM_WARN("invalid parameters\n");
 		return SR_KEMI_FALSE;
 	}
 
 	if(msg->first_line.type==SIP_REQUEST) {
 		imethod = msg->first_line.u.request.method_value;
 	} else {
 		if(parse_headers(msg, HDR_CSEQ_F, 0)!=0 || msg->cseq==NULL) {
 			LM_ERR("cannot parse cseq header\n");
 			return SR_KEMI_FALSE;
 		}
 		imethod = get_cseq(msg)->method_id;
 	}
 
 	if(imethod==mtype) {
 		return SR_KEMI_TRUE;
 	}
 
 	return SR_KEMI_FALSE;
 }
 
 /**
  *
  */
 static int sr_kemi_core_is_method_invite(sip_msg_t *msg)
 {
 	return sr_kemi_core_is_method_type(msg, METHOD_INVITE);
 }
 
 /**
  *
  */
 static int sr_kemi_core_is_method_ack(sip_msg_t *msg)
 {
 	return sr_kemi_core_is_method_type(msg, METHOD_ACK);
 }
 
 /**
  *
  */
 static int sr_kemi_core_is_method_bye(sip_msg_t *msg)
 {
 	return sr_kemi_core_is_method_type(msg, METHOD_BYE);
 }
 
 /**
  *
  */
 static int sr_kemi_core_is_method_cancel(sip_msg_t *msg)
 {
 	return sr_kemi_core_is_method_type(msg, METHOD_CANCEL);
 }
 
 /**
  *
  */
 static int sr_kemi_core_is_method_register(sip_msg_t *msg)
 {
 	return sr_kemi_core_is_method_type(msg, METHOD_REGISTER);
 }
 
 /**
  *
  */
 static int sr_kemi_core_is_method_options(sip_msg_t *msg)
 {
 	return sr_kemi_core_is_method_type(msg, METHOD_OPTIONS);
 }
 
 /**
  *
  */
 static int sr_kemi_core_is_method_update(sip_msg_t *msg)
 {
 	return sr_kemi_core_is_method_type(msg, METHOD_UPDATE);
 }
 
 /**
  *
  */
 static int sr_kemi_core_is_method_subscribe(sip_msg_t *msg)
 {
 	return sr_kemi_core_is_method_type(msg, METHOD_SUBSCRIBE);
 }
 
 /**
  *
  */
 static int sr_kemi_core_is_method_publish(sip_msg_t *msg)
 {
 	return sr_kemi_core_is_method_type(msg, METHOD_PUBLISH);
 }
 
 /**
  *
  */
 static int sr_kemi_core_is_method_notify(sip_msg_t *msg)
 {
 	return sr_kemi_core_is_method_type(msg, METHOD_NOTIFY);
 }
 
840e29d7
 /**
  *
  */
 static int sr_kemi_core_is_method_refer(sip_msg_t *msg)
 {
 	return sr_kemi_core_is_method_type(msg, METHOD_REFER);
 }
 
d63638d4
 /**
  *
  */
 static int sr_kemi_core_is_method_info(sip_msg_t *msg)
 {
 	return sr_kemi_core_is_method_type(msg, METHOD_INFO);
 }
 
 /**
  *
  */
 static int sr_kemi_core_is_method_prack(sip_msg_t *msg)
 {
 	return sr_kemi_core_is_method_type(msg, METHOD_PRACK);
 }
 
8db5a12f
 
 /**
  *
  */
 static int sr_kemi_core_is_method_message(sip_msg_t *msg)
 {
 	return sr_kemi_core_is_method_type(msg, METHOD_MESSAGE);
 }
 
 
17d30403
 /**
  *
  */
 static int sr_kemi_core_is_method_kdmq(sip_msg_t *msg)
 {
 	return sr_kemi_core_is_method_type(msg, METHOD_KDMQ);
 }
 
 
f2458a66
 /**
  *
  */
 static int sr_kemi_core_is_method_get(sip_msg_t *msg)
 {
 	return sr_kemi_core_is_method_type(msg, METHOD_GET);
 }
 
 /**
  *
  */
 static int sr_kemi_core_is_method_post(sip_msg_t *msg)
 {
 	return sr_kemi_core_is_method_type(msg, METHOD_POST);
 }
 
 /**
  *
  */
 static int sr_kemi_core_is_method_put(sip_msg_t *msg)
 {
 	return sr_kemi_core_is_method_type(msg, METHOD_PUT);
 }
 
 /**
  *
  */
 static int sr_kemi_core_is_method_delete(sip_msg_t *msg)
 {
 	return sr_kemi_core_is_method_type(msg, METHOD_DELETE);
 }
 
d33d60e0
 /**
  *
  */
 static int sr_kemi_core_is_proto_udp(sip_msg_t *msg)
 {
 	return (msg->rcv.proto == PROTO_UDP)?SR_KEMI_TRUE:SR_KEMI_FALSE;
 }
 
 /**
  *
  */
 static int sr_kemi_core_is_proto_tcp(sip_msg_t *msg)
 {
 	return (msg->rcv.proto == PROTO_TCP)?SR_KEMI_TRUE:SR_KEMI_FALSE;
 }
 
 /**
  *
  */
 static int sr_kemi_core_is_proto_tls(sip_msg_t *msg)
 {
 	return (msg->rcv.proto == PROTO_TLS)?SR_KEMI_TRUE:SR_KEMI_FALSE;
 }
 
 /**
  *
  */
 static int sr_kemi_core_is_proto_ws(sip_msg_t *msg)
 {
 	return (msg->rcv.proto == PROTO_WS)?SR_KEMI_TRUE:SR_KEMI_FALSE;
 }
 
 /**
  *
  */
 static int sr_kemi_core_is_proto_wss(sip_msg_t *msg)
 {
 	return (msg->rcv.proto == PROTO_WSS)?SR_KEMI_TRUE:SR_KEMI_FALSE;
 }
 
5d03c923
 /**
  *
  */
 static int sr_kemi_core_is_proto_wsx(sip_msg_t *msg)
 {
 	if (msg->rcv.proto == PROTO_WSS) return SR_KEMI_TRUE;
 	if (msg->rcv.proto == PROTO_WS) return SR_KEMI_TRUE;
 
 	return SR_KEMI_FALSE;
 }
 
 
d33d60e0
 /**
  *
  */
 static int sr_kemi_core_is_proto_sctp(sip_msg_t *msg)
 {
 	return (msg->rcv.proto == PROTO_SCTP)?SR_KEMI_TRUE:SR_KEMI_FALSE;
 }
 
150252e7
 /**
  *
  */
 static int sr_kemi_core_is_proto(sip_msg_t *msg, str *sproto)
 {
 	int i;
 	if (msg==NULL || sproto==NULL || sproto->s==NULL || sproto->len<=0) {
 		return SR_KEMI_FALSE;
 	}
 	for(i=0; i<sproto->len; i++) {
 		switch(sproto->s[i]) {
 			case 'e':
 			case 'E':
 				if (msg->rcv.proto == PROTO_TLS) {
 					return SR_KEMI_TRUE;
 				}
 			break;
 			case 's':
 			case 'S':
 				if (msg->rcv.proto == PROTO_SCTP) {
 					return SR_KEMI_TRUE;
 				}
 			break;
 			case 't':
 			case 'T':
 				if (msg->rcv.proto == PROTO_TCP) {
 					return SR_KEMI_TRUE;
 				}
 			break;
 			case 'u':
 			case 'U':
 				if (msg->rcv.proto == PROTO_UDP) {
 					return SR_KEMI_TRUE;
 				}
 			break;
 			case 'v':
 			case 'V':
 				if (msg->rcv.proto == PROTO_WS) {
 					return SR_KEMI_TRUE;
 				}
 			break;
 
 			case 'w':
 			case 'W':
 				if (msg->rcv.proto == PROTO_WSS) {
 					return SR_KEMI_TRUE;
 				}
 			break;
 		}
 	}
 	return SR_KEMI_FALSE;
 }
 
61795123
 /**
  *
  */
 static int sr_kemi_core_is_af_ipv4(sip_msg_t *msg)
 {
 	if(msg==NULL || msg->rcv.bind_address==NULL) {
 		return SR_KEMI_FALSE;
 	}
 	return (msg->rcv.bind_address->address.af==AF_INET)?SR_KEMI_TRUE:SR_KEMI_FALSE;
 }
 
 /**
  *
  */
 static int sr_kemi_core_is_af_ipv6(sip_msg_t *msg)
 {
 	if(msg==NULL || msg->rcv.bind_address==NULL) {
 		return SR_KEMI_FALSE;
 	}
 	return (msg->rcv.bind_address->address.af==AF_INET6)?SR_KEMI_TRUE:SR_KEMI_FALSE;
 }
 
235a10bc
 /**
  *
  */
 static int sr_kemi_core_is_src_port(sip_msg_t *msg, int vport)
 {
 	return (vport == (int)msg->rcv.src_port)?SR_KEMI_TRUE:SR_KEMI_FALSE;
 }
 
 /**
  *
  */
 static int sr_kemi_core_is_dst_port(sip_msg_t *msg, int vport)
 {
 	if(msg==NULL || msg->rcv.bind_address==NULL) {
 		return SR_KEMI_FALSE;
 	}
 	return (vport == (int)msg->rcv.bind_address->port_no)?SR_KEMI_TRUE:SR_KEMI_FALSE;
 }
 
aec6c31b
 /**
  *
  */
 static int sr_kemi_core_forward_uri(sip_msg_t *msg, str *vuri)
 {
 	int ret;
 	dest_info_t dst;
 	sip_uri_t *u;
 	sip_uri_t next_hop;
 
 	if(msg==NULL) {
 		LM_WARN("invalid msg parameter\n");
 		return -1;
 	}
 
 	init_dest_info(&dst);
 
 	if(vuri==NULL || vuri->s==NULL || vuri->len<=0) {
 		if (msg->dst_uri.len) {
 			ret = parse_uri(msg->dst_uri.s, msg->dst_uri.len, &next_hop);
 			u = &next_hop;
 		} else {
 			ret = parse_sip_msg_uri(msg);
 			u = &msg->parsed_uri;
 		}
 	} else {
 		ret = parse_uri(vuri->s, vuri->len, &next_hop);
 		u = &next_hop;
 	}
 
 	if (ret<0) {
 		LM_ERR("forward - bad_uri dropping packet\n");
 		return -1;
 	}
 
 	dst.proto=u->proto;
 	ret=forward_request(msg, &u->host, u->port_no, &dst);
 	if (ret>=0) {
 		return 1;
 	}
 
 	return -1;
 }
 
 /**
  *
  */
 static int sr_kemi_core_forward(sip_msg_t *msg)
 {
 	return sr_kemi_core_forward_uri(msg, NULL);
 }
 
 /**
  *
  */
 static int sr_kemi_core_set_forward_close(sip_msg_t *msg)
 {
 	if(msg==NULL) {
 		LM_WARN("invalid msg parameter\n");
 		return SR_KEMI_FALSE;
 	}
 
 	msg->fwd_send_flags.f |= SND_F_CON_CLOSE;
 	return SR_KEMI_TRUE;
 }
 
 /**
  *
  */
 static int sr_kemi_core_set_forward_no_connect(sip_msg_t *msg)
 {
 	if(msg==NULL) {
 		LM_WARN("invalid msg parameter\n");
 		return SR_KEMI_FALSE;
 	}
 
 	msg->fwd_send_flags.f |= SND_F_FORCE_CON_REUSE;
 	return SR_KEMI_TRUE;
 }
 
 /**
  *
  */
 static int sr_kemi_core_set_reply_close(sip_msg_t *msg)
 {
 	if(msg==NULL) {
 		LM_WARN("invalid msg parameter\n");
 		return SR_KEMI_FALSE;
 	}
 
 	msg->rpl_send_flags.f |= SND_F_CON_CLOSE;
 	return SR_KEMI_TRUE;
 }
 
 /**
  *
  */
 static int sr_kemi_core_set_reply_no_connect(sip_msg_t *msg)
 {
 	if(msg==NULL) {
 		LM_WARN("invalid msg parameter\n");
 		return SR_KEMI_FALSE;
 	}
 
 	msg->rpl_send_flags.f |= SND_F_FORCE_CON_REUSE;
 	return SR_KEMI_TRUE;
 }
 
136f0b6a
 /**
  *
  */
 static int sr_kemi_core_set_advertised_address(sip_msg_t *msg, str *addr)
 {
 #define SR_ADV_ADDR_SIZE 128
 	static char _sr_adv_addr_buf[SR_ADV_ADDR_SIZE];
 
 	if(addr==NULL || addr->s==NULL) {
 		LM_ERR("invalid addr parameter\n");
 		return SR_KEMI_FALSE;
 	}
 
 	if(addr->len>=SR_ADV_ADDR_SIZE) {
 		LM_ERR("addr parameter is too large\n");
 		return SR_KEMI_FALSE;
 	}
 
 	if(msg==NULL) {
 		LM_WARN("invalid msg parameter\n");
 		return SR_KEMI_FALSE;
 	}
 
 	memcpy(_sr_adv_addr_buf, addr->s, addr->len);
 	_sr_adv_addr_buf[addr->len] = '\0';
 	msg->set_global_address.s = _sr_adv_addr_buf;
 	msg->set_global_address.len = addr->len;
 
 	return SR_KEMI_TRUE;
 }
 
 /**
  *
  */
 static int sr_kemi_core_set_advertised_port(sip_msg_t *msg, str *port)
 {
 #define SR_ADV_PORT_SIZE 8
 	static char _sr_adv_port_buf[SR_ADV_PORT_SIZE];
 
 	if(port==NULL || port->s==NULL) {
 		LM_ERR("invalid port parameter\n");
 		return SR_KEMI_FALSE;
 	}
 
 	if(port->len>=SR_ADV_PORT_SIZE) {
 		LM_ERR("port parameter is too large\n");
 		return SR_KEMI_FALSE;
 	}
 
 	if(msg==NULL) {
 		LM_WARN("invalid msg parameter\n");
 		return SR_KEMI_FALSE;
 	}
 
 	memcpy(_sr_adv_port_buf, port->s, port->len);
 	_sr_adv_port_buf[port->len] = '\0';
 	msg->set_global_port.s = _sr_adv_port_buf;
 	msg->set_global_port.len = port->len;
 
 	return SR_KEMI_TRUE;
 }
 
45260517
 /**
  *
  */
 static int sr_kemi_core_add_tcp_alias(sip_msg_t *msg, int port)
 {
 	if(msg==NULL) {
 		LM_WARN("invalid msg parameter\n");
 		return SR_KEMI_FALSE;
 	}
 
 #ifdef USE_TCP
 	if ( msg->rcv.proto==PROTO_TCP
 #ifdef USE_TLS
 				|| msg->rcv.proto==PROTO_TLS
 #endif
 			) {
 		if (tcpconn_add_alias(msg->rcv.proto_reserved1, port,
 							msg->rcv.proto)!=0){
 			LM_ERR("adding tcp alias failed\n");
 			return SR_KEMI_FALSE;
 		}
 	}
 #endif
 
 	return SR_KEMI_TRUE;
 }
 
 /**
  *
  */
 static int sr_kemi_core_add_tcp_alias_via(sip_msg_t *msg)
 {
 	if(msg==NULL) {
 		LM_WARN("invalid msg parameter\n");
 		return SR_KEMI_FALSE;
 	}
 
 #ifdef USE_TCP
 	if ( msg->rcv.proto==PROTO_TCP
 #ifdef USE_TLS
 				|| msg->rcv.proto==PROTO_TLS
 #endif
 			) {
 		if (tcpconn_add_alias(msg->rcv.proto_reserved1, msg->via1->port,
 							msg->rcv.proto)!=0){
 			LM_ERR("adding tcp alias failed\n");
 			return SR_KEMI_FALSE;
 		}
 	}
 #endif
 	return SR_KEMI_TRUE;
 }
 
 
f97093fa
 /**
  *
  */
 static int sr_kemi_core_get_debug(sip_msg_t *msg)
 {
 	return get_cfg_debug_level();
 }
 
d9dd2abe
 /**
  *
  */
 static int sr_kemi_core_route(sip_msg_t *msg, str *route)
 {
 	run_act_ctx_t tctx;
 	run_act_ctx_t *pctx = NULL;
 	int rtid = -1;
 	int ret = 0;
 
 	if(route == NULL || route->s == NULL) {
 		return -1;
 	}
 
 	rtid = route_lookup(&main_rt, route->s);
 	if (rtid < 0) {
 		return -1;
 	}
 
 	if(_sr_kemi_act_ctx != NULL) {
 		pctx = _sr_kemi_act_ctx;
 	} else {
 		init_run_actions_ctx(&tctx);
 		pctx = &tctx;
 	}
 
 	ret=run_actions(pctx, main_rt.rlist[rtid], msg);
 
 	if (pctx->run_flags & EXIT_R_F) {
 		return 0;
 	}
 
 	return ret;
 }
 
13e876e4
 /**
  *
  */
 static int sr_kemi_core_to_proto_helper(sip_msg_t *msg)
 {
 	sip_uri_t parsed_uri;
 	str uri;
 
 	if(msg==NULL) {
 		return -1;
 	}
 	if(msg->first_line.type == SIP_REPLY) {
 		/* REPLY doesnt have r/d-uri - use second Via */
 		if(parse_headers( msg, HDR_VIA2_F, 0)==-1) {
 			LM_DBG("no 2nd via parsed\n");
 			return -1;
 		}
 		if((msg->via2==0) || (msg->via2->error!=PARSE_OK)) {
 			return -1;
 		}
 		return (int)msg->via2->proto;
 	}
 	if (msg->dst_uri.s != NULL && msg->dst_uri.len>0) {
 		uri = msg->dst_uri;
 	} else {
 		if (msg->new_uri.s!=NULL && msg->new_uri.len>0)
 		{
 			uri = msg->new_uri;
 		} else {
 			uri = msg->first_line.u.request.uri;
 		}
 	}
 	if(parse_uri(uri.s, uri.len, &parsed_uri)!=0) {
 		LM_ERR("failed to parse nh uri [%.*s]\n", uri.len, uri.s);
 		return -1;
 	}
 	return (int)parsed_uri.proto;
 }
 
 /**
  *
  */
 static int sr_kemi_core_to_proto_udp(sip_msg_t *msg)
 {
 	int proto;
 
 	proto = sr_kemi_core_to_proto_helper(msg);
 	return (proto == PROTO_UDP)?SR_KEMI_TRUE:SR_KEMI_FALSE;
 }
 
2f933b39
 /**
  *
  */
 static int sr_kemi_core_to_proto_tcp(sip_msg_t *msg)
 {
 	int proto;
 
 	proto = sr_kemi_core_to_proto_helper(msg);
 	return (proto == PROTO_TCP)?SR_KEMI_TRUE:SR_KEMI_FALSE;
 }
 
 /**
  *
  */
 static int sr_kemi_core_to_proto_tls(sip_msg_t *msg)
 {
 	int proto;
 
 	proto = sr_kemi_core_to_proto_helper(msg);
 	return (proto == PROTO_TLS)?SR_KEMI_TRUE:SR_KEMI_FALSE;
 }
 
 /**
  *
  */
 static int sr_kemi_core_to_proto_sctp(sip_msg_t *msg)
 {
 	int proto;
 
 	proto = sr_kemi_core_to_proto_helper(msg);
 	return (proto == PROTO_SCTP)?SR_KEMI_TRUE:SR_KEMI_FALSE;
 }
 
 /**
  *
  */
 static int sr_kemi_core_to_proto_ws(sip_msg_t *msg)
 {
 	int proto;
 
 	proto = sr_kemi_core_to_proto_helper(msg);
 	return (proto == PROTO_WS)?SR_KEMI_TRUE:SR_KEMI_FALSE;
 }
 
 /**
  *
  */
 static int sr_kemi_core_to_proto_wss(sip_msg_t *msg)
 {
 	int proto;
 
 	proto = sr_kemi_core_to_proto_helper(msg);
 	return (proto == PROTO_WSS)?SR_KEMI_TRUE:SR_KEMI_FALSE;
 }
 
 /**
  *
  */
 static int sr_kemi_core_to_proto_wsx(sip_msg_t *msg)
 {
 	int proto;
 
 	proto = sr_kemi_core_to_proto_helper(msg);
 	if (proto == PROTO_WSS) { return SR_KEMI_TRUE; }
 	return (proto == PROTO_WS)?SR_KEMI_TRUE:SR_KEMI_FALSE;
 }
13e876e4
 
16a41dba
 /**
  *
  */
 static sr_kemi_t _sr_kemi_core[] = {
 	{ str_init(""), str_init("dbg"),
1f8ab5a6
 		SR_KEMIP_NONE, sr_kemi_core_dbg,
16a41dba
 		{ SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
 	{ str_init(""), str_init("err"),
1f8ab5a6
 		SR_KEMIP_NONE, sr_kemi_core_err,
16a41dba
 		{ SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
 	{ str_init(""), str_init("info"),
1f8ab5a6
 		SR_KEMIP_NONE, sr_kemi_core_info,
16a41dba
 		{ SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
f854f2c2
 	{ str_init(""), str_init("warn"),
 		SR_KEMIP_NONE, sr_kemi_core_warn,
 		{ SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
 	{ str_init(""), str_init("notice"),
 		SR_KEMIP_NONE, sr_kemi_core_notice,
 		{ SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
 	{ str_init(""), str_init("crit"),
 		SR_KEMIP_NONE, sr_kemi_core_crit,
 		{ SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
0f54afd1
 	{ str_init(""), str_init("log"),
 		SR_KEMIP_NONE, sr_kemi_core_log,
 		{ SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
ed87ecb6
 	{ str_init(""), str_init("set_drop"),
 		SR_KEMIP_NONE, sr_kemi_core_set_drop,
a6fc13d6
 		{ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
fb1e1d84
 	{ str_init(""), str_init("is_myself"),
 		SR_KEMIP_BOOL, sr_kemi_core_is_myself,
 		{ SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
03c3a04b
 	{ str_init(""), str_init("is_myself_ruri"),
 		SR_KEMIP_BOOL, sr_kemi_core_is_myself_ruri,
 		{ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
2c4deee6
 	{ str_init(""), str_init("is_myself_duri"),
 		SR_KEMIP_BOOL, sr_kemi_core_is_myself_duri,
 		{ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
 	{ str_init(""), str_init("is_myself_nhuri"),
 		SR_KEMIP_BOOL, sr_kemi_core_is_myself_nhuri,
 		{ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
03c3a04b
 	{ str_init(""), str_init("is_myself_furi"),
 		SR_KEMIP_BOOL, sr_kemi_core_is_myself_furi,
 		{ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
 	{ str_init(""), str_init("is_myself_turi"),
 		SR_KEMIP_BOOL, sr_kemi_core_is_myself_turi,
 		{ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
e4f6a39b
 	{ str_init(""), str_init("is_myself_suri"),
 		SR_KEMIP_BOOL, sr_kemi_core_is_myself_suri,
 		{ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
929823cd
 	{ str_init(""), str_init("is_myself_srcip"),
 		SR_KEMIP_BOOL, sr_kemi_core_is_myself_srcip,
 		{ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
0f54afd1
 	{ str_init(""), str_init("setflag"),
 		SR_KEMIP_BOOL, sr_kemi_core_setflag,
 		{ SR_KEMIP_INT, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
 	{ str_init(""), str_init("resetflag"),
 		SR_KEMIP_BOOL, sr_kemi_core_resetflag,
 		{ SR_KEMIP_INT, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
 	{ str_init(""), str_init("isflagset"),
 		SR_KEMIP_BOOL, sr_kemi_core_isflagset,
 		{ SR_KEMIP_INT, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
 	{ str_init(""), str_init("setbflag"),
 		SR_KEMIP_BOOL, sr_kemi_core_setbflag,
 		{ SR_KEMIP_INT, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
 	{ str_init(""), str_init("resetbflag"),
 		SR_KEMIP_BOOL, sr_kemi_core_resetbflag,
 		{ SR_KEMIP_INT, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
 	{ str_init(""), str_init("isbflagset"),
 		SR_KEMIP_BOOL, sr_kemi_core_isbflagset,
 		{ SR_KEMIP_INT, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
 	{ str_init(""), str_init("setbiflag"),
 		SR_KEMIP_BOOL, sr_kemi_core_setbiflag,
e4b7cd2a
 		{ SR_KEMIP_INT, SR_KEMIP_INT, SR_KEMIP_NONE,
0f54afd1
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
 	{ str_init(""), str_init("resetbiflag"),
 		SR_KEMIP_BOOL, sr_kemi_core_resetbiflag,
e4b7cd2a
 		{ SR_KEMIP_INT, SR_KEMIP_INT, SR_KEMIP_NONE,
0f54afd1
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
 	{ str_init(""), str_init("isbiflagset"),
 		SR_KEMIP_BOOL, sr_kemi_core_isbiflagset,
e4b7cd2a
 		{ SR_KEMIP_INT, SR_KEMIP_INT, SR_KEMIP_NONE,
0f54afd1
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
46334c18
 	{ str_init(""), str_init("setsflag"),
 		SR_KEMIP_BOOL, sr_kemi_core_setsflag,
 		{ SR_KEMIP_INT, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
 	{ str_init(""), str_init("resetsflag"),
 		SR_KEMIP_BOOL, sr_kemi_core_resetsflag,
 		{ SR_KEMIP_INT, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
 	{ str_init(""), str_init("issflagset"),
 		SR_KEMIP_BOOL, sr_kemi_core_issflagset,
 		{ SR_KEMIP_INT, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
0f54afd1
 	{ str_init(""), str_init("seturi"),
 		SR_KEMIP_BOOL, sr_kemi_core_seturi,
 		{ SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
 	{ str_init(""), str_init("setuser"),
 		SR_KEMIP_BOOL, sr_kemi_core_setuser,
 		{ SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
 	{ str_init(""), str_init("sethost"),
 		SR_KEMIP_BOOL, sr_kemi_core_sethost,
 		{ SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
 	{ str_init(""), str_init("setdsturi"),
 		SR_KEMIP_BOOL, sr_kemi_core_setdsturi,
 		{ SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
 	{ str_init(""), str_init("resetdsturi"),
 		SR_KEMIP_BOOL, sr_kemi_core_resetdsturi,
aec6c31b
 		{ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
0f54afd1
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
b97a8f46
 	},
 	{ str_init(""), str_init("isdsturiset"),
 		SR_KEMIP_BOOL, sr_kemi_core_isdsturiset,
 		{ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
0f54afd1
 	},
2c593481
 	{ str_init(""), str_init("force_rport"),
 		SR_KEMIP_BOOL, sr_kemi_core_force_rport,
 		{ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
136f0b6a
 	{ str_init(""), str_init("add_local_rport"),
 		SR_KEMIP_BOOL, sr_kemi_core_add_local_rport,
 		{ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
aec6c31b
 	{ str_init(""), str_init("is_method"),
 		SR_KEMIP_BOOL, sr_kemi_core_is_method,
 		{ SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
acf46dec
 	{ str_init(""), str_init("is_method_in"),
 		SR_KEMIP_BOOL, sr_kemi_core_is_method_in,
 		{ SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
aec6c31b
 	{ str_init(""), str_init("forward"),
 		SR_KEMIP_INT, sr_kemi_core_forward,
 		{ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
 	{ str_init(""), str_init("forward_uri"),
 		SR_KEMIP_INT, sr_kemi_core_forward_uri,
 		{ SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
 	{ str_init(""), str_init("set_forward_close"),
 		SR_KEMIP_BOOL, sr_kemi_core_set_forward_close,
 		{ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
 	{ str_init(""), str_init("set_forward_no_connect"),
 		SR_KEMIP_BOOL, sr_kemi_core_set_forward_no_connect,
 		{ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
 	{ str_init(""), str_init("set_reply_close"),
 		SR_KEMIP_BOOL, sr_kemi_core_set_reply_close,
 		{ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
 	{ str_init(""), str_init("set_reply_no_connect"),
 		SR_KEMIP_BOOL, sr_kemi_core_set_reply_no_connect,
 		{ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
136f0b6a
 	{ str_init(""), str_init("set_advertised_address"),
 		SR_KEMIP_INT, sr_kemi_core_set_advertised_address,
 		{ SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
 	{ str_init(""), str_init("set_advertised_port"),
 		SR_KEMIP_INT, sr_kemi_core_set_advertised_port,
 		{ SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
45260517
 	{ str_init(""), str_init("add_tcp_alias"),
 		SR_KEMIP_INT, sr_kemi_core_add_tcp_alias,
 		{ SR_KEMIP_INT, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
 	{ str_init(""), str_init("add_tcp_alias_via"),
 		SR_KEMIP_INT, sr_kemi_core_add_tcp_alias_via,
 		{ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
7c912517
 	{ str_init(""), str_init("is_INVITE"),
3b3302e4
 		SR_KEMIP_BOOL, sr_kemi_core_is_method_invite,
d63638d4
 		{ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
7c912517
 	{ str_init(""), str_init("is_ACK"),
3b3302e4
 		SR_KEMIP_BOOL, sr_kemi_core_is_method_ack,
d63638d4
 		{ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
7c912517
 	{ str_init(""), str_init("is_BYE"),
3b3302e4
 		SR_KEMIP_BOOL, sr_kemi_core_is_method_bye,
d63638d4
 		{ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
7c912517
 	{ str_init(""), str_init("is_CANCEL"),
3b3302e4
 		SR_KEMIP_BOOL, sr_kemi_core_is_method_cancel,
d63638d4
 		{ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
7c912517
 	{ str_init(""), str_init("is_REGISTER"),
3b3302e4
 		SR_KEMIP_BOOL, sr_kemi_core_is_method_register,
d63638d4
 		{ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
7c912517
 	{ str_init(""), str_init("is_OPTIONS"),
3b3302e4
 		SR_KEMIP_BOOL, sr_kemi_core_is_method_options,
d63638d4
 		{ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
7c912517
 	{ str_init(""), str_init("is_SUBSCRIBE"),
3b3302e4
 		SR_KEMIP_BOOL, sr_kemi_core_is_method_subscribe,
d63638d4
 		{ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
7c912517
 	{ str_init(""), str_init("is_PUBLISH"),
3b3302e4
 		SR_KEMIP_BOOL, sr_kemi_core_is_method_publish,
d63638d4
 		{ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
7c912517
 	{ str_init(""), str_init("is_NOTIFY"),
3b3302e4
 		SR_KEMIP_BOOL, sr_kemi_core_is_method_notify,
d63638d4
 		{ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
840e29d7
 	{ str_init(""), str_init("is_REFER"),
 		SR_KEMIP_BOOL, sr_kemi_core_is_method_refer,
 		{ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
7c912517
 	{ str_init(""), str_init("is_INFO"),
3b3302e4
 		SR_KEMIP_BOOL, sr_kemi_core_is_method_info,
d63638d4
 		{ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
7c912517
 	{ str_init(""), str_init("is_UPDATE"),
3b3302e4
 		SR_KEMIP_BOOL, sr_kemi_core_is_method_update,
d63638d4
 		{ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
7c912517
 	{ str_init(""), str_init("is_PRACK"),
3b3302e4
 		SR_KEMIP_BOOL, sr_kemi_core_is_method_prack,
d63638d4
 		{ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
d33d60e0
 	},
8db5a12f
 	{ str_init(""), str_init("is_MESSAGE"),
 		SR_KEMIP_BOOL, sr_kemi_core_is_method_message,
 		{ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
17d30403
 	{ str_init(""), str_init("is_KDMQ"),
 		SR_KEMIP_BOOL, sr_kemi_core_is_method_kdmq,
 		{ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
f2458a66
 	{ str_init(""), str_init("is_GET"),
 		SR_KEMIP_BOOL, sr_kemi_core_is_method_get,
 		{ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
 	{ str_init(""), str_init("is_POST"),
 		SR_KEMIP_BOOL, sr_kemi_core_is_method_post,
 		{ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
 	{ str_init(""), str_init("is_PUT"),
 		SR_KEMIP_BOOL, sr_kemi_core_is_method_put,
 		{ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
 	{ str_init(""), str_init("is_DELETE"),
 		SR_KEMIP_BOOL, sr_kemi_core_is_method_delete,
 		{ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
d33d60e0
 	{ str_init(""), str_init("is_UDP"),
 		SR_KEMIP_BOOL, sr_kemi_core_is_proto_udp,
 		{ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
 	{ str_init(""), str_init("is_TCP"),
 		SR_KEMIP_BOOL, sr_kemi_core_is_proto_tcp,
 		{ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
 	{ str_init(""), str_init("is_TLS"),
 		SR_KEMIP_BOOL, sr_kemi_core_is_proto_tls,
 		{ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
 	{ str_init(""), str_init("is_WS"),
 		SR_KEMIP_BOOL, sr_kemi_core_is_proto_ws,
 		{ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
 	{ str_init(""), str_init("is_WSS"),
 		SR_KEMIP_BOOL, sr_kemi_core_is_proto_wss,
 		{ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
5d03c923
 	{ str_init(""), str_init("is_WSX"),
 		SR_KEMIP_BOOL, sr_kemi_core_is_proto_wsx,
 		{ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
d33d60e0
 	{ str_init(""), str_init("is_SCTP"),
 		SR_KEMIP_BOOL, sr_kemi_core_is_proto_sctp,
 		{ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
61795123
 	},
150252e7
 	{ str_init(""), str_init("is_proto"),
 		SR_KEMIP_BOOL, sr_kemi_core_is_proto,
 		{ SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
61795123
 	{ str_init(""), str_init("is_IPv4"),
 		SR_KEMIP_BOOL, sr_kemi_core_is_af_ipv4,
 		{ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
 	{ str_init(""), str_init("is_IPv6"),
 		SR_KEMIP_BOOL, sr_kemi_core_is_af_ipv6,
 		{ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
235a10bc
 	},
795a9f57
 	{ str_init(""), str_init("to_UDP"),
 		SR_KEMIP_BOOL, sr_kemi_core_to_proto_udp,
 		{ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
2f933b39
 	{ str_init(""), str_init("to_TCP"),
 		SR_KEMIP_BOOL, sr_kemi_core_to_proto_tcp,
 		{ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
 	{ str_init(""), str_init("to_TLS"),
 		SR_KEMIP_BOOL, sr_kemi_core_to_proto_tls,
 		{ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
 	{ str_init(""), str_init("to_SCTP"),
 		SR_KEMIP_BOOL, sr_kemi_core_to_proto_sctp,
 		{ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
 	{ str_init(""), str_init("to_WS"),
 		SR_KEMIP_BOOL, sr_kemi_core_to_proto_ws,
 		{ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
 	{ str_init(""), str_init("to_WSS"),
 		SR_KEMIP_BOOL, sr_kemi_core_to_proto_wss,
 		{ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
 	{ str_init(""), str_init("to_WSX"),
 		SR_KEMIP_BOOL, sr_kemi_core_to_proto_wsx,
13e876e4
 		{ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
235a10bc
 	{ str_init(""), str_init("is_src_port"),
 		SR_KEMIP_BOOL, sr_kemi_core_is_src_port,
 		{ SR_KEMIP_INT, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
 	{ str_init(""), str_init("is_dst_port"),
 		SR_KEMIP_BOOL, sr_kemi_core_is_dst_port,
 		{ SR_KEMIP_INT, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
d63638d4
 	},
f97093fa
 	{ str_init(""), str_init("get_debug"),
 		SR_KEMIP_INT, sr_kemi_core_get_debug,
 		{ SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
d9dd2abe
 	{ str_init(""), str_init("route"),
 		SR_KEMIP_INT, sr_kemi_core_route,
 		{ SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
16a41dba
 
 	{ {0, 0}, {0, 0}, 0, NULL, { 0, 0, 0, 0, 0, 0 } }
 };
 
ff8bb9df
 /**
  *
  */
 static int sr_kemi_hdr_append(sip_msg_t *msg, str *txt)
 {
 	struct lump* anchor;
 	char *hdr;
 
 	if(txt==NULL || txt->s==NULL || msg==NULL)
 		return -1;
 
 	LM_DBG("append hf: %.*s\n", txt->len, txt->s);
 	if (parse_headers(msg, HDR_EOH_F, 0) == -1) {
 		LM_ERR("error while parsing message\n");
 		return -1;
 	}
 
 	hdr = (char*)pkg_malloc(txt->len);
 	if(hdr==NULL) {
e3ecad34
 		PKG_MEM_ERROR;
ff8bb9df
 		return -1;
 	}
 	memcpy(hdr, txt->s, txt->len);
7ab180c8
 	/* anchor after last header */
 	anchor = anchor_lump(msg, msg->unparsed - msg->buf, 0, 0);
875bd485
 	if((anchor==NULL)
 			|| (insert_new_lump_before(anchor, hdr, txt->len, 0) == 0)) {
0df40557
 		LM_ERR("can't insert lump\n");
 		pkg_free(hdr);
 		return -1;
 	}
 	return 1;
 }
 
 /**
  *
  */
 static int sr_kemi_hdr_append_after(sip_msg_t *msg, str *txt, str *hname)
 {
 	struct lump* anchor;
 	hdr_field_t *hf;
 	hdr_field_t hfm;
 	char *hdr;
 	char hbuf[SR_KEMI_HNAME_SIZE];
 
 	if(txt==NULL || txt->s==NULL || hname==NULL || hname->s==NULL || msg==NULL)
 		return -1;
 
 	if(hname->len>SR_KEMI_HNAME_SIZE-4) {
 		LM_ERR("header name too long: %d\n", hname->len);
 		return -1;
 	}
 	memcpy(hbuf, hname->s, hname->len);
 	hbuf[hname->len] = ':';
 	hbuf[hname->len+1] = '\0';
 
785bbaa0
 	parse_hname2_short(hbuf, hbuf+hname->len+1, &hfm);
 	if(hfm.type==HDR_ERROR_T) {
0df40557
 		LM_ERR("error parsing header name [%.*s]\n", hname->len, hname->s);
 		return -1;
 	}
 
 	if (parse_headers(msg, HDR_EOH_F, 0) == -1) {
 		LM_ERR("error while parsing message\n");
 		return -1;
 	}
 	for (hf=msg->headers; hf; hf=hf->next) {
 		if (hfm.type!=HDR_OTHER_T && hfm.type!=HDR_ERROR_T) {
 			if (hfm.type!=hf->type)
 				continue;
 		} else {
 			if (hf->name.len!=hfm.name.len)
 				continue;
 			if (cmp_hdrname_str(&hf->name, &hfm.name)!=0)
 				continue;
 		}
4dca6d5d
 		break;
0df40557
 	}
 
 	hdr = (char*)pkg_malloc(txt->len);
 	if(hdr==NULL) {
e3ecad34
 		PKG_MEM_ERROR;
0df40557
 		return -1;
 	}
 	memcpy(hdr, txt->s, txt->len);
 
 	if(hf==0) { /* after last header */
 		anchor = anchor_lump(msg, msg->unparsed - msg->buf, 0, 0);
 	} else { /* after hf */
 		anchor = anchor_lump(msg, hf->name.s + hf->len - msg->buf, 0, 0);
 	}
 
875bd485
 	if((anchor==NULL)
 			|| (insert_new_lump_before(anchor, hdr, txt->len, 0) == 0)) {
ff8bb9df
 		LM_ERR("can't insert lump\n");
 		pkg_free(hdr);
 		return -1;
 	}
875bd485
 	LM_DBG("appended after [%.*s] the hf: [%.*s]\n", hname->len, hname->s,
 			txt->len, txt->s);
 
ff8bb9df
 	return 1;
 }
 
 /**
  *
  */
9d6c274b
 int sr_kemi_hdr_remove(sip_msg_t *msg, str *hname)
ff8bb9df
 {
 	struct lump* anchor;
97f975fa
 	hdr_field_t *hf;
 	hdr_field_t hfm;
 	char hbuf[SR_KEMI_HNAME_SIZE];
ff8bb9df
 
97f975fa
 	if(hname==NULL || hname->s==NULL || msg==NULL)
 		return -1;
 
 	if(hname->len>SR_KEMI_HNAME_SIZE-4) {
 		LM_ERR("header name too long: %d\n", hname->len);
 		return -1;
 	}
 	memcpy(hbuf, hname->s, hname->len);
 	hbuf[hname->len] = ':';
 	hbuf[hname->len+1] = '\0';
 
785bbaa0
 	parse_hname2_short(hbuf, hbuf+hname->len+1, &hfm);
 	if(hfm.type==HDR_ERROR_T) {
97f975fa
 		LM_ERR("error parsing header name [%.*s]\n", hname->len, hname->s);
ff8bb9df
 		return -1;
97f975fa
 	}
ff8bb9df
 
 	if (parse_headers(msg, HDR_EOH_F, 0) == -1) {
 		LM_ERR("error while parsing message\n");
 		return -1;
 	}
 
97f975fa
 	LM_DBG("remove hf: %.*s\n", hname->len, hname->s);
ff8bb9df
 	for (hf=msg->headers; hf; hf=hf->next) {
97f975fa
 		if (hfm.type!=HDR_OTHER_T && hfm.type!=HDR_ERROR_T) {
 			if (hfm.type!=hf->type)
 				continue;
 		} else {
 			if (hf->name.len!=hname->len)
 				continue;
 			if(strncasecmp(hf->name.s, hname->s, hname->len)!=0)
 				continue;
 		}
 		anchor=del_lump(msg, hf->name.s - msg->buf, hf->len, 0);
 		if (anchor==0) {
 			LM_ERR("cannot remove hdr %.*s\n", hname->len, hname->s);
 			return -1;
ff8bb9df
 		}
 	}
 	return 1;
 }
 
97f975fa
 /**
  *
  */
 static int sr_kemi_hdr_is_present(sip_msg_t *msg, str *hname)
 {
 	hdr_field_t *hf;
 	hdr_field_t hfm;
 	char hbuf[SR_KEMI_HNAME_SIZE];
 
 	if(hname==NULL || hname->s==NULL || msg==NULL)
 		return -1;
 
 	if(hname->len>SR_KEMI_HNAME_SIZE-4) {
 		LM_ERR("header name too long: %d\n", hname->len);
 		return -1;
 	}
 	memcpy(hbuf, hname->s, hname->len);
 	hbuf[hname->len] = ':';
 	hbuf[hname->len+1] = '\0';
 
785bbaa0
 	parse_hname2_short(hbuf, hbuf+hname->len+1, &hfm);
 	if(hfm.type==HDR_ERROR_T) {
97f975fa
 		LM_ERR("error parsing header name [%.*s]\n", hname->len, hname->s);
 		return -1;
 	}
 
 	if (parse_headers(msg, HDR_EOH_F, 0) == -1) {
 		LM_ERR("error while parsing message\n");
 		return -1;
 	}
 
 	LM_DBG("searching hf: %.*s\n", hname->len, hname->s);
 	for (hf=msg->headers; hf; hf=hf->next) {
 		if (hfm.type!=HDR_OTHER_T && hfm.type!=HDR_ERROR_T) {
 			if (hfm.type!=hf->type)
 				continue;
 		} else {
 			if (hf->name.len!=hname->len)
 				continue;
 			if(strncasecmp(hf->name.s, hname->s, hname->len)!=0)
 				continue;
 		}
 		return 1;
 	}
 	return -1;
 }
 
ff8bb9df
 /**
  *
  */
 static int sr_kemi_hdr_insert(sip_msg_t *msg, str *txt)
 {
 	struct lump* anchor;
 	char *hdr;
 
 	if(txt==NULL || txt->s==NULL || msg==NULL)
 		return -1;
 
7bf00811
 	if ((parse_headers(msg, HDR_EOH_F, 0) == -1) || (msg->headers == NULL)) {
 		LM_ERR("error while parsing message\n");
 		return -1;
 	}
 
ff8bb9df
 	LM_DBG("insert hf: %.*s\n", txt->len, txt->s);
 	hdr = (char*)pkg_malloc(txt->len);
 	if(hdr==NULL) {
e3ecad34
 		PKG_MEM_ERROR;
ff8bb9df
 		return -1;
 	}
 	memcpy(hdr, txt->s, txt->len);
7ab180c8
 	/* anchor before first header */
 	anchor = anchor_lump(msg, msg->headers->name.s - msg->buf, 0, 0);
875bd485
 	if((anchor==NULL)
 			|| (insert_new_lump_before(anchor, hdr, txt->len, 0) == 0)) {
ff8bb9df
 		LM_ERR("can't insert lump\n");
 		pkg_free(hdr);
 		return -1;
 	}
 	return 1;
 }
 
0df40557
 /**
  *
  */
 static int sr_kemi_hdr_insert_before(sip_msg_t *msg, str *txt, str *hname)
 {
 	struct lump* anchor;
 	hdr_field_t *hf;
 	hdr_field_t hfm;
 	char *hdr;
 	char hbuf[SR_KEMI_HNAME_SIZE];
 
 	if(txt==NULL || txt->s==NULL || hname==NULL || hname->s==NULL || msg==NULL)
 		return -1;
 
 	if(hname->len>SR_KEMI_HNAME_SIZE-4) {
 		LM_ERR("header name too long: %d\n", hname->len);
 		return -1;
 	}
 	memcpy(hbuf, hname->s, hname->len);
 	hbuf[hname->len] = ':';
 	hbuf[hname->len+1] = '\0';
 
785bbaa0
 	parse_hname2_short(hbuf, hbuf+hname->len+1, &hfm);
 	if(hfm.type==HDR_ERROR_T) {
0df40557
 		LM_ERR("error parsing header name [%.*s]\n", hname->len, hname->s);
 		return -1;
 	}
 
7bf00811
 	if ((parse_headers(msg, HDR_EOH_F, 0) == -1) || (msg->headers == NULL)) {
0df40557
 		LM_ERR("error while parsing message\n");
 		return -1;
 	}
 	for (hf=msg->headers; hf; hf=hf->next) {
 		if (hfm.type!=HDR_OTHER_T && hfm.type!=HDR_ERROR_T) {
 			if (hfm.type!=hf->type)
 				continue;
 		} else {
 			if (hf->name.len!=hfm.name.len)
 				continue;
 			if (cmp_hdrname_str(&hf->name, &hfm.name)!=0)
 				continue;
 		}
4dca6d5d
 		break;
0df40557
 	}
 
 	hdr = (char*)pkg_malloc(txt->len);
 	if(hdr==NULL) {
e3ecad34
 		PKG_MEM_ERROR;
0df40557
 		return -1;
 	}
 	memcpy(hdr, txt->s, txt->len);
 	if(hf==0) { /* before first header */
 		anchor = anchor_lump(msg, msg->headers->name.s - msg->buf, 0, 0);
 	} else { /* before hf */
 		anchor = anchor_lump(msg, hf->name.s - msg->buf, 0, 0);
 	}
875bd485
 	if((anchor==NULL)
 			|| (insert_new_lump_before(anchor, hdr, txt->len, 0) == 0)) {
0df40557
 		LM_ERR("can't insert lump\n");
 		pkg_free(hdr);
 		return -1;
 	}
875bd485
 	LM_DBG("inserted before [%.*s] the hf: %.*s\n", hname->len, hname->s,
 			txt->len, txt->s);
 
0df40557
 	return 1;
 }
 
92b8d7aa
 /**
  *
  */
 static int sr_kemi_hdr_rmappend(sip_msg_t *msg, str *hrm, str *hadd)
 {
 	int ret;
 
 	ret = sr_kemi_hdr_remove(msg, hrm);
 	if(ret<0) {
 		return ret;
 	}
 	return sr_kemi_hdr_append(msg, hadd);
 }
 
bb66d054
 /**
  *
  */
 static int sr_kemi_hdr_rminsert(sip_msg_t *msg, str *hrm, str *hadd)
 {
 	int ret;
 
 	ret = sr_kemi_hdr_remove(msg, hrm);
 	if(ret<0) {
 		return ret;
 	}
 	return sr_kemi_hdr_insert(msg, hadd);
 }
 
 
ff8bb9df
 /**
  *
  */
 static int sr_kemi_hdr_append_to_reply(sip_msg_t *msg, str *txt)
 {
 	if(txt==NULL || txt->s==NULL || msg==NULL)
 		return -1;
 
 	LM_DBG("append to reply: %.*s\n", txt->len, txt->s);
 
 	if(add_lump_rpl(msg, txt->s, txt->len, LUMP_RPL_HDR)==0) {
 		LM_ERR("unable to add reply lump\n");
 		return -1;
 	}
 
 	return 1;
 }
 
9d33196d
 /**
  *
  */
166ef92d
 static sr_kemi_xval_t* sr_kemi_hdr_get_mode(sip_msg_t *msg, str *hname, int idx,
 		int rmode)
9d33196d
 {
 	hdr_field_t shdr;
 	hdr_field_t *ihdr;
166ef92d
 #define SR_KEMI_VHDR_SIZE 256
 	hdr_field_t *vhdr[SR_KEMI_VHDR_SIZE];
 	int n;
 	int hmatch;
9d33196d
 
 	memset(&_sr_kemi_xval, 0, sizeof(sr_kemi_xval_t));
 
 	if(msg==NULL) {
 		sr_kemi_xval_null(&_sr_kemi_xval, rmode);
 		return &_sr_kemi_xval;
 	}
 	/* we need to be sure we have parsed all headers */
 	if(parse_headers(msg, HDR_EOH_F, 0)<0) {
 		LM_ERR("error parsing headers\n");
 		sr_kemi_xval_null(&_sr_kemi_xval, rmode);
 		return &_sr_kemi_xval;
 	}
785bbaa0
 	parse_hname2_str(hname, &shdr);
 	if(shdr.type==HDR_ERROR_T) {
432c7dd3
 		LM_ERR("error parsing header name [%.*s]\n", hname->len, hname->s);
9d33196d
 		sr_kemi_xval_null(&_sr_kemi_xval, rmode);
 		return &_sr_kemi_xval;
 	}
 
166ef92d
 	n = 0;
9d33196d
 	for (ihdr=msg->headers; ihdr; ihdr=ihdr->next) {
166ef92d
 		hmatch = 0;
9d33196d
 		if (shdr.type!=HDR_OTHER_T && shdr.type!=HDR_ERROR_T) {
 			/* find by type */
 			if (shdr.type==ihdr->type) {
166ef92d
 				hmatch = 1;
9d33196d
 			}
 		} else {
 			/* find by name */
 			if (cmp_hdrname_str(&ihdr->name, hname)==0) {
166ef92d
 				hmatch = 1;
 			}
 		}
 		if (hmatch == 1) {
 			if(idx==n) {
9d33196d
 				break;
166ef92d
 			} else {
 				if(idx<0) {
 					vhdr[n] = ihdr;
 				}
 				n++;
 				if(n==SR_KEMI_VHDR_SIZE) {
 					LM_DBG("too many headers with name: %.*s\n",
 							hname->len, hname->s);
 					sr_kemi_xval_null(&_sr_kemi_xval, rmode);
 					return &_sr_kemi_xval;
 				}
9d33196d
 			}
 		}
 	}
166ef92d
 	if(idx>=0) {
 		if(ihdr==NULL) {
 			sr_kemi_xval_null(&_sr_kemi_xval, rmode);
 			return &_sr_kemi_xval;
 		}
 	} else {
 		if(n + idx < 0) {
 			sr_kemi_xval_null(&_sr_kemi_xval, rmode);
 			return &_sr_kemi_xval;
 		}
 		ihdr = vhdr[n + idx];
9d33196d
 	}
 
 	_sr_kemi_xval.vtype = SR_KEMIP_STR;
 	_sr_kemi_xval.v.s = ihdr->body;
 	return &_sr_kemi_xval;
 }
 
 /**
  *
  */
 static sr_kemi_xval_t* sr_kemi_hdr_get(sip_msg_t *msg, str *hname)
 {
166ef92d
 	return sr_kemi_hdr_get_mode(msg, hname, 0, SR_KEMI_XVAL_NULL_NONE);
9d33196d
 }
 
 /**
  *
  */
 static sr_kemi_xval_t* sr_kemi_hdr_gete(sip_msg_t *msg, str *hname)
 {
166ef92d
 	return sr_kemi_hdr_get_mode(msg, hname, 0, SR_KEMI_XVAL_NULL_EMPTY);
9d33196d
 }
 
 /**
  *
  */
 static sr_kemi_xval_t* sr_kemi_hdr_getw(sip_msg_t *msg, str *hname)
 {
166ef92d
 	return sr_kemi_hdr_get_mode(msg, hname, 0, SR_KEMI_XVAL_NULL_PRINT);
 }
 
 /**
  *
  */
 static sr_kemi_xval_t* sr_kemi_hdr_get_idx(sip_msg_t *msg, str *hname, int idx)
 {
 	return sr_kemi_hdr_get_mode(msg, hname, idx, SR_KEMI_XVAL_NULL_NONE);
 }
 
 /**
  *
  */
 static sr_kemi_xval_t* sr_kemi_hdr_gete_idx(sip_msg_t *msg, str *hname, int idx)
 {
 	return sr_kemi_hdr_get_mode(msg, hname, idx, SR_KEMI_XVAL_NULL_EMPTY);
 }
 
 /**
  *
  */
 static sr_kemi_xval_t* sr_kemi_hdr_getw_idx(sip_msg_t *msg, str *hname, int idx)
 {
 	return sr_kemi_hdr_get_mode(msg, hname, idx, SR_KEMI_XVAL_NULL_PRINT);
9d33196d
 }
 
b84b67a0
 /**
  *
  */
 static int sr_kemi_hdr_match_content(sip_msg_t *msg, str *hname, str *op,
 		str *mval, str *hidx)
 {
 	hdr_field_t *hf;
 	hdr_field_t hfm;
 	int opval = 0;
 	int hidxval = 0;
 	int matched = 0;
 	int hnum = 0;
 	str hbody = STR_NULL;
 
 	if(hname==NULL || hname->s==NULL || msg==NULL) {
 		return SR_KEMI_FALSE;
 	}
 
785bbaa0
 	parse_hname2_str(hname, &hfm);
 	if(hfm.type==HDR_ERROR_T) {
b84b67a0
 		LM_ERR("error parsing header name [%.*s]\n", hname->len, hname->s);
 		return SR_KEMI_FALSE;
 	}
 
 	if (parse_headers(msg, HDR_EOH_F, 0) == -1) {
 		LM_ERR("error while parsing message\n");
 		return SR_KEMI_FALSE;
 	}
 
 	if(op->len == 2) {
 		if(strncasecmp(op->s, "eq", 2) == 0) {
 			opval = 1;
3d4f5fca
 		} else if(strncasecmp(op->s, "ne", 2) == 0) {
b84b67a0
 			opval = 2;
3d4f5fca
 		} else if(strncasecmp(op->s, "sw", 2) == 0) {
b84b67a0
 			opval = 3;
3d4f5fca
 		} else if(strncasecmp(op->s, "in", 2) == 0) {
b84b67a0
 			opval = 4;
3d4f5fca
 		} else if(strncasecmp(op->s, "re", 2) == 0) {
b84b67a0
 			opval = 5;
 			LM_ERR("operator not implemented: %.*s\n", op->len, op->s);
 			return SR_KEMI_FALSE;
 		} else {
 			LM_ERR("invalid operator: %.*s\n", op->len, op->s);
 			return SR_KEMI_FALSE;
 		}
 	} else {
 		LM_ERR("invalid operator: %.*s\n", op->len, op->s);
 		return SR_KEMI_FALSE;
 	}
 
 
 	if(hidx->len >= 1) {
 		if(hidx->s[0]=='f' || hidx->s[0]=='F') {
 			/* first */
 			hidxval = 1;
 		} else if(hidx->s[0]=='l' || hidx->s[0]=='L') {
 			/* last */
 			hidxval = 2;
3d4f5fca
 		} else if(hidx->s[0]=='a' || hidx->s[0]=='A') {
b84b67a0
 			/* all */
 			hidxval = 3;
 		} else if(hidx->s[0]=='o' || hidx->s[0]=='O') {
 			/* one - at least one */
 			hidxval = 4;
 		} else {
 			LM_ERR("invalid header index: %.*s\n", hidx->len, hidx->s);
 			return SR_KEMI_FALSE;
 		}
 	} else {
 		LM_ERR("invalid header index: %.*s\n", hidx->len, hidx->s);
 		return SR_KEMI_FALSE;
 	}
 
 	LM_DBG("searching hf: %.*s\n", hname->len, hname->s);
 	for (hf=msg->headers; hf; hf=hf->next) {
 		if (hfm.type!=HDR_OTHER_T && hfm.type!=HDR_ERROR_T) {
 			if (hfm.type!=hf->type) {
 				continue;
 			}
 		} else {
 			if (hf->name.len!=hname->len) {
 				continue;
 			}
 			if(strncasecmp(hf->name.s, hname->s, hname->len)!=0) {
 				continue;
 			}
 		}
 		hnum++;
 		matched = 0;
 		hbody = hf->body;
 		trim(&hbody);
 		switch(opval) {
 			case 1:
 			case 2:
 				if(mval->len != hbody.len) {
 					if(opval == 2) {
 						/* ne */
 						matched = 1;
 					}
 				} else {
 					if(strncasecmp(mval->s, hbody.s, hbody.len) == 0) {
 						if(opval == 1) {
 							/* eq */
 							matched = 1;
 						}
 					}
 				}
 				break;
 			case 3:
 				/* sw */
 				if(hbody.len >= mval->len) {
 					if(strncasecmp(hbody.s, mval->s, mval->len) == 0) {
 						matched = 1;
 					}
 				}
 				break;
 			case 4:
 				/* in */
 				if(hbody.len >= mval->len) {
 					if(str_casesearch(&hbody, mval) != NULL) {
 						matched = 1;
 					}
 				}
 				break;
 			case 5:
 				/* re */
 				break;
 		}
 		if(hnum==1 && hidxval==1) {
 			/* first */
 			if(matched == 1) {
 				return SR_KEMI_TRUE;
 			} else {
 				return SR_KEMI_FALSE;
 			}
 		}
 		if(hidxval==3) {
 			/* all */
 			if(matched == 0) {
 				return SR_KEMI_FALSE;
 			}
 		}
 		if(hidxval==4) {
 			/* one */
 			if(matched == 1) {
 				return SR_KEMI_TRUE;
 			}
 		}
 	}
 
 	/* last - all */
 	if(matched == 1) {
 		return SR_KEMI_TRUE;
 	} else {
 		return SR_KEMI_FALSE;
 	}
 }
 
 
ff8bb9df
 /**
  *
  */
 static sr_kemi_t _sr_kemi_hdr[] = {
 	{ str_init("hdr"), str_init("append"),
 		SR_KEMIP_INT, sr_kemi_hdr_append,
 		{ SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
0df40557
 	{ str_init("hdr"), str_init("append_after"),
 		SR_KEMIP_INT, sr_kemi_hdr_append_after,
 		{ SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
ff8bb9df
 	{ str_init("hdr"), str_init("insert"),
 		SR_KEMIP_INT, sr_kemi_hdr_insert,
 		{ SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
0df40557
 	{ str_init("hdr"), str_init("insert_before"),
 		SR_KEMIP_INT, sr_kemi_hdr_insert_before,
 		{ SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
ff8bb9df
 	{ str_init("hdr"), str_init("remove"),
 		SR_KEMIP_INT, sr_kemi_hdr_remove,
 		{ SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
92b8d7aa
 	{ str_init("hdr"), str_init("rmappend"),
 		SR_KEMIP_INT, sr_kemi_hdr_rmappend,
 		{ SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
bb66d054
 	{ str_init("hdr"), str_init("rminsert"),
 		SR_KEMIP_INT, sr_kemi_hdr_rminsert,
 		{ SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
97f975fa
 	{ str_init("hdr"), str_init("is_present"),
 		SR_KEMIP_INT, sr_kemi_hdr_is_present,
 		{ SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
ff8bb9df
 	{ str_init("hdr"), str_init("append_to_reply"),
 		SR_KEMIP_INT, sr_kemi_hdr_append_to_reply,
 		{ SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
9d33196d
 	{ str_init("hdr"), str_init("get"),
 		SR_KEMIP_XVAL, sr_kemi_hdr_get,
 		{ SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
 	{ str_init("hdr"), str_init("gete"),
 		SR_KEMIP_XVAL, sr_kemi_hdr_gete,
 		{ SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
 	{ str_init("hdr"), str_init("getw"),
 		SR_KEMIP_XVAL, sr_kemi_hdr_getw,
 		{ SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
166ef92d
 	{ str_init("hdr"), str_init("get_idx"),
 		SR_KEMIP_XVAL, sr_kemi_hdr_get_idx,
 		{ SR_KEMIP_STR, SR_KEMIP_INT, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
 	{ str_init("hdr"), str_init("gete_idx"),
 		SR_KEMIP_XVAL, sr_kemi_hdr_gete_idx,
 		{ SR_KEMIP_STR, SR_KEMIP_INT, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
 	{ str_init("hdr"), str_init("getw_idx"),
 		SR_KEMIP_XVAL, sr_kemi_hdr_getw_idx,
 		{ SR_KEMIP_STR, SR_KEMIP_INT, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
b84b67a0
 	{ str_init("hdr"), str_init("match_content"),
 		SR_KEMIP_BOOL, sr_kemi_hdr_match_content,
 		{ SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_STR,
 			SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
ff8bb9df
 
 	{ {0, 0}, {0, 0}, 0, NULL, { 0, 0, 0, 0, 0, 0 } }
 };
 
64f744e9
 
 /**
  *
  */
850681da
 void sr_kemi_xval_null(sr_kemi_xval_t *xval, int rmode)
64f744e9
 {
e46dcd29
 	switch(rmode) {
 		case SR_KEMI_XVAL_NULL_PRINT:
 			xval->vtype = SR_KEMIP_STR;
 			xval->v.s = *pv_get_null_str();
 			return;
 		case SR_KEMI_XVAL_NULL_EMPTY:
 			xval->vtype = SR_KEMIP_STR;
 			xval->v.s = *pv_get_empty_str();
 			return;
 		case SR_KEMI_XVAL_NULL_ZERO:
 			xval->vtype = SR_KEMIP_INT;
 			xval->v.n = 0;
 			return;
 		default:
 			xval->vtype = SR_KEMIP_NULL;
 			xval->v.s.s = NULL;
 			xval->v.s.len = 0;
 			return;
64f744e9
 	}
 }
 
8f753d10
 /**
  *
  */
 void sr_kemi_dict_item_free(sr_kemi_dict_item_t *item)
 {
 	sr_kemi_dict_item_t *v;
 
 	while(item) {
 		if (item->vtype == SR_KEMIP_ARRAY || item->vtype == SR_KEMIP_DICT) {
 			sr_kemi_dict_item_free(item->v.dict);
 		}
 		v = item;
 		item = item->next;
 		pkg_free(v);
 	}
 }
 
 /**
  *
  */
 void sr_kemi_xval_free(sr_kemi_xval_t *xval)
 {
 	if(xval && (xval->vtype == SR_KEMIP_ARRAY || xval->vtype == SR_KEMIP_DICT))
 	{
 		sr_kemi_dict_item_free(xval->v.dict);
 	}
 }
 
64f744e9
 /**
  *
  */
 static sr_kemi_xval_t* sr_kemi_pv_get_mode(sip_msg_t *msg, str *pvn, int rmode)
 {
 	pv_spec_t *pvs;
 	pv_value_t val;
 	int pl;
 
 	memset(&_sr_kemi_xval, 0, sizeof(sr_kemi_xval_t));
 
 	LM_DBG("pv get: %.*s\n", pvn->len, pvn->s);
 	pl = pv_locate_name(pvn);
 	if(pl != pvn->len) {
 		LM_ERR("invalid pv [%.*s] (%d/%d)\n", pvn->len, pvn->s, pl, pvn->len);
850681da
 		sr_kemi_xval_null(&_sr_kemi_xval, rmode);
64f744e9
 		return &_sr_kemi_xval;
 	}
 	pvs = pv_cache_get(pvn);
 	if(pvs==NULL) {
 		LM_ERR("cannot get pv spec for [%.*s]\n", pvn->len, pvn->s);
850681da
 		sr_kemi_xval_null(&_sr_kemi_xval, rmode);
64f744e9
 		return &_sr_kemi_xval;
 	}
 
 	memset(&val, 0, sizeof(pv_value_t));
 	if(pv_get_spec_value(msg, pvs, &val) != 0) {
 		LM_ERR("unable to get pv value for [%.*s]\n", pvn->len, pvn->s);
850681da
 		sr_kemi_xval_null(&_sr_kemi_xval, rmode);
64f744e9
 		return &_sr_kemi_xval;
 	}
 	if(val.flags&PV_VAL_NULL) {
850681da
 		sr_kemi_xval_null(&_sr_kemi_xval, rmode);
64f744e9
 		return &_sr_kemi_xval;
 	}
 	if(val.flags&PV_TYPE_INT) {
 		_sr_kemi_xval.vtype = SR_KEMIP_INT;
 		_sr_kemi_xval.v.n = val.ri;
 		return &_sr_kemi_xval;
 	}
 	_sr_kemi_xval.vtype = SR_KEMIP_STR;
 	_sr_kemi_xval.v.s = val.rs;
 	return &_sr_kemi_xval;
 }
 
 /**
  *
  */
 static sr_kemi_xval_t* sr_kemi_pv_get(sip_msg_t *msg, str *pvn)
 {
e91d9562
 	return sr_kemi_pv_get_mode(msg, pvn, SR_KEMI_XVAL_NULL_NONE);
64f744e9
 }
 
 /**
  *
  */
 static sr_kemi_xval_t* sr_kemi_pv_getw(sip_msg_t *msg, str *pvn)
 {
e91d9562
 	return sr_kemi_pv_get_mode(msg, pvn, SR_KEMI_XVAL_NULL_PRINT);
64f744e9
 }
 
 /**
  *
  */
 static sr_kemi_xval_t* sr_kemi_pv_gete(sip_msg_t *msg, str *pvn)
 {
e91d9562
 	return sr_kemi_pv_get_mode(msg, pvn, SR_KEMI_XVAL_NULL_EMPTY);
64f744e9
 }
 
 /**
  *
  */
 static void sr_kemi_pv_push_valx (sr_kemi_xval_t *xval, int rmode, int vi, str *vs)
 {
 	if(rmode==1) {
 		xval->vtype = SR_KEMIP_INT;
 		xval->v.n = vi;
 	} else {
 		xval->vtype = SR_KEMIP_STR;
 		xval->v.s = *vs;
 	}
 }
 
 /**
  *
  */
 static sr_kemi_xval_t* sr_kemi_pv_get_valx (sip_msg_t *msg, str *pvn, str *xsval,
 		int xival, int rmode)
 {
 	pv_spec_t *pvs;
 	pv_value_t val;
 	int pl;
 
 	memset(&_sr_kemi_xval, 0, sizeof(sr_kemi_xval_t));
 
 	LM_DBG("pv get: %.*s\n", pvn->len, pvn->s);
 	pl = pv_locate_name(pvn);
 	if(pl != pvn->len) {
 		LM_ERR("invalid pv [%.*s] (%d/%d)\n", pvn->len, pvn->s, pl, pvn->len);
 		sr_kemi_pv_push_valx(&_sr_kemi_xval, rmode, xival, xsval);
 		return &_sr_kemi_xval;
 	}
 	pvs = pv_cache_get(pvn);
 	if(pvs==NULL) {
 		LM_ERR("cannot get pv spec for [%.*s]\n", pvn->len, pvn->s);
 		sr_kemi_pv_push_valx(&_sr_kemi_xval, rmode, xival, xsval);
 		return &_sr_kemi_xval;
 	}
 
 	memset(&val, 0, sizeof(pv_value_t));
 	if(pv_get_spec_value(msg, pvs, &val) != 0) {
 		LM_ERR("unable to get pv value for [%.*s]\n", pvn->len, pvn->s);
 		sr_kemi_pv_push_valx(&_sr_kemi_xval, rmode, xival, xsval);
 		return &_sr_kemi_xval;
 	}
 	if(val.flags&PV_VAL_NULL) {
 		sr_kemi_pv_push_valx(&_sr_kemi_xval, rmode, xival, xsval);
 		return &_sr_kemi_xval;
 	}
 	if(val.flags&PV_TYPE_INT) {
 		_sr_kemi_xval.vtype = SR_KEMIP_INT;
 		_sr_kemi_xval.v.n = val.ri;
 		return &_sr_kemi_xval;
 	}
 	_sr_kemi_xval.vtype = SR_KEMIP_STR;
 	_sr_kemi_xval.v.s = val.rs;
 	return &_sr_kemi_xval;
 }
 
 /**
  *
  */
 static sr_kemi_xval_t* sr_kemi_pv_getvs (sip_msg_t *msg, str *pvn, str *xsval)
 {
 	return sr_kemi_pv_get_valx (msg, pvn, xsval, 0, 0);
 }
 
 /**
  *
  */
 static sr_kemi_xval_t* sr_kemi_pv_getvn (sip_msg_t *msg, str *pvn, int xival)
 {
 	return sr_kemi_pv_get_valx (msg, pvn, NULL, xival, 1);
 }
 
71d7d583
 /**
  *
  */
 static int sr_kemi_pv_geti (sip_msg_t *msg, str *pvn)
 {
 	pv_spec_t *pvs;
 	pv_value_t val;
 	int vi;
 
 	LM_DBG("pv get: %.*s\n", pvn->len, pvn->s);
 	vi = pv_locate_name(pvn);
 	if(vi != pvn->len) {
 		LM_WARN("invalid pv [%.*s] (%d/%d)\n", pvn->len, pvn->s, vi, pvn->len);
 		return 0;
 	}
 	pvs = pv_cache_get(pvn);
 	if(pvs==NULL) {
 		LM_WARN("cannot get pv spec for [%.*s]\n", pvn->len, pvn->s);
 		return 0;
 	}
 
 	memset(&val, 0, sizeof(pv_value_t));
 	if(pv_get_spec_value(msg, pvs, &val) != 0) {
 		LM_WARN("unable to get pv value for [%.*s]\n", pvn->len, pvn->s);
 		return 0;
 	}
 	if(val.flags&PV_VAL_NULL) {
 		return 0;
 	}
 	if(val.flags&(PV_TYPE_INT|PV_VAL_INT)) {
 		return val.ri;
 	}
 	if(val.ri!=0) {
 		return val.ri;
 	}
 	vi = 0;
 	str2sint(&val.rs, &vi);
 
 	return vi;
 }
 
64f744e9
 /**
  *
  */
 static int sr_kemi_pv_seti (sip_msg_t *msg, str *pvn, int ival)
 {
 	pv_spec_t *pvs;
 	pv_value_t val;
 	int pl;
 
 	LM_DBG("pv get: %.*s\n", pvn->len, pvn->s);
 	pl = pv_locate_name(pvn);
 	if(pl != pvn->len) {
 		LM_ERR("invalid pv [%.*s] (%d/%d)\n", pvn->len, pvn->s, pl, pvn->len);
 		return SR_KEMI_FALSE;
 	}
 	pvs = pv_cache_get(pvn);
 	if(pvs==NULL) {
 		LM_ERR("cannot get pv spec for [%.*s]\n", pvn->len, pvn->s);
 		return SR_KEMI_FALSE;
 	}
 
 	memset(&val, 0, sizeof(pv_value_t));
 	val.ri = ival;
 	val.flags |= PV_TYPE_INT|PV_VAL_INT;
 
 	if(pv_set_spec_value(msg, pvs, 0, &val)<0) {
 		LM_ERR("unable to set pv [%.*s]\n", pvn->len, pvn->s);
 		return SR_KEMI_FALSE;
 	}
 
 	return SR_KEMI_TRUE;
 }
 
 /**
  *
  */
 static int sr_kemi_pv_sets (sip_msg_t *msg, str *pvn, str *sval)
 {
 	pv_spec_t *pvs;
 	pv_value_t val;
 	int pl;
 
 	LM_DBG("pv set: %.*s\n", pvn->len, pvn->s);
 	pl = pv_locate_name(pvn);
 	if(pl != pvn->len) {
 		LM_ERR("invalid pv [%.*s] (%d/%d)\n", pvn->len, pvn->s, pl, pvn->len);
 		return SR_KEMI_FALSE;
 	}
 	pvs = pv_cache_get(pvn);
 	if(pvs==NULL) {
 		LM_ERR("cannot get pv spec for [%.*s]\n", pvn->len, pvn->s);
 		return SR_KEMI_FALSE;
 	}
 
 	memset(&val, 0, sizeof(pv_value_t));
 	val.rs = *sval;
 	val.flags |= PV_VAL_STR;
 
 	if(pv_set_spec_value(msg, pvs, 0, &val)<0) {
 		LM_ERR("unable to set pv [%.*s]\n", pvn->len, pvn->s);
 		return SR_KEMI_FALSE;
 	}
 
 	return SR_KEMI_TRUE;
 }
 
 /**
  *
  */
 static int sr_kemi_pv_unset (sip_msg_t *msg, str *pvn)
 {
 	pv_spec_t *pvs;
 	pv_value_t val;
 	int pl;
 
 	LM_DBG("pv unset: %.*s\n", pvn->len, pvn->s);
 	pl = pv_locate_name(pvn);
 	if(pl != pvn->len) {
 		LM_ERR("invalid pv [%.*s] (%d/%d)\n", pvn->len, pvn->s, pl, pvn->len);
 		return SR_KEMI_FALSE;
 	}
 	pvs = pv_cache_get(pvn);
 	if(pvs==NULL) {
 		LM_ERR("cannot get pv spec for [%.*s]\n", pvn->len, pvn->s);
 		return SR_KEMI_FALSE;
 	}
 	memset(&val, 0, sizeof(pv_value_t));
 	val.flags |= PV_VAL_NULL;
 	if(pv_set_spec_value(msg, pvs, 0, &val)<0) {
 		LM_ERR("unable to unset pv [%.*s]\n", pvn->len, pvn->s);
 		return SR_KEMI_FALSE;
 	}
 
 	return SR_KEMI_TRUE;
 }
 
 /**
  *
  */
 static int sr_kemi_pv_is_null (sip_msg_t *msg, str *pvn)
 {
 	pv_spec_t *pvs;
 	pv_value_t val;
 	int pl;
 
 	LM_DBG("pv is null test: %.*s\n", pvn->len, pvn->s);
 	pl = pv_locate_name(pvn);
 	if(pl != pvn->len) {
 		LM_ERR("invalid pv [%.*s] (%d/%d)\n", pvn->len, pvn->s, pl, pvn->len);
 		return SR_KEMI_TRUE;
 	}
 	pvs = pv_cache_get(pvn);
 	if(pvs==NULL) {
 		LM_ERR("cannot get pv spec for [%.*s]\n", pvn->len, pvn->s);
 		return SR_KEMI_TRUE;
 	}
 
 	memset(&val, 0, sizeof(pv_value_t));
 	if(pv_get_spec_value(msg, pvs, &val) != 0) {
 		LM_NOTICE("unable to get pv value for [%.*s]\n", pvn->len, pvn->s);
 		return SR_KEMI_TRUE;
 	}
 	if(val.flags&PV_VAL_NULL) {
 		return SR_KEMI_TRUE;
 	} else {
 		return SR_KEMI_FALSE;
 	}
 }
 
 /**
  *
  */
 static sr_kemi_t _sr_kemi_pv[] = {
 	{ str_init("pv"), str_init("get"),
 		SR_KEMIP_XVAL, sr_kemi_pv_get,
 		{ SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
 	{ str_init("pv"), str_init("getw"),
 		SR_KEMIP_XVAL, sr_kemi_pv_getw,
 		{ SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
 	{ str_init("pv"), str_init("gete"),
 		SR_KEMIP_XVAL, sr_kemi_pv_gete,
 		{ SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
71d7d583
 	{ str_init("pv"), str_init("geti"),
 		SR_KEMIP_INT, sr_kemi_pv_geti,
 		{ SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
64f744e9
 	{ str_init("pv"), str_init("getvn"),
 		SR_KEMIP_XVAL, sr_kemi_pv_getvn,
 		{ SR_KEMIP_STR, SR_KEMIP_INT, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
 	{ str_init("pv"), str_init("getvs"),
 		SR_KEMIP_XVAL, sr_kemi_pv_getvs,
 		{ SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
 	{ str_init("pv"), str_init("seti"),
 		SR_KEMIP_BOOL, sr_kemi_pv_seti,
 		{ SR_KEMIP_STR, SR_KEMIP_INT, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
 	{ str_init("pv"), str_init("sets"),
 		SR_KEMIP_BOOL, sr_kemi_pv_sets,
 		{ SR_KEMIP_STR, SR_KEMIP_STR, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
 	{ str_init("pv"), str_init("unset"),
 		SR_KEMIP_BOOL, sr_kemi_pv_unset,
 		{ SR_KEMIP_STR, SR_KEMIP_NONE, SR_KEMIP_NONE,
 			SR_KEMIP_NONE, SR_KEMIP_NONE, SR_KEMIP_NONE }
 	},
 	{ str_init("pv"), str_init("is_null"),
 		SR_KEMIP_BOOL, sr_kemi_pv_is_null,
 		{ 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 } }
 };
 
 /**
  *
  */
 sr_kemi_t* sr_kemi_exports_get_pv(void)
 {
 	return _sr_kemi_pv;
 }
 
1f8ab5a6
 #define SR_KEMI_MODULES_MAX_SIZE	1024
ff8bb9df
 static int _sr_kemi_modules_size = 0;
1f8ab5a6
 static sr_kemi_module_t _sr_kemi_modules[SR_KEMI_MODULES_MAX_SIZE];
 
 /**
  *
  */
 int sr_kemi_modules_add(sr_kemi_t *klist)
 {
 	if(_sr_kemi_modules_size>=SR_KEMI_MODULES_MAX_SIZE) {
f1e2e12e
 		LM_ERR("exceeded max number of modules\n");
1f8ab5a6
 		return -1;
 	}
ff8bb9df
 	if(_sr_kemi_modules_size==0) {
1f8ab5a6
 		LM_DBG("adding core module\n");
ff8bb9df
 		_sr_kemi_modules[_sr_kemi_modules_size].mname = _sr_kemi_core[0].mname;
 		_sr_kemi_modules[_sr_kemi_modules_size].kexp = _sr_kemi_core;
 		_sr_kemi_modules_size++;
2e95afb3
 		LM_DBG("adding pv module\n");
 		_sr_kemi_modules[_sr_kemi_modules_size].mname = _sr_kemi_pv[0].mname;
 		_sr_kemi_modules[_sr_kemi_modules_size].kexp = _sr_kemi_pv;
 		_sr_kemi_modules_size++;
ff8bb9df
 		LM_DBG("adding hdr module\n");
 		_sr_kemi_modules[_sr_kemi_modules_size].mname = _sr_kemi_hdr[0].mname;
 		_sr_kemi_modules[_sr_kemi_modules_size].kexp = _sr_kemi_hdr;
 		_sr_kemi_modules_size++;
1f8ab5a6
 	}
2fe556a1
 	if((_sr_kemi_modules_size>1)
 			&& (_sr_kemi_modules[_sr_kemi_modules_size-1].mname.len
 					==klist[0].mname.len)
 			&& (strncmp(_sr_kemi_modules[_sr_kemi_modules_size-1].mname.s,
 					klist[0].mname.s, klist[0].mname.len)==0)) {
 		/* handle re-open of the module */
 		LM_DBG("updating module: %.*s\n", klist[0].mname.len, klist[0].mname.s);
 		_sr_kemi_modules[_sr_kemi_modules_size-1].kexp = klist;
 	} else {
 		LM_DBG("adding module: %.*s\n", klist[0].mname.len, klist[0].mname.s);
 		_sr_kemi_modules[_sr_kemi_modules_size].mname = klist[0].mname;
 		_sr_kemi_modules[_sr_kemi_modules_size].kexp = klist;
 		_sr_kemi_modules_size++;
 	}
1f8ab5a6
 	return 0;
 }
 
 /**
  *
  */
 int sr_kemi_modules_size_get(void)
 {
 	return _sr_kemi_modules_size;
 }
 
 /**
  *
  */
 sr_kemi_module_t* sr_kemi_modules_get(void)
 {
 	return _sr_kemi_modules;
 }
 
16a41dba
 /**
  *
  */
 sr_kemi_t* sr_kemi_lookup(str *mname, int midx, str *fname)
 {
 	int i;
 	sr_kemi_t *ket;
 
 	if(mname==NULL || mname->len<=0) {
08854a87
 		for(i=0; _sr_kemi_core[i].fname.s!=NULL; i++) {
16a41dba
 			ket = &_sr_kemi_core[i];
 			if(ket->fname.len==fname->len
 					&& strncasecmp(ket->fname.s, fname->s, fname->len)==0) {
 				return ket;
 			}
 		}
 	} else {
 		if(midx>0 && midx<SR_KEMI_MODULES_MAX_SIZE) {
1f8ab5a6
 			for(i=0; _sr_kemi_modules[midx].kexp[i].fname.s!=NULL; i++) {
16a41dba
 				ket = &_sr_kemi_modules[midx].kexp[i];
 				if(ket->fname.len==fname->len
 						&& strncasecmp(ket->fname.s, fname->s, fname->len)==0) {
 					return ket;
 				}
 			}
 		}
 	}
 	return NULL;
 }
d0436602
 
 /**
  *
  */
 
 #define SR_KEMI_ENG_LIST_MAX_SIZE	8
 static sr_kemi_eng_t _sr_kemi_eng_list[SR_KEMI_ENG_LIST_MAX_SIZE];
 sr_kemi_eng_t *_sr_kemi_eng = NULL;
 static int _sr_kemi_eng_list_size=0;
 
 /**
  *
  */
 int sr_kemi_eng_register(str *ename, sr_kemi_eng_route_f froute)
 {
 	int i;
 
 	for(i=0; i<_sr_kemi_eng_list_size; i++) {
 		if(_sr_kemi_eng_list[i].ename.len==ename->len
 				&& strncasecmp(_sr_kemi_eng_list[i].ename.s, ename->s,
 					ename->len)==0) {
 			/* found */
 			return 1;
 		}
 	}
 	if(_sr_kemi_eng_list_size>=SR_KEMI_ENG_LIST_MAX_SIZE) {
 		LM_ERR("too many config routing engines registered\n");
 		return -1;
 	}
 	if(ename->len>=SR_KEMI_BNAME_SIZE) {
 		LM_ERR("config routing engine name too long\n");
 		return -1;
 	}
 	strncpy(_sr_kemi_eng_list[_sr_kemi_eng_list_size].bname,
 			ename->s, ename->len);
 	_sr_kemi_eng_list[_sr_kemi_eng_list_size].ename.s
 			= _sr_kemi_eng_list[_sr_kemi_eng_list_size].bname;
 	_sr_kemi_eng_list[_sr_kemi_eng_list_size].ename.len = ename->len;
 	_sr_kemi_eng_list[_sr_kemi_eng_list_size].ename.s[ename->len] = 0;
 	_sr_kemi_eng_list[_sr_kemi_eng_list_size].froute = froute;
 	_sr_kemi_eng_list_size++;
 
0476993b
 	LM_DBG("registered config routing enginge [%.*s]\n",
41359ef2
 			ename->len, ename->s);
 
d0436602
 	return 0;
 }
 
 /**
  *
  */
 int sr_kemi_eng_set(str *ename, str *cpath)
 {
 	int i;
 
41359ef2
 	/* skip native and default */
 	if(ename->len==6 && strncasecmp(ename->s, "native", 6)==0) {
 		return 0;
 	}
 	if(ename->len==7 && strncasecmp(ename->s, "default", 7)==0) {
 		return 0;
 	}
 
b0d8849b
 	if(sr_kemi_cbname_list_init()<0) {
 		return -1;
 	}
 
d0436602
 	for(i=0; i<_sr_kemi_eng_list_size; i++) {
 		if(_sr_kemi_eng_list[i].ename.len==ename->len
 				&& strncasecmp(_sr_kemi_eng_list[i].ename.s, ename->s,
 					ename->len)==0) {
 			/* found */
 			_sr_kemi_eng = &_sr_kemi_eng_list[i];
 			return 0;
 		}
 	}
 	return -1;
 }
 
41359ef2
 /**
  *
  */
 int sr_kemi_eng_setz(char *ename, char *cpath)
 {
 	str sname;
 	str spath;
 
 	sname.s = ename;
 	sname.len = strlen(ename);
 
 	if(cpath!=0) {
 		spath.s = cpath;
 		spath.len = strlen(cpath);
 		return sr_kemi_eng_set(&sname, &spath);
 	} else {
 		return sr_kemi_eng_set(&sname, NULL);
 	}
 }
 
b0d8849b
 /**
  *
  */
d0436602
 sr_kemi_eng_t* sr_kemi_eng_get(void)
 {
 	return _sr_kemi_eng;
 }
b0d8849b
 
 /**
  *
  */
 #define KEMI_CBNAME_MAX_LEN	128
 #define KEMI_CBNAME_LIST_SIZE	256
 
 typedef struct sr_kemi_cbname {
 	str name;
 	char bname[KEMI_CBNAME_MAX_LEN];
 } sr_kemi_cbname_t;
 
 static gen_lock_t *_sr_kemi_cbname_lock = 0;
 static sr_kemi_cbname_t *_sr_kemi_cbname_list = NULL;
f1f0aad7
 static int *_sr_kemi_cbname_list_size = NULL;
b0d8849b
 
 /**
  *
  */
 int sr_kemi_cbname_list_init(void)
 {
 	if(_sr_kemi_cbname_list!=NULL) {
 		return 0;
 	}
 	if ( (_sr_kemi_cbname_lock=lock_alloc())==0) {
 		LM_CRIT("failed to alloc lock\n");
 		return -1;
 	}
 	if (lock_init(_sr_kemi_cbname_lock)==0 ) {
 		LM_CRIT("failed to init lock\n");
 		lock_dealloc(_sr_kemi_cbname_lock);
 		_sr_kemi_cbname_lock = NULL;
 		return -1;
 	}
f1f0aad7
 	_sr_kemi_cbname_list_size = shm_malloc(sizeof(int));
 	if(_sr_kemi_cbname_list_size==NULL) {
 		lock_destroy(_sr_kemi_cbname_lock);
 		lock_dealloc(_sr_kemi_cbname_lock);
e3ecad34
 		SHM_MEM_ERROR;
f1f0aad7
 		return -1;
 	}
 	*_sr_kemi_cbname_list_size = 0;
b0d8849b
 	_sr_kemi_cbname_list
 			= shm_malloc(KEMI_CBNAME_LIST_SIZE*sizeof(sr_kemi_cbname_t));
 	if(_sr_kemi_cbname_list==NULL) {
e3ecad34
 		SHM_MEM_ERROR;
f1f0aad7
 		shm_free(_sr_kemi_cbname_list_size);
 		_sr_kemi_cbname_list_size = NULL;
b0d8849b
 		lock_destroy(_sr_kemi_cbname_lock);
 		lock_dealloc(_sr_kemi_cbname_lock);
 		_sr_kemi_cbname_lock = NULL;
 		return -1;
 	}
 	memset(_sr_kemi_cbname_list, 0,
 			KEMI_CBNAME_LIST_SIZE*sizeof(sr_kemi_cbname_t));
 	return 0;
 }
 
 /**
  *
  */
 int sr_kemi_cbname_lookup_name(str *name)
 {
 	int n;
 	int i;
 
 	if(_sr_kemi_cbname_list==NULL) {
 		return 0;
 	}
 	if(name->len >= KEMI_CBNAME_MAX_LEN) {
 		LM_ERR("callback name is too long [%.*s] (max: %d)\n",
 				name->len, name->s, KEMI_CBNAME_MAX_LEN);
 		return 0;
 	}
f1f0aad7
 	n = *_sr_kemi_cbname_list_size;
b0d8849b
 
 	for(i=0; i<n; i++) {
 		if(_sr_kemi_cbname_list[i].name.len==name->len
 				&& strncmp(_sr_kemi_cbname_list[i].name.s,
 						name->s, name->len)==0) {
 			return i+1;
 		}
 	}
 
 	/* not found -- add it */
 	lock_get(_sr_kemi_cbname_lock);
 
 	/* check if new callback were indexed meanwhile */
f1f0aad7
 	for(; i<*_sr_kemi_cbname_list_size; i++) {
b0d8849b
 		if(_sr_kemi_cbname_list[i].name.len==name->len
 				&& strncmp(_sr_kemi_cbname_list[i].name.s,
 						name->s, name->len)==0) {
ff695de3
 			lock_release(_sr_kemi_cbname_lock);
b0d8849b
 			return i+1;
 		}
 	}
f1f0aad7
 	if(*_sr_kemi_cbname_list_size>=KEMI_CBNAME_LIST_SIZE) {
b0d8849b
 		lock_release(_sr_kemi_cbname_lock);
 		LM_ERR("no more space to index callbacks\n");
 		return 0;
 	}
 	strncpy(_sr_kemi_cbname_list[i].bname, name->s, name->len);
 	_sr_kemi_cbname_list[i].bname[name->len] = '\0';
 	_sr_kemi_cbname_list[i].name.s = _sr_kemi_cbname_list[i].bname;
 	_sr_kemi_cbname_list[i].name.len = name->len;
f1f0aad7
 	i++;
 	*_sr_kemi_cbname_list_size = i;
b0d8849b
 	lock_release(_sr_kemi_cbname_lock);
f1f0aad7
 	return i;
b0d8849b
 }
 
 /**
  *
  */
 str* sr_kemi_cbname_lookup_idx(int idx)
 {
 	int n;
 
 	if(_sr_kemi_cbname_list==NULL) {
 		return NULL;
 	}
f1f0aad7
 	n = *_sr_kemi_cbname_list_size;
b0d8849b
 	if(idx<1 || idx>n) {
 		LM_ERR("index %d is out of range\n", idx);
 		return NULL;
 	}
 	return &_sr_kemi_cbname_list[idx-1].name;
 }
e68bf3a7
 
 /**
  *
  */
 typedef struct sr_kemi_param_map {
 	int ptype;
 	str pname;
 } sr_kemi_param_map_t;
 
 /**
  *
  */
 static sr_kemi_param_map_t _sr_kemi_param_map[] = {
0135d9a3
 	{ SR_KEMIP_NONE,   str_init("none") },
 	{ SR_KEMIP_INT,    str_init("int") },
 	{ SR_KEMIP_STR,    str_init("str") },
 	{ SR_KEMIP_BOOL,   str_init("bool") },
a9a8731d
 	{ SR_KEMIP_XVAL,   str_init("xval") },
e68bf3a7
 	{ 0, STR_NULL }
 };
 
 /**
  *
  */
 str *sr_kemi_param_map_get_name(int ptype)
 {
 	int i;
 
 	for(i=0; _sr_kemi_param_map[i].pname.s!=NULL; i++) {
 		if(_sr_kemi_param_map[i].ptype==ptype)
 			return &_sr_kemi_param_map[i].pname;
 	}
 	return NULL;
 }
 
 /**
  *
  */
 str *sr_kemi_param_map_get_params(int *ptypes)
 {
 	int i;
e7fc7ca2
 	int l;
 #define KEMI_PARAM_MAP_SIZE 72
 	static char pbuf[KEMI_PARAM_MAP_SIZE];
e68bf3a7
 	static str sret = STR_NULL;
 	str *pn;
 
 	pbuf[0] = '\0';
e7fc7ca2
 	l = 0;
 	for(i = 0; i < SR_KEMI_PARAMS_MAX; i++) {
 		if(ptypes[i] == SR_KEMIP_NONE)
 			break;
 		if(i > 0) {
 			l += 2;
 			if(l >= KEMI_PARAM_MAP_SIZE - 8) {
 				strcat(pbuf, ", ...");
 				goto done;
 			}
 			strcat(pbuf, ", ");
 		}
e68bf3a7
 		pn = sr_kemi_param_map_get_name(ptypes[i]);
e7fc7ca2
 		if(pn == NULL)
 			return NULL;
 		l += pn->len;
 		if(l >= KEMI_PARAM_MAP_SIZE - 8) {
 			strcat(pbuf, ", ...");
 			goto done;
 		}
e68bf3a7
 		strcat(pbuf, pn->s);
 	}
 	if(pbuf[0]=='\0') {
 		pn = sr_kemi_param_map_get_name(SR_KEMIP_NONE);
e7fc7ca2
 		if(pn == NULL)
 			return NULL;
af9c9c47
 		if(pn->len<KEMI_PARAM_MAP_SIZE-1) strncat(pbuf, pn->s, pn->len);
e68bf3a7
 	}
e7fc7ca2
 done:
e68bf3a7
 	sret.s = pbuf;
 	sret.len = strlen(sret.s);
 	return &sret;
e4b7cd2a
 }
6be53f64
 
 /**
  *
  */
 int sr_kemi_route(sr_kemi_eng_t *keng, sip_msg_t *msg, int rtype,
 		str *ename, str *edata)
 {
 	flag_t sfbk;
 	int ret;
 
 	sfbk = getsflags();
 	setsflagsval(0);
 	reset_static_buffer();
 	ret = keng->froute(msg, rtype, ename, edata);
 	setsflagsval(sfbk);
 	return ret;
 }
395cae83
 
 /**
  *
  */
 int sr_kemi_ctx_route(sr_kemi_eng_t *keng, run_act_ctx_t *ctx, sip_msg_t *msg,
 		int rtype, str *ename, str *edata)
 {
0689ac59
 	run_act_ctx_t *bctx;
 	int ret;
 
 	bctx = sr_kemi_act_ctx_get();
395cae83
 	sr_kemi_act_ctx_set(ctx);
0689ac59
 	ret = sr_kemi_route(keng, msg, rtype, ename, edata);
 	sr_kemi_act_ctx_set(bctx);
 	return ret;
395cae83
 }