VirtualBox

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

Last change on this file since 45883 was 44528, checked in by vboxsync, 12 years ago

header (C) fixes

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