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