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