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