diff options
author | dscho <dscho> | 2001-08-01 11:52:01 +0000 |
---|---|---|
committer | dscho <dscho> | 2001-08-01 11:52:01 +0000 |
commit | 757fdc2454a97890c119cca8662b8d1763265e9a (patch) | |
tree | 44256826d7aafaa816041a18fa0405097f2ed4cd /rfb.h | |
download | libtdevnc-757fdc2454a97890c119cca8662b8d1763265e9a.tar.gz libtdevnc-757fdc2454a97890c119cca8662b8d1763265e9a.zip |
Initial revision
Diffstat (limited to 'rfb.h')
-rw-r--r-- | rfb.h | 522 |
1 files changed, 522 insertions, 0 deletions
@@ -0,0 +1,522 @@ +/* + * rfb.h - header file for RFB DDX implementation. + */ + +/* + * OSXvnc Copyright (C) 2001 Dan McGuirk <[email protected]>. + * Original Xvnc code 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 "scrnintstr.h" + +/* trying to replace the above with some more minimal set of includes */ +#include "misc.h" +#include "Xmd.h" +#include "regionstr.h" +#include <zlib.h> + +#include <rfbproto.h> +#include <vncauth.h> +#include <netinet/in.h> +#ifdef HAVE_PTHREADS +#include <pthread.h> +#endif +#ifdef __linux__ +#include <endian.h> +#else +#include <sys/endian.h> +#endif + +#ifndef _BYTE_ORDER +#define _BYTE_ORDER __BYTE_ORDER +#endif + +#ifndef _LITTLE_ENDIAN +#define _LITTLE_ENDIAN __LITTLE_ENDIAN +#endif + +#define MAX_ENCODINGS 10 + +#ifdef HAVE_PTHREADS +#define IF_PTHREADS(x) (x) +#else +#define IF_PTHREADS(x) +#endif + +struct rfbClientRec; +//typedef struct rfbClientInfo* rfbClientPtr; +typedef void (*KbdAddEventProcPtr) (Bool down, KeySym keySym, struct rfbClientRec* cl); +typedef void (*KbdReleaseAllKeysProcPtr) (struct rfbClientRec* cl); +typedef void (*PtrAddEventProcPtr) (int buttonMask, int x, int y, struct rfbClientRec* cl); +typedef void (*SetXCutTextProcPtr) (char* str,int len, struct rfbClientRec* cl); + +/* + * Per-screen (framebuffer) structure. There is only one of these, since we + * don't allow the X server to have multiple screens. + */ + +typedef struct +{ + int width; + int paddedWidthInBytes; + int height; + int depth; + int bitsPerPixel; + int sizeInBytes; + + Pixel blackPixel; + Pixel whitePixel; + + /* The following two members are used to minimise the amount of unnecessary + drawing caused by cursor movement. Whenever any drawing affects the + part of the screen where the cursor is, the cursor is removed first and + then the drawing is done (this is what the sprite routines test for). + Afterwards, however, we do not replace the cursor, even when the cursor + is logically being moved across the screen. We only draw the cursor + again just as we are about to send the client a framebuffer update. + + We need to be careful when removing and drawing the cursor because of + their relationship with the normal drawing routines. The drawing + routines can invoke the cursor routines, but also the cursor routines + themselves end up invoking drawing routines. + + Removing the cursor (rfbSpriteRemoveCursor) is eventually achieved by + doing a CopyArea from a pixmap to the screen, where the pixmap contains + the saved contents of the screen under the cursor. Before doing this, + however, we set cursorIsDrawn to FALSE. Then, when CopyArea is called, + it sees that cursorIsDrawn is FALSE and so doesn't feel the need to + (recursively!) remove the cursor before doing it. + + Putting up the cursor (rfbSpriteRestoreCursor) involves a call to + PushPixels. While this is happening, cursorIsDrawn must be FALSE so + that PushPixels doesn't think it has to remove the cursor first. + Obviously cursorIsDrawn is set to TRUE afterwards. + + Another problem we face is that drawing routines sometimes cause a + framebuffer update to be sent to the RFB client. When the RFB client is + already waiting for a framebuffer update and some drawing to the + framebuffer then happens, the drawing routine sees that the client is + ready, so it calls rfbSendFramebufferUpdate. If the cursor is not drawn + at this stage, it must be put up, and so rfbSpriteRestoreCursor is + called. However, if the original drawing routine was actually called + from within rfbSpriteRestoreCursor or rfbSpriteRemoveCursor we don't + want this to happen. So both the cursor routines set + dontSendFramebufferUpdate to TRUE, and all the drawing routines check + this before calling rfbSendFramebufferUpdate. */ + + Bool cursorIsDrawn; /* TRUE if the cursor is currently drawn */ + Bool dontSendFramebufferUpdate; /* TRUE while removing or drawing the + cursor */ + + /* wrapped screen functions */ + + CloseScreenProcPtr CloseScreen; + CreateGCProcPtr CreateGC; + PaintWindowBackgroundProcPtr PaintWindowBackground; + PaintWindowBorderProcPtr PaintWindowBorder; + CopyWindowProcPtr CopyWindow; + ClearToBackgroundProcPtr ClearToBackground; + RestoreAreasProcPtr RestoreAreas; + + /* additions by libvncserver */ + + ScreenRec screen; + rfbPixelFormat rfbServerFormat; + char* desktopName; + char rfbThisHost[255]; + int rfbPort; + Bool socketInitDone; + int inetdSock; + int maxSock; + int maxFd; + int rfbListenSock; + int udpPort; + int udpSock; + Bool udpSockConnected; + struct sockaddr_in udpRemoteAddr; + Bool inetdInitDone; + fd_set allFds; + int rfbMaxClientWait; + char* rfbAuthPasswdFile; + int rfbDeferUpdateTime; + char* rfbScreen; + Bool rfbAlwaysShared; + Bool rfbNeverShared; + Bool rfbDontDisconnect; + struct rfbClientRec* rfbClientHead; + + /* the following members have to be supplied by the serving process */ + char* frameBuffer; + KbdAddEventProcPtr kbdAddEvent; + KbdReleaseAllKeysProcPtr kbdReleaseAllKeys; + PtrAddEventProcPtr ptrAddEvent; + SetXCutTextProcPtr setXCutText; +} rfbScreenInfo, *rfbScreenInfoPtr; + + +/* + * rfbTranslateFnType is the type of translation functions. + */ + +struct rfbClientRec; +typedef void (*rfbTranslateFnType)(char *table, rfbPixelFormat *in, + rfbPixelFormat *out, + char *iptr, char *optr, + int bytesBetweenInputLines, + int width, int height); + + +/* + * Per-client structure. + */ + +typedef struct rfbClientRec { + rfbScreenInfoPtr screen; + + int sock; + char *host; +#ifdef HAVE_PTHREADS + pthread_mutex_t outputMutex; +#endif + /* Possible client states: */ + enum { + RFB_PROTOCOL_VERSION, /* establishing protocol version */ + RFB_AUTHENTICATION, /* authenticating */ + RFB_INITIALISATION, /* sending initialisation messages */ + RFB_NORMAL /* normal protocol messages */ + } state; + + Bool reverseConnection; + + Bool readyForSetColourMapEntries; + + Bool useCopyRect; + int preferredEncoding; + int correMaxWidth, correMaxHeight; + + /* The following member is only used during VNC authentication */ + + CARD8 authChallenge[CHALLENGESIZE]; + + /* The following members represent the update needed to get the client's + framebuffer from its present state to the current state of our + framebuffer. + + If the client does not accept CopyRect encoding then the update is + simply represented as the region of the screen which has been modified + (modifiedRegion). + + If the client does accept CopyRect encoding, then the update consists of + two parts. First we have a single copy from one region of the screen to + another (the destination of the copy is copyRegion), and second we have + the region of the screen which has been modified in some other way + (modifiedRegion). + + Although the copy is of a single region, this region may have many + rectangles. When sending an update, the copyRegion is always sent + before the modifiedRegion. This is because the modifiedRegion may + overlap parts of the screen which are in the source of the copy. + + In fact during normal processing, the modifiedRegion may even overlap + the destination copyRegion. Just before an update is sent we remove + from the copyRegion anything in the modifiedRegion. */ + + RegionRec copyRegion; /* the destination region of the copy */ + int copyDX, copyDY; /* the translation by which the copy happens */ + + +#ifdef HAVE_PTHREADS + pthread_mutex_t updateMutex; + pthread_cond_t updateCond; +#endif + + RegionRec modifiedRegion; + + /* As part of the FramebufferUpdateRequest, a client can express interest + in a subrectangle of the whole framebuffer. This is stored in the + requestedRegion member. In the normal case this is the whole + framebuffer if the client is ready, empty if it's not. */ + + RegionRec requestedRegion; + + /* The following members represent the state of the "deferred update" timer + - when the framebuffer is modified and the client is ready, in most + cases it is more efficient to defer sending the update by a few + milliseconds so that several changes to the framebuffer can be combined + into a single update. */ + + Bool deferredUpdateScheduled; + OsTimerPtr deferredUpdateTimer; + + /* translateFn points to the translation function which is used to copy + and translate a rectangle from the framebuffer to an output buffer. */ + + rfbTranslateFnType translateFn; + + char *translateLookupTable; + + rfbPixelFormat format; + +/* + * UPDATE_BUF_SIZE must be big enough to send at least one whole line of the + * framebuffer. So for a max screen width of say 2K with 32-bit pixels this + * means 8K minimum. + */ + +#define UPDATE_BUF_SIZE 30000 + + char updateBuf[UPDATE_BUF_SIZE]; + int ublen; + + /* statistics */ + + int rfbBytesSent[MAX_ENCODINGS]; + int rfbRectanglesSent[MAX_ENCODINGS]; + int rfbLastRectMarkersSent; + int rfbLastRectBytesSent; + int rfbCursorBytesSent; + int rfbCursorUpdatesSent; + int rfbFramebufferUpdateMessagesSent; + int rfbRawBytesEquivalent; + int rfbKeyEventsRcvd; + int rfbPointerEventsRcvd; + + /* zlib encoding -- necessary compression state info per client */ + + struct z_stream_s compStream; + Bool compStreamInited; + + CARD32 zlibCompressLevel; + + /* tight encoding -- preserve zlib streams' state for each client */ + + z_stream zsStruct[4]; + Bool zsActive[4]; + int zsLevel[4]; + int tightCompressLevel; + int tightQualityLevel; + + Bool enableLastRectEncoding; /* client supports LastRect encoding */ + Bool enableCursorShapeUpdates; /* client supports cursor shape updates */ + Bool useRichCursorEncoding; /* rfbEncodingRichCursor is preferred */ + Bool cursorWasChanged; /* cursor shape update should be sent */ + + struct rfbClientRec *prev; + struct rfbClientRec *next; + +} rfbClientRec, *rfbClientPtr; + + +/* + * This macro is used to test whether there is a framebuffer update needing to + * be sent to the client. + */ + +#define FB_UPDATE_PENDING(cl) \ + ((!(cl)->enableCursorShapeUpdates && !(cl)->screen->cursorIsDrawn) || \ + ((cl)->enableCursorShapeUpdates && (cl)->cursorWasChanged) || \ + REGION_NOTEMPTY(&((cl)->screenInfo->screen),&(cl)->copyRegion) || \ + REGION_NOTEMPTY(&((cl)->screenInfo->screen),&(cl)->modifiedRegion)) + +/* + * This macro creates an empty region (ie. a region with no areas) if it is + * given a rectangle with a width or height of zero. It appears that + * REGION_INTERSECT does not quite do the right thing with zero-width + * rectangles, but it should with completely empty regions. + */ + +#define SAFE_REGION_INIT(pscreen, preg, rect, size) \ +{ \ + if ( ( (rect) ) && \ + ( ( (rect)->x2 == (rect)->x1 ) || \ + ( (rect)->y2 == (rect)->y1 ) ) ) { \ + REGION_INIT( (pscreen), (preg), NullBox, 0 ); \ + } else { \ + REGION_INIT( (pscreen), (preg), (rect), (size) ); \ + } \ +} + + +/* + * Macros for endian swapping. + */ + +#define Swap16(s) ((((s) & 0xff) << 8) | (((s) >> 8) & 0xff)) + +#define Swap32(l) (((l) >> 24) | \ + (((l) & 0x00ff0000) >> 8) | \ + (((l) & 0x0000ff00) << 8) | \ + ((l) << 24)) + + +static const int rfbEndianTest = (_BYTE_ORDER == _LITTLE_ENDIAN); + +#define Swap16IfLE(s) (*(const char *)&rfbEndianTest ? Swap16(s) : (s)) + +#define Swap32IfLE(l) (*(const char *)&rfbEndianTest ? Swap32(l) : (l)) + +/* main.c */ + +extern void rfbLog(char *format, ...); +extern void rfbLogPerror(char *str); +extern int runVNCServer(int argc, char *argv[]); + + +/* sockets.c */ + +extern int rfbMaxClientWait; + +extern void rfbCloseClient(rfbClientPtr cl); +extern int ReadExact(rfbClientPtr cl, char *buf, int len); +extern int WriteExact(rfbClientPtr cl, char *buf, int len); +extern void rfbCheckFds(rfbScreenInfoPtr rfbScreen,long usec); +extern int ListenOnTCPPort(int port); +extern int ListenOnUDPPort(int port); + +/* rfbserver.c */ + +extern rfbClientPtr pointerClient; + + +/* Routines to iterate over the client list in a thread-safe way. + Only a single iterator can be in use at a time process-wide. */ +typedef struct rfbClientIterator *rfbClientIteratorPtr; + +extern void rfbClientListInit(rfbScreenInfoPtr rfbScreen); +extern rfbClientIteratorPtr rfbGetClientIterator(rfbScreenInfoPtr rfbScreen); +extern rfbClientPtr rfbClientIteratorNext(rfbClientIteratorPtr iterator); +extern void rfbReleaseClientIterator(rfbClientIteratorPtr iterator); + +extern void rfbNewClientConnection(rfbScreenInfoPtr rfbScreen,int sock); +extern rfbClientPtr rfbNewClient(rfbScreenInfoPtr rfbScreen,int sock); +extern rfbClientPtr rfbReverseConnection(char *host, int port); +extern void rfbClientConnectionGone(rfbClientPtr cl); +extern void rfbProcessClientMessage(rfbClientPtr cl); +extern void rfbClientConnFailed(rfbClientPtr cl, char *reason); +extern void rfbNewUDPConnection(rfbScreenInfoPtr rfbScreen,int sock); +extern void rfbProcessUDPInput(rfbClientPtr cl); +extern Bool rfbSendFramebufferUpdate(rfbClientPtr cl, RegionRec updateRegion); +extern Bool rfbSendRectEncodingRaw(rfbClientPtr cl, int x,int y,int w,int h); +extern Bool rfbSendUpdateBuf(rfbClientPtr cl); +extern void rfbSendServerCutText(rfbScreenInfoPtr rfbScreen,char *str, int len); + +void rfbGotXCutText(rfbScreenInfoPtr rfbScreen, char *str, int len); + +/* translate.c */ + +extern Bool rfbEconomicTranslate; + +extern void rfbTranslateNone(char *table, rfbPixelFormat *in, + rfbPixelFormat *out, + char *iptr, char *optr, + int bytesBetweenInputLines, + int width, int height); +extern Bool rfbSetTranslateFunction(rfbClientPtr cl); + + +/* httpd.c */ + +extern int httpPort; +extern char *httpDir; + +extern void httpInitSockets(); +extern void httpCheckFds(); + + + +/* auth.c */ + +extern char *rfbAuthPasswdFile; +extern Bool rfbAuthenticating; + +extern void rfbAuthNewClient(rfbClientPtr cl); +extern void rfbAuthProcessClientMessage(rfbClientPtr cl); + + +/* rre.c */ + +extern Bool rfbSendRectEncodingRRE(rfbClientPtr cl, int x,int y,int w,int h); + + +/* corre.c */ + +extern Bool rfbSendRectEncodingCoRRE(rfbClientPtr cl, int x,int y,int w,int h); + + +/* hextile.c */ + +extern Bool rfbSendRectEncodingHextile(rfbClientPtr cl, int x, int y, int w, + int h); + + +/* zlib.c */ + +/* Minimum zlib rectangle size in bytes. Anything smaller will + * not compress well due to overhead. + */ +#define VNC_ENCODE_ZLIB_MIN_COMP_SIZE (17) + +/* Set maximum zlib rectangle size in pixels. Always allow at least + * two scan lines. + */ +#define ZLIB_MAX_RECT_SIZE (128*256) +#define ZLIB_MAX_SIZE(min) ((( min * 2 ) > ZLIB_MAX_RECT_SIZE ) ? \ + ( min * 2 ) : ZLIB_MAX_RECT_SIZE ) + +extern Bool rfbSendRectEncodingZlib(rfbClientPtr cl, int x, int y, int w, + int h); + + +/* tight.c */ + +#define TIGHT_DEFAULT_COMPRESSION 6 + +extern Bool rfbTightDisableGradient; + +extern int rfbNumCodedRectsTight(rfbClientPtr cl, int x,int y,int w,int h); +extern Bool rfbSendRectEncodingTight(rfbClientPtr cl, int x,int y,int w,int h); + + +/* cursor.c */ + +extern Bool rfbSendCursorShape(rfbClientPtr cl, ScreenPtr pScreen); + + +/* stats.c */ + +extern void rfbResetStats(rfbClientPtr cl); +extern void rfbPrintStats(rfbClientPtr cl); + +extern void rfbInitSockets(rfbScreenInfoPtr rfbScreen); +extern void rfbDisconnectUDPSock(rfbScreenInfoPtr cl); + +void rfbMarkRectAsModified(rfbScreenInfoPtr rfbScreen,int x1,int y1,int x2,int y2); +void rfbMarkRegionAsModified(rfbScreenInfoPtr rfbScreen,RegionPtr modRegion); + + +/* functions to make a vnc server */ +extern rfbScreenInfoPtr rfbDefaultScreenInit(int argc,char** argv); +extern void rfbScreenCleanup(rfbScreenInfoPtr screenInfo); + +/* call one of these two functions to service the vnc clients. + usec are the microseconds the select on the fds waits. + if you are using the event loop, set this to some value > 0. */ + +extern void runEventLoop(rfbScreenInfoPtr screenInfo, long usec, Bool runInBackground); +extern void processEvents(rfbScreenInfoPtr screenInfo,long usec); |