GuestCtrlImpl.cpp revision 5312a5e8ef2a9b4196ce5b1b4a5a12c3af798ddb
af062818b47340eef15700d2f0211576ba3506eevboxsync * VirtualBox COM class implementation: Guest
af062818b47340eef15700d2f0211576ba3506eevboxsync * Copyright (C) 2006-2013 Oracle Corporation
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// public methods only for internal purposes
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 * @returns VBox status code.
af062818b47340eef15700d2f0211576ba3506eevboxsync/* static */
af062818b47340eef15700d2f0211576ba3506eevboxsyncDECLCALLBACK(int) Guest::notifyCtrlDispatcher(void *pvExtension,
af062818b47340eef15700d2f0211576ba3506eevboxsync using namespace guestControl;
af062818b47340eef15700d2f0211576ba3506eevboxsync * No locking, as this is purely a notification which does not make any
af062818b47340eef15700d2f0211576ba3506eevboxsync * changes to the object state.
af062818b47340eef15700d2f0211576ba3506eevboxsync LogFlowFunc(("pvExtension=%p, u32Function=%RU32, pvParms=%p, cbParms=%RU32\n",
af062818b47340eef15700d2f0211576ba3506eevboxsync ComObjPtr<Guest> pGuest = reinterpret_cast<Guest *>(pvExtension);
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 PVBOXGUESTCTRLHOSTCALLBACK pSvcCb = (PVBOXGUESTCTRLHOSTCALLBACK)pvData;
af062818b47340eef15700d2f0211576ba3506eevboxsync if (!pSvcCb->mParms) /* At least context ID must be present. */
af062818b47340eef15700d2f0211576ba3506eevboxsync int rc = pSvcCb->mpaParms[0].getUInt32(&uContextID);
af062818b47340eef15700d2f0211576ba3506eevboxsync AssertMsgRC(rc, ("Unable to extract callback context ID, pvData=%p\n", pSvcCb));
af062818b47340eef15700d2f0211576ba3506eevboxsync LogFlowFunc(("CID=%RU32, uSession=%RU32, uObject=%RU32, uCount=%RU32\n",
af062818b47340eef15700d2f0211576ba3506eevboxsync VBOXGUESTCTRLHOSTCBCTX ctxCb = { u32Function, uContextID };
af062818b47340eef15700d2f0211576ba3506eevboxsync#endif /* VBOX_WITH_GUEST_CONTROL */
af062818b47340eef15700d2f0211576ba3506eevboxsyncSTDMETHODIMP Guest::UpdateGuestAdditions(IN_BSTR aSource, ComSafeArrayIn(IN_BSTR, aArguments),
af062818b47340eef15700d2f0211576ba3506eevboxsync ComSafeArrayIn(AdditionsUpdateFlag_T, aFlags), IProgress **aProgress)
af062818b47340eef15700d2f0211576ba3506eevboxsync#else /* VBOX_WITH_GUEST_CONTROL */
af062818b47340eef15700d2f0211576ba3506eevboxsync if (FAILED(autoCaller.rc())) return autoCaller.rc();
af062818b47340eef15700d2f0211576ba3506eevboxsync /* Validate flags. */
af062818b47340eef15700d2f0211576ba3506eevboxsync com::SafeArray<CopyFileFlag_T> flags(ComSafeArrayInArg(aFlags));
af062818b47340eef15700d2f0211576ba3506eevboxsync if (!(fFlags & AdditionsUpdateFlag_WaitForUpdateStartOnly))
af062818b47340eef15700d2f0211576ba3506eevboxsync return setError(E_INVALIDARG, tr("Unknown flags (%#x)"), aFlags);
af062818b47340eef15700d2f0211576ba3506eevboxsync com::SafeArray<IN_BSTR> arguments(ComSafeArrayInArg(aArguments));
af062818b47340eef15700d2f0211576ba3506eevboxsync * Create an anonymous session. This is required to run the Guest Additions
af062818b47340eef15700d2f0211576ba3506eevboxsync * update process with administrative rights.
af062818b47340eef15700d2f0211576ba3506eevboxsync rc = sessionCreate(startupInfo, guestCreds, pSession);
af062818b47340eef15700d2f0211576ba3506eevboxsync hr = setError(VBOX_E_IPRT_ERROR, tr("Maximum number of concurrent guest sessions (%ld) reached"),
af062818b47340eef15700d2f0211576ba3506eevboxsync /** @todo Add more errors here. */
af062818b47340eef15700d2f0211576ba3506eevboxsync hr = setError(VBOX_E_IPRT_ERROR, tr("Could not create guest session: %Rrc"), rc);
af062818b47340eef15700d2f0211576ba3506eevboxsync /** @todo Handle guestRc! */
af062818b47340eef15700d2f0211576ba3506eevboxsync hr = setError(VBOX_E_IPRT_ERROR, tr("Could not open guest session: %Rrc"), rc);
af062818b47340eef15700d2f0211576ba3506eevboxsync SessionTaskUpdateAdditions *pTask = new SessionTaskUpdateAdditions(pSession /* GuestSession */,
af062818b47340eef15700d2f0211576ba3506eevboxsync rc = pSession->startTaskAsync(tr("Updating Guest Additions"), pTask, pProgress);
af062818b47340eef15700d2f0211576ba3506eevboxsync /* Return progress to the caller. */
af062818b47340eef15700d2f0211576ba3506eevboxsync tr("Starting task for updating Guest Additions on the guest failed: %Rrc"), rc);
af062818b47340eef15700d2f0211576ba3506eevboxsync#endif /* VBOX_WITH_GUEST_CONTROL */
af062818b47340eef15700d2f0211576ba3506eevboxsync// private methods
af062818b47340eef15700d2f0211576ba3506eevboxsync/////////////////////////////////////////////////////////////////////////////
af062818b47340eef15700d2f0211576ba3506eevboxsyncint Guest::dispatchToSession(PVBOXGUESTCTRLHOSTCBCTX pCtxCb, PVBOXGUESTCTRLHOSTCALLBACK pSvcCb)
af062818b47340eef15700d2f0211576ba3506eevboxsync LogFlowFunc(("pCtxCb=%p, pSvcCb=%p\n", pCtxCb, pSvcCb));
af062818b47340eef15700d2f0211576ba3506eevboxsync LogFlowFunc(("uFunction=%RU32, uContextID=%RU32, uProtocol=%RU32\n",
af062818b47340eef15700d2f0211576ba3506eevboxsync pCtxCb->uFunction, pCtxCb->uContextID, pCtxCb->uProtocol));
af062818b47340eef15700d2f0211576ba3506eevboxsync uint32_t uSessionID = VBOX_GUESTCTRL_CONTEXTID_GET_SESSION(pCtxCb->uContextID);
af062818b47340eef15700d2f0211576ba3506eevboxsync ComObjPtr<GuestSession> pSession(itSession->second);
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 /* pSvcCb->mpaParms[0] always contains the context ID. */
af062818b47340eef15700d2f0211576ba3506eevboxsync pSvcCb->mpaParms[4].getPointer(&dataCb.pvData, &dataCb.cbData);
af062818b47340eef15700d2f0211576ba3506eevboxsync LogFlowFunc(("Requested command with too much data, skipping dispatching ...\n"));
af062818b47340eef15700d2f0211576ba3506eevboxsync LogFlowFunc(("Closing session (ID=%RU32) ...\n", pSession->getId()));
af062818b47340eef15700d2f0211576ba3506eevboxsync GuestSessions::iterator itSessions = mData.mGuestSessions.begin();
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 fireGuestSessionRegisteredEvent(mEventSource, pSession,
af062818b47340eef15700d2f0211576ba3506eevboxsync false /* Unregistered */);
af062818b47340eef15700d2f0211576ba3506eevboxsyncint Guest::sessionCreate(const GuestSessionStartupInfo &ssInfo,
af062818b47340eef15700d2f0211576ba3506eevboxsync const GuestCredentials &guestCreds, ComObjPtr<GuestSession> &pGuestSession)
af062818b47340eef15700d2f0211576ba3506eevboxsync if (mData.mGuestSessions.size() >= VBOX_GUESTCTRL_MAX_SESSIONS)
af062818b47340eef15700d2f0211576ba3506eevboxsync /* Create a new session ID and assign it. */
af062818b47340eef15700d2f0211576ba3506eevboxsync /* Is the context ID already used? */
af062818b47340eef15700d2f0211576ba3506eevboxsync break; /* Don't try too hard. */
af062818b47340eef15700d2f0211576ba3506eevboxsync /* Create the session object. */
af062818b47340eef15700d2f0211576ba3506eevboxsync /** @todo Use an overloaded copy operator. Later. */
af062818b47340eef15700d2f0211576ba3506eevboxsync startupInfo.mID = uNewSessionID; /* Assign new session ID. */
af062818b47340eef15700d2f0211576ba3506eevboxsync startupInfo.mOpenTimeoutMS = ssInfo.mOpenTimeoutMS;
af062818b47340eef15700d2f0211576ba3506eevboxsync /** @todo Use an overloaded copy operator. Later. */
af062818b47340eef15700d2f0211576ba3506eevboxsync /* Internal (annonymous) session. */
af062818b47340eef15700d2f0211576ba3506eevboxsync rc = pGuestSession->init(this, startupInfo, guestCredentials);
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 mData.mGuestSessions[uNewSessionID] = pGuestSession;
af062818b47340eef15700d2f0211576ba3506eevboxsync fireGuestSessionRegisteredEvent(mEventSource, pGuestSession,
af062818b47340eef15700d2f0211576ba3506eevboxsync true /* Registered */);
af062818b47340eef15700d2f0211576ba3506eevboxsync catch (int rc2)
af062818b47340eef15700d2f0211576ba3506eevboxsyncinline bool Guest::sessionExists(uint32_t uSessionID)
af062818b47340eef15700d2f0211576ba3506eevboxsync GuestSessions::const_iterator itSessions = mData.mGuestSessions.find(uSessionID);
af062818b47340eef15700d2f0211576ba3506eevboxsync return (itSessions == mData.mGuestSessions.end()) ? false : true;
af062818b47340eef15700d2f0211576ba3506eevboxsync// implementation of public methods
af062818b47340eef15700d2f0211576ba3506eevboxsync/////////////////////////////////////////////////////////////////////////////
af062818b47340eef15700d2f0211576ba3506eevboxsyncSTDMETHODIMP Guest::CreateSession(IN_BSTR aUser, IN_BSTR aPassword, IN_BSTR aDomain, IN_BSTR aSessionName, IGuestSession **aGuestSession)
#ifndef VBOX_WITH_GUEST_CONTROL
switch (rc)
case VERR_MAX_PROCS_REACHED:
return hr;
#ifndef VBOX_WITH_GUEST_CONTROL
if (strName.contains(itSessions->second->getName())) /** @todo Use a (simple) pattern match (IPRT?). */
itSessions++;
return S_OK;