u-isdn/isdn_4/stream.c

351 lines
7.2 KiB
C

/*
* This file is part of the ISDN master program.
*
* Copyright (C) 1995 Matthias Urlichs.
* See the file COPYING for license details.
*/
#include "master.h"
#include <sys/uio.h>
void
read_info (void)
{
streamchar x[MAXLINE];
int len;
if ((len = read (fileno (stdin), x, sizeof (x) - 1)) <= 0)
xquit ("Read", "HL");
x[len] = '\0';
do_info (x, len);
}
void
read_data ()
{
struct _isdn23_hdr hdr;
int err;
#ifdef DO_DEBUGGING
static struct _isdn23_hdr oldhdr;
static
#endif
uchar_t dbuf[MAXLINE];
int len = 0;
int iovlen = 1;
struct iovec io[2];
#define xREAD(what) \
do { \
int xlen = hdr.hdr_##what.len; \
uchar_t *dbufp = dbuf; \
if (xlen == 0) \
break; \
if (xlen >= sizeof(dbuf)) { \
syslog(LOG_ERR,"Header %d: Len %d",hdr.key,hdr.hdr_##what.len); \
dumpaschex((u_char *)&hdr,sizeof(hdr)); \
xquit(NULL,NULL); \
} \
while((err = read(fd_mon,dbufp,xlen)) > 0) { \
len += err; \
dbufp += err; \
xlen -= err; \
if (xlen <= 0) \
break; \
} \
if (err < 0) \
xquit("Err Header Read",NULL); \
else if (err == 0) \
xquit("EOF Header Read",NULL); \
} while(0);
if ((err = read (fd_mon, &hdr, sizeof (hdr))) != sizeof (hdr)) {
if (err < 0)
xquit ("Read Header", NULL);
syslog (LOG_ERR, "Header: len is %d, got %d", sizeof (hdr), err);
xquit (NULL, NULL);
}
switch (hdr.key) {
default:
syslog (LOG_ERR, "Unknown header ID %d", hdr.key);
xquit (NULL, NULL);
case HDR_ATCMD:
xREAD (atcmd);
break;
case HDR_PROTOCMD:
xREAD (protocmd);
break;
case HDR_XDATA:
xREAD (xdata);
break;
case HDR_DATA:
xREAD (data);
break;
case HDR_UIDATA:
xREAD (uidata);
break;
case HDR_LOAD:
xREAD (load);
break;
case HDR_RAWDATA:
xREAD (rawdata);
break;
case HDR_OPEN:
break;
case HDR_CLOSE:
break;
case HDR_ATTACH:
break;
case HDR_DETACH:
break;
case HDR_CARD:
break;
case HDR_NOCARD:
break;
case HDR_OPENPROT:
break;
case HDR_CLOSEPROT:
break;
case HDR_NOTIFY:
break;
case HDR_TEI:
break;
case HDR_INVAL:
if ((err = read (fd_mon, dbuf, sizeof (hdr))) != sizeof (hdr)) {
if (err < 0)
xquit ("Read InvHeader", NULL);
syslog (LOG_ERR, "InvHeader: len is %d, got %d", sizeof (hdr), err);
xquit (NULL, NULL);
}
len = sizeof (hdr);
break;
}
/* dump_hdr(&hdr,"Read 2->3",dbuf); */
#ifdef DO_DEBUGGING
oldhdr = hdr;
#endif
io[0].iov_base = (caddr_t) & hdr;
io[0].iov_len = sizeof (struct _isdn23_hdr);
if (len > 0) {
io[1].iov_base = (caddr_t) dbuf;
io[1].iov_len = len;
iovlen = 2;
}
strwritev (xs_mon, io, iovlen, 0);
}
static int backtimeout;
static void backtime(void *nix) {
backtimeout = 1;
}
/* Do something until fd becomes active or timeout */
/* Also process alerts */
/* fd==-1: one-shot */
/* fd==-2: continuous loop */
int
backrun (int fd, int timeo)
{
int err;
fd_set rdx;
if(!testonly && !FD_ISSET(fd_mon,&rd))
xquit("RD fd_set cleared",NULL);
backtimeout = 0;
if(timeo > 0)
timeout(backtime,NULL,timeo);
do {
struct timeval now = {0, 0};
rdx = rd;
runqueues (); deadkid(); runqueues ();
MALLOC_IDLE();
if(fd >= 0) FD_SET(fd,&rdx);
err = select (FD_SETSIZE, &rdx, NULL, NULL, &now);
if (err == 0 || (err < 0 && errno == EINTR)) {
rdx = rd;
if(fd >= 0) FD_SET(fd,&rdx);
if(fd == -1) goto endit;
if(fd < 0) callout_adjtimeout ();
err = select (FD_SETSIZE, &rdx, NULL, NULL, (fd < 0 && callout_hastimer ())? &callout_time : NULL);
}
runqueues(); runqueues();
if (err <= 0) {
if (err < 0 && errno != EINTR)
xquit ("Select", NULL);
callout_alarm ();
if(backtimeout)
break;
else
continue;
}
if (!testonly && FD_ISSET (fd_mon, &rdx))
read_data ();
if (FD_ISSET (fileno (stdin), &rdx))
read_info ();
runqueues(); runqueues();
} while((fd >= 0) ? !FD_ISSET(fd,&rdx) : has_progs());
endit:
if(timeo && !backtimeout)
untimeout(backtime,NULL);
runqueues(); runqueues();
return backtimeout;
}
/* Main Program Loop */
void
syspoll (void)
{
FD_ZERO (&rd);
if (!testonly)
FD_SET (fd_mon, &rd);
if (!igstdin)
FD_SET (fileno (stdin), &rd);
while (has_progs())
backrun(-2,0);
}
/* Upper stream read */
void
do_h (queue_t * q)
{
uchar_t data[MAXLINE];
int len = sizeof (data) - 1;
int err;
while ((err = strread (xs_mon, (streamchar *) data, len, 1)) > 0) {
do_info (data, err);
len = sizeof (data) - 1;
}
if (err < 0) {
errno = -err;
syslog (LOG_ERR, "Read H: %m");
}
q->q_flag |= QWANTR;
}
/* from Linux libc:sysdeps/linux/writev.c */
/* This is necessary because we need to write a partitioned Streams message
as one block, not as several. Linux however doesn't really implement
readv/writev yet. The extra copy doesn't hurt much, fortunately, except
when loading binary data down, and that's a temporary problem. */
static int
xwritev(int fd,struct iovec *vector, size_t count)
{
char *buffer;
register char *bp;
size_t bytes, to_copy;
register size_t i;
/* Find the total number of bytes to be written. */
bytes = 0;
for (i = 0; i < count; ++i)
bytes += vector[i].iov_len;
if (bytes == 0)
return 0;
/* Allocate a temporary buffer to hold the data. */
buffer = (char *) __alloca(bytes);
/* Copy the data into BUFFER. */
to_copy = bytes;
bp = buffer;
for (i = 0; i < count; ++i)
{
#define min(a, b) ((a) > (b) ? (b) : (a))
size_t copy = min(vector[i].iov_len, to_copy);
(void) memcpy(bp, vector[i].iov_base, copy);
bp += copy;
to_copy -= copy;
if (bytes == 0)
break;
}
return write(fd, buffer, bytes);
}
/* Lower stream read */
void
do_l (queue_t * q)
{
struct _isdn23_hdr h;
int err;
uchar_t data[MAXLINE];
while (1) {
struct iovec io[3];
int iovlen = 1;
if ((err = strread (xs_mon, (streamchar *) &h, sizeof (struct _isdn23_hdr), 0)) == sizeof (struct _isdn23_hdr))
;
else
break;
io[0].iov_base = (caddr_t) & h;
io[0].iov_len = sizeof (struct _isdn23_hdr);
switch (h.key) {
default:
break;
case HDR_ATCMD:
case HDR_XDATA:
case HDR_RAWDATA:
case HDR_DATA:
case HDR_UIDATA:
case HDR_PROTOCMD:
case HDR_LOAD:
io[iovlen].iov_base = (caddr_t) data;
io[iovlen].iov_len = h.hdr_atcmd.len;
if ((err = strread (xs_mon, (streamchar *) data, h.hdr_atcmd.len, 0)) != h.hdr_atcmd.len) {
syslog (LOG_ERR, "do_l: Fault, %d, %m", err);
goto exhopp;
}
io[iovlen].iov_base = (caddr_t) data;
io[iovlen].iov_len = err;
iovlen++;
break;
case HDR_INVAL:
io[iovlen].iov_base = (caddr_t) data;
io[iovlen].iov_len = sizeof (struct _isdn23_hdr);
if ((err = strread (xs_mon, (streamchar *) data, sizeof (struct _isdn23_hdr), 0)) != sizeof (struct _isdn23_hdr)) {
syslog (LOG_ERR, "do_l: Fault, %m");
goto exhopp;
}
iovlen++;
break;
}
/*
* dump_hdr(&h,testonly ? "Write <-3" : "Write 2<-3",(uchar_t
* *)io[1].iov_base);
*/
if (testonly)
err = 0;
else {
if (((char *)(io[0].iov_base))[0] == 0x3F)
abort ();
err = xwritev (fd_mon, io, iovlen);
}
}
if (err < 0) {
errno = -err;
syslog (LOG_ERR, "Read L: %m");
}
exhopp:
q->q_flag |= QWANTR;
}