HGCM.cpp revision 7c01eb2f98aa5f3de05553686339632b31f2dc82
/** @file
*
* HGCM (Host-Guest Communication Manager)
*/
/*
* Copyright (C) 2006 InnoTek Systemberatung GmbH
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License as published by the Free Software Foundation,
* in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
* distribution. VirtualBox OSE is distributed in the hope that it will
* be useful, but WITHOUT ANY WARRANTY of any kind.
*
* If you received this file as part of a commercial VirtualBox
* distribution, then only the terms of your commercial VirtualBox
* license agreement apply instead of the previous paragraph.
*/
/*
* NOT FOR REVIEWING YET. A LOT OF TODO/MISSED/INCOMPLETE/SKETCH CODE INSIDE!
*/
#include "Logging.h"
#include <malloc.h>
#include "hgcm/HGCMThread.h"
#include <iprt/critsect.h>
#include <iprt/semaphore.h>
#include <VBox/VBoxGuest.h>
/**
*
* Service location types:
*
* LOCAL SERVICE
* service DLL is loaded by the VM process,
* and directly called by the VM HGCM instance.
*/
/**
* A service gets one thread, which synchronously delivers messages to
* the service. This is good for serialization.
*
* Some services may want to process messages asynchronously, and will want
* a next message to be delivered, while a previous message is still being
* processed.
*
* The dedicated service thread delivers a next message when service
* returns after fetching a previous one. The service will call a message
* completion callback when message is actually processed. So returning
* from the service call means only that the service is processing message.
*
* 'Message processed' condition is indicated by service, which call the
* callback, even if the callback is called synchronously in the dedicated
* thread.
*
* This message completion callback is only valid for Call requests.
* Connect and Disconnect are processed sznchronously by service.
*
*/
/** @todo services registration, only registered service dll can be loaded */
/** @todo a registered LOCAL service must also get a thread, for now
* a thread per service (later may be there will be an option to
* have a thread per client for a service, however I do not think it's
* really necessary).
* The requests will be queued and executed by the service thread,
* an IRQ notification will be ussued when a request is completed.
*
* May be other services (like VRDP acceleration) should still use
* the EMT thread, because they have their own threads for long
* operations.
* So we have to distinguish those services during
* External dlls will always have its own thread,
* internal (trusted) services will choose between having executed
* on EMT or on a separate thread.
*
*/
/* The maximum allowed size of a service name in bytes. */
#define VBOX_HGCM_SVC_NAME_MAX_BYTES 1024
/** Internal helper service object. HGCM code would use it to
* hold information about services and communicate with services.
* The HGCMService is an (in future) abstract class that implements
* common functionality. There will be derived classes for specific
* service types (Local, etc).
*/
/** @todo should be HGCMObject */
class HGCMService
{
private:
static HGCMService *sm_pSvcListHead;
static HGCMService *sm_pSvcListTail;
#ifdef HGCMSS
static int sm_cServices;
#endif /* HGCMSS */
uint32_t volatile m_u32RefCnt;
char *m_pszSvcName;
char *m_pszSvcLibrary;
int m_cClients;
int m_cClientsAllocated;
int loadServiceDLL (void);
void unloadServiceDLL (void);
int InstanceCreate (const char *pszServiceLibrary, const char *pszServiceName, PPDMIHGCMPORT pHGCMPort);
void InstanceDestroy (void);
HGCMService ();
~HGCMService () {};
public:
static void Reset (void);
#ifdef HGCMSS
#endif /* HGCMSS */
static int LoadService (const char *pszServiceLibrary, const char *pszServiceName, PPDMIHGCMPORT pHGCMPort);
void ReleaseService (void);
void DisconnectAll (void);
#ifdef HGCMSS
#endif /* HGCMSS */
int GuestCall (PPDMIHGCMPORT pHGCMPort, PVBOXHGCMCMD pCmd, uint32_t u32ClientID, uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM aParms[], bool fBlock);
int HostCall (PVBOXHGCMCMD pCmd, uint32_t u32ClientID, uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM aParms[]);
};
class HGCMClient: public HGCMObject
{
public:
~HGCMClient ();
/** Service that the client is connected to. */
/** Client specific data. */
void *pvData;
};
HGCMClient::~HGCMClient ()
{
}
{
if (pService->SizeOfClient () > 0)
{
if (!pvData)
{
return VERR_NO_MEMORY;
}
}
return VINF_SUCCESS;
}
/*
* Messages processed by worker threads.
*/
#define HGCMMSGID_SVC_LOAD (0)
#define HGCMMSGID_SVC_UNLOAD (1)
#define HGCMMSGID_SVC_CONNECT (2)
#define HGCMMSGID_SVC_DISCONNECT (3)
#define HGCMMSGID_GUESTCALL (4)
class HGCMMsgSvcLoad: public HGCMMsgCore
{
};
class HGCMMsgSvcUnload: public HGCMMsgCore
{
};
class HGCMMsgSvcConnect: public HGCMMsgCore
{
public:
/* client identifier */
};
class HGCMMsgSvcDisconnect: public HGCMMsgCore
{
public:
/* client identifier */
};
class HGCMMsgHeader: public HGCMMsgCore
{
public:
/* Command pointer/identifier. */
/* Port to be informed on message completion. */
};
class HGCMMsgCall: public HGCMMsgHeader
{
public:
/* client identifier */
/* function number */
/* number of parameters */
};
/*
* Messages processed by main HGCM thread.
*/
#define HGCMMSGID_CONNECT (10)
#define HGCMMSGID_DISCONNECT (11)
#define HGCMMSGID_LOAD (12)
#define HGCMMSGID_HOSTCALL (13)
#define HGCMMSGID_LOADSTATE (14)
#define HGCMMSGID_SAVESTATE (15)
#define HGCMMSGID_RESET (16)
class HGCMMsgConnect: public HGCMMsgHeader
{
public:
/* service location */
/* client identifier */
};
class HGCMMsgDisconnect: public HGCMMsgHeader
{
public:
/* client identifier */
};
class HGCMMsgLoadSaveState: public HGCMMsgHeader
{
public:
/* client identifier */
};
class HGCMMsgLoad: public HGCMMsgHeader
{
public:
virtual ~HGCMMsgLoad ()
{
}
{
if (!pszServiceName || !pszServiceLibrary)
{
return VERR_NO_MEMORY;
}
return VINF_SUCCESS;
}
char *pszServiceName;
char *pszServiceLibrary;
};
class HGCMMsgHostCall: public HGCMMsgHeader
{
public:
char *pszServiceName;
/* function number */
/* number of parameters */
};
class HGCMMsgReset: public HGCMMsgHeader
{
};
/* static */ DECLCALLBACK(void) HGCMService::svcHlpCallComplete (VBOXHGCMCALLHANDLE callHandle, int32_t rc)
{
{
/* Only call the completion for these messages. The helper
* is called by the service, and the service does not get
* any other messages.
*/
}
else
{
AssertFailed ();
}
}
#ifdef HGCMSS
int HGCMService::sm_cServices = 0;
#endif /* HGCMSS */
:
m_thread (0),
m_u32RefCnt (0),
m_pSvcNext (NULL),
m_pSvcPrev (NULL),
m_pszSvcName (NULL),
m_cClients (0),
m_cClientsAllocated (0),
{
}
{
switch (u32MsgId)
{
case HGCMMSGID_SVC_LOAD: return new HGCMMsgSvcLoad ();
case HGCMMSGID_SVC_UNLOAD: return new HGCMMsgSvcUnload ();
case HGCMMSGID_SVC_CONNECT: return new HGCMMsgSvcConnect ();
case HGCMMSGID_SVC_DISCONNECT: return new HGCMMsgSvcDisconnect ();
case HGCMMSGID_GUESTCALL: return new HGCMMsgCall ();
case HGCMMSGID_CONNECT: return new HGCMMsgConnect ();
case HGCMMSGID_DISCONNECT: return new HGCMMsgDisconnect ();
case HGCMMSGID_LOAD: return new HGCMMsgLoad ();
case HGCMMSGID_HOSTCALL: return new HGCMMsgHostCall ();
case HGCMMSGID_LOADSTATE:
case HGCMMSGID_SAVESTATE: return new HGCMMsgLoadSaveState ();
case HGCMMSGID_RESET: return new HGCMMsgReset ();
default:
}
return NULL;
}
static bool g_fResetting = false;
static bool g_fSaveState = false;
{
/* Call the VMMDev port interface to issue IRQ notification. */
{
pMsgHdr->pHGCMPort->pfnCompleted (pMsgHdr->pHGCMPort, g_fSaveState? VINF_HGCM_SAVE_STATE: result, pMsgHdr->pCmd);
}
return;
}
{
int rc = VINF_SUCCESS;
bool bUnloaded = false;
while (!bUnloaded)
{
if (VBOX_FAILURE (rc))
{
RTThreadSleep(100);
continue;
}
/* Cache required information to avoid unnecessary pMsgCore access. */
switch (u32MsgId)
{
case HGCMMSGID_SVC_LOAD:
{
LogFlow(("HGCMMSGID_SVC_LOAD\n"));
} break;
case HGCMMSGID_SVC_UNLOAD:
{
LogFlow(("HGCMMSGID_SVC_UNLOAD\n"));
pSvc->unloadServiceDLL ();
bUnloaded = true;
} break;
case HGCMMSGID_SVC_CONNECT:
{
LogFlow(("HGCMMSGID_SVC_CONNECT\n"));
rc = VINF_SUCCESS;
if (pClient)
{
}
} break;
case HGCMMSGID_SVC_DISCONNECT:
{
LogFlow(("HGCMMSGID_SVC_DISCONNECT\n"));
rc = VINF_SUCCESS;
if (pClient)
{
}
} break;
case HGCMMSGID_GUESTCALL:
{
LogFlow(("HGCMMSGID_GUESTCALL\n"));
rc = VINF_SUCCESS;
if (pClient)
{
pSvc->m_fntable.pfnCall ((VBOXHGCMCALLHANDLE)pMsg, pMsg->u32ClientID, HGCM_CLIENT_DATA(pSvc, pClient), pMsg->u32Function, pMsg->cParms, pMsg->paParms);
}
else
{
}
} break;
case HGCMMSGID_HOSTCALL:
{
LogFlow(("HGCMMSGID_HOSTCALL\n"));
pSvc->m_fntable.pfnHostCall ((VBOXHGCMCALLHANDLE)pMsg, 0, NULL, pMsg->u32Function, pMsg->cParms, pMsg->paParms);
rc = VINF_SUCCESS;
} break;
case HGCMMSGID_LOADSTATE:
{
LogFlow(("HGCMMSGID_LOADSTATE\n"));
rc = VINF_SUCCESS;
if (pClient)
{
{
}
}
break;
}
case HGCMMSGID_SAVESTATE:
{
LogFlow(("HGCMMSGID_SAVESTATE\n"));
rc = VINF_SUCCESS;
if (pClient)
{
{
g_fSaveState = true;
g_fSaveState = false;
}
}
break;
}
default:
{
} break;
}
if ( u32MsgId != HGCMMSGID_GUESTCALL
&& u32MsgId != HGCMMSGID_HOSTCALL)
{
/* For HGCMMSGID_GUESTCALL & HGCMMSGID_HOSTCALL the service
* calls the completion helper. Other messages have to be
* completed here.
*/
}
}
return;
}
int HGCMService::InstanceCreate (const char *pszServiceLibrary, const char *pszServiceName, PPDMIHGCMPORT pHGCMPort)
{
int rc = VINF_SUCCESS;
char achThreadName[14];
if (VBOX_SUCCESS(rc))
{
if (!m_pszSvcName || !m_pszSvcLibrary)
{
m_pszSvcName = NULL;
rc = VERR_NO_MEMORY;
}
else
{
m_svcHelpers.pvInstance = this;
/* Execute the load request on the service thread. */
if (VBOX_SUCCESS(rc))
{
}
}
}
else
{
Log(("HGCMService::InstanceCreate: FAILURE: service thread creation\n"));
}
if (VBOX_FAILURE(rc))
{
InstanceDestroy ();
}
return rc;
}
void HGCMService::InstanceDestroy (void)
{
LogFlow(("HGCMService::InstanceDestroy\n"));
if (VBOX_SUCCESS(rc))
{
}
m_pszSvcName = NULL;
// @todo Adjust the list sm_cServices--;
LogFlow(("HGCMService::InstanceDestroy completed\n"));
}
{
if (!loc || (loc->type != VMMDevHGCMLoc_LocalHost && loc->type != VMMDevHGCMLoc_LocalHost_Existing))
{
return false;
}
{
return false;
}
return true;
}
/** Services are searched by FindService function which is called
* by the main HGCM thread during CONNECT message processing.
* Reference count of the service is increased.
* Services are loaded by the LoadService function.
* Note: both methods are executed by the main HGCM thread.
*/
{
if (!loc || (loc->type != VMMDevHGCMLoc_LocalHost && loc->type != VMMDevHGCMLoc_LocalHost_Existing))
{
return VERR_INVALID_PARAMETER;
}
/* Look at already loaded services. */
while (psvc)
{
{
break;
}
}
if (psvc)
{
return VINF_SUCCESS;
}
return VERR_ACCESS_DENIED;
}
{
while (psvc)
{
{
break;
}
}
return psvc;
}
/* static */ int HGCMService::LoadService (const char *pszServiceLibrary, const char *pszServiceName, PPDMIHGCMPORT pHGCMPort)
{
int rc = VINF_SUCCESS;
/* Look at already loaded services to avoid double loading. */
if (psvc)
{
}
else
{
psvc = new HGCMService ();
if (!psvc)
{
Log(("HGCMService::Load: memory allocation for the service failed!!!\n"));
rc = VERR_NO_MEMORY;
}
if (VBOX_SUCCESS(rc))
{
if (VBOX_SUCCESS(rc))
{
/* Insert the just created service to list for future references. */
if (sm_pSvcListHead)
{
}
else
{
}
#ifdef HGCMSS
sm_cServices++;
#endif /* HGCMSS */
}
}
}
return rc;
}
{
/* This is called when the VM is being reset,
* that is no more requests from guest is expected.
* Scan al services and disconnect all clients.
*/
g_fResetting = true;
while (psvc)
{
psvc->DisconnectAll ();
}
g_fResetting = false;
}
#ifdef HGCMSS
{
/* Save the current handle count and restore afterwards to avoid client id conflicts. */
/* Save number of services. */
/* Save every service. */
while (pSvc)
{
/* Save the length of the service name. */
/* Save the name of the service. */
/* Save the number of clients. */
/* Call the service for every client. Normally a service must not have
* a global state to be saved: only per client info is relevant.
* The global state of a service is configured during VM startup.
*/
int i;
for (i = 0; i < pSvc->m_cClients; i++)
{
/* Save the client id. */
/* Call the service, so the operation is executed by the service thread. */
}
}
return VINF_SUCCESS;
}
{
/* Restore handle count to avoid client id conflicts. */
/* Get the number of services. */
while (cServices--)
{
/* Get the length of the service name. */
/* Get the service name. */
/* Resolve the service instance. */
/* Get the number of clients. */
while (cClients--)
{
/* Get the client id. */
/* Connect the client. */
/* Call the service, so the operation is executed by the service thread. */
}
}
return VINF_SUCCESS;
}
#endif /* HGCMSS */
void HGCMService::ReleaseService (void)
{
AssertRelease(u32RefCnt != ~0U);
if (u32RefCnt == 0)
{
/** @todo We do not unload services. Cache them all. Unloading will be later. HGCMObject! */
LogFlow(("HGCMService::ReleaseService: no more references.\n"));
// InstanceDestroy ();
// delete this;
}
}
/** Helper function to load a local service DLL.
*
* @return VBox code
*/
int HGCMService::loadServiceDLL (void)
{
if (m_pszSvcLibrary == NULL)
{
return VERR_INVALID_PARAMETER;
}
int rc = VINF_SUCCESS;
if (VBOX_SUCCESS(rc))
{
LogFlow(("HGCMService::loadServiceDLL: successfully loaded the library.\n"));
{
Log(("HGCMService::loadServiceDLL: Error resolving the service entry point %s, rc = %d, m_pfnLoad = %p\n", VBOX_HGCM_SVCLOAD_NAME, rc, m_pfnLoad));
if (VBOX_SUCCESS(rc))
{
/* m_pfnLoad was NULL */
}
}
if (VBOX_SUCCESS(rc))
{
if (VBOX_SUCCESS (rc))
{
)
{
Log(("HGCMService::loadServiceDLL: at least one of function pointers is NULL\n"));
{
}
}
}
}
}
else
{
LogFlow(("HGCMService::loadServiceDLL: failed to load service library. The service is not available.\n"));
}
if (VBOX_FAILURE(rc))
{
unloadServiceDLL ();
}
return rc;
}
/** Helper function to free a local service DLL.
*
* @return VBox code
*/
void HGCMService::unloadServiceDLL (void)
{
if (m_hLdrMod)
{
}
}
#ifdef HGCMSS
/* Create a new client instance and connect it to the service.
*
* @param pu32ClientIdOut If not NULL, then the method must generate a new handle for the client.
* If NULL, use the given 'u32ClientIdIn' handle.
* @param u32ClientIdIn The handle for the client, when 'pu32ClientIdOut' is NULL.
*
*/
{
/* Allocate a client information structure */
if (!pClient)
{
LogWarningFunc(("Could not allocate HGCMClient!!!\n"));
return VERR_NO_MEMORY;
}
if (pu32ClientIdOut != NULL)
{
}
else
{
}
if (VBOX_SUCCESS(rc))
{
}
if (VBOX_FAILURE(rc))
{
}
else
{
if (pu32ClientIdOut != NULL)
{
}
}
return rc;
}
#endif /* HGCMSS */
{
if (VBOX_SUCCESS(rc))
{
if (VBOX_SUCCESS (rc))
{
/* Add the client Id to the array. */
if (m_cClients == m_cClientsAllocated)
{
m_paClientIds = (uint32_t *)RTMemRealloc (m_paClientIds, (m_cClientsAllocated + 64) * sizeof (m_paClientIds[0]));
}
m_cClients++;
}
}
else
{
}
return rc;
}
{
int rc = VINF_SUCCESS;
if (VBOX_SUCCESS(rc))
{
/* Remove the client id from the array. */
int i;
for (i = 0; i < m_cClients; i++)
{
if (m_paClientIds[i] == u32ClientID)
{
m_cClients--;
if (m_cClients > i)
{
}
break;
}
}
}
else
{
}
return rc;
}
void HGCMService::DisconnectAll (void)
{
while (m_cClients && m_paClientIds)
{
Disconnect (m_paClientIds[0]);
}
}
/* Forward the call request to the dedicated service thread.
*/
int HGCMService::GuestCall (PPDMIHGCMPORT pHGCMPort, PVBOXHGCMCMD pCmd, uint32_t u32ClientID, uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM paParms[], bool fBlock)
{
HGCMMSGHANDLE hMsg = 0;
LogFlow(("MAIN::HGCMService::Call\n"));
if (VBOX_SUCCESS(rc))
{
if (fBlock)
else
{
}
}
else
{
}
return rc;
}
/* Forward the call request to the dedicated service thread.
*/
int HGCMService::HostCall (PVBOXHGCMCMD pCmd, uint32_t u32ClientID, uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
{
HGCMMSGHANDLE hMsg = 0;
if (VBOX_SUCCESS(rc))
{
}
else
{
}
return rc;
}
{
HGCMMSGHANDLE hMsg = 0;
if (VBOX_SUCCESS(rc))
{
}
else
{
}
return rc;
}
{
HGCMMSGHANDLE hMsg = 0;
if (VBOX_SUCCESS(rc))
{
}
else
{
}
return rc;
}
/* Main HGCM thread that processes CONNECT/DISCONNECT requests. */
{
int rc = VINF_SUCCESS;
for (;;)
{
LogFlow(("hgcmThread: Going to get a message\n"));
if (VBOX_FAILURE (rc))
{
Log(("hgcmThread: message get failed, rc = %Vrc\n"));
RTThreadSleep(100);
continue;
}
switch (u32MsgId)
{
case HGCMMSGID_CONNECT:
{
LogFlow(("HGCMMSGID_CONNECT\n"));
/* Search if the service exists.
* Create an information structure for the client.
* Inform the service about the client.
* Generate and return the client id.
*/
if (VBOX_SUCCESS (rc))
{
#ifdef HGCMSS
#else
/* Allocate a client information structure */
if (!pClient)
{
Log(("hgcmConnect::Could not allocate HGCMClient\n"));
rc = VERR_NO_MEMORY;
}
else
{
if (VBOX_SUCCESS(rc))
{
}
if (VBOX_FAILURE(rc))
{
}
else
{
}
}
#endif /* HGCMSS */
}
if (VBOX_FAILURE(rc))
{
if (pService)
{
pService->ReleaseService ();
}
}
} break;
case HGCMMSGID_DISCONNECT:
{
LogFlow(("HGCMMSGID_DISCONNECT\n"));
/* Forward call to the service dedicated HGCM thread. */
if (!pClient)
{
Log(("MAIN::hgcmThread:HGCMMSGID_DISCONNECT: FAILURE resolving client id\n"));
}
else
{
}
} break;
case HGCMMSGID_LOAD:
{
LogFlow(("HGCMMSGID_LOAD\n"));
} break;
case HGCMMSGID_HOSTCALL:
{
LogFlow(("HGCMMSGID_HOSTCALL at hgcmThread\n"));
if (pService)
{
LogFlow(("HGCMMSGID_HOSTCALL found service, forwarding the call.\n"));
}
} break;
case HGCMMSGID_RESET:
{
LogFlow(("HGCMMSGID_RESET\n"));
HGCMService::Reset ();
} break;
#ifdef HGCMSS
case HGCMMSGID_LOADSTATE:
{
LogFlow(("HGCMMSGID_LOADSTATE\n"));
} break;
case HGCMMSGID_SAVESTATE:
{
LogFlow(("HGCMMSGID_SAVESTATE\n"));
} break;
#endif /* HGCMSS */
default:
{
} break;
}
}
return;
}
static HGCMTHREADHANDLE g_hgcmThread = 0;
/*
* Find a service and inform it about a client connection.
* Main HGCM thread will process this request for serialization.
*/
int hgcmConnectInternal (PPDMIHGCMPORT pHGCMPort, PVBOXHGCMCMD pCmd, PHGCMSERVICELOCATION pLoc, uint32_t *pu32ClientID, bool fBlock)
{
int rc = VINF_SUCCESS;
LogFlow(("MAIN::hgcmConnectInternal: pHGCMPort = %p, pCmd = %p, loc = %p, pu32ClientID = %p\n",
{
return VERR_INVALID_PARAMETER;
}
HGCMMSGHANDLE hMsg = 0;
if (VBOX_SUCCESS(rc))
{
if (fBlock)
else
{
}
}
else
{
}
return rc;
}
/*
* Tell a service that the client is disconnecting.
* Main HGCM thread will process this request for serialization.
*/
int hgcmDisconnectInternal (PPDMIHGCMPORT pHGCMPort, PVBOXHGCMCMD pCmd, uint32_t u32ClientID, bool fBlock)
{
int rc = VINF_SUCCESS;
LogFlow(("MAIN::hgcmDisconnectInternal: pHGCMPort = %p, pCmd = %p, u32ClientID = %d\n",
{
return VERR_INVALID_PARAMETER;
}
HGCMMSGHANDLE hMsg = 0;
if (VBOX_SUCCESS(rc))
{
if (fBlock)
else
{
}
}
else
{
}
return rc;
}
#ifdef HGCMSS
{
/* Forward the request to the main HGCM thread. */
HGCMMSGHANDLE hMsg = 0;
if (VBOX_SUCCESS(rc))
{
}
return rc;
}
{
}
{
}
#else
{
int rc = VINF_SUCCESS;
if (!pClient)
{
return VERR_HGCM_INVALID_CLIENT_ID;
}
return rc;
}
{
int rc = VINF_SUCCESS;
if (!pClient)
{
return VERR_HGCM_INVALID_CLIENT_ID;
}
return rc;
}
#endif /* HGCMSS */
{
int rc = VINF_SUCCESS;
LogFlow(("MAIN::hgcmLoadInternal: name = %s, lib = %s\n",
if (!pszServiceName || !pszServiceLibrary)
{
return VERR_INVALID_PARAMETER;
}
HGCMMSGHANDLE hMsg = 0;
if (VBOX_SUCCESS(rc))
{
if (VBOX_SUCCESS (rc))
{
}
}
else
{
}
return rc;
}
/*
* Call a service.
* The service dedicated thread will process this request.
*/
int hgcmGuestCallInternal (PPDMIHGCMPORT pHGCMPort, PVBOXHGCMCMD pCmd, uint32_t u32ClientID, uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM aParms[], bool fBlock)
{
int rc = VINF_SUCCESS;
LogFlow(("MAIN::hgcmCallInternal: pHGCMPort = %p, pCmd = %p, u32ClientID = %d, u32Function = %d, cParms = %d, aParms = %p\n",
{
return VERR_INVALID_PARAMETER;
}
if (!pClient)
{
return VERR_HGCM_INVALID_CLIENT_ID;
}
rc = pClient->pService->GuestCall (pHGCMPort, pCmd, u32ClientID, u32Function, cParms, aParms, fBlock);
return rc;
}
/*
* Call a service.
* The service dedicated thread will process this request.
*/
int hgcmHostCallInternal (const char *pszServiceName, uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM aParms[])
{
int rc = VINF_SUCCESS;
LogFlow(("MAIN::hgcmHostCallInternal: service = %s, u32Function = %d, cParms = %d, aParms = %p\n",
if (!pszServiceName)
{
return VERR_INVALID_PARAMETER;
}
HGCMMSGHANDLE hMsg = 0;
if (VBOX_SUCCESS(rc))
{
}
else
{
}
return rc;
}
int hgcmInit (void)
{
int rc = VINF_SUCCESS;
Log(("MAIN::hgcmInit\n"));
rc = hgcmThreadInit ();
if (VBOX_FAILURE(rc))
{
Log(("FAILURE: Can't init worker threads.\n"));
}
else
{
/* Start main HGCM thread that will process Connect/Disconnect requests. */
if (VBOX_FAILURE (rc))
{
Log(("FAILURE: HGCM initialization.\n"));
}
}
return rc;
}
int hgcmReset (void)
{
int rc = VINF_SUCCESS;
Log(("MAIN::hgcmReset\n"));
/* Disconnect all clients. */
HGCMMSGHANDLE hMsg = 0;
if (VBOX_SUCCESS(rc))
{
}
else
{
}
return rc;
}