VirtualBox

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

Last change on this file since 32876 was 29071, checked in by vboxsync, 15 years ago

LogRel HGCM service name when restoring.

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