VirtualBox

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

Last change on this file since 35261 was 35191, checked in by vboxsync, 14 years ago

Some cleanup. Pass RTLDRLOAD_FLAGS_LOCAL instead of 0, since it's defined.

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