/* * $Id$ * * 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: * --------- * 2004-07-21 created (bogdan) */ #include #include "sr_module.h" #include "dprint.h" #include "str.h" #include "ut.h" #include "mem/shm_mem.h" #include "usr_avp.h" struct str_int_data { str name; int val; }; struct str_str_data { str name; str val; }; static struct usr_avp *global_avps = 0; static struct usr_avp **crt_avps = &global_avps; inline static unsigned short compute_ID( str *name ) { char *p; unsigned short id; id=0; for( p=name->s+name->len-1 ; p>=name->s ; p-- ) id ^= *p; return id; } int add_avp(unsigned short flags, int_str name, int_str val) { struct usr_avp *avp; str *s; struct str_int_data *sid; struct str_str_data *ssd; int len; assert( crt_avps!=0 ); /* compute the required mem size */ len = sizeof(struct usr_avp); if (flags&AVP_NAME_STR) { if (flags&AVP_VAL_STR) len += sizeof(struct str_str_data)-sizeof(void*) + name.s->len + val.s->len; else len += sizeof(struct str_int_data)-sizeof(void*) + name.s->len; } else if (flags&AVP_VAL_STR) len += sizeof(str)-sizeof(void*) + val.s->len; avp = (struct usr_avp*)shm_malloc( len ); if (avp==0) { LOG(L_ERR,"ERROR:avp:add_avp: no more shm mem\n"); goto error; } avp->flags = flags; avp->id = (flags&AVP_NAME_STR)? compute_ID(name.s) : name.n ; avp->next = *crt_avps; *crt_avps = avp; switch ( flags&(AVP_NAME_STR|AVP_VAL_STR) ) { case 0: /* avp type ID, int value */ avp->data = (void*)val.n; break; case AVP_NAME_STR: /* avp type str, int value */ sid = (struct str_int_data*)&(avp->data); 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); break; case AVP_VAL_STR: /* avp type ID, str value */ s = (str*)&(avp->data); s->len = val.s->len; s->s = (char*)s + sizeof(str); memcpy( s->s, val.s->s , s->len); break; case AVP_NAME_STR|AVP_VAL_STR: /* avp type str, str value */ ssd = (struct str_str_data*)&(avp->data); 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->val.len = val.s->len; ssd->val.s = ssd->name.s + ssd->name.len; memcpy( ssd->val.s , val.s->s, val.s->len); break; } return 0; error: return -1; } inline static str* get_avp_name(struct usr_avp *avp) { 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 */ return &((struct str_int_data*)&avp->data)->name; case AVP_NAME_STR|AVP_VAL_STR: /* avp type str, str value */ return &((struct str_str_data*)&avp->data)->name; } LOG(L_ERR,"BUG:avp:get_avp_name: unknown avp type (name&val) %d\n", avp->flags&(AVP_NAME_STR|AVP_VAL_STR)); return 0; } /* get value functions */ inline void get_avp_val(struct usr_avp *avp, int_str *val) { if (avp==0 || val==0) return; switch ( avp->flags&(AVP_NAME_STR|AVP_VAL_STR) ) { case 0: /* avp type ID, int value */ val->n = (int)(avp->data); break; case AVP_NAME_STR: /* avp type str, int value */ val->n = ((struct str_int_data*)(&avp->data))->val; break; case AVP_VAL_STR: /* avp type ID, str value */ val->s = (str*)(&avp->data); break; case AVP_NAME_STR|AVP_VAL_STR: /* avp type str, str value */ val->s = &(((struct str_str_data*)(&avp->data))->val); break; } } /* seach functions */ inline static struct usr_avp *internal_search_ID_avp( struct usr_avp *avp, unsigned short id) { for( ; avp ; avp=avp->next ) { if ( id==avp->id && (avp->flags&AVP_NAME_STR)==0 ) { return avp; } } return 0; } inline static struct usr_avp *internal_search_name_avp( struct usr_avp *avp, unsigned short id, str *name) { str * avp_name; for( ; avp ; avp=avp->next ) 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 avp; } return 0; } struct usr_avp *search_first_avp( unsigned short name_type, int_str name, int_str *val) { struct usr_avp *avp; assert( crt_avps!=0 ); if (*crt_avps==0) return 0; /* search for the AVP by ID (&name) */ if (name_type&AVP_NAME_STR) avp = internal_search_name_avp(*crt_avps,compute_ID(name.s),name.s); else avp = internal_search_ID_avp( *crt_avps, name.n ); /* get the value - if required */ if (avp && val) get_avp_val(avp, val); return avp; } struct usr_avp *search_next_avp( struct usr_avp *avp, int_str *val ) { if (avp==0 || (avp=avp->next)==0) return 0; if (avp->flags&AVP_NAME_STR) avp = internal_search_name_avp( avp, avp->id, get_avp_name(avp)); else avp = internal_search_ID_avp( avp, avp->id ); if (avp && val) get_avp_val(avp, val); return avp; } /********* free functions ********/ void destroy_avp( struct usr_avp *avp_del) { struct usr_avp *avp; struct usr_avp *avp_prev; for( avp_prev=0,avp=*crt_avps ; avp ; avp_prev=avp,avp=avp->next ) { if (avp==avp_del) { if (avp_prev) avp_prev->next=avp->next; else *crt_avps = avp->next; shm_free(avp); return; } } } void destroy_avp_list_unsafe( struct usr_avp **list ) { struct usr_avp *avp, *foo; avp = *list; while( avp ) { foo = avp; avp = avp->next; shm_free_unsafe( foo ); } *list = 0; } inline void destroy_avp_list( struct usr_avp **list ) { struct usr_avp *avp, *foo; DBG("DEBUG:destroy_avp_list: destroing list %p\n",*list); avp = *list; while( avp ) { foo = avp; avp = avp->next; shm_free( foo ); } *list = 0; } void reset_avps( ) { assert( crt_avps!=0 ); if ( crt_avps!=&global_avps) { crt_avps = &global_avps; } destroy_avp_list( crt_avps ); } struct usr_avp** set_avp_list( struct usr_avp **list ) { struct usr_avp **foo; assert( crt_avps!=0 ); foo = crt_avps; crt_avps = list; return foo; }