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)
if (se->nEncodings < MAX_ENCODINGS)
encs[se->nEncodings++] = rfbClientSwap32IfLE(rfbEncodingServerIdentity);
/* xvp */
if (se->nEncodings < MAX_ENCODINGS)
encs[se->nEncodings++] = rfbClientSwap32IfLE(rfbEncodingXvp);
/* client extensions */
for(e = rfbClientExtensions; e; e = e->next)
......@@ -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.
*/
......@@ -1984,6 +2018,24 @@ HandleRFBServerMessage(rfbClient* client)
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:
{
if (!ReadFromRFBServer(client, ((char *)&msg) + 1,
......
......@@ -901,6 +901,7 @@ rfbScreenInfoPtr rfbGetScreen(int* argc,char** argv,
screen->displayHook = NULL;
screen->displayFinishedHook = NULL;
screen->getKeyboardLedStateHook = NULL;
screen->xvpHook = NULL;
/* initialize client list and iterator mutex */
rfbClientListInit(screen);
......
......@@ -874,6 +874,7 @@ rfbSendSupportedMessages(rfbClientPtr cl)
/*rfbSetBit(msgs.client2server, rfbTextChat); */
/*rfbSetBit(msgs.client2server, rfbKeyFrameRequest); */
rfbSetBit(msgs.client2server, rfbPalmVNCSetScaleFactor);
rfbSetBit(msgs.client2server, rfbXvp);
rfbSetBit(msgs.server2client, rfbFramebufferUpdate);
rfbSetBit(msgs.server2client, rfbSetColourMapEntries);
......@@ -882,6 +883,7 @@ rfbSendSupportedMessages(rfbClientPtr cl)
rfbSetBit(msgs.server2client, rfbResizeFrameBuffer);
/*rfbSetBit(msgs.server2client, rfbKeyFrameUpdate); */
rfbSetBit(msgs.server2client, rfbPalmVNCReSizeFrameBuffer);
rfbSetBit(msgs.server2client, rfbXvp);
memcpy(&cl->updateBuf[cl->ublen], (char *)&msgs, sz_rfbSupportedMessages);
cl->ublen += sz_rfbSupportedMessages;
......@@ -1027,6 +1029,33 @@ rfbSendServerIdentity(rfbClientPtr cl)
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)
{
rfbTextChatMsg tc;
......@@ -1984,7 +2013,15 @@ rfbProcessClientNormalMessage(rfbClientPtr cl)
"%s\n", cl->host);
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:
#ifdef LIBVNCSERVER_HAVE_LIBZ
if ( enc >= (uint32_t)rfbEncodingCompressLevel0 &&
......@@ -2368,6 +2405,28 @@ rfbProcessClientNormalMessage(rfbClientPtr cl)
rfbSendNewScaleSize(cl);
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:
{
rfbExtensionData *e,*next;
......@@ -2756,7 +2815,7 @@ rfbSendFramebufferUpdate(rfbClientPtr cl,
if (!rfbSendServerIdentity(cl))
goto updateFailed;
}
if (!sraRgnEmpty(updateCopyRegion)) {
if (!rfbSendCopyRegion(cl,updateCopyRegion,dx,dy))
goto updateFailed;
......
......@@ -55,6 +55,7 @@ char *messageNameServer2Client(uint32_t type, char *buf, int len) {
case rfbFileTransfer: snprintf(buf, len, "FileTransfer"); break;
case rfbTextChat: snprintf(buf, len, "TextChat"); break;
case rfbPalmVNCReSizeFrameBuffer: snprintf(buf, len, "PalmVNCReSize"); break;
case rfbXvp: snprintf(buf, len, "XvpServerMessage"); break;
default:
snprintf(buf, len, "svr2cli-0x%08X", 0xFF);
}
......@@ -78,6 +79,7 @@ char *messageNameClient2Server(uint32_t type, char *buf, int len) {
case rfbTextChat: snprintf(buf, len, "TextChat"); break;
case rfbKeyFrameRequest: snprintf(buf, len, "KeyFrameRequest"); break;
case rfbPalmVNCSetScaleFactor: snprintf(buf, len, "PalmVNCSetScale"); break;
case rfbXvp: snprintf(buf, len, "XvpClientMessage"); break;
default:
snprintf(buf, len, "cli2svr-0x%08X", type);
......
......@@ -139,6 +139,7 @@ typedef void (*rfbDisplayHookPtr)(struct _rfbClientRec* cl);
typedef void (*rfbDisplayFinishedHookPtr)(struct _rfbClientRec* cl, int result);
/* support the capability to view the caps/num/scroll states of the X server */
typedef int (*rfbGetKeyboardLedStateHookPtr)(struct _rfbScreenInfo* screen);
typedef rfbBool (*rfbXvpHookPtr)(struct _rfbClientRec* cl, uint8_t, uint8_t);
/* If x==1 and y==1 then set the whole display
* else find the window underneath x and y and set the framebuffer to the dimensions
* of that window
......@@ -356,6 +357,8 @@ typedef struct _rfbScreenInfo
/* displayFinishedHook is called just after a frame buffer update */
rfbDisplayFinishedHookPtr displayFinishedHook;
/* xvpHook is called to handle an xvp client message */
rfbXvpHookPtr xvpHook;
} rfbScreenInfo, *rfbScreenInfoPtr;
......
......@@ -136,6 +136,7 @@ typedef union _rfbCredential
struct _rfbClient;
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 rfbBool (*HandleCursorPosProc)(struct _rfbClient* client, int x, int y);
typedef void (*SoftCursorLockAreaProc)(struct _rfbClient* client, int x, int y, int w, int h);
......@@ -316,6 +317,9 @@ typedef struct _rfbClient {
/* the QoS IP DSCP for this client */
int QoS_DSCP;
/* hook to handle xvp server messages */
HandleXvpMsgProc HandleXvpMsg;
} rfbClient;
/* cursor.c */
......@@ -352,6 +356,7 @@ extern rfbBool TextChatOpen(rfbClient* client);
extern rfbBool TextChatClose(rfbClient* client);
extern rfbBool TextChatFinish(rfbClient* client);
extern rfbBool PermitServerInput(rfbClient* client, int enabled);
extern rfbBool SendXvpMsg(rfbClient* client, uint8_t version, uint8_t code);
extern void PrintPixelFormat(rfbPixelFormat *format);
......
......@@ -106,7 +106,7 @@ typedef uint32_t in_addr_t;
#define INADDR_NONE ((in_addr_t) 0xffffffff)
#endif
#define MAX_ENCODINGS 20
#define MAX_ENCODINGS 21
/*****************************************************************************
*
......@@ -405,6 +405,8 @@ typedef struct {
#define rfbKeyFrameRequest 12
/* PalmVNC 1.4 & 2.0 SetScale Factor message */
#define rfbPalmVNCSetScaleFactor 0xF
/* Xvp message - bidirectional */
#define rfbXvp 250
......@@ -439,6 +441,9 @@ typedef struct {
#define rfbEncodingSolMonoZip 0xFFFF0008
#define rfbEncodingUltraZip 0xFFFF0009
/* Xvp pseudo-encoding */
#define rfbEncodingXvp 0xFFFFFECB
/*
* Special encoding numbers:
* 0xFFFFFF00 .. 0xFFFFFF0F -- encoding-specific compression levels;
......@@ -1061,6 +1066,44 @@ typedef struct _rfbTextChatMsg {
#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
......@@ -1115,6 +1158,7 @@ typedef union {
rfbPalmVNCReSizeFrameBufferMsg prsfb;
rfbFileTransferMsg ft;
rfbTextChatMsg tc;
rfbXvpMsg xvp;
} rfbServerToClientMsg;
......@@ -1350,6 +1394,7 @@ typedef struct _rfbSetSWMsg {
#define sz_rfbSetSWMsg 6
/*-----------------------------------------------------------------------------
* Union of all client->server messages.
*/
......@@ -1369,6 +1414,7 @@ typedef union {
rfbFileTransferMsg ft;
rfbSetSWMsg sw;
rfbTextChatMsg tc;
rfbXvpMsg xvp;
} 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