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