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