/* $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 #include #include "wire.h" #include "tags.h" #include "colormap.h" #include "init.h" #ifndef Lynx #include #else #include #endif #include #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 #ifdef BIGREQS #include #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 /* uname() */ #else #include /* 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; }