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