V10/sys/io/mesg.c
/*
* message processor-- written data turns into control, read control
* turns into data
* rmesg is just the opposite
*/
#include "sys/param.h"
#include "sys/stream.h"
#include "sys/conf.h"
#include "sys/mesg.h"
#define MS_OPEN 01
#define MS_DEL 02
#define MS_STOP 010
#define MS_IOCTL 020
struct block *msgcollect();
int msctodput(), msctodsrv(), msdtocput(), msdtocsrv(),
msgclose(), rmsgclose();
long msgopen(), rmsgopen();
struct qinit msgrinit = { msctodput, msctodsrv, msgopen, msgclose, 128, 65 };
struct qinit msgwinit = { msdtocput, msdtocsrv, msgopen, msgclose, 128, 65 };
struct streamtab msgstream = { &msgrinit, &msgwinit };
struct qinit rmsgrinit = { msdtocput, msdtocsrv, rmsgopen, rmsgclose, 128, 65 };
struct qinit rmsgwinit = { msctodput, msctodsrv, rmsgopen, rmsgclose, 128, 65 };
struct streamtab rmsgstream = { &rmsgrinit, &rmsgwinit };
extern struct imesg mesg[];
extern int msgcnt;
long
msgopen(q, dev)
register struct queue *q;
{
register struct imesg *mp;
register int i;
if (WR(q)->ptr)
return(1);
for (mp = mesg, i = msgcnt; mp->msflag&MS_OPEN; mp++, i--)
if (i <= 0)
return (0);
mp->msflag = MS_OPEN|MS_DEL;
mp->size = 0;
WR(q)->ptr = (caddr_t)mp;
WR(q)->flag |= QNOENB|QBIGB;
q->flag |= QDELIM;
return(1);
}
long
rmsgopen(q, dev)
register struct queue *q;
{
register struct imesg *mp;
register int i;
if (q->ptr)
return(1);
for (mp = mesg, i = msgcnt; mp->msflag&MS_OPEN; mp++, i--)
if (i <= 0)
return(0);
mp->msflag = MS_OPEN|MS_DEL;
mp->size = 0;
q->ptr = (caddr_t)mp;
WR(q)->flag |= QBIGB;
q->flag |= QDELIM|QNOENB;
return(1);
}
msgclose(q)
register struct queue *q;
{
msgbclose((struct imesg *)WR(q)->ptr);
}
rmsgclose(q)
register struct queue *q;
{
msgbclose((struct imesg *)q->ptr);
}
msgbclose(p)
register struct imesg *p;
{
if (p==NULL)
return;
p->msflag = 0;
if (p->saveb)
freeb(p->saveb);
p->saveb = NULL;
}
msctodput(q, bp)
register struct queue *q;
register struct block *bp;
{
register struct imesg *mp = (struct imesg *)(OTHERQ(q)->ptr);
register struct queue *bq = backq(q);
/* propagate changes in delimiter status */
if (mp->msflag&MS_DEL) {
if ((bq->flag&QDELIM) == 0) {
mp->msflag &= ~MS_DEL;
putctl(q, M_NDEL);
}
} else {
if (bq->flag&QDELIM) {
mp->msflag |= MS_DEL;
putctl(q, M_YDEL);
}
}
if (bp->type==M_STOP) {
freeb(bp);
mp->msflag |= MS_STOP;
return;
}
if (bp->type>=QPCTL) { /* including M_START */
if (bp->type==M_START)
freeb(bp);
else {
/* ioctl transparency */
if (mp->msflag & MS_IOCTL
&& (bp->type==M_IOCACK || bp->type==M_IOCNAK)) {
(*q->next->qinfo->putp)(q->next, bp);
mp->msflag &=~ MS_IOCTL;
return;
}
putq(q, bp);
}
mp->msflag &=~ MS_STOP;
qenable(q);
return;
}
putq(q, bp);
return;
}
msctodsrv(q)
register struct queue *q;
{
register struct block *bp, *hbp;
register struct imesg *mp = (struct imesg *)OTHERQ(q)->ptr;
register type;
register size, d;
for (;;) {
if (q->next->flag & QFULL || mp->msflag & MS_STOP)
return;
if ((bp = getq(q)) == NULL)
return;
if ((hbp = allocb(MSGHLEN)) == NULL) {
putbq(q, bp);
return;
}
((struct mesg *)(hbp->wptr))->magic = MSGMAGIC;
((struct mesg *)(hbp->wptr))->type = type = bp->type;
size = bp->wptr - bp->rptr;
((struct mesg *)(hbp->wptr))->losize = size;
((struct mesg *)(hbp->wptr))->hisize = size>>8;
hbp->wptr += MSGHLEN;
(*q->next->qinfo->putp)(q->next, hbp);
bp->type = M_DATA;
d = bp->class & S_DELIM;
bp->class |= S_DELIM;
(*q->next->qinfo->putp)(q->next, bp);
if (d) {
if ((hbp = allocb(MSGHLEN)) == NULL)
return;
((struct mesg *)(hbp->wptr))->magic = MSGMAGIC;
((struct mesg *)(hbp->wptr))->type = M_DELIM;
((struct mesg *)(hbp->wptr))->losize = 0;
((struct mesg *)(hbp->wptr))->hisize = 0;
hbp->wptr += MSGHLEN;
hbp->class |= S_DELIM;
(*q->next->qinfo->putp)(q->next, hbp);
}
if (type == M_HANGUP)
putctl(q->next, M_HANGUP);
}
}
msdtocput(q, bp)
register struct queue *q;
register struct block *bp;
{
switch (bp->type) {
default:
freeb(bp);
return;
case M_FLUSH:
flushq(OTHERQ(q), 1);
case M_IOCACK:
case M_IOCNAK:
case M_HANGUP:
(*q->next->qinfo->putp)(q->next, bp);
return;
case M_DATA:
case M_IOCTL:
putq(q, bp);
qenable(q);
return;
}
}
msdtocsrv(q)
register struct queue *q;
{
register struct block *bp;
register struct imesg *mp = (struct imesg *)q->ptr;
for (;;) {
if (q->next->flag & QFULL)
return;
if (mp->size == 0) { /* Start of message */
bp = msgcollect(q, MSGHLEN, 0, 1);
if (bp == NULL)
return;
mp->size = ((struct mesg *)bp->rptr)->losize;
mp->size += ((struct mesg *)bp->rptr)->hisize<<8;
mp->type = ((struct mesg *)bp->rptr)->type;
/* magic ok; was checked in msgcollect */
if (mp->type == M_PASS)
mp->type = M_DATA;
if (mp->size < 0)
mp->size = 0;
if (mp->size==0) {
bp->type = mp->type;
bp->rptr = bp->wptr;
if (bp->type==M_DELIM) {
if (mp->saveb) {
freeb(bp);
bp = mp->saveb;
mp->saveb = NULL;
bp->class |= S_DELIM;
}
bp->type = M_DATA;
bp->class |= S_DELIM;
} else if (bp->type==M_YDEL)
q->flag |= QDELIM;
else if (bp->type==M_NDEL)
q->flag &= ~QDELIM;
(*q->next->qinfo->putp)(q->next, bp);
continue;
}
freeb(bp);
}
bp = msgcollect(q, mp->size, mp->type == M_DATA, 0);
if (bp == NULL)
return;
if (mp->saveb) {
(*q->next->qinfo->putp)(q->next, mp->saveb);
mp->saveb = NULL;
}
bp->type = mp->type;
if (bp->type == M_DELIM) { /* delim messages back to data */
bp->type = M_DATA;
bp->class |= S_DELIM;
}
mp->size -= bp->wptr - bp->rptr;
if (bp->type==M_DATA && (bp->class&S_DELIM)==0 && q->flag&QDELIM)
mp->saveb = bp;
else
(*q->next->qinfo->putp)(q->next, bp);
}
}
long ms_badmag;
struct block *
msgcollect(q, size, isdata, findmag)
register struct queue *q;
{
register struct block *nbp, *bp;
register ninb;
register struct imesg *mp = (struct imesg *)q->ptr;
if (findmag == 0) {
if ((bp = getq(q)) == NULL)
return (NULL);
}
else {
while ((bp = getq(q)) != NULL) {
if (bp->type != M_DATA) {
/* prevent the ack from being turned to data */
if (bp->type==M_IOCTL)
mp->msflag |= MS_IOCTL;
(*q->next->qinfo->putp)(q->next, bp);
continue;
}
while (bp->rptr < bp->wptr-1) {
if (bp->rptr[1] == MSGMAGIC)
goto gotmagic;
bp->rptr++;
ms_badmag++;
}
freeb(bp);
}
if (bp == NULL)
return (NULL);
}
gotmagic:
nbp = allocb(size);
if (nbp == NULL) {
putbq(q, bp);
return(NULL);
}
if (size > nbp->lim - nbp->wptr)
size = nbp->lim - nbp->wptr;
while (size) {
if (bp->type != M_DATA) {
/* prevent the ack from being turned to data */
if (bp->type==M_IOCTL)
mp->msflag |= MS_IOCTL;
(*q->next->qinfo->putp)(q->next, bp);
if ((bp = getq(q)) == NULL)
break;
continue;
}
ninb = bp->wptr - bp->rptr;
if (ninb > size) {
bcopy((caddr_t)bp->rptr, (caddr_t)nbp->wptr, size);
nbp->wptr += size;
bp->rptr += size;
size = 0;
putbq(q, bp);
break;
}
bcopy((caddr_t)bp->rptr, (caddr_t)nbp->wptr, ninb);
size -= ninb;
nbp->wptr += ninb;
freeb(bp);
if (size == 0)
break;
if ((bp = getq(q)) == NULL)
break;
}
if (nbp->rptr >= nbp->wptr) {
freeb(nbp);
return(NULL);
}
if (size==0 || isdata)
return(nbp);
putbq(q, nbp);
return(NULL);
}