service.cpp revision 7aa42d10cb8b82c5a71c7929d6ec98c6dda96410
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * Drag and Drop Service.
7e5ac7913370b687d1b62e233ce54247d9db0f4fvboxsync * Copyright (C) 2011-2014 Oracle Corporation
3f1f30f349c6d9ef74ba8d16ff0c5b0ac47def6cvboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
3f1f30f349c6d9ef74ba8d16ff0c5b0ac47def6cvboxsync * available from http://www.virtualbox.org. This file is free software;
3f1f30f349c6d9ef74ba8d16ff0c5b0ac47def6cvboxsync * you can redistribute it and/or modify it under the terms of the GNU
3f1f30f349c6d9ef74ba8d16ff0c5b0ac47def6cvboxsync * General Public License (GPL) as published by the Free Software
3f1f30f349c6d9ef74ba8d16ff0c5b0ac47def6cvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
3f1f30f349c6d9ef74ba8d16ff0c5b0ac47def6cvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
3f1f30f349c6d9ef74ba8d16ff0c5b0ac47def6cvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
3f1f30f349c6d9ef74ba8d16ff0c5b0ac47def6cvboxsync/** @page pg_svc_guest_control Guest Control HGCM Service
3f1f30f349c6d9ef74ba8d16ff0c5b0ac47def6cvboxsync * This service acts as a proxy for handling and buffering host command requests
3f1f30f349c6d9ef74ba8d16ff0c5b0ac47def6cvboxsync * and clients on the guest. It tries to be as transparent as possible to let
3f1f30f349c6d9ef74ba8d16ff0c5b0ac47def6cvboxsync * the guest (client) and host side do their protocol handling as desired.
3f1f30f349c6d9ef74ba8d16ff0c5b0ac47def6cvboxsync * The following terms are used:
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * - Host: A host process (e.g. VBoxManage or another tool utilizing the Main API)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * which wants to control something on the guest.
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * - Client: A client (e.g. VBoxService) running inside the guest OS waiting for
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * new host commands to perform. There can be multiple clients connected
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * to a service. A client is represented by its HGCM client ID.
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * - Context ID: An (almost) unique ID automatically generated on the host (Main API)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * to not only distinguish clients but individual requests. Because
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * the host does not know anything about connected clients it needs
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * an indicator which it can refer to later. This context ID gets
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * internally bound by the service to a client which actually processes
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * the command in order to have a relationship between client<->context ID(s).
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * The host can trigger commands which get buffered by the service (with full HGCM
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * parameter info). As soon as a client connects (or is ready to do some new work)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * it gets a buffered host command to process it. This command then will be immediately
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * removed from the command list. If there are ready clients but no new commands to be
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * processed, these clients will be set into a deferred state (that is being blocked
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * to return until a new command is available).
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * If a client needs to inform the host that something happened, it can send a
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * message to a low level HGCM callback registered in Main. This callback contains
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * the actual data as well as the context ID to let the host do the next necessary
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * steps for this context. This context ID makes it possible to wait for an event
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * inside the host's Main API function (like starting a process on the guest and
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * wait for getting its PID returned by the client) as well as cancelling blocking
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * host calls in order the client terminated/crashed (HGCM detects disconnected
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * clients and reports it to this service's callback).
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync/******************************************************************************
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * Header Files *
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync ******************************************************************************/
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync/******************************************************************************
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * Service class declaration *
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync ******************************************************************************/
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * Specialized drag & drop service class.
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsyncclass DragAndDropService: public HGCM::AbstractService<DragAndDropService>
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync explicit DragAndDropService(PVBOXHGCMSVCHELPERS pHelpers)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync : HGCM::AbstractService<DragAndDropService>(pHelpers)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* HGCM service implementation */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync int clientConnect(uint32_t u32ClientID, void *pvClient);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync int clientDisconnect(uint32_t u32ClientID, void *pvClient);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync void guestCall(VBOXHGCMCALLHANDLE callHandle, uint32_t u32ClientID, void *pvClient, uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync int hostCall(uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM paParms[]);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync static DECLCALLBACK(int) progressCallback(uint32_t uPercentage, uint32_t uState, int rc, void *pvUser);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync/******************************************************************************
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * Service class implementation *
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync ******************************************************************************/
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsyncint DragAndDropService::init(VBOXHGCMSVCFNTABLE *pTable)
27a89c2c0495676503f99e4a63586e3073530d46vboxsync /* Register functions. */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync pTable->pfnSaveState = NULL; /* The service is stateless, so the normal */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync pTable->pfnLoadState = NULL; /* construction done before restoring suffices */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync pTable->pfnRegisterExtension = svcRegisterExtension;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* Drag'n drop mode is disabled by default. */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync m_pManager = new DnDManager(&DragAndDropService::progressCallback, this);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsyncint DragAndDropService::clientConnect(uint32_t u32ClientID, void *pvClient)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync LogFlowFunc(("New client (%RU32) connected\n", u32ClientID));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync AssertMsgFailed(("Maximum number of clients reached\n"));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * Clear the message queue as soon as a new clients connect
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * to ensure that every client has the same state.
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsyncint DragAndDropService::clientDisconnect(uint32_t u32ClientID, void *pvClient)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* Remove all waiters with this u32ClientID. */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync m_pHelpers->pfnCallComplete(pClient->handle(), VERR_INTERRUPTED);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /** @todo Validate mode. */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsyncvoid DragAndDropService::guestCall(VBOXHGCMCALLHANDLE callHandle, uint32_t u32ClientID,
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync LogFlowFunc(("u32ClientID=%RU32, u32Function=%RU32, cParms=%RU32\n",
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* Check if we've the right mode set. */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync LogFlowFunc(("DnD disabled, deferring request\n"));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if ( modeGet() == VBOX_DRAG_AND_DROP_MODE_BIDIRECTIONAL
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync || modeGet() == VBOX_DRAG_AND_DROP_MODE_HOST_TO_GUEST)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync LogFlowFunc(("Host -> Guest DnD mode disabled, ignoring request\n"));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if ( modeGet() == VBOX_DRAG_AND_DROP_MODE_BIDIRECTIONAL
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync || modeGet() == VBOX_DRAG_AND_DROP_MODE_GUEST_TO_HOST)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync LogFlowFunc(("Guest -> Host DnD mode disabled, ignoring request\n"));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* Reach through to DnD manager. */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync LogFlowFunc(("Mode (%RU32) check rc=%Rrc\n", modeGet(), rc));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if (rc == VINF_SUCCESS) /* Note: rc might be VINF_HGCM_ASYNC_EXECUTE! */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* Note: Older VBox versions with enabled DnD guest->host support (< 4.4)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * used the same message ID (300) for GUEST_DND_GET_NEXT_HOST_MSG and
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * HOST_DND_GH_REQ_PENDING, which led this service returning
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * VERR_INVALID_PARAMETER when the guest wanted to actually
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * handle HOST_DND_GH_REQ_PENDING. */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync || paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* message */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync || paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* parameter count */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync || paParms[2].type != VBOX_HGCM_SVC_PARM_32BIT /* blocking */)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync rc = m_pManager->nextMessageInfo(&paParms[0].u.uint32, &paParms[1].u.uint32);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* Defer client returning. */
if (m_pfnHostCallback)
if (m_pfnHostCallback)
#ifdef VBOX_WITH_DRAG_AND_DROP_GH
if (m_pfnHostCallback)
if (m_pfnHostCallback)
#ifdef DEBUG_andy
if (m_pfnHostCallback)
#ifdef DEBUG_andy
if (m_pfnHostCallback)
if (m_pfnHostCallback)
&& m_pHelpers)
int rc;
if (m_pHelpers)
delete pClient;
* not running VBoxTray/VBoxClient. */
return rc;
DECLCALLBACK(int) DragAndDropService::progressCallback(uint32_t uPercentage, uint32_t uState, int rc, void *pvUser)
return VINF_SUCCESS;