4 Copyright 1995, 1998 The Open Group
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
12 The above copyright notice and this permission notice shall be
13 included in all copies or substantial portions of the Software.
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.
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
28 Author: David P. Wiggins, The Open Group
30 This work benefited from earlier work done by Martha Zimet of NCD
31 and Jim Haggerty of Metheus.
35 #ifdef HAVE_DIX_CONFIG_H
36 #include <dix-config.h>
39 #include "dixstruct.h"
40 #include "extnsionst.h"
42 #include <X11/extensions/recordproto.h>
46 #include "eventconvert.h"
47 #include "scrnintstr.h"
54 #include "panoramiX.h"
55 #include "panoramiXsrv.h"
59 #include "protocol-versions.h"
61 static RESTYPE RTContext
; /* internal resource type for Record contexts */
63 /* How many bytes of protocol data to buffer in a context. Don't set to less
66 #define REPLY_BUF_SIZE 1024
68 /* Record Context structure */
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
;
83 /* RecordMinorOpRec - to hold minor opcode selections for extension requests
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 */
94 } RecordMinorOpRec
, *RecordMinorOpPtr
;
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.
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
;
121 /* how much bigger to make pRCAP->pClientIDs when reallocing */
122 #define CLIENT_ARRAY_GROWTH_INCREMENT 4
124 /* counts the total number of RCAPs belonging to enabled contexts. */
125 static int numEnabledRCAPs
;
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
132 #define VERIFY_CONTEXT(_pContext, _contextid, _client) { \
133 int rc = dixLookupResourceByType((pointer *)&(_pContext), _contextid, \
134 RTContext, _client, DixUseAccess); \
139 static int RecordDeleteContext(pointer
/*value */ ,
143 /***************************************************************************/
145 /* client private stuff */
147 /* To make declarations less obfuscated, have a typedef for a pointer to a
150 typedef int (*ProcFunctionPtr
) (ClientPtr
/*pClient */
153 /* Record client private. Generally a client only has one of these if
154 * any of its requests are being recorded.
157 /* ptr to client's proc vector before Record stuck its nose in */
158 ProcFunctionPtr
*originalVector
;
160 /* proc vector with pointers for recorded requests redirected to the
161 * function RecordARequest
163 ProcFunctionPtr recordVector
[256];
164 } RecordClientPrivateRec
, *RecordClientPrivatePtr
;
166 static DevPrivateKeyRec RecordClientPrivateKeyRec
;
168 #define RecordClientPrivateKey (&RecordClientPrivateKeyRec)
170 /* RecordClientPrivatePtr RecordClientPrivate(ClientPtr)
171 * gets the client private of the given client. Syntactic sugar.
173 #define RecordClientPrivate(_pClient) (RecordClientPrivatePtr) \
174 dixLookupPrivate(&(_pClient)->devPrivates, RecordClientPrivateKey)
176 /***************************************************************************/
178 /* global list of all contexts */
180 static RecordContextPtr
*ppAllContexts
;
182 static int numContexts
; /* number of contexts in ppAllContexts */
184 /* number of currently enabled contexts. All enabled contexts are bunched
185 * up at the front of the ppAllContexts array, from ppAllContexts[0] to
186 * ppAllContexts[numEnabledContexts-1], to eliminate time spent skipping
187 * past disabled contexts.
189 static int numEnabledContexts
;
191 /* RecordFindContextOnAllContexts
194 * pContext is the context to search for.
197 * The index into the array ppAllContexts at which pContext is stored.
198 * If pContext is not found in ppAllContexts, returns -1.
200 * Side Effects: none.
203 RecordFindContextOnAllContexts(RecordContextPtr pContext
)
207 assert(numContexts
>= numEnabledContexts
);
208 for (i
= 0; i
< numContexts
; i
++) {
209 if (ppAllContexts
[i
] == pContext
)
213 } /* RecordFindContextOnAllContexts */
215 /***************************************************************************/
217 /* RecordFlushReplyBuffer
220 * pContext is the context to flush.
221 * data1 is a pointer to additional data, and len1 is its length in bytes.
222 * data2 is a pointer to additional data, and len2 is its length in bytes.
227 * If the context is enabled, any buffered (recorded) protocol is written
228 * to the recording client, and the number of buffered bytes is set to
229 * zero. If len1 is not zero, data1/len1 are then written to the
230 * recording client, and similarly for data2/len2 (written after
234 RecordFlushReplyBuffer(RecordContextPtr pContext
,
235 pointer data1
, int len1
, pointer data2
, int len2
)
237 if (!pContext
->pRecordingClient
|| pContext
->pRecordingClient
->clientGone
||
241 if (pContext
->numBufBytes
)
242 WriteToClient(pContext
->pRecordingClient
, pContext
->numBufBytes
,
243 pContext
->replyBuffer
);
244 pContext
->numBufBytes
= 0;
246 WriteToClient(pContext
->pRecordingClient
, len1
, data1
);
248 WriteToClient(pContext
->pRecordingClient
, len2
, data2
);
250 } /* RecordFlushReplyBuffer */
252 /* RecordAProtocolElement
255 * pContext is the context that is recording a protocol element.
256 * pClient is the client whose protocol is being recorded. For
257 * device events and EndOfData, pClient is NULL.
258 * category is the category of the protocol element, as defined
259 * by the RECORD spec.
260 * data is a pointer to the protocol data, and datalen - padlen
261 * is its length in bytes.
262 * padlen is the number of pad bytes from a zeroed array.
263 * futurelen is the number of bytes that will be sent in subsequent
264 * calls to this function to complete this protocol element.
265 * In those subsequent calls, futurelen will be -1 to indicate
266 * that the current data is a continuation of the same protocol
272 * The context may be flushed. The new protocol element will be
273 * added to the context's protocol buffer with appropriate element
274 * headers prepended (sequence number and timestamp). If the data
275 * is continuation data (futurelen == -1), element headers won't
276 * be added. If the protocol element and headers won't fit in
277 * the context's buffer, it is sent directly to the recording
278 * client (after any buffered data).
281 RecordAProtocolElement(RecordContextPtr pContext
, ClientPtr pClient
,
282 int category
, pointer data
, int datalen
, int padlen
,
285 CARD32 elemHeaderData
[2];
286 int numElemHeaders
= 0;
287 Bool recordingClientSwapped
= pContext
->pRecordingClient
->swapped
;
288 CARD32 serverTime
= 0;
289 Bool gotServerTime
= FALSE
;
292 if (futurelen
>= 0) { /* start of new protocol element */
293 xRecordEnableContextReply
*pRep
= (xRecordEnableContextReply
*)
294 pContext
->replyBuffer
;
296 if (pContext
->pBufClient
!= pClient
||
297 pContext
->bufCategory
!= category
) {
298 RecordFlushReplyBuffer(pContext
, NULL
, 0, NULL
, 0);
299 pContext
->pBufClient
= pClient
;
300 pContext
->bufCategory
= category
;
303 if (!pContext
->numBufBytes
) {
304 serverTime
= GetTimeInMillis();
305 gotServerTime
= TRUE
;
306 pRep
->type
= X_Reply
;
307 pRep
->category
= category
;
308 pRep
->sequenceNumber
= pContext
->pRecordingClient
->sequence
;
310 pRep
->elementHeader
= pContext
->elemHeaders
;
311 pRep
->serverTime
= serverTime
;
313 pRep
->clientSwapped
=
314 (pClient
->swapped
!= recordingClientSwapped
);
315 pRep
->idBase
= pClient
->clientAsMask
;
316 pRep
->recordedSequenceNumber
= pClient
->sequence
;
318 else { /* it's a device event, StartOfData, or EndOfData */
320 pRep
->clientSwapped
= (category
!= XRecordFromServer
) &&
321 recordingClientSwapped
;
323 pRep
->recordedSequenceNumber
= 0;
326 if (recordingClientSwapped
) {
327 swaps(&pRep
->sequenceNumber
);
328 swapl(&pRep
->length
);
329 swapl(&pRep
->idBase
);
330 swapl(&pRep
->serverTime
);
331 swapl(&pRep
->recordedSequenceNumber
);
333 pContext
->numBufBytes
= SIZEOF(xRecordEnableContextReply
);
336 /* generate element headers if needed */
338 if (((pContext
->elemHeaders
& XRecordFromClientTime
)
339 && category
== XRecordFromClient
)
340 || ((pContext
->elemHeaders
& XRecordFromServerTime
)
341 && category
== XRecordFromServer
)) {
343 elemHeaderData
[numElemHeaders
] = serverTime
;
345 elemHeaderData
[numElemHeaders
] = GetTimeInMillis();
346 if (recordingClientSwapped
)
347 swapl(&elemHeaderData
[numElemHeaders
]);
351 if ((pContext
->elemHeaders
& XRecordFromClientSequence
)
352 && (category
== XRecordFromClient
|| category
== XRecordClientDied
)) {
353 elemHeaderData
[numElemHeaders
] = pClient
->sequence
;
354 if (recordingClientSwapped
)
355 swapl(&elemHeaderData
[numElemHeaders
]);
359 /* adjust reply length */
361 replylen
= pRep
->length
;
362 if (recordingClientSwapped
)
364 replylen
+= numElemHeaders
+ bytes_to_int32(datalen
) +
365 bytes_to_int32(futurelen
);
366 if (recordingClientSwapped
)
368 pRep
->length
= replylen
;
369 } /* end if not continued reply */
373 /* if space available >= space needed, buffer the data */
375 if (REPLY_BUF_SIZE
- pContext
->numBufBytes
>= datalen
+ numElemHeaders
) {
376 if (numElemHeaders
) {
377 memcpy(pContext
->replyBuffer
+ pContext
->numBufBytes
,
378 elemHeaderData
, numElemHeaders
);
379 pContext
->numBufBytes
+= numElemHeaders
;
382 static char padBuffer
[3]; /* as in FlushClient */
384 memcpy(pContext
->replyBuffer
+ pContext
->numBufBytes
,
385 data
, datalen
- padlen
);
386 pContext
->numBufBytes
+= datalen
- padlen
;
387 memcpy(pContext
->replyBuffer
+ pContext
->numBufBytes
,
389 pContext
->numBufBytes
+= padlen
;
393 RecordFlushReplyBuffer(pContext
, (pointer
) elemHeaderData
,
394 numElemHeaders
, (pointer
) data
,
397 } /* RecordAProtocolElement */
399 /* RecordFindClientOnContext
402 * pContext is the context to search.
403 * clientspec is the resource ID mask identifying the client to search
404 * for, or XRecordFutureClients.
405 * pposition is a pointer to an int, or NULL. See Returns.
408 * The RCAP on which clientspec was found, or NULL if not found on
409 * any RCAP on the given context.
410 * If pposition was not NULL and the returned RCAP is not NULL,
411 * *pposition will be set to the index into the returned the RCAP's
412 * pClientIDs array that holds clientspec.
414 * Side Effects: none.
416 static RecordClientsAndProtocolPtr
417 RecordFindClientOnContext(RecordContextPtr pContext
,
418 XID clientspec
, int *pposition
)
420 RecordClientsAndProtocolPtr pRCAP
;
422 for (pRCAP
= pContext
->pListOfRCAP
; pRCAP
; pRCAP
= pRCAP
->pNextRCAP
) {
425 for (i
= 0; i
< pRCAP
->numClients
; i
++) {
426 if (pRCAP
->pClientIDs
[i
] == clientspec
) {
434 } /* RecordFindClientOnContext */
439 * pContext is the recording context.
440 * client is the client being recorded.
441 * stuff is a pointer to the big request of client (see the Big Requests
442 * extension for details.)
447 * The big request is recorded with the correct length field re-inserted.
449 * Note: this function exists mainly to make RecordARequest smaller.
452 RecordABigRequest(RecordContextPtr pContext
, ClientPtr client
, xReq
* stuff
)
457 /* note: client->req_len has been frobbed by ReadRequestFromClient
458 * (os/io.c) to discount the extra 4 bytes taken by the extended length
459 * field in a big request. The actual request length to record is
460 * client->req_len + 1 (measured in CARD32s).
463 /* record the request header */
464 bytesLeft
= client
->req_len
<< 2;
465 RecordAProtocolElement(pContext
, client
, XRecordFromClient
,
466 (pointer
) stuff
, SIZEOF(xReq
), 0, bytesLeft
);
468 /* reinsert the extended length field that was squished out */
469 bigLength
= client
->req_len
+ bytes_to_int32(sizeof(bigLength
));
472 RecordAProtocolElement(pContext
, client
, XRecordFromClient
,
473 (pointer
) &bigLength
, sizeof(bigLength
), 0,
474 /* continuation */ -1);
475 bytesLeft
-= sizeof(bigLength
);
477 /* record the rest of the request after the length */
478 RecordAProtocolElement(pContext
, client
, XRecordFromClient
,
479 (pointer
) (stuff
+ 1), bytesLeft
, 0,
480 /* continuation */ -1);
481 } /* RecordABigRequest */
486 * client is a client that the server has dispatched a request to by
487 * calling client->requestVector[request opcode] .
488 * The request is in client->requestBuffer.
491 * Whatever is returned by the "real" Proc function for this request.
492 * The "real" Proc function is the function that was in
493 * client->requestVector[request opcode] before it was replaced by
494 * RecordARequest. (See the function RecordInstallHooks.)
497 * The request is recorded by all contexts that have registered this
498 * request for this client. The real Proc function is called.
501 RecordARequest(ClientPtr client
)
503 RecordContextPtr pContext
;
504 RecordClientsAndProtocolPtr pRCAP
;
506 RecordClientPrivatePtr pClientPriv
;
511 majorop
= stuff
->reqType
;
512 for (i
= 0; i
< numEnabledContexts
; i
++) {
513 pContext
= ppAllContexts
[i
];
514 pRCAP
= RecordFindClientOnContext(pContext
, client
->clientAsMask
, NULL
);
515 if (pRCAP
&& pRCAP
->pRequestMajorOpSet
&&
516 RecordIsMemberOfSet(pRCAP
->pRequestMajorOpSet
, majorop
)) {
517 if (majorop
<= 127) { /* core request */
519 if (stuff
->length
== 0)
520 RecordABigRequest(pContext
, client
, stuff
);
522 RecordAProtocolElement(pContext
, client
, XRecordFromClient
,
524 client
->req_len
<< 2, 0, 0);
526 else { /* extension, check minor opcode */
528 int minorop
= client
->minorOp
;
530 RecordMinorOpPtr pMinorOpInfo
= pRCAP
->pRequestMinOpInfo
;
532 assert(pMinorOpInfo
);
533 numMinOpInfo
= pMinorOpInfo
->count
;
535 assert(numMinOpInfo
);
536 for (; numMinOpInfo
; numMinOpInfo
--, pMinorOpInfo
++) {
537 if (majorop
>= pMinorOpInfo
->major
.first
&&
538 majorop
<= pMinorOpInfo
->major
.last
&&
539 RecordIsMemberOfSet(pMinorOpInfo
->major
.pMinOpSet
,
541 if (stuff
->length
== 0)
542 RecordABigRequest(pContext
, client
, stuff
);
544 RecordAProtocolElement(pContext
, client
,
547 client
->req_len
<< 2, 0, 0);
550 } /* end for each minor op info */
551 } /* end extension request */
552 } /* end this RCAP wants this major opcode */
553 } /* end for each context */
554 pClientPriv
= RecordClientPrivate(client
);
556 return (*pClientPriv
->originalVector
[majorop
]) (client
);
557 } /* RecordARequest */
562 * pcbl is &ReplyCallback.
564 * calldata is a pointer to a ReplyInfoRec (include/os.h)
565 * which provides information about replies that are being sent
571 * The reply is recorded by all contexts that have registered this
572 * reply type for this client. If more data belonging to the same
573 * reply is expected, and if the reply is being recorded by any
574 * context, pContext->continuedReply is set to 1.
575 * If pContext->continuedReply was already 1 and this is the last
576 * chunk of data belonging to this reply, it is set to 0.
579 RecordAReply(CallbackListPtr
*pcbl
, pointer nulldata
, pointer calldata
)
581 RecordContextPtr pContext
;
582 RecordClientsAndProtocolPtr pRCAP
;
584 ReplyInfoRec
*pri
= (ReplyInfoRec
*) calldata
;
585 ClientPtr client
= pri
->client
;
587 for (eci
= 0; eci
< numEnabledContexts
; eci
++) {
588 pContext
= ppAllContexts
[eci
];
589 pRCAP
= RecordFindClientOnContext(pContext
, client
->clientAsMask
, NULL
);
591 int majorop
= client
->majorOp
;
593 if (pContext
->continuedReply
) {
594 RecordAProtocolElement(pContext
, client
, XRecordFromServer
,
595 (pointer
) pri
->replyData
,
596 pri
->dataLenBytes
, pri
->padBytes
,
597 /* continuation */ -1);
598 if (!pri
->bytesRemaining
)
599 pContext
->continuedReply
= 0;
601 else if (pri
->startOfReply
&& pRCAP
->pReplyMajorOpSet
&&
602 RecordIsMemberOfSet(pRCAP
->pReplyMajorOpSet
, majorop
)) {
603 if (majorop
<= 127) { /* core reply */
604 RecordAProtocolElement(pContext
, client
, XRecordFromServer
,
605 (pointer
) pri
->replyData
,
606 pri
->dataLenBytes
, 0,
607 pri
->bytesRemaining
);
608 if (pri
->bytesRemaining
)
609 pContext
->continuedReply
= 1;
611 else { /* extension, check minor opcode */
613 int minorop
= client
->minorOp
;
615 RecordMinorOpPtr pMinorOpInfo
= pRCAP
->pReplyMinOpInfo
;
617 assert(pMinorOpInfo
);
618 numMinOpInfo
= pMinorOpInfo
->count
;
620 assert(numMinOpInfo
);
621 for (; numMinOpInfo
; numMinOpInfo
--, pMinorOpInfo
++) {
622 if (majorop
>= pMinorOpInfo
->major
.first
&&
623 majorop
<= pMinorOpInfo
->major
.last
&&
624 RecordIsMemberOfSet(pMinorOpInfo
->major
.pMinOpSet
,
626 RecordAProtocolElement(pContext
, client
,
628 (pointer
) pri
->replyData
,
629 pri
->dataLenBytes
, 0,
630 pri
->bytesRemaining
);
631 if (pri
->bytesRemaining
)
632 pContext
->continuedReply
= 1;
635 } /* end for each minor op info */
636 } /* end extension reply */
637 } /* end continued reply vs. start of reply */
638 } /* end client is registered on this context */
639 } /* end for each context */
642 /* RecordADeliveredEventOrError
645 * pcbl is &EventCallback.
647 * calldata is a pointer to a EventInfoRec (include/dix.h)
648 * which provides information about events that are being sent
654 * The event or error is recorded by all contexts that have registered
655 * it for this client.
658 RecordADeliveredEventOrError(CallbackListPtr
*pcbl
, pointer nulldata
,
661 EventInfoRec
*pei
= (EventInfoRec
*) calldata
;
662 RecordContextPtr pContext
;
663 RecordClientsAndProtocolPtr pRCAP
;
664 int eci
; /* enabled context index */
665 ClientPtr pClient
= pei
->client
;
667 for (eci
= 0; eci
< numEnabledContexts
; eci
++) {
668 pContext
= ppAllContexts
[eci
];
669 pRCAP
= RecordFindClientOnContext(pContext
, pClient
->clientAsMask
,
671 if (pRCAP
&& (pRCAP
->pDeliveredEventSet
|| pRCAP
->pErrorSet
)) {
672 int ev
; /* event index */
673 xEvent
*pev
= pei
->events
;
675 for (ev
= 0; ev
< pei
->count
; ev
++, pev
++) {
678 if (pRCAP
->pErrorSet
) {
679 recordit
= RecordIsMemberOfSet(pRCAP
->pErrorSet
,
683 else if (pRCAP
->pDeliveredEventSet
) {
684 recordit
= RecordIsMemberOfSet(pRCAP
->pDeliveredEventSet
,
685 pev
->u
.u
.type
& 0177);
689 xEvent
*pEvToRecord
= pev
;
691 if (pClient
->swapped
) {
692 (*EventSwapVector
[pev
->u
.u
.type
& 0177])
693 (pev
, &swappedEvent
);
694 pEvToRecord
= &swappedEvent
;
697 RecordAProtocolElement(pContext
, pClient
,
698 XRecordFromServer
, pEvToRecord
,
699 SIZEOF(xEvent
), 0, 0);
701 } /* end for each event */
702 } /* end this client is on this context */
703 } /* end for each enabled context */
704 } /* RecordADeliveredEventOrError */
707 RecordSendProtocolEvents(RecordClientsAndProtocolPtr pRCAP
,
708 RecordContextPtr pContext
, xEvent
*pev
, int count
)
710 int ev
; /* event index */
712 for (ev
= 0; ev
< count
; ev
++, pev
++) {
713 if (RecordIsMemberOfSet(pRCAP
->pDeviceEventSet
, pev
->u
.u
.type
& 0177)) {
715 xEvent
*pEvToRecord
= pev
;
720 if (!noPanoramiXExtension
&&
721 (pev
->u
.u
.type
== MotionNotify
||
722 pev
->u
.u
.type
== ButtonPress
||
723 pev
->u
.u
.type
== ButtonRelease
||
724 pev
->u
.u
.type
== KeyPress
|| pev
->u
.u
.type
== KeyRelease
)) {
725 int scr
= XineramaGetCursorScreen(inputInfo
.pointer
);
727 memcpy(&shiftedEvent
, pev
, sizeof(xEvent
));
728 shiftedEvent
.u
.keyButtonPointer
.rootX
+=
729 screenInfo
.screens
[scr
]->x
- screenInfo
.screens
[0]->x
;
730 shiftedEvent
.u
.keyButtonPointer
.rootY
+=
731 screenInfo
.screens
[scr
]->y
- screenInfo
.screens
[0]->y
;
732 pEvToRecord
= &shiftedEvent
;
734 #endif /* PANORAMIX */
736 if (pContext
->pRecordingClient
->swapped
) {
737 (*EventSwapVector
[pEvToRecord
->u
.u
.type
& 0177])
738 (pEvToRecord
, &swappedEvent
);
739 pEvToRecord
= &swappedEvent
;
742 RecordAProtocolElement(pContext
, NULL
,
743 XRecordFromServer
, pEvToRecord
,
744 SIZEOF(xEvent
), 0, 0);
745 /* make sure device events get flushed in the absence
746 * of other client activity
748 SetCriticalOutputPending();
750 } /* end for each event */
752 } /* RecordADeviceEvent */
754 /* RecordADeviceEvent
757 * pcbl is &DeviceEventCallback.
759 * calldata is a pointer to a DeviceEventInfoRec (include/dix.h)
760 * which provides information about device events that occur.
765 * The device event is recorded by all contexts that have registered
766 * it for this client.
769 RecordADeviceEvent(CallbackListPtr
*pcbl
, pointer nulldata
, pointer calldata
)
771 DeviceEventInfoRec
*pei
= (DeviceEventInfoRec
*) calldata
;
772 RecordContextPtr pContext
;
773 RecordClientsAndProtocolPtr pRCAP
;
774 int eci
; /* enabled context index */
776 for (eci
= 0; eci
< numEnabledContexts
; eci
++) {
777 pContext
= ppAllContexts
[eci
];
778 for (pRCAP
= pContext
->pListOfRCAP
; pRCAP
; pRCAP
= pRCAP
->pNextRCAP
) {
779 if (pRCAP
->pDeviceEventSet
) {
781 xEvent
*xi_events
= NULL
;
783 /* TODO check return values */
784 if (IsMaster(pei
->device
)) {
787 EventToCore(pei
->event
, &core_events
, &count
);
788 RecordSendProtocolEvents(pRCAP
, pContext
, core_events
,
793 EventToXI(pei
->event
, &xi_events
, &count
);
794 RecordSendProtocolEvents(pRCAP
, pContext
, xi_events
, count
);
796 } /* end this RCAP selects device events */
797 } /* end for each RCAP on this context */
798 } /* end for each enabled context */
801 /* RecordFlushAllContexts
804 * pcbl is &FlushCallback.
805 * nulldata and calldata are NULL.
810 * All buffered reply data of all enabled contexts is written to
811 * the recording clients.
814 RecordFlushAllContexts(CallbackListPtr
*pcbl
,
815 pointer nulldata
, pointer calldata
)
817 int eci
; /* enabled context index */
818 RecordContextPtr pContext
;
820 for (eci
= 0; eci
< numEnabledContexts
; eci
++) {
821 pContext
= ppAllContexts
[eci
];
823 /* In most cases we leave it to RecordFlushReplyBuffer to make
824 * this check, but this function could be called very often, so we
825 * check before calling hoping to save the function call cost
828 if (pContext
->numBufBytes
)
829 RecordFlushReplyBuffer(ppAllContexts
[eci
], NULL
, 0, NULL
, 0);
831 } /* RecordFlushAllContexts */
833 /* RecordInstallHooks
836 * pRCAP is an RCAP on an enabled or being-enabled context.
837 * oneclient can be zero or the resource ID mask identifying a client.
839 * Returns: BadAlloc if a memory allocation error occurred, else Success.
842 * Recording hooks needed by RCAP are installed.
843 * If oneclient is zero, recording hooks needed for all clients and
844 * protocol on the RCAP are installed. If oneclient is non-zero,
845 * only those hooks needed for the specified client are installed.
847 * Client requestVectors may be altered. numEnabledRCAPs will be
848 * incremented if oneclient == 0. Callbacks may be added to
849 * various callback lists.
852 RecordInstallHooks(RecordClientsAndProtocolPtr pRCAP
, XID oneclient
)
860 client
= pRCAP
->numClients
? pRCAP
->pClientIDs
[i
++] : 0;
863 if (client
!= XRecordFutureClients
) {
864 if (pRCAP
->pRequestMajorOpSet
) {
865 RecordSetIteratePtr pIter
= NULL
;
866 RecordSetInterval interval
;
867 ClientPtr pClient
= clients
[CLIENT_ID(client
)];
869 if (pClient
&& !RecordClientPrivate(pClient
)) {
870 RecordClientPrivatePtr pClientPriv
;
872 /* no Record proc vector; allocate one */
873 pClientPriv
= (RecordClientPrivatePtr
)
874 malloc(sizeof(RecordClientPrivateRec
));
877 /* copy old proc vector to new */
878 memcpy(pClientPriv
->recordVector
, pClient
->requestVector
,
879 sizeof(pClientPriv
->recordVector
));
880 pClientPriv
->originalVector
= pClient
->requestVector
;
881 dixSetPrivate(&pClient
->devPrivates
,
882 RecordClientPrivateKey
, pClientPriv
);
883 pClient
->requestVector
= pClientPriv
->recordVector
;
885 while ((pIter
= RecordIterateSet(pRCAP
->pRequestMajorOpSet
,
886 pIter
, &interval
))) {
889 for (j
= interval
.first
; j
<= interval
.last
; j
++)
890 pClient
->requestVector
[j
] = RecordARequest
;
897 client
= (i
< pRCAP
->numClients
) ? pRCAP
->pClientIDs
[i
++] : 0;
900 assert(numEnabledRCAPs
>= 0);
901 if (!oneclient
&& ++numEnabledRCAPs
== 1) { /* we're enabling the first context */
902 if (!AddCallback(&EventCallback
, RecordADeliveredEventOrError
, NULL
))
904 if (!AddCallback(&DeviceEventCallback
, RecordADeviceEvent
, NULL
))
906 if (!AddCallback(&ReplyCallback
, RecordAReply
, NULL
))
908 if (!AddCallback(&FlushCallback
, RecordFlushAllContexts
, NULL
))
910 /* Alternate context flushing scheme: delete the line above
911 * and call RegisterBlockAndWakeupHandlers here passing
912 * RecordFlushAllContexts. Is this any better?
916 } /* RecordInstallHooks */
918 /* RecordUninstallHooks
921 * pRCAP is an RCAP on an enabled or being-disabled context.
922 * oneclient can be zero or the resource ID mask identifying a client.
927 * Recording hooks needed by RCAP may be uninstalled.
928 * If oneclient is zero, recording hooks needed for all clients and
929 * protocol on the RCAP may be uninstalled. If oneclient is non-zero,
930 * only those hooks needed for the specified client may be uninstalled.
932 * Client requestVectors may be altered. numEnabledRCAPs will be
933 * decremented if oneclient == 0. Callbacks may be deleted from
934 * various callback lists.
937 RecordUninstallHooks(RecordClientsAndProtocolPtr pRCAP
, XID oneclient
)
945 client
= pRCAP
->numClients
? pRCAP
->pClientIDs
[i
++] : 0;
948 if (client
!= XRecordFutureClients
) {
949 if (pRCAP
->pRequestMajorOpSet
) {
950 ClientPtr pClient
= clients
[CLIENT_ID(client
)];
952 Bool otherRCAPwantsProcVector
= FALSE
;
953 RecordClientPrivatePtr pClientPriv
= NULL
;
956 pClientPriv
= RecordClientPrivate(pClient
);
958 memcpy(pClientPriv
->recordVector
, pClientPriv
->originalVector
,
959 sizeof(pClientPriv
->recordVector
));
961 for (c
= 0; c
< numEnabledContexts
; c
++) {
962 RecordClientsAndProtocolPtr pOtherRCAP
;
963 RecordContextPtr pContext
= ppAllContexts
[c
];
965 if (pContext
== pRCAP
->pContext
)
967 pOtherRCAP
= RecordFindClientOnContext(pContext
, client
,
969 if (pOtherRCAP
&& pOtherRCAP
->pRequestMajorOpSet
) {
970 RecordSetIteratePtr pIter
= NULL
;
971 RecordSetInterval interval
;
973 otherRCAPwantsProcVector
= TRUE
;
975 RecordIterateSet(pOtherRCAP
->pRequestMajorOpSet
,
976 pIter
, &interval
))) {
979 for (j
= interval
.first
; j
<= interval
.last
; j
++)
980 pClient
->requestVector
[j
] = RecordARequest
;
984 if (!otherRCAPwantsProcVector
) { /* nobody needs it, so free it */
985 pClient
->requestVector
= pClientPriv
->originalVector
;
986 dixSetPrivate(&pClient
->devPrivates
,
987 RecordClientPrivateKey
, NULL
);
990 } /* end if this RCAP specifies any requests */
991 } /* end if not future clients */
995 client
= (i
< pRCAP
->numClients
) ? pRCAP
->pClientIDs
[i
++] : 0;
998 assert(numEnabledRCAPs
>= 1);
999 if (!oneclient
&& --numEnabledRCAPs
== 0) { /* we're disabling the last context */
1000 DeleteCallback(&EventCallback
, RecordADeliveredEventOrError
, NULL
);
1001 DeleteCallback(&DeviceEventCallback
, RecordADeviceEvent
, NULL
);
1002 DeleteCallback(&ReplyCallback
, RecordAReply
, NULL
);
1003 DeleteCallback(&FlushCallback
, RecordFlushAllContexts
, NULL
);
1004 /* Alternate context flushing scheme: delete the line above
1005 * and call RemoveBlockAndWakeupHandlers here passing
1006 * RecordFlushAllContexts. Is this any better?
1008 /* Having deleted the callback, call it one last time. -gildea */
1009 RecordFlushAllContexts(&FlushCallback
, NULL
, NULL
);
1011 } /* RecordUninstallHooks */
1013 /* RecordDeleteClientFromRCAP
1016 * pRCAP is an RCAP to delete the client from.
1017 * position is the index into the array pRCAP->pClientIDs of the
1023 * Recording hooks needed by client will be uninstalled if the context
1024 * is enabled. The designated client will be removed from the
1025 * pRCAP->pClientIDs array. If it was the only client on the RCAP,
1026 * the RCAP is removed from the context and freed. (Invariant: RCAPs
1027 * have at least one client.)
1030 RecordDeleteClientFromRCAP(RecordClientsAndProtocolPtr pRCAP
, int position
)
1032 if (pRCAP
->pContext
->pRecordingClient
)
1033 RecordUninstallHooks(pRCAP
, pRCAP
->pClientIDs
[position
]);
1034 if (position
!= pRCAP
->numClients
- 1)
1035 pRCAP
->pClientIDs
[position
] = pRCAP
->pClientIDs
[pRCAP
->numClients
- 1];
1036 if (--pRCAP
->numClients
== 0) { /* no more clients; remove RCAP from context's list */
1037 RecordContextPtr pContext
= pRCAP
->pContext
;
1039 if (pContext
->pRecordingClient
)
1040 RecordUninstallHooks(pRCAP
, 0);
1041 if (pContext
->pListOfRCAP
== pRCAP
)
1042 pContext
->pListOfRCAP
= pRCAP
->pNextRCAP
;
1044 RecordClientsAndProtocolPtr prevRCAP
;
1046 for (prevRCAP
= pContext
->pListOfRCAP
;
1047 prevRCAP
->pNextRCAP
!= pRCAP
; prevRCAP
= prevRCAP
->pNextRCAP
);
1048 prevRCAP
->pNextRCAP
= pRCAP
->pNextRCAP
;
1051 if (pRCAP
->clientIDsSeparatelyAllocated
)
1052 free(pRCAP
->pClientIDs
);
1055 } /* RecordDeleteClientFromRCAP */
1057 /* RecordAddClientToRCAP
1060 * pRCAP is an RCAP to add the client to.
1061 * clientspec is the resource ID mask identifying a client, or
1062 * XRecordFutureClients.
1067 * Recording hooks needed by client will be installed if the context
1068 * is enabled. The designated client will be added to the
1069 * pRCAP->pClientIDs array, which may be realloced.
1070 * pRCAP->clientIDsSeparatelyAllocated may be set to 1 if there
1071 * is no more room to hold clients internal to the RCAP.
1074 RecordAddClientToRCAP(RecordClientsAndProtocolPtr pRCAP
, XID clientspec
)
1076 if (pRCAP
->numClients
== pRCAP
->sizeClients
) {
1077 if (pRCAP
->clientIDsSeparatelyAllocated
) {
1078 XID
*pNewIDs
= (XID
*) realloc(pRCAP
->pClientIDs
,
1079 (pRCAP
->sizeClients
+
1080 CLIENT_ARRAY_GROWTH_INCREMENT
) *
1084 pRCAP
->pClientIDs
= pNewIDs
;
1085 pRCAP
->sizeClients
+= CLIENT_ARRAY_GROWTH_INCREMENT
;
1088 XID
*pNewIDs
= (XID
*) malloc((pRCAP
->sizeClients
+
1089 CLIENT_ARRAY_GROWTH_INCREMENT
) *
1093 memcpy(pNewIDs
, pRCAP
->pClientIDs
, pRCAP
->numClients
* sizeof(XID
));
1094 pRCAP
->pClientIDs
= pNewIDs
;
1095 pRCAP
->sizeClients
+= CLIENT_ARRAY_GROWTH_INCREMENT
;
1096 pRCAP
->clientIDsSeparatelyAllocated
= 1;
1099 pRCAP
->pClientIDs
[pRCAP
->numClients
++] = clientspec
;
1100 if (pRCAP
->pContext
->pRecordingClient
)
1101 RecordInstallHooks(pRCAP
, clientspec
);
1102 } /* RecordDeleteClientFromRCAP */
1104 /* RecordDeleteClientFromContext
1107 * pContext is the context to delete from.
1108 * clientspec is the resource ID mask identifying a client, or
1109 * XRecordFutureClients.
1114 * If clientspec is on any RCAP of the context, it is deleted from that
1115 * RCAP. (A given clientspec can only be on one RCAP of a context.)
1118 RecordDeleteClientFromContext(RecordContextPtr pContext
, XID clientspec
)
1120 RecordClientsAndProtocolPtr pRCAP
;
1123 if ((pRCAP
= RecordFindClientOnContext(pContext
, clientspec
, &position
)))
1124 RecordDeleteClientFromRCAP(pRCAP
, position
);
1125 } /* RecordDeleteClientFromContext */
1127 /* RecordSanityCheckClientSpecifiers
1130 * clientspecs is an array of alleged CLIENTSPECs passed by the client.
1131 * nspecs is the number of elements in clientspecs.
1132 * errorspec, if non-zero, is the resource id base of a client that
1133 * must not appear in clienspecs.
1135 * Returns: BadMatch if any of the clientspecs are invalid, else Success.
1137 * Side Effects: none.
1140 RecordSanityCheckClientSpecifiers(ClientPtr client
, XID
*clientspecs
,
1141 int nspecs
, XID errorspec
)
1148 for (i
= 0; i
< nspecs
; i
++) {
1149 if (clientspecs
[i
] == XRecordCurrentClients
||
1150 clientspecs
[i
] == XRecordFutureClients
||
1151 clientspecs
[i
] == XRecordAllClients
)
1153 if (errorspec
&& (CLIENT_BITS(clientspecs
[i
]) == errorspec
))
1155 clientIndex
= CLIENT_ID(clientspecs
[i
]);
1156 if (clientIndex
&& clients
[clientIndex
] &&
1157 clients
[clientIndex
]->clientState
== ClientStateRunning
) {
1158 if (clientspecs
[i
] == clients
[clientIndex
]->clientAsMask
)
1160 rc
= dixLookupResourceByClass(&value
, clientspecs
[i
], RC_ANY
,
1161 client
, DixGetAttrAccess
);
1169 } /* RecordSanityCheckClientSpecifiers */
1171 /* RecordCanonicalizeClientSpecifiers
1174 * pClientspecs is an array of CLIENTSPECs that have been sanity
1176 * pNumClientspecs is a pointer to the number of elements in pClientspecs.
1177 * excludespec, if non-zero, is the resource id base of a client that
1178 * should not be included in the expansion of XRecordAllClients or
1179 * XRecordCurrentClients.
1182 * A pointer to an array of CLIENTSPECs that is the same as the
1183 * passed array with the following modifications:
1184 * - all but the client id bits of resource IDs are stripped off.
1185 * - duplicates removed.
1186 * - XRecordAllClients expanded to a list of all currently connected
1187 * clients + XRecordFutureClients - excludespec (if non-zero)
1188 * - XRecordCurrentClients expanded to a list of all currently
1189 * connected clients - excludespec (if non-zero)
1190 * The returned array may be the passed array modified in place, or
1191 * it may be an malloc'ed array. The caller should keep a pointer to the
1192 * original array and free the returned array if it is different.
1194 * *pNumClientspecs is set to the number of elements in the returned
1198 * pClientspecs may be modified in place.
1201 RecordCanonicalizeClientSpecifiers(XID
*pClientspecs
, int *pNumClientspecs
,
1205 int numClients
= *pNumClientspecs
;
1207 /* first pass strips off the resource index bits, leaving just the
1208 * client id bits. This makes searching for a particular client simpler
1211 for (i
= 0; i
< numClients
; i
++) {
1212 XID cs
= pClientspecs
[i
];
1214 if (cs
> XRecordAllClients
)
1215 pClientspecs
[i
] = CLIENT_BITS(cs
);
1218 for (i
= 0; i
< numClients
; i
++) {
1219 if (pClientspecs
[i
] == XRecordAllClients
|| pClientspecs
[i
] == XRecordCurrentClients
) { /* expand All/Current */
1221 XID
*pCanon
= (XID
*) malloc(sizeof(XID
) * (currentMaxClients
+ 1));
1225 for (nc
= 0, j
= 1; j
< currentMaxClients
; j
++) {
1226 ClientPtr client
= clients
[j
];
1228 if (client
!= NullClient
&&
1229 client
->clientState
== ClientStateRunning
&&
1230 client
->clientAsMask
!= excludespec
) {
1231 pCanon
[nc
++] = client
->clientAsMask
;
1234 if (pClientspecs
[i
] == XRecordAllClients
)
1235 pCanon
[nc
++] = XRecordFutureClients
;
1236 *pNumClientspecs
= nc
;
1239 else { /* not All or Current */
1243 for (j
= i
+ 1; j
< numClients
;) {
1244 if (pClientspecs
[i
] == pClientspecs
[j
]) {
1245 pClientspecs
[j
] = pClientspecs
[--numClients
];
1251 } /* end for each clientspec */
1252 *pNumClientspecs
= numClients
;
1253 return pClientspecs
;
1254 } /* RecordCanonicalizeClientSpecifiers */
1256 /****************************************************************************/
1258 /* stuff for RegisterClients */
1263 * size is the number of bytes taken by an object.
1264 * align is a byte boundary (e.g. 4, 8)
1267 * the number of pad bytes to add at the end of an object of the
1268 * given size so that an object placed immediately behind it will
1269 * begin on an <align>-byte boundary.
1271 * Side Effects: none.
1274 RecordPadAlign(int size
, int align
)
1276 return (align
- (size
& (align
- 1))) & (align
- 1);
1277 } /* RecordPadAlign */
1279 /* RecordSanityCheckRegisterClients
1282 * pContext is the context being registered on.
1283 * client is the client that issued a RecordCreateContext or
1284 * RecordRegisterClients request.
1285 * stuff is a pointer to the request.
1288 * Any one of several possible error values if any of the request
1289 * arguments are invalid. Success if everything is OK.
1291 * Side Effects: none.
1294 RecordSanityCheckRegisterClients(RecordContextPtr pContext
, ClientPtr client
,
1295 xRecordRegisterClientsReq
* stuff
)
1298 xRecordRange
*pRange
;
1300 XID recordingClient
;
1302 if (((client
->req_len
<< 2) - SIZEOF(xRecordRegisterClientsReq
)) !=
1303 4 * stuff
->nClients
+ SIZEOF(xRecordRange
) * stuff
->nRanges
)
1306 if (stuff
->elementHeader
&
1307 ~(XRecordFromClientSequence
| XRecordFromClientTime
|
1308 XRecordFromServerTime
)) {
1309 client
->errorValue
= stuff
->elementHeader
;
1313 recordingClient
= pContext
->pRecordingClient
?
1314 pContext
->pRecordingClient
->clientAsMask
: 0;
1315 err
= RecordSanityCheckClientSpecifiers(client
, (XID
*) &stuff
[1],
1316 stuff
->nClients
, recordingClient
);
1320 pRange
= (xRecordRange
*) (((XID
*) &stuff
[1]) + stuff
->nClients
);
1321 for (i
= 0; i
< stuff
->nRanges
; i
++, pRange
++) {
1322 if (pRange
->coreRequestsFirst
> pRange
->coreRequestsLast
) {
1323 client
->errorValue
= pRange
->coreRequestsFirst
;
1326 if (pRange
->coreRepliesFirst
> pRange
->coreRepliesLast
) {
1327 client
->errorValue
= pRange
->coreRepliesFirst
;
1330 if ((pRange
->extRequestsMajorFirst
|| pRange
->extRequestsMajorLast
) &&
1331 (pRange
->extRequestsMajorFirst
< 128 ||
1332 pRange
->extRequestsMajorLast
< 128 ||
1333 pRange
->extRequestsMajorFirst
> pRange
->extRequestsMajorLast
)) {
1334 client
->errorValue
= pRange
->extRequestsMajorFirst
;
1337 if (pRange
->extRequestsMinorFirst
> pRange
->extRequestsMinorLast
) {
1338 client
->errorValue
= pRange
->extRequestsMinorFirst
;
1341 if ((pRange
->extRepliesMajorFirst
|| pRange
->extRepliesMajorLast
) &&
1342 (pRange
->extRepliesMajorFirst
< 128 ||
1343 pRange
->extRepliesMajorLast
< 128 ||
1344 pRange
->extRepliesMajorFirst
> pRange
->extRepliesMajorLast
)) {
1345 client
->errorValue
= pRange
->extRepliesMajorFirst
;
1348 if (pRange
->extRepliesMinorFirst
> pRange
->extRepliesMinorLast
) {
1349 client
->errorValue
= pRange
->extRepliesMinorFirst
;
1352 if ((pRange
->deliveredEventsFirst
|| pRange
->deliveredEventsLast
) &&
1353 (pRange
->deliveredEventsFirst
< 2 ||
1354 pRange
->deliveredEventsLast
< 2 ||
1355 pRange
->deliveredEventsFirst
> pRange
->deliveredEventsLast
)) {
1356 client
->errorValue
= pRange
->deliveredEventsFirst
;
1359 if ((pRange
->deviceEventsFirst
|| pRange
->deviceEventsLast
) &&
1360 (pRange
->deviceEventsFirst
< 2 ||
1361 pRange
->deviceEventsLast
< 2 ||
1362 pRange
->deviceEventsFirst
> pRange
->deviceEventsLast
)) {
1363 client
->errorValue
= pRange
->deviceEventsFirst
;
1366 if (pRange
->errorsFirst
> pRange
->errorsLast
) {
1367 client
->errorValue
= pRange
->errorsFirst
;
1370 if (pRange
->clientStarted
!= xFalse
&& pRange
->clientStarted
!= xTrue
) {
1371 client
->errorValue
= pRange
->clientStarted
;
1374 if (pRange
->clientDied
!= xFalse
&& pRange
->clientDied
!= xTrue
) {
1375 client
->errorValue
= pRange
->clientDied
;
1378 } /* end for each range */
1380 } /* end RecordSanityCheckRegisterClients */
1382 /* This is a tactical structure used to gather information about all the sets
1383 * (RecordSetPtr) that need to be created for an RCAP in the process of
1384 * digesting a list of RECORDRANGEs (converting it to the internal
1388 int nintervals
; /* number of intervals in following array */
1389 RecordSetInterval
*intervals
; /* array of intervals for this set */
1390 int size
; /* size of intevals array; >= nintervals */
1391 int align
; /* alignment restriction for set */
1392 int offset
; /* where to store set pointer rel. to start of RCAP */
1393 short first
, last
; /* if for extension, major opcode interval */
1394 } SetInfoRec
, *SetInfoPtr
;
1396 #if defined(ERR) && defined(__sun)
1397 #undef ERR /* Avoid conflict with Solaris <sys/regset.h> */
1400 /* These constant are used to index into an array of SetInfoRec. */
1401 enum { REQ
, /* set info for requests */
1402 REP
, /* set info for replies */
1403 ERR
, /* set info for errors */
1404 DEV
, /* set info for device events */
1405 DLEV
, /* set info for delivered events */
1407 }; /* number of predefined array entries */
1409 /* RecordAllocIntervals
1412 * psi is a pointer to a SetInfoRec whose intervals pointer is NULL.
1413 * nIntervals is the desired size of the intervals array.
1415 * Returns: BadAlloc if a memory allocation error occurred, else Success.
1418 * If Success is returned, psi->intervals is a pointer to size
1419 * RecordSetIntervals, all zeroed, and psi->size is set to size.
1422 RecordAllocIntervals(SetInfoPtr psi
, int nIntervals
)
1424 assert(!psi
->intervals
);
1425 psi
->intervals
= (RecordSetInterval
*)
1426 malloc(nIntervals
* sizeof(RecordSetInterval
));
1427 if (!psi
->intervals
)
1429 memset(psi
->intervals
, 0, nIntervals
* sizeof(RecordSetInterval
));
1430 psi
->size
= nIntervals
;
1432 } /* end RecordAllocIntervals */
1434 /* RecordConvertRangesToIntervals
1437 * psi is a pointer to the SetInfoRec we are building.
1438 * pRanges is an array of xRecordRanges.
1439 * nRanges is the number of elements in pRanges.
1440 * byteoffset is the offset from the start of an xRecordRange of the
1441 * two bytes (1 for first, 1 for last) we are interested in.
1442 * pExtSetInfo, if non-NULL, indicates that the two bytes mentioned
1443 * above are followed by four bytes (2 for first, 2 for last)
1444 * representing a minor opcode range, and this information should be
1445 * stored in one of the SetInfoRecs starting at pExtSetInfo.
1446 * pnExtSetInfo is the number of elements in the pExtSetInfo array.
1448 * Returns: BadAlloc if a memory allocation error occurred, else Success.
1451 * The slice of pRanges indicated by byteoffset is stored in psi.
1452 * If pExtSetInfo is non-NULL, minor opcode intervals are stored
1453 * in an existing SetInfoRec if the major opcode interval matches, else
1454 * they are stored in a new SetInfoRec, and *pnExtSetInfo is
1455 * increased accordingly.
1458 RecordConvertRangesToIntervals(SetInfoPtr psi
,
1459 xRecordRange
* pRanges
,
1462 SetInfoPtr pExtSetInfo
, int *pnExtSetInfo
)
1469 for (i
= 0; i
< nRanges
; i
++, pRanges
++) {
1470 pCARD8
= ((CARD8
*) pRanges
) + byteoffset
;
1473 if (first
|| last
) {
1474 if (!psi
->intervals
) {
1475 err
= RecordAllocIntervals(psi
, 2 * (nRanges
- i
));
1479 psi
->intervals
[psi
->nintervals
].first
= first
;
1480 psi
->intervals
[psi
->nintervals
].last
= last
;
1482 assert(psi
->nintervals
<= psi
->size
);
1484 SetInfoPtr pesi
= pExtSetInfo
;
1485 CARD16
*pCARD16
= (CARD16
*) (pCARD8
+ 2);
1488 for (j
= 0; j
< *pnExtSetInfo
; j
++, pesi
++) {
1489 if ((first
== pesi
->first
) && (last
== pesi
->last
))
1492 if (j
== *pnExtSetInfo
) {
1493 err
= RecordAllocIntervals(pesi
, 2 * (nRanges
- i
));
1496 pesi
->first
= first
;
1500 pesi
->intervals
[pesi
->nintervals
].first
= pCARD16
[0];
1501 pesi
->intervals
[pesi
->nintervals
].last
= pCARD16
[1];
1503 assert(pesi
->nintervals
<= pesi
->size
);
1508 } /* end RecordConvertRangesToIntervals */
1510 #define offset_of(_structure, _field) \
1511 ((char *)(& (_structure . _field)) - (char *)(&_structure))
1513 /* RecordRegisterClients
1516 * pContext is the context on which to register the clients.
1517 * client is the client that issued the RecordCreateContext or
1518 * RecordRegisterClients request.
1519 * stuff is a pointer to the request.
1522 * Any one of several possible error values defined by the protocol.
1523 * Success if everything is OK.
1526 * If different element headers are specified, the context is flushed.
1527 * If any of the specified clients are already registered on the
1528 * context, they are first unregistered. A new RCAP is created to
1529 * hold the specified protocol and clients, and it is linked onto the
1530 * context. If the context is enabled, appropriate hooks are installed
1531 * to record the new clients and protocol.
1534 RecordRegisterClients(RecordContextPtr pContext
, ClientPtr client
,
1535 xRecordRegisterClientsReq
* stuff
)
1541 int nExtReqSets
= 0;
1542 int nExtRepSets
= 0;
1543 int extReqSetsOffset
= 0;
1544 int extRepSetsOffset
= 0;
1545 SetInfoPtr pExtReqSets
, pExtRepSets
;
1546 int clientListOffset
;
1548 int clientStarted
= 0, clientDied
= 0;
1549 xRecordRange
*pRanges
, rr
;
1553 RecordClientsAndProtocolPtr pRCAP
;
1555 XID recordingClient
;
1557 /* do all sanity checking up front */
1559 err
= RecordSanityCheckRegisterClients(pContext
, client
, stuff
);
1563 /* if element headers changed, flush buffer */
1565 if (pContext
->elemHeaders
!= stuff
->elementHeader
) {
1566 RecordFlushReplyBuffer(pContext
, NULL
, 0, NULL
, 0);
1567 pContext
->elemHeaders
= stuff
->elementHeader
;
1570 nClients
= stuff
->nClients
;
1572 /* if empty clients list, we're done. */
1575 recordingClient
= pContext
->pRecordingClient
?
1576 pContext
->pRecordingClient
->clientAsMask
: 0;
1577 pCanonClients
= RecordCanonicalizeClientSpecifiers((XID
*) &stuff
[1],
1583 /* We may have to create as many as one set for each "predefined"
1584 * protocol types, plus one per range for extension reuests, plus one per
1585 * range for extension replies.
1587 maxSets
= PREDEFSETS
+ 2 * stuff
->nRanges
;
1588 si
= (SetInfoPtr
) malloc(sizeof(SetInfoRec
) * maxSets
);
1593 memset(si
, 0, sizeof(SetInfoRec
) * maxSets
);
1595 /* theoretically you must do this because NULL may not be all-bits-zero */
1596 for (i
= 0; i
< maxSets
; i
++)
1597 si
[i
].intervals
= NULL
;
1599 pExtReqSets
= si
+ PREDEFSETS
;
1600 pExtRepSets
= pExtReqSets
+ stuff
->nRanges
;
1602 pRanges
= (xRecordRange
*) (((XID
*) &stuff
[1]) + stuff
->nClients
);
1604 err
= RecordConvertRangesToIntervals(&si
[REQ
], pRanges
, stuff
->nRanges
,
1605 offset_of(rr
, coreRequestsFirst
), NULL
,
1610 err
= RecordConvertRangesToIntervals(&si
[REQ
], pRanges
, stuff
->nRanges
,
1611 offset_of(rr
, extRequestsMajorFirst
),
1612 pExtReqSets
, &nExtReqSets
);
1616 err
= RecordConvertRangesToIntervals(&si
[REP
], pRanges
, stuff
->nRanges
,
1617 offset_of(rr
, coreRepliesFirst
), NULL
,
1622 err
= RecordConvertRangesToIntervals(&si
[REP
], pRanges
, stuff
->nRanges
,
1623 offset_of(rr
, extRepliesMajorFirst
),
1624 pExtRepSets
, &nExtRepSets
);
1628 err
= RecordConvertRangesToIntervals(&si
[ERR
], pRanges
, stuff
->nRanges
,
1629 offset_of(rr
, errorsFirst
), NULL
,
1634 err
= RecordConvertRangesToIntervals(&si
[DLEV
], pRanges
, stuff
->nRanges
,
1635 offset_of(rr
, deliveredEventsFirst
),
1640 err
= RecordConvertRangesToIntervals(&si
[DEV
], pRanges
, stuff
->nRanges
,
1641 offset_of(rr
, deviceEventsFirst
), NULL
,
1646 /* collect client-started and client-died */
1648 for (i
= 0; i
< stuff
->nRanges
; i
++) {
1649 if (pRanges
[i
].clientStarted
)
1650 clientStarted
= TRUE
;
1651 if (pRanges
[i
].clientDied
)
1655 /* We now have all the information collected to create all the sets,
1656 * and we can compute the total memory required for the RCAP.
1659 totRCAPsize
= sizeof(RecordClientsAndProtocolRec
);
1661 /* leave a little room to grow before forcing a separate allocation */
1662 sizeClients
= nClients
+ CLIENT_ARRAY_GROWTH_INCREMENT
;
1663 pad
= RecordPadAlign(totRCAPsize
, sizeof(XID
));
1664 clientListOffset
= totRCAPsize
+ pad
;
1665 totRCAPsize
+= pad
+ sizeClients
* sizeof(XID
);
1668 pad
= RecordPadAlign(totRCAPsize
, sizeof(RecordSetPtr
));
1669 extReqSetsOffset
= totRCAPsize
+ pad
;
1670 totRCAPsize
+= pad
+ (nExtReqSets
+ 1) * sizeof(RecordMinorOpRec
);
1673 pad
= RecordPadAlign(totRCAPsize
, sizeof(RecordSetPtr
));
1674 extRepSetsOffset
= totRCAPsize
+ pad
;
1675 totRCAPsize
+= pad
+ (nExtRepSets
+ 1) * sizeof(RecordMinorOpRec
);
1678 for (i
= 0; i
< maxSets
; i
++) {
1679 if (si
[i
].nintervals
) {
1681 RecordSetMemoryRequirements(si
[i
].intervals
, si
[i
].nintervals
,
1683 pad
= RecordPadAlign(totRCAPsize
, si
[i
].align
);
1684 si
[i
].offset
= pad
+ totRCAPsize
;
1685 totRCAPsize
+= pad
+ si
[i
].size
;
1689 /* allocate memory for the whole RCAP */
1691 pRCAP
= (RecordClientsAndProtocolPtr
) malloc(totRCAPsize
);
1697 /* fill in the RCAP */
1699 pRCAP
->pContext
= pContext
;
1700 pRCAP
->pClientIDs
= (XID
*) ((char *) pRCAP
+ clientListOffset
);
1701 pRCAP
->numClients
= nClients
;
1702 pRCAP
->sizeClients
= sizeClients
;
1703 pRCAP
->clientIDsSeparatelyAllocated
= 0;
1704 for (i
= 0; i
< nClients
; i
++) {
1705 RecordDeleteClientFromContext(pContext
, pCanonClients
[i
]);
1706 pRCAP
->pClientIDs
[i
] = pCanonClients
[i
];
1709 /* create all the sets */
1711 if (si
[REQ
].intervals
) {
1712 pRCAP
->pRequestMajorOpSet
=
1713 RecordCreateSet(si
[REQ
].intervals
, si
[REQ
].nintervals
,
1714 (RecordSetPtr
) ((char *) pRCAP
+ si
[REQ
].offset
),
1718 pRCAP
->pRequestMajorOpSet
= NULL
;
1720 if (si
[REP
].intervals
) {
1721 pRCAP
->pReplyMajorOpSet
=
1722 RecordCreateSet(si
[REP
].intervals
, si
[REP
].nintervals
,
1723 (RecordSetPtr
) ((char *) pRCAP
+ si
[REP
].offset
),
1727 pRCAP
->pReplyMajorOpSet
= NULL
;
1729 if (si
[ERR
].intervals
) {
1731 RecordCreateSet(si
[ERR
].intervals
, si
[ERR
].nintervals
,
1732 (RecordSetPtr
) ((char *) pRCAP
+ si
[ERR
].offset
),
1736 pRCAP
->pErrorSet
= NULL
;
1738 if (si
[DEV
].intervals
) {
1739 pRCAP
->pDeviceEventSet
=
1740 RecordCreateSet(si
[DEV
].intervals
, si
[DEV
].nintervals
,
1741 (RecordSetPtr
) ((char *) pRCAP
+ si
[DEV
].offset
),
1745 pRCAP
->pDeviceEventSet
= NULL
;
1747 if (si
[DLEV
].intervals
) {
1748 pRCAP
->pDeliveredEventSet
=
1749 RecordCreateSet(si
[DLEV
].intervals
, si
[DLEV
].nintervals
,
1750 (RecordSetPtr
) ((char *) pRCAP
+ si
[DLEV
].offset
),
1754 pRCAP
->pDeliveredEventSet
= NULL
;
1757 pRCAP
->pRequestMinOpInfo
= (RecordMinorOpPtr
)
1758 ((char *) pRCAP
+ extReqSetsOffset
);
1759 pRCAP
->pRequestMinOpInfo
[0].count
= nExtReqSets
;
1760 for (i
= 0; i
< nExtReqSets
; i
++, pExtReqSets
++) {
1761 pRCAP
->pRequestMinOpInfo
[i
+ 1].major
.first
= pExtReqSets
->first
;
1762 pRCAP
->pRequestMinOpInfo
[i
+ 1].major
.last
= pExtReqSets
->last
;
1763 pRCAP
->pRequestMinOpInfo
[i
+ 1].major
.pMinOpSet
=
1764 RecordCreateSet(pExtReqSets
->intervals
,
1765 pExtReqSets
->nintervals
,
1766 (RecordSetPtr
) ((char *) pRCAP
+
1767 pExtReqSets
->offset
),
1772 pRCAP
->pRequestMinOpInfo
= NULL
;
1775 pRCAP
->pReplyMinOpInfo
= (RecordMinorOpPtr
)
1776 ((char *) pRCAP
+ extRepSetsOffset
);
1777 pRCAP
->pReplyMinOpInfo
[0].count
= nExtRepSets
;
1778 for (i
= 0; i
< nExtRepSets
; i
++, pExtRepSets
++) {
1779 pRCAP
->pReplyMinOpInfo
[i
+ 1].major
.first
= pExtRepSets
->first
;
1780 pRCAP
->pReplyMinOpInfo
[i
+ 1].major
.last
= pExtRepSets
->last
;
1781 pRCAP
->pReplyMinOpInfo
[i
+ 1].major
.pMinOpSet
=
1782 RecordCreateSet(pExtRepSets
->intervals
,
1783 pExtRepSets
->nintervals
,
1784 (RecordSetPtr
) ((char *) pRCAP
+
1785 pExtRepSets
->offset
),
1790 pRCAP
->pReplyMinOpInfo
= NULL
;
1792 pRCAP
->clientStarted
= clientStarted
;
1793 pRCAP
->clientDied
= clientDied
;
1795 /* link the RCAP onto the context */
1797 pRCAP
->pNextRCAP
= pContext
->pListOfRCAP
;
1798 pContext
->pListOfRCAP
= pRCAP
;
1800 if (pContext
->pRecordingClient
) /* context enabled */
1801 RecordInstallHooks(pRCAP
, 0);
1805 for (i
= 0; i
< maxSets
; i
++)
1806 free(si
[i
].intervals
);
1809 if (pCanonClients
&& pCanonClients
!= (XID
*) &stuff
[1])
1810 free(pCanonClients
);
1812 } /* RecordRegisterClients */
1814 /* Proc functions all take a client argument, execute the request in
1815 * client->requestBuffer, and return a protocol error status.
1819 ProcRecordQueryVersion(ClientPtr client
)
1821 /* REQUEST(xRecordQueryVersionReq); */
1822 xRecordQueryVersionReply rep
= {
1824 .sequenceNumber
= client
->sequence
,
1826 .majorVersion
= SERVER_RECORD_MAJOR_VERSION
,
1827 .minorVersion
= SERVER_RECORD_MINOR_VERSION
1830 REQUEST_SIZE_MATCH(xRecordQueryVersionReq
);
1831 if (client
->swapped
) {
1832 swaps(&rep
.sequenceNumber
);
1833 swaps(&rep
.majorVersion
);
1834 swaps(&rep
.minorVersion
);
1836 WriteToClient(client
, sizeof(xRecordQueryVersionReply
), &rep
);
1838 } /* ProcRecordQueryVersion */
1841 ProcRecordCreateContext(ClientPtr client
)
1843 REQUEST(xRecordCreateContextReq
);
1844 RecordContextPtr pContext
;
1845 RecordContextPtr
*ppNewAllContexts
= NULL
;
1848 REQUEST_AT_LEAST_SIZE(xRecordCreateContextReq
);
1849 LEGAL_NEW_RESOURCE(stuff
->context
, client
);
1851 pContext
= (RecordContextPtr
) malloc(sizeof(RecordContextRec
));
1855 /* make sure there is room in ppAllContexts to store the new context */
1857 ppNewAllContexts
= (RecordContextPtr
*)
1858 realloc(ppAllContexts
, sizeof(RecordContextPtr
) * (numContexts
+ 1));
1859 if (!ppNewAllContexts
)
1861 ppAllContexts
= ppNewAllContexts
;
1863 pContext
->id
= stuff
->context
;
1864 pContext
->pRecordingClient
= NULL
;
1865 pContext
->pListOfRCAP
= NULL
;
1866 pContext
->elemHeaders
= 0;
1867 pContext
->bufCategory
= 0;
1868 pContext
->numBufBytes
= 0;
1869 pContext
->pBufClient
= NULL
;
1870 pContext
->continuedReply
= 0;
1871 pContext
->inFlush
= 0;
1873 err
= RecordRegisterClients(pContext
, client
,
1874 (xRecordRegisterClientsReq
*) stuff
);
1878 if (AddResource(pContext
->id
, RTContext
, pContext
)) {
1879 ppAllContexts
[numContexts
++] = pContext
;
1883 RecordDeleteContext((pointer
) pContext
, pContext
->id
);
1889 } /* ProcRecordCreateContext */
1892 ProcRecordRegisterClients(ClientPtr client
)
1894 RecordContextPtr pContext
;
1896 REQUEST(xRecordRegisterClientsReq
);
1898 REQUEST_AT_LEAST_SIZE(xRecordRegisterClientsReq
);
1899 VERIFY_CONTEXT(pContext
, stuff
->context
, client
);
1901 return RecordRegisterClients(pContext
, client
, stuff
);
1902 } /* ProcRecordRegisterClients */
1905 ProcRecordUnregisterClients(ClientPtr client
)
1907 RecordContextPtr pContext
;
1910 REQUEST(xRecordUnregisterClientsReq
);
1915 REQUEST_AT_LEAST_SIZE(xRecordUnregisterClientsReq
);
1916 if ((client
->req_len
<< 2) - SIZEOF(xRecordUnregisterClientsReq
) !=
1917 4 * stuff
->nClients
)
1919 VERIFY_CONTEXT(pContext
, stuff
->context
, client
);
1920 err
= RecordSanityCheckClientSpecifiers(client
, (XID
*) &stuff
[1],
1921 stuff
->nClients
, 0);
1925 nClients
= stuff
->nClients
;
1926 pCanonClients
= RecordCanonicalizeClientSpecifiers((XID
*) &stuff
[1],
1931 for (i
= 0; i
< nClients
; i
++) {
1932 RecordDeleteClientFromContext(pContext
, pCanonClients
[i
]);
1934 if (pCanonClients
!= (XID
*) &stuff
[1])
1935 free(pCanonClients
);
1937 } /* ProcRecordUnregisterClients */
1939 /****************************************************************************/
1941 /* stuff for GetContext */
1943 /* This is a tactical structure used to hold the xRecordRanges as they are
1944 * being reconstituted from the sets in the RCAPs.
1948 xRecordRange
*pRanges
; /* array of xRecordRanges for one RCAP */
1949 int size
; /* number of elements in pRanges, >= nRanges */
1950 int nRanges
; /* number of occupied element of pRanges */
1951 } GetContextRangeInfoRec
, *GetContextRangeInfoPtr
;
1953 /* RecordAllocRanges
1956 * pri is a pointer to a GetContextRangeInfoRec to allocate for.
1957 * nRanges is the number of xRecordRanges desired for pri.
1959 * Returns: BadAlloc if a memory allocation error occurred, else Success.
1962 * If Success is returned, pri->pRanges points to at least nRanges
1963 * ranges. pri->nRanges is set to nRanges. pri->size is the actual
1964 * number of ranges. Newly allocated ranges are zeroed.
1967 RecordAllocRanges(GetContextRangeInfoPtr pri
, int nRanges
)
1970 xRecordRange
*pNewRange
;
1974 newsize
= max(pri
->size
+ SZINCR
, nRanges
);
1975 pNewRange
= (xRecordRange
*) realloc(pri
->pRanges
,
1976 newsize
* sizeof(xRecordRange
));
1980 pri
->pRanges
= pNewRange
;
1981 pri
->size
= newsize
;
1982 memset(&pri
->pRanges
[pri
->size
- SZINCR
], 0, SZINCR
* sizeof(xRecordRange
));
1983 if (pri
->nRanges
< nRanges
)
1984 pri
->nRanges
= nRanges
;
1986 } /* RecordAllocRanges */
1988 /* RecordConvertSetToRanges
1991 * pSet is the set to be converted.
1992 * pri is where the result should be stored.
1993 * byteoffset is the offset from the start of an xRecordRange of the
1994 * two vales (first, last) we are interested in.
1995 * card8 is TRUE if the vales are one byte each and FALSE if two bytes
1997 * imax is the largest set value to store in pri->pRanges.
1998 * pStartIndex, if non-NULL, is the index of the first range in
1999 * pri->pRanges that should be stored to. If NULL,
2002 * Returns: BadAlloc if a memory allocation error occurred, else Success.
2005 * If Success is returned, the slice of pri->pRanges indicated by
2006 * byteoffset and card8 is filled in with the intervals from pSet.
2007 * if pStartIndex was non-NULL, *pStartIndex is filled in with one
2008 * more than the index of the last xRecordRange that was touched.
2011 RecordConvertSetToRanges(RecordSetPtr pSet
,
2012 GetContextRangeInfoPtr pri
,
2014 Bool card8
, unsigned int imax
, int *pStartIndex
)
2017 RecordSetIteratePtr pIter
= NULL
;
2018 RecordSetInterval interval
;
2026 nRanges
= pStartIndex
? *pStartIndex
: 0;
2027 while ((pIter
= RecordIterateSet(pSet
, pIter
, &interval
))) {
2028 if (interval
.first
> imax
)
2030 if (interval
.last
> imax
)
2031 interval
.last
= imax
;
2033 if (nRanges
> pri
->size
) {
2034 err
= RecordAllocRanges(pri
, nRanges
);
2039 pri
->nRanges
= max(pri
->nRanges
, nRanges
);
2041 pCARD8
= ((CARD8
*) &pri
->pRanges
[nRanges
- 1]) + byteoffset
;
2042 *pCARD8
++ = interval
.first
;
2043 *pCARD8
= interval
.last
;
2046 pCARD16
= (CARD16
*)
2047 (((char *) &pri
->pRanges
[nRanges
- 1]) + byteoffset
);
2048 *pCARD16
++ = interval
.first
;
2049 *pCARD16
= interval
.last
;
2053 *pStartIndex
= nRanges
;
2055 } /* RecordConvertSetToRanges */
2057 /* RecordConvertMinorOpInfoToRanges
2060 * pMinOpInfo is the minor opcode info to convert to xRecordRanges.
2061 * pri is where the result should be stored.
2062 * byteoffset is the offset from the start of an xRecordRange of the
2063 * four vales (CARD8 major_first, CARD8 major_last,
2064 * CARD16 minor_first, CARD16 minor_last) we are going to store.
2066 * Returns: BadAlloc if a memory allocation error occurred, else Success.
2069 * If Success is returned, the slice of pri->pRanges indicated by
2070 * byteoffset is filled in with the information from pMinOpInfo.
2073 RecordConvertMinorOpInfoToRanges(RecordMinorOpPtr pMinOpInfo
,
2074 GetContextRangeInfoPtr pri
, int byteoffset
)
2084 nsets
= pMinOpInfo
->count
;
2087 for (i
= 0; i
< nsets
; i
++) {
2091 err
= RecordConvertSetToRanges(pMinOpInfo
[i
].major
.pMinOpSet
, pri
,
2092 byteoffset
+ 2, FALSE
, 65535, &start
);
2095 for (j
= s
; j
< start
; j
++) {
2096 CARD8
*pCARD8
= ((CARD8
*) &pri
->pRanges
[j
]) + byteoffset
;
2098 *pCARD8
++ = pMinOpInfo
[i
].major
.first
;
2099 *pCARD8
= pMinOpInfo
[i
].major
.last
;
2103 } /* RecordConvertMinorOpInfoToRanges */
2108 * pRanges is an array of xRecordRanges.
2109 * nRanges is the number of elements in pRanges.
2114 * The 16 bit fields of each xRecordRange are byte swapped.
2117 RecordSwapRanges(xRecordRange
* pRanges
, int nRanges
)
2121 for (i
= 0; i
< nRanges
; i
++, pRanges
++) {
2122 swaps(&pRanges
->extRequestsMinorFirst
);
2123 swaps(&pRanges
->extRequestsMinorLast
);
2124 swaps(&pRanges
->extRepliesMinorFirst
);
2125 swaps(&pRanges
->extRepliesMinorLast
);
2127 } /* RecordSwapRanges */
2130 ProcRecordGetContext(ClientPtr client
)
2132 RecordContextPtr pContext
;
2134 REQUEST(xRecordGetContextReq
);
2135 xRecordGetContextReply rep
;
2136 RecordClientsAndProtocolPtr pRCAP
;
2138 GetContextRangeInfoPtr pRangeInfo
;
2139 GetContextRangeInfoPtr pri
;
2142 CARD32 nClients
, length
;
2144 REQUEST_SIZE_MATCH(xRecordGetContextReq
);
2145 VERIFY_CONTEXT(pContext
, stuff
->context
, client
);
2147 /* how many RCAPs are there on this context? */
2149 for (pRCAP
= pContext
->pListOfRCAP
; pRCAP
; pRCAP
= pRCAP
->pNextRCAP
)
2152 /* allocate and initialize space for record range info */
2155 (GetContextRangeInfoPtr
) malloc(nRCAPs
*
2156 sizeof(GetContextRangeInfoRec
));
2157 if (!pRangeInfo
&& nRCAPs
> 0)
2159 for (i
= 0; i
< nRCAPs
; i
++) {
2160 pRangeInfo
[i
].pRanges
= NULL
;
2161 pRangeInfo
[i
].size
= 0;
2162 pRangeInfo
[i
].nRanges
= 0;
2165 /* convert the RCAP (internal) representation of the recorded protocol
2166 * to the wire protocol (external) representation, storing the information
2167 * for the ith RCAP in pri[i]
2170 for (pRCAP
= pContext
->pListOfRCAP
, pri
= pRangeInfo
;
2171 pRCAP
; pRCAP
= pRCAP
->pNextRCAP
, pri
++) {
2174 err
= RecordConvertSetToRanges(pRCAP
->pRequestMajorOpSet
, pri
,
2175 offset_of(rr
, coreRequestsFirst
), TRUE
,
2180 err
= RecordConvertSetToRanges(pRCAP
->pReplyMajorOpSet
, pri
,
2181 offset_of(rr
, coreRepliesFirst
), TRUE
,
2186 err
= RecordConvertSetToRanges(pRCAP
->pDeliveredEventSet
, pri
,
2187 offset_of(rr
, deliveredEventsFirst
),
2192 err
= RecordConvertSetToRanges(pRCAP
->pDeviceEventSet
, pri
,
2193 offset_of(rr
, deviceEventsFirst
), TRUE
,
2198 err
= RecordConvertSetToRanges(pRCAP
->pErrorSet
, pri
,
2199 offset_of(rr
, errorsFirst
), TRUE
, 255,
2204 err
= RecordConvertMinorOpInfoToRanges(pRCAP
->pRequestMinOpInfo
,
2206 extRequestsMajorFirst
));
2210 err
= RecordConvertMinorOpInfoToRanges(pRCAP
->pReplyMinOpInfo
,
2212 extRepliesMajorFirst
));
2216 if (pRCAP
->clientStarted
|| pRCAP
->clientDied
) {
2217 if (pri
->nRanges
== 0)
2218 RecordAllocRanges(pri
, 1);
2219 pri
->pRanges
[0].clientStarted
= pRCAP
->clientStarted
;
2220 pri
->pRanges
[0].clientDied
= pRCAP
->clientDied
;
2224 /* calculate number of clients and reply length */
2228 for (pRCAP
= pContext
->pListOfRCAP
, pri
= pRangeInfo
;
2229 pRCAP
; pRCAP
= pRCAP
->pNextRCAP
, pri
++) {
2230 nClients
+= pRCAP
->numClients
;
2231 length
+= pRCAP
->numClients
*
2232 (bytes_to_int32(sizeof(xRecordClientInfo
)) +
2233 pri
->nRanges
* bytes_to_int32(sizeof(xRecordRange
)));
2236 /* write the reply header */
2238 rep
= (xRecordGetContextReply
) {
2240 .enabled
= pContext
->pRecordingClient
!= NULL
,
2241 .sequenceNumber
= client
->sequence
,
2243 .elementHeader
= pContext
->elemHeaders
,
2244 .nClients
= nClients
2246 if (client
->swapped
) {
2247 swaps(&rep
.sequenceNumber
);
2249 swapl(&rep
.nClients
);
2251 WriteToClient(client
, sizeof(xRecordGetContextReply
), &rep
);
2253 /* write all the CLIENT_INFOs */
2255 for (pRCAP
= pContext
->pListOfRCAP
, pri
= pRangeInfo
;
2256 pRCAP
; pRCAP
= pRCAP
->pNextRCAP
, pri
++) {
2257 xRecordClientInfo rci
;
2259 rci
.nRanges
= pri
->nRanges
;
2260 if (client
->swapped
) {
2261 swapl(&rci
.nRanges
);
2262 RecordSwapRanges(pri
->pRanges
, pri
->nRanges
);
2264 for (i
= 0; i
< pRCAP
->numClients
; i
++) {
2265 rci
.clientResource
= pRCAP
->pClientIDs
[i
];
2266 if (client
->swapped
)
2267 swapl(&rci
.clientResource
);
2268 WriteToClient(client
, sizeof(xRecordClientInfo
), &rci
);
2269 WriteToClient(client
, sizeof(xRecordRange
) * pri
->nRanges
,
2276 for (i
= 0; i
< nRCAPs
; i
++) {
2277 free(pRangeInfo
[i
].pRanges
);
2281 } /* ProcRecordGetContext */
2284 ProcRecordEnableContext(ClientPtr client
)
2286 RecordContextPtr pContext
;
2288 REQUEST(xRecordEnableContextReq
);
2290 RecordClientsAndProtocolPtr pRCAP
;
2292 REQUEST_SIZE_MATCH(xRecordGetContextReq
);
2293 VERIFY_CONTEXT(pContext
, stuff
->context
, client
);
2294 if (pContext
->pRecordingClient
)
2295 return BadMatch
; /* already enabled */
2297 /* install record hooks for each RCAP */
2299 for (pRCAP
= pContext
->pListOfRCAP
; pRCAP
; pRCAP
= pRCAP
->pNextRCAP
) {
2300 int err
= RecordInstallHooks(pRCAP
, 0);
2302 if (err
!= Success
) { /* undo the previous installs */
2303 RecordClientsAndProtocolPtr pUninstallRCAP
;
2305 for (pUninstallRCAP
= pContext
->pListOfRCAP
;
2306 pUninstallRCAP
!= pRCAP
;
2307 pUninstallRCAP
= pUninstallRCAP
->pNextRCAP
) {
2308 RecordUninstallHooks(pUninstallRCAP
, 0);
2314 /* Disallow further request processing on this connection until
2315 * the context is disabled.
2317 IgnoreClient(client
);
2318 pContext
->pRecordingClient
= client
;
2320 /* Don't allow the data connection to record itself; unregister it. */
2321 RecordDeleteClientFromContext(pContext
,
2322 pContext
->pRecordingClient
->clientAsMask
);
2324 /* move the newly enabled context to the front part of ppAllContexts,
2325 * where all the enabled contexts are
2327 i
= RecordFindContextOnAllContexts(pContext
);
2328 assert(i
>= numEnabledContexts
);
2329 if (i
!= numEnabledContexts
) {
2330 ppAllContexts
[i
] = ppAllContexts
[numEnabledContexts
];
2331 ppAllContexts
[numEnabledContexts
] = pContext
;
2334 ++numEnabledContexts
;
2335 assert(numEnabledContexts
> 0);
2337 /* send StartOfData */
2338 RecordAProtocolElement(pContext
, NULL
, XRecordStartOfData
, NULL
, 0, 0, 0);
2339 RecordFlushReplyBuffer(pContext
, NULL
, 0, NULL
, 0);
2341 } /* ProcRecordEnableContext */
2343 /* RecordDisableContext
2346 * pContext is the context to disable.
2347 * nRanges is the number of elements in pRanges.
2352 * If the context was enabled, it is disabled. An EndOfData
2353 * message is sent to the recording client. Recording hooks for
2354 * this context are uninstalled. The context is moved to the
2355 * rear part of the ppAllContexts array. numEnabledContexts is
2356 * decremented. Request processing for the formerly recording client
2360 RecordDisableContext(RecordContextPtr pContext
)
2362 RecordClientsAndProtocolPtr pRCAP
;
2365 if (!pContext
->pRecordingClient
)
2367 if (!pContext
->pRecordingClient
->clientGone
) {
2368 RecordAProtocolElement(pContext
, NULL
, XRecordEndOfData
, NULL
, 0, 0, 0);
2369 RecordFlushReplyBuffer(pContext
, NULL
, 0, NULL
, 0);
2370 /* Re-enable request processing on this connection. */
2371 AttendClient(pContext
->pRecordingClient
);
2374 for (pRCAP
= pContext
->pListOfRCAP
; pRCAP
; pRCAP
= pRCAP
->pNextRCAP
) {
2375 RecordUninstallHooks(pRCAP
, 0);
2378 pContext
->pRecordingClient
= NULL
;
2380 /* move the newly disabled context to the rear part of ppAllContexts,
2381 * where all the disabled contexts are
2383 i
= RecordFindContextOnAllContexts(pContext
);
2384 assert((i
!= -1) && (i
< numEnabledContexts
));
2385 if (i
!= (numEnabledContexts
- 1)) {
2386 ppAllContexts
[i
] = ppAllContexts
[numEnabledContexts
- 1];
2387 ppAllContexts
[numEnabledContexts
- 1] = pContext
;
2389 --numEnabledContexts
;
2390 assert(numEnabledContexts
>= 0);
2391 } /* RecordDisableContext */
2394 ProcRecordDisableContext(ClientPtr client
)
2396 RecordContextPtr pContext
;
2398 REQUEST(xRecordDisableContextReq
);
2400 REQUEST_SIZE_MATCH(xRecordDisableContextReq
);
2401 VERIFY_CONTEXT(pContext
, stuff
->context
, client
);
2402 RecordDisableContext(pContext
);
2404 } /* ProcRecordDisableContext */
2406 /* RecordDeleteContext
2409 * value is the context to delete.
2410 * id is its resource ID.
2415 * Disables the context, frees all associated memory, and removes
2416 * it from the ppAllContexts array.
2419 RecordDeleteContext(pointer value
, XID id
)
2422 RecordContextPtr pContext
= (RecordContextPtr
) value
;
2423 RecordClientsAndProtocolPtr pRCAP
;
2425 RecordDisableContext(pContext
);
2427 /* Remove all the clients from all the RCAPs.
2428 * As a result, the RCAPs will be freed.
2431 while ((pRCAP
= pContext
->pListOfRCAP
)) {
2432 int numClients
= pRCAP
->numClients
;
2434 /* when the last client is deleted, the RCAP will go away. */
2435 while (numClients
--) {
2436 RecordDeleteClientFromRCAP(pRCAP
, numClients
);
2440 /* remove context from AllContexts list */
2442 if (-1 != (i
= RecordFindContextOnAllContexts(pContext
))) {
2443 ppAllContexts
[i
] = ppAllContexts
[numContexts
- 1];
2444 if (--numContexts
== 0) {
2445 free(ppAllContexts
);
2446 ppAllContexts
= NULL
;
2452 } /* RecordDeleteContext */
2455 ProcRecordFreeContext(ClientPtr client
)
2457 RecordContextPtr pContext
;
2459 REQUEST(xRecordFreeContextReq
);
2461 REQUEST_SIZE_MATCH(xRecordFreeContextReq
);
2462 VERIFY_CONTEXT(pContext
, stuff
->context
, client
);
2463 FreeResource(stuff
->context
, RT_NONE
);
2465 } /* ProcRecordFreeContext */
2468 ProcRecordDispatch(ClientPtr client
)
2472 switch (stuff
->data
) {
2473 case X_RecordQueryVersion
:
2474 return ProcRecordQueryVersion(client
);
2475 case X_RecordCreateContext
:
2476 return ProcRecordCreateContext(client
);
2477 case X_RecordRegisterClients
:
2478 return ProcRecordRegisterClients(client
);
2479 case X_RecordUnregisterClients
:
2480 return ProcRecordUnregisterClients(client
);
2481 case X_RecordGetContext
:
2482 return ProcRecordGetContext(client
);
2483 case X_RecordEnableContext
:
2484 return ProcRecordEnableContext(client
);
2485 case X_RecordDisableContext
:
2486 return ProcRecordDisableContext(client
);
2487 case X_RecordFreeContext
:
2488 return ProcRecordFreeContext(client
);
2492 } /* ProcRecordDispatch */
2495 SProcRecordQueryVersion(ClientPtr client
)
2497 REQUEST(xRecordQueryVersionReq
);
2499 swaps(&stuff
->length
);
2500 REQUEST_SIZE_MATCH(xRecordQueryVersionReq
);
2501 swaps(&stuff
->majorVersion
);
2502 swaps(&stuff
->minorVersion
);
2503 return ProcRecordQueryVersion(client
);
2504 } /* SProcRecordQueryVersion */
2507 SwapCreateRegister(xRecordRegisterClientsReq
* stuff
)
2512 swapl(&stuff
->context
);
2513 swapl(&stuff
->nClients
);
2514 swapl(&stuff
->nRanges
);
2515 pClientID
= (XID
*) &stuff
[1];
2516 if (stuff
->nClients
>
2517 stuff
->length
- bytes_to_int32(sz_xRecordRegisterClientsReq
))
2519 for (i
= 0; i
< stuff
->nClients
; i
++, pClientID
++) {
2522 if (stuff
->nRanges
>
2523 stuff
->length
- bytes_to_int32(sz_xRecordRegisterClientsReq
)
2526 RecordSwapRanges((xRecordRange
*) pClientID
, stuff
->nRanges
);
2528 } /* SwapCreateRegister */
2531 SProcRecordCreateContext(ClientPtr client
)
2533 REQUEST(xRecordCreateContextReq
);
2536 swaps(&stuff
->length
);
2537 REQUEST_AT_LEAST_SIZE(xRecordCreateContextReq
);
2538 if ((status
= SwapCreateRegister((pointer
) stuff
)) != Success
)
2540 return ProcRecordCreateContext(client
);
2541 } /* SProcRecordCreateContext */
2544 SProcRecordRegisterClients(ClientPtr client
)
2546 REQUEST(xRecordRegisterClientsReq
);
2549 swaps(&stuff
->length
);
2550 REQUEST_AT_LEAST_SIZE(xRecordRegisterClientsReq
);
2551 if ((status
= SwapCreateRegister((pointer
) stuff
)) != Success
)
2553 return ProcRecordRegisterClients(client
);
2554 } /* SProcRecordRegisterClients */
2557 SProcRecordUnregisterClients(ClientPtr client
)
2559 REQUEST(xRecordUnregisterClientsReq
);
2561 swaps(&stuff
->length
);
2562 REQUEST_AT_LEAST_SIZE(xRecordUnregisterClientsReq
);
2563 swapl(&stuff
->context
);
2564 swapl(&stuff
->nClients
);
2566 return ProcRecordUnregisterClients(client
);
2567 } /* SProcRecordUnregisterClients */
2570 SProcRecordGetContext(ClientPtr client
)
2572 REQUEST(xRecordGetContextReq
);
2574 swaps(&stuff
->length
);
2575 REQUEST_SIZE_MATCH(xRecordGetContextReq
);
2576 swapl(&stuff
->context
);
2577 return ProcRecordGetContext(client
);
2578 } /* SProcRecordGetContext */
2581 SProcRecordEnableContext(ClientPtr client
)
2583 REQUEST(xRecordEnableContextReq
);
2585 swaps(&stuff
->length
);
2586 REQUEST_SIZE_MATCH(xRecordEnableContextReq
);
2587 swapl(&stuff
->context
);
2588 return ProcRecordEnableContext(client
);
2589 } /* SProcRecordEnableContext */
2592 SProcRecordDisableContext(ClientPtr client
)
2594 REQUEST(xRecordDisableContextReq
);
2596 swaps(&stuff
->length
);
2597 REQUEST_SIZE_MATCH(xRecordDisableContextReq
);
2598 swapl(&stuff
->context
);
2599 return ProcRecordDisableContext(client
);
2600 } /* SProcRecordDisableContext */
2603 SProcRecordFreeContext(ClientPtr client
)
2605 REQUEST(xRecordFreeContextReq
);
2607 swaps(&stuff
->length
);
2608 REQUEST_SIZE_MATCH(xRecordFreeContextReq
);
2609 swapl(&stuff
->context
);
2610 return ProcRecordFreeContext(client
);
2611 } /* SProcRecordFreeContext */
2614 SProcRecordDispatch(ClientPtr client
)
2618 switch (stuff
->data
) {
2619 case X_RecordQueryVersion
:
2620 return SProcRecordQueryVersion(client
);
2621 case X_RecordCreateContext
:
2622 return SProcRecordCreateContext(client
);
2623 case X_RecordRegisterClients
:
2624 return SProcRecordRegisterClients(client
);
2625 case X_RecordUnregisterClients
:
2626 return SProcRecordUnregisterClients(client
);
2627 case X_RecordGetContext
:
2628 return SProcRecordGetContext(client
);
2629 case X_RecordEnableContext
:
2630 return SProcRecordEnableContext(client
);
2631 case X_RecordDisableContext
:
2632 return SProcRecordDisableContext(client
);
2633 case X_RecordFreeContext
:
2634 return SProcRecordFreeContext(client
);
2638 } /* SProcRecordDispatch */
2640 /* RecordConnectionSetupInfo
2643 * pContext is an enabled context that specifies recording of
2644 * connection setup info.
2645 * pci holds the connection setup info.
2650 * The connection setup info is sent to the recording client.
2653 RecordConnectionSetupInfo(RecordContextPtr pContext
, NewClientInfoRec
* pci
)
2655 int prefixsize
= SIZEOF(xConnSetupPrefix
);
2656 int restsize
= pci
->prefix
->length
* 4;
2658 if (pci
->client
->swapped
) {
2659 char *pConnSetup
= (char *) malloc(prefixsize
+ restsize
);
2663 SwapConnSetupPrefix(pci
->prefix
, (xConnSetupPrefix
*) pConnSetup
);
2664 SwapConnSetupInfo((char *) pci
->setup
,
2665 (char *) (pConnSetup
+ prefixsize
));
2666 RecordAProtocolElement(pContext
, pci
->client
, XRecordClientStarted
,
2667 (pointer
) pConnSetup
, prefixsize
+ restsize
, 0,
2672 /* don't alloc and copy as in the swapped case; just send the
2673 * data in two pieces
2675 RecordAProtocolElement(pContext
, pci
->client
, XRecordClientStarted
,
2676 (pointer
) pci
->prefix
, prefixsize
, 0, restsize
);
2677 RecordAProtocolElement(pContext
, pci
->client
, XRecordClientStarted
,
2678 (pointer
) pci
->setup
, restsize
, 0,
2679 /* continuation */ -1);
2681 } /* RecordConnectionSetupInfo */
2683 /* RecordDeleteContext
2686 * pcbl is &ClientStateCallback.
2688 * calldata is a pointer to a NewClientInfoRec (include/dixstruct.h)
2689 * which contains information about client state changes.
2694 * If a new client has connected and any contexts have specified
2695 * XRecordFutureClients, the new client is registered on those contexts.
2696 * If any of those contexts specify recording of the connection setup
2697 * info, it is recorded.
2699 * If an existing client has disconnected, it is deleted from any
2700 * contexts that it was registered on. If any of those contexts
2701 * specified XRecordClientDied, they record a ClientDied protocol element.
2702 * If the disconnectiong client happened to be the data connection of an
2703 * enabled context, the context is disabled.
2707 RecordAClientStateChange(CallbackListPtr
*pcbl
, pointer nulldata
,
2710 NewClientInfoRec
*pci
= (NewClientInfoRec
*) calldata
;
2712 ClientPtr pClient
= pci
->client
;
2713 RecordContextPtr
*ppAllContextsCopy
= NULL
;
2714 int numContextsCopy
= 0;
2716 switch (pClient
->clientState
) {
2717 case ClientStateRunning
: /* new client */
2718 for (i
= 0; i
< numContexts
; i
++) {
2719 RecordClientsAndProtocolPtr pRCAP
;
2720 RecordContextPtr pContext
= ppAllContexts
[i
];
2722 if ((pRCAP
= RecordFindClientOnContext(pContext
,
2723 XRecordFutureClients
, NULL
)))
2725 RecordAddClientToRCAP(pRCAP
, pClient
->clientAsMask
);
2726 if (pContext
->pRecordingClient
&& pRCAP
->clientStarted
)
2727 RecordConnectionSetupInfo(pContext
, pci
);
2732 case ClientStateGone
:
2733 case ClientStateRetained
: /* client disconnected */
2735 /* RecordDisableContext modifies contents of ppAllContexts. */
2736 numContextsCopy
= numContexts
;
2737 ppAllContextsCopy
= malloc(numContextsCopy
* sizeof(RecordContextPtr
));
2738 assert(ppAllContextsCopy
);
2739 memcpy(ppAllContextsCopy
, ppAllContexts
,
2740 numContextsCopy
* sizeof(RecordContextPtr
));
2742 for (i
= 0; i
< numContextsCopy
; i
++) {
2743 RecordClientsAndProtocolPtr pRCAP
;
2744 RecordContextPtr pContext
= ppAllContextsCopy
[i
];
2747 if (pContext
->pRecordingClient
== pClient
)
2748 RecordDisableContext(pContext
);
2749 if ((pRCAP
= RecordFindClientOnContext(pContext
,
2750 pClient
->clientAsMask
,
2752 if (pContext
->pRecordingClient
&& pRCAP
->clientDied
)
2753 RecordAProtocolElement(pContext
, pClient
,
2754 XRecordClientDied
, NULL
, 0, 0, 0);
2755 RecordDeleteClientFromRCAP(pRCAP
, pos
);
2759 free(ppAllContextsCopy
);
2764 } /* end switch on client state */
2765 } /* RecordAClientStateChange */
2770 * extEntry is the extension information for RECORD.
2775 * Performs any cleanup needed by RECORD at server shutdown time.
2779 RecordCloseDown(ExtensionEntry
* extEntry
)
2781 DeleteCallback(&ClientStateCallback
, RecordAClientStateChange
, NULL
);
2782 } /* RecordCloseDown */
2784 /* RecordExtensionInit
2791 * Enables the RECORD extension if possible.
2794 RecordExtensionInit(void)
2796 ExtensionEntry
*extentry
;
2798 RTContext
= CreateNewResourceType(RecordDeleteContext
, "RecordContext");
2802 if (!dixRegisterPrivateKey(RecordClientPrivateKey
, PRIVATE_CLIENT
, 0))
2805 ppAllContexts
= NULL
;
2806 numContexts
= numEnabledContexts
= numEnabledRCAPs
= 0;
2808 if (!AddCallback(&ClientStateCallback
, RecordAClientStateChange
, NULL
))
2811 extentry
= AddExtension(RECORD_NAME
, RecordNumEvents
, RecordNumErrors
,
2812 ProcRecordDispatch
, SProcRecordDispatch
,
2813 RecordCloseDown
, StandardMinorOpcode
);
2815 DeleteCallback(&ClientStateCallback
, RecordAClientStateChange
, NULL
);
2818 SetResourceTypeErrorValue(RTContext
,
2819 extentry
->errorBase
+ XRecordBadContext
);
2821 } /* RecordExtensionInit */