Пример #1
0
/**
 * Notify the progress object that we're almost at the point of no return.
 *
 * This atomically checks for and disables cancelation.  Calls to
 * IProgress::Cancel() made after a successful call to this method will fail
 * and the user can be told.  While this isn't entirely clean behavior, it
 * prevents issues with an irreversible actually operation succeeding while the
 * user believe it was rolled back.
 *
 * @returns Success indicator.
 * @retval  true on success.
 * @retval  false if the progress object has already been canceled or is in an
 *          invalid state
 */
bool Progress::i_notifyPointOfNoReturn(void)
{
    AutoCaller autoCaller(this);
    AssertComRCReturn(autoCaller.rc(), false);

    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);

    if (mCanceled)
    {
        LogThisFunc(("returns false\n"));
        return false;
    }

    mCancelable = FALSE;
    LogThisFunc(("returns true\n"));
    return true;
}
Пример #2
0
HRESULT Progress::cancel()
{
    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);

    if (!mCancelable)
        return setError(VBOX_E_INVALID_OBJECT_STATE,
                        tr("Operation cannot be canceled"));

    if (!mCanceled)
    {
        LogThisFunc(("Canceling\n"));
        mCanceled = TRUE;
        if (m_pfnCancelCallback)
            m_pfnCancelCallback(m_pvCancelUserArg);

    }
    else
        LogThisFunc(("Already canceled\n"));

    return S_OK;
}
Пример #3
0
HRESULT Progress::setTimeout(ULONG aTimeout)
{
    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);

    if (!mCancelable)
        return setError(VBOX_E_INVALID_OBJECT_STATE,
                        tr("Operation cannot be canceled"));

    LogThisFunc(("%#x => %#x\n", m_cMsTimeout, aTimeout));
    m_cMsTimeout = aTimeout;
    return S_OK;
}
Пример #4
0
STDMETHODIMP Progress::COMSETTER(Timeout)(ULONG aTimeout)
{
    AutoCaller autoCaller(this);
    if (FAILED(autoCaller.rc())) return autoCaller.rc();

    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);

    if (!mCancelable)
        return setError(VBOX_E_INVALID_OBJECT_STATE,
                        tr("Operation cannot be canceled"));

    LogThisFunc(("%#x => %#x\n", m_cMsTimeout, aTimeout));
    m_cMsTimeout = aTimeout;
    return S_OK;
}
/**
 * Internal worker for ThreadTask::createThread,
 * ThreadTask::createThreadWithType.
 *
 * @note Always consumes @a this!
 */
