|
|
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.