|
|
1.1 root 1: /***********************************************************
2: Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts,
3: and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
4:
5: All Rights Reserved
6:
7: Permission to use, copy, modify, and distribute this software and its
8: documentation for any purpose and without fee is hereby granted,
9: provided that the above copyright notice appear in all copies and that
10: both that copyright notice and this permission notice appear in
11: supporting documentation, and that the names of Digital or MIT not be
12: used in advertising or publicity pertaining to distribution of the
13: software without specific, written prior permission.
14:
15: DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
16: ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
17: DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
18: ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
19: WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
20: ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
21: SOFTWARE.
22:
23: ******************************************************************/
24: /* $Header: io.c,v 1.36 87/09/09 23:04:35 rws Exp $ */
25: /*****************************************************************
26: * i/o functions
27: *
28: * WriteToClient, ReadRequestFromClient
29: *
30: *****************************************************************/
31:
32: #include <stdio.h>
33: #include "Xmd.h"
34: #include <errno.h>
35: #include <sys/param.h>
36: #include <sys/types.h>
37: #include "X.h"
38: #include "Xproto.h"
39: #include "os.h"
40: #include "osdep.h"
41: #include "opaque.h"
42: #include "dixstruct.h"
43:
44: extern long ClientsWithInput[];
45: extern long PartialRequest;
46: extern ClientPtr ConnectionTranslation[];
47: static int timesThisConnection = 0;
48:
49: extern int errno;
50:
51: #define request_length(req, cli) ((cli->swapped ? \
52: lswaps((req)->length) : (req)->length) << 2)
53: #define MAX_TIMES_PER 10
54:
55: /*****************************************************************
56: * ReadRequestFromClient
57: * Returns one request from client. If the client misbehaves,
58: * returns NULL. The dispatcher closes down all misbehaving clients.
59: *
60: * client: index into bit array returned from WaitForSomething()
61: *
62: * status: status is set to
63: * > 0 the number of bytes in the request if the read is sucessful
64: * = 0 if action would block (entire request not ready)
65: * < 0 indicates an error (probably client died)
66: *
67: * oldbuf:
68: * To facilitate buffer management (e.g. on multi-processor
69: * systems), the diX layer must tell the OS layer when it is
70: * done with a request, so the parameter oldbuf is a pointer
71: * to a request that diX is finished with. In the
72: * sample implementation, which is single threaded,
73: * oldbuf is ignored. We assume that when diX calls
74: * ReadRequestFromClient(), the previous buffer is finished with.
75: *
76: * The returned string returned must be contiguous so that it can be
77: * cast in the dispatcher to the correct request type. Because requests
78: * are variable length, ReadRequestFromClient() must look at the first 4
79: * bytes of a request to determine the length (the request length is
80: * always the 3rd byte in the request).
81: *
82: * Note: in order to make the server scheduler (WaitForSomething())
83: * "fair", the ClientsWithInput mask is used. This mask tells which
84: * clients have FULL requests left in their buffers. Clients with
85: * partial requests require a read. Basically, client buffers
86: * are drained before select() is called again. But, we can't keep
87: * reading from a client that is sending buckets of data (or has
88: * a partial request) because others clients need to be scheduled.
89: *****************************************************************/
90:
91: ConnectionInput inputBuffers[MAXSOCKS]; /* buffers for clients */
92:
93: char *
94: ReadRequestFromClient(who, status, oldbuf)
95: ClientPtr who;
96: int *status; /* read at least n from client */
97: char *oldbuf;
98: {
99: int client = ((osPrivPtr)who->osPrivate)->fd;
100: int result, gotnow, needed;
101: register ConnectionInput *pBuff;
102: register xReq *request;
103:
104: /* ignore oldbuf, just assume we're done with prev. buffer */
105:
106: if (client == -1)
107: {
108: ErrorF( "OH NO, %d translates to -1\n", who);
109: return((char *)NULL);
110: }
111:
112: pBuff = &inputBuffers[client];
113: pBuff->bufptr += pBuff->lenLastReq;
114: pBuff->lenLastReq = 0;
115:
116: /* handle buffer empty or full case first */
117:
118: if ((pBuff->bufptr - pBuff->buffer >= pBuff->bufcnt) || (!pBuff->bufcnt))
119: {
120: result = read(client, pBuff->buffer, pBuff->size);
121: if (result <= 0)
122: {
123: *status = -1;
124: BITCLEAR(ClientsWithInput, client);
125: isItTimeToYield = TRUE;
126: return((char *)NULL);
127: }
128: else
129: {
130: pBuff->bufcnt = result;
131: pBuff->bufptr = pBuff->buffer;
132: }
133: }
134: /* now look if there is enough in the buffer */
135:
136: request = (xReq *)pBuff->bufptr;
137: gotnow = pBuff->bufcnt + pBuff->buffer - pBuff->bufptr;
138:
139: if (gotnow < sizeof(xReq))
140: needed = sizeof(xReq) - gotnow;
141: else
142: {
143: needed = request_length(request, who);
144: if (needed > MAXBUFSIZE)
145: {
146: *status = -1;
147: BITCLEAR(ClientsWithInput, client);
148: isItTimeToYield = TRUE;
149: return((char *)NULL);
150: }
151: if (needed <= 0)
152: needed = sizeof(xReq);
153: }
154: /* if the needed amount won't fit in what's remaining,
155: move everything to the front of the buffer. If the
156: entire header isn't available, move what's there too */
157: if ((pBuff->bufptr + needed - pBuff->buffer > pBuff->size) ||
158: (gotnow < sizeof(xReq)))
159: {
160: bcopy(pBuff->bufptr, pBuff->buffer, gotnow);
161: pBuff->bufcnt = gotnow;
162: if (needed > pBuff->size)
163: {
164: pBuff->size = needed;
165: pBuff->buffer = (char *)Xrealloc(pBuff->buffer, needed);
166: }
167: pBuff->bufptr = pBuff->buffer;
168: }
169: /* don't have a full header */
170: if (gotnow < sizeof(xReq))
171: {
172: while (pBuff->bufcnt + pBuff->buffer - pBuff->bufptr < sizeof(xReq))
173: {
174: result = read(client, pBuff->buffer + pBuff->bufcnt,
175: pBuff->size - pBuff->bufcnt);
176: if (result <= 0)
177: {
178: *status = -1;
179: BITCLEAR(ClientsWithInput, client);
180: isItTimeToYield = TRUE;
181: return((char *)NULL);
182: }
183: pBuff->bufcnt += result;
184: }
185: request = (xReq *)pBuff->bufptr;
186: gotnow = pBuff->bufcnt + pBuff->buffer - pBuff->bufptr;
187: needed = request_length(request, who);
188: if (needed <= 0)
189: needed = sizeof(xReq);
190: if (needed > pBuff->size)
191: {
192: pBuff->size = needed;
193: pBuff->buffer = (char *)Xrealloc(pBuff->buffer, needed);
194: }
195: pBuff->bufptr = pBuff->buffer;
196: }
197:
198: if (gotnow < needed )
199: {
200: int i, wanted;
201:
202: wanted = needed - gotnow;
203: i = 0;
204: while (i < wanted)
205: {
206: result = read(client, pBuff->buffer + pBuff->bufcnt,
207: pBuff->size - pBuff->bufcnt);
208: if (result <= 0) {
209: *status = -1;
210: BITCLEAR(ClientsWithInput, client);
211: isItTimeToYield = TRUE;
212: return((char *)NULL);
213: }
214: i += result;
215: pBuff->bufcnt += result;
216: }
217: }
218: *status = needed;
219: pBuff->lenLastReq = needed;
220:
221: /*
222: * Check to see if client has at least one whole request in the
223: * buffer. If there is only a partial request, treat like buffer
224: * is empty so that select() will be called again and other clients
225: * can get into the queue.
226: */
227:
228: if (pBuff->bufcnt + pBuff->buffer >= pBuff->bufptr + needed + sizeof(xReq))
229: {
230: request = (xReq *)(pBuff->bufptr + needed);
231: if ((pBuff->bufcnt + pBuff->buffer) >=
232: ((char *)request + request_length(request, who)))
233: BITSET(ClientsWithInput, client);
234: else
235: {
236: BITCLEAR(ClientsWithInput, client);
237: isItTimeToYield = TRUE;
238: }
239: }
240: else
241: {
242: BITCLEAR(ClientsWithInput, client);
243: isItTimeToYield = TRUE;
244: }
245: if ((++timesThisConnection == MAX_TIMES_PER) || (isItTimeToYield))
246: {
247: isItTimeToYield = TRUE;
248: timesThisConnection = 0;
249: }
250: return((char *)pBuff->bufptr);
251: }
252:
253:
254: /*****************
255: * WriteToClient
256: * We might have to wait, if the client isn't keeping up with us. We
257: * wait for a short time, then close the connection. This isn't a
258: * wonderful solution,
259: * but it rarely seems to be a problem right now, and buffering output for
260: * asynchronous delivery sounds complicated and expensive.
261: * Long word aligns all data.
262: * Makes assumption that at least three bytes after address given
263: * are writeable (used for padding)
264: *****************/
265:
266: /* lookup table for adding padding bytes to data that is read from
267: or written to the X socket. */
268: static int padlength[4] = {0, 3, 2, 1};
269:
270: int
1.1.1.2 ! root 271: WriteToClient (who, count, buf)
1.1 root 272: ClientPtr who;
273: char *buf;
1.1.1.2 ! root 274: int count;
1.1 root 275: {
276: #define OUTTIME 2
277: int connection = ((osPrivPtr)who->osPrivate)->fd;
1.1.1.2 ! root 278: int total;
1.1 root 279: register int n;
1.1.1.2 ! root 280: int mask[mskcnt];
! 281: int secondTime = 0;
1.1 root 282:
283: if (connection == -1)
284: {
285: ErrorF( "OH NO, %d translates to -1\n", connection);
286: return(-1);
287: }
288:
289: if (connection == -2)
290: {
291: #ifdef notdef
292: ErrorF( "CONNECTION %d ON ITS WAY OUT\n", connection);
293: #endif
294: return(-1);
295: }
296:
1.1.1.2 ! root 297: total = count + padlength[count & 3];
! 298: while ((n = write(connection, buf, total)) != total)
! 299: {
! 300: if (n > 0)
! 301: {
! 302: total -= n;
! 303: buf += n;
! 304: continue;
! 305: }
! 306: else if (errno != EBUSY)
! 307: {
! 308: close(connection);
! 309: MarkClientException(who);
! 310: return(-1);
! 311: }
! 312: /* blocked => be willing to try him once more */
! 313: CLEARBITS(mask);
! 314: BITSET(mask, connection);
! 315: n = select (connection + 1, (int *) NULL, mask, OUTTIME * 1000);
! 316: if ((n != 1) && (secondTime == 3))
! 317: {
! 318: /* this close will cause the select in WaitForSomething
! 319: to return that the connection is dead, so we can actually
! 320: clean up after the client. We can't clean up here,
! 321: because the we're in the middle of doing something
! 322: and will probably screw up some data strucutres */
! 323: close(connection);
! 324: MarkClientException(who);
! 325: return(-1);
! 326: }
! 327: else
! 328: secondTime++;
1.1 root 329: }
1.1.1.2 ! root 330: return(count);
1.1 root 331: }
332:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.