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