VirtualBox

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

Last change on this file since 30045 was 28800, checked in by vboxsync, 15 years ago

Automated rebranding to Oracle copyright/license strings via filemuncher

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