VirtualBox

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

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

HGCM: delete a disconnected client handle. Fixes HGCMReset hang/assertion.

  • 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 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(("[%s] m_u32RefCnt = %d\n", m_pszSvcName, 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 else
1362 {
1363 LogRel(("(%d, %d) [%s] hgcmMsgAlloc(%p, SVC_MSG_DISCONNECT) failed %Rrc\n",
1364 u32ClientId, fFromService, RT_VALID_PTR(m_pszSvcName)? m_pszSvcName: "", m_thread, rc));
1365 }
1366 }
1367
1368 /* Remove the client id from the array in any case, rc does not matter. */
1369 int i;
1370
1371 for (i = 0; i < m_cClients; i++)
1372 {
1373 if (m_paClientIds[i] == u32ClientId)
1374 {
1375 m_cClients--;
1376
1377 if (m_cClients > i)
1378 {
1379 memmove (&m_paClientIds[i], &m_paClientIds[i + 1], sizeof (m_paClientIds[0]) * (m_cClients - i));
1380 }
1381
1382 /* Delete the client handle. */
1383 hgcmObjDeleteHandle (u32ClientId);
1384
1385 /* The service must be released. */
1386 ReleaseService ();
1387
1388 break;
1389 }
1390 }
1391
1392 LogFlowFunc(("rc = %Rrc\n", rc));
1393 return rc;
1394}
1395
1396int HGCMService::RegisterExtension (HGCMSVCEXTHANDLE handle,
1397 PFNHGCMSVCEXT pfnExtension,
1398 void *pvExtension)
1399{
1400 LogFlowFunc(("%s\n", handle->pszServiceName));
1401
1402 /* Forward the message to the service thread. */
1403 HGCMMSGHANDLE hMsg = 0;
1404 int rc = hgcmMsgAlloc (m_thread, &hMsg, SVC_MSG_REGEXT, hgcmMessageAllocSvc);
1405
1406 if (RT_SUCCESS(rc))
1407 {
1408 HGCMMsgSvcRegisterExtension *pMsg = (HGCMMsgSvcRegisterExtension *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
1409 AssertRelease(pMsg);
1410
1411 pMsg->handle = handle;
1412 pMsg->pfnExtension = pfnExtension;
1413 pMsg->pvExtension = pvExtension;
1414
1415 hgcmObjDereference (pMsg);
1416
1417 rc = hgcmMsgSend (hMsg);
1418 }
1419
1420 LogFlowFunc(("rc = %Rrc\n", rc));
1421 return rc;
1422}
1423
1424void HGCMService::UnregisterExtension (HGCMSVCEXTHANDLE handle)
1425{
1426 /* Forward the message to the service thread. */
1427 HGCMMSGHANDLE hMsg = 0;
1428 int rc = hgcmMsgAlloc (m_thread, &hMsg, SVC_MSG_UNREGEXT, hgcmMessageAllocSvc);
1429
1430 if (RT_SUCCESS(rc))
1431 {
1432 HGCMMsgSvcUnregisterExtension *pMsg = (HGCMMsgSvcUnregisterExtension *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
1433 AssertRelease(pMsg);
1434
1435 pMsg->handle = handle;
1436
1437 hgcmObjDereference (pMsg);
1438
1439 rc = hgcmMsgSend (hMsg);
1440 }
1441
1442 LogFlowFunc(("rc = %Rrc\n", rc));
1443}
1444
1445/* Perform a guest call to the service.
1446 *
1447 * @param pHGCMPort The port to be used for completion confirmation.
1448 * @param pCmd The VBox HGCM context.
1449 * @param u32ClientId The client handle to be disconnected and deleted.
1450 * @param u32Function The function number.
1451 * @param cParms Number of parameters.
1452 * @param paParms Pointer to array of parameters.
1453 * @return VBox rc.
1454 */
1455int HGCMService::GuestCall (PPDMIHGCMPORT pHGCMPort, PVBOXHGCMCMD pCmd, uint32_t u32ClientId, uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
1456{
1457 HGCMMSGHANDLE hMsg = 0;
1458
1459 LogFlow(("MAIN::HGCMService::Call\n"));
1460
1461 int rc = hgcmMsgAlloc (m_thread, &hMsg, SVC_MSG_GUESTCALL, hgcmMessageAllocSvc);
1462
1463 if (RT_SUCCESS(rc))
1464 {
1465 HGCMMsgCall *pMsg = (HGCMMsgCall *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
1466
1467 AssertRelease(pMsg);
1468
1469 pMsg->pCmd = pCmd;
1470 pMsg->pHGCMPort = pHGCMPort;
1471
1472 pMsg->u32ClientId = u32ClientId;
1473 pMsg->u32Function = u32Function;
1474 pMsg->cParms = cParms;
1475 pMsg->paParms = paParms;
1476
1477 hgcmObjDereference (pMsg);
1478
1479 rc = hgcmMsgPost (hMsg, hgcmMsgCompletionCallback);
1480 }
1481 else
1482 {
1483 Log(("MAIN::HGCMService::Call: Message allocation failed: %Rrc\n", rc));
1484 }
1485
1486 LogFlowFunc(("rc = %Rrc\n", rc));
1487 return rc;
1488}
1489
1490/* Perform a host call the service.
1491 *
1492 * @param u32Function The function number.
1493 * @param cParms Number of parameters.
1494 * @param paParms Pointer to array of parameters.
1495 * @return VBox rc.
1496 */
1497int HGCMService::HostCall (uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM *paParms)
1498{
1499 LogFlowFunc(("%s u32Function = %d, cParms = %d, paParms = %p\n",
1500 m_pszSvcName, u32Function, cParms, paParms));
1501
1502 HGCMMSGHANDLE hMsg = 0;
1503 int rc = hgcmMsgAlloc (m_thread, &hMsg, SVC_MSG_HOSTCALL, hgcmMessageAllocSvc);
1504
1505 if (RT_SUCCESS(rc))
1506 {
1507 HGCMMsgHostCallSvc *pMsg = (HGCMMsgHostCallSvc *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
1508 AssertRelease(pMsg);
1509
1510 pMsg->u32Function = u32Function;
1511 pMsg->cParms = cParms;
1512 pMsg->paParms = paParms;
1513
1514 hgcmObjDereference (pMsg);
1515
1516 rc = hgcmMsgSend (hMsg);
1517 }
1518
1519 LogFlowFunc(("rc = %Rrc\n", rc));
1520 return rc;
1521}
1522
1523
1524/*
1525 * Main HGCM thread that manages services.
1526 */
1527
1528/* Messages processed by the main HGCM thread. */
1529#define HGCM_MSG_CONNECT (10) /* Connect a client to a service. */
1530#define HGCM_MSG_DISCONNECT (11) /* Disconnect the specified client id. */
1531#define HGCM_MSG_LOAD (12) /* Load the service. */
1532#define HGCM_MSG_HOSTCALL (13) /* Call the service. */
1533#define HGCM_MSG_LOADSTATE (14) /* Load saved state for the specified service. */
1534#define HGCM_MSG_SAVESTATE (15) /* Save state for the specified service. */
1535#define HGCM_MSG_RESET (16) /* Disconnect all clients from the specified service. */
1536#define HGCM_MSG_QUIT (17) /* Unload all services and terminate the thread. */
1537#define HGCM_MSG_REGEXT (18) /* Register a service extension. */
1538#define HGCM_MSG_UNREGEXT (19) /* Unregister a service extension. */
1539
1540class HGCMMsgMainConnect: public HGCMMsgHeader
1541{
1542 public:
1543 /* Service name. */
1544 const char *pszServiceName;
1545 /* Where to store the client handle. */
1546 uint32_t *pu32ClientId;
1547};
1548
1549class HGCMMsgMainDisconnect: public HGCMMsgHeader
1550{
1551 public:
1552 /* Handle of the client to be disconnected. */
1553 uint32_t u32ClientId;
1554};
1555
1556class HGCMMsgMainLoad: public HGCMMsgCore
1557{
1558 public:
1559 /* Name of the library to be loaded. */
1560 const char *pszServiceLibrary;
1561 /* Name to be assigned to the service. */
1562 const char *pszServiceName;
1563};
1564
1565class HGCMMsgMainHostCall: public HGCMMsgCore
1566{
1567 public:
1568 /* Which service to call. */
1569 const char *pszServiceName;
1570 /* Function number. */
1571 uint32_t u32Function;
1572 /* Number of the function parameters. */
1573 uint32_t cParms;
1574 /* Pointer to array of the function parameters. */
1575 VBOXHGCMSVCPARM *paParms;
1576};
1577
1578class HGCMMsgMainLoadSaveState: public HGCMMsgCore
1579{
1580 public:
1581 /* SSM context. */
1582 PSSMHANDLE pSSM;
1583};
1584
1585class HGCMMsgMainReset: public HGCMMsgCore
1586{
1587};
1588
1589class HGCMMsgMainQuit: public HGCMMsgCore
1590{
1591};
1592
1593class HGCMMsgMainRegisterExtension: public HGCMMsgCore
1594{
1595 public:
1596 /* Returned handle to be used in HGCMMsgMainUnregisterExtension. */
1597 HGCMSVCEXTHANDLE *pHandle;
1598 /* Name of the service. */
1599 const char *pszServiceName;
1600 /* The extension entry point. */
1601 PFNHGCMSVCEXT pfnExtension;
1602 /* The extension pointer. */
1603 void *pvExtension;
1604};
1605
1606class HGCMMsgMainUnregisterExtension: public HGCMMsgCore
1607{
1608 public:
1609 /* Handle of the registered extension. */
1610 HGCMSVCEXTHANDLE handle;
1611};
1612
1613static HGCMMsgCore *hgcmMainMessageAlloc (uint32_t u32MsgId)
1614{
1615 switch (u32MsgId)
1616 {
1617 case HGCM_MSG_CONNECT: return new HGCMMsgMainConnect ();
1618 case HGCM_MSG_DISCONNECT: return new HGCMMsgMainDisconnect ();
1619 case HGCM_MSG_LOAD: return new HGCMMsgMainLoad ();
1620 case HGCM_MSG_HOSTCALL: return new HGCMMsgMainHostCall ();
1621 case HGCM_MSG_LOADSTATE:
1622 case HGCM_MSG_SAVESTATE: return new HGCMMsgMainLoadSaveState ();
1623 case HGCM_MSG_RESET: return new HGCMMsgMainReset ();
1624 case HGCM_MSG_QUIT: return new HGCMMsgMainQuit ();
1625 case HGCM_MSG_REGEXT: return new HGCMMsgMainRegisterExtension ();
1626 case HGCM_MSG_UNREGEXT: return new HGCMMsgMainUnregisterExtension ();
1627 default:
1628 AssertReleaseMsgFailed(("Msg id = %08X\n", u32MsgId));
1629 }
1630
1631 return NULL;
1632}
1633
1634
1635/* The main HGCM thread handler. */
1636static DECLCALLBACK(void) hgcmThread (HGCMTHREADHANDLE ThreadHandle, void *pvUser)
1637{
1638 LogFlowFunc(("ThreadHandle = %p, pvUser = %p\n",
1639 ThreadHandle, pvUser));
1640
1641 NOREF(pvUser);
1642
1643 bool fQuit = false;
1644
1645 while (!fQuit)
1646 {
1647 HGCMMsgCore *pMsgCore;
1648 int rc = hgcmMsgGet (ThreadHandle, &pMsgCore);
1649
1650 if (RT_FAILURE(rc))
1651 {
1652 /* The error means some serious unrecoverable problem in the hgcmMsg/hgcmThread layer. */
1653 AssertMsgFailed (("%Rrc\n", rc));
1654 break;
1655 }
1656
1657 uint32_t u32MsgId = pMsgCore->MsgId ();
1658
1659 switch (u32MsgId)
1660 {
1661 case HGCM_MSG_CONNECT:
1662 {
1663 HGCMMsgMainConnect *pMsg = (HGCMMsgMainConnect *)pMsgCore;
1664
1665 LogFlowFunc(("HGCM_MSG_CONNECT pszServiceName %s, pu32ClientId %p\n",
1666 pMsg->pszServiceName, pMsg->pu32ClientId));
1667
1668 /* Resolve the service name to the pointer to service instance.
1669 */
1670 HGCMService *pService;
1671 rc = HGCMService::ResolveService (&pService, pMsg->pszServiceName);
1672
1673 if (RT_SUCCESS(rc))
1674 {
1675 /* Call the service instance method. */
1676 rc = pService->CreateAndConnectClient (pMsg->pu32ClientId, 0);
1677
1678 /* Release the service after resolve. */
1679 pService->ReleaseService ();
1680 }
1681 } break;
1682
1683 case HGCM_MSG_DISCONNECT:
1684 {
1685 HGCMMsgMainDisconnect *pMsg = (HGCMMsgMainDisconnect *)pMsgCore;
1686
1687 LogFlowFunc(("HGCM_MSG_DISCONNECT u32ClientId = %d\n",
1688 pMsg->u32ClientId));
1689
1690 HGCMClient *pClient = (HGCMClient *)hgcmObjReference (pMsg->u32ClientId, HGCMOBJ_CLIENT);
1691
1692 if (!pClient)
1693 {
1694 rc = VERR_HGCM_INVALID_CLIENT_ID;
1695 break;
1696 }
1697
1698 /* The service the client belongs to. */
1699 HGCMService *pService = pClient->pService;
1700
1701 /* Call the service instance to disconnect the client. */
1702 rc = pService->DisconnectClient (pMsg->u32ClientId, false);
1703
1704 hgcmObjDereference (pClient);
1705 } break;
1706
1707 case HGCM_MSG_LOAD:
1708 {
1709 HGCMMsgMainLoad *pMsg = (HGCMMsgMainLoad *)pMsgCore;
1710
1711 LogFlowFunc(("HGCM_MSG_LOAD pszServiceName = %s, pMsg->pszServiceLibrary = %s\n",
1712 pMsg->pszServiceName, pMsg->pszServiceLibrary));
1713
1714 rc = HGCMService::LoadService (pMsg->pszServiceLibrary, pMsg->pszServiceName);
1715 } break;
1716
1717 case HGCM_MSG_HOSTCALL:
1718 {
1719 HGCMMsgMainHostCall *pMsg = (HGCMMsgMainHostCall *)pMsgCore;
1720
1721 LogFlowFunc(("HGCM_MSG_HOSTCALL pszServiceName %s, u32Function %d, cParms %d, paParms %p\n",
1722 pMsg->pszServiceName, pMsg->u32Function, pMsg->cParms, pMsg->paParms));
1723
1724 /* Resolve the service name to the pointer to service instance. */
1725 HGCMService *pService;
1726 rc = HGCMService::ResolveService (&pService, pMsg->pszServiceName);
1727
1728 if (RT_SUCCESS(rc))
1729 {
1730 rc = pService->HostCall (pMsg->u32Function, pMsg->cParms, pMsg->paParms);
1731
1732 pService->ReleaseService ();
1733 }
1734 } break;
1735
1736 case HGCM_MSG_RESET:
1737 {
1738 LogFlowFunc(("HGCM_MSG_RESET\n"));
1739
1740 HGCMService::Reset ();
1741 } break;
1742
1743 case HGCM_MSG_LOADSTATE:
1744 {
1745 HGCMMsgMainLoadSaveState *pMsg = (HGCMMsgMainLoadSaveState *)pMsgCore;
1746
1747 LogFlowFunc(("HGCM_MSG_LOADSTATE\n"));
1748
1749 rc = HGCMService::LoadState (pMsg->pSSM);
1750 } break;
1751
1752 case HGCM_MSG_SAVESTATE:
1753 {
1754 HGCMMsgMainLoadSaveState *pMsg = (HGCMMsgMainLoadSaveState *)pMsgCore;
1755
1756 LogFlowFunc(("HGCM_MSG_SAVESTATE\n"));
1757
1758 rc = HGCMService::SaveState (pMsg->pSSM);
1759 } break;
1760
1761 case HGCM_MSG_QUIT:
1762 {
1763 LogFlowFunc(("HGCM_MSG_QUIT\n"));
1764
1765 HGCMService::UnloadAll ();
1766
1767 fQuit = true;
1768 } break;
1769
1770 case HGCM_MSG_REGEXT:
1771 {
1772 HGCMMsgMainRegisterExtension *pMsg = (HGCMMsgMainRegisterExtension *)pMsgCore;
1773
1774 LogFlowFunc(("HGCM_MSG_REGEXT\n"));
1775
1776 /* Allocate the handle data. */
1777 HGCMSVCEXTHANDLE handle = (HGCMSVCEXTHANDLE)RTMemAllocZ (sizeof (struct _HGCMSVCEXTHANDLEDATA)
1778 + strlen (pMsg->pszServiceName)
1779 + sizeof (char));
1780
1781 if (handle == NULL)
1782 {
1783 rc = VERR_NO_MEMORY;
1784 }
1785 else
1786 {
1787 handle->pszServiceName = (char *)((uint8_t *)handle + sizeof (struct _HGCMSVCEXTHANDLEDATA));
1788 strcpy (handle->pszServiceName, pMsg->pszServiceName);
1789
1790 HGCMService *pService;
1791 rc = HGCMService::ResolveService (&pService, handle->pszServiceName);
1792
1793 if (RT_SUCCESS(rc))
1794 {
1795 pService->RegisterExtension (handle, pMsg->pfnExtension, pMsg->pvExtension);
1796
1797 pService->ReleaseService ();
1798 }
1799
1800 if (RT_FAILURE(rc))
1801 {
1802 RTMemFree (handle);
1803 }
1804 else
1805 {
1806 *pMsg->pHandle = handle;
1807 }
1808 }
1809 } break;
1810
1811 case HGCM_MSG_UNREGEXT:
1812 {
1813 HGCMMsgMainUnregisterExtension *pMsg = (HGCMMsgMainUnregisterExtension *)pMsgCore;
1814
1815 LogFlowFunc(("HGCM_MSG_UNREGEXT\n"));
1816
1817 HGCMService *pService;
1818 rc = HGCMService::ResolveService (&pService, pMsg->handle->pszServiceName);
1819
1820 if (RT_SUCCESS(rc))
1821 {
1822 pService->UnregisterExtension (pMsg->handle);
1823
1824 pService->ReleaseService ();
1825 }
1826
1827 RTMemFree (pMsg->handle);
1828 } break;
1829
1830 default:
1831 {
1832 AssertMsgFailed(("hgcmThread: Unsupported message number %08X!!!\n", u32MsgId));
1833 rc = VERR_NOT_SUPPORTED;
1834 } break;
1835 }
1836
1837 /* Complete the message processing. */
1838 hgcmMsgComplete (pMsgCore, rc);
1839
1840 LogFlowFunc(("message processed %Rrc\n", rc));
1841 }
1842}
1843
1844
1845/*
1846 * The HGCM API.
1847 */
1848
1849/* The main hgcm thread. */
1850static HGCMTHREADHANDLE g_hgcmThread = 0;
1851
1852/*
1853 * Public HGCM functions.
1854 *
1855 * hgcmGuest* - called as a result of the guest HGCM requests.
1856 * hgcmHost* - called by the host.
1857 */
1858
1859/* Load a HGCM service from the specified library.
1860 * Assign the specified name to the service.
1861 *
1862 * @param pszServiceLibrary The library to be loaded.
1863 * @param pszServiceName The name to be assigned to the service.
1864 * @return VBox rc.
1865 */
1866int HGCMHostLoad (const char *pszServiceLibrary,
1867 const char *pszServiceName)
1868{
1869 LogFlowFunc(("lib = %s, name = %s\n", pszServiceLibrary, pszServiceName));
1870
1871 if (!pszServiceLibrary || !pszServiceName)
1872 {
1873 return VERR_INVALID_PARAMETER;
1874 }
1875
1876 /* Forward the request to the main hgcm thread. */
1877 HGCMMSGHANDLE hMsg = 0;
1878
1879 int rc = hgcmMsgAlloc (g_hgcmThread, &hMsg, HGCM_MSG_LOAD, hgcmMainMessageAlloc);
1880
1881 if (RT_SUCCESS(rc))
1882 {
1883 /* Initialize the message. Since the message is synchronous, use the supplied pointers. */
1884 HGCMMsgMainLoad *pMsg = (HGCMMsgMainLoad *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
1885 AssertRelease(pMsg);
1886
1887 pMsg->pszServiceLibrary = pszServiceLibrary;
1888 pMsg->pszServiceName = pszServiceName;
1889
1890 hgcmObjDereference (pMsg);
1891
1892 rc = hgcmMsgSend (hMsg);
1893 }
1894
1895 LogFlowFunc(("rc = %Rrc\n", rc));
1896 return rc;
1897}
1898
1899/* Register a HGCM service extension.
1900 *
1901 * @param pHandle Returned handle for the registered extension.
1902 * @param pszServiceName The name of the service.
1903 * @param pfnExtension The extension callback.
1904 * @return VBox rc.
1905 */
1906int HGCMHostRegisterServiceExtension (HGCMSVCEXTHANDLE *pHandle,
1907 const char *pszServiceName,
1908 PFNHGCMSVCEXT pfnExtension,
1909 void *pvExtension)
1910{
1911 LogFlowFunc(("pHandle = %p, name = %s, pfn = %p, rv = %p\n", pHandle, pszServiceName, pfnExtension, pvExtension));
1912
1913 if (!pHandle || !pszServiceName || !pfnExtension)
1914 {
1915 return VERR_INVALID_PARAMETER;
1916 }
1917
1918 /* Forward the request to the main hgcm thread. */
1919 HGCMMSGHANDLE hMsg = 0;
1920
1921 int rc = hgcmMsgAlloc (g_hgcmThread, &hMsg, HGCM_MSG_REGEXT, hgcmMainMessageAlloc);
1922
1923 if (RT_SUCCESS(rc))
1924 {
1925 /* Initialize the message. Since the message is synchronous, use the supplied pointers. */
1926 HGCMMsgMainRegisterExtension *pMsg = (HGCMMsgMainRegisterExtension *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
1927 AssertRelease(pMsg);
1928
1929 pMsg->pHandle = pHandle;
1930 pMsg->pszServiceName = pszServiceName;
1931 pMsg->pfnExtension = pfnExtension;
1932 pMsg->pvExtension = pvExtension;
1933
1934 hgcmObjDereference (pMsg);
1935
1936 rc = hgcmMsgSend (hMsg);
1937 }
1938
1939 LogFlowFunc(("*pHandle = %p, rc = %Rrc\n", *pHandle, rc));
1940 return rc;
1941}
1942
1943void HGCMHostUnregisterServiceExtension (HGCMSVCEXTHANDLE handle)
1944{
1945 LogFlowFunc(("handle = %p\n", handle));
1946
1947 /* Forward the request to the main hgcm thread. */
1948 HGCMMSGHANDLE hMsg = 0;
1949
1950 int rc = hgcmMsgAlloc (g_hgcmThread, &hMsg, HGCM_MSG_UNREGEXT, hgcmMainMessageAlloc);
1951
1952 if (RT_SUCCESS(rc))
1953 {
1954 /* Initialize the message. */
1955 HGCMMsgMainUnregisterExtension *pMsg = (HGCMMsgMainUnregisterExtension *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
1956 AssertRelease(pMsg);
1957
1958 pMsg->handle = handle;
1959
1960 hgcmObjDereference (pMsg);
1961
1962 rc = hgcmMsgSend (hMsg);
1963 }
1964
1965 LogFlowFunc(("rc = %Rrc\n", rc));
1966 return;
1967}
1968
1969/* Find a service and inform it about a client connection, create a client handle.
1970 *
1971 * @param pHGCMPort The port to be used for completion confirmation.
1972 * @param pCmd The VBox HGCM context.
1973 * @param pszServiceName The name of the service to be connected to.
1974 * @param pu32ClientId Where the store the created client handle.
1975 * @return VBox rc.
1976 */
1977int HGCMGuestConnect (PPDMIHGCMPORT pHGCMPort,
1978 PVBOXHGCMCMD pCmd,
1979 const char *pszServiceName,
1980 uint32_t *pu32ClientId)
1981{
1982 LogFlowFunc(("pHGCMPort = %p, pCmd = %p, name = %s, pu32ClientId = %p\n",
1983 pHGCMPort, pCmd, pszServiceName, pu32ClientId));
1984
1985 if (pHGCMPort == NULL || pCmd == NULL || pszServiceName == NULL || pu32ClientId == NULL)
1986 {
1987 return VERR_INVALID_PARAMETER;
1988 }
1989
1990 /* Forward the request to the main hgcm thread. */
1991 HGCMMSGHANDLE hMsg = 0;
1992
1993 int rc = hgcmMsgAlloc (g_hgcmThread, &hMsg, HGCM_MSG_CONNECT, hgcmMainMessageAlloc);
1994
1995 if (RT_SUCCESS(rc))
1996 {
1997 /* Initialize the message. Since 'pszServiceName' and 'pu32ClientId'
1998 * will not be deallocated by the caller until the message is completed,
1999 * use the supplied pointers.
2000 */
2001 HGCMMsgMainConnect *pMsg = (HGCMMsgMainConnect *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
2002 AssertRelease(pMsg);
2003
2004 pMsg->pHGCMPort = pHGCMPort;
2005 pMsg->pCmd = pCmd;
2006 pMsg->pszServiceName = pszServiceName;
2007 pMsg->pu32ClientId = pu32ClientId;
2008
2009 hgcmObjDereference (pMsg);
2010
2011 rc = hgcmMsgPost (hMsg, hgcmMsgCompletionCallback);
2012 }
2013
2014 LogFlowFunc(("rc = %Rrc\n", rc));
2015 return rc;
2016}
2017
2018/* Tell a service that the client is disconnecting, destroy the client handle.
2019 *
2020 * @param pHGCMPort The port to be used for completion confirmation.
2021 * @param pCmd The VBox HGCM context.
2022 * @param u32ClientId The client handle to be disconnected and deleted.
2023 * @return VBox rc.
2024 */
2025int HGCMGuestDisconnect (PPDMIHGCMPORT pHGCMPort,
2026 PVBOXHGCMCMD pCmd,
2027 uint32_t u32ClientId)
2028{
2029 LogFlowFunc(("pHGCMPort = %p, pCmd = %p, u32ClientId = %d\n",
2030 pHGCMPort, pCmd, u32ClientId));
2031
2032 if (!pHGCMPort || !pCmd || !u32ClientId)
2033 {
2034 return VERR_INVALID_PARAMETER;
2035 }
2036
2037 /* Forward the request to the main hgcm thread. */
2038 HGCMMSGHANDLE hMsg = 0;
2039
2040 int rc = hgcmMsgAlloc (g_hgcmThread, &hMsg, HGCM_MSG_DISCONNECT, hgcmMainMessageAlloc);
2041
2042 if (RT_SUCCESS(rc))
2043 {
2044 /* Initialize the message. */
2045 HGCMMsgMainDisconnect *pMsg = (HGCMMsgMainDisconnect *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
2046 AssertRelease(pMsg);
2047
2048 pMsg->pCmd = pCmd;
2049 pMsg->pHGCMPort = pHGCMPort;
2050 pMsg->u32ClientId = u32ClientId;
2051
2052 hgcmObjDereference (pMsg);
2053
2054 rc = hgcmMsgPost (hMsg, hgcmMsgCompletionCallback);
2055 }
2056
2057 LogFlowFunc(("rc = %Rrc\n", rc));
2058 return rc;
2059}
2060
2061/* Helper to send either HGCM_MSG_SAVESTATE or HGCM_MSG_LOADSTATE messages to the main HGCM thread.
2062 *
2063 * @param pSSM The SSM handle.
2064 * @param u32MsgId The message to be sent: HGCM_MSG_SAVESTATE or HGCM_MSG_LOADSTATE.
2065 * @return VBox rc.
2066 */
2067static int hgcmHostLoadSaveState (PSSMHANDLE pSSM,
2068 uint32_t u32MsgId)
2069{
2070 LogFlowFunc(("pSSM = %p, u32MsgId = %d\n", pSSM, u32MsgId));
2071
2072 HGCMMSGHANDLE hMsg = 0;
2073
2074 int rc = hgcmMsgAlloc (g_hgcmThread, &hMsg, u32MsgId, hgcmMainMessageAlloc);
2075
2076 if (RT_SUCCESS(rc))
2077 {
2078 HGCMMsgMainLoadSaveState *pMsg = (HGCMMsgMainLoadSaveState *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
2079 AssertRelease(pMsg);
2080
2081 pMsg->pSSM = pSSM;
2082
2083 hgcmObjDereference (pMsg);
2084
2085 rc = hgcmMsgSend (hMsg);
2086 }
2087
2088 LogFlowFunc(("rc = %Rrc\n", rc));
2089 return rc;
2090}
2091
2092/* Save the state of services.
2093 *
2094 * @param pSSM The SSM handle.
2095 * @return VBox rc.
2096 */
2097int HGCMHostSaveState (PSSMHANDLE pSSM)
2098{
2099 return hgcmHostLoadSaveState (pSSM, HGCM_MSG_SAVESTATE);
2100}
2101
2102/* Load the state of services.
2103 *
2104 * @param pSSM The SSM handle.
2105 * @return VBox rc.
2106 */
2107int HGCMHostLoadState (PSSMHANDLE pSSM)
2108{
2109 return hgcmHostLoadSaveState (pSSM, HGCM_MSG_LOADSTATE);
2110}
2111
2112/* The guest calls the service.
2113 *
2114 * @param pHGCMPort The port to be used for completion confirmation.
2115 * @param pCmd The VBox HGCM context.
2116 * @param u32ClientId The client handle to be disconnected and deleted.
2117 * @param u32Function The function number.
2118 * @param cParms Number of parameters.
2119 * @param paParms Pointer to array of parameters.
2120 * @return VBox rc.
2121 */
2122int HGCMGuestCall (PPDMIHGCMPORT pHGCMPort,
2123 PVBOXHGCMCMD pCmd,
2124 uint32_t u32ClientId,
2125 uint32_t u32Function,
2126 uint32_t cParms,
2127 VBOXHGCMSVCPARM *paParms)
2128{
2129 LogFlowFunc(("pHGCMPort = %p, pCmd = %p, u32ClientId = %d, u32Function = %d, cParms = %d, paParms = %p\n",
2130 pHGCMPort, pCmd, u32ClientId, u32Function, cParms, paParms));
2131
2132 if (!pHGCMPort || !pCmd || u32ClientId == 0)
2133 {
2134 return VERR_INVALID_PARAMETER;
2135 }
2136
2137 int rc = VERR_HGCM_INVALID_CLIENT_ID;
2138
2139 /* Resolve the client handle to the client instance pointer. */
2140 HGCMClient *pClient = (HGCMClient *)hgcmObjReference (u32ClientId, HGCMOBJ_CLIENT);
2141
2142 if (pClient)
2143 {
2144 AssertRelease(pClient->pService);
2145
2146 /* Forward the message to the service thread. */
2147 rc = pClient->pService->GuestCall (pHGCMPort, pCmd, u32ClientId, u32Function, cParms, paParms);
2148
2149 hgcmObjDereference (pClient);
2150 }
2151
2152 LogFlowFunc(("rc = %Rrc\n", rc));
2153 return rc;
2154}
2155
2156/* The host calls the service.
2157 *
2158 * @param pszServiceName The service name to be called.
2159 * @param u32Function The function number.
2160 * @param cParms Number of parameters.
2161 * @param paParms Pointer to array of parameters.
2162 * @return VBox rc.
2163 */
2164int HGCMHostCall (const char *pszServiceName,
2165 uint32_t u32Function,
2166 uint32_t cParms,
2167 VBOXHGCMSVCPARM *paParms)
2168{
2169 LogFlowFunc(("name = %s, u32Function = %d, cParms = %d, paParms = %p\n",
2170 pszServiceName, u32Function, cParms, paParms));
2171
2172 if (!pszServiceName)
2173 {
2174 return VERR_INVALID_PARAMETER;
2175 }
2176
2177 HGCMMSGHANDLE hMsg = 0;
2178
2179 /* Host calls go to main HGCM thread that resolves the service name to the
2180 * service instance pointer and then, using the service pointer, forwards
2181 * the message to the service thread.
2182 * So it is slow but host calls are intended mostly for configuration and
2183 * other non-time-critical functions.
2184 */
2185 int rc = hgcmMsgAlloc (g_hgcmThread, &hMsg, HGCM_MSG_HOSTCALL, hgcmMainMessageAlloc);
2186
2187 if (RT_SUCCESS(rc))
2188 {
2189 HGCMMsgMainHostCall *pMsg = (HGCMMsgMainHostCall *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
2190 AssertRelease(pMsg);
2191
2192 pMsg->pszServiceName = (char *)pszServiceName;
2193 pMsg->u32Function = u32Function;
2194 pMsg->cParms = cParms;
2195 pMsg->paParms = paParms;
2196
2197 hgcmObjDereference (pMsg);
2198
2199 rc = hgcmMsgSend (hMsg);
2200 }
2201
2202 LogFlowFunc(("rc = %Rrc\n", rc));
2203 return rc;
2204}
2205
2206int HGCMHostReset (void)
2207{
2208 LogFlowFunc(("\n"));
2209
2210 /* Disconnect all clients.
2211 */
2212
2213 HGCMMSGHANDLE hMsg = 0;
2214
2215 int rc = hgcmMsgAlloc (g_hgcmThread, &hMsg, HGCM_MSG_RESET, hgcmMainMessageAlloc);
2216
2217 if (RT_SUCCESS(rc))
2218 {
2219 rc = hgcmMsgSend (hMsg);
2220 }
2221
2222 LogFlowFunc(("rc = %Rrc\n", rc));
2223 return rc;
2224}
2225
2226int HGCMHostInit (void)
2227{
2228 LogFlowFunc(("\n"));
2229
2230 int rc = hgcmThreadInit ();
2231
2232 if (RT_SUCCESS(rc))
2233 {
2234 /*
2235 * Start main HGCM thread.
2236 */
2237
2238 rc = hgcmThreadCreate (&g_hgcmThread, "MainHGCMthread", hgcmThread, NULL);
2239
2240 if (RT_FAILURE(rc))
2241 {
2242 LogRel(("Failed to start HGCM thread. HGCM services will be unavailable!!! rc = %Rrc\n", rc));
2243 }
2244 }
2245
2246 LogFlowFunc(("rc = %Rrc\n", rc));
2247 return rc;
2248}
2249
2250int HGCMHostShutdown (void)
2251{
2252 LogFlowFunc(("\n"));
2253
2254 /*
2255 * Do HGCMReset and then unload all services.
2256 */
2257
2258 int rc = HGCMHostReset ();
2259
2260 if (RT_SUCCESS(rc))
2261 {
2262 /* Send the quit message to the main hgcmThread. */
2263 HGCMMSGHANDLE hMsg = 0;
2264
2265 rc = hgcmMsgAlloc (g_hgcmThread, &hMsg, HGCM_MSG_QUIT, hgcmMainMessageAlloc);
2266
2267 if (RT_SUCCESS(rc))
2268 {
2269 rc = hgcmMsgSend (hMsg);
2270
2271 if (RT_SUCCESS(rc))
2272 {
2273 /* Wait for the thread termination. */
2274 hgcmThreadWait (g_hgcmThread);
2275 g_hgcmThread = 0;
2276
2277 hgcmThreadUninit ();
2278 }
2279 }
2280 }
2281
2282 LogFlowFunc(("rc = %Rrc\n", rc));
2283 return rc;
2284}
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