VirtualBox

source: vbox/trunk/src/VBox/ExtPacks/VNC/VBoxVNC.cpp@ 87466

Last change on this file since 87466 was 82968, checked in by vboxsync, 5 years ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 48.3 KB
Line 
1/* $Id: VBoxVNC.cpp 82968 2020-02-04 10:35:17Z vboxsync $ */
2/** @file
3 * VBoxVNC - VNC VRDE module.
4 */
5
6/*
7 * Contributed by Ivo Smits <Ivo@UFO-Net.nl>, Howard Su and
8 * Christophe Devriese <christophe.devriese@gmail.com>.
9 *
10 * Copyright (C) 2011-2020 Oracle Corporation
11 *
12 * This file is part of VirtualBox Open Source Edition (OSE), as
13 * available from http://www.virtualbox.org. This file is free software;
14 * you can redistribute it and/or modify it under the terms of the GNU
15 * General Public License (GPL) as published by the Free Software
16 * Foundation, in version 2 as it comes in the "COPYING" file of the
17 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
18 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
19 */
20
21
22/*********************************************************************************************************************************
23* Header Files *
24*********************************************************************************************************************************/
25#define LOG_GROUP LOG_GROUP_VRDE
26#include <VBox/log.h>
27
28#include <iprt/asm.h>
29#include <iprt/alloca.h>
30#include <iprt/ldr.h>
31#include <iprt/param.h>
32#include <iprt/path.h>
33#include <iprt/mem.h>
34#include <iprt/socket.h>
35#include <iprt/stream.h>
36#include <iprt/string.h>
37#include <iprt/thread.h>
38#include <iprt/cpp/utils.h>
39
40#include <iprt/errcore.h>
41#include <VBox/RemoteDesktop/VRDEOrders.h>
42#include <VBox/RemoteDesktop/VRDE.h>
43
44#include <rfb/rfb.h>
45
46#ifdef LIBVNCSERVER_IPv6
47// enable manually!
48// #define VBOX_USE_IPV6
49#endif
50
51
52/*********************************************************************************************************************************
53* Defined Constants And Macros *
54*********************************************************************************************************************************/
55#define VNC_SIZEOFRGBA 4
56#define VNC_PASSWORDSIZE 20
57#define VNC_ADDRESSSIZE 60
58#define VNC_PORTSSIZE 20
59#define VNC_ADDRESS_OPTION_MAX 500
60
61
62/*********************************************************************************************************************************
63* Structures and Typedefs *
64*********************************************************************************************************************************/
65class VNCServerImpl
66{
67public:
68 VNCServerImpl()
69 {
70 mVNCServer = NULL;
71 mFrameBuffer = NULL;
72 mScreenBuffer = NULL;
73 mCursor = NULL;
74 uClients = 0;
75 }
76
77 ~VNCServerImpl()
78 {
79 if (mFrameBuffer)
80 RTMemFree(mFrameBuffer);
81 if (mCursor)
82 rfbFreeCursor(mCursor);
83 RT_ZERO(szVNCPassword);
84 if (mVNCServer)
85 rfbScreenCleanup(mVNCServer);
86 }
87
88 int Init(const VRDEINTERFACEHDR *pCallbacks, void *pvCallback);
89
90 VRDEINTERFACEHDR *GetInterface() { return &Entries.header; }
91
92private:
93 // VNC password
94 char szVNCPassword[VNC_PASSWORDSIZE + 1];
95 // the structure we pass to libvncserver
96 char *apszVNCPasswordStruct[2];
97
98 // VNC related variables
99 rfbScreenInfoPtr mVNCServer;
100 void *mCallback;
101 rfbCursorPtr mCursor;
102 VRDEFRAMEBUFFERINFO FrameInfo;
103 unsigned char *mScreenBuffer;
104 unsigned char *mFrameBuffer;
105 uint32_t uClients;
106 static enum rfbNewClientAction rfbNewClientEvent(rfbClientPtr cl);
107 static void vncMouseEvent(int buttonMask, int x, int y, rfbClientPtr cl);
108 static void vncKeyboardEvent(rfbBool down, rfbKeySym keySym, rfbClientPtr cl);
109 static void clientGoneHook(rfbClientPtr cl);
110
111 static uint32_t RGB2BGR(uint32_t c)
112 {
113 c = ((c >> 0) & 0xff) << 16 |
114 ((c >> 8) & 0xff) << 8 |
115 ((c >> 16) & 0xff) << 0;
116
117 return c;
118 }
119
120 int queryVrdeFeature(const char *pszName, char *pszValue, size_t cbValue);
121
122 static VRDEENTRYPOINTS_4 Entries;
123 VRDECALLBACKS_4 *mCallbacks;
124
125 static DECLCALLBACK(void) VRDEDestroy(HVRDESERVER hServer);
126 static DECLCALLBACK(int) VRDEEnableConnections(HVRDESERVER hServer, bool fEnable);
127 static DECLCALLBACK(void) VRDEDisconnect(HVRDESERVER hServer, uint32_t u32ClientId, bool fReconnect);
128 static DECLCALLBACK(void) VRDEResize(HVRDESERVER hServer);
129 static DECLCALLBACK(void) VRDEUpdate(HVRDESERVER hServer, unsigned uScreenId, void *pvUpdate,uint32_t cbUpdate);
130 static DECLCALLBACK(void) VRDEColorPointer(HVRDESERVER hServer, const VRDECOLORPOINTER *pPointer);
131 static DECLCALLBACK(void) VRDEHidePointer(HVRDESERVER hServer);
132 static DECLCALLBACK(void) VRDEAudioSamples(HVRDESERVER hServer, const void *pvSamples, uint32_t cSamples, VRDEAUDIOFORMAT format);
133 static DECLCALLBACK(void) VRDEAudioVolume(HVRDESERVER hServer, uint16_t u16Left, uint16_t u16Right);
134 static DECLCALLBACK(void) VRDEUSBRequest(HVRDESERVER hServer,
135 uint32_t u32ClientId,
136 void *pvParm,
137 uint32_t cbParm);
138 static DECLCALLBACK(void) VRDEClipboard(HVRDESERVER hServer,
139 uint32_t u32Function,
140 uint32_t u32Format,
141 void *pvData,
142 uint32_t cbData,
143 uint32_t *pcbActualRead);
144 static DECLCALLBACK(void) VRDEQueryInfo(HVRDESERVER hServer,
145 uint32_t index,
146 void *pvBuffer,
147 uint32_t cbBuffer,
148 uint32_t *pcbOut);
149 static DECLCALLBACK(void) VRDERedirect(HVRDESERVER hServer,
150 uint32_t u32ClientId,
151 const char *pszServer,
152 const char *pszUser,
153 const char *pszDomain,
154 const char *pszPassword,
155 uint32_t u32SessionId,
156 const char *pszCookie);
157 static DECLCALLBACK(void) VRDEAudioInOpen(HVRDESERVER hServer,
158 void *pvCtx,
159 uint32_t u32ClientId,
160 VRDEAUDIOFORMAT audioFormat,
161 uint32_t u32SamplesPerBlock);
162 static DECLCALLBACK(void) VRDEAudioInClose(HVRDESERVER hServer,
163 uint32_t u32ClientId);
164};
165
166VRDEENTRYPOINTS_4 VNCServerImpl::Entries = {
167 { VRDE_INTERFACE_VERSION_3, sizeof(VRDEENTRYPOINTS_3) },
168 VNCServerImpl::VRDEDestroy,
169 VNCServerImpl::VRDEEnableConnections,
170 VNCServerImpl::VRDEDisconnect,
171 VNCServerImpl::VRDEResize,
172 VNCServerImpl::VRDEUpdate,
173 VNCServerImpl::VRDEColorPointer,
174 VNCServerImpl::VRDEHidePointer,
175 VNCServerImpl::VRDEAudioSamples,
176 VNCServerImpl::VRDEAudioVolume,
177 VNCServerImpl::VRDEUSBRequest,
178 VNCServerImpl::VRDEClipboard,
179 VNCServerImpl::VRDEQueryInfo,
180 VNCServerImpl::VRDERedirect,
181 VNCServerImpl::VRDEAudioInOpen,
182 VNCServerImpl::VRDEAudioInClose
183};
184
185
186/** Destroy the server instance.
187 *
188 * @param hServer The server instance handle.
189 *
190 * @return IPRT status code.
191 */
192DECLCALLBACK(void) VNCServerImpl::VRDEDestroy(HVRDESERVER hServer)
193{
194 VNCServerImpl *instance = (VNCServerImpl *)hServer;
195 rfbShutdownServer(instance->mVNCServer, TRUE);
196
197 uint32_t port = UINT32_MAX;
198 instance->mCallbacks->VRDECallbackProperty(instance->mCallback,
199 VRDE_SP_NETWORK_BIND_PORT,
200 &port, sizeof(port), NULL);
201 return;
202}
203
204
205/**
206 * Query a feature and store it's value in a user supplied buffer.
207 *
208 * @returns VBox status code.
209 * @param pszName The feature name.
210 * @param pszValue The value buffer. The buffer is not touched at
211 * all on failure.
212 * @param cbValue The size of the output buffer.
213 */
214int VNCServerImpl::queryVrdeFeature(const char *pszName, char *pszValue, size_t cbValue)
215{
216 union
217 {
218 VRDEFEATURE Feat;
219 uint8_t abBuf[VNC_ADDRESS_OPTION_MAX + sizeof(VRDEFEATURE)];
220 } u;
221
222 u.Feat.u32ClientId = 0;
223 int rc = RTStrCopy(u.Feat.achInfo, VNC_ADDRESS_OPTION_MAX, pszName); AssertRC(rc);
224 if (RT_SUCCESS(rc))
225 {
226 uint32_t cbOut = 0;
227 rc = mCallbacks->VRDECallbackProperty(mCallback,
228 VRDE_QP_FEATURE,
229 &u.Feat,
230 VNC_ADDRESS_OPTION_MAX,
231 &cbOut);
232 if (RT_SUCCESS(rc))
233 {
234 size_t cbRet = strlen(u.Feat.achInfo) + 1;
235 if (cbRet <= cbValue)
236 memcpy(pszValue, u.Feat.achInfo, cbRet);
237 else
238 rc = VERR_BUFFER_OVERFLOW;
239 }
240 }
241
242 return rc;
243}
244
245
246/** The server should start to accept clients connections.
247 *
248 * @param hServer The server instance handle.
249 * @param fEnable Whether to enable or disable client connections.
250 * When is false, all existing clients are disconnected.
251 *
252 * @return IPRT status code.
253 */
254DECLCALLBACK(int) VNCServerImpl::VRDEEnableConnections(HVRDESERVER hServer, bool fEnable)
255{
256 RT_NOREF(fEnable);
257 VNCServerImpl *instance = (VNCServerImpl *)hServer;
258
259#ifdef LOG_ENABLED
260 // enable logging
261 rfbLogEnable(true);
262#endif
263 LogFlowFunc(("enter\n"));
264
265 // At this point, VRDECallbackFramebufferQuery will not succeed.
266 // Initialize VNC with 640x480 and wait for VRDEResize to get actual size.
267 int dummyWidth = 640, dummyHeight = 480;
268
269 rfbScreenInfoPtr vncServer = rfbGetScreen(0, NULL, dummyWidth, dummyHeight, 8, 3, VNC_SIZEOFRGBA);
270 instance->mVNCServer = vncServer;
271
272 VRDEFRAMEBUFFERINFO info;
273 RT_ZERO(info);
274 info.cWidth = dummyWidth, info.cHeight = dummyHeight;
275 info.cBitsPerPixel = 24;
276 info.pu8Bits = NULL;
277 unsigned char *FrameBuffer = (unsigned char *)RTMemAlloc(info.cWidth * info.cHeight * VNC_SIZEOFRGBA); // RGBA
278 rfbNewFramebuffer(instance->mVNCServer, (char *)FrameBuffer, info.cWidth, info.cHeight, 8, 3, VNC_SIZEOFRGBA);
279 instance->mFrameBuffer = FrameBuffer;
280 instance->mScreenBuffer = (unsigned char *)info.pu8Bits;
281 instance->FrameInfo = info;
282
283 vncServer->serverFormat.redShift = 16;
284 vncServer->serverFormat.greenShift = 8;
285 vncServer->serverFormat.blueShift = 0;
286 vncServer->screenData = (void *)instance;
287 vncServer->desktopName = "VBoxVNC";
288
289#ifndef VBOX_USE_IPV6
290
291 // get listen address
292 char szAddress[VNC_ADDRESSSIZE + 1] = {0};
293 uint32_t cbOut = 0;
294 int rc = instance->mCallbacks->VRDECallbackProperty(instance->mCallback,
295 VRDE_QP_NETWORK_ADDRESS,
296 &szAddress, sizeof(szAddress), &cbOut);
297 Assert(cbOut <= sizeof(szAddress));
298 if (RT_SUCCESS(rc) && szAddress[0])
299 {
300 if (!rfbStringToAddr(szAddress, &vncServer->listenInterface))
301 LogRel(("VNC: could not parse VNC server listen address '%s'\n", szAddress));
302 }
303
304 // get listen port
305 uint32_t port = 0;
306 rc = instance->mCallbacks->VRDECallbackProperty(instance->mCallback,
307 VRDE_QP_NETWORK_PORT,
308 &port, sizeof(port), &cbOut);
309 Assert(cbOut <= sizeof(port));
310 if (RT_SUCCESS(rc) && port != 0)
311 vncServer->port = port;
312 else
313 {
314 const char szFeatName[] = "Property/TCP/Ports";
315 const uint32_t featLen = sizeof(VRDEFEATURE) + RT_MAX(VNC_PORTSSIZE, sizeof(szFeatName)) - 1;
316 VRDEFEATURE *feature = (VRDEFEATURE *)RTMemTmpAlloc(featLen);
317 feature->u32ClientId = 0;
318 RTStrCopy(feature->achInfo, featLen - sizeof(VRDEFEATURE) + 1, szFeatName);
319
320 cbOut = featLen;
321 rc = instance->mCallbacks->VRDECallbackProperty(instance->mCallback, VRDE_QP_FEATURE, feature, featLen, &cbOut);
322 Assert(cbOut <= featLen);
323
324 if (RT_SUCCESS(rc) && feature->achInfo[0])
325 {
326 rc = RTStrToUInt32Ex(feature->achInfo, NULL, 0, &port);
327 if (RT_FAILURE(rc) || port >= 65535)
328 vncServer->autoPort = 1;
329 else
330 vncServer->port = port;
331 }
332 else
333 vncServer->autoPort = 1;
334
335 RTMemTmpFree(feature);
336 }
337
338 rfbInitServer(vncServer);
339
340 vncServer->newClientHook = rfbNewClientEvent;
341 vncServer->kbdAddEvent = vncKeyboardEvent;
342 vncServer->ptrAddEvent = vncMouseEvent;
343
344 // notify about the actually used port
345 port = vncServer->port;
346 instance->mCallbacks->VRDECallbackProperty(instance->mCallback,
347 VRDE_SP_NETWORK_BIND_PORT,
348 &port, sizeof(port), NULL);
349 LogRel(("VNC: port = %u\n", port));
350#else
351 // with IPv6 from here
352 /*
353
354 This is the deal:
355
356 Four new options are available:
357 - VNCAddress4 -> IPv4 address to use
358 - VNCPort4 -> IPv4 Port to use
359 - VNCAddress6 -> IPv6 address to use
360 - VNCPort6 -> IPv6 port to use
361
362 By default we prefer IPv6 over IPv4.
363
364 The address length can be unlimited as the interface identifier is not
365 limited by any specs - if this is wrong, and someone knows the line
366 and the RFC number, i'd appreciate a message :)
367
368 THE MAXIMUM LENGTH OF THE RETURNED VALUES MUST NOT BE GREATER THAN:
369
370 --> VBOX_ADDRESS_OPTION_MAX <--
371
372 which is defined at the top of this file.
373
374 The way to determine which address to use is as follows:
375
376 1st - get address information from VRDEProperties
377 "TCP/Address"
378 "TCP/Ports"
379
380 2nd - if the address information is IPv4 get VNCAddress6 and VNCPort6
381 2nd - if the address information is IPv6 get VNCAddress4 and VNCPort4
382 2nd - if the address information is EMPTY and TCP/Ports returns 3389,
383 check both, VNCAddress4 and VNCAddress6 as well as the ports.
384 3389 is not a valid VNC port, therefore we assume it's not
385 been set
386
387 If one of the addresses is empty we assume to listen on any
388 interface/address for that protocol. In other words:
389 IPv4: 0.0.0.0
390 IPv6: ::
391
392 2nd - if everything is empty -> listen on all interfaces
393
394 3rd - check if the addresses are valid hand them to libvncserver
395 to open the initial sockets.
396
397 4th - after the sockets have been opened, the used port of the
398 address/protocol in TCP/Address is returned.
399 if TCP/Address is empty, prefer IPv6
400
401 */
402
403 /* ok, now first get the address from VRDE/TCP/Address.
404
405 */
406 // this should be put somewhere else
407 char szIPv6ListenAll[] = "::";
408 char szIPv4ListenAll[] = "0.0.0.0";
409
410 uint32_t uServerPort4 = 0;
411 uint32_t uServerPort6 = 0;
412 uint32_t cbOut = 0;
413 size_t resSize = 0;
414 RTNETADDRTYPE enmAddrType;
415 char *pszVNCAddress6 = NULL;
416 char *pszVNCPort6 = NULL;
417 char *pszServerAddress4 = NULL;
418 char *pszServerAddress6 = NULL;
419 char *pszGetAddrInfo4 = NULL; // used to store the result of RTSocketQueryAddressStr()
420 char *pszGetAddrInfo6 = NULL; // used to store the result of RTSocketQueryAddressStr()
421
422 // get address
423 char *pszTCPAddress = (char *)RTMemTmpAllocZ(VNC_ADDRESS_OPTION_MAX);
424 rc = instance->mCallbacks->VRDECallbackProperty(instance->mCallback,
425 VRDE_QP_NETWORK_ADDRESS,
426 pszTCPAddress,
427 VNC_ADDRESS_OPTION_MAX,
428 &cbOut);
429
430 // get port (range)
431 char *pszTCPPort = (char *)RTMemTmpAllocZ(VNC_ADDRESS_OPTION_MAX);
432 rc = instance->mCallbacks->VRDECallbackProperty(instance->mCallback,
433 VRDE_QP_NETWORK_PORT_RANGE,
434 pszTCPPort,
435 VNC_ADDRESS_OPTION_MAX,
436 &cbOut);
437 Assert(cbOut < VNC_ADDRESS_OPTION_MAX);
438
439 // get tcp ports option from vrde.
440 /** @todo r=bird: Is this intentionally overriding VRDE_QP_NETWORK_PORT_RANGE? */
441 instance->queryVrdeFeature("Property/TCP/Ports", pszTCPPort, VNC_ADDRESS_OPTION_MAX);
442
443 // get VNCAddress4
444 char *pszVNCAddress4 = (char *)RTMemTmpAllocZ(24);
445 instance->queryVrdeFeature("Property/VNCAddress4", pszVNCAddress4, 24);
446
447 // VNCPort4
448 char *pszVNCPort4 = (char *)RTMemTmpAlloc(6);
449 instance->queryVrdeFeature("Property/VNCPort4", pszVNCPort4, 6);
450
451 // VNCAddress6
452 pszVNCAddress6 = (char *) RTMemTmpAllocZ(VNC_ADDRESS_OPTION_MAX);
453 instance->queryVrdeFeature("Property/VNCAddress6", pszVNCAddress6, VNC_ADDRESS_OPTION_MAX);
454
455 // VNCPort6
456 pszVNCPort6 = (char *)RTMemTmpAllocZ(6);
457 instance->queryVrdeFeature("Property/VNCPort6", pszVNCPort6, 6);
458
459
460 if (RTNetIsIPv4AddrStr(pszTCPAddress))
461 {
462 pszServerAddress4 = pszTCPAddress;
463
464 if (strlen(pszTCPPort) > 0)
465 {
466 rc = RTStrToUInt32Ex(pszTCPPort, NULL, 10, &uServerPort4);
467 if (!RT_SUCCESS(rc) || uServerPort4 > 65535)
468 uServerPort4 = 0;
469 }
470
471 if (RTNetIsIPv6AddrStr(pszVNCAddress6))
472 pszServerAddress6 = pszVNCAddress6;
473 else
474 pszServerAddress6 = szIPv6ListenAll;
475
476 if (strlen(pszVNCPort6) > 0)
477 {
478 rc = RTStrToUInt32Ex(pszVNCPort6, NULL, 10, &uServerPort6);
479 if (!RT_SUCCESS(rc) || uServerPort6 > 65535)
480 uServerPort6 = 0;
481
482 }
483
484 }
485
486 if (RTNetIsIPv6AddrStr(pszTCPAddress))
487 {
488 pszServerAddress6 = pszTCPAddress;
489
490 if (strlen(pszTCPPort) > 0)
491 {
492 rc = RTStrToUInt32Ex(pszTCPPort, NULL, 10, &uServerPort6);
493 if (!RT_SUCCESS(rc) || uServerPort6 > 65535)
494 uServerPort6 = 0;
495 }
496
497 if (RTNetIsIPv4AddrStr(pszVNCAddress4))
498 pszServerAddress4 = pszVNCAddress4;
499 else
500 pszServerAddress4 = szIPv4ListenAll;
501
502 if (strlen(pszVNCPort4) > 0)
503 {
504 rc = RTStrToUInt32Ex(pszVNCPort4, NULL, 10, &uServerPort4);
505 if (!RT_SUCCESS(rc) || uServerPort4 > 65535)
506 uServerPort4 = 0;
507
508 }
509 }
510
511 if ((pszServerAddress4 != pszTCPAddress) && (pszServerAddress6 != pszTCPAddress) && (strlen(pszTCPAddress) > 0))
512 {
513 // here we go, we prefer IPv6 over IPv4;
514 resSize = 42;
515 pszGetAddrInfo6 = (char *) RTMemTmpAllocZ(resSize);
516 enmAddrType = RTNETADDRTYPE_IPV6;
517
518 rc = RTSocketQueryAddressStr(pszTCPAddress, pszGetAddrInfo6, &resSize, &enmAddrType);
519 if (RT_SUCCESS(rc))
520 pszServerAddress6 = pszGetAddrInfo6;
521 else
522 {
523 RTMemTmpFree(pszGetAddrInfo6);
524 pszGetAddrInfo6 = NULL;
525 }
526
527 if (!pszServerAddress6)
528 {
529 resSize = 16;
530 pszGetAddrInfo4 = (char *) RTMemTmpAllocZ(resSize);
531 enmAddrType = RTNETADDRTYPE_IPV4;
532
533 rc = RTSocketQueryAddressStr(pszTCPAddress, pszGetAddrInfo4, &resSize, &enmAddrType);
534
535 if (RT_SUCCESS(rc))
536 pszServerAddress4 = pszGetAddrInfo4;
537 else
538 {
539 RTMemTmpFree(pszGetAddrInfo4);
540 pszGetAddrInfo4 = NULL;
541 }
542 }
543 }
544
545 if (!pszServerAddress4 && strlen(pszVNCAddress4) > 0)
546 {
547 resSize = 16;
548 pszGetAddrInfo4 = (char *) RTMemTmpAllocZ(resSize);
549 enmAddrType = RTNETADDRTYPE_IPV4;
550
551 rc = RTSocketQueryAddressStr(pszVNCAddress4, pszGetAddrInfo4, &resSize, &enmAddrType);
552
553 if (RT_SUCCESS(rc))
554 pszServerAddress4 = pszGetAddrInfo4;
555
556 }
557
558 if (!pszServerAddress6 && strlen(pszVNCAddress6) > 0)
559 {
560 resSize = 42;
561 pszGetAddrInfo6 = (char *) RTMemTmpAllocZ(resSize);
562 enmAddrType = RTNETADDRTYPE_IPV6;
563
564 rc = RTSocketQueryAddressStr(pszVNCAddress6, pszGetAddrInfo6, &resSize, &enmAddrType);
565
566 if (RT_SUCCESS(rc))
567 pszServerAddress6 = pszGetAddrInfo6;
568
569 }
570 if (!pszServerAddress4)
571 {
572 if (RTNetIsIPv4AddrStr(pszVNCAddress4))
573 pszServerAddress4 = pszVNCAddress4;
574 else
575 pszServerAddress4 = szIPv4ListenAll;
576 }
577 if (!pszServerAddress6)
578 {
579 if (RTNetIsIPv6AddrStr(pszVNCAddress6))
580 pszServerAddress6 = pszVNCAddress6;
581 else
582 pszServerAddress6 = szIPv6ListenAll;
583 }
584
585 if (pszVNCPort4 && uServerPort4 == 0)
586 {
587 rc = RTStrToUInt32Ex(pszVNCPort4, NULL, 10, &uServerPort4);
588 if (!RT_SUCCESS(rc) || uServerPort4 > 65535)
589 uServerPort4 = 0;
590 }
591
592 if (pszVNCPort6 && uServerPort6 == 0)
593 {
594 rc = RTStrToUInt32Ex(pszVNCPort6, NULL, 10, &uServerPort6);
595 if (!RT_SUCCESS(rc) || uServerPort6 > 65535)
596 uServerPort6 = 0;
597 }
598
599 if (uServerPort4 == 0 || uServerPort6 == 0)
600 vncServer->autoPort = 1;
601 else
602 {
603 vncServer->port = uServerPort4;
604 vncServer->ipv6port = uServerPort6;
605 }
606
607 if (!rfbStringToAddr(pszServerAddress4,&vncServer->listenInterface))
608 LogRel(("VNC: could not parse VNC server listen address IPv4 '%s'\n", pszServerAddress4));
609
610 vncServer->listen6Interface = pszServerAddress6;
611
612 rfbInitServer(vncServer);
613
614 vncServer->newClientHook = rfbNewClientEvent;
615 vncServer->kbdAddEvent = vncKeyboardEvent;
616 vncServer->ptrAddEvent = vncMouseEvent;
617
618 // notify about the actually used port
619 int port = 0;
620 port = vncServer->ipv6port;
621
622 if (vncServer->listen6Sock < 0)
623 {
624 LogRel(("VNC: not able to bind to IPv6 socket with address '%s'\n",pszServerAddress6));
625 port = 0;
626
627 }
628
629 instance->mCallbacks->VRDECallbackProperty(instance->mCallback,
630 VRDE_SP_NETWORK_BIND_PORT,
631 &port, sizeof(port), NULL);
632 LogRel(("VNC: port6 = %u\n", port));
633
634
635 if (pszTCPAddress)
636 {
637 if (pszTCPAddress == pszServerAddress4)
638 pszServerAddress4 = NULL;
639
640 if (pszTCPAddress == pszServerAddress6)
641 pszServerAddress6 = NULL;
642
643 RTMemTmpFree(pszTCPAddress);
644 }
645
646 RTMemTmpFree(pszTCPPort);
647 RTMemTmpFree(pszVNCAddress4);
648 RTMemTmpFree(pszVNCPort4);
649 RTMemTmpFree(pszGetAddrInfo4);
650 RTMemTmpFree(pszVNCAddress6);
651 RTMemTmpFree(pszGetAddrInfo6);
652
653 // with ipv6 to here
654#endif
655 // let's get the password
656 instance->szVNCPassword[0] = '\0';
657 const char szFeatName[] = "Property/VNCPassword";
658 const uint32_t featLen = sizeof(VRDEFEATURE) + RT_MAX(sizeof(instance->szVNCPassword), sizeof(szFeatName)) - 1;
659 VRDEFEATURE *feature = (VRDEFEATURE *)RTMemTmpAlloc(featLen);
660 feature->u32ClientId = 0;
661 RTStrCopy(feature->achInfo, featLen - sizeof(VRDEFEATURE) + 1, szFeatName);
662
663 cbOut = featLen;
664 rc = instance->mCallbacks->VRDECallbackProperty(instance->mCallback, VRDE_QP_FEATURE, feature, featLen, &cbOut);
665 Assert(cbOut <= featLen);
666
667 if (RT_SUCCESS(rc))
668 {
669 RTStrCopy(instance->szVNCPassword, sizeof(instance->szVNCPassword), feature->achInfo);
670 memset(feature->achInfo, '\0', featLen - sizeof(VRDEFEATURE) + 1);
671 LogRel(("VNC: Configuring password\n"));
672
673 instance->apszVNCPasswordStruct[0] = instance->szVNCPassword;
674 instance->apszVNCPasswordStruct[1] = NULL;
675
676 vncServer->authPasswdData = (void *)instance->apszVNCPasswordStruct;
677 vncServer->passwordCheck = rfbCheckPasswordByList;
678 }
679 else
680 LogRel(("VNC: No password result = %Rrc\n", rc));
681
682 RTMemTmpFree(feature);
683
684 rfbRunEventLoop(vncServer, -1, TRUE);
685
686 return VINF_SUCCESS;
687}
688
689/** The server should disconnect the client.
690 *
691 * @param hServer The server instance handle.
692 * @param u32ClientId The client identifier.
693 * @param fReconnect Whether to send a "REDIRECT to the same server" packet to the
694 * client before disconnecting.
695 *
696 * @return IPRT status code.
697 */
698DECLCALLBACK(void) VNCServerImpl::VRDEDisconnect(HVRDESERVER hServer, uint32_t u32ClientId, bool fReconnect)
699{
700 RT_NOREF(hServer, u32ClientId, fReconnect);
701}
702
703static inline void convert15To32bpp(uint8_t msb, uint8_t lsb, uint8_t &r, uint8_t &g, uint8_t &b)
704{
705 uint16_t px = lsb << 8 | msb;
706 // RGB 555 (1 bit unused)
707 r = (px >> 7) & 0xf8;
708 g = (px >> 2) & 0xf8;
709 b = (px << 3) & 0xf8;
710}
711
712static inline void convert16To32bpp(uint8_t msb, uint8_t lsb, uint8_t &r, uint8_t &g, uint8_t &b)
713{
714 uint16_t px = lsb << 8 | msb;
715 // RGB 565 (all bits used, 1 extra bit for green)
716 r = (px >> 8) & 0xf8;
717 g = (px >> 3) & 0xfc;
718 b = (px << 3) & 0xf8;
719}
720
721/**
722 * Inform the server that the display was resized.
723 * The server will query information about display
724 * from the application via callbacks.
725 *
726 * @param hServer Handle of VRDE server instance.
727 */
728DECLCALLBACK(void) VNCServerImpl::VRDEResize(HVRDESERVER hServer)
729{
730 VNCServerImpl *instance = (VNCServerImpl *)hServer;
731 VRDEFRAMEBUFFERINFO info;
732 bool fAvail = instance->mCallbacks->VRDECallbackFramebufferQuery(instance->mCallback, 0, &info);
733 if (!fAvail)
734 return;
735
736 LogRel(("VNCServerImpl::VRDEResize to %dx%dx%dbpp\n", info.cWidth, info.cHeight, info.cBitsPerPixel));
737
738 // we always alloc an RGBA buffer
739 unsigned char *FrameBuffer = (unsigned char *)RTMemAlloc(info.cWidth * info.cHeight * VNC_SIZEOFRGBA); // RGBA
740 if (info.cBitsPerPixel == 32 || info.cBitsPerPixel == 24)
741 {
742 // Convert RGB (windows/vbox) to BGR(vnc)
743 uint32_t i, j;
744 for (i = 0, j = 0; i < info.cWidth * info.cHeight * VNC_SIZEOFRGBA; i += VNC_SIZEOFRGBA, j += info.cBitsPerPixel / 8)
745 {
746 unsigned char r = info.pu8Bits[j];
747 unsigned char g = info.pu8Bits[j + 1];
748 unsigned char b = info.pu8Bits[j + 2];
749 FrameBuffer[i] = b;
750 FrameBuffer[i + 1] = g;
751 FrameBuffer[i + 2] = r;
752 }
753 }
754 else if (info.cBitsPerPixel == 16)
755 {
756 uint32_t i, j;
757 for (i = 0, j = 0;
758 i < info.cWidth * info.cHeight * VNC_SIZEOFRGBA;
759 i += VNC_SIZEOFRGBA, j += info.cBitsPerPixel / 8)
760 {
761 convert16To32bpp(info.pu8Bits[j],
762 info.pu8Bits[j + 1],
763 FrameBuffer[i],
764 FrameBuffer[i + 1],
765 FrameBuffer[i + 2]);
766 }
767 }
768 rfbNewFramebuffer(instance->mVNCServer, (char *)FrameBuffer, info.cWidth, info.cHeight, 8, 3, VNC_SIZEOFRGBA);
769
770 void *temp = instance->mFrameBuffer;
771 instance->mFrameBuffer = FrameBuffer;
772 instance->mScreenBuffer = (unsigned char *)info.pu8Bits;
773 instance->FrameInfo = info;
774 if (temp)
775 RTMemFree(temp);
776}
777
778/**
779 * Send a update.
780 *
781 * @param hServer Handle of VRDE server instance.
782 * @param uScreenId The screen index.
783 * @param pvUpdate Pointer to VBoxGuest.h::VRDEORDERHDR structure with extra data.
784 * @param cbUpdate Size of the update data.
785 */
786DECLCALLBACK(void) VNCServerImpl::VRDEUpdate(HVRDESERVER hServer, unsigned uScreenId, void *pvUpdate,uint32_t cbUpdate)
787{
788 RT_NOREF(uScreenId);
789 char *ptr = (char *)pvUpdate;
790 VNCServerImpl *instance = (VNCServerImpl *)hServer;
791 VRDEORDERHDR *order = (VRDEORDERHDR *)ptr;
792 ptr += sizeof(VRDEORDERHDR);
793 if (order == NULL)
794 {
795 /* Inform the VRDE server that the current display update sequence is
796 * completed. At this moment the framebuffer memory contains a definite
797 * image, that is synchronized with the orders already sent to VRDE client.
798 * The server can now process redraw requests from clients or initial
799 * fullscreen updates for new clients.
800 */
801
802 }
803 else
804 {
805 if (sizeof(VRDEORDERHDR) != cbUpdate)
806 {
807 VRDEORDERCODE *code = (VRDEORDERCODE *)ptr;
808 ptr += sizeof(VRDEORDERCODE);
809
810 switch(code->u32Code)
811 {
812 case VRDE_ORDER_SOLIDRECT:
813 {
814 VRDEORDERSOLIDRECT *solidrect = (VRDEORDERSOLIDRECT *)ptr;
815 rfbFillRect(instance->mVNCServer, solidrect->x, solidrect->y,
816 solidrect->x + solidrect->w, solidrect->y + solidrect->h, RGB2BGR(solidrect->rgb));
817 return;
818 }
819 /// @todo more orders
820 }
821 }
822
823 if (!instance->mScreenBuffer)
824 {
825 VRDEResize(hServer);
826 if (!instance->mScreenBuffer)
827 {
828 LogRel(("VNCServerImpl::VRDEUpdate: Cannot get frame buffer"));
829 return;
830 }
831 }
832
833 uint32_t width = instance->FrameInfo.cWidth;
834 uint32_t bpp = instance->FrameInfo.cBitsPerPixel / 8;
835 uint32_t joff = order->y * width + order->x;
836 uint32_t srcx, srcy, destx, desty;
837 if (instance->FrameInfo.cBitsPerPixel == 32 || instance->FrameInfo.cBitsPerPixel == 24)
838 {
839 for (srcy = joff * bpp, desty = joff * VNC_SIZEOFRGBA;
840 desty < (joff + order->h * width) * VNC_SIZEOFRGBA;
841 srcy += width * bpp, desty += width * VNC_SIZEOFRGBA)
842 {
843 // RGB to BGR
844 for (srcx = srcy, destx = desty;
845 destx < desty + order->w * VNC_SIZEOFRGBA;
846 srcx += bpp, destx += VNC_SIZEOFRGBA)
847 {
848 instance->mFrameBuffer[destx] = instance->mScreenBuffer[srcx + 2];
849 instance->mFrameBuffer[destx + 1] = instance->mScreenBuffer[srcx + 1];
850 instance->mFrameBuffer[destx + 2] = instance->mScreenBuffer[srcx];
851 }
852 }
853 }
854 else if (instance->FrameInfo.cBitsPerPixel == 16)
855 {
856 for (srcy = joff * bpp, desty = joff * VNC_SIZEOFRGBA;
857 desty < (joff + order->h * width) * VNC_SIZEOFRGBA;
858 srcy += width * bpp, desty += width * VNC_SIZEOFRGBA)
859 {
860 for (srcx = srcy, destx = desty;
861 destx < desty + order->w * VNC_SIZEOFRGBA;
862 srcx += bpp, destx += VNC_SIZEOFRGBA)
863 {
864 convert16To32bpp(instance->mScreenBuffer[srcx],
865 instance->mScreenBuffer[srcx + 1],
866 instance->mFrameBuffer[destx],
867 instance->mFrameBuffer[destx + 1],
868 instance->mFrameBuffer[destx + 2]);
869 }
870 }
871 }
872 rfbMarkRectAsModified(instance->mVNCServer, order->x, order->y, order->x+order->w, order->y+order->h);
873 }
874}
875
876
877/**
878 * Set the mouse pointer shape.
879 *
880 * @param hServer Handle of VRDE server instance.
881 * @param pPointer The pointer shape information.
882 */
883DECLCALLBACK(void) VNCServerImpl::VRDEColorPointer(HVRDESERVER hServer,
884 const VRDECOLORPOINTER *pPointer)
885{
886 VNCServerImpl *instance = (VNCServerImpl *)hServer;
887 rfbCursorPtr cursor = (rfbCursorPtr)calloc(sizeof(rfbCursor), 1);
888
889 cursor->width = pPointer->u16Width;
890 cursor->height = pPointer->u16Height;
891
892 unsigned char *mem = (unsigned char *)malloc(pPointer->u16Width * pPointer->u16Height * VNC_SIZEOFRGBA);
893 cursor->richSource = mem;
894
895 unsigned char *maskmem = (unsigned char *)malloc(pPointer->u16Width * pPointer->u16Height);
896 cursor->mask = maskmem;
897
898 unsigned char *mask = (unsigned char *)pPointer + sizeof(VRDECOLORPOINTER);
899
900 for(int i = pPointer->u16Height - 1; i >= 0 ; i--)
901 {
902 for(uint16_t j = 0; j < pPointer->u16Width/8; j ++)
903 {
904 *maskmem = ~(*(mask + i * (pPointer->u16Width / 8) + j));
905 *maskmem++;
906 }
907 }
908 unsigned char *color = (unsigned char *)pPointer + sizeof(VRDECOLORPOINTER) + pPointer->u16MaskLen;
909 for(int i = pPointer->u16Height - 1; i >= 0 ; i--)
910 {
911 for(uint16_t j = 0; j < pPointer->u16Width; j ++)
912 {
913 // put the color value;
914 *(mem++) = *(color + (i * pPointer->u16Width *3 + j * 3 + 2));
915 *(mem++) = *(color + (i * pPointer->u16Width *3 + j * 3 + 1));
916 *(mem++) = *(color + (i * pPointer->u16Width *3 + j * 3));
917 *(mem++) = 0xff;
918 }
919 }
920
921 cursor->xhot = pPointer->u16HotX;
922 cursor->yhot = pPointer->u16HotY;
923
924 rfbSetCursor(instance->mVNCServer, cursor);
925
926 if (instance->mCursor)
927 rfbFreeCursor(instance->mCursor);
928
929 instance->mCursor = cursor;
930}
931
932/**
933 * Hide the mouse pointer.
934 *
935 * @param hServer Handle of VRDE server instance.
936 */
937DECLCALLBACK(void) VNCServerImpl::VRDEHidePointer(HVRDESERVER hServer)
938{
939 VNCServerImpl *pInstance = (VNCServerImpl *)hServer;
940 RT_NOREF(pInstance);
941
942 /// @todo what's behavior for this. hide doesn't seems right
943 //rfbSetCursor(pInstance->mVNCServer, NULL);
944}
945
946/**
947 * Queues the samples to be sent to clients.
948 *
949 * @param hServer Handle of VRDE server instance.
950 * @param pvSamples Address of samples to be sent.
951 * @param cSamples Number of samples.
952 * @param format Encoded audio format for these samples.
953 *
954 * @note Initialized to NULL when the application audio callbacks are NULL.
955 */
956DECLCALLBACK(void) VNCServerImpl::VRDEAudioSamples(HVRDESERVER hServer,
957 const void *pvSamples,
958 uint32_t cSamples,
959 VRDEAUDIOFORMAT format)
960{
961 RT_NOREF(hServer, pvSamples, cSamples, format);
962}
963
964/**
965 * Sets the sound volume on clients.
966 *
967 * @param hServer Handle of VRDE server instance.
968 * @param left 0..0xFFFF volume level for left channel.
969 * @param right 0..0xFFFF volume level for right channel.
970 *
971 * @note Initialized to NULL when the application audio callbacks are NULL.
972 */
973DECLCALLBACK(void) VNCServerImpl::VRDEAudioVolume(HVRDESERVER hServer,
974 uint16_t u16Left,
975 uint16_t u16Right)
976{
977 RT_NOREF(hServer, u16Left, u16Right);
978}
979
980/**
981 * Sends a USB request.
982 *
983 * @param hServer Handle of VRDE server instance.
984 * @param u32ClientId An identifier that allows the server to find the corresponding client.
985 * The identifier is always passed by the server as a parameter
986 * of the FNVRDEUSBCALLBACK. Note that the value is the same as
987 * in the VRDESERVERCALLBACK functions.
988 * @param pvParm Function specific parameters buffer.
989 * @param cbParm Size of the buffer.
990 *
991 * @note Initialized to NULL when the application USB callbacks are NULL.
992 */
993DECLCALLBACK(void) VNCServerImpl::VRDEUSBRequest(HVRDESERVER hServer,
994 uint32_t u32ClientId,
995 void *pvParm,
996 uint32_t cbParm)
997{
998 RT_NOREF(hServer, u32ClientId, pvParm, cbParm);
999}
1000
1001/**
1002 * Called by the application when (VRDE_CLIPBOARD_FUNCTION_*):
1003 * - (0) guest announces available clipboard formats;
1004 * - (1) guest requests clipboard data;
1005 * - (2) guest responds to the client's request for clipboard data.
1006 *
1007 * @param hServer The VRDE server handle.
1008 * @param u32Function The cause of the call.
1009 * @param u32Format Bitmask of announced formats or the format of data.
1010 * @param pvData Points to: (1) buffer to be filled with clients data;
1011 * (2) data from the host.
1012 * @param cbData Size of 'pvData' buffer in bytes.
1013 * @param pcbActualRead Size of the copied data in bytes.
1014 *
1015 * @note Initialized to NULL when the application clipboard callbacks are NULL.
1016 */
1017DECLCALLBACK(void) VNCServerImpl::VRDEClipboard(HVRDESERVER hServer,
1018 uint32_t u32Function,
1019 uint32_t u32Format,
1020 void *pvData,
1021 uint32_t cbData,
1022 uint32_t *pcbActualRead)
1023{
1024 RT_NOREF(hServer, u32Function, u32Format, pvData, cbData, pcbActualRead);
1025}
1026
1027/**
1028 * Query various information from the VRDE server.
1029 *
1030 * @param hServer The VRDE server handle.
1031 * @param index VRDE_QI_* identifier of information to be returned.
1032 * @param pvBuffer Address of memory buffer to which the information must be written.
1033 * @param cbBuffer Size of the memory buffer in bytes.
1034 * @param pcbOut Size in bytes of returned information value.
1035 *
1036 * @remark The caller must check the *pcbOut. 0 there means no information was returned.
1037 * A value greater than cbBuffer means that information is too big to fit in the
1038 * buffer, in that case no information was placed to the buffer.
1039 */
1040DECLCALLBACK(void) VNCServerImpl::VRDEQueryInfo(HVRDESERVER hServer,
1041 uint32_t index,
1042 void *pvBuffer,
1043 uint32_t cbBuffer,
1044 uint32_t *pcbOut)
1045{
1046 VNCServerImpl *instance = (VNCServerImpl *)hServer;
1047 *pcbOut = 0;
1048
1049 switch (index)
1050 {
1051 case VRDE_QI_ACTIVE: /* # of active clients */
1052 case VRDE_QI_NUMBER_OF_CLIENTS: /* # of connected clients */
1053 {
1054 uint32_t cbOut = sizeof(uint32_t);
1055 if (cbBuffer >= cbOut)
1056 {
1057 *pcbOut = cbOut;
1058 *(uint32_t *)pvBuffer = instance->uClients;
1059 }
1060 break;
1061 }
1062 /// @todo lots more queries to implement
1063 default:
1064 break;
1065 }
1066}
1067
1068
1069/**
1070 * The server should redirect the client to the specified server.
1071 *
1072 * @param hServer The server instance handle.
1073 * @param u32ClientId The client identifier.
1074 * @param pszServer The server to redirect the client to.
1075 * @param pszUser The username to use for the redirection.
1076 * Can be NULL.
1077 * @param pszDomain The domain. Can be NULL.
1078 * @param pszPassword The password. Can be NULL.
1079 * @param u32SessionId The ID of the session to redirect to.
1080 * @param pszCookie The routing token used by a load balancer to
1081 * route the redirection. Can be NULL.
1082 */
1083DECLCALLBACK(void) VNCServerImpl::VRDERedirect(HVRDESERVER hServer,
1084 uint32_t u32ClientId,
1085 const char *pszServer,
1086 const char *pszUser,
1087 const char *pszDomain,
1088 const char *pszPassword,
1089 uint32_t u32SessionId,
1090 const char *pszCookie)
1091{
1092 RT_NOREF(hServer, u32ClientId, pszServer, pszUser, pszDomain, pszPassword, u32SessionId, pszCookie);
1093}
1094
1095/**
1096 * Audio input open request.
1097 *
1098 * @param hServer Handle of VRDE server instance.
1099 * @param pvCtx To be used in VRDECallbackAudioIn.
1100 * @param u32ClientId An identifier that allows the server to find the corresponding client.
1101 * @param audioFormat Preferred format of audio data.
1102 * @param u32SamplesPerBlock Preferred number of samples in one block of audio input data.
1103 *
1104 * @note Initialized to NULL when the VRDECallbackAudioIn callback is NULL.
1105 */
1106DECLCALLBACK(void) VNCServerImpl::VRDEAudioInOpen(HVRDESERVER hServer,
1107 void *pvCtx,
1108 uint32_t u32ClientId,
1109 VRDEAUDIOFORMAT audioFormat,
1110 uint32_t u32SamplesPerBlock)
1111{
1112 RT_NOREF(hServer, pvCtx, u32ClientId, audioFormat, u32SamplesPerBlock);
1113}
1114
1115/**
1116 * Audio input close request.
1117 *
1118 * @param hServer Handle of VRDE server instance.
1119 * @param u32ClientId An identifier that allows the server to find the corresponding client.
1120 *
1121 * @note Initialized to NULL when the VRDECallbackAudioIn callback is NULL.
1122 */
1123DECLCALLBACK(void) VNCServerImpl::VRDEAudioInClose(HVRDESERVER hServer, uint32_t u32ClientId)
1124{
1125 RT_NOREF(hServer, u32ClientId);
1126}
1127
1128
1129
1130int VNCServerImpl::Init(const VRDEINTERFACEHDR *pCallbacks,
1131 void *pvCallback)
1132{
1133 if (pCallbacks->u64Version == VRDE_INTERFACE_VERSION_3)
1134 {
1135 mCallbacks = (VRDECALLBACKS_4 *)pCallbacks;
1136 mCallback = pvCallback;
1137 }
1138 else if (pCallbacks->u64Version == VRDE_INTERFACE_VERSION_1)
1139 {
1140 /// @todo this is incorrect and it will cause crash if client call unsupport func.
1141 mCallbacks = (VRDECALLBACKS_4 *)pCallbacks;
1142 mCallback = pvCallback;
1143
1144
1145 // since they are same in order, let's just change header
1146 Entries.header.u64Version = VRDE_INTERFACE_VERSION_1;
1147 Entries.header.u64Size = sizeof(VRDEENTRYPOINTS_1);
1148 }
1149 else
1150 return VERR_VERSION_MISMATCH;
1151
1152 return VINF_SUCCESS;
1153}
1154
1155
1156void VNCServerImpl::vncKeyboardEvent(rfbBool down, rfbKeySym keycode, rfbClientPtr cl)
1157{
1158 VNCServerImpl *instance = static_cast<VNCServerImpl *>(cl->screen->screenData);
1159 VRDEINPUTSCANCODE point;
1160
1161 /* Conversion table for key code range 32-127 (which happen to equal the ASCII codes).
1162 * Values 0xe0?? indicate that a 0xe0 scancode will be sent first (extended keys), then code ?? is sent */
1163 static unsigned codes_low[] =
1164 {
1165 // Conversion table for VNC key code range 32-127
1166 0x39, 0x02, 0x28, 0x04, 0x05, 0x06, 0x08, 0x28, 0x0a, 0x0b, 0x09, 0x0d, 0x33, 0x0c, 0x34, 0x35, //space, !"#$%&'()*+`-./
1167 0x0b, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x27, 0x27, 0x33, 0x0d, 0x34, 0x35, 0x03, //0123456789:;<=>?@
1168 0x1e, 0x30, 0x2e, 0x20, 0x12, 0x21, 0x22, 0x23, 0x17, 0x24, 0x25, 0x26, 0x32, //A-M
1169 0x31, 0x18, 0x19, 0x10, 0x13, 0x1f, 0x14, 0x16, 0x2f, 0x11, 0x2d, 0x15, 0x2c, //N-Z
1170 0x1a, 0x2b, 0x1b, 0x07, 0x0c, 0x29, //[\]^_`
1171 0x1e, 0x30, 0x2e, 0x20, 0x12, 0x21, 0x22, 0x23, 0x17, 0x24, 0x25, 0x26, 0x32, //a-m
1172 0x31, 0x18, 0x19, 0x10, 0x13, 0x1f, 0x14, 0x16, 0x2f, 0x11, 0x2d, 0x15, 0x2c, //n-z
1173 0x1a, 0x2b, 0x1b, 0x29 //{|}~
1174 };
1175
1176 int code = -1;
1177 if (keycode < 32)
1178 {
1179 //ASCII control codes.. unused..
1180 }
1181 else if (keycode < 127)
1182 {
1183 //DEL is in high area
1184 code = codes_low[keycode - 32];
1185 }
1186 else if ((keycode & 0xFE00) != 0xFE00)
1187 {
1188 }
1189 else
1190 {
1191 switch(keycode)
1192 {
1193 case 65027: code = 0xe038; break; //AltGr = RAlt
1194 case 65288: code = 0x0e; break; //Backspace
1195 case 65289: code = 0x0f; break; //Tab
1196
1197 case 65293: code = 0x1c; break; //Return
1198 //case 65299: break; Pause/break
1199 case 65300: code = 0x46; break; //ScrollLock
1200 //case 65301: break; SysRq
1201 case 65307: code = 0x01; break; //Escape
1202
1203 case 65360: code = 0xe047; break; //Home
1204 case 65361: code = 0xe04b; break; //Left
1205 case 65362: code = 0xe048; break; //Up
1206 case 65363: code = 0xe04d; break; //Right
1207 case 65364: code = 0xe050; break; //Down
1208 case 65365: code = 0xe049; break; //Page up
1209 case 65366: code = 0xe051; break; //Page down
1210 case 65367: code = 0xe04f; break; //End
1211
1212 //case 65377: break; //Print screen
1213 case 65379: code = 0xe052; break; //Insert
1214
1215 case 65383: code = 0xe05d; break; //Menu
1216 case 65407: code = 0x45; break; //NumLock
1217
1218 case 65421: code = 0xe01c; break; //Numpad return
1219 case 65429: code = 0x47; break; //Numpad home
1220 case 65430: code = 0x4b; break; //Numpad left
1221 case 65431: code = 0x48; break; //Numpad up
1222 case 65432: code = 0x4d; break; //Numpad right
1223 case 65433: code = 0x50; break; //Numpad down
1224 case 65434: code = 0x49; break; //Numpad page up
1225 case 65435: code = 0x51; break; //Numpad page down
1226 case 65436: code = 0x4f; break; //Numpad end
1227 case 65437: code = 0x4c; break; //Numpad begin
1228 case 65438: code = 0x52; break; //Numpad ins
1229 case 65439: code = 0x53; break; //Numpad del
1230 case 65450: code = 0x37; break; //Numpad *
1231 case 65451: code = 0x4e; break; //Numpad +
1232 case 65452: code = 0x53; break; //Numpad separator
1233 case 65453: code = 0x4a; break; //Numpad -
1234 case 65454: code = 0x53; break; //Numpad decimal
1235 case 65455: code = 0xe035; break; //Numpad /
1236 case 65456: code = 0x52; break; //Numpad 0
1237 case 65457: code = 0x4f; break; //Numpad 1
1238 case 65458: code = 0x50; break; //Numpad 2
1239 case 65459: code = 0x51; break; //Numpad 3
1240 case 65460: code = 0x4b; break; //Numpad 4
1241 case 65461: code = 0x4c; break; //Numpad 5
1242 case 65462: code = 0x4d; break; //Numpad 6
1243 case 65463: code = 0x47; break; //Numpad 7
1244 case 65464: code = 0x48; break; //Numpad 8
1245 case 65465: code = 0x49; break; //Numpad 9
1246
1247 case 65470: code = 0x3b; break; //F1
1248 case 65471: code = 0x3c; break; //F2
1249 case 65472: code = 0x3d; break; //F3
1250 case 65473: code = 0x3e; break; //F4
1251 case 65474: code = 0x3f; break; //F5
1252 case 65475: code = 0x40; break; //F6
1253 case 65476: code = 0x41; break; //F7
1254 case 65477: code = 0x42; break; //F8
1255 case 65478: code = 0x43; break; //F9
1256 case 65479: code = 0x44; break; //F10
1257 case 65480: code = 0x57; break; //F11
1258 case 65481: code = 0x58; break; //F12
1259
1260 case 65505: code = 0x2a; break; //Left shift
1261 case 65506: code = 0x36; break; //Right shift
1262 case 65507: code = 0x1d; break; //Left ctrl
1263 case 65508: code = 0xe01d; break; //Right ctrl
1264 case 65509: code = 0x3a; break; //Caps Lock
1265 case 65510: code = 0x3a; break; //Shift Lock
1266 case 65513: code = 0x38; break; //Left Alt
1267 case 65514: code = 0xe038; break; //Right Alt
1268 case 65515: code = 0xe05b; break; //Left windows key
1269 case 65516: code = 0xe05c; break; //Right windows key
1270 case 65535: code = 0xe053; break; //Delete
1271 }
1272 }
1273
1274 if (code == -1)
1275 {
1276 LogRel(("VNC: unhandled keyboard code: down=%d code=%d\n", down, keycode));
1277 return;
1278 }
1279 if (code > 0xff)
1280 {
1281 point.uScancode = (code >> 8) & 0xff;
1282 instance->mCallbacks->VRDECallbackInput(instance->mCallback, VRDE_INPUT_SCANCODE, &point, sizeof(point));
1283 }
1284
1285 point.uScancode = (code & 0xff) | (down ? 0 : 0x80);
1286 instance->mCallbacks->VRDECallbackInput(instance->mCallback, VRDE_INPUT_SCANCODE, &point, sizeof(point));
1287}
1288
1289void VNCServerImpl::vncMouseEvent(int buttonMask, int x, int y, rfbClientPtr cl)
1290{
1291 VNCServerImpl *instance = static_cast<VNCServerImpl *>(cl->screen->screenData);
1292
1293 VRDEINPUTPOINT point;
1294 unsigned button = 0;
1295 if (buttonMask & 1) button |= VRDE_INPUT_POINT_BUTTON1;
1296 if (buttonMask & 2) button |= VRDE_INPUT_POINT_BUTTON3;
1297 if (buttonMask & 4) button |= VRDE_INPUT_POINT_BUTTON2;
1298 if (buttonMask & 8) button |= VRDE_INPUT_POINT_WHEEL_UP;
1299 if (buttonMask & 16) button |= VRDE_INPUT_POINT_WHEEL_DOWN;
1300 point.uButtons = button;
1301 point.x = x;
1302 point.y = y;
1303 instance->mCallbacks->VRDECallbackInput(instance->mCallback, VRDE_INPUT_POINT, &point, sizeof(point));
1304 rfbDefaultPtrAddEvent(buttonMask, x, y, cl);
1305}
1306
1307enum rfbNewClientAction VNCServerImpl::rfbNewClientEvent(rfbClientPtr cl)
1308{
1309 VNCServerImpl *instance = static_cast<VNCServerImpl *>(cl->screen->screenData);
1310
1311 /// @todo we need auth user here
1312
1313 instance->mCallbacks->VRDECallbackClientConnect(instance->mCallback, (int)cl->sock);
1314 instance->uClients++;
1315
1316 cl->clientGoneHook = clientGoneHook;
1317
1318 return RFB_CLIENT_ACCEPT;
1319}
1320
1321void VNCServerImpl::clientGoneHook(rfbClientPtr cl)
1322{
1323 VNCServerImpl *instance = static_cast<VNCServerImpl *>(cl->screen->screenData);
1324
1325 instance->uClients--;
1326 instance->mCallbacks->VRDECallbackClientDisconnect(instance->mCallback, (int)cl->sock, 0);
1327}
1328
1329VNCServerImpl *g_VNCServer = 0;
1330
1331DECLEXPORT(int) VRDECreateServer(const VRDEINTERFACEHDR *pCallbacks,
1332 void *pvCallback,
1333 VRDEINTERFACEHDR **ppEntryPoints,
1334 HVRDESERVER *phServer)
1335{
1336 if (!g_VNCServer)
1337 {
1338 g_VNCServer = new VNCServerImpl();
1339 }
1340
1341 int rc = g_VNCServer->Init(pCallbacks, pvCallback);
1342
1343 if (RT_SUCCESS(rc))
1344 {
1345 *ppEntryPoints = g_VNCServer->GetInterface();
1346 *phServer = (HVRDESERVER)g_VNCServer;
1347 }
1348
1349 return rc;
1350}
1351
1352static const char * const supportedProperties[] =
1353{
1354 "TCP/Ports",
1355 "TCP/Address",
1356 NULL
1357};
1358
1359DECLEXPORT(const char * const *) VRDESupportedProperties(void)
1360{
1361 LogFlowFunc(("enter\n"));
1362 return supportedProperties;
1363}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette