VirtualBox

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

Last change on this file since 22292 was 21878, checked in by vboxsync, 15 years ago

Main: coding style: have Main obey the standard VirtualBox coding style rules (no functional changes)

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