summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsteven_carr <steven_carr>2006-05-15 05:37:39 +0000
committersteven_carr <steven_carr>2006-05-15 05:37:39 +0000
commitccdbe8f3256c3c776a1cc1a0517a38437b9e2c65 (patch)
tree9853559d1c965946b196cccd03ce0f466d524950
parent347c4a98475d1dba8030efe33aa0b35856c4d17f (diff)
downloadlibtdevnc-ccdbe8f3256c3c776a1cc1a0517a38437b9e2c65.tar.gz
libtdevnc-ccdbe8f3256c3c776a1cc1a0517a38437b9e2c65.zip
The great UltraVNC Compatibility Commit
-rw-r--r--ChangeLog20
-rw-r--r--client_examples/SDLvncviewer.c22
-rw-r--r--libvncclient/rfbproto.c366
-rw-r--r--libvncclient/ultra.c4
-rw-r--r--libvncclient/zrle.c2
-rwxr-xr-xlibvncserver/auth.c7
-rwxr-xr-xlibvncserver/corre.c8
-rw-r--r--libvncserver/cursor.c11
-rwxr-xr-xlibvncserver/hextile.c17
-rw-r--r--libvncserver/main.c32
-rw-r--r--libvncserver/rfbserver.c1013
-rwxr-xr-xlibvncserver/rre.c8
-rw-r--r--libvncserver/scale.c8
-rwxr-xr-xlibvncserver/sockets.c22
-rwxr-xr-xlibvncserver/stats.c476
-rw-r--r--libvncserver/tight.c32
-rw-r--r--libvncserver/tightvnc-filetransfer/rfbtightproto.h6
-rw-r--r--libvncserver/ultra.c4
-rw-r--r--libvncserver/zlib.c6
-rw-r--r--libvncserver/zrle.c5
-rw-r--r--rfb/rfb.h111
-rw-r--r--rfb/rfbclient.h21
-rw-r--r--rfb/rfbproto.h22
-rw-r--r--x11vnc/rates.c11
-rw-r--r--x11vnc/userinput.c2
25 files changed, 1935 insertions, 301 deletions
diff --git a/ChangeLog b/ChangeLog
index b8cfc44..ec55ee6 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,23 @@
+2006-05-15 Steven Carr <scarr@jsa-usa.com>
+ * The great UltraVNC Compatibility Commit!
+ libvncserver now supports the following messages:
+ SetSingleWindow - Select a single window to be the source of the
+ framebuffer.
+ ServerInput - Disable and blank the servers display
+ TextChat - TextChat between the remote/local user
+ (Bandwidth friendly VS the Notepad approach)
+ FileTransfer - Emulates a Windows Filesystem to the viewer
+ (Currently does not support Delta Transfers)
+ (Currently does not support Sending Directories)
+ UltraZip - Improved UltraZip support
+ * Improved Statistics SubSystem, now supports all encodings
+ * RFB 3.8 support! Error Messages are a 'Good Thing' (tm)
+ * Default to identify as RFB 3.6 to emulate UltraVNC server
+ (Server now has the ability to set the RFB version reported)
+ (permits the viewer to identify the server has FileTransfer ability)
+ * Client Encoding AutoSelection Supported (UltraViewer is speed aware)
+ * libvncclient has improved server detection/capabilities logic!
+
2006-05-13 Karl Runge <runge@karlrunge.com>
* minilzo.c,minilzo.h,lzoconf.h: switch to non-CRLF versions.
* libvncclient/Makefile.am: add minilzo.c, minilzo.h, lzoconf.h
diff --git a/client_examples/SDLvncviewer.c b/client_examples/SDLvncviewer.c
index 8bb6efa..99c8e85 100644
--- a/client_examples/SDLvncviewer.c
+++ b/client_examples/SDLvncviewer.c
@@ -150,6 +150,26 @@ static void kbd_leds(rfbClient* cl, int value, int pad) {
fflush(stderr);
}
+/* trivial support for textchat */
+static void text_chat(rfbClient* cl, int value, char *text) {
+ switch(value) {
+ case rfbTextChatOpen:
+ fprintf(stderr,"TextChat: We should open a textchat window!\n");
+ TextChatOpen(cl);
+ break;
+ case rfbTextChatClose:
+ fprintf(stderr,"TextChat: We should close our window!\n");
+ break;
+ case rfbTextChatFinished:
+ fprintf(stderr,"TextChat: We should close our window!\n");
+ break;
+ default:
+ fprintf(stderr,"TextChat: Received \"%s\"\n", text);
+ break;
+ }
+ fflush(stderr);
+}
+
#ifdef __MINGW32__
#define LOG_TO_FILE
#endif
@@ -212,7 +232,7 @@ int main(int argc,char** argv) {
cl->canHandleNewFBSize = TRUE;
cl->GotFrameBufferUpdate=update;
cl->HandleKeyboardLedState=kbd_leds;
-
+ cl->HandleTextChat=text_chat;
if(!rfbInitClient(cl,&argc,argv))
return 1;
diff --git a/libvncclient/rfbproto.c b/libvncclient/rfbproto.c
index a7ad216..a7aab60 100644
--- a/libvncclient/rfbproto.c
+++ b/libvncclient/rfbproto.c
@@ -224,6 +224,99 @@ static rfbBool HandleZRLE32(rfbClient* client, int rx, int ry, int rw, int rh);
#endif
/*
+ * Server Capability Functions
+ */
+rfbBool
+SupportsClient2Server(rfbClient* client, int messageType)
+{
+ return (client->supportedMessages.client2server[((messageType & 0xFF)/8)] & (1<<(messageType % 8)) ? TRUE : FALSE);
+}
+
+rfbBool
+SupportsServer2Client(rfbClient* client, int messageType)
+{
+ return (client->supportedMessages.server2client[((messageType & 0xFF)/8)] & (1<<(messageType % 8)) ? TRUE : FALSE);
+}
+
+void
+SetClient2Server(rfbClient* client, int messageType)
+{
+ client->supportedMessages.client2server[((messageType & 0xFF)/8)] |= (1<<(messageType % 8));
+}
+
+void
+SetServer2Client(rfbClient* client, int messageType)
+{
+ client->supportedMessages.server2client[((messageType & 0xFF)/8)] |= (1<<(messageType % 8));
+}
+
+void
+ClearClient2Server(rfbClient* client, int messageType)
+{
+ client->supportedMessages.client2server[((messageType & 0xFF)/8)] &= (!(1<<(messageType % 8)));
+}
+
+void
+ClearServer2Client(rfbClient* client, int messageType)
+{
+ client->supportedMessages.server2client[((messageType & 0xFF)/8)] &= (!(1<<(messageType % 8)));
+}
+
+
+void
+DefaultSupportedMessages(rfbClient* client)
+{
+ memset((char *)&client->supportedMessages,0,sizeof(client->supportedMessages));
+
+ /* Default client supported messages (universal RFB 3.3 protocol) */
+ SetClient2Server(client, rfbSetPixelFormat);
+ /* SetClient2Server(client, rfbFixColourMapEntries); Not currently supported */
+ SetClient2Server(client, rfbSetEncodings);
+ SetClient2Server(client, rfbFramebufferUpdateRequest);
+ SetClient2Server(client, rfbKeyEvent);
+ SetClient2Server(client, rfbPointerEvent);
+ SetClient2Server(client, rfbClientCutText);
+ /* technically, we only care what we can *send* to the server
+ * but, we set Server2Client Just in case it ever becomes useful
+ */
+ SetServer2Client(client, rfbFramebufferUpdate);
+ SetServer2Client(client, rfbSetColourMapEntries);
+ SetServer2Client(client, rfbBell);
+ SetServer2Client(client, rfbServerCutText);
+}
+
+void
+DefaultSupportedMessagesUltraVNC(rfbClient* client)
+{
+ DefaultSupportedMessages(client);
+ SetClient2Server(client, rfbFileTransfer);
+ SetClient2Server(client, rfbSetScale);
+ SetClient2Server(client, rfbSetServerInput);
+ SetClient2Server(client, rfbSetSW);
+ SetClient2Server(client, rfbTextChat);
+ SetClient2Server(client, rfbPalmVNCSetScaleFactor);
+ /* technically, we only care what we can *send* to the server */
+ SetServer2Client(client, rfbResizeFrameBuffer);
+ SetServer2Client(client, rfbPalmVNCReSizeFrameBuffer);
+ SetServer2Client(client, rfbFileTransfer);
+ SetServer2Client(client, rfbTextChat);
+}
+
+
+void
+DefaultSupportedMessagesTightVNC(rfbClient* client)
+{
+ DefaultSupportedMessages(client);
+ SetClient2Server(client, rfbFileTransfer);
+ SetClient2Server(client, rfbSetServerInput);
+ SetClient2Server(client, rfbSetSW);
+ /* SetClient2Server(client, rfbTextChat); */
+ /* technically, we only care what we can *send* to the server */
+ SetServer2Client(client, rfbFileTransfer);
+ SetServer2Client(client, rfbTextChat);
+}
+
+/*
* ConnectToRFBServer.
*/
@@ -310,26 +403,87 @@ InitialiseRFBConnection(rfbClient* client)
return FALSE;
}
-#if rfbProtocolMinorVersion == 7
- /* work around LibVNCClient not yet speaking RFB 3.7 */
-#undef rfbProtocolMinorVersion
-#define rfbProtocolMinorVersion 3
-#endif
+
+ DefaultSupportedMessages(client);
+ client->major = major;
+ client->minor = minor;
+
+ /* fall back to viewer supported version */
+ if ((major==rfbProtocolMajorVersion) && (minor>rfbProtocolMinorVersion))
+ client->minor = rfbProtocolMinorVersion;
+
+ /* UltraVNC uses minor codes 4 and 6 for the server */
+ if (major==3 && (minor==4 || minor==6)) {
+ rfbClientLog("UltraVNC server detected, enabling UltraVNC specific messages\n",pv);
+ DefaultSupportedMessagesUltraVNC(client);
+ }
+
+ /* TightVNC uses minor codes 5 for the server */
+ if (major==3 && minor==5) {
+ rfbClientLog("TightVNC server detected, enabling TightVNC specific messages\n",pv);
+ DefaultSupportedMessagesTightVNC(client);
+ }
+
+ /* we do not support > RFB3.8 */
+ if (major==3 && minor>8)
+ client->minor=8;
rfbClientLog("VNC server supports protocol version %d.%d (viewer %d.%d)\n",
major, minor, rfbProtocolMajorVersion, rfbProtocolMinorVersion);
- major = rfbProtocolMajorVersion;
- minor = rfbProtocolMinorVersion;
-
- sprintf(pv,rfbProtocolVersionFormat,major,minor);
+ sprintf(pv,rfbProtocolVersionFormat,client->major,client->minor);
if (!WriteToRFBServer(client, pv, sz_rfbProtocolVersionMsg)) return FALSE;
- if (!ReadFromRFBServer(client, (char *)&authScheme, 4)) return FALSE;
- authScheme = rfbClientSwap32IfLE(authScheme);
+ /* 3.7 and onwards sends a # of security types first */
+ if (client->major==3 && client->minor > 6)
+ {
+ uint8_t count=0;
+ uint8_t loop=0;
+ uint8_t flag=0;
+ uint8_t tAuth=0;
+
+ if (!ReadFromRFBServer(client, (char *)&count, 1)) return FALSE;
+
+ if (count==0)
+ {
+ rfbClientLog("List of security types is ZERO, expecting an error to follow\n");
+
+ /* we have an error following */
+ if (!ReadFromRFBServer(client, (char *)&reasonLen, 4)) return FALSE;
+ reasonLen = rfbClientSwap32IfLE(reasonLen);
+ reason = malloc(reasonLen);
+ if (!ReadFromRFBServer(client, reason, reasonLen)) { free(reason); return FALSE; }
+ rfbClientLog("VNC connection failed: %.*s\n",(int)reasonLen, reason);
+ free(reason);
+ return FALSE;
+ }
+ rfbClientLog("We have %d security types to read\n", count);
+ /* now, we have a list of available security types to read ( uint8_t[] ) */
+ for (loop=0;loop<count;loop++)
+ {
+ if (!ReadFromRFBServer(client, (char *)&tAuth, 1)) return FALSE;
+ rfbClientLog("%d) Received security type %d\n", loop, tAuth);
+ if ((flag==0) && ((tAuth==rfbVncAuth) || (tAuth==rfbNoAuth)))
+ {
+ flag++;
+ authScheme=tAuth;
+ rfbClientLog("Selecting security type %d (%d/%d in the list)\n", authScheme, loop, count);
+ /* send back a single byte indicating which security type to use */
+ if (!WriteToRFBServer(client, (char *)&tAuth, 1)) return FALSE;
+ }
+ }
+ }
+ else
+ {
+ if (!ReadFromRFBServer(client, (char *)&authScheme, 4)) return FALSE;
+ authScheme = rfbClientSwap32IfLE(authScheme);
+ }
+
+ rfbClientLog("Selected Security Scheme %d\n", authScheme);
+
switch (authScheme) {
case rfbConnFailed:
@@ -338,9 +492,10 @@ InitialiseRFBConnection(rfbClient* client)
reason = malloc(reasonLen);
- if (!ReadFromRFBServer(client, reason, reasonLen)) return FALSE;
+ if (!ReadFromRFBServer(client, reason, reasonLen)) { free(reason); return FALSE; }
rfbClientLog("VNC connection failed: %.*s\n",(int)reasonLen, reason);
+ free(reason);
return FALSE;
case rfbNoAuth:
@@ -382,6 +537,17 @@ InitialiseRFBConnection(rfbClient* client)
rfbClientLog("VNC authentication succeeded\n");
break;
case rfbVncAuthFailed:
+ if (client->major==3 && client->minor>7)
+ {
+ /* we have an error following */
+ if (!ReadFromRFBServer(client, (char *)&reasonLen, 4)) return FALSE;
+ reasonLen = rfbClientSwap32IfLE(reasonLen);
+ reason = malloc(reasonLen);
+ if (!ReadFromRFBServer(client, reason, reasonLen)) { free(reason); return FALSE; }
+ rfbClientLog("VNC connection failed: %.*s\n",(int)reasonLen, reason);
+ free(reason);
+ return FALSE;
+ }
rfbClientLog("VNC authentication failed\n");
return FALSE;
case rfbVncAuthTooMany:
@@ -427,7 +593,7 @@ InitialiseRFBConnection(rfbClient* client)
rfbClientLog("Desktop name \"%s\"\n",client->desktopName);
rfbClientLog("Connected to VNC server, using protocol version %d.%d\n",
- rfbProtocolMajorVersion, rfbProtocolMinorVersion);
+ client->major, client->minor);
rfbClientLog("VNC server default format:\n");
PrintPixelFormat(&client->si.format);
@@ -445,6 +611,7 @@ SetFormatAndEncodings(rfbClient* client)
{
rfbSetPixelFormatMsg spf;
char buf[sz_rfbSetEncodingsMsg + MAX_ENCODINGS * 4];
+
rfbSetEncodingsMsg *se = (rfbSetEncodingsMsg *)buf;
uint32_t *encs = (uint32_t *)(&buf[sz_rfbSetEncodingsMsg]);
int len = 0;
@@ -453,6 +620,8 @@ SetFormatAndEncodings(rfbClient* client)
rfbBool requestLastRectEncoding = FALSE;
rfbClientProtocolExtension* e;
+ if (!SupportsClient2Server(client, rfbSetPixelFormat)) return TRUE;
+
spf.type = rfbSetPixelFormat;
spf.format = client->format;
spf.format.redMax = rfbClientSwap16IfLE(spf.format.redMax);
@@ -462,6 +631,9 @@ SetFormatAndEncodings(rfbClient* client)
if (!WriteToRFBServer(client, (char *)&spf, sz_rfbSetPixelFormatMsg))
return FALSE;
+
+ if (!SupportsClient2Server(client, rfbSetEncodings)) return TRUE;
+
se->type = rfbSetEncodings;
se->nEncodings = 0;
@@ -641,7 +813,7 @@ SetFormatAndEncodings(rfbClient* client)
rfbBool
SendIncrementalFramebufferUpdateRequest(rfbClient* client)
{
- return SendFramebufferUpdateRequest(client, 0, 0, client->width,
+ return SendFramebufferUpdateRequest(client, 0, 0, client->width,
client->height, TRUE);
}
@@ -655,6 +827,8 @@ SendFramebufferUpdateRequest(rfbClient* client, int x, int y, int w, int h, rfbB
{
rfbFramebufferUpdateRequestMsg fur;
+ if (!SupportsClient2Server(client, rfbFramebufferUpdateRequest)) return TRUE;
+
fur.type = rfbFramebufferUpdateRequest;
fur.incremental = incremental ? 1 : 0;
fur.x = rfbClientSwap16IfLE(x);
@@ -677,20 +851,106 @@ SendScaleSetting(rfbClient* client,int scaleSetting)
{
rfbSetScaleMsg ssm;
- if (client->appData.palmVNC)
- ssm.type = rfbPalmVNCSetScaleFactor;
- else
- ssm.type = rfbSetScale;
ssm.scale = scaleSetting;
ssm.pad = 0;
- if (!WriteToRFBServer(client, (char *)&ssm, sz_rfbSetScaleMsg))
- return FALSE;
+ /* favor UltraVNC SetScale if both are supported */
+ if (SupportsClient2Server(client, rfbSetScale)) {
+ ssm.type = rfbSetScale;
+ if (!WriteToRFBServer(client, (char *)&ssm, sz_rfbSetScaleMsg))
+ return FALSE;
+ }
+
+ if (SupportsClient2Server(client, rfbPalmVNCSetScaleFactor)) {
+ ssm.type = rfbPalmVNCSetScaleFactor;
+ if (!WriteToRFBServer(client, (char *)&ssm, sz_rfbSetScaleMsg))
+ return FALSE;
+ }
return TRUE;
}
/*
+ * TextChatFunctions (UltraVNC)
+ * Extremely bandwidth friendly method of communicating with a user
+ * (Think HelpDesk type applications)
+ */
+
+rfbBool TextChatSend(rfbClient* client, char *text)
+{
+ rfbTextChatMsg chat;
+ int count = strlen(text);
+
+ if (!SupportsClient2Server(client, rfbTextChat)) return TRUE;
+ chat.type = rfbTextChat;
+ chat.pad1 = 0;
+ chat.pad2 = 0;
+ chat.length = (uint32_t)count;
+ chat.length = rfbClientSwap32IfLE(chat.length);
+
+ if (!WriteToRFBServer(client, (char *)&chat, sz_rfbTextChatMsg))
+ return FALSE;
+
+ if (count>0) {
+ if (!WriteToRFBServer(client, text, count))
+ return FALSE;
+ }
+ return TRUE;
+}
+
+rfbBool TextChatOpen(rfbClient* client)
+{
+ rfbTextChatMsg chat;
+
+ if (!SupportsClient2Server(client, rfbTextChat)) return TRUE;
+ chat.type = rfbTextChat;
+ chat.pad1 = 0;
+ chat.pad2 = 0;
+ chat.length = rfbClientSwap32IfLE(rfbTextChatOpen);
+ return (WriteToRFBServer(client, (char *)&chat, sz_rfbTextChatMsg) ? TRUE : FALSE);
+}
+
+rfbBool TextChatClose(rfbClient* client)
+{
+ rfbTextChatMsg chat;
+ if (!SupportsClient2Server(client, rfbTextChat)) return TRUE;
+ chat.type = rfbTextChat;
+ chat.pad1 = 0;
+ chat.pad2 = 0;
+ chat.length = rfbClientSwap32IfLE(rfbTextChatClose);
+ return (WriteToRFBServer(client, (char *)&chat, sz_rfbTextChatMsg) ? TRUE : FALSE);
+}
+
+rfbBool TextChatFinish(rfbClient* client)
+{
+ rfbTextChatMsg chat;
+ if (!SupportsClient2Server(client, rfbTextChat)) return TRUE;
+ chat.type = rfbTextChat;
+ chat.pad1 = 0;
+ chat.pad2 = 0;
+ chat.length = rfbClientSwap32IfLE(rfbTextChatFinished);
+ return (WriteToRFBServer(client, (char *)&chat, sz_rfbTextChatMsg) ? TRUE : FALSE);
+}
+
+/*
+ * UltraVNC Server Input Disable
+ * Apparently, the remote client can *prevent* the local user from interacting with the display
+ * I would think this is extremely helpful when used in a HelpDesk situation
+ */
+rfbBool PermitServerInput(rfbClient* client, int enabled)
+{
+ rfbSetServerInputMsg msg;
+
+ if (!SupportsClient2Server(client, rfbSetServerInput)) return TRUE;
+ /* enabled==1, then server input from local keyboard is disabled */
+ msg.type = rfbSetServerInput;
+ msg.status = (enabled ? 1 : 0);
+ msg.pad = 0;
+ return (WriteToRFBServer(client, (char *)&msg, sz_rfbSetServerInputMsg) ? TRUE : FALSE);
+}
+
+
+/*
* SendPointerEvent.
*/
@@ -699,6 +959,8 @@ SendPointerEvent(rfbClient* client,int x, int y, int buttonMask)
{
rfbPointerEventMsg pe;
+ if (!SupportsClient2Server(client, rfbPointerEvent)) return TRUE;
+
pe.type = rfbPointerEvent;
pe.buttonMask = buttonMask;
if (x < 0) x = 0;
@@ -719,6 +981,8 @@ SendKeyEvent(rfbClient* client, uint32_t key, rfbBool down)
{
rfbKeyEventMsg ke;
+ if (!SupportsClient2Server(client, rfbKeyEvent)) return TRUE;
+
ke.type = rfbKeyEvent;
ke.down = down ? 1 : 0;
ke.key = rfbClientSwap32IfLE(key);
@@ -739,6 +1003,8 @@ SendClientCutText(rfbClient* client, char *str, int len)
free(client->serverCutText);
client->serverCutText = NULL;
+ if (!SupportsClient2Server(client, rfbClientCutText)) return TRUE;
+
cct.type = rfbClientCutText;
cct.length = rfbClientSwap32IfLE(len);
return (WriteToRFBServer(client, (char *)&cct, sz_rfbClientCutTextMsg) &&
@@ -858,9 +1124,8 @@ HandleRFBServerMessage(rfbClient* client)
/* rect.r.w=byte count */
if (rect.encoding == rfbEncodingSupportedMessages) {
- rfbSupportedMessages msgs;
int loop;
- if (!ReadFromRFBServer(client, (char *)&msgs, sz_rfbSupportedMessages))
+ if (!ReadFromRFBServer(client, (char *)&client->supportedMessages, sz_rfbSupportedMessages))
return FALSE;
/* msgs is two sets of bit flags of supported messages client2server[] and server2client[] */
@@ -869,18 +1134,18 @@ HandleRFBServerMessage(rfbClient* client)
rfbClientLog("client2server supported messages (bit flags)\n");
for (loop=0;loop<32;loop+=8)
rfbClientLog("%02X: %04x %04x %04x %04x - %04x %04x %04x %04x\n", loop,
- msgs.client2server[loop], msgs.client2server[loop+1],
- msgs.client2server[loop+2], msgs.client2server[loop+3],
- msgs.client2server[loop+4], msgs.client2server[loop+5],
- msgs.client2server[loop+6], msgs.client2server[loop+7]);
+ client->supportedMessages.client2server[loop], client->supportedMessages.client2server[loop+1],
+ client->supportedMessages.client2server[loop+2], client->supportedMessages.client2server[loop+3],
+ client->supportedMessages.client2server[loop+4], client->supportedMessages.client2server[loop+5],
+ client->supportedMessages.client2server[loop+6], client->supportedMessages.client2server[loop+7]);
rfbClientLog("server2client supported messages (bit flags)\n");
for (loop=0;loop<32;loop+=8)
rfbClientLog("%02X: %04x %04x %04x %04x - %04x %04x %04x %04x\n", loop,
- msgs.server2client[loop], msgs.server2client[loop+1],
- msgs.server2client[loop+2], msgs.server2client[loop+3],
- msgs.server2client[loop+4], msgs.server2client[loop+5],
- msgs.server2client[loop+6], msgs.server2client[loop+7]);
+ client->supportedMessages.server2client[loop], client->supportedMessages.server2client[loop+1],
+ client->supportedMessages.server2client[loop+2], client->supportedMessages.server2client[loop+3],
+ client->supportedMessages.server2client[loop+4], client->supportedMessages.server2client[loop+5],
+ client->supportedMessages.server2client[loop+6], client->supportedMessages.server2client[loop+7]);
continue;
}
@@ -1217,6 +1482,47 @@ HandleRFBServerMessage(rfbClient* client)
break;
}
+ case rfbTextChat:
+ {
+ char *buffer=NULL;
+ if (!ReadFromRFBServer(client, ((char *)&msg) + 1,
+ sz_rfbTextChatMsg- 1))
+ return FALSE;
+ msg.tc.length = rfbClientSwap32IfLE(msg.sct.length);
+ switch(msg.tc.length) {
+ case rfbTextChatOpen:
+ rfbClientLog("Received TextChat Open\n");
+ if (client->HandleTextChat!=NULL)
+ client->HandleTextChat(client, (int)rfbTextChatOpen, NULL);
+ break;
+ case rfbTextChatClose:
+ rfbClientLog("Received TextChat Close\n");
+ if (client->HandleTextChat!=NULL)
+ client->HandleTextChat(client, (int)rfbTextChatClose, NULL);
+ break;
+ case rfbTextChatFinished:
+ rfbClientLog("Received TextChat Finished\n");
+ if (client->HandleTextChat!=NULL)
+ client->HandleTextChat(client, (int)rfbTextChatFinished, NULL);
+ break;
+ default:
+ buffer=malloc(msg.tc.length+1);
+ if (!ReadFromRFBServer(client, buffer, msg.tc.length))
+ {
+ free(buffer);
+ return FALSE;
+ }
+ /* Null Terminate <just in case> */
+ buffer[msg.tc.length]=0;
+ rfbClientLog("Received TextChat \"%s\"\n", buffer);
+ if (client->HandleTextChat!=NULL)
+ client->HandleTextChat(client, (int)msg.tc.length, buffer);
+ free(buffer);
+ break;
+ }
+ break;
+ }
+
case rfbResizeFrameBuffer:
{
if (!ReadFromRFBServer(client, ((char *)&msg) + 1,
diff --git a/libvncclient/ultra.c b/libvncclient/ultra.c
index 641200f..3be150d 100644
--- a/libvncclient/ultra.c
+++ b/libvncclient/ultra.c
@@ -18,8 +18,6 @@
* USA.
*/
-#ifdef LIBVNCSERVER_HAVE_LIBZ
-
/*
* ultrazip.c - handle ultrazip encoding.
*
@@ -210,5 +208,3 @@ HandleUltraZipBPP (rfbClient* client, int rx, int ry, int rw, int rh)
}
#undef CARDBPP
-
-#endif
diff --git a/libvncclient/zrle.c b/libvncclient/zrle.c
index 50654b3..701fb43 100644
--- a/libvncclient/zrle.c
+++ b/libvncclient/zrle.c
@@ -377,7 +377,7 @@ static int HandleZRLETile(rfbClient* client,
#undef HandleZRLETile
#undef UncompressCPixel
#undef REALBPP
-#undef UNCOMP
#endif
+#undef UNCOMP
diff --git a/libvncserver/auth.c b/libvncserver/auth.c
index fd4c487..6e7a617 100755
--- a/libvncserver/auth.c
+++ b/libvncserver/auth.c
@@ -317,7 +317,12 @@ rfbAuthProcessClientMessage(rfbClientPtr cl)
if (rfbWriteExact(cl, (char *)&authResult, 4) < 0) {
rfbLogPerror("rfbAuthProcessClientMessage: write");
}
- rfbCloseClient(cl);
+ /* support RFB 3.8 clients, they expect a reason *why* it was disconnected */
+ if (cl->protocolMinorVersion > 7) {
+ rfbClientConnFailed(cl, "password check failed!");
+ }
+ else
+ rfbCloseClient(cl);
return;
}
diff --git a/libvncserver/corre.c b/libvncserver/corre.c
index c1164c0..75f1211 100755
--- a/libvncserver/corre.c
+++ b/libvncserver/corre.c
@@ -41,7 +41,7 @@ static char *rreBeforeBuf = NULL;
static int rreAfterBufSize = 0;
static char *rreAfterBuf = NULL;
-static int rreAfterBufLen;
+static int rreAfterBufLen = 0;
static int subrectEncode8(uint8_t *data, int w, int h);
static int subrectEncode16(uint16_t *data, int w, int h);
@@ -145,9 +145,9 @@ rfbSendSmallRectEncodingCoRRE(rfbClientPtr cl,
return rfbSendRectEncodingRaw(cl, x, y, w, h);
}
- cl->rectanglesSent[rfbEncodingCoRRE]++;
- cl->bytesSent[rfbEncodingCoRRE] += (sz_rfbFramebufferUpdateRectHeader
- + sz_rfbRREHeader + rreAfterBufLen);
+ rfbStatRecordEncodingSent(cl,rfbEncodingCoRRE,
+ sz_rfbFramebufferUpdateRectHeader + sz_rfbRREHeader + rreAfterBufLen,
+ sz_rfbFramebufferUpdateRectHeader + w * h * (cl->format.bitsPerPixel / 8));
if (cl->ublen + sz_rfbFramebufferUpdateRectHeader + sz_rfbRREHeader
> UPDATE_BUF_SIZE)
diff --git a/libvncserver/cursor.c b/libvncserver/cursor.c
index 2accc25..8cc5ecb 100644
--- a/libvncserver/cursor.c
+++ b/libvncserver/cursor.c
@@ -78,9 +78,6 @@ rfbSendCursorShape(rfbClientPtr cl)
sz_rfbFramebufferUpdateRectHeader);
cl->ublen += sz_rfbFramebufferUpdateRectHeader;
- cl->cursorShapeBytesSent += sz_rfbFramebufferUpdateRectHeader;
- cl->cursorShapeUpdatesSent++;
-
if (!rfbSendUpdateBuf(cl))
return FALSE;
@@ -167,9 +164,8 @@ rfbSendCursorShape(rfbClientPtr cl)
}
/* Send everything we have prepared in the cl->updateBuf[]. */
-
- cl->cursorShapeBytesSent += (cl->ublen - saved_ublen);
- cl->cursorShapeUpdatesSent++;
+ rfbStatRecordMessageSent(cl, (cl->useRichCursorEncoding ? rfbEncodingRichCursor : rfbEncodingXCursor),
+ sz_rfbFramebufferUpdateRectHeader + (cl->ublen - saved_ublen), sz_rfbFramebufferUpdateRectHeader + (cl->ublen - saved_ublen));
if (!rfbSendUpdateBuf(cl))
return FALSE;
@@ -201,8 +197,7 @@ rfbSendCursorPos(rfbClientPtr cl)
sz_rfbFramebufferUpdateRectHeader);
cl->ublen += sz_rfbFramebufferUpdateRectHeader;
- cl->cursorPosBytesSent += sz_rfbFramebufferUpdateRectHeader;
- cl->cursorPosUpdatesSent++;
+ rfbStatRecordMessageSent(cl, rfbEncodingPointerPos, sz_rfbFramebufferUpdateRectHeader, sz_rfbFramebufferUpdateRectHeader);
if (!rfbSendUpdateBuf(cl))
return FALSE;
diff --git a/libvncserver/hextile.c b/libvncserver/hextile.c
index cd598ac..52920d8 100755
--- a/libvncserver/hextile.c
+++ b/libvncserver/hextile.c
@@ -44,7 +44,7 @@ rfbSendRectEncodingHextile(rfbClientPtr cl,
int h)
{
rfbFramebufferUpdateRectHeader rect;
-
+
if (cl->ublen + sz_rfbFramebufferUpdateRectHeader > UPDATE_BUF_SIZE) {
if (!rfbSendUpdateBuf(cl))
return FALSE;
@@ -60,8 +60,9 @@ rfbSendRectEncodingHextile(rfbClientPtr cl,
sz_rfbFramebufferUpdateRectHeader);
cl->ublen += sz_rfbFramebufferUpdateRectHeader;
- cl->rectanglesSent[rfbEncodingHextile]++;
- cl->bytesSent[rfbEncodingHextile] += sz_rfbFramebufferUpdateRectHeader;
+ rfbStatRecordEncodingSent(cl, rfbEncodingHextile,
+ sz_rfbFramebufferUpdateRectHeader,
+ sz_rfbFramebufferUpdateRectHeader + w * (cl->format.bitsPerPixel / 8) * h);
switch (cl->format.bitsPerPixel) {
case 8:
@@ -136,6 +137,7 @@ sendHextiles##bpp(rfbClientPtr cl, int rx, int ry, int rw, int rh) {
startUblen = cl->ublen; \
cl->updateBuf[startUblen] = 0; \
cl->ublen++; \
+ rfbStatRecordEncodingSentAdd(cl, rfbEncodingHextile, 1); \
\
testColours##bpp(clientPixelData, w * h, \
&mono, &solid, &newBg, &newFg); \
@@ -148,7 +150,6 @@ sendHextiles##bpp(rfbClientPtr cl, int rx, int ry, int rw, int rh) {
} \
\
if (solid) { \
- cl->bytesSent[rfbEncodingHextile] += cl->ublen - startUblen; \
continue; \
} \
\
@@ -175,15 +176,15 @@ sendHextiles##bpp(rfbClientPtr cl, int rx, int ry, int rw, int rh) {
(*cl->translateFn)(cl->translateLookupTable, \
&(cl->screen->serverFormat), &cl->format, fbptr, \
(char *)clientPixelData, \
- cl->scaledScreen->paddedWidthInBytes, w, h); \
+ cl->scaledScreen->paddedWidthInBytes, w, h); \
\
memcpy(&cl->updateBuf[cl->ublen], (char *)clientPixelData, \
w * h * (bpp/8)); \
\
cl->ublen += w * h * (bpp/8); \
+ rfbStatRecordEncodingSentAdd(cl, rfbEncodingHextile, \
+ w * h * (bpp/8)); \
} \
- \
- cl->bytesSent[rfbEncodingHextile] += cl->ublen - startUblen; \
} \
} \
\
@@ -210,6 +211,7 @@ subrectEncode##bpp(rfbClientPtr cl, uint##bpp##_t *data, int w, int h,
\
nSubrectsUblen = cl->ublen; \
cl->ublen++; \
+ rfbStatRecordEncodingSentAdd(cl, rfbEncodingHextile, 1); \
\
for (y=0; y<h; y++) { \
line = data+(y*w); \
@@ -268,6 +270,7 @@ subrectEncode##bpp(rfbClientPtr cl, uint##bpp##_t *data, int w, int h,
\
cl->updateBuf[cl->ublen++] = rfbHextilePackXY(thex,they); \
cl->updateBuf[cl->ublen++] = rfbHextilePackWH(thew,theh); \
+ rfbStatRecordEncodingSentAdd(cl, rfbEncodingHextile, 1); \
\
/* \
* Now mark the subrect as done. \
diff --git a/libvncserver/main.c b/libvncserver/main.c
index 6a34980..cded456 100644
--- a/libvncserver/main.c
+++ b/libvncserver/main.c
@@ -495,22 +495,40 @@ clientInput(void *data)
pthread_create(&output_thread, NULL, clientOutput, (void *)cl);
while (1) {
- fd_set fds;
+ fd_set rfds, wfds, efds;
struct timeval tv;
int n;
- FD_ZERO(&fds);
- FD_SET(cl->sock, &fds);
+ FD_ZERO(&rfds);
+ FD_SET(cl->sock, &rfds);
+ FD_ZERO(&efds);
+ FD_SET(cl->sock, &efds);
+
+ /* Are we transferring a file in the background? */
+ FD_ZERO(&wfds);
+ if ((cl->fileTransfer.fd!=-1) && (cl->fileTransfer.sending==1))
+ FD_SET(cl->sock, &wfds);
+
tv.tv_sec = 60; /* 1 minute */
tv.tv_usec = 0;
- n = select(cl->sock + 1, &fds, NULL, &fds, &tv);
+ n = select(cl->sock + 1, &rfds, &wfds, &efds, &tv);
if (n < 0) {
rfbLogPerror("ReadExact: select");
break;
}
if (n == 0) /* timeout */
+ {
+ rfbSendFileTransferChunk(cl);
continue;
- rfbProcessClientMessage(cl);
+ }
+
+ /* We have some space on the transmit queue, send some data */
+ if (FD_ISSET(cl->sock, &wfds))
+ rfbSendFileTransferChunk(cl);
+
+ if (FD_ISSET(cl->sock, &rfds) || FD_ISSET(cl->sock, &efds))
+ rfbProcessClientMessage(cl);
+
if (cl->sock == -1) {
/* Client has disconnected. */
break;
@@ -818,6 +836,10 @@ rfbScreenInfoPtr rfbGetScreen(int* argc,char** argv,
screen->handleEventsEagerly = FALSE;
+ /* Emulate UltraVNC Server by default */
+ screen->protocolMajorVersion = 3;
+ screen->protocolMinorVersion = 6;
+
if(!rfbProcessArguments(screen,argc,argv)) {
free(screen);
return NULL;
diff --git a/libvncserver/rfbserver.c b/libvncserver/rfbserver.c
index 1945ae1..ab4e04f 100644
--- a/libvncserver/rfbserver.c
+++ b/libvncserver/rfbserver.c
@@ -66,6 +66,14 @@
#endif
#include <stdarg.h>
#include <scale.h>
+/* stst() */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+/* readdir() */
+#include <dirent.h>
+/* errno */
+#include <errno.h>
static void rfbProcessClientProtocolVersion(rfbClientPtr cl);
static void rfbProcessClientNormalMessage(rfbClientPtr cl);
@@ -229,6 +237,20 @@ rfbReverseConnection(rfbScreenInfoPtr rfbScreen,
}
+void
+rfbSetProtocolVersion(rfbScreenInfoPtr rfbScreen, int major_, int minor_)
+{
+ /* Permit the server to set the version to report */
+ /* TODO: sanity checking */
+ if ((major_==3) && (minor_ > 2 && minor_ < 9))
+ {
+ rfbScreen->protocolMajorVersion = major_;
+ rfbScreen->protocolMinorVersion = minor_;
+ }
+ else
+ rfbLog("rfbSetProtocolVersion(%d,%d) set to invalid values\n", major_, minor_);
+}
+
/*
* rfbNewClient is called when a new connection has been made by whatever
* means.
@@ -348,6 +370,8 @@ rfbNewTCPOrUDPClient(rfbScreenInfoPtr rfbScreen,
#endif
#endif
+ cl->fileTransfer.fd = -1;
+
cl->enableCursorShapeUpdates = FALSE;
cl->enableCursorPosUpdates = FALSE;
cl->useRichCursorEncoding = FALSE;
@@ -378,8 +402,8 @@ rfbNewTCPOrUDPClient(rfbScreenInfoPtr rfbScreen,
cl->lastPtrX = -1;
- sprintf(pv,rfbProtocolVersionFormat,rfbProtocolMajorVersion,
- rfbProtocolMinorVersion);
+ sprintf(pv,rfbProtocolVersionFormat,rfbScreen->protocolMajorVersion,
+ rfbScreen->protocolMinorVersion);
if (rfbWriteExact(cl, pv, sz_rfbProtocolVersionMsg) < 0) {
rfbLogPerror("rfbNewClient: write");
@@ -583,7 +607,7 @@ rfbProcessClientProtocolVersion(rfbClientPtr cl)
free(cl->host);
cl->host=strdup(name);
}
- rfbLog("Protocol version %d.%d\n", major_, minor_);
+ rfbLog("Client Protocol Version %d.%d\n", major_, minor_);
if (major_ != rfbProtocolMajorVersion) {
/* Major version mismatch - send a ConnFailed message */
@@ -591,23 +615,24 @@ rfbProcessClientProtocolVersion(rfbClientPtr cl)
rfbErr("Major version mismatch\n");
sprintf(failureReason,
"RFB protocol version mismatch - server %d.%d, client %d.%d",
- rfbProtocolMajorVersion,rfbProtocolMinorVersion,major_,minor_);
+ cl->screen->protocolMajorVersion, cl->screen->protocolMinorVersion,
+ major_,minor_);
rfbClientConnFailed(cl, failureReason);
return;
}
- /* Chk for the minor version use either of the two standard version of RFB */
+ /* Check for the minor version use either of the two standard version of RFB */
+ /*
+ * UltraVNC Viewer detects FileTransfer compatible servers via rfb versions
+ * 3.4, 3.6, 3.14, 3.16
+ * It's a bad method, but it is what they use to enable features...
+ * maintaining RFB version compatibility across multiple servers is a pain
+ * Should use something like ServerIdentity encoding
+ */
cl->protocolMinorVersion = minor_;
- if (minor_ > rfbProtocolMinorVersion) {
- cl->protocolMinorVersion = rfbProtocolMinorVersion;
- } else if (minor_ < rfbProtocolMinorVersion) {
- cl->protocolMinorVersion = rfbProtocolFallbackMinorVersion;
- }
- if (minor_ != rfbProtocolMinorVersion &&
- minor_ != rfbProtocolFallbackMinorVersion) {
- rfbLog("Non-standard protocol version %d.%d, using %d.%d instead\n",
+
+ rfbLog("Protocol version sent %d.%d, using %d.%d\n",
major_, minor_, rfbProtocolMajorVersion, cl->protocolMinorVersion);
- }
rfbAuthNewClient(cl);
}
@@ -775,8 +800,7 @@ rfbSendKeyboardLedState(rfbClientPtr cl)
sz_rfbFramebufferUpdateRectHeader);
cl->ublen += sz_rfbFramebufferUpdateRectHeader;
- cl->cursorPosBytesSent += sz_rfbFramebufferUpdateRectHeader;
- cl->cursorPosUpdatesSent++;
+ rfbStatRecordEncodingSent(cl, rfbEncodingKeyboardLedState, sz_rfbFramebufferUpdateRectHeader, sz_rfbFramebufferUpdateRectHeader);
if (!rfbSendUpdateBuf(cl))
return FALSE;
@@ -806,7 +830,7 @@ rfbSendSupportedMessages(rfbClientPtr cl)
rect.encoding = Swap32IfLE(rfbEncodingSupportedMessages);
rect.r.x = 0;
rect.r.y = 0;
- rect.r.w = Swap16IfLE(sz_rfbFramebufferUpdateRectHeader);
+ rect.r.w = Swap16IfLE(sz_rfbSupportedMessages);
rect.r.h = 0;
memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,
@@ -823,10 +847,10 @@ rfbSendSupportedMessages(rfbClientPtr cl)
rfbSetBit(msgs.client2server, rfbClientCutText);
rfbSetBit(msgs.client2server, rfbFileTransfer);
rfbSetBit(msgs.client2server, rfbSetScale);
- //rfbSetBit(msgs.client2server, rfbSetServerInput);
- //rfbSetBit(msgs.client2server, rfbSetSW);
- //rfbSetBit(msgs.client2server, rfbTextChat);
- //rfbSetBit(msgs.client2server, rfbKeyFrameRequest);
+ /*rfbSetBit(msgs.client2server, rfbSetServerInput); */
+ /*rfbSetBit(msgs.client2server, rfbSetSW); */
+ /*rfbSetBit(msgs.client2server, rfbTextChat); */
+ /*rfbSetBit(msgs.client2server, rfbKeyFrameRequest); */
rfbSetBit(msgs.client2server, rfbPalmVNCSetScaleFactor);
rfbSetBit(msgs.server2client, rfbFramebufferUpdate);
@@ -834,12 +858,15 @@ rfbSendSupportedMessages(rfbClientPtr cl)
rfbSetBit(msgs.server2client, rfbBell);
rfbSetBit(msgs.server2client, rfbServerCutText);
rfbSetBit(msgs.server2client, rfbResizeFrameBuffer);
- //rfbSetBit(msgs.server2client, rfbKeyFrameUpdate);
+ /*rfbSetBit(msgs.server2client, rfbKeyFrameUpdate); */
rfbSetBit(msgs.server2client, rfbPalmVNCReSizeFrameBuffer);
memcpy(&cl->updateBuf[cl->ublen], (char *)&msgs, sz_rfbSupportedMessages);
cl->ublen += sz_rfbSupportedMessages;
+ rfbStatRecordEncodingSent(cl, rfbEncodingSupportedMessages,
+ sz_rfbFramebufferUpdateRectHeader+sz_rfbSupportedMessages,
+ sz_rfbFramebufferUpdateRectHeader+sz_rfbSupportedMessages);
if (!rfbSendUpdateBuf(cl))
return FALSE;
@@ -918,6 +945,10 @@ rfbSendSupportedEncodings(rfbClientPtr cl)
rfbSendSupporteddEncodings_SendEncoding(cl, rfbEncodingSupportedEncodings);
rfbSendSupporteddEncodings_SendEncoding(cl, rfbEncodingServerIdentity);
+ rfbStatRecordEncodingSent(cl, rfbEncodingSupportedEncodings,
+ sz_rfbFramebufferUpdateRectHeader+(nEncodings * sizeof(uint32_t)),
+ sz_rfbFramebufferUpdateRectHeader+(nEncodings * sizeof(uint32_t)));
+
if (!rfbSendUpdateBuf(cl))
return FALSE;
@@ -973,17 +1004,655 @@ rfbSendServerIdentity(rfbClientPtr cl)
memcpy(&cl->updateBuf[cl->ublen], buffer, strlen(buffer)+1);
cl->ublen += strlen(buffer)+1;
+ rfbStatRecordEncodingSent(cl, rfbEncodingServerIdentity,
+ sz_rfbFramebufferUpdateRectHeader+strlen(buffer)+1,
+ sz_rfbFramebufferUpdateRectHeader+strlen(buffer)+1);
+
+
if (!rfbSendUpdateBuf(cl))
return FALSE;
return TRUE;
}
+rfbBool rfbSendFileTransferMessage(rfbClientPtr cl, uint8_t contentType, uint8_t contentParam, uint32_t size, uint32_t length, char *buffer)
+{
+ rfbFileTransferMsg ft;
+ ft.type = rfbFileTransfer;
+ ft.contentType = contentType;
+ ft.contentParam = contentParam;
+ ft.pad = 0; /* UltraVNC did not Swap16LE(ft.contentParam) (Looks like it might be BigEndian) */
+ ft.size = Swap32IfLE(size);
+ ft.length = Swap32IfLE(length);
+
+ /*
+ rfbLog("rfbSendFileTransferMessage( %dtype, %dparam, %dsize, %dlen, %p)\n", contentType, contentParam, size, length, buffer);
+ */
+ if (rfbWriteExact(cl, (char *)&ft, sz_rfbFileTransferMsg) < 0) {
+ rfbLogPerror("rfbSendFileTransferMessage: write");
+ rfbCloseClient(cl);
+ return FALSE;
+ }
+ if (length>0)
+ {
+ if (rfbWriteExact(cl, buffer, length) < 0) {
+ rfbLogPerror("rfbSendFileTransferMessage: write");
+ rfbCloseClient(cl);
+ return FALSE;
+ }
+ }
+
+ rfbStatRecordMessageSent(cl, rfbFileTransfer, sz_rfbFileTransferMsg+length, sz_rfbFileTransferMsg+length);
+ return TRUE;
+}
/*
+ * UltraVNC uses Windows Structures
+ */
+#define MAX_PATH 260
+
+typedef struct _FILETIME {
+ uint32_t dwLowDateTime;
+ uint32_t dwHighDateTime;
+} FILETIME;
+
+typedef struct _WIN32_FIND_DATA {
+ uint32_t dwFileAttributes;
+ FILETIME ftCreationTime;
+ FILETIME ftLastAccessTime;
+ FILETIME ftLastWriteTime;
+ uint32_t nFileSizeHigh;
+ uint32_t nFileSizeLow;
+ uint32_t dwReserved0;
+ uint32_t dwReserved1;
+ uint8_t cFileName[ MAX_PATH ];
+ uint8_t cAlternateFileName[ 14 ];
+} WIN32_FIND_DATA;
+
+#define FILE_ATTRIBUTE_READONLY 0x1
+#define FILE_ATTRIBUTE_HIDDEN 0x2
+#define FILE_ATTRIBUTE_SYSTEM 0x4
+#define FILE_ATTRIBUTE_DIRECTORY 0x10
+#define FILE_ATTRIBUTE_ARCHIVE 0x20
+#define FILE_ATTRIBUTE_NORMAL 0x80
+#define FILE_ATTRIBUTE_TEMPORARY 0x100
+#define FILE_ATTRIBUTE_COMPRESSED 0x800
+
+rfbBool rfbFilenameTranslate2UNIX(rfbClientPtr cl, char *path, char *unixPath)
+{
+ int x;
+ char *home=NULL;
+ /* C: */
+ if (path[0]=='C' && path[1]==':')
+ strcpy(unixPath, &path[2]);
+ else
+ {
+ home = getenv("HOME");
+ if (home!=NULL)
+ {
+ strcpy(unixPath, home);
+ strcat(unixPath,"/");
+ strcat(unixPath, path);
+ }
+ else
+ strcpy(unixPath, path);
+ }
+ for (x=0;x<strlen(unixPath);x++)
+ if (unixPath[x]=='\\') unixPath[x]='/';
+ return TRUE;
+}
+
+rfbBool rfbFilenameTranslate2DOS(rfbClientPtr cl, char *unixPath, char *path)
+{
+ int x;
+ sprintf(path,"C:%s", unixPath);
+ for (x=2;x<strlen(path);x++)
+ if (path[x]=='/') path[x]='\\';
+ return TRUE;
+}
+
+rfbBool rfbSendDirContent(rfbClientPtr cl, int length, char *buffer)
+{
+ char retfilename[MAX_PATH];
+ char path[MAX_PATH];
+ struct stat statbuf;
+ WIN32_FIND_DATA win32filename;
+ int nOptLen = 0, retval=0;
+ DIR *dirp=NULL;
+ struct dirent *direntp=NULL;
+
+ /* Client thinks we are Winblows */
+ rfbFilenameTranslate2UNIX(cl, buffer, path);
+
+// /*
+ rfbLog("rfbProcessFileTransfer() rfbDirContentRequest: rfbRDirContent: \"%s\"->\"%s\"\n",buffer, path);
+// */
+ dirp=opendir(path);
+ if (dirp==NULL)
+ return rfbSendFileTransferMessage(cl, rfbDirPacket, rfbADirectory, 0, 0, NULL);
+ /* send back the path name (necessary for links) */
+ if (rfbSendFileTransferMessage(cl, rfbDirPacket, rfbADirectory, 0, length, buffer)==FALSE) return FALSE;
+ for (direntp=readdir(dirp); direntp!=NULL; direntp=readdir(dirp))
+ {
+ /* get stats */
+ snprintf(retfilename,sizeof(retfilename),"%s/%s", path, direntp->d_name);
+ retval = stat(retfilename, &statbuf);
+
+ if (retval==0)
+ {
+ memset((char *)&win32filename, 0, sizeof(win32filename));
+ win32filename.dwFileAttributes = Swap32IfBE(FILE_ATTRIBUTE_NORMAL);
+ if (S_ISDIR(statbuf.st_mode))
+ win32filename.dwFileAttributes = Swap32IfBE(FILE_ATTRIBUTE_DIRECTORY);
+ win32filename.ftCreationTime.dwLowDateTime = Swap32IfBE(statbuf.st_ctime); /* Intel Order */
+ win32filename.ftCreationTime.dwHighDateTime = 0;
+ win32filename.ftLastAccessTime.dwLowDateTime = Swap32IfBE(statbuf.st_atime); /* Intel Order */
+ win32filename.ftLastAccessTime.dwHighDateTime = 0;
+ win32filename.ftLastWriteTime.dwLowDateTime = Swap32IfBE(statbuf.st_mtime); /* Intel Order */
+ win32filename.ftLastWriteTime.dwHighDateTime = 0;
+ win32filename.nFileSizeLow = Swap32IfBE(statbuf.st_size); /* Intel Order */
+ win32filename.nFileSizeHigh = 0;
+ win32filename.dwReserved0 = 0;
+ win32filename.dwReserved1 = 0;
+
+ /* If this had the full path, we would need to translate to DOS format ("C:\") */
+ /* rfbFilenameTranslate2DOS(cl, retfilename, win32filename.cFileName); */
+ strcpy((char *)win32filename.cFileName, direntp->d_name);
+
+ /* Do not show hidden files (but show how to move up the tree) */
+ if ((strcmp(direntp->d_name, "..")==0) || (direntp->d_name[0]!='.'))
+ {
+ nOptLen = sizeof(WIN32_FIND_DATA) - MAX_PATH - 14 + strlen((char *)win32filename.cFileName);
+ /*
+ rfbLog("rfbProcessFileTransfer() rfbDirContentRequest: rfbRDirContent: Sending \"%s\"\n", (char *)win32filename.cFileName);
+ */
+ if (rfbSendFileTransferMessage(cl, rfbDirPacket, rfbADirectory, 0, nOptLen, (char *)&win32filename)==FALSE) return FALSE;
+ }
+ }
+ }
+ closedir(dirp);
+ /* End of the transfer */
+ return rfbSendFileTransferMessage(cl, rfbDirPacket, 0, 0, 0, NULL);
+}
+
+
+char *rfbProcessFileTransferReadBuffer(rfbClientPtr cl, uint32_t length)
+{
+ char *buffer=NULL;
+ int n=0;
+ /*
+ rfbLog("rfbProcessFileTransferReadBuffer(%dlen)\n", length);
+ */
+ if (length>0) {
+ buffer=malloc(length+1);
+ if (buffer!=NULL) {
+ if ((n = rfbReadExact(cl, (char *)buffer, length)) <= 0) {
+ if (n != 0)
+ rfbLogPerror("rfbProcessFileTransferReadBuffer: read");
+ rfbCloseClient(cl);
+ /* NOTE: don't forget to free(buffer) if you return early! */
+ if (buffer!=NULL) free(buffer);
+ return NULL;
+ }
+ /* Null Terminate */
+ buffer[length]=0;
+ }
+ }
+ return buffer;
+}
+
+
+rfbBool rfbSendFileTransferChunk(rfbClientPtr cl)
+{
+ /* Allocate buffer for compression */
+ unsigned char readBuf[sz_rfbBlockSize];
+ int bytesRead=0;
+ int retval=0;
+ fd_set wfds;
+ struct timeval tv;
+ int n;
+#ifdef LIBVNCSERVER_HAVE_LIBZ
+ unsigned char compBuf[sz_rfbBlockSize + 1024];
+ unsigned long nMaxCompSize = sizeof(compBuf);
+ int nRetC = 0;
+#endif
+
+ /* If not sending, or no file open... Return as if we sent something! */
+ if ((cl->fileTransfer.fd!=-1) && (cl->fileTransfer.sending==1))
+ {
+ FD_ZERO(&wfds);
+ FD_SET(cl->sock, &wfds);
+
+ /* return immediately */
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ n = select(cl->sock + 1, NULL, &wfds, NULL, &tv);
+
+ if (n<1)
+ rfbLog("rfbSendFileTransferChunk() select failed: %s\n", strerror(errno));
+ /* We have space on the transmit queue */
+ if (n > 0)
+ {
+ bytesRead = read(cl->fileTransfer.fd, readBuf, sz_rfbBlockSize);
+ switch (bytesRead) {
+ case 0:
+ /*
+ rfbLog("rfbSendFileTransferChunk(): End-Of-File Encountered\n");
+ */
+ retval = rfbSendFileTransferMessage(cl, rfbEndOfFile, 0, 0, 0, NULL);
+ close(cl->fileTransfer.fd);
+ cl->fileTransfer.fd = -1;
+ cl->fileTransfer.sending = 0;
+ cl->fileTransfer.receiving = 0;
+ return retval;
+ case -1:
+ /* TODO : send an error msg to the client... */
+ rfbLog("rfbSendFileTransferChunk(): %s\n",strerror(errno));
+ retval = rfbSendFileTransferMessage(cl, rfbAbortFileTransfer, 0, 0, 0, NULL);
+ close(cl->fileTransfer.fd);
+ cl->fileTransfer.fd = -1;
+ cl->fileTransfer.sending = 0;
+ cl->fileTransfer.receiving = 0;
+ return retval;
+ default:
+ /*
+ rfbLog("rfbSendFileTransferChunk(): Read %d bytes\n", bytesRead);
+ */
+ if (!cl->fileTransfer.compressionEnabled)
+ return rfbSendFileTransferMessage(cl, rfbFilePacket, 0, 0, bytesRead, (char *)readBuf);
+ else
+ {
+#ifdef LIBVNCSERVER_HAVE_LIBZ
+ nRetC = compress(compBuf, &nMaxCompSize, readBuf, bytesRead);
+ /*
+ rfbLog("Compressed the packet from %d -> %d bytes\n", nMaxCompSize, bytesRead);
+ */
+
+ if ((nRetC==0) && (nMaxCompSize<bytesRead))
+ return rfbSendFileTransferMessage(cl, rfbFilePacket, 0, 1, nMaxCompSize, (char *)compBuf);
+ else
+ return rfbSendFileTransferMessage(cl, rfbFilePacket, 0, 0, bytesRead, (char *)readBuf);
+#else
+ /* We do not support compression of the data stream */
+ return rfbSendFileTransferMessage(cl, rfbFilePacket, 0, 0, bytesRead, (char *)readBuf);
+#endif
+ }
+ }
+ }
+ }
+ return TRUE;
+}
+
+rfbBool rfbProcessFileTransfer(rfbClientPtr cl, uint8_t contentType, uint8_t contentParam, uint32_t size, uint32_t length)
+{
+ char *buffer=NULL, *p=NULL;
+ int retval=0;
+ char filename1[MAX_PATH];
+ char filename2[MAX_PATH];
+ char szFileTime[MAX_PATH];
+ struct stat statbuf;
+ uint32_t sizeHtmp=0;
+ int n=0;
+ char timespec[64];
+#ifdef LIBVNCSERVER_HAVE_LIBZ
+ unsigned char compBuff[sz_rfbBlockSize];
+ unsigned long nRawBytes = sz_rfbBlockSize;
+ int nRet = 0;
+#endif
+
+ /*
+ rfbLog("rfbProcessFileTransfer(%dtype, %dparam, %dsize, %dlen)\n", contentType, contentParam, size, length);
+ */
+
+ switch (contentType) {
+ case rfbDirContentRequest:
+ switch (contentParam) {
+ case rfbRDrivesList: /* Client requests the List of Local Drives */
+ /*
+ rfbLog("rfbProcessFileTransfer() rfbDirContentRequest: rfbRDrivesList:\n");
+ */
+ /* Format when filled : "C:\<NULL>D:\<NULL>....Z:\<NULL><NULL>
+ *
+ * We replace the "\" char following the drive letter and ":"
+ * with a char corresponding to the type of drive
+ * We obtain something like "C:l<NULL>D:c<NULL>....Z:n\<NULL><NULL>"
+ * Isn't it ugly ?
+ * DRIVE_FIXED = 'l' (local?)
+ * DRIVE_REMOVABLE = 'f' (floppy?)
+ * DRIVE_CDROM = 'c'
+ * DRIVE_REMOTE = 'n'
+ */
+
+ /* in unix, there are no 'drives' (We could list mount points though)
+ * We fake the root as a "C:" for the Winblows users
+ */
+ filename2[0]='C';
+ filename2[1]=':';
+ filename2[2]='l';
+ filename2[3]=0;
+ filename2[4]=0;
+ retval = rfbSendFileTransferMessage(cl, rfbDirPacket, rfbADrivesList, 0, 5, filename2);
+ if (buffer!=NULL) free(buffer);
+ return retval;
+ break;
+ case rfbRDirContent: /* Client requests the content of a directory */
+ /*
+ rfbLog("rfbProcessFileTransfer() rfbDirContentRequest: rfbRDirContent\n");
+ */
+ if ((buffer = rfbProcessFileTransferReadBuffer(cl, length))==NULL) return FALSE;
+ retval = rfbSendDirContent(cl, length, buffer);
+ if (buffer!=NULL) free(buffer);
+ return retval;
+ }
+ break;
+
+ case rfbDirPacket:
+ rfbLog("rfbProcessFileTransfer() rfbDirPacket\n");
+ break;
+ case rfbFileAcceptHeader:
+ rfbLog("rfbProcessFileTransfer() rfbFileAcceptHeader\n");
+ break;
+ case rfbCommandReturn:
+ rfbLog("rfbProcessFileTransfer() rfbCommandReturn\n");
+ break;
+ case rfbFileChecksums:
+ /* Destination file already exists - the viewer sends the checksums */
+ rfbLog("rfbProcessFileTransfer() rfbFileChecksums\n");
+ break;
+ case rfbFileTransferAccess:
+ rfbLog("rfbProcessFileTransfer() rfbFileTransferAccess\n");
+ break;
+
+ /*
+ * sending from the server to the viewer
+ */
+
+ case rfbFileTransferRequest:
+ /*
+ rfbLog("rfbProcessFileTransfer() rfbFileTransferRequest:\n");
+ */
+ /* add some space to the end of the buffer as we will be adding a timespec to it */
+ if ((buffer = rfbProcessFileTransferReadBuffer(cl, length))==NULL) return FALSE;
+ /* The client requests a File */
+ rfbFilenameTranslate2UNIX(cl, buffer, filename1);
+ cl->fileTransfer.fd=open(filename1, O_RDONLY, 0744);
+
+ /*
+ rfbLog("rfbProcessFileTransfer() rfbFileTransferRequest(\"%s\"->\"%s\") Open: %s\n", buffer, filename1, (cl->fileTransfer.fd==-1?"Failed":"Success"));
+ */
+
+ if (cl->fileTransfer.fd!=-1) {
+ if (fstat(cl->fileTransfer.fd, &statbuf)!=0) {
+ close(cl->fileTransfer.fd);
+ cl->fileTransfer.fd=-1;
+ }
+ else
+ {
+ /* Add the File Time Stamp to the filename */
+ strftime(timespec, sizeof(timespec), "%m/%d/%Y %H:%M",gmtime(&statbuf.st_ctime));
+ buffer=realloc(buffer, length + strlen(timespec) + 2); /* comma, and Null term */
+ if (buffer==NULL) {
+ rfbLog("rfbProcessFileTransfer() rfbFileTransferRequest: Failed to malloc %d bytes\n", length + strlen(timespec) + 2);
+ return FALSE;
+ }
+ strcat(buffer,",");
+ strcat(buffer, timespec);
+ length = strlen(buffer);
+ }
+ }
+
+ /* The viewer supports compression if size==1 */
+ cl->fileTransfer.compressionEnabled = (size==1);
+
+ /*
+ rfbLog("rfbProcessFileTransfer() rfbFileTransferRequest(\"%s\"->\"%s\")%s\n", buffer, filename1, (size==1?" <Compression Enabled>":""));
+ */
+
+ /* File Size in bytes, 0xFFFFFFFF (-1) means error */
+ retval = rfbSendFileTransferMessage(cl, rfbFileHeader, 0, (cl->fileTransfer.fd==-1 ? -1 : statbuf.st_size), length, buffer);
+
+ if (cl->fileTransfer.fd==-1)
+ {
+ if (buffer!=NULL) free(buffer);
+ return retval;
+ }
+ /* setup filetransfer stuff */
+ cl->fileTransfer.fileSize = statbuf.st_size;
+ cl->fileTransfer.numPackets = statbuf.st_size / sz_rfbBlockSize;
+ cl->fileTransfer.receiving = 0;
+ cl->fileTransfer.sending = 0; /* set when we receive a rfbFileHeader: */
+
+ /* TODO: finish 64-bit file size support */
+ sizeHtmp = 0;
+ if (rfbWriteExact(cl, (char *)&sizeHtmp, 4) < 0) {
+ rfbLogPerror("rfbProcessFileTransfer: write");
+ rfbCloseClient(cl);
+ if (buffer!=NULL) free(buffer);
+ return FALSE;
+ }
+ break;
+
+ case rfbFileHeader:
+ /* Destination file (viewer side) is ready for reception (size > 0) or not (size = -1) */
+ if (size==-1) {
+ rfbLog("rfbProcessFileTransfer() rfbFileHeader (error, aborting)\n");
+ close(cl->fileTransfer.fd);
+ cl->fileTransfer.fd=-1;
+ return TRUE;
+ }
+
+ /*
+ rfbLog("rfbProcessFileTransfer() rfbFileHeader (%d bytes of a file)\n", size);
+ */
+
+ /* Starts the transfer! */
+ cl->fileTransfer.sending=1;
+ return rfbSendFileTransferChunk(cl);
+ break;
+
+
+ /*
+ * sending from the viewer to the server
+ */
+
+ case rfbFileTransferOffer:
+ /* client is sending a file to us */
+ /* buffer contains full path name (plus FileTime) */
+ /* size contains size of the file */
+ /*
+ rfbLog("rfbProcessFileTransfer() rfbFileTransferOffer:\n");
+ */
+ if ((buffer = rfbProcessFileTransferReadBuffer(cl, length))==NULL) return FALSE;
+
+ /* Parse the FileTime */
+ p = strrchr(buffer, ',');
+ if (p!=NULL) {
+ *p = '\0';
+ strcpy(szFileTime, p+1);
+ } else
+ szFileTime[0]=0;
+
+
+
+ /* Need to read in sizeHtmp */
+ if ((n = rfbReadExact(cl, (char *)&sizeHtmp, 4)) <= 0) {
+ if (n != 0)
+ rfbLogPerror("rfbProcessFileTransfer: read sizeHtmp");
+ rfbCloseClient(cl);
+ /* NOTE: don't forget to free(buffer) if you return early! */
+ if (buffer!=NULL) free(buffer);
+ return FALSE;
+ }
+ sizeHtmp = Swap32IfLE(sizeHtmp);
+
+ rfbFilenameTranslate2UNIX(cl, buffer, filename1);
+
+ /* If the file exists... We can send a rfbFileChecksums back to the client before we send an rfbFileAcceptHeader */
+ /* TODO: Delta Transfer */
+
+ cl->fileTransfer.fd=open(filename1, O_CREAT|O_WRONLY|O_TRUNC, 0744);
+ /*
+ rfbLog("rfbProcessFileTransfer() rfbFileTransferOffer(\"%s\"->\"%s\") %s %s\n", buffer, filename1, (cl->fileTransfer.fd==-1?"Failed":"Success"), (cl->fileTransfer.fd==-1?strerror(errno):""));
+ */
+
+ /* File Size in bytes, 0xFFFFFFFF (-1) means error */
+ retval = rfbSendFileTransferMessage(cl, rfbFileAcceptHeader, 0, (cl->fileTransfer.fd==-1 ? -1 : 0), length, buffer);
+ if (cl->fileTransfer.fd==-1) {
+ free(buffer);
+ return retval;
+ }
+
+ /* setup filetransfer stuff */
+ cl->fileTransfer.fileSize = size;
+ cl->fileTransfer.numPackets = size / sz_rfbBlockSize;
+ cl->fileTransfer.receiving = 1;
+ cl->fileTransfer.sending = 0;
+ break;
+
+ case rfbFilePacket:
+ /*
+ rfbLog("rfbProcessFileTransfer() rfbFilePacket:\n");
+ */
+ if ((buffer = rfbProcessFileTransferReadBuffer(cl, length))==NULL) return FALSE;
+ if (cl->fileTransfer.fd!=-1) {
+ /* buffer contains the contents of the file */
+ if (size==0)
+ retval=write(cl->fileTransfer.fd, buffer, length);
+ else
+ {
+#ifdef LIBVNCSERVER_HAVE_LIBZ
+ /* compressed packet */
+ nRet = uncompress(compBuff,&nRawBytes,(const unsigned char*)buffer, length);
+ retval=write(cl->fileTransfer.fd, compBuff, nRawBytes);
+#else
+ /* Write the file out as received... */
+ retval=write(cl->fileTransfer.fd, buffer, length);
+#endif
+ }
+ if (retval==-1)
+ {
+ close(cl->fileTransfer.fd);
+ cl->fileTransfer.fd=-1;
+ cl->fileTransfer.sending = 0;
+ cl->fileTransfer.receiving = 0;
+ }
+ }
+ break;
+
+ case rfbEndOfFile:
+ /*
+ rfbLog("rfbProcessFileTransfer() rfbEndOfFile\n");
+ */
+ if (cl->fileTransfer.fd!=-1)
+ close(cl->fileTransfer.fd);
+ cl->fileTransfer.fd=-1;
+ cl->fileTransfer.sending = 0;
+ cl->fileTransfer.receiving = 0;
+ break;
+
+ case rfbAbortFileTransfer:
+ /*
+ rfbLog("rfbProcessFileTransfer() rfbAbortFileTransfer\n");
+ */
+ if (cl->fileTransfer.fd!=-1)
+ {
+ close(cl->fileTransfer.fd);
+ cl->fileTransfer.fd=-1;
+ cl->fileTransfer.sending = 0;
+ cl->fileTransfer.receiving = 0;
+ }
+ else
+ {
+ /* We use this message for FileTransfer rights (<=RC18 versions)
+ * The client asks for FileTransfer permission
+ */
+ if (contentParam == 0)
+ {
+ rfbLog("rfbProcessFileTransfer() File Transfer Permission DENIED! (Client Version <=RC18)\n");
+ /* Old method for FileTransfer handshake perimssion (<=RC18) (Deny it)*/
+ return rfbSendFileTransferMessage(cl, rfbAbortFileTransfer, 0, -1, 0, "");
+ }
+ /* New method is allowed */
+ if (cl->screen->getFileTransferPermission!=NULL)
+ {
+ if (cl->screen->getFileTransferPermission(cl)==TRUE)
+ {
+ rfbLog("rfbProcessFileTransfer() File Transfer Permission Granted!\n");
+ return rfbSendFileTransferMessage(cl, rfbFileTransferAccess, 0, 1 , 0, ""); /* Permit */
+ }
+ else
+ {
+ rfbLog("rfbProcessFileTransfer() File Transfer Permission DENIED!\n");
+ return rfbSendFileTransferMessage(cl, rfbFileTransferAccess, 0, -1 , 0, ""); /* Deny */
+ }
+ }
+ rfbLog("rfbProcessFileTransfer() File Transfer Permission DENIED by default!\n");
+ return rfbSendFileTransferMessage(cl, rfbFileTransferAccess, 0, -1 , 0, ""); /* DEFAULT: DENY (for security) */
+ }
+ break;
+
+
+ case rfbCommand:
+ /*
+ rfbLog("rfbProcessFileTransfer() rfbCommand:\n");
+ */
+ if ((buffer = rfbProcessFileTransferReadBuffer(cl, length))==NULL) return FALSE;
+ switch (contentParam) {
+ case rfbCDirCreate: /* Client requests the creation of a directory */
+ rfbFilenameTranslate2UNIX(cl, buffer, filename1);
+ retval = mkdir(filename1, 0755);
+ /*
+ rfbLog("rfbProcessFileTransfer() rfbCommand: rfbCDirCreate(\"%s\"->\"%s\") %s\n", buffer, filename1, (retval==-1?"Failed":"Success"));
+ */
+ retval = rfbSendFileTransferMessage(cl, rfbCommandReturn, rfbADirCreate, retval, length, buffer);
+ if (buffer!=NULL) free(buffer);
+ return retval;
+ case rfbCFileDelete: /* Client requests the deletion of a file */
+ rfbFilenameTranslate2UNIX(cl, buffer, filename1);
+ if (stat(filename1,&statbuf)==0)
+ {
+ if (S_ISDIR(statbuf.st_mode))
+ retval = rmdir(filename1);
+ else
+ retval = unlink(filename1);
+ }
+ else retval=-1;
+ retval = rfbSendFileTransferMessage(cl, rfbCommandReturn, rfbAFileDelete, retval, length, buffer);
+ if (buffer!=NULL) free(buffer);
+ return retval;
+ case rfbCFileRename: /* Client requests the Renaming of a file/directory */
+ p = strrchr(buffer, '*');
+ if (p != NULL)
+ {
+ /* Split into 2 filenames ('*' is a seperator) */
+ *p = '\0';
+ rfbFilenameTranslate2UNIX(cl, buffer, filename1);
+ rfbFilenameTranslate2UNIX(cl, p+1, filename2);
+ retval = rename(filename1,filename2);
+ /*
+ rfbLog("rfbProcessFileTransfer() rfbCommand: rfbCFileRename(\"%s\"->\"%s\" -->> \"%s\"->\"%s\") %s\n", buffer, filename1, p+1, filename2, (retval==-1?"Failed":"Success"));
+ */
+ /* Restore the buffer so the reply is good */
+ *p = '*';
+ retval = rfbSendFileTransferMessage(cl, rfbCommandReturn, rfbAFileRename, retval, length, buffer);
+ if (buffer!=NULL) free(buffer);
+ return retval;
+ }
+ break;
+ }
+
+ break;
+ }
+
+ /* NOTE: don't forget to free(buffer) if you return early! */
+ if (buffer!=NULL) free(buffer);
+ return TRUE;
+}
+
+/*
* rfbProcessClientNormalMessage is called when the client has sent a normal
* protocol message.
*/
@@ -994,6 +1663,11 @@ rfbProcessClientNormalMessage(rfbClientPtr cl)
int n=0;
rfbClientToServerMsg msg;
char *str;
+ int i;
+ uint32_t enc=0;
+ uint32_t lastPreferredEncoding = -1;
+ char encBuf[64];
+ char encBuf2[64];
if ((n = rfbReadExact(cl, (char *)&msg, 1)) <= 0) {
if (n != 0)
@@ -1028,6 +1702,8 @@ rfbProcessClientNormalMessage(rfbClientPtr cl)
cl->readyForSetColourMapEntries = TRUE;
cl->screen->setTranslateFunction(cl);
+ rfbStatRecordMessageRcvd(cl, msg.type, sz_rfbSetPixelFormatMsg, sz_rfbSetPixelFormatMsg);
+
return;
@@ -1039,16 +1715,23 @@ rfbProcessClientNormalMessage(rfbClientPtr cl)
rfbCloseClient(cl);
return;
}
+ rfbStatRecordMessageRcvd(cl, msg.type, sz_rfbSetPixelFormatMsg, sz_rfbSetPixelFormatMsg);
rfbLog("rfbProcessClientNormalMessage: %s",
"FixColourMapEntries unsupported\n");
rfbCloseClient(cl);
return;
+ /* NOTE: Some clients send us a set of encodings (ie: PointerPos) designed to enable/disable features...
+ * We may want to look into this...
+ * Example:
+ * case rfbEncodingXCursor:
+ * cl->enableCursorShapeUpdates = TRUE;
+ *
+ * Currently: cl->enableCursorShapeUpdates can *never* be turned off...
+ */
case rfbSetEncodings:
{
- int i;
- uint32_t enc;
if ((n = rfbReadExact(cl, ((char *)&msg) + 1,
sz_rfbSetEncodingsMsg - 1)) <= 0) {
@@ -1060,6 +1743,31 @@ rfbProcessClientNormalMessage(rfbClientPtr cl)
msg.se.nEncodings = Swap16IfLE(msg.se.nEncodings);
+ rfbStatRecordMessageRcvd(cl, msg.type, sz_rfbSetEncodingsMsg+(msg.se.nEncodings*4),sz_rfbSetEncodingsMsg+(msg.se.nEncodings*4));
+
+ /*
+ * UltraVNC Client has the ability to adapt to changing network environments
+ * So, let's give it a change to tell us what it wants now!
+ */
+ if (cl->preferredEncoding!=-1)
+ lastPreferredEncoding = cl->preferredEncoding;
+
+ /* Reset all flags to defaults (allows us to switch between PointerPos and Server Drawn Cursors) */
+ cl->preferredEncoding=-1;
+ cl->useCopyRect = FALSE;
+ cl->useNewFBSize = FALSE;
+ cl->cursorWasChanged = FALSE;
+ cl->useRichCursorEncoding = FALSE;
+ cl->enableCursorPosUpdates = FALSE;
+ cl->enableCursorShapeUpdates = FALSE;
+ cl->enableCursorShapeUpdates = FALSE;
+ cl->enableLastRectEncoding = FALSE;
+ cl->enableKeyboardLedState = FALSE;
+ cl->enableSupportedMessages = FALSE;
+ cl->enableSupportedEncodings = FALSE;
+ cl->enableServerIdentity = FALSE;
+
+
for (i = 0; i < msg.se.nEncodings; i++) {
if ((n = rfbReadExact(cl, (char *)&enc, 4)) <= 0) {
if (n != 0)
@@ -1075,58 +1783,23 @@ rfbProcessClientNormalMessage(rfbClientPtr cl)
cl->useCopyRect = TRUE;
break;
case rfbEncodingRaw:
- if (cl->preferredEncoding == -1) {
- cl->preferredEncoding = enc;
- rfbLog("Using raw encoding for client %s\n",
- cl->host);
- }
- break;
case rfbEncodingRRE:
- if (cl->preferredEncoding == -1) {
- cl->preferredEncoding = enc;
- rfbLog("Using rre encoding for client %s\n",
- cl->host);
- }
- break;
case rfbEncodingCoRRE:
- if (cl->preferredEncoding == -1) {
- cl->preferredEncoding = enc;
- rfbLog("Using CoRRE encoding for client %s\n",
- cl->host);
- }
- break;
case rfbEncodingHextile:
- if (cl->preferredEncoding == -1) {
- cl->preferredEncoding = enc;
- rfbLog("Using hextile encoding for client %s\n",
- cl->host);
- }
- break;
case rfbEncodingUltra:
- if (cl->preferredEncoding == -1) {
- cl->preferredEncoding = enc;
- rfbLog("Using Ultra encoding for client %s\n",
- cl->host);
- }
- break;
#ifdef LIBVNCSERVER_HAVE_LIBZ
case rfbEncodingZlib:
- if (cl->preferredEncoding == -1) {
- cl->preferredEncoding = enc;
- rfbLog("Using zlib encoding for client %s\n",
- cl->host);
- }
- break;
+ case rfbEncodingZRLE:
#ifdef LIBVNCSERVER_HAVE_LIBJPEG
case rfbEncodingTight:
- if (cl->preferredEncoding == -1) {
- cl->preferredEncoding = enc;
- rfbLog("Using tight encoding for client %s\n",
- cl->host);
- }
- break;
#endif
#endif
+ /* The first supported encoding is the 'preferred' encoding */
+ if (cl->preferredEncoding == -1)
+ cl->preferredEncoding = enc;
+
+
+ break;
case rfbEncodingXCursor:
if(!cl->screen->dontConvertRichCursorToXCursor) {
rfbLog("Enabling X-style cursor updates for client %s\n",
@@ -1200,15 +1873,6 @@ rfbProcessClientNormalMessage(rfbClientPtr cl)
cl->enableServerIdentity = TRUE;
}
break;
-#ifdef LIBVNCSERVER_HAVE_LIBZ
- case rfbEncodingZRLE:
- if (cl->preferredEncoding == -1) {
- cl->preferredEncoding = enc;
- rfbLog("Using ZRLE encoding for client %s\n",
- cl->host);
- }
- break;
-#endif
default:
#ifdef LIBVNCSERVER_HAVE_LIBZ
if ( enc >= (uint32_t)rfbEncodingCompressLevel0 &&
@@ -1268,17 +1932,36 @@ rfbProcessClientNormalMessage(rfbClientPtr cl)
if(!handled)
rfbLog("rfbProcessClientNormalMessage: "
- "ignoring unknown encoding type %d\n",
- (int)enc);
+ "ignoring unsupported encoding type %s\n",
+ encodingName(enc,encBuf,sizeof(encBuf)));
}
}
}
}
+
+
if (cl->preferredEncoding == -1) {
- cl->preferredEncoding = rfbEncodingRaw;
+ if (lastPreferredEncoding==-1) {
+ cl->preferredEncoding = rfbEncodingRaw;
+ rfbLog("Defaulting to %s encoding for client %s\n", encodingName(cl->preferredEncoding,encBuf,sizeof(encBuf)),cl->host);
+ }
+ else {
+ cl->preferredEncoding = lastPreferredEncoding;
+ rfbLog("Sticking with %s encoding for client %s\n", encodingName(cl->preferredEncoding,encBuf,sizeof(encBuf)),cl->host);
+ }
}
-
+ else
+ {
+ if (lastPreferredEncoding==-1) {
+ rfbLog("Using %s encoding for client %s\n", encodingName(cl->preferredEncoding,encBuf,sizeof(encBuf)),cl->host);
+ } else {
+ rfbLog("Switching from %s to %s Encoding for client %s\n",
+ encodingName(lastPreferredEncoding,encBuf2,sizeof(encBuf2)),
+ encodingName(cl->preferredEncoding,encBuf,sizeof(encBuf)), cl->host);
+ }
+ }
+
if (cl->enableCursorPosUpdates && !cl->enableCursorShapeUpdates) {
rfbLog("Disabling cursor position updates for client %s\n",
cl->host);
@@ -1301,6 +1984,7 @@ rfbProcessClientNormalMessage(rfbClientPtr cl)
return;
}
+ rfbStatRecordMessageRcvd(cl, msg.type, sz_rfbFramebufferUpdateRequestMsg,sz_rfbFramebufferUpdateRequestMsg);
/* The values come in based on the scaled screen, we need to convert them to
* values based on the main screen's coordinate system
@@ -1347,8 +2031,6 @@ rfbProcessClientNormalMessage(rfbClientPtr cl)
case rfbKeyEvent:
- cl->keyEventsRcvd++;
-
if ((n = rfbReadExact(cl, ((char *)&msg) + 1,
sz_rfbKeyEventMsg - 1)) <= 0) {
if (n != 0)
@@ -1357,6 +2039,8 @@ rfbProcessClientNormalMessage(rfbClientPtr cl)
return;
}
+ rfbStatRecordMessageRcvd(cl, msg.type, sz_rfbKeyEventMsg, sz_rfbKeyEventMsg);
+
if(!cl->viewOnly) {
cl->screen->kbdAddEvent(msg.ke.down, (rfbKeySym)Swap32IfLE(msg.ke.key), cl);
}
@@ -1366,8 +2050,6 @@ rfbProcessClientNormalMessage(rfbClientPtr cl)
case rfbPointerEvent:
- cl->pointerEventsRcvd++;
-
if ((n = rfbReadExact(cl, ((char *)&msg) + 1,
sz_rfbPointerEventMsg - 1)) <= 0) {
if (n != 0)
@@ -1376,6 +2058,8 @@ rfbProcessClientNormalMessage(rfbClientPtr cl)
return;
}
+ rfbStatRecordMessageRcvd(cl, msg.type, sz_rfbPointerEventMsg, sz_rfbPointerEventMsg);
+
if (cl->screen->pointerClient && cl->screen->pointerClient != cl)
return;
@@ -1401,6 +2085,115 @@ rfbProcessClientNormalMessage(rfbClientPtr cl)
return;
+ case rfbFileTransfer:
+ if ((n = rfbReadExact(cl, ((char *)&msg) + 1,
+ sz_rfbFileTransferMsg - 1)) <= 0) {
+ if (n != 0)
+ rfbLogPerror("rfbProcessClientNormalMessage: read");
+ rfbCloseClient(cl);
+ return;
+ }
+ msg.ft.size = Swap32IfLE(msg.ft.size);
+ msg.ft.length = Swap32IfLE(msg.ft.length);
+ /* record statistics in rfbProcessFileTransfer as length is filled with garbage when it is not valid */
+ rfbProcessFileTransfer(cl, msg.ft.contentType, msg.ft.contentParam, msg.ft.size, msg.ft.length);
+ return;
+
+ case rfbSetSW:
+ if ((n = rfbReadExact(cl, ((char *)&msg) + 1,
+ sz_rfbSetSWMsg - 1)) <= 0) {
+ if (n != 0)
+ rfbLogPerror("rfbProcessClientNormalMessage: read");
+ rfbCloseClient(cl);
+ return;
+ }
+ msg.sw.x = Swap16IfLE(msg.sw.x);
+ msg.sw.y = Swap16IfLE(msg.sw.y);
+ rfbStatRecordMessageRcvd(cl, msg.type, sz_rfbSetSWMsg, sz_rfbSetSWMsg);
+ /* msg.sw.status is not initialized in the ultraVNC viewer and contains random numbers (why???) */
+
+ rfbLog("Received a rfbSetSingleWindow(%d x, %d y)\n", msg.sw.x, msg.sw.y);
+ if (cl->screen->setSingleWindow!=NULL)
+ cl->screen->setSingleWindow(cl, msg.sw.x, msg.sw.y);
+ return;
+
+ case rfbSetServerInput:
+ if ((n = rfbReadExact(cl, ((char *)&msg) + 1,
+ sz_rfbSetServerInputMsg - 1)) <= 0) {
+ if (n != 0)
+ rfbLogPerror("rfbProcessClientNormalMessage: read");
+ rfbCloseClient(cl);
+ return;
+ }
+ rfbStatRecordMessageRcvd(cl, msg.type, sz_rfbSetServerInputMsg, sz_rfbSetServerInputMsg);
+
+ /* msg.sim.pad is not initialized in the ultraVNC viewer and contains random numbers (why???) */
+ /* msg.sim.pad = Swap16IfLE(msg.sim.pad); */
+
+ rfbLog("Received a rfbSetServerInput(%d status)\n", msg.sim.status);
+ if (cl->screen->setServerInput!=NULL)
+ cl->screen->setServerInput(cl, msg.sim.status);
+ return;
+
+ case rfbTextChat:
+ if ((n = rfbReadExact(cl, ((char *)&msg) + 1,
+ sz_rfbTextChatMsg - 1)) <= 0) {
+ if (n != 0)
+ rfbLogPerror("rfbProcessClientNormalMessage: read");
+ rfbCloseClient(cl);
+ return;
+ }
+
+ msg.tc.pad2 = Swap16IfLE(msg.tc.pad2);
+ msg.tc.length = Swap32IfLE(msg.tc.length);
+
+ switch (msg.tc.length) {
+ case rfbTextChatOpen:
+ case rfbTextChatClose:
+ case rfbTextChatFinished:
+ /* commands do not have text following */
+ /* Why couldn't they have used the pad byte??? */
+ str=NULL;
+ rfbStatRecordMessageRcvd(cl, msg.type, sz_rfbTextChatMsg, sz_rfbTextChatMsg);
+ break;
+ default:
+ if ((msg.tc.length>0) && (msg.tc.length<rfbTextMaxSize))
+ {
+ str = (char *)malloc(msg.tc.length);
+ if (str==NULL)
+ {
+ rfbLog("Unable to malloc %d bytes for a TextChat Message\n", msg.tc.length);
+ rfbCloseClient(cl);
+ return;
+ }
+ if ((n = rfbReadExact(cl, str, msg.tc.length)) <= 0) {
+ if (n != 0)
+ rfbLogPerror("rfbProcessClientNormalMessage: read");
+ free(str);
+ rfbCloseClient(cl);
+ return;
+ }
+ rfbStatRecordMessageRcvd(cl, msg.type, sz_rfbTextChatMsg+msg.tc.length, sz_rfbTextChatMsg+msg.tc.length);
+ }
+ else
+ {
+ /* This should never happen */
+ rfbLog("client sent us a Text Message that is too big %d>%d\n", msg.tc.length, rfbTextMaxSize);
+ rfbCloseClient(cl);
+ return;
+ }
+ }
+
+ /* Note: length can be commands: rfbTextChatOpen, rfbTextChatClose, and rfbTextChatFinished
+ * at which point, the str is NULL (as it is not sent)
+ */
+ if (cl->screen->setTextChat!=NULL)
+ cl->screen->setTextChat(cl, msg.tc.length, str);
+
+ free(str);
+ return;
+
+
case rfbClientCutText:
if ((n = rfbReadExact(cl, ((char *)&msg) + 1,
@@ -1422,7 +2215,7 @@ rfbProcessClientNormalMessage(rfbClientPtr cl)
rfbCloseClient(cl);
return;
}
-
+ rfbStatRecordMessageRcvd(cl, msg.type, sz_rfbClientCutTextMsg+msg.cct.length, sz_rfbClientCutTextMsg+msg.cct.length);
if(!cl->viewOnly) {
cl->screen->setXCutText(str, msg.cct.length, cl);
}
@@ -1432,6 +2225,20 @@ rfbProcessClientNormalMessage(rfbClientPtr cl)
case rfbPalmVNCSetScaleFactor:
cl->PalmVNC = TRUE;
+ if ((n = rfbReadExact(cl, ((char *)&msg) + 1,
+ sz_rfbSetScaleMsg - 1)) <= 0) {
+ if (n != 0)
+ rfbLogPerror("rfbProcessClientNormalMessage: read");
+ rfbCloseClient(cl);
+ return;
+ }
+ rfbStatRecordMessageRcvd(cl, msg.type, sz_rfbSetScaleMsg, sz_rfbSetScaleMsg);
+ rfbLog("rfbSetScale(%d)\n", msg.ssc.scale);
+ rfbScalingSetup(cl,cl->screen->width/msg.ssc.scale, cl->screen->height/msg.ssc.scale);
+
+ rfbSendNewScaleSize(cl);
+ return;
+
case rfbSetScale:
if ((n = rfbReadExact(cl, ((char *)&msg) + 1,
@@ -1441,11 +2248,11 @@ rfbProcessClientNormalMessage(rfbClientPtr cl)
rfbCloseClient(cl);
return;
}
+ rfbStatRecordMessageRcvd(cl, msg.type, sz_rfbSetScaleMsg, sz_rfbSetScaleMsg);
rfbLog("rfbSetScale(%d)\n", msg.ssc.scale);
rfbScalingSetup(cl,cl->screen->width/msg.ssc.scale, cl->screen->height/msg.ssc.scale);
rfbSendNewScaleSize(cl);
-
return;
default:
@@ -1456,7 +2263,10 @@ rfbProcessClientNormalMessage(rfbClientPtr cl)
next = e->next;
if(e->extension->handleMessage &&
e->extension->handleMessage(cl, e->data, &msg))
+ {
+ rfbStatRecordMessageRcvd(cl, msg.type, 0, 0); /* Extension should handle this */
return;
+ }
e = next;
}
@@ -1508,7 +2318,6 @@ rfbSendFramebufferUpdate(rfbClientPtr cl,
LOCK(cl->updateMutex);
cl->newFBSizePending = FALSE;
UNLOCK(cl->updateMutex);
- cl->framebufferUpdateMessagesSent++;
fu->type = rfbFramebufferUpdate;
fu->nRects = Swap16IfLE(1);
cl->ublen = sz_rfbFramebufferUpdateMsg;
@@ -1690,11 +2499,11 @@ rfbSendFramebufferUpdate(rfbClientPtr cl,
rfbShowCursor(cl);
}
- /*
+ /*
* Now send the update.
*/
- cl->framebufferUpdateMessagesSent++;
-
+
+ rfbStatRecordMessageSent(cl, rfbFramebufferUpdate, 0, 0);
if (cl->preferredEncoding == rfbEncodingCoRRE) {
nUpdateRegionRects = 0;
@@ -1843,9 +2652,6 @@ rfbSendFramebufferUpdate(rfbClientPtr cl,
if (cl->screen!=cl->scaledScreen)
rfbScaledCorrection(cl->screen, cl->scaledScreen, &x, &y, &w, &h, "rfbSendFramebufferUpdate");
- cl->rawBytesEquivalent += (sz_rfbFramebufferUpdateRectHeader
- + w * (cl->format.bitsPerPixel / 8) * h);
-
switch (cl->preferredEncoding) {
case -1:
case rfbEncodingRaw:
@@ -1961,10 +2767,8 @@ rfbSendCopyRegion(rfbClientPtr cl,
memcpy(&cl->updateBuf[cl->ublen], (char *)&cr, sz_rfbCopyRect);
cl->ublen += sz_rfbCopyRect;
- cl->rectanglesSent[rfbEncodingCopyRect]++;
- cl->bytesSent[rfbEncodingCopyRect]
- += sz_rfbFramebufferUpdateRectHeader + sz_rfbCopyRect;
-
+ rfbStatRecordEncodingSent(cl, rfbEncodingCopyRect, sz_rfbFramebufferUpdateRectHeader + sz_rfbCopyRect,
+ w * h * (cl->scaledScreen->bitsPerPixel / 8));
}
sraRgnReleaseIterator(i);
@@ -2003,9 +2807,9 @@ rfbSendRectEncodingRaw(rfbClientPtr cl,
memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,sz_rfbFramebufferUpdateRectHeader);
cl->ublen += sz_rfbFramebufferUpdateRectHeader;
- cl->rectanglesSent[rfbEncodingRaw]++;
- cl->bytesSent[rfbEncodingRaw]
- += sz_rfbFramebufferUpdateRectHeader + bytesPerLine * h;
+
+ rfbStatRecordEncodingSent(cl, rfbEncodingRaw, sz_rfbFramebufferUpdateRectHeader + bytesPerLine * h,
+ sz_rfbFramebufferUpdateRectHeader + bytesPerLine * h);
nlines = (UPDATE_BUF_SIZE - cl->ublen) / bytesPerLine;
@@ -2069,8 +2873,8 @@ rfbSendLastRectMarker(rfbClientPtr cl)
memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,sz_rfbFramebufferUpdateRectHeader);
cl->ublen += sz_rfbFramebufferUpdateRectHeader;
- cl->lastRectMarkersSent++;
- cl->lastRectBytesSent += sz_rfbFramebufferUpdateRectHeader;
+
+ rfbStatRecordEncodingSent(cl, rfbEncodingLastRect, sz_rfbFramebufferUpdateRectHeader, sz_rfbFramebufferUpdateRectHeader);
return TRUE;
}
@@ -2108,8 +2912,7 @@ rfbSendNewFBSize(rfbClientPtr cl,
sz_rfbFramebufferUpdateRectHeader);
cl->ublen += sz_rfbFramebufferUpdateRectHeader;
- cl->lastRectMarkersSent++;
- cl->lastRectBytesSent += sz_rfbFramebufferUpdateRectHeader;
+ rfbStatRecordEncodingSent(cl, rfbEncodingNewFBSize, sz_rfbFramebufferUpdateRectHeader, sz_rfbFramebufferUpdateRectHeader);
return TRUE;
}
@@ -2181,6 +2984,8 @@ rfbSendSetColourMapEntries(rfbClientPtr cl,
rfbCloseClient(cl);
return FALSE;
}
+
+ rfbStatRecordMessageSent(cl, rfbSetColourMapEntries, len, len);
return TRUE;
}
@@ -2203,6 +3008,7 @@ rfbSendBell(rfbScreenInfoPtr rfbScreen)
rfbCloseClient(cl);
}
}
+ rfbStatRecordMessageSent(cl, rfbBell, sz_rfbBellMsg, sz_rfbBellMsg);
rfbReleaseClientIterator(i);
}
@@ -2232,6 +3038,7 @@ rfbSendServerCutText(rfbScreenInfoPtr rfbScreen,char *str, int len)
rfbLogPerror("rfbSendServerCutText: write");
rfbCloseClient(cl);
}
+ rfbStatRecordMessageSent(cl, rfbServerCutText, sz_rfbServerCutTextMsg+len, sz_rfbServerCutTextMsg+len);
}
rfbReleaseClientIterator(iterator);
}
diff --git a/libvncserver/rre.c b/libvncserver/rre.c
index 8ef91fd..c0759aa 100755
--- a/libvncserver/rre.c
+++ b/libvncserver/rre.c
@@ -40,7 +40,7 @@ static char *rreBeforeBuf = NULL;
static int rreAfterBufSize = 0;
static char *rreAfterBuf = NULL;
-static int rreAfterBufLen;
+static int rreAfterBufLen=0;
static int subrectEncode8(uint8_t *data, int w, int h);
static int subrectEncode16(uint16_t *data, int w, int h);
@@ -112,9 +112,9 @@ rfbSendRectEncodingRRE(rfbClientPtr cl,
return rfbSendRectEncodingRaw(cl, x, y, w, h);
}
- cl->rectanglesSent[rfbEncodingRRE]++;
- cl->bytesSent[rfbEncodingRRE] += (sz_rfbFramebufferUpdateRectHeader
- + sz_rfbRREHeader + rreAfterBufLen);
+ rfbStatRecordEncodingSent(cl, rfbEncodingRRE,
+ sz_rfbFramebufferUpdateRectHeader + sz_rfbRREHeader + rreAfterBufLen,
+ sz_rfbFramebufferUpdateRectHeader + w * h * (cl->format.bitsPerPixel / 8));
if (cl->ublen + sz_rfbFramebufferUpdateRectHeader + sz_rfbRREHeader
> UPDATE_BUF_SIZE)
diff --git a/libvncserver/scale.c b/libvncserver/scale.c
index 63d232e..67de35f 100644
--- a/libvncserver/scale.c
+++ b/libvncserver/scale.c
@@ -128,8 +128,8 @@ void rfbScaledCorrection(rfbScreenInfoPtr from, rfbScreenInfoPtr to, int *x, int
*h = (int)h2;
/* Small changes for a thumbnail may be scaled to zero */
- if (*w==0) *w++;
- if (*h==0) *h++;
+ if (*w==0) (*w)++;
+ if (*h==0) (*h)++;
/* scaling from small to big may overstep the size a bit */
if (*x+*w > to->width) *w=to->width - *x;
if (*y+*h > to->height) *h=to->height - *y;
@@ -212,7 +212,9 @@ void rfbScaledScreenUpdateRect(rfbScreenInfoPtr screen, rfbScreenInfoPtr ptr, in
pixel_value += (srcptr2[z] << (8 * z));
break;
}
- //srcptr2 += bytesPerPixel;
+ /*
+ srcptr2 += bytesPerPixel;
+ */
red += ((pixel_value >> redShift) & redMax);
green += ((pixel_value >> greenShift) & greenMax);
diff --git a/libvncserver/sockets.c b/libvncserver/sockets.c
index 181862d..0d04f0a 100755
--- a/libvncserver/sockets.c
+++ b/libvncserver/sockets.c
@@ -239,8 +239,18 @@ rfbCheckFds(rfbScreenInfoPtr rfbScreen,long usec)
tv.tv_usec = usec;
nfds = select(rfbScreen->maxFd + 1, &fds, NULL, NULL /* &fds */, &tv);
if (nfds == 0) {
+ /* timed out, check for async events */
+ i = rfbGetClientIterator(rfbScreen);
+ while((cl = rfbClientIteratorNext(i))) {
+ if (cl->onHold)
+ continue;
+ if (FD_ISSET(cl->sock, &(rfbScreen->allFds)))
+ rfbSendFileTransferChunk(cl);
+ }
+ rfbReleaseClientIterator(i);
return result;
}
+
if (nfds < 0) {
#ifdef WIN32
errno = WSAGetLastError();
@@ -332,11 +342,17 @@ rfbCheckFds(rfbScreenInfoPtr rfbScreen,long usec)
i = rfbGetClientIterator(rfbScreen);
while((cl = rfbClientIteratorNext(i))) {
+
if (cl->onHold)
continue;
- if (FD_ISSET(cl->sock, &fds) &&
- FD_ISSET(cl->sock, &(rfbScreen->allFds)))
- rfbProcessClientMessage(cl);
+
+ if (FD_ISSET(cl->sock, &(rfbScreen->allFds)))
+ {
+ if (FD_ISSET(cl->sock, &fds))
+ rfbProcessClientMessage(cl);
+ else
+ rfbSendFileTransferChunk(cl);
+ }
}
rfbReleaseClientIterator(i);
} while(rfbScreen->handleEventsEagerly);
diff --git a/libvncserver/stats.c b/libvncserver/stats.c
index ed9a3d0..0f8758f 100755
--- a/libvncserver/stats.c
+++ b/libvncserver/stats.c
@@ -26,90 +26,434 @@
#include <rfb/rfb.h>
-static const char* encNames[] = {
- "raw", "copyRect", "RRE", "[encoding 3]", "CoRRE", "hextile",
- "zlib", "tight", "[encoding 8]", "ultra", "[encoding 10]",
- "[encoding 11]", "[encoding 12]", "[encoding 13]", "[encoding 14]",
- "[encoding 15]",
- "ZRLE", "[encoding 17]", "[encoding 18]", "[encoding 19]", "[encoding 20]"
-};
+char *messageNameServer2Client(uint32_t type, char *buf, int len);
+char *messageNameClient2Server(uint32_t type, char *buf, int len);
+char *encodingName(uint32_t enc, char *buf, int len);
+rfbStatList *rfbStatLookupEncoding(rfbClientPtr cl, uint32_t type);
+rfbStatList *rfbStatLookupMessage(rfbClientPtr cl, uint32_t type);
-void
-rfbResetStats(rfbClientPtr cl)
+void rfbStatRecordEncodingSent(rfbClientPtr cl, uint32_t type, int byteCount, int byteIfRaw);
+void rfbStatRecordEncodingRcvd(rfbClientPtr cl, uint32_t type, int byteCount, int byteIfRaw);
+void rfbStatRecordMessageSent(rfbClientPtr cl, uint32_t type, int byteCount, int byteIfRaw);
+void rfbStatRecordMessageRcvd(rfbClientPtr cl, uint32_t type, int byteCount, int byteIfRaw);
+void rfbResetStats(rfbClientPtr cl);
+void rfbPrintStats(rfbClientPtr cl);
+
+
+
+
+char *messageNameServer2Client(uint32_t type, char *buf, int len) {
+ if (buf==NULL) return "error";
+ switch (type) {
+ case rfbFramebufferUpdate: snprintf(buf, len, "FramebufferUpdate"); break;
+ case rfbSetColourMapEntries: snprintf(buf, len, "SetColourMapEntries"); break;
+ case rfbBell: snprintf(buf, len, "Bell"); break;
+ case rfbServerCutText: snprintf(buf, len, "ServerCutText"); break;
+ case rfbResizeFrameBuffer: snprintf(buf, len, "ResizeFrameBuffer"); break;
+ case rfbKeyFrameUpdate: snprintf(buf, len, "KeyFrameUpdate"); break;
+ case rfbFileTransfer: snprintf(buf, len, "FileTransfer"); break;
+ case rfbTextChat: snprintf(buf, len, "TextChat"); break;
+ case rfbPalmVNCReSizeFrameBuffer: snprintf(buf, len, "PalmVNCReSize"); break;
+ default:
+ snprintf(buf, len, "server2client(0x%04X)", type);
+ }
+ return buf;
+}
+
+char *messageNameClient2Server(uint32_t type, char *buf, int len) {
+ if (buf==NULL) return "error";
+ switch (type) {
+ case rfbSetPixelFormat: snprintf(buf, len, "SetPixelFormat"); break;
+ case rfbFixColourMapEntries: snprintf(buf, len, "FixColourMapEntries"); break;
+ case rfbSetEncodings: snprintf(buf, len, "SetEncodings"); break;
+ case rfbFramebufferUpdateRequest: snprintf(buf, len, "FramebufferUpdate"); break;
+ case rfbKeyEvent: snprintf(buf, len, "KeyEvent"); break;
+ case rfbPointerEvent: snprintf(buf, len, "PointerEvent"); break;
+ case rfbClientCutText: snprintf(buf, len, "ClientCutText"); break;
+ case rfbFileTransfer: snprintf(buf, len, "FileTransfer"); break;
+ case rfbSetScale: snprintf(buf, len, "SetScale"); break;
+ case rfbSetServerInput: snprintf(buf, len, "SetServerInput"); break;
+ case rfbSetSW: snprintf(buf, len, "SetSingleWindow"); break;
+ case rfbTextChat: snprintf(buf, len, "TextChat"); break;
+ case rfbKeyFrameRequest: snprintf(buf, len, "KeyFrameRequest"); break;
+ case rfbPalmVNCSetScaleFactor: snprintf(buf, len, "PalmVNCSetScale"); break;
+ default:
+ snprintf(buf, len, "client2server(0x%04X)", type);
+
+
+ }
+ return buf;
+}
+
+char *encodingName(uint32_t type, char *buf, int len) {
+ if (buf==NULL) return "error";
+
+ switch (type) {
+ case rfbEncodingRaw: snprintf(buf, len, "raw"); break;
+ case rfbEncodingCopyRect: snprintf(buf, len, "copyRect"); break;
+ case rfbEncodingRRE: snprintf(buf, len, "RRE"); break;
+ case rfbEncodingCoRRE: snprintf(buf, len, "CoRRE"); break;
+ case rfbEncodingHextile: snprintf(buf, len, "hextile"); break;
+ case rfbEncodingZlib: snprintf(buf, len, "zlib"); break;
+ case rfbEncodingTight: snprintf(buf, len, "tight"); break;
+ case rfbEncodingZlibHex: snprintf(buf, len, "zlibhex"); break;
+ case rfbEncodingUltra: snprintf(buf, len, "ultra"); break;
+ case rfbEncodingZRLE: snprintf(buf, len, "ZRLE"); break;
+ case rfbEncodingCache: snprintf(buf, len, "cache"); break;
+ case rfbEncodingCacheEnable: snprintf(buf, len, "cacheEnable"); break;
+ case rfbEncodingXOR_Zlib: snprintf(buf, len, "xorZlib"); break;
+ case rfbEncodingXORMonoColor_Zlib: snprintf(buf, len, "xorMonoZlib"); break;
+ case rfbEncodingXORMultiColor_Zlib: snprintf(buf, len, "xorColorZlib"); break;
+ case rfbEncodingSolidColor: snprintf(buf, len, "solidColor"); break;
+ case rfbEncodingXOREnable: snprintf(buf, len, "xorEnable"); break;
+ case rfbEncodingCacheZip: snprintf(buf, len, "cacheZip"); break;
+ case rfbEncodingSolMonoZip: snprintf(buf, len, "monoZip"); break;
+ case rfbEncodingUltraZip: snprintf(buf, len, "ultraZip"); break;
+
+ case rfbEncodingXCursor: snprintf(buf, len, "Xcursor"); break;
+ case rfbEncodingRichCursor: snprintf(buf, len, "RichCursor"); break;
+ case rfbEncodingPointerPos: snprintf(buf, len, "PointerPos"); break;
+
+ case rfbEncodingLastRect: snprintf(buf, len, "LastRect"); break;
+ case rfbEncodingNewFBSize: snprintf(buf, len, "NewFBSize"); break;
+ case rfbEncodingKeyboardLedState: snprintf(buf, len, "LedState"); break;
+ case rfbEncodingSupportedMessages: snprintf(buf, len, "SupportedMessages"); break;
+ case rfbEncodingSupportedEncodings: snprintf(buf, len, "SupportedEncodings"); break;
+ case rfbEncodingServerIdentity: snprintf(buf, len, "ServerIdentity"); break;
+
+ case rfbEncodingCompressLevel0: snprintf(buf, len, "CompressLevel0"); break;
+ case rfbEncodingCompressLevel1: snprintf(buf, len, "CompressLevel1"); break;
+ case rfbEncodingCompressLevel2: snprintf(buf, len, "CompressLevel2"); break;
+ case rfbEncodingCompressLevel3: snprintf(buf, len, "CompressLevel3"); break;
+ case rfbEncodingCompressLevel4: snprintf(buf, len, "CompressLevel4"); break;
+ case rfbEncodingCompressLevel5: snprintf(buf, len, "CompressLevel5"); break;
+ case rfbEncodingCompressLevel6: snprintf(buf, len, "CompressLevel6"); break;
+ case rfbEncodingCompressLevel7: snprintf(buf, len, "CompressLevel7"); break;
+ case rfbEncodingCompressLevel8: snprintf(buf, len, "CompressLevel8"); break;
+ case rfbEncodingCompressLevel9: snprintf(buf, len, "CompressLevel9"); break;
+
+ case rfbEncodingQualityLevel0: snprintf(buf, len, "QualityLevel0"); break;
+ case rfbEncodingQualityLevel1: snprintf(buf, len, "QualityLevel1"); break;
+ case rfbEncodingQualityLevel2: snprintf(buf, len, "QualityLevel2"); break;
+ case rfbEncodingQualityLevel3: snprintf(buf, len, "QualityLevel3"); break;
+ case rfbEncodingQualityLevel4: snprintf(buf, len, "QualityLevel4"); break;
+ case rfbEncodingQualityLevel5: snprintf(buf, len, "QualityLevel5"); break;
+ case rfbEncodingQualityLevel6: snprintf(buf, len, "QualityLevel6"); break;
+ case rfbEncodingQualityLevel7: snprintf(buf, len, "QualityLevel7"); break;
+ case rfbEncodingQualityLevel8: snprintf(buf, len, "QualityLevel8"); break;
+ case rfbEncodingQualityLevel9: snprintf(buf, len, "QualityLevel9"); break;
+
+
+ default:
+ snprintf(buf, len, "encoding(0x%04X)", type);
+ }
+
+ return buf;
+}
+
+
+
+
+
+rfbStatList *rfbStatLookupEncoding(rfbClientPtr cl, uint32_t type)
{
- int i;
- for (i = 0; i < MAX_ENCODINGS; i++) {
- cl->bytesSent[i] = 0;
- cl->rectanglesSent[i] = 0;
+ rfbStatList *ptr;
+ if (cl==NULL) return NULL;
+ for (ptr = cl->statEncList; ptr!=NULL; ptr=ptr->Next)
+ {
+ if (ptr->type==type) return ptr;
+ }
+ /* Well, we are here... need to *CREATE* an entry */
+ ptr = (rfbStatList *)malloc(sizeof(rfbStatList));
+ if (ptr!=NULL)
+ {
+ memset((char *)ptr, 0, sizeof(rfbStatList));
+ ptr->type = type;
+ /* add to the top of the list */
+ ptr->Next = cl->statEncList;
+ cl->statEncList = ptr;
}
- cl->lastRectMarkersSent = 0;
- cl->lastRectBytesSent = 0;
- cl->cursorShapeBytesSent = 0;
- cl->cursorShapeUpdatesSent = 0;
- cl->cursorPosBytesSent = 0;
- cl->cursorPosUpdatesSent = 0;
- cl->framebufferUpdateMessagesSent = 0;
- cl->rawBytesEquivalent = 0;
- cl->keyEventsRcvd = 0;
- cl->pointerEventsRcvd = 0;
+ return ptr;
}
-void
-rfbPrintStats(rfbClientPtr cl)
+
+rfbStatList *rfbStatLookupMessage(rfbClientPtr cl, uint32_t type)
{
- int i;
- int totalRectanglesSent = 0;
- int totalBytesSent = 0;
+ rfbStatList *ptr;
+ if (cl==NULL) return NULL;
+ for (ptr = cl->statMsgList; ptr!=NULL; ptr=ptr->Next)
+ {
+ if (ptr->type==type) return ptr;
+ }
+ /* Well, we are here... need to *CREATE* an entry */
+ ptr = (rfbStatList *)malloc(sizeof(rfbStatList));
+ if (ptr!=NULL)
+ {
+ memset((char *)ptr, 0, sizeof(rfbStatList));
+ ptr->type = type;
+ /* add to the top of the list */
+ ptr->Next = cl->statMsgList;
+ cl->statMsgList = ptr;
+ }
+ return ptr;
+}
- rfbLog("Statistics:\n");
+void rfbStatRecordEncodingSentAdd(rfbClientPtr cl, uint32_t type, int byteCount) /* Specifically for tight encoding */
+{
+ rfbStatList *ptr;
- if ((cl->keyEventsRcvd != 0) || (cl->pointerEventsRcvd != 0))
- rfbLog(" key events received %d, pointer events %d\n",
- cl->keyEventsRcvd, cl->pointerEventsRcvd);
+ ptr = rfbStatLookupEncoding(cl, type);
+ if (ptr!=NULL)
+ ptr->bytesSent += byteCount;
+}
- for (i = 0; i < MAX_ENCODINGS; i++) {
- totalRectanglesSent += cl->rectanglesSent[i];
- totalBytesSent += cl->bytesSent[i];
+
+void rfbStatRecordEncodingSent(rfbClientPtr cl, uint32_t type, int byteCount, int byteIfRaw)
+{
+ rfbStatList *ptr;
+
+ ptr = rfbStatLookupEncoding(cl, type);
+ if (ptr!=NULL)
+ {
+ ptr->sentCount++;
+ ptr->bytesSent += byteCount;
+ ptr->bytesSentIfRaw += byteIfRaw;
}
+}
- totalRectanglesSent += (cl->cursorShapeUpdatesSent +
- cl->cursorPosUpdatesSent +
- cl->lastRectMarkersSent);
- totalBytesSent += (cl->cursorShapeBytesSent +
- cl->cursorPosBytesSent +
- cl->lastRectBytesSent);
+void rfbStatRecordEncodingRcvd(rfbClientPtr cl, uint32_t type, int byteCount, int byteIfRaw)
+{
+ rfbStatList *ptr;
- rfbLog(" framebuffer updates %d, rectangles %d, bytes %d\n",
- cl->framebufferUpdateMessagesSent, totalRectanglesSent,
- totalBytesSent);
+ ptr = rfbStatLookupEncoding(cl, type);
+ if (ptr!=NULL)
+ {
+ ptr->rcvdCount++;
+ ptr->bytesRcvd += byteCount;
+ ptr->bytesRcvdIfRaw += byteIfRaw;
+ }
+}
- if (cl->lastRectMarkersSent != 0)
- rfbLog(" LastRect and NewFBSize markers %d, bytes %d\n",
- cl->lastRectMarkersSent, cl->lastRectBytesSent);
+void rfbStatRecordMessageSent(rfbClientPtr cl, uint32_t type, int byteCount, int byteIfRaw)
+{
+ rfbStatList *ptr;
- if (cl->cursorShapeUpdatesSent != 0)
- rfbLog(" cursor shape updates %d, bytes %d\n",
- cl->cursorShapeUpdatesSent, cl->cursorShapeBytesSent);
+ ptr = rfbStatLookupMessage(cl, type);
+ if (ptr!=NULL)
+ {
+ ptr->sentCount++;
+ ptr->bytesSent += byteCount;
+ ptr->bytesSentIfRaw += byteIfRaw;
+ }
+}
- if (cl->cursorPosUpdatesSent != 0)
- rfbLog(" cursor position updates %d, bytes %d\n",
- cl->cursorPosUpdatesSent, cl->cursorPosBytesSent);
+void rfbStatRecordMessageRcvd(rfbClientPtr cl, uint32_t type, int byteCount, int byteIfRaw)
+{
+ rfbStatList *ptr;
- for (i = 0; i < MAX_ENCODINGS; i++) {
- if (cl->rectanglesSent[i] != 0)
- rfbLog(" %s rectangles %d, bytes %d\n",
- encNames[i], cl->rectanglesSent[i], cl->bytesSent[i]);
+ ptr = rfbStatLookupMessage(cl, type);
+ if (ptr!=NULL)
+ {
+ ptr->rcvdCount++;
+ ptr->bytesRcvd += byteCount;
+ ptr->bytesRcvdIfRaw += byteIfRaw;
}
+}
+
+
+int rfbStatGetSentBytes(rfbClientPtr cl)
+{
+ rfbStatList *ptr=NULL;
+ int bytes=0;
+ if (cl==NULL) return 0;
+ for (ptr = cl->statMsgList; ptr!=NULL; ptr=ptr->Next)
+ bytes += ptr->bytesSent;
+ for (ptr = cl->statEncList; ptr!=NULL; ptr=ptr->Next)
+ bytes += ptr->bytesSent;
+ return bytes;
+}
+
+int rfbStatGetSentBytesIfRaw(rfbClientPtr cl)
+{
+ rfbStatList *ptr=NULL;
+ int bytes=0;
+ if (cl==NULL) return 0;
+ for (ptr = cl->statMsgList; ptr!=NULL; ptr=ptr->Next)
+ bytes += ptr->bytesSentIfRaw;
+ for (ptr = cl->statEncList; ptr!=NULL; ptr=ptr->Next)
+ bytes += ptr->bytesSentIfRaw;
+ return bytes;
+}
+
+int rfbStatGetRcvdBytes(rfbClientPtr cl)
+{
+ rfbStatList *ptr=NULL;
+ int bytes=0;
+ if (cl==NULL) return 0;
+ for (ptr = cl->statMsgList; ptr!=NULL; ptr=ptr->Next)
+ bytes += ptr->bytesRcvd;
+ for (ptr = cl->statEncList; ptr!=NULL; ptr=ptr->Next)
+ bytes += ptr->bytesRcvd;
+ return bytes;
+}
+
+int rfbStatGetRcvdBytesIfRaw(rfbClientPtr cl)
+{
+ rfbStatList *ptr=NULL;
+ int bytes=0;
+ if (cl==NULL) return 0;
+ for (ptr = cl->statMsgList; ptr!=NULL; ptr=ptr->Next)
+ bytes += ptr->bytesRcvdIfRaw;
+ for (ptr = cl->statEncList; ptr!=NULL; ptr=ptr->Next)
+ bytes += ptr->bytesRcvdIfRaw;
+ return bytes;
+}
+
+int rfbStatGetMessageCountSent(rfbClientPtr cl, uint32_t type)
+{
+ rfbStatList *ptr=NULL;
+ if (cl==NULL) return 0;
+ for (ptr = cl->statMsgList; ptr!=NULL; ptr=ptr->Next)
+ if (ptr->type==type) return ptr->sentCount;
+ return 0;
+}
+int rfbStatGetMessageCountRcvd(rfbClientPtr cl, uint32_t type)
+{
+ rfbStatList *ptr=NULL;
+ if (cl==NULL) return 0;
+ for (ptr = cl->statMsgList; ptr!=NULL; ptr=ptr->Next)
+ if (ptr->type==type) return ptr->rcvdCount;
+ return 0;
+}
+
+int rfbStatGetEncodingCountSent(rfbClientPtr cl, uint32_t type)
+{
+ rfbStatList *ptr=NULL;
+ if (cl==NULL) return 0;
+ for (ptr = cl->statEncList; ptr!=NULL; ptr=ptr->Next)
+ if (ptr->type==type) return ptr->sentCount;
+ return 0;
+}
+int rfbStatGetEncodingCountRcvd(rfbClientPtr cl, uint32_t type)
+{
+ rfbStatList *ptr=NULL;
+ if (cl==NULL) return 0;
+ for (ptr = cl->statEncList; ptr!=NULL; ptr=ptr->Next)
+ if (ptr->type==type) return ptr->rcvdCount;
+ return 0;
+}
+
+
- if ((totalBytesSent - cl->bytesSent[rfbEncodingCopyRect]) != 0) {
- rfbLog(" raw bytes equivalent %d, compression ratio %f\n",
- cl->rawBytesEquivalent,
- (double)cl->rawBytesEquivalent
- / (double)(totalBytesSent
- - cl->bytesSent[rfbEncodingCopyRect]-
- cl->cursorShapeBytesSent -
- cl->cursorPosBytesSent -
- cl->lastRectBytesSent));
+
+void rfbResetStats(rfbClientPtr cl)
+{
+ rfbStatList *ptr;
+ if (cl==NULL) return;
+ while (cl->statEncList!=NULL)
+ {
+ ptr = cl->statEncList;
+ cl->statEncList = ptr->Next;
+ free(ptr);
+ }
+ while (cl->statMsgList!=NULL)
+ {
+ ptr = cl->statMsgList;
+ cl->statMsgList = ptr->Next;
+ free(ptr);
}
}
+
+
+void rfbPrintStats(rfbClientPtr cl)
+{
+ rfbStatList *ptr=NULL;
+ char encBuf[64];
+ double savings=0.0;
+ int totalRectsSent=0;
+ double totalBytesSent=0.0;
+ double totalBytesIfRawSent=0.0;
+ int totalRectsRcvd=0;
+ double totalBytesRcvd=0.0;
+ double totalBytesIfRawRcvd=0.0;
+
+ char *name=NULL;
+ int bytes=0;
+ int count=0;
+
+ if (cl==NULL) return;
+
+ rfbLog("Statistics: Transmit\n");
+ for (ptr = cl->statMsgList; ptr!=NULL; ptr=ptr->Next)
+ {
+ name = messageNameServer2Client(ptr->type, encBuf, sizeof(encBuf));
+ count = ptr->sentCount;
+ bytes = ptr->bytesSent;
+ savings = 0.0;
+ if (ptr->bytesSentIfRaw>0.0)
+ savings = 100.0 - (((double)ptr->bytesSent / (double)ptr->bytesSentIfRaw) * 100.0);
+ if ((bytes>0) || (count>0))
+ rfbLog(" %-24.24s: %6d events %9d/%9d bytes (%5.2f%% saved)\n",
+ name, count, bytes, ptr->bytesSentIfRaw, savings);
+ totalRectsSent += count;
+ totalBytesSent += bytes;
+ totalBytesIfRawSent += ptr->bytesSentIfRaw;
+ }
+ for (ptr = cl->statEncList; ptr!=NULL; ptr=ptr->Next)
+ {
+ name = encodingName(ptr->type, encBuf, sizeof(encBuf));
+ count = ptr->sentCount;
+ bytes = ptr->bytesSent;
+ savings = 0.0;
+ if (ptr->bytesSentIfRaw>0.0)
+ savings = 100.0 - (((double)ptr->bytesSent / (double)ptr->bytesSentIfRaw) * 100.0);
+ if ((bytes>0) || (count>0))
+ rfbLog(" %-24.24s: %6d events %9d/%9d bytes (%5.2f%% saved)\n",
+ name, count, bytes, ptr->bytesSentIfRaw, savings);
+ totalRectsSent += count;
+ totalBytesSent += bytes;
+ totalBytesIfRawSent += ptr->bytesSentIfRaw;
+ }
+ savings = 100.0 - ((totalBytesSent/totalBytesIfRawSent)*100.0);
+ rfbLog(" %-24.24s: %6d events %9.0f/%9.0f bytes (%5.2f%% savings)\n",
+ "TOTALS", totalRectsSent, totalBytesSent, totalBytesIfRawSent, savings);
+
+
+ rfbLog("Statistics: Receive\n");
+ for (ptr = cl->statMsgList; ptr!=NULL; ptr=ptr->Next)
+ {
+ name = messageNameClient2Server(ptr->type, encBuf, sizeof(encBuf));
+ count = ptr->rcvdCount;
+ bytes = ptr->bytesRcvd;
+ savings = 0.0;
+ if (ptr->bytesSentIfRaw>0.0)
+ savings = 100.0 - (((double)ptr->bytesRcvd / (double)ptr->bytesRcvdIfRaw) * 100.0);
+ if ((bytes>0) || (count>0))
+ rfbLog(" %-24.24s: %6d events %9d/%9d bytes (%5.2f%% saved)\n",
+ name, count, bytes, ptr->bytesRcvdIfRaw, savings);
+ totalRectsRcvd += count;
+ totalBytesRcvd += bytes;
+ totalBytesIfRawRcvd += ptr->bytesRcvdIfRaw;
+ }
+ for (ptr = cl->statEncList; ptr!=NULL; ptr=ptr->Next)
+ {
+ name = encodingName(ptr->type, encBuf, sizeof(encBuf));
+ count = ptr->rcvdCount;
+ bytes = ptr->bytesRcvd;
+ savings = 0.0;
+ if (ptr->bytesSentIfRaw>0.0)
+ savings = 100.0 - (((double)ptr->bytesRcvd / (double)ptr->bytesRcvdIfRaw) * 100.0);
+ if ((bytes>0) || (count>0))
+ rfbLog(" %-24.24s: %6d events %9d/%9d bytes (%5.2f%% saved)\n",
+ name, count, bytes, ptr->bytesRcvdIfRaw, savings);
+ totalRectsRcvd += count;
+ totalBytesRcvd += bytes;
+ totalBytesIfRawRcvd += ptr->bytesRcvdIfRaw;
+ }
+ savings = 100.0 - ((totalBytesRcvd/totalBytesIfRawRcvd)*100.0);
+ rfbLog(" %-24.24s: %6d events %9.0f/%9.0f bytes (%5.2f%% savings)\n",
+ "TOTALS", totalRectsRcvd, totalBytesRcvd,totalBytesIfRawRcvd, savings);
+
+}
+
diff --git a/libvncserver/tight.c b/libvncserver/tight.c
index 71ce0d9..8a594c2 100644
--- a/libvncserver/tight.c
+++ b/libvncserver/tight.c
@@ -663,8 +663,8 @@ SendTightHeader(rfbClientPtr cl,
sz_rfbFramebufferUpdateRectHeader);
cl->ublen += sz_rfbFramebufferUpdateRectHeader;
- cl->rectanglesSent[rfbEncodingTight]++;
- cl->bytesSent[rfbEncodingTight] += sz_rfbFramebufferUpdateRectHeader;
+ rfbStatRecordEncodingSent(cl, rfbEncodingTight, sz_rfbFramebufferUpdateRectHeader,
+ sz_rfbFramebufferUpdateRectHeader + w * (cl->format.bitsPerPixel / 8) * h);
return TRUE;
}
@@ -693,7 +693,7 @@ SendSolidRect(rfbClientPtr cl)
memcpy (&cl->updateBuf[cl->ublen], tightBeforeBuf, len);
cl->ublen += len;
- cl->bytesSent[rfbEncodingTight] += len + 1;
+ rfbStatRecordEncodingSentAdd(cl, rfbEncodingTight, len+1);
return TRUE;
}
@@ -736,7 +736,7 @@ SendMonoRect(rfbClientPtr cl,
memcpy(&cl->updateBuf[cl->ublen], tightAfterBuf, paletteLen);
cl->ublen += paletteLen;
- cl->bytesSent[rfbEncodingTight] += 3 + paletteLen;
+ rfbStatRecordEncodingSentAdd(cl, rfbEncodingTight, 3 + paletteLen);
break;
case 16:
@@ -747,7 +747,7 @@ SendMonoRect(rfbClientPtr cl,
memcpy(&cl->updateBuf[cl->ublen], tightAfterBuf, 4);
cl->ublen += 4;
- cl->bytesSent[rfbEncodingTight] += 7;
+ rfbStatRecordEncodingSentAdd(cl, rfbEncodingTight, 7);
break;
default:
@@ -755,7 +755,7 @@ SendMonoRect(rfbClientPtr cl,
cl->updateBuf[cl->ublen++] = (char)monoBackground;
cl->updateBuf[cl->ublen++] = (char)monoForeground;
- cl->bytesSent[rfbEncodingTight] += 5;
+ rfbStatRecordEncodingSentAdd(cl, rfbEncodingTight, 5);
}
return CompressData(cl, streamId, dataLen,
@@ -801,7 +801,7 @@ SendIndexedRect(rfbClientPtr cl,
memcpy(&cl->updateBuf[cl->ublen], tightAfterBuf, paletteNumColors * entryLen);
cl->ublen += paletteNumColors * entryLen;
- cl->bytesSent[rfbEncodingTight] += 3 + paletteNumColors * entryLen;
+ rfbStatRecordEncodingSentAdd(cl, rfbEncodingTight, 3 + paletteNumColors * entryLen);
break;
case 16:
@@ -814,7 +814,7 @@ SendIndexedRect(rfbClientPtr cl,
memcpy(&cl->updateBuf[cl->ublen], tightAfterBuf, paletteNumColors * 2);
cl->ublen += paletteNumColors * 2;
- cl->bytesSent[rfbEncodingTight] += 3 + paletteNumColors * 2;
+ rfbStatRecordEncodingSentAdd(cl, rfbEncodingTight, 3 + paletteNumColors * 2);
break;
default:
@@ -840,7 +840,7 @@ SendFullColorRect(rfbClientPtr cl,
}
cl->updateBuf[cl->ublen++] = 0x00; /* stream id = 0, no flushing, no filter */
- cl->bytesSent[rfbEncodingTight]++;
+ rfbStatRecordEncodingSentAdd(cl, rfbEncodingTight, 1);
if (usePixelFormat24) {
Pack24(cl, tightBeforeBuf, &cl->format, w * h);
@@ -874,7 +874,7 @@ SendGradientRect(rfbClientPtr cl,
cl->updateBuf[cl->ublen++] = (streamId | rfbTightExplicitFilter) << 4;
cl->updateBuf[cl->ublen++] = rfbTightFilterGradient;
- cl->bytesSent[rfbEncodingTight] += 2;
+ rfbStatRecordEncodingSentAdd(cl, rfbEncodingTight, 2);
if (usePixelFormat24) {
FilterGradient24(cl, tightBeforeBuf, &cl->format, w, h);
@@ -905,7 +905,7 @@ CompressData(rfbClientPtr cl,
if (dataLen < TIGHT_MIN_TO_COMPRESS) {
memcpy(&cl->updateBuf[cl->ublen], tightBeforeBuf, dataLen);
cl->ublen += dataLen;
- cl->bytesSent[rfbEncodingTight] += dataLen;
+ rfbStatRecordEncodingSentAdd(cl, rfbEncodingTight, dataLen);
return TRUE;
}
@@ -955,15 +955,15 @@ static rfbBool SendCompressedData(rfbClientPtr cl,
int i, portionLen;
cl->updateBuf[cl->ublen++] = compressedLen & 0x7F;
- cl->bytesSent[rfbEncodingTight]++;
+ rfbStatRecordEncodingSentAdd(cl, rfbEncodingTight, 1);
if (compressedLen > 0x7F) {
cl->updateBuf[cl->ublen-1] |= 0x80;
cl->updateBuf[cl->ublen++] = compressedLen >> 7 & 0x7F;
- cl->bytesSent[rfbEncodingTight]++;
+ rfbStatRecordEncodingSentAdd(cl, rfbEncodingTight, 1);
if (compressedLen > 0x3FFF) {
cl->updateBuf[cl->ublen-1] |= 0x80;
cl->updateBuf[cl->ublen++] = compressedLen >> 14 & 0xFF;
- cl->bytesSent[rfbEncodingTight]++;
+ rfbStatRecordEncodingSentAdd(cl, rfbEncodingTight, 1);
}
}
@@ -979,7 +979,7 @@ static rfbBool SendCompressedData(rfbClientPtr cl,
memcpy(&cl->updateBuf[cl->ublen], &tightAfterBuf[i], portionLen);
cl->ublen += portionLen;
}
- cl->bytesSent[rfbEncodingTight] += compressedLen;
+ rfbStatRecordEncodingSentAdd(cl, rfbEncodingTight, compressedLen);
return TRUE;
}
@@ -1686,7 +1686,7 @@ SendJpegRect(rfbClientPtr cl, int x, int y, int w, int h, int quality)
}
cl->updateBuf[cl->ublen++] = (char)(rfbTightJpeg << 4);
- cl->bytesSent[rfbEncodingTight]++;
+ rfbStatRecordEncodingSentAdd(cl, rfbEncodingTight, 1);
return SendCompressedData(cl, jpegDstDataLen);
}
diff --git a/libvncserver/tightvnc-filetransfer/rfbtightproto.h b/libvncserver/tightvnc-filetransfer/rfbtightproto.h
index 397daba..ef683ae 100644
--- a/libvncserver/tightvnc-filetransfer/rfbtightproto.h
+++ b/libvncserver/tightvnc-filetransfer/rfbtightproto.h
@@ -28,6 +28,12 @@
#include <rfb/rfb.h>
#include <limits.h>
+/* PATH_MAX is not defined in limits.h on some platforms */
+#ifndef PATH_MAX
+#define PATH_MAX 4096
+#endif
+
+
#define rfbSecTypeTight 16
void rfbTightUsage(void);
diff --git a/libvncserver/ultra.c b/libvncserver/ultra.c
index e1821bb..1e51446 100644
--- a/libvncserver/ultra.c
+++ b/libvncserver/ultra.c
@@ -101,9 +101,7 @@ rfbSendOneRectEncodingUltra(rfbClientPtr cl,
}
/* Update statics */
- cl->rectanglesSent[rfbEncodingUltra]++;
- cl->bytesSent[rfbEncodingUltra] += (sz_rfbFramebufferUpdateRectHeader
- + sz_rfbZlibHeader + lzoAfterBufLen);
+ rfbStatRecordEncodingSent(cl, rfbEncodingUltra, sz_rfbFramebufferUpdateRectHeader + sz_rfbZlibHeader + lzoAfterBufLen, maxRawSize);
if (cl->ublen + sz_rfbFramebufferUpdateRectHeader + sz_rfbZlibHeader
> UPDATE_BUF_SIZE)
diff --git a/libvncserver/zlib.c b/libvncserver/zlib.c
index 321d86f..56bcc6e 100644
--- a/libvncserver/zlib.c
+++ b/libvncserver/zlib.c
@@ -121,6 +121,7 @@ rfbSendOneRectEncodingZlib(rfbClientPtr cl,
zlibAfterBuf = (char *)realloc(zlibAfterBuf, zlibAfterBufSize);
}
+
/*
* Convert pixel data to client format.
*/
@@ -176,9 +177,8 @@ rfbSendOneRectEncodingZlib(rfbClientPtr cl,
*/
/* Update statics */
- cl->rectanglesSent[rfbEncodingZlib]++;
- cl->bytesSent[rfbEncodingZlib] += (sz_rfbFramebufferUpdateRectHeader
- + sz_rfbZlibHeader + zlibAfterBufLen);
+ rfbStatRecordEncodingSent(cl, rfbEncodingZlib, sz_rfbFramebufferUpdateRectHeader + sz_rfbZlibHeader + zlibAfterBufLen,
+ + w * (cl->format.bitsPerPixel / 8) * h);
if (cl->ublen + sz_rfbFramebufferUpdateRectHeader + sz_rfbZlibHeader
> UPDATE_BUF_SIZE)
diff --git a/libvncserver/zrle.c b/libvncserver/zrle.c
index 76123a0..d72993e 100644
--- a/libvncserver/zrle.c
+++ b/libvncserver/zrle.c
@@ -124,9 +124,8 @@ rfbBool rfbSendRectEncodingZRLE(rfbClientPtr cl, int x, int y, int w, int h)
break;
}
- cl->rectanglesSent[rfbEncodingZRLE]++;
- cl->bytesSent[rfbEncodingZRLE] += (sz_rfbFramebufferUpdateRectHeader
- + sz_rfbZRLEHeader + ZRLE_BUFFER_LENGTH(&zos->out));
+ rfbStatRecordEncodingSent(cl, rfbEncodingZRLE, sz_rfbFramebufferUpdateRectHeader + sz_rfbZRLEHeader + ZRLE_BUFFER_LENGTH(&zos->out),
+ + w * (cl->format.bitsPerPixel / 8) * h);
if (cl->ublen + sz_rfbFramebufferUpdateRectHeader + sz_rfbZRLEHeader
> UPDATE_BUF_SIZE)
diff --git a/rfb/rfb.h b/rfb/rfb.h
index 39abe77..0f098a5 100644
--- a/rfb/rfb.h
+++ b/rfb/rfb.h
@@ -136,8 +136,22 @@ typedef rfbBool (*rfbPasswordCheckProcPtr)(struct _rfbClientRec* cl,const char*
typedef enum rfbNewClientAction (*rfbNewClientHookPtr)(struct _rfbClientRec* cl);
typedef void (*rfbDisplayHookPtr)(struct _rfbClientRec* cl);
/* support the capability to view the caps/num/scroll states of the X server */
-typedef int (*rfbGetKeyboardLedStateHookPtr)(struct _rfbScreenInfo* screen);
-
+typedef int (*rfbGetKeyboardLedStateHookPtr)(struct _rfbScreenInfo* screen);
+/* 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;
@@ -296,7 +310,11 @@ typedef struct _rfbScreenInfo
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 */
@@ -326,6 +344,10 @@ typedef struct _rfbScreenInfo
/* rfbEncodingServerIdentity */
char *versionString;
+
+ /* What does the server tell the new clients which version it supports */
+ int protocolMajorVersion;
+ int protocolMinorVersion;
} rfbScreenInfo, *rfbScreenInfoPtr;
@@ -351,6 +373,27 @@ typedef struct sraRegion* sraRegionPtr;
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 _rfbClientRec {
/* back pointer to the screen */
@@ -467,20 +510,11 @@ typedef struct _rfbClientRec {
int ublen;
/* statistics */
-
- int bytesSent[MAX_ENCODINGS];
- int rectanglesSent[MAX_ENCODINGS];
- int lastRectMarkersSent;
- int lastRectBytesSent;
- int cursorShapeBytesSent;
- int cursorShapeUpdatesSent;
- int cursorPosBytesSent;
- int cursorPosUpdatesSent;
- int framebufferUpdateMessagesSent;
+ struct _rfbStatList *statEncList;
+ struct _rfbStatList *statMsgList;
int rawBytesEquivalent;
- int keyEventsRcvd;
- int pointerEventsRcvd;
-
+ int bytesSent;
+
#ifdef LIBVNCSERVER_HAVE_LIBZ
/* zlib encoding -- necessary compression state info per client */
@@ -502,6 +536,7 @@ typedef struct _rfbClientRec {
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 */
@@ -584,6 +619,11 @@ extern char rfbEndianTest;
#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;
@@ -634,6 +674,13 @@ 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, 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 */
@@ -880,6 +927,38 @@ extern rfbBool rfbIsActive(rfbScreenInfoPtr screenInfo);
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_);
+
+
+
+
#endif
#if(defined __cplusplus)
diff --git a/rfb/rfbclient.h b/rfb/rfbclient.h
index 3454af4..d8e3fdc 100644
--- a/rfb/rfbclient.h
+++ b/rfb/rfbclient.h
@@ -96,6 +96,7 @@ typedef struct {
struct _rfbClient;
+typedef void (*HandleTextChatProc)(struct _rfbClient* client, int value, char *text);
typedef void (*HandleKeyboardLedStateProc)(struct _rfbClient* client, int value, int pad);
typedef rfbBool (*HandleCursorPosProc)(struct _rfbClient* client, int x, int y);
typedef void (*SoftCursorLockAreaProc)(struct _rfbClient* client, int x, int y, int w, int h);
@@ -210,6 +211,7 @@ typedef struct _rfbClient {
int canHandleNewFBSize;
/* hooks */
+ HandleTextChatProc HandleTextChat;
HandleKeyboardLedStateProc HandleKeyboardLedState;
HandleCursorPosProc HandleCursorPos;
SoftCursorLockAreaProc SoftCursorLockArea;
@@ -219,6 +221,19 @@ typedef struct _rfbClient {
GetPasswordProc GetPassword;
MallocFrameBufferProc MallocFrameBuffer;
BellProc Bell;
+
+ /* Which messages are supported by the server
+ * This is a *guess* for most servers.
+ * (If we can even detect the type of server)
+ *
+ * If the server supports the "rfbEncodingSupportedMessages"
+ * then this will be updated when the encoding is received to
+ * accurately reflect the servers capabilities.
+ */
+ rfbSupportedMessages supportedMessages;
+
+ /* negotiated protocol version */
+ int major, minor;
} rfbClient;
/* cursor.c */
@@ -247,6 +262,12 @@ extern rfbBool SendKeyEvent(rfbClient* client,uint32_t key, rfbBool down);
extern rfbBool SendClientCutText(rfbClient* client,char *str, int len);
extern rfbBool HandleRFBServerMessage(rfbClient* client);
+extern rfbBool TextChatSend(rfbClient* client, char *text);
+extern rfbBool TextChatOpen(rfbClient* client);
+extern rfbBool TextChatClose(rfbClient* client);
+extern rfbBool TextChatFinish(rfbClient* client);
+extern rfbBool PermitServerInput(rfbClient* client, int enabled);
+
extern void PrintPixelFormat(rfbPixelFormat *format);
/* client data */
diff --git a/rfb/rfbproto.h b/rfb/rfbproto.h
index c642f61..672d0d7 100644
--- a/rfb/rfbproto.h
+++ b/rfb/rfbproto.h
@@ -218,8 +218,10 @@ typedef struct {
#define rfbProtocolVersionFormat "RFB %03d.%03d\n"
#define rfbProtocolMajorVersion 3
-#define rfbProtocolMinorVersion 7
-#define rfbProtocolFallbackMinorVersion 3
+#define rfbProtocolMinorVersion 6
+/* UltraVNC Viewer examines rfbProtocolMinorVersion number (4, and 6)
+ * to identify if the server supports File Transfer
+ */
typedef char rfbProtocolVersionMsg[13]; /* allow extra byte for null */
@@ -397,24 +399,18 @@ typedef struct {
#define rfbEncodingRRE 2
#define rfbEncodingCoRRE 4
#define rfbEncodingHextile 5
-#ifdef LIBVNCSERVER_HAVE_LIBZ
#define rfbEncodingZlib 6
#define rfbEncodingTight 7
#define rfbEncodingZlibHex 8
-#endif
#define rfbEncodingUltra 9
-#ifdef LIBVNCSERVER_HAVE_LIBZ
#define rfbEncodingZRLE 16
-#endif
/* Cache & XOR-Zlib - rdv@2002 */
#define rfbEncodingCache 0xFFFF0000
#define rfbEncodingCacheEnable 0xFFFF0001
-#ifdef LIBVNCSERVER_HAVE_LIBZ
#define rfbEncodingXOR_Zlib 0xFFFF0002
#define rfbEncodingXORMonoColor_Zlib 0xFFFF0003
#define rfbEncodingXORMultiColor_Zlib 0xFFFF0004
-#endif
#define rfbEncodingSolidColor 0xFFFF0005
#define rfbEncodingXOREnable 0xFFFF0006
#define rfbEncodingCacheZip 0xFFFF0007
@@ -649,11 +645,11 @@ typedef struct {
#define rfbHextileExtractW(byte) (((byte) >> 4) + 1)
#define rfbHextileExtractH(byte) (((byte) & 0xf) + 1)
-#ifdef LIBVNCSERVER_HAVE_LIBZ
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* zlib - zlib compressed Encoding. We have an rfbZlibHeader structure
* giving the number of bytes following. Finally the data follows is
* zlib compressed version of the raw pixel data as negotiated.
+ * (NOTE: also used by Ultra Encoding)
*/
typedef struct {
@@ -662,6 +658,7 @@ typedef struct {
#define sz_rfbZlibHeader 4
+#ifdef LIBVNCSERVER_HAVE_LIBZ
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* Tight Encoding.
@@ -935,9 +932,10 @@ typedef struct {
typedef struct _rfbFileTransferMsg {
uint8_t type; /* always rfbFileTransfer */
uint8_t contentType; /* See defines below */
- uint16_t contentParam;/* Other possible content classification (Dir or File name, etc..) */
- uint32_t size; /* FileSize or packet index or error or other */
- /* uint32_t sizeH; Additional 32Bits params to handle big values. Only for V2 (we want backward compatibility between all V1 versions) */
+ uint8_t contentParam;/* Other possible content classification (Dir or File name, etc..) */
+ uint8_t pad; /* It appears that UltraVNC *forgot* to Swap16IfLE(contentParam) */
+ uint32_t size; /* FileSize or packet index or error or other */
+/* uint32_t sizeH; Additional 32Bits params to handle big values. Only for V2 (we want backward compatibility between all V1 versions) */
uint32_t length;
/* followed by data char text[length] */
} rfbFileTransferMsg;
diff --git a/x11vnc/rates.c b/x11vnc/rates.c
index 811a7ae..d6f1c5c 100644
--- a/x11vnc/rates.c
+++ b/x11vnc/rates.c
@@ -350,11 +350,8 @@ db = 0;
}
nclients++;
- cbs = 0;
- for (i=0; i<MAX_ENCODINGS; i++) {
- cbs += cl->bytesSent[i];
- }
- rbs = cl->rawBytesEquivalent;
+ cbs = rfbStatGetSentBytes(cl);
+ rbs = rfbStatGetSentBytesIfRaw(cl);
if (init) {
@@ -435,7 +432,7 @@ if (db) fprintf(stderr, "%d client num rects req: %d mod: %d cbs: %d "
if (db) fprintf(stderr, "dt2 calc: num rects req: %d/%d mod: %d/%d "
"fbu-sent: %d dt: %.4f dt2: %.4f tm: %.4f\n",
- req0, req1, mod0, mod1, cl->framebufferUpdateMessagesSent, dt, dt2, tm);
+ req0, req1, mod0, mod1, rfbStatGetMessageCountSent(cl, rfbFramebufferUpdate), dt, dt2, tm);
if (req1 != 0 && mod1 == 0) {
got_t2 = 1;
break;
@@ -502,7 +499,7 @@ if (db) fprintf(stderr, "dt2 calc: num rects req: %d/%d mod: %d/%d "
if (db) fprintf(stderr, "dt3 calc: num rects req: %d/%d mod: %d/%d "
"fbu-sent: %d dt: %.4f dt3: %.4f tm: %.4f\n",
- req0, req1, mod0, mod1, cl->framebufferUpdateMessagesSent, dt, dt3, tm);
+ req0, req1, mod0, mod1, rfbStatGetMessageCountSent(cl, rfbFramebufferUpdate), dt, dt3, tm);
if (req1 != 0 && mod1 == 0) {
dts[got_t3++] = dt3;
diff --git a/x11vnc/userinput.c b/x11vnc/userinput.c
index ef1563f..7646d08 100644
--- a/x11vnc/userinput.c
+++ b/x11vnc/userinput.c
@@ -4082,7 +4082,7 @@ int fb_update_sent(int *count) {
i = rfbGetClientIterator(screen);
while( (cl = rfbClientIteratorNext(i)) ) {
- sent += cl->framebufferUpdateMessagesSent;
+ sent += rfbStatGetMessageCountSent(cl, rfbFramebufferUpdate);
}
rfbReleaseClientIterator(i);
if (sent != last_count) {