2973 lines
		
	
	
		
			86 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			2973 lines
		
	
	
		
			86 KiB
		
	
	
	
		
			C
		
	
	
	
 | 
						||
/*
 | 
						||
 | 
						||
Copyright 1995, 1998  The Open Group
 | 
						||
 | 
						||
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.
 | 
						||
 | 
						||
The above copyright notice and this permission notice shall be
 | 
						||
included in all copies or substantial portions of the Software.
 | 
						||
 | 
						||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 | 
						||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 | 
						||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 | 
						||
IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
 | 
						||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 | 
						||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 | 
						||
OTHER DEALINGS IN THE SOFTWARE.
 | 
						||
 | 
						||
Except as contained in this notice, the name of The Open Group shall
 | 
						||
not be used in advertising or otherwise to promote the sale, use or
 | 
						||
other dealings in this Software without prior written authorization
 | 
						||
from The Open Group.
 | 
						||
 | 
						||
Author: David P. Wiggins, The Open Group
 | 
						||
 | 
						||
This work benefited from earlier work done by Martha Zimet of NCD
 | 
						||
and Jim Haggerty of Metheus.
 | 
						||
 | 
						||
*/
 | 
						||
 | 
						||
#define NEED_EVENTS
 | 
						||
#ifdef HAVE_DIX_CONFIG_H
 | 
						||
#include <dix-config.h>
 | 
						||
#endif
 | 
						||
 | 
						||
#include "dixstruct.h"
 | 
						||
#include "extnsionst.h"
 | 
						||
#define _XRECORD_SERVER_
 | 
						||
#include <X11/extensions/recordstr.h>
 | 
						||
#include "set.h"
 | 
						||
#include "swaprep.h"
 | 
						||
 | 
						||
#include <stdio.h>
 | 
						||
#include <assert.h>
 | 
						||
 | 
						||
#ifdef PANORAMIX
 | 
						||
#include "globals.h"
 | 
						||
#include "panoramiX.h"
 | 
						||
#include "panoramiXsrv.h"
 | 
						||
#include "cursor.h"
 | 
						||
#endif
 | 
						||
 | 
						||
static RESTYPE RTContext;   /* internal resource type for Record contexts */
 | 
						||
static int RecordErrorBase; /* first Record error number */
 | 
						||
 | 
						||
/* How many bytes of protocol data to buffer in a context. Don't set to less
 | 
						||
 * than 32.
 | 
						||
 */
 | 
						||
#define REPLY_BUF_SIZE 1024
 | 
						||
 | 
						||
/* Record Context structure */
 | 
						||
 | 
						||
typedef struct {
 | 
						||
    XID		id;		   /* resource id of context */
 | 
						||
    ClientPtr	pRecordingClient;  /* client that has context enabled */
 | 
						||
    struct _RecordClientsAndProtocolRec *pListOfRCAP; /* all registered info */
 | 
						||
    ClientPtr	pBufClient;	   /* client whose protocol is in replyBuffer*/
 | 
						||
    unsigned int continuedReply:1; /* recording a reply that is split up? */
 | 
						||
    char	elemHeaders;	   /* element header flags (time/seq no.) */
 | 
						||
    char	bufCategory;	   /* category of protocol in replyBuffer */
 | 
						||
    int		numBufBytes;	   /* number of bytes in replyBuffer */
 | 
						||
    char	replyBuffer[REPLY_BUF_SIZE]; /* buffered recorded protocol */
 | 
						||
} RecordContextRec, *RecordContextPtr;
 | 
						||
 | 
						||
/*  RecordMinorOpRec - to hold minor opcode selections for extension requests
 | 
						||
 *  and replies
 | 
						||
 */
 | 
						||
 | 
						||
typedef union {
 | 
						||
    int count; /* first element of array: how many "major" structs to follow */
 | 
						||
    struct {   /* rest of array elements are this */
 | 
						||
	short first;		/* first major opcode */
 | 
						||
	short last;		/* last major opcode */
 | 
						||
	RecordSetPtr pMinOpSet; /*  minor opcode set for above major range */
 | 
						||
    } major;
 | 
						||
} RecordMinorOpRec, *RecordMinorOpPtr;
 | 
						||
 | 
						||
 | 
						||
/*  RecordClientsAndProtocolRec, nicknamed RCAP - holds all the client and 
 | 
						||
 *  protocol selections passed in a single CreateContext or RegisterClients.
 | 
						||
 *  Generally, a context will have one of these from the create and an
 | 
						||
 *  additional one for each RegisterClients.  RCAPs are freed when all their
 | 
						||
 *  clients are unregistered.
 | 
						||
 */
 | 
						||
 | 
						||
typedef struct _RecordClientsAndProtocolRec {
 | 
						||
    RecordContextPtr pContext;		 /* context that owns this RCAP */
 | 
						||
    struct _RecordClientsAndProtocolRec *pNextRCAP; /* next RCAP on context */
 | 
						||
    RecordSetPtr     pRequestMajorOpSet; /* requests to record */
 | 
						||
    RecordMinorOpPtr pRequestMinOpInfo;  /* extension requests to record */
 | 
						||
    RecordSetPtr     pReplyMajorOpSet;   /* replies to record */
 | 
						||
    RecordMinorOpPtr pReplyMinOpInfo;    /* extension replies to record */
 | 
						||
    RecordSetPtr     pDeviceEventSet;    /* device events to record */
 | 
						||
    RecordSetPtr     pDeliveredEventSet; /* delivered events to record */
 | 
						||
    RecordSetPtr     pErrorSet;          /* errors to record */
 | 
						||
    XID *	     pClientIDs;	 /* array of clients to record */
 | 
						||
    short 	     numClients;	 /* number of clients in pClientIDs */
 | 
						||
    short	     sizeClients;	 /* size of pClientIDs array */
 | 
						||
    unsigned int     clientStarted:1;	 /* record new client connections? */
 | 
						||
    unsigned int     clientDied:1;	 /* record client disconnections? */
 | 
						||
    unsigned int     clientIDsSeparatelyAllocated:1; /* pClientIDs malloced? */
 | 
						||
} RecordClientsAndProtocolRec, *RecordClientsAndProtocolPtr;
 | 
						||
 | 
						||
/* how much bigger to make pRCAP->pClientIDs when reallocing */
 | 
						||
#define CLIENT_ARRAY_GROWTH_INCREMENT 4
 | 
						||
 | 
						||
/* counts the total number of RCAPs belonging to enabled contexts. */
 | 
						||
static int numEnabledRCAPs;
 | 
						||
 | 
						||
/*  void VERIFY_CONTEXT(RecordContextPtr, XID, ClientPtr)
 | 
						||
 *  In the spirit of the VERIFY_* macros in dix.h, this macro fills in
 | 
						||
 *  the context pointer if the given ID is a valid Record Context, else it
 | 
						||
 *  returns an error.
 | 
						||
 */
 | 
						||
#define VERIFY_CONTEXT(_pContext, _contextid, _client) { \
 | 
						||
    (_pContext) = (RecordContextPtr)LookupIDByType((_contextid), RTContext); \
 | 
						||
    if (!(_pContext)) { \
 | 
						||
        (_client)->errorValue = (_contextid); \
 | 
						||
	return RecordErrorBase + XRecordBadContext; \
 | 
						||
    } \
 | 
						||
}
 | 
						||
 | 
						||
static int RecordDeleteContext(
 | 
						||
    pointer /*value*/,
 | 
						||
    XID /*id*/
 | 
						||
);
 | 
						||
 | 
						||
 | 
						||
/***************************************************************************/
 | 
						||
 | 
						||
/* client private stuff */
 | 
						||
 | 
						||
/*  To make declarations less obfuscated, have a typedef for a pointer to a
 | 
						||
 *  Proc function.
 | 
						||
 */
 | 
						||
typedef int (*ProcFunctionPtr)(
 | 
						||
    ClientPtr /*pClient*/
 | 
						||
);
 | 
						||
 | 
						||
/* Record client private.  Generally a client only has one of these if
 | 
						||
 * any of its requests are being recorded.
 | 
						||
 */
 | 
						||
typedef struct {
 | 
						||
/* ptr to client's proc vector before Record stuck its nose in */
 | 
						||
    ProcFunctionPtr *originalVector;   
 | 
						||
					
 | 
						||
/* proc vector with pointers for recorded requests redirected to the
 | 
						||
 * function RecordARequest
 | 
						||
 */
 | 
						||
    ProcFunctionPtr recordVector[256]; 
 | 
						||
} RecordClientPrivateRec, *RecordClientPrivatePtr;
 | 
						||
 | 
						||
static int RecordClientPrivateIndex;
 | 
						||
 | 
						||
/*  RecordClientPrivatePtr RecordClientPrivate(ClientPtr)
 | 
						||
 *  gets the client private of the given client.  Syntactic sugar.
 | 
						||
 */
 | 
						||
#define RecordClientPrivate(_pClient) (RecordClientPrivatePtr) \
 | 
						||
    ((_pClient)->devPrivates[RecordClientPrivateIndex].ptr)
 | 
						||
 | 
						||
 | 
						||
/***************************************************************************/
 | 
						||
 | 
						||
/* global list of all contexts */
 | 
						||
 | 
						||
static RecordContextPtr *ppAllContexts;
 | 
						||
 | 
						||
static int numContexts;/* number of contexts in ppAllContexts */
 | 
						||
 | 
						||
/* number of currently enabled contexts.  All enabled contexts are bunched
 | 
						||
 * up at the front of the ppAllContexts array, from ppAllContexts[0] to
 | 
						||
 * ppAllContexts[numEnabledContexts-1], to eliminate time spent skipping
 | 
						||
 * past disabled contexts.
 | 
						||
 */
 | 
						||
static int numEnabledContexts;
 | 
						||
 | 
						||
/* RecordFindContextOnAllContexts
 | 
						||
 *
 | 
						||
 * Arguments:
 | 
						||
 *	pContext is the context to search for.
 | 
						||
 *
 | 
						||
 * Returns:
 | 
						||
 *	The index into the array ppAllContexts at which pContext is stored.
 | 
						||
 *	If pContext is not found in ppAllContexts, returns -1.
 | 
						||
 *
 | 
						||
 * Side Effects: none.
 | 
						||
 */
 | 
						||
static int
 | 
						||
RecordFindContextOnAllContexts(RecordContextPtr pContext)
 | 
						||
{
 | 
						||
    int i;
 | 
						||
 | 
						||
    assert(numContexts >= numEnabledContexts);
 | 
						||
    for (i = 0; i < numContexts; i++)
 | 
						||
    {
 | 
						||
	if (ppAllContexts[i] == pContext)
 | 
						||
	    return i;
 | 
						||
    }
 | 
						||
    return -1;
 | 
						||
} /* RecordFindContextOnAllContexts */
 | 
						||
 | 
						||
 | 
						||
/***************************************************************************/
 | 
						||
 | 
						||
/* RecordFlushReplyBuffer
 | 
						||
 *
 | 
						||
 * Arguments:
 | 
						||
 *	pContext is the context to flush.
 | 
						||
 *	data1 is a pointer to additional data, and len1 is its length in bytes.
 | 
						||
 *	data2 is a pointer to additional data, and len2 is its length in bytes.
 | 
						||
 *
 | 
						||
 * Returns: nothing.
 | 
						||
 *
 | 
						||
 * Side Effects:
 | 
						||
 *	If the context is enabled, any buffered (recorded) protocol is written
 | 
						||
 *	to the recording client, and the number of buffered bytes is set to
 | 
						||
 *	zero.  If len1 is not zero, data1/len1 are then written to the
 | 
						||
 *	recording client, and similarly for data2/len2 (written after
 | 
						||
 *	data1/len1).
 | 
						||
 */
 | 
						||
static void
 | 
						||
RecordFlushReplyBuffer(
 | 
						||
    RecordContextPtr pContext,
 | 
						||
    pointer data1,
 | 
						||
    int len1,
 | 
						||
    pointer data2,
 | 
						||
    int len2
 | 
						||
)
 | 
						||
{
 | 
						||
    if (!pContext->pRecordingClient || pContext->pRecordingClient->clientGone) 
 | 
						||
	return;
 | 
						||
    if (pContext->numBufBytes)
 | 
						||
	WriteToClient(pContext->pRecordingClient, pContext->numBufBytes,
 | 
						||
		      (char *)pContext->replyBuffer);
 | 
						||
    pContext->numBufBytes = 0;
 | 
						||
    if (len1)
 | 
						||
	WriteToClient(pContext->pRecordingClient, len1, (char *)data1);
 | 
						||
    if (len2)
 | 
						||
	WriteToClient(pContext->pRecordingClient, len2, (char *)data2);
 | 
						||
} /* RecordFlushReplyBuffer */
 | 
						||
 | 
						||
 | 
						||
/* RecordAProtocolElement
 | 
						||
 *
 | 
						||
 * Arguments:
 | 
						||
 *	pContext is the context that is recording a protocol element.
 | 
						||
 *	pClient is the client whose protocol is being recorded.  For
 | 
						||
 *	  device events and EndOfData, pClient is NULL.
 | 
						||
 *	category is the category of the protocol element, as defined
 | 
						||
 *	  by the RECORD spec.
 | 
						||
 *	data is a pointer to the protocol data, and datalen is its length
 | 
						||
 *	  in bytes.
 | 
						||
 *	futurelen is the number of bytes that will be sent in subsequent
 | 
						||
 *	  calls to this function to complete this protocol element.  
 | 
						||
 *	  In those subsequent calls, futurelen will be -1 to indicate
 | 
						||
 *	  that the current data is a continuation of the same protocol
 | 
						||
 *	  element.
 | 
						||
 *
 | 
						||
 * Returns: nothing.
 | 
						||
 *
 | 
						||
 * Side Effects:
 | 
						||
 *	The context may be flushed.  The new protocol element will be
 | 
						||
 *	added to the context's protocol buffer with appropriate element
 | 
						||
 *	headers prepended (sequence number and timestamp).  If the data
 | 
						||
 *	is continuation data (futurelen == -1), element headers won't
 | 
						||
 *	be added.  If the protocol element and headers won't fit in
 | 
						||
 *	the context's buffer, it is sent directly to the recording
 | 
						||
 *	client (after any buffered data).
 | 
						||
 */
 | 
						||
static void
 | 
						||
RecordAProtocolElement(RecordContextPtr pContext, ClientPtr pClient,
 | 
						||
		       int category, pointer data, int datalen, int futurelen)
 | 
						||
{
 | 
						||
    CARD32 elemHeaderData[2];
 | 
						||
    int numElemHeaders = 0;
 | 
						||
    Bool recordingClientSwapped = pContext->pRecordingClient->swapped;
 | 
						||
    int n;
 | 
						||
    CARD32 serverTime = 0;
 | 
						||
    Bool gotServerTime = FALSE;
 | 
						||
    int replylen;
 | 
						||
 | 
						||
    if (futurelen >= 0)
 | 
						||
    { /* start of new protocol element */
 | 
						||
	xRecordEnableContextReply *pRep = (xRecordEnableContextReply *)
 | 
						||
							pContext->replyBuffer;
 | 
						||
	if (pContext->pBufClient != pClient ||
 | 
						||
	    pContext->bufCategory != category)
 | 
						||
	{
 | 
						||
	    RecordFlushReplyBuffer(pContext, NULL, 0, NULL, 0);
 | 
						||
	    pContext->pBufClient = pClient;
 | 
						||
	    pContext->bufCategory = category;
 | 
						||
	}
 | 
						||
 | 
						||
	if (!pContext->numBufBytes)
 | 
						||
	{
 | 
						||
	    serverTime = GetTimeInMillis();
 | 
						||
	    gotServerTime = TRUE;
 | 
						||
	    pRep->type          = X_Reply;
 | 
						||
	    pRep->category      = category;
 | 
						||
	    pRep->sequenceNumber = pContext->pRecordingClient->sequence;
 | 
						||
	    pRep->length        = 0;
 | 
						||
	    pRep->elementHeader = pContext->elemHeaders;
 | 
						||
	    pRep->serverTime    = serverTime;
 | 
						||
	    if (pClient)
 | 
						||
	    {
 | 
						||
		pRep->clientSwapped =
 | 
						||
				(pClient->swapped != recordingClientSwapped);
 | 
						||
		pRep->idBase = pClient->clientAsMask;
 | 
						||
		pRep->recordedSequenceNumber = pClient->sequence;
 | 
						||
	    }
 | 
						||
	    else /* it's a device event, StartOfData, or EndOfData */
 | 
						||
	    {
 | 
						||
		pRep->clientSwapped = (category != XRecordFromServer) && 
 | 
						||
						recordingClientSwapped;
 | 
						||
		pRep->idBase = 0;
 | 
						||
		pRep->recordedSequenceNumber = 0;
 | 
						||
	    }
 | 
						||
 | 
						||
	    if (recordingClientSwapped)
 | 
						||
	    {
 | 
						||
		swaps(&pRep->sequenceNumber, n);
 | 
						||
		swapl(&pRep->length, n);
 | 
						||
		swapl(&pRep->idBase, n);
 | 
						||
		swapl(&pRep->serverTime, n);
 | 
						||
		swapl(&pRep->recordedSequenceNumber, n);
 | 
						||
	    }
 | 
						||
	    pContext->numBufBytes = SIZEOF(xRecordEnableContextReply);
 | 
						||
	}
 | 
						||
 | 
						||
	/* generate element headers if needed */
 | 
						||
 | 
						||
	if ( ( (pContext->elemHeaders & XRecordFromClientTime)
 | 
						||
	      && category == XRecordFromClient)
 | 
						||
	    ||
 | 
						||
	    ( (pContext->elemHeaders & XRecordFromServerTime)
 | 
						||
	     && category == XRecordFromServer))
 | 
						||
	{
 | 
						||
	    if (gotServerTime)
 | 
						||
		elemHeaderData[numElemHeaders] = serverTime;
 | 
						||
	    else
 | 
						||
		elemHeaderData[numElemHeaders] = GetTimeInMillis();
 | 
						||
	    if (recordingClientSwapped)
 | 
						||
		swapl(&elemHeaderData[numElemHeaders], n);
 | 
						||
	    numElemHeaders++;
 | 
						||
	}
 | 
						||
 | 
						||
	if ( (pContext->elemHeaders & XRecordFromClientSequence)
 | 
						||
	    &&
 | 
						||
	    (category == XRecordFromClient || category == XRecordClientDied))
 | 
						||
	{
 | 
						||
	    elemHeaderData[numElemHeaders] = pClient->sequence;
 | 
						||
	    if (recordingClientSwapped)
 | 
						||
		swapl(&elemHeaderData[numElemHeaders], n);
 | 
						||
	    numElemHeaders++;
 | 
						||
	}
 | 
						||
 | 
						||
	/* adjust reply length */
 | 
						||
 | 
						||
	replylen = pRep->length;
 | 
						||
	if (recordingClientSwapped) swapl(&replylen, n);
 | 
						||
	replylen += numElemHeaders + (datalen >> 2) + (futurelen >> 2);
 | 
						||
	if (recordingClientSwapped) swapl(&replylen, n);
 | 
						||
	pRep->length = replylen;
 | 
						||
    } /* end if not continued reply */
 | 
						||
 | 
						||
    numElemHeaders *= 4;
 | 
						||
 | 
						||
    /* if space available >= space needed, buffer the data */
 | 
						||
 | 
						||
    if (REPLY_BUF_SIZE - pContext->numBufBytes >= datalen + numElemHeaders)
 | 
						||
    {
 | 
						||
	if (numElemHeaders)
 | 
						||
	{
 | 
						||
	    memcpy(pContext->replyBuffer + pContext->numBufBytes,
 | 
						||
		   elemHeaderData, numElemHeaders);
 | 
						||
	    pContext->numBufBytes += numElemHeaders;
 | 
						||
	}
 | 
						||
	if (datalen)
 | 
						||
	{
 | 
						||
	    memcpy(pContext->replyBuffer + pContext->numBufBytes,
 | 
						||
		   data, datalen);
 | 
						||
	    pContext->numBufBytes += datalen;
 | 
						||
	}
 | 
						||
    }
 | 
						||
    else
 | 
						||
	RecordFlushReplyBuffer(pContext, (pointer)elemHeaderData,
 | 
						||
			       numElemHeaders, (pointer)data, datalen);
 | 
						||
 | 
						||
} /* RecordAProtocolElement */
 | 
						||
 | 
						||
 | 
						||
/* RecordFindClientOnContext
 | 
						||
 *
 | 
						||
 * Arguments:
 | 
						||
 *	pContext is the context to search.
 | 
						||
 *	clientspec is the resource ID mask identifying the client to search
 | 
						||
 *	  for, or XRecordFutureClients.
 | 
						||
 *	pposition is a pointer to an int, or NULL.  See Returns.
 | 
						||
 *
 | 
						||
 * Returns:
 | 
						||
 *	The RCAP on which clientspec was found, or NULL if not found on
 | 
						||
 *	any RCAP on the given context.
 | 
						||
 *	If pposition was not NULL and the returned RCAP is not NULL,
 | 
						||
 *	*pposition will be set to the index into the returned the RCAP's
 | 
						||
 *	pClientIDs array that holds clientspec.
 | 
						||
 *
 | 
						||
 * Side Effects: none.
 | 
						||
 */
 | 
						||
static RecordClientsAndProtocolPtr
 | 
						||
RecordFindClientOnContext(
 | 
						||
    RecordContextPtr pContext,
 | 
						||
    XID clientspec,
 | 
						||
    int *pposition
 | 
						||
)
 | 
						||
{
 | 
						||
    RecordClientsAndProtocolPtr pRCAP;
 | 
						||
 | 
						||
    for (pRCAP = pContext->pListOfRCAP; pRCAP; pRCAP = pRCAP->pNextRCAP)
 | 
						||
    {
 | 
						||
	int i;
 | 
						||
	for (i = 0; i < pRCAP->numClients; i++)
 | 
						||
	{
 | 
						||
	    if (pRCAP->pClientIDs[i] == clientspec)
 | 
						||
	    {
 | 
						||
		if (pposition)
 | 
						||
		    *pposition = i;
 | 
						||
		return pRCAP;
 | 
						||
	    }
 | 
						||
	}
 | 
						||
    }
 | 
						||
    return NULL;
 | 
						||
} /* RecordFindClientOnContext */
 | 
						||
 | 
						||
 | 
						||
/* RecordABigRequest
 | 
						||
 *
 | 
						||
 * Arguments:
 | 
						||
 *	pContext is the recording context.
 | 
						||
 *	client is the client being recorded.
 | 
						||
 *	stuff is a pointer to the big request of client (see the Big Requests
 | 
						||
 *	extension for details.)
 | 
						||
 *
 | 
						||
 * Returns: nothing.
 | 
						||
 *
 | 
						||
 * Side Effects:
 | 
						||
 *	The big request is recorded with the correct length field re-inserted.
 | 
						||
 *	
 | 
						||
 * Note: this function exists mainly to make RecordARequest smaller.
 | 
						||
 */
 | 
						||
static void
 | 
						||
RecordABigRequest(RecordContextPtr pContext, ClientPtr client, xReq *stuff)
 | 
						||
{
 | 
						||
    CARD32 bigLength;
 | 
						||
    char n;
 | 
						||
    int bytesLeft;
 | 
						||
 | 
						||
    /* note: client->req_len has been frobbed by ReadRequestFromClient
 | 
						||
     * (os/io.c) to discount the extra 4 bytes taken by the extended length
 | 
						||
     * field in a big request.  The actual request length to record is
 | 
						||
     * client->req_len + 1 (measured in CARD32s).
 | 
						||
     */
 | 
						||
 | 
						||
    /* record the request header */
 | 
						||
    bytesLeft = client->req_len << 2;
 | 
						||
    RecordAProtocolElement(pContext, client, XRecordFromClient,
 | 
						||
			   (pointer)stuff, SIZEOF(xReq), bytesLeft);
 | 
						||
 | 
						||
    /* reinsert the extended length field that was squished out */
 | 
						||
    bigLength = client->req_len + (sizeof(bigLength) >> 2);
 | 
						||
    if (client->swapped)
 | 
						||
	swapl(&bigLength, n);
 | 
						||
    RecordAProtocolElement(pContext, client, XRecordFromClient,
 | 
						||
		(pointer)&bigLength, sizeof(bigLength), /* continuation */ -1);
 | 
						||
    bytesLeft -= sizeof(bigLength);
 | 
						||
 | 
						||
    /* record the rest of the request after the length */
 | 
						||
    RecordAProtocolElement(pContext, client, XRecordFromClient,
 | 
						||
		(pointer)(stuff + 1), bytesLeft, /* continuation */ -1);
 | 
						||
} /* RecordABigRequest */
 | 
						||
 | 
						||
 | 
						||
/* RecordARequest
 | 
						||
 *
 | 
						||
 * Arguments:
 | 
						||
 *	client is a client that the server has dispatched a request to by
 | 
						||
 *	calling client->requestVector[request opcode] .
 | 
						||
 *	The request is in client->requestBuffer.
 | 
						||
 *
 | 
						||
 * Returns:
 | 
						||
 *	Whatever is returned by the "real" Proc function for this request.
 | 
						||
 *	The "real" Proc function is the function that was in
 | 
						||
 *	client->requestVector[request opcode]  before it was replaced by
 | 
						||
 *	RecordARequest.  (See the function RecordInstallHooks.)
 | 
						||
 *
 | 
						||
 * Side Effects:
 | 
						||
 *	The request is recorded by all contexts that have registered this
 | 
						||
 *	request for this client.  The real Proc function is called.
 | 
						||
 */
 | 
						||
static int
 | 
						||
RecordARequest(ClientPtr client)
 | 
						||
{
 | 
						||
    RecordContextPtr pContext;
 | 
						||
    RecordClientsAndProtocolPtr pRCAP;
 | 
						||
    int i;
 | 
						||
    RecordClientPrivatePtr pClientPriv;
 | 
						||
    REQUEST(xReq);
 | 
						||
    int majorop;
 | 
						||
 | 
						||
    majorop = stuff->reqType;
 | 
						||
    for (i = 0; i < numEnabledContexts; i++)
 | 
						||
    {
 | 
						||
	pContext = ppAllContexts[i];
 | 
						||
	pRCAP = RecordFindClientOnContext(pContext, client->clientAsMask,
 | 
						||
					  NULL);
 | 
						||
	if (pRCAP && pRCAP->pRequestMajorOpSet &&
 | 
						||
	    RecordIsMemberOfSet(pRCAP->pRequestMajorOpSet, majorop))
 | 
						||
	{
 | 
						||
	    if (majorop <= 127)
 | 
						||
	    { /* core request */
 | 
						||
 | 
						||
		if (stuff->length == 0)
 | 
						||
		    RecordABigRequest(pContext, client, stuff);
 | 
						||
		else
 | 
						||
		    RecordAProtocolElement(pContext, client, XRecordFromClient,
 | 
						||
				(pointer)stuff, client->req_len << 2, 0);
 | 
						||
	    }
 | 
						||
	    else /* extension, check minor opcode */
 | 
						||
	    {
 | 
						||
		int minorop = MinorOpcodeOfRequest(client);
 | 
						||
		int numMinOpInfo;
 | 
						||
		RecordMinorOpPtr pMinorOpInfo = pRCAP->pRequestMinOpInfo;
 | 
						||
 | 
						||
		assert (pMinorOpInfo);
 | 
						||
		numMinOpInfo = pMinorOpInfo->count;
 | 
						||
		pMinorOpInfo++;
 | 
						||
		assert (numMinOpInfo);
 | 
						||
		for ( ; numMinOpInfo; numMinOpInfo--, pMinorOpInfo++)
 | 
						||
		{
 | 
						||
		    if (majorop >= pMinorOpInfo->major.first &&
 | 
						||
			majorop <= pMinorOpInfo->major.last &&
 | 
						||
			RecordIsMemberOfSet(pMinorOpInfo->major.pMinOpSet,
 | 
						||
					    minorop))
 | 
						||
		    {
 | 
						||
			if (stuff->length == 0)
 | 
						||
			    RecordABigRequest(pContext, client, stuff);
 | 
						||
			else
 | 
						||
			    RecordAProtocolElement(pContext, client, 
 | 
						||
					XRecordFromClient, (pointer)stuff,
 | 
						||
					client->req_len << 2, 0);
 | 
						||
			break;
 | 
						||
		    }			    
 | 
						||
		} /* end for each minor op info */
 | 
						||
	    } /* end extension request */
 | 
						||
	} /* end this RCAP wants this major opcode */
 | 
						||
    } /* end for each context */
 | 
						||
    pClientPriv = RecordClientPrivate(client);
 | 
						||
    assert(pClientPriv);
 | 
						||
    return (* pClientPriv->originalVector[majorop])(client);
 | 
						||
} /* RecordARequest */
 | 
						||
 | 
						||
 | 
						||
/* RecordASkippedRequest
 | 
						||
 *
 | 
						||
 * Arguments:
 | 
						||
 *	pcbl is &SkippedRequestCallback.
 | 
						||
 *	nulldata is NULL.
 | 
						||
 *	calldata is a pointer to a SkippedRequestInfoRec (include/os.h)
 | 
						||
 *	  which provides information about requests that the server is
 | 
						||
 *	  skipping.  The client's proc vector won't be called for skipped
 | 
						||
 *	  requests, so that's why we have to catch them here.
 | 
						||
 *
 | 
						||
 * Returns: nothing.
 | 
						||
 *
 | 
						||
 * Side Effects:
 | 
						||
 *	The skipped requests are recorded by all contexts that have 
 | 
						||
 *	registered those requests for this client.
 | 
						||
 *
 | 
						||
 * Note: most servers don't skip requests, so calls to this will probably
 | 
						||
 *	 be rare.  For more information on skipped requests, search for
 | 
						||
 *	 the word skip in ddx.tbl.ms (the porting layer document).
 | 
						||
 */
 | 
						||
static void
 | 
						||
RecordASkippedRequest(CallbackListPtr *pcbl, pointer nulldata, pointer calldata)
 | 
						||
{
 | 
						||
    SkippedRequestInfoRec *psi = (SkippedRequestInfoRec *)calldata;
 | 
						||
    RecordContextPtr pContext;
 | 
						||
    RecordClientsAndProtocolPtr pRCAP;
 | 
						||
    xReqPtr stuff = psi->req;
 | 
						||
    ClientPtr client = psi->client;
 | 
						||
    int numSkippedRequests = psi->numskipped;
 | 
						||
    int reqlen;
 | 
						||
    int i;
 | 
						||
    int majorop;
 | 
						||
    
 | 
						||
    while (numSkippedRequests--)
 | 
						||
    {
 | 
						||
	majorop = stuff->reqType;
 | 
						||
	reqlen = ReqLen(stuff, client);
 | 
						||
	/* handle big request */
 | 
						||
	if (stuff->length == 0)
 | 
						||
	    reqlen += 4;
 | 
						||
	for (i = 0; i < numEnabledContexts; i++)
 | 
						||
	{
 | 
						||
	    pContext = ppAllContexts[i];
 | 
						||
	    pRCAP = RecordFindClientOnContext(pContext, client->clientAsMask,
 | 
						||
					      NULL);
 | 
						||
	    if (pRCAP && pRCAP->pRequestMajorOpSet &&
 | 
						||
		RecordIsMemberOfSet(pRCAP->pRequestMajorOpSet, majorop))
 | 
						||
	    {
 | 
						||
		if (majorop <= 127)
 | 
						||
		{ /* core request */
 | 
						||
 | 
						||
		    RecordAProtocolElement(pContext, client, XRecordFromClient,
 | 
						||
				(pointer)stuff, reqlen, 0);
 | 
						||
		}
 | 
						||
		else /* extension, check minor opcode */
 | 
						||
		{
 | 
						||
		    int minorop = MinorOpcodeOfRequest(client);
 | 
						||
		    int numMinOpInfo;
 | 
						||
		    RecordMinorOpPtr pMinorOpInfo = pRCAP->pRequestMinOpInfo;
 | 
						||
 | 
						||
		    assert (pMinorOpInfo);
 | 
						||
		    numMinOpInfo = pMinorOpInfo->count;
 | 
						||
		    pMinorOpInfo++;
 | 
						||
		    assert (numMinOpInfo);
 | 
						||
		    for ( ; numMinOpInfo; numMinOpInfo--, pMinorOpInfo++)
 | 
						||
		    {
 | 
						||
			if (majorop >= pMinorOpInfo->major.first &&
 | 
						||
			    majorop <= pMinorOpInfo->major.last &&
 | 
						||
			    RecordIsMemberOfSet(pMinorOpInfo->major.pMinOpSet,
 | 
						||
						minorop))
 | 
						||
			{
 | 
						||
			    RecordAProtocolElement(pContext, client, 
 | 
						||
				    XRecordFromClient, (pointer)stuff,
 | 
						||
				    reqlen, 0);
 | 
						||
			    break;
 | 
						||
			}			    
 | 
						||
		    } /* end for each minor op info */
 | 
						||
		} /* end extension request */
 | 
						||
	    } /* end this RCAP wants this major opcode */
 | 
						||
	} /* end for each context */
 | 
						||
 | 
						||
	/* go to next request */
 | 
						||
	stuff = (xReqPtr)( ((char *)stuff) + reqlen);
 | 
						||
 | 
						||
    } /* end for each skipped request */
 | 
						||
} /* RecordASkippedRequest */
 | 
						||
 | 
						||
 | 
						||
/* RecordAReply
 | 
						||
 *
 | 
						||
 * Arguments:
 | 
						||
 *	pcbl is &ReplyCallback.
 | 
						||
 *	nulldata is NULL.
 | 
						||
 *	calldata is a pointer to a ReplyInfoRec (include/os.h)
 | 
						||
 *	  which provides information about replies that are being sent
 | 
						||
 *	  to clients.
 | 
						||
 *
 | 
						||
 * Returns: nothing.
 | 
						||
 *
 | 
						||
 * Side Effects:
 | 
						||
 *	The reply is recorded by all contexts that have registered this
 | 
						||
 *	reply type for this client.  If more data belonging to the same
 | 
						||
 *	reply is expected, and if the reply is being recorded by any
 | 
						||
 *	context, pContext->continuedReply is set to 1.
 | 
						||
 *	If pContext->continuedReply was already 1 and this is the last
 | 
						||
 *	chunk of data belonging to this reply, it is set to 0.
 | 
						||
 */
 | 
						||
static void
 | 
						||
RecordAReply(CallbackListPtr *pcbl, pointer nulldata, pointer calldata)
 | 
						||
{
 | 
						||
    RecordContextPtr pContext;
 | 
						||
    RecordClientsAndProtocolPtr pRCAP;
 | 
						||
    int eci;
 | 
						||
    int majorop;
 | 
						||
    ReplyInfoRec *pri = (ReplyInfoRec *)calldata;
 | 
						||
    ClientPtr client = pri->client;
 | 
						||
    REQUEST(xReq);
 | 
						||
 | 
						||
    majorop = stuff->reqType;
 | 
						||
    for (eci = 0; eci < numEnabledContexts; eci++)
 | 
						||
    {
 | 
						||
	pContext = ppAllContexts[eci];
 | 
						||
	pRCAP = RecordFindClientOnContext(pContext, client->clientAsMask,
 | 
						||
					  NULL);
 | 
						||
	if (pRCAP)
 | 
						||
	{
 | 
						||
	    if (pContext->continuedReply)
 | 
						||
	    {
 | 
						||
		RecordAProtocolElement(pContext, client, XRecordFromServer,
 | 
						||
		    pri->replyData, pri->dataLenBytes, /* continuation */ -1);
 | 
						||
		if (!pri->bytesRemaining)
 | 
						||
		    pContext->continuedReply = 0;
 | 
						||
	    }
 | 
						||
	    else if (pri->startOfReply && pRCAP->pReplyMajorOpSet &&
 | 
						||
		     RecordIsMemberOfSet(pRCAP->pReplyMajorOpSet, majorop))
 | 
						||
	    {
 | 
						||
		if (majorop <= 127)
 | 
						||
		{ /* core reply */
 | 
						||
		    RecordAProtocolElement(pContext, client, XRecordFromServer,
 | 
						||
		       pri->replyData, pri->dataLenBytes, pri->bytesRemaining);
 | 
						||
		    if (pri->bytesRemaining)
 | 
						||
			pContext->continuedReply = 1;
 | 
						||
		}
 | 
						||
		else /* extension, check minor opcode */
 | 
						||
		{
 | 
						||
		    int minorop = MinorOpcodeOfRequest(client);
 | 
						||
		    int numMinOpInfo;
 | 
						||
		    RecordMinorOpPtr pMinorOpInfo = pRCAP->pReplyMinOpInfo;
 | 
						||
		    		    assert (pMinorOpInfo);
 | 
						||
		    numMinOpInfo = pMinorOpInfo->count;
 | 
						||
		    pMinorOpInfo++;
 | 
						||
		    assert (numMinOpInfo);
 | 
						||
		    for ( ; numMinOpInfo; numMinOpInfo--, pMinorOpInfo++)
 | 
						||
		    {
 | 
						||
			if (majorop >= pMinorOpInfo->major.first &&
 | 
						||
			    majorop <= pMinorOpInfo->major.last &&
 | 
						||
			    RecordIsMemberOfSet(pMinorOpInfo->major.pMinOpSet,
 | 
						||
						minorop))
 | 
						||
			{
 | 
						||
			    RecordAProtocolElement(pContext, client, 
 | 
						||
				XRecordFromServer, pri->replyData,
 | 
						||
				pri->dataLenBytes, pri->bytesRemaining);
 | 
						||
			    if (pri->bytesRemaining)
 | 
						||
				pContext->continuedReply = 1;
 | 
						||
			    break;
 | 
						||
			}			    
 | 
						||
		    } /* end for each minor op info */
 | 
						||
		} /* end extension reply */
 | 
						||
	    } /* end continued reply vs. start of reply */
 | 
						||
	} /* end client is registered on this context */
 | 
						||
    } /* end for each context */
 | 
						||
} /* RecordAReply */
 | 
						||
 | 
						||
 | 
						||
