VirtualBox

source: vbox/trunk/src/VBox/Main/src-client/ConsoleImpl.cpp@ 107268

Last change on this file since 107268 was 107268, checked in by vboxsync, 5 weeks ago

Build fix

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 419.9 KB
Line 
1/* $Id: ConsoleImpl.cpp 107268 2024-12-10 07:51:34Z vboxsync $ */
2/** @file
3 * VBox Console COM Class implementation
4 */
5
6/*
7 * Copyright (C) 2005-2024 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28#define LOG_GROUP LOG_GROUP_MAIN_CONSOLE
29#include "LoggingNew.h"
30
31/** @todo Move the TAP mess back into the driver! */
32#if defined(RT_OS_WINDOWS)
33#elif defined(RT_OS_LINUX)
34# include <errno.h>
35# include <sys/ioctl.h>
36# include <sys/poll.h>
37# include <sys/fcntl.h>
38# include <sys/types.h>
39# include <sys/wait.h>
40# include <net/if.h>
41# include <linux/if_tun.h>
42# include <stdio.h>
43# include <stdlib.h>
44# include <string.h>
45#elif defined(RT_OS_FREEBSD)
46# include <errno.h>
47# include <sys/ioctl.h>
48# include <sys/poll.h>
49# include <sys/fcntl.h>
50# include <sys/types.h>
51# include <sys/wait.h>
52# include <stdio.h>
53# include <stdlib.h>
54# include <string.h>
55#elif defined(RT_OS_SOLARIS)
56# include <iprt/coredumper.h>
57#endif
58
59#include "ConsoleImpl.h"
60
61#include "Global.h"
62#include "VirtualBoxErrorInfoImpl.h"
63#include "GuestImpl.h"
64#include "KeyboardImpl.h"
65#include "MouseImpl.h"
66#include "DisplayImpl.h"
67#include "MachineDebuggerImpl.h"
68#include "USBDeviceImpl.h"
69#include "RemoteUSBDeviceImpl.h"
70#include "ConsoleSharedFolderImpl.h"
71#ifdef VBOX_WITH_AUDIO_VRDE
72# include "DrvAudioVRDE.h"
73#endif
74#ifdef VBOX_WITH_AUDIO_RECORDING
75# include "DrvAudioRec.h"
76#endif
77#ifdef VBOX_WITH_USB_CARDREADER
78# include "UsbCardReader.h"
79#endif
80#include "PlatformPropertiesImpl.h"
81#include "ProgressImpl.h"
82#include "ConsoleVRDPServer.h"
83#include "VMMDev.h"
84#ifdef VBOX_WITH_EXTPACK
85# include "ExtPackManagerImpl.h"
86#endif
87#include "BusAssignmentManager.h"
88#include "PCIDeviceAttachmentImpl.h"
89#include "EmulatedUSBImpl.h"
90#include "NvramStoreImpl.h"
91#ifdef VBOX_WITH_VIRT_ARMV8
92# include "ResourceStoreImpl.h"
93#endif
94#ifdef VBOX_WITH_SHARED_CLIPBOARD
95# include "GuestShClPrivate.h"
96#endif
97#include "StringifyEnums.h"
98
99#include "VBoxEvents.h"
100#include "AutoCaller.h"
101#include "ThreadTask.h"
102
103#ifdef VBOX_WITH_RECORDING
104# include "Recording.h"
105#endif
106
107#include "CryptoUtils.h"
108
109#include <VBox/com/array.h>
110#include "VBox/com/ErrorInfo.h"
111#include <VBox/com/listeners.h>
112
113#include <iprt/asm.h>
114#include <iprt/buildconfig.h>
115#include <iprt/cpp/utils.h>
116#include <iprt/dir.h>
117#include <iprt/file.h>
118#include <iprt/ldr.h>
119#include <iprt/path.h>
120#include <iprt/process.h>
121#include <iprt/string.h>
122#include <iprt/system.h>
123#include <iprt/base64.h>
124#include <iprt/memsafer.h>
125
126#include <VBox/vmm/vmmr3vtable.h>
127#include <VBox/vmm/vmapi.h>
128#include <VBox/vmm/vmm.h>
129#include <VBox/vmm/pdmapi.h>
130#include <VBox/vmm/pdmaudioifs.h>
131#include <VBox/vmm/pdmasynccompletion.h>
132#include <VBox/vmm/pdmnetifs.h>
133#include <VBox/vmm/pdmstorageifs.h>
134#ifdef VBOX_WITH_USB
135# include <VBox/vmm/pdmusb.h>
136#endif
137#ifdef VBOX_WITH_NETSHAPER
138# include <VBox/vmm/pdmnetshaper.h>
139#endif /* VBOX_WITH_NETSHAPER */
140#include <VBox/vmm/mm.h>
141#include <VBox/vmm/ssm.h>
142#include <VBox/err.h>
143#include <VBox/param.h>
144#include <VBox/vusb.h>
145
146#include <VBox/VMMDev.h>
147
148#ifdef VBOX_WITH_SHARED_CLIPBOARD
149# include <VBox/HostServices/VBoxClipboardSvc.h>
150#endif
151#include <VBox/HostServices/DragAndDropSvc.h>
152#ifdef VBOX_WITH_GUEST_PROPS
153# include <VBox/HostServices/GuestPropertySvc.h>
154# include <VBox/com/array.h>
155#endif
156
157#ifdef VBOX_OPENSSL_FIPS
158# include <openssl/crypto.h>
159#endif
160
161#include <set>
162#include <algorithm>
163#include <memory> // for auto_ptr
164#include <vector>
165#include <exception>// std::exception
166
167// VMTask and friends
168////////////////////////////////////////////////////////////////////////////////
169
170/**
171 * Task structure for asynchronous VM operations.
172 *
173 * Once created, the task structure adds itself as a Console caller. This means:
174 *
175 * 1. The user must check for #hrc() before using the created structure
176 * (e.g. passing it as a thread function argument). If #hrc() returns a
177 * failure, the Console object may not be used by the task.
178 * 2. On successful initialization, the structure keeps the Console caller
179 * until destruction (to ensure Console remains in the Ready state and won't
180 * be accidentally uninitialized). Forgetting to delete the created task
181 * will lead to Console::uninit() stuck waiting for releasing all added
182 * callers.
183 *
184 * If \a aUsesVMPtr parameter is true, the task structure will also add itself
185 * as a Console::mpUVM caller with the same meaning as above. See
186 * Console::addVMCaller() for more info.
187 */
188class VMTask: public ThreadTask
189{
190public:
191 VMTask(Console *aConsole,
192 Progress *aProgress,
193 const ComPtr<IProgress> &aServerProgress,
194 bool aUsesVMPtr)
195 : ThreadTask("GenericVMTask"),
196 mConsole(aConsole),
197 mConsoleCaller(aConsole),
198 mProgress(aProgress),
199 mServerProgress(aServerProgress),
200 mRC(E_FAIL),
201 mpSafeVMPtr(NULL)
202 {
203 AssertReturnVoid(aConsole);
204 mRC = mConsoleCaller.hrc();
205 if (FAILED(mRC))
206 return;
207 if (aUsesVMPtr)
208 {
209 mpSafeVMPtr = new Console::SafeVMPtr(aConsole);
210 if (!mpSafeVMPtr->isOk())
211 mRC = mpSafeVMPtr->hrc();
212 }
213 }
214
215 virtual ~VMTask()
216 {
217 releaseVMCaller();
218 }
219
220 HRESULT hrc() const { return mRC; }
221 bool isOk() const { return SUCCEEDED(hrc()); }
222
223 /** Releases the VM caller before destruction. Not normally necessary. */
224 void releaseVMCaller()
225 {
226 if (mpSafeVMPtr)
227 {
228 delete mpSafeVMPtr;
229 mpSafeVMPtr = NULL;
230 }
231 }
232
233 const ComObjPtr<Console> mConsole;
234 AutoCaller mConsoleCaller;
235 const ComObjPtr<Progress> mProgress;
236 Utf8Str mErrorMsg;
237 const ComPtr<IProgress> mServerProgress;
238
239private:
240 HRESULT mRC;
241 Console::SafeVMPtr *mpSafeVMPtr;
242};
243
244
245class VMPowerUpTask : public VMTask
246{
247public:
248 VMPowerUpTask(Console *aConsole,
249 Progress *aProgress)
250 : VMTask(aConsole, aProgress, NULL /* aServerProgress */, false /* aUsesVMPtr */)
251 , mpfnConfigConstructor(NULL)
252 , mStartPaused(false)
253 , mTeleporterEnabled(FALSE)
254 , m_pKeyStore(NULL)
255 {
256 m_strTaskName = "VMPwrUp";
257 }
258
259 PFNCFGMCONSTRUCTOR mpfnConfigConstructor;
260 Utf8Str mSavedStateFile;
261 Utf8Str mKeyStore;
262 Utf8Str mKeyId;
263 Console::SharedFolderDataMap mSharedFolders;
264 bool mStartPaused;
265 BOOL mTeleporterEnabled;
266 SecretKeyStore *m_pKeyStore;
267
268 /* array of progress objects for hard disk reset operations */
269 typedef std::list<ComPtr<IProgress> > ProgressList;
270 ProgressList hardDiskProgresses;
271
272 void handler()
273 {
274 Console::i_powerUpThreadTask(this);
275 }
276
277};
278
279class VMPowerDownTask : public VMTask
280{
281public:
282 VMPowerDownTask(Console *aConsole,
283 const ComPtr<IProgress> &aServerProgress)
284 : VMTask(aConsole, NULL /* aProgress */, aServerProgress,
285 true /* aUsesVMPtr */)
286 {
287 m_strTaskName = "VMPwrDwn";
288 }
289
290 void handler()
291 {
292 Console::i_powerDownThreadTask(this);
293 }
294};
295
296// Handler for global events
297////////////////////////////////////////////////////////////////////////////////
298inline static const char *networkAdapterTypeToName(NetworkAdapterType_T adapterType);
299
300class VmEventListener
301{
302public:
303 VmEventListener()
304 {}
305
306
307 HRESULT init(Console *aConsole)
308 {
309 mConsole = aConsole;
310 return S_OK;
311 }
312
313 void uninit()
314 {
315 }
316
317 virtual ~VmEventListener()
318 {
319 }
320
321 STDMETHOD(HandleEvent)(VBoxEventType_T aType, IEvent *aEvent)
322 {
323 switch(aType)
324 {
325 case VBoxEventType_OnNATRedirect:
326 {
327 ComPtr<IMachine> pMachine = mConsole->i_machine();
328 ComPtr<INATRedirectEvent> pNREv = aEvent;
329 Assert(pNREv);
330
331 Bstr id;
332 HRESULT hrc = pNREv->COMGETTER(MachineId)(id.asOutParam());
333 AssertComRC(hrc);
334 if (id != mConsole->i_getId())
335 break;
336
337 /* now we can operate with redirects */
338 NATProtocol_T proto = (NATProtocol_T)0;
339 pNREv->COMGETTER(Proto)(&proto);
340 BOOL fRemove;
341 pNREv->COMGETTER(Remove)(&fRemove);
342 Bstr hostIp;
343 pNREv->COMGETTER(HostIP)(hostIp.asOutParam());
344 LONG hostPort = 0;
345 pNREv->COMGETTER(HostPort)(&hostPort);
346 Bstr guestIp;
347 pNREv->COMGETTER(GuestIP)(guestIp.asOutParam());
348 LONG guestPort = 0;
349 pNREv->COMGETTER(GuestPort)(&guestPort);
350 ULONG ulSlot;
351 hrc = pNREv->COMGETTER(Slot)(&ulSlot);
352 AssertComRCBreak(hrc, RT_NOTHING);
353 mConsole->i_onNATRedirectRuleChanged(ulSlot, fRemove, proto, hostIp.raw(), hostPort, guestIp.raw(), guestPort);
354 break;
355 }
356
357 case VBoxEventType_OnHostNameResolutionConfigurationChange:
358 {
359 mConsole->i_onNATDnsChanged();
360 break;
361 }
362
363 case VBoxEventType_OnHostPCIDevicePlug:
364 {
365 // handle if needed
366 break;
367 }
368
369 case VBoxEventType_OnExtraDataChanged:
370 {
371 ComPtr<IExtraDataChangedEvent> pEDCEv = aEvent;
372 Bstr strMachineId;
373 HRESULT hrc = pEDCEv->COMGETTER(MachineId)(strMachineId.asOutParam());
374 if (FAILED(hrc)) break;
375
376 Bstr strKey;
377 hrc = pEDCEv->COMGETTER(Key)(strKey.asOutParam());
378 if (FAILED(hrc)) break;
379
380 Bstr strVal;
381 hrc = pEDCEv->COMGETTER(Value)(strVal.asOutParam());
382 if (FAILED(hrc)) break;
383
384 mConsole->i_onExtraDataChange(strMachineId.raw(), strKey.raw(), strVal.raw());
385 break;
386 }
387
388 default:
389 AssertFailed();
390 }
391
392 return S_OK;
393 }
394private:
395 ComObjPtr<Console> mConsole;
396};
397
398typedef ListenerImpl<VmEventListener, Console*> VmEventListenerImpl;
399
400
401VBOX_LISTENER_DECLARE(VmEventListenerImpl)
402
403
404// constructor / destructor
405/////////////////////////////////////////////////////////////////////////////
406
407Console::Console()
408 : mSavedStateDataLoaded(false)
409 , mConsoleVRDPServer(NULL)
410 , mfVRDEChangeInProcess(false)
411 , mfVRDEChangePending(false)
412 , mhModVMM(NIL_RTLDRMOD)
413 , mpVMM(NULL)
414 , mpUVM(NULL)
415 , mVMCallers(0)
416 , mVMZeroCallersSem(NIL_RTSEMEVENT)
417 , mVMDestroying(false)
418 , mVMPoweredOff(false)
419 , mVMIsAlreadyPoweringOff(false)
420 , mfSnapshotFolderSizeWarningShown(false)
421 , mfSnapshotFolderExt4WarningShown(false)
422 , mfSnapshotFolderDiskTypeShown(false)
423 , mfVMHasUsbController(false)
424 , mfTurnResetIntoPowerOff(false)
425 , mfPowerOffCausedByReset(false)
426 , mpVmm2UserMethods(NULL)
427 , m_pVMMDev(NULL)
428 , mAudioVRDE(NULL)
429#ifdef VBOX_WITH_USB_CARDREADER
430 , mUsbCardReader(NULL)
431#endif
432 , mBusMgr(NULL)
433 , mLedLock(LOCKCLASS_LISTOFOTHEROBJECTS /* must be higher than LOCKCLASS_OTHEROBJECT */, "LedLock")
434 , muLedGen(0)
435 , muLedTypeGen(0)
436 , mcLedSets(0)
437 , m_pKeyStore(NULL)
438 , mpIfSecKey(NULL)
439 , mpIfSecKeyHlp(NULL)
440 , mVMStateChangeCallbackDisabled(false)
441 , mfUseHostClipboard(true)
442 , mMachineState(MachineState_PoweredOff)
443 , mhLdrModCrypto(NIL_RTLDRMOD)
444 , mcRefsCrypto(0)
445 , mpCryptoIf(NULL)
446{
447 RT_ZERO(maLedSets);
448 RT_ZERO(maLedTypes);
449}
450
451Console::~Console()
452{}
453
454HRESULT Console::FinalConstruct()
455{
456 LogFlowThisFunc(("\n"));
457
458 MYVMM2USERMETHODS *pVmm2UserMethods = (MYVMM2USERMETHODS *)RTMemAllocZ(sizeof(*mpVmm2UserMethods) + sizeof(Console *));
459 if (!pVmm2UserMethods)
460 return E_OUTOFMEMORY;
461 pVmm2UserMethods->u32Magic = VMM2USERMETHODS_MAGIC;
462 pVmm2UserMethods->u32Version = VMM2USERMETHODS_VERSION;
463 pVmm2UserMethods->pfnSaveState = Console::i_vmm2User_SaveState;
464 pVmm2UserMethods->pfnNotifyEmtInit = Console::i_vmm2User_NotifyEmtInit;
465 pVmm2UserMethods->pfnNotifyEmtTerm = Console::i_vmm2User_NotifyEmtTerm;
466 pVmm2UserMethods->pfnNotifyPdmtInit = Console::i_vmm2User_NotifyPdmtInit;
467 pVmm2UserMethods->pfnNotifyPdmtTerm = Console::i_vmm2User_NotifyPdmtTerm;
468 pVmm2UserMethods->pfnNotifyResetTurnedIntoPowerOff = Console::i_vmm2User_NotifyResetTurnedIntoPowerOff;
469 pVmm2UserMethods->pfnQueryGenericObject = Console::i_vmm2User_QueryGenericObject;
470 pVmm2UserMethods->u32EndMagic = VMM2USERMETHODS_MAGIC;
471 pVmm2UserMethods->pConsole = this;
472 mpVmm2UserMethods = pVmm2UserMethods;
473
474 MYPDMISECKEY *pIfSecKey = (MYPDMISECKEY *)RTMemAllocZ(sizeof(*mpIfSecKey) + sizeof(Console *));
475 if (!pIfSecKey)
476 return E_OUTOFMEMORY;
477 pIfSecKey->pfnKeyRetain = Console::i_pdmIfSecKey_KeyRetain;
478 pIfSecKey->pfnKeyRelease = Console::i_pdmIfSecKey_KeyRelease;
479 pIfSecKey->pfnPasswordRetain = Console::i_pdmIfSecKey_PasswordRetain;
480 pIfSecKey->pfnPasswordRelease = Console::i_pdmIfSecKey_PasswordRelease;
481 pIfSecKey->pConsole = this;
482 mpIfSecKey = pIfSecKey;
483
484 MYPDMISECKEYHLP *pIfSecKeyHlp = (MYPDMISECKEYHLP *)RTMemAllocZ(sizeof(*mpIfSecKeyHlp) + sizeof(Console *));
485 if (!pIfSecKeyHlp)
486 return E_OUTOFMEMORY;
487 pIfSecKeyHlp->pfnKeyMissingNotify = Console::i_pdmIfSecKeyHlp_KeyMissingNotify;
488 pIfSecKeyHlp->pConsole = this;
489 mpIfSecKeyHlp = pIfSecKeyHlp;
490
491#ifdef VBOX_WITH_USB
492 mRemoteUsbIf.pvUser = this;
493 mRemoteUsbIf.pfnQueryRemoteUsbBackend = Console::i_usbQueryRemoteUsbBackend;
494#endif
495
496 return BaseFinalConstruct();
497}
498
499void Console::FinalRelease()
500{
501 LogFlowThisFunc(("\n"));
502
503 uninit();
504
505 BaseFinalRelease();
506}
507
508// public initializer/uninitializer for internal purposes only
509/////////////////////////////////////////////////////////////////////////////
510
511/** @todo r=bird: aLockType is always LockType_VM. */
512HRESULT Console::initWithMachine(IMachine *aMachine, IInternalMachineControl *aControl, LockType_T aLockType)
513{
514 AssertReturn(aMachine && aControl, E_INVALIDARG);
515
516 /* Enclose the state transition NotReady->InInit->Ready */
517 AutoInitSpan autoInitSpan(this);
518 AssertReturn(autoInitSpan.isOk(), E_FAIL);
519
520 LogFlowThisFuncEnter();
521 LogFlowThisFunc(("aMachine=%p, aControl=%p\n", aMachine, aControl));
522
523 unconst(mMachine) = aMachine;
524 unconst(mControl) = aControl;
525
526 /* Cache essential properties and objects, and create child objects */
527
528 HRESULT hrc = mMachine->COMGETTER(State)(&mMachineState);
529 AssertComRCReturnRC(hrc);
530
531 hrc = mMachine->COMGETTER(Id)(mstrUuid.asOutParam());
532 AssertComRCReturnRC(hrc);
533
534#ifdef VBOX_WITH_EXTPACK
535 unconst(mptrExtPackManager).createObject();
536 hrc = mptrExtPackManager->initExtPackManager(NULL, VBOXEXTPACKCTX_VM_PROCESS);
537 AssertComRCReturnRC(hrc);
538#endif
539
540 // Event source may be needed by other children
541 unconst(mEventSource).createObject();
542 hrc = mEventSource->init();
543 AssertComRCReturnRC(hrc);
544
545 mcAudioRefs = 0;
546 mcVRDPClients = 0;
547 mu32SingleRDPClientId = 0;
548 mcGuestCredentialsProvided = false;
549
550 ComPtr<IPlatform> pPlatform;
551 hrc = mMachine->COMGETTER(Platform)(pPlatform.asOutParam());
552 AssertComRCReturnRC(hrc);
553
554 PlatformArchitecture_T platformArch;
555 hrc = pPlatform->COMGETTER(Architecture)(&platformArch);
556 AssertComRCReturnRC(hrc);
557
558 /* Now the VM specific parts */
559 /** @todo r=bird: aLockType is always LockType_VM. */
560 if (aLockType == LockType_VM)
561 {
562 const char *pszVMM = NULL; /* Shut up MSVC. */
563
564 switch (platformArch)
565 {
566 case PlatformArchitecture_x86:
567#if !defined(RT_ARCH_AMD64) && !defined(VBOX_WITH_X86_ON_ARM_ENABLED)
568 {
569 ComPtr<IVirtualBox> pVirtualBox;
570 hrc = mMachine->COMGETTER(Parent)(pVirtualBox.asOutParam());
571 if (SUCCEEDED(hrc))
572 {
573 Bstr bstrEnableX86OnArm;
574 hrc = pVirtualBox->GetExtraData(Bstr("VBoxInternal2/EnableX86OnArm").raw(), bstrEnableX86OnArm.asOutParam());
575 if (FAILED(hrc) || !bstrEnableX86OnArm.equals("1"))
576 {
577 hrc = setError(VBOX_E_PLATFORM_ARCH_NOT_SUPPORTED,
578 tr("Cannot run the machine because its platform architecture %s is not supported on %s"),
579 Global::stringifyPlatformArchitecture(platformArch),
580 Global::stringifyPlatformArchitecture(PlatformArchitecture_ARM));
581 break;
582 }
583 }
584 }
585#endif
586 pszVMM = "VBoxVMM";
587 break;
588#ifdef VBOX_WITH_VIRT_ARMV8
589 case PlatformArchitecture_ARM:
590 pszVMM = "VBoxVMMArm";
591 break;
592#endif
593 default:
594 hrc = VBOX_E_PLATFORM_ARCH_NOT_SUPPORTED;
595 break;
596 }
597
598 if (FAILED(hrc))
599 return hrc;
600
601 /* Load the VMM. We won't continue without it being successfully loaded here. */
602 hrc = i_loadVMM(pszVMM);
603 AssertComRCReturnRC(hrc);
604
605#ifdef VBOX_WITH_VIRT_ARMV8
606 unconst(mptrResourceStore).createObject();
607 hrc = mptrResourceStore->init(this);
608 AssertComRCReturnRC(hrc);
609#endif
610 hrc = mMachine->COMGETTER(VRDEServer)(unconst(mVRDEServer).asOutParam());
611 AssertComRCReturnRC(hrc);
612
613 unconst(mGuest).createObject();
614 hrc = mGuest->init(this);
615 AssertComRCReturnRC(hrc);
616
617 ULONG cCpus = 1;
618 hrc = mMachine->COMGETTER(CPUCount)(&cCpus);
619 mGuest->i_setCpuCount(cCpus);
620
621 unconst(mKeyboard).createObject();
622 hrc = mKeyboard->init(this);
623 AssertComRCReturnRC(hrc);
624
625 unconst(mMouse).createObject();
626 hrc = mMouse->init(this);
627 AssertComRCReturnRC(hrc);
628
629 unconst(mDisplay).createObject();
630 hrc = mDisplay->init(this);
631 AssertComRCReturnRC(hrc);
632
633 unconst(mVRDEServerInfo).createObject();
634 hrc = mVRDEServerInfo->init(this);
635 AssertComRCReturnRC(hrc);
636
637 unconst(mEmulatedUSB).createObject();
638 hrc = mEmulatedUSB->init(this);
639 AssertComRCReturnRC(hrc);
640
641 /* Init the NVRAM store. */
642 ComPtr<INvramStore> pNvramStore;
643 hrc = aMachine->COMGETTER(NonVolatileStore)(pNvramStore.asOutParam());
644 AssertComRCReturnRC(hrc);
645
646 Bstr strNonVolatilePath;
647 pNvramStore->COMGETTER(NonVolatileStorageFile)(strNonVolatilePath.asOutParam());
648
649 unconst(mptrNvramStore).createObject();
650 hrc = mptrNvramStore->init(this, strNonVolatilePath);
651 AssertComRCReturnRC(hrc);
652
653#ifdef VBOX_WITH_FULL_VM_ENCRYPTION
654 Bstr bstrNvramKeyId;
655 Bstr bstrNvramKeyStore;
656 hrc = pNvramStore->COMGETTER(KeyId)(bstrNvramKeyId.asOutParam());
657 AssertComRCReturnRC(hrc);
658 hrc = pNvramStore->COMGETTER(KeyStore)(bstrNvramKeyStore.asOutParam());
659 AssertComRCReturnRC(hrc);
660 const Utf8Str strNvramKeyId(bstrNvramKeyId);
661 const Utf8Str strNvramKeyStore(bstrNvramKeyStore);
662 mptrNvramStore->i_updateEncryptionSettings(strNvramKeyId, strNvramKeyStore);
663#endif
664
665 /* Grab global and machine shared folder lists */
666
667 hrc = i_fetchSharedFolders(true /* aGlobal */);
668 AssertComRCReturnRC(hrc);
669 hrc = i_fetchSharedFolders(false /* aGlobal */);
670 AssertComRCReturnRC(hrc);
671
672 /* Create other child objects */
673
674 unconst(mConsoleVRDPServer) = new ConsoleVRDPServer(this);
675 AssertReturn(mConsoleVRDPServer, E_FAIL);
676
677 /* Figure out size of meAttachmentType vector */
678 ComPtr<IVirtualBox> pVirtualBox;
679 hrc = aMachine->COMGETTER(Parent)(pVirtualBox.asOutParam());
680 AssertComRC(hrc);
681
682 ComPtr<ISystemProperties> pSystemProperties;
683 ComPtr<IPlatformProperties> pPlatformProperties;
684 if (pVirtualBox)
685 {
686 hrc = pVirtualBox->COMGETTER(SystemProperties)(pSystemProperties.asOutParam());
687 AssertComRC(hrc);
688 hrc = pVirtualBox->GetPlatformProperties(platformArch, pPlatformProperties.asOutParam());
689 AssertComRC(hrc);
690 }
691
692 ChipsetType_T chipsetType = ChipsetType_PIIX3;
693 pPlatform->COMGETTER(ChipsetType)(&chipsetType);
694 ULONG maxNetworkAdapters = 0;
695 if (pPlatformProperties)
696 pPlatformProperties->GetMaxNetworkAdapters(chipsetType, &maxNetworkAdapters);
697 meAttachmentType.resize(maxNetworkAdapters);
698 for (ULONG slot = 0; slot < maxNetworkAdapters; ++slot)
699 meAttachmentType[slot] = NetworkAttachmentType_Null;
700
701#ifdef VBOX_WITH_AUDIO_VRDE
702 unconst(mAudioVRDE) = new AudioVRDE(this);
703 AssertReturn(mAudioVRDE, E_FAIL);
704#endif
705#ifdef VBOX_WITH_AUDIO_RECORDING
706 unconst(mRecording.mAudioRec) = new AudioVideoRec(this);
707 AssertReturn(mRecording.mAudioRec, E_FAIL);
708#endif
709
710#ifdef VBOX_WITH_USB_CARDREADER
711 unconst(mUsbCardReader) = new UsbCardReader(this);
712 AssertReturn(mUsbCardReader, E_FAIL);
713#endif
714
715 m_cDisksPwProvided = 0;
716 m_cDisksEncrypted = 0;
717
718 unconst(m_pKeyStore) = new SecretKeyStore(true /* fKeyBufNonPageable */);
719 AssertReturn(m_pKeyStore, E_FAIL);
720
721 /* VirtualBox events registration. */
722 {
723 ComPtr<IEventSource> pES;
724 hrc = pVirtualBox->COMGETTER(EventSource)(pES.asOutParam());
725 AssertComRC(hrc);
726 ComObjPtr<VmEventListenerImpl> aVmListener;
727 aVmListener.createObject();
728 aVmListener->init(new VmEventListener(), this);
729 mVmListener = aVmListener;
730 com::SafeArray<VBoxEventType_T> eventTypes;
731 eventTypes.push_back(VBoxEventType_OnNATRedirect);
732 eventTypes.push_back(VBoxEventType_OnHostNameResolutionConfigurationChange);
733 eventTypes.push_back(VBoxEventType_OnHostPCIDevicePlug);
734 eventTypes.push_back(VBoxEventType_OnExtraDataChanged);
735 hrc = pES->RegisterListener(aVmListener, ComSafeArrayAsInParam(eventTypes), true);
736 AssertComRC(hrc);
737 }
738 }
739
740 /* Confirm a successful initialization when it's the case */
741 autoInitSpan.setSucceeded();
742
743#ifdef VBOX_WITH_EXTPACK
744 /* Let the extension packs have a go at things (hold no locks). */
745 if (SUCCEEDED(hrc))
746 mptrExtPackManager->i_callAllConsoleReadyHooks(this);
747#endif
748
749 LogFlowThisFuncLeave();
750
751 return S_OK;
752}
753
754/**
755 * Uninitializes the Console object.
756 */
757void Console::uninit()
758{
759 LogFlowThisFuncEnter();
760
761 /* Enclose the state transition Ready->InUninit->NotReady */
762 AutoUninitSpan autoUninitSpan(this);
763 if (autoUninitSpan.uninitDone())
764 {
765 LogFlowThisFunc(("Already uninitialized.\n"));
766 LogFlowThisFuncLeave();
767 return;
768 }
769
770 LogFlowThisFunc(("initFailed()=%d\n", autoUninitSpan.initFailed()));
771 if (mVmListener)
772 {
773 ComPtr<IEventSource> pES;
774 ComPtr<IVirtualBox> pVirtualBox;
775 HRESULT hrc = mMachine->COMGETTER(Parent)(pVirtualBox.asOutParam());
776 AssertComRC(hrc);
777 if (SUCCEEDED(hrc) && !pVirtualBox.isNull())
778 {
779 hrc = pVirtualBox->COMGETTER(EventSource)(pES.asOutParam());
780 AssertComRC(hrc);
781 if (!pES.isNull())
782 {
783 hrc = pES->UnregisterListener(mVmListener);
784 AssertComRC(hrc);
785 }
786 }
787 mVmListener.setNull();
788 }
789
790 /* power down the VM if necessary */
791 if (mpUVM)
792 {
793 i_powerDown();
794 Assert(mpUVM == NULL);
795 }
796
797 if (mVMZeroCallersSem != NIL_RTSEMEVENT)
798 {
799 RTSemEventDestroy(mVMZeroCallersSem);
800 mVMZeroCallersSem = NIL_RTSEMEVENT;
801 }
802
803 if (mpVmm2UserMethods)
804 {
805 RTMemFree((void *)mpVmm2UserMethods);
806 mpVmm2UserMethods = NULL;
807 }
808
809 if (mpIfSecKey)
810 {
811 RTMemFree((void *)mpIfSecKey);
812 mpIfSecKey = NULL;
813 }
814
815 if (mpIfSecKeyHlp)
816 {
817 RTMemFree((void *)mpIfSecKeyHlp);
818 mpIfSecKeyHlp = NULL;
819 }
820
821#ifdef VBOX_WITH_USB_CARDREADER
822 if (mUsbCardReader)
823 {
824 delete mUsbCardReader;
825 unconst(mUsbCardReader) = NULL;
826 }
827#endif
828
829#ifdef VBOX_WITH_AUDIO_VRDE
830 if (mAudioVRDE)
831 {
832 delete mAudioVRDE;
833 unconst(mAudioVRDE) = NULL;
834 }
835#endif
836
837#ifdef VBOX_WITH_RECORDING
838 i_recordingDestroy();
839# ifdef VBOX_WITH_AUDIO_RECORDING
840 if (mRecording.mAudioRec)
841 {
842 delete mRecording.mAudioRec;
843 unconst(mRecording.mAudioRec) = NULL;
844 }
845# endif
846#endif /* VBOX_WITH_RECORDING */
847
848 // if the VM had a VMMDev with an HGCM thread, then remove that here
849 if (m_pVMMDev)
850 {
851 delete m_pVMMDev;
852 unconst(m_pVMMDev) = NULL;
853 }
854
855 if (mBusMgr)
856 {
857 mBusMgr->Release();
858 mBusMgr = NULL;
859 }
860
861 if (m_pKeyStore)
862 {
863 delete m_pKeyStore;
864 unconst(m_pKeyStore) = NULL;
865 }
866
867 m_mapGlobalSharedFolders.clear();
868 m_mapMachineSharedFolders.clear();
869 m_mapSharedFolders.clear(); // console instances
870
871 mRemoteUSBDevices.clear();
872 mUSBDevices.clear();
873
874 if (mVRDEServerInfo)
875 {
876 mVRDEServerInfo->uninit();
877 unconst(mVRDEServerInfo).setNull();
878 }
879
880 if (mEmulatedUSB)
881 {
882 mEmulatedUSB->uninit();
883 unconst(mEmulatedUSB).setNull();
884 }
885
886 if (mDebugger)
887 {
888 mDebugger->uninit();
889 unconst(mDebugger).setNull();
890 }
891
892 if (mDisplay)
893 {
894 mDisplay->uninit();
895 unconst(mDisplay).setNull();
896 }
897
898 if (mMouse)
899 {
900 mMouse->uninit();
901 unconst(mMouse).setNull();
902 }
903
904 if (mKeyboard)
905 {
906 mKeyboard->uninit();
907 unconst(mKeyboard).setNull();
908 }
909
910 if (mGuest)
911 {
912 mGuest->uninit();
913 unconst(mGuest).setNull();
914 }
915
916 if (mConsoleVRDPServer)
917 {
918 delete mConsoleVRDPServer;
919 unconst(mConsoleVRDPServer) = NULL;
920 }
921
922 if (mptrNvramStore)
923 {
924 mptrNvramStore->uninit();
925 unconst(mptrNvramStore).setNull();
926 }
927
928 unconst(mVRDEServer).setNull();
929
930#ifdef VBOX_WITH_VIRT_ARMV8
931 if (mptrResourceStore)
932 {
933 mptrResourceStore->uninit();
934 unconst(mptrResourceStore).setNull();
935 }
936#endif
937
938 unconst(mControl).setNull();
939 unconst(mMachine).setNull();
940
941 // we don't perform uninit() as it's possible that some pending event refers to this source
942 unconst(mEventSource).setNull();
943
944#ifdef VBOX_WITH_EXTPACK
945 unconst(mptrExtPackManager).setNull();
946#endif
947
948 /* Unload the VMM. */
949 mpVMM = NULL;
950 if (mhModVMM != NIL_RTLDRMOD)
951 {
952 RTLdrClose(mhModVMM);
953 mhModVMM = NIL_RTLDRMOD;
954 }
955
956 /* Release memory held by the LED sets (no need to take lock). */
957 for (size_t idxType = 0; idxType < RT_ELEMENTS(maLedTypes); idxType++)
958 {
959 maLedTypes[idxType].cLeds = 0;
960 maLedTypes[idxType].cAllocated = 0;
961 RTMemFree(maLedTypes[idxType].pappLeds);
962 maLedTypes[idxType].pappLeds = NULL;
963 }
964 for (size_t idxSet = 0; idxSet < mcLedSets; idxSet++)
965 {
966 maLedSets[idxSet].cLeds = 0;
967 RTMemFree((void *)maLedSets[idxSet].papLeds);
968 maLedSets[idxSet].papLeds = NULL;
969 maLedSets[idxSet].paSubTypes = NULL;
970 }
971 mcLedSets = 0;
972
973#ifdef VBOX_WITH_FULL_VM_ENCRYPTION
974 /* Close the release log before unloading the cryptographic module. */
975 if (m_fEncryptedLog)
976 {
977 PRTLOGGER pLogEnc = RTLogRelSetDefaultInstance(NULL);
978 int vrc = RTLogDestroy(pLogEnc);
979 AssertRC(vrc);
980 }
981#endif
982
983 HRESULT hrc = i_unloadCryptoIfModule();
984 AssertComRC(hrc);
985
986 LogFlowThisFuncLeave();
987}
988
989#ifdef VBOX_WITH_GUEST_PROPS
990
991/**
992 * Wrapper for VMMDev::i_guestPropertiesHandleVMReset
993 */
994HRESULT Console::i_pullGuestProperties(ComSafeArrayOut(BSTR, names), ComSafeArrayOut(BSTR, values),
995 ComSafeArrayOut(LONG64, timestamps), ComSafeArrayOut(BSTR, flags))
996{
997 AssertReturn(mControl.isNotNull(), E_POINTER);
998 return mControl->PullGuestProperties(ComSafeArrayOutArg(names), ComSafeArrayOutArg(values),
999 ComSafeArrayOutArg(timestamps), ComSafeArrayOutArg(flags));
1000}
1001
1002/**
1003 * Handles guest properties on a VM reset.
1004 *
1005 * We must delete properties that are flagged TRANSRESET.
1006 *
1007 * @todo r=bird: Would be more efficient if we added a request to the HGCM
1008 * service to do this instead of detouring thru VBoxSVC.
1009 * (IMachine::SetGuestProperty ends up in VBoxSVC, which in turns calls
1010 * back into the VM process and the HGCM service.)
1011 */
1012void Console::i_guestPropertiesHandleVMReset(void)
1013{
1014 std::vector<Utf8Str> names;
1015 std::vector<Utf8Str> values;
1016 std::vector<LONG64> timestamps;
1017 std::vector<Utf8Str> flags;
1018 HRESULT hrc = i_enumerateGuestProperties("*", names, values, timestamps, flags);
1019 if (SUCCEEDED(hrc))
1020 {
1021 for (size_t i = 0; i < flags.size(); i++)
1022 {
1023 /* Delete all properties which have the flag "TRANSRESET". */
1024 if (flags[i].contains("TRANSRESET", Utf8Str::CaseInsensitive))
1025 {
1026 hrc = mMachine->DeleteGuestProperty(Bstr(names[i]).raw());
1027 if (FAILED(hrc))
1028 LogRel(("RESET: Could not delete transient property \"%s\", hrc=%Rhrc\n",
1029 names[i].c_str(), hrc));
1030 }
1031 }
1032 }
1033 else
1034 LogRel(("RESET: Unable to enumerate guest properties, hrc=%Rhrc\n", hrc));
1035}
1036
1037bool Console::i_guestPropertiesVRDPEnabled(void)
1038{
1039 Bstr value;
1040 HRESULT hrc = mMachine->GetExtraData(Bstr("VBoxInternal2/EnableGuestPropertiesVRDP").raw(),
1041 value.asOutParam());
1042 if ( hrc == S_OK
1043 && value == "1")
1044 return true;
1045 return false;
1046}
1047
1048void Console::i_guestPropertiesVRDPUpdateLogon(uint32_t u32ClientId, const char *pszUser, const char *pszDomain)
1049{
1050 if (!i_guestPropertiesVRDPEnabled())
1051 return;
1052
1053 LogFlowFunc(("\n"));
1054
1055 char szPropNm[256];
1056 Bstr bstrReadOnlyGuest(L"RDONLYGUEST");
1057
1058 RTStrPrintf(szPropNm, sizeof(szPropNm), "/VirtualBox/HostInfo/VRDP/Client/%u/Name", u32ClientId);
1059 Bstr clientName;
1060 mVRDEServerInfo->COMGETTER(ClientName)(clientName.asOutParam());
1061
1062 mMachine->SetGuestProperty(Bstr(szPropNm).raw(),
1063 clientName.raw(),
1064 bstrReadOnlyGuest.raw());
1065
1066 RTStrPrintf(szPropNm, sizeof(szPropNm), "/VirtualBox/HostInfo/VRDP/Client/%u/User", u32ClientId);
1067 mMachine->SetGuestProperty(Bstr(szPropNm).raw(),
1068 Bstr(pszUser).raw(),
1069 bstrReadOnlyGuest.raw());
1070
1071 RTStrPrintf(szPropNm, sizeof(szPropNm), "/VirtualBox/HostInfo/VRDP/Client/%u/Domain", u32ClientId);
1072 mMachine->SetGuestProperty(Bstr(szPropNm).raw(),
1073 Bstr(pszDomain).raw(),
1074 bstrReadOnlyGuest.raw());
1075
1076 char szClientId[64];
1077 RTStrPrintf(szClientId, sizeof(szClientId), "%u", u32ClientId);
1078 mMachine->SetGuestProperty(Bstr("/VirtualBox/HostInfo/VRDP/LastConnectedClient").raw(),
1079 Bstr(szClientId).raw(),
1080 bstrReadOnlyGuest.raw());
1081
1082 return;
1083}
1084
1085void Console::i_guestPropertiesVRDPUpdateActiveClient(uint32_t u32ClientId)
1086{
1087 if (!i_guestPropertiesVRDPEnabled())
1088 return;
1089
1090 LogFlowFunc(("%d\n", u32ClientId));
1091
1092 Bstr bstrFlags(L"RDONLYGUEST,TRANSIENT");
1093
1094 char szClientId[64];
1095 RTStrPrintf(szClientId, sizeof(szClientId), "%u", u32ClientId);
1096
1097 mMachine->SetGuestProperty(Bstr("/VirtualBox/HostInfo/VRDP/ActiveClient").raw(),
1098 Bstr(szClientId).raw(),
1099 bstrFlags.raw());
1100
1101 return;
1102}
1103
1104void Console::i_guestPropertiesVRDPUpdateNameChange(uint32_t u32ClientId, const char *pszName)
1105{
1106 if (!i_guestPropertiesVRDPEnabled())
1107 return;
1108
1109 LogFlowFunc(("\n"));
1110
1111 char szPropNm[256];
1112 Bstr bstrReadOnlyGuest(L"RDONLYGUEST");
1113
1114 RTStrPrintf(szPropNm, sizeof(szPropNm), "/VirtualBox/HostInfo/VRDP/Client/%u/Name", u32ClientId);
1115 Bstr clientName(pszName);
1116
1117 mMachine->SetGuestProperty(Bstr(szPropNm).raw(),
1118 clientName.raw(),
1119 bstrReadOnlyGuest.raw());
1120
1121}
1122
1123void Console::i_guestPropertiesVRDPUpdateIPAddrChange(uint32_t u32ClientId, const char *pszIPAddr)
1124{
1125 if (!i_guestPropertiesVRDPEnabled())
1126 return;
1127
1128 LogFlowFunc(("\n"));
1129
1130 char szPropNm[256];
1131 Bstr bstrReadOnlyGuest(L"RDONLYGUEST");
1132
1133 RTStrPrintf(szPropNm, sizeof(szPropNm), "/VirtualBox/HostInfo/VRDP/Client/%u/IPAddr", u32ClientId);
1134 Bstr clientIPAddr(pszIPAddr);
1135
1136 mMachine->SetGuestProperty(Bstr(szPropNm).raw(),
1137 clientIPAddr.raw(),
1138 bstrReadOnlyGuest.raw());
1139
1140}
1141
1142void Console::i_guestPropertiesVRDPUpdateLocationChange(uint32_t u32ClientId, const char *pszLocation)
1143{
1144 if (!i_guestPropertiesVRDPEnabled())
1145 return;
1146
1147 LogFlowFunc(("\n"));
1148
1149 char szPropNm[256];
1150 Bstr bstrReadOnlyGuest(L"RDONLYGUEST");
1151
1152 RTStrPrintf(szPropNm, sizeof(szPropNm), "/VirtualBox/HostInfo/VRDP/Client/%u/Location", u32ClientId);
1153 Bstr clientLocation(pszLocation);
1154
1155 mMachine->SetGuestProperty(Bstr(szPropNm).raw(),
1156 clientLocation.raw(),
1157 bstrReadOnlyGuest.raw());
1158
1159}
1160
1161void Console::i_guestPropertiesVRDPUpdateOtherInfoChange(uint32_t u32ClientId, const char *pszOtherInfo)
1162{
1163 if (!i_guestPropertiesVRDPEnabled())
1164 return;
1165
1166 LogFlowFunc(("\n"));
1167
1168 char szPropNm[256];
1169 Bstr bstrReadOnlyGuest(L"RDONLYGUEST");
1170
1171 RTStrPrintf(szPropNm, sizeof(szPropNm), "/VirtualBox/HostInfo/VRDP/Client/%u/OtherInfo", u32ClientId);
1172 Bstr clientOtherInfo(pszOtherInfo);
1173
1174 mMachine->SetGuestProperty(Bstr(szPropNm).raw(),
1175 clientOtherInfo.raw(),
1176 bstrReadOnlyGuest.raw());
1177
1178}
1179
1180void Console::i_guestPropertiesVRDPUpdateClientAttach(uint32_t u32ClientId, bool fAttached)
1181{
1182 if (!i_guestPropertiesVRDPEnabled())
1183 return;
1184
1185 LogFlowFunc(("\n"));
1186
1187 Bstr bstrReadOnlyGuest(L"RDONLYGUEST");
1188
1189 char szPropNm[256];
1190 RTStrPrintf(szPropNm, sizeof(szPropNm), "/VirtualBox/HostInfo/VRDP/Client/%u/Attach", u32ClientId);
1191
1192 Bstr bstrValue = fAttached? "1": "0";
1193
1194 mMachine->SetGuestProperty(Bstr(szPropNm).raw(),
1195 bstrValue.raw(),
1196 bstrReadOnlyGuest.raw());
1197}
1198
1199void Console::i_guestPropertiesVRDPUpdateDisconnect(uint32_t u32ClientId)
1200{
1201 if (!i_guestPropertiesVRDPEnabled())
1202 return;
1203
1204 LogFlowFunc(("\n"));
1205
1206 Bstr bstrReadOnlyGuest(L"RDONLYGUEST");
1207
1208 char szPropNm[256];
1209 RTStrPrintf(szPropNm, sizeof(szPropNm), "/VirtualBox/HostInfo/VRDP/Client/%u/Name", u32ClientId);
1210 mMachine->SetGuestProperty(Bstr(szPropNm).raw(), NULL,
1211 bstrReadOnlyGuest.raw());
1212
1213 RTStrPrintf(szPropNm, sizeof(szPropNm), "/VirtualBox/HostInfo/VRDP/Client/%u/User", u32ClientId);
1214 mMachine->SetGuestProperty(Bstr(szPropNm).raw(), NULL,
1215 bstrReadOnlyGuest.raw());
1216
1217 RTStrPrintf(szPropNm, sizeof(szPropNm), "/VirtualBox/HostInfo/VRDP/Client/%u/Domain", u32ClientId);
1218 mMachine->SetGuestProperty(Bstr(szPropNm).raw(), NULL,
1219 bstrReadOnlyGuest.raw());
1220
1221 RTStrPrintf(szPropNm, sizeof(szPropNm), "/VirtualBox/HostInfo/VRDP/Client/%u/Attach", u32ClientId);
1222 mMachine->SetGuestProperty(Bstr(szPropNm).raw(), NULL,
1223 bstrReadOnlyGuest.raw());
1224
1225 char szClientId[64];
1226 RTStrPrintf(szClientId, sizeof(szClientId), "%d", u32ClientId);
1227 mMachine->SetGuestProperty(Bstr("/VirtualBox/HostInfo/VRDP/LastDisconnectedClient").raw(),
1228 Bstr(szClientId).raw(),
1229 bstrReadOnlyGuest.raw());
1230
1231 return;
1232}
1233
1234#endif /* VBOX_WITH_GUEST_PROPS */
1235
1236#ifdef VBOX_WITH_EXTPACK
1237/**
1238 * Used by VRDEServer and others to talke to the extension pack manager.
1239 *
1240 * @returns The extension pack manager.
1241 */
1242ExtPackManager *Console::i_getExtPackManager()
1243{
1244 return mptrExtPackManager;
1245}
1246#endif
1247
1248
1249int Console::i_VRDPClientLogon(uint32_t u32ClientId, const char *pszUser, const char *pszPassword, const char *pszDomain)
1250{
1251 LogFlowFuncEnter();
1252 LogFlowFunc(("%d, %s, %s, %s\n", u32ClientId, pszUser, pszPassword, pszDomain));
1253
1254 AutoCaller autoCaller(this);
1255 if (!autoCaller.isOk())
1256 {
1257 /* Console has been already uninitialized, deny request */
1258 LogRel(("AUTH: Access denied (Console uninitialized).\n"));
1259 LogFlowFuncLeave();
1260 return VERR_ACCESS_DENIED;
1261 }
1262
1263 Guid uuid = Guid(i_getId());
1264
1265 AuthType_T authType = AuthType_Null;
1266 HRESULT hrc = mVRDEServer->COMGETTER(AuthType)(&authType);
1267 AssertComRCReturn(hrc, VERR_ACCESS_DENIED);
1268
1269 ULONG authTimeout = 0;
1270 hrc = mVRDEServer->COMGETTER(AuthTimeout)(&authTimeout);
1271 AssertComRCReturn(hrc, VERR_ACCESS_DENIED);
1272
1273 AuthResult result = AuthResultAccessDenied;
1274 AuthGuestJudgement guestJudgement = AuthGuestNotAsked;
1275
1276 LogFlowFunc(("Auth type %d\n", authType));
1277
1278 LogRel(("AUTH: User: [%s]. Domain: [%s]. Authentication type: [%s]\n",
1279 pszUser, pszDomain,
1280 authType == AuthType_Null?
1281 "Null":
1282 (authType == AuthType_External?
1283 "External":
1284 (authType == AuthType_Guest?
1285 "Guest":
1286 "INVALID"
1287 )
1288 )
1289 ));
1290
1291 switch (authType)
1292 {
1293 case AuthType_Null:
1294 {
1295 result = AuthResultAccessGranted;
1296 break;
1297 }
1298
1299 case AuthType_External:
1300 {
1301 /* Call the external library. */
1302 result = mConsoleVRDPServer->Authenticate(uuid, guestJudgement, pszUser, pszPassword, pszDomain, u32ClientId);
1303
1304 if (result != AuthResultDelegateToGuest)
1305 {
1306 break;
1307 }
1308
1309 LogRel(("AUTH: Delegated to guest.\n"));
1310
1311 LogFlowFunc(("External auth asked for guest judgement\n"));
1312 }
1313 RT_FALL_THRU();
1314
1315 case AuthType_Guest:
1316 {
1317 guestJudgement = AuthGuestNotReacted;
1318
1319 /** @todo r=dj locking required here for m_pVMMDev? */
1320 PPDMIVMMDEVPORT pDevPort;
1321 if ( m_pVMMDev
1322 && ((pDevPort = m_pVMMDev->getVMMDevPort()))
1323 )
1324 {
1325 /* Issue the request to guest. Assume that the call does not require EMT. It should not. */
1326
1327 /* Ask the guest to judge these credentials. */
1328 uint32_t u32GuestFlags = VMMDEV_SETCREDENTIALS_JUDGE;
1329
1330 int vrc = pDevPort->pfnSetCredentials(pDevPort, pszUser, pszPassword, pszDomain, u32GuestFlags);
1331 if (RT_SUCCESS(vrc))
1332 {
1333 /* Wait for guest. */
1334 vrc = m_pVMMDev->WaitCredentialsJudgement(authTimeout, &u32GuestFlags);
1335 if (RT_SUCCESS(vrc))
1336 {
1337 switch (u32GuestFlags & ( VMMDEV_CREDENTIALS_JUDGE_OK
1338 | VMMDEV_CREDENTIALS_JUDGE_DENY
1339 | VMMDEV_CREDENTIALS_JUDGE_NOJUDGEMENT))
1340 {
1341 case VMMDEV_CREDENTIALS_JUDGE_DENY: guestJudgement = AuthGuestAccessDenied; break;
1342 case VMMDEV_CREDENTIALS_JUDGE_NOJUDGEMENT: guestJudgement = AuthGuestNoJudgement; break;
1343 case VMMDEV_CREDENTIALS_JUDGE_OK: guestJudgement = AuthGuestAccessGranted; break;
1344 default:
1345 LogFlowFunc(("Invalid guest flags %#08x!!!\n", u32GuestFlags));
1346 break;
1347 }
1348 }
1349 else
1350 LogFlowFunc(("Wait for credentials judgement vrc = %Rrc!!!\n", vrc));
1351 LogFlowFunc(("Guest judgement %d\n", guestJudgement));
1352 }
1353 else
1354 LogFlowFunc(("Could not set credentials vrc = %Rrc!!!\n", vrc));
1355 }
1356
1357 if (authType == AuthType_External)
1358 {
1359 LogRel(("AUTH: Guest judgement %d.\n", guestJudgement));
1360 LogFlowFunc(("External auth called again with guest judgement = %d\n", guestJudgement));
1361 result = mConsoleVRDPServer->Authenticate(uuid, guestJudgement, pszUser, pszPassword, pszDomain, u32ClientId);
1362 }
1363 else
1364 {
1365 switch (guestJudgement)
1366 {
1367 case AuthGuestAccessGranted:
1368 result = AuthResultAccessGranted;
1369 break;
1370 default:
1371 result = AuthResultAccessDenied;
1372 break;
1373 }
1374 }
1375 break;
1376 }
1377
1378 default:
1379 AssertFailed();
1380 }
1381
1382 LogFlowFunc(("Result = %d\n", result));
1383 LogFlowFuncLeave();
1384
1385 if (result != AuthResultAccessGranted)
1386 {
1387 /* Reject. */
1388 LogRel(("AUTH: Access denied.\n"));
1389 return VERR_ACCESS_DENIED;
1390 }
1391
1392 LogRel(("AUTH: Access granted.\n"));
1393
1394 /* Multiconnection check must be made after authentication, so bad clients would not interfere with a good one. */
1395 BOOL allowMultiConnection = FALSE;
1396 hrc = mVRDEServer->COMGETTER(AllowMultiConnection)(&allowMultiConnection);
1397 AssertComRCReturn(hrc, VERR_ACCESS_DENIED);
1398
1399 BOOL reuseSingleConnection = FALSE;
1400 hrc = mVRDEServer->COMGETTER(ReuseSingleConnection)(&reuseSingleConnection);
1401 AssertComRCReturn(hrc, VERR_ACCESS_DENIED);
1402
1403 LogFlowFunc(("allowMultiConnection %d, reuseSingleConnection = %d, mcVRDPClients = %d, mu32SingleRDPClientId = %d\n",
1404 allowMultiConnection, reuseSingleConnection, mcVRDPClients, mu32SingleRDPClientId));
1405
1406 if (allowMultiConnection == FALSE)
1407 {
1408 /* Note: the 'mcVRDPClients' variable is incremented in ClientConnect callback, which is called when the client
1409 * is successfully connected, that is after the ClientLogon callback. Therefore the mcVRDPClients
1410 * value is 0 for first client.
1411 */
1412 if (mcVRDPClients != 0)
1413 {
1414 Assert(mcVRDPClients == 1);
1415 /* There is a client already.
1416 * If required drop the existing client connection and let the connecting one in.
1417 */
1418 if (reuseSingleConnection)
1419 {
1420 LogRel(("AUTH: Multiple connections are not enabled. Disconnecting existing client.\n"));
1421 mConsoleVRDPServer->DisconnectClient(mu32SingleRDPClientId, false);
1422 }
1423 else
1424 {
1425 /* Reject. */
1426 LogRel(("AUTH: Multiple connections are not enabled. Access denied.\n"));
1427 return VERR_ACCESS_DENIED;
1428 }
1429 }
1430
1431 /* Save the connected client id. From now on it will be necessary to disconnect this one. */
1432 mu32SingleRDPClientId = u32ClientId;
1433 }
1434
1435#ifdef VBOX_WITH_GUEST_PROPS
1436 i_guestPropertiesVRDPUpdateLogon(u32ClientId, pszUser, pszDomain);
1437#endif /* VBOX_WITH_GUEST_PROPS */
1438
1439 /* Check if the successfully verified credentials are to be sent to the guest. */
1440 BOOL fProvideGuestCredentials = FALSE;
1441
1442 Bstr value;
1443 hrc = mMachine->GetExtraData(Bstr("VRDP/ProvideGuestCredentials").raw(),
1444 value.asOutParam());
1445 if (SUCCEEDED(hrc) && value == "1")
1446 {
1447 /* Provide credentials only if there are no logged in users. */
1448 Utf8Str noLoggedInUsersValue;
1449 LONG64 ul64Timestamp = 0;
1450 Utf8Str flags;
1451
1452 hrc = i_getGuestProperty("/VirtualBox/GuestInfo/OS/NoLoggedInUsers",
1453 &noLoggedInUsersValue, &ul64Timestamp, &flags);
1454
1455 if (SUCCEEDED(hrc) && noLoggedInUsersValue != "false")
1456 {
1457 /* And only if there are no connected clients. */
1458 if (ASMAtomicCmpXchgBool(&mcGuestCredentialsProvided, true, false))
1459 {
1460 fProvideGuestCredentials = TRUE;
1461 }
1462 }
1463 }
1464
1465 /** @todo r=dj locking required here for m_pVMMDev? */
1466 if ( fProvideGuestCredentials
1467 && m_pVMMDev)
1468 {
1469 uint32_t u32GuestFlags = VMMDEV_SETCREDENTIALS_GUESTLOGON;
1470
1471 PPDMIVMMDEVPORT pDevPort = m_pVMMDev->getVMMDevPort();
1472 if (pDevPort)
1473 {
1474 int vrc = pDevPort->pfnSetCredentials(m_pVMMDev->getVMMDevPort(), pszUser, pszPassword, pszDomain, u32GuestFlags);
1475 AssertRC(vrc);
1476 }
1477 }
1478
1479 return VINF_SUCCESS;
1480}
1481
1482void Console::i_VRDPClientStatusChange(uint32_t u32ClientId, const char *pszStatus)
1483{
1484 LogFlowFuncEnter();
1485
1486 AutoCaller autoCaller(this);
1487 AssertComRCReturnVoid(autoCaller.hrc());
1488
1489 LogFlowFunc(("%s\n", pszStatus));
1490
1491#ifdef VBOX_WITH_GUEST_PROPS
1492 /* Parse the status string. */
1493 if (RTStrICmp(pszStatus, "ATTACH") == 0)
1494 {
1495 i_guestPropertiesVRDPUpdateClientAttach(u32ClientId, true);
1496 }
1497 else if (RTStrICmp(pszStatus, "DETACH") == 0)
1498 {
1499 i_guestPropertiesVRDPUpdateClientAttach(u32ClientId, false);
1500 }
1501 else if (RTStrNICmp(pszStatus, "NAME=", strlen("NAME=")) == 0)
1502 {
1503 i_guestPropertiesVRDPUpdateNameChange(u32ClientId, pszStatus + strlen("NAME="));
1504 }
1505 else if (RTStrNICmp(pszStatus, "CIPA=", strlen("CIPA=")) == 0)
1506 {
1507 i_guestPropertiesVRDPUpdateIPAddrChange(u32ClientId, pszStatus + strlen("CIPA="));
1508 }
1509 else if (RTStrNICmp(pszStatus, "CLOCATION=", strlen("CLOCATION=")) == 0)
1510 {
1511 i_guestPropertiesVRDPUpdateLocationChange(u32ClientId, pszStatus + strlen("CLOCATION="));
1512 }
1513 else if (RTStrNICmp(pszStatus, "COINFO=", strlen("COINFO=")) == 0)
1514 {
1515 i_guestPropertiesVRDPUpdateOtherInfoChange(u32ClientId, pszStatus + strlen("COINFO="));
1516 }
1517#endif
1518
1519 LogFlowFuncLeave();
1520}
1521
1522void Console::i_VRDPClientConnect(uint32_t u32ClientId)
1523{
1524 LogFlowFuncEnter();
1525
1526 AutoCaller autoCaller(this);
1527 AssertComRCReturnVoid(autoCaller.hrc());
1528
1529 uint32_t u32Clients = ASMAtomicIncU32(&mcVRDPClients);
1530 VMMDev *pDev;
1531 PPDMIVMMDEVPORT pPort;
1532 if ( (u32Clients == 1)
1533 && ((pDev = i_getVMMDev()))
1534 && ((pPort = pDev->getVMMDevPort()))
1535 )
1536 {
1537 pPort->pfnVRDPChange(pPort,
1538 true,
1539 VRDP_EXPERIENCE_LEVEL_FULL); /** @todo configurable */
1540 }
1541
1542 NOREF(u32ClientId);
1543 mDisplay->i_VRDPConnectionEvent(true);
1544
1545#ifdef VBOX_WITH_GUEST_PROPS
1546 i_guestPropertiesVRDPUpdateActiveClient(u32ClientId);
1547#endif /* VBOX_WITH_GUEST_PROPS */
1548
1549 LogFlowFuncLeave();
1550 return;
1551}
1552
1553void Console::i_VRDPClientDisconnect(uint32_t u32ClientId,
1554 uint32_t fu32Intercepted)
1555{
1556 LogFlowFuncEnter();
1557
1558 AutoCaller autoCaller(this);
1559 AssertComRCReturnVoid(autoCaller.hrc());
1560
1561 AssertReturnVoid(mConsoleVRDPServer);
1562
1563 uint32_t u32Clients = ASMAtomicDecU32(&mcVRDPClients);
1564 VMMDev *pDev;
1565 PPDMIVMMDEVPORT pPort;
1566
1567 if ( (u32Clients == 0)
1568 && ((pDev = i_getVMMDev()))
1569 && ((pPort = pDev->getVMMDevPort()))
1570 )
1571 {
1572 pPort->pfnVRDPChange(pPort,
1573 false,
1574 0);
1575 }
1576
1577 mDisplay->i_VRDPConnectionEvent(false);
1578
1579 if (fu32Intercepted & VRDE_CLIENT_INTERCEPT_USB)
1580 {
1581 mConsoleVRDPServer->USBBackendDelete(u32ClientId);
1582 }
1583
1584 if (fu32Intercepted & VRDE_CLIENT_INTERCEPT_CLIPBOARD)
1585 {
1586 mConsoleVRDPServer->ClipboardDelete(u32ClientId);
1587 }
1588
1589#ifdef VBOX_WITH_AUDIO_VRDE
1590 if (fu32Intercepted & VRDE_CLIENT_INTERCEPT_AUDIO)
1591 {
1592 if (mAudioVRDE)
1593 mAudioVRDE->onVRDEControl(false /* fEnable */, 0 /* uFlags */);
1594 }
1595#endif
1596
1597 AuthType_T authType = AuthType_Null;
1598 HRESULT hrc = mVRDEServer->COMGETTER(AuthType)(&authType);
1599 AssertComRC(hrc);
1600
1601 if (authType == AuthType_External)
1602 mConsoleVRDPServer->AuthDisconnect(i_getId(), u32ClientId);
1603
1604#ifdef VBOX_WITH_GUEST_PROPS
1605 i_guestPropertiesVRDPUpdateDisconnect(u32ClientId);
1606 if (u32Clients == 0)
1607 i_guestPropertiesVRDPUpdateActiveClient(0);
1608#endif /* VBOX_WITH_GUEST_PROPS */
1609
1610 if (u32Clients == 0)
1611 mcGuestCredentialsProvided = false;
1612
1613 LogFlowFuncLeave();
1614 return;
1615}
1616
1617void Console::i_VRDPInterceptAudio(uint32_t u32ClientId)
1618{
1619 RT_NOREF(u32ClientId);
1620 LogFlowFuncEnter();
1621
1622 AutoCaller autoCaller(this);
1623 AssertComRCReturnVoid(autoCaller.hrc());
1624
1625 LogFlowFunc(("u32ClientId=%RU32\n", u32ClientId));
1626
1627#ifdef VBOX_WITH_AUDIO_VRDE
1628 if (mAudioVRDE)
1629 mAudioVRDE->onVRDEControl(true /* fEnable */, 0 /* uFlags */);
1630#endif
1631
1632 LogFlowFuncLeave();
1633 return;
1634}
1635
1636void Console::i_VRDPInterceptUSB(uint32_t u32ClientId, void **ppvIntercept)
1637{
1638 LogFlowFuncEnter();
1639
1640 AutoCaller autoCaller(this);
1641 AssertComRCReturnVoid(autoCaller.hrc());
1642
1643 AssertReturnVoid(mConsoleVRDPServer);
1644
1645 mConsoleVRDPServer->USBBackendCreate(u32ClientId, ppvIntercept);
1646
1647 LogFlowFuncLeave();
1648 return;
1649}
1650
1651void Console::i_VRDPInterceptClipboard(uint32_t u32ClientId)
1652{
1653 LogFlowFuncEnter();
1654
1655 AutoCaller autoCaller(this);
1656 AssertComRCReturnVoid(autoCaller.hrc());
1657
1658 AssertReturnVoid(mConsoleVRDPServer);
1659
1660 mConsoleVRDPServer->ClipboardCreate(u32ClientId);
1661
1662 LogFlowFuncLeave();
1663 return;
1664}
1665
1666
1667//static
1668const char *Console::sSSMConsoleUnit = "ConsoleData";
1669/** The saved state version. */
1670#define CONSOLE_SAVED_STATE_VERSION UINT32_C(0x00010002)
1671/** The saved state version, pre shared folder autoMountPoint. */
1672#define CONSOLE_SAVED_STATE_VERSION_PRE_AUTO_MOUNT_POINT UINT32_C(0x00010001)
1673
1674inline static const char *networkAdapterTypeToName(NetworkAdapterType_T adapterType)
1675{
1676 switch (adapterType)
1677 {
1678 case NetworkAdapterType_Am79C970A:
1679 case NetworkAdapterType_Am79C973:
1680 case NetworkAdapterType_Am79C960:
1681 return "pcnet";
1682#ifdef VBOX_WITH_E1000
1683 case NetworkAdapterType_I82540EM:
1684 case NetworkAdapterType_I82543GC:
1685 case NetworkAdapterType_I82545EM:
1686 return "e1000";
1687#endif
1688#ifdef VBOX_WITH_VIRTIO
1689 case NetworkAdapterType_Virtio:
1690 return "virtio-net";
1691#endif
1692 case NetworkAdapterType_NE1000:
1693 case NetworkAdapterType_NE2000:
1694 case NetworkAdapterType_WD8003:
1695 case NetworkAdapterType_WD8013:
1696 case NetworkAdapterType_ELNK2:
1697 return "dp8390";
1698 case NetworkAdapterType_ELNK1:
1699 return "3c501";
1700 case NetworkAdapterType_UsbNet:
1701 return "usbnet";
1702 default:
1703 AssertFailed();
1704 return "unknown";
1705 }
1706 /* not reached */
1707}
1708
1709/**
1710 * Loads various console data stored in the saved state file.
1711 *
1712 * This method does validation of the state file and returns an error info
1713 * when appropriate.
1714 *
1715 * The method does nothing if the machine is not in the Saved file or if
1716 * console data from it has already been loaded.
1717 *
1718 * @note The caller must lock this object for writing.
1719 */
1720HRESULT Console::i_loadDataFromSavedState()
1721{
1722 if ( ( mMachineState != MachineState_Saved
1723 && mMachineState != MachineState_AbortedSaved)
1724 || mSavedStateDataLoaded)
1725 return S_OK;
1726
1727 Bstr bstrSavedStateFile;
1728 HRESULT hrc = mMachine->COMGETTER(StateFilePath)(bstrSavedStateFile.asOutParam());
1729 if (SUCCEEDED(hrc))
1730 {
1731 Bstr bstrStateKeyId;
1732 hrc = mMachine->COMGETTER(StateKeyId)(bstrStateKeyId.asOutParam());
1733 if (SUCCEEDED(hrc))
1734 {
1735 Bstr bstrStateKeyStore;
1736 hrc = mMachine->COMGETTER(StateKeyStore)(bstrStateKeyStore.asOutParam());
1737 if (SUCCEEDED(hrc))
1738 {
1739 Utf8Str const strSavedStateFile(bstrSavedStateFile);
1740
1741 PCVMMR3VTABLE pVMM = mpVMM;
1742 AssertPtrReturn(pVMM, E_UNEXPECTED);
1743
1744 PSSMHANDLE pSSM;
1745 SsmStream ssmStream(this, pVMM, m_pKeyStore, bstrStateKeyId, bstrStateKeyStore);
1746
1747 int vrc = ssmStream.open(strSavedStateFile.c_str(), false /*fWrite*/, &pSSM);
1748 if (RT_SUCCESS(vrc))
1749 {
1750 uint32_t uVersion = 0;
1751 vrc = pVMM->pfnSSMR3Seek(pSSM, sSSMConsoleUnit, 0 /* iInstance */, &uVersion);
1752 /** @todo r=bird: This version check is premature, so the logic here is
1753 * buggered as we won't ignore VERR_SSM_UNIT_NOT_FOUND as seems to be
1754 * intended. Sigh. */
1755 if (SSM_VERSION_MAJOR(uVersion) == SSM_VERSION_MAJOR(CONSOLE_SAVED_STATE_VERSION))
1756 {
1757 if (RT_SUCCESS(vrc))
1758 try
1759 {
1760 vrc = i_loadStateFileExecInternal(pSSM, pVMM, uVersion);
1761 }
1762 catch (std::bad_alloc &)
1763 {
1764 vrc = VERR_NO_MEMORY;
1765 }
1766 else if (vrc == VERR_SSM_UNIT_NOT_FOUND)
1767 vrc = VINF_SUCCESS;
1768 }
1769 else
1770 vrc = VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
1771
1772 ssmStream.close();
1773 }
1774
1775 if (RT_FAILURE(vrc))
1776 hrc = setErrorBoth(VBOX_E_FILE_ERROR, vrc,
1777 tr("The saved state file '%s' is invalid (%Rrc). Delete the saved state and try again"),
1778 strSavedStateFile.c_str(), vrc);
1779
1780 mSavedStateDataLoaded = true;
1781 }
1782 }
1783 }
1784
1785 return hrc;
1786}
1787
1788/**
1789 * Callback handler to save various console data to the state file,
1790 * called when the user saves the VM state.
1791 *
1792 * @returns VBox status code.
1793 * @param pSSM SSM handle.
1794 * @param pVMM The VMM ring-3 vtable.
1795 * @param pvUser Pointer to Console
1796 *
1797 * @note Locks the Console object for reading.
1798 */
1799/*static*/ DECLCALLBACK(int)
1800Console::i_saveStateFileExec(PSSMHANDLE pSSM, PCVMMR3VTABLE pVMM, void *pvUser)
1801{
1802 LogFlowFunc(("\n"));
1803
1804 Console *pThat = static_cast<Console *>(pvUser);
1805 AssertReturn(pThat, VERR_INVALID_POINTER);
1806
1807 AutoCaller autoCaller(pThat);
1808 AssertComRCReturn(autoCaller.hrc(), VERR_INVALID_STATE);
1809
1810 AutoReadLock alock(pThat COMMA_LOCKVAL_SRC_POS);
1811
1812 pVMM->pfnSSMR3PutU32(pSSM, (uint32_t)pThat->m_mapSharedFolders.size());
1813
1814 for (SharedFolderMap::const_iterator it = pThat->m_mapSharedFolders.begin();
1815 it != pThat->m_mapSharedFolders.end();
1816 ++it)
1817 {
1818 ConsoleSharedFolder *pSF = (*it).second;
1819 AutoCaller sfCaller(pSF);
1820 AutoReadLock sfLock(pSF COMMA_LOCKVAL_SRC_POS);
1821
1822 const Utf8Str &name = pSF->i_getName();
1823 pVMM->pfnSSMR3PutU32(pSSM, (uint32_t)name.length() + 1 /* term. 0 */);
1824 pVMM->pfnSSMR3PutStrZ(pSSM, name.c_str());
1825
1826 const Utf8Str &hostPath = pSF->i_getHostPath();
1827 pVMM->pfnSSMR3PutU32(pSSM, (uint32_t)hostPath.length() + 1 /* term. 0 */);
1828 pVMM->pfnSSMR3PutStrZ(pSSM, hostPath.c_str());
1829
1830 pVMM->pfnSSMR3PutBool(pSSM, !!pSF->i_isWritable());
1831 pVMM->pfnSSMR3PutBool(pSSM, !!pSF->i_isAutoMounted());
1832
1833 const Utf8Str &rStrAutoMountPoint = pSF->i_getAutoMountPoint();
1834 pVMM->pfnSSMR3PutU32(pSSM, (uint32_t)rStrAutoMountPoint.length() + 1 /* term. 0 */);
1835 pVMM->pfnSSMR3PutStrZ(pSSM, rStrAutoMountPoint.c_str());
1836 }
1837
1838 return VINF_SUCCESS;
1839}
1840
1841/**
1842 * Callback handler to load various console data from the state file.
1843 *
1844 * Called when the VM is being restored from the saved state.
1845 *
1846 * @returns VBox status code.
1847 * @param pSSM SSM handle.
1848 * @param pVMM The VMM ring-3 vtable.
1849 * @param pvUser pointer to Console
1850 * @param uVersion Console unit version. Should match sSSMConsoleVer.
1851 * @param uPass The data pass.
1852 */
1853//static
1854DECLCALLBACK(int)
1855Console::i_loadStateFileExec(PSSMHANDLE pSSM, PCVMMR3VTABLE pVMM, void *pvUser, uint32_t uVersion, uint32_t uPass)
1856{
1857 LogFlowFunc(("uVersion=%#x uPass=%#x\n", uVersion, uPass));
1858 Assert(uPass == SSM_PASS_FINAL); RT_NOREF_PV(uPass);
1859
1860 if (SSM_VERSION_MAJOR_CHANGED(uVersion, CONSOLE_SAVED_STATE_VERSION))
1861 return VERR_VERSION_MISMATCH;
1862
1863 Console *pThat = static_cast<Console *>(pvUser);
1864 AssertReturn(pThat, VERR_INVALID_PARAMETER);
1865
1866 /* Currently, nothing to do when we've been called from VMR3Load*. */
1867 return pVMM->pfnSSMR3SkipToEndOfUnit(pSSM);
1868}
1869
1870/**
1871 * Method to load various console data from the state file.
1872 *
1873 * Called from #i_loadDataFromSavedState.
1874 *
1875 * @param pSSM SSM handle.
1876 * @param pVMM The VMM vtable.
1877 * @param u32Version Console unit version.
1878 * Should match sSSMConsoleVer.
1879 *
1880 * @note Locks the Console object for writing.
1881 */
1882int Console::i_loadStateFileExecInternal(PSSMHANDLE pSSM, PCVMMR3VTABLE pVMM, uint32_t u32Version)
1883{
1884 AutoCaller autoCaller(this);
1885 AssertComRCReturn(autoCaller.hrc(), VERR_ACCESS_DENIED);
1886
1887 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1888
1889 AssertReturn(m_mapSharedFolders.empty(), VERR_INTERNAL_ERROR);
1890
1891 uint32_t size = 0;
1892 int vrc = pVMM->pfnSSMR3GetU32(pSSM, &size);
1893 AssertRCReturn(vrc, vrc);
1894
1895 for (uint32_t i = 0; i < size; ++i)
1896 {
1897 Utf8Str strName;
1898 Utf8Str strHostPath;
1899 bool writable = true;
1900 bool autoMount = false;
1901
1902 uint32_t cbStr = 0;
1903 char *buf = NULL;
1904
1905 vrc = pVMM->pfnSSMR3GetU32(pSSM, &cbStr);
1906 AssertRCReturn(vrc, vrc);
1907 buf = new char[cbStr];
1908 vrc = pVMM->pfnSSMR3GetStrZ(pSSM, buf, cbStr);
1909 AssertRC(vrc);
1910 strName = buf;
1911 delete[] buf;
1912
1913 vrc = pVMM->pfnSSMR3GetU32(pSSM, &cbStr);
1914 AssertRCReturn(vrc, vrc);
1915 buf = new char[cbStr];
1916 vrc = pVMM->pfnSSMR3GetStrZ(pSSM, buf, cbStr);
1917 AssertRC(vrc);
1918 strHostPath = buf;
1919 delete[] buf;
1920
1921 if (u32Version >= CONSOLE_SAVED_STATE_VERSION_PRE_AUTO_MOUNT_POINT)
1922 pVMM->pfnSSMR3GetBool(pSSM, &writable);
1923
1924 if ( u32Version >= CONSOLE_SAVED_STATE_VERSION_PRE_AUTO_MOUNT_POINT
1925#ifndef VBOX_OSE /* This broke saved state when introduced in r63916 (4.0). */
1926 && pVMM->pfnSSMR3HandleRevision(pSSM) >= 63916
1927#endif
1928 )
1929 pVMM->pfnSSMR3GetBool(pSSM, &autoMount);
1930
1931 Utf8Str strAutoMountPoint;
1932 if (u32Version >= CONSOLE_SAVED_STATE_VERSION)
1933 {
1934 vrc = pVMM->pfnSSMR3GetU32(pSSM, &cbStr);
1935 AssertRCReturn(vrc, vrc);
1936 vrc = strAutoMountPoint.reserveNoThrow(cbStr);
1937 AssertRCReturn(vrc, vrc);
1938 vrc = pVMM->pfnSSMR3GetStrZ(pSSM, strAutoMountPoint.mutableRaw(), cbStr);
1939 AssertRCReturn(vrc, vrc);
1940 strAutoMountPoint.jolt();
1941 }
1942
1943 ComObjPtr<ConsoleSharedFolder> pSharedFolder;
1944 pSharedFolder.createObject();
1945 HRESULT hrc = pSharedFolder->init(this,
1946 strName,
1947 strHostPath,
1948 writable,
1949 autoMount,
1950 strAutoMountPoint,
1951 false /* fFailOnError */);
1952 AssertComRCReturn(hrc, VERR_INTERNAL_ERROR);
1953
1954 m_mapSharedFolders.insert(std::make_pair(strName, pSharedFolder));
1955 }
1956
1957 return VINF_SUCCESS;
1958}
1959
1960#ifdef VBOX_WITH_GUEST_PROPS
1961
1962// static
1963DECLCALLBACK(int) Console::i_doGuestPropNotification(void *pvExtension,
1964 uint32_t u32Function,
1965 void *pvParms,
1966 uint32_t cbParms)
1967{
1968 Assert(u32Function == 0); NOREF(u32Function);
1969
1970 /*
1971 * No locking, as this is purely a notification which does not make any
1972 * changes to the object state.
1973 */
1974 PGUESTPROPHOSTCALLBACKDATA pCBData = reinterpret_cast<PGUESTPROPHOSTCALLBACKDATA>(pvParms);
1975 AssertReturn(sizeof(GUESTPROPHOSTCALLBACKDATA) == cbParms, VERR_INVALID_PARAMETER);
1976 AssertReturn(pCBData->u32Magic == GUESTPROPHOSTCALLBACKDATA_MAGIC, VERR_INVALID_PARAMETER);
1977 LogFlow(("Console::doGuestPropNotification: pCBData={.pcszName=%s, .pcszValue=%s, .pcszFlags=%s}\n",
1978 pCBData->pcszName, pCBData->pcszValue, pCBData->pcszFlags));
1979
1980 Bstr name(pCBData->pcszName);
1981 Bstr value(pCBData->pcszValue);
1982 Bstr flags(pCBData->pcszFlags);
1983 BOOL fWasDeleted = !pCBData->pcszValue;
1984 ComObjPtr<Console> pConsole = reinterpret_cast<Console *>(pvExtension);
1985 HRESULT hrc = pConsole->mControl->PushGuestProperty(name.raw(),
1986 value.raw(),
1987 pCBData->u64Timestamp,
1988 flags.raw(),
1989 fWasDeleted);
1990 if (SUCCEEDED(hrc))
1991 {
1992 ::FireGuestPropertyChangedEvent(pConsole->mEventSource, pConsole->i_getId().raw(), name.raw(), value.raw(), flags.raw(),
1993 fWasDeleted);
1994 return VINF_SUCCESS;
1995 }
1996 LogFlow(("Console::doGuestPropNotification: hrc=%Rhrc pCBData={.pcszName=%s, .pcszValue=%s, .pcszFlags=%s}\n",
1997 hrc, pCBData->pcszName, pCBData->pcszValue, pCBData->pcszFlags));
1998 return Global::vboxStatusCodeFromCOM(hrc);
1999}
2000
2001HRESULT Console::i_doEnumerateGuestProperties(const Utf8Str &aPatterns,
2002 std::vector<Utf8Str> &aNames,
2003 std::vector<Utf8Str> &aValues,
2004 std::vector<LONG64> &aTimestamps,
2005 std::vector<Utf8Str> &aFlags)
2006{
2007 AssertReturn(m_pVMMDev, E_FAIL);
2008
2009 VBOXHGCMSVCPARM parm[3];
2010 parm[0].type = VBOX_HGCM_SVC_PARM_PTR;
2011 parm[0].u.pointer.addr = (void*)aPatterns.c_str();
2012 parm[0].u.pointer.size = (uint32_t)aPatterns.length() + 1;
2013
2014 /*
2015 * Now things get slightly complicated. Due to a race with the guest adding
2016 * properties, there is no good way to know how much to enlarge a buffer for
2017 * the service to enumerate into. We choose a decent starting size and loop a
2018 * few times, each time retrying with the size suggested by the service plus
2019 * one Kb.
2020 */
2021 size_t cchBuf = 4096;
2022 Utf8Str Utf8Buf;
2023 int vrc = VERR_BUFFER_OVERFLOW;
2024 for (unsigned i = 0; i < 10 && (VERR_BUFFER_OVERFLOW == vrc); ++i)
2025 {
2026 try
2027 {
2028 Utf8Buf.reserve(cchBuf + 1024);
2029 }
2030 catch(...)
2031 {
2032 return E_OUTOFMEMORY;
2033 }
2034
2035 parm[1].type = VBOX_HGCM_SVC_PARM_PTR;
2036 parm[1].u.pointer.addr = Utf8Buf.mutableRaw();
2037 parm[1].u.pointer.size = (uint32_t)cchBuf + 1024;
2038
2039 parm[2].type = VBOX_HGCM_SVC_PARM_32BIT;
2040 parm[2].u.uint32 = 0;
2041
2042 vrc = m_pVMMDev->hgcmHostCall("VBoxGuestPropSvc", GUEST_PROP_FN_HOST_ENUM_PROPS, 3, &parm[0]);
2043 Utf8Buf.jolt();
2044 if (parm[2].type != VBOX_HGCM_SVC_PARM_32BIT)
2045 return setErrorBoth(E_FAIL, vrc, tr("Internal application error"));
2046 cchBuf = parm[2].u.uint32;
2047 }
2048 if (vrc == VERR_BUFFER_OVERFLOW)
2049 return setError(E_UNEXPECTED, tr("Temporary failure due to guest activity, please retry"));
2050
2051 /*
2052 * Finally we have to unpack the data returned by the service into the safe
2053 * arrays supplied by the caller. We start by counting the number of entries.
2054 */
2055 const char *pszBuf
2056 = reinterpret_cast<const char *>(parm[1].u.pointer.addr);
2057 unsigned cEntries = 0;
2058 /* The list is terminated by a zero-length string at the end of a set
2059 * of four strings. */
2060 for (size_t i = 0; strlen(pszBuf + i) != 0; )
2061 {
2062 /* We are counting sets of four strings. */
2063 for (unsigned j = 0; j < 4; ++j)
2064 i += strlen(pszBuf + i) + 1;
2065 ++cEntries;
2066 }
2067
2068 aNames.resize(cEntries);
2069 aValues.resize(cEntries);
2070 aTimestamps.resize(cEntries);
2071 aFlags.resize(cEntries);
2072
2073 size_t iBuf = 0;
2074 /* Rely on the service to have formated the data correctly. */
2075 for (unsigned i = 0; i < cEntries; ++i)
2076 {
2077 size_t cchName = strlen(pszBuf + iBuf);
2078 aNames[i] = &pszBuf[iBuf];
2079 iBuf += cchName + 1;
2080
2081 size_t cchValue = strlen(pszBuf + iBuf);
2082 aValues[i] = &pszBuf[iBuf];
2083 iBuf += cchValue + 1;
2084
2085 size_t cchTimestamp = strlen(pszBuf + iBuf);
2086 aTimestamps[i] = RTStrToUInt64(&pszBuf[iBuf]);
2087 iBuf += cchTimestamp + 1;
2088
2089 size_t cchFlags = strlen(pszBuf + iBuf);
2090 aFlags[i] = &pszBuf[iBuf];
2091 iBuf += cchFlags + 1;
2092 }
2093
2094 return S_OK;
2095}
2096
2097#endif /* VBOX_WITH_GUEST_PROPS */
2098
2099
2100// IConsole properties
2101/////////////////////////////////////////////////////////////////////////////
2102HRESULT Console::getMachine(ComPtr<IMachine> &aMachine)
2103{
2104 /* mMachine is constant during life time, no need to lock */
2105 mMachine.queryInterfaceTo(aMachine.asOutParam());
2106
2107 /* callers expect to get a valid reference, better fail than crash them */
2108 if (mMachine.isNull())
2109 return E_FAIL;
2110
2111 return S_OK;
2112}
2113
2114HRESULT Console::getState(MachineState_T *aState)
2115{
2116 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
2117
2118 /* we return our local state (since it's always the same as on the server) */
2119 *aState = mMachineState;
2120
2121 return S_OK;
2122}
2123
2124HRESULT Console::getGuest(ComPtr<IGuest> &aGuest)
2125{
2126 /* mGuest is constant during life time, no need to lock */
2127 mGuest.queryInterfaceTo(aGuest.asOutParam());
2128
2129 return S_OK;
2130}
2131
2132HRESULT Console::getKeyboard(ComPtr<IKeyboard> &aKeyboard)
2133{
2134 /* mKeyboard is constant during life time, no need to lock */
2135 mKeyboard.queryInterfaceTo(aKeyboard.asOutParam());
2136
2137 return S_OK;
2138}
2139
2140HRESULT Console::getMouse(ComPtr<IMouse> &aMouse)
2141{
2142 /* mMouse is constant during life time, no need to lock */
2143 mMouse.queryInterfaceTo(aMouse.asOutParam());
2144
2145 return S_OK;
2146}
2147
2148HRESULT Console::getDisplay(ComPtr<IDisplay> &aDisplay)
2149{
2150 /* mDisplay is constant during life time, no need to lock */
2151 mDisplay.queryInterfaceTo(aDisplay.asOutParam());
2152
2153 return S_OK;
2154}
2155
2156HRESULT Console::getDebugger(ComPtr<IMachineDebugger> &aDebugger)
2157{
2158 /* we need a write lock because of the lazy mDebugger initialization*/
2159 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2160
2161 /* check if we have to create the debugger object */
2162 if (!mDebugger)
2163 {
2164 unconst(mDebugger).createObject();
2165 mDebugger->init(this);
2166 }
2167
2168 mDebugger.queryInterfaceTo(aDebugger.asOutParam());
2169
2170 return S_OK;
2171}
2172
2173HRESULT Console::getUSBDevices(std::vector<ComPtr<IUSBDevice> > &aUSBDevices)
2174{
2175 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
2176
2177 size_t i = 0;
2178 aUSBDevices.resize(mUSBDevices.size());
2179 for (USBDeviceList::const_iterator it = mUSBDevices.begin(); it != mUSBDevices.end(); ++i, ++it)
2180 (*it).queryInterfaceTo(aUSBDevices[i].asOutParam());
2181
2182 return S_OK;
2183}
2184
2185
2186HRESULT Console::getRemoteUSBDevices(std::vector<ComPtr<IHostUSBDevice> > &aRemoteUSBDevices)
2187{
2188 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
2189
2190 size_t i = 0;
2191 aRemoteUSBDevices.resize(mRemoteUSBDevices.size());
2192 for (RemoteUSBDeviceList::const_iterator it = mRemoteUSBDevices.begin(); it != mRemoteUSBDevices.end(); ++i, ++it)
2193 (*it).queryInterfaceTo(aRemoteUSBDevices[i].asOutParam());
2194
2195 return S_OK;
2196}
2197
2198HRESULT Console::getVRDEServerInfo(ComPtr<IVRDEServerInfo> &aVRDEServerInfo)
2199{
2200 /* mVRDEServerInfo is constant during life time, no need to lock */
2201 mVRDEServerInfo.queryInterfaceTo(aVRDEServerInfo.asOutParam());
2202
2203 return S_OK;
2204}
2205
2206HRESULT Console::getEmulatedUSB(ComPtr<IEmulatedUSB> &aEmulatedUSB)
2207{
2208 /* mEmulatedUSB is constant during life time, no need to lock */
2209 mEmulatedUSB.queryInterfaceTo(aEmulatedUSB.asOutParam());
2210
2211 return S_OK;
2212}
2213
2214HRESULT Console::getSharedFolders(std::vector<ComPtr<ISharedFolder> > &aSharedFolders)
2215{
2216 /* loadDataFromSavedState() needs a write lock */
2217 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2218
2219 /* Read console data stored in the saved state file (if not yet done) */
2220 HRESULT hrc = i_loadDataFromSavedState();
2221 if (FAILED(hrc))
2222 return hrc;
2223
2224 size_t i = 0;
2225 aSharedFolders.resize(m_mapSharedFolders.size());
2226 for (SharedFolderMap::const_iterator it = m_mapSharedFolders.begin(); it != m_mapSharedFolders.end(); ++i, ++it)
2227 (it)->second.queryInterfaceTo(aSharedFolders[i].asOutParam());
2228
2229 return S_OK;
2230}
2231
2232HRESULT Console::getEventSource(ComPtr<IEventSource> &aEventSource)
2233{
2234 // no need to lock - lifetime constant
2235 mEventSource.queryInterfaceTo(aEventSource.asOutParam());
2236
2237 return S_OK;
2238}
2239
2240HRESULT Console::getAttachedPCIDevices(std::vector<ComPtr<IPCIDeviceAttachment> > &aAttachedPCIDevices)
2241{
2242 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
2243
2244 if (mBusMgr)
2245 {
2246 std::vector<BusAssignmentManager::PCIDeviceInfo> devInfos;
2247 mBusMgr->listAttachedPCIDevices(devInfos);
2248 ComObjPtr<PCIDeviceAttachment> dev;
2249 aAttachedPCIDevices.resize(devInfos.size());
2250 for (size_t i = 0; i < devInfos.size(); i++)
2251 {
2252 const BusAssignmentManager::PCIDeviceInfo &devInfo = devInfos[i];
2253 dev.createObject();
2254 dev->init(NULL, devInfo.strDeviceName,
2255 devInfo.hostAddress.valid() ? devInfo.hostAddress.asLong() : -1,
2256 devInfo.guestAddress.asLong(),
2257 devInfo.hostAddress.valid());
2258 dev.queryInterfaceTo(aAttachedPCIDevices[i].asOutParam());
2259 }
2260 }
2261 else
2262 aAttachedPCIDevices.resize(0);
2263
2264 return S_OK;
2265}
2266
2267HRESULT Console::getUseHostClipboard(BOOL *aUseHostClipboard)
2268{
2269 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
2270
2271 *aUseHostClipboard = mfUseHostClipboard;
2272
2273 return S_OK;
2274}
2275
2276HRESULT Console::setUseHostClipboard(BOOL aUseHostClipboard)
2277{
2278 if (mfUseHostClipboard != RT_BOOL(aUseHostClipboard))
2279 {
2280 mfUseHostClipboard = RT_BOOL(aUseHostClipboard);
2281 LogRel(("Shared Clipboard: %s using host clipboard\n", mfUseHostClipboard ? "Enabled" : "Disabled"));
2282 }
2283
2284 return S_OK;
2285}
2286
2287// IConsole methods
2288/////////////////////////////////////////////////////////////////////////////
2289
2290HRESULT Console::powerUp(ComPtr<IProgress> &aProgress)
2291{
2292 return i_powerUp(aProgress.asOutParam(), false /* aPaused */);
2293}
2294
2295HRESULT Console::powerUpPaused(ComPtr<IProgress> &aProgress)
2296{
2297 return i_powerUp(aProgress.asOutParam(), true /* aPaused */);
2298}
2299
2300HRESULT Console::powerDown(ComPtr<IProgress> &aProgress)
2301{
2302 LogFlowThisFuncEnter();
2303
2304 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2305
2306 LogFlowThisFunc(("mMachineState=%d\n", mMachineState));
2307 switch (mMachineState)
2308 {
2309 case MachineState_Running:
2310 case MachineState_Paused:
2311 case MachineState_Stuck:
2312 break;
2313
2314 /* Try cancel the save state. */
2315 case MachineState_Saving:
2316 if (!mptrCancelableProgress.isNull())
2317 {
2318 HRESULT hrc = mptrCancelableProgress->Cancel();
2319 if (SUCCEEDED(hrc))
2320 break;
2321 }
2322 return setError(VBOX_E_INVALID_VM_STATE, tr("Cannot power down at this point during a save state"));
2323
2324 /* Try cancel the teleportation. */
2325 case MachineState_Teleporting:
2326 case MachineState_TeleportingPausedVM:
2327 if (!mptrCancelableProgress.isNull())
2328 {
2329 HRESULT hrc = mptrCancelableProgress->Cancel();
2330 if (SUCCEEDED(hrc))
2331 break;
2332 }
2333 return setError(VBOX_E_INVALID_VM_STATE, tr("Cannot power down at this point in a teleportation"));
2334
2335 /* Try cancel the online snapshot. */
2336 case MachineState_OnlineSnapshotting:
2337 if (!mptrCancelableProgress.isNull())
2338 {
2339 HRESULT hrc = mptrCancelableProgress->Cancel();
2340 if (SUCCEEDED(hrc))
2341 break;
2342 }
2343 return setError(VBOX_E_INVALID_VM_STATE, tr("Cannot power down at this point in an online snapshot"));
2344
2345 /* Try cancel the live snapshot. */
2346 case MachineState_LiveSnapshotting:
2347 if (!mptrCancelableProgress.isNull())
2348 {
2349 HRESULT hrc = mptrCancelableProgress->Cancel();
2350 if (SUCCEEDED(hrc))
2351 break;
2352 }
2353 return setError(VBOX_E_INVALID_VM_STATE, tr("Cannot power down at this point in a live snapshot"));
2354
2355 /* extra nice error message for a common case */
2356 case MachineState_Saved:
2357 case MachineState_AbortedSaved:
2358 return setError(VBOX_E_INVALID_VM_STATE, tr("Cannot power down a saved virtual machine"));
2359 case MachineState_Stopping:
2360 return setError(VBOX_E_INVALID_VM_STATE, tr("The virtual machine is being powered down"));
2361 default:
2362 return setError(VBOX_E_INVALID_VM_STATE,
2363 tr("Invalid machine state: %s (must be Running, Paused or Stuck)"),
2364 Global::stringifyMachineState(mMachineState));
2365 }
2366 LogFlowThisFunc(("Initiating SHUTDOWN request...\n"));
2367
2368 /* memorize the current machine state */
2369 MachineState_T lastMachineState = mMachineState;
2370
2371#ifdef VBOX_WITH_GUEST_PROPS
2372 if (mfTurnResetIntoPowerOff)
2373 {
2374 alock.release(); /** @todo r=bird: This code introduces a race condition wrt to the state. This must be done elsewhere! */
2375 mMachine->DeleteGuestProperty(Bstr("/VirtualBox/HostInfo/VMPowerOffReason").raw());
2376 mMachine->SetGuestProperty(Bstr("/VirtualBox/HostInfo/VMPowerOffReason").raw(),
2377 Bstr("PowerOff").raw(), Bstr("RDONLYGUEST").raw());
2378 mMachine->SaveSettings();
2379 alock.acquire();
2380 }
2381#endif
2382
2383 /*
2384 * Request a progress object from the server (this will set the machine state
2385 * to Stopping on the server to block others from accessing this machine).
2386 */
2387 ComPtr<IProgress> ptrProgress;
2388 HRESULT hrc = mControl->BeginPoweringDown(ptrProgress.asOutParam());
2389 if (SUCCEEDED(hrc))
2390 {
2391 /* Sync the state with the server: */
2392 i_setMachineStateLocally(MachineState_Stopping);
2393
2394 /* Create the power down task: */
2395 VMPowerDownTask *pTask = NULL;
2396 try
2397 {
2398 pTask = new VMPowerDownTask(this, ptrProgress);
2399 if (!pTask->isOk())
2400 {
2401 hrc = setError(FAILED(pTask->hrc()) ? pTask->hrc() : E_FAIL, tr("Could not create VMPowerDownTask object\n"));
2402 delete(pTask);
2403 pTask = NULL;
2404 }
2405 }
2406 catch (std::bad_alloc &)
2407 {
2408 hrc = E_OUTOFMEMORY;
2409 }
2410 if (SUCCEEDED(hrc))
2411 {
2412 hrc = pTask->createThread();
2413 if (SUCCEEDED(hrc))
2414 {
2415 ptrProgress.queryInterfaceTo(aProgress.asOutParam());
2416 LogFlowThisFunc(("LEAVE: hrc=%Rhrc\n", hrc));
2417 return hrc;
2418 }
2419 }
2420
2421 /*
2422 * Cancel the requested power down procedure.
2423 * This will reset the machine state to the state it had right
2424 * before calling mControl->BeginPoweringDown().
2425 */
2426 ErrorInfoKeeper eik;
2427 mControl->EndPoweringDown(eik.getResultCode(), eik.getText().raw());
2428 i_setMachineStateLocally(lastMachineState);
2429 }
2430 LogFlowThisFunc(("LEAVE: hrc=%Rhrc\n", hrc));
2431 return hrc;
2432}
2433
2434HRESULT Console::reset()
2435{
2436 LogFlowThisFuncEnter();
2437
2438 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2439
2440 LogFlowThisFunc(("mMachineState=%d\n", mMachineState));
2441 if ( mMachineState != MachineState_Running
2442 && mMachineState != MachineState_Teleporting
2443 && mMachineState != MachineState_LiveSnapshotting
2444 /** @todo r=bird: This should be allowed on paused VMs as well. Later. */
2445 )
2446 return i_setInvalidMachineStateError();
2447
2448 /* protect mpUVM */
2449 SafeVMPtr ptrVM(this);
2450 HRESULT hrc = ptrVM.hrc();
2451 if (SUCCEEDED(hrc))
2452 {
2453 /* release the lock before a VMR3* call (EMT might wait for it, @bugref{7648})! */
2454 alock.release();
2455
2456 int vrc = ptrVM.vtable()->pfnVMR3Reset(ptrVM.rawUVM());
2457
2458 hrc = RT_SUCCESS(vrc) ? S_OK : setErrorBoth(VBOX_E_VM_ERROR, vrc, tr("Could not reset the machine (%Rrc)"), vrc);
2459 }
2460
2461 LogFlowThisFunc(("mMachineState=%d, hrc=%Rhrc\n", mMachineState, hrc));
2462 LogFlowThisFuncLeave();
2463 return hrc;
2464}
2465
2466/*static*/ DECLCALLBACK(int) Console::i_unplugCpu(Console *pThis, PUVM pUVM, PCVMMR3VTABLE pVMM, VMCPUID idCpu)
2467{
2468 LogFlowFunc(("pThis=%p pVM=%p idCpu=%u\n", pThis, pUVM, idCpu));
2469
2470 AssertReturn(pThis, VERR_INVALID_PARAMETER);
2471
2472 int vrc = pVMM->pfnPDMR3DeviceDetach(pUVM, "acpi", 0, idCpu, 0);
2473 Log(("UnplugCpu: vrc=%Rrc\n", vrc));
2474
2475 return vrc;
2476}
2477
2478HRESULT Console::i_doCPURemove(ULONG aCpu, PUVM pUVM, PCVMMR3VTABLE pVMM)
2479{
2480 LogFlowThisFuncEnter();
2481
2482 AutoCaller autoCaller(this);
2483 HRESULT hrc = autoCaller.hrc();
2484 if (FAILED(hrc))
2485 return hrc;
2486
2487 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2488
2489 LogFlowThisFunc(("mMachineState=%d\n", mMachineState));
2490 AssertReturn(m_pVMMDev, E_FAIL);
2491 PPDMIVMMDEVPORT pVmmDevPort = m_pVMMDev->getVMMDevPort();
2492 AssertReturn(pVmmDevPort, E_FAIL);
2493
2494 if ( mMachineState != MachineState_Running
2495 && mMachineState != MachineState_Teleporting
2496 && mMachineState != MachineState_LiveSnapshotting
2497 )
2498 return i_setInvalidMachineStateError();
2499
2500 /* Check if the CPU is present */
2501 BOOL fCpuAttached;
2502 hrc = mMachine->GetCPUStatus(aCpu, &fCpuAttached);
2503 if (FAILED(hrc))
2504 return hrc;
2505 if (!fCpuAttached)
2506 return setError(E_FAIL, tr("CPU %d is not attached"), aCpu);
2507
2508 /* Leave the lock before any EMT/VMMDev call. */
2509 alock.release();
2510 bool fLocked = true;
2511
2512 /* Check if the CPU is unlocked */
2513 PPDMIBASE pBase;
2514 int vrc = pVMM->pfnPDMR3QueryDeviceLun(pUVM, "acpi", 0, aCpu, &pBase);
2515 if (RT_SUCCESS(vrc))
2516 {
2517 Assert(pBase);
2518 PPDMIACPIPORT pApicPort = PDMIBASE_QUERY_INTERFACE(pBase, PDMIACPIPORT);
2519
2520 /* Notify the guest if possible. */
2521 uint32_t idCpuCore, idCpuPackage;
2522 vrc = pVMM->pfnVMR3GetCpuCoreAndPackageIdFromCpuId(pUVM, aCpu, &idCpuCore, &idCpuPackage); AssertRC(vrc);
2523 if (RT_SUCCESS(vrc))
2524 vrc = pVmmDevPort->pfnCpuHotUnplug(pVmmDevPort, idCpuCore, idCpuPackage);
2525 if (RT_SUCCESS(vrc))
2526 {
2527 unsigned cTries = 100;
2528 do
2529 {
2530 /* It will take some time until the event is processed in the guest. Wait... */
2531 vrc = pApicPort ? pApicPort->pfnGetCpuStatus(pApicPort, aCpu, &fLocked) : VERR_INVALID_POINTER;
2532 if (RT_SUCCESS(vrc) && !fLocked)
2533 break;
2534
2535 /* Sleep a bit */
2536 RTThreadSleep(100);
2537 } while (cTries-- > 0);
2538 }
2539 else if (vrc == VERR_VMMDEV_CPU_HOTPLUG_NOT_MONITORED_BY_GUEST)
2540 {
2541 /* Query one time. It is possible that the user ejected the CPU. */
2542 vrc = pApicPort ? pApicPort->pfnGetCpuStatus(pApicPort, aCpu, &fLocked) : VERR_INVALID_POINTER;
2543 }
2544 }
2545
2546 /* If the CPU was unlocked we can detach it now. */
2547 if (RT_SUCCESS(vrc) && !fLocked)
2548 {
2549 /*
2550 * Call worker on EMT #0, that's faster and safer than doing everything
2551 * using VMR3ReqCall.
2552 */
2553 PVMREQ pReq;
2554 vrc = pVMM->pfnVMR3ReqCallU(pUVM, 0, &pReq, 0 /* no wait! */, VMREQFLAGS_VBOX_STATUS, (PFNRT)i_unplugCpu, 4,
2555 this, pUVM, pVMM, (VMCPUID)aCpu);
2556
2557 if (vrc == VERR_TIMEOUT)
2558 vrc = pVMM->pfnVMR3ReqWait(pReq, RT_INDEFINITE_WAIT);
2559 AssertRC(vrc);
2560 if (RT_SUCCESS(vrc))
2561 vrc = pReq->iStatus;
2562 pVMM->pfnVMR3ReqFree(pReq);
2563
2564 if (RT_SUCCESS(vrc))
2565 {
2566 /* Detach it from the VM */
2567 vrc = pVMM->pfnVMR3HotUnplugCpu(pUVM, aCpu);
2568 AssertRC(vrc);
2569 }
2570 else
2571 hrc = setErrorBoth(VBOX_E_VM_ERROR, vrc, tr("Hot-Remove failed (vrc=%Rrc)"), vrc);
2572 }
2573 else
2574 hrc = setErrorBoth(VBOX_E_VM_ERROR, VERR_RESOURCE_BUSY,
2575 tr("Hot-Remove was aborted because the CPU may still be used by the guest"), VERR_RESOURCE_BUSY);
2576
2577 LogFlowThisFunc(("mMachineState=%d, hrc=%Rhrc\n", mMachineState, hrc));
2578 LogFlowThisFuncLeave();
2579 return hrc;
2580}
2581
2582/*static*/ DECLCALLBACK(int) Console::i_plugCpu(Console *pThis, PUVM pUVM, PCVMMR3VTABLE pVMM, VMCPUID idCpu)
2583{
2584 LogFlowFunc(("pThis=%p uCpu=%u\n", pThis, idCpu));
2585 RT_NOREF(pThis);
2586
2587 int vrc = pVMM->pfnVMR3HotPlugCpu(pUVM, idCpu);
2588 AssertRC(vrc);
2589
2590 /** @todo r=bird: Error handling here just sucks. */
2591
2592 PCFGMNODE pInst = pVMM->pfnCFGMR3GetChild(pVMM->pfnCFGMR3GetRootU(pUVM), "Devices/acpi/0/");
2593 AssertRelease(pInst);
2594 /* nuke anything which might have been left behind. */
2595 pVMM->pfnCFGMR3RemoveNode(pVMM->pfnCFGMR3GetChildF(pInst, "LUN#%u", idCpu));
2596
2597#define RC_CHECK() do { AssertReleaseRC(vrc); } while (0)
2598
2599 PCFGMNODE pLunL0;
2600 PCFGMNODE pCfg;
2601 vrc = pVMM->pfnCFGMR3InsertNodeF(pInst, &pLunL0, "LUN#%u", idCpu); RC_CHECK();
2602 vrc = pVMM->pfnCFGMR3InsertString(pLunL0, "Driver", "ACPICpu"); RC_CHECK();
2603 vrc = pVMM->pfnCFGMR3InsertNode(pLunL0, "Config", &pCfg); RC_CHECK();
2604
2605 /*
2606 * Attach the driver.
2607 */
2608 PPDMIBASE pBase;
2609 vrc = pVMM->pfnPDMR3DeviceAttach(pUVM, "acpi", 0, idCpu, 0, &pBase); RC_CHECK();
2610
2611 Log(("PlugCpu: vrc=%Rrc\n", vrc));
2612
2613 pVMM->pfnCFGMR3Dump(pInst);
2614
2615#undef RC_CHECK
2616
2617 return VINF_SUCCESS;
2618}
2619
2620HRESULT Console::i_doCPUAdd(ULONG aCpu, PUVM pUVM, PCVMMR3VTABLE pVMM)
2621{
2622 LogFlowThisFuncEnter();
2623
2624 AutoCaller autoCaller(this);
2625 HRESULT hrc = autoCaller.hrc();
2626 if (FAILED(hrc))
2627 return hrc;
2628
2629 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2630
2631 LogFlowThisFunc(("mMachineState=%d\n", mMachineState));
2632 if ( mMachineState != MachineState_Running
2633 && mMachineState != MachineState_Teleporting
2634 && mMachineState != MachineState_LiveSnapshotting
2635 /** @todo r=bird: This should be allowed on paused VMs as well. Later. */
2636 )
2637 return i_setInvalidMachineStateError();
2638
2639 AssertReturn(m_pVMMDev, E_FAIL);
2640 PPDMIVMMDEVPORT pDevPort = m_pVMMDev->getVMMDevPort();
2641 AssertReturn(pDevPort, E_FAIL);
2642
2643 /* Check if the CPU is present */
2644 BOOL fCpuAttached;
2645 hrc = mMachine->GetCPUStatus(aCpu, &fCpuAttached);
2646 if (FAILED(hrc))
2647 return hrc;
2648
2649 if (fCpuAttached)
2650 return setError(E_FAIL, tr("CPU %d is already attached"), aCpu);
2651
2652 /*
2653 * Call worker on EMT #0, that's faster and safer than doing everything
2654 * using VMR3ReqCall. Note that we separate VMR3ReqCall from VMR3ReqWait
2655 * here to make requests from under the lock in order to serialize them.
2656 */
2657 PVMREQ pReq;
2658 int vrc = pVMM->pfnVMR3ReqCallU(pUVM, 0, &pReq, 0 /* no wait! */, VMREQFLAGS_VBOX_STATUS, (PFNRT)i_plugCpu, 4,
2659 this, pUVM, pVMM, aCpu);
2660
2661 /* release the lock before a VMR3* call (EMT might wait for it, @bugref{7648})! */
2662 alock.release();
2663
2664 if (vrc == VERR_TIMEOUT)
2665 vrc = pVMM->pfnVMR3ReqWait(pReq, RT_INDEFINITE_WAIT);
2666 AssertRC(vrc);
2667 if (RT_SUCCESS(vrc))
2668 vrc = pReq->iStatus;
2669 pVMM->pfnVMR3ReqFree(pReq);
2670
2671 if (RT_SUCCESS(vrc))
2672 {
2673 /* Notify the guest if possible. */
2674 uint32_t idCpuCore, idCpuPackage;
2675 vrc = pVMM->pfnVMR3GetCpuCoreAndPackageIdFromCpuId(pUVM, aCpu, &idCpuCore, &idCpuPackage); AssertRC(vrc);
2676 if (RT_SUCCESS(vrc))
2677 vrc = pDevPort->pfnCpuHotPlug(pDevPort, idCpuCore, idCpuPackage);
2678 /** @todo warning if the guest doesn't support it */
2679 }
2680 else
2681 hrc = setErrorBoth(VBOX_E_VM_ERROR, vrc, tr("Could not add CPU to the machine (%Rrc)"), vrc);
2682
2683 LogFlowThisFunc(("mMachineState=%d, hrc=%Rhrc\n", mMachineState, hrc));
2684 LogFlowThisFuncLeave();
2685 return hrc;
2686}
2687
2688HRESULT Console::pause()
2689{
2690 LogFlowThisFuncEnter();
2691
2692 HRESULT hrc = i_pause(Reason_Unspecified);
2693
2694 LogFlowThisFunc(("hrc=%Rhrc\n", hrc));
2695 LogFlowThisFuncLeave();
2696 return hrc;
2697}
2698
2699HRESULT Console::resume()
2700{
2701 LogFlowThisFuncEnter();
2702
2703 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2704
2705 if (mMachineState != MachineState_Paused)
2706 return setError(VBOX_E_INVALID_VM_STATE,
2707 tr("Cannot resume the machine as it is not paused (machine state: %s)"),
2708 Global::stringifyMachineState(mMachineState));
2709
2710 HRESULT hrc = i_resume(Reason_Unspecified, alock);
2711
2712 LogFlowThisFunc(("hrc=%Rhrc\n", hrc));
2713 LogFlowThisFuncLeave();
2714 return hrc;
2715}
2716
2717HRESULT Console::powerButton()
2718{
2719 LogFlowThisFuncEnter();
2720
2721 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2722
2723 if ( mMachineState != MachineState_Running
2724 && mMachineState != MachineState_Teleporting
2725 && mMachineState != MachineState_LiveSnapshotting
2726 )
2727 return i_setInvalidMachineStateError();
2728
2729 /* get the VM handle. */
2730 SafeVMPtr ptrVM(this);
2731 HRESULT hrc = ptrVM.hrc();
2732 if (SUCCEEDED(hrc))
2733 {
2734 // no need to release lock, as there are no cross-thread callbacks
2735
2736 /* get the acpi device interface and press the button. */
2737 PPDMIBASE pBase = NULL;
2738 int vrc = ptrVM.vtable()->pfnPDMR3QueryDeviceLun(ptrVM.rawUVM(), "acpi", 0, 0, &pBase);
2739 /** @todo r=aeichner Think about a prettier way to do this without relying on hardocded device/driver names. */
2740 if (vrc == VERR_PDM_DEVICE_INSTANCE_NOT_FOUND) /* Try GPIO device for ARM VMs */
2741 vrc = ptrVM.vtable()->pfnPDMR3QueryDriverOnLun(ptrVM.rawUVM(), "arm-pl061-gpio", 0, 0, "GpioButton", &pBase);
2742 if (RT_SUCCESS(vrc))
2743 {
2744 Assert(pBase);
2745 PPDMIEVENTBUTTONPORT pPort = PDMIBASE_QUERY_INTERFACE(pBase, PDMIEVENTBUTTONPORT);
2746 if (pPort)
2747 vrc = pPort->pfnPowerButtonPress(pPort);
2748 else
2749 vrc = VERR_PDM_MISSING_INTERFACE;
2750 }
2751
2752 hrc = RT_SUCCESS(vrc) ? S_OK : setErrorBoth(VBOX_E_PDM_ERROR, vrc, tr("Controlled power off failed (%Rrc)"), vrc);
2753 }
2754
2755 LogFlowThisFunc(("hrc=%Rhrc\n", hrc));
2756 LogFlowThisFuncLeave();
2757 return hrc;
2758}
2759
2760HRESULT Console::getPowerButtonHandled(BOOL *aHandled)
2761{
2762 LogFlowThisFuncEnter();
2763
2764 *aHandled = FALSE;
2765
2766 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2767
2768 if ( mMachineState != MachineState_Running
2769 && mMachineState != MachineState_Teleporting
2770 && mMachineState != MachineState_LiveSnapshotting
2771 )
2772 return i_setInvalidMachineStateError();
2773
2774 /* get the VM handle. */
2775 SafeVMPtr ptrVM(this);
2776 HRESULT hrc = ptrVM.hrc();
2777 if (SUCCEEDED(hrc))
2778 {
2779 // no need to release lock, as there are no cross-thread callbacks
2780
2781 /* get the acpi device interface and check if the button press was handled. */
2782 PPDMIBASE pBase;
2783 int vrc = ptrVM.vtable()->pfnPDMR3QueryDeviceLun(ptrVM.rawUVM(), "acpi", 0, 0, &pBase);
2784 if (RT_SUCCESS(vrc))
2785 {
2786 Assert(pBase);
2787 PPDMIEVENTBUTTONPORT pPort = PDMIBASE_QUERY_INTERFACE(pBase, PDMIEVENTBUTTONPORT);
2788 if (pPort)
2789 {
2790 bool fHandled = false;
2791 vrc = pPort->pfnQueryPowerButtonHandled(pPort, &fHandled);
2792 if (RT_SUCCESS(vrc))
2793 *aHandled = fHandled;
2794 }
2795 else
2796 vrc = VERR_PDM_MISSING_INTERFACE;
2797 }
2798
2799 hrc = RT_SUCCESS(vrc) ? S_OK
2800 : setErrorBoth(VBOX_E_PDM_ERROR, vrc,
2801 tr("Checking if the ACPI Power Button event was handled by the guest OS failed (%Rrc)"), vrc);
2802
2803 }
2804 LogFlowThisFunc(("hrc=%Rhrc\n", hrc));
2805 LogFlowThisFuncLeave();
2806 return hrc;
2807}
2808
2809HRESULT Console::getGuestEnteredACPIMode(BOOL *aEntered)
2810{
2811 LogFlowThisFuncEnter();
2812
2813 *aEntered = FALSE;
2814
2815 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2816
2817 if ( mMachineState != MachineState_Running
2818 && mMachineState != MachineState_Teleporting
2819 && mMachineState != MachineState_LiveSnapshotting
2820 )
2821 return setError(VBOX_E_INVALID_VM_STATE,
2822 tr("Invalid machine state %s when checking if the guest entered the ACPI mode"),
2823 Global::stringifyMachineState(mMachineState));
2824
2825 /* get the VM handle. */
2826 SafeVMPtr ptrVM(this);
2827 HRESULT hrc = ptrVM.hrc();
2828 if (SUCCEEDED(hrc))
2829 {
2830 // no need to release lock, as there are no cross-thread callbacks
2831
2832 /* get the acpi device interface and query the information. */
2833 PPDMIBASE pBase;
2834 int vrc = ptrVM.vtable()->pfnPDMR3QueryDeviceLun(ptrVM.rawUVM(), "acpi", 0, 0, &pBase);
2835 if (RT_SUCCESS(vrc))
2836 {
2837 Assert(pBase);
2838 PPDMIACPIPORT pPort = PDMIBASE_QUERY_INTERFACE(pBase, PDMIACPIPORT);
2839 if (pPort)
2840 {
2841 bool fEntered = false;
2842 vrc = pPort->pfnGetGuestEnteredACPIMode(pPort, &fEntered);
2843 if (RT_SUCCESS(vrc))
2844 *aEntered = fEntered;
2845 }
2846 else
2847 vrc = VERR_PDM_MISSING_INTERFACE;
2848 }
2849
2850 if (vrc == VERR_PDM_DEVICE_INSTANCE_NOT_FOUND)
2851 {
2852 /* Might be an ARM VM. */
2853 /** @todo r=aeichner Think about a prettier way to do this without relying on hardocded device/driver names,
2854 * and this shouldn't be here as it is not about ACPI but needs a dedicated interface. */
2855 vrc = ptrVM.vtable()->pfnPDMR3QueryDriverOnLun(ptrVM.rawUVM(), "arm-pl061-gpio", 0, 0, "GpioButton", &pBase);
2856 if (RT_SUCCESS(vrc))
2857 {
2858 Assert(pBase);
2859 PPDMIEVENTBUTTONPORT pPort = PDMIBASE_QUERY_INTERFACE(pBase, PDMIEVENTBUTTONPORT);
2860 if (pPort)
2861 {
2862 bool fEntered = false;
2863 vrc = pPort->pfnQueryGuestCanHandleButtonEvents(pPort, &fEntered);
2864 if (RT_SUCCESS(vrc))
2865 *aEntered = fEntered;
2866 }
2867 else
2868 vrc = VERR_PDM_MISSING_INTERFACE;
2869 }
2870 }
2871 }
2872
2873 LogFlowThisFuncLeave();
2874 return hrc;
2875}
2876
2877HRESULT Console::sleepButton()
2878{
2879 LogFlowThisFuncEnter();
2880
2881 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
2882
2883 if ( mMachineState != MachineState_Running
2884 && mMachineState != MachineState_Teleporting
2885 && mMachineState != MachineState_LiveSnapshotting)
2886 return i_setInvalidMachineStateError();
2887
2888 /* get the VM handle. */
2889 SafeVMPtr ptrVM(this);
2890 HRESULT hrc = ptrVM.hrc();
2891 if (SUCCEEDED(hrc))
2892 {
2893 // no need to release lock, as there are no cross-thread callbacks
2894
2895 /* get the acpi device interface and press the sleep button. */
2896 PPDMIBASE pBase = NULL;
2897 int vrc = ptrVM.vtable()->pfnPDMR3QueryDeviceLun(ptrVM.rawUVM(), "acpi", 0, 0, &pBase);
2898 /** @todo r=aeichner Think about a prettier way to do this without relying on hardocded device/driver names. */
2899 if (vrc == VERR_PDM_DEVICE_INSTANCE_NOT_FOUND) /* Try GPIO device for ARM VMs */
2900 vrc = ptrVM.vtable()->pfnPDMR3QueryDriverOnLun(ptrVM.rawUVM(), "arm-pl061-gpio", 0, 0, "GpioButton", &pBase);
2901 if (RT_SUCCESS(vrc))
2902 {
2903 Assert(pBase);
2904 PPDMIEVENTBUTTONPORT pPort = PDMIBASE_QUERY_INTERFACE(pBase, PDMIEVENTBUTTONPORT);
2905 if (pPort)
2906 vrc = pPort->pfnSleepButtonPress(pPort);
2907 else
2908 vrc = VERR_PDM_MISSING_INTERFACE;
2909 }
2910
2911 hrc = RT_SUCCESS(vrc) ? S_OK : setErrorBoth(VBOX_E_PDM_ERROR, vrc, tr("Sending sleep button event failed (%Rrc)"), vrc);
2912 }
2913
2914 LogFlowThisFunc(("hrc=%Rhrc\n", hrc));
2915 LogFlowThisFuncLeave();
2916 return hrc;
2917}
2918
2919/**
2920 * Refreshes the maLedTypes and muLedTypeGen members.
2921 */
2922HRESULT Console::i_refreshLedTypeArrays(AutoReadLock *pReadLock)
2923{
2924 pReadLock->release();
2925 AutoWriteLock alock(mLedLock COMMA_LOCKVAL_SRC_POS);
2926
2927 /*
2928 * Check that the refresh was already done by someone else while we
2929 * acquired the write lock.
2930 */
2931 if (muLedTypeGen != muLedGen)
2932 {
2933 /*
2934 * Reset the data.
2935 */
2936 for (size_t idxType = 0; idxType < RT_ELEMENTS(maLedTypes); idxType++)
2937 maLedTypes[idxType].cLeds = 0;
2938
2939 /*
2940 * Rebuild the data.
2941 */
2942 for (uint32_t idxSet = 0; idxSet < mcLedSets; idxSet++)
2943 {
2944 PLEDSET const pLS = &maLedSets[idxSet];
2945 uint32_t const cLeds = pLS->cLeds;
2946 PPDMLED volatile * const papSrcLeds = pLS->papLeds;
2947 DeviceType_T * const paSubTypes = pLS->paSubTypes;
2948 for (uint32_t idxLed = 0; idxLed < cLeds; idxLed++)
2949 {
2950 /** @todo If we make Console::i_drvStatus_UnitChanged() modify the generation
2951 * too, we could skip NULL entries here and make it a bit more compact.
2952 * OTOH, most unused LED entires have a paSubTypes of DeviceType_Null. */
2953 DeviceType_T enmType = paSubTypes ? paSubTypes[idxLed] : (DeviceType_T)(ASMBitFirstSetU32(pLS->fTypes) - 1);
2954 if (enmType > DeviceType_Null && enmType < DeviceType_End)
2955 {
2956 uint32_t const idxLedType = maLedTypes[enmType].cLeds;
2957 if (idxLedType >= maLedTypes[enmType].cAllocated)
2958 {
2959 void *pvNew = RTMemRealloc(maLedTypes[enmType].pappLeds,
2960 sizeof(maLedTypes[0].pappLeds[0]) * (idxLedType + 16));
2961 if (!pvNew)
2962 return E_OUTOFMEMORY;
2963 maLedTypes[enmType].pappLeds = (PPDMLED volatile **)pvNew;
2964 maLedTypes[enmType].cAllocated = idxLedType + 16;
2965 }
2966 maLedTypes[enmType].pappLeds[idxLedType] = &papSrcLeds[idxLed];
2967 maLedTypes[enmType].cLeds = idxLedType + 1;
2968 }
2969 }
2970 }
2971 muLedTypeGen = muLedGen;
2972 }
2973
2974 /*
2975 * We have to release the write lock before re-acquiring the read-lock.
2976 *
2977 * This means there is a theoretical race here, however we ASSUME that
2978 * LED sets are never removed and therefore we will be just fine
2979 * accessing slightly dated per-type data.
2980 */
2981 alock.release();
2982 pReadLock->acquire();
2983 return S_OK;
2984}
2985
2986/** read the value of a LED. */
2987DECLINLINE(uint32_t) readAndClearLed(PPDMLED pLed)
2988{
2989 if (!pLed)
2990 return 0;
2991 uint32_t u32 = pLed->Actual.u32 | pLed->Asserted.u32;
2992 pLed->Asserted.u32 = 0;
2993 return u32;
2994}
2995
2996HRESULT Console::getDeviceActivity(const std::vector<DeviceType_T> &aType, std::vector<DeviceActivity_T> &aActivity)
2997{
2998 /*
2999 * Make a roadmap of which DeviceType_T LED types are wanted.
3000 *
3001 * Note! This approach means we'll return the same values in aActivity for
3002 * duplicate aType entries.
3003 */
3004 uint32_t fRequestedTypes = 0;
3005 AssertCompile(DeviceType_End <= 32);
3006
3007 for (size_t iType = 0; iType < aType.size(); ++iType)
3008 {
3009 DeviceType_T const enmType = aType[iType];
3010 AssertCompile((unsigned)DeviceType_Null == 0 /* first */);
3011 AssertReturn(enmType > DeviceType_Null && enmType < DeviceType_End,
3012 setError(E_INVALIDARG, tr("Invalid DeviceType for getDeviceActivity in entry #%u: %d"), iType, enmType));
3013 fRequestedTypes |= RT_BIT_32((unsigned)enmType);
3014 }
3015
3016 /*
3017 * Resize the result vector before making changes (may throw, paranoia).
3018 */
3019 aActivity.resize(aType.size());
3020
3021 /*
3022 * Accumulate the per-type data for all the requested types.
3023 * We will lazily refresh the per-type data collection here when needed.
3024 */
3025 PDMLEDCORE aLEDs[DeviceType_End] = { {0} };
3026 Assert(aLEDs[1].u32 == 0 && aLEDs[DeviceType_End / 2].u32 == 0 && aLEDs[DeviceType_End - 1].u32 == 0); /* paranoia */
3027 {
3028 AutoReadLock alock(mLedLock COMMA_LOCKVAL_SRC_POS);
3029 if (RT_LIKELY(muLedGen == muLedTypeGen))
3030 { /* likely */ }
3031 else
3032 {
3033 HRESULT hrc = i_refreshLedTypeArrays(&alock);
3034 if (FAILED(hrc))
3035 return hrc;
3036 }
3037
3038 AssertCompile((unsigned)DeviceType_Null == 0 /* we skip this one */);
3039 for (uint32_t idxType = 1; idxType < RT_ELEMENTS(maLedTypes); idxType++)
3040 if (fRequestedTypes & RT_BIT_32(idxType))
3041 {
3042 uint32_t const cLeds = maLedTypes[idxType].cLeds;
3043 PPDMLED volatile ** const pappSrcLeds = maLedTypes[idxType].pappLeds;
3044 for (size_t iLed = 0; iLed < cLeds; iLed++)
3045 aLEDs[idxType].u32 |= readAndClearLed(*pappSrcLeds[iLed]);
3046 }
3047 }
3048
3049 /*
3050 * Compose the result vector:
3051 */
3052 for (size_t iType = 0; iType < aActivity.size(); ++iType)
3053 {
3054 switch (aLEDs[aType[iType]].u32 & (PDMLED_READING | PDMLED_WRITING))
3055 {
3056 case 0:
3057 aActivity[iType] = DeviceActivity_Idle;
3058 break;
3059 case PDMLED_READING:
3060 aActivity[iType] = DeviceActivity_Reading;
3061 break;
3062 case PDMLED_WRITING:
3063 case PDMLED_READING | PDMLED_WRITING:
3064 aActivity[iType] = DeviceActivity_Writing;
3065 break;
3066 }
3067 }
3068
3069 return S_OK;
3070}
3071
3072HRESULT Console::attachUSBDevice(const com::Guid &aId, const com::Utf8Str &aCaptureFilename)
3073{
3074#ifdef VBOX_WITH_USB
3075 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
3076
3077 if ( mMachineState != MachineState_Running
3078 && mMachineState != MachineState_Paused)
3079 return setError(VBOX_E_INVALID_VM_STATE,
3080 tr("Cannot attach a USB device to the machine which is not running or paused (machine state: %s)"),
3081 Global::stringifyMachineState(mMachineState));
3082
3083 /* Get the VM handle. */
3084 SafeVMPtr ptrVM(this);
3085 HRESULT hrc = ptrVM.hrc();
3086 if (SUCCEEDED(hrc))
3087 {
3088 /* Don't proceed unless we have a USB controller. */
3089 if (mfVMHasUsbController)
3090 {
3091 /* release the lock because the USB Proxy service may call us back
3092 * (via onUSBDeviceAttach()) */
3093 alock.release();
3094
3095 /* Request the device capture */
3096 hrc = mControl->CaptureUSBDevice(Bstr(aId.toString()).raw(), Bstr(aCaptureFilename).raw());
3097 }
3098 else
3099 hrc = setError(VBOX_E_PDM_ERROR, tr("The virtual machine does not have a USB controller"));
3100 }
3101 return hrc;
3102
3103#else /* !VBOX_WITH_USB */
3104 RT_NOREF(aId, aCaptureFilename);
3105 return setError(VBOX_E_PDM_ERROR, tr("The virtual machine does not have a USB controller"));
3106#endif /* !VBOX_WITH_USB */
3107}
3108
3109HRESULT Console::detachUSBDevice(const com::Guid &aId, ComPtr<IUSBDevice> &aDevice)
3110{
3111 RT_NOREF(aDevice);
3112#ifdef VBOX_WITH_USB
3113 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
3114
3115 /* Find it. */
3116 for (USBDeviceList::iterator it = mUSBDevices.begin(); it != mUSBDevices.end(); ++it)
3117 if ((*it)->i_id() == aId)
3118 {
3119 /* Found it! */
3120 ComObjPtr<OUSBDevice> pUSBDevice(*it);
3121
3122 /* Remove the device from the collection, it is re-added below for failures */
3123 mUSBDevices.erase(it);
3124
3125 /*
3126 * Inform the USB device and USB proxy about what's cooking.
3127 */
3128 alock.release();
3129 HRESULT hrc = mControl->DetachUSBDevice(Bstr(aId.toString()).raw(), false /* aDone */);
3130 if (SUCCEEDED(hrc))
3131 {
3132 /* Request the PDM to detach the USB device. */
3133 hrc = i_detachUSBDevice(pUSBDevice);
3134 if (SUCCEEDED(hrc))
3135 {
3136 //return the detached USB device
3137 pUSBDevice.queryInterfaceTo(aDevice.asOutParam());
3138 /* Request the device release. Even if it fails, the device will
3139 * remain as held by proxy, which is OK for us (the VM process). */
3140 return mControl->DetachUSBDevice(Bstr(aId.toString()).raw(), true /* aDone */);
3141 }
3142 }
3143
3144 /* Re-add the device to the collection */
3145 alock.acquire();
3146 mUSBDevices.push_back(pUSBDevice);
3147 return hrc;
3148 }
3149
3150 return setError(E_INVALIDARG, tr("USB device with UUID {%RTuuid} is not attached to this machine"), aId.raw());
3151
3152#else /* !VBOX_WITH_USB */
3153 RT_NOREF(aId, aDevice);
3154 return setError(VBOX_E_PDM_ERROR, tr("The virtual machine does not have a USB controller"));
3155#endif /* !VBOX_WITH_USB */
3156}
3157
3158
3159HRESULT Console::findUSBDeviceByAddress(const com::Utf8Str &aName, ComPtr<IUSBDevice> &aDevice)
3160{
3161#ifdef VBOX_WITH_USB
3162 aDevice = NULL;
3163
3164 SafeIfaceArray<IUSBDevice> devsvec;
3165 HRESULT hrc = COMGETTER(USBDevices)(ComSafeArrayAsOutParam(devsvec));
3166 if (FAILED(hrc))
3167 return hrc;
3168
3169 for (size_t i = 0; i < devsvec.size(); ++i)
3170 {
3171 Bstr bstrAddress;
3172 hrc = devsvec[i]->COMGETTER(Address)(bstrAddress.asOutParam());
3173 if (FAILED(hrc))
3174 return hrc;
3175 if (bstrAddress == aName)
3176 {
3177 ComObjPtr<OUSBDevice> pUSBDevice;
3178 pUSBDevice.createObject();
3179 pUSBDevice->init(devsvec[i]);
3180 return pUSBDevice.queryInterfaceTo(aDevice.asOutParam());
3181 }
3182 }
3183
3184 return setErrorNoLog(VBOX_E_OBJECT_NOT_FOUND, tr("Could not find a USB device with address '%s'"), aName.c_str());
3185
3186#else /* !VBOX_WITH_USB */
3187 RT_NOREF(aName, aDevice);
3188 return E_NOTIMPL;
3189#endif /* !VBOX_WITH_USB */
3190}
3191
3192HRESULT Console::findUSBDeviceById(const com::Guid &aId, ComPtr<IUSBDevice> &aDevice)
3193{
3194#ifdef VBOX_WITH_USB
3195 aDevice = NULL;
3196
3197 SafeIfaceArray<IUSBDevice> devsvec;
3198 HRESULT hrc = COMGETTER(USBDevices)(ComSafeArrayAsOutParam(devsvec));
3199 if (FAILED(hrc))
3200 return hrc;
3201
3202 Utf8Str const strId = aId.toString();
3203 for (size_t i = 0; i < devsvec.size(); ++i)
3204 {
3205 Bstr id;
3206 hrc = devsvec[i]->COMGETTER(Id)(id.asOutParam());
3207 if (FAILED(hrc))
3208 return hrc;
3209 if (id == strId)
3210 {
3211 ComObjPtr<OUSBDevice> pUSBDevice;
3212 pUSBDevice.createObject();
3213 pUSBDevice->init(devsvec[i]);
3214 ComObjPtr<IUSBDevice> iUSBDevice = static_cast <ComObjPtr<IUSBDevice> > (pUSBDevice);
3215 return iUSBDevice.queryInterfaceTo(aDevice.asOutParam());
3216 }
3217 }
3218
3219 return setErrorNoLog(VBOX_E_OBJECT_NOT_FOUND, tr("Could not find a USB device with uuid {%RTuuid}"), aId.raw());
3220
3221#else /* !VBOX_WITH_USB */
3222 RT_NOREF(aId, aDevice);
3223 return E_NOTIMPL;
3224#endif /* !VBOX_WITH_USB */
3225}
3226
3227HRESULT Console::createSharedFolder(const com::Utf8Str &aName, const com::Utf8Str &aHostPath, BOOL aWritable,
3228 BOOL aAutomount, const com::Utf8Str &aAutoMountPoint)
3229{
3230 LogFlowThisFunc(("Entering for '%s' -> '%s'\n", aName.c_str(), aHostPath.c_str()));
3231
3232 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
3233
3234 /// @todo see @todo in AttachUSBDevice() about the Paused state
3235 if (mMachineState == MachineState_Saved || mMachineState == MachineState_AbortedSaved)
3236 return setError(VBOX_E_INVALID_VM_STATE,
3237 tr("Cannot create a transient shared folder on a machine in a saved state (machine state: %s)"),
3238 Global::stringifyMachineState(mMachineState));
3239 if ( mMachineState != MachineState_PoweredOff
3240 && mMachineState != MachineState_Teleported
3241 && mMachineState != MachineState_Aborted
3242 && mMachineState != MachineState_Running
3243 && mMachineState != MachineState_Paused
3244 )
3245 return setError(VBOX_E_INVALID_VM_STATE,
3246 tr("Cannot create a transient shared folder on the machine while it is changing the state (machine state: %s)"),
3247 Global::stringifyMachineState(mMachineState));
3248
3249 ComObjPtr<ConsoleSharedFolder> pSharedFolder;
3250 HRESULT hrc = i_findSharedFolder(aName, pSharedFolder, false /* aSetError */);
3251 if (SUCCEEDED(hrc))
3252 return setError(VBOX_E_FILE_ERROR, tr("Shared folder named '%s' already exists"), aName.c_str());
3253
3254 pSharedFolder.createObject();
3255 hrc = pSharedFolder->init(this,
3256 aName,
3257 aHostPath,
3258 !!aWritable,
3259 !!aAutomount,
3260 aAutoMountPoint,
3261 true /* fFailOnError */);
3262 if (FAILED(hrc))
3263 return hrc;
3264
3265 /* If the VM is online and supports shared folders, share this folder
3266 * under the specified name. (Ignore any failure to obtain the VM handle.) */
3267 SafeVMPtrQuiet ptrVM(this);
3268 if ( ptrVM.isOk()
3269 && m_pVMMDev
3270 && m_pVMMDev->isShFlActive()
3271 )
3272 {
3273 /* first, remove the machine or the global folder if there is any */
3274 SharedFolderDataMap::const_iterator it;
3275 if (i_findOtherSharedFolder(aName, it))
3276 {
3277 hrc = i_removeSharedFolder(aName);
3278 if (FAILED(hrc))
3279 return hrc;
3280 }
3281
3282 /* second, create the given folder */
3283 hrc = i_createSharedFolder(aName, SharedFolderData(aHostPath, !!aWritable, !!aAutomount, aAutoMountPoint));
3284 if (FAILED(hrc))
3285 return hrc;
3286 }
3287
3288 m_mapSharedFolders.insert(std::make_pair(aName, pSharedFolder));
3289
3290 /* Notify console callbacks after the folder is added to the list. */
3291 alock.release();
3292 ::FireSharedFolderChangedEvent(mEventSource, Scope_Session);
3293
3294 LogFlowThisFunc(("Leaving for '%s' -> '%s'\n", aName.c_str(), aHostPath.c_str()));
3295
3296 return hrc;
3297}
3298
3299HRESULT Console::removeSharedFolder(const com::Utf8Str &aName)
3300{
3301 LogFlowThisFunc(("Entering for '%s'\n", aName.c_str()));
3302
3303 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
3304
3305 /// @todo see @todo in AttachUSBDevice() about the Paused state
3306 if (mMachineState == MachineState_Saved || mMachineState == MachineState_AbortedSaved)
3307 return setError(VBOX_E_INVALID_VM_STATE,
3308 tr("Cannot remove a transient shared folder from a machine in a saved state (machine state: %s)"),
3309 Global::stringifyMachineState(mMachineState));;
3310 if ( mMachineState != MachineState_PoweredOff
3311 && mMachineState != MachineState_Teleported
3312 && mMachineState != MachineState_Aborted
3313 && mMachineState != MachineState_Running
3314 && mMachineState != MachineState_Paused
3315 )
3316 return setError(VBOX_E_INVALID_VM_STATE,
3317 tr("Cannot remove a transient shared folder from the machine while it is changing the state (machine state: %s)"),
3318 Global::stringifyMachineState(mMachineState));
3319
3320 ComObjPtr<ConsoleSharedFolder> pSharedFolder;
3321 HRESULT hrc = i_findSharedFolder(aName, pSharedFolder, true /* aSetError */);
3322 if (FAILED(hrc))
3323 return hrc;
3324
3325 /* protect the VM handle (if not NULL) */
3326 SafeVMPtrQuiet ptrVM(this);
3327 if ( ptrVM.isOk()
3328 && m_pVMMDev
3329 && m_pVMMDev->isShFlActive()
3330 )
3331 {
3332 /* if the VM is online and supports shared folders, UNshare this folder. */
3333
3334 /* first, remove the given folder */
3335 hrc = i_removeSharedFolder(aName);
3336 if (FAILED(hrc))
3337 return hrc;
3338
3339 /* first, remove the machine or the global folder if there is any */
3340 SharedFolderDataMap::const_iterator it;
3341 if (i_findOtherSharedFolder(aName, it))
3342 {
3343 hrc = i_createSharedFolder(aName, it->second);
3344 /* don't check hrc here because we need to remove the console
3345 * folder from the collection even on failure */
3346 }
3347 }
3348
3349 m_mapSharedFolders.erase(aName);
3350
3351 /* Notify console callbacks after the folder is removed from the list. */
3352 alock.release();
3353 ::FireSharedFolderChangedEvent(mEventSource, Scope_Session);
3354
3355 LogFlowThisFunc(("Leaving for '%s'\n", aName.c_str()));
3356
3357 return hrc;
3358}
3359
3360HRESULT Console::addEncryptionPassword(const com::Utf8Str &aId, const com::Utf8Str &aPassword,
3361 BOOL aClearOnSuspend)
3362{
3363 if ( aId.isEmpty()
3364 || aPassword.isEmpty())
3365 return setError(E_FAIL, tr("The ID and password must be both valid"));
3366
3367 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
3368
3369 HRESULT hrc = S_OK;
3370 size_t cbKey = aPassword.length() + 1; /* Include terminator */
3371 const uint8_t *pbKey = (const uint8_t *)aPassword.c_str();
3372
3373 int vrc = m_pKeyStore->addSecretKey(aId, pbKey, cbKey);
3374 if ( RT_SUCCESS(vrc)
3375#ifdef VBOX_WITH_FULL_VM_ENCRYPTION
3376 || vrc == VERR_ALREADY_EXISTS /* Allow setting an existing key for encrypted VMs. */
3377#endif
3378 )
3379 {
3380 unsigned cDisksConfigured = 0;
3381
3382#ifdef VBOX_WITH_FULL_VM_ENCRYPTION
3383 if (mptrNvramStore.isNotNull())
3384 mptrNvramStore->i_addPassword(aId, aPassword);
3385
3386 SecretKey *pKey = NULL;
3387 vrc = m_pKeyStore->retainSecretKey(aId, &pKey);
3388 AssertRCReturn(vrc, E_FAIL);
3389 pKey->setRemoveOnSuspend(!!aClearOnSuspend);
3390 pKey->release();
3391#endif
3392
3393 hrc = i_configureEncryptionForDisk(aId, &cDisksConfigured);
3394 if (SUCCEEDED(hrc))
3395 {
3396#ifndef VBOX_WITH_FULL_VM_ENCRYPTION
3397 SecretKey *pKey = NULL;
3398#endif
3399 vrc = m_pKeyStore->retainSecretKey(aId, &pKey);
3400 AssertRCReturn(vrc, E_FAIL);
3401
3402 pKey->setUsers(cDisksConfigured);
3403#ifndef VBOX_WITH_FULL_VM_ENCRYPTION
3404 pKey->setRemoveOnSuspend(!!aClearOnSuspend);
3405 m_pKeyStore->releaseSecretKey(aId);
3406#endif
3407 m_cDisksPwProvided += cDisksConfigured;
3408
3409 if ( m_cDisksPwProvided == m_cDisksEncrypted
3410 && mMachineState == MachineState_Paused)
3411 {
3412 /* get the VM handle. */
3413 SafeVMPtr ptrVM(this);
3414 if (!ptrVM.isOk())
3415 return ptrVM.hrc();
3416
3417 alock.release();
3418 vrc = ptrVM.vtable()->pfnVMR3Resume(ptrVM.rawUVM(), VMRESUMEREASON_RECONFIG);
3419
3420 hrc = RT_SUCCESS(vrc) ? S_OK
3421 : setErrorBoth(VBOX_E_VM_ERROR, vrc, tr("Could not resume the machine execution (%Rrc)"), vrc);
3422 }
3423 }
3424 }
3425#ifndef VBOX_WITH_FULL_VM_ENCRYPTION
3426 else if (vrc == VERR_ALREADY_EXISTS)
3427 hrc = setErrorBoth(VBOX_E_OBJECT_IN_USE, vrc, tr("A password with the given ID already exists"));
3428#endif
3429 else if (vrc == VERR_NO_MEMORY)
3430 hrc = setErrorBoth(E_FAIL, vrc, tr("Failed to allocate enough secure memory for the key"));
3431 else
3432 hrc = setErrorBoth(E_FAIL, vrc, tr("Unknown error happened while adding a password (%Rrc)"), vrc);
3433
3434 return hrc;
3435}
3436
3437HRESULT Console::addEncryptionPasswords(const std::vector<com::Utf8Str> &aIds, const std::vector<com::Utf8Str> &aPasswords,
3438 BOOL aClearOnSuspend)
3439{
3440 HRESULT hrc = S_OK;
3441
3442 if ( aIds.empty()
3443 || aPasswords.empty())
3444 return setError(E_FAIL, tr("IDs and passwords must not be empty"));
3445
3446 if (aIds.size() != aPasswords.size())
3447 return setError(E_FAIL, tr("The number of entries in the id and password arguments must match"));
3448
3449 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
3450
3451#ifndef VBOX_WITH_FULL_VM_ENCRYPTION
3452 /* Check that the IDs do not exist already before changing anything. */
3453 for (unsigned i = 0; i < aIds.size(); i++)
3454 {
3455 SecretKey *pKey = NULL;
3456 int vrc = m_pKeyStore->retainSecretKey(aIds[i], &pKey);
3457 if (vrc != VERR_NOT_FOUND)
3458 {
3459 AssertPtr(pKey);
3460 if (pKey)
3461 pKey->release();
3462 return setError(VBOX_E_OBJECT_IN_USE, tr("A password with the given ID already exists"));
3463 }
3464 }
3465#else
3466 /*
3467 * Passwords for the same ID can be added in different ways because
3468 * of encrypted VMs now. Just add them instead of generating an error.
3469 */
3470 /** @todo Check that passwords with the same ID match. */
3471#endif
3472
3473 for (unsigned i = 0; i < aIds.size(); i++)
3474 {
3475 hrc = addEncryptionPassword(aIds[i], aPasswords[i], aClearOnSuspend);
3476 if (FAILED(hrc))
3477 {
3478 /*
3479 * Try to remove already successfully added passwords from the map to not
3480 * change the state of the Console object.
3481 */
3482 ErrorInfoKeeper eik; /* Keep current error info or it gets deestroyed in the IPC methods below. */
3483 for (unsigned ii = 0; ii < i; ii++)
3484 {
3485 i_clearDiskEncryptionKeysOnAllAttachmentsWithKeyId(aIds[ii]);
3486 removeEncryptionPassword(aIds[ii]);
3487 }
3488
3489 break;
3490 }
3491 }
3492
3493 return hrc;
3494}
3495
3496HRESULT Console::removeEncryptionPassword(const com::Utf8Str &aId)
3497{
3498 if (aId.isEmpty())
3499 return setError(E_FAIL, tr("The ID must be valid"));
3500
3501 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
3502
3503 SecretKey *pKey = NULL;
3504 int vrc = m_pKeyStore->retainSecretKey(aId, &pKey);
3505 if (RT_SUCCESS(vrc))
3506 {
3507 m_cDisksPwProvided -= pKey->getUsers();
3508 m_pKeyStore->releaseSecretKey(aId);
3509 vrc = m_pKeyStore->deleteSecretKey(aId);
3510 AssertRCReturn(vrc, E_FAIL);
3511
3512#ifdef VBOX_WITH_FULL_VM_ENCRYPTION
3513 if (mptrNvramStore.isNotNull())
3514 mptrNvramStore->i_removePassword(aId);
3515#endif
3516 }
3517 else if (vrc == VERR_NOT_FOUND)
3518 return setErrorBoth(VBOX_E_OBJECT_NOT_FOUND, vrc, tr("A password with the ID \"%s\" does not exist"), aId.c_str());
3519 else
3520 return setErrorBoth(E_FAIL, vrc, tr("Failed to remove password with ID \"%s\" (%Rrc)"), aId.c_str(), vrc);
3521
3522 return S_OK;
3523}
3524
3525HRESULT Console::clearAllEncryptionPasswords()
3526{
3527 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
3528
3529#ifdef VBOX_WITH_FULL_VM_ENCRYPTION
3530 if (mptrNvramStore.isNotNull())
3531 mptrNvramStore->i_removeAllPasswords();
3532#endif
3533
3534 int vrc = m_pKeyStore->deleteAllSecretKeys(false /* fSuspend */, false /* fForce */);
3535 if (vrc == VERR_RESOURCE_IN_USE)
3536 return setErrorBoth(VBOX_E_OBJECT_IN_USE, vrc, tr("A password is still in use by the VM"));
3537 else if (RT_FAILURE(vrc))
3538 return setErrorBoth(E_FAIL, vrc, tr("Deleting all passwords failed (%Rrc)"));
3539
3540 m_cDisksPwProvided = 0;
3541 return S_OK;
3542}
3543
3544// Non-interface public methods
3545/////////////////////////////////////////////////////////////////////////////
3546
3547/*static*/
3548HRESULT Console::i_setErrorStatic(HRESULT aResultCode, const char *pcsz, ...)
3549{
3550 va_list args;
3551 va_start(args, pcsz);
3552 HRESULT hrc = setErrorInternalV(aResultCode,
3553 getStaticClassIID(),
3554 getStaticComponentName(),
3555 pcsz, args,
3556 false /* aWarning */,
3557 true /* aLogIt */);
3558 va_end(args);
3559 return hrc;
3560}
3561
3562/*static*/
3563HRESULT Console::i_setErrorStaticBoth(HRESULT aResultCode, int vrc, const char *pcsz, ...)
3564{
3565 va_list args;
3566 va_start(args, pcsz);
3567 HRESULT hrc = setErrorInternalV(aResultCode,
3568 getStaticClassIID(),
3569 getStaticComponentName(),
3570 pcsz, args,
3571 false /* aWarning */,
3572 true /* aLogIt */,
3573 vrc);
3574 va_end(args);
3575 return hrc;
3576}
3577
3578HRESULT Console::i_setInvalidMachineStateError()
3579{
3580 return setError(VBOX_E_INVALID_VM_STATE,
3581 tr("Invalid machine state: %s"),
3582 Global::stringifyMachineState(mMachineState));
3583}
3584
3585
3586/**
3587 * Converts to PDM device names.
3588 */
3589/* static */ const char *Console::i_storageControllerTypeToStr(StorageControllerType_T enmCtrlType)
3590{
3591 switch (enmCtrlType)
3592 {
3593 case StorageControllerType_LsiLogic:
3594 return "lsilogicscsi";
3595 case StorageControllerType_BusLogic:
3596 return "buslogic";
3597 case StorageControllerType_LsiLogicSas:
3598 return "lsilogicsas";
3599 case StorageControllerType_IntelAhci:
3600 return "ahci";
3601 case StorageControllerType_PIIX3:
3602 case StorageControllerType_PIIX4:
3603 case StorageControllerType_ICH6:
3604 return "piix3ide";
3605 case StorageControllerType_I82078:
3606 return "i82078";
3607 case StorageControllerType_USB:
3608 return "Msd";
3609 case StorageControllerType_NVMe:
3610 return "nvme";
3611 case StorageControllerType_VirtioSCSI:
3612 return "virtio-scsi";
3613 default:
3614 return NULL;
3615 }
3616}
3617
3618HRESULT Console::i_storageBusPortDeviceToLun(StorageBus_T enmBus, LONG port, LONG device, unsigned &uLun)
3619{
3620 switch (enmBus)
3621 {
3622 case StorageBus_IDE:
3623 case StorageBus_Floppy:
3624 {
3625 AssertMsgReturn(port < 2 && port >= 0, ("%d\n", port), E_INVALIDARG);
3626 AssertMsgReturn(device < 2 && device >= 0, ("%d\n", device), E_INVALIDARG);
3627 uLun = 2 * port + device;
3628 return S_OK;
3629 }
3630 case StorageBus_SATA:
3631 case StorageBus_SCSI:
3632 case StorageBus_SAS:
3633 case StorageBus_PCIe:
3634 case StorageBus_VirtioSCSI:
3635 {
3636 uLun = port;
3637 return S_OK;
3638 }
3639 case StorageBus_USB:
3640 {
3641 /*
3642 * It is always the first lun, the port denotes the device instance
3643 * for the Msd device.
3644 */
3645 uLun = 0;
3646 return S_OK;
3647 }
3648 default:
3649 uLun = 0;
3650 AssertMsgFailedReturn(("%d\n", enmBus), E_INVALIDARG);
3651 }
3652}
3653
3654// private methods
3655/////////////////////////////////////////////////////////////////////////////
3656
3657/**
3658 * Suspend the VM before we do any medium or network attachment change.
3659 *
3660 * @param pUVM Safe VM handle.
3661 * @param pVMM Safe VMM vtable.
3662 * @param pAlock The automatic lock instance. This is for when we have
3663 * to leave it in order to avoid deadlocks.
3664 * @param pfResume where to store the information if we need to resume
3665 * afterwards.
3666 */
3667HRESULT Console::i_suspendBeforeConfigChange(PUVM pUVM, PCVMMR3VTABLE pVMM, AutoWriteLock *pAlock, bool *pfResume)
3668{
3669 *pfResume = false;
3670
3671 VMSTATE enmVMState = pVMM->pfnVMR3GetStateU(pUVM);
3672 switch (enmVMState)
3673 {
3674 case VMSTATE_RUNNING:
3675 case VMSTATE_RESETTING:
3676 case VMSTATE_SOFT_RESETTING:
3677 {
3678 LogFlowFunc(("Suspending the VM...\n"));
3679 /* disable the callback to prevent Console-level state change */
3680 mVMStateChangeCallbackDisabled = true;
3681 if (pAlock)
3682 pAlock->release();
3683 int vrc = pVMM->pfnVMR3Suspend(pUVM, VMSUSPENDREASON_RECONFIG);
3684 if (pAlock)
3685 pAlock->acquire();
3686 mVMStateChangeCallbackDisabled = false;
3687 if (RT_FAILURE(vrc))
3688 return setErrorInternalF(VBOX_E_INVALID_VM_STATE,
3689 COM_IIDOF(IConsole),
3690 getStaticComponentName(),
3691 false /*aWarning*/,
3692 true /*aLogIt*/,
3693 vrc,
3694 tr("Could suspend VM for medium change (%Rrc)"), vrc);
3695 *pfResume = true;
3696 break;
3697 }
3698 case VMSTATE_SUSPENDED:
3699 break;
3700 default:
3701 return setErrorInternalF(VBOX_E_INVALID_VM_STATE,
3702 COM_IIDOF(IConsole),
3703 getStaticComponentName(),
3704 false /*aWarning*/,
3705 true /*aLogIt*/,
3706 0 /* aResultDetail */,
3707 tr("Invalid state '%s' for changing medium"),
3708 pVMM->pfnVMR3GetStateName(enmVMState));
3709 }
3710
3711 return S_OK;
3712}
3713
3714/**
3715 * Resume the VM after we did any medium or network attachment change.
3716 * This is the counterpart to Console::suspendBeforeConfigChange().
3717 *
3718 * @param pUVM Safe VM handle.
3719 * @param pVMM Safe VMM vtable.
3720 */
3721void Console::i_resumeAfterConfigChange(PUVM pUVM, PCVMMR3VTABLE pVMM)
3722{
3723 LogFlowFunc(("Resuming the VM...\n"));
3724
3725 /* disable the callback to prevent Console-level state change */
3726 mVMStateChangeCallbackDisabled = true;
3727 int vrc = pVMM->pfnVMR3Resume(pUVM, VMRESUMEREASON_RECONFIG);
3728 mVMStateChangeCallbackDisabled = false;
3729 AssertRC(vrc);
3730 if (RT_FAILURE(vrc))
3731 {
3732 VMSTATE enmVMState = pVMM->pfnVMR3GetStateU(pUVM);
3733 if (enmVMState == VMSTATE_SUSPENDED)
3734 {
3735 /* too bad, we failed. try to sync the console state with the VMM state */
3736 i_vmstateChangeCallback(pUVM, pVMM, VMSTATE_SUSPENDED, enmVMState, this);
3737 }
3738 }
3739}
3740
3741/**
3742 * Process a medium change.
3743 *
3744 * @param aMediumAttachment The medium attachment with the new medium state.
3745 * @param fForce Force medium chance, if it is locked or not.
3746 * @param pUVM Safe VM handle.
3747 * @param pVMM Safe VMM vtable.
3748 *
3749 * @note Locks this object for writing.
3750 */
3751HRESULT Console::i_doMediumChange(IMediumAttachment *aMediumAttachment, bool fForce, PUVM pUVM, PCVMMR3VTABLE pVMM)
3752{
3753 AutoCaller autoCaller(this);
3754 AssertComRCReturnRC(autoCaller.hrc());
3755
3756 /* We will need to release the write lock before calling EMT */
3757 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
3758
3759 const char *pszDevice = NULL;
3760
3761 SafeIfaceArray<IStorageController> ctrls;
3762 HRESULT hrc = mMachine->COMGETTER(StorageControllers)(ComSafeArrayAsOutParam(ctrls));
3763 AssertComRC(hrc);
3764
3765 IMedium *pMedium = NULL;
3766 hrc = aMediumAttachment->COMGETTER(Medium)(&pMedium);
3767 AssertComRC(hrc);
3768
3769 Bstr mediumLocation;
3770 if (pMedium)
3771 {
3772 hrc = pMedium->COMGETTER(Location)(mediumLocation.asOutParam());
3773 AssertComRC(hrc);
3774 }
3775
3776 Bstr attCtrlName;
3777 hrc = aMediumAttachment->COMGETTER(Controller)(attCtrlName.asOutParam());
3778 AssertComRC(hrc);
3779 ComPtr<IStorageController> pStorageController;
3780 for (size_t i = 0; i < ctrls.size(); ++i)
3781 {
3782 Bstr ctrlName;
3783 hrc = ctrls[i]->COMGETTER(Name)(ctrlName.asOutParam());
3784 AssertComRC(hrc);
3785 if (attCtrlName == ctrlName)
3786 {
3787 pStorageController = ctrls[i];
3788 break;
3789 }
3790 }
3791 if (pStorageController.isNull())
3792 return setError(E_FAIL, tr("Could not find storage controller '%ls'"), attCtrlName.raw());
3793
3794 StorageControllerType_T enmCtrlType;
3795 hrc = pStorageController->COMGETTER(ControllerType)(&enmCtrlType);
3796 AssertComRC(hrc);
3797 pszDevice = i_storageControllerTypeToStr(enmCtrlType);
3798
3799 StorageBus_T enmBus;
3800 hrc = pStorageController->COMGETTER(Bus)(&enmBus);
3801 AssertComRC(hrc);
3802
3803 ULONG uInstance;
3804 hrc = pStorageController->COMGETTER(Instance)(&uInstance);
3805 AssertComRC(hrc);
3806
3807 BOOL fUseHostIOCache;
3808 hrc = pStorageController->COMGETTER(UseHostIOCache)(&fUseHostIOCache);
3809 AssertComRC(hrc);
3810
3811 /*
3812 * Suspend the VM first. The VM must not be running since it might have
3813 * pending I/O to the drive which is being changed.
3814 */
3815 bool fResume = false;
3816 hrc = i_suspendBeforeConfigChange(pUVM, pVMM, &alock, &fResume);
3817 if (FAILED(hrc))
3818 return hrc;
3819
3820 /*
3821 * Call worker on EMT #0, that's faster and safer than doing everything
3822 * using VMR3ReqCall. Note that we separate VMR3ReqCall from VMR3ReqWait
3823 * here to make requests from under the lock in order to serialize them.
3824 */
3825 PVMREQ pReq;
3826 int vrc = pVMM->pfnVMR3ReqCallU(pUVM, 0, &pReq, 0 /* no wait! */, VMREQFLAGS_VBOX_STATUS, (PFNRT)i_changeRemovableMedium, 9,
3827 this, pUVM, pVMM, pszDevice, uInstance, enmBus, fUseHostIOCache, aMediumAttachment, fForce);
3828
3829 /* release the lock before waiting for a result (EMT might wait for it, @bugref{7648})! */
3830 alock.release();
3831
3832 if (vrc == VERR_TIMEOUT)
3833 vrc = pVMM->pfnVMR3ReqWait(pReq, RT_INDEFINITE_WAIT);
3834 AssertRC(vrc);
3835 if (RT_SUCCESS(vrc))
3836 vrc = pReq->iStatus;
3837 pVMM->pfnVMR3ReqFree(pReq);
3838
3839 if (fResume)
3840 i_resumeAfterConfigChange(pUVM, pVMM);
3841
3842 if (RT_SUCCESS(vrc))
3843 {
3844 LogFlowThisFunc(("Returns S_OK\n"));
3845 return S_OK;
3846 }
3847
3848 if (pMedium)
3849 return setErrorBoth(E_FAIL, vrc, tr("Could not mount the media/drive '%ls' (%Rrc)"), mediumLocation.raw(), vrc);
3850 return setErrorBoth(E_FAIL, vrc, tr("Could not unmount the currently mounted media/drive (%Rrc)"), vrc);
3851}
3852
3853/**
3854 * Performs the medium change in EMT.
3855 *
3856 * @returns VBox status code.
3857 *
3858 * @param pThis Pointer to the Console object.
3859 * @param pUVM The VM handle.
3860 * @param pVMM The VMM vtable.
3861 * @param pcszDevice The PDM device name.
3862 * @param uInstance The PDM device instance.
3863 * @param enmBus The storage bus type of the controller.
3864 * @param fUseHostIOCache Whether to use the host I/O cache (disable async I/O).
3865 * @param aMediumAtt The medium attachment.
3866 * @param fForce Force unmounting.
3867 *
3868 * @thread EMT
3869 * @note The VM must not be running since it might have pending I/O to the drive which is being changed.
3870 */
3871DECLCALLBACK(int) Console::i_changeRemovableMedium(Console *pThis,
3872 PUVM pUVM,
3873 PCVMMR3VTABLE pVMM,
3874 const char *pcszDevice,
3875 unsigned uInstance,
3876 StorageBus_T enmBus,
3877 bool fUseHostIOCache,
3878 IMediumAttachment *aMediumAtt,
3879 bool fForce)
3880{
3881 LogFlowFunc(("pThis=%p uInstance=%u pszDevice=%p:{%s} enmBus=%u, aMediumAtt=%p, fForce=%d\n",
3882 pThis, uInstance, pcszDevice, pcszDevice, enmBus, aMediumAtt, fForce));
3883
3884 AssertReturn(pThis, VERR_INVALID_PARAMETER);
3885
3886 AutoCaller autoCaller(pThis);
3887 AssertComRCReturn(autoCaller.hrc(), VERR_ACCESS_DENIED);
3888
3889 /*
3890 * Check the VM for correct state.
3891 */
3892 VMSTATE enmVMState = pVMM->pfnVMR3GetStateU(pUVM);
3893 AssertReturn(enmVMState == VMSTATE_SUSPENDED, VERR_INVALID_STATE);
3894
3895 int vrc = pThis->i_configMediumAttachment(pcszDevice,
3896 uInstance,
3897 enmBus,
3898 fUseHostIOCache,
3899 false /* fSetupMerge */,
3900 false /* fBuiltinIOCache */,
3901 false /* fInsertDiskIntegrityDrv. */,
3902 0 /* uMergeSource */,
3903 0 /* uMergeTarget */,
3904 aMediumAtt,
3905 pThis->mMachineState,
3906 NULL /* phrc */,
3907 true /* fAttachDetach */,
3908 fForce /* fForceUnmount */,
3909 false /* fHotplug */,
3910 pUVM,
3911 pVMM,
3912 NULL /* paLedDevType */,
3913 NULL /* ppLunL0 */);
3914 LogFlowFunc(("Returning %Rrc\n", vrc));
3915 return vrc;
3916}
3917
3918
3919/**
3920 * Attach a new storage device to the VM.
3921 *
3922 * @param aMediumAttachment The medium attachment which is added.
3923 * @param pUVM Safe VM handle.
3924 * @param pVMM Safe VMM vtable.
3925 * @param fSilent Flag whether to notify the guest about the attached device.
3926 *
3927 * @note Locks this object for writing.
3928 */
3929HRESULT Console::i_doStorageDeviceAttach(IMediumAttachment *aMediumAttachment, PUVM pUVM, PCVMMR3VTABLE pVMM, bool fSilent)
3930{
3931 AutoCaller autoCaller(this);
3932 AssertComRCReturnRC(autoCaller.hrc());
3933
3934 /* We will need to release the write lock before calling EMT */
3935 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
3936
3937 const char *pszDevice = NULL;
3938
3939 SafeIfaceArray<IStorageController> ctrls;
3940 HRESULT hrc = mMachine->COMGETTER(StorageControllers)(ComSafeArrayAsOutParam(ctrls));
3941 AssertComRC(hrc);
3942
3943 IMedium *pMedium = NULL;
3944 hrc = aMediumAttachment->COMGETTER(Medium)(&pMedium);
3945 AssertComRC(hrc);
3946
3947 Bstr mediumLocation;
3948 if (pMedium)
3949 {
3950 hrc = pMedium->COMGETTER(Location)(mediumLocation.asOutParam());
3951 AssertComRC(hrc);
3952 }
3953
3954 Bstr attCtrlName;
3955 hrc = aMediumAttachment->COMGETTER(Controller)(attCtrlName.asOutParam());
3956 AssertComRC(hrc);
3957 ComPtr<IStorageController> pStorageController;
3958 for (size_t i = 0; i < ctrls.size(); ++i)
3959 {
3960 Bstr ctrlName;
3961 hrc = ctrls[i]->COMGETTER(Name)(ctrlName.asOutParam());
3962 AssertComRC(hrc);
3963 if (attCtrlName == ctrlName)
3964 {
3965 pStorageController = ctrls[i];
3966 break;
3967 }
3968 }
3969 if (pStorageController.isNull())
3970 return setError(E_FAIL, tr("Could not find storage controller '%ls'"), attCtrlName.raw());
3971
3972 StorageControllerType_T enmCtrlType;
3973 hrc = pStorageController->COMGETTER(ControllerType)(&enmCtrlType);
3974 AssertComRC(hrc);
3975 pszDevice = i_storageControllerTypeToStr(enmCtrlType);
3976
3977 StorageBus_T enmBus;
3978 hrc = pStorageController->COMGETTER(Bus)(&enmBus);
3979 AssertComRC(hrc);
3980
3981 ULONG uInstance;
3982 hrc = pStorageController->COMGETTER(Instance)(&uInstance);
3983 AssertComRC(hrc);
3984
3985 BOOL fUseHostIOCache;
3986 hrc = pStorageController->COMGETTER(UseHostIOCache)(&fUseHostIOCache);
3987 AssertComRC(hrc);
3988
3989 /*
3990 * Suspend the VM first. The VM must not be running since it might have
3991 * pending I/O to the drive which is being changed.
3992 */
3993 bool fResume = false;
3994 hrc = i_suspendBeforeConfigChange(pUVM, pVMM, &alock, &fResume);
3995 if (FAILED(hrc))
3996 return hrc;
3997
3998 /*
3999 * Call worker on EMT #0, that's faster and safer than doing everything
4000 * using VMR3ReqCall. Note that we separate VMR3ReqCall from VMR3ReqWait
4001 * here to make requests from under the lock in order to serialize them.
4002 */
4003 PVMREQ pReq;
4004 int vrc = pVMM->pfnVMR3ReqCallU(pUVM, 0, &pReq, 0 /* no wait! */, VMREQFLAGS_VBOX_STATUS, (PFNRT)i_attachStorageDevice, 9,
4005 this, pUVM, pVMM, pszDevice, uInstance, enmBus, fUseHostIOCache, aMediumAttachment, fSilent);
4006
4007 /* release the lock before waiting for a result (EMT might wait for it, @bugref{7648})! */
4008 alock.release();
4009
4010 if (vrc == VERR_TIMEOUT)
4011 vrc = pVMM->pfnVMR3ReqWait(pReq, RT_INDEFINITE_WAIT);
4012 AssertRC(vrc);
4013 if (RT_SUCCESS(vrc))
4014 vrc = pReq->iStatus;
4015 pVMM->pfnVMR3ReqFree(pReq);
4016
4017 if (fResume)
4018 i_resumeAfterConfigChange(pUVM, pVMM);
4019
4020 if (RT_SUCCESS(vrc))
4021 {
4022 LogFlowThisFunc(("Returns S_OK\n"));
4023 return S_OK;
4024 }
4025
4026 if (!pMedium)
4027 return setErrorBoth(E_FAIL, vrc, tr("Could not mount the media/drive '%ls' (%Rrc)"), mediumLocation.raw(), vrc);
4028 return setErrorBoth(E_FAIL, vrc, tr("Could not unmount the currently mounted media/drive (%Rrc)"), vrc);
4029}
4030
4031
4032/**
4033 * Performs the storage attach operation in EMT.
4034 *
4035 * @returns VBox status code.
4036 *
4037 * @param pThis Pointer to the Console object.
4038 * @param pUVM The VM handle.
4039 * @param pVMM The VMM vtable.
4040 * @param pcszDevice The PDM device name.
4041 * @param uInstance The PDM device instance.
4042 * @param enmBus The storage bus type of the controller.
4043 * @param fUseHostIOCache Whether to use the host I/O cache (disable async I/O).
4044 * @param aMediumAtt The medium attachment.
4045 * @param fSilent Flag whether to inform the guest about the attached device.
4046 *
4047 * @thread EMT
4048 * @note The VM must not be running since it might have pending I/O to the drive which is being changed.
4049 */
4050DECLCALLBACK(int) Console::i_attachStorageDevice(Console *pThis,
4051 PUVM pUVM,
4052 PCVMMR3VTABLE pVMM,
4053 const char *pcszDevice,
4054 unsigned uInstance,
4055 StorageBus_T enmBus,
4056 bool fUseHostIOCache,
4057 IMediumAttachment *aMediumAtt,
4058 bool fSilent)
4059{
4060 LogFlowFunc(("pThis=%p uInstance=%u pszDevice=%p:{%s} enmBus=%u, aMediumAtt=%p\n",
4061 pThis, uInstance, pcszDevice, pcszDevice, enmBus, aMediumAtt));
4062
4063 AssertReturn(pThis, VERR_INVALID_PARAMETER);
4064
4065 AutoCaller autoCaller(pThis);
4066 AssertComRCReturn(autoCaller.hrc(), VERR_ACCESS_DENIED);
4067
4068 /*
4069 * Check the VM for correct state.
4070 */
4071 VMSTATE enmVMState = pVMM->pfnVMR3GetStateU(pUVM);
4072 AssertReturn(enmVMState == VMSTATE_SUSPENDED, VERR_INVALID_STATE);
4073
4074 int vrc = pThis->i_configMediumAttachment(pcszDevice,
4075 uInstance,
4076 enmBus,
4077 fUseHostIOCache,
4078 false /* fSetupMerge */,
4079 false /* fBuiltinIOCache */,
4080 false /* fInsertDiskIntegrityDrv. */,
4081 0 /* uMergeSource */,
4082 0 /* uMergeTarget */,
4083 aMediumAtt,
4084 pThis->mMachineState,
4085 NULL /* phrc */,
4086 true /* fAttachDetach */,
4087 false /* fForceUnmount */,
4088 !fSilent /* fHotplug */,
4089 pUVM,
4090 pVMM,
4091 NULL /* paLedDevType */,
4092 NULL);
4093 LogFlowFunc(("Returning %Rrc\n", vrc));
4094 return vrc;
4095}
4096
4097/**
4098 * Attach a new storage device to the VM.
4099 *
4100 * @param aMediumAttachment The medium attachment which is added.
4101 * @param pUVM Safe VM handle.
4102 * @param pVMM Safe VMM vtable.
4103 * @param fSilent Flag whether to notify the guest about the detached device.
4104 *
4105 * @note Locks this object for writing.
4106 */
4107HRESULT Console::i_doStorageDeviceDetach(IMediumAttachment *aMediumAttachment, PUVM pUVM, PCVMMR3VTABLE pVMM, bool fSilent)
4108{
4109 AutoCaller autoCaller(this);
4110 AssertComRCReturnRC(autoCaller.hrc());
4111
4112 /* We will need to release the write lock before calling EMT */
4113 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
4114
4115 const char *pszDevice = NULL;
4116
4117 SafeIfaceArray<IStorageController> ctrls;
4118 HRESULT hrc = mMachine->COMGETTER(StorageControllers)(ComSafeArrayAsOutParam(ctrls));
4119 AssertComRC(hrc);
4120
4121 IMedium *pMedium = NULL;
4122 hrc = aMediumAttachment->COMGETTER(Medium)(&pMedium);
4123 AssertComRC(hrc);
4124
4125 Bstr mediumLocation;
4126 if (pMedium)
4127 {
4128 hrc = pMedium->COMGETTER(Location)(mediumLocation.asOutParam());
4129 AssertComRC(hrc);
4130 }
4131
4132 Bstr attCtrlName;
4133 hrc = aMediumAttachment->COMGETTER(Controller)(attCtrlName.asOutParam());
4134 AssertComRC(hrc);
4135 ComPtr<IStorageController> pStorageController;
4136 for (size_t i = 0; i < ctrls.size(); ++i)
4137 {
4138 Bstr ctrlName;
4139 hrc = ctrls[i]->COMGETTER(Name)(ctrlName.asOutParam());
4140 AssertComRC(hrc);
4141 if (attCtrlName == ctrlName)
4142 {
4143 pStorageController = ctrls[i];
4144 break;
4145 }
4146 }
4147 if (pStorageController.isNull())
4148 return setError(E_FAIL, tr("Could not find storage controller '%ls'"), attCtrlName.raw());
4149
4150 StorageControllerType_T enmCtrlType;
4151 hrc = pStorageController->COMGETTER(ControllerType)(&enmCtrlType);
4152 AssertComRC(hrc);
4153 pszDevice = i_storageControllerTypeToStr(enmCtrlType);
4154
4155 StorageBus_T enmBus = (StorageBus_T)0;
4156 hrc = pStorageController->COMGETTER(Bus)(&enmBus);
4157 AssertComRC(hrc);
4158
4159 ULONG uInstance = 0;
4160 hrc = pStorageController->COMGETTER(Instance)(&uInstance);
4161 AssertComRC(hrc);
4162
4163 /*
4164 * Suspend the VM first. The VM must not be running since it might have
4165 * pending I/O to the drive which is being changed.
4166 */
4167 bool fResume = false;
4168 hrc = i_suspendBeforeConfigChange(pUVM, pVMM, &alock, &fResume);
4169 if (FAILED(hrc))
4170 return hrc;
4171
4172 /*
4173 * Call worker on EMT #0, that's faster and safer than doing everything
4174 * using VMR3ReqCall. Note that we separate VMR3ReqCall from VMR3ReqWait
4175 * here to make requests from under the lock in order to serialize them.
4176 */
4177 PVMREQ pReq;
4178 int vrc = pVMM->pfnVMR3ReqCallU(pUVM, 0, &pReq, 0 /* no wait! */, VMREQFLAGS_VBOX_STATUS, (PFNRT)i_detachStorageDevice, 8,
4179 this, pUVM, pVMM, pszDevice, uInstance, enmBus, aMediumAttachment, fSilent);
4180
4181 /* release the lock before waiting for a result (EMT might wait for it, @bugref{7648})! */
4182 alock.release();
4183
4184 if (vrc == VERR_TIMEOUT)
4185 vrc = pVMM->pfnVMR3ReqWait(pReq, RT_INDEFINITE_WAIT);
4186 AssertRC(vrc);
4187 if (RT_SUCCESS(vrc))
4188 vrc = pReq->iStatus;
4189 pVMM->pfnVMR3ReqFree(pReq);
4190
4191 if (fResume)
4192 i_resumeAfterConfigChange(pUVM, pVMM);
4193
4194 if (RT_SUCCESS(vrc))
4195 {
4196 LogFlowThisFunc(("Returns S_OK\n"));
4197 return S_OK;
4198 }
4199
4200 if (!pMedium)
4201 return setErrorBoth(E_FAIL, vrc, tr("Could not mount the media/drive '%ls' (%Rrc)"), mediumLocation.raw(), vrc);
4202 return setErrorBoth(E_FAIL, vrc, tr("Could not unmount the currently mounted media/drive (%Rrc)"), vrc);
4203}
4204
4205/**
4206 * Performs the storage detach operation in EMT.
4207 *
4208 * @returns VBox status code.
4209 *
4210 * @param pThis Pointer to the Console object.
4211 * @param pUVM The VM handle.
4212 * @param pVMM The VMM vtable.
4213 * @param pcszDevice The PDM device name.
4214 * @param uInstance The PDM device instance.
4215 * @param enmBus The storage bus type of the controller.
4216 * @param pMediumAtt Pointer to the medium attachment.
4217 * @param fSilent Flag whether to notify the guest about the detached device.
4218 *
4219 * @thread EMT
4220 * @note The VM must not be running since it might have pending I/O to the drive which is being changed.
4221 */
4222DECLCALLBACK(int) Console::i_detachStorageDevice(Console *pThis,
4223 PUVM pUVM,
4224 PCVMMR3VTABLE pVMM,
4225 const char *pcszDevice,
4226 unsigned uInstance,
4227 StorageBus_T enmBus,
4228 IMediumAttachment *pMediumAtt,
4229 bool fSilent)
4230{
4231 LogRelFlowFunc(("pThis=%p uInstance=%u pszDevice=%p:{%s} enmBus=%u, pMediumAtt=%p\n",
4232 pThis, uInstance, pcszDevice, pcszDevice, enmBus, pMediumAtt));
4233
4234 AssertReturn(pThis, VERR_INVALID_PARAMETER);
4235
4236 AutoCaller autoCaller(pThis);
4237 AssertComRCReturn(autoCaller.hrc(), VERR_ACCESS_DENIED);
4238
4239 /*
4240 * Check the VM for correct state.
4241 */
4242 VMSTATE enmVMState = pVMM->pfnVMR3GetStateU(pUVM);
4243 AssertReturn(enmVMState == VMSTATE_SUSPENDED, VERR_INVALID_STATE);
4244
4245 /* Determine the base path for the device instance. */
4246 PCFGMNODE pCtlInst = pVMM->pfnCFGMR3GetChildF(pVMM->pfnCFGMR3GetRootU(pUVM), "Devices/%s/%u/", pcszDevice, uInstance);
4247 AssertReturn(pCtlInst || enmBus == StorageBus_USB, VERR_INTERNAL_ERROR);
4248
4249#define H() AssertMsgReturn(!FAILED(hrc), ("hrc=%Rhrc\n", hrc), VERR_GENERAL_FAILURE)
4250
4251 HRESULT hrc;
4252 int vrc = VINF_SUCCESS;
4253 LONG lDev;
4254 hrc = pMediumAtt->COMGETTER(Device)(&lDev); H();
4255 LONG lPort;
4256 hrc = pMediumAtt->COMGETTER(Port)(&lPort); H();
4257 DeviceType_T lType;
4258 hrc = pMediumAtt->COMGETTER(Type)(&lType); H();
4259 unsigned uLUN;
4260 hrc = Console::i_storageBusPortDeviceToLun(enmBus, lPort, lDev, uLUN); H();
4261
4262#undef H
4263
4264 PCFGMNODE pLunL0 = NULL;
4265 if (enmBus != StorageBus_USB)
4266 {
4267 /* First check if the LUN really exists. */
4268 pLunL0 = pVMM->pfnCFGMR3GetChildF(pCtlInst, "LUN#%u", uLUN);
4269 if (pLunL0)
4270 {
4271 uint32_t fFlags = 0;
4272 if (fSilent)
4273 fFlags |= PDM_TACH_FLAGS_NOT_HOT_PLUG;
4274
4275 vrc = pVMM->pfnPDMR3DeviceDetach(pUVM, pcszDevice, uInstance, uLUN, fFlags);
4276 if (vrc == VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN)
4277 vrc = VINF_SUCCESS;
4278 AssertLogRelRCReturn(vrc, vrc);
4279 pVMM->pfnCFGMR3RemoveNode(pLunL0);
4280
4281 Utf8StrFmt devicePath("%s/%u/LUN#%u", pcszDevice, uInstance, uLUN);
4282 pThis->mapMediumAttachments.erase(devicePath);
4283 }
4284 else
4285 AssertLogRelFailedReturn(VERR_INTERNAL_ERROR);
4286
4287 pVMM->pfnCFGMR3Dump(pCtlInst);
4288 }
4289#ifdef VBOX_WITH_USB
4290 else
4291 {
4292 /* Find the correct USB device in the list. */
4293 USBStorageDeviceList::iterator it;
4294 for (it = pThis->mUSBStorageDevices.begin(); it != pThis->mUSBStorageDevices.end(); ++it)
4295 if (it->iPort == lPort)
4296 break;
4297 AssertLogRelReturn(it != pThis->mUSBStorageDevices.end(), VERR_INTERNAL_ERROR);
4298
4299 vrc = pVMM->pfnPDMR3UsbDetachDevice(pUVM, &it->mUuid);
4300 AssertLogRelRCReturn(vrc, vrc);
4301 pThis->mUSBStorageDevices.erase(it);
4302 }
4303#endif
4304
4305 LogFlowFunc(("Returning VINF_SUCCESS\n"));
4306 return VINF_SUCCESS;
4307}
4308
4309/**
4310 * Called by IInternalSessionControl::OnNetworkAdapterChange().
4311 *
4312 * @note Locks this object for writing.
4313 */
4314HRESULT Console::i_onNetworkAdapterChange(INetworkAdapter *aNetworkAdapter, BOOL changeAdapter)
4315{
4316 LogFlowThisFunc(("\n"));
4317
4318 AutoCaller autoCaller(this);
4319 AssertComRCReturnRC(autoCaller.hrc());
4320
4321 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
4322
4323 HRESULT hrc = S_OK;
4324
4325 /* don't trigger network changes if the VM isn't running */
4326 SafeVMPtrQuiet ptrVM(this);
4327 if (ptrVM.isOk())
4328 {
4329 /* Get the properties we need from the adapter */
4330 BOOL fCableConnected, fTraceEnabled;
4331 hrc = aNetworkAdapter->COMGETTER(CableConnected)(&fCableConnected);
4332 AssertComRC(hrc);
4333 if (SUCCEEDED(hrc))
4334 {
4335 hrc = aNetworkAdapter->COMGETTER(TraceEnabled)(&fTraceEnabled);
4336 AssertComRC(hrc);
4337 if (SUCCEEDED(hrc))
4338 {
4339 ULONG ulInstance;
4340 hrc = aNetworkAdapter->COMGETTER(Slot)(&ulInstance);
4341 AssertComRC(hrc);
4342 if (SUCCEEDED(hrc))
4343 {
4344 /*
4345 * Find the adapter instance, get the config interface and update
4346 * the link state.
4347 */
4348 NetworkAdapterType_T adapterType;
4349 hrc = aNetworkAdapter->COMGETTER(AdapterType)(&adapterType);
4350 AssertComRC(hrc);
4351 const char *pszAdapterName = networkAdapterTypeToName(adapterType);
4352
4353 // prevent cross-thread deadlocks, don't need the lock any more
4354 alock.release();
4355
4356 PPDMIBASE pBase = NULL;
4357 int vrc = VINF_SUCCESS;
4358 if (adapterType == NetworkAdapterType_UsbNet)
4359 vrc = ptrVM.vtable()->pfnPDMR3UsbQueryLun(ptrVM.rawUVM(), pszAdapterName, ulInstance, 0, &pBase);
4360 else
4361 vrc = ptrVM.vtable()->pfnPDMR3QueryDeviceLun(ptrVM.rawUVM(), pszAdapterName, ulInstance, 0, &pBase);
4362 if (RT_SUCCESS(vrc))
4363 {
4364 Assert(pBase);
4365 PPDMINETWORKCONFIG pINetCfg;
4366 pINetCfg = PDMIBASE_QUERY_INTERFACE(pBase, PDMINETWORKCONFIG);
4367 if (pINetCfg)
4368 {
4369 Log(("Console::onNetworkAdapterChange: setting link state to %d\n",
4370 fCableConnected));
4371 vrc = pINetCfg->pfnSetLinkState(pINetCfg,
4372 fCableConnected ? PDMNETWORKLINKSTATE_UP
4373 : PDMNETWORKLINKSTATE_DOWN);
4374 ComAssertRC(vrc);
4375 }
4376 if (RT_SUCCESS(vrc) && changeAdapter)
4377 {
4378 VMSTATE enmVMState = mpVMM->pfnVMR3GetStateU(ptrVM.rawUVM());
4379 if ( enmVMState == VMSTATE_RUNNING /** @todo LiveMigration: Forbid or deal
4380 correctly with the _LS variants */
4381 || enmVMState == VMSTATE_SUSPENDED)
4382 {
4383 if (fTraceEnabled && fCableConnected && pINetCfg)
4384 {
4385 vrc = pINetCfg->pfnSetLinkState(pINetCfg, PDMNETWORKLINKSTATE_DOWN);
4386 ComAssertRC(vrc);
4387 }
4388
4389 hrc = i_doNetworkAdapterChange(ptrVM.rawUVM(), ptrVM.vtable(), pszAdapterName,
4390 ulInstance, 0, aNetworkAdapter);
4391
4392 if (fTraceEnabled && fCableConnected && pINetCfg)
4393 {
4394 vrc = pINetCfg->pfnSetLinkState(pINetCfg, PDMNETWORKLINKSTATE_UP);
4395 ComAssertRC(vrc);
4396 }
4397 }
4398 }
4399 }
4400 else if (vrc == VERR_PDM_DEVICE_INSTANCE_NOT_FOUND)
4401 return setErrorBoth(E_FAIL, vrc, tr("The network adapter #%u is not enabled"), ulInstance);
4402 else
4403 ComAssertRC(vrc);
4404
4405 if (RT_FAILURE(vrc))
4406 hrc = E_FAIL;
4407
4408 alock.acquire();
4409 }
4410 }
4411 }
4412 ptrVM.release();
4413 }
4414
4415 // definitely don't need the lock any more
4416 alock.release();
4417
4418 /* notify console callbacks on success */
4419 if (SUCCEEDED(hrc))
4420 ::FireNetworkAdapterChangedEvent(mEventSource, aNetworkAdapter);
4421
4422 LogFlowThisFunc(("Leaving hrc=%#x\n", hrc));
4423 return hrc;
4424}
4425
4426/**
4427 * Called by IInternalSessionControl::OnNATEngineChange().
4428 *
4429 * @note Locks this object for writing.
4430 */
4431HRESULT Console::i_onNATRedirectRuleChanged(ULONG ulInstance, BOOL aNatRuleRemove, NATProtocol_T aProto, IN_BSTR aHostIP,
4432 LONG aHostPort, IN_BSTR aGuestIP, LONG aGuestPort)
4433{
4434 LogFlowThisFunc(("\n"));
4435
4436 AutoCaller autoCaller(this);
4437 AssertComRCReturnRC(autoCaller.hrc());
4438
4439 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
4440
4441 HRESULT hrc = S_OK;
4442
4443 /* don't trigger NAT engine changes if the VM isn't running */
4444 SafeVMPtrQuiet ptrVM(this);
4445 if (ptrVM.isOk())
4446 {
4447 do
4448 {
4449 ComPtr<INetworkAdapter> pNetworkAdapter;
4450 hrc = i_machine()->GetNetworkAdapter(ulInstance, pNetworkAdapter.asOutParam());
4451 if ( FAILED(hrc)
4452 || pNetworkAdapter.isNull())
4453 break;
4454
4455 /*
4456 * Find the adapter instance, get the config interface and update
4457 * the link state.
4458 */
4459 NetworkAdapterType_T adapterType;
4460 hrc = pNetworkAdapter->COMGETTER(AdapterType)(&adapterType);
4461 if (FAILED(hrc))
4462 {
4463 AssertComRC(hrc);
4464 hrc = E_FAIL;
4465 break;
4466 }
4467
4468 const char *pszAdapterName = networkAdapterTypeToName(adapterType);
4469 PPDMIBASE pBase;
4470 int vrc = ptrVM.vtable()->pfnPDMR3QueryLun(ptrVM.rawUVM(), pszAdapterName, ulInstance, 0, &pBase);
4471 if (RT_FAILURE(vrc))
4472 {
4473 /* This may happen if the NAT network adapter is currently not attached.
4474 * This is a valid condition. */
4475 if (vrc == VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN)
4476 break;
4477 ComAssertRC(vrc);
4478 hrc = E_FAIL;
4479 break;
4480 }
4481
4482 NetworkAttachmentType_T attachmentType;
4483 hrc = pNetworkAdapter->COMGETTER(AttachmentType)(&attachmentType);
4484 if ( FAILED(hrc)
4485 || attachmentType != NetworkAttachmentType_NAT)
4486 {
4487 hrc = E_FAIL;
4488 break;
4489 }
4490
4491 /* look down for PDMINETWORKNATCONFIG interface */
4492 PPDMINETWORKNATCONFIG pNetNatCfg = NULL;
4493 while (pBase)
4494 {
4495 pNetNatCfg = (PPDMINETWORKNATCONFIG)pBase->pfnQueryInterface(pBase, PDMINETWORKNATCONFIG_IID);
4496 if (pNetNatCfg)
4497 break;
4498 /** @todo r=bird: This stinks! */
4499 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pBase);
4500 pBase = pDrvIns->pDownBase;
4501 }
4502 if (!pNetNatCfg)
4503 break;
4504
4505 bool fUdp = aProto == NATProtocol_UDP;
4506 vrc = pNetNatCfg->pfnRedirectRuleCommand(pNetNatCfg, !!aNatRuleRemove, fUdp,
4507 Utf8Str(aHostIP).c_str(), (uint16_t)aHostPort, Utf8Str(aGuestIP).c_str(),
4508 (uint16_t)aGuestPort);
4509 if (RT_FAILURE(vrc))
4510 hrc = E_FAIL;
4511 } while (0); /* break loop */
4512 ptrVM.release();
4513 }
4514
4515 LogFlowThisFunc(("Leaving hrc=%#x\n", hrc));
4516 return hrc;
4517}
4518
4519
4520/** Helper that converts a BSTR safe array into a C-string array. */
4521static char **bstrSafeArrayToC(SafeArray<BSTR> const &a_rStrings, size_t *pcEntries) RT_NOEXCEPT
4522{
4523 if (pcEntries)
4524 *pcEntries = 0;
4525
4526 /*
4527 * The array is NULL terminated.
4528 */
4529 const size_t cStrings = a_rStrings.size();
4530 char **papszRet = (char **)RTMemAllocZ((cStrings + 1) * sizeof(papszRet[0]));
4531 AssertReturn(papszRet, NULL);
4532
4533 /*
4534 * The individual strings.
4535 */
4536 for (size_t i = 0; i < cStrings; i++)
4537 {
4538 int vrc = RTUtf16ToUtf8Ex((PCRTUTF16)a_rStrings[i], RTSTR_MAX, &papszRet[i], 0, NULL);
4539 AssertRC(vrc);
4540 if (RT_FAILURE(vrc))
4541 {
4542 while (i-- > 0)
4543 {
4544 RTStrFree(papszRet[i]);
4545 papszRet[i] = NULL;
4546 }
4547 return NULL;
4548 }
4549
4550 }
4551 if (pcEntries)
4552 *pcEntries = cStrings;
4553 return papszRet;
4554}
4555
4556
4557/**
4558 * IHostNameResolutionConfigurationChangeEvent
4559 *
4560 * Currently this event doesn't carry actual resolver configuration,
4561 * so we have to go back to VBoxSVC and ask... This is not ideal.
4562 */
4563HRESULT Console::i_onNATDnsChanged()
4564{
4565 AutoCaller autoCaller(this);
4566 AssertComRCReturnRC(autoCaller.hrc());
4567
4568 /* We wrap PDMINETWORKNATDNSCONFIG to simplify freeing memory allocations
4569 in it (exceptions, AssertReturn, regular returns). */
4570 struct DnsConfigCleanupWrapper
4571 {
4572 PDMINETWORKNATDNSCONFIG Core;
4573
4574 DnsConfigCleanupWrapper()
4575 {
4576 Core.szDomainName[0] = '\0';
4577 Core.cNameServers = 0;
4578 Core.papszNameServers = NULL;
4579 Core.cSearchDomains = 0;
4580 Core.papszSearchDomains = NULL;
4581 }
4582
4583 void freeStrArray(char **papsz)
4584 {
4585 if (papsz)
4586 {
4587 for (size_t i = 0; papsz[i] != NULL; i++)
4588 RTStrFree(papsz[i]);
4589 RTMemFree(papsz);
4590 }
4591 }
4592
4593 ~DnsConfigCleanupWrapper()
4594 {
4595 freeStrArray((char **)Core.papszNameServers);
4596 Core.papszNameServers = NULL;
4597 freeStrArray((char **)Core.papszSearchDomains);
4598 Core.papszSearchDomains = NULL;
4599 }
4600 } DnsConfig;
4601
4602
4603 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS); /** @todo r=bird: Why a write lock? */
4604
4605 ComPtr<IVirtualBox> ptrVirtualBox;
4606 HRESULT hrc = mMachine->COMGETTER(Parent)(ptrVirtualBox.asOutParam());
4607 if (FAILED(hrc))
4608 return S_OK;
4609
4610 ComPtr<IHost> ptrHost;
4611 hrc = ptrVirtualBox->COMGETTER(Host)(ptrHost.asOutParam());
4612 if (FAILED(hrc))
4613 return S_OK;
4614
4615 /* Domain name: */
4616 {
4617 com::Bstr bstrDomain;
4618 ptrHost->COMGETTER(DomainName)(bstrDomain.asOutParam());
4619 com::Utf8Str const strDomainName(bstrDomain);
4620 int vrc = RTStrCopy(DnsConfig.Core.szDomainName, sizeof(DnsConfig.Core.szDomainName), strDomainName.c_str());
4621 AssertRC(vrc);
4622 }
4623 Log(("domain name = \"%s\"\n", DnsConfig.Core.szDomainName));
4624
4625 /* Name servers: */
4626 {
4627 SafeArray<BSTR> nameServers;
4628 hrc = ptrHost->COMGETTER(NameServers)(ComSafeArrayAsOutParam(nameServers));
4629 if (FAILED(hrc))
4630 return S_OK;
4631 DnsConfig.Core.papszNameServers = bstrSafeArrayToC(nameServers, &DnsConfig.Core.cNameServers);
4632 if (!DnsConfig.Core.papszNameServers)
4633 return E_OUTOFMEMORY;
4634 }
4635 Log(("DNS change - %zu nameservers\n", DnsConfig.Core.cNameServers));
4636 for (size_t i = 0; i < DnsConfig.Core.cNameServers; i++)
4637 Log(("- papszNameServers[%zu] = \"%s\"\n", i, DnsConfig.Core.papszNameServers[i]));
4638
4639 /* Search domains: */
4640 {
4641 SafeArray<BSTR> searchDomains;
4642 hrc = ptrHost->COMGETTER(SearchStrings)(ComSafeArrayAsOutParam(searchDomains));
4643 if (FAILED(hrc))
4644 return S_OK;
4645 DnsConfig.Core.papszSearchDomains = bstrSafeArrayToC(searchDomains, &DnsConfig.Core.cSearchDomains);
4646 if (!DnsConfig.Core.papszSearchDomains)
4647 return E_OUTOFMEMORY;
4648 }
4649 Log(("Search Domain change - %u domains\n", DnsConfig.Core.cSearchDomains));
4650 for (size_t i = 0; i < DnsConfig.Core.cSearchDomains; i++)
4651 Log(("- papszSearchDomain[%zu] = \"%s\"\n", i, DnsConfig.Core.papszSearchDomains[i]));
4652
4653 /*
4654 * Notify all the NAT drivers.
4655 */
4656 SafeVMPtrQuiet ptrVM(this);
4657 if (ptrVM.isOk())
4658 ptrVM.vtable()->pfnPDMR3DriverEnumInstances(ptrVM.rawUVM(), "NAT", Console::notifyNatDnsChangeCallback, &DnsConfig.Core);
4659
4660 return S_OK;
4661}
4662
4663/**
4664 * @callback_method_impl{FNPDMENUMDRVINS,Helper for Console::i_onNATDnsChanged.}
4665 */
4666/*static*/ DECLCALLBACK(int)
4667Console::notifyNatDnsChangeCallback(PPDMIBASE pIBase, uint32_t uDrvInstance, bool fUsbDev, const char *pszDevice,
4668 uint32_t uDevInstance, unsigned uLun, void *pvUser)
4669{
4670 PPDMINETWORKNATCONFIG const pINetNatCfg = (PPDMINETWORKNATCONFIG)pIBase->pfnQueryInterface(pIBase, PDMINETWORKNATCONFIG_IID);
4671 if (pINetNatCfg && pINetNatCfg->pfnNotifyDnsChanged)
4672 {
4673 LogFunc(("Notifying instance #%u attached to %s%s#%u on lun #%u...\n",
4674 uDrvInstance, fUsbDev ? "usb device " : "", pszDevice, uDevInstance, uLun));
4675 pINetNatCfg->pfnNotifyDnsChanged(pINetNatCfg, (PCPDMINETWORKNATDNSCONFIG)pvUser);
4676 }
4677 else
4678 LogFunc(("Not notifying instance #%u attached to %s%s#%u on lun #%u: pINetNatCfg=%p pfnNotifyDnsChanged=%p\n",
4679 uDrvInstance, fUsbDev ? "usb device " : "", pszDevice, uDevInstance, uLun,
4680 pINetNatCfg, pINetNatCfg ? pINetNatCfg->pfnNotifyDnsChanged : NULL));
4681
4682 RT_NOREF(uDrvInstance, fUsbDev, pszDevice, uDevInstance, uLun);
4683 return VINF_SUCCESS;
4684}
4685
4686VMMDevMouseInterface *Console::i_getVMMDevMouseInterface()
4687{
4688 return m_pVMMDev;
4689}
4690
4691DisplayMouseInterface *Console::i_getDisplayMouseInterface()
4692{
4693 return mDisplay;
4694}
4695
4696/**
4697 * Parses one key value pair.
4698 *
4699 * @returns VBox status code.
4700 * @param psz Configuration string.
4701 * @param ppszEnd Where to store the pointer to the string following the key value pair.
4702 * @param ppszKey Where to store the key on success.
4703 * @param ppszVal Where to store the value on success.
4704 */
4705int Console::i_consoleParseKeyValue(const char *psz, const char **ppszEnd, char **ppszKey, char **ppszVal)
4706{
4707 const char *pszKeyStart = psz;
4708 while ( *psz != '='
4709 && *psz)
4710 psz++;
4711
4712 /* End of string at this point is invalid. */
4713 if (*psz == '\0')
4714 return VERR_INVALID_PARAMETER;
4715
4716 size_t const cchKey = psz - pszKeyStart;
4717
4718 psz++; /* Skip '=' character */
4719 const char *pszValStart = psz;
4720
4721 while ( *psz != ','
4722 && *psz != '\n'
4723 && *psz != '\r'
4724 && *psz)
4725 psz++;
4726 size_t const cchVal = psz - pszValStart;
4727
4728 int vrc = VINF_SUCCESS;
4729 if (cchKey && cchVal)
4730 {
4731 *ppszKey = RTStrDupN(pszKeyStart, cchKey);
4732 if (*ppszKey)
4733 {
4734 *ppszVal = RTStrDupN(pszValStart, cchVal);
4735 if (*ppszVal)
4736 *ppszEnd = psz;
4737 else
4738 {
4739 RTStrFree(*ppszKey);
4740 vrc = VERR_NO_STR_MEMORY;
4741 }
4742 }
4743 else
4744 vrc = VERR_NO_STR_MEMORY;
4745 }
4746 else
4747 vrc = VERR_INVALID_PARAMETER;
4748
4749 return vrc;
4750}
4751
4752/**
4753 * Initializes the secret key interface on all configured attachments.
4754 *
4755 * @returns COM status code.
4756 */
4757HRESULT Console::i_initSecretKeyIfOnAllAttachments(void)
4758{
4759 HRESULT hrc = S_OK;
4760 SafeIfaceArray<IMediumAttachment> sfaAttachments;
4761
4762 AutoCaller autoCaller(this);
4763 AssertComRCReturnRC(autoCaller.hrc());
4764
4765 /* Get the VM - must be done before the read-locking. */
4766 SafeVMPtr ptrVM(this);
4767 if (!ptrVM.isOk())
4768 return ptrVM.hrc();
4769
4770 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
4771
4772 hrc = mMachine->COMGETTER(MediumAttachments)(ComSafeArrayAsOutParam(sfaAttachments));
4773 AssertComRCReturnRC(hrc);
4774
4775#ifdef VBOX_WITH_FULL_VM_ENCRYPTION
4776 m_cDisksPwProvided = 0;
4777#endif
4778
4779 /* Find the correct attachment. */
4780 for (unsigned i = 0; i < sfaAttachments.size(); i++)
4781 {
4782 const ComPtr<IMediumAttachment> &pAtt = sfaAttachments[i];
4783
4784#ifdef VBOX_WITH_FULL_VM_ENCRYPTION
4785 ComPtr<IMedium> pMedium;
4786 ComPtr<IMedium> pBase;
4787
4788 hrc = pAtt->COMGETTER(Medium)(pMedium.asOutParam());
4789 AssertComRC(hrc);
4790
4791 bool fKeepSecIf = false;
4792 /* Skip non hard disk attachments. */
4793 if (pMedium.isNotNull())
4794 {
4795 /* Get the UUID of the base medium and compare. */
4796 hrc = pMedium->COMGETTER(Base)(pBase.asOutParam());
4797 AssertComRC(hrc);
4798
4799 Bstr bstrKeyId;
4800 hrc = pBase->GetProperty(Bstr("CRYPT/KeyId").raw(), bstrKeyId.asOutParam());
4801 if (SUCCEEDED(hrc))
4802 {
4803 Utf8Str strKeyId(bstrKeyId);
4804 SecretKey *pKey = NULL;
4805 int vrc = m_pKeyStore->retainSecretKey(strKeyId, &pKey);
4806 if (RT_SUCCESS(vrc))
4807 {
4808 fKeepSecIf = true;
4809 m_pKeyStore->releaseSecretKey(strKeyId);
4810 }
4811 }
4812 }
4813#endif
4814
4815 /*
4816 * Query storage controller, port and device
4817 * to identify the correct driver.
4818 */
4819 ComPtr<IStorageController> pStorageCtrl;
4820 Bstr storageCtrlName;
4821 LONG lPort, lDev;
4822 ULONG ulStorageCtrlInst;
4823
4824 hrc = pAtt->COMGETTER(Controller)(storageCtrlName.asOutParam());
4825 AssertComRC(hrc);
4826
4827 hrc = pAtt->COMGETTER(Port)(&lPort);
4828 AssertComRC(hrc);
4829
4830 hrc = pAtt->COMGETTER(Device)(&lDev);
4831 AssertComRC(hrc);
4832
4833 hrc = mMachine->GetStorageControllerByName(storageCtrlName.raw(), pStorageCtrl.asOutParam());
4834 AssertComRC(hrc);
4835
4836 hrc = pStorageCtrl->COMGETTER(Instance)(&ulStorageCtrlInst);
4837 AssertComRC(hrc);
4838
4839 StorageControllerType_T enmCtrlType;
4840 hrc = pStorageCtrl->COMGETTER(ControllerType)(&enmCtrlType);
4841 AssertComRC(hrc);
4842 const char *pcszDevice = i_storageControllerTypeToStr(enmCtrlType);
4843
4844 StorageBus_T enmBus;
4845 hrc = pStorageCtrl->COMGETTER(Bus)(&enmBus);
4846 AssertComRC(hrc);
4847
4848 unsigned uLUN;
4849 hrc = Console::i_storageBusPortDeviceToLun(enmBus, lPort, lDev, uLUN);
4850 AssertComRC(hrc);
4851
4852 PPDMIBASE pIBase = NULL;
4853 PPDMIMEDIA pIMedium = NULL;
4854 int vrc = ptrVM.vtable()->pfnPDMR3QueryDriverOnLun(ptrVM.rawUVM(), pcszDevice, ulStorageCtrlInst, uLUN, "VD", &pIBase);
4855 if (RT_SUCCESS(vrc))
4856 {
4857 if (pIBase)
4858 {
4859 pIMedium = (PPDMIMEDIA)pIBase->pfnQueryInterface(pIBase, PDMIMEDIA_IID);
4860 if (pIMedium)
4861 {
4862#ifdef VBOX_WITH_FULL_VM_ENCRYPTION
4863 vrc = pIMedium->pfnSetSecKeyIf(pIMedium, fKeepSecIf ? mpIfSecKey : NULL, mpIfSecKeyHlp);
4864 Assert(RT_SUCCESS(vrc) || vrc == VERR_NOT_SUPPORTED);
4865 if (fKeepSecIf)
4866 m_cDisksPwProvided++;
4867#else
4868 vrc = pIMedium->pfnSetSecKeyIf(pIMedium, NULL, mpIfSecKeyHlp);
4869 Assert(RT_SUCCESS(vrc) || vrc == VERR_NOT_SUPPORTED);
4870#endif
4871 }
4872 }
4873 }
4874 }
4875
4876 return hrc;
4877}
4878
4879/**
4880 * Removes the key interfaces from all disk attachments with the given key ID.
4881 * Useful when changing the key store or dropping it.
4882 *
4883 * @returns COM status code.
4884 * @param strId The ID to look for.
4885 */
4886HRESULT Console::i_clearDiskEncryptionKeysOnAllAttachmentsWithKeyId(const Utf8Str &strId)
4887{
4888 HRESULT hrc = S_OK;
4889 SafeIfaceArray<IMediumAttachment> sfaAttachments;
4890
4891 /* Get the VM - must be done before the read-locking. */
4892 SafeVMPtr ptrVM(this);
4893 if (!ptrVM.isOk())
4894 return ptrVM.hrc();
4895
4896 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
4897
4898 hrc = mMachine->COMGETTER(MediumAttachments)(ComSafeArrayAsOutParam(sfaAttachments));
4899 AssertComRCReturnRC(hrc);
4900
4901 /* Find the correct attachment. */
4902 for (unsigned i = 0; i < sfaAttachments.size(); i++)
4903 {
4904 const ComPtr<IMediumAttachment> &pAtt = sfaAttachments[i];
4905 ComPtr<IMedium> pMedium;
4906 ComPtr<IMedium> pBase;
4907 Bstr bstrKeyId;
4908
4909 hrc = pAtt->COMGETTER(Medium)(pMedium.asOutParam());
4910 if (FAILED(hrc))
4911 break;
4912
4913 /* Skip non hard disk attachments. */
4914 if (pMedium.isNull())
4915 continue;
4916
4917 /* Get the UUID of the base medium and compare. */
4918 hrc = pMedium->COMGETTER(Base)(pBase.asOutParam());
4919 if (FAILED(hrc))
4920 break;
4921
4922 hrc = pBase->GetProperty(Bstr("CRYPT/KeyId").raw(), bstrKeyId.asOutParam());
4923 if (hrc == VBOX_E_OBJECT_NOT_FOUND)
4924 {
4925 hrc = S_OK;
4926 continue;
4927 }
4928 else if (FAILED(hrc))
4929 break;
4930
4931 if (strId.equals(Utf8Str(bstrKeyId)))
4932 {
4933
4934 /*
4935 * Query storage controller, port and device
4936 * to identify the correct driver.
4937 */
4938 ComPtr<IStorageController> pStorageCtrl;
4939 Bstr storageCtrlName;
4940 LONG lPort, lDev;
4941 ULONG ulStorageCtrlInst;
4942
4943 hrc = pAtt->COMGETTER(Controller)(storageCtrlName.asOutParam());
4944 AssertComRC(hrc);
4945
4946 hrc = pAtt->COMGETTER(Port)(&lPort);
4947 AssertComRC(hrc);
4948
4949 hrc = pAtt->COMGETTER(Device)(&lDev);
4950 AssertComRC(hrc);
4951
4952 hrc = mMachine->GetStorageControllerByName(storageCtrlName.raw(), pStorageCtrl.asOutParam());
4953 AssertComRC(hrc);
4954
4955 hrc = pStorageCtrl->COMGETTER(Instance)(&ulStorageCtrlInst);
4956 AssertComRC(hrc);
4957
4958 StorageControllerType_T enmCtrlType;
4959 hrc = pStorageCtrl->COMGETTER(ControllerType)(&enmCtrlType);
4960 AssertComRC(hrc);
4961 const char *pcszDevice = i_storageControllerTypeToStr(enmCtrlType);
4962
4963 StorageBus_T enmBus;
4964 hrc = pStorageCtrl->COMGETTER(Bus)(&enmBus);
4965 AssertComRC(hrc);
4966
4967 unsigned uLUN;
4968 hrc = Console::i_storageBusPortDeviceToLun(enmBus, lPort, lDev, uLUN);
4969 AssertComRC(hrc);
4970
4971 PPDMIBASE pIBase = NULL;
4972 PPDMIMEDIA pIMedium = NULL;
4973 int vrc = ptrVM.vtable()->pfnPDMR3QueryDriverOnLun(ptrVM.rawUVM(), pcszDevice, ulStorageCtrlInst, uLUN, "VD", &pIBase);
4974 if (RT_SUCCESS(vrc))
4975 {
4976 if (pIBase)
4977 {
4978 pIMedium = (PPDMIMEDIA)pIBase->pfnQueryInterface(pIBase, PDMIMEDIA_IID);
4979 if (pIMedium)
4980 {
4981 vrc = pIMedium->pfnSetSecKeyIf(pIMedium, NULL, mpIfSecKeyHlp);
4982 Assert(RT_SUCCESS(vrc) || vrc == VERR_NOT_SUPPORTED);
4983 }
4984 }
4985 }
4986 }
4987 }
4988
4989 return hrc;
4990}
4991
4992/**
4993 * Configures the encryption support for the disk which have encryption conigured
4994 * with the configured key.
4995 *
4996 * @returns COM status code.
4997 * @param strId The ID of the password.
4998 * @param pcDisksConfigured Where to store the number of disks configured for the given ID.
4999 */
5000HRESULT Console::i_configureEncryptionForDisk(const com::Utf8Str &strId, unsigned *pcDisksConfigured)
5001{
5002 unsigned cDisksConfigured = 0;
5003 HRESULT hrc = S_OK;
5004 SafeIfaceArray<IMediumAttachment> sfaAttachments;
5005
5006 AutoCaller autoCaller(this);
5007 AssertComRCReturnRC(autoCaller.hrc());
5008
5009 /* Get the VM - must be done before the read-locking. */
5010 SafeVMPtr ptrVM(this);
5011 if (!ptrVM.isOk())
5012 return ptrVM.hrc();
5013
5014 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
5015
5016 hrc = mMachine->COMGETTER(MediumAttachments)(ComSafeArrayAsOutParam(sfaAttachments));
5017 if (FAILED(hrc))
5018 return hrc;
5019
5020 /* Find the correct attachment. */
5021 for (unsigned i = 0; i < sfaAttachments.size(); i++)
5022 {
5023 const ComPtr<IMediumAttachment> &pAtt = sfaAttachments[i];
5024 ComPtr<IMedium> pMedium;
5025 ComPtr<IMedium> pBase;
5026 Bstr bstrKeyId;
5027
5028 hrc = pAtt->COMGETTER(Medium)(pMedium.asOutParam());
5029 if (FAILED(hrc))
5030 break;
5031
5032 /* Skip non hard disk attachments. */
5033 if (pMedium.isNull())
5034 continue;
5035
5036 /* Get the UUID of the base medium and compare. */
5037 hrc = pMedium->COMGETTER(Base)(pBase.asOutParam());
5038 if (FAILED(hrc))
5039 break;
5040
5041 hrc = pBase->GetProperty(Bstr("CRYPT/KeyId").raw(), bstrKeyId.asOutParam());
5042 if (hrc == VBOX_E_OBJECT_NOT_FOUND)
5043 {
5044 hrc = S_OK;
5045 continue;
5046 }
5047 else if (FAILED(hrc))
5048 break;
5049
5050 if (strId.equals(Utf8Str(bstrKeyId)))
5051 {
5052 /*
5053 * Found the matching medium, query storage controller, port and device
5054 * to identify the correct driver.
5055 */
5056 ComPtr<IStorageController> pStorageCtrl;
5057 Bstr storageCtrlName;
5058 LONG lPort, lDev;
5059 ULONG ulStorageCtrlInst;
5060
5061 hrc = pAtt->COMGETTER(Controller)(storageCtrlName.asOutParam());
5062 if (FAILED(hrc))
5063 break;
5064
5065 hrc = pAtt->COMGETTER(Port)(&lPort);
5066 if (FAILED(hrc))
5067 break;
5068
5069 hrc = pAtt->COMGETTER(Device)(&lDev);
5070 if (FAILED(hrc))
5071 break;
5072
5073 hrc = mMachine->GetStorageControllerByName(storageCtrlName.raw(), pStorageCtrl.asOutParam());
5074 if (FAILED(hrc))
5075 break;
5076
5077 hrc = pStorageCtrl->COMGETTER(Instance)(&ulStorageCtrlInst);
5078 if (FAILED(hrc))
5079 break;
5080
5081 StorageControllerType_T enmCtrlType;
5082 hrc = pStorageCtrl->COMGETTER(ControllerType)(&enmCtrlType);
5083 AssertComRC(hrc);
5084 const char *pcszDevice = i_storageControllerTypeToStr(enmCtrlType);
5085
5086 StorageBus_T enmBus;
5087 hrc = pStorageCtrl->COMGETTER(Bus)(&enmBus);
5088 AssertComRC(hrc);
5089
5090 unsigned uLUN;
5091 hrc = Console::i_storageBusPortDeviceToLun(enmBus, lPort, lDev, uLUN);
5092 AssertComRCReturnRC(hrc);
5093
5094 PPDMIBASE pIBase = NULL;
5095 PPDMIMEDIA pIMedium = NULL;
5096 int vrc = ptrVM.vtable()->pfnPDMR3QueryDriverOnLun(ptrVM.rawUVM(), pcszDevice, ulStorageCtrlInst, uLUN, "VD", &pIBase);
5097 if (RT_SUCCESS(vrc))
5098 {
5099 if (pIBase)
5100 {
5101 pIMedium = (PPDMIMEDIA)pIBase->pfnQueryInterface(pIBase, PDMIMEDIA_IID);
5102 if (!pIMedium)
5103 return setError(E_FAIL, tr("could not query medium interface of controller"));
5104 vrc = pIMedium->pfnSetSecKeyIf(pIMedium, mpIfSecKey, mpIfSecKeyHlp);
5105 if (vrc == VERR_VD_PASSWORD_INCORRECT)
5106 {
5107 hrc = setError(VBOX_E_PASSWORD_INCORRECT,
5108 tr("The provided password for ID \"%s\" is not correct for at least one disk using this ID"),
5109 strId.c_str());
5110 break;
5111 }
5112 else if (RT_FAILURE(vrc))
5113 {
5114 hrc = setErrorBoth(E_FAIL, vrc, tr("Failed to set the encryption key (%Rrc)"), vrc);
5115 break;
5116 }
5117
5118 if (RT_SUCCESS(vrc))
5119 cDisksConfigured++;
5120 }
5121 else
5122 return setError(E_FAIL, tr("could not query base interface of controller"));
5123 }
5124 }
5125 }
5126
5127 if ( SUCCEEDED(hrc)
5128 && pcDisksConfigured)
5129 *pcDisksConfigured = cDisksConfigured;
5130 else if (FAILED(hrc))
5131 {
5132 /* Clear disk encryption setup on successfully configured attachments. */
5133 ErrorInfoKeeper eik; /* Keep current error info or it gets deestroyed in the IPC methods below. */
5134 i_clearDiskEncryptionKeysOnAllAttachmentsWithKeyId(strId);
5135 }
5136
5137 return hrc;
5138}
5139
5140/**
5141 * Parses the encryption configuration for one disk.
5142 *
5143 * @returns COM status code.
5144 * @param psz Pointer to the configuration for the encryption of one disk.
5145 * @param ppszEnd Pointer to the string following encrpytion configuration.
5146 */
5147HRESULT Console::i_consoleParseDiskEncryption(const char *psz, const char **ppszEnd)
5148{
5149 char *pszUuid = NULL;
5150 char *pszKeyEnc = NULL;
5151 int vrc = VINF_SUCCESS;
5152 HRESULT hrc = S_OK;
5153
5154 while ( *psz
5155 && RT_SUCCESS(vrc))
5156 {
5157 char *pszKey = NULL;
5158 char *pszVal = NULL;
5159 const char *pszEnd = NULL;
5160
5161 vrc = i_consoleParseKeyValue(psz, &pszEnd, &pszKey, &pszVal);
5162 if (RT_SUCCESS(vrc))
5163 {
5164 if (!RTStrCmp(pszKey, "uuid"))
5165 pszUuid = pszVal;
5166 else if (!RTStrCmp(pszKey, "dek"))
5167 pszKeyEnc = pszVal;
5168 else
5169 vrc = VERR_INVALID_PARAMETER;
5170
5171 RTStrFree(pszKey);
5172
5173 if (*pszEnd == ',')
5174 psz = pszEnd + 1;
5175 else
5176 {
5177 /*
5178 * End of the configuration for the current disk, skip linefeed and
5179 * carriage returns.
5180 */
5181 while ( *pszEnd == '\n'
5182 || *pszEnd == '\r')
5183 pszEnd++;
5184
5185 psz = pszEnd;
5186 break; /* Stop parsing */
5187 }
5188
5189 }
5190 }
5191
5192 if ( RT_SUCCESS(vrc)
5193 && pszUuid
5194 && pszKeyEnc)
5195 {
5196 ssize_t cbKey = 0;
5197
5198 /* Decode the key. */
5199 cbKey = RTBase64DecodedSize(pszKeyEnc, NULL);
5200 if (cbKey != -1)
5201 {
5202 uint8_t *pbKey;
5203 vrc = RTMemSaferAllocZEx((void **)&pbKey, cbKey, RTMEMSAFER_F_REQUIRE_NOT_PAGABLE);
5204 if (RT_SUCCESS(vrc))
5205 {
5206 vrc = RTBase64Decode(pszKeyEnc, pbKey, cbKey, NULL, NULL);
5207 if (RT_SUCCESS(vrc))
5208 {
5209 vrc = m_pKeyStore->addSecretKey(Utf8Str(pszUuid), pbKey, cbKey);
5210 if (RT_SUCCESS(vrc))
5211 {
5212 hrc = i_configureEncryptionForDisk(Utf8Str(pszUuid), NULL);
5213 if (FAILED(hrc))
5214 {
5215 /* Delete the key from the map. */
5216 vrc = m_pKeyStore->deleteSecretKey(Utf8Str(pszUuid));
5217 AssertRC(vrc);
5218 }
5219 }
5220 }
5221 else
5222 hrc = setErrorBoth(E_FAIL, vrc, tr("Failed to decode the key (%Rrc)"), vrc);
5223
5224 RTMemSaferFree(pbKey, cbKey);
5225 }
5226 else
5227 hrc = setErrorBoth(E_FAIL, vrc, tr("Failed to allocate secure memory for the key (%Rrc)"), vrc);
5228 }
5229 else
5230 hrc = setError(E_FAIL, tr("The base64 encoding of the passed key is incorrect"));
5231 }
5232 else if (RT_SUCCESS(vrc))
5233 hrc = setError(E_FAIL, tr("The encryption configuration is incomplete"));
5234
5235 if (pszUuid)
5236 RTStrFree(pszUuid);
5237 if (pszKeyEnc)
5238 {
5239 RTMemWipeThoroughly(pszKeyEnc, strlen(pszKeyEnc), 10 /* cMinPasses */);
5240 RTStrFree(pszKeyEnc);
5241 }
5242
5243 if (ppszEnd)
5244 *ppszEnd = psz;
5245
5246 return hrc;
5247}
5248
5249HRESULT Console::i_setDiskEncryptionKeys(const Utf8Str &strCfg)
5250{
5251 HRESULT hrc = S_OK;
5252 const char *pszCfg = strCfg.c_str();
5253
5254 while ( *pszCfg
5255 && SUCCEEDED(hrc))
5256 {
5257 const char *pszNext = NULL;
5258 hrc = i_consoleParseDiskEncryption(pszCfg, &pszNext);
5259 pszCfg = pszNext;
5260 }
5261
5262 return hrc;
5263}
5264
5265void Console::i_removeSecretKeysOnSuspend()
5266{
5267 /* Remove keys which are supposed to be removed on a suspend. */
5268 int vrc = m_pKeyStore->deleteAllSecretKeys(true /* fSuspend */, true /* fForce */);
5269 AssertRC(vrc);
5270}
5271
5272/**
5273 * Process a network adaptor change.
5274 *
5275 * @returns COM status code.
5276 *
5277 * @param pUVM The VM handle (caller hold this safely).
5278 * @param pVMM The VMM vtable.
5279 * @param pszDevice The PDM device name.
5280 * @param uInstance The PDM device instance.
5281 * @param uLun The PDM LUN number of the drive.
5282 * @param aNetworkAdapter The network adapter whose attachment needs to be changed
5283 */
5284HRESULT Console::i_doNetworkAdapterChange(PUVM pUVM, PCVMMR3VTABLE pVMM, const char *pszDevice,
5285 unsigned uInstance, unsigned uLun, INetworkAdapter *aNetworkAdapter)
5286{
5287 LogFlowThisFunc(("pszDevice=%p:{%s} uInstance=%u uLun=%u aNetworkAdapter=%p\n",
5288 pszDevice, pszDevice, uInstance, uLun, aNetworkAdapter));
5289
5290 AutoCaller autoCaller(this);
5291 AssertComRCReturnRC(autoCaller.hrc());
5292
5293 /*
5294 * Suspend the VM first.
5295 */
5296 bool fResume = false;
5297 HRESULT hr = i_suspendBeforeConfigChange(pUVM, pVMM, NULL, &fResume);
5298 if (FAILED(hr))
5299 return hr;
5300
5301 /*
5302 * Call worker in EMT, that's faster and safer than doing everything
5303 * using VM3ReqCall. Note that we separate VMR3ReqCall from VMR3ReqWait
5304 * here to make requests from under the lock in order to serialize them.
5305 */
5306 int vrc = pVMM->pfnVMR3ReqCallWaitU(pUVM, 0 /*idDstCpu*/, (PFNRT)i_changeNetworkAttachment, 7,
5307 this, pUVM, pVMM, pszDevice, uInstance, uLun, aNetworkAdapter);
5308
5309 if (fResume)
5310 i_resumeAfterConfigChange(pUVM, pVMM);
5311
5312 if (RT_SUCCESS(vrc))
5313 return S_OK;
5314
5315 return setErrorBoth(E_FAIL, vrc, tr("Could not change the network adaptor attachement type (%Rrc)"), vrc);
5316}
5317
5318
5319/**
5320 * Performs the Network Adaptor change in EMT.
5321 *
5322 * @returns VBox status code.
5323 *
5324 * @param pThis Pointer to the Console object.
5325 * @param pUVM The VM handle.
5326 * @param pVMM The VMM vtable.
5327 * @param pszDevice The PDM device name.
5328 * @param uInstance The PDM device instance.
5329 * @param uLun The PDM LUN number of the drive.
5330 * @param aNetworkAdapter The network adapter whose attachment needs to be changed
5331 *
5332 * @thread EMT
5333 * @note Locks the Console object for writing.
5334 * @note The VM must not be running.
5335 */
5336/*static*/ DECLCALLBACK(int) Console::i_changeNetworkAttachment(Console *pThis,
5337 PUVM pUVM,
5338 PCVMMR3VTABLE pVMM,
5339 const char *pszDevice,
5340 unsigned uInstance,
5341 unsigned uLun,
5342 INetworkAdapter *aNetworkAdapter)
5343{
5344 LogFlowFunc(("pThis=%p pszDevice=%p:{%s} uInstance=%u uLun=%u aNetworkAdapter=%p\n",
5345 pThis, pszDevice, pszDevice, uInstance, uLun, aNetworkAdapter));
5346
5347 AssertReturn(pThis, VERR_INVALID_PARAMETER);
5348
5349 AutoCaller autoCaller(pThis);
5350 AssertComRCReturn(autoCaller.hrc(), VERR_ACCESS_DENIED);
5351
5352#ifdef VBOX_STRICT
5353 ComPtr<IPlatform> pPlatform;
5354 HRESULT hrc = pThis->mMachine->COMGETTER(Platform)(pPlatform.asOutParam());
5355 AssertComRC(hrc);
5356
5357 PlatformArchitecture_T platformArch;
5358 hrc = pPlatform->COMGETTER(Architecture)(&platformArch);
5359 AssertComRC(hrc);
5360
5361 ComPtr<IVirtualBox> pVirtualBox;
5362 pThis->mMachine->COMGETTER(Parent)(pVirtualBox.asOutParam());
5363
5364 ComPtr<IPlatformProperties> pPlatformProperties;
5365 hrc = pVirtualBox->GetPlatformProperties(platformArch, pPlatformProperties.asOutParam());
5366 AssertComRC(hrc);
5367
5368 ChipsetType_T chipsetType = ChipsetType_PIIX3;
5369 pPlatform->COMGETTER(ChipsetType)(&chipsetType);
5370 AssertComRC(hrc);
5371
5372 ULONG maxNetworkAdapters = 0;
5373 hrc = pPlatformProperties->GetMaxNetworkAdapters(chipsetType, &maxNetworkAdapters);
5374 AssertComRC(hrc);
5375 AssertMsg(uLun == 0 && uInstance < maxNetworkAdapters,
5376 ("pszDevice=%s uLun=%d uInstance=%d\n", pszDevice, uLun, uInstance));
5377#endif
5378 Log(("pszDevice=%s uLun=%d uInstance=%d\n", pszDevice, uLun, uInstance));
5379
5380 /*
5381 * Check the VM for correct state.
5382 */
5383 PCFGMNODE pCfg = NULL; /* /Devices/Dev/.../Config/ */
5384 PCFGMNODE pLunL0 = NULL; /* /Devices/Dev/0/LUN#0/ */
5385 PCFGMNODE pInst = pVMM->pfnCFGMR3GetChildF(pVMM->pfnCFGMR3GetRootU(pUVM), "Devices/%s/%d/", pszDevice, uInstance);
5386 AssertLogRelMsgReturn(pInst, ("pszDevices=%s uInstance=%u\n", pszDevice, uInstance), VERR_CFGM_CHILD_NOT_FOUND);
5387
5388 int vrc = pThis->i_configNetwork(pszDevice, uInstance, uLun, aNetworkAdapter, pCfg, pLunL0, pInst,
5389 true /*fAttachDetach*/, false /*fIgnoreConnectFailure*/, pUVM, pVMM);
5390
5391 LogFlowFunc(("Returning %Rrc\n", vrc));
5392 return vrc;
5393}
5394
5395/**
5396 * Returns the device name of a given audio adapter.
5397 *
5398 * @returns Device name, or an empty string if no device is configured.
5399 * @param aAudioAdapter Audio adapter to return device name for.
5400 */
5401Utf8Str Console::i_getAudioAdapterDeviceName(IAudioAdapter *aAudioAdapter)
5402{
5403 Utf8Str strDevice;
5404
5405 AudioControllerType_T audioController;
5406 HRESULT hrc = aAudioAdapter->COMGETTER(AudioController)(&audioController);
5407 AssertComRC(hrc);
5408 if (SUCCEEDED(hrc))
5409 {
5410 switch (audioController)
5411 {
5412 case AudioControllerType_HDA: strDevice = "hda"; break;
5413 case AudioControllerType_AC97: strDevice = "ichac97"; break;
5414 case AudioControllerType_SB16: strDevice = "sb16"; break;
5415 case AudioControllerType_VirtioSound: strDevice = "virtio-sound"; break;
5416 default: break; /* None. */
5417 }
5418 }
5419
5420 return strDevice;
5421}
5422
5423/**
5424 * Called by IInternalSessionControl::OnAudioAdapterChange().
5425 */
5426HRESULT Console::i_onAudioAdapterChange(IAudioAdapter *aAudioAdapter)
5427{
5428 LogFlowThisFunc(("\n"));
5429
5430 AutoCaller autoCaller(this);
5431 AssertComRCReturnRC(autoCaller.hrc());
5432
5433 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
5434
5435 HRESULT hrc = S_OK;
5436
5437 /* don't trigger audio changes if the VM isn't running */
5438 SafeVMPtrQuiet ptrVM(this);
5439 if (ptrVM.isOk())
5440 {
5441 BOOL fEnabledIn, fEnabledOut;
5442 hrc = aAudioAdapter->COMGETTER(EnabledIn)(&fEnabledIn);
5443 AssertComRC(hrc);
5444 if (SUCCEEDED(hrc))
5445 {
5446 hrc = aAudioAdapter->COMGETTER(EnabledOut)(&fEnabledOut);
5447 AssertComRC(hrc);
5448 if (SUCCEEDED(hrc))
5449 {
5450 int vrc = VINF_SUCCESS;
5451
5452 for (ULONG ulLUN = 0; ulLUN < 16 /** @todo Use a define */; ulLUN++)
5453 {
5454 PPDMIBASE pBase;
5455 int vrc2 = ptrVM.vtable()->pfnPDMR3QueryDriverOnLun(ptrVM.rawUVM(),
5456 i_getAudioAdapterDeviceName(aAudioAdapter).c_str(),
5457 0 /* iInstance */, ulLUN, "AUDIO", &pBase);
5458 if (RT_FAILURE(vrc2))
5459 continue;
5460
5461 if (pBase)
5462 {
5463 PPDMIAUDIOCONNECTOR pAudioCon = (PPDMIAUDIOCONNECTOR)pBase->pfnQueryInterface(pBase,
5464 PDMIAUDIOCONNECTOR_IID);
5465 if ( pAudioCon
5466 && pAudioCon->pfnEnable)
5467 {
5468 int vrcIn = pAudioCon->pfnEnable(pAudioCon, PDMAUDIODIR_IN, RT_BOOL(fEnabledIn));
5469 if (RT_FAILURE(vrcIn))
5470 LogRel(("Audio: Failed to %s input of LUN#%RU32, vrcIn=%Rrc\n",
5471 fEnabledIn ? "enable" : "disable", ulLUN, vrcIn));
5472
5473 if (RT_SUCCESS(vrc))
5474 vrc = vrcIn;
5475
5476 int vrcOut = pAudioCon->pfnEnable(pAudioCon, PDMAUDIODIR_OUT, RT_BOOL(fEnabledOut));
5477 if (RT_FAILURE(vrcOut))
5478 LogRel(("Audio: Failed to %s output of LUN#%RU32, vrcOut=%Rrc\n",
5479 fEnabledIn ? "enable" : "disable", ulLUN, vrcOut));
5480
5481 if (RT_SUCCESS(vrc))
5482 vrc = vrcOut;
5483 }
5484 }
5485 }
5486
5487 if (RT_SUCCESS(vrc))
5488 LogRel(("Audio: Status has changed (input is %s, output is %s)\n",
5489 fEnabledIn ? "enabled" : "disabled", fEnabledOut ? "enabled" : "disabled"));
5490 }
5491 }
5492
5493 ptrVM.release();
5494 }
5495
5496 alock.release();
5497
5498 /* notify console callbacks on success */
5499 if (SUCCEEDED(hrc))
5500 ::FireAudioAdapterChangedEvent(mEventSource, aAudioAdapter);
5501
5502 LogFlowThisFunc(("Leaving S_OKn"));
5503 return S_OK;
5504}
5505
5506/**
5507 * Called by IInternalSessionControl::OnHostAudioDeviceChange().
5508 */
5509HRESULT Console::i_onHostAudioDeviceChange(IHostAudioDevice *aDevice, BOOL aNew, AudioDeviceState_T aState,
5510 IVirtualBoxErrorInfo *aErrInfo)
5511{
5512 LogFlowThisFunc(("\n"));
5513
5514 AutoCaller autoCaller(this);
5515 AssertComRCReturnRC(autoCaller.hrc());
5516
5517 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
5518
5519 HRESULT hrc = S_OK;
5520
5521 /** @todo Implement logic here. */
5522
5523 alock.release();
5524
5525 /* notify console callbacks on success */
5526 if (SUCCEEDED(hrc))
5527 ::FireHostAudioDeviceChangedEvent(mEventSource, aDevice, aNew, aState, aErrInfo);
5528
5529 LogFlowThisFunc(("Leaving S_OK\n"));
5530 return S_OK;
5531}
5532
5533/**
5534 * Performs the Serial Port attachment change in EMT.
5535 *
5536 * @returns VBox status code.
5537 *
5538 * @param pThis Pointer to the Console object.
5539 * @param pUVM The VM handle.
5540 * @param pVMM The VMM vtable.
5541 * @param pSerialPort The serial port whose attachment needs to be changed
5542 *
5543 * @thread EMT
5544 * @note Locks the Console object for writing.
5545 * @note The VM must not be running.
5546 */
5547DECLCALLBACK(int) Console::i_changeSerialPortAttachment(Console *pThis, PUVM pUVM, PCVMMR3VTABLE pVMM, ISerialPort *pSerialPort)
5548{
5549 LogFlowFunc(("pThis=%p pUVM=%p pSerialPort=%p\n", pThis, pUVM, pSerialPort));
5550
5551 AssertReturn(pThis, VERR_INVALID_PARAMETER);
5552
5553 AutoCaller autoCaller(pThis);
5554 AssertComRCReturn(autoCaller.hrc(), VERR_ACCESS_DENIED);
5555
5556 AutoWriteLock alock(pThis COMMA_LOCKVAL_SRC_POS);
5557
5558 /*
5559 * Check the VM for correct state.
5560 */
5561 VMSTATE enmVMState = pVMM->pfnVMR3GetStateU(pUVM);
5562 AssertReturn(enmVMState == VMSTATE_SUSPENDED, VERR_INVALID_STATE);
5563
5564 HRESULT hrc = S_OK;
5565 int vrc = VINF_SUCCESS;
5566 ULONG ulSlot;
5567 hrc = pSerialPort->COMGETTER(Slot)(&ulSlot);
5568 if (SUCCEEDED(hrc))
5569 {
5570 /* Check whether the port mode changed and act accordingly. */
5571 Assert(ulSlot < 4);
5572
5573 PortMode_T eHostMode;
5574 hrc = pSerialPort->COMGETTER(HostMode)(&eHostMode);
5575 if (SUCCEEDED(hrc))
5576 {
5577 PCFGMNODE pInst = pVMM->pfnCFGMR3GetChildF(pVMM->pfnCFGMR3GetRootU(pUVM), "Devices/serial/%d/", ulSlot);
5578 AssertRelease(pInst);
5579
5580 /* Remove old driver. */
5581 if (pThis->m_aeSerialPortMode[ulSlot] != PortMode_Disconnected)
5582 {
5583 vrc = pVMM->pfnPDMR3DeviceDetach(pUVM, "serial", ulSlot, 0, 0);
5584 PCFGMNODE pLunL0 = pVMM->pfnCFGMR3GetChildF(pInst, "LUN#0");
5585 pVMM->pfnCFGMR3RemoveNode(pLunL0);
5586 }
5587
5588 if (RT_SUCCESS(vrc))
5589 {
5590 BOOL fServer;
5591 Bstr bstrPath;
5592 hrc = pSerialPort->COMGETTER(Server)(&fServer);
5593 if (SUCCEEDED(hrc))
5594 hrc = pSerialPort->COMGETTER(Path)(bstrPath.asOutParam());
5595
5596 /* Configure new driver. */
5597 if ( SUCCEEDED(hrc)
5598 && eHostMode != PortMode_Disconnected)
5599 {
5600 vrc = pThis->i_configSerialPort(pInst, eHostMode, Utf8Str(bstrPath).c_str(), RT_BOOL(fServer));
5601 if (RT_SUCCESS(vrc))
5602 {
5603 /*
5604 * Attach the driver.
5605 */
5606 PPDMIBASE pBase;
5607 vrc = pVMM->pfnPDMR3DeviceAttach(pUVM, "serial", ulSlot, 0, 0, &pBase);
5608
5609 pVMM->pfnCFGMR3Dump(pInst);
5610 }
5611 }
5612 }
5613 }
5614 }
5615
5616 if (RT_SUCCESS(vrc) && FAILED(hrc))
5617 vrc = VERR_INTERNAL_ERROR;
5618
5619 LogFlowFunc(("Returning %Rrc\n", vrc));
5620 return vrc;
5621}
5622
5623
5624/**
5625 * Called by IInternalSessionControl::OnSerialPortChange().
5626 */
5627HRESULT Console::i_onSerialPortChange(ISerialPort *aSerialPort)
5628{
5629 LogFlowThisFunc(("\n"));
5630
5631 AutoCaller autoCaller(this);
5632 AssertComRCReturnRC(autoCaller.hrc());
5633
5634 HRESULT hrc = S_OK;
5635
5636 /* don't trigger audio changes if the VM isn't running */
5637 SafeVMPtrQuiet ptrVM(this);
5638 if (ptrVM.isOk())
5639 {
5640 ULONG ulSlot;
5641 BOOL fEnabled = FALSE;
5642 hrc = aSerialPort->COMGETTER(Slot)(&ulSlot);
5643 if (SUCCEEDED(hrc))
5644 hrc = aSerialPort->COMGETTER(Enabled)(&fEnabled);
5645 if (SUCCEEDED(hrc) && fEnabled)
5646 {
5647 /* Check whether the port mode changed and act accordingly. */
5648 Assert(ulSlot < 4);
5649
5650 PortMode_T eHostMode;
5651 hrc = aSerialPort->COMGETTER(HostMode)(&eHostMode);
5652 if (SUCCEEDED(hrc) && m_aeSerialPortMode[ulSlot] != eHostMode)
5653 {
5654 /*
5655 * Suspend the VM first.
5656 */
5657 bool fResume = false;
5658 hrc = i_suspendBeforeConfigChange(ptrVM.rawUVM(), ptrVM.vtable(), NULL, &fResume);
5659 if (FAILED(hrc))
5660 return hrc;
5661
5662 /*
5663 * Call worker in EMT, that's faster and safer than doing everything
5664 * using VM3ReqCallWait.
5665 */
5666 int vrc = ptrVM.vtable()->pfnVMR3ReqCallWaitU(ptrVM.rawUVM(), 0 /*idDstCpu*/,
5667 (PFNRT)i_changeSerialPortAttachment, 4,
5668 this, ptrVM.rawUVM(), ptrVM.vtable(), aSerialPort);
5669
5670 if (fResume)
5671 i_resumeAfterConfigChange(ptrVM.rawUVM(), ptrVM.vtable());
5672 if (RT_SUCCESS(vrc))
5673 m_aeSerialPortMode[ulSlot] = eHostMode;
5674 else
5675 hrc = setErrorBoth(E_FAIL, vrc, tr("Failed to change the serial port attachment (%Rrc)"), vrc);
5676 }
5677 }
5678 }
5679
5680 if (SUCCEEDED(hrc))
5681 ::FireSerialPortChangedEvent(mEventSource, aSerialPort);
5682
5683 LogFlowThisFunc(("Leaving hrc=%#x\n", hrc));
5684 return hrc;
5685}
5686
5687/**
5688 * Called by IInternalSessionControl::OnParallelPortChange().
5689 */
5690HRESULT Console::i_onParallelPortChange(IParallelPort *aParallelPort)
5691{
5692 LogFlowThisFunc(("\n"));
5693
5694 AutoCaller autoCaller(this);
5695 AssertComRCReturnRC(autoCaller.hrc());
5696
5697 ::FireParallelPortChangedEvent(mEventSource, aParallelPort);
5698
5699 LogFlowThisFunc(("Leaving S_OK\n"));
5700 return S_OK;
5701}
5702
5703/**
5704 * Called by IInternalSessionControl::OnStorageControllerChange().
5705 */
5706HRESULT Console::i_onStorageControllerChange(const Guid &aMachineId, const Utf8Str &aControllerName)
5707{
5708 LogFlowThisFunc(("\n"));
5709
5710 AutoCaller autoCaller(this);
5711 AssertComRCReturnRC(autoCaller.hrc());
5712
5713 ::FireStorageControllerChangedEvent(mEventSource, aMachineId.toString(), aControllerName);
5714
5715 LogFlowThisFunc(("Leaving S_OK\n"));
5716 return S_OK;
5717}
5718
5719/**
5720 * Called by IInternalSessionControl::OnMediumChange().
5721 */
5722HRESULT Console::i_onMediumChange(IMediumAttachment *aMediumAttachment, BOOL aForce)
5723{
5724 LogFlowThisFunc(("\n"));
5725
5726 AutoCaller autoCaller(this);
5727 AssertComRCReturnRC(autoCaller.hrc());
5728
5729 HRESULT hrc = S_OK;
5730
5731 /* don't trigger medium changes if the VM isn't running */
5732 SafeVMPtrQuiet ptrVM(this);
5733 if (ptrVM.isOk())
5734 {
5735 hrc = i_doMediumChange(aMediumAttachment, !!aForce, ptrVM.rawUVM(), ptrVM.vtable());
5736 ptrVM.release();
5737 }
5738
5739 /* notify console callbacks on success */
5740 if (SUCCEEDED(hrc))
5741 ::FireMediumChangedEvent(mEventSource, aMediumAttachment);
5742
5743 LogFlowThisFunc(("Leaving hrc=%#x\n", hrc));
5744 return hrc;
5745}
5746
5747/**
5748 * Called by IInternalSessionControl::OnCPUChange().
5749 *
5750 * @note Locks this object for writing.
5751 */
5752HRESULT Console::i_onCPUChange(ULONG aCPU, BOOL aRemove)
5753{
5754 LogFlowThisFunc(("\n"));
5755
5756 AutoCaller autoCaller(this);
5757 AssertComRCReturnRC(autoCaller.hrc());
5758
5759 HRESULT hrc = S_OK;
5760
5761 /* don't trigger CPU changes if the VM isn't running */
5762 SafeVMPtrQuiet ptrVM(this);
5763 if (ptrVM.isOk())
5764 {
5765 if (aRemove)
5766 hrc = i_doCPURemove(aCPU, ptrVM.rawUVM(), ptrVM.vtable());
5767 else
5768 hrc = i_doCPUAdd(aCPU, ptrVM.rawUVM(), ptrVM.vtable());
5769 ptrVM.release();
5770 }
5771
5772 /* notify console callbacks on success */
5773 if (SUCCEEDED(hrc))
5774 ::FireCPUChangedEvent(mEventSource, aCPU, aRemove);
5775
5776 LogFlowThisFunc(("Leaving hrc=%#x\n", hrc));
5777 return hrc;
5778}
5779
5780/**
5781 * Called by IInternalSessionControl::OnCpuExecutionCapChange().
5782 *
5783 * @note Locks this object for writing.
5784 */
5785HRESULT Console::i_onCPUExecutionCapChange(ULONG aExecutionCap)
5786{
5787 LogFlowThisFunc(("\n"));
5788
5789 AutoCaller autoCaller(this);
5790 AssertComRCReturnRC(autoCaller.hrc());
5791
5792 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
5793
5794 HRESULT hrc = S_OK;
5795
5796 /* don't trigger the CPU priority change if the VM isn't running */
5797 SafeVMPtrQuiet ptrVM(this);
5798 if (ptrVM.isOk())
5799 {
5800 if ( mMachineState == MachineState_Running
5801 || mMachineState == MachineState_Teleporting
5802 || mMachineState == MachineState_LiveSnapshotting
5803 )
5804 {
5805 /* No need to call in the EMT thread. */
5806 int vrc = ptrVM.vtable()->pfnVMR3SetCpuExecutionCap(ptrVM.rawUVM(), aExecutionCap);
5807 if (RT_FAILURE(vrc))
5808 hrc = setErrorBoth(E_FAIL, vrc, tr("Failed to change the CPU execution limit (%Rrc)"), vrc);
5809 }
5810 else
5811 hrc = i_setInvalidMachineStateError();
5812 ptrVM.release();
5813 }
5814
5815 /* notify console callbacks on success */
5816 if (SUCCEEDED(hrc))
5817 {
5818 alock.release();
5819 ::FireCPUExecutionCapChangedEvent(mEventSource, aExecutionCap);
5820 }
5821
5822 LogFlowThisFunc(("Leaving hrc=%#x\n", hrc));
5823 return hrc;
5824}
5825
5826/**
5827 * Called by IInternalSessionControl::OnClipboardError().
5828 *
5829 * @note Locks this object for writing.
5830 */
5831HRESULT Console::i_onClipboardError(const Utf8Str &aId, const Utf8Str &aErrMsg, LONG aRc)
5832{
5833 LogFlowThisFunc(("\n"));
5834
5835 AutoCaller autoCaller(this);
5836 AssertComRCReturnRC(autoCaller.hrc());
5837
5838 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
5839
5840 HRESULT hrc = S_OK;
5841
5842 /* don't trigger the drag and drop mode change if the VM isn't running */
5843 SafeVMPtrQuiet ptrVM(this);
5844 if (ptrVM.isOk())
5845 {
5846 if ( mMachineState == MachineState_Running
5847 || mMachineState == MachineState_Teleporting
5848 || mMachineState == MachineState_LiveSnapshotting)
5849 {
5850 }
5851 else
5852 hrc = i_setInvalidMachineStateError();
5853 ptrVM.release();
5854 }
5855
5856 /* notify console callbacks on success */
5857 if (SUCCEEDED(hrc))
5858 {
5859 alock.release();
5860 ::FireClipboardErrorEvent(mEventSource, aId, aErrMsg, aRc);
5861 }
5862
5863 LogFlowThisFunc(("Leaving hrc=%#x\n", hrc));
5864 return hrc;
5865}
5866
5867/**
5868 * Called by IInternalSessionControl::OnClipboardModeChange().
5869 *
5870 * @note Locks this object for writing.
5871 */
5872HRESULT Console::i_onClipboardModeChange(ClipboardMode_T aClipboardMode)
5873{
5874 LogFlowThisFunc(("\n"));
5875
5876 AutoCaller autoCaller(this);
5877 AssertComRCReturnRC(autoCaller.hrc());
5878
5879 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
5880
5881 HRESULT hrc = S_OK;
5882
5883 /* don't trigger the clipboard mode change if the VM isn't running */
5884 SafeVMPtrQuiet ptrVM(this);
5885 if (ptrVM.isOk())
5886 {
5887 if ( mMachineState == MachineState_Running
5888 || mMachineState == MachineState_Teleporting
5889 || mMachineState == MachineState_LiveSnapshotting)
5890 {
5891 int vrc = i_changeClipboardMode(aClipboardMode);
5892 if (RT_FAILURE(vrc))
5893 hrc = E_FAIL; /** @todo r=andy Set error info here! */
5894 }
5895 else
5896 hrc = i_setInvalidMachineStateError();
5897 ptrVM.release();
5898 }
5899
5900 /* notify console callbacks on success */
5901 if (SUCCEEDED(hrc))
5902 {
5903 alock.release();
5904 ::FireClipboardModeChangedEvent(mEventSource, aClipboardMode);
5905 }
5906
5907 LogFlowThisFunc(("Leaving hrc=%#x\n", hrc));
5908 return hrc;
5909}
5910
5911/**
5912 * Called by IInternalSessionControl::OnClipboardFileTransferModeChange().
5913 *
5914 * @note Locks this object for writing.
5915 */
5916HRESULT Console::i_onClipboardFileTransferModeChange(bool aEnabled)
5917{
5918 LogFlowThisFunc(("\n"));
5919
5920 AutoCaller autoCaller(this);
5921 AssertComRCReturnRC(autoCaller.hrc());
5922
5923 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
5924
5925 HRESULT hrc = S_OK;
5926
5927 /* don't trigger the change if the VM isn't running */
5928 SafeVMPtrQuiet ptrVM(this);
5929 if (ptrVM.isOk())
5930 {
5931 if ( mMachineState == MachineState_Running
5932 || mMachineState == MachineState_Teleporting
5933 || mMachineState == MachineState_LiveSnapshotting)
5934 {
5935 int vrc = i_changeClipboardFileTransferMode(aEnabled);
5936 if (RT_FAILURE(vrc))
5937 hrc = E_FAIL; /** @todo r=andy Set error info here! */
5938 }
5939 else
5940 hrc = i_setInvalidMachineStateError();
5941 ptrVM.release();
5942 }
5943
5944 /* notify console callbacks on success */
5945 if (SUCCEEDED(hrc))
5946 {
5947 alock.release();
5948 ::FireClipboardFileTransferModeChangedEvent(mEventSource, aEnabled ? TRUE : FALSE);
5949 }
5950
5951 LogFlowThisFunc(("Leaving hrc=%#x\n", hrc));
5952 return hrc;
5953}
5954
5955/**
5956 * Called by IInternalSessionControl::OnDnDModeChange().
5957 *
5958 * @note Locks this object for writing.
5959 */
5960HRESULT Console::i_onDnDModeChange(DnDMode_T aDnDMode)
5961{
5962 LogFlowThisFunc(("\n"));
5963
5964 AutoCaller autoCaller(this);
5965 AssertComRCReturnRC(autoCaller.hrc());
5966
5967 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
5968
5969 HRESULT hrc = S_OK;
5970
5971 /* don't trigger the drag and drop mode change if the VM isn't running */
5972 SafeVMPtrQuiet ptrVM(this);
5973 if (ptrVM.isOk())
5974 {
5975 if ( mMachineState == MachineState_Running
5976 || mMachineState == MachineState_Teleporting
5977 || mMachineState == MachineState_LiveSnapshotting)
5978 i_changeDnDMode(aDnDMode);
5979 else
5980 hrc = i_setInvalidMachineStateError();
5981 ptrVM.release();
5982 }
5983
5984 /* notify console callbacks on success */
5985 if (SUCCEEDED(hrc))
5986 {
5987 alock.release();
5988 ::FireDnDModeChangedEvent(mEventSource, aDnDMode);
5989 }
5990
5991 LogFlowThisFunc(("Leaving hrc=%#x\n", hrc));
5992 return hrc;
5993}
5994
5995/**
5996 * Check the return code of mConsoleVRDPServer->Launch. LogRel() the error reason and
5997 * return an error message appropriate for setError().
5998 */
5999Utf8Str Console::VRDPServerErrorToMsg(int vrc)
6000{
6001 Utf8Str errMsg;
6002 if (vrc == VERR_NET_ADDRESS_IN_USE)
6003 {
6004 /* Not fatal if we start the VM, fatal if the VM is already running. */
6005 Bstr bstr;
6006 mVRDEServer->GetVRDEProperty(Bstr("TCP/Ports").raw(), bstr.asOutParam());
6007 errMsg = Utf8StrFmt(tr("VirtualBox Remote Desktop Extension server can't bind to the port(s): %s"),
6008 Utf8Str(bstr).c_str());
6009 LogRel(("VRDE: Warning: failed to launch VRDE server (%Rrc): %s\n", vrc, errMsg.c_str()));
6010 }
6011 else if (vrc == VINF_NOT_SUPPORTED)
6012 {
6013 /* This means that the VRDE is not installed.
6014 * Not fatal if we start the VM, fatal if the VM is already running. */
6015 LogRel(("VRDE: VirtualBox Remote Desktop Extension is not available.\n"));
6016 errMsg = Utf8Str(tr("VirtualBox Remote Desktop Extension is not available"));
6017 }
6018 else if (RT_FAILURE(vrc))
6019 {
6020 /* Fail if the server is installed but can't start. Always fatal. */
6021 switch (vrc)
6022 {
6023 case VERR_FILE_NOT_FOUND:
6024 errMsg = Utf8StrFmt(tr("Could not find the VirtualBox Remote Desktop Extension library"));
6025 break;
6026 default:
6027 errMsg = Utf8StrFmt(tr("Failed to launch the Remote Desktop Extension server (%Rrc)"), vrc);
6028 break;
6029 }
6030 LogRel(("VRDE: Failed: (%Rrc): %s\n", vrc, errMsg.c_str()));
6031 }
6032
6033 return errMsg;
6034}
6035
6036/**
6037 * Called by IInternalSessionControl::OnVRDEServerChange().
6038 *
6039 * @note Locks this object for writing.
6040 */
6041HRESULT Console::i_onVRDEServerChange(BOOL aRestart)
6042{
6043 AutoCaller autoCaller(this);
6044 AssertComRCReturnRC(autoCaller.hrc());
6045
6046 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
6047
6048 HRESULT hrc = S_OK;
6049
6050 /* don't trigger VRDE server changes if the VM isn't running */
6051 SafeVMPtrQuiet ptrVM(this);
6052 if (ptrVM.isOk())
6053 {
6054 /* Serialize. */
6055 if (mfVRDEChangeInProcess)
6056 mfVRDEChangePending = true;
6057 else
6058 {
6059 do {
6060 mfVRDEChangeInProcess = true;
6061 mfVRDEChangePending = false;
6062
6063 if ( mVRDEServer
6064 && ( mMachineState == MachineState_Running
6065 || mMachineState == MachineState_Teleporting
6066 || mMachineState == MachineState_LiveSnapshotting
6067 || mMachineState == MachineState_Paused
6068 )
6069 )
6070 {
6071 BOOL vrdpEnabled = FALSE;
6072
6073 hrc = mVRDEServer->COMGETTER(Enabled)(&vrdpEnabled);
6074 ComAssertComRCRetRC(hrc);
6075
6076 if (aRestart)
6077 {
6078 /* VRDP server may call this Console object back from other threads (VRDP INPUT or OUTPUT). */
6079 alock.release();
6080
6081 if (vrdpEnabled)
6082 {
6083 // If there was no VRDP server started the 'stop' will do nothing.
6084 // However if a server was started and this notification was called,
6085 // we have to restart the server.
6086 mConsoleVRDPServer->Stop();
6087
6088 int vrc = mConsoleVRDPServer->Launch();
6089 if (vrc != VINF_SUCCESS)
6090 {
6091 Utf8Str errMsg = VRDPServerErrorToMsg(vrc);
6092 hrc = setErrorBoth(E_FAIL, vrc, "%s", errMsg.c_str());
6093 }
6094 else
6095 {
6096#ifdef VBOX_WITH_AUDIO_VRDE
6097 mAudioVRDE->doAttachDriverViaEmt(ptrVM.rawUVM(), ptrVM.vtable(), NULL /*alock is not held*/);
6098#endif
6099 mConsoleVRDPServer->EnableConnections();
6100 }
6101 }
6102 else
6103 {
6104 mConsoleVRDPServer->Stop();
6105#ifdef VBOX_WITH_AUDIO_VRDE
6106 mAudioVRDE->doDetachDriverViaEmt(ptrVM.rawUVM(), ptrVM.vtable(), NULL /*alock is not held*/);
6107#endif
6108 }
6109
6110 alock.acquire();
6111 }
6112 }
6113 else
6114 hrc = i_setInvalidMachineStateError();
6115
6116 mfVRDEChangeInProcess = false;
6117 } while (mfVRDEChangePending && SUCCEEDED(hrc));
6118 }
6119
6120 ptrVM.release();
6121 }
6122
6123 /* notify console callbacks on success */
6124 if (SUCCEEDED(hrc))
6125 {
6126 alock.release();
6127 ::FireVRDEServerChangedEvent(mEventSource);
6128 }
6129
6130 return hrc;
6131}
6132
6133void Console::i_onVRDEServerInfoChange()
6134{
6135 AutoCaller autoCaller(this);
6136 AssertComRCReturnVoid(autoCaller.hrc());
6137
6138 ::FireVRDEServerInfoChangedEvent(mEventSource);
6139}
6140
6141HRESULT Console::i_sendACPIMonitorHotPlugEvent()
6142{
6143 LogFlowThisFuncEnter();
6144
6145 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
6146
6147 if ( mMachineState != MachineState_Running
6148 && mMachineState != MachineState_Teleporting
6149 && mMachineState != MachineState_LiveSnapshotting)
6150 return i_setInvalidMachineStateError();
6151
6152 /* get the VM handle. */
6153 SafeVMPtr ptrVM(this);
6154 if (!ptrVM.isOk())
6155 return ptrVM.hrc();
6156
6157 // no need to release lock, as there are no cross-thread callbacks
6158
6159 /* get the acpi device interface and press the sleep button. */
6160 PPDMIBASE pBase;
6161 int vrc = ptrVM.vtable()->pfnPDMR3QueryDeviceLun(ptrVM.rawUVM(), "acpi", 0, 0, &pBase);
6162 if (RT_SUCCESS(vrc))
6163 {
6164 Assert(pBase);
6165 PPDMIACPIPORT pPort = PDMIBASE_QUERY_INTERFACE(pBase, PDMIACPIPORT);
6166 if (pPort)
6167 vrc = pPort->pfnMonitorHotPlugEvent(pPort);
6168 else
6169 vrc = VERR_PDM_MISSING_INTERFACE;
6170 }
6171
6172 HRESULT hrc = RT_SUCCESS(vrc) ? S_OK
6173 : setErrorBoth(VBOX_E_PDM_ERROR, vrc, tr("Sending monitor hot-plug event failed (%Rrc)"), vrc);
6174
6175 LogFlowThisFunc(("hrc=%Rhrc\n", hrc));
6176 LogFlowThisFuncLeave();
6177 return hrc;
6178}
6179
6180#ifdef VBOX_WITH_RECORDING
6181/**
6182 * Enables or disables recording of a VM.
6183 *
6184 * @returns VBox status code.
6185 * @retval VINF_NO_CHANGE if the recording state has not been changed.
6186 * @param fEnable Whether to enable or disable the recording.
6187 * @param pAutoLock Pointer to auto write lock to use for attaching/detaching required driver(s) at runtime.
6188 * @param pProgress Progress object to use. Optional and can be NULL.
6189 */
6190int Console::i_recordingEnable(BOOL fEnable, util::AutoWriteLock *pAutoLock, ComPtr<IProgress> &pProgress)
6191{
6192 AssertPtrReturn(pAutoLock, VERR_INVALID_POINTER);
6193
6194 bool const fIsEnabled = mRecording.mCtx.IsStarted();
6195
6196 if (RT_BOOL(fEnable) == fIsEnabled) /* No change? Bail out. */
6197 return VINF_NO_CHANGE;
6198
6199 int vrc = VINF_SUCCESS;
6200
6201 Display *pDisplay = i_getDisplay();
6202 AssertPtrReturn(pDisplay, VERR_INVALID_POINTER);
6203
6204 LogRel(("Recording: %s\n", fEnable ? "Enabling" : "Disabling"));
6205
6206 SafeVMPtrQuiet ptrVM(this);
6207 if (ptrVM.isOk())
6208 {
6209 if (fEnable)
6210 {
6211 vrc = i_recordingCreate(pProgress);
6212 if (RT_SUCCESS(vrc))
6213 {
6214# ifdef VBOX_WITH_AUDIO_RECORDING
6215 /* Attach the video recording audio driver if required. */
6216 if ( mRecording.mCtx.IsFeatureEnabled(RecordingFeature_Audio)
6217 && mRecording.mAudioRec)
6218 {
6219 vrc = mRecording.mAudioRec->applyConfiguration(mRecording.mCtx.GetConfig());
6220 if (RT_SUCCESS(vrc))
6221 vrc = mRecording.mAudioRec->doAttachDriverViaEmt(ptrVM.rawUVM(), ptrVM.vtable(), pAutoLock);
6222
6223 if (RT_FAILURE(vrc))
6224 mRecording.mCtx.SetError(vrc, Utf8StrFmt(tr("Attaching audio recording driver failed (%Rrc)"), vrc));
6225 }
6226# endif
6227 if ( RT_SUCCESS(vrc)
6228 && mRecording.mCtx.IsReady()) /* Any video recording (audio and/or video) feature enabled? */
6229 {
6230 vrc = i_recordingStart(pAutoLock);
6231 }
6232 }
6233
6234 if (RT_FAILURE(vrc))
6235 LogRel(("Recording: Failed to enable with %Rrc\n", vrc));
6236 }
6237 else /* Disable */
6238 {
6239 vrc = i_recordingStop(pAutoLock);
6240 if (RT_SUCCESS(vrc))
6241 {
6242# ifdef VBOX_WITH_AUDIO_RECORDING
6243 if (mRecording.mAudioRec)
6244 {
6245 vrc = mRecording.mAudioRec->doDetachDriverViaEmt(ptrVM.rawUVM(), ptrVM.vtable(), pAutoLock);
6246 if (RT_FAILURE(vrc))
6247 mRecording.mCtx.SetError(vrc, Utf8StrFmt(tr("Detaching audio recording driver failed (%Rrc) -- please consult log file for details"), vrc));
6248 }
6249# endif
6250 i_recordingDestroy();
6251 }
6252 }
6253 }
6254 else
6255 vrc = VERR_VM_INVALID_VM_STATE;
6256
6257 if (RT_FAILURE(vrc))
6258 LogRel(("Recording: %s failed with %Rrc\n", fEnable ? "Enabling" : "Disabling", vrc));
6259
6260 return vrc;
6261}
6262#endif /* VBOX_WITH_RECORDING */
6263
6264/**
6265 * Called by IInternalSessionControl::OnRecordingStateChange().
6266 */
6267HRESULT Console::i_onRecordingStateChange(BOOL aEnable, ComPtr<IProgress> &aProgress)
6268{
6269#ifdef VBOX_WITH_RECORDING
6270 HRESULT hrc = S_OK;
6271
6272 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
6273
6274 LogRel2(("Recording: State changed (%s)\n", aEnable ? "enabled" : "disabled"));
6275
6276 /* Don't trigger recording changes if the VM isn't running. */
6277 SafeVMPtrQuiet ptrVM(this);
6278 if (ptrVM.isOk())
6279 {
6280 ComPtr<IVirtualBoxErrorInfo> pErrorInfo;
6281
6282 int vrc = i_recordingEnable(aEnable, &alock, aProgress);
6283 if (RT_FAILURE(vrc))
6284 {
6285 /* If available, get the error information from the progress object and fire it via the event below. */
6286 if (aProgress.isNotNull())
6287 {
6288 hrc = aProgress->COMGETTER(ErrorInfo(pErrorInfo.asOutParam()));
6289 AssertComRCReturn(hrc, hrc);
6290 }
6291 }
6292
6293 alock.release(); /* Release lock before firing event. */
6294
6295 if (vrc != VINF_NO_CHANGE)
6296 ::FireRecordingStateChangedEvent(mEventSource, aEnable, pErrorInfo);
6297
6298 if (RT_FAILURE(vrc))
6299 hrc = VBOX_E_RECORDING_ERROR;
6300
6301 ptrVM.release();
6302 }
6303
6304 return hrc;
6305#else
6306 RT_NOREF(aEnable, aProgress);
6307 ReturnComNotImplemented();
6308#endif /* VBOX_WITH_RECORDING */
6309}
6310
6311/**
6312 * Called by IInternalSessionControl::OnRecordingScreenStateChange().
6313 */
6314HRESULT Console::i_onRecordingScreenStateChange(BOOL aEnable, ULONG aScreen)
6315{
6316 RT_NOREF(aEnable, aScreen);
6317 ReturnComNotImplemented();
6318}
6319
6320/**
6321 * Called by IInternalSessionControl::OnUSBControllerChange().
6322 */
6323HRESULT Console::i_onUSBControllerChange()
6324{
6325 LogFlowThisFunc(("\n"));
6326
6327 AutoCaller autoCaller(this);
6328 AssertComRCReturnRC(autoCaller.hrc());
6329
6330 ::FireUSBControllerChangedEvent(mEventSource);
6331
6332 return S_OK;
6333}
6334
6335/**
6336 * Called by IInternalSessionControl::OnSharedFolderChange().
6337 *
6338 * @note Locks this object for writing.
6339 */
6340HRESULT Console::i_onSharedFolderChange(BOOL aGlobal)
6341{
6342 LogFlowThisFunc(("aGlobal=%RTbool\n", aGlobal));
6343
6344 AutoCaller autoCaller(this);
6345 AssertComRCReturnRC(autoCaller.hrc());
6346
6347 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
6348
6349 HRESULT hrc = i_fetchSharedFolders(aGlobal);
6350
6351 /* notify console callbacks on success */
6352 if (SUCCEEDED(hrc))
6353 {
6354 alock.release();
6355 ::FireSharedFolderChangedEvent(mEventSource, aGlobal ? Scope_Global : Scope_Machine);
6356 }
6357
6358 return hrc;
6359}
6360
6361/**
6362 * Called by IInternalSessionControl::OnGuestDebugControlChange().
6363 */
6364HRESULT Console::i_onGuestDebugControlChange(IGuestDebugControl *aGuestDebugControl)
6365{
6366 LogFlowThisFunc(("\n"));
6367
6368 AutoCaller autoCaller(this);
6369 AssertComRCReturnRC(autoCaller.hrc());
6370
6371 HRESULT hrc = S_OK;
6372
6373 /* don't trigger changes if the VM isn't running */
6374 SafeVMPtrQuiet ptrVM(this);
6375 if (ptrVM.isOk())
6376 {
6377 /// @todo
6378 }
6379
6380 if (SUCCEEDED(hrc))
6381 ::FireGuestDebugControlChangedEvent(mEventSource, aGuestDebugControl);
6382
6383 LogFlowThisFunc(("Leaving hrc=%#x\n", hrc));
6384 return hrc;
6385}
6386
6387
6388/**
6389 * Called by IInternalSessionControl::OnUSBDeviceAttach() or locally by
6390 * processRemoteUSBDevices() after IInternalMachineControl::RunUSBDeviceFilters()
6391 * returns TRUE for a given remote USB device.
6392 *
6393 * @return S_OK if the device was attached to the VM.
6394 * @return failure if not attached.
6395 *
6396 * @param aDevice The device in question.
6397 * @param aError Error information.
6398 * @param aMaskedIfs The interfaces to hide from the guest.
6399 * @param aCaptureFilename File name where to store the USB traffic.
6400 *
6401 * @note Locks this object for writing.
6402 */
6403HRESULT Console::i_onUSBDeviceAttach(IUSBDevice *aDevice, IVirtualBoxErrorInfo *aError, ULONG aMaskedIfs,
6404 const Utf8Str &aCaptureFilename)
6405{
6406#ifdef VBOX_WITH_USB
6407 LogFlowThisFunc(("aDevice=%p aError=%p\n", aDevice, aError));
6408
6409 AutoCaller autoCaller(this);
6410 ComAssertComRCRetRC(autoCaller.hrc());
6411
6412 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
6413
6414 /* Get the VM pointer (we don't need error info, since it's a callback). */
6415 SafeVMPtrQuiet ptrVM(this);
6416 if (!ptrVM.isOk())
6417 {
6418 /* The VM may be no more operational when this message arrives
6419 * (e.g. it may be Saving or Stopping or just PoweredOff) --
6420 * autoVMCaller.hrc() will return a failure in this case. */
6421 LogFlowThisFunc(("Attach request ignored (mMachineState=%d).\n", mMachineState));
6422 return ptrVM.hrc();
6423 }
6424
6425 if (aError != NULL)
6426 {
6427 /* notify callbacks about the error */
6428 alock.release();
6429 i_onUSBDeviceStateChange(aDevice, true /* aAttached */, aError);
6430 return S_OK;
6431 }
6432
6433 /* Don't proceed unless there's at least one USB hub. */
6434 if (!ptrVM.vtable()->pfnPDMR3UsbHasHub(ptrVM.rawUVM()))
6435 {
6436 LogFlowThisFunc(("Attach request ignored (no USB controller).\n"));
6437 return E_FAIL;
6438 }
6439
6440 alock.release();
6441 HRESULT hrc = i_attachUSBDevice(aDevice, aMaskedIfs, aCaptureFilename);
6442 if (FAILED(hrc))
6443 {
6444 /* take the current error info */
6445 com::ErrorInfoKeeper eik;
6446 /* the error must be a VirtualBoxErrorInfo instance */
6447 ComPtr<IVirtualBoxErrorInfo> pError = eik.takeError();
6448 Assert(!pError.isNull());
6449 if (!pError.isNull())
6450 {
6451 /* notify callbacks about the error */
6452 i_onUSBDeviceStateChange(aDevice, true /* aAttached */, pError);
6453 }
6454 }
6455
6456 return hrc;
6457
6458#else /* !VBOX_WITH_USB */
6459 RT_NOREF(aDevice, aError, aMaskedIfs, aCaptureFilename);
6460 return E_FAIL;
6461#endif /* !VBOX_WITH_USB */
6462}
6463
6464/**
6465 * Called by IInternalSessionControl::OnUSBDeviceDetach() and locally by
6466 * processRemoteUSBDevices().
6467 *
6468 * @note Locks this object for writing.
6469 */
6470HRESULT Console::i_onUSBDeviceDetach(IN_BSTR aId,
6471 IVirtualBoxErrorInfo *aError)
6472{
6473#ifdef VBOX_WITH_USB
6474 Guid Uuid(aId);
6475 LogFlowThisFunc(("aId={%RTuuid} aError=%p\n", Uuid.raw(), aError));
6476
6477 AutoCaller autoCaller(this);
6478 AssertComRCReturnRC(autoCaller.hrc());
6479
6480 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
6481
6482 /* Find the device. */
6483 ComObjPtr<OUSBDevice> pUSBDevice;
6484 USBDeviceList::iterator it = mUSBDevices.begin();
6485 while (it != mUSBDevices.end())
6486 {
6487 LogFlowThisFunc(("it={%RTuuid}\n", (*it)->i_id().raw()));
6488 if ((*it)->i_id() == Uuid)
6489 {
6490 pUSBDevice = *it;
6491 break;
6492 }
6493 ++it;
6494 }
6495
6496
6497 if (pUSBDevice.isNull())
6498 {
6499 LogFlowThisFunc(("USB device not found.\n"));
6500
6501 /* The VM may be no more operational when this message arrives
6502 * (e.g. it may be Saving or Stopping or just PoweredOff). Use
6503 * AutoVMCaller to detect it -- AutoVMCaller::hrc() will return a
6504 * failure in this case. */
6505
6506 AutoVMCallerQuiet autoVMCaller(this);
6507 if (FAILED(autoVMCaller.hrc()))
6508 {
6509 LogFlowThisFunc(("Detach request ignored (mMachineState=%d).\n", mMachineState));
6510 return autoVMCaller.hrc();
6511 }
6512
6513 /* the device must be in the list otherwise */
6514 AssertFailedReturn(E_FAIL);
6515 }
6516
6517 if (aError != NULL)
6518 {
6519 /* notify callback about an error */
6520 alock.release();
6521 i_onUSBDeviceStateChange(pUSBDevice, false /* aAttached */, aError);
6522 return S_OK;
6523 }
6524
6525 /* Remove the device from the collection, it is re-added below for failures */
6526 mUSBDevices.erase(it);
6527
6528 alock.release();
6529 HRESULT hrc = i_detachUSBDevice(pUSBDevice);
6530 if (FAILED(hrc))
6531 {
6532 /* Re-add the device to the collection */
6533 alock.acquire();
6534 mUSBDevices.push_back(pUSBDevice);
6535 alock.release();
6536 /* take the current error info */
6537 com::ErrorInfoKeeper eik;
6538 /* the error must be a VirtualBoxErrorInfo instance */
6539 ComPtr<IVirtualBoxErrorInfo> pError = eik.takeError();
6540 Assert(!pError.isNull());
6541 if (!pError.isNull())
6542 {
6543 /* notify callbacks about the error */
6544 i_onUSBDeviceStateChange(pUSBDevice, false /* aAttached */, pError);
6545 }
6546 }
6547
6548 return hrc;
6549
6550#else /* !VBOX_WITH_USB */
6551 RT_NOREF(aId, aError);
6552 return E_FAIL;
6553#endif /* !VBOX_WITH_USB */
6554}
6555
6556/**
6557 * Called by IInternalSessionControl::OnBandwidthGroupChange().
6558 *
6559 * @note Locks this object for writing.
6560 */
6561HRESULT Console::i_onBandwidthGroupChange(IBandwidthGroup *aBandwidthGroup)
6562{
6563 LogFlowThisFunc(("\n"));
6564
6565 AutoCaller autoCaller(this);
6566 AssertComRCReturnRC(autoCaller.hrc());
6567
6568 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
6569
6570 HRESULT hrc = S_OK;
6571
6572 /* don't trigger bandwidth group changes if the VM isn't running */
6573 SafeVMPtrQuiet ptrVM(this);
6574 if (ptrVM.isOk())
6575 {
6576 if ( mMachineState == MachineState_Running
6577 || mMachineState == MachineState_Teleporting
6578 || mMachineState == MachineState_LiveSnapshotting
6579 )
6580 {
6581 /* No need to call in the EMT thread. */
6582 Bstr bstrName;
6583 hrc = aBandwidthGroup->COMGETTER(Name)(bstrName.asOutParam());
6584 if (SUCCEEDED(hrc))
6585 {
6586 Utf8Str const strName(bstrName);
6587 LONG64 cMax;
6588 hrc = aBandwidthGroup->COMGETTER(MaxBytesPerSec)(&cMax);
6589 if (SUCCEEDED(hrc))
6590 {
6591 BandwidthGroupType_T enmType;
6592 hrc = aBandwidthGroup->COMGETTER(Type)(&enmType);
6593 if (SUCCEEDED(hrc))
6594 {
6595 int vrc = VINF_SUCCESS;
6596 if (enmType == BandwidthGroupType_Disk)
6597 vrc = ptrVM.vtable()->pfnPDMR3AsyncCompletionBwMgrSetMaxForFile(ptrVM.rawUVM(), strName.c_str(),
6598 (uint32_t)cMax);
6599#ifdef VBOX_WITH_NETSHAPER
6600 else if (enmType == BandwidthGroupType_Network)
6601 vrc = ptrVM.vtable()->pfnPDMR3NsBwGroupSetLimit(ptrVM.rawUVM(), strName.c_str(), cMax);
6602 else
6603 hrc = E_NOTIMPL;
6604#endif
6605 AssertRC(vrc);
6606 }
6607 }
6608 }
6609 }
6610 else
6611 hrc = i_setInvalidMachineStateError();
6612 ptrVM.release();
6613 }
6614
6615 /* notify console callbacks on success */
6616 if (SUCCEEDED(hrc))
6617 {
6618 alock.release();
6619 ::FireBandwidthGroupChangedEvent(mEventSource, aBandwidthGroup);
6620 }
6621
6622 LogFlowThisFunc(("Leaving hrc=%#x\n", hrc));
6623 return hrc;
6624}
6625
6626/**
6627 * Called by IInternalSessionControl::OnStorageDeviceChange().
6628 *
6629 * @note Locks this object for writing.
6630 */
6631HRESULT Console::i_onStorageDeviceChange(IMediumAttachment *aMediumAttachment, BOOL aRemove, BOOL aSilent)
6632{
6633 LogFlowThisFunc(("\n"));
6634
6635 AutoCaller autoCaller(this);
6636 AssertComRCReturnRC(autoCaller.hrc());
6637
6638 HRESULT hrc = S_OK;
6639
6640 /* don't trigger medium changes if the VM isn't running */
6641 SafeVMPtrQuiet ptrVM(this);
6642 if (ptrVM.isOk())
6643 {
6644 if (aRemove)
6645 hrc = i_doStorageDeviceDetach(aMediumAttachment, ptrVM.rawUVM(), ptrVM.vtable(), RT_BOOL(aSilent));
6646 else
6647 hrc = i_doStorageDeviceAttach(aMediumAttachment, ptrVM.rawUVM(), ptrVM.vtable(), RT_BOOL(aSilent));
6648 ptrVM.release();
6649 }
6650
6651 /* notify console callbacks on success */
6652 if (SUCCEEDED(hrc))
6653 ::FireStorageDeviceChangedEvent(mEventSource, aMediumAttachment, aRemove, aSilent);
6654
6655 LogFlowThisFunc(("Leaving hrc=%#x\n", hrc));
6656 return hrc;
6657}
6658
6659HRESULT Console::i_onExtraDataChange(const Bstr &aMachineId, const Bstr &aKey, const Bstr &aVal)
6660{
6661 LogFlowThisFunc(("\n"));
6662
6663 AutoCaller autoCaller(this);
6664 if (FAILED(autoCaller.hrc()))
6665 return autoCaller.hrc();
6666
6667 if (aMachineId != i_getId())
6668 return S_OK;
6669
6670 /* don't do anything if the VM isn't running */
6671 if (aKey == "VBoxInternal2/TurnResetIntoPowerOff")
6672 {
6673 SafeVMPtrQuiet ptrVM(this);
6674 if (ptrVM.isOk())
6675 {
6676 mfTurnResetIntoPowerOff = aVal == "1";
6677 int vrc = ptrVM.vtable()->pfnVMR3SetPowerOffInsteadOfReset(ptrVM.rawUVM(), mfTurnResetIntoPowerOff);
6678 AssertRC(vrc);
6679
6680 ptrVM.release();
6681 }
6682 }
6683
6684 /* notify console callbacks on success */
6685 ::FireExtraDataChangedEvent(mEventSource, aMachineId.raw(), aKey.raw(), aVal.raw());
6686
6687 LogFlowThisFunc(("Leaving S_OK\n"));
6688 return S_OK;
6689}
6690
6691/**
6692 * @note Temporarily locks this object for writing.
6693 */
6694HRESULT Console::i_getGuestProperty(const Utf8Str &aName, Utf8Str *aValue, LONG64 *aTimestamp, Utf8Str *aFlags)
6695{
6696#ifndef VBOX_WITH_GUEST_PROPS
6697 ReturnComNotImplemented();
6698#else /* VBOX_WITH_GUEST_PROPS */
6699 if (!RT_VALID_PTR(aValue))
6700 return E_POINTER;
6701#ifndef VBOX_WITH_PARFAIT /** @todo Fails due to RT_VALID_PTR() being only a != NULL check with parfait. */
6702 if (aTimestamp != NULL && !RT_VALID_PTR(aTimestamp))
6703 return E_POINTER;
6704 if (aFlags != NULL && !RT_VALID_PTR(aFlags))
6705 return E_POINTER;
6706#endif
6707
6708 AutoCaller autoCaller(this);
6709 AssertComRCReturnRC(autoCaller.hrc());
6710
6711 /* protect mpUVM (if not NULL) */
6712 SafeVMPtrQuiet ptrVM(this);
6713 if (FAILED(ptrVM.hrc()))
6714 return ptrVM.hrc();
6715
6716 /* Note: validity of mVMMDev which is bound to uninit() is guaranteed by
6717 * ptrVM, so there is no need to hold a lock of this */
6718
6719 HRESULT hrc = E_UNEXPECTED;
6720 try
6721 {
6722 VBOXHGCMSVCPARM parm[4];
6723 char szBuffer[GUEST_PROP_MAX_VALUE_LEN + GUEST_PROP_MAX_FLAGS_LEN];
6724
6725 parm[0].type = VBOX_HGCM_SVC_PARM_PTR;
6726 parm[0].u.pointer.addr = (void *)aName.c_str();
6727 parm[0].u.pointer.size = (uint32_t)aName.length() + 1; /* The + 1 is the null terminator */
6728
6729 parm[1].type = VBOX_HGCM_SVC_PARM_PTR;
6730 parm[1].u.pointer.addr = szBuffer;
6731 parm[1].u.pointer.size = sizeof(szBuffer);
6732
6733 parm[2].type = VBOX_HGCM_SVC_PARM_64BIT;
6734 parm[2].u.uint64 = 0;
6735
6736 parm[3].type = VBOX_HGCM_SVC_PARM_32BIT;
6737 parm[3].u.uint32 = 0;
6738
6739 int vrc = m_pVMMDev->hgcmHostCall("VBoxGuestPropSvc", GUEST_PROP_FN_HOST_GET_PROP,
6740 4, &parm[0]);
6741 /* The returned string should never be able to be greater than our buffer */
6742 AssertLogRel(vrc != VERR_BUFFER_OVERFLOW);
6743 AssertLogRel(RT_FAILURE(vrc) || parm[2].type == VBOX_HGCM_SVC_PARM_64BIT);
6744 if (RT_SUCCESS(vrc))
6745 {
6746 *aValue = szBuffer;
6747
6748 if (aTimestamp)
6749 *aTimestamp = parm[2].u.uint64;
6750
6751 if (aFlags)
6752 *aFlags = &szBuffer[strlen(szBuffer) + 1];
6753
6754 hrc = S_OK;
6755 }
6756 else if (vrc == VERR_NOT_FOUND)
6757 {
6758 *aValue = "";
6759 hrc = S_OK;
6760 }
6761 else
6762 hrc = setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("The VBoxGuestPropSvc service call failed with the error %Rrc"), vrc);
6763 }
6764 catch(std::bad_alloc & /*e*/)
6765 {
6766 hrc = E_OUTOFMEMORY;
6767 }
6768
6769 return hrc;
6770#endif /* VBOX_WITH_GUEST_PROPS */
6771}
6772
6773/**
6774 * @note Temporarily locks this object for writing.
6775 */
6776HRESULT Console::i_setGuestProperty(const Utf8Str &aName, const Utf8Str &aValue, const Utf8Str &aFlags)
6777{
6778#ifndef VBOX_WITH_GUEST_PROPS
6779 ReturnComNotImplemented();
6780#else /* VBOX_WITH_GUEST_PROPS */
6781
6782 AutoCaller autoCaller(this);
6783 AssertComRCReturnRC(autoCaller.hrc());
6784
6785 /* protect mpUVM (if not NULL) */
6786 SafeVMPtrQuiet ptrVM(this);
6787 if (FAILED(ptrVM.hrc()))
6788 return ptrVM.hrc();
6789
6790 /* Note: validity of mVMMDev which is bound to uninit() is guaranteed by
6791 * ptrVM, so there is no need to hold a lock of this */
6792
6793 VBOXHGCMSVCPARM parm[3];
6794
6795 parm[0].type = VBOX_HGCM_SVC_PARM_PTR;
6796 parm[0].u.pointer.addr = (void*)aName.c_str();
6797 parm[0].u.pointer.size = (uint32_t)aName.length() + 1; /* The + 1 is the null terminator */
6798
6799 parm[1].type = VBOX_HGCM_SVC_PARM_PTR;
6800 parm[1].u.pointer.addr = (void *)aValue.c_str();
6801 parm[1].u.pointer.size = (uint32_t)aValue.length() + 1; /* The + 1 is the null terminator */
6802
6803 int vrc;
6804 if (aFlags.isEmpty())
6805 {
6806 vrc = m_pVMMDev->hgcmHostCall("VBoxGuestPropSvc", GUEST_PROP_FN_HOST_SET_PROP_VALUE, 2, &parm[0]);
6807 }
6808 else
6809 {
6810 parm[2].type = VBOX_HGCM_SVC_PARM_PTR;
6811 parm[2].u.pointer.addr = (void*)aFlags.c_str();
6812 parm[2].u.pointer.size = (uint32_t)aFlags.length() + 1; /* The + 1 is the null terminator */
6813
6814 vrc = m_pVMMDev->hgcmHostCall("VBoxGuestPropSvc", GUEST_PROP_FN_HOST_SET_PROP, 3, &parm[0]);
6815 }
6816
6817 HRESULT hrc = S_OK;
6818 if (RT_FAILURE(vrc))
6819 hrc = setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("The VBoxGuestPropSvc service call failed with the error %Rrc"), vrc);
6820 return hrc;
6821#endif /* VBOX_WITH_GUEST_PROPS */
6822}
6823
6824HRESULT Console::i_deleteGuestProperty(const Utf8Str &aName)
6825{
6826#ifndef VBOX_WITH_GUEST_PROPS
6827 ReturnComNotImplemented();
6828#else /* VBOX_WITH_GUEST_PROPS */
6829
6830 AutoCaller autoCaller(this);
6831 AssertComRCReturnRC(autoCaller.hrc());
6832
6833 /* protect mpUVM (if not NULL) */
6834 SafeVMPtrQuiet ptrVM(this);
6835 if (FAILED(ptrVM.hrc()))
6836 return ptrVM.hrc();
6837
6838 /* Note: validity of mVMMDev which is bound to uninit() is guaranteed by
6839 * ptrVM, so there is no need to hold a lock of this */
6840
6841 VBOXHGCMSVCPARM parm[1];
6842 parm[0].type = VBOX_HGCM_SVC_PARM_PTR;
6843 parm[0].u.pointer.addr = (void*)aName.c_str();
6844 parm[0].u.pointer.size = (uint32_t)aName.length() + 1; /* The + 1 is the null terminator */
6845
6846 int vrc = m_pVMMDev->hgcmHostCall("VBoxGuestPropSvc", GUEST_PROP_FN_HOST_DEL_PROP, 1, &parm[0]);
6847
6848 HRESULT hrc = S_OK;
6849 if (RT_FAILURE(vrc))
6850 hrc = setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("The VBoxGuestPropSvc service call failed with the error %Rrc"), vrc);
6851 return hrc;
6852#endif /* VBOX_WITH_GUEST_PROPS */
6853}
6854
6855/**
6856 * @note Temporarily locks this object for writing.
6857 */
6858HRESULT Console::i_enumerateGuestProperties(const Utf8Str &aPatterns,
6859 std::vector<Utf8Str> &aNames,
6860 std::vector<Utf8Str> &aValues,
6861 std::vector<LONG64> &aTimestamps,
6862 std::vector<Utf8Str> &aFlags)
6863{
6864#ifndef VBOX_WITH_GUEST_PROPS
6865 ReturnComNotImplemented();
6866#else /* VBOX_WITH_GUEST_PROPS */
6867
6868 AutoCaller autoCaller(this);
6869 AssertComRCReturnRC(autoCaller.hrc());
6870
6871 /* protect mpUVM (if not NULL) */
6872 AutoVMCallerWeak autoVMCaller(this);
6873 if (FAILED(autoVMCaller.hrc()))
6874 return autoVMCaller.hrc();
6875
6876 /* Note: validity of mVMMDev which is bound to uninit() is guaranteed by
6877 * autoVMCaller, so there is no need to hold a lock of this */
6878
6879 return i_doEnumerateGuestProperties(aPatterns, aNames, aValues, aTimestamps, aFlags);
6880#endif /* VBOX_WITH_GUEST_PROPS */
6881}
6882
6883
6884/*
6885 * Internal: helper function for connecting progress reporting
6886 */
6887static DECLCALLBACK(int) onlineMergeMediumProgress(void *pvUser, unsigned uPercentage)
6888{
6889 HRESULT hrc = S_OK;
6890 IProgress *pProgress = static_cast<IProgress *>(pvUser);
6891 if (pProgress)
6892 {
6893 ComPtr<IInternalProgressControl> pProgressControl(pProgress);
6894 AssertReturn(!!pProgressControl, VERR_INVALID_PARAMETER);
6895 hrc = pProgressControl->SetCurrentOperationProgress(uPercentage);
6896 }
6897 return SUCCEEDED(hrc) ? VINF_SUCCESS : VERR_GENERAL_FAILURE;
6898}
6899
6900/**
6901 * @note Temporarily locks this object for writing. bird: And/or reading?
6902 */
6903HRESULT Console::i_onlineMergeMedium(IMediumAttachment *aMediumAttachment,
6904 ULONG aSourceIdx, ULONG aTargetIdx,
6905 IProgress *aProgress)
6906{
6907 AutoCaller autoCaller(this);
6908 AssertComRCReturnRC(autoCaller.hrc());
6909
6910 HRESULT hrc = S_OK;
6911 int vrc = VINF_SUCCESS;
6912
6913 /* Get the VM - must be done before the read-locking. */
6914 SafeVMPtr ptrVM(this);
6915 if (!ptrVM.isOk())
6916 return ptrVM.hrc();
6917
6918 /* We will need to release the lock before doing the actual merge */
6919 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
6920
6921 /* paranoia - we don't want merges to happen while teleporting etc. */
6922 switch (mMachineState)
6923 {
6924 case MachineState_DeletingSnapshotOnline:
6925 case MachineState_DeletingSnapshotPaused:
6926 break;
6927
6928 default:
6929 return i_setInvalidMachineStateError();
6930 }
6931
6932 /** @todo AssertComRC -> AssertComRCReturn! Could potentially end up
6933 * using uninitialized variables here. */
6934 BOOL fBuiltinIOCache = FALSE;
6935 hrc = mMachine->COMGETTER(IOCacheEnabled)(&fBuiltinIOCache);
6936 AssertComRC(hrc);
6937 SafeIfaceArray<IStorageController> ctrls;
6938 hrc = mMachine->COMGETTER(StorageControllers)(ComSafeArrayAsOutParam(ctrls));
6939 AssertComRC(hrc);
6940 LONG lDev = -1;
6941 hrc = aMediumAttachment->COMGETTER(Device)(&lDev);
6942 AssertComRC(hrc);
6943 LONG lPort = -1;
6944 hrc = aMediumAttachment->COMGETTER(Port)(&lPort);
6945 AssertComRC(hrc);
6946 IMedium *pMedium = NULL;
6947 hrc = aMediumAttachment->COMGETTER(Medium)(&pMedium);
6948 AssertComRC(hrc);
6949 Bstr mediumLocation;
6950 if (pMedium)
6951 {
6952 hrc = pMedium->COMGETTER(Location)(mediumLocation.asOutParam());
6953 AssertComRC(hrc);
6954 }
6955
6956 Bstr attCtrlName;
6957 hrc = aMediumAttachment->COMGETTER(Controller)(attCtrlName.asOutParam());
6958 AssertComRC(hrc);
6959 ComPtr<IStorageController> pStorageController;
6960 for (size_t i = 0; i < ctrls.size(); ++i)
6961 {
6962 Bstr ctrlName;
6963 hrc = ctrls[i]->COMGETTER(Name)(ctrlName.asOutParam());
6964 AssertComRC(hrc);
6965 if (attCtrlName == ctrlName)
6966 {
6967 pStorageController = ctrls[i];
6968 break;
6969 }
6970 }
6971 if (pStorageController.isNull())
6972 return setError(E_FAIL,
6973 tr("Could not find storage controller '%ls'"),
6974 attCtrlName.raw());
6975
6976 StorageControllerType_T enmCtrlType;
6977 hrc = pStorageController->COMGETTER(ControllerType)(&enmCtrlType);
6978 AssertComRC(hrc);
6979 const char *pcszDevice = i_storageControllerTypeToStr(enmCtrlType);
6980
6981 StorageBus_T enmBus;
6982 hrc = pStorageController->COMGETTER(Bus)(&enmBus);
6983 AssertComRC(hrc);
6984
6985 ULONG uInstance = 0;
6986 hrc = pStorageController->COMGETTER(Instance)(&uInstance);
6987 AssertComRC(hrc);
6988
6989 BOOL fUseHostIOCache = TRUE;
6990 hrc = pStorageController->COMGETTER(UseHostIOCache)(&fUseHostIOCache);
6991 AssertComRC(hrc);
6992
6993 unsigned uLUN;
6994 hrc = Console::i_storageBusPortDeviceToLun(enmBus, lPort, lDev, uLUN);
6995 AssertComRCReturnRC(hrc);
6996
6997 Assert(mMachineState == MachineState_DeletingSnapshotOnline);
6998
6999 /* Pause the VM, as it might have pending IO on this drive */
7000 bool fResume = false;
7001 hrc = i_suspendBeforeConfigChange(ptrVM.rawUVM(), ptrVM.vtable(), &alock, &fResume);
7002 if (FAILED(hrc))
7003 return hrc;
7004
7005 bool fInsertDiskIntegrityDrv = false;
7006 Bstr strDiskIntegrityFlag;
7007 hrc = mMachine->GetExtraData(Bstr("VBoxInternal2/EnableDiskIntegrityDriver").raw(), strDiskIntegrityFlag.asOutParam());
7008 if ( hrc == S_OK
7009 && strDiskIntegrityFlag == "1")
7010 fInsertDiskIntegrityDrv = true;
7011
7012 alock.release();
7013
7014 Console::ReconfigureMediumAttachmentArgs Args1;
7015 Args1.pcszDevice = pcszDevice;
7016 Args1.uInstance = uInstance;
7017 Args1.enmBus = enmBus;
7018 Args1.fUseHostIOCache = fUseHostIOCache;
7019 Args1.fBuiltinIOCache = fBuiltinIOCache;
7020 Args1.fInsertDiskIntegrityDrv = fInsertDiskIntegrityDrv;
7021 Args1.fSetupMerge = true;
7022 Args1.uMergeSource = aSourceIdx;
7023 Args1.uMergeTarget = aTargetIdx;
7024 Args1.aMediumAtt = aMediumAttachment;
7025 Args1.aMachineState = mMachineState;
7026 vrc = ptrVM.vtable()->pfnVMR3ReqCallWaitU(ptrVM.rawUVM(), VMCPUID_ANY, (PFNRT)i_reconfigureMediumAttachment, 5,
7027 this, ptrVM.rawUVM(), ptrVM.vtable(), &Args1, &hrc);
7028 /* error handling is after resuming the VM */
7029
7030 if (fResume)
7031 i_resumeAfterConfigChange(ptrVM.rawUVM(), ptrVM.vtable());
7032
7033 if (RT_FAILURE(vrc))
7034 return setErrorBoth(E_FAIL, vrc, "%Rrc", vrc);
7035 if (FAILED(hrc))
7036 return hrc;
7037
7038 PPDMIBASE pIBase = NULL;
7039 PPDMIMEDIA pIMedium = NULL;
7040 vrc = ptrVM.vtable()->pfnPDMR3QueryDriverOnLun(ptrVM.rawUVM(), pcszDevice, uInstance, uLUN, "VD", &pIBase);
7041 if (RT_SUCCESS(vrc))
7042 {
7043 if (pIBase)
7044 {
7045 pIMedium = (PPDMIMEDIA)pIBase->pfnQueryInterface(pIBase, PDMIMEDIA_IID);
7046 if (!pIMedium)
7047 return setError(E_FAIL, tr("could not query medium interface of controller"));
7048 }
7049 else
7050 return setError(E_FAIL, tr("could not query base interface of controller"));
7051 }
7052
7053 /* Finally trigger the merge. */
7054 vrc = pIMedium->pfnMerge(pIMedium, onlineMergeMediumProgress, aProgress);
7055 if (RT_FAILURE(vrc))
7056 return setErrorBoth(E_FAIL, vrc, tr("Failed to perform an online medium merge (%Rrc)"), vrc);
7057
7058 alock.acquire();
7059 /* Pause the VM, as it might have pending IO on this drive */
7060 hrc = i_suspendBeforeConfigChange(ptrVM.rawUVM(), ptrVM.vtable(), &alock, &fResume);
7061 if (FAILED(hrc))
7062 return hrc;
7063 alock.release();
7064
7065 /* Update medium chain and state now, so that the VM can continue. */
7066 hrc = mControl->FinishOnlineMergeMedium();
7067
7068 Console::ReconfigureMediumAttachmentArgs Args2;
7069 Args2.pcszDevice = pcszDevice;
7070 Args2.uInstance = uInstance;
7071 Args2.enmBus = enmBus;
7072 Args2.fUseHostIOCache = fUseHostIOCache;
7073 Args2.fBuiltinIOCache = fBuiltinIOCache;
7074 Args2.fInsertDiskIntegrityDrv = fInsertDiskIntegrityDrv;
7075 Args2.fSetupMerge = false;
7076 Args2.uMergeSource = 0;
7077 Args2.uMergeTarget = 0;
7078 Args2.aMediumAtt = aMediumAttachment;
7079 Args2.aMachineState = mMachineState;
7080 vrc = ptrVM.vtable()->pfnVMR3ReqCallWaitU(ptrVM.rawUVM(), VMCPUID_ANY, (PFNRT)i_reconfigureMediumAttachment, 5,
7081 this, ptrVM.rawUVM(), ptrVM.vtable(), &Args2, &hrc);
7082 /* error handling is after resuming the VM */
7083
7084 if (fResume)
7085 i_resumeAfterConfigChange(ptrVM.rawUVM(), ptrVM.vtable());
7086
7087 if (RT_FAILURE(vrc))
7088 return setErrorBoth(E_FAIL, vrc, "%Rrc", vrc);
7089 if (FAILED(hrc))
7090 return hrc;
7091
7092 return hrc;
7093}
7094
7095HRESULT Console::i_reconfigureMediumAttachments(const std::vector<ComPtr<IMediumAttachment> > &aAttachments)
7096{
7097
7098 AutoCaller autoCaller(this);
7099 if (FAILED(autoCaller.hrc()))
7100 return autoCaller.hrc();
7101
7102 /* get the VM handle. */
7103 SafeVMPtr ptrVM(this);
7104 if (!ptrVM.isOk())
7105 return ptrVM.hrc();
7106
7107 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
7108
7109 for (size_t i = 0; i < aAttachments.size(); ++i)
7110 {
7111 /*
7112 * We could pass the objects, but then EMT would have to do lots of
7113 * IPC (to VBoxSVC) which takes a significant amount of time.
7114 * Better query needed values here and pass them.
7115 */
7116 Bstr controllerName;
7117 HRESULT hrc = aAttachments[i]->COMGETTER(Controller)(controllerName.asOutParam());
7118 if (FAILED(hrc))
7119 return hrc;
7120
7121 ComPtr<IStorageController> pStorageController;
7122 hrc = mMachine->GetStorageControllerByName(controllerName.raw(), pStorageController.asOutParam());
7123 if (FAILED(hrc))
7124 return hrc;
7125
7126 StorageControllerType_T enmController;
7127 hrc = pStorageController->COMGETTER(ControllerType)(&enmController);
7128 if (FAILED(hrc))
7129 return hrc;
7130 const char * const pcszDevice = i_storageControllerTypeToStr(enmController);
7131
7132 ULONG lInstance;
7133 hrc = pStorageController->COMGETTER(Instance)(&lInstance);
7134 if (FAILED(hrc))
7135 return hrc;
7136
7137 StorageBus_T enmBus;
7138 hrc = pStorageController->COMGETTER(Bus)(&enmBus);
7139 if (FAILED(hrc))
7140 return hrc;
7141
7142 BOOL fUseHostIOCache;
7143 hrc = pStorageController->COMGETTER(UseHostIOCache)(&fUseHostIOCache);
7144 if (FAILED(hrc))
7145 return hrc;
7146
7147 BOOL fBuiltinIOCache;
7148 hrc = mMachine->COMGETTER(IOCacheEnabled)(&fBuiltinIOCache);
7149 if (FAILED(hrc))
7150 return hrc;
7151
7152 bool fInsertDiskIntegrityDrv = false;
7153 Bstr strDiskIntegrityFlag;
7154 hrc = mMachine->GetExtraData(Bstr("VBoxInternal2/EnableDiskIntegrityDriver").raw(),
7155 strDiskIntegrityFlag.asOutParam());
7156 if ( hrc == S_OK
7157 && strDiskIntegrityFlag == "1")
7158 fInsertDiskIntegrityDrv = true;
7159
7160 alock.release();
7161
7162 hrc = S_OK;
7163 Console::ReconfigureMediumAttachmentArgs Args;
7164 Args.pcszDevice = pcszDevice;
7165 Args.uInstance = lInstance;
7166 Args.enmBus = enmBus;
7167 Args.fUseHostIOCache = fUseHostIOCache;
7168 Args.fBuiltinIOCache = fBuiltinIOCache;
7169 Args.fInsertDiskIntegrityDrv = fInsertDiskIntegrityDrv;
7170 Args.fSetupMerge = false;
7171 Args.uMergeSource = 0;
7172 Args.uMergeTarget = 0;
7173 Args.aMediumAtt = aAttachments[i];
7174 Args.aMachineState = mMachineState;
7175 int vrc = ptrVM.vtable()->pfnVMR3ReqCallWaitU(ptrVM.rawUVM(), VMCPUID_ANY, (PFNRT)i_reconfigureMediumAttachment, 5,
7176 this, ptrVM.rawUVM(), ptrVM.vtable(), &Args, &hrc);
7177 if (RT_FAILURE(vrc))
7178 throw setErrorBoth(E_FAIL, vrc, "%Rrc", vrc);
7179 if (FAILED(hrc))
7180 throw hrc;
7181
7182 alock.acquire();
7183 }
7184
7185 return S_OK;
7186}
7187
7188HRESULT Console::i_onVMProcessPriorityChange(VMProcPriority_T priority)
7189{
7190 AutoCaller autoCaller(this);
7191 HRESULT hrc = autoCaller.hrc();
7192 if (FAILED(hrc))
7193 return hrc;
7194
7195 RTPROCPRIORITY enmProcPriority = RTPROCPRIORITY_DEFAULT;
7196 switch (priority)
7197 {
7198 case VMProcPriority_Default:
7199 enmProcPriority = RTPROCPRIORITY_DEFAULT;
7200 break;
7201 case VMProcPriority_Flat:
7202 enmProcPriority = RTPROCPRIORITY_FLAT;
7203 break;
7204 case VMProcPriority_Low:
7205 enmProcPriority = RTPROCPRIORITY_LOW;
7206 break;
7207 case VMProcPriority_Normal:
7208 enmProcPriority = RTPROCPRIORITY_NORMAL;
7209 break;
7210 case VMProcPriority_High:
7211 enmProcPriority = RTPROCPRIORITY_HIGH;
7212 break;
7213 default:
7214 return setError(E_INVALIDARG, tr("Unsupported priority type (%d)"), priority);
7215 }
7216 int vrc = RTProcSetPriority(enmProcPriority);
7217 if (RT_FAILURE(vrc))
7218 hrc = setErrorBoth(VBOX_E_VM_ERROR, vrc,
7219 tr("Could not set the priority of the process (%Rrc). Try to set it when VM is not started."), vrc);
7220
7221 return hrc;
7222}
7223
7224/**
7225 * Load an HGCM service.
7226 *
7227 * Main purpose of this method is to allow extension packs to load HGCM
7228 * service modules, which they can't, because the HGCM functionality lives
7229 * in module VBoxC (and ConsoleImpl.cpp is part of it and thus can call it).
7230 * Extension modules must not link directly against VBoxC, (XP)COM is
7231 * handling this.
7232 */
7233int Console::i_hgcmLoadService(const char *pszServiceLibrary, const char *pszServiceName)
7234{
7235 /* Everyone seems to delegate all HGCM calls to VMMDev, so stick to this
7236 * convention. Adds one level of indirection for no obvious reason. */
7237 AssertPtrReturn(m_pVMMDev, VERR_INVALID_STATE);
7238 return m_pVMMDev->hgcmLoadService(pszServiceLibrary, pszServiceName);
7239}
7240
7241/**
7242 * Merely passes the call to Guest::enableVMMStatistics().
7243 */
7244void Console::i_enableVMMStatistics(BOOL aEnable)
7245{
7246 if (mGuest)
7247 mGuest->i_enableVMMStatistics(aEnable);
7248}
7249
7250/**
7251 * Worker for Console::Pause and internal entry point for pausing a VM for
7252 * a specific reason.
7253 */
7254HRESULT Console::i_pause(Reason_T aReason)
7255{
7256 LogFlowThisFuncEnter();
7257
7258 AutoCaller autoCaller(this);
7259 if (FAILED(autoCaller.hrc())) return autoCaller.hrc();
7260
7261 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
7262
7263 switch (mMachineState)
7264 {
7265 case MachineState_Running:
7266 case MachineState_Teleporting:
7267 case MachineState_LiveSnapshotting:
7268 break;
7269
7270 case MachineState_Paused:
7271 case MachineState_TeleportingPausedVM:
7272 case MachineState_OnlineSnapshotting:
7273 /* Remove any keys which are supposed to be removed on a suspend. */
7274 if ( aReason == Reason_HostSuspend
7275 || aReason == Reason_HostBatteryLow)
7276 {
7277 i_removeSecretKeysOnSuspend();
7278 return S_OK;
7279 }
7280 return setError(VBOX_E_INVALID_VM_STATE, tr("Already paused"));
7281
7282 default:
7283 return i_setInvalidMachineStateError();
7284 }
7285
7286 /* get the VM handle. */
7287 SafeVMPtr ptrVM(this);
7288 HRESULT hrc = ptrVM.hrc();
7289 if (SUCCEEDED(hrc))
7290 {
7291 /* release the lock before a VMR3* call (EMT might wait for it, @bugref{7648})! */
7292 alock.release();
7293
7294 LogFlowThisFunc(("Sending PAUSE request...\n"));
7295 if (aReason != Reason_Unspecified)
7296 LogRel(("Pausing VM execution, reason '%s'\n", ::stringifyReason(aReason)));
7297
7298 /** @todo r=klaus make use of aReason */
7299 VMSUSPENDREASON enmReason = VMSUSPENDREASON_USER;
7300 if (aReason == Reason_HostSuspend)
7301 enmReason = VMSUSPENDREASON_HOST_SUSPEND;
7302 else if (aReason == Reason_HostBatteryLow)
7303 enmReason = VMSUSPENDREASON_HOST_BATTERY_LOW;
7304
7305 int vrc = ptrVM.vtable()->pfnVMR3Suspend(ptrVM.rawUVM(), enmReason);
7306
7307 if (RT_FAILURE(vrc))
7308 hrc = setErrorBoth(VBOX_E_VM_ERROR, vrc, tr("Could not suspend the machine execution (%Rrc)"), vrc);
7309 else if ( aReason == Reason_HostSuspend
7310 || aReason == Reason_HostBatteryLow)
7311 {
7312 alock.acquire();
7313 i_removeSecretKeysOnSuspend();
7314 }
7315 }
7316
7317 LogFlowThisFunc(("hrc=%Rhrc\n", hrc));
7318 LogFlowThisFuncLeave();
7319 return hrc;
7320}
7321
7322/**
7323 * Worker for Console::Resume and internal entry point for resuming a VM for
7324 * a specific reason.
7325 */
7326HRESULT Console::i_resume(Reason_T aReason, AutoWriteLock &alock)
7327{
7328 LogFlowThisFuncEnter();
7329
7330 AutoCaller autoCaller(this);
7331 if (FAILED(autoCaller.hrc())) return autoCaller.hrc();
7332
7333 /* get the VM handle. */
7334 SafeVMPtr ptrVM(this);
7335 if (!ptrVM.isOk())
7336 return ptrVM.hrc();
7337
7338 /* release the lock before a VMR3* call (EMT might wait for it, @bugref{7648})! */
7339 alock.release();
7340
7341 LogFlowThisFunc(("Sending RESUME request...\n"));
7342 if (aReason != Reason_Unspecified)
7343 LogRel(("Resuming VM execution, reason '%s'\n", ::stringifyReason(aReason)));
7344
7345 int vrc;
7346 VMSTATE const enmVMState = mpVMM->pfnVMR3GetStateU(ptrVM.rawUVM());
7347 if (enmVMState == VMSTATE_CREATED)
7348 {
7349#ifdef VBOX_WITH_EXTPACK
7350 vrc = mptrExtPackManager->i_callAllVmPowerOnHooks(this, ptrVM.vtable()->pfnVMR3GetVM(ptrVM.rawUVM()), ptrVM.vtable());
7351#else
7352 vrc = VINF_SUCCESS;
7353#endif
7354 if (RT_SUCCESS(vrc))
7355 vrc = ptrVM.vtable()->pfnVMR3PowerOn(ptrVM.rawUVM()); /* (PowerUpPaused) */
7356 }
7357 else
7358 {
7359 VMRESUMEREASON enmReason;
7360 if (aReason == Reason_HostResume)
7361 {
7362 /*
7363 * Host resume may be called multiple times successively. We don't want to VMR3Resume->vmR3Resume->vmR3TrySetState()
7364 * to assert on us, hence check for the VM state here and bail if it's not in the 'suspended' state.
7365 * See @bugref{3495}.
7366 *
7367 * Also, don't resume the VM through a host-resume unless it was suspended due to a host-suspend.
7368 */
7369 if (enmVMState != VMSTATE_SUSPENDED)
7370 {
7371 LogRel(("Ignoring VM resume request, VM is currently not suspended (%d)\n", enmVMState));
7372 return S_OK;
7373 }
7374 VMSUSPENDREASON const enmSuspendReason = ptrVM.vtable()->pfnVMR3GetSuspendReason(ptrVM.rawUVM());
7375 if (enmSuspendReason != VMSUSPENDREASON_HOST_SUSPEND)
7376 {
7377 LogRel(("Ignoring VM resume request, VM was not suspended due to host-suspend (%d)\n", enmSuspendReason));
7378 return S_OK;
7379 }
7380
7381 enmReason = VMRESUMEREASON_HOST_RESUME;
7382 }
7383 else
7384 {
7385 /*
7386 * Any other reason to resume the VM throws an error when the VM was suspended due to a host suspend.
7387 * See @bugref{7836}.
7388 */
7389 if ( enmVMState == VMSTATE_SUSPENDED
7390 && ptrVM.vtable()->pfnVMR3GetSuspendReason(ptrVM.rawUVM()) == VMSUSPENDREASON_HOST_SUSPEND)
7391 return setError(VBOX_E_INVALID_VM_STATE, tr("VM is paused due to host power management"));
7392
7393 enmReason = aReason == Reason_Snapshot ? VMRESUMEREASON_STATE_SAVED : VMRESUMEREASON_USER;
7394 }
7395
7396 // for snapshots: no state change callback, VBoxSVC does everything
7397 if (aReason == Reason_Snapshot)
7398 mVMStateChangeCallbackDisabled = true;
7399
7400 vrc = ptrVM.vtable()->pfnVMR3Resume(ptrVM.rawUVM(), enmReason);
7401
7402 if (aReason == Reason_Snapshot)
7403 mVMStateChangeCallbackDisabled = false;
7404 }
7405
7406 HRESULT hrc = RT_SUCCESS(vrc) ? S_OK
7407 : setErrorBoth(VBOX_E_VM_ERROR, vrc, tr("Could not resume the machine execution (%Rrc)"), vrc);
7408
7409 LogFlowThisFunc(("hrc=%Rhrc\n", hrc));
7410 LogFlowThisFuncLeave();
7411 return hrc;
7412}
7413
7414/**
7415 * Internal entry point for saving state of a VM for a specific reason. This
7416 * method is completely synchronous.
7417 *
7418 * The machine state is already set appropriately. It is only changed when
7419 * saving state actually paused the VM (happens with live snapshots and
7420 * teleportation), and in this case reflects the now paused variant.
7421 *
7422 * @note Locks this object for writing.
7423 */
7424HRESULT Console::i_saveState(Reason_T aReason, const ComPtr<IProgress> &aProgress, const ComPtr<ISnapshot> &aSnapshot,
7425 const Utf8Str &aStateFilePath, bool aPauseVM, bool &aLeftPaused)
7426{
7427 LogFlowThisFuncEnter();
7428 aLeftPaused = false;
7429
7430 AssertReturn(!aProgress.isNull(), E_INVALIDARG);
7431 AssertReturn(!aStateFilePath.isEmpty(), E_INVALIDARG);
7432 Assert(aSnapshot.isNull() || aReason == Reason_Snapshot);
7433
7434 AutoCaller autoCaller(this);
7435 if (FAILED(autoCaller.hrc())) return autoCaller.hrc();
7436
7437 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
7438
7439 LogFlowThisFunc(("mMachineState=%d\n", mMachineState));
7440 if ( mMachineState != MachineState_Saving
7441 && mMachineState != MachineState_LiveSnapshotting
7442 && mMachineState != MachineState_OnlineSnapshotting
7443 && mMachineState != MachineState_Teleporting
7444 && mMachineState != MachineState_TeleportingPausedVM)
7445 return setError(VBOX_E_INVALID_VM_STATE,
7446 tr("Cannot save the execution state as the machine is not running or paused (machine state: %s)"),
7447 Global::stringifyMachineState(mMachineState));
7448 bool fContinueAfterwards = mMachineState != MachineState_Saving;
7449
7450 Bstr strDisableSaveState;
7451 mMachine->GetExtraData(Bstr("VBoxInternal2/DisableSaveState").raw(), strDisableSaveState.asOutParam());
7452 if (strDisableSaveState == "1")
7453 return setError(VBOX_E_VM_ERROR,
7454 tr("Saving the execution state is disabled for this VM"));
7455
7456 if (aReason != Reason_Unspecified)
7457 LogRel(("Saving state of VM, reason '%s'\n", ::stringifyReason(aReason)));
7458
7459 /* ensure the directory for the saved state file exists */
7460 {
7461 Utf8Str dir = aStateFilePath;
7462 dir.stripFilename();
7463 if (!RTDirExists(dir.c_str()))
7464 {
7465 int vrc = RTDirCreateFullPath(dir.c_str(), 0700);
7466 if (RT_FAILURE(vrc))
7467 return setErrorBoth(VBOX_E_FILE_ERROR, vrc, tr("Could not create a directory '%s' to save the state to (%Rrc)"),
7468 dir.c_str(), vrc);
7469 }
7470 }
7471
7472 /* Get the VM handle early, we need it in several places. */
7473 SafeVMPtr ptrVM(this);
7474 HRESULT hrc = ptrVM.hrc();
7475 if (SUCCEEDED(hrc))
7476 {
7477 bool fPaused = false;
7478 if (aPauseVM)
7479 {
7480 /* release the lock before a VMR3* call (EMT might wait for it, @bugref{7648})! */
7481 alock.release();
7482 VMSUSPENDREASON enmReason = VMSUSPENDREASON_USER;
7483 if (aReason == Reason_HostSuspend)
7484 enmReason = VMSUSPENDREASON_HOST_SUSPEND;
7485 else if (aReason == Reason_HostBatteryLow)
7486 enmReason = VMSUSPENDREASON_HOST_BATTERY_LOW;
7487 int vrc = ptrVM.vtable()->pfnVMR3Suspend(ptrVM.rawUVM(), enmReason);
7488 alock.acquire();
7489
7490 if (RT_SUCCESS(vrc))
7491 fPaused = true;
7492 else
7493 hrc = setErrorBoth(VBOX_E_VM_ERROR, vrc, tr("Could not suspend the machine execution (%Rrc)"), vrc);
7494 }
7495
7496 Bstr bstrStateKeyId;
7497 Bstr bstrStateKeyStore;
7498#ifdef VBOX_WITH_FULL_VM_ENCRYPTION
7499 if (SUCCEEDED(hrc))
7500 {
7501 hrc = mMachine->COMGETTER(StateKeyId)(bstrStateKeyId.asOutParam());
7502 if (SUCCEEDED(hrc))
7503 {
7504 hrc = mMachine->COMGETTER(StateKeyStore)(bstrStateKeyStore.asOutParam());
7505 if (FAILED(hrc))
7506 hrc = setError(hrc, tr("Could not get key store for state file(%Rhrc (0x%08X))"), hrc, hrc);
7507 }
7508 else
7509 hrc = setError(hrc, tr("Could not get key id for state file(%Rhrc (0x%08X))"), hrc, hrc);
7510 }
7511#endif
7512
7513 if (SUCCEEDED(hrc))
7514 {
7515 LogFlowFunc(("Saving the state to '%s'...\n", aStateFilePath.c_str()));
7516
7517 mpVmm2UserMethods->pISnapshot = aSnapshot;
7518 mptrCancelableProgress = aProgress;
7519
7520 SsmStream ssmStream(this, ptrVM.vtable(), m_pKeyStore, bstrStateKeyId, bstrStateKeyStore);
7521 int vrc = ssmStream.create(aStateFilePath.c_str());
7522 if (RT_SUCCESS(vrc))
7523 {
7524 PCSSMSTRMOPS pStreamOps = NULL;
7525 void *pvStreamOpsUser = NULL;
7526 vrc = ssmStream.querySsmStrmOps(&pStreamOps, &pvStreamOpsUser);
7527 if (RT_SUCCESS(vrc))
7528 {
7529 alock.release();
7530
7531 vrc = ptrVM.vtable()->pfnVMR3Save(ptrVM.rawUVM(),
7532 NULL /*pszFilename*/,
7533 pStreamOps,
7534 pvStreamOpsUser,
7535 fContinueAfterwards,
7536 Console::i_stateProgressCallback,
7537 static_cast<IProgress *>(aProgress),
7538 &aLeftPaused);
7539
7540 alock.acquire();
7541 }
7542
7543 ssmStream.close();
7544 if (RT_FAILURE(vrc))
7545 {
7546 int vrc2 = RTFileDelete(aStateFilePath.c_str());
7547 AssertRC(vrc2);
7548 }
7549 }
7550
7551 mpVmm2UserMethods->pISnapshot = NULL;
7552 mptrCancelableProgress.setNull();
7553 if (RT_SUCCESS(vrc))
7554 {
7555 Assert(fContinueAfterwards || !aLeftPaused);
7556
7557 if (!fContinueAfterwards)
7558 {
7559 /*
7560 * The machine has been successfully saved, so power it down
7561 * (vmstateChangeCallback() will set state to Saved on success).
7562 * Note: we release the VM caller, otherwise it will deadlock.
7563 */
7564 ptrVM.release();
7565 alock.release();
7566 autoCaller.release();
7567
7568 HRESULT hrc2 = i_powerDown();
7569 AssertComRC(hrc2);
7570
7571 autoCaller.add();
7572 alock.acquire();
7573 }
7574 else if (fPaused)
7575 aLeftPaused = true;
7576 }
7577 else
7578 {
7579 if (fPaused)
7580 {
7581 alock.release();
7582 ptrVM.vtable()->pfnVMR3Resume(ptrVM.rawUVM(), VMRESUMEREASON_STATE_RESTORED);
7583 alock.acquire();
7584 }
7585 hrc = setErrorBoth(E_FAIL, vrc, tr("Failed to save the machine state to '%s' (%Rrc)"),
7586 aStateFilePath.c_str(), vrc);
7587 }
7588 }
7589 }
7590
7591 LogFlowFuncLeave();
7592 return S_OK;
7593}
7594
7595/**
7596 * Internal entry point for cancelling a VM save state.
7597 *
7598 * @note Locks this object for writing.
7599 */
7600HRESULT Console::i_cancelSaveState()
7601{
7602 LogFlowThisFuncEnter();
7603
7604 AutoCaller autoCaller(this);
7605 if (FAILED(autoCaller.hrc())) return autoCaller.hrc();
7606
7607 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
7608
7609 /* Get the VM handle. */
7610 SafeVMPtr ptrVM(this);
7611 HRESULT hrc = ptrVM.hrc();
7612 if (SUCCEEDED(hrc))
7613 ptrVM.vtable()->pfnSSMR3Cancel(ptrVM.rawUVM());
7614
7615 LogFlowFuncLeave();
7616 return hrc;
7617}
7618
7619#ifdef VBOX_WITH_AUDIO_RECORDING
7620/**
7621 * Sends audio (frame) data to the recording routines.
7622 *
7623 * @returns HRESULT
7624 * @param pvData Audio data to send.
7625 * @param cbData Size (in bytes) of audio data to send.
7626 * @param uTimestampMs Timestamp (in ms) of audio data.
7627 */
7628HRESULT Console::i_recordingSendAudio(const void *pvData, size_t cbData, uint64_t uTimestampMs)
7629{
7630 if ( mRecording.mCtx.IsStarted()
7631 && mRecording.mCtx.IsFeatureEnabled(RecordingFeature_Audio))
7632 {
7633 int vrc = mRecording.mCtx.SendAudioFrame(pvData, cbData, uTimestampMs);
7634 if (RT_FAILURE(vrc))
7635 return E_FAIL;
7636 }
7637
7638 return S_OK;
7639}
7640#endif /* VBOX_WITH_AUDIO_RECORDING */
7641
7642#ifdef VBOX_WITH_RECORDING
7643
7644int Console::i_recordingGetSettings(settings::Recording &Settings)
7645{
7646 Assert(mMachine.isNotNull());
7647
7648 Settings.applyDefaults();
7649
7650 ComPtr<IRecordingSettings> pRecordSettings;
7651 HRESULT hrc = mMachine->COMGETTER(RecordingSettings)(pRecordSettings.asOutParam());
7652 AssertComRCReturn(hrc, VERR_INVALID_PARAMETER);
7653
7654 BOOL fTemp;
7655 hrc = pRecordSettings->COMGETTER(Enabled)(&fTemp);
7656 AssertComRCReturn(hrc, VERR_INVALID_PARAMETER);
7657 Settings.common.fEnabled = RT_BOOL(fTemp);
7658
7659 SafeIfaceArray<IRecordingScreenSettings> paRecScreens;
7660 hrc = pRecordSettings->COMGETTER(Screens)(ComSafeArrayAsOutParam(paRecScreens));
7661 AssertComRCReturn(hrc, VERR_INVALID_PARAMETER);
7662
7663 for (unsigned long i = 0; i < (unsigned long)paRecScreens.size(); ++i)
7664 {
7665 settings::RecordingScreen recScreenSettings;
7666 ComPtr<IRecordingScreenSettings> pRecScreenSettings = paRecScreens[i];
7667
7668 hrc = pRecScreenSettings->COMGETTER(Enabled)(&fTemp);
7669 AssertComRCReturn(hrc, VERR_INVALID_PARAMETER);
7670 recScreenSettings.fEnabled = RT_BOOL(fTemp);
7671 com::SafeArray<RecordingFeature_T> vecFeatures;
7672 hrc = pRecScreenSettings->COMGETTER(Features)(ComSafeArrayAsOutParam(vecFeatures));
7673 AssertComRCReturn(hrc, VERR_INVALID_PARAMETER);
7674 /* Make sure to clear map first, as we want to (re-)set enabled features. */
7675 recScreenSettings.featureMap.clear();
7676 for (size_t f = 0; f < vecFeatures.size(); ++f)
7677 {
7678 if (vecFeatures[f] == RecordingFeature_Audio)
7679 recScreenSettings.featureMap[RecordingFeature_Audio] = true;
7680 else if (vecFeatures[f] == RecordingFeature_Video)
7681 recScreenSettings.featureMap[RecordingFeature_Video] = true;
7682 }
7683 hrc = pRecScreenSettings->COMGETTER(MaxTime)((ULONG *)&recScreenSettings.ulMaxTimeS);
7684 AssertComRCReturn(hrc, VERR_INVALID_PARAMETER);
7685 hrc = pRecScreenSettings->COMGETTER(MaxFileSize)((ULONG *)&recScreenSettings.File.ulMaxSizeMB);
7686 AssertComRCReturn(hrc, VERR_INVALID_PARAMETER);
7687 Bstr bstrTemp;
7688 hrc = pRecScreenSettings->COMGETTER(Filename)(bstrTemp.asOutParam());
7689 AssertComRCReturn(hrc, VERR_INVALID_PARAMETER);
7690 recScreenSettings.File.strName = bstrTemp;
7691 hrc = pRecScreenSettings->COMGETTER(Options)(bstrTemp.asOutParam());
7692 AssertComRCReturn(hrc, VERR_INVALID_PARAMETER);
7693 recScreenSettings.strOptions = bstrTemp;
7694 hrc = pRecScreenSettings->COMGETTER(AudioCodec)(&recScreenSettings.Audio.enmCodec);
7695 AssertComRCReturn(hrc, VERR_INVALID_PARAMETER);
7696 hrc = pRecScreenSettings->COMGETTER(AudioDeadline)(&recScreenSettings.Audio.enmDeadline);
7697 AssertComRCReturn(hrc, VERR_INVALID_PARAMETER);
7698 hrc = pRecScreenSettings->COMGETTER(AudioRateControlMode)(&recScreenSettings.Audio.enmRateCtlMode);
7699 AssertComRCReturn(hrc, VERR_INVALID_PARAMETER);
7700 hrc = pRecScreenSettings->COMGETTER(AudioHz)((ULONG *)&recScreenSettings.Audio.uHz);
7701 AssertComRCReturn(hrc, VERR_INVALID_PARAMETER);
7702 hrc = pRecScreenSettings->COMGETTER(AudioBits)((ULONG *)&recScreenSettings.Audio.cBits);
7703 AssertComRCReturn(hrc, VERR_INVALID_PARAMETER);
7704 hrc = pRecScreenSettings->COMGETTER(AudioChannels)((ULONG *)&recScreenSettings.Audio.cChannels);
7705 AssertComRCReturn(hrc, VERR_INVALID_PARAMETER);
7706 hrc = pRecScreenSettings->COMGETTER(VideoCodec)(&recScreenSettings.Video.enmCodec);
7707 AssertComRCReturn(hrc, VERR_INVALID_PARAMETER);
7708 hrc = pRecScreenSettings->COMGETTER(VideoWidth)((ULONG *)&recScreenSettings.Video.ulWidth);
7709 AssertComRCReturn(hrc, VERR_INVALID_PARAMETER);
7710 hrc = pRecScreenSettings->COMGETTER(VideoHeight)((ULONG *)&recScreenSettings.Video.ulHeight);
7711 AssertComRCReturn(hrc, VERR_INVALID_PARAMETER);
7712 hrc = pRecScreenSettings->COMGETTER(VideoDeadline)(&recScreenSettings.Video.enmDeadline);
7713 AssertComRCReturn(hrc, VERR_INVALID_PARAMETER);
7714 hrc = pRecScreenSettings->COMGETTER(VideoRateControlMode)(&recScreenSettings.Video.enmRateCtlMode);
7715 AssertComRCReturn(hrc, VERR_INVALID_PARAMETER);
7716 hrc = pRecScreenSettings->COMGETTER(VideoScalingMode)(&recScreenSettings.Video.enmScalingMode);
7717 AssertComRCReturn(hrc, VERR_INVALID_PARAMETER);
7718 hrc = pRecScreenSettings->COMGETTER(VideoRate)((ULONG *)&recScreenSettings.Video.ulRate);
7719 AssertComRCReturn(hrc, VERR_INVALID_PARAMETER);
7720 hrc = pRecScreenSettings->COMGETTER(VideoFPS)((ULONG *)&recScreenSettings.Video.ulFPS);
7721 AssertComRCReturn(hrc, VERR_INVALID_PARAMETER);
7722
7723 Settings.mapScreens[i] = recScreenSettings;
7724 }
7725
7726 Assert(Settings.mapScreens.size() == paRecScreens.size());
7727
7728 return VINF_SUCCESS;
7729}
7730
7731/**
7732 * Creates the recording context.
7733 *
7734 * @returns VBox status code.
7735 */
7736int Console::i_recordingCreate(ComPtr<IProgress> &pProgress)
7737{
7738 settings::Recording Settings;
7739 int vrc = i_recordingGetSettings(Settings);
7740 if (RT_SUCCESS(vrc))
7741 vrc = mRecording.mCtx.Create(this, Settings, pProgress);
7742
7743 if (RT_FAILURE(vrc))
7744 setErrorBoth(VBOX_E_RECORDING_ERROR, vrc, tr("Recording initialization failed (%Rrc) -- please consult log file for details"), vrc);
7745
7746 LogFlowFuncLeaveRC(vrc);
7747 return vrc;
7748}
7749
7750/**
7751 * Destroys the recording context.
7752 */
7753void Console::i_recordingDestroy(void)
7754{
7755 mRecording.mCtx.Destroy();
7756}
7757
7758/**
7759 * Starts recording. Does nothing if recording is already started.
7760 *
7761 * @returns VBox status code.
7762 */
7763int Console::i_recordingStart(util::AutoWriteLock *pAutoLock /* = NULL */)
7764{
7765 RT_NOREF(pAutoLock);
7766
7767 if (mRecording.mCtx.IsStarted())
7768 return VINF_SUCCESS;
7769
7770 int vrc = mRecording.mCtx.Start();
7771 if (RT_SUCCESS(vrc))
7772 vrc = mDisplay->i_recordingStart();
7773
7774 if (RT_FAILURE(vrc))
7775 mRecording.mCtx.SetError(vrc, Utf8StrFmt(tr("Recording start failed (%Rrc)"), vrc).c_str());
7776
7777 LogFlowFuncLeaveRC(vrc);
7778 return vrc;
7779}
7780
7781/**
7782 * Stops recording. Does nothing if recording is not in started state.
7783 *
7784 * Note: This does *not* disable recording for a VM, in other words,
7785 * it does not change the VM's recording (enabled) setting.
7786 */
7787int Console::i_recordingStop(util::AutoWriteLock *)
7788{
7789 if (!mRecording.mCtx.IsStarted())
7790 return VINF_SUCCESS;
7791
7792 int vrc = mRecording.mCtx.Stop();
7793 if (RT_SUCCESS(vrc))
7794 vrc = mDisplay->i_recordingStop();
7795
7796 if (RT_FAILURE(vrc))
7797 setErrorBoth(VBOX_E_RECORDING_ERROR, vrc, tr("Recording stop failed (%Rrc)"), vrc);
7798
7799 LogFlowFuncLeaveRC(vrc);
7800 return vrc;
7801}
7802
7803/**
7804 * Sends a cursor shape change to the recording context.
7805 *
7806 * @returns VBox status code.
7807 * @param fVisible Whether the mouse cursor actually is visible or not.
7808 * @param fAlpha Whether the pixel data contains alpha channel information or not.
7809 * @param xHot X hot position (in pixel) of the new cursor.
7810 * @param yHot Y hot position (in pixel) of the new cursor.
7811 * @param uWidth Width (in pixel) of the new cursor.
7812 * @param uHeight Height (in pixel) of the new cursor.
7813 * @param pu8Shape Pixel data of the new cursor.
7814 * @param cbShape Size of \a pu8Shape (in bytes).
7815 */
7816int Console::i_recordingCursorShapeChange(bool fVisible, bool fAlpha, uint32_t xHot, uint32_t yHot, uint32_t uWidth, uint32_t uHeight, const uint8_t *pu8Shape, uint32_t cbShape)
7817{
7818 if (!mRecording.mCtx.IsStarted())
7819 return VINF_SUCCESS;
7820
7821 return mRecording.mCtx.SendCursorShapeChange(fVisible, fAlpha, xHot, yHot, uWidth, uHeight, pu8Shape, cbShape,
7822 mRecording.mCtx.GetCurrentPTS());
7823}
7824#endif /* VBOX_WITH_RECORDING */
7825
7826/**
7827 * Gets called by Session::UpdateMachineState()
7828 * (IInternalSessionControl::updateMachineState()).
7829 *
7830 * Must be called only in certain cases (see the implementation).
7831 *
7832 * @note Locks this object for writing.
7833 */
7834HRESULT Console::i_updateMachineState(MachineState_T aMachineState)
7835{
7836 AutoCaller autoCaller(this);
7837 AssertComRCReturnRC(autoCaller.hrc());
7838
7839 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
7840
7841 AssertReturn( mMachineState == MachineState_Saving
7842 || mMachineState == MachineState_OnlineSnapshotting
7843 || mMachineState == MachineState_LiveSnapshotting
7844 || mMachineState == MachineState_DeletingSnapshotOnline
7845 || mMachineState == MachineState_DeletingSnapshotPaused
7846 || aMachineState == MachineState_Saving
7847 || aMachineState == MachineState_OnlineSnapshotting
7848 || aMachineState == MachineState_LiveSnapshotting
7849 || aMachineState == MachineState_DeletingSnapshotOnline
7850 || aMachineState == MachineState_DeletingSnapshotPaused
7851 , E_FAIL);
7852
7853 return i_setMachineStateLocally(aMachineState);
7854}
7855
7856/**
7857 * Gets called by Session::COMGETTER(NominalState)()
7858 * (IInternalSessionControl::getNominalState()).
7859 *
7860 * @note Locks this object for reading.
7861 */
7862HRESULT Console::i_getNominalState(MachineState_T &aNominalState)
7863{
7864 LogFlowThisFuncEnter();
7865
7866 AutoCaller autoCaller(this);
7867 AssertComRCReturnRC(autoCaller.hrc());
7868
7869 /* Get the VM handle. */
7870 SafeVMPtr ptrVM(this);
7871 if (!ptrVM.isOk())
7872 return ptrVM.hrc();
7873
7874 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
7875
7876 MachineState_T enmMachineState = MachineState_Null;
7877 VMSTATE enmVMState = ptrVM.vtable()->pfnVMR3GetStateU(ptrVM.rawUVM());
7878 switch (enmVMState)
7879 {
7880 case VMSTATE_CREATING:
7881 case VMSTATE_CREATED:
7882 case VMSTATE_POWERING_ON:
7883 enmMachineState = MachineState_Starting;
7884 break;
7885 case VMSTATE_LOADING:
7886 enmMachineState = MachineState_Restoring;
7887 break;
7888 case VMSTATE_RESUMING:
7889 case VMSTATE_SUSPENDING:
7890 case VMSTATE_SUSPENDING_LS:
7891 case VMSTATE_SUSPENDING_EXT_LS:
7892 case VMSTATE_SUSPENDED:
7893 case VMSTATE_SUSPENDED_LS:
7894 case VMSTATE_SUSPENDED_EXT_LS:
7895 enmMachineState = MachineState_Paused;
7896 break;
7897 case VMSTATE_RUNNING:
7898 case VMSTATE_RUNNING_LS:
7899 case VMSTATE_RESETTING:
7900 case VMSTATE_RESETTING_LS:
7901 case VMSTATE_SOFT_RESETTING:
7902 case VMSTATE_SOFT_RESETTING_LS:
7903 case VMSTATE_DEBUGGING:
7904 case VMSTATE_DEBUGGING_LS:
7905 enmMachineState = MachineState_Running;
7906 break;
7907 case VMSTATE_SAVING:
7908 enmMachineState = MachineState_Saving;
7909 break;
7910 case VMSTATE_POWERING_OFF:
7911 case VMSTATE_POWERING_OFF_LS:
7912 case VMSTATE_DESTROYING:
7913 enmMachineState = MachineState_Stopping;
7914 break;
7915 case VMSTATE_OFF:
7916 case VMSTATE_OFF_LS:
7917 case VMSTATE_FATAL_ERROR:
7918 case VMSTATE_FATAL_ERROR_LS:
7919 case VMSTATE_LOAD_FAILURE:
7920 case VMSTATE_TERMINATED:
7921 enmMachineState = MachineState_PoweredOff;
7922 break;
7923 case VMSTATE_GURU_MEDITATION:
7924 case VMSTATE_GURU_MEDITATION_LS:
7925 enmMachineState = MachineState_Stuck;
7926 break;
7927 default:
7928 AssertMsgFailed(("%s\n", ptrVM.vtable()->pfnVMR3GetStateName(enmVMState)));
7929 enmMachineState = MachineState_PoweredOff;
7930 }
7931 aNominalState = enmMachineState;
7932
7933 LogFlowFuncLeave();
7934 return S_OK;
7935}
7936
7937void Console::i_onMousePointerShapeChange(bool fVisible, bool fAlpha,
7938 uint32_t xHot, uint32_t yHot,
7939 uint32_t width, uint32_t height,
7940 const uint8_t *pu8Shape,
7941 uint32_t cbShape)
7942{
7943#if 0
7944 LogFlowThisFuncEnter();
7945 LogFlowThisFunc(("fVisible=%d, fAlpha=%d, xHot = %d, yHot = %d, width=%d, height=%d, shape=%p\n",
7946 fVisible, fAlpha, xHot, yHot, width, height, pShape));
7947#endif
7948
7949 AutoCaller autoCaller(this);
7950 AssertComRCReturnVoid(autoCaller.hrc());
7951
7952 if (!mMouse.isNull())
7953 mMouse->i_updatePointerShape(fVisible, fAlpha, xHot, yHot, width, height, pu8Shape, cbShape);
7954
7955 com::SafeArray<BYTE> shape(cbShape);
7956 if (pu8Shape)
7957 memcpy(shape.raw(), pu8Shape, cbShape);
7958 ::FireMousePointerShapeChangedEvent(mEventSource, fVisible, fAlpha, xHot, yHot, width, height, ComSafeArrayAsInParam(shape));
7959
7960#ifdef VBOX_WITH_RECORDING
7961 i_recordingCursorShapeChange(fVisible, fAlpha, xHot, yHot, width, height, pu8Shape, cbShape);
7962#endif
7963
7964#if 0
7965 LogFlowThisFuncLeave();
7966#endif
7967}
7968
7969void Console::i_onMouseCapabilityChange(BOOL supportsAbsolute, BOOL supportsRelative,
7970 BOOL supportsTouchScreen, BOOL supportsTouchPad, BOOL needsHostCursor)
7971{
7972 LogFlowThisFunc(("supportsAbsolute=%d supportsRelative=%d supportsTouchScreen=%d supportsTouchPad=%d needsHostCursor=%d\n",
7973 supportsAbsolute, supportsRelative, supportsTouchScreen, supportsTouchPad, needsHostCursor));
7974
7975 AutoCaller autoCaller(this);
7976 AssertComRCReturnVoid(autoCaller.hrc());
7977
7978 ::FireMouseCapabilityChangedEvent(mEventSource, supportsAbsolute, supportsRelative, supportsTouchScreen, supportsTouchPad, needsHostCursor);
7979}
7980
7981void Console::i_onStateChange(MachineState_T machineState)
7982{
7983 AutoCaller autoCaller(this);
7984 AssertComRCReturnVoid(autoCaller.hrc());
7985 ::FireStateChangedEvent(mEventSource, machineState);
7986}
7987
7988void Console::i_onAdditionsStateChange()
7989{
7990 AutoCaller autoCaller(this);
7991 AssertComRCReturnVoid(autoCaller.hrc());
7992
7993 ::FireAdditionsStateChangedEvent(mEventSource);
7994}
7995
7996/**
7997 * @remarks This notification only is for reporting an incompatible
7998 * Guest Additions interface, *not* the Guest Additions version!
7999 *
8000 * The user will be notified inside the guest if new Guest
8001 * Additions are available (via VBoxTray/VBoxClient).
8002 */
8003void Console::i_onAdditionsOutdated()
8004{
8005 AutoCaller autoCaller(this);
8006 AssertComRCReturnVoid(autoCaller.hrc());
8007
8008 /** @todo implement this */
8009}
8010
8011void Console::i_onKeyboardLedsChange(bool fNumLock, bool fCapsLock, bool fScrollLock)
8012{
8013 AutoCaller autoCaller(this);
8014 AssertComRCReturnVoid(autoCaller.hrc());
8015
8016 ::FireKeyboardLedsChangedEvent(mEventSource, fNumLock, fCapsLock, fScrollLock);
8017}
8018
8019void Console::i_onUSBDeviceStateChange(IUSBDevice *aDevice, bool aAttached,
8020 IVirtualBoxErrorInfo *aError)
8021{
8022 AutoCaller autoCaller(this);
8023 AssertComRCReturnVoid(autoCaller.hrc());
8024
8025 ::FireUSBDeviceStateChangedEvent(mEventSource, aDevice, aAttached, aError);
8026}
8027
8028void Console::i_onRuntimeError(BOOL aFatal, IN_BSTR aErrorID, IN_BSTR aMessage)
8029{
8030 AutoCaller autoCaller(this);
8031 AssertComRCReturnVoid(autoCaller.hrc());
8032
8033 ::FireRuntimeErrorEvent(mEventSource, aFatal, aErrorID, aMessage);
8034}
8035
8036HRESULT Console::i_onShowWindow(BOOL aCheck, BOOL *aCanShow, LONG64 *aWinId)
8037{
8038 AssertReturn(aCanShow, E_POINTER);
8039 AssertReturn(aWinId, E_POINTER);
8040
8041 *aCanShow = FALSE;
8042 *aWinId = 0;
8043
8044 AutoCaller autoCaller(this);
8045 AssertComRCReturnRC(autoCaller.hrc());
8046
8047 ComPtr<IEvent> ptrEvent;
8048 if (aCheck)
8049 {
8050 *aCanShow = TRUE;
8051 HRESULT hrc = ::CreateCanShowWindowEvent(ptrEvent.asOutParam(), mEventSource);
8052 if (SUCCEEDED(hrc))
8053 {
8054 VBoxEventDesc EvtDesc(ptrEvent, mEventSource);
8055 BOOL fDelivered = EvtDesc.fire(5000); /* Wait up to 5 secs for delivery */
8056 //Assert(fDelivered);
8057 if (fDelivered)
8058 {
8059 // bit clumsy
8060 ComPtr<ICanShowWindowEvent> ptrCanShowEvent = ptrEvent;
8061 if (ptrCanShowEvent)
8062 {
8063 BOOL fVetoed = FALSE;
8064 BOOL fApproved = FALSE;
8065 ptrCanShowEvent->IsVetoed(&fVetoed);
8066 ptrCanShowEvent->IsApproved(&fApproved);
8067 *aCanShow = fApproved || !fVetoed;
8068 }
8069 else
8070 AssertFailed();
8071 }
8072 }
8073 }
8074 else
8075 {
8076 HRESULT hrc = ::CreateShowWindowEvent(ptrEvent.asOutParam(), mEventSource, 0);
8077 if (SUCCEEDED(hrc))
8078 {
8079 VBoxEventDesc EvtDesc(ptrEvent, mEventSource);
8080 BOOL fDelivered = EvtDesc.fire(5000); /* Wait up to 5 secs for delivery */
8081 //Assert(fDelivered);
8082 if (fDelivered)
8083 {
8084 ComPtr<IShowWindowEvent> ptrShowEvent = ptrEvent;
8085 if (ptrShowEvent)
8086 {
8087 LONG64 idWindow = 0;
8088 ptrShowEvent->COMGETTER(WinId)(&idWindow);
8089 if (idWindow != 0 && *aWinId == 0)
8090 *aWinId = idWindow;
8091 }
8092 else
8093 AssertFailed();
8094 }
8095 }
8096 }
8097
8098 return S_OK;
8099}
8100
8101// private methods
8102////////////////////////////////////////////////////////////////////////////////
8103
8104/**
8105 * Loads the VMM if needed.
8106 *
8107 * @returns COM status.
8108 * @param pszVMMMod The VMM module to load.
8109 * @remarks Caller must write lock the console object.
8110 */
8111HRESULT Console::i_loadVMM(const char *pszVMMMod) RT_NOEXCEPT
8112{
8113 if ( mhModVMM == NIL_RTLDRMOD
8114 || mpVMM == NULL)
8115 {
8116 Assert(!mpVMM);
8117
8118 HRESULT hrc;
8119 RTERRINFOSTATIC ErrInfo;
8120 RTLDRMOD hModVMM = NIL_RTLDRMOD;
8121 int vrc = SUPR3HardenedLdrLoadAppPriv(pszVMMMod, &hModVMM, RTLDRLOAD_FLAGS_LOCAL, RTErrInfoInitStatic(&ErrInfo));
8122 if (RT_SUCCESS(vrc))
8123 {
8124 PFNVMMGETVTABLE pfnGetVTable = NULL;
8125 vrc = RTLdrGetSymbol(hModVMM, VMMR3VTABLE_GETTER_NAME, (void **)&pfnGetVTable);
8126 if (pfnGetVTable)
8127 {
8128 PCVMMR3VTABLE pVMM = pfnGetVTable();
8129 if (pVMM)
8130 {
8131 if (VMMR3VTABLE_IS_COMPATIBLE(pVMM->uMagicVersion))
8132 {
8133 if (pVMM->uMagicVersion == pVMM->uMagicVersionEnd)
8134 {
8135 mhModVMM = hModVMM;
8136 mpVMM = pVMM;
8137 LogFunc(("mhLdrVMM=%p phVMM=%p uMagicVersion=%#RX64\n", hModVMM, pVMM, pVMM->uMagicVersion));
8138 return S_OK;
8139 }
8140
8141 hrc = setErrorVrc(vrc, "Bogus VMM vtable: uMagicVersion=%#RX64 uMagicVersionEnd=%#RX64",
8142 pVMM->uMagicVersion, pVMM->uMagicVersionEnd);
8143 }
8144 else
8145 hrc = setErrorVrc(vrc, "Incompatible of bogus VMM version magic: %#RX64", pVMM->uMagicVersion);
8146 }
8147 else
8148 hrc = setErrorVrc(vrc, "pfnGetVTable return NULL!");
8149 }
8150 else
8151 hrc = setErrorVrc(vrc, "Failed to locate symbol '%s' in VBoxVMM: %Rrc", VMMR3VTABLE_GETTER_NAME, vrc);
8152 RTLdrClose(hModVMM);
8153 }
8154 else
8155 hrc = setErrorVrc(vrc, "Failed to load VBoxVMM: %#RTeic", &ErrInfo.Core);
8156 return hrc;
8157 }
8158
8159 return S_OK;
8160}
8161
8162/**
8163 * Increases the usage counter of the mpUVM pointer.
8164 *
8165 * Guarantees that VMR3Destroy() will not be called on it at least until
8166 * releaseVMCaller() is called.
8167 *
8168 * If this method returns a failure, the caller is not allowed to use mpUVM and
8169 * may return the failed result code to the upper level. This method sets the
8170 * extended error info on failure if \a aQuiet is false.
8171 *
8172 * Setting \a aQuiet to true is useful for methods that don't want to return
8173 * the failed result code to the caller when this method fails (e.g. need to
8174 * silently check for the mpUVM availability).
8175 *
8176 * When mpUVM is NULL but \a aAllowNullVM is true, a corresponding error will be
8177 * returned instead of asserting. Having it false is intended as a sanity check
8178 * for methods that have checked mMachineState and expect mpUVM *NOT* to be
8179 * NULL.
8180 *
8181 * @param aQuiet true to suppress setting error info
8182 * @param aAllowNullVM true to accept mpUVM being NULL and return a failure
8183 * (otherwise this method will assert if mpUVM is NULL)
8184 *
8185 * @note Locks this object for writing.
8186 */
8187HRESULT Console::i_addVMCaller(bool aQuiet /* = false */,
8188 bool aAllowNullVM /* = false */)
8189{
8190 RT_NOREF(aAllowNullVM);
8191 AutoCaller autoCaller(this);
8192 /** @todo Fix race during console/VM reference destruction, refer @bugref{6318}
8193 * comment 25. */
8194 if (FAILED(autoCaller.hrc()))
8195 return autoCaller.hrc();
8196
8197 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
8198
8199 if (mVMDestroying)
8200 {
8201 /* powerDown() is waiting for all callers to finish */
8202 return aQuiet ? E_ACCESSDENIED : setError(E_ACCESSDENIED, tr("The virtual machine is being powered down"));
8203 }
8204
8205 if (mpUVM == NULL)
8206 {
8207 Assert(aAllowNullVM == true);
8208
8209 /* The machine is not powered up */
8210 return aQuiet ? E_ACCESSDENIED : setError(E_ACCESSDENIED, tr("The virtual machine is not powered up"));
8211 }
8212
8213 ++mVMCallers;
8214
8215 return S_OK;
8216}
8217
8218/**
8219 * Decreases the usage counter of the mpUVM pointer.
8220 *
8221 * Must always complete the addVMCaller() call after the mpUVM pointer is no
8222 * more necessary.
8223 *
8224 * @note Locks this object for writing.
8225 */
8226void Console::i_releaseVMCaller()
8227{
8228 AutoCaller autoCaller(this);
8229 AssertComRCReturnVoid(autoCaller.hrc());
8230
8231 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
8232
8233 AssertReturnVoid(mpUVM != NULL);
8234
8235 Assert(mVMCallers > 0);
8236 --mVMCallers;
8237
8238 if (mVMCallers == 0 && mVMDestroying)
8239 {
8240 /* inform powerDown() there are no more callers */
8241 RTSemEventSignal(mVMZeroCallersSem);
8242 }
8243}
8244
8245
8246/**
8247 * Helper for SafeVMPtrBase.
8248 */
8249HRESULT Console::i_safeVMPtrRetainer(PUVM *a_ppUVM, PCVMMR3VTABLE *a_ppVMM, bool a_Quiet) RT_NOEXCEPT
8250{
8251 *a_ppUVM = NULL;
8252 *a_ppVMM = NULL;
8253
8254 AutoCaller autoCaller(this);
8255 AssertComRCReturnRC(autoCaller.hrc());
8256 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
8257
8258 /*
8259 * Repeat the checks done by addVMCaller.
8260 */
8261 if (mVMDestroying) /* powerDown() is waiting for all callers to finish */
8262 return a_Quiet
8263 ? E_ACCESSDENIED
8264 : setError(E_ACCESSDENIED, tr("The virtual machine is being powered down"));
8265 PUVM const pUVM = mpUVM;
8266 if (!pUVM)
8267 return a_Quiet
8268 ? E_ACCESSDENIED
8269 : setError(E_ACCESSDENIED, tr("The virtual machine is powered off"));
8270 PCVMMR3VTABLE const pVMM = mpVMM;
8271 if (!pVMM)
8272 return a_Quiet
8273 ? E_ACCESSDENIED
8274 : setError(E_ACCESSDENIED, tr("No VMM loaded!"));
8275
8276 /*
8277 * Retain a reference to the user mode VM handle and get the global handle.
8278 */
8279 uint32_t cRefs = pVMM->pfnVMR3RetainUVM(pUVM);
8280 if (cRefs == UINT32_MAX)
8281 return a_Quiet
8282 ? E_ACCESSDENIED
8283 : setError(E_ACCESSDENIED, tr("The virtual machine is powered off"));
8284
8285 /* done */
8286 *a_ppUVM = pUVM;
8287 *a_ppVMM = pVMM;
8288 return S_OK;
8289}
8290
8291void Console::i_safeVMPtrReleaser(PUVM *a_ppUVM)
8292{
8293 PUVM const pUVM = *a_ppUVM;
8294 *a_ppUVM = NULL;
8295 if (pUVM)
8296 {
8297 PCVMMR3VTABLE const pVMM = mpVMM;
8298 if (pVMM)
8299 pVMM->pfnVMR3ReleaseUVM(pUVM);
8300 }
8301}
8302
8303#ifdef VBOX_WITH_FULL_VM_ENCRYPTION
8304
8305/*static*/ DECLCALLBACK(int)
8306Console::i_logEncryptedDirCtxOpen(PCRTLOGOUTPUTIF pIf, void *pvUser, const char *pszFilename, void **ppvDirCtx)
8307{
8308 RT_NOREF(pIf, pvUser, pszFilename, ppvDirCtx);
8309 *ppvDirCtx = (void *)(intptr_t)22;
8310 return VINF_SUCCESS;
8311}
8312
8313/*static*/ DECLCALLBACK(int)
8314Console::i_logEncryptedDirCtxClose(PCRTLOGOUTPUTIF pIf, void *pvUser, void *pvDirCtx)
8315{
8316 RT_NOREF(pIf, pvUser, pvDirCtx);
8317 Assert((intptr_t)pvDirCtx == 22);
8318 return VINF_SUCCESS;
8319}
8320
8321/*static*/ DECLCALLBACK(int)
8322Console::i_logEncryptedDelete(PCRTLOGOUTPUTIF pIf, void *pvUser, void *pvDirCtx, const char *pszFilename)
8323{
8324 RT_NOREF(pIf, pvDirCtx, pvUser);
8325 return RTFileDelete(pszFilename);
8326}
8327
8328
8329/*static*/ DECLCALLBACK(int)
8330Console::i_logEncryptedRename(PCRTLOGOUTPUTIF pIf, void *pvUser, void *pvDirCtx,
8331 const char *pszFilenameOld, const char *pszFilenameNew, uint32_t fFlags)
8332{
8333 RT_NOREF(pIf, pvDirCtx, pvUser);
8334 return RTFileRename(pszFilenameOld, pszFilenameNew, fFlags);
8335}
8336
8337/*static*/ DECLCALLBACK(int)
8338Console::i_logEncryptedOpen(PCRTLOGOUTPUTIF pIf, void *pvUser, void *pvDirCtx, const char *pszFilename, uint32_t fFlags)
8339{
8340 RT_NOREF(pIf, pvDirCtx);
8341 Console *pConsole = static_cast<Console *>(pvUser);
8342 RTVFSFILE hVfsFile = NIL_RTVFSFILE;
8343
8344 int vrc = RTVfsFileOpenNormal(pszFilename, fFlags, &hVfsFile);
8345 if (RT_SUCCESS(vrc))
8346 {
8347 PCVBOXCRYPTOIF pCryptoIf = NULL;
8348 vrc = pConsole->i_retainCryptoIf(&pCryptoIf);
8349 if (RT_SUCCESS(vrc))
8350 {
8351 SecretKey *pKey = NULL;
8352
8353 vrc = pConsole->m_pKeyStore->retainSecretKey(pConsole->m_strLogKeyId, &pKey);
8354 if (RT_SUCCESS(vrc))
8355 {
8356 const char *pszPassword = (const char *)pKey->getKeyBuffer();
8357
8358 vrc = pCryptoIf->pfnCryptoFileFromVfsFile(hVfsFile, pConsole->m_strLogKeyStore.c_str(), pszPassword,
8359 &pConsole->m_hVfsFileLog);
8360 pKey->release();
8361 }
8362
8363 /* On success we keep the reference to keep the cryptographic module loaded. */
8364 if (RT_FAILURE(vrc))
8365 pConsole->i_releaseCryptoIf(pCryptoIf);
8366 }
8367
8368 /* Always do this because the encrypted log has retained a reference to the underlying file. */
8369 RTVfsFileRelease(hVfsFile);
8370 if (RT_FAILURE(vrc))
8371 RTFileDelete(pszFilename);
8372 }
8373
8374 return vrc;
8375}
8376
8377
8378/*static*/ DECLCALLBACK(int)
8379Console::i_logEncryptedClose(PCRTLOGOUTPUTIF pIf, void *pvUser)
8380{
8381 RT_NOREF(pIf);
8382 Console *pConsole = static_cast<Console *>(pvUser);
8383
8384 RTVfsFileRelease(pConsole->m_hVfsFileLog);
8385 pConsole->m_hVfsFileLog = NIL_RTVFSFILE;
8386 return VINF_SUCCESS;
8387}
8388
8389
8390/*static*/ DECLCALLBACK(int)
8391Console::i_logEncryptedQuerySize(PCRTLOGOUTPUTIF pIf, void *pvUser, uint64_t *pcbSize)
8392{
8393 RT_NOREF(pIf);
8394 Console *pConsole = static_cast<Console *>(pvUser);
8395
8396 return RTVfsFileQuerySize(pConsole->m_hVfsFileLog, pcbSize);
8397}
8398
8399
8400/*static*/ DECLCALLBACK(int)
8401Console::i_logEncryptedWrite(PCRTLOGOUTPUTIF pIf, void *pvUser, const void *pvBuf, size_t cbWrite, size_t *pcbWritten)
8402{
8403 RT_NOREF(pIf);
8404 Console *pConsole = static_cast<Console *>(pvUser);
8405
8406 return RTVfsFileWrite(pConsole->m_hVfsFileLog, pvBuf, cbWrite, pcbWritten);
8407}
8408
8409
8410/*static*/ DECLCALLBACK(int)
8411Console::i_logEncryptedFlush(PCRTLOGOUTPUTIF pIf, void *pvUser)
8412{
8413 RT_NOREF(pIf);
8414 Console *pConsole = static_cast<Console *>(pvUser);
8415
8416 return RTVfsFileFlush(pConsole->m_hVfsFileLog);
8417}
8418
8419
8420/*static*/ RTLOGOUTPUTIF const Console::s_ConsoleEncryptedLogOutputIf =
8421{
8422 Console::i_logEncryptedDirCtxOpen,
8423 Console::i_logEncryptedDirCtxClose,
8424 Console::i_logEncryptedDelete,
8425 Console::i_logEncryptedRename,
8426 Console::i_logEncryptedOpen,
8427 Console::i_logEncryptedClose,
8428 Console::i_logEncryptedQuerySize,
8429 Console::i_logEncryptedWrite,
8430 Console::i_logEncryptedFlush
8431};
8432
8433#endif /* VBOX_WITH_FULL_VM_ENCRYPTION */
8434
8435/**
8436 * Initialize the release logging facility. In case something
8437 * goes wrong, there will be no release logging. Maybe in the future
8438 * we can add some logic to use different file names in this case.
8439 * Note that the logic must be in sync with Machine::DeleteSettings().
8440 */
8441HRESULT Console::i_consoleInitReleaseLog(const ComPtr<IMachine> aMachine)
8442{
8443 Bstr bstrLogFolder;
8444 HRESULT hrc = aMachine->COMGETTER(LogFolder)(bstrLogFolder.asOutParam());
8445 if (FAILED(hrc))
8446 return hrc;
8447 Utf8Str strLogDir = bstrLogFolder;
8448
8449 /* make sure the Logs folder exists */
8450 Assert(strLogDir.length());
8451 if (!RTDirExists(strLogDir.c_str()))
8452 RTDirCreateFullPath(strLogDir.c_str(), 0700);
8453
8454 Utf8StrFmt logFile("%s%cVBox.log", strLogDir.c_str(), RTPATH_DELIMITER);
8455 Utf8StrFmt pngFile("%s%cVBox.png", strLogDir.c_str(), RTPATH_DELIMITER);
8456
8457 /*
8458 * Age the old log files.
8459 * Rename .(n-1) to .(n), .(n-2) to .(n-1), ..., and the last log file to .1
8460 * Overwrite target files in case they exist.
8461 */
8462 ComPtr<IVirtualBox> pVirtualBox;
8463 aMachine->COMGETTER(Parent)(pVirtualBox.asOutParam());
8464 ComPtr<ISystemProperties> pSystemProperties;
8465 pVirtualBox->COMGETTER(SystemProperties)(pSystemProperties.asOutParam());
8466 ULONG cHistoryFiles = 3;
8467 pSystemProperties->COMGETTER(LogHistoryCount)(&cHistoryFiles);
8468 if (cHistoryFiles)
8469 {
8470 for (int i = cHistoryFiles - 1; i >= 0; i--)
8471 {
8472 Utf8Str *files[] = { &logFile, &pngFile };
8473 Utf8Str oldName, newName;
8474
8475 for (unsigned int j = 0; j < RT_ELEMENTS(files); ++j)
8476 {
8477 if (i > 0)
8478 oldName.printf("%s.%d", files[j]->c_str(), i);
8479 else
8480 oldName = *files[j];
8481 newName.printf("%s.%d", files[j]->c_str(), i + 1);
8482
8483 /* If the old file doesn't exist, delete the new file (if it
8484 * exists) to provide correct rotation even if the sequence is
8485 * broken */
8486 if (RTFileRename(oldName.c_str(), newName.c_str(), RTFILEMOVE_FLAGS_REPLACE) == VERR_FILE_NOT_FOUND)
8487 RTFileDelete(newName.c_str());
8488 }
8489 }
8490 }
8491
8492 Bstr bstrLogKeyId;
8493 Bstr bstrLogKeyStore;
8494 PCRTLOGOUTPUTIF pLogOutputIf = NULL;
8495 void *pvLogOutputUser = NULL;
8496 int vrc = VINF_SUCCESS;
8497#ifdef VBOX_WITH_FULL_VM_ENCRYPTION
8498 hrc = aMachine->COMGETTER(LogKeyId)(bstrLogKeyId.asOutParam());
8499 if (SUCCEEDED(hrc))
8500 {
8501 hrc = aMachine->COMGETTER(LogKeyStore)(bstrLogKeyStore.asOutParam());
8502 if ( SUCCEEDED(hrc)
8503 && bstrLogKeyId.isNotEmpty()
8504 && bstrLogKeyStore.isNotEmpty())
8505 {
8506 m_strLogKeyId = Utf8Str(bstrLogKeyId);
8507 m_strLogKeyStore = Utf8Str(bstrLogKeyStore);
8508
8509 pLogOutputIf = &s_ConsoleEncryptedLogOutputIf;
8510 pvLogOutputUser = this;
8511 m_fEncryptedLog = true;
8512 }
8513 }
8514
8515 if (RT_FAILURE(vrc))
8516 hrc = setErrorBoth(E_FAIL, vrc, tr("Failed to set encryption for release log (%Rrc)"), vrc);
8517 else
8518#endif
8519 {
8520 RTERRINFOSTATIC ErrInfo;
8521 vrc = com::VBoxLogRelCreateEx("VM", logFile.c_str(),
8522 RTLOGFLAGS_PREFIX_TIME_PROG | RTLOGFLAGS_RESTRICT_GROUPS,
8523 "all all.restrict -default.restrict",
8524 "VBOX_RELEASE_LOG", RTLOGDEST_FILE,
8525 32768 /* cMaxEntriesPerGroup */,
8526 0 /* cHistory */, 0 /* uHistoryFileTime */,
8527 0 /* uHistoryFileSize */,
8528 pLogOutputIf, pvLogOutputUser,
8529 RTErrInfoInitStatic(&ErrInfo));
8530 if (RT_FAILURE(vrc))
8531 hrc = setErrorBoth(E_FAIL, vrc, tr("Failed to open release log (%s, %Rrc)"), ErrInfo.Core.pszMsg, vrc);
8532 }
8533
8534 /* If we've made any directory changes, flush the directory to increase
8535 the likelihood that the log file will be usable after a system panic.
8536
8537 Tip: Try 'export VBOX_RELEASE_LOG_FLAGS=flush' if the last bits of the log
8538 is missing. Just don't have too high hopes for this to help. */
8539 if (SUCCEEDED(hrc) || cHistoryFiles)
8540 RTDirFlush(strLogDir.c_str());
8541
8542 return hrc;
8543}
8544
8545/**
8546 * Common worker for PowerUp and PowerUpPaused.
8547 *
8548 * @returns COM status code.
8549 *
8550 * @param aProgress Where to return the progress object.
8551 * @param aPaused true if PowerUpPaused called.
8552 */
8553HRESULT Console::i_powerUp(IProgress **aProgress, bool aPaused)
8554{
8555 LogFlowThisFuncEnter();
8556
8557 CheckComArgOutPointerValid(aProgress);
8558
8559 AutoCaller autoCaller(this);
8560 HRESULT hrc = autoCaller.hrc();
8561 if (FAILED(hrc))
8562 return hrc;
8563
8564 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
8565 LogFlowThisFunc(("mMachineState=%d\n", mMachineState));
8566
8567 if (Global::IsOnlineOrTransient(mMachineState))
8568 return setError(VBOX_E_INVALID_VM_STATE, tr("The virtual machine is already running or busy (machine state: %s)"),
8569 Global::stringifyMachineState(mMachineState));
8570
8571
8572 /* Set up release logging as early as possible after the check if
8573 * there is already a running VM which we shouldn't disturb. */
8574 hrc = i_consoleInitReleaseLog(mMachine);
8575 if (FAILED(hrc))
8576 return hrc;
8577
8578#ifdef VBOX_OPENSSL_FIPS
8579 LogRel(("crypto: FIPS mode %s\n", FIPS_mode() ? "enabled" : "FAILED"));
8580#endif
8581
8582 /* test and clear the TeleporterEnabled property */
8583 BOOL fTeleporterEnabled;
8584 hrc = mMachine->COMGETTER(TeleporterEnabled)(&fTeleporterEnabled);
8585 if (FAILED(hrc))
8586 return hrc;
8587
8588#if 0 /** @todo we should save it afterwards, but that isn't necessarily a good idea. Find a better place for this (VBoxSVC). */
8589 if (fTeleporterEnabled)
8590 {
8591 hrc = mMachine->COMSETTER(TeleporterEnabled)(FALSE);
8592 if (FAILED(hrc))
8593 return hrc;
8594 }
8595#endif
8596
8597 PCVMMR3VTABLE const pVMM = mpVMM;
8598 AssertPtrReturn(pVMM, E_UNEXPECTED);
8599
8600 ComObjPtr<Progress> pPowerupProgress;
8601 bool fBeganPoweringUp = false;
8602
8603 LONG cOperations = 1;
8604 LONG ulTotalOperationsWeight = 1;
8605 VMPowerUpTask *task = NULL;
8606
8607 try
8608 {
8609 /* Create a progress object to track progress of this operation. Must
8610 * be done as early as possible (together with BeginPowerUp()) as this
8611 * is vital for communicating as much as possible early powerup
8612 * failure information to the API caller */
8613 pPowerupProgress.createObject();
8614 Bstr progressDesc;
8615 if (mMachineState == MachineState_Saved || mMachineState == MachineState_AbortedSaved)
8616 progressDesc = tr("Restoring virtual machine");
8617 else if (fTeleporterEnabled)
8618 progressDesc = tr("Teleporting virtual machine");
8619 else
8620 progressDesc = tr("Starting virtual machine");
8621
8622 /*
8623 * Saved VMs will have to prove that their saved states seem kosher.
8624 */
8625 Utf8Str strSavedStateFile;
8626 Bstr bstrStateKeyId;
8627 Bstr bstrStateKeyStore;
8628
8629 if (mMachineState == MachineState_Saved || mMachineState == MachineState_AbortedSaved)
8630 {
8631 Bstr bstrSavedStateFile;
8632 hrc = mMachine->COMGETTER(StateFilePath)(bstrSavedStateFile.asOutParam());
8633 if (FAILED(hrc))
8634 throw hrc;
8635 strSavedStateFile = bstrSavedStateFile;
8636
8637#ifdef VBOX_WITH_FULL_VM_ENCRYPTION
8638 hrc = mMachine->COMGETTER(StateKeyId)(bstrStateKeyId.asOutParam());
8639 if (FAILED(hrc))
8640 throw hrc;
8641 hrc = mMachine->COMGETTER(StateKeyStore)(bstrStateKeyStore.asOutParam());
8642 if (FAILED(hrc))
8643 throw hrc;
8644#endif
8645
8646 ComAssertRet(bstrSavedStateFile.isNotEmpty(), E_FAIL);
8647 SsmStream ssmStream(this, pVMM, m_pKeyStore, bstrStateKeyId, bstrStateKeyStore);
8648 int vrc = ssmStream.open(strSavedStateFile.c_str());
8649 if (RT_SUCCESS(vrc))
8650 {
8651 PCSSMSTRMOPS pStreamOps;
8652 void *pvStreamOpsUser;
8653
8654 vrc = ssmStream.querySsmStrmOps(&pStreamOps, &pvStreamOpsUser);
8655 if (RT_SUCCESS(vrc))
8656 vrc = pVMM->pfnSSMR3ValidateFile(NULL /*pszFilename*/, pStreamOps, pvStreamOpsUser,
8657 false /* fChecksumIt */);
8658 }
8659
8660 if (RT_FAILURE(vrc))
8661 {
8662 Utf8Str errMsg;
8663 switch (vrc)
8664 {
8665 case VERR_FILE_NOT_FOUND:
8666 errMsg.printf(tr("VM failed to start because the saved state file '%s' does not exist."),
8667 strSavedStateFile.c_str());
8668 break;
8669 default:
8670 errMsg.printf(tr("VM failed to start because the saved state file '%s' is invalid (%Rrc). "
8671 "Delete the saved state prior to starting the VM."), strSavedStateFile.c_str(), vrc);
8672 break;
8673 }
8674 throw setErrorBoth(VBOX_E_FILE_ERROR, vrc, errMsg.c_str());
8675 }
8676
8677 }
8678
8679 /* Read console data, including console shared folders, stored in the
8680 * saved state file (if not yet done).
8681 */
8682 hrc = i_loadDataFromSavedState();
8683 if (FAILED(hrc))
8684 throw hrc;
8685
8686 /* Check all types of shared folders and compose a single list */
8687 SharedFolderDataMap sharedFolders;
8688 {
8689 /* first, insert global folders */
8690 for (SharedFolderDataMap::const_iterator it = m_mapGlobalSharedFolders.begin();
8691 it != m_mapGlobalSharedFolders.end();
8692 ++it)
8693 {
8694 const SharedFolderData &d = it->second;
8695 sharedFolders[it->first] = d;
8696 }
8697
8698 /* second, insert machine folders */
8699 for (SharedFolderDataMap::const_iterator it = m_mapMachineSharedFolders.begin();
8700 it != m_mapMachineSharedFolders.end();
8701 ++it)
8702 {
8703 const SharedFolderData &d = it->second;
8704 sharedFolders[it->first] = d;
8705 }
8706
8707 /* third, insert console folders */
8708 for (SharedFolderMap::const_iterator it = m_mapSharedFolders.begin();
8709 it != m_mapSharedFolders.end();
8710 ++it)
8711 {
8712 ConsoleSharedFolder *pSF = it->second;
8713 AutoCaller sfCaller(pSF);
8714 AutoReadLock sfLock(pSF COMMA_LOCKVAL_SRC_POS);
8715 sharedFolders[it->first] = SharedFolderData(pSF->i_getHostPath(),
8716 pSF->i_isWritable(),
8717 pSF->i_isAutoMounted(),
8718 pSF->i_getAutoMountPoint());
8719 }
8720 }
8721
8722
8723 /* Setup task object and thread to carry out the operation
8724 * asynchronously */
8725 try { task = new VMPowerUpTask(this, pPowerupProgress); }
8726 catch (std::bad_alloc &) { throw hrc = E_OUTOFMEMORY; }
8727 if (!task->isOk())
8728 throw task->hrc();
8729
8730 task->mpfnConfigConstructor = i_configConstructor;
8731 task->mSharedFolders = sharedFolders;
8732 task->mStartPaused = aPaused;
8733 if (mMachineState == MachineState_Saved || mMachineState == MachineState_AbortedSaved)
8734 try { task->mSavedStateFile = strSavedStateFile; }
8735 catch (std::bad_alloc &) { throw hrc = E_OUTOFMEMORY; }
8736 task->mTeleporterEnabled = fTeleporterEnabled;
8737
8738 /* Reset differencing hard disks for which autoReset is true,
8739 * but only if the machine has no snapshots OR the current snapshot
8740 * is an OFFLINE snapshot; otherwise we would reset the current
8741 * differencing image of an ONLINE snapshot which contains the disk
8742 * state of the machine while it was previously running, but without
8743 * the corresponding machine state, which is equivalent to powering
8744 * off a running machine and not good idea
8745 */
8746 ComPtr<ISnapshot> pCurrentSnapshot;
8747 hrc = mMachine->COMGETTER(CurrentSnapshot)(pCurrentSnapshot.asOutParam());
8748 if (FAILED(hrc))
8749 throw hrc;
8750
8751 BOOL fCurrentSnapshotIsOnline = false;
8752 if (pCurrentSnapshot)
8753 {
8754 hrc = pCurrentSnapshot->COMGETTER(Online)(&fCurrentSnapshotIsOnline);
8755 if (FAILED(hrc))
8756 throw hrc;
8757 }
8758
8759 if (strSavedStateFile.isEmpty() && !fCurrentSnapshotIsOnline)
8760 {
8761 LogFlowThisFunc(("Looking for immutable images to reset\n"));
8762
8763 com::SafeIfaceArray<IMediumAttachment> atts;
8764 hrc = mMachine->COMGETTER(MediumAttachments)(ComSafeArrayAsOutParam(atts));
8765 if (FAILED(hrc))
8766 throw hrc;
8767
8768 for (size_t i = 0;
8769 i < atts.size();
8770 ++i)
8771 {
8772 DeviceType_T devType;
8773 hrc = atts[i]->COMGETTER(Type)(&devType);
8774 /** @todo later applies to floppies as well */
8775 if (devType == DeviceType_HardDisk)
8776 {
8777 ComPtr<IMedium> pMedium;
8778 hrc = atts[i]->COMGETTER(Medium)(pMedium.asOutParam());
8779 if (FAILED(hrc))
8780 throw hrc;
8781
8782 /* needs autoreset? */
8783 BOOL autoReset = FALSE;
8784 hrc = pMedium->COMGETTER(AutoReset)(&autoReset);
8785 if (FAILED(hrc))
8786 throw hrc;
8787
8788 if (autoReset)
8789 {
8790 ComPtr<IProgress> pResetProgress;
8791 hrc = pMedium->Reset(pResetProgress.asOutParam());
8792 if (FAILED(hrc))
8793 throw hrc;
8794
8795 /* save for later use on the powerup thread */
8796 task->hardDiskProgresses.push_back(pResetProgress);
8797 }
8798 }
8799 }
8800 }
8801 else
8802 LogFlowThisFunc(("Machine has a current snapshot which is online, skipping immutable images reset\n"));
8803
8804 /* setup task object and thread to carry out the operation
8805 * asynchronously */
8806
8807#ifdef VBOX_WITH_EXTPACK
8808 mptrExtPackManager->i_dumpAllToReleaseLog();
8809#endif
8810
8811#ifdef RT_OS_SOLARIS
8812 /* setup host core dumper for the VM */
8813 Bstr value;
8814 hrc = mMachine->GetExtraData(Bstr("VBoxInternal2/CoreDumpEnabled").raw(), value.asOutParam());
8815 if (SUCCEEDED(hrc) && value == "1")
8816 {
8817 Bstr coreDumpDir, coreDumpReplaceSys, coreDumpLive;
8818 mMachine->GetExtraData(Bstr("VBoxInternal2/CoreDumpDir").raw(), coreDumpDir.asOutParam());
8819 mMachine->GetExtraData(Bstr("VBoxInternal2/CoreDumpReplaceSystemDump").raw(), coreDumpReplaceSys.asOutParam());
8820 mMachine->GetExtraData(Bstr("VBoxInternal2/CoreDumpLive").raw(), coreDumpLive.asOutParam());
8821
8822 uint32_t fCoreFlags = 0;
8823 if ( coreDumpReplaceSys.isEmpty() == false
8824 && Utf8Str(coreDumpReplaceSys).toUInt32() == 1)
8825 fCoreFlags |= RTCOREDUMPER_FLAGS_REPLACE_SYSTEM_DUMP;
8826
8827 if ( coreDumpLive.isEmpty() == false
8828 && Utf8Str(coreDumpLive).toUInt32() == 1)
8829 fCoreFlags |= RTCOREDUMPER_FLAGS_LIVE_CORE;
8830
8831 Utf8Str strDumpDir(coreDumpDir);
8832 const char *pszDumpDir = strDumpDir.c_str();
8833 if ( pszDumpDir
8834 && *pszDumpDir == '\0')
8835 pszDumpDir = NULL;
8836
8837 int vrc;
8838 if ( pszDumpDir
8839 && !RTDirExists(pszDumpDir))
8840 {
8841 /*
8842 * Try create the directory.
8843 */
8844 vrc = RTDirCreateFullPath(pszDumpDir, 0700);
8845 if (RT_FAILURE(vrc))
8846 throw setErrorBoth(E_FAIL, vrc, tr("Failed to setup CoreDumper. Couldn't create dump directory '%s' (%Rrc)"),
8847 pszDumpDir, vrc);
8848 }
8849
8850 vrc = RTCoreDumperSetup(pszDumpDir, fCoreFlags);
8851 if (RT_FAILURE(vrc))
8852 throw setErrorBoth(E_FAIL, vrc, tr("Failed to setup CoreDumper (%Rrc)"), vrc);
8853 LogRel(("CoreDumper setup successful. pszDumpDir=%s fFlags=%#x\n", pszDumpDir ? pszDumpDir : ".", fCoreFlags));
8854 }
8855#endif
8856
8857
8858 // If there is immutable drive the process that.
8859 VMPowerUpTask::ProgressList progresses(task->hardDiskProgresses);
8860 if (aProgress && !progresses.empty())
8861 {
8862 for (VMPowerUpTask::ProgressList::const_iterator it = progresses.begin(); it != progresses.end(); ++it)
8863 {
8864 ++cOperations;
8865 ulTotalOperationsWeight += 1;
8866 }
8867 hrc = pPowerupProgress->init(static_cast<IConsole *>(this),
8868 progressDesc.raw(),
8869 TRUE, // Cancelable
8870 cOperations,
8871 ulTotalOperationsWeight,
8872 tr("Starting Hard Disk operations"),
8873 1);
8874 AssertComRCReturnRC(hrc);
8875 }
8876 else if ( mMachineState == MachineState_Saved
8877 || mMachineState == MachineState_AbortedSaved
8878 || !fTeleporterEnabled)
8879 hrc = pPowerupProgress->init(static_cast<IConsole *>(this),
8880 progressDesc.raw(),
8881 FALSE /* aCancelable */);
8882 else if (fTeleporterEnabled)
8883 hrc = pPowerupProgress->init(static_cast<IConsole *>(this),
8884 progressDesc.raw(),
8885 TRUE /* aCancelable */,
8886 3 /* cOperations */,
8887 10 /* ulTotalOperationsWeight */,
8888 tr("Teleporting virtual machine"),
8889 1 /* ulFirstOperationWeight */);
8890
8891 if (FAILED(hrc))
8892 throw hrc;
8893
8894 /* Tell VBoxSVC and Machine about the progress object so they can
8895 combine/proxy it to any openRemoteSession caller. */
8896 LogFlowThisFunc(("Calling BeginPowerUp...\n"));
8897 hrc = mControl->BeginPowerUp(pPowerupProgress);
8898 if (FAILED(hrc))
8899 {
8900 LogFlowThisFunc(("BeginPowerUp failed\n"));
8901 throw hrc;
8902 }
8903 fBeganPoweringUp = true;
8904
8905 LogFlowThisFunc(("Checking if canceled...\n"));
8906 BOOL fCanceled;
8907 hrc = pPowerupProgress->COMGETTER(Canceled)(&fCanceled);
8908 if (FAILED(hrc))
8909 throw hrc;
8910
8911 if (fCanceled)
8912 {
8913 LogFlowThisFunc(("Canceled in BeginPowerUp\n"));
8914 throw setError(E_FAIL, tr("Powerup was canceled"));
8915 }
8916 LogFlowThisFunc(("Not canceled yet.\n"));
8917
8918 /** @todo this code prevents starting a VM with unavailable bridged
8919 * networking interface. The only benefit is a slightly better error
8920 * message, which should be moved to the driver code. This is the
8921 * only reason why I left the code in for now. The driver allows
8922 * unavailable bridged networking interfaces in certain circumstances,
8923 * and this is sabotaged by this check. The VM will initially have no
8924 * network connectivity, but the user can fix this at runtime. */
8925#if 0
8926 /* the network cards will undergo a quick consistency check */
8927 for (ULONG slot = 0;
8928 slot < maxNetworkAdapters;
8929 ++slot)
8930 {
8931 ComPtr<INetworkAdapter> pNetworkAdapter;
8932 mMachine->GetNetworkAdapter(slot, pNetworkAdapter.asOutParam());
8933 BOOL enabled = FALSE;
8934 pNetworkAdapter->COMGETTER(Enabled)(&enabled);
8935 if (!enabled)
8936 continue;
8937
8938 NetworkAttachmentType_T netattach;
8939 pNetworkAdapter->COMGETTER(AttachmentType)(&netattach);
8940 switch (netattach)
8941 {
8942 case NetworkAttachmentType_Bridged:
8943 {
8944 /* a valid host interface must have been set */
8945 Bstr hostif;
8946 pNetworkAdapter->COMGETTER(HostInterface)(hostif.asOutParam());
8947 if (hostif.isEmpty())
8948 {
8949 throw setError(VBOX_E_HOST_ERROR,
8950 tr("VM cannot start because host interface networking requires a host interface name to be set"));
8951 }
8952 ComPtr<IVirtualBox> pVirtualBox;
8953 mMachine->COMGETTER(Parent)(pVirtualBox.asOutParam());
8954 ComPtr<IHost> pHost;
8955 pVirtualBox->COMGETTER(Host)(pHost.asOutParam());
8956 ComPtr<IHostNetworkInterface> pHostInterface;
8957 if (!SUCCEEDED(pHost->FindHostNetworkInterfaceByName(hostif.raw(), pHostInterface.asOutParam())))
8958 throw setError(VBOX_E_HOST_ERROR,
8959 tr("VM cannot start because the host interface '%ls' does not exist"), hostif.raw());
8960 break;
8961 }
8962 default:
8963 break;
8964 }
8965 }
8966#endif // 0
8967
8968
8969 /* setup task object and thread to carry out the operation
8970 * asynchronously */
8971 if (aProgress)
8972 {
8973 hrc = pPowerupProgress.queryInterfaceTo(aProgress);
8974 AssertComRCReturnRC(hrc);
8975 }
8976
8977#ifdef VBOX_WITH_FULL_VM_ENCRYPTION
8978 task->mKeyStore = Utf8Str(bstrStateKeyStore);
8979 task->mKeyId = Utf8Str(bstrStateKeyId);
8980 task->m_pKeyStore = m_pKeyStore;
8981#endif
8982
8983 hrc = task->createThread();
8984 task = NULL;
8985 if (FAILED(hrc))
8986 throw hrc;
8987
8988 /* finally, set the state: no right to fail in this method afterwards
8989 * since we've already started the thread and it is now responsible for
8990 * any error reporting and appropriate state change! */
8991 if (mMachineState == MachineState_Saved || mMachineState == MachineState_AbortedSaved)
8992 i_setMachineState(MachineState_Restoring);
8993 else if (fTeleporterEnabled)
8994 i_setMachineState(MachineState_TeleportingIn);
8995 else
8996 i_setMachineState(MachineState_Starting);
8997 }
8998 catch (HRESULT aRC)
8999 {
9000 hrc = aRC;
9001 }
9002
9003 if (FAILED(hrc) && fBeganPoweringUp)
9004 {
9005
9006 /* The progress object will fetch the current error info */
9007 if (!pPowerupProgress.isNull())
9008 pPowerupProgress->i_notifyComplete(hrc);
9009
9010 /* Save the error info across the IPC below. Can't be done before the
9011 * progress notification above, as saving the error info deletes it
9012 * from the current context, and thus the progress object wouldn't be
9013 * updated correctly. */
9014 ErrorInfoKeeper eik;
9015
9016 /* signal end of operation */
9017 mControl->EndPowerUp(hrc);
9018 }
9019
9020 if (task)
9021 {
9022 ErrorInfoKeeper eik;
9023 delete task;
9024 }
9025
9026 LogFlowThisFunc(("mMachineState=%d, hrc=%Rhrc\n", mMachineState, hrc));
9027 LogFlowThisFuncLeave();
9028 return hrc;
9029}
9030
9031/**
9032 * Internal power off worker routine.
9033 *
9034 * This method may be called only at certain places with the following meaning
9035 * as shown below:
9036 *
9037 * - if the machine state is either Running or Paused, a normal
9038 * Console-initiated powerdown takes place (e.g. PowerDown());
9039 * - if the machine state is Saving, saveStateThread() has successfully done its
9040 * job;
9041 * - if the machine state is Starting or Restoring, powerUpThread() has failed
9042 * to start/load the VM;
9043 * - if the machine state is Stopping, the VM has powered itself off (i.e. not
9044 * as a result of the powerDown() call).
9045 *
9046 * Calling it in situations other than the above will cause unexpected behavior.
9047 *
9048 * Note that this method should be the only one that destroys mpUVM and sets it
9049 * to NULL.
9050 *
9051 * @param aProgress Progress object to run (may be NULL).
9052 *
9053 * @note Locks this object for writing.
9054 *
9055 * @note Never call this method from a thread that called addVMCaller() or
9056 * instantiated an AutoVMCaller object; first call releaseVMCaller() or
9057 * release(). Otherwise it will deadlock.
9058 */
9059HRESULT Console::i_powerDown(IProgress *aProgress /*= NULL*/)
9060{
9061 LogFlowThisFuncEnter();
9062
9063 AutoCaller autoCaller(this);
9064 AssertComRCReturnRC(autoCaller.hrc());
9065
9066 ComPtr<IInternalProgressControl> pProgressControl(aProgress);
9067
9068 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
9069
9070 /* Total # of steps for the progress object. Must correspond to the
9071 * number of "advance percent count" comments in this method! */
9072 enum { StepCount = 7 };
9073 /* current step */
9074 ULONG step = 0;
9075
9076 HRESULT hrc = S_OK;
9077 int vrc = VINF_SUCCESS;
9078
9079 /* sanity */
9080 Assert(mVMDestroying == false);
9081
9082 PCVMMR3VTABLE const pVMM = mpVMM;
9083 AssertPtrReturn(pVMM, E_UNEXPECTED);
9084 PUVM pUVM = mpUVM;
9085 AssertPtrReturn(pUVM, E_UNEXPECTED);
9086
9087 uint32_t cRefs = pVMM->pfnVMR3RetainUVM(pUVM);
9088 Assert(cRefs != UINT32_MAX); NOREF(cRefs);
9089
9090 AssertMsg( mMachineState == MachineState_Running
9091 || mMachineState == MachineState_Paused
9092 || mMachineState == MachineState_Stuck
9093 || mMachineState == MachineState_Starting
9094 || mMachineState == MachineState_Stopping
9095 || mMachineState == MachineState_Saving
9096 || mMachineState == MachineState_Restoring
9097 || mMachineState == MachineState_TeleportingPausedVM
9098 || mMachineState == MachineState_TeleportingIn
9099 , ("Invalid machine state: %s\n", ::stringifyMachineState(mMachineState)));
9100
9101 LogRel(("Console::powerDown(): A request to power off the VM has been issued (mMachineState=%s, InUninit=%d)\n",
9102 ::stringifyMachineState(mMachineState), getObjectState().getState() == ObjectState::InUninit));
9103
9104 /* Check if we need to power off the VM. In case of mVMPoweredOff=true, the
9105 * VM has already powered itself off in vmstateChangeCallback() and is just
9106 * notifying Console about that. In case of Starting or Restoring,
9107 * powerUpThread() is calling us on failure, so the VM is already off at
9108 * that point. */
9109 if ( !mVMPoweredOff
9110 && ( mMachineState == MachineState_Starting
9111 || mMachineState == MachineState_Restoring
9112 || mMachineState == MachineState_TeleportingIn)
9113 )
9114 mVMPoweredOff = true;
9115
9116 /*
9117 * Go to Stopping state if not already there.
9118 *
9119 * Note that we don't go from Saving/Restoring to Stopping because
9120 * vmstateChangeCallback() needs it to set the state to Saved on
9121 * VMSTATE_TERMINATED. In terms of protecting from inappropriate operations
9122 * while leaving the lock below, Saving or Restoring should be fine too.
9123 * Ditto for TeleportingPausedVM -> Teleported.
9124 */
9125 if ( mMachineState != MachineState_Saving
9126 && mMachineState != MachineState_Restoring
9127 && mMachineState != MachineState_Stopping
9128 && mMachineState != MachineState_TeleportingIn
9129 && mMachineState != MachineState_TeleportingPausedVM
9130 )
9131 i_setMachineState(MachineState_Stopping);
9132
9133 /* ----------------------------------------------------------------------
9134 * DONE with necessary state changes, perform the power down actions (it's
9135 * safe to release the object lock now if needed)
9136 * ---------------------------------------------------------------------- */
9137
9138 if (mDisplay)
9139 {
9140 alock.release();
9141
9142 mDisplay->i_notifyPowerDown();
9143
9144 alock.acquire();
9145 }
9146
9147 /* Stop the VRDP server to prevent new clients connection while VM is being
9148 * powered off. */
9149 if (mConsoleVRDPServer)
9150 {
9151 LogFlowThisFunc(("Stopping VRDP server...\n"));
9152
9153 /* Leave the lock since EMT could call us back as addVMCaller() */
9154 alock.release();
9155
9156 mConsoleVRDPServer->Stop();
9157
9158 alock.acquire();
9159 }
9160
9161 /* advance percent count */
9162 if (pProgressControl)
9163 pProgressControl->SetCurrentOperationProgress(99 * (++step) / StepCount);
9164
9165
9166 /* ----------------------------------------------------------------------
9167 * Now, wait for all mpUVM callers to finish their work if there are still
9168 * some on other threads. NO methods that need mpUVM (or initiate other calls
9169 * that need it) may be called after this point
9170 * ---------------------------------------------------------------------- */
9171
9172 /* go to the destroying state to prevent from adding new callers */
9173 mVMDestroying = true;
9174
9175 if (mVMCallers > 0)
9176 {
9177 /* lazy creation */
9178 if (mVMZeroCallersSem == NIL_RTSEMEVENT)
9179 RTSemEventCreate(&mVMZeroCallersSem);
9180
9181 LogFlowThisFunc(("Waiting for mpUVM callers (%d) to drop to zero...\n", mVMCallers));
9182
9183 alock.release();
9184
9185 RTSemEventWait(mVMZeroCallersSem, RT_INDEFINITE_WAIT);
9186
9187 alock.acquire();
9188 }
9189
9190 /* advance percent count */
9191 if (pProgressControl)
9192 pProgressControl->SetCurrentOperationProgress(99 * (++step) / StepCount);
9193
9194 vrc = VINF_SUCCESS;
9195
9196 /*
9197 * Power off the VM if not already done that.
9198 * Leave the lock since EMT will call vmstateChangeCallback.
9199 *
9200 * Note that VMR3PowerOff() may fail here (invalid VMSTATE) if the
9201 * VM-(guest-)initiated power off happened in parallel a ms before this
9202 * call. So far, we let this error pop up on the user's side.
9203 */
9204 if (!mVMPoweredOff)
9205 {
9206 LogFlowThisFunc(("Powering off the VM...\n"));
9207 alock.release();
9208 vrc = pVMM->pfnVMR3PowerOff(pUVM);
9209#ifdef VBOX_WITH_EXTPACK
9210 mptrExtPackManager->i_callAllVmPowerOffHooks(this, pVMM->pfnVMR3GetVM(pUVM), pVMM);
9211#endif
9212 alock.acquire();
9213 }
9214
9215 /* advance percent count */
9216 if (pProgressControl)
9217 pProgressControl->SetCurrentOperationProgress(99 * (++step) / StepCount);
9218
9219#ifdef VBOX_WITH_HGCM
9220 /* Shutdown HGCM services before destroying the VM. */
9221 if (m_pVMMDev)
9222 {
9223 LogFlowThisFunc(("Shutdown HGCM...\n"));
9224
9225 /* Leave the lock since EMT might wait for it and will call us back as addVMCaller() */
9226 alock.release();
9227
9228# ifdef VBOX_WITH_SHARED_CLIPBOARD
9229 if (m_hHgcmSvcExtShCl)
9230 {
9231 HGCMHostUnregisterServiceExtension(m_hHgcmSvcExtShCl);
9232 m_hHgcmSvcExtShCl = NULL;
9233 }
9234 GuestShCl::destroyInstance();
9235#endif
9236
9237# ifdef VBOX_WITH_DRAG_AND_DROP
9238 if (m_hHgcmSvcExtDragAndDrop)
9239 {
9240 HGCMHostUnregisterServiceExtension(m_hHgcmSvcExtDragAndDrop);
9241 m_hHgcmSvcExtDragAndDrop = NULL;
9242 }
9243# endif
9244
9245 m_pVMMDev->hgcmShutdown();
9246
9247 alock.acquire();
9248 }
9249
9250 /* advance percent count */
9251 if (pProgressControl)
9252 pProgressControl->SetCurrentOperationProgress(99 * (++step) / StepCount);
9253
9254#endif /* VBOX_WITH_HGCM */
9255
9256 LogFlowThisFunc(("Ready for VM destruction.\n"));
9257
9258 /* If we are called from Console::uninit(), then try to destroy the VM even
9259 * on failure (this will most likely fail too, but what to do?..) */
9260 if (RT_SUCCESS(vrc) || getObjectState().getState() == ObjectState::InUninit)
9261 {
9262 /* If the machine has a USB controller, release all USB devices
9263 * (symmetric to the code in captureUSBDevices()) */
9264 if (mfVMHasUsbController)
9265 {
9266 alock.release();
9267 i_detachAllUSBDevices(false /* aDone */);
9268 alock.acquire();
9269 }
9270
9271 /* Now we've got to destroy the VM as well. (mpUVM is not valid beyond
9272 * this point). We release the lock before calling VMR3Destroy() because
9273 * it will result into calling destructors of drivers associated with
9274 * Console children which may in turn try to lock Console (e.g. by
9275 * instantiating SafeVMPtr to access mpUVM). It's safe here because
9276 * mVMDestroying is set which should prevent any activity. */
9277
9278 /* Set mpUVM to NULL early just in case if some old code is not using
9279 * addVMCaller()/releaseVMCaller(). (We have our own ref on pUVM.) */
9280 pVMM->pfnVMR3ReleaseUVM(mpUVM);
9281 mpUVM = NULL;
9282
9283 LogFlowThisFunc(("Destroying the VM...\n"));
9284
9285 alock.release();
9286
9287 vrc = pVMM->pfnVMR3Destroy(pUVM);
9288
9289 /* take the lock again */
9290 alock.acquire();
9291
9292 /* advance percent count */
9293 if (pProgressControl)
9294 pProgressControl->SetCurrentOperationProgress(99 * (++step) / StepCount);
9295
9296 if (RT_SUCCESS(vrc))
9297 {
9298 LogFlowThisFunc(("Machine has been destroyed (mMachineState=%d)\n",
9299 mMachineState));
9300 /* Note: the Console-level machine state change happens on the
9301 * VMSTATE_TERMINATE state change in vmstateChangeCallback(). If
9302 * powerDown() is called from EMT (i.e. from vmstateChangeCallback()
9303 * on receiving VM-initiated VMSTATE_OFF), VMSTATE_TERMINATE hasn't
9304 * occurred yet. This is okay, because mMachineState is already
9305 * Stopping in this case, so any other attempt to call PowerDown()
9306 * will be rejected. */
9307 }
9308 else
9309 {
9310 /* bad bad bad, but what to do? (Give Console our UVM ref.) */
9311 mpUVM = pUVM;
9312 pUVM = NULL;
9313 hrc = setErrorBoth(VBOX_E_VM_ERROR, vrc, tr("Could not destroy the machine. (Error: %Rrc)"), vrc);
9314 }
9315
9316 /* Complete the detaching of the USB devices. */
9317 if (mfVMHasUsbController)
9318 {
9319 alock.release();
9320 i_detachAllUSBDevices(true /* aDone */);
9321 alock.acquire();
9322 }
9323
9324 /* advance percent count */
9325 if (pProgressControl)
9326 pProgressControl->SetCurrentOperationProgress(99 * (++step) / StepCount);
9327 }
9328 else
9329 hrc = setErrorBoth(VBOX_E_VM_ERROR, vrc, tr("Could not power off the machine. (Error: %Rrc)"), vrc);
9330
9331 /*
9332 * Finished with the destruction.
9333 *
9334 * Note that if something impossible happened and we've failed to destroy
9335 * the VM, mVMDestroying will remain true and mMachineState will be
9336 * something like Stopping, so most Console methods will return an error
9337 * to the caller.
9338 */
9339 if (pUVM != NULL)
9340 pVMM->pfnVMR3ReleaseUVM(pUVM);
9341 else
9342 mVMDestroying = false;
9343
9344 LogFlowThisFuncLeave();
9345 return hrc;
9346}
9347
9348/**
9349 * @note Locks this object for writing.
9350 */
9351HRESULT Console::i_setMachineState(MachineState_T aMachineState, bool aUpdateServer /* = true */)
9352{
9353 AutoCaller autoCaller(this);
9354 AssertComRCReturnRC(autoCaller.hrc());
9355
9356 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
9357
9358 HRESULT hrc = S_OK;
9359
9360 if (mMachineState != aMachineState)
9361 {
9362 LogThisFunc(("machineState=%s -> %s aUpdateServer=%RTbool\n",
9363 ::stringifyMachineState(mMachineState), ::stringifyMachineState(aMachineState), aUpdateServer));
9364 LogRel(("Console: Machine state changed to '%s'\n", ::stringifyMachineState(aMachineState)));
9365 mMachineState = aMachineState;
9366
9367 /// @todo (dmik)
9368 // possibly, we need to redo onStateChange() using the dedicated
9369 // Event thread, like it is done in VirtualBox. This will make it
9370 // much safer (no deadlocks possible if someone tries to use the
9371 // console from the callback), however, listeners will lose the
9372 // ability to synchronously react to state changes (is it really
9373 // necessary??)
9374 LogFlowThisFunc(("Doing onStateChange()...\n"));
9375 i_onStateChange(aMachineState);
9376 LogFlowThisFunc(("Done onStateChange()\n"));
9377
9378 if (aUpdateServer)
9379 {
9380 /* Server notification MUST be done from under the lock; otherwise
9381 * the machine state here and on the server might go out of sync
9382 * which can lead to various unexpected results (like the machine
9383 * state being >= MachineState_Running on the server, while the
9384 * session state is already SessionState_Unlocked at the same time
9385 * there).
9386 *
9387 * Cross-lock conditions should be carefully watched out: calling
9388 * UpdateState we will require Machine and SessionMachine locks
9389 * (remember that here we're holding the Console lock here, and also
9390 * all locks that have been acquire by the thread before calling
9391 * this method).
9392 */
9393 LogFlowThisFunc(("Doing mControl->UpdateState()...\n"));
9394 hrc = mControl->UpdateState(aMachineState);
9395 LogFlowThisFunc(("mControl->UpdateState()=%Rhrc\n", hrc));
9396 }
9397 }
9398
9399 return hrc;
9400}
9401
9402/**
9403 * Searches for a shared folder with the given logical name
9404 * in the collection of shared folders.
9405 *
9406 * @param strName logical name of the shared folder
9407 * @param aSharedFolder where to return the found object
9408 * @param aSetError whether to set the error info if the folder is
9409 * not found
9410 * @return
9411 * S_OK when found or E_INVALIDARG when not found
9412 *
9413 * @note The caller must lock this object for writing.
9414 */
9415HRESULT Console::i_findSharedFolder(const Utf8Str &strName, ComObjPtr<ConsoleSharedFolder> &aSharedFolder, bool aSetError /* = false */)
9416{
9417 /* sanity check */
9418 AssertReturn(isWriteLockOnCurrentThread(), E_FAIL);
9419
9420 SharedFolderMap::const_iterator it = m_mapSharedFolders.find(strName);
9421 if (it != m_mapSharedFolders.end())
9422 {
9423 aSharedFolder = it->second;
9424 return S_OK;
9425 }
9426
9427 if (aSetError)
9428 setError(VBOX_E_FILE_ERROR, tr("Could not find a shared folder named '%s'."), strName.c_str());
9429 return VBOX_E_FILE_ERROR;
9430}
9431
9432/**
9433 * Fetches the list of global or machine shared folders from the server.
9434 *
9435 * @param aGlobal true to fetch global folders.
9436 *
9437 * @note The caller must lock this object for writing.
9438 */
9439HRESULT Console::i_fetchSharedFolders(BOOL aGlobal)
9440{
9441 /* sanity check */
9442 AssertReturn( getObjectState().getState() == ObjectState::InInit
9443 || isWriteLockOnCurrentThread(), E_FAIL);
9444
9445 LogFlowThisFunc(("Entering\n"));
9446
9447 /* Check if we're online and keep it that way. */
9448 SafeVMPtrQuiet ptrVM(this);
9449 AutoVMCallerQuietWeak autoVMCaller(this);
9450 bool const online = ptrVM.isOk()
9451 && m_pVMMDev
9452 && m_pVMMDev->isShFlActive();
9453
9454 HRESULT hrc = S_OK;
9455
9456 try
9457 {
9458 if (aGlobal)
9459 {
9460 /// @todo grab & process global folders when they are done
9461 }
9462 else
9463 {
9464 SharedFolderDataMap oldFolders;
9465 if (online)
9466 oldFolders = m_mapMachineSharedFolders;
9467
9468 m_mapMachineSharedFolders.clear();
9469
9470 SafeIfaceArray<ISharedFolder> folders;
9471 hrc = mMachine->COMGETTER(SharedFolders)(ComSafeArrayAsOutParam(folders));
9472 if (FAILED(hrc)) throw hrc;
9473
9474 for (size_t i = 0; i < folders.size(); ++i)
9475 {
9476 ComPtr<ISharedFolder> pSharedFolder = folders[i];
9477
9478 Bstr bstr;
9479 hrc = pSharedFolder->COMGETTER(Name)(bstr.asOutParam());
9480 if (FAILED(hrc)) throw hrc;
9481 Utf8Str strName(bstr);
9482
9483 hrc = pSharedFolder->COMGETTER(HostPath)(bstr.asOutParam());
9484 if (FAILED(hrc)) throw hrc;
9485 Utf8Str strHostPath(bstr);
9486
9487 BOOL writable;
9488 hrc = pSharedFolder->COMGETTER(Writable)(&writable);
9489 if (FAILED(hrc)) throw hrc;
9490
9491 BOOL autoMount;
9492 hrc = pSharedFolder->COMGETTER(AutoMount)(&autoMount);
9493 if (FAILED(hrc)) throw hrc;
9494
9495 hrc = pSharedFolder->COMGETTER(AutoMountPoint)(bstr.asOutParam());
9496 if (FAILED(hrc)) throw hrc;
9497 Utf8Str strAutoMountPoint(bstr);
9498
9499 m_mapMachineSharedFolders.insert(std::make_pair(strName,
9500 SharedFolderData(strHostPath, !!writable,
9501 !!autoMount, strAutoMountPoint)));
9502
9503 /* send changes to HGCM if the VM is running */
9504 if (online)
9505 {
9506 SharedFolderDataMap::iterator it = oldFolders.find(strName);
9507 if ( it == oldFolders.end()
9508 || it->second.m_strHostPath != strHostPath)
9509 {
9510 /* a new machine folder is added or
9511 * the existing machine folder is changed */
9512 if (m_mapSharedFolders.find(strName) != m_mapSharedFolders.end())
9513 ; /* the console folder exists, nothing to do */
9514 else
9515 {
9516 /* remove the old machine folder (when changed)
9517 * or the global folder if any (when new) */
9518 if ( it != oldFolders.end()
9519 || m_mapGlobalSharedFolders.find(strName) != m_mapGlobalSharedFolders.end()
9520 )
9521 {
9522 hrc = i_removeSharedFolder(strName);
9523 if (FAILED(hrc)) throw hrc;
9524 }
9525
9526 /* create the new machine folder */
9527 hrc = i_createSharedFolder(strName,
9528 SharedFolderData(strHostPath, !!writable, !!autoMount, strAutoMountPoint));
9529 if (FAILED(hrc)) throw hrc;
9530 }
9531 }
9532 /* forget the processed (or identical) folder */
9533 if (it != oldFolders.end())
9534 oldFolders.erase(it);
9535 }
9536 }
9537
9538 /* process outdated (removed) folders */
9539 if (online)
9540 {
9541 for (SharedFolderDataMap::const_iterator it = oldFolders.begin();
9542 it != oldFolders.end(); ++it)
9543 {
9544 if (m_mapSharedFolders.find(it->first) != m_mapSharedFolders.end())
9545 ; /* the console folder exists, nothing to do */
9546 else
9547 {
9548 /* remove the outdated machine folder */
9549 hrc = i_removeSharedFolder(it->first);
9550 if (FAILED(hrc)) throw hrc;
9551
9552 /* create the global folder if there is any */
9553 SharedFolderDataMap::const_iterator git =
9554 m_mapGlobalSharedFolders.find(it->first);
9555 if (git != m_mapGlobalSharedFolders.end())
9556 {
9557 hrc = i_createSharedFolder(git->first, git->second);
9558 if (FAILED(hrc)) throw hrc;
9559 }
9560 }
9561 }
9562 }
9563 }
9564 }
9565 catch (HRESULT hrc2)
9566 {
9567 hrc = hrc2;
9568 if (online)
9569 i_atVMRuntimeErrorCallbackF(0, "BrokenSharedFolder", N_("Broken shared folder!"));
9570 }
9571
9572 LogFlowThisFunc(("Leaving\n"));
9573
9574 return hrc;
9575}
9576
9577/**
9578 * Searches for a shared folder with the given name in the list of machine
9579 * shared folders and then in the list of the global shared folders.
9580 *
9581 * @param strName Name of the folder to search for.
9582 * @param aIt Where to store the pointer to the found folder.
9583 * @return @c true if the folder was found and @c false otherwise.
9584 *
9585 * @note The caller must lock this object for reading.
9586 */
9587bool Console::i_findOtherSharedFolder(const Utf8Str &strName,
9588 SharedFolderDataMap::const_iterator &aIt)
9589{
9590 /* sanity check */
9591 AssertReturn(isWriteLockOnCurrentThread(), false);
9592
9593 /* first, search machine folders */
9594 aIt = m_mapMachineSharedFolders.find(strName);
9595 if (aIt != m_mapMachineSharedFolders.end())
9596 return true;
9597
9598 /* second, search machine folders */
9599 aIt = m_mapGlobalSharedFolders.find(strName);
9600 if (aIt != m_mapGlobalSharedFolders.end())
9601 return true;
9602
9603 return false;
9604}
9605
9606/**
9607 * Calls the HGCM service to add a shared folder definition.
9608 *
9609 * @param strName Shared folder name.
9610 * @param aData Shared folder data.
9611 *
9612 * @note Must be called from under AutoVMCaller and when mpUVM != NULL!
9613 * @note Doesn't lock anything.
9614 */
9615HRESULT Console::i_createSharedFolder(const Utf8Str &strName, const SharedFolderData &aData)
9616{
9617 Log(("Adding shared folder '%s' -> '%s'\n", strName.c_str(), aData.m_strHostPath.c_str()));
9618
9619 /*
9620 * Sanity checks
9621 */
9622 ComAssertRet(strName.isNotEmpty(), E_FAIL);
9623 ComAssertRet(aData.m_strHostPath.isNotEmpty(), E_FAIL);
9624
9625 AssertReturn(mpUVM, E_FAIL);
9626 AssertReturn(m_pVMMDev && m_pVMMDev->isShFlActive(), E_FAIL);
9627
9628 /*
9629 * Find out whether we should allow symbolic link creation.
9630 */
9631 Bstr bstrValue;
9632 HRESULT hrc = mMachine->GetExtraData(BstrFmt("VBoxInternal2/SharedFoldersEnableSymlinksCreate/%s", strName.c_str()).raw(),
9633 bstrValue.asOutParam());
9634 bool fSymlinksCreate = hrc == S_OK && bstrValue == "1";
9635
9636 /*
9637 * Check whether the path is valid and exists.
9638 */
9639 char szAbsHostPath[RTPATH_MAX];
9640 int vrc = RTPathAbs(aData.m_strHostPath.c_str(), szAbsHostPath, sizeof(szAbsHostPath));
9641 if (RT_FAILURE(vrc))
9642 return setErrorBoth(E_INVALIDARG, vrc, tr("Invalid shared folder path: '%s' (%Rrc)"), aData.m_strHostPath.c_str(), vrc);
9643
9644 /* Check whether the path is full (absolute). ASSUMING a RTPATH_MAX of ~4K
9645 this also checks that the length is within bounds of a SHFLSTRING. */
9646 if (RTPathCompare(aData.m_strHostPath.c_str(), szAbsHostPath) != 0)
9647 return setError(E_INVALIDARG, tr("Shared folder path '%s' is not absolute"), aData.m_strHostPath.c_str());
9648
9649 bool const fMissing = !RTPathExists(szAbsHostPath);
9650
9651 /*
9652 * Check the other two string lengths before converting them all to SHFLSTRINGS.
9653 */
9654 if (strName.length() >= _2K)
9655 return setError(E_INVALIDARG, tr("Shared folder name is too long: %zu bytes", "", strName.length()), strName.length());
9656 if (aData.m_strAutoMountPoint.length() >= RTPATH_MAX)
9657 return setError(E_INVALIDARG, tr("Shared folder mount point too long: %zu bytes", "",
9658 (int)aData.m_strAutoMountPoint.length()),
9659 aData.m_strAutoMountPoint.length());
9660
9661 PSHFLSTRING pHostPath = ShflStringDupUtf8AsUtf16(aData.m_strHostPath.c_str());
9662 PSHFLSTRING pName = ShflStringDupUtf8AsUtf16(strName.c_str());
9663 PSHFLSTRING pAutoMountPoint = ShflStringDupUtf8AsUtf16(aData.m_strAutoMountPoint.c_str());
9664 if (pHostPath && pName && pAutoMountPoint)
9665 {
9666 /*
9667 * Make a SHFL_FN_ADD_MAPPING call to tell the service about folder.
9668 */
9669 VBOXHGCMSVCPARM aParams[SHFL_CPARMS_ADD_MAPPING];
9670 SHFLSTRING_TO_HGMC_PARAM(&aParams[0], pHostPath);
9671 SHFLSTRING_TO_HGMC_PARAM(&aParams[1], pName);
9672 HGCMSvcSetU32(&aParams[2],
9673 (aData.m_fWritable ? SHFL_ADD_MAPPING_F_WRITABLE : 0)
9674 | (aData.m_fAutoMount ? SHFL_ADD_MAPPING_F_AUTOMOUNT : 0)
9675 | (fSymlinksCreate ? SHFL_ADD_MAPPING_F_CREATE_SYMLINKS : 0)
9676 | (fMissing ? SHFL_ADD_MAPPING_F_MISSING : 0));
9677 SHFLSTRING_TO_HGMC_PARAM(&aParams[3], pAutoMountPoint);
9678 HGCMSvcSetU32(&aParams[4], SymlinkPolicy_None);
9679 AssertCompile(SHFL_CPARMS_ADD_MAPPING == 5);
9680
9681 vrc = m_pVMMDev->hgcmHostCall("VBoxSharedFolders", SHFL_FN_ADD_MAPPING, SHFL_CPARMS_ADD_MAPPING, aParams);
9682 if (RT_FAILURE(vrc))
9683 hrc = setErrorBoth(E_FAIL, vrc, tr("Could not create a shared folder '%s' mapped to '%s' (%Rrc)"),
9684 strName.c_str(), aData.m_strHostPath.c_str(), vrc);
9685
9686 else if (fMissing)
9687 hrc = setError(E_INVALIDARG, tr("Shared folder path '%s' does not exist on the host"), aData.m_strHostPath.c_str());
9688 else
9689 hrc = S_OK;
9690 }
9691 else
9692 hrc = E_OUTOFMEMORY;
9693 RTMemFree(pAutoMountPoint);
9694 RTMemFree(pName);
9695 RTMemFree(pHostPath);
9696 return hrc;
9697}
9698
9699/**
9700 * Calls the HGCM service to remove the shared folder definition.
9701 *
9702 * @param strName Shared folder name.
9703 *
9704 * @note Must be called from under AutoVMCaller and when mpUVM != NULL!
9705 * @note Doesn't lock anything.
9706 */
9707HRESULT Console::i_removeSharedFolder(const Utf8Str &strName)
9708{
9709 ComAssertRet(strName.isNotEmpty(), E_FAIL);
9710
9711 /* sanity checks */
9712 AssertReturn(mpUVM, E_FAIL);
9713 AssertReturn(m_pVMMDev && m_pVMMDev->isShFlActive(), E_FAIL);
9714
9715 VBOXHGCMSVCPARM parms;
9716 SHFLSTRING *pMapName;
9717 size_t cbString;
9718
9719 Log(("Removing shared folder '%s'\n", strName.c_str()));
9720
9721 Bstr bstrName(strName);
9722 cbString = (bstrName.length() + 1) * sizeof(RTUTF16);
9723 if (cbString >= UINT16_MAX)
9724 return setError(E_INVALIDARG, tr("The name is too long"));
9725 pMapName = (SHFLSTRING *) RTMemAllocZ(SHFLSTRING_HEADER_SIZE + cbString);
9726 Assert(pMapName);
9727 memcpy(pMapName->String.ucs2, bstrName.raw(), cbString);
9728
9729 pMapName->u16Size = (uint16_t)cbString;
9730 pMapName->u16Length = (uint16_t)(cbString - sizeof(RTUTF16));
9731
9732 parms.type = VBOX_HGCM_SVC_PARM_PTR;
9733 parms.u.pointer.addr = pMapName;
9734 parms.u.pointer.size = ShflStringSizeOfBuffer(pMapName);
9735
9736 int vrc = m_pVMMDev->hgcmHostCall("VBoxSharedFolders", SHFL_FN_REMOVE_MAPPING, 1, &parms);
9737 RTMemFree(pMapName);
9738 if (RT_FAILURE(vrc))
9739 return setErrorBoth(E_FAIL, vrc, tr("Could not remove the shared folder '%s' (%Rrc)"), strName.c_str(), vrc);
9740
9741 return S_OK;
9742}
9743
9744/**
9745 * Retains a reference to the default cryptographic interface.
9746 *
9747 * @returns VBox status code.
9748 * @retval VERR_NOT_SUPPORTED if the VM is not configured for encryption.
9749 * @param ppCryptoIf Where to store the pointer to the cryptographic interface on success.
9750 *
9751 * @note Locks this object for writing.
9752 */
9753int Console::i_retainCryptoIf(PCVBOXCRYPTOIF *ppCryptoIf)
9754{
9755 AssertReturn(ppCryptoIf != NULL, VERR_INVALID_PARAMETER);
9756
9757 int vrc = VINF_SUCCESS;
9758 if (mhLdrModCrypto == NIL_RTLDRMOD)
9759 {
9760#ifdef VBOX_WITH_EXTPACK
9761 /*
9762 * Check that a crypto extension pack name is set and resolve it into a
9763 * library path.
9764 */
9765 HRESULT hrc = S_OK;
9766 Bstr bstrExtPack;
9767
9768 ComPtr<IVirtualBox> pVirtualBox;
9769 hrc = mMachine->COMGETTER(Parent)(pVirtualBox.asOutParam());
9770 ComPtr<ISystemProperties> pSystemProperties;
9771 if (SUCCEEDED(hrc))
9772 hrc = pVirtualBox->COMGETTER(SystemProperties)(pSystemProperties.asOutParam());
9773 if (SUCCEEDED(hrc))
9774 hrc = pSystemProperties->COMGETTER(DefaultCryptoExtPack)(bstrExtPack.asOutParam());
9775 if (FAILED(hrc))
9776 {
9777 setErrorBoth(hrc, VERR_INVALID_PARAMETER,
9778 tr("Failed to query default extension pack name for the cryptographic module"));
9779 return VERR_INVALID_PARAMETER;
9780 }
9781
9782 Utf8Str strExtPack(bstrExtPack);
9783 if (strExtPack.isEmpty())
9784 {
9785 setError(VBOX_E_OBJECT_NOT_FOUND,
9786 tr("Ńo extension pack providing a cryptographic support module could be found"));
9787 return VERR_NOT_FOUND;
9788 }
9789
9790 Utf8Str strCryptoLibrary;
9791 vrc = mptrExtPackManager->i_getCryptoLibraryPathForExtPack(&strExtPack, &strCryptoLibrary);
9792 if (RT_SUCCESS(vrc))
9793 {
9794 RTERRINFOSTATIC ErrInfo;
9795 vrc = SUPR3HardenedLdrLoadPlugIn(strCryptoLibrary.c_str(), &mhLdrModCrypto, RTErrInfoInitStatic(&ErrInfo));
9796 if (RT_SUCCESS(vrc))
9797 {
9798 /* Resolve the entry point and query the pointer to the cryptographic interface. */
9799 PFNVBOXCRYPTOENTRY pfnCryptoEntry = NULL;
9800 vrc = RTLdrGetSymbol(mhLdrModCrypto, VBOX_CRYPTO_MOD_ENTRY_POINT, (void **)&pfnCryptoEntry);
9801 if (RT_SUCCESS(vrc))
9802 {
9803 vrc = pfnCryptoEntry(&mpCryptoIf);
9804 if (RT_FAILURE(vrc))
9805 setErrorBoth(VBOX_E_IPRT_ERROR, vrc,
9806 tr("Failed to query the interface callback table from the cryptographic support module '%s' from extension pack '%s'"),
9807 strCryptoLibrary.c_str(), strExtPack.c_str());
9808 }
9809 else
9810 setErrorBoth(VBOX_E_IPRT_ERROR, vrc,
9811 tr("Failed to resolve the entry point for the cryptographic support module '%s' from extension pack '%s'"),
9812 strCryptoLibrary.c_str(), strExtPack.c_str());
9813
9814 if (RT_FAILURE(vrc))
9815 {
9816 RTLdrClose(mhLdrModCrypto);
9817 mhLdrModCrypto = NIL_RTLDRMOD;
9818 }
9819 }
9820 else
9821 setErrorBoth(VBOX_E_IPRT_ERROR, vrc,
9822 tr("Couldn't load the cryptographic support module '%s' from extension pack '%s' (error: '%s')"),
9823 strCryptoLibrary.c_str(), strExtPack.c_str(), ErrInfo.Core.pszMsg);
9824 }
9825 else
9826 setErrorBoth(VBOX_E_IPRT_ERROR, vrc,
9827 tr("Couldn't resolve the library path of the crpytographic support module for extension pack '%s'"),
9828 strExtPack.c_str());
9829#else
9830 setError(VBOX_E_NOT_SUPPORTED,
9831 tr("The cryptographic support module is not supported in this build because extension packs are not supported"));
9832 vrc = VERR_NOT_SUPPORTED;
9833#endif
9834 }
9835
9836 if (RT_SUCCESS(vrc))
9837 {
9838 ASMAtomicIncU32(&mcRefsCrypto);
9839 *ppCryptoIf = mpCryptoIf;
9840 }
9841
9842 return vrc;
9843}
9844
9845/**
9846 * Releases the reference of the given cryptographic interface.
9847 *
9848 * @returns VBox status code.
9849 * @param pCryptoIf Pointer to the cryptographic interface to release.
9850 *
9851 * @note Locks this object for writing.
9852 */
9853int Console::i_releaseCryptoIf(PCVBOXCRYPTOIF pCryptoIf)
9854{
9855 AssertReturn(pCryptoIf == mpCryptoIf, VERR_INVALID_PARAMETER);
9856
9857 ASMAtomicDecU32(&mcRefsCrypto);
9858 return VINF_SUCCESS;
9859}
9860
9861/**
9862 * Tries to unload any loaded cryptographic support module if it is not in use currently.
9863 *
9864 * @returns COM status code.
9865 *
9866 * @note Locks this object for writing.
9867 */
9868HRESULT Console::i_unloadCryptoIfModule(void)
9869{
9870 AutoCaller autoCaller(this);
9871 AssertComRCReturnRC(autoCaller.hrc());
9872
9873 AutoWriteLock wlock(this COMMA_LOCKVAL_SRC_POS);
9874
9875 if (mcRefsCrypto)
9876 return setError(E_ACCESSDENIED,
9877 tr("The cryptographic support module is in use and can't be unloaded"));
9878
9879 if (mhLdrModCrypto != NIL_RTLDRMOD)
9880 {
9881 int vrc = RTLdrClose(mhLdrModCrypto);
9882 AssertRC(vrc);
9883 mhLdrModCrypto = NIL_RTLDRMOD;
9884 }
9885
9886 return S_OK;
9887}
9888
9889/** @callback_method_impl{FNVMATSTATE}
9890 *
9891 * @note Locks the Console object for writing.
9892 * @remarks The @a pUVM parameter can be NULL in one case where powerUpThread()
9893 * calls after the VM was destroyed.
9894 */
9895/*static*/ DECLCALLBACK(void)
9896Console::i_vmstateChangeCallback(PUVM pUVM, PCVMMR3VTABLE pVMM, VMSTATE enmState, VMSTATE enmOldState, void *pvUser)
9897{
9898 LogFlowFunc(("Changing state from %s to %s (pUVM=%p)\n",
9899 pVMM->pfnVMR3GetStateName(enmOldState), pVMM->pfnVMR3GetStateName(enmState), pUVM));
9900 RT_NOREF(pVMM);
9901
9902 Console *that = static_cast<Console *>(pvUser);
9903 AssertReturnVoid(that);
9904
9905 AutoCaller autoCaller(that);
9906
9907 /* Note that we must let this method proceed even if Console::uninit() has
9908 * been already called. In such case this VMSTATE change is a result of:
9909 * 1) powerDown() called from uninit() itself, or
9910 * 2) VM-(guest-)initiated power off. */
9911 AssertReturnVoid( autoCaller.isOk()
9912 || that->getObjectState().getState() == ObjectState::InUninit);
9913
9914 switch (enmState)
9915 {
9916 /*
9917 * The VM has terminated
9918 */
9919 case VMSTATE_OFF:
9920 {
9921#ifdef VBOX_WITH_GUEST_PROPS
9922 if (that->mfTurnResetIntoPowerOff)
9923 {
9924 Bstr strPowerOffReason;
9925
9926 if (that->mfPowerOffCausedByReset)
9927 strPowerOffReason = Bstr("Reset");
9928 else
9929 strPowerOffReason = Bstr("PowerOff");
9930
9931 that->mMachine->DeleteGuestProperty(Bstr("/VirtualBox/HostInfo/VMPowerOffReason").raw());
9932 that->mMachine->SetGuestProperty(Bstr("/VirtualBox/HostInfo/VMPowerOffReason").raw(),
9933 strPowerOffReason.raw(), Bstr("RDONLYGUEST").raw());
9934 that->mMachine->SaveSettings();
9935 }
9936#endif
9937
9938 AutoWriteLock alock(that COMMA_LOCKVAL_SRC_POS);
9939
9940 if (that->mVMStateChangeCallbackDisabled)
9941 return;
9942
9943 /* Do we still think that it is running? It may happen if this is a
9944 * VM-(guest-)initiated shutdown/poweroff.
9945 */
9946 if ( that->mMachineState != MachineState_Stopping
9947 && that->mMachineState != MachineState_Saving
9948 && that->mMachineState != MachineState_Restoring
9949 && that->mMachineState != MachineState_TeleportingIn
9950 && that->mMachineState != MachineState_TeleportingPausedVM
9951 && !that->mVMIsAlreadyPoweringOff
9952 )
9953 {
9954 LogFlowFunc(("VM has powered itself off but Console still thinks it is running. Notifying.\n"));
9955
9956 /*
9957 * Prevent powerDown() from calling VMR3PowerOff() again if this was called from
9958 * the power off state change.
9959 * When called from the Reset state make sure to call VMR3PowerOff() first.
9960 */
9961 Assert(that->mVMPoweredOff == false);
9962 that->mVMPoweredOff = true;
9963
9964 /*
9965 * request a progress object from the server
9966 * (this will set the machine state to Stopping on the server
9967 * to block others from accessing this machine)
9968 */
9969 ComPtr<IProgress> pProgress;
9970 HRESULT hrc = that->mControl->BeginPoweringDown(pProgress.asOutParam());
9971 AssertComRC(hrc);
9972
9973 /* sync the state with the server */
9974 that->i_setMachineStateLocally(MachineState_Stopping);
9975
9976 /*
9977 * Setup task object and thread to carry out the operation
9978 * asynchronously (if we call powerDown() right here but there
9979 * is one or more mpUVM callers (added with addVMCaller()) we'll
9980 * deadlock).
9981 */
9982 VMPowerDownTask *pTask = NULL;
9983 try
9984 {
9985 pTask = new VMPowerDownTask(that, pProgress);
9986 }
9987 catch (std::bad_alloc &)
9988 {
9989 LogRelFunc(("E_OUTOFMEMORY creating VMPowerDownTask"));
9990 hrc = E_OUTOFMEMORY;
9991 break;
9992 }
9993
9994 /*
9995 * If creating a task failed, this can currently mean one of
9996 * two: either Console::uninit() has been called just a ms
9997 * before (so a powerDown() call is already on the way), or
9998 * powerDown() itself is being already executed. Just do
9999 * nothing.
10000 */
10001 if (pTask->isOk())
10002 {
10003 hrc = pTask->createThread();
10004 pTask = NULL;
10005 if (FAILED(hrc))
10006 LogRelFunc(("Problem with creating thread for VMPowerDownTask.\n"));
10007 }
10008 else
10009 {
10010 LogFlowFunc(("Console is already being uninitialized. (%Rhrc)\n", pTask->hrc()));
10011 delete pTask;
10012 pTask = NULL;
10013 hrc = E_FAIL;
10014 }
10015 }
10016 break;
10017 }
10018
10019 /* The VM has been completely destroyed.
10020 *
10021 * Note: This state change can happen at two points:
10022 * 1) At the end of VMR3Destroy() if it was not called from EMT.
10023 * 2) At the end of vmR3EmulationThread if VMR3Destroy() was
10024 * called by EMT.
10025 */
10026 case VMSTATE_TERMINATED:
10027 {
10028 AutoWriteLock alock(that COMMA_LOCKVAL_SRC_POS);
10029
10030 if (that->mVMStateChangeCallbackDisabled)
10031 break;
10032
10033#ifdef VBOX_WITH_CLOUD_NET
10034 /*
10035 * We stop cloud gateway here because we may have failed to connect to it,
10036 * configure it, or establish a tunnel. We definitely do not want an orphaned
10037 * instance running in the cloud.
10038 */
10039 if (!that->mGateway.mGatewayInstanceId.isEmpty())
10040 {
10041 ComPtr<IVirtualBox> pVirtualBox;
10042 HRESULT hrc = that->mMachine->COMGETTER(Parent)(pVirtualBox.asOutParam());
10043 AssertComRC(hrc);
10044 if (SUCCEEDED(hrc) && !pVirtualBox.isNull())
10045 stopCloudGateway(pVirtualBox, that->mGateway);
10046 }
10047#endif /* VBOX_WITH_CLOUD_NET */
10048
10049 /* Terminate host interface networking. If pUVM is NULL, we've been
10050 * manually called from powerUpThread() either before calling
10051 * VMR3Create() or after VMR3Create() failed, so no need to touch
10052 * networking.
10053 */
10054 if (pUVM)
10055 that->i_powerDownHostInterfaces();
10056
10057 /* From now on the machine is officially powered down or remains in
10058 * the Saved state.
10059 */
10060 switch (that->mMachineState)
10061 {
10062 default:
10063 AssertFailed();
10064 RT_FALL_THRU();
10065 case MachineState_Stopping:
10066 /* successfully powered down */
10067 that->i_setMachineState(MachineState_PoweredOff);
10068 break;
10069 case MachineState_Saving:
10070 /* successfully saved */
10071 that->i_setMachineState(MachineState_Saved);
10072 break;
10073 case MachineState_Starting:
10074 /* failed to start, but be patient: set back to PoweredOff
10075 * (for similarity with the below) */
10076 that->i_setMachineState(MachineState_PoweredOff);
10077 break;
10078 case MachineState_Restoring:
10079 /* failed to load the saved state file, but be patient: set
10080 * to AbortedSaved (to preserve the saved state file) */
10081 that->i_setMachineState(MachineState_AbortedSaved);
10082 break;
10083 case MachineState_TeleportingIn:
10084 /* Teleportation failed or was canceled. Back to powered off. */
10085 that->i_setMachineState(MachineState_PoweredOff);
10086 break;
10087 case MachineState_TeleportingPausedVM:
10088 /* Successfully teleported the VM. */
10089 that->i_setMachineState(MachineState_Teleported);
10090 break;
10091 }
10092 break;
10093 }
10094
10095 case VMSTATE_RESETTING:
10096 /** @todo shouldn't VMSTATE_RESETTING_LS be here? */
10097 {
10098#ifdef VBOX_WITH_GUEST_PROPS
10099 /* Do not take any read/write locks here! */
10100 that->i_guestPropertiesHandleVMReset();
10101#endif
10102 break;
10103 }
10104
10105 case VMSTATE_SOFT_RESETTING:
10106 case VMSTATE_SOFT_RESETTING_LS:
10107 /* Shouldn't do anything here! */
10108 break;
10109
10110 case VMSTATE_SUSPENDED:
10111 {
10112 AutoWriteLock alock(that COMMA_LOCKVAL_SRC_POS);
10113
10114 if (that->mVMStateChangeCallbackDisabled)
10115 break;
10116
10117 switch (that->mMachineState)
10118 {
10119 case MachineState_Teleporting:
10120 that->i_setMachineState(MachineState_TeleportingPausedVM);
10121 break;
10122
10123 case MachineState_LiveSnapshotting:
10124 that->i_setMachineState(MachineState_OnlineSnapshotting);
10125 break;
10126
10127 case MachineState_TeleportingPausedVM:
10128 case MachineState_Saving:
10129 case MachineState_Restoring:
10130 case MachineState_Stopping:
10131 case MachineState_TeleportingIn:
10132 case MachineState_OnlineSnapshotting:
10133 /* The worker thread handles the transition. */
10134 break;
10135
10136 case MachineState_Running:
10137 that->i_setMachineState(MachineState_Paused);
10138 break;
10139
10140 case MachineState_Paused:
10141 /* Nothing to do. */
10142 break;
10143
10144 default:
10145 AssertMsgFailed(("%s\n", ::stringifyMachineState(that->mMachineState)));
10146 }
10147 break;
10148 }
10149
10150 case VMSTATE_SUSPENDED_LS:
10151 case VMSTATE_SUSPENDED_EXT_LS:
10152 {
10153 AutoWriteLock alock(that COMMA_LOCKVAL_SRC_POS);
10154 if (that->mVMStateChangeCallbackDisabled)
10155 break;
10156 switch (that->mMachineState)
10157 {
10158 case MachineState_Teleporting:
10159 that->i_setMachineState(MachineState_TeleportingPausedVM);
10160 break;
10161
10162 case MachineState_LiveSnapshotting:
10163 that->i_setMachineState(MachineState_OnlineSnapshotting);
10164 break;
10165
10166 case MachineState_TeleportingPausedVM:
10167 case MachineState_Saving:
10168 /* ignore */
10169 break;
10170
10171 default:
10172 AssertMsgFailed(("%s/%s -> %s\n", ::stringifyMachineState(that->mMachineState),
10173 pVMM->pfnVMR3GetStateName(enmOldState), pVMM->pfnVMR3GetStateName(enmState) ));
10174 that->i_setMachineState(MachineState_Paused);
10175 break;
10176 }
10177 break;
10178 }
10179
10180 case VMSTATE_RUNNING:
10181 {
10182 if ( enmOldState == VMSTATE_POWERING_ON
10183 || enmOldState == VMSTATE_RESUMING)
10184 {
10185 AutoWriteLock alock(that COMMA_LOCKVAL_SRC_POS);
10186
10187 if (that->mVMStateChangeCallbackDisabled)
10188 break;
10189
10190 Assert( ( ( that->mMachineState == MachineState_Starting
10191 || that->mMachineState == MachineState_Paused)
10192 && enmOldState == VMSTATE_POWERING_ON)
10193 || ( ( that->mMachineState == MachineState_Restoring
10194 || that->mMachineState == MachineState_TeleportingIn
10195 || that->mMachineState == MachineState_Paused
10196 || that->mMachineState == MachineState_Saving
10197 )
10198 && enmOldState == VMSTATE_RESUMING));
10199
10200 that->i_setMachineState(MachineState_Running);
10201 }
10202
10203 break;
10204 }
10205
10206 case VMSTATE_RUNNING_LS:
10207 AssertMsg( that->mMachineState == MachineState_LiveSnapshotting
10208 || that->mMachineState == MachineState_Teleporting,
10209 ("%s/%s -> %s\n", ::stringifyMachineState(that->mMachineState),
10210 pVMM->pfnVMR3GetStateName(enmOldState), pVMM->pfnVMR3GetStateName(enmState) ));
10211 break;
10212
10213 case VMSTATE_FATAL_ERROR:
10214 {
10215 AutoWriteLock alock(that COMMA_LOCKVAL_SRC_POS);
10216
10217 if (that->mVMStateChangeCallbackDisabled)
10218 break;
10219
10220 /* Fatal errors are only for running VMs. */
10221 Assert(Global::IsOnline(that->mMachineState));
10222
10223 /* Note! 'Pause' is used here in want of something better. There
10224 * are currently only two places where fatal errors might be
10225 * raised, so it is not worth adding a new externally
10226 * visible state for this yet. */
10227 that->i_setMachineState(MachineState_Paused);
10228 break;
10229 }
10230
10231 case VMSTATE_GURU_MEDITATION:
10232 {
10233 AutoWriteLock alock(that COMMA_LOCKVAL_SRC_POS);
10234
10235 if (that->mVMStateChangeCallbackDisabled)
10236 break;
10237
10238 /* Guru are only for running VMs */
10239 Assert(Global::IsOnline(that->mMachineState));
10240
10241 that->i_setMachineState(MachineState_Stuck);
10242 break;
10243 }
10244
10245 case VMSTATE_CREATED:
10246 {
10247 /*
10248 * We have to set the secret key helper interface for the VD drivers to
10249 * get notified about missing keys.
10250 */
10251 that->i_initSecretKeyIfOnAllAttachments();
10252 break;
10253 }
10254
10255 default: /* shut up gcc */
10256 break;
10257 }
10258}
10259
10260/**
10261 * Changes the clipboard mode.
10262 *
10263 * @returns VBox status code.
10264 * @param aClipboardMode new clipboard mode.
10265 */
10266int Console::i_changeClipboardMode(ClipboardMode_T aClipboardMode)
10267{
10268#ifdef VBOX_WITH_SHARED_CLIPBOARD
10269 VMMDev *pVMMDev = m_pVMMDev;
10270 AssertPtrReturn(pVMMDev, VERR_INVALID_POINTER);
10271
10272 VBOXHGCMSVCPARM parm;
10273 parm.type = VBOX_HGCM_SVC_PARM_32BIT;
10274
10275 switch (aClipboardMode)
10276 {
10277 default:
10278 case ClipboardMode_Disabled:
10279 LogRel(("Shared Clipboard: Mode: Off\n"));
10280 parm.u.uint32 = VBOX_SHCL_MODE_OFF;
10281 break;
10282 case ClipboardMode_GuestToHost:
10283 LogRel(("Shared Clipboard: Mode: Guest to Host\n"));
10284 parm.u.uint32 = VBOX_SHCL_MODE_GUEST_TO_HOST;
10285 break;
10286 case ClipboardMode_HostToGuest:
10287 LogRel(("Shared Clipboard: Mode: Host to Guest\n"));
10288 parm.u.uint32 = VBOX_SHCL_MODE_HOST_TO_GUEST;
10289 break;
10290 case ClipboardMode_Bidirectional:
10291 LogRel(("Shared Clipboard: Mode: Bidirectional\n"));
10292 parm.u.uint32 = VBOX_SHCL_MODE_BIDIRECTIONAL;
10293 break;
10294 }
10295
10296 int vrc = pVMMDev->hgcmHostCall("VBoxSharedClipboard", VBOX_SHCL_HOST_FN_SET_MODE, 1, &parm);
10297 if (RT_FAILURE(vrc))
10298 LogRel(("Shared Clipboard: Error changing mode: %Rrc\n", vrc));
10299
10300 return vrc;
10301#else
10302 RT_NOREF(aClipboardMode);
10303 return VERR_NOT_IMPLEMENTED;
10304#endif
10305}
10306
10307/**
10308 * Changes the clipboard file transfer mode.
10309 *
10310 * @returns VBox status code.
10311 * @param aEnabled Whether clipboard file transfers are enabled or not.
10312 */
10313int Console::i_changeClipboardFileTransferMode(bool aEnabled)
10314{
10315#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
10316 VMMDev *pVMMDev = m_pVMMDev;
10317 AssertPtrReturn(pVMMDev, VERR_INVALID_POINTER);
10318
10319 VBOXHGCMSVCPARM parm;
10320 RT_ZERO(parm);
10321
10322 parm.type = VBOX_HGCM_SVC_PARM_32BIT;
10323 parm.u.uint32 = aEnabled ? VBOX_SHCL_TRANSFER_MODE_F_ENABLED : VBOX_SHCL_TRANSFER_MODE_F_NONE;
10324
10325 int vrc = pVMMDev->hgcmHostCall("VBoxSharedClipboard", VBOX_SHCL_HOST_FN_SET_TRANSFER_MODE, 1 /* cParms */, &parm);
10326 if (RT_FAILURE(vrc))
10327 LogRel(("Shared Clipboard: Error changing file transfer mode: %Rrc\n", vrc));
10328
10329 return vrc;
10330#else
10331 RT_NOREF(aEnabled);
10332 return VERR_NOT_IMPLEMENTED;
10333#endif
10334}
10335
10336/**
10337 * Changes the drag and drop mode.
10338 *
10339 * @param aDnDMode new drag and drop mode.
10340 */
10341int Console::i_changeDnDMode(DnDMode_T aDnDMode)
10342{
10343 VMMDev *pVMMDev = m_pVMMDev;
10344 AssertPtrReturn(pVMMDev, VERR_INVALID_POINTER);
10345
10346 VBOXHGCMSVCPARM parm;
10347 RT_ZERO(parm);
10348 parm.type = VBOX_HGCM_SVC_PARM_32BIT;
10349
10350 switch (aDnDMode)
10351 {
10352 default:
10353 case DnDMode_Disabled:
10354 LogRel(("Drag and drop mode: Off\n"));
10355 parm.u.uint32 = VBOX_DRAG_AND_DROP_MODE_OFF;
10356 break;
10357 case DnDMode_GuestToHost:
10358 LogRel(("Drag and drop mode: Guest to Host\n"));
10359 parm.u.uint32 = VBOX_DRAG_AND_DROP_MODE_GUEST_TO_HOST;
10360 break;
10361 case DnDMode_HostToGuest:
10362 LogRel(("Drag and drop mode: Host to Guest\n"));
10363 parm.u.uint32 = VBOX_DRAG_AND_DROP_MODE_HOST_TO_GUEST;
10364 break;
10365 case DnDMode_Bidirectional:
10366 LogRel(("Drag and drop mode: Bidirectional\n"));
10367 parm.u.uint32 = VBOX_DRAG_AND_DROP_MODE_BIDIRECTIONAL;
10368 break;
10369 }
10370
10371 int vrc = pVMMDev->hgcmHostCall("VBoxDragAndDropSvc", DragAndDropSvc::HOST_DND_FN_SET_MODE, 1 /* cParms */, &parm);
10372 if (RT_FAILURE(vrc))
10373 LogRel(("Error changing drag and drop mode: %Rrc\n", vrc));
10374
10375 return vrc;
10376}
10377
10378#ifdef VBOX_WITH_USB
10379/**
10380 * @interface_method_impl{REMOTEUSBIF,pfnQueryRemoteUsbBackend}
10381 */
10382/*static*/ DECLCALLBACK(PREMOTEUSBCALLBACK)
10383Console::i_usbQueryRemoteUsbBackend(void *pvUser, PCRTUUID pUuid, uint32_t idClient)
10384{
10385 Console *pConsole = (Console *)pvUser;
10386
10387 AutoReadLock thatLock(pConsole COMMA_LOCKVAL_SRC_POS);
10388
10389 Guid const uuid(*pUuid);
10390 return (PREMOTEUSBCALLBACK)pConsole->i_consoleVRDPServer()->USBBackendRequestPointer(idClient, &uuid);
10391}
10392
10393
10394/**
10395 * Sends a request to VMM to attach the given host device.
10396 * After this method succeeds, the attached device will appear in the
10397 * mUSBDevices collection.
10398 *
10399 * @param aHostDevice device to attach
10400 *
10401 * @note Synchronously calls EMT.
10402 */
10403HRESULT Console::i_attachUSBDevice(IUSBDevice *aHostDevice, ULONG aMaskedIfs, const Utf8Str &aCaptureFilename)
10404{
10405 AssertReturn(aHostDevice, E_FAIL);
10406 AssertReturn(!isWriteLockOnCurrentThread(), E_FAIL);
10407
10408 HRESULT hrc;
10409
10410 /*
10411 * Get the address and the Uuid, and call the pfnCreateProxyDevice roothub
10412 * method in EMT (using usbAttachCallback()).
10413 */
10414 Bstr bstrAddress;
10415 hrc = aHostDevice->COMGETTER(Address)(bstrAddress.asOutParam());
10416 ComAssertComRCRetRC(hrc);
10417 Utf8Str const Address(bstrAddress);
10418
10419 Bstr id;
10420 hrc = aHostDevice->COMGETTER(Id)(id.asOutParam());
10421 ComAssertComRCRetRC(hrc);
10422 Guid const uuid(id);
10423
10424 BOOL fRemote = FALSE;
10425 hrc = aHostDevice->COMGETTER(Remote)(&fRemote);
10426 ComAssertComRCRetRC(hrc);
10427
10428 Bstr bstrBackend;
10429 hrc = aHostDevice->COMGETTER(Backend)(bstrBackend.asOutParam());
10430 ComAssertComRCRetRC(hrc);
10431 Utf8Str const strBackend(bstrBackend);
10432
10433 /* Get the VM handle. */
10434 SafeVMPtr ptrVM(this);
10435 if (!ptrVM.isOk())
10436 return ptrVM.hrc();
10437
10438 LogFlowThisFunc(("Proxying USB device '%s' {%RTuuid}...\n", Address.c_str(), uuid.raw()));
10439
10440 PCFGMNODE pRemoteCfg = NULL;
10441 if (fRemote)
10442 {
10443 RemoteUSBDevice *pRemoteUSBDevice = static_cast<RemoteUSBDevice *>(aHostDevice);
10444
10445 pRemoteCfg = mpVMM->pfnCFGMR3CreateTree(ptrVM.rawUVM());
10446 if (pRemoteCfg)
10447 {
10448 int vrc = mpVMM->pfnCFGMR3InsertInteger(pRemoteCfg, "ClientId", pRemoteUSBDevice->clientId());
10449 if (RT_FAILURE(vrc))
10450 {
10451 mpVMM->pfnCFGMR3DestroyTree(pRemoteCfg);
10452 return setErrorBoth(E_FAIL, vrc, tr("Failed to create configuration for USB device."));
10453 }
10454 }
10455 else
10456 return setErrorBoth(E_OUTOFMEMORY, VERR_NO_MEMORY, tr("Failed to allocate config tree for USB device."));
10457 }
10458
10459 USBConnectionSpeed_T enmSpeed;
10460 hrc = aHostDevice->COMGETTER(Speed)(&enmSpeed);
10461 AssertComRCReturnRC(hrc);
10462
10463 int vrc = ptrVM.vtable()->pfnVMR3ReqCallWaitU(ptrVM.rawUVM(), 0 /* idDstCpu (saved state, see #6232) */,
10464 (PFNRT)i_usbAttachCallback, 11 | VMREQ_F_EXTRA_ARGS_ALL_PTRS,
10465 this, ptrVM.rawUVM(), ptrVM.vtable(), aHostDevice, uuid.raw(),
10466 strBackend.c_str(), Address.c_str(), pRemoteCfg, /* extra arg (ptrs only): */
10467 &enmSpeed, &aMaskedIfs, aCaptureFilename.isEmpty()
10468 ? (const char *)NULL : aCaptureFilename.c_str());
10469 if (RT_SUCCESS(vrc))
10470 {
10471 /* Create a OUSBDevice and add it to the device list */
10472 ComObjPtr<OUSBDevice> pUSBDevice;
10473 pUSBDevice.createObject();
10474 hrc = pUSBDevice->init(aHostDevice);
10475 AssertComRC(hrc);
10476
10477 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
10478 mUSBDevices.push_back(pUSBDevice);
10479 LogFlowFunc(("Attached device {%RTuuid}\n", pUSBDevice->i_id().raw()));
10480
10481 /* notify callbacks */
10482 alock.release();
10483 i_onUSBDeviceStateChange(pUSBDevice, true /* aAttached */, NULL);
10484 }
10485 else
10486 {
10487 Log1WarningThisFunc(("Failed to create proxy device for '%s' {%RTuuid} (%Rrc)\n", Address.c_str(), uuid.raw(), vrc));
10488 switch (vrc)
10489 {
10490 case VERR_VUSB_NO_PORTS:
10491 hrc = setErrorBoth(E_FAIL, vrc, tr("Failed to attach the USB device. (No available ports on the USB controller)."));
10492 break;
10493 case VERR_VUSB_USBFS_PERMISSION:
10494 hrc = setErrorBoth(E_FAIL, vrc, tr("Not permitted to open the USB device, check usbfs options"));
10495 break;
10496 default:
10497 hrc = setErrorBoth(E_FAIL, vrc, tr("Failed to create a proxy device for the USB device. (Error: %Rrc)"), vrc);
10498 break;
10499 }
10500 }
10501
10502 return hrc;
10503}
10504
10505/**
10506 * USB device attach callback used by AttachUSBDevice().
10507 * Note that AttachUSBDevice() doesn't return until this callback is executed,
10508 * so we don't use AutoCaller and don't care about reference counters of
10509 * interface pointers passed in.
10510 *
10511 * @thread EMT
10512 * @note Locks the console object for writing.
10513 */
10514//static
10515DECLCALLBACK(int)
10516Console::i_usbAttachCallback(Console *that, PUVM pUVM, PCVMMR3VTABLE pVMM, IUSBDevice *aHostDevice, PCRTUUID aUuid,
10517 const char *pszBackend, const char *aAddress, PCFGMNODE pRemoteCfg,
10518 USBConnectionSpeed_T *penmSpeed, ULONG *pfMaskedIfs, const char *pszCaptureFilename)
10519{
10520 RT_NOREF(aHostDevice);
10521 LogFlowFuncEnter();
10522 LogFlowFunc(("that={%p} aUuid={%RTuuid}\n", that, aUuid));
10523
10524 AssertReturn(that && aUuid, VERR_INVALID_PARAMETER);
10525 AssertReturn(!that->isWriteLockOnCurrentThread(), VERR_GENERAL_FAILURE);
10526
10527 VUSBSPEED enmSpeed = VUSB_SPEED_UNKNOWN;
10528 switch (*penmSpeed)
10529 {
10530 case USBConnectionSpeed_Low: enmSpeed = VUSB_SPEED_LOW; break;
10531 case USBConnectionSpeed_Full: enmSpeed = VUSB_SPEED_FULL; break;
10532 case USBConnectionSpeed_High: enmSpeed = VUSB_SPEED_HIGH; break;
10533 case USBConnectionSpeed_Super: enmSpeed = VUSB_SPEED_SUPER; break;
10534 case USBConnectionSpeed_SuperPlus: enmSpeed = VUSB_SPEED_SUPERPLUS; break;
10535 default: AssertFailed(); break;
10536 }
10537
10538 int vrc = pVMM->pfnPDMR3UsbCreateProxyDevice(pUVM, aUuid, pszBackend, aAddress, pRemoteCfg,
10539 enmSpeed, *pfMaskedIfs, pszCaptureFilename);
10540 LogFlowFunc(("vrc=%Rrc\n", vrc));
10541 LogFlowFuncLeave();
10542 return vrc;
10543}
10544
10545/**
10546 * Sends a request to VMM to detach the given host device. After this method
10547 * succeeds, the detached device will disappear from the mUSBDevices
10548 * collection.
10549 *
10550 * @param aHostDevice device to attach
10551 *
10552 * @note Synchronously calls EMT.
10553 */
10554HRESULT Console::i_detachUSBDevice(const ComObjPtr<OUSBDevice> &aHostDevice)
10555{
10556 AssertReturn(!isWriteLockOnCurrentThread(), E_FAIL);
10557
10558 /* Get the VM handle. */
10559 SafeVMPtr ptrVM(this);
10560 if (!ptrVM.isOk())
10561 return ptrVM.hrc();
10562
10563 /* if the device is attached, then there must at least one USB hub. */
10564 AssertReturn(ptrVM.vtable()->pfnPDMR3UsbHasHub(ptrVM.rawUVM()), E_FAIL);
10565
10566 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
10567 LogFlowThisFunc(("Detaching USB proxy device {%RTuuid}...\n", aHostDevice->i_id().raw()));
10568
10569 /*
10570 * If this was a remote device, release the backend pointer.
10571 * The pointer was requested in usbAttachCallback.
10572 */
10573 BOOL fRemote = FALSE;
10574
10575 HRESULT hrc2 = aHostDevice->COMGETTER(Remote)(&fRemote);
10576 if (FAILED(hrc2))
10577 i_setErrorStatic(hrc2, "GetRemote() failed");
10578
10579 PCRTUUID pUuid = aHostDevice->i_id().raw();
10580 if (fRemote)
10581 {
10582 Guid guid(*pUuid);
10583 i_consoleVRDPServer()->USBBackendReleasePointer(&guid);
10584 }
10585
10586 alock.release();
10587 int vrc = ptrVM.vtable()->pfnVMR3ReqCallWaitU(ptrVM.rawUVM(), 0 /* idDstCpu (saved state, see #6232) */,
10588 (PFNRT)i_usbDetachCallback, 4, this, ptrVM.rawUVM(), ptrVM.vtable(), pUuid);
10589 if (RT_SUCCESS(vrc))
10590 {
10591 LogFlowFunc(("Detached device {%RTuuid}\n", pUuid));
10592
10593 /* notify callbacks */
10594 i_onUSBDeviceStateChange(aHostDevice, false /* aAttached */, NULL);
10595 }
10596
10597 ComAssertRCRet(vrc, E_FAIL);
10598
10599 return S_OK;
10600}
10601
10602/**
10603 * USB device detach callback used by DetachUSBDevice().
10604 *
10605 * Note that DetachUSBDevice() doesn't return until this callback is executed,
10606 * so we don't use AutoCaller and don't care about reference counters of
10607 * interface pointers passed in.
10608 *
10609 * @thread EMT
10610 */
10611//static
10612DECLCALLBACK(int)
10613Console::i_usbDetachCallback(Console *that, PUVM pUVM, PCVMMR3VTABLE pVMM, PCRTUUID aUuid)
10614{
10615 LogFlowFuncEnter();
10616 LogFlowFunc(("that={%p} aUuid={%RTuuid}\n", that, aUuid));
10617
10618 AssertReturn(that && aUuid, VERR_INVALID_PARAMETER);
10619 AssertReturn(!that->isWriteLockOnCurrentThread(), VERR_GENERAL_FAILURE);
10620
10621 int vrc = pVMM->pfnPDMR3UsbDetachDevice(pUVM, aUuid);
10622
10623 LogFlowFunc(("vrc=%Rrc\n", vrc));
10624 LogFlowFuncLeave();
10625 return vrc;
10626}
10627#endif /* VBOX_WITH_USB */
10628
10629/* Note: FreeBSD needs this whether netflt is used or not. */
10630#if ((defined(RT_OS_LINUX) && !defined(VBOX_WITH_NETFLT)) || defined(RT_OS_FREEBSD))
10631
10632/**
10633 * Helper function to handle host interface device creation and attachment.
10634 *
10635 * @param networkAdapter the network adapter which attachment should be reset
10636 * @return COM status code
10637 *
10638 * @note The caller must lock this object for writing.
10639 *
10640 * @todo Move this back into the driver!
10641 */
10642HRESULT Console::i_attachToTapInterface(INetworkAdapter *networkAdapter)
10643{
10644 LogFlowThisFunc(("\n"));
10645 /* sanity check */
10646 AssertReturn(isWriteLockOnCurrentThread(), E_FAIL);
10647
10648# ifdef VBOX_STRICT
10649 /* paranoia */
10650 NetworkAttachmentType_T attachment;
10651 networkAdapter->COMGETTER(AttachmentType)(&attachment);
10652 Assert(attachment == NetworkAttachmentType_Bridged);
10653# endif /* VBOX_STRICT */
10654
10655 ULONG slot = 0;
10656 HRESULT hrc = networkAdapter->COMGETTER(Slot)(&slot);
10657 AssertComRCReturnRC(hrc);
10658
10659# ifdef RT_OS_LINUX
10660 /*
10661 * Allocate a host interface device
10662 */
10663 int vrc = RTFileOpen(&maTapFD[slot], "/dev/net/tun",
10664 RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_NONE | RTFILE_O_INHERIT);
10665 if (RT_SUCCESS(vrc))
10666 {
10667 /*
10668 * Set/obtain the tap interface.
10669 */
10670 struct ifreq IfReq;
10671 RT_ZERO(IfReq);
10672 /* The name of the TAP interface we are using */
10673 Bstr tapDeviceName;
10674 hrc = networkAdapter->COMGETTER(BridgedInterface)(tapDeviceName.asOutParam());
10675 if (FAILED(hrc))
10676 tapDeviceName.setNull(); /* Is this necessary? */
10677 if (tapDeviceName.isEmpty())
10678 {
10679 LogRel(("No TAP device name was supplied.\n"));
10680 hrc = setError(E_FAIL, tr("No TAP device name was supplied for the host networking interface"));
10681 }
10682
10683 if (SUCCEEDED(hrc))
10684 {
10685 /* If we are using a static TAP device then try to open it. */
10686 Utf8Str str(tapDeviceName);
10687 RTStrCopy(IfReq.ifr_name, sizeof(IfReq.ifr_name), str.c_str()); /** @todo bitch about names which are too long... */
10688 IfReq.ifr_flags = IFF_TAP | IFF_NO_PI;
10689 vrc = ioctl(RTFileToNative(maTapFD[slot]), TUNSETIFF, &IfReq);
10690 if (vrc != 0)
10691 {
10692 LogRel(("Failed to open the host network interface %ls\n", tapDeviceName.raw()));
10693 hrc = setErrorBoth(E_FAIL, vrc, tr("Failed to open the host network interface %ls"), tapDeviceName.raw());
10694 }
10695 }
10696 if (SUCCEEDED(hrc))
10697 {
10698 /*
10699 * Make it pollable.
10700 */
10701 if (fcntl(RTFileToNative(maTapFD[slot]), F_SETFL, O_NONBLOCK) != -1)
10702 {
10703 Log(("i_attachToTapInterface: %RTfile %ls\n", maTapFD[slot], tapDeviceName.raw()));
10704 /*
10705 * Here is the right place to communicate the TAP file descriptor and
10706 * the host interface name to the server if/when it becomes really
10707 * necessary.
10708 */
10709 maTAPDeviceName[slot] = tapDeviceName;
10710 vrc = VINF_SUCCESS;
10711 }
10712 else
10713 {
10714 int iErr = errno;
10715
10716 LogRel(("Configuration error: Failed to configure /dev/net/tun non blocking. Error: %s\n", strerror(iErr)));
10717 vrc = VERR_HOSTIF_BLOCKING;
10718 hrc = setErrorBoth(E_FAIL, vrc, tr("could not set up the host networking device for non blocking access: %s"),
10719 strerror(errno));
10720 }
10721 }
10722 }
10723 else
10724 {
10725 LogRel(("Configuration error: Failed to open /dev/net/tun vrc=%Rrc\n", vrc));
10726 switch (vrc)
10727 {
10728 case VERR_ACCESS_DENIED:
10729 /* will be handled by our caller */
10730 hrc = E_ACCESSDENIED;
10731 break;
10732 default:
10733 hrc = setErrorBoth(E_FAIL, vrc, tr("Could not set up the host networking device: %Rrc"), vrc);
10734 break;
10735 }
10736 }
10737
10738# elif defined(RT_OS_FREEBSD)
10739 /*
10740 * Set/obtain the tap interface.
10741 */
10742 /* The name of the TAP interface we are using */
10743 Bstr tapDeviceName;
10744 hrc = networkAdapter->COMGETTER(BridgedInterface)(tapDeviceName.asOutParam());
10745 if (FAILED(hrc))
10746 tapDeviceName.setNull(); /* Is this necessary? */
10747 if (tapDeviceName.isEmpty())
10748 {
10749 LogRel(("No TAP device name was supplied.\n"));
10750 hrc = setError(E_FAIL, tr("No TAP device name was supplied for the host networking interface"));
10751 }
10752 char szTapdev[1024] = "/dev/";
10753 /* If we are using a static TAP device then try to open it. */
10754 Utf8Str str(tapDeviceName);
10755 if (str.length() + strlen(szTapdev) <= sizeof(szTapdev))
10756 strcat(szTapdev, str.c_str());
10757 else
10758 memcpy(szTapdev + strlen(szTapdev), str.c_str(),
10759 sizeof(szTapdev) - strlen(szTapdev) - 1); /** @todo bitch about names which are too long... */
10760 int vrc = RTFileOpen(&maTapFD[slot], szTapdev,
10761 RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_NONE | RTFILE_O_INHERIT | RTFILE_O_NON_BLOCK);
10762
10763 if (RT_SUCCESS(vrc))
10764 maTAPDeviceName[slot] = tapDeviceName;
10765 else
10766 {
10767 switch (vrc)
10768 {
10769 case VERR_ACCESS_DENIED:
10770 /* will be handled by our caller */
10771 hrc = E_ACCESSDENIED;
10772 break;
10773 default:
10774 hrc = setErrorBoth(E_FAIL, vrc, tr("Failed to open the host network interface %ls"), tapDeviceName.raw());
10775 break;
10776 }
10777 }
10778# else
10779# error "huh?"
10780# endif
10781 /* in case of failure, cleanup. */
10782 if (RT_FAILURE(vrc) && SUCCEEDED(hrc))
10783 {
10784 LogRel(("General failure attaching to host interface\n"));
10785 hrc = setErrorBoth(E_FAIL, vrc, tr("General failure attaching to host interface"));
10786 }
10787 LogFlowThisFunc(("hrc=%Rhrc\n", hrc));
10788 return hrc;
10789}
10790
10791
10792/**
10793 * Helper function to handle detachment from a host interface
10794 *
10795 * @param networkAdapter the network adapter which attachment should be reset
10796 * @return COM status code
10797 *
10798 * @note The caller must lock this object for writing.
10799 *
10800 * @todo Move this back into the driver!
10801 */
10802HRESULT Console::i_detachFromTapInterface(INetworkAdapter *networkAdapter)
10803{
10804 /* sanity check */
10805 LogFlowThisFunc(("\n"));
10806 AssertReturn(isWriteLockOnCurrentThread(), E_FAIL);
10807
10808# ifdef VBOX_STRICT
10809 /* paranoia */
10810 NetworkAttachmentType_T attachment;
10811 networkAdapter->COMGETTER(AttachmentType)(&attachment);
10812 Assert(attachment == NetworkAttachmentType_Bridged);
10813# endif /* VBOX_STRICT */
10814
10815 ULONG slot = 0;
10816 HRESULT hrc = networkAdapter->COMGETTER(Slot)(&slot);
10817 AssertComRCReturnRC(hrc);
10818
10819 /* is there an open TAP device? */
10820 if (maTapFD[slot] != NIL_RTFILE)
10821 {
10822 /*
10823 * Close the file handle.
10824 */
10825 Bstr tapDeviceName, tapTerminateApplication;
10826 bool isStatic = true;
10827 hrc = networkAdapter->COMGETTER(BridgedInterface)(tapDeviceName.asOutParam());
10828 if (FAILED(hrc) || tapDeviceName.isEmpty())
10829 {
10830 /* If the name is empty, this is a dynamic TAP device, so close it now,
10831 so that the termination script can remove the interface. Otherwise we still
10832 need the FD to pass to the termination script. */
10833 isStatic = false;
10834 int vrc = RTFileClose(maTapFD[slot]);
10835 AssertRC(vrc);
10836 maTapFD[slot] = NIL_RTFILE;
10837 }
10838 if (isStatic)
10839 {
10840 /* If we are using a static TAP device, we close it now, after having called the
10841 termination script. */
10842 int vrc = RTFileClose(maTapFD[slot]);
10843 AssertRC(vrc);
10844 }
10845 /* the TAP device name and handle are no longer valid */
10846 maTapFD[slot] = NIL_RTFILE;
10847 maTAPDeviceName[slot] = "";
10848 }
10849 LogFlowThisFunc(("returning %Rhrc\n", hrc));
10850 return hrc;
10851}
10852
10853#endif /* (RT_OS_LINUX || RT_OS_FREEBSD) && !VBOX_WITH_NETFLT */
10854
10855/**
10856 * Called at power down to terminate host interface networking.
10857 *
10858 * @note The caller must lock this object for writing.
10859 */
10860HRESULT Console::i_powerDownHostInterfaces()
10861{
10862 LogFlowThisFunc(("\n"));
10863
10864 /* sanity check */
10865 AssertReturn(isWriteLockOnCurrentThread(), E_FAIL);
10866
10867#if (defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)) && !defined(VBOX_WITH_NETFLT)
10868 /*
10869 * Host TAP interface termination handling.
10870 */
10871 ComPtr<IVirtualBox> pVirtualBox;
10872 mMachine->COMGETTER(Parent)(pVirtualBox.asOutParam());
10873
10874 ComPtr<IPlatform> pPlatform;
10875 HRESULT hrc = mMachine->COMGETTER(Platform)(pPlatform.asOutParam());
10876 AssertComRC(hrc);
10877
10878 PlatformArchitecture_T platformArch;
10879 hrc = pPlatform->COMGETTER(Architecture)(&platformArch);
10880 AssertComRC(hrc);
10881
10882 ComPtr<IPlatformProperties> pPlatformProperties;
10883 hrc = pVirtualBox->GetPlatformProperties(platformArch, pPlatformProperties.asOutParam());
10884 AssertComRC(hrc);
10885
10886 ChipsetType_T chipsetType = ChipsetType_PIIX3;
10887 pPlatform->COMGETTER(ChipsetType)(&chipsetType);
10888 AssertComRC(hrc);
10889
10890 ULONG maxNetworkAdapters = 0;
10891 hrc = pPlatformProperties->GetMaxNetworkAdapters(chipsetType, &maxNetworkAdapters);
10892 AssertComRC(hrc);
10893
10894 for (ULONG slot = 0; slot < maxNetworkAdapters; slot++)
10895 {
10896 ComPtr<INetworkAdapter> pNetworkAdapter;
10897 hrc = mMachine->GetNetworkAdapter(slot, pNetworkAdapter.asOutParam());
10898 if (FAILED(hrc)) break;
10899
10900 BOOL enabled = FALSE;
10901 pNetworkAdapter->COMGETTER(Enabled)(&enabled);
10902 if (!enabled)
10903 continue;
10904
10905 NetworkAttachmentType_T attachment;
10906 pNetworkAdapter->COMGETTER(AttachmentType)(&attachment);
10907 if (attachment == NetworkAttachmentType_Bridged)
10908 {
10909 HRESULT hrc2 = i_detachFromTapInterface(pNetworkAdapter);
10910 if (FAILED(hrc2) && SUCCEEDED(hrc))
10911 hrc = hrc2;
10912 }
10913 }
10914
10915 return hrc;
10916
10917#else
10918 /* Nothing to do here. */
10919 return S_OK;
10920#endif
10921}
10922
10923
10924/**
10925 * Process callback handler for VMR3LoadFromFile, VMR3LoadFromStream, VMR3Save
10926 * and VMR3Teleport.
10927 *
10928 * @param pUVM The user mode VM handle.
10929 * @param uPercent Completion percentage (0-100).
10930 * @param pvUser Pointer to an IProgress instance.
10931 * @return VINF_SUCCESS.
10932 */
10933/*static*/
10934DECLCALLBACK(int) Console::i_stateProgressCallback(PUVM pUVM, unsigned uPercent, void *pvUser)
10935{
10936 IProgress *pProgress = static_cast<IProgress *>(pvUser);
10937
10938 /* update the progress object */
10939 if (pProgress)
10940 {
10941 ComPtr<IInternalProgressControl> pProgressControl(pProgress);
10942 AssertReturn(!!pProgressControl, VERR_INVALID_PARAMETER);
10943 pProgressControl->SetCurrentOperationProgress(uPercent);
10944 }
10945
10946 NOREF(pUVM);
10947 return VINF_SUCCESS;
10948}
10949
10950/**
10951 * @copydoc FNVMATERROR
10952 *
10953 * @remarks Might be some tiny serialization concerns with access to the string
10954 * object here...
10955 */
10956/*static*/ DECLCALLBACK(void)
10957Console::i_genericVMSetErrorCallback(PUVM pUVM, void *pvUser, int vrc, RT_SRC_POS_DECL, const char *pszFormat, va_list args)
10958{
10959 RT_SRC_POS_NOREF();
10960 Utf8Str *pErrorText = (Utf8Str *)pvUser;
10961 AssertPtr(pErrorText);
10962
10963 /* We ignore RT_SRC_POS_DECL arguments to avoid confusion of end-users. */
10964 va_list va2;
10965 va_copy(va2, args);
10966
10967 /* Append to any the existing error message. */
10968 try
10969 {
10970 if (pErrorText->length())
10971 pErrorText->appendPrintf(".\n%N (%Rrc)", pszFormat, &va2, vrc, vrc);
10972 else
10973 pErrorText->printf("%N (%Rrc)", pszFormat, &va2, vrc, vrc);
10974 }
10975 catch (std::bad_alloc &)
10976 {
10977 }
10978
10979 va_end(va2);
10980
10981 NOREF(pUVM);
10982}
10983
10984/**
10985 * VM runtime error callback function (FNVMATRUNTIMEERROR).
10986 *
10987 * See VMSetRuntimeError for the detailed description of parameters.
10988 *
10989 * @param pUVM The user mode VM handle. Ignored, so passing NULL
10990 * is fine.
10991 * @param pvUser The user argument, pointer to the Console instance.
10992 * @param fFlags The action flags. See VMSETRTERR_FLAGS_*.
10993 * @param pszErrorId Error ID string.
10994 * @param pszFormat Error message format string.
10995 * @param va Error message arguments.
10996 * @thread EMT.
10997 */
10998/* static */ DECLCALLBACK(void)
10999Console::i_atVMRuntimeErrorCallback(PUVM pUVM, void *pvUser, uint32_t fFlags,
11000 const char *pszErrorId, const char *pszFormat, va_list va)
11001{
11002 bool const fFatal = !!(fFlags & VMSETRTERR_FLAGS_FATAL);
11003 LogFlowFuncEnter();
11004
11005 Console *that = static_cast<Console *>(pvUser);
11006 AssertReturnVoid(that);
11007
11008 Utf8Str message(pszFormat, va);
11009
11010 LogRel(("Console: VM runtime error: fatal=%RTbool, errorID=%s message=\"%s\"\n", fFatal, pszErrorId, message.c_str()));
11011 try
11012 {
11013 that->i_onRuntimeError(BOOL(fFatal), Bstr(pszErrorId).raw(), Bstr(message).raw());
11014 }
11015 catch (std::bad_alloc &)
11016 {
11017 }
11018 LogFlowFuncLeave(); NOREF(pUVM);
11019}
11020
11021/**
11022 * Captures USB devices that match filters of the VM.
11023 * Called at VM startup.
11024 *
11025 * @param pUVM The VM handle.
11026 */
11027HRESULT Console::i_captureUSBDevices(PUVM pUVM)
11028{
11029 RT_NOREF(pUVM);
11030 LogFlowThisFunc(("\n"));
11031
11032 /* sanity check */
11033 AssertReturn(!isWriteLockOnCurrentThread(), E_FAIL);
11034 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
11035
11036 /* If the machine has a USB controller, ask the USB proxy service to
11037 * capture devices */
11038 if (mfVMHasUsbController)
11039 {
11040 /* release the lock before calling Host in VBoxSVC since Host may call
11041 * us back from under its lock (e.g. onUSBDeviceAttach()) which would
11042 * produce an inter-process dead-lock otherwise. */
11043 alock.release();
11044
11045 HRESULT hrc = mControl->AutoCaptureUSBDevices();
11046 ComAssertComRCRetRC(hrc);
11047 }
11048
11049 return S_OK;
11050}
11051
11052
11053/**
11054 * Detach all USB device which are attached to the VM for the
11055 * purpose of clean up and such like.
11056 */
11057void Console::i_detachAllUSBDevices(bool aDone)
11058{
11059 LogFlowThisFunc(("aDone=%RTbool\n", aDone));
11060
11061 /* sanity check */
11062 AssertReturnVoid(!isWriteLockOnCurrentThread());
11063 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
11064
11065 mUSBDevices.clear();
11066
11067 /* release the lock before calling Host in VBoxSVC since Host may call
11068 * us back from under its lock (e.g. onUSBDeviceAttach()) which would
11069 * produce an inter-process dead-lock otherwise. */
11070 alock.release();
11071
11072 mControl->DetachAllUSBDevices(aDone);
11073}
11074
11075/* Make sure that the string is null-terminated and its size is less than cchMax bytes.
11076 * Replace invalid UTF8 bytes with '?'.
11077 */
11078static int validateUtf8String(char *psz, size_t cchMax)
11079{
11080 for (;;)
11081 {
11082 RTUNICP Cp;
11083 int vrc = RTStrGetCpNEx((const char **)&psz, &cchMax, &Cp);
11084 if (RT_SUCCESS(vrc))
11085 {
11086 if (!Cp)
11087 break;
11088 }
11089 else
11090 {
11091 if (!cchMax)
11092 return VERR_END_OF_STRING;
11093
11094 psz[-1] = '?';
11095 }
11096 }
11097 return VINF_SUCCESS;
11098}
11099
11100static int validateRemoteUSBDeviceDesc(VRDEUSBDEVICEDESC const *e, uint32_t cbRemaining, bool fDescExt)
11101{
11102 uint32_t const cbDesc = fDescExt ? sizeof(VRDEUSBDEVICEDESCEXT) : sizeof(VRDEUSBDEVICEDESC);
11103 if (cbDesc > cbRemaining)
11104 return VERR_INVALID_PARAMETER;
11105
11106 if ( e->oNext > cbRemaining /* It is OK for oNext to point to the end of buffer. */
11107 || e->oManufacturer >= cbRemaining
11108 || e->oProduct >= cbRemaining
11109 || e->oSerialNumber >= cbRemaining)
11110 return VERR_INVALID_PARAMETER;
11111
11112 int vrc;
11113 if (e->oManufacturer)
11114 {
11115 vrc = validateUtf8String((char *)e + e->oManufacturer, cbRemaining - e->oManufacturer);
11116 if (RT_FAILURE(vrc))
11117 return VERR_INVALID_PARAMETER;
11118 }
11119 if (e->oProduct)
11120 {
11121 vrc = validateUtf8String((char *)e + e->oProduct, cbRemaining - e->oProduct);
11122 if (RT_FAILURE(vrc))
11123 return VERR_INVALID_PARAMETER;
11124 }
11125 if (e->oSerialNumber)
11126 {
11127 vrc = validateUtf8String((char *)e + e->oSerialNumber, cbRemaining - e->oSerialNumber);
11128 if (RT_FAILURE(vrc))
11129 return VERR_INVALID_PARAMETER;
11130 }
11131
11132 return VINF_SUCCESS;
11133}
11134
11135/**
11136 * @note Locks this object for writing.
11137 */
11138void Console::i_processRemoteUSBDevices(uint32_t u32ClientId, VRDEUSBDEVICEDESC *pDevList, uint32_t cbDevList, bool fDescExt)
11139{
11140 LogFlowThisFuncEnter();
11141 LogFlowThisFunc(("u32ClientId = %d, pDevList=%p, cbDevList = %d, fDescExt = %d\n",
11142 u32ClientId, pDevList, cbDevList, fDescExt));
11143
11144 AutoCaller autoCaller(this);
11145 if (!autoCaller.isOk())
11146 {
11147 /* Console has been already uninitialized, deny request */
11148 AssertMsgFailed(("Console is already uninitialized\n"));
11149 LogFlowThisFunc(("Console is already uninitialized\n"));
11150 LogFlowThisFuncLeave();
11151 return;
11152 }
11153
11154 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
11155
11156 /*
11157 * Mark all existing remote USB devices as dirty.
11158 */
11159 for (RemoteUSBDeviceList::iterator it = mRemoteUSBDevices.begin();
11160 it != mRemoteUSBDevices.end();
11161 ++it)
11162 {
11163 (*it)->dirty(true);
11164 }
11165
11166 /*
11167 * Process the pDevList and add devices those are not already in the mRemoteUSBDevices list.
11168 */
11169 VRDEUSBDEVICEDESC *e = pDevList;
11170 uint32_t cbRemaining = cbDevList;
11171
11172 /* The cbRemaining condition must be checked first, because the function can
11173 * receive pDevList = NULL and cbDevList = 0 on client disconnect.
11174 */
11175 while (cbRemaining >= sizeof(e->oNext) && e->oNext)
11176 {
11177 int const vrc = validateRemoteUSBDeviceDesc(e, cbRemaining, fDescExt);
11178 if (RT_FAILURE(vrc))
11179 break; /* Consider the rest of the list invalid too. */
11180
11181 LogFlowThisFunc(("vendor %04x, product %04x, name = %s\n",
11182 e->idVendor, e->idProduct, e->oProduct ? (char *)e + e->oProduct : ""));
11183
11184 bool fNewDevice = true;
11185
11186 for (RemoteUSBDeviceList::iterator it = mRemoteUSBDevices.begin();
11187 it != mRemoteUSBDevices.end();
11188 ++it)
11189 {
11190 if ( (*it)->devId() == e->id
11191 && (*it)->clientId() == u32ClientId)
11192 {
11193 /* The device is already in the list. */
11194 (*it)->dirty(false);
11195 fNewDevice = false;
11196 break;
11197 }
11198 }
11199
11200 if (fNewDevice)
11201 {
11202 LogRel(("Remote USB: ++++ Vendor %04X. Product %04X. Name = [%s].\n",
11203 e->idVendor, e->idProduct, e->oProduct? (char *)e + e->oProduct: ""));
11204
11205 /* Create the device object and add the new device to list. */
11206 ComObjPtr<RemoteUSBDevice> pUSBDevice;
11207 pUSBDevice.createObject();
11208 pUSBDevice->init(u32ClientId, e, fDescExt);
11209
11210 mRemoteUSBDevices.push_back(pUSBDevice);
11211
11212 /* Check if the device is ok for current USB filters. */
11213 BOOL fMatched = FALSE;
11214 ULONG fMaskedIfs = 0;
11215 HRESULT hrc = mControl->RunUSBDeviceFilters(pUSBDevice, &fMatched, &fMaskedIfs);
11216
11217 AssertComRC(hrc);
11218
11219 LogFlowThisFunc(("USB filters return %d %#x\n", fMatched, fMaskedIfs));
11220
11221 if (fMatched)
11222 {
11223 alock.release();
11224 hrc = i_onUSBDeviceAttach(pUSBDevice, NULL, fMaskedIfs, Utf8Str());
11225 alock.acquire();
11226
11227 /// @todo (r=dmik) warning reporting subsystem
11228
11229 if (hrc == S_OK)
11230 {
11231 LogFlowThisFunc(("Device attached\n"));
11232 pUSBDevice->captured(true);
11233 }
11234 }
11235 }
11236
11237 AssertBreak(cbRemaining >= e->oNext); /* validateRemoteUSBDeviceDesc ensures this. */
11238 cbRemaining -= e->oNext;
11239
11240 e = (VRDEUSBDEVICEDESC *)((uint8_t *)e + e->oNext);
11241 }
11242
11243 /*
11244 * Remove dirty devices, that is those which are not reported by the server anymore.
11245 */
11246 for (;;)
11247 {
11248 ComObjPtr<RemoteUSBDevice> pUSBDevice;
11249
11250 RemoteUSBDeviceList::iterator it = mRemoteUSBDevices.begin();
11251 while (it != mRemoteUSBDevices.end())
11252 {
11253 if ((*it)->dirty())
11254 {
11255 pUSBDevice = *it;
11256 break;
11257 }
11258
11259 ++it;
11260 }
11261
11262 if (!pUSBDevice)
11263 {
11264 break;
11265 }
11266
11267 USHORT vendorId = 0;
11268 pUSBDevice->COMGETTER(VendorId)(&vendorId);
11269
11270 USHORT productId = 0;
11271 pUSBDevice->COMGETTER(ProductId)(&productId);
11272
11273 Bstr product;
11274 pUSBDevice->COMGETTER(Product)(product.asOutParam());
11275
11276 LogRel(("Remote USB: ---- Vendor %04x. Product %04x. Name = [%ls].\n", vendorId, productId, product.raw()));
11277
11278 /* Detach the device from VM. */
11279 if (pUSBDevice->captured())
11280 {
11281 Bstr uuid;
11282 pUSBDevice->COMGETTER(Id)(uuid.asOutParam());
11283 alock.release();
11284 i_onUSBDeviceDetach(uuid.raw(), NULL);
11285 alock.acquire();
11286 }
11287
11288 /* And remove it from the list. */
11289 mRemoteUSBDevices.erase(it);
11290 }
11291
11292 LogFlowThisFuncLeave();
11293}
11294
11295
11296/**
11297 * Worker called by VMPowerUpTask::handler to start the VM (also from saved
11298 * state) and track progress.
11299 *
11300 * @param pTask The power up task.
11301 *
11302 * @note Locks the Console object for writing.
11303 */
11304/*static*/
11305void Console::i_powerUpThreadTask(VMPowerUpTask *pTask)
11306{
11307 LogFlowFuncEnter();
11308
11309 AssertReturnVoid(pTask);
11310 AssertReturnVoid(!pTask->mConsole.isNull());
11311 AssertReturnVoid(!pTask->mProgress.isNull());
11312
11313 VirtualBoxBase::initializeComForThread();
11314
11315 HRESULT hrc = S_OK;
11316 int vrc = VINF_SUCCESS;
11317
11318 /* Set up a build identifier so that it can be seen from core dumps what
11319 * exact build was used to produce the core. */
11320 static char s_szBuildID[48];
11321 RTStrPrintf(s_szBuildID, sizeof(s_szBuildID), "%s%s%s%s VirtualBox %s r%u %s%s%s%s",
11322 "BU", "IL", "DI", "D", RTBldCfgVersion(), RTBldCfgRevision(), "BU", "IL", "DI", "D");
11323
11324 ComObjPtr<Console> pConsole = pTask->mConsole;
11325
11326 /* Note: no need to use AutoCaller because VMPowerUpTask does that */
11327
11328 /* The lock is also used as a signal from the task initiator (which
11329 * releases it only after RTThreadCreate()) that we can start the job */
11330 AutoWriteLock alock(pConsole COMMA_LOCKVAL_SRC_POS);
11331
11332 /* sanity */
11333 Assert(pConsole->mpUVM == NULL);
11334
11335 try
11336 {
11337 // Create the VMM device object, which starts the HGCM thread; do this only
11338 // once for the console, for the pathological case that the same console
11339 // object is used to power up a VM twice.
11340 if (!pConsole->m_pVMMDev)
11341 {
11342 pConsole->m_pVMMDev = new VMMDev(pConsole);
11343 AssertReturnVoid(pConsole->m_pVMMDev);
11344 }
11345
11346 /* wait for auto reset ops to complete so that we can successfully lock
11347 * the attached hard disks by calling LockMedia() below */
11348 for (VMPowerUpTask::ProgressList::const_iterator
11349 it = pTask->hardDiskProgresses.begin();
11350 it != pTask->hardDiskProgresses.end(); ++it)
11351 {
11352 HRESULT hrc2 = (*it)->WaitForCompletion(-1);
11353 AssertComRC(hrc2);
11354
11355 hrc = pTask->mProgress->SetNextOperation(BstrFmt(tr("Disk Image Reset Operation - Immutable Image")).raw(), 1);
11356 AssertComRCReturnVoid(hrc);
11357 }
11358
11359 /*
11360 * Lock attached media. This method will also check their accessibility.
11361 * If we're a teleporter, we'll have to postpone this action so we can
11362 * migrate between local processes.
11363 *
11364 * Note! The media will be unlocked automatically by
11365 * SessionMachine::i_setMachineState() when the VM is powered down.
11366 */
11367 if (!pTask->mTeleporterEnabled)
11368 {
11369 hrc = pConsole->mControl->LockMedia();
11370 if (FAILED(hrc)) throw hrc;
11371 }
11372
11373 /* Create the VRDP server. In case of headless operation, this will
11374 * also create the framebuffer, required at VM creation.
11375 */
11376 ConsoleVRDPServer *server = pConsole->i_consoleVRDPServer();
11377 Assert(server);
11378
11379 /* Does VRDP server call Console from the other thread?
11380 * Not sure (and can change), so release the lock just in case.
11381 */
11382 alock.release();
11383 vrc = server->Launch();
11384 alock.acquire();
11385
11386 if (vrc != VINF_SUCCESS)
11387 {
11388 Utf8Str errMsg = pConsole->VRDPServerErrorToMsg(vrc);
11389 if ( RT_FAILURE(vrc)
11390 && vrc != VERR_NET_ADDRESS_IN_USE) /* not fatal */
11391 throw i_setErrorStaticBoth(E_FAIL, vrc, errMsg.c_str());
11392 }
11393
11394 ComPtr<IMachine> pMachine = pConsole->i_machine();
11395 ULONG cCpus = 1;
11396 pMachine->COMGETTER(CPUCount)(&cCpus);
11397
11398 VMProcPriority_T enmVMPriority = VMProcPriority_Default;
11399 pMachine->COMGETTER(VMProcessPriority)(&enmVMPriority);
11400
11401 VMExecutionEngine_T enmExecEngine = VMExecutionEngine_NotSet;
11402 pMachine->COMGETTER(VMExecutionEngine)(&enmExecEngine);
11403
11404 /*
11405 * Create the VM
11406 *
11407 * Note! Release the lock since EMT will call Console. It's safe because
11408 * mMachineState is either Starting or Restoring state here.
11409 */
11410 alock.release();
11411
11412 if (enmVMPriority != VMProcPriority_Default)
11413 pConsole->i_onVMProcessPriorityChange(enmVMPriority);
11414
11415 PCVMMR3VTABLE pVMM = pConsole->mpVMM;
11416 PVM pVM = NULL;
11417 vrc = pVMM->pfnVMR3Create(cCpus,
11418 pConsole->mpVmm2UserMethods,
11419 enmExecEngine == VMExecutionEngine_Interpreter
11420 || enmExecEngine == VMExecutionEngine_Recompiler /** @todo NativeApi too? */
11421 ? VMCREATE_F_DRIVERLESS : 0,
11422 Console::i_genericVMSetErrorCallback,
11423 &pTask->mErrorMsg,
11424 pTask->mpfnConfigConstructor,
11425 static_cast<Console *>(pConsole),
11426 &pVM, NULL);
11427 alock.acquire();
11428 if (RT_SUCCESS(vrc))
11429 {
11430 do /* break "loop" */
11431 {
11432 /*
11433 * Register our load/save state file handlers
11434 */
11435 vrc = pVMM->pfnSSMR3RegisterExternal(pConsole->mpUVM, sSSMConsoleUnit, 0 /*iInstance*/,
11436 CONSOLE_SAVED_STATE_VERSION, 0 /* cbGuess */,
11437 NULL, NULL, NULL,
11438 NULL, i_saveStateFileExec, NULL,
11439 NULL, i_loadStateFileExec, NULL,
11440 static_cast<Console *>(pConsole));
11441 AssertRCBreak(vrc);
11442
11443 vrc = static_cast<Console *>(pConsole)->i_getDisplay()->i_registerSSM(pConsole->mpUVM);
11444 AssertRC(vrc);
11445 if (RT_FAILURE(vrc))
11446 break;
11447
11448 /*
11449 * Synchronize debugger settings
11450 */
11451 MachineDebugger *machineDebugger = pConsole->i_getMachineDebugger();
11452 if (machineDebugger)
11453 machineDebugger->i_flushQueuedSettings();
11454
11455 /*
11456 * Set domain name and DNS search list for DrvNAT
11457 */
11458 pConsole->i_onNATDnsChanged();
11459
11460 /*
11461 * Shared Folders
11462 */
11463 if (pConsole->m_pVMMDev->isShFlActive())
11464 {
11465 /* Does the code below call Console from the other thread?
11466 * Not sure, so release the lock just in case. */
11467 alock.release();
11468
11469 for (SharedFolderDataMap::const_iterator it = pTask->mSharedFolders.begin();
11470 it != pTask->mSharedFolders.end();
11471 ++it)
11472 {
11473 const SharedFolderData &d = it->second;
11474 hrc = pConsole->i_createSharedFolder(it->first, d);
11475 if (FAILED(hrc))
11476 {
11477 ErrorInfoKeeper eik;
11478 pConsole->i_atVMRuntimeErrorCallbackF(0, "BrokenSharedFolder",
11479 N_("The shared folder '%s' could not be set up: %ls.\n"
11480 "The shared folder setup will not be complete. It is recommended to power down the virtual "
11481 "machine and fix the shared folder settings while the machine is not running"),
11482 it->first.c_str(), eik.getText().raw());
11483 }
11484 }
11485 if (FAILED(hrc))
11486 hrc = S_OK; // do not fail with broken shared folders
11487
11488 /* acquire the lock again */
11489 alock.acquire();
11490 }
11491
11492#ifdef VBOX_WITH_AUDIO_VRDE
11493 /*
11494 * Attach the VRDE audio driver.
11495 */
11496 if (pConsole->i_getVRDEServer())
11497 {
11498 BOOL fVRDEEnabled = FALSE;
11499 hrc = pConsole->i_getVRDEServer()->COMGETTER(Enabled)(&fVRDEEnabled);
11500 AssertComRCBreak(hrc, RT_NOTHING);
11501
11502 if ( fVRDEEnabled
11503 && pConsole->mAudioVRDE)
11504 pConsole->mAudioVRDE->doAttachDriverViaEmt(pConsole->mpUVM, pVMM, &alock);
11505 }
11506#endif
11507
11508 /*
11509 * Enable client connections to the VRDP server.
11510 */
11511 pConsole->i_consoleVRDPServer()->EnableConnections();
11512
11513 /* Release the lock before a lengthy operation. */
11514 alock.release();
11515
11516#ifdef VBOX_WITH_RECORDING
11517 /*
11518 * Start recording if configured.
11519 */
11520 ComPtr<IRecordingSettings> pRecordingSettings;
11521 hrc = pConsole->mMachine->COMGETTER(RecordingSettings)(pRecordingSettings.asOutParam());
11522 AssertComRCBreak(hrc, RT_NOTHING);
11523
11524 BOOL fRecordingEnabled = FALSE;
11525 hrc = pRecordingSettings->COMGETTER(Enabled)(&fRecordingEnabled);
11526 AssertComRCBreak(hrc, RT_NOTHING);
11527
11528 if (fRecordingEnabled)
11529 {
11530 ComPtr<IProgress> pProgress;
11531 hrc = pRecordingSettings->Start(pProgress.asOutParam());
11532 if (FAILED(hrc))
11533 {
11534 com::ErrorInfoKeeper eik;
11535 ComPtr<IVirtualBoxErrorInfo> pErrorInfo = eik.takeError();
11536 Bstr strMsg;
11537 hrc = pErrorInfo->COMGETTER(Text)(strMsg.asOutParam());
11538 AssertComRCBreak(hrc, RT_NOTHING);
11539 LONG lRc;
11540 hrc = pErrorInfo->COMGETTER(ResultCode)(&lRc);
11541 AssertComRCBreak(hrc, RT_NOTHING);
11542
11543 LogRel(("Recording: Failed to start on VM power up: %ls (%Rrc)\n",
11544 strMsg.raw(), lRc));
11545 }
11546 }
11547#endif
11548 /*
11549 * Capture USB devices.
11550 */
11551 hrc = pConsole->i_captureUSBDevices(pConsole->mpUVM);
11552 if (FAILED(hrc))
11553 {
11554 alock.acquire();
11555 break;
11556 }
11557
11558 /*
11559 * Load saved state?
11560 */
11561 if (pTask->mSavedStateFile.length())
11562 {
11563 LogFlowFunc(("Restoring saved state from '%s'...\n", pTask->mSavedStateFile.c_str()));
11564
11565#ifdef VBOX_WITH_FULL_VM_ENCRYPTION
11566 SsmStream ssmStream(pConsole, pVMM, pTask->m_pKeyStore, pTask->mKeyId, pTask->mKeyStore);
11567
11568 vrc = ssmStream.open(pTask->mSavedStateFile.c_str());
11569 if (RT_SUCCESS(vrc))
11570 {
11571 PCSSMSTRMOPS pStreamOps;
11572 void *pvStreamOpsUser;
11573
11574 vrc = ssmStream.querySsmStrmOps(&pStreamOps, &pvStreamOpsUser);
11575 if (RT_SUCCESS(vrc))
11576 vrc = pVMM->pfnVMR3LoadFromStream(pConsole->mpUVM,
11577 pStreamOps, pvStreamOpsUser,
11578 Console::i_stateProgressCallback,
11579 static_cast<IProgress *>(pTask->mProgress),
11580 false /*fTeleporting*/);
11581 }
11582#else
11583 vrc = pVMM->pfnVMR3LoadFromFile(pConsole->mpUVM,
11584 pTask->mSavedStateFile.c_str(),
11585 Console::i_stateProgressCallback,
11586 static_cast<IProgress *>(pTask->mProgress));
11587#endif
11588 if (RT_SUCCESS(vrc))
11589 {
11590 if (pTask->mStartPaused)
11591 /* done */
11592 pConsole->i_setMachineState(MachineState_Paused);
11593 else
11594 {
11595 /* Start/Resume the VM execution */
11596#ifdef VBOX_WITH_EXTPACK
11597 vrc = pConsole->mptrExtPackManager->i_callAllVmPowerOnHooks(pConsole, pVM, pVMM);
11598#endif
11599 if (RT_SUCCESS(vrc))
11600 vrc = pVMM->pfnVMR3Resume(pConsole->mpUVM, VMRESUMEREASON_STATE_RESTORED);
11601 AssertLogRelRC(vrc);
11602 }
11603 }
11604
11605 /* Power off in case we failed loading or resuming the VM */
11606 if (RT_FAILURE(vrc))
11607 {
11608 int vrc2 = pVMM->pfnVMR3PowerOff(pConsole->mpUVM); AssertLogRelRC(vrc2);
11609#ifdef VBOX_WITH_EXTPACK
11610 pConsole->mptrExtPackManager->i_callAllVmPowerOffHooks(pConsole, pVM, pVMM);
11611#endif
11612 }
11613 }
11614 else if (pTask->mTeleporterEnabled)
11615 {
11616 /* -> ConsoleImplTeleporter.cpp */
11617 bool fPowerOffOnFailure;
11618 hrc = pConsole->i_teleporterTrg(pConsole->mpUVM, pConsole->mpVMM, pMachine, &pTask->mErrorMsg,
11619 pTask->mStartPaused, pTask->mProgress, &fPowerOffOnFailure);
11620 if (FAILED(hrc) && fPowerOffOnFailure)
11621 {
11622 ErrorInfoKeeper eik;
11623 int vrc2 = pVMM->pfnVMR3PowerOff(pConsole->mpUVM); AssertLogRelRC(vrc2);
11624#ifdef VBOX_WITH_EXTPACK
11625 pConsole->mptrExtPackManager->i_callAllVmPowerOffHooks(pConsole, pVM, pVMM);
11626#endif
11627 }
11628 }
11629 else if (pTask->mStartPaused)
11630 /* done */
11631 pConsole->i_setMachineState(MachineState_Paused);
11632 else
11633 {
11634 /* Power on the VM (i.e. start executing) */
11635#ifdef VBOX_WITH_EXTPACK
11636 vrc = pConsole->mptrExtPackManager->i_callAllVmPowerOnHooks(pConsole, pVM, pVMM);
11637#endif
11638 if (RT_SUCCESS(vrc))
11639 vrc = pVMM->pfnVMR3PowerOn(pConsole->mpUVM);
11640 AssertLogRelRC(vrc);
11641 }
11642
11643 /* acquire the lock again */
11644 alock.acquire();
11645 }
11646 while (0);
11647
11648 /* On failure, destroy the VM */
11649 if (FAILED(hrc) || RT_FAILURE(vrc))
11650 {
11651 /* preserve existing error info */
11652 ErrorInfoKeeper eik;
11653
11654 /* powerDown() will call VMR3Destroy() and do all necessary
11655 * cleanup (VRDP, USB devices) */
11656 alock.release();
11657 HRESULT hrc2 = pConsole->i_powerDown();
11658 alock.acquire();
11659 AssertComRC(hrc2);
11660 }
11661 else
11662 {
11663 /*
11664 * Deregister the VMSetError callback. This is necessary as the
11665 * pfnVMAtError() function passed to VMR3Create() is supposed to
11666 * be sticky but our error callback isn't.
11667 */
11668 alock.release();
11669 pVMM->pfnVMR3AtErrorDeregister(pConsole->mpUVM, Console::i_genericVMSetErrorCallback, &pTask->mErrorMsg);
11670 /** @todo register another VMSetError callback? */
11671 alock.acquire();
11672 }
11673 }
11674 else
11675 {
11676 /*
11677 * If VMR3Create() failed it has released the VM memory.
11678 */
11679 if (pConsole->m_pVMMDev)
11680 {
11681 alock.release(); /* just to be on the safe side... */
11682 pConsole->m_pVMMDev->hgcmShutdown(true /*fUvmIsInvalid*/);
11683 alock.acquire();
11684 }
11685 pVMM->pfnVMR3ReleaseUVM(pConsole->mpUVM);
11686 pConsole->mpUVM = NULL;
11687 }
11688
11689 if (SUCCEEDED(hrc) && RT_FAILURE(vrc))
11690 {
11691 /* If VMR3Create() or one of the other calls in this function fail,
11692 * an appropriate error message has been set in pTask->mErrorMsg.
11693 * However since that happens via a callback, the hrc status code in
11694 * this function is not updated.
11695 */
11696 if (!pTask->mErrorMsg.length())
11697 {
11698 /* If the error message is not set but we've got a failure,
11699 * convert the VBox status code into a meaningful error message.
11700 * This becomes unused once all the sources of errors set the
11701 * appropriate error message themselves.
11702 */
11703 AssertMsgFailed(("Missing error message during powerup for status code %Rrc\n", vrc));
11704 pTask->mErrorMsg = Utf8StrFmt(tr("Failed to start VM execution (%Rrc)"), vrc);
11705 }
11706
11707 /* Set the error message as the COM error.
11708 * Progress::notifyComplete() will pick it up later. */
11709 throw i_setErrorStaticBoth(E_FAIL, vrc, pTask->mErrorMsg.c_str());
11710 }
11711 }
11712 catch (HRESULT hrcXcpt) { hrc = hrcXcpt; }
11713
11714 if ( pConsole->mMachineState == MachineState_Starting
11715 || pConsole->mMachineState == MachineState_Restoring
11716 || pConsole->mMachineState == MachineState_TeleportingIn
11717 )
11718 {
11719 /* We are still in the Starting/Restoring state. This means one of:
11720 *
11721 * 1) we failed before VMR3Create() was called;
11722 * 2) VMR3Create() failed.
11723 *
11724 * In both cases, there is no need to call powerDown(), but we still
11725 * need to go back to the PoweredOff/Saved state. Reuse
11726 * vmstateChangeCallback() for that purpose.
11727 */
11728
11729 /* preserve existing error info */
11730 ErrorInfoKeeper eik;
11731
11732 Assert(pConsole->mpUVM == NULL);
11733 i_vmstateChangeCallback(NULL, pConsole->mpVMM, VMSTATE_TERMINATED, VMSTATE_CREATING, pConsole);
11734 }
11735
11736 /*
11737 * Evaluate the final result. Note that the appropriate mMachineState value
11738 * is already set by vmstateChangeCallback() in all cases.
11739 */
11740
11741 /* release the lock, don't need it any more */
11742 alock.release();
11743
11744 if (SUCCEEDED(hrc))
11745 {
11746 /* Notify the progress object of the success */
11747 pTask->mProgress->i_notifyComplete(S_OK);
11748 }
11749 else
11750 {
11751 /* The progress object will fetch the current error info */
11752 pTask->mProgress->i_notifyComplete(hrc);
11753 LogRel(("Power up failed (vrc=%Rrc, hrc=%Rhrc (%#08X))\n", vrc, hrc, hrc));
11754 }
11755
11756 /* Notify VBoxSVC and any waiting openRemoteSession progress object. */
11757 pConsole->mControl->EndPowerUp(hrc);
11758
11759#if defined(RT_OS_WINDOWS)
11760 /* uninitialize COM */
11761 CoUninitialize();
11762#endif
11763
11764 LogFlowFuncLeave();
11765}
11766
11767
11768/**
11769 * Reconfigures a medium attachment (part of taking or deleting an online snapshot).
11770 *
11771 * @param pThis Reference to the console object.
11772 * @param pUVM The VM handle.
11773 * @param pVMM The VMM vtable.
11774 * @param pArgs Argument package.
11775 * @param phrc Where to store com error - only valid if we return VERR_GENERAL_FAILURE.
11776 * @return VBox status code.
11777 */
11778/* static */
11779DECLCALLBACK(int) Console::i_reconfigureMediumAttachment(Console *pThis,
11780 PUVM pUVM,
11781 PCVMMR3VTABLE pVMM,
11782 Console::ReconfigureMediumAttachmentArgs const *pArgs,
11783 HRESULT *phrc)
11784{
11785 LogFlowFunc(("pUVM=%p aMediumAtt=%p phrc=%p\n", pUVM, pArgs->aMediumAtt, phrc));
11786
11787 HRESULT hrc;
11788 Bstr bstr;
11789 *phrc = S_OK;
11790#define H() do { if (FAILED(hrc)) { AssertMsgFailed(("hrc=%Rhrc (%#x)\n", hrc, hrc)); *phrc = hrc; return VERR_GENERAL_FAILURE; } } while (0)
11791
11792 /* Ignore attachments other than hard disks, since at the moment they are
11793 * not subject to snapshotting in general. */
11794 DeviceType_T lType;
11795 hrc = pArgs->aMediumAtt->COMGETTER(Type)(&lType); H();
11796 if (lType != DeviceType_HardDisk)
11797 return VINF_SUCCESS;
11798
11799 /* Update the device instance configuration. */
11800 int vrc = pThis->i_configMediumAttachment(pArgs->pcszDevice,
11801 pArgs->uInstance,
11802 pArgs->enmBus,
11803 pArgs->fUseHostIOCache,
11804 pArgs->fBuiltinIOCache,
11805 pArgs->fInsertDiskIntegrityDrv,
11806 pArgs->fSetupMerge,
11807 pArgs->uMergeSource,
11808 pArgs->uMergeTarget,
11809 pArgs->aMediumAtt,
11810 pArgs->aMachineState,
11811 phrc,
11812 true /* fAttachDetach */,
11813 false /* fForceUnmount */,
11814 false /* fHotplug */,
11815 pUVM,
11816 pVMM,
11817 NULL /* paLedDevType */,
11818 NULL /* ppLunL0)*/);
11819 if (RT_FAILURE(vrc))
11820 {
11821 AssertMsgFailed(("vrc=%Rrc\n", vrc));
11822 return vrc;
11823 }
11824
11825#undef H
11826
11827 LogFlowFunc(("Returns success\n"));
11828 return VINF_SUCCESS;
11829}
11830
11831/**
11832 * Thread for powering down the Console.
11833 *
11834 * @param pTask The power down task.
11835 *
11836 * @note Locks the Console object for writing.
11837 */
11838/*static*/
11839void Console::i_powerDownThreadTask(VMPowerDownTask *pTask)
11840{
11841 int vrc = VINF_SUCCESS; /* only used in assertion */
11842 LogFlowFuncEnter();
11843 try
11844 {
11845 if (pTask->isOk() == false)
11846 vrc = VERR_GENERAL_FAILURE;
11847
11848 const ComObjPtr<Console> &that = pTask->mConsole;
11849
11850 /* Note: no need to use AutoCaller to protect Console because VMTask does
11851 * that */
11852
11853 /* wait until the method tat started us returns */
11854 AutoWriteLock thatLock(that COMMA_LOCKVAL_SRC_POS);
11855
11856 /* release VM caller to avoid the powerDown() deadlock */
11857 pTask->releaseVMCaller();
11858
11859 thatLock.release();
11860
11861 that->i_powerDown(pTask->mServerProgress);
11862
11863 /* complete the operation */
11864 that->mControl->EndPoweringDown(S_OK, Bstr().raw());
11865
11866 }
11867 catch (const std::exception &e)
11868 {
11869 AssertMsgFailed(("Exception %s was caught, vrc=%Rrc\n", e.what(), vrc));
11870 NOREF(e); NOREF(vrc);
11871 }
11872
11873 LogFlowFuncLeave();
11874}
11875
11876/**
11877 * @interface_method_impl{VMM2USERMETHODS,pfnSaveState}
11878 */
11879/*static*/ DECLCALLBACK(int)
11880Console::i_vmm2User_SaveState(PCVMM2USERMETHODS pThis, PUVM pUVM)
11881{
11882 Console *pConsole = ((MYVMM2USERMETHODS *)pThis)->pConsole;
11883 NOREF(pUVM);
11884
11885 /*
11886 * For now, just call SaveState. We should probably try notify the GUI so
11887 * it can pop up a progress object and stuff. The progress object created
11888 * by the call isn't returned to anyone and thus gets updated without
11889 * anyone noticing it.
11890 */
11891 ComPtr<IProgress> pProgress;
11892 HRESULT hrc = pConsole->mMachine->SaveState(pProgress.asOutParam());
11893 return SUCCEEDED(hrc) ? VINF_SUCCESS : Global::vboxStatusCodeFromCOM(hrc);
11894}
11895
11896/**
11897 * @interface_method_impl{VMM2USERMETHODS,pfnNotifyEmtInit}
11898 */
11899/*static*/ DECLCALLBACK(void)
11900Console::i_vmm2User_NotifyEmtInit(PCVMM2USERMETHODS pThis, PUVM pUVM, PUVMCPU pUVCpu)
11901{
11902 NOREF(pThis); NOREF(pUVM); NOREF(pUVCpu);
11903 VirtualBoxBase::initializeComForThread();
11904}
11905
11906/**
11907 * @interface_method_impl{VMM2USERMETHODS,pfnNotifyEmtTerm}
11908 */
11909/*static*/ DECLCALLBACK(void)
11910Console::i_vmm2User_NotifyEmtTerm(PCVMM2USERMETHODS pThis, PUVM pUVM, PUVMCPU pUVCpu)
11911{
11912 NOREF(pThis); NOREF(pUVM); NOREF(pUVCpu);
11913 VirtualBoxBase::uninitializeComForThread();
11914}
11915
11916/**
11917 * @interface_method_impl{VMM2USERMETHODS,pfnNotifyPdmtInit}
11918 */
11919/*static*/ DECLCALLBACK(void)
11920Console::i_vmm2User_NotifyPdmtInit(PCVMM2USERMETHODS pThis, PUVM pUVM)
11921{
11922 NOREF(pThis); NOREF(pUVM);
11923 VirtualBoxBase::initializeComForThread();
11924}
11925
11926/**
11927 * @interface_method_impl{VMM2USERMETHODS,pfnNotifyPdmtTerm}
11928 */
11929/*static*/ DECLCALLBACK(void)
11930Console::i_vmm2User_NotifyPdmtTerm(PCVMM2USERMETHODS pThis, PUVM pUVM)
11931{
11932 NOREF(pThis); NOREF(pUVM);
11933 VirtualBoxBase::uninitializeComForThread();
11934}
11935
11936/**
11937 * @interface_method_impl{VMM2USERMETHODS,pfnNotifyResetTurnedIntoPowerOff}
11938 */
11939/*static*/ DECLCALLBACK(void)
11940Console::i_vmm2User_NotifyResetTurnedIntoPowerOff(PCVMM2USERMETHODS pThis, PUVM pUVM)
11941{
11942 Console *pConsole = ((MYVMM2USERMETHODS *)pThis)->pConsole;
11943 NOREF(pUVM);
11944
11945 pConsole->mfPowerOffCausedByReset = true;
11946}
11947
11948/**
11949 * Internal function to get LED set off of Console instance
11950 *
11951 * @returns pointer to PDMLED object
11952 *
11953 * @param iLedSet Index of LED set to fetch
11954 */
11955PPDMLED volatile *
11956Console::i_getLedSet(uint32_t iLedSet)
11957{
11958 AssertReturn(iLedSet < RT_ELEMENTS(maLedSets), NULL);
11959 return maLedSets[iLedSet].papLeds;
11960}
11961
11962/**
11963 * @interface_method_impl{VMM2USERMETHODS,pfnQueryGenericObject}
11964 */
11965/*static*/ DECLCALLBACK(void *)
11966Console::i_vmm2User_QueryGenericObject(PCVMM2USERMETHODS pThis, PUVM pUVM, PCRTUUID pUuid)
11967{
11968 Console *pConsole = ((MYVMM2USERMETHODS *)pThis)->pConsole;
11969 NOREF(pUVM);
11970
11971 /* To simplify comparison we copy the UUID into a com::Guid object. */
11972 com::Guid const UuidCopy(*pUuid);
11973
11974 if (UuidCopy == COM_IIDOF(IConsole))
11975 {
11976 IConsole *pIConsole = static_cast<IConsole *>(pConsole);
11977 return pIConsole;
11978 }
11979
11980 if (UuidCopy == COM_IIDOF(IMachine))
11981 {
11982 IMachine *pIMachine = pConsole->mMachine;
11983 return pIMachine;
11984 }
11985
11986 if (UuidCopy == COM_IIDOF(IKeyboard))
11987 {
11988 IKeyboard *pIKeyboard = pConsole->mKeyboard;
11989 return pIKeyboard;
11990 }
11991
11992 if (UuidCopy == COM_IIDOF(IMouse))
11993 {
11994 IMouse *pIMouse = pConsole->mMouse;
11995 return pIMouse;
11996 }
11997
11998 if (UuidCopy == COM_IIDOF(IDisplay))
11999 {
12000 IDisplay *pIDisplay = pConsole->mDisplay;
12001 return pIDisplay;
12002 }
12003
12004 if (UuidCopy == COM_IIDOF(INvramStore))
12005 {
12006 NvramStore *pNvramStore = static_cast<NvramStore *>(pConsole->mptrNvramStore);
12007 return pNvramStore;
12008 }
12009
12010#ifdef VBOX_WITH_VIRT_ARMV8
12011 if (UuidCopy == COM_IIDOF(IResourceStore))
12012 {
12013 ResourceStore *pResourceStore = static_cast<ResourceStore *>(pConsole->mptrResourceStore);
12014 return pResourceStore;
12015 }
12016#endif
12017
12018 if (UuidCopy == VMMDEV_OID)
12019 return pConsole->m_pVMMDev;
12020
12021 if (UuidCopy == USBCARDREADER_OID)
12022 return pConsole->mUsbCardReader;
12023
12024 if (UuidCopy == COM_IIDOF(ISnapshot))
12025 return ((MYVMM2USERMETHODS *)pThis)->pISnapshot;
12026
12027#ifdef VBOX_WITH_USB
12028 if (UuidCopy == REMOTEUSBIF_OID)
12029 return &pConsole->mRemoteUsbIf;
12030#endif
12031
12032 if (UuidCopy == EMULATEDUSBIF_OID)
12033 return pConsole->mEmulatedUSB->i_getEmulatedUsbIf();
12034
12035 return NULL;
12036}
12037
12038
12039/**
12040 * @interface_method_impl{PDMISECKEY,pfnKeyRetain}
12041 */
12042/*static*/ DECLCALLBACK(int)
12043Console::i_pdmIfSecKey_KeyRetain(PPDMISECKEY pInterface, const char *pszId, const uint8_t **ppbKey, size_t *pcbKey)
12044{
12045 Console *pConsole = ((MYPDMISECKEY *)pInterface)->pConsole;
12046
12047 AutoReadLock thatLock(pConsole COMMA_LOCKVAL_SRC_POS);
12048 SecretKey *pKey = NULL;
12049
12050 int vrc = pConsole->m_pKeyStore->retainSecretKey(Utf8Str(pszId), &pKey);
12051 if (RT_SUCCESS(vrc))
12052 {
12053 *ppbKey = (const uint8_t *)pKey->getKeyBuffer();
12054 *pcbKey = pKey->getKeySize();
12055 }
12056
12057 return vrc;
12058}
12059
12060/**
12061 * @interface_method_impl{PDMISECKEY,pfnKeyRelease}
12062 */
12063/*static*/ DECLCALLBACK(int)
12064Console::i_pdmIfSecKey_KeyRelease(PPDMISECKEY pInterface, const char *pszId)
12065{
12066 Console *pConsole = ((MYPDMISECKEY *)pInterface)->pConsole;
12067
12068 AutoReadLock thatLock(pConsole COMMA_LOCKVAL_SRC_POS);
12069 return pConsole->m_pKeyStore->releaseSecretKey(Utf8Str(pszId));
12070}
12071
12072/**
12073 * @interface_method_impl{PDMISECKEY,pfnPasswordRetain}
12074 */
12075/*static*/ DECLCALLBACK(int)
12076Console::i_pdmIfSecKey_PasswordRetain(PPDMISECKEY pInterface, const char *pszId, const char **ppszPassword)
12077{
12078 Console *pConsole = ((MYPDMISECKEY *)pInterface)->pConsole;
12079
12080 AutoReadLock thatLock(pConsole COMMA_LOCKVAL_SRC_POS);
12081 SecretKey *pKey = NULL;
12082
12083 int vrc = pConsole->m_pKeyStore->retainSecretKey(Utf8Str(pszId), &pKey);
12084 if (RT_SUCCESS(vrc))
12085 *ppszPassword = (const char *)pKey->getKeyBuffer();
12086
12087 return vrc;
12088}
12089
12090/**
12091 * @interface_method_impl{PDMISECKEY,pfnPasswordRelease}
12092 */
12093/*static*/ DECLCALLBACK(int)
12094Console::i_pdmIfSecKey_PasswordRelease(PPDMISECKEY pInterface, const char *pszId)
12095{
12096 Console *pConsole = ((MYPDMISECKEY *)pInterface)->pConsole;
12097
12098 AutoReadLock thatLock(pConsole COMMA_LOCKVAL_SRC_POS);
12099 return pConsole->m_pKeyStore->releaseSecretKey(Utf8Str(pszId));
12100}
12101
12102/**
12103 * @interface_method_impl{PDMISECKEYHLP,pfnKeyMissingNotify}
12104 */
12105/*static*/ DECLCALLBACK(int)
12106Console::i_pdmIfSecKeyHlp_KeyMissingNotify(PPDMISECKEYHLP pInterface)
12107{
12108 Console *pConsole = ((MYPDMISECKEYHLP *)pInterface)->pConsole;
12109
12110 /* Set guest property only, the VM is paused in the media driver calling us. */
12111 pConsole->mMachine->DeleteGuestProperty(Bstr("/VirtualBox/HostInfo/DekMissing").raw());
12112 pConsole->mMachine->SetGuestProperty(Bstr("/VirtualBox/HostInfo/DekMissing").raw(),
12113 Bstr("1").raw(), Bstr("RDONLYGUEST").raw());
12114 pConsole->mMachine->SaveSettings();
12115
12116 return VINF_SUCCESS;
12117}
12118
12119
12120
12121/**
12122 * The Main status driver instance data.
12123 */
12124typedef struct DRVMAINSTATUS
12125{
12126 /** The LED connectors. */
12127 PDMILEDCONNECTORS ILedConnectors;
12128 /** Pointer to the LED ports interface above us. */
12129 PPDMILEDPORTS pLedPorts;
12130 /** Pointer to the array of LED pointers. */
12131 PPDMLED volatile *papLeds;
12132 /** The unit number corresponding to the first entry in the LED array. */
12133 uint32_t iFirstLUN;
12134 /** The unit number corresponding to the last entry in the LED array.
12135 * (The size of the LED array is iLastLUN - iFirstLUN + 1.) */
12136 uint32_t iLastLUN;
12137 /** Pointer to the driver instance. */
12138 PPDMDRVINS pDrvIns;
12139 /** The Media Notify interface. */
12140 PDMIMEDIANOTIFY IMediaNotify;
12141 /** Set if there potentially are medium attachments. */
12142 bool fHasMediumAttachments;
12143 /** Device name+instance for mapping */
12144 char *pszDeviceInstance;
12145 /** Pointer to the Console object, for driver triggered activities. */
12146 Console *pConsole;
12147} DRVMAINSTATUS;
12148/** Pointer the instance data for a Main status driver. */
12149typedef DRVMAINSTATUS *PDRVMAINSTATUS;
12150
12151
12152/**
12153 * Notification about a unit which have been changed.
12154 *
12155 * The driver must discard any pointers to data owned by
12156 * the unit and requery it.
12157 *
12158 * @param pInterface Pointer to the interface structure containing the called function pointer.
12159 * @param iLUN The unit number.
12160 */
12161DECLCALLBACK(void) Console::i_drvStatus_UnitChanged(PPDMILEDCONNECTORS pInterface, unsigned iLUN)
12162{
12163 PDRVMAINSTATUS pThis = RT_FROM_MEMBER(pInterface, DRVMAINSTATUS, ILedConnectors);
12164 if (iLUN >= pThis->iFirstLUN && iLUN <= pThis->iLastLUN)
12165 {
12166 /*
12167 * Query the pointer to the PDMLED field inside the target device
12168 * structure (owned by the virtual hardware device).
12169 */
12170 PPDMLED pLed;
12171 int vrc = pThis->pLedPorts->pfnQueryStatusLed(pThis->pLedPorts, iLUN, &pLed);
12172 if (RT_FAILURE(vrc))
12173 pLed = NULL;
12174
12175 /*
12176 * Update the corresponding papLeds[] entry.
12177 *
12178 * papLeds[] points to the struct PDMLED of each of this driver's
12179 * units. The entries are initialized here, called out of a loop
12180 * in Console::i_drvStatus_Construct(), which previously called
12181 * Console::i_attachStatusDriver() to allocate the array itself.
12182 *
12183 * The arrays (and thus individual LEDs) are eventually read out
12184 * by Console::getDeviceActivity(), which is itself called from
12185 * src/VBox/Frontends/VirtualBox/src/runtime/UIIndicatorsPool.cpp
12186 */
12187 /** @todo acquire Console::mLedLock here in exclusive mode? */
12188 ASMAtomicWritePtr(&pThis->papLeds[iLUN - pThis->iFirstLUN], pLed);
12189 Log(("drvStatus_UnitChanged: iLUN=%d pLed=%p\n", iLUN, pLed));
12190 }
12191}
12192
12193
12194/**
12195 * Notification about a medium eject.
12196 *
12197 * @returns VBox status code.
12198 * @param pInterface Pointer to the interface structure containing the called function pointer.
12199 * @param uLUN The unit number.
12200 */
12201DECLCALLBACK(int) Console::i_drvStatus_MediumEjected(PPDMIMEDIANOTIFY pInterface, unsigned uLUN)
12202{
12203 PDRVMAINSTATUS pThis = RT_FROM_MEMBER(pInterface, DRVMAINSTATUS, IMediaNotify);
12204 LogFunc(("uLUN=%d\n", uLUN));
12205 if (pThis->fHasMediumAttachments)
12206 {
12207 Console * const pConsole = pThis->pConsole;
12208 AutoWriteLock alock(pConsole COMMA_LOCKVAL_SRC_POS);
12209
12210 ComPtr<IMediumAttachment> pMediumAtt;
12211 Utf8Str devicePath = Utf8StrFmt("%s/LUN#%u", pThis->pszDeviceInstance, uLUN);
12212 Console::MediumAttachmentMap::const_iterator end = pConsole->mapMediumAttachments.end();
12213 Console::MediumAttachmentMap::const_iterator it = pConsole->mapMediumAttachments.find(devicePath);
12214 if (it != end)
12215 pMediumAtt = it->second;
12216 Assert(!pMediumAtt.isNull());
12217 if (!pMediumAtt.isNull())
12218 {
12219 IMedium *pMedium = NULL;
12220 HRESULT hrc = pMediumAtt->COMGETTER(Medium)(&pMedium);
12221 AssertComRC(hrc);
12222 if (SUCCEEDED(hrc) && pMedium)
12223 {
12224 BOOL fHostDrive = FALSE;
12225 hrc = pMedium->COMGETTER(HostDrive)(&fHostDrive);
12226 AssertComRC(hrc);
12227 if (!fHostDrive)
12228 {
12229 alock.release();
12230
12231 ComPtr<IMediumAttachment> pNewMediumAtt;
12232 hrc = pThis->pConsole->mControl->EjectMedium(pMediumAtt, pNewMediumAtt.asOutParam());
12233 if (SUCCEEDED(hrc))
12234 {
12235 pThis->pConsole->mMachine->SaveSettings();
12236 ::FireMediumChangedEvent(pThis->pConsole->mEventSource, pNewMediumAtt);
12237 }
12238
12239 alock.acquire();
12240 if (pNewMediumAtt != pMediumAtt)
12241 {
12242 pConsole->mapMediumAttachments.erase(devicePath);
12243 pConsole->mapMediumAttachments.insert(std::make_pair(devicePath, pNewMediumAtt));
12244 }
12245 }
12246 }
12247 }
12248 }
12249 return VINF_SUCCESS;
12250}
12251
12252
12253/**
12254 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
12255 */
12256DECLCALLBACK(void *) Console::i_drvStatus_QueryInterface(PPDMIBASE pInterface, const char *pszIID)
12257{
12258 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
12259 PDRVMAINSTATUS pThis = PDMINS_2_DATA(pDrvIns, PDRVMAINSTATUS);
12260 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
12261 PDMIBASE_RETURN_INTERFACE(pszIID, PDMILEDCONNECTORS, &pThis->ILedConnectors);
12262 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIANOTIFY, &pThis->IMediaNotify);
12263 return NULL;
12264}
12265
12266
12267/**
12268 * Destruct a status driver instance.
12269 *
12270 * @param pDrvIns The driver instance data.
12271 */
12272DECLCALLBACK(void) Console::i_drvStatus_Destruct(PPDMDRVINS pDrvIns)
12273{
12274 PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
12275 PDRVMAINSTATUS pThis = PDMINS_2_DATA(pDrvIns, PDRVMAINSTATUS);
12276 LogFlowFunc(("iInstance=%d\n", pDrvIns->iInstance));
12277
12278 if (pThis->papLeds)
12279 {
12280 unsigned iLed = pThis->iLastLUN - pThis->iFirstLUN + 1;
12281 while (iLed-- > 0)
12282 ASMAtomicWriteNullPtr(&pThis->papLeds[iLed]);
12283 }
12284}
12285
12286
12287/**
12288 * Construct a status driver instance.
12289 *
12290 * @copydoc FNPDMDRVCONSTRUCT
12291 */
12292DECLCALLBACK(int) Console::i_drvStatus_Construct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
12293{
12294 RT_NOREF(fFlags);
12295 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
12296 PDRVMAINSTATUS pThis = PDMINS_2_DATA(pDrvIns, PDRVMAINSTATUS);
12297 LogFlowFunc(("iInstance=%d\n", pDrvIns->iInstance));
12298
12299 /*
12300 * Initialize data.
12301 */
12302 com::Guid ConsoleUuid(COM_IIDOF(IConsole));
12303 IConsole *pIConsole = (IConsole *)PDMDrvHlpQueryGenericUserObject(pDrvIns, ConsoleUuid.raw());
12304 AssertLogRelReturn(pIConsole, VERR_INTERNAL_ERROR_3);
12305 Console *pConsole = static_cast<Console *>(pIConsole);
12306 AssertLogRelReturn(pConsole, VERR_INTERNAL_ERROR_3);
12307
12308 pDrvIns->IBase.pfnQueryInterface = Console::i_drvStatus_QueryInterface;
12309 pThis->ILedConnectors.pfnUnitChanged = Console::i_drvStatus_UnitChanged;
12310 pThis->IMediaNotify.pfnEjected = Console::i_drvStatus_MediumEjected;
12311 pThis->pDrvIns = pDrvIns;
12312 pThis->pConsole = pConsole;
12313 pThis->fHasMediumAttachments = false;
12314 pThis->papLeds = NULL;
12315 pThis->pszDeviceInstance = NULL;
12316
12317 /*
12318 * Validate configuration.
12319 */
12320 PDMDRV_VALIDATE_CONFIG_RETURN(pDrvIns,
12321 "DeviceInstance|"
12322 "iLedSet|"
12323 "HasMediumAttachments|"
12324 "First|"
12325 "Last",
12326 "");
12327 AssertMsgReturn(PDMDrvHlpNoAttach(pDrvIns) == VERR_PDM_NO_ATTACHED_DRIVER,
12328 ("Configuration error: Not possible to attach anything to this driver!\n"),
12329 VERR_PDM_DRVINS_NO_ATTACH);
12330
12331 /*
12332 * Read config.
12333 */
12334 PCPDMDRVHLPR3 const pHlp = pDrvIns->pHlpR3;
12335
12336 uint32_t iLedSet;
12337 int vrc = pHlp->pfnCFGMQueryU32(pCfg, "iLedSet", &iLedSet);
12338 AssertLogRelMsgRCReturn(vrc, ("Configuration error: Failed to query the \"iLedSet\" value! vrc=%Rrc\n", vrc), vrc);
12339 pThis->papLeds = pConsole->i_getLedSet(iLedSet);
12340
12341 vrc = pHlp->pfnCFGMQueryBoolDef(pCfg, "HasMediumAttachments", &pThis->fHasMediumAttachments, false);
12342 AssertLogRelMsgRCReturn(vrc, ("Configuration error: Failed to query the \"HasMediumAttachments\" value! vrc=%Rrc\n", vrc), vrc);
12343
12344 if (pThis->fHasMediumAttachments)
12345 {
12346 vrc = pHlp->pfnCFGMQueryStringAlloc(pCfg, "DeviceInstance", &pThis->pszDeviceInstance);
12347 AssertLogRelMsgRCReturn(vrc, ("Configuration error: Failed to query the \"DeviceInstance\" value! vrc=%Rrc\n", vrc), vrc);
12348 }
12349
12350 vrc = pHlp->pfnCFGMQueryU32Def(pCfg, "First", &pThis->iFirstLUN, 0);
12351 AssertLogRelMsgRCReturn(vrc, ("Configuration error: Failed to query the \"First\" value! vrc=%Rrc\n", vrc), vrc);
12352
12353 vrc = pHlp->pfnCFGMQueryU32Def(pCfg, "Last", &pThis->iLastLUN, 0);
12354 AssertLogRelMsgRCReturn(vrc, ("Configuration error: Failed to query the \"Last\" value! vrc=%Rrc\n", vrc), vrc);
12355
12356 AssertLogRelMsgReturn(pThis->iFirstLUN <= pThis->iLastLUN,
12357 ("Configuration error: Invalid unit range %u-%u\n", pThis->iFirstLUN, pThis->iLastLUN),
12358 VERR_INVALID_PARAMETER);
12359
12360 /*
12361 * Get the ILedPorts interface of the above driver/device and
12362 * query the LEDs we want.
12363 */
12364 pThis->pLedPorts = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMILEDPORTS);
12365 AssertMsgReturn(pThis->pLedPorts, ("Configuration error: No led ports interface above!\n"),
12366 VERR_PDM_MISSING_INTERFACE_ABOVE);
12367
12368 for (unsigned i = pThis->iFirstLUN; i <= pThis->iLastLUN; ++i)
12369 Console::i_drvStatus_UnitChanged(&pThis->ILedConnectors, i);
12370
12371 return VINF_SUCCESS;
12372}
12373
12374
12375/**
12376 * Console status driver (LED) registration record.
12377 */
12378const PDMDRVREG Console::DrvStatusReg =
12379{
12380 /* u32Version */
12381 PDM_DRVREG_VERSION,
12382 /* szName */
12383 "MainStatus",
12384 /* szRCMod */
12385 "",
12386 /* szR0Mod */
12387 "",
12388 /* pszDescription */
12389 "Main status driver (Main as in the API).",
12390 /* fFlags */
12391 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
12392 /* fClass. */
12393 PDM_DRVREG_CLASS_STATUS,
12394 /* cMaxInstances */
12395 ~0U,
12396 /* cbInstance */
12397 sizeof(DRVMAINSTATUS),
12398 /* pfnConstruct */
12399 Console::i_drvStatus_Construct,
12400 /* pfnDestruct */
12401 Console::i_drvStatus_Destruct,
12402 /* pfnRelocate */
12403 NULL,
12404 /* pfnIOCtl */
12405 NULL,
12406 /* pfnPowerOn */
12407 NULL,
12408 /* pfnReset */
12409 NULL,
12410 /* pfnSuspend */
12411 NULL,
12412 /* pfnResume */
12413 NULL,
12414 /* pfnAttach */
12415 NULL,
12416 /* pfnDetach */
12417 NULL,
12418 /* pfnPowerOff */
12419 NULL,
12420 /* pfnSoftReset */
12421 NULL,
12422 /* u32EndVersion */
12423 PDM_DRVREG_VERSION
12424};
12425
12426
12427
12428/* vi: set tabstop=4 shiftwidth=4 expandtab: */
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette