service.cpp revision 470122d12fa43f83f993ae8e93ba8e3cf4c674cd
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync/* $Id$ */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync/** @file
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * Guest Control Service: Controlling the guest.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync/*
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * Copyright (C) 2010 Oracle Corporation
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync *
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * available from http://www.virtualbox.org. This file is free software;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * you can redistribute it and/or modify it under the terms of the GNU
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * General Public License (GPL) as published by the Free Software
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync/** @page pg_svc_guest_control Guest Control HGCM Service
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync *
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * This service acts as a proxy for handling and buffering host command requests
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * and clients on the guest. It tries to be as transparent as possible to let
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * the guest (client) and host side do their protocol handling as desired.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync *
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * The following terms are used:
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * - Host: A host process (e.g. VBoxManage or another tool utilizing the Main API)
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * which wants to control something on the guest.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * - Client: A client (e.g. VBoxService) running inside the guest OS waiting for
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * new host commands to perform. There can be multiple clients connected
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * to a service. A client is represented by its HGCM client ID.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * - Context ID: An (almost) unique ID automatically generated on the host (Main API)
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * to not only distinguish clients but individual requests. Because
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * the host does not know anything about connected clients it needs
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * an indicator which it can refer to later. This context ID gets
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * internally bound by the service to a client which actually processes
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * the command in order to have a relationship between client<->context ID(s).
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync *
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * The host can trigger commands which get buffered by the service (with full HGCM
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * parameter info). As soon as a client connects (or is ready to do some new work)
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * it gets a buffered host command to process it. This command then will be immediately
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * removed from the command list. If there are ready clients but no new commands to be
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * processed, these clients will be set into a deferred state (that is being blocked
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * to return until a new command is available).
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync *
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * If a client needs to inform the host that something happened, it can send a
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * message to a low level HGCM callback registered in Main. This callback contains
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * the actual data as well as the context ID to let the host do the next necessary
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * steps for this context. This context ID makes it possible to wait for an event
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * inside the host's Main API function (like starting a process on the guest and
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * wait for getting its PID returned by the client) as well as cancelling blocking
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * host calls in order the client terminated/crashed (HGCM detects disconnected
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * clients and reports it to this service's callback).
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync/*******************************************************************************
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync* Header Files *
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync*******************************************************************************/
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync#define LOG_GROUP LOG_GROUP_HGCM
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync#include <VBox/HostServices/GuestControlSvc.h>
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync#include <VBox/log.h>
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync#include <iprt/asm.h> /* For ASMBreakpoint(). */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync#include <iprt/assert.h>
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync#include <iprt/cpp/autores.h>
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync#include <iprt/cpp/utils.h>
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync#include <iprt/err.h>
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync#include <iprt/mem.h>
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync#include <iprt/req.h>
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync#include <iprt/string.h>
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync#include <iprt/thread.h>
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync#include <iprt/time.h>
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync#include <memory> /* for auto_ptr */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync#include <string>
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync#include <list>
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync#include "gctrl.h"
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsyncnamespace guestControl {
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync/**
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * Structure for holding all clients with their
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * generated host contexts. This is necessary for
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * maintaining the relationship between a client and its context IDs.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsyncstruct ClientContexts
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync{
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /** This client ID. */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync uint32_t mClientID;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /** The list of contexts a client is assigned to. */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync std::list< uint32_t > mContextList;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /** The normal constructor. */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync ClientContexts(uint32_t aClientID)
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync : mClientID(aClientID) {}
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync};
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync/** The client list + iterator type */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsynctypedef std::list< ClientContexts > ClientContextsList;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsynctypedef std::list< ClientContexts >::iterator ClientContextsListIter;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsynctypedef std::list< ClientContexts >::const_iterator ClientContextsListIterConst;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync/**
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * Structure for holding an uncompleted guest call.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsyncstruct ClientWaiter
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync{
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /** Client ID; a client can have multiple handles! */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync uint32_t mClientID;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /** The call handle */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync VBOXHGCMCALLHANDLE mHandle;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /** The call parameters */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync VBOXHGCMSVCPARM *mParms;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /** Number of parameters */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync uint32_t mNumParms;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /** The standard constructor. */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync ClientWaiter() : mClientID(0), mHandle(0), mParms(NULL), mNumParms(0) {}
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /** The normal constructor. */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync ClientWaiter(uint32_t aClientID, VBOXHGCMCALLHANDLE aHandle,
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync VBOXHGCMSVCPARM aParms[], uint32_t cParms)
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync : mClientID(aClientID), mHandle(aHandle), mParms(aParms), mNumParms(cParms) {}
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync};
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync/** The guest call list type */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsynctypedef std::list< ClientWaiter > ClientWaiterList;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsynctypedef std::list< ClientWaiter >::iterator CallListIter;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsynctypedef std::list< ClientWaiter >::const_iterator CallListIterConst;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync/**
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * Structure for holding a buffered host command.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsyncstruct HostCmd
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync{
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /** The context ID this command belongs to. Will be extracted
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * from the HGCM parameters. */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync uint32_t mContextID;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /** How many times the host service has tried to deliver this
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * command to the guest. */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync uint32_t mTries;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /** Dynamic structure for holding the HGCM parms */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync VBOXGUESTCTRPARAMBUFFER mParmBuf;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /** The standard constructor. */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync HostCmd() : mContextID(0), mTries(0) {}
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync};
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync/** The host cmd list + iterator type */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsynctypedef std::list< HostCmd > HostCmdList;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsynctypedef std::list< HostCmd >::iterator HostCmdListIter;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsynctypedef std::list< HostCmd >::const_iterator HostCmdListIterConst;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync/**
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * Class containing the shared information service functionality.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsyncclass Service : public RTCNonCopyable
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync{
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsyncprivate:
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /** Type definition for use in callback functions. */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync typedef Service SELF;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /** HGCM helper functions. */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync PVBOXHGCMSVCHELPERS mpHelpers;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /*
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * Callback function supplied by the host for notification of updates
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * to properties.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync PFNHGCMSVCEXT mpfnHostCallback;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /** User data pointer to be supplied to the host callback function. */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync void *mpvHostData;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /** The deferred calls list. */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync ClientWaiterList mClientWaiterList;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /** The host command list. */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync HostCmdList mHostCmds;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /** Client contexts list. */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync ClientContextsList mClientContextsList;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /** Number of connected clients. */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync uint32_t mNumClients;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsyncpublic:
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync explicit Service(PVBOXHGCMSVCHELPERS pHelpers)
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync : mpHelpers(pHelpers)
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync , mpfnHostCallback(NULL)
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync , mpvHostData(NULL)
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync , mNumClients(0)
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync {
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync }
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /**
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * @copydoc VBOXHGCMSVCHELPERS::pfnUnload
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * Simply deletes the service object
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync static DECLCALLBACK(int) svcUnload (void *pvService)
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync {
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync AssertLogRelReturn(VALID_PTR(pvService), VERR_INVALID_PARAMETER);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync SELF *pSelf = reinterpret_cast<SELF *>(pvService);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync int rc = pSelf->uninit();
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync AssertRC(rc);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync if (RT_SUCCESS(rc))
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync delete pSelf;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync return rc;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync }
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /**
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * @copydoc VBOXHGCMSVCHELPERS::pfnConnect
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * Stub implementation of pfnConnect and pfnDisconnect.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync static DECLCALLBACK(int) svcConnect (void *pvService,
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync uint32_t u32ClientID,
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync void *pvClient)
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync {
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync AssertLogRelReturn(VALID_PTR(pvService), VERR_INVALID_PARAMETER);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync LogFlowFunc (("pvService=%p, u32ClientID=%u, pvClient=%p\n", pvService, u32ClientID, pvClient));
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync SELF *pSelf = reinterpret_cast<SELF *>(pvService);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync int rc = pSelf->clientConnect(u32ClientID, pvClient);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync LogFlowFunc (("rc=%Rrc\n", rc));
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync return rc;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync }
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /**
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * @copydoc VBOXHGCMSVCHELPERS::pfnConnect
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * Stub implementation of pfnConnect and pfnDisconnect.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync static DECLCALLBACK(int) svcDisconnect (void *pvService,
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync uint32_t u32ClientID,
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync void *pvClient)
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync {
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync AssertLogRelReturn(VALID_PTR(pvService), VERR_INVALID_PARAMETER);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync LogFlowFunc (("pvService=%p, u32ClientID=%u, pvClient=%p\n", pvService, u32ClientID, pvClient));
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync SELF *pSelf = reinterpret_cast<SELF *>(pvService);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync int rc = pSelf->clientDisconnect(u32ClientID, pvClient);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync LogFlowFunc (("rc=%Rrc\n", rc));
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync return rc;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync }
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /**
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * @copydoc VBOXHGCMSVCHELPERS::pfnCall
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * Wraps to the call member function
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync static DECLCALLBACK(void) svcCall (void * pvService,
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync VBOXHGCMCALLHANDLE callHandle,
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync uint32_t u32ClientID,
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync void *pvClient,
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync uint32_t u32Function,
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync uint32_t cParms,
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync VBOXHGCMSVCPARM paParms[])
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync {
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync AssertLogRelReturnVoid(VALID_PTR(pvService));
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync LogFlowFunc (("pvService=%p, callHandle=%p, u32ClientID=%u, pvClient=%p, u32Function=%u, cParms=%u, paParms=%p\n", pvService, callHandle, u32ClientID, pvClient, u32Function, cParms, paParms));
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync SELF *pSelf = reinterpret_cast<SELF *>(pvService);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync pSelf->call(callHandle, u32ClientID, pvClient, u32Function, cParms, paParms);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync LogFlowFunc (("returning\n"));
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync }
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /**
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * @copydoc VBOXHGCMSVCHELPERS::pfnHostCall
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * Wraps to the hostCall member function
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync static DECLCALLBACK(int) svcHostCall (void *pvService,
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync uint32_t u32Function,
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync uint32_t cParms,
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync VBOXHGCMSVCPARM paParms[])
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync {
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync AssertLogRelReturn(VALID_PTR(pvService), VERR_INVALID_PARAMETER);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync LogFlowFunc (("pvService=%p, u32Function=%u, cParms=%u, paParms=%p\n", pvService, u32Function, cParms, paParms));
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync SELF *pSelf = reinterpret_cast<SELF *>(pvService);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync int rc = pSelf->hostCall(u32Function, cParms, paParms);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync LogFlowFunc (("rc=%Rrc\n", rc));
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync return rc;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync }
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /**
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * @copydoc VBOXHGCMSVCHELPERS::pfnRegisterExtension
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * Installs a host callback for notifications of property changes.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync static DECLCALLBACK(int) svcRegisterExtension (void *pvService,
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync PFNHGCMSVCEXT pfnExtension,
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync void *pvExtension)
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync {
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync AssertLogRelReturn(VALID_PTR(pvService), VERR_INVALID_PARAMETER);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync SELF *pSelf = reinterpret_cast<SELF *>(pvService);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync pSelf->mpfnHostCallback = pfnExtension;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync pSelf->mpvHostData = pvExtension;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync return VINF_SUCCESS;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync }
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsyncprivate:
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync int paramBufferAllocate(PVBOXGUESTCTRPARAMBUFFER pBuf, uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync void paramBufferFree(PVBOXGUESTCTRPARAMBUFFER pBuf);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync int paramBufferAssign(PVBOXGUESTCTRPARAMBUFFER pBuf, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync int prepareExecute(uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync int clientConnect(uint32_t u32ClientID, void *pvClient);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync int clientDisconnect(uint32_t u32ClientID, void *pvClient);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync int sendHostCmdToGuest(HostCmd *pCmd, VBOXHGCMCALLHANDLE callHandle, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync int retrieveNextHostCmd(uint32_t u32ClientID, VBOXHGCMCALLHANDLE callHandle, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync int cancelPendingWaits(uint32_t u32ClientID);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync int notifyHost(uint32_t eFunction, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync int processHostCmd(uint32_t eFunction, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync void call(VBOXHGCMCALLHANDLE callHandle, uint32_t u32ClientID,
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync void *pvClient, uint32_t eFunction, uint32_t cParms,
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync VBOXHGCMSVCPARM paParms[]);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync int hostCall(uint32_t eFunction, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync int uninit();
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync};
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync/**
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * Stores a HGCM request in an internal buffer. Needs to be free'd using paramBufferFree().
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync *
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * @return IPRT status code.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * @param pBuf Buffer to store the HGCM request into.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * @param uMsg Message type.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * @param cParms Number of parameters of HGCM request.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * @param paParms Array of parameters of HGCM request.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsyncint Service::paramBufferAllocate(PVBOXGUESTCTRPARAMBUFFER pBuf, uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync{
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync AssertPtr(pBuf);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync int rc = VINF_SUCCESS;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /* Paranoia. */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync if (cParms > 256)
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync cParms = 256;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /*
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * Don't verify anything here (yet), because this function only buffers
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * the HGCM data into an internal structure and reaches it back to the guest (client)
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * in an unmodified state.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync if (RT_SUCCESS(rc))
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync {
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync pBuf->uMsg = uMsg;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync pBuf->uParmCount = cParms;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync pBuf->pParms = (VBOXHGCMSVCPARM*)RTMemAlloc(sizeof(VBOXHGCMSVCPARM) * pBuf->uParmCount);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync if (NULL == pBuf->pParms)
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync {
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync rc = VERR_NO_MEMORY;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync }
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync else
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync {
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync for (uint32_t i = 0; i < pBuf->uParmCount; i++)
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync {
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync pBuf->pParms[i].type = paParms[i].type;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync switch (paParms[i].type)
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync {
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync case VBOX_HGCM_SVC_PARM_32BIT:
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync pBuf->pParms[i].u.uint32 = paParms[i].u.uint32;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync break;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync case VBOX_HGCM_SVC_PARM_64BIT:
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /* Not supported yet. */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync break;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync case VBOX_HGCM_SVC_PARM_PTR:
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync pBuf->pParms[i].u.pointer.size = paParms[i].u.pointer.size;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync if (pBuf->pParms[i].u.pointer.size > 0)
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync {
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync pBuf->pParms[i].u.pointer.addr = RTMemAlloc(pBuf->pParms[i].u.pointer.size);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync if (NULL == pBuf->pParms[i].u.pointer.addr)
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync {
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync rc = VERR_NO_MEMORY;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync break;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync }
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync else
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync memcpy(pBuf->pParms[i].u.pointer.addr,
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync paParms[i].u.pointer.addr,
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync pBuf->pParms[i].u.pointer.size);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync }
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync break;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync default:
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync break;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync }
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync if (RT_FAILURE(rc))
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync break;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync }
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync }
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync }
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync return rc;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync}
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync/**
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * Frees a buffered HGCM request.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync *
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * @return IPRT status code.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * @param pBuf Parameter buffer to free.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsyncvoid Service::paramBufferFree(PVBOXGUESTCTRPARAMBUFFER pBuf)
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync{
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync AssertPtr(pBuf);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync for (uint32_t i = 0; i < pBuf->uParmCount; i++)
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync {
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync switch (pBuf->pParms[i].type)
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync {
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync case VBOX_HGCM_SVC_PARM_PTR:
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync if (pBuf->pParms[i].u.pointer.size > 0)
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync RTMemFree(pBuf->pParms[i].u.pointer.addr);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync break;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync }
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync }
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync if (pBuf->uParmCount)
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync {
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync RTMemFree(pBuf->pParms);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync pBuf->uParmCount = 0;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync }
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync}
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync/**
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * Assigns data from a buffered HGCM request to the current HGCM request.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync *
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * @return IPRT status code.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * @param pBuf Parameter buffer to assign.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * @param cParms Number of parameters the HGCM request can handle.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * @param paParms Array of parameters of HGCM request to fill the data into.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsyncint Service::paramBufferAssign(PVBOXGUESTCTRPARAMBUFFER pBuf, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync{
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync AssertPtr(pBuf);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync int rc = VINF_SUCCESS;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync if (cParms != pBuf->uParmCount)
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync {
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync LogFlowFunc(("Parameter count does not match (%u (buffer), %u (guest))\n",
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync pBuf->uParmCount, cParms));
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync rc = VERR_INVALID_PARAMETER;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync }
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync else
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync {
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /** @todo Add check to verify if the HGCM request is the same *type* as the buffered one! */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync for (uint32_t i = 0; i < pBuf->uParmCount; i++)
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync {
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync paParms[i].type = pBuf->pParms[i].type;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync switch (paParms[i].type)
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync {
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync case VBOX_HGCM_SVC_PARM_32BIT:
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync paParms[i].u.uint32 = pBuf->pParms[i].u.uint32;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync break;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync case VBOX_HGCM_SVC_PARM_64BIT:
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /* Not supported yet. */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync break;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync case VBOX_HGCM_SVC_PARM_PTR:
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync if (paParms[i].u.pointer.size >= pBuf->pParms[i].u.pointer.size)
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync {
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync memcpy(paParms[i].u.pointer.addr,
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync pBuf->pParms[i].u.pointer.addr,
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync pBuf->pParms[i].u.pointer.size);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync }
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync else
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync rc = VERR_BUFFER_OVERFLOW;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync break;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync default:
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync break;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync }
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync }
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync }
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync return rc;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync}
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync/**
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * Handles a client which just connected.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync *
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * @return IPRT status code.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * @param u32ClientID
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * @param pvClient
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsyncint Service::clientConnect(uint32_t u32ClientID, void *pvClient)
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync{
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync LogFlowFunc(("New client (%ld) connected\n", u32ClientID));
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync if (mNumClients < UINT32_MAX)
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync mNumClients++;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync else
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync AssertMsgFailed(("Max. number of clients reached\n"));
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync return VINF_SUCCESS;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync}
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync/**
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * Handles a client which disconnected. This functiond does some
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * internal cleanup as well as sends notifications to the host so
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * that the host can do the same (if required).
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync *
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * @return IPRT status code.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * @param u32ClientID The client's ID of which disconnected.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * @param pvClient User data, not used at the moment.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsyncint Service::clientDisconnect(uint32_t u32ClientID, void *pvClient)
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync{
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync LogFlowFunc(("Client (%ld) disconnected\n", u32ClientID));
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync Assert(mNumClients > 0);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync mNumClients--;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /*
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * Throw out all stale clients.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync int rc = VINF_SUCCESS;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync CallListIter itCall = mClientWaiterList.begin();
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync while (itCall != mClientWaiterList.end())
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync {
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync if (itCall->mClientID == u32ClientID)
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync {
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync itCall = mClientWaiterList.erase(itCall);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync }
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync else
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync itCall++;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync }
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync ClientContextsListIter it = mClientContextsList.begin();
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync while ( it != mClientContextsList.end()
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync && RT_SUCCESS(rc))
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync {
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync if (it->mClientID == u32ClientID)
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync {
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync std::list< uint32_t >::iterator itContext = it->mContextList.begin();
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync while ( itContext != it->mContextList.end()
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync && RT_SUCCESS(rc))
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync {
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync LogFlowFunc(("Notifying host context %u of disconnect ...\n", (*itContext)));
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /*
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * Notify the host that clients with u32ClientID are no longer
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * around and need to be cleaned up (canceling waits etc).
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync if (mpfnHostCallback)
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync {
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync CALLBACKDATACLIENTDISCONNECTED data;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync data.hdr.u32Magic = CALLBACKDATAMAGICCLIENTDISCONNECTED;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync data.hdr.u32ContextID = (*itContext);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync rc = mpfnHostCallback(mpvHostData, GUEST_DISCONNECTED, (void *)(&data), sizeof(data));
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync if (RT_FAILURE(rc))
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync LogFlowFunc(("Notification of host context %u failed with %Rrc\n", rc));
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync }
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync itContext++;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync }
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync it = mClientContextsList.erase(it);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync }
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync else
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync it++;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync }
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync return rc;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync}
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync/**
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * Sends a specified host command to a client.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync *
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * @return IPRT status code.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * @param pCmd Host comamnd to send.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * @param callHandle Call handle of the client to send the command to.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * @param cParms Number of parameters.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * @param paParms Array of parameters.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsyncint Service::sendHostCmdToGuest(HostCmd *pCmd, VBOXHGCMCALLHANDLE callHandle, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync{
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync AssertPtr(pCmd);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync int rc;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /* Sufficient parameter space? */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync if (pCmd->mParmBuf.uParmCount > cParms)
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync {
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync paParms[0].setUInt32(pCmd->mParmBuf.uMsg); /* Message ID */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync paParms[1].setUInt32(pCmd->mParmBuf.uParmCount); /* Required parameters for message */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /*
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * So this call apparently failed because the guest wanted to peek
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * how much parameters it has to supply in order to successfully retrieve
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * this command. Let's tell him so!
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync rc = VERR_TOO_MUCH_DATA;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync }
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync else
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync {
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync rc = paramBufferAssign(&pCmd->mParmBuf, cParms, paParms);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync }
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync return rc;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync}
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync/**
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * Either fills in parameters from a pending host command into our guest context or
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * defer the guest call until we have something from the host.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync *
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * @return IPRT status code.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * @param u32ClientID The client's ID.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * @param callHandle The client's call handle.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * @param cParms Number of parameters.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * @param paParms Array of parameters.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsyncint Service::retrieveNextHostCmd(uint32_t u32ClientID, VBOXHGCMCALLHANDLE callHandle,
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync uint32_t cParms, VBOXHGCMSVCPARM paParms[])
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync{
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync int rc = VINF_SUCCESS;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /*
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * Lookup client in our list so that we can assign the context ID of
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * a command to that client.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync std::list< ClientContexts >::reverse_iterator it = mClientContextsList.rbegin();
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync while (it != mClientContextsList.rend())
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync {
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync if (it->mClientID == u32ClientID)
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync break;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync it++;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync }
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /* Not found? Add client to list. */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync if (it == mClientContextsList.rend())
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync {
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync mClientContextsList.push_back(ClientContexts(u32ClientID));
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync it = mClientContextsList.rbegin();
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync }
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync Assert(it != mClientContextsList.rend());
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /*
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * If host command list is empty (nothing to do right now) just
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * defer the call until we got something to do (makes the client
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * wait, depending on the flags set).
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync if (mHostCmds.empty()) /* If command list is empty, defer ... */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync {
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync mClientWaiterList.push_back(ClientWaiter(u32ClientID, callHandle, paParms, cParms));
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync rc = VINF_HGCM_ASYNC_EXECUTE;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync }
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync else
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync {
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /*
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * Get the next unassigned host command in the list.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync HostCmd curCmd = mHostCmds.front();
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync rc = sendHostCmdToGuest(&curCmd, callHandle, cParms, paParms);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync if (RT_SUCCESS(rc))
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync {
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /* Remember which client processes which context (for
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * later reference & cleanup). */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync Assert(curCmd.mContextID > 0);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /// @todo r=bird: check if already in the list.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync it->mContextList.push_back(curCmd.mContextID);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /* Only if the guest really got and understood the message remove it from the list. */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync paramBufferFree(&curCmd.mParmBuf);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync mHostCmds.pop_front();
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync }
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync else if (rc == VERR_BUFFER_OVERFLOW)
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync {
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /* If the client understood the message but supplied too little buffer space
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * don't send this message again and drop it after 3 unsuccessful attempts.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * The host then should take care of next actions (maybe retry it with a smaller buffer). */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync if (++curCmd.mTries >= 3)
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync {
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync paramBufferFree(&curCmd.mParmBuf);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync mHostCmds.pop_front();
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync }
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync }
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync }
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync return rc;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync}
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync/**
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * Client asks itself (in another thread) to cancel all pending waits which are blocking the client
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * from shutting down / doing something else.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync *
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * @return IPRT status code.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * @param u32ClientID The client's ID.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsyncint Service::cancelPendingWaits(uint32_t u32ClientID)
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync{
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync int rc = VINF_SUCCESS;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync CallListIter it = mClientWaiterList.begin();
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync while (it != mClientWaiterList.end())
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync {
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync if (it->mClientID == u32ClientID)
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync {
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync if (it->mNumParms >= 2)
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync {
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync it->mParms[0].setUInt32(HOST_CANCEL_PENDING_WAITS); /* Message ID. */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync it->mParms[1].setUInt32(0); /* Required parameters for message. */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync }
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync if (mpHelpers)
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync mpHelpers->pfnCallComplete(it->mHandle, rc);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync it = mClientWaiterList.erase(it);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync }
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync else
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync it++;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync }
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync return rc;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync}
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync/**
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * Notifies the host (using low-level HGCM callbacks) about an event
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * which was sent from the client.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync *
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * @return IPRT status code.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * @param eFunction Function (event) that occured.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * @param cParms Number of parameters.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * @param paParms Array of parameters.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsyncint Service::notifyHost(uint32_t eFunction, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync{
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync LogFlowFunc(("eFunction=%ld, cParms=%ld, paParms=%p\n",
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync eFunction, cParms, paParms));
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync int rc = VINF_SUCCESS;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync if ( eFunction == GUEST_EXEC_SEND_STATUS
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync && cParms == 5)
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync {
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync CALLBACKDATAEXECSTATUS data;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync data.hdr.u32Magic = CALLBACKDATAMAGICEXECSTATUS;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync paParms[0].getUInt32(&data.hdr.u32ContextID);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync paParms[1].getUInt32(&data.u32PID);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync paParms[2].getUInt32(&data.u32Status);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync paParms[3].getUInt32(&data.u32Flags);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync paParms[4].getPointer(&data.pvData, &data.cbData);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync if (mpfnHostCallback)
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync rc = mpfnHostCallback(mpvHostData, eFunction,
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync (void *)(&data), sizeof(data));
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync }
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync else if ( eFunction == GUEST_EXEC_SEND_OUTPUT
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync && cParms == 5)
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync {
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync CALLBACKDATAEXECOUT data;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync data.hdr.u32Magic = CALLBACKDATAMAGICEXECOUT;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync paParms[0].getUInt32(&data.hdr.u32ContextID);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync paParms[1].getUInt32(&data.u32PID);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync paParms[2].getUInt32(&data.u32HandleId);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync paParms[3].getUInt32(&data.u32Flags);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync paParms[4].getPointer(&data.pvData, &data.cbData);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync if (mpfnHostCallback)
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync rc = mpfnHostCallback(mpvHostData, eFunction,
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync (void *)(&data), sizeof(data));
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync }
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync else if ( eFunction == GUEST_EXEC_SEND_INPUT_STATUS
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync && cParms == 5)
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync {
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync CALLBACKDATAEXECINSTATUS data;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync data.hdr.u32Magic = CALLBACKDATAMAGICEXECINSTATUS;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync paParms[0].getUInt32(&data.hdr.u32ContextID);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync paParms[1].getUInt32(&data.u32PID);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync paParms[2].getUInt32(&data.u32Status);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync paParms[3].getUInt32(&data.u32Flags);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync paParms[4].getUInt32(&data.cbProcessed);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync if (mpfnHostCallback)
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync rc = mpfnHostCallback(mpvHostData, eFunction,
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync (void *)(&data), sizeof(data));
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync }
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync else
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync rc = VERR_NOT_SUPPORTED;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync LogFlowFunc(("returning %Rrc\n", rc));
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync return rc;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync}
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync/**
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * Processes a command receiveed from the host side and re-routes it to
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * a connect client on the guest.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync *
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * @return IPRT status code.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * @param eFunction Function code to process.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * @param cParms Number of parameters.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * @param paParms Array of parameters.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsyncint Service::processHostCmd(uint32_t eFunction, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync{
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /*
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * If no client is connected at all we don't buffer any host commands
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * and immediately return an error to the host. This avoids the host
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * waiting for a response from the guest side in case VBoxService on
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * the guest is not running/system is messed up somehow.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync if (mNumClients == 0)
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync return VERR_NOT_FOUND;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync HostCmd newCmd;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync int rc = paramBufferAllocate(&newCmd.mParmBuf, eFunction, cParms, paParms);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync if ( RT_SUCCESS(rc)
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync && newCmd.mParmBuf.uParmCount > 0)
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync {
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /*
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * Assume that the context ID *always* is the first parameter,
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * assign the context ID to the command.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync newCmd.mParmBuf.pParms[0].getUInt32(&newCmd.mContextID);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync Assert(newCmd.mContextID > 0);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync }
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync bool fProcessed = false;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync if (RT_SUCCESS(rc))
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync {
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /* Can we wake up a waiting client on guest? */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync if (!mClientWaiterList.empty())
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync {
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync ClientWaiter guest = mClientWaiterList.front();
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync rc = sendHostCmdToGuest(&newCmd,
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync guest.mHandle, guest.mNumParms, guest.mParms);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /* In any case the client did something, so wake up and remove from list. */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync AssertPtr(mpHelpers);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync mpHelpers->pfnCallComplete(guest.mHandle, rc);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync mClientWaiterList.pop_front();
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /* If we got VERR_TOO_MUCH_DATA we buffer the host command in the next block
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * and return success to the host. */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync if (rc == VERR_TOO_MUCH_DATA)
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync {
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync rc = VINF_SUCCESS;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync }
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync else /* If command was understood by the client, free and remove from host commands list. */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync {
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync paramBufferFree(&newCmd.mParmBuf);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync fProcessed = true;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync }
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync }
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /* If not processed, buffer it ... */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync if (!fProcessed)
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync {
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync mHostCmds.push_back(newCmd);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync#if 0
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /* Limit list size by deleting oldest element. */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync if (mHostCmds.size() > 256) /** @todo Use a define! */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync mHostCmds.pop_front();
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync#endif
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync }
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync }
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync return rc;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync}
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync/**
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * Handle an HGCM service call.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * @copydoc VBOXHGCMSVCFNTABLE::pfnCall
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * @note All functions which do not involve an unreasonable delay will be
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * handled synchronously. If needed, we will add a request handler
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * thread in future for those which do.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync *
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * @thread HGCM
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsyncvoid Service::call(VBOXHGCMCALLHANDLE callHandle, uint32_t u32ClientID,
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync void * /* pvClient */, uint32_t eFunction, uint32_t cParms,
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync VBOXHGCMSVCPARM paParms[])
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync{
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync int rc = VINF_SUCCESS;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync LogFlowFunc(("u32ClientID = %d, fn = %d, cParms = %d, pparms = %d\n",
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync u32ClientID, eFunction, cParms, paParms));
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync try
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync {
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync switch (eFunction)
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync {
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /*
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * The guest asks the host for the next message to process.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync case GUEST_GET_HOST_MSG:
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync LogFlowFunc(("GUEST_GET_HOST_MSG\n"));
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync rc = retrieveNextHostCmd(u32ClientID, callHandle, cParms, paParms);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync break;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /*
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * The guest wants to shut down and asks us (this service) to cancel
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * all blocking pending waits (VINF_HGCM_ASYNC_EXECUTE) so that the
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * guest can gracefully shut down.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync case GUEST_CANCEL_PENDING_WAITS:
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync LogFlowFunc(("GUEST_CANCEL_PENDING_WAITS\n"));
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync rc = cancelPendingWaits(u32ClientID);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync break;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /*
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * The guest notifies the host that some output at stdout/stderr is available.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync case GUEST_EXEC_SEND_OUTPUT:
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync LogFlowFunc(("GUEST_EXEC_SEND_OUTPUT\n"));
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync rc = notifyHost(eFunction, cParms, paParms);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync break;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /*
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * The guest notifies the host of the executed process status.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync case GUEST_EXEC_SEND_STATUS:
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync LogFlowFunc(("GUEST_EXEC_SEND_STATUS\n"));
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync rc = notifyHost(eFunction, cParms, paParms);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync break;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync case GUEST_EXEC_SEND_INPUT_STATUS:
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync LogFlowFunc(("GUEST_EXEC_SEND_INPUT_STATUS\n"));
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync rc = notifyHost(eFunction, cParms, paParms);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync break;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync default:
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync rc = VERR_NOT_SUPPORTED;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync break;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync }
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync if (rc != VINF_HGCM_ASYNC_EXECUTE)
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync {
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /* Tell the client that the call is complete (unblocks waiting). */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync AssertPtr(mpHelpers);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync mpHelpers->pfnCallComplete(callHandle, rc);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync }
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync }
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync catch (std::bad_alloc)
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync {
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync rc = VERR_NO_MEMORY;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync }
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync LogFlowFunc(("rc = %Rrc\n", rc));
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync}
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync/**
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * Service call handler for the host.
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * @copydoc VBOXHGCMSVCFNTABLE::pfnHostCall
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * @thread hgcm
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsyncint Service::hostCall(uint32_t eFunction, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync{
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync int rc = VINF_SUCCESS;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync LogFlowFunc(("fn = %d, cParms = %d, pparms = %d\n",
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync eFunction, cParms, paParms));
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync try
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync {
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync switch (eFunction)
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync {
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /* The host wants to execute something. */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync case HOST_EXEC_CMD:
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync LogFlowFunc(("HOST_EXEC_CMD\n"));
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync rc = processHostCmd(eFunction, cParms, paParms);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync break;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /* The host wants to send something to the
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * started process' stdin pipe. */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync case HOST_EXEC_SET_INPUT:
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync LogFlowFunc(("HOST_EXEC_SET_INPUT\n"));
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync rc = processHostCmd(eFunction, cParms, paParms);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync break;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync case HOST_EXEC_GET_OUTPUT:
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync LogFlowFunc(("HOST_EXEC_GET_OUTPUT\n"));
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync rc = processHostCmd(eFunction, cParms, paParms);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync break;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync default:
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync rc = VERR_NOT_SUPPORTED;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync break;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync }
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync }
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync catch (std::bad_alloc)
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync {
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync rc = VERR_NO_MEMORY;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync }
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync LogFlowFunc(("rc = %Rrc\n", rc));
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync return rc;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync}
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsyncint Service::uninit()
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync{
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /* Free allocated buffered host commands. */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync HostCmdListIter it;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync for (it = mHostCmds.begin(); it != mHostCmds.end(); it++)
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync paramBufferFree(&it->mParmBuf);
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync mHostCmds.clear();
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync return VINF_SUCCESS;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync}
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync} /* namespace guestControl */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsyncusing guestControl::Service;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync/**
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * @copydoc VBOXHGCMSVCLOAD
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsyncextern "C" DECLCALLBACK(DECLEXPORT(int)) VBoxHGCMSvcLoad(VBOXHGCMSVCFNTABLE *ptable)
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync{
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync int rc = VINF_SUCCESS;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync LogFlowFunc(("ptable = %p\n", ptable));
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync if (!VALID_PTR(ptable))
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync {
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync rc = VERR_INVALID_PARAMETER;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync }
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync else
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync {
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync LogFlowFunc(("ptable->cbSize = %d, ptable->u32Version = 0x%08X\n", ptable->cbSize, ptable->u32Version));
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync if ( ptable->cbSize != sizeof (VBOXHGCMSVCFNTABLE)
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync || ptable->u32Version != VBOX_HGCM_SVC_VERSION)
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync {
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync rc = VERR_VERSION_MISMATCH;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync }
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync else
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync {
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync std::auto_ptr<Service> apService;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /* No exceptions may propagate outside. */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync try {
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync apService = std::auto_ptr<Service>(new Service(ptable->pHelpers));
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync } catch (int rcThrown) {
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync rc = rcThrown;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync } catch (...) {
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync rc = VERR_UNRESOLVED_ERROR;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync }
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync if (RT_SUCCESS(rc))
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync {
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /*
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * We don't need an additional client data area on the host,
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync * because we're a class which can have members for that :-).
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync ptable->cbClient = 0;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /* Register functions. */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync ptable->pfnUnload = Service::svcUnload;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync ptable->pfnConnect = Service::svcConnect;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync ptable->pfnDisconnect = Service::svcDisconnect;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync ptable->pfnCall = Service::svcCall;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync ptable->pfnHostCall = Service::svcHostCall;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync ptable->pfnSaveState = NULL; /* The service is stateless, so the normal */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync ptable->pfnLoadState = NULL; /* construction done before restoring suffices */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync ptable->pfnRegisterExtension = Service::svcRegisterExtension;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync /* Service specific initialization. */
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync ptable->pvService = apService.release();
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync }
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync }
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync }
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync LogFlowFunc(("returning %Rrc\n", rc));
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync return rc;
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync}
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync
38ae7e4efe803ea78b6499cd05a394db32623e41vboxsync