VirtualBox

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

Last change on this file since 105016 was 105016, checked in by vboxsync, 8 months ago

doc/manual,include/VBox,Frontends/VBoxManage,HostServices/SharedFolders,
Main/{include,SharedFolder,Console,Machine,VirtualBox.xidl}: Add a
new attribute to ISharedFolder for specifying a symbolic link creation
policy to restrict the source pathname when creating symbolic links
within a guest. The symbolic link policies are represented by a new
enumeration of type SymlinkPolicy_T which includes values for no
restrictions ('any'), symlink sources only within the subtree of the
share ('subtree'), symlink sources as any relative path ('relative'),
and no symlinks allowed ('forbidden'). The symlink policy can only be
applied to permanent shared folders at this stage. bugref:10619

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