lcr/trace.c

335 lines
9.7 KiB
C

/*****************************************************************************\
** **
** Linux Call Router **
** **
**---------------------------------------------------------------------------**
** Copyright: Andreas Eversberg **
** **
** trace functions **
** **
\*****************************************************************************/
#include "main.h"
struct trace trace;
char trace_string[MAX_TRACE_ELEMENTS * 100 + 400];
static const char *spaces = " ";
/*
* initializes a new trace
* all values will be reset
*/
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)
{
struct timeval current_time;
if (trace.name[0])
PERROR("trace already started (name=%s) in file %s line %d\n", trace.name, __file, __line);
memset(&trace, 0, sizeof(struct trace));
trace.port = port;
if (interface)
SCPY(trace.interface, interface->name);
if (caller) if (caller[0])
SCPY(trace.caller, caller);
if (dialing) if (dialing[0])
SCPY(trace.dialing, dialing);
trace.direction = direction;
trace.category = category;
trace.serial = serial;
if (name) if (name[0])
SCPY(trace.name, name);
if (!trace.name[0])
SCPY(trace.name, "<unknown>");
gettimeofday(&current_time, NULL);
trace.sec = current_time.tv_sec;
trace.usec = current_time.tv_usec;
}
/*
* adds a new element to the trace
* if subelement is given, element will also contain a subelement
* if multiple subelements belong to same element, name must be equal for all subelements
*/
void _add_trace(const char *__file, int __line, const char *name, const char *sub, const char *fmt, ...)
{
va_list args;
if (!trace.name[0])
PERROR("trace not started in file %s line %d\n", __file, __line);
/* check for required name value */
if (!name)
goto nostring;
if (!name[0]) {
nostring:
PERROR("trace with name=%s gets element with no string\n", trace.name);
return;
}
/* write name, sub and value */
SCPY(trace.element[trace.elements].name, name);
if (sub) if (sub[0])
SCPY(trace.element[trace.elements].sub, sub);
if (fmt) if (fmt[0]) {
va_start(args, fmt);
VUNPRINT(trace.element[trace.elements].value, sizeof(trace.element[trace.elements].value)-1, fmt, args);
va_end(args);
}
/* increment elements */
trace.elements++;
}
/*
* prints trace to socket or log
* detail: 1 = brief, 2=short, 3=long
*/
static char *print_trace(int detail, int port, char *interface, char *caller, char *dialing, int category)
{
char buffer[256];
time_t ti = trace.sec;
struct tm *tm;
#ifdef WITH_MISDN
struct mISDNport *mISDNport;
#endif
int i;
trace_string[0] = '\0'; // always clear string
if (detail < 1)
return(NULL);
/* filter trace */
if (port >= 0 && trace.port >= 0)
if (port != trace.port) return(NULL);
if (interface) if (interface[0] && trace.interface[0])
if (!!strcasecmp(interface, trace.interface)) return(NULL);
if (caller) if (caller[0] && trace.caller[0])
if (!!strncasecmp(caller, trace.caller, strlen(trace.caller))) return(NULL);
if (dialing) if (dialing[0] && trace.dialing[0])
if (!!strncasecmp(dialing, trace.dialing, strlen(trace.dialing))) return(NULL);
if (category && trace.category)
if (!(category & trace.category)) return(NULL);
/* head */
if (detail >= 3) {
SCAT(trace_string, "------------------------------------------------------------------------------\n");
#ifdef WITH_MISDN
/* "Port: 1 (BRI PTMP TE)" */
if (trace.port >= 0) {
mISDNport = mISDNport_first;
while(mISDNport) {
if (mISDNport->portnum == trace.port)
break;
mISDNport = mISDNport->next;
}
if (mISDNport) {
SPRINT(buffer, "Port: %d (%s %s %s)", trace.port, (mISDNport->pri)?"PRI":"BRI", (mISDNport->ptp)?"PTP":"PTMP", (mISDNport->ntmode)?"NT":"TE");
/* copy interface, if we have a port */
if (mISDNport->ifport) if (mISDNport->ifport->interface)
SCPY(trace.interface, mISDNport->ifport->interface->name);
} else
SPRINT(buffer, "Port: %d (does not exist)\n", trace.port);
SCAT(trace_string, buffer);
} else
#endif
SCAT(trace_string, "Port: ---");
if (trace.interface[0]) {
/* " Interface: 'Ext'" */
SPRINT(buffer, " Interface: '%s'", trace.interface);
SCAT(trace_string, buffer);
} else
SCAT(trace_string, " Interface: ---");
if (trace.caller[0]) {
/* " Caller: '021256493'" */
SPRINT(buffer, " Caller: '%s'\n", trace.caller);
SCAT(trace_string, buffer);
} else
SCAT(trace_string, " Caller: ---\n");
/* "Time: 25.08.73 05:14:39.282" */
tm = localtime(&ti);
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);
SCAT(trace_string, buffer);
if (trace.direction) {
/* " Direction: out" */
SPRINT(buffer, " Direction: %s", (trace.direction==DIRECTION_OUT)?"OUT":"IN");
SCAT(trace_string, buffer);
} else
SCAT(trace_string, " Direction: ---");
if (trace.dialing[0]) {
/* " Dialing: '57077'" */
SPRINT(buffer, " Dialing: '%s'\n", trace.dialing);
SCAT(trace_string, buffer);
} else
SCAT(trace_string, " Dialing: ---\n");
SCAT(trace_string, "------------------------------------------------------------------------------\n");
}
if (detail < 3) {
tm = localtime(&ti);
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);
SCAT(trace_string, buffer);
}
/* "CH(45): CC_SETUP (net->user)" */
switch (trace.category) {
case CATEGORY_CH:
SCAT(trace_string, "CH");
break;
case CATEGORY_EP:
SCAT(trace_string, "EP");
break;
default:
SCAT(trace_string, "--");
}
if (trace.serial)
SPRINT(buffer, "(%lu): %s", trace.serial, trace.name[0]?trace.name:"<unknown>");
else
SPRINT(buffer, ": %s", trace.name[0]?trace.name:"<unknown>");
SCAT(trace_string, buffer);
/* elements */
switch(detail) {
case 1: /* brief */
if (trace.interface[0]) {
SPRINT(buffer, " iface %s", trace.interface);
SCAT(trace_string, buffer);
}
if (trace.port >= 0) {
SPRINT(buffer, " port %d", trace.port);
SCAT(trace_string, buffer);
}
i = 0;
while(i < trace.elements) {
SPRINT(buffer, " %s", trace.element[i].name);
if (i) if (!strcmp(trace.element[i].name, trace.element[i-1].name))
buffer[0] = '\0';
SCAT(trace_string, buffer);
if (trace.element[i].sub[0])
SPRINT(buffer, " %s=", trace.element[i].sub);
else
SPRINT(buffer, " ");
SCAT(trace_string, buffer);
if (strchr(trace.element[i].value, ' '))
SPRINT(buffer, "'%s'", trace.element[i].value);
else
SPRINT(buffer, "%s", trace.element[i].value);
SCAT(trace_string, buffer);
i++;
}
SCAT(trace_string, "\n");
break;
case 2: /* short */
case 3: /* long */
SCAT(trace_string, "\n");
i = 0;
while(i < trace.elements) {
SPRINT(buffer, " %s%s", trace.element[i].name, &spaces[strlen(trace.element[i].name)]);
if (i) if (!strcmp(trace.element[i].name, trace.element[i-1].name))
SPRINT(buffer, " ");
SCAT(trace_string, buffer);
if (trace.element[i].sub[0])
SPRINT(buffer, " : %s%s = ", trace.element[i].sub, &spaces[strlen(trace.element[i].sub)]);
else
SPRINT(buffer, " : ");
SCAT(trace_string, buffer);
if (strchr(trace.element[i].value, ' '))
SPRINT(buffer, "'%s'\n", trace.element[i].value);
else
SPRINT(buffer, "%s\n", trace.element[i].value);
SCAT(trace_string, buffer);
i++;
}
break;
}
/* end */
if (detail >= 3)
SCAT(trace_string, "\n");
return(trace_string);
}
/*
* trace ends
* this function will put the trace to sockets and logfile, if requested
*/
void _end_trace(const char *__file, int __line)
{
char *string;
FILE *fp;
struct admin_list *admin;
struct admin_queue *response, **responsep; /* response pointer */
int __attribute__((__unused__)) ret;
if (!trace.name[0])
PERROR("trace not started in file %s line %d\n", __file, __line);
if (options.deb || options.log[0]) {
string = print_trace(1, -1, NULL, NULL, NULL, 0);
if (string) {
/* process debug */
if (options.deb)
debug(NULL, NULL, 0, "TRACE", string);
/* process log */
if (options.log[0]) {
fp = fopen(options.log, "a");
if (fp) {
ret = fwrite(string, strlen(string), 1, fp);
fclose(fp);
}
}
}
}
/* process admin */
admin = admin_first;
while(admin) {
if (admin->trace.detail) {
string = print_trace(admin->trace.detail, admin->trace.port, admin->trace.interface, admin->trace.caller, admin->trace.dialing, admin->trace.category);
if (string) {
/* seek to end of response list */
response = admin->response;
responsep = &admin->response;
while(response) {
responsep = &response->next;
response = response->next;
}
/* create state response */
response = (struct admin_queue *)MALLOC(sizeof(struct admin_queue)+sizeof(admin_message));
memuse++;
response->num = 1;
/* message */
response->am[0].message = ADMIN_TRACE_RESPONSE;
SCPY(response->am[0].u.trace_rsp.text, string);
/* attach to response chain */
*responsep = response;
responsep = &response->next;
admin->fd.when |= LCR_FD_WRITE;
}
}
admin = admin->next;
}
// fwrite(string, strlen(string), 1, fp);
memset(&trace, 0, sizeof(struct trace));
}