/* $Xorg: lbxfuncs.c,v 1.3 2000/08/17 19:53:55 cpqbld Exp $ */ /* * Copyright 1994 Network Computing Devices, Inc. * Copyright 1996 X Consortium, Inc. * * 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 Network Computing Devices, Inc. not be * used in advertising or publicity pertaining to distribution of this * software without specific, written prior permission. * * THIS SOFTWARE IS PROVIDED `AS-IS'. NETWORK COMPUTING DEVICES, INC., * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING WITHOUT * LIMITATION ALL IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * PARTICULAR PURPOSE, OR NONINFRINGEMENT. IN NO EVENT SHALL NETWORK * COMPUTING DEVICES, INC., BE LIABLE FOR ANY DAMAGES WHATSOEVER, INCLUDING * SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES, INCLUDING LOSS OF USE, DATA, * OR PROFITS, EVEN IF ADVISED OF THE POSSIBILITY THEREOF, AND REGARDLESS OF * WHETHER IN AN ACTION IN CONTRACT, TORT OR NEGLIGENCE, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * */ /* $XFree86: xc/programs/lbxproxy/di/lbxfuncs.c,v 1.6tsi Exp $ */ /* * top level LBX request & reply handling */ /* * requests copy out interesting stuff and then swap so original data * is left alone as much as possible. note that the length field * is *not* swapped * * replied data is copied yet again before swapping because the data * may be stored as a tag result and we don't want to change that. */ #include #include "assert.h" #include "lbxproxy.h" #include "atomcache.h" #include "util.h" #include "init.h" #include "tags.h" #include "resource.h" #include "wire.h" #include "swap.h" #include "reqtype.h" #include "lbxext.h" #include "proxyopts.h" #ifdef DEBUG extern int lbxDebug; #endif static Bool intern_atom_reply(ClientPtr client, ReplyStuffPtr nr, char *data); static Bool get_atom_name_reply(ClientPtr client, ReplyStuffPtr nr, char *data); static Bool get_mod_map_reply(ClientPtr client, ReplyStuffPtr nr, char *data); static Bool get_key_map_reply(ClientPtr client, ReplyStuffPtr nr, char *data); static Bool sync_reply(ClientPtr client, ReplyStuffPtr nr, char *data); static Bool get_queryfont_reply(ClientPtr client, ReplyStuffPtr nr, char *data); static Bool GetWinAttrAndGeomReply (ClientPtr client, ReplyStuffPtr nr, char *data); #define reply_length(cp,rep) ((rep)->type==X_Reply ? \ 32 + (HostUnswapLong((cp),(rep)->length) << 2) \ : 32) char protocolMode = PROTOCOL_FULL; /* ARGSUSED */ static void get_connection_info(ClientPtr client, xConnSetup *cs, int cs_len, int change_type, CARD32 *changes, int changes_len) { xWindowRoot *root; xDepth *depth; xVisualType *vis; char *dp = (char *) cs; int i, j, k; static int pad[4] = {0, 3, 2, 1}; if (!changes) return; cs->ridBase = changes[0]; dp += sizeof(xConnSetup); /* skip vendor string & pixmap formats */ dp += cs->nbytesVendor + pad[cs->nbytesVendor & 3]; for (i = 0; i < cs->numFormats; i++) { if (((xPixmapFormat *)dp)->depth == 1) client->ZbitsPerPixel1 = ((xPixmapFormat *)dp)->bitsPerPixel; dp += sizeof(xPixmapFormat); } /* process screens */ root = (xWindowRoot *) dp; if (change_type == 2) { if (changes[2]) root->rootVisualID = (VisualID) changes[2]; if (changes[3]) { root->defaultColormap = (Colormap) changes[3]; root->whitePixel = changes[4]; root->blackPixel = changes[5]; } } client->rootWindow = root->windowId; for (i = 0; i < cs->numRoots; i++) { if (change_type != 2) { root->currentInputMask = changes[i + 1]; } else { root->currentInputMask = changes[i + 6]; } dp += sizeof(xWindowRoot); for (j = 0; j < root->nDepths; j++) { depth = (xDepth *) dp; dp += sizeof(xDepth); for (k = 0; k < depth->nVisuals; k++) { vis = (xVisualType *) dp; CreateVisual(depth->depth, vis); dp += (sizeof(xVisualType)); vis = (xVisualType *) dp; } } if (!LookupIDByType(client, root->defaultColormap, RT_COLORMAP)) CreateColormap(client, root->defaultColormap, root->rootVisualID); } } static void send_setup_reply(ClientPtr client, Bool success, int majorVer, int minorVer, void *cs, int cs_len) { xConnSetupPrefix reply; reply.success = success; if (!success) { reply.lengthReason = strlen((char *)cs); cs_len = reply.lengthReason + 3; } reply.majorVersion = majorVer; reply.minorVersion = minorVer; reply.length = cs_len >> 2; if (client->swapped) WriteSConnSetupPrefix(client, &reply); else (void)WriteToClient(client, sizeof(xConnSetupPrefix), (char *) &reply); if (success && client->swapped) WriteSConnectionInfo(client, (unsigned long)(reply.length << 2), cs); else (void)WriteToClient(client, (int)(reply.length << 2), cs); } static void finish_setup_reply(ClientPtr client, xConnSetup *cs, int cs_len, int change_type, CARD32* changes, int changes_len, int majorVer, int minorVer) { get_connection_info(client, cs, cs_len, change_type, changes, changes_len); client->minKeyCode = cs->minKeyCode; client->maxKeyCode = cs->maxKeyCode; client->imageByteOrder = cs->imageByteOrder; client->bitmapBitOrder = cs->bitmapBitOrder; client->bitmapScanlineUnit = cs->bitmapScanlineUnit; client->bitmapScanlinePad = cs->bitmapScanlinePad; client->ridBase = cs->ridBase; client->ridMask = cs->ridMask; FinishInitClientResources (client, cs->ridBase, cs->ridMask); send_setup_reply(client, TRUE, majorVer, minorVer, cs, cs_len); } /* * ConnectionSetup data can come from three places: 1) a fully qualified * connection-setup in the reply, 2) from the tag store, and 3) built * from the Display* returned by the call the proxy made to XOpenDisplay. */ static void get_setup_reply(ClientPtr client, char *data, int len) { register xLbxConnSetupPrefix *rep; TagData td; xConnSetup *tag_data; Bool free_td = FALSE; CARD32* changes = NULL; int changes_len = 0; rep = (xLbxConnSetupPrefix *) data; if (client->swapped) { data = (char *)ALLOCATE_LOCAL(len); memcpy(data, (char *)rep, len); rep = (xLbxConnSetupPrefix *) data; SwapLbxConnSetupPrefix(rep); } switch (rep->changeType) { default: case 0: /* full ConnectionSetup, possibly with tag */ #ifdef LBX_STATS getsetup_full++; #endif tag_data = (xConnSetup *) &rep[1]; if (rep->tag != 0) { if (!TagStoreData(client->server, client->server->global_cache, rep->tag, rep->length, LbxTagTypeConnInfo, tag_data)) { /* tell server we lost it */ SendInvalidateTag(client, rep->tag); } } len = rep->length << 2; break; case 1: /* LbxNormalDeltas */ case 2: /* LbxEmbeddedAppGroup */ changes = (CARD32*) &rep[1]; changes_len = rep->length - 1; if (client->swapped) SwapLongs(changes, changes_len); if (rep->tag != 0) { td = TagGetTag(client->server, client->server->global_cache, rep->tag); if (!td) { fprintf(stderr, "no data for setup tag 0x%lx\n", (long)rep->tag); send_setup_reply(client, FALSE, 0, 0, "bad tag data from server", 0); if (client->swapped) DEALLOCATE_LOCAL(data); return; } #ifdef LBX_STATS getsetup_tag++; tag_bytes_unsent += td->size - len; #endif tag_data = td->tdata; len = td->size; } else { DisplayGetConnSetup (client->server->dpy, &tag_data, &len, rep->changeType, changes, changes_len); free_td = TRUE; } break; } finish_setup_reply(client, tag_data, len, rep->changeType, changes, changes_len, (int) rep->majorVersion, (int) rep->minorVersion); if (free_td) xfree (tag_data); if (client->swapped) DEALLOCATE_LOCAL(data); } int ProcLBXInternAtom(ClientPtr client) { REQUEST(xInternAtomReq); char *s; Atom atom, a = None; xInternAtomReply reply; ReplyStuffPtr nr; char n; CARD16 nbytes; nbytes = stuff->nbytes; if (client->swapped) { swaps(&nbytes, n); } if (nbytes > MAX_ATOM_LENGTH) return ProcStandardRequest(client); s = (char *)stuff + sizeof(xInternAtomReq); atom = LbxMakeAtom(client->server, s, nbytes, a, FALSE); if (atom != None) { reply.type = X_Reply; reply.length = 0; reply.sequenceNumber = LBXSequenceNumber(client); reply.atom = atom; if (client->swapped) SwapInternAtomReply(&reply); if (LBXCacheSafe(client)) { FinishLBXRequest(client, REQ_YANK); WriteToClient(client, sizeof(xInternAtomReply), &reply); } else { /* store for later */ if (!LBXCanDelayReply(client)) SendLbxSync(client); FinishLBXRequest(client, REQ_YANKLATE); SaveReplyData(client, (xReply *) & reply, 0, NULL); } #ifdef LBX_STATS intern_good++; #endif return Success; } else if (nbytes < MAX_ATOM_LENGTH) { nr = NewReply(client, X_InternAtom, 0, intern_atom_reply); if (!nr) return ProcStandardRequest(client); strncpy(nr->request_info.xintern.str, s, nbytes); nr->request_info.xintern.str[nbytes] = '\0'; nr->request_info.xintern.len = nbytes; #ifdef LBX_STATS intern_miss++; #endif return ProcStandardRequest(client); } return 0; /* ?!?!? */ } static Bool intern_atom_reply(ClientPtr client, ReplyStuffPtr nr, char *data) { Atom atom; char *str; xInternAtomReply *reply; int len; char n; reply = (xInternAtomReply *) data; str = nr->request_info.xintern.str; len = nr->request_info.xintern.len; atom = reply->atom; if (client->swapped) { swapl(&atom, n); } if (atom != None) /* make sure it gets stuffed in the DB */ (void) LbxMakeAtom(client->server, str, len, atom, TRUE); return TRUE; } int ProcLBXGetAtomName(ClientPtr client) { REQUEST(xResourceReq); char *str; xGetAtomNameReply reply; int len; ReplyStuffPtr nr; char n; Atom id; id = stuff->id; if (client->swapped) { swapl(&id, n); } str = NameForAtom(client->server, id); if (str) { /* found the value */ len = strlen(str); reply.type = X_Reply; reply.length = (len + 3) >> 2; reply.sequenceNumber = LBXSequenceNumber(client); reply.nameLength = len; if (client->swapped) SwapGetAtomNameReply(&reply); if (LBXCacheSafe(client)) { FinishLBXRequest(client, REQ_YANK); WriteToClient(client, sizeof(xGetAtomNameReply), &reply); WriteToClient(client, len, str); } else { if (!LBXCanDelayReply(client)) SendLbxSync(client); FinishLBXRequest(client, REQ_YANKLATE); SaveReplyData(client, (xReply *) & reply, len, str); } #ifdef LBX_STATS getatom_good++; #endif return Success; } else { nr = NewReply(client, X_GetAtomName, 0, get_atom_name_reply); if (!nr) return ProcStandardRequest(client); nr->request_info.xgetatom.atom = id; #ifdef LBX_STATS getatom_miss++; #endif return ProcStandardRequest(client); } } static Bool get_atom_name_reply(ClientPtr client, ReplyStuffPtr nr, char *data) { Atom atom; char *s; xGetAtomNameReply *reply; CARD16 len; char n; reply = (xGetAtomNameReply *) data; len = reply->nameLength; if (client->swapped) { swaps(&len, n); } if (len > MAX_ATOM_LENGTH) return FALSE; s = data + sizeof(xGetAtomNameReply); atom = nr->request_info.xgetatom.atom; /* make sure it gets stuffed in the DB */ if (atom) (void) LbxMakeAtom(client->server, s, (unsigned) len, atom, TRUE); return TRUE; } /* * Send an LbxSync request to the server. After the SyncReply comes * back, the proxy will flush any replies it saved for the client. */ void SendLbxSync(ClientPtr client) { xLbxSyncReq req; ReplyStuffPtr nr; #ifdef SEQ_DEBUG fprintf(stderr, "sending LbxSync, seq 0x%x\n", LBXSequenceNumber(client) - 1); #endif ForceSequenceUpdate(client); nr = NewReply(client, client->server->lbxReq, X_LbxSync, sync_reply); --nr->sequenceNumber; /* executed BEFORE the real request */ req.reqType = client->server->lbxReq; req.lbxReqType = X_LbxSync; req.length = sz_xLbxSyncReq >> 2; WriteReqToServer (client, sz_xLbxSyncReq, (char *) &req, TRUE); } /* ARGSUSED */ static Bool sync_reply(ClientPtr client, ReplyStuffPtr nr, char *data) { /* do nothing; just here to catch and discard the reply */ return TRUE; } void WriteError(ClientPtr client, unsigned int majorCode, unsigned int minorCode, XID resId, int errorCode) { xError rep; int n; rep.type = X_Error; rep.sequenceNumber = LBXSequenceNumber(client); rep.errorCode = errorCode; rep.majorCode = majorCode; rep.minorCode = minorCode; rep.resourceID = resId; if (client->swapped) { swaps(&rep.sequenceNumber, n); swaps(&rep.minorCode, n); swaps(&rep.resourceID, n); } WriteToClient(client, sizeof(rep), (char *)&rep); } int ProcLBXGetModifierMapping(ClientPtr client) { ReplyStuffPtr nr; nr = NewReply(client, client->server->lbxReq, X_LbxGetModifierMapping, get_mod_map_reply); if (!nr) return ProcStandardRequest(client); FinishLBXRequest(client, REQ_PASSTHROUGH); SendGetModifierMapping(client); return Success; } /*ARGSUSED*/ static Bool get_mod_map_reply(ClientPtr client, ReplyStuffPtr nr, char *data) { xLbxGetModifierMappingReply *rep; int len; pointer tag_data; CARD32 tag; char n; xGetModifierMappingReply reply; rep = (xLbxGetModifierMappingReply *) data; tag = rep->tag; if (client->swapped) { swapl(&tag, n); } len = rep->keyspermod << 3; if (rep->tag) { if (rep->length) { /* first time, set tag */ #ifdef LBX_STATS getmodmap_full++; #endif tag_data = (pointer) &rep[1]; if (!TagStoreData(client->server, client->server->global_cache, tag, len, LbxTagTypeModmap, tag_data)) { /* tell server we lost it */ SendInvalidateTag(client, tag); } } else { tag_data = TagGetData(client->server, client->server->global_cache, tag); if (!tag_data) { fprintf(stderr, "no data for mod map tag 0x%lx\n", (long)tag); WriteError(client, X_GetModifierMapping, 0, 0, BadAlloc); return TRUE; } #ifdef LBX_STATS getmodmap_tag++; tag_bytes_unsent += (rep->keyspermod << 3); #endif } } else { #ifdef LBX_STATS getmodmap_full++; #endif /* server didn't send us a tag for some reason -- just pass on data */ tag_data = (pointer) &rep[1]; } reply.type = X_Reply; reply.numKeyPerModifier = rep->keyspermod; reply.sequenceNumber = rep->sequenceNumber; reply.length = len >> 2; if (client->swapped) SwapModmapReply(&reply); WriteToClient(client, sizeof(xGetModifierMappingReply), &reply); WriteToClient(client, len, tag_data); return TRUE; } int ProcLBXGetKeyboardMapping(ClientPtr client) { REQUEST(xGetKeyboardMappingReq); ReplyStuffPtr nr; nr = NewReply(client, client->server->lbxReq, X_LbxGetKeyboardMapping, get_key_map_reply); if (!nr) return ProcStandardRequest(client); nr->request_info.lbxgetkeymap.count = stuff->count; nr->request_info.lbxgetkeymap.first = stuff->firstKeyCode; FinishLBXRequest(client, REQ_PASSTHROUGH); SendGetKeyboardMapping(client); return Success; } /* * always ask for the whole map from server, and send requested subset to * client */ static Bool get_key_map_reply(ClientPtr client, ReplyStuffPtr nr, char *data) { xLbxGetKeyboardMappingReply *rep; int len; pointer tag_data; CARD32 tag; char n; xGetKeyboardMappingReply reply; char *sdata; rep = (xLbxGetKeyboardMappingReply *) data; tag = rep->tag; if (client->swapped) { swapl(&tag, n); } if (tag) { if (rep->length) { /* first time, set tag */ #ifdef LBX_STATS getkeymap_full++; #endif tag_data = (pointer) &rep[1]; len = rep->keysperkeycode * (LBXMaxKeyCode(client) - LBXMinKeyCode(client) + 1) * 4; /* data always swapped, because reswapped when written */ if (client->swapped) SwapLongs((CARD32 *) tag_data, len / 4); if (!TagStoreData(client->server, client->server->global_cache, tag, len, LbxTagTypeKeymap, tag_data)) { /* tell server we lost it */ SendInvalidateTag(client, tag); } } else { tag_data = TagGetData(client->server, client->server->global_cache, tag); if (!tag_data) { fprintf(stderr, "no data for key map tag 0x%lx\n", (long)tag); WriteError(client, X_GetKeyboardMapping, 0, 0, BadAlloc); return TRUE; } #ifdef LBX_STATS getkeymap_tag++; tag_bytes_unsent += (rep->keysperkeycode * (LBXMaxKeyCode(client) - LBXMinKeyCode(client) + 1) * 4); #endif } } else { #ifdef LBX_STATS getkeymap_full++; #endif /* server didn't send us a tag for some reason -- just pass on data */ tag_data = (pointer) &rep[1]; /* data always swapped, because reswapped when written */ if (client->swapped) { len = rep->keysperkeycode * (LBXMaxKeyCode(client) - LBXMinKeyCode(client) + 1) * 4; SwapLongs((CARD32 *) tag_data, len / 4); } } len = (rep->keysperkeycode * nr->request_info.lbxgetkeymap.count) << 2; reply.type = X_Reply; reply.keySymsPerKeyCode = rep->keysperkeycode; reply.sequenceNumber = rep->sequenceNumber; reply.length = len >> 2; tag_data = (char *)tag_data + (rep->keysperkeycode * (nr->request_info.lbxgetkeymap.first - LBXMinKeyCode(client))); if (client->swapped) { SwapKeymapReply(&reply); /* have to copy data because we could be handed the tag storage */ sdata = (char *) ALLOCATE_LOCAL(len); if (sdata) { memcpy(sdata, tag_data, len); SwapLongs((CARD32 *) sdata, len / 4); } } else sdata = tag_data; WriteToClient(client, sizeof(xGetKeyboardMappingReply), &reply); WriteToClient(client, len, sdata); if (sdata != tag_data) DEALLOCATE_LOCAL(sdata); return TRUE; } int ProcLBXQueryFont(ClientPtr client) { REQUEST(xResourceReq); ReplyStuffPtr nr; Font fid; char n; fid = stuff->id; if (client->swapped) { swapl(&fid, n); } nr = NewReply(client, client->server->lbxReq, X_LbxQueryFont, get_queryfont_reply); if (!nr) return ProcStandardRequest(client); FinishLBXRequest(client, REQ_PASSTHROUGH); SendQueryFont(client, fid); return Success; } static INT16 unpack_val(CARD32 val, CARD32 mask, int sft, int bts) { CARD16 utmp; INT16 sval; /* get the proper value */ utmp = (val & mask) >> sft; /* push the sign bit to the right spot */ utmp <<= (16 - bts); /* cast it so sign bit takes effect */ sval = (INT16) utmp; /* shift back down */ sval >>= (16 - bts); return sval; } /*ARGSUSED*/ static int UnsquishFontInfo(int compression, xLbxFontInfo *fdata, int dlen, pointer *qfr) { int len, hlen, junklen = sizeof(BYTE) * 2 + sizeof(CARD16) + sizeof(CARD32); char *t; int nchars; int i; xCharInfo *maxb; xQueryFontReply *new; xLbxCharInfo *lci; xCharInfo *ci; CARD16 attrs; maxb = &fdata->maxBounds; nchars = fdata->nCharInfos; hlen = sizeof(xQueryFontReply) + fdata->nFontProps * sizeof(xFontProp); len = hlen + nchars * sizeof(xCharInfo); new = (xQueryFontReply *) xalloc(len); *qfr = (pointer) new; if (!new) /* XXX bad stuff... */ return 0; /* copy the header & props parts */ t = (char *) new; t += junklen; if (compression) { memcpy((char *) t, (char *) fdata, hlen - junklen); } else { memcpy((char *) t, (char *) fdata, len - junklen); return len; } attrs = maxb->attributes; t = (char *) fdata; t += hlen - junklen; lci = (xLbxCharInfo *) t; t = (char *) new; t += hlen; ci = (xCharInfo *) t; /* now expand the chars */ for (i = 0; i < nchars; i++, lci++, ci++) { if (lci->metrics == 0) { /* empty char */ ci->characterWidth = ci->leftSideBearing = ci->rightSideBearing = ci->ascent = ci->descent = ci->attributes = 0; } else { ci->characterWidth = unpack_val(lci->metrics, LBX_WIDTH_MASK, LBX_WIDTH_SHIFT, LBX_WIDTH_BITS); ci->leftSideBearing = unpack_val(lci->metrics, LBX_LEFT_MASK, LBX_LEFT_SHIFT, LBX_LEFT_BITS); ci->rightSideBearing = unpack_val(lci->metrics, LBX_RIGHT_MASK, LBX_RIGHT_SHIFT, LBX_RIGHT_BITS); ci->ascent = unpack_val(lci->metrics, LBX_ASCENT_MASK, LBX_ASCENT_SHIFT, LBX_ASCENT_BITS); ci->descent = unpack_val(lci->metrics, LBX_DESCENT_MASK, LBX_DESCENT_SHIFT, LBX_DESCENT_BITS); ci->attributes = attrs; } } return len; } /*ARGSUSED*/ static Bool get_queryfont_reply(ClientPtr client, ReplyStuffPtr nr, char *data) { xLbxQueryFontReply *rep; int len, sqlen; pointer tag_data, sqtag_data; TagData td; CARD32 tag; char n; xQueryFontReply *reply; rep = (xLbxQueryFontReply *) data; tag = rep->tag; if (client->swapped) { swapl(&tag, n); } if (tag) { if (rep->length) { /* first time, set tag */ #ifdef LBX_STATS queryfont_full++; #endif sqtag_data = (pointer) &rep[1]; sqlen = rep->length << 2; if (client->swapped) LbxSwapFontInfo(sqtag_data, rep->compression); /* * store squished version of data */ if (!TagStoreData(client->server, client->server->global_cache, tag, sqlen, LbxTagTypeFont, sqtag_data)) { /* tell server we lost it */ SendInvalidateTag(client, tag); } len = UnsquishFontInfo(rep->compression, sqtag_data, sqlen, &tag_data); } else { td = TagGetTag(client->server, client->server->global_cache, tag); if (!td) { fprintf(stderr, "no data for font tag 0x%lx\n", (long)tag); WriteError(client, X_QueryFont, 0, 0, BadAlloc); return TRUE; } sqlen = td->size; sqtag_data = td->tdata; len = UnsquishFontInfo(rep->compression, sqtag_data, sqlen, &tag_data); #ifdef LBX_STATS queryfont_tag++; tag_bytes_unsent += len; #endif } } else { #ifdef LBX_STATS queryfont_full++; #endif /* server didn't send us a tag for some reason -- just pass on data */ sqtag_data = (pointer) &rep[1]; if (client->swapped) LbxSwapFontInfo(sqtag_data, FALSE); sqlen = rep->length << 2; len = UnsquishFontInfo(rep->compression, sqtag_data, sqlen, &tag_data); } reply = (xQueryFontReply *) ALLOCATE_LOCAL(len); if (reply) { memcpy((char *) reply, (char *) tag_data, len); /* patch up certain fields */ reply->type = X_Reply; reply->sequenceNumber = rep->sequenceNumber; reply->length = (len - sizeof(xGenericReply)) >> 2; len -= sizeof(xQueryFontReply); if (client->swapped) SwapFont(reply, TRUE); WriteToClient(client, sizeof(xQueryFontReply), reply); WriteToClient(client, len, reply + 1); DEALLOCATE_LOCAL(reply); } xfree(tag_data); /* free unsquished version */ return TRUE; } int ProcLBXGetWindowAttributes(ClientPtr client) { REQUEST(xResourceReq); xLbxGetWinAttrAndGeomReq newreq; XServerPtr server = client->server; ReplyStuffPtr nr; /* * GetWindowAttributes is always followed by GetGeometry. * At this point, if lbxproxy requests the window attributes * *AND* the geometry in one request, we are guaranteed to be * able to short circuit the GetGeometry that follows. */ nr = NewReply(client, client->server->lbxReq, X_LbxGetWinAttrAndGeom, GetWinAttrAndGeomReply); if (!nr) return ProcStandardRequest(client); /* * R6 Xlib will not wait for the GetWindowAttributes reply before * sending the GetGeometry. As a result, when lbxproxy gets the * GetGeometry we must defer short circuting until lbxproxy receives * the LbxGetWinAttrAndGeomReply. */ nr->request_info.lbxWinGeom.got_geom_request = FALSE; nr->request_info.lbxWinGeom.got_geom_reply = FALSE; FinishLBXRequest(client, REQ_PASSTHROUGH); newreq.reqType = server->lbxReq; newreq.lbxReqType = X_LbxGetWinAttrAndGeom; newreq.length = sz_xLbxGetWinAttrAndGeomReq >> 2; newreq.id = stuff->id; WriteReqToServer (client, sz_xLbxGetWinAttrAndGeomReq, (char *) &newreq, TRUE); return Success; } static Bool GetWinAttrAndGeomReply (ClientPtr client, ReplyStuffPtr nr, char *data) { xLbxGetWinAttrAndGeomReply *lbxrep; xGetWindowAttributesReply reply; char n; /* * We got the window attributes and geometry. Write the * WindowAttributes reply now. */ lbxrep = (xLbxGetWinAttrAndGeomReply *) data; reply.type = X_Reply; reply.sequenceNumber = lbxrep->sequenceNumber; reply.length = (sizeof(xGetWindowAttributesReply) - sizeof(xGenericReply)) >> 2; reply.backingStore = lbxrep->backingStore; reply.visualID = lbxrep->visualID; #if defined(__cplusplus) || defined(c_plusplus) reply.c_class = lbxrep->c_class; #else reply.class = lbxrep->class; #endif reply.bitGravity = lbxrep->bitGravity; reply.winGravity = lbxrep->winGravity; reply.backingBitPlanes = lbxrep->backingBitPlanes; reply.backingPixel = lbxrep->backingPixel; reply.saveUnder = lbxrep->saveUnder; reply.mapInstalled = lbxrep->mapInstalled; reply.mapState = lbxrep->mapState; reply.override = lbxrep->override; reply.colormap = lbxrep->colormap; reply.allEventMasks = lbxrep->allEventMasks; reply.yourEventMask = lbxrep->yourEventMask; reply.doNotPropagateMask = lbxrep->doNotPropagateMask; if (client->swapped) { swaps (&reply.sequenceNumber, n); swapl (&reply.length, n); } WriteToClient(client, sizeof(xGetWindowAttributesReply), &reply); if (nr->request_info.lbxWinGeom.got_geom_request) { /* * We can write the GetGeometry reply now too. */ xGetGeometryReply geomReply; geomReply.type = X_Reply; geomReply.sequenceNumber = lbxrep->sequenceNumber + 1; geomReply.length = 0; geomReply.depth = lbxrep->depth; geomReply.root = lbxrep->root; geomReply.x = lbxrep->x; geomReply.y = lbxrep->y; geomReply.width = lbxrep->width; geomReply.height = lbxrep->height; geomReply.borderWidth = lbxrep->borderWidth; if (client->swapped) { swaps (&geomReply.sequenceNumber, n); } WriteToClient(client, sizeof(xGetGeometryReply), &geomReply); LBXLastResponse(client) = lbxrep->sequenceNumber + 1; return TRUE; /* remove matching reply record */ } else { /* * We didn't get the GetGeometry request yet, so we * stash away the geometry. */ nr->request_info.lbxWinGeom.got_geom_reply = TRUE; nr->request_info.lbxWinGeom.depth = lbxrep->depth; nr->request_info.lbxWinGeom.root = lbxrep->root; nr->request_info.lbxWinGeom.x = lbxrep->x; nr->request_info.lbxWinGeom.y = lbxrep->y; nr->request_info.lbxWinGeom.width = lbxrep->width; nr->request_info.lbxWinGeom.height = lbxrep->height; nr->request_info.lbxWinGeom.borderWidth = lbxrep->borderWidth; return FALSE; /* don't remove matching reply record */ } } int ProcLBXGetGeometry(ClientPtr client) { /* REQUEST(xResourceReq); */ xGetGeometryReply reply; ReplyStuffPtr nr; char n; /* * If the previous request was GetWindowAttributes, then lbxproxy * requested the window attributes *AND* the geometry in one request. * That means we can short circuit this GetGeometry! */ nr = GetMatchingReply (client, LBXSequenceNumber(client) - 1, FALSE); if (!nr || nr->major != client->server->lbxReq || nr->minor != X_LbxGetWinAttrAndGeom) { /* * This GetGeometry was not preceded by a GetWindowAttributes, * so we can't short circuit. Send the normal GetGeometry request. */ return ProcStandardRequest(client); } if (nr->request_info.lbxWinGeom.got_geom_reply) { /* * We already have the geom information, so we * can write the reply now. */ reply.type = X_Reply; reply.sequenceNumber = LBXSequenceNumber(client); reply.length = 0; reply.depth = nr->request_info.lbxWinGeom.depth; reply.root = nr->request_info.lbxWinGeom.root; reply.x = nr->request_info.lbxWinGeom.x; reply.y = nr->request_info.lbxWinGeom.y; reply.width = nr->request_info.lbxWinGeom.width; reply.height = nr->request_info.lbxWinGeom.height; reply.borderWidth = nr->request_info.lbxWinGeom.borderWidth; if (client->swapped) { swaps (&reply.sequenceNumber, n); } FinishLBXRequest(client, REQ_YANK); WriteToClient(client, sizeof(xGetGeometryReply), &reply); RemoveReply (client, nr); } else { /* * We must wait for the geom information before * writing the GetGeometry reply. */ nr->request_info.lbxWinGeom.got_geom_request = TRUE; FinishLBXRequest(client, REQ_YANKLATE); } return Success; } /* We're just looking for signs of the window manager here */ int ProcLBXChangeWindowAttributes(ClientPtr client) { REQUEST(xChangeWindowAttributesReq); Window win; CARD32 mask; char n; win = stuff->window; mask = stuff->valueMask; if (client->swapped) { swapl(&win, n); swapl(&mask, n); } if (mask == CWEventMask && win == LBXRootWindow(client)) { mask = *(CARD32 *)&stuff[1]; if (client->swapped) { swapl(&mask, n); } if (mask & SubstructureRedirectMask) client->server->wm_running = TRUE; } return ProcStandardRequest(client); } void FinishLBXRequest(ClientPtr client, int yank) { REQUEST(xReq); char n; if (yank != REQ_PASSTHROUGH) { LBXLastForReply(client) = LBXSequenceNumber(client); LBXLastForResponse(client) = LBXSequenceNumber(client); if (yank == REQ_YANK || yank == REQ_REPLACE) LBXLastResponse(client) = LBXSequenceNumber(client); } else { switch (GeneratesReplies(client, stuff)) { case REQ_TYPE_YES: LBXLastForReply(client) = LBXSequenceNumber(client); LBXLastForResponse(client) = LBXSequenceNumber(client); break; case REQ_TYPE_MAYBE: LBXLastForResponse(client) = LBXSequenceNumber(client); break; case REQ_TYPE_NO: if (protocolMode != PROTOCOL_POOR && GeneratesEvents(client, stuff)) LBXLastForResponse(client) = LBXSequenceNumber(client); break; } } switch (protocolMode) { case PROTOCOL_FULL: LBXCacheSafe(client) = (LBXSequenceNumber(client) == LBXLastResponse(client)); LBXCanDelayReply(client) = (LBXSequenceNumber(client) == LBXLastForReply(client)); break; default: LBXCacheSafe(client) = (LBXLastForResponse(client) <= LBXLastResponse(client)); LBXCanDelayReply(client) = (LBXLastForResponse(client) <= LBXLastForReply(client)); break; } #ifdef SEQ_DEBUG fprintf(stderr, "finished req %d, seq 0x%x, yank %d cache %d delay %d reply 0x%x response 0x%x\n", stuff->reqType, LBXSequenceNumber(client), yank, LBXCacheSafe(client), LBXCanDelayReply(client), LBXLastForReply(client), LBXLastForResponse(client)); #endif if (yank == REQ_YANK || yank == REQ_YANKLATE) { LBXSequenceLost(client)++; LBXYanked(client)++; DBG(DBG_CLIENT, (stderr, "short-circuited client %d req %d\n", client->index, stuff->reqType)); } /* make sure server's sequence number is accurate */ if (yank != REQ_YANK && yank != REQ_YANKLATE && LBXSequenceLost(client)) BumpSequence(client); /* put request length in proxy byte order */ if (client->swapped) { swaps(&stuff->length, n); } } /* * need to rewrite error codes for requests we've replaced. * * QueryFont regularly hits this in normal operation */ static int patchup_error(ClientPtr client, xError *err, ReplyStuffPtr nr) { int retval = 1; CARD16 minor_code; char n; minor_code = err->minorCode; if (client->swapped) { swaps(&minor_code, n); } switch (minor_code) { case X_LbxGetModifierMapping: minor_code = X_GetModifierMapping; break; case X_LbxGetKeyboardMapping: minor_code = X_GetKeyboardMapping; break; case X_LbxGetProperty: minor_code = X_GetProperty; break; case X_LbxQueryFont: minor_code = X_QueryFont; break; case X_LbxGetWinAttrAndGeom: minor_code = X_GetWindowAttributes; if (nr->request_info.lbxWinGeom.got_geom_request) { err->majorCode = minor_code; err->minorCode = 0; if (client->swapped) { swaps(&err->sequenceNumber, n); } WriteToClient (client, sizeof(xError), (char *)err); if (client->swapped) { swaps(&err->sequenceNumber, n); } err->sequenceNumber++; LBXLastResponse(client) = err->sequenceNumber; minor_code = X_GetGeometry; } break; default: retval = 0; /* error caused by some LBX req that shouldn't * have an error, so eat it */ break; } err->majorCode = minor_code; /* err->majorCode is CARD8, don't swap */ err->minorCode = 0; return retval; } static Bool error_matches(ClientPtr client, ReplyStuffPtr nr, xError *err) { CARD16 mc; char n; mc = err->minorCode; if (client->swapped) { swaps(&mc, n); } return (err->majorCode == nr->major && mc == nr->minor); } /* * returns TRUE if data (possibly modified) is to be sent on to client, * FALSE if data is replaced */ static Bool HandleReply(ClientPtr client, char *data, int len) { xGenericReply *reply; xError *err; ReplyStuffPtr nr; Bool ret = TRUE; char n; reply = (xGenericReply *) data; if (client->awaitingSetup) { xConnSetupPrefix *prefix = (xConnSetupPrefix *) reply; AttendClient(client); if (prefix->success) { get_setup_reply(client, (char *) reply, len); return FALSE; } return TRUE; } if (client->swapped && reply->type != KeymapNotify) { swaps(&reply->sequenceNumber, n); } if (reply->type != KeymapNotify && reply->sequenceNumber < LBXLastResponse(client)) { /* spontaneous events, and events in PROTOCOL_POOR mode, * may have sequence numbers that are earlier * than short-circuited replies and errors */ if (reply->type > X_Reply) reply->sequenceNumber = LBXLastResponse(client); } if (reply->type != KeymapNotify && reply->sequenceNumber > LBXSequenceNumber(client)) { #ifdef SEQ_DEBUG fprintf(stderr, "lbxproxy: reply seq #0x%x > internal seq 0x%x\n", reply->sequenceNumber, LBXSequenceNumber(client)); #endif reply->sequenceNumber = LBXSequenceNumber(client); } if (reply->type != X_Reply) { /* event or error */ /* clear out pending replies that resulted in errors */ if (reply->type == X_Error) { LBXLastResponse(client) = reply->sequenceNumber; err = (xError *) reply; nr = GetMatchingReply(client, reply->sequenceNumber, TRUE); if (nr && error_matches(client, nr, err)) { if (err->majorCode == client->server->lbxReq) { int eret; if ((eret = patchup_error(client, err, nr)) < 0) { CloseDownClient(client); return FALSE; } else if (eret == 0) { /* error for proxy -- eat it */ ret = FALSE; } } else { /* error in core X or other extension */ HandleExtensionError(client, err, nr); } } if (nr) RemoveReply(client, nr); } else if (reply->type >= 64) HandleExtensionEvent(client, (xEvent *)reply); if (client->swapped && reply->type != KeymapNotify) { swaps(&reply->sequenceNumber, n); } return ret; } LBXLastResponse(client) = reply->sequenceNumber; nr = GetMatchingReply(client, reply->sequenceNumber, TRUE); if (nr) { if (nr->major == client->server->lbxReq) ret = FALSE; if ((*nr->reply_func)(client, nr, (char *)reply)) RemoveReply(client, nr); } if (client->swapped) { /* put seq & length back */ swaps(&reply->sequenceNumber, n); swapl(&reply->length, n); } return ret; } void DoLBXReply(ClientPtr client, char *data, int len) { if (HandleReply(client, data, len)) WriteToClient (client, len, data); FlushDelayedReplies (client); switch (protocolMode) { case PROTOCOL_FULL: LBXCacheSafe(client) = (LBXSequenceNumber(client) == LBXLastResponse(client)); break; default: LBXCacheSafe(client) = (LBXLastForResponse(client) <= LBXLastResponse(client)); break; } #ifdef SEQ_DEBUG fprintf(stderr, "finished reply 0x%x, cache %d\n", ((xGenericReply *)data)->sequenceNumber, LBXCacheSafe(client)); #endif }