Commit e5523350 authored by Christian Beier's avatar Christian Beier

libvnc[server|client]: implement xvp VNC extension.

This implements the xvp VNC extension, which is described in the
community version of the RFB protocol:
http://tigervnc.sourceforge.net/cgi-bin/rfbproto
It is also mentioned in the official RFB protocol.
parent 5da7c7a7
...@@ -1230,6 +1230,9 @@ SetFormatAndEncodings(rfbClient* client) ...@@ -1230,6 +1230,9 @@ SetFormatAndEncodings(rfbClient* client)
if (se->nEncodings < MAX_ENCODINGS) if (se->nEncodings < MAX_ENCODINGS)
encs[se->nEncodings++] = rfbClientSwap32IfLE(rfbEncodingServerIdentity); encs[se->nEncodings++] = rfbClientSwap32IfLE(rfbEncodingServerIdentity);
/* xvp */
if (se->nEncodings < MAX_ENCODINGS)
encs[se->nEncodings++] = rfbClientSwap32IfLE(rfbEncodingXvp);
/* client extensions */ /* client extensions */
for(e = rfbClientExtensions; e; e = e->next) for(e = rfbClientExtensions; e; e = e->next)
...@@ -1394,6 +1397,37 @@ rfbBool PermitServerInput(rfbClient* client, int enabled) ...@@ -1394,6 +1397,37 @@ rfbBool PermitServerInput(rfbClient* client, int enabled)
} }
/*
* send xvp client message
* A client supporting the xvp extension sends this to request that the server initiate
* a clean shutdown, clean reboot or abrupt reset of the system whose framebuffer the
* client is displaying.
*
* only version 1 is defined in the protocol specs
*
* possible values for code are:
* rfbXvp_Shutdown
* rfbXvp_Reboot
* rfbXvp_Reset
*/
rfbBool SendXvpMsg(rfbClient* client, uint8_t version, uint8_t code)
{
rfbXvpMsg xvp;
if (!SupportsClient2Server(client, rfbXvp)) return TRUE;
xvp.type = rfbXvp;
xvp.pad = 0;
xvp.version = version;
xvp.code = code;
if (!WriteToRFBServer(client, (char *)&xvp, sz_rfbXvpMsg))
return FALSE;
return TRUE;
}
/* /*
* SendPointerEvent. * SendPointerEvent.
*/ */
...@@ -1984,6 +2018,24 @@ HandleRFBServerMessage(rfbClient* client) ...@@ -1984,6 +2018,24 @@ HandleRFBServerMessage(rfbClient* client)
break; break;
} }
case rfbXvp:
{
if (!ReadFromRFBServer(client, ((char *)&msg) + 1,
sz_rfbXvpMsg -1))
return FALSE;
SetClient2Server(client, rfbXvp);
/* technically, we only care what we can *send* to the server
* but, we set Server2Client Just in case it ever becomes useful
*/
SetServer2Client(client, rfbXvp);
if(client->HandleXvpMsg)
client->HandleXvpMsg(client, msg.xvp.version, msg.xvp.code);
break;
}
case rfbResizeFrameBuffer: case rfbResizeFrameBuffer:
{ {
if (!ReadFromRFBServer(client, ((char *)&msg) + 1, if (!ReadFromRFBServer(client, ((char *)&msg) + 1,
......
...@@ -901,6 +901,7 @@ rfbScreenInfoPtr rfbGetScreen(int* argc,char** argv, ...@@ -901,6 +901,7 @@ rfbScreenInfoPtr rfbGetScreen(int* argc,char** argv,
screen->displayHook = NULL; screen->displayHook = NULL;
screen->displayFinishedHook = NULL; screen->displayFinishedHook = NULL;
screen->getKeyboardLedStateHook = NULL; screen->getKeyboardLedStateHook = NULL;
screen->xvpHook = NULL;
/* initialize client list and iterator mutex */ /* initialize client list and iterator mutex */
rfbClientListInit(screen); rfbClientListInit(screen);
......
...@@ -874,6 +874,7 @@ rfbSendSupportedMessages(rfbClientPtr cl) ...@@ -874,6 +874,7 @@ rfbSendSupportedMessages(rfbClientPtr cl)
/*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.client2server, rfbXvp);
rfbSetBit(msgs.server2client, rfbFramebufferUpdate); rfbSetBit(msgs.server2client, rfbFramebufferUpdate);
rfbSetBit(msgs.server2client, rfbSetColourMapEntries); rfbSetBit(msgs.server2client, rfbSetColourMapEntries);
...@@ -882,6 +883,7 @@ rfbSendSupportedMessages(rfbClientPtr cl) ...@@ -882,6 +883,7 @@ rfbSendSupportedMessages(rfbClientPtr cl)
rfbSetBit(msgs.server2client, rfbResizeFrameBuffer); rfbSetBit(msgs.server2client, rfbResizeFrameBuffer);
/*rfbSetBit(msgs.server2client, rfbKeyFrameUpdate); */ /*rfbSetBit(msgs.server2client, rfbKeyFrameUpdate); */
rfbSetBit(msgs.server2client, rfbPalmVNCReSizeFrameBuffer); rfbSetBit(msgs.server2client, rfbPalmVNCReSizeFrameBuffer);
rfbSetBit(msgs.server2client, rfbXvp);
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;
...@@ -1027,6 +1029,33 @@ rfbSendServerIdentity(rfbClientPtr cl) ...@@ -1027,6 +1029,33 @@ rfbSendServerIdentity(rfbClientPtr cl)
return TRUE; return TRUE;
} }
/*
* Send an xvp server message
*/
rfbBool
rfbSendXvp(rfbClientPtr cl, uint8_t version, uint8_t code)
{
rfbXvpMsg xvp;
xvp.type = rfbXvp;
xvp.pad = 0;
xvp.version = version;
xvp.code = code;
LOCK(cl->sendMutex);
if (rfbWriteExact(cl, (char *)&xvp, sz_rfbXvpMsg) < 0) {
rfbLogPerror("rfbSendXvp: write");
rfbCloseClient(cl);
}
UNLOCK(cl->sendMutex);
rfbStatRecordMessageSent(cl, rfbXvp, sz_rfbXvpMsg, sz_rfbXvpMsg);
return TRUE;
}
rfbBool rfbSendTextChatMessage(rfbClientPtr cl, uint32_t length, char *buffer) rfbBool rfbSendTextChatMessage(rfbClientPtr cl, uint32_t length, char *buffer)
{ {
rfbTextChatMsg tc; rfbTextChatMsg tc;
...@@ -1985,6 +2014,14 @@ rfbProcessClientNormalMessage(rfbClientPtr cl) ...@@ -1985,6 +2014,14 @@ rfbProcessClientNormalMessage(rfbClientPtr cl)
cl->enableServerIdentity = TRUE; cl->enableServerIdentity = TRUE;
} }
break; break;
case rfbEncodingXvp:
rfbLog("Enabling Xvp protocol extension for client "
"%s\n", cl->host);
if (!rfbSendXvp(cl, 1, rfbXvp_Init)) {
rfbCloseClient(cl);
return;
}
break;
default: default:
#ifdef LIBVNCSERVER_HAVE_LIBZ #ifdef LIBVNCSERVER_HAVE_LIBZ
if ( enc >= (uint32_t)rfbEncodingCompressLevel0 && if ( enc >= (uint32_t)rfbEncodingCompressLevel0 &&
...@@ -2368,6 +2405,28 @@ rfbProcessClientNormalMessage(rfbClientPtr cl) ...@@ -2368,6 +2405,28 @@ rfbProcessClientNormalMessage(rfbClientPtr cl)
rfbSendNewScaleSize(cl); rfbSendNewScaleSize(cl);
return; return;
case rfbXvp:
if ((n = rfbReadExact(cl, ((char *)&msg) + 1,
sz_rfbXvpMsg - 1)) <= 0) {
if (n != 0)
rfbLogPerror("rfbProcessClientNormalMessage: read");
rfbCloseClient(cl);
return;
}
rfbStatRecordMessageRcvd(cl, msg.type, sz_rfbXvpMsg, sz_rfbXvpMsg);
/* only version when is defined, so echo back a fail */
if(msg.xvp.version != 1) {
rfbSendXvp(cl, msg.xvp.version, rfbXvp_Fail);
}
else {
/* if the hook exists and fails, send a fail msg */
if(cl->screen->xvpHook && !cl->screen->xvpHook(cl, msg.xvp.version, msg.xvp.code))
rfbSendXvp(cl, 1, rfbXvp_Fail);
}
return;
default: default:
{ {
rfbExtensionData *e,*next; rfbExtensionData *e,*next;
......
...@@ -55,6 +55,7 @@ char *messageNameServer2Client(uint32_t type, char *buf, int len) { ...@@ -55,6 +55,7 @@ char *messageNameServer2Client(uint32_t type, char *buf, int len) {
case rfbFileTransfer: snprintf(buf, len, "FileTransfer"); break; case rfbFileTransfer: snprintf(buf, len, "FileTransfer"); break;
case rfbTextChat: snprintf(buf, len, "TextChat"); break; case rfbTextChat: snprintf(buf, len, "TextChat"); break;
case rfbPalmVNCReSizeFrameBuffer: snprintf(buf, len, "PalmVNCReSize"); break; case rfbPalmVNCReSizeFrameBuffer: snprintf(buf, len, "PalmVNCReSize"); break;
case rfbXvp: snprintf(buf, len, "XvpServerMessage"); break;
default: default:
snprintf(buf, len, "svr2cli-0x%08X", 0xFF); snprintf(buf, len, "svr2cli-0x%08X", 0xFF);
} }
...@@ -78,6 +79,7 @@ char *messageNameClient2Server(uint32_t type, char *buf, int len) { ...@@ -78,6 +79,7 @@ char *messageNameClient2Server(uint32_t type, char *buf, int len) {
case rfbTextChat: snprintf(buf, len, "TextChat"); break; case rfbTextChat: snprintf(buf, len, "TextChat"); break;
case rfbKeyFrameRequest: snprintf(buf, len, "KeyFrameRequest"); break; case rfbKeyFrameRequest: snprintf(buf, len, "KeyFrameRequest"); break;
case rfbPalmVNCSetScaleFactor: snprintf(buf, len, "PalmVNCSetScale"); break; case rfbPalmVNCSetScaleFactor: snprintf(buf, len, "PalmVNCSetScale"); break;
case rfbXvp: snprintf(buf, len, "XvpClientMessage"); break;
default: default:
snprintf(buf, len, "cli2svr-0x%08X", type); snprintf(buf, len, "cli2svr-0x%08X", type);
......
...@@ -139,6 +139,7 @@ typedef void (*rfbDisplayHookPtr)(struct _rfbClientRec* cl); ...@@ -139,6 +139,7 @@ typedef void (*rfbDisplayHookPtr)(struct _rfbClientRec* cl);
typedef void (*rfbDisplayFinishedHookPtr)(struct _rfbClientRec* cl, int result); typedef void (*rfbDisplayFinishedHookPtr)(struct _rfbClientRec* cl, int result);
/* 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);
typedef rfbBool (*rfbXvpHookPtr)(struct _rfbClientRec* cl, uint8_t, uint8_t);
/* If x==1 and y==1 then set the whole display /* 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 * else find the window underneath x and y and set the framebuffer to the dimensions
* of that window * of that window
...@@ -356,6 +357,8 @@ typedef struct _rfbScreenInfo ...@@ -356,6 +357,8 @@ typedef struct _rfbScreenInfo
/* displayFinishedHook is called just after a frame buffer update */ /* displayFinishedHook is called just after a frame buffer update */
rfbDisplayFinishedHookPtr displayFinishedHook; rfbDisplayFinishedHookPtr displayFinishedHook;
/* xvpHook is called to handle an xvp client message */
rfbXvpHookPtr xvpHook;
} rfbScreenInfo, *rfbScreenInfoPtr; } rfbScreenInfo, *rfbScreenInfoPtr;
......
...@@ -136,6 +136,7 @@ typedef union _rfbCredential ...@@ -136,6 +136,7 @@ typedef union _rfbCredential
struct _rfbClient; struct _rfbClient;
typedef void (*HandleTextChatProc)(struct _rfbClient* client, int value, char *text); typedef void (*HandleTextChatProc)(struct _rfbClient* client, int value, char *text);
typedef void (*HandleXvpMsgProc)(struct _rfbClient* client, uint8_t version, uint8_t opcode);
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);
...@@ -316,6 +317,9 @@ typedef struct _rfbClient { ...@@ -316,6 +317,9 @@ typedef struct _rfbClient {
/* the QoS IP DSCP for this client */ /* the QoS IP DSCP for this client */
int QoS_DSCP; int QoS_DSCP;
/* hook to handle xvp server messages */
HandleXvpMsgProc HandleXvpMsg;
} rfbClient; } rfbClient;
/* cursor.c */ /* cursor.c */
...@@ -352,6 +356,7 @@ extern rfbBool TextChatOpen(rfbClient* client); ...@@ -352,6 +356,7 @@ extern rfbBool TextChatOpen(rfbClient* client);
extern rfbBool TextChatClose(rfbClient* client); extern rfbBool TextChatClose(rfbClient* client);
extern rfbBool TextChatFinish(rfbClient* client); extern rfbBool TextChatFinish(rfbClient* client);
extern rfbBool PermitServerInput(rfbClient* client, int enabled); extern rfbBool PermitServerInput(rfbClient* client, int enabled);
extern rfbBool SendXvpMsg(rfbClient* client, uint8_t version, uint8_t code);
extern void PrintPixelFormat(rfbPixelFormat *format); extern void PrintPixelFormat(rfbPixelFormat *format);
......
...@@ -106,7 +106,7 @@ typedef uint32_t in_addr_t; ...@@ -106,7 +106,7 @@ typedef uint32_t in_addr_t;
#define INADDR_NONE ((in_addr_t) 0xffffffff) #define INADDR_NONE ((in_addr_t) 0xffffffff)
#endif #endif
#define MAX_ENCODINGS 20 #define MAX_ENCODINGS 21
/***************************************************************************** /*****************************************************************************
* *
...@@ -405,6 +405,8 @@ typedef struct { ...@@ -405,6 +405,8 @@ typedef struct {
#define rfbKeyFrameRequest 12 #define rfbKeyFrameRequest 12
/* PalmVNC 1.4 & 2.0 SetScale Factor message */ /* PalmVNC 1.4 & 2.0 SetScale Factor message */
#define rfbPalmVNCSetScaleFactor 0xF #define rfbPalmVNCSetScaleFactor 0xF
/* Xvp message - bidirectional */
#define rfbXvp 250
...@@ -439,6 +441,9 @@ typedef struct { ...@@ -439,6 +441,9 @@ typedef struct {
#define rfbEncodingSolMonoZip 0xFFFF0008 #define rfbEncodingSolMonoZip 0xFFFF0008
#define rfbEncodingUltraZip 0xFFFF0009 #define rfbEncodingUltraZip 0xFFFF0009
/* Xvp pseudo-encoding */
#define rfbEncodingXvp 0xFFFFFECB
/* /*
* Special encoding numbers: * Special encoding numbers:
* 0xFFFFFF00 .. 0xFFFFFF0F -- encoding-specific compression levels; * 0xFFFFFF00 .. 0xFFFFFF0F -- encoding-specific compression levels;
...@@ -1061,6 +1066,44 @@ typedef struct _rfbTextChatMsg { ...@@ -1061,6 +1066,44 @@ typedef struct _rfbTextChatMsg {
#define rfbTextChatFinished 0xFFFFFFFD #define rfbTextChatFinished 0xFFFFFFFD
/*-----------------------------------------------------------------------------
* Xvp Message
* Bidirectional message
* A server which supports the xvp extension declares this by sending a message
* with an Xvp_INIT xvp-message-code when it receives a request from the client
* to use the xvp Pseudo-encoding. The server must specify in this message the
* highest xvp-extension-version it supports: the client may assume that the
* server supports all versions from 1 up to this value. The client is then
* free to use any supported version. Currently, only version 1 is defined.
*
* A server which subsequently receives an xvp Client Message requesting an
* operation which it is unable to perform, informs the client of this by
* sending a message with an Xvp_FAIL xvp-message-code, and the same
* xvp-extension-version as included in the client's operation request.
*
* A client supporting the xvp extension sends this to request that the server
* initiate a clean shutdown, clean reboot or abrupt reset of the system whose
* framebuffer the client is displaying.
*/
typedef struct {
uint8_t type; /* always rfbXvp */
uint8_t pad;
uint8_t version; /* xvp extension version */
uint8_t code; /* xvp message code */
} rfbXvpMsg;
#define sz_rfbXvpMsg (4)
/* server message codes */
#define rfbXvp_Fail 0
#define rfbXvp_Init 1
/* client message codes */
#define rfbXvp_Shutdown 2
#define rfbXvp_Reboot 3
#define rfbXvp_Reset 4
/*----------------------------------------------------------------------------- /*-----------------------------------------------------------------------------
* Modif sf@2002 * Modif sf@2002
...@@ -1115,6 +1158,7 @@ typedef union { ...@@ -1115,6 +1158,7 @@ typedef union {
rfbPalmVNCReSizeFrameBufferMsg prsfb; rfbPalmVNCReSizeFrameBufferMsg prsfb;
rfbFileTransferMsg ft; rfbFileTransferMsg ft;
rfbTextChatMsg tc; rfbTextChatMsg tc;
rfbXvpMsg xvp;
} rfbServerToClientMsg; } rfbServerToClientMsg;
...@@ -1350,6 +1394,7 @@ typedef struct _rfbSetSWMsg { ...@@ -1350,6 +1394,7 @@ typedef struct _rfbSetSWMsg {
#define sz_rfbSetSWMsg 6 #define sz_rfbSetSWMsg 6
/*----------------------------------------------------------------------------- /*-----------------------------------------------------------------------------
* Union of all client->server messages. * Union of all client->server messages.
*/ */
...@@ -1369,6 +1414,7 @@ typedef union { ...@@ -1369,6 +1414,7 @@ typedef union {
rfbFileTransferMsg ft; rfbFileTransferMsg ft;
rfbSetSWMsg sw; rfbSetSWMsg sw;
rfbTextChatMsg tc; rfbTextChatMsg tc;
rfbXvpMsg xvp;
} rfbClientToServerMsg; } rfbClientToServerMsg;
/* /*
......
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