1#include <rfb/rfb.h>
2
3/**
4 * @example backchannel.c
5 * This is a simple example demonstrating a protocol extension.
6 *
7 * The "back channel" permits sending commands between client and server.
8 * It works by sending plain text messages.
9 *
10 * As suggested in the RFB protocol, the back channel is enabled by asking
11 * for a "pseudo encoding", and enabling the back channel on the client side
12 * as soon as it gets a back channel message from the server.
13 *
14 * This implements the server part.
15 *
16 * Note: If you design your own extension and want it to be useful for others,
17 * too, you should make sure that
18 *
19 * - your server as well as your client can speak to other clients and
20 *   servers respectively (i.e. they are nice if they are talking to a
21 *   program which does not know about your extension).
22 *
23 * - if the machine is little endian, all 16-bit and 32-bit integers are
24 *   swapped before they are sent and after they are received.
25 *
26 */
27
28#define rfbBackChannel 155
29
30typedef struct backChannelMsg {
31	uint8_t type;
32	uint8_t pad1;
33	uint16_t pad2;
34	uint32_t size;
35} backChannelMsg;
36
37rfbBool enableBackChannel(rfbClientPtr cl, void** data, int encoding)
38{
39	if(encoding == rfbBackChannel) {
40		backChannelMsg msg;
41		const char* text="Server acknowledges back channel encoding\n";
42		uint32_t length = strlen(text)+1;
43		int n;
44
45		rfbLog("Enabling the back channel\n");
46
47		msg.type = rfbBackChannel;
48		msg.size = Swap32IfLE(length);
49		if((n = rfbWriteExact(cl, (char*)&msg, sizeof(msg))) <= 0 ||
50				(n = rfbWriteExact(cl, text, length)) <= 0) {
51			rfbLogPerror("enableBackChannel: write");
52		}
53		return TRUE;
54	}
55	return FALSE;
56}
57
58static rfbBool handleBackChannelMessage(rfbClientPtr cl, void* data,
59		const rfbClientToServerMsg* message)
60{
61	if(message->type == rfbBackChannel) {
62		backChannelMsg msg;
63		char* text;
64		int n;
65		if((n = rfbReadExact(cl, ((char*)&msg)+1, sizeof(backChannelMsg)-1)) <= 0) {
66			if(n != 0)
67				rfbLogPerror("handleBackChannelMessage: read");
68			rfbCloseClient(cl);
69			return TRUE;
70		}
71		msg.size = Swap32IfLE(msg.size);
72		if((text = malloc(msg.size)) == NULL) {
73			rfbErr("Could not allocate %d bytes\n", msg.size);
74			return TRUE;
75		}
76		if((n = rfbReadExact(cl, text, msg.size)) <= 0) {
77			if(n != 0)
78				rfbLogPerror("handleBackChannelMessage: read");
79			rfbCloseClient(cl);
80			return TRUE;
81		}
82		rfbLog("got message:\n%s\n", text);
83		free(text);
84		return TRUE;
85	}
86	return FALSE;
87}
88
89static int backChannelEncodings[] = {rfbBackChannel, 0};
90
91static rfbProtocolExtension backChannelExtension = {
92	NULL,				/* newClient */
93	NULL,				/* init */
94	backChannelEncodings,		/* pseudoEncodings */
95	enableBackChannel,		/* enablePseudoEncoding */
96	handleBackChannelMessage,	/* handleMessage */
97	NULL,				/* close */
98	NULL,				/* usage */
99	NULL,				/* processArgument */
100	NULL				/* next extension */
101};
102
103int main(int argc,char** argv)
104{
105	rfbScreenInfoPtr server;
106
107	rfbRegisterProtocolExtension(&backChannelExtension);
108
109	server=rfbGetScreen(&argc,argv,400,300,8,3,4);
110	if(!server)
111	  return 0;
112	server->frameBuffer=(char*)malloc(400*300*4);
113	rfbInitServer(server);
114	rfbRunEventLoop(server,-1,FALSE);
115	return(0);
116}
117