acc_extra.c

Go to the documentation of this file.
00001 /*
00002  * $Id: acc_extra.c 4812 2008-09-03 15:42:41Z juhe $
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 
00035 /*! \file
00036  * \ingroup acc
00037  * \brief Acc:: Extra attributes
00038  *
00039  * - Module: \ref acc
00040  */
00041 
00042 
00043 
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_extra.h"
00052 
00053 #define EQUAL '='
00054 #define SEPARATOR ';'
00055 
00056 
00057 #if MAX_ACC_EXTRA<MAX_ACC_LEG
00058    #define MAX_ACC_INT_BUF MAX_ACC_LEG
00059 #else
00060    #define MAX_ACC_INT_BUF MAX_ACC_EXTRA
00061 #endif
00062 /* here we copy the strings returned by int2str (which uses a static buffer) */
00063 static char int_buf[INT2STR_MAX_LEN*MAX_ACC_INT_BUF];
00064 
00065 static char *static_detector = 0;
00066 
00067 void init_acc_extra(void)
00068 {
00069    int i;
00070    /* ugly trick to get the address of the static buffer */
00071    static_detector = int2str( (unsigned long)3, &i) + i;
00072 }
00073 
00074 
00075 struct acc_extra *parse_acc_leg(char *extra_str)
00076 {
00077    struct acc_extra *legs;
00078    struct acc_extra *it;
00079    int n;
00080 
00081    legs = parse_acc_extra(extra_str);
00082    if (legs==0) {
00083       LM_ERR("failed to parse extra leg\n");
00084       return 0;
00085    }
00086 
00087    /* check the type and len */
00088    for( it=legs,n=0 ; it ; it=it->next ) {
00089       if (it->spec.type!=PVT_AVP) {
00090          LM_ERR("only AVP are accepted as leg info\n");
00091          destroy_extras(legs);
00092          return 0;
00093       }
00094       n++;
00095       if (n>MAX_ACC_LEG) {
00096          LM_ERR("too many leg info; MAX=%d\n", MAX_ACC_LEG);
00097          destroy_extras(legs);
00098          return 0;
00099       }
00100    }
00101 
00102    return legs;
00103 }
00104 
00105 
00106 struct acc_extra *parse_acc_extra(char *extra_str)
00107 {
00108    struct acc_extra *head;
00109    struct acc_extra *tail;
00110    struct acc_extra *extra;
00111    char *foo;
00112    char *s;
00113    int  n;
00114    str stmp;
00115 
00116    n = 0;
00117    head = 0;
00118    extra = 0;
00119    tail = 0;
00120    s = extra_str;
00121 
00122    if (s==0) {
00123       LM_ERR("null string received\n");
00124       goto error;
00125    }
00126 
00127    while (*s) {
00128       /* skip white spaces */
00129       while (*s && isspace((int)*s))  s++;
00130       if (*s==0)
00131          goto parse_error;
00132       if (n==MAX_ACC_EXTRA) {
00133          LM_ERR("too many extras -> please increase the internal buffer\n");
00134          goto error;
00135       }
00136       extra = (struct acc_extra*)pkg_malloc(sizeof(struct acc_extra));
00137       if (extra==0) {
00138          LM_ERR("no more pkg mem 1\n");
00139          goto error;
00140       }
00141       memset( extra, 0, sizeof(struct acc_extra));
00142 
00143       /* link the new extra at the end */
00144       if (tail==0) {
00145          head = extra;
00146       } else {
00147          tail->next = extra;
00148       }
00149       tail = extra;
00150       n++;
00151 
00152       /* get name */
00153       foo = s;
00154       while (*s && !isspace((int)*s) && EQUAL!=*s)  s++;
00155       if (*s==0)
00156          goto parse_error;
00157       if (*s==EQUAL) {
00158          extra->name.len = (s++) - foo;
00159       } else {
00160          extra->name.len = (s++) - foo;
00161          /* skip spaces */
00162          while (*s && isspace((int)*s))  s++;
00163          if (*s!=EQUAL)
00164             goto parse_error;
00165          s++;
00166       }
00167       extra->name.s = foo;
00168 
00169       /* skip spaces */
00170       while (*s && isspace((int)*s))  s++;
00171 
00172       /* get value type */
00173       stmp.s = s; stmp.len = strlen(s);
00174       if ( (foo=pv_parse_spec(&stmp, &extra->spec))==0 )
00175          goto parse_error;
00176       s = foo;
00177 
00178       /* skip spaces */
00179       while (*s && isspace((int)*s))  s++;
00180       if (*s && (*(s++)!=SEPARATOR || *s==0))
00181          goto parse_error;
00182    }
00183 
00184    /* go throught all extras and make the names null terminated */
00185    for( extra=head ; extra ; extra=extra->next)
00186       extra->name.s[extra->name.len] = 0;
00187 
00188    return head;
00189 parse_error:
00190    LM_ERR("parse failed in <%s> "
00191       "around position %d\n",extra_str, (int)(long)(s-extra_str));
00192 error:
00193    LM_ERR("error\n");
00194    destroy_extras(head);
00195    return 0;
00196 }
00197 
00198 
00199 
00200 void destroy_extras( struct acc_extra *extra)
00201 {
00202    struct acc_extra *foo;
00203 
00204    while (extra) {
00205       foo = extra;
00206       extra = extra->next;
00207       pkg_free(foo);
00208    }
00209 }
00210 
00211 
00212 #ifdef RAD_ACC
00213 /*! \brief extra name is moved as string part of an attribute; str.len will contain an
00214  * index to the corresponding attribute
00215  */
00216 int extra2attrs( struct acc_extra *extra, struct attr *attrs, int offset)
00217 {
00218    int i;
00219 
00220    for(i=0 ; extra ; i++, extra=extra->next) {
00221       attrs[offset+i].n = extra->name.s;
00222    }
00223    return i;
00224 }
00225 #endif
00226 
00227 
00228 /*! \brief converts the name of the extra from str to integer 
00229  * and stores it over str.len ; str.s is freed and made zero
00230  */
00231 int extra2int( struct acc_extra *extra, int *attrs )
00232 {
00233    unsigned int ui;
00234    int i;
00235 
00236    for( i=0 ; extra ; i++,extra=extra->next ) {
00237       if (str2int( &extra->name, &ui)!=0) {
00238          LM_ERR("<%s> is not a number\n", extra->name.s);
00239          return -1;
00240       }
00241       attrs[i] = (int)ui;
00242    }
00243    return i;
00244 }
00245 
00246 
00247 
00248 int extra2strar(struct acc_extra *extra, struct sip_msg *rq, str *val_arr,
00249       int *int_arr, char *type_arr)
00250 {
00251    pv_value_t value;
00252    int n;
00253    int r;
00254 
00255    n = 0;
00256    r = 0;
00257    
00258    while (extra) {
00259       /* get the value */
00260       if (pv_get_spec_value( rq, &extra->spec, &value)!=0) {
00261          LM_ERR("failed to get '%.*s'\n", extra->name.len,extra->name.s);
00262       }
00263 
00264       /* check for overflow */
00265       if (n==MAX_ACC_EXTRA) {
00266          LM_WARN("array to short -> ommiting extras for accounting\n");
00267          goto done;
00268       }
00269 
00270       if(value.flags&PV_VAL_NULL) {
00271          /* convert <null> to empty to have consistency */
00272          val_arr[n].s = 0;
00273          val_arr[n].len = 0;
00274          type_arr[n] = TYPE_NULL;
00275       } else {
00276          /* set the value into the acc buffer */
00277          if (value.rs.s+value.rs.len==static_detector) {
00278             val_arr[n].s = int_buf + r*INT2STR_MAX_LEN;
00279             val_arr[n].len = value.rs.len;
00280             memcpy(val_arr[n].s, value.rs.s, value.rs.len);
00281             r++;
00282          } else {
00283             val_arr[n] = value.rs;
00284          }
00285          if (value.flags&PV_VAL_INT) {
00286              int_arr[n] = value.ri;
00287              type_arr[n] = TYPE_INT;
00288          } else {
00289              type_arr[n] = TYPE_STR;
00290          }
00291       }
00292       n++;
00293 
00294       extra = extra->next;
00295    }
00296 
00297 done:
00298    return n;
00299 }
00300 
00301 
00302 int legs2strar( struct acc_extra *legs, struct sip_msg *rq, str *val_arr,
00303       int *int_arr, char *type_arr, int start)
00304 {
00305    static struct usr_avp *avp[MAX_ACC_LEG];
00306    unsigned short name_type;
00307    int_str name;
00308    int_str value;
00309    int    n;
00310    int    found;
00311    int    r;
00312 
00313    found = 0;
00314    r = 0;
00315 
00316    for( n=0 ; legs ; legs=legs->next,n++ ) {
00317       /* search for the AVP */
00318       if (start) {
00319          if ( pv_get_avp_name( rq, &(legs->spec.pvp), &name, &name_type)<0 )
00320             goto exit;
00321          avp[n] = search_first_avp( name_type, name, &value, 0);
00322       } else {
00323          avp[n] = search_next_avp( avp[n], &value);
00324       }
00325 
00326       /* set new leg record */
00327       if (avp[n]) {
00328          found = 1;
00329          /* get its value */
00330          if(avp[n]->flags & AVP_VAL_STR) {
00331             val_arr[n] = value.s;
00332             type_arr[n] = TYPE_STR;
00333          } else {
00334             val_arr[n].s = int2bstr( value.n, int_buf+r*INT2STR_MAX_LEN,
00335                &val_arr[n].len);
00336             r++;
00337             int_arr[n] = value.n;
00338             type_arr[n] = TYPE_INT;
00339          }
00340       } else {
00341          val_arr[n].s = 0;
00342          val_arr[n].len = 0;
00343          type_arr[n] = TYPE_NULL;
00344       }
00345 
00346    }
00347 
00348    if (found || start)
00349       return n;
00350 exit:
00351    return 0;
00352 }

Generated on Thu May 17 12:00:24 2012 for Kamailio - The Open Source SIP Server by  doxygen 1.5.6