VirtualBox

source: vbox/trunk/src/VBox/Frontends/VBoxBFE/HGCM.cpp@ 16827

Last change on this file since 16827 was 13837, checked in by vboxsync, 16 years ago

s/%Vr\([acfs]\)/%Rr\1/g - since I'm upsetting everyone anyway, better make the most of it...

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