Wie alles angefangen hat ...

Am Thu, 28 Sep 1995 19:19:18 +0100 (MET) schrieb' ich unter dem Subject
"ISDN-Protokoll-Programm" folgende Mail in der ISDN4Linux-Mailing-Liste:

Hallo isdn4linux'er!

Da ich hier vor gut zwei Wochen eine relativ heftige Debatte bzgl.
"auch non DATA-Calls wieder in's Syslog" losgetreten habe, wollte ich das
nun auch selber ausbaden.

Ich habe mich also mal in das Thema reingearbeitet, und im Zuge dessen
ein kleines Programm zum protokollieren _aller_ ISDN-Verbindungen geschrieben.

Die entscheidende Idee dazu verdanke ich
  Gernot Zander (hifi@scorpio.in-berlin.de)

Es handelt sich um zwei Programme:

  isdnlog
    lauscht staendig am "/dev/isdnctrl0", und schreibt alle Verbindungen
    (also auch die non DATA-Verbindungen) nach "/var/adm/isdn.log"

  isdnrep
    erstellt eine Gebuehrenabrechnung aus der "isdn.log"

* isdnrep enthaelt z.Zt. leider noch zu viele fest einprogrammierte Parameter,
* daher werde ich das in den naechsten Tagen um eine Config-Datei erweitern,
* und dann nachliefern. :-(

Erstellt wird isdnlog mittels:

      make isdnlog    ;-)

Gestartet wird isdnlog (am besten gleich in der /etc/rc.d/rc.isdn) mittels:

         telesctrl /dev/isdnctrl0 1 4
         isdnlog [ -vsp ] [ -i cmd ] /dev/isdnctrl0 &

Beim telesctrl koennen auch noch weitere Debug-Flags eingeschaltet werden,
isdnlog benoetigt allerdings auf jeden Fall mindestens die "4"

Die Optionen von isdnlog haben im einzelnen folgende Funktion:

  -v     "verbose" isdnlog schreibt den gesamten Output von "/dev/isdnctrl0",
         ergaenzt um Datum/Uhrzeit auch nach "/tmp/isdnctrl0"

  -s     "sync"    fuehrt direkt nach jedem Eintrag in die "/tmp/isdnctrl0"
         einen flush() darauf aus (fuer Kisten, die gerne mal zwischendurch
         abstuerzen)

  -p     "pipe"    reicht den Output von "/dev/isdnctrl0" auf stdout weiter,
         falls jemand da noch was anderes rausholen moechte (also z.b.
         "isdnlog -p /dev/isdnctrl0 | isdnproto &" oder so)

  -i cmd "info"    startet beim Aufbau jeder DATA-Verbindung das angegebene
         Programm, und uebergibt Ihm dabei die beiden beteiligten
         Telefonnummern, also "cmd <Anrufer-Nummer> <Angerufene Nummer>"

Output der ganzen Geschichte ist die Datei "/var/adm/isdn.log" mit folgendem
Inhalt:

Sep 28 18:22:48 1995|xxxxx           |yyyyyyyyyyy     |   10|       912
      (1)                (2)               (3)           (4)        (5)

Wobei in den einzelnen Spalten folgendes steht:

 (1) Zeitpunkt des Verbindungsaufbaues
 (2) Telefonnummer des Anrufers (oder Blank, falls z.b. Analog-Anschluss)
     (d.h. natuerlich auch die eigene MSN, wenn man selber raus-ruft!)
 (3) Telefonnummer des Angerufenen (d.h. die eigene MSN, wenn man angerufen
     wird)
 (4) Dauer der Verbindung in Sekunden (nur gueltig bei DATA-Verbindungen,
     sonst stets 0)
 (5) Dauer der Verbindung in 1/100 Sekunden
     (im obigen Beispiel: 912 / 100 = 9,12 Sekunden)

Bedanken moechte ich mich vor allem bei
  Gernot Zander (hifi@scorpio.in-berlin.de) fuer den goldenen Hinweis
sowie bei
  Martin Stover (mstover@Kool.f.EUnet.de) fuer seine Muehe beim Testen
von isdnlog.

So, und nun der Code. Bitte als "isdnlog.c" abspeichern, und dann "make" ...
------------------------------ snip ----------------------------------
/* $Id: README.History,v 1.1 2000/07/21 18:46:24 akool Exp $
 *
 * ISDN accounting for isdn4linux. (log-module)
 *
 * Copyright 1995 by Andreas Kool (akool@Kool.f.EUnet.de)
 *
 * 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, or (at your option)
 * any later version.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 * $Log: README.History,v $
 * Revision 1.1  2000/07/21 18:46:24  akool
 * isdnlog-4.35
 *  - isdnlog/aclocal.m4 ... postgre95 in mysql, thx Daniel Pluta
 *  - isdnlog/configure  ... -""-
 *  - country-de.dat enhanced
 *  - new provider One.Tel added (starts next week)
 *
 * Revision 1.11  1995/09/28  18:51:17  akool
 * First public release
 *
 * Revision 1.1  1995/09/16  16:54:12  akool
 * Initial revision
 *
 */

#include <stdio.h>
#include <string.h>
#include <time.h>
#include <sys/types.h>
#include <sys/times.h>
#include <limits.h>
#include <unistd.h>

#define SETUP         1
#define PROCEEDING    2
#define ALERTING      3
#define CONNECT       4
#define DISCONNECT    5
#define RELEASE       6
#define COMPLETE      7

#define CALLING       0
#define CALLED        1

typedef struct {
  char    num[2][20];
  int     inuse;
  time_t  connect;
  time_t  disconnect;
  clock_t duration;
} CALL;

