first cut of client
authordjk <djk>
Sun, 26 Mar 2000 00:03:30 +0000 (00:03 +0000)
committerdjk <djk>
Sun, 26 Mar 2000 00:03:30 +0000 (00:03 +0000)
src/Makefile [new file with mode: 0644]
src/chain.c [new file with mode: 0755]
src/chain.h [new file with mode: 0755]
src/client.c [new file with mode: 0644]
src/cmsg.c [new file with mode: 0755]
src/cmsg.h [new file with mode: 0755]
src/sel.c [new file with mode: 0755]
src/sel.h [new file with mode: 0755]

diff --git a/src/Makefile b/src/Makefile
new file mode 100644 (file)
index 0000000..09d6864
--- /dev/null
@@ -0,0 +1,11 @@
+#
+# makefile for the C programs for the DXSpider node
+#
+
+CFLAGS = -g -O
+
+CLIENTOBJ = client.o sel.o cmsg.o chain.o
+CLIENTBIN = client
+
+$(CLIENTBIN) : $(CLIENTOBJ)
+       $(CC) $(CFLAGS) $(CLIENTOBJ) -o $(CLIENTBIN) 
\ No newline at end of file
diff --git a/src/chain.c b/src/chain.c
new file mode 100755 (executable)
index 0000000..4e36b3e
--- /dev/null
@@ -0,0 +1,222 @@
+/*
+ * routines to operate on double linked circular chains
+ *
+ * chain_init() - initialise a chain
+ * chain_add() - add an item after the ref provided
+ * chain_delete() - delete the item
+ * chainins() - insert an item before the ref
+ * chainnext() - get the next item on chain returning NULL if eof
+ * chainprev() - get the previous item on chain returning NULL if eof
+ * chain_empty_test() - is the chain empty?
+ * chain_movebase() - move a chain of things onto (the end of) another base
+ *
+ * $Header$
+ *
+ * $Log$
+ * Revision 1.1  2000-03-26 00:03:30  djk
+ * first cut of client
+ *
+ * Revision 1.4  1998/01/02 19:39:58  djk
+ * made various changes to cope with glibc
+ * fixed problem with extended status in etsi_router
+ *
+ * Revision 1.3  1997/01/02 18:46:46  djk
+ * Added conv.c from ETSI router
+ * Changed qerror.c to use syslog rather than qerror.log
+ * removed all the map27 stuff into a separate directory
+ * added dump.c (a debugging tool for dumping frames of data)
+ *
+ * Revision 1.1  1996/08/08 11:33:44  djk
+ * Initial revision
+ *
+ * Revision 1.2  1995/04/21  16:02:51  djk
+ * remove rcs id
+ *
+ * Revision 1.1  1995/03/04  11:46:26  djk
+ * Initial revision
+ *
+ * Revision 1.2  1995/01/24  15:09:39  djk
+ * Changed Indent to Id in rcsid
+ *
+ * Revision 1.1  1995/01/24  15:06:28  djk
+ * Initial revision
+ *
+ * Revision 1.3  91/03/08  13:21:56  dlp
+ * changed the chain broken checks to dlpabort for dlperror
+ * 
+ * Revision 1.2  90/09/15  22:37:39  dlp
+ * checked in with -k by dirk at 91.02.20.15.53.51.
+ * 
+ * Revision 1.2  90/09/15  22:37:39  dlp
+ * *** empty log message ***
+ * 
+ * Revision 1.1  90/09/15  22:18:23  dlp
+ * Initial revision
+ * 
+ */
+
+#include <stdlib.h>
+
+/* chain definitions */
+typedef struct _reft {
+       struct _reft *next, *prev;
+} reft;
+
+static char erm[] = "chain broken in %s";
+#define check(p, ss) if (p == (struct _reft *) 0 || p->prev->next != p || p->next->prev != p) die(erm, ss);
+
+/*
+ * chain_init()
+ */
+
+void chain_init(p)
+struct _reft *p;
+{
+       p->next = p->prev = p;
+}
+
+/*
+ * chain_insert() - insert an item before the ref provided
+ */
+
+void chain_insert(p, q)
+struct _reft *p, *q;
+{
+       check(p, "ins");
+       q->prev = p->prev;
+       q->next = p;
+       p->prev->next = q;
+       p->prev = q;
+}
+/*
+ * chain_movebase() - insert an chain of items from one base to another
+ */
+
+void chain_movebase(p, q)
+struct _reft *p, *q;
+{
+       check(p, "movebase");
+       q->prev->prev = p->prev;
+       q->next->next = p;
+       p->prev->next = q->next;
+       p->prev = q->prev;
+       q->next = q->prev = q;
+}
+
+/*
+ * chain_add() - add an item after the ref
+ */
+
+void chain_add(p, q)
+struct _reft *p, *q;
+{
+       check(p, "add");
+       p = p->next;
+       chain_insert(p, q);
+}
+
+/*
+ * chain_delete() - delete an item in a chain
+ */
+
+struct _reft *chain_delete(p)
+struct _reft *p;
+{
+       check(p, "del");
+       p->prev->next = p->next;
+       p->next->prev = p->prev;
+       return p->prev;
+}
+
+/*
+ * chain_empty_test() - test to see if the chain is empty
+ */
+
+int chain_empty_test(base)
+struct _reft *base;
+{
+       check(base, "chain_empty_test")
+               return base->next == base;
+}
+
+/*
+ * chainnext() - get next item in chain
+ */
+
+struct _reft *chain_get_next(base, p)
+struct _reft *base, *p;
+{
+
+       check(base, "next base");
+       
+       if (!p)
+               return (chain_empty_test(base)) ? 0 : base->next;
+
+       check(p, "next last ref");
+       if (p->next != base)
+               return p->next;
+       else
+               return (struct _reft *) 0;
+}
+
+/*
+ * chainprev() - get previous item in chain
+ */
+
+struct _reft *chain_get_prev(base, p)
+struct _reft *base, *p;
+{
+       check(base, "prev base");
+       if (!p)
+               return (chain_empty_test(base)) ? 0 : base->prev;
+
+       check(p, "prev last ref");
+       if (p->prev != base)
+               return p->prev;
+       else
+               return (struct _reft *) 0;
+}
+
+/*
+ * rechain() - re-chain an item at this point (usually after the chain base)
+ */
+
+void chain_rechain(base, p)
+struct _reft *base, *p;
+{
+       check(base, "rechain base");
+       check(p, "rechain last ref");
+       chain_delete(p);
+       chain_add(base, p);
+}
+
+/*
+ * emptychain() - remove all the elements in a chain, this frees all elements
+ *                in a chain leaving just the base.
+ */
+
+void chain_flush(base)
+struct _reft *base;
+{
+       struct _reft *p;
+
+       while (!chain_empty_test(base)) {
+               p = base->next;
+               chain_delete(p);
+               free(p);
+       }
+}
+
+/*
+ * newchain() - create a new chain base in the heap
+ */
+
+reft *chain_new()
+{
+       reft *p = malloc(sizeof(reft));
+       if (!p)
+               die("out of room in chain_new");
+       chain_init(p);
+       return p;
+}
+
diff --git a/src/chain.h b/src/chain.h
new file mode 100755 (executable)
index 0000000..b4e6378
--- /dev/null
@@ -0,0 +1,28 @@
+
+/*
+ * chain base definitions
+ */
+
+
+#ifndef _CHAIN_DEFS                    /* chain definitions */
+
+typedef struct _reft
+{
+       struct _reft *next, *prev;
+} reft;
+
+extern void chain_init(reft *);
+extern void chain_insert(reft *, void *);
+extern void chain_add(reft *, void *);
+extern void *chain_delete(void *);
+extern void *chain_get_next(reft *, void *);
+extern void *chain_get_prev(reft *, void *);
+extern void chain_rechain(reft *, void *);
+extern int  chain_empty_test(reft *);
+extern void chain_flush(reft *);
+extern reft *chain_new(void);
+
+#define is_chain_empty chain_empty_test
+
+#define _CHAIN_DEFS
+#endif
diff --git a/src/client.c b/src/client.c
new file mode 100644 (file)
index 0000000..640c2b4
--- /dev/null
@@ -0,0 +1,463 @@
+/*
+ * C Client for the DX Spider cluster program
+ *
+ * Eventually this program will be a complete replacement
+ * for the perl version.
+ *
+ * This program provides the glue necessary to talk between
+ * an input (eg from telnet or ax25) and the perl DXSpider
+ * node.
+ *
+ * Currently, this program connects STDIN/STDOUT to the
+ * message system used by cluster.pl
+ *
+ * Copyright (c) 2000 Dirk Koopman G1TLH
+ *
+ * $Id$
+ */
+
+#include <stdio.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <netdb.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <errno.h>
+#include <signal.h>
+#include <string.h>
+
+#include "sel.h"
+#include "cmsg.h"
+
+#define TEXT 1
+#define MSG 2
+#define MAXBUFL 1024
+
+typedef struct 
+{
+       int cnum;                                       /* the connection number */
+       int sort;                                       /* the type of connection either text or msg */
+       cmsg_t *in;                                     /* current input message being built up */
+       cmsg_t *out;                            /* current output message being sent */
+       reft *inq;                                      /* input queue */
+       reft *outq;                                     /* output queue */
+       sel_t *sp;                                      /* my select fcb address */
+} fcb_t;
+
+char *node_addr = "localhost"; /* the node tcp address */
+int node_port = 27754;                 /* the tcp port of the node at the above address */
+char *call;                                            /* the caller's callsign */
+char *connsort;                                        /* the type of connection */
+fcb_t *in;                                             /* the fcb of 'stdin' that I shall use */
+fcb_t *out;                                            /* the fcb of 'stdout' that I shall use */
+fcb_t *node;                                   /* the fcb of the msg system */
+char nl = '\n';                                        /* line end character */
+char ending = 0;                               /* set this to end the program */
+char send_Z = 1;                               /* set a Z record to the node on termination */
+
+/*
+ * utility routines - various
+ */
+
+void die(char *s, ...)
+{
+       char buf[2000];
+       
+       va_list ap;
+       va_start(ap, s);
+       vsprintf(buf, s, ap);
+       va_end(ap);
+       fprintf(stderr, buf);
+       exit(-1);
+}
+
+char *strupper(char *s)
+{
+       char *d = malloc(strlen(s)+1);
+       char *p = d;
+       
+       if (!d)
+               die("out of room in strupper");
+       while (*p++ = toupper(*s++)) ;
+       return d;
+}
+
+char *strlower(char *s)
+{
+       char *d = malloc(strlen(s)+1);
+       char *p = d;
+       
+       if (!d)
+               die("out of room in strlower");
+       while (*p++ = tolower(*s++)) ;
+       return d;
+}
+
+int eq(char *a, char *b)
+{
+       return (strcmp(a, b) == 0);
+}
+
+/*
+ * higher level send and receive routines
+ */
+
+fcb_t *fcb_new(int cnum, int sort)
+{
+       fcb_t *f = malloc(sizeof(fcb_t));
+       if (!f)
+               die("no room in fcb_new");
+       memset (f, 0, sizeof(fcb_t));
+       f->cnum = cnum;
+       f->sort = sort;
+       f->inq = chain_new();
+       f->outq = chain_new();
+       return f;
+}
+
+void send_text(fcb_t *f, char *s, int l)
+{
+       cmsg_t *mp;
+       mp = cmsg_new(l+1, f->sort, f);
+       memcpy(mp->inp, s, l);
+       mp->inp += l;
+       *mp->inp++ = nl;
+       cmsg_send(f->outq, mp, 0);
+       f->sp->flags |= SEL_OUTPUT;
+}
+
+void send_msg(fcb_t *f, char let, char *s, int l)
+{
+       cmsg_t *mp;
+       int ln;
+       int myl = strlen(call)+2+l;
+
+       mp = cmsg_new(myl+4, f->sort, f);
+       ln = htonl(myl);
+       memcpy(mp->inp, &ln, 4);
+       mp->inp += 4;
+       *mp->inp++ = let;
+       strcpy(mp->inp, call);
+       mp->inp += strlen(call);
+       *mp->inp++ = '|';
+       if (l) {
+               memcpy(mp->inp, s, l);
+               mp->inp += l;
+       }
+       *mp->inp = 0;
+       cmsg_send(f->outq, mp, 0);
+       f->sp->flags |= SEL_OUTPUT;
+}
+
+int fcb_handler(sel_t *sp, int in, int out, int err)
+{
+       fcb_t *f = sp->fcb;
+       cmsg_t *mp;
+       
+       /* input modes */
+       if (in) {
+               char *p, buf[MAXBUFL];
+               int r;
+
+               /* read what we have into a buffer */
+               r = read(f->cnum, buf, MAXBUFL);
+               if (r < 0) {
+                       switch (errno) {
+                       case EINTR:
+                       case EINPROGRESS:
+                       case EAGAIN:
+                               goto lout;
+                       default:
+                               if (f->sort == MSG)
+                                       send_Z = 0;
+                               ending++;
+                               return 0;
+                       }
+               } else if (r == 0) {
+                       if (f->sort == MSG)
+                               send_Z = 0;
+                       ending++;
+                       return 0;
+               }
+
+               /* create a new message buffer if required */
+               if (!f->in)
+                       f->in = cmsg_new(MAXBUFL, sp->sort, f);
+               mp = f->in;
+
+               switch (f->sort) {
+               case TEXT:
+                       p = buf;
+                       while (r > 0 && p < &buf[r]) {
+                               
+                               /*
+                                * if we have a nl then send the message upstairs
+                                * start a new message
+                                */
+                               
+                               if (*p == nl) {
+                                       if (mp->inp == mp->data)
+                                               *mp->inp++ = ' ';
+                                       *mp->inp = 0;              /* zero terminate it, but don't include it in the length */
+                                       cmsg_send(f->inq, mp, 0);
+                                       f->in = mp = cmsg_new(MAXBUFL, sp->sort, f);
+                                       ++p;
+                               } else {
+                                       if (mp->inp < &mp->data[MAXBUFL])
+                                               *mp->inp++ = *p++;
+                                       else {
+                                               mp->inp = mp->data;
+                                       }
+                               }
+                       }
+                       break;
+
+               case MSG:
+                       p = buf;
+                       while (r > 0 && p < &buf[r]) {
+
+                               /* build up the size into the likely message length (yes I know it's a short) */
+                               switch (mp->state) {
+                               case 0:
+                               case 1:
+                               case 2:
+                               case 3:
+                                       mp->size = (mp->size << 8) | *p++;
+                                       mp->state++;
+                                       break;
+                               default:
+                                       if (mp->inp - mp->data < mp->size) {
+                                               *mp->inp++ = *p++;
+                                       } else {
+                                               /* kick it upstairs */
+                                               cmsg_send(f->inq, mp, 0);
+                                               mp = f->in = cmsg_new(MAXBUFL, f->sort, f);
+                                       }
+                               }
+                       }
+                       break;
+                       
+               default:
+                       die("invalid sort (%d) in input handler", f->sort);
+               }
+       }
+       
+       /* output modes */
+lout:;
+       if (out) {
+               int l, r;
+               
+               if (!f->out) {
+                       mp = f->out = cmsg_next(f->outq);
+                       if (!mp) {
+                               sp->flags &= ~SEL_OUTPUT;
+                               return 0;
+                       }
+                       mp->inp = mp->data;
+               }
+               l = mp->size - (mp->inp - mp->data);
+               if (l > 0) {
+                       r = write(f->cnum, mp->inp, l);
+                       if (r < 0) {
+                               switch (errno) {
+                               case EINTR:
+                               case EINPROGRESS:
+                               case EAGAIN:
+                                       goto lend;
+                               default:
+                                       if (f->sort == MSG)
+                                               send_Z = 0;
+                                       ending++;
+                                       return;
+                               }
+                       } else if (r > 0) {
+                               mp->inp += r;
+                       }
+               } else if (l < 0) 
+                       die("got negative length in handler on node");
+               if (mp->inp - mp->data >= mp->size) {
+                       cmsg_callback(mp, 0);
+                       f->out = 0;
+                       if (!is_chain_empty(f->outq))
+                               sp->flags &= ~SEL_OUTPUT;
+               }
+       }
+lend:;
+       return 0;
+}
+
+/*
+ * things to do with initialisation
+ */
+
+void initargs(int argc, char *argv[])
+{
+       int i;
+       if (argc >= 2) {
+               call = strupper(argv[1]);
+               if (eq(call, "LOGIN"))
+                       die("login not implemented (yet)");
+       }
+       if (!call)
+               die("Must have at least a callsign (for now)");
+
+       if (argc >= 3) {
+               connsort = strlower(argv[2]);
+               if (eq(connsort, "telnet") || eq(connsort, "local")) {
+                       nl = '\n';
+               } else if (eq(connsort, "ax25")) {
+                       nl = '\r';
+               } else {
+                       die("2nd argument must be \"telnet\" or \"ax25\" or \"local\"");
+               }
+       } else {
+               connsort = "local";
+       }
+}
+
+void connect_to_node()
+{
+       struct hostent *hp, *gethostbyname();
+       struct sockaddr_in server;
+       int nodef;
+       sel_t *sp;
+                               
+       if ((hp = gethostbyname(node_addr)) == 0) 
+               die("Unknown host tcp host %s for printer", node_addr);
+
+       memset(&server, 0, sizeof server);
+       server.sin_family = AF_INET;
+       memcpy(&server.sin_addr, hp->h_addr, hp->h_length);
+       server.sin_port = htons(node_port);
+                                               
+       nodef = socket(AF_INET, SOCK_STREAM, 0);
+       if (nodef < 0) 
+               die("Can't open socket to %s port %d (%d)", node_addr, node_port, errno);
+
+       if (connect(nodef, (struct sockaddr *) &server, sizeof server) < 0) {
+               die("Error on connect to %s port %d (%d)", node_addr, node_port, errno);
+       }
+       node = fcb_new(nodef, MSG);
+       node->sp = sel_open(nodef, node, "Msg System", fcb_handler, MSG, SEL_INPUT);
+       
+}
+
+/*
+ * things to do with going away
+ */
+
+void term_timeout(int i)
+{
+       /* none of this is going to be reused so don't bother cleaning up properly */
+       if (out)
+               out = 0;
+       if (node) {
+               close(node->cnum);
+               node = 0;
+       }
+       exit(i);
+}
+
+void terminate(int i)
+{
+       if (send_Z && call) {
+               send_msg(node, 'Z', "", 0);
+       }
+       
+       signal(SIGALRM, term_timeout);
+       alarm(10);
+       
+       while ((out && !is_chain_empty(out->outq)) ||
+                  (node && !is_chain_empty(node->outq))) {
+               sel_run();
+       }
+       if (node) 
+               close(node->cnum);
+       exit(i);
+}
+
+/*
+ * things to do with ongoing processing of inputs
+ */
+
+void process_stdin()
+{
+       cmsg_t *mp = cmsg_next(in->inq);
+       if (mp) {
+               send_msg(node, 'I', mp->data, mp->size);
+               cmsg_callback(mp, 0);
+       }
+}
+
+void process_node()
+{
+       cmsg_t *mp = cmsg_next(node->inq);
+       if (mp) {
+               char *p = strchr(mp->data, '|');
+               if (p)
+                       p++;
+               switch (mp->data[0]) {
+               case 'Z':
+                       send_Z = 0;
+                       ending++;
+                       return;
+               case 'D':
+                       if (p) {
+                               int l = mp->inp - (unsigned char *) p;
+                               send_text(out, p, l);
+                       }
+                       break;
+               default:
+                       break;
+               }
+               cmsg_callback(mp, 0);
+       }
+       if (is_chain_empty(out->outq))
+               fsync(out->cnum);
+}
+
+/*
+ * the program itself....
+ */
+
+main(int argc, char *argv[])
+{
+       initargs(argc, argv);
+       sel_init(10, 0, 10000);
+
+       signal(SIGHUP, SIG_IGN);
+
+       signal(SIGINT, terminate);
+       signal(SIGQUIT, terminate);
+       signal(SIGTERM, terminate);
+       signal(SIGPWR, terminate);
+
+       /* connect up stdin, stdout and message system */
+       in = fcb_new(0, TEXT);
+       in->sp = sel_open(0, in, "STDIN", fcb_handler, TEXT, SEL_INPUT);
+       out = fcb_new(1, TEXT);
+       out->sp = sel_open(1, out, "STDOUT", fcb_handler, TEXT, 0);
+       connect_to_node();
+
+       /* tell the cluster who I am */
+       send_msg(node, 'A', connsort, strlen(connsort));
+       
+       /* main processing loop */
+       while (!ending) {
+               sel_run();
+               if (!ending) {
+                       process_stdin();
+                       process_node();
+               }
+       }
+       terminate(0);
+}
+
+
+
+
+
diff --git a/src/cmsg.c b/src/cmsg.c
new file mode 100755 (executable)
index 0000000..1b325b5
--- /dev/null
@@ -0,0 +1,226 @@
+/*
+ * cmsg.c
+ * 
+ * create and free message buffers
+ * 
+ * Copyright 1996 (c) D-J Koopman
+ * 
+ * $Header$
+ */
+
+
+static char rcsid[] = "$Id$";
+
+#include <time.h>
+#include <stdlib.h>
+
+#include "chain.h"
+#include "cmsg.h"
+
+long cmsg_count = 0;
+
+#ifdef DB_CMSG
+#include <malloc.h>
+#include <stdio.h>
+
+
+#define MAXSORT 20
+#define INTERVAL 10
+#define FN "msg_stats"
+
+static struct {
+       long new;
+       long free;
+} stats[MAXSORT+1];
+
+static void store()
+{
+       static time_t t;
+       time_t systime;
+       
+       time(&systime);
+       if (systime - t > INTERVAL) {
+               FILE *f = fopen(FN, "w");
+               if (f) {
+                       int i;
+                       struct mallinfo m;                      
+                       fprintf(f, "\nMSG STATISTICS\n");
+                       fprintf(f,   "==============\n\n");
+                       fprintf(f, "cmsg_count = %ld\n\n", cmsg_count);
+                       for (i = 0; i < MAXSORT+1; ++i) {
+                               if (stats[i].new == 0 && stats[i].free == 0)
+                                       continue;
+                               fprintf(f, "%d new: %ld free: %ld outstanding: %ld\n", i, stats[i].new, stats[i].free, stats[i].new-stats[i].free);
+                       }
+                       m = mallinfo();
+                       fprintf(f, "\nmalloc total arena used: %ld used: %ld free: %ld\n\n", m.arena, m.uordblks, m.fordblks);
+                       fclose(f);
+               }
+               t = systime;
+       }
+}
+
+void cmsg_clear_stats()
+{
+       memset(stats, 0, sizeof stats);
+       store();
+}
+
+#endif
+
+cmsg_t *cmsg_new(int size, int sort, void *pp)
+{
+       cmsg_t *mp;
+       
+       mp = malloc(sizeof(cmsg_t) + size);
+       if (!mp)
+               die("no room in cmsg_new");
+       mp->size = 0;
+       mp->sort = sort & CMSG_SORTMASK;
+       mp->portp = pp;
+       mp->state = mp->reply = 0;
+       mp->inp = mp->data;
+       mp->callback = 0;
+       ++cmsg_count;
+#ifdef DB_CMSG
+       if (sort > MAXSORT)
+               sort = MAXSORT;
+       ++stats[sort].new;      
+       store();
+#endif
+       return mp;
+}
+
+void cmsg_send(reft *base, cmsg_t *mp, void (*callback)())
+{
+       time(&mp->t);
+       mp->size = mp->inp - mp->data;     /* calc the real size */
+       mp->callback = callback;                   /* store the reply address */
+       chain_insert(base, mp);
+#ifdef DB_CMSG
+       store();
+#endif
+}
+
+void cmsg_priority_send(reft *base, cmsg_t *mp, void (*callback)())
+{
+       time(&mp->t);
+       mp->size = mp->inp - mp->data;     /* calc the real size */
+       mp->callback = callback;                   /* store the reply address */
+       chain_add(base, mp);
+#ifdef DB_CMSG
+       store();
+#endif
+}
+
+/*
+ * get the next cmsg (from the front), this removes the message from the chain
+ */
+
+cmsg_t *cmsg_next(reft *base)
+{
+       cmsg_t *mp = chain_get_next(base, 0);
+       if (mp)
+               chain_delete(mp);
+#ifdef DB_CMSG
+       store();
+#endif
+       return mp;
+}
+
+/*
+ * get the prev cmsg (from the back), this removes the message from the chain
+ */
+
+cmsg_t *cmsg_prev(reft *base)
+{
+       cmsg_t *mp = chain_get_prev(base, 0);
+       if (mp)
+               chain_delete(mp);
+#ifdef DB_CMSG
+       store();
+#endif
+       return mp;
+}
+
+void cmsg_callback(cmsg_t *m, int reply)
+{
+       if (m->callback)
+               (m->callback)(m, reply);
+       cmsg_free(m);
+}
+
+void cmsg_free(cmsg_t *m)
+{
+       --cmsg_count;
+#ifdef DB_CMSG
+       if (m->sort > MAXSORT)
+               m->sort = MAXSORT;
+       ++stats[m->sort].free;  
+       store();
+#endif
+       free(m);
+}
+
+void cmsg_flush(reft *base, int reply)
+{
+       cmsg_t *m;
+       
+       while (m = cmsg_next(base)) {
+               cmsg_callback(m, reply);
+       }
+#ifdef DB_CMSG
+       store();
+#endif
+}              
+
+/*
+ * 
+ * $Log$
+ * Revision 1.1  2000-03-26 00:03:30  djk
+ * first cut of client
+ *
+ * Revision 1.12  1998/05/05 14:01:27  djk
+ * Tidied up various global variables in the hope that there is likely
+ * to be less undefined interaction between modules.
+ * Added some extra LINUX debugging to check for possible cmsg memory leaks.
+ *
+ * Revision 1.11  1998/01/02 19:39:58  djk
+ * made various changes to cope with glibc
+ * fixed problem with extended status in etsi_router
+ *
+ * Revision 1.10  1997/06/13 16:51:17  djk
+ * fixed various library problems
+ * got the taipstack and hayes to the point of half duplex reliability
+ * hayes now successfully communicates with taiptest and has part of the
+ * command level taip stuff in.
+ *
+ * Revision 1.9  1997/05/20 20:45:14  djk
+ * The 1.22 version more or less unchanged
+ *
+ * Revision 1.8  1997/03/25 18:12:55  djk
+ * dunno
+ *
+ * Revision 1.7  1997/03/19 09:57:28  djk
+ * added a count to check for leaks
+ *
+ * Revision 1.6  1997/02/13 17:02:04  djk
+ * forgotten?
+ *
+ * Revision 1.5  1997/02/04 17:47:04  djk
+ * brought into line with public2
+ *
+ * Revision 1.4  1997/02/04 01:27:37  djk
+ * altered size semantics on create (size now = 0 not creation size)
+ *
+ * Revision 1.3  1997/01/20 22:29:27  djk
+ * added status back
+ *
+ * Revision 1.2  1997/01/13 23:34:29  djk
+ * The first working test version of smsd
+ *
+ * Revision 1.1  1997/01/03 23:42:21  djk
+ * added a general message handling module (still developing)
+ * added parity handling to ser.c
+ *
+ */
diff --git a/src/cmsg.h b/src/cmsg.h
new file mode 100755 (executable)
index 0000000..384b90f
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * cmsg.h
+ * 
+ * general purpose message format
+ * 
+ * Copyright 1996 (c) D-J Koopman
+ * 
+ * $Header$
+ * 
+ * $Log$
+ * Revision 1.1  2000-03-26 00:03:30  djk
+ * first cut of client
+ *
+ * Revision 1.7  1998/01/02 19:39:57  djk
+ * made various changes to cope with glibc
+ * fixed problem with extended status in etsi_router
+ *
+ * Revision 1.6  1997/03/25 18:12:45  djk
+ * dunno
+ *
+ * Revision 1.5  1997/03/19 09:57:54  djk
+ * added a count to check for leaks
+ *
+ * Revision 1.4  1997/02/13 17:01:55  djk
+ * forgotten?
+ *
+ * Revision 1.3  1997/01/20 22:29:23  djk
+ * added status back
+ *
+ * Revision 1.2  1997/01/13 23:34:22  djk
+ * The first working test version of smsd
+ *
+ * Revision 1.1  1997/01/03 23:41:27  djk
+ * added a general message handling module (still developing)
+ * added dump (a general debugging routine)
+ *
+ *
+ */
+
+#ifndef _CMSG_H
+#define _CMSG_H
+static char _cmsg_h_rcsid[] = "$Id$";
+
+#include <time.h>
+
+typedef struct {
+       reft  head;                                     /* the chain on which this message is going */
+       short size;                                     /* the length of the data part of the message */
+       short sort;                                     /* the type of message (ie text, rmip, etsi) (may have reply bit set) */
+       short state;                            /* the current state of this message */
+       short reply;                            /* the (standard) reply field */
+       time_t t;                                       /* the time of arrival */
+       void (*callback)();                     /* the callback address if any */
+       void *portp;                            /* the pointer to the port it came from */
+       unsigned char *inp;                     /* the current character pointer for input */
+    unsigned char data[1];             /* the actual data of the message */
+} cmsg_t;
+
+#define CMSG_REPLY 0x8000
+#define CMSG_SORTMASK (~CMSG_REPLY)
+
+extern long cmsg_count;
+
+cmsg_t *cmsg_new(int, int, void *);
+void cmsg_send(reft *, cmsg_t *, void (*)());
+void cmsg_priority_send(reft *, cmsg_t *, void (*)());
+void cmsg_callback(cmsg_t *, int);
+void cmsg_flush(reft *, int);
+void cmsg_free(cmsg_t *);
+cmsg_t *cmsg_next(reft *);
+cmsg_t *cmsg_prev(reft *);
+#endif
diff --git a/src/sel.c b/src/sel.c
new file mode 100755 (executable)
index 0000000..2d8972f
--- /dev/null
+++ b/src/sel.c
@@ -0,0 +1,214 @@
+/*
+ * sel.c
+ * 
+ * util routines for do the various select activities
+ * 
+ * Copyright 1996 (c) D-J Koopman
+ * 
+ * $Header$
+ */
+
+static char rcsid[] = "$Id$";
+
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <time.h>
+#include <string.h>
+#include <errno.h>
+
+#include "chain.h"
+#include "sel.h"
+
+sel_t *sel;                                                       /* the array of selectors */
+int sel_max;                                              /* the maximum no of selectors */
+int sel_top;                                              /* the last selector in use */
+int sel_inuse;                                            /* the no of selectors in use */
+time_t sel_systime;                                       /* the unix time now */
+struct timeval sel_tv;                            /* the current timeout for select */
+
+/*
+ * initialise the selector system, no is the no of slots to reserve
+ */
+
+void sel_init(int no, long sec, long usec)
+{
+       sel = malloc(sizeof(sel_t) * no);
+       if (!sel)
+               die("no room in sel_init");
+       memset(sel, 0, sizeof(sel_t) * no);
+       sel_max = no;
+       sel_inuse = sel_top = 0;
+       if (sec == 0 && usec == 0) 
+               usec = 10000;
+       sel_tv.tv_sec = sec;
+       sel_tv.tv_usec = usec;
+}
+
+/*
+ * open and initialise a selector slot, you are expected to deal with the
+ * actual opening and setting up of the device itself
+ */
+
+sel_t *sel_open(int cnum, void *fcb, char *name, int (*handler)(), int sort, int flags)
+{
+       int i;
+       sel_t *sp;
+       
+       /* get a free slot */
+       for (i = 0; i < sel_max; ++i) {
+               sp = &sel[i];
+               if (sp->sort == 0)
+                       break;
+       }
+       if (i >= sel_max)
+               die("there are no more sel slots available (max %d)", sel_max);
+       
+       /* fill in the blanks */
+       sp->cnum = cnum;
+       sp->fcb = fcb;
+       sp->name = strdup(name);
+       sp->handler = handler;
+       sp->sort = sort;
+       sp->flags = flags;
+       sp->msgbase = chain_new();
+       sp->err = 0;
+       ++sel_inuse;
+       if (sel_top < (sp - sel) + 1)
+               sel_top = (sp - sel) + 1;
+       return sp;
+}
+
+/*
+ * close (and thus clear down) a slot, it is assumed that you have done whatever
+ * you need to do to close the actual device already
+ */
+
+void sel_close(sel_t *sp)
+{
+       if (sp->sort) {
+               chain_flush(sp->msgbase);
+               free(sp->msgbase);
+               free(sp->name);
+               memset(sp, 0, sizeof(sel_t));
+               if (sel_top == (sp - sel) + 1)
+                       --sel_top;
+               --sel_inuse;
+       }
+}
+
+/*
+ * this actually runs the (de)multiplexor, it simply listens to the various cnums 
+ * presents the events to the handler which has to deal with them
+ */
+
+void sel_run()
+{
+       int i, r, max = 0;
+       struct timeval tv;
+       fd_set infd;
+       fd_set outfd;
+       fd_set errfd;
+       sel_t *sp;
+       
+       /* first set up the parameters for the select according to the slots registered */
+       FD_ZERO(&infd);
+       FD_ZERO(&outfd);
+       FD_ZERO(&errfd);
+       tv = sel_tv;
+       
+       for (i = 0; i < sel_top; ++i) {
+               sp = &sel[i];
+               if (sp->sort && !sp->err) {
+                       if (sp->flags & SEL_INPUT)
+                               FD_SET(sp->cnum, &infd);
+                       if (sp->flags & SEL_OUTPUT)
+                               FD_SET(sp->cnum, &outfd);
+                       if (sp->flags & SEL_ERROR)
+                               FD_SET(sp->cnum, &errfd);
+                       if (sp->cnum > max)
+                               max = sp->cnum;
+               }
+       }
+       
+       /* now do the select */
+       r = select(max + 1, &infd, &outfd, &errfd, &tv);
+
+       if (r < 0) {
+               if (errno != EINTR)
+                       die("Error during select (%d)", errno);
+               return;
+       }
+
+       /* if there is anything to do, pass it on to the appropriate handler */
+       if (r > 0) {
+               int in, out, err;
+               int hr;
+               
+               for (i = 0; i < sel_top; ++i) {
+                       sp = &sel[i];
+                       if (sp->sort) {
+                               in = FD_ISSET(sp->cnum, &infd);
+                               out = FD_ISSET(sp->cnum, &outfd);
+                               err = FD_ISSET(sp->cnum, &errfd);
+                               if (in || out || err) {
+                                       hr = (sp->handler)(sp, in, out, err);
+                                       
+                                       /* if this is positive, close this selector */
+                                       if (hr)
+                                               sel_close(sp);
+                                       else {
+                                               FD_CLR(sp->cnum, &infd);
+                                               FD_CLR(sp->cnum, &outfd);
+                                               FD_CLR(sp->cnum, &errfd);
+                                       }
+                               }
+                       }
+               }
+       }
+       
+       time(&sel_systime);                                /* note the time, for general purpuse use */
+}
+
+/*
+ * get/set error flag - -1 simply gets the flag, 0 or 1 sets the flag
+ * 
+ * in all cases the old setting of the flag is returned
+ */
+
+int sel_error(sel_t *sp, int err)
+{
+       int r = sp->err;
+       if (err >= 0)
+               sp->err = err;
+       return err;
+}
+
+/*
+ * $Log$
+ * Revision 1.1  2000-03-26 00:03:30  djk
+ * first cut of client
+ *
+ * Revision 1.3  1998/01/02 19:39:59  djk
+ * made various changes to cope with glibc
+ * fixed problem with extended status in etsi_router
+ *
+ * Revision 1.2  1997/06/18 18:44:31  djk
+ * A working hayes implementation!
+ *
+ * Revision 1.1  1997/01/28 16:14:38  djk
+ * moved these into lib as general routines to use with sel
+ *
+ * Revision 1.3  1997/01/15 21:23:26  djk
+ * fixed a few minor svlp problems and added the router logging system
+ *
+ * Revision 1.2  1997/01/13 23:34:56  djk
+ * The first working test version of smsd
+ *
+ * Revision 1.1  1997/01/03 23:44:31  djk
+ * initial workings
+ *
+ *
+ */
diff --git a/src/sel.h b/src/sel.h
new file mode 100755 (executable)
index 0000000..664a55a
--- /dev/null
+++ b/src/sel.h
@@ -0,0 +1,83 @@
+/*
+ * sel.c
+ * 
+ * util routines for do the various select activities
+ * 
+ * Copyright 1996 (c) D-J Koopman
+ * 
+ * $Header$
+ * 
+ * $Log$
+ * Revision 1.1  2000-03-26 00:03:30  djk
+ * first cut of client
+ *
+ * Revision 1.3  1998/01/02 19:39:57  djk
+ * made various changes to cope with glibc
+ * fixed problem with extended status in etsi_router
+ *
+ * Revision 1.2  1997/06/18 18:44:31  djk
+ * A working hayes implementation!
+ *
+ * Revision 1.1  1997/01/28 16:14:23  djk
+ * moved these into lib as general routines to use with sel
+ *
+ * Revision 1.3  1997/01/20 22:30:31  djk
+ * Added modem connection for incoming SMS messages
+ * Added stats message
+ * Added multipack
+ *
+ * Revision 1.2  1997/01/13 23:34:56  djk
+ * The first working test version of smsd
+ *
+ * Revision 1.1  1997/01/03 23:44:31  djk
+ * initial workings
+ *
+ *
+ */
+
+#ifndef _SEL_H
+#define _SEL_H
+
+static char _sel_h_rcsid[] = "$Id$";
+
+#include "chain.h"
+
+typedef struct {
+       int cnum;                                                  /* from open */
+       short err;                                                 /* error flag, to delay closing if required */
+       short sort;                                                /* this thing's sort */
+       short flags;                                               /* fdset flags */
+       char *name;                                                /* device name */
+       void *fcb;                                                 /* any fcb associated with this thing */
+       reft *msgbase;                                     /* any messages for this port */
+       int (*handler)();                                  /* the handler for this thingy */
+} sel_t;
+
+extern sel_t *sel;
+extern int sel_max;
+extern int sel_top;
+extern int sel_inuse;
+extern time_t sel_systime;
+extern struct timeval sel_tv;
+
+#define SEL_INPUT 1
+#define SEL_OUTPUT 2
+#define SEL_ERROR 4
+#define SEL_IOALL 7
+
+#define SEL_ETSI 1
+#define SEL_RMIP 2
+#define SEL_SVLP 3
+#define SEL_TCP 4
+#define SEL_X28 5
+#define SEL_STDIO 6
+#define SEL_DIALDLE 7
+#define SEL_NOKIA 8
+
+void sel_init(int, long, long);                                           /* initialise the select thing */
+void sel_run();                                                   /* run the select multiplexor */
+sel_t *sel_open(int, void *, char *, int (*)(), int, int);/*  initialise a slot */
+void sel_close(sel_t *);
+int sel_error(sel_t *, int);              /* set/clear error flag */
+
+#endif