--- /dev/null
+#
+# 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
--- /dev/null
+/*
+ * 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;
+}
+
--- /dev/null
+
+/*
+ * 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
--- /dev/null
+/*
+ * 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);
+}
+
+
+
+
+
--- /dev/null
+/*
+ * 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
+ *
+ */
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
+ *
+ *
+ */
--- /dev/null
+/*
+ * 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