/* $Id: client.cpp 85318 2020-07-13 21:07:41Z vboxsync $ */ /** @file * Base class for a host-guest service. */ /* * Copyright (C) 2011-2020 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; * you can redistribute it and/or modify it under the terms of the GNU * 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 #include #include #include #include #include using namespace HGCM; Client::Client(uint32_t idClient) : m_idClient(idClient) , m_uProtocolVer(0) , m_fDeferred(false) { RT_ZERO(m_Deferred); RT_ZERO(m_SvcCtx); } Client::~Client(void) { } /** * Completes a guest call by returning the control back to the guest side, * together with a status code, internal version. * * @returns IPRT status code. * @param hHandle Call handle to complete guest call for. * @param rcOp Return code to return to the guest side. */ int Client::completeInternal(VBOXHGCMCALLHANDLE hHandle, int rcOp) RT_NOEXCEPT { LogFlowThisFunc(("idClient=%RU32\n", m_idClient)); if ( m_SvcCtx.pHelpers && m_SvcCtx.pHelpers->pfnCallComplete) { m_SvcCtx.pHelpers->pfnCallComplete(hHandle, rcOp); reset(); return VINF_SUCCESS; } return VERR_NOT_AVAILABLE; } /** * Resets the client's internal state. */ void Client::reset(void) RT_NOEXCEPT { m_fDeferred = false; RT_ZERO(m_Deferred); } /** * Completes a guest call by returning the control back to the guest side, * together with a status code. * * @returns IPRT status code. * @param hHandle Call handle to complete guest call for. * @param rcOp Return code to return to the guest side. */ int Client::Complete(VBOXHGCMCALLHANDLE hHandle, int rcOp /* = VINF_SUCCESS */) RT_NOEXCEPT { return completeInternal(hHandle, rcOp); } /** * Completes a deferred guest call by returning the control back to the guest side, * together with a status code. * * @returns IPRT status code. VERR_INVALID_STATE if the client is not in deferred mode. * @param rcOp Return code to return to the guest side. */ int Client::CompleteDeferred(int rcOp) RT_NOEXCEPT { if (m_fDeferred) { Assert(m_Deferred.hHandle != NULL); int rc = completeInternal(m_Deferred.hHandle, rcOp); if (RT_SUCCESS(rc)) m_fDeferred = false; return rc; } AssertMsg(m_fDeferred, ("Client %RU32 is not in deferred mode\n", m_idClient)); return VERR_INVALID_STATE; } /** * Returns the HGCM call handle of the client. * * @returns HGCM handle. */ VBOXHGCMCALLHANDLE Client::GetHandle(void) const RT_NOEXCEPT { return m_Deferred.hHandle; } /** * Returns the HGCM call handle of the client. * * @returns HGCM handle. */ uint32_t Client::GetMsgType(void) const RT_NOEXCEPT { return m_Deferred.uType; } uint32_t Client::GetMsgParamCount(void) const RT_NOEXCEPT { return m_Deferred.cParms; } /** * Returns the client's (HGCM) ID. * * @returns The client's (HGCM) ID. */ uint32_t Client::GetClientID(void) const RT_NOEXCEPT { return m_idClient; } /** * Returns the client's used protocol version. * * @returns Protocol version, or 0 if not set. */ uint32_t Client::GetProtocolVer(void) const RT_NOEXCEPT { return m_uProtocolVer; } /** * Returns whether the client currently is in deferred mode or not. * * @returns \c True if in deferred mode, \c False if not. */ bool Client::IsDeferred(void) const RT_NOEXCEPT { return m_fDeferred; } /** * Set the client's status to deferred, meaning that it does not return to the caller * until CompleteDeferred() has been called. */ void Client::SetDeferred(VBOXHGCMCALLHANDLE hHandle, uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM paParms[]) RT_NOEXCEPT { LogFlowThisFunc(("uClient=%RU32\n", m_idClient)); #ifndef DEBUG_bird /** r=bird: This bugger triggers in the DnD service when restoring saved state. Not tested? */ AssertMsg(m_fDeferred == false, ("Client already in deferred mode\n")); #endif m_fDeferred = true; m_Deferred.hHandle = hHandle; m_Deferred.uType = u32Function; m_Deferred.cParms = cParms; m_Deferred.paParms = paParms; } /** * Sets the client's protocol version. The protocol version is purely optional and bound * to a specific HGCM service. * * @param uVersion Version number to set. */ void Client::SetProtocolVer(uint32_t uVersion) RT_NOEXCEPT { m_uProtocolVer = uVersion; } /** * Sets the HGCM service context. * * @param SvcCtx Service context to set. */ void Client::SetSvcContext(const VBOXHGCMSVCTX &SvcCtx) RT_NOEXCEPT { m_SvcCtx = SvcCtx; } /** * Sets the deferred parameters to a specific message type and * required parameters. That way the client can re-request that message with * the right amount of parameters from the service. * * @returns IPRT status code. * @param uMsg Message type (number) to set. * @param cParms Number of parameters the message needs. */ int Client::SetDeferredMsgInfo(uint32_t uMsg, uint32_t cParms) RT_NOEXCEPT { if (m_fDeferred) { if (m_Deferred.cParms < 2) return VERR_INVALID_PARAMETER; AssertPtrReturn(m_Deferred.paParms, VERR_BUFFER_OVERFLOW); HGCMSvcSetU32(&m_Deferred.paParms[0], uMsg); HGCMSvcSetU32(&m_Deferred.paParms[1], cParms); return VINF_SUCCESS; } AssertFailed(); return VERR_INVALID_STATE; } /** * Sets the deferred parameters to a specific message type and * required parameters. That way the client can re-request that message with * the right amount of parameters from the service. * * @returns IPRT status code. * @param pMessage Message to get message type and required parameters from. */ int Client::SetDeferredMsgInfo(const Message *pMessage) RT_NOEXCEPT { AssertPtrReturn(pMessage, VERR_INVALID_POINTER); return SetDeferredMsgInfo(pMessage->GetType(), pMessage->GetParamCount()); }