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