/* RecordADeliveredEventOrError
 | 
						||
 *
 | 
						||
 * Arguments:
 | 
						||
 *	pcbl is &EventCallback.
 | 
						||
 *	nulldata is NULL.
 | 
						||
 *	calldata is a pointer to a EventInfoRec (include/dix.h)
 | 
						||
 *	  which provides information about events that are being sent
 | 
						||
 *	  to clients.
 | 
						||
 *
 | 
						||
 * Returns: nothing.
 | 
						||
 *
 | 
						||
 * Side Effects:
 | 
						||
 *	The event or error is recorded by all contexts that have registered
 | 
						||
 *	it for this client.
 | 
						||
 */
 | 
						||
static void
 | 
						||
RecordADeliveredEventOrError(CallbackListPtr *pcbl, pointer nulldata, pointer calldata)
 | 
						||
{
 | 
						||
    EventInfoRec *pei = (EventInfoRec *)calldata;
 | 
						||
    RecordContextPtr pContext;
 | 
						||
    RecordClientsAndProtocolPtr pRCAP;
 | 
						||
    int eci; /* enabled context index */
 | 
						||
    ClientPtr pClient = pei->client;
 | 
						||
 | 
						||
    for (eci = 0; eci < numEnabledContexts; eci++)
 | 
						||
    {
 | 
						||
	pContext = ppAllContexts[eci];
 | 
						||
	pRCAP = RecordFindClientOnContext(pContext, pClient->clientAsMask,
 | 
						||
					  NULL);
 | 
						||
	if (pRCAP && (pRCAP->pDeliveredEventSet || pRCAP->pErrorSet))
 | 
						||
	{
 | 
						||
	    int ev; /* event index */
 | 
						||
	    xEvent *pev = pei->events;
 | 
						||
	    for (ev = 0; ev < pei->count; ev++, pev++)
 | 
						||
	    {
 | 
						||
		int recordit = 0;
 | 
						||
		if (pRCAP->pErrorSet)
 | 
						||
		{
 | 
						||
		    recordit = RecordIsMemberOfSet(pRCAP->pErrorSet,
 | 
						||
						((xError *)(pev))->errorCode);
 | 
						||
		}
 | 
						||
		else if (pRCAP->pDeliveredEventSet)
 | 
						||
		{
 | 
						||
		    recordit = RecordIsMemberOfSet(pRCAP->pDeliveredEventSet,
 | 
						||
						   pev->u.u.type & 0177);
 | 
						||
		}
 | 
						||
		if (recordit)
 | 
						||
		{
 | 
						||
		    xEvent swappedEvent;
 | 
						||
		    xEvent *pEvToRecord = pev;
 | 
						||
 | 
						||
		    if (pClient->swapped)
 | 
						||
		    {
 | 
						||
			(*EventSwapVector[pev->u.u.type & 0177])
 | 
						||
			    (pev, &swappedEvent);
 | 
						||
			pEvToRecord = &swappedEvent;
 | 
						||
			
 | 
						||
		    }
 | 
						||
		    RecordAProtocolElement(pContext, pClient,
 | 
						||
			XRecordFromServer, pEvToRecord, SIZEOF(xEvent), 0);
 | 
						||
		}
 | 
						||
	    } /* end for each event */
 | 
						||
	} /* end this client is on this context */
 | 
						||
    } /* end for each enabled context */
 | 
						||
} /* RecordADeliveredEventOrError */
 | 
						||
 | 
						||
 | 
						||
/* RecordADeviceEvent
 | 
						||
 *
 | 
						||
 * Arguments:
 | 
						||
 *	pcbl is &DeviceEventCallback.
 | 
						||
 *	nulldata is NULL.
 | 
						||
 *	calldata is a pointer to a DeviceEventInfoRec (include/dix.h)
 | 
						||
 *	  which provides information about device events that occur.
 | 
						||
 *
 | 
						||
 * Returns: nothing.
 | 
						||
 *
 | 
						||
 * Side Effects:
 | 
						||
 *	The device event is recorded by all contexts that have registered
 | 
						||
 *	it for this client.
 | 
						||
 */
 | 
						||
static void
 | 
						||
RecordADeviceEvent(CallbackListPtr *pcbl, pointer nulldata, pointer calldata)
 | 
						||
{
 | 
						||
    DeviceEventInfoRec *pei = (DeviceEventInfoRec *)calldata;
 | 
						||
    RecordContextPtr pContext;
 | 
						||
    RecordClientsAndProtocolPtr pRCAP;
 | 
						||
    int eci; /* enabled context index */
 | 
						||
 | 
						||
    for (eci = 0; eci < numEnabledContexts; eci++)
 | 
						||
    {
 | 
						||
	pContext = ppAllContexts[eci];
 | 
						||
	for (pRCAP = pContext->pListOfRCAP; pRCAP; pRCAP = pRCAP->pNextRCAP)
 | 
						||
	{
 | 
						||
	    if (pRCAP->pDeviceEventSet)
 | 
						||
	    {
 | 
						||
		int ev; /* event index */
 | 
						||
		xEvent *pev = pei->events;
 | 
						||
		for (ev = 0; ev < pei->count; ev++, pev++)
 | 
						||
		{
 | 
						||
		    if (RecordIsMemberOfSet(pRCAP->pDeviceEventSet,
 | 
						||
					    pev->u.u.type & 0177))
 | 
						||
		    {
 | 
						||
		        xEvent swappedEvent;
 | 
						||
		        xEvent *pEvToRecord = pev;
 | 
						||
#ifdef PANORAMIX
 | 
						||
		        xEvent shiftedEvent;
 | 
						||
 | 
						||
			if (!noPanoramiXExtension &&
 | 
						||
			    (pev->u.u.type == MotionNotify ||
 | 
						||
			     pev->u.u.type == ButtonPress ||
 | 
						||
			     pev->u.u.type == ButtonRelease ||
 | 
						||
			     pev->u.u.type == KeyPress ||
 | 
						||
			     pev->u.u.type == KeyRelease)) {
 | 
						||
				int scr = XineramaGetCursorScreen();
 | 
						||
				memcpy(&shiftedEvent, pev, sizeof(xEvent));
 | 
						||
				shiftedEvent.u.keyButtonPointer.rootX +=
 | 
						||
				    panoramiXdataPtr[scr].x - 
 | 
						||
					panoramiXdataPtr[0].x;
 | 
						||
				shiftedEvent.u.keyButtonPointer.rootY +=
 | 
						||
				    panoramiXdataPtr[scr].y -
 | 
						||
					panoramiXdataPtr[0].y;
 | 
						||
				pEvToRecord = &shiftedEvent;
 | 
						||
			}
 | 
						||
#endif /* PANORAMIX */
 | 
						||
 | 
						||
			if (pContext->pRecordingClient->swapped)
 | 
						||
			{
 | 
						||
			    (*EventSwapVector[pEvToRecord->u.u.type & 0177])
 | 
						||
				(pEvToRecord, &swappedEvent);
 | 
						||
			    pEvToRecord = &swappedEvent;
 | 
						||
			}
 | 
						||
 | 
						||
			RecordAProtocolElement(pContext, NULL,
 | 
						||
			   XRecordFromServer,  pEvToRecord, SIZEOF(xEvent), 0);
 | 
						||
			/* make sure device events get flushed in the absence
 | 
						||
			 * of other client activity
 | 
						||
			 */
 | 
						||
			SetCriticalOutputPending();
 | 
						||
		    }
 | 
						||
		} /* end for each event */
 | 
						||
	    } /* end this RCAP selects device events */
 | 
						||
	} /* end for each RCAP on this context */
 | 
						||
    } /* end for each enabled context */
 | 
						||
} /* RecordADeviceEvent */
 | 
						||
 | 
						||
 | 
						||
/* RecordFlushAllContexts
 | 
						||
 *
 | 
						||
 * Arguments:
 | 
						||
 *	pcbl is &FlushCallback.
 | 
						||
 *	nulldata and calldata are NULL.
 | 
						||
 *
 | 
						||
 * Returns: nothing.
 | 
						||
 *
 | 
						||
 * Side Effects:
 | 
						||
 *	All buffered reply data of all enabled contexts is written to
 | 
						||
 *	the recording clients.
 | 
						||
 */
 | 
						||
static void
 | 
						||
RecordFlushAllContexts(
 | 
						||
    CallbackListPtr *pcbl,
 | 
						||
    pointer nulldata,
 | 
						||
    pointer calldata
 | 
						||
)
 | 
						||
{
 | 
						||
    int eci; /* enabled context index */
 | 
						||
    RecordContextPtr pContext;
 | 
						||
 | 
						||
    for (eci = 0; eci < numEnabledContexts; eci++)
 | 
						||
    {
 | 
						||
	pContext = ppAllContexts[eci];
 | 
						||
 | 
						||
	/* In most cases we leave it to RecordFlushReplyBuffer to make
 | 
						||
	 * this check, but this function could be called very often, so we
 | 
						||
	 * check before calling hoping to save the function call cost
 | 
						||
	 * most of the time.
 | 
						||
	 */
 | 
						||
	if (pContext->numBufBytes)
 | 
						||
	    RecordFlushReplyBuffer(ppAllContexts[eci], NULL, 0, NULL, 0);
 | 
						||
    }
 | 
						||
} /* RecordFlushAllContexts */
 | 
						||
 | 
						||
 | 
						||
/* RecordInstallHooks
 | 
						||
 *
 | 
						||
 * Arguments:
 | 
						||
 *	pRCAP is an RCAP on an enabled or being-enabled context.
 | 
						||
 *	oneclient can be zero or the resource ID mask identifying a client.
 | 
						||
 *
 | 
						||
 * Returns: BadAlloc if a memory allocation error occurred, else Success.
 | 
						||
 *
 | 
						||
 * Side Effects:
 | 
						||
 *	Recording hooks needed by RCAP are installed.
 | 
						||
 *	If oneclient is zero, recording hooks needed for all clients and
 | 
						||
 *	protocol on the RCAP are installed.  If oneclient is non-zero,
 | 
						||
 *	only those hooks needed for the specified client are installed.
 | 
						||
 *	
 | 
						||
 *	Client requestVectors may be altered.  numEnabledRCAPs will be
 | 
						||
 *	incremented if oneclient == 0.  Callbacks may be added to
 | 
						||
 *	various callback lists.
 | 
						||
 */
 | 
						||
static int
 | 
						||
RecordInstallHooks(RecordClientsAndProtocolPtr pRCAP, XID oneclient)
 | 
						||
{
 | 
						||
    int i = 0;
 | 
						||
    XID client;
 | 
						||
 | 
						||
    if (oneclient)
 | 
						||
	client = oneclient;
 | 
						||
    else
 | 
						||
	client = pRCAP->numClients ? pRCAP->pClientIDs[i++] : 0;
 | 
						||
 | 
						||
    while (client)
 | 
						||
    {
 | 
						||
	if (client != XRecordFutureClients)
 | 
						||
	{
 | 
						||
	    if (pRCAP->pRequestMajorOpSet)
 | 
						||
	    {
 | 
						||
		RecordSetIteratePtr pIter = NULL;
 | 
						||
		RecordSetInterval interval;
 | 
						||
		ClientPtr pClient = clients[CLIENT_ID(client)];
 | 
						||
 | 
						||
		if (pClient && !RecordClientPrivate(pClient))
 | 
						||
		{
 | 
						||
		    RecordClientPrivatePtr pClientPriv;
 | 
						||
		    /* no Record proc vector; allocate one */
 | 
						||
		    pClientPriv = (RecordClientPrivatePtr)
 | 
						||
				xalloc(sizeof(RecordClientPrivateRec));
 | 
						||
		    if (!pClientPriv)
 | 
						||
			return BadAlloc;
 | 
						||
		    /* copy old proc vector to new */
 | 
						||
		    memcpy(pClientPriv->recordVector, pClient->requestVector, 
 | 
						||
			   sizeof (pClientPriv->recordVector));
 | 
						||
		    pClientPriv->originalVector = pClient->requestVector;
 | 
						||
		    pClient->devPrivates[RecordClientPrivateIndex].ptr =
 | 
						||
			(pointer)pClientPriv;
 | 
						||
		    pClient->requestVector = pClientPriv->recordVector;
 | 
						||
		}
 | 
						||
		while ((pIter = RecordIterateSet(pRCAP->pRequestMajorOpSet,
 | 
						||
						pIter, &interval)))
 | 
						||
		{
 | 
						||
		    unsigned int j;
 | 
						||
		    for (j = interval.first; j <= interval.last; j++)
 | 
						||
			pClient->requestVector[j] = RecordARequest;
 | 
						||
		}
 | 
						||
	    }
 | 
						||
	}
 | 
						||
	if (oneclient)
 | 
						||
	    client = 0;
 | 
						||
	else
 | 
						||
	    client = (i < pRCAP->numClients) ? pRCAP->pClientIDs[i++] : 0;
 | 
						||
    }
 | 
						||
 | 
						||
    assert(numEnabledRCAPs >= 0);
 | 
						||
    if (!oneclient && ++numEnabledRCAPs == 1)
 | 
						||
    { /* we're enabling the first context */
 | 
						||
	if (!AddCallback(&EventCallback, RecordADeliveredEventOrError, NULL))
 | 
						||
	    return BadAlloc;
 | 
						||
	if (!AddCallback(&DeviceEventCallback, RecordADeviceEvent, NULL))
 | 
						||
	    return BadAlloc;
 | 
						||
	if (!AddCallback(&ReplyCallback, RecordAReply, NULL))
 | 
						||
	    return BadAlloc;
 | 
						||
	if (!AddCallback(&SkippedRequestsCallback, RecordASkippedRequest,
 | 
						||
			 NULL))
 | 
						||
	    return BadAlloc;
 | 
						||
	if (!AddCallback(&FlushCallback, RecordFlushAllContexts, NULL))
 | 
						||
	    return BadAlloc;
 | 
						||
	/* Alternate context flushing scheme: delete the line above
 | 
						||
	 * and call RegisterBlockAndWakeupHandlers here passing
 | 
						||
	 * RecordFlushAllContexts.  Is this any better?
 | 
						||
	 */
 | 
						||
    }
 | 
						||
    return Success;
 | 
						||
} /* RecordInstallHooks */
 | 
						||
 | 
						||
 | 
						||
/* RecordUninstallHooks
 | 
						||
 *
 | 
						||
 * Arguments:
 | 
						||
 *	pRCAP is an RCAP on an enabled or being-disabled context.
 | 
						||
 *	oneclient can be zero or the resource ID mask identifying a client.
 | 
						||
 *
 | 
						||
 * Returns: nothing.
 | 
						||
 *
 | 
						||
 * Side Effects:
 | 
						||
 *	Recording hooks needed by RCAP may be uninstalled.
 | 
						||
 *	If oneclient is zero, recording hooks needed for all clients and
 | 
						||
 *	protocol on the RCAP may be uninstalled.  If oneclient is non-zero,
 | 
						||
 *	only those hooks needed for the specified client may be uninstalled.
 | 
						||
 *	
 | 
						||
 *	Client requestVectors may be altered.  numEnabledRCAPs will be
 | 
						||
 *	decremented if oneclient == 0.  Callbacks may be deleted from
 | 
						||
 *	various callback lists.
 | 
						||
 */
 | 
						||
static void
 | 
						||
RecordUninstallHooks(RecordClientsAndProtocolPtr pRCAP, XID oneclient)
 | 
						||
{
 | 
						||
    int i = 0;
 | 
						||
    XID client;
 | 
						||
 | 
						||
    if (oneclient)
 | 
						||
	client = oneclient;
 | 
						||
    else
 | 
						||
	client = pRCAP->numClients ? pRCAP->pClientIDs[i++] : 0;
 | 
						||
 | 
						||
    while (client)
 | 
						||
    {
 | 
						||
	if (client != XRecordFutureClients)
 | 
						||
	{
 | 
						||
	    if (pRCAP->pRequestMajorOpSet)
 | 
						||
	    {
 | 
						||
		ClientPtr pClient = clients[CLIENT_ID(client)];
 | 
						||
		int c;
 | 
						||
		Bool otherRCAPwantsProcVector = FALSE;
 | 
						||
		RecordClientPrivatePtr pClientPriv =
 | 
						||
						RecordClientPrivate(pClient);
 | 
						||
 | 
						||
		assert (pClient && RecordClientPrivate(pClient));
 | 
						||
		memcpy(pClientPriv->recordVector, pClientPriv->originalVector,
 | 
						||
		       sizeof (pClientPriv->recordVector));
 | 
						||
 | 
						||
		for (c = 0; c < numEnabledContexts; c++)
 | 
						||
		{
 | 
						||
		    RecordClientsAndProtocolPtr pOtherRCAP;
 | 
						||
		    RecordContextPtr pContext = ppAllContexts[c];
 | 
						||
 | 
						||
		    if (pContext == pRCAP->pContext) continue;
 | 
						||
		    pOtherRCAP = RecordFindClientOnContext(pContext, client,
 | 
						||
							   NULL);
 | 
						||
		    if (pOtherRCAP && pOtherRCAP->pRequestMajorOpSet)
 | 
						||
		    {
 | 
						||
			RecordSetIteratePtr pIter = NULL;
 | 
						||
			RecordSetInterval interval;
 | 
						||
 | 
						||
			otherRCAPwantsProcVector = TRUE;
 | 
						||
			while ((pIter = RecordIterateSet(
 | 
						||
						pOtherRCAP->pRequestMajorOpSet,
 | 
						||
						pIter, &interval)))
 | 
						||
			{
 | 
						||
			    unsigned int j;
 | 
						||
			    for (j = interval.first; j <= interval.last; j++)
 | 
						||
				pClient->requestVector[j] = RecordARequest;
 | 
						||
			}
 | 
						||
		    }
 | 
						||
		}
 | 
						||
		if (!otherRCAPwantsProcVector)
 | 
						||
		{ /* nobody needs it, so free it */
 | 
						||
		    pClient->requestVector = pClientPriv->originalVector;
 | 
						||
		    pClient->devPrivates[RecordClientPrivateIndex].ptr = NULL;
 | 
						||
		    xfree(pClientPriv);
 | 
						||
		}
 | 
						||
	    } /* end if this RCAP specifies any requests */
 | 
						||
	} /* end if not future clients */
 | 
						||
	if (oneclient)
 | 
						||
	    client = 0;
 | 
						||
	else
 | 
						||
	    client = (i < pRCAP->numClients) ? pRCAP->pClientIDs[i++] : 0;
 | 
						||
    }
 | 
						||
 | 
						||
    assert(numEnabledRCAPs >= 1);
 | 
						||
    if (!oneclient && --numEnabledRCAPs == 0)
 | 
						||
    { /* we're disabling the last context */
 | 
						||
	DeleteCallback(&EventCallback, RecordADeliveredEventOrError, NULL);
 | 
						||
	DeleteCallback(&DeviceEventCallback, RecordADeviceEvent, NULL);
 | 
						||
	DeleteCallback(&ReplyCallback, RecordAReply, NULL);
 | 
						||
	DeleteCallback(&SkippedRequestsCallback, RecordASkippedRequest, NULL);
 | 
						||
	DeleteCallback(&FlushCallback, RecordFlushAllContexts, NULL);
 | 
						||
	/* Alternate context flushing scheme: delete the line above
 | 
						||
	 * and call RemoveBlockAndWakeupHandlers here passing
 | 
						||
	 * RecordFlushAllContexts.  Is this any better?
 | 
						||
	 */
 | 
						||
	/* Having deleted the callback, call it one last time. -gildea */
 | 
						||
	RecordFlushAllContexts(&FlushCallback, NULL, NULL);
 | 
						||
    }
 | 
						||
} /* RecordUninstallHooks */
 | 
						||
 | 
						||
 | 
						||
