1 /////////////////////////////////////////////////////////////////////////
2 // $Id: rfb.cc 14277 2021-06-11 14:46:38Z vruppert $
3 /////////////////////////////////////////////////////////////////////////
4 //
5 //  Copyright (C) 2000  Psyon.Org!
6 //
7 //    Donald Becker
8 //    http://www.psyon.org
9 //
10 //  Copyright (C) 2001-2021  The Bochs Project
11 //
12 //  This library is free software; you can redistribute it and/or
13 //  modify it under the terms of the GNU Lesser General Public
14 //  License as published by the Free Software Foundation; either
15 //  version 2 of the License, or (at your option) any later version.
16 //
17 //  This library is distributed in the hope that it will be useful,
18 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
19 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20 //  Lesser General Public License for more details.
21 //
22 //  You should have received a copy of the GNU Lesser General Public
23 //  License along with this library; if not, write to the Free Software
24 //  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
25 
26 // RFB still to do :
27 // - properly handle SetPixelFormat, including big/little-endian flag
28 // - depth > 8bpp support
29 // - optional compression support
30 
31 
32 // Define BX_PLUGGABLE in files that can be compiled into plugins.  For
33 // platforms that require a special tag on exported symbols, BX_PLUGGABLE
34 // is used to know when we are exporting symbols and when we are importing.
35 #define BX_PLUGGABLE
36 
37 #include "param_names.h"
38 #include "iodev.h"
39 #include "keymap.h"
40 #if BX_WITH_RFB
41 
42 #include "icon_bochs.h"
43 #include "font/vga.bitmap.h"
44 #include "sdl.h" // 8x8 font for status text
45 
46 #include "rfb.h"
47 #include "rfbkeys.h"
48 
49 #include "bxthread.h"
50 
51 
52 class bx_rfb_gui_c : public bx_gui_c {
53 public:
bx_rfb_gui_c(void)54   bx_rfb_gui_c (void) {}
55   DECLARE_GUI_VIRTUAL_METHODS()
56   DECLARE_GUI_NEW_VIRTUAL_METHODS()
57   virtual void draw_char(Bit8u ch, Bit8u fc, Bit8u bc, Bit16u xc, Bit16u yc,
58                          Bit8u fw, Bit8u fh, Bit8u fx, Bit8u fy,
59                          bool gfxcharw9, Bit8u cs, Bit8u ce, bool curs);
60   virtual void set_display_mode(disp_mode_t newmode);
61   void get_capabilities(Bit16u *xres, Bit16u *yres, Bit16u *bpp);
62   void statusbar_setitem_specific(int element, bool active, bool w);
63   virtual void set_mouse_mode_absxy(bool mode);
64 #if BX_SHOW_IPS
65   void show_ips(Bit32u ips_count);
66 #endif
67 private:
68   void rfbMouseMove(int x, int y, int z, int bmask);
69   void rfbKeyPressed(Bit32u key, int press_release);
70 };
71 
72 // declare one instance of the gui object and call macro to insert the
73 // plugin code
74 static bx_rfb_gui_c *theGui = NULL;
75 IMPLEMENT_GUI_PLUGIN_CODE(rfb)
76 
77 #define LOG_THIS theGui->
78 
79 #if defined(WIN32) && !defined(__CYGWIN__)
80 
81 #include <winsock2.h>
82 #include <process.h>
83 #define BX_RFB_WIN32
84 
85 #else
86 
87 #include <sys/socket.h>
88 #include <netinet/tcp.h>
89 #include <netinet/in.h>
90 #include <unistd.h>
91 #ifndef __QNXNTO__
92 #include <sys/errno.h>
93 #else
94 #include <errno.h>
95 #endif
96 
97 typedef int SOCKET;
98 #ifndef INVALID_SOCKET
99 #define INVALID_SOCKET -1
100 #endif
101 
102 #endif
103 
104 static bool keep_alive;
105 static bool client_connected;
106 static bool desktop_resizable;
107 #if BX_SHOW_IPS
108 static bool rfbHideIPS = 0;
109 static bool rfbIPSupdate = 0;
110 static char rfbIPStext[40];
111 #endif
112 static unsigned short rfbPort;
113 
114 // Headerbar stuff
115 static unsigned rfbBitmapCount = 0;
116 static struct _rfbBitmaps {
117     char *bmap;
118     unsigned xdim;
119     unsigned ydim;
120 } rfbBitmaps[BX_MAX_PIXMAPS];
121 
122 // Keyboard/Mouse stuff
123 #define KEYBOARD 1
124 #define MOUSE    0
125 #define MAX_KEY_EVENTS 512
126 static struct _rfbKeyboardEvent {
127     bool type;
128     int key;
129     int down;
130     int x;
131     int y;
132     int z;
133 } rfbKeyboardEvent[MAX_KEY_EVENTS];
134 static unsigned long rfbKeyboardEvents = 0;
135 static bool bKeyboardInUse = 0;
136 
137 // Misc Stuff
138 static struct _rfbUpdateRegion {
139     unsigned int x;
140     unsigned int y;
141     unsigned int width;
142     unsigned int height;
143     bool updated;
144 } rfbUpdateRegion;
145 
146 #define BX_RFB_MAX_XDIM 1280
147 #define BX_RFB_MAX_YDIM 1024
148 #define BX_RFB_DEF_XDIM 720
149 #define BX_RFB_DEF_YDIM 480
150 
151 static Bit8u status_leds[3] = {0x38, 0x07, 0x3f};
152 static unsigned char status_gray_text = 0xa4;
153 const unsigned char headerbar_bg = 0xff;
154 const unsigned char headerbar_fg = 0x00;
155 
156 static char *rfbScreen;
157 static char rfbPalette[256];
158 static bool rfbBGR233Format;
159 
160 static unsigned rfbWindowX, rfbWindowY;
161 static unsigned rfbDimensionX, rfbDimensionY;
162 static Bit16u rfbHeaderbarY;
163 static unsigned rfbTileX = 0;
164 static unsigned rfbTileY = 0;
165 static unsigned long rfbOriginLeft = 0;
166 static unsigned long rfbOriginRight = 0;
167 static bool rfbMouseModeAbsXY = 0;
168 static unsigned rfbStatusbarY = 18;
169 static unsigned rfbStatusitemPos[12] = {
170   0, 170, 210, 250, 290, 330, 370, 410, 450, 490, 530, 570
171 };
172 static bool rfbStatusitemActive[12];
173 
174 static SOCKET sGlobal;
175 
176 static Bit32u clientEncodingsCount = 0;
177 static Bit32u *clientEncodings = NULL;
178 
179 #ifdef BX_RFB_WIN32
180 bool StopWinsock();
181 #endif
182 void rfbStartThread();
183 void HandleRfbClient(SOCKET sClient);
184 int ReadExact(int sock, char *buf, int len);
185 int WriteExact(int sock, char *buf, int len);
186 void DrawBitmap(int x, int y, int width, int height, char *bmap, char fg,
187         char bg, bool update_client);
188 void DrawChar(int x, int y, int width, int height, int fontx, int fonty,
189               char *bmap, char fg, char bg, bool gfxchar);
190 void UpdateScreen(unsigned char *newBits, int x, int y, int width, int height,
191         bool update_client);
192 void SendUpdate(int x, int y, int width, int height, Bit32u encoding);
193 void rfbSetUpdateRegion(unsigned x0, unsigned y0, unsigned w, unsigned h);
194 void rfbAddUpdateRegion(unsigned x0, unsigned y0, unsigned w, unsigned h);
195 void rfbSetStatusText(int element, const char *text, bool active, Bit8u color = 0);
196 static Bit32u convertStringToRfbKey(const char *string);
197 #if BX_SHOW_IPS && defined(WIN32)
198 DWORD WINAPI rfbShowIPSthread(LPVOID);
199 #endif
200 
201 static const rfbPixelFormat BGR233Format = {
202     8, 8, 1, 1, 7, 7, 3, 0, 3, 6
203 };
204 static const rfbPixelFormat RGB332Format = {
205     8, 8, 0, 1, 7, 7, 3, 5, 2, 0
206 };
207 
208 // VNCViewer code to be replaced
209 #define PF_EQ(x,y) ((x.bitsPerPixel == y.bitsPerPixel) && (x.depth == y.depth) && (x.trueColourFlag == y.trueColourFlag) && ((x.bigEndianFlag == y.bigEndianFlag) || (x.bitsPerPixel == 8)) && (!x.trueColourFlag || ((x.redMax == y.redMax) &&    (x.greenMax == y.greenMax) && (x.blueMax == y.blueMax) && (x.redShift == y.redShift) && (x.greenShift == y.greenShift) && (x.blueShift == y.blueShift))))
210 
211 
212 // RFB implementation of the bx_gui_c methods (see nogui.cc for details)
213 
specific_init(int argc,char ** argv,unsigned headerbar_y)214 void bx_rfb_gui_c::specific_init(int argc, char **argv, unsigned headerbar_y)
215 {
216   int i, timeout = 30;
217 
218   put("RFB");
219   UNUSED(bochs_icon_bits);
220 
221   rfbHeaderbarY = (Bit16u)headerbar_y;
222   rfbDimensionX = BX_RFB_DEF_XDIM;
223   rfbDimensionY = BX_RFB_DEF_YDIM;
224   rfbWindowX = rfbDimensionX;
225   rfbWindowY = rfbDimensionY + rfbHeaderbarY + rfbStatusbarY;
226   rfbTileX = x_tilesize;
227   rfbTileY = y_tilesize;
228 
229   for (i = 0; i < 256; i++) {
230     for (int j = 0; j < 16; j++) {
231       vga_charmap[i * 32 + j] = reverse_bitorder(bx_vgafont[i].data[j]);
232     }
233   }
234 
235   console.present = 1;
236 
237   // parse rfb specific options
238   if (argc > 1) {
239     for (i = 1; i < argc; i++) {
240       if (!strncmp(argv[i], "timeout=", 8)) {
241         timeout = atoi(&argv[i][8]);
242         if (timeout < 0) {
243           BX_PANIC(("invalid timeout value: %d", timeout));
244         } else {
245           BX_INFO(("connection timeout set to %d", timeout));
246         }
247 #if BX_SHOW_IPS
248       } else if (!strcmp(argv[i], "hideIPS")) {
249         BX_INFO(("hide IPS display in status bar"));
250         rfbHideIPS = 1;
251 #endif
252       } else if (!strcmp(argv[i], "no_gui_console")) {
253         console.present = 0;
254       } else {
255         BX_PANIC(("Unknown rfb option '%s'", argv[i]));
256       }
257     }
258   }
259 
260   if (SIM->get_param_bool(BXPN_PRIVATE_COLORMAP)->get()) {
261     BX_ERROR(("private_colormap option ignored."));
262   }
263 
264   rfbScreen = new char[rfbWindowX * rfbWindowY];
265   memset(&rfbPalette, 0, sizeof(rfbPalette));
266 
267   rfbSetUpdateRegion(rfbWindowX, rfbWindowY, 0, 0);
268 
269   clientEncodingsCount=0;
270   clientEncodings=NULL;
271 
272   keep_alive = 1;
273   client_connected = 0;
274   desktop_resizable = 0;
275   rfbStartThread();
276 
277 #ifdef WIN32
278   Sleep(1000);
279   SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL);
280 #endif
281 
282   // load keymap for rfb
283   if (SIM->get_param_bool(BXPN_KBD_USEMAPPING)->get()) {
284     bx_keymap.loadKeymap(convertStringToRfbKey);
285   }
286 
287   // the ask menu doesn't work on the client side
288   io->set_log_action(LOGLEV_PANIC, ACT_FATAL);
289 
290   if (timeout > 0) {
291     while ((!client_connected) && (timeout--)) {
292       fprintf(stderr, "Bochs RFB server waiting for client: %2d\r", timeout+1);
293 #ifdef BX_RFB_WIN32
294       Sleep(1000);
295 #else
296       sleep(1);
297 #endif
298     }
299     if ((timeout < 0) && (!client_connected)) {
300       BX_PANIC(("timeout! no client present"));
301     } else {
302       fprintf(stderr, "RFB client connected                   \r");
303     }
304   }
305 
306 #if BX_SHOW_IPS && defined(WIN32)
307   if (!rfbHideIPS) {
308     DWORD threadID;
309     CreateThread(NULL, 0, rfbShowIPSthread, NULL, 0, &threadID);
310   }
311 #endif
312 
313   new_gfx_api = 1;
314   new_text_api = 1;
315 }
316 
handle_events(void)317 void bx_rfb_gui_c::handle_events(void)
318 {
319   while (bKeyboardInUse) ;
320 
321   bKeyboardInUse = 1;
322   if (rfbKeyboardEvents > 0) {
323     for (unsigned i = 0; i < rfbKeyboardEvents; i++) {
324       if (rfbKeyboardEvent[i].type == KEYBOARD) {
325         rfbKeyPressed(rfbKeyboardEvent[i].key, rfbKeyboardEvent[i].down);
326       } else { //type == MOUSE;
327         rfbMouseMove(rfbKeyboardEvent[i].x, rfbKeyboardEvent[i].y, rfbKeyboardEvent[i].z, rfbKeyboardEvent[i].down);
328       }
329     }
330     rfbKeyboardEvents = 0;
331   }
332   bKeyboardInUse = 0;
333 
334 #if BX_SHOW_IPS
335   if (rfbIPSupdate) {
336     rfbIPSupdate = 0;
337     rfbSetStatusText(0, rfbIPStext, 1);
338   }
339 #endif
340 }
341 
flush(void)342 void bx_rfb_gui_c::flush(void)
343 {
344   if (rfbUpdateRegion.updated) {
345     SendUpdate(rfbUpdateRegion.x, rfbUpdateRegion.y, rfbUpdateRegion.width,
346                rfbUpdateRegion.height, rfbEncodingRaw);
347     rfbSetUpdateRegion(rfbWindowX, rfbWindowY, 0, 0);
348   }
349 }
350 
clear_screen(void)351 void bx_rfb_gui_c::clear_screen(void)
352 {
353   memset(&rfbScreen[rfbWindowX * rfbHeaderbarY], 0, rfbWindowX * rfbDimensionY);
354   rfbAddUpdateRegion(0, rfbHeaderbarY, rfbWindowX, rfbDimensionY);
355 }
356 
draw_char(Bit8u ch,Bit8u fc,Bit8u bc,Bit16u xc,Bit16u yc,Bit8u fw,Bit8u fh,Bit8u fx,Bit8u fy,bool gfxcharw9,Bit8u cs,Bit8u ce,bool curs)357 void bx_rfb_gui_c::draw_char(Bit8u ch, Bit8u fc, Bit8u bc, Bit16u xc, Bit16u yc,
358                              Bit8u fw, Bit8u fh, Bit8u fx, Bit8u fy,
359                              bool gfxcharw9, Bit8u cs, Bit8u ce, bool curs)
360 {
361   Bit8u fgcol = rfbPalette[fc];
362   Bit8u bgcol = rfbPalette[bc];
363 
364   yc += rfbHeaderbarY;
365   DrawChar(xc, yc, fw, fh, fx, fy, (char *)&vga_charmap[ch << 5], fgcol, bgcol,
366            gfxcharw9);
367   rfbAddUpdateRegion(xc, yc, fw, fh);
368   if (curs && (ce >= fy) && (cs < (fh + fy))) {
369     if (cs > fy) {
370       yc += (cs - fy);
371       fh -= (cs - fy);
372     }
373     if ((ce - cs + 1) < fh) {
374       fh = ce - cs + 1;
375     }
376     DrawChar(xc, yc, fw, fh, fx, cs, (char *)&vga_charmap[ch << 5], bgcol,
377              fgcol, gfxcharw9);
378   }
379 }
380 
text_update(Bit8u * old_text,Bit8u * new_text,unsigned long cursor_x,unsigned long cursor_y,bx_vga_tminfo_t * tm_info)381 void bx_rfb_gui_c::text_update(Bit8u *old_text, Bit8u *new_text, unsigned long cursor_x, unsigned long cursor_y, bx_vga_tminfo_t *tm_info)
382 {
383   // present for compatibilty
384 }
385 
get_clipboard_text(Bit8u ** bytes,Bit32s * nbytes)386 int bx_rfb_gui_c::get_clipboard_text(Bit8u **bytes, Bit32s *nbytes)
387 {
388   return 0;
389 }
390 
set_clipboard_text(char * text_snapshot,Bit32u len)391 int bx_rfb_gui_c::set_clipboard_text(char *text_snapshot, Bit32u len)
392 {
393   return 0;
394 }
395 
palette_change(Bit8u index,Bit8u red,Bit8u green,Bit8u blue)396 bool bx_rfb_gui_c::palette_change(Bit8u index, Bit8u red, Bit8u green, Bit8u blue)
397 {
398   if (rfbBGR233Format) {
399     rfbPalette[index] = (((red * 7 + 127) / 255) << 0) | (((green * 7 + 127) / 255) << 3) | (((blue * 3 + 127) / 255) << 6);
400   } else {
401     rfbPalette[index] = (((red * 7 + 127) / 255) << 5) | (((green * 7 + 127) / 255) << 2) | (((blue * 3 + 127) / 255) << 0);
402   }
403   return 1;
404 }
405 
graphics_tile_update(Bit8u * tile,unsigned x0,unsigned y0)406 void bx_rfb_gui_c::graphics_tile_update(Bit8u *tile, unsigned x0, unsigned y0)
407 {
408   unsigned c, i, h, y;
409 
410   switch (guest_bpp) {
411     case 8: /* 8 bpp */
412       y = y0 + rfbHeaderbarY;
413       if ((y0 + rfbTileY) > rfbDimensionY) {
414         h = rfbDimensionY - y0;
415       } else {
416         h = rfbTileY;
417       }
418       for (i = 0; i < h; i++) {
419         for (c = 0; c < rfbTileX; c++) {
420           tile[(i * rfbTileX) + c] = rfbPalette[tile[(i * rfbTileX) + c]];
421         }
422         memcpy(&rfbScreen[y * rfbWindowX + x0], &tile[i * rfbTileX], rfbTileX);
423         y++;
424       }
425       break;
426     default:
427       BX_PANIC(("%u bpp modes handled by new graphics API", guest_bpp));
428       return;
429   }
430   rfbAddUpdateRegion(x0, y0 + rfbHeaderbarY, rfbTileX, h);
431 }
432 
dimension_update(unsigned x,unsigned y,unsigned fheight,unsigned fwidth,unsigned bpp)433 void bx_rfb_gui_c::dimension_update(unsigned x, unsigned y, unsigned fheight, unsigned fwidth, unsigned bpp)
434 {
435   if (bpp == 8) {
436     guest_bpp = bpp;
437   } else {
438     BX_PANIC(("%d bpp graphics mode not supported yet", bpp));
439   }
440   guest_textmode = (fheight > 0);
441   guest_fwidth = fwidth;
442   guest_fheight = fheight;
443   guest_xres = x;
444   guest_yres = y;
445   if ((x != rfbDimensionX) || (y != rfbDimensionY)) {
446     if (desktop_resizable) {
447       if ((x > BX_RFB_MAX_XDIM) || (y > BX_RFB_MAX_YDIM)) {
448         BX_PANIC(("dimension_update(): RFB doesn't support graphics mode %dx%d", x, y));
449       }
450       rfbDimensionX = x;
451       rfbDimensionY = y;
452       rfbWindowX = rfbDimensionX;
453       rfbWindowY = rfbDimensionY + rfbHeaderbarY + rfbStatusbarY;
454       delete [] rfbScreen;
455       rfbScreen = new char[rfbWindowX * rfbWindowY];
456       SendUpdate(0, 0, rfbWindowX, rfbWindowY, rfbEncodingDesktopSize);
457       bx_gui->show_headerbar();
458       rfbSetUpdateRegion(0, 0, rfbWindowX, rfbWindowY);
459     } else {
460       if ((x > BX_RFB_DEF_XDIM) || (y > BX_RFB_DEF_YDIM)) {
461         BX_PANIC(("dimension_update(): RFB doesn't support graphics mode %dx%d", x, y));
462       }
463       clear_screen();
464       SendUpdate(0, rfbHeaderbarY, rfbDimensionX, rfbDimensionY, rfbEncodingRaw);
465       rfbDimensionX = x;
466       rfbDimensionY = y;
467     }
468   }
469 }
470 
create_bitmap(const unsigned char * bmap,unsigned xdim,unsigned ydim)471 unsigned bx_rfb_gui_c::create_bitmap(const unsigned char *bmap, unsigned xdim, unsigned ydim)
472 {
473   if (rfbBitmapCount >= BX_MAX_PIXMAPS) {
474     BX_ERROR(("too many pixmaps."));
475     return 0;
476   }
477   rfbBitmaps[rfbBitmapCount].bmap = new char[(xdim * ydim) / 8];
478   rfbBitmaps[rfbBitmapCount].xdim = xdim;
479   rfbBitmaps[rfbBitmapCount].ydim = ydim;
480   memcpy(rfbBitmaps[rfbBitmapCount].bmap, bmap, (xdim * ydim) / 8);
481 
482   rfbBitmapCount++;
483   return (rfbBitmapCount - 1);
484 }
485 
headerbar_bitmap(unsigned bmap_id,unsigned alignment,void (* f)(void))486 unsigned bx_rfb_gui_c::headerbar_bitmap(unsigned bmap_id, unsigned alignment, void (*f)(void))
487 {
488   int hb_index;
489 
490   if ((bx_headerbar_entries + 1) > BX_MAX_HEADERBAR_ENTRIES) {
491     return 0;
492   }
493 
494   hb_index = bx_headerbar_entries++;
495   bx_headerbar_entry[hb_index].bmap_id = bmap_id;
496   bx_headerbar_entry[hb_index].xdim = rfbBitmaps[bmap_id].xdim;
497   bx_headerbar_entry[hb_index].ydim = rfbBitmaps[bmap_id].ydim;
498   bx_headerbar_entry[hb_index].alignment = alignment;
499   bx_headerbar_entry[hb_index].f = f;
500   if (alignment == BX_GRAVITY_LEFT) {
501     bx_headerbar_entry[hb_index].xorigin = rfbOriginLeft;
502     rfbOriginLeft += rfbBitmaps[bmap_id].xdim;
503   } else { // BX_GRAVITY_RIGHT
504     rfbOriginRight += rfbBitmaps[bmap_id].xdim;
505     bx_headerbar_entry[hb_index].xorigin = rfbOriginRight;
506   }
507   return hb_index;
508 }
509 
show_headerbar(void)510 void bx_rfb_gui_c::show_headerbar(void)
511 {
512   char *newBits, value;
513   unsigned int i, xorigin, addr, bmap_id;
514 
515   newBits = new char[rfbWindowX * rfbHeaderbarY];
516   memset(newBits, 0, (rfbWindowX * rfbHeaderbarY));
517   DrawBitmap(0, 0, rfbWindowX, rfbHeaderbarY, newBits, headerbar_fg, headerbar_bg, 0);
518   for (i = 0; i < bx_headerbar_entries; i++) {
519     if (bx_headerbar_entry[i].alignment == BX_GRAVITY_LEFT) {
520       xorigin = bx_headerbar_entry[i].xorigin;
521     } else {
522       xorigin = rfbWindowX - bx_headerbar_entry[i].xorigin;
523     }
524     bmap_id = bx_headerbar_entry[i].bmap_id;
525     DrawBitmap(xorigin, 0, rfbBitmaps[bmap_id].xdim, rfbBitmaps[bmap_id].ydim,
526                rfbBitmaps[bmap_id].bmap, headerbar_fg, headerbar_bg, 0);
527   }
528   delete [] newBits;
529   newBits = new char[rfbWindowX * rfbStatusbarY / 8];
530   memset(newBits, 0, (rfbWindowX * rfbStatusbarY / 8));
531   for (i = 1; i < 12; i++) {
532     addr = rfbStatusitemPos[i] / 8;
533     value = 1 << (rfbStatusitemPos[i] % 8);
534     for (unsigned j = 1; j < rfbStatusbarY; j++) {
535       newBits[(rfbWindowX * j / 8) + addr] = value;
536     }
537   }
538   DrawBitmap(0, rfbWindowY - rfbStatusbarY, rfbWindowX, rfbStatusbarY, newBits,
539              headerbar_fg, headerbar_bg, 0);
540   delete [] newBits;
541   for (i = 1; i <= statusitem_count; i++) {
542     rfbSetStatusText(i, statusitem[i - 1].text, rfbStatusitemActive[i]);
543   }
544 }
545 
replace_bitmap(unsigned hbar_id,unsigned bmap_id)546 void bx_rfb_gui_c::replace_bitmap(unsigned hbar_id, unsigned bmap_id)
547 {
548   unsigned int xorigin;
549 
550   if (bmap_id == bx_headerbar_entry[hbar_id].bmap_id)
551     return;
552   bx_headerbar_entry[hbar_id].bmap_id = bmap_id;
553   if (bx_headerbar_entry[hbar_id].alignment == BX_GRAVITY_LEFT) {
554     xorigin = bx_headerbar_entry[hbar_id].xorigin;
555   } else {
556     xorigin = rfbWindowX - bx_headerbar_entry[hbar_id].xorigin;
557   }
558   DrawBitmap(xorigin, 0, rfbBitmaps[bmap_id].xdim, rfbBitmaps[bmap_id].ydim,
559              rfbBitmaps[bmap_id].bmap, headerbar_fg, headerbar_bg, 1);
560 }
561 
exit(void)562 void bx_rfb_gui_c::exit(void)
563 {
564   unsigned int i;
565   keep_alive = 0;
566 #ifdef BX_RFB_WIN32
567   StopWinsock();
568 #endif
569   delete [] rfbScreen;
570   for(i = 0; i < rfbBitmapCount; i++) {
571     free(rfbBitmaps[i].bmap);
572   }
573 
574   // Clear supported encodings
575   if (clientEncodings != NULL) {
576     delete [] clientEncodings;
577     clientEncodingsCount = 0;
578   }
579 
580   BX_DEBUG(("bx_rfb_gui_c::exit()"));
581 }
582 
mouse_enabled_changed_specific(bool val)583 void bx_rfb_gui_c::mouse_enabled_changed_specific(bool val)
584 {
585 }
586 
graphics_tile_info(bx_svga_tileinfo_t * info)587 bx_svga_tileinfo_t *bx_rfb_gui_c::graphics_tile_info(bx_svga_tileinfo_t *info)
588 {
589   info->bpp = 8;
590   info->pitch = rfbWindowX;
591   info->red_shift = 3;
592   info->green_shift = 6;
593   info->blue_shift = 8;
594   info->red_mask = 0x07;
595   info->green_mask = 0x38;
596   info->blue_mask = 0xc0;
597   info->is_indexed = 0;
598 #ifdef BX_LITTLE_ENDIAN
599   info->is_little_endian = 1;
600 #else
601   info->is_little_endian = 0;
602 #endif
603 
604   return info;
605 }
606 
graphics_tile_get(unsigned x0,unsigned y0,unsigned * w,unsigned * h)607 Bit8u *bx_rfb_gui_c::graphics_tile_get(unsigned x0, unsigned y0,
608                             unsigned *w, unsigned *h)
609 {
610   if (x0 + rfbTileX > rfbDimensionX) {
611     *w = rfbDimensionX - x0;
612   } else {
613     *w = rfbTileX;
614   }
615 
616   if (y0 + rfbTileY > rfbDimensionY) {
617     *h = rfbDimensionY - y0;
618   } else {
619     *h = rfbTileY;
620   }
621 
622   return (Bit8u *)rfbScreen + (rfbHeaderbarY + y0) * rfbWindowX + x0;
623 }
624 
graphics_tile_update_in_place(unsigned x0,unsigned y0,unsigned w,unsigned h)625 void bx_rfb_gui_c::graphics_tile_update_in_place(unsigned x0, unsigned y0,
626                                         unsigned w, unsigned h)
627 {
628   rfbAddUpdateRegion(x0, y0 + rfbHeaderbarY, w, h);
629 }
630 
631 
get_capabilities(Bit16u * xres,Bit16u * yres,Bit16u * bpp)632 void bx_rfb_gui_c::get_capabilities(Bit16u *xres, Bit16u *yres, Bit16u *bpp)
633 {
634   if (desktop_resizable) {
635     *xres = BX_RFB_MAX_XDIM;
636     *yres = BX_RFB_MAX_YDIM;
637   } else {
638     *xres = BX_RFB_DEF_XDIM;
639     *yres = BX_RFB_DEF_YDIM;
640   }
641   *bpp = 8;
642 }
643 
statusbar_setitem_specific(int element,bool active,bool w)644 void bx_rfb_gui_c::statusbar_setitem_specific(int element, bool active, bool w)
645 {
646   Bit8u color = 0;
647   if (w) {
648     color = statusitem[element].auto_off ? 1 : 2;
649   }
650   rfbSetStatusText(element+1, statusitem[element].text, active, color);
651 }
652 
set_mouse_mode_absxy(bool mode)653 void bx_rfb_gui_c::set_mouse_mode_absxy(bool mode)
654 {
655   rfbMouseModeAbsXY = mode;
656 }
657 
658 #if BX_SHOW_IPS
show_ips(Bit32u ips_count)659 void bx_rfb_gui_c::show_ips(Bit32u ips_count)
660 {
661   if (!rfbIPSupdate && !rfbHideIPS) {
662     ips_count /= 1000;
663     sprintf(rfbIPStext, "IPS: %u.%3.3uM", ips_count / 1000, ips_count % 1000);
664     rfbIPSupdate = 1;
665   }
666 }
667 #endif
668 
set_display_mode(disp_mode_t newmode)669 void bx_rfb_gui_c::set_display_mode(disp_mode_t newmode)
670 {
671   // if no mode change, do nothing.
672   if (disp_mode == newmode) return;
673   // remember the display mode for next time
674   disp_mode = newmode;
675   if ((newmode == DISP_MODE_SIM) && console_running()) {
676     console_cleanup();
677   }
678 }
679 
rfbMouseMove(int x,int y,int z,int bmask)680 void bx_rfb_gui_c::rfbMouseMove(int x, int y, int z, int bmask)
681 {
682   static int oldx = -1;
683   static int oldy = -1;
684   int dx, dy;
685 
686   if ((oldx == 1) && (oldy == -1)) {
687     oldx = x;
688     oldy = y;
689     return;
690   }
691   if (y > rfbHeaderbarY) {
692     if (console_running())
693       return;
694     if (rfbMouseModeAbsXY) {
695       if ((y >= rfbHeaderbarY) && (y < (int)(rfbDimensionY + rfbHeaderbarY))) {
696         dx = x * 0x7fff / rfbDimensionX;
697         dy = (y - rfbHeaderbarY) * 0x7fff / rfbDimensionY;
698         DEV_mouse_motion(dx, dy, z, bmask, 1);
699       }
700     } else {
701       DEV_mouse_motion(x - oldx, oldy - y, z, bmask, 0);
702     }
703     oldx = x;
704     oldy = y;
705   } else {
706     if (bmask == 1) {
707       bKeyboardInUse = 0;
708       rfbKeyboardEvents = 0;
709       headerbar_click(x);
710     }
711   }
712 }
713 
714 // function to convert key names into rfb key values.
715 // This first try will be horribly inefficient, but it only has
716 // to be done while loading a keymap.  Once the simulation starts,
717 // this function won't be called.
convertStringToRfbKey(const char * string)718 static Bit32u convertStringToRfbKey(const char *string)
719 {
720   rfbKeyTabEntry *ptr;
721   for (ptr = &rfb_keytable[0]; ptr->name != NULL; ptr++) {
722     if (!strcmp(string, ptr->name))
723       return ptr->value;
724   }
725   return BX_KEYMAP_UNKNOWN;
726 }
727 
728 static Bit32u rfb_ascii_to_key_event[0x5f] = {
729   //  !"#$%&'
730   BX_KEY_SPACE,
731   BX_KEY_1,
732   BX_KEY_SINGLE_QUOTE,
733   BX_KEY_3,
734   BX_KEY_4,
735   BX_KEY_5,
736   BX_KEY_7,
737   BX_KEY_SINGLE_QUOTE,
738 
739   // ()*+,-./
740   BX_KEY_9,
741   BX_KEY_0,
742   BX_KEY_8,
743   BX_KEY_EQUALS,
744   BX_KEY_COMMA,
745   BX_KEY_MINUS,
746   BX_KEY_PERIOD,
747   BX_KEY_SLASH,
748 
749   // 01234567
750   BX_KEY_0,
751   BX_KEY_1,
752   BX_KEY_2,
753   BX_KEY_3,
754   BX_KEY_4,
755   BX_KEY_5,
756   BX_KEY_6,
757   BX_KEY_7,
758 
759   // 89:;<=>?
760   BX_KEY_8,
761   BX_KEY_9,
762   BX_KEY_SEMICOLON,
763   BX_KEY_SEMICOLON,
764   BX_KEY_COMMA,
765   BX_KEY_EQUALS,
766   BX_KEY_PERIOD,
767   BX_KEY_SLASH,
768 
769   // @ABCDEFG
770   BX_KEY_2,
771   BX_KEY_A,
772   BX_KEY_B,
773   BX_KEY_C,
774   BX_KEY_D,
775   BX_KEY_E,
776   BX_KEY_F,
777   BX_KEY_G,
778 
779 
780   // HIJKLMNO
781   BX_KEY_H,
782   BX_KEY_I,
783   BX_KEY_J,
784   BX_KEY_K,
785   BX_KEY_L,
786   BX_KEY_M,
787   BX_KEY_N,
788   BX_KEY_O,
789 
790 
791   // PQRSTUVW
792   BX_KEY_P,
793   BX_KEY_Q,
794   BX_KEY_R,
795   BX_KEY_S,
796   BX_KEY_T,
797   BX_KEY_U,
798   BX_KEY_V,
799   BX_KEY_W,
800 
801   // XYZ[\]^_
802   BX_KEY_X,
803   BX_KEY_Y,
804   BX_KEY_Z,
805   BX_KEY_LEFT_BRACKET,
806   BX_KEY_BACKSLASH,
807   BX_KEY_RIGHT_BRACKET,
808   BX_KEY_6,
809   BX_KEY_MINUS,
810 
811   // `abcdefg
812   BX_KEY_GRAVE,
813   BX_KEY_A,
814   BX_KEY_B,
815   BX_KEY_C,
816   BX_KEY_D,
817   BX_KEY_E,
818   BX_KEY_F,
819   BX_KEY_G,
820 
821   // hijklmno
822   BX_KEY_H,
823   BX_KEY_I,
824   BX_KEY_J,
825   BX_KEY_K,
826   BX_KEY_L,
827   BX_KEY_M,
828   BX_KEY_N,
829   BX_KEY_O,
830 
831   // pqrstuvw
832   BX_KEY_P,
833   BX_KEY_Q,
834   BX_KEY_R,
835   BX_KEY_S,
836   BX_KEY_T,
837   BX_KEY_U,
838   BX_KEY_V,
839   BX_KEY_W,
840 
841   // xyz{|}~
842   BX_KEY_X,
843   BX_KEY_Y,
844   BX_KEY_Z,
845   BX_KEY_LEFT_BRACKET,
846   BX_KEY_BACKSLASH,
847   BX_KEY_RIGHT_BRACKET,
848   BX_KEY_GRAVE
849 };
850 
rfbKeyPressed(Bit32u key,int press_release)851 void bx_rfb_gui_c::rfbKeyPressed(Bit32u key, int press_release)
852 {
853   Bit32u key_event;
854 
855   if (console_running() && press_release) {
856     if (((key >= XK_space) && (key <= XK_asciitilde)) ||
857         (key == XK_Return) || (key == XK_BackSpace)) {
858       console_key_enq((Bit8u)(key & 0xff));
859     }
860     return;
861   }
862   if (!SIM->get_param_bool(BXPN_KBD_USEMAPPING)->get()) {
863     if ((key >= XK_space) && (key <= XK_asciitilde)) {
864       key_event = rfb_ascii_to_key_event[key - XK_space];
865     } else {
866       switch (key) {
867         case XK_KP_1:
868 #ifdef XK_KP_End
869         case XK_KP_End:
870 #endif
871           key_event = BX_KEY_KP_END;
872           break;
873 
874         case XK_KP_2:
875 #ifdef XK_KP_Down
876         case XK_KP_Down:
877 #endif
878           key_event = BX_KEY_KP_DOWN;
879           break;
880 
881         case XK_KP_3:
882 #ifdef XK_KP_Page_Down
883         case XK_KP_Page_Down:
884 #endif
885           key_event = BX_KEY_KP_PAGE_DOWN;
886           break;
887 
888         case XK_KP_4:
889 #ifdef XK_KP_Left
890         case XK_KP_Left:
891 #endif
892           key_event = BX_KEY_KP_LEFT;
893           break;
894 
895         case XK_KP_5:
896 #ifdef XK_KP_Begin
897         case XK_KP_Begin:
898 #endif
899           key_event = BX_KEY_KP_5;
900           break;
901 
902         case XK_KP_6:
903 #ifdef XK_KP_Right
904         case XK_KP_Right:
905 #endif
906           key_event = BX_KEY_KP_RIGHT;
907           break;
908 
909         case XK_KP_7:
910 #ifdef XK_KP_Home
911         case XK_KP_Home:
912 #endif
913           key_event = BX_KEY_KP_HOME;
914           break;
915 
916         case XK_KP_8:
917 #ifdef XK_KP_Up
918         case XK_KP_Up:
919 #endif
920           key_event = BX_KEY_KP_UP;
921           break;
922 
923         case XK_KP_9:
924 #ifdef XK_KP_Page_Up
925         case XK_KP_Page_Up:
926 #endif
927           key_event = BX_KEY_KP_PAGE_UP;
928           break;
929 
930         case XK_KP_0:
931 #ifdef XK_KP_Insert
932         case XK_KP_Insert:
933 #endif
934           key_event = BX_KEY_KP_INSERT;
935           break;
936 
937         case XK_KP_Decimal:
938 #ifdef XK_KP_Delete
939         case XK_KP_Delete:
940 #endif
941           key_event = BX_KEY_KP_DELETE;
942           break;
943 
944 #ifdef XK_KP_Enter
945         case XK_KP_Enter:
946           key_event = BX_KEY_KP_ENTER;
947           break;
948 #endif
949 
950         case XK_KP_Subtract:
951           key_event = BX_KEY_KP_SUBTRACT;
952           break;
953         case XK_KP_Add:
954           key_event = BX_KEY_KP_ADD;
955           break;
956 
957         case XK_KP_Multiply:
958           key_event = BX_KEY_KP_MULTIPLY;
959           break;
960         case XK_KP_Divide:
961           key_event = BX_KEY_KP_DIVIDE;
962           break;
963 
964         case XK_Up:
965           key_event = BX_KEY_UP;
966           break;
967         case XK_Down:
968           key_event = BX_KEY_DOWN;
969           break;
970         case XK_Left:
971           key_event = BX_KEY_LEFT;
972           break;
973         case XK_Right:
974           key_event = BX_KEY_RIGHT;
975           break;
976 
977         case XK_Delete:
978           key_event = BX_KEY_DELETE;
979           break;
980         case XK_BackSpace:
981           key_event = BX_KEY_BACKSPACE;
982           break;
983         case XK_Tab:
984           key_event = BX_KEY_TAB;
985           break;
986 #ifdef XK_ISO_Left_Tab
987         case XK_ISO_Left_Tab:
988           key_event = BX_KEY_TAB;
989           break;
990 #endif
991         case XK_Return:
992           key_event = BX_KEY_ENTER;
993           break;
994         case XK_Escape:
995           key_event = BX_KEY_ESC;
996           break;
997         case XK_F1:
998           key_event = BX_KEY_F1;
999           break;
1000         case XK_F2:
1001           key_event = BX_KEY_F2;
1002           break;
1003         case XK_F3:
1004           key_event = BX_KEY_F3;
1005           break;
1006         case XK_F4:
1007           key_event = BX_KEY_F4;
1008           break;
1009         case XK_F5:
1010           key_event = BX_KEY_F5;
1011           break;
1012         case XK_F6:
1013           key_event = BX_KEY_F6;
1014           break;
1015         case XK_F7:
1016           key_event = BX_KEY_F7;
1017           break;
1018         case XK_F8:
1019           key_event = BX_KEY_F8;
1020           break;
1021         case XK_F9:
1022           key_event = BX_KEY_F9;
1023           break;
1024         case XK_F10:
1025           key_event = BX_KEY_F10;
1026           break;
1027         case XK_F11:
1028           key_event = BX_KEY_F11;
1029           break;
1030         case XK_F12:
1031           key_event = BX_KEY_F12;
1032           break;
1033         case XK_Control_L:
1034           key_event = BX_KEY_CTRL_L;
1035           break;
1036 #ifdef XK_Control_R
1037         case XK_Control_R:
1038           key_event = BX_KEY_CTRL_R;
1039           break;
1040 #endif
1041         case XK_Shift_L:
1042           key_event = BX_KEY_SHIFT_L;
1043           break;
1044         case XK_Shift_R:
1045           key_event = BX_KEY_SHIFT_R;
1046           break;
1047         case XK_Alt_L:
1048           key_event = BX_KEY_ALT_L;
1049           break;
1050 #ifdef XK_Alt_R
1051         case XK_Alt_R:
1052           key_event = BX_KEY_ALT_R;
1053           break;
1054 #endif
1055         case XK_Caps_Lock:
1056           key_event = BX_KEY_CAPS_LOCK;
1057           break;
1058         case XK_Num_Lock:
1059           key_event = BX_KEY_NUM_LOCK;
1060           break;
1061 #ifdef XK_Scroll_Lock
1062         case XK_Scroll_Lock:
1063           key_event = BX_KEY_SCRL_LOCK;
1064           break;
1065 #endif
1066 #ifdef XK_Print
1067         case XK_Print:
1068           key_event = BX_KEY_PRINT;
1069           break;
1070 #endif
1071 #ifdef XK_Pause
1072         case XK_Pause:
1073           key_event = BX_KEY_PAUSE;
1074           break;
1075 #endif
1076 
1077         case XK_Insert:
1078           key_event = BX_KEY_INSERT;
1079           break;
1080         case XK_Home:
1081           key_event = BX_KEY_HOME;
1082           break;
1083         case XK_End:
1084           key_event = BX_KEY_END;
1085           break;
1086         case XK_Page_Up:
1087           key_event = BX_KEY_PAGE_UP;
1088           break;
1089         case XK_Page_Down:
1090           key_event = BX_KEY_PAGE_DOWN;
1091           break;
1092 
1093         default:
1094           BX_ERROR(("rfbKeyPress(): key %04x unhandled!", key));
1095           return;
1096       }
1097     }
1098   } else {
1099     BXKeyEntry *entry = bx_keymap.findHostKey(key);
1100     if (!entry) {
1101       BX_ERROR(("rfbKeyPressed(): key %x unhandled!", (unsigned) key));
1102       return;
1103     }
1104     key_event = entry->baseKey;
1105   }
1106 
1107   if (!press_release)
1108     key_event |= BX_KEY_RELEASED;
1109   DEV_kbd_gen_scancode(key_event);
1110 }
1111 
1112 // RFB specific functions
1113 
1114 #ifdef BX_RFB_WIN32
InitWinsock()1115 bool InitWinsock()
1116 {
1117   WSADATA wsaData;
1118   if (WSAStartup(MAKEWORD(1,1), &wsaData) != 0) return false;
1119   return true;
1120 }
1121 
StopWinsock()1122 bool StopWinsock()
1123 {
1124   WSACleanup();
1125   return true;
1126 }
1127 #endif
1128 
BX_THREAD_FUNC(rfbServerThreadInit,indata)1129 BX_THREAD_FUNC(rfbServerThreadInit, indata)
1130 {
1131     SOCKET             sServer;
1132     SOCKET             sClient;
1133     struct sockaddr_in sai;
1134     unsigned int       sai_size;
1135     int port_ok = 0;
1136     int one=1;
1137 
1138 #ifdef WIN32
1139     SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_IDLE);
1140 #endif
1141 #ifdef BX_RFB_WIN32
1142     if(!InitWinsock()) {
1143         BX_PANIC(("could not initialize winsock."));
1144         goto end_of_thread;
1145     }
1146 #endif
1147 
1148     sServer = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
1149     if(sServer == (SOCKET) -1) {
1150         BX_PANIC(("could not create socket."));
1151         goto end_of_thread;
1152     }
1153     if (setsockopt(sServer, SOL_SOCKET, SO_REUSEADDR, (const char *)&one, sizeof(int)) == -1)  {
1154         BX_PANIC(("could not set socket option."));
1155         goto end_of_thread;
1156     }
1157 
1158     for (rfbPort = BX_RFB_PORT_MIN; rfbPort <= BX_RFB_PORT_MAX; rfbPort++) {
1159       sai.sin_addr.s_addr = INADDR_ANY;
1160       sai.sin_family      = AF_INET;
1161       sai.sin_port        = htons(rfbPort);
1162       BX_INFO (("Trying port %d", rfbPort));
1163       if(bind(sServer, (struct sockaddr *)&sai, sizeof(sai)) == -1) {
1164           BX_INFO(("Could not bind socket."));
1165           continue;
1166       }
1167       if(listen(sServer, SOMAXCONN) == -1) {
1168           BX_INFO(("Could not listen on socket."));
1169           continue;
1170       }
1171       // success
1172       port_ok = 1;
1173       break;
1174     }
1175     if (!port_ok) {
1176       BX_PANIC (("RFB could not bind any port between %d and %d",
1177         BX_RFB_PORT_MIN,
1178         BX_RFB_PORT_MAX));
1179       goto end_of_thread;
1180     }
1181     BX_INFO (("listening for connections on port %i", rfbPort));
1182     sai_size = sizeof(sai);
1183     while (keep_alive) {
1184         sClient = accept(sServer, (struct sockaddr *)&sai, (socklen_t*)&sai_size);
1185         if(sClient != INVALID_SOCKET) {
1186             HandleRfbClient(sClient);
1187             sGlobal = INVALID_SOCKET;
1188             close(sClient);
1189         } else {
1190             close(sClient);
1191         }
1192     }
1193 
1194 end_of_thread:
1195 #ifdef BX_RFB_WIN32
1196     StopWinsock();
1197 #endif
1198   BX_THREAD_EXIT;
1199 }
1200 
rfbStartThread()1201 void rfbStartThread()
1202 {
1203   BX_THREAD_VAR(thread_var);
1204 
1205   BX_THREAD_CREATE(rfbServerThreadInit, NULL, thread_var);
1206   UNUSED(thread_var);
1207 }
1208 
HandleRfbClient(SOCKET sClient)1209 void HandleRfbClient(SOCKET sClient)
1210 {
1211   char rfbName[] = "Bochs-RFB";
1212   rfbProtocolVersionMessage pv;
1213   int one = 1;
1214   U32 auth;
1215   rfbClientInitMessage cim;
1216   rfbServerInitMessage sim;
1217   bool mouse_toggle = 0;
1218   static Bit8u wheel_status = 0;
1219 
1220   setsockopt(sClient, IPPROTO_TCP, TCP_NODELAY, (const char *)&one, sizeof(one));
1221   BX_INFO(("accepted client connection."));
1222   snprintf(pv, rfbProtocolVersionMessageSize + 1,
1223            rfbProtocolVersionFormat,
1224            rfbServerProtocolMajorVersion,
1225            rfbServerProtocolMinorVersion);
1226 
1227   if(WriteExact(sClient, pv, rfbProtocolVersionMessageSize) < 0) {
1228     BX_ERROR(("could not send protocol version."));
1229     return;
1230   }
1231   if(ReadExact(sClient, pv, rfbProtocolVersionMessageSize) < 0) {
1232     BX_ERROR(("could not receive client protocol version."));
1233     return;
1234   }
1235   pv[rfbProtocolVersionMessageSize-1]=0; // Drop last character
1236   BX_INFO(("Client protocol version is '%s'", pv));
1237   // FIXME should check for version number
1238 
1239   auth = htonl(rfbSecurityNone);
1240 
1241   if(WriteExact(sClient, (char *)&auth, sizeof(auth)) < 0) {
1242     BX_ERROR(("could not send authorization method."));
1243     return;
1244   }
1245 
1246   if(ReadExact(sClient, (char *)&cim, rfbClientInitMessageSize) < 0) {
1247     BX_ERROR(("could not receive client initialization message."));
1248     return;
1249   }
1250 
1251   sim.framebufferWidth  = htons((short)rfbWindowX);
1252   sim.framebufferHeight = htons((short)rfbWindowY);
1253   sim.serverPixelFormat            = BGR233Format;
1254   sim.serverPixelFormat.redMax     = htons(sim.serverPixelFormat.redMax);
1255   sim.serverPixelFormat.greenMax   = htons(sim.serverPixelFormat.greenMax);
1256   sim.serverPixelFormat.blueMax    = htons(sim.serverPixelFormat.blueMax);
1257   sim.nameLength = strlen(rfbName);
1258   sim.nameLength = htonl(sim.nameLength);
1259   if(WriteExact(sClient, (char *)&sim, rfbServerInitMessageSize) < 0) {
1260     BX_ERROR(("could send server initialization message."));
1261     return;
1262   }
1263   if(WriteExact(sClient, rfbName, strlen(rfbName)) < 0) {
1264     BX_ERROR (("could not send server name."));
1265     return;
1266   }
1267 
1268   client_connected = 1;
1269   sGlobal = sClient;
1270   while (keep_alive) {
1271     U8 msgType;
1272     int n;
1273 
1274     if ((n = recv(sClient, (char *)&msgType, 1, MSG_PEEK)) <= 0) {
1275       if (n == 0) {
1276         // client closed connection
1277         client_connected = 0;
1278       } else {
1279         if (errno == EINTR)
1280           continue;
1281         BX_ERROR(("error receiving data."));
1282       }
1283       return;
1284     }
1285 
1286     switch (msgType) {
1287       case rfbSetPixelFormat:
1288         {
1289           rfbSetPixelFormatMessage spf;
1290           ReadExact(sClient, (char *)&spf, sizeof(rfbSetPixelFormatMessage));
1291 
1292           spf.pixelFormat.trueColourFlag = (spf.pixelFormat.trueColourFlag ? 1 : 0);
1293           spf.pixelFormat.bigEndianFlag = (spf.pixelFormat.bigEndianFlag ? 1 : 0);
1294           spf.pixelFormat.redMax = ntohs(spf.pixelFormat.redMax);
1295           spf.pixelFormat.greenMax = ntohs(spf.pixelFormat.greenMax);
1296           spf.pixelFormat.blueMax = ntohs(spf.pixelFormat.blueMax);
1297 
1298           rfbBGR233Format = 1;
1299           if (PF_EQ(spf.pixelFormat, RGB332Format)) {
1300             rfbBGR233Format = 0;
1301             status_leds[0] = 0x1c;
1302             status_leds[1] = 0xe0;
1303             status_leds[2] = 0xfc;
1304             status_gray_text = 0x92;
1305           } else if (!PF_EQ(spf.pixelFormat, BGR233Format)) {
1306             BX_ERROR(("client has wrong pixel format (%d %d %d %d %d %d %d %d %d %d)",
1307                       spf.pixelFormat.bitsPerPixel,spf.pixelFormat.depth,spf.pixelFormat.bigEndianFlag,
1308                       spf.pixelFormat.trueColourFlag,spf.pixelFormat.redMax,spf.pixelFormat.greenMax,
1309                       spf.pixelFormat.blueMax,spf.pixelFormat.redShift,spf.pixelFormat.greenShift,
1310                       spf.pixelFormat.blueShift));
1311             //return;
1312           }
1313           break;
1314         }
1315       case rfbFixColourMapEntries:
1316         {
1317           rfbFixColourMapEntriesMessage fcme;
1318           ReadExact(sClient, (char *)&fcme, sizeof(rfbFixColourMapEntriesMessage));
1319           break;
1320         }
1321       case rfbSetEncodings:
1322         {
1323           rfbSetEncodingsMessage se;
1324           Bit32u                 i;
1325           U32                    enc;
1326 
1327           // free previously registered encodings
1328           if (clientEncodings != NULL) {
1329             delete [] clientEncodings;
1330             clientEncodingsCount = 0;
1331           }
1332 
1333           ReadExact(sClient, (char *)&se, sizeof(rfbSetEncodingsMessage));
1334 
1335           // Alloc new clientEncodings
1336           clientEncodingsCount = ntohs(se.numberOfEncodings);
1337           clientEncodings = new Bit32u[clientEncodingsCount];
1338 
1339           for (i = 0; i < clientEncodingsCount; i++) {
1340             if ((n = ReadExact(sClient, (char *)&enc, sizeof(U32))) <= 0) {
1341               if (n == 0) {
1342                 // client closed connection
1343                 client_connected = 0;
1344               } else {
1345                 BX_ERROR(("error receiving data."));
1346               }
1347               return;
1348             }
1349             clientEncodings[i]=ntohl(enc);
1350           }
1351 
1352           // print supported encodings
1353           BX_INFO(("rfbSetEncodings : client supported encodings:"));
1354           for (i = 0; i < clientEncodingsCount; i++) {
1355             Bit32u j;
1356             bool found = 0;
1357             for (j=0; j < rfbEncodingsCount; j ++) {
1358               if (clientEncodings[i] == rfbEncodings[j].id) {
1359                 BX_INFO(("%08x %s", rfbEncodings[j].id, rfbEncodings[j].name));
1360                 found=1;
1361                 if (clientEncodings[i] == rfbEncodingDesktopSize) {
1362                   desktop_resizable = 1;
1363                 }
1364                 break;
1365               }
1366             }
1367             if (!found) BX_INFO(("%08x Unknown", clientEncodings[i]));
1368           }
1369           break;
1370         }
1371       case rfbFramebufferUpdateRequest:
1372         {
1373           rfbFramebufferUpdateRequestMessage fur;
1374 
1375           ReadExact(sClient, (char *)&fur, sizeof(rfbFramebufferUpdateRequestMessage));
1376           if(!fur.incremental) {
1377             rfbSetUpdateRegion(0, 0, rfbWindowX, rfbWindowY);
1378           } //else {
1379           //    if(fur.x < rfbUpdateRegion.x) rfbUpdateRegion.x = fur.x;
1380           //    if(fur.y < rfbUpdateRegion.x) rfbUpdateRegion.y = fur.y;
1381           //    if(((fur.x + fur.w) - rfbUpdateRegion.x) > rfbUpdateRegion.width) rfbUpdateRegion.width = ((fur.x + fur.w) - rfbUpdateRegion.x);
1382           //    if(((fur.y + fur.h) - rfbUpdateRegion.y) > rfbUpdateRegion.height) rfbUpdateRegion.height = ((fur.y + fur.h) - rfbUpdateRegion.y);
1383           //}
1384           //rfbUpdateRegion.updated = 1;
1385           break;
1386         }
1387       case rfbKeyEvent:
1388         {
1389           rfbKeyEventMessage ke;
1390           ReadExact(sClient, (char *)&ke, sizeof(rfbKeyEventMessage));
1391           ke.key = ntohl(ke.key);
1392           while (bKeyboardInUse) ;
1393 
1394           if ((ke.key == XK_Control_L) || (ke.key == XK_Control_R)) {
1395             mouse_toggle = bx_gui->mouse_toggle_check(BX_MT_KEY_CTRL, ke.downFlag);
1396           } else if (ke.key == XK_Alt_L) {
1397             mouse_toggle = bx_gui->mouse_toggle_check(BX_MT_KEY_ALT, ke.downFlag);
1398           } else if (ke.key == XK_F10) {
1399             mouse_toggle = bx_gui->mouse_toggle_check(BX_MT_KEY_F10, ke.downFlag);
1400           } else if (ke.key == XK_F12) {
1401             mouse_toggle = bx_gui->mouse_toggle_check(BX_MT_KEY_F12, ke.downFlag);
1402           }
1403           if (mouse_toggle) {
1404             bx_gui->toggle_mouse_enable();
1405           } else {
1406             bKeyboardInUse = 1;
1407             if (rfbKeyboardEvents >= MAX_KEY_EVENTS) break;
1408             rfbKeyboardEvent[rfbKeyboardEvents].type = KEYBOARD;
1409             rfbKeyboardEvent[rfbKeyboardEvents].key  = ke.key;
1410             rfbKeyboardEvent[rfbKeyboardEvents].down = ke.downFlag;
1411             rfbKeyboardEvents++;
1412             bKeyboardInUse = 0;
1413           }
1414           break;
1415         }
1416       case rfbPointerEvent:
1417         {
1418           rfbPointerEventMessage pe;
1419           ReadExact(sClient, (char *)&pe, sizeof(rfbPointerEventMessage));
1420           while (bKeyboardInUse) ;
1421 
1422           if (bx_gui->mouse_toggle_check(BX_MT_MBUTTON, (pe.buttonMask & 0x02) > 0)) {
1423             bx_gui->toggle_mouse_enable();
1424           } else {
1425             bKeyboardInUse = 1;
1426             if (rfbKeyboardEvents >= MAX_KEY_EVENTS) break;
1427             rfbKeyboardEvent[rfbKeyboardEvents].type = MOUSE;
1428             rfbKeyboardEvent[rfbKeyboardEvents].x    = ntohs(pe.xPosition);
1429             rfbKeyboardEvent[rfbKeyboardEvents].y    = ntohs(pe.yPosition);
1430             rfbKeyboardEvent[rfbKeyboardEvents].z    = 0;
1431             rfbKeyboardEvent[rfbKeyboardEvents].down = (pe.buttonMask & 0x01) |
1432                                                        ((pe.buttonMask>>1) & 0x02) |
1433                                                        ((pe.buttonMask<<1) & 0x04);
1434             if ((pe.buttonMask & 0x18) != wheel_status) {
1435               if (pe.buttonMask & 0x10) {
1436                 rfbKeyboardEvent[rfbKeyboardEvents].z = -1;
1437               } else if (pe.buttonMask & 0x08) {
1438                 rfbKeyboardEvent[rfbKeyboardEvents].z = 1;
1439               }
1440               wheel_status = pe.buttonMask & 0x18;
1441             }
1442             rfbKeyboardEvents++;
1443             bKeyboardInUse = 0;
1444           }
1445           break;
1446         }
1447       case rfbClientCutText:
1448         {
1449           rfbClientCutTextMessage cct;
1450           ReadExact(sClient, (char *)&cct, sizeof(rfbClientCutTextMessage));
1451           break;
1452         }
1453     }
1454   }
1455 }
1456 
1457 /*
1458 * ReadExact reads an exact number of bytes on a TCP socket.  Returns 1 if
1459 * those bytes have been read, 0 if the other end has closed, or -1 if an error
1460 * occurred (errno is set to ETIMEDOUT if it timed out).
1461 */
1462 
ReadExact(int sock,char * buf,int len)1463 int ReadExact(int sock, char *buf, int len)
1464 {
1465     while (len > 0) {
1466       int n = recv(sock, buf, len, 0);
1467       if (n > 0) {
1468         buf += n;
1469         len -= n;
1470       } else {
1471         return n;
1472       }
1473     }
1474     return 1;
1475 }
1476 
1477 /*
1478 * WriteExact writes an exact number of bytes on a TCP socket.  Returns 1 if
1479 * those bytes have been written, or -1 if an error occurred (errno is set to
1480 * ETIMEDOUT if it timed out).
1481 */
1482 
WriteExact(int sock,char * buf,int len)1483 int WriteExact(int sock, char *buf, int len)
1484 {
1485     while (len > 0) {
1486       int n = send(sock, buf, len,0);
1487 
1488       if (n > 0) {
1489         buf += n;
1490         len -= n;
1491       } else {
1492         if (n == 0) BX_ERROR(("WriteExact: write returned 0?"));
1493         return n;
1494       }
1495     }
1496     return 1;
1497 }
1498 
DrawBitmap(int x,int y,int width,int height,char * bmap,char fgcolor,char bgcolor,bool update_client)1499 void DrawBitmap(int x, int y, int width, int height, char *bmap,
1500         char fgcolor, char bgcolor, bool update_client)
1501 {
1502   unsigned char *newBits;
1503   newBits = new unsigned char[width * height];
1504   memset(newBits, 0, (width * height));
1505   for (int i = 0; i < (width * height) / 8; i++) {
1506     newBits[i * 8 + 0] = (bmap[i] & 0x01) ? fgcolor : bgcolor;
1507     newBits[i * 8 + 1] = (bmap[i] & 0x02) ? fgcolor : bgcolor;
1508     newBits[i * 8 + 2] = (bmap[i] & 0x04) ? fgcolor : bgcolor;
1509     newBits[i * 8 + 3] = (bmap[i] & 0x08) ? fgcolor : bgcolor;
1510     newBits[i * 8 + 4] = (bmap[i] & 0x10) ? fgcolor : bgcolor;
1511     newBits[i * 8 + 5] = (bmap[i] & 0x20) ? fgcolor : bgcolor;
1512     newBits[i * 8 + 6] = (bmap[i] & 0x40) ? fgcolor : bgcolor;
1513     newBits[i * 8 + 7] = (bmap[i] & 0x80) ? fgcolor : bgcolor;
1514   }
1515   UpdateScreen(newBits, x, y, width, height, update_client);
1516   delete [] newBits;
1517 }
1518 
DrawChar(int x,int y,int width,int height,int fontx,int fonty,char * bmap,char fgcolor,char bgcolor,bool gfxchar)1519 void DrawChar(int x, int y, int width, int height, int fontx, int fonty,
1520               char *bmap, char fgcolor, char bgcolor, bool gfxchar)
1521 {
1522   static unsigned char newBits[18 * 32];
1523   unsigned char mask;
1524   int bytes = width * height;
1525   bool dwidth = (width > 9);
1526   for (int i = 0; i < bytes; i += width) {
1527     mask = 0x80 >> fontx;
1528     for (int j = 0; j < width; j++) {
1529       if (mask > 0) {
1530         newBits[i + j] = (bmap[fonty] & mask) ? fgcolor : bgcolor;
1531       } else {
1532         if (gfxchar) {
1533           newBits[i + j] = (bmap[fonty] & 0x01) ? fgcolor : bgcolor;
1534         } else {
1535           newBits[i + j] = bgcolor;
1536         }
1537       }
1538       if (!dwidth || (j & 1)) mask >>= 1;
1539     }
1540     fonty++;
1541   }
1542   UpdateScreen(newBits, x, y, width, height, 0);
1543 }
1544 
UpdateScreen(unsigned char * newBits,int x,int y,int width,int height,bool update_client)1545 void UpdateScreen(unsigned char *newBits, int x, int y, int width, int height,
1546                   bool update_client)
1547 {
1548   int i, x0, y0;
1549   x0 = x;
1550   y0 = y;
1551   if ((unsigned)(x + width - 1) >= rfbWindowX) {
1552     width = rfbWindowX - x + 1;
1553   }
1554   if ((unsigned)(y + height - 1) >= rfbWindowY) {
1555     height = rfbWindowY - y + 1;
1556   }
1557   for (i = 0; i < height; i++) {
1558     memcpy(&rfbScreen[y * rfbWindowX + x0], &newBits[i * width], width);
1559     y++;
1560   }
1561   if (update_client) {
1562     if(sGlobal == INVALID_SOCKET) return;
1563     rfbFramebufferUpdateMessage fum;
1564     rfbFramebufferUpdateRectHeader furh;
1565     fum.messageType = rfbFramebufferUpdate;
1566     fum.numberOfRectangles = htons(1);
1567     WriteExact(sGlobal, (char *)&fum, rfbFramebufferUpdateMessageSize);
1568     furh.r.xPosition = htons(x0);
1569     furh.r.yPosition = htons(y0);
1570     furh.r.width = htons((short)width);
1571     furh.r.height = htons((short)height);
1572     furh.r.encodingType = htonl(rfbEncodingRaw);
1573     WriteExact(sGlobal, (char *)&furh, rfbFramebufferUpdateRectHeaderSize);
1574     WriteExact(sGlobal, (char *)newBits, width * height);
1575   }
1576 }
1577 
SendUpdate(int x,int y,int width,int height,Bit32u encoding)1578 void SendUpdate(int x, int y, int width, int height, Bit32u encoding)
1579 {
1580     char *newBits;
1581 
1582     if(x < 0 || y < 0 || (x + width) > (int)rfbWindowX || (y + height) > (int)rfbWindowY) {
1583         BX_ERROR(("Dimensions out of bounds.  x=%i y=%i w=%i h=%i", x, y, width, height));
1584     }
1585     if(sGlobal != INVALID_SOCKET) {
1586         rfbFramebufferUpdateMessage fum;
1587         rfbFramebufferUpdateRectHeader furh;
1588 
1589         fum.messageType = rfbFramebufferUpdate;
1590         fum.numberOfRectangles = htons(1);
1591 
1592         furh.r.xPosition = htons(x);
1593         furh.r.yPosition = htons(y);
1594         furh.r.width = htons((short)width);
1595         furh.r.height = htons((short)height);
1596         furh.r.encodingType = htonl(encoding);
1597 
1598         WriteExact(sGlobal, (char *)&fum, rfbFramebufferUpdateMessageSize);
1599         WriteExact(sGlobal, (char *)&furh, rfbFramebufferUpdateRectHeaderSize);
1600 
1601         if (encoding == rfbEncodingRaw) {
1602           newBits = new char[width * height];
1603           for(int i = 0; i < height; i++) {
1604             memcpy(&newBits[i * width], &rfbScreen[y * rfbWindowX + x], width);
1605             y++;
1606           }
1607           WriteExact(sGlobal, (char *)newBits, width * height);
1608           delete [] newBits;
1609         }
1610     }
1611 }
1612 
rfbSetUpdateRegion(unsigned x0,unsigned y0,unsigned w,unsigned h)1613 void rfbSetUpdateRegion(unsigned x0, unsigned y0, unsigned w, unsigned h)
1614 {
1615   rfbUpdateRegion.x = x0;
1616   rfbUpdateRegion.y = y0;
1617   rfbUpdateRegion.width  = w;
1618   rfbUpdateRegion.height = h;
1619   rfbUpdateRegion.updated = ((w > 0) && (h > 0));
1620 }
1621 
rfbAddUpdateRegion(unsigned x0,unsigned y0,unsigned w,unsigned h)1622 void rfbAddUpdateRegion(unsigned x0, unsigned y0, unsigned w, unsigned h)
1623 {
1624   unsigned x1, y1;
1625 
1626   if (!rfbUpdateRegion.updated) {
1627     rfbSetUpdateRegion(x0, y0, w, h);
1628   } else {
1629     x1 = rfbUpdateRegion.x + rfbUpdateRegion.width;
1630     y1 = rfbUpdateRegion.y + rfbUpdateRegion.height;
1631     if (x0 < rfbUpdateRegion.x) {
1632       rfbUpdateRegion.x = x0;
1633     }
1634     if (y0 < rfbUpdateRegion.y) {
1635       rfbUpdateRegion.y = y0;
1636     }
1637     if ((x0 + w) > x1) {
1638       rfbUpdateRegion.width = x0 + w - rfbUpdateRegion.x;
1639     } else {
1640       rfbUpdateRegion.width= x1 - rfbUpdateRegion.x;
1641     }
1642     if ((y0 + h) > y1) {
1643       rfbUpdateRegion.height = y0 + h - rfbUpdateRegion.y;
1644     } else {
1645       rfbUpdateRegion.height = y1 - rfbUpdateRegion.y;
1646     }
1647     if ((rfbUpdateRegion.x + rfbUpdateRegion.width) > rfbWindowX) {
1648       rfbUpdateRegion.width = rfbWindowX - rfbUpdateRegion.x;
1649     }
1650     if ((rfbUpdateRegion.y + rfbUpdateRegion.height) > rfbWindowY) {
1651       rfbUpdateRegion.height = rfbWindowY - rfbUpdateRegion.y;
1652     }
1653     rfbUpdateRegion.updated = 1;
1654   }
1655 }
1656 
rfbSetStatusText(int element,const char * text,bool active,Bit8u color)1657 void rfbSetStatusText(int element, const char *text, bool active, Bit8u color)
1658 {
1659   char *newBits;
1660   unsigned xleft, xsize, i, len;
1661 
1662   rfbStatusitemActive[element] = active;
1663   xleft = rfbStatusitemPos[element] + 2;
1664   xsize = rfbStatusitemPos[element + 1] - xleft - 1;
1665   newBits = new char[((xsize / 8) + 1) * (rfbStatusbarY - 2)];
1666   memset(newBits, 0, ((xsize / 8) + 1) * (rfbStatusbarY - 2));
1667   for (i = 0; i < (rfbStatusbarY - 2); i++) {
1668     newBits[((xsize / 8) + 1) * i] = 0;
1669   }
1670 
1671   Bit8u fgcolor = active ? headerbar_fg : status_gray_text;
1672   Bit8u bgcolor = 0;
1673   if ((element > 0) && active) {
1674     bgcolor = status_leds[color];
1675   } else {
1676     bgcolor = headerbar_bg;
1677   }
1678   DrawBitmap(xleft, rfbWindowY - rfbStatusbarY + 1, xsize, rfbStatusbarY - 2,
1679              newBits, fgcolor, bgcolor, 0);
1680 
1681   delete [] newBits;
1682   len = ((element > 0) && (strlen(text) > 4)) ? 4 : strlen(text);
1683   for (i = 0; i < len; i++) {
1684     DrawChar(xleft + i * 8 + 2, rfbWindowY - rfbStatusbarY + 5, 8, 8, 0, 0,
1685              (char *) &sdl_font8x8[(unsigned) text[i]][0], fgcolor, bgcolor, 0);
1686   }
1687 
1688   rfbAddUpdateRegion(xleft, rfbWindowY - rfbStatusbarY + 1, xsize, rfbStatusbarY - 2);
1689 }
1690 
1691 #if BX_SHOW_IPS && defined(WIN32)
IPSTimerProc(HWND hWnd,UINT nMsg,UINT_PTR nIDEvent,DWORD dwTime)1692 VOID CALLBACK IPSTimerProc(HWND hWnd, UINT nMsg, UINT_PTR nIDEvent, DWORD dwTime)
1693 {
1694   if (keep_alive) {
1695     bx_show_ips_handler();
1696   }
1697 }
1698 
rfbShowIPSthread(LPVOID)1699 DWORD WINAPI rfbShowIPSthread(LPVOID)
1700 {
1701   MSG msg;
1702 
1703   UINT TimerId = SetTimer(NULL, 0, 1000, &IPSTimerProc);
1704   while (keep_alive && GetMessage(&msg, NULL, 0, 0)) {
1705     DispatchMessage(&msg);
1706   }
1707   KillTimer(NULL, TimerId);
1708   return 0;
1709 }
1710 #endif
1711 
1712 #endif /* if BX_WITH_RFB */
1713