/* * binkleyforce -- unix FTN mailer project * * Copyright (c) 1998-2000 Alexander Belkin, 2:5020/1398.11 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * $Id$ */ #include "includes.h" #include "confread.h" #include "logger.h" #include "bforce.h" #include "util.h" #include "nodelist.h" #include "session.h" /* * Format of 'sts' files (project only..) * * Header: * 0 byte - version (current is 1) * 1 byte - global undialable flag (for all lines) * 2 word - tries * 4 word - handshake tries * 6 dword - hold all calls until * 8 dword - node will not accept our file requests till this time * 10 dword - last successfull outgoing session * 12 dword - last successfull incoming session * * Each entry (per-line statistics) */ void session_stat_reset_counters(s_sess_stat *stat) { stat->tries = TRIES_RESET; stat->tries_noansw = TRIES_RESET; stat->tries_noconn = TRIES_RESET; stat->tries_nodial = TRIES_RESET; stat->tries_hshake = TRIES_RESET; stat->tries_sessns = TRIES_RESET; } static char *session_stat_get_stsfile(s_faddr *addr, int linenum) { char buf[32]; char *yield = NULL; char *p_stsdir = conf_string(cf_status_directory); if( p_stsdir && *p_stsdir ) { if( linenum == -1 ) sprintf(buf, "%u.%u.%u.%u.sts", addr->zone, addr->net, addr->node, addr->point); else sprintf(buf, "%u.%u.%u.%u-%u.sts", addr->zone, addr->net, addr->node, addr->point, linenum); yield = string_concat(p_stsdir, buf, NULL); } return yield; } static int session_stat_read_stsfile(FILE *fp, s_sess_stat *stat) { int res; if( fseek(fp, 0, SEEK_SET) == -1 ) return -1; memset(stat, '\0', sizeof(s_sess_stat)); res = fscanf(fp, "%u %u %u %u %u %u %lu %lu %lu %lu", (unsigned int *) &stat->tries, (unsigned int *) &stat->tries_noconn, (unsigned int *) &stat->tries_noansw, (unsigned int *) &stat->tries_nodial, (unsigned int *) &stat->tries_hshake, (unsigned int *) &stat->tries_sessns, (unsigned long *) &stat->hold_until, (unsigned long *) &stat->hold_freqs, (unsigned long *) &stat->last_success_out, (unsigned long *) &stat->last_success_in); if (res == 0) { log("Read STS unsuccessfull..."); return -1; } /* Set last successfull session time */ stat->last_success = MAX(stat->last_success_out, stat->last_success_in); return 0; } static int session_stat_write_stsfile(FILE *fp, s_sess_stat *stat) { if( fseek(fp, 0, SEEK_SET) == -1 ) return -1; fprintf(fp, "%u %u %u %u %u %u %lu %lu %lu %lu", (unsigned int) stat->tries, (unsigned int) stat->tries_noconn, (unsigned int) stat->tries_noansw, (unsigned int) stat->tries_nodial, (unsigned int) stat->tries_hshake, (unsigned int) stat->tries_sessns, (unsigned long) stat->hold_until, (unsigned long) stat->hold_freqs, (unsigned long) stat->last_success_out, (unsigned long) stat->last_success_in); return 0; } static int session_stat_update_stsfile(const char *stsname, s_sess_stat *stat) { int rc = 0; FILE *sts_fp = NULL; s_sess_stat tmpstat; bool stsexist = FALSE; memset(&tmpstat, '\0', sizeof(s_sess_stat)); stsexist = (access(stsname, R_OK) == 0); if( (sts_fp = file_open(stsname, stsexist ? "r+" : "w")) == NULL ) { logerr("cannot open status file \"%s\"", stsname); gotoexit(-1); } if( stsexist ) { /* Ignore read errors */ (void)session_stat_read_stsfile(sts_fp, &tmpstat); if( ftruncate(fileno(sts_fp), 0) == -1 ) { logerr("cannot truncate status file \"%s\"", stsname); gotoexit(-1); } } /* * Update statistic */ if( stat->tries == TRIES_RESET ) tmpstat.tries = 0; else tmpstat.tries += stat->tries; if( stat->tries_noconn == TRIES_RESET ) tmpstat.tries_noconn = 0; else tmpstat.tries_noconn += stat->tries_noconn; if( stat->tries_nodial == TRIES_RESET ) tmpstat.tries_nodial = 0; else tmpstat.tries_nodial += stat->tries_nodial; if( stat->tries_noansw == TRIES_RESET ) tmpstat.tries_noansw = 0; else tmpstat.tries_noansw += stat->tries_noansw; if( stat->tries_hshake == TRIES_RESET ) tmpstat.tries_hshake = 0; else tmpstat.tries_hshake += stat->tries_hshake; if( stat->tries_sessns == TRIES_RESET ) tmpstat.tries_sessns = 0; else tmpstat.tries_sessns += stat->tries_sessns; if( stat->hold_until == HOLD_RESET ) tmpstat.hold_until = 0; else if( stat->hold_until > tmpstat.hold_until ) tmpstat.hold_until = stat->hold_until; if( stat->hold_freqs == HOLD_RESET ) tmpstat.hold_freqs = 0; else if( stat->hold_freqs > tmpstat.hold_freqs ) tmpstat.hold_freqs = stat->hold_freqs; if( stat->last_success_out > tmpstat.last_success_out ) tmpstat.last_success_out = stat->last_success_out; if( stat->last_success_in > tmpstat.last_success_in ) tmpstat.last_success_in = stat->last_success_in; /* * Write new statistic to the 'sts' file */ if( session_stat_write_stsfile(sts_fp, &tmpstat) == -1 ) { logerr("error writing status file \"%s\"", stsname); gotoexit(-1); } exit: if( sts_fp ) file_close(sts_fp); return rc; } int session_stat_get(s_sess_stat *stat, s_faddr *addr) { FILE *fp; char *stsname = session_stat_get_stsfile(addr, -1); memset(stat, '\0', sizeof(s_sess_stat)); if( stsname ) { fp = file_open(stsname, "r"); if( !fp ) { free(stsname); return -1; } (void)session_stat_read_stsfile(fp, stat); (void)file_close(fp); free(stsname); } return 0; } int session_stat_apply_diff(s_faddr addr, s_sess_stat stat) { int rc; char *stsname = session_stat_get_stsfile(&addr, -1); if( !stsname ) return -1; rc = session_stat_update_stsfile(stsname, &stat); free(stsname); return rc; } int session_stat_update(s_faddr *addr, s_sess_stat *stat, bool caller, int rc) { char *stsname; /* * Update sessions statistic depending on session * return code. The latter must be one of BFERR * values. Warning, stat structure might allready * contain desired settings! */ if( rc == BFERR_NOERROR ) { if( caller ) stat->last_success_out = time(NULL); else stat->last_success_in = time(NULL); session_stat_reset_counters(stat); } else { if( caller ) { stat->tries++; if( rc == BFERR_HANDSHAKE_ERROR ) stat->tries_hshake++; if( rc == BFERR_CANT_CONNECT14 ) stat->tries_noansw++; if( rc == BFERR_CANT_CONNECT13 ) stat->tries_nodial++; if( BFERR_CANT_CONNECT10 <= rc && rc <= BFERR_CANT_CONNECT19 ) stat->tries_noconn++; if( rc >= BFERR_CONNECT_TOOLOW ) stat->tries_sessns++; /* Reset some counters */ if( rc >= BFERR_CONNECT_TOOLOW ) { stat->tries_noansw = TRIES_RESET; stat->tries_noconn = TRIES_RESET; } if( rc > BFERR_HANDSHAKE_ERROR ) stat->tries_hshake = TRIES_RESET; } } stsname = session_stat_get_stsfile(addr, -1); if( !stsname ) return -1; rc = session_stat_update_stsfile(stsname, stat); free(stsname); return rc; }