static char usage[]   = "%s: usage: %s [ -%s ] /dev/isdnctrl0\n";
static char options[] = "vsi:p";
static char msg1[]    = "%s: Can't open %s (errno=%d)\n";

static char fn1[]     = "/var/adm/isdn.log";

static FILE *log;
static CALL  call[4];

static void logger(int tei)
{
  register char  *p;
  auto     char   s[BUFSIZ];

  strcpy(s, ctime(&call[tei].connect));

  if (p = strchr(s, '\n'))
    *p = 0;

  fprintf(log, "%s|%-16s|%-16s|%5d|%10d\n",
    s + 4, call[tei].num[CALLING], call[tei].num[CALLED],
    call[tei].disconnect - call[tei].connect, call[tei].duration);

  fflush(log);
} /* logger */

main(int argc, char *argv[], char *envp[])
{
  register char      *p;
  auto     int        verbose = 0, sync = 0, pipe = 0;
  auto     int        next = 0, setup = 0, tei = 0, i, c, chan = 2;
  auto     int        teis[2];
  auto     char       s[BUFSIZ], s1[BUFSIZ], info[BUFSIZ], fn2[BUFSIZ];
  auto     time_t     now;
  auto     FILE      *fin, *log1;
  auto     struct tms tms;
  extern   int        optind, errno;
  extern   char      *optarg;

  *info = 0;

  while ((c = getopt(argc, argv, options)) != EOF)
    switch (c) {
      case 'v' : verbose++;
                 break;

      case 's' : sync++;
                 break;

      case 'i' : strcpy(info, optarg);
                 break;

      case 'p' : pipe++;
                 break;

      case '?' : fprintf(stderr, usage, argv[0], argv[0], options);
                 return(1);
    } /* switch */

  if (optind == argc) {
    fprintf(stderr, usage, argv[0], argv[0], options);
    return(1);
  } /* if */

  if ((fin = fopen(argv[optind], "r")) != (FILE *)NULL) {
    if ((log = fopen(fn1, "a")) != (FILE *)NULL) {

      if (verbose) {
        if (p = strrchr(argv[optind], '/'))
          p++;
        else
          p = argv[optind];

        sprintf(fn2, "/tmp/%s", p);
      } /* if */

      if (!verbose || ((log1 = fopen(fn2, "a")) != (FILE *)NULL)) {

        teis[0] = teis[1] = -1;
        memset(call, 0, sizeof(call));

        while (1) {

          if (fgets(s, BUFSIZ, fin) && (*s != '\n')) {

            if (p = strchr(s, '\n'))
              *p = 0;

            if (verbose) {
              time(&now);
              strcpy(s1, ctime(&now));

              if (p = strchr(s1, '\n'))
                *p = 0;

              fprintf(log1, "%s  %s\n", s1, s);

              if (sync)
                fflush(log1);
            } /* if */

            if (p = strstr(s, "tei")) {
              i = atoi(p + 4);

              if (i == teis[0])
                tei = 0;
              else if (i == teis[1])
                tei = 1;
              else if (teis[0] == -1)
                tei = 0;
              else
                tei = 1;

              teis[tei] = i;
            }
            else if (strstr(s, " SETUP")) {
              setup++;

              if (setup > 1) {
                logger(chan);
                setup = 0;
              } /* if */
            }
            else if (strstr(s, " CONNECT ACKNOWLEDGE")) {
              setup = 0;
            }
            else if (strstr(s, " CONNECT")) {
              setup = 0;
              call[tei].duration = times(&tms);
              time(&call[tei].connect);
              strcpy(call[tei].num[CALLING], call[chan].num[CALLING]);
              strcpy(call[tei].num[CALLED], call[chan].num[CALLED]);

              call[tei].inuse = 1;

              if (*info) {
                if (!fork()) {
                  execl(info, info, call[tei].num[CALLING], call[tei].num[CALLED], NULL);
                  exit(0);
                } /* if */
              } /* if */

            }
            else if (strstr(s, " DISCONNECT")) {
              setup = 0;
              call[tei].duration = times(&tms) - call[tei].duration;
              time(&call[tei].disconnect);

              if (call[tei].inuse)
                logger(tei);

              call[tei].inuse = 0;
              teis[tei] = -1;
            }
            else if (!memcmp(s, "  Calling", 9))
              next = CALLING;
            else if (!memcmp(s, "  Called", 8))
              next = CALLED;
            else if (!memcmp(s, "    number digits", 17)) {
              if ((next == CALLING) && strcmp(call[chan].num[next], s + 18)) {
                if (++chan == 4)
                  chan = 2;
                setup++;
              } /* if */

              strcpy(call[chan].num[next], s + 18);
              time(&call[chan].connect);
              call[chan].disconnect = call[chan].connect;
            } /* else */

            if (pipe)
              fprintf(stdout, s);

          } /* if */
        } /* while */

        if (verbose)
          fclose(log1);
      }
      else {
        fprintf(stderr, msg1, argv[0], fn2, errno);
        return(1);
      } /* else */

      fclose(log);
    }
    else {
      fprintf(stderr, msg1, argv[0], fn1, errno);
      return(1);
    } /* else */

    fclose(fin);
  }
  else {
    fprintf(stderr, msg1, argv[0], argv[optind], errno);
    return(1);
  } /* else */

  return(0);
} /* main */
------------------------------ snap ----------------------------------

Ciao,
Andreas
--
Andreas Kool (akool@Kool.f.EUnet.de)
Transmission of this message via the Microsoft Network is prohibited
