1598 lines
42 KiB
C
1598 lines
42 KiB
C
/* $Xorg: wire.c,v 1.4 2001/02/09 02:05:32 xorgcvs Exp $ */
|
|
/*
|
|
|
|
Copyright 1998 The Open Group
|
|
|
|
Permission to use, copy, modify, distribute, and sell this software and its
|
|
documentation for any purpose is hereby granted without fee, provided that
|
|
the above copyright notice appear in all copies and that both that
|
|
copyright notice and this permission notice appear in supporting
|
|
documentation.
|
|
|
|
The above copyright notice and this permission notice shall be included in
|
|
all copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
|
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
Except as contained in this notice, the name of The Open Group shall not be
|
|
used in advertising or otherwise to promote the sale, use or other dealings
|
|
in this Software without prior written authorization from The Open Group.
|
|
|
|
*/
|
|
/*
|
|
* Copyright 1992 Network Computing Devices
|
|
*
|
|
* Permission to use, copy, modify, distribute, and sell this software and its
|
|
* documentation for any purpose is hereby granted without fee, provided that
|
|
* the above copyright notice appear in all copies and that both that
|
|
* copyright notice and this permission notice appear in supporting
|
|
* documentation, and that the name of NCD. not be used in advertising or
|
|
* publicity pertaining to distribution of the software without specific,
|
|
* written prior permission. NCD. makes no representations about the
|
|
* suitability of this software for any purpose. It is provided "as is"
|
|
* without express or implied warranty.
|
|
*
|
|
* NCD. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL NCD.
|
|
* BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
|
|
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
|
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
*
|
|
*/
|
|
/* $XFree86: xc/programs/lbxproxy/di/wire.c,v 1.14 2002/09/19 13:22:03 tsi Exp $ */
|
|
|
|
#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 <X11/extensions/bigreqstr.h>
|
|
#endif
|
|
|
|
/*
|
|
* The following include for utsname.h is from lib/xtrans
|
|
*/
|
|
#if (defined(_POSIX_SOURCE) && !defined(AIXV3) && !defined(__QNX__)) || defined(hpux) || defined(USG) || defined(SVR4)
|
|
#define NEED_UTSNAME
|
|
#include <sys/utsname.h> /* uname() */
|
|
#else
|
|
#include <unistd.h> /* gethostname() */
|
|
#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
|
|
|
|
/*
|
|
* Local constants
|
|
*/
|
|
#define MAXBYTESDIFF 8
|
|
#define PM_Unable 0
|
|
#define PM_Success 1
|
|
#define PM_Failure 2
|
|
|
|
/*
|
|
* Global vars
|
|
*/
|
|
int lbxDebug = 0;
|
|
|
|
/*
|
|
* Local functions
|
|
*/
|
|
static void LbxOnlyListenToOneClient();
|
|
static void LbxListenToAllClients();
|
|
|
|
/*
|
|
* Any request that could be delta compressed comes through here
|
|
*/
|
|
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;
|
|
/* Don't byte swap -- lengths are always in proxy order */
|
|
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)) {
|
|
/*
|
|
* Check if this is a large request only if there is more than
|
|
* one client and a different client was the last to execute or
|
|
* there are already large requests queued.
|
|
*
|
|
* If it is a large request, and there is room in the large request
|
|
* queue, add it to the queue. lbxproxy will send the large request
|
|
* in chunks, preventing this client from hogging the wire.
|
|
*
|
|
* By checking that the previous client was someone else,
|
|
* we hope that we can prevent splitting a large request
|
|
* when the other clients appear to be idle (based on their past
|
|
* history).
|
|
*/
|
|
|
|
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);
|
|
|
|
/*
|
|
* Add this large request to the queue
|
|
*/
|
|
|
|
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;
|
|
|
|
/*
|
|
* Once we have the whole large request, we want to disable
|
|
* input from this client - we don't want to read new requests
|
|
* until we are done sending the whole large request.
|
|
*/
|
|
|
|
if (reqSize == len)
|
|
IgnoreClient(client);
|
|
|
|
return;
|
|
} else if (client->largeRequest) {
|
|
|
|
/*
|
|
* Append to the large request
|
|
*/
|
|
|
|
char *dst = client->largeRequest->buf +
|
|
client->largeRequest->bytesRead;
|
|
memcpy (dst, buf, len);
|
|
client->largeRequest->bytesRead += len;
|
|
|
|
/*
|
|
* Once we have the whole large request, we want to disable
|
|
* input from this client - we don't want to read new requests
|
|
* until we are done sending the whole large request.
|
|
*/
|
|
|
|
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);
|
|
}
|
|
|
|
/* all these requests may need to be swapped back to the order of
|
|
* the client they're being executed for
|
|
*/
|
|
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;
|
|
|
|
/*
|
|
* always ask for entire thing so tag always works, and pass on requested
|
|
* subset
|
|
*/
|
|
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]) /* proxy resetting */
|
|
return;
|
|
|
|
server = client->server;
|
|
|
|
req.reqType = server->lbxReq;
|
|
req.lbxReqType = X_LbxInvalidateTag;
|
|
req.length = 2;
|
|
req.tag = tag;
|
|
/* need tag type ? */
|
|
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;
|
|
/* need tag type ? */
|
|
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;
|
|
}
|
|
|
|
/*ARGSUSED*/
|
|
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);
|
|
|
|
/*
|
|
* Now the proxy is ready to accept connections from clients.
|
|
*/
|
|
|
|
(void) ListenWellKnownSockets ();
|
|
}
|
|
|
|
|
|
static unsigned long pendingServerReplySequence;
|
|
static void (*serverReplyFunc) ();
|
|
|
|
static void
|
|
ServerReply(server, rep)
|
|
XServerPtr server;
|
|
xReply *rep;
|
|
{
|
|
if (serverReplyFunc &&
|
|
rep->generic.sequenceNumber == pendingServerReplySequence) {
|
|
/*
|
|
* We got the reply we were waiting from the server
|
|
*/
|
|
|
|
(*serverReplyFunc) (server, rep);
|
|
|
|
/*
|
|
* ExpectServerReply() might have been called within the server
|
|
* reply func just processed.
|
|
*/
|
|
|
|
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;
|
|
|
|
/* need to calculate length up from for Delta cache */
|
|
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
|
|
|
|
/* Note that LBXDecodeDelta decodes and adds current msg to the cache */
|
|
len = LBXDecodeDelta(&server->indeltas,
|
|
(xLbxDiffItem *)((char *) rep + sz_xLbxDeltaReq),
|
|
delta->diffs, delta->cindex,
|
|
(unsigned char **)&rep);
|
|
|
|
/* Make local copy in case someone writes to the request buffer */
|
|
memcpy(server->tempdeltabuf, (char *) rep, len);
|
|
rep = (xReply *) server->tempdeltabuf;
|
|
|
|
cacheable = FALSE;
|
|
}
|
|
|
|
/* stick in delta buffer before LBX code modified things */
|
|
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;
|
|
|
|
/*
|
|
* We use the motion delta event to generate a real MotionNotify event.
|
|
*
|
|
* The motion cache contains the last motion event we got from
|
|
* the server.
|
|
*
|
|
* The following are always stored in the cache in the proxy's
|
|
* byte order:
|
|
* sequenceNumber, time, rootX, rootY, eventX, eventY
|
|
* This is because when constructing the MotionNotify event using
|
|
* the delta event, we must do arithmetic in the proxy's byte order.
|
|
*
|
|
* The following are stored in the byte order of the latest client
|
|
* receiving a motion event (indicated by motionCache->swapped):
|
|
* root, event, child, state
|
|
* The assumption is that a client will receive a series of motion
|
|
* events, and we don't want to unnecessarily swap these fields.
|
|
* If the next motion event goes to a client with a byte order
|
|
* different from the previous client, we will have to swap these
|
|
* fields.
|
|
*/
|
|
|
|
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);
|
|
}
|
|
/*
|
|
* Write the reply
|
|
*/
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Write the reply
|
|
*/
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
/* ARGSUSED */
|
|
static void
|
|
LbxAttendAllClients(server)
|
|
XServerPtr server;
|
|
{
|
|
if (server->lbxIgnoringAll) {
|
|
ListenToAllClients();
|
|
server->lbxIgnoringAll = FALSE;
|
|
if (server->lbxGrabInProgress) {
|
|
OnlyListenToOneClient(clients[server->lbxGrabInProgress]);
|
|
server->lbxGrabInProgress = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* ARGSUSED */
|
|
static void
|
|
LbxOnlyListenToOneClient(client)
|
|
ClientPtr client;
|
|
{
|
|
/*
|
|
* For a multi-display proxy, there is no need to do anything -
|
|
* don't want one server grab to impact the clients for a
|
|
* different server.
|
|
*/
|
|
return;
|
|
}
|
|
|
|
/* ARGSUSED */
|
|
static void
|
|
LbxListenToAllClients(server)
|
|
XServerPtr server;
|
|
{
|
|
/*
|
|
* For a multi-display proxy, there is no need to do anything -
|
|
* don't want one server grab to impact the clients for a
|
|
* different server.
|
|
*/
|
|
return;
|
|
}
|
|
|
|
/* ARGSUSED */
|
|
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);
|
|
}
|
|
/* Need to flush the output buffers before we flush compression buffer */
|
|
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 we've got stuff remaining in the output buffers to the server, then
|
|
* don't allow reads from any other clients, otherwise we could overflow.
|
|
*/
|
|
if (PendingClientOutput(server->serverClient))
|
|
LbxIgnoreAllClients(server);
|
|
else
|
|
LbxAttendAllClients(server);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
Bool reconnectAfterCloseServer = FALSE;
|
|
|
|
void
|
|
CloseServer(client)
|
|
ClientPtr client; /* This client is connected to a display server */
|
|
{
|
|
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);
|
|
|
|
/*
|
|
* If another server is still active, don't terminate
|
|
*/
|
|
for (found = 0, i = 0; i < lbxMaxServers; i++) {
|
|
if (servers[i]) {
|
|
found = 1;
|
|
break;
|
|
}
|
|
}
|
|
if (!found && !reconnectAfterCloseServer)
|
|
dispatchException |= DE_TERMINATE;
|
|
|
|
/*
|
|
* Close all of the "real" clients for this server
|
|
*/
|
|
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--;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Need to remove this server's listen port(s)
|
|
*/
|
|
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);
|
|
}
|
|
|
|
/* remove all back pointers */
|
|
for (i = 1; i < currentMaxClients; i++) {
|
|
if (clients[i] && clients[i]->server == server)
|
|
clients[i]->server = NULL;
|
|
}
|
|
|
|
/*
|
|
* Try to reconnect to this server
|
|
*/
|
|
if (reconnectAfterCloseServer && !ConnectToServer (server->display_name)) {
|
|
|
|
fprintf (stderr, "could not reconnect to '%s'\n", server->display_name);
|
|
|
|
if (!found && !proxyMngr)
|
|
/*
|
|
* There is no need to continue if there is no proxyManager
|
|
*/
|
|
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);
|
|
|
|
/*
|
|
* Now the proxy is ready to accept connections from clients.
|
|
*/
|
|
|
|
(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;
|
|
/*
|
|
* Don't call WriteToServer because we don't want to switch.
|
|
*/
|
|
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;
|
|
|
|
/*
|
|
* Initialize the atom fields
|
|
*/
|
|
server->atom_control_count = 0;
|
|
server->atom_control = NULL;
|
|
LBXReadAtomsFile(server);
|
|
|
|
/*
|
|
* Initialize global and property caches
|
|
*/
|
|
server->num_caches = 0;
|
|
server->seed = 0;
|
|
|
|
/*
|
|
* The ProcVector table contains the default functions plus any
|
|
* changes that were made when the command line options were
|
|
* parsed.
|
|
*
|
|
* In multi-display lbxproxy, each server may have different
|
|
* lbx options that are negotiated. Consequently, a version
|
|
* of ProcVector must be maintained for each server. The field
|
|
* requestVector is used for this purpose.
|
|
*
|
|
* When a client connects, its requestVector will be set to its
|
|
* server's requestVector.
|
|
*/
|
|
server->requestVector = (int (**)()) xalloc (sizeof (ProcVector));
|
|
if (!server->requestVector) return FALSE;
|
|
memcpy (server->requestVector, ProcVector, sizeof (ProcVector));
|
|
|
|
/*
|
|
* Initialize the resource fields
|
|
*/
|
|
server->lastLbxClientIndexLookup = NULL;
|
|
|
|
/*
|
|
* Initialize the grab state variables
|
|
*/
|
|
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;
|
|
}
|
|
|
|
/*
|
|
* Create the socket(s) this display will listen on
|
|
*/
|
|
for (j=0; j < MAXTRANSPORTS; j++)
|
|
server->listen_fds[j] = -1;
|
|
CreateServerSockets(server->listen_fds);
|
|
|
|
/*
|
|
* Generate the proxy address and save the host name part
|
|
*/
|
|
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;
|
|
|
|
/*
|
|
* AllocNewConn didn't initialize the client resources so
|
|
* it needs to be done here
|
|
*/
|
|
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;
|
|
}
|