/** * Start teleporter to the specified target. * * @returns COM status code. * * @param aHostname The name of the target host. * @param aPort The TCP port number. * @param aPassword The password. * @param aMaxDowntime Max allowed "downtime" in milliseconds. * @param aProgress Where to return the progress object. */ STDMETHODIMP Console::Teleport(IN_BSTR aHostname, ULONG aPort, IN_BSTR aPassword, ULONG aMaxDowntime, IProgress **aProgress) { /* * Validate parameters, check+hold object status, write lock the object * and validate the state. */ CheckComArgOutPointerValid(aProgress); CheckComArgStrNotEmptyOrNull(aHostname); CheckComArgStrNotEmptyOrNull(aPassword); CheckComArgExprMsg(aPort, aPort > 0 && aPort <= 65535, ("is %u", aPort)); CheckComArgExprMsg(aMaxDowntime, aMaxDowntime > 0, ("is %u", aMaxDowntime)); Utf8Str strPassword(aPassword); if (!strPassword.isEmpty()) { if (VBoxIsPasswordHashed(&strPassword)) return setError(E_INVALIDARG, tr("The specified password resembles a hashed password, expected plain text")); VBoxHashPassword(&strPassword); } AutoCaller autoCaller(this); if (FAILED(autoCaller.rc())) return autoCaller.rc(); AutoWriteLock autoLock(this COMMA_LOCKVAL_SRC_POS); LogFlowThisFunc(("mMachineState=%d\n", mMachineState)); switch (mMachineState) { case MachineState_Running: case MachineState_Paused: break; default: return setError(VBOX_E_INVALID_VM_STATE, tr("Invalid machine state: %s (must be Running or Paused)"), Global::stringifyMachineState(mMachineState)); } /* * Create a progress object, spawn a worker thread and change the state. * Note! The thread won't start working until we release the lock. */ LogFlowThisFunc(("Initiating TELEPORT request...\n")); ComObjPtr<Progress> ptrProgress; HRESULT hrc = ptrProgress.createObject(); if (SUCCEEDED(hrc)) hrc = ptrProgress->init(static_cast<IConsole *>(this), Bstr(tr("Teleporter")).raw(), TRUE /*aCancelable*/); if (FAILED(hrc)) return hrc; TeleporterStateSrc *pState = new TeleporterStateSrc(this, mpUVM, ptrProgress, mMachineState); pState->mstrPassword = strPassword; pState->mstrHostname = aHostname; pState->muPort = aPort; pState->mcMsMaxDowntime = aMaxDowntime; void *pvUser = static_cast<void *>(static_cast<TeleporterState *>(pState)); ptrProgress->setCancelCallback(teleporterProgressCancelCallback, pvUser); int vrc = RTThreadCreate(NULL, Console::teleporterSrcThreadWrapper, (void *)pState, 0 /*cbStack*/, RTTHREADTYPE_EMULATION, 0 /*fFlags*/, "Teleport"); if (RT_SUCCESS(vrc)) { if (mMachineState == MachineState_Running) hrc = setMachineState(MachineState_Teleporting); else hrc = setMachineState(MachineState_TeleportingPausedVM); if (SUCCEEDED(hrc)) { ptrProgress.queryInterfaceTo(aProgress); mptrCancelableProgress = ptrProgress; } else ptrProgress->Cancel(); } else { ptrProgress->setCancelCallback(NULL, NULL); delete pState; hrc = setError(E_FAIL, tr("RTThreadCreate -> %Rrc"), vrc); } return hrc; }