VirtualBox

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

Last change on this file since 43060 was 40383, checked in by vboxsync, 13 years ago

ExtPacks/VNC: New extension pack contributed by Ivo Smits, Howard Su and Christophe Devriese. Thank you very much!
Frontends/VBoxHeadless: delete old VNC support which was far less useful

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 34.7 KB
Line 
1/* $Id: VBoxVNC.cpp 40383 2012-03-06 16:14:40Z vboxsync $ */
2/** @file
3 * VBoxVNC - VNC VRDE module.
4 */
5
6/*
7 * Contributed by Ivo Smits <[email protected]>, Howard Su and
8 * Christophe Devriese <[email protected]>
9 *
10 * Copyright (C) 2011-2012 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#define LOG_GROUP LOG_GROUP_VRDE
22#include <VBox/log.h>
23
24#include <iprt/asm.h>
25#include <iprt/alloca.h>
26#include <iprt/ldr.h>
27#include <iprt/param.h>
28#include <iprt/path.h>
29#include <iprt/mem.h>
30#include <iprt/stream.h>
31#include <iprt/string.h>
32#include <iprt/thread.h>
33#include <iprt/cpp/utils.h>
34
35#include <VBox/err.h>
36#include <VBox/RemoteDesktop/VRDEOrders.h>
37#include <VBox/RemoteDesktop/VRDE.h>
38
39#include <rfb/rfb.h>
40
41#define VNC_SIZEOFRGBA 4
42#define VNC_PASSWORDSIZE 20
43#define VNC_ADDRESSSIZE 60
44#define VNC_PORTSSIZE 20
45
46class VNCServerImpl
47{
48public:
49 VNCServerImpl()
50 {
51 mFrameBuffer = NULL;
52 mScreenBuffer = NULL;
53 mCursor = NULL;
54 uClients = 0;
55 }
56
57 ~VNCServerImpl()
58 {
59 if (mFrameBuffer)
60 RTMemFree(mFrameBuffer);
61 if (mCursor)
62 rfbFreeCursor(mCursor);
63 memset(szVNCPassword, '\0', sizeof(szVNCPassword));
64 }
65
66 int Init(const VRDEINTERFACEHDR *pCallbacks, void *pvCallback);
67
68 VRDEINTERFACEHDR *GetInterface() { return &Entries.header; }
69
70private:
71 // VNC password
72 char szVNCPassword[VNC_PASSWORDSIZE + 1];
73 // the structure we pass to libvncserver
74 char *apszVNCPasswordStruct[2];
75
76 // VNC related variables
77 rfbScreenInfoPtr mVNCServer;
78 void *mCallback;
79 rfbCursorPtr mCursor;
80 VRDEFRAMEBUFFERINFO FrameInfo;
81 unsigned char *mScreenBuffer;
82 unsigned char *mFrameBuffer;
83 uint32_t uClients;
84 static DECLCALLBACK(enum rfbNewClientAction) rfbNewClientEvent(rfbClientPtr cl);
85 static DECLCALLBACK(void) vncMouseEvent(int buttonMask, int x, int y, rfbClientPtr cl);
86 static void vncKeyboardEvent(rfbBool down, rfbKeySym keySym, rfbClientPtr cl);
87 static void clientGoneHook(rfbClientPtr cl);
88
89 static uint32_t RGB2BGR(uint32_t c)
90 {
91 c = ((c >> 0) & 0xff) << 16 |
92 ((c >> 8) & 0xff) << 8 |
93 ((c >> 16) & 0xff) << 0;
94
95 return c;
96 }
97
98 static VRDEENTRYPOINTS_4 Entries;
99 VRDECALLBACKS_4 *mCallbacks;
100
101
102 static DECLCALLBACK(void) VRDEDestroy(HVRDESERVER hServer);
103 static DECLCALLBACK(int) VRDEEnableConnections(HVRDESERVER hServer, bool fEnable);
104 static DECLCALLBACK(void) VRDEDisconnect(HVRDESERVER hServer, uint32_t u32ClientId, bool fReconnect);
105 static DECLCALLBACK(void) VRDEResize(HVRDESERVER hServer);
106 static DECLCALLBACK(void) VRDEUpdate(HVRDESERVER hServer, unsigned uScreenId, void *pvUpdate,uint32_t cbUpdate);
107 static DECLCALLBACK(void) VRDEColorPointer(HVRDESERVER hServer, const VRDECOLORPOINTER *pPointer);
108 static DECLCALLBACK(void) VRDEHidePointer(HVRDESERVER hServer);
109 static DECLCALLBACK(void) VRDEAudioSamples(HVRDESERVER hServer, const void *pvSamples, uint32_t cSamples, VRDEAUDIOFORMAT format);
110 static DECLCALLBACK(void) VRDEAudioVolume(HVRDESERVER hServer, uint16_t u16Left, uint16_t u16Right);
111 static DECLCALLBACK(void) VRDEUSBRequest(HVRDESERVER hServer,
112 uint32_t u32ClientId,
113 void *pvParm,
114 uint32_t cbParm);
115 static DECLCALLBACK(void) VRDEClipboard(HVRDESERVER hServer,
116 uint32_t u32Function,
117 uint32_t u32Format,
118 void *pvData,
119 uint32_t cbData,
120 uint32_t *pcbActualRead);
121 static DECLCALLBACK(void) VRDEQueryInfo(HVRDESERVER hServer,
122 uint32_t index,
123 void *pvBuffer,
124 uint32_t cbBuffer,
125 uint32_t *pcbOut);
126 static DECLCALLBACK(void) VRDERedirect(HVRDESERVER hServer,
127 uint32_t u32ClientId,
128 const char *pszServer,
129 const char *pszUser,
130 const char *pszDomain,
131 const char *pszPassword,
132 uint32_t u32SessionId,
133 const char *pszCookie);
134 static DECLCALLBACK(void) VRDEAudioInOpen(HVRDESERVER hServer,
135 void *pvCtx,
136 uint32_t u32ClientId,
137 VRDEAUDIOFORMAT audioFormat,
138 uint32_t u32SamplesPerBlock);
139 static DECLCALLBACK(void) VRDEAudioInClose(HVRDESERVER hServer,
140 uint32_t u32ClientId);
141};
142
143VRDEENTRYPOINTS_4 VNCServerImpl::Entries = {
144 { VRDE_INTERFACE_VERSION_3, sizeof(VRDEENTRYPOINTS_3) },
145 VNCServerImpl::VRDEDestroy,
146 VNCServerImpl::VRDEEnableConnections,
147 VNCServerImpl::VRDEDisconnect,
148 VNCServerImpl::VRDEResize,
149 VNCServerImpl::VRDEUpdate,
150 VNCServerImpl::VRDEColorPointer,
151 VNCServerImpl::VRDEHidePointer,
152 VNCServerImpl::VRDEAudioSamples,
153 VNCServerImpl::VRDEAudioVolume,
154 VNCServerImpl::VRDEUSBRequest,
155 VNCServerImpl::VRDEClipboard,
156 VNCServerImpl::VRDEQueryInfo,
157 VNCServerImpl::VRDERedirect,
158 VNCServerImpl::VRDEAudioInOpen,
159 VNCServerImpl::VRDEAudioInClose
160};
161
162
163/** Destroy the server instance.
164 *
165 * @param hServer The server instance handle.
166 *
167 * @return IPRT status code.
168 */
169DECLCALLBACK(void) VNCServerImpl::VRDEDestroy(HVRDESERVER hServer)
170{
171 VNCServerImpl *instance = (VNCServerImpl *)hServer;
172 rfbShutdownServer(instance->mVNCServer, TRUE);
173
174 uint32_t port = UINT32_MAX;
175 instance->mCallbacks->VRDECallbackProperty(instance->mCallback,
176 VRDE_SP_NETWORK_BIND_PORT,
177 &port, sizeof(port), NULL);
178 return;
179}
180
181
182/** The server should start to accept clients connections.
183 *
184 * @param hServer The server instance handle.
185 * @param fEnable Whether to enable or disable client connections.
186 * When is false, all existing clients are disconnected.
187 *
188 * @return IPRT status code.
189 */
190DECLCALLBACK(int) VNCServerImpl::VRDEEnableConnections(HVRDESERVER hServer, bool fEnable)
191{
192 VNCServerImpl *instance = (VNCServerImpl *)hServer;
193
194#ifdef LOG_ENABLED
195 // enable logging
196 rfbLogEnable(true);
197#endif
198 LogFlowFunc(("enter\n"));
199
200 // query server for the framebuffer
201 VRDEFRAMEBUFFERINFO info;
202 int rc = instance->mCallbacks->VRDECallbackFramebufferQuery(instance->mCallback, 0, &info);
203
204 rfbScreenInfoPtr vncServer = rfbGetScreen(0, NULL, info.cWidth, info.cHeight, 8, 3, VNC_SIZEOFRGBA);
205 instance->mVNCServer = vncServer;
206 vncServer->serverFormat.redShift = 16;
207 vncServer->serverFormat.greenShift = 8;
208 vncServer->serverFormat.blueShift = 0;
209 vncServer->screenData = (void *)instance;
210 vncServer->desktopName = "VBoxVNC";
211
212 // get listen address
213 char szAddress[VNC_ADDRESSSIZE + 1] = {0};
214 uint32_t cbOut = 0;
215 rc = instance->mCallbacks->VRDECallbackProperty(instance->mCallback,
216 VRDE_QP_NETWORK_ADDRESS,
217 &szAddress, sizeof(szAddress), &cbOut);
218 Assert(cbOut <= sizeof(szAddress));
219 if (RT_SUCCESS(rc) && szAddress[0])
220 {
221 if (!rfbStringToAddr(szAddress, &vncServer->listenInterface))
222 LogRel(("VNC: could not parse VNC server listen address '%s'\n", szAddress));
223 }
224
225 // get listen port
226 uint32_t port = 0;
227 rc = instance->mCallbacks->VRDECallbackProperty(instance->mCallback,
228 VRDE_QP_NETWORK_PORT,
229 &port, sizeof(port), &cbOut);
230 Assert(cbOut <= sizeof(port));
231 if (RT_SUCCESS(rc) && port != 0)
232 vncServer->port = port;
233 else
234 {
235 const char szFeatName[] = "Property/TCP/Ports";
236 const uint32_t featLen = sizeof(VRDEFEATURE) + RT_MAX(sizeof(VNC_PORTSSIZE), sizeof(szFeatName)) - 1;
237 VRDEFEATURE *feature = (VRDEFEATURE *)RTMemTmpAlloc(featLen);
238 feature->u32ClientId = 0;
239 RTStrCopy(feature->achInfo, featLen - sizeof(VRDEFEATURE) + 1, szFeatName);
240
241 cbOut = featLen;
242 rc = instance->mCallbacks->VRDECallbackProperty(instance->mCallback, VRDE_QP_FEATURE, feature, featLen, &cbOut);
243 Assert(cbOut <= featLen);
244
245 if (RT_SUCCESS(rc) && feature->achInfo[0])
246 {
247 rc = RTStrToUInt32Ex(feature->achInfo, NULL, 0, &port);
248 if (RT_FAILURE(rc) || port >= 65535)
249 vncServer->autoPort = 1;
250 else
251 vncServer->port = port;
252 }
253 else
254 vncServer->autoPort = 1;
255
256 RTMemTmpFree(feature);
257 }
258
259 rfbInitServer(vncServer);
260
261 vncServer->newClientHook = rfbNewClientEvent;
262 vncServer->kbdAddEvent = vncKeyboardEvent;
263 vncServer->ptrAddEvent = vncMouseEvent;
264
265 // notify about the actually used port
266 port = vncServer->port;
267 instance->mCallbacks->VRDECallbackProperty(instance->mCallback,
268 VRDE_SP_NETWORK_BIND_PORT,
269 &port, sizeof(port), NULL);
270 LogRel(("VNC: port = %u\n", port));
271
272 // let's get the password
273 instance->szVNCPassword[0] = '\0';
274 const char szFeatName[] = "Property/VNCPassword";
275 const uint32_t featLen = sizeof(VRDEFEATURE) + RT_MAX(sizeof(instance->szVNCPassword), sizeof(szFeatName)) - 1;
276 VRDEFEATURE *feature = (VRDEFEATURE *)RTMemTmpAlloc(featLen);
277 feature->u32ClientId = 0;
278 RTStrCopy(feature->achInfo, featLen - sizeof(VRDEFEATURE) + 1, szFeatName);
279
280 cbOut = featLen;
281 rc = instance->mCallbacks->VRDECallbackProperty(instance->mCallback, VRDE_QP_FEATURE, feature, featLen, &cbOut);
282 Assert(cbOut <= featLen);
283
284 if (RT_SUCCESS(rc))
285 {
286 RTStrCopy(instance->szVNCPassword, sizeof(instance->szVNCPassword), feature->achInfo);
287 memset(feature->achInfo, '\0', featLen - sizeof(VRDEFEATURE) + 1);
288 LogRel(("VNC: Configuring password\n"));
289
290 instance->apszVNCPasswordStruct[0] = instance->szVNCPassword;
291 instance->apszVNCPasswordStruct[1] = NULL;
292
293 vncServer->authPasswdData = (void *)instance->apszVNCPasswordStruct;
294 vncServer->passwordCheck = rfbCheckPasswordByList;
295 }
296 else
297 LogRel(("VNC: No password result = %Rrc\n", rc));
298
299 RTMemTmpFree(feature);
300
301 rfbRunEventLoop(vncServer, -1, TRUE);
302
303 return VINF_SUCCESS;
304}
305
306/** The server should disconnect the client.
307 *
308 * @param hServer The server instance handle.
309 * @param u32ClientId The client identifier.
310 * @param fReconnect Whether to send a "REDIRECT to the same server" packet to the
311 * client before disconnecting.
312 *
313 * @return IPRT status code.
314 */
315DECLCALLBACK(void) VNCServerImpl::VRDEDisconnect(HVRDESERVER hServer, uint32_t u32ClientId,
316 bool fReconnect)
317{
318}
319
320static inline void convert15To32bpp(uint8_t msb, uint8_t lsb, uint8_t &r, uint8_t &g, uint8_t &b)
321{
322 uint16_t px = lsb << 8 | msb;
323 // RGB 555 (1 bit unused)
324 r = (px >> 7) & 0xf8;
325 g = (px >> 2) & 0xf8;
326 b = (px << 3) & 0xf8;
327}
328
329static inline void convert16To32bpp(uint8_t msb, uint8_t lsb, uint8_t &r, uint8_t &g, uint8_t &b)
330{
331 uint16_t px = lsb << 8 | msb;
332 // RGB 565 (all bits used, 1 extra bit for green)
333 r = (px >> 8) & 0xf8;
334 g = (px >> 3) & 0xfc;
335 b = (px << 3) & 0xf8;
336}
337
338/**
339 * Inform the server that the display was resized.
340 * The server will query information about display
341 * from the application via callbacks.
342 *
343 * @param hServer Handle of VRDE server instance.
344 */
345DECLCALLBACK(void) VNCServerImpl::VRDEResize(HVRDESERVER hServer)
346{
347 VNCServerImpl *instance = (VNCServerImpl *)hServer;
348 VRDEFRAMEBUFFERINFO info;
349 int rc = instance->mCallbacks->VRDECallbackFramebufferQuery(instance->mCallback, 0, &info);
350 if (!RT_SUCCESS(rc))
351 {
352 return;
353 }
354
355 LogRel(("VNCServerImpl::VRDEResize to %dx%dx%dbpp\n", info.cWidth, info.cHeight, info.cBitsPerPixel));
356
357 // we always alloc an RGBA buffer
358 unsigned char *FrameBuffer = (unsigned char *)RTMemAlloc(info.cWidth * info.cHeight * VNC_SIZEOFRGBA); // RGBA
359 if (info.cBitsPerPixel == 32 || info.cBitsPerPixel == 24)
360 {
361 // Convert RGB (windows/vbox) to BGR(vnc)
362 uint32_t i, j;
363 for (i = 0, j = 0; i < info.cWidth * info.cHeight * VNC_SIZEOFRGBA; i += VNC_SIZEOFRGBA, j += info.cBitsPerPixel / 8)
364 {
365 unsigned char r = info.pu8Bits[j];
366 unsigned char g = info.pu8Bits[j + 1];
367 unsigned char b = info.pu8Bits[j + 2];
368 FrameBuffer[i] = b;
369 FrameBuffer[i + 1] = g;
370 FrameBuffer[i + 2] = r;
371 }
372 }
373 else if (info.cBitsPerPixel == 16)
374 {
375 uint32_t i, j;
376 for (i = 0, j = 0;
377 i < info.cWidth * info.cHeight * VNC_SIZEOFRGBA;
378 i += VNC_SIZEOFRGBA, j += info.cBitsPerPixel / 8)
379 {
380 convert16To32bpp(info.pu8Bits[j],
381 info.pu8Bits[j + 1],
382 FrameBuffer[i],
383 FrameBuffer[i + 1],
384 FrameBuffer[i + 2]);
385 }
386 }
387 rfbNewFramebuffer(instance->mVNCServer, (char *)FrameBuffer, info.cWidth, info.cHeight, 8, 3, VNC_SIZEOFRGBA);
388
389 void *temp = instance->mFrameBuffer;
390 instance->mFrameBuffer = FrameBuffer;
391 instance->mScreenBuffer = (unsigned char *)info.pu8Bits;
392 instance->FrameInfo = info;
393 if (temp)
394 RTMemFree(temp);
395}
396
397/**
398 * Send a update.
399 *
400 * @param hServer Handle of VRDE server instance.
401 * @param uScreenId The screen index.
402 * @param pvUpdate Pointer to VBoxGuest.h::VRDEORDERHDR structure with extra data.
403 * @param cbUpdate Size of the update data.
404 */
405DECLCALLBACK(void) VNCServerImpl::VRDEUpdate(HVRDESERVER hServer, unsigned uScreenId,
406 void *pvUpdate,uint32_t cbUpdate)
407{
408 char *ptr = (char *)pvUpdate;
409 VNCServerImpl *instance = (VNCServerImpl *)hServer;
410 VRDEORDERHDR *order = (VRDEORDERHDR *)ptr;
411 ptr += sizeof(VRDEORDERHDR);
412 if (order == NULL)
413 {
414 /* Inform the VRDE server that the current display update sequence is
415 * completed. At this moment the framebuffer memory contains a definite
416 * image, that is synchronized with the orders already sent to VRDE client.
417 * The server can now process redraw requests from clients or initial
418 * fullscreen updates for new clients.
419 */
420
421 }
422 else
423 {
424 if (sizeof(VRDEORDERHDR) != cbUpdate)
425 {
426 VRDEORDERCODE *code = (VRDEORDERCODE *)ptr;
427 ptr += sizeof(VRDEORDERCODE);
428
429 switch(code->u32Code)
430 {
431 case VRDE_ORDER_SOLIDRECT:
432 {
433 VRDEORDERSOLIDRECT *solidrect = (VRDEORDERSOLIDRECT *)ptr;
434 rfbFillRect(instance->mVNCServer, solidrect->x, solidrect->y,
435 solidrect->x + solidrect->w, solidrect->y + solidrect->h, RGB2BGR(solidrect->rgb));
436 return;
437 }
438 ///@todo: more orders
439 }
440 }
441
442 uint32_t width = instance->FrameInfo.cWidth;
443 uint32_t bpp = instance->FrameInfo.cBitsPerPixel / 8;
444 uint32_t joff = order->y * width + order->x;
445 uint32_t srcx, srcy, destx, desty;
446 if (instance->FrameInfo.cBitsPerPixel == 32 || instance->FrameInfo.cBitsPerPixel == 24)
447 {
448 for (srcy = joff * bpp, desty = joff * VNC_SIZEOFRGBA;
449 desty < (joff + order->h * width) * VNC_SIZEOFRGBA;
450 srcy += width * bpp, desty += width * VNC_SIZEOFRGBA)
451 {
452 // RGB to BGR
453 for (srcx = srcy, destx = desty;
454 destx < desty + order->w * VNC_SIZEOFRGBA;
455 srcx += bpp, destx += VNC_SIZEOFRGBA)
456 {
457 instance->mFrameBuffer[destx] = instance->mScreenBuffer[srcx + 2];
458 instance->mFrameBuffer[destx + 1] = instance->mScreenBuffer[srcx + 1];
459 instance->mFrameBuffer[destx + 2] = instance->mScreenBuffer[srcx];
460 }
461 }
462 }
463 else if (instance->FrameInfo.cBitsPerPixel == 16)
464 {
465 for (srcy = joff * bpp, desty = joff * VNC_SIZEOFRGBA;
466 desty < (joff + order->h * width) * VNC_SIZEOFRGBA;
467 srcy += width * bpp, desty += width * VNC_SIZEOFRGBA)
468 {
469 for (srcx = srcy, destx = desty;
470 destx < desty + order->w * VNC_SIZEOFRGBA;
471 srcx += bpp, destx += VNC_SIZEOFRGBA)
472 {
473 convert16To32bpp(instance->mScreenBuffer[srcx],
474 instance->mScreenBuffer[srcx + 1],
475 instance->mFrameBuffer[destx],
476 instance->mFrameBuffer[destx + 1],
477 instance->mFrameBuffer[destx + 2]);
478 }
479 }
480 }
481 rfbMarkRectAsModified(instance->mVNCServer, order->x, order->y, order->x+order->w, order->y+order->h);
482 }
483}
484
485
486/**
487 * Set the mouse pointer shape.
488 *
489 * @param hServer Handle of VRDE server instance.
490 * @param pPointer The pointer shape information.
491 */
492DECLCALLBACK(void) VNCServerImpl::VRDEColorPointer(HVRDESERVER hServer,
493 const VRDECOLORPOINTER *pPointer)
494{
495 VNCServerImpl *instance = (VNCServerImpl *)hServer;
496 rfbCursorPtr cursor = (rfbCursorPtr)calloc(sizeof(rfbCursor), 1);
497
498 cursor->width = pPointer->u16Width;
499 cursor->height = pPointer->u16Height;
500
501 unsigned char *mem = (unsigned char *)malloc(pPointer->u16Width * pPointer->u16Height * VNC_SIZEOFRGBA);
502 cursor->richSource = mem;
503
504 unsigned char *maskmem = (unsigned char *)malloc(pPointer->u16Width * pPointer->u16Height);
505 cursor->mask = maskmem;
506
507 unsigned char *mask = (unsigned char *)pPointer + sizeof(VRDECOLORPOINTER);
508
509 for(int i = pPointer->u16Height - 1; i >= 0 ; i--)
510 {
511 for(uint16_t j = 0; j < pPointer->u16Width/8; j ++)
512 {
513 *maskmem = ~(*(mask + i * (pPointer->u16Width / 8) + j));
514 *maskmem++;
515 }
516 }
517 unsigned char *color = (unsigned char *)pPointer + sizeof(VRDECOLORPOINTER) + pPointer->u16MaskLen;
518 for(int i = pPointer->u16Height - 1; i >= 0 ; i--)
519 {
520 for(uint16_t j = 0; j < pPointer->u16Width; j ++)
521 {
522 // put the color value;
523 *(mem++) = *(color + (i * pPointer->u16Width *3 + j * 3 + 2));
524 *(mem++) = *(color + (i * pPointer->u16Width *3 + j * 3 + 1));
525 *(mem++) = *(color + (i * pPointer->u16Width *3 + j * 3));
526 *(mem++) = 0xff;
527 }
528 }
529
530 cursor->xhot = pPointer->u16HotX;
531 cursor->yhot = pPointer->u16HotY;
532
533 rfbSetCursor(instance->mVNCServer, cursor);
534
535 if (instance->mCursor)
536 rfbFreeCursor(instance->mCursor);
537
538 instance->mCursor = cursor;
539}
540
541/**
542 * Hide the mouse pointer.
543 *
544 * @param hServer Handle of VRDE server instance.
545 */
546DECLCALLBACK(void) VNCServerImpl::VRDEHidePointer(HVRDESERVER hServer)
547{
548 VNCServerImpl *instance = (VNCServerImpl *)hServer;
549
550 ///@todo: what's behavior for this. hide doesn't seems right
551 //rfbSetCursor(instance->mVNCServer, NULL);
552}
553
554/**
555 * Queues the samples to be sent to clients.
556 *
557 * @param hServer Handle of VRDE server instance.
558 * @param pvSamples Address of samples to be sent.
559 * @param cSamples Number of samples.
560 * @param format Encoded audio format for these samples.
561 *
562 * @note Initialized to NULL when the application audio callbacks are NULL.
563 */
564DECLCALLBACK(void) VNCServerImpl::VRDEAudioSamples(HVRDESERVER hServer,
565 const void *pvSamples,
566 uint32_t cSamples,
567 VRDEAUDIOFORMAT format)
568{
569}
570
571/**
572 * Sets the sound volume on clients.
573 *
574 * @param hServer Handle of VRDE server instance.
575 * @param left 0..0xFFFF volume level for left channel.
576 * @param right 0..0xFFFF volume level for right channel.
577 *
578 * @note Initialized to NULL when the application audio callbacks are NULL.
579 */
580DECLCALLBACK(void) VNCServerImpl::VRDEAudioVolume(HVRDESERVER hServer,
581 uint16_t u16Left,
582 uint16_t u16Right)
583{
584}
585
586/**
587 * Sends a USB request.
588 *
589 * @param hServer Handle of VRDE server instance.
590 * @param u32ClientId An identifier that allows the server to find the corresponding client.
591 * The identifier is always passed by the server as a parameter
592 * of the FNVRDEUSBCALLBACK. Note that the value is the same as
593 * in the VRDESERVERCALLBACK functions.
594 * @param pvParm Function specific parameters buffer.
595 * @param cbParm Size of the buffer.
596 *
597 * @note Initialized to NULL when the application USB callbacks are NULL.
598 */
599DECLCALLBACK(void) VNCServerImpl::VRDEUSBRequest(HVRDESERVER hServer,
600 uint32_t u32ClientId,
601 void *pvParm,
602 uint32_t cbParm)
603{
604}
605
606/**
607 * Called by the application when (VRDE_CLIPBOARD_FUNCTION_*):
608 * - (0) guest announces available clipboard formats;
609 * - (1) guest requests clipboard data;
610 * - (2) guest responds to the client's request for clipboard data.
611 *
612 * @param hServer The VRDE server handle.
613 * @param u32Function The cause of the call.
614 * @param u32Format Bitmask of announced formats or the format of data.
615 * @param pvData Points to: (1) buffer to be filled with clients data;
616 * (2) data from the host.
617 * @param cbData Size of 'pvData' buffer in bytes.
618 * @param pcbActualRead Size of the copied data in bytes.
619 *
620 * @note Initialized to NULL when the application clipboard callbacks are NULL.
621 */
622DECLCALLBACK(void) VNCServerImpl::VRDEClipboard(HVRDESERVER hServer,
623 uint32_t u32Function,
624 uint32_t u32Format,
625 void *pvData,
626 uint32_t cbData,
627 uint32_t *pcbActualRead)
628{
629}
630
631/**
632 * Query various information from the VRDE server.
633 *
634 * @param hServer The VRDE server handle.
635 * @param index VRDE_QI_* identifier of information to be returned.
636 * @param pvBuffer Address of memory buffer to which the information must be written.
637 * @param cbBuffer Size of the memory buffer in bytes.
638 * @param pcbOut Size in bytes of returned information value.
639 *
640 * @remark The caller must check the *pcbOut. 0 there means no information was returned.
641 * A value greater than cbBuffer means that information is too big to fit in the
642 * buffer, in that case no information was placed to the buffer.
643 */
644DECLCALLBACK(void) VNCServerImpl::VRDEQueryInfo(HVRDESERVER hServer,
645 uint32_t index,
646 void *pvBuffer,
647 uint32_t cbBuffer,
648 uint32_t *pcbOut)
649{
650 VNCServerImpl *instance = (VNCServerImpl *)hServer;
651 *pcbOut = 0;
652
653 switch (index)
654 {
655 case VRDE_QI_ACTIVE: /* # of active clients */
656 case VRDE_QI_NUMBER_OF_CLIENTS: /* # of connected clients */
657 {
658 uint32_t cbOut = sizeof(uint32_t);
659 if (cbBuffer >= cbOut)
660 {
661 *pcbOut = cbOut;
662 *(uint32_t *)pvBuffer = instance->uClients;
663 }
664 break;
665 }
666 ///@todo lots more queries to implement
667 default:
668 break;
669 }
670}
671
672
673/**
674 * The server should redirect the client to the specified server.
675 *
676 * @param hServer The server instance handle.
677 * @param u32ClientId The client identifier.
678 * @param pszServer The server to redirect the client to.
679 * @param pszUser The username to use for the redirection.
680 * Can be NULL.
681 * @param pszDomain The domain. Can be NULL.
682 * @param pszPassword The password. Can be NULL.
683 * @param u32SessionId The ID of the session to redirect to.
684 * @param pszCookie The routing token used by a load balancer to
685 * route the redirection. Can be NULL.
686 */
687DECLCALLBACK(void) VNCServerImpl::VRDERedirect(HVRDESERVER hServer,
688 uint32_t u32ClientId,
689 const char *pszServer,
690 const char *pszUser,
691 const char *pszDomain,
692 const char *pszPassword,
693 uint32_t u32SessionId,
694 const char *pszCookie)
695{
696}
697
698/**
699 * Audio input open request.
700 *
701 * @param hServer Handle of VRDE server instance.
702 * @param pvCtx To be used in VRDECallbackAudioIn.
703 * @param u32ClientId An identifier that allows the server to find the corresponding client.
704 * @param audioFormat Preferred format of audio data.
705 * @param u32SamplesPerBlock Preferred number of samples in one block of audio input data.
706 *
707 * @note Initialized to NULL when the VRDECallbackAudioIn callback is NULL.
708 */
709DECLCALLBACK(void) VNCServerImpl::VRDEAudioInOpen(HVRDESERVER hServer,
710 void *pvCtx,
711 uint32_t u32ClientId,
712 VRDEAUDIOFORMAT audioFormat,
713 uint32_t u32SamplesPerBlock)
714{
715}
716
717/**
718 * Audio input close request.
719 *
720 * @param hServer Handle of VRDE server instance.
721 * @param u32ClientId An identifier that allows the server to find the corresponding client.
722 *
723 * @note Initialized to NULL when the VRDECallbackAudioIn callback is NULL.
724 */
725DECLCALLBACK(void) VNCServerImpl::VRDEAudioInClose(HVRDESERVER hServer,
726 uint32_t u32ClientId)
727{
728}
729
730
731
732int VNCServerImpl::Init(const VRDEINTERFACEHDR *pCallbacks,
733 void *pvCallback)
734{
735 if (pCallbacks->u64Version == VRDE_INTERFACE_VERSION_3)
736 {
737 mCallbacks = (VRDECALLBACKS_4 *)pCallbacks;
738 mCallback = pvCallback;
739 }
740 else if (pCallbacks->u64Version == VRDE_INTERFACE_VERSION_1)
741 {
742 ///@todo: this is incorrect and it will cause crash if client call unsupport func.
743 mCallbacks = (VRDECALLBACKS_4 *)pCallbacks;
744 mCallback = pvCallback;
745
746
747 // since they are same in order, let's just change header
748 Entries.header.u64Version = VRDE_INTERFACE_VERSION_1;
749 Entries.header.u64Size = sizeof(VRDEENTRYPOINTS_1);
750 }
751 else
752 return VERR_VERSION_MISMATCH;
753
754 return VINF_SUCCESS;
755}
756
757
758void VNCServerImpl::vncKeyboardEvent(rfbBool down, rfbKeySym keycode, rfbClientPtr cl)
759{
760 VNCServerImpl *instance = static_cast<VNCServerImpl *>(cl->screen->screenData);
761 VRDEINPUTSCANCODE point;
762
763 /* Conversion table for key code range 32-127 (which happen to equal the ASCII codes).
764 * Values 0xe0?? indicate that a 0xe0 scancode will be sent first (extended keys), then code ?? is sent */
765 static unsigned codes_low[] =
766 {
767 // Conversion table for VNC key code range 32-127
768 0x39, 0x02, 0x28, 0x04, 0x05, 0x06, 0x08, 0x28, 0x0a, 0x0b, 0x09, 0x0d, 0x33, 0x0c, 0x34, 0x35, //space, !"#$%&'()*+`-./
769 0x0b, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x27, 0x27, 0x33, 0x0d, 0x34, 0x35, 0x03, //0123456789:;<=>?@
770 0x1e, 0x30, 0x2e, 0x20, 0x12, 0x21, 0x22, 0x23, 0x17, 0x24, 0x25, 0x26, 0x32, //A-M
771 0x31, 0x18, 0x19, 0x10, 0x13, 0x1f, 0x14, 0x16, 0x2f, 0x11, 0x2d, 0x15, 0x2c, //N-Z
772 0x1a, 0x2b, 0x1b, 0x07, 0x0c, 0x29, //[\]^_`
773 0x1e, 0x30, 0x2e, 0x20, 0x12, 0x21, 0x22, 0x23, 0x17, 0x24, 0x25, 0x26, 0x32, //a-m
774 0x31, 0x18, 0x19, 0x10, 0x13, 0x1f, 0x14, 0x16, 0x2f, 0x11, 0x2d, 0x15, 0x2c, //n-z
775 0x1a, 0x2b, 0x1b, 0x29 //{|}~
776 };
777
778 int code = -1;
779 if (keycode < 32)
780 {
781 //ASCII control codes.. unused..
782 }
783 else if (keycode < 127)
784 {
785 //DEL is in high area
786 code = codes_low[keycode - 32];
787 }
788 else if ((keycode & 0xFE00) != 0xFE00)
789 {
790 }
791 else
792 {
793 switch(keycode)
794 {
795 case 65027: code = 0xe038; break; //AltGr = RAlt
796 case 65288: code = 0x0e; break; //Backspace
797 case 65289: code = 0x0f; break; //Tab
798
799 case 65293: code = 0x1c; break; //Return
800 //case 65299: break; Pause/break
801 case 65300: code = 0x46; break; //ScrollLock
802 //case 65301: break; SysRq
803 case 65307: code = 0x01; break; //Escape
804
805 case 65360: code = 0xe047; break; //Home
806 case 65361: code = 0xe04b; break; //Left
807 case 65362: code = 0xe048; break; //Up
808 case 65363: code = 0xe04d; break; //Right
809 case 65364: code = 0xe050; break; //Down
810 case 65365: code = 0xe049; break; //Page up
811 case 65366: code = 0xe051; break; //Page down
812 case 65367: code = 0xe04f; break; //End
813
814 //case 65377: break; //Print screen
815 case 65379: code = 0xe052; break; //Insert
816
817 case 65383: code = 0xe05d; break; //Menu
818 case 65407: code = 0x45; break; //NumLock
819
820 case 65421: code = 0xe01c; break; //Numpad return
821 case 65429: code = 0x47; break; //Numpad home
822 case 65430: code = 0x4b; break; //Numpad left
823 case 65431: code = 0x48; break; //Numpad up
824 case 65432: code = 0x4d; break; //Numpad right
825 case 65433: code = 0x50; break; //Numpad down
826 case 65434: code = 0x49; break; //Numpad page up
827 case 65435: code = 0x51; break; //Numpad page down
828 case 65436: code = 0x4f; break; //Numpad end
829 case 65437: code = 0x4c; break; //Numpad begin
830 case 65438: code = 0x52; break; //Numpad ins
831 case 65439: code = 0x53; break; //Numpad del
832 case 65450: code = 0x37; break; //Numpad *
833 case 65451: code = 0x4e; break; //Numpad +
834 case 65452: code = 0x53; break; //Numpad separator
835 case 65453: code = 0x4a; break; //Numpad -
836 case 65454: code = 0x53; break; //Numpad decimal
837 case 65455: code = 0xe035; break; //Numpad /
838 case 65456: code = 0x52; break; //Numpad 0
839 case 65457: code = 0x4f; break; //Numpad 1
840 case 65458: code = 0x50; break; //Numpad 2
841 case 65459: code = 0x51; break; //Numpad 3
842 case 65460: code = 0x4b; break; //Numpad 4
843 case 65461: code = 0x4c; break; //Numpad 5
844 case 65462: code = 0x4d; break; //Numpad 6
845 case 65463: code = 0x47; break; //Numpad 7
846 case 65464: code = 0x48; break; //Numpad 8
847 case 65465: code = 0x49; break; //Numpad 9
848
849 case 65470: code = 0x3b; break; //F1
850 case 65471: code = 0x3c; break; //F2
851 case 65472: code = 0x3d; break; //F3
852 case 65473: code = 0x3e; break; //F4
853 case 65474: code = 0x3f; break; //F5
854 case 65475: code = 0x40; break; //F6
855 case 65476: code = 0x41; break; //F7
856 case 65477: code = 0x42; break; //F8
857 case 65478: code = 0x43; break; //F9
858 case 65479: code = 0x44; break; //F10
859 case 65480: code = 0x57; break; //F11
860 case 65481: code = 0x58; break; //F12
861
862 case 65505: code = 0x2a; break; //Left shift
863 case 65506: code = 0x36; break; //Right shift
864 case 65507: code = 0x1d; break; //Left ctrl
865 case 65508: code = 0xe01d; break; //Right ctrl
866 case 65509: code = 0x3a; break; //Caps Lock
867 case 65510: code = 0x3a; break; //Shift Lock
868 case 65513: code = 0x38; break; //Left Alt
869 case 65514: code = 0xe038; break; //Right Alt
870 case 65515: code = 0xe05b; break; //Left windows key
871 case 65516: code = 0xe05c; break; //Right windows key
872 case 65535: code = 0xe053; break; //Delete
873 }
874 }
875
876 if (code == -1)
877 {
878 LogRel(("VNC: unhandled keyboard code: down=%d code=%d\n", down, keycode));
879 return;
880 }
881 if (code > 0xff)
882 {
883 point.uScancode = (code >> 8) & 0xff;
884 instance->mCallbacks->VRDECallbackInput(instance->mCallback, VRDE_INPUT_SCANCODE, &point, sizeof(point));
885 }
886
887 point.uScancode = (code & 0xff) | (down ? 0 : 0x80);
888 instance->mCallbacks->VRDECallbackInput(instance->mCallback, VRDE_INPUT_SCANCODE, &point, sizeof(point));
889}
890
891void VNCServerImpl::vncMouseEvent(int buttonMask, int x, int y, rfbClientPtr cl)
892{
893 VNCServerImpl *instance = static_cast<VNCServerImpl *>(cl->screen->screenData);
894
895 VRDEINPUTPOINT point;
896 unsigned button = 0;
897 if (buttonMask & 1) button |= VRDE_INPUT_POINT_BUTTON1;
898 if (buttonMask & 2) button |= VRDE_INPUT_POINT_BUTTON3;
899 if (buttonMask & 4) button |= VRDE_INPUT_POINT_BUTTON2;
900 if (buttonMask & 8) button |= VRDE_INPUT_POINT_WHEEL_UP;
901 if (buttonMask & 16) button |= VRDE_INPUT_POINT_WHEEL_DOWN;
902 point.uButtons = button;
903 point.x = x;
904 point.y = y;
905 instance->mCallbacks->VRDECallbackInput(instance->mCallback, VRDE_INPUT_POINT, &point, sizeof(point));
906 rfbDefaultPtrAddEvent(buttonMask, x, y, cl);
907}
908
909enum rfbNewClientAction VNCServerImpl::rfbNewClientEvent(rfbClientPtr cl)
910{
911 VNCServerImpl *instance = static_cast<VNCServerImpl *>(cl->screen->screenData);
912
913 ///@todo: we need auth user here
914
915 instance->mCallbacks->VRDECallbackClientConnect(instance->mCallback, (int)cl->sock);
916 instance->uClients++;
917
918 cl->clientGoneHook = clientGoneHook;
919
920 return RFB_CLIENT_ACCEPT;
921}
922
923void VNCServerImpl::clientGoneHook(rfbClientPtr cl)
924{
925 VNCServerImpl *instance = static_cast<VNCServerImpl *>(cl->screen->screenData);
926
927 instance->uClients--;
928 instance->mCallbacks->VRDECallbackClientDisconnect(instance->mCallback, (int)cl->sock, 0);
929}
930
931VNCServerImpl *g_VNCServer = 0;
932
933DECLEXPORT(int) VRDECreateServer(const VRDEINTERFACEHDR *pCallbacks,
934 void *pvCallback,
935 VRDEINTERFACEHDR **ppEntryPoints,
936 HVRDESERVER *phServer)
937{
938 if (!g_VNCServer)
939 {
940 g_VNCServer = new VNCServerImpl();
941 }
942
943 int rc = g_VNCServer->Init(pCallbacks, pvCallback);
944
945 if (RT_SUCCESS(rc))
946 {
947 *ppEntryPoints = g_VNCServer->GetInterface();
948 *phServer = (HVRDESERVER)g_VNCServer;
949 }
950
951 return rc;
952}
953
954static const char * const supportedProperties[] =
955{
956 "TCP/Ports",
957 "TCP/Address",
958 NULL
959};
960
961DECLEXPORT(const char * const *) VRDESupportedProperties(void)
962{
963 LogFlowFunc(("enter\n"));
964 return supportedProperties;
965}
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