/* RecordDeleteClientFromRCAP
 | 
						||
 *
 | 
						||
 * Arguments:
 | 
						||
 *	pRCAP is an RCAP to delete the client from.
 | 
						||
 *	position is the index into the array pRCAP->pClientIDs of the
 | 
						||
 *	client to delete.
 | 
						||
 *
 | 
						||
 * Returns: nothing.
 | 
						||
 *
 | 
						||
 * Side Effects:
 | 
						||
 *	Recording hooks needed by client will be uninstalled if the context
 | 
						||
 *	is enabled.  The designated client will be removed from the 
 | 
						||
 *	pRCAP->pClientIDs array.  If it was the only client on the RCAP, 
 | 
						||
 *	the RCAP is removed from the context and freed.  (Invariant: RCAPs
 | 
						||
 *	have at least one client.)
 | 
						||
 */
 | 
						||
static void
 | 
						||
RecordDeleteClientFromRCAP(RecordClientsAndProtocolPtr pRCAP, int position)
 | 
						||
{
 | 
						||
    if (pRCAP->pContext->pRecordingClient)
 | 
						||
	RecordUninstallHooks(pRCAP, pRCAP->pClientIDs[position]);
 | 
						||
    if (position != pRCAP->numClients - 1)
 | 
						||
	pRCAP->pClientIDs[position] = pRCAP->pClientIDs[pRCAP->numClients - 1];
 | 
						||
    if (--pRCAP->numClients == 0)
 | 
						||
    {	/* no more clients; remove RCAP from context's list */
 | 
						||
	RecordContextPtr pContext = pRCAP->pContext;
 | 
						||
	if (pContext->pRecordingClient)
 | 
						||
	    RecordUninstallHooks(pRCAP, 0);
 | 
						||
	if (pContext->pListOfRCAP == pRCAP)
 | 
						||
	    pContext->pListOfRCAP = pRCAP->pNextRCAP;
 | 
						||
	else
 | 
						||
	{
 | 
						||
	    RecordClientsAndProtocolPtr prevRCAP;
 | 
						||
	    for (prevRCAP = pContext->pListOfRCAP;
 | 
						||
		 prevRCAP->pNextRCAP != pRCAP;
 | 
						||
		 prevRCAP = prevRCAP->pNextRCAP)
 | 
						||
		;
 | 
						||
	    prevRCAP->pNextRCAP = pRCAP->pNextRCAP;
 | 
						||
	}
 | 
						||
	/* free the RCAP */
 | 
						||
	if (pRCAP->clientIDsSeparatelyAllocated)
 | 
						||
	    xfree(pRCAP->pClientIDs);
 | 
						||
	xfree(pRCAP);
 | 
						||
    }
 | 
						||
} /* RecordDeleteClientFromRCAP */
 | 
						||
 | 
						||
 | 
						||
/* RecordAddClientToRCAP
 | 
						||
 *
 | 
						||
 * Arguments:
 | 
						||
 *	pRCAP is an RCAP to add the client to.
 | 
						||
 *	clientspec is the resource ID mask identifying a client, or
 | 
						||
 *	  XRecordFutureClients.
 | 
						||
 *
 | 
						||
 * Returns: nothing.
 | 
						||
 *
 | 
						||
 * Side Effects:
 | 
						||
 *	Recording hooks needed by client will be installed if the context
 | 
						||
 *	is enabled.  The designated client will be added to the 
 | 
						||
 *	pRCAP->pClientIDs array, which may be realloced.
 | 
						||
 *	pRCAP->clientIDsSeparatelyAllocated may be set to 1 if there
 | 
						||
 *	is no more room to hold clients internal to the RCAP.
 | 
						||
 */
 | 
						||
static void
 | 
						||
RecordAddClientToRCAP(RecordClientsAndProtocolPtr pRCAP, XID clientspec)
 | 
						||
{
 | 
						||
    if (pRCAP->numClients == pRCAP->sizeClients)
 | 
						||
    {
 | 
						||
	if (pRCAP->clientIDsSeparatelyAllocated)
 | 
						||
	{
 | 
						||
	    XID *pNewIDs = (XID *)xrealloc(pRCAP->pClientIDs,
 | 
						||
			(pRCAP->sizeClients + CLIENT_ARRAY_GROWTH_INCREMENT) *
 | 
						||
								sizeof(XID));
 | 
						||
	    if (!pNewIDs)
 | 
						||
		return;
 | 
						||
	    pRCAP->pClientIDs = pNewIDs;
 | 
						||
	    pRCAP->sizeClients += CLIENT_ARRAY_GROWTH_INCREMENT;
 | 
						||
	}
 | 
						||
	else
 | 
						||
	{
 | 
						||
	    XID *pNewIDs = (XID *)xalloc((pRCAP->sizeClients +
 | 
						||
				CLIENT_ARRAY_GROWTH_INCREMENT) * sizeof(XID));
 | 
						||
	    if (!pNewIDs)
 | 
						||
		return;
 | 
						||
	    memcpy(pNewIDs, pRCAP->pClientIDs, pRCAP->numClients *sizeof(XID));
 | 
						||
	    pRCAP->pClientIDs = pNewIDs;
 | 
						||
	    pRCAP->sizeClients += CLIENT_ARRAY_GROWTH_INCREMENT;
 | 
						||
	    pRCAP->clientIDsSeparatelyAllocated = 1;
 | 
						||
	}
 | 
						||
    }
 | 
						||
    pRCAP->pClientIDs[pRCAP->numClients++] = clientspec;
 | 
						||
    if (pRCAP->pContext->pRecordingClient)
 | 
						||
	RecordInstallHooks(pRCAP, clientspec);
 | 
						||
} /* RecordDeleteClientFromRCAP */
 | 
						||
 | 
						||
 | 
						||
/* RecordDeleteClientFromContext
 | 
						||
 *
 | 
						||
 * Arguments:
 | 
						||
 *	pContext is the context to delete from.
 | 
						||
 *	clientspec is the resource ID mask identifying a client, or
 | 
						||
 *	  XRecordFutureClients.
 | 
						||
 *
 | 
						||
 * Returns: nothing.
 | 
						||
 *
 | 
						||
 * Side Effects:
 | 
						||
 *	If clientspec is on any RCAP of the context, it is deleted from that
 | 
						||
 *	RCAP.  (A given clientspec can only be on one RCAP of a context.)
 | 
						||
 */
 | 
						||
static void
 | 
						||
RecordDeleteClientFromContext(RecordContextPtr pContext, XID clientspec)
 | 
						||
{
 | 
						||
    RecordClientsAndProtocolPtr pRCAP;
 | 
						||
    int position;
 | 
						||
 | 
						||
    if ((pRCAP = RecordFindClientOnContext(pContext, clientspec, &position)))
 | 
						||
	RecordDeleteClientFromRCAP(pRCAP, position);
 | 
						||
} /* RecordDeleteClientFromContext */
 | 
						||
 | 
						||
 | 
						||
/* RecordSanityCheckClientSpecifiers
 | 
						||
 *
 | 
						||
 * Arguments:
 | 
						||
 *	clientspecs is an array of alleged CLIENTSPECs passed by the client.
 | 
						||
 *	nspecs is the number of elements in clientspecs.
 | 
						||
 *	errorspec, if non-zero, is the resource id base of a client that
 | 
						||
 *	  must not appear in clienspecs.
 | 
						||
 *
 | 
						||
 * Returns: BadMatch if any of the clientspecs are invalid, else Success.
 | 
						||
 *
 | 
						||
 * Side Effects: none.
 | 
						||
 */
 | 
						||
static int
 | 
						||
RecordSanityCheckClientSpecifiers(XID *clientspecs, int nspecs, XID errorspec)
 | 
						||
{
 | 
						||
    int i;
 | 
						||
    int clientIndex;
 | 
						||
 | 
						||
    for (i = 0; i < nspecs; i++)
 | 
						||
    {
 | 
						||
	if (clientspecs[i] == XRecordCurrentClients ||
 | 
						||
	    clientspecs[i] == XRecordFutureClients ||
 | 
						||
	    clientspecs[i] == XRecordAllClients)
 | 
						||
	    continue;
 | 
						||
	if (errorspec && (CLIENT_BITS(clientspecs[i]) == errorspec) )
 | 
						||
	    return BadMatch;
 | 
						||
	clientIndex = CLIENT_ID(clientspecs[i]);
 | 
						||
	if (clientIndex && clients[clientIndex] &&
 | 
						||
	    clients[clientIndex]->clientState == ClientStateRunning)
 | 
						||
	{
 | 
						||
	    if (clientspecs[i] == clients[clientIndex]->clientAsMask)
 | 
						||
		continue;
 | 
						||
	    if (!LookupIDByClass(clientspecs[i], RC_ANY))
 | 
						||
		return BadMatch;
 | 
						||
	}
 | 
						||
	else
 | 
						||
	    return BadMatch;
 | 
						||
    }
 | 
						||
    return Success;
 | 
						||
} /* RecordSanityCheckClientSpecifiers */
 | 
						||
 | 
						||
 | 
						||
/* RecordCanonicalizeClientSpecifiers
 | 
						||
 *
 | 
						||
 * Arguments:
 | 
						||
 *	pClientspecs is an array of CLIENTSPECs that have been sanity
 | 
						||
 *	  checked.
 | 
						||
 *	pNumClientspecs is a pointer to the number of elements in pClientspecs.
 | 
						||
 *	excludespec, if non-zero, is the resource id base of a client that 
 | 
						||
 *	  should not be included in the expansion of XRecordAllClients or 
 | 
						||
 *	  XRecordCurrentClients.
 | 
						||
 *
 | 
						||
 * Returns:
 | 
						||
 *	A pointer to an array of CLIENTSPECs that is the same as the
 | 
						||
 *	passed array with the following modifications:
 | 
						||
 *	  - all but the client id bits of resource IDs are stripped off.
 | 
						||
 *	  - duplicates removed.
 | 
						||
 *	  - XRecordAllClients expanded to a list of all currently connected
 | 
						||
 *	    clients + XRecordFutureClients - excludespec (if non-zero)
 | 
						||
 *	  - XRecordCurrentClients expanded to a list of all currently
 | 
						||
 *	    connected clients - excludespec (if non-zero)
 | 
						||
 *	The returned array may be the passed array modified in place, or
 | 
						||
 *	it may be an Xalloc'ed array.  The caller should keep a pointer to the
 | 
						||
 *	original array and free the returned array if it is different.
 | 
						||
 *
 | 
						||
 *	*pNumClientspecs is set to the number of elements in the returned
 | 
						||
 *	array.
 | 
						||
 *
 | 
						||
 * Side Effects:
 | 
						||
 *	pClientspecs may be modified in place.
 | 
						||
 */
 | 
						||
static XID *
 | 
						||
RecordCanonicalizeClientSpecifiers(XID *pClientspecs, int *pNumClientspecs, XID excludespec)
 | 
						||
{
 | 
						||
    int i;
 | 
						||
    int numClients = *pNumClientspecs;
 | 
						||
 | 
						||
    /*  first pass strips off the resource index bits, leaving just the
 | 
						||
     *  client id bits.  This makes searching for a particular client simpler
 | 
						||
     *  (and faster.)
 | 
						||
     */
 | 
						||
    for (i = 0; i < numClients; i++)
 | 
						||
    {
 | 
						||
	XID cs = pClientspecs[i];
 | 
						||
	if (cs > XRecordAllClients)
 | 
						||
	    pClientspecs[i] = CLIENT_BITS(cs);
 | 
						||
    }
 | 
						||
 | 
						||
    for (i = 0; i < numClients; i++)
 | 
						||
    {
 | 
						||
	if (pClientspecs[i] == XRecordAllClients ||
 | 
						||
	    pClientspecs[i] == XRecordCurrentClients)
 | 
						||
	{ /* expand All/Current */
 | 
						||
	    int j, nc;
 | 
						||
	    XID *pCanon = (XID *)xalloc(sizeof(XID) * (currentMaxClients + 1));
 | 
						||
	    if (!pCanon) return NULL;
 | 
						||
	    for (nc = 0, j = 1; j < currentMaxClients; j++)
 | 
						||
	    {
 | 
						||
		ClientPtr client = clients[j];
 | 
						||
		if (client != NullClient &&
 | 
						||
		    client->clientState == ClientStateRunning &&
 | 
						||
		    client->clientAsMask != excludespec)
 | 
						||
		{
 | 
						||
		    pCanon[nc++] = client->clientAsMask;
 | 
						||
		}
 | 
						||
	    }
 | 
						||
	    if (pClientspecs[i] == XRecordAllClients)
 | 
						||
		pCanon[nc++] = XRecordFutureClients;
 | 
						||
	    *pNumClientspecs = nc;
 | 
						||
	    return pCanon;
 | 
						||
	}
 | 
						||
	else /* not All or Current */
 | 
						||
	{
 | 
						||
	    int j;
 | 
						||
	    for (j = i + 1; j < numClients; )
 | 
						||
	    {
 | 
						||
		if (pClientspecs[i] == pClientspecs[j])
 | 
						||
		{
 | 
						||
		    pClientspecs[j] = pClientspecs[--numClients];
 | 
						||
		}
 | 
						||
		else
 | 
						||
		    j++;
 | 
						||
	    }
 | 
						||
	}
 | 
						||
    } /* end for each clientspec */
 | 
						||
    *pNumClientspecs = numClients;
 | 
						||
    return pClientspecs;
 | 
						||
} /* RecordCanonicalizeClientSpecifiers */
 | 
						||
 | 
						||
 | 
						||
/****************************************************************************/
 | 
						||
 | 
						||
/* stuff for RegisterClients */
 | 
						||
 | 
						||
/* RecordPadAlign
 | 
						||
 *
 | 
						||
 * Arguments:
 | 
						||
 *	size is the number of bytes taken by an object.
 | 
						||
 *	align is a byte boundary (e.g. 4, 8)
 | 
						||
 *
 | 
						||
 * Returns:
 | 
						||
 *	the number of pad bytes to add at the end of an object of the
 | 
						||
 *	given size so that an object placed immediately behind it will
 | 
						||
 *	begin on an <align>-byte boundary.
 | 
						||
 *
 | 
						||
 * Side Effects: none.
 | 
						||
 */
 | 
						||
static int
 | 
						||
RecordPadAlign(int size, int align)
 | 
						||
{
 | 
						||
    return (align - (size & (align - 1))) & (align - 1);
 | 
						||
} /* RecordPadAlign */
 | 
						||
 | 
						||
 | 
						||
/* RecordSanityCheckRegisterClients
 | 
						||
 *
 | 
						||
 * Arguments:
 | 
						||
 *	pContext is the context being registered on.
 | 
						||
 *	client is the client that issued a RecordCreateContext or
 | 
						||
 *	  RecordRegisterClients request.
 | 
						||
 *	stuff is a pointer to the request.
 | 
						||
 *
 | 
						||
 * Returns:
 | 
						||
 *	Any one of several possible error values if any of the request
 | 
						||
 *	arguments are invalid.  Success if everything is OK.
 | 
						||
 *
 | 
						||
 * Side Effects: none.
 | 
						||
 */
 | 
						||
static int
 | 
						||
RecordSanityCheckRegisterClients(RecordContextPtr pContext, ClientPtr client, xRecordRegisterClientsReq *stuff)
 | 
						||
{
 | 
						||
    int err;
 | 
						||
    xRecordRange *pRange;
 | 
						||
    int i;
 | 
						||
    XID recordingClient;
 | 
						||
 | 
						||
    if (((client->req_len << 2) - SIZEOF(xRecordRegisterClientsReq)) !=
 | 
						||
	4 * stuff->nClients + SIZEOF(xRecordRange) * stuff->nRanges)
 | 
						||
	return BadLength;
 | 
						||
 | 
						||
    if (stuff->elementHeader &
 | 
						||
     ~(XRecordFromClientSequence|XRecordFromClientTime|XRecordFromServerTime))
 | 
						||
    {
 | 
						||
	client->errorValue = stuff->elementHeader;
 | 
						||
	return BadValue;
 | 
						||
    }
 | 
						||
 | 
						||
    recordingClient = pContext->pRecordingClient ?
 | 
						||
		      pContext->pRecordingClient->clientAsMask : 0;
 | 
						||
    err = RecordSanityCheckClientSpecifiers((XID *)&stuff[1], stuff->nClients,
 | 
						||
					    recordingClient);
 | 
						||
    if (err != Success) return err;
 | 
						||
 | 
						||
    pRange = (xRecordRange *)(((XID *)&stuff[1]) + stuff->nClients);
 | 
						||
    for (i = 0; i < stuff->nRanges; i++, pRange++)
 | 
						||
    {
 | 
						||
	if (pRange->coreRequestsFirst > pRange->coreRequestsLast)
 | 
						||
	{
 | 
						||
	    client->errorValue = pRange->coreRequestsFirst;
 | 
						||
	    return BadValue;
 | 
						||
	}
 | 
						||
	if (pRange->coreRepliesFirst > pRange->coreRepliesLast)
 | 
						||
	{
 | 
						||
	    client->errorValue = pRange->coreRepliesFirst;
 | 
						||
	    return BadValue;
 | 
						||
	}
 | 
						||
	if ((pRange->extRequestsMajorFirst || pRange->extRequestsMajorLast) &&
 | 
						||
	    (pRange->extRequestsMajorFirst < 128 ||
 | 
						||
	     pRange->extRequestsMajorLast < 128 ||
 | 
						||
	     pRange->extRequestsMajorFirst > pRange->extRequestsMajorLast))
 | 
						||
	{
 | 
						||
	    client->errorValue = pRange->extRequestsMajorFirst;
 | 
						||
	    return BadValue;
 | 
						||
	}
 | 
						||
	if (pRange->extRequestsMinorFirst > pRange->extRequestsMinorLast)
 | 
						||
	{
 | 
						||
	    client->errorValue = pRange->extRequestsMinorFirst;
 | 
						||
	    return BadValue;
 | 
						||
	}
 | 
						||
	if ((pRange->extRepliesMajorFirst || pRange->extRepliesMajorLast) &&
 | 
						||
	    (pRange->extRepliesMajorFirst < 128 ||
 | 
						||
	     pRange->extRepliesMajorLast < 128 ||
 | 
						||
	     pRange->extRepliesMajorFirst > pRange->extRepliesMajorLast))
 | 
						||
	{
 | 
						||
	    client->errorValue = pRange->extRepliesMajorFirst;
 | 
						||
	    return BadValue;
 | 
						||
	}
 | 
						||
	if (pRange->extRepliesMinorFirst > pRange->extRepliesMinorLast)
 | 
						||
	{
 | 
						||
	    client->errorValue = pRange->extRepliesMinorFirst;
 | 
						||
	    return BadValue;
 | 
						||
	}
 | 
						||
	if ((pRange->deliveredEventsFirst || pRange->deliveredEventsLast) &&
 | 
						||
	    (pRange->deliveredEventsFirst < 2 ||
 | 
						||
	     pRange->deliveredEventsLast < 2 ||
 | 
						||
	     pRange->deliveredEventsFirst > pRange->deliveredEventsLast))
 | 
						||
	{
 | 
						||
	    client->errorValue = pRange->deliveredEventsFirst;
 | 
						||
	    return BadValue;
 | 
						||
	}
 | 
						||
	if ((pRange->deviceEventsFirst || pRange->deviceEventsLast) &&
 | 
						||
	    (pRange->deviceEventsFirst < 2 ||
 | 
						||
	     pRange->deviceEventsLast < 2 ||
 | 
						||
	     pRange->deviceEventsFirst > pRange->deviceEventsLast))
 | 
						||
	{
 | 
						||
	    client->errorValue = pRange->deviceEventsFirst;
 | 
						||
	    return BadValue;
 | 
						||
	}
 | 
						||
	if (pRange->errorsFirst > pRange->errorsLast)
 | 
						||
	{
 | 
						||
	    client->errorValue = pRange->errorsFirst;
 | 
						||
	    return BadValue;
 | 
						||
	}
 | 
						||
	if (pRange->clientStarted != xFalse && pRange->clientStarted != xTrue)
 | 
						||
	{
 | 
						||
	    client->errorValue = pRange->clientStarted;
 | 
						||
	    return BadValue;
 | 
						||
	}
 | 
						||
	if (pRange->clientDied != xFalse && pRange->clientDied != xTrue)
 | 
						||
	{
 | 
						||
	    client->errorValue = pRange->clientDied;
 | 
						||
	    return BadValue;
 | 
						||
	}
 | 
						||
    } /* end for each range */
 | 
						||
    return Success;
 | 
						||
} /* end RecordSanityCheckRegisterClients */
 | 
						||
 | 
						||
