xserver

xserver with xephyr scale patch
git clone https://git.neptards.moe/u3shit/xserver.git
Log | Files | Refs | README | LICENSE

record.c (100886B)


      1 
      2 /*
      3 
      4 Copyright 1995, 1998  The Open Group
      5 
      6 Permission to use, copy, modify, distribute, and sell this software and its
      7 documentation for any purpose is hereby granted without fee, provided that
      8 the above copyright notice appear in all copies and that both that
      9 copyright notice and this permission notice appear in supporting
     10 documentation.
     11 
     12 The above copyright notice and this permission notice shall be
     13 included in all copies or substantial portions of the Software.
     14 
     15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
     16 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     17 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
     18 IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
     19 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     20 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     21 OTHER DEALINGS IN THE SOFTWARE.
     22 
     23 Except as contained in this notice, the name of The Open Group shall
     24 not be used in advertising or otherwise to promote the sale, use or
     25 other dealings in this Software without prior written authorization
     26 from The Open Group.
     27 
     28 Author: David P. Wiggins, The Open Group
     29 
     30 This work benefited from earlier work done by Martha Zimet of NCD
     31 and Jim Haggerty of Metheus.
     32 
     33 */
     34 
     35 #ifdef HAVE_DIX_CONFIG_H
     36 #include <dix-config.h>
     37 #endif
     38 
     39 #include "dixstruct.h"
     40 #include "extnsionst.h"
     41 #include "extinit.h"
     42 #include <X11/extensions/recordproto.h>
     43 #include "set.h"
     44 #include "swaprep.h"
     45 #include "inputstr.h"
     46 #include "eventconvert.h"
     47 #include "scrnintstr.h"
     48 
     49 #include <stdio.h>
     50 #include <assert.h>
     51 
     52 #ifdef PANORAMIX
     53 #include "globals.h"
     54 #include "panoramiX.h"
     55 #include "panoramiXsrv.h"
     56 #include "cursor.h"
     57 #endif
     58 
     59 #include "protocol-versions.h"
     60 
     61 static RESTYPE RTContext;       /* internal resource type for Record contexts */
     62 
     63 /* How many bytes of protocol data to buffer in a context. Don't set to less
     64  * than 32.
     65  */
     66 #define REPLY_BUF_SIZE 1024
     67 
     68 /* Record Context structure */
     69 
     70 typedef struct {
     71     XID id;                     /* resource id of context */
     72     ClientPtr pRecordingClient; /* client that has context enabled */
     73     struct _RecordClientsAndProtocolRec *pListOfRCAP;   /* all registered info */
     74     ClientPtr pBufClient;       /* client whose protocol is in replyBuffer */
     75     unsigned int continuedReply:1;      /* recording a reply that is split up? */
     76     char elemHeaders;           /* element header flags (time/seq no.) */
     77     char bufCategory;           /* category of protocol in replyBuffer */
     78     int numBufBytes;            /* number of bytes in replyBuffer */
     79     char replyBuffer[REPLY_BUF_SIZE];   /* buffered recorded protocol */
     80     int inFlush;                /*  are we inside RecordFlushReplyBuffer */
     81 } RecordContextRec, *RecordContextPtr;
     82 
     83 /*  RecordMinorOpRec - to hold minor opcode selections for extension requests
     84  *  and replies
     85  */
     86 
     87 typedef union {
     88     int count;                  /* first element of array: how many "major" structs to follow */
     89     struct {                    /* rest of array elements are this */
     90         short first;            /* first major opcode */
     91         short last;             /* last major opcode */
     92         RecordSetPtr pMinOpSet; /*  minor opcode set for above major range */
     93     } major;
     94 } RecordMinorOpRec, *RecordMinorOpPtr;
     95 
     96 /*  RecordClientsAndProtocolRec, nicknamed RCAP - holds all the client and
     97  *  protocol selections passed in a single CreateContext or RegisterClients.
     98  *  Generally, a context will have one of these from the create and an
     99  *  additional one for each RegisterClients.  RCAPs are freed when all their
    100  *  clients are unregistered.
    101  */
    102 
    103 typedef struct _RecordClientsAndProtocolRec {
    104     RecordContextPtr pContext;  /* context that owns this RCAP */
    105     struct _RecordClientsAndProtocolRec *pNextRCAP;     /* next RCAP on context */
    106     RecordSetPtr pRequestMajorOpSet;    /* requests to record */
    107     RecordMinorOpPtr pRequestMinOpInfo; /* extension requests to record */
    108     RecordSetPtr pReplyMajorOpSet;      /* replies to record */
    109     RecordMinorOpPtr pReplyMinOpInfo;   /* extension replies to record */
    110     RecordSetPtr pDeviceEventSet;       /* device events to record */
    111     RecordSetPtr pDeliveredEventSet;    /* delivered events to record */
    112     RecordSetPtr pErrorSet;     /* errors to record */
    113     XID *pClientIDs;            /* array of clients to record */
    114     short numClients;           /* number of clients in pClientIDs */
    115     short sizeClients;          /* size of pClientIDs array */
    116     unsigned int clientStarted:1;       /* record new client connections? */
    117     unsigned int clientDied:1;  /* record client disconnections? */
    118     unsigned int clientIDsSeparatelyAllocated:1;        /* pClientIDs malloced? */
    119 } RecordClientsAndProtocolRec, *RecordClientsAndProtocolPtr;
    120 
    121 /* how much bigger to make pRCAP->pClientIDs when reallocing */
    122 #define CLIENT_ARRAY_GROWTH_INCREMENT 4
    123 
    124 /* counts the total number of RCAPs belonging to enabled contexts. */
    125 static int numEnabledRCAPs;
    126 
    127 /*  void VERIFY_CONTEXT(RecordContextPtr, XID, ClientPtr)
    128  *  In the spirit of the VERIFY_* macros in dix.h, this macro fills in
    129  *  the context pointer if the given ID is a valid Record Context, else it
    130  *  returns an error.
    131  */
    132 #define VERIFY_CONTEXT(_pContext, _contextid, _client) { \
    133     int rc = dixLookupResourceByType((void **)&(_pContext), _contextid, \
    134                                      RTContext, _client, DixUseAccess); \
    135     if (rc != Success) \
    136 	return rc; \
    137 }
    138 
    139 static int RecordDeleteContext(void     *value,
    140                                XID      id);
    141 
    142 /***************************************************************************/
    143 
    144 /* client private stuff */
    145 
    146 /*  To make declarations less obfuscated, have a typedef for a pointer to a
    147  *  Proc function.
    148  */
    149 typedef int (*ProcFunctionPtr) (ClientPtr       /*pClient */
    150     );
    151 
    152 /* Record client private.  Generally a client only has one of these if
    153  * any of its requests are being recorded.
    154  */
    155 typedef struct {
    156 /* ptr to client's proc vector before Record stuck its nose in */
    157     ProcFunctionPtr *originalVector;
    158 
    159 /* proc vector with pointers for recorded requests redirected to the
    160  * function RecordARequest
    161  */
    162     ProcFunctionPtr recordVector[256];
    163 } RecordClientPrivateRec, *RecordClientPrivatePtr;
    164 
    165 static DevPrivateKeyRec RecordClientPrivateKeyRec;
    166 
    167 #define RecordClientPrivateKey (&RecordClientPrivateKeyRec)
    168 
    169 /*  RecordClientPrivatePtr RecordClientPrivate(ClientPtr)
    170  *  gets the client private of the given client.  Syntactic sugar.
    171  */
    172 #define RecordClientPrivate(_pClient) (RecordClientPrivatePtr) \
    173     dixLookupPrivate(&(_pClient)->devPrivates, RecordClientPrivateKey)
    174 
    175 /***************************************************************************/
    176 
    177 /* global list of all contexts */
    178 
    179 static RecordContextPtr *ppAllContexts;
    180 
    181 static int numContexts;         /* number of contexts in ppAllContexts */
    182 
    183 /* number of currently enabled contexts.  All enabled contexts are bunched
    184  * up at the front of the ppAllContexts array, from ppAllContexts[0] to
    185  * ppAllContexts[numEnabledContexts-1], to eliminate time spent skipping
    186  * past disabled contexts.
    187  */
    188 static int numEnabledContexts;
    189 
    190 /* RecordFindContextOnAllContexts
    191  *
    192  * Arguments:
    193  *	pContext is the context to search for.
    194  *
    195  * Returns:
    196  *	The index into the array ppAllContexts at which pContext is stored.
    197  *	If pContext is not found in ppAllContexts, returns -1.
    198  *
    199  * Side Effects: none.
    200  */
    201 static int
    202 RecordFindContextOnAllContexts(RecordContextPtr pContext)
    203 {
    204     int i;
    205 
    206     assert(numContexts >= numEnabledContexts);
    207     for (i = 0; i < numContexts; i++) {
    208         if (ppAllContexts[i] == pContext)
    209             return i;
    210     }
    211     return -1;
    212 }                               /* RecordFindContextOnAllContexts */
    213 
    214 /***************************************************************************/
    215 
    216 /* RecordFlushReplyBuffer
    217  *
    218  * Arguments:
    219  *	pContext is the context to flush.
    220  *	data1 is a pointer to additional data, and len1 is its length in bytes.
    221  *	data2 is a pointer to additional data, and len2 is its length in bytes.
    222  *
    223  * Returns: nothing.
    224  *
    225  * Side Effects:
    226  *	If the context is enabled, any buffered (recorded) protocol is written
    227  *	to the recording client, and the number of buffered bytes is set to
    228  *	zero.  If len1 is not zero, data1/len1 are then written to the
    229  *	recording client, and similarly for data2/len2 (written after
    230  *	data1/len1).
    231  */
    232 static void
    233 RecordFlushReplyBuffer(RecordContextPtr pContext,
    234                        void *data1, int len1, void *data2, int len2)
    235 {
    236     if (!pContext->pRecordingClient || pContext->pRecordingClient->clientGone ||
    237         pContext->inFlush)
    238         return;
    239     ++pContext->inFlush;
    240     if (pContext->numBufBytes)
    241         WriteToClient(pContext->pRecordingClient, pContext->numBufBytes,
    242                       pContext->replyBuffer);
    243     pContext->numBufBytes = 0;
    244     if (len1)
    245         WriteToClient(pContext->pRecordingClient, len1, data1);
    246     if (len2)
    247         WriteToClient(pContext->pRecordingClient, len2, data2);
    248     --pContext->inFlush;
    249 }                               /* RecordFlushReplyBuffer */
    250 
    251 /* RecordAProtocolElement
    252  *
    253  * Arguments:
    254  *	pContext is the context that is recording a protocol element.
    255  *	pClient is the client whose protocol is being recorded.  For
    256  *	  device events and EndOfData, pClient is NULL.
    257  *	category is the category of the protocol element, as defined
    258  *	  by the RECORD spec.
    259  *	data is a pointer to the protocol data, and datalen - padlen
    260  *	  is its length in bytes.
    261  *	padlen is the number of pad bytes from a zeroed array.
    262  *	futurelen is the number of bytes that will be sent in subsequent
    263  *	  calls to this function to complete this protocol element.
    264  *	  In those subsequent calls, futurelen will be -1 to indicate
    265  *	  that the current data is a continuation of the same protocol
    266  *	  element.
    267  *
    268  * Returns: nothing.
    269  *
    270  * Side Effects:
    271  *	The context may be flushed.  The new protocol element will be
    272  *	added to the context's protocol buffer with appropriate element
    273  *	headers prepended (sequence number and timestamp).  If the data
    274  *	is continuation data (futurelen == -1), element headers won't
    275  *	be added.  If the protocol element and headers won't fit in
    276  *	the context's buffer, it is sent directly to the recording
    277  *	client (after any buffered data).
    278  */
    279 static void
    280 RecordAProtocolElement(RecordContextPtr pContext, ClientPtr pClient,
    281                        int category, void *data, int datalen, int padlen,
    282                        int futurelen)
    283 {
    284     CARD32 elemHeaderData[2];
    285     int numElemHeaders = 0;
    286     Bool recordingClientSwapped = pContext->pRecordingClient->swapped;
    287     CARD32 serverTime = 0;
    288     Bool gotServerTime = FALSE;
    289     int replylen;
    290 
    291     if (futurelen >= 0) {       /* start of new protocol element */
    292         xRecordEnableContextReply *pRep = (xRecordEnableContextReply *)
    293             pContext->replyBuffer;
    294 
    295         if (pContext->pBufClient != pClient ||
    296             pContext->bufCategory != category) {
    297             RecordFlushReplyBuffer(pContext, NULL, 0, NULL, 0);
    298             pContext->pBufClient = pClient;
    299             pContext->bufCategory = category;
    300         }
    301 
    302         if (!pContext->numBufBytes) {
    303             serverTime = GetTimeInMillis();
    304             gotServerTime = TRUE;
    305             pRep->type = X_Reply;
    306             pRep->category = category;
    307             pRep->sequenceNumber = pContext->pRecordingClient->sequence;
    308             pRep->length = 0;
    309             pRep->elementHeader = pContext->elemHeaders;
    310             pRep->serverTime = serverTime;
    311             if (pClient) {
    312                 pRep->clientSwapped =
    313                     (pClient->swapped != recordingClientSwapped);
    314                 pRep->idBase = pClient->clientAsMask;
    315                 pRep->recordedSequenceNumber = pClient->sequence;
    316             }
    317             else {              /* it's a device event, StartOfData, or EndOfData */
    318 
    319                 pRep->clientSwapped = (category != XRecordFromServer) &&
    320                     recordingClientSwapped;
    321                 pRep->idBase = 0;
    322                 pRep->recordedSequenceNumber = 0;
    323             }
    324 
    325             if (recordingClientSwapped) {
    326                 swaps(&pRep->sequenceNumber);
    327                 swapl(&pRep->length);
    328                 swapl(&pRep->idBase);
    329                 swapl(&pRep->serverTime);
    330                 swapl(&pRep->recordedSequenceNumber);
    331             }
    332             pContext->numBufBytes = SIZEOF(xRecordEnableContextReply);
    333         }
    334 
    335         /* generate element headers if needed */
    336 
    337         if (((pContext->elemHeaders & XRecordFromClientTime)
    338              && category == XRecordFromClient)
    339             || ((pContext->elemHeaders & XRecordFromServerTime)
    340                 && category == XRecordFromServer)) {
    341             if (gotServerTime)
    342                 elemHeaderData[numElemHeaders] = serverTime;
    343             else
    344                 elemHeaderData[numElemHeaders] = GetTimeInMillis();
    345             if (recordingClientSwapped)
    346                 swapl(&elemHeaderData[numElemHeaders]);
    347             numElemHeaders++;
    348         }
    349 
    350         if ((pContext->elemHeaders & XRecordFromClientSequence)
    351             && (category == XRecordFromClient || category == XRecordClientDied)) {
    352             elemHeaderData[numElemHeaders] = pClient->sequence;
    353             if (recordingClientSwapped)
    354                 swapl(&elemHeaderData[numElemHeaders]);
    355             numElemHeaders++;
    356         }
    357 
    358         /* adjust reply length */
    359 
    360         replylen = pRep->length;
    361         if (recordingClientSwapped)
    362             swapl(&replylen);
    363         replylen += numElemHeaders + bytes_to_int32(datalen) +
    364             bytes_to_int32(futurelen);
    365         if (recordingClientSwapped)
    366             swapl(&replylen);
    367         pRep->length = replylen;
    368     }                           /* end if not continued reply */
    369 
    370     numElemHeaders *= 4;
    371 
    372     /* if space available >= space needed, buffer the data */
    373 
    374     if (REPLY_BUF_SIZE - pContext->numBufBytes >= datalen + numElemHeaders) {
    375         if (numElemHeaders) {
    376             memcpy(pContext->replyBuffer + pContext->numBufBytes,
    377                    elemHeaderData, numElemHeaders);
    378             pContext->numBufBytes += numElemHeaders;
    379         }
    380         if (datalen) {
    381             static char padBuffer[3];   /* as in FlushClient */
    382 
    383             memcpy(pContext->replyBuffer + pContext->numBufBytes,
    384                    data, datalen - padlen);
    385             pContext->numBufBytes += datalen - padlen;
    386             memcpy(pContext->replyBuffer + pContext->numBufBytes,
    387                    padBuffer, padlen);
    388             pContext->numBufBytes += padlen;
    389         }
    390     }
    391     else {
    392         RecordFlushReplyBuffer(pContext, (void *) elemHeaderData,
    393                                numElemHeaders, (void *) data,
    394                                datalen - padlen);
    395     }
    396 }                               /* RecordAProtocolElement */
    397 
    398 /* RecordFindClientOnContext
    399  *
    400  * Arguments:
    401  *	pContext is the context to search.
    402  *	clientspec is the resource ID mask identifying the client to search
    403  *	  for, or XRecordFutureClients.
    404  *	pposition is a pointer to an int, or NULL.  See Returns.
    405  *
    406  * Returns:
    407  *	The RCAP on which clientspec was found, or NULL if not found on
    408  *	any RCAP on the given context.
    409  *	If pposition was not NULL and the returned RCAP is not NULL,
    410  *	*pposition will be set to the index into the returned the RCAP's
    411  *	pClientIDs array that holds clientspec.
    412  *
    413  * Side Effects: none.
    414  */
    415 static RecordClientsAndProtocolPtr
    416 RecordFindClientOnContext(RecordContextPtr pContext,
    417                           XID clientspec, int *pposition)
    418 {
    419     RecordClientsAndProtocolPtr pRCAP;
    420 
    421     for (pRCAP = pContext->pListOfRCAP; pRCAP; pRCAP = pRCAP->pNextRCAP) {
    422         int i;
    423 
    424         for (i = 0; i < pRCAP->numClients; i++) {
    425             if (pRCAP->pClientIDs[i] == clientspec) {
    426                 if (pposition)
    427                     *pposition = i;
    428                 return pRCAP;
    429             }
    430         }
    431     }
    432     return NULL;
    433 }                               /* RecordFindClientOnContext */
    434 
    435 /* RecordABigRequest
    436  *
    437  * Arguments:
    438  *	pContext is the recording context.
    439  *	client is the client being recorded.
    440  *	stuff is a pointer to the big request of client (see the Big Requests
    441  *	extension for details.)
    442  *
    443  * Returns: nothing.
    444  *
    445  * Side Effects:
    446  *	The big request is recorded with the correct length field re-inserted.
    447  *	
    448  * Note: this function exists mainly to make RecordARequest smaller.
    449  */
    450 static void
    451 RecordABigRequest(RecordContextPtr pContext, ClientPtr client, xReq * stuff)
    452 {
    453     CARD32 bigLength;
    454     int bytesLeft;
    455 
    456     /* note: client->req_len has been frobbed by ReadRequestFromClient
    457      * (os/io.c) to discount the extra 4 bytes taken by the extended length
    458      * field in a big request.  The actual request length to record is
    459      * client->req_len + 1 (measured in CARD32s).
    460      */
    461 
    462     /* record the request header */
    463     bytesLeft = client->req_len << 2;
    464     RecordAProtocolElement(pContext, client, XRecordFromClient,
    465                            (void *) stuff, SIZEOF(xReq), 0, bytesLeft);
    466 
    467     /* reinsert the extended length field that was squished out */
    468     bigLength = client->req_len + bytes_to_int32(sizeof(bigLength));
    469     if (client->swapped)
    470         swapl(&bigLength);
    471     RecordAProtocolElement(pContext, client, XRecordFromClient,
    472                            (void *) &bigLength, sizeof(bigLength), 0,
    473                            /* continuation */ -1);
    474     bytesLeft -= sizeof(bigLength);
    475 
    476     /* record the rest of the request after the length */
    477     RecordAProtocolElement(pContext, client, XRecordFromClient,
    478                            (void *) (stuff + 1), bytesLeft, 0,
    479                            /* continuation */ -1);
    480 }                               /* RecordABigRequest */
    481 
    482 /* RecordARequest
    483  *
    484  * Arguments:
    485  *	client is a client that the server has dispatched a request to by
    486  *	calling client->requestVector[request opcode] .
    487  *	The request is in client->requestBuffer.
    488  *
    489  * Returns:
    490  *	Whatever is returned by the "real" Proc function for this request.
    491  *	The "real" Proc function is the function that was in
    492  *	client->requestVector[request opcode]  before it was replaced by
    493  *	RecordARequest.  (See the function RecordInstallHooks.)
    494  *
    495  * Side Effects:
    496  *	The request is recorded by all contexts that have registered this
    497  *	request for this client.  The real Proc function is called.
    498  */
    499 static int
    500 RecordARequest(ClientPtr client)
    501 {
    502     RecordContextPtr pContext;
    503     RecordClientsAndProtocolPtr pRCAP;
    504     int i;
    505     RecordClientPrivatePtr pClientPriv;
    506 
    507     REQUEST(xReq);
    508     int majorop;
    509 
    510     majorop = stuff->reqType;
    511     for (i = 0; i < numEnabledContexts; i++) {
    512         pContext = ppAllContexts[i];
    513         pRCAP = RecordFindClientOnContext(pContext, client->clientAsMask, NULL);
    514         if (pRCAP && pRCAP->pRequestMajorOpSet &&
    515             RecordIsMemberOfSet(pRCAP->pRequestMajorOpSet, majorop)) {
    516             if (majorop <= 127) {       /* core request */
    517 
    518                 if (stuff->length == 0)
    519                     RecordABigRequest(pContext, client, stuff);
    520                 else
    521                     RecordAProtocolElement(pContext, client, XRecordFromClient,
    522                                            (void *) stuff,
    523                                            client->req_len << 2, 0, 0);
    524             }
    525             else {              /* extension, check minor opcode */
    526 
    527                 int minorop = client->minorOp;
    528                 int numMinOpInfo;
    529                 RecordMinorOpPtr pMinorOpInfo = pRCAP->pRequestMinOpInfo;
    530 
    531                 assert(pMinorOpInfo);
    532                 numMinOpInfo = pMinorOpInfo->count;
    533                 pMinorOpInfo++;
    534                 assert(numMinOpInfo);
    535                 for (; numMinOpInfo; numMinOpInfo--, pMinorOpInfo++) {
    536                     if (majorop >= pMinorOpInfo->major.first &&
    537                         majorop <= pMinorOpInfo->major.last &&
    538                         RecordIsMemberOfSet(pMinorOpInfo->major.pMinOpSet,
    539                                             minorop)) {
    540                         if (stuff->length == 0)
    541                             RecordABigRequest(pContext, client, stuff);
    542                         else
    543                             RecordAProtocolElement(pContext, client,
    544                                                    XRecordFromClient,
    545                                                    (void *) stuff,
    546                                                    client->req_len << 2, 0, 0);
    547                         break;
    548                     }
    549                 }               /* end for each minor op info */
    550             }                   /* end extension request */
    551         }                       /* end this RCAP wants this major opcode */
    552     }                           /* end for each context */
    553     pClientPriv = RecordClientPrivate(client);
    554     assert(pClientPriv);
    555     return (*pClientPriv->originalVector[majorop]) (client);
    556 }                               /* RecordARequest */
    557 
    558 /* RecordAReply
    559  *
    560  * Arguments:
    561  *	pcbl is &ReplyCallback.
    562  *	nulldata is NULL.
    563  *	calldata is a pointer to a ReplyInfoRec (include/os.h)
    564  *	  which provides information about replies that are being sent
    565  *	  to clients.
    566  *
    567  * Returns: nothing.
    568  *
    569  * Side Effects:
    570  *	The reply is recorded by all contexts that have registered this
    571  *	reply type for this client.  If more data belonging to the same
    572  *	reply is expected, and if the reply is being recorded by any
    573  *	context, pContext->continuedReply is set to 1.
    574  *	If pContext->continuedReply was already 1 and this is the last
    575  *	chunk of data belonging to this reply, it is set to 0.
    576  */
    577 static void
    578 RecordAReply(CallbackListPtr *pcbl, void *nulldata, void *calldata)
    579 {
    580     RecordContextPtr pContext;
    581     RecordClientsAndProtocolPtr pRCAP;
    582     int eci;
    583     ReplyInfoRec *pri = (ReplyInfoRec *) calldata;
    584     ClientPtr client = pri->client;
    585 
    586     for (eci = 0; eci < numEnabledContexts; eci++) {
    587         pContext = ppAllContexts[eci];
    588         pRCAP = RecordFindClientOnContext(pContext, client->clientAsMask, NULL);
    589         if (pRCAP) {
    590             int majorop = client->majorOp;
    591 
    592             if (pContext->continuedReply) {
    593                 RecordAProtocolElement(pContext, client, XRecordFromServer,
    594                                        (void *) pri->replyData,
    595                                        pri->dataLenBytes, pri->padBytes,
    596                                        /* continuation */ -1);
    597                 if (!pri->bytesRemaining)
    598                     pContext->continuedReply = 0;
    599             }
    600             else if (pri->startOfReply && pRCAP->pReplyMajorOpSet &&
    601                      RecordIsMemberOfSet(pRCAP->pReplyMajorOpSet, majorop)) {
    602                 if (majorop <= 127) {   /* core reply */
    603                     RecordAProtocolElement(pContext, client, XRecordFromServer,
    604                                            (void *) pri->replyData,
    605                                            pri->dataLenBytes, 0,
    606                                            pri->bytesRemaining);
    607                     if (pri->bytesRemaining)
    608                         pContext->continuedReply = 1;
    609                 }
    610                 else {          /* extension, check minor opcode */
    611 
    612                     int minorop = client->minorOp;
    613                     int numMinOpInfo;
    614                     RecordMinorOpPtr pMinorOpInfo = pRCAP->pReplyMinOpInfo;
    615 
    616                     assert(pMinorOpInfo);
    617                     numMinOpInfo = pMinorOpInfo->count;
    618                     pMinorOpInfo++;
    619                     assert(numMinOpInfo);
    620                     for (; numMinOpInfo; numMinOpInfo--, pMinorOpInfo++) {
    621                         if (majorop >= pMinorOpInfo->major.first &&
    622                             majorop <= pMinorOpInfo->major.last &&
    623                             RecordIsMemberOfSet(pMinorOpInfo->major.pMinOpSet,
    624                                                 minorop)) {
    625                             RecordAProtocolElement(pContext, client,
    626                                                    XRecordFromServer,
    627                                                    (void *) pri->replyData,
    628                                                    pri->dataLenBytes, 0,
    629                                                    pri->bytesRemaining);
    630                             if (pri->bytesRemaining)
    631                                 pContext->continuedReply = 1;
    632                             break;
    633                         }
    634                     }           /* end for each minor op info */
    635                 }               /* end extension reply */
    636             }                   /* end continued reply vs. start of reply */
    637         }                       /* end client is registered on this context */
    638     }                           /* end for each context */
    639 }                               /* RecordAReply */
    640 
    641 /* RecordADeliveredEventOrError
    642  *
    643  * Arguments:
    644  *	pcbl is &EventCallback.
    645  *	nulldata is NULL.
    646  *	calldata is a pointer to a EventInfoRec (include/dix.h)
    647  *	  which provides information about events that are being sent
    648  *	  to clients.
    649  *
    650  * Returns: nothing.
    651  *
    652  * Side Effects:
    653  *	The event or error is recorded by all contexts that have registered
    654  *	it for this client.
    655  */
    656 static void
    657 RecordADeliveredEventOrError(CallbackListPtr *pcbl, void *nulldata,
    658                              void *calldata)
    659 {
    660     EventInfoRec *pei = (EventInfoRec *) calldata;
    661     RecordContextPtr pContext;
    662     RecordClientsAndProtocolPtr pRCAP;
    663     int eci;                    /* enabled context index */
    664     ClientPtr pClient = pei->client;
    665 
    666     for (eci = 0; eci < numEnabledContexts; eci++) {
    667         pContext = ppAllContexts[eci];
    668         pRCAP = RecordFindClientOnContext(pContext, pClient->clientAsMask,
    669                                           NULL);
    670         if (pRCAP && (pRCAP->pDeliveredEventSet || pRCAP->pErrorSet)) {
    671             int ev;             /* event index */
    672             xEvent *pev = pei->events;
    673 
    674             for (ev = 0; ev < pei->count; ev++, pev++) {
    675                 int recordit = 0;
    676 
    677                 if (pRCAP->pErrorSet) {
    678                     recordit = RecordIsMemberOfSet(pRCAP->pErrorSet,
    679                                                    ((xError *) (pev))->
    680                                                    errorCode);
    681                 }
    682                 else if (pRCAP->pDeliveredEventSet) {
    683                     recordit = RecordIsMemberOfSet(pRCAP->pDeliveredEventSet,
    684                                                    pev->u.u.type & 0177);
    685                 }
    686                 if (recordit) {
    687                     xEvent swappedEvent;
    688                     xEvent *pEvToRecord = pev;
    689 
    690                     if (pClient->swapped) {
    691                         (*EventSwapVector[pev->u.u.type & 0177])
    692                             (pev, &swappedEvent);
    693                         pEvToRecord = &swappedEvent;
    694 
    695                     }
    696                     RecordAProtocolElement(pContext, pClient,
    697                                            XRecordFromServer, pEvToRecord,
    698                                            SIZEOF(xEvent), 0, 0);
    699                 }
    700             }                   /* end for each event */
    701         }                       /* end this client is on this context */
    702     }                           /* end for each enabled context */
    703 }                               /* RecordADeliveredEventOrError */
    704 
    705 static void
    706 RecordSendProtocolEvents(RecordClientsAndProtocolPtr pRCAP,
    707                          RecordContextPtr pContext, xEvent *pev, int count)
    708 {
    709     int ev;                     /* event index */
    710 
    711     for (ev = 0; ev < count; ev++, pev++) {
    712         if (RecordIsMemberOfSet(pRCAP->pDeviceEventSet, pev->u.u.type & 0177)) {
    713             xEvent swappedEvent;
    714             xEvent *pEvToRecord = pev;
    715 
    716 #ifdef PANORAMIX
    717             xEvent shiftedEvent;
    718 
    719             if (!noPanoramiXExtension &&
    720                 (pev->u.u.type == MotionNotify ||
    721                  pev->u.u.type == ButtonPress ||
    722                  pev->u.u.type == ButtonRelease ||
    723                  pev->u.u.type == KeyPress || pev->u.u.type == KeyRelease)) {
    724                 int scr = XineramaGetCursorScreen(inputInfo.pointer);
    725 
    726                 memcpy(&shiftedEvent, pev, sizeof(xEvent));
    727                 shiftedEvent.u.keyButtonPointer.rootX +=
    728                     screenInfo.screens[scr]->x - screenInfo.screens[0]->x;
    729                 shiftedEvent.u.keyButtonPointer.rootY +=
    730                     screenInfo.screens[scr]->y - screenInfo.screens[0]->y;
    731                 pEvToRecord = &shiftedEvent;
    732             }
    733 #endif                          /* PANORAMIX */
    734 
    735             if (pContext->pRecordingClient->swapped) {
    736                 (*EventSwapVector[pEvToRecord->u.u.type & 0177])
    737                     (pEvToRecord, &swappedEvent);
    738                 pEvToRecord = &swappedEvent;
    739             }
    740 
    741             RecordAProtocolElement(pContext, NULL,
    742                                    XRecordFromServer, pEvToRecord,
    743                                    SIZEOF(xEvent), 0, 0);
    744             /* make sure device events get flushed in the absence
    745              * of other client activity
    746              */
    747             SetCriticalOutputPending();
    748         }
    749     }                           /* end for each event */
    750 
    751 }                               /* RecordADeviceEvent */
    752 
    753 /* RecordADeviceEvent
    754  *
    755  * Arguments:
    756  *	pcbl is &DeviceEventCallback.
    757  *	nulldata is NULL.
    758  *	calldata is a pointer to a DeviceEventInfoRec (include/dix.h)
    759  *	  which provides information about device events that occur.
    760  *
    761  * Returns: nothing.
    762  *
    763  * Side Effects:
    764  *	The device event is recorded by all contexts that have registered
    765  *	it for this client.
    766  */
    767 static void
    768 RecordADeviceEvent(CallbackListPtr *pcbl, void *nulldata, void *calldata)
    769 {
    770     DeviceEventInfoRec *pei = (DeviceEventInfoRec *) calldata;
    771     RecordContextPtr pContext;
    772     RecordClientsAndProtocolPtr pRCAP;
    773     int eci;                    /* enabled context index */
    774 
    775     for (eci = 0; eci < numEnabledContexts; eci++) {
    776         pContext = ppAllContexts[eci];
    777         for (pRCAP = pContext->pListOfRCAP; pRCAP; pRCAP = pRCAP->pNextRCAP) {
    778             if (pRCAP->pDeviceEventSet) {
    779                 int count;
    780                 xEvent *xi_events = NULL;
    781 
    782                 /* TODO check return values */
    783                 if (IsMaster(pei->device)) {
    784                     xEvent *core_events;
    785 
    786                     EventToCore(pei->event, &core_events, &count);
    787                     RecordSendProtocolEvents(pRCAP, pContext, core_events,
    788                                              count);
    789                     free(core_events);
    790                 }
    791 
    792                 EventToXI(pei->event, &xi_events, &count);
    793                 RecordSendProtocolEvents(pRCAP, pContext, xi_events, count);
    794                 free(xi_events);
    795             }                   /* end this RCAP selects device events */
    796         }                       /* end for each RCAP on this context */
    797     }                           /* end for each enabled context */
    798 }
    799 
    800 /* RecordFlushAllContexts
    801  *
    802  * Arguments:
    803  *	pcbl is &FlushCallback.
    804  *	nulldata and calldata are NULL.
    805  *
    806  * Returns: nothing.
    807  *
    808  * Side Effects:
    809  *	All buffered reply data of all enabled contexts is written to
    810  *	the recording clients.
    811  */
    812 static void
    813 RecordFlushAllContexts(CallbackListPtr *pcbl,
    814                        void *nulldata, void *calldata)
    815 {
    816     int eci;                    /* enabled context index */
    817     RecordContextPtr pContext;
    818 
    819     for (eci = 0; eci < numEnabledContexts; eci++) {
    820         pContext = ppAllContexts[eci];
    821 
    822         /* In most cases we leave it to RecordFlushReplyBuffer to make
    823          * this check, but this function could be called very often, so we
    824          * check before calling hoping to save the function call cost
    825          * most of the time.
    826          */
    827         if (pContext->numBufBytes)
    828             RecordFlushReplyBuffer(ppAllContexts[eci], NULL, 0, NULL, 0);
    829     }
    830 }                               /* RecordFlushAllContexts */
    831 
    832 /* RecordInstallHooks
    833  *
    834  * Arguments:
    835  *	pRCAP is an RCAP on an enabled or being-enabled context.
    836  *	oneclient can be zero or the resource ID mask identifying a client.
    837  *
    838  * Returns: BadAlloc if a memory allocation error occurred, else Success.
    839  *
    840  * Side Effects:
    841  *	Recording hooks needed by RCAP are installed.
    842  *	If oneclient is zero, recording hooks needed for all clients and
    843  *	protocol on the RCAP are installed.  If oneclient is non-zero,
    844  *	only those hooks needed for the specified client are installed.
    845  *	
    846  *	Client requestVectors may be altered.  numEnabledRCAPs will be
    847  *	incremented if oneclient == 0.  Callbacks may be added to
    848  *	various callback lists.
    849  */
    850 static int
    851 RecordInstallHooks(RecordClientsAndProtocolPtr pRCAP, XID oneclient)
    852 {
    853     int i = 0;
    854     XID client;
    855 
    856     if (oneclient)
    857         client = oneclient;
    858     else
    859         client = pRCAP->numClients ? pRCAP->pClientIDs[i++] : 0;
    860 
    861     while (client) {
    862         if (client != XRecordFutureClients) {
    863             if (pRCAP->pRequestMajorOpSet) {
    864                 RecordSetIteratePtr pIter = NULL;
    865                 RecordSetInterval interval;
    866                 ClientPtr pClient = clients[CLIENT_ID(client)];
    867 
    868                 if (pClient && !RecordClientPrivate(pClient)) {
    869                     RecordClientPrivatePtr pClientPriv;
    870 
    871                     /* no Record proc vector; allocate one */
    872                     pClientPriv = (RecordClientPrivatePtr)
    873                         malloc(sizeof(RecordClientPrivateRec));
    874                     if (!pClientPriv)
    875                         return BadAlloc;
    876                     /* copy old proc vector to new */
    877                     memcpy(pClientPriv->recordVector, pClient->requestVector,
    878                            sizeof(pClientPriv->recordVector));
    879                     pClientPriv->originalVector = pClient->requestVector;
    880                     dixSetPrivate(&pClient->devPrivates,
    881                                   RecordClientPrivateKey, pClientPriv);
    882                     pClient->requestVector = pClientPriv->recordVector;
    883                 }
    884                 while ((pIter = RecordIterateSet(pRCAP->pRequestMajorOpSet,
    885                                                  pIter, &interval))) {
    886                     unsigned int j;
    887 
    888                     for (j = interval.first; j <= interval.last; j++)
    889                         pClient->requestVector[j] = RecordARequest;
    890                 }
    891             }
    892         }
    893         if (oneclient)
    894             client = 0;
    895         else
    896             client = (i < pRCAP->numClients) ? pRCAP->pClientIDs[i++] : 0;
    897     }
    898 
    899     assert(numEnabledRCAPs >= 0);
    900     if (!oneclient && ++numEnabledRCAPs == 1) { /* we're enabling the first context */
    901         if (!AddCallback(&EventCallback, RecordADeliveredEventOrError, NULL))
    902             return BadAlloc;
    903         if (!AddCallback(&DeviceEventCallback, RecordADeviceEvent, NULL))
    904             return BadAlloc;
    905         if (!AddCallback(&ReplyCallback, RecordAReply, NULL))
    906             return BadAlloc;
    907         if (!AddCallback(&FlushCallback, RecordFlushAllContexts, NULL))
    908             return BadAlloc;
    909         /* Alternate context flushing scheme: delete the line above
    910          * and call RegisterBlockAndWakeupHandlers here passing
    911          * RecordFlushAllContexts.  Is this any better?
    912          */
    913     }
    914     return Success;
    915 }                               /* RecordInstallHooks */
    916 
    917 /* RecordUninstallHooks
    918  *
    919  * Arguments:
    920  *	pRCAP is an RCAP on an enabled or being-disabled context.
    921  *	oneclient can be zero or the resource ID mask identifying a client.
    922  *
    923  * Returns: nothing.
    924  *
    925  * Side Effects:
    926  *	Recording hooks needed by RCAP may be uninstalled.
    927  *	If oneclient is zero, recording hooks needed for all clients and
    928  *	protocol on the RCAP may be uninstalled.  If oneclient is non-zero,
    929  *	only those hooks needed for the specified client may be uninstalled.
    930  *	
    931  *	Client requestVectors may be altered.  numEnabledRCAPs will be
    932  *	decremented if oneclient == 0.  Callbacks may be deleted from
    933  *	various callback lists.
    934  */
    935 static void
    936 RecordUninstallHooks(RecordClientsAndProtocolPtr pRCAP, XID oneclient)
    937 {
    938     int i = 0;
    939     XID client;
    940 
    941     if (oneclient)
    942         client = oneclient;
    943     else
    944         client = pRCAP->numClients ? pRCAP->pClientIDs[i++] : 0;
    945 
    946     while (client) {
    947         if (client != XRecordFutureClients) {
    948             if (pRCAP->pRequestMajorOpSet) {
    949                 ClientPtr pClient = clients[CLIENT_ID(client)];
    950                 int c;
    951                 Bool otherRCAPwantsProcVector = FALSE;
    952                 RecordClientPrivatePtr pClientPriv = NULL;
    953 
    954                 assert(pClient);
    955                 pClientPriv = RecordClientPrivate(pClient);
    956                 assert(pClientPriv);
    957                 memcpy(pClientPriv->recordVector, pClientPriv->originalVector,
    958                        sizeof(pClientPriv->recordVector));
    959 
    960                 for (c = 0; c < numEnabledContexts; c++) {
    961                     RecordClientsAndProtocolPtr pOtherRCAP;
    962                     RecordContextPtr pContext = ppAllContexts[c];
    963 
    964                     if (pContext == pRCAP->pContext)
    965                         continue;
    966                     pOtherRCAP = RecordFindClientOnContext(pContext, client,
    967                                                            NULL);
    968                     if (pOtherRCAP && pOtherRCAP->pRequestMajorOpSet) {
    969                         RecordSetIteratePtr pIter = NULL;
    970                         RecordSetInterval interval;
    971 
    972                         otherRCAPwantsProcVector = TRUE;
    973                         while ((pIter =
    974                                 RecordIterateSet(pOtherRCAP->pRequestMajorOpSet,
    975                                                  pIter, &interval))) {
    976                             unsigned int j;
    977 
    978                             for (j = interval.first; j <= interval.last; j++)
    979                                 pClient->requestVector[j] = RecordARequest;
    980                         }
    981                     }
    982                 }
    983                 if (!otherRCAPwantsProcVector) {        /* nobody needs it, so free it */
    984                     pClient->requestVector = pClientPriv->originalVector;
    985                     dixSetPrivate(&pClient->devPrivates,
    986                                   RecordClientPrivateKey, NULL);
    987                     free(pClientPriv);
    988                 }
    989             }                   /* end if this RCAP specifies any requests */
    990         }                       /* end if not future clients */
    991         if (oneclient)
    992             client = 0;
    993         else
    994             client = (i < pRCAP->numClients) ? pRCAP->pClientIDs[i++] : 0;
    995     }
    996 
    997     assert(numEnabledRCAPs >= 1);
    998     if (!oneclient && --numEnabledRCAPs == 0) { /* we're disabling the last context */
    999         DeleteCallback(&EventCallback, RecordADeliveredEventOrError, NULL);
   1000         DeleteCallback(&DeviceEventCallback, RecordADeviceEvent, NULL);
   1001         DeleteCallback(&ReplyCallback, RecordAReply, NULL);
   1002         DeleteCallback(&FlushCallback, RecordFlushAllContexts, NULL);
   1003         /* Alternate context flushing scheme: delete the line above
   1004          * and call RemoveBlockAndWakeupHandlers here passing
   1005          * RecordFlushAllContexts.  Is this any better?
   1006          */
   1007         /* Having deleted the callback, call it one last time. -gildea */
   1008         RecordFlushAllContexts(&FlushCallback, NULL, NULL);
   1009     }
   1010 }                               /* RecordUninstallHooks */
   1011 
   1012 /* RecordDeleteClientFromRCAP
   1013  *
   1014  * Arguments:
   1015  *	pRCAP is an RCAP to delete the client from.
   1016  *	position is the index into the array pRCAP->pClientIDs of the
   1017  *	client to delete.
   1018  *
   1019  * Returns: nothing.
   1020  *
   1021  * Side Effects:
   1022  *	Recording hooks needed by client will be uninstalled if the context
   1023  *	is enabled.  The designated client will be removed from the
   1024  *	pRCAP->pClientIDs array.  If it was the only client on the RCAP,
   1025  *	the RCAP is removed from the context and freed.  (Invariant: RCAPs
   1026  *	have at least one client.)
   1027  */
   1028 static void
   1029 RecordDeleteClientFromRCAP(RecordClientsAndProtocolPtr pRCAP, int position)
   1030 {
   1031     if (pRCAP->pContext->pRecordingClient)
   1032         RecordUninstallHooks(pRCAP, pRCAP->pClientIDs[position]);
   1033     if (position != pRCAP->numClients - 1)
   1034         pRCAP->pClientIDs[position] = pRCAP->pClientIDs[pRCAP->numClients - 1];
   1035     if (--pRCAP->numClients == 0) {     /* no more clients; remove RCAP from context's list */
   1036         RecordContextPtr pContext = pRCAP->pContext;
   1037 
   1038         if (pContext->pRecordingClient)
   1039             RecordUninstallHooks(pRCAP, 0);
   1040         if (pContext->pListOfRCAP == pRCAP)
   1041             pContext->pListOfRCAP = pRCAP->pNextRCAP;
   1042         else {
   1043             RecordClientsAndProtocolPtr prevRCAP;
   1044 
   1045             for (prevRCAP = pContext->pListOfRCAP;
   1046                  prevRCAP->pNextRCAP != pRCAP; prevRCAP = prevRCAP->pNextRCAP);
   1047             prevRCAP->pNextRCAP = pRCAP->pNextRCAP;
   1048         }
   1049         /* free the RCAP */
   1050         if (pRCAP->clientIDsSeparatelyAllocated)
   1051             free(pRCAP->pClientIDs);
   1052         free(pRCAP);
   1053     }
   1054 }                               /* RecordDeleteClientFromRCAP */
   1055 
   1056 /* RecordAddClientToRCAP
   1057  *
   1058  * Arguments:
   1059  *	pRCAP is an RCAP to add the client to.
   1060  *	clientspec is the resource ID mask identifying a client, or
   1061  *	  XRecordFutureClients.
   1062  *
   1063  * Returns: nothing.
   1064  *
   1065  * Side Effects:
   1066  *	Recording hooks needed by client will be installed if the context
   1067  *	is enabled.  The designated client will be added to the
   1068  *	pRCAP->pClientIDs array, which may be realloced.
   1069  *	pRCAP->clientIDsSeparatelyAllocated may be set to 1 if there
   1070  *	is no more room to hold clients internal to the RCAP.
   1071  */
   1072 static void
   1073 RecordAddClientToRCAP(RecordClientsAndProtocolPtr pRCAP, XID clientspec)
   1074 {
   1075     if (pRCAP->numClients == pRCAP->sizeClients) {
   1076         if (pRCAP->clientIDsSeparatelyAllocated) {
   1077             XID *pNewIDs =
   1078                 reallocarray(pRCAP->pClientIDs,
   1079                              pRCAP->sizeClients + CLIENT_ARRAY_GROWTH_INCREMENT,
   1080                              sizeof(XID));
   1081             if (!pNewIDs)
   1082                 return;
   1083             pRCAP->pClientIDs = pNewIDs;
   1084             pRCAP->sizeClients += CLIENT_ARRAY_GROWTH_INCREMENT;
   1085         }
   1086         else {
   1087             XID *pNewIDs =
   1088                 xallocarray(pRCAP->sizeClients + CLIENT_ARRAY_GROWTH_INCREMENT,
   1089                             sizeof(XID));
   1090             if (!pNewIDs)
   1091                 return;
   1092             memcpy(pNewIDs, pRCAP->pClientIDs, pRCAP->numClients * sizeof(XID));
   1093             pRCAP->pClientIDs = pNewIDs;
   1094             pRCAP->sizeClients += CLIENT_ARRAY_GROWTH_INCREMENT;
   1095             pRCAP->clientIDsSeparatelyAllocated = 1;
   1096         }
   1097     }
   1098     pRCAP->pClientIDs[pRCAP->numClients++] = clientspec;
   1099     if (pRCAP->pContext->pRecordingClient)
   1100         RecordInstallHooks(pRCAP, clientspec);
   1101 }                               /* RecordDeleteClientFromRCAP */
   1102 
   1103 /* RecordDeleteClientFromContext
   1104  *
   1105  * Arguments:
   1106  *	pContext is the context to delete from.
   1107  *	clientspec is the resource ID mask identifying a client, or
   1108  *	  XRecordFutureClients.
   1109  *
   1110  * Returns: nothing.
   1111  *
   1112  * Side Effects:
   1113  *	If clientspec is on any RCAP of the context, it is deleted from that
   1114  *	RCAP.  (A given clientspec can only be on one RCAP of a context.)
   1115  */
   1116 static void
   1117 RecordDeleteClientFromContext(RecordContextPtr pContext, XID clientspec)
   1118 {
   1119     RecordClientsAndProtocolPtr pRCAP;
   1120     int position;
   1121 
   1122     if ((pRCAP = RecordFindClientOnContext(pContext, clientspec, &position)))
   1123         RecordDeleteClientFromRCAP(pRCAP, position);
   1124 }                               /* RecordDeleteClientFromContext */
   1125 
   1126 /* RecordSanityCheckClientSpecifiers
   1127  *
   1128  * Arguments:
   1129  *	clientspecs is an array of alleged CLIENTSPECs passed by the client.
   1130  *	nspecs is the number of elements in clientspecs.
   1131  *	errorspec, if non-zero, is the resource id base of a client that
   1132  *	  must not appear in clienspecs.
   1133  *
   1134  * Returns: BadMatch if any of the clientspecs are invalid, else Success.
   1135  *
   1136  * Side Effects: none.
   1137  */
   1138 static int
   1139 RecordSanityCheckClientSpecifiers(ClientPtr client, XID *clientspecs,
   1140                                   int nspecs, XID errorspec)
   1141 {
   1142     int i;
   1143     int clientIndex;
   1144     int rc;
   1145     void *value;
   1146 
   1147     for (i = 0; i < nspecs; i++) {
   1148         if (clientspecs[i] == XRecordCurrentClients ||
   1149             clientspecs[i] == XRecordFutureClients ||
   1150             clientspecs[i] == XRecordAllClients)
   1151             continue;
   1152         if (errorspec && (CLIENT_BITS(clientspecs[i]) == errorspec))
   1153             return BadMatch;
   1154         clientIndex = CLIENT_ID(clientspecs[i]);
   1155         if (clientIndex && clients[clientIndex] &&
   1156             clients[clientIndex]->clientState == ClientStateRunning) {
   1157             if (clientspecs[i] == clients[clientIndex]->clientAsMask)
   1158                 continue;
   1159             rc = dixLookupResourceByClass(&value, clientspecs[i], RC_ANY,
   1160                                           client, DixGetAttrAccess);
   1161             if (rc != Success)
   1162                 return rc;
   1163         }
   1164         else
   1165             return BadMatch;
   1166     }
   1167     return Success;
   1168 }                               /* RecordSanityCheckClientSpecifiers */
   1169 
   1170 /* RecordCanonicalizeClientSpecifiers
   1171  *
   1172  * Arguments:
   1173  *	pClientspecs is an array of CLIENTSPECs that have been sanity
   1174  *	  checked.
   1175  *	pNumClientspecs is a pointer to the number of elements in pClientspecs.
   1176  *	excludespec, if non-zero, is the resource id base of a client that
   1177  *	  should not be included in the expansion of XRecordAllClients or
   1178  *	  XRecordCurrentClients.
   1179  *
   1180  * Returns:
   1181  *	A pointer to an array of CLIENTSPECs that is the same as the
   1182  *	passed array with the following modifications:
   1183  *	  - all but the client id bits of resource IDs are stripped off.
   1184  *	  - duplicates removed.
   1185  *	  - XRecordAllClients expanded to a list of all currently connected
   1186  *	    clients + XRecordFutureClients - excludespec (if non-zero)
   1187  *	  - XRecordCurrentClients expanded to a list of all currently
   1188  *	    connected clients - excludespec (if non-zero)
   1189  *	The returned array may be the passed array modified in place, or
   1190  *	it may be an malloc'ed array.  The caller should keep a pointer to the
   1191  *	original array and free the returned array if it is different.
   1192  *
   1193  *	*pNumClientspecs is set to the number of elements in the returned
   1194  *	array.
   1195  *
   1196  * Side Effects:
   1197  *	pClientspecs may be modified in place.
   1198  */
   1199 static XID *
   1200 RecordCanonicalizeClientSpecifiers(XID *pClientspecs, int *pNumClientspecs,
   1201                                    XID excludespec)
   1202 {
   1203     int i;
   1204     int numClients = *pNumClientspecs;
   1205 
   1206     /*  first pass strips off the resource index bits, leaving just the
   1207      *  client id bits.  This makes searching for a particular client simpler
   1208      *  (and faster.)
   1209      */
   1210     for (i = 0; i < numClients; i++) {
   1211         XID cs = pClientspecs[i];
   1212 
   1213         if (cs > XRecordAllClients)
   1214             pClientspecs[i] = CLIENT_BITS(cs);
   1215     }
   1216 
   1217     for (i = 0; i < numClients; i++) {
   1218         if (pClientspecs[i] == XRecordAllClients || pClientspecs[i] == XRecordCurrentClients) { /* expand All/Current */
   1219             int j, nc;
   1220             XID *pCanon = xallocarray(currentMaxClients + 1, sizeof(XID));
   1221 
   1222             if (!pCanon)
   1223                 return NULL;
   1224             for (nc = 0, j = 1; j < currentMaxClients; j++) {
   1225                 ClientPtr client = clients[j];
   1226 
   1227                 if (client != NullClient &&
   1228                     client->clientState == ClientStateRunning &&
   1229                     client->clientAsMask != excludespec) {
   1230                     pCanon[nc++] = client->clientAsMask;
   1231                 }
   1232             }
   1233             if (pClientspecs[i] == XRecordAllClients)
   1234                 pCanon[nc++] = XRecordFutureClients;
   1235             *pNumClientspecs = nc;
   1236             return pCanon;
   1237         }
   1238         else {                  /* not All or Current */
   1239 
   1240             int j;
   1241 
   1242             for (j = i + 1; j < numClients;) {
   1243                 if (pClientspecs[i] == pClientspecs[j]) {
   1244                     pClientspecs[j] = pClientspecs[--numClients];
   1245                 }
   1246                 else
   1247                     j++;
   1248             }
   1249         }
   1250     }                           /* end for each clientspec */
   1251     *pNumClientspecs = numClients;
   1252     return pClientspecs;
   1253 }                               /* RecordCanonicalizeClientSpecifiers */
   1254 
   1255 /****************************************************************************/
   1256 
   1257 /* stuff for RegisterClients */
   1258 
   1259 /* RecordPadAlign
   1260  *
   1261  * Arguments:
   1262  *	size is the number of bytes taken by an object.
   1263  *	align is a byte boundary (e.g. 4, 8)
   1264  *
   1265  * Returns:
   1266  *	the number of pad bytes to add at the end of an object of the
   1267  *	given size so that an object placed immediately behind it will
   1268  *	begin on an <align>-byte boundary.
   1269  *
   1270  * Side Effects: none.
   1271  */
   1272 static int
   1273 RecordPadAlign(int size, int align)
   1274 {
   1275     return (align - (size & (align - 1))) & (align - 1);
   1276 }                               /* RecordPadAlign */
   1277 
   1278 /* RecordSanityCheckRegisterClients
   1279  *
   1280  * Arguments:
   1281  *	pContext is the context being registered on.
   1282  *	client is the client that issued a RecordCreateContext or
   1283  *	  RecordRegisterClients request.
   1284  *	stuff is a pointer to the request.
   1285  *
   1286  * Returns:
   1287  *	Any one of several possible error values if any of the request
   1288  *	arguments are invalid.  Success if everything is OK.
   1289  *
   1290  * Side Effects: none.
   1291  */
   1292 static int
   1293 RecordSanityCheckRegisterClients(RecordContextPtr pContext, ClientPtr client,
   1294                                  xRecordRegisterClientsReq * stuff)
   1295 {
   1296     int err;
   1297     xRecordRange *pRange;
   1298     int i;
   1299     XID recordingClient;
   1300 
   1301     if (((client->req_len << 2) - SIZEOF(xRecordRegisterClientsReq)) !=
   1302         4 * stuff->nClients + SIZEOF(xRecordRange) * stuff->nRanges)
   1303         return BadLength;
   1304 
   1305     if (stuff->elementHeader &
   1306         ~(XRecordFromClientSequence | XRecordFromClientTime |
   1307           XRecordFromServerTime)) {
   1308         client->errorValue = stuff->elementHeader;
   1309         return BadValue;
   1310     }
   1311 
   1312     recordingClient = pContext->pRecordingClient ?
   1313         pContext->pRecordingClient->clientAsMask : 0;
   1314     err = RecordSanityCheckClientSpecifiers(client, (XID *) &stuff[1],
   1315                                             stuff->nClients, recordingClient);
   1316     if (err != Success)
   1317         return err;
   1318 
   1319     pRange = (xRecordRange *) (((XID *) &stuff[1]) + stuff->nClients);
   1320     for (i = 0; i < stuff->nRanges; i++, pRange++) {
   1321         if (pRange->coreRequestsFirst > pRange->coreRequestsLast) {
   1322             client->errorValue = pRange->coreRequestsFirst;
   1323             return BadValue;
   1324         }
   1325         if (pRange->coreRepliesFirst > pRange->coreRepliesLast) {
   1326             client->errorValue = pRange->coreRepliesFirst;
   1327             return BadValue;
   1328         }
   1329         if ((pRange->extRequestsMajorFirst || pRange->extRequestsMajorLast) &&
   1330             (pRange->extRequestsMajorFirst < 128 ||
   1331              pRange->extRequestsMajorLast < 128 ||
   1332              pRange->extRequestsMajorFirst > pRange->extRequestsMajorLast)) {
   1333             client->errorValue = pRange->extRequestsMajorFirst;
   1334             return BadValue;
   1335         }
   1336         if (pRange->extRequestsMinorFirst > pRange->extRequestsMinorLast) {
   1337             client->errorValue = pRange->extRequestsMinorFirst;
   1338             return BadValue;
   1339         }
   1340         if ((pRange->extRepliesMajorFirst || pRange->extRepliesMajorLast) &&
   1341             (pRange->extRepliesMajorFirst < 128 ||
   1342              pRange->extRepliesMajorLast < 128 ||
   1343              pRange->extRepliesMajorFirst > pRange->extRepliesMajorLast)) {
   1344             client->errorValue = pRange->extRepliesMajorFirst;
   1345             return BadValue;
   1346         }
   1347         if (pRange->extRepliesMinorFirst > pRange->extRepliesMinorLast) {
   1348             client->errorValue = pRange->extRepliesMinorFirst;
   1349             return BadValue;
   1350         }
   1351         if ((pRange->deliveredEventsFirst || pRange->deliveredEventsLast) &&
   1352             (pRange->deliveredEventsFirst < 2 ||
   1353              pRange->deliveredEventsLast < 2 ||
   1354              pRange->deliveredEventsFirst > pRange->deliveredEventsLast)) {
   1355             client->errorValue = pRange->deliveredEventsFirst;
   1356             return BadValue;
   1357         }
   1358         if ((pRange->deviceEventsFirst || pRange->deviceEventsLast) &&
   1359             (pRange->deviceEventsFirst < 2 ||
   1360              pRange->deviceEventsLast < 2 ||
   1361              pRange->deviceEventsFirst > pRange->deviceEventsLast)) {
   1362             client->errorValue = pRange->deviceEventsFirst;
   1363             return BadValue;
   1364         }
   1365         if (pRange->errorsFirst > pRange->errorsLast) {
   1366             client->errorValue = pRange->errorsFirst;
   1367             return BadValue;
   1368         }
   1369         if (pRange->clientStarted != xFalse && pRange->clientStarted != xTrue) {
   1370             client->errorValue = pRange->clientStarted;
   1371             return BadValue;
   1372         }
   1373         if (pRange->clientDied != xFalse && pRange->clientDied != xTrue) {
   1374             client->errorValue = pRange->clientDied;
   1375             return BadValue;
   1376         }
   1377     }                           /* end for each range */
   1378     return Success;
   1379 }                               /* end RecordSanityCheckRegisterClients */
   1380 
   1381 /* This is a tactical structure used to gather information about all the sets
   1382  * (RecordSetPtr) that need to be created for an RCAP in the process of
   1383  * digesting a list of RECORDRANGEs (converting it to the internal
   1384  * representation).
   1385  */
   1386 typedef struct {
   1387     int nintervals;             /* number of intervals in following array */
   1388     RecordSetInterval *intervals;       /* array of intervals for this set */
   1389     int size;                   /* size of intervals array; >= nintervals */
   1390     int align;                  /* alignment restriction for set */
   1391     int offset;                 /* where to store set pointer rel. to start of RCAP */
   1392     short first, last;          /* if for extension, major opcode interval */
   1393 } SetInfoRec, *SetInfoPtr;
   1394 
   1395 #if defined(ERR) && defined(__sun)
   1396 #undef ERR /* Avoid conflict with Solaris <sys/regset.h> */
   1397 #endif
   1398 
   1399 /* These constant are used to index into an array of SetInfoRec. */
   1400 enum { REQ,                     /* set info for requests */
   1401     REP,                        /* set info for replies */
   1402     ERR,                        /* set info for errors */
   1403     DEV,                        /* set info for device events */
   1404     DLEV,                       /* set info for delivered events */
   1405     PREDEFSETS
   1406 };                              /* number of predefined array entries */
   1407 
   1408 /* RecordAllocIntervals
   1409  *
   1410  * Arguments:
   1411  *	psi is a pointer to a SetInfoRec whose intervals pointer is NULL.
   1412  *	nIntervals is the desired size of the intervals array.
   1413  *
   1414  * Returns: BadAlloc if a memory allocation error occurred, else Success.
   1415  *
   1416  * Side Effects:
   1417  *	If Success is returned, psi->intervals is a pointer to size
   1418  *	RecordSetIntervals, all zeroed, and psi->size is set to size.
   1419  */
   1420 static int
   1421 RecordAllocIntervals(SetInfoPtr psi, int nIntervals)
   1422 {
   1423     assert(!psi->intervals);
   1424     psi->intervals = xallocarray(nIntervals, sizeof(RecordSetInterval));
   1425     if (!psi->intervals)
   1426         return BadAlloc;
   1427     memset(psi->intervals, 0, nIntervals * sizeof(RecordSetInterval));
   1428     psi->size = nIntervals;
   1429     return Success;
   1430 }                               /* end RecordAllocIntervals */
   1431 
   1432 /* RecordConvertRangesToIntervals
   1433  *
   1434  * Arguments:
   1435  *	psi is a pointer to the SetInfoRec we are building.
   1436  *	pRanges is an array of xRecordRanges.
   1437  *	nRanges is the number of elements in pRanges.
   1438  *	byteoffset is the offset from the start of an xRecordRange of the
   1439  *	  two bytes (1 for first, 1 for last) we are interested in.
   1440  *	pExtSetInfo, if non-NULL, indicates that the two bytes mentioned
   1441  *	  above are followed by four bytes (2 for first, 2 for last)
   1442  *	  representing a minor opcode range, and this information should be
   1443  *	  stored in one of the SetInfoRecs starting at pExtSetInfo.
   1444  *	pnExtSetInfo is the number of elements in the pExtSetInfo array.
   1445  *
   1446  * Returns:  BadAlloc if a memory allocation error occurred, else Success.
   1447  *
   1448  * Side Effects:
   1449  *	The slice of pRanges indicated by byteoffset is stored in psi.
   1450  *	If pExtSetInfo is non-NULL, minor opcode intervals are stored
   1451  *	in an existing SetInfoRec if the major opcode interval matches, else
   1452  *	they are stored in a new SetInfoRec, and *pnExtSetInfo is
   1453  *	increased accordingly.
   1454  */
   1455 static int
   1456 RecordConvertRangesToIntervals(SetInfoPtr psi,
   1457                                xRecordRange * pRanges,
   1458                                int nRanges,
   1459                                int byteoffset,
   1460                                SetInfoPtr pExtSetInfo, int *pnExtSetInfo)
   1461 {
   1462     int i;
   1463     CARD8 *pCARD8;
   1464     int first, last;
   1465     int err;
   1466 
   1467     for (i = 0; i < nRanges; i++, pRanges++) {
   1468         pCARD8 = ((CARD8 *) pRanges) + byteoffset;
   1469         first = pCARD8[0];
   1470         last = pCARD8[1];
   1471         if (first || last) {
   1472             if (!psi->intervals) {
   1473                 err = RecordAllocIntervals(psi, 2 * (nRanges - i));
   1474                 if (err != Success)
   1475                     return err;
   1476             }
   1477             psi->intervals[psi->nintervals].first = first;
   1478             psi->intervals[psi->nintervals].last = last;
   1479             psi->nintervals++;
   1480             assert(psi->nintervals <= psi->size);
   1481             if (pExtSetInfo) {
   1482                 SetInfoPtr pesi = pExtSetInfo;
   1483                 CARD16 *pCARD16 = (CARD16 *) (pCARD8 + 2);
   1484                 int j;
   1485 
   1486                 for (j = 0; j < *pnExtSetInfo; j++, pesi++) {
   1487                     if ((first == pesi->first) && (last == pesi->last))
   1488                         break;
   1489                 }
   1490                 if (j == *pnExtSetInfo) {
   1491                     err = RecordAllocIntervals(pesi, 2 * (nRanges - i));
   1492                     if (err != Success)
   1493                         return err;
   1494                     pesi->first = first;
   1495                     pesi->last = last;
   1496                     (*pnExtSetInfo)++;
   1497                 }
   1498                 pesi->intervals[pesi->nintervals].first = pCARD16[0];
   1499                 pesi->intervals[pesi->nintervals].last = pCARD16[1];
   1500                 pesi->nintervals++;
   1501                 assert(pesi->nintervals <= pesi->size);
   1502             }
   1503         }
   1504     }
   1505     return Success;
   1506 }                               /* end RecordConvertRangesToIntervals */
   1507 
   1508 #define offset_of(_structure, _field) \
   1509     ((char *)(& (_structure . _field)) - (char *)(&_structure))
   1510 
   1511 /* RecordRegisterClients
   1512  *
   1513  * Arguments:
   1514  *	pContext is the context on which to register the clients.
   1515  *	client is the client that issued the RecordCreateContext or
   1516  *	  RecordRegisterClients request.
   1517  *	stuff is a pointer to the request.
   1518  *
   1519  * Returns:
   1520  *	Any one of several possible error values defined by the protocol.
   1521  *	Success if everything is OK.
   1522  *
   1523  * Side Effects:
   1524  *	If different element headers are specified, the context is flushed.
   1525  *	If any of the specified clients are already registered on the
   1526  *	context, they are first unregistered.  A new RCAP is created to
   1527  *	hold the specified protocol and clients, and it is linked onto the
   1528  *	context.  If the context is enabled, appropriate hooks are installed
   1529  *	to record the new clients and protocol.
   1530  */
   1531 static int
   1532 RecordRegisterClients(RecordContextPtr pContext, ClientPtr client,
   1533                       xRecordRegisterClientsReq * stuff)
   1534 {
   1535     int err;
   1536     int i;
   1537     SetInfoPtr si;
   1538     int maxSets;
   1539     int nExtReqSets = 0;
   1540     int nExtRepSets = 0;
   1541     int extReqSetsOffset = 0;
   1542     int extRepSetsOffset = 0;
   1543     SetInfoPtr pExtReqSets, pExtRepSets;
   1544     int clientListOffset;
   1545     XID *pCanonClients;
   1546     int clientStarted = 0, clientDied = 0;
   1547     xRecordRange *pRanges, rr;
   1548     int nClients;
   1549     int sizeClients;
   1550     int totRCAPsize;
   1551     RecordClientsAndProtocolPtr pRCAP;
   1552     int pad;
   1553     XID recordingClient;
   1554 
   1555     /* do all sanity checking up front */
   1556 
   1557     err = RecordSanityCheckRegisterClients(pContext, client, stuff);
   1558     if (err != Success)
   1559         return err;
   1560 
   1561     /* if element headers changed, flush buffer */
   1562 
   1563     if (pContext->elemHeaders != stuff->elementHeader) {
   1564         RecordFlushReplyBuffer(pContext, NULL, 0, NULL, 0);
   1565         pContext->elemHeaders = stuff->elementHeader;
   1566     }
   1567 
   1568     nClients = stuff->nClients;
   1569     if (!nClients)
   1570         /* if empty clients list, we're done. */
   1571         return Success;
   1572 
   1573     recordingClient = pContext->pRecordingClient ?
   1574         pContext->pRecordingClient->clientAsMask : 0;
   1575     pCanonClients = RecordCanonicalizeClientSpecifiers((XID *) &stuff[1],
   1576                                                        &nClients,
   1577                                                        recordingClient);
   1578     if (!pCanonClients)
   1579         return BadAlloc;
   1580 
   1581     /* We may have to create as many as one set for each "predefined"
   1582      * protocol types, plus one per range for extension requests, plus one per
   1583      * range for extension replies.
   1584      */
   1585     maxSets = PREDEFSETS + 2 * stuff->nRanges;
   1586     si = xallocarray(maxSets, sizeof(SetInfoRec));
   1587     if (!si) {
   1588         err = BadAlloc;
   1589         goto bailout;
   1590     }
   1591     memset(si, 0, sizeof(SetInfoRec) * maxSets);
   1592 
   1593     /* theoretically you must do this because NULL may not be all-bits-zero */
   1594     for (i = 0; i < maxSets; i++)
   1595         si[i].intervals = NULL;
   1596 
   1597     pExtReqSets = si + PREDEFSETS;
   1598     pExtRepSets = pExtReqSets + stuff->nRanges;
   1599 
   1600     pRanges = (xRecordRange *) (((XID *) &stuff[1]) + stuff->nClients);
   1601 
   1602     err = RecordConvertRangesToIntervals(&si[REQ], pRanges, stuff->nRanges,
   1603                                          offset_of(rr, coreRequestsFirst), NULL,
   1604                                          NULL);
   1605     if (err != Success)
   1606         goto bailout;
   1607 
   1608     err = RecordConvertRangesToIntervals(&si[REQ], pRanges, stuff->nRanges,
   1609                                          offset_of(rr, extRequestsMajorFirst),
   1610                                          pExtReqSets, &nExtReqSets);
   1611     if (err != Success)
   1612         goto bailout;
   1613 
   1614     err = RecordConvertRangesToIntervals(&si[REP], pRanges, stuff->nRanges,
   1615                                          offset_of(rr, coreRepliesFirst), NULL,
   1616                                          NULL);
   1617     if (err != Success)
   1618         goto bailout;
   1619 
   1620     err = RecordConvertRangesToIntervals(&si[REP], pRanges, stuff->nRanges,
   1621                                          offset_of(rr, extRepliesMajorFirst),
   1622                                          pExtRepSets, &nExtRepSets);
   1623     if (err != Success)
   1624         goto bailout;
   1625 
   1626     err = RecordConvertRangesToIntervals(&si[ERR], pRanges, stuff->nRanges,
   1627                                          offset_of(rr, errorsFirst), NULL,
   1628                                          NULL);
   1629     if (err != Success)
   1630         goto bailout;
   1631 
   1632     err = RecordConvertRangesToIntervals(&si[DLEV], pRanges, stuff->nRanges,
   1633                                          offset_of(rr, deliveredEventsFirst),
   1634                                          NULL, NULL);
   1635     if (err != Success)
   1636         goto bailout;
   1637 
   1638     err = RecordConvertRangesToIntervals(&si[DEV], pRanges, stuff->nRanges,
   1639                                          offset_of(rr, deviceEventsFirst), NULL,
   1640                                          NULL);
   1641     if (err != Success)
   1642         goto bailout;
   1643 
   1644     /* collect client-started and client-died */
   1645 
   1646     for (i = 0; i < stuff->nRanges; i++) {
   1647         if (pRanges[i].clientStarted)
   1648             clientStarted = TRUE;
   1649         if (pRanges[i].clientDied)
   1650             clientDied = TRUE;
   1651     }
   1652 
   1653     /*  We now have all the information collected to create all the sets,
   1654      * and we can compute the total memory required for the RCAP.
   1655      */
   1656 
   1657     totRCAPsize = sizeof(RecordClientsAndProtocolRec);
   1658 
   1659     /* leave a little room to grow before forcing a separate allocation */
   1660     sizeClients = nClients + CLIENT_ARRAY_GROWTH_INCREMENT;
   1661     pad = RecordPadAlign(totRCAPsize, sizeof(XID));
   1662     clientListOffset = totRCAPsize + pad;
   1663     totRCAPsize += pad + sizeClients * sizeof(XID);
   1664 
   1665     if (nExtReqSets) {
   1666         pad = RecordPadAlign(totRCAPsize, sizeof(RecordSetPtr));
   1667         extReqSetsOffset = totRCAPsize + pad;
   1668         totRCAPsize += pad + (nExtReqSets + 1) * sizeof(RecordMinorOpRec);
   1669     }
   1670     if (nExtRepSets) {
   1671         pad = RecordPadAlign(totRCAPsize, sizeof(RecordSetPtr));
   1672         extRepSetsOffset = totRCAPsize + pad;
   1673         totRCAPsize += pad + (nExtRepSets + 1) * sizeof(RecordMinorOpRec);
   1674     }
   1675 
   1676     for (i = 0; i < maxSets; i++) {
   1677         if (si[i].nintervals) {
   1678             si[i].size =
   1679                 RecordSetMemoryRequirements(si[i].intervals, si[i].nintervals,
   1680                                             &si[i].align);
   1681             pad = RecordPadAlign(totRCAPsize, si[i].align);
   1682             si[i].offset = pad + totRCAPsize;
   1683             totRCAPsize += pad + si[i].size;
   1684         }
   1685     }
   1686 
   1687     /* allocate memory for the whole RCAP */
   1688 
   1689     pRCAP = (RecordClientsAndProtocolPtr) malloc(totRCAPsize);
   1690     if (!pRCAP) {
   1691         err = BadAlloc;
   1692         goto bailout;
   1693     }
   1694 
   1695     /* fill in the RCAP */
   1696 
   1697     pRCAP->pContext = pContext;
   1698     pRCAP->pClientIDs = (XID *) ((char *) pRCAP + clientListOffset);
   1699     pRCAP->numClients = nClients;
   1700     pRCAP->sizeClients = sizeClients;
   1701     pRCAP->clientIDsSeparatelyAllocated = 0;
   1702     for (i = 0; i < nClients; i++) {
   1703         RecordDeleteClientFromContext(pContext, pCanonClients[i]);
   1704         pRCAP->pClientIDs[i] = pCanonClients[i];
   1705     }
   1706 
   1707     /* create all the sets */
   1708 
   1709     if (si[REQ].intervals) {
   1710         pRCAP->pRequestMajorOpSet =
   1711             RecordCreateSet(si[REQ].intervals, si[REQ].nintervals,
   1712                             (RecordSetPtr) ((char *) pRCAP + si[REQ].offset),
   1713                             si[REQ].size);
   1714     }
   1715     else
   1716         pRCAP->pRequestMajorOpSet = NULL;
   1717 
   1718     if (si[REP].intervals) {
   1719         pRCAP->pReplyMajorOpSet =
   1720             RecordCreateSet(si[REP].intervals, si[REP].nintervals,
   1721                             (RecordSetPtr) ((char *) pRCAP + si[REP].offset),
   1722                             si[REP].size);
   1723     }
   1724     else
   1725         pRCAP->pReplyMajorOpSet = NULL;
   1726 
   1727     if (si[ERR].intervals) {
   1728         pRCAP->pErrorSet =
   1729             RecordCreateSet(si[ERR].intervals, si[ERR].nintervals,
   1730                             (RecordSetPtr) ((char *) pRCAP + si[ERR].offset),
   1731                             si[ERR].size);
   1732     }
   1733     else
   1734         pRCAP->pErrorSet = NULL;
   1735 
   1736     if (si[DEV].intervals) {
   1737         pRCAP->pDeviceEventSet =
   1738             RecordCreateSet(si[DEV].intervals, si[DEV].nintervals,
   1739                             (RecordSetPtr) ((char *) pRCAP + si[DEV].offset),
   1740                             si[DEV].size);
   1741     }
   1742     else
   1743         pRCAP->pDeviceEventSet = NULL;
   1744 
   1745     if (si[DLEV].intervals) {
   1746         pRCAP->pDeliveredEventSet =
   1747             RecordCreateSet(si[DLEV].intervals, si[DLEV].nintervals,
   1748                             (RecordSetPtr) ((char *) pRCAP + si[DLEV].offset),
   1749                             si[DLEV].size);
   1750     }
   1751     else
   1752         pRCAP->pDeliveredEventSet = NULL;
   1753 
   1754     if (nExtReqSets) {
   1755         pRCAP->pRequestMinOpInfo = (RecordMinorOpPtr)
   1756             ((char *) pRCAP + extReqSetsOffset);
   1757         pRCAP->pRequestMinOpInfo[0].count = nExtReqSets;
   1758         for (i = 0; i < nExtReqSets; i++, pExtReqSets++) {
   1759             pRCAP->pRequestMinOpInfo[i + 1].major.first = pExtReqSets->first;
   1760             pRCAP->pRequestMinOpInfo[i + 1].major.last = pExtReqSets->last;
   1761             pRCAP->pRequestMinOpInfo[i + 1].major.pMinOpSet =
   1762                 RecordCreateSet(pExtReqSets->intervals,
   1763                                 pExtReqSets->nintervals,
   1764                                 (RecordSetPtr) ((char *) pRCAP +
   1765                                                 pExtReqSets->offset),
   1766                                 pExtReqSets->size);
   1767         }
   1768     }
   1769     else
   1770         pRCAP->pRequestMinOpInfo = NULL;
   1771 
   1772     if (nExtRepSets) {
   1773         pRCAP->pReplyMinOpInfo = (RecordMinorOpPtr)
   1774             ((char *) pRCAP + extRepSetsOffset);
   1775         pRCAP->pReplyMinOpInfo[0].count = nExtRepSets;
   1776         for (i = 0; i < nExtRepSets; i++, pExtRepSets++) {
   1777             pRCAP->pReplyMinOpInfo[i + 1].major.first = pExtRepSets->first;
   1778             pRCAP->pReplyMinOpInfo[i + 1].major.last = pExtRepSets->last;
   1779             pRCAP->pReplyMinOpInfo[i + 1].major.pMinOpSet =
   1780                 RecordCreateSet(pExtRepSets->intervals,
   1781                                 pExtRepSets->nintervals,
   1782                                 (RecordSetPtr) ((char *) pRCAP +
   1783                                                 pExtRepSets->offset),
   1784                                 pExtRepSets->size);
   1785         }
   1786     }
   1787     else
   1788         pRCAP->pReplyMinOpInfo = NULL;
   1789 
   1790     pRCAP->clientStarted = clientStarted;
   1791     pRCAP->clientDied = clientDied;
   1792 
   1793     /* link the RCAP onto the context */
   1794 
   1795     pRCAP->pNextRCAP = pContext->pListOfRCAP;
   1796     pContext->pListOfRCAP = pRCAP;
   1797 
   1798     if (pContext->pRecordingClient)     /* context enabled */
   1799         RecordInstallHooks(pRCAP, 0);
   1800 
   1801  bailout:
   1802     if (si) {
   1803         for (i = 0; i < maxSets; i++)
   1804             free(si[i].intervals);
   1805         free(si);
   1806     }
   1807     if (pCanonClients && pCanonClients != (XID *) &stuff[1])
   1808         free(pCanonClients);
   1809     return err;
   1810 }                               /* RecordRegisterClients */
   1811 
   1812 /* Proc functions all take a client argument, execute the request in
   1813  * client->requestBuffer, and return a protocol error status.
   1814  */
   1815 
   1816 static int
   1817 ProcRecordQueryVersion(ClientPtr client)
   1818 {
   1819     /* REQUEST(xRecordQueryVersionReq); */
   1820     xRecordQueryVersionReply rep = {
   1821         .type = X_Reply,
   1822         .sequenceNumber = client->sequence,
   1823         .length = 0,
   1824         .majorVersion = SERVER_RECORD_MAJOR_VERSION,
   1825         .minorVersion = SERVER_RECORD_MINOR_VERSION
   1826     };
   1827 
   1828     REQUEST_SIZE_MATCH(xRecordQueryVersionReq);
   1829     if (client->swapped) {
   1830         swaps(&rep.sequenceNumber);
   1831         swaps(&rep.majorVersion);
   1832         swaps(&rep.minorVersion);
   1833     }
   1834     WriteToClient(client, sizeof(xRecordQueryVersionReply), &rep);
   1835     return Success;
   1836 }                               /* ProcRecordQueryVersion */
   1837 
   1838 static int
   1839 ProcRecordCreateContext(ClientPtr client)
   1840 {
   1841     REQUEST(xRecordCreateContextReq);
   1842     RecordContextPtr pContext;
   1843     RecordContextPtr *ppNewAllContexts = NULL;
   1844     int err = BadAlloc;
   1845 
   1846     REQUEST_AT_LEAST_SIZE(xRecordCreateContextReq);
   1847     LEGAL_NEW_RESOURCE(stuff->context, client);
   1848 
   1849     pContext = (RecordContextPtr) malloc(sizeof(RecordContextRec));
   1850     if (!pContext)
   1851         goto bailout;
   1852 
   1853     /* make sure there is room in ppAllContexts to store the new context */
   1854 
   1855     ppNewAllContexts =
   1856         reallocarray(ppAllContexts, numContexts + 1, sizeof(RecordContextPtr));
   1857     if (!ppNewAllContexts)
   1858         goto bailout;
   1859     ppAllContexts = ppNewAllContexts;
   1860 
   1861     pContext->id = stuff->context;
   1862     pContext->pRecordingClient = NULL;
   1863     pContext->pListOfRCAP = NULL;
   1864     pContext->elemHeaders = 0;
   1865     pContext->bufCategory = 0;
   1866     pContext->numBufBytes = 0;
   1867     pContext->pBufClient = NULL;
   1868     pContext->continuedReply = 0;
   1869     pContext->inFlush = 0;
   1870 
   1871     err = RecordRegisterClients(pContext, client,
   1872                                 (xRecordRegisterClientsReq *) stuff);
   1873     if (err != Success)
   1874         goto bailout;
   1875 
   1876     if (AddResource(pContext->id, RTContext, pContext)) {
   1877         ppAllContexts[numContexts++] = pContext;
   1878         return Success;
   1879     }
   1880     else {
   1881         return BadAlloc;
   1882     }
   1883  bailout:
   1884     free(pContext);
   1885     return err;
   1886 }                               /* ProcRecordCreateContext */
   1887 
   1888 static int
   1889 ProcRecordRegisterClients(ClientPtr client)
   1890 {
   1891     RecordContextPtr pContext;
   1892 
   1893     REQUEST(xRecordRegisterClientsReq);
   1894 
   1895     REQUEST_AT_LEAST_SIZE(xRecordRegisterClientsReq);
   1896     VERIFY_CONTEXT(pContext, stuff->context, client);
   1897 
   1898     return RecordRegisterClients(pContext, client, stuff);
   1899 }                               /* ProcRecordRegisterClients */
   1900 
   1901 static int
   1902 ProcRecordUnregisterClients(ClientPtr client)
   1903 {
   1904     RecordContextPtr pContext;
   1905     int err;
   1906 
   1907     REQUEST(xRecordUnregisterClientsReq);
   1908     XID *pCanonClients;
   1909     int nClients;
   1910     int i;
   1911 
   1912     REQUEST_AT_LEAST_SIZE(xRecordUnregisterClientsReq);
   1913     if (INT_MAX / 4 < stuff->nClients ||
   1914         (client->req_len << 2) - SIZEOF(xRecordUnregisterClientsReq) !=
   1915         4 * stuff->nClients)
   1916         return BadLength;
   1917     VERIFY_CONTEXT(pContext, stuff->context, client);
   1918     err = RecordSanityCheckClientSpecifiers(client, (XID *) &stuff[1],
   1919                                             stuff->nClients, 0);
   1920     if (err != Success)
   1921         return err;
   1922 
   1923     nClients = stuff->nClients;
   1924     pCanonClients = RecordCanonicalizeClientSpecifiers((XID *) &stuff[1],
   1925                                                        &nClients, 0);
   1926     if (!pCanonClients)
   1927         return BadAlloc;
   1928 
   1929     for (i = 0; i < nClients; i++) {
   1930         RecordDeleteClientFromContext(pContext, pCanonClients[i]);
   1931     }
   1932     if (pCanonClients != (XID *) &stuff[1])
   1933         free(pCanonClients);
   1934     return Success;
   1935 }                               /* ProcRecordUnregisterClients */
   1936 
   1937 /****************************************************************************/
   1938 
   1939 /* stuff for GetContext */
   1940 
   1941 /* This is a tactical structure used to hold the xRecordRanges as they are
   1942  * being reconstituted from the sets in the RCAPs.
   1943  */
   1944 
   1945 typedef struct {
   1946     xRecordRange *pRanges;      /* array of xRecordRanges for one RCAP */
   1947     int size;                   /* number of elements in pRanges, >= nRanges */
   1948     int nRanges;                /* number of occupied element of pRanges */
   1949 } GetContextRangeInfoRec, *GetContextRangeInfoPtr;
   1950 
   1951 /* RecordAllocRanges
   1952  *
   1953  * Arguments:
   1954  *	pri is a pointer to a GetContextRangeInfoRec to allocate for.
   1955  *	nRanges is the number of xRecordRanges desired for pri.
   1956  *
   1957  * Returns: BadAlloc if a memory allocation error occurred, else Success.
   1958  *
   1959  * Side Effects:
   1960  *	If Success is returned, pri->pRanges points to at least nRanges
   1961  *	ranges.  pri->nRanges is set to nRanges.  pri->size is the actual
   1962  *	number of ranges.  Newly allocated ranges are zeroed.
   1963  */
   1964 static int
   1965 RecordAllocRanges(GetContextRangeInfoPtr pri, int nRanges)
   1966 {
   1967     int newsize;
   1968     xRecordRange *pNewRange;
   1969 
   1970 #define SZINCR 8
   1971 
   1972     newsize = max(pri->size + SZINCR, nRanges);
   1973     pNewRange = reallocarray(pri->pRanges, newsize, sizeof(xRecordRange));
   1974     if (!pNewRange)
   1975         return BadAlloc;
   1976 
   1977     pri->pRanges = pNewRange;
   1978     pri->size = newsize;
   1979     memset(&pri->pRanges[pri->size - SZINCR], 0, SZINCR * sizeof(xRecordRange));
   1980     if (pri->nRanges < nRanges)
   1981         pri->nRanges = nRanges;
   1982     return Success;
   1983 }                               /* RecordAllocRanges */
   1984 
   1985 /* RecordConvertSetToRanges
   1986  *
   1987  * Arguments:
   1988  *	pSet is the set to be converted.
   1989  *	pri is where the result should be stored.
   1990  *	byteoffset is the offset from the start of an xRecordRange of the
   1991  *	  two vales (first, last) we are interested in.
   1992  *	card8 is TRUE if the vales are one byte each and FALSE if two bytes
   1993  *	  each.
   1994  *	imax is the largest set value to store in pri->pRanges.
   1995  *	pStartIndex, if non-NULL, is the index of the first range in
   1996  *	  pri->pRanges that should be stored to.  If NULL,
   1997  *	  start at index 0.
   1998  *
   1999  * Returns: BadAlloc if a memory allocation error occurred, else Success.
   2000  *
   2001  * Side Effects:
   2002  *	If Success is returned, the slice of pri->pRanges indicated by
   2003  *	byteoffset and card8 is filled in with the intervals from pSet.
   2004  *	if pStartIndex was non-NULL, *pStartIndex is filled in with one
   2005  *	more than the index of the last xRecordRange that was touched.
   2006  */
   2007 static int
   2008 RecordConvertSetToRanges(RecordSetPtr pSet,
   2009                          GetContextRangeInfoPtr pri,
   2010                          int byteoffset,
   2011                          Bool card8, unsigned int imax, int *pStartIndex)
   2012 {
   2013     int nRanges;
   2014     RecordSetIteratePtr pIter = NULL;
   2015     RecordSetInterval interval;
   2016     CARD8 *pCARD8;
   2017     CARD16 *pCARD16;
   2018     int err;
   2019 
   2020     if (!pSet)
   2021         return Success;
   2022 
   2023     nRanges = pStartIndex ? *pStartIndex : 0;
   2024     while ((pIter = RecordIterateSet(pSet, pIter, &interval))) {
   2025         if (interval.first > imax)
   2026             break;
   2027         if (interval.last > imax)
   2028             interval.last = imax;
   2029         nRanges++;
   2030         if (nRanges > pri->size) {
   2031             err = RecordAllocRanges(pri, nRanges);
   2032             if (err != Success)
   2033                 return err;
   2034         }
   2035         else
   2036             pri->nRanges = max(pri->nRanges, nRanges);
   2037         if (card8) {
   2038             pCARD8 = ((CARD8 *) &pri->pRanges[nRanges - 1]) + byteoffset;
   2039             *pCARD8++ = interval.first;
   2040             *pCARD8 = interval.last;
   2041         }
   2042         else {
   2043             pCARD16 = (CARD16 *)
   2044                 (((char *) &pri->pRanges[nRanges - 1]) + byteoffset);
   2045             *pCARD16++ = interval.first;
   2046             *pCARD16 = interval.last;
   2047         }
   2048     }
   2049     if (pStartIndex)
   2050         *pStartIndex = nRanges;
   2051     return Success;
   2052 }                               /* RecordConvertSetToRanges */
   2053 
   2054 /* RecordConvertMinorOpInfoToRanges
   2055  *
   2056  * Arguments:
   2057  *	pMinOpInfo is the minor opcode info to convert to xRecordRanges.
   2058  *	pri is where the result should be stored.
   2059  *	byteoffset is the offset from the start of an xRecordRange of the
   2060  *	  four vales (CARD8 major_first, CARD8 major_last,
   2061  *	  CARD16 minor_first, CARD16 minor_last) we are going to store.
   2062  *
   2063  * Returns: BadAlloc if a memory allocation error occurred, else Success.
   2064  *
   2065  * Side Effects:
   2066  *	If Success is returned, the slice of pri->pRanges indicated by
   2067  *	byteoffset is filled in with the information from pMinOpInfo.
   2068  */
   2069 static int
   2070 RecordConvertMinorOpInfoToRanges(RecordMinorOpPtr pMinOpInfo,
   2071                                  GetContextRangeInfoPtr pri, int byteoffset)
   2072 {
   2073     int nsets;
   2074     int start;
   2075     int i;
   2076     int err;
   2077 
   2078     if (!pMinOpInfo)
   2079         return Success;
   2080 
   2081     nsets = pMinOpInfo->count;
   2082     pMinOpInfo++;
   2083     start = 0;
   2084     for (i = 0; i < nsets; i++) {
   2085         int j, s;
   2086 
   2087         s = start;
   2088         err = RecordConvertSetToRanges(pMinOpInfo[i].major.pMinOpSet, pri,
   2089                                        byteoffset + 2, FALSE, 65535, &start);
   2090         if (err != Success)
   2091             return err;
   2092         for (j = s; j < start; j++) {
   2093             CARD8 *pCARD8 = ((CARD8 *) &pri->pRanges[j]) + byteoffset;
   2094 
   2095             *pCARD8++ = pMinOpInfo[i].major.first;
   2096             *pCARD8 = pMinOpInfo[i].major.last;
   2097         }
   2098     }
   2099     return Success;
   2100 }                               /* RecordConvertMinorOpInfoToRanges */
   2101 
   2102 /* RecordSwapRanges
   2103  *
   2104  * Arguments:
   2105  *	pRanges is an array of xRecordRanges.
   2106  *	nRanges is the number of elements in pRanges.
   2107  *
   2108  * Returns: nothing.
   2109  *
   2110  * Side Effects:
   2111  *	The 16 bit fields of each xRecordRange are byte swapped.
   2112  */
   2113 static void
   2114 RecordSwapRanges(xRecordRange * pRanges, int nRanges)
   2115 {
   2116     int i;
   2117 
   2118     for (i = 0; i < nRanges; i++, pRanges++) {
   2119         swaps(&pRanges->extRequestsMinorFirst);
   2120         swaps(&pRanges->extRequestsMinorLast);
   2121         swaps(&pRanges->extRepliesMinorFirst);
   2122         swaps(&pRanges->extRepliesMinorLast);
   2123     }
   2124 }                               /* RecordSwapRanges */
   2125 
   2126 static int
   2127 ProcRecordGetContext(ClientPtr client)
   2128 {
   2129     RecordContextPtr pContext;
   2130 
   2131     REQUEST(xRecordGetContextReq);
   2132     xRecordGetContextReply rep;
   2133     RecordClientsAndProtocolPtr pRCAP;
   2134     int nRCAPs = 0;
   2135     GetContextRangeInfoPtr pRangeInfo;
   2136     GetContextRangeInfoPtr pri;
   2137     int i;
   2138     int err;
   2139     CARD32 nClients, length;
   2140 
   2141     REQUEST_SIZE_MATCH(xRecordGetContextReq);
   2142     VERIFY_CONTEXT(pContext, stuff->context, client);
   2143 
   2144     /* how many RCAPs are there on this context? */
   2145 
   2146     for (pRCAP = pContext->pListOfRCAP; pRCAP; pRCAP = pRCAP->pNextRCAP)
   2147         nRCAPs++;
   2148 
   2149     /* allocate and initialize space for record range info */
   2150 
   2151     pRangeInfo = xallocarray(nRCAPs, sizeof(GetContextRangeInfoRec));
   2152     if (!pRangeInfo && nRCAPs > 0)
   2153         return BadAlloc;
   2154     for (i = 0; i < nRCAPs; i++) {
   2155         pRangeInfo[i].pRanges = NULL;
   2156         pRangeInfo[i].size = 0;
   2157         pRangeInfo[i].nRanges = 0;
   2158     }
   2159 
   2160     /* convert the RCAP (internal) representation of the recorded protocol
   2161      * to the wire protocol (external) representation, storing the information
   2162      * for the ith RCAP in pri[i]
   2163      */
   2164 
   2165     for (pRCAP = pContext->pListOfRCAP, pri = pRangeInfo;
   2166          pRCAP; pRCAP = pRCAP->pNextRCAP, pri++) {
   2167         xRecordRange rr;
   2168 
   2169         err = RecordConvertSetToRanges(pRCAP->pRequestMajorOpSet, pri,
   2170                                        offset_of(rr, coreRequestsFirst), TRUE,
   2171                                        127, NULL);
   2172         if (err != Success)
   2173             goto bailout;
   2174 
   2175         err = RecordConvertSetToRanges(pRCAP->pReplyMajorOpSet, pri,
   2176                                        offset_of(rr, coreRepliesFirst), TRUE,
   2177                                        127, NULL);
   2178         if (err != Success)
   2179             goto bailout;
   2180 
   2181         err = RecordConvertSetToRanges(pRCAP->pDeliveredEventSet, pri,
   2182                                        offset_of(rr, deliveredEventsFirst),
   2183                                        TRUE, 255, NULL);
   2184         if (err != Success)
   2185             goto bailout;
   2186 
   2187         err = RecordConvertSetToRanges(pRCAP->pDeviceEventSet, pri,
   2188                                        offset_of(rr, deviceEventsFirst), TRUE,
   2189                                        255, NULL);
   2190         if (err != Success)
   2191             goto bailout;
   2192 
   2193         err = RecordConvertSetToRanges(pRCAP->pErrorSet, pri,
   2194                                        offset_of(rr, errorsFirst), TRUE, 255,
   2195                                        NULL);
   2196         if (err != Success)
   2197             goto bailout;
   2198 
   2199         err = RecordConvertMinorOpInfoToRanges(pRCAP->pRequestMinOpInfo,
   2200                                                pri, offset_of(rr,
   2201                                                               extRequestsMajorFirst));
   2202         if (err != Success)
   2203             goto bailout;
   2204 
   2205         err = RecordConvertMinorOpInfoToRanges(pRCAP->pReplyMinOpInfo,
   2206                                                pri, offset_of(rr,
   2207                                                               extRepliesMajorFirst));
   2208         if (err != Success)
   2209             goto bailout;
   2210 
   2211         if (pRCAP->clientStarted || pRCAP->clientDied) {
   2212             if (pri->nRanges == 0)
   2213                 RecordAllocRanges(pri, 1);
   2214             pri->pRanges[0].clientStarted = pRCAP->clientStarted;
   2215             pri->pRanges[0].clientDied = pRCAP->clientDied;
   2216         }
   2217     }
   2218 
   2219     /* calculate number of clients and reply length */
   2220 
   2221     nClients = 0;
   2222     length = 0;
   2223     for (pRCAP = pContext->pListOfRCAP, pri = pRangeInfo;
   2224          pRCAP; pRCAP = pRCAP->pNextRCAP, pri++) {
   2225         nClients += pRCAP->numClients;
   2226         length += pRCAP->numClients *
   2227             (bytes_to_int32(sizeof(xRecordClientInfo)) +
   2228              pri->nRanges * bytes_to_int32(sizeof(xRecordRange)));
   2229     }
   2230 
   2231     /* write the reply header */
   2232 
   2233     rep = (xRecordGetContextReply) {
   2234         .type = X_Reply,
   2235         .enabled = pContext->pRecordingClient != NULL,
   2236         .sequenceNumber = client->sequence,
   2237         .length = length,
   2238         .elementHeader = pContext->elemHeaders,
   2239         .nClients = nClients
   2240     };
   2241     if (client->swapped) {
   2242         swaps(&rep.sequenceNumber);
   2243         swapl(&rep.length);
   2244         swapl(&rep.nClients);
   2245     }
   2246     WriteToClient(client, sizeof(xRecordGetContextReply), &rep);
   2247 
   2248     /* write all the CLIENT_INFOs */
   2249 
   2250     for (pRCAP = pContext->pListOfRCAP, pri = pRangeInfo;
   2251          pRCAP; pRCAP = pRCAP->pNextRCAP, pri++) {
   2252         xRecordClientInfo rci;
   2253 
   2254         rci.nRanges = pri->nRanges;
   2255         if (client->swapped) {
   2256             swapl(&rci.nRanges);
   2257             RecordSwapRanges(pri->pRanges, pri->nRanges);
   2258         }
   2259         for (i = 0; i < pRCAP->numClients; i++) {
   2260             rci.clientResource = pRCAP->pClientIDs[i];
   2261             if (client->swapped)
   2262                 swapl(&rci.clientResource);
   2263             WriteToClient(client, sizeof(xRecordClientInfo), &rci);
   2264             WriteToClient(client, sizeof(xRecordRange) * pri->nRanges,
   2265                           pri->pRanges);
   2266         }
   2267     }
   2268     err = Success;
   2269 
   2270  bailout:
   2271     for (i = 0; i < nRCAPs; i++) {
   2272         free(pRangeInfo[i].pRanges);
   2273     }
   2274     free(pRangeInfo);
   2275     return err;
   2276 }                               /* ProcRecordGetContext */
   2277 
   2278 static int
   2279 ProcRecordEnableContext(ClientPtr client)
   2280 {
   2281     RecordContextPtr pContext;
   2282 
   2283     REQUEST(xRecordEnableContextReq);
   2284     int i;
   2285     RecordClientsAndProtocolPtr pRCAP;
   2286 
   2287     REQUEST_SIZE_MATCH(xRecordGetContextReq);
   2288     VERIFY_CONTEXT(pContext, stuff->context, client);
   2289     if (pContext->pRecordingClient)
   2290         return BadMatch;        /* already enabled */
   2291 
   2292     /* install record hooks for each RCAP */
   2293 
   2294     for (pRCAP = pContext->pListOfRCAP; pRCAP; pRCAP = pRCAP->pNextRCAP) {
   2295         int err = RecordInstallHooks(pRCAP, 0);
   2296 
   2297         if (err != Success) {   /* undo the previous installs */
   2298             RecordClientsAndProtocolPtr pUninstallRCAP;
   2299 
   2300             for (pUninstallRCAP = pContext->pListOfRCAP;
   2301                  pUninstallRCAP != pRCAP;
   2302                  pUninstallRCAP = pUninstallRCAP->pNextRCAP) {
   2303                 RecordUninstallHooks(pUninstallRCAP, 0);
   2304             }
   2305             return err;
   2306         }
   2307     }
   2308 
   2309     /* Disallow further request processing on this connection until
   2310      * the context is disabled.
   2311      */
   2312     IgnoreClient(client);
   2313     pContext->pRecordingClient = client;
   2314 
   2315     /* Don't allow the data connection to record itself; unregister it. */
   2316     RecordDeleteClientFromContext(pContext,
   2317                                   pContext->pRecordingClient->clientAsMask);
   2318 
   2319     /* move the newly enabled context to the front part of ppAllContexts,
   2320      * where all the enabled contexts are
   2321      */
   2322     i = RecordFindContextOnAllContexts(pContext);
   2323     assert(i >= numEnabledContexts);
   2324     if (i != numEnabledContexts) {
   2325         ppAllContexts[i] = ppAllContexts[numEnabledContexts];
   2326         ppAllContexts[numEnabledContexts] = pContext;
   2327     }
   2328 
   2329     ++numEnabledContexts;
   2330     assert(numEnabledContexts > 0);
   2331 
   2332     /* send StartOfData */
   2333     RecordAProtocolElement(pContext, NULL, XRecordStartOfData, NULL, 0, 0, 0);
   2334     RecordFlushReplyBuffer(pContext, NULL, 0, NULL, 0);
   2335     return Success;
   2336 }                               /* ProcRecordEnableContext */
   2337 
   2338 /* RecordDisableContext
   2339  *
   2340  * Arguments:
   2341  *	pContext is the context to disable.
   2342  *	nRanges is the number of elements in pRanges.
   2343  *
   2344  * Returns: nothing.
   2345  *
   2346  * Side Effects:
   2347  *	If the context was enabled, it is disabled.  An EndOfData
   2348  *	message is sent to the recording client.  Recording hooks for
   2349  *	this context are uninstalled.  The context is moved to the
   2350  *	rear part of the ppAllContexts array.  numEnabledContexts is
   2351  *	decremented.  Request processing for the formerly recording client
   2352  *	is resumed.
   2353  */
   2354 static void
   2355 RecordDisableContext(RecordContextPtr pContext)
   2356 {
   2357     RecordClientsAndProtocolPtr pRCAP;
   2358     int i;
   2359 
   2360     if (!pContext->pRecordingClient)
   2361         return;
   2362     if (!pContext->pRecordingClient->clientGone) {
   2363         RecordAProtocolElement(pContext, NULL, XRecordEndOfData, NULL, 0, 0, 0);
   2364         RecordFlushReplyBuffer(pContext, NULL, 0, NULL, 0);
   2365     }
   2366     /* Re-enable request processing on this connection. */
   2367     AttendClient(pContext->pRecordingClient);
   2368 
   2369     for (pRCAP = pContext->pListOfRCAP; pRCAP; pRCAP = pRCAP->pNextRCAP) {
   2370         RecordUninstallHooks(pRCAP, 0);
   2371     }
   2372 
   2373     pContext->pRecordingClient = NULL;
   2374 
   2375     /* move the newly disabled context to the rear part of ppAllContexts,
   2376      * where all the disabled contexts are
   2377      */
   2378     i = RecordFindContextOnAllContexts(pContext);
   2379     assert(i != -1);
   2380     assert(i < numEnabledContexts);
   2381     if (i != (numEnabledContexts - 1)) {
   2382         ppAllContexts[i] = ppAllContexts[numEnabledContexts - 1];
   2383         ppAllContexts[numEnabledContexts - 1] = pContext;
   2384     }
   2385     --numEnabledContexts;
   2386     assert(numEnabledContexts >= 0);
   2387 }                               /* RecordDisableContext */
   2388 
   2389 static int
   2390 ProcRecordDisableContext(ClientPtr client)
   2391 {
   2392     RecordContextPtr pContext;
   2393 
   2394     REQUEST(xRecordDisableContextReq);
   2395 
   2396     REQUEST_SIZE_MATCH(xRecordDisableContextReq);
   2397     VERIFY_CONTEXT(pContext, stuff->context, client);
   2398     RecordDisableContext(pContext);
   2399     return Success;
   2400 }                               /* ProcRecordDisableContext */
   2401 
   2402 /* RecordDeleteContext
   2403  *
   2404  * Arguments:
   2405  *	value is the context to delete.
   2406  *	id is its resource ID.
   2407  *
   2408  * Returns: Success.
   2409  *
   2410  * Side Effects:
   2411  *	Disables the context, frees all associated memory, and removes
   2412  *	it from the ppAllContexts array.
   2413  */
   2414 static int
   2415 RecordDeleteContext(void *value, XID id)
   2416 {
   2417     int i;
   2418     RecordContextPtr pContext = (RecordContextPtr) value;
   2419     RecordClientsAndProtocolPtr pRCAP;
   2420 
   2421     RecordDisableContext(pContext);
   2422 
   2423     /*  Remove all the clients from all the RCAPs.
   2424      *  As a result, the RCAPs will be freed.
   2425      */
   2426 
   2427     while ((pRCAP = pContext->pListOfRCAP)) {
   2428         int numClients = pRCAP->numClients;
   2429 
   2430         /* when the last client is deleted, the RCAP will go away. */
   2431         while (numClients--) {
   2432             RecordDeleteClientFromRCAP(pRCAP, numClients);
   2433         }
   2434     }
   2435 
   2436     /* remove context from AllContexts list */
   2437 
   2438     if (-1 != (i = RecordFindContextOnAllContexts(pContext))) {
   2439         ppAllContexts[i] = ppAllContexts[numContexts - 1];
   2440         if (--numContexts == 0) {
   2441             free(ppAllContexts);
   2442             ppAllContexts = NULL;
   2443         }
   2444     }
   2445     free(pContext);
   2446 
   2447     return Success;
   2448 }                               /* RecordDeleteContext */
   2449 
   2450 static int
   2451 ProcRecordFreeContext(ClientPtr client)
   2452 {
   2453     RecordContextPtr pContext;
   2454 
   2455     REQUEST(xRecordFreeContextReq);
   2456 
   2457     REQUEST_SIZE_MATCH(xRecordFreeContextReq);
   2458     VERIFY_CONTEXT(pContext, stuff->context, client);
   2459     FreeResource(stuff->context, RT_NONE);
   2460     return Success;
   2461 }                               /* ProcRecordFreeContext */
   2462 
   2463 static int
   2464 ProcRecordDispatch(ClientPtr client)
   2465 {
   2466     REQUEST(xReq);
   2467 
   2468     switch (stuff->data) {
   2469     case X_RecordQueryVersion:
   2470         return ProcRecordQueryVersion(client);
   2471     case X_RecordCreateContext:
   2472         return ProcRecordCreateContext(client);
   2473     case X_RecordRegisterClients:
   2474         return ProcRecordRegisterClients(client);
   2475     case X_RecordUnregisterClients:
   2476         return ProcRecordUnregisterClients(client);
   2477     case X_RecordGetContext:
   2478         return ProcRecordGetContext(client);
   2479     case X_RecordEnableContext:
   2480         return ProcRecordEnableContext(client);
   2481     case X_RecordDisableContext:
   2482         return ProcRecordDisableContext(client);
   2483     case X_RecordFreeContext:
   2484         return ProcRecordFreeContext(client);
   2485     default:
   2486         return BadRequest;
   2487     }
   2488 }                               /* ProcRecordDispatch */
   2489 
   2490 static int _X_COLD
   2491 SProcRecordQueryVersion(ClientPtr client)
   2492 {
   2493     REQUEST(xRecordQueryVersionReq);
   2494 
   2495     swaps(&stuff->length);
   2496     REQUEST_SIZE_MATCH(xRecordQueryVersionReq);
   2497     swaps(&stuff->majorVersion);
   2498     swaps(&stuff->minorVersion);
   2499     return ProcRecordQueryVersion(client);
   2500 }                               /* SProcRecordQueryVersion */
   2501 
   2502 static int _X_COLD
   2503 SwapCreateRegister(ClientPtr client, xRecordRegisterClientsReq * stuff)
   2504 {
   2505     int i;
   2506     XID *pClientID;
   2507 
   2508     swapl(&stuff->context);
   2509     swapl(&stuff->nClients);
   2510     swapl(&stuff->nRanges);
   2511     pClientID = (XID *) &stuff[1];
   2512     if (stuff->nClients >
   2513         client->req_len - bytes_to_int32(sz_xRecordRegisterClientsReq))
   2514         return BadLength;
   2515     for (i = 0; i < stuff->nClients; i++, pClientID++) {
   2516         swapl(pClientID);
   2517     }
   2518     if (stuff->nRanges >
   2519         (client->req_len - bytes_to_int32(sz_xRecordRegisterClientsReq)
   2520         - stuff->nClients) / bytes_to_int32(sz_xRecordRange))
   2521         return BadLength;
   2522     RecordSwapRanges((xRecordRange *) pClientID, stuff->nRanges);
   2523     return Success;
   2524 }                               /* SwapCreateRegister */
   2525 
   2526 static int _X_COLD
   2527 SProcRecordCreateContext(ClientPtr client)
   2528 {
   2529     REQUEST(xRecordCreateContextReq);
   2530     int status;
   2531 
   2532     swaps(&stuff->length);
   2533     REQUEST_AT_LEAST_SIZE(xRecordCreateContextReq);
   2534     if ((status = SwapCreateRegister(client, (void *) stuff)) != Success)
   2535         return status;
   2536     return ProcRecordCreateContext(client);
   2537 }                               /* SProcRecordCreateContext */
   2538 
   2539 static int _X_COLD
   2540 SProcRecordRegisterClients(ClientPtr client)
   2541 {
   2542     REQUEST(xRecordRegisterClientsReq);
   2543     int status;
   2544 
   2545     swaps(&stuff->length);
   2546     REQUEST_AT_LEAST_SIZE(xRecordRegisterClientsReq);
   2547     if ((status = SwapCreateRegister(client, (void *) stuff)) != Success)
   2548         return status;
   2549     return ProcRecordRegisterClients(client);
   2550 }                               /* SProcRecordRegisterClients */
   2551 
   2552 static int _X_COLD
   2553 SProcRecordUnregisterClients(ClientPtr client)
   2554 {
   2555     REQUEST(xRecordUnregisterClientsReq);
   2556 
   2557     swaps(&stuff->length);
   2558     REQUEST_AT_LEAST_SIZE(xRecordUnregisterClientsReq);
   2559     swapl(&stuff->context);
   2560     swapl(&stuff->nClients);
   2561     SwapRestL(stuff);
   2562     return ProcRecordUnregisterClients(client);
   2563 }                               /* SProcRecordUnregisterClients */
   2564 
   2565 static int _X_COLD
   2566 SProcRecordGetContext(ClientPtr client)
   2567 {
   2568     REQUEST(xRecordGetContextReq);
   2569 
   2570     swaps(&stuff->length);
   2571     REQUEST_SIZE_MATCH(xRecordGetContextReq);
   2572     swapl(&stuff->context);
   2573     return ProcRecordGetContext(client);
   2574 }                               /* SProcRecordGetContext */
   2575 
   2576 static int _X_COLD
   2577 SProcRecordEnableContext(ClientPtr client)
   2578 {
   2579     REQUEST(xRecordEnableContextReq);
   2580 
   2581     swaps(&stuff->length);
   2582     REQUEST_SIZE_MATCH(xRecordEnableContextReq);
   2583     swapl(&stuff->context);
   2584     return ProcRecordEnableContext(client);
   2585 }                               /* SProcRecordEnableContext */
   2586 
   2587 static int _X_COLD
   2588 SProcRecordDisableContext(ClientPtr client)
   2589 {
   2590     REQUEST(xRecordDisableContextReq);
   2591 
   2592     swaps(&stuff->length);
   2593     REQUEST_SIZE_MATCH(xRecordDisableContextReq);
   2594     swapl(&stuff->context);
   2595     return ProcRecordDisableContext(client);
   2596 }                               /* SProcRecordDisableContext */
   2597 
   2598 static int _X_COLD
   2599 SProcRecordFreeContext(ClientPtr client)
   2600 {
   2601     REQUEST(xRecordFreeContextReq);
   2602 
   2603     swaps(&stuff->length);
   2604     REQUEST_SIZE_MATCH(xRecordFreeContextReq);
   2605     swapl(&stuff->context);
   2606     return ProcRecordFreeContext(client);
   2607 }                               /* SProcRecordFreeContext */
   2608 
   2609 static int _X_COLD
   2610 SProcRecordDispatch(ClientPtr client)
   2611 {
   2612     REQUEST(xReq);
   2613 
   2614     switch (stuff->data) {
   2615     case X_RecordQueryVersion:
   2616         return SProcRecordQueryVersion(client);
   2617     case X_RecordCreateContext:
   2618         return SProcRecordCreateContext(client);
   2619     case X_RecordRegisterClients:
   2620         return SProcRecordRegisterClients(client);
   2621     case X_RecordUnregisterClients:
   2622         return SProcRecordUnregisterClients(client);
   2623     case X_RecordGetContext:
   2624         return SProcRecordGetContext(client);
   2625     case X_RecordEnableContext:
   2626         return SProcRecordEnableContext(client);
   2627     case X_RecordDisableContext:
   2628         return SProcRecordDisableContext(client);
   2629     case X_RecordFreeContext:
   2630         return SProcRecordFreeContext(client);
   2631     default:
   2632         return BadRequest;
   2633     }
   2634 }                               /* SProcRecordDispatch */
   2635 
   2636 /* RecordConnectionSetupInfo
   2637  *
   2638  * Arguments:
   2639  *	pContext is an enabled context that specifies recording of
   2640  *	  connection setup info.
   2641  *	pci holds the connection setup info.
   2642  *
   2643  * Returns: nothing.
   2644  *
   2645  * Side Effects:
   2646  *	The connection setup info is sent to the recording client.
   2647  */
   2648 static void
   2649 RecordConnectionSetupInfo(RecordContextPtr pContext, NewClientInfoRec * pci)
   2650 {
   2651     int prefixsize = SIZEOF(xConnSetupPrefix);
   2652     int restsize = pci->prefix->length * 4;
   2653 
   2654     if (pci->client->swapped) {
   2655         char *pConnSetup = (char *) malloc(prefixsize + restsize);
   2656 
   2657         if (!pConnSetup)
   2658             return;
   2659         SwapConnSetupPrefix(pci->prefix, (xConnSetupPrefix *) pConnSetup);
   2660         SwapConnSetupInfo((char *) pci->setup,
   2661                           (char *) (pConnSetup + prefixsize));
   2662         RecordAProtocolElement(pContext, pci->client, XRecordClientStarted,
   2663                                (void *) pConnSetup, prefixsize + restsize, 0,
   2664                                0);
   2665         free(pConnSetup);
   2666     }
   2667     else {
   2668         /* don't alloc and copy as in the swapped case; just send the
   2669          * data in two pieces
   2670          */
   2671         RecordAProtocolElement(pContext, pci->client, XRecordClientStarted,
   2672                                (void *) pci->prefix, prefixsize, 0, restsize);
   2673         RecordAProtocolElement(pContext, pci->client, XRecordClientStarted,
   2674                                (void *) pci->setup, restsize, 0,
   2675                                /* continuation */ -1);
   2676     }
   2677 }                               /* RecordConnectionSetupInfo */
   2678 
   2679 /* RecordDeleteContext
   2680  *
   2681  * Arguments:
   2682  *	pcbl is &ClientStateCallback.
   2683  *	nullata is NULL.
   2684  *	calldata is a pointer to a NewClientInfoRec (include/dixstruct.h)
   2685  *	which contains information about client state changes.
   2686  *
   2687  * Returns: nothing.
   2688  *
   2689  * Side Effects:
   2690  *	If a new client has connected and any contexts have specified
   2691  *	XRecordFutureClients, the new client is registered on those contexts.
   2692  *	If any of those contexts specify recording of the connection setup
   2693  *	info, it is recorded.
   2694  *
   2695  *	If an existing client has disconnected, it is deleted from any
   2696  *	contexts that it was registered on.  If any of those contexts
   2697  *	specified XRecordClientDied, they record a ClientDied protocol element.
   2698  *	If the disconnectiong client happened to be the data connection of an
   2699  *	enabled context, the context is disabled.
   2700  */
   2701 
   2702 static void
   2703 RecordAClientStateChange(CallbackListPtr *pcbl, void *nulldata,
   2704                          void *calldata)
   2705 {
   2706     NewClientInfoRec *pci = (NewClientInfoRec *) calldata;
   2707     int i;
   2708     ClientPtr pClient = pci->client;
   2709     RecordContextPtr *ppAllContextsCopy = NULL;
   2710     int numContextsCopy = 0;
   2711 
   2712     switch (pClient->clientState) {
   2713     case ClientStateRunning:   /* new client */
   2714         for (i = 0; i < numContexts; i++) {
   2715             RecordClientsAndProtocolPtr pRCAP;
   2716             RecordContextPtr pContext = ppAllContexts[i];
   2717 
   2718             if ((pRCAP = RecordFindClientOnContext(pContext,
   2719                                                    XRecordFutureClients, NULL)))
   2720             {
   2721                 RecordAddClientToRCAP(pRCAP, pClient->clientAsMask);
   2722                 if (pContext->pRecordingClient && pRCAP->clientStarted)
   2723                     RecordConnectionSetupInfo(pContext, pci);
   2724             }
   2725         }
   2726         break;
   2727 
   2728     case ClientStateGone:
   2729     case ClientStateRetained:  /* client disconnected */
   2730 
   2731         /* RecordDisableContext modifies contents of ppAllContexts. */
   2732         if (!(numContextsCopy = numContexts))
   2733             break;
   2734         ppAllContextsCopy = xallocarray(numContextsCopy,
   2735                                         sizeof(RecordContextPtr));
   2736         assert(ppAllContextsCopy);
   2737         memcpy(ppAllContextsCopy, ppAllContexts,
   2738                numContextsCopy * sizeof(RecordContextPtr));
   2739 
   2740         for (i = 0; i < numContextsCopy; i++) {
   2741             RecordClientsAndProtocolPtr pRCAP;
   2742             RecordContextPtr pContext = ppAllContextsCopy[i];
   2743             int pos;
   2744 
   2745             if (pContext->pRecordingClient == pClient)
   2746                 RecordDisableContext(pContext);
   2747             if ((pRCAP = RecordFindClientOnContext(pContext,
   2748                                                    pClient->clientAsMask,
   2749                                                    &pos))) {
   2750                 if (pContext->pRecordingClient && pRCAP->clientDied)
   2751                     RecordAProtocolElement(pContext, pClient,
   2752                                            XRecordClientDied, NULL, 0, 0, 0);
   2753                 RecordDeleteClientFromRCAP(pRCAP, pos);
   2754             }
   2755         }
   2756 
   2757         free(ppAllContextsCopy);
   2758         break;
   2759 
   2760     default:
   2761         break;
   2762     }                           /* end switch on client state */
   2763 }                               /* RecordAClientStateChange */
   2764 
   2765 /* RecordCloseDown
   2766  *
   2767  * Arguments:
   2768  *	extEntry is the extension information for RECORD.
   2769  *
   2770  * Returns: nothing.
   2771  *
   2772  * Side Effects:
   2773  *	Performs any cleanup needed by RECORD at server shutdown time.
   2774  *	
   2775  */
   2776 static void
   2777 RecordCloseDown(ExtensionEntry * extEntry)
   2778 {
   2779     DeleteCallback(&ClientStateCallback, RecordAClientStateChange, NULL);
   2780 }                               /* RecordCloseDown */
   2781 
   2782 /* RecordExtensionInit
   2783  *
   2784  * Arguments: none.
   2785  *
   2786  * Returns: nothing.
   2787  *
   2788  * Side Effects:
   2789  *	Enables the RECORD extension if possible.
   2790  */
   2791 void
   2792 RecordExtensionInit(void)
   2793 {
   2794     ExtensionEntry *extentry;
   2795 
   2796     RTContext = CreateNewResourceType(RecordDeleteContext, "RecordContext");
   2797     if (!RTContext)
   2798         return;
   2799 
   2800     if (!dixRegisterPrivateKey(RecordClientPrivateKey, PRIVATE_CLIENT, 0))
   2801         return;
   2802 
   2803     ppAllContexts = NULL;
   2804     numContexts = numEnabledContexts = numEnabledRCAPs = 0;
   2805 
   2806     if (!AddCallback(&ClientStateCallback, RecordAClientStateChange, NULL))
   2807         return;
   2808 
   2809     extentry = AddExtension(RECORD_NAME, RecordNumEvents, RecordNumErrors,
   2810                             ProcRecordDispatch, SProcRecordDispatch,
   2811                             RecordCloseDown, StandardMinorOpcode);
   2812     if (!extentry) {
   2813         DeleteCallback(&ClientStateCallback, RecordAClientStateChange, NULL);
   2814         return;
   2815     }
   2816     SetResourceTypeErrorValue(RTContext,
   2817                               extentry->errorBase + XRecordBadContext);
   2818 
   2819 }                               /* RecordExtensionInit */