service.cpp revision c7210c2150d85e23412b7c1d887e7f38c6ab2d25
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync/** @file
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync *
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync * Shared Clipboard:
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync * Host service entry points.
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync */
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync
e64031e20c39650a7bc902a3e1aba613b9415deevboxsync/*
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync * Copyright (C) 2006-2007 Sun Microsystems, Inc.
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync *
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync * available from http://www.virtualbox.org. This file is free software;
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync * you can redistribute it and/or modify it under the terms of the GNU
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync * General Public License (GPL) as published by the Free Software
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync *
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync * Clara, CA 95054 USA or visit http://www.sun.com if you need
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync * additional information or have any questions.
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync */
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync#include <VBox/HostServices/VBoxClipboardSvc.h>
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync#include <VBox/HostServices/VBoxClipboardExt.h>
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync#include <iprt/alloc.h>
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync#include <iprt/string.h>
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync#include <iprt/assert.h>
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync#include <iprt/critsect.h>
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync#include <VBox/ssm.h>
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync#include "VBoxClipboard.h"
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsyncstatic void VBoxHGCMParmUInt32Set (VBOXHGCMSVCPARM *pParm, uint32_t u32)
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync{
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync pParm->type = VBOX_HGCM_SVC_PARM_32BIT;
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync pParm->u.uint32 = u32;
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync}
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsync
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsyncstatic int VBoxHGCMParmUInt32Get (VBOXHGCMSVCPARM *pParm, uint32_t *pu32)
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsync{
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync if (pParm->type == VBOX_HGCM_SVC_PARM_32BIT)
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync {
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync *pu32 = pParm->u.uint32;
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync return VINF_SUCCESS;
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync }
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync return VERR_INVALID_PARAMETER;
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync}
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync#if 0
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsyncstatic void VBoxHGCMParmPtrSet (VBOXHGCMSVCPARM *pParm, void *pv, uint32_t cb)
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync{
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync pParm->type = VBOX_HGCM_SVC_PARM_PTR;
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync pParm->u.pointer.size = cb;
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync pParm->u.pointer.addr = pv;
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync}
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync#endif
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsyncstatic int VBoxHGCMParmPtrGet (VBOXHGCMSVCPARM *pParm, void **ppv, uint32_t *pcb)
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync{
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync if (pParm->type == VBOX_HGCM_SVC_PARM_PTR)
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync {
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync *ppv = pParm->u.pointer.addr;
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync *pcb = pParm->u.pointer.size;
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync return VINF_SUCCESS;
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync }
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync return VERR_INVALID_PARAMETER;
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync}
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsyncstatic PVBOXHGCMSVCHELPERS g_pHelpers;
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsyncstatic RTCRITSECT critsect;
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsyncstatic uint32_t g_u32Mode;
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsyncstatic PFNHGCMSVCEXT g_pfnExtension;
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsyncstatic void *g_pvExtension;
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsyncstatic VBOXCLIPBOARDCLIENTDATA *g_pClient;
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsync
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsync/* Serialization of data reading and format announcements from the RDP client. */
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsyncstatic bool g_fReadingData = false;
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsyncstatic bool g_fDelayedAnnouncement = false;
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsyncstatic uint32_t g_u32DelayedFormats = 0;
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsync
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsyncstatic uint32_t vboxSvcClipboardMode (void)
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync{
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync return g_u32Mode;
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync}
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsyncstatic void vboxSvcClipboardModeSet (uint32_t u32Mode)
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync{
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync switch (u32Mode)
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync {
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync case VBOX_SHARED_CLIPBOARD_MODE_OFF:
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync case VBOX_SHARED_CLIPBOARD_MODE_HOST_TO_GUEST:
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync case VBOX_SHARED_CLIPBOARD_MODE_GUEST_TO_HOST:
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync case VBOX_SHARED_CLIPBOARD_MODE_BIDIRECTIONAL:
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync g_u32Mode = u32Mode;
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync break;
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync default:
0368e9c310393e82ef37c480b6acbd0f107cf0edvboxsync g_u32Mode = VBOX_SHARED_CLIPBOARD_MODE_OFF;
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync }
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync}
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsyncbool vboxSvcClipboardLock (void)
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync{
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync return RT_SUCCESS(RTCritSectEnter (&critsect));
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync}
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsyncvoid vboxSvcClipboardUnlock (void)
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsync{
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsync RTCritSectLeave (&critsect);
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync}
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync/* Set the HGCM parameters according to pending messages.
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync * Executed under the clipboard lock.
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsync */
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsyncstatic bool vboxSvcClipboardReturnMsg (VBOXCLIPBOARDCLIENTDATA *pClient, VBOXHGCMSVCPARM paParms[])
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsync{
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsync /* Message priority is taken into account. */
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsync if (pClient->fMsgQuit)
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsync {
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsync LogFlow(("vboxSvcClipboardReturnMsg: Quit\n"));
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsync VBoxHGCMParmUInt32Set (&paParms[0], VBOX_SHARED_CLIPBOARD_HOST_MSG_QUIT);
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsync VBoxHGCMParmUInt32Set (&paParms[1], 0);
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync pClient->fMsgQuit = false;
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync }
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync else if (pClient->fMsgReadData)
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync {
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsync LogFlow(("vboxSvcClipboardReturnMsg: ReadData %02X\n", pClient->u32RequestedFormat));
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsync VBoxHGCMParmUInt32Set (&paParms[0], VBOX_SHARED_CLIPBOARD_HOST_MSG_READ_DATA);
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsync VBoxHGCMParmUInt32Set (&paParms[1], pClient->u32RequestedFormat);
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync pClient->fMsgReadData = false;
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync }
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync else if (pClient->fMsgFormats)
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync {
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync LogFlow(("vboxSvcClipboardReturnMsg: Formats %02X\n", pClient->u32AvailableFormats));
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync VBoxHGCMParmUInt32Set (&paParms[0], VBOX_SHARED_CLIPBOARD_HOST_MSG_FORMATS);
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync VBoxHGCMParmUInt32Set (&paParms[1], pClient->u32AvailableFormats);
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync pClient->fMsgFormats = false;
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync }
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsync else
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsync {
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsync /* No pending messages. */
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync LogFlow(("vboxSvcClipboardReturnMsg: no message\n"));
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync return false;
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync }
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync /* Message information assigned. */
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsync return true;
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsync}
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsync
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsyncvoid vboxSvcClipboardReportMsg (VBOXCLIPBOARDCLIENTDATA *pClient, uint32_t u32Msg, uint32_t u32Formats)
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsync{
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync if (vboxSvcClipboardLock ())
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync {
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync switch (u32Msg)
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync {
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync case VBOX_SHARED_CLIPBOARD_HOST_MSG_QUIT:
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsync {
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsync LogFlow(("vboxSvcClipboardReportMsg: Quit\n"));
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsync pClient->fMsgQuit = true;
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync } break;
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync case VBOX_SHARED_CLIPBOARD_HOST_MSG_READ_DATA:
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync {
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsync if ( vboxSvcClipboardMode () != VBOX_SHARED_CLIPBOARD_MODE_GUEST_TO_HOST
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsync && vboxSvcClipboardMode () != VBOX_SHARED_CLIPBOARD_MODE_BIDIRECTIONAL)
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsync {
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsync /* Skip the message. */
d1c36fd86d36726777e3d6f9d040573e0aaf30devboxsync break;
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync }
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync LogFlow(("vboxSvcClipboardReportMsg: ReadData %02X\n", u32Formats));
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync pClient->u32RequestedFormat = u32Formats;
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync pClient->fMsgReadData = true;
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync } break;
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync case VBOX_SHARED_CLIPBOARD_HOST_MSG_FORMATS:
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync {
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync if ( vboxSvcClipboardMode () != VBOX_SHARED_CLIPBOARD_MODE_HOST_TO_GUEST
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync && vboxSvcClipboardMode () != VBOX_SHARED_CLIPBOARD_MODE_BIDIRECTIONAL)
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync {
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync /* Skip the message. */
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync break;
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync }
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync LogFlow(("vboxSvcClipboardReportMsg: Formats %02X\n", u32Formats));
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync pClient->u32AvailableFormats = u32Formats;
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync pClient->fMsgFormats = true;
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync } break;
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync default:
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync {
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync /* Invalid message. */
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync LogFlow(("vboxSvcClipboardReportMsg: invalid message %d\n", u32Msg));
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync } break;
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync }
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync if (pClient->fAsync)
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync {
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync /* The client waits for a responce. */
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync bool fMessageReturned = vboxSvcClipboardReturnMsg (pClient, pClient->async.paParms);
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync /* Make a copy of the handle. */
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync VBOXHGCMCALLHANDLE callHandle = pClient->async.callHandle;
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync if (fMessageReturned)
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync {
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync /* There is a responce. */
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync pClient->fAsync = false;
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync }
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync vboxSvcClipboardUnlock ();
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync if (fMessageReturned)
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync {
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync LogFlow(("vboxSvcClipboardReportMsg: CallComplete\n"));
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync g_pHelpers->pfnCallComplete (callHandle, VINF_SUCCESS);
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync }
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync }
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync else
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync {
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync vboxSvcClipboardUnlock ();
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync }
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync }
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync}
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsyncstatic int svcInit (void)
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsync{
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsync int rc = RTCritSectInit (&critsect);
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsync
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsync if (RT_SUCCESS (rc))
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsync {
d8dee9a7ef33d4c705d5fd087d5af9c7cb071f85vboxsync vboxSvcClipboardModeSet (VBOX_SHARED_CLIPBOARD_MODE_OFF);
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsync
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsync rc = vboxClipboardInit ();
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsync
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsync /* Clean up on failure, because 'svnUnload' will not be called
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsync * if the 'svcInit' returns an error.
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsync */
d8dee9a7ef33d4c705d5fd087d5af9c7cb071f85vboxsync if (RT_FAILURE (rc))
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsync {
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsync RTCritSectDelete (&critsect);
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsync }
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsync }
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsync
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsync return rc;
d8dee9a7ef33d4c705d5fd087d5af9c7cb071f85vboxsync}
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsync
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsyncstatic DECLCALLBACK(int) svcUnload (void *)
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsync{
39c2eccedfdb7455c52225543c355e33a65f0c81vboxsync vboxClipboardDestroy ();
d8dee9a7ef33d4c705d5fd087d5af9c7cb071f85vboxsync RTCritSectDelete (&critsect);
d8dee9a7ef33d4c705d5fd087d5af9c7cb071f85vboxsync return VINF_SUCCESS;
d8dee9a7ef33d4c705d5fd087d5af9c7cb071f85vboxsync}
d8dee9a7ef33d4c705d5fd087d5af9c7cb071f85vboxsync
d8dee9a7ef33d4c705d5fd087d5af9c7cb071f85vboxsync/**
d8dee9a7ef33d4c705d5fd087d5af9c7cb071f85vboxsync * Disconnect the host side of the shared clipboard and send a "host disconnected" message
b35e3948f1287430503b6b432945b8cf4bfd3a23vboxsync * to the guest side.
d8dee9a7ef33d4c705d5fd087d5af9c7cb071f85vboxsync */
d8dee9a7ef33d4c705d5fd087d5af9c7cb071f85vboxsyncstatic DECLCALLBACK(int) svcDisconnect (void *, uint32_t u32ClientID, void *pvClient)
d8dee9a7ef33d4c705d5fd087d5af9c7cb071f85vboxsync{
d8dee9a7ef33d4c705d5fd087d5af9c7cb071f85vboxsync VBOXCLIPBOARDCLIENTDATA *pClient = (VBOXCLIPBOARDCLIENTDATA *)pvClient;
d8dee9a7ef33d4c705d5fd087d5af9c7cb071f85vboxsync
d8dee9a7ef33d4c705d5fd087d5af9c7cb071f85vboxsync vboxSvcClipboardReportMsg (pClient, VBOX_SHARED_CLIPBOARD_HOST_MSG_QUIT, 0);
d8dee9a7ef33d4c705d5fd087d5af9c7cb071f85vboxsync
d8dee9a7ef33d4c705d5fd087d5af9c7cb071f85vboxsync vboxClipboardDisconnect (pClient);
d8dee9a7ef33d4c705d5fd087d5af9c7cb071f85vboxsync
d8dee9a7ef33d4c705d5fd087d5af9c7cb071f85vboxsync memset (pClient, 0, sizeof (*pClient));
d8dee9a7ef33d4c705d5fd087d5af9c7cb071f85vboxsync
d8dee9a7ef33d4c705d5fd087d5af9c7cb071f85vboxsync g_pClient = NULL;
d8dee9a7ef33d4c705d5fd087d5af9c7cb071f85vboxsync
d8dee9a7ef33d4c705d5fd087d5af9c7cb071f85vboxsync return VINF_SUCCESS;
d8dee9a7ef33d4c705d5fd087d5af9c7cb071f85vboxsync}
d8dee9a7ef33d4c705d5fd087d5af9c7cb071f85vboxsync
d8dee9a7ef33d4c705d5fd087d5af9c7cb071f85vboxsyncstatic DECLCALLBACK(int) svcConnect (void *, uint32_t u32ClientID, void *pvClient)
d8dee9a7ef33d4c705d5fd087d5af9c7cb071f85vboxsync{
d8dee9a7ef33d4c705d5fd087d5af9c7cb071f85vboxsync VBOXCLIPBOARDCLIENTDATA *pClient = (VBOXCLIPBOARDCLIENTDATA *)pvClient;
d8dee9a7ef33d4c705d5fd087d5af9c7cb071f85vboxsync
0612e2adbcc146b9eb7748983c720e35e38d0dc9vboxsync int rc = VINF_SUCCESS;
e2a73964f463b9e91f6f096f9e15974a3edcc416vboxsync
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync /* If there is already a client connected then we want to release it first. */
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync if (g_pClient != NULL)
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync {
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync uint32_t u32ClientID = g_pClient->u32ClientID;
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync
84f746c9015f34e9ab096b87e063d0d6ab7fc7aevboxsync svcDisconnect(NULL, u32ClientID, g_pClient);
/* And free the resources in the hgcm subsystem. */
g_pHelpers->pfnDisconnectClient(g_pHelpers->pvInstance, u32ClientID);
}
/* Register the client. */
memset (pClient, 0, sizeof (*pClient));
pClient->u32ClientID = u32ClientID;
rc = vboxClipboardConnect (pClient);
if (RT_SUCCESS (rc))
{
g_pClient = pClient;
}
Log(("vboxClipboardConnect: rc = %Rrc\n", rc));
return rc;
}
static DECLCALLBACK(void) svcCall (void *,
VBOXHGCMCALLHANDLE callHandle,
uint32_t u32ClientID,
void *pvClient,
uint32_t u32Function,
uint32_t cParms,
VBOXHGCMSVCPARM paParms[])
{
int rc = VINF_SUCCESS;
Log(("svcCall: u32ClientID = %d, fn = %d, cParms = %d, pparms = %d\n",
u32ClientID, u32Function, cParms, paParms));
VBOXCLIPBOARDCLIENTDATA *pClient = (VBOXCLIPBOARDCLIENTDATA *)pvClient;
bool fAsynchronousProcessing = false;
#ifdef DEBUG
uint32_t i;
for (i = 0; i < cParms; i++)
{
/** @todo parameters other than 32 bit */
Log((" pparms[%d]: type %d value %d\n", i, paParms[i].type, paParms[i].u.uint32));
}
#endif
switch (u32Function)
{
case VBOX_SHARED_CLIPBOARD_FN_GET_HOST_MSG:
{
/* The quest requests a host message. */
Log(("svcCall: VBOX_SHARED_CLIPBOARD_FN_GET_HOST_MSG\n"));
if (cParms != VBOX_SHARED_CLIPBOARD_CPARMS_GET_HOST_MSG)
{
rc = VERR_INVALID_PARAMETER;
}
else if ( paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* msg */
|| paParms[1].type != VBOX_HGCM_SVC_PARM_32BIT /* formats */
)
{
rc = VERR_INVALID_PARAMETER;
}
else
{
/* Atomically verify the client's state. */
if (vboxSvcClipboardLock ())
{
bool fMessageReturned = vboxSvcClipboardReturnMsg (pClient, paParms);
if (fMessageReturned)
{
/* Just return to the caller. */
pClient->fAsync = false;
}
else
{
/* No event available at the time. Process asynchronously. */
fAsynchronousProcessing = true;
pClient->fAsync = true;
pClient->async.callHandle = callHandle;
pClient->async.paParms = paParms;
Log(("svcCall: async.\n"));
}
vboxSvcClipboardUnlock ();
}
else
{
rc = VERR_NOT_SUPPORTED;
}
}
} break;
case VBOX_SHARED_CLIPBOARD_FN_FORMATS:
{
/* The guest reports that some formats are available. */
Log(("svcCall: VBOX_SHARED_CLIPBOARD_FN_FORMATS\n"));
if (cParms != VBOX_SHARED_CLIPBOARD_CPARMS_FORMATS)
{
rc = VERR_INVALID_PARAMETER;
}
else if ( paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* formats */
)
{
rc = VERR_INVALID_PARAMETER;
}
else
{
uint32_t u32Formats;
rc = VBoxHGCMParmUInt32Get (&paParms[0], &u32Formats);
if (RT_SUCCESS (rc))
{
if ( vboxSvcClipboardMode () != VBOX_SHARED_CLIPBOARD_MODE_GUEST_TO_HOST
&& vboxSvcClipboardMode () != VBOX_SHARED_CLIPBOARD_MODE_BIDIRECTIONAL)
{
rc = VERR_NOT_SUPPORTED;
break;
}
if (g_pfnExtension)
{
VBOXCLIPBOARDEXTPARMS parms;
parms.u32Format = u32Formats;
g_pfnExtension (g_pvExtension, VBOX_CLIPBOARD_EXT_FN_FORMAT_ANNOUNCE, &parms, sizeof (parms));
}
else
{
vboxClipboardFormatAnnounce (pClient, u32Formats);
}
}
}
} break;
case VBOX_SHARED_CLIPBOARD_FN_READ_DATA:
{
/* The guest wants to read data in the given format. */
Log(("svcCall: VBOX_SHARED_CLIPBOARD_FN_READ_DATA\n"));
if (cParms != VBOX_SHARED_CLIPBOARD_CPARMS_READ_DATA)
{
rc = VERR_INVALID_PARAMETER;
}
else if ( paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* format */
|| paParms[1].type != VBOX_HGCM_SVC_PARM_PTR /* ptr */
|| paParms[2].type != VBOX_HGCM_SVC_PARM_32BIT /* size */
)
{
rc = VERR_INVALID_PARAMETER;
}
else
{
uint32_t u32Format;
void *pv;
uint32_t cb;
rc = VBoxHGCMParmUInt32Get (&paParms[0], &u32Format);
if (RT_SUCCESS (rc))
{
rc = VBoxHGCMParmPtrGet (&paParms[1], &pv, &cb);
if (RT_SUCCESS (rc))
{
if ( vboxSvcClipboardMode () != VBOX_SHARED_CLIPBOARD_MODE_HOST_TO_GUEST
&& vboxSvcClipboardMode () != VBOX_SHARED_CLIPBOARD_MODE_BIDIRECTIONAL)
{
rc = VERR_NOT_SUPPORTED;
break;
}
uint32_t cbActual = 0;
if (g_pfnExtension)
{
VBOXCLIPBOARDEXTPARMS parms;
parms.u32Format = u32Format;
parms.u.pvData = pv;
parms.cbData = cb;
g_fReadingData = true;
rc = g_pfnExtension (g_pvExtension, VBOX_CLIPBOARD_EXT_FN_DATA_READ, &parms, sizeof (parms));
LogFlow(("DATA: g_fDelayedAnnouncement = %d, g_u32DelayedFormats = 0x%x\n", g_fDelayedAnnouncement, g_u32DelayedFormats));
if (g_fDelayedAnnouncement)
{
vboxSvcClipboardReportMsg (g_pClient, VBOX_SHARED_CLIPBOARD_HOST_MSG_FORMATS, g_u32DelayedFormats);
g_fDelayedAnnouncement = false;
g_u32DelayedFormats = 0;
}
g_fReadingData = false;
if (RT_SUCCESS (rc))
{
cbActual = parms.cbData;
}
}
else
{
rc = vboxClipboardReadData (pClient, u32Format, pv, cb, &cbActual);
}
if (RT_SUCCESS (rc))
{
VBoxHGCMParmUInt32Set (&paParms[2], cbActual);
}
}
}
}
} break;
case VBOX_SHARED_CLIPBOARD_FN_WRITE_DATA:
{
/* The guest writes the requested data. */
Log(("svcCall: VBOX_SHARED_CLIPBOARD_FN_WRITE_DATA\n"));
if (cParms != VBOX_SHARED_CLIPBOARD_CPARMS_WRITE_DATA)
{
rc = VERR_INVALID_PARAMETER;
}
else if ( paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* format */
|| paParms[1].type != VBOX_HGCM_SVC_PARM_PTR /* ptr */
)
{
rc = VERR_INVALID_PARAMETER;
}
else
{
void *pv;
uint32_t cb;
uint32_t u32Format;
rc = VBoxHGCMParmUInt32Get (&paParms[0], &u32Format);
if (RT_SUCCESS (rc))
{
rc = VBoxHGCMParmPtrGet (&paParms[1], &pv, &cb);
if (RT_SUCCESS (rc))
{
if ( vboxSvcClipboardMode () != VBOX_SHARED_CLIPBOARD_MODE_GUEST_TO_HOST
&& vboxSvcClipboardMode () != VBOX_SHARED_CLIPBOARD_MODE_BIDIRECTIONAL)
{
rc = VERR_NOT_SUPPORTED;
break;
}
if (g_pfnExtension)
{
VBOXCLIPBOARDEXTPARMS parms;
parms.u32Format = u32Format;
parms.u.pvData = pv;
parms.cbData = cb;
g_pfnExtension (g_pvExtension, VBOX_CLIPBOARD_EXT_FN_DATA_WRITE, &parms, sizeof (parms));
}
else
{
vboxClipboardWriteData (pClient, pv, cb, u32Format);
}
}
}
}
} break;
default:
{
rc = VERR_NOT_IMPLEMENTED;
}
}
LogFlow(("svcCall: rc = %Rrc\n", rc));
if (!fAsynchronousProcessing)
{
g_pHelpers->pfnCallComplete (callHandle, rc);
}
}
/*
* We differentiate between a function handler for the guest and one for the host.
*/
static DECLCALLBACK(int) svcHostCall (void *,
uint32_t u32Function,
uint32_t cParms,
VBOXHGCMSVCPARM paParms[])
{
int rc = VINF_SUCCESS;
Log(("svcHostCall: fn = %d, cParms = %d, pparms = %d\n",
u32Function, cParms, paParms));
switch (u32Function)
{
case VBOX_SHARED_CLIPBOARD_HOST_FN_SET_MODE:
{
Log(("svcCall: VBOX_SHARED_CLIPBOARD_HOST_FN_SET_MODE\n"));
if (cParms != 1)
{
rc = VERR_INVALID_PARAMETER;
}
else if ( paParms[0].type != VBOX_HGCM_SVC_PARM_32BIT /* mode */
)
{
rc = VERR_INVALID_PARAMETER;
}
else
{
uint32_t u32Mode = VBOX_SHARED_CLIPBOARD_MODE_OFF;
rc = VBoxHGCMParmUInt32Get (&paParms[0], &u32Mode);
/* The setter takes care of invalid values. */
vboxSvcClipboardModeSet (u32Mode);
}
} break;
default:
break;
}
LogFlow(("svcHostCall: rc = %Rrc\n", rc));
return rc;
}
static DECLCALLBACK(int) svcSaveState(void *, uint32_t u32ClientID, void *pvClient, PSSMHANDLE pSSM)
{
/* If there are any pending requests, they must be completed here. Since
* the service is single threaded, there could be only requests
* which the service itself has postponed.
*
* HGCM knows that the state is being saved and that the pfnComplete
* calls are just clean ups. These requests are saved by the VMMDev.
*
* When the state will be restored, these requests will be reissued
* by VMMDev. The service therefore must save state as if there were no
* pending request.
*/
Log(("svcSaveState: u32ClientID = %d\n", u32ClientID));
VBOXCLIPBOARDCLIENTDATA *pClient = (VBOXCLIPBOARDCLIENTDATA *)pvClient;
/* Save client structure length & contents */
int rc = SSMR3PutU32(pSSM, sizeof(*pClient));
AssertRCReturn(rc, rc);
rc = SSMR3PutMem(pSSM, pClient, sizeof(*pClient));
AssertRCReturn(rc, rc);
if (pClient->fAsync)
{
g_pHelpers->pfnCallComplete (pClient->async.callHandle, VINF_SUCCESS /* error code is not important here. */);
pClient->fAsync = false;
}
return VINF_SUCCESS;
}
static DECLCALLBACK(int) svcLoadState(void *, uint32_t u32ClientID, void *pvClient, PSSMHANDLE pSSM)
{
Log(("svcLoadState: u32ClientID = %d\n", u32ClientID));
VBOXCLIPBOARDCLIENTDATA *pClient = (VBOXCLIPBOARDCLIENTDATA *)pvClient;
/* Existing client can not be in async state yet. */
Assert(!pClient->fAsync);
/* Restore the client data. */
uint32_t len;
int rc = SSMR3GetU32(pSSM, &len);
AssertRCReturn(rc, rc);
if (len != sizeof(VBOXCLIPBOARDCLIENTDATA))
{
Log(("Client len mismatch: %d %d\n", len, sizeof (VBOXCLIPBOARDCLIENTDATA)));
return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
}
VBOXCLIPBOARDCLIENTDATA client;
rc = SSMR3GetMem(pSSM, &client, sizeof(client));
AssertRCReturn(rc, rc);
/* Verify the loaded clients data and update the pClient. */
if (pClient->u32ClientID != client.u32ClientID)
{
Log(("Client ID mismatch: %d %d\n", pClient->u32ClientID, client.u32ClientID));
return VERR_SSM_DATA_UNIT_FORMAT_CHANGED;
}
pClient->fMsgQuit = client.fMsgQuit;
pClient->fMsgReadData = client.fMsgReadData;
pClient->fMsgFormats = client.fMsgFormats;
pClient->u32RequestedFormat = client.u32RequestedFormat;
/* Actual host data are to be reported to guest (SYNC). */
vboxClipboardSync (pClient);
return VINF_SUCCESS;
}
static DECLCALLBACK(int) extCallback (uint32_t u32Function, uint32_t u32Format, void *pvData, uint32_t cbData)
{
if (g_pClient != NULL)
{
switch (u32Function)
{
case VBOX_CLIPBOARD_EXT_FN_FORMAT_ANNOUNCE:
{
LogFlow(("ANNOUNCE: g_fReadingData = %d\n", g_fReadingData));
if (g_fReadingData)
{
g_fDelayedAnnouncement = true;
g_u32DelayedFormats = u32Format;
}
else
{
vboxSvcClipboardReportMsg (g_pClient, VBOX_SHARED_CLIPBOARD_HOST_MSG_FORMATS, u32Format);
}
} break;
case VBOX_CLIPBOARD_EXT_FN_DATA_READ:
{
vboxSvcClipboardReportMsg (g_pClient, VBOX_SHARED_CLIPBOARD_HOST_MSG_READ_DATA, u32Format);
} break;
default:
return VERR_NOT_SUPPORTED;
}
}
return VINF_SUCCESS;
}
static DECLCALLBACK(int) svcRegisterExtension(void *, PFNHGCMSVCEXT pfnExtension, void *pvExtension)
{
LogFlowFunc(("pfnExtension = %p\n", pfnExtension));
VBOXCLIPBOARDEXTPARMS parms;
if (pfnExtension)
{
/* Install extension. */
g_pfnExtension = pfnExtension;
g_pvExtension = pvExtension;
parms.u.pfnCallback = (void (*)())extCallback;
g_pfnExtension (g_pvExtension, VBOX_CLIPBOARD_EXT_FN_SET_CALLBACK, &parms, sizeof (parms));
}
else
{
if (g_pfnExtension)
{
parms.u.pfnCallback = NULL;
g_pfnExtension (g_pvExtension, VBOX_CLIPBOARD_EXT_FN_SET_CALLBACK, &parms, sizeof (parms));
}
/* Uninstall extension. */
g_pfnExtension = NULL;
g_pvExtension = NULL;
}
return VINF_SUCCESS;
}
extern "C" DECLCALLBACK(DECLEXPORT(int)) VBoxHGCMSvcLoad (VBOXHGCMSVCFNTABLE *ptable)
{
int rc = VINF_SUCCESS;
LogFlowFunc(("ptable = %p\n", ptable));
if (!ptable)
{
rc = VERR_INVALID_PARAMETER;
}
else
{
Log(("VBoxHGCMSvcLoad: ptable->cbSize = %d, ptable->u32Version = 0x%08X\n", ptable->cbSize, ptable->u32Version));
if ( ptable->cbSize != sizeof (VBOXHGCMSVCFNTABLE)
|| ptable->u32Version != VBOX_HGCM_SVC_VERSION)
{
rc = VERR_INVALID_PARAMETER;
}
else
{
g_pHelpers = ptable->pHelpers;
ptable->cbClient = sizeof (VBOXCLIPBOARDCLIENTDATA);
ptable->pfnUnload = svcUnload;
ptable->pfnConnect = svcConnect;
ptable->pfnDisconnect = svcDisconnect;
ptable->pfnCall = svcCall;
ptable->pfnHostCall = svcHostCall;
ptable->pfnSaveState = svcSaveState;
ptable->pfnLoadState = svcLoadState;
ptable->pfnRegisterExtension = svcRegisterExtension;
ptable->pvService = NULL;
/* Service specific initialization. */
rc = svcInit ();
}
}
return rc;
}