/* This is a tactical structure used to gather information about all the sets
 | 
						||
 * (RecordSetPtr) that need to be created for an RCAP in the process of 
 | 
						||
 * digesting a list of RECORDRANGEs (converting it to the internal
 | 
						||
 * representation).
 | 
						||
 */
 | 
						||
typedef struct
 | 
						||
{
 | 
						||
    int nintervals;	/* number of intervals in following array */
 | 
						||
    RecordSetInterval *intervals;  /* array of intervals for this set */
 | 
						||
    int size;		/* size of intevals array; >= nintervals */
 | 
						||
    int align;		/* alignment restriction for set */
 | 
						||
    int offset;		/* where to store set pointer rel. to start of RCAP */
 | 
						||
    short first, last;	/* if for extension, major opcode interval */
 | 
						||
} SetInfoRec, *SetInfoPtr;
 | 
						||
 | 
						||
/* These constant are used to index into an array of SetInfoRec. */
 | 
						||
enum {REQ,	/* set info for requests */
 | 
						||
      REP,	/* set info for replies */
 | 
						||
      ERR,	/* set info for errors */
 | 
						||
      DEV,	/* set info for device events */
 | 
						||
      DLEV,	/* set info for delivered events */
 | 
						||
      PREDEFSETS};  /* number of predefined array entries */
 | 
						||
 | 
						||
 | 
						||
/* RecordAllocIntervals
 | 
						||
 *
 | 
						||
 * Arguments:
 | 
						||
 *	psi is a pointer to a SetInfoRec whose intervals pointer is NULL.
 | 
						||
 *	nIntervals is the desired size of the intervals array.
 | 
						||
 *
 | 
						||
 * Returns: BadAlloc if a memory allocation error occurred, else Success.
 | 
						||
 *
 | 
						||
 * Side Effects:
 | 
						||
 *	If Success is returned, psi->intervals is a pointer to size
 | 
						||
 *	RecordSetIntervals, all zeroed, and psi->size is set to size.
 | 
						||
 */
 | 
						||
static int
 | 
						||
RecordAllocIntervals(SetInfoPtr psi, int nIntervals)
 | 
						||
{
 | 
						||
    assert(!psi->intervals);
 | 
						||
    psi->intervals = (RecordSetInterval *)
 | 
						||
			xalloc(nIntervals * sizeof(RecordSetInterval));
 | 
						||
    if (!psi->intervals)
 | 
						||
	return BadAlloc;
 | 
						||
    bzero(psi->intervals, nIntervals * sizeof(RecordSetInterval));
 | 
						||
    psi->size = nIntervals;
 | 
						||
    return Success;
 | 
						||
} /* end RecordAllocIntervals */
 | 
						||
 | 
						||
 | 
						||
/* RecordConvertRangesToIntervals
 | 
						||
 *
 | 
						||
 * Arguments:
 | 
						||
 *	psi is a pointer to the SetInfoRec we are building.
 | 
						||
 *	pRanges is an array of xRecordRanges.
 | 
						||
 *	nRanges is the number of elements in pRanges.
 | 
						||
 *	byteoffset is the offset from the start of an xRecordRange of the
 | 
						||
 *	  two bytes (1 for first, 1 for last) we are interested in.
 | 
						||
 *	pExtSetInfo, if non-NULL, indicates that the two bytes mentioned
 | 
						||
 *	  above are followed by four bytes (2 for first, 2 for last)
 | 
						||
 *	  representing a minor opcode range, and this information should be
 | 
						||
 *	  stored in one of the SetInfoRecs starting at pExtSetInfo.
 | 
						||
 *	pnExtSetInfo is the number of elements in the pExtSetInfo array.
 | 
						||
 *
 | 
						||
 * Returns:  BadAlloc if a memory allocation error occurred, else Success.
 | 
						||
 *
 | 
						||
 * Side Effects:
 | 
						||
 *	The slice of pRanges indicated by byteoffset is stored in psi.  
 | 
						||
 *	If pExtSetInfo is non-NULL, minor opcode intervals are stored
 | 
						||
 *	in an existing SetInfoRec if the major opcode interval matches, else
 | 
						||
 *	they are stored in a new SetInfoRec, and *pnExtSetInfo is
 | 
						||
 *	increased accordingly.
 | 
						||
 */
 | 
						||
static int
 | 
						||
RecordConvertRangesToIntervals(
 | 
						||
    SetInfoPtr psi,
 | 
						||
    xRecordRange *pRanges,
 | 
						||
    int nRanges,
 | 
						||
    int byteoffset,
 | 
						||
    SetInfoPtr pExtSetInfo,
 | 
						||
    int *pnExtSetInfo
 | 
						||
)
 | 
						||
{
 | 
						||
    int i;
 | 
						||
    CARD8 *pCARD8;
 | 
						||
    int first, last;
 | 
						||
    int err;
 | 
						||
 | 
						||
    for (i = 0; i < nRanges; i++, pRanges++)
 | 
						||
    {
 | 
						||
	pCARD8 = ((CARD8 *)pRanges) + byteoffset;
 | 
						||
	first = pCARD8[0];
 | 
						||
	last  = pCARD8[1];
 | 
						||
	if (first || last)
 | 
						||
	{
 | 
						||
	    if (!psi->intervals)
 | 
						||
	    {
 | 
						||
		err = RecordAllocIntervals(psi, 2 * (nRanges - i));
 | 
						||
		if (err != Success)
 | 
						||
		    return err;
 | 
						||
	    }
 | 
						||
	    psi->intervals[psi->nintervals].first = first;
 | 
						||
	    psi->intervals[psi->nintervals].last  = last;
 | 
						||
	    psi->nintervals++;
 | 
						||
	    assert(psi->nintervals <= psi->size);
 | 
						||
	    if (pExtSetInfo)
 | 
						||
	    {
 | 
						||
		SetInfoPtr pesi = pExtSetInfo;
 | 
						||
		CARD16 *pCARD16 = (CARD16 *)(pCARD8 + 2);
 | 
						||
		int j;
 | 
						||
 | 
						||
		for (j = 0; j < *pnExtSetInfo; j++, pesi++)
 | 
						||
		{
 | 
						||
		    if ( (first == pesi->first) && (last == pesi->last) )
 | 
						||
			break;
 | 
						||
		}
 | 
						||
		if (j == *pnExtSetInfo)
 | 
						||
		{
 | 
						||
		    err = RecordAllocIntervals(pesi, 2 * (nRanges - i));
 | 
						||
		    if (err != Success)
 | 
						||
			return err;
 | 
						||
		    pesi->first = first;
 | 
						||
		    pesi->last  = last;
 | 
						||
		    (*pnExtSetInfo)++;
 | 
						||
		}
 | 
						||
		pesi->intervals[pesi->nintervals].first = pCARD16[0];
 | 
						||
		pesi->intervals[pesi->nintervals].last  = pCARD16[1];
 | 
						||
		pesi->nintervals++;
 | 
						||
		assert(pesi->nintervals <= pesi->size);
 | 
						||
	    }
 | 
						||
	}
 | 
						||
    }
 | 
						||
    return Success;
 | 
						||
}  /* end RecordConvertRangesToIntervals */
 | 
						||
 | 
						||
#define offset_of(_structure, _field) \
 | 
						||
    ((char *)(& (_structure . _field)) - (char *)(&_structure))
 | 
						||
 | 
						||
/* RecordRegisterClients
 | 
						||
 *
 | 
						||
 * Arguments:
 | 
						||
 *	pContext is the context on which to register the clients.
 | 
						||
 *	client is the client that issued the RecordCreateContext or
 | 
						||
 *	  RecordRegisterClients request.
 | 
						||
 *	stuff is a pointer to the request.
 | 
						||
 *
 | 
						||
 * Returns:
 | 
						||
 *	Any one of several possible error values defined by the protocol.
 | 
						||
 *	Success if everything is OK.
 | 
						||
 *
 | 
						||
 * Side Effects:
 | 
						||
 *	If different element headers are specified, the context is flushed.
 | 
						||
 *	If any of the specified clients are already registered on the
 | 
						||
 *	context, they are first unregistered.  A new RCAP is created to
 | 
						||
 *	hold the specified protocol and clients, and it is linked onto the
 | 
						||
 *	context.  If the context is enabled, appropriate hooks are installed
 | 
						||
 *	to record the new clients and protocol.
 | 
						||
 */
 | 
						||
static int
 | 
						||
RecordRegisterClients(RecordContextPtr pContext, ClientPtr client, xRecordRegisterClientsReq *stuff)
 | 
						||
{
 | 
						||
    int err;
 | 
						||
    int i;
 | 
						||
    SetInfoPtr si;
 | 
						||
    int maxSets;
 | 
						||
    int nExtReqSets = 0;
 | 
						||
    int nExtRepSets = 0;
 | 
						||
    int extReqSetsOffset = 0;
 | 
						||
    int extRepSetsOffset = 0;
 | 
						||
    SetInfoPtr pExtReqSets, pExtRepSets;
 | 
						||
    int clientListOffset;
 | 
						||
    XID *pCanonClients;
 | 
						||
    int clientStarted = 0, clientDied = 0;
 | 
						||
    xRecordRange *pRanges, rr;
 | 
						||
    int nClients;
 | 
						||
    int sizeClients;
 | 
						||
    int totRCAPsize;
 | 
						||
    RecordClientsAndProtocolPtr pRCAP;
 | 
						||
    int pad;
 | 
						||
    XID recordingClient;
 | 
						||
 | 
						||
    /* do all sanity checking up front */
 | 
						||
 | 
						||
    err = RecordSanityCheckRegisterClients(pContext, client, stuff);
 | 
						||
    if (err != Success)
 | 
						||
	return err;
 | 
						||
 | 
						||
    /* if element headers changed, flush buffer */
 | 
						||
	
 | 
						||
    if (pContext->elemHeaders != stuff->elementHeader)
 | 
						||
    {
 | 
						||
	RecordFlushReplyBuffer(pContext, NULL, 0, NULL, 0);
 | 
						||
	pContext->elemHeaders = stuff->elementHeader;
 | 
						||
    }
 | 
						||
 | 
						||
    nClients = stuff->nClients;
 | 
						||
    if (!nClients)
 | 
						||
	/* if empty clients list, we're done. */
 | 
						||
	return Success;
 | 
						||
 | 
						||
    recordingClient = pContext->pRecordingClient ?
 | 
						||
		      pContext->pRecordingClient->clientAsMask : 0;
 | 
						||
    pCanonClients = RecordCanonicalizeClientSpecifiers((XID *)&stuff[1],
 | 
						||
						 &nClients, recordingClient);
 | 
						||
    if (!pCanonClients)
 | 
						||
	return BadAlloc;
 | 
						||
 | 
						||
    /* We may have to create as many as one set for each "predefined"
 | 
						||
     * protocol types, plus one per range for extension reuests, plus one per
 | 
						||
     * range for extension replies.
 | 
						||
     */
 | 
						||
    maxSets = PREDEFSETS + 2 * stuff->nRanges;
 | 
						||
    si = (SetInfoPtr)ALLOCATE_LOCAL(sizeof(SetInfoRec) * maxSets);
 | 
						||
    if (!si)
 | 
						||
    {
 | 
						||
	err = BadAlloc;
 | 
						||
	goto bailout;
 | 
						||
    }
 | 
						||
    bzero(si, sizeof(SetInfoRec) * maxSets);
 | 
						||
 | 
						||
    /* theoretically you must do this because NULL may not be all-bits-zero */
 | 
						||
    for (i = 0; i < maxSets; i++)
 | 
						||
	si[i].intervals = NULL;
 | 
						||
 | 
						||
    pExtReqSets = si + PREDEFSETS;
 | 
						||
    pExtRepSets = pExtReqSets + stuff->nRanges;
 | 
						||
 | 
						||
    pRanges = (xRecordRange *)(((XID *)&stuff[1]) + stuff->nClients);
 | 
						||
 | 
						||
    err = RecordConvertRangesToIntervals(&si[REQ], pRanges, stuff->nRanges,
 | 
						||
			offset_of(rr, coreRequestsFirst), NULL, NULL);
 | 
						||
    if (err != Success) goto bailout;
 | 
						||
 | 
						||
    err = RecordConvertRangesToIntervals(&si[REQ], pRanges, stuff->nRanges,
 | 
						||
	   offset_of(rr, extRequestsMajorFirst), pExtReqSets, &nExtReqSets);
 | 
						||
    if (err != Success) goto bailout;
 | 
						||
 | 
						||
    err = RecordConvertRangesToIntervals(&si[REP], pRanges, stuff->nRanges,
 | 
						||
			offset_of(rr, coreRepliesFirst), NULL, NULL);
 | 
						||
    if (err != Success) goto bailout;
 | 
						||
 | 
						||
    err = RecordConvertRangesToIntervals(&si[REP], pRanges, stuff->nRanges,
 | 
						||
	   offset_of(rr, extRepliesMajorFirst), pExtRepSets, &nExtRepSets);
 | 
						||
    if (err != Success) goto bailout;
 | 
						||
 | 
						||
    err = RecordConvertRangesToIntervals(&si[ERR], pRanges, stuff->nRanges,
 | 
						||
			offset_of(rr, errorsFirst), NULL, NULL);
 | 
						||
    if (err != Success) goto bailout;
 | 
						||
 | 
						||
    err = RecordConvertRangesToIntervals(&si[DLEV], pRanges, stuff->nRanges,
 | 
						||
			offset_of(rr, deliveredEventsFirst), NULL, NULL);
 | 
						||
    if (err != Success) goto bailout;
 | 
						||
 | 
						||
    err = RecordConvertRangesToIntervals(&si[DEV], pRanges, stuff->nRanges,
 | 
						||
			offset_of(rr, deviceEventsFirst), NULL, NULL);
 | 
						||
    if (err != Success) goto bailout;
 | 
						||
 | 
						||
    /* collect client-started and client-died */
 | 
						||
 | 
						||
    for (i = 0; i < stuff->nRanges; i++)
 | 
						||
    {
 | 
						||
	if (pRanges[i].clientStarted) clientStarted = TRUE;
 | 
						||
	if (pRanges[i].clientDied)    clientDied    = TRUE;
 | 
						||
    }
 | 
						||
 | 
						||
    /*  We now have all the information collected to create all the sets,
 | 
						||
     * and we can compute the total memory required for the RCAP.
 | 
						||
     */
 | 
						||
 | 
						||
    totRCAPsize = sizeof(RecordClientsAndProtocolRec);
 | 
						||
 | 
						||
    /* leave a little room to grow before forcing a separate allocation */
 | 
						||
    sizeClients = nClients + CLIENT_ARRAY_GROWTH_INCREMENT;
 | 
						||
    pad = RecordPadAlign(totRCAPsize, sizeof(XID));
 | 
						||
    clientListOffset = totRCAPsize + pad;
 | 
						||
    totRCAPsize += pad + sizeClients * sizeof(XID);
 | 
						||
 | 
						||
    if (nExtReqSets)
 | 
						||
    {
 | 
						||
	pad = RecordPadAlign(totRCAPsize, sizeof(RecordSetPtr));
 | 
						||
	extReqSetsOffset = totRCAPsize + pad;
 | 
						||
	totRCAPsize += pad + (nExtReqSets + 1) * sizeof(RecordMinorOpRec);
 | 
						||
    }
 | 
						||
    if (nExtRepSets)
 | 
						||
    {
 | 
						||
	pad = RecordPadAlign(totRCAPsize, sizeof(RecordSetPtr));
 | 
						||
	extRepSetsOffset = totRCAPsize + pad;
 | 
						||
	totRCAPsize += pad + (nExtRepSets + 1) * sizeof(RecordMinorOpRec);
 | 
						||
    }
 | 
						||
 | 
						||
    for (i = 0; i < maxSets; i++)
 | 
						||
    {
 | 
						||
	if (si[i].nintervals)
 | 
						||
	{
 | 
						||
	    si[i].size = RecordSetMemoryRequirements(
 | 
						||
				si[i].intervals, si[i].nintervals, &si[i].align);
 | 
						||
	    pad = RecordPadAlign(totRCAPsize, si[i].align);
 | 
						||
	    si[i].offset = pad + totRCAPsize;
 | 
						||
	    totRCAPsize += pad + si[i].size;
 | 
						||
	}
 | 
						||
    }
 | 
						||
 | 
						||
    /* allocate memory for the whole RCAP */
 | 
						||
 | 
						||
    pRCAP = (RecordClientsAndProtocolPtr)xalloc(totRCAPsize);
 | 
						||
    if (!pRCAP) 
 | 
						||
    {
 | 
						||
	err = BadAlloc;
 | 
						||
	goto bailout;
 | 
						||
    }
 | 
						||
 | 
						||
    /* fill in the RCAP */
 | 
						||
 | 
						||
    pRCAP->pContext = pContext;
 | 
						||
    pRCAP->pClientIDs = (XID *)((char *)pRCAP + clientListOffset);
 | 
						||
    pRCAP->numClients  = nClients;
 | 
						||
    pRCAP->sizeClients = sizeClients;
 | 
						||
    pRCAP->clientIDsSeparatelyAllocated = 0;
 | 
						||
    for (i = 0; i < nClients; i++)
 | 
						||
    {
 | 
						||
	RecordDeleteClientFromContext(pContext, pCanonClients[i]);
 | 
						||
	pRCAP->pClientIDs[i] = pCanonClients[i];
 | 
						||
    }
 | 
						||
 | 
						||
    /* create all the sets */
 | 
						||
 | 
						||
    if (si[REQ].intervals)
 | 
						||
    {
 | 
						||
	pRCAP->pRequestMajorOpSet =
 | 
						||
	    RecordCreateSet(si[REQ].intervals, si[REQ].nintervals,
 | 
						||
		(RecordSetPtr)((char *)pRCAP + si[REQ].offset), si[REQ].size);
 | 
						||
    }
 | 
						||
    else pRCAP->pRequestMajorOpSet = NULL;
 | 
						||
 | 
						||
    if (si[REP].intervals)
 | 
						||
    {
 | 
						||
	pRCAP->pReplyMajorOpSet =
 | 
						||
	    RecordCreateSet(si[REP].intervals, si[REP].nintervals,
 | 
						||
		(RecordSetPtr)((char *)pRCAP + si[REP].offset), si[REP].size);
 | 
						||
    }
 | 
						||
    else pRCAP->pReplyMajorOpSet = NULL;
 | 
						||
 | 
						||
    if (si[ERR].intervals)
 | 
						||
    {
 | 
						||
	pRCAP->pErrorSet =
 | 
						||
	    RecordCreateSet(si[ERR].intervals, si[ERR].nintervals,
 | 
						||
		(RecordSetPtr)((char *)pRCAP + si[ERR].offset), si[ERR].size);
 | 
						||
    }
 | 
						||
    else pRCAP->pErrorSet = NULL;
 | 
						||
 | 
						||
    if (si[DEV].intervals)
 | 
						||
    {
 | 
						||
	pRCAP->pDeviceEventSet =
 | 
						||
	    RecordCreateSet(si[DEV].intervals, si[DEV].nintervals,
 | 
						||
		(RecordSetPtr)((char *)pRCAP + si[DEV].offset), si[DEV].size);
 | 
						||
    }
 | 
						||
    else pRCAP->pDeviceEventSet = NULL;
 | 
						||
 | 
						||
    if (si[DLEV].intervals)
 | 
						||
    {
 | 
						||
	pRCAP->pDeliveredEventSet =
 | 
						||
	    RecordCreateSet(si[DLEV].intervals, si[DLEV].nintervals,
 | 
						||
	      (RecordSetPtr)((char *)pRCAP + si[DLEV].offset), si[DLEV].size);
 | 
						||
    }
 | 
						||
    else pRCAP->pDeliveredEventSet = NULL;
 | 
						||
 | 
						||
    if (nExtReqSets)
 | 
						||
    {
 | 
						||
	pRCAP->pRequestMinOpInfo = (RecordMinorOpPtr)
 | 
						||
					((char *)pRCAP + extReqSetsOffset);
 | 
						||
	pRCAP->pRequestMinOpInfo[0].count = nExtReqSets;
 | 
						||
	for (i = 0; i < nExtReqSets; i++, pExtReqSets++)
 | 
						||
	{
 | 
						||
	    pRCAP->pRequestMinOpInfo[i+1].major.first = pExtReqSets->first;
 | 
						||
	    pRCAP->pRequestMinOpInfo[i+1].major.last  = pExtReqSets->last;
 | 
						||
	    pRCAP->pRequestMinOpInfo[i+1].major.pMinOpSet =
 | 
						||
		RecordCreateSet(pExtReqSets->intervals,
 | 
						||
				pExtReqSets->nintervals, 
 | 
						||
		  (RecordSetPtr)((char *)pRCAP + pExtReqSets->offset),
 | 
						||
				pExtReqSets->size);
 | 
						||
	}
 | 
						||
    }
 | 
						||
    else pRCAP->pRequestMinOpInfo = NULL;
 | 
						||
 | 
						||
    if (nExtRepSets)
 | 
						||
    {
 | 
						||
	pRCAP->pReplyMinOpInfo = (RecordMinorOpPtr)
 | 
						||
					((char *)pRCAP + extRepSetsOffset);
 | 
						||
	pRCAP->pReplyMinOpInfo[0].count = nExtRepSets;
 | 
						||
	for (i = 0; i < nExtRepSets; i++, pExtRepSets++)
 | 
						||
	{
 | 
						||
	    pRCAP->pReplyMinOpInfo[i+1].major.first = pExtRepSets->first;
 | 
						||
	    pRCAP->pReplyMinOpInfo[i+1].major.last  = pExtRepSets->last;
 | 
						||
	    pRCAP->pReplyMinOpInfo[i+1].major.pMinOpSet =
 | 
						||
		RecordCreateSet(pExtRepSets->intervals,
 | 
						||
				pExtRepSets->nintervals, 
 | 
						||
		  (RecordSetPtr)((char *)pRCAP + pExtRepSets->offset),
 | 
						||
				pExtRepSets->size);
 | 
						||
	}
 | 
						||
    }
 | 
						||
    else pRCAP->pReplyMinOpInfo = NULL;
 | 
						||
 | 
						||
    pRCAP->clientStarted = clientStarted;
 | 
						||
    pRCAP->clientDied    = clientDied;
 | 
						||
 | 
						||
    /* link the RCAP onto the context */
 | 
						||
 | 
						||
    pRCAP->pNextRCAP = pContext->pListOfRCAP;
 | 
						||
    pContext->pListOfRCAP = pRCAP;
 | 
						||
 | 
						||
    if (pContext->pRecordingClient) /* context enabled */
 | 
						||
	RecordInstallHooks(pRCAP, 0);
 | 
						||
 | 
						||
bailout:
 | 
						||
    if (si)
 | 
						||
    {
 | 
						||
	for (i = 0; i < maxSets; i++)
 | 
						||
	    if (si[i].intervals)
 | 
						||
		xfree(si[i].intervals);
 | 
						||
	DEALLOCATE_LOCAL(si);
 | 
						||
    }
 | 
						||
    if (pCanonClients && pCanonClients != (XID *)&stuff[1])
 | 
						||
	xfree(pCanonClients);
 | 
						||
    return err;
 | 
						||
} /* RecordRegisterClients */
 | 
						||
 | 
						||
 | 
						||
