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
RecordFindContextOnAllContexts(RecordContextPtr pContext)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
RecordFlushReplyBuffer(RecordContextPtr pContext,void * data1,int len1,void * data2,int len2)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
RecordAProtocolElement(RecordContextPtr pContext,ClientPtr pClient,int category,void * data,int datalen,int padlen,int futurelen)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
RecordFindClientOnContext(RecordContextPtr pContext,XID clientspec,int * pposition)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
RecordABigRequest(RecordContextPtr pContext,ClientPtr client,xReq * stuff)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
RecordARequest(ClientPtr client)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
RecordAReply(CallbackListPtr * pcbl,void * nulldata,void * calldata)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
RecordADeliveredEventOrError(CallbackListPtr * pcbl,void * nulldata,void * calldata)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
RecordSendProtocolEvents(RecordClientsAndProtocolPtr pRCAP,RecordContextPtr pContext,xEvent * pev,int count)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
RecordADeviceEvent(CallbackListPtr * pcbl,void * nulldata,void * calldata)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
RecordFlushAllContexts(CallbackListPtr * pcbl,void * nulldata,void * calldata)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
RecordInstallHooks(RecordClientsAndProtocolPtr pRCAP,XID oneclient)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
RecordUninstallHooks(RecordClientsAndProtocolPtr pRCAP,XID oneclient)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
RecordDeleteClientFromRCAP(RecordClientsAndProtocolPtr pRCAP,int position)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
RecordAddClientToRCAP(RecordClientsAndProtocolPtr pRCAP,XID clientspec)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
RecordDeleteClientFromContext(RecordContextPtr pContext,XID clientspec)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
RecordSanityCheckClientSpecifiers(ClientPtr client,XID * clientspecs,int nspecs,XID errorspec)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 *
RecordCanonicalizeClientSpecifiers(XID * pClientspecs,int * pNumClientspecs,XID excludespec)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
RecordPadAlign(int size,int align)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
RecordSanityCheckRegisterClients(RecordContextPtr pContext,ClientPtr client,xRecordRegisterClientsReq * stuff)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 intevals 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
RecordAllocIntervals(SetInfoPtr psi,int nIntervals)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
RecordConvertRangesToIntervals(SetInfoPtr psi,xRecordRange * pRanges,int nRanges,int byteoffset,SetInfoPtr pExtSetInfo,int * pnExtSetInfo)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
RecordRegisterClients(RecordContextPtr pContext,ClientPtr client,xRecordRegisterClientsReq * stuff)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 reuests, 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
ProcRecordQueryVersion(ClientPtr client)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
ProcRecordCreateContext(ClientPtr client)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
ProcRecordRegisterClients(ClientPtr client)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
ProcRecordUnregisterClients(ClientPtr client)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
RecordAllocRanges(GetContextRangeInfoPtr pri,int nRanges)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
RecordConvertSetToRanges(RecordSetPtr pSet,GetContextRangeInfoPtr pri,int byteoffset,Bool card8,unsigned int imax,int * pStartIndex)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
RecordConvertMinorOpInfoToRanges(RecordMinorOpPtr pMinOpInfo,GetContextRangeInfoPtr pri,int byteoffset)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
RecordSwapRanges(xRecordRange * pRanges,int nRanges)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
ProcRecordGetContext(ClientPtr client)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
ProcRecordEnableContext(ClientPtr client)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
RecordDisableContext(RecordContextPtr pContext)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) && (i < numEnabledContexts));
2380     if (i != (numEnabledContexts - 1)) {
2381         ppAllContexts[i] = ppAllContexts[numEnabledContexts - 1];
2382         ppAllContexts[numEnabledContexts - 1] = pContext;
2383     }
2384     --numEnabledContexts;
2385     assert(numEnabledContexts >= 0);
2386 }                               /* RecordDisableContext */
2387 
2388 static int
ProcRecordDisableContext(ClientPtr client)2389 ProcRecordDisableContext(ClientPtr client)
2390 {
2391     RecordContextPtr pContext;
2392 
2393     REQUEST(xRecordDisableContextReq);
2394 
2395     REQUEST_SIZE_MATCH(xRecordDisableContextReq);
2396     VERIFY_CONTEXT(pContext, stuff->context, client);
2397     RecordDisableContext(pContext);
2398     return Success;
2399 }                               /* ProcRecordDisableContext */
2400 
2401 /* RecordDeleteContext
2402  *
2403  * Arguments:
2404  *	value is the context to delete.
2405  *	id is its resource ID.
2406  *
2407  * Returns: Success.
2408  *
2409  * Side Effects:
2410  *	Disables the context, frees all associated memory, and removes
2411  *	it from the ppAllContexts array.
2412  */
2413 static int
RecordDeleteContext(void * value,XID id)2414 RecordDeleteContext(void *value, XID id)
2415 {
2416     int i;
2417     RecordContextPtr pContext = (RecordContextPtr) value;
2418     RecordClientsAndProtocolPtr pRCAP;
2419 
2420     RecordDisableContext(pContext);
2421 
2422     /*  Remove all the clients from all the RCAPs.
2423      *  As a result, the RCAPs will be freed.
2424      */
2425 
2426     while ((pRCAP = pContext->pListOfRCAP)) {
2427         int numClients = pRCAP->numClients;
2428 
2429         /* when the last client is deleted, the RCAP will go away. */
2430         while (numClients--) {
2431             RecordDeleteClientFromRCAP(pRCAP, numClients);
2432         }
2433     }
2434 
2435     /* remove context from AllContexts list */
2436 
2437     if (-1 != (i = RecordFindContextOnAllContexts(pContext))) {
2438         ppAllContexts[i] = ppAllContexts[numContexts - 1];
2439         if (--numContexts == 0) {
2440             free(ppAllContexts);
2441             ppAllContexts = NULL;
2442         }
2443     }
2444     free(pContext);
2445 
2446     return Success;
2447 }                               /* RecordDeleteContext */
2448 
2449 static int
ProcRecordFreeContext(ClientPtr client)2450 ProcRecordFreeContext(ClientPtr client)
2451 {
2452     RecordContextPtr pContext;
2453 
2454     REQUEST(xRecordFreeContextReq);
2455 
2456     REQUEST_SIZE_MATCH(xRecordFreeContextReq);
2457     VERIFY_CONTEXT(pContext, stuff->context, client);
2458     FreeResource(stuff->context, RT_NONE);
2459     return Success;
2460 }                               /* ProcRecordFreeContext */
2461 
2462 static int
ProcRecordDispatch(ClientPtr client)2463 ProcRecordDispatch(ClientPtr client)
2464 {
2465     REQUEST(xReq);
2466 
2467     switch (stuff->data) {
2468     case X_RecordQueryVersion:
2469         return ProcRecordQueryVersion(client);
2470     case X_RecordCreateContext:
2471         return ProcRecordCreateContext(client);
2472     case X_RecordRegisterClients:
2473         return ProcRecordRegisterClients(client);
2474     case X_RecordUnregisterClients:
2475         return ProcRecordUnregisterClients(client);
2476     case X_RecordGetContext:
2477         return ProcRecordGetContext(client);
2478     case X_RecordEnableContext:
2479         return ProcRecordEnableContext(client);
2480     case X_RecordDisableContext:
2481         return ProcRecordDisableContext(client);
2482     case X_RecordFreeContext:
2483         return ProcRecordFreeContext(client);
2484     default:
2485         return BadRequest;
2486     }
2487 }                               /* ProcRecordDispatch */
2488 
2489 static int _X_COLD
SProcRecordQueryVersion(ClientPtr client)2490 SProcRecordQueryVersion(ClientPtr client)
2491 {
2492     REQUEST(xRecordQueryVersionReq);
2493 
2494     swaps(&stuff->length);
2495     REQUEST_SIZE_MATCH(xRecordQueryVersionReq);
2496     swaps(&stuff->majorVersion);
2497     swaps(&stuff->minorVersion);
2498     return ProcRecordQueryVersion(client);
2499 }                               /* SProcRecordQueryVersion */
2500 
2501 static int _X_COLD
SwapCreateRegister(ClientPtr client,xRecordRegisterClientsReq * stuff)2502 SwapCreateRegister(ClientPtr client, xRecordRegisterClientsReq * stuff)
2503 {
2504     int i;
2505     XID *pClientID;
2506 
2507     swapl(&stuff->context);
2508     swapl(&stuff->nClients);
2509     swapl(&stuff->nRanges);
2510     pClientID = (XID *) &stuff[1];
2511     if (stuff->nClients >
2512         client->req_len - bytes_to_int32(sz_xRecordRegisterClientsReq))
2513         return BadLength;
2514     for (i = 0; i < stuff->nClients; i++, pClientID++) {
2515         swapl(pClientID);
2516     }
2517     if (stuff->nRanges >
2518         client->req_len - bytes_to_int32(sz_xRecordRegisterClientsReq)
2519         - stuff->nClients)
2520         return BadLength;
2521     RecordSwapRanges((xRecordRange *) pClientID, stuff->nRanges);
2522     return Success;
2523 }                               /* SwapCreateRegister */
2524 
2525 static int _X_COLD
SProcRecordCreateContext(ClientPtr client)2526 SProcRecordCreateContext(ClientPtr client)
2527 {
2528     REQUEST(xRecordCreateContextReq);
2529     int status;
2530 
2531     swaps(&stuff->length);
2532     REQUEST_AT_LEAST_SIZE(xRecordCreateContextReq);
2533     if ((status = SwapCreateRegister(client, (void *) stuff)) != Success)
2534         return status;
2535     return ProcRecordCreateContext(client);
2536 }                               /* SProcRecordCreateContext */
2537 
2538 static int _X_COLD
SProcRecordRegisterClients(ClientPtr client)2539 SProcRecordRegisterClients(ClientPtr client)
2540 {
2541     REQUEST(xRecordRegisterClientsReq);
2542     int status;
2543 
2544     swaps(&stuff->length);
2545     REQUEST_AT_LEAST_SIZE(xRecordRegisterClientsReq);
2546     if ((status = SwapCreateRegister(client, (void *) stuff)) != Success)
2547         return status;
2548     return ProcRecordRegisterClients(client);
2549 }                               /* SProcRecordRegisterClients */
2550 
2551 static int _X_COLD
SProcRecordUnregisterClients(ClientPtr client)2552 SProcRecordUnregisterClients(ClientPtr client)
2553 {
2554     REQUEST(xRecordUnregisterClientsReq);
2555 
2556     swaps(&stuff->length);
2557     REQUEST_AT_LEAST_SIZE(xRecordUnregisterClientsReq);
2558     swapl(&stuff->context);
2559     swapl(&stuff->nClients);
2560     SwapRestL(stuff);
2561     return ProcRecordUnregisterClients(client);
2562 }                               /* SProcRecordUnregisterClients */
2563 
2564 static int _X_COLD
SProcRecordGetContext(ClientPtr client)2565 SProcRecordGetContext(ClientPtr client)
2566 {
2567     REQUEST(xRecordGetContextReq);
2568 
2569     swaps(&stuff->length);
2570     REQUEST_SIZE_MATCH(xRecordGetContextReq);
2571     swapl(&stuff->context);
2572     return ProcRecordGetContext(client);
2573 }                               /* SProcRecordGetContext */
2574 
2575 static int _X_COLD
SProcRecordEnableContext(ClientPtr client)2576 SProcRecordEnableContext(ClientPtr client)
2577 {
2578     REQUEST(xRecordEnableContextReq);
2579 
2580     swaps(&stuff->length);
2581     REQUEST_SIZE_MATCH(xRecordEnableContextReq);
2582     swapl(&stuff->context);
2583     return ProcRecordEnableContext(client);
2584 }                               /* SProcRecordEnableContext */
2585 
2586 static int _X_COLD
SProcRecordDisableContext(ClientPtr client)2587 SProcRecordDisableContext(ClientPtr client)
2588 {
2589     REQUEST(xRecordDisableContextReq);
2590 
2591     swaps(&stuff->length);
2592     REQUEST_SIZE_MATCH(xRecordDisableContextReq);
2593     swapl(&stuff->context);
2594     return ProcRecordDisableContext(client);
2595 }                               /* SProcRecordDisableContext */
2596 
2597 static int _X_COLD
SProcRecordFreeContext(ClientPtr client)2598 SProcRecordFreeContext(ClientPtr client)
2599 {
2600     REQUEST(xRecordFreeContextReq);
2601 
2602     swaps(&stuff->length);
2603     REQUEST_SIZE_MATCH(xRecordFreeContextReq);
2604     swapl(&stuff->context);
2605     return ProcRecordFreeContext(client);
2606 }                               /* SProcRecordFreeContext */
2607 
2608 static int _X_COLD
SProcRecordDispatch(ClientPtr client)2609 SProcRecordDispatch(ClientPtr client)
2610 {
2611     REQUEST(xReq);
2612 
2613     switch (stuff->data) {
2614     case X_RecordQueryVersion:
2615         return SProcRecordQueryVersion(client);
2616     case X_RecordCreateContext:
2617         return SProcRecordCreateContext(client);
2618     case X_RecordRegisterClients:
2619         return SProcRecordRegisterClients(client);
2620     case X_RecordUnregisterClients:
2621         return SProcRecordUnregisterClients(client);
2622     case X_RecordGetContext:
2623         return SProcRecordGetContext(client);
2624     case X_RecordEnableContext:
2625         return SProcRecordEnableContext(client);
2626     case X_RecordDisableContext:
2627         return SProcRecordDisableContext(client);
2628     case X_RecordFreeContext:
2629         return SProcRecordFreeContext(client);
2630     default:
2631         return BadRequest;
2632     }
2633 }                               /* SProcRecordDispatch */
2634 
2635 /* RecordConnectionSetupInfo
2636  *
2637  * Arguments:
2638  *	pContext is an enabled context that specifies recording of
2639  *	  connection setup info.
2640  *	pci holds the connection setup info.
2641  *
2642  * Returns: nothing.
2643  *
2644  * Side Effects:
2645  *	The connection setup info is sent to the recording client.
2646  */
2647 static void
RecordConnectionSetupInfo(RecordContextPtr pContext,NewClientInfoRec * pci)2648 RecordConnectionSetupInfo(RecordContextPtr pContext, NewClientInfoRec * pci)
2649 {
2650     int prefixsize = SIZEOF(xConnSetupPrefix);
2651     int restsize = pci->prefix->length * 4;
2652 
2653     if (pci->client->swapped) {
2654         char *pConnSetup = (char *) malloc(prefixsize + restsize);
2655 
2656         if (!pConnSetup)
2657             return;
2658         SwapConnSetupPrefix(pci->prefix, (xConnSetupPrefix *) pConnSetup);
2659         SwapConnSetupInfo((char *) pci->setup,
2660                           (char *) (pConnSetup + prefixsize));
2661         RecordAProtocolElement(pContext, pci->client, XRecordClientStarted,
2662                                (void *) pConnSetup, prefixsize + restsize, 0,
2663                                0);
2664         free(pConnSetup);
2665     }
2666     else {
2667         /* don't alloc and copy as in the swapped case; just send the
2668          * data in two pieces
2669          */
2670         RecordAProtocolElement(pContext, pci->client, XRecordClientStarted,
2671                                (void *) pci->prefix, prefixsize, 0, restsize);
2672         RecordAProtocolElement(pContext, pci->client, XRecordClientStarted,
2673                                (void *) pci->setup, restsize, 0,
2674                                /* continuation */ -1);
2675     }
2676 }                               /* RecordConnectionSetupInfo */
2677 
2678 /* RecordDeleteContext
2679  *
2680  * Arguments:
2681  *	pcbl is &ClientStateCallback.
2682  *	nullata is NULL.
2683  *	calldata is a pointer to a NewClientInfoRec (include/dixstruct.h)
2684  *	which contains information about client state changes.
2685  *
2686  * Returns: nothing.
2687  *
2688  * Side Effects:
2689  *	If a new client has connected and any contexts have specified
2690  *	XRecordFutureClients, the new client is registered on those contexts.
2691  *	If any of those contexts specify recording of the connection setup
2692  *	info, it is recorded.
2693  *
2694  *	If an existing client has disconnected, it is deleted from any
2695  *	contexts that it was registered on.  If any of those contexts
2696  *	specified XRecordClientDied, they record a ClientDied protocol element.
2697  *	If the disconnectiong client happened to be the data connection of an
2698  *	enabled context, the context is disabled.
2699  */
2700 
2701 static void
RecordAClientStateChange(CallbackListPtr * pcbl,void * nulldata,void * calldata)2702 RecordAClientStateChange(CallbackListPtr *pcbl, void *nulldata,
2703                          void *calldata)
2704 {
2705     NewClientInfoRec *pci = (NewClientInfoRec *) calldata;
2706     int i;
2707     ClientPtr pClient = pci->client;
2708     RecordContextPtr *ppAllContextsCopy = NULL;
2709     int numContextsCopy = 0;
2710 
2711     switch (pClient->clientState) {
2712     case ClientStateRunning:   /* new client */
2713         for (i = 0; i < numContexts; i++) {
2714             RecordClientsAndProtocolPtr pRCAP;
2715             RecordContextPtr pContext = ppAllContexts[i];
2716 
2717             if ((pRCAP = RecordFindClientOnContext(pContext,
2718                                                    XRecordFutureClients, NULL)))
2719             {
2720                 RecordAddClientToRCAP(pRCAP, pClient->clientAsMask);
2721                 if (pContext->pRecordingClient && pRCAP->clientStarted)
2722                     RecordConnectionSetupInfo(pContext, pci);
2723             }
2724         }
2725         break;
2726 
2727     case ClientStateGone:
2728     case ClientStateRetained:  /* client disconnected */
2729 
2730         /* RecordDisableContext modifies contents of ppAllContexts. */
2731         numContextsCopy = numContexts;
2732         ppAllContextsCopy = xallocarray(numContextsCopy,
2733                                         sizeof(RecordContextPtr));
2734         assert(ppAllContextsCopy);
2735         memcpy(ppAllContextsCopy, ppAllContexts,
2736                numContextsCopy * sizeof(RecordContextPtr));
2737 
2738         for (i = 0; i < numContextsCopy; i++) {
2739             RecordClientsAndProtocolPtr pRCAP;
2740             RecordContextPtr pContext = ppAllContextsCopy[i];
2741             int pos;
2742 
2743             if (pContext->pRecordingClient == pClient)
2744                 RecordDisableContext(pContext);
2745             if ((pRCAP = RecordFindClientOnContext(pContext,
2746                                                    pClient->clientAsMask,
2747                                                    &pos))) {
2748                 if (pContext->pRecordingClient && pRCAP->clientDied)
2749                     RecordAProtocolElement(pContext, pClient,
2750                                            XRecordClientDied, NULL, 0, 0, 0);
2751                 RecordDeleteClientFromRCAP(pRCAP, pos);
2752             }
2753         }
2754 
2755         free(ppAllContextsCopy);
2756         break;
2757 
2758     default:
2759         break;
2760     }                           /* end switch on client state */
2761 }                               /* RecordAClientStateChange */
2762 
2763 /* RecordCloseDown
2764  *
2765  * Arguments:
2766  *	extEntry is the extension information for RECORD.
2767  *
2768  * Returns: nothing.
2769  *
2770  * Side Effects:
2771  *	Performs any cleanup needed by RECORD at server shutdown time.
2772  *
2773  */
2774 static void
RecordCloseDown(ExtensionEntry * extEntry)2775 RecordCloseDown(ExtensionEntry * extEntry)
2776 {
2777     DeleteCallback(&ClientStateCallback, RecordAClientStateChange, NULL);
2778 }                               /* RecordCloseDown */
2779 
2780 /* RecordExtensionInit
2781  *
2782  * Arguments: none.
2783  *
2784  * Returns: nothing.
2785  *
2786  * Side Effects:
2787  *	Enables the RECORD extension if possible.
2788  */
2789 void
RecordExtensionInit(void)2790 RecordExtensionInit(void)
2791 {
2792     ExtensionEntry *extentry;
2793 
2794     RTContext = CreateNewResourceType(RecordDeleteContext, "RecordContext");
2795     if (!RTContext)
2796         return;
2797 
2798     if (!dixRegisterPrivateKey(RecordClientPrivateKey, PRIVATE_CLIENT, 0))
2799         return;
2800 
2801     ppAllContexts = NULL;
2802     numContexts = numEnabledContexts = numEnabledRCAPs = 0;
2803 
2804     if (!AddCallback(&ClientStateCallback, RecordAClientStateChange, NULL))
2805         return;
2806 
2807     extentry = AddExtension(RECORD_NAME, RecordNumEvents, RecordNumErrors,
2808                             ProcRecordDispatch, SProcRecordDispatch,
2809                             RecordCloseDown, StandardMinorOpcode);
2810     if (!extentry) {
2811         DeleteCallback(&ClientStateCallback, RecordAClientStateChange, NULL);
2812         return;
2813     }
2814     SetResourceTypeErrorValue(RTContext,
2815                               extentry->errorBase + XRecordBadContext);
2816 
2817 }                               /* RecordExtensionInit */
2818