VirtualBox

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

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

© 2023 Oracle
ContactPrivacy policyTerms of Use