VirtualBox

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

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

The Giant CDDL Dual-License Header Change.

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

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