VirtualBox

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

Last change on this file was 108046, checked in by vboxsync, 2 weeks ago

doc/manual,include/VBox,Frontends/{VBoxManage,VirtualBox/src},Main/{include,SharedFolder,Console,Machine,VirtualBox,VirtualBox.xidl}: Added global shared folders and adjusted fetching and handling of folders between shared folder types bugref:3544

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