Annotation of researchv9/X11/src/X.V11R1/server/os/v9/io.c, revision 1.1.1.1

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: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.