1: /* 2: * This file contains routines useful to the applications developer who 3: * must read or write BDT data. 4: */ 5: 6: /* 7: $Log: bdt.c,v $ 8: * Revision 2.0 85/11/21 07:22:02 jqj 9: * 4.3BSD standard release 10: * 11: * Revision 1.4 85/03/11 16:36:38 jqj 12: * *** empty log message *** 13: * 14: * Revision 1.4 85/03/11 16:36:38 jqj 15: * Public alpha-test version, released 11 March 1985 16: * 17: * Revision 1.3 85/03/11 16:34:19 jqj 18: * Public alpha-test version, released 11 March 1985 19: * 20: * Revision 1.2 85/01/27 07:37:06 jqj 21: * finished but undebugged version 22: * 23: */ 24: 25: #ifndef lint 26: static char rcsid[] = "$Header: bdt.c,v 2.0 85/11/21 07:22:02 jqj Exp $"; 27: #endif 28: 29: #include <stdio.h> 30: #include <sys/time.h> 31: #include <sys/types.h> /* for socket.h and xn.h */ 32: #include <sys/socket.h> 33: #include <sys/uio.h> /* for scatter/gather io */ 34: #include <netns/ns.h> /* for XNS addresses and courierconnection.h */ 35: #include <netns/idp.h> 36: #include <netns/sp.h> /* for spphdr */ 37: #include "courier.h" 38: #include "realcourierconnection.h" 39: 40: #define MAKEVEC(idx, addr, len) our_iovec[idx].iov_base = (caddr_t)addr;\ 41: our_iovec[idx].iov_len = len; 42: 43: 44: 45: int 46: BDTwrite(f,buffer,nbytes) 47: /* Call with CourierConnection*, not *(CourierConnection*) */ 48: /* Semantics are much like write(), except that it returns -1 49: * if a BDT abort message arrives from receiver. 50: * Returns # of bytes actually written. 51: */ 52: register CourierConnection *f; 53: char *buffer; 54: int nbytes; 55: { 56: register int n, w; 57: struct iovec our_iovec[2]; 58: 59: MAKEVEC(0, &(f->sphdrOpts), sizeof(f->sphdrOpts)); 60: MAKEVEC(1, buffer, SPPMAXDATA); 61: 62: if (f->bdtstate == wantdata) { 63: /* stream=BDT, EOM=FALSE, Attn=FALSE */ 64: f->sphdrOpts.sp_dt = SPPSST_BDT; 65: f->sphdrOpts.sp_cc &= ~SP_EM; 66: f->bdtstate = established; 67: } 68: if (BDTabortSeen(f)) { 69: BDTabort(f); /* send end (abort) */ 70: f->abortseen = FALSE; /* clear abort */ 71: f->bdtstate = bdteomseen; 72: return(-1); /* truncate the stream */ 73: } 74: /* ### if nbytes > SPPMAXDATA, do something intelligent? */ 75: for(n = nbytes; n > SPPMAXDATA; n -= SPPMAXDATA) { 76: w = writev(f->fd, our_iovec, 2); 77: if(w < SPPMAXDATA) 78: return( w + nbytes - n); 79: our_iovec[1].iov_base += SPPMAXDATA; 80: } 81: our_iovec[1].iov_len = n; 82: w = writev(f->fd, our_iovec, 2); 83: return( w + nbytes - n); 84: } 85: 86: 87: int 88: BDTclosewrite(f) 89: /* call with CourierConnection*, not *(CourierConnection*) */ 90: /* End a BDT connection. Returns 0 on success, -1 on failure. 91: */ 92: register CourierConnection *f; 93: { 94: 95: f->bdtstate = bdteomseen; 96: if (BDTabortSeen(f)) { 97: BDTabort(f); 98: f->abortseen = FALSE; 99: return(-1); 100: } 101: /* stream=BDT, EOM=TRUE, Attn=FALSE */ 102: f->sphdrOpts.sp_dt = SPPSST_BDT; 103: f->sphdrOpts.sp_cc |= SP_EM; 104: /* finally, send normal end in a packet of its own */ 105: write(f->fd,(char*)&f->sphdrOpts,sizeof(struct sphdr)); 106: return(0); 107: } 108: 109: 110: int 111: BDTread(f, buffer, nbytes) 112: /* Call with CourierConnection*, not *(CourierConnection*) */ 113: /* Semantics are much like read(), except that it returns -1 on 114: * more conditions. Returns number of characters actually read, 115: * or 0 on end of message. 116: */ 117: register CourierConnection *f; 118: char *buffer; 119: int nbytes; 120: { 121: register int count; 122: struct { 123: struct sphdr hdr; 124: char data[SPPMAXDATA]; 125: } packbuf; 126: struct iovec our_iovec[2]; 127: 128: switch (f->state) { 129: case closed: 130: case calldone: 131: fprintf(stderr,"BDTread() called while connection state = %s\n", 132: (f->state == closed) ? "closed" : "calldone"); 133: exit(1); 134: /* NOTREACHED */ 135: case wantversion: 136: count = recv(f->fd, (char*) &packbuf, sizeof(packbuf), MSG_PEEK) 137: - sizeof(struct sphdr); 138: while (count == 0 139: && packbuf.hdr.sp_dt == SPPSST_RPC) { 140: read(f->fd, (char*) &packbuf, sizeof(packbuf)); 141: count = recv(f->fd, (char*) &packbuf, sizeof(packbuf), 142: MSG_PEEK) 143: - sizeof(struct sphdr); 144: } 145: if (count == 0) 146: /* streamtype != SPPSST_RPC, so we can't */ 147: /* have a version number */ 148: break; 149: /* fall out of switch, still wantversion */ 150: /* ### N.B. we don't handle count==2 */ 151: else if (count != (2*sizeof(Cardinal))) 152: /* must be a REJECT or ABORT message */ 153: /* let someone else handle it! */ 154: return(-1); 155: else { 156: /* must be a Courier version number */ 157: /* read it and throw it away */ 158: read(f->fd, (char*) &packbuf, sizeof(packbuf)); 159: f->state = inprogress; 160: /* fall into case inprogress */ 161: } 162: case inprogress: 163: switch (f->bdtstate) { 164: case wantdata: 165: count = recv(f->fd, (char*) &packbuf, sizeof(packbuf), 166: MSG_PEEK) 167: - sizeof(struct sphdr); 168: if (packbuf.hdr.sp_dt == SPPSST_RPC) 169: return(-1); 170: f->bdtstate = established; 171: /* fall through to case established */ 172: case established: 173: break; 174: /* fall out of inner (and outer!) switch */ 175: case bdteomseen: 176: return(0); 177: } 178: break; 179: } 180: MAKEVEC(0,&packbuf.hdr,sizeof(struct sphdr)); 181: MAKEVEC(1,buffer,nbytes); 182: count = readv(f->fd,our_iovec,2) - sizeof(struct sphdr); 183: /* at this point, we've read a packet that isn't SPPSST_RPC */ 184: while (TRUE) { 185: if (packbuf.hdr.sp_dt == SPPSST_END) { 186: (void) sppclosereply(f->fd); 187: f->state = closed; 188: fprintf(stderr,"SPP END received during BDT\n"); 189: exit(1); 190: } 191: if (packbuf.hdr.sp_dt != SPPSST_BDT) { 192: fprintf(stderr, 193: "wrong stream type, %d, seen during BDT\n", 194: packbuf.hdr.sp_dt); 195: exit(1); 196: /* NOTREACHED */ 197: } 198: if (f->abortseen || (packbuf.hdr.sp_cc & SP_OB)) { 199: f->abortseen = TRUE; 200: return(-1); 201: } 202: if (packbuf.hdr.sp_cc & SP_EM) { 203: f->bdtstate = bdteomseen; 204: /* next read will return 0 */ 205: return(count); 206: } 207: if (count > 0) 208: return(count); 209: count = readv(f->fd,our_iovec,2) - sizeof(struct sphdr); 210: } 211: } 212: 213: BDTabort(f) 214: register CourierConnection *f; 215: { 216: static struct handy { 217: struct sphdr hdr; 218: char value; 219: } data; 220: /* stream=BDT, EOM=FALSE, Attn=TRUE */ 221: data.hdr.sp_dt = SPPSST_BDT; 222: data.hdr.sp_cc = SP_EM; 223: data.value = 1; /* BDT abort data value */ 224: send(f->fd, &data, sizeof(data), MSG_OOB); 225: f->bdtstate = bdteomseen; 226: f->abortseen = TRUE; 227: } 228: 229: 230: BDTabortSeen(f) 231: register CourierConnection *f; 232: { 233: struct { 234: struct sphdr hdr; 235: Unspecified data[MAXWORDS]; 236: } packbuf; 237: int fdmask; 238: register int count; 239: static struct timeval timeout = {0,0}; 240: 241: fdmask = 1<<(f->fd); 242: /* ### code here for OOB signalling! */ 243: while (select(f->fd+1,&fdmask,(int*)NULL,(int*)NULL,&timeout) > 0 244: && (count = recv(f->fd,(char*)&packbuf, sizeof(packbuf), 245: MSG_PEEK) - sizeof(struct sphdr)) > 0) { 246: if (packbuf.hdr.sp_dt == SPPSST_BDT 247: && (packbuf.hdr.sp_dt & SP_OB) 248: && count == 1) { 249: read(f->fd, (char*)&packbuf, sizeof(packbuf)); 250: f->abortseen = TRUE; 251: return(TRUE); 252: } 253: else if (count == 0) 254: read(f->fd, (char*)&packbuf, sizeof(packbuf)); 255: else return(FALSE); 256: } 257: return(FALSE); 258: }