Annotation of researchv9/X11/src/X.V11R1/server/os/v9/connection.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: connection.c,v 1.62 87/09/07 17:12:18 rws Exp $ */
        !            25: /*****************************************************************
        !            26:  *  Stuff to create connections --- OS dependent
        !            27:  *
        !            28:  *      EstablishNewConnections, CreateWellKnownSockets,
        !            29:  *      CloseDownConnection, CheckConnections, AddEnabledDevice,
        !            30:  *     RemoveEnabledDevice, OnlyListToOneClient,
        !            31:  *      ListenToAllClients,
        !            32:  *
        !            33:  *      (WaitForSomething is in its own file)
        !            34:  *
        !            35:  *      In this implementation, a client socket table is not kept.
        !            36:  *      Instead, what would be the index into the table is just the
        !            37:  *      file descriptor of the socket.  This won't work for if the
        !            38:  *      socket ids aren't small nums (0 - 2^8)
        !            39:  *
        !            40:  *****************************************************************/
        !            41: 
        !            42: #undef NULL
        !            43: #include "X.h"
        !            44: #include "Xproto.h"
        !            45: #include <sys/param.h>
        !            46: #include <errno.h>
        !            47: #include <sys/types.h>
        !            48: #include <sys/filio.h>
        !            49: #include <signal.h>
        !            50: #include <setjmp.h>
        !            51: #include <ipc.h>
        !            52: #include <stdio.h>
        !            53: #include <strings.h>
        !            54: #include "osstruct.h"
        !            55: #include "osdep.h"
        !            56: #include "opaque.h"
        !            57: 
        !            58: #include "dixstruct.h"
        !            59: 
        !            60: char *display;                 /* The display number */
        !            61: int lastfdesc;                  /* maximum file descriptor */
        !            62: 
        !            63: long WellKnownConnections;    /* Listener mask */
        !            64: long EnabledDevices;           /* mask for input devices that are on */
        !            65: long AllSockets[mskcnt];        /* select on this */
        !            66: long AllClients[mskcnt];              /* available clients */
        !            67: long LastSelectMask[mskcnt];          /* mask returned from last select call */
        !            68: long ClientsWithInput[mskcnt];
        !            69: long MaxClients = MAXSOCKS ;
        !            70: long NConnBitArrays = mskcnt;
        !            71: long FirstClient;
        !            72: 
        !            73: static Bool debug_conns = FALSE;
        !            74: 
        !            75: static char whichByteIsFirst;
        !            76: 
        !            77: static int SavedAllClients[mskcnt];
        !            78: static int SavedAllSockets[mskcnt];
        !            79: static int SavedClientsWithInput[mskcnt];
        !            80: static Bool GrabDone = FALSE;
        !            81: 
        !            82: ClientPtr ConnectionTranslation[MAXSOCKS];
        !            83: extern ClientPtr NextAvailableClient();
        !            84: 
        !            85: extern ConnectionInput inputBuffers[];
        !            86: 
        !            87: int swappedClients[MAXSOCKS];
        !            88: 
        !            89: extern int AutoResetServer();
        !            90: extern int GiveUp();
        !            91: 
        !            92: /*****************
        !            93:  * CreateWellKnownSockets
        !            94:  *    At initialization, create the sockets to listen on for new clients.
        !            95:  *    There are potentially 4: DECnet, UNIX Domain, TCP-IP with MSB first, 
        !            96:  *    with TCP-IP with LSB first.
        !            97:  *****************/
        !            98: 
        !            99: void
        !           100: CreateWellKnownSockets()
        !           101: {
        !           102:     char       fname[32];
        !           103:     char       port[32];
        !           104:     int                request, i;
        !           105:     int                whichbyte;          /* used to figure out whether this is
        !           106:                                         LSB or MSB */
        !           107:     int retry;
        !           108: 
        !           109:     CLEARBITS(AllSockets);
        !           110:     CLEARBITS(AllClients);
        !           111:     CLEARBITS(LastSelectMask);
        !           112:     CLEARBITS(ClientsWithInput);
        !           113: 
        !           114:     for (i=0; i<MAXSOCKS; i++) ConnectionTranslation[i] = (ClientPtr)NULL;
        !           115:     
        !           116:     lastfdesc = MAXSOCKS - 1;
        !           117: 
        !           118:        /* hack test to decide where to log errors */
        !           119: 
        !           120:     if (write (2, fname, 0)) 
        !           121:     {
        !           122:        long t; 
        !           123: 
        !           124:        char *ctime();
        !           125:         close(stdin);
        !           126:         close(stdout);
        !           127:        strcpy (fname, "/usr/adm/X");
        !           128:        strcat (fname, display);
        !           129:        strcat (fname, "msgs");
        !           130:        freopen (fname, "a+", stderr);
        !           131:        time (&t);
        !           132:        fprintf (stderr, "start %s", ctime(&t));
        !           133:     }
        !           134:        if (getpgrp (0) == 0)
        !           135:            setpgrp (0, getpid ());
        !           136: 
        !           137:     WellKnownConnections = 0;
        !           138:     whichbyte = 1;
        !           139:     
        !           140:     if (*(char *) &whichbyte)
        !           141:         whichByteIsFirst = 'l';
        !           142:     else
        !           143:         whichByteIsFirst = 'B';
        !           144: 
        !           145: 
        !           146:     retry = 10;
        !           147:     sprintf(port, "/cs/tcp.%d", atoi (display) + X_TCP_PORT);
        !           148:     while ((request = ipccreat(port, "heavy")) < 0) 
        !           149:     {
        !           150:         if (--retry == 0)
        !           151:                Notice ("Binding TCP socket");
        !           152:         sleep (10);
        !           153:     }
        !           154:     WellKnownConnections |= (1 << request);
        !           155:     DefineSelf (request);
        !           156: 
        !           157:     if (WellKnownConnections == 0)
        !           158:         Error ("No Listeners, nothing to do");
        !           159:     signal (SIGPIPE, SIG_IGN);
        !           160:     signal (SIGHUP, AutoResetServer);
        !           161:     signal (SIGINT, GiveUp);
        !           162:     signal (SIGTERM, GiveUp);
        !           163:     FirstClient = request + 1;
        !           164:     AllSockets[0] = WellKnownConnections;
        !           165:     ResetHosts(display);
        !           166: 
        !           167:     for (i=0; i<MaxClients; i++)
        !           168:     {
        !           169:        inputBuffers[i].buffer = (char *) NULL;
        !           170:        inputBuffers[i].bufptr = (char *) NULL;
        !           171:        inputBuffers[i].bufcnt = 0;
        !           172:        inputBuffers[i].lenLastReq = 0;
        !           173:        inputBuffers[i].size = 0;
        !           174:     }
        !           175: }
        !           176: 
        !           177: /* We want to read the connection information.  If the client doesn't
        !           178:  * send us enough data, however, we want to time out eventually.
        !           179:  * The scheme is to clear a flag, set an alarm, and keep doing non-blocking
        !           180:  * reads until we get all the data we want. If the alarm goes
        !           181:  * off, the handler will clear the flag.  If we see that the flag is
        !           182:  * cleared, we know we've timed out and return with an error.
        !           183:  *
        !           184:  * there remains one problem with this code:
        !           185:  * there is a window of vulnerability in which we might get an alarm
        !           186:  * even though all the data has come in properly.  This is because I
        !           187:  * can't atomically clear the alarm.
        !           188:  * 
        !           189:  * Anyone who sees how to fix this problem should do so and
        !           190:  * submit a fix.
        !           191:  */
        !           192: 
        !           193: jmp_buf        env;
        !           194: void TimeOut()
        !           195: {
        !           196:     longjmp(env, 1);
        !           197: }
        !           198: static Bool 
        !           199: ReadBuffer(conn, buffer, charsWanted)
        !           200:     long conn;
        !           201:     char *buffer;
        !           202:     int charsWanted;
        !           203: {
        !           204:     char *bptr = buffer;
        !           205:     int got, fTimeOut;
        !           206: 
        !           207:     signal(SIGALRM, TimeOut);
        !           208:     fTimeOut = FALSE;
        !           209:     /* only 1 alarm, please, not 1 per minute */
        !           210:     alarm(TimeOutValue);
        !           211:     /* It better not take a full minute to get to the read call */
        !           212: 
        !           213:     while (charsWanted && (fTimeOut = setjmp(env)) == FALSE)
        !           214:     {
        !           215:        got = read(conn, bptr, charsWanted);    
        !           216:        if (got <= 0)
        !           217:            return FALSE;
        !           218:        if(got > 0)
        !           219:        {
        !           220:            charsWanted -= got;
        !           221:            bptr += got;
        !           222:            /* Ok, we got something, reset the timer */
        !           223:            alarm(TimeOutValue);
        !           224:        }
        !           225:     }
        !           226:     /* disable the timer */
        !           227:     alarm(0);
        !           228:     /* If we got here and we didn't time out, then return TRUE, because
        !           229:      * we must have read what we wanted. If we timed out, return FALSE */
        !           230:     if(fTimeOut && debug_conns)
        !           231:        ErrorF("Timed out on connection %d\n", conn);
        !           232:     return (!fTimeOut);
        !           233: }
        !           234: 
        !           235: /*****************************************************************
        !           236:  * ClientAuthorized
        !           237:  *
        !           238:  *    Sent by the client at connection setup:
        !           239:  *                typedef struct _xConnClientPrefix {
        !           240:  *                   CARD8     byteOrder;
        !           241:  *                   BYTE      pad;
        !           242:  *                   CARD16    majorVersion, minorVersion;
        !           243:  *                   CARD16    nbytesAuthProto;    
        !           244:  *                   CARD16    nbytesAuthString;   
        !           245:  *                 } xConnClientPrefix;
        !           246:  *
        !           247:  *             It is hoped that eventually one protocol will be agreed upon.  In the
        !           248:  *        mean time, a server that implements a different protocol than the
        !           249:  *        client expects, or a server that only implements the host-based
        !           250:  *        mechanism, will simply ignore this information.
        !           251:  *
        !           252:  *****************************************************************/
        !           253: 
        !           254: int 
        !           255: ClientAuthorized(conn, pswapped, reason)
        !           256:     long conn;
        !           257:     int  *pswapped;
        !           258:     char **reason;   /* if authorization fails, put reason in here */
        !           259: {
        !           260:     short slen;
        !           261:     xConnClientPrefix xccp;
        !           262:     char auth_proto[100];
        !           263:     char auth_string[100];
        !           264: 
        !           265:     if (!ReadBuffer(conn, &xccp, sizeof(xConnClientPrefix)))
        !           266:     {
        !           267:        /* If they can't even give us this much, just blow them off
        !           268:         * without an error message */
        !           269:        *reason = 0;
        !           270:         return 0;
        !           271:     }
        !           272:     if (xccp.byteOrder != whichByteIsFirst)
        !           273:     {        
        !           274:        SwapConnClientPrefix(&xccp);
        !           275:        *pswapped = TRUE;
        !           276:     }
        !           277:     else
        !           278:         *pswapped = FALSE;
        !           279:     if ((xccp.majorVersion != X_PROTOCOL) ||
        !           280:        (xccp.minorVersion != X_PROTOCOL_REVISION))
        !           281:     {        
        !           282: #define STR "Protocol version mismatch"
        !           283:         *reason = (char *)Xalloc(strlen(STR) + 1);
        !           284:         strcpy(*reason, STR);
        !           285:        if (debug_conns)
        !           286:            ErrorF("%s\n", STR);
        !           287: #undef STR
        !           288:         return 0;
        !           289:     }
        !           290:     
        !           291:    slen = (xccp.nbytesAuthProto + 3) & ~3;  
        !           292:     if ( slen )
        !           293:         if (!ReadBuffer(conn, auth_proto, slen))
        !           294:         {
        !           295: #define STR "Length error in xConnClientPrefix for protocol authorization "
        !           296:             *reason = (char *)Xalloc(strlen(STR));
        !           297:             strcpy(*reason, STR);
        !           298:             return 0;
        !           299: #undef STR
        !           300:        }
        !           301:     auth_proto[slen] = '\0';
        !           302: 
        !           303:     slen = (xccp.nbytesAuthString + 3) & ~3;   
        !           304:     if ( slen)
        !           305:         if (!ReadBuffer(conn, auth_string, slen))
        !           306:         {
        !           307: #define STR "Length error in xConnClientPrefix for protocol string"
        !           308:             *reason = (char *)Xalloc(strlen(STR));
        !           309:             strcpy(*reason, STR);
        !           310:             return 0;
        !           311: #undef STR
        !           312:        }
        !           313:     auth_string[slen] = '\0';
        !           314: 
        !           315:     /* At this point, if the client is authorized to change the access control
        !           316:      * list, we should getpeername() information, and add the client to
        !           317:      * the selfhosts list.  It's not really the host machine, but the
        !           318:      * true purpose of the selfhosts list is to see who may change the
        !           319:      * access control list.
        !           320:      */
        !           321:     return(1);
        !           322: }    
        !           323: 
        !           324: static int padlength[4] = {0, 3, 2, 1};
        !           325: 
        !           326: /*****************
        !           327:  * EstablishNewConnections
        !           328:  *    If anyone is waiting on listened sockets, accept them.
        !           329:  *    Returns a mask with indices of new clients.  Updates AllClients
        !           330:  *    and AllSockets.
        !           331:  *****************/
        !           332: 
        !           333: void
        !           334: EstablishNewConnections(newclients, nnew)
        !           335:     ClientPtr          *newclients;
        !           336:     int                *nnew;
        !           337: {
        !           338:     long readyconnections;     /* mask of listeners that are ready */
        !           339:     long curconn;                  /* fd of listener that's ready */
        !           340:     long newconn;                  /* fd of new client */
        !           341:     int         swapped;               /* set by ClientAuthorized if connection is
        !           342:                                 * swapped */
        !           343:     char *reason;
        !           344:     ipcinfo *ip;
        !           345: 
        !           346:     *nnew = 0;
        !           347:     if (readyconnections = (LastSelectMask[0] & WellKnownConnections)) 
        !           348:     {
        !           349:        while (readyconnections) 
        !           350:        {
        !           351:            curconn = ffs (readyconnections) - 1;
        !           352:            if ((ip = ipclisten(curconn)) && (newconn = ipcaccept(ip)) >= 0)
        !           353:            {
        !           354:                if (newconn >= lastfdesc)
        !           355:                {
        !           356:                    if (debug_conns)
        !           357: ErrorF("Didn't make connection: Out of file descriptors for connections\n");
        !           358:                    close (newconn);
        !           359:                } 
        !           360:                else 
        !           361:                {
        !           362:                    if (ClientAuthorized(newconn, &swapped, &reason))
        !           363:                    {
        !           364:                        ClientPtr next;
        !           365: 
        !           366:                        (void) ioctl(newconn, FIOWNBLK, 0);
        !           367:                        inputBuffers[newconn].used = 1; 
        !           368:                         if (! inputBuffers[newconn].size) 
        !           369:                        {
        !           370:                            inputBuffers[newconn].buffer = 
        !           371:                                        (char *)Xalloc(BUFSIZE);
        !           372:                            inputBuffers[newconn].size = BUFSIZE;
        !           373:                            inputBuffers[newconn].bufptr =      
        !           374:                                        inputBuffers[newconn].buffer;
        !           375:                        }
        !           376:                        if (GrabDone)
        !           377:                        {
        !           378:                            BITSET(SavedAllClients, newconn);
        !           379:                            BITSET(SavedAllSockets, newconn);
        !           380:                        }
        !           381:                        else
        !           382:                        {
        !           383:                            BITSET(AllClients, newconn);
        !           384:                            BITSET(AllSockets, newconn);
        !           385:                        }
        !           386:                        next = NextAvailableClient();
        !           387:                        if (next != (ClientPtr)NULL)
        !           388:                        {
        !           389:                           osPrivPtr priv;
        !           390: 
        !           391:                           newclients[(*nnew)++] = next;
        !           392:                           next->swapped = swapped;
        !           393:                           ConnectionTranslation[newconn] = next;
        !           394:                           priv =  (osPrivPtr)Xalloc(sizeof(osPrivRec));
        !           395:                           priv->fd = newconn;
        !           396:                           next->osPrivate = (pointer)priv;
        !           397:                        }
        !           398:                    }
        !           399:                    else
        !           400:                    {
        !           401:                        xConnSetupPrefix c;
        !           402: 
        !           403:                        if(reason)
        !           404:                        {
        !           405:                            c.success = xFalse;
        !           406:                            c.lengthReason = strlen(reason);
        !           407:                            c.length = (c.lengthReason + 3) >> 2;
        !           408:                            c.majorVersion = X_PROTOCOL;
        !           409:                            c.minorVersion = X_PROTOCOL_REVISION;
        !           410:                            if(swapped)
        !           411:                            {
        !           412:                                int     n;
        !           413: 
        !           414:                                swaps(&c.majorVersion, n);
        !           415:                                swaps(&c.minorVersion, n);
        !           416:                                swaps(&c.length, n);
        !           417:                            }
        !           418: 
        !           419:                            write(newconn, &c, sizeof(xConnSetupPrefix)); 
        !           420:                            write(newconn, reason,
        !           421:                                c.lengthReason+padlength[strlen(reason) & 3]);
        !           422:                            if (debug_conns)
        !           423:                                ErrorF("Didn't make connection:%s\n", reason);
        !           424:                        }
        !           425:                        close(newconn);
        !           426:                        Xfree(reason);
        !           427:                    }
        !           428: 
        !           429:                }
        !           430:            }
        !           431:            readyconnections &= ~(1 << curconn);
        !           432:        }
        !           433:     }
        !           434: }
        !           435: 
        !           436: /************
        !           437:  *   CloseDwonFileDescriptor:
        !           438:  *     Remove this file descriptor and it's inputbuffers, etc.
        !           439:  ************/
        !           440: 
        !           441: void
        !           442: CloseDownFileDescriptor(connection)
        !           443:     long connection;
        !           444: {
        !           445:     close(connection);
        !           446: 
        !           447:     inputBuffers[connection].bufptr = inputBuffers[connection].buffer;
        !           448:     inputBuffers[connection].bufcnt = 0;
        !           449:     inputBuffers[connection].lenLastReq = 0;
        !           450:     inputBuffers[connection].used = 0;
        !           451: 
        !           452:     BITCLEAR(AllSockets, connection);
        !           453:     BITCLEAR(AllClients, connection);
        !           454:     BITCLEAR(ClientsWithInput, connection);
        !           455: 
        !           456: }
        !           457: 
        !           458: /*****************
        !           459:  * CheckConections
        !           460:  *    Some connection has died, go find which one and shut it down 
        !           461:  *    The file descriptor has been closed, but is still in AllClients.
        !           462:  *    If would truly be wonderful if select() would put the bogus
        !           463:  *    file descriptors in the exception mask, but nooooo.  So we have
        !           464:  *    to check each and every socket individually.
        !           465:  *****************/
        !           466: 
        !           467: void
        !           468: CheckConnections()
        !           469: {
        !           470:     long               mask[mskcnt];
        !           471:     long               tmask[mskcnt]; 
        !           472:     register int       curclient;
        !           473:     int                        i;
        !           474:     ClientPtr           bad;
        !           475:     int r;
        !           476: 
        !           477:     COPYBITS(AllClients, mask);
        !           478:     for (i=0; i<mskcnt; i++)
        !           479:     {
        !           480:         while (mask[i])
        !           481:        {
        !           482:            curclient = ffs (mask[i]) - 1 + (i << 5);
        !           483:             CLEARBITS(tmask);
        !           484:             BITSET(tmask, curclient);
        !           485:             r = select (curclient + 1, tmask, (int *)NULL, 0);
        !           486:             if (r < 0)
        !           487:             {
        !           488:                if (bad = ConnectionTranslation[curclient])
        !           489:                    CloseDownClient(bad);
        !           490:                 else
        !           491:                     CloseDownFileDescriptor(curclient);
        !           492:             }
        !           493:            BITCLEAR(mask, curclient);
        !           494:        }
        !           495:     }  
        !           496: }
        !           497: 
        !           498: 
        !           499: /*****************
        !           500:  * CloseDownConnection
        !           501:  *    Delete client from AllClients and free resources 
        !           502:  *****************/
        !           503: 
        !           504: CloseDownConnection(client)
        !           505:     ClientPtr client;
        !           506: {
        !           507:     int connection = ((osPrivPtr)client->osPrivate)->fd;
        !           508: 
        !           509:     ConnectionTranslation[connection] = (ClientPtr)NULL;
        !           510:     CloseDownFileDescriptor(connection);
        !           511:     Xfree(client->osPrivate);
        !           512: }
        !           513: 
        !           514: 
        !           515: AddEnabledDevice(fd)
        !           516:     int fd;
        !           517: {
        !           518:     EnabledDevices |= (1<<fd);
        !           519:     BITSET(AllSockets, fd);
        !           520: }
        !           521: 
        !           522: 
        !           523: RemoveEnabledDevice(fd)
        !           524:     int fd;
        !           525: {
        !           526:     EnabledDevices &= ~(1<<fd);
        !           527:     BITCLEAR(AllSockets, fd);
        !           528: }
        !           529: 
        !           530: /*****************
        !           531:  * OnlyListenToOneClient:
        !           532:  *    Only accept requests from  one client.  Continue to handle new
        !           533:  *    connections, but don't take any protocol requests from the new
        !           534:  *    ones.  Note that if GrabDone is set, EstablishNewConnections
        !           535:  *    needs to put new clients into SavedAllSockets and SavedAllClients.
        !           536:  *    Note also that there is no timeout for this in the protocol.
        !           537:  *    This routine is "undone" by ListenToAllClients()
        !           538:  *****************/
        !           539: 
        !           540: OnlyListenToOneClient(client)
        !           541:     ClientPtr client;
        !           542: {
        !           543:     int connection = ((osPrivPtr)client->osPrivate)->fd;
        !           544: 
        !           545:     if (! GrabDone)
        !           546:     {
        !           547:        COPYBITS (ClientsWithInput, SavedClientsWithInput);
        !           548:         BITCLEAR (SavedClientsWithInput, connection);
        !           549:        if (GETBIT(ClientsWithInput, connection))
        !           550:        {
        !           551:            CLEARBITS(ClientsWithInput);            
        !           552:            BITSET(ClientsWithInput, connection);
        !           553:        }
        !           554:        else
        !           555:         {
        !           556:            CLEARBITS(ClientsWithInput);            
        !           557:        }
        !           558:        COPYBITS(AllSockets, SavedAllSockets);
        !           559:        COPYBITS(AllClients, SavedAllClients);
        !           560: 
        !           561:        UNSETBITS(AllSockets, AllClients);
        !           562:        BITSET(AllSockets, connection);
        !           563:        CLEARBITS(AllClients);
        !           564:        BITSET(AllClients, connection);
        !           565:        GrabDone = TRUE;
        !           566:     }
        !           567: }
        !           568: 
        !           569: /****************
        !           570:  * ListenToAllClients:
        !           571:  *    Undoes OnlyListentToOneClient()
        !           572:  ****************/
        !           573: 
        !           574: ListenToAllClients()
        !           575: {
        !           576:     if (GrabDone)
        !           577:     {
        !           578:        ORBITS(AllSockets, AllSockets, SavedAllSockets);
        !           579:        ORBITS(AllClients, AllClients, SavedAllClients);
        !           580:        ORBITS(ClientsWithInput, ClientsWithInput, SavedClientsWithInput);
        !           581:        GrabDone = FALSE;
        !           582:     }  
        !           583: }
        !           584: 
        !           585: 

unix.superglobalmegacorp.com

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