service.cpp revision e64031e20c39650a7bc902a3e1aba613b9415dee
/* $Id$ */
/** @file
* Guest Control Service: Controlling the guest.
*/
/*
* Copyright (C) 2010 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.
*/
/** @page pg_svc_guest_control Guest Control HGCM Service
*
* @todo Write up some nice text here.
*/
/*******************************************************************************
* Header Files *
*******************************************************************************/
#define LOG_GROUP LOG_GROUP_HGCM
#include <memory> /* for auto_ptr */
#include <string>
#include <list>
#include "gctrl.h"
namespace guestControl {
/**
* Structure for holding a buffered host command
*/
struct HostCmd
{
/** Dynamic structure for holding the HGCM parms */
};
/** The host cmd list type */
/**
* Structure for holding an uncompleted guest call
*/
struct GuestCall
{
/** The call handle */
/** The function that was requested */
/** The call parameters */
/** Number of parameters */
/** The default return value, used for passing warnings */
int mRc;
/** The standard constructor */
/** The normal contructor */
};
/** The guest call list type */
/**
* Class containing the shared information service functionality.
*/
{
private:
/** Type definition for use in callback functions */
/** HGCM helper functions. */
/** @todo we should have classes for thread and request handler thread */
/** Queue of outstanding property change notifications */
/** Request that we've left pending in a call to flushNotifications. */
/** Thread for processing the request queue */
/** Tell the thread that it should exit */
bool volatile mfExitThread;
/** Callback function supplied by the host for notification of updates
* to properties */
/** User data pointer to be supplied to the host callback function */
void *mpvHostData;
/** The deferred calls list */
/** The host command list */
public:
, mfExitThread(false)
, mpvHostData(NULL)
{
#ifndef VBOX_GUEST_CTRL_TEST_NOTHREAD
if (RT_SUCCESS(rc))
"GuestCtrlReq");
#endif
if (RT_FAILURE(rc))
throw rc;
}
/**
* @copydoc VBOXHGCMSVCHELPERS::pfnUnload
* Simply deletes the service object
*/
{
if (RT_SUCCESS(rc))
delete pSelf;
return rc;
}
/**
* @copydoc VBOXHGCMSVCHELPERS::pfnConnect
* Stub implementation of pfnConnect and pfnDisconnect.
*/
void *pvClient)
{
return rc;
}
/**
* @copydoc VBOXHGCMSVCHELPERS::pfnConnect
* Stub implementation of pfnConnect and pfnDisconnect.
*/
void *pvClient)
{
return rc;
}
/**
* @copydoc VBOXHGCMSVCHELPERS::pfnCall
* Wraps to the call member function
*/
void *pvClient,
{
LogFlowFunc (("pvService=%p, callHandle=%p, u32ClientID=%u, pvClient=%p, u32Function=%u, cParms=%u, paParms=%p\n", pvService, callHandle, u32ClientID, pvClient, u32Function, cParms, paParms));
LogFlowFunc (("returning\n"));
}
/**
* @copydoc VBOXHGCMSVCHELPERS::pfnHostCall
* Wraps to the hostCall member function
*/
{
LogFlowFunc (("pvService=%p, u32Function=%u, cParms=%u, paParms=%p\n", pvService, u32Function, cParms, paParms));
return rc;
}
/**
* @copydoc VBOXHGCMSVCHELPERS::pfnRegisterExtension
* Installs a host callback for notifications of property changes.
*/
void *pvExtension)
{
return VINF_SUCCESS;
}
private:
int paramBufferAllocate(PVBOXGUESTCTRPARAMBUFFER pBuf, uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
int uninit();
};
/**
* Thread function for processing the request queue
* @copydoc FNRTTHREAD
*/
/* static */
{
while (!pSelf->mfExitThread)
return VINF_SUCCESS;
}
/** @todo Write some nice doc headers! */
/* Stores a HGCM request in an internal buffer (pEx). Needs to be freed later using execBufferFree(). */
int Service::paramBufferAllocate(PVBOXGUESTCTRPARAMBUFFER pBuf, uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
{
int rc = VINF_SUCCESS;
/*
* Don't verify anything here (yet), because this function only buffers
* the HGCM data into an internal structure and reaches it back to the guest (client)
* in an unmodified state.
*/
if (RT_SUCCESS(rc))
{
{
rc = VERR_NO_MEMORY;
}
else
{
{
{
case VBOX_HGCM_SVC_PARM_32BIT:
break;
case VBOX_HGCM_SVC_PARM_64BIT:
/* Not supported yet. */
break;
case VBOX_HGCM_SVC_PARM_PTR:
{
{
rc = VERR_NO_MEMORY;
break;
}
else
}
break;
default:
break;
}
if (RT_FAILURE(rc))
break;
}
}
}
return rc;
}
/* Frees a buffered HGCM request. */
{
{
{
case VBOX_HGCM_SVC_PARM_PTR:
break;
}
}
if (pBuf->uParmCount)
{
pBuf->uParmCount = 0;
}
}
/* Assigns data from a buffered HGCM request to the current HGCM request. */
int Service::paramBufferAssign(PVBOXGUESTCTRPARAMBUFFER pBuf, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
{
int rc = VINF_SUCCESS;
{
}
else
{
/** @todo Add check to verify if the HGCM request is the same *type* as the buffered one! */
{
{
case VBOX_HGCM_SVC_PARM_32BIT:
break;
case VBOX_HGCM_SVC_PARM_64BIT:
/* Not supported yet. */
break;
case VBOX_HGCM_SVC_PARM_PTR:
break;
default:
break;
}
}
}
return rc;
}
{
return VINF_SUCCESS;
}
{
return VINF_SUCCESS;
}
/*
* Either fills in parameters from a pending host command into our guest context or
* defer the guest call until we have something from the host.
*/
int Service::processHostMsg(VBOXHGCMCALLHANDLE callHandle, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
{
int rc = VINF_SUCCESS;
if (cParms < 2)
{
LogFlowFunc(("Guest parameter buffer is too small!\n"));
}
else
{
/*
* If host command list is empty (nothing to do right now) just
* defer the call until we got something to do (makes the client
* wait, depending on the flags set).
*/
if (rc != VINF_HGCM_ASYNC_EXECUTE)
{
/*
* Get the next unassigned host command in the list.
*/
/* Sufficient parameter space? */
if (uParmCount > cParms)
{
/*
* So this call apparently failed because the guest wanted to peek
* how much parameters it has to supply in order to successfully retrieve
* this command. Let's tell him so!
*/
}
else
{
if (RT_SUCCESS(rc))
{
}
}
}
else
{
/* Call is deferred because of reasons above. */
}
}
return rc;
}
/*
* order to wake up and do some work.
*/
int Service::notifyGuest(GuestCall *pCall, uint32_t eFunction, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
{
int rc = VINF_SUCCESS;
if (RT_SUCCESS(rc2))
return rc;
}
{
LogFlowFunc(("eFunction=%ld, cParms=%ld, paParms=%p\n",
int rc = VINF_SUCCESS;
if ( eFunction == GUEST_EXEC_SEND_STATUS
&& cParms == 5)
{
if (mpfnHostCallback)
}
else if ( eFunction == GUEST_EXEC_SEND_OUTPUT
&& cParms == 5)
{
if (mpfnHostCallback)
}
else
return rc;
}
{
int rc = VINF_SUCCESS;
/* Some lazy guests to wake up which can process this command right now? */
if (!mGuestWaiters.empty())
{
if (RT_SUCCESS(rc))
{
/* Limit list size by deleting oldest element. */
}
}
else /* No guest waiting, don't bother ... */
rc = VERR_TIMEOUT;
return rc;
}
/**
* Handle an HGCM service call.
* @copydoc VBOXHGCMSVCFNTABLE::pfnCall
* @note All functions which do not involve an unreasonable delay will be
* handled synchronously. If needed, we will add a request handler
* thread in future for those which do.
*
* @thread HGCM
*/
{
int rc = VINF_SUCCESS;
LogFlowFunc(("u32ClientID = %d, fn = %d, cParms = %d, pparms = %d\n",
try
{
switch (eFunction)
{
/* The guest asks the host for the next messsage to process. */
case GUEST_GET_HOST_MSG:
LogFlowFunc(("GUEST_GET_HOST_MSG\n"));
break;
case GUEST_EXEC_SEND_OUTPUT:
LogFlowFunc(("GUEST_EXEC_SEND_OUTPUT\n"));
break;
/* The guest notifies the host of the current client status. */
case GUEST_EXEC_SEND_STATUS:
LogFlowFunc(("SEND_STATUS\n"));
break;
default:
break;
}
/*
* If current call is not deferred, call the completion function.
*/
if (rc != VINF_HGCM_ASYNC_EXECUTE)
{
}
}
{
rc = VERR_NO_MEMORY;
}
}
/**
* Service call handler for the host.
* @copydoc VBOXHGCMSVCFNTABLE::pfnHostCall
* @thread hgcm
*/
{
int rc = VINF_SUCCESS;
LogFlowFunc(("fn = %d, cParms = %d, pparms = %d\n",
try
{
switch (eFunction)
{
/* The host wants to execute something. */
case HOST_EXEC_CMD:
LogFlowFunc(("HOST_EXEC_CMD\n"));
break;
/* The host wants to send something to the guest's stdin pipe. */
case HOST_EXEC_SET_INPUT:
LogFlowFunc(("HOST_EXEC_SET_INPUT\n"));
break;
case HOST_EXEC_GET_OUTPUT:
LogFlowFunc(("HOST_EXEC_GET_OUTPUT\n"));
break;
default:
break;
}
}
{
rc = VERR_NO_MEMORY;
}
return rc;
}
{
int rc = VINF_SUCCESS;
return rc;
}
} /* namespace guestControl */
using guestControl::Service;
/**
* @copydoc VBOXHGCMSVCLOAD
*/
{
int rc = VINF_SUCCESS;
{
}
else
{
LogFlowFunc(("ptable->cbSize = %d, ptable->u32Version = 0x%08X\n", ptable->cbSize, ptable->u32Version));
{
}
else
{
/* No exceptions may propogate outside. */
try {
} catch (int rcThrown) {
} catch (...) {
}
if (RT_SUCCESS(rc))
{
/*
* We don't need an additional client data area on the host,
* because we're a class which can have members for that :-).
*/
/* Register functions. */
/* Service specific initialization. */
}
}
}
return rc;
}