fixed trace bug
[lcr.git] / trace.c
1 /*****************************************************************************\
2 **                                                                           **
3 ** Linux Call Router                                                         **
4 **                                                                           **
5 **---------------------------------------------------------------------------**
6 ** Copyright: Andreas Eversberg                                              **
7 **                                                                           **
8 ** trace functions                                                           **
9 **                                                                           **
10 \*****************************************************************************/ 
11
12 #include "main.h"
13
14 struct trace trace;
15 char trace_string[MAX_TRACE_ELEMENTS * 100 + 400];
16
17 static char *spaces[11] = {
18         "          ",
19         "         ",
20         "        ",
21         "       ",
22         "      ",
23         "     ",
24         "    ",
25         "   ",
26         "  ",
27         " ",
28         "",
29 };
30
31 /*
32  * initializes a new trace
33  * all values will be reset
34  */
35 void _start_trace(const char *__file, int __line, int port, struct interface *interface, char *caller, char *dialing, int direction, int category, int serial, char *name)
36 {
37         if (trace.name[0])
38                 PERROR("trace already started (name=%s) in file %s line %d\n", trace.name, __file, __line);
39         memset(&trace, 0, sizeof(struct trace));
40         trace.port = port;
41         if (interface)
42                 SCPY(trace.interface, interface->name);
43         if (caller) if (caller[0])
44                 SCPY(trace.caller, caller);
45         if (dialing) if (dialing[0])
46                 SCPY(trace.dialing, dialing);
47         trace.direction = direction;
48         trace.category = category;
49         trace.serial = serial;
50         if (name) if (name[0])
51                 SCPY(trace.name, name);
52         if (!trace.name[0])
53                 SCPY(trace.name, "<unknown>");
54         trace.sec = now_tv.tv_sec;
55         trace.usec = now_tv.tv_usec;
56 }
57
58
59 /*
60  * adds a new element to the trace
61  * if subelement is given, element will also contain a subelement
62  * if multiple subelements belong to same element, name must be equal for all subelements
63  */
64 void _add_trace(const char *__file, int __line, char *name, char *sub, const char *fmt, ...)
65 {
66         va_list args;
67
68         if (!trace.name[0])
69                 PERROR("trace not started in file %s line %d\n", __file, __line);
70         
71         /* check for required name value */
72         if (!name)
73                 goto nostring;
74         if (!name[0])
75         {
76                 nostring:
77                 PERROR("trace with name=%s gets element with no string\n", trace.name);
78                 return;
79         }
80         
81         /* write name, sub and value */
82         SCPY(trace.element[trace.elements].name, name);
83         if (sub) if (sub[0])
84                 SCPY(trace.element[trace.elements].sub, sub);
85         if (fmt) if (fmt[0])
86         {
87                 va_start(args, fmt);
88                 VUNPRINT(trace.element[trace.elements].value, sizeof(trace.element[trace.elements].value)-1, fmt, args);
89                 va_end(args);
90         }
91
92         /* increment elements */
93         trace.elements++;
94 }
95
96
97 /*
98  * prints trace to socket or log
99  * detail: 1 = brief, 2=short, 3=long
100  */
101 static char *print_trace(int detail, int port, char *interface, char *caller, char *dialing, int category)
102 {
103         char buffer[256];
104         time_t ti = trace.sec;
105         struct tm *tm;
106         struct mISDNport *mISDNport;
107         int i;
108
109         trace_string[0] = '\0'; // always clear string
110
111         if (detail < 1)
112                 return(NULL);
113
114         /* filter trace */
115         if (port && trace.port)
116                 if (port != trace.port) return(NULL);
117         if (interface) if (interface[0] && trace.interface[0])
118                 if (!!strcasecmp(interface, trace.interface)) return(NULL);
119         if (caller) if (caller[0] && trace.caller[0])
120                 if (!!strncasecmp(caller, trace.caller, strlen(trace.caller))) return(NULL);
121         if (dialing) if (dialing[0] && trace.dialing[0])
122                 if (!!strncasecmp(dialing, trace.dialing, strlen(trace.dialing))) return(NULL);
123         if (category && trace.category)
124                 if (!(category & trace.category)) return(NULL);
125
126         /* head */
127         if (detail >= 3)
128         {
129                 SCAT(trace_string, "------------------------------------------------------------------------------\n");
130                 /* "Port: 1 (BRI PTMP TE)" */
131                 if (trace.port)
132                 {
133                         mISDNport = mISDNport_first;
134                         while(mISDNport)
135                         {
136                                 if (mISDNport->portnum == trace.port)
137                                         break;
138                                 mISDNport = mISDNport->next;
139                         }
140                         if (mISDNport)
141                         {
142                                 SPRINT(buffer, "Port: %d (%s %s %s)", trace.port, (mISDNport->pri)?"PRI":"BRI", (mISDNport->ptp)?"PTP":"PTMP", (mISDNport->ntmode)?"NT":"TE");
143                                 /* copy interface, if we have a port */
144                                 if (mISDNport->ifport) if (mISDNport->ifport->interface)
145                                 SCPY(trace.interface, mISDNport->ifport->interface->name);
146                         } else
147                                 SPRINT(buffer, "Port: %d (does not exist)\n", trace.port);
148                         SCAT(trace_string, buffer);
149                 } else
150                         SCAT(trace_string, "Port: ---");
151
152                 if (trace.interface[0])
153                 {
154                         /* "  Interface: 'Ext'" */
155                         SPRINT(buffer, "  Interface: '%s'", trace.interface);
156                         SCAT(trace_string, buffer);
157                 } else
158                         SCAT(trace_string, "  Interface: ---");
159                         
160                 if (trace.caller[0])
161                 {
162                         /* "  Caller: '021256493'" */
163                         SPRINT(buffer, "  Caller: '%s'\n", trace.caller);
164                         SCAT(trace_string, buffer);
165                 } else
166                         SCAT(trace_string, "  Caller: ---\n");
167
168                 /* "Time: 25.08.73 05:14:39.282" */
169                 tm = localtime(&ti);
170                 SPRINT(buffer, "Time: %02d.%02d.%02d %02d:%02d:%02d.%03d", tm->tm_mday, tm->tm_mon+1, tm->tm_year%100, tm->tm_hour, tm->tm_min, tm->tm_sec, trace.usec/1000);
171                 SCAT(trace_string, buffer);
172
173                 if (trace.direction)
174                 {
175                         /* "  Direction: out" */
176                         SPRINT(buffer, "  Direction: %s", (trace.direction==DIRECTION_OUT)?"OUT":"IN");
177                         SCAT(trace_string, buffer);
178                 } else
179                         SCAT(trace_string, "  Direction: ---");
180
181                 if (trace.dialing[0])
182                 {
183                         /* "  Dialing: '57077'" */
184                         SPRINT(buffer, "  Dialing: '%s'\n", trace.dialing);
185                         SCAT(trace_string, buffer);
186                 } else
187                         SCAT(trace_string, "  Dialing: ---\n");
188
189                 SCAT(trace_string, "------------------------------------------------------------------------------\n");
190         }
191
192         if (detail < 3)
193         {
194                 tm = localtime(&ti);
195                 SPRINT(buffer, "%02d.%02d.%02d %02d:%02d:%02d.%03d ", tm->tm_mday, tm->tm_mon+1, tm->tm_year%100, tm->tm_hour, tm->tm_min, tm->tm_sec, trace.usec/1000);
196                 SCAT(trace_string, buffer);
197         }
198
199         /* "CH(45): CC_SETUP (net->user)" */
200         switch (trace.category)
201         {       case CATEGORY_CH:
202                 SCAT(trace_string, "CH");
203                 break;
204
205                 case CATEGORY_EP:
206                 SCAT(trace_string, "EP");
207                 break;
208
209                 default:
210                 SCAT(trace_string, "--");
211         }
212         if (trace.serial)
213                 SPRINT(buffer, "(%lu): %s", trace.serial, trace.name[0]?trace.name:"<unknown>");
214         else
215                 SPRINT(buffer, ": %s", trace.name[0]?trace.name:"<unknown>");
216         SCAT(trace_string, buffer);
217
218         /* elements */
219         switch(detail)
220         {
221                 case 1: /* brief */
222                 if (trace.port)
223                 {
224                         SPRINT(buffer, "  port %d", trace.port);
225                         SCAT(trace_string, buffer);
226                 }
227                 i = 0;
228                 while(i < trace.elements)
229                 {
230                         SPRINT(buffer, "  %s", trace.element[i].name);
231                         if (i) if (!strcmp(trace.element[i].name, trace.element[i-1].name))
232                                 buffer[0] = '\0';
233                         SCAT(trace_string, buffer);
234                         if (trace.element[i].sub[0])
235                                 SPRINT(buffer, " %s=", trace.element[i].sub);
236                         else
237                                 SPRINT(buffer, " ");
238                         SCAT(trace_string, buffer);
239                         if (strchr(trace.element[i].value, ' '))
240                                 SPRINT(buffer, "'%s'", trace.element[i].value);
241                         else
242                                 SPRINT(buffer, "%s", trace.element[i].value);
243                         SCAT(trace_string, buffer);
244                         i++;
245                 }
246                 SCAT(trace_string, "\n");
247                 break;
248
249                 case 2: /* short */
250                 case 3: /* long */
251                 SCAT(trace_string, "\n");
252                 i = 0;
253                 while(i < trace.elements)
254                 {
255                         SPRINT(buffer, " %s%s", trace.element[i].name, spaces[strlen(trace.element[i].name)]);
256                         if (i) if (!strcmp(trace.element[i].name, trace.element[i-1].name))
257                                 SPRINT(buffer, "           ");
258                         SCAT(trace_string, buffer);
259                         if (trace.element[i].sub[0])
260                                 SPRINT(buffer, " : %s%s = ", trace.element[i].sub, spaces[strlen(trace.element[i].sub)]);
261                         else
262                                 SPRINT(buffer, " :              ");
263                         SCAT(trace_string, buffer);
264                         if (strchr(trace.element[i].value, ' '))
265                                 SPRINT(buffer, "'%s'\n", trace.element[i].value);
266                         else
267                                 SPRINT(buffer, "%s\n", trace.element[i].value);
268                         SCAT(trace_string, buffer);
269                         i++;
270                 }
271                 break;
272         }
273
274         /* end */
275         if (detail >= 3)
276                 SCAT(trace_string, "\n");
277         return(trace_string);
278 }
279
280
281 /*
282  * trace ends
283  * this function will put the trace to sockets and logfile, if requested
284  */
285 void _end_trace(const char *__file, int __line)
286 {
287         char *string;
288         FILE *fp;
289         struct admin_list       *admin;
290         struct admin_queue      *response, **responsep; /* response pointer */
291
292         if (!trace.name[0])
293                 PERROR("trace not started in file %s line %d\n", __file, __line);
294         
295         if (options.deb || options.log[0])
296         {
297                 string = print_trace(1, 0, NULL, NULL, NULL, 0);
298                 if (string)
299                 {
300                         /* process debug */
301                         if (options.deb)
302                                 debug(NULL, 0, "trace", string);
303                         /* process log */
304                         if (options.log[0])
305                         {
306                                 fp = fopen(options.log, "a");
307                                 if (fp)
308                                 {
309                                         fwrite(string, strlen(string), 1, fp);
310                                         fclose(fp);
311                                 }
312                         }
313                 }
314         }
315
316         /* process admin */
317         admin = admin_first;
318         while(admin)
319         {
320                 if (admin->trace.detail)
321                 {
322                         string = print_trace(admin->trace.detail, admin->trace.port, admin->trace.interface, admin->trace.caller, admin->trace.dialing, admin->trace.category);
323                         if (string)
324                         {
325                                 /* seek to end of response list */
326                                 response = admin->response;
327                                 responsep = &admin->response;
328                                 while(response)
329                                 {
330                                         responsep = &response->next;
331                                         response = response->next;
332                                 }
333
334                                 /* create state response */
335                                 response = (struct admin_queue *)MALLOC(sizeof(struct admin_queue)+sizeof(admin_message));
336                                 memuse++;
337                                 response->num = 1;
338                                 /* message */
339                                 response->am[0].message = ADMIN_TRACE_RESPONSE;
340                                 SCPY(response->am[0].u.trace_rsp.text, string);
341
342                                 /* attach to response chain */
343                                 *responsep = response;
344                                 responsep = &response->next;
345                         }
346                 }
347                 admin = admin->next;
348         }
349 //      fwrite(string, strlen(string), 1, fp);
350
351         memset(&trace, 0, sizeof(struct trace));
352 }
353
354
355
356