VirtualBox

source: vbox/trunk/src/VBox/Main/src-client/HGCM.cpp@ 49498

Last change on this file since 49498 was 48229, checked in by vboxsync, 11 years ago

Main/HGCM: add plugin support (preparing for HGCM modules in an extension pack), just like it's done in VRDE

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 72.2 KB
Line 
1/** @file
2 *
3 * HGCM (Host-Guest Communication Manager)
4 */
5
6/*
7 * Copyright (C) 2006-2013 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#define LOG_GROUP_MAIN_OVERRIDE LOG_GROUP_HGCM
19#include "Logging.h"
20
21#include "HGCM.h"
22#include "HGCMThread.h"
23
24#include <VBox/err.h>
25#include <VBox/hgcmsvc.h>
26#include <VBox/vmm/ssm.h>
27#include <VBox/sup.h>
28
29#include <iprt/alloc.h>
30#include <iprt/alloca.h>
31#include <iprt/avl.h>
32#include <iprt/critsect.h>
33#include <iprt/asm.h>
34#include <iprt/ldr.h>
35#include <iprt/param.h>
36#include <iprt/path.h>
37#include <iprt/string.h>
38#include <iprt/semaphore.h>
39#include <iprt/thread.h>
40
41#include <VBox/VMMDev.h>
42
43/**
44 * A service gets one thread, which synchronously delivers messages to
45 * the service. This is good for serialization.
46 *
47 * Some services may want to process messages asynchronously, and will want
48 * a next message to be delivered, while a previous message is still being
49 * processed.
50 *
51 * The dedicated service thread delivers a next message when service
52 * returns after fetching a previous one. The service will call a message
53 * completion callback when message is actually processed. So returning
54 * from the service call means only that the service is processing message.
55 *
56 * 'Message processed' condition is indicated by service, which call the
57 * callback, even if the callback is called synchronously in the dedicated
58 * thread.
59 *
60 * This message completion callback is only valid for Call requests.
61 * Connect and Disconnect are processed synchronously by the service.
62 */
63
64
65/* The maximum allowed size of a service name in bytes. */
66#define VBOX_HGCM_SVC_NAME_MAX_BYTES 1024
67
68struct _HGCMSVCEXTHANDLEDATA
69{
70 char *pszServiceName;
71 /* The service name follows. */
72};
73
74/** Internal helper service object. HGCM code would use it to
75 * hold information about services and communicate with services.
76 * The HGCMService is an (in future) abstract class that implements
77 * common functionality. There will be derived classes for specific
78 * service types.
79 */
80
81class HGCMService
82{
83 private:
84 VBOXHGCMSVCHELPERS m_svcHelpers;
85
86 static HGCMService *sm_pSvcListHead;
87 static HGCMService *sm_pSvcListTail;
88
89 static int sm_cServices;
90
91 HGCMTHREADHANDLE m_thread;
92 friend DECLCALLBACK(void) hgcmServiceThread (HGCMTHREADHANDLE ThreadHandle, void *pvUser);
93
94 uint32_t volatile m_u32RefCnt;
95
96 HGCMService *m_pSvcNext;
97 HGCMService *m_pSvcPrev;
98
99 char *m_pszSvcName;
100 char *m_pszSvcLibrary;
101
102 RTLDRMOD m_hLdrMod;
103 PFNVBOXHGCMSVCLOAD m_pfnLoad;
104
105 VBOXHGCMSVCFNTABLE m_fntable;
106
107 int m_cClients;
108 int m_cClientsAllocated;
109
110 uint32_t *m_paClientIds;
111
112#ifdef VBOX_WITH_CRHGSMI
113 uint32_t m_cHandleAcquires;
114#endif
115
116 HGCMSVCEXTHANDLE m_hExtension;
117
118 int loadServiceDLL (void);
119 void unloadServiceDLL (void);
120
121 /*
122 * Main HGCM thread methods.
123 */
124 int instanceCreate (const char *pszServiceLibrary, const char *pszServiceName);
125 void instanceDestroy (void);
126
127 int saveClientState(uint32_t u32ClientId, PSSMHANDLE pSSM);
128 int loadClientState(uint32_t u32ClientId, PSSMHANDLE pSSM);
129
130 HGCMService ();
131 ~HGCMService () {};
132
133 static DECLCALLBACK(void) svcHlpCallComplete (VBOXHGCMCALLHANDLE callHandle, int32_t rc);
134 static DECLCALLBACK(void) svcHlpDisconnectClient (void *pvInstance, uint32_t u32ClientId);
135
136 public:
137
138 /*
139 * Main HGCM thread methods.
140 */
141 static int LoadService (const char *pszServiceLibrary, const char *pszServiceName);
142 void UnloadService (void);
143
144 static void UnloadAll (void);
145
146 static int ResolveService (HGCMService **ppsvc, const char *pszServiceName);
147 void ReferenceService (void);
148 void ReleaseService (void);
149
150 static void Reset (void);
151
152 static int SaveState (PSSMHANDLE pSSM);
153 static int LoadState (PSSMHANDLE pSSM);
154
155 int CreateAndConnectClient (uint32_t *pu32ClientIdOut, uint32_t u32ClientIdIn);
156 int DisconnectClient (uint32_t u32ClientId, bool fFromService);
157
158 int HostCall (uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM *paParms);
159
160#ifdef VBOX_WITH_CRHGSMI
161 int HandleAcquired();
162 int HandleReleased();
163 int HostFastCallAsync (uint32_t u32Function, VBOXHGCMSVCPARM *pParm, PHGCMHOSTFASTCALLCB pfnCompletion, void *pvCompletion);
164#endif
165
166 uint32_t SizeOfClient (void) { return m_fntable.cbClient; };
167
168 int RegisterExtension (HGCMSVCEXTHANDLE handle, PFNHGCMSVCEXT pfnExtension, void *pvExtension);
169 void UnregisterExtension (HGCMSVCEXTHANDLE handle);
170
171 /*
172 * The service thread methods.
173 */
174
175 int GuestCall (PPDMIHGCMPORT pHGCMPort, PVBOXHGCMCMD pCmd, uint32_t u32ClientId, uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM aParms[]);
176};
177
178
179class HGCMClient: public HGCMObject
180{
181 public:
182 HGCMClient () : HGCMObject(HGCMOBJ_CLIENT), pService(NULL),
183 pvData(NULL) {};
184 ~HGCMClient ();
185
186 int Init (HGCMService *pSvc);
187
188 /** Service that the client is connected to. */
189 HGCMService *pService;
190
191 /** Client specific data. */
192 void *pvData;
193};
194
195HGCMClient::~HGCMClient ()
196{
197 if (pService->SizeOfClient () > 0)
198 RTMemFree (pvData);
199}
200
201int HGCMClient::Init (HGCMService *pSvc)
202{
203 pService = pSvc;
204
205 if (pService->SizeOfClient () > 0)
206 {
207 pvData = RTMemAllocZ (pService->SizeOfClient ());
208
209 if (!pvData)
210 {
211 return VERR_NO_MEMORY;
212 }
213 }
214
215 return VINF_SUCCESS;
216}
217
218
219#define HGCM_CLIENT_DATA(pService, pClient) (pClient->pvData)
220
221
222
223HGCMService *HGCMService::sm_pSvcListHead = NULL;
224HGCMService *HGCMService::sm_pSvcListTail = NULL;
225int HGCMService::sm_cServices = 0;
226
227HGCMService::HGCMService ()
228 :
229 m_thread (0),
230 m_u32RefCnt (0),
231 m_pSvcNext (NULL),
232 m_pSvcPrev (NULL),
233 m_pszSvcName (NULL),
234 m_pszSvcLibrary (NULL),
235 m_hLdrMod (NIL_RTLDRMOD),
236 m_pfnLoad (NULL),
237 m_cClients (0),
238 m_cClientsAllocated (0),
239 m_paClientIds (NULL),
240#ifdef VBOX_WITH_CRHGSMI
241 m_cHandleAcquires (0),
242#endif
243 m_hExtension (NULL)
244{
245 RT_ZERO(m_fntable);
246}
247
248
249static bool g_fResetting = false;
250static bool g_fSaveState = false;
251
252
253/** Helper function to load a local service DLL.
254 *
255 * @return VBox code
256 */
257int HGCMService::loadServiceDLL(void)
258{
259 LogFlowFunc(("m_pszSvcLibrary = %s\n", m_pszSvcLibrary));
260
261 if (m_pszSvcLibrary == NULL)
262 {
263 return VERR_INVALID_PARAMETER;
264 }
265
266 RTERRINFOSTATIC ErrInfo;
267 RTErrInfoInitStatic(&ErrInfo);
268
269 int rc;
270
271 if (RTPathHasPath(m_pszSvcLibrary))
272 rc = SUPR3HardenedLdrLoadPlugIn(m_pszSvcLibrary, &m_hLdrMod, &ErrInfo.Core);
273 else
274 rc = SUPR3HardenedLdrLoadAppPriv(m_pszSvcLibrary, &m_hLdrMod, RTLDRLOAD_FLAGS_LOCAL, &ErrInfo.Core);
275
276 if (RT_SUCCESS(rc))
277 {
278 LogFlowFunc(("successfully loaded the library.\n"));
279
280 m_pfnLoad = NULL;
281
282 rc = RTLdrGetSymbol(m_hLdrMod, VBOX_HGCM_SVCLOAD_NAME, (void**)&m_pfnLoad);
283
284 if (RT_FAILURE(rc) || !m_pfnLoad)
285 {
286 Log(("HGCMService::loadServiceDLL: Error resolving the service entry point %s, rc = %d, m_pfnLoad = %p\n", VBOX_HGCM_SVCLOAD_NAME, rc, m_pfnLoad));
287
288 if (RT_SUCCESS(rc))
289 {
290 /* m_pfnLoad was NULL */
291 rc = VERR_SYMBOL_NOT_FOUND;
292 }
293 }
294
295 if (RT_SUCCESS(rc))
296 {
297 RT_ZERO(m_fntable);
298
299 m_fntable.cbSize = sizeof(m_fntable);
300 m_fntable.u32Version = VBOX_HGCM_SVC_VERSION;
301 m_fntable.pHelpers = &m_svcHelpers;
302
303 rc = m_pfnLoad(&m_fntable);
304
305 LogFlowFunc(("m_pfnLoad rc = %Rrc\n", rc));
306
307 if (RT_SUCCESS(rc))
308 {
309 if ( m_fntable.pfnUnload == NULL
310 || m_fntable.pfnConnect == NULL
311 || m_fntable.pfnDisconnect == NULL
312 || m_fntable.pfnCall == NULL
313 )
314 {
315 Log(("HGCMService::loadServiceDLL: at least one of function pointers is NULL\n"));
316
317 rc = VERR_INVALID_PARAMETER;
318
319 if (m_fntable.pfnUnload)
320 {
321 m_fntable.pfnUnload(m_fntable.pvService);
322 }
323 }
324 }
325 }
326 }
327 else
328 {
329 LogRel(("HGCM: Failed to load the service library: [%s], rc = %Rrc - %s. The service will be not available.\n",
330 m_pszSvcLibrary, rc, ErrInfo.Core.pszMsg));
331 m_hLdrMod = NIL_RTLDRMOD;
332 }
333
334 if (RT_FAILURE(rc))
335 {
336 unloadServiceDLL();
337 }
338
339 return rc;
340}
341
342/** Helper function to free a local service DLL.
343 *
344 * @return VBox code
345 */
346void HGCMService::unloadServiceDLL(void)
347{
348 if (m_hLdrMod)
349 {
350 RTLdrClose(m_hLdrMod);
351 }
352
353 RT_ZERO(m_fntable);
354 m_pfnLoad = NULL;
355 m_hLdrMod = NIL_RTLDRMOD;
356}
357
358/*
359 * Messages processed by service threads. These threads only call the service entry points.
360 */
361
362#define SVC_MSG_LOAD (0) /* Load the service library and call VBOX_HGCM_SVCLOAD_NAME entry point. */
363#define SVC_MSG_UNLOAD (1) /* call pfnUnload and unload the service library. */
364#define SVC_MSG_CONNECT (2) /* pfnConnect */
365#define SVC_MSG_DISCONNECT (3) /* pfnDisconnect */
366#define SVC_MSG_GUESTCALL (4) /* pfnGuestCall */
367#define SVC_MSG_HOSTCALL (5) /* pfnHostCall */
368#define SVC_MSG_LOADSTATE (6) /* pfnLoadState. */
369#define SVC_MSG_SAVESTATE (7) /* pfnSaveState. */
370#define SVC_MSG_QUIT (8) /* Terminate the thread. */
371#define SVC_MSG_REGEXT (9) /* pfnRegisterExtension */
372#define SVC_MSG_UNREGEXT (10) /* pfnRegisterExtension */
373#ifdef VBOX_WITH_CRHGSMI
374# define SVC_MSG_HOSTFASTCALLASYNC (21) /* pfnHostCall */
375#endif
376
377class HGCMMsgSvcLoad: public HGCMMsgCore
378{
379};
380
381class HGCMMsgSvcUnload: public HGCMMsgCore
382{
383};
384
385class HGCMMsgSvcConnect: public HGCMMsgCore
386{
387 public:
388 /* client identifier */
389 uint32_t u32ClientId;
390};
391
392class HGCMMsgSvcDisconnect: public HGCMMsgCore
393{
394 public:
395 /* client identifier */
396 uint32_t u32ClientId;
397};
398
399class HGCMMsgHeader: public HGCMMsgCore
400{
401 public:
402 HGCMMsgHeader () : pCmd (NULL), pHGCMPort (NULL) {};
403
404 /* Command pointer/identifier. */
405 PVBOXHGCMCMD pCmd;
406
407 /* Port to be informed on message completion. */
408 PPDMIHGCMPORT pHGCMPort;
409};
410
411
412class HGCMMsgCall: public HGCMMsgHeader
413{
414 public:
415 /* client identifier */
416 uint32_t u32ClientId;
417
418 /* function number */
419 uint32_t u32Function;
420
421 /* number of parameters */
422 uint32_t cParms;
423
424 VBOXHGCMSVCPARM *paParms;
425};
426
427class HGCMMsgLoadSaveStateClient: public HGCMMsgCore
428{
429 public:
430 uint32_t u32ClientId;
431 PSSMHANDLE pSSM;
432};
433
434class HGCMMsgHostCallSvc: public HGCMMsgCore
435{
436 public:
437 /* function number */
438 uint32_t u32Function;
439
440 /* number of parameters */
441 uint32_t cParms;
442
443 VBOXHGCMSVCPARM *paParms;
444};
445
446class HGCMMsgSvcRegisterExtension: public HGCMMsgCore
447{
448 public:
449 /* Handle of the extension to be registered. */
450 HGCMSVCEXTHANDLE handle;
451 /* The extension entry point. */
452 PFNHGCMSVCEXT pfnExtension;
453 /* The extension pointer. */
454 void *pvExtension;
455};
456
457class HGCMMsgSvcUnregisterExtension: public HGCMMsgCore
458{
459 public:
460 /* Handle of the registered extension. */
461 HGCMSVCEXTHANDLE handle;
462};
463
464#ifdef VBOX_WITH_CRHGSMI
465class HGCMMsgHostFastCallAsyncSvc: public HGCMMsgCore
466{
467 public:
468 /* function number */
469 uint32_t u32Function;
470 /* parameter */
471 VBOXHGCMSVCPARM Param;
472 /* completion info */
473 PHGCMHOSTFASTCALLCB pfnCompletion;
474 void *pvCompletion;
475};
476#endif
477
478static HGCMMsgCore *hgcmMessageAllocSvc (uint32_t u32MsgId)
479{
480 switch (u32MsgId)
481 {
482#ifdef VBOX_WITH_CRHGSMI
483 case SVC_MSG_HOSTFASTCALLASYNC: return new HGCMMsgHostFastCallAsyncSvc ();
484#endif
485 case SVC_MSG_LOAD: return new HGCMMsgSvcLoad ();
486 case SVC_MSG_UNLOAD: return new HGCMMsgSvcUnload ();
487 case SVC_MSG_CONNECT: return new HGCMMsgSvcConnect ();
488 case SVC_MSG_DISCONNECT: return new HGCMMsgSvcDisconnect ();
489 case SVC_MSG_HOSTCALL: return new HGCMMsgHostCallSvc ();
490 case SVC_MSG_GUESTCALL: return new HGCMMsgCall ();
491 case SVC_MSG_LOADSTATE:
492 case SVC_MSG_SAVESTATE: return new HGCMMsgLoadSaveStateClient ();
493 case SVC_MSG_REGEXT: return new HGCMMsgSvcRegisterExtension ();
494 case SVC_MSG_UNREGEXT: return new HGCMMsgSvcUnregisterExtension ();
495 default:
496 AssertReleaseMsgFailed(("Msg id = %08X\n", u32MsgId));
497 }
498
499 return NULL;
500}
501
502/*
503 * The service thread. Loads the service library and calls the service entry points.
504 */
505DECLCALLBACK(void) hgcmServiceThread (HGCMTHREADHANDLE ThreadHandle, void *pvUser)
506{
507 HGCMService *pSvc = (HGCMService *)pvUser;
508 AssertRelease(pSvc != NULL);
509
510 bool fQuit = false;
511
512 while (!fQuit)
513 {
514 HGCMMsgCore *pMsgCore;
515 int rc = hgcmMsgGet (ThreadHandle, &pMsgCore);
516
517 if (RT_FAILURE(rc))
518 {
519 /* The error means some serious unrecoverable problem in the hgcmMsg/hgcmThread layer. */
520 AssertMsgFailed (("%Rrc\n", rc));
521 break;
522 }
523
524 /* Cache required information to avoid unnecessary pMsgCore access. */
525 uint32_t u32MsgId = pMsgCore->MsgId ();
526
527 switch (u32MsgId)
528 {
529#ifdef VBOX_WITH_CRHGSMI
530 case SVC_MSG_HOSTFASTCALLASYNC:
531 {
532 HGCMMsgHostFastCallAsyncSvc *pMsg = (HGCMMsgHostFastCallAsyncSvc *)pMsgCore;
533
534 LogFlowFunc(("SVC_MSG_HOSTFASTCALLASYNC u32Function = %d, pParm = %p\n", pMsg->u32Function, &pMsg->Param));
535
536 rc = pSvc->m_fntable.pfnHostCall (pSvc->m_fntable.pvService, pMsg->u32Function, 1, &pMsg->Param);
537 } break;
538#endif
539 case SVC_MSG_LOAD:
540 {
541 LogFlowFunc(("SVC_MSG_LOAD\n"));
542 rc = pSvc->loadServiceDLL ();
543 } break;
544
545 case SVC_MSG_UNLOAD:
546 {
547 LogFlowFunc(("SVC_MSG_UNLOAD\n"));
548 if (pSvc->m_fntable.pfnUnload)
549 {
550 pSvc->m_fntable.pfnUnload (pSvc->m_fntable.pvService);
551 }
552
553 pSvc->unloadServiceDLL ();
554 fQuit = true;
555 } break;
556
557 case SVC_MSG_CONNECT:
558 {
559 HGCMMsgSvcConnect *pMsg = (HGCMMsgSvcConnect *)pMsgCore;
560
561 LogFlowFunc(("SVC_MSG_CONNECT u32ClientId = %d\n", pMsg->u32ClientId));
562
563 HGCMClient *pClient = (HGCMClient *)hgcmObjReference (pMsg->u32ClientId, HGCMOBJ_CLIENT);
564
565 if (pClient)
566 {
567 rc = pSvc->m_fntable.pfnConnect (pSvc->m_fntable.pvService, pMsg->u32ClientId, HGCM_CLIENT_DATA(pSvc, pClient));
568
569 hgcmObjDereference (pClient);
570 }
571 else
572 {
573 rc = VERR_HGCM_INVALID_CLIENT_ID;
574 }
575 } break;
576
577 case SVC_MSG_DISCONNECT:
578 {
579 HGCMMsgSvcDisconnect *pMsg = (HGCMMsgSvcDisconnect *)pMsgCore;
580
581 LogFlowFunc(("SVC_MSG_DISCONNECT u32ClientId = %d\n", pMsg->u32ClientId));
582
583 HGCMClient *pClient = (HGCMClient *)hgcmObjReference (pMsg->u32ClientId, HGCMOBJ_CLIENT);
584
585 if (pClient)
586 {
587 rc = pSvc->m_fntable.pfnDisconnect (pSvc->m_fntable.pvService, pMsg->u32ClientId, HGCM_CLIENT_DATA(pSvc, pClient));
588
589 hgcmObjDereference (pClient);
590 }
591 else
592 {
593 rc = VERR_HGCM_INVALID_CLIENT_ID;
594 }
595 } break;
596
597 case SVC_MSG_GUESTCALL:
598 {
599 HGCMMsgCall *pMsg = (HGCMMsgCall *)pMsgCore;
600
601 LogFlowFunc(("SVC_MSG_GUESTCALL u32ClientId = %d, u32Function = %d, cParms = %d, paParms = %p\n",
602 pMsg->u32ClientId, pMsg->u32Function, pMsg->cParms, pMsg->paParms));
603
604 HGCMClient *pClient = (HGCMClient *)hgcmObjReference (pMsg->u32ClientId, HGCMOBJ_CLIENT);
605
606 if (pClient)
607 {
608 pSvc->m_fntable.pfnCall (pSvc->m_fntable.pvService, (VBOXHGCMCALLHANDLE)pMsg, pMsg->u32ClientId, HGCM_CLIENT_DATA(pSvc, pClient), pMsg->u32Function, pMsg->cParms, pMsg->paParms);
609
610 hgcmObjDereference (pClient);
611 }
612 else
613 {
614 rc = VERR_HGCM_INVALID_CLIENT_ID;
615 }
616 } break;
617
618 case SVC_MSG_HOSTCALL:
619 {
620 HGCMMsgHostCallSvc *pMsg = (HGCMMsgHostCallSvc *)pMsgCore;
621
622 LogFlowFunc(("SVC_MSG_HOSTCALL u32Function = %d, cParms = %d, paParms = %p\n", pMsg->u32Function, pMsg->cParms, pMsg->paParms));
623
624 rc = pSvc->m_fntable.pfnHostCall (pSvc->m_fntable.pvService, pMsg->u32Function, pMsg->cParms, pMsg->paParms);
625 } break;
626
627 case SVC_MSG_LOADSTATE:
628 {
629 HGCMMsgLoadSaveStateClient *pMsg = (HGCMMsgLoadSaveStateClient *)pMsgCore;
630
631 LogFlowFunc(("SVC_MSG_LOADSTATE\n"));
632
633 HGCMClient *pClient = (HGCMClient *)hgcmObjReference (pMsg->u32ClientId, HGCMOBJ_CLIENT);
634
635 if (pClient)
636 {
637 if (pSvc->m_fntable.pfnLoadState)
638 {
639 rc = pSvc->m_fntable.pfnLoadState (pSvc->m_fntable.pvService, pMsg->u32ClientId, HGCM_CLIENT_DATA(pSvc, pClient), pMsg->pSSM);
640 }
641
642 hgcmObjDereference (pClient);
643 }
644 else
645 {
646 rc = VERR_HGCM_INVALID_CLIENT_ID;
647 }
648 } break;
649
650 case SVC_MSG_SAVESTATE:
651 {
652 HGCMMsgLoadSaveStateClient *pMsg = (HGCMMsgLoadSaveStateClient *)pMsgCore;
653
654 LogFlowFunc(("SVC_MSG_SAVESTATE\n"));
655
656 HGCMClient *pClient = (HGCMClient *)hgcmObjReference (pMsg->u32ClientId, HGCMOBJ_CLIENT);
657
658 rc = VINF_SUCCESS;
659
660 if (pClient)
661 {
662 if (pSvc->m_fntable.pfnSaveState)
663 {
664 g_fSaveState = true;
665 rc = pSvc->m_fntable.pfnSaveState (pSvc->m_fntable.pvService, pMsg->u32ClientId, HGCM_CLIENT_DATA(pSvc, pClient), pMsg->pSSM);
666 g_fSaveState = false;
667 }
668
669 hgcmObjDereference (pClient);
670 }
671 else
672 {
673 rc = VERR_HGCM_INVALID_CLIENT_ID;
674 }
675 } break;
676
677 case SVC_MSG_REGEXT:
678 {
679 HGCMMsgSvcRegisterExtension *pMsg = (HGCMMsgSvcRegisterExtension *)pMsgCore;
680
681 LogFlowFunc(("SVC_MSG_REGEXT handle = %p, pfn = %p\n", pMsg->handle, pMsg->pfnExtension));
682
683 if (pSvc->m_hExtension)
684 {
685 rc = VERR_NOT_SUPPORTED;
686 }
687 else
688 {
689 if (pSvc->m_fntable.pfnRegisterExtension)
690 {
691 rc = pSvc->m_fntable.pfnRegisterExtension (pSvc->m_fntable.pvService, pMsg->pfnExtension, pMsg->pvExtension);
692 }
693 else
694 {
695 rc = VERR_NOT_SUPPORTED;
696 }
697
698 if (RT_SUCCESS(rc))
699 {
700 pSvc->m_hExtension = pMsg->handle;
701 }
702 }
703 } break;
704
705 case SVC_MSG_UNREGEXT:
706 {
707 HGCMMsgSvcUnregisterExtension *pMsg = (HGCMMsgSvcUnregisterExtension *)pMsgCore;
708
709 LogFlowFunc(("SVC_MSG_UNREGEXT handle = %p\n", pMsg->handle));
710
711 if (pSvc->m_hExtension != pMsg->handle)
712 {
713 rc = VERR_NOT_SUPPORTED;
714 }
715 else
716 {
717 if (pSvc->m_fntable.pfnRegisterExtension)
718 {
719 rc = pSvc->m_fntable.pfnRegisterExtension (pSvc->m_fntable.pvService, NULL, NULL);
720 }
721 else
722 {
723 rc = VERR_NOT_SUPPORTED;
724 }
725
726 pSvc->m_hExtension = NULL;
727 }
728 } break;
729
730 default:
731 {
732 AssertMsgFailed(("hgcmServiceThread::Unsupported message number %08X\n", u32MsgId));
733 rc = VERR_NOT_SUPPORTED;
734 } break;
735 }
736
737 if (u32MsgId != SVC_MSG_GUESTCALL)
738 {
739 /* For SVC_MSG_GUESTCALL the service calls the completion helper.
740 * Other messages have to be completed here.
741 */
742 hgcmMsgComplete (pMsgCore, rc);
743 }
744 }
745}
746
747/* static */ DECLCALLBACK(void) HGCMService::svcHlpCallComplete (VBOXHGCMCALLHANDLE callHandle, int32_t rc)
748{
749 HGCMMsgCore *pMsgCore = (HGCMMsgCore *)callHandle;
750
751 if (pMsgCore->MsgId () == SVC_MSG_GUESTCALL)
752 {
753 /* Only call the completion for these messages. The helper
754 * is called by the service, and the service does not get
755 * any other messages.
756 */
757 hgcmMsgComplete (pMsgCore, rc);
758 }
759 else
760 {
761 AssertFailed ();
762 }
763}
764
765/* static */ DECLCALLBACK(void) HGCMService::svcHlpDisconnectClient (void *pvInstance, uint32_t u32ClientId)
766{
767 HGCMService *pService = static_cast <HGCMService *> (pvInstance);
768
769 if (pService)
770 {
771 pService->DisconnectClient (u32ClientId, true);
772 }
773}
774
775static DECLCALLBACK(void) hgcmMsgCompletionCallback (int32_t result, HGCMMsgCore *pMsgCore)
776{
777 /* Call the VMMDev port interface to issue IRQ notification. */
778 HGCMMsgHeader *pMsgHdr = (HGCMMsgHeader *)pMsgCore;
779
780 LogFlow(("MAIN::hgcmMsgCompletionCallback: message %p\n", pMsgCore));
781
782 if (pMsgHdr->pHGCMPort && !g_fResetting)
783 {
784 pMsgHdr->pHGCMPort->pfnCompleted (pMsgHdr->pHGCMPort, g_fSaveState? VINF_HGCM_SAVE_STATE: result, pMsgHdr->pCmd);
785 }
786}
787
788/*
789 * The main HGCM methods of the service.
790 */
791
792int HGCMService::instanceCreate (const char *pszServiceLibrary, const char *pszServiceName)
793{
794 LogFlowFunc(("name %s, lib %s\n", pszServiceName, pszServiceLibrary));
795
796 /* The maximum length of the thread name, allowed by the RT is 15. */
797 char szThreadName[16];
798 if (!strncmp (pszServiceName, RT_STR_TUPLE("VBoxShared")))
799 RTStrPrintf (szThreadName, sizeof (szThreadName), "Sh%s", pszServiceName + 10);
800 else if (!strncmp (pszServiceName, RT_STR_TUPLE("VBox")))
801 RTStrCopy (szThreadName, sizeof (szThreadName), pszServiceName + 4);
802 else
803 RTStrCopy (szThreadName, sizeof (szThreadName), pszServiceName);
804
805 int rc = hgcmThreadCreate (&m_thread, szThreadName, hgcmServiceThread, this);
806
807 if (RT_SUCCESS(rc))
808 {
809 m_pszSvcName = RTStrDup (pszServiceName);
810 m_pszSvcLibrary = RTStrDup (pszServiceLibrary);
811
812 if (!m_pszSvcName || !m_pszSvcLibrary)
813 {
814 RTStrFree (m_pszSvcLibrary);
815 m_pszSvcLibrary = NULL;
816
817 RTStrFree (m_pszSvcName);
818 m_pszSvcName = NULL;
819
820 rc = VERR_NO_MEMORY;
821 }
822 else
823 {
824 /* Initialize service helpers table. */
825 m_svcHelpers.pfnCallComplete = svcHlpCallComplete;
826 m_svcHelpers.pvInstance = this;
827 m_svcHelpers.pfnDisconnectClient = svcHlpDisconnectClient;
828
829 /* Execute the load request on the service thread. */
830 HGCMMSGHANDLE hMsg;
831 rc = hgcmMsgAlloc (m_thread, &hMsg, SVC_MSG_LOAD, hgcmMessageAllocSvc);
832
833 if (RT_SUCCESS(rc))
834 {
835 rc = hgcmMsgSend (hMsg);
836 }
837 }
838 }
839
840 if (RT_FAILURE(rc))
841 {
842 instanceDestroy ();
843 }
844
845 LogFlowFunc(("rc = %Rrc\n", rc));
846 return rc;
847}
848
849void HGCMService::instanceDestroy (void)
850{
851 LogFlowFunc(("%s\n", m_pszSvcName));
852
853 HGCMMSGHANDLE hMsg;
854 int rc = hgcmMsgAlloc (m_thread, &hMsg, SVC_MSG_UNLOAD, hgcmMessageAllocSvc);
855
856 if (RT_SUCCESS(rc))
857 {
858 rc = hgcmMsgSend (hMsg);
859
860 if (RT_SUCCESS(rc))
861 {
862 hgcmThreadWait (m_thread);
863 }
864 }
865
866 RTStrFree (m_pszSvcLibrary);
867 m_pszSvcLibrary = NULL;
868
869 RTStrFree (m_pszSvcName);
870 m_pszSvcName = NULL;
871}
872
873int HGCMService::saveClientState(uint32_t u32ClientId, PSSMHANDLE pSSM)
874{
875 LogFlowFunc(("%s\n", m_pszSvcName));
876
877 HGCMMSGHANDLE hMsg;
878 int rc = hgcmMsgAlloc (m_thread, &hMsg, SVC_MSG_SAVESTATE, hgcmMessageAllocSvc);
879
880 if (RT_SUCCESS(rc))
881 {
882 HGCMMsgLoadSaveStateClient *pMsg = (HGCMMsgLoadSaveStateClient *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
883 AssertRelease(pMsg);
884
885 pMsg->u32ClientId = u32ClientId;
886 pMsg->pSSM = pSSM;
887
888 hgcmObjDereference (pMsg);
889
890 rc = hgcmMsgSend (hMsg);
891 }
892
893 LogFlowFunc(("rc = %Rrc\n", rc));
894 return rc;
895}
896
897int HGCMService::loadClientState (uint32_t u32ClientId, PSSMHANDLE pSSM)
898{
899 LogFlowFunc(("%s\n", m_pszSvcName));
900
901 HGCMMSGHANDLE hMsg;
902 int rc = hgcmMsgAlloc (m_thread, &hMsg, SVC_MSG_LOADSTATE, hgcmMessageAllocSvc);
903
904 if (RT_SUCCESS(rc))
905 {
906 HGCMMsgLoadSaveStateClient *pMsg = (HGCMMsgLoadSaveStateClient *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
907
908 AssertRelease(pMsg);
909
910 pMsg->u32ClientId = u32ClientId;
911 pMsg->pSSM = pSSM;
912
913 hgcmObjDereference (pMsg);
914
915 rc = hgcmMsgSend (hMsg);
916 }
917
918 LogFlowFunc(("rc = %Rrc\n", rc));
919 return rc;
920}
921
922
923/** The method creates a service and references it.
924 *
925 * @param pszServiceLibrary The library to be loaded.
926 * @param pszServiceName The name of the service.
927 * @return VBox rc.
928 * @thread main HGCM
929 */
930/* static */ int HGCMService::LoadService (const char *pszServiceLibrary, const char *pszServiceName)
931{
932 LogFlowFunc(("lib %s, name = %s\n", pszServiceLibrary, pszServiceName));
933
934 /* Look at already loaded services to avoid double loading. */
935
936 HGCMService *pSvc;
937 int rc = HGCMService::ResolveService (&pSvc, pszServiceName);
938
939 if (RT_SUCCESS(rc))
940 {
941 /* The service is already loaded. */
942 pSvc->ReleaseService ();
943 rc = VERR_HGCM_SERVICE_EXISTS;
944 }
945 else
946 {
947 /* Create the new service. */
948 pSvc = new HGCMService ();
949
950 if (!pSvc)
951 {
952 rc = VERR_NO_MEMORY;
953 }
954 else
955 {
956 /* Load the library and call the initialization entry point. */
957 rc = pSvc->instanceCreate (pszServiceLibrary, pszServiceName);
958
959 if (RT_SUCCESS(rc))
960 {
961 /* Insert the just created service to list for future references. */
962 pSvc->m_pSvcNext = sm_pSvcListHead;
963 pSvc->m_pSvcPrev = NULL;
964
965 if (sm_pSvcListHead)
966 {
967 sm_pSvcListHead->m_pSvcPrev = pSvc;
968 }
969 else
970 {
971 sm_pSvcListTail = pSvc;
972 }
973
974 sm_pSvcListHead = pSvc;
975
976 sm_cServices++;
977
978 /* Reference the service (for first time) until it is unloaded on HGCM termination. */
979 AssertRelease (pSvc->m_u32RefCnt == 0);
980 pSvc->ReferenceService ();
981
982 LogFlowFunc(("service %p\n", pSvc));
983 }
984 }
985 }
986
987 LogFlowFunc(("rc = %Rrc\n", rc));
988 return rc;
989}
990
991/** The method unloads a service.
992 *
993 * @thread main HGCM
994 */
995void HGCMService::UnloadService (void)
996{
997 LogFlowFunc(("name = %s\n", m_pszSvcName));
998
999 /* Remove the service from the list. */
1000 if (m_pSvcNext)
1001 {
1002 m_pSvcNext->m_pSvcPrev = m_pSvcPrev;
1003 }
1004 else
1005 {
1006 sm_pSvcListTail = m_pSvcPrev;
1007 }
1008
1009 if (m_pSvcPrev)
1010 {
1011 m_pSvcPrev->m_pSvcNext = m_pSvcNext;
1012 }
1013 else
1014 {
1015 sm_pSvcListHead = m_pSvcNext;
1016 }
1017
1018 sm_cServices--;
1019
1020 /* The service must be unloaded only if all clients were disconnected. */
1021 LogFlowFunc(("m_u32RefCnt = %d\n", m_u32RefCnt));
1022 AssertRelease (m_u32RefCnt == 1);
1023
1024 /* Now the service can be released. */
1025 ReleaseService ();
1026}
1027
1028/** The method unloads all services.
1029 *
1030 * @thread main HGCM
1031 */
1032/* static */ void HGCMService::UnloadAll (void)
1033{
1034 while (sm_pSvcListHead)
1035 {
1036 sm_pSvcListHead->UnloadService ();
1037 }
1038}
1039
1040/** The method obtains a referenced pointer to the service with
1041 * specified name. The caller must call ReleaseService when
1042 * the pointer is no longer needed.
1043 *
1044 * @param ppSvc Where to store the pointer to the service.
1045 * @param pszServiceName The name of the service.
1046 * @return VBox rc.
1047 * @thread main HGCM
1048 */
1049/* static */ int HGCMService::ResolveService (HGCMService **ppSvc, const char *pszServiceName)
1050{
1051 LogFlowFunc(("ppSvc = %p name = %s\n",
1052 ppSvc, pszServiceName));
1053
1054 if (!ppSvc || !pszServiceName)
1055 {
1056 return VERR_INVALID_PARAMETER;
1057 }
1058
1059 HGCMService *pSvc = sm_pSvcListHead;
1060
1061 while (pSvc)
1062 {
1063 if (strcmp (pSvc->m_pszSvcName, pszServiceName) == 0)
1064 {
1065 break;
1066 }
1067
1068 pSvc = pSvc->m_pSvcNext;
1069 }
1070
1071 LogFlowFunc(("lookup in the list is %p\n", pSvc));
1072
1073 if (pSvc == NULL)
1074 {
1075 *ppSvc = NULL;
1076 return VERR_HGCM_SERVICE_NOT_FOUND;
1077 }
1078
1079 pSvc->ReferenceService ();
1080
1081 *ppSvc = pSvc;
1082
1083 return VINF_SUCCESS;
1084}
1085
1086/** The method increases reference counter.
1087 *
1088 * @thread main HGCM
1089 */
1090void HGCMService::ReferenceService (void)
1091{
1092 ASMAtomicIncU32 (&m_u32RefCnt);
1093 LogFlowFunc(("[%s] m_u32RefCnt = %d\n", m_pszSvcName, m_u32RefCnt));
1094}
1095
1096/** The method dereferences a service and deletes it when no more refs.
1097 *
1098 * @thread main HGCM
1099 */
1100void HGCMService::ReleaseService (void)
1101{
1102 LogFlowFunc(("m_u32RefCnt = %d\n", m_u32RefCnt));
1103 uint32_t u32RefCnt = ASMAtomicDecU32 (&m_u32RefCnt);
1104 AssertRelease(u32RefCnt != ~0U);
1105
1106 LogFlowFunc(("u32RefCnt = %d, name %s\n", u32RefCnt, m_pszSvcName));
1107
1108 if (u32RefCnt == 0)
1109 {
1110 instanceDestroy ();
1111 delete this;
1112 }
1113}
1114
1115/** The method is called when the VM is being reset or terminated
1116 * and disconnects all clients from all services.
1117 *
1118 * @thread main HGCM
1119 */
1120/* static */ void HGCMService::Reset (void)
1121{
1122 g_fResetting = true;
1123
1124 HGCMService *pSvc = sm_pSvcListHead;
1125
1126 while (pSvc)
1127 {
1128 while (pSvc->m_cClients && pSvc->m_paClientIds)
1129 {
1130 LogFlowFunc(("handle %d\n", pSvc->m_paClientIds[0]));
1131 pSvc->DisconnectClient (pSvc->m_paClientIds[0], false);
1132 }
1133
1134#ifdef VBOX_WITH_CRHGSMI
1135 /* @todo: could this actually happen that the service is destroyed on ReleaseService? */
1136 HGCMService *pNextSvc = pSvc->m_pSvcNext;
1137 while (pSvc->m_cHandleAcquires)
1138 {
1139 pSvc->HandleReleased ();
1140 pSvc->ReleaseService ();
1141 }
1142 pSvc = pNextSvc;
1143#else
1144 pSvc = pSvc->m_pSvcNext;
1145#endif
1146 }
1147
1148 g_fResetting = false;
1149}
1150
1151/** The method saves the HGCM state.
1152 *
1153 * @param pSSM The saved state context.
1154 * @return VBox rc.
1155 * @thread main HGCM
1156 */
1157/* static */ int HGCMService::SaveState (PSSMHANDLE pSSM)
1158{
1159 /* Save the current handle count and restore afterwards to avoid client id conflicts. */
1160 int rc = SSMR3PutU32(pSSM, hgcmObjQueryHandleCount());
1161 AssertRCReturn(rc, rc);
1162
1163 LogFlowFunc(("%d services to be saved:\n", sm_cServices));
1164
1165 /* Save number of services. */
1166 rc = SSMR3PutU32(pSSM, sm_cServices);
1167 AssertRCReturn(rc, rc);
1168
1169 /* Save every service. */
1170 HGCMService *pSvc = sm_pSvcListHead;
1171
1172 while (pSvc)
1173 {
1174 LogFlowFunc(("Saving service [%s]\n", pSvc->m_pszSvcName));
1175
1176 /* Save the length of the service name. */
1177 rc = SSMR3PutU32(pSSM, (uint32_t) strlen(pSvc->m_pszSvcName) + 1);
1178 AssertRCReturn(rc, rc);
1179
1180 /* Save the name of the service. */
1181 rc = SSMR3PutStrZ(pSSM, pSvc->m_pszSvcName);
1182 AssertRCReturn(rc, rc);
1183
1184 /* Save the number of clients. */
1185 rc = SSMR3PutU32(pSSM, pSvc->m_cClients);
1186 AssertRCReturn(rc, rc);
1187
1188 /* Call the service for every client. Normally a service must not have
1189 * a global state to be saved: only per client info is relevant.
1190 * The global state of a service is configured during VM startup.
1191 */
1192 int i;
1193
1194 for (i = 0; i < pSvc->m_cClients; i++)
1195 {
1196 uint32_t u32ClientId = pSvc->m_paClientIds[i];
1197
1198 Log(("client id 0x%08X\n", u32ClientId));
1199
1200 /* Save the client id. */
1201 rc = SSMR3PutU32(pSSM, u32ClientId);
1202 AssertRCReturn(rc, rc);
1203
1204 /* Call the service, so the operation is executed by the service thread. */
1205 rc = pSvc->saveClientState (u32ClientId, pSSM);
1206 AssertRCReturn(rc, rc);
1207 }
1208
1209 pSvc = pSvc->m_pSvcNext;
1210 }
1211
1212 return VINF_SUCCESS;
1213}
1214
1215/** The method loads saved HGCM state.
1216 *
1217 * @param pSSM The saved state context.
1218 * @return VBox rc.
1219 * @thread main HGCM
1220 */
1221/* static */ int HGCMService::LoadState (PSSMHANDLE pSSM)
1222{
1223 /* Restore handle count to avoid client id conflicts. */
1224 uint32_t u32;
1225
1226 int rc = SSMR3GetU32(pSSM, &u32);
1227 AssertRCReturn(rc, rc);
1228
1229 hgcmObjSetHandleCount(u32);
1230
1231 /* Get the number of services. */
1232 uint32_t cServices;
1233
1234 rc = SSMR3GetU32(pSSM, &cServices);
1235 AssertRCReturn(rc, rc);
1236
1237 LogFlowFunc(("%d services to be restored:\n", cServices));
1238
1239 while (cServices--)
1240 {
1241 /* Get the length of the service name. */
1242 rc = SSMR3GetU32(pSSM, &u32);
1243 AssertRCReturn(rc, rc);
1244 AssertReturn(u32 <= VBOX_HGCM_SVC_NAME_MAX_BYTES, VERR_SSM_UNEXPECTED_DATA);
1245
1246 char *pszServiceName = (char *)alloca (u32);
1247
1248 /* Get the service name. */
1249 rc = SSMR3GetStrZ(pSSM, pszServiceName, u32);
1250 AssertRCReturn(rc, rc);
1251
1252 LogRel(("HGCM: restoring [%s]\n", pszServiceName));
1253
1254 /* Resolve the service instance. */
1255 HGCMService *pSvc;
1256 rc = ResolveService (&pSvc, pszServiceName);
1257 AssertLogRelMsgReturn(pSvc, ("rc=%Rrc, %s\n", rc, pszServiceName), VERR_SSM_UNEXPECTED_DATA);
1258
1259 /* Get the number of clients. */
1260 uint32_t cClients;
1261 rc = SSMR3GetU32(pSSM, &cClients);
1262 if (RT_FAILURE(rc))
1263 {
1264 pSvc->ReleaseService ();
1265 AssertFailed();
1266 return rc;
1267 }
1268
1269 while (cClients--)
1270 {
1271 /* Get the client id. */
1272 uint32_t u32ClientId;
1273 rc = SSMR3GetU32(pSSM, &u32ClientId);
1274 if (RT_FAILURE(rc))
1275 {
1276 pSvc->ReleaseService ();
1277 AssertFailed();
1278 return rc;
1279 }
1280
1281 /* Connect the client. */
1282 rc = pSvc->CreateAndConnectClient (NULL, u32ClientId);
1283 if (RT_FAILURE(rc))
1284 {
1285 pSvc->ReleaseService ();
1286 AssertLogRelMsgFailed(("rc=%Rrc %s\n", rc, pszServiceName));
1287 return rc;
1288 }
1289
1290 /* Call the service, so the operation is executed by the service thread. */
1291 rc = pSvc->loadClientState (u32ClientId, pSSM);
1292 if (RT_FAILURE(rc))
1293 {
1294 pSvc->ReleaseService ();
1295 AssertLogRelMsgFailed(("rc=%Rrc %s\n", rc, pszServiceName));
1296 return rc;
1297 }
1298 }
1299
1300 pSvc->ReleaseService ();
1301 }
1302
1303 return VINF_SUCCESS;
1304}
1305
1306/* Create a new client instance and connect it to the service.
1307 *
1308 * @param pu32ClientIdOut If not NULL, then the method must generate a new handle for the client.
1309 * If NULL, use the given 'u32ClientIdIn' handle.
1310 * @param u32ClientIdIn The handle for the client, when 'pu32ClientIdOut' is NULL.
1311 * @return VBox rc.
1312 */
1313int HGCMService::CreateAndConnectClient (uint32_t *pu32ClientIdOut, uint32_t u32ClientIdIn)
1314{
1315 LogFlowFunc(("pu32ClientIdOut = %p, u32ClientIdIn = %d\n", pu32ClientIdOut, u32ClientIdIn));
1316
1317 /* Allocate a client information structure. */
1318 HGCMClient *pClient = new HGCMClient ();
1319
1320 if (!pClient)
1321 {
1322 LogWarningFunc(("Could not allocate HGCMClient!!!\n"));
1323 return VERR_NO_MEMORY;
1324 }
1325
1326 uint32_t handle;
1327
1328 if (pu32ClientIdOut != NULL)
1329 {
1330 handle = hgcmObjGenerateHandle (pClient);
1331 }
1332 else
1333 {
1334 handle = hgcmObjAssignHandle (pClient, u32ClientIdIn);
1335 }
1336
1337 LogFlowFunc(("client id = %d\n", handle));
1338
1339 AssertRelease(handle);
1340
1341 /* Initialize the HGCM part of the client. */
1342 int rc = pClient->Init (this);
1343
1344 if (RT_SUCCESS(rc))
1345 {
1346 /* Call the service. */
1347 HGCMMSGHANDLE hMsg;
1348
1349 rc = hgcmMsgAlloc (m_thread, &hMsg, SVC_MSG_CONNECT, hgcmMessageAllocSvc);
1350
1351 if (RT_SUCCESS(rc))
1352 {
1353 HGCMMsgSvcConnect *pMsg = (HGCMMsgSvcConnect *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
1354 AssertRelease(pMsg);
1355
1356 pMsg->u32ClientId = handle;
1357
1358 hgcmObjDereference (pMsg);
1359
1360 rc = hgcmMsgSend (hMsg);
1361
1362 if (RT_SUCCESS(rc))
1363 {
1364 /* Add the client Id to the array. */
1365 if (m_cClients == m_cClientsAllocated)
1366 {
1367 m_paClientIds = (uint32_t *)RTMemRealloc (m_paClientIds, (m_cClientsAllocated + 64) * sizeof (m_paClientIds[0]));
1368 Assert(m_paClientIds);
1369 m_cClientsAllocated += 64;
1370 }
1371
1372 m_paClientIds[m_cClients] = handle;
1373 m_cClients++;
1374 }
1375 }
1376 }
1377
1378 if (RT_FAILURE(rc))
1379 {
1380 hgcmObjDeleteHandle (handle);
1381 }
1382 else
1383 {
1384 if (pu32ClientIdOut != NULL)
1385 {
1386 *pu32ClientIdOut = handle;
1387 }
1388
1389 ReferenceService ();
1390 }
1391
1392 LogFlowFunc(("rc = %Rrc\n", rc));
1393 return rc;
1394}
1395
1396/* Disconnect the client from the service and delete the client handle.
1397 *
1398 * @param u32ClientId The handle of the client.
1399 * @return VBox rc.
1400 */
1401int HGCMService::DisconnectClient (uint32_t u32ClientId, bool fFromService)
1402{
1403 int rc = VINF_SUCCESS;
1404
1405 LogFlowFunc(("client id = %d, fFromService = %d\n", u32ClientId, fFromService));
1406
1407 if (!fFromService)
1408 {
1409 /* Call the service. */
1410 HGCMMSGHANDLE hMsg;
1411
1412 rc = hgcmMsgAlloc (m_thread, &hMsg, SVC_MSG_DISCONNECT, hgcmMessageAllocSvc);
1413
1414 if (RT_SUCCESS(rc))
1415 {
1416 HGCMMsgSvcDisconnect *pMsg = (HGCMMsgSvcDisconnect *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
1417 AssertRelease(pMsg);
1418
1419 pMsg->u32ClientId = u32ClientId;
1420
1421 hgcmObjDereference (pMsg);
1422
1423 rc = hgcmMsgSend (hMsg);
1424 }
1425 else
1426 {
1427 LogRel(("(%d, %d) [%s] hgcmMsgAlloc(%p, SVC_MSG_DISCONNECT) failed %Rrc\n",
1428 u32ClientId, fFromService, RT_VALID_PTR(m_pszSvcName)? m_pszSvcName: "", m_thread, rc));
1429 }
1430 }
1431
1432 /* Remove the client id from the array in any case, rc does not matter. */
1433 int i;
1434
1435 for (i = 0; i < m_cClients; i++)
1436 {
1437 if (m_paClientIds[i] == u32ClientId)
1438 {
1439 m_cClients--;
1440
1441 if (m_cClients > i)
1442 {
1443 memmove (&m_paClientIds[i], &m_paClientIds[i + 1], sizeof (m_paClientIds[0]) * (m_cClients - i));
1444 }
1445
1446 /* Delete the client handle. */
1447 hgcmObjDeleteHandle (u32ClientId);
1448
1449 /* The service must be released. */
1450 ReleaseService ();
1451
1452 break;
1453 }
1454 }
1455
1456 LogFlowFunc(("rc = %Rrc\n", rc));
1457 return rc;
1458}
1459
1460int HGCMService::RegisterExtension (HGCMSVCEXTHANDLE handle,
1461 PFNHGCMSVCEXT pfnExtension,
1462 void *pvExtension)
1463{
1464 LogFlowFunc(("%s\n", handle->pszServiceName));
1465
1466 /* Forward the message to the service thread. */
1467 HGCMMSGHANDLE hMsg = 0;
1468 int rc = hgcmMsgAlloc (m_thread, &hMsg, SVC_MSG_REGEXT, hgcmMessageAllocSvc);
1469
1470 if (RT_SUCCESS(rc))
1471 {
1472 HGCMMsgSvcRegisterExtension *pMsg = (HGCMMsgSvcRegisterExtension *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
1473 AssertRelease(pMsg);
1474
1475 pMsg->handle = handle;
1476 pMsg->pfnExtension = pfnExtension;
1477 pMsg->pvExtension = pvExtension;
1478
1479 hgcmObjDereference (pMsg);
1480
1481 rc = hgcmMsgSend (hMsg);
1482 }
1483
1484 LogFlowFunc(("rc = %Rrc\n", rc));
1485 return rc;
1486}
1487
1488void HGCMService::UnregisterExtension (HGCMSVCEXTHANDLE handle)
1489{
1490 /* Forward the message to the service thread. */
1491 HGCMMSGHANDLE hMsg = 0;
1492 int rc = hgcmMsgAlloc (m_thread, &hMsg, SVC_MSG_UNREGEXT, hgcmMessageAllocSvc);
1493
1494 if (RT_SUCCESS(rc))
1495 {
1496 HGCMMsgSvcUnregisterExtension *pMsg = (HGCMMsgSvcUnregisterExtension *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
1497 AssertRelease(pMsg);
1498
1499 pMsg->handle = handle;
1500
1501 hgcmObjDereference (pMsg);
1502
1503 rc = hgcmMsgSend (hMsg);
1504 }
1505
1506 LogFlowFunc(("rc = %Rrc\n", rc));
1507}
1508
1509/* Perform a guest call to the service.
1510 *
1511 * @param pHGCMPort The port to be used for completion confirmation.
1512 * @param pCmd The VBox HGCM context.
1513 * @param u32ClientId The client handle to be disconnected and deleted.
1514 * @param u32Function The function number.
1515 * @param cParms Number of parameters.
1516 * @param paParms Pointer to array of parameters.
1517 * @return VBox rc.
1518 */
1519int HGCMService::GuestCall (PPDMIHGCMPORT pHGCMPort, PVBOXHGCMCMD pCmd, uint32_t u32ClientId, uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
1520{
1521 HGCMMSGHANDLE hMsg = 0;
1522
1523 LogFlow(("MAIN::HGCMService::Call\n"));
1524
1525 int rc = hgcmMsgAlloc (m_thread, &hMsg, SVC_MSG_GUESTCALL, hgcmMessageAllocSvc);
1526
1527 if (RT_SUCCESS(rc))
1528 {
1529 HGCMMsgCall *pMsg = (HGCMMsgCall *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
1530
1531 AssertRelease(pMsg);
1532
1533 pMsg->pCmd = pCmd;
1534 pMsg->pHGCMPort = pHGCMPort;
1535
1536 pMsg->u32ClientId = u32ClientId;
1537 pMsg->u32Function = u32Function;
1538 pMsg->cParms = cParms;
1539 pMsg->paParms = paParms;
1540
1541 hgcmObjDereference (pMsg);
1542
1543 rc = hgcmMsgPost (hMsg, hgcmMsgCompletionCallback);
1544 }
1545 else
1546 {
1547 Log(("MAIN::HGCMService::Call: Message allocation failed: %Rrc\n", rc));
1548 }
1549
1550 LogFlowFunc(("rc = %Rrc\n", rc));
1551 return rc;
1552}
1553
1554/* Perform a host call the service.
1555 *
1556 * @param u32Function The function number.
1557 * @param cParms Number of parameters.
1558 * @param paParms Pointer to array of parameters.
1559 * @return VBox rc.
1560 */
1561int HGCMService::HostCall (uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM *paParms)
1562{
1563 LogFlowFunc(("%s u32Function = %d, cParms = %d, paParms = %p\n",
1564 m_pszSvcName, u32Function, cParms, paParms));
1565
1566 HGCMMSGHANDLE hMsg = 0;
1567 int rc = hgcmMsgAlloc (m_thread, &hMsg, SVC_MSG_HOSTCALL, hgcmMessageAllocSvc);
1568
1569 if (RT_SUCCESS(rc))
1570 {
1571 HGCMMsgHostCallSvc *pMsg = (HGCMMsgHostCallSvc *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
1572 AssertRelease(pMsg);
1573
1574 pMsg->u32Function = u32Function;
1575 pMsg->cParms = cParms;
1576 pMsg->paParms = paParms;
1577
1578 hgcmObjDereference (pMsg);
1579
1580 rc = hgcmMsgSend (hMsg);
1581 }
1582
1583 LogFlowFunc(("rc = %Rrc\n", rc));
1584 return rc;
1585}
1586
1587#ifdef VBOX_WITH_CRHGSMI
1588static DECLCALLBACK(void) hgcmMsgFastCallCompletionCallback (int32_t result, HGCMMsgCore *pMsgCore)
1589{
1590 /* Call the VMMDev port interface to issue IRQ notification. */
1591 LogFlow(("MAIN::hgcmMsgFastCallCompletionCallback: message %p\n", pMsgCore));
1592
1593 HGCMMsgHostFastCallAsyncSvc *pMsg = (HGCMMsgHostFastCallAsyncSvc *)pMsgCore;
1594 if (pMsg->pfnCompletion)
1595 {
1596 pMsg->pfnCompletion (result, pMsg->u32Function, &pMsg->Param, pMsg->pvCompletion);
1597 }
1598}
1599
1600int HGCMService::HandleAcquired()
1601{
1602 ++m_cHandleAcquires;
1603 return VINF_SUCCESS;
1604}
1605
1606int HGCMService::HandleReleased()
1607{
1608 Assert(m_cHandleAcquires);
1609 if (m_cHandleAcquires)
1610 {
1611 --m_cHandleAcquires;
1612 return VINF_SUCCESS;
1613 }
1614 return VERR_INVALID_STATE;
1615}
1616
1617int HGCMService::HostFastCallAsync (uint32_t u32Function, VBOXHGCMSVCPARM *pParm, PHGCMHOSTFASTCALLCB pfnCompletion, void *pvCompletion)
1618{
1619 LogFlowFunc(("%s u32Function = %d, pParm = %p\n",
1620 m_pszSvcName, u32Function, pParm));
1621
1622 HGCMMSGHANDLE hMsg = 0;
1623 int rc = hgcmMsgAlloc (m_thread, &hMsg, SVC_MSG_HOSTFASTCALLASYNC, hgcmMessageAllocSvc);
1624
1625 if (RT_SUCCESS(rc))
1626 {
1627 HGCMMsgHostFastCallAsyncSvc *pMsg = (HGCMMsgHostFastCallAsyncSvc *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
1628 AssertRelease(pMsg);
1629
1630 pMsg->u32Function = u32Function;
1631 pMsg->Param = *pParm;
1632 pMsg->pfnCompletion = pfnCompletion;
1633 pMsg->pvCompletion = pvCompletion;
1634
1635 hgcmObjDereference (pMsg);
1636
1637 rc = hgcmMsgPost(hMsg, hgcmMsgFastCallCompletionCallback);
1638 }
1639
1640 LogFlowFunc(("rc = %Rrc\n", rc));
1641 return rc;
1642}
1643#endif
1644
1645/*
1646 * Main HGCM thread that manages services.
1647 */
1648
1649/* Messages processed by the main HGCM thread. */
1650#define HGCM_MSG_CONNECT (10) /* Connect a client to a service. */
1651#define HGCM_MSG_DISCONNECT (11) /* Disconnect the specified client id. */
1652#define HGCM_MSG_LOAD (12) /* Load the service. */
1653#define HGCM_MSG_HOSTCALL (13) /* Call the service. */
1654#define HGCM_MSG_LOADSTATE (14) /* Load saved state for the specified service. */
1655#define HGCM_MSG_SAVESTATE (15) /* Save state for the specified service. */
1656#define HGCM_MSG_RESET (16) /* Disconnect all clients from the specified service. */
1657#define HGCM_MSG_QUIT (17) /* Unload all services and terminate the thread. */
1658#define HGCM_MSG_REGEXT (18) /* Register a service extension. */
1659#define HGCM_MSG_UNREGEXT (19) /* Unregister a service extension. */
1660#ifdef VBOX_WITH_CRHGSMI
1661# define HGCM_MSG_SVCAQUIRE (30) /* Acquire a service handle (for fast host calls) */
1662# define HGCM_MSG_SVCRELEASE (31) /* Release a service */
1663#endif
1664
1665class HGCMMsgMainConnect: public HGCMMsgHeader
1666{
1667 public:
1668 /* Service name. */
1669 const char *pszServiceName;
1670 /* Where to store the client handle. */
1671 uint32_t *pu32ClientId;
1672};
1673
1674class HGCMMsgMainDisconnect: public HGCMMsgHeader
1675{
1676 public:
1677 /* Handle of the client to be disconnected. */
1678 uint32_t u32ClientId;
1679};
1680
1681class HGCMMsgMainLoad: public HGCMMsgCore
1682{
1683 public:
1684 /* Name of the library to be loaded. */
1685 const char *pszServiceLibrary;
1686 /* Name to be assigned to the service. */
1687 const char *pszServiceName;
1688};
1689
1690class HGCMMsgMainHostCall: public HGCMMsgCore
1691{
1692 public:
1693 /* Which service to call. */
1694 const char *pszServiceName;
1695 /* Function number. */
1696 uint32_t u32Function;
1697 /* Number of the function parameters. */
1698 uint32_t cParms;
1699 /* Pointer to array of the function parameters. */
1700 VBOXHGCMSVCPARM *paParms;
1701};
1702
1703class HGCMMsgMainLoadSaveState: public HGCMMsgCore
1704{
1705 public:
1706 /* SSM context. */
1707 PSSMHANDLE pSSM;
1708};
1709
1710class HGCMMsgMainReset: public HGCMMsgCore
1711{
1712};
1713
1714class HGCMMsgMainQuit: public HGCMMsgCore
1715{
1716};
1717
1718class HGCMMsgMainRegisterExtension: public HGCMMsgCore
1719{
1720 public:
1721 /* Returned handle to be used in HGCMMsgMainUnregisterExtension. */
1722 HGCMSVCEXTHANDLE *pHandle;
1723 /* Name of the service. */
1724 const char *pszServiceName;
1725 /* The extension entry point. */
1726 PFNHGCMSVCEXT pfnExtension;
1727 /* The extension pointer. */
1728 void *pvExtension;
1729};
1730
1731class HGCMMsgMainUnregisterExtension: public HGCMMsgCore
1732{
1733 public:
1734 /* Handle of the registered extension. */
1735 HGCMSVCEXTHANDLE handle;
1736};
1737
1738#ifdef VBOX_WITH_CRHGSMI
1739class HGCMMsgMainSvcAcquire: public HGCMMsgCore
1740{
1741 public:
1742 /* Which service to call. */
1743 const char *pszServiceName;
1744 /* Returned service. */
1745 HGCMService *pService;
1746};
1747
1748class HGCMMsgMainSvcRelease: public HGCMMsgCore
1749{
1750 public:
1751 /* Svc . */
1752 HGCMService *pService;
1753};
1754#endif
1755
1756
1757static HGCMMsgCore *hgcmMainMessageAlloc (uint32_t u32MsgId)
1758{
1759 switch (u32MsgId)
1760 {
1761 case HGCM_MSG_CONNECT: return new HGCMMsgMainConnect ();
1762 case HGCM_MSG_DISCONNECT: return new HGCMMsgMainDisconnect ();
1763 case HGCM_MSG_LOAD: return new HGCMMsgMainLoad ();
1764 case HGCM_MSG_HOSTCALL: return new HGCMMsgMainHostCall ();
1765 case HGCM_MSG_LOADSTATE:
1766 case HGCM_MSG_SAVESTATE: return new HGCMMsgMainLoadSaveState ();
1767 case HGCM_MSG_RESET: return new HGCMMsgMainReset ();
1768 case HGCM_MSG_QUIT: return new HGCMMsgMainQuit ();
1769 case HGCM_MSG_REGEXT: return new HGCMMsgMainRegisterExtension ();
1770 case HGCM_MSG_UNREGEXT: return new HGCMMsgMainUnregisterExtension ();
1771#ifdef VBOX_WITH_CRHGSMI
1772 case HGCM_MSG_SVCAQUIRE: return new HGCMMsgMainSvcAcquire();
1773 case HGCM_MSG_SVCRELEASE: return new HGCMMsgMainSvcRelease();
1774#endif
1775
1776 default:
1777 AssertReleaseMsgFailed(("Msg id = %08X\n", u32MsgId));
1778 }
1779
1780 return NULL;
1781}
1782
1783
1784/* The main HGCM thread handler. */
1785static DECLCALLBACK(void) hgcmThread (HGCMTHREADHANDLE ThreadHandle, void *pvUser)
1786{
1787 LogFlowFunc(("ThreadHandle = %p, pvUser = %p\n",
1788 ThreadHandle, pvUser));
1789
1790 NOREF(pvUser);
1791
1792 bool fQuit = false;
1793
1794 while (!fQuit)
1795 {
1796 HGCMMsgCore *pMsgCore;
1797 int rc = hgcmMsgGet (ThreadHandle, &pMsgCore);
1798
1799 if (RT_FAILURE(rc))
1800 {
1801 /* The error means some serious unrecoverable problem in the hgcmMsg/hgcmThread layer. */
1802 AssertMsgFailed (("%Rrc\n", rc));
1803 break;
1804 }
1805
1806 uint32_t u32MsgId = pMsgCore->MsgId ();
1807
1808 switch (u32MsgId)
1809 {
1810 case HGCM_MSG_CONNECT:
1811 {
1812 HGCMMsgMainConnect *pMsg = (HGCMMsgMainConnect *)pMsgCore;
1813
1814 LogFlowFunc(("HGCM_MSG_CONNECT pszServiceName %s, pu32ClientId %p\n",
1815 pMsg->pszServiceName, pMsg->pu32ClientId));
1816
1817 /* Resolve the service name to the pointer to service instance.
1818 */
1819 HGCMService *pService;
1820 rc = HGCMService::ResolveService (&pService, pMsg->pszServiceName);
1821
1822 if (RT_SUCCESS(rc))
1823 {
1824 /* Call the service instance method. */
1825 rc = pService->CreateAndConnectClient (pMsg->pu32ClientId, 0);
1826
1827 /* Release the service after resolve. */
1828 pService->ReleaseService ();
1829 }
1830 } break;
1831
1832 case HGCM_MSG_DISCONNECT:
1833 {
1834 HGCMMsgMainDisconnect *pMsg = (HGCMMsgMainDisconnect *)pMsgCore;
1835
1836 LogFlowFunc(("HGCM_MSG_DISCONNECT u32ClientId = %d\n",
1837 pMsg->u32ClientId));
1838
1839 HGCMClient *pClient = (HGCMClient *)hgcmObjReference (pMsg->u32ClientId, HGCMOBJ_CLIENT);
1840
1841 if (!pClient)
1842 {
1843 rc = VERR_HGCM_INVALID_CLIENT_ID;
1844 break;
1845 }
1846
1847 /* The service the client belongs to. */
1848 HGCMService *pService = pClient->pService;
1849
1850 /* Call the service instance to disconnect the client. */
1851 rc = pService->DisconnectClient (pMsg->u32ClientId, false);
1852
1853 hgcmObjDereference (pClient);
1854 } break;
1855
1856 case HGCM_MSG_LOAD:
1857 {
1858 HGCMMsgMainLoad *pMsg = (HGCMMsgMainLoad *)pMsgCore;
1859
1860 LogFlowFunc(("HGCM_MSG_LOAD pszServiceName = %s, pMsg->pszServiceLibrary = %s\n",
1861 pMsg->pszServiceName, pMsg->pszServiceLibrary));
1862
1863 rc = HGCMService::LoadService (pMsg->pszServiceLibrary, pMsg->pszServiceName);
1864 } break;
1865
1866 case HGCM_MSG_HOSTCALL:
1867 {
1868 HGCMMsgMainHostCall *pMsg = (HGCMMsgMainHostCall *)pMsgCore;
1869
1870 LogFlowFunc(("HGCM_MSG_HOSTCALL pszServiceName %s, u32Function %d, cParms %d, paParms %p\n",
1871 pMsg->pszServiceName, pMsg->u32Function, pMsg->cParms, pMsg->paParms));
1872
1873 /* Resolve the service name to the pointer to service instance. */
1874 HGCMService *pService;
1875 rc = HGCMService::ResolveService (&pService, pMsg->pszServiceName);
1876
1877 if (RT_SUCCESS(rc))
1878 {
1879 rc = pService->HostCall (pMsg->u32Function, pMsg->cParms, pMsg->paParms);
1880
1881 pService->ReleaseService ();
1882 }
1883 } break;
1884
1885#ifdef VBOX_WITH_CRHGSMI
1886 case HGCM_MSG_SVCAQUIRE:
1887 {
1888 HGCMMsgMainSvcAcquire *pMsg = (HGCMMsgMainSvcAcquire *)pMsgCore;
1889
1890 LogFlowFunc(("HGCM_MSG_SVCAQUIRE pszServiceName %s\n", pMsg->pszServiceName));
1891
1892 /* Resolve the service name to the pointer to service instance. */
1893 HGCMService *pService;
1894 rc = HGCMService::ResolveService (&pService, pMsg->pszServiceName);
1895 if (RT_SUCCESS(rc))
1896 {
1897 rc = pService->HandleAcquired ();
1898 if (RT_SUCCESS(rc))
1899 {
1900 pMsg->pService = pService;
1901 }
1902 else
1903 {
1904 pService->ReleaseService ();
1905 }
1906 }
1907 } break;
1908
1909 case HGCM_MSG_SVCRELEASE:
1910 {
1911 HGCMMsgMainSvcRelease *pMsg = (HGCMMsgMainSvcRelease *)pMsgCore;
1912
1913 LogFlowFunc(("HGCM_MSG_SVCARELEASE pService %p\n", pMsg->pService));
1914
1915 /* Resolve the service name to the pointer to service instance. */
1916
1917 rc = pMsg->pService->HandleReleased ();
1918 if (RT_SUCCESS(rc))
1919 {
1920 pMsg->pService->ReleaseService ();
1921 }
1922 } break;
1923#endif
1924
1925 case HGCM_MSG_RESET:
1926 {
1927 LogFlowFunc(("HGCM_MSG_RESET\n"));
1928
1929 HGCMService::Reset ();
1930 } break;
1931
1932 case HGCM_MSG_LOADSTATE:
1933 {
1934 HGCMMsgMainLoadSaveState *pMsg = (HGCMMsgMainLoadSaveState *)pMsgCore;
1935
1936 LogFlowFunc(("HGCM_MSG_LOADSTATE\n"));
1937
1938 rc = HGCMService::LoadState (pMsg->pSSM);
1939 } break;
1940
1941 case HGCM_MSG_SAVESTATE:
1942 {
1943 HGCMMsgMainLoadSaveState *pMsg = (HGCMMsgMainLoadSaveState *)pMsgCore;
1944
1945 LogFlowFunc(("HGCM_MSG_SAVESTATE\n"));
1946
1947 rc = HGCMService::SaveState (pMsg->pSSM);
1948 } break;
1949
1950 case HGCM_MSG_QUIT:
1951 {
1952 LogFlowFunc(("HGCM_MSG_QUIT\n"));
1953
1954 HGCMService::UnloadAll ();
1955
1956 fQuit = true;
1957 } break;
1958
1959 case HGCM_MSG_REGEXT:
1960 {
1961 HGCMMsgMainRegisterExtension *pMsg = (HGCMMsgMainRegisterExtension *)pMsgCore;
1962
1963 LogFlowFunc(("HGCM_MSG_REGEXT\n"));
1964
1965 /* Allocate the handle data. */
1966 HGCMSVCEXTHANDLE handle = (HGCMSVCEXTHANDLE)RTMemAllocZ (sizeof (struct _HGCMSVCEXTHANDLEDATA)
1967 + strlen (pMsg->pszServiceName)
1968 + sizeof (char));
1969
1970 if (handle == NULL)
1971 {
1972 rc = VERR_NO_MEMORY;
1973 }
1974 else
1975 {
1976 handle->pszServiceName = (char *)((uint8_t *)handle + sizeof (struct _HGCMSVCEXTHANDLEDATA));
1977 strcpy (handle->pszServiceName, pMsg->pszServiceName);
1978
1979 HGCMService *pService;
1980 rc = HGCMService::ResolveService (&pService, handle->pszServiceName);
1981
1982 if (RT_SUCCESS(rc))
1983 {
1984 pService->RegisterExtension (handle, pMsg->pfnExtension, pMsg->pvExtension);
1985
1986 pService->ReleaseService ();
1987 }
1988
1989 if (RT_FAILURE(rc))
1990 {
1991 RTMemFree (handle);
1992 }
1993 else
1994 {
1995 *pMsg->pHandle = handle;
1996 }
1997 }
1998 } break;
1999
2000 case HGCM_MSG_UNREGEXT:
2001 {
2002 HGCMMsgMainUnregisterExtension *pMsg = (HGCMMsgMainUnregisterExtension *)pMsgCore;
2003
2004 LogFlowFunc(("HGCM_MSG_UNREGEXT\n"));
2005
2006 HGCMService *pService;
2007 rc = HGCMService::ResolveService (&pService, pMsg->handle->pszServiceName);
2008
2009 if (RT_SUCCESS(rc))
2010 {
2011 pService->UnregisterExtension (pMsg->handle);
2012
2013 pService->ReleaseService ();
2014 }
2015
2016 RTMemFree (pMsg->handle);
2017 } break;
2018
2019 default:
2020 {
2021 AssertMsgFailed(("hgcmThread: Unsupported message number %08X!!!\n", u32MsgId));
2022 rc = VERR_NOT_SUPPORTED;
2023 } break;
2024 }
2025
2026 /* Complete the message processing. */
2027 hgcmMsgComplete (pMsgCore, rc);
2028
2029 LogFlowFunc(("message processed %Rrc\n", rc));
2030 }
2031}
2032
2033
2034/*
2035 * The HGCM API.
2036 */
2037
2038/* The main hgcm thread. */
2039static HGCMTHREADHANDLE g_hgcmThread = 0;
2040
2041/*
2042 * Public HGCM functions.
2043 *
2044 * hgcmGuest* - called as a result of the guest HGCM requests.
2045 * hgcmHost* - called by the host.
2046 */
2047
2048/* Load a HGCM service from the specified library.
2049 * Assign the specified name to the service.
2050 *
2051 * @param pszServiceLibrary The library to be loaded.
2052 * @param pszServiceName The name to be assigned to the service.
2053 * @return VBox rc.
2054 */
2055int HGCMHostLoad (const char *pszServiceLibrary,
2056 const char *pszServiceName)
2057{
2058 LogFlowFunc(("lib = %s, name = %s\n", pszServiceLibrary, pszServiceName));
2059
2060 if (!pszServiceLibrary || !pszServiceName)
2061 {
2062 return VERR_INVALID_PARAMETER;
2063 }
2064
2065 /* Forward the request to the main hgcm thread. */
2066 HGCMMSGHANDLE hMsg = 0;
2067
2068 int rc = hgcmMsgAlloc (g_hgcmThread, &hMsg, HGCM_MSG_LOAD, hgcmMainMessageAlloc);
2069
2070 if (RT_SUCCESS(rc))
2071 {
2072 /* Initialize the message. Since the message is synchronous, use the supplied pointers. */
2073 HGCMMsgMainLoad *pMsg = (HGCMMsgMainLoad *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
2074 AssertRelease(pMsg);
2075
2076 pMsg->pszServiceLibrary = pszServiceLibrary;
2077 pMsg->pszServiceName = pszServiceName;
2078
2079 hgcmObjDereference (pMsg);
2080
2081 rc = hgcmMsgSend (hMsg);
2082 }
2083
2084 LogFlowFunc(("rc = %Rrc\n", rc));
2085 return rc;
2086}
2087
2088/* Register a HGCM service extension.
2089 *
2090 * @param pHandle Returned handle for the registered extension.
2091 * @param pszServiceName The name of the service.
2092 * @param pfnExtension The extension entry point (callback).
2093 * @param pvExtension The extension pointer.
2094 * @return VBox rc.
2095 */
2096int HGCMHostRegisterServiceExtension (HGCMSVCEXTHANDLE *pHandle,
2097 const char *pszServiceName,
2098 PFNHGCMSVCEXT pfnExtension,
2099 void *pvExtension)
2100{
2101 LogFlowFunc(("pHandle = %p, name = %s, pfn = %p, rv = %p\n", pHandle, pszServiceName, pfnExtension, pvExtension));
2102
2103 if (!pHandle || !pszServiceName || !pfnExtension)
2104 {
2105 return VERR_INVALID_PARAMETER;
2106 }
2107
2108 /* Forward the request to the main hgcm thread. */
2109 HGCMMSGHANDLE hMsg = 0;
2110
2111 int rc = hgcmMsgAlloc (g_hgcmThread, &hMsg, HGCM_MSG_REGEXT, hgcmMainMessageAlloc);
2112
2113 if (RT_SUCCESS(rc))
2114 {
2115 /* Initialize the message. Since the message is synchronous, use the supplied pointers. */
2116 HGCMMsgMainRegisterExtension *pMsg = (HGCMMsgMainRegisterExtension *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
2117 AssertRelease(pMsg);
2118
2119 pMsg->pHandle = pHandle;
2120 pMsg->pszServiceName = pszServiceName;
2121 pMsg->pfnExtension = pfnExtension;
2122 pMsg->pvExtension = pvExtension;
2123
2124 hgcmObjDereference (pMsg);
2125
2126 rc = hgcmMsgSend (hMsg);
2127 }
2128
2129 LogFlowFunc(("*pHandle = %p, rc = %Rrc\n", *pHandle, rc));
2130 return rc;
2131}
2132
2133void HGCMHostUnregisterServiceExtension (HGCMSVCEXTHANDLE handle)
2134{
2135 LogFlowFunc(("handle = %p\n", handle));
2136
2137 /* Forward the request to the main hgcm thread. */
2138 HGCMMSGHANDLE hMsg = 0;
2139
2140 int rc = hgcmMsgAlloc (g_hgcmThread, &hMsg, HGCM_MSG_UNREGEXT, hgcmMainMessageAlloc);
2141
2142 if (RT_SUCCESS(rc))
2143 {
2144 /* Initialize the message. */
2145 HGCMMsgMainUnregisterExtension *pMsg = (HGCMMsgMainUnregisterExtension *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
2146 AssertRelease(pMsg);
2147
2148 pMsg->handle = handle;
2149
2150 hgcmObjDereference (pMsg);
2151
2152 rc = hgcmMsgSend (hMsg);
2153 }
2154
2155 LogFlowFunc(("rc = %Rrc\n", rc));
2156 return;
2157}
2158
2159/* Find a service and inform it about a client connection, create a client handle.
2160 *
2161 * @param pHGCMPort The port to be used for completion confirmation.
2162 * @param pCmd The VBox HGCM context.
2163 * @param pszServiceName The name of the service to be connected to.
2164 * @param pu32ClientId Where the store the created client handle.
2165 * @return VBox rc.
2166 */
2167int HGCMGuestConnect (PPDMIHGCMPORT pHGCMPort,
2168 PVBOXHGCMCMD pCmd,
2169 const char *pszServiceName,
2170 uint32_t *pu32ClientId)
2171{
2172 LogFlowFunc(("pHGCMPort = %p, pCmd = %p, name = %s, pu32ClientId = %p\n",
2173 pHGCMPort, pCmd, pszServiceName, pu32ClientId));
2174
2175 if (pHGCMPort == NULL || pCmd == NULL || pszServiceName == NULL || pu32ClientId == NULL)
2176 {
2177 return VERR_INVALID_PARAMETER;
2178 }
2179
2180 /* Forward the request to the main hgcm thread. */
2181 HGCMMSGHANDLE hMsg = 0;
2182
2183 int rc = hgcmMsgAlloc (g_hgcmThread, &hMsg, HGCM_MSG_CONNECT, hgcmMainMessageAlloc);
2184
2185 if (RT_SUCCESS(rc))
2186 {
2187 /* Initialize the message. Since 'pszServiceName' and 'pu32ClientId'
2188 * will not be deallocated by the caller until the message is completed,
2189 * use the supplied pointers.
2190 */
2191 HGCMMsgMainConnect *pMsg = (HGCMMsgMainConnect *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
2192 AssertRelease(pMsg);
2193
2194 pMsg->pHGCMPort = pHGCMPort;
2195 pMsg->pCmd = pCmd;
2196 pMsg->pszServiceName = pszServiceName;
2197 pMsg->pu32ClientId = pu32ClientId;
2198
2199 hgcmObjDereference (pMsg);
2200
2201 rc = hgcmMsgPost (hMsg, hgcmMsgCompletionCallback);
2202 }
2203
2204 LogFlowFunc(("rc = %Rrc\n", rc));
2205 return rc;
2206}
2207
2208/* Tell a service that the client is disconnecting, destroy the client handle.
2209 *
2210 * @param pHGCMPort The port to be used for completion confirmation.
2211 * @param pCmd The VBox HGCM context.
2212 * @param u32ClientId The client handle to be disconnected and deleted.
2213 * @return VBox rc.
2214 */
2215int HGCMGuestDisconnect (PPDMIHGCMPORT pHGCMPort,
2216 PVBOXHGCMCMD pCmd,
2217 uint32_t u32ClientId)
2218{
2219 LogFlowFunc(("pHGCMPort = %p, pCmd = %p, u32ClientId = %d\n",
2220 pHGCMPort, pCmd, u32ClientId));
2221
2222 if (!pHGCMPort || !pCmd || !u32ClientId)
2223 {
2224 return VERR_INVALID_PARAMETER;
2225 }
2226
2227 /* Forward the request to the main hgcm thread. */
2228 HGCMMSGHANDLE hMsg = 0;
2229
2230 int rc = hgcmMsgAlloc (g_hgcmThread, &hMsg, HGCM_MSG_DISCONNECT, hgcmMainMessageAlloc);
2231
2232 if (RT_SUCCESS(rc))
2233 {
2234 /* Initialize the message. */
2235 HGCMMsgMainDisconnect *pMsg = (HGCMMsgMainDisconnect *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
2236 AssertRelease(pMsg);
2237
2238 pMsg->pCmd = pCmd;
2239 pMsg->pHGCMPort = pHGCMPort;
2240 pMsg->u32ClientId = u32ClientId;
2241
2242 hgcmObjDereference (pMsg);
2243
2244 rc = hgcmMsgPost (hMsg, hgcmMsgCompletionCallback);
2245 }
2246
2247 LogFlowFunc(("rc = %Rrc\n", rc));
2248 return rc;
2249}
2250
2251/* Helper to send either HGCM_MSG_SAVESTATE or HGCM_MSG_LOADSTATE messages to the main HGCM thread.
2252 *
2253 * @param pSSM The SSM handle.
2254 * @param u32MsgId The message to be sent: HGCM_MSG_SAVESTATE or HGCM_MSG_LOADSTATE.
2255 * @return VBox rc.
2256 */
2257static int hgcmHostLoadSaveState (PSSMHANDLE pSSM,
2258 uint32_t u32MsgId)
2259{
2260 LogFlowFunc(("pSSM = %p, u32MsgId = %d\n", pSSM, u32MsgId));
2261
2262 HGCMMSGHANDLE hMsg = 0;
2263
2264 int rc = hgcmMsgAlloc (g_hgcmThread, &hMsg, u32MsgId, hgcmMainMessageAlloc);
2265
2266 if (RT_SUCCESS(rc))
2267 {
2268 HGCMMsgMainLoadSaveState *pMsg = (HGCMMsgMainLoadSaveState *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
2269 AssertRelease(pMsg);
2270
2271 pMsg->pSSM = pSSM;
2272
2273 hgcmObjDereference (pMsg);
2274
2275 rc = hgcmMsgSend (hMsg);
2276 }
2277
2278 LogFlowFunc(("rc = %Rrc\n", rc));
2279 return rc;
2280}
2281
2282/* Save the state of services.
2283 *
2284 * @param pSSM The SSM handle.
2285 * @return VBox rc.
2286 */
2287int HGCMHostSaveState (PSSMHANDLE pSSM)
2288{
2289 return hgcmHostLoadSaveState (pSSM, HGCM_MSG_SAVESTATE);
2290}
2291
2292/* Load the state of services.
2293 *
2294 * @param pSSM The SSM handle.
2295 * @return VBox rc.
2296 */
2297int HGCMHostLoadState (PSSMHANDLE pSSM)
2298{
2299 return hgcmHostLoadSaveState (pSSM, HGCM_MSG_LOADSTATE);
2300}
2301
2302/* The guest calls the service.
2303 *
2304 * @param pHGCMPort The port to be used for completion confirmation.
2305 * @param pCmd The VBox HGCM context.
2306 * @param u32ClientId The client handle to be disconnected and deleted.
2307 * @param u32Function The function number.
2308 * @param cParms Number of parameters.
2309 * @param paParms Pointer to array of parameters.
2310 * @return VBox rc.
2311 */
2312int HGCMGuestCall (PPDMIHGCMPORT pHGCMPort,
2313 PVBOXHGCMCMD pCmd,
2314 uint32_t u32ClientId,
2315 uint32_t u32Function,
2316 uint32_t cParms,
2317 VBOXHGCMSVCPARM *paParms)
2318{
2319 LogFlowFunc(("pHGCMPort = %p, pCmd = %p, u32ClientId = %d, u32Function = %d, cParms = %d, paParms = %p\n",
2320 pHGCMPort, pCmd, u32ClientId, u32Function, cParms, paParms));
2321
2322 if (!pHGCMPort || !pCmd || u32ClientId == 0)
2323 {
2324 return VERR_INVALID_PARAMETER;
2325 }
2326
2327 int rc = VERR_HGCM_INVALID_CLIENT_ID;
2328
2329 /* Resolve the client handle to the client instance pointer. */
2330 HGCMClient *pClient = (HGCMClient *)hgcmObjReference (u32ClientId, HGCMOBJ_CLIENT);
2331
2332 if (pClient)
2333 {
2334 AssertRelease(pClient->pService);
2335
2336 /* Forward the message to the service thread. */
2337 rc = pClient->pService->GuestCall (pHGCMPort, pCmd, u32ClientId, u32Function, cParms, paParms);
2338
2339 hgcmObjDereference (pClient);
2340 }
2341
2342 LogFlowFunc(("rc = %Rrc\n", rc));
2343 return rc;
2344}
2345
2346/* The host calls the service.
2347 *
2348 * @param pszServiceName The service name to be called.
2349 * @param u32Function The function number.
2350 * @param cParms Number of parameters.
2351 * @param paParms Pointer to array of parameters.
2352 * @return VBox rc.
2353 */
2354int HGCMHostCall (const char *pszServiceName,
2355 uint32_t u32Function,
2356 uint32_t cParms,
2357 VBOXHGCMSVCPARM *paParms)
2358{
2359 LogFlowFunc(("name = %s, u32Function = %d, cParms = %d, paParms = %p\n",
2360 pszServiceName, u32Function, cParms, paParms));
2361
2362 if (!pszServiceName)
2363 {
2364 return VERR_INVALID_PARAMETER;
2365 }
2366
2367 HGCMMSGHANDLE hMsg = 0;
2368
2369 /* Host calls go to main HGCM thread that resolves the service name to the
2370 * service instance pointer and then, using the service pointer, forwards
2371 * the message to the service thread.
2372 * So it is slow but host calls are intended mostly for configuration and
2373 * other non-time-critical functions.
2374 */
2375 int rc = hgcmMsgAlloc (g_hgcmThread, &hMsg, HGCM_MSG_HOSTCALL, hgcmMainMessageAlloc);
2376
2377 if (RT_SUCCESS(rc))
2378 {
2379 HGCMMsgMainHostCall *pMsg = (HGCMMsgMainHostCall *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
2380 AssertRelease(pMsg);
2381
2382 pMsg->pszServiceName = (char *)pszServiceName;
2383 pMsg->u32Function = u32Function;
2384 pMsg->cParms = cParms;
2385 pMsg->paParms = paParms;
2386
2387 hgcmObjDereference (pMsg);
2388
2389 rc = hgcmMsgSend (hMsg);
2390 }
2391
2392 LogFlowFunc(("rc = %Rrc\n", rc));
2393 return rc;
2394}
2395
2396#ifdef VBOX_WITH_CRHGSMI
2397int HGCMHostSvcHandleCreate (const char *pszServiceName, HGCMCVSHANDLE * phSvc)
2398{
2399 LogFlowFunc(("name = %s\n", pszServiceName));
2400
2401 if (!pszServiceName)
2402 {
2403 return VERR_INVALID_PARAMETER;
2404 }
2405
2406 if (!phSvc)
2407 {
2408 return VERR_INVALID_PARAMETER;
2409 }
2410
2411 HGCMMSGHANDLE hMsg = 0;
2412
2413 /* Host calls go to main HGCM thread that resolves the service name to the
2414 * service instance pointer and then, using the service pointer, forwards
2415 * the message to the service thread.
2416 * So it is slow but host calls are intended mostly for configuration and
2417 * other non-time-critical functions.
2418 */
2419 int rc = hgcmMsgAlloc (g_hgcmThread, &hMsg, HGCM_MSG_SVCAQUIRE, hgcmMainMessageAlloc);
2420
2421 if (RT_SUCCESS(rc))
2422 {
2423 HGCMMsgMainSvcAcquire *pMsg = (HGCMMsgMainSvcAcquire *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
2424 AssertRelease(pMsg);
2425
2426 pMsg->pszServiceName = (char *)pszServiceName;
2427 pMsg->pService = NULL;
2428
2429 rc = hgcmMsgSend (hMsg);
2430 if (RT_SUCCESS(rc))
2431 {
2432 /* for simplicity just use a svc ptr as handle for now */
2433 *phSvc = (HGCMCVSHANDLE)pMsg->pService;
2434 }
2435
2436 hgcmObjDereference (pMsg);
2437 }
2438
2439 LogFlowFunc(("rc = %Rrc\n", rc));
2440 return rc;
2441}
2442
2443int HGCMHostSvcHandleDestroy (HGCMCVSHANDLE hSvc)
2444{
2445 LogFlowFunc(("hSvc = %p\n", hSvc));
2446
2447 if (!hSvc)
2448 {
2449 return VERR_INVALID_PARAMETER;
2450 }
2451
2452 HGCMMSGHANDLE hMsg = 0;
2453
2454 /* Host calls go to main HGCM thread that resolves the service name to the
2455 * service instance pointer and then, using the service pointer, forwards
2456 * the message to the service thread.
2457 * So it is slow but host calls are intended mostly for configuration and
2458 * other non-time-critical functions.
2459 */
2460 int rc = hgcmMsgAlloc (g_hgcmThread, &hMsg, HGCM_MSG_SVCRELEASE, hgcmMainMessageAlloc);
2461
2462 if (RT_SUCCESS(rc))
2463 {
2464 HGCMMsgMainSvcRelease *pMsg = (HGCMMsgMainSvcRelease *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
2465 AssertRelease(pMsg);
2466
2467 pMsg->pService = (HGCMService *)hSvc;
2468
2469 hgcmObjDereference (pMsg);
2470
2471 rc = hgcmMsgSend (hMsg);
2472 }
2473
2474 LogFlowFunc(("rc = %Rrc\n", rc));
2475 return rc;
2476}
2477
2478int HGCMHostFastCallAsync (HGCMCVSHANDLE hSvc, uint32_t function, VBOXHGCMSVCPARM *pParm, PHGCMHOSTFASTCALLCB pfnCompletion, void *pvCompletion)
2479{
2480 LogFlowFunc(("hSvc = %p, u32Function = %d, pParm = %p\n",
2481 hSvc, function, pParm));
2482
2483 if (!hSvc)
2484 {
2485 return VERR_INVALID_PARAMETER;
2486 }
2487
2488 HGCMService *pService = (HGCMService *)hSvc;
2489 int rc = pService->HostFastCallAsync (function, pParm, pfnCompletion, pvCompletion);
2490
2491 LogFlowFunc(("rc = %Rrc\n", rc));
2492 return rc;
2493}
2494#endif
2495
2496int HGCMHostReset (void)
2497{
2498 LogFlowFunc(("\n"));
2499
2500 /* Disconnect all clients.
2501 */
2502
2503 HGCMMSGHANDLE hMsg = 0;
2504
2505 int rc = hgcmMsgAlloc (g_hgcmThread, &hMsg, HGCM_MSG_RESET, hgcmMainMessageAlloc);
2506
2507 if (RT_SUCCESS(rc))
2508 {
2509 rc = hgcmMsgSend (hMsg);
2510 }
2511
2512 LogFlowFunc(("rc = %Rrc\n", rc));
2513 return rc;
2514}
2515
2516int HGCMHostInit (void)
2517{
2518 LogFlowFunc(("\n"));
2519
2520 int rc = hgcmThreadInit ();
2521
2522 if (RT_SUCCESS(rc))
2523 {
2524 /*
2525 * Start main HGCM thread.
2526 */
2527
2528 rc = hgcmThreadCreate (&g_hgcmThread, "MainHGCMthread", hgcmThread, NULL);
2529
2530 if (RT_FAILURE(rc))
2531 {
2532 LogRel(("Failed to start HGCM thread. HGCM services will be unavailable!!! rc = %Rrc\n", rc));
2533 }
2534 }
2535
2536 LogFlowFunc(("rc = %Rrc\n", rc));
2537 return rc;
2538}
2539
2540int HGCMHostShutdown (void)
2541{
2542 LogFlowFunc(("\n"));
2543
2544 /*
2545 * Do HGCMReset and then unload all services.
2546 */
2547
2548 int rc = HGCMHostReset ();
2549
2550 if (RT_SUCCESS(rc))
2551 {
2552 /* Send the quit message to the main hgcmThread. */
2553 HGCMMSGHANDLE hMsg = 0;
2554
2555 rc = hgcmMsgAlloc (g_hgcmThread, &hMsg, HGCM_MSG_QUIT, hgcmMainMessageAlloc);
2556
2557 if (RT_SUCCESS(rc))
2558 {
2559 rc = hgcmMsgSend (hMsg);
2560
2561 if (RT_SUCCESS(rc))
2562 {
2563 /* Wait for the thread termination. */
2564 hgcmThreadWait (g_hgcmThread);
2565 g_hgcmThread = 0;
2566
2567 hgcmThreadUninit ();
2568 }
2569 }
2570 }
2571
2572 LogFlowFunc(("rc = %Rrc\n", rc));
2573 return rc;
2574}
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