VirtualBox

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

Last change on this file since 1634 was 1577, checked in by vboxsync, 18 years ago

Do not access already completed message in HGCM.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 44.4 KB
Line 
1/** @file
2 *
3 * HGCM (Host-Guest Communication Manager)
4 */
5
6/*
7 * Copyright (C) 2006 InnoTek Systemberatung GmbH
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 as published by the Free Software Foundation,
13 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
14 * distribution. VirtualBox OSE is distributed in the hope that it will
15 * be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * If you received this file as part of a commercial VirtualBox
18 * distribution, then only the terms of your commercial VirtualBox
19 * license agreement apply instead of the previous paragraph.
20 */
21
22
23/*
24 * NOT FOR REVIEWING YET. A LOT OF TODO/MISSED/INCOMPLETE/SKETCH CODE INSIDE!
25 */
26
27#define LOG_GROUP_MAIN_OVERRIDE LOG_GROUP_HGCM
28#include "Logging.h"
29
30#include <string.h>
31
32#include "hgcm/HGCM.h"
33#include "hgcm/HGCMThread.h"
34
35#include <VBox/err.h>
36#include <VBox/hgcmsvc.h>
37
38#include <iprt/alloc.h>
39#include <iprt/avl.h>
40#include <iprt/critsect.h>
41#include <iprt/asm.h>
42#include <iprt/ldr.h>
43#include <iprt/string.h>
44#include <iprt/semaphore.h>
45#include <iprt/thread.h>
46
47#include <VBox/VBoxGuest.h>
48
49/**
50 *
51 * Service location types:
52 *
53 * LOCAL SERVICE
54 * service DLL is loaded by the VM process,
55 * and directly called by the VM HGCM instance.
56 */
57
58/**
59 * A service gets one thread, which synchronously delivers messages to
60 * the service. This is good for serialization.
61 *
62 * Some services may want to process messages asynchronously, and will want
63 * a next message to be delivered, while a previous message is still being
64 * processed.
65 *
66 * The dedicated service thread delivers a next message when service
67 * returns after fetching a previous one. The service will call a message
68 * completion callback when message is actually processed. So returning
69 * from the service call means only that the service is processing message.
70 *
71 * 'Message processed' condition is indicated by service, which call the
72 * callback, even if the callback is called synchronously in the dedicated
73 * thread.
74 *
75 * This message completion callback is only valid for Call requests.
76 * Connect and Disconnect are processed sznchronously by service.
77 *
78 */
79
80/** @todo services registration, only registered service dll can be loaded */
81
82/** @todo a registered LOCAL service must also get a thread, for now
83 * a thread per service (later may be there will be an option to
84 * have a thread per client for a service, however I do not think it's
85 * really necessary).
86 * The requests will be queued and executed by the service thread,
87 * an IRQ notification will be ussued when a request is completed.
88 *
89 * May be other services (like VRDP acceleration) should still use
90 * the EMT thread, because they have their own threads for long
91 * operations.
92 * So we have to distinguish those services during
93 * registration process (external/internal registration).
94 * External dlls will always have its own thread,
95 * internal (trusted) services will choose between having executed
96 * on EMT or on a separate thread.
97 *
98 */
99
100
101/** Internal helper service object. HGCM code would use it to
102 * hold information about services and communicate with services.
103 * The HGCMService is an (in future) abstract class that implements
104 * common functionality. There will be derived classes for specific
105 * service types (Local, etc).
106 */
107
108/** @todo should be HGCMObject */
109class HGCMService
110{
111 private:
112 VBOXHGCMSVCHELPERS m_svcHelpers;
113
114 static HGCMService *sm_pSvcListHead;
115 static HGCMService *sm_pSvcListTail;
116
117
118 HGCMTHREADHANDLE m_thread;
119 friend DECLCALLBACK(void) hgcmServiceThread (HGCMTHREADHANDLE ThreadHandle, void *pvUser);
120
121 uint32_t volatile m_u32RefCnt;
122
123 HGCMService *m_pSvcNext;
124 HGCMService *m_pSvcPrev;
125
126 char *m_pszSvcName;
127 char *m_pszSvcLibrary;
128
129 PPDMIHGCMPORT m_pHGCMPort;
130
131 RTLDRMOD m_hLdrMod;
132 PFNVBOXHGCMSVCLOAD m_pfnLoad;
133
134 VBOXHGCMSVCFNTABLE m_fntable;
135
136 int m_cClients;
137 int m_cClientsAllocated;
138
139 uint32_t *m_paClientIds;
140
141 int loadServiceDLL (void);
142 void unloadServiceDLL (void);
143
144 int InstanceCreate (const char *pszServiceLibrary, const char *pszServiceName, PPDMIHGCMPORT pHGCMPort);
145 void InstanceDestroy (void);
146
147 HGCMService ();
148 ~HGCMService () {};
149
150 bool EqualToLoc (HGCMServiceLocation *loc);
151
152 static DECLCALLBACK(void) svcHlpCallComplete (VBOXHGCMCALLHANDLE callHandle, int32_t rc);
153
154 public:
155
156 static void Reset (void);
157
158 static int FindService (HGCMService **ppsvc, HGCMServiceLocation *loc);
159 static HGCMService *FindServiceByName (const char *pszServiceName);
160 static int LoadService (const char *pszServiceLibrary, const char *pszServiceName, PPDMIHGCMPORT pHGCMPort);
161 void ReleaseService (void);
162
163 uint32_t SizeOfClient (void) { return m_fntable.cbClient; };
164
165 void DisconnectAll (void);
166
167 int Connect (uint32_t u32ClientID);
168 int Disconnect (uint32_t u32ClientID);
169 int GuestCall (PPDMIHGCMPORT pHGCMPort, PVBOXHGCMCMD pCmd, uint32_t u32ClientID, uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM aParms[], bool fBlock);
170 int HostCall (PVBOXHGCMCMD pCmd, uint32_t u32ClientID, uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM aParms[]);
171
172 int SaveState(uint32_t u32ClientID, PSSMHANDLE pSSM);
173 int LoadState(uint32_t u32ClientID, PSSMHANDLE pSSM);
174};
175
176
177class HGCMClient: public HGCMObject
178{
179 public:
180 HGCMClient () : HGCMObject(HGCMOBJ_CLIENT) {};
181 ~HGCMClient ();
182
183 int Init (HGCMService *pSvc);
184
185 /** Service that the client is connected to. */
186 HGCMService *pService;
187
188 /** Client specific data. */
189 void *pvData;
190};
191
192HGCMClient::~HGCMClient ()
193{
194 RTMemFree (pvData);
195}
196
197int HGCMClient::Init (HGCMService *pSvc)
198{
199 pService = pSvc;
200
201 if (pService->SizeOfClient () > 0)
202 {
203 pvData = RTMemAllocZ (pService->SizeOfClient ());
204
205 if (!pvData)
206 {
207 return VERR_NO_MEMORY;
208 }
209 }
210
211 return VINF_SUCCESS;
212}
213
214
215#define HGCM_CLIENT_DATA(pService, pClient) (pClient->pvData)
216
217
218/*
219 * Messages processed by worker threads.
220 */
221
222#define HGCMMSGID_SVC_LOAD (0)
223#define HGCMMSGID_SVC_UNLOAD (1)
224#define HGCMMSGID_SVC_CONNECT (2)
225#define HGCMMSGID_SVC_DISCONNECT (3)
226#define HGCMMSGID_GUESTCALL (4)
227
228class HGCMMsgSvcLoad: public HGCMMsgCore
229{
230};
231
232class HGCMMsgSvcUnload: public HGCMMsgCore
233{
234};
235
236class HGCMMsgSvcConnect: public HGCMMsgCore
237{
238 public:
239 /* client identifier */
240 uint32_t u32ClientID;
241};
242
243class HGCMMsgSvcDisconnect: public HGCMMsgCore
244{
245 public:
246 /* client identifier */
247 uint32_t u32ClientID;
248};
249
250class HGCMMsgHeader: public HGCMMsgCore
251{
252 public:
253 HGCMMsgHeader () : pCmd (NULL), pHGCMPort (NULL) {};
254
255 /* Command pointer/identifier. */
256 PVBOXHGCMCMD pCmd;
257
258 /* Port to be informed on message completion. */
259 PPDMIHGCMPORT pHGCMPort;
260};
261
262
263class HGCMMsgCall: public HGCMMsgHeader
264{
265 public:
266 /* client identifier */
267 uint32_t u32ClientID;
268
269 /* function number */
270 uint32_t u32Function;
271
272 /* number of parameters */
273 uint32_t cParms;
274
275 VBOXHGCMSVCPARM *paParms;
276};
277
278
279/*
280 * Messages processed by main HGCM thread.
281 */
282
283#define HGCMMSGID_CONNECT (10)
284#define HGCMMSGID_DISCONNECT (11)
285#define HGCMMSGID_LOAD (12)
286#define HGCMMSGID_HOSTCALL (13)
287#define HGCMMSGID_LOADSTATE (14)
288#define HGCMMSGID_SAVESTATE (15)
289#define HGCMMSGID_RESET (16)
290
291class HGCMMsgConnect: public HGCMMsgHeader
292{
293 public:
294 /* service location */
295 HGCMSERVICELOCATION *pLoc;
296
297 /* client identifier */
298 uint32_t *pu32ClientID;
299
300};
301
302class HGCMMsgDisconnect: public HGCMMsgHeader
303{
304 public:
305 /* client identifier */
306 uint32_t u32ClientID;
307};
308
309class HGCMMsgLoadSaveState: public HGCMMsgHeader
310{
311 public:
312 /* client identifier */
313 uint32_t u32ClientID;
314 PSSMHANDLE pSSM;
315};
316
317class HGCMMsgLoad: public HGCMMsgHeader
318{
319 public:
320 virtual ~HGCMMsgLoad ()
321 {
322 RTStrFree (pszServiceLibrary);
323 RTStrFree (pszServiceName);
324 }
325
326 int Init (const char *pszName, const char *pszLibrary)
327 {
328 pszServiceName = RTStrDup (pszName);
329 pszServiceLibrary = RTStrDup (pszLibrary);
330
331 if (!pszServiceName || !pszServiceLibrary)
332 {
333 RTStrFree (pszServiceLibrary);
334 RTStrFree (pszServiceName);
335 pszServiceLibrary = NULL;
336 pszServiceName = NULL;
337 return VERR_NO_MEMORY;
338 }
339
340 return VINF_SUCCESS;
341 }
342
343 char *pszServiceName;
344 char *pszServiceLibrary;
345};
346
347class HGCMMsgHostCall: public HGCMMsgHeader
348{
349 public:
350 char *pszServiceName;
351
352 /* function number */
353 uint32_t u32Function;
354
355 /* number of parameters */
356 uint32_t cParms;
357
358 VBOXHGCMSVCPARM *paParms;
359};
360
361class HGCMMsgReset: public HGCMMsgHeader
362{
363};
364
365/* static */ DECLCALLBACK(void) HGCMService::svcHlpCallComplete (VBOXHGCMCALLHANDLE callHandle, int32_t rc)
366{
367 HGCMMsgCore *pMsgCore = (HGCMMsgCore *)callHandle;
368
369 if ( pMsgCore->MsgId () == HGCMMSGID_GUESTCALL
370 || pMsgCore->MsgId () == HGCMMSGID_HOSTCALL)
371 {
372 /* Only call the completion for these messages. The helper
373 * is called by the service, and the service does not get
374 * any other messages.
375 */
376 hgcmMsgComplete (pMsgCore, rc);
377 }
378 else
379 {
380 AssertFailed ();
381 }
382}
383
384HGCMService *HGCMService::sm_pSvcListHead = NULL;
385HGCMService *HGCMService::sm_pSvcListTail = NULL;
386
387HGCMService::HGCMService ()
388 :
389 m_thread (0),
390 m_u32RefCnt (0),
391 m_pSvcNext (NULL),
392 m_pSvcPrev (NULL),
393 m_pszSvcName (NULL),
394 m_pszSvcLibrary (NULL),
395 m_hLdrMod (NIL_RTLDRMOD),
396 m_pfnLoad (NULL),
397 m_cClients (0),
398 m_cClientsAllocated (0),
399 m_paClientIds (NULL)
400{
401 memset (&m_fntable, 0, sizeof (m_fntable));
402}
403
404
405HGCMMsgCore *hgcmMessageAlloc (uint32_t u32MsgId)
406{
407 switch (u32MsgId)
408 {
409 case HGCMMSGID_SVC_LOAD: return new HGCMMsgSvcLoad ();
410 case HGCMMSGID_SVC_UNLOAD: return new HGCMMsgSvcUnload ();
411 case HGCMMSGID_SVC_CONNECT: return new HGCMMsgSvcConnect ();
412 case HGCMMSGID_SVC_DISCONNECT: return new HGCMMsgSvcDisconnect ();
413 case HGCMMSGID_GUESTCALL: return new HGCMMsgCall ();
414
415 case HGCMMSGID_CONNECT: return new HGCMMsgConnect ();
416 case HGCMMSGID_DISCONNECT: return new HGCMMsgDisconnect ();
417 case HGCMMSGID_LOAD: return new HGCMMsgLoad ();
418 case HGCMMSGID_HOSTCALL: return new HGCMMsgHostCall ();
419 case HGCMMSGID_LOADSTATE:
420 case HGCMMSGID_SAVESTATE: return new HGCMMsgLoadSaveState ();
421 case HGCMMSGID_RESET: return new HGCMMsgReset ();
422 default:
423 Log(("hgcmMessageAlloc::Unsupported message number %08X\n", u32MsgId));
424 AssertReleaseMsgFailed(("Msg id = %08X\n", u32MsgId));
425 }
426
427 return NULL;
428}
429
430static bool g_fResetting = false;
431
432static DECLCALLBACK(void) hgcmMsgCompletionCallback (int32_t result, HGCMMsgCore *pMsgCore)
433{
434 /* Call the VMMDev port interface to issue IRQ notification. */
435 HGCMMsgHeader *pMsgHdr = (HGCMMsgHeader *)pMsgCore;
436
437 LogFlow(("MAIN::hgcmMsgCompletionCallback: message %p\n", pMsgCore));
438
439 if (pMsgHdr->pHGCMPort && !g_fResetting)
440 {
441 pMsgHdr->pHGCMPort->pfnCompleted (pMsgHdr->pHGCMPort, result, pMsgHdr->pCmd);
442 }
443
444 return;
445}
446
447
448DECLCALLBACK(void) hgcmServiceThread (HGCMTHREADHANDLE ThreadHandle, void *pvUser)
449{
450 int rc = VINF_SUCCESS;
451
452 HGCMService *pSvc = (HGCMService *)pvUser;
453
454 AssertRelease(pSvc != NULL);
455
456 HGCMMsgCore *pMsgCore = NULL;
457
458 bool bUnloaded = false;
459
460 while (!bUnloaded)
461 {
462 rc = hgcmMsgGet (ThreadHandle, &pMsgCore);
463
464 if (VBOX_FAILURE (rc))
465 {
466 Log(("hgcmServiceThread: message get failed, rc = %Vrc\n", rc));
467
468 RTThreadSleep(100);
469
470 continue;
471 }
472
473 /* Cache required information to avoid unnecessary pMsgCore access. */
474 uint32_t u32MsgId = pMsgCore->MsgId ();
475
476 switch (u32MsgId)
477 {
478 case HGCMMSGID_SVC_LOAD:
479 {
480 LogFlow(("HGCMMSGID_SVC_LOAD\n"));
481 rc = pSvc->loadServiceDLL ();
482 } break;
483
484 case HGCMMSGID_SVC_UNLOAD:
485 {
486 LogFlow(("HGCMMSGID_SVC_UNLOAD\n"));
487 pSvc->unloadServiceDLL ();
488 bUnloaded = true;
489 } break;
490
491 case HGCMMSGID_SVC_CONNECT:
492 {
493 LogFlow(("HGCMMSGID_SVC_CONNECT\n"));
494
495 HGCMMsgSvcConnect *pMsg = (HGCMMsgSvcConnect *)pMsgCore;
496
497 rc = VINF_SUCCESS;
498
499 HGCMClient *pClient = (HGCMClient *)hgcmObjReference (pMsg->u32ClientID, HGCMOBJ_CLIENT);
500
501 if (pClient)
502 {
503 rc = pSvc->m_fntable.pfnConnect (pMsg->u32ClientID, HGCM_CLIENT_DATA(pSvc, pClient));
504
505 hgcmObjDereference (pClient);
506 }
507 } break;
508
509 case HGCMMSGID_SVC_DISCONNECT:
510 {
511 LogFlow(("HGCMMSGID_SVC_DISCONNECT\n"));
512
513 HGCMMsgSvcDisconnect *pMsg = (HGCMMsgSvcDisconnect *)pMsgCore;
514
515 rc = VINF_SUCCESS;
516
517 HGCMClient *pClient = (HGCMClient *)hgcmObjReference (pMsg->u32ClientID, HGCMOBJ_CLIENT);
518
519 if (pClient)
520 {
521 rc = pSvc->m_fntable.pfnDisconnect (pMsg->u32ClientID, HGCM_CLIENT_DATA(pSvc, pClient));
522
523 hgcmObjDereference (pClient);
524 }
525 } break;
526
527 case HGCMMSGID_GUESTCALL:
528 {
529 LogFlow(("HGCMMSGID_GUESTCALL\n"));
530
531 HGCMMsgCall *pMsg = (HGCMMsgCall *)pMsgCore;
532
533 rc = VINF_SUCCESS;
534
535 HGCMClient *pClient = (HGCMClient *)hgcmObjReference (pMsg->u32ClientID, HGCMOBJ_CLIENT);
536
537 if (pClient)
538 {
539 pSvc->m_fntable.pfnCall ((VBOXHGCMCALLHANDLE)pMsg, pMsg->u32ClientID, HGCM_CLIENT_DATA(pSvc, pClient), pMsg->u32Function, pMsg->cParms, pMsg->paParms);
540
541 hgcmObjDereference (pClient);
542 }
543 else
544 {
545 rc = VERR_HGCM_INVALID_CLIENT_ID;
546 }
547 } break;
548
549 case HGCMMSGID_HOSTCALL:
550 {
551 LogFlow(("HGCMMSGID_HOSTCALL\n"));
552
553 HGCMMsgHostCall *pMsg = (HGCMMsgHostCall *)pMsgCore;
554
555 pSvc->m_fntable.pfnHostCall ((VBOXHGCMCALLHANDLE)pMsg, 0, NULL, pMsg->u32Function, pMsg->cParms, pMsg->paParms);
556
557 rc = VINF_SUCCESS;
558 } break;
559
560 case HGCMMSGID_LOADSTATE:
561 {
562 LogFlow(("HGCMMSGID_LOADSTATE\n"));
563
564 HGCMMsgLoadSaveState *pMsg = (HGCMMsgLoadSaveState *)pMsgCore;
565 HGCMClient *pClient = (HGCMClient *)hgcmObjReference (pMsg->u32ClientID, HGCMOBJ_CLIENT);
566
567 rc = VINF_SUCCESS;
568 if (pClient && pSvc->m_fntable.pfnLoadState)
569 {
570 rc = pSvc->m_fntable.pfnLoadState (pMsg->u32ClientID, HGCM_CLIENT_DATA(pSvc, pClient), pMsg->pSSM);
571 hgcmObjDereference (pClient);
572 }
573 break;
574 }
575
576 case HGCMMSGID_SAVESTATE:
577 {
578 LogFlow(("HGCMMSGID_SAVESTATE\n"));
579
580 HGCMMsgLoadSaveState *pMsg = (HGCMMsgLoadSaveState *)pMsgCore;
581 HGCMClient *pClient = (HGCMClient *)hgcmObjReference (pMsg->u32ClientID, HGCMOBJ_CLIENT);
582
583 rc = VINF_SUCCESS;
584 if (pClient && pSvc->m_fntable.pfnSaveState)
585 {
586 rc = pSvc->m_fntable.pfnSaveState (pMsg->u32ClientID, HGCM_CLIENT_DATA(pSvc, pClient), pMsg->pSSM);
587 hgcmObjDereference (pClient);
588 }
589 break;
590 }
591
592 default:
593 {
594 Log(("hgcmServiceThread::Unsupported message number %08X\n", u32MsgId));
595 rc = VERR_NOT_SUPPORTED;
596 } break;
597 }
598
599 if ( u32MsgId != HGCMMSGID_GUESTCALL
600 && u32MsgId != HGCMMSGID_HOSTCALL)
601 {
602 /* For HGCMMSGID_GUESTCALL & HGCMMSGID_HOSTCALL the service
603 * calls the completion helper. Other messages have to be
604 * completed here.
605 */
606 hgcmMsgComplete (pMsgCore, rc);
607 }
608 }
609
610 return;
611}
612
613int HGCMService::InstanceCreate (const char *pszServiceLibrary, const char *pszServiceName, PPDMIHGCMPORT pHGCMPort)
614{
615 int rc = VINF_SUCCESS;
616
617 LogFlow(("HGCMService::InstanceCreate: name %s, lib %s\n", pszServiceName, pszServiceLibrary));
618
619 char achThreadName[14];
620
621 RTStrPrintf (achThreadName, sizeof (achThreadName), "HGCM%08X", this);
622
623 rc = hgcmThreadCreate (&m_thread, achThreadName, hgcmServiceThread, this);
624
625 if (VBOX_SUCCESS(rc))
626 {
627 m_pszSvcName = RTStrDup (pszServiceName);
628 m_pszSvcLibrary = RTStrDup (pszServiceLibrary);
629
630 if (!m_pszSvcName || !m_pszSvcLibrary)
631 {
632 RTStrFree (m_pszSvcLibrary);
633 m_pszSvcLibrary = NULL;
634
635 RTStrFree (m_pszSvcName);
636 m_pszSvcName = NULL;
637
638 rc = VERR_NO_MEMORY;
639 }
640 else
641 {
642 m_pHGCMPort = pHGCMPort;
643
644 m_svcHelpers.pfnCallComplete = svcHlpCallComplete;
645 m_svcHelpers.pvInstance = this;
646
647 /* Execute the load request on the service thread. */
648 HGCMMSGHANDLE hMsg;
649
650 rc = hgcmMsgAlloc (m_thread, &hMsg, HGCMMSGID_SVC_LOAD, hgcmMessageAlloc);
651
652 if (VBOX_SUCCESS(rc))
653 {
654 rc = hgcmMsgSend (hMsg);
655 }
656 }
657 }
658 else
659 {
660 Log(("HGCMService::InstanceCreate: FAILURE: service thread creation\n"));
661 }
662
663 if (VBOX_FAILURE(rc))
664 {
665 InstanceDestroy ();
666 }
667
668 LogFlow(("HGCMService::InstanceCreate rc = %Vrc\n", rc));
669
670 return rc;
671}
672
673void HGCMService::InstanceDestroy (void)
674{
675 HGCMMSGHANDLE hMsg;
676
677 LogFlow(("HGCMService::InstanceDestroy\n"));
678
679 int rc = hgcmMsgAlloc (m_thread, &hMsg, HGCMMSGID_SVC_UNLOAD, hgcmMessageAlloc);
680
681 if (VBOX_SUCCESS(rc))
682 {
683 rc = hgcmMsgSend (hMsg);
684 }
685
686 RTStrFree (m_pszSvcLibrary);
687 m_pszSvcLibrary = NULL;
688 RTStrFree (m_pszSvcName);
689 m_pszSvcName = NULL;
690
691 LogFlow(("HGCMService::InstanceDestroy completed\n"));
692}
693
694bool HGCMService::EqualToLoc (HGCMServiceLocation *loc)
695{
696 if (!loc || (loc->type != VMMDevHGCMLoc_LocalHost && loc->type != VMMDevHGCMLoc_LocalHost_Existing))
697 {
698 return false;
699 }
700
701 if (strcmp (m_pszSvcName, loc->u.host.achName) != 0)
702 {
703 return false;
704 }
705
706 return true;
707}
708
709/** Services are searched by FindService function which is called
710 * by the main HGCM thread during CONNECT message processing.
711 * Reference count of the service is increased.
712 * Services are loaded by the LoadService function.
713 * Note: both methods are executed by the main HGCM thread.
714 */
715/* static */ int HGCMService::FindService (HGCMService **ppsvc, HGCMServiceLocation *loc)
716{
717 HGCMService *psvc = NULL;
718
719 LogFlow(("HGCMService::FindService: loc = %p\n", loc));
720
721 if (!loc || (loc->type != VMMDevHGCMLoc_LocalHost && loc->type != VMMDevHGCMLoc_LocalHost_Existing))
722 {
723 return VERR_INVALID_PARAMETER;
724 }
725
726 LogFlow(("HGCMService::FindService: name %s\n", loc->u.host.achName));
727
728 /* Look at already loaded services. */
729 psvc = sm_pSvcListHead;
730
731 while (psvc)
732 {
733 if (psvc->EqualToLoc (loc))
734 {
735 break;
736 }
737
738 psvc = psvc->m_pSvcNext;
739 }
740
741 LogFlow(("HGCMService::FindService: lookup in the list is %p\n", psvc));
742
743 if (psvc)
744 {
745 ASMAtomicIncU32 (&psvc->m_u32RefCnt);
746
747 *ppsvc = psvc;
748
749 return VINF_SUCCESS;
750 }
751
752 return VERR_ACCESS_DENIED;
753}
754
755/* static */ HGCMService *HGCMService::FindServiceByName (const char *pszServiceName)
756{
757 HGCMService *psvc = sm_pSvcListHead;
758
759 while (psvc)
760 {
761 if (strcmp (psvc->m_pszSvcName, pszServiceName) == 0)
762 {
763 break;
764 }
765
766 psvc = psvc->m_pSvcNext;
767 }
768
769 return psvc;
770}
771
772/* static */ int HGCMService::LoadService (const char *pszServiceLibrary, const char *pszServiceName, PPDMIHGCMPORT pHGCMPort)
773{
774 int rc = VINF_SUCCESS;
775
776 HGCMService *psvc = NULL;
777
778 LogFlow(("HGCMService::LoadService: name = %s, lib %s\n", pszServiceName, pszServiceLibrary));
779
780 /* Look at already loaded services to avoid double loading. */
781 psvc = FindServiceByName (pszServiceName);
782
783 if (psvc)
784 {
785 LogFlow(("HGCMService::LoadService: Service already exists %p!!!\n", psvc));
786 }
787 else
788 {
789 psvc = new HGCMService ();
790
791 if (!psvc)
792 {
793 Log(("HGCMService::Load: memory allocation for the service failed!!!\n"));
794 rc = VERR_NO_MEMORY;
795 }
796
797 if (VBOX_SUCCESS(rc))
798 {
799 rc = psvc->InstanceCreate (pszServiceLibrary, pszServiceName, pHGCMPort);
800
801 if (VBOX_SUCCESS(rc))
802 {
803 /* Insert the just created service to list for future references. */
804 psvc->m_pSvcNext = sm_pSvcListHead;
805 psvc->m_pSvcPrev = NULL;
806
807 if (sm_pSvcListHead)
808 {
809 sm_pSvcListHead->m_pSvcPrev = psvc;
810 }
811 else
812 {
813 sm_pSvcListTail = psvc;
814 }
815
816 sm_pSvcListHead = psvc;
817
818 LogFlow(("HGCMService::LoadService: service %p\n", psvc));
819 }
820 }
821 }
822
823 return rc;
824}
825
826/* static */ void HGCMService::Reset (void)
827{
828 /* This is called when the VM is being reset,
829 * that is no more requests from guest is expected.
830 * Scan al services and disconnect all clients.
831 */
832
833 g_fResetting = true;
834
835 HGCMService *psvc = sm_pSvcListHead;
836
837 while (psvc)
838 {
839 psvc->DisconnectAll ();
840
841 psvc = psvc->m_pSvcNext;
842 }
843
844 g_fResetting = false;
845}
846
847void HGCMService::ReleaseService (void)
848{
849 uint32_t u32RefCnt = ASMAtomicDecU32 (&m_u32RefCnt);
850
851 AssertRelease(u32RefCnt != ~0U);
852
853 if (u32RefCnt == 0)
854 {
855 /** @todo We do not unload services. Cache them all. Unloading will be later. HGCMObject! */
856
857 LogFlow(("HGCMService::ReleaseService: no more references.\n"));
858
859// InstanceDestroy ();
860
861// delete this;
862 }
863}
864
865/** Helper function to load a local service DLL.
866 *
867 * @return VBox code
868 */
869int HGCMService::loadServiceDLL (void)
870{
871 LogFlow(("HGCMService::loadServiceDLL: m_pszSvcLibrary = %s\n", m_pszSvcLibrary));
872
873 if (m_pszSvcLibrary == NULL)
874 {
875 return VERR_INVALID_PARAMETER;
876 }
877
878 int rc = VINF_SUCCESS;
879
880 rc = RTLdrLoad (m_pszSvcLibrary, &m_hLdrMod);
881
882 if (VBOX_SUCCESS(rc))
883 {
884 LogFlow(("HGCMService::loadServiceDLL: successfully loaded the library.\n"));
885
886 m_pfnLoad = NULL;
887
888 rc = RTLdrGetSymbol (m_hLdrMod, VBOX_HGCM_SVCLOAD_NAME, (void**)&m_pfnLoad);
889
890 if (VBOX_FAILURE (rc) || !m_pfnLoad)
891 {
892 Log(("HGCMService::loadServiceDLL: Error resolving the service entry point %s, rc = %d, m_pfnLoad = %p\n", VBOX_HGCM_SVCLOAD_NAME, rc, m_pfnLoad));
893
894 if (VBOX_SUCCESS(rc))
895 {
896 /* m_pfnLoad was NULL */
897 rc = VERR_SYMBOL_NOT_FOUND;
898 }
899 }
900
901 if (VBOX_SUCCESS(rc))
902 {
903 memset (&m_fntable, 0, sizeof (m_fntable));
904
905 m_fntable.cbSize = sizeof (m_fntable);
906 m_fntable.u32Version = VBOX_HGCM_SVC_VERSION;
907 m_fntable.pHelpers = &m_svcHelpers;
908
909 rc = m_pfnLoad (&m_fntable);
910
911 LogFlow(("HGCMService::loadServiceDLL: m_pfnLoad rc = %Vrc\n", rc));
912
913 if (VBOX_SUCCESS (rc))
914 {
915 if ( m_fntable.pfnUnload == NULL
916 || m_fntable.pfnConnect == NULL
917 || m_fntable.pfnDisconnect == NULL
918 || m_fntable.pfnCall == NULL
919 )
920 {
921 Log(("HGCMService::loadServiceDLL: at least one of function pointers is NULL\n"));
922
923 rc = VERR_INVALID_PARAMETER;
924
925 if (m_fntable.pfnUnload)
926 {
927 m_fntable.pfnUnload ();
928 }
929 }
930 }
931 }
932 }
933 else
934 {
935 LogFlow(("HGCMService::loadServiceDLL: failed to load service library. The service is not available.\n"));
936 m_hLdrMod = NIL_RTLDRMOD;
937 }
938
939 if (VBOX_FAILURE(rc))
940 {
941 unloadServiceDLL ();
942 }
943
944 return rc;
945}
946
947/** Helper function to free a local service DLL.
948 *
949 * @return VBox code
950 */
951void HGCMService::unloadServiceDLL (void)
952{
953 if (m_hLdrMod)
954 {
955 RTLdrClose (m_hLdrMod);
956 }
957
958 memset (&m_fntable, 0, sizeof (m_fntable));
959 m_pfnLoad = NULL;
960 m_hLdrMod = NIL_RTLDRMOD;
961}
962
963
964int HGCMService::Connect (uint32_t u32ClientID)
965{
966 HGCMMSGHANDLE hMsg;
967
968 LogFlow(("MAIN::HGCMService::Connect: client id = %d\n", u32ClientID));
969
970 int rc = hgcmMsgAlloc (m_thread, &hMsg, HGCMMSGID_SVC_CONNECT, hgcmMessageAlloc);
971
972 if (VBOX_SUCCESS(rc))
973 {
974 HGCMMsgSvcConnect *pMsg = (HGCMMsgSvcConnect *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
975
976 AssertRelease(pMsg);
977
978 pMsg->u32ClientID = u32ClientID;
979
980 hgcmObjDereference (pMsg);
981
982 rc = hgcmMsgSend (hMsg);
983
984 if (VBOX_SUCCESS (rc))
985 {
986 /* Add the client Id to the array. */
987 if (m_cClients == m_cClientsAllocated)
988 {
989 m_paClientIds = (uint32_t *)RTMemRealloc (m_paClientIds, (m_cClientsAllocated + 64) * sizeof (m_paClientIds[0]));
990 Assert(m_paClientIds);
991 }
992
993 m_paClientIds[m_cClients] = u32ClientID;
994 m_cClients++;
995 }
996 }
997 else
998 {
999 Log(("MAIN::HGCMService::Connect: Message allocation failed: %Vrc\n", rc));
1000 }
1001
1002 return rc;
1003}
1004
1005int HGCMService::Disconnect (uint32_t u32ClientID)
1006{
1007 int rc = VINF_SUCCESS;
1008
1009 LogFlow(("MAIN::HGCMService::Disconnect: client id = %d\n", u32ClientID));
1010
1011 HGCMMSGHANDLE hMsg;
1012
1013 rc = hgcmMsgAlloc (m_thread, &hMsg, HGCMMSGID_SVC_DISCONNECT, hgcmMessageAlloc);
1014
1015 if (VBOX_SUCCESS(rc))
1016 {
1017 HGCMMsgSvcDisconnect *pMsg = (HGCMMsgSvcDisconnect *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
1018
1019 AssertRelease(pMsg);
1020
1021 pMsg->u32ClientID = u32ClientID;
1022
1023 hgcmObjDereference (pMsg);
1024
1025 rc = hgcmMsgSend (hMsg);
1026
1027 /* Remove the client id from the array. */
1028 int i;
1029 for (i = 0; i < m_cClients; i++)
1030 {
1031 if (m_paClientIds[i] == u32ClientID)
1032 {
1033 m_cClients--;
1034
1035 if (m_cClients > i)
1036 {
1037 memmove (&m_paClientIds[i], &m_paClientIds[i + 1], m_cClients - i);
1038 }
1039
1040 break;
1041 }
1042 }
1043 }
1044 else
1045 {
1046 Log(("MAIN::HGCMService::Disconnect: Message allocation failed: %Vrc\n", rc));
1047 }
1048
1049 return rc;
1050}
1051
1052void HGCMService::DisconnectAll (void)
1053{
1054 while (m_cClients && m_paClientIds)
1055 {
1056 Log(("MAIN::HGCMService::DisconnectAll: id %d\n", m_paClientIds[0]));
1057 Disconnect (m_paClientIds[0]);
1058 }
1059}
1060
1061/* Forward the call request to the dedicated service thread.
1062 */
1063int HGCMService::GuestCall (PPDMIHGCMPORT pHGCMPort, PVBOXHGCMCMD pCmd, uint32_t u32ClientID, uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM paParms[], bool fBlock)
1064{
1065 HGCMMSGHANDLE hMsg = 0;
1066
1067 LogFlow(("MAIN::HGCMService::Call\n"));
1068
1069 int rc = hgcmMsgAlloc (m_thread, &hMsg, HGCMMSGID_GUESTCALL, hgcmMessageAlloc);
1070
1071 if (VBOX_SUCCESS(rc))
1072 {
1073 HGCMMsgCall *pMsg = (HGCMMsgCall *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
1074
1075 AssertRelease(pMsg);
1076
1077 pMsg->pCmd = pCmd;
1078 pMsg->pHGCMPort = pHGCMPort;
1079
1080 pMsg->u32ClientID = u32ClientID;
1081 pMsg->u32Function = u32Function;
1082 pMsg->cParms = cParms;
1083 pMsg->paParms = paParms;
1084
1085 hgcmObjDereference (pMsg);
1086
1087 if (fBlock)
1088 rc = hgcmMsgSend (hMsg);
1089 else
1090 rc = hgcmMsgPost (hMsg, hgcmMsgCompletionCallback);
1091
1092 if (!fBlock && VBOX_SUCCESS(rc))
1093 {
1094 rc = VINF_HGCM_ASYNC_EXECUTE;
1095 }
1096 }
1097 else
1098 {
1099 Log(("MAIN::HGCMService::Call: Message allocation failed: %Vrc\n", rc));
1100 }
1101
1102 return rc;
1103}
1104
1105/* Forward the call request to the dedicated service thread.
1106 */
1107int HGCMService::HostCall (PVBOXHGCMCMD pCmd, uint32_t u32ClientID, uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
1108{
1109 HGCMMSGHANDLE hMsg = 0;
1110
1111 LogFlow(("MAIN::HGCMService::HostCall %s\n", m_pszSvcName));
1112
1113 int rc = hgcmMsgAlloc (m_thread, &hMsg, HGCMMSGID_HOSTCALL, hgcmMessageAlloc);
1114
1115 if (VBOX_SUCCESS(rc))
1116 {
1117 HGCMMsgHostCall *pMsg = (HGCMMsgHostCall *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
1118
1119 AssertRelease(pMsg);
1120
1121 pMsg->pCmd = NULL; /* Not used for host calls. */
1122 pMsg->pHGCMPort = NULL; /* Not used for host calls. */
1123
1124 pMsg->u32Function = u32Function;
1125 pMsg->cParms = cParms;
1126 pMsg->paParms = paParms;
1127
1128 hgcmObjDereference (pMsg);
1129
1130 rc = hgcmMsgSend (hMsg);
1131 }
1132 else
1133 {
1134 Log(("MAIN::HGCMService::Call: Message allocation failed: %Vrc\n", rc));
1135 }
1136
1137 return rc;
1138}
1139
1140int HGCMService::SaveState(uint32_t u32ClientID, PSSMHANDLE pSSM)
1141{
1142 HGCMMSGHANDLE hMsg = 0;
1143
1144 LogFlow(("MAIN::HGCMService::SaveState %s\n", m_pszSvcName));
1145
1146 int rc = hgcmMsgAlloc (m_thread, &hMsg, HGCMMSGID_SAVESTATE, hgcmMessageAlloc);
1147
1148 if (VBOX_SUCCESS(rc))
1149 {
1150 HGCMMsgLoadSaveState *pMsg = (HGCMMsgLoadSaveState *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
1151
1152 AssertRelease(pMsg);
1153
1154 pMsg->u32ClientID = u32ClientID;
1155 pMsg->pSSM = pSSM;
1156
1157 hgcmObjDereference (pMsg);
1158
1159 rc = hgcmMsgSend (hMsg);
1160 }
1161 else
1162 {
1163 Log(("MAIN::HGCMService::SaveState: Message allocation failed: %Vrc\n", rc));
1164 }
1165
1166 return rc;
1167}
1168
1169int HGCMService::LoadState (uint32_t u32ClientID, PSSMHANDLE pSSM)
1170{
1171 HGCMMSGHANDLE hMsg = 0;
1172
1173 LogFlow(("MAIN::HGCMService::LoadState %s\n", m_pszSvcName));
1174
1175 int rc = hgcmMsgAlloc (m_thread, &hMsg, HGCMMSGID_LOADSTATE, hgcmMessageAlloc);
1176
1177 if (VBOX_SUCCESS(rc))
1178 {
1179 HGCMMsgLoadSaveState *pMsg = (HGCMMsgLoadSaveState *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
1180
1181 AssertRelease(pMsg);
1182
1183 pMsg->u32ClientID = u32ClientID;
1184 pMsg->pSSM = pSSM;
1185
1186 hgcmObjDereference (pMsg);
1187
1188 rc = hgcmMsgSend (hMsg);
1189 }
1190 else
1191 {
1192 Log(("MAIN::HGCMService::LoadState: Message allocation failed: %Vrc\n", rc));
1193 }
1194
1195 return rc;
1196}
1197
1198/* Main HGCM thread that processes CONNECT/DISCONNECT requests. */
1199static DECLCALLBACK(void) hgcmThread (HGCMTHREADHANDLE ThreadHandle, void *pvUser)
1200{
1201 NOREF(pvUser);
1202
1203 int rc = VINF_SUCCESS;
1204
1205 HGCMMsgCore *pMsgCore = NULL;
1206
1207 for (;;)
1208 {
1209 LogFlow(("hgcmThread: Going to get a message\n"));
1210
1211 rc = hgcmMsgGet (ThreadHandle, &pMsgCore);
1212
1213 if (VBOX_FAILURE (rc))
1214 {
1215 Log(("hgcmThread: message get failed, rc = %Vrc\n"));
1216 RTThreadSleep(100);
1217 continue;
1218 }
1219
1220 uint32_t u32MsgId = pMsgCore->MsgId ();
1221
1222 switch (u32MsgId)
1223 {
1224 case HGCMMSGID_CONNECT:
1225 {
1226 LogFlow(("HGCMMSGID_CONNECT\n"));
1227
1228 HGCMMsgConnect *pMsg = (HGCMMsgConnect *)pMsgCore;
1229
1230 /* Search if the service exists.
1231 * Create an information structure for the client.
1232 * Inform the service about the client.
1233 * Generate and return the client id.
1234 */
1235
1236 Log(("MAIN::hgcmThread:HGCMMSGID_CONNECT: location type = %d\n", pMsg->pLoc->type));
1237
1238 HGCMService *pService = NULL;
1239
1240 rc = HGCMService::FindService (&pService, pMsg->pLoc);
1241
1242 if (VBOX_SUCCESS (rc))
1243 {
1244 /* Allocate a client information structure */
1245
1246 HGCMClient *pClient = new HGCMClient ();
1247
1248 if (!pClient)
1249 {
1250 Log(("hgcmConnect::Could not allocate HGCMClient\n"));
1251 rc = VERR_NO_MEMORY;
1252 }
1253 else
1254 {
1255 uint32_t handle = hgcmObjGenerateHandle (pClient);
1256
1257 AssertRelease(handle);
1258
1259 rc = pClient->Init (pService);
1260
1261 if (VBOX_SUCCESS(rc))
1262 {
1263 rc = pService->Connect (handle);
1264 }
1265
1266 if (VBOX_FAILURE(rc))
1267 {
1268 hgcmObjDeleteHandle (handle);
1269 }
1270 else
1271 {
1272 *pMsg->pu32ClientID = handle;
1273 }
1274 }
1275 }
1276
1277 if (VBOX_FAILURE(rc))
1278 {
1279 LogFlow(("HGCMMSGID_CONNECT: FAILURE rc = %Vrc\n", rc));
1280
1281 if (pService)
1282 {
1283 pService->ReleaseService ();
1284 }
1285 }
1286
1287 } break;
1288
1289 case HGCMMSGID_DISCONNECT:
1290 {
1291 LogFlow(("HGCMMSGID_DISCONNECT\n"));
1292
1293 HGCMMsgDisconnect *pMsg = (HGCMMsgDisconnect *)pMsgCore;
1294
1295 Log(("MAIN::hgcmThread:HGCMMSGID_DISCONNECT: client id = %d\n", pMsg->u32ClientID));
1296
1297 /* Forward call to the service dedicated HGCM thread. */
1298 HGCMClient *pClient = (HGCMClient *)hgcmObjReference (pMsg->u32ClientID, HGCMOBJ_CLIENT);
1299
1300 if (!pClient)
1301 {
1302 Log(("MAIN::hgcmThread:HGCMMSGID_DISCONNECT: FAILURE resolving client id\n"));
1303 rc = VERR_INVALID_PARAMETER;
1304 }
1305 else
1306 {
1307 rc = pClient->pService->Disconnect (pMsg->u32ClientID);
1308
1309 pClient->pService->ReleaseService ();
1310
1311 hgcmObjDereference (pClient);
1312
1313 hgcmObjDeleteHandle (pMsg->u32ClientID);
1314 }
1315
1316 } break;
1317
1318 case HGCMMSGID_LOAD:
1319 {
1320 LogFlow(("HGCMMSGID_LOAD\n"));
1321
1322 HGCMMsgLoad *pMsg = (HGCMMsgLoad *)pMsgCore;
1323
1324 rc = HGCMService::LoadService (pMsg->pszServiceName, pMsg->pszServiceLibrary, pMsg->pHGCMPort);
1325 } break;
1326
1327 case HGCMMSGID_HOSTCALL:
1328 {
1329 LogFlow(("HGCMMSGID_HOSTCALL at hgcmThread\n"));
1330
1331 HGCMMsgHostCall *pMsg = (HGCMMsgHostCall *)pMsgCore;
1332
1333 HGCMService *pService = HGCMService::FindServiceByName (pMsg->pszServiceName);
1334
1335 if (pService)
1336 {
1337 LogFlow(("HGCMMSGID_HOSTCALL found service, forwarding the call.\n"));
1338 pService->HostCall (NULL, 0, pMsg->u32Function, pMsg->cParms, pMsg->paParms);
1339 }
1340 } break;
1341
1342 case HGCMMSGID_RESET:
1343 {
1344 LogFlow(("HGCMMSGID_RESET\n"));
1345
1346 HGCMMsgReset *pMsg = (HGCMMsgReset *)pMsgCore;
1347
1348 HGCMService::Reset ();
1349 } break;
1350
1351 default:
1352 {
1353 Log(("hgcmThread: Unsupported message number %08X!!!\n", u32MsgId));
1354 rc = VERR_NOT_SUPPORTED;
1355 } break;
1356 }
1357
1358 hgcmMsgComplete (pMsgCore, rc);
1359 }
1360
1361 return;
1362}
1363
1364static HGCMTHREADHANDLE g_hgcmThread = 0;
1365
1366/*
1367 * Find a service and inform it about a client connection.
1368 * Main HGCM thread will process this request for serialization.
1369 */
1370int hgcmConnectInternal (PPDMIHGCMPORT pHGCMPort, PVBOXHGCMCMD pCmd, PHGCMSERVICELOCATION pLoc, uint32_t *pu32ClientID, bool fBlock)
1371{
1372 int rc = VINF_SUCCESS;
1373
1374 LogFlow(("MAIN::hgcmConnectInternal: pHGCMPort = %p, pCmd = %p, loc = %p, pu32ClientID = %p\n",
1375 pHGCMPort, pCmd, pLoc, pu32ClientID));
1376
1377 if (!pHGCMPort || !pCmd || !pLoc || !pu32ClientID)
1378 {
1379 return VERR_INVALID_PARAMETER;
1380 }
1381
1382 HGCMMSGHANDLE hMsg = 0;
1383
1384 rc = hgcmMsgAlloc (g_hgcmThread, &hMsg, HGCMMSGID_CONNECT, hgcmMessageAlloc);
1385
1386 if (VBOX_SUCCESS(rc))
1387 {
1388 HGCMMsgConnect *pMsg = (HGCMMsgConnect *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
1389
1390 AssertRelease(pMsg);
1391
1392 pMsg->pCmd = pCmd;
1393 pMsg->pHGCMPort = pHGCMPort;
1394
1395 pMsg->pLoc = pLoc;
1396 pMsg->pu32ClientID = pu32ClientID;
1397
1398 if (fBlock)
1399 rc = hgcmMsgSend (hMsg);
1400 else
1401 rc = hgcmMsgPost (hMsg, hgcmMsgCompletionCallback);
1402
1403 hgcmObjDereference (pMsg);
1404
1405 LogFlow(("MAIN::hgcmConnectInternal: hgcmMsgPost returned %Vrc\n", rc));
1406
1407 if (!fBlock && VBOX_SUCCESS(rc))
1408 {
1409 rc = VINF_HGCM_ASYNC_EXECUTE;
1410 }
1411 }
1412 else
1413 {
1414 Log(("MAIN::hgcmConnectInternal:Message allocation failed: %Vrc\n", rc));
1415 }
1416
1417
1418 return rc;
1419}
1420
1421/*
1422 * Tell a service that the client is disconnecting.
1423 * Main HGCM thread will process this request for serialization.
1424 */
1425int hgcmDisconnectInternal (PPDMIHGCMPORT pHGCMPort, PVBOXHGCMCMD pCmd, uint32_t u32ClientID, bool fBlock)
1426{
1427 int rc = VINF_SUCCESS;
1428
1429 LogFlow(("MAIN::hgcmDisconnectInternal: pHGCMPort = %p, pCmd = %p, u32ClientID = %d\n",
1430 pHGCMPort, pCmd, u32ClientID));
1431
1432 if (!pHGCMPort || !pCmd)
1433 {
1434 return VERR_INVALID_PARAMETER;
1435 }
1436
1437 HGCMMSGHANDLE hMsg = 0;
1438
1439 rc = hgcmMsgAlloc (g_hgcmThread, &hMsg, HGCMMSGID_DISCONNECT, hgcmMessageAlloc);
1440
1441 if (VBOX_SUCCESS(rc))
1442 {
1443 HGCMMsgDisconnect *pMsg = (HGCMMsgDisconnect *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
1444
1445 AssertRelease(pMsg);
1446
1447 pMsg->pCmd = pCmd;
1448 pMsg->pHGCMPort = pHGCMPort;
1449
1450 pMsg->u32ClientID = u32ClientID;
1451
1452 if (fBlock)
1453 rc = hgcmMsgSend (hMsg);
1454 else
1455 rc = hgcmMsgPost (hMsg, hgcmMsgCompletionCallback);
1456
1457 hgcmObjDereference (pMsg);
1458
1459 if (!fBlock && VBOX_SUCCESS(rc))
1460 {
1461 rc = VINF_HGCM_ASYNC_EXECUTE;
1462 }
1463 }
1464 else
1465 {
1466 Log(("MAIN::hgcmDisconnectInternal: Message allocation failed: %Vrc\n", rc));
1467 }
1468
1469
1470 return rc;
1471}
1472
1473int hgcmSaveStateInternal (uint32_t u32ClientID, PSSMHANDLE pSSM)
1474{
1475 int rc = VINF_SUCCESS;
1476
1477 LogFlow(("MAIN::hgcmSaveStateInternal: u32ClientID = %d\n", u32ClientID));
1478
1479 HGCMClient *pClient = (HGCMClient *)hgcmObjReference (u32ClientID, HGCMOBJ_CLIENT);
1480
1481 if (!pClient)
1482 {
1483 Log(("MAIN::hgcmCallInternal: FAILURE resolving client id %d\n", u32ClientID));
1484 return VERR_HGCM_INVALID_CLIENT_ID;
1485 }
1486
1487 AssertRelease(pClient->pService);
1488
1489 rc = pClient->pService->SaveState (u32ClientID, pSSM);
1490
1491 hgcmObjDereference (pClient);
1492
1493 return rc;
1494}
1495
1496int hgcmLoadStateInternal (uint32_t u32ClientID, PSSMHANDLE pSSM)
1497{
1498 int rc = VINF_SUCCESS;
1499
1500 LogFlow(("MAIN::hgcmLoadStateInternal: u32ClientID = %d\n", u32ClientID));
1501
1502 HGCMClient *pClient = (HGCMClient *)hgcmObjReference (u32ClientID, HGCMOBJ_CLIENT);
1503
1504 if (!pClient)
1505 {
1506 Log(("MAIN::hgcmCallInternal: FAILURE resolving client id %d\n", u32ClientID));
1507 return VERR_HGCM_INVALID_CLIENT_ID;
1508 }
1509
1510 AssertRelease(pClient->pService);
1511
1512 rc = pClient->pService->LoadState (u32ClientID, pSSM);
1513
1514 hgcmObjDereference (pClient);
1515 return rc;
1516}
1517
1518int hgcmLoadInternal (const char *pszServiceName, const char *pszServiceLibrary)
1519{
1520 int rc = VINF_SUCCESS;
1521
1522 LogFlow(("MAIN::hgcmLoadInternal: name = %s, lib = %s\n",
1523 pszServiceName, pszServiceLibrary));
1524
1525 if (!pszServiceName || !pszServiceLibrary)
1526 {
1527 return VERR_INVALID_PARAMETER;
1528 }
1529
1530 HGCMMSGHANDLE hMsg = 0;
1531
1532 rc = hgcmMsgAlloc (g_hgcmThread, &hMsg, HGCMMSGID_LOAD, hgcmMessageAlloc);
1533
1534 if (VBOX_SUCCESS(rc))
1535 {
1536 HGCMMsgLoad *pMsg = (HGCMMsgLoad *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
1537
1538 AssertRelease(pMsg);
1539
1540 pMsg->pHGCMPort = NULL; /* Not used by the call. */
1541
1542 rc = pMsg->Init (pszServiceName, pszServiceLibrary);
1543
1544 if (VBOX_SUCCESS (rc))
1545 {
1546 rc = hgcmMsgSend (hMsg);
1547 }
1548
1549 hgcmObjDereference (pMsg);
1550
1551 LogFlow(("MAIN::hgcm:LoadInternal: hgcmMsgSend returned %Vrc\n", rc));
1552 }
1553 else
1554 {
1555 Log(("MAIN::hgcmLoadInternal:Message allocation failed: %Vrc\n", rc));
1556 }
1557
1558
1559 return rc;
1560}
1561
1562/*
1563 * Call a service.
1564 * The service dedicated thread will process this request.
1565 */
1566int hgcmGuestCallInternal (PPDMIHGCMPORT pHGCMPort, PVBOXHGCMCMD pCmd, uint32_t u32ClientID, uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM aParms[], bool fBlock)
1567{
1568 int rc = VINF_SUCCESS;
1569
1570 LogFlow(("MAIN::hgcmCallInternal: pHGCMPort = %p, pCmd = %p, u32ClientID = %d, u32Function = %d, cParms = %d, aParms = %p\n",
1571 pHGCMPort, pCmd, u32ClientID, u32Function, cParms, aParms));
1572
1573 if (!pHGCMPort || !pCmd)
1574 {
1575 return VERR_INVALID_PARAMETER;
1576 }
1577
1578 HGCMClient *pClient = (HGCMClient *)hgcmObjReference (u32ClientID, HGCMOBJ_CLIENT);
1579
1580 if (!pClient)
1581 {
1582 Log(("MAIN::hgcmCallInternal: FAILURE resolving client id %d\n", u32ClientID));
1583 return VERR_HGCM_INVALID_CLIENT_ID;
1584 }
1585
1586 AssertRelease(pClient->pService);
1587
1588 rc = pClient->pService->GuestCall (pHGCMPort, pCmd, u32ClientID, u32Function, cParms, aParms, fBlock);
1589
1590 hgcmObjDereference (pClient);
1591
1592 return rc;
1593}
1594
1595/*
1596 * Call a service.
1597 * The service dedicated thread will process this request.
1598 */
1599int hgcmHostCallInternal (const char *pszServiceName, uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM aParms[])
1600{
1601 int rc = VINF_SUCCESS;
1602
1603 LogFlow(("MAIN::hgcmHostCallInternal: service = %s, u32Function = %d, cParms = %d, aParms = %p\n",
1604 pszServiceName, u32Function, cParms, aParms));
1605
1606 if (!pszServiceName)
1607 {
1608 return VERR_INVALID_PARAMETER;
1609 }
1610
1611 HGCMMSGHANDLE hMsg = 0;
1612
1613 rc = hgcmMsgAlloc (g_hgcmThread, &hMsg, HGCMMSGID_HOSTCALL, hgcmMessageAlloc);
1614
1615 if (VBOX_SUCCESS(rc))
1616 {
1617 HGCMMsgHostCall *pMsg = (HGCMMsgHostCall *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
1618
1619 AssertRelease(pMsg);
1620
1621 pMsg->pHGCMPort = NULL; /* Not used. */
1622
1623 pMsg->pszServiceName = (char *)pszServiceName;
1624 pMsg->u32Function = u32Function;
1625 pMsg->cParms = cParms;
1626 pMsg->paParms = &aParms[0];
1627
1628 rc = hgcmMsgSend (hMsg);
1629
1630 hgcmObjDereference (pMsg);
1631
1632 LogFlow(("MAIN::hgcm:HostCallInternal: hgcmMsgSend returned %Vrc\n", rc));
1633 }
1634 else
1635 {
1636 Log(("MAIN::hgcmHostCallInternal:Message allocation failed: %Vrc\n", rc));
1637 }
1638
1639 return rc;
1640}
1641
1642
1643int hgcmInit (void)
1644{
1645 int rc = VINF_SUCCESS;
1646
1647 Log(("MAIN::hgcmInit\n"));
1648
1649 rc = hgcmThreadInit ();
1650
1651 if (VBOX_FAILURE(rc))
1652 {
1653 Log(("FAILURE: Can't init worker threads.\n"));
1654 }
1655 else
1656 {
1657 /* Start main HGCM thread that will process Connect/Disconnect requests. */
1658
1659 rc = hgcmThreadCreate (&g_hgcmThread, "MainHGCMthread", hgcmThread, NULL);
1660
1661 if (VBOX_FAILURE (rc))
1662 {
1663 Log(("FAILURE: HGCM initialization.\n"));
1664 }
1665 }
1666
1667 LogFlow(("MAIN::hgcmInit: rc = %Vrc\n", rc));
1668
1669 return rc;
1670}
1671
1672int hgcmReset (void)
1673{
1674 int rc = VINF_SUCCESS;
1675 Log(("MAIN::hgcmReset\n"));
1676
1677 /* Disconnect all clients. */
1678 HGCMMSGHANDLE hMsg = 0;
1679
1680 rc = hgcmMsgAlloc (g_hgcmThread, &hMsg, HGCMMSGID_RESET, hgcmMessageAlloc);
1681
1682 if (VBOX_SUCCESS(rc))
1683 {
1684 HGCMMsgReset *pMsg = (HGCMMsgReset *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
1685
1686 AssertRelease(pMsg);
1687
1688 pMsg->pHGCMPort = NULL; /* Not used by the call. */
1689
1690 rc = hgcmMsgSend (hMsg);
1691
1692 hgcmObjDereference (pMsg);
1693
1694 LogFlow(("MAIN::hgcmReset: hgcmMsgSend returned %Vrc\n", rc));
1695 }
1696 else
1697 {
1698 Log(("MAIN::hgcmReset:Message allocation failed: %Vrc\n", rc));
1699 }
1700
1701 LogFlow(("MAIN::hgcmReset: rc = %Vrc\n", rc));
1702 return rc;
1703}
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