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