12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217 |
- /*
- * 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:
- * [email protected]
- *
- * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * History:
- * ---------
- * 2004-07-21 created (bogdan)
- * 2004-10-09 interface more flexible - more function available (bogdan)
- * 2004-11-07 AVP string values are kept 0 terminated (bogdan)
- * 2004-11-14 global aliases support added
- * 2005-01-05 parse avp name according new syntax
- */
- /*!
- * \file
- * \brief SIP-router core ::
- * \ingroup core
- * Module: \ref core
- */
- #include <assert.h>
- #include <ctype.h>
- #include <string.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include "sr_module.h"
- #include "dprint.h"
- #include "str.h"
- #include "ut.h"
- #include "mem/shm_mem.h"
- #include "mem/mem.h"
- #include "usr_avp.h"
- enum idx {
- IDX_FROM_URI = 0,
- IDX_TO_URI,
- IDX_FROM_USER,
- IDX_TO_USER,
- IDX_FROM_DOMAIN,
- IDX_TO_DOMAIN,
- IDX_MAX
- };
- struct avp_galias {
- str alias;
- struct avp_spec avp;
- struct avp_galias *next;
- };
- static struct avp_galias *galiases = 0;
- static avp_list_t def_list[IDX_MAX]; /* Default AVP lists */
- static avp_list_t* crt_list[IDX_MAX]; /* Pointer to current AVP lists */
- /* Global AVP related variables go to shm mem */
- static avp_list_t* def_glist;
- static avp_list_t** crt_glist;
- /* AVP flags */
- int registered_avpflags_no = 0;
- static char *registered_avpflags[MAX_AVPFLAG];
- /* Initialize AVP lists in private memory and allocate memory
- * for shared lists
- */
- int init_avps(void)
- {
- int i;
- /* Empty default lists */
- memset(def_list, 0, sizeof(avp_list_t) * IDX_MAX);
- /* Point current pointers to default lists */
- for(i = 0; i < IDX_MAX; i++) {
- crt_list[i] = &def_list[i];
- }
- def_glist = (avp_list_t*)shm_malloc(sizeof(avp_list_t));
- crt_glist = (avp_list_t**)shm_malloc(sizeof(avp_list_t*));
- if (!def_glist || !crt_glist) {
- LM_ERR("No memory to allocate default global AVP list\n");
- return -1;
- }
- *def_glist = 0;
- *crt_glist = def_glist;
- return 0;
- }
- /*
- * Select active AVP list based on the value of flags
- */
- static avp_list_t* select_list(avp_flags_t flags)
- {
- if (flags & AVP_CLASS_URI) {
- if (flags & AVP_TRACK_TO) {
- return crt_list[IDX_TO_URI];
- } else {
- return crt_list[IDX_FROM_URI];
- }
- } else if (flags & AVP_CLASS_USER) {
- if (flags & AVP_TRACK_TO) {
- return crt_list[IDX_TO_USER];
- } else {
- return crt_list[IDX_FROM_USER];
- }
- } else if (flags & AVP_CLASS_DOMAIN) {
- if (flags & AVP_TRACK_TO) {
- return crt_list[IDX_TO_DOMAIN];
- } else {
- return crt_list[IDX_FROM_DOMAIN];
- }
- } else if (flags & AVP_CLASS_GLOBAL) {
- return *crt_glist;
- }
- return NULL;
- }
- inline static avp_id_t compute_ID( str *name )
- {
- char *p;
- avp_id_t id;
- id=0;
- for( p=name->s+name->len-1 ; p>=name->s ; p-- )
- id ^= *p;
- return id;
- }
- avp_t *create_avp (avp_flags_t flags, avp_name_t name, avp_value_t val)
- {
- avp_t *avp;
- str *s;
- struct str_int_data *sid;
- struct str_str_data *ssd;
- int len;
- if (name.s.s == 0 && name.s.len == 0) {
- LM_ERR("0 ID or NULL NAME AVP!");
- goto error;
- }
- /* compute the required mem size */
- len = sizeof(struct usr_avp);
- if (flags&AVP_NAME_STR) {
- if ( name.s.s==0 || name.s.len==0) {
- LM_ERR("EMPTY NAME AVP!");
- goto error;
- }
- if (flags&AVP_VAL_STR) {
- len += sizeof(struct str_str_data)-sizeof(union usr_avp_data)
- + name.s.len + 1 /* Terminating zero for regex search */
- + val.s.len + 1; /* Value is zero terminated */
- } else {
- len += sizeof(struct str_int_data)-sizeof(union usr_avp_data)
- + name.s.len + 1; /* Terminating zero for regex search */
- }
- } else if (flags&AVP_VAL_STR) {
- len += sizeof(str)-sizeof(union usr_avp_data) + val.s.len + 1;
- }
- avp = (struct usr_avp*)shm_malloc( len );
- if (avp==0) {
- LM_ERR("no more shm mem\n");
- return 0;
- }
- avp->flags = flags;
- avp->id = (flags&AVP_NAME_STR)? compute_ID(&name.s) : name.n ;
- avp->next = NULL;
- switch ( flags&(AVP_NAME_STR|AVP_VAL_STR) )
- {
- case 0:
- /* avp type ID, int value */
- avp->d.l = val.n;
- break;
- case AVP_NAME_STR:
- /* avp type str, int value */
- sid = (struct str_int_data*)&avp->d.data[0];
- sid->val = val.n;
- sid->name.len =name.s.len;
- sid->name.s = (char*)sid + sizeof(struct str_int_data);
- memcpy( sid->name.s , name.s.s, name.s.len);
- sid->name.s[name.s.len] = '\0'; /* Zero terminator */
- break;
- case AVP_VAL_STR:
- /* avp type ID, str value */
- s = (str*)&avp->d.data[0];
- s->len = val.s.len;
- s->s = (char*)s + sizeof(str);
- memcpy( s->s, val.s.s , s->len);
- s->s[s->len] = 0;
- break;
- case AVP_NAME_STR|AVP_VAL_STR:
- /* avp type str, str value */
- ssd = (struct str_str_data*)&avp->d.data[0];
- ssd->name.len = name.s.len;
- ssd->name.s = (char*)ssd + sizeof(struct str_str_data);
- memcpy( ssd->name.s , name.s.s, name.s.len);
- ssd->name.s[name.s.len]='\0'; /* Zero terminator */
- ssd->val.len = val.s.len;
- ssd->val.s = ssd->name.s + ssd->name.len + 1;
- memcpy( ssd->val.s , val.s.s, val.s.len);
- ssd->val.s[ssd->val.len] = 0;
- break;
- }
- return avp;
- error:
- return 0;
- }
- int add_avp_list(avp_list_t* list, avp_flags_t flags, avp_name_t name, avp_value_t val)
- {
- avp_t *avp;
- assert(list != 0);
- if ((avp = create_avp(flags, name, val))) {
- avp->next = *list;
- *list = avp;
- return 0;
- }
- return -1;
- }
- int add_avp(avp_flags_t flags, avp_name_t name, avp_value_t val)
- {
- avp_flags_t avp_class;
- avp_list_t* list;
- /* Add avp to uri class if no class has been
- * specified by the caller
- */
- if ((flags & AVP_CLASS_ALL) == 0) flags |= AVP_CLASS_URI;
- if ((flags & AVP_TRACK_ALL) == 0) flags |= AVP_TRACK_FROM;
- if (!(list = select_list(flags)))
- return -1;
- if (flags & AVP_CLASS_URI) avp_class = AVP_CLASS_URI;
- else if (flags & AVP_CLASS_USER) avp_class = AVP_CLASS_USER;
- else if (flags & AVP_CLASS_DOMAIN) avp_class = AVP_CLASS_DOMAIN;
- else avp_class = AVP_CLASS_GLOBAL;
- /* Make that only the selected class is set
- * if the caller set more classes in flags
- */
- return add_avp_list(list, flags & (~(AVP_CLASS_ALL) | avp_class), name, val);
- }
- int add_avp_before(avp_t *avp, avp_flags_t flags, avp_name_t name, avp_value_t val)
- {
- avp_t *new_avp;
- if (!avp) {
- return add_avp(flags, name, val);
- }
- if ((flags & AVP_CLASS_ALL) == 0) flags |= (avp->flags & AVP_CLASS_ALL);
- if ((flags & AVP_TRACK_ALL) == 0) flags |= (avp->flags & AVP_TRACK_ALL);
- if ((avp->flags & (AVP_CLASS_ALL|AVP_TRACK_ALL)) != (flags & (AVP_CLASS_ALL|AVP_TRACK_ALL))) {
- LM_ERR("Source and target AVPs have different CLASS/TRACK\n");
- return -1;
- }
- if ((new_avp=create_avp(flags, name, val))) {
- new_avp->next=avp->next;
- avp->next=new_avp;
- return 0;
- }
- return -1;
- }
- /* get value functions */
- inline str* get_avp_name(avp_t *avp)
- {
- struct str_int_data *sid;
- struct str_str_data *ssd;
-
- switch ( avp->flags&(AVP_NAME_STR|AVP_VAL_STR) )
- {
- case 0:
- /* avp type ID, int value */
- case AVP_VAL_STR:
- /* avp type ID, str value */
- return 0;
- case AVP_NAME_STR:
- /* avp type str, int value */
- sid = (struct str_int_data*)&avp->d.data[0];
- return &sid->name;
- case AVP_NAME_STR|AVP_VAL_STR:
- /* avp type str, str value */
- ssd = (struct str_str_data*)&avp->d.data[0];
- return &ssd->name;
- }
- LM_ERR("unknown avp type (name&val) %d\n", avp->flags&(AVP_NAME_STR|AVP_VAL_STR));
- return 0;
- }
- inline void get_avp_val(avp_t *avp, avp_value_t *val)
- {
- str *s;
- struct str_int_data *sid;
- struct str_str_data *ssd;
-
- if (avp==0 || val==0)
- return;
- switch ( avp->flags&(AVP_NAME_STR|AVP_VAL_STR) ) {
- case 0:
- /* avp type ID, int value */
- val->n = avp->d.l;
- break;
- case AVP_NAME_STR:
- /* avp type str, int value */
- sid = (struct str_int_data*)&avp->d.data[0];
- val->n = sid->val;
- break;
- case AVP_VAL_STR:
- /* avp type ID, str value */
- s = (str*)&avp->d.data[0];
- val->s = *s;
- break;
- case AVP_NAME_STR|AVP_VAL_STR:
- /* avp type str, str value */
- ssd = (struct str_str_data*)&avp->d.data[0];
- val->s = ssd->val;
- break;
- }
- }
- /* Return the current list of user attributes */
- avp_list_t get_avp_list(avp_flags_t flags)
- {
- avp_list_t *list;
- list = select_list(flags);
- return (list ? *list : NULL);
- }
- /*
- * Compare given id with id in avp, return true if they match
- */
- static inline int match_by_id(avp_t* avp, avp_id_t id)
- {
- if (avp->id == id && (avp->flags&AVP_NAME_STR)==0) {
- return 1;
- }
- return 0;
- }
- /*
- * Compare given name with name in avp, return true if they are same
- */
- static inline int match_by_name(avp_t* avp, avp_id_t id, str* name)
- {
- str* avp_name;
- if (id==avp->id && avp->flags&AVP_NAME_STR &&
- (avp_name=get_avp_name(avp))!=0 && avp_name->len==name->len
- && !strncasecmp( avp_name->s, name->s, name->len) ) {
- return 1;
- }
- return 0;
- }
- /*
- * Compare name with name in AVP using regular expressions, return
- * true if they match
- */
- static inline int match_by_re(avp_t* avp, regex_t* re)
- {
- regmatch_t pmatch;
- str * avp_name;
- /* AVP identifiable by name ? */
- if (!(avp->flags&AVP_NAME_STR)) return 0;
- if ((avp_name=get_avp_name(avp))==0) /* valid AVP name ? */
- return 0;
- if (!avp_name->s) /* AVP name validation */
- return 0;
- if (regexec(re, avp_name->s, 1, &pmatch,0)==0) { /* re match ? */
- return 1;
- }
- return 0;
- }
- avp_t *search_first_avp(avp_flags_t flags, avp_name_t name, avp_value_t *val, struct search_state* s)
- {
- avp_ident_t id;
- id.flags = flags;
- id.name = name;
- id.index = 0;
- return search_avp (id, val, s);
- }
- avp_t *search_avp (avp_ident_t ident, avp_value_t* val, struct search_state* state)
- {
- avp_t* ret;
- static struct search_state st;
- avp_list_t* list;
- if (ident.name.s.s==0 && ident.name.s.len == 0) {
- LM_ERR("0 ID or NULL NAME AVP!");
- return 0;
- }
- switch (ident.flags & AVP_INDEX_ALL) {
- case AVP_INDEX_BACKWARD:
- case AVP_INDEX_FORWARD:
- WARN("AVP specified with index, but not used for search\n");
- break;
- }
- if (!state) state = &st;
- if ((ident.flags & AVP_CLASS_ALL) == 0) {
- /* The caller did not specify any class to search in, so enable
- * all of them by default
- */
- ident.flags |= AVP_CLASS_ALL;
- if ((ident.flags & AVP_TRACK_ALL) == 0) {
- /* The caller did not specify even the track to search in, so search
- * in the track_from
- */
- ident.flags |= AVP_TRACK_FROM;
- }
- }
- if (!(list = select_list(ident.flags)))
- return NULL;
- state->flags = ident.flags;
- state->avp = *list;
- state->name = ident.name;
- if (ident.flags & AVP_NAME_STR) {
- state->id = compute_ID(&ident.name.s);
- }
- ret = search_next_avp(state, val);
- /* Make sure that search next avp stays in the same class as the first
- * avp found
- */
- if (state && ret) state->flags = (ident.flags & ~AVP_CLASS_ALL) | (ret->flags & AVP_CLASS_ALL);
- return ret;
- }
- avp_t *search_next_avp(struct search_state* s, avp_value_t *val )
- {
- int matched;
- avp_t* avp;
- avp_list_t *list;
- if (s == 0) {
- LM_ERR("Invalid parameter value\n");
- return 0;
- }
- switch (s->flags & AVP_INDEX_ALL) {
- case AVP_INDEX_BACKWARD:
- case AVP_INDEX_FORWARD:
- WARN("AVP specified with index, but not used for search\n");
- break;
- }
- while(1) {
- for( ; s->avp; s->avp = s->avp->next) {
- if (s->flags & AVP_NAME_RE) {
- matched = match_by_re(s->avp, s->name.re);
- } else if (s->flags & AVP_NAME_STR) {
- matched = match_by_name(s->avp, s->id, &s->name.s);
- } else {
- matched = match_by_id(s->avp, s->name.n);
- }
- if (matched) {
- avp = s->avp;
- s->avp = s->avp->next;
- if (val) get_avp_val(avp, val);
- return avp;
- }
- }
- if (s->flags & AVP_CLASS_URI) {
- s->flags &= ~AVP_CLASS_URI;
- list = select_list(s->flags);
- } else if (s->flags & AVP_CLASS_USER) {
- s->flags &= ~AVP_CLASS_USER;
- list = select_list(s->flags);
- } else if (s->flags & AVP_CLASS_DOMAIN) {
- s->flags &= ~AVP_CLASS_DOMAIN;
- list = select_list(s->flags);
- } else {
- s->flags &= ~AVP_CLASS_GLOBAL;
- return 0;
- }
- if (!list) return 0;
- s->avp = *list;
- }
- return 0;
- }
- int search_reverse( avp_t *cur, struct search_state* st,
- avp_index_t index, avp_list_t *ret)
- {
- avp_index_t lvl;
- if (!cur)
- return 0;
- lvl = search_reverse(search_next_avp(st, NULL), st, index, ret)+1;
- if (index==lvl)
- *ret=cur;
- return lvl;
- }
- avp_t *search_avp_by_index( avp_flags_t flags, avp_name_t name,
- avp_value_t *val, avp_index_t index)
- {
- avp_t *ret, *cur;
- struct search_state st;
- if (flags & AVP_NAME_RE) {
- BUG("search_by_index not supported for AVP_NAME_RE\n");
- return 0;
- }
- switch (flags & AVP_INDEX_ALL) {
- case 0:
- ret = search_first_avp(flags, name, val, &st);
- if (!ret || search_next_avp(&st, NULL))
- return 0;
- else
- return ret;
- case AVP_INDEX_ALL:
- BUG("search_by_index not supported for anonymous index []\n");
- return 0;
- case AVP_INDEX_FORWARD:
- ret = NULL;
- cur = search_first_avp(flags & ~AVP_INDEX_ALL, name, NULL, &st);
- search_reverse(cur, &st, index, &ret);
- if (ret && val)
- get_avp_val(ret, val);
- return ret;
- case AVP_INDEX_BACKWARD:
- ret = search_first_avp(flags & ~AVP_INDEX_ALL, name, val, &st);
- for (index--; (ret && index); ret=search_next_avp(&st, val), index--);
- return ret;
- }
- return 0;
- }
- /* FIXME */
- /********* free functions ********/
- void destroy_avp(avp_t *avp_del)
- {
- int i;
- avp_t *avp, *avp_prev;
- for (i = 0; i < IDX_MAX; i++) {
- for( avp_prev=0,avp=*crt_list[i] ; avp ;
- avp_prev=avp,avp=avp->next ) {
- if (avp==avp_del) {
- if (avp_prev) {
- avp_prev->next=avp->next;
- } else {
- *crt_list[i] = avp->next;
- }
- shm_free(avp);
- return;
- }
- }
- }
- for( avp_prev=0,avp=**crt_glist ; avp ;
- avp_prev=avp,avp=avp->next ) {
- if (avp==avp_del) {
- if (avp_prev) {
- avp_prev->next=avp->next;
- } else {
- **crt_glist = avp->next;
- }
- shm_free(avp);
- return;
- }
- }
- }
- void destroy_avp_list_unsafe(avp_list_t* list)
- {
- avp_t *avp, *foo;
- avp = *list;
- while( avp ) {
- foo = avp;
- avp = avp->next;
- shm_free_unsafe( foo );
- }
- *list = 0;
- }
- inline void destroy_avp_list(avp_list_t* list)
- {
- avp_t *avp, *foo;
- DBG("DEBUG:destroy_avp_list: destroying list %p\n", *list);
- avp = *list;
- while( avp ) {
- foo = avp;
- avp = avp->next;
- shm_free( foo );
- }
- *list = 0;
- }
- int reset_avp_list(int flags)
- {
- int i;
- if (flags & AVP_CLASS_URI) {
- if (flags & AVP_TRACK_FROM) i = IDX_FROM_URI;
- else i = IDX_TO_URI;
- } else if (flags & AVP_CLASS_USER) {
- if (flags & AVP_TRACK_FROM) i = IDX_FROM_USER;
- else i = IDX_TO_USER;
- } else if (flags & AVP_CLASS_DOMAIN) {
- if (flags & AVP_TRACK_FROM) i = IDX_FROM_DOMAIN;
- else i = IDX_TO_DOMAIN;
- } else return -1;
- crt_list[i] = &def_list[i];
- destroy_avp_list(crt_list[i]);
- return 0;
- }
- void reset_avps(void)
- {
- int i;
- for(i = 0; i < IDX_MAX; i++) {
- crt_list[i] = &def_list[i];
- destroy_avp_list(crt_list[i]);
- }
- }
- avp_list_t* set_avp_list( avp_flags_t flags, avp_list_t* list )
- {
- avp_list_t* prev;
- if (flags & AVP_CLASS_URI) {
- if (flags & AVP_TRACK_FROM) {
- prev = crt_list[IDX_FROM_URI];
- crt_list[IDX_FROM_URI] = list;
- } else {
- prev = crt_list[IDX_TO_URI];
- crt_list[IDX_TO_URI] = list;
- }
- } else if (flags & AVP_CLASS_USER) {
- if (flags & AVP_TRACK_FROM) {
- prev = crt_list[IDX_FROM_USER];
- crt_list[IDX_FROM_USER] = list;
- } else {
- prev = crt_list[IDX_TO_USER];
- crt_list[IDX_TO_USER] = list;
- }
- } else if (flags & AVP_CLASS_DOMAIN) {
- if (flags & AVP_TRACK_FROM) {
- prev = crt_list[IDX_FROM_DOMAIN];
- crt_list[IDX_FROM_DOMAIN] = list;
- } else {
- prev = crt_list[IDX_TO_DOMAIN];
- crt_list[IDX_TO_DOMAIN] = list;
- }
- } else {
- prev = *crt_glist;
- *crt_glist = list;
- }
- return prev;
- }
- /********* global aliases functions ********/
- static inline int check_avp_galias(str *alias, int type, int_str avp_name)
- {
- struct avp_galias *ga;
- type &= AVP_NAME_STR;
- for( ga=galiases ; ga ; ga=ga->next ) {
- /* check for duplicated alias names */
- if ( alias->len==ga->alias.len &&
- (strncasecmp( alias->s, ga->alias.s, alias->len)==0) )
- return -1;
- /*check for duplicated avp names */
- if (type==ga->avp.type) {
- if (type&AVP_NAME_STR){
- if (avp_name.s.len==ga->avp.name.s.len &&
- (strncasecmp(avp_name.s.s, ga->avp.name.s.s,
- avp_name.s.len)==0) )
- return -1;
- } else {
- if (avp_name.n==ga->avp.name.n)
- return -1;
- }
- }
- }
- return 0;
- }
- int add_avp_galias(str *alias, int type, int_str avp_name)
- {
- struct avp_galias *ga;
- if ((type&AVP_NAME_STR && (!avp_name.s.s ||
- !avp_name.s.len)) ||!alias || !alias->s ||
- !alias->len ){
- LM_ERR("null params received\n");
- goto error;
- }
- if (check_avp_galias(alias,type,avp_name)!=0) {
- LM_ERR("duplicate alias/avp entry\n");
- goto error;
- }
- ga = (struct avp_galias*)pkg_malloc( sizeof(struct avp_galias) );
- if (ga==0) {
- LM_ERR("no more pkg memory\n");
- goto error;
- }
- ga->alias.s = (char*)pkg_malloc( alias->len+1 );
- if (ga->alias.s==0) {
- LM_ERR("no more pkg memory\n");
- goto error1;
- }
- memcpy( ga->alias.s, alias->s, alias->len);
- ga->alias.len = alias->len;
- ga->avp.type = type&AVP_NAME_STR;
- if (type&AVP_NAME_STR) {
- ga->avp.name.s.s = (char*)pkg_malloc( avp_name.s.len+1 );
- if (ga->avp.name.s.s==0) {
- LM_ERR("no more pkg memory\n");
- goto error2;
- }
- ga->avp.name.s.len = avp_name.s.len;
- memcpy( ga->avp.name.s.s, avp_name.s.s, avp_name.s.len);
- ga->avp.name.s.s[avp_name.s.len] = 0;
- DBG("DEBUG:add_avp_galias: registering <%s> for avp name <%s>\n",
- ga->alias.s, ga->avp.name.s.s);
- } else {
- ga->avp.name.n = avp_name.n;
- DBG("DEBUG:add_avp_galias: registering <%s> for avp id <%d>\n",
- ga->alias.s, ga->avp.name.n);
- }
- ga->next = galiases;
- galiases = ga;
- return 0;
- error2:
- pkg_free(ga->alias.s);
- error1:
- pkg_free(ga);
- error:
- return -1;
- }
- int lookup_avp_galias(str *alias, int *type, int_str *avp_name)
- {
- struct avp_galias *ga;
- for( ga=galiases ; ga ; ga=ga->next )
- if (alias->len==ga->alias.len &&
- (strncasecmp( alias->s, ga->alias.s, alias->len)==0) ) {
- *type = ga->avp.type;
- *avp_name = ga->avp.name;
- return 0;
- }
- return -1;
- }
- /* parsing functions */
- #define ERR_IF_CONTAINS(name,chr) \
- if (memchr(name->s,chr,name->len)) { \
- LM_ERR("Unexpected control character '%c' in AVP name\n", chr); \
- goto error; \
- }
- int parse_avp_name( str *name, int *type, int_str *avp_name, int *index)
- {
- int ret;
- avp_ident_t attr;
- ret=parse_avp_ident(name, &attr);
- if (!ret) {
- if (type) *type = attr.flags;
- if (avp_name) *avp_name = attr.name;
- if (index) *index = attr.index;
- }
- return ret;
- }
- /** parse an avp indentifier.
- *
- * Parses the following avp indentifier forms:
- * - "i:<number>" - old form, deprecated (e.g. i:42)
- * - "s:<string>" - old form, deprecated (e.g. s:foo)
- * - "<track>.<name>" (e.g.: f.bar)
- * - "<track>.<name>[<index>]" (e.g.: f.bar[1])
- * - "<track><class>.<name>" (e.g: tu.bar)
- * - "<track><class>.<name>[<index>]" (e.g: fd.bar[2])
- * - "<string>" (e.g.: foo)
- * Where:
- * \<string\> = ascii string
- * \<id\> = ascii string w/o '[', ']', '.' and '/'
- * \<name\> = \<id\> | '/' regex '/'
- * (Note: regex use is deprecated)
- * \<track\> = 'f' | 't'
- * (from or to)
- * \<class\> = 'r' | 'u' | 'd' | 'g'
- * (uri, user, domain or global)
- * \<index\> = \<number\> | '-' \<number\> | ''
- * (the avp index, if missing it means AVP_INDEX_ALL, but
- * it's use is deprecated)
- * More examples:
- * "fr.bar[1]" - from track, uri class, avp "bar", the value 1.
- * "tu./^foo/" - to track, user class, all avps for which the name
- * starts with foo (note RE in avp names are deprecated).
- * "t.did" - to track, "did" avp
- *
- * @param name - avp identifier
- * @param *attr - the result will be stored here
- * @return 0 on success, -1 on error
- */
- int parse_avp_ident( str *name, avp_ident_t* attr)
- {
- unsigned int id;
- char c;
- char *p;
- str s;
- if (name==0 || name->s==0 || name->len==0) {
- LM_ERR("NULL name or name->s or name->len\n");
- goto error;
- }
- attr->index = 0;
- DBG("Parsing '%.*s'\n", name->len, name->s);
- if (name->len>=2 && name->s[1]==':') { /* old fashion i: or s: */
- /* WARN("i: and s: avp name syntax is deprecated!\n"); */
- c = name->s[0];
- name->s += 2;
- name->len -= 2;
- if (name->len==0)
- goto error;
- switch (c) {
- case 's': case 'S':
- attr->flags = AVP_NAME_STR;
- attr->name.s = *name;
- break;
- case 'i': case 'I':
- attr->flags = 0;
- if (str2int( name, &id)!=0) {
- LM_ERR("invalid ID <%.*s> - not a number\n",
- name->len, name->s);
- goto error;
- }
- attr->name.n = (int)id;
- break;
- default:
- LM_ERR("unsupported type [%c]\n", c);
- goto error;
- }
- } else if ((p=memchr(name->s, '.', name->len))) {
- if (p-name->s==1) {
- id=name->s[0];
- name->s +=2;
- name->len -=2;
- } else if (p-name->s==2) {
- id=name->s[0]<<8 | name->s[1];
- name->s +=3;
- name->len -=3;
- } else {
- LM_ERR("AVP unknown class prefix '%.*s'\n", name->len, name->s);
- goto error;
- }
- if (name->len==0) {
- LM_ERR("AVP name not specified after the prefix separator\n");
- goto error;
- }
- switch (id) {
- case 'f':
- attr->flags = AVP_TRACK_FROM;
- break;
- case 't':
- attr->flags = AVP_TRACK_TO;
- break;
- case 0x6672: /* 'fr' */
- attr->flags = AVP_TRACK_FROM | AVP_CLASS_URI;
- break;
- case 0x7472: /* 'tr' */
- attr->flags = AVP_TRACK_TO | AVP_CLASS_URI;
- break;
- case 0x6675: /* 'fu' */
- attr->flags = AVP_TRACK_FROM | AVP_CLASS_USER;
- break;
- case 0x7475: /* 'tu' */
- attr->flags = AVP_TRACK_TO | AVP_CLASS_USER;
- break;
- case 0x6664: /* 'fd' */
- attr->flags = AVP_TRACK_FROM | AVP_CLASS_DOMAIN;
- break;
- case 0x7464: /* 'td' */
- attr->flags = AVP_TRACK_TO | AVP_CLASS_DOMAIN;
- break;
- case 'g':
- attr->flags = AVP_TRACK_ALL | AVP_CLASS_GLOBAL;
- break;
- default:
- if (id < 1<<8)
- LM_ERR("AVP unknown class prefix '%c'\n", id);
- else
- LM_ERR("AVP unknown class prefix '%c%c'\n", id>>8,id);
- goto error;
- }
- if (name->s[name->len-1]==']') {
- p=memchr(name->s, '[', name->len);
- if (!p) {
- LM_ERR("missing '[' for AVP index\n");
- goto error;
- }
- s.s=p+1;
- s.len=name->len-(p-name->s)-2; /* [ and ] */
- if (s.len == 0) {
- attr->flags |= AVP_INDEX_ALL;
- } else {
- if (s.s[0]=='-') {
- attr->flags |= AVP_INDEX_BACKWARD;
- s.s++;s.len--;
- } else {
- attr->flags |= AVP_INDEX_FORWARD;
- }
- if ((str2int(&s, &id) != 0)||(id==0)) {
- LM_ERR("Invalid AVP index '%.*s'\n", s.len, s.s);
- goto error;
- }
- attr->index = id;
- }
- name->len=p-name->s;
- }
- ERR_IF_CONTAINS(name,'.');
- ERR_IF_CONTAINS(name,'[');
- ERR_IF_CONTAINS(name,']');
- if ((name->len > 2) && (name->s[0]=='/') && (name->s[name->len-1]=='/')) {
- attr->name.re=pkg_malloc(sizeof(regex_t));
- if (!attr->name.re) {
- BUG("No free memory to allocate AVP_NAME_RE regex\n");
- goto error;
- }
- name->s[name->len-1]=0;
- if (regcomp(attr->name.re, name->s+1, REG_EXTENDED|REG_NOSUB|REG_ICASE)) {
- pkg_free(attr->name.re);
- attr->name.re=0;
- name->s[name->len-1] = '/';
- goto error;
- }
- name->s[name->len-1] = '/';
- attr->flags |= AVP_NAME_RE;
- } else {
- ERR_IF_CONTAINS(name,'/');
- attr->flags |= AVP_NAME_STR;
- attr->name.s = *name;
- }
- } else {
- /*default is string name*/
- attr->flags = AVP_NAME_STR;
- attr->name.s = *name;
- }
- return 0;
- error:
- return -1;
- }
- void free_avp_ident(avp_ident_t* attr)
- {
- if (attr->flags & AVP_NAME_RE) {
- if (! attr->name.re) {
- BUG("attr ident @%p has the regexp flag set, but no regexp.\n",
- attr);
- #ifdef EXTRA_DEBUG
- abort();
- #endif
- } else {
- regfree(attr->name.re);
- pkg_free(attr->name.re);
- }
- }
- }
- int km_parse_avp_spec( str *name, int *type, int_str *avp_name)
- {
- char *p;
- int index = 0;
- if (name==0 || name->s==0 || name->len==0)
- return -1;
- p = (char*)memchr((void*)name->s, ':', name->len);
- if (p==NULL) {
- /* might be kamailio avp alias or ser avp name style */
- if(lookup_avp_galias( name, type, avp_name)==0)
- return 0; /* found */
- }
- return parse_avp_name( name, type, avp_name, &index);
- }
- int parse_avp_spec( str *name, int *type, int_str *avp_name, int *index)
- {
- str alias;
- if (name==0 || name->s==0 || name->len==0)
- return -1;
- if (name->s[0]==GALIAS_CHAR_MARKER) {
- /* it's an avp alias */
- if (name->len==1) {
- LM_ERR("empty alias\n");
- return -1;
- }
- alias.s = name->s+1;
- alias.len = name->len-1;
- return lookup_avp_galias( &alias, type, avp_name);
- } else {
- return parse_avp_name( name, type, avp_name, index);
- }
- }
- void free_avp_name(avp_flags_t *type, int_str *avp_name)
- {
- if ((*type & AVP_NAME_RE) && (avp_name->re)){
- regfree(avp_name->re);
- pkg_free(avp_name->re);
- avp_name->re=0;
- }
- }
- int add_avp_galias_str(char *alias_definition)
- {
- int_str avp_name;
- char *s;
- str name;
- str alias;
- int type;
- int index;
- s = alias_definition;
- while(*s && isspace((int)*s))
- s++;
- while (*s) {
- /* parse alias name */
- alias.s = s;
- while(*s && *s!=';' && !isspace((int)*s) && *s!='=')
- s++;
- if (alias.s==s || *s==0 || *s==';')
- goto parse_error;
- alias.len = s-alias.s;
- while(*s && isspace((int)*s))
- s++;
- /* equal sign */
- if (*s!='=')
- goto parse_error;
- s++;
- while(*s && isspace((int)*s))
- s++;
- /* avp name */
- name.s = s;
- while(*s && *s!=';' && !isspace((int)*s))
- s++;
- if (name.s==s)
- goto parse_error;
- name.len = s-name.s;
- while(*s && isspace((int)*s))
- s++;
- /* check end */
- if (*s!=0 && *s!=';')
- goto parse_error;
- if (*s==';') {
- for( s++ ; *s && isspace((int)*s) ; s++ );
- if (*s==0)
- goto parse_error;
- }
- if (parse_avp_name( &name, &type, &avp_name, &index)!=0) {
- LM_ERR("<%.*s> not a valid AVP name\n", name.len, name.s);
- goto error;
- }
- if (add_avp_galias( &alias, type, avp_name)!=0) {
- LM_ERR("add global alias failed\n");
- goto error;
- }
- } /*end while*/
- return 0;
- parse_error:
- LM_ERR("parse error in <%s> around pos %ld\n",
- alias_definition, (long)(s-alias_definition));
- error:
- return -1;
- }
- int destroy_avps(avp_flags_t flags, avp_name_t name, int all)
- {
- struct search_state st;
- avp_t* avp;
- int n;
-
- n = 0;
- avp = search_first_avp(flags, name, 0, &st);
- while (avp) {
- destroy_avp(avp);
- n++;
- if (!all) break;
- avp = search_next_avp(&st, 0);
- }
- return n;
- }
- void delete_avp(avp_flags_t flags, avp_name_t name)
- {
- struct search_state st;
- avp_t* avp;
- avp = search_first_avp(flags, name, 0, &st);
- while(avp) {
- destroy_avp(avp);
- avp = search_next_avp(&st, 0);
- }
- }
- /* AVP flags functions */
- /* name2id conversion is intended to use during fixup (cfg parsing and modinit) only therefore no hash is used */
- avp_flags_t register_avpflag(char* name) {
- avp_flags_t ret;
- ret = get_avpflag_no(name);
- if (ret == 0) {
- if (registered_avpflags_no >= MAX_AVPFLAG) {
- LM_ERR("cannot register new avp flag ('%s'), max.number of flags (%d) reached\n",
- name, MAX_AVPFLAG);
- return -1;
- }
- ret = 1<<(AVP_CUSTOM_FLAGS+registered_avpflags_no);
- registered_avpflags[registered_avpflags_no++] = name;
- }
- return ret;
- }
- avp_flags_t get_avpflag_no(char* name) {
- int i;
- for (i=0; i<registered_avpflags_no; i++) {
- if (strcasecmp(name, registered_avpflags[i])==0)
- return 1<<(AVP_CUSTOM_FLAGS+i);
- }
- return 0;
- }
|