VirtualBox

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

Last change on this file since 107402 was 107276, checked in by vboxsync, 8 weeks ago

PDMUsb: bugref:10810 Introduced PDMR3UsbQueryDeviceLun needed by Console::i_onNetworkAdapterChange

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