/openser-1.3.4-tls/route.c
C | 1657 lines | 1470 code | 96 blank | 91 comment | 330 complexity | 42876e014bb79ab6d63f2cf4dbb4406b MD5 | raw file
Possible License(s): AGPL-1.0
- /*
- * $Id: route.c 5045 2008-10-08 13:37:39Z henningw $
- *
- * SIP routing engine
- *
- * Copyright (C) 2001-2003 FhG Fokus
- * Copyright (C) 2005-2006 Voice Sistem S.R.L.
- *
- * This file is part of openser, a free SIP server.
- *
- * openser 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
- *
- * openser is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * History:
- * --------
- * 2003-01-28 scratchpad removed, src_port introduced (jiri)
- * 2003-02-28 scratchpad compatibility abandoned (jiri)
- * 2003-03-10 updated to the new module exports format (andrei)
- * 2003-03-19 replaced all mallocs/frees w/ pkg_malloc/pkg_free (andrei)
- * 2003-04-01 added dst_port, proto, af; renamed comp_port to comp_no,
- * inlined all the comp_* functions (andrei)
- * 2003-04-05 s/reply_route/failure_route, onreply_route introduced (jiri)
- * 2003-05-23 comp_ip fixed, now it will resolve its operand and compare
- * the ip with all the addresses (andrei)
- * 2003-10-10 added more operators support to comp_* (<,>,<=,>=,!=) (andrei)
- * 2004-10-19 added from_uri & to_uri (andrei)
- * 2006-03-02 MODULE_T action points to a cmd_export_t struct instead to
- * a function address - more info is accessible (bogdan)
- * Fixup failure reports the config line (bogdan)
- * 2006-12-22 support for script and branch flags added (bogdan)
- */
-
- #include <stdlib.h>
- #include <sys/types.h>
- #include <regex.h>
- #include <netdb.h>
- #include <string.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #include <netdb.h>
- #include "route.h"
- #include "forward.h"
- #include "dprint.h"
- #include "proxy.h"
- #include "action.h"
- #include "sr_module.h"
- #include "ip_addr.h"
- #include "resolve.h"
- #include "socket_info.h"
- #include "blacklists.h"
- #include "parser/parse_uri.h"
- #include "parser/parse_from.h"
- #include "parser/parse_to.h"
- #include "mem/mem.h"
- /* main routing script table */
- struct action* rlist[RT_NO];
- /* reply routing table */
- struct action* onreply_rlist[ONREPLY_RT_NO];
- struct action* failure_rlist[FAILURE_RT_NO];
- struct action* branch_rlist[BRANCH_RT_NO];
- struct action* error_rlist;
- int route_type = REQUEST_ROUTE;
- static int fix_actions(struct action* a); /*fwd declaration*/
- extern int return_code;
- /*
- *
- */
- void init_route_lists(void)
- {
- memset(rlist, 0, sizeof(rlist));
- memset(onreply_rlist, 0, sizeof(onreply_rlist));
- memset(failure_rlist, 0, sizeof(failure_rlist));
- memset(branch_rlist, 0, sizeof(branch_rlist));
- error_rlist = 0;
- }
- /* traverses an expr tree and compiles the REs where necessary)
- * returns: 0 for ok, <0 if errors */
- static int fix_expr(struct expr* exp)
- {
- regex_t* re;
- int ret;
-
- ret=E_BUG;
- if (exp==0){
- LM_CRIT("null pointer\n");
- return E_BUG;
- }
- if (exp->type==EXP_T){
- switch(exp->op){
- case AND_OP:
- case OR_OP:
- if ((ret=fix_expr(exp->left.v.expr))!=0)
- return ret;
- ret=fix_expr(exp->right.v.expr);
- break;
- case NOT_OP:
- case EVAL_OP:
- ret=fix_expr(exp->left.v.expr);
- break;
- default:
- LM_CRIT("unknown op %d\n", exp->op);
- }
- }else if (exp->type==ELEM_T){
- if (exp->op==MATCH_OP || exp->op==NOTMATCH_OP){
- if (exp->right.type==STRING_ST){
- re=(regex_t*)pkg_malloc(sizeof(regex_t));
- if (re==0){
- LM_CRIT("out of pkg memory\n");
- return E_OUT_OF_MEM;
- }
- if (regcomp(re, (char*) exp->right.v.data,
- REG_EXTENDED|REG_NOSUB|REG_ICASE) ){
- LM_CRIT("bad re \"%s\"\n", (char*) exp->right.v.data);
- pkg_free(re);
- return E_BAD_RE;
- }
- /* replace the string with the re */
- pkg_free(exp->right.v.data);
- exp->right.v.data=re;
- exp->right.type=RE_ST;
- }else if (exp->right.type!=RE_ST
- && exp->right.type!=SCRIPTVAR_ST){
- LM_CRIT("invalid type for match\n");
- return E_BUG;
- }
- }
- if (exp->left.type==ACTION_O){
- ret=fix_actions((struct action*)exp->right.v.data);
- if (ret!=0){
- LM_CRIT("fix_actions error\n");
- return ret;
- }
- }
- if (exp->left.type==EXPR_O){
- ret=fix_expr(exp->left.v.expr);
- if (ret!=0){
- LM_CRIT("fix left exp error\n");
- return ret;
- }
- }
- if (exp->right.type==EXPR_ST){
- ret=fix_expr(exp->right.v.expr);
- if (ret!=0){
- LM_CRIT("fix rigth exp error\n");
- return ret;
- }
- }
- ret=0;
- }
- return ret;
- }
- /* adds the proxies in the proxy list & resolves the hostnames */
- /* returns 0 if ok, <0 on error */
- static int fix_actions(struct action* a)
- {
- struct action *t;
- int ret;
- cmd_export_t* cmd;
- struct hostent* he;
- struct ip_addr ip;
- struct socket_info* si;
- str host;
- int proto=PROTO_NONE, port;
- struct proxy_l *p;
- struct bl_head *blh;
- if (a==0){
- LM_CRIT("null pointer\n");
- return E_BUG;
- }
- for(t=a; t!=0; t=t->next){
- switch(t->type){
- case FORWARD_T:
- if (t->elem[0].type==NOSUBTYPE)
- break;
- case SEND_T:
- if (t->elem[0].type!=STRING_ST) {
- LM_CRIT("invalid type %d (should be string)\n", t->type);
- return E_BUG;
- }
- ret = parse_phostport( t->elem[0].u.string,
- strlen(t->elem[0].u.string),
- &host.s, &host.len, &port, &proto);
- if (ret!=0) {
- LM_ERR("ERROR:fix_actions: FORWARD/SEND bad "
- "argument\n");
- return E_CFG;
- }
- p = add_proxy( &host,(unsigned short)port, proto);
- if (p==0) {
- LM_ERR("forward/send failed to add proxy");
- return E_CFG;
- }
- t->elem[0].type = PROXY_ST;
- t->elem[0].u.data = (void*)p;
- break;
- case IF_T:
- if (t->elem[0].type!=EXPR_ST){
- LM_CRIT("invalid subtype %d for if (should be expr)\n",
- t->elem[0].type);
- return E_BUG;
- }else if( (t->elem[1].type!=ACTIONS_ST)
- &&(t->elem[1].type!=NOSUBTYPE) ){
- LM_CRIT("invalid subtype %d for if() {...} (should be"
- "action)\n", t->elem[1].type);
- return E_BUG;
- }else if( (t->elem[2].type!=ACTIONS_ST)
- &&(t->elem[2].type!=NOSUBTYPE) ){
- LM_CRIT("invalid subtype %d for if() {} else{...}(should"
- "be action)\n", t->elem[2].type);
- return E_BUG;
- }
- if (t->elem[0].u.data){
- if ((ret=fix_expr((struct expr*)t->elem[0].u.data))<0)
- return ret;
- }
- if ( (t->elem[1].type==ACTIONS_ST)&&(t->elem[1].u.data) ){
- if ((ret=fix_actions((struct action*)t->elem[1].u.data))<0)
- return ret;
- }
- if ( (t->elem[2].type==ACTIONS_ST)&&(t->elem[2].u.data) ){
- if((ret=fix_actions((struct action*)t->elem[2].u.data))<0)
- return ret;
- }
- break;
- case WHILE_T:
- if (t->elem[0].type!=EXPR_ST){
- LM_CRIT("invalid subtype %d for while (should be expr)\n",
- t->elem[0].type);
- return E_BUG;
- }else if( (t->elem[1].type!=ACTIONS_ST)
- &&(t->elem[1].type!=NOSUBTYPE) ){
- LM_CRIT("invalid subtype %d for while() {...} (should be"
- "action)\n", t->elem[1].type);
- return E_BUG;
- }
- if (t->elem[0].u.data){
- if ((ret=fix_expr((struct expr*)t->elem[0].u.data))<0)
- return ret;
- }
- if ( (t->elem[1].type==ACTIONS_ST)&&(t->elem[1].u.data) ){
- if ((ret=fix_actions((struct action*)t->elem[1].u.data))<0)
- return ret;
- }
- break;
- case SWITCH_T:
- if ( (t->elem[1].type==ACTIONS_ST)&&(t->elem[1].u.data) ){
- if ((ret=fix_actions((struct action*)t->elem[1].u.data))<0)
- return ret;
- }
- break;
- case CASE_T:
- if ( (t->elem[1].type==ACTIONS_ST)&&(t->elem[1].u.data) ){
- if ((ret=fix_actions((struct action*)t->elem[1].u.data))<0)
- return ret;
- }
- break;
- case DEFAULT_T:
- if ( (t->elem[0].type==ACTIONS_ST)&&(t->elem[0].u.data) ){
- if ((ret=fix_actions((struct action*)t->elem[0].u.data))<0)
- return ret;
- }
- break;
- case MODULE_T:
- cmd = (cmd_export_t*)t->elem[0].u.data;
- LM_DBG("fixing %s, line %d\n", cmd->name, t->line);
- if (cmd->fixup){
- if (cmd->param_no>0){
- ret=cmd->fixup(&t->elem[1].u.data, 1);
- t->elem[1].type=MODFIXUP_ST;
- if (ret<0) goto error;
- }
- if (cmd->param_no>1){
- ret=cmd->fixup(&t->elem[2].u.data, 2);
- t->elem[2].type=MODFIXUP_ST;
- if (ret<0) goto error;
- }
- if (cmd->param_no==0){
- ret=cmd->fixup( 0, 0);
- if (ret<0) goto error;
- }
- }
- break;
- case FORCE_SEND_SOCKET_T:
- if (t->elem[0].type!=SOCKID_ST){
- LM_CRIT("invalid subtype %d for force_send_socket\n",
- t->elem[0].type);
- return E_BUG;
- }
- he=resolvehost(((struct socket_id*)t->elem[0].u.data)->name,0);
- if (he==0){
- LM_ERR(" could not resolve %s\n",
- ((struct socket_id*)t->elem[0].u.data)->name);
- ret = E_BAD_ADDRESS;
- goto error;
- }
- hostent2ip_addr(&ip, he, 0);
- si=find_si(&ip, ((struct socket_id*)t->elem[0].u.data)->port,
- ((struct socket_id*)t->elem[0].u.data)->proto);
- if (si==0){
- LM_ERR("bad force_send_socket"
- " argument: %s:%d (ser doesn't listen on it)\n",
- ((struct socket_id*)t->elem[0].u.data)->name,
- ((struct socket_id*)t->elem[0].u.data)->port);
- ret = E_BAD_ADDRESS;
- goto error;
- }
- t->elem[0].u.data=si;
- t->elem[0].type=SOCKETINFO_ST;
- break;
- case SET_DEBUG_T:
- if (t->elem[0].type==NOSUBTYPE)
- break;
- if (t->elem[0].type!=NUMBER_ST) {
- LM_CRIT("fix_actions: BUG in setdebug() type %d\n",
- t->elem[0].type );
- ret=E_BUG;
- goto error;
- }
- /* normalize the value */
- if (t->elem[0].u.number>L_DBG)
- t->elem[0].u.number = L_DBG;
- else if (t->elem[0].u.number<L_ALERT)
- t->elem[0].u.number = L_ALERT;
- break;
- case SETFLAG_T:
- case RESETFLAG_T:
- case ISFLAGSET_T:
- if (t->elem[0].type!=NUMBER_ST) {
- LM_CRIT("bad xxxflag() type %d\n", t->elem[0].type );
- ret=E_BUG;
- goto error;
- }
- if (!flag_in_range( t->elem[0].u.number )) {
- ret=E_CFG;
- goto error;
- }
- break;
- case SETSFLAG_T:
- case RESETSFLAG_T:
- case ISSFLAGSET_T:
- if (t->elem[0].type!=NUMBER_ST) {
- LM_CRIT("bad xxxsflag() type %d\n", t->elem[0].type );
- ret=E_BUG;
- goto error;
- }
- t->elem[0].u.number = fixup_flag( t->elem[0].u.number );
- if (t->elem[0].u.data==0) {
- ret=E_CFG;
- goto error;
- }
- break;
- case SETBFLAG_T:
- case RESETBFLAG_T:
- case ISBFLAGSET_T:
- if (t->elem[0].type!=NUMBER_ST || t->elem[1].type!=NUMBER_ST) {
- LM_CRIT("bad xxxbflag() type "
- "%d,%d\n", t->elem[0].type, t->elem[0].type);
- ret=E_BUG;
- goto error;
- }
- t->elem[1].u.number = fixup_flag( t->elem[1].u.number );
- if (t->elem[1].u.data==0) {
- ret=E_CFG;
- goto error;
- }
- break;
- case EQ_T:
- case COLONEQ_T:
- case PLUSEQ_T:
- case MINUSEQ_T:
- case DIVEQ_T:
- case MULTEQ_T:
- case MODULOEQ_T:
- case BANDEQ_T:
- case BOREQ_T:
- case BXOREQ_T:
- if (t->elem[1].u.data){
- if ((ret=fix_expr((struct expr*)t->elem[1].u.data))<0)
- return ret;
- }
- break;
- case USE_BLACKLIST_T:
- if (t->elem[0].type!=STRING_ST) {
- LM_CRIT("bad USE_BLACKLIST type %d\n", t->elem[0].type);
- ret=E_BUG;
- goto error;
- }
- host.s = t->elem[0].u.string;
- host.len = strlen(host.s);
- blh = get_bl_head_by_name(&host);
- if (blh==NULL) {
- LM_ERR("USE_BLACKLIST - list "
- "%s not configured\n", t->elem[0].u.string);
- ret=E_CFG;
- goto error;
- }
- t->elem[0].type = BLACKLIST_ST;
- t->elem[0].u.data = blh;
- break;
- }
- }
- return 0;
- error:
- LM_ERR("fixing failed (code=%d) at cfg line %d\n", ret, t->line);
- return ret;
- }
- inline static int comp_no( int port, void *param, int op, int subtype )
- {
-
- if (subtype!=NUMBER_ST) {
- LM_CRIT("number expected: %d\n", subtype );
- return E_BUG;
- }
- switch (op){
- case EQUAL_OP:
- return port==(long)param;
- case DIFF_OP:
- return port!=(long)param;
- case GT_OP:
- return port>(long)param;
- case LT_OP:
- return port<(long)param;
- case GTE_OP:
- return port>=(long)param;
- case LTE_OP:
- return port<=(long)param;
- default:
- LM_CRIT("unknown operator: %d\n", op );
- return E_BUG;
- }
- }
- /* eval_elem helping function, returns str op param */
- inline static int comp_strval(struct sip_msg *msg, int op, str* ival,
- operand_t *opd)
- {
- int ret;
- regex_t* re;
- char backup;
- char backup2;
- str res;
- pv_value_t value;
-
- if(ival==NULL || ival->s==NULL || ival->len == 0)
- goto error;
-
- res.s = 0; res.len = 0;
- if(opd->type == SCRIPTVAR_ST)
- {
- if(pv_get_spec_value(msg, opd->v.spec, &value)!=0)
- {
- LM_CRIT("cannot get var value\n");
- goto error;
- }
- if(value.flags&PV_VAL_STR)
- {
- res = value.rs;
- } else {
- res.s = sint2str(value.ri, &res.len);
- }
- } else if(opd->type == NUMBER_ST) {
- res.s = sint2str(opd->v.n, &res.len);
- }else if(opd->type == STRING_ST) {
- res = opd->v.s;
- } else {
- if((op!=MATCH_OP && op!=NOTMATCH_OP) || opd->type != RE_ST)
- {
- LM_CRIT("invalid operation %d/%d\n", op, opd->type);
- goto error;
- }
- }
- ret=-1;
- switch(op){
- case EQUAL_OP:
- if(ival->len != res.len) return 0;
- ret=(strncasecmp(ival->s, res.s, ival->len)==0);
- break;
- case DIFF_OP:
- if(ival->len != res.len) return 1;
- ret=(strncasecmp(ival->s, res.s, ival->len)!=0);
- break;
- case MATCH_OP:
- case NOTMATCH_OP:
- backup=ival->s[ival->len];ival->s[ival->len]='\0';
- if(opd->type == SCRIPTVAR_ST) {
- re=(regex_t*)pkg_malloc(sizeof(regex_t));
- if (re==0){
- LM_CRIT("pkg memory allocation failure\n");
- ival->s[ival->len]=backup;
- goto error;
- }
- backup2 = res.s[res.len];res.s[res.len] = '\0';
- if (regcomp(re, res.s, REG_EXTENDED|REG_NOSUB|REG_ICASE)) {
- pkg_free(re);
- res.s[res.len] = backup2;
- ival->s[ival->len]=backup;
- goto error;
- }
- ret=(regexec(re, ival->s, 0, 0, 0)==0);
- regfree(re);
- pkg_free(re);
- res.s[res.len] = backup2;
- } else {
- ret=(regexec((regex_t*)opd->v.data, ival->s, 0, 0, 0)==0);
- }
- ival->s[ival->len]=backup;
- if(op==NOTMATCH_OP)
- ret = !ret;
- break;
- default:
- LM_CRIT("unknown op %d\n", op);
- goto error;
- }
- return ret;
-
- error:
- return -1;
- }
- /* eval_elem helping function, returns str op param */
- inline static int comp_str(char* str, void* param, int op, int subtype)
- {
- int ret;
-
- ret=-1;
- switch(op){
- case EQUAL_OP:
- if (subtype!=STRING_ST){
- LM_CRIT("bad type %d, string expected\n", subtype);
- goto error;
- }
- ret=(strcasecmp(str, (char*)param)==0);
- break;
- case DIFF_OP:
- if (subtype!=STRING_ST){
- LM_CRIT("bad type %d, string expected\n", subtype);
- goto error;
- }
- ret=(strcasecmp(str, (char*)param)!=0);
- break;
- case MATCH_OP:
- if (subtype!=RE_ST){
- LM_CRIT("bad type %d, RE expected\n", subtype);
- goto error;
- }
- ret=(regexec((regex_t*)param, str, 0, 0, 0)==0);
- break;
- case NOTMATCH_OP:
- if (subtype!=RE_ST){
- LM_CRIT("bad type %d, RE expected!\n", subtype);
- goto error;
- }
- ret=(regexec((regex_t*)param, str, 0, 0, 0)!=0);
- break;
- default:
- LM_CRIT("unknown op %d\n", op);
- goto error;
- }
- return ret;
-
- error:
- return -1;
- }
- /* check_self wrapper -- it checks also for the op */
- inline static int check_self_op(int op, str* s, unsigned short p)
- {
- int ret;
-
- ret=check_self(s, p, 0);
- switch(op){
- case EQUAL_OP:
- break;
- case DIFF_OP:
- if (ret>=0) ret=!ret;
- break;
- default:
- LM_CRIT("invalid operator %d\n", op);
- ret=-1;
- }
- return ret;
- }
- /* eval_elem helping function, returns an op param */
- inline static int comp_ip(struct sip_msg *msg, int op, struct ip_addr* ip,
- operand_t *opd)
- {
- struct hostent* he;
- char ** h;
- int ret;
- str tmp;
- ret=-1;
- switch(opd->type){
- case NET_ST:
- switch(op){
- case EQUAL_OP:
- ret=(matchnet(ip, (struct net*)opd->v.data)==1);
- break;
- case DIFF_OP:
- ret=(matchnet(ip, (struct net*)opd->v.data)!=1);
- break;
- default:
- goto error_op;
- }
- break;
- case STRING_ST:
- case RE_ST:
- switch(op){
- case EQUAL_OP:
- case MATCH_OP:
- /* 1: compare with ip2str*/
- ret=comp_str(ip_addr2a(ip), opd->v.data, op, opd->type);
- if (ret==1) break;
- /* 2: resolve (name) & compare w/ all the ips */
- if (opd->type==STRING_ST){
- he=resolvehost((char*)opd->v.data,0);
- if (he==0){
- LM_DBG("could not resolve %s\n",(char*)opd->v.data);
- }else if (he->h_addrtype==(int)ip->af){
- for(h=he->h_addr_list;(ret!=1)&& (*h); h++){
- ret=(memcmp(ip->u.addr, *h, ip->len)==0);
- }
- if (ret==1) break;
- }
- }
- /* 3: (slow) rev dns the address
- * and compare with all the aliases
- * !!??!! review: remove this? */
- if(received_dns & DO_REV_DNS)
- {
- he=rev_resolvehost(ip);
- if (he==0){
- print_ip( "comp_ip: could not rev_resolve ip "
- " address: ", ip, "\n");
- ret=0;
- }else{
- /* compare with primary host name */
- ret=comp_str(he->h_name, opd->v.data, op,
- opd->type);
- /* compare with all the aliases */
- for(h=he->h_aliases; (ret!=1) && (*h); h++){
- ret=comp_str(*h, opd->v.data, op, opd->type);
- }
- }
- } else {
- ret = 0;
- }
- break;
- case DIFF_OP:
- ret=comp_ip(msg, op, ip, opd);
- if (ret>=0) ret=!ret;
- break;
- default:
- goto error_op;
- }
- break;
- case MYSELF_ST: /* check if it's one of our addresses*/
- tmp.s=ip_addr2a(ip);
- tmp.len=strlen(tmp.s);
- ret=check_self_op(op, &tmp, 0);
- break;
- default:
- LM_CRIT("invalid type for src_ip or dst_ip (%d)\n", opd->type);
- ret=-1;
- }
- return ret;
- error_op:
- LM_CRIT("invalid operator %d\n", op);
- return -1;
-
- }
- /*! \brief compare str to regexp */
- inline static int comp_s2r(int op, str *s1, regex_t *re)
- {
- char backup;
- int ret;
- ret = -1;
- /* if string is NULL return FALSE */
- if(s1->len == 0 || s1->s==NULL || re==NULL)
- return 0;
- switch(op)
- {
- case MATCH_OP:
- backup = s1->s[s1->len]; s1->s[s1->len] = '\0';
- ret=(regexec(re, s1->s, 0, 0, 0)==0);
- s1->s[s1->len] = backup;
- break;
- case NOTMATCH_OP:
- backup = s1->s[s1->len]; s1->s[s1->len] = '\0';
- ret=(regexec(re, s1->s, 0, 0, 0)!=0);
- s1->s[s1->len] = backup;
- break;
- default:
- LM_CRIT("unknown op %d\n", op);
- }
- return ret;
- }
- /* compare str to str */
- inline static int comp_s2s(int op, str *s1, str *s2)
- {
- char backup;
- char backup2;
- int n;
- int rt;
- int ret;
- regex_t* re;
- ret = -1;
- /* if any of values is NULL return FALSE */
- if(s1->s==NULL || s2->s==NULL)
- return 0;
- switch(op) {
- case EQUAL_OP:
- if(s1->len != s2->len) return 0;
- ret=(strncasecmp(s1->s, s2->s, s2->len)==0);
- break;
- case DIFF_OP:
- if(s1->len != s2->len) return 1;
- ret=(strncasecmp(s1->s, s2->s, s2->len)!=0);
- break;
- case GT_OP:
- n = (s1->len>=s2->len)?s1->len:s2->len;
- rt = strncasecmp(s1->s,s2->s, n);
- if (rt>0)
- ret = 1;
- else if(rt==0 && s1->len>s1->len)
- ret = 1;
- else ret = 0;
- break;
- case GTE_OP:
- n = (s1->len>=s2->len)?s1->len:s2->len;
- rt = strncasecmp(s1->s,s2->s, n);
- if (rt>0)
- ret = 1;
- else if(rt==0 && s1->len>=s1->len)
- ret = 1;
- else ret = 0;
- break;
- case LT_OP:
- n = (s1->len>=s2->len)?s1->len:s2->len;
- rt = strncasecmp(s1->s,s2->s, n);
- if (rt<0)
- ret = 1;
- else if(rt==0 && s1->len<s1->len)
- ret = 1;
- else ret = 0;
- break;
- case LTE_OP:
- n = (s1->len>=s2->len)?s1->len:s2->len;
- rt = strncasecmp(s1->s,s2->s, n);
- if (rt<0)
- ret = 1;
- else if(rt==0 && s1->len<=s1->len)
- ret = 1;
- else ret = 0;
- break;
- case MATCHD_OP:
- case NOTMATCHD_OP:
- if(s1->len == 0 || s2->len == 0) return 0;
- re=(regex_t*)pkg_malloc(sizeof(regex_t));
- if (re==0) {
- LM_CRIT("pkg memory allocation failure\n");
- return -1;
- }
- backup = s1->s[s1->len]; s1->s[s1->len] = '\0';
- backup2 = s2->s[s2->len]; s2->s[s2->len] = '\0';
- if (regcomp(re, s2->s, REG_EXTENDED|REG_NOSUB|REG_ICASE)) {
- pkg_free(re);
- s2->s[s2->len] = backup2;
- s1->s[s1->len] = backup;
- return -1;
- }
- if(op==MATCHD_OP)
- ret=(regexec(re, s1->s, 0, 0, 0)==0);
- else
- ret=(regexec(re, s1->s, 0, 0, 0)!=0);
- regfree(re);
- pkg_free(re);
- s2->s[s2->len] = backup2;
- s1->s[s1->len] = backup;
- break;
- default:
- LM_CRIT("unknown op %d\n", op);
- }
- return ret;
- }
- /* compare nr to nr */
- inline static int comp_n2n(int op, int n1, int n2)
- {
- switch(op) {
- case EQUAL_OP:
- case MATCH_OP:
- case MATCHD_OP:
- if(n1 == n2)
- return 1;
- return 0;
- case NOTMATCH_OP:
- case NOTMATCHD_OP:
- case DIFF_OP:
- if(n1 != n2)
- return 1;
- return 0;
- case GT_OP:
- if(n1 > n2)
- return 1;
- return 0;
- case GTE_OP:
- if(n1 >= n2)
- return 1;
- return 0;
- case LT_OP:
- if(n1 < n2)
- return 1;
- return 0;
- case LTE_OP:
- if(n1 <= n2)
- return 1;
- return 0;
- default:
- LM_CRIT("unknown op %d\n", op);
- }
- return -1;
- }
- inline static int comp_scriptvar(struct sip_msg *msg, int op, operand_t *left,
- operand_t *right)
- {
- str lstr;
- str rstr;
- int ln;
- int rn;
- pv_value_t lvalue;
- pv_value_t rvalue;
- int type;
-
- lstr.s = 0; lstr.len = 0;
- rstr.s = 0; rstr.len = 0;
- ln = 0; rn =0;
- if(pv_get_spec_value(msg, left->v.spec, &lvalue)!=0)
- {
- LM_CRIT("cannot get left var value\n");
- goto error;
- }
- if(right->type==NULLV_ST)
- {
- if(op==EQUAL_OP)
- {
- if(lvalue.flags&PV_VAL_NULL)
- return 1;
- return 0;
- } else {
- if(lvalue.flags&PV_VAL_NULL)
- return 0;
- return 1;
- }
- }
- lstr = lvalue.rs;
- ln = lvalue.ri;
- type = 0;
- if(right->type == SCRIPTVAR_ST)
- {
- if(pv_get_spec_value(msg, right->v.spec, &rvalue)!=0)
- {
- LM_CRIT("cannot get right var value\n");
- goto error;
- }
- if(rvalue.flags&PV_VAL_NULL || lvalue.flags&PV_VAL_NULL ) {
- if (rvalue.flags&PV_VAL_NULL && lvalue.flags&PV_VAL_NULL )
- return (op==EQUAL_OP)?1:0;
- return (op==DIFF_OP)?1:0;
- }
-
- if(op==MATCH_OP||op==NOTMATCH_OP)
- {
- if(!((rvalue.flags&PV_VAL_STR) && (lvalue.flags&PV_VAL_STR)))
- {
- LM_CRIT("invalid operation %d/%d\n", op, right->type);
- goto error;
- }
- if(op==MATCH_OP)
- return comp_s2s(MATCHD_OP, &lstr, &rvalue.rs);
- else
- return comp_s2s(NOTMATCHD_OP, &lstr, &rvalue.rs);
- }
- if((rvalue.flags&PV_VAL_INT) && (lvalue.flags&PV_VAL_INT)) {
- /* comparing int */
- rn = rvalue.ri;
- type =2;
- } else if((rvalue.flags&PV_VAL_STR) && (lvalue.flags&PV_VAL_STR)) {
- /* comparing string */
- rstr = rvalue.rs;
- type =1;
- } else {
- LM_CRIT("invalid operation %d/%d!\n", op,
- right->type);
- goto error;
- }
- } else {
- /* null against a not-null constant */
- if(lvalue.flags&PV_VAL_NULL)
- return (op==DIFF_OP || op==NOTMATCH_OP || op==NOTMATCHD_OP)?1:0;
- if(right->type == NUMBER_ST) {
- if(!(lvalue.flags&PV_VAL_INT))
- {
- LM_CRIT("invalid operation %d/%d/%d!!\n", op,
- right->type, lvalue.flags);
- goto error;
- }
- /* comparing int */
- type =2;
- rn = right->v.n;
- } else if(right->type == STRING_ST) {
- if(!(lvalue.flags&PV_VAL_STR))
- {
- LM_CRIT("invalid operation %d/%d!!!\n", op, right->type);
- goto error;
- }
- /* comparing string */
- type =1;
- rstr = right->v.s;
- } else {
- /* comparing others */
- type = 0;
- }
-
- if(op==MATCH_OP || op==NOTMATCH_OP)
- {
- if(!(lvalue.flags&PV_VAL_STR) || right->type != RE_ST)
- {
- LM_CRIT("invalid operation %d/%d\n", op, right->type);
- goto error;
- }
- return comp_s2r(op, &lstr, (regex_t*)right->v.expr);
- }
- }
- if(type==1) { /* compare str */
- LM_DBG("str %d : %.*s\n", op, lstr.len, ZSW(lstr.s));
- return comp_s2s(op, &lstr, &rstr);
- } else if(type==2) {
- LM_DBG("int %d : %d / %d\n", op, ln, rn);
- return comp_n2n(op, ln, rn);
- } else {
- LM_CRIT("invalid operation %d/%d\n", op, right->type);
- }
-
- error:
- return -1;
- }
- /* returns: 0/1 (false/true) or -1 on error, -127 EXPR_DROP */
- static int eval_elem(struct expr* e, struct sip_msg* msg, pv_value_t *val)
- {
- struct sip_uri uri;
- int ret;
- int retl;
- int retr;
- int ival;
- pv_value_t lval;
- pv_value_t rval;
- char *p;
-
- ret=E_BUG;
- if (e->type!=ELEM_T){
- LM_CRIT("invalid type\n");
- goto error;
- }
-
- if(val) memset(val, 0, sizeof(pv_value_t));
- switch(e->left.type){
- case METHOD_O:
- ret=comp_strval(msg, e->op, &msg->first_line.u.request.method,
- &e->right);
- break;
- case URI_O:
- if(msg->new_uri.s){
- if (e->right.type==MYSELF_ST){
- if (parse_sip_msg_uri(msg)<0) ret=-1;
- else ret=check_self_op(e->op, &msg->parsed_uri.host,
- msg->parsed_uri.port_no?
- msg->parsed_uri.port_no:SIP_PORT);
- }else{
- ret=comp_strval(msg, e->op, &msg->new_uri, &e->right);
- }
- }else{
- if (e->right.type==MYSELF_ST){
- if (parse_sip_msg_uri(msg)<0) ret=-1;
- else ret=check_self_op(e->op, &msg->parsed_uri.host,
- msg->parsed_uri.port_no?
- msg->parsed_uri.port_no:SIP_PORT);
- }else{
- ret=comp_strval(msg, e->op,
- &msg->first_line.u.request.uri,
- &e->right);
- }
- }
- break;
- case FROM_URI_O:
- if (parse_from_header(msg)<0){
- LM_ERR("bad or missing From: header\n");
- goto error;
- }
- if (e->right.type==MYSELF_ST){
- if (parse_uri(get_from(msg)->uri.s, get_from(msg)->uri.len,
- &uri) < 0){
- LM_ERR("bad uri in From:\n");
- goto error;
- }
- ret=check_self_op(e->op, &uri.host,
- uri.port_no?uri.port_no:SIP_PORT);
- }else{
- ret=comp_strval(msg, e->op, &get_from(msg)->uri,
- &e->right);
- }
- break;
- case TO_URI_O:
- if ((msg->to==0) && ((parse_headers(msg, HDR_TO_F, 0)==-1) ||
- (msg->to==0))){
- LM_ERR("bad or missing To: header\n");
- goto error;
- }
- /* to content is parsed automatically */
- if (e->right.type==MYSELF_ST){
- if (parse_uri(get_to(msg)->uri.s, get_to(msg)->uri.len,
- &uri) < 0){
- LM_ERR("bad uri in To:\n");
- goto error;
- }
- ret=check_self_op(e->op, &uri.host,
- uri.port_no?uri.port_no:SIP_PORT);
- }else{
- ret=comp_strval(msg, e->op, &get_to(msg)->uri,
- &e->right);
- }
- break;
- case SRCIP_O:
- ret=comp_ip(msg, e->op, &msg->rcv.src_ip, &e->right);
- break;
- case DSTIP_O:
- ret=comp_ip(msg, e->op, &msg->rcv.dst_ip, &e->right);
- break;
- case NUMBER_O:
- ret=!(!e->right.v.n); /* !! to transform it in {0,1} */
- break;
- case ACTION_O:
- ret=run_action_list( (struct action*)e->right.v.data, msg);
- if(val)
- {
- val->flags = PV_TYPE_INT|PV_VAL_INT;
- val->ri = ret;
- }
- if (ret<=0) ret=(ret==0)?EXPR_DROP:0;
- else ret=1;
- return ret;
- case EXPR_O:
- retl = retr = 0;
- memset(&lval, 0, sizeof(pv_value_t));
- memset(&rval, 0, sizeof(pv_value_t));
- if(e->left.v.data)
- retl=eval_expr((struct expr*)e->left.v.data,msg,&lval);
- if(lval.flags == PV_VAL_NONE)
- {
- pv_value_destroy(&lval);
- pv_value_destroy(&rval);
- return 0;
- }
- if(e->op == BNOT_OP)
- {
- if(lval.flags&PV_VAL_INT)
- {
- if(val!=NULL)
- {
- val->flags = PV_TYPE_INT|PV_VAL_INT;
- val->ri = ~lval.ri;
- }
- pv_value_destroy(&lval);
- pv_value_destroy(&rval);
- return (val->ri)?1:0;
- }
- LM_ERR("binary NOT on non-numeric value\n");
- pv_value_destroy(&lval);
- pv_value_destroy(&rval);
- return 0;
- }
- if(e->right.v.data)
- retr=eval_expr((struct expr*)e->right.v.data,msg,&rval);
-
- if(lval.flags&PV_TYPE_INT)
- {
- if(!(rval.flags&PV_VAL_INT))
- {
- LM_ERR("invalid numeric operands\n");
- pv_value_destroy(&lval);
- pv_value_destroy(&rval);
- return 0;
- }
- if(val!=NULL)
- val->flags = PV_TYPE_INT|PV_VAL_INT;
- ival = 0;
- switch(e->op) {
- case PLUS_OP:
- ival = lval.ri + rval.ri;
- break;
- case MINUS_OP:
- ival = lval.ri - rval.ri;
- break;
- case DIV_OP:
- if(rval.ri==0)
- {
- LM_ERR("divide by 0\n");
- pv_value_destroy(&lval);
- pv_value_destroy(&rval);
- return 0;
- } else
- ival = lval.ri / rval.ri;
- break;
- case MULT_OP:
- ival = lval.ri * rval.ri;
- break;
- case MODULO_OP:
- if(rval.ri==0)
- {
- LM_ERR("divide by 0\n");
- pv_value_destroy(&lval);
- pv_value_destroy(&rval);
- return 0;
- } else
- ival = lval.ri % rval.ri;
- break;
- case BAND_OP:
- ival = lval.ri & rval.ri;
- break;
- case BOR_OP:
- ival = lval.ri | rval.ri;
- break;
- case BXOR_OP:
- ival = lval.ri ^ rval.ri;
- break;
- default:
- LM_ERR("invalid int op %d\n", e->op);
- val->ri = 0;
- pv_value_destroy(&lval);
- pv_value_destroy(&rval);
- return 0;
- }
- pv_value_destroy(&lval);
- pv_value_destroy(&rval);
- if(val!=NULL) val->ri = ival;
- return (ival)?1:0;
- } else {
- if(!(rval.flags&PV_VAL_STR))
- {
- LM_ERR("invalid string operands\n");
- pv_value_destroy(&lval);
- pv_value_destroy(&rval);
- return 0;
- }
- if(e->op != PLUS_OP)
- {
- LM_ERR("invalid string operator %d\n", e->op);
- pv_value_destroy(&lval);
- pv_value_destroy(&rval);
- return 0;
- }
- if(val==NULL)
- {
- ret = (lval.rs.len>0 || rval.rs.len>0);
- pv_value_destroy(&lval);
- pv_value_destroy(&rval);
- return ret;
- }
- val->rs.s=(char*)pkg_malloc((lval.rs.len+rval.rs.len+1)
- *sizeof(char));
- if(val->rs.s==0)
- {
- LM_ERR("no more memory\n");
- pv_value_destroy(&lval);
- pv_value_destroy(&rval);
- return 0;
- }
- val->flags = PV_VAL_PKG|PV_VAL_STR;
- memcpy(val->rs.s, lval.rs.s, lval.rs.len);
- memcpy(val->rs.s+lval.rs.len, rval.rs.s, rval.rs.len);
- val->rs.len = lval.rs.len + rval.rs.len;
- val->rs.s[val->rs.len] = '\0';
- pv_value_destroy(&lval);
- pv_value_destroy(&rval);
- return 1;
- }
- break;
- case SRCPORT_O:
- ret=comp_no(msg->rcv.src_port,
- e->right.v.data, /* e.g., 5060 */
- e->op, /* e.g. == */
- e->right.type /* 5060 is number */);
- break;
- case DSTPORT_O:
- ret=comp_no(msg->rcv.dst_port, e->right.v.data, e->op,
- e->right.type);
- break;
- case PROTO_O:
- ret=comp_no(msg->rcv.proto, e->right.v.data, e->op,
- e->right.type);
- break;
- case AF_O:
- ret=comp_no(msg->rcv.src_ip.af, e->right.v.data, e->op,
- e->right.type);
- break;
- case RETCODE_O:
- ret=comp_no(return_code, e->right.v.data, e->op,
- e->right.type);
- break;
- case MSGLEN_O:
- ret=comp_no(msg->len, e->right.v.data, e->op,
- e->right.type);
- break;
- case STRINGV_O:
- if(val) {
- val->flags = PV_VAL_STR;
- val->rs = e->left.v.s;
- }
- /* optimization for no dup ?!?! */
- return (e->left.v.s.len>0)?1:0;
- case NUMBERV_O:
- if(val) {
- val->flags = PV_TYPE_INT|PV_VAL_INT;
- val->ri = e->left.v.n;
- }
- ret=!(!e->left.v.n); /* !! to transform it in {0,1} */
- return ret;
- case SCRIPTVAR_O:
- if(e->op==NO_OP)
- {
- memset(&rval, 0, sizeof(pv_value_t));
- if(pv_get_spec_value(msg, e->right.v.spec, &rval)==0)
- {
- if(rval.flags==PV_VAL_NONE || (rval.flags&PV_VAL_NULL)
- || (rval.flags&PV_VAL_EMPTY)
- || ((rval.flags&PV_TYPE_INT)&&rval.ri==0))
- {
- pv_value_destroy(&rval);
- return 0;
- }
- if(rval.flags&PV_TYPE_INT)
- {
- pv_value_destroy(&rval);
- return 1;
- }
- if(rval.rs.len!=0)
- {
- pv_value_destroy(&rval);
- return 1;
- }
- pv_value_destroy(&rval);
- }
- return 0;
- }
- if(e->op==VALUE_OP)
- {
- if(pv_get_spec_value(msg, e->left.v.spec, &lval)==0)
- {
- if(val!=NULL)
- memcpy(val, &lval, sizeof(pv_value_t));
- if(lval.flags&PV_VAL_STR)
- {
- if(!((lval.flags&PV_VAL_PKG)
- || (lval.flags&PV_VAL_SHM)))
- {
- if(val!=NULL)
- {
- /* do pkg duplicate */
- p = (char*)pkg_malloc((val->rs.len+1)
- *sizeof(char));
- if(p==0)
- {
- LM_ERR("no more pkg memory\n");
- memset(val, 0, sizeof(pv_value_t));
- return 0;
- }
- memcpy(p, val->rs.s, val->rs.len);
- p[val->rs.len] = 0;
- val->rs.s = p;
- val->flags|= PV_VAL_PKG;
- }
- }
- return 1;
- }
- if(lval.flags==PV_VAL_NONE
- || (lval.flags & PV_VAL_NULL)
- || (lval.flags & PV_VAL_EMPTY))
- return 0;
- if(lval.flags&PV_TYPE_INT)
- return (lval.ri!=0);
- else
- return (lval.rs.len>0);
- }
- return 0;
- }
- ret=comp_scriptvar(msg, e->op, &e->left, &e->right);
- break;
- default:
- LM_CRIT("invalid operand %d\n", e->left.type);
- }
- if(val)
- {
- val->flags = PV_TYPE_INT|PV_VAL_INT;
- val->ri = ret;
- }
- return ret;
- error:
- if(val)
- {
- val->flags = PV_TYPE_INT|PV_VAL_INT;
- val->ri = -1;
- }
- return -1;
- }
- /* ret= 0/1 (true/false) , -1 on error or EXPR_DROP (-127) */
- int eval_expr(struct expr* e, struct sip_msg* msg, pv_value_t *val)
- {
- static int rec_lev=0;
- int ret;
-
- rec_lev++;
- if (rec_lev>MAX_REC_LEV){
- LM_CRIT("too many expressions (%d)\n", rec_lev);
- ret=-1;
- goto skip;
- }
-
- if (e->type==ELEM_T){
- ret=eval_elem(e, msg, val);
- }else if (e->type==EXP_T){
- switch(e->op){
- case AND_OP:
- ret=eval_expr(e->left.v.expr, msg, val);
- /* if error or false stop evaluating the rest */
- if (ret!=1) break;
- ret=eval_expr(e->right.v.expr, msg, val); /*ret1 is 1*/
- break;
- case OR_OP:
- ret=eval_expr(e->left.v.expr, msg, val);
- /* if true or error stop evaluating the rest */
- if (ret!=0) break;
- ret=eval_expr(e->right.v.expr, msg, val); /* ret1 is 0 */
- break;
- case NOT_OP:
- ret=eval_expr(e->left.v.expr, msg, val);
- if (ret<0) break;
- ret= ! ret;
- break;
- case EVAL_OP:
- ret=eval_expr(e->left.v.expr, msg, val);
- break;
- default:
- LM_CRIT("unknown op %d\n", e->op);
- ret=-1;
- }
- }else{
- LM_CRIT("unknown type %d\n", e->type);
- ret=-1;
- }
- skip:
- rec_lev--;
- return ret;
- }
- /* adds an action list to head; a must be null terminated (last a->next=0))*/
- void push(struct action* a, struct action** head)
- {
- struct action *t;
- if (*head==0){
- *head=a;
- return;
- }
- for (t=*head; t->next;t=t->next);
- t->next=a;
- }
- int add_actions(struct action* a, struct action** head)
- {
- int ret;
- LM_DBG("fixing actions...\n");
- if ((ret=fix_actions(a))!=0) goto error;
- push(a,head);
- return 0;
-
- error:
- return ret;
- }
- /* fixes all action tables */
- /* returns 0 if ok , <0 on error */
- int fix_rls(void)
- {
- int i,ret;
- for(i=0;i<RT_NO;i++){
- if(rlist[i]){
- if ((ret=fix_actions(rlist[i]))!=0){
- return ret;
- }
- }
- }
- for(i=0;i<ONREPLY_RT_NO;i++){
- if(onreply_rlist[i]){
- if ((ret=fix_actions(onreply_rlist[i]))!=0){
- return ret;
- }
- }
- }
- for(i=0;i<FAILURE_RT_NO;i++){
- if(failure_rlist[i]){
- if ((ret=fix_actions(failure_rlist[i]))!=0){
- return ret;
- }
- }
- }
- for(i=0;i<BRANCH_RT_NO;i++){
- if(branch_rlist[i]){
- if ((ret=fix_actions(branch_rlist[i]))!=0){
- return ret;
- }
- }
- }
- if(error_rlist){
- if ((ret=fix_actions(error_rlist))!=0){
- return ret;
- }
- }
- return 0;
- }
- static int rcheck_stack[RT_NO];
- static int rcheck_stack_p = 0;
- static int rcheck_status = 0;
- static int check_actions(struct action *a, int r_type)
- {
- struct action *aitem;
- cmd_export_t *fct;
- int n;
- for( ; a ; a=a->next ) {
- switch (a->type) {
- case ROUTE_T:
- /* this route is already on the current path ? */
- for( n=0 ; n<rcheck_stack_p ; n++ ) {
- if (rcheck_stack[n]==(int)a->elem[0].u.number)
- break;
- }
- if (n!=rcheck_stack_p)
- break;
- if (++rcheck_stack_p==RT_NO) {
- LM_CRIT("stack overflow (%d)\n", rcheck_stack_p);
- goto error;
- }
- rcheck_stack[rcheck_stack_p] = a->elem[0].u.number;
- if (check_actions( rlist[a->elem[0].u.number], r_type)!=0)
- goto error;
- rcheck_stack_p--;
- break;
- case IF_T:
- if (check_actions((struct action*)a->elem[1].u.data, r_type)!=0)
- goto error;
- if (check_actions((struct action*)a->elem[2].u.data, r_type)!=0)
- goto error;
- break;
- case WHILE_T:
- if (check_actions((struct action*)a->elem[1].u.data, r_type)!=0)
- goto error;
- break;
- case SWITCH_T:
- aitem = (struct action*)a->elem[1].u.data;
- for( ; aitem ; aitem=aitem->next ) {
- n = check_actions((struct action*)aitem->elem[1].u.data,
- r_type);
- if (n!=0) goto error;
- }
- break;
- case MODULE_T:
- /* do check :D */
- fct = (cmd_export_t*)(a->elem[0].u.data);
- if ( (fct->flags&r_type)!=r_type ) {
- rcheck_status = -1;
- LM_ERR("script function "
- "\"%s\" (types=%d) does not support route type "
- "(%d)\n",fct->name, fct->flags, r_type);
- for( n=rcheck_stack_p-1; n>=0 ; n-- ) {
- LM_ERR("route stack[%d]=%d\n",n,rcheck_stack[n]);
- }
- }
- break;
- default:
- break;
- }
- }
- return 0;
- error:
- return -1;
- }
- /* check all routing tables for compatiblity between
- * route types and called module functions;
- * returns 0 if ok , <0 on error */
- int check_rls(void)
- {
- int i,ret;
- rcheck_status = 0;
- if(rlist[0]){
- if ((ret=check_actions(rlist[0],REQUEST_ROUTE))!=0){
- LM_ERR("check failed for main request route\n");
- return ret;
- }
- }
- for(i=0;i<ONREPLY_RT_NO;i++){
- if(onreply_rlist[i]){
- if ((ret=check_actions(onreply_rlist[i],ONREPLY_ROUTE))!=0){
- LM_ERR("check failed for onreply_route[%d]\n",i);
- return ret;
- }
- }
- }
- for(i=0;i<FAILURE_RT_NO;i++){
- if(failure_rlist[i]){
- if ((ret=check_actions(failure_rlist[i],FAILURE_ROUTE))!=0){
- LM_ERR("check failed for failure_route[%d]\n",i);
- return ret;
- }
- }
- }
- for(i=0;i<BRANCH_RT_NO;i++){
- if(branch_rlist[i]){
- if ((ret=check_actions(branch_rlist[i],BRANCH_ROUTE))!=0){
- LM_ERR("check failed for branch_route[%d]\n",i);
- return ret;
- }
- }
- }
- if(error_rlist){
- if ((ret=check_actions(error_rlist,ERROR_ROUTE))!=0){
- LM_ERR("check failed for error_route\n");
- return ret;
- }
- }
- return rcheck_status;
- }
- /* debug function, prints main routing table */
- void print_rl(void)
- {
- int j;
- for(j=0; j<RT_NO; j++){
- if (rlist[j]==0){
- if (j==0) LM_DBG("WARNING: the main routing table is empty\n");
- continue;
- }
- LM_DBG("routing table %d:\n",j);
- print_actions(rlist[j]);
- LM_DBG("\n");
- }
- for(j=0; j<ONREPLY_RT_NO; j++){
- if (onreply_rlist[j]==0){
- continue;
- }
- LM_DBG("onreply routing table %d:\n",j);
- print_actions(onreply_rlist[j]);
- LM_DBG("\n");
- }
- for(j=0; j<FAILURE_RT_NO; j++){
- if (failure_rlist[j]==0){
- continue;
- }
- LM_DBG("failure routing table %d:\n",j);
- print_actions(failure_rlist[j]);
- LM_DBG("\n");
- }
- for(j=0; j<BRANCH_RT_NO; j++){
- if (branch_rlist[j]==0){
- continue;
- }
- LM_DBG("T-branch routing table %d:\n",j);
- print_actions(branch_rlist[j]);
- LM_DBG("\n");
- }
- }