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