Пример #1
0
int
VBoxDbgBase::dbgcCreate(PDBGCBACK pBack, unsigned fFlags)
{
    PUVM pUVM = m_pUVM;
    if (    pUVM
        &&  VMR3GetStateU(pUVM) < VMSTATE_DESTROYING)
        return DBGCCreate(pUVM, pBack, fFlags);
    return VERR_INVALID_HANDLE;
}
Пример #2
0
int
VBoxDbgBase::stamEnum(const QString &rPat, PFNSTAMR3ENUM pfnEnum, void *pvUser)
{
    QByteArray Utf8Array = rPat.toUtf8();
    const char *pszPat = !rPat.isEmpty() ? Utf8Array.constData() : NULL;
    PUVM pUVM = m_pUVM;
    if (    pUVM
        &&  VMR3GetStateU(pUVM) < VMSTATE_DESTROYING)
        return STAMR3Enum(pUVM, pszPat, pfnEnum, pvUser);
    return VERR_INVALID_HANDLE;
}
Пример #3
0
int
VBoxDbgBase::stamReset(const QString &rPat)
{
    QByteArray Utf8Array = rPat.toUtf8();
    const char *pszPat = !rPat.isEmpty() ? Utf8Array.constData() : NULL;
    PUVM pUVM = m_pUVM;
    if (    pUVM
        &&  VMR3GetStateU(pUVM) < VMSTATE_DESTROYING)
        return STAMR3Reset(pUVM, pszPat);
    return VERR_INVALID_HANDLE;
}
Console::teleporterSrcThreadWrapper(RTTHREAD hThread, void *pvUser)
{
    TeleporterStateSrc *pState = (TeleporterStateSrc *)pvUser;

    /*
     * Console::teleporterSrc does the work, we just grab onto the VM handle
     * and do the cleanups afterwards.
     */
    SafeVMPtr ptrVM(pState->mptrConsole);
    HRESULT hrc = ptrVM.rc();

    if (SUCCEEDED(hrc))
        hrc = pState->mptrConsole->teleporterSrc(pState);

    /* Close the connection ASAP on so that the other side can complete. */
    if (pState->mhSocket != NIL_RTSOCKET)
    {
        RTTcpClientClose(pState->mhSocket);
        pState->mhSocket = NIL_RTSOCKET;
    }

    /* Aaarg! setMachineState trashes error info on Windows, so we have to
       complete things here on failure instead of right before cleanup. */
    if (FAILED(hrc))
        pState->mptrProgress->notifyComplete(hrc);

    /* We can no longer be canceled (success), or it doesn't matter any longer (failure). */
    pState->mptrProgress->setCancelCallback(NULL, NULL);

    /*
     * Write lock the console before resetting mptrCancelableProgress and
     * fixing the state.
     */
    AutoWriteLock autoLock(pState->mptrConsole COMMA_LOCKVAL_SRC_POS);
    pState->mptrConsole->mptrCancelableProgress.setNull();

    VMSTATE const        enmVMState      = VMR3GetStateU(pState->mpUVM);
    MachineState_T const enmMachineState = pState->mptrConsole->mMachineState;
    if (SUCCEEDED(hrc))
    {
        /*
         * Automatically shut down the VM on success.
         *
         * Note! We have to release the VM caller object or we'll deadlock in
         *       powerDown.
         */
        AssertLogRelMsg(enmVMState == VMSTATE_SUSPENDED, ("%s\n", VMR3GetStateName(enmVMState)));
        AssertLogRelMsg(enmMachineState == MachineState_TeleportingPausedVM, ("%s\n", Global::stringifyMachineState(enmMachineState)));

        ptrVM.release();

        pState->mptrConsole->mVMIsAlreadyPoweringOff = true; /* (Make sure we stick in the TeleportingPausedVM state.) */
        hrc = pState->mptrConsole->powerDown();
        pState->mptrConsole->mVMIsAlreadyPoweringOff = false;

        pState->mptrProgress->notifyComplete(hrc);
    }
    else
    {
        /*
         * Work the state machinery on failure.
         *
         * If the state is no longer 'Teleporting*', some other operation has
         * canceled us and there is nothing we need to do here.  In all other
         * cases, we've failed one way or another.
         */
        if (   enmMachineState == MachineState_Teleporting
                || enmMachineState == MachineState_TeleportingPausedVM
           )
        {
            if (pState->mfUnlockedMedia)
            {
                ErrorInfoKeeper Oak;
                HRESULT hrc2 = pState->mptrConsole->mControl->LockMedia();
                if (FAILED(hrc2))
                {
                    uint64_t StartMS = RTTimeMilliTS();
                    do
                    {
                        RTThreadSleep(2);
                        hrc2 = pState->mptrConsole->mControl->LockMedia();
                    } while (   FAILED(hrc2)
                                && RTTimeMilliTS() - StartMS < 2000);
                }
                if (SUCCEEDED(hrc2))
                    pState->mfUnlockedMedia = true;
                else
                    LogRel(("FATAL ERROR: Failed to re-take the media locks. hrc2=%Rhrc\n", hrc2));
            }

            switch (enmVMState)
            {
            case VMSTATE_RUNNING:
            case VMSTATE_RUNNING_LS:
            case VMSTATE_DEBUGGING:
            case VMSTATE_DEBUGGING_LS:
            case VMSTATE_POWERING_OFF:
            case VMSTATE_POWERING_OFF_LS:
            case VMSTATE_RESETTING:
            case VMSTATE_RESETTING_LS:
                Assert(!pState->mfSuspendedByUs);
                Assert(!pState->mfUnlockedMedia);
                pState->mptrConsole->setMachineState(MachineState_Running);
                break;

            case VMSTATE_GURU_MEDITATION:
            case VMSTATE_GURU_MEDITATION_LS:
                pState->mptrConsole->setMachineState(MachineState_Stuck);
                break;

            case VMSTATE_FATAL_ERROR:
            case VMSTATE_FATAL_ERROR_LS:
                pState->mptrConsole->setMachineState(MachineState_Paused);
                break;

            default:
                AssertMsgFailed(("%s\n", VMR3GetStateName(enmVMState)));
            case VMSTATE_SUSPENDED:
            case VMSTATE_SUSPENDED_LS:
            case VMSTATE_SUSPENDING:
            case VMSTATE_SUSPENDING_LS:
            case VMSTATE_SUSPENDING_EXT_LS:
                if (!pState->mfUnlockedMedia)
                {
                    pState->mptrConsole->setMachineState(MachineState_Paused);
                    if (pState->mfSuspendedByUs)
                    {
                        autoLock.release();
                        int rc = VMR3Resume(VMR3GetVM(pState->mpUVM));
                        AssertLogRelMsgRC(rc, ("VMR3Resume -> %Rrc\n", rc));
                        autoLock.acquire();
                    }
                }
                else
                {
                    /* Faking a guru meditation is the best I can think of doing here... */
                    pState->mptrConsole->setMachineState(MachineState_Stuck);
                }
                break;
            }
        }
    }
    autoLock.release();

    /*
     * Cleanup.
     */
    Assert(pState->mhSocket == NIL_RTSOCKET);
    delete pState;

    return VINF_SUCCESS; /* ignored */
}
/**
 * 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;
}