GuestCtrlImpl.cpp revision 5312a5e8ef2a9b4196ce5b1b4a5a12c3af798ddb
af062818b47340eef15700d2f0211576ba3506eevboxsync/* $Id$ */
af062818b47340eef15700d2f0211576ba3506eevboxsync/** @file
af062818b47340eef15700d2f0211576ba3506eevboxsync * VirtualBox COM class implementation: Guest
af062818b47340eef15700d2f0211576ba3506eevboxsync */
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync/*
af062818b47340eef15700d2f0211576ba3506eevboxsync * Copyright (C) 2006-2013 Oracle Corporation
af062818b47340eef15700d2f0211576ba3506eevboxsync *
af062818b47340eef15700d2f0211576ba3506eevboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
af062818b47340eef15700d2f0211576ba3506eevboxsync * available from http://www.virtualbox.org. This file is free software;
af062818b47340eef15700d2f0211576ba3506eevboxsync * you can redistribute it and/or modify it under the terms of the GNU
af062818b47340eef15700d2f0211576ba3506eevboxsync * General Public License (GPL) as published by the Free Software
af062818b47340eef15700d2f0211576ba3506eevboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
af062818b47340eef15700d2f0211576ba3506eevboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
af062818b47340eef15700d2f0211576ba3506eevboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
af062818b47340eef15700d2f0211576ba3506eevboxsync */
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync#include "GuestImpl.h"
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync#include "GuestSessionImpl.h"
4b9d6701570cb98fd36e209314239d104ec584d3vboxsync#include "GuestCtrlImplPrivate.h"
4b9d6701570cb98fd36e209314239d104ec584d3vboxsync
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync#include "Global.h"
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync#include "ConsoleImpl.h"
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync#include "ProgressImpl.h"
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync#include "VBoxEvents.h"
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync#include "VMMDev.h"
589fd26cedb2b4ebbed14f2964cad03cc8ebbca2vboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync#include "AutoCaller.h"
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync#include <VBox/VMMDev.h>
af062818b47340eef15700d2f0211576ba3506eevboxsync#ifdef VBOX_WITH_GUEST_CONTROL
af062818b47340eef15700d2f0211576ba3506eevboxsync# include <VBox/com/array.h>
af062818b47340eef15700d2f0211576ba3506eevboxsync# include <VBox/com/ErrorInfo.h>
af062818b47340eef15700d2f0211576ba3506eevboxsync#endif
af062818b47340eef15700d2f0211576ba3506eevboxsync#include <iprt/cpp/utils.h>
af062818b47340eef15700d2f0211576ba3506eevboxsync#include <iprt/file.h>
af062818b47340eef15700d2f0211576ba3506eevboxsync#include <iprt/getopt.h>
af062818b47340eef15700d2f0211576ba3506eevboxsync#include <iprt/isofs.h>
af062818b47340eef15700d2f0211576ba3506eevboxsync#include <iprt/list.h>
af062818b47340eef15700d2f0211576ba3506eevboxsync#include <iprt/path.h>
af062818b47340eef15700d2f0211576ba3506eevboxsync#include <VBox/vmm/pgm.h>
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync#include <memory>
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync#ifdef LOG_GROUP
af062818b47340eef15700d2f0211576ba3506eevboxsync #undef LOG_GROUP
af062818b47340eef15700d2f0211576ba3506eevboxsync#endif
af062818b47340eef15700d2f0211576ba3506eevboxsync#define LOG_GROUP LOG_GROUP_GUEST_CONTROL
af062818b47340eef15700d2f0211576ba3506eevboxsync#include <VBox/log.h>
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync// public methods only for internal purposes
af062818b47340eef15700d2f0211576ba3506eevboxsync/////////////////////////////////////////////////////////////////////////////
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync#ifdef VBOX_WITH_GUEST_CONTROL
af062818b47340eef15700d2f0211576ba3506eevboxsync/**
af062818b47340eef15700d2f0211576ba3506eevboxsync * Static callback function for receiving updates on guest control commands
af062818b47340eef15700d2f0211576ba3506eevboxsync * from the guest. Acts as a dispatcher for the actual class instance.
af062818b47340eef15700d2f0211576ba3506eevboxsync *
af062818b47340eef15700d2f0211576ba3506eevboxsync * @returns VBox status code.
af062818b47340eef15700d2f0211576ba3506eevboxsync *
af062818b47340eef15700d2f0211576ba3506eevboxsync * @todo
af062818b47340eef15700d2f0211576ba3506eevboxsync *
af062818b47340eef15700d2f0211576ba3506eevboxsync */
af062818b47340eef15700d2f0211576ba3506eevboxsync/* static */
af062818b47340eef15700d2f0211576ba3506eevboxsyncDECLCALLBACK(int) Guest::notifyCtrlDispatcher(void *pvExtension,
af062818b47340eef15700d2f0211576ba3506eevboxsync uint32_t u32Function,
af062818b47340eef15700d2f0211576ba3506eevboxsync void *pvData,
af062818b47340eef15700d2f0211576ba3506eevboxsync uint32_t cbData)
af062818b47340eef15700d2f0211576ba3506eevboxsync{
af062818b47340eef15700d2f0211576ba3506eevboxsync using namespace guestControl;
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync /*
af062818b47340eef15700d2f0211576ba3506eevboxsync * No locking, as this is purely a notification which does not make any
af062818b47340eef15700d2f0211576ba3506eevboxsync * changes to the object state.
af062818b47340eef15700d2f0211576ba3506eevboxsync */
af062818b47340eef15700d2f0211576ba3506eevboxsync LogFlowFunc(("pvExtension=%p, u32Function=%RU32, pvParms=%p, cbParms=%RU32\n",
af062818b47340eef15700d2f0211576ba3506eevboxsync pvExtension, u32Function, pvData, cbData));
af062818b47340eef15700d2f0211576ba3506eevboxsync ComObjPtr<Guest> pGuest = reinterpret_cast<Guest *>(pvExtension);
af062818b47340eef15700d2f0211576ba3506eevboxsync Assert(!pGuest.isNull());
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync /*
af062818b47340eef15700d2f0211576ba3506eevboxsync * For guest control 2.0 using the legacy commands we need to do the following here:
af062818b47340eef15700d2f0211576ba3506eevboxsync * - Get the callback header to access the context ID
af062818b47340eef15700d2f0211576ba3506eevboxsync * - Get the context ID of the callback
af062818b47340eef15700d2f0211576ba3506eevboxsync * - Extract the session ID out of the context ID
af062818b47340eef15700d2f0211576ba3506eevboxsync * - Dispatch the whole stuff to the appropriate session (if still exists)
af062818b47340eef15700d2f0211576ba3506eevboxsync */
af062818b47340eef15700d2f0211576ba3506eevboxsync if (cbData != sizeof(VBOXGUESTCTRLHOSTCALLBACK))
af062818b47340eef15700d2f0211576ba3506eevboxsync return VERR_NOT_SUPPORTED;
af062818b47340eef15700d2f0211576ba3506eevboxsync PVBOXGUESTCTRLHOSTCALLBACK pSvcCb = (PVBOXGUESTCTRLHOSTCALLBACK)pvData;
af062818b47340eef15700d2f0211576ba3506eevboxsync AssertPtr(pSvcCb);
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync if (!pSvcCb->mParms) /* At least context ID must be present. */
af062818b47340eef15700d2f0211576ba3506eevboxsync return VERR_INVALID_PARAMETER;
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync uint32_t uContextID;
af062818b47340eef15700d2f0211576ba3506eevboxsync int rc = pSvcCb->mpaParms[0].getUInt32(&uContextID);
af062818b47340eef15700d2f0211576ba3506eevboxsync AssertMsgRC(rc, ("Unable to extract callback context ID, pvData=%p\n", pSvcCb));
af062818b47340eef15700d2f0211576ba3506eevboxsync if (RT_FAILURE(rc))
af062818b47340eef15700d2f0211576ba3506eevboxsync return rc;
af062818b47340eef15700d2f0211576ba3506eevboxsync#ifdef DEBUG
af062818b47340eef15700d2f0211576ba3506eevboxsync LogFlowFunc(("CID=%RU32, uSession=%RU32, uObject=%RU32, uCount=%RU32\n",
af062818b47340eef15700d2f0211576ba3506eevboxsync uContextID,
af062818b47340eef15700d2f0211576ba3506eevboxsync VBOX_GUESTCTRL_CONTEXTID_GET_SESSION(uContextID),
af062818b47340eef15700d2f0211576ba3506eevboxsync VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(uContextID),
af062818b47340eef15700d2f0211576ba3506eevboxsync VBOX_GUESTCTRL_CONTEXTID_GET_COUNT(uContextID)));
af062818b47340eef15700d2f0211576ba3506eevboxsync#endif
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync VBOXGUESTCTRLHOSTCBCTX ctxCb = { u32Function, uContextID };
af062818b47340eef15700d2f0211576ba3506eevboxsync rc = pGuest->dispatchToSession(&ctxCb, pSvcCb);
af062818b47340eef15700d2f0211576ba3506eevboxsync LogFlowFuncLeaveRC(rc);
af062818b47340eef15700d2f0211576ba3506eevboxsync return rc;
af062818b47340eef15700d2f0211576ba3506eevboxsync}
af062818b47340eef15700d2f0211576ba3506eevboxsync#endif /* VBOX_WITH_GUEST_CONTROL */
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsyncSTDMETHODIMP Guest::UpdateGuestAdditions(IN_BSTR aSource, ComSafeArrayIn(IN_BSTR, aArguments),
af062818b47340eef15700d2f0211576ba3506eevboxsync ComSafeArrayIn(AdditionsUpdateFlag_T, aFlags), IProgress **aProgress)
af062818b47340eef15700d2f0211576ba3506eevboxsync{
af062818b47340eef15700d2f0211576ba3506eevboxsync#ifndef VBOX_WITH_GUEST_CONTROL
af062818b47340eef15700d2f0211576ba3506eevboxsync ReturnComNotImplemented();
af062818b47340eef15700d2f0211576ba3506eevboxsync#else /* VBOX_WITH_GUEST_CONTROL */
af062818b47340eef15700d2f0211576ba3506eevboxsync CheckComArgStrNotEmptyOrNull(aSource);
af062818b47340eef15700d2f0211576ba3506eevboxsync CheckComArgOutPointerValid(aProgress);
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync AutoCaller autoCaller(this);
af062818b47340eef15700d2f0211576ba3506eevboxsync if (FAILED(autoCaller.rc())) return autoCaller.rc();
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync /* Validate flags. */
af062818b47340eef15700d2f0211576ba3506eevboxsync uint32_t fFlags = AdditionsUpdateFlag_None;
af062818b47340eef15700d2f0211576ba3506eevboxsync if (aFlags)
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync com::SafeArray<CopyFileFlag_T> flags(ComSafeArrayInArg(aFlags));
af062818b47340eef15700d2f0211576ba3506eevboxsync for (size_t i = 0; i < flags.size(); i++)
af062818b47340eef15700d2f0211576ba3506eevboxsync fFlags |= flags[i];
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync if (fFlags)
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync if (!(fFlags & AdditionsUpdateFlag_WaitForUpdateStartOnly))
af062818b47340eef15700d2f0211576ba3506eevboxsync return setError(E_INVALIDARG, tr("Unknown flags (%#x)"), aFlags);
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync int rc = VINF_SUCCESS;
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync ProcessArguments aArgs;
af062818b47340eef15700d2f0211576ba3506eevboxsync if (aArguments)
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync try
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync com::SafeArray<IN_BSTR> arguments(ComSafeArrayInArg(aArguments));
af062818b47340eef15700d2f0211576ba3506eevboxsync for (size_t i = 0; i < arguments.size(); i++)
af062818b47340eef15700d2f0211576ba3506eevboxsync aArgs.push_back(Utf8Str(arguments[i]));
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync catch(std::bad_alloc &)
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync rc = VERR_NO_MEMORY;
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync HRESULT hr = S_OK;
af062818b47340eef15700d2f0211576ba3506eevboxsync
5112e32d7072e280613921c982a6672f2c859cf3vboxsync /*
af062818b47340eef15700d2f0211576ba3506eevboxsync * Create an anonymous session. This is required to run the Guest Additions
af062818b47340eef15700d2f0211576ba3506eevboxsync * update process with administrative rights.
af062818b47340eef15700d2f0211576ba3506eevboxsync */
af062818b47340eef15700d2f0211576ba3506eevboxsync GuestSessionStartupInfo startupInfo;
af062818b47340eef15700d2f0211576ba3506eevboxsync startupInfo.mName = "Updating Guest Additions";
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync GuestCredentials guestCreds;
af062818b47340eef15700d2f0211576ba3506eevboxsync RT_ZERO(guestCreds);
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync ComObjPtr<GuestSession> pSession;
af062818b47340eef15700d2f0211576ba3506eevboxsync if (RT_SUCCESS(rc))
af062818b47340eef15700d2f0211576ba3506eevboxsync rc = sessionCreate(startupInfo, guestCreds, pSession);
af062818b47340eef15700d2f0211576ba3506eevboxsync if (RT_FAILURE(rc))
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync switch (rc)
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync case VERR_MAX_PROCS_REACHED:
af062818b47340eef15700d2f0211576ba3506eevboxsync hr = setError(VBOX_E_IPRT_ERROR, tr("Maximum number of concurrent guest sessions (%ld) reached"),
af062818b47340eef15700d2f0211576ba3506eevboxsync VBOX_GUESTCTRL_MAX_SESSIONS);
af062818b47340eef15700d2f0211576ba3506eevboxsync break;
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync /** @todo Add more errors here. */
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync default:
af062818b47340eef15700d2f0211576ba3506eevboxsync hr = setError(VBOX_E_IPRT_ERROR, tr("Could not create guest session: %Rrc"), rc);
af062818b47340eef15700d2f0211576ba3506eevboxsync break;
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync else
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync Assert(!pSession.isNull());
af062818b47340eef15700d2f0211576ba3506eevboxsync int guestRc;
af062818b47340eef15700d2f0211576ba3506eevboxsync rc = pSession->startSessionIntenal(&guestRc);
af062818b47340eef15700d2f0211576ba3506eevboxsync if (RT_FAILURE(rc))
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync /** @todo Handle guestRc! */
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync hr = setError(VBOX_E_IPRT_ERROR, tr("Could not open guest session: %Rrc"), rc);
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync else
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync try
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync ComObjPtr<Progress> pProgress;
af062818b47340eef15700d2f0211576ba3506eevboxsync SessionTaskUpdateAdditions *pTask = new SessionTaskUpdateAdditions(pSession /* GuestSession */,
af062818b47340eef15700d2f0211576ba3506eevboxsync Utf8Str(aSource), aArgs, fFlags);
af062818b47340eef15700d2f0211576ba3506eevboxsync rc = pSession->startTaskAsync(tr("Updating Guest Additions"), pTask, pProgress);
af062818b47340eef15700d2f0211576ba3506eevboxsync if (RT_SUCCESS(rc))
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync /* Return progress to the caller. */
af062818b47340eef15700d2f0211576ba3506eevboxsync hr = pProgress.queryInterfaceTo(aProgress);
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync else
af062818b47340eef15700d2f0211576ba3506eevboxsync hr = setError(VBOX_E_IPRT_ERROR,
af062818b47340eef15700d2f0211576ba3506eevboxsync tr("Starting task for updating Guest Additions on the guest failed: %Rrc"), rc);
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync catch(std::bad_alloc &)
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync hr = E_OUTOFMEMORY;
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync return hr;
af062818b47340eef15700d2f0211576ba3506eevboxsync#endif /* VBOX_WITH_GUEST_CONTROL */
af062818b47340eef15700d2f0211576ba3506eevboxsync}
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync// private methods
af062818b47340eef15700d2f0211576ba3506eevboxsync/////////////////////////////////////////////////////////////////////////////
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsyncint Guest::dispatchToSession(PVBOXGUESTCTRLHOSTCBCTX pCtxCb, PVBOXGUESTCTRLHOSTCALLBACK pSvcCb)
af062818b47340eef15700d2f0211576ba3506eevboxsync{
af062818b47340eef15700d2f0211576ba3506eevboxsync LogFlowFunc(("pCtxCb=%p, pSvcCb=%p\n", pCtxCb, pSvcCb));
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync AssertPtrReturn(pCtxCb, VERR_INVALID_POINTER);
af062818b47340eef15700d2f0211576ba3506eevboxsync AssertPtrReturn(pSvcCb, VERR_INVALID_POINTER);
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync LogFlowFunc(("uFunction=%RU32, uContextID=%RU32, uProtocol=%RU32\n",
af062818b47340eef15700d2f0211576ba3506eevboxsync pCtxCb->uFunction, pCtxCb->uContextID, pCtxCb->uProtocol));
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync uint32_t uSessionID = VBOX_GUESTCTRL_CONTEXTID_GET_SESSION(pCtxCb->uContextID);
af062818b47340eef15700d2f0211576ba3506eevboxsync#ifdef DEBUG
af062818b47340eef15700d2f0211576ba3506eevboxsync LogFlowFunc(("uSessionID=%RU32 (%zu total)\n",
af062818b47340eef15700d2f0211576ba3506eevboxsync uSessionID, mData.mGuestSessions.size()));
af062818b47340eef15700d2f0211576ba3506eevboxsync#endif
af062818b47340eef15700d2f0211576ba3506eevboxsync GuestSessions::const_iterator itSession
af062818b47340eef15700d2f0211576ba3506eevboxsync = mData.mGuestSessions.find(uSessionID);
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync int rc;
af062818b47340eef15700d2f0211576ba3506eevboxsync if (itSession != mData.mGuestSessions.end())
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync ComObjPtr<GuestSession> pSession(itSession->second);
af062818b47340eef15700d2f0211576ba3506eevboxsync Assert(!pSession.isNull());
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync alock.release();
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync bool fDispatch = true;
af062818b47340eef15700d2f0211576ba3506eevboxsync#ifdef DEBUG
af062818b47340eef15700d2f0211576ba3506eevboxsync /*
af062818b47340eef15700d2f0211576ba3506eevboxsync * Pre-check: If we got a status message with an error and VERR_TOO_MUCH_DATA
af062818b47340eef15700d2f0211576ba3506eevboxsync * it means that that guest could not handle the entire message
af062818b47340eef15700d2f0211576ba3506eevboxsync * because of its exceeding size. This should not happen on daily
af062818b47340eef15700d2f0211576ba3506eevboxsync * use but testcases might try this. It then makes no sense to dispatch
af062818b47340eef15700d2f0211576ba3506eevboxsync * this further because we don't have a valid context ID.
af062818b47340eef15700d2f0211576ba3506eevboxsync */
af062818b47340eef15700d2f0211576ba3506eevboxsync if ( pCtxCb->uFunction == GUEST_EXEC_STATUS
af062818b47340eef15700d2f0211576ba3506eevboxsync && pSvcCb->mParms >= 5)
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync CALLBACKDATA_PROC_STATUS dataCb;
af062818b47340eef15700d2f0211576ba3506eevboxsync /* pSvcCb->mpaParms[0] always contains the context ID. */
af062818b47340eef15700d2f0211576ba3506eevboxsync pSvcCb->mpaParms[1].getUInt32(&dataCb.uPID);
af062818b47340eef15700d2f0211576ba3506eevboxsync pSvcCb->mpaParms[2].getUInt32(&dataCb.uStatus);
af062818b47340eef15700d2f0211576ba3506eevboxsync pSvcCb->mpaParms[3].getUInt32(&dataCb.uFlags);
af062818b47340eef15700d2f0211576ba3506eevboxsync pSvcCb->mpaParms[4].getPointer(&dataCb.pvData, &dataCb.cbData);
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync if ( (dataCb.uStatus == PROC_STS_ERROR)
af062818b47340eef15700d2f0211576ba3506eevboxsync && (dataCb.uFlags == VERR_TOO_MUCH_DATA))
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync LogFlowFunc(("Requested command with too much data, skipping dispatching ...\n"));
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync Assert(dataCb.uPID == 0);
af062818b47340eef15700d2f0211576ba3506eevboxsync fDispatch = false;
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync#endif
af062818b47340eef15700d2f0211576ba3506eevboxsync if (fDispatch)
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync switch (pCtxCb->uFunction)
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync case GUEST_DISCONNECTED:
af062818b47340eef15700d2f0211576ba3506eevboxsync rc = pSession->dispatchToThis(pCtxCb, pSvcCb);
af062818b47340eef15700d2f0211576ba3506eevboxsync break;
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync case GUEST_SESSION_NOTIFY:
af062818b47340eef15700d2f0211576ba3506eevboxsync rc = pSession->dispatchToThis(pCtxCb, pSvcCb);
af062818b47340eef15700d2f0211576ba3506eevboxsync break;
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync case GUEST_EXEC_STATUS:
af062818b47340eef15700d2f0211576ba3506eevboxsync case GUEST_EXEC_OUTPUT:
af062818b47340eef15700d2f0211576ba3506eevboxsync case GUEST_EXEC_INPUT_STATUS:
af062818b47340eef15700d2f0211576ba3506eevboxsync case GUEST_EXEC_IO_NOTIFY:
af062818b47340eef15700d2f0211576ba3506eevboxsync rc = pSession->dispatchToProcess(pCtxCb, pSvcCb);
af062818b47340eef15700d2f0211576ba3506eevboxsync break;
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync case GUEST_FILE_NOTIFY:
af062818b47340eef15700d2f0211576ba3506eevboxsync rc = pSession->dispatchToFile(pCtxCb, pSvcCb);
af062818b47340eef15700d2f0211576ba3506eevboxsync break;
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync default:
af062818b47340eef15700d2f0211576ba3506eevboxsync rc = VERR_NOT_SUPPORTED;
af062818b47340eef15700d2f0211576ba3506eevboxsync break;
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync else
af062818b47340eef15700d2f0211576ba3506eevboxsync rc = VERR_NOT_FOUND;
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync else
af062818b47340eef15700d2f0211576ba3506eevboxsync rc = VERR_NOT_FOUND;
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync LogFlowFuncLeaveRC(rc);
af062818b47340eef15700d2f0211576ba3506eevboxsync return rc;
af062818b47340eef15700d2f0211576ba3506eevboxsync}
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsyncint Guest::sessionRemove(GuestSession *pSession)
af062818b47340eef15700d2f0211576ba3506eevboxsync{
af062818b47340eef15700d2f0211576ba3506eevboxsync LogFlowThisFuncEnter();
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync int rc = VERR_NOT_FOUND;
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync LogFlowFunc(("Closing session (ID=%RU32) ...\n", pSession->getId()));
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync GuestSessions::iterator itSessions = mData.mGuestSessions.begin();
af062818b47340eef15700d2f0211576ba3506eevboxsync while (itSessions != mData.mGuestSessions.end())
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync if (pSession == itSessions->second)
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync LogFlowFunc(("Removing session (pSession=%p, ID=%RU32) (now total %ld sessions)\n",
af062818b47340eef15700d2f0211576ba3506eevboxsync (GuestSession *)itSessions->second, itSessions->second->getId(), mData.mGuestSessions.size() - 1));
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync mData.mGuestSessions.erase(itSessions);
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync fireGuestSessionRegisteredEvent(mEventSource, pSession,
af062818b47340eef15700d2f0211576ba3506eevboxsync false /* Unregistered */);
af062818b47340eef15700d2f0211576ba3506eevboxsync rc = VINF_SUCCESS;
af062818b47340eef15700d2f0211576ba3506eevboxsync break;
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync itSessions++;
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync LogFlowFuncLeaveRC(rc);
af062818b47340eef15700d2f0211576ba3506eevboxsync return rc;
af062818b47340eef15700d2f0211576ba3506eevboxsync}
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsyncint Guest::sessionCreate(const GuestSessionStartupInfo &ssInfo,
af062818b47340eef15700d2f0211576ba3506eevboxsync const GuestCredentials &guestCreds, ComObjPtr<GuestSession> &pGuestSession)
af062818b47340eef15700d2f0211576ba3506eevboxsync{
af062818b47340eef15700d2f0211576ba3506eevboxsync AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync int rc = VERR_MAX_PROCS_REACHED;
af062818b47340eef15700d2f0211576ba3506eevboxsync if (mData.mGuestSessions.size() >= VBOX_GUESTCTRL_MAX_SESSIONS)
af062818b47340eef15700d2f0211576ba3506eevboxsync return rc;
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync try
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync /* Create a new session ID and assign it. */
af062818b47340eef15700d2f0211576ba3506eevboxsync uint32_t uNewSessionID = 0;
af062818b47340eef15700d2f0211576ba3506eevboxsync uint32_t uTries = 0;
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync for (;;)
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync /* Is the context ID already used? */
af062818b47340eef15700d2f0211576ba3506eevboxsync if (!sessionExists(uNewSessionID))
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync rc = VINF_SUCCESS;
af062818b47340eef15700d2f0211576ba3506eevboxsync break;
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync uNewSessionID++;
af062818b47340eef15700d2f0211576ba3506eevboxsync if (uNewSessionID >= VBOX_GUESTCTRL_MAX_SESSIONS)
af062818b47340eef15700d2f0211576ba3506eevboxsync uNewSessionID = 0;
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync if (++uTries == VBOX_GUESTCTRL_MAX_SESSIONS)
af062818b47340eef15700d2f0211576ba3506eevboxsync break; /* Don't try too hard. */
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync if (RT_FAILURE(rc)) throw rc;
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync /* Create the session object. */
af062818b47340eef15700d2f0211576ba3506eevboxsync HRESULT hr = pGuestSession.createObject();
af062818b47340eef15700d2f0211576ba3506eevboxsync if (FAILED(hr)) throw VERR_COM_UNEXPECTED;
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync /** @todo Use an overloaded copy operator. Later. */
af062818b47340eef15700d2f0211576ba3506eevboxsync GuestSessionStartupInfo startupInfo;
af062818b47340eef15700d2f0211576ba3506eevboxsync startupInfo.mID = uNewSessionID; /* Assign new session ID. */
af062818b47340eef15700d2f0211576ba3506eevboxsync startupInfo.mName = ssInfo.mName;
af062818b47340eef15700d2f0211576ba3506eevboxsync startupInfo.mOpenFlags = ssInfo.mOpenFlags;
af062818b47340eef15700d2f0211576ba3506eevboxsync startupInfo.mOpenTimeoutMS = ssInfo.mOpenTimeoutMS;
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync GuestCredentials guestCredentials;
af062818b47340eef15700d2f0211576ba3506eevboxsync if (!guestCreds.mUser.isEmpty())
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync /** @todo Use an overloaded copy operator. Later. */
af062818b47340eef15700d2f0211576ba3506eevboxsync guestCredentials.mUser = guestCreds.mUser;
af062818b47340eef15700d2f0211576ba3506eevboxsync guestCredentials.mPassword = guestCreds.mPassword;
af062818b47340eef15700d2f0211576ba3506eevboxsync guestCredentials.mDomain = guestCreds.mDomain;
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync else
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync /* Internal (annonymous) session. */
af062818b47340eef15700d2f0211576ba3506eevboxsync startupInfo.mIsInternal = true;
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync rc = pGuestSession->init(this, startupInfo, guestCredentials);
af062818b47340eef15700d2f0211576ba3506eevboxsync if (RT_FAILURE(rc)) throw rc;
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync /*
af062818b47340eef15700d2f0211576ba3506eevboxsync * Add session object to our session map. This is necessary
af062818b47340eef15700d2f0211576ba3506eevboxsync * before calling openSession because the guest calls back
af062818b47340eef15700d2f0211576ba3506eevboxsync * with the creation result of this session.
af062818b47340eef15700d2f0211576ba3506eevboxsync */
af062818b47340eef15700d2f0211576ba3506eevboxsync mData.mGuestSessions[uNewSessionID] = pGuestSession;
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync fireGuestSessionRegisteredEvent(mEventSource, pGuestSession,
af062818b47340eef15700d2f0211576ba3506eevboxsync true /* Registered */);
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync catch (int rc2)
af062818b47340eef15700d2f0211576ba3506eevboxsync {
af062818b47340eef15700d2f0211576ba3506eevboxsync rc = rc2;
af062818b47340eef15700d2f0211576ba3506eevboxsync }
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync LogFlowFuncLeaveRC(rc);
af062818b47340eef15700d2f0211576ba3506eevboxsync return rc;
af062818b47340eef15700d2f0211576ba3506eevboxsync}
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsyncinline bool Guest::sessionExists(uint32_t uSessionID)
af062818b47340eef15700d2f0211576ba3506eevboxsync{
af062818b47340eef15700d2f0211576ba3506eevboxsync GuestSessions::const_iterator itSessions = mData.mGuestSessions.find(uSessionID);
af062818b47340eef15700d2f0211576ba3506eevboxsync return (itSessions == mData.mGuestSessions.end()) ? false : true;
af062818b47340eef15700d2f0211576ba3506eevboxsync}
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsync// implementation of public methods
af062818b47340eef15700d2f0211576ba3506eevboxsync/////////////////////////////////////////////////////////////////////////////
af062818b47340eef15700d2f0211576ba3506eevboxsync
af062818b47340eef15700d2f0211576ba3506eevboxsyncSTDMETHODIMP Guest::CreateSession(IN_BSTR aUser, IN_BSTR aPassword, IN_BSTR aDomain, IN_BSTR aSessionName, IGuestSession **aGuestSession)
{
#ifndef VBOX_WITH_GUEST_CONTROL
ReturnComNotImplemented();
#else /* VBOX_WITH_GUEST_CONTROL */
LogFlowFuncEnter();
/* Do not allow anonymous sessions (with system rights) with public API. */
if (RT_UNLIKELY((aUser) == NULL || *(aUser) == '\0'))
return setError(E_INVALIDARG, tr("No user name specified"));
CheckComArgOutPointerValid(aGuestSession);
/* Rest is optional. */
AutoCaller autoCaller(this);
if (FAILED(autoCaller.rc())) return autoCaller.rc();
GuestSessionStartupInfo startupInfo;
startupInfo.mName = aSessionName;
GuestCredentials guestCreds;
guestCreds.mUser = aUser;
guestCreds.mPassword = aPassword;
guestCreds.mDomain = aDomain;
ComObjPtr<GuestSession> pSession;
int rc = sessionCreate(startupInfo, guestCreds, pSession);
if (RT_SUCCESS(rc))
{
/* Return guest session to the caller. */
HRESULT hr2 = pSession.queryInterfaceTo(aGuestSession);
if (FAILED(hr2))
rc = VERR_COM_OBJECT_NOT_FOUND;
}
if (RT_SUCCESS(rc))
{
/* Start (fork) the session asynchronously
* on the guest. */
rc = pSession->startSessionAsync();
}
HRESULT hr = S_OK;
if (RT_FAILURE(rc))
{
switch (rc)
{
case VERR_MAX_PROCS_REACHED:
hr = setError(VBOX_E_IPRT_ERROR, tr("Maximum number of concurrent guest sessions (%ld) reached"),
VBOX_GUESTCTRL_MAX_SESSIONS);
break;
/** @todo Add more errors here. */
default:
hr = setError(VBOX_E_IPRT_ERROR, tr("Could not create guest session: %Rrc"), rc);
break;
}
}
LogFlowFuncLeaveRC(rc);
return hr;
#endif /* VBOX_WITH_GUEST_CONTROL */
}
STDMETHODIMP Guest::FindSession(IN_BSTR aSessionName, ComSafeArrayOut(IGuestSession *, aSessions))
{
#ifndef VBOX_WITH_GUEST_CONTROL
ReturnComNotImplemented();
#else /* VBOX_WITH_GUEST_CONTROL */
CheckComArgOutSafeArrayPointerValid(aSessions);
LogFlowFuncEnter();
AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
Utf8Str strName(aSessionName);
std::list < ComObjPtr<GuestSession> > listSessions;
GuestSessions::const_iterator itSessions = mData.mGuestSessions.begin();
while (itSessions != mData.mGuestSessions.end())
{
if (strName.contains(itSessions->second->getName())) /** @todo Use a (simple) pattern match (IPRT?). */
listSessions.push_back(itSessions->second);
itSessions++;
}
LogFlowFunc(("Sessions with \"%ls\" = %RU32\n",
aSessionName, listSessions.size()));
if (listSessions.size())
{
SafeIfaceArray<IGuestSession> sessionIfacs(listSessions);
sessionIfacs.detachTo(ComSafeArrayOutArg(aSessions));
return S_OK;
}
return setErrorNoLog(VBOX_E_OBJECT_NOT_FOUND,
tr("Could not find sessions with name '%ls'"),
aSessionName);
#endif /* VBOX_WITH_GUEST_CONTROL */
}