VirtualBox

source: vbox/trunk/src/VBox/Frontends/VBoxBFE/HGCM.cpp@ 6967

Last change on this file since 6967 was 6967, checked in by vboxsync, 17 years ago

Don't use the system library path to look for plugins.

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

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