|
|
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
271: WriteToClient (who, cnt, buf)
272: ClientPtr who;
273: char *buf;
274: int cnt;
275: {
276: #define OUTTIME 2
277: int connection = ((osPrivPtr)who->osPrivate)->fd;
278: register int n;
279:
280: if (connection == -1)
281: {
282: ErrorF( "OH NO, %d translates to -1\n", connection);
283: return(-1);
284: }
285:
286: if (connection == -2)
287: {
288: #ifdef notdef
289: ErrorF( "CONNECTION %d ON ITS WAY OUT\n", connection);
290: #endif
291: return(-1);
292: }
293:
294: n = write(connection, buf, cnt + padlength[cnt & 3]);
295: if (n < cnt) {
296: close(connection);
297: MarkClientException(who);
298: return(-1);
299: }
300: return(cnt);
301: }
302:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.