VirtualBox

source: vbox/trunk/src/VBox/Main/src-client/HGCM.cpp@ 75392

Last change on this file since 75392 was 75385, checked in by vboxsync, 6 years ago

Main/HGCMService::LoadState: don't use alloca inside a loop.

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