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.


Updated vnc server to correspond to new mouse events
[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 inline int sign(int x) { return x<0; }
260
261 inline int abs(int x) { if (x<0) { return -x; } else {return x;}}
262
263 class V3Desktop : public SDesktop, public rfb::ColourMap
264 {
265 public:
266     V3Desktop(int fd)  // fd is the open fd of the VM's device
267     : v3_fd(fd), pb(0), server(0), oldButtonMask(0)
268     {
269
270         mouse_inited=false; // not yet
271     
272       // Let's get the needed resolution
273       if (v3_get_fb_spec(v3_fd,&v3_spec)) { 
274           fprintf(stderr, "Can't get spec from VM\n");
275           exit(-1);
276       }
277
278       // sanity check:
279       fprintf(stderr,"VM's spec is %u x %u x %u with %u bits per channel and rgb offsets (%u,%u,%u)\n",
280               v3_spec.width, v3_spec.height, v3_spec.bytes_per_pixel, 
281               v3_spec.bits_per_channel, v3_spec.red_offset, v3_spec.green_offset, v3_spec.blue_offset);
282
283       if (! (v3_spec.bytes_per_pixel==4 &&
284              v3_spec.bits_per_channel==8)) { 
285           fprintf(stderr,"Error in forma compatabiliity\n");
286           exit(-1);
287       }
288
289       dpyWidth=v3_spec.width;
290       dpyHeight=v3_spec.height;
291       
292       // Now we can build our image to match
293       image = new Image(dpyWidth, dpyHeight);
294
295       // Convert to the internal pixel format a
296       pf.bpp = v3_spec.bytes_per_pixel*8;
297       pf.depth = v3_spec.bits_per_channel*3;
298       pf.bigEndian = 0;
299       pf.trueColour = 1;
300     
301       //default pixel formats dont work!
302       pf.redShift   = v3_spec.red_offset*8;
303       pf.greenShift = v3_spec.green_offset*8;
304       pf.blueShift  = v3_spec.blue_offset*8;
305       pf.redMax     = 255;
306       pf.greenMax   = 255;
307       pf.blueMax    = 255;
308     
309       // assigns new pixelbuffer to xdesktop object
310       pb = new FullFramePixelBuffer(pf, dpyWidth, dpyHeight,
311                                     (rdr::U8*)image->data, this);
312     }
313
314     virtual ~V3Desktop() {
315         delete pb;
316         delete image;
317     }
318     
319     void setVNCServer(VNCServer* s) {
320         server = s;
321         server->setPixelBuffer(pb);
322     }
323     
324     // -=- SDesktop interface, worry about the pointer and key events later..
325
326     // Mouse events in VNC give absolute pixel coordinates of the mouse pointer
327     // the PS/2 mouse spec means we provide relative movements with +/- 256
328     // these relative movements can then be scaled by the mouse or by the software
329     // therefore, we will need to trans back from absolute to relative, perhaps
330     // converting one VNC event to multiple PS/2 events
331     // we assume here that the translation is 1:1
332     // 
333     virtual void pointerEvent(const Point& pos, rdr::U8 buttonMask) {
334         //vlog.info("Pointer event occurred, x position: %d, y position: %d; button mask: %d.", pos.x, pos.y, buttonMask); 
335         int dx, dy;
336         int incx;
337         int incy;
338
339
340         if (!mouse_inited) {
341             mouse_inited = true;
342             dx = pos.x;
343             dy = pos.y;
344         } else {
345             // delta from current position
346             dx = pos.x - mouse_lastpos.x ;
347             dy = pos.y - mouse_lastpos.y ;
348         }
349
350         // update last position
351         mouse_lastpos = pos;
352
353 #define MAXINC 32
354
355         // dx and dy are now +/- 2^16
356         // we can generate increments of up to +/- MAXINC;
357
358         while (dx || dy) { 
359             incx = min(MAXINC, abs(dx));
360             incy = min(MAXINC, abs(dy));
361
362             if (v3_send_mouse(v3_fd, sign(dx), incx, sign(dy), incy, buttonMask)) { 
363                 fprintf(stderr, "Error in sending mouse event\n");
364                 exit(-1);
365             }
366             
367             dx += (dx>=0) ? -incx : +incx;
368             dy += (dy>=0) ? -incy : +incy;
369         }
370     }
371     
372     virtual void keyEvent(rdr::U32 key, bool down) {
373         vlog.info("Key event received (key=%d, down=%d.",key,down);
374     
375         uint8_t scan_code = convert_to_scancode(key,down);
376
377         if (scan_code && v3_send_key(v3_fd,scan_code)) {
378             fprintf(stderr, "Error in sending key event\n");
379             exit(-1);
380         }
381         
382     }
383   
384     virtual void clientCutText(const char* str, int len) {
385     }
386     
387     virtual Point getFbSize() {
388         return Point(pb->width(), pb->height());
389     }
390
391     virtual void lookup(int index, int* r, int* g, int* b) {
392     
393         // Probably not important since we will use true-color
394
395         /* X implementation..
396            XColor xc;
397            xc.pixel = index;
398            if (index < DisplayCells(dpy,DefaultScreen(dpy))) {
399            XQueryColor(dpy, DefaultColormap(dpy,DefaultScreen(dpy)), &xc);
400            } else {
401            xc.red = xc.green = xc.blue = 0;
402            }
403            *r = xc.red;
404            *g = xc.green;
405            *b = xc.blue;
406            */
407     }
408     
409     virtual void poll() {
410         if (server && 
411             server->clientsReadyForUpdate() && 
412             v3_have_update(v3_fd)) {
413
414             struct v3_frame_buffer_spec newspec = v3_spec;
415
416             if (v3_get_fb_data(v3_fd,&newspec,image->data)<0) { 
417                 fprintf(stderr,"Failed to get fb data from VM\n");
418                 exit(-1);
419             }
420
421             if (memcmp(&newspec,&v3_spec,sizeof(struct v3_frame_buffer_spec))) { 
422                 fprintf(stderr,"Uh oh - screen spec has changed\n");
423                 exit(-1);
424             }
425             
426             fprintf(stderr,"render!\n");
427
428             server->add_changed(pb->getRect());
429             server->tryUpdate();
430         }
431     }
432     
433 protected:
434     int v3_fd;
435     struct v3_frame_buffer_spec v3_spec;
436     bool mouse_inited;
437     Point mouse_lastpos;
438
439     PixelFormat pf;
440     PixelBuffer* pb;
441     VNCServer* server;
442     Image* image;
443     int oldButtonMask;
444     bool haveXtest;
445     int dpyHeight;
446     int dpyWidth;
447 };
448
449 char* programName;
450
451 static void usage()
452 {
453   fprintf(stderr, "\nusage: %s [<parameters>] /dev/v3-vmN \n", programName);
454   fprintf(stderr,"\n"
455           "Parameters can be turned on with -<param> or off with -<param>=0\n"
456           "Parameters which take a value can be specified as "
457           "-<param> <value>\n"
458           "Other valid forms are <param>=<value> -<param>=<value> "
459           "--<param>=<value>\n"
460           "Parameter names are case-insensitive.  The parameters are:\n\n");
461   Configuration::listParams(79, 14);
462   exit(1);
463 }
464
465 int main(int argc, char** argv)
466 {
467   int v3_fd;
468   char *v3_dev;
469
470   initStdIOLoggers();
471   LogWriter::setLogParams("*:stderr:30");
472
473   programName = argv[0];
474
475   // Grab the v3 device before all the OO stuff goes inscrutable on us
476   if (argc<2) { 
477       usage();
478   }
479   v3_dev = argv[argc-1];
480   argc--;
481   fprintf(stderr,"Will attempt to connect to VM %s\n",v3_dev);
482
483
484
485
486   Display* dpy;
487
488   for (int i = 1; i < argc; i++) {
489     if (Configuration::setParam(argv[i]))
490       continue;
491
492     if (argv[i][0] == '-') {
493       if (i+1 < argc) {
494         if (Configuration::setParam(&argv[i][1], argv[i+1])) {
495           i++;
496           continue;
497         }
498       }
499       usage();
500     }
501
502     usage();
503   }
504
505   CharArray dpyStr(displayname.getData());
506   dpy = NULL;
507
508   signal(SIGHUP, CleanupSignalHandler);
509   signal(SIGINT, CleanupSignalHandler);
510   signal(SIGTERM, CleanupSignalHandler);
511
512   try {
513     v3_fd = open(v3_dev, O_RDONLY);    
514
515     if (v3_fd<0) { 
516         perror("Cannot open VM");
517         exit(-1);
518     }
519   
520     V3Desktop desktop(v3_fd);
521     VNCServerST server("v3x0vncserver", &desktop);
522     desktop.setVNCServer(&server);
523
524     TcpSocket::initTcpSockets();
525     TcpListener listener((int)rfbport);
526     vlog.info("Listening on port %d", (int)rfbport);
527     
528     while (true) {
529       fd_set rfds;
530       struct timeval tv;
531
532       tv.tv_sec = 0;
533       tv.tv_usec = 50*1000;
534
535       FD_ZERO(&rfds);
536       FD_SET(listener.getFd(), &rfds);
537
538       std::list<Socket*> sockets;
539       server.getSockets(&sockets);
540       std::list<Socket*>::iterator i;
541       for (i = sockets.begin(); i != sockets.end(); i++) {
542         FD_SET((*i)->getFd(), &rfds);
543       }
544
545       int n = select(FD_SETSIZE, &rfds, 0, 0, &tv);
546       if (n < 0) throw rdr::SystemException("select",errno);
547
548       if (FD_ISSET(listener.getFd(), &rfds)) {
549         Socket* sock = listener.accept();
550         server.addClient(sock);
551       }
552
553       server.getSockets(&sockets);
554       for (i = sockets.begin(); i != sockets.end(); i++) {
555         if (FD_ISSET((*i)->getFd(), &rfds)) {
556           server.processSocketEvent(*i);
557         }
558       }
559
560       server.checkTimeouts();
561       desktop.poll();
562     }
563
564   } catch (rdr::Exception &e) {
565     vlog.error(e.str());
566     close(v3_fd);
567   };
568
569   close(v3_fd);
570
571   return 0;
572 }