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

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: 

unix.superglobalmegacorp.com

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