HRESULT ThreadTask::createThreadInternal(RTTHREADTYPE enmType)
{
    LogThisFunc(("Created \"%s\"\n", m_strTaskName.c_str()));

    mAsync = true;
    int vrc = RTThreadCreate(NULL,
                             taskHandlerThreadProc,
                             (void *)this,
                             0,
                             enmType,
                             0,
                             m_strTaskName.c_str());
    if (RT_SUCCESS(vrc))
        return S_OK;

    mAsync = false;
    delete this;
    return E_FAIL;
}
Пример #6
0
int GuestDnDResponse::onDispatch(uint32_t u32Function, void *pvParms, uint32_t cbParms)
{
    LogFlowFunc(("u32Function=%RU32, pvParms=%p, cbParms=%RU32\n", u32Function, pvParms, cbParms));

    int rc = VERR_WRONG_ORDER; /* Play safe. */
    bool fTryCallbacks = false;

    switch (u32Function)
    {
        case DragAndDropSvc::GUEST_DND_CONNECT:
        {
            LogThisFunc(("Client connected\n"));

            /* Nothing to do here (yet). */
            rc = VINF_SUCCESS;
            break;
        }

        case DragAndDropSvc::GUEST_DND_DISCONNECT:
        {
            LogThisFunc(("Client disconnected\n"));
            rc = setProgress(100, DND_PROGRESS_CANCELLED, VINF_SUCCESS);
            break;
        }

        case DragAndDropSvc::GUEST_DND_HG_ACK_OP:
        {
            DragAndDropSvc::PVBOXDNDCBHGACKOPDATA pCBData = reinterpret_cast<DragAndDropSvc::PVBOXDNDCBHGACKOPDATA>(pvParms);
            AssertPtr(pCBData);
            AssertReturn(sizeof(DragAndDropSvc::VBOXDNDCBHGACKOPDATA) == cbParms, VERR_INVALID_PARAMETER);
            AssertReturn(DragAndDropSvc::CB_MAGIC_DND_HG_ACK_OP == pCBData->hdr.uMagic, VERR_INVALID_PARAMETER);

            setDefAction(pCBData->uAction);
            rc = notifyAboutGuestResponse();
            break;
        }

        case DragAndDropSvc::GUEST_DND_HG_REQ_DATA:
        {
            DragAndDropSvc::PVBOXDNDCBHGREQDATADATA pCBData = reinterpret_cast<DragAndDropSvc::PVBOXDNDCBHGREQDATADATA>(pvParms);
            AssertPtr(pCBData);
            AssertReturn(sizeof(DragAndDropSvc::VBOXDNDCBHGREQDATADATA) == cbParms, VERR_INVALID_PARAMETER);
            AssertReturn(DragAndDropSvc::CB_MAGIC_DND_HG_REQ_DATA == pCBData->hdr.uMagic, VERR_INVALID_PARAMETER);

            if (   pCBData->cbFormat  == 0
                || pCBData->cbFormat  > _64K /** @todo Make this configurable? */
                || pCBData->pszFormat == NULL)
            {
                rc = VERR_INVALID_PARAMETER;
            }
            else if (!RTStrIsValidEncoding(pCBData->pszFormat))
            {
                rc = VERR_INVALID_PARAMETER;
            }
            else
            {
                setFormats(GuestDnD::toFormatList(pCBData->pszFormat));
                rc = VINF_SUCCESS;
            }

            int rc2 = notifyAboutGuestResponse();
            if (RT_SUCCESS(rc))
                rc = rc2;
            break;
        }

        case DragAndDropSvc::GUEST_DND_HG_EVT_PROGRESS:
        {
            DragAndDropSvc::PVBOXDNDCBHGEVTPROGRESSDATA pCBData =
               reinterpret_cast<DragAndDropSvc::PVBOXDNDCBHGEVTPROGRESSDATA>(pvParms);
            AssertPtr(pCBData);
            AssertReturn(sizeof(DragAndDropSvc::VBOXDNDCBHGEVTPROGRESSDATA) == cbParms, VERR_INVALID_PARAMETER);
            AssertReturn(DragAndDropSvc::CB_MAGIC_DND_HG_EVT_PROGRESS == pCBData->hdr.uMagic, VERR_INVALID_PARAMETER);

            rc = setProgress(pCBData->uPercentage, pCBData->uStatus, pCBData->rc);
            if (RT_SUCCESS(rc))
                rc = notifyAboutGuestResponse();
            break;
        }
#ifdef VBOX_WITH_DRAG_AND_DROP_GH
        case DragAndDropSvc::GUEST_DND_GH_ACK_PENDING:
        {
            DragAndDropSvc::PVBOXDNDCBGHACKPENDINGDATA pCBData =
               reinterpret_cast<DragAndDropSvc::PVBOXDNDCBGHACKPENDINGDATA>(pvParms);
            AssertPtr(pCBData);
            AssertReturn(sizeof(DragAndDropSvc::VBOXDNDCBGHACKPENDINGDATA) == cbParms, VERR_INVALID_PARAMETER);
            AssertReturn(DragAndDropSvc::CB_MAGIC_DND_GH_ACK_PENDING == pCBData->hdr.uMagic, VERR_INVALID_PARAMETER);

            if (   pCBData->cbFormat  == 0
                || pCBData->cbFormat  > _64K /** @todo Make the maximum size configurable? */
                || pCBData->pszFormat == NULL)
            {
                rc = VERR_INVALID_PARAMETER;
            }
            else if (!RTStrIsValidEncoding(pCBData->pszFormat))
            {
                rc = VERR_INVALID_PARAMETER;
            }
            else
            {
                setFormats   (GuestDnD::toFormatList(pCBData->pszFormat));
                setDefAction (pCBData->uDefAction);
                setAllActions(pCBData->uAllActions);

                rc = VINF_SUCCESS;
            }

            int rc2 = notifyAboutGuestResponse();
            if (RT_SUCCESS(rc))
                rc = rc2;
            break;
        }
#endif /* VBOX_WITH_DRAG_AND_DROP_GH */
        default:
            /* * Try if the event is covered by a registered callback. */
            fTryCallbacks = true;
            break;
    }

    /*
     * Try the host's installed callbacks (if any).
     */
    if (fTryCallbacks)
    {
        GuestDnDCallbackMap::const_iterator it = m_mapCallbacks.find(u32Function);
        if (it != m_mapCallbacks.end())
        {
            AssertPtr(it->second.pfnCallback);
            rc = it->second.pfnCallback(u32Function, pvParms, cbParms, it->second.pvUser);
        }
        else
        {
            LogFlowFunc(("No callback for function %RU32 defined (%zu callbacks total)\n", u32Function, m_mapCallbacks.size()));
            rc = VERR_NOT_SUPPORTED; /* Tell the guest. */
        }
    }

    LogFlowFunc(("Returning rc=%Rrc\n", rc));
    return rc;
}
Пример #7
0
void Guest::i_updateStats(uint64_t iTick)
{
    uint64_t cbFreeTotal      = 0;
    uint64_t cbAllocTotal     = 0;
    uint64_t cbBalloonedTotal = 0;
    uint64_t cbSharedTotal    = 0;
    uint64_t cbSharedMem      = 0;
    ULONG    uNetStatRx       = 0;
    ULONG    uNetStatTx       = 0;
    ULONG    aGuestStats[GUESTSTATTYPE_MAX];
    RT_ZERO(aGuestStats);

    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);

    ULONG validStats = mVmValidStats;
    /* Check if we have anything to report */
    if (validStats)
    {
        mVmValidStats = pm::VMSTATMASK_NONE;
        memcpy(aGuestStats, mCurrentGuestStat, sizeof(aGuestStats));
    }
    alock.release();

    /*
     * Calling SessionMachine may take time as the object resides in VBoxSVC
     * process. This is why we took a snapshot of currently collected stats
     * and released the lock.
     */
    Console::SafeVMPtrQuiet ptrVM(mParent);
    if (ptrVM.isOk())
    {
        int rc;

        /*
         * There is no point in collecting VM shared memory if other memory
         * statistics are not available yet. Or is there?
         */
        if (validStats)
        {
            /* Query the missing per-VM memory statistics. */
            uint64_t cbTotalMemIgn, cbPrivateMemIgn, cbZeroMemIgn;
            rc = PGMR3QueryMemoryStats(ptrVM.rawUVM(), &cbTotalMemIgn, &cbPrivateMemIgn, &cbSharedMem, &cbZeroMemIgn);
            if (rc == VINF_SUCCESS)
                validStats |= pm::VMSTATMASK_GUEST_MEMSHARED;
        }

        if (mCollectVMMStats)
        {
            rc = PGMR3QueryGlobalMemoryStats(ptrVM.rawUVM(), &cbAllocTotal, &cbFreeTotal, &cbBalloonedTotal, &cbSharedTotal);
            AssertRC(rc);
            if (rc == VINF_SUCCESS)
                validStats |= pm::VMSTATMASK_VMM_ALLOC  | pm::VMSTATMASK_VMM_FREE
                           |  pm::VMSTATMASK_VMM_BALOON | pm::VMSTATMASK_VMM_SHARED;
        }

        uint64_t uRxPrev = mNetStatRx;
        uint64_t uTxPrev = mNetStatTx;
        mNetStatRx = mNetStatTx = 0;
        rc = STAMR3Enum(ptrVM.rawUVM(), "/Public/Net/*/Bytes*", i_staticEnumStatsCallback, this);
        AssertRC(rc);

        uint64_t uTsNow = RTTimeNanoTS();
        uint64_t cNsPassed = uTsNow - mNetStatLastTs;
        if (cNsPassed >= 1000)
        {
            mNetStatLastTs = uTsNow;

            uNetStatRx = (ULONG)((mNetStatRx - uRxPrev) * 1000000 / (cNsPassed / 1000)); /* in bytes per second */
            uNetStatTx = (ULONG)((mNetStatTx - uTxPrev) * 1000000 / (cNsPassed / 1000)); /* in bytes per second */
            validStats |= pm::VMSTATMASK_NET_RX | pm::VMSTATMASK_NET_TX;
            LogFlowThisFunc(("Net Rx=%llu Tx=%llu Ts=%llu Delta=%llu\n", mNetStatRx, mNetStatTx, uTsNow, cNsPassed));
        }
        else
        {
            /* Can happen on resume or if we're using a non-monotonic clock
               source for the timer and the time is adjusted. */
            mNetStatRx = uRxPrev;
            mNetStatTx = uTxPrev;
            LogThisFunc(("Net Ts=%llu cNsPassed=%llu - too small interval\n", uTsNow, cNsPassed));
        }
    }

    mParent->i_reportVmStatistics(validStats,
                                  aGuestStats[GUESTSTATTYPE_CPUUSER],
                                  aGuestStats[GUESTSTATTYPE_CPUKERNEL],
                                  aGuestStats[GUESTSTATTYPE_CPUIDLE],
                                  /* Convert the units for RAM usage stats: page (4K) -> 1KB units */
                                  mCurrentGuestStat[GUESTSTATTYPE_MEMTOTAL] * (_4K/_1K),
                                  mCurrentGuestStat[GUESTSTATTYPE_MEMFREE] * (_4K/_1K),
                                  mCurrentGuestStat[GUESTSTATTYPE_MEMBALLOON] * (_4K/_1K),
                                  (ULONG)(cbSharedMem / _1K), /* bytes -> KB */
                                  mCurrentGuestStat[GUESTSTATTYPE_MEMCACHE] * (_4K/_1K),
                                  mCurrentGuestStat[GUESTSTATTYPE_PAGETOTAL] * (_4K/_1K),
                                  (ULONG)(cbAllocTotal / _1K), /* bytes -> KB */
                                  (ULONG)(cbFreeTotal / _1K),
                                  (ULONG)(cbBalloonedTotal / _1K),
                                  (ULONG)(cbSharedTotal / _1K),
                                  uNetStatRx,
                                  uNetStatTx);
}
/**
 * Creates a TCP server that listens for the source machine and passes control
 * over to Console::teleporterTrgServeConnection().
 *
 * @returns VBox status code.
 * @param   pUVM                The user-mode VM handle
 * @param   pMachine            The IMachine for the virtual machine.
 * @param   pErrorMsg           Pointer to the error string for VMSetError.
 * @param   fStartPaused        Whether to start it in the Paused (true) or
 *                              Running (false) state,
 * @param   pProgress           Pointer to the progress object.
 * @param   pfPowerOffOnFailure Whether the caller should power off
 *                              the VM on failure.
 *
 * @remarks The caller expects error information to be set on failure.
 * @todo    Check that all the possible failure paths sets error info...
 */
