diff options
Diffstat (limited to 'kiss/kissnetd.c')
-rw-r--r-- | kiss/kissnetd.c | 257 |
1 files changed, 257 insertions, 0 deletions
diff --git a/kiss/kissnetd.c b/kiss/kissnetd.c new file mode 100644 index 0000000..ff38779 --- /dev/null +++ b/kiss/kissnetd.c @@ -0,0 +1,257 @@ +/* + * kissnetd.c : Simple kiss broadcast daemon between several + * pseudo-tty devices. + * Each kiss frame received on one pty is broadcasted + * to each other one. + * + * ATEPRA FPAC/Linux Project + * + * F1OAT 960804 - Frederic RIBLE + */ + +#include <stdio.h> +#include <stdlib.h> +#include <sys/time.h> +#include <sys/types.h> +#include <unistd.h> +#include <assert.h> +#include <fcntl.h> +#include <strings.h> +#include <errno.h> +#include <syslog.h> +#include <time.h> + +static char *Version = "1.5"; +static int VerboseMode = 0; +static int MaxFrameSize = 512; + +#define REOPEN_TIMEOUT 30 /* try tio reopen every 10 s */ + +struct PortDescriptor { + char Name[80]; + int Fd; + unsigned char *FrameBuffer; + int BufferIndex; + time_t TimeLastOpen; +}; + +static struct PortDescriptor *PortList[FD_SETSIZE]; +static int NbPort = 0; + +static void Usage(void) +{ + fprintf(stderr, "\nUsage : kissnetd [-v] [-f size] /dev/pty?? [/dev/pty??]*\n"); + fprintf(stderr, " -v : Verbose mode, trace on stdout\n"); + fprintf(stderr, " -f size : Set max frame size to size bytes (default 512)\n"); + exit(1); +} + +static void Banner(int Small) +{ + if (Small) { + printf("kissnetd V %s by Frederic RIBLE F1OAT - ATEPRA FPAC/Linux Project\n", Version); + } + else { + printf("****************************************\n"); + printf("* Network broadcast between kiss ports *\n"); + printf("* ATEPRA FPAC/Linux Project *\n"); + printf("****************************************\n"); + printf("* kissnetd Version %-4s *\n", Version); + printf("* by Frederic RIBLE F1OAT *\n"); + printf("****************************************\n"); + } +} + +static void NewPort(char *Name) +{ + struct PortDescriptor *MyPort; + + if (VerboseMode) { + printf("Opening port %s\n", Name); + } + + if (NbPort == FD_SETSIZE) { + fprintf(stderr, "Cannot handle %s : too many ports\n", Name); + exit(1); + } + + MyPort = calloc(sizeof(struct PortDescriptor), 1); + if (MyPort) MyPort->FrameBuffer = calloc(sizeof (unsigned char), MaxFrameSize); + if (!MyPort || !MyPort->FrameBuffer) { + perror("cannot allocate port descriptor"); + exit(1); + } + + strncpy(MyPort->Name, Name, sizeof(MyPort->Name)); + MyPort->Fd = -1; + MyPort->FrameBuffer[0] = 0xC0; + MyPort->BufferIndex = 1; + PortList[NbPort++] = MyPort; +} + +static void ReopenPort(int PortNumber) +{ + char MyString[80]; + + PortList[PortNumber]->TimeLastOpen = time(NULL); + + if (VerboseMode) { + printf("Reopening port %d\n", PortNumber); + } + + syslog(LOG_WARNING, "kissnetd : Opening port %s\n", PortList[PortNumber]->Name); + + PortList[PortNumber]->Fd = open(PortList[PortNumber]->Name, O_RDWR | O_NONBLOCK); + if (PortList[PortNumber]->Fd < 0) { + syslog(LOG_WARNING, "kissnetd : Error opening port %s : %s\n", + PortList[PortNumber]->Name, sys_errlist[errno]); + if (VerboseMode) { + sprintf(MyString, "cannot reopen %s", PortList[PortNumber]->Name); + perror(MyString); + } + } +} + +static void TickReopen(void) +{ + int i; + time_t CurrentTime = time(NULL); + + for (i=0; i<NbPort; i++) { + if (PortList[i]->Fd >= 0) continue; + if ( (CurrentTime - PortList[i]->TimeLastOpen) > REOPEN_TIMEOUT ) ReopenPort(i); + } +} + +static void Broadcast(int InputPort) +{ + int i; + int rc; + + /* Broadcast only info frames */ + + if (PortList[InputPort]->FrameBuffer[1] != 0x00) return; + + for (i=0; i<NbPort; i++) { + if (i == InputPort) continue; + if (PortList[i]->Fd < 0) continue; + rc = write(PortList[i]->Fd, + PortList[InputPort]->FrameBuffer, + PortList[InputPort]->BufferIndex); + if (VerboseMode) { + printf("Sending %d bytes on port %d : rc=%d\n", + PortList[InputPort]->BufferIndex, + i, rc); + } + } +} + +static void ProcessInput(int PortNumber) +{ + static unsigned char MyBuffer[2048]; + int Length; + int i; + struct PortDescriptor *MyPort = PortList[PortNumber]; + + Length = read(MyPort->Fd, MyBuffer, sizeof(MyBuffer)); + if (VerboseMode) { + printf("Read port %d : rc=%d\n", PortNumber, Length); + } + if (!Length) return; + if (Length < 0) { + syslog(LOG_WARNING, "kissnetd : Error reading port %s : %s\n", + PortList[PortNumber]->Name, sys_errlist[errno]); + if (VerboseMode) perror("read"); + close(MyPort->Fd); + MyPort->Fd = -1; + return; + } + for (i=0; i<Length; i++) { + if (MyPort->BufferIndex == MaxFrameSize) { + if (MyBuffer[i] == 0xC0) { + if (VerboseMode) printf("Drop frame too long\n"); + MyPort->BufferIndex = 1; + } + } + else { + MyPort->FrameBuffer[MyPort->BufferIndex++] = MyBuffer[i]; + if (MyBuffer[i] == 0xC0) { + Broadcast(PortNumber); + MyPort->BufferIndex = 1; + } + } + } +} + +static void ProcessPortList(void) +{ + static fd_set MyFdSet; + int i, rc; + struct timeval Timeout; + + Timeout.tv_sec = 1; + Timeout.tv_usec = 0; + + FD_ZERO(&MyFdSet); + for (i=0; i<NbPort; i++) { + if (PortList[i]->Fd >= 0) FD_SET(PortList[i]->Fd, &MyFdSet); + } + rc = select(FD_SETSIZE, &MyFdSet, NULL, NULL, &Timeout); + + if (VerboseMode) printf("select : rc=%d\n", rc); + if (!rc ) TickReopen(); + + if (rc > 0) { + for (i=0; i<NbPort && rc; i++) { + if (PortList[i]->Fd < 0) continue; + if (FD_ISSET(PortList[i]->Fd, &MyFdSet)) { + ProcessInput(i); + rc--; + } + } + } +} + +static void ProcessArgv(char *argv[]) +{ + char *Opt; + int ArgvIndex = 0; + + while (argv[ArgvIndex]) { + if (argv[ArgvIndex][0] != '-') { + NewPort(argv[ArgvIndex++]); + continue; + } + for (Opt = &argv[ArgvIndex++][1]; *Opt; Opt++) { + switch (*Opt) { + case 'v': + VerboseMode = 1; + break; + case 'f': + MaxFrameSize = atoi(argv[ArgvIndex++]); + break; + default: + fprintf(stderr, "Invalid option %c\n", *Opt); + Usage(); + break; + } + } + + } +} + + +int main(int argc, char *argv[]) +{ + if (argc < 2) { + Banner(0); + Usage(); + } + else { + Banner(1); + } + + ProcessArgv(argv+1); + while (1) ProcessPortList(); + return 0; +} |