Update of /cvsroot/squeak/squeak/platforms/unix/misc/rfb In directory usw-pr-cvs1:/tmp/cvs-serv21961 Added Files: Tag: cg_unix_rfb_server README auth.c cmap.c corre.c cutpaste.c dispcur.c draw.c hextile.c httpd.c init.c kbdptr.c rfb.h rfbserver.c rre.c sockets.c sprite.c sprite.h spritest.h stats.c tableinitcmtemplate.c tableinittctemplate.c tabletranstemplate.c translate.c Log Message: * Code from Xvnc server for RFB server support --- NEW FILE: README --- $Id: README,v 1.1.2.1 2002/10/07 20:32:54 cdegroot Exp $ This code is support code for an - experimental - RFB server implementation in Squeak. The idea is to use this for server-side Squeak. Copied from the VNC Xserver source code. This is the basis for a Squeak built-in RFB server. Plan of attack: - Make sqXwindow bitmap (stImage) available to rfb server; - Start RFB server; - See whether we can connect and view a snapshot; - Add updating; - Add event processing; - Iterate until perfect; - Remove unneeded code (everything in sqXWindow.c that talks to X :-)). This way, we can slowly move in while always being able to work/test in Squeak. In fact, in version 2 I'd like to simply share the bitmap image and update list with Smalltalk and code the RFB server over there... cg...@cd... --- NEW FILE: auth.c --- /* * auth.c - deal with authentication. * * This file implements the VNC authentication protocol when setting up an RFB * connection. */ /* * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this software; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. */ #include <stdio.h> #include <stdlib.h> #include "windowstr.h" #include "rfb.h" #define MAX_AUTH_TRIES 5 #define AUTH_TOO_MANY_BASE_DELAY 10 * 1000 /* in ms, doubles for each failure over MAX_AUTH_TRIES */ static CARD32 rfbAuthReenable(OsTimerPtr timer, CARD32 now, pointer arg); char *rfbAuthPasswdFile = NULL; int rfbAuthTries = 0; Bool rfbAuthTooManyTries = FALSE; static OsTimerPtr timer = NULL; /* * rfbAuthNewClient is called when we reach the point of authenticating * a new client. If authentication isn't being used then we simply send * rfbNoAuth. Otherwise we send rfbVncAuth plus the challenge. */ void rfbAuthNewClient(cl) rfbClientPtr cl; { char buf[4 + CHALLENGESIZE]; int len; cl->state = RFB_AUTHENTICATION; if (rfbAuthPasswdFile && !cl->reverseConnection) { if (rfbAuthTooManyTries) { rfbClientConnFailed(cl, "Too many authentication failures"); return; } *(CARD32 *)buf = Swap32IfLE(rfbVncAuth); vncRandomBytes(cl->authChallenge); memcpy(&buf[4], (char *)cl->authChallenge, CHALLENGESIZE); len = 4 + CHALLENGESIZE; } else { *(CARD32 *)buf = Swap32IfLE(rfbNoAuth); len = 4; cl->state = RFB_INITIALISATION; } if (WriteExact(cl->sock, buf, len) < 0) { rfbLogPerror("rfbAuthNewClient: write"); rfbCloseSock(cl->sock); return; } } /* * rfbAuthProcessClientMessage is called when the client sends its * authentication response. */ void rfbAuthProcessClientMessage(cl) rfbClientPtr cl; { char *passwd; Bool ok; int i, n; CARD8 response[CHALLENGESIZE]; CARD32 authResult; if ((n = ReadExact(cl->sock, (char *)response, CHALLENGESIZE)) <= 0) { if (n != 0) rfbLogPerror("rfbAuthProcessClientMessage: read"); rfbCloseSock(cl->sock); return; } passwd = vncDecryptPasswdFromFile(rfbAuthPasswdFile); if (passwd == NULL) { rfbLog("rfbAuthProcessClientMessage: could not get password from %s\n", rfbAuthPasswdFile); authResult = Swap32IfLE(rfbVncAuthFailed); if (WriteExact(cl->sock, (char *)&authResult, 4) < 0) { rfbLogPerror("rfbAuthProcessClientMessage: write"); } rfbCloseSock(cl->sock); return; } vncEncryptBytes(cl->authChallenge, passwd); /* Lose the password from memory */ for (i = strlen(passwd); i >= 0; i--) { passwd[i] = '\0'; } free((char *)passwd); if (memcmp(cl->authChallenge, response, CHALLENGESIZE) != 0) { rfbLog("rfbAuthProcessClientMessage: authentication failed from %s\n", cl->host); rfbAuthTries++; if (rfbAuthTries >= MAX_AUTH_TRIES) { CARD32 delay = AUTH_TOO_MANY_BASE_DELAY; for (i = MAX_AUTH_TRIES; i < rfbAuthTries; i++) delay *= 2; timer = TimerSet(timer, 0, delay, rfbAuthReenable, NULL); rfbAuthTooManyTries = TRUE; authResult = Swap32IfLE(rfbVncAuthTooMany); } else { authResult = Swap32IfLE(rfbVncAuthFailed); } if (WriteExact(cl->sock, (char *)&authResult, 4) < 0) { rfbLogPerror("rfbAuthProcessClientMessage: write"); } rfbCloseSock(cl->sock); return; } rfbAuthTries = 0; authResult = Swap32IfLE(rfbVncAuthOK); if (WriteExact(cl->sock, (char *)&authResult, 4) < 0) { rfbLogPerror("rfbAuthProcessClientMessage: write"); rfbCloseSock(cl->sock); return; } cl->state = RFB_INITIALISATION; } static CARD32 rfbAuthReenable(OsTimerPtr timer, CARD32 now, pointer arg) { rfbAuthTooManyTries = FALSE; return 0; } --- NEW FILE: cmap.c --- /* * cmap.c */ /* * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this software; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. */ /* Copyright (c) 1993 X Consortium Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 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 X CONSORTIUM 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 X Consortium 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 X Consortium. */ #include <stdio.h> #include "scrnintstr.h" #include "resource.h" #include "colormapst.h" #include "rfb.h" ColormapPtr rfbInstalledColormap; int rfbListInstalledColormaps(pScreen, pmaps) ScreenPtr pScreen; Colormap *pmaps; { /* By the time we are processing requests, we can guarantee that there * is always a colormap installed */ *pmaps = rfbInstalledColormap->mid; return (1); } void rfbInstallColormap(pmap) ColormapPtr pmap; { ColormapPtr oldpmap = rfbInstalledColormap; if (pmap != oldpmap) { if(oldpmap != (ColormapPtr)None) WalkTree(pmap->pScreen, TellLostMap, (char *)&oldpmap->mid); /* Install pmap */ rfbInstalledColormap = pmap; WalkTree(pmap->pScreen, TellGainedMap, (char *)&pmap->mid); rfbSetClientColourMaps(0, 0); } } void rfbUninstallColormap(pmap) ColormapPtr pmap; { ColormapPtr curpmap = rfbInstalledColormap; if(pmap == curpmap) { if (pmap->mid != pmap->pScreen->defColormap) { curpmap = (ColormapPtr) LookupIDByType(pmap->pScreen->defColormap, RT_COLORMAP); (*pmap->pScreen->InstallColormap)(curpmap); } } } /* * rfbStoreColors. We have a set of pixels but they may be in any order. * If some of them happen to be in continuous ascending order then we can * group them together into a single call to rfbSetClientColourMaps. */ void rfbStoreColors(pmap, ndef, pdefs) ColormapPtr pmap; int ndef; xColorItem *pdefs; { int i; int first = -1; int n = 0; if (pmap == rfbInstalledColormap) { for (i = 0; i < ndef; i++) { if ((first != -1) && (first + n == pdefs[i].pixel)) { n++; } else { if (first != -1) { rfbSetClientColourMaps(first, n); } first = pdefs[i].pixel; n = 1; } } rfbSetClientColourMaps(first, n); } } --- NEW FILE: corre.c --- /* * corre.c * * Routines to implement Compact Rise-and-Run-length Encoding (CoRRE). This * code is based on krw's original javatel rfbserver. */ /* * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this software; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. */ #include <stdio.h> #include "rfb.h" /* * rreBeforeBuf contains pixel data in the client's format. * rreAfterBuf contains the RRE encoded version. If the RRE encoded version is * larger than the raw data or if it exceeds rreAfterBufSize then * raw encoding is used instead. */ static int rreBeforeBufSize = 0; static char *rreBeforeBuf = NULL; static int rreAfterBufSize = 0; static char *rreAfterBuf = NULL; static int rreAfterBufLen; static int subrectEncode8(CARD8 *data, int w, int h); static int subrectEncode16(CARD16 *data, int w, int h); static int subrectEncode32(CARD32 *data, int w, int h); static CARD32 getBgColour(char *data, int size, int bpp); static Bool rfbSendSmallRectEncodingCoRRE(rfbClientPtr cl, int x, int y, int w, int h); /* * rfbSendRectEncodingCoRRE - send an arbitrary size rectangle using CoRRE * encoding. */ Bool rfbSendRectEncodingCoRRE(cl, x, y, w, h) rfbClientPtr cl; int x, y, w, h; { if (h > cl->correMaxHeight) { rfbSendRectEncodingCoRRE(cl, x, y, w, cl->correMaxHeight ); rfbSendRectEncodingCoRRE(cl, x, y + cl->correMaxHeight, w, h - cl->correMaxHeight); return; } if (w > cl->correMaxWidth) { rfbSendRectEncodingCoRRE(cl, x, y, cl->correMaxWidth, h); rfbSendRectEncodingCoRRE(cl, x + cl->correMaxWidth, y, w - cl->correMaxWidth, h); return; } rfbSendSmallRectEncodingCoRRE(cl, x, y, w, h); } /* * rfbSendSmallRectEncodingCoRRE - send a small (guaranteed < 256x256) * rectangle using CoRRE encoding. */ static Bool rfbSendSmallRectEncodingCoRRE(cl, x, y, w, h) rfbClientPtr cl; int x, y, w, h; { rfbFramebufferUpdateRectHeader rect; rfbRREHeader hdr; int nSubrects; int i; char *fbptr = (rfbScreen.pfbMemory + (rfbScreen.paddedWidthInBytes * y) + (x * (rfbScreen.bitsPerPixel / 8))); int maxRawSize = (rfbScreen.width * rfbScreen.height * (cl->format.bitsPerPixel / 8)); if (rreBeforeBufSize < maxRawSize) { rreBeforeBufSize = maxRawSize; if (rreBeforeBuf == NULL) rreBeforeBuf = (char *)xalloc(rreBeforeBufSize); else rreBeforeBuf = (char *)xrealloc(rreBeforeBuf, rreBeforeBufSize); } if (rreAfterBufSize < maxRawSize) { rreAfterBufSize = maxRawSize; if (rreAfterBuf == NULL) rreAfterBuf = (char *)xalloc(rreAfterBufSize); else rreAfterBuf = (char *)xrealloc(rreAfterBuf, rreAfterBufSize); } (*cl->translateFn)(cl->translateLookupTable, &rfbServerFormat, &cl->format, fbptr, rreBeforeBuf, rfbScreen.paddedWidthInBytes, w, h); switch (cl->format.bitsPerPixel) { case 8: nSubrects = subrectEncode8((CARD8 *)rreBeforeBuf, w, h); break; case 16: nSubrects = subrectEncode16((CARD16 *)rreBeforeBuf, w, h); break; case 32: nSubrects = subrectEncode32((CARD32 *)rreBeforeBuf, w, h); break; default: rfbLog("getBgColour: bpp %d?\n",cl->format.bitsPerPixel); exit(1); } if (nSubrects < 0) { /* RRE encoding was too large, use raw */ return rfbSendRectEncodingRaw(cl, x, y, w, h); } cl->rfbRectanglesSent[rfbEncodingCoRRE]++; cl->rfbBytesSent[rfbEncodingCoRRE] += (sz_rfbFramebufferUpdateRectHeader + sz_rfbRREHeader + rreAfterBufLen); if (ublen + sz_rfbFramebufferUpdateRectHeader + sz_rfbRREHeader > UPDATE_BUF_SIZE) { if (!rfbSendUpdateBuf(cl)) return FALSE; } rect.r.x = Swap16IfLE(x); rect.r.y = Swap16IfLE(y); rect.r.w = Swap16IfLE(w); rect.r.h = Swap16IfLE(h); rect.encoding = Swap32IfLE(rfbEncodingCoRRE); memcpy(&updateBuf[ublen], (char *)&rect, sz_rfbFramebufferUpdateRectHeader); ublen += sz_rfbFramebufferUpdateRectHeader; hdr.nSubrects = Swap32IfLE(nSubrects); memcpy(&updateBuf[ublen], (char *)&hdr, sz_rfbRREHeader); ublen += sz_rfbRREHeader; for (i = 0; i < rreAfterBufLen;) { int bytesToCopy = UPDATE_BUF_SIZE - ublen; if (i + bytesToCopy > rreAfterBufLen) { bytesToCopy = rreAfterBufLen - i; } memcpy(&updateBuf[ublen], &rreAfterBuf[i], bytesToCopy); ublen += bytesToCopy; i += bytesToCopy; if (ublen == UPDATE_BUF_SIZE) { if (!rfbSendUpdateBuf(cl)) return FALSE; } } return TRUE; } /* * subrectEncode() encodes the given multicoloured rectangle as a background * colour overwritten by single-coloured rectangles. It returns the number * of subrectangles in the encoded buffer, or -1 if subrect encoding won't * fit in the buffer. It puts the encoded rectangles in rreAfterBuf. The * single-colour rectangle partition is not optimal, but does find the biggest * horizontal or vertical rectangle top-left anchored to each consecutive * coordinate position. * * The coding scheme is simply [<bgcolour><subrect><subrect>...] where each * <subrect> is [<colour><x><y><w><h>]. */ #define DEFINE_SUBRECT_ENCODE(bpp) \ static int \ subrectEncode##bpp(data,w,h) \ CARD##bpp *data; \ int w; \ int h; \ { \ CARD##bpp cl; \ rfbCoRRERectangle subrect; \ int x,y; \ int i,j; \ int hx=0,hy,vx=0,vy; \ int hyflag; \ CARD##bpp *seg; \ CARD##bpp *line; \ int hw,hh,vw,vh; \ int thex,they,thew,theh; \ int numsubs = 0; \ int newLen; \ CARD##bpp bg = (CARD##bpp)getBgColour((char*)data,w*h,bpp); \ \ *((CARD##bpp*)rreAfterBuf) = bg; \ \ rreAfterBufLen = (bpp/8); \ \ for (y=0; y<h; y++) { \ line = data+(y*w); \ for (x=0; x<w; x++) { \ if (line[x] != bg) { \ cl = line[x]; \ hy = y-1; \ hyflag = 1; \ for (j=y; j<h; j++) { \ seg = data+(j*w); \ if (seg[x] != cl) {break;} \ i = x; \ while ((seg[i] == cl) && (i < w)) i += 1; \ i -= 1; \ if (j == y) vx = hx = i; \ if (i < vx) vx = i; \ if ((hyflag > 0) && (i >= hx)) {hy += 1;} else {hyflag = 0;} \ } \ vy = j-1; \ \ /* We now have two possible subrects: (x,y,hx,hy) and (x,y,vx,vy) \ * We'll choose the bigger of the two. \ */ \ hw = hx-x+1; \ hh = hy-y+1; \ vw = vx-x+1; \ vh = vy-y+1; \ \ thex = x; \ they = y; \ \ if ((hw*hh) > (vw*vh)) { \ thew = hw; \ theh = hh; \ } else { \ thew = vw; \ theh = vh; \ } \ \ subrect.x = thex; \ subrect.y = they; \ subrect.w = thew; \ subrect.h = theh; \ \ newLen = rreAfterBufLen + (bpp/8) + sz_rfbCoRRERectangle; \ if ((newLen > (w * h * (bpp/8))) || (newLen > rreAfterBufSize)) \ return -1; \ \ numsubs += 1; \ *((CARD##bpp*)(rreAfterBuf + rreAfterBufLen)) = cl; \ rreAfterBufLen += (bpp/8); \ memcpy(&rreAfterBuf[rreAfterBufLen],&subrect,sz_rfbCoRRERectangle); \ rreAfterBufLen += sz_rfbCoRRERectangle; \ \ /* \ * Now mark the subrect as done. \ */ \ for (j=they; j < (they+theh); j++) { \ for (i=thex; i < (thex+thew); i++) { \ data[j*w+i] = bg; \ } \ } \ } \ } \ } \ \ return numsubs; \ } DEFINE_SUBRECT_ENCODE(8) DEFINE_SUBRECT_ENCODE(16) DEFINE_SUBRECT_ENCODE(32) /* * getBgColour() gets the most prevalent colour in a byte array. */ static CARD32 getBgColour(data,size,bpp) char *data; int size; int bpp; { #define NUMCLRS 256 static int counts[NUMCLRS]; int i,j,k; int maxcount = 0; CARD8 maxclr = 0; if (bpp != 8) { if (bpp == 16) { return ((CARD16 *)data)[0]; } else if (bpp == 32) { return ((CARD32 *)data)[0]; } else { rfbLog("getBgColour: bpp %d?\n",bpp); exit(1); } } for (i=0; i<NUMCLRS; i++) { counts[i] = 0; } for (j=0; j<size; j++) { k = (int)(((CARD8 *)data)[j]); if (k >= NUMCLRS) { rfbLog("getBgColour: unusual colour = %d\n", k); exit(1); } counts[k] += 1; if (counts[k] > maxcount) { maxcount = counts[k]; maxclr = ((CARD8 *)data)[j]; } } return maxclr; } --- NEW FILE: cutpaste.c --- /* * cutpaste.c - routines to deal with cut & paste buffers / selection. */ /* * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this software; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. */ #include <stdio.h> #define NEED_EVENTS #include <X.h> #include <Xproto.h> #include "rfb.h" #include "selection.h" #include "input.h" #include <Xatom.h> extern WindowPtr *WindowTable; /* Why isn't this in a header file? */ extern Selection *CurrentSelections; extern int NumCurrentSelections; static Bool inSetXCutText = FALSE; /* * rfbSetXCutText sets the cut buffer to be the given string. We also clear * the primary selection. Ideally we'd like to set it to the same thing, but I * can't work out how to do that without some kind of helper X client. */ void rfbSetXCutText(char *str, int len) { int i = 0; inSetXCutText = TRUE; ChangeWindowProperty(WindowTable[0], XA_CUT_BUFFER0, XA_STRING, 8, PropModeReplace, len, (pointer)str, TRUE); while ((i < NumCurrentSelections) && CurrentSelections[i].selection != XA_PRIMARY) i++; if (i < NumCurrentSelections) { xEvent event; if (CurrentSelections[i].client) { event.u.u.type = SelectionClear; event.u.selectionClear.time = GetTimeInMillis(); event.u.selectionClear.window = CurrentSelections[i].window; event.u.selectionClear.atom = CurrentSelections[i].selection; (void) TryClientEvents (CurrentSelections[i].client, &event, 1, NoEventMask, NoEventMask /* CantBeFiltered */, NullGrab); } CurrentSelections[i].window = None; CurrentSelections[i].pWin = NULL; CurrentSelections[i].client = NullClient; } inSetXCutText = FALSE; } void rfbGotXCutText(char *str, int len) { if (!inSetXCutText) rfbSendServerCutText(str, len); } --- NEW FILE: dispcur.c --- /* * dispcur.c * * cursor display routines - based on midispcur.c */ /* * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this software; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. */ /* Copyright (c) 1989 X Consortium Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 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 X CONSORTIUM 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 X Consortium 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 X Consortium. */ #define NEED_EVENTS # include "X.h" # include "misc.h" # include "input.h" # include "cursorstr.h" # include "windowstr.h" # include "regionstr.h" # include "dixstruct.h" # include "scrnintstr.h" # include "servermd.h" # include "mipointer.h" # include "sprite.h" # include "gcstruct.h" extern WindowPtr *WindowTable; /* per-screen private data */ static int rfbDCScreenIndex; static unsigned long rfbDCGeneration = 0; static Bool rfbDCCloseScreen(); typedef struct { GCPtr pSourceGC, pMaskGC; GCPtr pSaveGC, pRestoreGC; GCPtr pPixSourceGC, pPixMaskGC; CloseScreenProcPtr CloseScreen; PixmapPtr pSave; } rfbDCScreenRec, *rfbDCScreenPtr; /* per-cursor per-screen private data */ typedef struct { PixmapPtr sourceBits; /* source bits */ PixmapPtr maskBits; /* mask bits */ } rfbDCCursorRec, *rfbDCCursorPtr; /* * sprite/cursor method table */ static Bool rfbDCRealizeCursor(), rfbDCUnrealizeCursor(); static Bool rfbDCPutUpCursor(), rfbDCSaveUnderCursor(); static Bool rfbDCRestoreUnderCursor(); static rfbSpriteCursorFuncRec rfbDCFuncs = { rfbDCRealizeCursor, rfbDCUnrealizeCursor, rfbDCPutUpCursor, rfbDCSaveUnderCursor, rfbDCRestoreUnderCursor, }; Bool rfbDCInitialize (pScreen, screenFuncs) ScreenPtr pScreen; miPointerScreenFuncPtr screenFuncs; { rfbDCScreenPtr pScreenPriv; if (rfbDCGeneration != serverGeneration) { rfbDCScreenIndex = AllocateScreenPrivateIndex (); if (rfbDCScreenIndex < 0) return FALSE; rfbDCGeneration = serverGeneration; } pScreenPriv = (rfbDCScreenPtr) xalloc (sizeof (rfbDCScreenRec)); if (!pScreenPriv) return FALSE; /* * initialize the entire private structure to zeros */ pScreenPriv->pSourceGC = pScreenPriv->pMaskGC = pScreenPriv->pSaveGC = pScreenPriv->pRestoreGC = pScreenPriv->pPixSourceGC = pScreenPriv->pPixMaskGC = NULL; pScreenPriv->pSave = NULL; pScreenPriv->CloseScreen = pScreen->CloseScreen; pScreen->CloseScreen = rfbDCCloseScreen; pScreen->devPrivates[rfbDCScreenIndex].ptr = (pointer) pScreenPriv; if (!rfbSpriteInitialize (pScreen, &rfbDCFuncs, screenFuncs)) { xfree ((pointer) pScreenPriv); return FALSE; } return TRUE; } #define tossGC(gc) (gc ? FreeGC (gc, (GContext) 0) : 0) #define tossPix(pix) (pix ? (*pScreen->DestroyPixmap) (pix) : TRUE) static Bool rfbDCCloseScreen (index, pScreen) ScreenPtr pScreen; { rfbDCScreenPtr pScreenPriv; pScreenPriv = (rfbDCScreenPtr) pScreen->devPrivates[rfbDCScreenIndex].ptr; pScreen->CloseScreen = pScreenPriv->CloseScreen; tossGC (pScreenPriv->pSourceGC); tossGC (pScreenPriv->pMaskGC); tossGC (pScreenPriv->pSaveGC); tossGC (pScreenPriv->pRestoreGC); tossGC (pScreenPriv->pPixSourceGC); tossGC (pScreenPriv->pPixMaskGC); tossPix (pScreenPriv->pSave); xfree ((pointer) pScreenPriv); return (*pScreen->CloseScreen) (index, pScreen); } static Bool rfbDCRealizeCursor (pScreen, pCursor) ScreenPtr pScreen; CursorPtr pCursor; { if (pCursor->bits->refcnt <= 1) pCursor->bits->devPriv[pScreen->myNum] = (pointer)NULL; return TRUE; } static rfbDCCursorPtr rfbDCRealize (pScreen, pCursor) ScreenPtr pScreen; CursorPtr pCursor; { rfbDCCursorPtr pPriv; GCPtr pGC; XID gcvals[3]; pPriv = (rfbDCCursorPtr) xalloc (sizeof (rfbDCCursorRec)); if (!pPriv) return (rfbDCCursorPtr)NULL; pPriv->sourceBits = (*pScreen->CreatePixmap) (pScreen, pCursor->bits->width, pCursor->bits->height, 1); if (!pPriv->sourceBits) { xfree ((pointer) pPriv); return (rfbDCCursorPtr)NULL; } pPriv->maskBits = (*pScreen->CreatePixmap) (pScreen, pCursor->bits->width, pCursor->bits->height, 1); if (!pPriv->maskBits) { (*pScreen->DestroyPixmap) (pPriv->sourceBits); xfree ((pointer) pPriv); return (rfbDCCursorPtr)NULL; } pCursor->bits->devPriv[pScreen->myNum] = (pointer) pPriv; /* create the two sets of bits, clipping as appropriate */ pGC = GetScratchGC (1, pScreen); if (!pGC) { (void) rfbDCUnrealizeCursor (pScreen, pCursor); return (rfbDCCursorPtr)NULL; } ValidateGC ((DrawablePtr)pPriv->sourceBits, pGC); (*pGC->ops->PutImage) ((DrawablePtr)pPriv->sourceBits, pGC, 1, 0, 0, pCursor->bits->width, pCursor->bits->height, 0, XYPixmap, (char *)pCursor->bits->source); gcvals[0] = GXand; ChangeGC (pGC, GCFunction, gcvals); ValidateGC ((DrawablePtr)pPriv->sourceBits, pGC); (*pGC->ops->PutImage) ((DrawablePtr)pPriv->sourceBits, pGC, 1, 0, 0, pCursor->bits->width, pCursor->bits->height, 0, XYPixmap, (char *)pCursor->bits->mask); /* mask bits -- pCursor->mask & ~pCursor->source */ gcvals[0] = GXcopy; ChangeGC (pGC, GCFunction, gcvals); ValidateGC ((DrawablePtr)pPriv->maskBits, pGC); (*pGC->ops->PutImage) ((DrawablePtr)pPriv->maskBits, pGC, 1, 0, 0, pCursor->bits->width, pCursor->bits->height, 0, XYPixmap, (char *)pCursor->bits->mask); gcvals[0] = GXandInverted; ChangeGC (pGC, GCFunction, gcvals); ValidateGC ((DrawablePtr)pPriv->maskBits, pGC); (*pGC->ops->PutImage) ((DrawablePtr)pPriv->maskBits, pGC, 1, 0, 0, pCursor->bits->width, pCursor->bits->height, 0, XYPixmap, (char *)pCursor->bits->source); FreeScratchGC (pGC); return pPriv; } static Bool rfbDCUnrealizeCursor (pScreen, pCursor) ScreenPtr pScreen; CursorPtr pCursor; { rfbDCCursorPtr pPriv; pPriv = (rfbDCCursorPtr) pCursor->bits->devPriv[pScreen->myNum]; if (pPriv && (pCursor->bits->refcnt <= 1)) { (*pScreen->DestroyPixmap) (pPriv->sourceBits); (*pScreen->DestroyPixmap) (pPriv->maskBits); xfree ((pointer) pPriv); pCursor->bits->devPriv[pScreen->myNum] = (pointer)NULL; } return TRUE; } static void rfbDCPutBits (pDrawable, pPriv, sourceGC, maskGC, x, y, w, h, source, mask) DrawablePtr pDrawable; GCPtr sourceGC, maskGC; int x, y; unsigned w, h; rfbDCCursorPtr pPriv; unsigned long source, mask; { XID gcvals[1]; if (sourceGC->fgPixel != source) { gcvals[0] = source; DoChangeGC (sourceGC, GCForeground, gcvals, 0); } if (sourceGC->serialNumber != pDrawable->serialNumber) ValidateGC (pDrawable, sourceGC); (*sourceGC->ops->PushPixels) (sourceGC, pPriv->sourceBits, pDrawable, w, h, x, y); if (maskGC->fgPixel != mask) { gcvals[0] = mask; DoChangeGC (maskGC, GCForeground, gcvals, 0); } if (maskGC->serialNumber != pDrawable->serialNumber) ValidateGC (pDrawable, maskGC); (*maskGC->ops->PushPixels) (maskGC, pPriv->maskBits, pDrawable, w, h, x, y); } #define EnsureGC(gc,win) (gc || rfbDCMakeGC(&gc, win)) static GCPtr rfbDCMakeGC(ppGC, pWin) GCPtr *ppGC; WindowPtr pWin; { GCPtr pGC; int status; XID gcvals[2]; gcvals[0] = IncludeInferiors; gcvals[1] = FALSE; pGC = CreateGC((DrawablePtr)pWin, GCSubwindowMode|GCGraphicsExposures, gcvals, &status); if (pGC) (*pWin->drawable.pScreen->DrawGuarantee) (pWin, pGC, GuaranteeVisBack); *ppGC = pGC; return pGC; } static Bool rfbDCPutUpCursor (pScreen, pCursor, x, y, source, mask) ScreenPtr pScreen; CursorPtr pCursor; int x, y; unsigned long source, mask; { rfbDCScreenPtr pScreenPriv; rfbDCCursorPtr pPriv; WindowPtr pWin; pPriv = (rfbDCCursorPtr) pCursor->bits->devPriv[pScreen->myNum]; if (!pPriv) { pPriv = rfbDCRealize(pScreen, pCursor); if (!pPriv) return FALSE; } pScreenPriv = (rfbDCScreenPtr) pScreen->devPrivates[rfbDCScreenIndex].ptr; pWin = WindowTable[pScreen->myNum]; if (!EnsureGC(pScreenPriv->pSourceGC, pWin)) return FALSE; if (!EnsureGC(pScreenPriv->pMaskGC, pWin)) { FreeGC (pScreenPriv->pSourceGC, (GContext) 0); pScreenPriv->pSourceGC = 0; return FALSE; } rfbDCPutBits ((DrawablePtr)pWin, pPriv, pScreenPriv->pSourceGC, pScreenPriv->pMaskGC, x, y, pCursor->bits->width, pCursor->bits->height, source, mask); return TRUE; } static Bool rfbDCSaveUnderCursor (pScreen, x, y, w, h) ScreenPtr pScreen; int x, y, w, h; { rfbDCScreenPtr pScreenPriv; PixmapPtr pSave; WindowPtr pWin; GCPtr pGC; pScreenPriv = (rfbDCScreenPtr) pScreen->devPrivates[rfbDCScreenIndex].ptr; pSave = pScreenPriv->pSave; pWin = WindowTable[pScreen->myNum]; if (!pSave || pSave->drawable.width < w || pSave->drawable.height < h) { if (pSave) (*pScreen->DestroyPixmap) (pSave); pScreenPriv->pSave = pSave = (*pScreen->CreatePixmap) (pScreen, w, h, pScreen->rootDepth); if (!pSave) return FALSE; } if (!EnsureGC(pScreenPriv->pSaveGC, pWin)) return FALSE; pGC = pScreenPriv->pSaveGC; if (pSave->drawable.serialNumber != pGC->serialNumber) ValidateGC ((DrawablePtr) pSave, pGC); (*pGC->ops->CopyArea) ((DrawablePtr) pWin, (DrawablePtr) pSave, pGC, x, y, w, h, 0, 0); return TRUE; } static Bool rfbDCRestoreUnderCursor (pScreen, x, y, w, h) ScreenPtr pScreen; int x, y, w, h; { rfbDCScreenPtr pScreenPriv; PixmapPtr pSave; WindowPtr pWin; GCPtr pGC; pScreenPriv = (rfbDCScreenPtr) pScreen->devPrivates[rfbDCScreenIndex].ptr; pSave = pScreenPriv->pSave; pWin = WindowTable[pScreen->myNum]; if (!pSave) return FALSE; if (!EnsureGC(pScreenPriv->pRestoreGC, pWin)) return FALSE; pGC = pScreenPriv->pRestoreGC; if (pWin->drawable.serialNumber != pGC->serialNumber) ValidateGC ((DrawablePtr) pWin, pGC); (*pGC->ops->CopyArea) ((DrawablePtr) pSave, (DrawablePtr) pWin, pGC, 0, 0, w, h, x, y); return TRUE; } --- NEW FILE: draw.c --- /* * draw.c - drawing routines for the RFB X server. This is a set of * wrappers around the standard MI/MFB/CFB drawing routines which work out * to a fair approximation the region of the screen being modified by the * drawing. If the RFB client is ready then the modified region of the screen * is sent to the client, otherwise the modified region will simply grow with * each drawing request until the client is ready. */ /* * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of [...1837 lines suppressed...] ScreenPtr pScreen; RegionPtr reg; { int nrects = REGION_NUM_RECTS(reg); int i; rfbLog("Region num rects %d extents %d,%d %d,%d\n",nrects, (REGION_EXTENTS(pScreen,reg))->x1, (REGION_EXTENTS(pScreen,reg))->y1, (REGION_EXTENTS(pScreen,reg))->x2, (REGION_EXTENTS(pScreen,reg))->y2); for (i = 0; i < nrects; i++) { rfbLog(" rect %d,%d %dx%d\n", REGION_RECTS(reg)[i].x1, REGION_RECTS(reg)[i].y1, REGION_RECTS(reg)[i].x2-REGION_RECTS(reg)[i].x1, REGION_RECTS(reg)[i].y2-REGION_RECTS(reg)[i].y1); } } --- NEW FILE: hextile.c --- /* * hextile.c * * Routines to implement Hextile Encoding */ /* * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this software; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. */ #include <stdio.h> #include "rfb.h" static Bool sendHextiles8(rfbClientPtr cl, int x, int y, int w, int h); static Bool sendHextiles16(rfbClientPtr cl, int x, int y, int w, int h); static Bool sendHextiles32(rfbClientPtr cl, int x, int y, int w, int h); /* * rfbSendRectEncodingHextile - send a rectangle using hextile encoding. */ Bool rfbSendRectEncodingHextile(cl, x, y, w, h) rfbClientPtr cl; int x, y, w, h; { rfbFramebufferUpdateRectHeader rect; if (ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE) { if (!rfbSendUpdateBuf(cl)) return FALSE; } rect.r.x = Swap16IfLE(x); rect.r.y = Swap16IfLE(y); rect.r.w = Swap16IfLE(w); rect.r.h = Swap16IfLE(h); rect.encoding = Swap32IfLE(rfbEncodingHextile); memcpy(&updateBuf[ublen], (char *)&rect, sz_rfbFramebufferUpdateRectHeader); ublen += sz_rfbFramebufferUpdateRectHeader; cl->rfbRectanglesSent[rfbEncodingHextile]++; cl->rfbBytesSent[rfbEncodingHextile] += sz_rfbFramebufferUpdateRectHeader; switch (cl->format.bitsPerPixel) { case 8: return sendHextiles8(cl, x, y, w, h); case 16: return sendHextiles16(cl, x, y, w, h); case 32: return sendHextiles32(cl, x, y, w, h); } rfbLog("rfbSendRectEncodingHextile: bpp %d?\n", cl->format.bitsPerPixel); return FALSE; } #define PUT_PIXEL8(pix) (updateBuf[ublen++] = (pix)) #define PUT_PIXEL16(pix) (updateBuf[ublen++] = ((char*)&(pix))[0], \ updateBuf[ublen++] = ((char*)&(pix))[1]) #define PUT_PIXEL32(pix) (updateBuf[ublen++] = ((char*)&(pix))[0], \ updateBuf[ublen++] = ((char*)&(pix))[1], \ updateBuf[ublen++] = ((char*)&(pix))[2], \ updateBuf[ublen++] = ((char*)&(pix))[3]) #define DEFINE_SEND_HEXTILES(bpp) \ \ \ static Bool subrectEncode##bpp(CARD##bpp *data, int w, int h, CARD##bpp bg, \ CARD##bpp fg, Bool mono); \ static void testColours##bpp(CARD##bpp *data, int size, Bool *mono, \ Bool *solid, CARD##bpp *bg, CARD##bpp *fg); \ \ \ /* \ * rfbSendHextiles \ */ \ \ static Bool \ sendHextiles##bpp(cl, rx, ry, rw, rh) \ rfbClientPtr cl; \ int rx, ry, rw, rh; \ { \ int x, y, w, h; \ int startUblen; \ char *fbptr; \ CARD##bpp bg, fg, newBg, newFg; \ Bool mono, solid; \ Bool validBg = FALSE; \ Bool validFg = FALSE; \ CARD##bpp clientPixelData[16*16*(bpp/8)]; \ \ for (y = ry; y < ry+rh; y += 16) { \ for (x = rx; x < rx+rw; x += 16) { \ w = h = 16; \ if (rx+rw - x < 16) \ w = rx+rw - x; \ if (ry+rh - y < 16) \ h = ry+rh - y; \ \ if ((ublen + 1 + (2 + 16 * 16) * (bpp/8)) > UPDATE_BUF_SIZE) { \ if (!rfbSendUpdateBuf(cl)) \ return FALSE; \ } \ \ fbptr = (rfbScreen.pfbMemory + (rfbScreen.paddedWidthInBytes * y) \ + (x * (rfbScreen.bitsPerPixel / 8))); \ \ (*cl->translateFn)(cl->translateLookupTable, &rfbServerFormat, \ &cl->format, fbptr, (char *)clientPixelData, \ rfbScreen.paddedWidthInBytes, w, h); \ \ startUblen = ublen; \ updateBuf[startUblen] = 0; \ ublen++; \ \ testColours##bpp(clientPixelData, w * h, \ &mono, &solid, &newBg, &newFg); \ \ if (!validBg || (newBg != bg)) { \ validBg = TRUE; \ bg = newBg; \ updateBuf[startUblen] |= rfbHextileBackgroundSpecified; \ PUT_PIXEL##bpp(bg); \ } \ \ if (solid) { \ cl->rfbBytesSent[rfbEncodingHextile] += ublen - startUblen; \ continue; \ } \ \ updateBuf[startUblen] |= rfbHextileAnySubrects; \ \ if (mono) { \ if (!validFg || (newFg != fg)) { \ validFg = TRUE; \ fg = newFg; \ updateBuf[startUblen] |= rfbHextileForegroundSpecified; \ PUT_PIXEL##bpp(fg); \ } \ } else { \ validFg = FALSE; \ updateBuf[startUblen] |= rfbHextileSubrectsColoured; \ } \ \ if (!subrectEncode##bpp(clientPixelData, w, h, bg, fg, mono)) { \ /* encoding was too large, use raw */ \ validBg = FALSE; \ validFg = FALSE; \ ublen = startUblen; \ updateBuf[ublen++] = rfbHextileRaw; \ (*cl->translateFn)(cl->translateLookupTable, \ &rfbServerFormat, &cl->format, fbptr, \ (char *)clientPixelData, \ rfbScreen.paddedWidthInBytes, w, h); \ \ memcpy(&updateBuf[ublen], (char *)clientPixelData, \ w * h * (bpp/8)); \ \ ublen += w * h * (bpp/8); \ } \ \ cl->rfbBytesSent[rfbEncodingHextile] += ublen - startUblen; \ } \ } \ \ return TRUE; \ } \ \ \ static Bool \ subrectEncode##bpp(CARD##bpp *data, int w, int h, CARD##bpp bg, \ CARD##bpp fg, Bool mono) \ { \ CARD##bpp cl; \ int x,y; \ int i,j; \ int hx=0,hy,vx=0,vy; \ int hyflag; \ CARD##bpp *seg; \ CARD##bpp *line; \ int hw,hh,vw,vh; \ int thex,they,thew,theh; \ int numsubs = 0; \ int newLen; \ int nSubrectsUblen; \ \ nSubrectsUblen = ublen; \ ublen++; \ \ for (y=0; y<h; y++) { \ line = data+(y*w); \ for (x=0; x<w; x++) { \ if (line[x] != bg) { \ cl = line[x]; \ hy = y-1; \ hyflag = 1; \ for (j=y; j<h; j++) { \ seg = data+(j*w); \ if (seg[x] != cl) {break;} \ i = x; \ while ((seg[i] == cl) && (i < w)) i += 1; \ i -= 1; \ if (j == y) vx = hx = i; \ if (i < vx) vx = i; \ if ((hyflag > 0) && (i >= hx)) { \ hy += 1; \ } else { \ hyflag = 0; \ } \ } \ vy = j-1; \ \ /* We now have two possible subrects: (x,y,hx,hy) and \ * (x,y,vx,vy). We'll choose the bigger of the two. \ */ \ hw = hx-x+1; \ hh = hy-y+1; \ vw = vx-x+1; \ vh = vy-y+1; \ \ thex = x; \ they = y; \ \ if ((hw*hh) > (vw*vh)) { \ thew = hw; \ theh = hh; \ } else { \ thew = vw; \ theh = vh; \ } \ \ if (mono) { \ newLen = ublen - nSubrectsUblen + 2; \ } else { \ newLen = ublen - nSubrectsUblen + bpp/8 + 2; \ } \ \ if (newLen > (w * h * (bpp/8))) \ return FALSE; \ \ numsubs += 1; \ \ if (!mono) PUT_PIXEL##bpp(cl); \ \ updateBuf[ublen++] = rfbHextilePackXY(thex,they); \ updateBuf[ublen++] = rfbHextilePackWH(thew,theh); \ \ /* \ * Now mark the subrect as done. \ */ \ for (j=they; j < (they+theh); j++) { \ for (i=thex; i < (thex+thew); i++) { \ data[j*w+i] = bg; \ } \ } \ } \ } \ } \ \ updateBuf[nSubrectsUblen] = numsubs; \ \ return TRUE; \ } \ \ \ /* \ * testColours() tests if there are one (solid), two (mono) or more \ * colours in a tile and gets a reasonable guess at the best background \ * pixel, and the foreground pixel for mono. \ */ \ \ static void \ testColours##bpp(data,size,mono,solid,bg,fg) \ CARD##bpp *data; \ int size; \ Bool *mono; \ Bool *solid; \ CARD##bpp *bg; \ CARD##bpp *fg; \ { \ CARD##bpp colour1, colour2; \ int n1 = 0, n2 = 0; \ *mono = TRUE; \ *solid = TRUE; \ \ for (; size > 0; size--, data++) { \ \ if (n1 == 0) \ colour1 = *data; \ \ if (*data == colour1) { \ n1++; \ continue; \ } \ \ if (n2 == 0) { \ *solid = FALSE; \ colour2 = *data; \ } \ \ if (*data == colour2) { \ n2++; \ continue; \ } \ \ *mono = FALSE; \ break; \ } \ \ if (n1 > n2) { \ *bg = colour1; \ *fg = colour2; \ } else { \ *bg = colour2; \ *fg = colour1; \ } \ } DEFINE_SEND_HEXTILES(8) DEFINE_SEND_HEXTILES(16) DEFINE_SEND_HEXTILES(32) --- NEW FILE: httpd.c --- /* * httpd.c - a simple HTTP server */ /* * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this software; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. */ #include <stdio.h> #include <sys/types.h> #include <sys/time.h> #include <sys/socket.h> #include <netinet/in.h> #include <netinet/tcp.h> #include <netdb.h> #include <fcntl.h> #include <errno.h> #include <pwd.h> #include "rfb.h" #define NOT_FOUND_STR "HTTP/1.0 404 Not found\n\n" \ "<HEAD><TITLE>File Not Found</TITLE></HEAD>\n" \ "<BODY><H1>File Not Found</H1></BODY>\n" #define OK_STR "HTTP/1.0 200 OK\n\n" static void httpProcessInput(); static Bool compareAndSkip(char **ptr, const char *str); int httpPort = 0; char *httpDir = NULL; int httpListenSock = -1; int httpSock = -1; FILE* httpFP = NULL; #define BUF_SIZE 32768 static char buf[BUF_SIZE]; /* * httpInitSockets sets up the TCP socket to listen for HTTP connections. */ void httpInitSockets() { static Bool done = FALSE; if (done) return; done = TRUE; if (!httpDir) return; if (httpPort == 0) { httpPort = 5800 + atoi(display); } rfbLog("Listening for HTTP connections on TCP port %d\n", httpPort); rfbLog(" URL http://%s:%d\n",rfbThisHost,httpPort); if ((httpListenSock = ListenOnTCPPort(httpPort)) < 0) { rfbLogPerror("ListenOnTCPPort"); exit(1); } AddEnabledDevice(httpListenSock); } /* * httpCheckFds is called from ProcessInputEvents to check for input on the * HTTP socket(s). If there is input to process, httpProcessInput is called. */ void httpCheckFds() { int nfds, n; fd_set fds; struct timeval tv; struct sockaddr_in addr; int addrlen = sizeof(addr); if (!httpDir) return; FD_ZERO(&fds); FD_SET(httpListenSock, &fds); if (httpSock >= 0) { FD_SET(httpSock, &fds); } tv.tv_sec = 0; tv.tv_usec = 0; nfds = select(max(httpSock,httpListenSock) + 1, &fds, NULL, NULL, &tv); if (nfds == 0) { return; } if (nfds < 0) { rfbLogPerror("httpCheckFds: select"); return; } if ((httpSock >= 0) && FD_ISSET(httpSock, &fds)) { httpProcessInput(); } if (FD_ISSET(httpListenSock, &fds)) { if (httpSock >= 0) close(httpSock); if ((httpSock = accept(httpListenSock, (struct sockaddr *)&addr, &addrlen)) < 0) { rfbLogPerror("httpCheckFds: accept"); return; } if ((httpFP = fdopen(httpSock, "r+")) == NULL) { rfbLogPerror("httpCheckFds: fdopen"); close(httpSock); httpSock = -1; return; } AddEnabledDevice(httpSock); } } static void httpCloseSock() { fclose(httpFP); httpFP = NULL; RemoveEnabledDevice(httpSock); httpSock = -1; } /* * httpProcessInput is called when input is received on the HTTP socket. */ static void httpProcessInput() { struct sockaddr_in addr; int addrlen = sizeof(addr); char fullFname[256]; char *fname; int maxFnameLen; int fd; Bool gotGet = FALSE; Bool performSubstitutions = FALSE; char str[256]; struct passwd *user = getpwuid(getuid());; if (strlen(httpDir) > 200) { rfbLog("-httpd directory too long\n"); httpCloseSock(); return; } strcpy(fullFname, httpDir); fname = &fullFname[strlen(fullFname)]; maxFnameLen = 255 - strlen(fullFname); buf[0] = '\0'; while (1) { /* Read lines from the HTTP client until a blank line. The only line we need to parse is the line "GET <filename> ..." */ if (!fgets(buf, BUF_SIZE, httpFP)) { rfbLogPerror("httpProcessInput: fgets"); httpCloseSock(); return; } if ((strcmp(buf,"\n") == 0) || (strcmp(buf,"\r\n") == 0) || (strcmp(buf,"\r") == 0) || (strcmp(buf,"\n\r") == 0)) /* end of client request */ break; if (strncmp(buf, "GET ", 4) == 0) { gotGet = TRUE; if (strlen(buf) > maxFnameLen) { rfbLog("GET line too long\n"); httpCloseSock(); return; } if (sscanf(buf, "GET %s HTTP/1.0", fname) != 1) { rfbLog("couldn't parse GET line\n"); httpCloseSock(); return; } if (fname[0] != '/') { rfbLog("filename didn't begin with '/'\n"); WriteExact(httpSock, NOT_FOUND_STR, strlen(NOT_FOUND_STR)); httpCloseSock(); return; } if (strchr(fname+1, '/') != NULL) { rfbLog("asking for file in other directory\n"); WriteExact(httpSock, NOT_FOUND_STR, strlen(NOT_FOUND_STR)); httpCloseSock(); return; } getpeername(httpSock, (struct sockaddr *)&addr, &addrlen); rfbLog("httpd: get '%s' for %s\n", fname+1, inet_ntoa(addr.sin_addr)); continue; } } if (!gotGet) { rfbLog("no GET line\n"); httpCloseSock(); return; } /* If we were asked for '/', actually read the file index.vnc */ if (strcmp(fname, "/") == 0) { strcpy(fname, "/index.vnc"); rfbLog("httpd: defaulting to '%s'\n", fname+1); } /* Substitutions are performed on files ending .vnc */ if (strlen(fname) >= 4 && strcmp(&fname[strlen(fname)-4], ".vnc") == 0) { performSubstitutions = TRUE; } /* Open the file */ if ((fd = open(fullFname, O_RDONLY)) < 0) { rfbLogPerror("httpProcessInput: open"); WriteExact(httpSock, NOT_FOUND_STR, strlen(NOT_FOUND_STR)); httpCloseSock(); return; } WriteExact(httpSock, OK_STR, strlen(OK_STR)); while (1) { int n = read(fd, buf, BUF_SIZE-1); if (n < 0) { rfbLogPerror("httpProcessInput: read"); close(fd); httpCloseSock(); return; } if (n == 0) break; if (performSubstitutions) { /* Substitute $WIDTH, $HEIGHT, etc with the appropriate values. This won't quite work properly if the .vnc file is longer than BUF_SIZE, but it's reasonable to assume that .vnc files will always be short. */ char *ptr = buf; char *dollar; buf[n] = 0; /* make sure it's null-terminated */ while (dollar = strchr(ptr, '$')) { WriteExact(httpSock, ptr, (dollar - ptr)); ptr = dollar; if (compareAndSkip(&ptr, "$WIDTH")) { sprintf(str, "%d", rfbScreen.width); WriteExact(httpSock, str, strlen(str)); } else if (compareAndSkip(&ptr, "$HEIGHT")) { sprintf(str, "%d", rfbScreen.height); WriteExact(httpSock, str, strlen(str)); } else if (compareAndSkip(&ptr, "$APPLETWIDTH")) { sprintf(str, "%d", rfbScreen.width); WriteExact(httpSock, str, strlen(str)); } else if (compareAndSkip(&ptr, "$APPLETHEIGHT")) { sprintf(str, "%d", rfbScreen.height + 32); WriteExact(httpSock, str, strlen(str)); } else if (compareAndSkip(&ptr, "$PORT")) { sprintf(str, "%d", rfbPort); WriteExact(httpSock, str, strlen(str)); } else if (compareAndSkip(&ptr, "$DESKTOP")) { WriteExact(httpSock, desktopName, strlen(desktopName)); } else if (compareAndSkip(&ptr, "$DISPLAY")) { sprintf(str, "%s:%s", rfbThisHost, display); WriteExact(httpSock, str, strlen(str)); } else if (compareAndSkip(&ptr, "$USER")) { if (user) { WriteExact(httpSock, user->pw_name, strlen(user->pw_name)); } else { WriteExact(httpSock, "?", 1); } } else { if (!compareAndSkip(&ptr, "$$")) ptr++; if (WriteExact(httpSock, "$", 1) < 0) { close(fd); httpCloseSock(); return; } } } if (WriteExact(httpSock, ptr, (&buf[n] - ptr)) < 0) break; } else { /* For files not ending .vnc, just write out the buffer */ if (WriteExact(httpSock, buf, n) < 0) break; } } close(fd); httpCloseSock(); } static Bool compareAndSkip(char **ptr, const char *str) { if (strncmp(*ptr, str, strlen(str)) == 0) { *ptr += strlen(str); return TRUE; } return FALSE; } --- NEW FILE: init.c --- /* * init.c */ /* * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. * * This is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this software; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, * USA. */ /* Copyright (c) 1993 X Consortium Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 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 X CONSORTIUM 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 X Consortium 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 X Consortium. */ /* Use ``#define CORBA'' to enable CORBA control interface */ #include <stdio.h> #include <stdarg.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <netdb.h> #include "X11/X.h" #define NEED_EVENTS #include "X11/Xproto.h" #include "X11/Xos.h" #include "scrnintstr.h" #include "servermd.h" #define PSZ 8 #include "cfb.h" #include "mibstore.h" #include "colormapst.h" #include "gcstruct.h" #include "input.h" #include "mipointer.h" #include "dixstruct.h" #include "propertyst.h" #include <Xatom.h> #include <errno.h> #include <sys/param.h> #include "dix.h" #include "rfb.h" #ifdef CORBA #include <vncserverctrl.h> #endif #define RFB_DEFAULT_WIDTH 640 #define RFB_DEFAULT_HEIGHT 480 #define RFB_DEFAULT_DEPTH 8 #define RFB_DEFAULT_WHITEPIXEL 0 #define RFB_DEFAULT_BLACKPIXEL 1 rfbScreenInfo rfbScreen; int rfbGCIndex; static Bool initOutputCalled = FALSE; static Bool noCursor = FALSE; char *desktopName = "x11"; char rfbThisHost[256]; Atom VNC_LAST_CLIENT_ID; Atom VNC_CONNECT; static HWEventQueueType alwaysCheckForInput[2] = { 0, 1 }; static HWEventQueueType *mieqCheckForInput[2]; static char primaryOrder[4] = ""; static int redBits, greenBits, blueBits; static Bool rfbScreenInit(int index, ScreenPtr pScreen, int argc, char **argv); static int rfbKeybdProc(DeviceIntPtr pDevice, int onoff); static int rfbMouseProc(DeviceIntPtr pDevice, int onoff); static Bool CheckDisplayNumber(int n); static Bool rfbAlwaysTrue(); static char *rfbAllocateFramebufferMemory(rfbScreenInfoPtr prfb); static Bool rfbCursorOffScreen(ScreenPtr *ppScreen, int *x, int *y); static void rfbCrossScreen(ScreenPtr pScreen, Bool entering); static void rfbClientStateChange(CallbackListPtr *, pointer myData, pointer client); static miPointerScreenFuncRec rfbPointerCursorFuncs = { rfbCursorOffScreen, rfbCrossScreen, miPointerWarpCursor }; int inetdSock = -1; static char inetdDisplayNumStr[10]; /* * ddxProcessArgument is our first entry point and will be called at the * very start for each argument. It is not called again on server reset. */ int ddxProcessArgument (argc, argv, i) int argc; char *argv[]; int i; { static Bool firstTime = TRUE; if (firstTime) { rfbScreen.width = RFB_DEFAULT_WIDTH; rfbScreen.height = RFB_DEFAULT_HEIGHT; rfbScreen.depth = RFB_DEFAULT_DEPTH; rfbScreen.blackPixel = RFB_DEFAULT_BLACKPIXEL; rfbScreen.whitePixel = RFB_DEFAULT_WHITEPIXEL; rfbScreen.pfbMemory = NULL; gethostname(rfbThisHost, 255); firstTime = FALSE; } if (strcmp (argv[i], "-geometry") == 0) /* -geometry WxH */ { if (i + 1 >= argc) UseMsg(); if (sscanf(argv[i+1],"%dx%d", &rfbScreen.width,&rfbScreen.height) != 2) { ErrorF("Invalid geometry %s\n", argv[i+1]); UseMsg(); } #ifdef CORBA screenWidth= rfbScreen.width; screenHeight= rfbScreen.height; #endif return 2; } if (strcmp (argv[i], "-depth") == 0) /* -depth D */ { if (i + 1 >= argc) UseMsg(); rfbScreen.depth = atoi(argv[i+1]); #ifdef CORBA screenDepth= rfbScreen.depth; #endif return 2; } if (strcmp (argv[i], "-pixelformat") == 0) { if (i + 1 >= argc) UseMsg(); if (sscanf(argv[i+1], "%3s%1d%1d%1d", prima... [truncated message content] |