/* Proc functions all take a client argument, execute the request in
 | 
						||
 * client->requestBuffer, and return a protocol error status.
 | 
						||
 */
 | 
						||
 | 
						||
static int
 | 
						||
ProcRecordQueryVersion(ClientPtr client)
 | 
						||
{
 | 
						||
    /* REQUEST(xRecordQueryVersionReq); */
 | 
						||
    xRecordQueryVersionReply 	rep;
 | 
						||
    int 		n;
 | 
						||
 | 
						||
    REQUEST_SIZE_MATCH(xRecordQueryVersionReq);
 | 
						||
    rep.type        	= X_Reply;
 | 
						||
    rep.sequenceNumber 	= client->sequence;
 | 
						||
    rep.length         	= 0;
 | 
						||
    rep.majorVersion  	= RECORD_MAJOR_VERSION;
 | 
						||
    rep.minorVersion  	= RECORD_MINOR_VERSION;
 | 
						||
    if(client->swapped)
 | 
						||
    {
 | 
						||
    	swaps(&rep.sequenceNumber, n);
 | 
						||
	swaps(&rep.majorVersion, n);
 | 
						||
	swaps(&rep.minorVersion, n);
 | 
						||
    }
 | 
						||
    (void)WriteToClient(client, sizeof(xRecordQueryVersionReply),
 | 
						||
			(char *)&rep);
 | 
						||
    return (client->noClientException);
 | 
						||
} /* ProcRecordQueryVersion */
 | 
						||
 | 
						||
 | 
						||
static int
 | 
						||
ProcRecordCreateContext(ClientPtr client)
 | 
						||
{
 | 
						||
    REQUEST(xRecordCreateContextReq);
 | 
						||
    RecordContextPtr pContext;
 | 
						||
    RecordContextPtr *ppNewAllContexts = NULL;
 | 
						||
    int err = BadAlloc;
 | 
						||
 | 
						||
    REQUEST_AT_LEAST_SIZE(xRecordCreateContextReq);
 | 
						||
    LEGAL_NEW_RESOURCE(stuff->context, client);
 | 
						||
 | 
						||
    pContext = (RecordContextPtr)xalloc(sizeof(RecordContextRec));
 | 
						||
    if (!pContext)
 | 
						||
	goto bailout;
 | 
						||
 | 
						||
    /* make sure there is room in ppAllContexts to store the new context */
 | 
						||
 | 
						||
    ppNewAllContexts = (RecordContextPtr *)
 | 
						||
	xrealloc(ppAllContexts, sizeof(RecordContextPtr) * (numContexts + 1));
 | 
						||
    if (!ppNewAllContexts)
 | 
						||
	goto bailout;
 | 
						||
    ppAllContexts = ppNewAllContexts;
 | 
						||
 | 
						||
    pContext->id = stuff->context;
 | 
						||
    pContext->pRecordingClient = NULL;
 | 
						||
    pContext->pListOfRCAP = NULL;
 | 
						||
    pContext->elemHeaders = 0;
 | 
						||
    pContext->bufCategory = 0;
 | 
						||
    pContext->numBufBytes = 0;
 | 
						||
    pContext->pBufClient = NULL;
 | 
						||
    pContext->continuedReply = 0;
 | 
						||
 | 
						||
    err = RecordRegisterClients(pContext, client,
 | 
						||
				(xRecordRegisterClientsReq *)stuff);
 | 
						||
    if (err != Success)
 | 
						||
	goto bailout;
 | 
						||
 | 
						||
    if (AddResource(pContext->id, RTContext, pContext))
 | 
						||
    {
 | 
						||
	ppAllContexts[numContexts++] = pContext;
 | 
						||
	return Success;
 | 
						||
    }
 | 
						||
    else
 | 
						||
    {
 | 
						||
	RecordDeleteContext((pointer)pContext, pContext->id);
 | 
						||
	err = BadAlloc;
 | 
						||
    }
 | 
						||
bailout:
 | 
						||
    if (pContext)
 | 
						||
	xfree(pContext);
 | 
						||
    return err;
 | 
						||
} /* ProcRecordCreateContext */
 | 
						||
 | 
						||
 | 
						||
static int
 | 
						||
ProcRecordRegisterClients(ClientPtr client)
 | 
						||
{
 | 
						||
    RecordContextPtr pContext;
 | 
						||
    REQUEST(xRecordRegisterClientsReq);
 | 
						||
 | 
						||
    REQUEST_AT_LEAST_SIZE(xRecordRegisterClientsReq);
 | 
						||
    VERIFY_CONTEXT(pContext, stuff->context, client);
 | 
						||
 | 
						||
    return RecordRegisterClients(pContext, client, stuff);
 | 
						||
} /* ProcRecordRegisterClients */
 | 
						||
 | 
						||
 | 
						||
static int
 | 
						||
ProcRecordUnregisterClients(ClientPtr client)
 | 
						||
{
 | 
						||
    RecordContextPtr pContext;
 | 
						||
    int err;
 | 
						||
    REQUEST(xRecordUnregisterClientsReq);
 | 
						||
    XID *pCanonClients;
 | 
						||
    int nClients;
 | 
						||
    int i;
 | 
						||
 | 
						||
    REQUEST_AT_LEAST_SIZE(xRecordUnregisterClientsReq);
 | 
						||
    if ((client->req_len << 2) - SIZEOF(xRecordUnregisterClientsReq) !=
 | 
						||
	4 * stuff->nClients)
 | 
						||
	return BadLength;
 | 
						||
    VERIFY_CONTEXT(pContext, stuff->context, client);
 | 
						||
    err = RecordSanityCheckClientSpecifiers((XID *)&stuff[1],
 | 
						||
					    stuff->nClients, 0);
 | 
						||
    if (err != Success)
 | 
						||
	return err;
 | 
						||
 | 
						||
    nClients = stuff->nClients;
 | 
						||
    pCanonClients = RecordCanonicalizeClientSpecifiers((XID *)&stuff[1],
 | 
						||
						 &nClients, 0);
 | 
						||
    if (!pCanonClients)
 | 
						||
	return BadAlloc;
 | 
						||
 | 
						||
    for (i = 0; i < nClients; i++)
 | 
						||
    {
 | 
						||
	RecordDeleteClientFromContext(pContext, pCanonClients[i]);
 | 
						||
    }
 | 
						||
    if (pCanonClients != (XID *)&stuff[1])
 | 
						||
	xfree(pCanonClients);
 | 
						||
    return Success;
 | 
						||
} /* ProcRecordUnregisterClients */
 | 
						||
 | 
						||
 | 
						||
/****************************************************************************/
 | 
						||
 | 
						||
/* stuff for GetContext */
 | 
						||
 | 
						||
/* This is a tactical structure used to hold the xRecordRanges as they are
 | 
						||
 * being reconstituted from the sets in the RCAPs.
 | 
						||
 */
 | 
						||
 | 
						||
typedef struct {
 | 
						||
    xRecordRange *pRanges;  /* array of xRecordRanges for one RCAP */
 | 
						||
    int size;		/* number of elements in pRanges, >= nRanges */
 | 
						||
    int nRanges;	/* number of occupied element of pRanges */
 | 
						||
} GetContextRangeInfoRec, *GetContextRangeInfoPtr;
 | 
						||
 | 
						||
 | 
						||
/* RecordAllocRanges
 | 
						||
 *
 | 
						||
 * Arguments:
 | 
						||
 *	pri is a pointer to a GetContextRangeInfoRec to allocate for.
 | 
						||
 *	nRanges is the number of xRecordRanges desired for pri.
 | 
						||
 *
 | 
						||
 * Returns: BadAlloc if a memory allocation error occurred, else Success.
 | 
						||
 *
 | 
						||
 * Side Effects:
 | 
						||
 *	If Success is returned, pri->pRanges points to at least nRanges
 | 
						||
 *	ranges.  pri->nRanges is set to nRanges.  pri->size is the actual
 | 
						||
 *	number of ranges.  Newly allocated ranges are zeroed.
 | 
						||
 */
 | 
						||
static int
 | 
						||
RecordAllocRanges(GetContextRangeInfoPtr pri, int nRanges)
 | 
						||
{
 | 
						||
    int newsize;
 | 
						||
    xRecordRange *pNewRange;
 | 
						||
#define SZINCR 8
 | 
						||
 | 
						||
    newsize = max(pri->size + SZINCR, nRanges);
 | 
						||
    pNewRange = (xRecordRange *)xrealloc(pri->pRanges,
 | 
						||
			 newsize * sizeof(xRecordRange));
 | 
						||
    if (!pNewRange)
 | 
						||
	return BadAlloc;
 | 
						||
 | 
						||
    pri->pRanges = pNewRange;
 | 
						||
    pri->size = newsize;
 | 
						||
    bzero(&pri->pRanges[pri->size - SZINCR], SZINCR * sizeof(xRecordRange));
 | 
						||
    if (pri->nRanges < nRanges)
 | 
						||
	pri->nRanges = nRanges;
 | 
						||
    return Success;
 | 
						||
} /* RecordAllocRanges */
 | 
						||
 | 
						||
 | 
						||
/* RecordConvertSetToRanges
 | 
						||
 *
 | 
						||
 * Arguments:
 | 
						||
 *	pSet is the set to be converted.
 | 
						||
 *	pri is where the result should be stored.
 | 
						||
 *	byteoffset is the offset from the start of an xRecordRange of the
 | 
						||
 *	  two vales (first, last) we are interested in.
 | 
						||
 *	card8 is TRUE if the vales are one byte each and FALSE if two bytes
 | 
						||
 *	  each.
 | 
						||
 *	imax is the largest set value to store in pri->pRanges.
 | 
						||
 *	pStartIndex, if non-NULL, is the index of the first range in
 | 
						||
 *	  pri->pRanges that should be stored to.  If NULL,
 | 
						||
 *	  start at index 0.
 | 
						||
 *
 | 
						||
 * Returns: BadAlloc if a memory allocation error occurred, else Success.
 | 
						||
 *
 | 
						||
 * Side Effects:
 | 
						||
 *	If Success is returned, the slice of pri->pRanges indicated by
 | 
						||
 *	byteoffset and card8 is filled in with the intervals from pSet.
 | 
						||
 *	if pStartIndex was non-NULL, *pStartIndex is filled in with one
 | 
						||
 *	more than the index of the last xRecordRange that was touched.
 | 
						||
 */
 | 
						||
static int
 | 
						||
RecordConvertSetToRanges(
 | 
						||
    RecordSetPtr pSet,
 | 
						||
    GetContextRangeInfoPtr pri,
 | 
						||
    int byteoffset,
 | 
						||
    Bool card8,
 | 
						||
    unsigned int imax,
 | 
						||
    int *pStartIndex
 | 
						||
)
 | 
						||
{
 | 
						||
    int nRanges;
 | 
						||
    RecordSetIteratePtr pIter = NULL;
 | 
						||
    RecordSetInterval interval;
 | 
						||
    CARD8 *pCARD8;
 | 
						||
    CARD16 *pCARD16;
 | 
						||
    int err;
 | 
						||
 | 
						||
    if (!pSet)
 | 
						||
	return Success;
 | 
						||
 | 
						||
    nRanges = pStartIndex ? *pStartIndex : 0;
 | 
						||
    while ((pIter = RecordIterateSet(pSet, pIter, &interval)))
 | 
						||
    {
 | 
						||
	if (interval.first > imax) break;
 | 
						||
	if (interval.last  > imax) interval.last = imax;
 | 
						||
	nRanges++;
 | 
						||
	if (nRanges > pri->size)
 | 
						||
	{
 | 
						||
	    err = RecordAllocRanges(pri, nRanges);
 | 
						||
	    if (err != Success)
 | 
						||
		return err;
 | 
						||
	}
 | 
						||
	else
 | 
						||
	    pri->nRanges = max(pri->nRanges, nRanges);
 | 
						||
	if (card8)
 | 
						||
	{
 | 
						||
	    pCARD8 = ((CARD8 *)&pri->pRanges[nRanges-1]) + byteoffset;
 | 
						||
	    *pCARD8++ = interval.first;
 | 
						||
	    *pCARD8   = interval.last;
 | 
						||
	}
 | 
						||
	else
 | 
						||
	{
 | 
						||
	    pCARD16 = (CARD16 *)
 | 
						||
			(((char *)&pri->pRanges[nRanges-1]) + byteoffset);
 | 
						||
	    *pCARD16++ = interval.first;
 | 
						||
	    *pCARD16   = interval.last;
 | 
						||
	}
 | 
						||
    }
 | 
						||
    if (pStartIndex)
 | 
						||
	*pStartIndex = nRanges;
 | 
						||
    return Success;
 | 
						||
} /* RecordConvertSetToRanges */
 | 
						||
 | 
						||
 | 
						||
