VirtualBox

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

Last change on this file since 107772 was 107498, checked in by vboxsync, 7 weeks ago

src/VBox/Main/include/ConsoleImpl: Fixed warning found by Parfait (uninitialized attributes), sorted initializers, renaming. jiraref:VBP-1424

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