/* begincopyright Copyright (c) 1988, 1989 Xerox Corporation. All rights reserved. Use and copying of this software and preparation of derivative works based upon this software are permitted. Any distribution of this software or derivative works must comply with all applicable United States export control laws. This software is made available AS IS, and Xerox Corporation makes no warranty about the software, its performance or its conformity to any specification. Any person obtaining a copy of this software is requested to send their name and post office or electronic mail address to: PCR Coordinator Xerox PARC 3333 Coyote Hill Rd. Palo Alto, CA endcopyright */ /* * ThreadsTLI.c * * Tim Diebert: November 21, 1989 5:59:51 pm PST * Michael Plass: February 18, 1992 9:51:11 am PST * * This module provides an interface to the Mentat XNS implementation * via the AT&T TLI interfaces. This code started life looking * suprisingly like the AT&T stuff except that it maintains no global * state. * */ #include <ThreadsTLI.h> #include <xr/UIO.h> #include <xr/Errno.h> #include <sys/fcntl.h> #include <sys/param.h> /* would you believe NULL is in here */ #include <sys/stream.h> /* queue←t */ #include <sys/stropts.h> /* stream ioctl things */ #include <sys/tihdr.h> #include <nettli/timod.h> /* #include <nettli/tiuser.h> included in ThreadsTLI.h */ #define DEFSIZE 2048 extern XR←Pointer GC←malloc(); /* Open and Close */ int XR←T←Open(cd, path, flags, info) struct conn←data * cd; char * path; int flags; register struct t←info * info; { int retval; struct T←info←ack inforeq; int retlen; /* Open up the device. In the case of the Mentat XNS path should be * /dev/xr */ if ((cd->cd←fd = XR←OpenStream(path, flags)) < 0) { cd->cd←errno = TSYSERR; return(-1); } /* * is module already pushed ? */ if ((retval = XR←IOCtl(cd->cd←fd, I←FIND, "timod")) < 0) { cd->cd←errno = TSYSERR; XR←Close(cd->cd←fd); return(-1); } if (!retval) if (XR←IOCtl(cd->cd←fd, I←PUSH, "timod") < 0) { cd->cd←errno = TSYSERR; XR←Close(cd->cd←fd); return(-1); } inforeq.PRIM←type = T←INFO←REQ; if (!DoTIModIOCtl(cd, (caddr←t)&inforeq, sizeof(struct T←info←req), TI←GETINFO, &retlen)) { XR←Close(cd->cd←fd); return(-1); } if (retlen != sizeof(struct T←info←ack)) { cd->cd←errno = TSYSERR; XR←SetErrno(EIO); XR←Close(cd->cd←fd); return(-1); } cd->cd←info.addr = inforeq.ADDR←size; cd->cd←info.options = inforeq.OPT←size; cd->cd←info.tsdu = inforeq.TSDU←size; cd->cd←info.etsdu = inforeq.ETSDU←size; cd->cd←info.connect = inforeq.CDATA←size; cd->cd←info.discon = inforeq.DDATA←size; cd->cd←info.servtype = inforeq.SERV←type; if (info != NULL) { info->addr = inforeq.ADDR←size; info->options = inforeq.OPT←size; info->tsdu = inforeq.TSDU←size; info->etsdu = inforeq.ETSDU←size; info->connect = inforeq.CDATA←size; info->discon = inforeq.DDATA←size; info->servtype = inforeq.SERV←type; } /* * initialize data structure and allocate buffers if needed */ if (!(cd->cd←flags & USED)) { if (AllocateBuffers(cd, inforeq) < 0){ XR←T←Close(cd); cd->cd←errno = TSYSERR; return(-1); } if(XR←IOCtl(cd->cd←fd, I←FLUSH, 3L) < 0) { XR←T←Close(cd); cd->cd←errno = TSYSERR; return(-1); } cd->cd←flags = cd->cd←flags | USED; } return(cd->cd←fd); } int XR←T←Close(cd) struct conn←data * cd; { if (CheckCD(cd)) return(-1); /* don't release the memory, since someone else allocated it. * (void)free(cd->cd←rcvbuf); * (void)free(cd->cd←ctlbuf); * (void)free(cd->cd←lookcbuf); * (void)free(cd->cd←lookdbuf); */ XR←Close(cd->cd←fd); cd->cd←fd = -1; /* mark it as closed */ return(0); } /* Binding */ int XR←T←Bind(cd, req, ret) struct conn←data * cd; register struct t←bind *req; register struct t←bind *ret; { int fd; register char *buf; register struct T←bind←req *ti←bind; int size; if (CheckCD(cd)) return(-1); fd = cd->cd←fd; buf = cd->cd←ctlbuf; ti←bind = (struct T←bind←req *)buf; size = sizeof(struct T←bind←req); ti←bind->PRIM←type = T←BIND←REQ; ti←bind->ADDR←length = (req == NULL? 0: req->addr.len); ti←bind->ADDR←offset = 0; ti←bind->CONIND←number = (req == NULL? 0: req->qlen); if (ti←bind->ADDR←length) { AlignedCopy(buf, (int)ti←bind->ADDR←length, size, req->addr.buf, &ti←bind->ADDR←offset); size = ti←bind->ADDR←offset + ti←bind->ADDR←length; } if (!DoTIModIOCtl(cd, buf, size, TI←BIND, 0L)) { return(-1); } if ((ret != NULL) && (ti←bind->ADDR←length > ret->addr.maxlen)) { cd->cd←errno = TBUFOVFLW; return(-1); } if (ret != NULL) { bcopy((char *)(buf + ti←bind->ADDR←offset), ret->addr.buf, (int)ti←bind->ADDR←length); ret->addr.len = ti←bind->ADDR←length; ret->qlen = ti←bind->CONIND←number; } return(0); } int XR←T←UnBind(cd) struct conn←data * cd; { register struct ←ti←user *tiptr; struct T←unbind←req *unbind←req; if (CheckCD(cd)) return(-1); if (IsEvent(cd->cd←fd, tiptr)) { return(-1); } unbind←req = (struct T←unbind←req *)cd->cd←ctlbuf; unbind←req->PRIM←type = T←UNBIND←REQ; if (!DoTIModIOCtl(cd, (caddr←t)unbind←req, sizeof(struct T←unbind←req), TI←UNBIND, 0)) { return(-1); } if (XR←IOCtl(cd->cd←fd, I←FLUSH, FLUSHRW) < 0) { cd->cd←errno = TSYSERR; return(-1); } /* * clear more data in TSDU bit */ cd->cd←flags &= ~MORE; return(0); } /* Listening */ int XR←T←Listen(cd, call) struct conn←data * cd; struct t←call *call; { struct strbuf ctlbuf; struct strbuf rcvbuf; int flg = 0; int retval; register union T←primitives *pptr; if (CheckCD(cd)) return(-1); /* * check if something in look buffer */ if (cd->cd←lookflg) { cd->cd←errno = TLOOK; return(-1); } if (cd->cd←servtype == T←CLTS) { cd->cd←errno = TNOTSUPPORT; return(-1); } ctlbuf.maxlen = cd->cd←ctlsize; ctlbuf.len = 0; ctlbuf.buf = cd->cd←ctlbuf; rcvbuf.maxlen = cd->cd←rcvsize; rcvbuf.len = 0; rcvbuf.buf = cd->cd←rcvbuf; if ((retval = XR←GetMsg(cd->cd←fd, &ctlbuf, &rcvbuf, &flg)) < 0) { if (XR←GetErrno() == EAGAIN) cd->cd←errno = TNODATA; else cd->cd←errno = TSYSERR; return(-1); } if (rcvbuf.len == -1) rcvbuf.len = 0; /* * did I get entire message? */ if (retval) { cd->cd←errno = TSYSERR; XR←SetErrno(EIO); return(-1); } /* * is ctl part large enough to determine type */ if (ctlbuf.len < sizeof(long)) { cd->cd←errno = TSYSERR; XR←SetErrno(EPROTO); return(-1); } pptr = (union T←primitives *)ctlbuf.buf; switch(pptr->type) { case T←CONN←IND: if ((ctlbuf.len < sizeof(struct T←conn←ind)) || (ctlbuf.len < (pptr->conn←ind.OPT←length + pptr->conn←ind.OPT←offset))) { cd->cd←errno = TSYSERR; XR←SetErrno(EPROTO); return(-1); } if ((rcvbuf.len > (int)call->udata.maxlen) || (pptr->conn←ind.SRC←length > call->addr.maxlen) || (pptr->conn←ind.OPT←length > call->opt.maxlen)) { cd->cd←errno = TBUFOVFLW; return(-1); } bcopy(ctlbuf.buf + pptr->conn←ind.SRC←offset, call->addr.buf, (int)pptr->conn←ind.SRC←length); call->addr.len = pptr->conn←ind.SRC←length; bcopy(ctlbuf.buf + pptr->conn←ind.OPT←offset, call->opt.buf, (int)pptr->conn←ind.OPT←length); call->opt.len = pptr->conn←ind.OPT←length; bcopy(rcvbuf.buf, call->udata.buf, (int)rcvbuf.len); call->udata.len = rcvbuf.len; call->sequence = pptr->conn←ind.SEQ←number; return(0); case T←DISCON←IND: PutBack(cd, rcvbuf.buf, rcvbuf.len, ctlbuf.buf, ctlbuf.len); cd->cd←errno = TLOOK; return(-1); default: break; } cd->cd←errno = TSYSERR; errno = EPROTO; return(-1); } int XR←T←Accept(cd, rescd, call) struct conn←data * cd; struct conn←data * rescd; struct t←call *call; { char *buf; register struct T←conn←res *cres; struct strfdinsert strfdinsert; int size; int retval; int resfd; if (CheckCD(cd)) return(-1); if (CheckCD(rescd)) return(-1); resfd = rescd->cd←fd; if (cd->cd←servtype == T←CLTS) { cd->cd←errno = TNOTSUPPORT; return(-1); } if (cd->cd←fd != resfd) { if ((retval = XR←IOCtl(resfd, I←NREAD, &size)) < 0) { cd->cd←errno = TSYSERR; return(-1); } if (retval) { cd->cd←errno = TBADF; return(-1); } } if (IsEvent(cd)) { return(-1); } buf = cd->cd←ctlbuf; cres = (struct T←conn←res *)buf; cres->PRIM←type = T←CONN←RES; cres->OPT←length = call->opt.len; cres->OPT←offset = 0; cres->SEQ←number = call->sequence; size = sizeof(struct T←conn←res); if (call->opt.len) { AlignedCopy(buf, call->opt.len, size, call->opt.buf, &cres->OPT←offset); size = cres->OPT←offset + cres->OPT←length; } strfdinsert.ctlbuf.maxlen = cd->cd←ctlsize; strfdinsert.ctlbuf.len = size; strfdinsert.ctlbuf.buf = buf; strfdinsert.databuf.maxlen = call->udata.maxlen; strfdinsert.databuf.len = (call->udata.len? call->udata.len: -1); strfdinsert.databuf.buf = call->udata.buf; strfdinsert.fildes = resfd; strfdinsert.offset = sizeof(long); strfdinsert.flags = 0; /* could be EXPEDITED also */ if (XR←IOCtl(cd->cd←fd, I←FDINSERT, &strfdinsert) < 0) { if (XR←GetErrno() == EAGAIN) cd->cd←errno = TFLOW; else cd->cd←errno = TSYSERR; return(-1); } if (!IsOK(cd, (long)T←CONN←RES)) { return(-1); } return(0); } /* State and Info gathering */ int XR←T←GetInfo(cd, info) struct conn←data * cd; register struct t←info *info; { struct T←info←ack inforeq; int retlen; if (CheckCD(cd)) return(-1); inforeq.PRIM←type = T←INFO←REQ; if (!DoTIModIOCtl(cd, (caddr←t)&inforeq, sizeof(struct T←info←req), TI←GETINFO, &retlen)) { return(-1); } if (retlen != sizeof(struct T←info←ack)) { XR←SetErrno(EIO); cd->cd←errno = TSYSERR; return(-1); } info->addr = inforeq.ADDR←size; info->options = inforeq.OPT←size; info->tsdu = inforeq.TSDU←size; info->etsdu = inforeq.ETSDU←size; info->connect = inforeq.CDATA←size; info->discon = inforeq.DDATA←size; info->servtype = inforeq.SERV←type; return(0); } int XR←T←GetState(cd) struct conn←data * cd; { struct T←info←ack info; int retlen; if (CheckCD(cd)) return(-1); info.PRIM←type = T←INFO←REQ; if (!DoTIModIOCtl(cd, (caddr←t)&info, sizeof(struct T←info←req), TI←GETINFO, &retlen)) { return(-1); } if (retlen != sizeof(struct T←info←ack)) { cd->cd←errno = TSYSERR; XR←SetErrno(EIO); return(-1); } switch (info.CURRENT←state) { case TS←UNBND: return(T←UNBND); case TS←IDLE: return(T←IDLE); case TS←WRES←CIND: return(T←INCON); case TS←WCON←CREQ: return(T←OUTCON); case TS←DATA←XFER: return(T←DATAXFER); case TS←WIND←ORDREL: return(T←OUTREL); case TS←WREQ←ORDREL: return(T←INREL); default: cd->cd←errno = TSTATECHNG; return(-1); } } int XR←T←Look(cd) register struct conn←data * cd; { struct strpeek strpeek; int retval; union T←primitives *pptr; long type; if (CheckCD(cd)) return(-1); strpeek.ctlbuf.maxlen = sizeof(long); strpeek.ctlbuf.len = 0; strpeek.ctlbuf.buf = cd->cd←ctlbuf; strpeek.databuf.maxlen = 0; strpeek.databuf.len = 0; strpeek.databuf.buf = NULL; strpeek.flags = 0; if ((retval = XR←IOCtl(cd->cd←fd, I←PEEK, &strpeek)) < 0) return(T←ERROR); /* * if something there and cnt part also there */ if (cd->cd←lookflg || (retval && (strpeek.ctlbuf.len >= sizeof(long)))) { pptr = (union T←primitives *)strpeek.ctlbuf.buf; if (cd->cd←lookflg) { if (((type = *((long *)cd->cd←lookcbuf)) != T←DISCON←IND) && (retval && (pptr->type == T←DISCON←IND))) { type = pptr->type; cd->cd←lookflg = 0; } } else type = pptr->type; switch(type) { case T←CONN←IND: return(T←LISTEN); case T←CONN←CON: return(T←CONNECT); case T←DISCON←IND: return(T←DISCONNECT); case T←DATA←IND: case T←UNITDATA←IND: return(T←DATA); case T←EXDATA←IND: return(T←EXDATA); case T←UDERROR←IND: return(T←UDERR); case T←ORDREL←IND: return(T←ORDREL); default: cd->cd←errno = TSYSERR; XR←SetErrno(EPROTO); return(-1); } } /* * if something there put no control part * it must be data */ if (retval && (strpeek.ctlbuf.len <= 0)) return(T←DATA); /* * if msg there and control * part not large enough to determine type? * it must be illegal TLI message */ if (retval && (strpeek.ctlbuf.len > 0)) { cd->cd←errno = TSYSERR; XR←SetErrno(EPROTO); return(-1); } return(0); } /* Reliable streams */ int XR←T←Connect(cd, sndcall, rcvcall) struct conn←data * cd; struct t←call *sndcall; struct t←call *rcvcall; { int fctlflg; if (CheckCD(cd)) return(-1); if (SendConnectionRequest(cd, sndcall) < 0) return(-1); if ((fctlflg = XR←FCntl(cd->cd←fd, F←GETFL, 0)) < 0) { cd->cd←errno = TSYSERR; return(-1); } if (fctlflg & O←NDELAY) { cd->cd←errno = TNODATA; return(-1); } if (ReceiveConnectionConfirmation(cd, rcvcall) < 0) { return(-1); } return(0); } /* * SendConnectionRequest - send connect request message to * transport provider */ int SendConnectionRequest(cd, call) struct conn←data * cd; register struct t←call *call; { register struct T←conn←req *creq; struct strbuf ctlbuf; char *buf; int size; if (CheckCD(cd)) return(-1); if (cd->cd←servtype == T←CLTS) { cd->cd←errno = TNOTSUPPORT; return(-1); } if (IsEvent(cd)) { return(-1); } buf = cd->cd←ctlbuf; creq = (struct T←conn←req *)buf; creq->PRIM←type = T←CONN←REQ; creq->DEST←length = call->addr.len; creq->DEST←offset = 0L; creq->OPT←length = call->opt.len; creq->OPT←offset = 0L; size = sizeof(struct T←conn←req); if (call->addr.len) { AlignedCopy(buf, call->addr.len, size, call->addr.buf, &creq->DEST←offset); size = creq->DEST←offset + creq->DEST←length; } if (call->opt.len) { AlignedCopy(buf, call->opt.len, size, call->opt.buf, &creq->OPT←offset); size = creq->OPT←offset + creq->OPT←length; } ctlbuf.maxlen = cd->cd←ctlsize; ctlbuf.len = size; ctlbuf.buf = buf; if (XR←PutMsg(cd->cd←fd, &ctlbuf, (call->udata.len? &call->udata: 0L), 0) < 0) { cd->cd←errno = TSYSERR; return(-1); } if (!IsOK(cd, (long)T←CONN←REQ)) { return(-1); } return(0); } /* * ReceiveConnectionConfirmation - get connection confirmation off * of read queue */ int ReceiveConnectionConfirmation(cd, call) struct conn←data * cd; register struct t←call *call; { struct strbuf ctlbuf; struct strbuf rcvbuf; int flg = 0; register union T←primitives *pptr; int retval; if (CheckCD(cd)) return(-1); if (cd->cd←servtype == T←CLTS) { cd->cd←errno = TNOTSUPPORT; return(-1); } /* * see if there is something in look buffer */ if (cd->cd←lookflg) { cd->cd←errno = TLOOK; return(-1); } ctlbuf.maxlen = cd->cd←ctlsize; ctlbuf.len = 0; ctlbuf.buf = cd->cd←ctlbuf; rcvbuf.maxlen = cd->cd←rcvsize; rcvbuf.len = 0; rcvbuf.buf = cd->cd←rcvbuf; if ((retval = XR←GetMsg(cd->cd←fd, &ctlbuf, &rcvbuf, &flg)) < 0) { if (XR←GetErrno() == EAGAIN) cd->cd←errno = TNODATA; else cd->cd←errno = TSYSERR; return(-1); } if (rcvbuf.len == -1) rcvbuf.len = 0; /* * did we get entire message */ if (retval) { cd->cd←errno = TSYSERR; XR←SetErrno(EIO); return(-1); } /* * is cntl part large enough to determine message type? */ if (ctlbuf.len < sizeof(long)) { cd->cd←errno = TSYSERR; XR←SetErrno(EPROTO); return(-1); } pptr = (union T←primitives *)ctlbuf.buf; switch((int)pptr->type) { case T←CONN←CON: if ((ctlbuf.len < sizeof(struct T←conn←con)) || (ctlbuf.len < (pptr->conn←con.OPT←length + pptr->conn←con.OPT←offset))) { cd->cd←errno = TSYSERR; XR←SetErrno(EPROTO); return(-1); } if (call != NULL) { if ((rcvbuf.len > (int)call->udata.maxlen) || (pptr->conn←con.RES←length > call->addr.maxlen) || (pptr->conn←con.OPT←length > call->opt.maxlen)) { cd->cd←errno = TBUFOVFLW; return(-1); } bcopy(ctlbuf.buf + pptr->conn←con.RES←offset, call->addr.buf, (int)pptr->conn←con.RES←length); call->addr.len = pptr->conn←con.RES←length; bcopy(ctlbuf.buf + pptr->conn←con.OPT←offset, call->opt.buf, (int)pptr->conn←con.OPT←length); call->opt.len = pptr->conn←con.OPT←length; bcopy(rcvbuf.buf, call->udata.buf, (int)rcvbuf.len); call->udata.len = rcvbuf.len; /* * since a confirmation seq number * is -1 by default */ call->sequence = -1; } return(0); case T←DISCON←IND: /* * if disconnect indication then put it in look buf */ PutBack(cd, rcvbuf.buf, rcvbuf.len, ctlbuf.buf, ctlbuf.len); cd->cd←errno = TLOOK; return(-1); default: break; } cd->cd←errno = TSYSERR; XR←SetErrno(EPROTO); return(-1); } int XR←T←Rcv(cd, buf, nbytes, flags) register struct conn←data * cd; register char *buf; unsigned nbytes; int *flags; { struct strbuf ctlbuf, rcvbuf; int retval, flg = 0; int msglen; register union T←primitives *pptr; if (CheckCD(cd)) return(-1); if (cd->cd←servtype == T←CLTS) { cd->cd←errno = TNOTSUPPORT; return(-1); } /* * Check in lookbuf for stuff */ if (cd->cd←lookflg) { /* * Beware - this is right! * If something in lookbuf then check * read queue to see if there is something there. * If there is something there and there is not a * discon in lookbuf, then it must be a discon. * If so, fall through to get it off of queue. * I fall through to make sure it is a discon, * instead of making check here. * * If nothing in read queue then just return TLOOK. */ if ((retval = XR←IOCtl(cd->cd←fd, I←NREAD, &msglen)) < 0) { cd->cd←errno = TSYSERR; return(-1); } if (retval) { if (*((long *)cd->cd←lookcbuf) == T←DISCON←IND) { cd->cd←errno = TLOOK; return(-1); } } else { cd->cd←errno = TLOOK; return(-1); } } ctlbuf.maxlen = cd->cd←ctlsize; ctlbuf.len = 0; ctlbuf.buf = cd->cd←ctlbuf; rcvbuf.maxlen = nbytes; rcvbuf.len = 0; rcvbuf.buf = buf; *flags = 0; /* * data goes right in user buffer */ if ((retval = XR←GetMsg(cd->cd←fd, &ctlbuf, &rcvbuf, &flg)) < 0) { if (XR←GetErrno() == EAGAIN) cd->cd←errno = TNODATA; else cd->cd←errno = TSYSERR; return(-1); } printf("retval returned from XR←GetMsg: %d\n", retval); printf("flg returned from XR←GetMsg: %d\n", flg); if (rcvbuf.len == -1) rcvbuf.len = 0; if (ctlbuf.len > 0) { if (ctlbuf.len < sizeof(long)) { cd->cd←errno = TSYSERR; XR←SetErrno(EPROTO); return(-1); } pptr = (union T←primitives *)ctlbuf.buf; switch(pptr->type) { case T←EXDATA←IND: *flags |= T←EXPEDITED; /* flow thru */ case T←DATA←IND: if ((ctlbuf.len < sizeof(struct T←data←ind)) || (cd->cd←lookflg)) { cd->cd←errno = TSYSERR; XR←SetErrno(EPROTO); return(-1); } if ((pptr->data←ind.MORE←flag) || retval) { printf("pptr->data←ind.MORE←flag = %d\n", pptr->data←ind.MORE←flag); *flags |= T←MORE; } if ((pptr->data←ind.MORE←flag) && retval) cd->cd←flags |= MORE; return(rcvbuf.len); case T←ORDREL←IND: if (cd->cd←lookflg) { cd->cd←errno = TSYSERR; XR←SetErrno(EPROTO); return(-1); } /* flow thru */ case T←DISCON←IND: PutBack(cd, rcvbuf.buf, rcvbuf.len, ctlbuf.buf, ctlbuf.len); if (retval&MOREDATA) { ctlbuf.maxlen = 0; ctlbuf.len = 0; ctlbuf.buf = cd->cd←ctlbuf; rcvbuf.maxlen = cd->cd←rcvsize - rcvbuf.len; rcvbuf.len = 0; rcvbuf.buf = cd->cd←lookdbuf+cd->cd←lookdsize; *flags = 0; if ((retval = XR←GetMsg(cd->cd←fd, &ctlbuf, &rcvbuf, &flg)) < 0) { cd->cd←errno = TSYSERR; return(-1); } if (rcvbuf.len == -1) rcvbuf.len = 0; if (retval) { cd->cd←errno = TSYSERR; XR←SetErrno(EPROTO); cd->cd←lookflg = 0; return(-1); } cd->cd←lookdsize += rcvbuf.len; } cd->cd←errno = TLOOK; return(-1); default: break; } cd->cd←errno = TSYSERR; XR←SetErrno(EPROTO); return(-1); } else { if (!retval && (cd->cd←flags&MORE)) { *flags |= T←MORE; cd->cd←flags &= ~MORE; } if (retval) *flags |= T←MORE; return(rcvbuf.len); } } int XR←T←RcvConnect(cd, call) struct conn←data * cd; struct t←call *call; { return(ReceiveConnectionConfirmation(cd, call)); } int XR←T←RcvDis(cd, discon) struct conn←data * cd; struct t←discon *discon; { struct strbuf ctlbuf; struct strbuf databuf; int retval; int flg = 0; union T←primitives *pptr; if (CheckCD(cd)) return(-1); if (cd->cd←servtype == T←CLTS) { cd->cd←errno = TNOTSUPPORT; return(-1); } /* * is there a discon in look buffer */ if (cd->cd←lookflg && (*((long *)cd->cd←lookcbuf) == T←DISCON←IND)) { ctlbuf.maxlen = cd->cd←lookcsize; ctlbuf.len = cd->cd←lookcsize; ctlbuf.buf = cd->cd←lookcbuf; databuf.maxlen = cd->cd←lookdsize; databuf.len = cd->cd←lookdsize; databuf.buf = cd->cd←lookdbuf; } else { if ((retval = XR←T←Look(cd)) < 0) { return(-1); } if (retval != T←DISCONNECT) { cd->cd←errno = TNODIS; return(-1); } /* * get disconnect off read queue. * use ctl and rcv buffers */ ctlbuf.maxlen = cd->cd←ctlsize; ctlbuf.len = 0; ctlbuf.buf = cd->cd←ctlbuf; databuf.maxlen = cd->cd←rcvsize; databuf.len = 0; databuf.buf = cd->cd←rcvbuf; if ((retval = XR←GetMsg(cd->cd←fd, &ctlbuf, &databuf, &flg)) < 0) { cd->cd←errno = TSYSERR; return(-1); } if (databuf.len == -1) databuf.len = 0; /* * did I get entire message? */ if (retval) { cd->cd←errno = TSYSERR; XR←SetErrno(EIO); return(-1); } } cd->cd←lookflg = 0; pptr = (union T←primitives *)ctlbuf.buf; if ((ctlbuf.len < sizeof(struct T←discon←ind)) || (pptr->type != T←DISCON←IND)) { cd->cd←errno = TSYSERR; XR←SetErrno(EPROTO); return(-1); } if (discon != NULL) { if (databuf.len > (int)discon->udata.maxlen) { cd->cd←errno = TBUFOVFLW; return(-1); } discon->reason = pptr->discon←ind.DISCON←reason; bcopy(databuf.buf, discon->udata.buf, (int)databuf.len); discon->udata.len = databuf.len; discon->sequence = pptr->discon←ind.SEQ←number; } /* * clear more flag */ cd->cd←flags &= ~MORE; return(0); } int XR←T←RcvRel(cd) struct conn←data * cd; { struct strbuf ctlbuf; struct strbuf databuf; int retval; int flg = 0; union T←primitives *pptr; if (CheckCD(cd)) return(-1); if (cd->cd←servtype != T←COTS←ORD) { cd->cd←errno = TNOTSUPPORT; return(-1); } if ((retval = XR←T←Look(cd)) < 0) { return(-1); } if (retval == T←DISCONNECT) { cd->cd←errno = TLOOK; return(-1); } if (cd->cd←lookflg && (*((long *)cd->cd←lookcbuf) == T←ORDREL←IND)) { cd->cd←lookflg = 0; return(0); } else { if (retval != T←ORDREL) { cd->cd←errno = TNOREL; return(-1); } } /* * get ordrel off read queue. * use ctl and rcv buffers */ ctlbuf.maxlen = cd->cd←ctlsize; ctlbuf.len = 0; ctlbuf.buf = cd->cd←ctlbuf; databuf.maxlen = cd->cd←rcvsize; databuf.len = 0; databuf.buf = cd->cd←rcvbuf; if ((retval = XR←GetMsg(cd->cd←fd, &ctlbuf, &databuf, &flg)) < 0) { cd->cd←errno = TSYSERR; return(-1); } /* * did I get entire message? */ if (retval) { cd->cd←errno = TSYSERR; XR←SetErrno(EIO); return(-1); } pptr = (union T←primitives *)ctlbuf.buf; if ((ctlbuf.len < sizeof(struct T←ordrel←ind)) || (pptr->type != T←ORDREL←IND)) { cd->cd←errno = TSYSERR; XR←SetErrno(EPROTO); return(-1); } return(0); } int XR←T←Snd(cd, buf, nbytes, flags) struct conn←data * cd; register char *buf; unsigned nbytes; int flags; { struct strbuf ctlbuf, databuf; struct T←data←req *datareq; int flg = 0; int tmpcnt, tmp; char *tmpbuf; if (CheckCD(cd)) return(-1); if (cd->cd←servtype == T←CLTS) { cd->cd←errno = TNOTSUPPORT; return(-1); } datareq = (struct T←data←req *)cd->cd←ctlbuf; if (flags & T←EXPEDITED) { datareq->PRIM←type = T←EXDATA←REQ; } else datareq->PRIM←type = T←DATA←REQ; ctlbuf.maxlen = sizeof(struct T←data←req); ctlbuf.len = sizeof(struct T←data←req); ctlbuf.buf = cd->cd←ctlbuf; tmp = nbytes; tmpbuf = buf; while (tmp) { if ((tmpcnt = tmp) > cd->cd←maxpsz) { datareq->MORE←flag = 1; tmpcnt = cd->cd←maxpsz; } else { if (flags & T←MORE) datareq->MORE←flag = 1; else datareq->MORE←flag = 0; } databuf.maxlen = tmpcnt; databuf.len = tmpcnt; databuf.buf = tmpbuf; if (XR←PutMsg(cd->cd←fd, &ctlbuf, &databuf, flg) < 0) { if (nbytes == tmp) { if (XR←GetErrno() == EAGAIN) cd->cd←errno = TFLOW; else cd->cd←errno = TSYSERR; return(-1); } else return(nbytes - tmp); } tmp = tmp - tmpcnt; tmpbuf = tmpbuf + tmpcnt; } return(nbytes - tmp); } int XR←T←SndDis(cd, call) register struct conn←data * cd; struct t←call *call; { struct T←discon←req dreq; struct strbuf ctlbuf; struct strbuf databuf; if (CheckCD(cd)) return(-1); if (cd->cd←servtype == T←CLTS) { cd->cd←errno = TNOTSUPPORT; return(-1); } /* * look at look buffer to see if there is a discon there */ if (XR←T←Look(cd) == T←DISCONNECT) { cd->cd←errno = TLOOK; return(-1); } cd->cd←lookflg = 0; if (XR←IOCtl(cd->cd←fd, I←FLUSH, FLUSHW) < 0) { cd->cd←errno = TSYSERR; return(-1); } dreq.PRIM←type = T←DISCON←REQ; dreq.SEQ←number = (call? call->sequence: -1); ctlbuf.maxlen = sizeof(struct T←discon←req); ctlbuf.len = sizeof(struct T←discon←req); ctlbuf.buf = (caddr←t)&dreq; databuf.maxlen = (call? call->udata.len: 0); databuf.len = (call? call->udata.len: 0); databuf.buf = (call? call->udata.buf: NULL); if (XR←PutMsg(cd->cd←fd, &ctlbuf, (databuf.len? &databuf: NULL), 0) < 0) { cd->cd←errno = TSYSERR; return(-1); } if (!IsOK(cd, (long)T←DISCON←REQ)) { return(-1); } cd->cd←flags &= ~MORE; return(0); } int XR←T←SndRel(cd) register struct conn←data * cd; { struct T←ordrel←req orreq; struct strbuf ctlbuf; if (CheckCD(cd)) return(-1); if (cd->cd←servtype != T←COTS←ORD) { cd->cd←errno = TNOTSUPPORT; return(-1); } orreq.PRIM←type = T←ORDREL←REQ; ctlbuf.maxlen = sizeof(struct T←ordrel←req); ctlbuf.len = sizeof(struct T←ordrel←req); ctlbuf.buf = (caddr←t)&orreq; if (XR←PutMsg(cd->cd←fd, &ctlbuf, NULL, 0) < 0) { if (XR←GetErrno() == EAGAIN) cd->cd←errno = TFLOW; else cd->cd←errno = TSYSERR; return(-1); } return(0); } /* Datagram things */ int XR←T←RcvUData(cd, unitdata, flags) struct conn←data * cd; register struct t←unitdata *unitdata; int *flags; { struct strbuf ctlbuf; int retval, flg = 0; register union T←primitives *pptr; if (CheckCD(cd)) return(-1); /* because of cd->cd←errno */ if (cd->cd←servtype != T←CLTS) { cd->cd←errno = TNOTSUPPORT; return(-1); } /* * check if there is something in look buffer */ if (cd->cd←lookflg) { cd->cd←errno = TLOOK; return(-1); } ctlbuf.maxlen = cd->cd←ctlsize; ctlbuf.len = 0; ctlbuf.buf = cd->cd←ctlbuf; *flags = 0; /* * data goes right in user buffer */ if ((retval = XR←GetMsg(cd->cd←fd, &ctlbuf, &unitdata->udata, &flg)) < 0) { if (XR←GetErrno() == EAGAIN) cd->cd←errno = TNODATA; else cd->cd←errno = TSYSERR; return(-1); } if (unitdata->udata.len == -1) unitdata->udata.len = 0; /* * is there control piece with data? */ if (ctlbuf.len > 0) { if (ctlbuf.len < sizeof(long)) { cd->cd←errno = TSYSERR; XR←SetErrno(EPROTO); unitdata->udata.len = 0; return(-1); } pptr = (union T←primitives *)ctlbuf.buf; switch(pptr->type) { case T←UNITDATA←IND: if ((ctlbuf.len < sizeof(struct T←unitdata←ind)) || (pptr->unitdata←ind.OPT←length && (ctlbuf.len < (pptr->unitdata←ind.OPT←length + pptr->unitdata←ind.OPT←offset)))) { cd->cd←errno = TSYSERR; XR←SetErrno(EPROTO); unitdata->udata.len = 0; return(-1); } if ((pptr->unitdata←ind.SRC←length > (int)unitdata->addr.maxlen) || (pptr->unitdata←ind.OPT←length > (int)unitdata->opt.maxlen)) { cd->cd←errno = TBUFOVFLW; unitdata->udata.len = 0; return(-1); } if (retval) *flags |= T←MORE; bcopy(ctlbuf.buf + pptr->unitdata←ind.SRC←offset, unitdata->addr.buf, (int)pptr->unitdata←ind.SRC←length); unitdata->addr.len = pptr->unitdata←ind.SRC←length; bcopy(ctlbuf.buf + pptr->unitdata←ind.OPT←offset, unitdata->opt.buf, (int)pptr->unitdata←ind.OPT←length); unitdata->opt.len = pptr->unitdata←ind.OPT←length; return(0); case T←UDERROR←IND: PutBack(cd, unitdata->udata.buf, 0, ctlbuf.buf, ctlbuf.len); unitdata->udata.len = 0; cd->cd←errno = TLOOK; return(-1); default: break; } cd->cd←errno = TSYSERR; XR←SetErrno(EPROTO); return(-1); } else { unitdata->addr.len = 0; unitdata->opt.len = 0; /* * only data in message no control piece */ if (retval) *flags = T←MORE; return(0); } } int XR←T←RcvUDErr(cd, uderr) struct conn←data * cd; struct t←uderr *uderr; { struct strbuf ctlbuf, rcvbuf; int flg; int retval; register union T←primitives *pptr; if (CheckCD(cd)) return(-1); if (cd->cd←servtype != T←CLTS) { cd->cd←errno = TNOTSUPPORT; return(-1); } /* * is there an error indication in look buffer */ if (cd->cd←lookflg) { ctlbuf.maxlen = cd->cd←lookcsize; ctlbuf.len = cd->cd←lookcsize; ctlbuf.buf = cd->cd←lookcbuf; rcvbuf.maxlen = 0; rcvbuf.len = 0; rcvbuf.buf = NULL; } else { if ((retval = XR←T←Look(cd)) < 0) return(-1); if (retval != T←UDERR) { cd->cd←errno = TNOUDERR; return(-1); } ctlbuf.maxlen = cd->cd←ctlsize; ctlbuf.len = 0; ctlbuf.buf = cd->cd←ctlbuf; rcvbuf.maxlen = 0; rcvbuf.len = 0; rcvbuf.buf = NULL; if ((retval = XR←GetMsg(cd->cd←fd, &ctlbuf, &rcvbuf, &flg)) < 0) { cd->cd←errno = TSYSERR; return(-1); } /* * did I get entire message? */ if (retval) { cd->cd←errno = TSYSERR; XR←SetErrno(EIO); return(-1); } } cd->cd←lookflg = 0; pptr = (union T←primitives *)ctlbuf.buf; if ((ctlbuf.len < sizeof(struct T←uderror←ind)) || (pptr->type != T←UDERROR←IND)) { cd->cd←errno = TSYSERR; XR←SetErrno(EPROTO); return(-1); } if (uderr) { if ((uderr->addr.maxlen < pptr->uderror←ind.DEST←length) || (uderr->opt.maxlen < pptr->uderror←ind.OPT←length)) { cd->cd←errno = TBUFOVFLW; return(-1); } uderr->error = pptr->uderror←ind.ERROR←type; bcopy(ctlbuf.buf + pptr->uderror←ind.DEST←offset, uderr->addr.buf, (int)pptr->uderror←ind.DEST←length); bcopy(ctlbuf.buf + pptr->uderror←ind.OPT←offset, uderr->opt.buf, (int)pptr->uderror←ind.OPT←length); } return(0); } int XR←T←SndUData(cd, unitdata) struct conn←data * cd; register struct t←unitdata *unitdata; { register struct T←unitdata←req *udreq; char *buf; struct strbuf ctlbuf; int size; if (CheckCD(cd)) return(-1); if (cd->cd←servtype != T←CLTS) { cd->cd←errno = TNOTSUPPORT; return(-1); } if ((int)unitdata->udata.len == 0) return(0); if ((int)unitdata->udata.len > cd->cd←maxpsz) { cd->cd←errno = TSYSERR; XR←SetErrno(ERANGE); return(-1); } buf = cd->cd←ctlbuf; udreq = (struct T←unitdata←req *)buf; udreq->PRIM←type = T←UNITDATA←REQ; udreq->DEST←length = unitdata->addr.len; udreq->DEST←offset = 0; udreq->OPT←length = unitdata->opt.len; udreq->OPT←offset = 0; size = sizeof(struct T←unitdata←req); if (unitdata->addr.len) { AlignedCopy(buf, unitdata->addr.len, size, unitdata->addr.buf, &udreq->DEST←offset); size = udreq->DEST←offset + udreq->DEST←length; } if (unitdata->opt.len) { AlignedCopy(buf, unitdata->opt.len, size, unitdata->opt.buf, &udreq->OPT←offset); size = udreq->OPT←offset + udreq->OPT←length; } if (size > cd->cd←ctlsize) { cd->cd←errno = TSYSERR; XR←SetErrno(EIO); return(-1); } ctlbuf.maxlen = cd->cd←ctlsize; ctlbuf.len = size; ctlbuf.buf = buf; if (XR←PutMsg(cd->cd←fd, &ctlbuf, (unitdata->udata.len? &unitdata->udata: NULL), 0) < 0) { if (XR←GetErrno() == EAGAIN) cd->cd←errno = TFLOW; else cd->cd←errno = TSYSERR; return(-1); } return(0); } /* Allocation things */ char * XR←T←Alloc(cd, struct←type, fields) struct conn←data * cd; int struct←type; int fields; { struct strioctl strioc; struct T←info←ack info; union structptrs { char *caddr; struct t←bind *bind; struct t←call *call; struct t←discon *dis; struct t←optmgmt *opt; struct t←unitdata *udata; struct t←uderr *uderr; struct t←info *info; } p; unsigned dsize; if (CheckCD(cd)) return(NULL); /* * Get size info for T←ADDR, T←OPT, and T←UDATA fields */ info.PRIM←type = T←INFO←REQ; strioc.ic←cmd = TI←GETINFO; strioc.ic←timout = -1; strioc.ic←len = sizeof(struct T←info←req); strioc.ic←dp = (char *)&info; if (XR←IOCtl(cd->cd←fd, I←STR, &strioc) < 0) { cd->cd←errno = TSYSERR; return(NULL); } if (strioc.ic←len != sizeof(struct T←info←ack)) { XR←SetErrno(EIO); cd->cd←errno = TSYSERR; return(NULL); } /* * Malloc appropriate structure and the specified * fields within each structure. Initialize the * 'buf' and 'maxlen' fields of each. */ switch (struct←type) { case T←BIND: if ((p.bind = (struct t←bind *) GC←malloc((unsigned)sizeof(struct t←bind))) == NULL) goto out; if (fields & T←ADDR) { if (AllocBuf(&p.bind->addr, info.ADDR←size) < 0) goto out; } return((char *)p.bind); case T←CALL: if ((p.call = (struct t←call *) GC←malloc((unsigned)sizeof(struct t←call))) == NULL) goto out; if (fields & T←ADDR) { if (AllocBuf(&p.call->addr, info.ADDR←size) < 0) goto out; } if (fields & T←OPT) { if (AllocBuf(&p.call->opt, info.OPT←size) < 0) goto out; } if (fields & T←UDATA) { dsize = Max(info.CDATA←size, info.DDATA←size); if (AllocBuf(&p.call->udata, dsize) < 0) goto out; } return((char *)p.call); case T←OPTMGMT: if ((p.opt = (struct t←optmgmt *) GC←malloc((unsigned)sizeof(struct t←optmgmt))) == NULL) goto out; if (fields & T←OPT){ if (AllocBuf(&p.opt->opt, info.OPT←size) < 0) goto out; } return((char *)p.opt); case T←DIS: if ((p.dis = (struct t←discon *) GC←malloc((unsigned)sizeof(struct t←discon))) == NULL) goto out; if (fields & T←UDATA){ if (AllocBuf(&p.dis->udata, info.DDATA←size) < 0) goto out; } return((char *)p.dis); case T←UNITDATA: if ((p.udata = (struct t←unitdata *) GC←malloc((unsigned)sizeof(struct t←unitdata))) == NULL) goto out; if (fields & T←ADDR){ if (AllocBuf(&p.udata->addr, info.ADDR←size) < 0) goto out; } if (fields & T←OPT){ if (AllocBuf(&p.udata->opt, info.OPT←size) < 0) goto out; } if (fields & T←UDATA){ if (AllocBuf(&p.udata->udata, info.TSDU←size) < 0) goto out; } return((char *)p.udata); case T←UDERROR: if ((p.uderr = (struct t←uderr *) GC←malloc((unsigned)sizeof(struct t←uderr))) == NULL) goto out; if (fields & T←ADDR){ if (AllocBuf(&p.uderr->addr, info.ADDR←size) < 0) goto out; } if (fields & T←OPT){ if (AllocBuf(&p.uderr->opt, info.OPT←size) < 0) goto out; } return((char *)p.uderr); case T←INFO: if ((p.info = (struct t←info *) GC←malloc((unsigned)sizeof(struct t←info))) == NULL) goto out; return((char *)p.info); default: XR←SetErrno(EINVAL); cd->cd←errno = TSYSERR; return(NULL); } /* * Clean up. Set errno to ENOMEM if * memory could not be allocated. */ out: if (p.caddr) XR←T←Free(cd, p.caddr, struct←type); cd->cd←errno = TSYSERR; XR←SetErrno(ENOMEM); return(NULL); }; int XR←T←Free(cd, ptr, struct←type) struct conn←data * cd; char *ptr; int struct←type; { union structptrs { struct t←bind *bind; struct t←call *call; struct t←discon *dis; struct t←optmgmt *opt; struct t←unitdata *udata; struct t←uderr *uderr; } p; if (CheckCD(cd)) return(-1); /* because of cd->cd←errno */ /* * Free all the buffers associated with the appropriate * fields of each structure. */ switch (struct←type) { case T←BIND: p.bind = (struct t←bind *)ptr; if (p.bind->addr.buf != NULL) free(p.bind->addr.buf); break; case T←CALL: p.call = (struct t←call *)ptr; if (p.call->addr.buf != NULL) free(p.call->addr.buf); if (p.call->opt.buf != NULL) free(p.call->opt.buf); if (p.call->udata.buf != NULL) free(p.call->udata.buf); break; case T←OPTMGMT: p.opt = (struct t←optmgmt *)ptr; if (p.opt->opt.buf != NULL) free(p.opt->opt.buf); break; case T←DIS: p.dis = (struct t←discon *)ptr; if (p.dis->udata.buf != NULL) free(p.dis->udata.buf); break; case T←UNITDATA: p.udata = (struct t←unitdata *)ptr; if (p.udata->addr.buf != NULL) free(p.udata->addr.buf); if (p.udata->opt.buf != NULL) free(p.udata->opt.buf); if (p.udata->udata.buf != NULL) free(p.udata->udata.buf); break; case T←UDERROR: p.uderr = (struct t←uderr *)ptr; if (p.uderr->addr.buf != NULL) free(p.uderr->addr.buf); if (p.uderr->opt.buf != NULL) free(p.uderr->opt.buf); break; case T←INFO: break; default: XR←SetErrno(EINVAL); cd->cd←errno = TSYSERR; return(-1); } free(ptr); return(0); } /* Other useful stuff */ /* * put data and control info in look buffer * * The only thing that can be in look buffer is a T←discon←ind, * T←ordrel←ind or a T←uderr←ind. */ int PutBack(cd, dptr, dsize, cptr, csize) struct conn←data * cd; caddr←t dptr; int dsize; caddr←t cptr; int csize; { if (CheckCD(cd)) return(-1); bcopy(dptr, cd->cd←lookdbuf, dsize); bcopy(cptr, cd->cd←lookcbuf, csize); cd->cd←lookdsize = dsize; cd->cd←lookcsize = csize; cd->cd←lookflg++; } int AllocBuf(buf, n) struct netbuf *buf; { switch(n) { case -1: if ((buf->buf = (char *) GC←malloc(1024)) == NULL) return(-1); else buf->maxlen = 1024; break; case 0: case -2: buf->buf = NULL; buf->maxlen = 0; break; default: if ((buf->buf = (char *) GC←malloc(n)) == NULL) return(-1); else buf->maxlen = n; break; } return(0); } /* * copy data to output buffer and align it as in input buffer * This is to ensure that if the user wants to align a network * addr on a non-word boundry then it will happen. */ int AlignedCopy(buf, len, init←offset, datap, rtn←offset) char *buf; int len; int init←offset; char *datap; long *rtn←offset; { *rtn←offset = ROUNDUP(init←offset) + ((unsigned)datap&0x03); bcopy(datap, (char *)(buf + *rtn←offset), (int)len); } /* * CheckCD checks to see that the contents of the cd data * structure is good */ int CheckCD(cd) struct conn←data * cd; { if (cd == NULL) return(1); if ((cd->cd←fd < 0) || !(cd->cd←flags & USED)) { cd->cd←errno = TBADF; return(1); }; return(0); }; /* * Max - return max between two ints */ int Max(x, y) int x; int y; { if (x > y) return(x); else return(y); }; /* * Is there something that needs attention? */ int IsEvent(cd) struct conn←data * cd; { int size, retval; if ((retval = XR←IOCtl(cd->cd←fd, I←NREAD, &size)) < 0) { cd->cd←errno = TSYSERR; return(1); } if (retval || cd->cd←lookflg) { cd->cd←errno = TLOOK; return(1); } return(0); } /* * wait for T←OK←ACK */ int IsOK(cd, type) register struct conn←data * cd; long type; { struct strbuf ctlbuf; struct strbuf rcvbuf; register union T←primitives *pptr; int flags, retval, cntlflag; int size; int fd = cd->cd←fd; cntlflag = XR←FCntl(fd, F←GETFL, 0); XR←FCntl(fd, F←SETFL, XR←FCntl(fd, F←GETFL, 0) & ~O←NDELAY); ctlbuf.len = 0; ctlbuf.buf = cd->cd←ctlbuf; ctlbuf.maxlen = cd->cd←ctlsize; rcvbuf.maxlen = cd->cd←rcvsize; rcvbuf.len = 0; rcvbuf.buf = cd->cd←rcvbuf; flags = RS←HIPRI; while ((retval = XR←GetMsg(fd, &ctlbuf, &rcvbuf, &flags)) < 0) { if (XR←GetErrno() == EINTR) continue; cd->cd←errno = TSYSERR; return(0); } /* did I get entire message */ if (retval) { cd->cd←errno = TSYSERR; XR←SetErrno(EIO); return(0); } /* * is ctl part large enough to determine type? */ if (ctlbuf.len < sizeof(long)) { cd->cd←errno = TSYSERR; XR←SetErrno(EPROTO); return(0); } XR←FCntl(cd->cd←fd, F←SETFL, cntlflag); pptr = (union T←primitives *)ctlbuf.buf; switch((int)pptr->type) { case T←OK←ACK: if ((ctlbuf.len < sizeof(struct T←ok←ack)) || (pptr->ok←ack.CORRECT←prim != type)) { cd->cd←errno = TSYSERR; XR←SetErrno(EPROTO); return(0); } return(1); case T←ERROR←ACK: if ((ctlbuf.len < sizeof(struct T←error←ack)) || (pptr->error←ack.ERROR←prim != type)) { cd->cd←errno = TSYSERR; XR←SetErrno(EPROTO); return(0); } /* * if error is out of state and there is something * on read queue, then indicate to user that * there is something that needs attention */ if (pptr->error←ack.TLI←error == TOUTSTATE) { if ((retval = XR←IOCtl(fd, I←NREAD, &size)) < 0) { cd->cd←errno = TSYSERR; return(0); } if (retval) cd->cd←errno = TLOOK; else cd->cd←errno = TOUTSTATE; } else { cd->cd←errno = pptr->error←ack.TLI←error; if (cd->cd←errno == TSYSERR) XR←SetErrno(pptr->error←ack.UNIX←error); } return(0); default: cd->cd←errno = TSYSERR; XR←SetErrno(EPROTO); return(0); } } /* * timod XR←IOCtl */ int DoTIModIOCtl(cd, buf, size, cmd, retlen) struct conn←data * cd; char *buf; int size; int cmd; int *retlen; { int fd = cd->cd←fd; int retval; struct strioctl strioc; strioc.ic←cmd = cmd; strioc.ic←timout = -1; strioc.ic←len = size; strioc.ic←dp = buf; if ((retval = XR←IOCtl(fd, I←STR, &strioc)) < 0) { cd->cd←errno = TSYSERR; return(0); } if (retval) { cd->cd←errno = retval&0xff; if (cd->cd←errno == TSYSERR) XR←SetErrno((retval >> 8)&0xff); return(0); } if (retlen){ *retlen = strioc.ic←len; } return(1); } /* * alloc scratch buffers and look buffers */ AllocateBuffers(cd, info) struct conn←data * cd; struct T←info←ack info; { unsigned size1, size2; unsigned csize, dsize, asize, osize; char *ctlbuf, *rcvbuf; char *lookdbuf, *lookcbuf; csize = SetSize(info.CDATA←size); dsize = SetSize(info.DDATA←size); size1 = Max(csize, dsize); if ((rcvbuf = (char *) GC←malloc(size1)) == NULL) { return(-1); } if ((lookdbuf = (char *) GC←malloc(size1)) == NULL) { (void)free(rcvbuf); return(-1); } asize = SetSize(info.ADDR←size); osize = SetSize(info.OPT←size); size2 = sizeof(union T←primitives) + asize + sizeof(long) + osize + sizeof(long); if ((ctlbuf = (char *) GC←malloc(size2)) == NULL) { (void)free(rcvbuf); (void)free(lookdbuf); return(-1); } if ((lookcbuf = (char *) GC←malloc(size2)) == NULL) { (void)free(rcvbuf); (void)free(lookdbuf); (void)free(ctlbuf); return(-1); } cd->cd←rcvsize = size1; cd->cd←rcvbuf = rcvbuf; cd->cd←ctlsize = size2; cd->cd←ctlbuf = ctlbuf; cd->cd←lookcbuf = lookcbuf; cd->cd←lookdbuf = lookdbuf; cd->cd←lookcsize = 0; cd->cd←lookdsize = 0; cd->cd←lookflg = 0; cd->cd←flags = USED; cd->cd←maxpsz = info.TIDU←size; cd->cd←servtype = info.SERV←type; return(0); } /* * set sizes of buffers */ SetSize(infosize) long infosize; { switch((int)infosize) { case -1: return(DEFSIZE); case -2: return(0); default: return(infosize); } }