service.cpp revision 7aa42d10cb8b82c5a71c7929d6ec98c6dda96410
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync/* $Id$ */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync/** @file
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * Drag and Drop Service.
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync/*
7e5ac7913370b687d1b62e233ce54247d9db0f4fvboxsync * Copyright (C) 2011-2014 Oracle Corporation
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync *
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 */
3f1f30f349c6d9ef74ba8d16ff0c5b0ac47def6cvboxsync
3f1f30f349c6d9ef74ba8d16ff0c5b0ac47def6cvboxsync/** @page pg_svc_guest_control Guest Control HGCM Service
3f1f30f349c6d9ef74ba8d16ff0c5b0ac47def6cvboxsync *
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 *
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 *
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 *
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
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync/******************************************************************************
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * Header Files *
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync ******************************************************************************/
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync#ifdef LOG_GROUP
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync #undef LOG_GROUP
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync#endif
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync#define LOG_GROUP LOG_GROUP_GUEST_DND
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync#include "dndmanager.h"
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync/******************************************************************************
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * Service class declaration *
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync ******************************************************************************/
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync/**
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * Specialized drag & drop service class.
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsyncclass DragAndDropService: public HGCM::AbstractService<DragAndDropService>
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync{
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsyncpublic:
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync explicit DragAndDropService(PVBOXHGCMSVCHELPERS pHelpers)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync : HGCM::AbstractService<DragAndDropService>(pHelpers)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync , m_pManager(0)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync , m_cClients(0)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync {}
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsyncprotected:
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* HGCM service implementation */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync int init(VBOXHGCMSVCFNTABLE *pTable);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync int uninit();
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
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync static DECLCALLBACK(int) progressCallback(uint32_t uPercentage, uint32_t uState, int rc, void *pvUser);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync int modeSet(uint32_t u32Mode);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync inline uint32_t modeGet() { return m_u32Mode; };
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync DnDManager *m_pManager;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync uint32_t m_cClients;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync RTCList<HGCM::Client*> m_clientQueue;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync uint32_t m_u32Mode;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync};
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync/******************************************************************************
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * Service class implementation *
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync ******************************************************************************/
3a09e6a461351151b509aa21e72c50c28e34206cvboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsyncint DragAndDropService::init(VBOXHGCMSVCFNTABLE *pTable)
3a09e6a461351151b509aa21e72c50c28e34206cvboxsync{
27a89c2c0495676503f99e4a63586e3073530d46vboxsync /* Register functions. */
27a89c2c0495676503f99e4a63586e3073530d46vboxsync pTable->pfnHostCall = svcHostCall;
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
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* Drag'n drop mode is disabled by default. */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync modeSet(VBOX_DRAG_AND_DROP_MODE_OFF);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync m_pManager = new DnDManager(&DragAndDropService::progressCallback, this);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync return VINF_SUCCESS;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync}
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsyncint DragAndDropService::uninit(void)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync{
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync delete m_pManager;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync return VINF_SUCCESS;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync}
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsyncint DragAndDropService::clientConnect(uint32_t u32ClientID, void *pvClient)
a93df3b074afab82b9f5fa0d5dde963d22857521vboxsync{
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync LogFlowFunc(("New client (%RU32) connected\n", u32ClientID));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if (m_cClients < UINT32_MAX)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync m_cClients++;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync else
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync AssertMsgFailed(("Maximum number of clients reached\n"));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /*
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * Clear the message queue as soon as a new clients connect
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync * to ensure that every client has the same state.
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if (m_pManager)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync m_pManager->clear();
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync return VINF_SUCCESS;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync}
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsyncint DragAndDropService::clientDisconnect(uint32_t u32ClientID, void *pvClient)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync{
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* Remove all waiters with this u32ClientID. */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync for (size_t i = 0; i < m_clientQueue.size(); )
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync {
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync HGCM::Client *pClient = m_clientQueue.at(i);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if (pClient->clientId() == u32ClientID)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync {
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if (m_pHelpers)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync m_pHelpers->pfnCallComplete(pClient->handle(), VERR_INTERRUPTED);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
7e5ac7913370b687d1b62e233ce54247d9db0f4fvboxsync m_clientQueue.removeAt(i);
7e5ac7913370b687d1b62e233ce54247d9db0f4fvboxsync delete pClient;
7e5ac7913370b687d1b62e233ce54247d9db0f4fvboxsync }
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync else
7e5ac7913370b687d1b62e233ce54247d9db0f4fvboxsync i++;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync }
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync return VINF_SUCCESS;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync}
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsyncint DragAndDropService::modeSet(uint32_t u32Mode)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync{
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /** @todo Validate mode. */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync switch (u32Mode)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync {
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync case VBOX_DRAG_AND_DROP_MODE_OFF:
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync case VBOX_DRAG_AND_DROP_MODE_HOST_TO_GUEST:
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync case VBOX_DRAG_AND_DROP_MODE_GUEST_TO_HOST:
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync case VBOX_DRAG_AND_DROP_MODE_BIDIRECTIONAL:
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync m_u32Mode = u32Mode;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync break;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync default:
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync m_u32Mode = VBOX_DRAG_AND_DROP_MODE_OFF;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync break;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync }
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync return VINF_SUCCESS;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync}
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsyncvoid DragAndDropService::guestCall(VBOXHGCMCALLHANDLE callHandle, uint32_t u32ClientID,
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync void *pvClient, uint32_t u32Function,
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync uint32_t cParms, VBOXHGCMSVCPARM paParms[])
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync{
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync LogFlowFunc(("u32ClientID=%RU32, u32Function=%RU32, cParms=%RU32\n",
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync u32ClientID, u32Function, cParms));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* Check if we've the right mode set. */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync int rc = VERR_ACCESS_DENIED; /* Play safe. */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync switch (u32Function)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync {
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync case DragAndDropSvc::GUEST_DND_GET_NEXT_HOST_MSG:
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if (modeGet() != VBOX_DRAG_AND_DROP_MODE_OFF)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync {
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync rc = VINF_SUCCESS;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync }
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync else
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync {
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync LogFlowFunc(("DnD disabled, deferring request\n"));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync rc = VINF_HGCM_ASYNC_EXECUTE;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync }
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync break;
ef18b2695476bf69da3b80e961a45532302ce14fvboxsync case DragAndDropSvc::GUEST_DND_HG_ACK_OP:
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync case DragAndDropSvc::GUEST_DND_HG_REQ_DATA:
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if ( modeGet() == VBOX_DRAG_AND_DROP_MODE_BIDIRECTIONAL
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync || modeGet() == VBOX_DRAG_AND_DROP_MODE_HOST_TO_GUEST)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync {
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync rc = VINF_SUCCESS;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync }
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync else
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync LogFlowFunc(("Host -> Guest DnD mode disabled, ignoring request\n"));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync break;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync case DragAndDropSvc::GUEST_DND_GH_ACK_PENDING:
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync case DragAndDropSvc::GUEST_DND_GH_SND_DATA:
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync case DragAndDropSvc::GUEST_DND_GH_SND_DIR:
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync case DragAndDropSvc::GUEST_DND_GH_SND_FILE:
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync case DragAndDropSvc::GUEST_DND_GH_EVT_ERROR:
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync#ifdef VBOX_WITH_DRAG_AND_DROP_GH
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if ( modeGet() == VBOX_DRAG_AND_DROP_MODE_BIDIRECTIONAL
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync || modeGet() == VBOX_DRAG_AND_DROP_MODE_GUEST_TO_HOST)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync {
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync rc = VINF_SUCCESS;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync }
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync else
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync#endif
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync LogFlowFunc(("Guest -> Host DnD mode disabled, ignoring request\n"));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync break;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync default:
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* Reach through to DnD manager. */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync rc = VINF_SUCCESS;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync break;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync }
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync#ifdef DEBUG_andy
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync LogFlowFunc(("Mode (%RU32) check rc=%Rrc\n", modeGet(), rc));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync#endif
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if (rc == VINF_SUCCESS) /* Note: rc might be VINF_HGCM_ASYNC_EXECUTE! */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync {
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync switch (u32Function)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync {
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 case DragAndDropSvc::GUEST_DND_GET_NEXT_HOST_MSG:
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync {
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync LogFlowFunc(("GUEST_DND_GET_NEXT_HOST_MSG\n"));
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if ( cParms != 3
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 = VERR_INVALID_PARAMETER;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync else
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync {
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync rc = m_pManager->nextMessageInfo(&paParms[0].u.uint32, &paParms[1].u.uint32);
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync if ( RT_FAILURE(rc)
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync && paParms[2].u.uint32) /* Blocking? */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync {
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync /* Defer client returning. */
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync rc = VINF_HGCM_ASYNC_EXECUTE;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync }
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync }
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync break;
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync }
9de2fa82343af2df7df171b18afbe32b6f37ed84vboxsync case DragAndDropSvc::GUEST_DND_HG_ACK_OP:
{
LogFlowFunc(("GUEST_DND_HG_ACK_OP\n"));
if ( cParms != 1
|| paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* action */)
rc = VERR_INVALID_PARAMETER;
else
{
DragAndDropSvc::VBOXDNDCBHGACKOPDATA data;
data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_HG_ACK_OP;
paParms[0].getUInt32(&data.uAction); /* Get drop action. */
if (m_pfnHostCallback)
rc = m_pfnHostCallback(m_pvHostData, u32Function, &data, sizeof(data));
}
break;
}
case DragAndDropSvc::GUEST_DND_HG_REQ_DATA:
{
LogFlowFunc(("GUEST_DND_HG_REQ_DATA\n"));
if ( cParms != 1
|| paParms[0].type != VBOX_HGCM_SVC_PARM_PTR /* format */)
rc = VERR_INVALID_PARAMETER;
else
{
DragAndDropSvc::VBOXDNDCBHGREQDATADATA data;
data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_HG_REQ_DATA;
uint32_t cTmp;
paParms[0].getPointer((void**)&data.pszFormat, &cTmp);
if (m_pfnHostCallback)
rc = m_pfnHostCallback(m_pvHostData, u32Function, &data, sizeof(data));
}
break;
}
#ifdef VBOX_WITH_DRAG_AND_DROP_GH
case DragAndDropSvc::GUEST_DND_GH_ACK_PENDING:
{
LogFlowFunc(("GUEST_DND_GH_ACK_PENDING\n"));
if ( cParms != 3
|| paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* defaction */
|| paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* allactions */
|| paParms[2].type != VBOX_HGCM_SVC_PARM_PTR /* format */)
rc = VERR_INVALID_PARAMETER;
else
{
DragAndDropSvc::VBOXDNDCBGHACKPENDINGDATA data;
data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_GH_ACK_PENDING;
paParms[0].getUInt32(&data.uDefAction);
paParms[1].getUInt32(&data.uAllActions);
uint32_t cTmp;
paParms[2].getPointer((void**)&data.pszFormat, &cTmp);
if (m_pfnHostCallback)
rc = m_pfnHostCallback(m_pvHostData, u32Function, &data, sizeof(data));
}
break;
}
case DragAndDropSvc::GUEST_DND_GH_SND_DATA:
{
LogFlowFunc(("GUEST_DND_GH_SND_DATA\n"));
if ( cParms != 2
|| paParms[0].type != VBOX_HGCM_SVC_PARM_PTR /* data */
|| paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* size */)
rc = VERR_INVALID_PARAMETER;
else
{
DragAndDropSvc::VBOXDNDCBSNDDATADATA data;
data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_GH_SND_DATA;
paParms[0].getPointer((void**)&data.pvData, &data.cbData);
paParms[1].getUInt32(&data.cbTotalSize);
if (m_pfnHostCallback)
rc = m_pfnHostCallback(m_pvHostData, u32Function, &data, sizeof(data));
}
break;
}
case DragAndDropSvc::GUEST_DND_GH_SND_DIR:
{
LogFlowFunc(("GUEST_DND_GH_SND_DIR\n"));
if ( cParms != 3
|| paParms[0].type != VBOX_HGCM_SVC_PARM_PTR /* path */
|| paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* path length */
|| paParms[2].type != VBOX_HGCM_SVC_PARM_32BIT /* creation mode */)
rc = VERR_INVALID_PARAMETER;
else
{
DragAndDropSvc::VBOXDNDCBSNDDIRDATA data;
data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_GH_SND_DIR;
uint32_t cTmp;
paParms[0].getPointer((void**)&data.pszPath, &cTmp);
paParms[1].getUInt32(&data.cbPath);
paParms[2].getUInt32(&data.fMode);
#ifdef DEBUG_andy
LogFlowFunc(("pszPath=%s, cbPath=%RU32, fMode=0x%x\n",
data.pszPath, data.cbPath, data.fMode));
#endif
if (m_pfnHostCallback)
rc = m_pfnHostCallback(m_pvHostData, u32Function, &data, sizeof(data));
}
break;
}
case DragAndDropSvc::GUEST_DND_GH_SND_FILE:
{
LogFlowFunc(("GUEST_DND_GH_SND_FILE\n"));
if ( cParms != 5
|| paParms[0].type != VBOX_HGCM_SVC_PARM_PTR /* file path */
|| paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* file path length */
|| paParms[2].type != VBOX_HGCM_SVC_PARM_PTR /* file data */
|| paParms[3].type != VBOX_HGCM_SVC_PARM_32BIT /* file data length */
|| paParms[4].type != VBOX_HGCM_SVC_PARM_32BIT /* creation mode */)
rc = VERR_INVALID_PARAMETER;
else
{
DragAndDropSvc::VBOXDNDCBSNDFILEDATA data;
data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_GH_SND_FILE;
uint32_t cTmp;
paParms[0].getPointer((void**)&data.pszFilePath, &cTmp);
paParms[1].getUInt32(&data.cbFilePath);
paParms[2].getPointer((void**)&data.pvData, &data.cbData);
/* paParms[3] is cbData. */
paParms[4].getUInt32(&data.fMode);
#ifdef DEBUG_andy
LogFlowFunc(("pszFilePath=%s, cbData=%RU32, pvData=0x%p, fMode=0x%x\n",
data.pszFilePath, data.cbData, data.pvData, data.fMode));
#endif
if (m_pfnHostCallback)
rc = m_pfnHostCallback(m_pvHostData, u32Function, &data, sizeof(data));
}
break;
}
case DragAndDropSvc::GUEST_DND_GH_EVT_ERROR:
{
LogFlowFunc(("GUEST_DND_GH_EVT_ERROR\n"));
if ( cParms != 1
|| paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* rc */)
rc = VERR_INVALID_PARAMETER;
else
{
DragAndDropSvc::VBOXDNDCBEVTERRORDATA data;
data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_GH_EVT_ERROR;
uint32_t rcOp;
paParms[0].getUInt32(&rcOp);
data.rc = rcOp;
if (m_pfnHostCallback)
rc = m_pfnHostCallback(m_pvHostData, u32Function, &data, sizeof(data));
}
break;
}
#endif /* VBOX_WITH_DRAG_AND_DROP_GH */
default:
{
/* All other messages are handled by the DnD manager. */
rc = m_pManager->nextMessage(u32Function, cParms, paParms);
break;
}
}
}
/* If async execution is requested, we didn't notify the guest yet about
* completion. The client is queued into the waiters list and will be
* notified as soon as a new event is available. */
if (rc == VINF_HGCM_ASYNC_EXECUTE)
{
m_clientQueue.append(new HGCM::Client(u32ClientID, callHandle,
u32Function, cParms, paParms));
}
if ( rc != VINF_HGCM_ASYNC_EXECUTE
&& m_pHelpers)
{
m_pHelpers->pfnCallComplete(callHandle, rc);
}
LogFlowFunc(("Returning rc=%Rrc\n", rc));
}
int DragAndDropService::hostCall(uint32_t u32Function,
uint32_t cParms, VBOXHGCMSVCPARM paParms[])
{
LogFlowFunc(("u32Function=%RU32, cParms=%RU32\n", u32Function, cParms));
int rc;
if (u32Function == DragAndDropSvc::HOST_DND_SET_MODE)
{
if (cParms != 1)
rc = VERR_INVALID_PARAMETER;
else if (paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT)
rc = VERR_INVALID_PARAMETER;
else
rc = modeSet(paParms[0].u.uint32);
}
else if (modeGet() != VBOX_DRAG_AND_DROP_MODE_OFF)
{
if (!m_clientQueue.isEmpty()) /* At least one client on the guest connected? */
{
rc = m_pManager->addMessage(u32Function, cParms, paParms);
if (RT_SUCCESS(rc))
{
HGCM::Client *pClient = m_clientQueue.first();
AssertPtr(pClient);
/* Check if this was a request for getting the next host
* message. If so, return the message id and the parameter
* count. The message itself has to be queued. */
uint32_t uMsg = pClient->message();
if (uMsg == DragAndDropSvc::GUEST_DND_GET_NEXT_HOST_MSG)
{
LogFlowFunc(("Client %RU32 is waiting for next host msg\n", pClient->clientId()));
uint32_t uMsg1;
uint32_t cParms1;
rc = m_pManager->nextMessageInfo(&uMsg1, &cParms1);
if (RT_SUCCESS(rc))
{
pClient->addMessageInfo(uMsg1, cParms1);
if (m_pHelpers)
m_pHelpers->pfnCallComplete(pClient->handle(), rc);
m_clientQueue.removeFirst();
delete pClient;
}
else
AssertMsgFailed(("m_pManager::nextMessageInfo failed with rc=%Rrc\n", rc));
}
else
AssertMsgFailed(("Client ID=%RU32 in wrong state with uMsg=%RU32\n",
pClient->clientId(), uMsg));
}
else
AssertMsgFailed(("Adding new message of type=%RU32 failed with rc=%Rrc\n",
u32Function, rc));
}
else
{
/* Tell the host that the guest does not support drag'n drop.
* This might happen due to not installed Guest Additions or
* not running VBoxTray/VBoxClient. */
rc = VERR_NOT_SUPPORTED;
}
}
else
{
/* Tell the host that a wrong drag'n drop mode is set. */
rc = VERR_ACCESS_DENIED;
}
LogFlowFunc(("rc=%Rrc\n", rc));
return rc;
}
DECLCALLBACK(int) DragAndDropService::progressCallback(uint32_t uPercentage, uint32_t uState, int rc, void *pvUser)
{
AssertPtrReturn(pvUser, VERR_INVALID_POINTER);
DragAndDropService *pSelf = static_cast<DragAndDropService *>(pvUser);
AssertPtr(pSelf);
if (pSelf->m_pfnHostCallback)
{
LogFlowFunc(("GUEST_DND_HG_EVT_PROGRESS: uPercentage=%RU32, uState=%RU32, rc=%Rrc\n",
uPercentage, uState, rc));
DragAndDropSvc::VBOXDNDCBHGEVTPROGRESSDATA data;
data.hdr.u32Magic = DragAndDropSvc::CB_MAGIC_DND_HG_EVT_PROGRESS;
data.uPercentage = RT_MIN(uPercentage, 100);
data.uState = uState;
data.rc = rc;
return pSelf->m_pfnHostCallback(pSelf->m_pvHostData,
DragAndDropSvc::GUEST_DND_HG_EVT_PROGRESS,
&data, sizeof(data));
}
return VINF_SUCCESS;
}
/**
* @copydoc VBOXHGCMSVCLOAD
*/
extern "C" DECLCALLBACK(DECLEXPORT(int)) VBoxHGCMSvcLoad(VBOXHGCMSVCFNTABLE *pTable)
{
return DragAndDropService::svcLoad(pTable);
}