isdn4k-utils/eurofile/src/eft/tdu_log.c

486 lines
13 KiB
C

/* $Id: tdu_log.c,v 1.2 2001/03/01 14:59:12 paul Exp $ */
/*
Copyright 1997 by Henner Eisen
This code is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This code is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <unistd.h>
#include <time.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <tdu_user.h>
#include "tdu.h"
#include "fileheader.h"
char * (*tdu_extended_reason)(int) = NULL;
/* Table with various information on tdu protocol data units */
static struct tdu_descr cmd_descr[] = {
{"T_RESPONSE_POSITIVE", TDU_CI_T_RESPONSE_POSITIVE,0},
{"T_RESPONSE_NEGATIVE", TDU_CI_T_RESPONSE_NEGATIVE,0},
{"T_ASSOCIATE", TDU_CI_T_ASSOCIATE,0},
{"T_RELEASE", TDU_CI_T_RELEASE,0},
{"T_ABORT", TDU_CI_T_ABORT,0},
{"T_ACCESS", TDU_CI_T_ACCESS,1},
{"T_END_ACCESS", TDU_CI_T_END_ACCESS,1},
{"T_DIRECTORY", TDU_CI_T_DIRECTORY,1},
{"T_LOAD", TDU_CI_T_LOAD,1},
{"T_SAVE", TDU_CI_T_SAVE,1},
{"T_RENAME", TDU_CI_T_RENAME,1},
{"T_DELETE", TDU_CI_T_DELETE,1},
{"T_TYPED_DATA", TDU_CI_T_TYPED_DATA,1},
{"T_WRITE", TDU_CI_T_WRITE,0},
{"T_TRANSFER_REJECT", TDU_CI_T_TRANSFER_REJECT,0},
{"T_READ_RESTART", TDU_CI_T_READ_RESTART,0},
{"T_P_EXCEPTION", TDU_CI_T_P_EXCEPTION,1},
{"RESPONSE_TIMEOUT", TDU_CI_RESPONSE_TIMEOUT,2},
{"SOCKET_READ_ERROR", TDU_CI_SOCK_READ_ERROR,2},
{"TC disconnected", TDU_CI_TC_DISCONNECT,2},
{"Empty TDU", TDU_CI_EMPTY,2},
{NULL, 0,0}
};
/* Table with various information on result/reason codes.
According to ETS 300 075, 7.2.1 and 7.2.2*/
static struct tdu_descr tdu_res_descr[] = {
{"provider: called address incorrect", TDU_RE_CALLED_ADDR_INCOR_P,0},
{"user: called address incorrect", TDU_RE_CALLED_ADDR_INCOR_U,0},
{"provider: calling address incorrect", TDU_RE_CALLING_ADDR_INCOR_P,0},
{"user: calling address incorrect", TDU_RE_CALLING_ADDR_INCOR_U,0},
{"provider: role refused", TDU_RE_ROLE_REFUSED_P,0},
{"user: role refused", TDU_RE_ROLE_REFUSED_U,0},
{"insufficient primitives handled", TDU_RE_INSUFF_PRIMITIVES,0},
{"application name unknown", TDU_RE_APPL_NAME_UNKNOWN,0},
{"provider: service class refused", TDU_RE_SVC_CLASS_REFUSED_P,0},
{"user: service class refused", TDU_RE_SVC_CLASS_REFUSED_U,0},
{"erroneous revovery point", TDU_RE_ERRON_RECOV_POINT,0},
{"erroneous designation", TDU_RE_ERRON_DESIGN,0},
{"no answer to the request", TDU_RE_NO_ANSWER,0},
{"unknown file", TDU_RE_UNKNOWN_FILE,0},
{"already existing file", TDU_RE_FILE_EXISTS,0},
{"erroneous file", TDU_RE_ERRON_FILE,0},
{"erroneous new name", TDU_RE_ERRON_NEW_NAME,0},
{"new name already in use", TDU_RE_NEW_NAME_IN_USE,0},
{"wrong identity/identification", TDU_RE_WRONG_ID,0},
{"erroneous user data", TDU_RE_ERRON_UDATA,0},
{"service unknown", TDU_RE_SVC_UNKNOWN,0},
{"group forbidden", TDU_RE_GROUP_FORBIDDEN,0},
{"other reason", TDU_RE_OTHER_REASON,0},
{"repeated errors/negative acknowledges",TDU_RE_REPEATED_ERROR,0},
{"delay expired", TDU_RE_DELAY_EXPIRED,0},
{"unknown message", TDU_RE_UNKNOWN_MESSAGE,0},
{"syntax error/missing parameter", TDU_RE_SYNTAX_ERROR,0},
{"unrecoverable lower layer error", TDU_RE_LOWER_LAYER_ERROR,0},
{"protocol conflict", TDU_RE_PROTOCOL_CONFLICT,0},
{"primitive not handled", TDU_RE_PRIMITIVE_NOT_HANDLED,0},
{NULL, 0,0}
};
/* Table with various information on tdu parameters */
static struct tdu_descr tdu_par_descr[] = {
{"USER_DATA", TDU_PI_USER_DATA,0},
{"CALLED_ADDRESS", TDU_PI_CALLED_ADDRESS,1},
{"CALLING_ADDRESS", TDU_PI_CALLING_ADDRESS,1},
{"Result/Reason", TDU_PI_RESULT_REASON,1},
{"Role/Function", TDU_PI_ROLE_FUNCTION,0},
{"APPLICATION_NAME", TDU_PI_APPLICATION_NAME,0},
{"APPL_RESPONSE_TIMOUT", TDU_PI_APPL_RESPONSE_TIMEOUT,0},
{"Size/Recovery/Window", TDU_PI_SIZE_RECOVERY_WINDOW,1},
{"DESIGNATION", TDU_PI_DESIGNATION,1},
{"NEW_NAME", TDU_PI_NEW_NAME,1},
{"REQUEST_IDENT", TDU_PI_REQUEST_IDENT,1},
{"Identification", TDU_PI_IDENTIFICATION,1},
{"ExplCnf/1st/last/bl#", TDU_PI_EX_CONF_1ST_LAST_BLNO,0},
{"TRANSFER_MODE", TDU_PI_TRANSFER_MODE,1},
{"RECOVERY_POINT", TDU_PI_RECOVERY_POINT,1},
{"SERVICE_CLASS", TDU_PI_SERVICE_CLASS,0},
/* not a parameter but compatible */
{"File_Header", TDU_PI_FILE_HEADER,0},
{NULL, 0,0}
};
const char * tdu_cmd_descr(int ci)
{
static const char unknown[] = "Unknown_TDU_Command";
char * des = tdu_des(cmd_descr,ci);
return des ? des : unknown;
}
const char * tdu_param_descr(int pi)
{
static const char unknown[] = "Unknown_TDU_Parameter";
char* des = tdu_des(tdu_par_descr,pi);
return des ? des : unknown;
}
FILE * tdu_logfile;
unsigned int tdu_stderr_mask = 0,
tdu_logfile_mask = 0,
tdu_stderr_dirty = 0,
nl_err=1,
nl_log=1;
pid_t log_pid=0;
char log_prefix[20]="e4l[%d]:%s: ",
time_format[20]="%Y-%m-%d %H:%M:%S";
int tdu_open_log(const char * fname)
{
tdu_logfile = fopen(fname,"a");
if( ! tdu_logfile ) {
perror("fopen log file");
tdu_logfile_mask = 0;
} else {
setvbuf(tdu_logfile,NULL,_IOLBF,4098);
}
return tdu_logfile != NULL;
}
/*
* set/change log prefix and date format
*/
int tdu_log_prefix(const char * id_fmt, const char *tm_fmt)
{
if( id_fmt) strncpy(log_prefix, id_fmt, sizeof(log_prefix));
if( tm_fmt) strncpy(time_format, tm_fmt, sizeof(time_format));
log_pid = getpid();
return 0;
}
int tdu_printf( int context, char * fmt, ... )
{
int ret, nl, i;
va_list ap;
char tst[20];
/*
* Check for trailing newline might fail if newline is part of last
* argument. It is also not bullet proof if several processes
* are writing to the same output channel in parallel. Setting
* line buffered io mode should help for most scenarios.
*/
nl = ( fmt[strlen(fmt)-1] == '\n' );
if( nl_err || nl_log ){
struct tm * tm_time;
time_t t=0;
time(&t);
tm_time = localtime(&t);
i = strftime(tst, sizeof(tst), time_format, tm_time);
}
va_start(ap, fmt);
if( context & tdu_stderr_mask ){
if( nl_err ) fprintf(stderr, log_prefix, log_pid, tst);
ret = vfprintf(stderr, fmt, ap);
tdu_stderr_dirty = 1;
nl_err = nl;
}
if( ret < 0 ) return ret;
va_start(ap, fmt);
if( context & tdu_logfile_mask ){
if( nl_log ) fprintf(tdu_logfile, log_prefix, log_pid, tst);
ret = vfprintf(tdu_logfile, fmt, ap);
nl_log = nl;
}
va_end(ap);
return ret;
}
void tdu_prompt(char * prompt)
{
fprintf(stderr,prompt);
tdu_stderr_dirty = 0;
}
unsigned char * tdu_print_cmd( int ct, unsigned char *pkt, unsigned char *end,
int level )
{
unsigned char ci, ci2;
int len=0, garbage=0;
if( pkt >= end ) goto packet_too_small;
if( level < 1 ) {
tdu_printf(ct,"\n");
return pkt;
}
ci = *(pkt++);
tdu_printf(ct, " %s(", tdu_cmd_descr(ci));
if( pkt < end ) len = *(pkt++);
if( len == 0xff ) {
if( pkt+2 >= end ) goto packet_too_small;
len = 0x100 * *(pkt) + *(pkt+1);
pkt += 2;
}
if( pkt+len < end ){
garbage = end - pkt - len;
/* remove trailing garbage */
end = pkt + len;
}
if( ci == TDU_CI_T_RESPONSE_POSITIVE ||
ci == TDU_CI_T_RESPONSE_NEGATIVE ){
if( pkt+2 > end ) goto packet_too_small;
ci2 = *(pkt+2);
tdu_printf(ct, "%s,", tdu_cmd_descr(ci2));
}
tdu_printf(ct, "len=%d", len);
if ( garbage ) tdu_printf(ct,"[+%d]", garbage);
tdu_printf(ct, ")" );
if( level < 2 ) {
tdu_printf(ct,"\n");
return pkt;
}
tdu_printf(ct, ": " );
/* Never log t-write contents */
if( ci == TDU_CI_T_WRITE ) {
pkt = tdu_print_par( ct, pkt, end, ci, level );
tdu_printf(ct,"\n");
return end;
}
while( pkt < end ) pkt = tdu_print_par( ct, pkt, end, ci, level );
tdu_printf(ct,"\n");
return pkt;
packet_too_small : tdu_printf(ct, "CMD packet to small!\n" );
return end;
}
void tdu_print_hex( int ct, unsigned char * pkt, unsigned char * end)
{
tdu_printf(ct,"0x");
while ( pkt < end )
tdu_printf(ct, "%02x ", (int) *(pkt++) );
}
void tdu_print_txt( int ct, unsigned char * pkt, unsigned char * end)
{
unsigned char tmp;
while ( pkt < end ){
tmp = *pkt & 0x7f;
if( tmp < 32 ){
tdu_printf(ct, "^%c", (int) ( *pkt + 64 ) );
} else if ( *pkt == 0x7f ) {
tdu_printf(ct, "^?" );
} else {
tdu_printf(ct, "%c", (int) *pkt );
}
pkt++;
};
}
void tdu_print_li( int ct, unsigned char * pkt, unsigned char * end)
{
int i = 0;
while ( pkt < end ) {
i = i * 256;
i += *(pkt++);
}
tdu_printf(ct, "%d", i );
}
static void tdu_print_srw( int ct, unsigned char * pkt, unsigned char * end)
{
int log2, size=512;
if ( pkt >= end ) return;
/* packet size */
log2 = (0x0e & *pkt) >> 1;
while( log2-- ) size <<= 1;
tdu_printf(ct,"%d/", size);
/* recovery */
tdu_printf(ct,"%sAccepted/", (*pkt & 0x01) ? "" : "Not");
/* window size */
tdu_printf(ct,"%d", ((*pkt & 0xe0) >> 5) + 1 );
}
static void tdu_print_mode( int ct, unsigned char * pkt, unsigned char * end)
{
if ( pkt >= end ) return;
tdu_printf(ct,"%sBasicMode", (*pkt & 0x01) ? "" : "No");
}
static void tdu_print_role( int ct, unsigned char * pkt, unsigned char * end)
{
if ( pkt >= end ) return;
if( *pkt & 0x01 ) {
tdu_printf(ct, "Master(" );
if (*pkt & 0x02) tdu_printf(ct," ReadRestart");
if (*pkt & 0x04) tdu_printf(ct," TypedData");
} else {
tdu_printf(ct, "Slave(" );
if (*pkt & 0x02) tdu_printf(ct," ReadRestart");
if (*pkt & 0x04) tdu_printf(ct," TypedData");
if (*pkt & 0x08) tdu_printf(ct," Directory");
if (*pkt & 0x10) tdu_printf(ct," Delete");
if (*pkt & 0x20) tdu_printf(ct," Rename");
if (*pkt & 0x40) tdu_printf(ct," Save");
if (*pkt & 0x80) tdu_printf(ct," Load");
}
tdu_printf(ct," )");
}
/* FIXME: should not go into this source file */
#include "eft.h"
static void tdu_print_reason( int ct, unsigned char * pkt, unsigned char * end, int ci)
{
int rci;
if( pkt < end && ( ci == TDU_CI_T_RESPONSE_NEGATIVE ||
ci == TDU_CI_T_RESPONSE_POSITIVE ) ) {
rci = *(pkt++);
tdu_printf(ct, "%s ", tdu_cmd_descr( rci ) );
if( rci == TDU_CI_T_WRITE ){
int count = 0;
if( pkt < end ) count += *(pkt++);
if( pkt < end ) { count *= 256; count += *(pkt++);}
tdu_printf(ct, "packet No %d",count);
}
}
while ( pkt < end ){
tdu_printf(ct, "%s ", tdu_str_reason(*pkt) );
if( *pkt == TDU_RE_ERRON_UDATA && (pkt+1 < end)){
tdu_print_reason( ct, pkt+1, end, ci);
return;
}
if( *pkt == TDU_RE_OTHER_REASON ){
char * ext_re = NULL;
pkt++;
/* FIXME: should not belong here */
if( (pkt+1) == end && tdu_extended_reason)
ext_re = tdu_extended_reason(*pkt);
while ( pkt < end )
tdu_printf(ct, "%c", (int) *(pkt++) );
tdu_printf(ct," ");
if( ext_re ) tdu_printf(ct, "[%s] ",ext_re);
};
pkt++;
};
}
unsigned char * tdu_print_par( int ct, unsigned char *pkt, unsigned char *end, int ci, int level )
{
unsigned char pi, *ret;
int len=0;
if( pkt >= end ) goto packet_too_small;
pi = *(pkt++);
tdu_printf(ct, " %s(", tdu_param_descr(pi));
if( pkt >= end ) goto packet_too_small;
if( (len = *(pkt++)) == 0xff ) {
if( pkt+2 > end ) goto packet_too_small;
len = 0x100 * *(pkt++) + *(pkt++);
}
tdu_printf(ct,"len=%d)", len);
ret = pkt + len;
if( level < 3 ) {
return ret;
}
tdu_printf(ct,"=");
switch ( pi ) {
case TDU_PI_RESULT_REASON:
tdu_print_reason(ct,pkt,ret,ci);
break;
case TDU_PI_SIZE_RECOVERY_WINDOW:
tdu_print_srw(ct,pkt,ret);
break;
case TDU_PI_ROLE_FUNCTION:
tdu_print_role(ct,pkt,ret);
break;
case TDU_PI_TRANSFER_MODE:
tdu_print_mode(ct,pkt,ret);
break;
case TDU_PI_APPLICATION_NAME:
case TDU_PI_CALLED_ADDRESS:
case TDU_PI_CALLING_ADDRESS:
case TDU_PI_DESIGNATION:
case TDU_PI_NEW_NAME:
case TDU_PI_IDENTIFICATION:
tdu_print_txt(ct,pkt,ret);
break;
default:
tdu_print_hex(ct,pkt,ret );
};
return ret;
packet_too_small : tdu_printf(ct, "PAR packet to small!\n" );
return end;
}
const char * tdu_str_reason(int reason)
{
static const char unknown[] = "Unknown_TDU_ReasonCode";
char * des = tdu_des(tdu_res_descr,reason);
return des ? des : unknown;
}
/*
* Replace unprintable characters from string type tdu parameters.
* Thus should be applied before printing those as strings in order
* to prevent them from screwing up your terminal state.
*
* The data array must be at least dimensioned max(len+1,1), which is essential
* to be verified before calling in order to prevent buffer overflow attacks.
* The last data[len] (or data[0] if len<0) will be terminated by zero on exit.
*/
int tdu_mk_printable(unsigned char * pr_data, const unsigned char * in_data,
int len){
int i;
if( len < 0 ) {
pr_data[0]=0;
return 0;
}
pr_data[len]=0;
memcpy(pr_data, in_data, len);
for(i=0; i < len; i++){
if( ((0x7f & pr_data[i]) < 32) || (pr_data[i] == 0x7f) )
pr_data[i]='?';
}
return 0;
}