From 31fe82cdc9b84d7d3ddff5c23e4d56aa1cceb78a Mon Sep 17 00:00:00 2001 From: Thomas Osterried Date: Fri, 9 Jan 2009 17:49:33 +0000 Subject: kissnetd now supports unix98 pty's (new option: -p num). The num devices are written to stdout and could easily used in startp scripts. Introduced PATH_MAX for the pty name. Kiss header for crc smack and rmnc are now supported. write return code is now honoured. Thanks to dk2crn for contriution. --- kiss/kissnetd.8 | 6 +- kiss/kissnetd.c | 210 ++++++++++++++++++++++++++++++++++++++++++++------------ 2 files changed, 171 insertions(+), 45 deletions(-) (limited to 'kiss') diff --git a/kiss/kissnetd.8 b/kiss/kissnetd.8 index d069ac9..3b47bac 100644 --- a/kiss/kissnetd.8 +++ b/kiss/kissnetd.8 @@ -2,7 +2,7 @@ .SH NAME kissnetd \- Create a virtual network. .SH SYNOPSIS -.B kissnetd [-f size] [-v] tty... +.B kissnetd [-f size] [-v] [-p | tty... ] .SH DESCRIPTION .LP .B Kissnetd @@ -12,6 +12,10 @@ received on tty is copied to the other ttys. This allows a number of AX.25 systems to share the same packets. .SH OPTIONS .TP 10 +.BI "\-p num" +Automaticaly allocate num Unix98 slave pty's via /dev/ptmx. +These are written to stdout and could be parsed by your startup scripts. +.TP 10 .BI "\-f size" This sets the maximum KISS frame size that the program will handle. The default is 512 bytes which will be adequate under most circumstances. diff --git a/kiss/kissnetd.c b/kiss/kissnetd.c index 62ad4e0..d993e4a 100644 --- a/kiss/kissnetd.c +++ b/kiss/kissnetd.c @@ -10,6 +10,7 @@ */ #include +#define __USE_XOPEN #include #include #include @@ -21,6 +22,7 @@ #include #include #include +#include static char *Version = "1.5"; static int VerboseMode = 0; @@ -29,21 +31,26 @@ static int MaxFrameSize = 512; #define REOPEN_TIMEOUT 30 /* try tio reopen every 10 s */ struct PortDescriptor { - char Name[80]; + char Name[PATH_MAX]; int Fd; unsigned char *FrameBuffer; int BufferIndex; time_t TimeLastOpen; + char namepts[PATH_MAX]; /* name of the unix98 pts slaves, which + * the client has to use */ + int is_active; }; 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, "\nUsage : kissnetd [-v] [-f size] [-p num | /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"); + fprintf(stderr, " -p num : Number of /dev/ptmx-master-devices has to open\n"); exit(1); } @@ -83,45 +90,107 @@ static void NewPort(char *Name) exit(1); } - strncpy(MyPort->Name, Name, sizeof(MyPort->Name)); + strncpy(MyPort->Name, Name, PATH_MAX-1); + MyPort->Name[PATH_MAX-1] = '\0'; MyPort->Fd = -1; MyPort->FrameBuffer[0] = 0xC0; MyPort->BufferIndex = 1; + MyPort->namepts [0] = '\0'; + MyPort->is_active = 0; 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, strerror(errno)); - if (VerboseMode) { - sprintf(MyString, "cannot reopen %s", PortList[PortNumber]->Name); - perror(MyString); + if (PortList[PortNumber]->namepts[0] == '\0') { + + 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, strerror(errno)); + if (VerboseMode) { + sprintf(MyString, "cannot reopen %s", PortList[PortNumber]->Name); + perror(MyString); + } + return; } + PortList[PortNumber]->is_active = 1; + if (!strcmp(PortList[PortNumber]->Name, "/dev/ptmx")) { + char *npts; + /* get name of pts-device */ + if ((npts = ptsname(PortList[PortNumber]->Fd)) == NULL) { + sprintf(MyString, "Cannot get name of pts-device.\n"); + syslog(LOG_WARNING, "kissnetd : Cannot get name of pts-device\n"); + exit(1); + } + strncpy(PortList[PortNumber]->namepts, npts, PATH_MAX-1); + PortList[PortNumber]->namepts[PATH_MAX-1] = '\0'; + + /* unlock pts-device */ + if (unlockpt(PortList[PortNumber]->Fd) == -1) { + sprintf(MyString, "Cannot unlock pts-device %s\n", PortList[PortNumber]->namepts); + syslog(LOG_WARNING, "kissnetd : Cannot unlock pts-device %s\n", PortList[PortNumber]->namepts); + exit(1); + } + syslog(LOG_WARNING, "kissnetd : Using /dev/ptmx with slave pty %s\n", PortList[PortNumber]->namepts); + } + } else { + if (PortList[PortNumber]->Fd == -1) { + syslog(LOG_WARNING, "kissnetd : Cannot reopen port ptmx (slave %s) : not supported by ptmx-device\n", + PortList[PortNumber]->namepts); + if (VerboseMode) { + sprintf(MyString, "cannot reopen ptmx (slave %s).", PortList[PortNumber]->namepts); + perror(MyString); + } + return; + } + syslog(LOG_WARNING, "kissnetd : Trying to poll port ptmx (slave %s).\n", + PortList[PortNumber]->namepts); + PortList[PortNumber]->is_active = 1; } } static void TickReopen(void) { int i; + static int wrote_info = 0; time_t CurrentTime = time(NULL); for (i=0; iFd >= 0) continue; + if (PortList[i]->Fd >= 0 && PortList[i]->is_active == 1) continue; if ( (CurrentTime - PortList[i]->TimeLastOpen) > REOPEN_TIMEOUT ) ReopenPort(i); } + + if (!wrote_info) { + for (i=0; inamepts[0] != '\0') { + if (wrote_info == 0) + printf("\nAwaiting client connects on:\n"); + else + printf(" "); + printf("%s", PortList[i]->namepts); + wrote_info = 1; + } + } + if (wrote_info > 0) { + printf("\n"); + if (!VerboseMode) { + fflush(stdout); + fflush(stderr); + close(0); + close(1); + close(2); + } + } + } } static void Broadcast(int InputPort) @@ -131,19 +200,52 @@ static void Broadcast(int InputPort) /* Broadcast only info frames */ - if (PortList[InputPort]->FrameBuffer[1] != 0x00) return; + if (PortList[InputPort]->FrameBuffer[1] != 0x00 && \ + PortList[InputPort]->FrameBuffer[1] != 0x20 && \ + PortList[InputPort]->FrameBuffer[1] != 0x80) + return; for (i=0; iFd < 0) continue; + if (PortList[i]->Fd < 0 || PortList[i]->is_active == 0) continue; +again: rc = write(PortList[i]->Fd, - PortList[InputPort]->FrameBuffer, - PortList[InputPort]->BufferIndex); + PortList[InputPort]->FrameBuffer+offset, + PortList[InputPort]->BufferIndex-offset); + if (rc < 0) { + if (errno == EAGAIN) { + if (PortList[i]->namepts[0] == '\0') + syslog(LOG_WARNING, "kissnetd : write buffer full on port %s. dropping frame. %s", + PortList[i]->Name, strerror(errno)); + else + syslog(LOG_WARNING, "kissnetd : write buffer full on ptmx port %s. dropping frame. %s", + PortList[i]->namepts, strerror(errno)); + continue; + } + if (PortList[i]->namepts[0] == '\0') + syslog(LOG_WARNING, "kissnetd : Error writing to port %s : %s\n", + PortList[i]->Name, strerror(errno)); + else + syslog(LOG_WARNING, "kissnetd : Error writing to port ptmx (slave %s) : %s\n", + PortList[i]->namepts, strerror(errno)); + if (VerboseMode) perror("write"); + PortList[i]->is_active = 0; + if (PortList[i]->namepts[0] == '\0') { + close(PortList[i]->Fd); + PortList[i]->Fd = -1; + } + continue; + } if (VerboseMode) { printf("Sending %d bytes on port %d : rc=%d\n", PortList[InputPort]->BufferIndex, i, rc); } + if (rc < PortList[InputPort]->BufferIndex-offset) { + offset += rc; + goto again; + } } } @@ -160,11 +262,20 @@ static void ProcessInput(int PortNumber) } if (!Length) return; if (Length < 0) { - syslog(LOG_WARNING, "kissnetd : Error reading port %s : %s\n", - PortList[PortNumber]->Name, strerror(errno)); + if (errno == EAGAIN) + return; + if (MyPort->namepts[0] == '\0') + syslog(LOG_WARNING, "kissnetd : Error reading from port %s : %s\n", + PortList[PortNumber]->Name, strerror(errno)); + else + syslog(LOG_WARNING, "kissnetd : Error reading from port ptmx (slave %s) : %s\n", + PortList[PortNumber]->namepts, strerror(errno)); if (VerboseMode) perror("read"); - close(MyPort->Fd); - MyPort->Fd = -1; + MyPort->is_active = 0; + if (MyPort->namepts[0] == '\0') { + close(MyPort->Fd); + MyPort->Fd = -1; + } return; } for (i=0; iFd >= 0) FD_SET(PortList[i]->Fd, &MyFdSet); + if (PortList[i]->Fd >= 0 && PortList[i]->is_active) FD_SET(PortList[i]->Fd, &MyFdSet); } rc = select(FD_SETSIZE, &MyFdSet, NULL, NULL, &Timeout); @@ -213,31 +324,42 @@ static void ProcessPortList(void) } } -static void ProcessArgv(char *argv[]) +static void ProcessArgv(int argc, char *argv[]) { - char *Opt; - int ArgvIndex = 0; + int opt; + int i=0; + int ptmxdevices = 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; + while ((opt = getopt(argc, argv, "vf:p:")) != -1) { + switch (opt) { + case 'v': + VerboseMode = 1; + break; + case 'f': + MaxFrameSize = atoi(argv[optind]); + break; + case 'p': + ptmxdevices = atoi(optarg); + if (ptmxdevices < 1) { + fprintf(stderr, "error: too many devices\n"); + exit(1); } + for (i=0; i < ptmxdevices; i++) + NewPort("/dev/ptmx"); + break; + default: + fprintf(stderr, "Invalid option %s\n", argv[optind]); + Usage(); + exit(1); } + } + while (optind < argc) + NewPort(argv[optind++]); + + if (NbPort < 2) { + fprintf(stderr, "This multiplexer needs at least two pty's\n"); + exit(1); } } @@ -252,7 +374,7 @@ int main(int argc, char *argv[]) Banner(1); } - ProcessArgv(argv+1); + ProcessArgv(argc, argv); while (1) ProcessPortList(); return 0; } -- cgit v1.2.3