first cut of client

This commit is contained in:
djk 2000-03-26 00:03:30 +00:00
parent a6d0720c82
commit 8804833a62
8 changed files with 1319 additions and 0 deletions

11
src/Makefile Normal file
View File

@ -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)

222
src/chain.c Executable file
View File

@ -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;
}

28
src/chain.h Executable file
View File

@ -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

463
src/client.c Normal file
View File

@ -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);
}

226
src/cmsg.c Executable file
View File

@ -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
*
*/

72
src/cmsg.h Executable file
View File

@ -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

214
src/sel.c Executable file
View File

@ -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
*
*
*/

83
src/sel.h Executable file
View File

@ -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