1277 lines
48 KiB
C
1277 lines
48 KiB
C
|
#ifndef RFB_H
|
||
|
#define RFB_H
|
||
|
/**
|
||
|
* @defgroup libvncserver_api LibVNCServer API Reference
|
||
|
* @{
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* @file rfb.h
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
* Copyright (C) 2005 Rohit Kumar <rokumar@novell.com>,
|
||
|
* Johannes E. Schindelin <johannes.schindelin@gmx.de>
|
||
|
* Copyright (C) 2002 RealVNC Ltd.
|
||
|
* OSXvnc Copyright (C) 2001 Dan McGuirk <mcguirk@incompleteness.net>.
|
||
|
* 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.
|
||
|
*/
|
||
|
|
||
|
#if(defined __cplusplus)
|
||
|
extern "C"
|
||
|
{
|
||
|
#endif
|
||
|
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
#include <rfb/rfbproto.h>
|
||
|
|
||
|
#if defined(ANDROID) || defined(LIBVNCSERVER_HAVE_ANDROID)
|
||
|
#include <arpa/inet.h>
|
||
|
#include <sys/select.h>
|
||
|
#endif
|
||
|
|
||
|
#ifdef LIBVNCSERVER_HAVE_SYS_TYPES_H
|
||
|
#include <sys/types.h>
|
||
|
#endif
|
||
|
|
||
|
#ifdef __MINGW32__
|
||
|
#undef SOCKET
|
||
|
#include <winsock2.h>
|
||
|
#ifdef LIBVNCSERVER_HAVE_WS2TCPIP_H
|
||
|
#undef socklen_t
|
||
|
#include <ws2tcpip.h>
|
||
|
#endif
|
||
|
#endif
|
||
|
|
||
|
#ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
|
||
|
#include <pthread.h>
|
||
|
#if 0 /* debugging */
|
||
|
#define LOCK(mutex) (rfbLog("%s:%d LOCK(%s,0x%x)\n",__FILE__,__LINE__,#mutex,&(mutex)), pthread_mutex_lock(&(mutex)))
|
||
|
#define UNLOCK(mutex) (rfbLog("%s:%d UNLOCK(%s,0x%x)\n",__FILE__,__LINE__,#mutex,&(mutex)), pthread_mutex_unlock(&(mutex)))
|
||
|
#define MUTEX(mutex) pthread_mutex_t (mutex)
|
||
|
#define INIT_MUTEX(mutex) (rfbLog("%s:%d INIT_MUTEX(%s,0x%x)\n",__FILE__,__LINE__,#mutex,&(mutex)), pthread_mutex_init(&(mutex),NULL))
|
||
|
#define TINI_MUTEX(mutex) (rfbLog("%s:%d TINI_MUTEX(%s)\n",__FILE__,__LINE__,#mutex), pthread_mutex_destroy(&(mutex)))
|
||
|
#define TSIGNAL(cond) (rfbLog("%s:%d TSIGNAL(%s)\n",__FILE__,__LINE__,#cond), pthread_cond_signal(&(cond)))
|
||
|
#define WAIT(cond,mutex) (rfbLog("%s:%d WAIT(%s,%s)\n",__FILE__,__LINE__,#cond,#mutex), pthread_cond_wait(&(cond),&(mutex)))
|
||
|
#define COND(cond) pthread_cond_t (cond)
|
||
|
#define INIT_COND(cond) (rfbLog("%s:%d INIT_COND(%s)\n",__FILE__,__LINE__,#cond), pthread_cond_init(&(cond),NULL))
|
||
|
#define TINI_COND(cond) (rfbLog("%s:%d TINI_COND(%s)\n",__FILE__,__LINE__,#cond), pthread_cond_destroy(&(cond)))
|
||
|
#define IF_PTHREADS(x) x
|
||
|
#else
|
||
|
#if !NONETWORK
|
||
|
#define LOCK(mutex) pthread_mutex_lock(&(mutex));
|
||
|
#define UNLOCK(mutex) pthread_mutex_unlock(&(mutex));
|
||
|
#endif
|
||
|
#define MUTEX(mutex) pthread_mutex_t (mutex)
|
||
|
#define INIT_MUTEX(mutex) pthread_mutex_init(&(mutex),NULL)
|
||
|
#define TINI_MUTEX(mutex) pthread_mutex_destroy(&(mutex))
|
||
|
#define TSIGNAL(cond) pthread_cond_signal(&(cond))
|
||
|
#define WAIT(cond,mutex) pthread_cond_wait(&(cond),&(mutex))
|
||
|
#define COND(cond) pthread_cond_t (cond)
|
||
|
#define INIT_COND(cond) pthread_cond_init(&(cond),NULL)
|
||
|
#define TINI_COND(cond) pthread_cond_destroy(&(cond))
|
||
|
#define IF_PTHREADS(x) x
|
||
|
#endif
|
||
|
#else
|
||
|
#define LOCK(mutex)
|
||
|
#define UNLOCK(mutex)
|
||
|
#define MUTEX(mutex)
|
||
|
#define INIT_MUTEX(mutex)
|
||
|
#define TINI_MUTEX(mutex)
|
||
|
#define TSIGNAL(cond)
|
||
|
#define WAIT(cond,mutex) this_is_unsupported
|
||
|
#define COND(cond)
|
||
|
#define INIT_COND(cond)
|
||
|
#define TINI_COND(cond)
|
||
|
#define IF_PTHREADS(x)
|
||
|
#endif
|
||
|
|
||
|
/* end of stuff for autoconf */
|
||
|
|
||
|
/* if you use pthreads, but don't define LIBVNCSERVER_HAVE_LIBPTHREAD, the structs
|
||
|
get all mixed up. So this gives a linker error reminding you to compile
|
||
|
the library and your application (at least the parts including rfb.h)
|
||
|
with the same support for pthreads. */
|
||
|
#ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
|
||
|
#ifdef LIBVNCSERVER_HAVE_LIBZ
|
||
|
#define rfbInitServer rfbInitServerWithPthreadsAndZRLE
|
||
|
#else
|
||
|
#define rfbInitServer rfbInitServerWithPthreadsButWithoutZRLE
|
||
|
#endif
|
||
|
#else
|
||
|
#ifdef LIBVNCSERVER_HAVE_LIBZ
|
||
|
#define rfbInitServer rfbInitServerWithoutPthreadsButWithZRLE
|
||
|
#else
|
||
|
#define rfbInitServer rfbInitServerWithoutPthreadsAndZRLE
|
||
|
#endif
|
||
|
#endif
|
||
|
|
||
|
struct _rfbClientRec;
|
||
|
struct _rfbScreenInfo;
|
||
|
struct rfbCursor;
|
||
|
|
||
|
enum rfbNewClientAction {
|
||
|
RFB_CLIENT_ACCEPT,
|
||
|
RFB_CLIENT_ON_HOLD,
|
||
|
RFB_CLIENT_REFUSE
|
||
|
};
|
||
|
|
||
|
enum rfbSocketState {
|
||
|
RFB_SOCKET_INIT,
|
||
|
RFB_SOCKET_READY,
|
||
|
RFB_SOCKET_SHUTDOWN
|
||
|
};
|
||
|
|
||
|
typedef void (*rfbKbdAddEventProcPtr) (rfbBool down, rfbKeySym keySym, struct _rfbClientRec* cl);
|
||
|
typedef void (*rfbKbdReleaseAllKeysProcPtr) (struct _rfbClientRec* cl);
|
||
|
typedef void (*rfbPtrAddEventProcPtr) (int buttonMask, int x, int y, struct _rfbClientRec* cl);
|
||
|
typedef void (*rfbSetXCutTextProcPtr) (char* str,int len, struct _rfbClientRec* cl);
|
||
|
typedef struct rfbCursor* (*rfbGetCursorProcPtr) (struct _rfbClientRec* pScreen);
|
||
|
typedef rfbBool (*rfbSetTranslateFunctionProcPtr)(struct _rfbClientRec* cl);
|
||
|
typedef rfbBool (*rfbPasswordCheckProcPtr)(struct _rfbClientRec* cl,const char* encryptedPassWord,int len);
|
||
|
typedef enum rfbNewClientAction (*rfbNewClientHookPtr)(struct _rfbClientRec* cl);
|
||
|
typedef void (*rfbDisplayHookPtr)(struct _rfbClientRec* cl);
|
||
|
typedef void (*rfbDisplayFinishedHookPtr)(struct _rfbClientRec* cl, int result);
|
||
|
/** support the capability to view the caps/num/scroll states of the X server */
|
||
|
typedef int (*rfbGetKeyboardLedStateHookPtr)(struct _rfbScreenInfo* screen);
|
||
|
typedef rfbBool (*rfbXvpHookPtr)(struct _rfbClientRec* cl, uint8_t, uint8_t);
|
||
|
/**
|
||
|
* If x==1 and y==1 then set the whole display
|
||
|
* else find the window underneath x and y and set the framebuffer to the dimensions
|
||
|
* of that window
|
||
|
*/
|
||
|
typedef void (*rfbSetSingleWindowProcPtr) (struct _rfbClientRec* cl, int x, int y);
|
||
|
/**
|
||
|
* Status determines if the X11 server permits input from the local user
|
||
|
* status==0 or 1
|
||
|
*/
|
||
|
typedef void (*rfbSetServerInputProcPtr) (struct _rfbClientRec* cl, int status);
|
||
|
/**
|
||
|
* Permit the server to allow or deny filetransfers. This is defaulted to deny
|
||
|
* It is called when a client initiates a connection to determine if it is permitted.
|
||
|
*/
|
||
|
typedef int (*rfbFileTransferPermitted) (struct _rfbClientRec* cl);
|
||
|
/** Handle the textchat messages */
|
||
|
typedef void (*rfbSetTextChat) (struct _rfbClientRec* cl, int length, char *string);
|
||
|
|
||
|
typedef struct {
|
||
|
uint32_t count;
|
||
|
rfbBool is16; /**< is the data format short? */
|
||
|
union {
|
||
|
uint8_t* bytes;
|
||
|
uint16_t* shorts;
|
||
|
} data; /**< there have to be count*3 entries */
|
||
|
} rfbColourMap;
|
||
|
|
||
|
/**
|
||
|
* Security handling (RFB protocol version 3.7)
|
||
|
*/
|
||
|
|
||
|
typedef struct _rfbSecurity {
|
||
|
uint8_t type;
|
||
|
void (*handler)(struct _rfbClientRec* cl);
|
||
|
struct _rfbSecurity* next;
|
||
|
} rfbSecurityHandler;
|
||
|
|
||
|
/**
|
||
|
* Protocol extension handling.
|
||
|
*/
|
||
|
|
||
|
typedef struct _rfbProtocolExtension {
|
||
|
/** returns FALSE if extension should be deactivated for client.
|
||
|
if newClient == NULL, it is always deactivated. */
|
||
|
rfbBool (*newClient)(struct _rfbClientRec* client, void** data);
|
||
|
/** returns FALSE if extension should be deactivated for client.
|
||
|
if init == NULL, it stays activated. */
|
||
|
rfbBool (*init)(struct _rfbClientRec* client, void* data);
|
||
|
/** if pseudoEncodings is not NULL, it contains a 0 terminated
|
||
|
list of the pseudo encodings handled by this extension. */
|
||
|
int *pseudoEncodings;
|
||
|
/** returns TRUE if that pseudo encoding is handled by the extension.
|
||
|
encodingNumber==0 means "reset encodings". */
|
||
|
rfbBool (*enablePseudoEncoding)(struct _rfbClientRec* client,
|
||
|
void** data, int encodingNumber);
|
||
|
/** returns TRUE if message was handled */
|
||
|
rfbBool (*handleMessage)(struct _rfbClientRec* client,
|
||
|
void* data,
|
||
|
const rfbClientToServerMsg* message);
|
||
|
void (*close)(struct _rfbClientRec* client, void* data);
|
||
|
void (*usage)(void);
|
||
|
/** processArguments returns the number of handled arguments */
|
||
|
int (*processArgument)(int argc, char *argv[]);
|
||
|
struct _rfbProtocolExtension* next;
|
||
|
} rfbProtocolExtension;
|
||
|
|
||
|
typedef struct _rfbExtensionData {
|
||
|
rfbProtocolExtension* extension;
|
||
|
void* data;
|
||
|
struct _rfbExtensionData* next;
|
||
|
} rfbExtensionData;
|
||
|
|
||
|
/**
|
||
|
* Per-screen (framebuffer) structure. There can be as many as you wish,
|
||
|
* each serving different clients. However, you have to call
|
||
|
* rfbProcessEvents for each of these.
|
||
|
*/
|
||
|
|
||
|
typedef struct _rfbScreenInfo
|
||
|
{
|
||
|
/** this structure has children that are scaled versions of this screen */
|
||
|
struct _rfbScreenInfo *scaledScreenNext;
|
||
|
int scaledScreenRefCount;
|
||
|
|
||
|
int width;
|
||
|
int paddedWidthInBytes;
|
||
|
int height;
|
||
|
int depth;
|
||
|
int bitsPerPixel;
|
||
|
int sizeInBytes;
|
||
|
|
||
|
rfbPixel blackPixel;
|
||
|
rfbPixel whitePixel;
|
||
|
|
||
|
/**
|
||
|
* some screen specific data can be put into a struct where screenData
|
||
|
* points to. You need this if you have more than one screen at the
|
||
|
* same time while using the same functions.
|
||
|
*/
|
||
|
void* screenData;
|
||
|
|
||
|
/* additions by libvncserver */
|
||
|
|
||
|
rfbPixelFormat serverFormat;
|
||
|
rfbColourMap colourMap; /**< set this if rfbServerFormat.trueColour==FALSE */
|
||
|
const char* desktopName;
|
||
|
char thisHost[255];
|
||
|
|
||
|
rfbBool autoPort;
|
||
|
int port;
|
||
|
SOCKET listenSock;
|
||
|
int maxSock;
|
||
|
int maxFd;
|
||
|
#ifdef __MINGW32__
|
||
|
struct fd_set allFds;
|
||
|
#else
|
||
|
fd_set allFds;
|
||
|
#endif
|
||
|
|
||
|
enum rfbSocketState socketState;
|
||
|
SOCKET inetdSock;
|
||
|
rfbBool inetdInitDone;
|
||
|
|
||
|
int udpPort;
|
||
|
SOCKET udpSock;
|
||
|
struct _rfbClientRec* udpClient;
|
||
|
rfbBool udpSockConnected;
|
||
|
struct sockaddr_in udpRemoteAddr;
|
||
|
|
||
|
int maxClientWait;
|
||
|
|
||
|
/* http stuff */
|
||
|
rfbBool httpInitDone;
|
||
|
rfbBool httpEnableProxyConnect;
|
||
|
int httpPort;
|
||
|
char* httpDir;
|
||
|
SOCKET httpListenSock;
|
||
|
SOCKET httpSock;
|
||
|
|
||
|
rfbPasswordCheckProcPtr passwordCheck;
|
||
|
void* authPasswdData;
|
||
|
/** If rfbAuthPasswdData is given a list, this is the first
|
||
|
view only password. */
|
||
|
int authPasswdFirstViewOnly;
|
||
|
|
||
|
/** send only this many rectangles in one update */
|
||
|
int maxRectsPerUpdate;
|
||
|
/** this is the amount of milliseconds to wait at least before sending
|
||
|
* an update. */
|
||
|
int deferUpdateTime;
|
||
|
#ifdef TODELETE
|
||
|
char* screen;
|
||
|
#endif
|
||
|
rfbBool alwaysShared;
|
||
|
rfbBool neverShared;
|
||
|
rfbBool dontDisconnect;
|
||
|
struct _rfbClientRec* clientHead;
|
||
|
struct _rfbClientRec* pointerClient; /**< "Mutex" for pointer events */
|
||
|
|
||
|
|
||
|
/* cursor */
|
||
|
int cursorX, cursorY,underCursorBufferLen;
|
||
|
char* underCursorBuffer;
|
||
|
rfbBool dontConvertRichCursorToXCursor;
|
||
|
struct rfbCursor* cursor;
|
||
|
|
||
|
/**
|
||
|
* the frameBuffer has to be supplied by the serving process.
|
||
|
* The buffer will not be freed by
|
||
|
*/
|
||
|
char* frameBuffer;
|
||
|
rfbKbdAddEventProcPtr kbdAddEvent;
|
||
|
rfbKbdReleaseAllKeysProcPtr kbdReleaseAllKeys;
|
||
|
rfbPtrAddEventProcPtr ptrAddEvent;
|
||
|
rfbSetXCutTextProcPtr setXCutText;
|
||
|
rfbGetCursorProcPtr getCursorPtr;
|
||
|
rfbSetTranslateFunctionProcPtr setTranslateFunction;
|
||
|
rfbSetSingleWindowProcPtr setSingleWindow;
|
||
|
rfbSetServerInputProcPtr setServerInput;
|
||
|
rfbFileTransferPermitted getFileTransferPermission;
|
||
|
rfbSetTextChat setTextChat;
|
||
|
|
||
|
/** newClientHook is called just after a new client is created */
|
||
|
rfbNewClientHookPtr newClientHook;
|
||
|
/** displayHook is called just before a frame buffer update */
|
||
|
rfbDisplayHookPtr displayHook;
|
||
|
|
||
|
/** These hooks are called to pass keyboard state back to the client */
|
||
|
rfbGetKeyboardLedStateHookPtr getKeyboardLedStateHook;
|
||
|
|
||
|
#ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
|
||
|
MUTEX(cursorMutex);
|
||
|
rfbBool backgroundLoop;
|
||
|
#endif
|
||
|
|
||
|
/** if TRUE, an ignoring signal handler is installed for SIGPIPE */
|
||
|
rfbBool ignoreSIGPIPE;
|
||
|
|
||
|
/** if not zero, only a slice of this height is processed every time
|
||
|
* an update should be sent. This should make working on a slow
|
||
|
* link more interactive. */
|
||
|
int progressiveSliceHeight;
|
||
|
|
||
|
in_addr_t listenInterface;
|
||
|
int deferPtrUpdateTime;
|
||
|
|
||
|
/** handle as many input events as possible (default off) */
|
||
|
rfbBool handleEventsEagerly;
|
||
|
|
||
|
/** rfbEncodingServerIdentity */
|
||
|
char *versionString;
|
||
|
|
||
|
/** What does the server tell the new clients which version it supports */
|
||
|
int protocolMajorVersion;
|
||
|
int protocolMinorVersion;
|
||
|
|
||
|
/** command line authorization of file transfers */
|
||
|
rfbBool permitFileTransfer;
|
||
|
|
||
|
/** displayFinishedHook is called just after a frame buffer update */
|
||
|
rfbDisplayFinishedHookPtr displayFinishedHook;
|
||
|
/** xvpHook is called to handle an xvp client message */
|
||
|
rfbXvpHookPtr xvpHook;
|
||
|
#ifdef LIBVNCSERVER_WITH_WEBSOCKETS
|
||
|
char *sslkeyfile;
|
||
|
char *sslcertfile;
|
||
|
#endif
|
||
|
int ipv6port; /**< The port to listen on when using IPv6. */
|
||
|
char* listen6Interface;
|
||
|
/* We have an additional IPv6 listen socket since there are systems that
|
||
|
don't support dual binding sockets under *any* circumstances, for
|
||
|
instance OpenBSD */
|
||
|
SOCKET listen6Sock;
|
||
|
int http6Port;
|
||
|
SOCKET httpListen6Sock;
|
||
|
} rfbScreenInfo, *rfbScreenInfoPtr;
|
||
|
|
||
|
|
||
|
/**
|
||
|
* rfbTranslateFnType is the type of translation functions.
|
||
|
*/
|
||
|
|
||
|
typedef void (*rfbTranslateFnType)(char *table, rfbPixelFormat *in,
|
||
|
rfbPixelFormat *out,
|
||
|
char *iptr, char *optr,
|
||
|
int bytesBetweenInputLines,
|
||
|
int width, int height);
|
||
|
|
||
|
|
||
|
/* region stuff */
|
||
|
|
||
|
struct sraRegion;
|
||
|
typedef struct sraRegion* sraRegionPtr;
|
||
|
|
||
|
/*
|
||
|
* Per-client structure.
|
||
|
*/
|
||
|
|
||
|
typedef void (*ClientGoneHookPtr)(struct _rfbClientRec* cl);
|
||
|
|
||
|
typedef struct _rfbFileTransferData {
|
||
|
int fd;
|
||
|
int compressionEnabled;
|
||
|
int fileSize;
|
||
|
int numPackets;
|
||
|
int receiving;
|
||
|
int sending;
|
||
|
} rfbFileTransferData;
|
||
|
|
||
|
|
||
|
typedef struct _rfbStatList {
|
||
|
uint32_t type;
|
||
|
uint32_t sentCount;
|
||
|
uint32_t bytesSent;
|
||
|
uint32_t bytesSentIfRaw;
|
||
|
uint32_t rcvdCount;
|
||
|
uint32_t bytesRcvd;
|
||
|
uint32_t bytesRcvdIfRaw;
|
||
|
struct _rfbStatList *Next;
|
||
|
} rfbStatList;
|
||
|
|
||
|
typedef struct _rfbSslCtx rfbSslCtx;
|
||
|
typedef struct _wsCtx wsCtx;
|
||
|
|
||
|
typedef struct _rfbClientRec {
|
||
|
|
||
|
/** back pointer to the screen */
|
||
|
rfbScreenInfoPtr screen;
|
||
|
|
||
|
/** points to a scaled version of the screen buffer in cl->scaledScreenList */
|
||
|
rfbScreenInfoPtr scaledScreen;
|
||
|
/** how did the client tell us it wanted the screen changed? Ultra style or palm style? */
|
||
|
rfbBool PalmVNC;
|
||
|
|
||
|
|
||
|
/** private data. You should put any application client specific data
|
||
|
* into a struct and let clientData point to it. Don't forget to
|
||
|
* free the struct via clientGoneHook!
|
||
|
*
|
||
|
* This is useful if the IO functions have to behave client specific.
|
||
|
*/
|
||
|
void* clientData;
|
||
|
ClientGoneHookPtr clientGoneHook;
|
||
|
|
||
|
SOCKET sock;
|
||
|
char *host;
|
||
|
|
||
|
/* RFB protocol minor version number */
|
||
|
int protocolMajorVersion;
|
||
|
int protocolMinorVersion;
|
||
|
|
||
|
#ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
|
||
|
pthread_t client_thread;
|
||
|
#endif
|
||
|
|
||
|
/* Note that the RFB_INITIALISATION_SHARED state is provided to support
|
||
|
clients that under some circumstances do not send a ClientInit message.
|
||
|
In particular the Mac OS X built-in VNC client (with protocolMinorVersion
|
||
|
== 889) is one of those. However, it only requires this support under
|
||
|
special circumstances that can only be determined during the initial
|
||
|
authentication. If the right conditions are met this state will be
|
||
|
set (see the auth.c file) when rfbProcessClientInitMessage is called.
|
||
|
|
||
|
If the state is RFB_INITIALISATION_SHARED we should not expect to recieve
|
||
|
any ClientInit message, but instead should proceed to the next stage
|
||
|
of initialisation as though an implicit ClientInit message was received
|
||
|
with a shared-flag of true. (There is currently no corresponding
|
||
|
RFB_INITIALISATION_NOTSHARED state to represent an implicit ClientInit
|
||
|
message with a shared-flag of false because no known existing client
|
||
|
requires such support at this time.)
|
||
|
|
||
|
Note that software using LibVNCServer to provide a VNC server will only
|
||
|
ever have a chance to see the state field set to
|
||
|
RFB_INITIALISATION_SHARED if the software is multi-threaded and manages
|
||
|
to examine the state field during the extremely brief window after the
|
||
|
'None' authentication type selection has been received from the built-in
|
||
|
OS X VNC client and before the rfbProcessClientInitMessage function is
|
||
|
called -- control cannot return to the caller during this brief window
|
||
|
while the state field is set to RFB_INITIALISATION_SHARED. */
|
||
|
|
||
|
/** Possible client states: */
|
||
|
enum {
|
||
|
RFB_PROTOCOL_VERSION, /**< establishing protocol version */
|
||
|
RFB_SECURITY_TYPE, /**< negotiating security (RFB v.3.7) */
|
||
|
RFB_AUTHENTICATION, /**< authenticating */
|
||
|
RFB_INITIALISATION, /**< sending initialisation messages */
|
||
|
RFB_NORMAL, /**< normal protocol messages */
|
||
|
|
||
|
/* Ephemeral internal-use states that will never be seen by software
|
||
|
* using LibVNCServer to provide services: */
|
||
|
|
||
|
RFB_INITIALISATION_SHARED /**< sending initialisation messages with implicit shared-flag already true */
|
||
|
} state;
|
||
|
|
||
|
rfbBool reverseConnection;
|
||
|
rfbBool onHold;
|
||
|
rfbBool readyForSetColourMapEntries;
|
||
|
rfbBool useCopyRect;
|
||
|
int preferredEncoding;
|
||
|
int correMaxWidth, correMaxHeight;
|
||
|
|
||
|
rfbBool viewOnly;
|
||
|
|
||
|
/* The following member is only used during VNC authentication */
|
||
|
uint8_t 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. */
|
||
|
|
||
|
sraRegionPtr copyRegion; /**< the destination region of the copy */
|
||
|
int copyDX, copyDY; /**< the translation by which the copy happens */
|
||
|
|
||
|
sraRegionPtr 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. */
|
||
|
|
||
|
sraRegionPtr requestedRegion;
|
||
|
|
||
|
/** The following member represents 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. */
|
||
|
|
||
|
struct timeval startDeferring;
|
||
|
struct timeval startPtrDeferring;
|
||
|
int lastPtrX;
|
||
|
int lastPtrY;
|
||
|
int lastPtrButtons;
|
||
|
|
||
|
/** 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 */
|
||
|
struct _rfbStatList *statEncList;
|
||
|
struct _rfbStatList *statMsgList;
|
||
|
int rawBytesEquivalent;
|
||
|
int bytesSent;
|
||
|
|
||
|
#ifdef LIBVNCSERVER_HAVE_LIBZ
|
||
|
/* zlib encoding -- necessary compression state info per client */
|
||
|
|
||
|
struct z_stream_s compStream;
|
||
|
rfbBool compStreamInited;
|
||
|
uint32_t zlibCompressLevel;
|
||
|
#endif
|
||
|
#if defined(LIBVNCSERVER_HAVE_LIBZ) || defined(LIBVNCSERVER_HAVE_LIBPNG)
|
||
|
/** the quality level is also used by ZYWRLE and TightPng */
|
||
|
int tightQualityLevel;
|
||
|
|
||
|
#ifdef LIBVNCSERVER_HAVE_LIBJPEG
|
||
|
/* tight encoding -- preserve zlib streams' state for each client */
|
||
|
z_stream zsStruct[4];
|
||
|
rfbBool zsActive[4];
|
||
|
int zsLevel[4];
|
||
|
int tightCompressLevel;
|
||
|
#endif
|
||
|
#endif
|
||
|
|
||
|
/* Ultra Encoding support */
|
||
|
rfbBool compStreamInitedLZO;
|
||
|
char *lzoWrkMem;
|
||
|
|
||
|
rfbFileTransferData fileTransfer;
|
||
|
|
||
|
int lastKeyboardLedState; /**< keep track of last value so we can send *change* events */
|
||
|
rfbBool enableSupportedMessages; /**< client supports SupportedMessages encoding */
|
||
|
rfbBool enableSupportedEncodings; /**< client supports SupportedEncodings encoding */
|
||
|
rfbBool enableServerIdentity; /**< client supports ServerIdentity encoding */
|
||
|
rfbBool enableKeyboardLedState; /**< client supports KeyboardState encoding */
|
||
|
rfbBool enableLastRectEncoding; /**< client supports LastRect encoding */
|
||
|
rfbBool enableCursorShapeUpdates; /**< client supports cursor shape updates */
|
||
|
rfbBool enableCursorPosUpdates; /**< client supports cursor position updates */
|
||
|
rfbBool useRichCursorEncoding; /**< rfbEncodingRichCursor is preferred */
|
||
|
rfbBool cursorWasChanged; /**< cursor shape update should be sent */
|
||
|
rfbBool cursorWasMoved; /**< cursor position update should be sent */
|
||
|
int cursorX,cursorY; /**< the coordinates of the cursor,
|
||
|
if enableCursorShapeUpdates = FALSE */
|
||
|
|
||
|
rfbBool useNewFBSize; /**< client supports NewFBSize encoding */
|
||
|
rfbBool newFBSizePending; /**< framebuffer size was changed */
|
||
|
|
||
|
struct _rfbClientRec *prev;
|
||
|
struct _rfbClientRec *next;
|
||
|
|
||
|
#ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
|
||
|
/** whenever a client is referenced, the refCount has to be incremented
|
||
|
and afterwards decremented, so that the client is not cleaned up
|
||
|
while being referenced.
|
||
|
Use the functions rfbIncrClientRef(cl) and rfbDecrClientRef(cl);
|
||
|
*/
|
||
|
int refCount;
|
||
|
MUTEX(refCountMutex);
|
||
|
COND(deleteCond);
|
||
|
|
||
|
MUTEX(outputMutex);
|
||
|
MUTEX(updateMutex);
|
||
|
COND(updateCond);
|
||
|
#endif
|
||
|
|
||
|
#ifdef LIBVNCSERVER_HAVE_LIBZ
|
||
|
void* zrleData;
|
||
|
int zywrleLevel;
|
||
|
int zywrleBuf[rfbZRLETileWidth * rfbZRLETileHeight];
|
||
|
#endif
|
||
|
|
||
|
/** if progressive updating is on, this variable holds the current
|
||
|
* y coordinate of the progressive slice. */
|
||
|
int progressiveSliceY;
|
||
|
|
||
|
rfbExtensionData* extensions;
|
||
|
|
||
|
/** for threaded zrle */
|
||
|
char *zrleBeforeBuf;
|
||
|
void *paletteHelper;
|
||
|
|
||
|
/** for thread safety for rfbSendFBUpdate() */
|
||
|
#ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
|
||
|
#define LIBVNCSERVER_SEND_MUTEX
|
||
|
MUTEX(sendMutex);
|
||
|
#endif
|
||
|
|
||
|
/* buffers to hold pixel data before and after encoding.
|
||
|
per-client for thread safety */
|
||
|
char *beforeEncBuf;
|
||
|
int beforeEncBufSize;
|
||
|
char *afterEncBuf;
|
||
|
int afterEncBufSize;
|
||
|
int afterEncBufLen;
|
||
|
#if defined(LIBVNCSERVER_HAVE_LIBZ) || defined(LIBVNCSERVER_HAVE_LIBPNG)
|
||
|
uint32_t tightEncoding; /* rfbEncodingTight or rfbEncodingTightPng */
|
||
|
#ifdef LIBVNCSERVER_HAVE_LIBJPEG
|
||
|
/* TurboVNC Encoding support (extends TightVNC) */
|
||
|
int turboSubsampLevel;
|
||
|
int turboQualityLevel; // 1-100 scale
|
||
|
#endif
|
||
|
#endif
|
||
|
|
||
|
#ifdef LIBVNCSERVER_WITH_WEBSOCKETS
|
||
|
rfbSslCtx *sslctx;
|
||
|
wsCtx *wsctx;
|
||
|
char *wspath; /* Requests path component */
|
||
|
#endif
|
||
|
} 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)->cursorWasChanged) || \
|
||
|
(((cl)->enableCursorShapeUpdates == FALSE && \
|
||
|
((cl)->cursorX != (cl)->screen->cursorX || \
|
||
|
(cl)->cursorY != (cl)->screen->cursorY))) || \
|
||
|
((cl)->useNewFBSize && (cl)->newFBSizePending) || \
|
||
|
((cl)->enableCursorPosUpdates && (cl)->cursorWasMoved) || \
|
||
|
!sraRgnEmpty((cl)->copyRegion) || !sraRgnEmpty((cl)->modifiedRegion))
|
||
|
|
||
|
/*
|
||
|
* Macros for endian swapping.
|
||
|
*/
|
||
|
|
||
|
#define Swap16(s) ((((s) & 0xff) << 8) | (((s) >> 8) & 0xff))
|
||
|
|
||
|
#define Swap24(l) ((((l) & 0xff) << 16) | (((l) >> 16) & 0xff) | \
|
||
|
(((l) & 0x00ff00)))
|
||
|
|
||
|
#define Swap32(l) (((l) >> 24) | \
|
||
|
(((l) & 0x00ff0000) >> 8) | \
|
||
|
(((l) & 0x0000ff00) << 8) | \
|
||
|
((l) << 24))
|
||
|
|
||
|
|
||
|
extern char rfbEndianTest;
|
||
|
|
||
|
#define Swap16IfLE(s) (rfbEndianTest ? Swap16(s) : (s))
|
||
|
#define Swap24IfLE(l) (rfbEndianTest ? Swap24(l) : (l))
|
||
|
#define Swap32IfLE(l) (rfbEndianTest ? Swap32(l) : (l))
|
||
|
|
||
|
/* UltraVNC uses some windows structures unmodified, so the viewer expects LittleEndian Data */
|
||
|
#define Swap16IfBE(s) (rfbEndianTest ? (s) : Swap16(s))
|
||
|
#define Swap24IfBE(l) (rfbEndianTest ? (l) : Swap24(l))
|
||
|
#define Swap32IfBE(l) (rfbEndianTest ? (l) : Swap32(l))
|
||
|
|
||
|
/* sockets.c */
|
||
|
|
||
|
extern int rfbMaxClientWait;
|
||
|
|
||
|
extern void rfbInitSockets(rfbScreenInfoPtr rfbScreen);
|
||
|
extern void rfbShutdownSockets(rfbScreenInfoPtr rfbScreen);
|
||
|
extern void rfbDisconnectUDPSock(rfbScreenInfoPtr rfbScreen);
|
||
|
extern void rfbCloseClient(rfbClientPtr cl);
|
||
|
extern int rfbReadExact(rfbClientPtr cl, char *buf, int len);
|
||
|
extern int rfbReadExactTimeout(rfbClientPtr cl, char *buf, int len,int timeout);
|
||
|
extern int rfbPeekExactTimeout(rfbClientPtr cl, char *buf, int len,int timeout);
|
||
|
extern int rfbWriteExact(rfbClientPtr cl, const char *buf, int len);
|
||
|
extern int rfbCheckFds(rfbScreenInfoPtr rfbScreen,long usec);
|
||
|
extern int rfbConnect(rfbScreenInfoPtr rfbScreen, char* host, int port);
|
||
|
extern int rfbConnectToTcpAddr(char* host, int port);
|
||
|
extern int rfbListenOnTCPPort(int port, in_addr_t iface);
|
||
|
extern int rfbListenOnTCP6Port(int port, const char* iface);
|
||
|
extern int rfbListenOnUDPPort(int port, in_addr_t iface);
|
||
|
extern int rfbStringToAddr(char* string,in_addr_t* addr);
|
||
|
extern rfbBool rfbSetNonBlocking(int sock);
|
||
|
|
||
|
#ifdef LIBVNCSERVER_WITH_WEBSOCKETS
|
||
|
/* websockets.c */
|
||
|
|
||
|
extern rfbBool webSocketsCheck(rfbClientPtr cl);
|
||
|
extern rfbBool webSocketCheckDisconnect(rfbClientPtr cl);
|
||
|
extern int webSocketsEncode(rfbClientPtr cl, const char *src, int len, char **dst);
|
||
|
extern int webSocketsDecode(rfbClientPtr cl, char *dst, int len);
|
||
|
#endif
|
||
|
|
||
|
/* rfbserver.c */
|
||
|
|
||
|
/* 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 rfbIncrClientRef(rfbClientPtr cl);
|
||
|
extern void rfbDecrClientRef(rfbClientPtr cl);
|
||
|
|
||
|
extern void rfbNewClientConnection(rfbScreenInfoPtr rfbScreen,int sock);
|
||
|
extern rfbClientPtr rfbNewClient(rfbScreenInfoPtr rfbScreen,int sock);
|
||
|
extern rfbClientPtr rfbNewUDPClient(rfbScreenInfoPtr rfbScreen);
|
||
|
extern rfbClientPtr rfbReverseConnection(rfbScreenInfoPtr rfbScreen,char *host, int port);
|
||
|
extern void rfbClientConnectionGone(rfbClientPtr cl);
|
||
|
extern void rfbProcessClientMessage(rfbClientPtr cl);
|
||
|
extern void rfbClientConnFailed(rfbClientPtr cl, const char *reason);
|
||
|
extern void rfbNewUDPConnection(rfbScreenInfoPtr rfbScreen,int sock);
|
||
|
extern void rfbProcessUDPInput(rfbScreenInfoPtr rfbScreen);
|
||
|
extern rfbBool rfbSendFramebufferUpdate(rfbClientPtr cl, sraRegionPtr updateRegion);
|
||
|
extern rfbBool rfbSendRectEncodingRaw(rfbClientPtr cl, int x,int y,int w,int h);
|
||
|
extern rfbBool rfbSendUpdateBuf(rfbClientPtr cl);
|
||
|
extern void rfbSendServerCutText(rfbScreenInfoPtr rfbScreen,char *str, int len);
|
||
|
extern rfbBool rfbSendCopyRegion(rfbClientPtr cl,sraRegionPtr reg,int dx,int dy);
|
||
|
extern rfbBool rfbSendLastRectMarker(rfbClientPtr cl);
|
||
|
extern rfbBool rfbSendNewFBSize(rfbClientPtr cl, int w, int h);
|
||
|
extern rfbBool rfbSendSetColourMapEntries(rfbClientPtr cl, int firstColour, int nColours);
|
||
|
extern void rfbSendBell(rfbScreenInfoPtr rfbScreen);
|
||
|
|
||
|
extern char *rfbProcessFileTransferReadBuffer(rfbClientPtr cl, uint32_t length);
|
||
|
extern rfbBool rfbSendFileTransferChunk(rfbClientPtr cl);
|
||
|
extern rfbBool rfbSendDirContent(rfbClientPtr cl, int length, char *buffer);
|
||
|
extern rfbBool rfbSendFileTransferMessage(rfbClientPtr cl, uint8_t contentType, uint8_t contentParam, uint32_t size, uint32_t length, const char *buffer);
|
||
|
extern char *rfbProcessFileTransferReadBuffer(rfbClientPtr cl, uint32_t length);
|
||
|
extern rfbBool rfbProcessFileTransfer(rfbClientPtr cl, uint8_t contentType, uint8_t contentParam, uint32_t size, uint32_t length);
|
||
|
|
||
|
void rfbGotXCutText(rfbScreenInfoPtr rfbScreen, char *str, int len);
|
||
|
|
||
|
/* translate.c */
|
||
|
|
||
|
extern rfbBool rfbEconomicTranslate;
|
||
|
|
||
|
extern void rfbTranslateNone(char *table, rfbPixelFormat *in,
|
||
|
rfbPixelFormat *out,
|
||
|
char *iptr, char *optr,
|
||
|
int bytesBetweenInputLines,
|
||
|
int width, int height);
|
||
|
extern rfbBool rfbSetTranslateFunction(rfbClientPtr cl);
|
||
|
extern rfbBool rfbSetClientColourMap(rfbClientPtr cl, int firstColour, int nColours);
|
||
|
extern void rfbSetClientColourMaps(rfbScreenInfoPtr rfbScreen, int firstColour, int nColours);
|
||
|
|
||
|
/* httpd.c */
|
||
|
|
||
|
extern void rfbHttpInitSockets(rfbScreenInfoPtr rfbScreen);
|
||
|
extern void rfbHttpShutdownSockets(rfbScreenInfoPtr rfbScreen);
|
||
|
extern void rfbHttpCheckFds(rfbScreenInfoPtr rfbScreen);
|
||
|
|
||
|
|
||
|
|
||
|
/* auth.c */
|
||
|
|
||
|
extern void rfbAuthNewClient(rfbClientPtr cl);
|
||
|
extern void rfbProcessClientSecurityType(rfbClientPtr cl);
|
||
|
extern void rfbAuthProcessClientMessage(rfbClientPtr cl);
|
||
|
extern void rfbRegisterSecurityHandler(rfbSecurityHandler* handler);
|
||
|
extern void rfbUnregisterSecurityHandler(rfbSecurityHandler* handler);
|
||
|
|
||
|
/* rre.c */
|
||
|
|
||
|
extern rfbBool rfbSendRectEncodingRRE(rfbClientPtr cl, int x,int y,int w,int h);
|
||
|
|
||
|
|
||
|
/* corre.c */
|
||
|
|
||
|
extern rfbBool rfbSendRectEncodingCoRRE(rfbClientPtr cl, int x,int y,int w,int h);
|
||
|
|
||
|
|
||
|
/* hextile.c */
|
||
|
|
||
|
extern rfbBool rfbSendRectEncodingHextile(rfbClientPtr cl, int x, int y, int w,
|
||
|
int h);
|
||
|
|
||
|
/* ultra.c */
|
||
|
|
||
|
/* Set maximum ultra rectangle size in pixels. Always allow at least
|
||
|
* two scan lines.
|
||
|
*/
|
||
|
#define ULTRA_MAX_RECT_SIZE (128*256)
|
||
|
#define ULTRA_MAX_SIZE(min) ((( min * 2 ) > ULTRA_MAX_RECT_SIZE ) ? \
|
||
|
( min * 2 ) : ULTRA_MAX_RECT_SIZE )
|
||
|
|
||
|
extern rfbBool rfbSendRectEncodingUltra(rfbClientPtr cl, int x,int y,int w,int h);
|
||
|
|
||
|
|
||
|
#ifdef LIBVNCSERVER_HAVE_LIBZ
|
||
|
/* 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 rfbBool rfbSendRectEncodingZlib(rfbClientPtr cl, int x, int y, int w,
|
||
|
int h);
|
||
|
|
||
|
#ifdef LIBVNCSERVER_HAVE_LIBJPEG
|
||
|
/* tight.c */
|
||
|
|
||
|
#define TIGHT_DEFAULT_COMPRESSION 6
|
||
|
#define TURBO_DEFAULT_SUBSAMP 0
|
||
|
|
||
|
extern rfbBool rfbTightDisableGradient;
|
||
|
|
||
|
extern int rfbNumCodedRectsTight(rfbClientPtr cl, int x,int y,int w,int h);
|
||
|
|
||
|
extern rfbBool rfbSendRectEncodingTight(rfbClientPtr cl, int x,int y,int w,int h);
|
||
|
|
||
|
#if defined(LIBVNCSERVER_HAVE_LIBPNG)
|
||
|
extern rfbBool rfbSendRectEncodingTightPng(rfbClientPtr cl, int x,int y,int w,int h);
|
||
|
#endif
|
||
|
|
||
|
#endif
|
||
|
#endif
|
||
|
|
||
|
|
||
|
/* cursor.c */
|
||
|
|
||
|
typedef struct rfbCursor {
|
||
|
/** set this to true if LibVNCServer has to free this cursor */
|
||
|
rfbBool cleanup, cleanupSource, cleanupMask, cleanupRichSource;
|
||
|
unsigned char *source; /**< points to bits */
|
||
|
unsigned char *mask; /**< points to bits */
|
||
|
unsigned short width, height, xhot, yhot; /**< metrics */
|
||
|
unsigned short foreRed, foreGreen, foreBlue; /**< device-independent colour */
|
||
|
unsigned short backRed, backGreen, backBlue; /**< device-independent colour */
|
||
|
unsigned char *richSource; /**< source bytes for a rich cursor */
|
||
|
unsigned char *alphaSource; /**< source for alpha blending info */
|
||
|
rfbBool alphaPreMultiplied; /**< if richSource already has alpha applied */
|
||
|
} rfbCursor, *rfbCursorPtr;
|
||
|
extern unsigned char rfbReverseByte[0x100];
|
||
|
|
||
|
extern rfbBool rfbSendCursorShape(rfbClientPtr cl/*, rfbScreenInfoPtr pScreen*/);
|
||
|
extern rfbBool rfbSendCursorPos(rfbClientPtr cl);
|
||
|
extern void rfbConvertLSBCursorBitmapOrMask(int width,int height,unsigned char* bitmap);
|
||
|
extern rfbCursorPtr rfbMakeXCursor(int width,int height,char* cursorString,char* maskString);
|
||
|
extern char* rfbMakeMaskForXCursor(int width,int height,char* cursorString);
|
||
|
extern char* rfbMakeMaskFromAlphaSource(int width,int height,unsigned char* alphaSource);
|
||
|
extern void rfbMakeXCursorFromRichCursor(rfbScreenInfoPtr rfbScreen,rfbCursorPtr cursor);
|
||
|
extern void rfbMakeRichCursorFromXCursor(rfbScreenInfoPtr rfbScreen,rfbCursorPtr cursor);
|
||
|
extern void rfbFreeCursor(rfbCursorPtr cursor);
|
||
|
extern void rfbSetCursor(rfbScreenInfoPtr rfbScreen,rfbCursorPtr c);
|
||
|
|
||
|
/** cursor handling for the pointer */
|
||
|
extern void rfbDefaultPtrAddEvent(int buttonMask,int x,int y,rfbClientPtr cl);
|
||
|
|
||
|
/* zrle.c */
|
||
|
#ifdef LIBVNCSERVER_HAVE_LIBZ
|
||
|
extern rfbBool rfbSendRectEncodingZRLE(rfbClientPtr cl, int x, int y, int w,int h);
|
||
|
#endif
|
||
|
|
||
|
/* stats.c */
|
||
|
|
||
|
extern void rfbResetStats(rfbClientPtr cl);
|
||
|
extern void rfbPrintStats(rfbClientPtr cl);
|
||
|
|
||
|
/* font.c */
|
||
|
|
||
|
typedef struct rfbFontData {
|
||
|
unsigned char* data;
|
||
|
/**
|
||
|
metaData is a 256*5 array:
|
||
|
for each character
|
||
|
(offset,width,height,x,y)
|
||
|
*/
|
||
|
int* metaData;
|
||
|
} rfbFontData,* rfbFontDataPtr;
|
||
|
|
||
|
int rfbDrawChar(rfbScreenInfoPtr rfbScreen,rfbFontDataPtr font,int x,int y,unsigned char c,rfbPixel colour);
|
||
|
void rfbDrawString(rfbScreenInfoPtr rfbScreen,rfbFontDataPtr font,int x,int y,const char* string,rfbPixel colour);
|
||
|
/** if colour==backColour, background is transparent */
|
||
|
int rfbDrawCharWithClip(rfbScreenInfoPtr rfbScreen,rfbFontDataPtr font,int x,int y,unsigned char c,int x1,int y1,int x2,int y2,rfbPixel colour,rfbPixel backColour);
|
||
|
void rfbDrawStringWithClip(rfbScreenInfoPtr rfbScreen,rfbFontDataPtr font,int x,int y,const char* string,int x1,int y1,int x2,int y2,rfbPixel colour,rfbPixel backColour);
|
||
|
int rfbWidthOfString(rfbFontDataPtr font,const char* string);
|
||
|
int rfbWidthOfChar(rfbFontDataPtr font,unsigned char c);
|
||
|
void rfbFontBBox(rfbFontDataPtr font,unsigned char c,int* x1,int* y1,int* x2,int* y2);
|
||
|
/** this returns the smallest box enclosing any character of font. */
|
||
|
void rfbWholeFontBBox(rfbFontDataPtr font,int *x1, int *y1, int *x2, int *y2);
|
||
|
|
||
|
/** dynamically load a linux console font (4096 bytes, 256 glyphs a 8x16 */
|
||
|
rfbFontDataPtr rfbLoadConsoleFont(char *filename);
|
||
|
/** free a dynamically loaded font */
|
||
|
void rfbFreeFont(rfbFontDataPtr font);
|
||
|
|
||
|
/* draw.c */
|
||
|
|
||
|
void rfbFillRect(rfbScreenInfoPtr s,int x1,int y1,int x2,int y2,rfbPixel col);
|
||
|
void rfbDrawPixel(rfbScreenInfoPtr s,int x,int y,rfbPixel col);
|
||
|
void rfbDrawLine(rfbScreenInfoPtr s,int x1,int y1,int x2,int y2,rfbPixel col);
|
||
|
|
||
|
/* selbox.c */
|
||
|
|
||
|
/** this opens a modal select box. list is an array of strings, the end marked
|
||
|
with a NULL.
|
||
|
It returns the index in the list or -1 if cancelled or something else
|
||
|
wasn't kosher. */
|
||
|
typedef void (*SelectionChangedHookPtr)(int _index);
|
||
|
extern int rfbSelectBox(rfbScreenInfoPtr rfbScreen,
|
||
|
rfbFontDataPtr font, char** list,
|
||
|
int x1, int y1, int x2, int y2,
|
||
|
rfbPixel foreColour, rfbPixel backColour,
|
||
|
int border,SelectionChangedHookPtr selChangedHook);
|
||
|
|
||
|
/* cargs.c */
|
||
|
|
||
|
extern void rfbUsage(void);
|
||
|
extern void rfbPurgeArguments(int* argc,int* position,int count,char *argv[]);
|
||
|
extern rfbBool rfbProcessArguments(rfbScreenInfoPtr rfbScreen,int* argc, char *argv[]);
|
||
|
extern rfbBool rfbProcessSizeArguments(int* width,int* height,int* bpp,int* argc, char *argv[]);
|
||
|
|
||
|
/* main.c */
|
||
|
|
||
|
extern void rfbLogEnable(int enabled);
|
||
|
typedef void (*rfbLogProc)(const char *format, ...);
|
||
|
extern rfbLogProc rfbLog, rfbErr;
|
||
|
extern void rfbLogPerror(const char *str);
|
||
|
|
||
|
void rfbScheduleCopyRect(rfbScreenInfoPtr rfbScreen,int x1,int y1,int x2,int y2,int dx,int dy);
|
||
|
void rfbScheduleCopyRegion(rfbScreenInfoPtr rfbScreen,sraRegionPtr copyRegion,int dx,int dy);
|
||
|
|
||
|
void rfbDoCopyRect(rfbScreenInfoPtr rfbScreen,int x1,int y1,int x2,int y2,int dx,int dy);
|
||
|
void rfbDoCopyRegion(rfbScreenInfoPtr rfbScreen,sraRegionPtr copyRegion,int dx,int dy);
|
||
|
|
||
|
void rfbMarkRectAsModified(rfbScreenInfoPtr rfbScreen,int x1,int y1,int x2,int y2);
|
||
|
void rfbMarkRegionAsModified(rfbScreenInfoPtr rfbScreen,sraRegionPtr modRegion);
|
||
|
void rfbDoNothingWithClient(rfbClientPtr cl);
|
||
|
enum rfbNewClientAction defaultNewClientHook(rfbClientPtr cl);
|
||
|
void rfbRegisterProtocolExtension(rfbProtocolExtension* extension);
|
||
|
void rfbUnregisterProtocolExtension(rfbProtocolExtension* extension);
|
||
|
struct _rfbProtocolExtension* rfbGetExtensionIterator();
|
||
|
void rfbReleaseExtensionIterator();
|
||
|
rfbBool rfbEnableExtension(rfbClientPtr cl, rfbProtocolExtension* extension,
|
||
|
void* data);
|
||
|
rfbBool rfbDisableExtension(rfbClientPtr cl, rfbProtocolExtension* extension);
|
||
|
void* rfbGetExtensionClientData(rfbClientPtr cl, rfbProtocolExtension* extension);
|
||
|
|
||
|
/** to check against plain passwords */
|
||
|
rfbBool rfbCheckPasswordByList(rfbClientPtr cl,const char* response,int len);
|
||
|
|
||
|
/* functions to make a vnc server */
|
||
|
extern rfbScreenInfoPtr rfbGetScreen(int* argc,char** argv,
|
||
|
int width,int height,int bitsPerSample,int samplesPerPixel,
|
||
|
int bytesPerPixel);
|
||
|
extern void rfbInitServer(rfbScreenInfoPtr rfbScreen);
|
||
|
extern void rfbShutdownServer(rfbScreenInfoPtr rfbScreen,rfbBool disconnectClients);
|
||
|
extern void rfbNewFramebuffer(rfbScreenInfoPtr rfbScreen,char *framebuffer,
|
||
|
int width,int height, int bitsPerSample,int samplesPerPixel,
|
||
|
int bytesPerPixel);
|
||
|
|
||
|
extern void rfbScreenCleanup(rfbScreenInfoPtr screenInfo);
|
||
|
extern void rfbSetServerVersionIdentity(rfbScreenInfoPtr screen, char *fmt, ...);
|
||
|
|
||
|
/* functions to accept/refuse a client that has been put on hold
|
||
|
by a NewClientHookPtr function. Must not be called in other
|
||
|
situations. */
|
||
|
extern void rfbStartOnHoldClient(rfbClientPtr cl);
|
||
|
extern void rfbRefuseOnHoldClient(rfbClientPtr cl);
|
||
|
|
||
|
/* 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, so the
|
||
|
server doesn't get a high load just by listening.
|
||
|
rfbProcessEvents() returns TRUE if an update was pending. */
|
||
|
|
||
|
extern void rfbRunEventLoop(rfbScreenInfoPtr screenInfo, long usec, rfbBool runInBackground);
|
||
|
extern rfbBool rfbProcessEvents(rfbScreenInfoPtr screenInfo,long usec);
|
||
|
extern rfbBool rfbIsActive(rfbScreenInfoPtr screenInfo);
|
||
|
|
||
|
/* TightVNC file transfer extension */
|
||
|
void rfbRegisterTightVNCFileTransferExtension();
|
||
|
void rfbUnregisterTightVNCFileTransferExtension();
|
||
|
|
||
|
/* Statistics */
|
||
|
extern char *messageNameServer2Client(uint32_t type, char *buf, int len);
|
||
|
extern char *messageNameClient2Server(uint32_t type, char *buf, int len);
|
||
|
extern char *encodingName(uint32_t enc, char *buf, int len);
|
||
|
|
||
|
extern rfbStatList *rfbStatLookupEncoding(rfbClientPtr cl, uint32_t type);
|
||
|
extern rfbStatList *rfbStatLookupMessage(rfbClientPtr cl, uint32_t type);
|
||
|
|
||
|
/* Each call to rfbStatRecord* adds one to the rect count for that type */
|
||
|
extern void rfbStatRecordEncodingSent(rfbClientPtr cl, uint32_t type, int byteCount, int byteIfRaw);
|
||
|
extern void rfbStatRecordEncodingSentAdd(rfbClientPtr cl, uint32_t type, int byteCount); /* Specifically for tight encoding */
|
||
|
extern void rfbStatRecordEncodingRcvd(rfbClientPtr cl, uint32_t type, int byteCount, int byteIfRaw);
|
||
|
extern void rfbStatRecordMessageSent(rfbClientPtr cl, uint32_t type, int byteCount, int byteIfRaw);
|
||
|
extern void rfbStatRecordMessageRcvd(rfbClientPtr cl, uint32_t type, int byteCount, int byteIfRaw);
|
||
|
extern void rfbResetStats(rfbClientPtr cl);
|
||
|
extern void rfbPrintStats(rfbClientPtr cl);
|
||
|
|
||
|
extern int rfbStatGetSentBytes(rfbClientPtr cl);
|
||
|
extern int rfbStatGetSentBytesIfRaw(rfbClientPtr cl);
|
||
|
extern int rfbStatGetRcvdBytes(rfbClientPtr cl);
|
||
|
extern int rfbStatGetRcvdBytesIfRaw(rfbClientPtr cl);
|
||
|
extern int rfbStatGetMessageCountSent(rfbClientPtr cl, uint32_t type);
|
||
|
extern int rfbStatGetMessageCountRcvd(rfbClientPtr cl, uint32_t type);
|
||
|
extern int rfbStatGetEncodingCountSent(rfbClientPtr cl, uint32_t type);
|
||
|
extern int rfbStatGetEncodingCountRcvd(rfbClientPtr cl, uint32_t type);
|
||
|
|
||
|
/** Set which version you want to advertise 3.3, 3.6, 3.7 and 3.8 are currently supported*/
|
||
|
extern void rfbSetProtocolVersion(rfbScreenInfoPtr rfbScreen, int major_, int minor_);
|
||
|
|
||
|
/** send a TextChat message to a client */
|
||
|
extern rfbBool rfbSendTextChatMessage(rfbClientPtr cl, uint32_t length, char *buffer);
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Additions for Qt event loop integration
|
||
|
* Original idea taken from vino.
|
||
|
*/
|
||
|
rfbBool rfbProcessNewConnection(rfbScreenInfoPtr rfbScreen);
|
||
|
rfbBool rfbUpdateClient(rfbClientPtr cl);
|
||
|
|
||
|
|
||
|
#if(defined __cplusplus)
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
/**
|
||
|
* @}
|
||
|
*/
|
||
|
|
||
|
|
||
|
/**
|
||
|
@page libvncserver_doc LibVNCServer Documentation
|
||
|
@section create_server Creating a server instance
|
||
|
To make a server, you just have to initialise a server structure using the
|
||
|
function rfbGetScreen(), like
|
||
|
@code
|
||
|
rfbScreenInfoPtr screen =
|
||
|
rfbGetScreen(argc,argv,screenwidth,screenheight,8,3,bpp);
|
||
|
@endcode
|
||
|
where byte per pixel should be 1, 2 or 4. If performance doesn't matter,
|
||
|
you may try bpp=3 (internally one cannot use native data types in this
|
||
|
case; if you want to use this, look at pnmshow24.c).
|
||
|
|
||
|
You then can set hooks and io functions (see @ref making_it_interactive) or other
|
||
|
options (see @ref server_options).
|
||
|
|
||
|
And you allocate the frame buffer like this:
|
||
|
@code
|
||
|
screen->frameBuffer = (char*)malloc(screenwidth*screenheight*bpp);
|
||
|
@endcode
|
||
|
After that, you initialize the server, like
|
||
|
@code
|
||
|
rfbInitServer(screen);
|
||
|
@endcode
|
||
|
You can use a blocking event loop, a background (pthread based) event loop,
|
||
|
or implement your own using the rfbProcessEvents() function.
|
||
|
|
||
|
@subsection server_options Optional Server Features
|
||
|
|
||
|
These options have to be set between rfbGetScreen() and rfbInitServer().
|
||
|
|
||
|
If you already have a socket to talk to, just set rfbScreenInfo::inetdSock
|
||
|
(originally this is for inetd handling, but why not use it for your purpose?).
|
||
|
|
||
|
To also start an HTTP server (running on port 5800+display_number), you have
|
||
|
to set rfbScreenInfo::httpDir to a directory containing vncviewer.jar and
|
||
|
index.vnc (like the included "webclients" directory).
|
||
|
|
||
|
@section making_it_interactive Making it interactive
|
||
|
|
||
|
Whenever you draw something, you have to call
|
||
|
@code
|
||
|
rfbMarkRectAsModified(screen,x1,y1,x2,y2).
|
||
|
@endcode
|
||
|
This tells LibVNCServer to send updates to all connected clients.
|
||
|
|
||
|
There exist the following IO functions as members of rfbScreen:
|
||
|
rfbScreenInfo::kbdAddEvent(), rfbScreenInfo::kbdReleaseAllKeys(), rfbScreenInfo::ptrAddEvent() and rfbScreenInfo::setXCutText()
|
||
|
|
||
|
rfbScreenInfo::kbdAddEvent()
|
||
|
is called when a key is pressed.
|
||
|
rfbScreenInfo::kbdReleaseAllKeys()
|
||
|
is not called at all (maybe in the future).
|
||
|
rfbScreenInfo::ptrAddEvent()
|
||
|
is called when the mouse moves or a button is pressed.
|
||
|
WARNING: if you want to have proper cursor handling, call
|
||
|
rfbDefaultPtrAddEvent()
|
||
|
in your own function. This sets the coordinates of the cursor.
|
||
|
rfbScreenInfo::setXCutText()
|
||
|
is called when the selection changes.
|
||
|
|
||
|
There are only two hooks:
|
||
|
rfbScreenInfo::newClientHook()
|
||
|
is called when a new client has connected.
|
||
|
rfbScreenInfo::displayHook()
|
||
|
is called just before a frame buffer update is sent.
|
||
|
|
||
|
You can also override the following methods:
|
||
|
rfbScreenInfo::getCursorPtr()
|
||
|
This could be used to make an animated cursor (if you really want ...)
|
||
|
rfbScreenInfo::setTranslateFunction()
|
||
|
If you insist on colour maps or something more obscure, you have to
|
||
|
implement this. Default is a trueColour mapping.
|
||
|
|
||
|
@section cursor_handling Cursor handling
|
||
|
|
||
|
The screen holds a pointer
|
||
|
rfbScreenInfo::cursor
|
||
|
to the current cursor. Whenever you set it, remember that any dynamically
|
||
|
created cursor (like return value from rfbMakeXCursor()) is not free'd!
|
||
|
|
||
|
The rfbCursor structure consists mainly of a mask and a source. The rfbCursor::mask
|
||
|
describes, which pixels are drawn for the cursor (a cursor needn't be
|
||
|
rectangular). The rfbCursor::source describes, which colour those pixels should have.
|
||
|
|
||
|
The standard is an XCursor: a cursor with a foreground and a background
|
||
|
colour (stored in backRed,backGreen,backBlue and the same for foreground
|
||
|
in a range from 0-0xffff). Therefore, the arrays "mask" and "source"
|
||
|
contain pixels as single bits stored in bytes in MSB order. The rows are
|
||
|
padded, such that each row begins with a new byte (i.e. a 10x4
|
||
|
cursor's mask has 2x4 bytes, because 2 bytes are needed to hold 10 bits).
|
||
|
|
||
|
It is however very easy to make a cursor like this:
|
||
|
@code
|
||
|
char* cur=" "
|
||
|
" xx "
|
||
|
" x "
|
||
|
" ";
|
||
|
char* mask="xxxx"
|
||
|
"xxxx"
|
||
|
"xxxx"
|
||
|
"xxx ";
|
||
|
rfbCursorPtr c=rfbMakeXCursor(4,4,cur,mask);
|
||
|
@endcode
|
||
|
You can even set rfbCursor::mask to NULL in this call and LibVNCServer will calculate
|
||
|
a mask for you (dynamically, so you have to free it yourself).
|
||
|
|
||
|
There is also an array named rfbCursor::richSource for colourful cursors. They have
|
||
|
the same format as the frameBuffer (i.e. if the server is 32 bit,
|
||
|
a 10x4 cursor has 4x10x4 bytes).
|
||
|
|
||
|
@section screen_client_difference What is the difference between rfbScreenInfoPtr and rfbClientPtr?
|
||
|
|
||
|
The rfbScreenInfoPtr is a pointer to a rfbScreenInfo structure, which
|
||
|
holds information about the server, like pixel format, io functions,
|
||
|
frame buffer etc. The rfbClientPtr is a pointer to an rfbClientRec structure, which holds
|
||
|
information about a client, like pixel format, socket of the
|
||
|
connection, etc. A server can have several clients, but needn't have any. So, if you
|
||
|
have a server and three clients are connected, you have one instance
|
||
|
of a rfbScreenInfo and three instances of rfbClientRec's.
|
||
|
|
||
|
The rfbClientRec structure holds a member rfbClientRec::screen which points to the server.
|
||
|
So, to access the server from the client structure, you use client->screen.
|
||
|
|
||
|
To access all clients from a server be sure to use the provided iterator
|
||
|
rfbGetClientIterator()
|
||
|
with
|
||
|
rfbClientIteratorNext()
|
||
|
and
|
||
|
rfbReleaseClientIterator()
|
||
|
to prevent thread clashes.
|
||
|
|
||
|
@section example_code Example Code
|
||
|
|
||
|
There are two documented examples included:
|
||
|
- example.c, a shared scribble sheet
|
||
|
- pnmshow.c, a program to show PNMs (pictures) over the net.
|
||
|
|
||
|
The examples are not too well documented, but easy straight forward and a
|
||
|
good starting point.
|
||
|
|
||
|
Try example.c: it outputs on which port it listens (default: 5900), so it is
|
||
|
display 0. To view, call @code vncviewer :0 @endcode
|
||
|
You should see a sheet with a gradient and "Hello World!" written on it. Try
|
||
|
to paint something. Note that everytime you click, there is some bigger blot,
|
||
|
whereas when you drag the mouse while clicked you draw a line. The size of the
|
||
|
blot depends on the mouse button you click. Open a second vncviewer with
|
||
|
the same parameters and watch it as you paint in the other window. This also
|
||
|
works over internet. You just have to know either the name or the IP of your
|
||
|
machine. Then it is @code vncviewer machine.where.example.runs.com:0 @endcode
|
||
|
or similar for the remote client. Now you are ready to type something. Be sure
|
||
|
that your mouse sits still, because everytime the mouse moves, the cursor is
|
||
|
reset to the position of the pointer! If you are done with that demo, press
|
||
|
the down or up arrows. If your viewer supports it, then the dimensions of the
|
||
|
sheet change. Just press Escape in the viewer. Note that the server still
|
||
|
runs, even if you closed both windows. When you reconnect now, everything you
|
||
|
painted and wrote is still there. You can press "Page Up" for a blank page.
|
||
|
|
||
|
The demo pnmshow.c is much simpler: you either provide a filename as argument
|
||
|
or pipe a file through stdin. Note that the file has to be a raw pnm/ppm file,
|
||
|
i.e. a truecolour graphics. Only the Escape key is implemented. This may be
|
||
|
the best starting point if you want to learn how to use LibVNCServer. You
|
||
|
are confronted with the fact that the bytes per pixel can only be 8, 16 or 32.
|
||
|
*/
|
||
|
|
||
|
#endif
|