summaryrefslogtreecommitdiffstats
path: root/kiss/kissnetd.c
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1999-04-21 09:51:03 +0200
committerRalf Baechle <ralf@linux-mips.org>1999-04-21 09:51:03 +0200
commit17287576555a5c46fa23549e2e5f073660dccb70 (patch)
tree08be5f5005dad609a2803758b8b825170f6701cb /kiss/kissnetd.c
Import ax25-tools 0.0.1 from tarballax25-tools-0.0.1
Diffstat (limited to 'kiss/kissnetd.c')
-rw-r--r--kiss/kissnetd.c257
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;
+}