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