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