Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


3628f1556347226c9c395bf4d4656142dffb7e4d
[palacios.git] / linux_usr / vnc / x0vncserver.cxx
1 /* Copyright (C) 2002-2004 RealVNC Ltd.  All Rights Reserved.
2  *    
3  * This is free software; you can redistribute it and/or modify
4  * it under the terms of the GNU General Public License as published by
5  * the Free Software Foundation; either version 2 of the License, or
6  * (at your option) any later version.
7  * 
8  * This software is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  * 
13  * You should have received a copy of the GNU General Public License
14  * along with this software; if not, write to the Free Software
15  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
16  * USA.
17  */
18 #include <strings.h>
19 #include <sys/time.h>
20 #include <sys/types.h>
21 #include <unistd.h>
22 #include <errno.h>
23 #include <rfb/Logger_stdio.h>
24 #include <rfb/LogWriter.h>
25 #include <rfb/VNCServerST.h>
26 #include <rfb/Configuration.h>
27 #include <rfb/SSecurityFactoryStandard.h>
28
29 #include <network/TcpSocket.h>
30
31 #include "Image.h"
32 #include <signal.h>
33 #include <X11/X.h>
34 #include <X11/Xlib.h>
35 #include <X11/Xutil.h>
36 #include <X11/extensions/XTest.h>
37
38
39 #include <rfb/Encoder.h>
40
41
42 using namespace rfb;
43 using namespace rdr;
44 using namespace network;
45
46 #include "v3_fb.h"
47
48
49
50 #define NO_KEY { 0, 0 }
51
52 struct key_code {
53     uint8_t scan_code;
54     uint8_t capital;
55 };
56
57
58 static const struct key_code ascii_to_key_code[] = {             // ASCII Value Serves as Index
59     NO_KEY,         NO_KEY,         NO_KEY,         NO_KEY,      // 0x00 - 0x03
60     NO_KEY,         NO_KEY,         NO_KEY,         NO_KEY,      // 0x04 - 0x07
61     { 0x0E, 0 },    { 0x0F, 0 },    { 0x1C, 0 },    NO_KEY,      // 0x08 - 0x0B
62     NO_KEY,         { 0x1C, 0 },    NO_KEY,         NO_KEY,      // 0x0C - 0x0F
63     NO_KEY,         NO_KEY,         NO_KEY,         NO_KEY,      // 0x10 - 0x13
64     NO_KEY,         NO_KEY,         NO_KEY,         NO_KEY,      // 0x14 - 0x17
65     NO_KEY,         NO_KEY,         NO_KEY,         { 0x01, 0 }, // 0x18 - 0x1B
66     NO_KEY,         NO_KEY,         NO_KEY,         NO_KEY,      // 0x1C - 0x1F
67     { 0x39, 0 },    { 0x02, 1 },    { 0x28, 1 },    { 0x04, 1 }, // 0x20 - 0x23
68     { 0x05, 1 },    { 0x06, 1 },    { 0x08, 1 },    { 0x28, 0 }, // 0x24 - 0x27
69     { 0x0A, 1 },    { 0x0B, 1 },    { 0x09, 1 },    { 0x0D, 1 }, // 0x28 - 0x2B
70     { 0x33, 0 },    { 0x0C, 0 },    { 0x34, 0 },    { 0x35, 0 }, // 0x2C - 0x2F
71     { 0x0B, 0 },    { 0x02, 0 },    { 0x03, 0 },    { 0x04, 0 }, // 0x30 - 0x33
72     { 0x05, 0 },    { 0x06, 0 },    { 0x07, 0 },    { 0x08, 0 }, // 0x34 - 0x37
73     { 0x09, 0 },    { 0x0A, 0 },    { 0x27, 1 },    { 0x27, 0 }, // 0x38 - 0x3B
74     { 0x33, 1 },    { 0x0D, 0 },    { 0x34, 1 },    { 0x35, 1 }, // 0x3C - 0x3F
75     { 0x03, 1 },    { 0x1E, 1 },    { 0x30, 1 },    { 0x2E, 1 }, // 0x40 - 0x43
76     { 0x20, 1 },    { 0x12, 1 },    { 0x21, 1 },    { 0x22, 1 }, // 0x44 - 0x47
77     { 0x23, 1 },    { 0x17, 1 },    { 0x24, 1 },    { 0x25, 1 }, // 0x48 - 0x4B
78     { 0x26, 1 },    { 0x32, 1 },    { 0x31, 1 },    { 0x18, 1 }, // 0x4C - 0x4F
79     { 0x19, 1 },    { 0x10, 1 },    { 0x13, 1 },    { 0x1F, 1 }, // 0x50 - 0x53
80     { 0x14, 1 },    { 0x16, 1 },    { 0x2F, 1 },    { 0x11, 1 }, // 0x54 - 0x57
81     { 0x2D, 1 },    { 0x15, 1 },    { 0x2C, 1 },    { 0x1A, 0 }, // 0x58 - 0x5B
82     { 0x2B, 0 },    { 0x1B, 0 },    { 0x07, 1 },    { 0x0C, 1 }, // 0x5C - 0x5F
83     { 0x29, 0 },    { 0x1E, 0 },    { 0x30, 0 },    { 0x2E, 0 }, // 0x60 - 0x63
84     { 0x20, 0 },    { 0x12, 0 },    { 0x21, 0 },    { 0x22, 0 }, // 0x64 - 0x67
85     { 0x23, 0 },    { 0x17, 0 },    { 0x24, 0 },    { 0x25, 0 }, // 0x68 - 0x6B
86     { 0x26, 0 },    { 0x32, 0 },    { 0x31, 0 },    { 0x18, 0 }, // 0x6C - 0x6F
87     { 0x19, 0 },    { 0x10, 0 },    { 0x13, 0 },    { 0x1F, 0 }, // 0x70 - 0x73
88     { 0x14, 0 },    { 0x16, 0 },    { 0x2F, 0 },    { 0x11, 0 }, // 0x74 - 0x77
89     { 0x2D, 0 },    { 0x15, 0 },    { 0x2C, 0 },    { 0x1A, 1 }, // 0x78 - 0x7B
90     { 0x2B, 1 },    { 0x1B, 1 },    { 0x29, 1 },    { 0x0E, 0 }  // 0x7C - 0x7F
91 };
92
93 static uint8_t convert_to_scancode(rdr::U32 key, bool down)
94 {
95     
96
97     unsigned char scancode=0;
98
99     if (key<0x80) { 
100         struct key_code c = ascii_to_key_code[key];
101         scancode=c.scan_code;
102     } else {
103         switch (key) { 
104             case 0xffe1:  //left shift
105                 scancode = 0x2a;
106                 break;
107
108             case 0xffe2:  //right shift
109                 scancode = 0x36;
110                 break;
111
112             case 0xffe3:  //left ctrl
113             case 0xffe4:  //right ctrl
114                 scancode = 0x1d;   // translated as left ctrl
115                 break;
116
117             case 0xffe7:  //left meta
118             case 0xffe8:  //right meta
119             case 0xffe9:  //left alt
120             case 0xffea:  //right alt
121                 scancode = 0x38;  // translated as a left alt
122                 break; 
123
124             case 0xff08: // backspace
125                 scancode = 0x0e;
126                 break; 
127
128             case 0xff09: // tab
129                 scancode = 0x0f;  
130                 break; 
131
132             case 0xff0d: // return
133                 scancode = 0x1c;
134                 break; 
135
136             case 0xff1b: // escape
137                 scancode = 0x01;
138                 break; 
139
140             case 0xff63: // insert
141                 scancode = 0x52;
142                 break; 
143
144             case 0xffff: // delete
145                 scancode = 0x53;
146                 break; 
147
148             case 0xff50: // home
149                 scancode = 0x47;
150                 break; 
151
152             case 0xff57: // end
153                 scancode = 0x4f;
154                 break; 
155                 
156             case 0xff55: // pageup
157                 scancode = 0x49;
158                 break; 
159
160             case 0xff56: // pagedown
161                 scancode = 0x51;
162                 break; 
163
164             case 0xff51: // left
165                 scancode = 0x4b;
166                 break; 
167
168             case 0xff52: // up
169                 scancode = 0x48;
170                 break; 
171
172             case 0xff53: // right
173                 scancode = 0x4d;
174                 break; 
175
176             case 0xff54: // down
177                 scancode = 0x50;
178                 break; 
179
180             case 0xffbe: // f1
181                 scancode = 0x3b;
182                 break; 
183             case 0xffbf: // f2
184                 scancode = 0x3c;
185                 break; 
186             case 0xffc0: // f3
187                 scancode = 0x3d;
188                 break; 
189             case 0xffc1: // f4
190                 scancode = 0x3e;
191                 break; 
192             case 0xffc2: // f5
193                 scancode = 0x3f;
194                 break; 
195             case 0xffc3: // f6
196                 scancode = 0x40;
197                 break; 
198             case 0xffc4: // f7
199                 scancode = 0x41;
200                 break; 
201             case 0xffc5: // f8
202                 scancode = 0x42;
203                 break; 
204             case 0xffc6: // f9
205                 scancode = 0x43;
206                 break;
207             case 0xffc7: // f10
208                 scancode = 0x44;
209                 break; 
210             case 0xffc8: // f11
211                 scancode = 0x57;
212                 break; 
213             case 0xffc9: // f12
214                 scancode = 0x58;
215                 break; 
216
217
218             default:
219                 scancode = 0;
220                 fprintf(stderr,"Ignoring key 0x%x (down=%d)\n", key, down);
221         }
222     }
223     
224     if (scancode==0) { 
225         return 0;
226     }
227
228     if (!down) { 
229         scancode|=0x80;
230     }
231     
232     return scancode;
233 }
234
235         
236         
237         
238     
239
240
241
242 LogWriter vlog("main");
243
244 StringParameter displayname("display", "The X display", "");
245 IntParameter rfbport("rfbport", "TCP port to listen for RFB protocol",5900);
246 StringParameter geometry("geometry", "Height and width", "1024x768");
247
248 VncAuthPasswdFileParameter vncAuthPasswdFile;
249
250 static void CleanupSignalHandler(int sig)
251 {
252   // CleanupSignalHandler allows C++ object cleanup to happen because it calls
253   // exit() rather than the default which is to abort.
254   fprintf(stderr,"CleanupSignalHandler called\n");
255   exit(1);
256 }
257
258
259 class V3Desktop : public SDesktop, public rfb::ColourMap
260 {
261 public:
262     V3Desktop(int fd)  // fd is the open fd of the VM's device
263     : v3_fd(fd), pb(0), server(0), oldButtonMask(0)
264     {
265     
266       // Let's get the needed resolution
267       if (v3_get_fb_spec(v3_fd,&v3_spec)) { 
268           fprintf(stderr, "Can't get spec from VM\n");
269           exit(-1);
270       }
271
272       // sanity check:
273       fprintf(stderr,"VM's spec is %u x %u x %u with %u bits per channel and rgb offsets (%u,%u,%u)\n",
274               v3_spec.width, v3_spec.height, v3_spec.bytes_per_pixel, 
275               v3_spec.bits_per_channel, v3_spec.red_offset, v3_spec.green_offset, v3_spec.blue_offset);
276
277       if (! (v3_spec.bytes_per_pixel==4 &&
278              v3_spec.bits_per_channel==8)) { 
279           fprintf(stderr,"Error in forma compatabiliity\n");
280           exit(-1);
281       }
282
283       dpyWidth=v3_spec.width;
284       dpyHeight=v3_spec.height;
285       
286       // Now we can build our image to match
287       image = new Image(dpyWidth, dpyHeight);
288
289       // Convert to the internal pixel format a
290       pf.bpp = v3_spec.bytes_per_pixel*8;
291       pf.depth = v3_spec.bits_per_channel*3;
292       pf.bigEndian = 0;
293       pf.trueColour = 1;
294     
295       //default pixel formats dont work!
296       pf.redShift   = v3_spec.red_offset*8;
297       pf.greenShift = v3_spec.green_offset*8;
298       pf.blueShift  = v3_spec.blue_offset*8;
299       pf.redMax     = 255;
300       pf.greenMax   = 255;
301       pf.blueMax    = 255;
302     
303       // assigns new pixelbuffer to xdesktop object
304       pb = new FullFramePixelBuffer(pf, dpyWidth, dpyHeight,
305                                     (rdr::U8*)image->data, this);
306     }
307
308     virtual ~V3Desktop() {
309         delete pb;
310         delete image;
311     }
312     
313     void setVNCServer(VNCServer* s) {
314         server = s;
315         server->setPixelBuffer(pb);
316     }
317     
318     // -=- SDesktop interface, worry about the pointer and key events later..
319     virtual void pointerEvent(const Point& pos, rdr::U8 buttonMask) {
320         vlog.info("Pointer event occurred, x position: %d, y position: %d; button mask: %d.", pos.x, pos.y, buttonMask); 
321         if (v3_send_mouse(v3_fd,pos.x,pos.y,buttonMask)) { 
322             fprintf(stderr, "Error in sending mouse event\n");
323             exit(-1);
324         }
325     }
326     
327     virtual void keyEvent(rdr::U32 key, bool down) {
328         vlog.info("Key event received (key=%d, down=%d.",key,down);
329     
330         //STILL NEED TO FIND MAPPING FROM KEYSYM TO ACTUAL KEYSTROKES    
331         uint8_t scan_code = convert_to_scancode(key,down);
332
333         if (scan_code && v3_send_key(v3_fd,scan_code)) {
334             fprintf(stderr, "Error in sending key event\n");
335             exit(-1);
336         }
337         
338     }
339   
340     virtual void clientCutText(const char* str, int len) {
341     }
342     
343     virtual Point getFbSize() {
344         return Point(pb->width(), pb->height());
345     }
346
347     virtual void lookup(int index, int* r, int* g, int* b) {
348     
349         // Probably not important since we will use true-color
350
351         /* X implementation..
352            XColor xc;
353            xc.pixel = index;
354            if (index < DisplayCells(dpy,DefaultScreen(dpy))) {
355            XQueryColor(dpy, DefaultColormap(dpy,DefaultScreen(dpy)), &xc);
356            } else {
357            xc.red = xc.green = xc.blue = 0;
358            }
359            *r = xc.red;
360            *g = xc.green;
361            *b = xc.blue;
362            */
363     }
364     
365     virtual void poll() {
366         if (server && 
367             server->clientsReadyForUpdate() && 
368             v3_have_update(v3_fd)) {
369
370             struct v3_frame_buffer_spec newspec = v3_spec;
371
372             if (v3_get_fb_data(v3_fd,&newspec,image->data)<0) { 
373                 fprintf(stderr,"Failed to get fb data from VM\n");
374                 exit(-1);
375             }
376
377             if (memcmp(&newspec,&v3_spec,sizeof(struct v3_frame_buffer_spec))) { 
378                 fprintf(stderr,"Uh oh - screen spec has changed\n");
379                 exit(-1);
380             }
381             
382             fprintf(stderr,"render!\n");
383
384             server->add_changed(pb->getRect());
385             server->tryUpdate();
386         }
387     }
388     
389 protected:
390     int v3_fd;
391     struct v3_frame_buffer_spec v3_spec;
392     
393     PixelFormat pf;
394     PixelBuffer* pb;
395     VNCServer* server;
396     Image* image;
397     int oldButtonMask;
398     bool haveXtest;
399     int dpyHeight;
400     int dpyWidth;
401 };
402
403 char* programName;
404
405 static void usage()
406 {
407   fprintf(stderr, "\nusage: %s [<parameters>] /dev/v3-vmN \n", programName);
408   fprintf(stderr,"\n"
409           "Parameters can be turned on with -<param> or off with -<param>=0\n"
410           "Parameters which take a value can be specified as "
411           "-<param> <value>\n"
412           "Other valid forms are <param>=<value> -<param>=<value> "
413           "--<param>=<value>\n"
414           "Parameter names are case-insensitive.  The parameters are:\n\n");
415   Configuration::listParams(79, 14);
416   exit(1);
417 }
418
419 int main(int argc, char** argv)
420 {
421   int v3_fd;
422   char *v3_dev;
423
424   initStdIOLoggers();
425   LogWriter::setLogParams("*:stderr:30");
426
427   programName = argv[0];
428
429   // Grab the v3 device before all the OO stuff goes inscrutable on us
430   if (argc<2) { 
431       usage();
432   }
433   v3_dev = argv[argc-1];
434   argc--;
435   fprintf(stderr,"Will attempt to connect to VM %s\n",v3_dev);
436
437
438
439
440   Display* dpy;
441
442   for (int i = 1; i < argc; i++) {
443     if (Configuration::setParam(argv[i]))
444       continue;
445
446     if (argv[i][0] == '-') {
447       if (i+1 < argc) {
448         if (Configuration::setParam(&argv[i][1], argv[i+1])) {
449           i++;
450           continue;
451         }
452       }
453       usage();
454     }
455
456     usage();
457   }
458
459   CharArray dpyStr(displayname.getData());
460   dpy = NULL;
461
462   signal(SIGHUP, CleanupSignalHandler);
463   signal(SIGINT, CleanupSignalHandler);
464   signal(SIGTERM, CleanupSignalHandler);
465
466   try {
467     v3_fd = open(v3_dev, O_RDONLY);    
468
469     if (v3_fd<0) { 
470         perror("Cannot open VM");
471         exit(-1);
472     }
473   
474     V3Desktop desktop(v3_fd);
475     VNCServerST server("v3x0vncserver", &desktop);
476     desktop.setVNCServer(&server);
477
478     TcpSocket::initTcpSockets();
479     TcpListener listener((int)rfbport);
480     vlog.info("Listening on port %d", (int)rfbport);
481     
482     while (true) {
483       fd_set rfds;
484       struct timeval tv;
485
486       tv.tv_sec = 0;
487       tv.tv_usec = 50*1000;
488
489       FD_ZERO(&rfds);
490       FD_SET(listener.getFd(), &rfds);
491
492       std::list<Socket*> sockets;
493       server.getSockets(&sockets);
494       std::list<Socket*>::iterator i;
495       for (i = sockets.begin(); i != sockets.end(); i++) {
496         FD_SET((*i)->getFd(), &rfds);
497       }
498
499       int n = select(FD_SETSIZE, &rfds, 0, 0, &tv);
500       if (n < 0) throw rdr::SystemException("select",errno);
501
502       if (FD_ISSET(listener.getFd(), &rfds)) {
503         Socket* sock = listener.accept();
504         server.addClient(sock);
505       }
506
507       server.getSockets(&sockets);
508       for (i = sockets.begin(); i != sockets.end(); i++) {
509         if (FD_ISSET((*i)->getFd(), &rfds)) {
510           server.processSocketEvent(*i);
511         }
512       }
513
514       server.checkTimeouts();
515       desktop.poll();
516     }
517
518   } catch (rdr::Exception &e) {
519     vlog.error(e.str());
520     close(v3_fd);
521   };
522
523   close(v3_fd);
524
525   return 0;
526 }