1: /* 2: * This file implements functions used by both client and servers in the 3: * XNS courier library 4: */ 5: 6: /* 7: $Log: readwrite.c,v $ 8: * Revision 2.0 85/11/21 07:22:15 jqj 9: * 4.3BSD standard release 10: * 11: * Revision 1.8 85/10/21 13:01:17 jqj 12: * Gould version. 13: * 14: * Revision 1.7 85/10/17 07:22:53 jqj 15: * Fix to previous edit. 16: * 17: * Revision 1.6 85/10/17 07:07:02 jqj 18: * ReadMessage had a typo which Gould compiler caught: bug in case of 19: * message with Courier header split across several SPP packets. 20: * 21: * Revision 1.5 85/09/27 16:01:23 jqj 22: * added error checking to read in ReadMessage to bomb on closed connections. 23: * 24: * Revision 1.4 85/03/11 16:37:24 jqj 25: * Public alpha-test version, released 11 March 1985 26: * 27: * Revision 1.3 85/02/22 09:27:40 bill 28: * Almost working version. Am about to change 29: * ReadMessage to match what really shows up from the Xerox stuff. 30: * 31: * Revision 1.2 85/01/27 07:37:39 jqj 32: * finished but undebugged version 33: * 34: */ 35: 36: #ifndef lint 37: static char rcsid[] = "$Header: readwrite.c,v 2.0 85/11/21 07:22:15 jqj Exp $"; 38: #endif 39: 40: #include <stdio.h> 41: #include <sys/types.h> /* for ns.h and socket.h */ 42: #include <sys/socket.h> 43: #include <sys/time.h> 44: #include <sys/uio.h> /* for scatter/gather io */ 45: #include <netns/ns.h> /* for XNS addresses and courierconnection.h */ 46: #include <netns/idp.h> 47: #include <netns/sp.h> /* for spphdr */ 48: #include <errno.h> /* for EPROTOTYPE */ 49: #include "courier.h" 50: #include "realcourierconnection.h" 51: 52: #define MAKEVEC(idx, addr, len) our_iovec[idx].iov_base = (caddr_t)addr;\ 53: our_iovec[idx].iov_len = len; 54: 55: 56: CourierWrite(f, hdrlen, hdrbuf, nwords, arguments) 57: /* write a 2-block message possibly consisting of several packets */ 58: register CourierConnection *f; 59: int hdrlen; /* length of hdrbuf, in words */ 60: Unspecified *hdrbuf; 61: register Cardinal nwords; /* length of arguments, in words */ 62: register Unspecified *arguments; 63: { 64: struct iovec our_iovec[3]; 65: 66: if (f->state == closed) { 67: f->abortseen = FALSE; 68: if ((f->fd = openSPPConnection(&(f->host))) >= 0) { 69: f->state = wantversion; 70: } 71: else { 72: fprintf(stderr,"(Courier) Can't reopen SPP connection\n"); 73: exit(1); 74: /* NOTREACHED */ 75: } 76: } 77: MAKEVEC(0, &(f->sphdrOpts), sizeof(f->sphdrOpts)); 78: MAKEVEC(1, hdrbuf, (hdrlen*sizeof(Unspecified)) ); 79: if (nwords <= MAXWORDS-hdrlen) { 80: /* SetSPPoptions(f->fd, SPPSST_RPC, 1, 0); 81: datastream=0, EOM=TRUE, Attn=FALSE */ 82: f->sphdrOpts.sp_dt = SPPSST_RPC; 83: f->sphdrOpts.sp_cc |= SP_EM; 84: MAKEVEC(2, arguments, nwords*sizeof(Unspecified)); 85: if (writev(f->fd, our_iovec, 3) < 0) { 86: perror("(Courier) writev"); 87: exit(1); 88: } 89: 90: } 91: else { 92: MAKEVEC(2, arguments, (MAXWORDS-hdrlen)*sizeof(Unspecified)); 93: /* SetSPPoptions(f->fd, SPPSST_RPC, 0, 0); 94: /* datastream=0, EOM=FALSE, Attn=FALSE */ 95: f->sphdrOpts.sp_dt = SPPSST_RPC; 96: f->sphdrOpts.sp_cc &= ~SP_EM; 97: nwords -= MAXWORDS-hdrlen; arguments += MAXWORDS-hdrlen; 98: if (writev(f->fd, our_iovec, 3) < 0) { 99: perror("(Courier) writev"); 100: exit(1); 101: } 102: MAKEVEC(1, (char *)arguments, MAXWORDS*sizeof(Unspecified)); 103: while (nwords > MAXWORDS) { 104: writev(f->fd, our_iovec, 2); 105: nwords -= MAXWORDS; arguments += MAXWORDS; 106: our_iovec[1].iov_base = (char *)arguments; 107: } 108: f->sphdrOpts.sp_cc |= SP_EM; 109: /* SetSPPoptions(f->fd, SPPSST_RPC, 1, 0); 110: /* datastream=0, EOM=TRUE, Attn=FALSE */ 111: our_iovec[1].iov_len = nwords*sizeof(Unspecified); 112: writev(f->fd, our_iovec, 2); 113: } 114: 115: } 116: 117: 118: 119: Unspecified * 120: ReadMessage(f, firstbuf, firstlength) 121: register CourierConnection *f; /* socket descriptor */ 122: Unspecified *firstbuf; 123: Cardinal firstlength; 124: /* Read a complete Courier message from SPP socket f->fd, skipping packets 125: * with the wrong datastream type. 126: * If firstbuf is specified with a non-zero length (in Unspecifieds), then it 127: * is filled before the malloced packet. 128: * Return a pointer to beginning of a malloced packet (caller is responsible 129: * for freeing it), and a length in *retlength 130: * Returns NULL if connection closes prematurely. 131: */ 132: { 133: char *buf; /* ptr to message buffer */ 134: Cardinal length, /* current message length, bytes */ 135: bufsize, /* current buffer size, bytes */ 136: nextincrement; /* amt of space to try for next */ 137: register int count; /* data bytes read by current readv() */ 138: struct iovec our_iovec[3]; 139: struct { 140: struct sphdr hdr; 141: Cardinal version[2]; 142: } hdrbuf; 143: Cardinal versionl, /* version numbers received */ 144: versionh; 145: int verbyteswanted; 146: extern char *malloc(), *realloc(); 147: extern free(); 148: int cc; 149: 150: /* spp & idp header */ 151: MAKEVEC(0, &hdrbuf.hdr, sizeof(struct sphdr)); 152: /* conn id, etc... */ 153: if (firstbuf == NULL) 154: firstlength = 0; 155: else 156: firstlength *= sizeof(Unspecified); /* length in bytes */ 157: MAKEVEC(1, firstbuf, firstlength); 158: /* data */ 159: buf = malloc(SPPMAXDATA); 160: MAKEVEC(2, buf, SPPMAXDATA); 161: 162: bufsize = SPPMAXDATA; 163: /* 164: * flush Courier version number if necessary 165: */ 166: if (f->state != wantversion) { 167: /* we don't have to look for a version number this time! */ 168: count = readv(f->fd, our_iovec, 3) - sizeof(struct sphdr); 169: if (count < 0 || hdrbuf.hdr.sp_dt == SPPSST_END) { 170: if (count >= 0) (void) sppclosereply(f->fd); 171: f->state = closed; 172: free(buf); 173: return(NULL); 174: } 175: } else { 176: /* stick version range in with header */ 177: verbyteswanted = 2*sizeof(Cardinal); 178: our_iovec[0].iov_len += verbyteswanted; 179: while (verbyteswanted > 0) { 180: count = readv(f->fd, our_iovec, 3) 181: - sizeof(struct sphdr); 182: if (count < 0 || hdrbuf.hdr.sp_dt == SPPSST_END) { 183: if (count >= 0) (void) sppclosereply(f->fd); 184: f->state = closed; 185: free(buf); 186: return(NULL); 187: } 188: /* we don't bother to check for matching */ 189: /* Courier version */ 190: if (count >= verbyteswanted) { 191: count -= verbyteswanted; 192: our_iovec[0].iov_len -= verbyteswanted; 193: verbyteswanted = 0; 194: } 195: else { 196: verbyteswanted -= count; 197: our_iovec[0].iov_len -= count; 198: count = 0; 199: } 200: } 201: f->state = inprogress; 202: while (count == 0) { 203: /* read either RPC reply or BDT garbage */ 204: count = readv(f->fd, our_iovec, 3) 205: - sizeof(struct sphdr); 206: if (count < 0 || hdrbuf.hdr.sp_dt == SPPSST_END) { 207: if (count >= 0) (void) sppclosereply(f->fd); 208: f->state = closed; 209: free(buf); 210: return(NULL); 211: } 212: } 213: /* {version-packet, null-0-packet, bdt-packet, reply-packet}, 214: * is handled, but I don't think it's legal */ 215: } 216: /* 217: * we've flushed any version number that might be present, 218: * and have read the first packet -- which may be garbage. 219: * Throw away any further garbage (e.g. BDT data) too. 220: */ 221: while (hdrbuf.hdr.sp_dt != SPPSST_RPC) { 222: count = readv(f->fd, our_iovec, 3) - sizeof(struct sphdr); 223: if (count < 0 || hdrbuf.hdr.sp_dt == SPPSST_END) { 224: if (count >= 0) (void) sppclosereply(f->fd); 225: f->state = closed; 226: free(buf); 227: return(NULL); 228: } 229: } 230: /* 231: * Now we have a real RPC data packet, which we hope is the reply 232: */ 233: length = count; 234: nextincrement = SPPMAXDATA; 235: while ( ! (hdrbuf.hdr.sp_cc & SP_EM)) { 236: /* Not to end of message yet, so read another packet */ 237: if (length+nextincrement-firstlength > bufsize) { 238: /* not enough space for next packet. Make room. */ 239: bufsize = length+nextincrement-firstlength; 240: buf = realloc(buf, (unsigned) bufsize); 241: /* do order(log(messagelength)) reallocs */ 242: nextincrement += nextincrement; 243: } 244: if (length >= firstlength) { 245: MAKEVEC(1,NULL,0); 246: MAKEVEC(2,buf+length-firstlength,bufsize+firstlength-length); 247: } 248: else { 249: firstbuf += length/sizeof(Unspecified); 250: firstlength -= length; 251: MAKEVEC(1, firstbuf, firstlength); 252: } 253: count = readv(f->fd, our_iovec, 3) - sizeof(struct sphdr); 254: if (count < 0 || hdrbuf.hdr.sp_dt == SPPSST_END) { 255: if (count >= 0) (void) sppclosereply(f->fd); 256: f->state = closed; 257: free(buf); 258: return(NULL); 259: } 260: if (hdrbuf.hdr.sp_dt != SPPSST_RPC) { 261: fprintf(stderr,"(Courier) Stream type changed from %d to %d during message\n", 262: SPPSST_RPC, hdrbuf.hdr.sp_dt); 263: exit(1); 264: /* NOTREACHED */ 265: } 266: length += count; 267: } 268: return((Unspecified*) buf); 269: } 270: 271: 272: 273: CheckEND(f) 274: /* look ahead on courier connection, checking for an END packet. 275: * If seen, set state to closed. 276: */ 277: CourierConnection *f; 278: { 279: struct { 280: struct sphdr hdr; 281: char data[SPPMAXDATA]; 282: } packbuf; 283: int count; 284: int fdmask; 285: static struct timeval timeout = {0,0}; 286: 287: fdmask = 1<<(f->fd); 288: while (select(f->fd+1,&fdmask,(int*)NULL,(int*)NULL,&timeout) > 0 289: && (count = recv(f->fd,(char*)&packbuf, sizeof(packbuf), 290: MSG_PEEK)) > 0) { 291: if (packbuf.hdr.sp_dt == SPPSST_END) { 292: read(f->fd, (char*)&packbuf, sizeof(packbuf)); 293: (void) sppclosereply(f->fd); 294: f->state = closed; 295: return(TRUE); 296: } 297: else if (count == sizeof(struct sphdr)) 298: read(f->fd, (char*)&packbuf, sizeof(packbuf)); 299: else return(FALSE); 300: } 301: return(FALSE); 302: } 303: 304: 305: CourierClose(conn) 306: CourierConnection * conn; 307: { 308: (void) sppclose(conn->fd); 309: free((char*) conn); 310: } 311: 312: 313: openSPPConnection(dst) 314: struct sockaddr_ns *dst; 315: { 316: int s; 317: extern int errno; 318: 319: if ((s = socket(dst->sns_family, SOCK_SEQPACKET, 0)) < 0) { 320: perror("(Courier) socket"); 321: exit(1); 322: /*NOTREACHED*/ 323: } 324: if (connect(s, (struct sockaddr*)dst, sizeof(struct sockaddr_ns)) < 0) { 325: perror("(Courier) connect"); 326: exit(1); 327: /*NOTREACHED*/ 328: } 329: return(s); 330: }