aboutsummaryrefslogtreecommitdiff
path: root/nxcomp/src/ServerChannel.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'nxcomp/src/ServerChannel.cpp')
-rw-r--r--nxcomp/src/ServerChannel.cpp7946
1 files changed, 7946 insertions, 0 deletions
diff --git a/nxcomp/src/ServerChannel.cpp b/nxcomp/src/ServerChannel.cpp
new file mode 100644
index 000000000..a560eca6d
--- /dev/null
+++ b/nxcomp/src/ServerChannel.cpp
@@ -0,0 +1,7946 @@
+/**************************************************************************/
+/* */
+/* Copyright (c) 2001, 2011 NoMachine (http://www.nomachine.com) */
+/* Copyright (c) 2008-2014 Oleksandr Shneyder <o.shneyder@phoca-gmbh.de> */
+/* Copyright (c) 2014-2016 Ulrich Sibiller <uli42@gmx.de> */
+/* Copyright (c) 2014-2016 Mihai Moldovan <ionic@ionic.de> */
+/* Copyright (c) 2011-2016 Mike Gabriel <mike.gabriel@das-netzwerkteam.de>*/
+/* Copyright (c) 2015-2016 Qindel Group (http://www.qindel.com) */
+/* */
+/* NXCOMP, NX protocol compression and NX extensions to this software */
+/* are copyright of the aforementioned persons and companies. */
+/* */
+/* Redistribution and use of the present software is allowed according */
+/* to terms specified in the file LICENSE.nxcomp which comes in the */
+/* source distribution. */
+/* */
+/* All rights reserved. */
+/* */
+/* NOTE: This software has received contributions from various other */
+/* contributors, only the core maintainers and supporters are listed as */
+/* copyright holders. Please contact us, if you feel you should be listed */
+/* as copyright holder, as well. */
+/* */
+/**************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string.h>
+#include <sys/types.h>
+#include <sys/ipc.h>
+#ifndef ANDROID
+#include <sys/shm.h>
+#endif
+
+#include <X11/X.h>
+#include <X11/Xatom.h>
+
+#include "NXproto.h"
+#include "NXalert.h"
+#include "NXpack.h"
+#include "NXmitshm.h"
+
+#include "ServerChannel.h"
+
+#include "EncodeBuffer.h"
+#include "DecodeBuffer.h"
+
+#include "StaticCompressor.h"
+
+#include "Statistics.h"
+#include "Proxy.h"
+
+#include "Auth.h"
+#include "Unpack.h"
+
+//
+// Available unpack methods.
+//
+
+#include "Alpha.h"
+#include "Colormap.h"
+#include "Bitmap.h"
+#include "Jpeg.h"
+#include "Pgn.h"
+#include "Rgb.h"
+#include "Rle.h"
+
+extern Proxy *proxy;
+
+//
+// Set the verbosity level. You also
+// need to define OPCODES in Misc.cpp
+// if you want literals instead of
+// opcodes' numbers.
+//
+
+#define PANIC
+#define WARNING
+#undef OPCODES
+#undef TEST
+#undef DEBUG
+#undef DUMP
+
+//
+// Log the important tracepoints related
+// to writing packets to the peer proxy.
+//
+
+#undef FLUSH
+
+//
+// Log the operations related to splits.
+//
+
+#undef SPLIT
+
+//
+// Define this to log when a channel
+// is created or destroyed.
+//
+
+#undef REFERENCES
+
+//
+// Define this to exit and suspend the
+// session after a given number of X
+// messages decoded by the proxy.
+//
+
+#undef SUSPEND
+
+//
+// Define these to hide the server extensions.
+//
+
+#define HIDE_MIT_SHM_EXTENSION
+#define HIDE_BIG_REQUESTS_EXTENSION
+#define HIDE_XFree86_Bigfont_EXTENSION
+#undef HIDE_SHAPE_EXTENSION
+#undef HIDE_XKEYBOARD_EXTENSION
+
+//
+// Known reasons of connection failures.
+//
+
+#define INVALID_COOKIE_DATA "Invalid MIT-MAGIC-COOKIE-1 key"
+#define INVALID_COOKIE_SIZE ((int) sizeof(INVALID_COOKIE_DATA) - 1)
+
+#define NO_AUTH_PROTO_DATA "No protocol specified"
+#define NO_AUTH_PROTO_SIZE ((int) sizeof(NO_AUTH_PROTO_DATA) - 1)
+
+//
+// Here are the static members.
+//
+
+#ifdef REFERENCES
+
+int ServerChannel::references_ = 0;
+
+#endif
+
+ServerChannel::ServerChannel(Transport *transport, StaticCompressor *compressor)
+
+ : Channel(transport, compressor), readBuffer_(transport_, this)
+{
+ //
+ // Sequence number of the next message
+ // being encoded or decoded.
+ //
+
+ clientSequence_ = 0;
+ serverSequence_ = 0;
+
+ //
+ // Save the last motion event and flush
+ // it only when the timeout expires.
+ //
+
+ lastMotion_[0] = '\0';
+
+ //
+ // Clear the queue of sequence numbers
+ // of split commits. Used to mask the
+ // errors.
+ //
+
+ initCommitQueue();
+
+ //
+ // Do we enable or not sending of expose
+ // events to the X client.
+ //
+
+ enableExpose_ = 1;
+ enableGraphicsExpose_ = 1;
+ enableNoExpose_ = 1;
+
+ //
+ // Track data of image currently being
+ // decompressed.
+ //
+
+ imageState_ = NULL;
+
+ //
+ // Track MIT-SHM resources.
+ //
+
+ shmemState_ = NULL;
+
+ //
+ // Store the unpack state for each agent
+ // resource.
+ //
+
+ for (int i = 0; i < CONNECTIONS_LIMIT; i++)
+ {
+ unpackState_[i] = NULL;
+ }
+
+ //
+ // Data about the split parameters requested
+ // by the encoding side.
+ //
+
+ splitState_.resource = nothing;
+ splitState_.current = 0;
+ splitState_.save = 1;
+ splitState_.load = 1;
+ splitState_.commit = 0;
+
+ //
+ // It will be eventually set by
+ // the server proxy.
+ //
+
+ fontPort_ = -1;
+
+ #ifdef REFERENCES
+ *logofs << "ServerChannel: Created new object at "
+ << this << " for FD#" << fd_ << " out of "
+ << ++references_ << " allocated channels.\n"
+ << logofs_flush;
+ #endif
+}
+
+ServerChannel::~ServerChannel()
+{
+ #ifdef TEST
+ *logofs << "ServerChannel: Freeing image state information.\n"
+ << logofs_flush;
+ #endif
+
+ handleImageStateRemove();
+
+ #ifdef TEST
+ *logofs << "ServerChannel: Freeing shared memory information.\n"
+ << logofs_flush;
+ #endif
+
+ handleShmemStateRemove();
+
+ #ifdef TEST
+ *logofs << "ServerChannel: Freeing unpack state information.\n"
+ << logofs_flush;
+ #endif
+
+ for (int i = 0; i < CONNECTIONS_LIMIT; i++)
+ {
+ handleUnpackStateRemove(i);
+ }
+
+ #ifdef TEST
+ *logofs << "ServerChannel: Freeing channel caches.\n"
+ << logofs_flush;
+ #endif
+
+ #ifdef REFERENCES
+ *logofs << "ServerChannel: Deleted object at "
+ << this << " for FD#" << fd_ << " out of "
+ << --references_ << " allocated channels.\n"
+ << logofs_flush;
+ #endif
+}
+
+//
+// Beginning of handleRead().
+//
+
+int ServerChannel::handleRead(EncodeBuffer &encodeBuffer, const unsigned char *message,
+ unsigned int length)
+{
+ #ifdef DEBUG
+ *logofs << "handleRead: Called for FD#" << fd_
+ << ".\n" << logofs_flush;
+ #endif
+
+ //
+ // Pointer to located message and
+ // its size in bytes.
+ //
+
+ const unsigned char *inputMessage;
+ unsigned int inputLength;
+
+ //
+ // Set when message is found in
+ // cache.
+ //
+
+ int hit;
+
+ #if defined(TEST) || defined(INFO)
+ *logofs << "handleRead: Trying to read from FD#"
+ << fd_ << " at " << strMsTimestamp() << ".\n"
+ << logofs_flush;
+ #endif
+
+ int result = readBuffer_.readMessage();
+
+ #if defined(DEBUG) || defined(INFO)
+ *logofs << "handleRead: Read result on FD#" << fd_
+ << " is " << result << ".\n"
+ << logofs_flush;
+ #endif
+
+ if (result < 0)
+ {
+ //
+ // Let the proxy close the channel.
+ //
+
+ return -1;
+ }
+ else if (result == 0)
+ {
+ #if defined(TEST) || defined(INFO)
+
+ //
+ // This can happen because we have the descriptor
+ // selected in the read set but we already read
+ // the data asynchronously, while decoding data
+ // read from the proxy.
+ //
+
+ *logofs << "handleRead: WARNING! No data read from FD#"
+ << fd_ << " while encoding messages.\n"
+ << logofs_flush;
+
+ #endif
+
+ return 0;
+ }
+
+ #if defined(TEST) || defined(INFO) || defined(FLUSH)
+ *logofs << "handleRead: Encoding messages for FD#" << fd_
+ << " with " << readBuffer_.getLength() << " bytes "
+ << "in the buffer.\n" << logofs_flush;
+ #endif
+
+ //
+ // Extract any complete message which
+ // is available in the buffer.
+ //
+
+ if (proxy -> handleAsyncSwitch(fd_) < 0)
+ {
+ return -1;
+ }
+
+ while ((inputMessage = readBuffer_.getMessage(inputLength)) != NULL)
+ {
+ hit = 0;
+
+ if (firstReply_)
+ {
+ //
+ // Handle the X server's authorization reply.
+ //
+
+ if (handleAuthorization(inputMessage, inputLength) < 0)
+ {
+ return -1;
+ }
+
+ imageByteOrder_ = inputMessage[30];
+ bitmapBitOrder_ = inputMessage[31];
+ scanlineUnit_ = inputMessage[32];
+ scanlinePad_ = inputMessage[33];
+
+ encodeBuffer.encodeValue((unsigned int) inputMessage[0], 8);
+ encodeBuffer.encodeValue((unsigned int) inputMessage[1], 8);
+ encodeBuffer.encodeValue(GetUINT(inputMessage + 2, bigEndian_), 16);
+ encodeBuffer.encodeValue(GetUINT(inputMessage + 4, bigEndian_), 16);
+ encodeBuffer.encodeValue(GetUINT(inputMessage + 6, bigEndian_), 16);
+
+ if (ServerCache::lastInitReply.compare(inputLength - 8, inputMessage + 8))
+ {
+ encodeBuffer.encodeBoolValue(1);
+ }
+ else
+ {
+ encodeBuffer.encodeBoolValue(0);
+
+ for (unsigned int i = 8; i < inputLength; i++)
+ {
+ encodeBuffer.encodeValue((unsigned int) inputMessage[i], 8);
+ }
+ }
+
+ firstReply_ = 0;
+
+ #if defined(TEST) || defined(OPCODES)
+
+ int bits = encodeBuffer.diffBits();
+
+ *logofs << "handleRead: Handled first reply. " << inputLength
+ << " bytes in, " << bits << " bits (" << ((float) bits) / 8
+ << " bytes) out.\n" << logofs_flush;
+
+ #endif
+
+ priority_++;
+
+ }
+ else
+ {
+ //
+ // NX client needs this line to consider
+ // the initialization phase successfully
+ // completed.
+ //
+
+ if (firstClient_ == -1)
+ {
+ cerr << "Info" << ": Established X server connection.\n" ;
+
+ firstClient_ = fd_;
+ }
+
+ //
+ // Check if this is a reply.
+ //
+
+ if (*inputMessage == X_Reply)
+ {
+ int bits = 0;
+
+ unsigned char inputOpcode = *inputMessage;
+
+ unsigned short int requestSequenceNum;
+ unsigned char requestOpcode;
+ unsigned int requestData[3];
+
+ unsigned int sequenceNum = GetUINT(inputMessage + 2, bigEndian_);
+
+ #ifdef SUSPEND
+
+ if (sequenceNum >= 1000)
+ {
+ cerr << "Warning" << ": Exiting to test the resilience of the agent.\n";
+
+ sleep(2);
+
+ HandleAbort();
+ }
+
+ #endif
+
+ //
+ // We managed all the events and errors caused
+ // by the previous requests. We can now reset
+ // the queue of split commits.
+ //
+
+ clearCommitQueue();
+
+ //
+ // Encode opcode and difference between
+ // current sequence and the last one.
+ //
+
+ encodeBuffer.encodeOpcodeValue(inputOpcode, serverCache_ -> opcodeCache);
+
+ unsigned int sequenceDiff = sequenceNum - serverSequence_;
+
+ serverSequence_ = sequenceNum;
+
+ #ifdef DEBUG
+ *logofs << "handleRead: Last server sequence number for FD#"
+ << fd_ << " is " << serverSequence_ << " with "
+ << "difference " << sequenceDiff << ".\n"
+ << logofs_flush;
+ #endif
+
+ encodeBuffer.encodeCachedValue(sequenceDiff, 16,
+ serverCache_ -> replySequenceCache, 7);
+
+ //
+ // Now handle the data part.
+ //
+
+ if (sequenceQueue_.peek(requestSequenceNum, requestOpcode) &&
+ requestSequenceNum == sequenceNum)
+ {
+ //
+ // We've found the request that generated this reply.
+ // It is possible to compress the reply based on the
+ // specific request type.
+ //
+
+ sequenceQueue_.pop(requestSequenceNum, requestOpcode,
+ requestData[0], requestData[1], requestData[2]);
+
+ //
+ // If differential compression is disabled
+ // then use the most simple encoding.
+ //
+
+ if (control -> LocalDeltaCompression == 0)
+ {
+ int result = handleFastReadReply(encodeBuffer, requestOpcode,
+ inputMessage, inputLength);
+ if (result < 0)
+ {
+ return -1;
+ }
+ else if (result > 0)
+ {
+ continue;
+ }
+ }
+
+ switch (requestOpcode)
+ {
+ case X_AllocColor:
+ {
+ const unsigned char *nextSrc = inputMessage + 8;
+ for (unsigned int i = 0; i < 3; i++)
+ {
+ unsigned int colorValue = GetUINT(nextSrc, bigEndian_);
+ nextSrc += 2;
+ if (colorValue == requestData[i])
+ encodeBuffer.encodeBoolValue(1);
+ else
+ {
+ encodeBuffer.encodeBoolValue(0);
+ encodeBuffer.encodeValue(colorValue - colorValue, 16, 6);
+ }
+ }
+ unsigned int pixel = GetULONG(inputMessage + 16, bigEndian_);
+ encodeBuffer.encodeValue(pixel, 32, 9);
+
+ priority_++;
+ }
+ break;
+ case X_GetAtomName:
+ {
+ unsigned int nameLength = GetUINT(inputMessage + 8, bigEndian_);
+ encodeBuffer.encodeValue(nameLength, 16, 6);
+ const unsigned char *nextSrc = inputMessage + 32;
+
+ // Since ProtoStep7 (#issue 108)
+ encodeBuffer.encodeTextData(nextSrc, nameLength);
+
+ priority_++;
+ }
+ break;
+ case X_GetGeometry:
+ {
+ //
+ // TODO: This obtains a satisfactory 10:1, but
+ // could be cached to leverage the big amount
+ // of such requests issued by QT clients.
+ //
+
+ encodeBuffer.encodeCachedValue(inputMessage[1], 8,
+ serverCache_ -> depthCache);
+ encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 8, bigEndian_),
+ 29, serverCache_ -> getGeometryRootCache, 9);
+ const unsigned char *nextSrc = inputMessage + 12;
+ for (unsigned int i = 0; i < 5; i++)
+ {
+ encodeBuffer.encodeCachedValue(GetUINT(nextSrc, bigEndian_), 16,
+ *serverCache_ -> getGeometryGeomCache[i], 8);
+ nextSrc += 2;
+ }
+
+ priority_++;
+ }
+ break;
+ case X_GetInputFocus:
+ {
+ //
+ // Is it a real X_GetInputFocus or a
+ // masqueraded reply?
+ //
+
+ if (requestData[0] == X_GetInputFocus)
+ {
+ encodeBuffer.encodeValue((unsigned int) inputMessage[1], 2);
+ encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 8, bigEndian_),
+ 29, serverCache_ -> getInputFocusWindowCache);
+
+ priority_++;
+ }
+ else
+ {
+ //
+ // TODO: We are not setting priority in case
+ // of replies other than real X_GetInputFocus
+ // or X_NXGetUnpackParameters. We should check
+ // once again that this is OK.
+ //
+
+ #ifdef TEST
+ *logofs << "handleRead: Received tainted X_GetInputFocus reply "
+ << "for request OPCODE#" << requestData[0] << " with "
+ << "sequence " << sequenceNum << ".\n"
+ << logofs_flush;
+ #endif
+
+ //
+ // Don't encode any data in case of sync
+ // messages or any other reply for which
+ // opcode is enough.
+ //
+
+ if (requestData[0] == opcodeStore_ -> getUnpackParameters)
+ {
+ for (int i = 0; i < PACK_METHOD_LIMIT; i++)
+ {
+ encodeBuffer.encodeBoolValue(control -> LocalUnpackMethods[i]);
+ }
+
+ priority_++;
+ }
+ else if (requestData[0] == opcodeStore_ -> getShmemParameters)
+ {
+ if (handleShmemReply(encodeBuffer, requestOpcode, requestData[1],
+ inputMessage, inputLength) < 0)
+ {
+ return -1;
+ }
+
+ priority_++;
+ }
+ else if (requestData[0] == opcodeStore_ -> getFontParameters)
+ {
+ if (handleFontReply(encodeBuffer, requestOpcode,
+ inputMessage, inputLength) < 0)
+ {
+ return -1;
+ }
+ }
+
+ //
+ // Account this data to the original opcode.
+ //
+
+ requestOpcode = requestData[0];
+ }
+ }
+ break;
+ case X_GetKeyboardMapping:
+ {
+ unsigned int keysymsPerKeycode = (unsigned int) inputMessage[1];
+ if (ServerCache::getKeyboardMappingLastMap.compare(inputLength - 32,
+ inputMessage + 32) && (keysymsPerKeycode ==
+ ServerCache::getKeyboardMappingLastKeysymsPerKeycode))
+ {
+ encodeBuffer.encodeBoolValue(1);
+
+ priority_++;
+
+ break;
+ }
+ ServerCache::getKeyboardMappingLastKeysymsPerKeycode = keysymsPerKeycode;
+ encodeBuffer.encodeBoolValue(0);
+ unsigned int numKeycodes =
+ (((inputLength - 32) / keysymsPerKeycode) >> 2);
+ encodeBuffer.encodeValue(numKeycodes, 8);
+ encodeBuffer.encodeValue(keysymsPerKeycode, 8, 4);
+ const unsigned char *nextSrc = inputMessage + 32;
+ unsigned char previous = 0;
+ for (unsigned int count = numKeycodes * keysymsPerKeycode;
+ count; --count)
+ {
+ unsigned int keysym = GetULONG(nextSrc, bigEndian_);
+ nextSrc += 4;
+ if (keysym == NoSymbol)
+ encodeBuffer.encodeBoolValue(1);
+ else
+ {
+ encodeBuffer.encodeBoolValue(0);
+ unsigned int first3Bytes = (keysym >> 8);
+ encodeBuffer.encodeCachedValue(first3Bytes, 24,
+ serverCache_ -> getKeyboardMappingKeysymCache, 9);
+ unsigned char lastByte = (unsigned char) (keysym & 0xff);
+ encodeBuffer.encodeCachedValue(lastByte - previous, 8,
+ serverCache_ -> getKeyboardMappingLastByteCache, 5);
+ previous = lastByte;
+ }
+ }
+
+ priority_++;
+ }
+ break;
+ case X_GetModifierMapping:
+ {
+ encodeBuffer.encodeValue((unsigned int) inputMessage[1], 8);
+ const unsigned char *nextDest = inputMessage + 32;
+ if (ServerCache::getModifierMappingLastMap.compare(inputLength - 32,
+ nextDest))
+ {
+ encodeBuffer.encodeBoolValue(1);
+
+ priority_++;
+
+ break;
+ }
+ encodeBuffer.encodeBoolValue(0);
+ for (unsigned int count = inputLength - 32; count; count--)
+ {
+ unsigned char next = *nextDest++;
+ if (next == 0)
+ encodeBuffer.encodeBoolValue(1);
+ else
+ {
+ encodeBuffer.encodeBoolValue(0);
+ encodeBuffer.encodeValue(next, 8);
+ }
+ }
+
+ priority_++;
+ }
+ break;
+ case X_GetProperty:
+ {
+ MessageStore *messageStore = serverStore_ ->
+ getReplyStore(X_GetProperty);
+
+ hit = handleEncode(encodeBuffer, serverCache_, messageStore,
+ requestOpcode, inputMessage, inputLength);
+
+ priority_++;
+ }
+ break;
+ case X_GetSelectionOwner:
+ {
+ encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 8, bigEndian_),
+ 29, serverCache_ -> getSelectionOwnerCache, 9);
+ priority_++;
+ }
+ break;
+ case X_GetWindowAttributes:
+ {
+ encodeBuffer.encodeValue((unsigned int) inputMessage[1], 2);
+ encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 8, bigEndian_),
+ 29, serverCache_ -> visualCache);
+ encodeBuffer.encodeCachedValue(GetUINT(inputMessage + 12, bigEndian_),
+ 16, serverCache_ -> getWindowAttributesClassCache, 3);
+ encodeBuffer.encodeCachedValue(inputMessage[14], 8,
+ serverCache_ -> getWindowAttributesBitGravityCache);
+ encodeBuffer.encodeCachedValue(inputMessage[15], 8,
+ serverCache_ -> getWindowAttributesWinGravityCache);
+ encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 16, bigEndian_),
+ 32, serverCache_ -> getWindowAttributesPlanesCache, 9);
+ encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 20, bigEndian_),
+ 32, serverCache_ -> getWindowAttributesPixelCache, 9);
+ encodeBuffer.encodeBoolValue((unsigned int) inputMessage[24]);
+ encodeBuffer.encodeBoolValue((unsigned int) inputMessage[25]);
+ encodeBuffer.encodeValue((unsigned int) inputMessage[26], 2);
+ encodeBuffer.encodeBoolValue((unsigned int) inputMessage[27]);
+ encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 28, bigEndian_),
+ 29, serverCache_ -> colormapCache, 9);
+ encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 32, bigEndian_),
+ 32, serverCache_ -> getWindowAttributesAllEventsCache);
+ encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 36, bigEndian_),
+ 32, serverCache_ -> getWindowAttributesYourEventsCache);
+ encodeBuffer.encodeCachedValue(GetUINT(inputMessage + 40, bigEndian_),
+ 16, serverCache_ -> getWindowAttributesDontPropagateCache);
+
+ priority_++;
+ }
+ break;
+ case X_GrabKeyboard:
+ case X_GrabPointer:
+ {
+ encodeBuffer.encodeValue((unsigned int) inputMessage[1], 3);
+
+ priority_++;
+ }
+ break;
+ case X_InternAtom:
+ {
+ encodeBuffer.encodeValue(GetULONG(inputMessage + 8, bigEndian_), 29, 9);
+
+ priority_++;
+ }
+ break;
+ case X_ListExtensions:
+ {
+ encodeBuffer.encodeValue(GetULONG(inputMessage + 4, bigEndian_), 32, 8);
+ unsigned int numExtensions = (unsigned int) inputMessage[1];
+ encodeBuffer.encodeValue(numExtensions, 8);
+ const unsigned char *nextSrc = inputMessage + 32;
+
+ for (; numExtensions; numExtensions--)
+ {
+ unsigned int length = (unsigned int) (*nextSrc++);
+
+ encodeBuffer.encodeValue(length, 8);
+
+ #ifdef HIDE_MIT_SHM_EXTENSION
+
+ if (!strncmp((char *) nextSrc, "MIT-SHM", 7))
+ {
+ #ifdef TEST
+ *logofs << "handleRead: Hiding MIT-SHM extension in reply.\n"
+ << logofs_flush;
+ #endif
+
+ memcpy((unsigned char *) nextSrc, "NO-MIT-", 7);
+ }
+
+ #endif
+
+ #ifdef HIDE_BIG_REQUESTS_EXTENSION
+
+ if (!strncmp((char *) nextSrc, "BIG-REQUESTS", 12))
+ {
+ #ifdef TEST
+ *logofs << "handleRead: Hiding BIG-REQUESTS extension in reply.\n"
+ << logofs_flush;
+ #endif
+
+ memcpy((unsigned char *) nextSrc, "NO-BIG-REQUE", 12);
+ }
+
+ #endif
+
+ #ifdef HIDE_XKEYBOARD_EXTENSION
+
+ if (!strncmp((char *) nextSrc, "XKEYBOARD", 9))
+ {
+ #ifdef TEST
+ *logofs << "handleRead: Hiding XKEYBOARD extension in reply.\n"
+ << logofs_flush;
+ #endif
+
+ memcpy((unsigned char *) nextSrc, "NO-XKEYBO", 9);
+ }
+
+ #endif
+
+ #ifdef HIDE_XFree86_Bigfont_EXTENSION
+
+ if (!strncmp((char *) nextSrc, "XFree86-Bigfont", 15))
+ {
+ #ifdef TEST
+ *logofs << "handleRead: Hiding XFree86-Bigfont extension in reply.\n"
+ << logofs_flush;
+ #endif
+
+ memcpy((unsigned char *) nextSrc, "NO-XFree86-Bigf", 15);
+ }
+
+ #endif
+
+ #ifdef HIDE_SHAPE_EXTENSION
+
+ if (!strncmp((char *) nextSrc, "SHAPE", 5))
+ {
+ #ifdef TEST
+ *logofs << "handleRead: Hiding SHAPE extension in reply.\n"
+ << logofs_flush;
+ #endif
+
+ memcpy((unsigned char *) nextSrc, "NO-SH", 5);
+ }
+
+ #endif
+
+ //
+ // Check if user disabled RENDER extension.
+ //
+
+ if (control -> HideRender == 1 &&
+ !strncmp((char *) nextSrc, "RENDER", 6))
+ {
+ #ifdef TEST
+ *logofs << "handleRead: Hiding RENDER extension in reply.\n"
+ << logofs_flush;
+ #endif
+
+ memcpy((unsigned char *) nextSrc, "NO-REN", 6);
+ }
+
+ for (; length; length--)
+ {
+ encodeBuffer.encodeValue((unsigned int) (*nextSrc++), 8);
+ }
+ }
+
+ priority_++;
+ }
+ break;
+ case X_ListFonts:
+ {
+ MessageStore *messageStore = serverStore_ ->
+ getReplyStore(X_ListFonts);
+
+ if (handleEncodeCached(encodeBuffer, serverCache_, messageStore,
+ inputMessage, inputLength))
+ {
+ priority_++;
+
+ hit = 1;
+
+ break;
+ }
+
+ encodeBuffer.encodeValue(GetULONG(inputMessage + 4, bigEndian_), 32, 8);
+ unsigned int numFonts = GetUINT(inputMessage + 8, bigEndian_);
+ encodeBuffer.encodeValue(numFonts, 16, 6);
+
+ // Differential encoding.
+ encodeBuffer.encodeBoolValue(1);
+
+ const unsigned char* nextSrc = inputMessage + 32;
+ for (; numFonts; numFonts--)
+ {
+ unsigned int length = (unsigned int) (*nextSrc++);
+ encodeBuffer.encodeValue(length, 8);
+
+ // Since ProtoStep7 (#issue 108)
+ encodeBuffer.encodeTextData(nextSrc, length);
+
+ nextSrc += length;
+ }
+
+ priority_++;
+ }
+ break;
+ case X_LookupColor:
+ case X_AllocNamedColor:
+ {
+ const unsigned char *nextSrc = inputMessage + 8;
+ if (requestOpcode == X_AllocNamedColor)
+ {
+ encodeBuffer.encodeValue(GetULONG(nextSrc, bigEndian_), 32, 9);
+ nextSrc += 4;
+ }
+ unsigned int count = 3;
+ do
+ {
+ unsigned int exactColor = GetUINT(nextSrc, bigEndian_);
+ encodeBuffer.encodeValue(exactColor, 16, 9);
+ unsigned int visualColor = GetUINT(nextSrc + 6, bigEndian_) -
+ exactColor;
+ encodeBuffer.encodeValue(visualColor, 16, 5);
+ nextSrc += 2;
+ }
+ while (--count);
+
+ priority_++;
+ }
+ break;
+ case X_QueryBestSize:
+ {
+ encodeBuffer.encodeValue(GetUINT(inputMessage + 8, bigEndian_), 16, 8);
+ encodeBuffer.encodeValue(GetUINT(inputMessage + 10, bigEndian_), 16, 8);
+
+ priority_++;
+ }
+ break;
+ case X_QueryColors:
+ {
+ // Differential encoding.
+ encodeBuffer.encodeBoolValue(1);
+
+ unsigned int numColors = ((inputLength - 32) >> 3);
+ const unsigned char *nextSrc = inputMessage + 40;
+ unsigned char *nextDest = (unsigned char *) inputMessage + 38;
+ for (unsigned int c = 1; c < numColors; c++)
+ {
+ for (unsigned int i = 0; i < 6; i++)
+ *nextDest++ = *nextSrc++;
+ nextSrc += 2;
+ }
+ unsigned int colorsLength = numColors * 6;
+ if (serverCache_ -> queryColorsLastReply.compare(colorsLength,
+ inputMessage + 32))
+ encodeBuffer.encodeBoolValue(1);
+ else
+ {
+ const unsigned char *nextSrc = inputMessage + 32;
+ encodeBuffer.encodeBoolValue(0);
+ encodeBuffer.encodeValue(numColors, 16, 5);
+ for (numColors *= 3; numColors; numColors--)
+ {
+ encodeBuffer.encodeValue(GetUINT(nextSrc, bigEndian_), 16);
+ nextSrc += 2;
+ }
+ }
+
+ priority_++;
+ }
+ break;
+ case X_QueryExtension:
+ {
+ if (requestData[0] == X_QueryExtension)
+ {
+ //
+ // Value in requestData[0] will be nonzero
+ // if the request is for an extension that
+ // we should hide to the X client.
+ //
+
+ if (requestData[1])
+ {
+ encodeBuffer.encodeBoolValue(0);
+ encodeBuffer.encodeValue(0, 8);
+ }
+ else
+ {
+ encodeBuffer.encodeBoolValue((unsigned int) inputMessage[8]);
+ encodeBuffer.encodeValue((unsigned int) inputMessage[9], 8);
+ }
+
+ encodeBuffer.encodeValue((unsigned int) inputMessage[10], 8);
+ encodeBuffer.encodeValue((unsigned int) inputMessage[11], 8);
+
+ if (requestData[2] == X_NXInternalShapeExtension)
+ {
+ opcodeStore_ -> shapeExtension = inputMessage[9];
+
+ #ifdef TEST
+ *logofs << "handleRead: Shape extension opcode for FD#" << fd_
+ << " is " << (unsigned int) opcodeStore_ -> shapeExtension
+ << ".\n" << logofs_flush;
+ #endif
+ }
+ else if (requestData[2] == X_NXInternalRenderExtension)
+ {
+ opcodeStore_ -> renderExtension = inputMessage[9];
+
+ #ifdef TEST
+ *logofs << "handleRead: Render extension opcode for FD#" << fd_
+ << " is " << (unsigned int) opcodeStore_ -> renderExtension
+ << ".\n" << logofs_flush;
+ #endif
+ }
+
+ priority_++;
+ }
+ else
+ {
+ #ifdef TEST
+ *logofs << "handleRead: Received tainted X_QueryExtension reply "
+ << "for request OPCODE#" << requestData[0] << " with "
+ << "sequence " << sequenceNum << ".\n"
+ << logofs_flush;
+ #endif
+
+ if (requestData[0] == opcodeStore_ -> getShmemParameters)
+ {
+ if (handleShmemReply(encodeBuffer, requestOpcode, requestData[1],
+ inputMessage, inputLength) < 0)
+ {
+ return -1;
+ }
+
+ priority_++;
+ }
+ //
+ // Account this data to the original opcode.
+ //
+
+ requestOpcode = requestData[0];
+ }
+ }
+ break;
+ case X_QueryFont:
+ {
+ MessageStore *messageStore = serverStore_ ->
+ getReplyStore(X_QueryFont);
+
+ if (handleEncodeCached(encodeBuffer, serverCache_, messageStore,
+ inputMessage, inputLength))
+ {
+ priority_++;
+
+ hit = 1;
+
+ break;
+ }
+
+ // Differential encoding.
+ encodeBuffer.encodeBoolValue(1);
+
+ unsigned int numProperties = GetUINT(inputMessage + 46, bigEndian_);
+ unsigned int numCharInfos = GetULONG(inputMessage + 56, bigEndian_);
+ encodeBuffer.encodeValue(numProperties, 16, 8);
+ encodeBuffer.encodeValue(numCharInfos, 32, 10);
+ handleEncodeCharInfo(inputMessage + 8, encodeBuffer);
+ handleEncodeCharInfo(inputMessage + 24, encodeBuffer);
+ encodeBuffer.encodeValue(GetUINT(inputMessage + 40, bigEndian_), 16, 9);
+ encodeBuffer.encodeValue(GetUINT(inputMessage + 42, bigEndian_), 16, 9);
+ encodeBuffer.encodeValue(GetUINT(inputMessage + 44, bigEndian_), 16, 9);
+ encodeBuffer.encodeBoolValue((unsigned int) inputMessage[48]);
+ encodeBuffer.encodeValue((unsigned int) inputMessage[49], 8);
+ encodeBuffer.encodeValue((unsigned int) inputMessage[50], 8);
+ encodeBuffer.encodeBoolValue((unsigned int) inputMessage[51]);
+ encodeBuffer.encodeValue(GetUINT(inputMessage + 52, bigEndian_), 16, 9);
+ encodeBuffer.encodeValue(GetUINT(inputMessage + 54, bigEndian_), 16, 9);
+ const unsigned char *nextSrc = inputMessage + 60;
+ unsigned int index;
+
+ int end = 0;
+
+ if (ServerCache::queryFontFontCache.lookup(numProperties * 8 +
+ numCharInfos * 12, nextSrc, index))
+ {
+ encodeBuffer.encodeBoolValue(1);
+ encodeBuffer.encodeValue(index, 4);
+
+ end = 1;
+ }
+
+ if (end == 0)
+ {
+ encodeBuffer.encodeBoolValue(0);
+ for (; numProperties; numProperties--)
+ {
+ encodeBuffer.encodeValue(GetULONG(nextSrc, bigEndian_), 32, 9);
+ encodeBuffer.encodeValue(GetULONG(nextSrc + 4, bigEndian_), 32, 9);
+ nextSrc += 8;
+ }
+ for (; numCharInfos; numCharInfos--)
+ {
+ handleEncodeCharInfo(nextSrc, encodeBuffer);
+
+ nextSrc += 12;
+ }
+ }
+
+ priority_++;
+ }
+ break;
+ case X_QueryPointer:
+ {
+ encodeBuffer.encodeBoolValue((unsigned int) inputMessage[1]);
+ encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 8, bigEndian_),
+ 29, serverCache_ -> queryPointerRootCache, 9);
+ encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 12, bigEndian_),
+ 29, serverCache_ -> queryPointerChildCache, 9);
+ unsigned int rootX = GetUINT(inputMessage + 16, bigEndian_);
+ unsigned int rootY = GetUINT(inputMessage + 18, bigEndian_);
+ unsigned int eventX = GetUINT(inputMessage + 20, bigEndian_);
+ unsigned int eventY = GetUINT(inputMessage + 22, bigEndian_);
+ eventX -= rootX;
+ eventY -= rootY;
+ encodeBuffer.encodeCachedValue(
+ rootX - serverCache_ -> motionNotifyLastRootX, 16,
+ serverCache_ -> motionNotifyRootXCache, 8);
+ serverCache_ -> motionNotifyLastRootX = rootX;
+ encodeBuffer.encodeCachedValue(
+ rootY - serverCache_ -> motionNotifyLastRootY, 16,
+ serverCache_ -> motionNotifyRootYCache, 8);
+ serverCache_ -> motionNotifyLastRootY = rootY;
+ encodeBuffer.encodeCachedValue(eventX, 16,
+ serverCache_ -> motionNotifyEventXCache, 8);
+ encodeBuffer.encodeCachedValue(eventY, 16,
+ serverCache_ -> motionNotifyEventYCache, 8);
+ encodeBuffer.encodeCachedValue(GetUINT(inputMessage + 24, bigEndian_),
+ 16, serverCache_ -> motionNotifyStateCache);
+ priority_++;
+ }
+ break;
+ case X_QueryTree:
+ {
+ //
+ // This was very inefficient. In practice
+ // it just copied data on the output. Now
+ // it obtains an average 7:1 compression
+ // and could optionally be cached.
+ //
+
+ unsigned int children = GetUINT(inputMessage + 16, bigEndian_);
+
+ encodeBuffer.encodeValue(children, 16, 8);
+
+ encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 8, bigEndian_), 29,
+ serverCache_ -> queryTreeWindowCache);
+
+ encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 12, bigEndian_), 29,
+ serverCache_ -> queryTreeWindowCache);
+
+ const unsigned char *next = inputMessage + 32;
+
+ for (unsigned int i = 0; i < children; i++)
+ {
+ encodeBuffer.encodeCachedValue(GetULONG(next + (i * 4), bigEndian_), 29,
+ serverCache_ -> queryTreeWindowCache);
+ }
+
+ priority_++;
+ }
+ break;
+ case X_TranslateCoords:
+ {
+ encodeBuffer.encodeBoolValue((unsigned int) inputMessage[1]);
+ encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 8, bigEndian_),
+ 29, serverCache_ -> translateCoordsChildCache, 9);
+ encodeBuffer.encodeCachedValue(GetUINT(inputMessage + 12, bigEndian_),
+ 16, serverCache_ -> translateCoordsXCache, 8);
+ encodeBuffer.encodeCachedValue(GetUINT(inputMessage + 14, bigEndian_),
+ 16, serverCache_ -> translateCoordsYCache, 8);
+ priority_++;
+ }
+ break;
+ case X_GetImage:
+ {
+ MessageStore *messageStore = serverStore_ ->
+ getReplyStore(X_GetImage);
+
+ if (handleEncodeCached(encodeBuffer, serverCache_, messageStore,
+ inputMessage, inputLength))
+ {
+ priority_++;
+
+ hit = 1;
+
+ break;
+ }
+
+ // Depth.
+ encodeBuffer.encodeCachedValue(inputMessage[1], 8,
+ serverCache_ -> depthCache);
+ // Reply length.
+ encodeBuffer.encodeValue(GetULONG(inputMessage + 4, bigEndian_), 32, 9);
+
+ // Visual.
+ encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 8, bigEndian_), 29,
+ serverCache_ -> visualCache);
+
+ // Since ProtoStep8 (#issue 108)
+ handleCopy(encodeBuffer, requestOpcode, messageStore ->
+ dataOffset, inputMessage, inputLength);
+
+ priority_++;
+ }
+ break;
+ case X_GetPointerMapping:
+ {
+ encodeBuffer.encodeValue(inputMessage[1], 8, 4);
+ encodeBuffer.encodeValue(GetULONG(inputMessage + 4, bigEndian_), 32, 4);
+ for (unsigned int i = 32; i < inputLength; i++)
+ encodeBuffer.encodeValue((unsigned int) inputMessage[i], 8, 4);
+
+ priority_++;
+ }
+ break;
+ case X_GetKeyboardControl:
+ {
+ encodeBuffer.encodeValue(inputMessage[1], 8, 2);
+ encodeBuffer.encodeValue(GetULONG(inputMessage + 4, bigEndian_), 32, 8);
+ for (unsigned int i = 8; i < inputLength; i++)
+ encodeBuffer.encodeValue((unsigned int) inputMessage[i], 8, 4);
+
+ priority_++;
+ }
+ break;
+ default:
+ {
+ #ifdef PANIC
+ *logofs << "ServerChannel: PANIC! No matching request with "
+ << "OPCODE#" << (unsigned int) requestOpcode
+ << " for reply with sequence number "
+ << requestSequenceNum << ".\n"
+ << logofs_flush;
+ #endif
+
+ cerr << "Error" << ": No matching request with OPCODE#"
+ << (unsigned int) requestOpcode << " for reply with "
+ << "sequence number " << requestSequenceNum << ".\n";
+
+ return -1;
+ }
+ }
+
+ bits = encodeBuffer.diffBits();
+
+ #if defined(TEST) || defined(OPCODES)
+
+ const char *cacheString = (hit ? "cached " : "");
+
+ *logofs << "handleRead: Handled " << cacheString << "reply to OPCODE#"
+ << (unsigned int) requestOpcode << " (" << DumpOpcode(requestOpcode)
+ << ") for FD#" << fd_ << " sequence " << serverSequence_
+ << ". " << inputLength << " bytes in, " << bits << " bits ("
+ << ((float) bits) / 8 << " bytes) out.\n" << logofs_flush;
+
+ #endif
+
+ } // End of if (sequenceQueue_.peek(requestSequenceNum, requestOpcode) && ...
+ else
+ {
+ //
+ // We didn't push the request opcode.
+ // Check if fast encoding is required.
+ //
+
+ requestOpcode = X_Reply;
+
+ if (control -> LocalDeltaCompression == 0)
+ {
+ int result = handleFastReadReply(encodeBuffer, requestOpcode,
+ inputMessage, inputLength);
+ if (result < 0)
+ {
+ return -1;
+ }
+ else if (result > 0)
+ {
+ continue;
+ }
+ }
+
+ //
+ // Group all replies whose opcode was not
+ // pushed in sequence number queue under
+ // the category 'generic reply'.
+ //
+
+ #ifdef DEBUG
+ *logofs << "handleRead: Identified generic reply.\n"
+ << logofs_flush;
+ #endif
+
+ MessageStore *messageStore = serverStore_ ->
+ getReplyStore(X_NXInternalGenericReply);
+
+ hit = handleEncode(encodeBuffer, serverCache_, messageStore,
+ requestOpcode, inputMessage, inputLength);
+
+ priority_++;
+
+ bits = encodeBuffer.diffBits();
+
+ #if defined(TEST) || defined(OPCODES)
+
+ const char *cacheString = (hit ? "cached " : "");
+
+ *logofs << "handleRead: Handled " << cacheString << "generic reply "
+ << "OPCODE#" << X_NXInternalGenericReply << " for FD#" << fd_
+ << " sequence " << serverSequence_ << ". " << inputLength
+ << " bytes in, " << bits << " bits (" << ((float) bits) / 8
+ << " bytes) out.\n" << logofs_flush;
+
+ #endif
+ }
+
+ if (hit)
+ {
+ statistics -> addCachedReply(requestOpcode);
+ }
+
+ statistics -> addReplyBits(requestOpcode, inputLength << 3, bits);
+
+ } // End of if (inputMessage[0] == 1) ...
+ else
+ {
+ //
+ // Event or error.
+ //
+
+ unsigned char inputOpcode = *inputMessage;
+
+ unsigned int inputSequence = GetUINT(inputMessage + 2, bigEndian_);
+
+ //
+ // Check if this is an event which we can discard.
+ //
+
+ if ((inputOpcode == Expose && enableExpose_ == 0) ||
+ (inputOpcode == GraphicsExpose && enableGraphicsExpose_ == 0) ||
+ (inputOpcode == NoExpose && enableNoExpose_ == 0))
+ {
+ continue;
+ }
+ else if (shmemState_ != NULL && shmemState_ -> enabled == 1 &&
+ inputOpcode == shmemState_ -> event &&
+ checkShmemEvent(inputOpcode, inputSequence,
+ inputMessage) > 0)
+ {
+ continue;
+ }
+ else if (inputOpcode == MotionNotify)
+ {
+ //
+ // Save the motion event and send when another
+ // event or error is received or the motion ti-
+ // meout is elapsed. If a previous motion event
+ // was already saved, we replace it with the
+ // new one and don't reset the timeout, so we
+ // still have a motion event every given ms.
+ //
+
+ memcpy(lastMotion_, inputMessage, 32);
+
+ #ifdef TEST
+ *logofs << "handleRead: Saved suppressed motion event for FD#"
+ << fd_ << ".\n" << logofs_flush;
+ #endif
+
+ continue;
+ }
+ else if (inputOpcode == X_Error)
+ {
+ //
+ // Check if this is an error that matches a
+ // sequence number for which we are expecting
+ // a reply.
+ //
+
+ unsigned short int errorSequenceNum;
+ unsigned char errorOpcode;
+
+ if (sequenceQueue_.peek(errorSequenceNum, errorOpcode) &&
+ ((unsigned int) errorSequenceNum == inputSequence))
+ {
+ sequenceQueue_.pop(errorSequenceNum, errorOpcode);
+ }
+
+ //
+ // Check if error is due to an image commit
+ // generated at the end of a split.
+ //
+
+ if (checkCommitError(*(inputMessage + 1), inputSequence, inputMessage) > 0)
+ {
+ #ifdef TEST
+ *logofs << "handleRead: Skipping error on image commit for FD#"
+ << fd_ << ".\n" << logofs_flush;
+ #endif
+
+ continue;
+ }
+
+ //
+ // Check if it's an error generated by a request
+ // concerning shared memory support.
+ //
+
+ else if (shmemState_ != NULL && (shmemState_ -> sequence ==
+ inputSequence || (shmemState_ -> enabled == 1 &&
+ (shmemState_ -> opcode == *(inputMessage + 10) ||
+ shmemState_ -> error == *(inputMessage + 1)))) &&
+ checkShmemError(*(inputMessage + 1), inputSequence,
+ inputMessage) > 0)
+ {
+ #ifdef TEST
+ *logofs << "handleRead: Skipping error on shmem operation for FD#"
+ << fd_ << ".\n" << logofs_flush;
+ #endif
+
+ continue;
+ }
+ }
+ //
+ // Check if user pressed the CTRL+ALT+SHIFT+ESC key
+ // sequence because was unable to kill the session
+ // through the normal procedure.
+ //
+
+ if (inputOpcode == KeyPress)
+ {
+ if (checkKeyboardEvent(inputOpcode, inputSequence, inputMessage) == 1)
+ {
+ #ifdef TEST
+ *logofs << "handleRead: Removing the key sequence from the "
+ << "event stream for FD#" << fd_ << ".\n"
+ << logofs_flush;
+ #endif
+
+ continue;
+ }
+ }
+
+ //
+ // We are going to handle an event or error
+ // that's not a mouse motion. Prepend any
+ // saved motion to it.
+ //
+
+ if (lastMotion_[0] != '\0')
+ {
+ if (handleMotion(encodeBuffer) < 0)
+ {
+ #ifdef PANIC
+ *logofs << "handleRead: PANIC! Can't encode motion event for FD#"
+ << fd_ << ".\n" << logofs_flush;
+ #endif
+
+ cerr << "Error" << ": Can't encode motion event for FD#"
+ << fd_ << ".\n";
+
+ return -1;
+ }
+ }
+
+ //
+ // Encode opcode and difference between
+ // current sequence and the last one.
+ //
+
+ encodeBuffer.encodeOpcodeValue(inputOpcode, serverCache_ -> opcodeCache);
+
+ unsigned int sequenceDiff = inputSequence - serverSequence_;
+
+ serverSequence_ = inputSequence;
+
+ #ifdef DEBUG
+ *logofs << "handleRead: Last server sequence number for FD#"
+ << fd_ << " is " << serverSequence_ << " with "
+ << "difference " << sequenceDiff << ".\n"
+ << logofs_flush;
+ #endif
+
+ encodeBuffer.encodeCachedValue(sequenceDiff, 16,
+ serverCache_ -> eventSequenceCache, 7);
+
+ //
+ // If differential compression is disabled
+ // then use the most simple encoding.
+ //
+
+ if (control -> LocalDeltaCompression == 0)
+ {
+ int result = handleFastReadEvent(encodeBuffer, inputOpcode,
+ inputMessage, inputLength);
+ if (result < 0)
+ {
+ return -1;
+ }
+ else if (result > 0)
+ {
+ continue;
+ }
+ }
+
+ switch (inputOpcode)
+ {
+ case X_Error:
+ {
+ //
+ // Set the priority flag in the case of
+ // a X protocol error. This may restart
+ // the client if it was waiting for the
+ // reply.
+ //
+
+ priority_++;
+
+ unsigned char errorCode = *(inputMessage + 1);
+
+ encodeBuffer.encodeCachedValue(errorCode, 8,
+ serverCache_ -> errorCodeCache);
+
+ if (errorCode != 11 && errorCode != 8 &&
+ errorCode != 15 && errorCode != 1)
+ {
+ encodeBuffer.encodeValue(GetULONG(inputMessage + 4, bigEndian_), 32, 16);
+ }
+
+ if (errorCode >= 18)
+ {
+ encodeBuffer.encodeCachedValue(GetUINT(inputMessage + 8, bigEndian_), 16,
+ serverCache_ -> errorMinorCache);
+ }
+
+ encodeBuffer.encodeCachedValue(inputMessage[10], 8,
+ serverCache_ -> errorMajorCache);
+
+ if (errorCode >= 18)
+ {
+ const unsigned char *nextSrc = inputMessage + 11;
+ for (unsigned int i = 11; i < 32; i++)
+ encodeBuffer.encodeValue(*nextSrc++, 8);
+ }
+ }
+ break;
+ case ButtonPress:
+ case ButtonRelease:
+ case KeyPress:
+ case KeyRelease:
+ case MotionNotify:
+ case EnterNotify:
+ case LeaveNotify:
+ {
+ //
+ // Set the priority in the case this is
+ // an event that the remote side may
+ // care to receive as soon as possible.
+ //
+
+ switch (inputOpcode)
+ {
+ case ButtonPress:
+ case ButtonRelease:
+ case KeyPress:
+ case KeyRelease:
+ {
+ priority_++;
+ }
+ }
+
+ unsigned char detail = inputMessage[1];
+ if (*inputMessage == MotionNotify)
+ encodeBuffer.encodeBoolValue((unsigned int) detail);
+ else if ((*inputMessage == EnterNotify) || (*inputMessage == LeaveNotify))
+ encodeBuffer.encodeValue((unsigned int) detail, 3);
+ else if (*inputMessage == KeyRelease)
+ {
+ if (detail == serverCache_ -> keyPressLastKey)
+ encodeBuffer.encodeBoolValue(1);
+ else
+ {
+ encodeBuffer.encodeBoolValue(0);
+ encodeBuffer.encodeValue((unsigned int) detail, 8);
+ }
+ }
+ else if ((*inputMessage == ButtonPress) || (*inputMessage == ButtonRelease))
+ encodeBuffer.encodeCachedValue(detail, 8,
+ serverCache_ -> buttonCache);
+ else
+ encodeBuffer.encodeValue((unsigned int) detail, 8);
+ unsigned int timestamp = GetULONG(inputMessage + 4, bigEndian_);
+ unsigned int timestampDiff =
+ timestamp - serverCache_ -> lastTimestamp;
+ serverCache_ -> lastTimestamp = timestamp;
+ encodeBuffer.encodeCachedValue(timestampDiff, 32,
+ serverCache_ -> motionNotifyTimestampCache, 9);
+ int skipRest = 0;
+ if (*inputMessage == KeyRelease)
+ {
+ skipRest = 1;
+ for (unsigned int i = 8; i < 31; i++)
+ {
+ if (inputMessage[i] != serverCache_ -> keyPressCache[i - 8])
+ {
+ skipRest = 0;
+ break;
+ }
+ }
+ encodeBuffer.encodeBoolValue(skipRest);
+ }
+
+ if (!skipRest)
+ {
+ const unsigned char *nextSrc = inputMessage + 8;
+ for (unsigned int i = 0; i < 3; i++)
+ {
+ encodeBuffer.encodeCachedValue(GetULONG(nextSrc, bigEndian_), 29,
+ *serverCache_ -> motionNotifyWindowCache[i], 6);
+ nextSrc += 4;
+ }
+ unsigned int rootX = GetUINT(inputMessage + 20, bigEndian_);
+ unsigned int rootY = GetUINT(inputMessage + 22, bigEndian_);
+ unsigned int eventX = GetUINT(inputMessage + 24, bigEndian_);
+ unsigned int eventY = GetUINT(inputMessage + 26, bigEndian_);
+ eventX -= rootX;
+ eventY -= rootY;
+ encodeBuffer.encodeCachedValue(rootX -
+ serverCache_ -> motionNotifyLastRootX, 16,
+ serverCache_ -> motionNotifyRootXCache, 6);
+ serverCache_ -> motionNotifyLastRootX = rootX;
+ encodeBuffer.encodeCachedValue(rootY -
+ serverCache_ -> motionNotifyLastRootY, 16,
+ serverCache_ -> motionNotifyRootYCache, 6);
+ serverCache_ -> motionNotifyLastRootY = rootY;
+ encodeBuffer.encodeCachedValue(eventX, 16,
+ serverCache_ -> motionNotifyEventXCache, 6);
+ encodeBuffer.encodeCachedValue(eventY, 16,
+ serverCache_ -> motionNotifyEventYCache, 6);
+ encodeBuffer.encodeCachedValue(GetUINT(inputMessage + 28, bigEndian_),
+ 16, serverCache_ -> motionNotifyStateCache);
+ if ((*inputMessage == EnterNotify) || (*inputMessage == LeaveNotify))
+ encodeBuffer.encodeValue((unsigned int) inputMessage[30], 2);
+ else
+ encodeBuffer.encodeBoolValue((unsigned int) inputMessage[30]);
+ if ((*inputMessage == EnterNotify) || (*inputMessage == LeaveNotify))
+ encodeBuffer.encodeValue((unsigned int) inputMessage[31], 2);
+ else if (*inputMessage == KeyPress)
+ {
+ serverCache_ -> keyPressLastKey = detail;
+ for (unsigned int i = 8; i < 31; i++)
+ {
+ serverCache_ -> keyPressCache[i - 8] = inputMessage[i];
+ }
+ }
+ }
+ }
+ break;
+ case ColormapNotify:
+ {
+ encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 4, bigEndian_),
+ 29, serverCache_ -> colormapNotifyWindowCache, 8);
+ encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 8, bigEndian_),
+ 29, serverCache_ -> colormapNotifyColormapCache, 8);
+ encodeBuffer.encodeBoolValue((unsigned int) inputMessage[12]);
+ encodeBuffer.encodeBoolValue((unsigned int) inputMessage[13]);
+ }
+ break;
+ case ConfigureNotify:
+ {
+ const unsigned char *nextSrc = inputMessage + 4;
+ for (unsigned int i = 0; i < 3; i++)
+ {
+ encodeBuffer.encodeCachedValue(GetULONG(nextSrc, bigEndian_), 29,
+ *serverCache_ -> configureNotifyWindowCache[i], 9);
+ nextSrc += 4;
+ }
+ for (unsigned int j = 0; j < 5; j++)
+ {
+ encodeBuffer.encodeCachedValue(GetUINT(nextSrc, bigEndian_), 16,
+ *serverCache_ -> configureNotifyGeomCache[j], 8);
+ nextSrc += 2;
+ }
+ encodeBuffer.encodeBoolValue(*nextSrc);
+ }
+ break;
+ case CreateNotify:
+ {
+ encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 4, bigEndian_),
+ 29, serverCache_ -> createNotifyWindowCache, 9);
+ unsigned int window = GetULONG(inputMessage + 8, bigEndian_);
+ encodeBuffer.encodeValue(window -
+ serverCache_ -> createNotifyLastWindow, 29, 5);
+ serverCache_ -> createNotifyLastWindow = window;
+ const unsigned char* nextSrc = inputMessage + 12;
+ for (unsigned int i = 0; i < 5; i++)
+ {
+ encodeBuffer.encodeValue(GetUINT(nextSrc, bigEndian_), 16, 9);
+ nextSrc += 2;
+ }
+ encodeBuffer.encodeBoolValue(*nextSrc);
+ }
+ break;
+ case Expose:
+ {
+ encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 4, bigEndian_), 29,
+ serverCache_ -> exposeWindowCache, 9);
+ const unsigned char *nextSrc = inputMessage + 8;
+ for (unsigned int i = 0; i < 5; i++)
+ {
+ encodeBuffer.encodeCachedValue(GetUINT(nextSrc, bigEndian_), 16,
+ *serverCache_ -> exposeGeomCache[i], 6);
+ nextSrc += 2;
+ }
+ }
+ break;
+ case FocusIn:
+ case FocusOut:
+ {
+ encodeBuffer.encodeValue((unsigned int) inputMessage[1], 3);
+ encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 4, bigEndian_),
+ 29, serverCache_ -> focusInWindowCache, 9);
+ encodeBuffer.encodeValue((unsigned int) inputMessage[8], 2);
+ }
+ break;
+ case KeymapNotify:
+ {
+ if (ServerCache::lastKeymap.compare(31, inputMessage + 1))
+ encodeBuffer.encodeBoolValue(1);
+ else
+ {
+ encodeBuffer.encodeBoolValue(0);
+ const unsigned char *nextSrc = inputMessage + 1;
+ for (unsigned int i = 1; i < 32; i++)
+ encodeBuffer.encodeValue((unsigned int) *nextSrc++, 8);
+ }
+ }
+ break;
+ case MapNotify:
+ case UnmapNotify:
+ case DestroyNotify:
+ {
+ encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 4, bigEndian_),
+ 29, serverCache_ -> mapNotifyEventCache, 9);
+ encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 8, bigEndian_),
+ 29, serverCache_ -> mapNotifyWindowCache, 9);
+ if ((*inputMessage == MapNotify) || (*inputMessage == UnmapNotify))
+ encodeBuffer.encodeBoolValue((unsigned int) inputMessage[12]);
+ }
+ break;
+ case NoExpose:
+ {
+ encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 4, bigEndian_),
+ 29, serverCache_ -> noExposeDrawableCache, 9);
+ encodeBuffer.encodeCachedValue(GetUINT(inputMessage + 8, bigEndian_), 16,
+ serverCache_ -> noExposeMinorCache);
+ encodeBuffer.encodeCachedValue(inputMessage[10], 8,
+ serverCache_ -> noExposeMajorCache);
+ }
+ break;
+ case PropertyNotify:
+ {
+ encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 4, bigEndian_),
+ 29, serverCache_ -> propertyNotifyWindowCache, 9);
+ encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 8, bigEndian_),
+ 29, serverCache_ -> propertyNotifyAtomCache, 9);
+ unsigned int timestamp = GetULONG(inputMessage + 12, bigEndian_);
+ unsigned int timestampDiff =
+ timestamp - serverCache_ -> lastTimestamp;
+ serverCache_ -> lastTimestamp = timestamp;
+ encodeBuffer.encodeValue(timestampDiff, 32, 9);
+ encodeBuffer.encodeBoolValue((unsigned int) inputMessage[16]);
+ }
+ break;
+ case ReparentNotify:
+ {
+ const unsigned char* nextSrc = inputMessage + 4;
+ for (unsigned int i = 0; i < 3; i++)
+ {
+ encodeBuffer.encodeCachedValue(GetULONG(nextSrc, bigEndian_),
+ 29, serverCache_ -> reparentNotifyWindowCache, 9);
+ nextSrc += 4;
+ }
+ encodeBuffer.encodeValue(GetUINT(nextSrc, bigEndian_), 16, 6);
+ encodeBuffer.encodeValue(GetUINT(nextSrc + 2, bigEndian_), 16, 6);
+ encodeBuffer.encodeBoolValue((unsigned int)inputMessage[20]);
+ }
+ break;
+ case SelectionClear:
+ {
+ unsigned int timestamp = GetULONG(inputMessage + 4, bigEndian_);
+ unsigned int timestampDiff = timestamp - serverCache_ -> lastTimestamp;
+ serverCache_ -> lastTimestamp = timestamp;
+ encodeBuffer.encodeValue(timestampDiff, 32, 9);
+ encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 8, bigEndian_),
+ 29, serverCache_ -> selectionClearWindowCache, 9);
+ encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 12, bigEndian_),
+ 29, serverCache_ -> selectionClearAtomCache, 9);
+ }
+ break;
+ case SelectionRequest:
+ {
+ unsigned int timestamp = GetULONG(inputMessage + 4, bigEndian_);
+ unsigned int timestampDiff = timestamp - serverCache_ -> lastTimestamp;
+ serverCache_ -> lastTimestamp = timestamp;
+ encodeBuffer.encodeValue(timestampDiff, 32, 9);
+ encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 8, bigEndian_),
+ 29, serverCache_ -> selectionClearWindowCache, 9);
+ encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 12, bigEndian_),
+ 29, serverCache_ -> selectionClearWindowCache, 9);
+ encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 16, bigEndian_),
+ 29, serverCache_ -> selectionClearAtomCache, 9);
+ encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 20, bigEndian_),
+ 29, serverCache_ -> selectionClearAtomCache, 9);
+ encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 24, bigEndian_),
+ 29, serverCache_ -> selectionClearAtomCache, 9);
+ }
+ break;
+ case VisibilityNotify:
+ {
+ encodeBuffer.encodeCachedValue(GetULONG(inputMessage + 4, bigEndian_),
+ 29, serverCache_ -> visibilityNotifyWindowCache, 9);
+ encodeBuffer.encodeValue((unsigned int) inputMessage[8], 2);
+ }
+ break;
+ default:
+ {
+ #ifdef TEST
+ *logofs << "handleRead: Using generic event compression "
+ << "for OPCODE#" << (unsigned int) inputOpcode
+ << ".\n" << logofs_flush;
+ #endif
+
+ encodeBuffer.encodeCachedValue(*(inputMessage + 1), 8,
+ serverCache_ -> genericEventCharCache);
+
+ for (unsigned int i = 0; i < 14; i++)
+ {
+ encodeBuffer.encodeCachedValue(GetUINT(inputMessage + i * 2 + 4, bigEndian_),
+ 16, *serverCache_ -> genericEventIntCache[i]);
+ }
+ }
+
+ } // switch (inputOpcode)...
+
+ int bits = encodeBuffer.diffBits();
+
+ #if defined(TEST) || defined(OPCODES)
+
+ if (*inputMessage == X_Error)
+ {
+ unsigned char code = *(inputMessage + 1);
+
+ *logofs << "handleRead: Handled error ERR_CODE#"
+ << (unsigned int) code << " for FD#" << fd_;
+
+ *logofs << " RES_ID#" << GetULONG(inputMessage + 4, bigEndian_);
+
+ *logofs << " MIN_OP#" << GetUINT(inputMessage + 8, bigEndian_);
+
+ *logofs << " MAJ_OP#" << (unsigned int) *(inputMessage + 10);
+
+ *logofs << " sequence " << inputSequence << ". " << inputLength
+ << " bytes in, " << bits << " bits (" << ((float) bits) / 8
+ << " bytes) out.\n" << logofs_flush;
+ }
+ else
+ {
+ *logofs << "handleRead: Handled event OPCODE#"
+ << (unsigned int) *inputMessage << " for FD#" << fd_
+ << " sequence " << inputSequence << ". " << inputLength
+ << " bytes in, " << bits << " bits (" << ((float) bits) / 8
+ << " bytes) out.\n" << logofs_flush;
+ }
+
+ #endif
+
+ statistics -> addEventBits(*inputMessage, inputLength << 3, bits);
+
+ } // End of if (inputMessage[0] == X_Reply) ... else ...
+
+ } // End of if (firstReply_) ... else ...
+
+ } // End of while ((inputMessage = readBuffer_.getMessage(inputLength)) != 0) ...
+
+ //
+ // Check if we need to flush because of
+ // prioritized data.
+ //
+
+ if (priority_ > 0)
+ {
+ #if defined(TEST) || defined(INFO)
+ *logofs << "handleRead: WARNING! Requesting flush "
+ << "because of " << priority_ << " prioritized "
+ << "messages for FD#" << fd_ << ".\n"
+ << logofs_flush;
+ #endif
+
+ if (proxy -> handleAsyncPriority() < 0)
+ {
+ return -1;
+ }
+
+ //
+ // Reset the priority flag.
+ //
+
+ priority_ = 0;
+ }
+
+ //
+ // Flush if we produced enough data.
+ //
+
+ if (proxy -> canAsyncFlush() == 1)
+ {
+ #if defined(TEST) || defined(INFO)
+ *logofs << "handleRead: WARNING! Requesting flush "
+ << "because of token length exceeded.\n"
+ << logofs_flush;
+ #endif
+
+ if (proxy -> handleAsyncFlush() < 0)
+ {
+ return -1;
+ }
+ }
+
+ #if defined(TEST) || defined(INFO)
+
+ if (transport_ -> pending() != 0 ||
+ readBuffer_.checkMessage() != 0)
+ {
+ *logofs << "handleRead: PANIC! Buffer for X descriptor FD#"
+ << fd_ << " has " << transport_ -> pending()
+ << " bytes to read.\n" << logofs_flush;
+
+ HandleCleanup();
+ }
+
+ #endif
+
+ //
+ // Reset the read buffer.
+ //
+
+ readBuffer_.fullReset();
+
+ return 1;
+}
+
+//
+// End of handleRead().
+//
+
+//
+// Beginning of handleWrite().
+//
+
+int ServerChannel::handleWrite(const unsigned char *message, unsigned int length)
+{
+ #ifdef TEST
+ *logofs << "handleWrite: Called for FD#" << fd_
+ << ".\n" << logofs_flush;
+ #endif
+
+ //
+ // Create the buffer from which to
+ // decode messages.
+ //
+
+ DecodeBuffer decodeBuffer(message, length);
+
+ #if defined(TEST) || defined(INFO) || defined(FLUSH)
+ *logofs << "handleWrite: Decoding messages for FD#" << fd_
+ << " with " << length << " bytes in the buffer.\n"
+ << logofs_flush;
+ #endif
+
+ if (firstRequest_)
+ {
+ //
+ // Need to add the length of the first request
+ // because it was not present in the previous
+ // versions. Length of the first request was
+ // assumed to be the same as the encode buffer
+ // but this may be not the case if a different
+ // encoding is used.
+ //
+
+ // Since ProtoStep7 (#issue 108)
+ decodeBuffer.decodeValue(length, 8);
+
+ unsigned int nextByte;
+ unsigned char *outputMessage = writeBuffer_.addMessage(length);
+ unsigned char *nextDest = outputMessage;
+
+ for (unsigned int i = 0; i < length; i++)
+ {
+ decodeBuffer.decodeValue(nextByte, 8);
+
+ *nextDest++ = (unsigned char) nextByte;
+ }
+
+ if (*outputMessage == 0x42)
+ {
+ setBigEndian(1);
+ }
+ else
+ {
+ setBigEndian(0);
+ }
+
+ #ifdef TEST
+ *logofs << "handleWrite: First request detected.\n" << logofs_flush;
+ #endif
+
+ //
+ // Handle the fake authorization cookie.
+ //
+
+ if (handleAuthorization(outputMessage) < 0)
+ {
+ return -1;
+ }
+
+ firstRequest_ = 0;
+
+ } // End of if (firstRequest_)
+
+ //
+ // This was previously in a 'else' block.
+ // Due to the way the first request was
+ // handled, we could not decode multiple
+ // messages in the first frame.
+ //
+
+ { // Start of the decoding block.
+
+ unsigned char outputOpcode;
+
+ unsigned char *outputMessage;
+ unsigned int outputLength;
+
+ //
+ // Set when message is found in cache.
+ //
+
+ int hit;
+
+ while (decodeBuffer.decodeOpcodeValue(outputOpcode, clientCache_ -> opcodeCache, 1))
+ {
+ hit = 0;
+
+ //
+ // Splits are sent by client proxy outside the
+ // normal read loop. As we 'insert' splits in
+ // the real client-server X protocol, we must
+ // avoid to increment the sequence number or
+ // our clients would get confused.
+ //
+
+ if (outputOpcode != opcodeStore_ -> splitData)
+ {
+ clientSequence_++;
+ clientSequence_ &= 0xffff;
+
+ #ifdef DEBUG
+ *logofs << "handleWrite: Last client sequence number for FD#"
+ << fd_ << " is " << clientSequence_ << ".\n"
+ << logofs_flush;
+ #endif
+ }
+ else
+ {
+ //
+ // It's a split, not a normal
+ // burst of proxy data.
+ //
+
+ handleSplit(decodeBuffer);
+
+ continue;
+ }
+
+ #ifdef SUSPEND
+
+ if (clientSequence_ == 1000)
+ {
+ cerr << "Warning" << ": Exiting to test the resilience of the agent.\n";
+
+ sleep(2);
+
+ HandleAbort();
+ }
+
+ #endif
+
+ //
+ // Is differential encoding disabled?
+ //
+
+ if (control -> RemoteDeltaCompression == 0)
+ {
+ int result = handleFastWriteRequest(decodeBuffer, outputOpcode,
+ outputMessage, outputLength);
+ if (result < 0)
+ {
+ return -1;
+ }
+ else if (result > 0)
+ {
+ continue;
+ }
+ }
+
+ //
+ // General-purpose temp variables for
+ // decoding ints and chars.
+ //
+
+ unsigned int value;
+ unsigned char cValue;
+
+ #ifdef DEBUG
+ *logofs << "handleWrite: Going to handle request OPCODE#"
+ << (unsigned int) outputOpcode << " (" << DumpOpcode(outputOpcode)
+ << ") for FD#" << fd_ << " sequence " << clientSequence_
+ << ".\n" << logofs_flush;
+ #endif
+
+ switch (outputOpcode)
+ {
+ case X_AllocColor:
+ {
+ outputLength = 16;
+ outputMessage = writeBuffer_.addMessage(outputLength);
+ decodeBuffer.decodeCachedValue(value, 29,
+ clientCache_ -> colormapCache);
+ PutULONG(value, outputMessage + 4, bigEndian_);
+ unsigned char *nextDest = outputMessage + 8;
+ unsigned int colorData[3];
+
+ for (unsigned int i = 0; i < 3; i++)
+ {
+ decodeBuffer.decodeCachedValue(value, 16,
+ *(clientCache_ -> allocColorRGBCache[i]), 4);
+ PutUINT(value, nextDest, bigEndian_);
+ colorData[i] = value;
+ nextDest += 2;
+ }
+
+ sequenceQueue_.push(clientSequence_, outputOpcode,
+ colorData[0], colorData[1], colorData[2]);
+ }
+ break;
+ case X_ReparentWindow:
+ {
+ outputLength = 16;
+ outputMessage = writeBuffer_.addMessage(outputLength);
+ decodeBuffer.decodeXidValue(value, clientCache_ -> windowCache);
+ PutULONG(value, outputMessage + 4, bigEndian_);
+ decodeBuffer.decodeXidValue(value, clientCache_ -> windowCache);
+ PutULONG(value, outputMessage + 8, bigEndian_);
+ decodeBuffer.decodeValue(value, 16, 11);
+ PutUINT(value, outputMessage + 12, bigEndian_);
+ decodeBuffer.decodeValue(value, 16, 11);
+ PutUINT(value, outputMessage + 14, bigEndian_);
+ }
+ break;
+ case X_ChangeProperty:
+ {
+ MessageStore *messageStore = clientStore_ ->
+ getRequestStore(X_ChangeProperty);
+
+ if (handleDecodeCached(decodeBuffer, clientCache_, messageStore,
+ outputMessage, outputLength))
+ {
+ break;
+ }
+
+ unsigned char format;
+ decodeBuffer.decodeCachedValue(format, 8,
+ clientCache_ -> changePropertyFormatCache);
+ unsigned int dataLength;
+ decodeBuffer.decodeValue(dataLength, 32, 6);
+ outputLength = 24 + RoundUp4(dataLength * (format >> 3));
+ outputMessage = writeBuffer_.addMessage(outputLength);
+ decodeBuffer.decodeValue(value, 2);
+ outputMessage[1] = (unsigned char) value;
+ decodeBuffer.decodeXidValue(value, clientCache_ -> windowCache);
+ PutULONG(value, outputMessage + 4, bigEndian_);
+ decodeBuffer.decodeCachedValue(value, 29,
+ clientCache_ -> changePropertyPropertyCache, 9);
+ PutULONG(value, outputMessage + 8, bigEndian_);
+ decodeBuffer.decodeCachedValue(value, 29,
+ clientCache_ -> changePropertyTypeCache, 9);
+ PutULONG(value, outputMessage + 12, bigEndian_);
+ outputMessage[16] = format;
+ PutULONG(dataLength, outputMessage + 20, bigEndian_);
+ unsigned char *nextDest = outputMessage + 24;
+
+ if (format == 8)
+ {
+ // Since ProtoStep7 (#issue 108)
+ decodeBuffer.decodeTextData(nextDest, dataLength);
+ }
+ else if (format == 32)
+ {
+ for (unsigned int i = 0; i < dataLength; i++)
+ {
+ decodeBuffer.decodeCachedValue(value, 32,
+ clientCache_ -> changePropertyData32Cache);
+
+ PutULONG(value, nextDest, bigEndian_);
+
+ nextDest += 4;
+ }
+ }
+ else
+ {
+ for (unsigned int i = 0; i < dataLength; i++)
+ {
+ decodeBuffer.decodeValue(value, 16);
+
+ PutUINT(value, nextDest, bigEndian_);
+
+ nextDest += 2;
+ }
+ }
+
+ handleSave(messageStore, outputMessage, outputLength);
+ }
+ break;
+ case X_SendEvent:
+ {
+ MessageStore *messageStore = clientStore_ ->
+ getRequestStore(X_SendEvent);
+
+ if (handleDecodeCached(decodeBuffer, clientCache_, messageStore,
+ outputMessage, outputLength))
+ {
+ break;
+ }
+
+ outputLength = 44;
+ outputMessage = writeBuffer_.addMessage(outputLength);
+ decodeBuffer.decodeBoolValue(value);
+ *(outputMessage + 1) = value;
+ decodeBuffer.decodeBoolValue(value);
+ if (value)
+ {
+ decodeBuffer.decodeBoolValue(value);
+ }
+ else
+ {
+ decodeBuffer.decodeXidValue(value, clientCache_ -> windowCache);
+ }
+ PutULONG(value, outputMessage + 4, bigEndian_);
+ decodeBuffer.decodeCachedValue(value, 32,
+ clientCache_ -> sendEventMaskCache, 9);
+ PutULONG(value, outputMessage + 8, bigEndian_);
+ decodeBuffer.decodeCachedValue(*(outputMessage + 12), 8,
+ clientCache_ -> sendEventCodeCache);
+ decodeBuffer.decodeCachedValue(*(outputMessage + 13), 8,
+ clientCache_ -> sendEventByteDataCache);
+ decodeBuffer.decodeValue(value, 16, 4);
+ clientCache_ -> sendEventLastSequence += value;
+ clientCache_ -> sendEventLastSequence &= 0xffff;
+ PutUINT(clientCache_ -> sendEventLastSequence, outputMessage + 14, bigEndian_);
+ decodeBuffer.decodeCachedValue(value, 32,
+ clientCache_ -> sendEventIntDataCache);
+ PutULONG(value, outputMessage + 16, bigEndian_);
+
+ for (unsigned int i = 20; i < 44; i++)
+ {
+ decodeBuffer.decodeCachedValue(cValue, 8,
+ clientCache_ -> sendEventEventCache);
+ *(outputMessage + i) = cValue;
+ }
+
+ handleSave(messageStore, outputMessage, outputLength);
+ }
+ break;
+ case X_ChangeWindowAttributes:
+ {
+ unsigned int numAttrs;
+ decodeBuffer.decodeValue(numAttrs, 4);
+ outputLength = 12 + (numAttrs << 2);
+ outputMessage = writeBuffer_.addMessage(outputLength);
+ decodeBuffer.decodeXidValue(value, clientCache_ -> windowCache);
+ PutULONG(value, outputMessage + 4, bigEndian_);
+ unsigned int bitmask;
+ decodeBuffer.decodeCachedValue(bitmask, 15,
+ clientCache_ -> createWindowBitmaskCache);
+ PutULONG(bitmask, outputMessage + 8, bigEndian_);
+ unsigned char *nextDest = outputMessage + 12;
+ unsigned int mask = 0x1;
+ for (unsigned int i = 0; i < 15; i++)
+ {
+ if (bitmask & mask)
+ {
+ decodeBuffer.decodeCachedValue(value, 32,
+ *clientCache_ -> createWindowAttrCache[i]);
+ PutULONG(value, nextDest, bigEndian_);
+ nextDest += 4;
+ }
+ mask <<= 1;
+ }
+ }
+ break;
+ case X_ClearArea:
+ {
+ MessageStore *messageStore = clientStore_ ->
+ getRequestStore(X_ClearArea);
+
+ if (handleDecodeCached(decodeBuffer, clientCache_, messageStore,
+ outputMessage, outputLength))
+ {
+ break;
+ }
+
+ outputLength = 16;
+ outputMessage = writeBuffer_.addMessage(outputLength);
+ decodeBuffer.decodeBoolValue(value);
+ outputMessage[1] = (unsigned char) value;
+ decodeBuffer.decodeXidValue(value, clientCache_ -> windowCache);
+ PutULONG(value, outputMessage + 4, bigEndian_);
+ unsigned char *nextDest = outputMessage + 8;
+ for (unsigned int i = 0; i < 4; i++)
+ {
+ decodeBuffer.decodeCachedValue(value, 16,
+ *clientCache_ -> clearAreaGeomCache[i], 8);
+ PutUINT(value, nextDest, bigEndian_);
+ nextDest += 2;
+ }
+
+ handleSave(messageStore, outputMessage, outputLength);
+ }
+ break;
+ case X_CloseFont:
+ {
+ outputLength = 8;
+ outputMessage = writeBuffer_.addMessage(outputLength);
+ decodeBuffer.decodeValue(value, 29, 5);
+ clientCache_ -> lastFont += value;
+ clientCache_ -> lastFont &= 0x1fffffff;
+ PutULONG(clientCache_ -> lastFont, outputMessage + 4, bigEndian_);
+ }
+ break;
+ case X_ConfigureWindow:
+ {
+ MessageStore *messageStore = clientStore_ ->
+ getRequestStore(X_ConfigureWindow);
+
+ if (handleDecodeCached(decodeBuffer, clientCache_, messageStore,
+ outputMessage, outputLength))
+ {
+ break;
+ }
+
+ outputLength = 12;
+ outputMessage = writeBuffer_.addMessage(outputLength);
+ writeBuffer_.registerPointer(&outputMessage);
+ decodeBuffer.decodeXidValue(value, clientCache_ -> windowCache);
+ PutULONG(value, outputMessage + 4, bigEndian_);
+ unsigned int bitmask;
+ decodeBuffer.decodeCachedValue(bitmask, 7,
+ clientCache_ -> configureWindowBitmaskCache);
+ PutUINT(bitmask, outputMessage + 8, bigEndian_);
+ unsigned int mask = 0x1;
+ for (unsigned int i = 0; i < 7; i++)
+ {
+ if (bitmask & mask)
+ {
+ unsigned char* nextDest = writeBuffer_.addMessage(4);
+ outputLength += 4;
+ decodeBuffer.decodeCachedValue(value, CONFIGUREWINDOW_FIELD_WIDTH[i],
+ *clientCache_ -> configureWindowAttrCache[i], 8);
+ PutULONG(value, nextDest, bigEndian_);
+ nextDest += 4;
+ }
+ mask <<= 1;
+ }
+ writeBuffer_.unregisterPointer();
+
+ handleSave(messageStore, outputMessage, outputLength);
+ }
+ break;
+ case X_ConvertSelection:
+ {
+ outputLength = 24;
+ outputMessage = writeBuffer_.addMessage(outputLength);
+ decodeBuffer.decodeCachedValue(value, 29,
+ clientCache_ -> convertSelectionRequestorCache, 9);
+ PutULONG(value, outputMessage + 4, bigEndian_);
+ unsigned char* nextDest = outputMessage + 8;
+ for (unsigned int i = 0; i < 3; i++)
+ {
+ decodeBuffer.decodeCachedValue(value, 29,
+ *(clientCache_ -> convertSelectionAtomCache[i]), 9);
+ PutULONG(value, nextDest, bigEndian_);
+ nextDest += 4;
+ }
+ decodeBuffer.decodeValue(value, 32, 4);
+ clientCache_ -> convertSelectionLastTimestamp += value;
+ PutULONG(clientCache_ -> convertSelectionLastTimestamp,
+ nextDest, bigEndian_);
+ }
+ break;
+ case X_CopyArea:
+ {
+ MessageStore *messageStore = clientStore_ ->
+ getRequestStore(X_CopyArea);
+
+ if (handleDecodeCached(decodeBuffer, clientCache_, messageStore,
+ outputMessage, outputLength))
+ {
+ break;
+ }
+
+ outputLength = 28;
+ outputMessage = writeBuffer_.addMessage(outputLength);
+ decodeBuffer.decodeXidValue(value, clientCache_ -> drawableCache);
+ PutULONG(value, outputMessage + 4, bigEndian_);
+ decodeBuffer.decodeXidValue(value, clientCache_ -> drawableCache);
+ PutULONG(value, outputMessage + 8, bigEndian_);
+ decodeBuffer.decodeXidValue(value, clientCache_ -> gcCache);
+ PutULONG(value, outputMessage + 12, bigEndian_);
+ unsigned char *nextDest = outputMessage + 16;
+ for (unsigned int i = 0; i < 6; i++)
+ {
+ decodeBuffer.decodeCachedValue(value, 16,
+ *clientCache_ -> copyAreaGeomCache[i], 8);
+ PutUINT(value, nextDest, bigEndian_);
+ nextDest += 2;
+ }
+
+ handleSave(messageStore, outputMessage, outputLength);
+ }
+ break;
+ case X_CopyGC:
+ {
+ outputLength = 16;
+ outputMessage = writeBuffer_.addMessage(outputLength);
+ decodeBuffer.decodeXidValue(value, clientCache_ -> gcCache);
+ PutULONG(value, outputMessage + 4, bigEndian_);
+ decodeBuffer.decodeXidValue(value, clientCache_ -> gcCache);
+ PutULONG(value, outputMessage + 8, bigEndian_);
+ decodeBuffer.decodeCachedValue(value, 23,
+ clientCache_ -> createGCBitmaskCache);
+ PutULONG(value, outputMessage + 12, bigEndian_);
+ }
+ break;
+ case X_CopyPlane:
+ {
+ outputLength = 32;
+ outputMessage = writeBuffer_.addMessage(outputLength);
+ decodeBuffer.decodeXidValue(value, clientCache_ -> drawableCache);
+ PutULONG(value, outputMessage + 4, bigEndian_);
+ decodeBuffer.decodeXidValue(value, clientCache_ -> drawableCache);
+ PutULONG(value, outputMessage + 8, bigEndian_);
+ decodeBuffer.decodeXidValue(value, clientCache_ -> gcCache);
+ PutULONG(value, outputMessage + 12, bigEndian_);
+ unsigned char *nextDest = outputMessage + 16;
+ for (unsigned int i = 0; i < 6; i++)
+ {
+ decodeBuffer.decodeCachedValue(value, 16,
+ *clientCache_ -> copyPlaneGeomCache[i], 8);
+ PutUINT(value, nextDest, bigEndian_);
+ nextDest += 2;
+ }
+ decodeBuffer.decodeCachedValue(value, 32,
+ clientCache_ -> copyPlaneBitPlaneCache, 10);
+ PutULONG(value, outputMessage + 28, bigEndian_);
+ }
+ break;
+ case X_CreateGC:
+ {
+ MessageStore *messageStore = clientStore_ ->
+ getRequestStore(X_CreateGC);
+
+ if (handleDecodeCached(decodeBuffer, clientCache_, messageStore,
+ outputMessage, outputLength))
+ {
+ break;
+ }
+
+ outputLength = 16;
+ outputMessage = writeBuffer_.addMessage(outputLength);
+ writeBuffer_.registerPointer(&outputMessage);
+
+ // Since ProtoStep7 (#issue 108)
+ decodeBuffer.decodeNewXidValue(value, clientCache_ -> lastId,
+ clientCache_ -> lastIdCache, clientCache_ -> gcCache,
+ clientCache_ -> freeGCCache);
+
+ PutULONG(value, outputMessage + 4, bigEndian_);
+ unsigned int offset = 8;
+ decodeBuffer.decodeXidValue(value, clientCache_ -> drawableCache);
+ PutULONG(value, outputMessage + offset, bigEndian_);
+ offset += 4;
+ unsigned int bitmask;
+ decodeBuffer.decodeCachedValue(bitmask, 23,
+ clientCache_ -> createGCBitmaskCache);
+ PutULONG(bitmask, outputMessage + offset, bigEndian_);
+ unsigned int mask = 0x1;
+ for (unsigned int i = 0; i < 23; i++)
+ {
+ if (bitmask & mask)
+ {
+ unsigned char* nextDest = writeBuffer_.addMessage(4);
+ outputLength += 4;
+ unsigned int fieldWidth = CREATEGC_FIELD_WIDTH[i];
+ if (fieldWidth <= 4)
+ decodeBuffer.decodeValue(value, fieldWidth);
+ else
+ decodeBuffer.decodeCachedValue(value, fieldWidth,
+ *clientCache_ -> createGCAttrCache[i]);
+ PutULONG(value, nextDest, bigEndian_);
+ }
+ mask <<= 1;
+ }
+ writeBuffer_.unregisterPointer();
+
+ handleSave(messageStore, outputMessage, outputLength);
+ }
+ break;
+ case X_ChangeGC:
+ {
+ MessageStore *messageStore = clientStore_ ->
+ getRequestStore(X_ChangeGC);
+
+ if (handleDecodeCached(decodeBuffer, clientCache_, messageStore,
+ outputMessage, outputLength))
+ {
+ break;
+ }
+
+ outputLength = 12;
+ outputMessage = writeBuffer_.addMessage(outputLength);
+ writeBuffer_.registerPointer(&outputMessage);
+ decodeBuffer.decodeXidValue(value, clientCache_ -> gcCache);
+ PutULONG(value, outputMessage + 4, bigEndian_);
+ unsigned int offset = 8;
+ unsigned int bitmask;
+ decodeBuffer.decodeCachedValue(bitmask, 23,
+ clientCache_ -> createGCBitmaskCache);
+ PutULONG(bitmask, outputMessage + offset, bigEndian_);
+ unsigned int mask = 0x1;
+ for (unsigned int i = 0; i < 23; i++)
+ {
+ if (bitmask & mask)
+ {
+ unsigned char* nextDest = writeBuffer_.addMessage(4);
+ outputLength += 4;
+ unsigned int fieldWidth = CREATEGC_FIELD_WIDTH[i];
+ if (fieldWidth <= 4)
+ decodeBuffer.decodeValue(value, fieldWidth);
+ else
+ decodeBuffer.decodeCachedValue(value, fieldWidth,
+ *clientCache_ -> createGCAttrCache[i]);
+ PutULONG(value, nextDest, bigEndian_);
+ }
+ mask <<= 1;
+ }
+ writeBuffer_.unregisterPointer();
+
+ handleSave(messageStore, outputMessage, outputLength);
+ }
+ break;
+ case X_CreatePixmap:
+ {
+ MessageStore *messageStore = clientStore_ ->
+ getRequestStore(X_CreatePixmap);
+
+ hit = handleDecode(decodeBuffer, clientCache_, messageStore,
+ outputOpcode, outputMessage, outputLength);
+ }
+ break;
+ case X_CreateWindow:
+ {
+ outputLength = 32;
+ outputMessage = writeBuffer_.addMessage(outputLength);
+ writeBuffer_.registerPointer(&outputMessage);
+ decodeBuffer.decodeCachedValue(cValue, 8, clientCache_ -> depthCache);
+ outputMessage[1] = cValue;
+ decodeBuffer.decodeXidValue(value, clientCache_ -> windowCache);
+ PutULONG(value, outputMessage + 8, bigEndian_);
+
+ // Since ProtoStep7 (#issue 108)
+ decodeBuffer.decodeNewXidValue(value, clientCache_ -> lastId,
+ clientCache_ -> lastIdCache, clientCache_ -> windowCache,
+ clientCache_ -> freeWindowCache);
+
+ PutULONG(value, outputMessage + 4, bigEndian_);
+ unsigned char *nextDest = outputMessage + 12;
+ unsigned int i;
+ for (i = 0; i < 6; i++)
+ {
+ decodeBuffer.decodeCachedValue(value, 16,
+ *clientCache_ -> createWindowGeomCache[i], 8);
+ PutUINT(value, nextDest, bigEndian_);
+ nextDest += 2;
+ }
+ decodeBuffer.decodeCachedValue(value, 29, clientCache_ -> visualCache);
+ PutULONG(value, outputMessage + 24, bigEndian_);
+ unsigned int bitmask;
+ decodeBuffer.decodeCachedValue(bitmask, 15,
+ clientCache_ -> createWindowBitmaskCache);
+ PutULONG(bitmask, outputMessage + 28, bigEndian_);
+ unsigned int mask = 0x1;
+ for (i = 0; i < 15; i++)
+ {
+ if (bitmask & mask)
+ {
+ nextDest = writeBuffer_.addMessage(4);
+ outputLength += 4;
+ decodeBuffer.decodeCachedValue(value, 32,
+ *clientCache_ -> createWindowAttrCache[i]);
+ PutULONG(value, nextDest, bigEndian_);
+ }
+ mask <<= 1;
+ }
+ writeBuffer_.unregisterPointer();
+ }
+ break;
+ case X_DeleteProperty:
+ {
+ outputLength = 12;
+ outputMessage = writeBuffer_.addMessage(outputLength);
+ decodeBuffer.decodeXidValue(value, clientCache_ -> windowCache);
+ PutULONG(value, outputMessage + 4, bigEndian_);
+ decodeBuffer.decodeValue(value, 29, 9);
+ PutULONG(value, outputMessage + 8, bigEndian_);
+ }
+ break;
+ case X_FillPoly:
+ {
+ MessageStore *messageStore = clientStore_ ->
+ getRequestStore(X_FillPoly);
+
+ if (handleDecodeCached(decodeBuffer, clientCache_, messageStore,
+ outputMessage, outputLength))
+ {
+ break;
+ }
+
+ unsigned int numPoints;
+
+ // Since ProtoStep10 (#issue 108)
+ decodeBuffer.decodeCachedValue(numPoints, 16,
+ clientCache_ -> fillPolyNumPointsCache, 4);
+
+ outputLength = 16 + (numPoints << 2);
+ outputMessage = writeBuffer_.addMessage(outputLength);
+ decodeBuffer.decodeXidValue(value, clientCache_ -> drawableCache);
+ PutULONG(value, outputMessage + 4, bigEndian_);
+ decodeBuffer.decodeXidValue(value, clientCache_ -> gcCache);
+ PutULONG(value, outputMessage + 8, bigEndian_);
+ decodeBuffer.decodeValue(value, 2);
+ outputMessage[12] = (unsigned char) value;
+ unsigned int relativeCoordMode;
+ decodeBuffer.decodeBoolValue(relativeCoordMode);
+ outputMessage[13] = (unsigned char) relativeCoordMode;
+ unsigned char *nextDest = outputMessage + 16;
+ unsigned int pointIndex = 0;
+ for (unsigned int i = 0; i < numPoints; i++)
+ {
+ if (relativeCoordMode)
+ {
+ decodeBuffer.decodeCachedValue(value, 16,
+ *clientCache_ -> fillPolyXRelCache[pointIndex], 8);
+ PutUINT(value, nextDest, bigEndian_);
+ nextDest += 2;
+ decodeBuffer.decodeCachedValue(value, 16,
+ *clientCache_ -> fillPolyYRelCache[pointIndex], 8);
+ PutUINT(value, nextDest, bigEndian_);
+ nextDest += 2;
+ }
+ else
+ {
+ unsigned int x, y;
+ decodeBuffer.decodeBoolValue(value);
+ if (value)
+ {
+ decodeBuffer.decodeValue(value, 3);
+ x = clientCache_ -> fillPolyRecentX[value];
+ y = clientCache_ -> fillPolyRecentY[value];
+ }
+ else
+ {
+ decodeBuffer.decodeCachedValue(x, 16,
+ *clientCache_ -> fillPolyXAbsCache[pointIndex], 8);
+ decodeBuffer.decodeCachedValue(y, 16,
+ *clientCache_ -> fillPolyYAbsCache[pointIndex], 8);
+ clientCache_ -> fillPolyRecentX[clientCache_ -> fillPolyIndex] = x;
+ clientCache_ -> fillPolyRecentY[clientCache_ -> fillPolyIndex] = y;
+ clientCache_ -> fillPolyIndex++;
+ if (clientCache_ -> fillPolyIndex == 8)
+ clientCache_ -> fillPolyIndex = 0;
+ }
+ PutUINT(x, nextDest, bigEndian_);
+ nextDest += 2;
+ PutUINT(y, nextDest, bigEndian_);
+ nextDest += 2;
+ }
+
+ if (++pointIndex == 10) pointIndex = 0;
+ }
+
+ handleSave(messageStore, outputMessage, outputLength);
+ }
+ break;
+ case X_FreeColors:
+ {
+ unsigned int numPixels;
+ decodeBuffer.decodeValue(numPixels, 16, 4);
+ outputLength = 12 + (numPixels << 2);
+ outputMessage = writeBuffer_.addMessage(outputLength);
+ decodeBuffer.decodeCachedValue(value, 29,
+ clientCache_ -> colormapCache);
+ PutULONG(value, outputMessage + 4, bigEndian_);
+ decodeBuffer.decodeValue(value, 32, 4);
+ PutULONG(value, outputMessage + 8, bigEndian_);
+ unsigned char* nextDest = outputMessage + 12;
+ while (numPixels)
+ {
+ decodeBuffer.decodeValue(value, 32, 8);
+ PutULONG(value, nextDest, bigEndian_);
+ nextDest += 4;
+ numPixels--;
+ }
+ }
+ break;
+ case X_FreeCursor:
+ {
+ outputLength = 8;
+ outputMessage = writeBuffer_.addMessage(outputLength);
+ decodeBuffer.decodeCachedValue(value, 29, clientCache_ -> cursorCache, 9);
+ PutULONG(value, outputMessage + 4, bigEndian_);
+ }
+ break;
+ case X_FreeGC:
+ {
+ outputLength = 8;
+ outputMessage = writeBuffer_.addMessage(outputLength);
+
+ // Since ProtoStep7 (#issue 108)
+ decodeBuffer.decodeFreeXidValue(value, clientCache_ -> freeGCCache);
+
+ PutULONG(value, outputMessage + 4, bigEndian_);
+ }
+ break;
+ case X_FreePixmap:
+ {
+ outputLength = 8;
+ outputMessage = writeBuffer_.addMessage(outputLength);
+
+ // Since ProtoStep7 (#issue 108)
+ decodeBuffer.decodeFreeXidValue(value, clientCache_ -> freeDrawableCache);
+
+ PutULONG(value, outputMessage + 4, bigEndian_);
+ }
+ break;
+ case X_GetAtomName:
+ {
+ outputLength = 8;
+ outputMessage = writeBuffer_.addMessage(outputLength);
+ decodeBuffer.decodeValue(value, 29, 9);
+ PutULONG(value, outputMessage + 4, bigEndian_);
+
+ sequenceQueue_.push(clientSequence_, outputOpcode);
+ }
+ break;
+ case X_GetGeometry:
+ {
+ outputLength = 8;
+ outputMessage = writeBuffer_.addMessage(outputLength);
+ decodeBuffer.decodeXidValue(value, clientCache_ -> drawableCache);
+ PutULONG(value, outputMessage + 4, bigEndian_);
+
+ sequenceQueue_.push(clientSequence_, outputOpcode);
+ }
+ break;
+ case X_GetInputFocus:
+ {
+ outputLength = 4;
+ outputMessage = writeBuffer_.addMessage(outputLength);
+
+ sequenceQueue_.push(clientSequence_, outputOpcode, outputOpcode);
+ }
+ break;
+ case X_GetModifierMapping:
+ {
+ outputLength = 4;
+ outputMessage = writeBuffer_.addMessage(outputLength);
+
+ sequenceQueue_.push(clientSequence_, outputOpcode);
+ }
+ break;
+ case X_GetKeyboardMapping:
+ {
+ outputLength = 8;
+ outputMessage = writeBuffer_.addMessage(outputLength);
+ decodeBuffer.decodeValue(value, 8);
+ outputMessage[4] = value;
+ decodeBuffer.decodeValue(value, 8);
+ outputMessage[5] = value;
+
+ sequenceQueue_.push(clientSequence_, outputOpcode);
+ }
+ break;
+ case X_GetProperty:
+ {
+ MessageStore *messageStore = clientStore_ ->
+ getRequestStore(X_GetProperty);
+
+ if (handleDecodeCached(decodeBuffer, clientCache_, messageStore,
+ outputMessage, outputLength))
+ {
+ //
+ // Save a reference to identify the reply.
+ //
+
+ unsigned int property = GetULONG(outputMessage + 8, bigEndian_);
+
+ sequenceQueue_.push(clientSequence_, outputOpcode, property);
+
+ break;
+ }
+
+ outputLength = 24;
+ outputMessage = writeBuffer_.addMessage(outputLength);
+ decodeBuffer.decodeBoolValue(value);
+ outputMessage[1] = (unsigned char) value;
+ decodeBuffer.decodeXidValue(value, clientCache_ -> windowCache);
+ PutULONG(value, outputMessage + 4, bigEndian_);
+ unsigned int property;
+ decodeBuffer.decodeValue(property, 29, 9);
+ PutULONG(property, outputMessage + 8, bigEndian_);
+ decodeBuffer.decodeValue(value, 29, 9);
+ PutULONG(value, outputMessage + 12, bigEndian_);
+ decodeBuffer.decodeValue(value, 32, 2);
+ PutULONG(value, outputMessage + 16, bigEndian_);
+ decodeBuffer.decodeValue(value, 32, 8);
+ PutULONG(value, outputMessage + 20, bigEndian_);
+
+ sequenceQueue_.push(clientSequence_, outputOpcode, property);
+
+ handleSave(messageStore, outputMessage, outputLength);
+ }
+ break;
+ case X_GetSelectionOwner:
+ {
+ outputLength = 8;
+ outputMessage = writeBuffer_.addMessage(outputLength);
+ decodeBuffer.decodeCachedValue(value, 29,
+ clientCache_ -> getSelectionOwnerSelectionCache, 9);
+ PutULONG(value, outputMessage + 4, bigEndian_);
+
+ sequenceQueue_.push(clientSequence_, outputOpcode);
+ }
+ break;
+ case X_GrabButton:
+ case X_GrabPointer:
+ {
+ outputLength = 24;
+ outputMessage = writeBuffer_.addMessage(outputLength);
+ decodeBuffer.decodeBoolValue(value);
+ outputMessage[1] = (unsigned char) value;
+ decodeBuffer.decodeXidValue(value, clientCache_ -> windowCache);
+ PutULONG(value, outputMessage + 4, bigEndian_);
+ decodeBuffer.decodeCachedValue(value, 16,
+ clientCache_ -> grabButtonEventMaskCache);
+ PutUINT(value, outputMessage + 8, bigEndian_);
+ decodeBuffer.decodeBoolValue(value);
+ outputMessage[10] = (unsigned char) value;
+ decodeBuffer.decodeBoolValue(value);
+ outputMessage[11] = (unsigned char) value;
+ decodeBuffer.decodeCachedValue(value, 29,
+ clientCache_ -> grabButtonConfineCache, 9);
+ PutULONG(value, outputMessage + 12, bigEndian_);
+ decodeBuffer.decodeCachedValue(value, 29,
+ clientCache_ -> cursorCache, 9);
+ PutULONG(value, outputMessage + 16, bigEndian_);
+ if (outputOpcode == X_GrabButton)
+ {
+ decodeBuffer.decodeCachedValue(cValue, 8,
+ clientCache_ -> grabButtonButtonCache);
+ outputMessage[20] = cValue;
+ decodeBuffer.decodeCachedValue(value, 16,
+ clientCache_ -> grabButtonModifierCache);
+ PutUINT(value, outputMessage + 22, bigEndian_);
+ }
+ else
+ {
+ decodeBuffer.decodeValue(value, 32, 4);
+ clientCache_ -> grabKeyboardLastTimestamp += value;
+ PutULONG(clientCache_ -> grabKeyboardLastTimestamp,
+ outputMessage + 20, bigEndian_);
+
+ sequenceQueue_.push(clientSequence_, outputOpcode);
+ }
+ }
+ break;
+ case X_GrabKeyboard:
+ {
+ outputLength = 16;
+ outputMessage = writeBuffer_.addMessage(outputLength);
+ decodeBuffer.decodeBoolValue(value);
+ outputMessage[1] = (unsigned char) value;
+ decodeBuffer.decodeXidValue(value, clientCache_ -> windowCache);
+ PutULONG(value, outputMessage + 4, bigEndian_);
+ decodeBuffer.decodeValue(value, 32, 4);
+ clientCache_ -> grabKeyboardLastTimestamp += value;
+ PutULONG(clientCache_ -> grabKeyboardLastTimestamp, outputMessage + 8,
+ bigEndian_);
+ decodeBuffer.decodeBoolValue(value);
+ outputMessage[12] = (unsigned char) value;
+ decodeBuffer.decodeBoolValue(value);
+ outputMessage[13] = (unsigned char) value;
+
+ sequenceQueue_.push(clientSequence_, outputOpcode);
+ }
+ break;
+ case X_GrabServer:
+ case X_UngrabServer:
+ case X_NoOperation:
+ {
+ #ifdef DEBUG
+ *logofs << "handleWrite: Managing (probably tainted) X_NoOperation request for FD#"
+ << fd_ << ".\n" << logofs_flush;
+ #endif
+
+ outputLength = 4;
+ outputMessage = writeBuffer_.addMessage(outputLength);
+ }
+ break;
+ case X_PolyText8:
+ {
+ MessageStore *messageStore = clientStore_ ->
+ getRequestStore(X_PolyText8);
+
+ if (handleDecodeCached(decodeBuffer, clientCache_, messageStore,
+ outputMessage, outputLength))
+ {
+ break;
+ }
+
+ outputLength = 16;
+ outputMessage = writeBuffer_.addMessage(outputLength);
+ decodeBuffer.decodeXidValue(value, clientCache_ -> drawableCache);
+ PutULONG(value, outputMessage + 4, bigEndian_);
+ decodeBuffer.decodeXidValue(value, clientCache_ -> gcCache);
+ PutULONG(value, outputMessage + 8, bigEndian_);
+ decodeBuffer.decodeCachedValue(value, 16,
+ clientCache_ -> polyTextCacheX);
+ clientCache_ -> polyTextLastX += value;
+ clientCache_ -> polyTextLastX &= 0xffff;
+ PutUINT(clientCache_ -> polyTextLastX, outputMessage + 12, bigEndian_);
+ decodeBuffer.decodeCachedValue(value, 16,
+ clientCache_ -> polyTextCacheY);
+ clientCache_ -> polyTextLastY += value;
+ clientCache_ -> polyTextLastY &= 0xffff;
+ PutUINT(clientCache_ -> polyTextLastY, outputMessage + 14, bigEndian_);
+ unsigned int addedLength = 0;
+ writeBuffer_.registerPointer(&outputMessage);
+ for (;;)
+ {
+ decodeBuffer.decodeBoolValue(value);
+ if (!value)
+ break;
+ unsigned int textLength;
+ decodeBuffer.decodeValue(textLength, 8);
+ if (textLength == 255)
+ {
+ addedLength += 5;
+ unsigned char *nextSegment = writeBuffer_.addMessage(5);
+ *nextSegment = (unsigned char) textLength;
+ decodeBuffer.decodeCachedValue(value, 29,
+ clientCache_ -> polyTextFontCache);
+ PutULONG(value, nextSegment + 1, 1);
+ }
+ else
+ {
+ addedLength += (textLength + 2);
+ unsigned char *nextSegment =
+ writeBuffer_.addMessage(textLength + 2);
+ *nextSegment = (unsigned char) textLength;
+ unsigned char *nextDest = nextSegment + 1;
+ decodeBuffer.decodeCachedValue(cValue, 8,
+ clientCache_ -> polyTextDeltaCache);
+ *nextDest++ = cValue;
+
+ // Since ProtoStep7 (#issue 108)
+ decodeBuffer.decodeTextData(nextDest, textLength);
+
+ nextDest += textLength;
+ }
+ }
+ outputLength += addedLength;
+ unsigned int mod4 = (addedLength & 0x3);
+ if (mod4)
+ {
+ unsigned int extra = 4 - mod4;
+ unsigned char *nextDest = writeBuffer_.addMessage(extra);
+ for (unsigned int i = 0; i < extra; i++)
+ *nextDest++ = 0;
+ outputLength += extra;
+ }
+ writeBuffer_.unregisterPointer();
+
+ handleSave(messageStore, outputMessage, outputLength);
+ }
+ break;
+ case X_PolyText16:
+ {
+ MessageStore *messageStore = clientStore_ ->
+ getRequestStore(X_PolyText16);
+
+ if (handleDecodeCached(decodeBuffer, clientCache_, messageStore,
+ outputMessage, outputLength))
+ {
+ break;
+ }
+
+ outputLength = 16;
+ outputMessage = writeBuffer_.addMessage(outputLength);
+ decodeBuffer.decodeXidValue(value, clientCache_ -> drawableCache);
+ PutULONG(value, outputMessage + 4, bigEndian_);
+ decodeBuffer.decodeXidValue(value, clientCache_ -> gcCache);
+ PutULONG(value, outputMessage + 8, bigEndian_);
+ decodeBuffer.decodeCachedValue(value, 16,
+ clientCache_ -> polyTextCacheX);
+ clientCache_ -> polyTextLastX += value;
+ clientCache_ -> polyTextLastX &= 0xffff;
+ PutUINT(clientCache_ -> polyTextLastX, outputMessage + 12, bigEndian_);
+ decodeBuffer.decodeCachedValue(value, 16,
+ clientCache_ -> polyTextCacheY);
+ clientCache_ -> polyTextLastY += value;
+ clientCache_ -> polyTextLastY &= 0xffff;
+ PutUINT(clientCache_ -> polyTextLastY, outputMessage + 14, bigEndian_);
+ unsigned int addedLength = 0;
+ writeBuffer_.registerPointer(&outputMessage);
+ for (;;)
+ {
+ decodeBuffer.decodeBoolValue(value);
+ if (!value)
+ break;
+ unsigned int textLength;
+ decodeBuffer.decodeValue(textLength, 8);
+ if (textLength == 255)
+ {
+ addedLength += 5;
+ unsigned char *nextSegment = writeBuffer_.addMessage(5);
+ *nextSegment = (unsigned char) textLength;
+ decodeBuffer.decodeCachedValue(value, 29, clientCache_ -> polyTextFontCache);
+ PutULONG(value, nextSegment + 1, 1);
+ }
+ else
+ {
+ addedLength += (textLength * 2 + 2);
+ unsigned char *nextSegment =
+ writeBuffer_.addMessage(textLength * 2 + 2);
+ *nextSegment = (unsigned char) textLength;
+ unsigned char *nextDest = nextSegment + 1;
+ decodeBuffer.decodeCachedValue(cValue, 8, clientCache_ -> polyTextDeltaCache);
+ *nextDest++ = cValue;
+
+ // Since ProtoStep7 (#issue 108)
+ decodeBuffer.decodeTextData(nextDest, textLength * 2);
+
+ nextDest += textLength * 2;
+ }
+ }
+ outputLength += addedLength;
+
+ unsigned int mod4 = (addedLength & 0x3);
+ if (mod4)
+ {
+ unsigned int extra = 4 - mod4;
+ unsigned char *nextDest = writeBuffer_.addMessage(extra);
+ for (unsigned int i = 0; i < extra; i++)
+ *nextDest++ = 0;
+ outputLength += extra;
+ }
+ writeBuffer_.unregisterPointer();
+
+ handleSave(messageStore, outputMessage, outputLength);
+ }
+ break;
+ case X_ImageText8:
+ {
+ MessageStore *messageStore = clientStore_ ->
+ getRequestStore(X_ImageText8);
+
+ if (handleDecodeCached(decodeBuffer, clientCache_, messageStore,
+ outputMessage, outputLength))
+ {
+ break;
+ }
+
+ unsigned int textLength;
+ decodeBuffer.decodeCachedValue(textLength, 8,
+ clientCache_ -> imageTextLengthCache, 4);
+ outputLength = 16 + RoundUp4(textLength);
+ outputMessage = writeBuffer_.addMessage(outputLength);
+ outputMessage[1] = (unsigned char) textLength;
+ decodeBuffer.decodeXidValue(value, clientCache_ -> drawableCache);
+ PutULONG(value, outputMessage + 4, bigEndian_);
+ decodeBuffer.decodeXidValue(value, clientCache_ -> gcCache);
+ PutULONG(value, outputMessage + 8, bigEndian_);
+ decodeBuffer.decodeCachedValue(value, 16,
+ clientCache_ -> imageTextCacheX);
+ clientCache_ -> imageTextLastX += value;
+ clientCache_ -> imageTextLastX &= 0xffff;
+ PutUINT(clientCache_ -> imageTextLastX, outputMessage + 12, bigEndian_);
+ decodeBuffer.decodeCachedValue(value, 16,
+ clientCache_ -> imageTextCacheY);
+ clientCache_ -> imageTextLastY += value;
+ clientCache_ -> imageTextLastY &= 0xffff;
+ PutUINT(clientCache_ -> imageTextLastY, outputMessage + 14, bigEndian_);
+ unsigned char *nextDest = outputMessage + 16;
+
+ // Since ProtoStep7 (#issue 108)
+ decodeBuffer.decodeTextData(nextDest, textLength);
+
+ handleSave(messageStore, outputMessage, outputLength);
+ }
+ break;
+ case X_ImageText16:
+ {
+ MessageStore *messageStore = clientStore_ ->
+ getRequestStore(X_ImageText16);
+
+ if (handleDecodeCached(decodeBuffer, clientCache_, messageStore,
+ outputMessage, outputLength))
+ {
+ break;
+ }
+
+ unsigned int textLength;
+ decodeBuffer.decodeCachedValue(textLength, 8,
+ clientCache_ -> imageTextLengthCache, 4);
+ outputLength = 16 + RoundUp4(textLength * 2);
+ outputMessage = writeBuffer_.addMessage(outputLength);
+ outputMessage[1] = (unsigned char) textLength;
+ decodeBuffer.decodeXidValue(value, clientCache_ -> drawableCache);
+ PutULONG(value, outputMessage + 4, bigEndian_);
+ decodeBuffer.decodeXidValue(value, clientCache_ -> gcCache);
+ PutULONG(value, outputMessage + 8, bigEndian_);
+ decodeBuffer.decodeCachedValue(value, 16,
+ clientCache_ -> imageTextCacheX);
+ clientCache_ -> imageTextLastX += value;
+ clientCache_ -> imageTextLastX &= 0xffff;
+ PutUINT(clientCache_ -> imageTextLastX, outputMessage + 12, bigEndian_);
+ decodeBuffer.decodeCachedValue(value, 16,
+ clientCache_ -> imageTextCacheY);
+ clientCache_ -> imageTextLastY += value;
+ clientCache_ -> imageTextLastY &= 0xffff;
+ PutUINT(clientCache_ -> imageTextLastY, outputMessage + 14, bigEndian_);
+ unsigned char *nextDest = outputMessage + 16;
+
+ // Since ProtoStep7 (#issue 108)
+ decodeBuffer.decodeTextData(nextDest, textLength * 2);
+
+ handleSave(messageStore, outputMessage, outputLength);
+ }
+ break;
+ case X_InternAtom:
+ {
+ MessageStore *messageStore = clientStore_ ->
+ getRequestStore(X_InternAtom);
+
+ if (handleDecodeCached(decodeBuffer, clientCache_, messageStore,
+ outputMessage, outputLength))
+ {
+ sequenceQueue_.push(clientSequence_, outputOpcode);
+
+ break;
+ }
+
+ unsigned int nameLength;
+ decodeBuffer.decodeValue(nameLength, 16, 6);
+ outputLength = RoundUp4(nameLength) + 8;
+ outputMessage = writeBuffer_.addMessage(outputLength);
+ PutUINT(nameLength, outputMessage + 4, bigEndian_);
+ decodeBuffer.decodeBoolValue(value);
+ outputMessage[1] = (unsigned char) value;
+ unsigned char *nextDest = outputMessage + 8;
+
+ // Since ProtoStep7 (#issue 108)
+ decodeBuffer.decodeTextData(nextDest, nameLength);
+
+ sequenceQueue_.push(clientSequence_, outputOpcode);
+
+ handleSave(messageStore, outputMessage, outputLength);
+ }
+ break;
+ case X_ListExtensions:
+ {
+ outputLength = 4;
+ outputMessage = writeBuffer_.addMessage(outputLength);
+
+ sequenceQueue_.push(clientSequence_, outputOpcode);
+ }
+ break;
+ case X_ListFonts:
+ {
+ unsigned int textLength;
+ decodeBuffer.decodeValue(textLength, 16, 6);
+ outputLength = 8 + RoundUp4(textLength);
+ outputMessage = writeBuffer_.addMessage(outputLength);
+ PutUINT(textLength, outputMessage + 6, bigEndian_);
+ decodeBuffer.decodeValue(value, 16, 6);
+ PutUINT(value, outputMessage + 4, bigEndian_);
+ unsigned char* nextDest = outputMessage + 8;
+
+ // Since ProtoStep7 (#issue 108)
+ decodeBuffer.decodeTextData(nextDest, textLength);
+
+ sequenceQueue_.push(clientSequence_, outputOpcode);
+ }
+ break;
+ case X_LookupColor:
+ case X_AllocNamedColor:
+ {
+ unsigned int textLength;
+ decodeBuffer.decodeValue(textLength, 16, 6);
+ outputLength = 12 + RoundUp4(textLength);
+ outputMessage = writeBuffer_.addMessage(outputLength);
+ decodeBuffer.decodeCachedValue(value, 29,
+ clientCache_ -> colormapCache);
+ PutULONG(value, outputMessage + 4, bigEndian_);
+ PutUINT(textLength, outputMessage + 8, bigEndian_);
+ unsigned char *nextDest = outputMessage + 12;
+
+ // Since ProtoStep7 (#issue 108)
+ decodeBuffer.decodeTextData(nextDest, textLength);
+
+ sequenceQueue_.push(clientSequence_, outputOpcode);
+ }
+ break;
+ case X_MapWindow:
+ case X_UnmapWindow:
+ case X_MapSubwindows:
+ case X_GetWindowAttributes:
+ case X_DestroyWindow:
+ case X_DestroySubwindows:
+ case X_QueryPointer:
+ case X_QueryTree:
+ {
+ outputLength = 8;
+ outputMessage = writeBuffer_.addMessage(outputLength);
+
+ if (outputOpcode == X_DestroyWindow) // Since ProtoStep7 (#issue 108)
+ {
+ decodeBuffer.decodeFreeXidValue(value, clientCache_ -> freeWindowCache);
+ }
+ else
+ {
+ decodeBuffer.decodeXidValue(value, clientCache_ -> windowCache);
+ }
+
+ PutULONG(value, outputMessage + 4, bigEndian_);
+ if (outputOpcode == X_QueryPointer ||
+ outputOpcode == X_GetWindowAttributes ||
+ outputOpcode == X_QueryTree)
+ {
+ sequenceQueue_.push(clientSequence_, outputOpcode);
+ }
+ }
+ break;
+ case X_OpenFont:
+ {
+ unsigned int nameLength;
+ decodeBuffer.decodeValue(nameLength, 16, 7);
+ outputLength = RoundUp4(12 + nameLength);
+ outputMessage = writeBuffer_.addMessage(outputLength);
+ PutUINT(nameLength, outputMessage + 8, bigEndian_);
+ decodeBuffer.decodeValue(value, 29, 5);
+ clientCache_ -> lastFont += value;
+ clientCache_ -> lastFont &= 0x1fffffff;
+ PutULONG(clientCache_ -> lastFont, outputMessage + 4, bigEndian_);
+ unsigned char *nextDest = outputMessage + 12;
+
+ // Since ProtoStep7 (#issue 108)
+ decodeBuffer.decodeTextData(nextDest, nameLength);
+ }
+ break;
+ case X_PolyFillRectangle:
+ {
+ MessageStore *messageStore = clientStore_ ->
+ getRequestStore(X_PolyFillRectangle);
+
+ if (handleDecodeCached(decodeBuffer, clientCache_, messageStore,
+ outputMessage, outputLength))
+ {
+ break;
+ }
+
+ outputLength = 12;
+ outputMessage = writeBuffer_.addMessage(outputLength);
+ writeBuffer_.registerPointer(&outputMessage);
+ decodeBuffer.decodeXidValue(value, clientCache_ -> drawableCache);
+ PutULONG(value, outputMessage + 4, bigEndian_);
+ decodeBuffer.decodeXidValue(value, clientCache_ -> gcCache);
+ PutULONG(value, outputMessage + 8, bigEndian_);
+
+ unsigned int index = 0;
+ unsigned int lastX = 0, lastY = 0, lastWidth = 0, lastHeight = 0;
+ unsigned int numRectangles = 0;
+
+ for (;;)
+ {
+ outputLength += 8;
+ writeBuffer_.addMessage(8);
+ unsigned char *nextDest = outputMessage + 12 +
+ (numRectangles << 3);
+ numRectangles++;
+ decodeBuffer.decodeCachedValue(value, 16,
+ *clientCache_ -> polyFillRectangleCacheX[index], 8);
+ value += lastX;
+ PutUINT(value, nextDest, bigEndian_);
+ lastX = value;
+ nextDest += 2;
+ decodeBuffer.decodeCachedValue(value, 16,
+ *clientCache_ -> polyFillRectangleCacheY[index], 8);
+ value += lastY;
+ PutUINT(value, nextDest, bigEndian_);
+ lastY = value;
+ nextDest += 2;
+ decodeBuffer.decodeCachedValue(value, 16,
+ *clientCache_ -> polyFillRectangleCacheWidth[index], 8);
+ value += lastWidth;
+ PutUINT(value, nextDest, bigEndian_);
+ lastWidth = value;
+ nextDest += 2;
+ decodeBuffer.decodeCachedValue(value, 16,
+ *clientCache_ -> polyFillRectangleCacheHeight[index], 8);
+ value += lastHeight;
+ PutUINT(value, nextDest, bigEndian_);
+ lastHeight = value;
+ nextDest += 2;
+
+ if (++index == 4) index = 0;
+
+ decodeBuffer.decodeBoolValue(value);
+
+ if (!value) break;
+ }
+ writeBuffer_.unregisterPointer();
+
+ handleSave(messageStore, outputMessage, outputLength);
+ }
+ break;
+ case X_PolyFillArc:
+ {
+ MessageStore *messageStore = clientStore_ ->
+ getRequestStore(X_PolyFillArc);
+
+ if (handleDecodeCached(decodeBuffer, clientCache_, messageStore,
+ outputMessage, outputLength))
+ {
+ break;
+ }
+
+ outputLength = 12;
+ outputMessage = writeBuffer_.addMessage(outputLength);
+ writeBuffer_.registerPointer(&outputMessage);
+ decodeBuffer.decodeXidValue(value, clientCache_ -> drawableCache);
+ PutULONG(value, outputMessage + 4, bigEndian_);
+ decodeBuffer.decodeXidValue(value, clientCache_ -> gcCache);
+ PutULONG(value, outputMessage + 8, bigEndian_);
+
+ unsigned int index = 0;
+ unsigned int lastX = 0, lastY = 0,
+ lastWidth = 0, lastHeight = 0,
+ lastAngle1 = 0, lastAngle2 = 0;
+
+ unsigned int numArcs = 0;
+
+ for (;;)
+ {
+ outputLength += 12;
+ writeBuffer_.addMessage(12);
+
+ unsigned char *nextDest = outputMessage + 12 +
+ (numArcs * 12);
+ numArcs++;
+
+ decodeBuffer.decodeCachedValue(value, 16,
+ *clientCache_ -> polyFillArcCacheX[index], 8);
+ value += lastX;
+ PutUINT(value, nextDest, bigEndian_);
+ lastX = value;
+ nextDest += 2;
+
+ decodeBuffer.decodeCachedValue(value, 16,
+ *clientCache_ -> polyFillArcCacheY[index], 8);
+ value += lastY;
+ PutUINT(value, nextDest, bigEndian_);
+ lastY = value;
+ nextDest += 2;
+
+ decodeBuffer.decodeCachedValue(value, 16,
+ *clientCache_ -> polyFillArcCacheWidth[index], 8);
+ value += lastWidth;
+ PutUINT(value, nextDest, bigEndian_);
+ lastWidth = value;
+ nextDest += 2;
+
+ decodeBuffer.decodeCachedValue(value, 16,
+ *clientCache_ -> polyFillArcCacheHeight[index], 8);
+ value += lastHeight;
+ PutUINT(value, nextDest, bigEndian_);
+ lastHeight = value;
+ nextDest += 2;
+
+ decodeBuffer.decodeCachedValue(value, 16,
+ *clientCache_ -> polyFillArcCacheAngle1[index], 8);
+ value += lastAngle1;
+ PutUINT(value, nextDest, bigEndian_);
+ lastAngle1 = value;
+ nextDest += 2;
+
+ decodeBuffer.decodeCachedValue(value, 16,
+ *clientCache_ -> polyFillArcCacheAngle2[index], 8);
+ value += lastAngle2;
+ PutUINT(value, nextDest, bigEndian_);
+ lastAngle2 = value;
+ nextDest += 2;
+
+ if (++index == 2) index = 0;
+
+ decodeBuffer.decodeBoolValue(value);
+
+ if (!value) break;
+ }
+ writeBuffer_.unregisterPointer();
+
+ handleSave(messageStore, outputMessage, outputLength);
+ }
+ break;
+ case X_PolyArc:
+ {
+ MessageStore *messageStore = clientStore_ ->
+ getRequestStore(X_PolyArc);
+
+ if (handleDecodeCached(decodeBuffer, clientCache_, messageStore,
+ outputMessage, outputLength))
+ {
+ break;
+ }
+
+ outputLength = 12;
+ outputMessage = writeBuffer_.addMessage(outputLength);
+ writeBuffer_.registerPointer(&outputMessage);
+ decodeBuffer.decodeXidValue(value, clientCache_ -> drawableCache);
+ PutULONG(value, outputMessage + 4, bigEndian_);
+ decodeBuffer.decodeXidValue(value, clientCache_ -> gcCache);
+ PutULONG(value, outputMessage + 8, bigEndian_);
+
+ unsigned int index = 0;
+ unsigned int lastX = 0, lastY = 0,
+ lastWidth = 0, lastHeight = 0,
+ lastAngle1 = 0, lastAngle2 = 0;
+
+ unsigned int numArcs = 0;
+
+ for (;;)
+ {
+ outputLength += 12;
+ writeBuffer_.addMessage(12);
+
+ unsigned char *nextDest = outputMessage + 12 +
+ (numArcs * 12);
+ numArcs++;
+
+ decodeBuffer.decodeCachedValue(value, 16,
+ *clientCache_ -> polyArcCacheX[index], 8);
+ value += lastX;
+ PutUINT(value, nextDest, bigEndian_);
+ lastX = value;
+ nextDest += 2;
+
+ decodeBuffer.decodeCachedValue(value, 16,
+ *clientCache_ -> polyArcCacheY[index], 8);
+ value += lastY;
+ PutUINT(value, nextDest, bigEndian_);
+ lastY = value;
+ nextDest += 2;
+
+ decodeBuffer.decodeCachedValue(value, 16,
+ *clientCache_ -> polyArcCacheWidth[index], 8);
+ value += lastWidth;
+ PutUINT(value, nextDest, bigEndian_);
+ lastWidth = value;
+ nextDest += 2;
+
+ decodeBuffer.decodeCachedValue(value, 16,
+ *clientCache_ -> polyArcCacheHeight[index], 8);
+ value += lastHeight;
+ PutUINT(value, nextDest, bigEndian_);
+ lastHeight = value;
+ nextDest += 2;
+
+ decodeBuffer.decodeCachedValue(value, 16,
+ *clientCache_ -> polyArcCacheAngle1[index], 8);
+ value += lastAngle1;
+ PutUINT(value, nextDest, bigEndian_);
+ lastAngle1 = value;
+ nextDest += 2;
+
+ decodeBuffer.decodeCachedValue(value, 16,
+ *clientCache_ -> polyArcCacheAngle2[index], 8);
+ value += lastAngle2;
+ PutUINT(value, nextDest, bigEndian_);
+ lastAngle2 = value;
+ nextDest += 2;
+
+ if (++index == 2) index = 0;
+
+ decodeBuffer.decodeBoolValue(value);
+
+ if (!value) break;
+ }
+ writeBuffer_.unregisterPointer();
+
+ handleSave(messageStore, outputMessage, outputLength);
+ }
+ break;
+ case X_PolyPoint:
+ {
+ MessageStore *messageStore = clientStore_ ->
+ getRequestStore(X_PolyPoint);
+
+ if (handleDecodeCached(decodeBuffer, clientCache_, messageStore,
+ outputMessage, outputLength))
+ {
+ break;
+ }
+
+ unsigned int numPoints;
+ decodeBuffer.decodeValue(numPoints, 16, 4);
+ outputLength = (numPoints << 2) + 12;
+ outputMessage = writeBuffer_.addMessage(outputLength);
+ unsigned int relativeCoordMode;
+ decodeBuffer.decodeBoolValue(relativeCoordMode);
+ outputMessage[1] = (unsigned char) relativeCoordMode;
+ decodeBuffer.decodeXidValue(value, clientCache_ -> drawableCache);
+ PutULONG(value, outputMessage + 4, bigEndian_);
+ decodeBuffer.decodeXidValue(value, clientCache_ -> gcCache);
+ PutULONG(value, outputMessage + 8, bigEndian_);
+ unsigned char *nextDest = outputMessage + 12;
+
+ unsigned int index = 0;
+ unsigned int lastX = 0, lastY = 0;
+
+ for (unsigned int i = 0; i < numPoints; i++)
+ {
+ decodeBuffer.decodeCachedValue(value, 16,
+ *clientCache_ -> polyPointCacheX[index], 8);
+ lastX += value;
+ PutUINT(lastX, nextDest, bigEndian_);
+ nextDest += 2;
+ decodeBuffer.decodeCachedValue(value, 16,
+ *clientCache_ -> polyPointCacheY[index], 8);
+ lastY += value;
+ PutUINT(lastY, nextDest, bigEndian_);
+ nextDest += 2;
+
+ if (++index == 2) index = 0;
+ }
+
+ handleSave(messageStore, outputMessage, outputLength);
+ }
+ break;
+ case X_PolyLine:
+ {
+ MessageStore *messageStore = clientStore_ ->
+ getRequestStore(X_PolyLine);
+
+ if (handleDecodeCached(decodeBuffer, clientCache_, messageStore,
+ outputMessage, outputLength))
+ {
+ break;
+ }
+
+ unsigned int numPoints;
+ decodeBuffer.decodeValue(numPoints, 16, 4);
+ outputLength = (numPoints << 2) + 12;
+ outputMessage = writeBuffer_.addMessage(outputLength);
+ unsigned int relativeCoordMode;
+ decodeBuffer.decodeBoolValue(relativeCoordMode);
+ outputMessage[1] = (unsigned char) relativeCoordMode;
+ decodeBuffer.decodeXidValue(value, clientCache_ -> drawableCache);
+ PutULONG(value, outputMessage + 4, bigEndian_);
+ decodeBuffer.decodeXidValue(value, clientCache_ -> gcCache);
+ PutULONG(value, outputMessage + 8, bigEndian_);
+ unsigned char *nextDest = outputMessage + 12;
+
+ unsigned int index = 0;
+ unsigned int lastX = 0, lastY = 0;
+
+ for (unsigned int i = 0; i < numPoints; i++)
+ {
+ decodeBuffer.decodeCachedValue(value, 16,
+ *clientCache_ -> polyLineCacheX[index], 8);
+ lastX += value;
+ PutUINT(lastX, nextDest, bigEndian_);
+ nextDest += 2;
+ decodeBuffer.decodeCachedValue(value, 16,
+ *clientCache_ -> polyLineCacheY[index], 8);
+ lastY += value;
+ PutUINT(lastY, nextDest, bigEndian_);
+ nextDest += 2;
+
+ if (++index == 2) index = 0;
+ }
+
+ handleSave(messageStore, outputMessage, outputLength);
+ }
+ break;
+ case X_PolyRectangle:
+ {
+ unsigned int numRectangles;
+ decodeBuffer.decodeValue(numRectangles, 16, 3);
+ outputLength = (numRectangles << 3) + 12;
+ outputMessage = writeBuffer_.addMessage(outputLength);
+ decodeBuffer.decodeXidValue(value, clientCache_ -> drawableCache);
+ PutULONG(value, outputMessage + 4, bigEndian_);
+ decodeBuffer.decodeXidValue(value, clientCache_ -> gcCache);
+ PutULONG(value, outputMessage + 8, bigEndian_);
+ unsigned char *nextDest = outputMessage + 12;
+ for (unsigned int i = 0; i < numRectangles; i++)
+ for (unsigned int k = 0; k < 4; k++)
+ {
+ decodeBuffer.decodeCachedValue(value, 16,
+ *clientCache_ -> polyRectangleGeomCache[k], 8);
+ PutUINT(value, nextDest, bigEndian_);
+ nextDest += 2;
+ }
+ }
+ break;
+ case X_PolySegment:
+ {
+ MessageStore *messageStore = clientStore_ ->
+ getRequestStore(X_PolySegment);
+
+ if (handleDecodeCached(decodeBuffer, clientCache_, messageStore,
+ outputMessage, outputLength))
+ {
+ break;
+ }
+
+ unsigned int numSegments;
+ decodeBuffer.decodeValue(numSegments, 16, 4);
+ outputLength = (numSegments << 3) + 12;
+ outputMessage = writeBuffer_.addMessage(outputLength);
+ decodeBuffer.decodeXidValue(value, clientCache_ -> drawableCache);
+ PutULONG(value, outputMessage + 4, bigEndian_);
+ decodeBuffer.decodeXidValue(value, clientCache_ -> gcCache);
+ PutULONG(value, outputMessage + 8, bigEndian_);
+ unsigned char *nextDest = outputMessage + 12;
+
+ for (numSegments *= 2; numSegments; numSegments--)
+ {
+ unsigned int index;
+ decodeBuffer.decodeBoolValue(index);
+ unsigned int x;
+ decodeBuffer.decodeCachedValue(x, 16,
+ clientCache_ -> polySegmentCacheX, 6);
+ x += clientCache_ -> polySegmentLastX[index];
+ PutUINT(x, nextDest, bigEndian_);
+ nextDest += 2;
+
+ unsigned int y;
+ decodeBuffer.decodeCachedValue(y, 16,
+ clientCache_ -> polySegmentCacheY, 6);
+ y += clientCache_ -> polySegmentLastY[index];
+ PutUINT(y, nextDest, bigEndian_);
+ nextDest += 2;
+
+ clientCache_ -> polySegmentLastX[clientCache_ -> polySegmentCacheIndex] = x;
+ clientCache_ -> polySegmentLastY[clientCache_ -> polySegmentCacheIndex] = y;
+
+ if (clientCache_ -> polySegmentCacheIndex == 1)
+ clientCache_ -> polySegmentCacheIndex = 0;
+ else
+ clientCache_ -> polySegmentCacheIndex = 1;
+ }
+
+ handleSave(messageStore, outputMessage, outputLength);
+ }
+ break;
+ case X_PutImage:
+ {
+ MessageStore *messageStore = clientStore_ ->
+ getRequestStore(X_PutImage);
+
+ hit = handleDecode(decodeBuffer, clientCache_, messageStore,
+ outputOpcode, outputMessage, outputLength);
+
+ if (outputOpcode == X_PutImage)
+ {
+ handleImage(outputOpcode, outputMessage, outputLength);
+ }
+ }
+ break;
+ case X_QueryBestSize:
+ {
+ outputLength = 12;
+ outputMessage = writeBuffer_.addMessage(outputLength);
+ decodeBuffer.decodeValue(value, 2);
+ outputMessage[1] = (unsigned char)value;
+ decodeBuffer.decodeXidValue(value, clientCache_ -> drawableCache);
+ PutULONG(value, outputMessage + 4, bigEndian_);
+ decodeBuffer.decodeValue(value, 16, 8);
+ PutUINT(value, outputMessage + 8, bigEndian_);
+ decodeBuffer.decodeValue(value, 16, 8);
+ PutUINT(value, outputMessage + 10, bigEndian_);
+
+ sequenceQueue_.push(clientSequence_, outputOpcode);
+ }
+ break;
+ case X_QueryColors:
+ {
+ // Differential or plain data compression?
+ decodeBuffer.decodeBoolValue(value);
+
+ if (value)
+ {
+ unsigned int numColors;
+ decodeBuffer.decodeValue(numColors, 16, 5);
+ outputLength = (numColors << 2) + 8;
+ outputMessage = writeBuffer_.addMessage(outputLength);
+ decodeBuffer.decodeCachedValue(value, 29,
+ clientCache_ -> colormapCache);
+ PutULONG(value, outputMessage + 4, bigEndian_);
+ unsigned char *nextDest = outputMessage + 8;
+ unsigned int predictedPixel = clientCache_ -> queryColorsLastPixel;
+ for (unsigned int i = 0; i < numColors; i++)
+ {
+ unsigned int pixel;
+ decodeBuffer.decodeBoolValue(value);
+ if (value)
+ pixel = predictedPixel;
+ else
+ decodeBuffer.decodeValue(pixel, 32, 9);
+ PutULONG(pixel, nextDest, bigEndian_);
+ if (i == 0)
+ clientCache_ -> queryColorsLastPixel = pixel;
+ predictedPixel = pixel + 1;
+ nextDest += 4;
+ }
+ }
+ else
+ {
+ // Request length.
+ unsigned int requestLength;
+ decodeBuffer.decodeValue(requestLength, 16, 10);
+ outputLength = (requestLength << 2);
+ outputMessage = writeBuffer_.addMessage(outputLength);
+
+ const unsigned char *compressedData = NULL;
+ unsigned int compressedDataSize = 0;
+
+ int decompressed = handleDecompress(decodeBuffer, outputOpcode, 4,
+ outputMessage, outputLength, compressedData,
+ compressedDataSize);
+ if (decompressed < 0)
+ {
+ return -1;
+ }
+ }
+
+ sequenceQueue_.push(clientSequence_, outputOpcode);
+ }
+ break;
+ case X_QueryExtension:
+ {
+ unsigned int nameLength;
+ decodeBuffer.decodeValue(nameLength, 16, 6);
+ outputLength = 8 + RoundUp4(nameLength);
+ outputMessage = writeBuffer_.addMessage(outputLength);
+ PutUINT(nameLength, outputMessage + 4, bigEndian_);
+ unsigned char *nextDest = outputMessage + 8;
+ for (unsigned int i = 0; i < nameLength; i++)
+ {
+ decodeBuffer.decodeValue(value, 8);
+ *nextDest++ = (unsigned char) value;
+ }
+
+ unsigned int hide = 0;
+
+ #ifdef HIDE_MIT_SHM_EXTENSION
+
+ if (!strncmp((char *) outputMessage + 8, "MIT-SHM", 7))
+ {
+ #ifdef TEST
+ *logofs << "handleWrite: Going to hide MIT-SHM extension in reply.\n"
+ << logofs_flush;
+ #endif
+
+ hide = 1;
+ }
+
+ #endif
+
+ #ifdef HIDE_BIG_REQUESTS_EXTENSION
+
+ if (!strncmp((char *) outputMessage + 8, "BIG-REQUESTS", 12))
+ {
+ #ifdef TEST
+ *logofs << "handleWrite: Going to hide BIG-REQUESTS extension in reply.\n"
+ << logofs_flush;
+ #endif
+
+ hide = 1;
+ }
+
+ #endif
+
+ #ifdef HIDE_XKEYBOARD_EXTENSION
+
+ else if (!strncmp((char *) outputMessage + 8, "XKEYBOARD", 9))
+ {
+ #ifdef TEST
+ *logofs << "handleWrite: Going to hide XKEYBOARD extension in reply.\n"
+ << logofs_flush;
+ #endif
+
+ hide = 1;
+ }
+
+ #endif
+
+ #ifdef HIDE_XFree86_Bigfont_EXTENSION
+
+ else if (!strncmp((char *) outputMessage + 8, "XFree86-Bigfont", 15))
+ {
+ #ifdef TEST
+ *logofs << "handleWrite: Going to hide XFree86-Bigfont extension in reply.\n"
+ << logofs_flush;
+ #endif
+
+ hide = 1;
+ }
+
+ #endif
+
+ //
+ // This is if you want to experiment disabling SHAPE extensions.
+ //
+
+ #ifdef HIDE_SHAPE_EXTENSION
+
+ if (!strncmp((char *) outputMessage + 8, "SHAPE", 5))
+ {
+ #ifdef DEBUG
+ *logofs << "handleWrite: Going to hide SHAPE extension in reply.\n"
+ << logofs_flush;
+ #endif
+
+ hide = 1;
+ }
+
+ #endif
+
+ //
+ // Check if user disabled RENDER extension.
+ //
+
+ if (control -> HideRender == 1 &&
+ strncmp((char *) outputMessage + 8, "RENDER", 6) == 0)
+ {
+ #ifdef TEST
+ *logofs << "handleWrite: Going to hide RENDER extension in reply.\n"
+ << logofs_flush;
+ #endif
+
+ hide = 1;
+ }
+
+ unsigned int extension = 0;
+
+ if (strncmp((char *) outputMessage + 8, "SHAPE", 5) == 0)
+ {
+ extension = X_NXInternalShapeExtension;
+ }
+ else if (strncmp((char *) outputMessage + 8, "RENDER", 6) == 0)
+ {
+ extension = X_NXInternalRenderExtension;
+ }
+
+ sequenceQueue_.push(clientSequence_, outputOpcode,
+ outputOpcode, hide, extension);
+ }
+ break;
+ case X_QueryFont:
+ {
+ outputLength = 8;
+ outputMessage = writeBuffer_.addMessage(outputLength);
+ decodeBuffer.decodeValue(value, 29, 5);
+ clientCache_ -> lastFont += value;
+ clientCache_ -> lastFont &= 0x1fffffff;
+ PutULONG(clientCache_ -> lastFont, outputMessage + 4, bigEndian_);
+
+ sequenceQueue_.push(clientSequence_, outputOpcode);
+ }
+ break;
+ case X_SetClipRectangles:
+ {
+ MessageStore *messageStore = clientStore_ ->
+ getRequestStore(X_SetClipRectangles);
+
+ if (handleDecodeCached(decodeBuffer, clientCache_, messageStore,
+ outputMessage, outputLength))
+ {
+ break;
+ }
+
+ unsigned int numRectangles;
+
+ // Since ProtoStep9 (#issue 108)
+ decodeBuffer.decodeValue(numRectangles, 15, 4);
+
+ outputLength = (numRectangles << 3) + 12;
+ outputMessage = writeBuffer_.addMessage(outputLength);
+ decodeBuffer.decodeValue(value, 2);
+ outputMessage[1] = (unsigned char) value;
+ decodeBuffer.decodeXidValue(value, clientCache_ -> gcCache);
+ PutULONG(value, outputMessage + 4, bigEndian_);
+ decodeBuffer.decodeCachedValue(value, 16,
+ clientCache_ -> setClipRectanglesXCache, 8);
+ PutUINT(value, outputMessage + 8, bigEndian_);
+ decodeBuffer.decodeCachedValue(value, 16,
+ clientCache_ -> setClipRectanglesYCache, 8);
+ PutUINT(value, outputMessage + 10, bigEndian_);
+ unsigned char *nextDest = outputMessage + 12;
+ for (unsigned int i = 0; i < numRectangles; i++)
+ {
+ for (unsigned int k = 0; k < 4; k++)
+ {
+ decodeBuffer.decodeCachedValue(value, 16,
+ *clientCache_ -> setClipRectanglesGeomCache[k], 8);
+ PutUINT(value, nextDest, bigEndian_);
+ nextDest += 2;
+ }
+ }
+
+ handleSave(messageStore, outputMessage, outputLength);
+ }
+ break;
+ case X_SetDashes:
+ {
+ unsigned int numDashes;
+ decodeBuffer.decodeCachedValue(numDashes, 16,
+ clientCache_ -> setDashesLengthCache, 5);
+ outputLength = 12 + RoundUp4(numDashes);
+ outputMessage = writeBuffer_.addMessage(outputLength);
+ PutUINT(numDashes, outputMessage + 10, bigEndian_);
+ decodeBuffer.decodeXidValue(value, clientCache_ -> gcCache);
+ PutULONG(value, outputMessage + 4, bigEndian_);
+ decodeBuffer.decodeCachedValue(value, 16,
+ clientCache_ -> setDashesOffsetCache, 5);
+ PutUINT(value, outputMessage + 8, bigEndian_);
+ unsigned char *nextDest = outputMessage + 12;
+ for (unsigned int i = 0; i < numDashes; i++)
+ {
+ decodeBuffer.decodeCachedValue(cValue, 8,
+ clientCache_ -> setDashesDashCache_[i & 1], 5);
+ *nextDest++ = cValue;
+ }
+ }
+ break;
+ case X_SetSelectionOwner:
+ {
+ outputLength = 16;
+ outputMessage = writeBuffer_.addMessage(outputLength);
+ decodeBuffer.decodeCachedValue(value, 29,
+ clientCache_ -> setSelectionOwnerCache, 9);
+ PutULONG(value, outputMessage + 4, bigEndian_);
+ decodeBuffer.decodeCachedValue(value, 29,
+ clientCache_ -> getSelectionOwnerSelectionCache, 9);
+ PutULONG(value, outputMessage + 8, bigEndian_);
+ decodeBuffer.decodeCachedValue(value, 32,
+ clientCache_ -> setSelectionOwnerTimestampCache, 9);
+ PutULONG(value, outputMessage + 12, bigEndian_);
+ }
+ break;
+ case X_TranslateCoords:
+ {
+ MessageStore *messageStore = clientStore_ ->
+ getRequestStore(X_TranslateCoords);
+
+ if (handleDecodeCached(decodeBuffer, clientCache_, messageStore,
+ outputMessage, outputLength))
+ {
+ sequenceQueue_.push(clientSequence_, outputOpcode);
+
+ break;
+ }
+
+ outputLength = 16;
+ outputMessage = writeBuffer_.addMessage(outputLength);
+ decodeBuffer.decodeCachedValue(value, 29,
+ clientCache_ -> translateCoordsSrcCache, 9);
+ PutULONG(value, outputMessage + 4, bigEndian_);
+ decodeBuffer.decodeCachedValue(value, 29,
+ clientCache_ -> translateCoordsDstCache, 9);
+ PutULONG(value, outputMessage + 8, bigEndian_);
+ decodeBuffer.decodeCachedValue(value, 16,
+ clientCache_ -> translateCoordsXCache, 8);
+ PutUINT(value, outputMessage + 12, bigEndian_);
+ decodeBuffer.decodeCachedValue(value, 16,
+ clientCache_ -> translateCoordsYCache, 8);
+ PutUINT(value, outputMessage + 14, bigEndian_);
+
+ sequenceQueue_.push(clientSequence_, outputOpcode);
+
+ handleSave(messageStore, outputMessage, outputLength);
+ }
+ break;
+ case X_GetImage:
+ {
+ MessageStore *messageStore = clientStore_ ->
+ getRequestStore(X_GetImage);
+
+ if (handleDecodeCached(decodeBuffer, clientCache_, messageStore,
+ outputMessage, outputLength))
+ {
+ sequenceQueue_.push(clientSequence_, outputOpcode);
+
+ break;
+ }
+
+ outputLength = 20;
+ outputMessage = writeBuffer_.addMessage(outputLength);
+ // Format.
+ unsigned int format;
+ decodeBuffer.decodeValue(format, 2);
+ outputMessage[1] = (unsigned char) format;
+ // Drawable.
+ decodeBuffer.decodeXidValue(value, clientCache_ -> drawableCache);
+ PutULONG(value, outputMessage + 4, bigEndian_);
+ // X.
+ decodeBuffer.decodeCachedValue(value, 16,
+ clientCache_ -> putImageXCache, 8);
+ clientCache_ -> putImageLastX += value;
+ clientCache_ -> putImageLastX &= 0xffff;
+ PutUINT(clientCache_ -> putImageLastX, outputMessage + 8, bigEndian_);
+ // Y.
+ decodeBuffer.decodeCachedValue(value, 16,
+ clientCache_ -> putImageYCache, 8);
+ clientCache_ -> putImageLastY += value;
+ clientCache_ -> putImageLastY &= 0xffff;
+ PutUINT(clientCache_ -> putImageLastY, outputMessage + 10, bigEndian_);
+ // Width.
+ unsigned int width;
+ decodeBuffer.decodeCachedValue(width, 16,
+ clientCache_ -> putImageWidthCache, 8);
+ PutUINT(width, outputMessage + 12, bigEndian_);
+ // Height.
+ unsigned int height;
+ decodeBuffer.decodeCachedValue(height, 16,
+ clientCache_ -> putImageHeightCache, 8);
+ PutUINT(height, outputMessage + 14, bigEndian_);
+ // Plane mask.
+ decodeBuffer.decodeCachedValue(value, 32,
+ clientCache_ -> getImagePlaneMaskCache, 5);
+ PutULONG(value, outputMessage + 16, bigEndian_);
+
+ sequenceQueue_.push(clientSequence_, outputOpcode);
+
+ handleSave(messageStore, outputMessage, outputLength);
+ }
+ break;
+ case X_GetPointerMapping:
+ {
+ outputLength = 4;
+ outputMessage = writeBuffer_.addMessage(outputLength);
+
+ sequenceQueue_.push(clientSequence_, outputOpcode);
+ }
+ break;
+ case X_GetKeyboardControl:
+ {
+ outputLength = 4;
+ outputMessage = writeBuffer_.addMessage(outputLength);
+
+ sequenceQueue_.push(clientSequence_, outputOpcode);
+ }
+ break;
+ default:
+ {
+ if (outputOpcode == opcodeStore_ -> renderExtension)
+ {
+ MessageStore *messageStore = clientStore_ ->
+ getRequestStore(X_NXInternalRenderExtension);
+
+ hit = handleDecode(decodeBuffer, clientCache_, messageStore,
+ outputOpcode, outputMessage, outputLength);
+ }
+ else if (outputOpcode == opcodeStore_ -> shapeExtension)
+ {
+ MessageStore *messageStore = clientStore_ ->
+ getRequestStore(X_NXInternalShapeExtension);
+
+ hit = handleDecode(decodeBuffer, clientCache_, messageStore,
+ outputOpcode, outputMessage, outputLength);
+ }
+ else if (outputOpcode == opcodeStore_ -> putPackedImage)
+ {
+ #ifdef DEBUG
+ *logofs << "handleWrite: Decoding packed image request for FD#"
+ << fd_ << ".\n" << logofs_flush;
+ #endif
+
+ MessageStore *messageStore = clientStore_ ->
+ getRequestStore(X_NXPutPackedImage);
+
+ hit = handleDecode(decodeBuffer, clientCache_, messageStore,
+ outputOpcode, outputMessage, outputLength);
+
+ if (outputOpcode == opcodeStore_ -> putPackedImage)
+ {
+ handleImage(outputOpcode, outputMessage, outputLength);
+ }
+ }
+ else if (outputOpcode == opcodeStore_ -> setUnpackColormap)
+ {
+ #ifdef DEBUG
+ *logofs << "handleWrite: Decoding set unpack colormap request "
+ << "for FD#" << fd_ << ".\n" << logofs_flush;
+ #endif
+
+ MessageStore *messageStore = clientStore_ ->
+ getRequestStore(X_NXSetUnpackColormap);
+
+ hit = handleDecode(decodeBuffer, clientCache_, messageStore,
+ outputOpcode, outputMessage, outputLength);
+ //
+ // Message could have been split.
+ //
+
+ if (outputOpcode == opcodeStore_ -> setUnpackColormap)
+ {
+ handleColormap(outputOpcode, outputMessage, outputLength);
+ }
+ }
+ else if (outputOpcode == opcodeStore_ -> setUnpackAlpha)
+ {
+ #ifdef DEBUG
+ *logofs << "handleWrite: Decoding unpack alpha request for FD#"
+ << fd_ << ".\n" << logofs_flush;
+ #endif
+
+ MessageStore *messageStore = clientStore_ ->
+ getRequestStore(X_NXSetUnpackAlpha);
+
+ hit = handleDecode(decodeBuffer, clientCache_, messageStore,
+ outputOpcode, outputMessage, outputLength);
+ //
+ // Message could have been split.
+ //
+
+ if (outputOpcode == opcodeStore_ -> setUnpackAlpha)
+ {
+ handleAlpha(outputOpcode, outputMessage, outputLength);
+ }
+ }
+ else if (outputOpcode == opcodeStore_ -> setUnpackGeometry)
+ {
+ #ifdef DEBUG
+ *logofs << "handleWrite: Decoding set unpack geometry request "
+ << "for FD#" << fd_ << ".\n" << logofs_flush;
+ #endif
+
+ MessageStore *messageStore = clientStore_ ->
+ getRequestStore(X_NXSetUnpackGeometry);
+
+ hit = handleDecode(decodeBuffer, clientCache_, messageStore,
+ outputOpcode, outputMessage, outputLength);
+
+ handleGeometry(outputOpcode, outputMessage, outputLength);
+ }
+ else if (outputOpcode == opcodeStore_ -> startSplit)
+ {
+ handleStartSplitRequest(decodeBuffer, outputOpcode,
+ outputMessage, outputLength);
+ }
+ else if (outputOpcode == opcodeStore_ -> endSplit)
+ {
+ handleEndSplitRequest(decodeBuffer, outputOpcode,
+ outputMessage, outputLength);
+ }
+ else if (outputOpcode == opcodeStore_ -> commitSplit)
+ {
+ int result = handleCommitSplitRequest(decodeBuffer, outputOpcode,
+ outputMessage, outputLength);
+
+ //
+ // Check if message has been successfully
+ // extracted from the split store. In this
+ // case post-process it in the usual way.
+ //
+
+ if (result > 0)
+ {
+ if (outputOpcode == opcodeStore_ -> putPackedImage ||
+ outputOpcode == X_PutImage)
+ {
+ handleImage(outputOpcode, outputMessage, outputLength);
+ }
+ else if (outputOpcode == opcodeStore_ -> setUnpackColormap)
+ {
+ handleColormap(outputOpcode, outputMessage, outputLength);
+ }
+ else if (outputOpcode == opcodeStore_ -> setUnpackAlpha)
+ {
+ handleAlpha(outputOpcode, outputMessage, outputLength);
+ }
+ }
+ else if (result < 0)
+ {
+ return -1;
+ }
+ }
+ else if (outputOpcode == opcodeStore_ -> abortSplit)
+ {
+ handleAbortSplitRequest(decodeBuffer, outputOpcode,
+ outputMessage, outputLength);
+ }
+ else if (outputOpcode == opcodeStore_ -> finishSplit)
+ {
+ #ifdef DEBUG
+ *logofs << "handleWrite: Decoding finish split request "
+ << "for FD#" << fd_ << ".\n" << logofs_flush;
+ #endif
+
+ decodeBuffer.decodeCachedValue(cValue, 8,
+ clientCache_ -> resourceCache);
+
+ handleNullRequest(outputOpcode, outputMessage, outputLength);
+ }
+ else if (outputOpcode == opcodeStore_ -> freeSplit)
+ {
+ #ifdef DEBUG
+ *logofs << "handleWrite: Decoding free split request "
+ << "for FD#" << fd_ << ".\n" << logofs_flush;
+ #endif
+
+ decodeBuffer.decodeCachedValue(cValue, 8,
+ clientCache_ -> resourceCache);
+
+ handleNullRequest(outputOpcode, outputMessage, outputLength);
+ }
+ else if (outputOpcode == opcodeStore_ -> freeUnpack)
+ {
+ #ifdef DEBUG
+ *logofs << "handleWrite: Decoding free unpack request "
+ << "for FD#" << fd_ << ".\n" << logofs_flush;
+ #endif
+
+ decodeBuffer.decodeCachedValue(cValue, 8,
+ clientCache_ -> resourceCache);
+
+ #ifdef DEBUG
+ *logofs << "handleWrite: Freeing unpack state for resource "
+ << (unsigned int) cValue << ".\n" << logofs_flush;
+ #endif
+
+ handleUnpackStateRemove(cValue);
+
+ handleNullRequest(outputOpcode, outputMessage, outputLength);
+ }
+ else if (outputOpcode == opcodeStore_ -> setExposeParameters)
+ {
+ //
+ // Send expose events according to agent's wish.
+ //
+
+ decodeBuffer.decodeBoolValue(enableExpose_);
+ decodeBuffer.decodeBoolValue(enableGraphicsExpose_);
+ decodeBuffer.decodeBoolValue(enableNoExpose_);
+
+ handleNullRequest(outputOpcode, outputMessage, outputLength);
+ }
+ else if (outputOpcode == opcodeStore_ -> getUnpackParameters)
+ {
+ //
+ // Client proxy needs the list of supported
+ // unpack methods. We would need an encode
+ // buffer, but this is in proxy, not here in
+ // channel.
+ //
+
+ #ifdef TEST
+ *logofs << "handleWrite: Sending X_GetInputFocus request for FD#"
+ << fd_ << " due to OPCODE#" << (unsigned int) outputOpcode
+ << ".\n" << logofs_flush;
+ #endif
+
+ outputOpcode = X_GetInputFocus;
+
+ outputLength = 4;
+ outputMessage = writeBuffer_.addMessage(outputLength);
+
+ sequenceQueue_.push(clientSequence_, outputOpcode,
+ opcodeStore_ -> getUnpackParameters);
+ }
+ else if (outputOpcode == opcodeStore_ -> getControlParameters ||
+ outputOpcode == opcodeStore_ -> getCleanupParameters ||
+ outputOpcode == opcodeStore_ -> getImageParameters)
+ {
+ handleNullRequest(outputOpcode, outputMessage, outputLength);
+ }
+ else if (outputOpcode == opcodeStore_ -> getShmemParameters)
+ {
+ if (handleShmemRequest(decodeBuffer, outputOpcode,
+ outputMessage, outputLength) < 0)
+ {
+ return -1;
+ }
+ }
+ else if (outputOpcode == opcodeStore_ -> setCacheParameters)
+ {
+ if (handleCacheRequest(decodeBuffer, outputOpcode,
+ outputMessage, outputLength) < 0)
+ {
+ return -1;
+ }
+ }
+ else if (outputOpcode == opcodeStore_ -> getFontParameters)
+ {
+ if (handleFontRequest(decodeBuffer, outputOpcode,
+ outputMessage, outputLength) < 0)
+ {
+ return -1;
+ }
+ }
+ else
+ {
+ MessageStore *messageStore = clientStore_ ->
+ getRequestStore(X_NXInternalGenericRequest);
+
+ hit = handleDecode(decodeBuffer, clientCache_, messageStore,
+ outputOpcode, outputMessage, outputLength);
+ }
+ }
+ } // End of switch on opcode.
+
+ //
+ // TODO: at the moment the variable hit was being set
+ // but not used, so to avoid the corresponding warning
+ // this logging block has been added.
+ // This code will probably be optimized away when none
+ // of the defines is set, but if there is no additional
+ // use for the hit variable in the future, then maybe
+ // it could be removed completely.
+ //
+
+ if (hit)
+ {
+ #if defined(TEST) || defined(OPCODES)
+ *logofs << "handleWrite: Cached flag enabled in handled request.\n"
+ << logofs_flush;
+ #endif
+ }
+
+ //
+ // A packed image request can generate more than just
+ // a single X_PutImage. Write buffer is handled inside
+ // handleUnpack(). Cannot simply assume that the final
+ // opcode and size must be put at the buffer offset as
+ // as buffer could have been grown or could have been
+ // replaced by a scratch buffer. The same is true in
+ // the case of a shared memory image.
+ //
+
+ if (outputOpcode != 0)
+ {
+ //
+ // Commit opcode and size to the buffer.
+ //
+
+ *outputMessage = (unsigned char) outputOpcode;
+
+ PutUINT(outputLength >> 2, outputMessage + 2, bigEndian_);
+
+ #if defined(TEST) || defined(OPCODES)
+ *logofs << "handleWrite: Handled request OPCODE#"
+ << (unsigned int) outputOpcode << " ("
+ << DumpOpcode(outputOpcode) << ") for FD#"
+ << fd_ << " sequence " << clientSequence_
+ << ". " << outputLength << " bytes out.\n"
+ << logofs_flush;
+ #endif
+ }
+ #if defined(TEST) || defined(OPCODES)
+ else
+ {
+ //
+ // In case of shared memory images the log doesn't
+ // reflect the actual opcode of the request that is
+ // going to be written. It would be possible to find
+ // the opcode of the original request received from
+ // the remote proxy in member imageState_ -> opcode,
+ // but we have probably already deleted the struct.
+ //
+
+ *logofs << "handleWrite: Handled image request for FD#"
+ << fd_ << " new sequence " << clientSequence_
+ << ". " << outputLength << " bytes out.\n"
+ << logofs_flush;
+ }
+ #endif
+
+ //
+ // Check if we produced enough data. We need to
+ // decode all the proxy messages or the decode
+ // buffer will be left in an inconsistent state,
+ // so we just update the finish flag in case of
+ // failure.
+ //
+
+ handleFlush(flush_if_needed);
+
+ } // End of while (decodeBuffer.decodeOpcodeValue(outputOpcode, 8, ...
+
+ } // End of the decoding block.
+
+ //
+ // Write any remaining data to the X connection.
+ //
+
+ if (handleFlush(flush_if_any) < 0)
+ {
+ return -1;
+ }
+
+ //
+ // Reset offset at which we read the
+ // last event looking for the shared
+ // memory completion.
+ //
+
+ if (shmemState_ != NULL)
+ {
+ shmemState_ -> checked = 0;
+ }
+
+ return 1;
+}
+
+//
+// End of handleWrite().
+//
+
+//
+// Other members.
+//
+
+int ServerChannel::handleSplit(DecodeBuffer &decodeBuffer, MessageStore *store,
+ T_store_action action, int position, unsigned char &opcode,
+ unsigned char *&buffer, unsigned int &size)
+{
+ // Since ProtoStep7 (#issue 108)
+ splitState_.current = splitState_.resource;
+
+ handleSplitStoreAlloc(&splitResources_, splitState_.current);
+
+ #if defined(TEST) || defined(SPLIT)
+ *logofs << "handleSplit: SPLIT! Message OPCODE#"
+ << (unsigned int) store -> opcode() << " of size " << size
+ << " [split] with resource " << splitState_.current
+ << " position " << position << " and action ["
+ << DumpAction(action) << "] at " << strMsTimestamp()
+ << ".\n" << logofs_flush;
+ #endif
+
+ //
+ // Get the MD5 of the message being
+ // split.
+ //
+
+ T_checksum checksum = NULL;
+
+ if (action != IS_HIT)
+ {
+ handleSplitChecksum(decodeBuffer, checksum);
+ }
+
+ //
+ // The method must abort the connection
+ // if it can't allocate the split.
+ //
+
+ Split *splitMessage = clientStore_ -> getSplitStore(splitState_.current) ->
+ add(store, splitState_.current, position,
+ action, checksum, buffer, size);
+
+ //
+ // If the encoding side didn't provide
+ // a checksum, then don't send the split
+ // report.
+ //
+
+ if (checksum == NULL)
+ {
+ if (action == IS_HIT)
+ {
+ splitMessage -> setState(split_loaded);
+ }
+ else
+ {
+ splitMessage -> setState(split_missed);
+ }
+
+ #if defined(TEST) || defined(SPLIT)
+
+ *logofs << "handleSplit: SPLIT! There are " << clientStore_ ->
+ getSplitTotalSize() << " messages and " << clientStore_ ->
+ getSplitTotalStorageSize() << " bytes to send in "
+ << "the split stores.\n" << logofs_flush;
+
+ clientStore_ -> dumpSplitStore(splitState_.current);
+
+ #endif
+
+ return 1;
+ }
+
+ delete [] checksum;
+
+ //
+ // Tell the split store if it must use
+ // the disk cache to retrieve and save
+ // the message.
+ //
+
+ splitMessage -> setPolicy(splitState_.load, splitState_.save);
+
+ //
+ // Try to locate the message on disk.
+ //
+
+ if (clientStore_ -> getSplitStore(splitState_.current) ->
+ load(splitMessage) == 1)
+ {
+ #if defined(TEST) || defined(SPLIT)
+ *logofs << "handleSplit: SPLIT! Loaded the message "
+ << "from the image cache.\n" << logofs_flush;
+ #endif
+
+ splitMessage -> setState(split_loaded);
+ }
+ else
+ {
+ #if defined(TEST) || defined(SPLIT)
+ *logofs << "handleSplit: WARNING! SPLIT! Can't find the message "
+ << "in the image cache.\n" << logofs_flush;
+ #endif
+
+ splitMessage -> setState(split_missed);
+ }
+
+ #if defined(TEST) || defined(SPLIT)
+
+ T_timestamp startTs = getTimestamp();
+
+ *logofs << "handleSplit: SPLIT! Encoding abort "
+ << "split events for FD#" << fd_ << " at "
+ << strMsTimestamp() << ".\n" << logofs_flush;
+ #endif
+
+ if (proxy -> handleAsyncSplit(fd_, splitMessage) < 0)
+ {
+ return -1;
+ }
+
+ //
+ // Send the encoded data immediately. We
+ // want the abort split message to reach
+ // the remote proxy as soon as possible.
+ //
+
+ if (proxy -> handleAsyncFlush() < 0)
+ {
+ return -1;
+ }
+
+ #if defined(TEST) || defined(SPLIT)
+
+ *logofs << "handleSplit: SPLIT! Spent "
+ << diffTimestamp(startTs, getTimestamp()) << " Ms "
+ << "handling abort split events for FD#" << fd_
+ << ".\n" << logofs_flush;
+
+ *logofs << "handleSplit: SPLIT! There are " << clientStore_ ->
+ getSplitTotalSize() << " messages and " << clientStore_ ->
+ getSplitTotalStorageSize() << " bytes to send in "
+ << "the split stores.\n" << logofs_flush;
+
+ clientStore_ -> dumpSplitStore(splitState_.current);
+
+ #endif
+
+ return 1;
+}
+
+int ServerChannel::handleSplit(DecodeBuffer &decodeBuffer)
+{
+ #if defined(TEST) || defined(SPLIT)
+ *logofs << "handleSplit: SPLIT! Going to handle splits "
+ << "for FD#" << fd_ << " at " << strMsTimestamp()
+ << ".\n" << logofs_flush;
+ #endif
+
+ unsigned char resource;
+
+ // Since ProtoStep7 (#issue 108)
+ decodeBuffer.decodeCachedValue(resource, 8,
+ clientCache_ -> resourceCache);
+
+ splitState_.current = resource;
+
+ handleSplitStoreAlloc(&splitResources_, splitState_.current);
+
+ SplitStore *splitStore = clientStore_ -> getSplitStore(splitState_.current);
+
+ #if defined(TEST) || defined(SPLIT)
+ *logofs << "handleSplit: SPLIT! Handling splits for "
+ << "resource [" << splitState_.current << "] with "
+ << splitStore -> getSize() << " elements "
+ << "in the split store.\n" << logofs_flush;
+ #endif
+
+ int result = splitStore -> receive(decodeBuffer);
+
+ if (result < 0)
+ {
+ #ifdef PANIC
+ *logofs << "handleSplit: PANIC! Receive of split for FD#" << fd_
+ << " failed.\n" << logofs_flush;
+ #endif
+
+ cerr << "Error" << ": Receive of split for FD#" << fd_
+ << " failed.\n";
+
+ return -1;
+ }
+ else if (result == 0)
+ {
+ //
+ // The split is still incomplete. It's time
+ // to check if we need to start the house-
+ // keeping process to take care of the image
+ // cache.
+ //
+
+ if (proxy -> handleAsyncKeeperCallback() < 0)
+ {
+ return -1;
+ }
+ }
+ else
+ {
+ //
+ // Note that we don't need the resource id at the
+ // X server side and, thus, we don't provide it
+ // at the time we add split to the split store.
+ //
+
+ #if defined(TEST) || defined(SPLIT)
+ *logofs << "handleSplit: SPLIT! Remote agent should "
+ << "now commit a new split for resource ["
+ << splitState_.current << "].\n"
+ << logofs_flush;
+
+ clientStore_ -> dumpCommitStore();
+
+ #endif
+
+ if (splitStore -> getSize() == 0)
+ {
+ #if defined(TEST) || defined(SPLIT)
+ *logofs << "handleSplit: SPLIT! Removing split store "
+ << "for resource [" << splitState_.current
+ << "] at " << strMsTimestamp() << ".\n"
+ << logofs_flush;
+ #endif
+
+ handleSplitStoreRemove(&splitResources_, splitState_.current);
+
+ #if defined(TEST) || defined(SPLIT)
+ *logofs << "handleSplit: SPLIT! There are [" << clientStore_ ->
+ getSplitTotalSize() << "] messages and " << clientStore_ ->
+ getSplitTotalStorageSize() << " bytes to send in "
+ << "the split stores.\n" << logofs_flush;
+ #endif
+ }
+ else
+ {
+ //
+ // If the next split is discarded, it can be
+ // that, since the beginning of the split, we
+ // have saved the message on the disk, due to
+ // a more recent split operation. This is also
+ // the case when we had to discard the message
+ // because it was locked but, since then, we
+ // completed the transferral of the split.
+ //
+
+ Split *splitMessage = splitStore -> getFirstSplit();
+
+ if (splitMessage -> getAction() == is_discarded &&
+ splitMessage -> getState() == split_missed &&
+ splitStore -> load(splitMessage) == 1)
+ {
+ #if defined(TEST) || defined(SPLIT)
+ *logofs << "handleSplit: WARNING! SPLIT! Asynchronously "
+ << "loaded the message from the image cache.\n"
+ << logofs_flush;
+ #endif
+
+ splitMessage -> setState(split_loaded);
+
+ #if defined(TEST) || defined(SPLIT)
+
+ T_timestamp startTs = getTimestamp();
+
+ *logofs << "handleSplit: WARNING! SPLIT! Asynchronously "
+ << "encoding abort split events for FD#" << fd_
+ << " at " << strMsTimestamp() << ".\n"
+ << logofs_flush;
+ #endif
+
+ if (proxy -> handleAsyncSplit(fd_, splitMessage) < 0)
+ {
+ return -1;
+ }
+
+ //
+ // Send the encoded data immediately. We
+ // want the abort split message to reach
+ // the remote proxy as soon as possible.
+ //
+
+ if (proxy -> handleAsyncFlush() < 0)
+ {
+ return -1;
+ }
+
+ #if defined(TEST) || defined(SPLIT)
+
+ *logofs << "handleSplit: WARNING! SPLIT! Spent "
+ << diffTimestamp(startTs, getTimestamp()) << " Ms "
+ << "handling asynchronous abort split events for "
+ << "FD#" << fd_ << ".\n" << logofs_flush;
+
+ *logofs << "handleSplit: SPLIT! There are " << clientStore_ ->
+ getSplitTotalSize() << " messages and " << clientStore_ ->
+ getSplitTotalStorageSize() << " bytes to send in "
+ << "the split stores.\n" << logofs_flush;
+
+ clientStore_ -> dumpSplitStore(splitState_.current);
+
+ #endif
+ }
+ }
+ }
+
+ return 1;
+}
+
+int ServerChannel::handleSplitEvent(EncodeBuffer &encodeBuffer, Split *splitMessage)
+{
+ int resource = splitMessage -> getResource();
+
+ #if defined(TEST) || defined(SPLIT)
+ *logofs << "handleSplitEvent: SPLIT! Going to send a "
+ << "split report for resource " << resource
+ << ".\n" << logofs_flush;
+ #endif
+
+ //
+ // This function is called only after the message
+ // has been searched in the disk cache. We need to
+ // inform the other side if the data transfer can
+ // start or it must be aborted to let the local
+ // side use the copy that was found on the disk.
+ //
+
+ #if defined(TEST) || defined(INFO)
+
+ if (splitMessage -> getState() != split_loaded &&
+ splitMessage -> getState() != split_missed)
+ {
+ *logofs << "handleSplitEvent: PANIC! Can't find the split to be aborted.\n"
+ << logofs_flush;
+
+ HandleCleanup();
+ }
+
+ #endif
+
+ //
+ // We need to send a boolean telling if the split
+ // was found or not, followed by the checksum of
+ // message we are referencing.
+ //
+
+ T_checksum checksum = splitMessage -> getChecksum();
+
+ #if defined(TEST) || defined(SPLIT)
+ *logofs << "handleSplitEvent: SPLIT! Sending split report for "
+ << "checksum [" << DumpChecksum(checksum) << "].\n"
+ << logofs_flush;
+ #endif
+
+ if (proxy -> handleAsyncSwitch(fd_) < 0)
+ {
+ return -1;
+ }
+
+ encodeBuffer.encodeOpcodeValue(opcodeStore_ -> splitEvent,
+ serverCache_ -> opcodeCache);
+
+ //
+ // The encoding in older protocol versions
+ // is different but we will never try to
+ // send a split report if the remote does
+ // not support our version.
+ //
+
+ encodeBuffer.encodeCachedValue(resource, 8,
+ serverCache_ -> resourceCache);
+
+ if (splitMessage -> getState() == split_loaded)
+ {
+ encodeBuffer.encodeBoolValue(1);
+
+ encodeBuffer.encodeOpcodeValue(splitMessage -> getStore() -> opcode(),
+ serverCache_ -> abortOpcodeCache);
+
+ encodeBuffer.encodeValue(splitMessage -> compressedSize(), 32, 14);
+ }
+ else
+ {
+ encodeBuffer.encodeBoolValue(0);
+ }
+
+ for (unsigned int i = 0; i < MD5_LENGTH; i++)
+ {
+ encodeBuffer.encodeValue((unsigned int) checksum[i], 8);
+ }
+
+ //
+ // Update statistics for this special opcode.
+ //
+
+ int bits = encodeBuffer.diffBits();
+
+ #if defined(TEST) || defined(OPCODES) || defined(INFO) || defined(SPLIT)
+ *logofs << "handleSplitEvent: SPLIT! Handled event OPCODE#"
+ << (unsigned int) opcodeStore_ -> splitEvent << " ("
+ << DumpOpcode(opcodeStore_ -> splitEvent) << ")" << " for FD#"
+ << fd_ << " sequence none. 0 bytes in, " << bits << " bits ("
+ << ((float) bits) / 8 << " bytes) out.\n" << logofs_flush;
+ #endif
+
+ statistics -> addEventBits(opcodeStore_ -> splitEvent, 0, bits);
+
+ return 1;
+}
+
+int ServerChannel::handleAbortSplitRequest(DecodeBuffer &decodeBuffer, unsigned char &opcode,
+ unsigned char *&buffer, unsigned int &size)
+{
+ unsigned char resource;
+
+ decodeBuffer.decodeCachedValue(resource, 8,
+ clientCache_ -> resourceCache);
+
+ #if defined(TEST) || defined(SPLIT)
+ *logofs << "handleAbortSplitRequest: SPLIT! Handling abort split "
+ << "request for FD#" << fd_ << " and resource "
+ << (unsigned) resource << ".\n"
+ << logofs_flush;
+ #endif
+
+ int splits = 0;
+
+ SplitStore *splitStore = clientStore_ -> getSplitStore(resource);
+
+ if (splitStore != NULL)
+ {
+ //
+ // Discard from the memory cache the messages
+ // that are still incomplete and then get rid
+ // of the splits in the store.
+ //
+
+ #if defined(TEST) || defined(SPLIT)
+
+ clientStore_ -> dumpSplitStore(resource);
+
+ #endif
+
+ Split *splitMessage;
+
+ for (;;)
+ {
+ splitMessage = splitStore -> getFirstSplit();
+
+ if (splitMessage == NULL)
+ {
+ //
+ // Check if we had created the store
+ // but no message was added yet.
+ //
+
+ #ifdef WARNING
+
+ if (splits == 0)
+ {
+ *logofs << "handleAbortSplitRequest: WARNING! SPLIT! The "
+ << "split store for resource [" << (unsigned int)
+ resource << "] is unexpectedly empty.\n"
+ << logofs_flush;
+ }
+
+ #endif
+
+ break;
+ }
+
+ //
+ // Splits already aborted can't be in the
+ // split store.
+ //
+
+ #if defined(TEST) || defined(SPLIT)
+
+ if (splitMessage -> getState() == split_aborted)
+ {
+ *logofs << "handleAbortSplitRequest: PANIC! SPLIT! Found an "
+ << "aborted split in store [" << (unsigned int) resource
+ << "].\n" << logofs_flush;
+
+ HandleCleanup();
+ }
+
+ #endif
+
+ if (splitMessage -> getAction() == IS_HIT)
+ {
+ #if defined(TEST) || defined(SPLIT)
+ *logofs << "handleAbortSplitRequest: SPLIT! Removing the "
+ << "split from the memory cache.\n"
+ << logofs_flush;
+ #endif
+
+ splitMessage -> getStore() -> remove(splitMessage -> getPosition(),
+ discard_checksum, use_data);
+ }
+
+ #if defined(TEST) || defined(SPLIT)
+ *logofs << "handleAbortSplitRequest: SPLIT! Removing the "
+ << "split from the split store.\n"
+ << logofs_flush;
+ #endif
+
+ splitMessage = splitStore -> pop();
+
+ #if defined(TEST) || defined(SPLIT)
+ *logofs << "handleAbortSplitRequest: SPLIT! Freeing up the "
+ << "aborted split.\n" << logofs_flush;
+ #endif
+
+ delete splitMessage;
+
+ splits++;
+ }
+ }
+ #ifdef WARNING
+ else
+ {
+ *logofs << "handleAbortSplitRequest: WARNING! SPLIT! The "
+ << "split store for resource [" << (unsigned int)
+ resource << "] is already empty.\n"
+ << logofs_flush;
+ }
+ #endif
+
+ handleNullRequest(opcode, buffer, size);
+
+ return (splits > 0);
+}
+
+int ServerChannel::handleCommitSplitRequest(DecodeBuffer &decodeBuffer, unsigned char &opcode,
+ unsigned char *&buffer, unsigned int &size)
+{
+ //
+ // Get request type and position of the image
+ // to commit.
+ //
+
+ unsigned char request;
+
+ decodeBuffer.decodeOpcodeValue(request, clientCache_ -> opcodeCache);
+
+ unsigned int diffCommit;
+
+ decodeBuffer.decodeValue(diffCommit, 32, 5);
+
+ splitState_.commit += diffCommit;
+
+ unsigned char resource = 0;
+ unsigned int commit = 1;
+
+ //
+ // Send the resource id and the commit flag.
+ // The resource id is ignored at the moment.
+ // The message will be handled based on the
+ // resource id that was sent together with
+ // the original message.
+ //
+
+ decodeBuffer.decodeCachedValue(resource, 8,
+ clientCache_ -> resourceCache);
+
+ decodeBuffer.decodeBoolValue(commit);
+
+ Split *split = handleSplitCommitRemove(request, resource, splitState_.commit);
+
+ if (split == NULL)
+ {
+ return -1;
+ }
+
+ clientStore_ -> getCommitStore() -> update(split);
+
+ if (commit == 1)
+ {
+ #if defined(TEST) || defined(SPLIT)
+ *logofs << "handleCommitSplitRequest: SPLIT! Handling split commit "
+ << "for FD#" << fd_ << " with commit " << commit
+ << " request " << (unsigned) request << " resource "
+ << (unsigned) resource << " and position "
+ << splitState_.commit << ".\n"
+ << logofs_flush;
+ #endif
+
+ //
+ // Allocate as many bytes in the write
+ // buffer as the final length of the
+ // message in uncompressed form.
+ //
+
+ size = split -> plainSize();
+
+ buffer = writeBuffer_.addMessage(size);
+
+ #if defined(TEST) || defined(SPLIT)
+ *logofs << "handleCommitSplitRequest: SPLIT! Prepared an "
+ << "outgoing buffer of " << size << " bytes.\n"
+ << logofs_flush;
+ #endif
+
+ if (clientStore_ -> getCommitStore() -> expand(split, buffer, size) < 0)
+ {
+ writeBuffer_.removeMessage(size);
+
+ commit = 0;
+ }
+ }
+
+ //
+ // Free the split.
+ //
+
+ #if defined(TEST) || defined(SPLIT)
+ *logofs << "handleCommitSplitRequest: SPLIT! Freeing up the "
+ << "committed split.\n" << logofs_flush;
+ #endif
+
+ delete split;
+
+ //
+ // Discard the operation and send a null
+ // message.
+ //
+
+ if (commit == 0)
+ {
+ handleNullRequest(opcode, buffer, size);
+ }
+ else
+ {
+ //
+ // Save the sequence number to be able
+ // to mask any error generated by the
+ // request.
+ //
+
+ updateCommitQueue(clientSequence_);
+
+ //
+ // Now in the write buffer there is
+ // a copy of this request.
+ //
+
+ opcode = request;
+ }
+
+ return commit;
+}
+
+int ServerChannel::handleGeometry(unsigned char &opcode, unsigned char *&buffer,
+ unsigned int &size)
+{
+ //
+ // Replace the old geometry and taint
+ // the message into a X_NoOperation.
+ //
+
+ int resource = *(buffer + 1);
+
+ #ifdef TEST
+ *logofs << "handleGeometry: Setting new unpack geometry "
+ << "for resource " << resource << ".\n"
+ << logofs_flush;
+ #endif
+
+ handleUnpackStateInit(resource);
+
+ handleUnpackAllocGeometry(resource);
+
+ unpackState_[resource] -> geometry -> depth1_bpp = *(buffer + 4);
+ unpackState_[resource] -> geometry -> depth4_bpp = *(buffer + 5);
+ unpackState_[resource] -> geometry -> depth8_bpp = *(buffer + 6);
+ unpackState_[resource] -> geometry -> depth16_bpp = *(buffer + 7);
+ unpackState_[resource] -> geometry -> depth24_bpp = *(buffer + 8);
+ unpackState_[resource] -> geometry -> depth32_bpp = *(buffer + 9);
+
+ unpackState_[resource] -> geometry -> red_mask = GetULONG(buffer + 12, bigEndian_);
+ unpackState_[resource] -> geometry -> green_mask = GetULONG(buffer + 16, bigEndian_);
+ unpackState_[resource] -> geometry -> blue_mask = GetULONG(buffer + 20, bigEndian_);
+
+ handleCleanAndNullRequest(opcode, buffer, size);
+
+ return 1;
+}
+
+int ServerChannel::handleColormap(unsigned char &opcode, unsigned char *&buffer,
+ unsigned int &size)
+{
+ //
+ // Replace the old colormap and taint
+ // the message into a X_NoOperation.
+ //
+
+ int resource = *(buffer + 1);
+
+ #ifdef TEST
+ *logofs << "handleColormap: Setting new unpack colormap "
+ << "for resource " << resource << ".\n"
+ << logofs_flush;
+ #endif
+
+ handleUnpackStateInit(resource);
+
+ handleUnpackAllocColormap(resource);
+
+ //
+ // New protocol versions send the alpha
+ // data in compressed form.
+ //
+
+ //
+ // Since ProtoStep7 (#issue 108)
+ //
+
+ { // An anonymous block is used here to limit the scope of local variables
+ unsigned int packed = GetULONG(buffer + 8, bigEndian_);
+ unsigned int unpacked = GetULONG(buffer + 12, bigEndian_);
+
+ validateSize("colormap", packed, unpacked, 16, size);
+
+ if (unpackState_[resource] -> colormap -> entries != unpacked >> 2 &&
+ unpackState_[resource] -> colormap -> data != NULL)
+ {
+ #ifdef TEST
+ *logofs << "handleColormap: Freeing previously allocated "
+ << "unpack colormap data.\n" << logofs_flush;
+ #endif
+
+ delete [] unpackState_[resource] -> colormap -> data;
+
+ unpackState_[resource] -> colormap -> data = NULL;
+ unpackState_[resource] -> colormap -> entries = 0;
+ }
+
+ #ifdef TEST
+ *logofs << "handleColormap: Setting " << unpacked
+ << " bytes of unpack colormap data for resource "
+ << resource << ".\n" << logofs_flush;
+ #endif
+
+ if (unpackState_[resource] -> colormap -> data == NULL)
+ {
+ unpackState_[resource] -> colormap -> data =
+ (unsigned int *) new unsigned char[unpacked];
+
+ if (unpackState_[resource] -> colormap -> data == NULL)
+ {
+ #ifdef PANIC
+ *logofs << "handleColormap: PANIC! Can't allocate "
+ << unpacked << " entries for unpack colormap data "
+ << "for FD#" << fd_ << ".\n" << logofs_flush;
+ #endif
+
+ goto handleColormapEnd;
+ }
+
+ #ifdef DEBUG
+ *logofs << "handleColormap: Size of new colormap data is "
+ << unpacked << ".\n" << logofs_flush;
+ #endif
+ }
+
+ unsigned int method = *(buffer + 4);
+
+ if (method == PACK_COLORMAP)
+ {
+ if (UnpackColormap(method, buffer + 16, packed,
+ (unsigned char *) unpackState_[resource] ->
+ colormap -> data, unpacked) < 0)
+ {
+ #ifdef PANIC
+ *logofs << "handleColormap: PANIC! Can't unpack " << packed
+ << " bytes to " << unpacked << " entries for FD#"
+ << fd_ << ".\n" << logofs_flush;
+ #endif
+
+ delete [] unpackState_[resource] -> colormap -> data;
+
+ unpackState_[resource] -> colormap -> data = NULL;
+ unpackState_[resource] -> colormap -> entries = 0;
+
+ goto handleColormapEnd;
+ }
+ }
+ else
+ {
+ memcpy((unsigned char *) unpackState_[resource] ->
+ colormap -> data, buffer + 16, unpacked);
+ }
+
+ unpackState_[resource] -> colormap -> entries = unpacked >> 2;
+
+ #if defined(DEBUG) && defined(DUMP)
+
+ *logofs << "handleColormap: Dumping colormap entries:\n"
+ << logofs_flush;
+
+ const unsigned char *p = (const unsigned char *) unpackState_[resource] -> colormap -> data;
+
+ for (unsigned int i = 0; i < unpackState_[resource] ->
+ colormap -> entries; i++)
+ {
+ *logofs << "handleColormap: [" << i << "] ["
+ << (void *) ((int) p[i]) << "].\n"
+ << logofs_flush;
+ }
+
+ #endif
+ } // end anonymous block
+
+handleColormapEnd:
+
+ handleCleanAndNullRequest(opcode, buffer, size);
+
+ return 1;
+}
+
+int ServerChannel::handleAlpha(unsigned char &opcode, unsigned char *&buffer,
+ unsigned int &size)
+{
+ int resource = *(buffer + 1);
+
+ #ifdef TEST
+ *logofs << "handleAlpha: Setting new unpack alpha "
+ << "for resource " << resource << ".\n"
+ << logofs_flush;
+ #endif
+
+ handleUnpackStateInit(resource);
+
+ handleUnpackAllocAlpha(resource);
+
+ //
+ // New protocol versions send the alpha
+ // data in compressed form.
+ //
+
+ //
+ // Since ProtoStep7 (#issue 108)
+ //
+
+ { // An anonymous block is used here to limit the scope of local variables
+ unsigned int packed = GetULONG(buffer + 8, bigEndian_);
+ unsigned int unpacked = GetULONG(buffer + 12, bigEndian_);
+
+ validateSize("alpha", packed, unpacked, 16, size);
+
+ if (unpackState_[resource] -> alpha -> entries != unpacked &&
+ unpackState_[resource] -> alpha -> data != NULL)
+ {
+ #ifdef TEST
+ *logofs << "handleAlpha: Freeing previously allocated "
+ << "unpack alpha data.\n" << logofs_flush;
+ #endif
+
+ delete [] unpackState_[resource] -> alpha -> data;
+
+ unpackState_[resource] -> alpha -> data = NULL;
+ unpackState_[resource] -> alpha -> entries = 0;
+ }
+
+ #ifdef TEST
+ *logofs << "handleAlpha: Setting " << unpacked
+ << " bytes of unpack alpha data for resource "
+ << resource << ".\n" << logofs_flush;
+ #endif
+
+ if (unpackState_[resource] -> alpha -> data == NULL)
+ {
+ unpackState_[resource] -> alpha -> data = new unsigned char[unpacked];
+
+ if (unpackState_[resource] -> alpha -> data == NULL)
+ {
+ #ifdef PANIC
+ *logofs << "handleAlpha: PANIC! Can't allocate "
+ << unpacked << " entries for unpack alpha data "
+ << "for FD#" << fd_ << ".\n" << logofs_flush;
+ #endif
+
+ goto handleAlphaEnd;
+ }
+
+ #ifdef DEBUG
+ *logofs << "handleAlpha: Size of new alpha data is "
+ << unpacked << ".\n" << logofs_flush;
+ #endif
+ }
+
+ unsigned int method = *(buffer + 4);
+
+ if (method == PACK_ALPHA)
+ {
+ if (UnpackAlpha(method, buffer + 16, packed,
+ unpackState_[resource] -> alpha ->
+ data, unpacked) < 0)
+ {
+ #ifdef PANIC
+ *logofs << "handleAlpha: PANIC! Can't unpack " << packed
+ << " bytes to " << unpacked << " entries for FD#"
+ << fd_ << ".\n" << logofs_flush;
+ #endif
+
+ delete [] unpackState_[resource] -> alpha -> data;
+
+ unpackState_[resource] -> alpha -> data = NULL;
+ unpackState_[resource] -> alpha -> entries = 0;
+
+ goto handleAlphaEnd;
+ }
+ }
+ else
+ {
+ memcpy((unsigned char *) unpackState_[resource] ->
+ alpha -> data, buffer + 16, unpacked);
+ }
+
+ unpackState_[resource] -> alpha -> entries = unpacked;
+
+ #if defined(DEBUG) && defined(DUMP)
+
+ *logofs << "handleAlpha: Dumping alpha entries:\n"
+ << logofs_flush;
+
+ const unsigned char *p = unpackState_[resource] -> alpha -> data;
+
+ for (unsigned int i = 0; i < unpackState_[resource] ->
+ alpha -> entries; i++)
+ {
+ *logofs << "handleAlpha: [" << i << "] ["
+ << (void *) ((int) p[i]) << "].\n"
+ << logofs_flush;
+ }
+
+ #endif
+ } //end anonymous block
+
+handleAlphaEnd:
+
+ handleCleanAndNullRequest(opcode, buffer, size);
+
+ return 1;
+}
+
+int ServerChannel::handleImage(unsigned char &opcode, unsigned char *&buffer,
+ unsigned int &size)
+{
+ int result = 1;
+
+ //
+ // Save the original opcode together with
+ // the image state so we can later find if
+ // this is a plain or a packed image when
+ // moving data to the shared memory area.
+ //
+
+ handleImageStateAlloc(opcode);
+
+ if (opcode == opcodeStore_ -> putPackedImage)
+ {
+ //
+ // Unpack the image and put a X_PutImage in a
+ // new buffer. Save the expected output size,
+ // so, in the case of a decoding error we can
+ // still update the statistics.
+ //
+
+ int length = GetULONG(buffer + 20, bigEndian_);
+
+ #ifdef TEST
+ *logofs << "handleImage: Sending image for FD#" << fd_
+ << " due to OPCODE#" << (unsigned int) opcode << " with "
+ << GetULONG(buffer + 16, bigEndian_) << " bytes packed "
+ << "and " << GetULONG(buffer + 20, bigEndian_)
+ << " bytes unpacked.\n" << logofs_flush;
+ #endif
+
+ statistics -> addPackedBytesIn(size);
+
+ result = handleUnpack(opcode, buffer, size);
+
+ if (result < 0)
+ {
+ //
+ // Recover from the error. Send a X_NoOperation
+ // to keep the sequence counter in sync with
+ // the remote peer.
+ //
+
+ size = 4;
+ buffer = writeBuffer_.addMessage(size);
+
+ *buffer = X_NoOperation;
+
+ PutUINT(size >> 2, buffer + 2, bigEndian_);
+
+ #ifdef PANIC
+ *logofs << "handleImage: PANIC! Sending X_NoOperation for FD#"
+ << fd_ << " to recover from failed unpack.\n"
+ << logofs_flush;
+ #endif
+
+ //
+ // Set the output length to reflect the amount of
+ // data that would have been produced by unpacking
+ // the image. This is advisable to keep the count-
+ // ers in sync with those at remote proxy. Setting
+ // the size here doesn't have any effect on the
+ // size of data sent to the X server as the actual
+ // size will be taken from the content of the write
+ // buffer.
+ //
+
+ size = length;
+ }
+
+ statistics -> addPackedBytesOut(size);
+
+ //
+ // Refrain the write loop from putting
+ // opcode and size in the output buffer.
+ //
+
+ opcode = 0;
+ }
+
+ //
+ // Now image is unpacked as a X_PutImage
+ // in write buffer. Check if we can send
+ // the image using the MIT-SHM extension.
+ //
+
+ if (result > 0)
+ {
+ result = handleShmem(opcode, buffer, size);
+
+ //
+ // We already put opcode and size in
+ // the resulting buffer.
+ //
+
+ if (result > 0)
+ {
+ opcode = 0;
+ }
+ }
+
+ return 1;
+}
+
+int ServerChannel::handleMotion(EncodeBuffer &encodeBuffer)
+{
+ #if defined(TEST) || defined(INFO)
+
+ if (lastMotion_[0] == '\0')
+ {
+ *logofs << "handleMotion: PANIC! No motion events to send "
+ << "for FD#" << fd_ << ".\n" << logofs_flush;
+
+ HandleCleanup();
+ }
+
+ #endif
+
+ #if defined(TEST) || defined(INFO)
+ *logofs << "handleMotion: Sending motion events for FD#"
+ << fd_ << " at " << strMsTimestamp() << ".\n"
+ << logofs_flush;
+ #endif
+
+ //
+ // Replicate code from read loop. When have
+ // time and wish, try to split everything
+ // in functions.
+ //
+
+ if (proxy -> handleAsyncSwitch(fd_) < 0)
+ {
+ return -1;
+ }
+
+ const unsigned char *buffer = lastMotion_;
+ unsigned char opcode = *lastMotion_;
+ unsigned int size = 32;
+
+ if (GetUINT(buffer + 2, bigEndian_) < serverSequence_)
+ {
+ PutUINT(serverSequence_, (unsigned char *) buffer + 2, bigEndian_);
+ }
+
+ encodeBuffer.encodeOpcodeValue(opcode, serverCache_ -> opcodeCache);
+
+ unsigned int sequenceNum = GetUINT(buffer + 2, bigEndian_);
+
+ unsigned int sequenceDiff = sequenceNum - serverSequence_;
+
+ serverSequence_ = sequenceNum;
+
+ #ifdef DEBUG
+ *logofs << "handleMotion: Last server sequence number for FD#"
+ << fd_ << " is " << serverSequence_ << " with "
+ << "difference " << sequenceDiff << ".\n"
+ << logofs_flush;
+ #endif
+
+ encodeBuffer.encodeCachedValue(sequenceDiff, 16,
+ serverCache_ -> eventSequenceCache, 7);
+
+ //
+ // If we fast encoded the message
+ // then skip the rest.
+ //
+
+ if (control -> LocalDeltaCompression == 0)
+ {
+ int result = handleFastReadEvent(encodeBuffer, opcode,
+ buffer, size);
+
+ #ifdef DEBUG
+ *logofs << "handleMotion: Sent saved motion event for FD#"
+ << fd_ << ".\n" << logofs_flush;
+ #endif
+
+ lastMotion_[0] = '\0';
+
+ #ifdef DEBUG
+ *logofs << "handleMotion: Reset last motion event for FD#"
+ << fd_ << ".\n" << logofs_flush;
+ #endif
+
+ if (result < 0)
+ {
+ return -1;
+ }
+ else if (result > 0)
+ {
+ return 1;
+ }
+ }
+
+ //
+ // This should be just the part specific
+ // for motion events but is currently a
+ // copy-paste of code from the read loop.
+ //
+
+ unsigned char detail = buffer[1];
+ if (*buffer == MotionNotify)
+ encodeBuffer.encodeBoolValue((unsigned int) detail);
+ else if ((*buffer == EnterNotify) || (*buffer == LeaveNotify))
+ encodeBuffer.encodeValue((unsigned int) detail, 3);
+ else if (*buffer == KeyRelease)
+ {
+ if (detail == serverCache_ -> keyPressLastKey)
+ encodeBuffer.encodeBoolValue(1);
+ else
+ {
+ encodeBuffer.encodeBoolValue(0);
+ encodeBuffer.encodeValue((unsigned int) detail, 8);
+ }
+ }
+ else if ((*buffer == ButtonPress) || (*buffer == ButtonRelease))
+ encodeBuffer.encodeCachedValue(detail, 8,
+ serverCache_ -> buttonCache);
+ else
+ encodeBuffer.encodeValue((unsigned int) detail, 8);
+ unsigned int timestamp = GetULONG(buffer + 4, bigEndian_);
+ unsigned int timestampDiff = timestamp - serverCache_ -> lastTimestamp;
+ serverCache_ -> lastTimestamp = timestamp;
+ encodeBuffer.encodeCachedValue(timestampDiff, 32,
+ serverCache_ -> motionNotifyTimestampCache, 9);
+ int skipRest = 0;
+ if (*buffer == KeyRelease)
+ {
+ skipRest = 1;
+ for (unsigned int i = 8; i < 31; i++)
+ {
+ if (buffer[i] != serverCache_ -> keyPressCache[i - 8])
+ {
+ skipRest = 0;
+ break;
+ }
+ }
+ encodeBuffer.encodeBoolValue(skipRest);
+ }
+ if (!skipRest)
+ {
+ const unsigned char *nextSrc = buffer + 8;
+ for (unsigned int i = 0; i < 3; i++)
+ {
+ encodeBuffer.encodeCachedValue(GetULONG(nextSrc, bigEndian_), 29,
+ *serverCache_ -> motionNotifyWindowCache[i], 6);
+ nextSrc += 4;
+ }
+ unsigned int rootX = GetUINT(buffer + 20, bigEndian_);
+ unsigned int rootY = GetUINT(buffer + 22, bigEndian_);
+ unsigned int eventX = GetUINT(buffer + 24, bigEndian_);
+ unsigned int eventY = GetUINT(buffer + 26, bigEndian_);
+ eventX -= rootX;
+ eventY -= rootY;
+ encodeBuffer.encodeCachedValue(rootX -
+ serverCache_ -> motionNotifyLastRootX, 16,
+ serverCache_ -> motionNotifyRootXCache, 6);
+ serverCache_ -> motionNotifyLastRootX = rootX;
+ encodeBuffer.encodeCachedValue(rootY -
+ serverCache_ -> motionNotifyLastRootY, 16,
+ serverCache_ -> motionNotifyRootYCache, 6);
+ serverCache_ -> motionNotifyLastRootY = rootY;
+ encodeBuffer.encodeCachedValue(eventX, 16,
+ serverCache_ -> motionNotifyEventXCache, 6);
+ encodeBuffer.encodeCachedValue(eventY, 16,
+ serverCache_ -> motionNotifyEventYCache, 6);
+ encodeBuffer.encodeCachedValue(GetUINT(buffer + 28, bigEndian_),
+ 16, serverCache_ -> motionNotifyStateCache);
+ if ((*buffer == EnterNotify) || (*buffer == LeaveNotify))
+ encodeBuffer.encodeValue((unsigned int) buffer[30], 2);
+ else
+ encodeBuffer.encodeBoolValue((unsigned int) buffer[30]);
+ if ((*buffer == EnterNotify) || (*buffer == LeaveNotify))
+ encodeBuffer.encodeValue((unsigned int) buffer[31], 2);
+ else if (*buffer == KeyPress)
+ {
+ serverCache_ -> keyPressLastKey = detail;
+ for (unsigned int i = 8; i < 31; i++)
+ {
+ serverCache_ -> keyPressCache[i - 8] = buffer[i];
+ }
+ }
+ }
+
+ //
+ // Print info about achieved compression
+ // and update the statistics.
+ //
+
+ int bits = encodeBuffer.diffBits();
+
+ #if defined(TEST) || defined(OPCODES)
+ *logofs << "handleMotion: Handled event OPCODE#" << (unsigned int) buffer[0]
+ << " for FD#" << fd_ << " sequence " << sequenceNum << ". "
+ << size << " bytes in, " << bits << " bits (" << ((float) bits) / 8
+ << " bytes) out.\n" << logofs_flush;
+ #endif
+
+ statistics -> addEventBits(*buffer, size << 3, bits);
+
+ #ifdef DEBUG
+ *logofs << "handleMotion: Sent saved motion event for FD#"
+ << fd_ << ".\n" << logofs_flush;
+ #endif
+
+ lastMotion_[0] = '\0';
+
+ #ifdef DEBUG
+ *logofs << "handleMotion: Reset last motion event for FD#"
+ << fd_ << ".\n" << logofs_flush;
+ #endif
+
+ return 1;
+}
+
+int ServerChannel::handleConfiguration()
+{
+ #ifdef TEST
+ *logofs << "ServerChannel: Setting new buffer parameters "
+ << "for FD#" << fd_ << ".\n" << logofs_flush;
+ #endif
+
+ readBuffer_.setSize(control -> ServerInitialReadSize,
+ control -> ServerMaximumBufferSize);
+
+ writeBuffer_.setSize(control -> TransportXBufferSize,
+ control -> TransportXBufferThreshold,
+ control -> TransportMaximumBufferSize);
+
+ transport_ -> setSize(control -> TransportXBufferSize,
+ control -> TransportXBufferThreshold,
+ control -> TransportMaximumBufferSize);
+ return 1;
+}
+
+int ServerChannel::handleFinish()
+{
+ #ifdef TEST
+ *logofs << "ServerChannel: Finishing connection for FD#"
+ << fd_ << ".\n" << logofs_flush;
+ #endif
+
+ congestion_ = 0;
+ priority_ = 0;
+
+ finish_ = 1;
+
+ //
+ // Reset the motion event.
+ //
+
+ lastMotion_[0] = '\0';
+
+ transport_ -> fullReset();
+
+ return 1;
+}
+
+int ServerChannel::handleAsyncEvents()
+{
+ //
+ // Encode more events while decoding the
+ // proxy messages.
+ //
+
+ if (transport_ -> readable() > 0)
+ {
+ #if defined(TEST) || defined(INFO)
+ *logofs << "handleAsyncEvents: WARNING! Encoding events "
+ << "for FD#" << fd_ << " at " << strMsTimestamp()
+ << ".\n" << logofs_flush;
+ #endif
+
+ #if defined(TEST) || defined(INFO)
+
+ T_timestamp startTs = getTimestamp();
+
+ #endif
+
+ if (proxy -> handleAsyncRead(fd_) < 0)
+ {
+ return -1;
+ }
+
+ #if defined(TEST) || defined(INFO)
+ *logofs << "handleAsyncEvents: Spent " << diffTimestamp(startTs,
+ getTimestamp()) << " Ms handling events for FD#"
+ << fd_ << ".\n" << logofs_flush;
+ #endif
+
+ return 1;
+ }
+
+ return 0;
+}
+
+int ServerChannel::handleUnpack(unsigned char &opcode, unsigned char *&buffer,
+ unsigned int &size)
+{
+ int resource = *(buffer + 1);
+
+ #ifdef DEBUG
+ *logofs << "handleUnpack: Unpacking image for resource " << resource
+ << " with method " << (unsigned int) *(buffer + 12)
+ << ".\n" << logofs_flush;
+ #endif
+
+ handleUnpackStateInit(resource);
+
+ T_geometry *geometryState = unpackState_[resource] -> geometry;
+ T_colormap *colormapState = unpackState_[resource] -> colormap;
+ T_alpha *alphaState = unpackState_[resource] -> alpha;
+
+ if (geometryState == NULL)
+ {
+ #ifdef PANIC
+ *logofs << "handleUnpack: PANIC! Missing geometry unpacking "
+ << "image for resource " << resource << ".\n"
+ << logofs_flush;
+ #endif
+
+ cerr << "Error" << ": Missing geometry unpacking "
+ << "image for resource " << resource << ".\n";
+
+ return -1;
+ }
+
+ //
+ // Get the image data from the buffer.
+ //
+
+ imageState_ -> drawable = GetULONG(buffer + 4, bigEndian_);
+ imageState_ -> gcontext = GetULONG(buffer + 8, bigEndian_);
+
+ imageState_ -> method = *(buffer + 12);
+
+ imageState_ -> format = *(buffer + 13);
+ imageState_ -> srcDepth = *(buffer + 14);
+ imageState_ -> dstDepth = *(buffer + 15);
+
+ imageState_ -> srcLength = GetULONG(buffer + 16, bigEndian_);
+ imageState_ -> dstLength = GetULONG(buffer + 20, bigEndian_);
+
+ imageState_ -> srcX = GetUINT(buffer + 24, bigEndian_);
+ imageState_ -> srcY = GetUINT(buffer + 26, bigEndian_);
+ imageState_ -> srcWidth = GetUINT(buffer + 28, bigEndian_);
+ imageState_ -> srcHeight = GetUINT(buffer + 30, bigEndian_);
+
+ imageState_ -> dstX = GetUINT(buffer + 32, bigEndian_);
+ imageState_ -> dstY = GetUINT(buffer + 34, bigEndian_);
+ imageState_ -> dstWidth = GetUINT(buffer + 36, bigEndian_);
+ imageState_ -> dstHeight = GetUINT(buffer + 38, bigEndian_);
+
+ #ifdef TEST
+ *logofs << "handleUnpack: Source X is " << imageState_ -> srcX
+ << " Y is " << imageState_ -> srcY << " width is "
+ << imageState_ -> srcWidth << " height is "
+ << imageState_ -> srcHeight << ".\n"
+ << logofs_flush;
+ #endif
+
+ #ifdef TEST
+ *logofs << "handleUnpack: Destination X is " << imageState_ -> dstX
+ << " Y is " << imageState_ -> dstY << " width is "
+ << imageState_ -> dstWidth << " height is "
+ << imageState_ -> dstHeight << ".\n"
+ << logofs_flush;
+ #endif
+
+ if (imageState_ -> srcX != 0 || imageState_ -> srcY != 0)
+ {
+ #ifdef PANIC
+ *logofs << "handleUnpack: PANIC! Unsupported source coordinates "
+ << "in unpack request.\n" << logofs_flush;
+ #endif
+
+ return -1;
+ }
+ else if (imageState_ -> method == PACK_COLORMAP_256_COLORS &&
+ (colormapState == NULL || colormapState -> data == NULL))
+ {
+ #ifdef PANIC
+ *logofs << "handleUnpack: PANIC! Cannot find any unpack colormap.\n"
+ << logofs_flush;
+ #endif
+
+ return -1;
+ }
+
+ //
+ // Field srcLength carries size of image data in
+ // packed format. Field dstLength is size of the
+ // image in the original X bitmap format.
+ //
+
+ unsigned int srcDataOffset = 40;
+
+ unsigned int srcSize = imageState_ -> srcLength;
+
+ unsigned int removeSize = size;
+
+ unsigned char *srcData = buffer + srcDataOffset;
+
+ //
+ // Get source and destination bits per pixel.
+ //
+
+ int srcBitsPerPixel = MethodBitsPerPixel(imageState_ -> method);
+
+ if (srcBitsPerPixel <= 0)
+ {
+ #ifdef PANIC
+ *logofs << "handleUnpack: PANIC! Can't identify source "
+ << "bits per pixel for method " << (unsigned int)
+ imageState_ -> method << ".\n" << logofs_flush;
+ #endif
+
+ cerr << "Error" << ": Can't identify source bits "
+ << "per pixel for method " << (unsigned int)
+ imageState_ -> method << ".\n";
+
+ writeBuffer_.removeMessage(removeSize);
+
+ return -1;
+ }
+
+ #ifdef TEST
+ *logofs << "handleUnpack: Source bits per pixel are "
+ << srcBitsPerPixel << " source data size is "
+ << srcSize << ".\n" << logofs_flush;
+ #endif
+
+ int dstBitsPerPixel = UnpackBitsPerPixel(geometryState, imageState_ -> dstDepth);
+
+ if (dstBitsPerPixel <= 0)
+ {
+ #ifdef PANIC
+ *logofs << "handleUnpack: PANIC! Can't identify "
+ << "destination bits per pixel for depth "
+ << (unsigned int) imageState_ -> dstDepth
+ << ".\n" << logofs_flush;
+ #endif
+
+ cerr << "Error" << ": Can't identify "
+ << "destination bits per pixel for depth "
+ << (unsigned int) imageState_ -> dstDepth
+ << ".\n";
+
+ writeBuffer_.removeMessage(removeSize);
+
+ return -1;
+ }
+
+ //
+ // Destination is a PutImage request.
+ //
+
+ unsigned int dstDataOffset = 24;
+
+ //
+ // Output buffer size must match the number of input
+ // pixels multiplied by the number of bytes per pixel
+ // of current geometry.
+ //
+
+ size = (RoundUp4(imageState_ -> dstWidth * dstBitsPerPixel / 8) *
+ imageState_ -> dstHeight) + dstDataOffset;
+
+ #ifdef TEST
+ *logofs << "handleUnpack: Destination bits per pixel are "
+ << dstBitsPerPixel << " destination data size is "
+ << size - dstDataOffset << ".\n" << logofs_flush;
+ #endif
+
+ unsigned int dstSize = size - dstDataOffset;
+
+ imageState_ -> dstLines = imageState_ -> dstHeight;
+
+ unsigned char *dstData;
+
+ //
+ // Size of the final output buffer had to be stored
+ // in the offset field of XImage/NXPackedImage.
+ //
+
+ #ifdef WARNING
+
+ if (dstSize != imageState_ -> dstLength)
+ {
+ *logofs << "handleUnpack: WARNING! Destination size mismatch "
+ << "with reported " << imageState_ -> dstLength
+ << " and actual " << dstSize << ".\n"
+ << logofs_flush;
+ }
+
+ #endif
+
+ //
+ // The decoding algorithm has put the packed image
+ // in the plain write buffer. Let's use the scratch
+ // buffer to uncompress the image.
+ //
+
+ buffer = writeBuffer_.addScratchMessage(size);
+
+ dstData = buffer + dstDataOffset;
+
+ //
+ // Unpack image into the buffer.
+ //
+
+ *buffer = (unsigned char) X_PutImage;
+
+ *(buffer + 1) = imageState_ -> format;
+
+ PutUINT(size >> 2, buffer + 2, bigEndian_);
+
+ PutULONG(imageState_ -> drawable, buffer + 4, bigEndian_);
+ PutULONG(imageState_ -> gcontext, buffer + 8, bigEndian_);
+
+ PutUINT(imageState_ -> dstWidth, buffer + 12, bigEndian_);
+ PutUINT(imageState_ -> dstLines, buffer + 14, bigEndian_);
+
+ PutUINT(imageState_ -> dstX, buffer + 16, bigEndian_);
+ PutUINT(imageState_ -> dstY, buffer + 18, bigEndian_);
+
+ *(buffer + 20) = 0;
+ *(buffer + 21) = imageState_ -> dstDepth;
+
+ #ifdef TEST
+ *logofs << "handleUnpack: Write buffer size is "
+ << writeBuffer_.getLength() << " scratch size is "
+ << writeBuffer_.getScratchLength() << ".\n"
+ << logofs_flush;
+ #endif
+
+ int result = 0;
+
+ switch (imageState_ -> method)
+ {
+ case PACK_JPEG_8_COLORS:
+ case PACK_JPEG_64_COLORS:
+ case PACK_JPEG_256_COLORS:
+ case PACK_JPEG_512_COLORS:
+ case PACK_JPEG_4K_COLORS:
+ case PACK_JPEG_32K_COLORS:
+ case PACK_JPEG_64K_COLORS:
+ case PACK_JPEG_256K_COLORS:
+ case PACK_JPEG_2M_COLORS:
+ case PACK_JPEG_16M_COLORS:
+ {
+ result = UnpackJpeg(geometryState, imageState_ -> method, srcData,
+ srcSize, dstBitsPerPixel, imageState_ -> dstWidth,
+ imageState_ -> dstHeight, dstData, dstSize);
+ break;
+ }
+ case PACK_PNG_8_COLORS:
+ case PACK_PNG_64_COLORS:
+ case PACK_PNG_256_COLORS:
+ case PACK_PNG_512_COLORS:
+ case PACK_PNG_4K_COLORS:
+ case PACK_PNG_32K_COLORS:
+ case PACK_PNG_64K_COLORS:
+ case PACK_PNG_256K_COLORS:
+ case PACK_PNG_2M_COLORS:
+ case PACK_PNG_16M_COLORS:
+ {
+ result = UnpackPng(geometryState, imageState_ -> method, srcData,
+ srcSize, dstBitsPerPixel, imageState_ -> dstWidth,
+ imageState_ -> dstHeight, dstData, dstSize);
+ break;
+ }
+ case PACK_RGB_16M_COLORS:
+ {
+ result = UnpackRgb(geometryState, imageState_ -> method, srcData,
+ srcSize, dstBitsPerPixel, imageState_ -> dstWidth,
+ imageState_ -> dstHeight, dstData, dstSize);
+ break;
+ }
+ case PACK_RLE_16M_COLORS:
+ {
+ result = UnpackRle(geometryState, imageState_ -> method, srcData,
+ srcSize, dstBitsPerPixel, imageState_ -> dstWidth,
+ imageState_ -> dstHeight, dstData, dstSize);
+ break;
+ }
+ case PACK_BITMAP_16M_COLORS:
+ {
+ result = UnpackBitmap(geometryState, imageState_ -> method, srcData,
+ srcSize, dstBitsPerPixel, imageState_ -> dstWidth,
+ imageState_ -> dstHeight, dstData, dstSize);
+ break;
+ }
+ case PACK_COLORMAP_256_COLORS:
+ {
+ result = Unpack8(geometryState, colormapState, srcBitsPerPixel,
+ imageState_ -> srcWidth, imageState_ -> srcHeight, srcData,
+ srcSize, dstBitsPerPixel, imageState_ -> dstWidth,
+ imageState_ -> dstHeight, dstData, dstSize);
+
+ break;
+ }
+ default:
+ {
+ const T_colormask *colorMask = MethodColorMask(imageState_ -> method);
+
+ switch (imageState_ -> method)
+ {
+ case PACK_MASKED_8_COLORS:
+ case PACK_MASKED_64_COLORS:
+ case PACK_MASKED_256_COLORS:
+ {
+ result = Unpack8(geometryState, colorMask, imageState_ -> srcDepth,
+ imageState_ -> srcWidth, imageState_ -> srcHeight,
+ srcData, srcSize, imageState_ -> dstDepth,
+ imageState_ -> dstWidth, imageState_ -> dstHeight,
+ dstData, dstSize);
+ break;
+ }
+ case PACK_MASKED_512_COLORS:
+ case PACK_MASKED_4K_COLORS:
+ case PACK_MASKED_32K_COLORS:
+ case PACK_MASKED_64K_COLORS:
+ {
+ result = Unpack16(geometryState, colorMask, imageState_ -> srcDepth,
+ imageState_ -> srcWidth, imageState_ -> srcHeight,
+ srcData, srcSize, imageState_ -> dstDepth,
+ imageState_ -> dstWidth, imageState_ -> dstHeight,
+ dstData, dstSize);
+ break;
+ }
+ case PACK_MASKED_256K_COLORS:
+ case PACK_MASKED_2M_COLORS:
+ case PACK_MASKED_16M_COLORS:
+ {
+ result = Unpack24(geometryState, colorMask, imageState_ -> srcDepth,
+ imageState_ -> srcWidth, imageState_ -> srcHeight,
+ srcData, srcSize, imageState_ -> dstDepth,
+ imageState_ -> dstWidth, imageState_ -> dstHeight,
+ dstData, dstSize);
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ }
+ }
+
+ writeBuffer_.removeMessage(removeSize);
+
+ if (result <= 0)
+ {
+ #ifdef PANIC
+ *logofs << "handleUnpack: PANIC! Failed to unpack image "
+ << "with method '" << (unsigned int) imageState_ -> method
+ << "'.\n" << logofs_flush;
+ #endif
+
+ cerr << "Warning" << ": Failed to unpack image "
+ << "with method '" << (unsigned int) imageState_ -> method
+ << "'.\n";
+
+ //
+ // TODO: We should mark the image somehow,
+ // and force the remote to remove it from
+ // the cache.
+ //
+
+ writeBuffer_.removeScratchMessage();
+
+ return -1;
+ }
+
+ //
+ // Alpha channel is used only on some 32 bits pixmaps
+ // and only if render extension is in use. Presently
+ // we don't have an efficient way to know in advance
+ // if mask must be applied or not to the image. If an
+ // alpha channel is set, the function will check if
+ // the size of the alpha data matches the size of the
+ // image. In the worst case we'll create an useless
+ // alpha plane for a pixmap that doesn't need it.
+ //
+
+ if (alphaState != NULL && alphaState -> data != NULL &&
+ imageState_ -> dstDepth == 32)
+ {
+ UnpackAlpha(alphaState, dstData, dstSize, imageByteOrder_);
+ }
+
+ return 1;
+}
+
+int ServerChannel::handleAuthorization(unsigned char *buffer)
+{
+ //
+ // At the present moment we don't support more than
+ // a single display for each proxy, so authorization
+ // data is shared among all the channels.
+ //
+ // Use the following code to simulate authentication
+ // failures on a LSB machine:
+ //
+ // memcpy(buffer + 12 + (((buffer[6] + 256 *
+ // buffer[7]) + 3) & ~3), "1234567890123456", 16);
+ //
+
+ if (auth == NULL)
+ {
+ #if defined(TEST) || defined(INFO)
+ *logofs << "handleAuthorization: Forwarding the real cookie "
+ << "for FD#" << fd_ << ".\n" << logofs_flush;
+ #endif
+
+ return 0;
+ }
+ else if (auth -> checkCookie(buffer) == 1)
+ {
+ #if defined(TEST) || defined(INFO)
+ *logofs << "handleAuthorization: Matched the fake cookie "
+ << "for FD#" << fd_ << ".\n" << logofs_flush;
+ #endif
+
+ return 1;
+ }
+ else
+ {
+ #if defined(TEST) || defined(INFO)
+ *logofs << "handleAuthorization: WARNING! Failed to match "
+ << "the fake cookie for FD#" << fd_ << ".\n"
+ << logofs_flush;
+ #endif
+
+ return -1;
+ }
+}
+
+int ServerChannel::handleAuthorization(const unsigned char *buffer, int size)
+{
+ //
+ // Check the X server's response and, in the case of
+ // an error, print the textual information reported
+ // by the server.
+ //
+
+ if (*buffer != 1)
+ {
+ const char *reason = NULL;
+
+ //
+ // At the moment we don't take into account the end-
+ // ianess of the reply. This should work in any case
+ // because we simply try to match a few well-known
+ // error strings.
+ //
+
+ if (size >= INVALID_COOKIE_SIZE + 8 &&
+ memcmp(buffer + 8, INVALID_COOKIE_DATA,
+ INVALID_COOKIE_SIZE) == 0)
+ {
+ reason = INVALID_COOKIE_DATA;
+ }
+ else if (size >= NO_AUTH_PROTO_SIZE + 8 &&
+ memcmp(buffer + 8, NO_AUTH_PROTO_DATA,
+ NO_AUTH_PROTO_SIZE) == 0)
+ {
+ reason = NO_AUTH_PROTO_DATA;
+ }
+ else
+ {
+ reason = "Unknown";
+ }
+
+ #ifdef WARNING
+ *logofs << "handleAuthorization: WARNING! X connection failed "
+ << "with error '" << reason << "' on FD#" << fd_
+ << ".\n" << logofs_flush;
+ #endif
+
+ cerr << "Warning" << ": X connection failed "
+ << "with error '" << reason << "'.\n";
+ }
+ #if defined(TEST) || defined(INFO)
+ else
+ {
+ *logofs << "handleAuthorization: X connection successful "
+ << "on FD#" << fd_ << ".\n" << logofs_flush;
+ }
+ #endif
+
+ return 1;
+}
+
+//
+// Use a simple encoding. Need to handle the image
+// requests in the usual way and the X_ListExtensions
+// and X_QueryExtension to hide MIT-SHM and RENDER
+// in the reply.
+//
+
+int ServerChannel::handleFastWriteRequest(DecodeBuffer &decodeBuffer, unsigned char &opcode,
+ unsigned char *&buffer, unsigned int &size)
+{
+ //
+ // All the NX requests are handled in the
+ // main message loop.
+ //
+
+ //
+ // Since ProtoStep7 (#issue 108)
+ //
+ // The X_PutImage can be handled here only
+ // if a split was not requested.
+ //
+
+ if ((opcode >= X_NXFirstOpcode && opcode <= X_NXLastOpcode) ||
+ (opcode == X_PutImage && splitState_.resource != nothing) ||
+ opcode == X_ListExtensions ||
+ opcode == X_QueryExtension)
+ {
+ return 0;
+ }
+
+ #ifdef DEBUG
+ *logofs << "handleFastWriteRequest: Decoding raw request OPCODE#"
+ << (unsigned int) opcode << " for FD#" << fd_
+ << ".\n" << logofs_flush;
+ #endif
+
+ buffer = writeBuffer_.addMessage(4);
+
+ #ifndef __sun
+
+ unsigned int *next = (unsigned int *) decodeBuffer.decodeMemory(4);
+
+ *((unsigned int *) buffer) = *next;
+
+ #else /* #ifndef __sun */
+
+ memcpy(buffer, decodeBuffer.decodeMemory(4), 4);
+
+ #endif /* #ifndef __sun */
+
+ size = GetUINT(buffer + 2, bigEndian_) << 2;
+
+ if (size < 4)
+ {
+ #ifdef WARNING
+ *logofs << "handleFastWriteRequest: WARNING! Assuming size 4 "
+ << "for suspicious message of size " << size
+ << ".\n" << logofs_flush;
+ #endif
+
+ size = 4;
+ }
+
+ writeBuffer_.registerPointer(&buffer);
+
+ if (writeBuffer_.getAvailable() < size - 4 ||
+ (int) size >= control -> TransportFlushBufferSize)
+ {
+ #ifdef DEBUG
+ *logofs << "handleFastWriteRequest: Using scratch buffer for OPCODE#"
+ << (unsigned int) opcode << " with size " << size << " and "
+ << writeBuffer_.getLength() << " bytes in buffer.\n"
+ << logofs_flush;
+ #endif
+
+ //
+ // The procedure moving data to shared memory
+ // assumes that the full message is stored in
+ // the scratch buffer. We can safely let the
+ // scratch buffer inherit the decode buffer
+ // at the next offset.
+ //
+
+ writeBuffer_.removeMessage(4);
+
+ buffer = writeBuffer_.addScratchMessage(((unsigned char *)
+ decodeBuffer.decodeMemory(size - 4)) - 4, size);
+ }
+ else
+ {
+ writeBuffer_.addMessage(size - 4);
+
+ #ifndef __sun
+
+ if (size <= 32)
+ {
+ next = (unsigned int *) decodeBuffer.decodeMemory(size - 4);
+
+ for (unsigned int i = 4; i < size; i += sizeof(unsigned int))
+ {
+ *((unsigned int *) (buffer + i)) = *next++;
+ }
+ }
+ else
+ {
+ memcpy(buffer + 4, decodeBuffer.decodeMemory(size - 4), size - 4);
+ }
+
+ #else /* #ifndef __sun */
+
+ memcpy(buffer + 4, decodeBuffer.decodeMemory(size - 4), size - 4);
+
+ #endif /* #ifndef __sun */
+ }
+
+ //
+ // Opcode could have been tainted by the client
+ // proxy. Replace the original opcode with the
+ // one sent in the decode buffer.
+ //
+
+ *buffer = opcode;
+
+ writeBuffer_.unregisterPointer();
+
+ if (opcode == X_PutImage)
+ {
+ handleImage(opcode, buffer, size);
+ }
+
+ #if defined(TEST) || defined(OPCODES)
+
+ if (opcode != 0)
+ {
+ *logofs << "handleFastWriteRequest: Handled request "
+ << "OPCODE#" << (unsigned int) opcode << " ("
+ << DumpOpcode(opcode) << ") for FD#" << fd_
+ << " sequence " << clientSequence_ << ". "
+ << size << " bytes out.\n" << logofs_flush;
+ }
+ else
+ {
+ *logofs << "handleFastWriteRequest: Handled image or "
+ << "other request for FD#" << fd_
+ << " sequence " << clientSequence_ << ". "
+ << size << " bytes out.\n" << logofs_flush;
+ }
+
+ #endif
+
+ handleFlush(flush_if_needed);
+
+ return 1;
+}
+
+//
+// Use the simplest encoding except for replies that
+// need to be managed some way.
+//
+
+int ServerChannel::handleFastReadReply(EncodeBuffer &encodeBuffer, const unsigned char &opcode,
+ const unsigned char *&buffer, const unsigned int &size)
+{
+ //
+ // If we pushed a X_GetInputFocus in the sequence
+ // queue this means that the original message was
+ // a NX request for which we have to provide a NX
+ // reply.
+ //
+
+ if ((opcode >= X_NXFirstOpcode &&
+ opcode <= X_NXLastOpcode) ||
+ opcode == X_QueryExtension ||
+ opcode == X_ListExtensions ||
+ opcode == X_GetInputFocus)
+ {
+ return 0;
+ }
+
+ #ifdef DEBUG
+ *logofs << "handleFastReadReply: Encoding raw reply OPCODE#"
+ << (unsigned int) opcode << " for FD#" << fd_
+ << " with size " << size << ".\n"
+ << logofs_flush;
+ #endif
+
+ encodeBuffer.encodeMemory(buffer, size);
+
+ //
+ // Send back the reply as soon
+ // as possible.
+ //
+
+ priority_++;
+
+ int bits = encodeBuffer.diffBits();
+
+ #if defined(TEST) || defined(OPCODES)
+ *logofs << "handleFastReadReply: Handled raw reply OPCODE#"
+ << (unsigned int) opcode << " for FD#" << fd_ << " sequence "
+ << serverSequence_ << ". " << size << " bytes in, "
+ << bits << " bits (" << ((float) bits) / 8
+ << " bytes) out.\n" << logofs_flush;
+ #endif
+
+ statistics -> addReplyBits(opcode, size << 3, bits);
+
+ return 1;
+}
+
+int ServerChannel::handleFastReadEvent(EncodeBuffer &encodeBuffer, const unsigned char &opcode,
+ const unsigned char *&buffer, const unsigned int &size)
+{
+ #ifdef DEBUG
+ *logofs << "handleFastReadEvent: Encoding raw "
+ << (opcode == X_Error ? "error" : "event") << " OPCODE#"
+ << (unsigned int) opcode << " for FD#" << fd_
+ << " with size " << size << ".\n"
+ << logofs_flush;
+ #endif
+
+ encodeBuffer.encodeMemory(buffer, size);
+
+ switch (opcode)
+ {
+ case X_Error:
+ case ButtonPress:
+ case ButtonRelease:
+ case KeyPress:
+ case KeyRelease:
+ {
+ priority_++;
+ }
+ }
+
+ int bits = encodeBuffer.diffBits();
+
+ #if defined(TEST) || defined(OPCODES)
+
+ if (opcode == X_Error)
+ {
+ unsigned char code = *(buffer + 1);
+
+ *logofs << "handleFastReadEvent: Handled error ERR_CODE#"
+ << (unsigned int) code << " for FD#" << fd_;
+
+ *logofs << " RES_ID#" << GetULONG(buffer + 4, bigEndian_);
+
+ *logofs << " MIN_OP#" << GetUINT(buffer + 8, bigEndian_);
+
+ *logofs << " MAJ_OP#" << (unsigned int) *(buffer + 10);
+
+ *logofs << " sequence " << serverSequence_ << ". " << size
+ << " bytes in, " << bits << " bits (" << ((float) bits) / 8
+ << " bytes) out.\n" << logofs_flush;
+ }
+ else
+ {
+ *logofs << "handleFastReadEvent: Handled event OPCODE#"
+ << (unsigned int) *buffer << " for FD#" << fd_
+ << " sequence " << serverSequence_ << ". " << size
+ << " bytes in, " << bits << " bits (" << ((float) bits) / 8
+ << " bytes) out.\n" << logofs_flush;
+ }
+
+ #endif
+
+ statistics -> addEventBits(opcode, size << 3, bits);
+
+ return 1;
+}
+
+void ServerChannel::initCommitQueue()
+{
+ #ifdef TEST
+ *logofs << "initCommitQueue: Resetting the queue of split commits "
+ << "for FD#" << fd_ << ".\n" << logofs_flush;
+ #endif
+
+ for (int i = 0; i < MAX_COMMIT_SEQUENCE_QUEUE; i++)
+ {
+ commitSequenceQueue_[i] = 0;
+ }
+}
+
+void ServerChannel::updateCommitQueue(unsigned short sequence)
+{
+ for (int i = 0; i < MAX_COMMIT_SEQUENCE_QUEUE - 1; i++)
+ {
+ commitSequenceQueue_[i + 1] = commitSequenceQueue_[i];
+ }
+
+ #ifdef TEST
+ *logofs << "updateCommitQueue: Saved " << sequence
+ << " as last sequence number of image to commit.\n"
+ << logofs_flush;
+ #endif
+
+ commitSequenceQueue_[0] = sequence;
+}
+
+int ServerChannel::checkCommitError(unsigned char error, unsigned short sequence,
+ const unsigned char *buffer)
+{
+ //
+ // Check if error is due to an image commit
+ // generated at the end of a split.
+ //
+ // TODO: It should zero the head of the list
+ // when an event comes with a sequence number
+ // greater than the value of the last element
+ // added.
+ //
+
+ for (int i = 0; i < MAX_COMMIT_SEQUENCE_QUEUE &&
+ commitSequenceQueue_[i] != 0; i++)
+ {
+ #ifdef TEST
+ *logofs << "checkCommitError: Checking committed image's "
+ << "sequence number " << commitSequenceQueue_[i]
+ << " with input sequence " << sequence << ".\n"
+ << logofs_flush;
+ #endif
+
+ if (commitSequenceQueue_[i] == sequence)
+ {
+ #ifdef WARNING
+
+ *logofs << "checkCommitError: WARNING! Failed operation for "
+ << "FD#" << fd_ << " with ERR_CODE#"
+ << (unsigned int) *(buffer + 1);
+
+ *logofs << " RES_ID#" << GetULONG(buffer + 4, bigEndian_);
+
+ *logofs << " MIN_OP#" << GetUINT(buffer + 8, bigEndian_);
+
+ *logofs << " MAJ_OP#" << (unsigned int) *(buffer + 10);
+
+ *logofs << " sequence " << sequence << ".\n";
+
+ *logofs << logofs_flush;
+
+ #endif
+
+ cerr << "Warning" << ": Failed commit operation "
+ << "with ERR_CODE#" << (unsigned int) error;
+
+ cerr << " RES_ID#" << GetULONG(buffer + 4, bigEndian_);
+
+ cerr << " MIN_OP#" << GetUINT(buffer + 8, bigEndian_);
+
+ cerr << " MAJ_OP#" << (unsigned int) *(buffer + 10);
+
+ cerr << ".\n";
+
+ #ifdef WARNING
+ *logofs << "checkCommitError: WARNING! Suppressing error on "
+ << "OPCODE#" << (unsigned int) opcodeStore_ -> commitSplit
+ << " for FD#" << fd_ << " with sequence " << sequence
+ << " at position " << i << ".\n" << logofs_flush;
+ #endif
+
+ return 0;
+ }
+ }
+
+ return 0;
+}
+
+//
+// Check if the user pressed the CTRL+ALT+SHIFT+ESC
+// keystroke. At the present moment it uses different
+// keycodes based on the client OS. This should be
+// implemented in a way that is platform independent
+// (that's not an easy task, considered that we don't
+// have access to the higher level X libraries).
+//
+
+int ServerChannel::checkKeyboardEvent(unsigned char event, unsigned short sequence,
+ const unsigned char *buffer)
+{
+ #ifdef TEST
+ *logofs << "checkKeyboardEvent: Checking escape sequence with byte [1] "
+ << (void *) ((unsigned) *(buffer + 1)) << " and bytes [28-29] "
+ << (void *) ((unsigned) GetUINT(buffer + 28, bigEndian_))
+ << " for FD#" << fd_ << ".\n" << logofs_flush;
+ #endif
+
+ #ifdef __APPLE__
+
+ int alert = (*(buffer + 1) == 0x3d &&
+ GetUINT(buffer + 28, bigEndian_) == 0x2005);
+
+ #else
+
+ int alert = (*(buffer + 1) == 0x09 &&
+ ((GetUINT(buffer + 28, bigEndian_) &
+ 0x0d) == 0x0d));
+
+ #endif
+
+ if (alert == 1)
+ {
+ #ifdef PANIC
+ *logofs << "checkKeyboardEvent: PANIC! Received sequence "
+ << "CTRL+ALT+SHIFT+ESC " << "for FD#"<< fd_
+ << ". Showing the abort dialog.\n" << logofs_flush;
+ #endif
+
+ cerr << "Warning" << ": Received sequence CTRL+ALT+SHIFT+ESC. "
+ << "Showing the abort dialog.\n";
+
+ HandleAlert(CLOSE_UNRESPONSIVE_X_SERVER_ALERT, 1);
+ }
+
+ return alert;
+}
+
+//
+// Handle the MIT-SHM initialization
+// messages exchanged with the remote
+// proxy.
+//
+
+int ServerChannel::handleShmemReply(EncodeBuffer &encodeBuffer, const unsigned char opcode,
+ const unsigned int stage, const unsigned char *buffer,
+ const unsigned int size)
+{
+ #ifdef TEST
+ *logofs << "handleShmemReply: Returning shmem reply for "
+ << "stage " << stage << ".\n" << logofs_flush;
+ #endif
+
+ if (opcode == X_QueryExtension)
+ {
+ encodeBuffer.encodeValue(stage, 2);
+
+#ifndef ANDROID
+ shmemState_ -> present = *(buffer + 8);
+#else
+ shmemState_ -> present = 0;
+ cerr << "Info: handleShmemReply: In android no shared memory. Setting present to 0 hardcoded\n";
+#endif
+ shmemState_ -> opcode = *(buffer + 9);
+ shmemState_ -> event = *(buffer + 10);
+ shmemState_ -> error = *(buffer + 11);
+
+ #ifdef TEST
+ *logofs << "handleShmemReply: Extension present is "
+ << shmemState_ -> present << " with base OPCODE#"
+ << (unsigned int) shmemState_ -> opcode << " base event "
+ << (unsigned int) shmemState_ -> event << " base error "
+ << (unsigned int) shmemState_ -> error << ".\n"
+ << logofs_flush;
+ #endif
+ }
+ else if (opcode == X_GetInputFocus)
+ {
+ encodeBuffer.encodeValue(stage, 2);
+
+ encodeBuffer.encodeBoolValue(0);
+
+ if (shmemState_ -> present == 1 &&
+ shmemState_ -> address != NULL &&
+ shmemState_ -> segment > 0 &&
+ shmemState_ -> id > 0)
+ {
+ cerr << "Info" << ": Using shared memory parameters 1/"
+ << (shmemState_ -> size / 1024) << "K.\n";
+
+#ifndef ANDROID
+ shmemState_ -> enabled = 1;
+#else
+ cerr << "Info: handleShmemReply: In android no shared memory. Setting enabled to -1. This should not be displayed\n";
+ shmemState_ -> enabled = -1;
+#endif
+
+ encodeBuffer.encodeBoolValue(1);
+ }
+ else
+ {
+ #ifdef TEST
+ *logofs << "handleShmemReply: WARNING! Not using shared memory "
+ << "support in X server for FD#" << fd_ << ".\n"
+ << logofs_flush;
+ #endif
+
+ cerr << "Info" << ": Using shared memory parameters 0/0K.\n";
+
+ handleShmemStateRemove();
+
+ encodeBuffer.encodeBoolValue(0);
+ }
+ }
+ else
+ {
+ #ifdef PANIC
+ *logofs << "handleShmemReply: PANIC! Conversation error "
+ << "handling shared memory support for FD#"
+ << fd_ << ".\n" << logofs_flush;
+ #endif
+
+ cerr << "Error" << ": Conversation error handling "
+ << "shared memory support.\n";
+
+ return -1;
+ }
+
+ return 1;
+}
+
+int ServerChannel::handleShmemRequest(DecodeBuffer &decodeBuffer, unsigned char &opcode,
+ unsigned char *&buffer, unsigned int &size)
+{
+ //
+ // We need to query and initialize MIT-SHM on
+ // the real X server. To do this we'll need 3
+ // requests. At the end we'll have to encode
+ // the final reply for the X client side.
+ //
+
+ handleShmemStateAlloc();
+
+ unsigned int stage;
+
+ decodeBuffer.decodeValue(stage, 2);
+
+ unsigned int expected = shmemState_ -> stage + 1;
+
+ if (stage != expected || stage > 2)
+ {
+ #ifdef PANIC
+ *logofs << "handleShmemRequest: PANIC! Unexpected stage "
+ << stage << " in handling shared memory "
+ << "support for FD#" << fd_ << ".\n"
+ << logofs_flush;
+ #endif
+
+ cerr << "Error" << ": Unexpected stage "
+ << stage << " in handling shared memory "
+ << "support for FD#" << fd_ << ".\n";
+
+ return -1;
+ }
+
+ switch (stage)
+ {
+ case 0:
+ {
+ unsigned int enableClient;
+ unsigned int enableServer;
+
+ decodeBuffer.decodeBoolValue(enableClient);
+ decodeBuffer.decodeBoolValue(enableServer);
+
+ unsigned int clientSegment;
+ unsigned int serverSegment;
+
+ decodeBuffer.decodeValue(clientSegment, 29, 9);
+ decodeBuffer.decodeValue(serverSegment, 29, 9);
+
+ shmemState_ -> segment = serverSegment;
+
+ #ifdef TEST
+ *logofs << "handleShmemRequest: Size of the shared memory "
+ << "segment will be " << control -> ShmemServerSize
+ << ".\n" << logofs_flush;
+ #endif
+
+ #ifdef TEST
+ *logofs << "handleShmemRequest: Sending X_QueryExtension request "
+ << "for FD#" << fd_ << " due to OPCODE#" << (unsigned int)
+ opcodeStore_ -> getShmemParameters << " in stage "
+ << stage << ".\n" << logofs_flush;
+ #endif
+
+ opcode = X_QueryExtension;
+
+ size = 16;
+ buffer = writeBuffer_.addMessage(size);
+
+ PutUINT(7, buffer + 4, bigEndian_);
+
+ //
+ // Simply make the query fail if shared
+ // memory support is disabled by the
+ // user.
+ //
+#ifndef ANDROID
+ if (control -> ShmemServer == 1 &&
+ control -> ShmemServerSize > 0 &&
+ enableServer == 1)
+ {
+ memcpy(buffer + 8, "MIT-SHM", 7);
+ }
+ else
+ {
+ memcpy(buffer + 8, "NO-MIT-", 7);
+ }
+#else
+ cerr << "Info: handleShmemRequest: In android no shared memory. Returning NO-MIT- answer\n";
+
+ memcpy(buffer + 8, "NO-MIT-", 7);
+#endif
+ sequenceQueue_.push(clientSequence_, opcode,
+ opcodeStore_ -> getShmemParameters, stage);
+
+ //
+ // Save the sequence number so we can
+ // later identify any matching X error
+ // received from server.
+ //
+
+ shmemState_ -> sequence = clientSequence_;
+
+ break;
+ }
+ case 1:
+ {
+ if (shmemState_ -> present == 1)
+ {
+ //
+ // Make the segment read-write for everybody on
+ // Cygwin (to avoid any lack of support or any
+ // performance issue) and on MacOS/X (where the
+ // 0600 mask doesn't seem to work).
+ //
+
+ #if defined(__CYGWIN32__) || defined(__APPLE__)
+
+ int permissions = 0777;
+
+ #else
+
+ int permissions = 0600;
+
+ #endif
+
+ shmemState_ -> size = control -> ShmemServerSize;
+
+#ifndef ANDROID
+ shmemState_ -> id = shmget(IPC_PRIVATE, shmemState_ -> size,
+ IPC_CREAT | permissions);
+#else
+ cerr << "Info: handleShmemReqyest: In android no shared memory (shmget). This message should not be displayed present should never be 1 in android\n";
+ shmemState_ -> id = -1;
+#endif
+ if (shmemState_ -> id >= 0)
+ {
+ #if defined(TEST) || defined(INFO)
+ *logofs << "handleShmemRequest: Allocated shared memory "
+ << "segment of " << shmemState_ -> size
+ << " bytes with id " << shmemState_ -> id
+ << ".\n" << logofs_flush;
+ #endif
+
+
+#ifndef ANDROID
+ shmemState_ -> address = shmat(shmemState_ -> id, 0, 0);
+#else
+ cerr << "Info: handleShmemReqyest: In android no shared memory (shmat). This message should not be displayed. present should never be 1 in android\n";
+ shmemState_ -> address = NULL;
+#endif
+ if (shmemState_ -> address != NULL)
+ {
+ #ifdef TEST
+ *logofs << "handleShmemRequest: Sending X_ShmAttach request "
+ << "for FD#" << fd_ << " due to OPCODE#" << (unsigned int)
+ opcodeStore_ -> getShmemParameters << " in stage "
+ << stage << ".\n" << logofs_flush;
+ #endif
+
+ opcode = shmemState_ -> opcode;
+
+ size = 16;
+ buffer = writeBuffer_.addMessage(size);
+
+ *(buffer + 1) = X_ShmAttach;
+
+ PutULONG(shmemState_ -> segment, buffer + 4, bigEndian_);
+ PutULONG(shmemState_ -> id, buffer + 8, bigEndian_);
+
+ *(buffer + 12) = 1;
+
+ shmemState_ -> sequence = clientSequence_;
+
+ break;
+ }
+ else
+ {
+ #ifdef WARNING
+ *logofs << "handleShmemRequest: WARNING! Can't attach the shared "
+ << "memory segment. Error is " << EGET() << " '"
+ << ESTR() << "'.\n" << logofs_flush;
+ #endif
+
+ cerr << "Warning" << ": Can't attach the shared memory "
+ << "segment. Error is " << EGET() << " '"
+ << ESTR() << "'.\n";
+ }
+ }
+ else
+ {
+ #ifndef __CYGWIN32__
+
+ #ifdef WARNING
+ *logofs << "handleShmemRequest: WARNING! Can't create the shared "
+ << "memory segment. Error is " << EGET() << " '"
+ << ESTR() << "'.\n" << logofs_flush;
+ #endif
+
+ cerr << "Warning" << ": Can't create the shared memory "
+ << "segment. Error is " << EGET() << " '"
+ << ESTR() << "'.\n";
+
+ #else
+
+ #ifdef TEST
+ *logofs << "handleShmemRequest: WARNING! Can't create the shared "
+ << "memory segment. Error is " << EGET() << " '"
+ << ESTR() << "'.\n" << logofs_flush;
+ #endif
+
+ #endif
+ }
+ }
+
+ if (shmemState_ -> present != 0)
+ {
+ #ifdef TEST
+ *logofs << "handleShmemRequest: Resetting shared memory "
+ << "presence flag for FD#" << fd_ << ".\n"
+ << logofs_flush;
+ #endif
+
+ shmemState_ -> present = 0;
+ }
+
+ handleNullRequest(opcode, buffer, size);
+
+ break;
+ }
+ default:
+ {
+ #ifdef TEST
+ *logofs << "handleShmemRequest: Sending X_GetInputFocus request "
+ << "for FD#" << fd_ << " due to OPCODE#" << (unsigned int)
+ opcodeStore_ -> getShmemParameters << " in stage "
+ << stage << ".\n" << logofs_flush;
+ #endif
+
+ opcode = X_GetInputFocus;
+
+ size = 4;
+ buffer = writeBuffer_.addMessage(size);
+
+ sequenceQueue_.push(clientSequence_, opcode,
+ opcodeStore_ -> getShmemParameters, stage);
+ break;
+ }
+ }
+
+ shmemState_ -> stage += 1;
+
+ return 1;
+}
+
+//
+// Handling of MIT-SHM extension has been plugged late in
+// the design, so we have to make some assumptions. Image
+// is a X_PutImage request contained either in the scratch
+// buffer or in the normal write buffer. We need to move
+// the image data to the shared memory segment and replace
+// the X_PutImage request with a X_ShmPutImage.
+//
+
+int ServerChannel::handleShmem(unsigned char &opcode, unsigned char *&buffer,
+ unsigned int &size)
+{
+ if (shmemState_ == NULL || shmemState_ -> enabled != 1)
+ {
+ #ifdef TEST
+
+ if (shmemState_ != NULL)
+ {
+ *logofs << "handleShmem: PANIC! Shared memory "
+ << "state found but support is not enabled "
+ << "for FD#" << fd_ << " in stage "
+ << shmemState_ -> stage << ".\n"
+ << logofs_flush;
+ }
+
+ #endif
+
+ return 0;
+ }
+#ifdef ANDROID
+ cerr << "Info: handleShmem: In android no shared memory. enabled should never be 1. This should not be displayed\n";
+ return 0;
+#endif
+
+ //
+ // Ignore null requests and requests that will not result
+ // in a single X_PutImage. To conform with the other func-
+ // tions, we get the opcode passed as a parameter. It can
+ // be zero if we don't want the write loop to put opcode
+ // and length in the resulting buffer. Anyway we are only
+ // interested in the original opcode of the request, that
+ // is stored in the image state.
+ //
+
+ unsigned char *dstData = buffer + 24;
+ unsigned int dstDataSize = size - 24;
+
+ if (dstDataSize == 0 || dstDataSize >
+ (unsigned int) control -> MaximumRequestSize)
+ {
+ #ifdef TEST
+ *logofs << "handleShmem: Ignoring image with opcode "
+ << (unsigned int) imageState_ -> opcode
+ << " and size " << size << " for FD#" << fd_
+ << ".\n" << logofs_flush;
+ #endif
+
+ return 0;
+ }
+
+ #ifdef TEST
+ *logofs << "handleShmem: Handling image with opcode "
+ << (unsigned int) imageState_ -> opcode
+ << " and size " << size << " for FD#" << fd_
+ << ".\n" << logofs_flush;
+ #endif
+
+ //
+ // Get image data from buffer.
+ //
+
+ if (imageState_ -> opcode == X_PutImage)
+ {
+ //
+ // We still need to get the image's data.
+ //
+
+ imageState_ -> format = *(buffer + 1);
+
+ imageState_ -> drawable = GetULONG(buffer + 4, bigEndian_);
+ imageState_ -> gcontext = GetULONG(buffer + 8, bigEndian_);
+
+ imageState_ -> dstWidth = GetUINT(buffer + 12, bigEndian_);
+ imageState_ -> dstHeight = GetUINT(buffer + 14, bigEndian_);
+
+ imageState_ -> srcX = 0;
+ imageState_ -> srcY = 0;
+
+ imageState_ -> srcWidth = imageState_ -> dstWidth;
+ imageState_ -> srcHeight = imageState_ -> dstHeight;
+
+ imageState_ -> dstX = GetUINT(buffer + 16, bigEndian_);
+ imageState_ -> dstY = GetUINT(buffer + 18, bigEndian_);
+
+ imageState_ -> leftPad = *(buffer + 20);
+ imageState_ -> dstDepth = *(buffer + 21);
+
+ imageState_ -> dstLines = imageState_ -> dstHeight;
+
+ imageState_ -> dstLength = size - 24;
+ }
+
+ //
+ // Skip the MIT-SHM operation if the image
+ // is 1 bits-per-plane.
+ //
+
+ if (imageState_ -> dstDepth == 1)
+ {
+ #if defined(TEST) || defined(INFO)
+ *logofs << "handleShmem: Ignoring image with opcode "
+ << (unsigned int) imageState_ -> opcode << " depth "
+ << (unsigned int) imageState_ -> dstDepth << " and "
+ << "size " << size << " for FD#" << fd_
+ << ".\n" << logofs_flush;
+ #endif
+
+ return 0;
+ }
+
+ //
+ // If the image can't fit in the available
+ // space, check if the completion event is
+ // arrived.
+ //
+
+ #if defined(TEST) || defined(INFO)
+
+ if (isTimestamp(shmemState_ -> last) == 0 &&
+ shmemState_ -> offset != 0)
+ {
+ *logofs << "handleShmem: PANIC! No timestamp for sequence "
+ << shmemState_ -> sequence << " with offset "
+ << shmemState_ -> offset << ".\n"
+ << logofs_flush;
+ }
+
+ #endif
+
+ if (shmemState_ -> offset + imageState_ -> dstLength >
+ shmemState_ -> size)
+ {
+ if (imageState_ -> dstLength > shmemState_ -> size)
+ {
+ #if defined(TEST) || defined(INFO)
+ *logofs << "handleShmem: WARNING! Can't fit the image "
+ << "in the available memory segment for FD#"
+ << fd_ << ".\n" << logofs_flush;
+ #endif
+
+ return 0;
+ }
+ else if (handleShmemEvent() <= 0)
+ {
+ #if defined(TEST) || defined(INFO)
+ *logofs << "handleShmem: WARNING! Missing completion "
+ << "after " << diffTimestamp(shmemState_ -> last,
+ getTimestamp()) << " Ms for shared memory "
+ << "for FD#" << fd_ << ".\n" << logofs_flush;
+ #endif
+
+ return 0;
+ }
+ }
+
+ //
+ // Let image start at current offset
+ // in the shared segment.
+ //
+
+ #ifdef TEST
+ *logofs << "handleShmem: Copying " << dstDataSize
+ << " bytes to shared memory at offset "
+ << shmemState_ -> offset << " for FD#"
+ << fd_ << ".\n" << logofs_flush;
+ #endif
+
+ memcpy((unsigned char *) shmemState_ -> address +
+ shmemState_ -> offset, dstData, dstDataSize);
+
+ //
+ // Get rid of the original X_PutImage
+ // request.
+ //
+
+ if (writeBuffer_.getScratchData() != NULL)
+ {
+ writeBuffer_.removeScratchMessage();
+ }
+ else
+ {
+ writeBuffer_.removeMessage(size);
+ }
+
+ //
+ // Add a X_ShmPutImage request to the
+ // write buffer.
+ //
+
+ buffer = writeBuffer_.addMessage(40);
+
+ *buffer = shmemState_ -> opcode;
+
+ *(buffer + 1) = X_ShmPutImage;
+
+ PutUINT(40 >> 2, buffer + 2, bigEndian_);
+
+ PutULONG(imageState_ -> drawable, buffer + 4, bigEndian_);
+ PutULONG(imageState_ -> gcontext, buffer + 8, bigEndian_);
+
+ PutUINT(imageState_ -> dstWidth, buffer + 12, bigEndian_);
+ PutUINT(imageState_ -> dstLines, buffer + 14, bigEndian_);
+
+ PutUINT(imageState_ -> srcX, buffer + 16, bigEndian_);
+ PutUINT(imageState_ -> srcY, buffer + 18, bigEndian_);
+
+ PutUINT(imageState_ -> dstWidth, buffer + 20, bigEndian_);
+ PutUINT(imageState_ -> dstLines, buffer + 22, bigEndian_);
+
+ PutUINT(imageState_ -> dstX, buffer + 24, bigEndian_);
+ PutUINT(imageState_ -> dstY, buffer + 26, bigEndian_);
+
+ *(buffer + 28) = imageState_ -> dstDepth;
+ *(buffer + 29) = imageState_ -> format;
+ *(buffer + 30) = 1;
+
+ PutULONG(shmemState_ -> segment, buffer + 32, bigEndian_);
+ PutULONG(shmemState_ -> offset, buffer + 36, bigEndian_);
+
+ shmemState_ -> offset += dstDataSize;
+
+ shmemState_ -> sequence = clientSequence_;
+ shmemState_ -> last = getTimestamp();
+
+ #ifdef TEST
+ *logofs << "handleShmem: Saved shared memory sequence "
+ << shmemState_ -> sequence << " for FD#" << fd_
+ << " with offset " << shmemState_ -> offset
+ << " at " << strMsTimestamp() << ".\n"
+ << logofs_flush;
+ #endif
+
+ //
+ // Make the X server read immediately
+ // from the shared memory buffer and
+ // produce the completion event.
+ //
+
+ handleFlush(flush_if_any);
+
+ return 1;
+}
+
+//
+// Try to read more events from the socket in the
+// attempt to get the completion event required
+// to reset the MIT-SHM segment.
+//
+
+int ServerChannel::handleShmemEvent()
+{
+ #if defined(TEST) || defined(INFO)
+ *logofs << "handleShmemEvent: Waiting for shared memory "
+ << "sequence " << shmemState_ -> sequence
+ << " for X server FD#" << fd_ << ".\n"
+ << logofs_flush;
+
+ T_timestamp startTs = getTimestamp();
+
+ #endif
+
+ while (isTimestamp(shmemState_ -> last) != 0)
+ {
+ if (handleWait(control -> ShmemTimeout) <= 0)
+ {
+ break;
+ }
+ #if defined(TEST) || defined(INFO)
+ else
+ {
+ *logofs << "handleShmemEvent: WARNING! Encoded events "
+ << "for FD#" << fd_ << " at " << strMsTimestamp()
+ << ".\n" << logofs_flush;
+ }
+ #endif
+ }
+
+ if (isTimestamp(shmemState_ -> last) == 0)
+ {
+ #if defined(TEST) || defined(INFO)
+ *logofs << "handleShmemEvent: Spent "
+ << diffTimestamp(startTs, getTimestamp()) << " Ms "
+ << "waiting for shared memory sequence for FD#"
+ << fd_ << ".\n" << logofs_flush;
+ #endif
+
+ return 1;
+ }
+
+ #if defined(TEST) || defined(INFO)
+ *logofs << "handleShmemEvent: WARNING! Can't reset shared "
+ << "memory sequence for FD#" << fd_ << " after "
+ << diffTimestamp(shmemState_ -> last, getTimestamp())
+ << " Ms.\n" << logofs_flush;
+ #endif
+
+ return 0;
+}
+
+int ServerChannel::checkShmemEvent(unsigned char event, unsigned short sequence,
+ const unsigned char *buffer)
+{
+ if (isTimestamp(shmemState_ -> last) == 1 &&
+ sequence == shmemState_ -> sequence)
+ {
+ #ifdef TEST
+ *logofs << "checkShmemEvent: Reset shared memory sequence "
+ << shmemState_ -> sequence << " for FD#" << fd_
+ << " after " << diffTimestamp(shmemState_ -> last,
+ getTimestamp()) << " Ms.\n" << logofs_flush;
+ #endif
+
+ shmemState_ -> sequence = 0;
+ shmemState_ -> offset = 0;
+ shmemState_ -> last = nullTimestamp();
+ }
+ #ifdef TEST
+ else
+ {
+ *logofs << "checkShmemEvent: Skipping past shared memory "
+ << "image sequence " << sequence << " for FD#"
+ << fd_ << ".\n" << logofs_flush;
+ }
+ #endif
+
+ return 1;
+}
+
+int ServerChannel::checkShmemError(unsigned char error, unsigned short sequence,
+ const unsigned char *buffer)
+{
+ #ifdef TEST
+
+ *logofs << "checkShmemError: WARNING! Failed operation for "
+ << "FD#" << fd_ << " in stage " << shmemState_ -> stage
+ << " with ERR_CODE#" << (unsigned int) *(buffer + 1);
+
+ *logofs << " RES_ID#" << GetULONG(buffer + 4, bigEndian_);
+
+ *logofs << " MIN_OP#" << GetUINT(buffer + 8, bigEndian_);
+
+ *logofs << " MAJ_OP#" << (unsigned int) *(buffer + 10);
+
+ *logofs << " sequence " << sequence << ".\n";
+
+ *logofs << logofs_flush;
+
+ #endif
+
+ //
+ // If enabled flag is <= 0 we are still
+ // in the inizialization phase. In this
+ // case force presence to false.
+ //
+
+ if (shmemState_ -> enabled != 1)
+ {
+ if (shmemState_ -> present != 0)
+ {
+ #ifdef TEST
+ *logofs << "checkShmemError: Resetting shared memory "
+ << "presence flag for FD#" << fd_ << ".\n"
+ << logofs_flush;
+ #endif
+
+ shmemState_ -> present = 0;
+ }
+
+ return 0;
+ }
+
+ if (shmemState_ -> sequence == sequence)
+ {
+ //
+ // Reset the sequence and timestamp.
+ //
+
+ shmemState_ -> sequence = 0;
+ shmemState_ -> offset = 0;
+ shmemState_ -> last = nullTimestamp();
+ }
+
+ return 1;
+}
+
+int ServerChannel::handleFontRequest(DecodeBuffer &decodeBuffer, unsigned char &opcode,
+ unsigned char *&buffer, unsigned int &size)
+{
+ //
+ // Send a synchronization request and use
+ // the reply to return the requested font
+ // path.
+ //
+
+ #ifdef TEST
+ *logofs << "handleFontRequest: Sending X_GetInputFocus request "
+ << "for FD#" << fd_ << " due to OPCODE#" << (unsigned int)
+ opcodeStore_ -> getFontParameters << ".\n"
+ << logofs_flush;
+ #endif
+
+ opcode = X_GetInputFocus;
+
+ size = 4;
+ buffer = writeBuffer_.addMessage(size);
+
+ sequenceQueue_.push(clientSequence_, X_GetInputFocus,
+ opcodeStore_ -> getFontParameters);
+
+ return 1;
+}
+
+int ServerChannel::handleFontReply(EncodeBuffer &encodeBuffer, const unsigned char opcode,
+ const unsigned char *buffer, const unsigned int size)
+{
+ #ifdef TEST
+ *logofs << "handleFontReply: Encoding font operation "
+ << "reply with size " << size << ".\n"
+ << logofs_flush;
+ #endif
+
+ char data[256];
+
+ if (fontPort_ != -1)
+ {
+ sprintf(data + 1, "tcp/localhost:%d", fontPort_);
+ }
+ else
+ {
+ *(data + 1) = '\0';
+ }
+
+ *data = strlen(data + 1);
+
+ unsigned char *next = (unsigned char *) data;
+
+ unsigned int length = (unsigned int) (*next++);
+
+ encodeBuffer.encodeValue(length, 8);
+
+ encodeBuffer.encodeTextData(next, length);
+
+ return 1;
+}
+
+int ServerChannel::handleCacheRequest(DecodeBuffer &decodeBuffer, unsigned char &opcode,
+ unsigned char *&buffer, unsigned int &size)
+{
+ unsigned int mask;
+
+ decodeBuffer.decodeCachedValue(mask, 32, clientCache_ ->
+ setCacheParametersCache);
+
+ splitState_.save = (mask >> 8) & 0xff;
+ splitState_.load = mask & 0xff;
+
+ #ifdef TEST
+ *logofs << "handleCacheRequest: Set cache parameters to "
+ << "save " << splitState_.save << " load "
+ << splitState_.load << ".\n" << logofs_flush;
+ #endif
+
+ handleNullRequest(opcode, buffer, size);
+
+ return 1;
+}
+
+int ServerChannel::handleStartSplitRequest(DecodeBuffer &decodeBuffer, unsigned char &opcode,
+ unsigned char *&buffer, unsigned int &size)
+{
+ //
+ // Prepare for the split for the selected
+ // resource. Old proxy versions only used
+ // the split store at position 0.
+ //
+
+ // Since ProtoStep7 (#issue 108)
+ unsigned char resource;
+
+ decodeBuffer.decodeCachedValue(resource, 8,
+ clientCache_ -> resourceCache);
+
+ splitState_.resource = resource;
+
+ splitState_.current = splitState_.resource;
+
+ #if defined(TEST) || defined(SPLIT)
+ *logofs << "handleStartSplitRequest: SPLIT! Registered id "
+ << splitState_.resource << " as resource "
+ << "waiting for a split.\n" << logofs_flush;
+ #endif
+
+ handleNullRequest(opcode, buffer, size);
+
+ return 1;
+}
+
+int ServerChannel::handleEndSplitRequest(DecodeBuffer &decodeBuffer, unsigned char &opcode,
+ unsigned char *&buffer, unsigned int &size)
+{
+ //
+ // Verify that the agent resource matches.
+ //
+
+ // Since ProtoStep7 (#issue 108)
+ unsigned char resource;
+
+ decodeBuffer.decodeCachedValue(resource, 8,
+ clientCache_ -> resourceCache);
+
+ #ifdef TEST
+
+ if (splitState_.resource == nothing)
+ {
+ #ifdef PANIC
+ *logofs << "handleEndSplitRequest: PANIC! SPLIT! Received an end of "
+ << "split for resource id " << (unsigned int) *(buffer + 1)
+ << " without a previous start.\n"
+ << logofs_flush;
+ #endif
+
+ HandleCleanup();
+ }
+ else if (resource != splitState_.resource)
+ {
+ #ifdef PANIC
+ *logofs << "handleEndSplitRequest: PANIC! SPLIT! Invalid resource id "
+ << resource << " received while waiting for resource id "
+ << splitState_.resource << ".\n" << logofs_flush;
+ #endif
+
+ HandleCleanup();
+ }
+
+ #endif
+
+ #if defined(TEST) || defined(SPLIT)
+ *logofs << "handleEndSplitRequest: SPLIT! Reset id "
+ << splitState_.resource << " as resource "
+ << "selected for splits.\n" << logofs_flush;
+ #endif
+
+ splitState_.resource = nothing;
+
+ handleNullRequest(opcode, buffer, size);
+
+ return 1;
+}
+
+int ServerChannel::handleSplitChecksum(DecodeBuffer &decodeBuffer, T_checksum &checksum)
+{
+ unsigned int receive;
+
+ // Since ProtoStep7 (#issue 108)
+ decodeBuffer.decodeBoolValue(receive);
+
+ if (receive == 1)
+ {
+ checksum = new md5_byte_t[MD5_LENGTH];
+
+ for (unsigned int i = 0; i < MD5_LENGTH; i++)
+ {
+ decodeBuffer.decodeValue(receive, 8);
+
+ if (checksum != NULL)
+ {
+ checksum[i] = (unsigned char) receive;
+ }
+ }
+
+ #if defined(TEST) || defined(SPLIT)
+ *logofs << "handleSplitChecksum: SPLIT! Received checksum "
+ << "[" << DumpChecksum(checksum) << "].\n"
+ << logofs_flush;
+ #endif
+
+ return 1;
+ }
+
+ return 0;
+}
+
+void ServerChannel::handleShmemStateAlloc()
+{
+ if (shmemState_ == NULL)
+ {
+ shmemState_ = new T_shmem_state();
+
+ shmemState_ -> stage = -1;
+ shmemState_ -> present = -1;
+ shmemState_ -> enabled = -1;
+
+ shmemState_ -> segment = -1;
+ shmemState_ -> id = -1;
+ shmemState_ -> address = NULL;
+ shmemState_ -> size = 0;
+
+ shmemState_ -> opcode = 0xff;
+ shmemState_ -> event = 0xff;
+ shmemState_ -> error = 0xff;
+
+ shmemState_ -> sequence = 0;
+ shmemState_ -> offset = 0;
+ shmemState_ -> last = nullTimestamp();
+
+ shmemState_ -> checked = 0;
+ }
+}
+
+void ServerChannel::handleShmemStateRemove()
+{
+ if (shmemState_ != NULL)
+ {
+ if (shmemState_ -> address != NULL)
+ {
+#ifndef ANDROID
+ shmdt((char *) shmemState_ -> address);
+#else
+ cerr << "Info: handleShmemStateRemove: In android no shared memory. This should not be displayed. address should always be NULL\n";
+#endif
+ }
+
+ if (shmemState_ -> id > 0)
+ {
+#ifndef ANDROID
+ shmctl(shmemState_ -> id, IPC_RMID, 0);
+#else
+ cerr << "Info: handleShmemStateRemove: In android no shared memory. This should not be displayed. id should always be 0\n";
+#endif
+ }
+
+ delete shmemState_;
+
+ shmemState_ = NULL;
+ }
+}
+
+void ServerChannel::handleUnpackStateInit(int resource)
+{
+ if (unpackState_[resource] == NULL)
+ {
+ unpackState_[resource] = new T_unpack_state();
+
+ if (unpackState_[resource] == NULL)
+ {
+ #ifdef PANIC
+ *logofs << "handleUnpackStateInit: PANIC! Can't allocate "
+ << "memory for unpack state in context [A].\n"
+ << logofs_flush;
+ #endif
+
+ cerr << "Error" << ": Can't allocate memory for "
+ << "unpack state in context [A].\n";
+
+ HandleAbort();
+ }
+
+ unpackState_[resource] -> geometry = NULL;
+ unpackState_[resource] -> colormap = NULL;
+ unpackState_[resource] -> alpha = NULL;
+ }
+}
+
+void ServerChannel::handleUnpackAllocGeometry(int resource)
+{
+ if (unpackState_[resource] -> geometry == NULL)
+ {
+ unpackState_[resource] -> geometry = new T_geometry();
+
+ if (unpackState_[resource] -> geometry == NULL)
+ {
+ #ifdef PANIC
+ *logofs << "handleUnpackAllocGeometry: PANIC! Can't allocate "
+ << "memory for unpack state in context [B].\n"
+ << logofs_flush;
+ #endif
+
+ cerr << "Error" << ": Can't allocate memory for "
+ << "unpack state in context [B].\n";
+
+ HandleAbort();
+ }
+
+ unpackState_[resource] -> geometry -> depth1_bpp = 4;
+ unpackState_[resource] -> geometry -> depth4_bpp = 4;
+ unpackState_[resource] -> geometry -> depth8_bpp = 8;
+ unpackState_[resource] -> geometry -> depth16_bpp = 16;
+ unpackState_[resource] -> geometry -> depth24_bpp = 32;
+ unpackState_[resource] -> geometry -> depth32_bpp = 32;
+
+ unpackState_[resource] -> geometry -> red_mask = 0xff0000;
+ unpackState_[resource] -> geometry -> green_mask = 0x00ff00;
+ unpackState_[resource] -> geometry -> blue_mask = 0x0000ff;
+
+ unpackState_[resource] -> geometry -> image_byte_order = imageByteOrder_;
+ unpackState_[resource] -> geometry -> bitmap_bit_order = bitmapBitOrder_;
+ unpackState_[resource] -> geometry -> scanline_unit = scanlineUnit_;
+ unpackState_[resource] -> geometry -> scanline_pad = scanlinePad_;
+ }
+}
+
+void ServerChannel::handleUnpackAllocColormap(int resource)
+{
+ if (unpackState_[resource] -> colormap == NULL)
+ {
+ unpackState_[resource] -> colormap = new T_colormap();
+
+ if (unpackState_[resource] -> colormap == NULL)
+ {
+ #ifdef PANIC
+ *logofs << "handleUnpackAllocColormap: PANIC! Can't allocate "
+ << "memory for unpack state in context [C].\n"
+ << logofs_flush;
+ #endif
+
+ cerr << "Error" << ": Can't allocate memory for "
+ << "unpack state in context [C].\n";
+
+ HandleAbort();
+ }
+
+ unpackState_[resource] -> colormap -> entries = 0;
+ unpackState_[resource] -> colormap -> data = NULL;
+ }
+}
+
+void ServerChannel::handleUnpackAllocAlpha(int resource)
+{
+ if (unpackState_[resource] -> alpha == NULL)
+ {
+ unpackState_[resource] -> alpha = new T_alpha();
+
+ if (unpackState_[resource] -> alpha == NULL)
+ {
+ #ifdef PANIC
+ *logofs << "handleUnpackAllocAlpha: PANIC! Can't allocate "
+ << "memory for unpack state in context [D].\n"
+ << logofs_flush;
+ #endif
+
+ cerr << "Error" << ": Can't allocate memory for "
+ << "unpack state in context [D].\n";
+
+ HandleAbort();
+ }
+
+ unpackState_[resource] -> alpha -> entries = 0;
+ unpackState_[resource] -> alpha -> data = NULL;
+ }
+}
+
+void ServerChannel::handleUnpackStateRemove(int resource)
+{
+ if (unpackState_[resource] != NULL)
+ {
+ delete unpackState_[resource] -> geometry;
+
+ if (unpackState_[resource] -> colormap != NULL)
+ {
+ delete [] unpackState_[resource] -> colormap -> data;
+ }
+
+ delete unpackState_[resource] -> colormap;
+
+ if (unpackState_[resource] -> alpha != NULL)
+ {
+ delete [] unpackState_[resource] -> alpha -> data;
+ }
+
+ delete unpackState_[resource] -> alpha;
+
+ delete unpackState_[resource];
+
+ unpackState_[resource] = NULL;
+ }
+}
+
+void ServerChannel::handleEncodeCharInfo(const unsigned char *nextSrc, EncodeBuffer &encodeBuffer)
+{
+ unsigned int value = GetUINT(nextSrc, bigEndian_) |
+ (GetUINT(nextSrc + 10, bigEndian_) << 16);
+
+ encodeBuffer.encodeCachedValue(value, 32,
+ *serverCache_ -> queryFontCharInfoCache[0], 6);
+
+ nextSrc += 2;
+
+ for (unsigned int i = 1; i < 5; i++)
+ {
+ unsigned int value = GetUINT(nextSrc, bigEndian_);
+
+ nextSrc += 2;
+
+ encodeBuffer.encodeCachedValue(value, 16,
+ *serverCache_ -> queryFontCharInfoCache[i], 6);
+ }
+}
+
+int ServerChannel::setBigEndian(int flag)
+{
+ bigEndian_ = flag;
+
+ readBuffer_.setBigEndian(flag);
+
+ return 1;
+}
+
+int ServerChannel::setReferences()
+{
+ #ifdef TEST
+ *logofs << "ServerChannel: Initializing the static "
+ << "members for the server channels.\n"
+ << logofs_flush;
+ #endif
+
+ #ifdef REFERENCES
+
+ references_ = 0;
+
+ #endif
+
+ return 1;
+}