Edit

IABSD.fr/xenocara/app/lbxproxy/di/dispatch.c

Branch :

  • Show log

    Commit

  • Author : matthieu
    Date : 2006-11-26 14:07:37
    Hash : a79d551c
    Message : Importing from X.Org indiviual releases

  • app/lbxproxy/di/dispatch.c
  • /* $Xorg: dispatch.c,v 1.3 2000/08/17 19:53:55 cpqbld Exp $ */
    /*
     * Copyright 1992 Network Computing Devices
     * Copyright 1996 X Consortium, Inc.
     *
     * Permission to use, copy, modify, distribute, and sell this software and its
     * documentation for any purpose is hereby granted without fee, provided that
     * the above copyright notice appear in all copies and that both that
     * copyright notice and this permission notice appear in supporting
     * documentation, and that the name of NCD. not be used in advertising or
     * publicity pertaining to distribution of the software without specific,
     * written prior permission.  NCD. makes no representations about the
     * suitability of this software for any purpose.  It is provided "as is"
     * without express or implied warranty.
     *
     * NCD. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
     * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL NCD.
     * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
     * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 
     * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     *
     */
    /* $XFree86: xc/programs/lbxproxy/di/dispatch.c,v 1.6 2001/10/28 03:34:22 tsi Exp $ */
    
    #include <stdio.h>
    #include "assert.h"
    #include "lbx.h"
    #include "wire.h"
    #include "swap.h"
    #include "lbxext.h"
    #include "util.h"
    #include "resource.h"
    #include "pm.h"
    
    extern int (* InitialVector[3]) ();
    
    static void KillAllClients(
        void
    );
    
    static void
    HandleLargeRequest(
        void
    );
    
    int nextFreeClientID; /* always MIN free client ID */
    int nClients;	/* number active clients */
    char *display_name = 0;
    volatile char dispatchException = 0;
    volatile char isItTimeToYield;
    Bool lbxUseLbx = TRUE;
    Bool lbxCompressImages = TRUE;
    Bool lbxDoAtomShortCircuiting = TRUE;
    Bool lbxDoLbxGfx = TRUE;
    
    extern Bool lbxWinAttr;
    extern Bool lbxDoCmapGrabbing;
    extern char *atomsFile;
    
    #define MAJOROP ((xReq *)client->requestBuffer)->reqType
    #define MINOROP ((xReq *)client->requestBuffer)->data
    
    int
    Dispatch ()
    {
        register int        *clientReady;     /* array of request ready clients */
        register int	result = 0;
        register ClientPtr	client;
        register int	nready;
    
        nextFreeClientID = 2;
        nClients = 0;
    
        clientReady = (int *) xalloc(sizeof(int) * MaxClients);
        if (!clientReady)
    	FatalError("couldn't create client ready array");
    
        while (!dispatchException)
        {
    	if (numLargeRequestsInQueue == 0) {
    	    /*
    	     * There are no pending large requests, so do blocking read.
    	     */
    
    	    nready = WaitForSomething(clientReady, FALSE /* block */);
    
    	} else {
    	    /*
    	     * If there is no input from any clients (the only way we can
    	     * check this is by polling rather than blocking), handle a
    	     * large request.
    	     */
    
    	    nready = WaitForSomething(clientReady, TRUE  /* poll */);
    
    	    if (!nready && numLargeRequestsInQueue)
    		HandleLargeRequest ();
    	}
    
           /***************** 
    	*  Handle events in round robin fashion, doing input between 
    	*  each round 
    	*****************/
    
    	while (!dispatchException && (--nready >= 0))
    	{
    	    client = clients[clientReady[nready]];
    	    if (! client)
    	    {
    		/* KillClient can cause this to happen */
    		continue;
    	    }
    	    isItTimeToYield = FALSE;
     
    	    while (!isItTimeToYield)
    	    {
    		/* now, finally, deal with client requests */
    
    	        result = ReadRequestFromClient(client);
    	        if (result <= 0) 
    	        {
    		    if (result < 0)
    			CloseDownClient(client);
    		    break;
    	        }
    
    		client->sequence++;
    #ifdef DEBUG
    		if (client->requestLogIndex == MAX_REQUEST_LOG)
    		    client->requestLogIndex = 0;
    		client->requestLog[client->requestLogIndex] = MAJOROP;
    		client->requestLogIndex++;
    #endif
                    client->sequenceNumber++;
    		result = (* client->requestVector[MAJOROP])(client);
    	    
    		if (result != Success) 
    		{
    		    if (client->noClientException != Success)
                            CloseDownClient(client);
                        else
    		        SendErrorToClient(client, MAJOROP, MINOROP,
    					  client->errorValue, result);
    		    break;
    	        }
    	    }
    	    if (result >= 0 && client != client->server->serverClient)
    		client->server->prev_exec = client;
    	    FlushAllOutput();
    	}
        }
        KillAllClients();
        LbxCleanupSession();
        xfree (clientReady);
        dispatchException &= ~DE_RESET;
        return (dispatchException & DE_TERMINATE);
    }
    
    void
    SendErrorToClient(client, majorCode, minorCode, resId, errorCode)
        ClientPtr client;
        unsigned int majorCode;
        unsigned int minorCode;
        XID resId;
        int errorCode;
    {
        xError      rep;
        int		n;
    
        rep.type = X_Error;
        rep.sequenceNumber = LBXSequenceNumber(client);
        rep.errorCode = errorCode;
        rep.majorCode = majorCode;
        rep.minorCode = minorCode;
        rep.resourceID = resId;
    
        if (client->swapped) {
    	swaps(&rep.sequenceNumber, n);
    	swaps(&rep.minorCode, n);
    	swaps(&rep.resourceID, n);
        }
    
        if (LBXCacheSafe(client)) {
    	FinishLBXRequest(client, REQ_YANK);
    	WriteToClient(client, sizeof(rep), (char *)&rep);
        } else {
    	if (!LBXCanDelayReply(client))
    	    SendLbxSync(client);
    	FinishLBXRequest(client, REQ_YANKLATE);
    	SaveReplyData(client, (xReply *) &rep, 0, NULL);
        }
    }
    
    /************************
     * int NextAvailableClient(ospriv)
     *
     * OS dependent portion can't assign client id's because of CloseDownModes.
     * Returns NULL if there are no free clients.
     *************************/
    
    ClientPtr
    NextAvailableClient(ospriv, connect_fd)
        pointer ospriv;
        int connect_fd;
    {
        register int i;
        register ClientPtr client;
        xReq data;
        static int been_there;
    
        if (!been_there) {
           nextFreeClientID = 1; /* The first client is serverClient */
           been_there++;
        }
        i = nextFreeClientID;
        if (i == MAXCLIENTS)
    	return (ClientPtr)NULL;
        clients[i] = client = (ClientPtr)xcalloc(sizeof(ClientRec));
        if (!client)
    	return (ClientPtr)NULL;
        client->index = i;
        client->closeDownMode = DestroyAll;
        client->awaitingSetup = TRUE;
        client->saveSet = (pointer *)NULL;
        client->noClientException = Success;
        client->public.requestLength = StandardRequestLength;
        client->requestVector = InitialVector;
        client->osPrivate = ospriv;
        client->big_requests = TRUE;
    
        /*
         * Use the fd the client connected on as a search key to find the 
         * associated display for this client
         */
        if (connect_fd != -1)
        {
    	int j, k, found = 0;
    	for (j=0; j < lbxMaxServers; j++)
    	{
    	    if (servers[j])
    	    {
    	        for (k=0; k < MAXTRANSPORTS; k++)
    		   if (servers[j]->listen_fds[k] == connect_fd)
    		   {
    		       found = 1;
    		       break;
    		   }
    	    }
    	    if (found)
    		break;
    	}
    	if (!found) {
    	    fprintf (stderr, "Cannot determine a client's transport connection\n");
    	    return (ClientPtr) NULL;
    	}
            client->server = servers[j];
        }
    
        if (client->server && !InitClientResources(client))
        {
    	xfree(client);
    	return (ClientPtr)NULL;
        }
    
        if (i == currentMaxClients)
    	currentMaxClients++;
        while ((nextFreeClientID < MAXCLIENTS) && clients[nextFreeClientID])
    	nextFreeClientID++;
        if (client->server)
        {
    	data.reqType = 1;
    	data.length = (sz_xReq + sz_xConnClientPrefix) >> 2;
    	if (!InsertFakeRequest(client, (char *)&data, sz_xReq))
    	{
    	    xfree (client);
    	    return (ClientPtr) NULL;
    	}
        }
        return(client);
    }
    
    int
    ProcInitialConnection(client)
        register ClientPtr client;
    {
        REQUEST(xReq);
        register xConnClientPrefix *prefix;
        int whichbyte = 1;
    
        prefix = (xConnClientPrefix *)((char *)stuff + sz_xReq);
        if ((prefix->byteOrder != 'l') && (prefix->byteOrder != 'B'))
    	return (client->noClientException = -1);
        if (((*(char *) &whichbyte) && (prefix->byteOrder == 'B')) ||
    	(!(*(char *) &whichbyte) && (prefix->byteOrder == 'l')))
        {
    	client->swapped = TRUE;
    	SwapConnClientPrefix(prefix);
        }
        stuff->reqType = 2;
        stuff->length += ((prefix->nbytesAuthProto + 3) >> 2) +
    		     ((prefix->nbytesAuthString + 3) >> 2);
        if (client->swapped) {
    	swaps(&stuff->length, whichbyte);
        }
        ResetCurrentRequest(client);
        return (client->noClientException);
    }
    
    int
    ProcEstablishConnection(client)
        register ClientPtr client;
    {
        register xConnClientPrefix *prefix;
        register int i;
        int         len;
    
        REQUEST(xReq);
    
        prefix = (xConnClientPrefix *) ((char *) stuff + sz_xReq);
    
        nClients++;
        client->requestVector = client->server->requestVector;
        client->sequence = 0;
        client->sequenceNumber = 0;
        client->largeRequest = NULL;
    
        /* wait for X server to kill client */
        client->closeDownMode = RetainPermanent;
    
        /*
         * NewClient outputs the LbxNewClient request header - have to follow it
         * up with the setup connection info.
         */
        /* length is still swapped */
        if (client->swapped) {
    	swaps(&stuff->length, i);
    	/* put data back to the way server will expect it */
    	SwapConnClientPrefix((xConnClientPrefix *) prefix);
        }
        len = (stuff->length << 2) - sz_xReq;
        if (!NewClient(client, len))
    	return (client->noClientException = -1);
    
        WriteToServer(client->server->serverClient, len, (char *) prefix, 
    		  TRUE, FALSE);
    
        /*
         * Can't allow any requests to be passed on to the server until the
         * connection setup reply has been received.
         */
        IgnoreClient(client);
    
        return (client->noClientException);
    }
    
    /**********************
     * CloseDownClient
     *
     *  Client can either mark his resources destroy or retain.  If retained and
     *  then killed again, the client is really destroyed.
     *********************/
    
    Bool resetAfterLastClient = FALSE;
    Bool terminateAfterLastClient = FALSE;
    
    void
    CloseDownClient(client)
        register ClientPtr client;
    {
        if (!client->clientGone)
        {
    	CloseClient (client);
    	
    	
    	/* X server is telling us this client is dead */
    	if (client->closeDownMode == DestroyAll)
    	{
    	    client->clientGone = TRUE;  /* so events aren't sent to client */
    	    FreeClientResources(client);
    	    CloseDownConnection(client);
    	    if (ClientIsAsleep (client))
    		ClientSignal (client);
    	    if (client->index < nextFreeClientID)
    		nextFreeClientID = client->index;
    	    clients[client->index] = NullClient;
    	    if ((client->requestVector != InitialVector) &&
    		(client->server && client->server->serverClient != client) &&
    		(--nClients == 0))
    	    {
    		if (resetAfterLastClient)
    		    dispatchException |= DE_RESET;
    		else if (terminateAfterLastClient)
    		    dispatchException |= DE_TERMINATE;
    	    }
    	    xfree(client);
    	}
    	else
    	{
    	    client->clientGone = TRUE;
    	    CloseDownConnection(client);
    	    --nClients;
    	}
        }
        else
        {
    	/* really kill resources this time */
            FreeClientResources(client);
    	if (ClientIsAsleep (client))
    	    ClientSignal (client);
    	if (client->index < nextFreeClientID)
    	    nextFreeClientID = client->index;
    	clients[client->index] = NullClient;
            xfree(client);
    	if (nClients == 0)
    	{
    	    if (resetAfterLastClient)
    		dispatchException |= DE_RESET;
    	    else if (terminateAfterLastClient)
    		dispatchException |= DE_TERMINATE;
    	}
        }
    
        while (!clients[currentMaxClients-1])
          currentMaxClients--;
    }
    
    static void
    KillAllClients()
    {
        int i;
        for (i=1; i<currentMaxClients; i++)
        {
            if (clients[i])
    	{
    	    clients[i]->closeDownMode = DestroyAll;   
                CloseDownClient(clients[i]);
    	}
        }
    }
    
    extern void (*ZeroPadReqVector[128]) ();
    
    int
    ProcStandardRequest (client)
        ClientPtr	client;
    {
        REQUEST(xReq);
        void (*zeroPadProc)();
        extern int lbxZeroPad;
    
        if (lbxZeroPad &&
    	(MAJOROP < 128) && (zeroPadProc = ZeroPadReqVector[MAJOROP]))
    	(*zeroPadProc) ((void *) stuff);
        FinishLBXRequest(client, REQ_PASSTHROUGH);
        WriteReqToServer(client, client->req_len << 2, (char *) stuff, TRUE);
        return Success;
    }
    
    /* ARGSUSED */
    int
    ProcBadRequest (client)
        ClientPtr	client;
    {
        return BadRequest;
    }
    
    /*
     * Turn off optional features.  Some features, like tags, will be turned
     * off after option negotiation.
     */
    
    void
    AdjustProcVector()
    {
        int         i;
    
        /*
         * to turn off all LBX request reencodings, set all proc vectors to
         * ProcStandardRequest
         */
        if (!lbxUseLbx) {
        	for (i = 1; i < 256; i++) {
                ProcVector[i] = ProcStandardRequest;
            }
        }
    
        if (!atomsFile)
    	ProcVector[X_ChangeWindowAttributes] = ProcStandardRequest;
    
        if (!lbxCompressImages) {
    	ProcVector[X_PutImage] = ProcStandardRequest;
    	ProcVector[X_GetImage] = ProcStandardRequest;
        }
    
        if (!lbxDoAtomShortCircuiting) {
    	ProcVector[X_InternAtom] = ProcStandardRequest;
    	ProcVector[X_GetAtomName] = ProcStandardRequest;
        }
    
        if (!lbxDoCmapGrabbing)
        {
    	ProcVector[X_CreateColormap] = ProcStandardRequest;
    	ProcVector[X_FreeColormap] = ProcStandardRequest;
    	ProcVector[X_CopyColormapAndFree] = ProcStandardRequest;
    	ProcVector[X_AllocColor] = ProcStandardRequest;
    	ProcVector[X_AllocNamedColor] = ProcStandardRequest;
    	ProcVector[X_AllocColorCells] = ProcStandardRequest;
    	ProcVector[X_AllocColorPlanes] = ProcStandardRequest;
    	ProcVector[X_FreeColors] = ProcStandardRequest;
    	ProcVector[X_LookupColor] = ProcStandardRequest;
        }
    
        if (!lbxDoLbxGfx) {
    	ProcVector[X_CopyArea] = ProcStandardRequest;
    	ProcVector[X_CopyPlane] = ProcStandardRequest;
    	ProcVector[X_PolyPoint] = ProcStandardRequest;
    	ProcVector[X_PolyLine] = ProcStandardRequest;
    	ProcVector[X_PolySegment] = ProcStandardRequest;
    	ProcVector[X_PolyRectangle] = ProcStandardRequest;
    	ProcVector[X_PolyArc] = ProcStandardRequest;
    	ProcVector[X_FillPoly] = ProcStandardRequest;
    	ProcVector[X_PolyFillRectangle] = ProcStandardRequest;
    	ProcVector[X_PolyFillArc] = ProcStandardRequest;
    	ProcVector[X_PolyText8] = ProcStandardRequest;
    	ProcVector[X_PolyText16] = ProcStandardRequest;
    	ProcVector[X_ImageText8] = ProcStandardRequest;
    	ProcVector[X_ImageText16] = ProcStandardRequest;
        }
    
        if (!lbxWinAttr)
        {
    	ProcVector[X_GetWindowAttributes] = ProcStandardRequest;
    	ProcVector[X_GetGeometry] = ProcStandardRequest;
        }
    }
    
    
    static void
    HandleLargeRequest ()
    
    {
        LbxLargeRequestRec *largeRequest = largeRequestQueue[0];
        ClientPtr client = largeRequest->client;
        int bytesLeft, chunkSize;
    
        /*
         * Process the first large request on the queue.  If this is the first
         * chunk of a large request, send an LbxBeginLargeRequest message.
         */
    
        if (largeRequest->bytesWritten == 0) {
    	xLbxBeginLargeRequestReq beginReq;
    	int n;
    
    	beginReq.reqType = client->server->lbxReq;
    	beginReq.lbxReqType = X_LbxBeginLargeRequest;
    	beginReq.length = 2;
    	beginReq.largeReqLength = largeRequest->totalBytes >> 2;
    	if (client->swapped) {
    	    swapl(&beginReq.largeReqLength, n);
    	}
    	_write_to_server (client,
    	    largeRequest->compressed,
    	    sizeof (beginReq), (char *) &beginReq,
    	    FALSE, TRUE);
        }
    
        /*
         * Send a chunk of the large request using the LbxLargeRequestData message.
         */
    
        bytesLeft = largeRequest->totalBytes - largeRequest->bytesWritten;
    
        if (bytesLeft > LBX_LARGE_REQUEST_CHUNK_SIZE)
    	chunkSize = LBX_LARGE_REQUEST_CHUNK_SIZE;
        else
    	chunkSize = bytesLeft;
    
        if (chunkSize > 0) {
    	xLbxLargeRequestDataReq dataReq;
    
    	dataReq.reqType = client->server->lbxReq;
    	dataReq.lbxReqType = X_LbxLargeRequestData;
    	dataReq.length = 1 + (chunkSize >> 2);
    
    	_write_to_server (client,
    	    largeRequest->compressed,
    	    sizeof (dataReq), (char *) &dataReq,
    	    FALSE, TRUE);
    
    	_write_to_server (client,
    	    largeRequest->compressed,
    	    chunkSize,
    	    largeRequest->buf + largeRequest->bytesWritten,
    	    FALSE, FALSE);
    
    	largeRequest->bytesWritten += chunkSize;
        }
    
        if (numLargeRequestsInQueue > 1) {
    	/*
    	 * Move this large request to the end of the queue - this way
    	 * we can process large requests from other clients too.
    	 */
    
    	memmove((char *)&largeRequestQueue[0], (char *)&largeRequestQueue[1],
    		(numLargeRequestsInQueue - 1) * sizeof(LbxLargeRequestRec *));
    	largeRequestQueue[numLargeRequestsInQueue - 1] = largeRequest;
        }
    
        /*
         * See if the whole request has been sent.  If yes, send an
         * LbxEndLargeRequest and re-enable input for this client.
         */
    
        if (largeRequest->bytesWritten == largeRequest->totalBytes) {
    	xLbxEndLargeRequestReq endReq;
    
    	endReq.reqType = client->server->lbxReq;
    	endReq.lbxReqType = X_LbxEndLargeRequest;
    	endReq.length = 1;
    
    	_write_to_server (client,
    	    largeRequest->compressed,
    	    sizeof (endReq), (char *) &endReq,
    	    FALSE, TRUE);
    
    	xfree ((char *) largeRequest);
    	client->largeRequest = NULL;
    	numLargeRequestsInQueue--;
    		    
    	AttendClient (client);
        }
    }