/* RecordConvertMinorOpInfoToRanges
 | 
						||
 *
 | 
						||
 * Arguments:
 | 
						||
 *	pMinOpInfo is the minor opcode info to convert to xRecordRanges.
 | 
						||
 *	pri is where the result should be stored.
 | 
						||
 *	byteoffset is the offset from the start of an xRecordRange of the
 | 
						||
 *	  four vales (CARD8 major_first, CARD8 major_last,
 | 
						||
 *	  CARD16 minor_first, CARD16 minor_last) we are going to store.
 | 
						||
 *
 | 
						||
 * Returns: BadAlloc if a memory allocation error occurred, else Success.
 | 
						||
 *
 | 
						||
 * Side Effects:
 | 
						||
 *	If Success is returned, the slice of pri->pRanges indicated by
 | 
						||
 *	byteoffset is filled in with the information from pMinOpInfo.
 | 
						||
 */
 | 
						||
static int
 | 
						||
RecordConvertMinorOpInfoToRanges(
 | 
						||
    RecordMinorOpPtr pMinOpInfo,
 | 
						||
    GetContextRangeInfoPtr pri,
 | 
						||
    int byteoffset
 | 
						||
)
 | 
						||
{
 | 
						||
    int nsets;
 | 
						||
    int start;
 | 
						||
    int i;
 | 
						||
    int err;
 | 
						||
 | 
						||
    if (!pMinOpInfo)
 | 
						||
	return Success;
 | 
						||
 | 
						||
    nsets = pMinOpInfo->count;
 | 
						||
    pMinOpInfo++;
 | 
						||
    start = 0;
 | 
						||
    for (i = 0; i < nsets; i++)
 | 
						||
    {
 | 
						||
	int j, s;
 | 
						||
	s = start;
 | 
						||
	err = RecordConvertSetToRanges(pMinOpInfo[i].major.pMinOpSet, pri,
 | 
						||
				byteoffset + 2, FALSE, 65535, &start);
 | 
						||
	if (err != Success) return err;
 | 
						||
	for (j = s; j < start; j++)
 | 
						||
	{
 | 
						||
	    CARD8 *pCARD8 = ((CARD8 *)&pri->pRanges[j]) + byteoffset;
 | 
						||
	    *pCARD8++ = pMinOpInfo[i].major.first;
 | 
						||
	    *pCARD8   = pMinOpInfo[i].major.last;
 | 
						||
	}
 | 
						||
    }
 | 
						||
    return Success;
 | 
						||
} /* RecordConvertMinorOpInfoToRanges */
 | 
						||
 | 
						||
 | 
						||
/* RecordSwapRanges
 | 
						||
 *
 | 
						||
 * Arguments:
 | 
						||
 *	pRanges is an array of xRecordRanges.
 | 
						||
 *	nRanges is the number of elements in pRanges.
 | 
						||
 *
 | 
						||
 * Returns: nothing.
 | 
						||
 *
 | 
						||
 * Side Effects:
 | 
						||
 *	The 16 bit fields of each xRecordRange are byte swapped.
 | 
						||
 */
 | 
						||
static void
 | 
						||
RecordSwapRanges(xRecordRange *pRanges, int nRanges)
 | 
						||
{
 | 
						||
    int i;
 | 
						||
    register char n;
 | 
						||
    for (i = 0; i < nRanges; i++, pRanges++)
 | 
						||
    {
 | 
						||
	swaps(&pRanges->extRequestsMinorFirst, n);
 | 
						||
	swaps(&pRanges->extRequestsMinorLast, n);
 | 
						||
	swaps(&pRanges->extRepliesMinorFirst, n);
 | 
						||
	swaps(&pRanges->extRepliesMinorLast, n);
 | 
						||
    }
 | 
						||
} /* RecordSwapRanges */
 | 
						||
 | 
						||
 | 
						||
static int
 | 
						||
ProcRecordGetContext(ClientPtr client)
 | 
						||
{
 | 
						||
    RecordContextPtr pContext;
 | 
						||
    REQUEST(xRecordGetContextReq);
 | 
						||
    xRecordGetContextReply rep;
 | 
						||
    int n;
 | 
						||
    RecordClientsAndProtocolPtr pRCAP;
 | 
						||
    int nRCAPs = 0;
 | 
						||
    GetContextRangeInfoPtr pRangeInfo;
 | 
						||
    GetContextRangeInfoPtr pri;
 | 
						||
    int i;
 | 
						||
    int err;
 | 
						||
 | 
						||
    REQUEST_SIZE_MATCH(xRecordGetContextReq);
 | 
						||
    VERIFY_CONTEXT(pContext, stuff->context, client);
 | 
						||
 | 
						||
    /* how many RCAPs are there on this context? */
 | 
						||
 | 
						||
    for (pRCAP = pContext->pListOfRCAP; pRCAP; pRCAP = pRCAP->pNextRCAP)
 | 
						||
	nRCAPs++;
 | 
						||
 | 
						||
    /* allocate and initialize space for record range info */
 | 
						||
 | 
						||
    pRangeInfo = (GetContextRangeInfoPtr)ALLOCATE_LOCAL(
 | 
						||
				nRCAPs * sizeof(GetContextRangeInfoRec));
 | 
						||
    if (!pRangeInfo && nRCAPs > 0)
 | 
						||
	return BadAlloc;
 | 
						||
    for (i = 0; i < nRCAPs; i++)
 | 
						||
    {
 | 
						||
	pRangeInfo[i].pRanges = NULL;
 | 
						||
	pRangeInfo[i].size = 0;
 | 
						||
	pRangeInfo[i].nRanges = 0;
 | 
						||
    }
 | 
						||
 | 
						||
    /* convert the RCAP (internal) representation of the recorded protocol
 | 
						||
     * to the wire protocol (external) representation, storing the information
 | 
						||
     * for the ith RCAP in pri[i]
 | 
						||
     */
 | 
						||
 | 
						||
    for (pRCAP = pContext->pListOfRCAP, pri = pRangeInfo;
 | 
						||
	 pRCAP;
 | 
						||
	 pRCAP = pRCAP->pNextRCAP, pri++)
 | 
						||
    {
 | 
						||
	xRecordRange rr;
 | 
						||
 | 
						||
	err = RecordConvertSetToRanges(pRCAP->pRequestMajorOpSet, pri,
 | 
						||
			offset_of(rr, coreRequestsFirst), TRUE, 127, NULL);
 | 
						||
	if (err != Success) goto bailout;
 | 
						||
 | 
						||
	err = RecordConvertSetToRanges(pRCAP->pReplyMajorOpSet, pri,
 | 
						||
			offset_of(rr, coreRepliesFirst), TRUE, 127, NULL);
 | 
						||
	if (err != Success) goto bailout;
 | 
						||
 | 
						||
	err = RecordConvertSetToRanges(pRCAP->pDeliveredEventSet, pri,
 | 
						||
			offset_of(rr, deliveredEventsFirst), TRUE, 255, NULL);
 | 
						||
	if (err != Success) goto bailout;
 | 
						||
 | 
						||
	err = RecordConvertSetToRanges(pRCAP->pDeviceEventSet, pri,
 | 
						||
			offset_of(rr, deviceEventsFirst), TRUE, 255, NULL);
 | 
						||
	if (err != Success) goto bailout;
 | 
						||
 | 
						||
	err = RecordConvertSetToRanges(pRCAP->pErrorSet, pri,
 | 
						||
			      offset_of(rr, errorsFirst), TRUE, 255, NULL);
 | 
						||
	if (err != Success) goto bailout;
 | 
						||
 | 
						||
	err = RecordConvertMinorOpInfoToRanges(pRCAP->pRequestMinOpInfo,
 | 
						||
				pri, offset_of(rr, extRequestsMajorFirst));
 | 
						||
	if (err != Success) goto bailout;
 | 
						||
 | 
						||
	err = RecordConvertMinorOpInfoToRanges(pRCAP->pReplyMinOpInfo,
 | 
						||
				pri, offset_of(rr, extRepliesMajorFirst));
 | 
						||
	if (err != Success) goto bailout;
 | 
						||
 | 
						||
	if (pRCAP->clientStarted || pRCAP->clientDied)
 | 
						||
	{
 | 
						||
	    if (pri->nRanges == 0)
 | 
						||
		RecordAllocRanges(pri, 1);
 | 
						||
	    pri->pRanges[0].clientStarted = pRCAP->clientStarted;
 | 
						||
	    pri->pRanges[0].clientDied    = pRCAP->clientDied;
 | 
						||
	}
 | 
						||
    }
 | 
						||
 | 
						||
    /* calculate number of clients and reply length */
 | 
						||
 | 
						||
    rep.nClients = 0;
 | 
						||
    rep.length = 0;
 | 
						||
    for (pRCAP = pContext->pListOfRCAP, pri = pRangeInfo;
 | 
						||
	 pRCAP;
 | 
						||
	 pRCAP = pRCAP->pNextRCAP, pri++)
 | 
						||
    {
 | 
						||
	rep.nClients += pRCAP->numClients;
 | 
						||
	rep.length += pRCAP->numClients *
 | 
						||
		( (sizeof(xRecordClientInfo) >> 2) +
 | 
						||
		  pri->nRanges * (sizeof(xRecordRange) >> 2));
 | 
						||
    }
 | 
						||
 | 
						||
    /* write the reply header */
 | 
						||
 | 
						||
    rep.type = X_Reply;
 | 
						||
    rep.sequenceNumber 	= client->sequence;
 | 
						||
    rep.enabled = pContext->pRecordingClient != NULL;
 | 
						||
    rep.elementHeader = pContext->elemHeaders;
 | 
						||
    if(client->swapped)
 | 
						||
    {
 | 
						||
    	swaps(&rep.sequenceNumber, n);
 | 
						||
    	swapl(&rep.length, n);
 | 
						||
    	swapl(&rep.nClients, n);
 | 
						||
    }
 | 
						||
    (void)WriteToClient(client, sizeof(xRecordGetContextReply),
 | 
						||
			(char *)&rep);
 | 
						||
 | 
						||
    /* write all the CLIENT_INFOs */
 | 
						||
 | 
						||
    for (pRCAP = pContext->pListOfRCAP, pri = pRangeInfo;
 | 
						||
	 pRCAP;
 | 
						||
	 pRCAP = pRCAP->pNextRCAP, pri++)
 | 
						||
    {
 | 
						||
	xRecordClientInfo rci;
 | 
						||
	rci.nRanges = pri->nRanges;
 | 
						||
	if (client->swapped)
 | 
						||
	{
 | 
						||
	    swapl(&rci.nRanges, n);
 | 
						||
	    RecordSwapRanges(pri->pRanges, pri->nRanges);
 | 
						||
	}
 | 
						||
	for (i = 0; i < pRCAP->numClients; i++)
 | 
						||
	{
 | 
						||
	    rci.clientResource = pRCAP->pClientIDs[i];
 | 
						||
	    if (client->swapped) swapl(&rci.clientResource, n);
 | 
						||
	    WriteToClient(client, sizeof(xRecordClientInfo), (char *)&rci);
 | 
						||
	    WriteToClient(client, sizeof(xRecordRange) * pri->nRanges,
 | 
						||
			  (char *)pri->pRanges);
 | 
						||
	}
 | 
						||
    }
 | 
						||
    err = client->noClientException;
 | 
						||
 | 
						||
bailout:
 | 
						||
    for (i = 0; i < nRCAPs; i++)
 | 
						||
    {
 | 
						||
	if (pRangeInfo[i].pRanges) xfree(pRangeInfo[i].pRanges);
 | 
						||
    }
 | 
						||
    DEALLOCATE_LOCAL(pRangeInfo);
 | 
						||
    return err;
 | 
						||
} /* ProcRecordGetContext */
 | 
						||
 | 
						||
 | 
						||
static int
 | 
						||
ProcRecordEnableContext(ClientPtr client)
 | 
						||
{
 | 
						||
    RecordContextPtr pContext;
 | 
						||
    REQUEST(xRecordEnableContextReq);
 | 
						||
    int i;
 | 
						||
    RecordClientsAndProtocolPtr pRCAP;
 | 
						||
 | 
						||
    REQUEST_SIZE_MATCH(xRecordGetContextReq);
 | 
						||
    VERIFY_CONTEXT(pContext, stuff->context, client);
 | 
						||
    if (pContext->pRecordingClient)
 | 
						||
	return BadMatch; /* already enabled */
 | 
						||
 | 
						||
    /* install record hooks for each RCAP */
 | 
						||
 | 
						||
    for (pRCAP = pContext->pListOfRCAP; pRCAP; pRCAP = pRCAP->pNextRCAP)
 | 
						||
    {
 | 
						||
	int err = RecordInstallHooks(pRCAP, 0);
 | 
						||
	if (err != Success)
 | 
						||
	{ /* undo the previous installs */
 | 
						||
	    RecordClientsAndProtocolPtr pUninstallRCAP;
 | 
						||
	    for (pUninstallRCAP = pContext->pListOfRCAP;
 | 
						||
		 pUninstallRCAP != pRCAP;
 | 
						||
		 pUninstallRCAP = pUninstallRCAP->pNextRCAP)
 | 
						||
	    {
 | 
						||
		RecordUninstallHooks(pUninstallRCAP, 0);
 | 
						||
	    }
 | 
						||
	    return err;
 | 
						||
	}
 | 
						||
    }
 | 
						||
 | 
						||
    /* Disallow further request processing on this connection until
 | 
						||
     * the context is disabled.
 | 
						||
     */
 | 
						||
    IgnoreClient(client);
 | 
						||
    pContext->pRecordingClient = client;
 | 
						||
 | 
						||
    /* Don't allow the data connection to record itself; unregister it. */
 | 
						||
    RecordDeleteClientFromContext(pContext,
 | 
						||
				  pContext->pRecordingClient->clientAsMask);
 | 
						||
 | 
						||
    /* move the newly enabled context to the front part of ppAllContexts,
 | 
						||
     * where all the enabled contexts are
 | 
						||
     */
 | 
						||
    i = RecordFindContextOnAllContexts(pContext);
 | 
						||
    assert(i >= numEnabledContexts);
 | 
						||
    if (i != numEnabledContexts)
 | 
						||
    {
 | 
						||
	ppAllContexts[i] = ppAllContexts[numEnabledContexts];
 | 
						||
	ppAllContexts[numEnabledContexts] = pContext;
 | 
						||
    }
 | 
						||
 | 
						||
    ++numEnabledContexts;
 | 
						||
    assert(numEnabledContexts > 0);
 | 
						||
 | 
						||
    /* send StartOfData */
 | 
						||
    RecordAProtocolElement(pContext, NULL, XRecordStartOfData, NULL, 0, 0);
 | 
						||
    RecordFlushReplyBuffer(pContext, NULL, 0, NULL, 0);
 | 
						||
    return Success;
 | 
						||
} /* ProcRecordEnableContext */
 | 
						||
 | 
						||
 | 
						||
/* RecordDisableContext
 | 
						||
 *
 | 
						||
 * Arguments:
 | 
						||
 *	pContext is the context to disable.
 | 
						||
 *	nRanges is the number of elements in pRanges.
 | 
						||
 *
 | 
						||
 * Returns: nothing.
 | 
						||
 *
 | 
						||
 * Side Effects:
 | 
						||
 *	If the context was enabled, it is disabled.  An EndOfData
 | 
						||
 *	message is sent to the recording client.  Recording hooks for
 | 
						||
 *	this context are uninstalled.  The context is moved to the
 | 
						||
 *	rear part of the ppAllContexts array.  numEnabledContexts is
 | 
						||
 *	decremented.  Request processing for the formerly recording client
 | 
						||
 *	is resumed.
 | 
						||
 */
 | 
						||
static void
 | 
						||
RecordDisableContext(RecordContextPtr pContext)
 | 
						||
{
 | 
						||
    RecordClientsAndProtocolPtr pRCAP;
 | 
						||
    int i;
 | 
						||
 | 
						||
    if (!pContext->pRecordingClient) return;
 | 
						||
    if (!pContext->pRecordingClient->clientGone)
 | 
						||
    {
 | 
						||
	RecordAProtocolElement(pContext, NULL, XRecordEndOfData, NULL, 0, 0);
 | 
						||
	RecordFlushReplyBuffer(pContext, NULL, 0, NULL, 0);
 | 
						||
	/* Re-enable request processing on this connection. */
 | 
						||
	AttendClient(pContext->pRecordingClient);
 | 
						||
    }
 | 
						||
 | 
						||
    for (pRCAP = pContext->pListOfRCAP; pRCAP; pRCAP = pRCAP->pNextRCAP)
 | 
						||
    {
 | 
						||
	RecordUninstallHooks(pRCAP, 0);
 | 
						||
    }
 | 
						||
 | 
						||
    pContext->pRecordingClient = NULL;
 | 
						||
 | 
						||
    /* move the newly disabled context to the rear part of ppAllContexts,
 | 
						||
     * where all the disabled contexts are
 | 
						||
     */
 | 
						||
    i = RecordFindContextOnAllContexts(pContext);
 | 
						||
    assert( (i != -1) && (i < numEnabledContexts) );
 | 
						||
    if (i != (numEnabledContexts - 1) )
 | 
						||
    {
 | 
						||
	ppAllContexts[i] = ppAllContexts[numEnabledContexts-1];
 | 
						||
	ppAllContexts[numEnabledContexts-1] = pContext;
 | 
						||
    }
 | 
						||
    --numEnabledContexts;
 | 
						||
    assert(numEnabledContexts >= 0);
 | 
						||
} /* RecordDisableContext */
 | 
						||
 | 
						||
 | 
						||
static int
 | 
						||
ProcRecordDisableContext(ClientPtr client)
 | 
						||
{
 | 
						||
    RecordContextPtr pContext;
 | 
						||
    REQUEST(xRecordDisableContextReq);
 | 
						||
 | 
						||
    REQUEST_SIZE_MATCH(xRecordDisableContextReq);
 | 
						||
    VERIFY_CONTEXT(pContext, stuff->context, client);
 | 
						||
    RecordDisableContext(pContext);
 | 
						||
    return Success;
 | 
						||
} /* ProcRecordDisableContext */
 | 
						||
 | 
						||
 | 
						||
/* RecordDeleteContext
 | 
						||
 *
 | 
						||
 * Arguments:
 | 
						||
 *	value is the context to delete.
 | 
						||
 *	id is its resource ID.
 | 
						||
 *
 | 
						||
 * Returns: Success.
 | 
						||
 *
 | 
						||
 * Side Effects:
 | 
						||
 *	Disables the context, frees all associated memory, and removes
 | 
						||
 *	it from the ppAllContexts array.
 | 
						||
 */
 | 
						||
static int
 | 
						||
