V8/usr/sys/chncp/chstream.c
#include "../chunix/chsys.h"
#include "../chunix/chconf.h"
#include "../chaos/chaos.h"
/*
* This file contains code for a stream level (as opposed to packet level)
* interface to the chaosnet. It is written to be general enough to fit into
* various systems where such an interface in desirable. This has been the
* case both in UNIX and in FEZ, although UNIX also needs its own "tty"
* interface.
*
* Several macros must be supplied in chsys.h(they can do nothing of course):
* LOCK, UNLOCK - mask out chaos interrupts (send, receive, clock)
* NOINPUT - a LOCK'd hook for indicating that there is no input
* available on a channel (used in FEZ...)
* NOOUTPUT - a hook for indicating when no output is possible
* (window is full) (unused in UNIX, used in FEZ...)
* CHRCOPY - read copy routine (from, to, count) which should
* return the (to) ptr after copying is done.
* CHWCOPY - write copy routine (from, to, count) like CHRCOPY
*/
/*
* Stream read routine - given connection, ptr and number of chars
* As many of the desired characters are transferred as are available
* in the received packet list. If any have been read, the number
* transferred is return. If none were transferred then if
* an EOF has been encountered, CHEOF is returned, otherwise if the
* connection is still open, zero is returned, otherwise CHERROR is
* returned (connection no longer open).
* Note that answer (ANSOP) packets read just like data at act like
* an EOF was encountered after the ANSOP.
* UNCOP (uncontrolled data) packets are treated just like data packets.
* An EOF packet just terminates a read that has made some progress
* and is specifically indicated (by zero chars read) in the next read
* call. After this indication a bit (CHEOFSEEN) is set which causes
* end-of-file indications to be read as long as the connection
* is open. If more data packets arrive, this bit is turned off.
*/
ch_sread(conn, ptr, nchars)
register struct connection *conn;
char *ptr;
unsigned nchars;
{
register struct packet *pkt;
register unsigned count;
unsigned ntodo = nchars;
while (ntodo != 0 && (pkt = conn->cn_rhead) != NOPKT)
switch(pkt->pk_op) {
case EOFOP:
if (ntodo != nchars)
return(nchars - ntodo);
LOCK;
ch_read(conn); /* consume it */
ch_sts(conn); /* ensure immediately ack */
UNLOCK;
conn->cn_flags |= CHEOFSEEN;
return (CHEOF);
default:
if (!ISDATOP(pkt)) {
LOCK;
ch_read(conn);
UNLOCK;
break;
}
/* Fall into... */
case ANSOP:
case UNCOP:
conn->cn_flags &= ~CHEOFSEEN;
count = pkt->pk_len >= ntodo ? ntodo : pkt->pk_len;
ptr = CHRCOPY(&pkt->pk_cdata[conn->cn_roffset], ptr, count);
ntodo -= count;
if ((pkt->pk_len -= count) == 0) {
LOCK;
ch_read(conn);
UNLOCK;
conn->cn_roffset = 0;
if (pkt->pk_op == ANSOP)
conn->cn_flags |= CHEOFSEEN;
} else
conn->cn_roffset += count;
}
if (ntodo != 0) {
LOCK;
NOINPUT(conn);
UNLOCK;
}
return (ntodo != nchars ? nchars - ntodo :
conn->cn_flags & CHEOFSEEN ? CHEOF :
conn->cn_state == CSOPEN ? 0 : CHERROR);
}
/*
* Stream write routine - given connection, ptr and number of characters
* Characters are written until exhausted or until the window is full.
* The number of characters not read is returned, unless this connection
* closes, in which case CHERROR is returned. If no buffers are avaiable
* (presumably a temporary condition), CHTEMP is returned.
* ANS packets are sent if the flag is set.
*/
ch_swrite(conn, ptr, nchars)
register struct connection *conn;
char *ptr;
unsigned nchars;
{
register struct packet *pkt;
register unsigned count;
unsigned ntodo = nchars;
LOCK;
for (;;) {
if (conn->cn_state != CSOPEN &&
(conn->cn_state != CSRFCRCVD ||
(conn->cn_flags & CHANSWER) == 0)) {
UNLOCK;
return CHERROR;
}
if (ntodo == 0 || chtfull(conn))
break;
if ((pkt = conn->cn_toutput) == NOPKT) {
UNLOCK;
if ((pkt = pkalloc(CHMAXDATA, 0)) == NOPKT)
return (ntodo == nchars ? CHTEMP :
nchars - ntodo);
pkt->pk_op = conn->cn_flags & CHANSWER ? ANSOP : DATOP;
pkt->pk_lenword = 0;
conn->cn_troom = CHMAXDATA;
} else {
conn->cn_toutput = NOPKT;
UNLOCK;
}
count = ntodo > conn->cn_troom ? conn->cn_troom : ntodo;
ptr = CHWCOPY(ptr, &pkt->pk_cdata[pkt->pk_len], count);
pkt->pk_lenword += count;
ntodo -= count;
LOCK;
if ((conn->cn_troom -= count) == 0) {
if (ch_write(conn, pkt))
return CHERROR;
} else {
conn->cn_toutput = pkt;
pkt->pk_time = Chclock;
}
}
if (ntodo != 0)
NOOUTPUT(conn);
UNLOCK;
return(nchars - ntodo);
}
/*
* Output flush routine - release the currently-being-filled packet for
* transmission immediately.
* Called at high priority.
* If output window is full, CHTEMP is returned.
* If connection is not open, CHERROR is returned from ch_write.
*/
ch_sflush(conn)
register struct connection *conn;
{
register struct packet *pkt;
if ((pkt = conn->cn_toutput) != NOPKT)
if (chtfull(conn))
return CHTEMP;
else {
conn->cn_toutput = NOPKT;
return ch_write(conn, pkt);
}
return 0;
}