VirtualBox

source: vbox/trunk/src/VBox/Main/hgcm/HGCM.cpp@ 7449

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

HGCM: reapplied r28137, which got lost when I commited the code Vitali sent me

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