VirtualBox

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

Last change on this file since 8455 was 8155, checked in by vboxsync, 17 years ago

The Big Sun Rebranding Header Change

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