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