#include "lbx.h"
#include <stdio.h>
#include <stdlib.h>
#include "wire.h"
#include "tags.h"
#include "colormap.h"
#include "init.h"
#ifndef Lynx
#include <sys/uio.h>
#else
#include <uio.h>
#endif
#include <errno.h>
#include "proxyopts.h"
#include "swap.h"
#include "assert.h"
#include "os.h"
#include "resource.h"
#include "colormap.h"
#include "lbxext.h"
#include "atomcache.h"
#include "util.h"
#include "pm.h"
#include "misc.h"
#include <X11/ICE/ICElib.h>
#ifdef BIGREQS
#include "bigreqstr.h"
#endif
#if (defined(_POSIX_SOURCE) && !defined(AIXV3) && !defined(__QNX__)) || defined(hpux) || defined(USG) || defined(SVR4)
#define NEED_UTSNAME
#include <sys/utsname.h>
#else
#include <unistd.h>
#endif
#ifdef LBX_STATS
extern int delta_out_total;
extern int delta_out_attempts;
extern int delta_out_hits;
extern int delta_in_total;
extern int delta_in_attempts;
extern int delta_in_hits;
#endif
#define MAXBYTESDIFF 8
#define PM_Unable 0
#define PM_Success 1
#define PM_Failure 2
int lbxDebug = 0;
static void LbxOnlyListenToOneClient();
static void LbxListenToAllClients();
void
WriteReqToServer(client, len, buf, checkLargeRequest)
ClientPtr client;
int len;
char *buf;
Bool checkLargeRequest;
{
XServerPtr server = client->server;
xLbxDeltaReq *p = (xLbxDeltaReq *) server->tempdeltabuf;
int diffs;
int cindex;
int newlen;
Bool written = FALSE;
#ifdef LBX_STATS
delta_out_total++;
#endif
if (DELTA_CACHEABLE(&server->outdeltas, len)) {
#ifdef LBX_STATS
delta_out_attempts++;
#endif
if ((diffs = LBXDeltaMinDiffs(&server->outdeltas, (unsigned char *)buf,
len, min(MAXBYTESDIFF, (len - sz_xLbxDeltaReq) >> 1),
&cindex)) >= 0) {
#ifdef LBX_STATS
delta_out_hits++;
#endif
LBXEncodeDelta(&server->outdeltas, (unsigned char *)buf, diffs,
cindex, &server->tempdeltabuf[sz_xLbxDeltaReq]);
p->reqType = server->lbxReq;
p->lbxReqType = X_LbxDelta;
p->diffs = diffs;
p->cindex = cindex;
newlen = sz_xLbxDeltaReq + sz_xLbxDiffItem * diffs;
p->length = (newlen + 3) >> 2;
WriteToServer(client, newlen, (char *) p, TRUE, checkLargeRequest);
written = TRUE;
}
LBXAddDeltaOut(&server->outdeltas, (unsigned char *)buf, len);
}
if (!written) {
#ifdef BIGREQS
if (len > (0xffff << 2)) {
xBigReq bigreq;
bigreq.reqType = ((xReq *)buf)->reqType;
bigreq.data = ((xReq *)buf)->data;
bigreq.zero = 0;
bigreq.length = (len + sizeof(xBigReq) - sizeof(xReq)) >> 2;
WriteToServer(client, sizeof(xBigReq), (char *)&bigreq,
TRUE, checkLargeRequest);
WriteToServer(client, len - sizeof(xReq), buf + sizeof(xReq),
FALSE, checkLargeRequest);
return;
}
#endif
WriteToServer(client, len, buf, TRUE, checkLargeRequest);
}
}
void
_write_to_server(client, compressed, len, buf, checkLarge, startOfRequest)
ClientPtr client;
Bool compressed;
int len;
char *buf;
Bool checkLarge;
Bool startOfRequest;
{
XServerPtr server = client->server;
unsigned reqSize;
if (server->serverClient->clientGone)
return;
if (checkLarge && client != clients[0] && nClients > 1 &&
((client != server->prev_exec) || numLargeRequestsInQueue)) {
if (startOfRequest &&
(!(reqSize = (((xReq *) buf)->length) << 2) ||
reqSize >= LBX_LARGE_REQUEST_MIN_SIZE) &&
numLargeRequestsInQueue < LARGE_REQUEST_QUEUE_LEN) {
LbxLargeRequestRec *largeRequest;
if (!reqSize)
reqSize = ((xBigReq *)buf)->length << 2;
largeRequest = (LbxLargeRequestRec *)
xalloc (sizeof (LbxLargeRequestRec) + reqSize);
largeRequest->client = client;
largeRequest->compressed = compressed;
largeRequest->buf = (char *) largeRequest +
sizeof (LbxLargeRequestRec);
memcpy (largeRequest->buf, buf, len);
largeRequest->totalBytes = reqSize;
largeRequest->bytesRead = len;
largeRequest->bytesWritten = 0;
client->largeRequest = largeRequest;
largeRequestQueue[numLargeRequestsInQueue++] = largeRequest;
if (reqSize == len)
IgnoreClient(client);
return;
} else if (client->largeRequest) {
char *dst = client->largeRequest->buf +
client->largeRequest->bytesRead;
memcpy (dst, buf, len);
client->largeRequest->bytesRead += len;
if (client->largeRequest->bytesRead ==
client->largeRequest->totalBytes)
IgnoreClient(client);
return;
}
}
if (server->send != client) {
xLbxSwitchReq s;
DBG(DBG_SWITCH, (stderr, "switch downstream to %d\n", client->index));
s.reqType = server->lbxReq;
s.lbxReqType = X_LbxSwitch;
s.length = 2;
s.client = client->index;
WriteToClient(server->serverClient, sizeof(s), &s);
server->send = client;
}
DBG(DBG_IO, (stderr, "downstream %d len %d\n", client->index, len));
if (compressed || !server->compHandle)
WriteToClient(server->serverClient, len, buf);
else
UncompressWriteToClient(server->serverClient, len, buf);
}
void
WriteToServer(client, len, buf, startOfRequest, checkLargeRequest)
ClientPtr client;
int len;
char *buf;
Bool startOfRequest;
Bool checkLargeRequest;
{
_write_to_server(client, TRUE, len, buf, checkLargeRequest, startOfRequest);
}
void
WriteToServerUncompressed(client, len, buf, startOfRequest)
ClientPtr client;
int len;
char *buf;
Bool startOfRequest;
{
_write_to_server(client, FALSE, len, buf, TRUE, startOfRequest);
}
Bool
NewClient(client, setuplen)
ClientPtr client;
int setuplen;
{
xLbxNewClientReq n;
XServerPtr server = client->server;
DBG(DBG_CLIENT, (stderr, "new client %d\n", client->index));
n.reqType = server->lbxReq;
n.lbxReqType = X_LbxNewClient;
n.length = 2 + (setuplen >> 2);
n.client = client->index;
WriteToServer(server->serverClient, sizeof(n), (char *) &n, TRUE, FALSE);
++server->serverClient->sequence;
return TRUE;
}
void
CloseClient(client)
ClientPtr client;
{
xLbxCloseClientReq n;
XServerPtr server = client->server;
if (!client->server)
return;
if (client->server->serverClient == client)
return;
if (client->server->serverClient->clientGone)
return;
DBG(DBG_CLIENT, (stderr, "closing down client %d\n", client->index));
if (client->closeDownMode != DestroyAll) {
n.reqType = server->lbxReq;
n.lbxReqType = X_LbxCloseClient;
n.length = 2;
n.client = client->index;
if (client->swapped) {
SwapCloseClient(&n);
}
WriteReqToServer(client, sizeof(n), (char *) &n, TRUE);
}
}
void
ModifySequence(client, num)
ClientPtr client;
int num;
{
xLbxModifySequenceReq req;
XServerPtr server = client->server;
if (client->server->serverClient == client)
return;
req.reqType = server->lbxReq;
req.lbxReqType = X_LbxModifySequence;
req.length = 2;
req.adjust = num;
if (client->swapped) {
SwapModifySequence(&req);
}
WriteReqToServer(client, sizeof(req), (char *) &req, TRUE);
}
void
AllowMotion(client, num)
ClientPtr client;
int num;
{
client->server->motion_allowed += num;
}
void
SendIncrementPixel(client, cmap, pixel)
ClientPtr client;
XID cmap;
unsigned long pixel;
{
xLbxIncrementPixelReq req;
XServerPtr server = client->server;
if (client->server->serverClient == client)
return;
req.reqType = server->lbxReq;
req.lbxReqType = X_LbxIncrementPixel;
req.length = 3;
req.cmap = cmap;
req.pixel = pixel;
if (client->swapped) {
SwapIncrementPixel(&req);
}
WriteReqToServer(client, sizeof(req), (char *) &req, TRUE);
}
void
SendAllocColor(
ClientPtr client,
XID cmap,
CARD32 pixel,
CARD16 red,
CARD16 green,
CARD16 blue)
{
xLbxAllocColorReq req;
req.reqType = client->server->lbxReq;
req.lbxReqType = X_LbxAllocColor;
req.length = sz_xLbxAllocColorReq >> 2;
req.cmap = cmap;
req.pixel = pixel;
req.red = red;
req.green = green;
req.blue = blue;
req.pad = 0;
if (client->swapped)
SwapAllocColor (&req);
WriteReqToServer (client, sizeof(req), (char *) &req, TRUE);
}
void
SendGetModifierMapping(client)
ClientPtr client;
{
xLbxGetModifierMappingReq req;
XServerPtr server = client->server;
if (client->server->serverClient == client)
return;
req.reqType = server->lbxReq;
req.lbxReqType = X_LbxGetModifierMapping;
req.length = 1;
if (client->swapped) {
SwapGetModifierMapping(&req);
}
WriteReqToServer(client, sizeof(req), (char *) &req, TRUE);
}
void
SendGetKeyboardMapping(client)
ClientPtr client;
{
xLbxGetKeyboardMappingReq req;
XServerPtr server = client->server;
if (client->server->serverClient == client)
return;
req.reqType = server->lbxReq;
req.lbxReqType = X_LbxGetKeyboardMapping;
req.length = 2;
req.firstKeyCode = LBXMinKeyCode(client);
req.count = LBXMaxKeyCode(client) - LBXMinKeyCode(client) + 1;
req.pad1 = 0;
if (client->swapped) {
SwapGetKeyboardMapping(&req);
}
WriteReqToServer(client, sizeof(req), (char *) &req, TRUE);
}
void
SendQueryFont(client, fid)
ClientPtr client;
XID fid;
{
xLbxQueryFontReq req;
XServerPtr server = client->server;
if (client->server->serverClient == client)
return;
req.reqType = server->lbxReq;
req.lbxReqType = X_LbxQueryFont;
req.length = 2;
req.fid = fid;
if (client->swapped) {
SwapQueryFont(&req);
}
WriteReqToServer(client, sizeof(req), (char *) &req, TRUE);
}
void
SendChangeProperty(client, win, prop, type, format, mode, num)
ClientPtr client;
Window win;
Atom prop,
type;
int format,
mode;
unsigned long num;
{
xLbxChangePropertyReq req;
XServerPtr server = client->server;
if (client->server->serverClient == client)
return;
req.reqType = server->lbxReq;
req.lbxReqType = X_LbxChangeProperty;
req.length = 6;
req.window = win;
req.property = prop;
req.type = type;
req.format = format;
req.mode = mode;
req.nUnits = num;
req.pad[0] = req.pad[1] = 0;
if (client->swapped) {
SwapChangeProperty(&req);
}
WriteReqToServer(client, sizeof(req), (char *) &req, TRUE);
}
void
SendGetProperty(client, win, prop, type, delete, off, len)
ClientPtr client;
Window win;
Atom prop,
type;
Bool delete;
unsigned long off,
len;
{
xLbxGetPropertyReq req;
XServerPtr server = client->server;
if (client->server->serverClient == client)
return;
req.reqType = server->lbxReq;
req.lbxReqType = X_LbxGetProperty;
req.length = 7;
req.window = win;
req.property = prop;
req.type = type;
req.delete = delete;
req.longOffset = off;
req.longLength = len;
req.pad[0] = req.pad[1] = req.pad[2] = 0;
if (client->swapped) {
SwapGetProperty(&req);
}
WriteReqToServer(client, sizeof(req), (char *) &req, TRUE);
}
void
SendInvalidateTag(client, tag)
ClientPtr client;
XID tag;
{
xLbxInvalidateTagReq req;
XServerPtr server;
if (!servers[0])
return;
server = client->server;
req.reqType = server->lbxReq;
req.lbxReqType = X_LbxInvalidateTag;
req.length = 2;
req.tag = tag;
if (client->swapped) {
SwapInvalidateTag(&req);
}
WriteReqToServer(client, sizeof(req), (char *) &req, TRUE);
}
void
SendTagData(client, tag, len, data)
ClientPtr client;
XID tag;
unsigned long len;
pointer data;
{
xLbxTagDataReq req,
*reqp;
int req_len;
XServerPtr server;
server = client->server;
req_len = 3 + ((len + 3) >> 2);
if (DELTA_CACHEABLE(&server->outdeltas, req_len << 2)) {
reqp = (xLbxTagDataReq *) xalloc(req_len << 2);
memcpy((pointer) (reqp + 1), data, len);
} else {
reqp = &req;
}
reqp->reqType = server->lbxReq;
reqp->lbxReqType = X_LbxTagData;
reqp->length = req_len;
reqp->real_length = len;
reqp->tag = tag;
if (reqp == &req) {
WriteToServer(server->serverClient,
sizeof(req), (char *) &req, TRUE, FALSE);
if (len)
WriteToServer(server->serverClient,
len, (char *) data, FALSE, FALSE);
} else {
WriteReqToServer(server->serverClient,
req_len << 2, (char *) reqp, FALSE);
xfree(reqp);
}
}
void
SendGetImage(client, drawable, x, y, width, height, planeMask, format)
ClientPtr client;
Drawable drawable;
int x;
int y;
unsigned int width;
unsigned int height;
unsigned long planeMask;
int format;
{
xLbxGetImageReq req;
XServerPtr server = client->server;
if (client->server->serverClient == client)
return;
req.reqType = server->lbxReq;
req.lbxReqType = X_LbxGetImage;
req.length = 6;
req.drawable = drawable;
req.x = x;
req.y = y;
req.width = width;
req.height = height;
req.planeMask = planeMask;
req.format = format;
req.pad1 = 0;
req.pad2 = 0;
if (client->swapped) {
SwapGetImage(&req);
}
WriteReqToServer(client, sizeof(req), (char *) &req, TRUE);
}
static Bool
SendInternAtoms (server)
XServerPtr server;
{
xLbxInternAtomsReq *req;
int reqSize, i, num;
char lenbuf[2];
char *ptr;
reqSize = sz_xLbxInternAtomsReq;
num = 0;
for (i = 0; i < server->atom_control_count; i++) {
if (server->atom_control[i].flags & AtomPreInternFlag) {
reqSize += (2 + server->atom_control[i].len);
num++;
}
}
if (!num)
return FALSE;
if (!(req = (xLbxInternAtomsReq *) xalloc (reqSize)))
return FALSE;
req->reqType = server->lbxReq;
req->lbxReqType = X_LbxInternAtoms;
req->length = (reqSize + 3) >> 2;
req->num = num;
ptr = (char *) req + sz_xLbxInternAtomsReq;
for (i = 0; i < server->atom_control_count; i++)
{
if (server->atom_control[i].flags & AtomPreInternFlag) {
*((CARD16 *) lenbuf) = server->atom_control[i].len;
ptr[0] = lenbuf[0];
ptr[1] = lenbuf[1];
ptr += 2;
memcpy (ptr,
server->atom_control[i].name,
server->atom_control[i].len);
ptr += server->atom_control[i].len;
}
}
WriteToClient(server->serverClient, reqSize, (char *) req);
xfree (req);
return TRUE;
}
static void
InternAtomsReply (server, rep)
XServerPtr server;
xLbxInternAtomsReply *rep;
{
Atom *atoms = (Atom *) ((char *) rep + sz_xLbxInternAtomsReplyHdr);
int i;
for (i = 0; i < server->atom_control_count; i++) {
if (server->atom_control[i].flags & AtomPreInternFlag)
(void) LbxMakeAtom (server,
server->atom_control[i].name,
server->atom_control[i].len,
*atoms++, TRUE);
}
SendInitLBXPackets(server);
(void) ListenWellKnownSockets ();
}
static unsigned long pendingServerReplySequence;
static void (*serverReplyFunc) ();
static void
ServerReply(server, rep)
XServerPtr server;
xReply *rep;
{
if (serverReplyFunc &&
rep->generic.sequenceNumber == pendingServerReplySequence) {
(*serverReplyFunc) (server, rep);
if (rep->generic.sequenceNumber == pendingServerReplySequence)
serverReplyFunc = 0;
}
}
static void
ExpectServerReply(server, func)
XServerPtr server;
void (*func) ();
{
pendingServerReplySequence = server->serverClient->sequence;
serverReplyFunc = func;
}
extern int (*ServerVector[]) ();
static unsigned long
ServerRequestLength(req, sc, gotnow, partp)
xReq *req;
ClientPtr sc;
int gotnow;
Bool *partp;
{
XServerPtr server = servers[sc->lbxIndex];
ClientPtr client = server->recv;
xReply *rep;
xConnSetupPrefix *pre;
if (!req)
req = (xReq *) sc->requestBuffer;
if (gotnow < sizeof(xReq)) {
*partp = TRUE;
return sizeof(xReq);
}
if (req->reqType == server->lbxEvent && req->data == LbxDeltaEvent) {
*partp = FALSE;
return req->length << 2;
}
if (req->reqType == server->lbxEvent && req->data == LbxSwitchEvent) {
*partp = FALSE;
return sz_xLbxSwitchEvent;
}
if (req->reqType == server->lbxEvent + LbxQuickMotionDeltaEvent) {
*partp = FALSE;
return sz_lbxQuickMotionDeltaEvent;
}
if (req->reqType == server->lbxEvent && req->data == LbxMotionDeltaEvent) {
*partp = FALSE;
return sz_lbxMotionDeltaEvent;
}
if (client->awaitingSetup) {
if (gotnow < 8) {
*partp = TRUE;
return 8;
}
pre = (xConnSetupPrefix *) req;
*partp = FALSE;
return 8 + (pre->length << 2);
}
if (gotnow < 8) {
*partp = TRUE;
return 8;
}
*partp = FALSE;
rep = (xReply *) req;
if (rep->generic.type != X_Reply) {
return EventLength((xEvent *)rep, server->lbxNegOpt.squish);
}
return sz_xReply + (rep->generic.length << 2);
}
int
ServerProcStandardEvent(sc)
ClientPtr sc;
{
xReply *rep;
XServerPtr server = servers[sc->lbxIndex];
ClientPtr client = server->recv;
int len;
Bool part;
Bool cacheable = (server->initialized) ? TRUE : FALSE;
rep = (xReply *) sc->requestBuffer;
len = RequestLength(rep, sc, 8, &part);
#ifdef LBX_STATS
delta_in_total++;
#endif
if (rep->generic.type == server->lbxEvent &&
rep->generic.data1 == LbxDeltaEvent) {
xLbxDeltaReq *delta = (xLbxDeltaReq *) rep;
#ifdef LBX_STATS
delta_in_attempts++;
delta_in_hits++;
#endif
len = LBXDecodeDelta(&server->indeltas,
(xLbxDiffItem *)((char *) rep + sz_xLbxDeltaReq),
delta->diffs, delta->cindex,
(unsigned char **)&rep);
memcpy(server->tempdeltabuf, (char *) rep, len);
rep = (xReply *) server->tempdeltabuf;
cacheable = FALSE;
}
if (cacheable && DELTA_CACHEABLE(&server->indeltas, len)) {
#ifdef LBX_STATS
delta_in_attempts++;
#endif
LBXAddDeltaIn(&server->indeltas, (unsigned char *) rep, len);
}
if (rep->generic.type == server->lbxEvent &&
rep->generic.data1 != LbxMotionDeltaEvent) {
switch (rep->generic.data1) {
case LbxSwitchEvent:
DBG(DBG_SWITCH, (stderr, "switch upstream to %d\n",
((xLbxSwitchEvent *)rep)->client));
client = clients[((xLbxSwitchEvent *)rep)->client];
server->recv = client;
(void) CheckPendingClientInput(sc);
break;
case LbxCloseEvent:
DBG(DBG_CLIENT, (stderr, "close client %d\n",
((xLbxCloseEvent *)rep)->client));
client = clients[((xLbxCloseEvent *)rep)->client];
client->closeDownMode = DestroyAll;
CloseDownClient(client);
break;
case LbxInvalidateTagEvent:
DBG(DBG_CLIENT, (stderr, "invalidate tag %d type %d\n",
((xLbxInvalidateTagEvent *)rep)->tag,
((xLbxInvalidateTagEvent *)rep)->tagType));
LbxFreeTag(server,
((xLbxInvalidateTagEvent *)rep)->tag,
((xLbxInvalidateTagEvent *)rep)->tagType);
break;
case LbxSendTagDataEvent:
DBG(DBG_CLIENT, (stderr, "send tag data %d type %d\n",
((xLbxSendTagDataEvent *)rep)->tag,
((xLbxSendTagDataEvent *)rep)->tagType));
LbxSendTagData(sc,
((xLbxSendTagDataEvent *)rep)->tag,
((xLbxSendTagDataEvent *)rep)->tagType);
break;
case LbxListenToOne:
DBG(DBG_CLIENT, (stderr, "listen to one client %d\n",
((xLbxListenToOneEvent *)rep)->client));
if (((xLbxListenToOneEvent *)rep)->client == 0xffffffff)
LbxOnlyListenToOneClient(server->serverClient);
else
LbxOnlyListenToOneClient(clients[((xLbxListenToOneEvent *)rep)->client]);
break;
case LbxListenToAll:
DBG(DBG_CLIENT, (stderr, "listen to all clients\n"));
LbxListenToAllClients(server);
break;
case LbxReleaseCmapEvent:
{
Colormap cmap = ((xLbxReleaseCmapEvent *)rep)->colormap;
ColormapPtr pmap;
pmap = (ColormapPtr) LookupIDByType (client, cmap, RT_COLORMAP);
#ifdef COLOR_DEBUG
fprintf (stderr, "\nGot LbxReleaseCmapEvent, cmap = 0x%x\n\n", cmap);
#endif
if (pmap && pmap->grab_status == CMAP_GRABBED)
ReleaseCmap (client, pmap);
break;
}
case LbxFreeCellsEvent:
{
Colormap cmap = ((xLbxFreeCellsEvent *)rep)->colormap;
Pixel start = ((xLbxFreeCellsEvent *)rep)->pixelStart;
Pixel end = ((xLbxFreeCellsEvent *)rep)->pixelEnd;
ColormapPtr pmap;
pmap = (ColormapPtr) LookupIDByType (client, cmap, RT_COLORMAP);
#ifdef COLOR_DEBUG
fprintf (stderr, "\nGot LbxFreeCellsEvent, cmap = 0x%x, ", cmap);
fprintf (stderr, "startPixel = %d, endPixel = %d\n\n",
start, end);
#endif
if (pmap && pmap->grab_status == CMAP_GRABBED)
GotServerFreeCellsEvent (pmap, start, end);
break;
}
}
} else if ((rep->generic.type == server->lbxEvent &&
rep->generic.data1 == LbxMotionDeltaEvent) ||
(rep->generic.type == server->lbxEvent + LbxQuickMotionDeltaEvent))
{
lbxMotionCache *motionCache = &server->motionCache;
AllowMotion(client, 1);
if (rep->generic.type == server->lbxEvent)
{
lbxMotionDeltaEvent *mev = (lbxMotionDeltaEvent *) rep;
motionCache->sequenceNumber += mev->deltaSequence;
motionCache->time += mev->deltaTime;
motionCache->rootX += mev->deltaX;
motionCache->rootY += mev->deltaY;
motionCache->eventX += mev->deltaX;
motionCache->eventY += mev->deltaY;
}
else
{
lbxQuickMotionDeltaEvent *qmev = (lbxQuickMotionDeltaEvent *) rep;
motionCache->time += qmev->deltaTime;
motionCache->rootX += qmev->deltaX;
motionCache->rootY += qmev->deltaY;
motionCache->eventX += qmev->deltaX;
motionCache->eventY += qmev->deltaY;
}
if (!client->clientGone) {
xEvent ev;
int n;
if (motionCache->swapped != client->swapped)
{
swapl (&motionCache->root, n);
swapl (&motionCache->event, n);
swapl (&motionCache->child, n);
swaps (&motionCache->state, n);
motionCache->swapped = client->swapped;
}
ev.u.u.type = MotionNotify;
ev.u.u.detail = motionCache->detail;
ev.u.u.sequenceNumber = motionCache->sequenceNumber;
ev.u.keyButtonPointer.time = motionCache->time;
ev.u.keyButtonPointer.rootX = motionCache->rootX;
ev.u.keyButtonPointer.rootY = motionCache->rootY;
ev.u.keyButtonPointer.eventX = motionCache->eventX;
ev.u.keyButtonPointer.eventY = motionCache->eventY;
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;
if (client->swapped) {
swaps (&ev.u.u.sequenceNumber, n);
swapl (&ev.u.keyButtonPointer.time, n);
swaps (&ev.u.keyButtonPointer.rootX, n);
swaps (&ev.u.keyButtonPointer.rootY, n);
swaps (&ev.u.keyButtonPointer.eventX, n);
swaps (&ev.u.keyButtonPointer.eventY, n);
}
DoLBXReply (client, (char *) &ev, sz_xEvent);
}
} else {
len = RequestLength(rep, sc, 8, &part);
DBG(DBG_IO, (stderr, "upstream %d len %d\n", client->index, len));
if (client->index == 0) {
ServerReply(server, rep);
} else {
xEvent ev;
char *rp;
int n;
if (!client->awaitingSetup && UnsquishEvent(rep, &ev, &len))
rp = (char *) &ev;
else
rp = (char *) rep;
if (rep->generic.type == MotionNotify) {
xEvent *mev = (xEvent *) rp;
lbxMotionCache *motionCache = &server->motionCache;
AllowMotion(client, 1);
motionCache->swapped = client->swapped;
motionCache->detail = mev->u.u.detail;
motionCache->root = mev->u.keyButtonPointer.root;
motionCache->event = mev->u.keyButtonPointer.event;
motionCache->child = mev->u.keyButtonPointer.child;
motionCache->state = mev->u.keyButtonPointer.state;
motionCache->sameScreen = mev->u.keyButtonPointer.sameScreen;
motionCache->sequenceNumber = mev->u.u.sequenceNumber;
motionCache->time = mev->u.keyButtonPointer.time;
motionCache->rootX = mev->u.keyButtonPointer.rootX;
motionCache->rootY = mev->u.keyButtonPointer.rootY;
motionCache->eventX = mev->u.keyButtonPointer.eventX;
motionCache->eventY = mev->u.keyButtonPointer.eventY;
if (client->swapped)
{
swaps(&motionCache->sequenceNumber, n);
swapl(&motionCache->time, n);
swaps(&motionCache->rootX, n);
swaps(&motionCache->rootY, n);
swaps(&motionCache->eventX, n);
swaps(&motionCache->eventY, n);
}
}
if (!client->clientGone)
DoLBXReply (client, rp, len);
client->awaitingSetup = FALSE;
}
}
return Success;
}
static void
LbxIgnoreAllClients(server)
XServerPtr server;
{
if (!server->lbxIgnoringAll) {
if (GrabInProgress) {
server->lbxGrabInProgress = GrabInProgress;
ListenToAllClients();
}
OnlyListenToOneClient(server->serverClient);
server->lbxIgnoringAll = TRUE;
}
}
static void
LbxAttendAllClients(server)
XServerPtr server;
{
if (server->lbxIgnoringAll) {
ListenToAllClients();
server->lbxIgnoringAll = FALSE;
if (server->lbxGrabInProgress) {
OnlyListenToOneClient(clients[server->lbxGrabInProgress]);
server->lbxGrabInProgress = 0;
}
}
}
static void
LbxOnlyListenToOneClient(client)
ClientPtr client;
{
return;
}
static void
LbxListenToAllClients(server)
XServerPtr server;
{
return;
}
static Bool
ProxyWorkProc(dummy, index)
pointer dummy;
int index;
{
XServerPtr server;
xLbxAllowMotionReq req;
if ((server = servers[index]) == 0)
return TRUE;
if (!server->initialized)
return TRUE;
if (server->motion_allowed) {
DBG(DBG_CLIENT, (stderr, "allow %d motion events\n",
server->motion_allowed));
req.reqType = server->lbxReq;
req.lbxReqType = X_LbxAllowMotion;
req.length = 2;
req.num = server->motion_allowed;
server->motion_allowed = 0;
WriteToClient(server->serverClient, sizeof(req), &req);
}
if (NewOutputPending)
FlushAllOutput();
if (server->compHandle) {
if (server->lbxNegOpt.streamOpts.streamCompInputAvail(server->fd))
AvailableClientInput(server->serverClient);
if (server->lbxNegOpt.streamOpts.streamCompFlush(server->fd) != 0)
MarkConnectionWriteBlocked(server->serverClient);
}
if (PendingClientOutput(server->serverClient))
LbxIgnoreAllClients(server);
else
LbxAttendAllClients(server);
return FALSE;
}
Bool reconnectAfterCloseServer = FALSE;
void
CloseServer(client)
ClientPtr client;
{
XServerPtr server;
int i;
int found;
DBG(DBG_CLOSE, (stderr, "closing down server\n"));
server = client->server;
servers[server->index] = 0;
LBXFreeDeltaCache(&server->indeltas);
LBXFreeDeltaCache(&server->outdeltas);
if (server->compHandle)
server->lbxNegOpt.streamOpts.streamCompFreeHandle(server->compHandle);
for (found = 0, i = 0; i < lbxMaxServers; i++) {
if (servers[i]) {
found = 1;
break;
}
}
if (!found && !reconnectAfterCloseServer)
dispatchException |= DE_TERMINATE;
for (i = 1; i < currentMaxClients; i++) {
if (clients[i] &&
clients[i] != client &&
clients[i]->server == server) {
client->clientGone = TRUE;
CloseClient (clients[i]);
FreeClientResources (clients[i]);
CloseDownConnection (clients[i]);
if (clients[i]->index < nextFreeClientID)
nextFreeClientID = clients[i]->index;
clients[i] = NullClient;
xfree (clients[i]);
--nClients;
while (!clients[currentMaxClients-1])
currentMaxClients--;
}
}
for (i=0; i < MAXTRANSPORTS; i++)
if (server->listen_fds[i] != -1) {
close (server->listen_fds[i]);
FD_CLR (server->listen_fds[i], &WellKnownConnections);
FD_CLR (server->listen_fds[i], &AllSockets);
}
for (i = 1; i < currentMaxClients; i++) {
if (clients[i] && clients[i]->server == server)
clients[i]->server = NULL;
}
if (reconnectAfterCloseServer && !ConnectToServer (server->display_name)) {
fprintf (stderr, "could not reconnect to '%s'\n", server->display_name);
if (!found && !proxyMngr)
dispatchException |= DE_TERMINATE;
}
if (server->display_name)
free (server->display_name);
if (server->proxy_name)
free (server->proxy_name);
xfree (server->requestVector);
xfree(server);
CloseDownFileDescriptor(client);
isItTimeToYield = 1;
}
static void
StartProxyReply(server, rep)
XServerPtr server;
xLbxStartReply *rep;
{
int replylen;
replylen = (rep->length << 2) + sz_xLbxStartReply - sz_xLbxStartReplyHdr;
if (rep->nOpts == 0xff) {
fprintf(stderr, "WARNING: option negotiation failed - using defaults\n");
LbxOptInit(server);
} else if (LbxOptParseReply(server, rep->nOpts,
(unsigned char *)&rep->optDataStart, replylen) < 0) {
FatalError("Bad options from server");
}
#ifdef OPTDEBUG
fprintf(stderr, "server: N = %d, maxlen = %d, proxy: N = %d, maxlen = %d\n",
server->lbxNegOpt.serverDeltaN, server->lbxNegOpt.serverDeltaMaxLen,
server->lbxNegOpt.proxyDeltaN, server->lbxNegOpt.proxyDeltaMaxLen);
#endif
LBXInitDeltaCache(&server->indeltas, server->lbxNegOpt.serverDeltaN,
server->lbxNegOpt.serverDeltaMaxLen);
LBXInitDeltaCache(&server->outdeltas, server->lbxNegOpt.proxyDeltaN,
server->lbxNegOpt.proxyDeltaMaxLen);
QueueWorkProc(ProxyWorkProc, NULL, (pointer)(long) server->index);
#ifdef OPTDEBUG
fprintf(stderr, "squishing = %d\n", server->lbxNegOpt.squish);
fprintf(stderr, "useTags = %d\n", server->lbxNegOpt.useTags);
#endif
TagsInit(server, server->lbxNegOpt.useTags);
if (!server->lbxNegOpt.useTags)
{
ProcVector[X_GetModifierMapping] = ProcStandardRequest;
ProcVector[X_GetKeyboardMapping] = ProcStandardRequest;
ProcVector[X_QueryFont] = ProcStandardRequest;
ProcVector[X_ChangeProperty] = ProcStandardRequest;
ProcVector[X_GetProperty] = ProcStandardRequest;
}
if (server->lbxNegOpt.streamOpts.streamCompInit) {
unsigned char *extra = (unsigned char *) rep;
int len = sizeof(xReply) + (rep->length << 2);
int left = BytesInClientBuffer(server->serverClient);
server->compHandle =
(*server->lbxNegOpt.streamOpts.streamCompInit) (
server->fd, server->lbxNegOpt.streamOpts.streamCompArg);
SwitchConnectionFuncs(server->serverClient,
server->lbxNegOpt.streamOpts.streamCompRead,
server->lbxNegOpt.streamOpts.streamCompWriteV);
extra += len;
server->lbxNegOpt.streamOpts.streamCompStuffInput(server->fd,
extra,
left);
SkipInClientBuffer(server->serverClient, left + len, 0);
StartOutputCompression(server->serverClient,
server->lbxNegOpt.streamOpts.streamCompOn,
server->lbxNegOpt.streamOpts.streamCompOff);
}
server->initialized = TRUE;
MakeClientGrabImpervious(server->serverClient);
if (SendInternAtoms(server))
ExpectServerReply (server, InternAtomsReply);
else
{
SendInitLBXPackets(server);
(void) ListenWellKnownSockets ();
}
}
static void
StartProxy(server)
XServerPtr server;
{
char buf[1024];
int reqlen;
xLbxStartProxyReq *n = (xLbxStartProxyReq *) buf;
LbxOptInit(server);
n->reqType = server->lbxReq;
n->lbxReqType = X_LbxStartProxy;
reqlen = LbxOptBuildReq(server, buf + sz_xLbxStartProxyReq);
assert(reqlen > 0 && reqlen + sz_xLbxStartProxyReq <= 1024);
n->length = (reqlen + sz_xLbxStartProxyReq + 3) >> 2;
WriteToClient(server->serverClient, n->length << 2, (char *) n);
server->serverClient->sequence++;
ExpectServerReply(server, StartProxyReply);
while (NewOutputPending)
FlushAllOutput();
}
static Bool
InitServer (dpy_name, i, server, sequencep)
char* dpy_name;
int i;
XServerPtr server;
int* sequencep;
{
server->index = i;
DBG(DBG_IO, (stderr, "making server connection\n"));
server->dpy = DisplayOpen (dpy_name,
&server->lbxReq,
&server->lbxEvent,
&server->lbxError,
sequencep);
if (!server->dpy) return FALSE;
server->fd = DisplayConnectionNumber (server->dpy);
server->compHandle = NULL;
server->initialized = FALSE;
server->prev_exec = clients[0];
server->send = clients[0];
server->recv = clients[0];
server->motion_allowed = 0;
server->wm_running = FALSE;
server->extensions = NULL;
server->atom_control_count = 0;
server->atom_control = NULL;
LBXReadAtomsFile(server);
server->num_caches = 0;
server->seed = 0;
server->requestVector = (int (**)()) xalloc (sizeof (ProcVector));
if (!server->requestVector) return FALSE;
memcpy (server->requestVector, ProcVector, sizeof (ProcVector));
server->lastLbxClientIndexLookup = NULL;
server->lbxIgnoringAll = 0;
server->lbxGrabInProgress = 0;
return TRUE;
}
Bool
ConnectToServer(dpy_name)
char *dpy_name;
{
int i, j;
XServerPtr server;
int sequence;
ClientPtr sc;
static int been_there;
static char my_host[250];
char proxy_address[250+6];
#ifdef NEED_UTSNAME
struct utsname name;
#endif
for (i = 0; i < lbxMaxServers; i++)
if (!servers[i])
break;
if (i == lbxMaxServers) {
if (proxyMngr)
SendGetProxyAddrReply( PM_iceConn, PM_Unable, NULL,
"too many servers" );
return FALSE;
}
server = (XServerPtr) xalloc(sizeof(XServerRec));
if (!server) {
if (proxyMngr)
SendGetProxyAddrReply( PM_iceConn, PM_Unable, NULL,
"memory allocation failure");
return FALSE;
}
bzero(server, sizeof(XServerRec));
if (!InitServer (dpy_name, i, server, &sequence)) {
if (proxyMngr) {
(void) snprintf (proxy_address, sizeof(proxy_address),
"could not connect to server '%s'",
dpy_name);
SendGetProxyAddrReply( PM_iceConn, PM_Failure, NULL, proxy_address);
}
xfree(server);
return FALSE;
}
for (j=0; j < MAXTRANSPORTS; j++)
server->listen_fds[j] = -1;
CreateServerSockets(server->listen_fds);
if (!been_there || i == 0) {
been_there++;
clients[0]->server = server;
#ifdef NEED_UTSNAME
uname (&name);
(void) snprintf(my_host,sizeof(my_host),"%s",name.nodename);
#else
(void) gethostname (my_host,sizeof(my_host));
#endif
}
if (snprintf (proxy_address, sizeof(proxy_address) ,"%s:%s", my_host,
display) >= sizeof(proxy_address)) {
(void) snprintf (proxy_address, sizeof(proxy_address),
"display name too long");
SendGetProxyAddrReply( PM_iceConn, PM_Failure, NULL, proxy_address);
return FALSE;
}
servers[i] = server;
sc = AllocNewConnection(server->fd, -1, TRUE, NULL);
sc->server = server;
sc->public.requestLength = ServerRequestLength;
sc->lbxIndex = i;
sc->requestVector = ServerVector;
sc->awaitingSetup = FALSE;
sc->sequence = sequence;
InitClientResources(sc);
server->serverClient = sc;
server->proxy_name = strdup (proxy_address);
if (dpy_name)
server->display_name = strdup (dpy_name);
StartProxy(server);
if (proxyMngr) {
SendGetProxyAddrReply( PM_iceConn, PM_Success, proxy_address, NULL );
}
return TRUE;
}