📄 cpl_run.c
字号:
/* * $Id: cpl_run.c,v 1.37.2.2 2005/07/20 17:11:51 andrei Exp $ * * Copyright (C) 2001-2003 FhG Fokus * * This file is part of ser, a free SIP server. * * ser is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version * * For a license to use the ser software under conditions * other than those described here, or to purchase support for this * software, please contact iptel.org by e-mail at the following addresses: * info@iptel.org * * ser is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: * ------- * 2003-01-23 : created (bogdan) * 2003-09-11 : build_lump_rpl() merged into add_lump_rpl() (bogdan) * 2004-06-14 : all global variables merged into cpl_env and cpl_fct; * append_branches param added to lookup node (bogdan) * 2004-06-14 : flag CPL_IS_STATEFUL is set now immediately after the * transaction is created (bogdan)*/#include <stdio.h>#include <string.h>#include <time.h>#include <stdlib.h>#include "../../mem/mem.h"#include "../../mem/shm_mem.h"#include "../../str.h"#include "../../dprint.h"#include "../../parser/msg_parser.h"#include "../../data_lump_rpl.h"#include "../tm/tm_load.h"#include "../usrloc/usrloc.h"#include "CPL_tree.h"#include "loc_set.h"#include "cpl_utils.h"#include "cpl_nonsig.h"#include "cpl_sig.h"#include "cpl_env.h"#include "cpl_run.h"#define EO_SCRIPT ((char*)0xffffffff)#define DEFAULT_ACTION ((char*)0xfffffffe)#define CPL_SCRIPT_ERROR ((char*)0xfffffffd)#define CPL_RUNTIME_ERROR ((char*)0xfffffffc)#define CPL_TO_CONTINUE ((char*)0xfffffffb)#define HDR_NOT_FOUND ((char*)0xffffffff)#define UNDEF_CHAR (0xff)#define check_overflow_by_ptr(_ptr_,_intr_,_error_) \ do {\ if ( (char*)(_ptr_)>(_intr_)->script.len+(_intr_)->script.s ) {\ LOG(L_ERR,"ERROR:cpl_c: overflow detected ip=%p ptr=%p in "\ "func. %s, line %d\n",(_intr_)->ip,_ptr_,__FILE__,__LINE__);\ goto _error_; \ } \ }while(0)#define check_overflow_by_offset(_len_,_intr_,_error_) \ do {\ if ( (char*)((_intr_)->ip+(_len_)) > \ (_intr_)->script.len+(_intr_)->script.s ) {\ LOG(L_ERR,"ERROR:cpl_c: overflow detected ip=%p offset=%d in "\ "func. %s, line %d\n",(_intr_)->ip,_len_,__FILE__,__LINE__);\ goto _error_; \ } \ }while(0)#define get_first_child(_node_) \ ((NR_OF_KIDS(_node_)==0)?DEFAULT_ACTION:(_node_)+KID_OFFSET(_node_,0))#define get_basic_attr(_p_,_code_,_n_,_intr_,_error_) \ do{\ check_overflow_by_ptr( (_p_)+BASIC_ATTR_SIZE, _intr_, _error_);\ _code_ = ntohs( *((unsigned short*)(_p_)) );\ _n_ = ntohs( *((unsigned short*)((_p_)+2)) );\ (_p_) += 4;\ }while(0)#define get_str_attr(_p_,_s_,_len_,_intr_,_error_,_FIXUP_) \ do{\ if ( ((int)(_len_))-(_FIXUP_)<=0 ) {\ LOG(L_ERR,"ERROR:cpl_c:%s:%d: attribute is an empty string\n",\ __FILE__,__LINE__);\ goto _error_; \ } else {\ check_overflow_by_ptr( (_p_)+(_len_), _intr_, _error_);\ _s_ = _p_;\ (_p_) += (_len_) + 1*(((_len_)&0x0001)==1);\ (_len_) -= (_FIXUP_);\ }\ }while(0)struct cpl_interpreter* new_cpl_interpreter( struct sip_msg *msg, str *script){ struct cpl_interpreter *intr = 0; intr = (struct cpl_interpreter*)shm_malloc(sizeof(struct cpl_interpreter)); if (!intr) { LOG(L_ERR,"ERROR:build_cpl_interpreter: no more free memory!\n"); goto error; } memset( intr, 0, sizeof(struct cpl_interpreter)); /* init the interpreter*/ intr->script.s = script->s; intr->script.len = script->len; intr->recv_time = time(0); intr->ip = script->s; intr->msg = msg; /* check the beginning of the script */ if ( NODE_TYPE(intr->ip)!=CPL_NODE ) { LOG(L_ERR,"ERROR:build_cpl_interpreter: first node is not CPL!!\n"); goto error; } return intr;error: return 0;}void free_cpl_interpreter(struct cpl_interpreter *intr){ if (intr) { empty_location_set( &(intr->loc_set) ); if (intr->script.s) shm_free( intr->script.s); if (intr->user.s) shm_free(intr->user.s); if (intr->flags&CPL_RURI_DUPLICATED) shm_free(intr->ruri); if (intr->flags&CPL_TO_DUPLICATED) shm_free(intr->to); if (intr->flags&CPL_FROM_DUPLICATED) shm_free(intr->from); if (intr->flags&CPL_SUBJECT_DUPLICATED) shm_free(intr->subject); if (intr->flags&CPL_ORGANIZATION_DUPLICATED) shm_free(intr->organization); if (intr->flags&CPL_USERAGENT_DUPLICATED) shm_free(intr->user_agent); if (intr->flags&CPL_ACCEPTLANG_DUPLICATED) shm_free(intr->accept_language); if (intr->flags&CPL_PRIORITY_DUPLICATED) shm_free(intr->priority); shm_free(intr); }}/* UPDATED + CHECKED */static inline char *run_cpl_node( struct cpl_interpreter *intr ){ char *kid; unsigned char start; int i; start = (intr->flags&CPL_RUN_INCOMING)?INCOMING_NODE:OUTGOING_NODE; /* look for the starting node (incoming or outgoing) */ for(i=0;i<NR_OF_KIDS(intr->ip);i++) { kid= intr->ip + KID_OFFSET(intr->ip,i); if ( NODE_TYPE(kid)==start ) { return get_first_child(kid); } else if (NODE_TYPE(kid)==SUBACTION_NODE || NODE_TYPE(kid)==ANCILLARY_NODE || NODE_TYPE(kid)==INCOMING_NODE || NODE_TYPE(kid)==OUTGOING_NODE ) { continue; } else { LOG(L_ERR,"ERROR:cpl_c:run_cpl_node: unknown child type (%d) " "for CPL node!!\n",NODE_TYPE(kid)); return CPL_SCRIPT_ERROR; } } DBG("DEBUG:cpl_c:run_cpl_node: CPL node has no %d subnode -> default\n", start); return DEFAULT_ACTION;}/* UPDATED + CHECKED */static inline char *run_lookup( struct cpl_interpreter *intr ){ unsigned short attr_name; unsigned short n; unsigned char clear; char *p; char *kid; char *failure_kid = 0; char *success_kid = 0; char *notfound_kid = 0; int i; time_t tc; urecord_t* r; ucontact_t* contact; clear = NO_VAL; /* check the params */ for( i=NR_OF_ATTR(intr->ip),p=ATTR_PTR(intr->ip) ; i>0 ; i-- ) { get_basic_attr(p,attr_name,n,intr,script_error); switch (attr_name) { case CLEAR_ATTR: if (n!=YES_VAL && n!=NO_VAL) LOG(L_WARN,"WARNING:run_lookup: invalid value (%u) found" " for param. CLEAR in LOOKUP node -> using " "default (%u)!\n",n,clear); else clear = n; break; default: LOG(L_ERR,"ERROR:run_lookup: unknown attribute (%d) in " "LOOKUP node\n",attr_name); goto script_error; } } /* check the kids */ for( i=0 ; i<NR_OF_KIDS(intr->ip) ; i++ ) { kid = intr->ip + KID_OFFSET(intr->ip,i); check_overflow_by_ptr( kid+SIMPLE_NODE_SIZE(kid), intr, script_error); switch ( NODE_TYPE(kid) ) { case SUCCESS_NODE : success_kid = kid; break; case NOTFOUND_NODE: notfound_kid = kid; break; case FAILURE_NODE: failure_kid = kid; break; default: LOG(L_ERR,"ERROR:run_lookup: unknown output node type" " (%d) for LOOKUP node\n",NODE_TYPE(kid)); goto script_error; } } kid = failure_kid; if (cpl_env.lu_domain) { /* fetch user's contacts via usrloc */ tc = time(0); cpl_fct.ulb.lock_udomain( cpl_env.lu_domain ); i = cpl_fct.ulb.get_urecord( cpl_env.lu_domain, &intr->user, &r); if (i < 0) { /* failure */ LOG(L_ERR, "ERROR:run_lookup: Error while querying usrloc\n"); cpl_fct.ulb.unlock_udomain( cpl_env.lu_domain ); } else if (i > 0) { /* not found */ DBG("DBG:cpl-c:run_lookup: '%.*s' Not found in usrloc\n", intr->user.len, intr->user.s); cpl_fct.ulb.unlock_udomain( cpl_env.lu_domain ); kid = notfound_kid; } else { contact = r->contacts; /* skip expired contacts */ while (contact && contact->expires<=tc) contact = contact->next; /* any contacts left? */ if (contact) { /* clear loc set if requested */ if (clear) empty_location_set( &(intr->loc_set) ); /* start adding locations to set */ do { DBG("DBG:cpl-c:run_lookup: adding <%.*s>q=%d\n", contact->c.len,contact->c.s,(int)(10*contact->q)); if (add_location( &(intr->loc_set), &contact->c, (int)(10*contact->q), CPL_LOC_DUPL|((contact->flags & FL_NAT)*CPL_LOC_NATED) )==-1) { LOG(L_ERR,"ERROR:cpl-c:run_lookup: unable to add " "location to set :-(\n"); cpl_fct.ulb.unlock_udomain( cpl_env.lu_domain ); goto runtime_error; } contact = contact->next; }while( contact && cpl_env.lu_append_branches); /* set the flag for modifying the location set */ intr->flags |= CPL_LOC_SET_MODIFIED; /* we found a valid contact */ kid = success_kid; } else { /* no valid contact found */ kid = notfound_kid; } cpl_fct.ulb.unlock_udomain( cpl_env.lu_domain ); } } if (kid) return get_first_child(kid); return DEFAULT_ACTION;runtime_error: return CPL_RUNTIME_ERROR;script_error: return CPL_SCRIPT_ERROR;}/* UPDATED + CHECKED */static inline char *run_location( struct cpl_interpreter *intr ){ unsigned short attr_name; unsigned short n; char *p; unsigned char prio; unsigned char clear; str url; int i; clear = NO_VAL; prio = 10; url.s = (char*)UNDEF_CHAR; url.len = 0; /* fixes gcc 4.0 warning */ /* sanity check */ if (NR_OF_KIDS(intr->ip)>1) { LOG(L_ERR,"ERROR:run_location: LOCATION node suppose to have max " "one child, not %d!\n",NR_OF_KIDS(intr->ip)); goto script_error; } for( i=NR_OF_ATTR(intr->ip),p=ATTR_PTR(intr->ip) ; i>0 ; i-- ) { get_basic_attr(p,attr_name,n,intr,script_error); switch (attr_name) { case URL_ATTR: url.len = n; get_str_attr( p, url.s, url.len, intr, script_error,1); break; case PRIORITY_ATTR: if ( n>10) LOG(L_WARN,"WARNING:run_location: invalid value (%u) found" " for param. PRIORITY in LOCATION node -> using " "default (%u)!\n",n,prio); else prio = n; break; case CLEAR_ATTR: if (n!=YES_VAL && n!=NO_VAL) LOG(L_WARN,"WARNING:run_location: invalid value (%u) found" " for param. CLEAR in LOCATION node -> using " "default (%u)!\n",n,clear); else clear = n; break; default: LOG(L_ERR,"ERROR:run_location: unknown attribute (%d) in " "LOCATION node\n",attr_name); goto script_error; } } if (url.s==(char*)UNDEF_CHAR) { LOG(L_ERR,"ERROR:run_location: param. URL missing in LOCATION node\n"); goto script_error; } if (clear) empty_location_set( &(intr->loc_set) ); if (add_location( &(intr->loc_set), &url, prio, 0/*no dup*/ )==-1) { LOG(L_ERR,"ERROR:run_location: unable to add location to set :-(\n"); goto runtime_error; } /* set the flag for modifying the location set */ intr->flags |= CPL_LOC_SET_MODIFIED; return get_first_child(intr->ip);runtime_error: return CPL_RUNTIME_ERROR;script_error: return CPL_SCRIPT_ERROR;}/* UPDATED + CHECKED */static inline char *run_remove_location( struct cpl_interpreter *intr ){ unsigned short attr_name; unsigned short n; char *p; str url; int i; url.s = (char*)UNDEF_CHAR; /* sanity check */ if (NR_OF_KIDS(intr->ip)>1) { LOG(L_ERR,"ERROR:cpl_c:run_remove_location: REMOVE_LOCATION node " "suppose to have max one child, not %d!\n", NR_OF_KIDS(intr->ip)); goto script_error; } /* dirty hack to speed things up in when loc set is already empty */ if (intr->loc_set==0) goto done; for( i=NR_OF_ATTR(intr->ip),p=ATTR_PTR(intr->ip) ; i>0 ; i-- ) { get_basic_attr(p,attr_name,n,intr,script_error); switch (attr_name) { case LOCATION_ATTR: url.len = n; get_str_attr( p, url.s, url.len, intr, script_error,1); break; default: LOG(L_ERR,"ERROR:run_remove_location: unknown attribute " "(%d) in REMOVE_LOCATION node\n",attr_name); goto script_error; } } if (url.s==(char*)UNDEF_CHAR) { DBG("DEBUG:run_remove_location: remove all locs from loc_set\n"); empty_location_set( &(intr->loc_set) ); } else { remove_location( &(intr->loc_set), url.s, url.len ); } /* set the flag for modifying the location set */ intr->flags |= CPL_LOC_SET_MODIFIED;done: return get_first_child(intr->ip);script_error: return CPL_SCRIPT_ERROR;}/* UPDATED + CHECKED */static inline char *run_sub( struct cpl_interpreter *intr ){ char *p; unsigned short offset; unsigned short attr_name; int i; /* sanity check */ if (NR_OF_KIDS(intr->ip)!=0) { LOG(L_ERR,"ERROR:cpl_c:run_sub: SUB node doesn't suppose to have any " "sub-nodes. Found %d!\n",NR_OF_KIDS(intr->ip)); goto script_error; } /* check the number of attr */ i = NR_OF_ATTR( intr->ip ); if (i!=1) { LOG(L_ERR,"ERROR:cpl_c:run_sub: incorrect nr. of attr. %d (<>1) in " "SUB node\n",i); goto script_error; } /* get attr's name */ p = ATTR_PTR(intr->ip); get_basic_attr( p, attr_name, offset, intr, script_error); if (attr_name!=REF_ATTR) { LOG(L_ERR,"ERROR:cpl_c:run_sub: invalid attr. %d (expected %d)in " "SUB node\n", attr_name, REF_ATTR); goto script_error; } /* make the jump */ p = intr->ip - offset; /* check the destination pointer -> are we still inside the buffer ;-) */ if (((char*)p)<intr->script.s) { LOG(L_ERR,"ERROR:cpl_c:run_sub: jump offset lower than the script " "beginning -> underflow!\n"); goto script_error; } check_overflow_by_ptr( p+SIMPLE_NODE_SIZE(intr->ip), intr, script_error); /* check to see if we hit a subaction node */ if ( NODE_TYPE(p)!=SUBACTION_NODE ) { LOG(L_ERR,"ERROR:cpl_c:run_sub: sub. jump hit a nonsubaction node!\n"); goto script_error; } if ( NR_OF_ATTR(p)!=0 ) { LOG(L_ERR,"ERROR:cpl_c:run_sub: invalid subaction node reached " "(attrs=%d); expected (0)!\n",NR_OF_ATTR(p)); goto script_error; } return get_first_child(p);script_error: return CPL_SCRIPT_ERROR;}/* UPDATED + CHECKED */static inline char *run_reject( struct cpl_interpreter *intr ){ unsigned short attr_name; unsigned short status; unsigned short n; char *reason_s; char *p; int i; reason_s = (char*)UNDEF_CHAR; status = UNDEF_CHAR; /* sanity check */ if (NR_OF_KIDS(intr->ip)!=0) { LOG(L_ERR,"ERROR:cpl_c:run_reject: REJECT node doesn't suppose to have " "any sub-nodes. Found %d!\n",NR_OF_KIDS(intr->ip)); goto script_error;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -