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 
30 typedef struct backChannelMsg {
31 	uint8_t type;
32 	uint8_t pad1;
33 	uint16_t pad2;
34 	uint32_t size;
35 } backChannelMsg;
36 
enableBackChannel(rfbClientPtr cl,void ** data,int encoding)37 rfbBool 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 
handleBackChannelMessage(rfbClientPtr cl,void * data,const rfbClientToServerMsg * message)58 static 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 
89 static int backChannelEncodings[] = {rfbBackChannel, 0};
90 
91 static 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 
main(int argc,char ** argv)103 int 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