|
|
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.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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.