RecordDeleteContext(pointer value, XID id)
 | 
						||
{
 | 
						||
    int i;
 | 
						||
    RecordContextPtr pContext = (RecordContextPtr)value;
 | 
						||
    RecordClientsAndProtocolPtr pRCAP;
 | 
						||
 | 
						||
    RecordDisableContext(pContext);
 | 
						||
 | 
						||
    /*  Remove all the clients from all the RCAPs.
 | 
						||
     *  As a result, the RCAPs will be freed.
 | 
						||
     */
 | 
						||
 | 
						||
    while ((pRCAP = pContext->pListOfRCAP))
 | 
						||
    {
 | 
						||
	int numClients = pRCAP->numClients;
 | 
						||
	/* when the last client is deleted, the RCAP will go away. */
 | 
						||
	while(numClients--)
 | 
						||
	{
 | 
						||
	    RecordDeleteClientFromRCAP(pRCAP, numClients);
 | 
						||
	}
 | 
						||
    }
 | 
						||
 | 
						||
    xfree(pContext);
 | 
						||
 | 
						||
    /* remove context from AllContexts list */
 | 
						||
 | 
						||
    if (-1 != (i = RecordFindContextOnAllContexts(pContext)))
 | 
						||
    {
 | 
						||
	ppAllContexts[i] = ppAllContexts[numContexts - 1];
 | 
						||
	if (--numContexts == 0)
 | 
						||
	{
 | 
						||
	    xfree(ppAllContexts);
 | 
						||
	    ppAllContexts = NULL;
 | 
						||
	}
 | 
						||
    }
 | 
						||
    return Success;
 | 
						||
} /* RecordDeleteContext */
 | 
						||
 | 
						||
 | 
						||
static int
 | 
						||
ProcRecordFreeContext(ClientPtr client)
 | 
						||
{
 | 
						||
    RecordContextPtr pContext;
 | 
						||
    REQUEST(xRecordFreeContextReq);
 | 
						||
 | 
						||
    REQUEST_SIZE_MATCH(xRecordFreeContextReq);
 | 
						||
    VERIFY_CONTEXT(pContext, stuff->context, client);
 | 
						||
    FreeResource(stuff->context, RT_NONE);
 | 
						||
    return Success;
 | 
						||
} /* ProcRecordFreeContext */
 | 
						||
 | 
						||
 | 
						||
static int
 | 
						||
ProcRecordDispatch(ClientPtr client)
 | 
						||
{
 | 
						||
    REQUEST(xReq);
 | 
						||
 | 
						||
    switch (stuff->data)
 | 
						||
    {
 | 
						||
	case X_RecordQueryVersion:
 | 
						||
	    return ProcRecordQueryVersion(client);
 | 
						||
	case X_RecordCreateContext:
 | 
						||
	    return ProcRecordCreateContext(client);
 | 
						||
	case X_RecordRegisterClients:
 | 
						||
	    return ProcRecordRegisterClients(client);
 | 
						||
	case X_RecordUnregisterClients:
 | 
						||
	    return ProcRecordUnregisterClients(client);
 | 
						||
	case X_RecordGetContext:
 | 
						||
	    return ProcRecordGetContext(client);
 | 
						||
	case X_RecordEnableContext:
 | 
						||
	    return ProcRecordEnableContext(client);
 | 
						||
	case X_RecordDisableContext:
 | 
						||
	    return ProcRecordDisableContext(client);
 | 
						||
	case X_RecordFreeContext:
 | 
						||
	    return ProcRecordFreeContext(client);
 | 
						||
       default:
 | 
						||
	    return BadRequest;
 | 
						||
    }
 | 
						||
} /* ProcRecordDispatch */
 | 
						||
 | 
						||
 | 
						||
static int
 | 
						||
SProcRecordQueryVersion(ClientPtr client)
 | 
						||
{
 | 
						||
    REQUEST(xRecordQueryVersionReq);
 | 
						||
    register char 	n;
 | 
						||
 | 
						||
    swaps(&stuff->length, n);
 | 
						||
    REQUEST_SIZE_MATCH(xRecordQueryVersionReq);
 | 
						||
    swaps(&stuff->majorVersion, n);
 | 
						||
    swaps(&stuff->minorVersion,n);
 | 
						||
    return ProcRecordQueryVersion(client);
 | 
						||
} /* SProcRecordQueryVersion */
 | 
						||
 | 
						||
 | 
						||
static void
 | 
						||
SwapCreateRegister(xRecordRegisterClientsReq *stuff)
 | 
						||
{
 | 
						||
    register char n;
 | 
						||
    int i;
 | 
						||
    XID *pClientID;
 | 
						||
 | 
						||
    swapl(&stuff->context, n);
 | 
						||
    swapl(&stuff->nClients, n);
 | 
						||
    swapl(&stuff->nRanges, n);
 | 
						||
    pClientID = (XID *)&stuff[1];
 | 
						||
    for (i = 0; i < stuff->nClients; i++, pClientID++)
 | 
						||
    {
 | 
						||
	swapl(pClientID, n);
 | 
						||
    }
 | 
						||
    RecordSwapRanges((xRecordRange *)pClientID, stuff->nRanges);
 | 
						||
} /* SwapCreateRegister */
 | 
						||
 | 
						||
 | 
						||
static int
 | 
						||
SProcRecordCreateContext(ClientPtr client)
 | 
						||
{
 | 
						||
    REQUEST(xRecordCreateContextReq);
 | 
						||
    register char 	n;
 | 
						||
 | 
						||
    swaps(&stuff->length, n);
 | 
						||
    REQUEST_AT_LEAST_SIZE(xRecordCreateContextReq);
 | 
						||
    SwapCreateRegister((pointer)stuff);
 | 
						||
    return ProcRecordCreateContext(client);
 | 
						||
} /* SProcRecordCreateContext */
 | 
						||
 | 
						||
 | 
						||
static int
 | 
						||
SProcRecordRegisterClients(ClientPtr client)
 | 
						||
{
 | 
						||
    REQUEST(xRecordRegisterClientsReq);
 | 
						||
    register char 	n;
 | 
						||
 | 
						||
    swaps(&stuff->length, n);
 | 
						||
    REQUEST_AT_LEAST_SIZE(xRecordRegisterClientsReq);
 | 
						||
    SwapCreateRegister((pointer)stuff);
 | 
						||
    return ProcRecordRegisterClients(client);
 | 
						||
} /* SProcRecordRegisterClients */
 | 
						||
 | 
						||
 | 
						||
static int
 | 
						||
SProcRecordUnregisterClients(ClientPtr client)
 | 
						||
{
 | 
						||
    REQUEST(xRecordUnregisterClientsReq);
 | 
						||
    register char 	n;
 | 
						||
 | 
						||
    swaps(&stuff->length, n);
 | 
						||
    REQUEST_AT_LEAST_SIZE(xRecordUnregisterClientsReq);
 | 
						||
    swapl(&stuff->context, n);
 | 
						||
    swapl(&stuff->nClients, n);
 | 
						||
    SwapRestL(stuff);
 | 
						||
    return ProcRecordUnregisterClients(client);
 | 
						||
} /* SProcRecordUnregisterClients */
 | 
						||
 | 
						||
 | 
						||
static int
 | 
						||
SProcRecordGetContext(ClientPtr client)
 | 
						||
{
 | 
						||
    REQUEST(xRecordGetContextReq);
 | 
						||
    register char 	n;
 | 
						||
 | 
						||
    swaps(&stuff->length, n);
 | 
						||
    REQUEST_SIZE_MATCH(xRecordGetContextReq);
 | 
						||
    swapl(&stuff->context, n);
 | 
						||
    return ProcRecordGetContext(client);
 | 
						||
} /* SProcRecordGetContext */
 | 
						||
 | 
						||
static int
 | 
						||
SProcRecordEnableContext(ClientPtr client)
 | 
						||
{
 | 
						||
    REQUEST(xRecordEnableContextReq);
 | 
						||
    register char 	n;
 | 
						||
 | 
						||
    swaps(&stuff->length, n);
 | 
						||
    REQUEST_SIZE_MATCH(xRecordEnableContextReq);
 | 
						||
    swapl(&stuff->context, n);
 | 
						||
    return ProcRecordEnableContext(client);
 | 
						||
} /* SProcRecordEnableContext */
 | 
						||
 | 
						||
 | 
						||
static int
 | 
						||
SProcRecordDisableContext(ClientPtr client)
 | 
						||
{
 | 
						||
    REQUEST(xRecordDisableContextReq);
 | 
						||
    register char 	n;
 | 
						||
 | 
						||
    swaps(&stuff->length, n);
 | 
						||
    REQUEST_SIZE_MATCH(xRecordDisableContextReq);
 | 
						||
    swapl(&stuff->context, n);
 | 
						||
    return ProcRecordDisableContext(client);
 | 
						||
} /* SProcRecordDisableContext */
 | 
						||
 | 
						||
 | 
						||
static int
 | 
						||
SProcRecordFreeContext(ClientPtr client)
 | 
						||
{
 | 
						||
    REQUEST(xRecordFreeContextReq);
 | 
						||
    register char 	n;
 | 
						||
 | 
						||
    swaps(&stuff->length, n);
 | 
						||
    REQUEST_SIZE_MATCH(xRecordFreeContextReq);
 | 
						||
    swapl(&stuff->context, n);
 | 
						||
    return ProcRecordFreeContext(client);
 | 
						||
} /* SProcRecordFreeContext */
 | 
						||
 | 
						||
 | 
						||
static int
 | 
						||
SProcRecordDispatch(ClientPtr client)
 | 
						||
{
 | 
						||
    REQUEST(xReq);
 | 
						||
 | 
						||
    switch (stuff->data)
 | 
						||
    {
 | 
						||
	case X_RecordQueryVersion:
 | 
						||
	    return SProcRecordQueryVersion(client);
 | 
						||
	case X_RecordCreateContext:
 | 
						||
	    return SProcRecordCreateContext(client);
 | 
						||
	case X_RecordRegisterClients:
 | 
						||
	    return SProcRecordRegisterClients(client);
 | 
						||
	case X_RecordUnregisterClients:
 | 
						||
	    return SProcRecordUnregisterClients(client);
 | 
						||
	case X_RecordGetContext:
 | 
						||
	    return SProcRecordGetContext(client);
 | 
						||
	case X_RecordEnableContext:
 | 
						||
	    return SProcRecordEnableContext(client);
 | 
						||
	case X_RecordDisableContext:
 | 
						||
	    return SProcRecordDisableContext(client);
 | 
						||
	case X_RecordFreeContext:
 | 
						||
	    return SProcRecordFreeContext(client);
 | 
						||
       default:
 | 
						||
	    return BadRequest;
 | 
						||
    }
 | 
						||
} /* SProcRecordDispatch */
 | 
						||
 | 
						||
/* RecordConnectionSetupInfo
 | 
						||
 *
 | 
						||
 * Arguments:
 | 
						||
 *	pContext is an enabled context that specifies recording of 
 | 
						||
 *	  connection setup info.
 | 
						||
 *	pci holds the connection setup info.
 | 
						||
 *
 | 
						||
 * Returns: nothing.
 | 
						||
 *
 | 
						||
 * Side Effects:
 | 
						||
 *	The connection setup info is sent to the recording client.
 | 
						||
 */
 | 
						||
static void
 | 
						||
RecordConnectionSetupInfo(RecordContextPtr pContext, NewClientInfoRec *pci)
 | 
						||
{
 | 
						||
    int prefixsize = SIZEOF(xConnSetupPrefix);
 | 
						||
    int restsize = pci->prefix->length * 4;
 | 
						||
 | 
						||
    if (pci->client->swapped)
 | 
						||
    {
 | 
						||
	char *pConnSetup = (char *)ALLOCATE_LOCAL(prefixsize + restsize);
 | 
						||
	if (!pConnSetup)
 | 
						||
	    return;
 | 
						||
	SwapConnSetupPrefix(pci->prefix, pConnSetup);
 | 
						||
	SwapConnSetupInfo(pci->setup, pConnSetup + prefixsize);
 | 
						||
	RecordAProtocolElement(pContext, pci->client, XRecordClientStarted,
 | 
						||
			       (pointer)pConnSetup, prefixsize + restsize, 0);
 | 
						||
	DEALLOCATE_LOCAL(pConnSetup);
 | 
						||
    }
 | 
						||
    else
 | 
						||
    {
 | 
						||
	/* don't alloc and copy as in the swapped case; just send the
 | 
						||
	 * data in two pieces
 | 
						||
	 */
 | 
						||
	RecordAProtocolElement(pContext, pci->client, XRecordClientStarted,
 | 
						||
			(pointer)pci->prefix, prefixsize, restsize);
 | 
						||
	RecordAProtocolElement(pContext, pci->client, XRecordClientStarted,
 | 
						||
			(pointer)pci->setup, restsize, /* continuation */ -1);
 | 
						||
    }
 | 
						||
} /* RecordConnectionSetupInfo */
 | 
						||
 | 
						||
 | 
						||
/* RecordDeleteContext
 | 
						||
 *
 | 
						||
 * Arguments:
 | 
						||
 *	pcbl is &ClientStateCallback.
 | 
						||
 *	nullata is NULL.
 | 
						||
 *	calldata is a pointer to a NewClientInfoRec (include/dixstruct.h)
 | 
						||
 *	which contains information about client state changes.
 | 
						||
 *
 | 
						||
 * Returns: nothing.
 | 
						||
 *
 | 
						||
 * Side Effects:
 | 
						||
 *	If a new client has connected and any contexts have specified
 | 
						||
 *	XRecordFutureClients, the new client is registered on those contexts.
 | 
						||
 *	If any of those contexts specify recording of the connection setup
 | 
						||
 *	info, it is recorded.
 | 
						||
 *
 | 
						||
 *	If an existing client has disconnected, it is deleted from any
 | 
						||
 *	contexts that it was registered on.  If any of those contexts
 | 
						||
 *	specified XRecordClientDied, they record a ClientDied protocol element.
 | 
						||
 *	If the disconnectiong client happened to be the data connection of an
 | 
						||
 *	enabled context, the context is disabled.
 | 
						||
 */
 | 
						||
 | 
						||
static void
 | 
						||
RecordAClientStateChange(CallbackListPtr *pcbl, pointer nulldata, pointer calldata)
 | 
						||
{
 | 
						||
    NewClientInfoRec *pci = (NewClientInfoRec *)calldata;
 | 
						||
    int i;
 | 
						||
    ClientPtr pClient = pci->client;
 | 
						||
 | 
						||
    switch (pClient->clientState)
 | 
						||
    {
 | 
						||
    case ClientStateRunning: /* new client */
 | 
						||
	for (i = 0; i < numContexts; i++)
 | 
						||
	{
 | 
						||
	    RecordClientsAndProtocolPtr pRCAP;
 | 
						||
	    RecordContextPtr pContext = ppAllContexts[i];
 | 
						||
 | 
						||
	    if ((pRCAP = RecordFindClientOnContext(pContext,
 | 
						||
					    XRecordFutureClients, NULL)))
 | 
						||
	    {
 | 
						||
		RecordAddClientToRCAP(pRCAP, pClient->clientAsMask);
 | 
						||
		if (pContext->pRecordingClient && pRCAP->clientStarted)
 | 
						||
		    RecordConnectionSetupInfo(pContext, pci);
 | 
						||
	    }
 | 
						||
	}
 | 
						||
    break;
 | 
						||
 | 
						||
    case ClientStateGone:
 | 
						||
    case ClientStateRetained: /* client disconnected */
 | 
						||
	for (i = 0; i < numContexts; i++)
 | 
						||
	{
 | 
						||
	    RecordClientsAndProtocolPtr pRCAP;
 | 
						||
	    RecordContextPtr pContext = ppAllContexts[i];
 | 
						||
	    int pos;
 | 
						||
 | 
						||
	    if (pContext->pRecordingClient == pClient)
 | 
						||
		RecordDisableContext(pContext);
 | 
						||
	    if ((pRCAP = RecordFindClientOnContext(pContext,
 | 
						||
				    pClient->clientAsMask, &pos)))
 | 
						||
	    {
 | 
						||
		if (pContext->pRecordingClient && pRCAP->clientDied)
 | 
						||
		    RecordAProtocolElement(pContext, pClient,
 | 
						||
					   XRecordClientDied, NULL, 0, 0);
 | 
						||
		RecordDeleteClientFromRCAP(pRCAP, pos);
 | 
						||
	    }
 | 
						||
	}
 | 
						||
    break;
 | 
						||
 | 
						||
    default:
 | 
						||
    break;
 | 
						||
    } /* end switch on client state */
 | 
						||
} /* RecordAClientStateChange */
 | 
						||
 | 
						||
 | 
						||
/* RecordCloseDown
 | 
						||
 *
 | 
						||
 * Arguments:
 | 
						||
 *	extEntry is the extension information for RECORD.
 | 
						||
 *
 | 
						||
 * Returns: nothing.
 | 
						||
 *
 | 
						||
 * Side Effects:
 | 
						||
 *	Performs any cleanup needed by RECORD at server shutdown time.
 | 
						||
 *	
 | 
						||
 */
 | 
						||
static void
 | 
						||
RecordCloseDown(ExtensionEntry *extEntry)
 | 
						||
{
 | 
						||
    DeleteCallback(&ClientStateCallback, RecordAClientStateChange, NULL);
 | 
						||
} /* RecordCloseDown */
 | 
						||
 | 
						||
 | 
						||
/* RecordExtensionInit
 | 
						||
 *
 | 
						||
 * Arguments: none.
 | 
						||
 *
 | 
						||
 * Returns: nothing.
 | 
						||
 *
 | 
						||
 * Side Effects:
 | 
						||
 *	Enables the RECORD extension if possible.
 | 
						||
 */
 | 
						||
void 
 | 
						||
RecordExtensionInit(void)
 | 
						||
{
 | 
						||
    ExtensionEntry *extentry;
 | 
						||
 | 
						||
    RTContext = CreateNewResourceType(RecordDeleteContext);
 | 
						||
    if (!RTContext)
 | 
						||
	return;
 | 
						||
 | 
						||
    RecordClientPrivateIndex = AllocateClientPrivateIndex();
 | 
						||
    if (!AllocateClientPrivate(RecordClientPrivateIndex, 0))
 | 
						||
	return;
 | 
						||
 | 
						||
    ppAllContexts = NULL;
 | 
						||
    numContexts = numEnabledContexts = numEnabledRCAPs = 0;
 | 
						||
 | 
						||
    if (!AddCallback(&ClientStateCallback, RecordAClientStateChange, NULL))
 | 
						||
	return;
 | 
						||
 | 
						||
    extentry = AddExtension(RECORD_NAME, RecordNumEvents, RecordNumErrors,
 | 
						||
			    ProcRecordDispatch, SProcRecordDispatch,
 | 
						||
			    RecordCloseDown, StandardMinorOpcode);
 | 
						||
    if (!extentry)
 | 
						||
    {
 | 
						||
	DeleteCallback(&ClientStateCallback, RecordAClientStateChange, NULL);
 | 
						||
	return;
 | 
						||
    }
 | 
						||
    RecordErrorBase = extentry->errorBase;
 | 
						||
 | 
						||
} /* RecordExtensionInit */
 | 
						||
 |