VirtualBox

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

Last change on this file since 25517 was 21227, checked in by vboxsync, 15 years ago

VBoxGuest.h/VMMDev.h/VBoxGuestLib.h usage cleanup.

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