|
|
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 <sys/uio.h>
38: #include <sys/time.h>
39: #include "X.h"
40: #include "Xproto.h"
41: #include "os.h"
42: #include "osdep.h"
43: #include "opaque.h"
44: #include "dixstruct.h"
45:
46: extern long ClientsWithInput[];
47: extern long PartialRequest;
48: extern ClientPtr ConnectionTranslation[];
49: static int timesThisConnection = 0;
50:
51: extern int errno;
52:
53: #define request_length(req, cli) ((cli->swapped ? \
54: lswaps((req)->length) : (req)->length) << 2)
55: #define MAX_TIMES_PER 10
56:
57: /*****************************************************************
58: * ReadRequestFromClient
59: * Returns one request from client. If the client misbehaves,
60: * returns NULL. The dispatcher closes down all misbehaving clients.
61: *
62: * client: index into bit array returned from WaitForSomething()
63: *
64: * status: status is set to
65: * > 0 the number of bytes in the request if the read is sucessful
66: * = 0 if action would block (entire request not ready)
67: * < 0 indicates an error (probably client died)
68: *
69: * oldbuf:
70: * To facilitate buffer management (e.g. on multi-processor
71: * systems), the diX layer must tell the OS layer when it is
72: * done with a request, so the parameter oldbuf is a pointer
73: * to a request that diX is finished with. In the
74: * sample implementation, which is single threaded,
75: * oldbuf is ignored. We assume that when diX calls
76: * ReadRequestFromClient(), the previous buffer is finished with.
77: *
78: * The returned string returned must be contiguous so that it can be
79: * cast in the dispatcher to the correct request type. Because requests
80: * are variable length, ReadRequestFromClient() must look at the first 4
81: * bytes of a request to determine the length (the request length is
82: * always the 3rd byte in the request).
83: *
84: * Note: in order to make the server scheduler (WaitForSomething())
85: * "fair", the ClientsWithInput mask is used. This mask tells which
86: * clients have FULL requests left in their buffers. Clients with
87: * partial requests require a read. Basically, client buffers
88: * are drained before select() is called again. But, we can't keep
89: * reading from a client that is sending buckets of data (or has
90: * a partial request) because others clients need to be scheduled.
91: *****************************************************************/
92:
93: ConnectionInput inputBuffers[MAXSOCKS]; /* buffers for clients */
94:
95: char *
96: ReadRequestFromClient(who, status, oldbuf)
97: ClientPtr who;
98: int *status; /* read at least n from client */
99: char *oldbuf;
100: {
101: int client = ((osPrivPtr)who->osPrivate)->fd;
102: int result, gotnow, needed;
103: register ConnectionInput *pBuff;
104: register xReq *request;
105:
106: /* ignore oldbuf, just assume we're done with prev. buffer */
107:
108: if (client == -1)
109: {
110: ErrorF( "OH NO, %d translates to -1\n", who);
111: return((char *)NULL);
112: }
113:
114: pBuff = &inputBuffers[client];
115: pBuff->bufptr += pBuff->lenLastReq;
116: pBuff->lenLastReq = 0;
117:
118: /* handle buffer empty or full case first */
119:
120: if ((pBuff->bufptr - pBuff->buffer >= pBuff->bufcnt) || (!pBuff->bufcnt))
121: {
122: result = read(client, pBuff->buffer, pBuff->size);
123: if (result < 0)
124: {
125: if (errno == EWOULDBLOCK)
126: *status = 0;
127: else
128: *status = -1;
129: BITCLEAR(ClientsWithInput, client);
130: isItTimeToYield = TRUE;
131: return((char *)NULL);
132: }
133: else if (result == 0)
134: {
135: BITCLEAR(ClientsWithInput, client);
136: isItTimeToYield = TRUE;
137: *status = -1;
138: return((char *) NULL);
139: }
140: else
141: {
142: pBuff->bufcnt = result;
143: pBuff->bufptr = pBuff->buffer;
144: }
145: }
146: /* now look if there is enough in the buffer */
147:
148: request = (xReq *)pBuff->bufptr;
149: gotnow = pBuff->bufcnt + pBuff->buffer - pBuff->bufptr;
150:
151: if (gotnow < sizeof(xReq))
152: needed = sizeof(xReq) - gotnow;
153: else
154: {
155: needed = request_length(request, who);
156: if (needed > MAXBUFSIZE)
157: {
158: *status = -1;
159: BITCLEAR(ClientsWithInput, client);
160: isItTimeToYield = TRUE;
161: return((char *)NULL);
162: }
163: if (needed <= 0)
164: needed = sizeof(xReq);
165: }
166: /* if the needed amount won't fit in what's remaining,
167: move everything to the front of the buffer. If the
168: entire header isn't available, move what's there too */
169: if ((pBuff->bufptr + needed - pBuff->buffer > pBuff->size) ||
170: (gotnow < sizeof(xReq)))
171: {
172: bcopy(pBuff->bufptr, pBuff->buffer, gotnow);
173: pBuff->bufcnt = gotnow;
174: if (needed > pBuff->size)
175: {
176: pBuff->size = needed;
177: pBuff->buffer = (char *)Xrealloc(pBuff->buffer, needed);
178: }
179: pBuff->bufptr = pBuff->buffer;
180: }
181: /* don't have a full header */
182: if (gotnow < sizeof(xReq))
183: {
184: while (pBuff->bufcnt + pBuff->buffer - pBuff->bufptr < sizeof(xReq))
185: {
186: result = read(client, pBuff->buffer + pBuff->bufcnt,
187: pBuff->size - pBuff->bufcnt);
188: if (result < 0) {
189: if (errno == EWOULDBLOCK)
190: *status = 0;
191: else
192: *status = -1;
193: BITCLEAR(ClientsWithInput, client);
194: isItTimeToYield = TRUE;
195: return((char *)NULL);
196: }
197: if (result == 0) {
198: *status = -1;
199: BITCLEAR(ClientsWithInput, client);
200: isItTimeToYield = TRUE;
201: return((char *)NULL);
202: }
203: pBuff->bufcnt += result;
204: }
205: request = (xReq *)pBuff->bufptr;
206: gotnow = pBuff->bufcnt + pBuff->buffer - pBuff->bufptr;
207: needed = request_length(request, who);
208: if (needed <= 0)
209: needed = sizeof(xReq);
210: if (needed > pBuff->size)
211: {
212: pBuff->size = needed;
213: pBuff->buffer = (char *)Xrealloc(pBuff->buffer, needed);
214: }
215: pBuff->bufptr = pBuff->buffer;
216: }
217:
218: if (gotnow < needed )
219: {
220: int i, wanted;
221:
222: wanted = needed - gotnow;
223: i = 0;
224: while (i < wanted)
225: {
226: result = read(client, pBuff->buffer + pBuff->bufcnt,
227: pBuff->size - pBuff->bufcnt);
228: if (result < 0)
229: {
230: if (errno == EWOULDBLOCK)
231: *status = 0;
232: else
233: *status = -1;
234: BITCLEAR(ClientsWithInput, client);
235: isItTimeToYield = TRUE;
236: return((char *)NULL);
237: }
238: else if (result == 0)
239: {
240: *status = -1;
241: BITCLEAR(ClientsWithInput, client);
242: isItTimeToYield = TRUE;
243: return((char *)NULL);
244: }
245: i += result;
246: pBuff->bufcnt += result;
247: }
248: }
249: *status = needed;
250: pBuff->lenLastReq = needed;
251:
252: /*
253: * Check to see if client has at least one whole request in the
254: * buffer. If there is only a partial request, treat like buffer
255: * is empty so that select() will be called again and other clients
256: * can get into the queue.
257: */
258:
259: if (pBuff->bufcnt + pBuff->buffer >= pBuff->bufptr + needed + sizeof(xReq))
260: {
261: request = (xReq *)(pBuff->bufptr + needed);
262: if ((pBuff->bufcnt + pBuff->buffer) >=
263: ((char *)request + request_length(request, who)))
264: BITSET(ClientsWithInput, client);
265: else
266: {
267: BITCLEAR(ClientsWithInput, client);
268: isItTimeToYield = TRUE;
269: }
270: }
271: else
272: {
273: BITCLEAR(ClientsWithInput, client);
274: isItTimeToYield = TRUE;
275: }
276: if ((++timesThisConnection == MAX_TIMES_PER) || (isItTimeToYield))
277: {
278: isItTimeToYield = TRUE;
279: timesThisConnection = 0;
280: }
281: return((char *)pBuff->bufptr);
282: }
283:
284:
285: /*****************
286: * WriteToClient
287: * We might have to wait, if the client isn't keeping up with us. We
288: * wait for a short time, then close the connection. This isn't a
289: * wonderful solution,
290: * but it rarely seems to be a problem right now, and buffering output for
291: * asynchronous delivery sounds complicated and expensive.
292: * Long word aligns all data.
293: *****************/
294:
295: /* lookup table for adding padding bytes to data that is read from
296: or written to the X socket. */
297: static int padlength[4] = {0, 3, 2, 1};
298:
299: int
300: WriteToClient (who, count, buf)
301: ClientPtr who;
302: char *buf;
303: int count;
304: {
305: #define OUTTIME 2
306: int connection = ((osPrivPtr)who->osPrivate)->fd;
307: int total;
308: register int n;
309: int mask[mskcnt];
310: struct timeval outtime;
311: struct iovec iov[2];
312: char pad[3];
313: int secondTime = 0;
314:
315: outtime.tv_sec = (long) OUTTIME;
316: outtime.tv_usec = 0;
317:
318: if (connection == -1)
319: {
320: ErrorF( "OH NO, %d translates to -1\n", connection);
321: return(-1);
322: }
323:
324: if (connection == -2)
325: {
326: #ifdef notdef
327: ErrorF( "CONNECTION %d ON ITS WAY OUT\n", connection);
328: #endif
329: return(-1);
330: }
331:
332: iov[0].iov_len = count;
333: iov[0].iov_base = buf;
334: iov[1].iov_len = padlength[count & 3];
335: iov[1].iov_base = pad;
336:
337: total = iov[0].iov_len + iov[1].iov_len;
338: while ((n = writev (connection, iov, 2)) != total)
339: {
340: if (n > 0)
341: {
342: total -= n;
343: if ((iov[0].iov_len -= n) < 0)
344: {
345: iov[1].iov_len += iov[0].iov_len;
346: iov[1].iov_base -= iov[0].iov_len;
347: iov[0].iov_len = 0;
348: }
349: else
350: iov[0].iov_base += n;
351: continue;
352: }
353: else if (errno != EWOULDBLOCK)
354: {
355: #ifdef notdef
356: if (errno != EBADF)
357: ErrorF("Closing connection %d because write failed\n",
358: connection);
359: /* this close will cause the select in WaitForSomething
360: to return that the connection is dead, so we can actually
361: clean up after the client. We can't clean up here,
362: because the we're in the middle of doing something
363: and will probably screw up some data strucutres */
364: #endif
365: close(connection);
366: MarkClientException(who);
367: return(-1);
368: }
369: /* blocked => be willing to try him once more */
370: #ifdef notdef
371: ErrorF("Connection %d blocked, be willing to try write once more:\n",
372: connection);
373: ErrorF("need to write: %d, have written: %d, errno: %d\n",
374: total, n, errno);
375: #endif
376: CLEARBITS(mask);
377: BITSET(mask, connection);
378: n = select (connection + 1, (int *) NULL, mask, (int *) NULL,
379: &outtime);
380: if ((n != 1) && (secondTime == 3))
381: {
382: #ifdef notdef
383: ErrorF("Connection %d write failed after partial\n", connection);
384: #endif
385: /* this close will cause the select in WaitForSomething
386: to return that the connection is dead, so we can actually
387: clean up after the client. We can't clean up here,
388: because the we're in the middle of doing something
389: and will probably screw up some data strucutres */
390: close(connection);
391: MarkClientException(who);
392: return(-1);
393: }
394: else
395: secondTime++;
396: }
397: return(count);
398: }
399:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.