Annotation of researchv9/X11/src/X.V11R1/server/os/4.2bsd/io.c, revision 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 <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: 

unix.superglobalmegacorp.com

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