HGCM.cpp revision 9f439f3042940bcd877ff1fa2b8a389d39adbd49
/** @file
*
* HGCM (Host-Guest Communication Manager)
*/
/*
* Copyright (C) 2006-2007 Oracle Corporation
*
* 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 (GPL) 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.
*/
#include "Logging.h"
#include "hgcm/HGCMThread.h"
#include <iprt/critsect.h>
#include <iprt/semaphore.h>
/**
* 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 synchronously by the service.
*/
/* The maximum allowed size of a service name in bytes. */
#define VBOX_HGCM_SVC_NAME_MAX_BYTES 1024
struct _HGCMSVCEXTHANDLEDATA
{
char *pszServiceName;
/* The service name follows. */
};
/** 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.
*/
class HGCMService
{
private:
static HGCMService *sm_pSvcListHead;
static HGCMService *sm_pSvcListTail;
static int sm_cServices;
uint32_t volatile m_u32RefCnt;
char *m_pszSvcName;
char *m_pszSvcLibrary;
int m_cClients;
int m_cClientsAllocated;
#ifdef VBOX_WITH_CRHGSMI
#endif
int loadServiceDLL (void);
void unloadServiceDLL (void);
/*
* Main HGCM thread methods.
*/
void instanceDestroy (void);
HGCMService ();
~HGCMService () {};
public:
/*
* Main HGCM thread methods.
*/
void UnloadService (void);
static void UnloadAll (void);
void ReferenceService (void);
void ReleaseService (void);
static void Reset (void);
#ifdef VBOX_WITH_CRHGSMI
int HandleAcquired();
int HandleReleased();
int HostFastCallAsync (uint32_t u32Function, VBOXHGCMSVCPARM *pParm, PHGCMHOSTFASTCALLCB pfnCompletion, void *pvCompletion);
#endif
/*
* The service thread methods.
*/
int GuestCall (PPDMIHGCMPORT pHGCMPort, 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 (pService->SizeOfClient () > 0)
{
if (!pvData)
{
return VERR_NO_MEMORY;
}
}
return VINF_SUCCESS;
}
int HGCMService::sm_cServices = 0;
:
m_thread (0),
m_u32RefCnt (0),
m_pSvcNext (NULL),
m_pSvcPrev (NULL),
m_pszSvcName (NULL),
m_cClients (0),
m_cClientsAllocated (0),
#ifdef VBOX_WITH_CRHGSMI
m_cHandleAcquires (0),
#endif
{
}
static bool g_fResetting = false;
static bool g_fSaveState = false;
/** Helper function to load a local service DLL.
*
* @return VBox code
*/
int HGCMService::loadServiceDLL (void)
{
if (m_pszSvcLibrary == NULL)
{
return VERR_INVALID_PARAMETER;
}
if (RT_SUCCESS(rc))
{
LogFlowFunc(("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 (RT_SUCCESS(rc))
{
/* m_pfnLoad was NULL */
}
}
if (RT_SUCCESS(rc))
{
if (RT_SUCCESS(rc))
{
)
{
Log(("HGCMService::loadServiceDLL: at least one of function pointers is NULL\n"));
{
}
}
}
}
}
else
{
LogRel(("HGCM: Failed to load the service library: [%s], rc = %Rrc. The service will be not available.\n", m_pszSvcLibrary, rc));
}
if (RT_FAILURE(rc))
{
unloadServiceDLL ();
}
return rc;
}
/** Helper function to free a local service DLL.
*
* @return VBox code
*/
void HGCMService::unloadServiceDLL (void)
{
if (m_hLdrMod)
{
}
}
/*
* Messages processed by service threads. These threads only call the service entry points.
*/
#define SVC_MSG_LOAD (0) /* Load the service library and call VBOX_HGCM_SVCLOAD_NAME entry point. */
#ifdef VBOX_WITH_CRHGSMI
#endif
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 */
};
class HGCMMsgLoadSaveStateClient: public HGCMMsgCore
{
public:
};
class HGCMMsgHostCallSvc: public HGCMMsgCore
{
public:
/* function number */
/* number of parameters */
};
class HGCMMsgSvcRegisterExtension: public HGCMMsgCore
{
public:
/* Handle of the extension to be registered. */
/* The extension entry point. */
/* The extension pointer. */
void *pvExtension;
};
class HGCMMsgSvcUnregisterExtension: public HGCMMsgCore
{
public:
/* Handle of the registered extension. */
};
#ifdef VBOX_WITH_CRHGSMI
class HGCMMsgHostFastCallAsyncSvc: public HGCMMsgCore
{
public:
/* function number */
/* parameter */
/* completion info */
void *pvCompletion;
};
#endif
{
switch (u32MsgId)
{
#ifdef VBOX_WITH_CRHGSMI
case SVC_MSG_HOSTFASTCALLASYNC: return new HGCMMsgHostFastCallAsyncSvc ();
#endif
case SVC_MSG_LOAD: return new HGCMMsgSvcLoad ();
case SVC_MSG_UNLOAD: return new HGCMMsgSvcUnload ();
case SVC_MSG_CONNECT: return new HGCMMsgSvcConnect ();
case SVC_MSG_DISCONNECT: return new HGCMMsgSvcDisconnect ();
case SVC_MSG_HOSTCALL: return new HGCMMsgHostCallSvc ();
case SVC_MSG_GUESTCALL: return new HGCMMsgCall ();
case SVC_MSG_LOADSTATE:
case SVC_MSG_SAVESTATE: return new HGCMMsgLoadSaveStateClient ();
case SVC_MSG_REGEXT: return new HGCMMsgSvcRegisterExtension ();
case SVC_MSG_UNREGEXT: return new HGCMMsgSvcUnregisterExtension ();
default:
}
return NULL;
}
/*
* The service thread. Loads the service library and calls the service entry points.
*/
{
bool fQuit = false;
while (!fQuit)
{
if (RT_FAILURE(rc))
{
/* The error means some serious unrecoverable problem in the hgcmMsg/hgcmThread layer. */
break;
}
/* Cache required information to avoid unnecessary pMsgCore access. */
switch (u32MsgId)
{
#ifdef VBOX_WITH_CRHGSMI
{
LogFlowFunc(("SVC_MSG_HOSTFASTCALLASYNC u32Function = %d, pParm = %p\n", pMsg->u32Function, &pMsg->Param));
} break;
#endif
case SVC_MSG_LOAD:
{
LogFlowFunc(("SVC_MSG_LOAD\n"));
} break;
case SVC_MSG_UNLOAD:
{
LogFlowFunc(("SVC_MSG_UNLOAD\n"));
{
}
pSvc->unloadServiceDLL ();
fQuit = true;
} break;
case SVC_MSG_CONNECT:
{
if (pClient)
{
rc = pSvc->m_fntable.pfnConnect (pSvc->m_fntable.pvService, pMsg->u32ClientId, HGCM_CLIENT_DATA(pSvc, pClient));
}
else
{
}
} break;
case SVC_MSG_DISCONNECT:
{
if (pClient)
{
rc = pSvc->m_fntable.pfnDisconnect (pSvc->m_fntable.pvService, pMsg->u32ClientId, HGCM_CLIENT_DATA(pSvc, pClient));
}
else
{
}
} break;
case SVC_MSG_GUESTCALL:
{
LogFlowFunc(("SVC_MSG_GUESTCALL u32ClientId = %d, u32Function = %d, cParms = %d, paParms = %p\n",
if (pClient)
{
pSvc->m_fntable.pfnCall (pSvc->m_fntable.pvService, (VBOXHGCMCALLHANDLE)pMsg, pMsg->u32ClientId, HGCM_CLIENT_DATA(pSvc, pClient), pMsg->u32Function, pMsg->cParms, pMsg->paParms);
}
else
{
}
} break;
case SVC_MSG_HOSTCALL:
{
LogFlowFunc(("SVC_MSG_HOSTCALL u32Function = %d, cParms = %d, paParms = %p\n", pMsg->u32Function, pMsg->cParms, pMsg->paParms));
rc = pSvc->m_fntable.pfnHostCall (pSvc->m_fntable.pvService, pMsg->u32Function, pMsg->cParms, pMsg->paParms);
} break;
case SVC_MSG_LOADSTATE:
{
LogFlowFunc(("SVC_MSG_LOADSTATE\n"));
if (pClient)
{
{
rc = pSvc->m_fntable.pfnLoadState (pSvc->m_fntable.pvService, pMsg->u32ClientId, HGCM_CLIENT_DATA(pSvc, pClient), pMsg->pSSM);
}
}
else
{
}
} break;
case SVC_MSG_SAVESTATE:
{
LogFlowFunc(("SVC_MSG_SAVESTATE\n"));
rc = VINF_SUCCESS;
if (pClient)
{
{
g_fSaveState = true;
rc = pSvc->m_fntable.pfnSaveState (pSvc->m_fntable.pvService, pMsg->u32ClientId, HGCM_CLIENT_DATA(pSvc, pClient), pMsg->pSSM);
g_fSaveState = false;
}
}
else
{
}
} break;
case SVC_MSG_REGEXT:
{
if (pSvc->m_hExtension)
{
}
else
{
{
rc = pSvc->m_fntable.pfnRegisterExtension (pSvc->m_fntable.pvService, pMsg->pfnExtension, pMsg->pvExtension);
}
else
{
}
if (RT_SUCCESS(rc))
{
}
}
} break;
case SVC_MSG_UNREGEXT:
{
{
}
else
{
{
}
else
{
}
}
} break;
default:
{
} break;
}
if (u32MsgId != SVC_MSG_GUESTCALL)
{
/* For SVC_MSG_GUESTCALL the service calls the completion helper.
* Other messages have to be completed here.
*/
}
}
}
/* 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 ();
}
}
/* static */ DECLCALLBACK(void) HGCMService::svcHlpDisconnectClient (void *pvInstance, uint32_t u32ClientId)
{
if (pService)
{
}
}
{
/* Call the VMMDev port interface to issue IRQ notification. */
{
pMsgHdr->pHGCMPort->pfnCompleted (pMsgHdr->pHGCMPort, g_fSaveState? VINF_HGCM_SAVE_STATE: result, pMsgHdr->pCmd);
}
}
/*
* The main HGCM methods of the service.
*/
{
/* The maximum length of the thread name, allowed by the RT is 15. */
char achThreadName[16];
achThreadName[15] = 0;
if (RT_SUCCESS(rc))
{
if (!m_pszSvcName || !m_pszSvcLibrary)
{
m_pszSvcName = NULL;
rc = VERR_NO_MEMORY;
}
else
{
/* Initialize service helpers table. */
m_svcHelpers.pvInstance = this;
/* Execute the load request on the service thread. */
if (RT_SUCCESS(rc))
{
}
}
}
if (RT_FAILURE(rc))
{
instanceDestroy ();
}
return rc;
}
void HGCMService::instanceDestroy (void)
{
if (RT_SUCCESS(rc))
{
if (RT_SUCCESS(rc))
{
}
}
m_pszSvcName = NULL;
}
{
if (RT_SUCCESS(rc))
{
HGCMMsgLoadSaveStateClient *pMsg = (HGCMMsgLoadSaveStateClient *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
}
return rc;
}
{
if (RT_SUCCESS(rc))
{
HGCMMsgLoadSaveStateClient *pMsg = (HGCMMsgLoadSaveStateClient *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
}
return rc;
}
/** The method creates a service and references it.
*
* @param pszServcieLibrary The library to be loaded.
* @param pszServiceName The name of the service.
* @return VBox rc.
* @thread main HGCM
*/
/* static */ int HGCMService::LoadService (const char *pszServiceLibrary, const char *pszServiceName)
{
/* Look at already loaded services to avoid double loading. */
if (RT_SUCCESS(rc))
{
/* The service is already loaded. */
pSvc->ReleaseService ();
}
else
{
/* Create the new service. */
pSvc = new HGCMService ();
if (!pSvc)
{
rc = VERR_NO_MEMORY;
}
else
{
/* Load the library and call the initialization entry point. */
if (RT_SUCCESS(rc))
{
/* Insert the just created service to list for future references. */
if (sm_pSvcListHead)
{
}
else
{
}
sm_cServices++;
/* Reference the service (for first time) until it is unloaded on HGCM termination. */
pSvc->ReferenceService ();
}
}
}
return rc;
}
/** The method unloads a service.
*
* @thread main HGCM
*/
void HGCMService::UnloadService (void)
{
/* Remove the service from the list. */
if (m_pSvcNext)
{
}
else
{
}
if (m_pSvcPrev)
{
}
else
{
}
sm_cServices--;
/* The service must be unloaded only if all clients were disconnected. */
/* Now the service can be released. */
ReleaseService ();
}
/** The method unloads all services.
*
* @thread main HGCM
*/
{
while (sm_pSvcListHead)
{
}
}
/** The method obtains a referenced pointer to the service with
* specified name. The caller must call ReleaseService when
* the pointer is no longer needed.
*
* @param ppSvc Where to store the pointer to the service.
* @param pszServiceName The name of the service.
* @return VBox rc.
* @thread main HGCM
*/
{
LogFlowFunc(("ppSvc = %p name = %s\n",
ppSvc, pszServiceName));
if (!ppSvc || !pszServiceName)
{
return VERR_INVALID_PARAMETER;
}
while (pSvc)
{
{
break;
}
}
{
return VERR_HGCM_SERVICE_NOT_FOUND;
}
pSvc->ReferenceService ();
return VINF_SUCCESS;
}
/** The method increases reference counter.
*
* @thread main HGCM
*/
void HGCMService::ReferenceService (void)
{
}
/** The method dereferences a service and deletes it when no more refs.
*
* @thread main HGCM
*/
void HGCMService::ReleaseService (void)
{
AssertRelease(u32RefCnt != ~0U);
if (u32RefCnt == 0)
{
instanceDestroy ();
delete this;
}
}
/** The method is called when the VM is being reset or terminated
* and disconnects all clients from all services.
*
* @thread main HGCM
*/
{
g_fResetting = true;
while (pSvc)
{
{
}
#ifdef VBOX_WITH_CRHGSMI
/* @todo: could this actually happen that the service is destroyed on ReleaseService? */
while (pSvc->m_cHandleAcquires)
{
pSvc->HandleReleased ();
pSvc->ReleaseService ();
}
#else
#endif
}
g_fResetting = false;
}
/** The method saves the HGCM state.
*
* @param pSSM The saved state context.
* @return VBox rc.
* @thread main HGCM
*/
{
/* 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;
}
/** The method loads saved HGCM state.
*
* @param pSSM The saved state context.
* @return VBox rc.
* @thread main HGCM
*/
{
/* 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. */
if (RT_FAILURE(rc))
{
pSvc->ReleaseService ();
AssertFailed();
return rc;
}
while (cClients--)
{
/* Get the client id. */
if (RT_FAILURE(rc))
{
pSvc->ReleaseService ();
AssertFailed();
return rc;
}
/* Connect the client. */
if (RT_FAILURE(rc))
{
pSvc->ReleaseService ();
return rc;
}
/* Call the service, so the operation is executed by the service thread. */
if (RT_FAILURE(rc))
{
pSvc->ReleaseService ();
return rc;
}
}
pSvc->ReleaseService ();
}
return VINF_SUCCESS;
}
/* 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.
* @return VBox rc.
*/
{
/* Allocate a client information structure. */
if (!pClient)
{
LogWarningFunc(("Could not allocate HGCMClient!!!\n"));
return VERR_NO_MEMORY;
}
if (pu32ClientIdOut != NULL)
{
}
else
{
}
/* Initialize the HGCM part of the client. */
if (RT_SUCCESS(rc))
{
/* Call the service. */
if (RT_SUCCESS(rc))
{
if (RT_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_cClientsAllocated += 64;
}
m_cClients++;
}
}
}
if (RT_FAILURE(rc))
{
}
else
{
if (pu32ClientIdOut != NULL)
{
}
ReferenceService ();
}
return rc;
}
/* Disconnect the client from the service and delete the client handle.
*
* @param u32ClientId The handle of the client.
* @return VBox rc.
*/
{
int rc = VINF_SUCCESS;
if (!fFromService)
{
/* Call the service. */
if (RT_SUCCESS(rc))
{
}
else
{
LogRel(("(%d, %d) [%s] hgcmMsgAlloc(%p, SVC_MSG_DISCONNECT) failed %Rrc\n",
}
}
/* Remove the client id from the array in any case, rc does not matter. */
int i;
for (i = 0; i < m_cClients; i++)
{
if (m_paClientIds[i] == u32ClientId)
{
m_cClients--;
if (m_cClients > i)
{
}
/* Delete the client handle. */
/* The service must be released. */
ReleaseService ();
break;
}
}
return rc;
}
void *pvExtension)
{
/* Forward the message to the service thread. */
HGCMMSGHANDLE hMsg = 0;
if (RT_SUCCESS(rc))
{
HGCMMsgSvcRegisterExtension *pMsg = (HGCMMsgSvcRegisterExtension *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
}
return rc;
}
{
/* Forward the message to the service thread. */
HGCMMSGHANDLE hMsg = 0;
if (RT_SUCCESS(rc))
{
HGCMMsgSvcUnregisterExtension *pMsg = (HGCMMsgSvcUnregisterExtension *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
}
}
/* Perform a guest call to the service.
*
* @param pHGCMPort The port to be used for completion confirmation.
* @param pCmd The VBox HGCM context.
* @param u32ClientId The client handle to be disconnected and deleted.
* @param u32Function The function number.
* @param cParms Number of parameters.
* @param paParms Pointer to array of parameters.
* @return VBox rc.
*/
int HGCMService::GuestCall (PPDMIHGCMPORT pHGCMPort, PVBOXHGCMCMD pCmd, uint32_t u32ClientId, uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
{
HGCMMSGHANDLE hMsg = 0;
LogFlow(("MAIN::HGCMService::Call\n"));
if (RT_SUCCESS(rc))
{
}
else
{
}
return rc;
}
/* Perform a host call the service.
*
* @param u32Function The function number.
* @param cParms Number of parameters.
* @param paParms Pointer to array of parameters.
* @return VBox rc.
*/
{
LogFlowFunc(("%s u32Function = %d, cParms = %d, paParms = %p\n",
HGCMMSGHANDLE hMsg = 0;
if (RT_SUCCESS(rc))
{
}
return rc;
}
#ifdef VBOX_WITH_CRHGSMI
{
/* Call the VMMDev port interface to issue IRQ notification. */
if (pMsg->pfnCompletion)
{
}
}
int HGCMService::HandleAcquired()
{
return VINF_SUCCESS;
}
int HGCMService::HandleReleased()
{
if (m_cHandleAcquires)
{
return VINF_SUCCESS;
}
return VERR_INVALID_STATE;
}
int HGCMService::HostFastCallAsync (uint32_t u32Function, VBOXHGCMSVCPARM *pParm, PHGCMHOSTFASTCALLCB pfnCompletion, void *pvCompletion)
{
LogFlowFunc(("%s u32Function = %d, pParm = %p\n",
HGCMMSGHANDLE hMsg = 0;
if (RT_SUCCESS(rc))
{
HGCMMsgHostFastCallAsyncSvc *pMsg = (HGCMMsgHostFastCallAsyncSvc *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
}
return rc;
}
#endif
/*
* Main HGCM thread that manages services.
*/
/* Messages processed by the main HGCM thread. */
#ifdef VBOX_WITH_CRHGSMI
#endif
class HGCMMsgMainConnect: public HGCMMsgHeader
{
public:
/* Service name. */
const char *pszServiceName;
/* Where to store the client handle. */
};
class HGCMMsgMainDisconnect: public HGCMMsgHeader
{
public:
/* Handle of the client to be disconnected. */
};
class HGCMMsgMainLoad: public HGCMMsgCore
{
public:
/* Name of the library to be loaded. */
const char *pszServiceLibrary;
/* Name to be assigned to the service. */
const char *pszServiceName;
};
class HGCMMsgMainHostCall: public HGCMMsgCore
{
public:
/* Which service to call. */
const char *pszServiceName;
/* Function number. */
/* Number of the function parameters. */
/* Pointer to array of the function parameters. */
};
class HGCMMsgMainLoadSaveState: public HGCMMsgCore
{
public:
/* SSM context. */
};
class HGCMMsgMainReset: public HGCMMsgCore
{
};
class HGCMMsgMainQuit: public HGCMMsgCore
{
};
class HGCMMsgMainRegisterExtension: public HGCMMsgCore
{
public:
/* Returned handle to be used in HGCMMsgMainUnregisterExtension. */
/* Name of the service. */
const char *pszServiceName;
/* The extension entry point. */
/* The extension pointer. */
void *pvExtension;
};
class HGCMMsgMainUnregisterExtension: public HGCMMsgCore
{
public:
/* Handle of the registered extension. */
};
#ifdef VBOX_WITH_CRHGSMI
class HGCMMsgMainSvcAcquire: public HGCMMsgCore
{
public:
/* Which service to call. */
const char *pszServiceName;
/* Returned service. */
};
class HGCMMsgMainSvcRelease: public HGCMMsgCore
{
public:
/* Svc . */
};
#endif
{
switch (u32MsgId)
{
case HGCM_MSG_CONNECT: return new HGCMMsgMainConnect ();
case HGCM_MSG_DISCONNECT: return new HGCMMsgMainDisconnect ();
case HGCM_MSG_LOAD: return new HGCMMsgMainLoad ();
case HGCM_MSG_HOSTCALL: return new HGCMMsgMainHostCall ();
case HGCM_MSG_LOADSTATE:
case HGCM_MSG_SAVESTATE: return new HGCMMsgMainLoadSaveState ();
case HGCM_MSG_RESET: return new HGCMMsgMainReset ();
case HGCM_MSG_QUIT: return new HGCMMsgMainQuit ();
case HGCM_MSG_REGEXT: return new HGCMMsgMainRegisterExtension ();
case HGCM_MSG_UNREGEXT: return new HGCMMsgMainUnregisterExtension ();
#ifdef VBOX_WITH_CRHGSMI
case HGCM_MSG_SVCAQUIRE: return new HGCMMsgMainSvcAcquire();
case HGCM_MSG_SVCRELEASE: return new HGCMMsgMainSvcRelease();
#endif
default:
}
return NULL;
}
/* The main HGCM thread handler. */
{
LogFlowFunc(("ThreadHandle = %p, pvUser = %p\n",
ThreadHandle, pvUser));
bool fQuit = false;
while (!fQuit)
{
if (RT_FAILURE(rc))
{
/* The error means some serious unrecoverable problem in the hgcmMsg/hgcmThread layer. */
break;
}
switch (u32MsgId)
{
case HGCM_MSG_CONNECT:
{
LogFlowFunc(("HGCM_MSG_CONNECT pszServiceName %s, pu32ClientId %p\n",
/* Resolve the service name to the pointer to service instance.
*/
if (RT_SUCCESS(rc))
{
/* Call the service instance method. */
/* Release the service after resolve. */
pService->ReleaseService ();
}
} break;
case HGCM_MSG_DISCONNECT:
{
LogFlowFunc(("HGCM_MSG_DISCONNECT u32ClientId = %d\n",
pMsg->u32ClientId));
if (!pClient)
{
break;
}
/* The service the client belongs to. */
/* Call the service instance to disconnect the client. */
} break;
case HGCM_MSG_LOAD:
{
LogFlowFunc(("HGCM_MSG_LOAD pszServiceName = %s, pMsg->pszServiceLibrary = %s\n",
} break;
case HGCM_MSG_HOSTCALL:
{
LogFlowFunc(("HGCM_MSG_HOSTCALL pszServiceName %s, u32Function %d, cParms %d, paParms %p\n",
/* Resolve the service name to the pointer to service instance. */
if (RT_SUCCESS(rc))
{
pService->ReleaseService ();
}
} break;
#ifdef VBOX_WITH_CRHGSMI
case HGCM_MSG_SVCAQUIRE:
{
/* Resolve the service name to the pointer to service instance. */
if (RT_SUCCESS(rc))
{
if (RT_SUCCESS(rc))
{
}
else
{
pService->ReleaseService ();
}
}
} break;
case HGCM_MSG_SVCRELEASE:
{
/* Resolve the service name to the pointer to service instance. */
if (RT_SUCCESS(rc))
{
}
} break;
#endif
case HGCM_MSG_RESET:
{
LogFlowFunc(("HGCM_MSG_RESET\n"));
HGCMService::Reset ();
} break;
case HGCM_MSG_LOADSTATE:
{
LogFlowFunc(("HGCM_MSG_LOADSTATE\n"));
} break;
case HGCM_MSG_SAVESTATE:
{
LogFlowFunc(("HGCM_MSG_SAVESTATE\n"));
} break;
case HGCM_MSG_QUIT:
{
LogFlowFunc(("HGCM_MSG_QUIT\n"));
HGCMService::UnloadAll ();
fQuit = true;
} break;
case HGCM_MSG_REGEXT:
{
LogFlowFunc(("HGCM_MSG_REGEXT\n"));
/* Allocate the handle data. */
+ sizeof (char));
{
rc = VERR_NO_MEMORY;
}
else
{
if (RT_SUCCESS(rc))
{
pService->ReleaseService ();
}
if (RT_FAILURE(rc))
{
}
else
{
}
}
} break;
case HGCM_MSG_UNREGEXT:
{
LogFlowFunc(("HGCM_MSG_UNREGEXT\n"));
if (RT_SUCCESS(rc))
{
pService->ReleaseService ();
}
} break;
default:
{
} break;
}
/* Complete the message processing. */
}
}
/*
* The HGCM API.
*/
/* The main hgcm thread. */
static HGCMTHREADHANDLE g_hgcmThread = 0;
/*
* Public HGCM functions.
*
* hgcmGuest* - called as a result of the guest HGCM requests.
* hgcmHost* - called by the host.
*/
/* Load a HGCM service from the specified library.
* Assign the specified name to the service.
*
* @param pszServiceLibrary The library to be loaded.
* @param pszServiceName The name to be assigned to the service.
* @return VBox rc.
*/
int HGCMHostLoad (const char *pszServiceLibrary,
const char *pszServiceName)
{
if (!pszServiceLibrary || !pszServiceName)
{
return VERR_INVALID_PARAMETER;
}
/* Forward the request to the main hgcm thread. */
HGCMMSGHANDLE hMsg = 0;
if (RT_SUCCESS(rc))
{
/* Initialize the message. Since the message is synchronous, use the supplied pointers. */
}
return rc;
}
/* Register a HGCM service extension.
*
* @param pHandle Returned handle for the registered extension.
* @param pszServiceName The name of the service.
* @param pfnExtension The extension entry point (callback).
* @param pvExtension The extension pointer.
* @return VBox rc.
*/
const char *pszServiceName,
void *pvExtension)
{
LogFlowFunc(("pHandle = %p, name = %s, pfn = %p, rv = %p\n", pHandle, pszServiceName, pfnExtension, pvExtension));
{
return VERR_INVALID_PARAMETER;
}
/* Forward the request to the main hgcm thread. */
HGCMMSGHANDLE hMsg = 0;
if (RT_SUCCESS(rc))
{
/* Initialize the message. Since the message is synchronous, use the supplied pointers. */
HGCMMsgMainRegisterExtension *pMsg = (HGCMMsgMainRegisterExtension *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
}
return rc;
}
{
/* Forward the request to the main hgcm thread. */
HGCMMSGHANDLE hMsg = 0;
if (RT_SUCCESS(rc))
{
/* Initialize the message. */
HGCMMsgMainUnregisterExtension *pMsg = (HGCMMsgMainUnregisterExtension *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
}
return;
}
/* Find a service and inform it about a client connection, create a client handle.
*
* @param pHGCMPort The port to be used for completion confirmation.
* @param pCmd The VBox HGCM context.
* @param pszServiceName The name of the service to be connected to.
* @param pu32ClientId Where the store the created client handle.
* @return VBox rc.
*/
const char *pszServiceName,
{
LogFlowFunc(("pHGCMPort = %p, pCmd = %p, name = %s, pu32ClientId = %p\n",
{
return VERR_INVALID_PARAMETER;
}
/* Forward the request to the main hgcm thread. */
HGCMMSGHANDLE hMsg = 0;
if (RT_SUCCESS(rc))
{
/* Initialize the message. Since 'pszServiceName' and 'pu32ClientId'
* will not be deallocated by the caller until the message is completed,
* use the supplied pointers.
*/
}
return rc;
}
/* Tell a service that the client is disconnecting, destroy the client handle.
*
* @param pHGCMPort The port to be used for completion confirmation.
* @param pCmd The VBox HGCM context.
* @param u32ClientId The client handle to be disconnected and deleted.
* @return VBox rc.
*/
{
LogFlowFunc(("pHGCMPort = %p, pCmd = %p, u32ClientId = %d\n",
{
return VERR_INVALID_PARAMETER;
}
/* Forward the request to the main hgcm thread. */
HGCMMSGHANDLE hMsg = 0;
if (RT_SUCCESS(rc))
{
/* Initialize the message. */
}
return rc;
}
/* Helper to send either HGCM_MSG_SAVESTATE or HGCM_MSG_LOADSTATE messages to the main HGCM thread.
*
* @param pSSM The SSM handle.
* @param u32MsgId The message to be sent: HGCM_MSG_SAVESTATE or HGCM_MSG_LOADSTATE.
* @return VBox rc.
*/
{
HGCMMSGHANDLE hMsg = 0;
if (RT_SUCCESS(rc))
{
}
return rc;
}
/* Save the state of services.
*
* @param pSSM The SSM handle.
* @return VBox rc.
*/
{
}
/* Load the state of services.
*
* @param pSSM The SSM handle.
* @return VBox rc.
*/
{
}
/* The guest calls the service.
*
* @param pHGCMPort The port to be used for completion confirmation.
* @param pCmd The VBox HGCM context.
* @param u32ClientId The client handle to be disconnected and deleted.
* @param u32Function The function number.
* @param cParms Number of parameters.
* @param paParms Pointer to array of parameters.
* @return VBox rc.
*/
{
LogFlowFunc(("pHGCMPort = %p, pCmd = %p, u32ClientId = %d, u32Function = %d, cParms = %d, paParms = %p\n",
{
return VERR_INVALID_PARAMETER;
}
int rc = VERR_HGCM_INVALID_CLIENT_ID;
/* Resolve the client handle to the client instance pointer. */
if (pClient)
{
/* Forward the message to the service thread. */
}
return rc;
}
/* The host calls the service.
*
* @param pszServiceName The service name to be called.
* @param u32Function The function number.
* @param cParms Number of parameters.
* @param paParms Pointer to array of parameters.
* @return VBox rc.
*/
int HGCMHostCall (const char *pszServiceName,
{
LogFlowFunc(("name = %s, u32Function = %d, cParms = %d, paParms = %p\n",
if (!pszServiceName)
{
return VERR_INVALID_PARAMETER;
}
HGCMMSGHANDLE hMsg = 0;
/* Host calls go to main HGCM thread that resolves the service name to the
* service instance pointer and then, using the service pointer, forwards
* the message to the service thread.
* So it is slow but host calls are intended mostly for configuration and
* other non-time-critical functions.
*/
if (RT_SUCCESS(rc))
{
}
return rc;
}
#ifdef VBOX_WITH_CRHGSMI
{
if (!pszServiceName)
{
return VERR_INVALID_PARAMETER;
}
if (!phSvc)
{
return VERR_INVALID_PARAMETER;
}
HGCMMSGHANDLE hMsg = 0;
/* Host calls go to main HGCM thread that resolves the service name to the
* service instance pointer and then, using the service pointer, forwards
* the message to the service thread.
* So it is slow but host calls are intended mostly for configuration and
* other non-time-critical functions.
*/
if (RT_SUCCESS(rc))
{
if (RT_SUCCESS(rc))
{
/* for simplicity just use a svc ptr as handle for now */
}
}
return rc;
}
{
if (!hSvc)
{
return VERR_INVALID_PARAMETER;
}
HGCMMSGHANDLE hMsg = 0;
/* Host calls go to main HGCM thread that resolves the service name to the
* service instance pointer and then, using the service pointer, forwards
* the message to the service thread.
* So it is slow but host calls are intended mostly for configuration and
* other non-time-critical functions.
*/
if (RT_SUCCESS(rc))
{
}
return rc;
}
int HGCMHostFastCallAsync (HGCMCVSHANDLE hSvc, uint32_t function, VBOXHGCMSVCPARM *pParm, PHGCMHOSTFASTCALLCB pfnCompletion, void *pvCompletion)
{
LogFlowFunc(("hSvc = %p, u32Function = %d, pParm = %p\n",
if (!hSvc)
{
return VERR_INVALID_PARAMETER;
}
return rc;
}
#endif
int HGCMHostReset (void)
{
LogFlowFunc(("\n"));
/* Disconnect all clients.
*/
HGCMMSGHANDLE hMsg = 0;
if (RT_SUCCESS(rc))
{
}
return rc;
}
int HGCMHostInit (void)
{
LogFlowFunc(("\n"));
int rc = hgcmThreadInit ();
if (RT_SUCCESS(rc))
{
/*
* Start main HGCM thread.
*/
if (RT_FAILURE(rc))
{
}
}
return rc;
}
int HGCMHostShutdown (void)
{
LogFlowFunc(("\n"));
/*
* Do HGCMReset and then unload all services.
*/
int rc = HGCMHostReset ();
if (RT_SUCCESS(rc))
{
/* Send the quit message to the main hgcmThread. */
HGCMMSGHANDLE hMsg = 0;
if (RT_SUCCESS(rc))
{
if (RT_SUCCESS(rc))
{
/* Wait for the thread termination. */
g_hgcmThread = 0;
hgcmThreadUninit ();
}
}
}
return rc;
}