BSD 4_4_Lite2 development
authorCSRG <csrg@ucbvax.Berkeley.EDU>
Wed, 14 Jan 1987 04:39:05 +0000 (20:39 -0800)
committerCSRG <csrg@ucbvax.Berkeley.EDU>
Wed, 14 Jan 1987 04:39:05 +0000 (20:39 -0800)
Work on file usr/src/contrib/xns/xnslib/bdt.c

Synthesized-from: CSRG/cd3/4.4BSD-Lite2

usr/src/contrib/xns/xnslib/bdt.c [new file with mode: 0644]

diff --git a/usr/src/contrib/xns/xnslib/bdt.c b/usr/src/contrib/xns/xnslib/bdt.c
new file mode 100644 (file)
index 0000000..40bbcac
--- /dev/null
@@ -0,0 +1,267 @@
+/*
+ * This file contains routines useful to the applications developer who
+ * must read or write BDT data.
+ */
+
+/*
+ $Log: bdt.c,v $
+ * Revision 3.0  87/01/14  14:39:02  ed
+ * release containing Xerox (Webster Research Center) modifications
+ * 
+ * Revision 2.1  86/09/07  09:36:29  jqj
+ * return correct number of bytes written by BDTwrite, or -1 on error.
+ * 
+ * Revision 2.0  85/11/21  07:22:02  jqj
+ * 4.3BSD standard release
+ * 
+ * Revision 1.4  85/03/11  16:36:38  jqj
+ * *** empty log message ***
+ * 
+ * Revision 1.4  85/03/11  16:36:38  jqj
+ * Public alpha-test version, released 11 March 1985
+ * 
+ * Revision 1.3  85/03/11  16:34:19  jqj
+ * Public alpha-test version, released 11 March 1985
+ * 
+ * Revision 1.2  85/01/27  07:37:06  jqj
+ * finished but undebugged version
+ * 
+ */
+
+#ifndef lint
+static char rcsid[] = "$Header: bdt.c,v 3.0 87/01/14 14:39:02 ed Exp $";
+#endif
+
+#include <stdio.h>
+#include <sys/time.h>
+#include <sys/types.h>         /* for socket.h and xn.h */
+#include <sys/socket.h>
+#include <sys/uio.h>           /* for scatter/gather io */
+#include <netns/ns.h>          /* for XNS addresses and courierconnection.h */
+#include <netns/idp.h>
+#include <netns/sp.h>          /* for spphdr */
+#include "courier.h"
+#include "realcourierconnection.h"
+
+#define MAKEVEC(idx, addr, len) our_iovec[idx].iov_base = (caddr_t)addr;\
+                               our_iovec[idx].iov_len = len;
+
+\f
+
+int
+BDTwrite(f,buffer,nbytes)
+/* Call with CourierConnection*, not *(CourierConnection*) */
+/* Semantics are much like write(), except that it returns -1
+ * if a BDT abort message arrives from receiver.
+ * Returns # of bytes actually written, or -1 if an error occurs (some
+ * data may have been transferred!).
+ */
+       register CourierConnection *f;
+       char *buffer;
+       int nbytes;
+{
+       register int n, w;
+       struct iovec our_iovec[2];
+
+       MAKEVEC(0, &(f->sphdrOpts), sizeof(f->sphdrOpts));
+       MAKEVEC(1, buffer, SPPMAXDATA);
+
+       if (f->bdtstate == wantdata) {
+                       /* stream=BDT, EOM=FALSE, Attn=FALSE */
+               f->sphdrOpts.sp_dt = SPPSST_BDT;
+               f->sphdrOpts.sp_cc &= ~SP_EM;
+               f->bdtstate = established;
+       }
+       if (BDTabortSeen(f)) {
+               BDTabort(f);    /* send end (abort) */
+               f->abortseen = FALSE;   /* clear abort */
+               f->bdtstate = bdteomseen;
+               return(-1);     /* truncate the stream */
+       }
+       /* ### if nbytes > SPPMAXDATA, do something intelligent? */
+       for(n = nbytes; n > SPPMAXDATA; n -= SPPMAXDATA) {
+               w = writev(f->fd, our_iovec, 2) - sizeof(f->sphdrOpts);
+               if (w < 0) return(-1);
+               if(w < SPPMAXDATA)
+                       return( w + nbytes - n);
+               our_iovec[1].iov_base += SPPMAXDATA;
+       }
+       our_iovec[1].iov_len = n;
+       w = writev(f->fd, our_iovec, 2) - sizeof(f->sphdrOpts);
+       if (w < 0) return(-1);
+       return( w + nbytes - n);
+}
+
+
+int
+BDTclosewrite(f)
+/* call with CourierConnection*, not *(CourierConnection*) */
+/* End a BDT connection.  Returns 0 on success, -1 on failure.
+ */
+       register CourierConnection *f;
+{
+
+       f->bdtstate = bdteomseen;
+       if (BDTabortSeen(f)) {
+               BDTabort(f);
+               f->abortseen = FALSE;
+               return(-1);
+       }
+       /* stream=BDT, EOM=TRUE, Attn=FALSE */
+       f->sphdrOpts.sp_dt = SPPSST_BDT;
+       f->sphdrOpts.sp_cc |= SP_EM;
+       /* finally, send normal end in a packet of its own */
+       write(f->fd,(char*)&f->sphdrOpts,sizeof(struct sphdr));
+       return(0);
+}
+
+
+int
+BDTread(f, buffer, nbytes)
+/* Call with CourierConnection*, not *(CourierConnection*) */
+/* Semantics are much like read(), except that it returns -1 on
+ * more conditions.  Returns number of characters actually read,
+ * or 0 on end of message.
+ */
+       register CourierConnection *f;
+       char *buffer;
+       int nbytes;
+{
+       register int count;
+       struct {
+               struct sphdr hdr;
+               char data[SPPMAXDATA];
+       } packbuf;
+       struct iovec our_iovec[2];
+
+       switch (f->state) {
+       case closed:
+       case calldone:
+               fprintf(stderr,"BDTread() called while connection state = %s\n",
+                       (f->state == closed) ? "closed" : "calldone");
+               exit(1);
+               /* NOTREACHED */
+       case wantversion:
+               count = recv(f->fd, (char*) &packbuf, sizeof(packbuf), MSG_PEEK)
+                               - sizeof(struct sphdr);
+               while (count == 0
+                      && packbuf.hdr.sp_dt == SPPSST_RPC) {
+                       read(f->fd, (char*) &packbuf, sizeof(packbuf));
+                       count = recv(f->fd, (char*) &packbuf, sizeof(packbuf),
+                                       MSG_PEEK)
+                                       - sizeof(struct sphdr);
+               }
+               if (count == 0)
+                       /* streamtype != SPPSST_RPC, so we can't */
+                       /* have a version number */
+                       break;
+                       /* fall out of switch, still wantversion */
+               /* ### N.B. we don't handle count==2 */
+               else if (count != (2*sizeof(Cardinal)))
+                       /* must be a REJECT or ABORT message */
+                       /* let someone else handle it! */
+                       return(-1);
+               else {
+                       /* must be a Courier version number */
+                       /* read it and throw it away */
+                       read(f->fd, (char*) &packbuf, sizeof(packbuf));
+                       f->state = inprogress;
+                       /* fall into case inprogress */
+               }
+       case inprogress:
+               switch (f->bdtstate) {
+               case wantdata:
+                       count = recv(f->fd, (char*) &packbuf, sizeof(packbuf),
+                                       MSG_PEEK)
+                                       - sizeof(struct sphdr);
+                       if (packbuf.hdr.sp_dt == SPPSST_RPC)
+                               return(-1);
+                       f->bdtstate = established;
+                       /* fall through to case established */
+               case established:
+                       break;
+                       /* fall out of inner (and outer!) switch */
+               case bdteomseen:
+                       return(0);
+               }
+               break;
+       }
+       MAKEVEC(0,&packbuf.hdr,sizeof(struct sphdr));
+       MAKEVEC(1,buffer,nbytes);
+       count = readv(f->fd,our_iovec,2) - sizeof(struct sphdr);
+       /* at this point, we've read a packet that isn't SPPSST_RPC */
+       while (TRUE) {
+               if (packbuf.hdr.sp_dt == SPPSST_END) {
+                       (void) sppclosereply(f->fd);
+                       f->state = closed;
+                       fprintf(stderr,"SPP END received during BDT\n");
+                       exit(1);
+               }
+               if (packbuf.hdr.sp_dt != SPPSST_BDT) {
+                       fprintf(stderr,
+                               "wrong stream type, %d, seen during BDT\n",
+                               packbuf.hdr.sp_dt);
+                       exit(1);
+                       /* NOTREACHED */
+               }
+               if (f->abortseen || (packbuf.hdr.sp_cc & SP_OB)) {
+                       f->abortseen = TRUE;
+                       return(-1);
+               }
+               if (packbuf.hdr.sp_cc & SP_EM) {
+                       f->bdtstate = bdteomseen;
+                       /* next read will return 0 */
+                       return(count);
+               }
+               if (count > 0)
+                       return(count);
+               count = readv(f->fd,our_iovec,2) - sizeof(struct sphdr);
+       }
+}
+
+BDTabort(f)
+       register CourierConnection *f;
+{
+       static struct handy {
+               struct sphdr hdr;
+               char value;
+       } data;
+       /* stream=BDT, EOM=FALSE, Attn=TRUE */
+       data.hdr.sp_dt = SPPSST_BDT;
+       data.hdr.sp_cc = SP_EM;
+       data.value = 1; /* BDT abort data value */
+       send(f->fd, &data, sizeof(data), MSG_OOB);
+       f->bdtstate = bdteomseen;
+       f->abortseen = TRUE;
+}
+
+
+BDTabortSeen(f)
+       register CourierConnection *f;
+{
+       struct {
+               struct sphdr hdr;
+               Unspecified data[MAXWORDS];
+       } packbuf;
+       int fdmask;
+       register int count;
+       static struct timeval timeout = {0,0};
+
+       fdmask = 1<<(f->fd);
+       /* ### code here for OOB signalling! */
+       while (select(f->fd+1,&fdmask,(int*)NULL,(int*)NULL,&timeout) > 0
+           && (count = recv(f->fd,(char*)&packbuf, sizeof(packbuf),
+                               MSG_PEEK) - sizeof(struct sphdr)) > 0) {
+               if (packbuf.hdr.sp_dt == SPPSST_BDT
+                   && (packbuf.hdr.sp_dt & SP_OB)
+                   && count == 1) {
+                       read(f->fd, (char*)&packbuf, sizeof(packbuf));
+                       f->abortseen = TRUE;
+                       return(TRUE);
+               }
+               else if (count == 0)
+                       read(f->fd, (char*)&packbuf, sizeof(packbuf));
+               else return(FALSE);
+       }
+       return(FALSE);
+}