#include <sys/types.h>
#define NEED_REPLIES
#define NEED_EVENTS
#include "X.h"
#include "Xproto.h"
#include "Xos.h"
#include "misc.h"
#include "os.h"
#include "dixstruct.h"
#include "resource.h"
#include "scrnintstr.h"
#include "windowstr.h"
#include "pixmapstr.h"
#include "gcstruct.h"
#include "extnsionst.h"
#include "servermd.h"
#define _XLBX_SERVER_
#include "lbxstr.h"
#include "lbxdeltastr.h"
#include "lbxserve.h"
#include "lbximage.h"
#include "lbxsrvopts.h"
#include "lbxtags.h"
#include "Xfuncproto.h"
#include <errno.h>
#ifndef Lynx
#include <sys/uio.h>
#else
#include <uio.h>
#endif
#include <stdio.h>
#ifndef X_NOT_POSIX
#include <unistd.h>
#endif
#define CloseLbxClient 0xff
#define MAXBYTESDIFF 8
int LbxWhoAmI = 1;
static void LbxResetProc ( ExtensionEntry *extEntry );
static void LbxFreeClient ( ClientPtr client );
static void LbxShutdownProxy ( LbxProxyPtr proxy );
static int DecodeLbxDelta ( ClientPtr client );
static LbxProxyPtr proxyList;
unsigned char LbxReqCode;
int LbxEventCode;
static int BadLbxClientCode;
static int uid_seed;
static int lbxCompressWorkProcCount;
LbxClientPtr lbxClients[MAXCLIENTS];
extern xConnSetupPrefix connSetupPrefix;
extern char *ConnectionInfo;
extern int (*LbxInitialVector[3])(ClientPtr);
#ifdef DEBUG
int lbxDebug = 0;
#endif
void
LbxExtensionInit(void)
{
ExtensionEntry *extEntry;
lbxCompressWorkProcCount = 0;
proxyList = NULL;
uid_seed = 0;
if ((extEntry = AddExtension(LBXNAME, LbxNumberEvents, LbxNumberErrors,
ProcLbxDispatch, SProcLbxDispatch,
LbxResetProc, StandardMinorOpcode)))
{
LbxReqCode = (unsigned char)extEntry->base;
LbxEventCode = extEntry->eventBase;
BadLbxClientCode = extEntry->errorBase + BadLbxClient;
LbxDixInit();
LbxCmapInit ();
DeclareExtensionSecurity(LBXNAME, TRUE);
}
}
static void
LbxResetProc (ExtensionEntry *extEntry)
{
LbxResetTags();
uid_seed = 0;
}
void
LbxCloseClient (ClientPtr client)
{
xLbxCloseEvent closeEvent;
ClientPtr master;
LbxProxyPtr proxy;
LbxClientPtr lbxClient = LbxClient(client);
CARD32 id;
if (!lbxClient)
return;
id = lbxClient->id;
proxy = lbxClient->proxy;
DBG (DBG_CLIENT, (stderr, "Close client %d\n", client->index));
LbxFreeClient (client);
if (!id)
{
isItTimeToYield = TRUE;
CloseDownFileDescriptor (client);
LbxShutdownProxy (proxy);
}
else
{
master = NULL;
if (proxy->lbxClients[0])
master = LbxProxyClient(proxy);
if (master && !master->clientGone)
{
closeEvent.type = LbxEventCode;
closeEvent.lbxType = LbxCloseEvent;
closeEvent.client = id;
closeEvent.sequenceNumber = master->sequence;
closeEvent.pad1 = closeEvent.pad2 = closeEvent.pad3 =
closeEvent.pad4 = closeEvent.pad5 = closeEvent.pad6 = 0;
if (master->swapped) {
int n;
swaps(&closeEvent.sequenceNumber, n);
swapl(&closeEvent.client, n);
}
WriteToClient(master, sizeof (closeEvent), (char *)&closeEvent);
LbxForceOutput(proxy);
}
}
}
static int
LbxReencodeEvent(ClientPtr client,
LbxProxyPtr proxy,
char *buf)
{
xEvent *ev = (xEvent *)buf;
int n;
lbxMotionCache *motionCache = &proxy->motionCache;
int motionDelta = 0;
Bool swapCache;
xEvent tev, *sev;
if (ev->u.u.type != MotionNotify) {
if (proxy->dosquishing)
return LbxSquishEvent(buf);
return 0;
}
if (!proxy->motion_allowed_events) {
DBG(DBG_CLIENT, (stderr, "throttling motion event for client %d\n", client->index));
return sz_xEvent;
}
proxy->motion_allowed_events--;
motionCache = &proxy->motionCache;
if (!client->swapped)
{
swapCache = motionCache->swapped;
sev = ev;
}
else
{
swapCache = !motionCache->swapped;
sev = &tev;
cpswaps (ev->u.keyButtonPointer.rootX,
sev->u.keyButtonPointer.rootX);
cpswaps (ev->u.keyButtonPointer.rootY,
sev->u.keyButtonPointer.rootY);
cpswaps (ev->u.keyButtonPointer.eventX,
sev->u.keyButtonPointer.eventX);
cpswaps (ev->u.keyButtonPointer.eventY,
sev->u.keyButtonPointer.eventY);
cpswaps (ev->u.u.sequenceNumber,
sev->u.u.sequenceNumber);
cpswapl (ev->u.keyButtonPointer.time,
sev->u.keyButtonPointer.time);
}
if (swapCache)
{
swapl (&motionCache->root, n);
swapl (&motionCache->event, n);
swapl (&motionCache->child, n);
swaps (&motionCache->state, n);
motionCache->swapped = !motionCache->swapped;
}
motionDelta = 0;
if (ev->u.u.detail == motionCache->detail &&
ev->u.keyButtonPointer.root == motionCache->root &&
ev->u.keyButtonPointer.event == motionCache->event &&
ev->u.keyButtonPointer.child == motionCache->child &&
ev->u.keyButtonPointer.state == motionCache->state &&
ev->u.keyButtonPointer.sameScreen == motionCache->sameScreen) {
int root_delta_x =
sev->u.keyButtonPointer.rootX - motionCache->rootX;
int root_delta_y =
sev->u.keyButtonPointer.rootY - motionCache->rootY;
int event_delta_x =
sev->u.keyButtonPointer.eventX - motionCache->eventX;
int event_delta_y =
sev->u.keyButtonPointer.eventY - motionCache->eventY;
unsigned long sequence_delta =
sev->u.u.sequenceNumber - motionCache->sequenceNumber;
unsigned long time_delta =
sev->u.keyButtonPointer.time - motionCache->time;
if (root_delta_x == event_delta_x &&
event_delta_x >= -128 && event_delta_x < 128 &&
root_delta_y == event_delta_y &&
event_delta_y >= -128 && event_delta_y < 128) {
if (sequence_delta == 0 && time_delta < 256) {
lbxQuickMotionDeltaEvent *mev =
(lbxQuickMotionDeltaEvent *)(buf + sz_xEvent -
sz_lbxQuickMotionDeltaEvent);
mev->type = LbxEventCode + LbxQuickMotionDeltaEvent;
mev->deltaTime = time_delta;
mev->deltaX = event_delta_x;
mev->deltaY = event_delta_y;
motionDelta = sz_xEvent - sz_lbxQuickMotionDeltaEvent;
} else if (sequence_delta < 65536 && time_delta < 65536) {
lbxMotionDeltaEvent *mev =
(lbxMotionDeltaEvent *)(buf + sz_xEvent -
sz_lbxMotionDeltaEvent);
mev->type = LbxEventCode;
mev->lbxType = LbxMotionDeltaEvent;
mev->deltaTime = time_delta;
mev->deltaSequence = sequence_delta;
mev->deltaX = event_delta_x;
mev->deltaY = event_delta_y;
if (LbxProxyClient(proxy)->swapped)
{
swaps (&mev->deltaTime, n);
swaps (&mev->deltaSequence, n);
}
motionDelta = sz_xEvent - sz_lbxMotionDeltaEvent;
}
}
}
motionCache->sequenceNumber = sev->u.u.sequenceNumber;
motionCache->time = sev->u.keyButtonPointer.time;
motionCache->rootX = sev->u.keyButtonPointer.rootX;
motionCache->rootY = sev->u.keyButtonPointer.rootY;
motionCache->eventX = sev->u.keyButtonPointer.eventX;
motionCache->eventY = sev->u.keyButtonPointer.eventY;
if (motionDelta)
return motionDelta;
ev->u.keyButtonPointer.pad1 = 0;
motionCache->detail = ev->u.u.detail;
motionCache->root = ev->u.keyButtonPointer.root;
motionCache->event = ev->u.keyButtonPointer.event;
motionCache->child = ev->u.keyButtonPointer.child;
motionCache->state = ev->u.keyButtonPointer.state;
motionCache->sameScreen = ev->u.keyButtonPointer.sameScreen;
return 0;
}
static int
LbxComposeDelta(LbxProxyPtr proxy,
char *reply,
int len,
char *buf)
{
int diffs;
int cindex;
int n;
xLbxDeltaReq *p = (xLbxDeltaReq *)buf;
diffs = LBXDeltaMinDiffs(&proxy->outdeltas, (unsigned char *)reply, len,
min(MAXBYTESDIFF, (len - sz_xLbxDeltaReq) >> 1),
&cindex);
if (diffs < 0) {
LBXAddDeltaOut(&proxy->outdeltas, (unsigned char *)reply, len);
return 0;
}
LBXEncodeDelta(&proxy->outdeltas, (unsigned char *)reply, diffs, cindex,
(unsigned char *)(&buf[sz_xLbxDeltaReq]));
LBXAddDeltaOut(&proxy->outdeltas, (unsigned char *)reply, len);
p->reqType = LbxEventCode;
p->lbxReqType = LbxDeltaEvent;
p->diffs = diffs;
p->cindex = cindex;
len = (sz_xLbxDeltaReq + sz_xLbxDiffItem * diffs + 3) & ~3;
p->length = len >> 2;
if (LbxProxyClient(proxy)->swapped) {
swaps(&p->length, n);
}
return len;
}
void
LbxReencodeOutput(ClientPtr client,
char *pbuf,
int *pcount,
char *cbuf,
int *ccount)
{
LbxClientPtr lbxClient = LbxClient(client);
LbxProxyPtr proxy = lbxClient->proxy;
CARD32 len;
int n;
int count = *ccount;
char *obuf = cbuf;
if (client->clientState != ClientStateRunning) {
if (DELTA_CACHEABLE(&proxy->outdeltas, count) &&
(n = LbxComposeDelta(proxy, cbuf, count, proxy->oDeltaBuf))) {
memcpy(obuf, proxy->oDeltaBuf, n);
*ccount -= (count - n);
}
return;
}
if (lbxClient->bytes_remaining) {
if (count < lbxClient->bytes_remaining) {
lbxClient->bytes_remaining -= count;
return;
}
if (DELTA_CACHEABLE(&proxy->outdeltas, lbxClient->bytes_in_reply)) {
len = lbxClient->bytes_in_reply - lbxClient->bytes_remaining;
pbuf += (*pcount - len);
memcpy(proxy->replyBuf, pbuf, len);
memcpy(proxy->replyBuf + len, cbuf, lbxClient->bytes_remaining);
n = LbxComposeDelta(proxy, proxy->replyBuf,
lbxClient->bytes_in_reply, proxy->oDeltaBuf);
if (!n)
obuf += lbxClient->bytes_remaining;
else if (n <= len) {
memcpy(pbuf, proxy->oDeltaBuf, n);
*pcount -= (len - n);
*ccount -= lbxClient->bytes_remaining;
} else {
memcpy(pbuf, proxy->oDeltaBuf, len);
memcpy(obuf, proxy->oDeltaBuf + len, n - len);
*ccount -= lbxClient->bytes_remaining - (n - len);
obuf += n - len;
}
} else
obuf += lbxClient->bytes_remaining;
cbuf += lbxClient->bytes_remaining;
count -= lbxClient->bytes_remaining;
lbxClient->bytes_remaining = 0;
}
while (count) {
lbxClient->bytes_in_reply = sz_xEvent;
if (((xGenericReply *)cbuf)->type == X_Reply) {
len = ((xGenericReply *)cbuf)->length;
if (client->swapped) {
swapl(&len, n);
}
lbxClient->bytes_in_reply += (len << 2);
if (LbxProxyClient(proxy)->swapped != client->swapped) {
swapl(&((xGenericReply *)cbuf)->length, n);
}
if (count < lbxClient->bytes_in_reply) {
lbxClient->bytes_remaining = lbxClient->bytes_in_reply - count;
if (obuf != cbuf)
memmove(obuf, cbuf, count);
return;
}
} else if (((xGenericReply *)cbuf)->type > X_Reply &&
((xGenericReply *)cbuf)->type < LASTEvent &&
(n = LbxReencodeEvent(client, proxy, cbuf))) {
cbuf += n;
*ccount -= n;
count -= n;
if (n == sz_xEvent)
continue;
lbxClient->bytes_in_reply -= n;
}
if (DELTA_CACHEABLE(&proxy->outdeltas, lbxClient->bytes_in_reply) &&
(n = LbxComposeDelta(proxy, cbuf, lbxClient->bytes_in_reply,
proxy->oDeltaBuf))) {
memcpy(obuf, proxy->oDeltaBuf, n);
obuf += n;
*ccount -= (lbxClient->bytes_in_reply - n);
} else {
if (obuf != cbuf)
memmove(obuf, cbuf, lbxClient->bytes_in_reply);
obuf += lbxClient->bytes_in_reply;
}
cbuf += lbxClient->bytes_in_reply;
count -= lbxClient->bytes_in_reply;
}
}
static void
LbxReplyCallback(CallbackListPtr *pcbl,
pointer nulldata,
pointer calldata)
{
ReplyInfoRec *pri = (ReplyInfoRec *)calldata;
ClientPtr client = pri->client;
LbxClientPtr lbxClient;
REQUEST(xReq);
if (!pri->startOfReply || stuff->reqType > 127)
return;
lbxClient = LbxClient(client);
if (lbxClient)
ZeroReplyPadBytes(pri->replyData, stuff->reqType);
}
static Bool
LbxCheckCompressInput (ClientPtr dummy1,
pointer dummy2)
{
LbxProxyPtr proxy;
if (!lbxCompressWorkProcCount)
return TRUE;
for (proxy = proxyList; proxy; proxy = proxy->next) {
if (proxy->compHandle &&
proxy->streamOpts.streamCompInputAvail(proxy->fd))
AvailableClientInput (LbxProxyClient(proxy));
}
return FALSE;
}
static Bool
LbxIsClientBlocked (LbxClientPtr lbxClient)
{
LbxProxyPtr proxy = lbxClient->proxy;
return (lbxClient->ignored ||
(GrabInProgress && lbxClient->client->index != GrabInProgress &&
lbxClient != proxy->lbxClients[0]));
}
static void
LbxSwitchRecv (LbxProxyPtr proxy,
LbxClientPtr lbxClient)
{
ClientPtr client;
proxy->curRecv = lbxClient;
if (!lbxClient || lbxClient->client->clientGone)
{
DBG(DBG_CLIENT, (stderr, "switching to dispose input\n"));
lbxClient = proxy->lbxClients[0];
if (!lbxClient)
return;
}
client = lbxClient->client;
DBG (DBG_SWITCH, (stderr, "switching input to client %d\n", client->index));
SwitchClientInput (client, FALSE);
proxy->curDix = lbxClient;
}
static Bool
LbxWaitForUnblocked (ClientPtr client,
pointer closure)
{
LbxClientPtr lbxClient;
LbxProxyPtr proxy;
if (client->clientGone)
return TRUE;
lbxClient = LbxClient(client);
if (!lbxClient)
return TRUE;
proxy = lbxClient->proxy;
if (LbxIsClientBlocked (lbxClient) ||
((lbxClient != proxy->curDix) && proxy->curDix->reqs_pending &&
!LbxIsClientBlocked(proxy->curDix)))
return FALSE;
lbxClient->input_blocked = FALSE;
DBG (DBG_BLOCK, (stderr, "client %d no longer blocked, switching\n",
client->index));
SwitchClientInput (client, TRUE);
proxy->curDix = lbxClient;
return TRUE;
}
void
LbxSetForBlock(LbxClientPtr lbxClient)
{
lbxClient->reqs_pending++;
if (!lbxClient->input_blocked)
{
lbxClient->input_blocked = TRUE;
QueueWorkProc(LbxWaitForUnblocked, lbxClient->client, NULL);
}
}
static int
LbxWaitForUngrab (ClientPtr client,
pointer closure)
{
LbxClientPtr lbxClient = LbxClient(client);
LbxProxyPtr proxy;
xLbxListenToAllEvent ungrabEvent;
if (client->clientGone || !lbxClient)
return TRUE;
if (GrabInProgress)
return FALSE;
proxy = lbxClient->proxy;
proxy->grabClient = 0;
ungrabEvent.type = LbxEventCode;
ungrabEvent.lbxType = LbxListenToAll;
ungrabEvent.pad1 = ungrabEvent.pad2 = ungrabEvent.pad3 =
ungrabEvent.pad4 = ungrabEvent.pad5 = ungrabEvent.pad6 =
ungrabEvent.pad7 = 0;
WriteToClient (client,
sizeof(xLbxListenToAllEvent), (char *)&ungrabEvent);
LbxForceOutput(proxy);
return TRUE;
}
static void
LbxServerGrab(LbxProxyPtr proxy)
{
LbxClientPtr grabbingLbxClient;
xLbxListenToOneEvent grabEvent;
grabEvent.type = LbxEventCode;
grabEvent.lbxType = LbxListenToOne;
if (!(grabbingLbxClient = lbxClients[GrabInProgress]) ||
grabbingLbxClient->proxy != proxy)
grabEvent.client = 0xffffffff;
else
grabEvent.client = grabbingLbxClient->id;
grabEvent.pad1 = grabEvent.pad2 = grabEvent.pad3 =
grabEvent.pad4 = grabEvent.pad5 = grabEvent.pad6 = 0;
if (LbxProxyClient(proxy)->swapped) {
int n;
swapl(&grabEvent.client, n);
}
WriteToClient(LbxProxyClient(proxy),
sizeof(xLbxListenToOneEvent), (char *)&grabEvent);
LbxForceOutput(proxy);
if (!proxy->grabClient)
QueueWorkProc(LbxWaitForUngrab, LbxProxyClient(proxy), NULL);
proxy->grabClient = GrabInProgress;
}
#define MAJOROP(client) ((xReq *)client->requestBuffer)->reqType
#define MINOROP(client) ((xReq *)client->requestBuffer)->data
static Bool lbxCacheable[] = {
FALSE,
FALSE,
TRUE,
FALSE,
FALSE,
TRUE,
TRUE,
FALSE,
TRUE,
FALSE,
TRUE,
FALSE,
TRUE,
TRUE,
TRUE,
TRUE,
TRUE,
TRUE,
TRUE,
TRUE,
TRUE,
TRUE,
TRUE,
TRUE,
TRUE,
TRUE,
TRUE,
TRUE,
TRUE,
TRUE,
TRUE,
TRUE,
FALSE,
TRUE,
TRUE,
FALSE,
FALSE,
FALSE,
FALSE,
TRUE,
TRUE,
TRUE,
TRUE,
TRUE,
};
#define NUM(a) (sizeof (a) / sizeof (a[0]))
static int
LbxReadRequestFromClient (ClientPtr client)
{
int ret;
LbxClientPtr lbxClient = LbxClient(client);
LbxProxyPtr proxy = lbxClient->proxy;
ClientPtr masterClient = LbxProxyClient(proxy);
Bool isblocked;
Bool cacheable;
DBG (DBG_READ_REQ, (stderr, "Reading request from client %d\n", client->index));
if (GrabInProgress && (proxy->grabClient != GrabInProgress))
LbxServerGrab(proxy);
isblocked = LbxIsClientBlocked(lbxClient);
if (lbxClient->reqs_pending && !isblocked) {
ret = StandardReadRequestFromClient(client);
if (ret > 0 && (MAJOROP(client) == LbxReqCode) &&
(MINOROP(client) == X_LbxEndLargeRequest))
ret = PrepareLargeReqBuffer(client);
if (!--lbxClient->reqs_pending && (lbxClient != proxy->curRecv))
LbxSwitchRecv (proxy, proxy->curRecv);
return ret;
}
while (1) {
ret = StandardReadRequestFromClient(masterClient);
if (ret <= 0)
return ret;
client->requestBuffer = masterClient->requestBuffer;
client->req_len = masterClient->req_len;
cacheable = client->clientState == ClientStateRunning;
if (cacheable && (MAJOROP(client) == LbxReqCode)) {
if (MINOROP(client) < NUM(lbxCacheable))
cacheable = lbxCacheable[MINOROP(client)];
switch (MINOROP(client)) {
case X_LbxSwitch:
if (masterClient->swapped)
SProcLbxSwitch (client);
else
ProcLbxSwitch (client);
return 0;
case X_LbxDelta:
ret = DecodeLbxDelta (client);
DBG(DBG_DELTA,
(stderr,"delta decompressed msg %d, len = %d\n",
(unsigned)((unsigned char *)client->requestBuffer)[0],
ret));
break;
case X_LbxEndLargeRequest:
if (!isblocked)
ret = PrepareLargeReqBuffer(client);
break;
}
}
if (cacheable && DELTA_CACHEABLE(&proxy->indeltas, ret)) {
DBG(DBG_DELTA,
(stderr, "caching msg %d, len = %d, index = %d\n",
(unsigned)((unsigned char *)client->requestBuffer)[0],
ret, proxy->indeltas.nextDelta));
LBXAddDeltaIn(&proxy->indeltas, client->requestBuffer, ret);
}
if (client->swapped != masterClient->swapped) {
char n;
swaps(&((xReq *)client->requestBuffer)->length, n);
}
if (!isblocked)
return ret;
DBG (DBG_BLOCK, (stderr, "Stashing %d bytes for %d\n",
ret, client->index));
AppendFakeRequest (client, client->requestBuffer, ret);
LbxSetForBlock(lbxClient);
}
}
static LbxClientPtr
LbxInitClient (LbxProxyPtr proxy,
ClientPtr client,
CARD32 id)
{
LbxClientPtr lbxClient;
int i;
lbxClient = (LbxClientPtr) xalloc (sizeof (LbxClientRec));
if (!lbxClient)
return NULL;
lbxClient->id = id;
lbxClient->client = client;
lbxClient->proxy = proxy;
lbxClient->ignored = FALSE;
lbxClient->input_blocked = FALSE;
lbxClient->reqs_pending = 0;
lbxClient->bytes_in_reply = 0;
lbxClient->bytes_remaining = 0;
client->readRequest = LbxReadRequestFromClient;
bzero (lbxClient->drawableCache, sizeof (lbxClient->drawableCache));
bzero (lbxClient->gcontextCache, sizeof (lbxClient->gcontextCache));
lbxClients[client->index] = lbxClient;
for (i = 0; proxy->lbxClients[i]; i++)
;
if (i > proxy->maxIndex)
proxy->maxIndex = i;
proxy->lbxClients[i] = lbxClient;
proxy->numClients++;
lbxClient->gfx_buffer = (pointer) NULL;
lbxClient->gb_size = 0;
return lbxClient;
}
static void
LbxFreeClient (ClientPtr client)
{
LbxClientPtr lbxClient = LbxClient(client);
LbxProxyPtr proxy = lbxClient->proxy;
int i;
if (lbxClient != proxy->lbxClients[0]) {
if (lbxClient == proxy->curRecv)
LbxSwitchRecv(proxy, NULL);
else if (lbxClient == proxy->curDix)
LbxSwitchRecv(proxy, proxy->curRecv);
}
--proxy->numClients;
lbxClients[client->index] = NULL;
for (i = 0; i <= proxy->maxIndex; i++) {
if (proxy->lbxClients[i] == lbxClient) {
proxy->lbxClients[i] = NULL;
break;
}
}
while (proxy->maxIndex >= 0 && !proxy->lbxClients[proxy->maxIndex])
--proxy->maxIndex;
xfree(lbxClient->gfx_buffer);
client->readRequest = StandardReadRequestFromClient;
xfree (lbxClient);
}
static void
LbxFreeProxy (LbxProxyPtr proxy)
{
LbxProxyPtr *p;
LBXFreeDeltaCache(&proxy->indeltas);
LBXFreeDeltaCache(&proxy->outdeltas);
LbxFreeOsBuffers(proxy);
if (proxy->iDeltaBuf)
xfree(proxy->iDeltaBuf);
if (proxy->replyBuf)
xfree(proxy->replyBuf);
if (proxy->oDeltaBuf)
xfree(proxy->oDeltaBuf);
if (proxy->compHandle)
proxy->streamOpts.streamCompFreeHandle(proxy->compHandle);
if (proxy->bitmapCompMethods)
xfree (proxy->bitmapCompMethods);
if (proxy->pixmapCompMethods)
xfree (proxy->pixmapCompMethods);
if (proxy->pixmapCompDepths)
{
int i;
for (i = 0; i < proxy->numPixmapCompMethods; i++)
xfree (proxy->pixmapCompDepths[i]);
xfree (proxy->pixmapCompDepths);
}
for (p = &proxyList; *p; p = &(*p)->next) {
if (*p == proxy) {
*p = proxy->next;
break;
}
}
if (!proxyList)
DeleteCallback(&ReplyCallback, LbxReplyCallback, NULL);
xfree (proxy);
}
LbxProxyPtr
LbxPidToProxy(int pid)
{
LbxProxyPtr proxy;
for (proxy = proxyList; proxy; proxy = proxy->next) {
if (proxy->pid == pid)
return proxy;
}
return NULL;
}
static void
LbxShutdownProxy (LbxProxyPtr proxy)
{
int i;
ClientPtr client;
if (proxy->compHandle)
--lbxCompressWorkProcCount;
while (proxy->grabbedCmaps)
LbxReleaseCmap(proxy->grabbedCmaps, FALSE);
for (i = 0; i <= proxy->maxIndex; i++)
{
if (proxy->lbxClients[i])
{
client = proxy->lbxClients[i]->client;
if (!client->clientGone)
CloseDownClient (client);
}
}
LbxFlushTags(proxy);
LbxFreeProxy(proxy);
}
int
ProcLbxQueryVersion (ClientPtr client)
{
xLbxQueryVersionReply rep;
register int n;
REQUEST_SIZE_MATCH(xLbxQueryVersionReq);
rep.type = X_Reply;
rep.length = 0;
rep.sequenceNumber = client->sequence;
rep.majorVersion = LBX_MAJOR_VERSION;
rep.minorVersion = LBX_MINOR_VERSION;
rep.pad0 = rep.pad1 = rep.pad2 = rep.pad3 = rep.pad4 = 0;
if (client->swapped) {
swaps(&rep.sequenceNumber, n);
swapl(&rep.length, n);
swaps(&rep.majorVersion, n);
swaps(&rep.minorVersion, n);
}
WriteToClient(client, sizeof(xLbxQueryVersionReply), (char *)&rep);
return (client->noClientException);
}
static int
NextProxyID (void)
{
LbxProxyPtr proxy;
int id;
for (id = 1; id < MAX_NUM_PROXIES; id++) {
for (proxy = proxyList; proxy && proxy->pid != id; proxy = proxy->next)
;
if (!proxy)
return id;
}
return -1;
}
int
ProcLbxStartProxy (ClientPtr client)
{
REQUEST(xLbxStartProxyReq);
LbxProxyPtr proxy;
LbxClientPtr lbxClient;
int reqlen;
int replylen;
xLbxStartReply *replybuf;
LbxNegOptsRec negopt;
register int n;
pointer compHandle = NULL;
REQUEST_AT_LEAST_SIZE(xLbxStartProxyReq);
if (lbxClients[client->index])
return BadLbxClientCode;
proxy = (LbxProxyPtr) xalloc (sizeof (LbxProxyRec));
if (!proxy)
return BadAlloc;
bzero(proxy, sizeof (LbxProxyRec));
proxy->pid = NextProxyID();
if (proxy->pid < 0) {
xfree(proxy);
return BadAlloc;
}
proxy->uid = ++uid_seed;
if (!proxyList)
AddCallback(&ReplyCallback, LbxReplyCallback, NULL);
if(!proxyList)
proxyList = proxy;
else{
proxy->next = proxyList;
proxyList = proxy;
}
reqlen = client->req_len << 2;
replybuf = (xLbxStartReply *) xalloc(max(reqlen, sz_xLbxStartReply));
if (!replybuf) {
LbxFreeProxy(proxy);
return BadAlloc;
}
LbxOptionInit(&negopt);
replylen = LbxOptionParse(&negopt,
(unsigned char *)&stuff[1],
reqlen - sz_xLbxStartProxyReq,
(unsigned char *)&replybuf->optDataStart);
if (replylen < 0) {
LbxOptionInit(&negopt);
negopt.nopts = 0xff;
replylen = 0;
}
if (LBXInitDeltaCache(&proxy->indeltas, negopt.proxyDeltaN,
negopt.proxyDeltaMaxLen) < 0
||
LBXInitDeltaCache(&proxy->outdeltas, negopt.serverDeltaN,
negopt.serverDeltaMaxLen) < 0) {
LbxFreeProxy(proxy);
xfree(replybuf);
return BadAlloc;
}
n = 0;
if (negopt.proxyDeltaN)
n = negopt.proxyDeltaMaxLen;
if (negopt.serverDeltaN && negopt.serverDeltaMaxLen > n)
n = negopt.serverDeltaMaxLen;
if (n &&
(!(proxy->iDeltaBuf = (char *)xalloc (n)) ||
!(proxy->replyBuf = (char *)xalloc (n)) ||
!(proxy->oDeltaBuf = (char *)xalloc (n)))) {
LbxFreeProxy(proxy);
xfree(replybuf);
return BadAlloc;
}
MakeClientGrabImpervious(client);
proxy->fd = ClientConnectionNumber(client);
if (negopt.streamOpts.streamCompInit) {
compHandle =
(*negopt.streamOpts.streamCompInit)(proxy->fd, negopt.streamOpts.streamCompArg);
if (!compHandle) {
LbxFreeProxy(proxy);
xfree(replybuf);
return BadAlloc;
}
}
proxy->ofirst = NULL;
proxy->olast = NULL;
if (!LbxInitClient (proxy, client, 0))
{
LbxFreeProxy(proxy);
xfree(replybuf);
return BadAlloc;
}
proxy->dosquishing = negopt.squish;
proxy->numBitmapCompMethods = negopt.numBitmapCompMethods;
proxy->bitmapCompMethods = negopt.bitmapCompMethods;
proxy->numPixmapCompMethods = negopt.numPixmapCompMethods;
proxy->pixmapCompMethods = negopt.pixmapCompMethods;
proxy->pixmapCompDepths = negopt.pixmapCompDepths;
proxy->streamOpts = negopt.streamOpts;
proxy->useTags = negopt.useTags;
proxy->grabbedCmaps = NULL;
replybuf->type = X_Reply;
replybuf->nOpts = negopt.nopts;
replybuf->sequenceNumber = client->sequence;
replylen += sz_xLbxStartReplyHdr;
if (replylen < sz_xLbxStartReply)
replylen = sz_xLbxStartReply;
replybuf->length = (replylen - sz_xLbxStartReply + 3) >> 2;
if (client->swapped) {
swaps(&replybuf->sequenceNumber, n);
swapl(&replybuf->length, n);
}
lbxClient = LbxClient(client);
WriteToClient(client, replylen, (char *)replybuf);
LbxProxyConnection(client, proxy);
lbxClient = proxy->lbxClients[0];
proxy->curDix = lbxClient;
proxy->curRecv = lbxClient;
proxy->compHandle = compHandle;
if (proxy->compHandle && !lbxCompressWorkProcCount++)
QueueWorkProc(LbxCheckCompressInput, NULL, NULL);
xfree(replybuf);
return Success;
}
int
ProcLbxStopProxy(ClientPtr client)
{
LbxProxyPtr proxy;
LbxClientPtr lbxClient = LbxClient(client);
REQUEST_SIZE_MATCH(xLbxStopProxyReq);
if (!lbxClient)
return BadLbxClientCode;
if (lbxClient->id)
return BadLbxClientCode;
proxy = lbxClient->proxy;
LbxFreeClient (client);
LbxShutdownProxy (proxy);
return Success;
}
int
ProcLbxSwitch(ClientPtr client)
{
REQUEST(xLbxSwitchReq);
LbxProxyPtr proxy = LbxMaybeProxy(client);
LbxClientPtr lbxClient;
int i;
REQUEST_SIZE_MATCH(xLbxSwitchReq);
if (!proxy)
return BadLbxClientCode;
for (i = 0; i <= proxy->maxIndex; i++) {
lbxClient = proxy->lbxClients[i];
if (lbxClient && lbxClient->id == stuff->client) {
LbxSwitchRecv (proxy, lbxClient);
return Success;
}
}
LbxSwitchRecv (proxy, NULL);
return BadLbxClientCode;
}
int
ProcLbxBeginLargeRequest(ClientPtr client)
{
REQUEST(xLbxBeginLargeRequestReq);
client->sequence--;
REQUEST_SIZE_MATCH(xLbxBeginLargeRequestReq);
if (!AllocateLargeReqBuffer(client, stuff->largeReqLength << 2))
return BadAlloc;
return Success;
}
int
ProcLbxLargeRequestData(ClientPtr client)
{
REQUEST(xLbxLargeRequestDataReq);
client->sequence--;
REQUEST_AT_LEAST_SIZE(xLbxLargeRequestDataReq);
if (!AddToLargeReqBuffer(client, (char *) (stuff + 1),
(client->req_len - 1) << 2))
return BadAlloc;
return Success;
}
int
ProcLbxEndLargeRequest(ClientPtr client)
{
client->sequence--;
REQUEST_SIZE_MATCH(xReq);
return BadAlloc;
}
int
ProcLbxInternAtoms(ClientPtr client)
{
REQUEST(xLbxInternAtomsReq);
LbxClientPtr lbxClient = LbxClient(client);
xLbxInternAtomsReply *replyRet;
char *ptr = (char *) stuff + sz_xLbxInternAtomsReq;
Atom *atomsRet;
int replyLen, i;
char lenbuf[2];
CARD16 len;
char n;
REQUEST_AT_LEAST_SIZE(xLbxInternAtomsReq);
if (!lbxClient)
return BadLbxClientCode;
if (lbxClient->id)
return BadLbxClientCode;
replyLen = sz_xLbxInternAtomsReplyHdr + stuff->num * sizeof (Atom);
if (replyLen < sz_xLbxInternAtomsReply)
replyLen = sz_xLbxInternAtomsReply;
if (!(replyRet = (xLbxInternAtomsReply *) xalloc (replyLen)))
return BadAlloc;
atomsRet = (Atom *) ((char *) replyRet + sz_xLbxInternAtomsReplyHdr);
for (i = 0; i < stuff->num; i++)
{
lenbuf[0] = ptr[0];
lenbuf[1] = ptr[1];
len = *((CARD16 *) lenbuf);
ptr += 2;
if ((atomsRet[i] = MakeAtom (ptr, len, TRUE)) == BAD_RESOURCE)
{
xfree (replyRet);
return BadAlloc;
}
ptr += len;
}
if (client->swapped)
for (i = 0; i < stuff->num; i++)
swapl (&atomsRet[i], n);
replyRet->type = X_Reply;
replyRet->sequenceNumber = client->sequence;
replyRet->length = (replyLen - sz_xLbxInternAtomsReply + 3) >> 2;
if (client->swapped) {
swaps(&replyRet->sequenceNumber, n);
swapl(&replyRet->length, n);
}
WriteToClient (client, replyLen, (char *) replyRet);
xfree (replyRet);
return Success;
}
int
ProcLbxGetWinAttrAndGeom(ClientPtr client)
{
REQUEST(xLbxGetWinAttrAndGeomReq);
xGetWindowAttributesReply wa;
xGetGeometryReply wg;
xLbxGetWinAttrAndGeomReply reply;
WindowPtr pWin;
int status;
REQUEST_SIZE_MATCH(xLbxGetWinAttrAndGeomReq);
pWin = (WindowPtr)SecurityLookupWindow(stuff->id, client,
SecurityReadAccess);
if (!pWin)
return(BadWindow);
GetWindowAttributes(pWin, client, &wa);
if ((status = GetGeometry(client, &wg)) != Success)
return status;
reply.type = X_Reply;
reply.length = (sz_xLbxGetWinAttrAndGeomReply - 32) >> 2;
reply.sequenceNumber = client->sequence;
reply.backingStore = wa.backingStore;
reply.visualID = wa.visualID;
#if defined(__cplusplus) || defined(c_plusplus)
reply.c_class = wa.c_class;
#else
reply.class = wa.class;
#endif
reply.bitGravity = wa.bitGravity;
reply.winGravity = wa.winGravity;
reply.backingBitPlanes = wa.backingBitPlanes;
reply.backingPixel = wa.backingPixel;
reply.saveUnder = wa.saveUnder;
reply.mapInstalled = wa.mapInstalled;
reply.mapState = wa.mapState;
reply.override = wa.override;
reply.colormap = wa.colormap;
reply.allEventMasks = wa.allEventMasks;
reply.yourEventMask = wa.yourEventMask;
reply.doNotPropagateMask = wa.doNotPropagateMask;
reply.pad1 = 0;
reply.root = wg.root;
reply.x = wg.x;
reply.y = wg.y;
reply.width = wg.width;
reply.height = wg.height;
reply.borderWidth = wg.borderWidth;
reply.depth = wg.depth;
reply.pad2 = 0;
if (client->swapped)
{
register char n;
swaps(&reply.sequenceNumber, n);
swapl(&reply.length, n);
swapl(&reply.visualID, n);
swaps(&reply.class, n);
swapl(&reply.backingBitPlanes, n);
swapl(&reply.backingPixel, n);
swapl(&reply.colormap, n);
swapl(&reply.allEventMasks, n);
swapl(&reply.yourEventMask, n);
swaps(&reply.doNotPropagateMask, n);
swapl(&reply.root, n);
swaps(&reply.x, n);
swaps(&reply.y, n);
swaps(&reply.width, n);
swaps(&reply.height, n);
swaps(&reply.borderWidth, n);
}
WriteToClient(client, sizeof(xLbxGetWinAttrAndGeomReply), (char *)&reply);
return(client->noClientException);
}
int
ProcLbxNewClient(ClientPtr client)
{
REQUEST(xLbxNewClientReq);
ClientPtr newClient;
LbxProxyPtr proxy = LbxMaybeProxy(client);
CARD32 id;
int len, i;
char *setupbuf;
LbxClientPtr lbxClient;
REQUEST_AT_LEAST_SIZE(xLbxNewClientReq);
id = stuff->client;
if (!proxy || !id)
return BadLbxClientCode;
if (proxy->numClients == MAX_LBX_CLIENTS)
return BadAlloc;
for (i = 1; i <= proxy->maxIndex; i++) {
if (proxy->lbxClients[i] && proxy->lbxClients[i]->id == id)
return BadLbxClientCode;
}
len = (client->req_len << 2) - sizeof(xLbxNewClientReq);
setupbuf = (char *)xalloc (len);
if (!setupbuf)
return BadAlloc;
memcpy (setupbuf, (char *)&stuff[1], len);
newClient = AllocLbxClientConnection (client, proxy);
if (!newClient)
return BadAlloc;
newClient->requestVector = LbxInitialVector;
lbxClient = LbxInitClient (proxy, newClient, id);
if (!lbxClient)
{
CloseDownClient (newClient);
return BadAlloc;
}
AppendFakeRequest (newClient, setupbuf, len);
xfree (setupbuf);
LbxSetForBlock(lbxClient);
DBG (DBG_CLIENT, (stderr, "lbxNewClient X %d\n", newClient->index));
return Success;
}
int
ProcLbxEstablishConnection(ClientPtr client)
{
char *reason = NULL;
char *auth_proto, *auth_string;
register xConnClientPrefix *prefix;
REQUEST(xReq);
prefix = (xConnClientPrefix *)((char *)stuff + sz_xReq);
auth_proto = (char *)prefix + sz_xConnClientPrefix;
auth_string = auth_proto + ((prefix->nbytesAuthProto + 3) & ~3);
if ((prefix->majorVersion != X_PROTOCOL) ||
(prefix->minorVersion != X_PROTOCOL_REVISION))
reason = "Protocol version mismatch";
else
reason = ClientAuthorized(client,
prefix->nbytesAuthProto,
auth_proto,
prefix->nbytesAuthString,
auth_string);
if (client->clientState == ClientStateCheckingSecurity ||
client->clientState == ClientStateAuthenticating)
return (client->noClientException = -1);
return(LbxSendConnSetup(client, reason));
}
int
ProcLbxCloseClient (ClientPtr client)
{
REQUEST(xLbxCloseClientReq);
LbxClientPtr lbxClient = LbxClient(client);
REQUEST_SIZE_MATCH(xLbxCloseClientReq);
if (!lbxClient || lbxClient->id != stuff->client)
return BadLbxClientCode;
return(client->noClientException = CloseLbxClient);
}
int
ProcLbxModifySequence (ClientPtr client)
{
REQUEST(xLbxModifySequenceReq);
REQUEST_SIZE_MATCH(xLbxModifySequenceReq);
client->sequence += (stuff->adjust - 1);
return Success;
}
int
ProcLbxAllowMotion (ClientPtr client)
{
REQUEST(xLbxAllowMotionReq);
client->sequence--;
REQUEST_SIZE_MATCH(xLbxAllowMotionReq);
LbxAllowMotion(client, stuff->num);
return Success;
}
static int
DecodeLbxDelta (ClientPtr client)
{
REQUEST(xLbxDeltaReq);
LbxClientPtr lbxClient = LbxClient(client);
LbxProxyPtr proxy = lbxClient->proxy;
int len;
unsigned char *buf;
len = LBXDecodeDelta(&proxy->indeltas,
(xLbxDiffItem *)(((char *)stuff) + sz_xLbxDeltaReq),
stuff->diffs, stuff->cindex, &buf);
memcpy(proxy->iDeltaBuf, buf, len);
client->requestBuffer = proxy->iDeltaBuf;
client->req_len = len >> 2;
return len;
}
int
ProcLbxGetModifierMapping(ClientPtr client)
{
REQUEST_SIZE_MATCH(xLbxGetModifierMappingReq);
return LbxGetModifierMapping(client);
}
int
ProcLbxGetKeyboardMapping(ClientPtr client)
{
REQUEST_SIZE_MATCH(xLbxGetKeyboardMappingReq);
return LbxGetKeyboardMapping(client);
}
int
ProcLbxQueryFont(ClientPtr client)
{
REQUEST_SIZE_MATCH(xLbxQueryFontReq);
return LbxQueryFont(client);
}
int
ProcLbxChangeProperty(ClientPtr client)
{
REQUEST_SIZE_MATCH(xLbxChangePropertyReq);
return LbxChangeProperty(client);
}
int
ProcLbxGetProperty(ClientPtr client)
{
REQUEST_SIZE_MATCH(xLbxGetPropertyReq);
return LbxGetProperty(client);
}
int
ProcLbxTagData(ClientPtr client)
{
REQUEST(xLbxTagDataReq);
client->sequence--;
REQUEST_AT_LEAST_SIZE(xLbxTagDataReq);
return LbxTagData(client, stuff->tag, stuff->real_length,
(pointer)&stuff[1]);
}
int
ProcLbxInvalidateTag(ClientPtr client)
{
REQUEST(xLbxInvalidateTagReq);
client->sequence--;
REQUEST_SIZE_MATCH(xLbxInvalidateTagReq);
return LbxInvalidateTag(client, stuff->tag);
}
int
ProcLbxPolyPoint(ClientPtr client)
{
return LbxDecodePoly(client, X_PolyPoint, LbxDecodePoints);
}
int
ProcLbxPolyLine(ClientPtr client)
{
return LbxDecodePoly(client, X_PolyLine, LbxDecodePoints);
}
int
ProcLbxPolySegment(ClientPtr client)
{
return LbxDecodePoly(client, X_PolySegment, LbxDecodeSegment);
}
int
ProcLbxPolyRectangle(ClientPtr client)
{
return LbxDecodePoly(client, X_PolyRectangle, LbxDecodeRectangle);
}
int
ProcLbxPolyArc(ClientPtr client)
{
return LbxDecodePoly(client, X_PolyArc, LbxDecodeArc);
}
int
ProcLbxFillPoly(ClientPtr client)
{
return LbxDecodeFillPoly(client);
}
int
ProcLbxPolyFillRectangle(ClientPtr client)
{
return LbxDecodePoly(client, X_PolyFillRectangle, LbxDecodeRectangle);
}
int
ProcLbxPolyFillArc(ClientPtr client)
{
return LbxDecodePoly(client, X_PolyFillArc, LbxDecodeArc);
}
int
ProcLbxCopyArea(ClientPtr client)
{
return LbxDecodeCopyArea(client);
}
int
ProcLbxCopyPlane(ClientPtr client)
{
return LbxDecodeCopyPlane(client);
}
int
ProcLbxPolyText(ClientPtr client)
{
return LbxDecodePolyText(client);
}
int
ProcLbxImageText(ClientPtr client)
{
return LbxDecodeImageText(client);
}
int
ProcLbxQueryExtension(ClientPtr client)
{
REQUEST(xLbxQueryExtensionReq);
char *ename;
REQUEST_AT_LEAST_SIZE(xLbxQueryExtensionReq);
ename = (char *) &stuff[1];
return LbxQueryExtension(client, ename, stuff->nbytes);
}
int
ProcLbxPutImage(ClientPtr client)
{
return LbxDecodePutImage(client);
}
int
ProcLbxGetImage(ClientPtr client)
{
return LbxDecodeGetImage(client);
}
int
ProcLbxSync(ClientPtr client)
{
xLbxSyncReply reply;
client->sequence--;
#ifdef COLOR_DEBUG
fprintf (stderr, "Got LBX sync, seq = 0x%x\n", client->sequence);
#endif
reply.type = X_Reply;
reply.length = 0;
reply.sequenceNumber = client->sequence;
reply.pad0 = reply.pad1 = reply.pad2 = reply.pad3 = reply.pad4 =
reply.pad5 = reply.pad6 = 0;
if (client->swapped)
{
register char n;
swaps (&reply.sequenceNumber, n);
}
WriteToClient (client, sz_xLbxSyncReply, (char *)&reply);
return (client->noClientException);
}
int
ProcLbxDispatch(ClientPtr client)
{
REQUEST(xReq);
switch (stuff->data)
{
case X_LbxQueryVersion:
return ProcLbxQueryVersion(client);
case X_LbxStartProxy:
return ProcLbxStartProxy(client);
case X_LbxStopProxy:
return ProcLbxStopProxy(client);
case X_LbxNewClient:
return ProcLbxNewClient(client);
case X_LbxCloseClient:
return ProcLbxCloseClient(client);
case X_LbxModifySequence:
return ProcLbxModifySequence(client);
case X_LbxAllowMotion:
return ProcLbxAllowMotion(client);
case X_LbxIncrementPixel:
return ProcLbxIncrementPixel(client);
case X_LbxGrabCmap:
return ProcLbxGrabCmap(client);
case X_LbxReleaseCmap:
return ProcLbxReleaseCmap(client);
case X_LbxAllocColor:
return ProcLbxAllocColor(client);
case X_LbxGetModifierMapping:
return ProcLbxGetModifierMapping(client);
case X_LbxGetKeyboardMapping:
return ProcLbxGetKeyboardMapping(client);
case X_LbxInvalidateTag:
return ProcLbxInvalidateTag(client);
case X_LbxPolyPoint:
return ProcLbxPolyPoint (client);
case X_LbxPolyLine:
return ProcLbxPolyLine (client);
case X_LbxPolySegment:
return ProcLbxPolySegment (client);
case X_LbxPolyRectangle:
return ProcLbxPolyRectangle (client);
case X_LbxPolyArc:
return ProcLbxPolyArc (client);
case X_LbxFillPoly:
return ProcLbxFillPoly (client);
case X_LbxPolyFillRectangle:
return ProcLbxPolyFillRectangle (client);
case X_LbxPolyFillArc:
return ProcLbxPolyFillArc (client);
case X_LbxQueryFont:
return ProcLbxQueryFont (client);
case X_LbxChangeProperty:
return ProcLbxChangeProperty (client);
case X_LbxGetProperty:
return ProcLbxGetProperty (client);
case X_LbxTagData:
return ProcLbxTagData (client);
case X_LbxCopyArea:
return ProcLbxCopyArea (client);
case X_LbxCopyPlane:
return ProcLbxCopyPlane (client);
case X_LbxPolyText8:
case X_LbxPolyText16:
return ProcLbxPolyText (client);
case X_LbxImageText8:
case X_LbxImageText16:
return ProcLbxImageText (client);
case X_LbxQueryExtension:
return ProcLbxQueryExtension (client);
case X_LbxPutImage:
return ProcLbxPutImage (client);
case X_LbxGetImage:
return ProcLbxGetImage (client);
case X_LbxInternAtoms:
return ProcLbxInternAtoms(client);
case X_LbxGetWinAttrAndGeom:
return ProcLbxGetWinAttrAndGeom(client);
case X_LbxSync:
return ProcLbxSync(client);
case X_LbxBeginLargeRequest:
return ProcLbxBeginLargeRequest(client);
case X_LbxLargeRequestData:
return ProcLbxLargeRequestData(client);
case X_LbxEndLargeRequest:
return ProcLbxLargeRequestData(client);
default:
return BadRequest;
}
}