HRESULT
Console::teleporterTrg(PUVM pUVM, IMachine *pMachine, Utf8Str *pErrorMsg, bool fStartPaused,
                       Progress *pProgress, bool *pfPowerOffOnFailure)
{
    LogThisFunc(("pUVM=%p pMachine=%p fStartPaused=%RTbool pProgress=%p\n", pUVM, pMachine, fStartPaused, pProgress));

    *pfPowerOffOnFailure = true;

    /*
     * Get the config.
     */
    ULONG uPort;
    HRESULT hrc = pMachine->COMGETTER(TeleporterPort)(&uPort);
    if (FAILED(hrc))
        return hrc;
    ULONG const uPortOrg = uPort;

    Bstr bstrAddress;
    hrc = pMachine->COMGETTER(TeleporterAddress)(bstrAddress.asOutParam());
    if (FAILED(hrc))
        return hrc;
    Utf8Str strAddress(bstrAddress);
    const char *pszAddress = strAddress.isEmpty() ? NULL : strAddress.c_str();

    Bstr bstrPassword;
    hrc = pMachine->COMGETTER(TeleporterPassword)(bstrPassword.asOutParam());
    if (FAILED(hrc))
        return hrc;
    Utf8Str strPassword(bstrPassword);
    strPassword.append('\n');           /* To simplify password checking. */

    /*
     * Create the TCP server.
     */
    int vrc;
    PRTTCPSERVER hServer;
    if (uPort)
        vrc = RTTcpServerCreateEx(pszAddress, uPort, &hServer);
    else
    {
        for (int cTries = 10240; cTries > 0; cTries--)
        {
            uPort = RTRandU32Ex(cTries >= 8192 ? 49152 : 1024, 65534);
            vrc = RTTcpServerCreateEx(pszAddress, uPort, &hServer);
            if (vrc != VERR_NET_ADDRESS_IN_USE)
                break;
        }
        if (RT_SUCCESS(vrc))
        {
            hrc = pMachine->COMSETTER(TeleporterPort)(uPort);
            if (FAILED(hrc))
            {
                RTTcpServerDestroy(hServer);
                return hrc;
            }
        }
    }
    if (RT_FAILURE(vrc))
        return setError(E_FAIL, tr("RTTcpServerCreateEx failed with status %Rrc"), vrc);

    /*
     * Create a one-shot timer for timing out after 5 mins.
     */
    RTTIMERLR hTimerLR;
    vrc = RTTimerLRCreateEx(&hTimerLR, 0 /*ns*/, RTTIMER_FLAGS_CPU_ANY, teleporterDstTimeout, hServer);
    if (RT_SUCCESS(vrc))
    {
        vrc = RTTimerLRStart(hTimerLR, 5*60*UINT64_C(1000000000) /*ns*/);
        if (RT_SUCCESS(vrc))
        {
            /*
             * Do the job, when it returns we're done.
             */
            TeleporterStateTrg theState(this, pUVM, pProgress, pMachine, mControl, &hTimerLR, fStartPaused);
            theState.mstrPassword      = strPassword;
            theState.mhServer          = hServer;

            void *pvUser = static_cast<void *>(static_cast<TeleporterState *>(&theState));
            if (pProgress->setCancelCallback(teleporterProgressCancelCallback, pvUser))
            {
                LogRel(("Teleporter: Waiting for incoming VM...\n"));
                hrc = pProgress->SetNextOperation(Bstr(tr("Waiting for incoming VM")).raw(), 1);
                if (SUCCEEDED(hrc))
                {
                    vrc = RTTcpServerListen(hServer, Console::teleporterTrgServeConnection, &theState);
                    pProgress->setCancelCallback(NULL, NULL);

                    if (vrc == VERR_TCP_SERVER_STOP)
                    {
                        vrc = theState.mRc;
                        /* Power off the VM on failure unless the state callback
                           already did that. */
                        *pfPowerOffOnFailure = false;
                        if (RT_SUCCESS(vrc))
                            hrc = S_OK;
                        else
                        {
                            VMSTATE enmVMState = VMR3GetStateU(pUVM);
                            if (    enmVMState != VMSTATE_OFF
                                    &&  enmVMState != VMSTATE_POWERING_OFF)
                                *pfPowerOffOnFailure = true;

                            /* Set error. */
                            if (pErrorMsg->length())
                                hrc = setError(E_FAIL, "%s", pErrorMsg->c_str());
                            else
                                hrc = setError(E_FAIL, tr("Teleporation failed (%Rrc)"), vrc);
                        }
                    }
                    else if (vrc == VERR_TCP_SERVER_SHUTDOWN)
                    {
                        BOOL fCanceled = TRUE;
                        hrc = pProgress->COMGETTER(Canceled)(&fCanceled);
                        if (FAILED(hrc) || fCanceled)
                            hrc = setError(E_FAIL, tr("Teleporting canceled"));
                        else
                            hrc = setError(E_FAIL, tr("Teleporter timed out waiting for incoming connection"));
                        LogRel(("Teleporter: RTTcpServerListen aborted - %Rrc\n", vrc));
                    }
                    else
                    {
                        hrc = setError(E_FAIL, tr("Unexpected RTTcpServerListen status code %Rrc"), vrc);
                        LogRel(("Teleporter: Unexpected RTTcpServerListen rc: %Rrc\n", vrc));
                    }
                }
                else
                    LogThisFunc(("SetNextOperation failed, %Rhrc\n", hrc));
            }
            else
            {
                LogThisFunc(("Canceled - check point #1\n"));
                hrc = setError(E_FAIL, tr("Teleporting canceled"));
            }
        }
        else
            hrc = setError(E_FAIL, "RTTimerLRStart -> %Rrc", vrc);

        RTTimerLRDestroy(hTimerLR);
    }
    else
        hrc = setError(E_FAIL, "RTTimerLRCreate -> %Rrc", vrc);
    RTTcpServerDestroy(hServer);

    /*
     * If we change TeleporterPort above, set it back to it's original
     * value before returning.
     */
    if (uPortOrg != uPort)
    {
        ErrorInfoKeeper Eik;
        pMachine->COMSETTER(TeleporterPort)(uPortOrg);
    }

    return hrc;
}