Commit ccdbe8f3 authored by steven_carr's avatar steven_carr

The great UltraVNC Compatibility Commit

parent 347c4a98
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> 2006-05-13 Karl Runge <runge@karlrunge.com>
* minilzo.c,minilzo.h,lzoconf.h: switch to non-CRLF versions. * minilzo.c,minilzo.h,lzoconf.h: switch to non-CRLF versions.
* libvncclient/Makefile.am: add minilzo.c, minilzo.h, lzoconf.h * libvncclient/Makefile.am: add minilzo.c, minilzo.h, lzoconf.h
......
...@@ -150,6 +150,26 @@ static void kbd_leds(rfbClient* cl, int value, int pad) { ...@@ -150,6 +150,26 @@ static void kbd_leds(rfbClient* cl, int value, int pad) {
fflush(stderr); 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__ #ifdef __MINGW32__
#define LOG_TO_FILE #define LOG_TO_FILE
#endif #endif
...@@ -212,7 +232,7 @@ int main(int argc,char** argv) { ...@@ -212,7 +232,7 @@ int main(int argc,char** argv) {
cl->canHandleNewFBSize = TRUE; cl->canHandleNewFBSize = TRUE;
cl->GotFrameBufferUpdate=update; cl->GotFrameBufferUpdate=update;
cl->HandleKeyboardLedState=kbd_leds; cl->HandleKeyboardLedState=kbd_leds;
cl->HandleTextChat=text_chat;
if(!rfbInitClient(cl,&argc,argv)) if(!rfbInitClient(cl,&argc,argv))
return 1; return 1;
......
...@@ -223,6 +223,99 @@ static rfbBool HandleZRLE24Down(rfbClient* client, int rx, int ry, int rw, int r ...@@ -223,6 +223,99 @@ static rfbBool HandleZRLE24Down(rfbClient* client, int rx, int ry, int rw, int r
static rfbBool HandleZRLE32(rfbClient* client, int rx, int ry, int rw, int rh); static rfbBool HandleZRLE32(rfbClient* client, int rx, int ry, int rw, int rh);
#endif #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. * ConnectToRFBServer.
*/ */
...@@ -310,25 +403,86 @@ InitialiseRFBConnection(rfbClient* client) ...@@ -310,25 +403,86 @@ InitialiseRFBConnection(rfbClient* client)
return FALSE; return FALSE;
} }
#if rfbProtocolMinorVersion == 7
/* work around LibVNCClient not yet speaking RFB 3.7 */ DefaultSupportedMessages(client);
#undef rfbProtocolMinorVersion client->major = major;
#define rfbProtocolMinorVersion 3 client->minor = minor;
#endif
/* 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", rfbClientLog("VNC server supports protocol version %d.%d (viewer %d.%d)\n",
major, minor, rfbProtocolMajorVersion, rfbProtocolMinorVersion); major, minor, rfbProtocolMajorVersion, rfbProtocolMinorVersion);
major = rfbProtocolMajorVersion; sprintf(pv,rfbProtocolVersionFormat,client->major,client->minor);
minor = rfbProtocolMinorVersion;
sprintf(pv,rfbProtocolVersionFormat,major,minor);
if (!WriteToRFBServer(client, pv, sz_rfbProtocolVersionMsg)) return FALSE; if (!WriteToRFBServer(client, pv, sz_rfbProtocolVersionMsg)) return FALSE;
if (!ReadFromRFBServer(client, (char *)&authScheme, 4)) return FALSE;
/* 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); authScheme = rfbClientSwap32IfLE(authScheme);
}
rfbClientLog("Selected Security Scheme %d\n", authScheme);
switch (authScheme) { switch (authScheme) {
...@@ -338,9 +492,10 @@ InitialiseRFBConnection(rfbClient* client) ...@@ -338,9 +492,10 @@ InitialiseRFBConnection(rfbClient* client)
reason = malloc(reasonLen); 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); rfbClientLog("VNC connection failed: %.*s\n",(int)reasonLen, reason);
free(reason);
return FALSE; return FALSE;
case rfbNoAuth: case rfbNoAuth:
...@@ -382,6 +537,17 @@ InitialiseRFBConnection(rfbClient* client) ...@@ -382,6 +537,17 @@ InitialiseRFBConnection(rfbClient* client)
rfbClientLog("VNC authentication succeeded\n"); rfbClientLog("VNC authentication succeeded\n");
break; break;
case rfbVncAuthFailed: 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"); rfbClientLog("VNC authentication failed\n");
return FALSE; return FALSE;
case rfbVncAuthTooMany: case rfbVncAuthTooMany:
...@@ -427,7 +593,7 @@ InitialiseRFBConnection(rfbClient* client) ...@@ -427,7 +593,7 @@ InitialiseRFBConnection(rfbClient* client)
rfbClientLog("Desktop name \"%s\"\n",client->desktopName); rfbClientLog("Desktop name \"%s\"\n",client->desktopName);
rfbClientLog("Connected to VNC server, using protocol version %d.%d\n", rfbClientLog("Connected to VNC server, using protocol version %d.%d\n",
rfbProtocolMajorVersion, rfbProtocolMinorVersion); client->major, client->minor);
rfbClientLog("VNC server default format:\n"); rfbClientLog("VNC server default format:\n");
PrintPixelFormat(&client->si.format); PrintPixelFormat(&client->si.format);
...@@ -445,6 +611,7 @@ SetFormatAndEncodings(rfbClient* client) ...@@ -445,6 +611,7 @@ SetFormatAndEncodings(rfbClient* client)
{ {
rfbSetPixelFormatMsg spf; rfbSetPixelFormatMsg spf;
char buf[sz_rfbSetEncodingsMsg + MAX_ENCODINGS * 4]; char buf[sz_rfbSetEncodingsMsg + MAX_ENCODINGS * 4];
rfbSetEncodingsMsg *se = (rfbSetEncodingsMsg *)buf; rfbSetEncodingsMsg *se = (rfbSetEncodingsMsg *)buf;
uint32_t *encs = (uint32_t *)(&buf[sz_rfbSetEncodingsMsg]); uint32_t *encs = (uint32_t *)(&buf[sz_rfbSetEncodingsMsg]);
int len = 0; int len = 0;
...@@ -453,6 +620,8 @@ SetFormatAndEncodings(rfbClient* client) ...@@ -453,6 +620,8 @@ SetFormatAndEncodings(rfbClient* client)
rfbBool requestLastRectEncoding = FALSE; rfbBool requestLastRectEncoding = FALSE;
rfbClientProtocolExtension* e; rfbClientProtocolExtension* e;
if (!SupportsClient2Server(client, rfbSetPixelFormat)) return TRUE;
spf.type = rfbSetPixelFormat; spf.type = rfbSetPixelFormat;
spf.format = client->format; spf.format = client->format;
spf.format.redMax = rfbClientSwap16IfLE(spf.format.redMax); spf.format.redMax = rfbClientSwap16IfLE(spf.format.redMax);
...@@ -462,6 +631,9 @@ SetFormatAndEncodings(rfbClient* client) ...@@ -462,6 +631,9 @@ SetFormatAndEncodings(rfbClient* client)
if (!WriteToRFBServer(client, (char *)&spf, sz_rfbSetPixelFormatMsg)) if (!WriteToRFBServer(client, (char *)&spf, sz_rfbSetPixelFormatMsg))
return FALSE; return FALSE;
if (!SupportsClient2Server(client, rfbSetEncodings)) return TRUE;
se->type = rfbSetEncodings; se->type = rfbSetEncodings;
se->nEncodings = 0; se->nEncodings = 0;
...@@ -655,6 +827,8 @@ SendFramebufferUpdateRequest(rfbClient* client, int x, int y, int w, int h, rfbB ...@@ -655,6 +827,8 @@ SendFramebufferUpdateRequest(rfbClient* client, int x, int y, int w, int h, rfbB
{ {
rfbFramebufferUpdateRequestMsg fur; rfbFramebufferUpdateRequestMsg fur;
if (!SupportsClient2Server(client, rfbFramebufferUpdateRequest)) return TRUE;
fur.type = rfbFramebufferUpdateRequest; fur.type = rfbFramebufferUpdateRequest;
fur.incremental = incremental ? 1 : 0; fur.incremental = incremental ? 1 : 0;
fur.x = rfbClientSwap16IfLE(x); fur.x = rfbClientSwap16IfLE(x);
...@@ -677,19 +851,105 @@ SendScaleSetting(rfbClient* client,int scaleSetting) ...@@ -677,19 +851,105 @@ SendScaleSetting(rfbClient* client,int scaleSetting)
{ {
rfbSetScaleMsg ssm; rfbSetScaleMsg ssm;
if (client->appData.palmVNC)
ssm.type = rfbPalmVNCSetScaleFactor;
else
ssm.type = rfbSetScale;
ssm.scale = scaleSetting; ssm.scale = scaleSetting;
ssm.pad = 0; ssm.pad = 0;
/* 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)) if (!WriteToRFBServer(client, (char *)&ssm, sz_rfbSetScaleMsg))
return FALSE; return FALSE;
}
return TRUE; 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. * SendPointerEvent.
*/ */
...@@ -699,6 +959,8 @@ SendPointerEvent(rfbClient* client,int x, int y, int buttonMask) ...@@ -699,6 +959,8 @@ SendPointerEvent(rfbClient* client,int x, int y, int buttonMask)
{ {
rfbPointerEventMsg pe; rfbPointerEventMsg pe;
if (!SupportsClient2Server(client, rfbPointerEvent)) return TRUE;
pe.type = rfbPointerEvent; pe.type = rfbPointerEvent;
pe.buttonMask = buttonMask; pe.buttonMask = buttonMask;
if (x < 0) x = 0; if (x < 0) x = 0;
...@@ -719,6 +981,8 @@ SendKeyEvent(rfbClient* client, uint32_t key, rfbBool down) ...@@ -719,6 +981,8 @@ SendKeyEvent(rfbClient* client, uint32_t key, rfbBool down)
{ {
rfbKeyEventMsg ke; rfbKeyEventMsg ke;
if (!SupportsClient2Server(client, rfbKeyEvent)) return TRUE;
ke.type = rfbKeyEvent; ke.type = rfbKeyEvent;
ke.down = down ? 1 : 0; ke.down = down ? 1 : 0;
ke.key = rfbClientSwap32IfLE(key); ke.key = rfbClientSwap32IfLE(key);
...@@ -739,6 +1003,8 @@ SendClientCutText(rfbClient* client, char *str, int len) ...@@ -739,6 +1003,8 @@ SendClientCutText(rfbClient* client, char *str, int len)
free(client->serverCutText); free(client->serverCutText);
client->serverCutText = NULL; client->serverCutText = NULL;
if (!SupportsClient2Server(client, rfbClientCutText)) return TRUE;
cct.type = rfbClientCutText; cct.type = rfbClientCutText;
cct.length = rfbClientSwap32IfLE(len); cct.length = rfbClientSwap32IfLE(len);
return (WriteToRFBServer(client, (char *)&cct, sz_rfbClientCutTextMsg) && return (WriteToRFBServer(client, (char *)&cct, sz_rfbClientCutTextMsg) &&
...@@ -858,9 +1124,8 @@ HandleRFBServerMessage(rfbClient* client) ...@@ -858,9 +1124,8 @@ HandleRFBServerMessage(rfbClient* client)
/* rect.r.w=byte count */ /* rect.r.w=byte count */
if (rect.encoding == rfbEncodingSupportedMessages) { if (rect.encoding == rfbEncodingSupportedMessages) {
rfbSupportedMessages msgs;
int loop; int loop;
if (!ReadFromRFBServer(client, (char *)&msgs, sz_rfbSupportedMessages)) if (!ReadFromRFBServer(client, (char *)&client->supportedMessages, sz_rfbSupportedMessages))
return FALSE; return FALSE;
/* msgs is two sets of bit flags of supported messages client2server[] and server2client[] */ /* msgs is two sets of bit flags of supported messages client2server[] and server2client[] */
...@@ -869,18 +1134,18 @@ HandleRFBServerMessage(rfbClient* client) ...@@ -869,18 +1134,18 @@ HandleRFBServerMessage(rfbClient* client)
rfbClientLog("client2server supported messages (bit flags)\n"); rfbClientLog("client2server supported messages (bit flags)\n");
for (loop=0;loop<32;loop+=8) for (loop=0;loop<32;loop+=8)
rfbClientLog("%02X: %04x %04x %04x %04x - %04x %04x %04x %04x\n", loop, rfbClientLog("%02X: %04x %04x %04x %04x - %04x %04x %04x %04x\n", loop,
msgs.client2server[loop], msgs.client2server[loop+1], client->supportedMessages.client2server[loop], client->supportedMessages.client2server[loop+1],
msgs.client2server[loop+2], msgs.client2server[loop+3], client->supportedMessages.client2server[loop+2], client->supportedMessages.client2server[loop+3],
msgs.client2server[loop+4], msgs.client2server[loop+5], client->supportedMessages.client2server[loop+4], client->supportedMessages.client2server[loop+5],
msgs.client2server[loop+6], msgs.client2server[loop+7]); client->supportedMessages.client2server[loop+6], client->supportedMessages.client2server[loop+7]);
rfbClientLog("server2client supported messages (bit flags)\n"); rfbClientLog("server2client supported messages (bit flags)\n");
for (loop=0;loop<32;loop+=8) for (loop=0;loop<32;loop+=8)
rfbClientLog("%02X: %04x %04x %04x %04x - %04x %04x %04x %04x\n", loop, rfbClientLog("%02X: %04x %04x %04x %04x - %04x %04x %04x %04x\n", loop,
msgs.server2client[loop], msgs.server2client[loop+1], client->supportedMessages.server2client[loop], client->supportedMessages.server2client[loop+1],
msgs.server2client[loop+2], msgs.server2client[loop+3], client->supportedMessages.server2client[loop+2], client->supportedMessages.server2client[loop+3],
msgs.server2client[loop+4], msgs.server2client[loop+5], client->supportedMessages.server2client[loop+4], client->supportedMessages.server2client[loop+5],
msgs.server2client[loop+6], msgs.server2client[loop+7]); client->supportedMessages.server2client[loop+6], client->supportedMessages.server2client[loop+7]);
continue; continue;
} }
...@@ -1217,6 +1482,47 @@ HandleRFBServerMessage(rfbClient* client) ...@@ -1217,6 +1482,47 @@ HandleRFBServerMessage(rfbClient* client)
break; 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: case rfbResizeFrameBuffer:
{ {
if (!ReadFromRFBServer(client, ((char *)&msg) + 1, if (!ReadFromRFBServer(client, ((char *)&msg) + 1,
......
...@@ -18,8 +18,6 @@ ...@@ -18,8 +18,6 @@
* USA. * USA.
*/ */
#ifdef LIBVNCSERVER_HAVE_LIBZ
/* /*
* ultrazip.c - handle ultrazip encoding. * ultrazip.c - handle ultrazip encoding.
* *
...@@ -210,5 +208,3 @@ HandleUltraZipBPP (rfbClient* client, int rx, int ry, int rw, int rh) ...@@ -210,5 +208,3 @@ HandleUltraZipBPP (rfbClient* client, int rx, int ry, int rw, int rh)
} }
#undef CARDBPP #undef CARDBPP
#endif
...@@ -377,7 +377,7 @@ static int HandleZRLETile(rfbClient* client, ...@@ -377,7 +377,7 @@ static int HandleZRLETile(rfbClient* client,
#undef HandleZRLETile #undef HandleZRLETile
#undef UncompressCPixel #undef UncompressCPixel
#undef REALBPP #undef REALBPP
#undef UNCOMP
#endif #endif
#undef UNCOMP
...@@ -317,6 +317,11 @@ rfbAuthProcessClientMessage(rfbClientPtr cl) ...@@ -317,6 +317,11 @@ rfbAuthProcessClientMessage(rfbClientPtr cl)
if (rfbWriteExact(cl, (char *)&authResult, 4) < 0) { if (rfbWriteExact(cl, (char *)&authResult, 4) < 0) {
rfbLogPerror("rfbAuthProcessClientMessage: write"); rfbLogPerror("rfbAuthProcessClientMessage: write");
} }
/* 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); rfbCloseClient(cl);
return; return;
} }
......
...@@ -41,7 +41,7 @@ static char *rreBeforeBuf = NULL; ...@@ -41,7 +41,7 @@ static char *rreBeforeBuf = NULL;
static int rreAfterBufSize = 0; static int rreAfterBufSize = 0;
static char *rreAfterBuf = NULL; static char *rreAfterBuf = NULL;
static int rreAfterBufLen; static int rreAfterBufLen = 0;
static int subrectEncode8(uint8_t *data, int w, int h); static int subrectEncode8(uint8_t *data, int w, int h);
static int subrectEncode16(uint16_t *data, int w, int h); static int subrectEncode16(uint16_t *data, int w, int h);
...@@ -145,9 +145,9 @@ rfbSendSmallRectEncodingCoRRE(rfbClientPtr cl, ...@@ -145,9 +145,9 @@ rfbSendSmallRectEncodingCoRRE(rfbClientPtr cl,
return rfbSendRectEncodingRaw(cl, x, y, w, h); return rfbSendRectEncodingRaw(cl, x, y, w, h);
} }
cl->rectanglesSent[rfbEncodingCoRRE]++; rfbStatRecordEncodingSent(cl,rfbEncodingCoRRE,
cl->bytesSent[rfbEncodingCoRRE] += (sz_rfbFramebufferUpdateRectHeader sz_rfbFramebufferUpdateRectHeader + sz_rfbRREHeader + rreAfterBufLen,
+ sz_rfbRREHeader + rreAfterBufLen); sz_rfbFramebufferUpdateRectHeader + w * h * (cl->format.bitsPerPixel / 8));
if (cl->ublen + sz_rfbFramebufferUpdateRectHeader + sz_rfbRREHeader if (cl->ublen + sz_rfbFramebufferUpdateRectHeader + sz_rfbRREHeader
> UPDATE_BUF_SIZE) > UPDATE_BUF_SIZE)
......
...@@ -78,9 +78,6 @@ rfbSendCursorShape(rfbClientPtr cl) ...@@ -78,9 +78,6 @@ rfbSendCursorShape(rfbClientPtr cl)
sz_rfbFramebufferUpdateRectHeader); sz_rfbFramebufferUpdateRectHeader);
cl->ublen += sz_rfbFramebufferUpdateRectHeader; cl->ublen += sz_rfbFramebufferUpdateRectHeader;
cl->cursorShapeBytesSent += sz_rfbFramebufferUpdateRectHeader;
cl->cursorShapeUpdatesSent++;
if (!rfbSendUpdateBuf(cl)) if (!rfbSendUpdateBuf(cl))
return FALSE; return FALSE;
...@@ -167,9 +164,8 @@ rfbSendCursorShape(rfbClientPtr cl) ...@@ -167,9 +164,8 @@ rfbSendCursorShape(rfbClientPtr cl)
} }
/* Send everything we have prepared in the cl->updateBuf[]. */ /* Send everything we have prepared in the cl->updateBuf[]. */
rfbStatRecordMessageSent(cl, (cl->useRichCursorEncoding ? rfbEncodingRichCursor : rfbEncodingXCursor),
cl->cursorShapeBytesSent += (cl->ublen - saved_ublen); sz_rfbFramebufferUpdateRectHeader + (cl->ublen - saved_ublen), sz_rfbFramebufferUpdateRectHeader + (cl->ublen - saved_ublen));
cl->cursorShapeUpdatesSent++;
if (!rfbSendUpdateBuf(cl)) if (!rfbSendUpdateBuf(cl))
return FALSE; return FALSE;
...@@ -201,8 +197,7 @@ rfbSendCursorPos(rfbClientPtr cl) ...@@ -201,8 +197,7 @@ rfbSendCursorPos(rfbClientPtr cl)
sz_rfbFramebufferUpdateRectHeader); sz_rfbFramebufferUpdateRectHeader);
cl->ublen += sz_rfbFramebufferUpdateRectHeader; cl->ublen += sz_rfbFramebufferUpdateRectHeader;
cl->cursorPosBytesSent += sz_rfbFramebufferUpdateRectHeader; rfbStatRecordMessageSent(cl, rfbEncodingPointerPos, sz_rfbFramebufferUpdateRectHeader, sz_rfbFramebufferUpdateRectHeader);
cl->cursorPosUpdatesSent++;
if (!rfbSendUpdateBuf(cl)) if (!rfbSendUpdateBuf(cl))
return FALSE; return FALSE;
......
...@@ -60,8 +60,9 @@ rfbSendRectEncodingHextile(rfbClientPtr cl, ...@@ -60,8 +60,9 @@ rfbSendRectEncodingHextile(rfbClientPtr cl,
sz_rfbFramebufferUpdateRectHeader); sz_rfbFramebufferUpdateRectHeader);
cl->ublen += sz_rfbFramebufferUpdateRectHeader; cl->ublen += sz_rfbFramebufferUpdateRectHeader;
cl->rectanglesSent[rfbEncodingHextile]++; rfbStatRecordEncodingSent(cl, rfbEncodingHextile,
cl->bytesSent[rfbEncodingHextile] += sz_rfbFramebufferUpdateRectHeader; sz_rfbFramebufferUpdateRectHeader,
sz_rfbFramebufferUpdateRectHeader + w * (cl->format.bitsPerPixel / 8) * h);
switch (cl->format.bitsPerPixel) { switch (cl->format.bitsPerPixel) {
case 8: case 8:
...@@ -136,6 +137,7 @@ sendHextiles##bpp(rfbClientPtr cl, int rx, int ry, int rw, int rh) { ...@@ -136,6 +137,7 @@ sendHextiles##bpp(rfbClientPtr cl, int rx, int ry, int rw, int rh) {
startUblen = cl->ublen; \ startUblen = cl->ublen; \
cl->updateBuf[startUblen] = 0; \ cl->updateBuf[startUblen] = 0; \
cl->ublen++; \ cl->ublen++; \
rfbStatRecordEncodingSentAdd(cl, rfbEncodingHextile, 1); \
\ \
testColours##bpp(clientPixelData, w * h, \ testColours##bpp(clientPixelData, w * h, \
&mono, &solid, &newBg, &newFg); \ &mono, &solid, &newBg, &newFg); \
...@@ -148,7 +150,6 @@ sendHextiles##bpp(rfbClientPtr cl, int rx, int ry, int rw, int rh) { ...@@ -148,7 +150,6 @@ sendHextiles##bpp(rfbClientPtr cl, int rx, int ry, int rw, int rh) {
} \ } \
\ \
if (solid) { \ if (solid) { \
cl->bytesSent[rfbEncodingHextile] += cl->ublen - startUblen; \
continue; \ continue; \
} \ } \
\ \
...@@ -181,9 +182,9 @@ sendHextiles##bpp(rfbClientPtr cl, int rx, int ry, int rw, int rh) { ...@@ -181,9 +182,9 @@ sendHextiles##bpp(rfbClientPtr cl, int rx, int ry, int rw, int rh) {
w * h * (bpp/8)); \ w * h * (bpp/8)); \
\ \
cl->ublen += 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, ...@@ -210,6 +211,7 @@ subrectEncode##bpp(rfbClientPtr cl, uint##bpp##_t *data, int w, int h,
\ \
nSubrectsUblen = cl->ublen; \ nSubrectsUblen = cl->ublen; \
cl->ublen++; \ cl->ublen++; \
rfbStatRecordEncodingSentAdd(cl, rfbEncodingHextile, 1); \
\ \
for (y=0; y<h; y++) { \ for (y=0; y<h; y++) { \
line = data+(y*w); \ line = data+(y*w); \
...@@ -268,6 +270,7 @@ subrectEncode##bpp(rfbClientPtr cl, uint##bpp##_t *data, int w, int h, ...@@ -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++] = rfbHextilePackXY(thex,they); \
cl->updateBuf[cl->ublen++] = rfbHextilePackWH(thew,theh); \ cl->updateBuf[cl->ublen++] = rfbHextilePackWH(thew,theh); \
rfbStatRecordEncodingSentAdd(cl, rfbEncodingHextile, 1); \
\ \
/* \ /* \
* Now mark the subrect as done. \ * Now mark the subrect as done. \
......
...@@ -495,22 +495,40 @@ clientInput(void *data) ...@@ -495,22 +495,40 @@ clientInput(void *data)
pthread_create(&output_thread, NULL, clientOutput, (void *)cl); pthread_create(&output_thread, NULL, clientOutput, (void *)cl);
while (1) { while (1) {
fd_set fds; fd_set rfds, wfds, efds;
struct timeval tv; struct timeval tv;
int n; int n;
FD_ZERO(&fds); FD_ZERO(&rfds);
FD_SET(cl->sock, &fds); 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_sec = 60; /* 1 minute */
tv.tv_usec = 0; 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) { if (n < 0) {
rfbLogPerror("ReadExact: select"); rfbLogPerror("ReadExact: select");
break; break;
} }
if (n == 0) /* timeout */ if (n == 0) /* timeout */
{
rfbSendFileTransferChunk(cl);
continue; continue;
}
/* 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); rfbProcessClientMessage(cl);
if (cl->sock == -1) { if (cl->sock == -1) {
/* Client has disconnected. */ /* Client has disconnected. */
break; break;
...@@ -818,6 +836,10 @@ rfbScreenInfoPtr rfbGetScreen(int* argc,char** argv, ...@@ -818,6 +836,10 @@ rfbScreenInfoPtr rfbGetScreen(int* argc,char** argv,
screen->handleEventsEagerly = FALSE; screen->handleEventsEagerly = FALSE;
/* Emulate UltraVNC Server by default */
screen->protocolMajorVersion = 3;
screen->protocolMinorVersion = 6;
if(!rfbProcessArguments(screen,argc,argv)) { if(!rfbProcessArguments(screen,argc,argv)) {
free(screen); free(screen);
return NULL; return NULL;
......
...@@ -66,6 +66,14 @@ ...@@ -66,6 +66,14 @@
#endif #endif
#include <stdarg.h> #include <stdarg.h>
#include <scale.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 rfbProcessClientProtocolVersion(rfbClientPtr cl);
static void rfbProcessClientNormalMessage(rfbClientPtr cl); static void rfbProcessClientNormalMessage(rfbClientPtr cl);
...@@ -229,6 +237,20 @@ rfbReverseConnection(rfbScreenInfoPtr rfbScreen, ...@@ -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 * rfbNewClient is called when a new connection has been made by whatever
* means. * means.
...@@ -348,6 +370,8 @@ rfbNewTCPOrUDPClient(rfbScreenInfoPtr rfbScreen, ...@@ -348,6 +370,8 @@ rfbNewTCPOrUDPClient(rfbScreenInfoPtr rfbScreen,
#endif #endif
#endif #endif
cl->fileTransfer.fd = -1;
cl->enableCursorShapeUpdates = FALSE; cl->enableCursorShapeUpdates = FALSE;
cl->enableCursorPosUpdates = FALSE; cl->enableCursorPosUpdates = FALSE;
cl->useRichCursorEncoding = FALSE; cl->useRichCursorEncoding = FALSE;
...@@ -378,8 +402,8 @@ rfbNewTCPOrUDPClient(rfbScreenInfoPtr rfbScreen, ...@@ -378,8 +402,8 @@ rfbNewTCPOrUDPClient(rfbScreenInfoPtr rfbScreen,
cl->lastPtrX = -1; cl->lastPtrX = -1;
sprintf(pv,rfbProtocolVersionFormat,rfbProtocolMajorVersion, sprintf(pv,rfbProtocolVersionFormat,rfbScreen->protocolMajorVersion,
rfbProtocolMinorVersion); rfbScreen->protocolMinorVersion);
if (rfbWriteExact(cl, pv, sz_rfbProtocolVersionMsg) < 0) { if (rfbWriteExact(cl, pv, sz_rfbProtocolVersionMsg) < 0) {
rfbLogPerror("rfbNewClient: write"); rfbLogPerror("rfbNewClient: write");
...@@ -583,7 +607,7 @@ rfbProcessClientProtocolVersion(rfbClientPtr cl) ...@@ -583,7 +607,7 @@ rfbProcessClientProtocolVersion(rfbClientPtr cl)
free(cl->host); free(cl->host);
cl->host=strdup(name); cl->host=strdup(name);
} }
rfbLog("Protocol version %d.%d\n", major_, minor_); rfbLog("Client Protocol Version %d.%d\n", major_, minor_);
if (major_ != rfbProtocolMajorVersion) { if (major_ != rfbProtocolMajorVersion) {
/* Major version mismatch - send a ConnFailed message */ /* Major version mismatch - send a ConnFailed message */
...@@ -591,23 +615,24 @@ rfbProcessClientProtocolVersion(rfbClientPtr cl) ...@@ -591,23 +615,24 @@ rfbProcessClientProtocolVersion(rfbClientPtr cl)
rfbErr("Major version mismatch\n"); rfbErr("Major version mismatch\n");
sprintf(failureReason, sprintf(failureReason,
"RFB protocol version mismatch - server %d.%d, client %d.%d", "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); rfbClientConnFailed(cl, failureReason);
return; 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_; cl->protocolMinorVersion = minor_;
if (minor_ > rfbProtocolMinorVersion) {
cl->protocolMinorVersion = rfbProtocolMinorVersion; rfbLog("Protocol version sent %d.%d, using %d.%d\n",
} else if (minor_ < rfbProtocolMinorVersion) {
cl->protocolMinorVersion = rfbProtocolFallbackMinorVersion;
}
if (minor_ != rfbProtocolMinorVersion &&
minor_ != rfbProtocolFallbackMinorVersion) {
rfbLog("Non-standard protocol version %d.%d, using %d.%d instead\n",
major_, minor_, rfbProtocolMajorVersion, cl->protocolMinorVersion); major_, minor_, rfbProtocolMajorVersion, cl->protocolMinorVersion);
}
rfbAuthNewClient(cl); rfbAuthNewClient(cl);
} }
...@@ -775,8 +800,7 @@ rfbSendKeyboardLedState(rfbClientPtr cl) ...@@ -775,8 +800,7 @@ rfbSendKeyboardLedState(rfbClientPtr cl)
sz_rfbFramebufferUpdateRectHeader); sz_rfbFramebufferUpdateRectHeader);
cl->ublen += sz_rfbFramebufferUpdateRectHeader; cl->ublen += sz_rfbFramebufferUpdateRectHeader;
cl->cursorPosBytesSent += sz_rfbFramebufferUpdateRectHeader; rfbStatRecordEncodingSent(cl, rfbEncodingKeyboardLedState, sz_rfbFramebufferUpdateRectHeader, sz_rfbFramebufferUpdateRectHeader);
cl->cursorPosUpdatesSent++;
if (!rfbSendUpdateBuf(cl)) if (!rfbSendUpdateBuf(cl))
return FALSE; return FALSE;
...@@ -806,7 +830,7 @@ rfbSendSupportedMessages(rfbClientPtr cl) ...@@ -806,7 +830,7 @@ rfbSendSupportedMessages(rfbClientPtr cl)
rect.encoding = Swap32IfLE(rfbEncodingSupportedMessages); rect.encoding = Swap32IfLE(rfbEncodingSupportedMessages);
rect.r.x = 0; rect.r.x = 0;
rect.r.y = 0; rect.r.y = 0;
rect.r.w = Swap16IfLE(sz_rfbFramebufferUpdateRectHeader); rect.r.w = Swap16IfLE(sz_rfbSupportedMessages);
rect.r.h = 0; rect.r.h = 0;
memcpy(&cl->updateBuf[cl->ublen], (char *)&rect, memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,
...@@ -823,10 +847,10 @@ rfbSendSupportedMessages(rfbClientPtr cl) ...@@ -823,10 +847,10 @@ rfbSendSupportedMessages(rfbClientPtr cl)
rfbSetBit(msgs.client2server, rfbClientCutText); rfbSetBit(msgs.client2server, rfbClientCutText);
rfbSetBit(msgs.client2server, rfbFileTransfer); rfbSetBit(msgs.client2server, rfbFileTransfer);
rfbSetBit(msgs.client2server, rfbSetScale); rfbSetBit(msgs.client2server, rfbSetScale);
//rfbSetBit(msgs.client2server, rfbSetServerInput); /*rfbSetBit(msgs.client2server, rfbSetServerInput); */
//rfbSetBit(msgs.client2server, rfbSetSW); /*rfbSetBit(msgs.client2server, rfbSetSW); */
//rfbSetBit(msgs.client2server, rfbTextChat); /*rfbSetBit(msgs.client2server, rfbTextChat); */
//rfbSetBit(msgs.client2server, rfbKeyFrameRequest); /*rfbSetBit(msgs.client2server, rfbKeyFrameRequest); */
rfbSetBit(msgs.client2server, rfbPalmVNCSetScaleFactor); rfbSetBit(msgs.client2server, rfbPalmVNCSetScaleFactor);
rfbSetBit(msgs.server2client, rfbFramebufferUpdate); rfbSetBit(msgs.server2client, rfbFramebufferUpdate);
...@@ -834,12 +858,15 @@ rfbSendSupportedMessages(rfbClientPtr cl) ...@@ -834,12 +858,15 @@ rfbSendSupportedMessages(rfbClientPtr cl)
rfbSetBit(msgs.server2client, rfbBell); rfbSetBit(msgs.server2client, rfbBell);
rfbSetBit(msgs.server2client, rfbServerCutText); rfbSetBit(msgs.server2client, rfbServerCutText);
rfbSetBit(msgs.server2client, rfbResizeFrameBuffer); rfbSetBit(msgs.server2client, rfbResizeFrameBuffer);
//rfbSetBit(msgs.server2client, rfbKeyFrameUpdate); /*rfbSetBit(msgs.server2client, rfbKeyFrameUpdate); */
rfbSetBit(msgs.server2client, rfbPalmVNCReSizeFrameBuffer); rfbSetBit(msgs.server2client, rfbPalmVNCReSizeFrameBuffer);
memcpy(&cl->updateBuf[cl->ublen], (char *)&msgs, sz_rfbSupportedMessages); memcpy(&cl->updateBuf[cl->ublen], (char *)&msgs, sz_rfbSupportedMessages);
cl->ublen += sz_rfbSupportedMessages; cl->ublen += sz_rfbSupportedMessages;
rfbStatRecordEncodingSent(cl, rfbEncodingSupportedMessages,
sz_rfbFramebufferUpdateRectHeader+sz_rfbSupportedMessages,
sz_rfbFramebufferUpdateRectHeader+sz_rfbSupportedMessages);
if (!rfbSendUpdateBuf(cl)) if (!rfbSendUpdateBuf(cl))
return FALSE; return FALSE;
...@@ -918,6 +945,10 @@ rfbSendSupportedEncodings(rfbClientPtr cl) ...@@ -918,6 +945,10 @@ rfbSendSupportedEncodings(rfbClientPtr cl)
rfbSendSupporteddEncodings_SendEncoding(cl, rfbEncodingSupportedEncodings); rfbSendSupporteddEncodings_SendEncoding(cl, rfbEncodingSupportedEncodings);
rfbSendSupporteddEncodings_SendEncoding(cl, rfbEncodingServerIdentity); rfbSendSupporteddEncodings_SendEncoding(cl, rfbEncodingServerIdentity);
rfbStatRecordEncodingSent(cl, rfbEncodingSupportedEncodings,
sz_rfbFramebufferUpdateRectHeader+(nEncodings * sizeof(uint32_t)),
sz_rfbFramebufferUpdateRectHeader+(nEncodings * sizeof(uint32_t)));
if (!rfbSendUpdateBuf(cl)) if (!rfbSendUpdateBuf(cl))
return FALSE; return FALSE;
...@@ -973,16 +1004,654 @@ rfbSendServerIdentity(rfbClientPtr cl) ...@@ -973,16 +1004,654 @@ rfbSendServerIdentity(rfbClientPtr cl)
memcpy(&cl->updateBuf[cl->ublen], buffer, strlen(buffer)+1); memcpy(&cl->updateBuf[cl->ublen], buffer, strlen(buffer)+1);
cl->ublen += strlen(buffer)+1; cl->ublen += strlen(buffer)+1;
rfbStatRecordEncodingSent(cl, rfbEncodingServerIdentity,
sz_rfbFramebufferUpdateRectHeader+strlen(buffer)+1,
sz_rfbFramebufferUpdateRectHeader+strlen(buffer)+1);
if (!rfbSendUpdateBuf(cl)) if (!rfbSendUpdateBuf(cl))
return FALSE; return FALSE;
return TRUE; 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 * rfbProcessClientNormalMessage is called when the client has sent a normal
* protocol message. * protocol message.
...@@ -994,6 +1663,11 @@ rfbProcessClientNormalMessage(rfbClientPtr cl) ...@@ -994,6 +1663,11 @@ rfbProcessClientNormalMessage(rfbClientPtr cl)
int n=0; int n=0;
rfbClientToServerMsg msg; rfbClientToServerMsg msg;
char *str; 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 = rfbReadExact(cl, (char *)&msg, 1)) <= 0) {
if (n != 0) if (n != 0)
...@@ -1028,6 +1702,8 @@ rfbProcessClientNormalMessage(rfbClientPtr cl) ...@@ -1028,6 +1702,8 @@ rfbProcessClientNormalMessage(rfbClientPtr cl)
cl->readyForSetColourMapEntries = TRUE; cl->readyForSetColourMapEntries = TRUE;
cl->screen->setTranslateFunction(cl); cl->screen->setTranslateFunction(cl);
rfbStatRecordMessageRcvd(cl, msg.type, sz_rfbSetPixelFormatMsg, sz_rfbSetPixelFormatMsg);
return; return;
...@@ -1039,16 +1715,23 @@ rfbProcessClientNormalMessage(rfbClientPtr cl) ...@@ -1039,16 +1715,23 @@ rfbProcessClientNormalMessage(rfbClientPtr cl)
rfbCloseClient(cl); rfbCloseClient(cl);
return; return;
} }
rfbStatRecordMessageRcvd(cl, msg.type, sz_rfbSetPixelFormatMsg, sz_rfbSetPixelFormatMsg);
rfbLog("rfbProcessClientNormalMessage: %s", rfbLog("rfbProcessClientNormalMessage: %s",
"FixColourMapEntries unsupported\n"); "FixColourMapEntries unsupported\n");
rfbCloseClient(cl); rfbCloseClient(cl);
return; 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: case rfbSetEncodings:
{ {
int i;
uint32_t enc;
if ((n = rfbReadExact(cl, ((char *)&msg) + 1, if ((n = rfbReadExact(cl, ((char *)&msg) + 1,
sz_rfbSetEncodingsMsg - 1)) <= 0) { sz_rfbSetEncodingsMsg - 1)) <= 0) {
...@@ -1060,6 +1743,31 @@ rfbProcessClientNormalMessage(rfbClientPtr cl) ...@@ -1060,6 +1743,31 @@ rfbProcessClientNormalMessage(rfbClientPtr cl)
msg.se.nEncodings = Swap16IfLE(msg.se.nEncodings); 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++) { for (i = 0; i < msg.se.nEncodings; i++) {
if ((n = rfbReadExact(cl, (char *)&enc, 4)) <= 0) { if ((n = rfbReadExact(cl, (char *)&enc, 4)) <= 0) {
if (n != 0) if (n != 0)
...@@ -1075,58 +1783,23 @@ rfbProcessClientNormalMessage(rfbClientPtr cl) ...@@ -1075,58 +1783,23 @@ rfbProcessClientNormalMessage(rfbClientPtr cl)
cl->useCopyRect = TRUE; cl->useCopyRect = TRUE;
break; break;
case rfbEncodingRaw: case rfbEncodingRaw:
if (cl->preferredEncoding == -1) {
cl->preferredEncoding = enc;
rfbLog("Using raw encoding for client %s\n",
cl->host);
}
break;
case rfbEncodingRRE: case rfbEncodingRRE:
if (cl->preferredEncoding == -1) {
cl->preferredEncoding = enc;
rfbLog("Using rre encoding for client %s\n",
cl->host);
}
break;
case rfbEncodingCoRRE: case rfbEncodingCoRRE:
if (cl->preferredEncoding == -1) {
cl->preferredEncoding = enc;
rfbLog("Using CoRRE encoding for client %s\n",
cl->host);
}
break;
case rfbEncodingHextile: case rfbEncodingHextile:
if (cl->preferredEncoding == -1) {
cl->preferredEncoding = enc;
rfbLog("Using hextile encoding for client %s\n",
cl->host);
}
break;
case rfbEncodingUltra: case rfbEncodingUltra:
if (cl->preferredEncoding == -1) {
cl->preferredEncoding = enc;
rfbLog("Using Ultra encoding for client %s\n",
cl->host);
}
break;
#ifdef LIBVNCSERVER_HAVE_LIBZ #ifdef LIBVNCSERVER_HAVE_LIBZ
case rfbEncodingZlib: case rfbEncodingZlib:
if (cl->preferredEncoding == -1) { case rfbEncodingZRLE:
cl->preferredEncoding = enc;
rfbLog("Using zlib encoding for client %s\n",
cl->host);
}
break;
#ifdef LIBVNCSERVER_HAVE_LIBJPEG #ifdef LIBVNCSERVER_HAVE_LIBJPEG
case rfbEncodingTight: case rfbEncodingTight:
if (cl->preferredEncoding == -1) {
cl->preferredEncoding = enc;
rfbLog("Using tight encoding for client %s\n",
cl->host);
}
break;
#endif #endif
#endif #endif
/* The first supported encoding is the 'preferred' encoding */
if (cl->preferredEncoding == -1)
cl->preferredEncoding = enc;
break;
case rfbEncodingXCursor: case rfbEncodingXCursor:
if(!cl->screen->dontConvertRichCursorToXCursor) { if(!cl->screen->dontConvertRichCursorToXCursor) {
rfbLog("Enabling X-style cursor updates for client %s\n", rfbLog("Enabling X-style cursor updates for client %s\n",
...@@ -1200,15 +1873,6 @@ rfbProcessClientNormalMessage(rfbClientPtr cl) ...@@ -1200,15 +1873,6 @@ rfbProcessClientNormalMessage(rfbClientPtr cl)
cl->enableServerIdentity = TRUE; cl->enableServerIdentity = TRUE;
} }
break; 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: default:
#ifdef LIBVNCSERVER_HAVE_LIBZ #ifdef LIBVNCSERVER_HAVE_LIBZ
if ( enc >= (uint32_t)rfbEncodingCompressLevel0 && if ( enc >= (uint32_t)rfbEncodingCompressLevel0 &&
...@@ -1268,15 +1932,34 @@ rfbProcessClientNormalMessage(rfbClientPtr cl) ...@@ -1268,15 +1932,34 @@ rfbProcessClientNormalMessage(rfbClientPtr cl)
if(!handled) if(!handled)
rfbLog("rfbProcessClientNormalMessage: " rfbLog("rfbProcessClientNormalMessage: "
"ignoring unknown encoding type %d\n", "ignoring unsupported encoding type %s\n",
(int)enc); encodingName(enc,encBuf,sizeof(encBuf)));
} }
} }
} }
} }
if (cl->preferredEncoding == -1) { if (cl->preferredEncoding == -1) {
if (lastPreferredEncoding==-1) {
cl->preferredEncoding = rfbEncodingRaw; 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) { if (cl->enableCursorPosUpdates && !cl->enableCursorShapeUpdates) {
...@@ -1301,6 +1984,7 @@ rfbProcessClientNormalMessage(rfbClientPtr cl) ...@@ -1301,6 +1984,7 @@ rfbProcessClientNormalMessage(rfbClientPtr cl)
return; return;
} }
rfbStatRecordMessageRcvd(cl, msg.type, sz_rfbFramebufferUpdateRequestMsg,sz_rfbFramebufferUpdateRequestMsg);
/* The values come in based on the scaled screen, we need to convert them to /* The values come in based on the scaled screen, we need to convert them to
* values based on the main screen's coordinate system * values based on the main screen's coordinate system
...@@ -1347,8 +2031,6 @@ rfbProcessClientNormalMessage(rfbClientPtr cl) ...@@ -1347,8 +2031,6 @@ rfbProcessClientNormalMessage(rfbClientPtr cl)
case rfbKeyEvent: case rfbKeyEvent:
cl->keyEventsRcvd++;
if ((n = rfbReadExact(cl, ((char *)&msg) + 1, if ((n = rfbReadExact(cl, ((char *)&msg) + 1,
sz_rfbKeyEventMsg - 1)) <= 0) { sz_rfbKeyEventMsg - 1)) <= 0) {
if (n != 0) if (n != 0)
...@@ -1357,6 +2039,8 @@ rfbProcessClientNormalMessage(rfbClientPtr cl) ...@@ -1357,6 +2039,8 @@ rfbProcessClientNormalMessage(rfbClientPtr cl)
return; return;
} }
rfbStatRecordMessageRcvd(cl, msg.type, sz_rfbKeyEventMsg, sz_rfbKeyEventMsg);
if(!cl->viewOnly) { if(!cl->viewOnly) {
cl->screen->kbdAddEvent(msg.ke.down, (rfbKeySym)Swap32IfLE(msg.ke.key), cl); cl->screen->kbdAddEvent(msg.ke.down, (rfbKeySym)Swap32IfLE(msg.ke.key), cl);
} }
...@@ -1366,8 +2050,6 @@ rfbProcessClientNormalMessage(rfbClientPtr cl) ...@@ -1366,8 +2050,6 @@ rfbProcessClientNormalMessage(rfbClientPtr cl)
case rfbPointerEvent: case rfbPointerEvent:
cl->pointerEventsRcvd++;
if ((n = rfbReadExact(cl, ((char *)&msg) + 1, if ((n = rfbReadExact(cl, ((char *)&msg) + 1,
sz_rfbPointerEventMsg - 1)) <= 0) { sz_rfbPointerEventMsg - 1)) <= 0) {
if (n != 0) if (n != 0)
...@@ -1376,6 +2058,8 @@ rfbProcessClientNormalMessage(rfbClientPtr cl) ...@@ -1376,6 +2058,8 @@ rfbProcessClientNormalMessage(rfbClientPtr cl)
return; return;
} }
rfbStatRecordMessageRcvd(cl, msg.type, sz_rfbPointerEventMsg, sz_rfbPointerEventMsg);
if (cl->screen->pointerClient && cl->screen->pointerClient != cl) if (cl->screen->pointerClient && cl->screen->pointerClient != cl)
return; return;
...@@ -1401,6 +2085,115 @@ rfbProcessClientNormalMessage(rfbClientPtr cl) ...@@ -1401,6 +2085,115 @@ rfbProcessClientNormalMessage(rfbClientPtr cl)
return; 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: case rfbClientCutText:
if ((n = rfbReadExact(cl, ((char *)&msg) + 1, if ((n = rfbReadExact(cl, ((char *)&msg) + 1,
...@@ -1422,7 +2215,7 @@ rfbProcessClientNormalMessage(rfbClientPtr cl) ...@@ -1422,7 +2215,7 @@ rfbProcessClientNormalMessage(rfbClientPtr cl)
rfbCloseClient(cl); rfbCloseClient(cl);
return; return;
} }
rfbStatRecordMessageRcvd(cl, msg.type, sz_rfbClientCutTextMsg+msg.cct.length, sz_rfbClientCutTextMsg+msg.cct.length);
if(!cl->viewOnly) { if(!cl->viewOnly) {
cl->screen->setXCutText(str, msg.cct.length, cl); cl->screen->setXCutText(str, msg.cct.length, cl);
} }
...@@ -1432,6 +2225,20 @@ rfbProcessClientNormalMessage(rfbClientPtr cl) ...@@ -1432,6 +2225,20 @@ rfbProcessClientNormalMessage(rfbClientPtr cl)
case rfbPalmVNCSetScaleFactor: case rfbPalmVNCSetScaleFactor:
cl->PalmVNC = TRUE; 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: case rfbSetScale:
if ((n = rfbReadExact(cl, ((char *)&msg) + 1, if ((n = rfbReadExact(cl, ((char *)&msg) + 1,
...@@ -1441,11 +2248,11 @@ rfbProcessClientNormalMessage(rfbClientPtr cl) ...@@ -1441,11 +2248,11 @@ rfbProcessClientNormalMessage(rfbClientPtr cl)
rfbCloseClient(cl); rfbCloseClient(cl);
return; return;
} }
rfbStatRecordMessageRcvd(cl, msg.type, sz_rfbSetScaleMsg, sz_rfbSetScaleMsg);
rfbLog("rfbSetScale(%d)\n", msg.ssc.scale); rfbLog("rfbSetScale(%d)\n", msg.ssc.scale);
rfbScalingSetup(cl,cl->screen->width/msg.ssc.scale, cl->screen->height/msg.ssc.scale); rfbScalingSetup(cl,cl->screen->width/msg.ssc.scale, cl->screen->height/msg.ssc.scale);
rfbSendNewScaleSize(cl); rfbSendNewScaleSize(cl);
return; return;
default: default:
...@@ -1456,7 +2263,10 @@ rfbProcessClientNormalMessage(rfbClientPtr cl) ...@@ -1456,7 +2263,10 @@ rfbProcessClientNormalMessage(rfbClientPtr cl)
next = e->next; next = e->next;
if(e->extension->handleMessage && if(e->extension->handleMessage &&
e->extension->handleMessage(cl, e->data, &msg)) e->extension->handleMessage(cl, e->data, &msg))
{
rfbStatRecordMessageRcvd(cl, msg.type, 0, 0); /* Extension should handle this */
return; return;
}
e = next; e = next;
} }
...@@ -1508,7 +2318,6 @@ rfbSendFramebufferUpdate(rfbClientPtr cl, ...@@ -1508,7 +2318,6 @@ rfbSendFramebufferUpdate(rfbClientPtr cl,
LOCK(cl->updateMutex); LOCK(cl->updateMutex);
cl->newFBSizePending = FALSE; cl->newFBSizePending = FALSE;
UNLOCK(cl->updateMutex); UNLOCK(cl->updateMutex);
cl->framebufferUpdateMessagesSent++;
fu->type = rfbFramebufferUpdate; fu->type = rfbFramebufferUpdate;
fu->nRects = Swap16IfLE(1); fu->nRects = Swap16IfLE(1);
cl->ublen = sz_rfbFramebufferUpdateMsg; cl->ublen = sz_rfbFramebufferUpdateMsg;
...@@ -1693,8 +2502,8 @@ rfbSendFramebufferUpdate(rfbClientPtr cl, ...@@ -1693,8 +2502,8 @@ rfbSendFramebufferUpdate(rfbClientPtr cl,
/* /*
* Now send the update. * Now send the update.
*/ */
cl->framebufferUpdateMessagesSent++;
rfbStatRecordMessageSent(cl, rfbFramebufferUpdate, 0, 0);
if (cl->preferredEncoding == rfbEncodingCoRRE) { if (cl->preferredEncoding == rfbEncodingCoRRE) {
nUpdateRegionRects = 0; nUpdateRegionRects = 0;
...@@ -1843,9 +2652,6 @@ rfbSendFramebufferUpdate(rfbClientPtr cl, ...@@ -1843,9 +2652,6 @@ rfbSendFramebufferUpdate(rfbClientPtr cl,
if (cl->screen!=cl->scaledScreen) if (cl->screen!=cl->scaledScreen)
rfbScaledCorrection(cl->screen, cl->scaledScreen, &x, &y, &w, &h, "rfbSendFramebufferUpdate"); rfbScaledCorrection(cl->screen, cl->scaledScreen, &x, &y, &w, &h, "rfbSendFramebufferUpdate");
cl->rawBytesEquivalent += (sz_rfbFramebufferUpdateRectHeader
+ w * (cl->format.bitsPerPixel / 8) * h);
switch (cl->preferredEncoding) { switch (cl->preferredEncoding) {
case -1: case -1:
case rfbEncodingRaw: case rfbEncodingRaw:
...@@ -1961,10 +2767,8 @@ rfbSendCopyRegion(rfbClientPtr cl, ...@@ -1961,10 +2767,8 @@ rfbSendCopyRegion(rfbClientPtr cl,
memcpy(&cl->updateBuf[cl->ublen], (char *)&cr, sz_rfbCopyRect); memcpy(&cl->updateBuf[cl->ublen], (char *)&cr, sz_rfbCopyRect);
cl->ublen += sz_rfbCopyRect; cl->ublen += sz_rfbCopyRect;
cl->rectanglesSent[rfbEncodingCopyRect]++; rfbStatRecordEncodingSent(cl, rfbEncodingCopyRect, sz_rfbFramebufferUpdateRectHeader + sz_rfbCopyRect,
cl->bytesSent[rfbEncodingCopyRect] w * h * (cl->scaledScreen->bitsPerPixel / 8));
+= sz_rfbFramebufferUpdateRectHeader + sz_rfbCopyRect;
} }
sraRgnReleaseIterator(i); sraRgnReleaseIterator(i);
...@@ -2003,9 +2807,9 @@ rfbSendRectEncodingRaw(rfbClientPtr cl, ...@@ -2003,9 +2807,9 @@ rfbSendRectEncodingRaw(rfbClientPtr cl,
memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,sz_rfbFramebufferUpdateRectHeader); memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,sz_rfbFramebufferUpdateRectHeader);
cl->ublen += sz_rfbFramebufferUpdateRectHeader; cl->ublen += sz_rfbFramebufferUpdateRectHeader;
cl->rectanglesSent[rfbEncodingRaw]++;
cl->bytesSent[rfbEncodingRaw] rfbStatRecordEncodingSent(cl, rfbEncodingRaw, sz_rfbFramebufferUpdateRectHeader + bytesPerLine * h,
+= sz_rfbFramebufferUpdateRectHeader + bytesPerLine * h; sz_rfbFramebufferUpdateRectHeader + bytesPerLine * h);
nlines = (UPDATE_BUF_SIZE - cl->ublen) / bytesPerLine; nlines = (UPDATE_BUF_SIZE - cl->ublen) / bytesPerLine;
...@@ -2069,8 +2873,8 @@ rfbSendLastRectMarker(rfbClientPtr cl) ...@@ -2069,8 +2873,8 @@ rfbSendLastRectMarker(rfbClientPtr cl)
memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,sz_rfbFramebufferUpdateRectHeader); memcpy(&cl->updateBuf[cl->ublen], (char *)&rect,sz_rfbFramebufferUpdateRectHeader);
cl->ublen += sz_rfbFramebufferUpdateRectHeader; cl->ublen += sz_rfbFramebufferUpdateRectHeader;
cl->lastRectMarkersSent++;
cl->lastRectBytesSent += sz_rfbFramebufferUpdateRectHeader; rfbStatRecordEncodingSent(cl, rfbEncodingLastRect, sz_rfbFramebufferUpdateRectHeader, sz_rfbFramebufferUpdateRectHeader);
return TRUE; return TRUE;
} }
...@@ -2108,8 +2912,7 @@ rfbSendNewFBSize(rfbClientPtr cl, ...@@ -2108,8 +2912,7 @@ rfbSendNewFBSize(rfbClientPtr cl,
sz_rfbFramebufferUpdateRectHeader); sz_rfbFramebufferUpdateRectHeader);
cl->ublen += sz_rfbFramebufferUpdateRectHeader; cl->ublen += sz_rfbFramebufferUpdateRectHeader;
cl->lastRectMarkersSent++; rfbStatRecordEncodingSent(cl, rfbEncodingNewFBSize, sz_rfbFramebufferUpdateRectHeader, sz_rfbFramebufferUpdateRectHeader);
cl->lastRectBytesSent += sz_rfbFramebufferUpdateRectHeader;
return TRUE; return TRUE;
} }
...@@ -2181,6 +2984,8 @@ rfbSendSetColourMapEntries(rfbClientPtr cl, ...@@ -2181,6 +2984,8 @@ rfbSendSetColourMapEntries(rfbClientPtr cl,
rfbCloseClient(cl); rfbCloseClient(cl);
return FALSE; return FALSE;
} }
rfbStatRecordMessageSent(cl, rfbSetColourMapEntries, len, len);
return TRUE; return TRUE;
} }
...@@ -2203,6 +3008,7 @@ rfbSendBell(rfbScreenInfoPtr rfbScreen) ...@@ -2203,6 +3008,7 @@ rfbSendBell(rfbScreenInfoPtr rfbScreen)
rfbCloseClient(cl); rfbCloseClient(cl);
} }
} }
rfbStatRecordMessageSent(cl, rfbBell, sz_rfbBellMsg, sz_rfbBellMsg);
rfbReleaseClientIterator(i); rfbReleaseClientIterator(i);
} }
...@@ -2232,6 +3038,7 @@ rfbSendServerCutText(rfbScreenInfoPtr rfbScreen,char *str, int len) ...@@ -2232,6 +3038,7 @@ rfbSendServerCutText(rfbScreenInfoPtr rfbScreen,char *str, int len)
rfbLogPerror("rfbSendServerCutText: write"); rfbLogPerror("rfbSendServerCutText: write");
rfbCloseClient(cl); rfbCloseClient(cl);
} }
rfbStatRecordMessageSent(cl, rfbServerCutText, sz_rfbServerCutTextMsg+len, sz_rfbServerCutTextMsg+len);
} }
rfbReleaseClientIterator(iterator); rfbReleaseClientIterator(iterator);
} }
......
...@@ -40,7 +40,7 @@ static char *rreBeforeBuf = NULL; ...@@ -40,7 +40,7 @@ static char *rreBeforeBuf = NULL;
static int rreAfterBufSize = 0; static int rreAfterBufSize = 0;
static char *rreAfterBuf = NULL; static char *rreAfterBuf = NULL;
static int rreAfterBufLen; static int rreAfterBufLen=0;
static int subrectEncode8(uint8_t *data, int w, int h); static int subrectEncode8(uint8_t *data, int w, int h);
static int subrectEncode16(uint16_t *data, int w, int h); static int subrectEncode16(uint16_t *data, int w, int h);
...@@ -112,9 +112,9 @@ rfbSendRectEncodingRRE(rfbClientPtr cl, ...@@ -112,9 +112,9 @@ rfbSendRectEncodingRRE(rfbClientPtr cl,
return rfbSendRectEncodingRaw(cl, x, y, w, h); return rfbSendRectEncodingRaw(cl, x, y, w, h);
} }
cl->rectanglesSent[rfbEncodingRRE]++; rfbStatRecordEncodingSent(cl, rfbEncodingRRE,
cl->bytesSent[rfbEncodingRRE] += (sz_rfbFramebufferUpdateRectHeader sz_rfbFramebufferUpdateRectHeader + sz_rfbRREHeader + rreAfterBufLen,
+ sz_rfbRREHeader + rreAfterBufLen); sz_rfbFramebufferUpdateRectHeader + w * h * (cl->format.bitsPerPixel / 8));
if (cl->ublen + sz_rfbFramebufferUpdateRectHeader + sz_rfbRREHeader if (cl->ublen + sz_rfbFramebufferUpdateRectHeader + sz_rfbRREHeader
> UPDATE_BUF_SIZE) > UPDATE_BUF_SIZE)
......
...@@ -128,8 +128,8 @@ void rfbScaledCorrection(rfbScreenInfoPtr from, rfbScreenInfoPtr to, int *x, int ...@@ -128,8 +128,8 @@ void rfbScaledCorrection(rfbScreenInfoPtr from, rfbScreenInfoPtr to, int *x, int
*h = (int)h2; *h = (int)h2;
/* Small changes for a thumbnail may be scaled to zero */ /* Small changes for a thumbnail may be scaled to zero */
if (*w==0) *w++; if (*w==0) (*w)++;
if (*h==0) *h++; if (*h==0) (*h)++;
/* scaling from small to big may overstep the size a bit */ /* scaling from small to big may overstep the size a bit */
if (*x+*w > to->width) *w=to->width - *x; if (*x+*w > to->width) *w=to->width - *x;
if (*y+*h > to->height) *h=to->height - *y; if (*y+*h > to->height) *h=to->height - *y;
...@@ -212,7 +212,9 @@ void rfbScaledScreenUpdateRect(rfbScreenInfoPtr screen, rfbScreenInfoPtr ptr, in ...@@ -212,7 +212,9 @@ void rfbScaledScreenUpdateRect(rfbScreenInfoPtr screen, rfbScreenInfoPtr ptr, in
pixel_value += (srcptr2[z] << (8 * z)); pixel_value += (srcptr2[z] << (8 * z));
break; break;
} }
//srcptr2 += bytesPerPixel; /*
srcptr2 += bytesPerPixel;
*/
red += ((pixel_value >> redShift) & redMax); red += ((pixel_value >> redShift) & redMax);
green += ((pixel_value >> greenShift) & greenMax); green += ((pixel_value >> greenShift) & greenMax);
......
...@@ -239,8 +239,18 @@ rfbCheckFds(rfbScreenInfoPtr rfbScreen,long usec) ...@@ -239,8 +239,18 @@ rfbCheckFds(rfbScreenInfoPtr rfbScreen,long usec)
tv.tv_usec = usec; tv.tv_usec = usec;
nfds = select(rfbScreen->maxFd + 1, &fds, NULL, NULL /* &fds */, &tv); nfds = select(rfbScreen->maxFd + 1, &fds, NULL, NULL /* &fds */, &tv);
if (nfds == 0) { 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; return result;
} }
if (nfds < 0) { if (nfds < 0) {
#ifdef WIN32 #ifdef WIN32
errno = WSAGetLastError(); errno = WSAGetLastError();
...@@ -332,11 +342,17 @@ rfbCheckFds(rfbScreenInfoPtr rfbScreen,long usec) ...@@ -332,11 +342,17 @@ rfbCheckFds(rfbScreenInfoPtr rfbScreen,long usec)
i = rfbGetClientIterator(rfbScreen); i = rfbGetClientIterator(rfbScreen);
while((cl = rfbClientIteratorNext(i))) { while((cl = rfbClientIteratorNext(i))) {
if (cl->onHold) if (cl->onHold)
continue; continue;
if (FD_ISSET(cl->sock, &fds) &&
FD_ISSET(cl->sock, &(rfbScreen->allFds))) if (FD_ISSET(cl->sock, &(rfbScreen->allFds)))
{
if (FD_ISSET(cl->sock, &fds))
rfbProcessClientMessage(cl); rfbProcessClientMessage(cl);
else
rfbSendFileTransferChunk(cl);
}
} }
rfbReleaseClientIterator(i); rfbReleaseClientIterator(i);
} while(rfbScreen->handleEventsEagerly); } while(rfbScreen->handleEventsEagerly);
......
...@@ -26,90 +26,434 @@ ...@@ -26,90 +26,434 @@
#include <rfb/rfb.h> #include <rfb/rfb.h>
static const char* encNames[] = { char *messageNameServer2Client(uint32_t type, char *buf, int len);
"raw", "copyRect", "RRE", "[encoding 3]", "CoRRE", "hextile", char *messageNameClient2Server(uint32_t type, char *buf, int len);
"zlib", "tight", "[encoding 8]", "ultra", "[encoding 10]", char *encodingName(uint32_t enc, char *buf, int len);
"[encoding 11]", "[encoding 12]", "[encoding 13]", "[encoding 14]",
"[encoding 15]",
"ZRLE", "[encoding 17]", "[encoding 18]", "[encoding 19]", "[encoding 20]"
};
rfbStatList *rfbStatLookupEncoding(rfbClientPtr cl, uint32_t type);
rfbStatList *rfbStatLookupMessage(rfbClientPtr cl, uint32_t type);
void void rfbStatRecordEncodingSent(rfbClientPtr cl, uint32_t type, int byteCount, int byteIfRaw);
rfbResetStats(rfbClientPtr cl) 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; rfbStatList *ptr;
for (i = 0; i < MAX_ENCODINGS; i++) { if (cl==NULL) return NULL;
cl->bytesSent[i] = 0; for (ptr = cl->statEncList; ptr!=NULL; ptr=ptr->Next)
cl->rectanglesSent[i] = 0; {
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;
}
return ptr;
}
rfbStatList *rfbStatLookupMessage(rfbClientPtr cl, uint32_t type)
{
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;
} }
cl->lastRectMarkersSent = 0; return ptr;
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;
} }
void void rfbStatRecordEncodingSentAdd(rfbClientPtr cl, uint32_t type, int byteCount) /* Specifically for tight encoding */
rfbPrintStats(rfbClientPtr cl)
{ {
int i; rfbStatList *ptr;
int totalRectanglesSent = 0;
int totalBytesSent = 0; ptr = rfbStatLookupEncoding(cl, type);
if (ptr!=NULL)
ptr->bytesSent += byteCount;
}
rfbLog("Statistics:\n");
if ((cl->keyEventsRcvd != 0) || (cl->pointerEventsRcvd != 0)) void rfbStatRecordEncodingSent(rfbClientPtr cl, uint32_t type, int byteCount, int byteIfRaw)
rfbLog(" key events received %d, pointer events %d\n", {
cl->keyEventsRcvd, cl->pointerEventsRcvd); rfbStatList *ptr;
for (i = 0; i < MAX_ENCODINGS; i++) { ptr = rfbStatLookupEncoding(cl, type);
totalRectanglesSent += cl->rectanglesSent[i]; if (ptr!=NULL)
totalBytesSent += cl->bytesSent[i]; {
ptr->sentCount++;
ptr->bytesSent += byteCount;
ptr->bytesSentIfRaw += byteIfRaw;
} }
}
totalRectanglesSent += (cl->cursorShapeUpdatesSent + void rfbStatRecordEncodingRcvd(rfbClientPtr cl, uint32_t type, int byteCount, int byteIfRaw)
cl->cursorPosUpdatesSent + {
cl->lastRectMarkersSent); rfbStatList *ptr;
totalBytesSent += (cl->cursorShapeBytesSent +
cl->cursorPosBytesSent +
cl->lastRectBytesSent);
rfbLog(" framebuffer updates %d, rectangles %d, bytes %d\n", ptr = rfbStatLookupEncoding(cl, type);
cl->framebufferUpdateMessagesSent, totalRectanglesSent, if (ptr!=NULL)
totalBytesSent); {
ptr->rcvdCount++;
ptr->bytesRcvd += byteCount;
ptr->bytesRcvdIfRaw += byteIfRaw;
}
}
if (cl->lastRectMarkersSent != 0) void rfbStatRecordMessageSent(rfbClientPtr cl, uint32_t type, int byteCount, int byteIfRaw)
rfbLog(" LastRect and NewFBSize markers %d, bytes %d\n", {
cl->lastRectMarkersSent, cl->lastRectBytesSent); rfbStatList *ptr;
if (cl->cursorShapeUpdatesSent != 0) ptr = rfbStatLookupMessage(cl, type);
rfbLog(" cursor shape updates %d, bytes %d\n", if (ptr!=NULL)
cl->cursorShapeUpdatesSent, cl->cursorShapeBytesSent); {
ptr->sentCount++;
ptr->bytesSent += byteCount;
ptr->bytesSentIfRaw += byteIfRaw;
}
}
if (cl->cursorPosUpdatesSent != 0) void rfbStatRecordMessageRcvd(rfbClientPtr cl, uint32_t type, int byteCount, int byteIfRaw)
rfbLog(" cursor position updates %d, bytes %d\n", {
cl->cursorPosUpdatesSent, cl->cursorPosBytesSent); rfbStatList *ptr;
for (i = 0; i < MAX_ENCODINGS; i++) { ptr = rfbStatLookupMessage(cl, type);
if (cl->rectanglesSent[i] != 0) if (ptr!=NULL)
rfbLog(" %s rectangles %d, bytes %d\n", {
encNames[i], cl->rectanglesSent[i], cl->bytesSent[i]); 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;
}
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);
}
}
if ((totalBytesSent - cl->bytesSent[rfbEncodingCopyRect]) != 0) { void rfbPrintStats(rfbClientPtr cl)
rfbLog(" raw bytes equivalent %d, compression ratio %f\n", {
cl->rawBytesEquivalent, rfbStatList *ptr=NULL;
(double)cl->rawBytesEquivalent char encBuf[64];
/ (double)(totalBytesSent double savings=0.0;
- cl->bytesSent[rfbEncodingCopyRect]- int totalRectsSent=0;
cl->cursorShapeBytesSent - double totalBytesSent=0.0;
cl->cursorPosBytesSent - double totalBytesIfRawSent=0.0;
cl->lastRectBytesSent)); 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);
} }
...@@ -663,8 +663,8 @@ SendTightHeader(rfbClientPtr cl, ...@@ -663,8 +663,8 @@ SendTightHeader(rfbClientPtr cl,
sz_rfbFramebufferUpdateRectHeader); sz_rfbFramebufferUpdateRectHeader);
cl->ublen += sz_rfbFramebufferUpdateRectHeader; cl->ublen += sz_rfbFramebufferUpdateRectHeader;
cl->rectanglesSent[rfbEncodingTight]++; rfbStatRecordEncodingSent(cl, rfbEncodingTight, sz_rfbFramebufferUpdateRectHeader,
cl->bytesSent[rfbEncodingTight] += sz_rfbFramebufferUpdateRectHeader; sz_rfbFramebufferUpdateRectHeader + w * (cl->format.bitsPerPixel / 8) * h);
return TRUE; return TRUE;
} }
...@@ -693,7 +693,7 @@ SendSolidRect(rfbClientPtr cl) ...@@ -693,7 +693,7 @@ SendSolidRect(rfbClientPtr cl)
memcpy (&cl->updateBuf[cl->ublen], tightBeforeBuf, len); memcpy (&cl->updateBuf[cl->ublen], tightBeforeBuf, len);
cl->ublen += len; cl->ublen += len;
cl->bytesSent[rfbEncodingTight] += len + 1; rfbStatRecordEncodingSentAdd(cl, rfbEncodingTight, len+1);
return TRUE; return TRUE;
} }
...@@ -736,7 +736,7 @@ SendMonoRect(rfbClientPtr cl, ...@@ -736,7 +736,7 @@ SendMonoRect(rfbClientPtr cl,
memcpy(&cl->updateBuf[cl->ublen], tightAfterBuf, paletteLen); memcpy(&cl->updateBuf[cl->ublen], tightAfterBuf, paletteLen);
cl->ublen += paletteLen; cl->ublen += paletteLen;
cl->bytesSent[rfbEncodingTight] += 3 + paletteLen; rfbStatRecordEncodingSentAdd(cl, rfbEncodingTight, 3 + paletteLen);
break; break;
case 16: case 16:
...@@ -747,7 +747,7 @@ SendMonoRect(rfbClientPtr cl, ...@@ -747,7 +747,7 @@ SendMonoRect(rfbClientPtr cl,
memcpy(&cl->updateBuf[cl->ublen], tightAfterBuf, 4); memcpy(&cl->updateBuf[cl->ublen], tightAfterBuf, 4);
cl->ublen += 4; cl->ublen += 4;
cl->bytesSent[rfbEncodingTight] += 7; rfbStatRecordEncodingSentAdd(cl, rfbEncodingTight, 7);
break; break;
default: default:
...@@ -755,7 +755,7 @@ SendMonoRect(rfbClientPtr cl, ...@@ -755,7 +755,7 @@ SendMonoRect(rfbClientPtr cl,
cl->updateBuf[cl->ublen++] = (char)monoBackground; cl->updateBuf[cl->ublen++] = (char)monoBackground;
cl->updateBuf[cl->ublen++] = (char)monoForeground; cl->updateBuf[cl->ublen++] = (char)monoForeground;
cl->bytesSent[rfbEncodingTight] += 5; rfbStatRecordEncodingSentAdd(cl, rfbEncodingTight, 5);
} }
return CompressData(cl, streamId, dataLen, return CompressData(cl, streamId, dataLen,
...@@ -801,7 +801,7 @@ SendIndexedRect(rfbClientPtr cl, ...@@ -801,7 +801,7 @@ SendIndexedRect(rfbClientPtr cl,
memcpy(&cl->updateBuf[cl->ublen], tightAfterBuf, paletteNumColors * entryLen); memcpy(&cl->updateBuf[cl->ublen], tightAfterBuf, paletteNumColors * entryLen);
cl->ublen += paletteNumColors * entryLen; cl->ublen += paletteNumColors * entryLen;
cl->bytesSent[rfbEncodingTight] += 3 + paletteNumColors * entryLen; rfbStatRecordEncodingSentAdd(cl, rfbEncodingTight, 3 + paletteNumColors * entryLen);
break; break;
case 16: case 16:
...@@ -814,7 +814,7 @@ SendIndexedRect(rfbClientPtr cl, ...@@ -814,7 +814,7 @@ SendIndexedRect(rfbClientPtr cl,
memcpy(&cl->updateBuf[cl->ublen], tightAfterBuf, paletteNumColors * 2); memcpy(&cl->updateBuf[cl->ublen], tightAfterBuf, paletteNumColors * 2);
cl->ublen += paletteNumColors * 2; cl->ublen += paletteNumColors * 2;
cl->bytesSent[rfbEncodingTight] += 3 + paletteNumColors * 2; rfbStatRecordEncodingSentAdd(cl, rfbEncodingTight, 3 + paletteNumColors * 2);
break; break;
default: default:
...@@ -840,7 +840,7 @@ SendFullColorRect(rfbClientPtr cl, ...@@ -840,7 +840,7 @@ SendFullColorRect(rfbClientPtr cl,
} }
cl->updateBuf[cl->ublen++] = 0x00; /* stream id = 0, no flushing, no filter */ cl->updateBuf[cl->ublen++] = 0x00; /* stream id = 0, no flushing, no filter */
cl->bytesSent[rfbEncodingTight]++; rfbStatRecordEncodingSentAdd(cl, rfbEncodingTight, 1);
if (usePixelFormat24) { if (usePixelFormat24) {
Pack24(cl, tightBeforeBuf, &cl->format, w * h); Pack24(cl, tightBeforeBuf, &cl->format, w * h);
...@@ -874,7 +874,7 @@ SendGradientRect(rfbClientPtr cl, ...@@ -874,7 +874,7 @@ SendGradientRect(rfbClientPtr cl,
cl->updateBuf[cl->ublen++] = (streamId | rfbTightExplicitFilter) << 4; cl->updateBuf[cl->ublen++] = (streamId | rfbTightExplicitFilter) << 4;
cl->updateBuf[cl->ublen++] = rfbTightFilterGradient; cl->updateBuf[cl->ublen++] = rfbTightFilterGradient;
cl->bytesSent[rfbEncodingTight] += 2; rfbStatRecordEncodingSentAdd(cl, rfbEncodingTight, 2);
if (usePixelFormat24) { if (usePixelFormat24) {
FilterGradient24(cl, tightBeforeBuf, &cl->format, w, h); FilterGradient24(cl, tightBeforeBuf, &cl->format, w, h);
...@@ -905,7 +905,7 @@ CompressData(rfbClientPtr cl, ...@@ -905,7 +905,7 @@ CompressData(rfbClientPtr cl,
if (dataLen < TIGHT_MIN_TO_COMPRESS) { if (dataLen < TIGHT_MIN_TO_COMPRESS) {
memcpy(&cl->updateBuf[cl->ublen], tightBeforeBuf, dataLen); memcpy(&cl->updateBuf[cl->ublen], tightBeforeBuf, dataLen);
cl->ublen += dataLen; cl->ublen += dataLen;
cl->bytesSent[rfbEncodingTight] += dataLen; rfbStatRecordEncodingSentAdd(cl, rfbEncodingTight, dataLen);
return TRUE; return TRUE;
} }
...@@ -955,15 +955,15 @@ static rfbBool SendCompressedData(rfbClientPtr cl, ...@@ -955,15 +955,15 @@ static rfbBool SendCompressedData(rfbClientPtr cl,
int i, portionLen; int i, portionLen;
cl->updateBuf[cl->ublen++] = compressedLen & 0x7F; cl->updateBuf[cl->ublen++] = compressedLen & 0x7F;
cl->bytesSent[rfbEncodingTight]++; rfbStatRecordEncodingSentAdd(cl, rfbEncodingTight, 1);
if (compressedLen > 0x7F) { if (compressedLen > 0x7F) {
cl->updateBuf[cl->ublen-1] |= 0x80; cl->updateBuf[cl->ublen-1] |= 0x80;
cl->updateBuf[cl->ublen++] = compressedLen >> 7 & 0x7F; cl->updateBuf[cl->ublen++] = compressedLen >> 7 & 0x7F;
cl->bytesSent[rfbEncodingTight]++; rfbStatRecordEncodingSentAdd(cl, rfbEncodingTight, 1);
if (compressedLen > 0x3FFF) { if (compressedLen > 0x3FFF) {
cl->updateBuf[cl->ublen-1] |= 0x80; cl->updateBuf[cl->ublen-1] |= 0x80;
cl->updateBuf[cl->ublen++] = compressedLen >> 14 & 0xFF; cl->updateBuf[cl->ublen++] = compressedLen >> 14 & 0xFF;
cl->bytesSent[rfbEncodingTight]++; rfbStatRecordEncodingSentAdd(cl, rfbEncodingTight, 1);
} }
} }
...@@ -979,7 +979,7 @@ static rfbBool SendCompressedData(rfbClientPtr cl, ...@@ -979,7 +979,7 @@ static rfbBool SendCompressedData(rfbClientPtr cl,
memcpy(&cl->updateBuf[cl->ublen], &tightAfterBuf[i], portionLen); memcpy(&cl->updateBuf[cl->ublen], &tightAfterBuf[i], portionLen);
cl->ublen += portionLen; cl->ublen += portionLen;
} }
cl->bytesSent[rfbEncodingTight] += compressedLen; rfbStatRecordEncodingSentAdd(cl, rfbEncodingTight, compressedLen);
return TRUE; return TRUE;
} }
...@@ -1686,7 +1686,7 @@ SendJpegRect(rfbClientPtr cl, int x, int y, int w, int h, int quality) ...@@ -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->updateBuf[cl->ublen++] = (char)(rfbTightJpeg << 4);
cl->bytesSent[rfbEncodingTight]++; rfbStatRecordEncodingSentAdd(cl, rfbEncodingTight, 1);
return SendCompressedData(cl, jpegDstDataLen); return SendCompressedData(cl, jpegDstDataLen);
} }
......
...@@ -28,6 +28,12 @@ ...@@ -28,6 +28,12 @@
#include <rfb/rfb.h> #include <rfb/rfb.h>
#include <limits.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 #define rfbSecTypeTight 16
void rfbTightUsage(void); void rfbTightUsage(void);
......
...@@ -101,9 +101,7 @@ rfbSendOneRectEncodingUltra(rfbClientPtr cl, ...@@ -101,9 +101,7 @@ rfbSendOneRectEncodingUltra(rfbClientPtr cl,
} }
/* Update statics */ /* Update statics */
cl->rectanglesSent[rfbEncodingUltra]++; rfbStatRecordEncodingSent(cl, rfbEncodingUltra, sz_rfbFramebufferUpdateRectHeader + sz_rfbZlibHeader + lzoAfterBufLen, maxRawSize);
cl->bytesSent[rfbEncodingUltra] += (sz_rfbFramebufferUpdateRectHeader
+ sz_rfbZlibHeader + lzoAfterBufLen);
if (cl->ublen + sz_rfbFramebufferUpdateRectHeader + sz_rfbZlibHeader if (cl->ublen + sz_rfbFramebufferUpdateRectHeader + sz_rfbZlibHeader
> UPDATE_BUF_SIZE) > UPDATE_BUF_SIZE)
......
...@@ -121,6 +121,7 @@ rfbSendOneRectEncodingZlib(rfbClientPtr cl, ...@@ -121,6 +121,7 @@ rfbSendOneRectEncodingZlib(rfbClientPtr cl,
zlibAfterBuf = (char *)realloc(zlibAfterBuf, zlibAfterBufSize); zlibAfterBuf = (char *)realloc(zlibAfterBuf, zlibAfterBufSize);
} }
/* /*
* Convert pixel data to client format. * Convert pixel data to client format.
*/ */
...@@ -176,9 +177,8 @@ rfbSendOneRectEncodingZlib(rfbClientPtr cl, ...@@ -176,9 +177,8 @@ rfbSendOneRectEncodingZlib(rfbClientPtr cl,
*/ */
/* Update statics */ /* Update statics */
cl->rectanglesSent[rfbEncodingZlib]++; rfbStatRecordEncodingSent(cl, rfbEncodingZlib, sz_rfbFramebufferUpdateRectHeader + sz_rfbZlibHeader + zlibAfterBufLen,
cl->bytesSent[rfbEncodingZlib] += (sz_rfbFramebufferUpdateRectHeader + w * (cl->format.bitsPerPixel / 8) * h);
+ sz_rfbZlibHeader + zlibAfterBufLen);
if (cl->ublen + sz_rfbFramebufferUpdateRectHeader + sz_rfbZlibHeader if (cl->ublen + sz_rfbFramebufferUpdateRectHeader + sz_rfbZlibHeader
> UPDATE_BUF_SIZE) > UPDATE_BUF_SIZE)
......
...@@ -124,9 +124,8 @@ rfbBool rfbSendRectEncodingZRLE(rfbClientPtr cl, int x, int y, int w, int h) ...@@ -124,9 +124,8 @@ rfbBool rfbSendRectEncodingZRLE(rfbClientPtr cl, int x, int y, int w, int h)
break; break;
} }
cl->rectanglesSent[rfbEncodingZRLE]++; rfbStatRecordEncodingSent(cl, rfbEncodingZRLE, sz_rfbFramebufferUpdateRectHeader + sz_rfbZRLEHeader + ZRLE_BUFFER_LENGTH(&zos->out),
cl->bytesSent[rfbEncodingZRLE] += (sz_rfbFramebufferUpdateRectHeader + w * (cl->format.bitsPerPixel / 8) * h);
+ sz_rfbZRLEHeader + ZRLE_BUFFER_LENGTH(&zos->out));
if (cl->ublen + sz_rfbFramebufferUpdateRectHeader + sz_rfbZRLEHeader if (cl->ublen + sz_rfbFramebufferUpdateRectHeader + sz_rfbZRLEHeader
> UPDATE_BUF_SIZE) > UPDATE_BUF_SIZE)
......
...@@ -137,7 +137,21 @@ typedef enum rfbNewClientAction (*rfbNewClientHookPtr)(struct _rfbClientRec* cl) ...@@ -137,7 +137,21 @@ typedef enum rfbNewClientAction (*rfbNewClientHookPtr)(struct _rfbClientRec* cl)
typedef void (*rfbDisplayHookPtr)(struct _rfbClientRec* cl); typedef void (*rfbDisplayHookPtr)(struct _rfbClientRec* cl);
/* support the capability to view the caps/num/scroll states of the X server */ /* 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 { typedef struct {
uint32_t count; uint32_t count;
...@@ -296,6 +310,10 @@ typedef struct _rfbScreenInfo ...@@ -296,6 +310,10 @@ typedef struct _rfbScreenInfo
rfbSetXCutTextProcPtr setXCutText; rfbSetXCutTextProcPtr setXCutText;
rfbGetCursorProcPtr getCursorPtr; rfbGetCursorProcPtr getCursorPtr;
rfbSetTranslateFunctionProcPtr setTranslateFunction; rfbSetTranslateFunctionProcPtr setTranslateFunction;
rfbSetSingleWindowProcPtr setSingleWindow;
rfbSetServerInputProcPtr setServerInput;
rfbFileTransferPermitted getFileTransferPermission;
rfbSetTextChat setTextChat;
/* newClientHook is called just after a new client is created */ /* newClientHook is called just after a new client is created */
rfbNewClientHookPtr newClientHook; rfbNewClientHookPtr newClientHook;
...@@ -326,6 +344,10 @@ typedef struct _rfbScreenInfo ...@@ -326,6 +344,10 @@ typedef struct _rfbScreenInfo
/* rfbEncodingServerIdentity */ /* rfbEncodingServerIdentity */
char *versionString; char *versionString;
/* What does the server tell the new clients which version it supports */
int protocolMajorVersion;
int protocolMinorVersion;
} rfbScreenInfo, *rfbScreenInfoPtr; } rfbScreenInfo, *rfbScreenInfoPtr;
...@@ -351,6 +373,27 @@ typedef struct sraRegion* sraRegionPtr; ...@@ -351,6 +373,27 @@ typedef struct sraRegion* sraRegionPtr;
typedef void (*ClientGoneHookPtr)(struct _rfbClientRec* cl); 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 { typedef struct _rfbClientRec {
/* back pointer to the screen */ /* back pointer to the screen */
...@@ -467,19 +510,10 @@ typedef struct _rfbClientRec { ...@@ -467,19 +510,10 @@ typedef struct _rfbClientRec {
int ublen; int ublen;
/* statistics */ /* statistics */
struct _rfbStatList *statEncList;
int bytesSent[MAX_ENCODINGS]; struct _rfbStatList *statMsgList;
int rectanglesSent[MAX_ENCODINGS];
int lastRectMarkersSent;
int lastRectBytesSent;
int cursorShapeBytesSent;
int cursorShapeUpdatesSent;
int cursorPosBytesSent;
int cursorPosUpdatesSent;
int framebufferUpdateMessagesSent;
int rawBytesEquivalent; int rawBytesEquivalent;
int keyEventsRcvd; int bytesSent;
int pointerEventsRcvd;
#ifdef LIBVNCSERVER_HAVE_LIBZ #ifdef LIBVNCSERVER_HAVE_LIBZ
/* zlib encoding -- necessary compression state info per client */ /* zlib encoding -- necessary compression state info per client */
...@@ -502,6 +536,7 @@ typedef struct _rfbClientRec { ...@@ -502,6 +536,7 @@ typedef struct _rfbClientRec {
rfbBool compStreamInitedLZO; rfbBool compStreamInitedLZO;
char *lzoWrkMem; char *lzoWrkMem;
rfbFileTransferData fileTransfer;
int lastKeyboardLedState; /* keep track of last value so we can send *change* events */ int lastKeyboardLedState; /* keep track of last value so we can send *change* events */
rfbBool enableSupportedMessages; /* client supports SupportedMessages encoding */ rfbBool enableSupportedMessages; /* client supports SupportedMessages encoding */
...@@ -584,6 +619,11 @@ extern char rfbEndianTest; ...@@ -584,6 +619,11 @@ extern char rfbEndianTest;
#define Swap24IfLE(l) (rfbEndianTest ? Swap24(l) : (l)) #define Swap24IfLE(l) (rfbEndianTest ? Swap24(l) : (l))
#define Swap32IfLE(l) (rfbEndianTest ? Swap32(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 */ /* sockets.c */
extern int rfbMaxClientWait; extern int rfbMaxClientWait;
...@@ -634,6 +674,13 @@ extern rfbBool rfbSendNewFBSize(rfbClientPtr cl, int w, int h); ...@@ -634,6 +674,13 @@ extern rfbBool rfbSendNewFBSize(rfbClientPtr cl, int w, int h);
extern rfbBool rfbSendSetColourMapEntries(rfbClientPtr cl, int firstColour, int nColours); extern rfbBool rfbSendSetColourMapEntries(rfbClientPtr cl, int firstColour, int nColours);
extern void rfbSendBell(rfbScreenInfoPtr rfbScreen); 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); void rfbGotXCutText(rfbScreenInfoPtr rfbScreen, char *str, int len);
/* translate.c */ /* translate.c */
...@@ -880,6 +927,38 @@ extern rfbBool rfbIsActive(rfbScreenInfoPtr screenInfo); ...@@ -880,6 +927,38 @@ extern rfbBool rfbIsActive(rfbScreenInfoPtr screenInfo);
void rfbRegisterTightVNCFileTransferExtension(); void rfbRegisterTightVNCFileTransferExtension();
void rfbUnregisterTightVNCFileTransferExtension(); 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 #endif
#if(defined __cplusplus) #if(defined __cplusplus)
......
...@@ -96,6 +96,7 @@ typedef struct { ...@@ -96,6 +96,7 @@ typedef struct {
struct _rfbClient; struct _rfbClient;
typedef void (*HandleTextChatProc)(struct _rfbClient* client, int value, char *text);
typedef void (*HandleKeyboardLedStateProc)(struct _rfbClient* client, int value, int pad); typedef void (*HandleKeyboardLedStateProc)(struct _rfbClient* client, int value, int pad);
typedef rfbBool (*HandleCursorPosProc)(struct _rfbClient* client, int x, int y); typedef rfbBool (*HandleCursorPosProc)(struct _rfbClient* client, int x, int y);
typedef void (*SoftCursorLockAreaProc)(struct _rfbClient* client, int x, int y, int w, int h); typedef void (*SoftCursorLockAreaProc)(struct _rfbClient* client, int x, int y, int w, int h);
...@@ -210,6 +211,7 @@ typedef struct _rfbClient { ...@@ -210,6 +211,7 @@ typedef struct _rfbClient {
int canHandleNewFBSize; int canHandleNewFBSize;
/* hooks */ /* hooks */
HandleTextChatProc HandleTextChat;
HandleKeyboardLedStateProc HandleKeyboardLedState; HandleKeyboardLedStateProc HandleKeyboardLedState;
HandleCursorPosProc HandleCursorPos; HandleCursorPosProc HandleCursorPos;
SoftCursorLockAreaProc SoftCursorLockArea; SoftCursorLockAreaProc SoftCursorLockArea;
...@@ -219,6 +221,19 @@ typedef struct _rfbClient { ...@@ -219,6 +221,19 @@ typedef struct _rfbClient {
GetPasswordProc GetPassword; GetPasswordProc GetPassword;
MallocFrameBufferProc MallocFrameBuffer; MallocFrameBufferProc MallocFrameBuffer;
BellProc Bell; 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; } rfbClient;
/* cursor.c */ /* cursor.c */
...@@ -247,6 +262,12 @@ extern rfbBool SendKeyEvent(rfbClient* client,uint32_t key, rfbBool down); ...@@ -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 SendClientCutText(rfbClient* client,char *str, int len);
extern rfbBool HandleRFBServerMessage(rfbClient* client); 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); extern void PrintPixelFormat(rfbPixelFormat *format);
/* client data */ /* client data */
......
...@@ -218,8 +218,10 @@ typedef struct { ...@@ -218,8 +218,10 @@ typedef struct {
#define rfbProtocolVersionFormat "RFB %03d.%03d\n" #define rfbProtocolVersionFormat "RFB %03d.%03d\n"
#define rfbProtocolMajorVersion 3 #define rfbProtocolMajorVersion 3
#define rfbProtocolMinorVersion 7 #define rfbProtocolMinorVersion 6
#define rfbProtocolFallbackMinorVersion 3 /* 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 */ typedef char rfbProtocolVersionMsg[13]; /* allow extra byte for null */
...@@ -397,24 +399,18 @@ typedef struct { ...@@ -397,24 +399,18 @@ typedef struct {
#define rfbEncodingRRE 2 #define rfbEncodingRRE 2
#define rfbEncodingCoRRE 4 #define rfbEncodingCoRRE 4
#define rfbEncodingHextile 5 #define rfbEncodingHextile 5
#ifdef LIBVNCSERVER_HAVE_LIBZ
#define rfbEncodingZlib 6 #define rfbEncodingZlib 6
#define rfbEncodingTight 7 #define rfbEncodingTight 7
#define rfbEncodingZlibHex 8 #define rfbEncodingZlibHex 8
#endif
#define rfbEncodingUltra 9 #define rfbEncodingUltra 9
#ifdef LIBVNCSERVER_HAVE_LIBZ
#define rfbEncodingZRLE 16 #define rfbEncodingZRLE 16
#endif
/* Cache & XOR-Zlib - rdv@2002 */ /* Cache & XOR-Zlib - rdv@2002 */
#define rfbEncodingCache 0xFFFF0000 #define rfbEncodingCache 0xFFFF0000
#define rfbEncodingCacheEnable 0xFFFF0001 #define rfbEncodingCacheEnable 0xFFFF0001
#ifdef LIBVNCSERVER_HAVE_LIBZ
#define rfbEncodingXOR_Zlib 0xFFFF0002 #define rfbEncodingXOR_Zlib 0xFFFF0002
#define rfbEncodingXORMonoColor_Zlib 0xFFFF0003 #define rfbEncodingXORMonoColor_Zlib 0xFFFF0003
#define rfbEncodingXORMultiColor_Zlib 0xFFFF0004 #define rfbEncodingXORMultiColor_Zlib 0xFFFF0004
#endif
#define rfbEncodingSolidColor 0xFFFF0005 #define rfbEncodingSolidColor 0xFFFF0005
#define rfbEncodingXOREnable 0xFFFF0006 #define rfbEncodingXOREnable 0xFFFF0006
#define rfbEncodingCacheZip 0xFFFF0007 #define rfbEncodingCacheZip 0xFFFF0007
...@@ -649,11 +645,11 @@ typedef struct { ...@@ -649,11 +645,11 @@ typedef struct {
#define rfbHextileExtractW(byte) (((byte) >> 4) + 1) #define rfbHextileExtractW(byte) (((byte) >> 4) + 1)
#define rfbHextileExtractH(byte) (((byte) & 0xf) + 1) #define rfbHextileExtractH(byte) (((byte) & 0xf) + 1)
#ifdef LIBVNCSERVER_HAVE_LIBZ
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* zlib - zlib compressed Encoding. We have an rfbZlibHeader structure * zlib - zlib compressed Encoding. We have an rfbZlibHeader structure
* giving the number of bytes following. Finally the data follows is * giving the number of bytes following. Finally the data follows is
* zlib compressed version of the raw pixel data as negotiated. * zlib compressed version of the raw pixel data as negotiated.
* (NOTE: also used by Ultra Encoding)
*/ */
typedef struct { typedef struct {
...@@ -662,6 +658,7 @@ typedef struct { ...@@ -662,6 +658,7 @@ typedef struct {
#define sz_rfbZlibHeader 4 #define sz_rfbZlibHeader 4
#ifdef LIBVNCSERVER_HAVE_LIBZ
/*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /*- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* Tight Encoding. * Tight Encoding.
...@@ -935,9 +932,10 @@ typedef struct { ...@@ -935,9 +932,10 @@ typedef struct {
typedef struct _rfbFileTransferMsg { typedef struct _rfbFileTransferMsg {
uint8_t type; /* always rfbFileTransfer */ uint8_t type; /* always rfbFileTransfer */
uint8_t contentType; /* See defines below */ uint8_t contentType; /* See defines below */
uint16_t contentParam;/* Other possible content classification (Dir or File name, etc..) */ 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 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 sizeH; Additional 32Bits params to handle big values. Only for V2 (we want backward compatibility between all V1 versions) */
uint32_t length; uint32_t length;
/* followed by data char text[length] */ /* followed by data char text[length] */
} rfbFileTransferMsg; } rfbFileTransferMsg;
......
...@@ -350,11 +350,8 @@ db = 0; ...@@ -350,11 +350,8 @@ db = 0;
} }
nclients++; nclients++;
cbs = 0; cbs = rfbStatGetSentBytes(cl);
for (i=0; i<MAX_ENCODINGS; i++) { rbs = rfbStatGetSentBytesIfRaw(cl);
cbs += cl->bytesSent[i];
}
rbs = cl->rawBytesEquivalent;
if (init) { if (init) {
...@@ -435,7 +432,7 @@ if (db) fprintf(stderr, "%d client num rects req: %d mod: %d cbs: %d " ...@@ -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 " if (db) fprintf(stderr, "dt2 calc: num rects req: %d/%d mod: %d/%d "
"fbu-sent: %d dt: %.4f dt2: %.4f tm: %.4f\n", "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) { if (req1 != 0 && mod1 == 0) {
got_t2 = 1; got_t2 = 1;
break; break;
...@@ -502,7 +499,7 @@ if (db) fprintf(stderr, "dt2 calc: num rects req: %d/%d mod: %d/%d " ...@@ -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 " if (db) fprintf(stderr, "dt3 calc: num rects req: %d/%d mod: %d/%d "
"fbu-sent: %d dt: %.4f dt3: %.4f tm: %.4f\n", "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) { if (req1 != 0 && mod1 == 0) {
dts[got_t3++] = dt3; dts[got_t3++] = dt3;
......
...@@ -4082,7 +4082,7 @@ int fb_update_sent(int *count) { ...@@ -4082,7 +4082,7 @@ int fb_update_sent(int *count) {
i = rfbGetClientIterator(screen); i = rfbGetClientIterator(screen);
while( (cl = rfbClientIteratorNext(i)) ) { while( (cl = rfbClientIteratorNext(i)) ) {
sent += cl->framebufferUpdateMessagesSent; sent += rfbStatGetMessageCountSent(cl, rfbFramebufferUpdate);
} }
rfbReleaseClientIterator(i); rfbReleaseClientIterator(i);
if (sent != last_count) { if (sent != last_count) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment