1 /*
2 * Copyright (C) 2004-2006 Voice Sistem SRL
3 * Copyright (C) 2008 Juha Heinanen
4 *
5 * This file is part of Kamailio, a free SIP server.
6 *
7 * Kamailio is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * Kamailio is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 *
22 */
23
24 /*! \file
25 * \ingroup acc
26 * \brief Acc:: Extra attributes
27 *
28 * - Module: \ref acc
29 */
30
31
32
33 #include <stdlib.h>
34 #include <string.h>
35 #include <ctype.h>
36 #include "../../core/dprint.h"
37 #include "../../core/ut.h"
38 #include "../../core/usr_avp.h"
39 #include "../../core/mem/mem.h"
40 #include "acc_api.h"
41 #include "acc_extra.h"
42
43 #define EQUAL '='
44 #define SEPARATOR ';'
45
46
47 #if MAX_ACC_EXTRA<MAX_ACC_LEG
48 #define MAX_ACC_INT_BUF MAX_ACC_LEG
49 #else
50 #define MAX_ACC_INT_BUF MAX_ACC_EXTRA
51 #endif
52 /* here we copy the strings returned by int2str (which uses a static buffer) */
53 static char int_buf[INT2STR_MAX_LEN*MAX_ACC_INT_BUF];
54
parse_acc_leg(char * extra_str)55 struct acc_extra *parse_acc_leg(char *extra_str)
56 {
57 struct acc_extra *legs;
58 struct acc_extra *it;
59 int n;
60
61 legs = parse_acc_extra(extra_str);
62 if (legs==0) {
63 LM_ERR("failed to parse extra leg\n");
64 return 0;
65 }
66
67 /* check the type and len */
68 for( it=legs,n=0 ; it ; it=it->next ) {
69 if (it->spec.type!=PVT_AVP) {
70 LM_ERR("only AVP are accepted as leg info\n");
71 destroy_extras(legs);
72 return 0;
73 }
74 n++;
75 if (n>MAX_ACC_LEG) {
76 LM_ERR("too many leg info; MAX=%d\n", MAX_ACC_LEG);
77 destroy_extras(legs);
78 return 0;
79 }
80 }
81
82 return legs;
83 }
84
85
parse_acc_extra(char * extra_str)86 struct acc_extra *parse_acc_extra(char *extra_str)
87 {
88 struct acc_extra *head;
89 struct acc_extra *tail;
90 struct acc_extra *extra;
91 char *foo;
92 char *s;
93 int n;
94 str stmp;
95
96 n = 0;
97 head = 0;
98 extra = 0;
99 tail = 0;
100 s = extra_str;
101
102 if (s==0) {
103 LM_ERR("null string received\n");
104 goto error;
105 }
106
107 while (*s) {
108 /* skip white spaces */
109 while (*s && isspace((int)*s)) s++;
110 if (*s==0)
111 goto parse_error;
112 if (n==MAX_ACC_EXTRA) {
113 LM_ERR("too many extras -> please increase the internal buffer\n");
114 goto error;
115 }
116 extra = (struct acc_extra*)pkg_malloc(sizeof(struct acc_extra));
117 if (extra==0) {
118 PKG_MEM_ERROR;
119 goto error;
120 }
121 memset( extra, 0, sizeof(struct acc_extra));
122
123 /* link the new extra at the end */
124 if (tail==0) {
125 head = extra;
126 } else {
127 tail->next = extra;
128 }
129 tail = extra;
130 n++;
131
132 /* get name */
133 foo = s;
134 while (*s && !isspace((int)*s) && EQUAL!=*s) s++;
135 if (*s==0)
136 goto parse_error;
137 if (*s==EQUAL) {
138 extra->name.len = (s++) - foo;
139 } else {
140 extra->name.len = (s++) - foo;
141 /* skip spaces */
142 while (*s && isspace((int)*s)) s++;
143 if (*s!=EQUAL)
144 goto parse_error;
145 s++;
146 }
147 extra->name.s = foo;
148
149 /* skip spaces */
150 while (*s && isspace((int)*s)) s++;
151
152 /* get value type */
153 stmp.s = s; stmp.len = strlen(s);
154 if ( (foo=pv_parse_spec(&stmp, &extra->spec))==0 )
155 goto parse_error;
156 s = foo;
157
158 /* skip spaces */
159 while (*s && isspace((int)*s)) s++;
160 if (*s && (*(s++)!=SEPARATOR || *s==0))
161 goto parse_error;
162 }
163
164 /* go throught all extras and make the names null terminated */
165 for( extra=head ; extra ; extra=extra->next)
166 extra->name.s[extra->name.len] = 0;
167
168 return head;
169 parse_error:
170 LM_ERR("parse failed in <%s> "
171 "around position %d\n",extra_str, (int)(long)(s-extra_str));
172 error:
173 LM_ERR("error\n");
174 destroy_extras(head);
175 return 0;
176 }
177
178
179
destroy_extras(struct acc_extra * extra)180 void destroy_extras( struct acc_extra *extra)
181 {
182 struct acc_extra *foo;
183
184 while (extra) {
185 foo = extra;
186 extra = extra->next;
187 pkg_free(foo);
188 }
189 }
190
191
192 /*! \brief converts the name of the extra from str to integer
193 * and stores it over str.len ; str.s is freed and made zero
194 */
extra2int(struct acc_extra * extra,int * attrs)195 int extra2int( struct acc_extra *extra, int *attrs )
196 {
197 unsigned int ui;
198 int i;
199
200 for( i=0 ; extra ; i++,extra=extra->next ) {
201 if (str2int( &extra->name, &ui)!=0) {
202 LM_ERR("<%s> is not a number\n", extra->name.s);
203 return -1;
204 }
205 attrs[i] = (int)ui;
206 }
207 return i;
208 }
209
extra2strar(struct acc_extra * extra,struct sip_msg * rq,str * val_arr,int * int_arr,char * type_arr)210 int extra2strar(struct acc_extra *extra, struct sip_msg *rq, str *val_arr,
211 int *int_arr, char *type_arr)
212 {
213 pv_value_t value;
214 int n;
215 int i;
216
217 n = 0;
218 i = 0;
219
220 while (extra) {
221 /* get the value */
222 if (pv_get_spec_value( rq, &extra->spec, &value)!=0) {
223 LM_ERR("failed to get '%.*s'\n", extra->name.len,extra->name.s);
224 }
225
226 /* check for overflow */
227 if (n==MAX_ACC_EXTRA) {
228 LM_WARN("array to short -> omitting extras for accounting\n");
229 goto done;
230 }
231
232 if(value.flags&PV_VAL_NULL) {
233 /* convert <null> to empty to have consistency */
234 val_arr[n].s = 0;
235 val_arr[n].len = 0;
236 type_arr[n] = TYPE_NULL;
237 } else {
238 val_arr[n].s = (char *)pkg_malloc(value.rs.len);
239 if (val_arr[n].s == NULL ) {
240 PKG_MEM_ERROR;
241 /* Cleanup already allocated memory and
242 * return that we didn't do anything */
243 for (i = 0; i < n ; i++) {
244 if (NULL != val_arr[i].s){
245 pkg_free(val_arr[i].s);
246 val_arr[i].s = NULL;
247 }
248 }
249 n = 0;
250 goto done;
251 }
252 memcpy(val_arr[n].s, value.rs.s, value.rs.len);
253 val_arr[n].len = value.rs.len;
254 if (value.flags&PV_VAL_INT) {
255 int_arr[n] = value.ri;
256 type_arr[n] = TYPE_INT;
257 } else {
258 type_arr[n] = TYPE_STR;
259 }
260 }
261 n++;
262
263 extra = extra->next;
264 }
265
266 done:
267 return n;
268 }
269
extra2strar_dlg_only(struct acc_extra * extra,struct dlg_cell * dlg,str * val_arr,int * int_arr,char * type_arr,const struct dlg_binds * p_dlgb)270 int extra2strar_dlg_only(struct acc_extra *extra, struct dlg_cell* dlg, str *val_arr,
271 int *int_arr, char *type_arr, const struct dlg_binds* p_dlgb)
272 {
273 //string value;
274 str* value = 0;
275 int n=0;
276
277 if( !dlg || !val_arr || !int_arr || !type_arr || !p_dlgb)
278 {
279 LM_ERR( "invalid input parameter!\n");
280 return 0;
281 }
282
283 while (extra) {
284
285 /* check for overflow */
286 if (n==MAX_ACC_EXTRA) {
287 LM_WARN("array to short -> omitting extras for accounting\n");
288 goto done;
289 }
290
291 val_arr[n].s = 0;
292 val_arr[n].len = 0;
293 type_arr[n] = TYPE_NULL;
294
295 str key = extra->spec.pvp.pvn.u.isname.name.s;
296 if ( key.len == 0 || !key.s)
297 {
298 n++; extra = extra->next; continue;
299 }
300 /* get the value */
301 value = p_dlgb->get_dlg_var( dlg, &key);
302
303 if (value)
304 {
305 val_arr[n].s = value->s;
306 val_arr[n].len = value->len;
307 type_arr[n] = TYPE_STR;
308 }
309
310 n++;
311 extra = extra->next;
312 }
313 done:
314 return n;
315 }
316
legs2strar(struct acc_extra * legs,struct sip_msg * rq,str * val_arr,int * int_arr,char * type_arr,int start)317 int legs2strar( struct acc_extra *legs, struct sip_msg *rq, str *val_arr,
318 int *int_arr, char *type_arr, int start)
319 {
320 static struct usr_avp *avp[MAX_ACC_LEG];
321 static struct search_state st[MAX_ACC_LEG];
322 unsigned short name_type;
323 int_str name;
324 int_str value;
325 int n;
326 int found;
327 int r;
328
329 found = 0;
330 r = 0;
331
332 for( n=0 ; legs ; legs=legs->next,n++ ) {
333 /* search for the AVP */
334 if (start) {
335 if ( pv_get_avp_name( rq, &(legs->spec.pvp), &name, &name_type)<0 )
336 goto exit;
337 avp[n] = search_first_avp( name_type, name, &value, st + n);
338 } else {
339 avp[n] = search_next_avp(st + n, &value);
340 }
341
342 /* set new leg record */
343 if (avp[n]) {
344 found = 1;
345 /* get its value */
346 if(avp[n]->flags & AVP_VAL_STR) {
347 val_arr[n] = value.s;
348 type_arr[n] = TYPE_STR;
349 } else {
350 val_arr[n].s = int2bstr( value.n, int_buf+r*INT2STR_MAX_LEN,
351 &val_arr[n].len);
352 r++;
353 int_arr[n] = value.n;
354 type_arr[n] = TYPE_INT;
355 }
356 } else {
357 val_arr[n].s = 0;
358 val_arr[n].len = 0;
359 type_arr[n] = TYPE_NULL;
360 }
361
362 }
363
364 if (found || start)
365 return n;
366 exit:
367 return 0;
368 }
369