acc_extra.c

Go to the documentation of this file.
00001 /*
00002  * $Id$
00003  *
00004  * Copyright (C) 2004-2006 Voice Sistem SRL
00005  * Copyright (C) 2008 Juha Heinanen
00006  *
00007  * This file is part of Kamailio, a free SIP server.
00008  *
00009  * Kamailio is free software; you can redistribute it and/or
00010  * modify it under the terms of the GNU General Public License
00011  * as published by the Free Software Foundation; either version 2
00012  * of the License, or (at your option) any later version.
00013  *
00014  * Kamailio is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017  * GNU General Public License for more details.
00018  *
00019  * You should have received a copy of the GNU General Public License
00020  * along with this program; if not, write to the Free Software
00021  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00022  *
00023  *
00024  * History:
00025  * ---------
00026  *  2004-10-28  first version (ramona)
00027  *  2005-05-30  acc_extra patch commited (ramona)
00028  *  2005-07-13  acc_extra specification moved to use pseudo-variables (bogdan)
00029  *  2006-09-08  flexible multi leg accounting support added,
00030  *              code cleanup for low level functions (bogdan)
00031  *  2006-09-19  final stage of a masive re-structuring and cleanup (bogdan)
00032  *  2008-09-03  added support for integer type Radius attributes (jh)
00033  */
00034 
00044 #include <stdlib.h>
00045 #include <string.h>
00046 #include <ctype.h>
00047 #include "../../dprint.h"
00048 #include "../../ut.h"
00049 #include "../../usr_avp.h"
00050 #include "../../mem/mem.h"
00051 #include "acc_api.h"
00052 #include "acc_extra.h"
00053 
00054 #define EQUAL '='
00055 #define SEPARATOR ';'
00056 
00057 
00058 #if MAX_ACC_EXTRA<MAX_ACC_LEG
00059         #define MAX_ACC_INT_BUF MAX_ACC_LEG
00060 #else
00061         #define MAX_ACC_INT_BUF MAX_ACC_EXTRA
00062 #endif
00063 /* here we copy the strings returned by int2str (which uses a static buffer) */
00064 static char int_buf[INT2STR_MAX_LEN*MAX_ACC_INT_BUF];
00065 
00066 static char *static_detector = 0;
00067 
00068 void init_acc_extra(void)
00069 {
00070         int i;
00071         /* ugly trick to get the address of the static buffer */
00072         static_detector = int2str( (unsigned long)3, &i) + i;
00073 }
00074 
00075 
00076 struct acc_extra *parse_acc_leg(char *extra_str)
00077 {
00078         struct acc_extra *legs;
00079         struct acc_extra *it;
00080         int n;
00081 
00082         legs = parse_acc_extra(extra_str);
00083         if (legs==0) {
00084                 LM_ERR("failed to parse extra leg\n");
00085                 return 0;
00086         }
00087 
00088         /* check the type and len */
00089         for( it=legs,n=0 ; it ; it=it->next ) {
00090                 if (it->spec.type!=PVT_AVP) {
00091                         LM_ERR("only AVP are accepted as leg info\n");
00092                         destroy_extras(legs);
00093                         return 0;
00094                 }
00095                 n++;
00096                 if (n>MAX_ACC_LEG) {
00097                         LM_ERR("too many leg info; MAX=%d\n", MAX_ACC_LEG);
00098                         destroy_extras(legs);
00099                         return 0;
00100                 }
00101         }
00102 
00103         return legs;
00104 }
00105 
00106 
00107 struct acc_extra *parse_acc_extra(char *extra_str)
00108 {
00109         struct acc_extra *head;
00110         struct acc_extra *tail;
00111         struct acc_extra *extra;
00112         char *foo;
00113         char *s;
00114         int  n;
00115         str stmp;
00116 
00117         n = 0;
00118         head = 0;
00119         extra = 0;
00120         tail = 0;
00121         s = extra_str;
00122 
00123         if (s==0) {
00124                 LM_ERR("null string received\n");
00125                 goto error;
00126         }
00127 
00128         while (*s) {
00129                 /* skip white spaces */
00130                 while (*s && isspace((int)*s))  s++;
00131                 if (*s==0)
00132                         goto parse_error;
00133                 if (n==MAX_ACC_EXTRA) {
00134                         LM_ERR("too many extras -> please increase the internal buffer\n");
00135                         goto error;
00136                 }
00137                 extra = (struct acc_extra*)pkg_malloc(sizeof(struct acc_extra));
00138                 if (extra==0) {
00139                         LM_ERR("no more pkg mem 1\n");
00140                         goto error;
00141                 }
00142                 memset( extra, 0, sizeof(struct acc_extra));
00143 
00144                 /* link the new extra at the end */
00145                 if (tail==0) {
00146                         head = extra;
00147                 } else {
00148                         tail->next = extra;
00149                 }
00150                 tail = extra;
00151                 n++;
00152 
00153                 /* get name */
00154                 foo = s;
00155                 while (*s && !isspace((int)*s) && EQUAL!=*s)  s++;
00156                 if (*s==0)
00157                         goto parse_error;
00158                 if (*s==EQUAL) {
00159                         extra->name.len = (s++) - foo;
00160                 } else {
00161                         extra->name.len = (s++) - foo;
00162                         /* skip spaces */
00163                         while (*s && isspace((int)*s))  s++;
00164                         if (*s!=EQUAL)
00165                                 goto parse_error;
00166                         s++;
00167                 }
00168                 extra->name.s = foo;
00169 
00170                 /* skip spaces */
00171                 while (*s && isspace((int)*s))  s++;
00172 
00173                 /* get value type */
00174                 stmp.s = s; stmp.len = strlen(s);
00175                 if ( (foo=pv_parse_spec(&stmp, &extra->spec))==0 )
00176                         goto parse_error;
00177                 s = foo;
00178 
00179                 /* skip spaces */
00180                 while (*s && isspace((int)*s))  s++;
00181                 if (*s && (*(s++)!=SEPARATOR || *s==0))
00182                         goto parse_error;
00183         }
00184 
00185         /* go throught all extras and make the names null terminated */
00186         for( extra=head ; extra ; extra=extra->next)
00187                 extra->name.s[extra->name.len] = 0;
00188 
00189         return head;
00190 parse_error:
00191         LM_ERR("parse failed in <%s> "
00192                 "around position %d\n",extra_str, (int)(long)(s-extra_str));
00193 error:
00194         LM_ERR("error\n");
00195         destroy_extras(head);
00196         return 0;
00197 }
00198 
00199 
00200 
00201 void destroy_extras( struct acc_extra *extra)
00202 {
00203         struct acc_extra *foo;
00204 
00205         while (extra) {
00206                 foo = extra;
00207                 extra = extra->next;
00208                 pkg_free(foo);
00209         }
00210 }
00211 
00212 
00213 #ifdef RAD_ACC
00214 
00217 int extra2attrs( struct acc_extra *extra, struct attr *attrs, int offset)
00218 {
00219         int i;
00220 
00221         for(i=0 ; extra ; i++, extra=extra->next) {
00222                 attrs[offset+i].n = extra->name.s;
00223         }
00224         return i;
00225 }
00226 #endif
00227 
00228 
00232 int extra2int( struct acc_extra *extra, int *attrs )
00233 {
00234         unsigned int ui;
00235         int i;
00236 
00237         for( i=0 ; extra ; i++,extra=extra->next ) {
00238                 if (str2int( &extra->name, &ui)!=0) {
00239                         LM_ERR("<%s> is not a number\n", extra->name.s);
00240                         return -1;
00241                 }
00242                 attrs[i] = (int)ui;
00243         }
00244         return i;
00245 }
00246 
00247 
00248 
00249 int extra2strar(struct acc_extra *extra, struct sip_msg *rq, str *val_arr,
00250                 int *int_arr, char *type_arr)
00251 {
00252         pv_value_t value;
00253         int n;
00254         int r;
00255 
00256         n = 0;
00257         r = 0;
00258         
00259         while (extra) {
00260                 /* get the value */
00261                 if (pv_get_spec_value( rq, &extra->spec, &value)!=0) {
00262                         LM_ERR("failed to get '%.*s'\n", extra->name.len,extra->name.s);
00263                 }
00264 
00265                 /* check for overflow */
00266                 if (n==MAX_ACC_EXTRA) {
00267                         LM_WARN("array to short -> ommiting extras for accounting\n");
00268                         goto done;
00269                 }
00270 
00271                 if(value.flags&PV_VAL_NULL) {
00272                         /* convert <null> to empty to have consistency */
00273                         val_arr[n].s = 0;
00274                         val_arr[n].len = 0;
00275                         type_arr[n] = TYPE_NULL;
00276                 } else {
00277                         /* set the value into the acc buffer */
00278                         if (value.rs.s+value.rs.len==static_detector) {
00279                                 val_arr[n].s = int_buf + r*INT2STR_MAX_LEN;
00280                                 val_arr[n].len = value.rs.len;
00281                                 memcpy(val_arr[n].s, value.rs.s, value.rs.len);
00282                                 r++;
00283                         } else {
00284                                 val_arr[n] = value.rs;
00285                         }
00286                         if (value.flags&PV_VAL_INT) {
00287                             int_arr[n] = value.ri;
00288                             type_arr[n] = TYPE_INT;
00289                         } else {
00290                             type_arr[n] = TYPE_STR;
00291                         }
00292                 }
00293                 n++;
00294 
00295                 extra = extra->next;
00296         }
00297 
00298 done:
00299         return n;
00300 }
00301 
00302 
00303 int legs2strar( struct acc_extra *legs, struct sip_msg *rq, str *val_arr,
00304                 int *int_arr, char *type_arr, int start)
00305 {
00306         static struct usr_avp *avp[MAX_ACC_LEG];
00307         static struct search_state st[MAX_ACC_LEG];
00308         unsigned short name_type;
00309         int_str name;
00310         int_str value;
00311         int    n;
00312         int    found;
00313         int    r;
00314 
00315         found = 0;
00316         r = 0;
00317 
00318         for( n=0 ; legs ; legs=legs->next,n++ ) {
00319                 /* search for the AVP */
00320                 if (start) {
00321                         if ( pv_get_avp_name( rq, &(legs->spec.pvp), &name, &name_type)<0 )
00322                                 goto exit;
00323                         avp[n] = search_first_avp( name_type, name, &value, st + n);
00324                 } else {
00325                         avp[n] = search_next_avp(st + n, &value);
00326                 }
00327 
00328                 /* set new leg record */
00329                 if (avp[n]) {
00330                         found = 1;
00331                         /* get its value */
00332                         if(avp[n]->flags & AVP_VAL_STR) {
00333                                 val_arr[n] = value.s;
00334                                 type_arr[n] = TYPE_STR;
00335                         } else {
00336                                 val_arr[n].s = int2bstr( value.n, int_buf+r*INT2STR_MAX_LEN,
00337                                         &val_arr[n].len);
00338                                 r++;
00339                                 int_arr[n] = value.n;
00340                                 type_arr[n] = TYPE_INT;
00341                         }
00342                 } else {
00343                         val_arr[n].s = 0;
00344                         val_arr[n].len = 0;
00345                         type_arr[n] = TYPE_NULL;
00346                 }
00347 
00348         }
00349 
00350         if (found || start)
00351                 return n;
00352 exit:
00353         return 0;
00354 }