From: djk Date: Sun, 26 Mar 2000 00:03:30 +0000 (+0000) Subject: first cut of client X-Git-Tag: R_1_39~14 X-Git-Url: http://dxcluster.net/gitweb/gitweb.cgi?a=commitdiff_plain;h=8804833a62667fe6a33655351790b241256e5980;p=spider.git first cut of client --- diff --git a/src/Makefile b/src/Makefile new file mode 100644 index 00000000..09d68645 --- /dev/null +++ b/src/Makefile @@ -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 index 00000000..4e36b3ed --- /dev/null +++ b/src/chain.c @@ -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 + +/* 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 index 00000000..b4e63783 --- /dev/null +++ b/src/chain.h @@ -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 index 00000000..640c2b44 --- /dev/null +++ b/src/client.c @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 index 00000000..1b325b58 --- /dev/null +++ b/src/cmsg.c @@ -0,0 +1,226 @@ +/* + * cmsg.c + * + * create and free message buffers + * + * Copyright 1996 (c) D-J Koopman + * + * $Header$ + */ + + +static char rcsid[] = "$Id$"; + +#include +#include + +#include "chain.h" +#include "cmsg.h" + +long cmsg_count = 0; + +#ifdef DB_CMSG +#include +#include + + +#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 index 00000000..384b90f7 --- /dev/null +++ b/src/cmsg.h @@ -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 + +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 index 00000000..2d8972f2 --- /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 +#include +#include +#include +#include +#include +#include + +#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 index 00000000..664a55a8 --- /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