- Spelling checked
[sip-router] / usr_avp.c
1 /*
2  * $Id$
3  *
4  * Copyright (C) 2001-2003 FhG Fokus
5  *
6  * This file is part of ser, a free SIP server.
7  *
8  * ser is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version
12  *
13  * For a license to use the ser software under conditions
14  * other than those described here, or to purchase support for this
15  * software, please contact iptel.org by e-mail at the following addresses:
16  *    info@iptel.org
17  *
18  * ser is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License 
24  * along with this program; if not, write to the Free Software 
25  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26  *
27  * History:
28  * ---------
29  *  2004-07-21  created (bogdan)
30  */
31
32
33 #include <assert.h>
34
35 #include "sr_module.h"
36 #include "dprint.h"
37 #include "str.h"
38 #include "ut.h"
39 #include "mem/shm_mem.h"
40 #include "usr_avp.h"
41
42
43
44 struct str_int_data {
45         str  name;
46         int  val;
47 };
48
49 struct str_str_data {
50         str  name;
51         str  val;
52 };
53
54
55 static struct usr_avp *global_avps = 0;
56 static struct usr_avp **crt_avps  = &global_avps;
57
58
59
60 inline static unsigned short compute_ID( str *name )
61 {
62         char *p;
63         unsigned short id;
64
65         id=0;
66         for( p=name->s+name->len-1 ; p>=name->s ; p-- )
67                 id ^= *p;
68         return id;
69 }
70
71
72 int add_avp(unsigned short flags, int_str name, int_str val)
73 {
74         struct usr_avp *avp;
75         str *s;
76         struct str_int_data *sid;
77         struct str_str_data *ssd;
78         int len;
79
80         assert( crt_avps!=0 );
81
82         /* compute the required mem size */
83         len = sizeof(struct usr_avp);
84         if (flags&AVP_NAME_STR) {
85                 if (flags&AVP_VAL_STR)
86                         len += sizeof(struct str_str_data)-sizeof(void*) + name.s->len
87                                 + val.s->len;
88                 else
89                         len += sizeof(struct str_int_data)-sizeof(void*) + name.s->len;
90         } else if (flags&AVP_VAL_STR)
91                         len += sizeof(str)-sizeof(void*) + val.s->len;
92
93         avp = (struct usr_avp*)shm_malloc( len );
94         if (avp==0) {
95                 LOG(L_ERR,"ERROR:avp:add_avp: no more shm mem\n");
96                 goto error;
97         }
98
99         avp->flags = flags;
100         avp->id = (flags&AVP_NAME_STR)? compute_ID(name.s) : name.n ;
101
102         avp->next = *crt_avps;
103         *crt_avps = avp;
104
105         switch ( flags&(AVP_NAME_STR|AVP_VAL_STR) )
106         {
107                 case 0:
108                         /* avp type ID, int value */
109                         avp->data = (void*)(long)val.n;
110                         break;
111                 case AVP_NAME_STR:
112                         /* avp type str, int value */
113                         sid = (struct str_int_data*)&(avp->data);
114                         sid->val = val.n;
115                         sid->name.len =name.s->len;
116                         sid->name.s = (char*)sid + sizeof(struct str_int_data);
117                         memcpy( sid->name.s , name.s->s, name.s->len);
118                         break;
119                 case AVP_VAL_STR:
120                         /* avp type ID, str value */
121                         s = (str*)&(avp->data);
122                         s->len = val.s->len;
123                         s->s = (char*)s + sizeof(str);
124                         memcpy( s->s, val.s->s , s->len);
125                         break;
126                 case AVP_NAME_STR|AVP_VAL_STR:
127                         /* avp type str, str value */
128                         ssd = (struct str_str_data*)&(avp->data);
129                         ssd->name.len = name.s->len;
130                         ssd->name.s = (char*)ssd + sizeof(struct str_str_data);
131                         memcpy( ssd->name.s , name.s->s, name.s->len);
132                         ssd->val.len = val.s->len;
133                         ssd->val.s = ssd->name.s + ssd->name.len;
134                         memcpy( ssd->val.s , val.s->s, val.s->len);
135                         break;
136         }
137
138         return 0;
139 error:
140         return -1;
141 }
142
143
144 inline static str* get_avp_name(struct usr_avp *avp)
145 {
146         switch ( avp->flags&(AVP_NAME_STR|AVP_VAL_STR) )
147         {
148                 case 0:
149                         /* avp type ID, int value */
150                 case AVP_VAL_STR:
151                         /* avp type ID, str value */
152                         return 0;
153                 case AVP_NAME_STR:
154                         /* avp type str, int value */
155                         return &((struct str_int_data*)&avp->data)->name;
156                 case AVP_NAME_STR|AVP_VAL_STR:
157                         /* avp type str, str value */
158                         return &((struct str_str_data*)&avp->data)->name;
159         }
160
161         LOG(L_ERR,"BUG:avp:get_avp_name: unknown avp type (name&val) %d\n",
162                 avp->flags&(AVP_NAME_STR|AVP_VAL_STR));
163         return 0;
164 }
165
166
167 /* get value functions */
168
169 inline void get_avp_val(struct usr_avp *avp, int_str *val)
170 {
171         if (avp==0 || val==0)
172                 return;
173
174         switch ( avp->flags&(AVP_NAME_STR|AVP_VAL_STR) ) {
175                 case 0:
176                         /* avp type ID, int value */
177                         val->n = (long)(avp->data);
178                         break;
179                 case AVP_NAME_STR:
180                         /* avp type str, int value */
181                         val->n = ((struct str_int_data*)(&avp->data))->val;
182                         break;
183                 case AVP_VAL_STR:
184                         /* avp type ID, str value */
185                         val->s = (str*)(&avp->data);
186                         break;
187                 case AVP_NAME_STR|AVP_VAL_STR:
188                         /* avp type str, str value */
189                         val->s = &(((struct str_str_data*)(&avp->data))->val);
190                         break;
191         }
192 }
193
194
195
196
197 /* search functions */
198
199 inline static struct usr_avp *internal_search_ID_avp( struct usr_avp *avp,
200                                                                                                 unsigned short id)
201 {
202         for( ; avp ; avp=avp->next ) {
203                 if ( id==avp->id && (avp->flags&AVP_NAME_STR)==0  ) {
204                         return avp;
205                 }
206         }
207         return 0;
208 }
209
210
211
212 inline static struct usr_avp *internal_search_name_avp( struct usr_avp *avp,
213                                                                                                 unsigned short id, str *name)
214 {
215         str * avp_name;
216
217         for( ; avp ; avp=avp->next )
218                 if ( id==avp->id && avp->flags&AVP_NAME_STR &&
219                 (avp_name=get_avp_name(avp))!=0 && avp_name->len==name->len
220                  && !strncasecmp( avp_name->s, name->s, name->len) ) {
221                         return avp;
222                 }
223         return 0;
224 }
225
226
227
228 struct usr_avp *search_first_avp( unsigned short name_type,
229                                                                                 int_str name, int_str *val)
230 {
231         struct usr_avp *avp;
232
233         assert( crt_avps!=0 );
234         
235         if (*crt_avps==0)
236                 return 0;
237
238         /* search for the AVP by ID (&name) */
239         if (name_type&AVP_NAME_STR)
240                 avp = internal_search_name_avp(*crt_avps,compute_ID(name.s),name.s);
241         else
242                 avp = internal_search_ID_avp( *crt_avps, name.n );
243
244         /* get the value - if required */
245         if (avp && val)
246                 get_avp_val(avp, val);
247
248         return avp;
249 }
250
251
252
253 struct usr_avp *search_next_avp( struct usr_avp *avp,  int_str *val )
254 {
255         if (avp==0 || (avp=avp->next)==0)
256                 return 0;
257
258         if (avp->flags&AVP_NAME_STR)
259                 avp = internal_search_name_avp( avp, avp->id, get_avp_name(avp));
260         else
261                 avp = internal_search_ID_avp( avp, avp->id );
262
263         if (avp && val)
264                 get_avp_val(avp, val);
265
266         return avp;
267 }
268
269
270
271
272 /********* free functions ********/
273
274 void destroy_avp( struct usr_avp *avp_del)
275 {
276         struct usr_avp *avp;
277         struct usr_avp *avp_prev;
278
279         for( avp_prev=0,avp=*crt_avps ; avp ; avp_prev=avp,avp=avp->next ) {
280                 if (avp==avp_del) {
281                         if (avp_prev)
282                                 avp_prev->next=avp->next;
283                         else
284                                 *crt_avps = avp->next;
285                         shm_free(avp);
286                         return;
287                 }
288         }
289 }
290
291
292 void destroy_avp_list_unsafe( struct usr_avp **list )
293 {
294         struct usr_avp *avp, *foo;
295
296         avp = *list;
297         while( avp ) {
298                 foo = avp;
299                 avp = avp->next;
300                 shm_free_unsafe( foo );
301         }
302         *list = 0;
303 }
304
305
306 inline void destroy_avp_list( struct usr_avp **list )
307 {
308         struct usr_avp *avp, *foo;
309
310         DBG("DEBUG:destroy_avp_list: destroying list %p\n",*list);
311         avp = *list;
312         while( avp ) {
313                 foo = avp;
314                 avp = avp->next;
315                 shm_free( foo );
316         }
317         *list = 0;
318 }
319
320
321 void reset_avps( )
322 {
323         assert( crt_avps!=0 );
324         
325         if ( crt_avps!=&global_avps) {
326                 crt_avps = &global_avps;
327         }
328         destroy_avp_list( crt_avps );
329 }
330
331
332
333 struct usr_avp** set_avp_list( struct usr_avp **list )
334 {
335         struct usr_avp **foo;
336         
337         assert( crt_avps!=0 );
338
339         foo = crt_avps;
340         crt_avps = list;
341         return foo;
342 }
343