formatted logging module
[sip-router] / modules_s / xlog / xl_lib.c
1 /**\r
2  * $Id$
3  *
4  * XLOG module\r
5  *\r
6  * Copyright (C) 2001-2003 Fhg Fokus\r
7  *\r
8  * This file is part of ser, a free SIP server.\r
9  *\r
10  * ser is free software; you can redistribute it and/or modify\r
11  * it under the terms of the GNU General Public License as published by\r
12  * the Free Software Foundation; either version 2 of the License, or\r
13  * (at your option) any later version\r
14  *\r
15  * For a license to use the ser software under conditions\r
16  * other than those described here, or to purchase support for this\r
17  * software, please contact iptel.org by e-mail at the following addresses:\r
18  *    info@iptel.org\r
19  *\r
20  * ser is distributed in the hope that it will be useful,\r
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
23  * GNU General Public License for more details.\r
24  *\r
25  * You should have received a copy of the GNU General Public License \r
26  * along with this program; if not, write to the Free Software \r
27  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
28  */\r
29 \r
30 #include <stdio.h>\r
31 #include <string.h>\r
32 #include <time.h>\r
33 #include <sys/types.h>\r
34 #include <unistd.h>\r
35 \r
36 #include "../../dprint.h"\r
37 #include "../../mem/mem.h"\r
38 #include "../../ut.h" \r
39 #include "../../trim.h" \r
40 \r
41 #include "../../parser/parse_from.h"\r
42 #include "../../parser/parse_uri.h"\r
43 \r
44 #include "xl_lib.h"\r
45 \r
46 static str str_null = { "<null>", 6 };\r
47 static str str_per = { "%", 1 };\r
48 \r
49 int msg_id = 0;\r
50 time_t msg_tm = 0;\r
51 int cld_pid = 0;\r
52 \r
53 static int xl_get_null(struct sip_msg *msg, str *res)\r
54 {\r
55         if(msg==NULL || res==NULL)\r
56                 return -1;\r
57         \r
58         res->s = str_null.s;\r
59         res->len = str_null.len;\r
60         return 0;\r
61 }\r
62 \r
63 static int xl_get_percent(struct sip_msg *msg, str *res)\r
64 {\r
65         if(msg==NULL || res==NULL)\r
66                 return -1;\r
67         \r
68         res->s = str_per.s;\r
69         res->len = str_per.len;\r
70         return 0;\r
71 }\r
72 \r
73 static int xl_get_pid(struct sip_msg *msg, str *res)\r
74 {\r
75         int l = 0;\r
76         char *ch = NULL;\r
77 \r
78         if(msg==NULL || res==NULL)\r
79                 return -1;\r
80 \r
81         if(cld_pid == 0)\r
82                 cld_pid = (int)getpid();\r
83         ch = int2str(cld_pid, &l);\r
84 \r
85         res->s = ch;\r
86         res->len = l;\r
87 \r
88         return 0;\r
89 }\r
90 \r
91 static int xl_get_times(struct sip_msg *msg, str *res)\r
92 {\r
93         int l = 0;\r
94         char *ch = NULL;\r
95                 \r
96         if(msg==NULL || res==NULL)\r
97                 return -1;\r
98 \r
99         if(msg_id != msg->id)\r
100         {\r
101                 msg_tm = time(NULL);\r
102                 msg_id = msg->id;\r
103         }\r
104         ch = int2str(msg_tm, &l);\r
105         \r
106         res->s = ch;\r
107         res->len = l;\r
108 \r
109         return 0;\r
110 }\r
111 static int xl_get_timef(struct sip_msg *msg, str *res)\r
112 {\r
113         char *ch = NULL;\r
114         \r
115         if(msg==NULL || res==NULL)\r
116                 return -1;\r
117         if(msg_id != msg->id)\r
118         {\r
119                 msg_tm = time(NULL);\r
120                 msg_id = msg->id;\r
121         }\r
122         \r
123         ch = ctime(&msg_tm);\r
124         \r
125         res->s = ch;\r
126         res->len = strlen(ch)-1;\r
127 \r
128         return 0;\r
129 }\r
130 \r
131 static int xl_get_msgid(struct sip_msg *msg, str *res)\r
132 {\r
133         int l = 0;\r
134         char *ch = NULL;\r
135 \r
136         if(msg==NULL || res==NULL)\r
137                 return -1;\r
138 \r
139         ch = int2str(msg->id, &l);\r
140         res->s = ch;\r
141         res->len = l;\r
142 \r
143         return 0;\r
144 }\r
145 \r
146 static int xl_get_method(struct sip_msg *msg, str *res)\r
147 {\r
148         if(msg==NULL || res==NULL)\r
149                 return -1;\r
150 \r
151         if(msg->first_line.type == SIP_REQUEST)\r
152         {\r
153                 res->s = msg->first_line.u.request.method.s;\r
154                 res->len = msg->first_line.u.request.method.len;\r
155         }\r
156         else\r
157                 return xl_get_null(msg, res);\r
158         \r
159         return 0;\r
160 }\r
161 \r
162 static int xl_get_ruri(struct sip_msg *msg, str *res)\r
163 {\r
164         if(msg==NULL || res==NULL)\r
165                 return -1;\r
166 \r
167         if(msg->parsed_uri_ok==0 /* R-URI not parsed*/ && parse_sip_msg_uri(msg)<0)\r
168         {\r
169                 LOG(L_ERR, "XLOG: xl_get_ruri: ERROR while parsing the R-URI\n");\r
170                 return xl_get_null(msg, res);\r
171         }\r
172         \r
173         res->s=msg->parsed_uri.user.len>0?msg->parsed_uri.user.s:msg->parsed_uri.host.s;\r
174         res->len = msg->parsed_uri.user.len+\r
175                                 msg->parsed_uri.passwd.len+\r
176                                 msg->parsed_uri.host.len+\r
177                                 msg->parsed_uri.port.len+\r
178                                 msg->parsed_uri.params.len+\r
179                                 msg->parsed_uri.headers.len+\r
180                                 (msg->parsed_uri.passwd.len>0?1:0)+\r
181                                 (msg->parsed_uri.port.len>0?1:0)+\r
182                                 (msg->parsed_uri.params.len>0?1:0)+\r
183                                 (msg->parsed_uri.headers.len>0?1:0);\r
184         return 0;\r
185 }\r
186 \r
187 static int xl_get_contact(struct sip_msg* msg, str* res)\r
188 {\r
189         if(msg==NULL || res==NULL)\r
190                 return -1;\r
191 \r
192         if(msg->contact==NULL || parse_headers(msg, HDR_CONTACT, 0)==-1 \r
193                 || !msg->contact->body.s || msg->contact->body.len<=0)\r
194         {\r
195                 DBG("XLOG: xl_get_contact: no contact header\n");\r
196                 return xl_get_null(msg, res);\r
197         }\r
198         \r
199         res->s = msg->contact->body.s;\r
200         res->len = msg->contact->body.len;\r
201 \r
202         \r
203 //      res->s = ((struct to_body*)msg->contact->parsed)->uri.s;\r
204 //      res->len = ((struct to_body*)msg->contact->parsed)->uri.len;\r
205 \r
206         return 0;\r
207 }\r
208 \r
209 \r
210 static int xl_get_from(struct sip_msg *msg, str *res)\r
211 {\r
212         if(msg==NULL || res==NULL)\r
213                 return -1;\r
214 \r
215         if(msg->from==NULL && parse_from_header(msg)==-1)\r
216         {\r
217                 LOG(L_ERR, "XLOG: xl_get_from: ERROR cannot parse FROM header\n");\r
218                 return xl_get_null(msg, res);\r
219         }\r
220         \r
221         if(msg->from==NULL || get_from(msg)==NULL)\r
222                 return xl_get_null(msg, res);\r
223 \r
224         res->s = get_from(msg)->uri.s;\r
225         res->len = get_from(msg)->uri.len; \r
226         \r
227         return 0;\r
228 }\r
229 \r
230 static int xl_get_from_tag(struct sip_msg *msg, str *res)\r
231 {\r
232         if(msg==NULL || res==NULL)\r
233                 return -1;\r
234 \r
235         if(msg->from==NULL && parse_from_header(msg)==-1)\r
236         {\r
237                 LOG(L_ERR, "XLOG: xl_get_from: ERROR cannot parse FROM header\n");\r
238                 return xl_get_null(msg, res);\r
239         }\r
240         \r
241         \r
242         if(msg->from==NULL || get_from(msg)==NULL || get_from(msg)->tag_value.s==NULL)\r
243                 return xl_get_null(msg, res);\r
244 \r
245         res->s = get_from(msg)->uri.s;\r
246         res->len = get_from(msg)->uri.len; \r
247 \r
248         return 0;\r
249 }\r
250 \r
251 \r
252 static int xl_get_to(struct sip_msg *msg, str *res)\r
253 {\r
254         if(msg==NULL || res==NULL)\r
255                 return -1;\r
256 \r
257         if(msg->to==NULL && parse_headers(msg, HDR_TO, 0)==-1)\r
258         {\r
259                 LOG(L_ERR, "XLOG: xl_get_to: ERROR cannot parse TO header\n");\r
260                 return xl_get_null(msg, res);\r
261         }\r
262         if(msg->to==NULL || get_to(msg)==NULL)\r
263                 return xl_get_null(msg, res);\r
264 \r
265         res->s = get_to(msg)->uri.s;\r
266         res->len = get_to(msg)->uri.len; \r
267         \r
268         return 0;\r
269 }\r
270 \r
271 static int xl_get_to_tag(struct sip_msg* msg, str* res)\r
272 {\r
273         if(msg==NULL || res==NULL)\r
274                 return -1;\r
275 \r
276         if(msg->to==NULL && parse_headers(msg, HDR_TO, 0)==-1)\r
277         {\r
278                 LOG(L_ERR, "XLOG: xl_get_to: ERROR cannot parse TO header\n");\r
279                 return xl_get_null(msg, res);\r
280         }\r
281         \r
282         if (get_to(msg)->tag_value.len <= 0) \r
283                 return xl_get_null(msg, res);\r
284         \r
285         res->s = get_to(msg)->tag_value.s;\r
286         res->len = get_to(msg)->tag_value.len;\r
287 \r
288         return 0;\r
289 }\r
290 \r
291 static int xl_get_cseq(struct sip_msg *msg, str *res)\r
292 {\r
293         if(msg==NULL || res==NULL)\r
294                 return -1;\r
295         \r
296         if(msg->cseq==NULL && parse_headers(msg, HDR_CSEQ, 0)==-1)\r
297         {\r
298                 LOG(L_ERR, "XLOG: xl_get_cseq: ERROR cannot parse CSEQ header\n");\r
299                 return xl_get_null(msg, res);\r
300         }\r
301 \r
302         res->s = get_cseq(msg)->number.s;\r
303         res->len = get_cseq(msg)->number.len;\r
304 \r
305         return 0;\r
306 }\r
307 \r
308 static int xl_get_callid(struct sip_msg *msg, str *res)\r
309 {\r
310         if(msg==NULL || res==NULL)\r
311                 return -1;\r
312         \r
313         if(msg->callid==NULL && parse_headers(msg, HDR_CALLID, 0)==-1)\r
314         {\r
315                 LOG(L_ERR, "XLOG: xl_get_cseq: ERROR cannot parse Call-Id header\n");\r
316                 return xl_get_null(msg, res);\r
317         }\r
318 \r
319         res->s = msg->callid->body.s;\r
320         res->len = msg->callid->body.len;\r
321         trim(res);\r
322 \r
323         return 0;\r
324 }\r
325 \r
326 \r
327 int xl_parse_format(char *s, xl_elog_p *el)\r
328 {\r
329         char *p;\r
330         int n = 0;\r
331         xl_elog_p e, e0;\r
332         \r
333         if(s==NULL || el==NULL)\r
334                 return -1;\r
335 \r
336         DBG("XLOG: xl_parse_format: parsing [%s]\n", s);\r
337         \r
338         p = s;\r
339         *el = NULL;\r
340         e = e0 = NULL;\r
341 \r
342         while(*p)\r
343         {\r
344                 e0 = e;\r
345                 e = pkg_malloc(sizeof(xl_elog_t));\r
346                 if(!e)\r
347                         goto error;\r
348                 memset(e, 0, sizeof(xl_elog_t));\r
349                 n++;\r
350                 if(*el == NULL)\r
351                         *el = e;\r
352                 if(e0)\r
353                         e0->next = e;\r
354         \r
355                 e->text.s = p;\r
356                 while(*p && *p!='%')\r
357                         p++;\r
358                 e->text.len = p - e->text.s;\r
359                 if(*p == '\0')\r
360                         break;\r
361 \r
362                 p++;\r
363                 switch(*p)\r
364                 {\r
365                         case 'c':\r
366                                 p++;\r
367                                 switch(*p)\r
368                                 {\r
369                                         case 't':\r
370                                                 e->itf = xl_get_contact;\r
371                                         break;\r
372                                         case 'i':\r
373                                                 e->itf = xl_get_callid;\r
374                                         break;\r
375                                         case 's':\r
376                                                 e->itf = xl_get_cseq;\r
377                                         break;\r
378                                         default:\r
379                                                 e->itf = xl_get_null;\r
380                                 }\r
381                         break;\r
382                         case 'f':\r
383                                 p++;\r
384                                 switch(*p)\r
385                                 {\r
386                                         case 'u':\r
387                                                 e->itf = xl_get_from;\r
388                                         break;\r
389                                         case 't':\r
390                                                 e->itf = xl_get_from_tag;\r
391                                         break;\r
392                                         default:\r
393                                                 e->itf = xl_get_null;\r
394                                 }\r
395                         break;\r
396                         case 'm':\r
397                                 p++;\r
398                                 switch(*p)\r
399                                 {\r
400                                         case 'i':\r
401                                                 e->itf = xl_get_msgid;\r
402                                         break;\r
403                                         default:\r
404                                                 e->itf = xl_get_null;\r
405                                 }\r
406                                 break;\r
407                         case 'p':\r
408                                 p++;\r
409                                 switch(*p)\r
410                                 {\r
411                                         case 'p':\r
412                                                 e->itf = xl_get_pid;\r
413                                         break;\r
414                                         default:\r
415                                                 e->itf = xl_get_null;\r
416                                 }\r
417                         break;\r
418                         case 'r':\r
419                                 p++;\r
420                                 switch(*p)\r
421                                 {\r
422                                         case 'm':\r
423                                                 e->itf = xl_get_method;\r
424                                         break;\r
425                                         case 'u':\r
426                                                 e->itf = xl_get_ruri;\r
427                                         break;\r
428                                         default:\r
429                                                 e->itf = xl_get_null;\r
430                                 }\r
431                         break;\r
432                         case 't':\r
433                                 p++;\r
434                                 switch(*p)\r
435                                 {\r
436                                         case 'u':\r
437                                                 e->itf = xl_get_to;\r
438                                         break;\r
439                                         case 't':\r
440                                                 e->itf = xl_get_to_tag;\r
441                                         break;\r
442                                         default:\r
443                                                 e->itf = xl_get_null;\r
444                                 }\r
445                         break;\r
446                         case 'T':\r
447                                 p++;\r
448                                 switch(*p)\r
449                                 {\r
450                                         case 's':\r
451                                                 e->itf = xl_get_times;\r
452                                         break;\r
453                                         case 'f':\r
454                                                 e->itf = xl_get_timef;\r
455                                         break;\r
456                                         default:\r
457                                                 e->itf = xl_get_null;\r
458                                 }\r
459                         break;\r
460                         case '%':\r
461                                 e->itf = xl_get_percent;\r
462                         break;\r
463                         default:\r
464                                 e->itf = xl_get_null;\r
465                 }\r
466 \r
467                 if(*p == '\0')\r
468                         break;\r
469                 p++;\r
470         }\r
471         DBG("XLOG: xl_parse_format: format parsed OK: [%d] items\n", n);\r
472 \r
473         return 0;\r
474 \r
475 error:\r
476         xl_elog_free_all(*el);\r
477         *el = NULL;\r
478         return -1;\r
479 }\r
480 \r
481 int xl_print_log(struct sip_msg* msg, xl_elog_p log, char *buf, int *len)\r
482 {\r
483         int n;\r
484         str tok;\r
485         xl_elog_p it;\r
486         \r
487         if(msg==NULL || log==NULL || buf==NULL || len==NULL)\r
488                 return -1;\r
489 \r
490         if(*len <= 0)\r
491                 return -1;\r
492 \r
493         it = log;\r
494         buf[0] = '\0';\r
495         n = 0;\r
496         while(it)\r
497         {\r
498                 // put the text\r
499                 if(it->text.s && it->text.len>0)\r
500                 {\r
501                         if(n+it->text.len < *len)\r
502                         {\r
503                                 strncat(buf, it->text.s, it->text.len);\r
504                                 n+= it->text.len;\r
505                         }\r
506                         else\r
507                                 goto overflow;\r
508                 }\r
509                 // put the value of the specifier\r
510                 if(it->itf && !((*it->itf)(msg, &tok)))\r
511                 {\r
512                         if(n+tok.len < *len)\r
513                         {\r
514                                 strncat(buf, tok.s, tok.len);\r
515                                 n += tok.len;\r
516                         }\r
517                         else\r
518                                 goto overflow;\r
519                 }\r
520                 it = it->next;\r
521         }\r
522         goto done;\r
523         \r
524 overflow:\r
525         DBG("XLOG: xl_print_log: buffer overflow ...\n");\r
526 done:\r
527         DBG("XLOG: xl_print_log: final buffer length %d\n", n);\r
528         *len = n;\r
529         return 0;\r
530 }\r
531 \r
532 int xl_elog_free_all(xl_elog_p log)\r
533 {\r
534         xl_elog_p t;\r
535         while(log)\r
536         {\r
537                 t = log;\r
538                 log = log->next;\r
539                 pkg_free(t);\r
540         }\r
541         return 0;\r
542 }\r
543 \r