VirtualBox

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

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

Use RTLdrLoadAppSharedLib for VRDP and HGCM libraries.

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