VirtualBox

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

Last change on this file since 105266 was 105266, checked in by vboxsync, 10 months ago

Recording: Implemented support for a dedicated progress object, which is exposed to API clients. This can be used for better tracking the recording progress as well as for error reporting. The RecordingSettings API also now has a dedicated start() method to start recording, as well as support for attaching to an already ongoing recording by retrieving the progress object at a later time. Adapted FE/Qt (draft, see @todos), FE/VBoxManage and the Validation Kit testdriver to the new APIs. VBoxManage also can attach to an ongoing recording now. The recording progress object also will have multiple operations to get the recording progress for convenience. bugref:10718

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 416.3 KB
Line 
1/* $Id: ConsoleImpl.cpp 105266 2024-07-11 07:49:37Z 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 VINF_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 * @param pProgress Progress object to use. Optional and can be NULL.
6100 */
6101int Console::i_recordingEnable(BOOL fEnable, util::AutoWriteLock *pAutoLock, ComPtr<IProgress> &pProgress)
6102{
6103 AssertPtrReturn(pAutoLock, VERR_INVALID_POINTER);
6104
6105 bool const fIsEnabled = mRecording.mCtx.IsStarted();
6106
6107 if (RT_BOOL(fEnable) == fIsEnabled) /* No change? Bail out. */
6108 return VINF_NO_CHANGE;
6109
6110 int vrc = VINF_SUCCESS;
6111
6112 Display *pDisplay = i_getDisplay();
6113 AssertPtrReturn(pDisplay, VERR_INVALID_POINTER);
6114
6115 LogRel(("Recording: %s\n", fEnable ? "Enabling" : "Disabling"));
6116
6117 SafeVMPtrQuiet ptrVM(this);
6118 if (ptrVM.isOk())
6119 {
6120 if (fEnable)
6121 {
6122 vrc = i_recordingCreate(pProgress);
6123 if (RT_SUCCESS(vrc))
6124 {
6125# ifdef VBOX_WITH_AUDIO_RECORDING
6126 /* Attach the video recording audio driver if required. */
6127 if ( mRecording.mCtx.IsFeatureEnabled(RecordingFeature_Audio)
6128 && mRecording.mAudioRec)
6129 {
6130 vrc = mRecording.mAudioRec->applyConfiguration(mRecording.mCtx.GetConfig());
6131 if (RT_SUCCESS(vrc))
6132 vrc = mRecording.mAudioRec->doAttachDriverViaEmt(ptrVM.rawUVM(), ptrVM.vtable(), pAutoLock);
6133
6134 if (RT_FAILURE(vrc))
6135 mRecording.mCtx.SetError(vrc, Utf8StrFmt(tr("Attaching audio recording driver failed (%Rrc)"), vrc));
6136 }
6137# endif
6138 if ( RT_SUCCESS(vrc)
6139 && mRecording.mCtx.IsReady()) /* Any video recording (audio and/or video) feature enabled? */
6140 {
6141 vrc = i_recordingStart(pAutoLock);
6142 }
6143 }
6144
6145 if (RT_FAILURE(vrc))
6146 LogRel(("Recording: Failed to enable with %Rrc\n", vrc));
6147 }
6148 else /* Disable */
6149 {
6150 vrc = i_recordingStop(pAutoLock);
6151 if (RT_SUCCESS(vrc))
6152 {
6153# ifdef VBOX_WITH_AUDIO_RECORDING
6154 if (mRecording.mAudioRec)
6155 {
6156 vrc = mRecording.mAudioRec->doDetachDriverViaEmt(ptrVM.rawUVM(), ptrVM.vtable(), pAutoLock);
6157 if (RT_FAILURE(vrc))
6158 mRecording.mCtx.SetError(vrc, Utf8StrFmt(tr("Detaching audio recording driver failed (%Rrc) -- please consult log file for details"), vrc));
6159 }
6160# endif
6161 i_recordingDestroy();
6162 }
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 return vrc;
6172}
6173#endif /* VBOX_WITH_RECORDING */
6174
6175/**
6176 * Called by IInternalSessionControl::OnRecordingStateChange().
6177 */
6178HRESULT Console::i_onRecordingStateChange(BOOL aEnable, ComPtr<IProgress> &aProgress)
6179{
6180#ifdef VBOX_WITH_RECORDING
6181 HRESULT hrc = S_OK;
6182
6183 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
6184
6185 LogRel2(("Recording: State changed (%s)\n", aEnable ? "enabled" : "disabled"));
6186
6187 /* Don't trigger recording changes if the VM isn't running. */
6188 SafeVMPtrQuiet ptrVM(this);
6189 if (ptrVM.isOk())
6190 {
6191 ComPtr<IVirtualBoxErrorInfo> pErrorInfo;
6192
6193 int vrc = i_recordingEnable(aEnable, &alock, aProgress);
6194 if (RT_FAILURE(vrc))
6195 {
6196 /* If available, get the error information from the progress object and fire it via the event below. */
6197 if (aProgress.isNotNull())
6198 {
6199 hrc = aProgress->COMGETTER(ErrorInfo(pErrorInfo.asOutParam()));
6200 AssertComRCReturn(hrc, hrc);
6201 }
6202 }
6203
6204 alock.release(); /* Release lock before firing event. */
6205
6206 if (vrc != VINF_NO_CHANGE)
6207 ::FireRecordingStateChangedEvent(mEventSource, aEnable, pErrorInfo);
6208
6209 if (RT_FAILURE(vrc))
6210 hrc = VBOX_E_RECORDING_ERROR;
6211
6212 ptrVM.release();
6213 }
6214
6215 return hrc;
6216#else
6217 RT_NOREF(aEnabled, aProgress);
6218 ReturnComNotImplemented();
6219#endif /* VBOX_WITH_RECORDING */
6220}
6221
6222/**
6223 * Called by IInternalSessionControl::OnRecordingScreenStateChange().
6224 */
6225HRESULT Console::i_onRecordingScreenStateChange(BOOL aEnable, ULONG aScreen)
6226{
6227 RT_NOREF(aEnable, aScreen);
6228 ReturnComNotImplemented();
6229}
6230
6231/**
6232 * Called by IInternalSessionControl::OnUSBControllerChange().
6233 */
6234HRESULT Console::i_onUSBControllerChange()
6235{
6236 LogFlowThisFunc(("\n"));
6237
6238 AutoCaller autoCaller(this);
6239 AssertComRCReturnRC(autoCaller.hrc());
6240
6241 ::FireUSBControllerChangedEvent(mEventSource);
6242
6243 return S_OK;
6244}
6245
6246/**
6247 * Called by IInternalSessionControl::OnSharedFolderChange().
6248 *
6249 * @note Locks this object for writing.
6250 */
6251HRESULT Console::i_onSharedFolderChange(BOOL aGlobal)
6252{
6253 LogFlowThisFunc(("aGlobal=%RTbool\n", aGlobal));
6254
6255 AutoCaller autoCaller(this);
6256 AssertComRCReturnRC(autoCaller.hrc());
6257
6258 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
6259
6260 HRESULT hrc = i_fetchSharedFolders(aGlobal);
6261
6262 /* notify console callbacks on success */
6263 if (SUCCEEDED(hrc))
6264 {
6265 alock.release();
6266 ::FireSharedFolderChangedEvent(mEventSource, aGlobal ? Scope_Global : Scope_Machine);
6267 }
6268
6269 return hrc;
6270}
6271
6272/**
6273 * Called by IInternalSessionControl::OnGuestDebugControlChange().
6274 */
6275HRESULT Console::i_onGuestDebugControlChange(IGuestDebugControl *aGuestDebugControl)
6276{
6277 LogFlowThisFunc(("\n"));
6278
6279 AutoCaller autoCaller(this);
6280 AssertComRCReturnRC(autoCaller.hrc());
6281
6282 HRESULT hrc = S_OK;
6283
6284 /* don't trigger changes if the VM isn't running */
6285 SafeVMPtrQuiet ptrVM(this);
6286 if (ptrVM.isOk())
6287 {
6288 /// @todo
6289 }
6290
6291 if (SUCCEEDED(hrc))
6292 ::FireGuestDebugControlChangedEvent(mEventSource, aGuestDebugControl);
6293
6294 LogFlowThisFunc(("Leaving hrc=%#x\n", hrc));
6295 return hrc;
6296}
6297
6298
6299/**
6300 * Called by IInternalSessionControl::OnUSBDeviceAttach() or locally by
6301 * processRemoteUSBDevices() after IInternalMachineControl::RunUSBDeviceFilters()
6302 * returns TRUE for a given remote USB device.
6303 *
6304 * @return S_OK if the device was attached to the VM.
6305 * @return failure if not attached.
6306 *
6307 * @param aDevice The device in question.
6308 * @param aError Error information.
6309 * @param aMaskedIfs The interfaces to hide from the guest.
6310 * @param aCaptureFilename File name where to store the USB traffic.
6311 *
6312 * @note Locks this object for writing.
6313 */
6314HRESULT Console::i_onUSBDeviceAttach(IUSBDevice *aDevice, IVirtualBoxErrorInfo *aError, ULONG aMaskedIfs,
6315 const Utf8Str &aCaptureFilename)
6316{
6317#ifdef VBOX_WITH_USB
6318 LogFlowThisFunc(("aDevice=%p aError=%p\n", aDevice, aError));
6319
6320 AutoCaller autoCaller(this);
6321 ComAssertComRCRetRC(autoCaller.hrc());
6322
6323 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
6324
6325 /* Get the VM pointer (we don't need error info, since it's a callback). */
6326 SafeVMPtrQuiet ptrVM(this);
6327 if (!ptrVM.isOk())
6328 {
6329 /* The VM may be no more operational when this message arrives
6330 * (e.g. it may be Saving or Stopping or just PoweredOff) --
6331 * autoVMCaller.hrc() will return a failure in this case. */
6332 LogFlowThisFunc(("Attach request ignored (mMachineState=%d).\n", mMachineState));
6333 return ptrVM.hrc();
6334 }
6335
6336 if (aError != NULL)
6337 {
6338 /* notify callbacks about the error */
6339 alock.release();
6340 i_onUSBDeviceStateChange(aDevice, true /* aAttached */, aError);
6341 return S_OK;
6342 }
6343
6344 /* Don't proceed unless there's at least one USB hub. */
6345 if (!ptrVM.vtable()->pfnPDMR3UsbHasHub(ptrVM.rawUVM()))
6346 {
6347 LogFlowThisFunc(("Attach request ignored (no USB controller).\n"));
6348 return E_FAIL;
6349 }
6350
6351 alock.release();
6352 HRESULT hrc = i_attachUSBDevice(aDevice, aMaskedIfs, aCaptureFilename);
6353 if (FAILED(hrc))
6354 {
6355 /* take the current error info */
6356 com::ErrorInfoKeeper eik;
6357 /* the error must be a VirtualBoxErrorInfo instance */
6358 ComPtr<IVirtualBoxErrorInfo> pError = eik.takeError();
6359 Assert(!pError.isNull());
6360 if (!pError.isNull())
6361 {
6362 /* notify callbacks about the error */
6363 i_onUSBDeviceStateChange(aDevice, true /* aAttached */, pError);
6364 }
6365 }
6366
6367 return hrc;
6368
6369#else /* !VBOX_WITH_USB */
6370 RT_NOREF(aDevice, aError, aMaskedIfs, aCaptureFilename);
6371 return E_FAIL;
6372#endif /* !VBOX_WITH_USB */
6373}
6374
6375/**
6376 * Called by IInternalSessionControl::OnUSBDeviceDetach() and locally by
6377 * processRemoteUSBDevices().
6378 *
6379 * @note Locks this object for writing.
6380 */
6381HRESULT Console::i_onUSBDeviceDetach(IN_BSTR aId,
6382 IVirtualBoxErrorInfo *aError)
6383{
6384#ifdef VBOX_WITH_USB
6385 Guid Uuid(aId);
6386 LogFlowThisFunc(("aId={%RTuuid} aError=%p\n", Uuid.raw(), aError));
6387
6388 AutoCaller autoCaller(this);
6389 AssertComRCReturnRC(autoCaller.hrc());
6390
6391 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
6392
6393 /* Find the device. */
6394 ComObjPtr<OUSBDevice> pUSBDevice;
6395 USBDeviceList::iterator it = mUSBDevices.begin();
6396 while (it != mUSBDevices.end())
6397 {
6398 LogFlowThisFunc(("it={%RTuuid}\n", (*it)->i_id().raw()));
6399 if ((*it)->i_id() == Uuid)
6400 {
6401 pUSBDevice = *it;
6402 break;
6403 }
6404 ++it;
6405 }
6406
6407
6408 if (pUSBDevice.isNull())
6409 {
6410 LogFlowThisFunc(("USB device not found.\n"));
6411
6412 /* The VM may be no more operational when this message arrives
6413 * (e.g. it may be Saving or Stopping or just PoweredOff). Use
6414 * AutoVMCaller to detect it -- AutoVMCaller::hrc() will return a
6415 * failure in this case. */
6416
6417 AutoVMCallerQuiet autoVMCaller(this);
6418 if (FAILED(autoVMCaller.hrc()))
6419 {
6420 LogFlowThisFunc(("Detach request ignored (mMachineState=%d).\n", mMachineState));
6421 return autoVMCaller.hrc();
6422 }
6423
6424 /* the device must be in the list otherwise */
6425 AssertFailedReturn(E_FAIL);
6426 }
6427
6428 if (aError != NULL)
6429 {
6430 /* notify callback about an error */
6431 alock.release();
6432 i_onUSBDeviceStateChange(pUSBDevice, false /* aAttached */, aError);
6433 return S_OK;
6434 }
6435
6436 /* Remove the device from the collection, it is re-added below for failures */
6437 mUSBDevices.erase(it);
6438
6439 alock.release();
6440 HRESULT hrc = i_detachUSBDevice(pUSBDevice);
6441 if (FAILED(hrc))
6442 {
6443 /* Re-add the device to the collection */
6444 alock.acquire();
6445 mUSBDevices.push_back(pUSBDevice);
6446 alock.release();
6447 /* take the current error info */
6448 com::ErrorInfoKeeper eik;
6449 /* the error must be a VirtualBoxErrorInfo instance */
6450 ComPtr<IVirtualBoxErrorInfo> pError = eik.takeError();
6451 Assert(!pError.isNull());
6452 if (!pError.isNull())
6453 {
6454 /* notify callbacks about the error */
6455 i_onUSBDeviceStateChange(pUSBDevice, false /* aAttached */, pError);
6456 }
6457 }
6458
6459 return hrc;
6460
6461#else /* !VBOX_WITH_USB */
6462 RT_NOREF(aId, aError);
6463 return E_FAIL;
6464#endif /* !VBOX_WITH_USB */
6465}
6466
6467/**
6468 * Called by IInternalSessionControl::OnBandwidthGroupChange().
6469 *
6470 * @note Locks this object for writing.
6471 */
6472HRESULT Console::i_onBandwidthGroupChange(IBandwidthGroup *aBandwidthGroup)
6473{
6474 LogFlowThisFunc(("\n"));
6475
6476 AutoCaller autoCaller(this);
6477 AssertComRCReturnRC(autoCaller.hrc());
6478
6479 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
6480
6481 HRESULT hrc = S_OK;
6482
6483 /* don't trigger bandwidth group changes if the VM isn't running */
6484 SafeVMPtrQuiet ptrVM(this);
6485 if (ptrVM.isOk())
6486 {
6487 if ( mMachineState == MachineState_Running
6488 || mMachineState == MachineState_Teleporting
6489 || mMachineState == MachineState_LiveSnapshotting
6490 )
6491 {
6492 /* No need to call in the EMT thread. */
6493 Bstr bstrName;
6494 hrc = aBandwidthGroup->COMGETTER(Name)(bstrName.asOutParam());
6495 if (SUCCEEDED(hrc))
6496 {
6497 Utf8Str const strName(bstrName);
6498 LONG64 cMax;
6499 hrc = aBandwidthGroup->COMGETTER(MaxBytesPerSec)(&cMax);
6500 if (SUCCEEDED(hrc))
6501 {
6502 BandwidthGroupType_T enmType;
6503 hrc = aBandwidthGroup->COMGETTER(Type)(&enmType);
6504 if (SUCCEEDED(hrc))
6505 {
6506 int vrc = VINF_SUCCESS;
6507 if (enmType == BandwidthGroupType_Disk)
6508 vrc = ptrVM.vtable()->pfnPDMR3AsyncCompletionBwMgrSetMaxForFile(ptrVM.rawUVM(), strName.c_str(),
6509 (uint32_t)cMax);
6510#ifdef VBOX_WITH_NETSHAPER
6511 else if (enmType == BandwidthGroupType_Network)
6512 vrc = ptrVM.vtable()->pfnPDMR3NsBwGroupSetLimit(ptrVM.rawUVM(), strName.c_str(), cMax);
6513 else
6514 hrc = E_NOTIMPL;
6515#endif
6516 AssertRC(vrc);
6517 }
6518 }
6519 }
6520 }
6521 else
6522 hrc = i_setInvalidMachineStateError();
6523 ptrVM.release();
6524 }
6525
6526 /* notify console callbacks on success */
6527 if (SUCCEEDED(hrc))
6528 {
6529 alock.release();
6530 ::FireBandwidthGroupChangedEvent(mEventSource, aBandwidthGroup);
6531 }
6532
6533 LogFlowThisFunc(("Leaving hrc=%#x\n", hrc));
6534 return hrc;
6535}
6536
6537/**
6538 * Called by IInternalSessionControl::OnStorageDeviceChange().
6539 *
6540 * @note Locks this object for writing.
6541 */
6542HRESULT Console::i_onStorageDeviceChange(IMediumAttachment *aMediumAttachment, BOOL aRemove, BOOL aSilent)
6543{
6544 LogFlowThisFunc(("\n"));
6545
6546 AutoCaller autoCaller(this);
6547 AssertComRCReturnRC(autoCaller.hrc());
6548
6549 HRESULT hrc = S_OK;
6550
6551 /* don't trigger medium changes if the VM isn't running */
6552 SafeVMPtrQuiet ptrVM(this);
6553 if (ptrVM.isOk())
6554 {
6555 if (aRemove)
6556 hrc = i_doStorageDeviceDetach(aMediumAttachment, ptrVM.rawUVM(), ptrVM.vtable(), RT_BOOL(aSilent));
6557 else
6558 hrc = i_doStorageDeviceAttach(aMediumAttachment, ptrVM.rawUVM(), ptrVM.vtable(), RT_BOOL(aSilent));
6559 ptrVM.release();
6560 }
6561
6562 /* notify console callbacks on success */
6563 if (SUCCEEDED(hrc))
6564 ::FireStorageDeviceChangedEvent(mEventSource, aMediumAttachment, aRemove, aSilent);
6565
6566 LogFlowThisFunc(("Leaving hrc=%#x\n", hrc));
6567 return hrc;
6568}
6569
6570HRESULT Console::i_onExtraDataChange(const Bstr &aMachineId, const Bstr &aKey, const Bstr &aVal)
6571{
6572 LogFlowThisFunc(("\n"));
6573
6574 AutoCaller autoCaller(this);
6575 if (FAILED(autoCaller.hrc()))
6576 return autoCaller.hrc();
6577
6578 if (aMachineId != i_getId())
6579 return S_OK;
6580
6581 /* don't do anything if the VM isn't running */
6582 if (aKey == "VBoxInternal2/TurnResetIntoPowerOff")
6583 {
6584 SafeVMPtrQuiet ptrVM(this);
6585 if (ptrVM.isOk())
6586 {
6587 mfTurnResetIntoPowerOff = aVal == "1";
6588 int vrc = ptrVM.vtable()->pfnVMR3SetPowerOffInsteadOfReset(ptrVM.rawUVM(), mfTurnResetIntoPowerOff);
6589 AssertRC(vrc);
6590
6591 ptrVM.release();
6592 }
6593 }
6594
6595 /* notify console callbacks on success */
6596 ::FireExtraDataChangedEvent(mEventSource, aMachineId.raw(), aKey.raw(), aVal.raw());
6597
6598 LogFlowThisFunc(("Leaving S_OK\n"));
6599 return S_OK;
6600}
6601
6602/**
6603 * @note Temporarily locks this object for writing.
6604 */
6605HRESULT Console::i_getGuestProperty(const Utf8Str &aName, Utf8Str *aValue, LONG64 *aTimestamp, Utf8Str *aFlags)
6606{
6607#ifndef VBOX_WITH_GUEST_PROPS
6608 ReturnComNotImplemented();
6609#else /* VBOX_WITH_GUEST_PROPS */
6610 if (!RT_VALID_PTR(aValue))
6611 return E_POINTER;
6612#ifndef VBOX_WITH_PARFAIT /** @todo Fails due to RT_VALID_PTR() being only a != NULL check with parfait. */
6613 if (aTimestamp != NULL && !RT_VALID_PTR(aTimestamp))
6614 return E_POINTER;
6615 if (aFlags != NULL && !RT_VALID_PTR(aFlags))
6616 return E_POINTER;
6617#endif
6618
6619 AutoCaller autoCaller(this);
6620 AssertComRCReturnRC(autoCaller.hrc());
6621
6622 /* protect mpUVM (if not NULL) */
6623 SafeVMPtrQuiet ptrVM(this);
6624 if (FAILED(ptrVM.hrc()))
6625 return ptrVM.hrc();
6626
6627 /* Note: validity of mVMMDev which is bound to uninit() is guaranteed by
6628 * ptrVM, so there is no need to hold a lock of this */
6629
6630 HRESULT hrc = E_UNEXPECTED;
6631 try
6632 {
6633 VBOXHGCMSVCPARM parm[4];
6634 char szBuffer[GUEST_PROP_MAX_VALUE_LEN + GUEST_PROP_MAX_FLAGS_LEN];
6635
6636 parm[0].type = VBOX_HGCM_SVC_PARM_PTR;
6637 parm[0].u.pointer.addr = (void *)aName.c_str();
6638 parm[0].u.pointer.size = (uint32_t)aName.length() + 1; /* The + 1 is the null terminator */
6639
6640 parm[1].type = VBOX_HGCM_SVC_PARM_PTR;
6641 parm[1].u.pointer.addr = szBuffer;
6642 parm[1].u.pointer.size = sizeof(szBuffer);
6643
6644 parm[2].type = VBOX_HGCM_SVC_PARM_64BIT;
6645 parm[2].u.uint64 = 0;
6646
6647 parm[3].type = VBOX_HGCM_SVC_PARM_32BIT;
6648 parm[3].u.uint32 = 0;
6649
6650 int vrc = m_pVMMDev->hgcmHostCall("VBoxGuestPropSvc", GUEST_PROP_FN_HOST_GET_PROP,
6651 4, &parm[0]);
6652 /* The returned string should never be able to be greater than our buffer */
6653 AssertLogRel(vrc != VERR_BUFFER_OVERFLOW);
6654 AssertLogRel(RT_FAILURE(vrc) || parm[2].type == VBOX_HGCM_SVC_PARM_64BIT);
6655 if (RT_SUCCESS(vrc))
6656 {
6657 *aValue = szBuffer;
6658
6659 if (aTimestamp)
6660 *aTimestamp = parm[2].u.uint64;
6661
6662 if (aFlags)
6663 *aFlags = &szBuffer[strlen(szBuffer) + 1];
6664
6665 hrc = S_OK;
6666 }
6667 else if (vrc == VERR_NOT_FOUND)
6668 {
6669 *aValue = "";
6670 hrc = S_OK;
6671 }
6672 else
6673 hrc = setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("The VBoxGuestPropSvc service call failed with the error %Rrc"), vrc);
6674 }
6675 catch(std::bad_alloc & /*e*/)
6676 {
6677 hrc = E_OUTOFMEMORY;
6678 }
6679
6680 return hrc;
6681#endif /* VBOX_WITH_GUEST_PROPS */
6682}
6683
6684/**
6685 * @note Temporarily locks this object for writing.
6686 */
6687HRESULT Console::i_setGuestProperty(const Utf8Str &aName, const Utf8Str &aValue, const Utf8Str &aFlags)
6688{
6689#ifndef VBOX_WITH_GUEST_PROPS
6690 ReturnComNotImplemented();
6691#else /* VBOX_WITH_GUEST_PROPS */
6692
6693 AutoCaller autoCaller(this);
6694 AssertComRCReturnRC(autoCaller.hrc());
6695
6696 /* protect mpUVM (if not NULL) */
6697 SafeVMPtrQuiet ptrVM(this);
6698 if (FAILED(ptrVM.hrc()))
6699 return ptrVM.hrc();
6700
6701 /* Note: validity of mVMMDev which is bound to uninit() is guaranteed by
6702 * ptrVM, so there is no need to hold a lock of this */
6703
6704 VBOXHGCMSVCPARM parm[3];
6705
6706 parm[0].type = VBOX_HGCM_SVC_PARM_PTR;
6707 parm[0].u.pointer.addr = (void*)aName.c_str();
6708 parm[0].u.pointer.size = (uint32_t)aName.length() + 1; /* The + 1 is the null terminator */
6709
6710 parm[1].type = VBOX_HGCM_SVC_PARM_PTR;
6711 parm[1].u.pointer.addr = (void *)aValue.c_str();
6712 parm[1].u.pointer.size = (uint32_t)aValue.length() + 1; /* The + 1 is the null terminator */
6713
6714 int vrc;
6715 if (aFlags.isEmpty())
6716 {
6717 vrc = m_pVMMDev->hgcmHostCall("VBoxGuestPropSvc", GUEST_PROP_FN_HOST_SET_PROP_VALUE, 2, &parm[0]);
6718 }
6719 else
6720 {
6721 parm[2].type = VBOX_HGCM_SVC_PARM_PTR;
6722 parm[2].u.pointer.addr = (void*)aFlags.c_str();
6723 parm[2].u.pointer.size = (uint32_t)aFlags.length() + 1; /* The + 1 is the null terminator */
6724
6725 vrc = m_pVMMDev->hgcmHostCall("VBoxGuestPropSvc", GUEST_PROP_FN_HOST_SET_PROP, 3, &parm[0]);
6726 }
6727
6728 HRESULT hrc = S_OK;
6729 if (RT_FAILURE(vrc))
6730 hrc = setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("The VBoxGuestPropSvc service call failed with the error %Rrc"), vrc);
6731 return hrc;
6732#endif /* VBOX_WITH_GUEST_PROPS */
6733}
6734
6735HRESULT Console::i_deleteGuestProperty(const Utf8Str &aName)
6736{
6737#ifndef VBOX_WITH_GUEST_PROPS
6738 ReturnComNotImplemented();
6739#else /* VBOX_WITH_GUEST_PROPS */
6740
6741 AutoCaller autoCaller(this);
6742 AssertComRCReturnRC(autoCaller.hrc());
6743
6744 /* protect mpUVM (if not NULL) */
6745 SafeVMPtrQuiet ptrVM(this);
6746 if (FAILED(ptrVM.hrc()))
6747 return ptrVM.hrc();
6748
6749 /* Note: validity of mVMMDev which is bound to uninit() is guaranteed by
6750 * ptrVM, so there is no need to hold a lock of this */
6751
6752 VBOXHGCMSVCPARM parm[1];
6753 parm[0].type = VBOX_HGCM_SVC_PARM_PTR;
6754 parm[0].u.pointer.addr = (void*)aName.c_str();
6755 parm[0].u.pointer.size = (uint32_t)aName.length() + 1; /* The + 1 is the null terminator */
6756
6757 int vrc = m_pVMMDev->hgcmHostCall("VBoxGuestPropSvc", GUEST_PROP_FN_HOST_DEL_PROP, 1, &parm[0]);
6758
6759 HRESULT hrc = S_OK;
6760 if (RT_FAILURE(vrc))
6761 hrc = setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("The VBoxGuestPropSvc service call failed with the error %Rrc"), vrc);
6762 return hrc;
6763#endif /* VBOX_WITH_GUEST_PROPS */
6764}
6765
6766/**
6767 * @note Temporarily locks this object for writing.
6768 */
6769HRESULT Console::i_enumerateGuestProperties(const Utf8Str &aPatterns,
6770 std::vector<Utf8Str> &aNames,
6771 std::vector<Utf8Str> &aValues,
6772 std::vector<LONG64> &aTimestamps,
6773 std::vector<Utf8Str> &aFlags)
6774{
6775#ifndef VBOX_WITH_GUEST_PROPS
6776 ReturnComNotImplemented();
6777#else /* VBOX_WITH_GUEST_PROPS */
6778
6779 AutoCaller autoCaller(this);
6780 AssertComRCReturnRC(autoCaller.hrc());
6781
6782 /* protect mpUVM (if not NULL) */
6783 AutoVMCallerWeak autoVMCaller(this);
6784 if (FAILED(autoVMCaller.hrc()))
6785 return autoVMCaller.hrc();
6786
6787 /* Note: validity of mVMMDev which is bound to uninit() is guaranteed by
6788 * autoVMCaller, so there is no need to hold a lock of this */
6789
6790 return i_doEnumerateGuestProperties(aPatterns, aNames, aValues, aTimestamps, aFlags);
6791#endif /* VBOX_WITH_GUEST_PROPS */
6792}
6793
6794
6795/*
6796 * Internal: helper function for connecting progress reporting
6797 */
6798static DECLCALLBACK(int) onlineMergeMediumProgress(void *pvUser, unsigned uPercentage)
6799{
6800 HRESULT hrc = S_OK;
6801 IProgress *pProgress = static_cast<IProgress *>(pvUser);
6802 if (pProgress)
6803 {
6804 ComPtr<IInternalProgressControl> pProgressControl(pProgress);
6805 AssertReturn(!!pProgressControl, VERR_INVALID_PARAMETER);
6806 hrc = pProgressControl->SetCurrentOperationProgress(uPercentage);
6807 }
6808 return SUCCEEDED(hrc) ? VINF_SUCCESS : VERR_GENERAL_FAILURE;
6809}
6810
6811/**
6812 * @note Temporarily locks this object for writing. bird: And/or reading?
6813 */
6814HRESULT Console::i_onlineMergeMedium(IMediumAttachment *aMediumAttachment,
6815 ULONG aSourceIdx, ULONG aTargetIdx,
6816 IProgress *aProgress)
6817{
6818 AutoCaller autoCaller(this);
6819 AssertComRCReturnRC(autoCaller.hrc());
6820
6821 HRESULT hrc = S_OK;
6822 int vrc = VINF_SUCCESS;
6823
6824 /* Get the VM - must be done before the read-locking. */
6825 SafeVMPtr ptrVM(this);
6826 if (!ptrVM.isOk())
6827 return ptrVM.hrc();
6828
6829 /* We will need to release the lock before doing the actual merge */
6830 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
6831
6832 /* paranoia - we don't want merges to happen while teleporting etc. */
6833 switch (mMachineState)
6834 {
6835 case MachineState_DeletingSnapshotOnline:
6836 case MachineState_DeletingSnapshotPaused:
6837 break;
6838
6839 default:
6840 return i_setInvalidMachineStateError();
6841 }
6842
6843 /** @todo AssertComRC -> AssertComRCReturn! Could potentially end up
6844 * using uninitialized variables here. */
6845 BOOL fBuiltinIOCache = FALSE;
6846 hrc = mMachine->COMGETTER(IOCacheEnabled)(&fBuiltinIOCache);
6847 AssertComRC(hrc);
6848 SafeIfaceArray<IStorageController> ctrls;
6849 hrc = mMachine->COMGETTER(StorageControllers)(ComSafeArrayAsOutParam(ctrls));
6850 AssertComRC(hrc);
6851 LONG lDev = -1;
6852 hrc = aMediumAttachment->COMGETTER(Device)(&lDev);
6853 AssertComRC(hrc);
6854 LONG lPort = -1;
6855 hrc = aMediumAttachment->COMGETTER(Port)(&lPort);
6856 AssertComRC(hrc);
6857 IMedium *pMedium = NULL;
6858 hrc = aMediumAttachment->COMGETTER(Medium)(&pMedium);
6859 AssertComRC(hrc);
6860 Bstr mediumLocation;
6861 if (pMedium)
6862 {
6863 hrc = pMedium->COMGETTER(Location)(mediumLocation.asOutParam());
6864 AssertComRC(hrc);
6865 }
6866
6867 Bstr attCtrlName;
6868 hrc = aMediumAttachment->COMGETTER(Controller)(attCtrlName.asOutParam());
6869 AssertComRC(hrc);
6870 ComPtr<IStorageController> pStorageController;
6871 for (size_t i = 0; i < ctrls.size(); ++i)
6872 {
6873 Bstr ctrlName;
6874 hrc = ctrls[i]->COMGETTER(Name)(ctrlName.asOutParam());
6875 AssertComRC(hrc);
6876 if (attCtrlName == ctrlName)
6877 {
6878 pStorageController = ctrls[i];
6879 break;
6880 }
6881 }
6882 if (pStorageController.isNull())
6883 return setError(E_FAIL,
6884 tr("Could not find storage controller '%ls'"),
6885 attCtrlName.raw());
6886
6887 StorageControllerType_T enmCtrlType;
6888 hrc = pStorageController->COMGETTER(ControllerType)(&enmCtrlType);
6889 AssertComRC(hrc);
6890 const char *pcszDevice = i_storageControllerTypeToStr(enmCtrlType);
6891
6892 StorageBus_T enmBus;
6893 hrc = pStorageController->COMGETTER(Bus)(&enmBus);
6894 AssertComRC(hrc);
6895
6896 ULONG uInstance = 0;
6897 hrc = pStorageController->COMGETTER(Instance)(&uInstance);
6898 AssertComRC(hrc);
6899
6900 BOOL fUseHostIOCache = TRUE;
6901 hrc = pStorageController->COMGETTER(UseHostIOCache)(&fUseHostIOCache);
6902 AssertComRC(hrc);
6903
6904 unsigned uLUN;
6905 hrc = Console::i_storageBusPortDeviceToLun(enmBus, lPort, lDev, uLUN);
6906 AssertComRCReturnRC(hrc);
6907
6908 Assert(mMachineState == MachineState_DeletingSnapshotOnline);
6909
6910 /* Pause the VM, as it might have pending IO on this drive */
6911 bool fResume = false;
6912 hrc = i_suspendBeforeConfigChange(ptrVM.rawUVM(), ptrVM.vtable(), &alock, &fResume);
6913 if (FAILED(hrc))
6914 return hrc;
6915
6916 bool fInsertDiskIntegrityDrv = false;
6917 Bstr strDiskIntegrityFlag;
6918 hrc = mMachine->GetExtraData(Bstr("VBoxInternal2/EnableDiskIntegrityDriver").raw(), strDiskIntegrityFlag.asOutParam());
6919 if ( hrc == S_OK
6920 && strDiskIntegrityFlag == "1")
6921 fInsertDiskIntegrityDrv = true;
6922
6923 alock.release();
6924 vrc = ptrVM.vtable()->pfnVMR3ReqCallWaitU(ptrVM.rawUVM(), VMCPUID_ANY,
6925 (PFNRT)i_reconfigureMediumAttachment, 15,
6926 this, ptrVM.rawUVM(), ptrVM.vtable(), pcszDevice, uInstance, enmBus,
6927 fUseHostIOCache, fBuiltinIOCache, fInsertDiskIntegrityDrv, true /* fSetupMerge */,
6928 aSourceIdx, aTargetIdx, aMediumAttachment, mMachineState, &hrc);
6929 /* error handling is after resuming the VM */
6930
6931 if (fResume)
6932 i_resumeAfterConfigChange(ptrVM.rawUVM(), ptrVM.vtable());
6933
6934 if (RT_FAILURE(vrc))
6935 return setErrorBoth(E_FAIL, vrc, "%Rrc", vrc);
6936 if (FAILED(hrc))
6937 return hrc;
6938
6939 PPDMIBASE pIBase = NULL;
6940 PPDMIMEDIA pIMedium = NULL;
6941 vrc = ptrVM.vtable()->pfnPDMR3QueryDriverOnLun(ptrVM.rawUVM(), pcszDevice, uInstance, uLUN, "VD", &pIBase);
6942 if (RT_SUCCESS(vrc))
6943 {
6944 if (pIBase)
6945 {
6946 pIMedium = (PPDMIMEDIA)pIBase->pfnQueryInterface(pIBase, PDMIMEDIA_IID);
6947 if (!pIMedium)
6948 return setError(E_FAIL, tr("could not query medium interface of controller"));
6949 }
6950 else
6951 return setError(E_FAIL, tr("could not query base interface of controller"));
6952 }
6953
6954 /* Finally trigger the merge. */
6955 vrc = pIMedium->pfnMerge(pIMedium, onlineMergeMediumProgress, aProgress);
6956 if (RT_FAILURE(vrc))
6957 return setErrorBoth(E_FAIL, vrc, tr("Failed to perform an online medium merge (%Rrc)"), vrc);
6958
6959 alock.acquire();
6960 /* Pause the VM, as it might have pending IO on this drive */
6961 hrc = i_suspendBeforeConfigChange(ptrVM.rawUVM(), ptrVM.vtable(), &alock, &fResume);
6962 if (FAILED(hrc))
6963 return hrc;
6964 alock.release();
6965
6966 /* Update medium chain and state now, so that the VM can continue. */
6967 hrc = mControl->FinishOnlineMergeMedium();
6968
6969 vrc = ptrVM.vtable()->pfnVMR3ReqCallWaitU(ptrVM.rawUVM(), VMCPUID_ANY,
6970 (PFNRT)i_reconfigureMediumAttachment, 15,
6971 this, ptrVM.rawUVM(), ptrVM.vtable(), pcszDevice, uInstance, enmBus,
6972 fUseHostIOCache, fBuiltinIOCache, fInsertDiskIntegrityDrv, false /* fSetupMerge */,
6973 0 /* uMergeSource */, 0 /* uMergeTarget */, aMediumAttachment, mMachineState, &hrc);
6974 /* error handling is after resuming the VM */
6975
6976 if (fResume)
6977 i_resumeAfterConfigChange(ptrVM.rawUVM(), ptrVM.vtable());
6978
6979 if (RT_FAILURE(vrc))
6980 return setErrorBoth(E_FAIL, vrc, "%Rrc", vrc);
6981 if (FAILED(hrc))
6982 return hrc;
6983
6984 return hrc;
6985}
6986
6987HRESULT Console::i_reconfigureMediumAttachments(const std::vector<ComPtr<IMediumAttachment> > &aAttachments)
6988{
6989
6990 AutoCaller autoCaller(this);
6991 if (FAILED(autoCaller.hrc()))
6992 return autoCaller.hrc();
6993
6994 /* get the VM handle. */
6995 SafeVMPtr ptrVM(this);
6996 if (!ptrVM.isOk())
6997 return ptrVM.hrc();
6998
6999 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
7000
7001 for (size_t i = 0; i < aAttachments.size(); ++i)
7002 {
7003 /*
7004 * We could pass the objects, but then EMT would have to do lots of
7005 * IPC (to VBoxSVC) which takes a significant amount of time.
7006 * Better query needed values here and pass them.
7007 */
7008 Bstr controllerName;
7009 HRESULT hrc = aAttachments[i]->COMGETTER(Controller)(controllerName.asOutParam());
7010 if (FAILED(hrc))
7011 return hrc;
7012
7013 ComPtr<IStorageController> pStorageController;
7014 hrc = mMachine->GetStorageControllerByName(controllerName.raw(), pStorageController.asOutParam());
7015 if (FAILED(hrc))
7016 return hrc;
7017
7018 StorageControllerType_T enmController;
7019 hrc = pStorageController->COMGETTER(ControllerType)(&enmController);
7020 if (FAILED(hrc))
7021 return hrc;
7022 const char * const pcszDevice = i_storageControllerTypeToStr(enmController);
7023
7024 ULONG lInstance;
7025 hrc = pStorageController->COMGETTER(Instance)(&lInstance);
7026 if (FAILED(hrc))
7027 return hrc;
7028
7029 StorageBus_T enmBus;
7030 hrc = pStorageController->COMGETTER(Bus)(&enmBus);
7031 if (FAILED(hrc))
7032 return hrc;
7033
7034 BOOL fUseHostIOCache;
7035 hrc = pStorageController->COMGETTER(UseHostIOCache)(&fUseHostIOCache);
7036 if (FAILED(hrc))
7037 return hrc;
7038
7039 BOOL fBuiltinIOCache;
7040 hrc = mMachine->COMGETTER(IOCacheEnabled)(&fBuiltinIOCache);
7041 if (FAILED(hrc))
7042 return hrc;
7043
7044 bool fInsertDiskIntegrityDrv = false;
7045 Bstr strDiskIntegrityFlag;
7046 hrc = mMachine->GetExtraData(Bstr("VBoxInternal2/EnableDiskIntegrityDriver").raw(),
7047 strDiskIntegrityFlag.asOutParam());
7048 if ( hrc == S_OK
7049 && strDiskIntegrityFlag == "1")
7050 fInsertDiskIntegrityDrv = true;
7051
7052 alock.release();
7053
7054 hrc = S_OK;
7055 IMediumAttachment *pAttachment = aAttachments[i];
7056 int vrc = ptrVM.vtable()->pfnVMR3ReqCallWaitU(ptrVM.rawUVM(), VMCPUID_ANY,
7057 (PFNRT)i_reconfigureMediumAttachment, 15,
7058 this, ptrVM.rawUVM(), ptrVM.vtable(), pcszDevice, lInstance, enmBus,
7059 fUseHostIOCache, fBuiltinIOCache, fInsertDiskIntegrityDrv,
7060 false /* fSetupMerge */, 0 /* uMergeSource */, 0 /* uMergeTarget */,
7061 pAttachment, mMachineState, &hrc);
7062 if (RT_FAILURE(vrc))
7063 throw setErrorBoth(E_FAIL, vrc, "%Rrc", vrc);
7064 if (FAILED(hrc))
7065 throw hrc;
7066
7067 alock.acquire();
7068 }
7069
7070 return S_OK;
7071}
7072
7073HRESULT Console::i_onVMProcessPriorityChange(VMProcPriority_T priority)
7074{
7075 AutoCaller autoCaller(this);
7076 HRESULT hrc = autoCaller.hrc();
7077 if (FAILED(hrc))
7078 return hrc;
7079
7080 RTPROCPRIORITY enmProcPriority = RTPROCPRIORITY_DEFAULT;
7081 switch (priority)
7082 {
7083 case VMProcPriority_Default:
7084 enmProcPriority = RTPROCPRIORITY_DEFAULT;
7085 break;
7086 case VMProcPriority_Flat:
7087 enmProcPriority = RTPROCPRIORITY_FLAT;
7088 break;
7089 case VMProcPriority_Low:
7090 enmProcPriority = RTPROCPRIORITY_LOW;
7091 break;
7092 case VMProcPriority_Normal:
7093 enmProcPriority = RTPROCPRIORITY_NORMAL;
7094 break;
7095 case VMProcPriority_High:
7096 enmProcPriority = RTPROCPRIORITY_HIGH;
7097 break;
7098 default:
7099 return setError(E_INVALIDARG, tr("Unsupported priority type (%d)"), priority);
7100 }
7101 int vrc = RTProcSetPriority(enmProcPriority);
7102 if (RT_FAILURE(vrc))
7103 hrc = setErrorBoth(VBOX_E_VM_ERROR, vrc,
7104 tr("Could not set the priority of the process (%Rrc). Try to set it when VM is not started."), vrc);
7105
7106 return hrc;
7107}
7108
7109/**
7110 * Load an HGCM service.
7111 *
7112 * Main purpose of this method is to allow extension packs to load HGCM
7113 * service modules, which they can't, because the HGCM functionality lives
7114 * in module VBoxC (and ConsoleImpl.cpp is part of it and thus can call it).
7115 * Extension modules must not link directly against VBoxC, (XP)COM is
7116 * handling this.
7117 */
7118int Console::i_hgcmLoadService(const char *pszServiceLibrary, const char *pszServiceName)
7119{
7120 /* Everyone seems to delegate all HGCM calls to VMMDev, so stick to this
7121 * convention. Adds one level of indirection for no obvious reason. */
7122 AssertPtrReturn(m_pVMMDev, VERR_INVALID_STATE);
7123 return m_pVMMDev->hgcmLoadService(pszServiceLibrary, pszServiceName);
7124}
7125
7126/**
7127 * Merely passes the call to Guest::enableVMMStatistics().
7128 */
7129void Console::i_enableVMMStatistics(BOOL aEnable)
7130{
7131 if (mGuest)
7132 mGuest->i_enableVMMStatistics(aEnable);
7133}
7134
7135/**
7136 * Worker for Console::Pause and internal entry point for pausing a VM for
7137 * a specific reason.
7138 */
7139HRESULT Console::i_pause(Reason_T aReason)
7140{
7141 LogFlowThisFuncEnter();
7142
7143 AutoCaller autoCaller(this);
7144 if (FAILED(autoCaller.hrc())) return autoCaller.hrc();
7145
7146 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
7147
7148 switch (mMachineState)
7149 {
7150 case MachineState_Running:
7151 case MachineState_Teleporting:
7152 case MachineState_LiveSnapshotting:
7153 break;
7154
7155 case MachineState_Paused:
7156 case MachineState_TeleportingPausedVM:
7157 case MachineState_OnlineSnapshotting:
7158 /* Remove any keys which are supposed to be removed on a suspend. */
7159 if ( aReason == Reason_HostSuspend
7160 || aReason == Reason_HostBatteryLow)
7161 {
7162 i_removeSecretKeysOnSuspend();
7163 return S_OK;
7164 }
7165 return setError(VBOX_E_INVALID_VM_STATE, tr("Already paused"));
7166
7167 default:
7168 return i_setInvalidMachineStateError();
7169 }
7170
7171 /* get the VM handle. */
7172 SafeVMPtr ptrVM(this);
7173 HRESULT hrc = ptrVM.hrc();
7174 if (SUCCEEDED(hrc))
7175 {
7176 /* release the lock before a VMR3* call (EMT might wait for it, @bugref{7648})! */
7177 alock.release();
7178
7179 LogFlowThisFunc(("Sending PAUSE request...\n"));
7180 if (aReason != Reason_Unspecified)
7181 LogRel(("Pausing VM execution, reason '%s'\n", ::stringifyReason(aReason)));
7182
7183 /** @todo r=klaus make use of aReason */
7184 VMSUSPENDREASON enmReason = VMSUSPENDREASON_USER;
7185 if (aReason == Reason_HostSuspend)
7186 enmReason = VMSUSPENDREASON_HOST_SUSPEND;
7187 else if (aReason == Reason_HostBatteryLow)
7188 enmReason = VMSUSPENDREASON_HOST_BATTERY_LOW;
7189
7190 int vrc = ptrVM.vtable()->pfnVMR3Suspend(ptrVM.rawUVM(), enmReason);
7191
7192 if (RT_FAILURE(vrc))
7193 hrc = setErrorBoth(VBOX_E_VM_ERROR, vrc, tr("Could not suspend the machine execution (%Rrc)"), vrc);
7194 else if ( aReason == Reason_HostSuspend
7195 || aReason == Reason_HostBatteryLow)
7196 {
7197 alock.acquire();
7198 i_removeSecretKeysOnSuspend();
7199 }
7200 }
7201
7202 LogFlowThisFunc(("hrc=%Rhrc\n", hrc));
7203 LogFlowThisFuncLeave();
7204 return hrc;
7205}
7206
7207/**
7208 * Worker for Console::Resume and internal entry point for resuming a VM for
7209 * a specific reason.
7210 */
7211HRESULT Console::i_resume(Reason_T aReason, AutoWriteLock &alock)
7212{
7213 LogFlowThisFuncEnter();
7214
7215 AutoCaller autoCaller(this);
7216 if (FAILED(autoCaller.hrc())) return autoCaller.hrc();
7217
7218 /* get the VM handle. */
7219 SafeVMPtr ptrVM(this);
7220 if (!ptrVM.isOk())
7221 return ptrVM.hrc();
7222
7223 /* release the lock before a VMR3* call (EMT might wait for it, @bugref{7648})! */
7224 alock.release();
7225
7226 LogFlowThisFunc(("Sending RESUME request...\n"));
7227 if (aReason != Reason_Unspecified)
7228 LogRel(("Resuming VM execution, reason '%s'\n", ::stringifyReason(aReason)));
7229
7230 int vrc;
7231 VMSTATE const enmVMState = mpVMM->pfnVMR3GetStateU(ptrVM.rawUVM());
7232 if (enmVMState == VMSTATE_CREATED)
7233 {
7234#ifdef VBOX_WITH_EXTPACK
7235 vrc = mptrExtPackManager->i_callAllVmPowerOnHooks(this, ptrVM.vtable()->pfnVMR3GetVM(ptrVM.rawUVM()), ptrVM.vtable());
7236#else
7237 vrc = VINF_SUCCESS;
7238#endif
7239 if (RT_SUCCESS(vrc))
7240 vrc = ptrVM.vtable()->pfnVMR3PowerOn(ptrVM.rawUVM()); /* (PowerUpPaused) */
7241 }
7242 else
7243 {
7244 VMRESUMEREASON enmReason;
7245 if (aReason == Reason_HostResume)
7246 {
7247 /*
7248 * Host resume may be called multiple times successively. We don't want to VMR3Resume->vmR3Resume->vmR3TrySetState()
7249 * to assert on us, hence check for the VM state here and bail if it's not in the 'suspended' state.
7250 * See @bugref{3495}.
7251 *
7252 * Also, don't resume the VM through a host-resume unless it was suspended due to a host-suspend.
7253 */
7254 if (enmVMState != VMSTATE_SUSPENDED)
7255 {
7256 LogRel(("Ignoring VM resume request, VM is currently not suspended (%d)\n", enmVMState));
7257 return S_OK;
7258 }
7259 VMSUSPENDREASON const enmSuspendReason = ptrVM.vtable()->pfnVMR3GetSuspendReason(ptrVM.rawUVM());
7260 if (enmSuspendReason != VMSUSPENDREASON_HOST_SUSPEND)
7261 {
7262 LogRel(("Ignoring VM resume request, VM was not suspended due to host-suspend (%d)\n", enmSuspendReason));
7263 return S_OK;
7264 }
7265
7266 enmReason = VMRESUMEREASON_HOST_RESUME;
7267 }
7268 else
7269 {
7270 /*
7271 * Any other reason to resume the VM throws an error when the VM was suspended due to a host suspend.
7272 * See @bugref{7836}.
7273 */
7274 if ( enmVMState == VMSTATE_SUSPENDED
7275 && ptrVM.vtable()->pfnVMR3GetSuspendReason(ptrVM.rawUVM()) == VMSUSPENDREASON_HOST_SUSPEND)
7276 return setError(VBOX_E_INVALID_VM_STATE, tr("VM is paused due to host power management"));
7277
7278 enmReason = aReason == Reason_Snapshot ? VMRESUMEREASON_STATE_SAVED : VMRESUMEREASON_USER;
7279 }
7280
7281 // for snapshots: no state change callback, VBoxSVC does everything
7282 if (aReason == Reason_Snapshot)
7283 mVMStateChangeCallbackDisabled = true;
7284
7285 vrc = ptrVM.vtable()->pfnVMR3Resume(ptrVM.rawUVM(), enmReason);
7286
7287 if (aReason == Reason_Snapshot)
7288 mVMStateChangeCallbackDisabled = false;
7289 }
7290
7291 HRESULT hrc = RT_SUCCESS(vrc) ? S_OK
7292 : setErrorBoth(VBOX_E_VM_ERROR, vrc, tr("Could not resume the machine execution (%Rrc)"), vrc);
7293
7294 LogFlowThisFunc(("hrc=%Rhrc\n", hrc));
7295 LogFlowThisFuncLeave();
7296 return hrc;
7297}
7298
7299/**
7300 * Internal entry point for saving state of a VM for a specific reason. This
7301 * method is completely synchronous.
7302 *
7303 * The machine state is already set appropriately. It is only changed when
7304 * saving state actually paused the VM (happens with live snapshots and
7305 * teleportation), and in this case reflects the now paused variant.
7306 *
7307 * @note Locks this object for writing.
7308 */
7309HRESULT Console::i_saveState(Reason_T aReason, const ComPtr<IProgress> &aProgress, const ComPtr<ISnapshot> &aSnapshot,
7310 const Utf8Str &aStateFilePath, bool aPauseVM, bool &aLeftPaused)
7311{
7312 LogFlowThisFuncEnter();
7313 aLeftPaused = false;
7314
7315 AssertReturn(!aProgress.isNull(), E_INVALIDARG);
7316 AssertReturn(!aStateFilePath.isEmpty(), E_INVALIDARG);
7317 Assert(aSnapshot.isNull() || aReason == Reason_Snapshot);
7318
7319 AutoCaller autoCaller(this);
7320 if (FAILED(autoCaller.hrc())) return autoCaller.hrc();
7321
7322 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
7323
7324 LogFlowThisFunc(("mMachineState=%d\n", mMachineState));
7325 if ( mMachineState != MachineState_Saving
7326 && mMachineState != MachineState_LiveSnapshotting
7327 && mMachineState != MachineState_OnlineSnapshotting
7328 && mMachineState != MachineState_Teleporting
7329 && mMachineState != MachineState_TeleportingPausedVM)
7330 return setError(VBOX_E_INVALID_VM_STATE,
7331 tr("Cannot save the execution state as the machine is not running or paused (machine state: %s)"),
7332 Global::stringifyMachineState(mMachineState));
7333 bool fContinueAfterwards = mMachineState != MachineState_Saving;
7334
7335 Bstr strDisableSaveState;
7336 mMachine->GetExtraData(Bstr("VBoxInternal2/DisableSaveState").raw(), strDisableSaveState.asOutParam());
7337 if (strDisableSaveState == "1")
7338 return setError(VBOX_E_VM_ERROR,
7339 tr("Saving the execution state is disabled for this VM"));
7340
7341 if (aReason != Reason_Unspecified)
7342 LogRel(("Saving state of VM, reason '%s'\n", ::stringifyReason(aReason)));
7343
7344 /* ensure the directory for the saved state file exists */
7345 {
7346 Utf8Str dir = aStateFilePath;
7347 dir.stripFilename();
7348 if (!RTDirExists(dir.c_str()))
7349 {
7350 int vrc = RTDirCreateFullPath(dir.c_str(), 0700);
7351 if (RT_FAILURE(vrc))
7352 return setErrorBoth(VBOX_E_FILE_ERROR, vrc, tr("Could not create a directory '%s' to save the state to (%Rrc)"),
7353 dir.c_str(), vrc);
7354 }
7355 }
7356
7357 /* Get the VM handle early, we need it in several places. */
7358 SafeVMPtr ptrVM(this);
7359 HRESULT hrc = ptrVM.hrc();
7360 if (SUCCEEDED(hrc))
7361 {
7362 bool fPaused = false;
7363 if (aPauseVM)
7364 {
7365 /* release the lock before a VMR3* call (EMT might wait for it, @bugref{7648})! */
7366 alock.release();
7367 VMSUSPENDREASON enmReason = VMSUSPENDREASON_USER;
7368 if (aReason == Reason_HostSuspend)
7369 enmReason = VMSUSPENDREASON_HOST_SUSPEND;
7370 else if (aReason == Reason_HostBatteryLow)
7371 enmReason = VMSUSPENDREASON_HOST_BATTERY_LOW;
7372 int vrc = ptrVM.vtable()->pfnVMR3Suspend(ptrVM.rawUVM(), enmReason);
7373 alock.acquire();
7374
7375 if (RT_SUCCESS(vrc))
7376 fPaused = true;
7377 else
7378 hrc = setErrorBoth(VBOX_E_VM_ERROR, vrc, tr("Could not suspend the machine execution (%Rrc)"), vrc);
7379 }
7380
7381 Bstr bstrStateKeyId;
7382 Bstr bstrStateKeyStore;
7383#ifdef VBOX_WITH_FULL_VM_ENCRYPTION
7384 if (SUCCEEDED(hrc))
7385 {
7386 hrc = mMachine->COMGETTER(StateKeyId)(bstrStateKeyId.asOutParam());
7387 if (SUCCEEDED(hrc))
7388 {
7389 hrc = mMachine->COMGETTER(StateKeyStore)(bstrStateKeyStore.asOutParam());
7390 if (FAILED(hrc))
7391 hrc = setError(hrc, tr("Could not get key store for state file(%Rhrc (0x%08X))"), hrc, hrc);
7392 }
7393 else
7394 hrc = setError(hrc, tr("Could not get key id for state file(%Rhrc (0x%08X))"), hrc, hrc);
7395 }
7396#endif
7397
7398 if (SUCCEEDED(hrc))
7399 {
7400 LogFlowFunc(("Saving the state to '%s'...\n", aStateFilePath.c_str()));
7401
7402 mpVmm2UserMethods->pISnapshot = aSnapshot;
7403 mptrCancelableProgress = aProgress;
7404
7405 SsmStream ssmStream(this, ptrVM.vtable(), m_pKeyStore, bstrStateKeyId, bstrStateKeyStore);
7406 int vrc = ssmStream.create(aStateFilePath.c_str());
7407 if (RT_SUCCESS(vrc))
7408 {
7409 PCSSMSTRMOPS pStreamOps = NULL;
7410 void *pvStreamOpsUser = NULL;
7411 vrc = ssmStream.querySsmStrmOps(&pStreamOps, &pvStreamOpsUser);
7412 if (RT_SUCCESS(vrc))
7413 {
7414 alock.release();
7415
7416 vrc = ptrVM.vtable()->pfnVMR3Save(ptrVM.rawUVM(),
7417 NULL /*pszFilename*/,
7418 pStreamOps,
7419 pvStreamOpsUser,
7420 fContinueAfterwards,
7421 Console::i_stateProgressCallback,
7422 static_cast<IProgress *>(aProgress),
7423 &aLeftPaused);
7424
7425 alock.acquire();
7426 }
7427
7428 ssmStream.close();
7429 if (RT_FAILURE(vrc))
7430 {
7431 int vrc2 = RTFileDelete(aStateFilePath.c_str());
7432 AssertRC(vrc2);
7433 }
7434 }
7435
7436 mpVmm2UserMethods->pISnapshot = NULL;
7437 mptrCancelableProgress.setNull();
7438 if (RT_SUCCESS(vrc))
7439 {
7440 Assert(fContinueAfterwards || !aLeftPaused);
7441
7442 if (!fContinueAfterwards)
7443 {
7444 /*
7445 * The machine has been successfully saved, so power it down
7446 * (vmstateChangeCallback() will set state to Saved on success).
7447 * Note: we release the VM caller, otherwise it will deadlock.
7448 */
7449 ptrVM.release();
7450 alock.release();
7451 autoCaller.release();
7452
7453 HRESULT hrc2 = i_powerDown();
7454 AssertComRC(hrc2);
7455
7456 autoCaller.add();
7457 alock.acquire();
7458 }
7459 else if (fPaused)
7460 aLeftPaused = true;
7461 }
7462 else
7463 {
7464 if (fPaused)
7465 {
7466 alock.release();
7467 ptrVM.vtable()->pfnVMR3Resume(ptrVM.rawUVM(), VMRESUMEREASON_STATE_RESTORED);
7468 alock.acquire();
7469 }
7470 hrc = setErrorBoth(E_FAIL, vrc, tr("Failed to save the machine state to '%s' (%Rrc)"),
7471 aStateFilePath.c_str(), vrc);
7472 }
7473 }
7474 }
7475
7476 LogFlowFuncLeave();
7477 return S_OK;
7478}
7479
7480/**
7481 * Internal entry point for cancelling a VM save state.
7482 *
7483 * @note Locks this object for writing.
7484 */
7485HRESULT Console::i_cancelSaveState()
7486{
7487 LogFlowThisFuncEnter();
7488
7489 AutoCaller autoCaller(this);
7490 if (FAILED(autoCaller.hrc())) return autoCaller.hrc();
7491
7492 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
7493
7494 /* Get the VM handle. */
7495 SafeVMPtr ptrVM(this);
7496 HRESULT hrc = ptrVM.hrc();
7497 if (SUCCEEDED(hrc))
7498 ptrVM.vtable()->pfnSSMR3Cancel(ptrVM.rawUVM());
7499
7500 LogFlowFuncLeave();
7501 return hrc;
7502}
7503
7504#ifdef VBOX_WITH_AUDIO_RECORDING
7505/**
7506 * Sends audio (frame) data to the recording routines.
7507 *
7508 * @returns HRESULT
7509 * @param pvData Audio data to send.
7510 * @param cbData Size (in bytes) of audio data to send.
7511 * @param uTimestampMs Timestamp (in ms) of audio data.
7512 */
7513HRESULT Console::i_recordingSendAudio(const void *pvData, size_t cbData, uint64_t uTimestampMs)
7514{
7515 if ( mRecording.mCtx.IsStarted()
7516 && mRecording.mCtx.IsFeatureEnabled(RecordingFeature_Audio))
7517 {
7518 int vrc = mRecording.mCtx.SendAudioFrame(pvData, cbData, uTimestampMs);
7519 if (RT_FAILURE(vrc))
7520 return E_FAIL;
7521 }
7522
7523 return S_OK;
7524}
7525#endif /* VBOX_WITH_AUDIO_RECORDING */
7526
7527#ifdef VBOX_WITH_RECORDING
7528
7529int Console::i_recordingGetSettings(settings::RecordingSettings &recording)
7530{
7531 Assert(mMachine.isNotNull());
7532
7533 recording.applyDefaults();
7534
7535 ComPtr<IRecordingSettings> pRecordSettings;
7536 HRESULT hrc = mMachine->COMGETTER(RecordingSettings)(pRecordSettings.asOutParam());
7537 AssertComRCReturn(hrc, VERR_INVALID_PARAMETER);
7538
7539 BOOL fTemp;
7540 hrc = pRecordSettings->COMGETTER(Enabled)(&fTemp);
7541 AssertComRCReturn(hrc, VERR_INVALID_PARAMETER);
7542 recording.common.fEnabled = RT_BOOL(fTemp);
7543
7544 SafeIfaceArray<IRecordingScreenSettings> paRecScreens;
7545 hrc = pRecordSettings->COMGETTER(Screens)(ComSafeArrayAsOutParam(paRecScreens));
7546 AssertComRCReturn(hrc, VERR_INVALID_PARAMETER);
7547
7548 for (unsigned long i = 0; i < (unsigned long)paRecScreens.size(); ++i)
7549 {
7550 settings::RecordingScreenSettings recScreenSettings;
7551 ComPtr<IRecordingScreenSettings> pRecScreenSettings = paRecScreens[i];
7552
7553 hrc = pRecScreenSettings->COMGETTER(Enabled)(&fTemp);
7554 AssertComRCReturn(hrc, VERR_INVALID_PARAMETER);
7555 recScreenSettings.fEnabled = RT_BOOL(fTemp);
7556 com::SafeArray<RecordingFeature_T> vecFeatures;
7557 hrc = pRecScreenSettings->COMGETTER(Features)(ComSafeArrayAsOutParam(vecFeatures));
7558 AssertComRCReturn(hrc, VERR_INVALID_PARAMETER);
7559 /* Make sure to clear map first, as we want to (re-)set enabled features. */
7560 recScreenSettings.featureMap.clear();
7561 for (size_t f = 0; f < vecFeatures.size(); ++f)
7562 {
7563 if (vecFeatures[f] == RecordingFeature_Audio)
7564 recScreenSettings.featureMap[RecordingFeature_Audio] = true;
7565 else if (vecFeatures[f] == RecordingFeature_Video)
7566 recScreenSettings.featureMap[RecordingFeature_Video] = true;
7567 }
7568 hrc = pRecScreenSettings->COMGETTER(MaxTime)((ULONG *)&recScreenSettings.ulMaxTimeS);
7569 AssertComRCReturn(hrc, VERR_INVALID_PARAMETER);
7570 hrc = pRecScreenSettings->COMGETTER(MaxFileSize)((ULONG *)&recScreenSettings.File.ulMaxSizeMB);
7571 AssertComRCReturn(hrc, VERR_INVALID_PARAMETER);
7572 Bstr bstrTemp;
7573 hrc = pRecScreenSettings->COMGETTER(Filename)(bstrTemp.asOutParam());
7574 AssertComRCReturn(hrc, VERR_INVALID_PARAMETER);
7575 recScreenSettings.File.strName = bstrTemp;
7576 hrc = pRecScreenSettings->COMGETTER(Options)(bstrTemp.asOutParam());
7577 AssertComRCReturn(hrc, VERR_INVALID_PARAMETER);
7578 recScreenSettings.strOptions = bstrTemp;
7579 hrc = pRecScreenSettings->COMGETTER(AudioCodec)(&recScreenSettings.Audio.enmCodec);
7580 AssertComRCReturn(hrc, VERR_INVALID_PARAMETER);
7581 hrc = pRecScreenSettings->COMGETTER(AudioDeadline)(&recScreenSettings.Audio.enmDeadline);
7582 AssertComRCReturn(hrc, VERR_INVALID_PARAMETER);
7583 hrc = pRecScreenSettings->COMGETTER(AudioRateControlMode)(&recScreenSettings.Audio.enmRateCtlMode);
7584 AssertComRCReturn(hrc, VERR_INVALID_PARAMETER);
7585 hrc = pRecScreenSettings->COMGETTER(AudioHz)((ULONG *)&recScreenSettings.Audio.uHz);
7586 AssertComRCReturn(hrc, VERR_INVALID_PARAMETER);
7587 hrc = pRecScreenSettings->COMGETTER(AudioBits)((ULONG *)&recScreenSettings.Audio.cBits);
7588 AssertComRCReturn(hrc, VERR_INVALID_PARAMETER);
7589 hrc = pRecScreenSettings->COMGETTER(AudioChannels)((ULONG *)&recScreenSettings.Audio.cChannels);
7590 AssertComRCReturn(hrc, VERR_INVALID_PARAMETER);
7591 hrc = pRecScreenSettings->COMGETTER(VideoCodec)(&recScreenSettings.Video.enmCodec);
7592 AssertComRCReturn(hrc, VERR_INVALID_PARAMETER);
7593 hrc = pRecScreenSettings->COMGETTER(VideoWidth)((ULONG *)&recScreenSettings.Video.ulWidth);
7594 AssertComRCReturn(hrc, VERR_INVALID_PARAMETER);
7595 hrc = pRecScreenSettings->COMGETTER(VideoHeight)((ULONG *)&recScreenSettings.Video.ulHeight);
7596 AssertComRCReturn(hrc, VERR_INVALID_PARAMETER);
7597 hrc = pRecScreenSettings->COMGETTER(VideoDeadline)(&recScreenSettings.Video.enmDeadline);
7598 AssertComRCReturn(hrc, VERR_INVALID_PARAMETER);
7599 hrc = pRecScreenSettings->COMGETTER(VideoRateControlMode)(&recScreenSettings.Video.enmRateCtlMode);
7600 AssertComRCReturn(hrc, VERR_INVALID_PARAMETER);
7601 hrc = pRecScreenSettings->COMGETTER(VideoScalingMode)(&recScreenSettings.Video.enmScalingMode);
7602 AssertComRCReturn(hrc, VERR_INVALID_PARAMETER);
7603 hrc = pRecScreenSettings->COMGETTER(VideoRate)((ULONG *)&recScreenSettings.Video.ulRate);
7604 AssertComRCReturn(hrc, VERR_INVALID_PARAMETER);
7605 hrc = pRecScreenSettings->COMGETTER(VideoFPS)((ULONG *)&recScreenSettings.Video.ulFPS);
7606 AssertComRCReturn(hrc, VERR_INVALID_PARAMETER);
7607
7608 recording.mapScreens[i] = recScreenSettings;
7609 }
7610
7611 Assert(recording.mapScreens.size() == paRecScreens.size());
7612
7613 return VINF_SUCCESS;
7614}
7615
7616/**
7617 * Creates the recording context.
7618 *
7619 * @returns VBox status code.
7620 */
7621int Console::i_recordingCreate(ComPtr<IProgress> &pProgress)
7622{
7623 settings::RecordingSettings recordingSettings;
7624 int vrc = i_recordingGetSettings(recordingSettings);
7625 if (RT_SUCCESS(vrc))
7626 vrc = mRecording.mCtx.Create(this, recordingSettings, pProgress);
7627
7628 if (RT_FAILURE(vrc))
7629 setErrorBoth(VBOX_E_RECORDING_ERROR, vrc, tr("Recording initialization failed (%Rrc) -- please consult log file for details"), vrc);
7630
7631 LogFlowFuncLeaveRC(vrc);
7632 return vrc;
7633}
7634
7635/**
7636 * Destroys the recording context.
7637 */
7638void Console::i_recordingDestroy(void)
7639{
7640 mRecording.mCtx.Destroy();
7641}
7642
7643/**
7644 * Starts recording. Does nothing if recording is already started.
7645 *
7646 * @returns VBox status code.
7647 */
7648int Console::i_recordingStart(util::AutoWriteLock *pAutoLock /* = NULL */)
7649{
7650 RT_NOREF(pAutoLock);
7651
7652 if (mRecording.mCtx.IsStarted())
7653 return VINF_SUCCESS;
7654
7655 int vrc = mRecording.mCtx.Start();
7656 if (RT_SUCCESS(vrc))
7657 vrc = mDisplay->i_recordingStart();
7658
7659 if (RT_FAILURE(vrc))
7660 mRecording.mCtx.SetError(vrc, Utf8StrFmt(tr("Recording start failed (%Rrc)"), vrc).c_str());
7661
7662 LogFlowFuncLeaveRC(vrc);
7663 return vrc;
7664}
7665
7666/**
7667 * Stops recording. Does nothing if recording is not in started state.
7668 *
7669 * Note: This does *not* disable recording for a VM, in other words,
7670 * it does not change the VM's recording (enabled) setting.
7671 */
7672int Console::i_recordingStop(util::AutoWriteLock *)
7673{
7674 if (!mRecording.mCtx.IsStarted())
7675 return VINF_SUCCESS;
7676
7677 int vrc = mRecording.mCtx.Stop();
7678 if (RT_SUCCESS(vrc))
7679 vrc = mDisplay->i_recordingStop();
7680
7681 if (RT_FAILURE(vrc))
7682 setErrorBoth(VBOX_E_RECORDING_ERROR, vrc, tr("Recording stop failed (%Rrc)"), vrc);
7683
7684 LogFlowFuncLeaveRC(vrc);
7685 return vrc;
7686}
7687
7688/**
7689 * Sends a cursor shape change to the recording context.
7690 *
7691 * @returns VBox status code.
7692 * @param fVisible Whether the mouse cursor actually is visible or not.
7693 * @param fAlpha Whether the pixel data contains alpha channel information or not.
7694 * @param xHot X hot position (in pixel) of the new cursor.
7695 * @param yHot Y hot position (in pixel) of the new cursor.
7696 * @param uWidth Width (in pixel) of the new cursor.
7697 * @param uHeight Height (in pixel) of the new cursor.
7698 * @param pu8Shape Pixel data of the new cursor.
7699 * @param cbShape Size of \a pu8Shape (in bytes).
7700 */
7701int 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)
7702{
7703 if (!mRecording.mCtx.IsStarted())
7704 return VINF_SUCCESS;
7705
7706 return mRecording.mCtx.SendCursorShapeChange(fVisible, fAlpha, xHot, yHot, uWidth, uHeight, pu8Shape, cbShape,
7707 mRecording.mCtx.GetCurrentPTS());
7708}
7709#endif /* VBOX_WITH_RECORDING */
7710
7711/**
7712 * Gets called by Session::UpdateMachineState()
7713 * (IInternalSessionControl::updateMachineState()).
7714 *
7715 * Must be called only in certain cases (see the implementation).
7716 *
7717 * @note Locks this object for writing.
7718 */
7719HRESULT Console::i_updateMachineState(MachineState_T aMachineState)
7720{
7721 AutoCaller autoCaller(this);
7722 AssertComRCReturnRC(autoCaller.hrc());
7723
7724 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
7725
7726 AssertReturn( mMachineState == MachineState_Saving
7727 || mMachineState == MachineState_OnlineSnapshotting
7728 || mMachineState == MachineState_LiveSnapshotting
7729 || mMachineState == MachineState_DeletingSnapshotOnline
7730 || mMachineState == MachineState_DeletingSnapshotPaused
7731 || aMachineState == MachineState_Saving
7732 || aMachineState == MachineState_OnlineSnapshotting
7733 || aMachineState == MachineState_LiveSnapshotting
7734 || aMachineState == MachineState_DeletingSnapshotOnline
7735 || aMachineState == MachineState_DeletingSnapshotPaused
7736 , E_FAIL);
7737
7738 return i_setMachineStateLocally(aMachineState);
7739}
7740
7741/**
7742 * Gets called by Session::COMGETTER(NominalState)()
7743 * (IInternalSessionControl::getNominalState()).
7744 *
7745 * @note Locks this object for reading.
7746 */
7747HRESULT Console::i_getNominalState(MachineState_T &aNominalState)
7748{
7749 LogFlowThisFuncEnter();
7750
7751 AutoCaller autoCaller(this);
7752 AssertComRCReturnRC(autoCaller.hrc());
7753
7754 /* Get the VM handle. */
7755 SafeVMPtr ptrVM(this);
7756 if (!ptrVM.isOk())
7757 return ptrVM.hrc();
7758
7759 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
7760
7761 MachineState_T enmMachineState = MachineState_Null;
7762 VMSTATE enmVMState = ptrVM.vtable()->pfnVMR3GetStateU(ptrVM.rawUVM());
7763 switch (enmVMState)
7764 {
7765 case VMSTATE_CREATING:
7766 case VMSTATE_CREATED:
7767 case VMSTATE_POWERING_ON:
7768 enmMachineState = MachineState_Starting;
7769 break;
7770 case VMSTATE_LOADING:
7771 enmMachineState = MachineState_Restoring;
7772 break;
7773 case VMSTATE_RESUMING:
7774 case VMSTATE_SUSPENDING:
7775 case VMSTATE_SUSPENDING_LS:
7776 case VMSTATE_SUSPENDING_EXT_LS:
7777 case VMSTATE_SUSPENDED:
7778 case VMSTATE_SUSPENDED_LS:
7779 case VMSTATE_SUSPENDED_EXT_LS:
7780 enmMachineState = MachineState_Paused;
7781 break;
7782 case VMSTATE_RUNNING:
7783 case VMSTATE_RUNNING_LS:
7784 case VMSTATE_RESETTING:
7785 case VMSTATE_RESETTING_LS:
7786 case VMSTATE_SOFT_RESETTING:
7787 case VMSTATE_SOFT_RESETTING_LS:
7788 case VMSTATE_DEBUGGING:
7789 case VMSTATE_DEBUGGING_LS:
7790 enmMachineState = MachineState_Running;
7791 break;
7792 case VMSTATE_SAVING:
7793 enmMachineState = MachineState_Saving;
7794 break;
7795 case VMSTATE_POWERING_OFF:
7796 case VMSTATE_POWERING_OFF_LS:
7797 case VMSTATE_DESTROYING:
7798 enmMachineState = MachineState_Stopping;
7799 break;
7800 case VMSTATE_OFF:
7801 case VMSTATE_OFF_LS:
7802 case VMSTATE_FATAL_ERROR:
7803 case VMSTATE_FATAL_ERROR_LS:
7804 case VMSTATE_LOAD_FAILURE:
7805 case VMSTATE_TERMINATED:
7806 enmMachineState = MachineState_PoweredOff;
7807 break;
7808 case VMSTATE_GURU_MEDITATION:
7809 case VMSTATE_GURU_MEDITATION_LS:
7810 enmMachineState = MachineState_Stuck;
7811 break;
7812 default:
7813 AssertMsgFailed(("%s\n", ptrVM.vtable()->pfnVMR3GetStateName(enmVMState)));
7814 enmMachineState = MachineState_PoweredOff;
7815 }
7816 aNominalState = enmMachineState;
7817
7818 LogFlowFuncLeave();
7819 return S_OK;
7820}
7821
7822void Console::i_onMousePointerShapeChange(bool fVisible, bool fAlpha,
7823 uint32_t xHot, uint32_t yHot,
7824 uint32_t width, uint32_t height,
7825 const uint8_t *pu8Shape,
7826 uint32_t cbShape)
7827{
7828#if 0
7829 LogFlowThisFuncEnter();
7830 LogFlowThisFunc(("fVisible=%d, fAlpha=%d, xHot = %d, yHot = %d, width=%d, height=%d, shape=%p\n",
7831 fVisible, fAlpha, xHot, yHot, width, height, pShape));
7832#endif
7833
7834 AutoCaller autoCaller(this);
7835 AssertComRCReturnVoid(autoCaller.hrc());
7836
7837 if (!mMouse.isNull())
7838 mMouse->i_updatePointerShape(fVisible, fAlpha, xHot, yHot, width, height, pu8Shape, cbShape);
7839
7840 com::SafeArray<BYTE> shape(cbShape);
7841 if (pu8Shape)
7842 memcpy(shape.raw(), pu8Shape, cbShape);
7843 ::FireMousePointerShapeChangedEvent(mEventSource, fVisible, fAlpha, xHot, yHot, width, height, ComSafeArrayAsInParam(shape));
7844
7845#ifdef VBOX_WITH_RECORDING
7846 i_recordingCursorShapeChange(fVisible, fAlpha, xHot, yHot, width, height, pu8Shape, cbShape);
7847#endif
7848
7849#if 0
7850 LogFlowThisFuncLeave();
7851#endif
7852}
7853
7854void Console::i_onMouseCapabilityChange(BOOL supportsAbsolute, BOOL supportsRelative,
7855 BOOL supportsTouchScreen, BOOL supportsTouchPad, BOOL needsHostCursor)
7856{
7857 LogFlowThisFunc(("supportsAbsolute=%d supportsRelative=%d supportsTouchScreen=%d supportsTouchPad=%d needsHostCursor=%d\n",
7858 supportsAbsolute, supportsRelative, supportsTouchScreen, supportsTouchPad, needsHostCursor));
7859
7860 AutoCaller autoCaller(this);
7861 AssertComRCReturnVoid(autoCaller.hrc());
7862
7863 ::FireMouseCapabilityChangedEvent(mEventSource, supportsAbsolute, supportsRelative, supportsTouchScreen, supportsTouchPad, needsHostCursor);
7864}
7865
7866void Console::i_onStateChange(MachineState_T machineState)
7867{
7868 AutoCaller autoCaller(this);
7869 AssertComRCReturnVoid(autoCaller.hrc());
7870 ::FireStateChangedEvent(mEventSource, machineState);
7871}
7872
7873void Console::i_onAdditionsStateChange()
7874{
7875 AutoCaller autoCaller(this);
7876 AssertComRCReturnVoid(autoCaller.hrc());
7877
7878 ::FireAdditionsStateChangedEvent(mEventSource);
7879}
7880
7881/**
7882 * @remarks This notification only is for reporting an incompatible
7883 * Guest Additions interface, *not* the Guest Additions version!
7884 *
7885 * The user will be notified inside the guest if new Guest
7886 * Additions are available (via VBoxTray/VBoxClient).
7887 */
7888void Console::i_onAdditionsOutdated()
7889{
7890 AutoCaller autoCaller(this);
7891 AssertComRCReturnVoid(autoCaller.hrc());
7892
7893 /** @todo implement this */
7894}
7895
7896void Console::i_onKeyboardLedsChange(bool fNumLock, bool fCapsLock, bool fScrollLock)
7897{
7898 AutoCaller autoCaller(this);
7899 AssertComRCReturnVoid(autoCaller.hrc());
7900
7901 ::FireKeyboardLedsChangedEvent(mEventSource, fNumLock, fCapsLock, fScrollLock);
7902}
7903
7904void Console::i_onUSBDeviceStateChange(IUSBDevice *aDevice, bool aAttached,
7905 IVirtualBoxErrorInfo *aError)
7906{
7907 AutoCaller autoCaller(this);
7908 AssertComRCReturnVoid(autoCaller.hrc());
7909
7910 ::FireUSBDeviceStateChangedEvent(mEventSource, aDevice, aAttached, aError);
7911}
7912
7913void Console::i_onRuntimeError(BOOL aFatal, IN_BSTR aErrorID, IN_BSTR aMessage)
7914{
7915 AutoCaller autoCaller(this);
7916 AssertComRCReturnVoid(autoCaller.hrc());
7917
7918 ::FireRuntimeErrorEvent(mEventSource, aFatal, aErrorID, aMessage);
7919}
7920
7921HRESULT Console::i_onShowWindow(BOOL aCheck, BOOL *aCanShow, LONG64 *aWinId)
7922{
7923 AssertReturn(aCanShow, E_POINTER);
7924 AssertReturn(aWinId, E_POINTER);
7925
7926 *aCanShow = FALSE;
7927 *aWinId = 0;
7928
7929 AutoCaller autoCaller(this);
7930 AssertComRCReturnRC(autoCaller.hrc());
7931
7932 ComPtr<IEvent> ptrEvent;
7933 if (aCheck)
7934 {
7935 *aCanShow = TRUE;
7936 HRESULT hrc = ::CreateCanShowWindowEvent(ptrEvent.asOutParam(), mEventSource);
7937 if (SUCCEEDED(hrc))
7938 {
7939 VBoxEventDesc EvtDesc(ptrEvent, mEventSource);
7940 BOOL fDelivered = EvtDesc.fire(5000); /* Wait up to 5 secs for delivery */
7941 //Assert(fDelivered);
7942 if (fDelivered)
7943 {
7944 // bit clumsy
7945 ComPtr<ICanShowWindowEvent> ptrCanShowEvent = ptrEvent;
7946 if (ptrCanShowEvent)
7947 {
7948 BOOL fVetoed = FALSE;
7949 BOOL fApproved = FALSE;
7950 ptrCanShowEvent->IsVetoed(&fVetoed);
7951 ptrCanShowEvent->IsApproved(&fApproved);
7952 *aCanShow = fApproved || !fVetoed;
7953 }
7954 else
7955 AssertFailed();
7956 }
7957 }
7958 }
7959 else
7960 {
7961 HRESULT hrc = ::CreateShowWindowEvent(ptrEvent.asOutParam(), mEventSource, 0);
7962 if (SUCCEEDED(hrc))
7963 {
7964 VBoxEventDesc EvtDesc(ptrEvent, mEventSource);
7965 BOOL fDelivered = EvtDesc.fire(5000); /* Wait up to 5 secs for delivery */
7966 //Assert(fDelivered);
7967 if (fDelivered)
7968 {
7969 ComPtr<IShowWindowEvent> ptrShowEvent = ptrEvent;
7970 if (ptrShowEvent)
7971 {
7972 LONG64 idWindow = 0;
7973 ptrShowEvent->COMGETTER(WinId)(&idWindow);
7974 if (idWindow != 0 && *aWinId == 0)
7975 *aWinId = idWindow;
7976 }
7977 else
7978 AssertFailed();
7979 }
7980 }
7981 }
7982
7983 return S_OK;
7984}
7985
7986// private methods
7987////////////////////////////////////////////////////////////////////////////////
7988
7989/**
7990 * Loads the VMM if needed.
7991 *
7992 * @returns COM status.
7993 * @param pszVMMMod The VMM module to load.
7994 * @remarks Caller must write lock the console object.
7995 */
7996HRESULT Console::i_loadVMM(const char *pszVMMMod) RT_NOEXCEPT
7997{
7998 if ( mhModVMM == NIL_RTLDRMOD
7999 || mpVMM == NULL)
8000 {
8001 Assert(!mpVMM);
8002
8003 HRESULT hrc;
8004 RTERRINFOSTATIC ErrInfo;
8005 RTLDRMOD hModVMM = NIL_RTLDRMOD;
8006 int vrc = SUPR3HardenedLdrLoadAppPriv(pszVMMMod, &hModVMM, RTLDRLOAD_FLAGS_LOCAL, RTErrInfoInitStatic(&ErrInfo));
8007 if (RT_SUCCESS(vrc))
8008 {
8009 PFNVMMGETVTABLE pfnGetVTable = NULL;
8010 vrc = RTLdrGetSymbol(hModVMM, VMMR3VTABLE_GETTER_NAME, (void **)&pfnGetVTable);
8011 if (pfnGetVTable)
8012 {
8013 PCVMMR3VTABLE pVMM = pfnGetVTable();
8014 if (pVMM)
8015 {
8016 if (VMMR3VTABLE_IS_COMPATIBLE(pVMM->uMagicVersion))
8017 {
8018 if (pVMM->uMagicVersion == pVMM->uMagicVersionEnd)
8019 {
8020 mhModVMM = hModVMM;
8021 mpVMM = pVMM;
8022 LogFunc(("mhLdrVMM=%p phVMM=%p uMagicVersion=%#RX64\n", hModVMM, pVMM, pVMM->uMagicVersion));
8023 return S_OK;
8024 }
8025
8026 hrc = setErrorVrc(vrc, "Bogus VMM vtable: uMagicVersion=%#RX64 uMagicVersionEnd=%#RX64",
8027 pVMM->uMagicVersion, pVMM->uMagicVersionEnd);
8028 }
8029 else
8030 hrc = setErrorVrc(vrc, "Incompatible of bogus VMM version magic: %#RX64", pVMM->uMagicVersion);
8031 }
8032 else
8033 hrc = setErrorVrc(vrc, "pfnGetVTable return NULL!");
8034 }
8035 else
8036 hrc = setErrorVrc(vrc, "Failed to locate symbol '%s' in VBoxVMM: %Rrc", VMMR3VTABLE_GETTER_NAME, vrc);
8037 RTLdrClose(hModVMM);
8038 }
8039 else
8040 hrc = setErrorVrc(vrc, "Failed to load VBoxVMM: %#RTeic", &ErrInfo.Core);
8041 return hrc;
8042 }
8043
8044 return S_OK;
8045}
8046
8047/**
8048 * Increases the usage counter of the mpUVM pointer.
8049 *
8050 * Guarantees that VMR3Destroy() will not be called on it at least until
8051 * releaseVMCaller() is called.
8052 *
8053 * If this method returns a failure, the caller is not allowed to use mpUVM and
8054 * may return the failed result code to the upper level. This method sets the
8055 * extended error info on failure if \a aQuiet is false.
8056 *
8057 * Setting \a aQuiet to true is useful for methods that don't want to return
8058 * the failed result code to the caller when this method fails (e.g. need to
8059 * silently check for the mpUVM availability).
8060 *
8061 * When mpUVM is NULL but \a aAllowNullVM is true, a corresponding error will be
8062 * returned instead of asserting. Having it false is intended as a sanity check
8063 * for methods that have checked mMachineState and expect mpUVM *NOT* to be
8064 * NULL.
8065 *
8066 * @param aQuiet true to suppress setting error info
8067 * @param aAllowNullVM true to accept mpUVM being NULL and return a failure
8068 * (otherwise this method will assert if mpUVM is NULL)
8069 *
8070 * @note Locks this object for writing.
8071 */
8072HRESULT Console::i_addVMCaller(bool aQuiet /* = false */,
8073 bool aAllowNullVM /* = false */)
8074{
8075 RT_NOREF(aAllowNullVM);
8076 AutoCaller autoCaller(this);
8077 /** @todo Fix race during console/VM reference destruction, refer @bugref{6318}
8078 * comment 25. */
8079 if (FAILED(autoCaller.hrc()))
8080 return autoCaller.hrc();
8081
8082 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
8083
8084 if (mVMDestroying)
8085 {
8086 /* powerDown() is waiting for all callers to finish */
8087 return aQuiet ? E_ACCESSDENIED : setError(E_ACCESSDENIED, tr("The virtual machine is being powered down"));
8088 }
8089
8090 if (mpUVM == NULL)
8091 {
8092 Assert(aAllowNullVM == true);
8093
8094 /* The machine is not powered up */
8095 return aQuiet ? E_ACCESSDENIED : setError(E_ACCESSDENIED, tr("The virtual machine is not powered up"));
8096 }
8097
8098 ++mVMCallers;
8099
8100 return S_OK;
8101}
8102
8103/**
8104 * Decreases the usage counter of the mpUVM pointer.
8105 *
8106 * Must always complete the addVMCaller() call after the mpUVM pointer is no
8107 * more necessary.
8108 *
8109 * @note Locks this object for writing.
8110 */
8111void Console::i_releaseVMCaller()
8112{
8113 AutoCaller autoCaller(this);
8114 AssertComRCReturnVoid(autoCaller.hrc());
8115
8116 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
8117
8118 AssertReturnVoid(mpUVM != NULL);
8119
8120 Assert(mVMCallers > 0);
8121 --mVMCallers;
8122
8123 if (mVMCallers == 0 && mVMDestroying)
8124 {
8125 /* inform powerDown() there are no more callers */
8126 RTSemEventSignal(mVMZeroCallersSem);
8127 }
8128}
8129
8130
8131/**
8132 * Helper for SafeVMPtrBase.
8133 */
8134HRESULT Console::i_safeVMPtrRetainer(PUVM *a_ppUVM, PCVMMR3VTABLE *a_ppVMM, bool a_Quiet) RT_NOEXCEPT
8135{
8136 *a_ppUVM = NULL;
8137 *a_ppVMM = NULL;
8138
8139 AutoCaller autoCaller(this);
8140 AssertComRCReturnRC(autoCaller.hrc());
8141 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
8142
8143 /*
8144 * Repeat the checks done by addVMCaller.
8145 */
8146 if (mVMDestroying) /* powerDown() is waiting for all callers to finish */
8147 return a_Quiet
8148 ? E_ACCESSDENIED
8149 : setError(E_ACCESSDENIED, tr("The virtual machine is being powered down"));
8150 PUVM const pUVM = mpUVM;
8151 if (!pUVM)
8152 return a_Quiet
8153 ? E_ACCESSDENIED
8154 : setError(E_ACCESSDENIED, tr("The virtual machine is powered off"));
8155 PCVMMR3VTABLE const pVMM = mpVMM;
8156 if (!pVMM)
8157 return a_Quiet
8158 ? E_ACCESSDENIED
8159 : setError(E_ACCESSDENIED, tr("No VMM loaded!"));
8160
8161 /*
8162 * Retain a reference to the user mode VM handle and get the global handle.
8163 */
8164 uint32_t cRefs = pVMM->pfnVMR3RetainUVM(pUVM);
8165 if (cRefs == UINT32_MAX)
8166 return a_Quiet
8167 ? E_ACCESSDENIED
8168 : setError(E_ACCESSDENIED, tr("The virtual machine is powered off"));
8169
8170 /* done */
8171 *a_ppUVM = pUVM;
8172 *a_ppVMM = pVMM;
8173 return S_OK;
8174}
8175
8176void Console::i_safeVMPtrReleaser(PUVM *a_ppUVM)
8177{
8178 PUVM const pUVM = *a_ppUVM;
8179 *a_ppUVM = NULL;
8180 if (pUVM)
8181 {
8182 PCVMMR3VTABLE const pVMM = mpVMM;
8183 if (pVMM)
8184 pVMM->pfnVMR3ReleaseUVM(pUVM);
8185 }
8186}
8187
8188#ifdef VBOX_WITH_FULL_VM_ENCRYPTION
8189
8190/*static*/ DECLCALLBACK(int)
8191Console::i_logEncryptedDirCtxOpen(PCRTLOGOUTPUTIF pIf, void *pvUser, const char *pszFilename, void **ppvDirCtx)
8192{
8193 RT_NOREF(pIf, pvUser, pszFilename, ppvDirCtx);
8194 *ppvDirCtx = (void *)(intptr_t)22;
8195 return VINF_SUCCESS;
8196}
8197
8198/*static*/ DECLCALLBACK(int)
8199Console::i_logEncryptedDirCtxClose(PCRTLOGOUTPUTIF pIf, void *pvUser, void *pvDirCtx)
8200{
8201 RT_NOREF(pIf, pvUser, pvDirCtx);
8202 Assert((intptr_t)pvDirCtx == 22);
8203 return VINF_SUCCESS;
8204}
8205
8206/*static*/ DECLCALLBACK(int)
8207Console::i_logEncryptedDelete(PCRTLOGOUTPUTIF pIf, void *pvUser, void *pvDirCtx, const char *pszFilename)
8208{
8209 RT_NOREF(pIf, pvDirCtx, pvUser);
8210 return RTFileDelete(pszFilename);
8211}
8212
8213
8214/*static*/ DECLCALLBACK(int)
8215Console::i_logEncryptedRename(PCRTLOGOUTPUTIF pIf, void *pvUser, void *pvDirCtx,
8216 const char *pszFilenameOld, const char *pszFilenameNew, uint32_t fFlags)
8217{
8218 RT_NOREF(pIf, pvDirCtx, pvUser);
8219 return RTFileRename(pszFilenameOld, pszFilenameNew, fFlags);
8220}
8221
8222/*static*/ DECLCALLBACK(int)
8223Console::i_logEncryptedOpen(PCRTLOGOUTPUTIF pIf, void *pvUser, void *pvDirCtx, const char *pszFilename, uint32_t fFlags)
8224{
8225 RT_NOREF(pIf, pvDirCtx);
8226 Console *pConsole = static_cast<Console *>(pvUser);
8227 RTVFSFILE hVfsFile = NIL_RTVFSFILE;
8228
8229 int vrc = RTVfsFileOpenNormal(pszFilename, fFlags, &hVfsFile);
8230 if (RT_SUCCESS(vrc))
8231 {
8232 PCVBOXCRYPTOIF pCryptoIf = NULL;
8233 vrc = pConsole->i_retainCryptoIf(&pCryptoIf);
8234 if (RT_SUCCESS(vrc))
8235 {
8236 SecretKey *pKey = NULL;
8237
8238 vrc = pConsole->m_pKeyStore->retainSecretKey(pConsole->m_strLogKeyId, &pKey);
8239 if (RT_SUCCESS(vrc))
8240 {
8241 const char *pszPassword = (const char *)pKey->getKeyBuffer();
8242
8243 vrc = pCryptoIf->pfnCryptoFileFromVfsFile(hVfsFile, pConsole->m_strLogKeyStore.c_str(), pszPassword,
8244 &pConsole->m_hVfsFileLog);
8245 pKey->release();
8246 }
8247
8248 /* On success we keep the reference to keep the cryptographic module loaded. */
8249 if (RT_FAILURE(vrc))
8250 pConsole->i_releaseCryptoIf(pCryptoIf);
8251 }
8252
8253 /* Always do this because the encrypted log has retained a reference to the underlying file. */
8254 RTVfsFileRelease(hVfsFile);
8255 if (RT_FAILURE(vrc))
8256 RTFileDelete(pszFilename);
8257 }
8258
8259 return vrc;
8260}
8261
8262
8263/*static*/ DECLCALLBACK(int)
8264Console::i_logEncryptedClose(PCRTLOGOUTPUTIF pIf, void *pvUser)
8265{
8266 RT_NOREF(pIf);
8267 Console *pConsole = static_cast<Console *>(pvUser);
8268
8269 RTVfsFileRelease(pConsole->m_hVfsFileLog);
8270 pConsole->m_hVfsFileLog = NIL_RTVFSFILE;
8271 return VINF_SUCCESS;
8272}
8273
8274
8275/*static*/ DECLCALLBACK(int)
8276Console::i_logEncryptedQuerySize(PCRTLOGOUTPUTIF pIf, void *pvUser, uint64_t *pcbSize)
8277{
8278 RT_NOREF(pIf);
8279 Console *pConsole = static_cast<Console *>(pvUser);
8280
8281 return RTVfsFileQuerySize(pConsole->m_hVfsFileLog, pcbSize);
8282}
8283
8284
8285/*static*/ DECLCALLBACK(int)
8286Console::i_logEncryptedWrite(PCRTLOGOUTPUTIF pIf, void *pvUser, const void *pvBuf, size_t cbWrite, size_t *pcbWritten)
8287{
8288 RT_NOREF(pIf);
8289 Console *pConsole = static_cast<Console *>(pvUser);
8290
8291 return RTVfsFileWrite(pConsole->m_hVfsFileLog, pvBuf, cbWrite, pcbWritten);
8292}
8293
8294
8295/*static*/ DECLCALLBACK(int)
8296Console::i_logEncryptedFlush(PCRTLOGOUTPUTIF pIf, void *pvUser)
8297{
8298 RT_NOREF(pIf);
8299 Console *pConsole = static_cast<Console *>(pvUser);
8300
8301 return RTVfsFileFlush(pConsole->m_hVfsFileLog);
8302}
8303
8304
8305/*static*/ RTLOGOUTPUTIF const Console::s_ConsoleEncryptedLogOutputIf =
8306{
8307 Console::i_logEncryptedDirCtxOpen,
8308 Console::i_logEncryptedDirCtxClose,
8309 Console::i_logEncryptedDelete,
8310 Console::i_logEncryptedRename,
8311 Console::i_logEncryptedOpen,
8312 Console::i_logEncryptedClose,
8313 Console::i_logEncryptedQuerySize,
8314 Console::i_logEncryptedWrite,
8315 Console::i_logEncryptedFlush
8316};
8317
8318#endif /* VBOX_WITH_FULL_VM_ENCRYPTION */
8319
8320/**
8321 * Initialize the release logging facility. In case something
8322 * goes wrong, there will be no release logging. Maybe in the future
8323 * we can add some logic to use different file names in this case.
8324 * Note that the logic must be in sync with Machine::DeleteSettings().
8325 */
8326HRESULT Console::i_consoleInitReleaseLog(const ComPtr<IMachine> aMachine)
8327{
8328 Bstr bstrLogFolder;
8329 HRESULT hrc = aMachine->COMGETTER(LogFolder)(bstrLogFolder.asOutParam());
8330 if (FAILED(hrc))
8331 return hrc;
8332 Utf8Str strLogDir = bstrLogFolder;
8333
8334 /* make sure the Logs folder exists */
8335 Assert(strLogDir.length());
8336 if (!RTDirExists(strLogDir.c_str()))
8337 RTDirCreateFullPath(strLogDir.c_str(), 0700);
8338
8339 Utf8StrFmt logFile("%s%cVBox.log", strLogDir.c_str(), RTPATH_DELIMITER);
8340 Utf8StrFmt pngFile("%s%cVBox.png", strLogDir.c_str(), RTPATH_DELIMITER);
8341
8342 /*
8343 * Age the old log files.
8344 * Rename .(n-1) to .(n), .(n-2) to .(n-1), ..., and the last log file to .1
8345 * Overwrite target files in case they exist.
8346 */
8347 ComPtr<IVirtualBox> pVirtualBox;
8348 aMachine->COMGETTER(Parent)(pVirtualBox.asOutParam());
8349 ComPtr<ISystemProperties> pSystemProperties;
8350 pVirtualBox->COMGETTER(SystemProperties)(pSystemProperties.asOutParam());
8351 ULONG cHistoryFiles = 3;
8352 pSystemProperties->COMGETTER(LogHistoryCount)(&cHistoryFiles);
8353 if (cHistoryFiles)
8354 {
8355 for (int i = cHistoryFiles - 1; i >= 0; i--)
8356 {
8357 Utf8Str *files[] = { &logFile, &pngFile };
8358 Utf8Str oldName, newName;
8359
8360 for (unsigned int j = 0; j < RT_ELEMENTS(files); ++j)
8361 {
8362 if (i > 0)
8363 oldName.printf("%s.%d", files[j]->c_str(), i);
8364 else
8365 oldName = *files[j];
8366 newName.printf("%s.%d", files[j]->c_str(), i + 1);
8367
8368 /* If the old file doesn't exist, delete the new file (if it
8369 * exists) to provide correct rotation even if the sequence is
8370 * broken */
8371 if (RTFileRename(oldName.c_str(), newName.c_str(), RTFILEMOVE_FLAGS_REPLACE) == VERR_FILE_NOT_FOUND)
8372 RTFileDelete(newName.c_str());
8373 }
8374 }
8375 }
8376
8377 Bstr bstrLogKeyId;
8378 Bstr bstrLogKeyStore;
8379 PCRTLOGOUTPUTIF pLogOutputIf = NULL;
8380 void *pvLogOutputUser = NULL;
8381 int vrc = VINF_SUCCESS;
8382#ifdef VBOX_WITH_FULL_VM_ENCRYPTION
8383 hrc = aMachine->COMGETTER(LogKeyId)(bstrLogKeyId.asOutParam());
8384 if (SUCCEEDED(hrc))
8385 {
8386 hrc = aMachine->COMGETTER(LogKeyStore)(bstrLogKeyStore.asOutParam());
8387 if ( SUCCEEDED(hrc)
8388 && bstrLogKeyId.isNotEmpty()
8389 && bstrLogKeyStore.isNotEmpty())
8390 {
8391 m_strLogKeyId = Utf8Str(bstrLogKeyId);
8392 m_strLogKeyStore = Utf8Str(bstrLogKeyStore);
8393
8394 pLogOutputIf = &s_ConsoleEncryptedLogOutputIf;
8395 pvLogOutputUser = this;
8396 m_fEncryptedLog = true;
8397 }
8398 }
8399
8400 if (RT_FAILURE(vrc))
8401 hrc = setErrorBoth(E_FAIL, vrc, tr("Failed to set encryption for release log (%Rrc)"), vrc);
8402 else
8403#endif
8404 {
8405 RTERRINFOSTATIC ErrInfo;
8406 vrc = com::VBoxLogRelCreateEx("VM", logFile.c_str(),
8407 RTLOGFLAGS_PREFIX_TIME_PROG | RTLOGFLAGS_RESTRICT_GROUPS,
8408 "all all.restrict -default.restrict",
8409 "VBOX_RELEASE_LOG", RTLOGDEST_FILE,
8410 32768 /* cMaxEntriesPerGroup */,
8411 0 /* cHistory */, 0 /* uHistoryFileTime */,
8412 0 /* uHistoryFileSize */,
8413 pLogOutputIf, pvLogOutputUser,
8414 RTErrInfoInitStatic(&ErrInfo));
8415 if (RT_FAILURE(vrc))
8416 hrc = setErrorBoth(E_FAIL, vrc, tr("Failed to open release log (%s, %Rrc)"), ErrInfo.Core.pszMsg, vrc);
8417 }
8418
8419 /* If we've made any directory changes, flush the directory to increase
8420 the likelihood that the log file will be usable after a system panic.
8421
8422 Tip: Try 'export VBOX_RELEASE_LOG_FLAGS=flush' if the last bits of the log
8423 is missing. Just don't have too high hopes for this to help. */
8424 if (SUCCEEDED(hrc) || cHistoryFiles)
8425 RTDirFlush(strLogDir.c_str());
8426
8427 return hrc;
8428}
8429
8430/**
8431 * Common worker for PowerUp and PowerUpPaused.
8432 *
8433 * @returns COM status code.
8434 *
8435 * @param aProgress Where to return the progress object.
8436 * @param aPaused true if PowerUpPaused called.
8437 */
8438HRESULT Console::i_powerUp(IProgress **aProgress, bool aPaused)
8439{
8440 LogFlowThisFuncEnter();
8441
8442 CheckComArgOutPointerValid(aProgress);
8443
8444 AutoCaller autoCaller(this);
8445 HRESULT hrc = autoCaller.hrc();
8446 if (FAILED(hrc))
8447 return hrc;
8448
8449 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
8450 LogFlowThisFunc(("mMachineState=%d\n", mMachineState));
8451
8452 if (Global::IsOnlineOrTransient(mMachineState))
8453 return setError(VBOX_E_INVALID_VM_STATE, tr("The virtual machine is already running or busy (machine state: %s)"),
8454 Global::stringifyMachineState(mMachineState));
8455
8456
8457 /* Set up release logging as early as possible after the check if
8458 * there is already a running VM which we shouldn't disturb. */
8459 hrc = i_consoleInitReleaseLog(mMachine);
8460 if (FAILED(hrc))
8461 return hrc;
8462
8463#ifdef VBOX_OPENSSL_FIPS
8464 LogRel(("crypto: FIPS mode %s\n", FIPS_mode() ? "enabled" : "FAILED"));
8465#endif
8466
8467 /* test and clear the TeleporterEnabled property */
8468 BOOL fTeleporterEnabled;
8469 hrc = mMachine->COMGETTER(TeleporterEnabled)(&fTeleporterEnabled);
8470 if (FAILED(hrc))
8471 return hrc;
8472
8473#if 0 /** @todo we should save it afterwards, but that isn't necessarily a good idea. Find a better place for this (VBoxSVC). */
8474 if (fTeleporterEnabled)
8475 {
8476 hrc = mMachine->COMSETTER(TeleporterEnabled)(FALSE);
8477 if (FAILED(hrc))
8478 return hrc;
8479 }
8480#endif
8481
8482 PCVMMR3VTABLE const pVMM = mpVMM;
8483 AssertPtrReturn(pVMM, E_UNEXPECTED);
8484
8485 ComObjPtr<Progress> pPowerupProgress;
8486 bool fBeganPoweringUp = false;
8487
8488 LONG cOperations = 1;
8489 LONG ulTotalOperationsWeight = 1;
8490 VMPowerUpTask *task = NULL;
8491
8492 try
8493 {
8494 /* Create a progress object to track progress of this operation. Must
8495 * be done as early as possible (together with BeginPowerUp()) as this
8496 * is vital for communicating as much as possible early powerup
8497 * failure information to the API caller */
8498 pPowerupProgress.createObject();
8499 Bstr progressDesc;
8500 if (mMachineState == MachineState_Saved || mMachineState == MachineState_AbortedSaved)
8501 progressDesc = tr("Restoring virtual machine");
8502 else if (fTeleporterEnabled)
8503 progressDesc = tr("Teleporting virtual machine");
8504 else
8505 progressDesc = tr("Starting virtual machine");
8506
8507 /*
8508 * Saved VMs will have to prove that their saved states seem kosher.
8509 */
8510 Utf8Str strSavedStateFile;
8511 Bstr bstrStateKeyId;
8512 Bstr bstrStateKeyStore;
8513
8514 if (mMachineState == MachineState_Saved || mMachineState == MachineState_AbortedSaved)
8515 {
8516 Bstr bstrSavedStateFile;
8517 hrc = mMachine->COMGETTER(StateFilePath)(bstrSavedStateFile.asOutParam());
8518 if (FAILED(hrc))
8519 throw hrc;
8520 strSavedStateFile = bstrSavedStateFile;
8521
8522#ifdef VBOX_WITH_FULL_VM_ENCRYPTION
8523 hrc = mMachine->COMGETTER(StateKeyId)(bstrStateKeyId.asOutParam());
8524 if (FAILED(hrc))
8525 throw hrc;
8526 hrc = mMachine->COMGETTER(StateKeyStore)(bstrStateKeyStore.asOutParam());
8527 if (FAILED(hrc))
8528 throw hrc;
8529#endif
8530
8531 ComAssertRet(bstrSavedStateFile.isNotEmpty(), E_FAIL);
8532 SsmStream ssmStream(this, pVMM, m_pKeyStore, bstrStateKeyId, bstrStateKeyStore);
8533 int vrc = ssmStream.open(strSavedStateFile.c_str());
8534 if (RT_SUCCESS(vrc))
8535 {
8536 PCSSMSTRMOPS pStreamOps;
8537 void *pvStreamOpsUser;
8538
8539 vrc = ssmStream.querySsmStrmOps(&pStreamOps, &pvStreamOpsUser);
8540 if (RT_SUCCESS(vrc))
8541 vrc = pVMM->pfnSSMR3ValidateFile(NULL /*pszFilename*/, pStreamOps, pvStreamOpsUser,
8542 false /* fChecksumIt */);
8543 }
8544
8545 if (RT_FAILURE(vrc))
8546 {
8547 Utf8Str errMsg;
8548 switch (vrc)
8549 {
8550 case VERR_FILE_NOT_FOUND:
8551 errMsg.printf(tr("VM failed to start because the saved state file '%s' does not exist."),
8552 strSavedStateFile.c_str());
8553 break;
8554 default:
8555 errMsg.printf(tr("VM failed to start because the saved state file '%s' is invalid (%Rrc). "
8556 "Delete the saved state prior to starting the VM."), strSavedStateFile.c_str(), vrc);
8557 break;
8558 }
8559 throw setErrorBoth(VBOX_E_FILE_ERROR, vrc, errMsg.c_str());
8560 }
8561
8562 }
8563
8564 /* Read console data, including console shared folders, stored in the
8565 * saved state file (if not yet done).
8566 */
8567 hrc = i_loadDataFromSavedState();
8568 if (FAILED(hrc))
8569 throw hrc;
8570
8571 /* Check all types of shared folders and compose a single list */
8572 SharedFolderDataMap sharedFolders;
8573 {
8574 /* first, insert global folders */
8575 for (SharedFolderDataMap::const_iterator it = m_mapGlobalSharedFolders.begin();
8576 it != m_mapGlobalSharedFolders.end();
8577 ++it)
8578 {
8579 const SharedFolderData &d = it->second;
8580 sharedFolders[it->first] = d;
8581 }
8582
8583 /* second, insert machine folders */
8584 for (SharedFolderDataMap::const_iterator it = m_mapMachineSharedFolders.begin();
8585 it != m_mapMachineSharedFolders.end();
8586 ++it)
8587 {
8588 const SharedFolderData &d = it->second;
8589 sharedFolders[it->first] = d;
8590 }
8591
8592 /* third, insert console folders */
8593 for (SharedFolderMap::const_iterator it = m_mapSharedFolders.begin();
8594 it != m_mapSharedFolders.end();
8595 ++it)
8596 {
8597 ConsoleSharedFolder *pSF = it->second;
8598 AutoCaller sfCaller(pSF);
8599 AutoReadLock sfLock(pSF COMMA_LOCKVAL_SRC_POS);
8600 sharedFolders[it->first] = SharedFolderData(pSF->i_getHostPath(),
8601 pSF->i_isWritable(),
8602 pSF->i_isAutoMounted(),
8603 pSF->i_getAutoMountPoint());
8604 }
8605 }
8606
8607
8608 /* Setup task object and thread to carry out the operation
8609 * asynchronously */
8610 try { task = new VMPowerUpTask(this, pPowerupProgress); }
8611 catch (std::bad_alloc &) { throw hrc = E_OUTOFMEMORY; }
8612 if (!task->isOk())
8613 throw task->hrc();
8614
8615 task->mpfnConfigConstructor = i_configConstructor;
8616 task->mSharedFolders = sharedFolders;
8617 task->mStartPaused = aPaused;
8618 if (mMachineState == MachineState_Saved || mMachineState == MachineState_AbortedSaved)
8619 try { task->mSavedStateFile = strSavedStateFile; }
8620 catch (std::bad_alloc &) { throw hrc = E_OUTOFMEMORY; }
8621 task->mTeleporterEnabled = fTeleporterEnabled;
8622
8623 /* Reset differencing hard disks for which autoReset is true,
8624 * but only if the machine has no snapshots OR the current snapshot
8625 * is an OFFLINE snapshot; otherwise we would reset the current
8626 * differencing image of an ONLINE snapshot which contains the disk
8627 * state of the machine while it was previously running, but without
8628 * the corresponding machine state, which is equivalent to powering
8629 * off a running machine and not good idea
8630 */
8631 ComPtr<ISnapshot> pCurrentSnapshot;
8632 hrc = mMachine->COMGETTER(CurrentSnapshot)(pCurrentSnapshot.asOutParam());
8633 if (FAILED(hrc))
8634 throw hrc;
8635
8636 BOOL fCurrentSnapshotIsOnline = false;
8637 if (pCurrentSnapshot)
8638 {
8639 hrc = pCurrentSnapshot->COMGETTER(Online)(&fCurrentSnapshotIsOnline);
8640 if (FAILED(hrc))
8641 throw hrc;
8642 }
8643
8644 if (strSavedStateFile.isEmpty() && !fCurrentSnapshotIsOnline)
8645 {
8646 LogFlowThisFunc(("Looking for immutable images to reset\n"));
8647
8648 com::SafeIfaceArray<IMediumAttachment> atts;
8649 hrc = mMachine->COMGETTER(MediumAttachments)(ComSafeArrayAsOutParam(atts));
8650 if (FAILED(hrc))
8651 throw hrc;
8652
8653 for (size_t i = 0;
8654 i < atts.size();
8655 ++i)
8656 {
8657 DeviceType_T devType;
8658 hrc = atts[i]->COMGETTER(Type)(&devType);
8659 /** @todo later applies to floppies as well */
8660 if (devType == DeviceType_HardDisk)
8661 {
8662 ComPtr<IMedium> pMedium;
8663 hrc = atts[i]->COMGETTER(Medium)(pMedium.asOutParam());
8664 if (FAILED(hrc))
8665 throw hrc;
8666
8667 /* needs autoreset? */
8668 BOOL autoReset = FALSE;
8669 hrc = pMedium->COMGETTER(AutoReset)(&autoReset);
8670 if (FAILED(hrc))
8671 throw hrc;
8672
8673 if (autoReset)
8674 {
8675 ComPtr<IProgress> pResetProgress;
8676 hrc = pMedium->Reset(pResetProgress.asOutParam());
8677 if (FAILED(hrc))
8678 throw hrc;
8679
8680 /* save for later use on the powerup thread */
8681 task->hardDiskProgresses.push_back(pResetProgress);
8682 }
8683 }
8684 }
8685 }
8686 else
8687 LogFlowThisFunc(("Machine has a current snapshot which is online, skipping immutable images reset\n"));
8688
8689 /* setup task object and thread to carry out the operation
8690 * asynchronously */
8691
8692#ifdef VBOX_WITH_EXTPACK
8693 mptrExtPackManager->i_dumpAllToReleaseLog();
8694#endif
8695
8696#ifdef RT_OS_SOLARIS
8697 /* setup host core dumper for the VM */
8698 Bstr value;
8699 hrc = mMachine->GetExtraData(Bstr("VBoxInternal2/CoreDumpEnabled").raw(), value.asOutParam());
8700 if (SUCCEEDED(hrc) && value == "1")
8701 {
8702 Bstr coreDumpDir, coreDumpReplaceSys, coreDumpLive;
8703 mMachine->GetExtraData(Bstr("VBoxInternal2/CoreDumpDir").raw(), coreDumpDir.asOutParam());
8704 mMachine->GetExtraData(Bstr("VBoxInternal2/CoreDumpReplaceSystemDump").raw(), coreDumpReplaceSys.asOutParam());
8705 mMachine->GetExtraData(Bstr("VBoxInternal2/CoreDumpLive").raw(), coreDumpLive.asOutParam());
8706
8707 uint32_t fCoreFlags = 0;
8708 if ( coreDumpReplaceSys.isEmpty() == false
8709 && Utf8Str(coreDumpReplaceSys).toUInt32() == 1)
8710 fCoreFlags |= RTCOREDUMPER_FLAGS_REPLACE_SYSTEM_DUMP;
8711
8712 if ( coreDumpLive.isEmpty() == false
8713 && Utf8Str(coreDumpLive).toUInt32() == 1)
8714 fCoreFlags |= RTCOREDUMPER_FLAGS_LIVE_CORE;
8715
8716 Utf8Str strDumpDir(coreDumpDir);
8717 const char *pszDumpDir = strDumpDir.c_str();
8718 if ( pszDumpDir
8719 && *pszDumpDir == '\0')
8720 pszDumpDir = NULL;
8721
8722 int vrc;
8723 if ( pszDumpDir
8724 && !RTDirExists(pszDumpDir))
8725 {
8726 /*
8727 * Try create the directory.
8728 */
8729 vrc = RTDirCreateFullPath(pszDumpDir, 0700);
8730 if (RT_FAILURE(vrc))
8731 throw setErrorBoth(E_FAIL, vrc, tr("Failed to setup CoreDumper. Couldn't create dump directory '%s' (%Rrc)"),
8732 pszDumpDir, vrc);
8733 }
8734
8735 vrc = RTCoreDumperSetup(pszDumpDir, fCoreFlags);
8736 if (RT_FAILURE(vrc))
8737 throw setErrorBoth(E_FAIL, vrc, tr("Failed to setup CoreDumper (%Rrc)"), vrc);
8738 LogRel(("CoreDumper setup successful. pszDumpDir=%s fFlags=%#x\n", pszDumpDir ? pszDumpDir : ".", fCoreFlags));
8739 }
8740#endif
8741
8742
8743 // If there is immutable drive the process that.
8744 VMPowerUpTask::ProgressList progresses(task->hardDiskProgresses);
8745 if (aProgress && !progresses.empty())
8746 {
8747 for (VMPowerUpTask::ProgressList::const_iterator it = progresses.begin(); it != progresses.end(); ++it)
8748 {
8749 ++cOperations;
8750 ulTotalOperationsWeight += 1;
8751 }
8752 hrc = pPowerupProgress->init(static_cast<IConsole *>(this),
8753 progressDesc.raw(),
8754 TRUE, // Cancelable
8755 cOperations,
8756 ulTotalOperationsWeight,
8757 tr("Starting Hard Disk operations"),
8758 1);
8759 AssertComRCReturnRC(hrc);
8760 }
8761 else if ( mMachineState == MachineState_Saved
8762 || mMachineState == MachineState_AbortedSaved
8763 || !fTeleporterEnabled)
8764 hrc = pPowerupProgress->init(static_cast<IConsole *>(this),
8765 progressDesc.raw(),
8766 FALSE /* aCancelable */);
8767 else if (fTeleporterEnabled)
8768 hrc = pPowerupProgress->init(static_cast<IConsole *>(this),
8769 progressDesc.raw(),
8770 TRUE /* aCancelable */,
8771 3 /* cOperations */,
8772 10 /* ulTotalOperationsWeight */,
8773 tr("Teleporting virtual machine"),
8774 1 /* ulFirstOperationWeight */);
8775
8776 if (FAILED(hrc))
8777 throw hrc;
8778
8779 /* Tell VBoxSVC and Machine about the progress object so they can
8780 combine/proxy it to any openRemoteSession caller. */
8781 LogFlowThisFunc(("Calling BeginPowerUp...\n"));
8782 hrc = mControl->BeginPowerUp(pPowerupProgress);
8783 if (FAILED(hrc))
8784 {
8785 LogFlowThisFunc(("BeginPowerUp failed\n"));
8786 throw hrc;
8787 }
8788 fBeganPoweringUp = true;
8789
8790 LogFlowThisFunc(("Checking if canceled...\n"));
8791 BOOL fCanceled;
8792 hrc = pPowerupProgress->COMGETTER(Canceled)(&fCanceled);
8793 if (FAILED(hrc))
8794 throw hrc;
8795
8796 if (fCanceled)
8797 {
8798 LogFlowThisFunc(("Canceled in BeginPowerUp\n"));
8799 throw setError(E_FAIL, tr("Powerup was canceled"));
8800 }
8801 LogFlowThisFunc(("Not canceled yet.\n"));
8802
8803 /** @todo this code prevents starting a VM with unavailable bridged
8804 * networking interface. The only benefit is a slightly better error
8805 * message, which should be moved to the driver code. This is the
8806 * only reason why I left the code in for now. The driver allows
8807 * unavailable bridged networking interfaces in certain circumstances,
8808 * and this is sabotaged by this check. The VM will initially have no
8809 * network connectivity, but the user can fix this at runtime. */
8810#if 0
8811 /* the network cards will undergo a quick consistency check */
8812 for (ULONG slot = 0;
8813 slot < maxNetworkAdapters;
8814 ++slot)
8815 {
8816 ComPtr<INetworkAdapter> pNetworkAdapter;
8817 mMachine->GetNetworkAdapter(slot, pNetworkAdapter.asOutParam());
8818 BOOL enabled = FALSE;
8819 pNetworkAdapter->COMGETTER(Enabled)(&enabled);
8820 if (!enabled)
8821 continue;
8822
8823 NetworkAttachmentType_T netattach;
8824 pNetworkAdapter->COMGETTER(AttachmentType)(&netattach);
8825 switch (netattach)
8826 {
8827 case NetworkAttachmentType_Bridged:
8828 {
8829 /* a valid host interface must have been set */
8830 Bstr hostif;
8831 pNetworkAdapter->COMGETTER(HostInterface)(hostif.asOutParam());
8832 if (hostif.isEmpty())
8833 {
8834 throw setError(VBOX_E_HOST_ERROR,
8835 tr("VM cannot start because host interface networking requires a host interface name to be set"));
8836 }
8837 ComPtr<IVirtualBox> pVirtualBox;
8838 mMachine->COMGETTER(Parent)(pVirtualBox.asOutParam());
8839 ComPtr<IHost> pHost;
8840 pVirtualBox->COMGETTER(Host)(pHost.asOutParam());
8841 ComPtr<IHostNetworkInterface> pHostInterface;
8842 if (!SUCCEEDED(pHost->FindHostNetworkInterfaceByName(hostif.raw(), pHostInterface.asOutParam())))
8843 throw setError(VBOX_E_HOST_ERROR,
8844 tr("VM cannot start because the host interface '%ls' does not exist"), hostif.raw());
8845 break;
8846 }
8847 default:
8848 break;
8849 }
8850 }
8851#endif // 0
8852
8853
8854 /* setup task object and thread to carry out the operation
8855 * asynchronously */
8856 if (aProgress)
8857 {
8858 hrc = pPowerupProgress.queryInterfaceTo(aProgress);
8859 AssertComRCReturnRC(hrc);
8860 }
8861
8862#ifdef VBOX_WITH_FULL_VM_ENCRYPTION
8863 task->mKeyStore = Utf8Str(bstrStateKeyStore);
8864 task->mKeyId = Utf8Str(bstrStateKeyId);
8865 task->m_pKeyStore = m_pKeyStore;
8866#endif
8867
8868 hrc = task->createThread();
8869 task = NULL;
8870 if (FAILED(hrc))
8871 throw hrc;
8872
8873 /* finally, set the state: no right to fail in this method afterwards
8874 * since we've already started the thread and it is now responsible for
8875 * any error reporting and appropriate state change! */
8876 if (mMachineState == MachineState_Saved || mMachineState == MachineState_AbortedSaved)
8877 i_setMachineState(MachineState_Restoring);
8878 else if (fTeleporterEnabled)
8879 i_setMachineState(MachineState_TeleportingIn);
8880 else
8881 i_setMachineState(MachineState_Starting);
8882 }
8883 catch (HRESULT aRC)
8884 {
8885 hrc = aRC;
8886 }
8887
8888 if (FAILED(hrc) && fBeganPoweringUp)
8889 {
8890
8891 /* The progress object will fetch the current error info */
8892 if (!pPowerupProgress.isNull())
8893 pPowerupProgress->i_notifyComplete(hrc);
8894
8895 /* Save the error info across the IPC below. Can't be done before the
8896 * progress notification above, as saving the error info deletes it
8897 * from the current context, and thus the progress object wouldn't be
8898 * updated correctly. */
8899 ErrorInfoKeeper eik;
8900
8901 /* signal end of operation */
8902 mControl->EndPowerUp(hrc);
8903 }
8904
8905 if (task)
8906 {
8907 ErrorInfoKeeper eik;
8908 delete task;
8909 }
8910
8911 LogFlowThisFunc(("mMachineState=%d, hrc=%Rhrc\n", mMachineState, hrc));
8912 LogFlowThisFuncLeave();
8913 return hrc;
8914}
8915
8916/**
8917 * Internal power off worker routine.
8918 *
8919 * This method may be called only at certain places with the following meaning
8920 * as shown below:
8921 *
8922 * - if the machine state is either Running or Paused, a normal
8923 * Console-initiated powerdown takes place (e.g. PowerDown());
8924 * - if the machine state is Saving, saveStateThread() has successfully done its
8925 * job;
8926 * - if the machine state is Starting or Restoring, powerUpThread() has failed
8927 * to start/load the VM;
8928 * - if the machine state is Stopping, the VM has powered itself off (i.e. not
8929 * as a result of the powerDown() call).
8930 *
8931 * Calling it in situations other than the above will cause unexpected behavior.
8932 *
8933 * Note that this method should be the only one that destroys mpUVM and sets it
8934 * to NULL.
8935 *
8936 * @param aProgress Progress object to run (may be NULL).
8937 *
8938 * @note Locks this object for writing.
8939 *
8940 * @note Never call this method from a thread that called addVMCaller() or
8941 * instantiated an AutoVMCaller object; first call releaseVMCaller() or
8942 * release(). Otherwise it will deadlock.
8943 */
8944HRESULT Console::i_powerDown(IProgress *aProgress /*= NULL*/)
8945{
8946 LogFlowThisFuncEnter();
8947
8948 AutoCaller autoCaller(this);
8949 AssertComRCReturnRC(autoCaller.hrc());
8950
8951 ComPtr<IInternalProgressControl> pProgressControl(aProgress);
8952
8953 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
8954
8955 /* Total # of steps for the progress object. Must correspond to the
8956 * number of "advance percent count" comments in this method! */
8957 enum { StepCount = 7 };
8958 /* current step */
8959 ULONG step = 0;
8960
8961 HRESULT hrc = S_OK;
8962 int vrc = VINF_SUCCESS;
8963
8964 /* sanity */
8965 Assert(mVMDestroying == false);
8966
8967 PCVMMR3VTABLE const pVMM = mpVMM;
8968 AssertPtrReturn(pVMM, E_UNEXPECTED);
8969 PUVM pUVM = mpUVM;
8970 AssertPtrReturn(pUVM, E_UNEXPECTED);
8971
8972 uint32_t cRefs = pVMM->pfnVMR3RetainUVM(pUVM);
8973 Assert(cRefs != UINT32_MAX); NOREF(cRefs);
8974
8975 AssertMsg( mMachineState == MachineState_Running
8976 || mMachineState == MachineState_Paused
8977 || mMachineState == MachineState_Stuck
8978 || mMachineState == MachineState_Starting
8979 || mMachineState == MachineState_Stopping
8980 || mMachineState == MachineState_Saving
8981 || mMachineState == MachineState_Restoring
8982 || mMachineState == MachineState_TeleportingPausedVM
8983 || mMachineState == MachineState_TeleportingIn
8984 , ("Invalid machine state: %s\n", ::stringifyMachineState(mMachineState)));
8985
8986 LogRel(("Console::powerDown(): A request to power off the VM has been issued (mMachineState=%s, InUninit=%d)\n",
8987 ::stringifyMachineState(mMachineState), getObjectState().getState() == ObjectState::InUninit));
8988
8989 /* Check if we need to power off the VM. In case of mVMPoweredOff=true, the
8990 * VM has already powered itself off in vmstateChangeCallback() and is just
8991 * notifying Console about that. In case of Starting or Restoring,
8992 * powerUpThread() is calling us on failure, so the VM is already off at
8993 * that point. */
8994 if ( !mVMPoweredOff
8995 && ( mMachineState == MachineState_Starting
8996 || mMachineState == MachineState_Restoring
8997 || mMachineState == MachineState_TeleportingIn)
8998 )
8999 mVMPoweredOff = true;
9000
9001 /*
9002 * Go to Stopping state if not already there.
9003 *
9004 * Note that we don't go from Saving/Restoring to Stopping because
9005 * vmstateChangeCallback() needs it to set the state to Saved on
9006 * VMSTATE_TERMINATED. In terms of protecting from inappropriate operations
9007 * while leaving the lock below, Saving or Restoring should be fine too.
9008 * Ditto for TeleportingPausedVM -> Teleported.
9009 */
9010 if ( mMachineState != MachineState_Saving
9011 && mMachineState != MachineState_Restoring
9012 && mMachineState != MachineState_Stopping
9013 && mMachineState != MachineState_TeleportingIn
9014 && mMachineState != MachineState_TeleportingPausedVM
9015 )
9016 i_setMachineState(MachineState_Stopping);
9017
9018 /* ----------------------------------------------------------------------
9019 * DONE with necessary state changes, perform the power down actions (it's
9020 * safe to release the object lock now if needed)
9021 * ---------------------------------------------------------------------- */
9022
9023 if (mDisplay)
9024 {
9025 alock.release();
9026
9027 mDisplay->i_notifyPowerDown();
9028
9029 alock.acquire();
9030 }
9031
9032 /* Stop the VRDP server to prevent new clients connection while VM is being
9033 * powered off. */
9034 if (mConsoleVRDPServer)
9035 {
9036 LogFlowThisFunc(("Stopping VRDP server...\n"));
9037
9038 /* Leave the lock since EMT could call us back as addVMCaller() */
9039 alock.release();
9040
9041 mConsoleVRDPServer->Stop();
9042
9043 alock.acquire();
9044 }
9045
9046 /* advance percent count */
9047 if (pProgressControl)
9048 pProgressControl->SetCurrentOperationProgress(99 * (++step) / StepCount);
9049
9050
9051 /* ----------------------------------------------------------------------
9052 * Now, wait for all mpUVM callers to finish their work if there are still
9053 * some on other threads. NO methods that need mpUVM (or initiate other calls
9054 * that need it) may be called after this point
9055 * ---------------------------------------------------------------------- */
9056
9057 /* go to the destroying state to prevent from adding new callers */
9058 mVMDestroying = true;
9059
9060 if (mVMCallers > 0)
9061 {
9062 /* lazy creation */
9063 if (mVMZeroCallersSem == NIL_RTSEMEVENT)
9064 RTSemEventCreate(&mVMZeroCallersSem);
9065
9066 LogFlowThisFunc(("Waiting for mpUVM callers (%d) to drop to zero...\n", mVMCallers));
9067
9068 alock.release();
9069
9070 RTSemEventWait(mVMZeroCallersSem, RT_INDEFINITE_WAIT);
9071
9072 alock.acquire();
9073 }
9074
9075 /* advance percent count */
9076 if (pProgressControl)
9077 pProgressControl->SetCurrentOperationProgress(99 * (++step) / StepCount);
9078
9079 vrc = VINF_SUCCESS;
9080
9081 /*
9082 * Power off the VM if not already done that.
9083 * Leave the lock since EMT will call vmstateChangeCallback.
9084 *
9085 * Note that VMR3PowerOff() may fail here (invalid VMSTATE) if the
9086 * VM-(guest-)initiated power off happened in parallel a ms before this
9087 * call. So far, we let this error pop up on the user's side.
9088 */
9089 if (!mVMPoweredOff)
9090 {
9091 LogFlowThisFunc(("Powering off the VM...\n"));
9092 alock.release();
9093 vrc = pVMM->pfnVMR3PowerOff(pUVM);
9094#ifdef VBOX_WITH_EXTPACK
9095 mptrExtPackManager->i_callAllVmPowerOffHooks(this, pVMM->pfnVMR3GetVM(pUVM), pVMM);
9096#endif
9097 alock.acquire();
9098 }
9099
9100 /* advance percent count */
9101 if (pProgressControl)
9102 pProgressControl->SetCurrentOperationProgress(99 * (++step) / StepCount);
9103
9104#ifdef VBOX_WITH_HGCM
9105 /* Shutdown HGCM services before destroying the VM. */
9106 if (m_pVMMDev)
9107 {
9108 LogFlowThisFunc(("Shutdown HGCM...\n"));
9109
9110 /* Leave the lock since EMT might wait for it and will call us back as addVMCaller() */
9111 alock.release();
9112
9113# ifdef VBOX_WITH_SHARED_CLIPBOARD
9114 if (m_hHgcmSvcExtShCl)
9115 {
9116 HGCMHostUnregisterServiceExtension(m_hHgcmSvcExtShCl);
9117 m_hHgcmSvcExtShCl = NULL;
9118 }
9119 GuestShCl::destroyInstance();
9120#endif
9121
9122# ifdef VBOX_WITH_DRAG_AND_DROP
9123 if (m_hHgcmSvcExtDragAndDrop)
9124 {
9125 HGCMHostUnregisterServiceExtension(m_hHgcmSvcExtDragAndDrop);
9126 m_hHgcmSvcExtDragAndDrop = NULL;
9127 }
9128# endif
9129
9130 m_pVMMDev->hgcmShutdown();
9131
9132 alock.acquire();
9133 }
9134
9135 /* advance percent count */
9136 if (pProgressControl)
9137 pProgressControl->SetCurrentOperationProgress(99 * (++step) / StepCount);
9138
9139#endif /* VBOX_WITH_HGCM */
9140
9141 LogFlowThisFunc(("Ready for VM destruction.\n"));
9142
9143 /* If we are called from Console::uninit(), then try to destroy the VM even
9144 * on failure (this will most likely fail too, but what to do?..) */
9145 if (RT_SUCCESS(vrc) || getObjectState().getState() == ObjectState::InUninit)
9146 {
9147 /* If the machine has a USB controller, release all USB devices
9148 * (symmetric to the code in captureUSBDevices()) */
9149 if (mfVMHasUsbController)
9150 {
9151 alock.release();
9152 i_detachAllUSBDevices(false /* aDone */);
9153 alock.acquire();
9154 }
9155
9156 /* Now we've got to destroy the VM as well. (mpUVM is not valid beyond
9157 * this point). We release the lock before calling VMR3Destroy() because
9158 * it will result into calling destructors of drivers associated with
9159 * Console children which may in turn try to lock Console (e.g. by
9160 * instantiating SafeVMPtr to access mpUVM). It's safe here because
9161 * mVMDestroying is set which should prevent any activity. */
9162
9163 /* Set mpUVM to NULL early just in case if some old code is not using
9164 * addVMCaller()/releaseVMCaller(). (We have our own ref on pUVM.) */
9165 pVMM->pfnVMR3ReleaseUVM(mpUVM);
9166 mpUVM = NULL;
9167
9168 LogFlowThisFunc(("Destroying the VM...\n"));
9169
9170 alock.release();
9171
9172 vrc = pVMM->pfnVMR3Destroy(pUVM);
9173
9174 /* take the lock again */
9175 alock.acquire();
9176
9177 /* advance percent count */
9178 if (pProgressControl)
9179 pProgressControl->SetCurrentOperationProgress(99 * (++step) / StepCount);
9180
9181 if (RT_SUCCESS(vrc))
9182 {
9183 LogFlowThisFunc(("Machine has been destroyed (mMachineState=%d)\n",
9184 mMachineState));
9185 /* Note: the Console-level machine state change happens on the
9186 * VMSTATE_TERMINATE state change in vmstateChangeCallback(). If
9187 * powerDown() is called from EMT (i.e. from vmstateChangeCallback()
9188 * on receiving VM-initiated VMSTATE_OFF), VMSTATE_TERMINATE hasn't
9189 * occurred yet. This is okay, because mMachineState is already
9190 * Stopping in this case, so any other attempt to call PowerDown()
9191 * will be rejected. */
9192 }
9193 else
9194 {
9195 /* bad bad bad, but what to do? (Give Console our UVM ref.) */
9196 mpUVM = pUVM;
9197 pUVM = NULL;
9198 hrc = setErrorBoth(VBOX_E_VM_ERROR, vrc, tr("Could not destroy the machine. (Error: %Rrc)"), vrc);
9199 }
9200
9201 /* Complete the detaching of the USB devices. */
9202 if (mfVMHasUsbController)
9203 {
9204 alock.release();
9205 i_detachAllUSBDevices(true /* aDone */);
9206 alock.acquire();
9207 }
9208
9209 /* advance percent count */
9210 if (pProgressControl)
9211 pProgressControl->SetCurrentOperationProgress(99 * (++step) / StepCount);
9212 }
9213 else
9214 hrc = setErrorBoth(VBOX_E_VM_ERROR, vrc, tr("Could not power off the machine. (Error: %Rrc)"), vrc);
9215
9216 /*
9217 * Finished with the destruction.
9218 *
9219 * Note that if something impossible happened and we've failed to destroy
9220 * the VM, mVMDestroying will remain true and mMachineState will be
9221 * something like Stopping, so most Console methods will return an error
9222 * to the caller.
9223 */
9224 if (pUVM != NULL)
9225 pVMM->pfnVMR3ReleaseUVM(pUVM);
9226 else
9227 mVMDestroying = false;
9228
9229 LogFlowThisFuncLeave();
9230 return hrc;
9231}
9232
9233/**
9234 * @note Locks this object for writing.
9235 */
9236HRESULT Console::i_setMachineState(MachineState_T aMachineState, bool aUpdateServer /* = true */)
9237{
9238 AutoCaller autoCaller(this);
9239 AssertComRCReturnRC(autoCaller.hrc());
9240
9241 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
9242
9243 HRESULT hrc = S_OK;
9244
9245 if (mMachineState != aMachineState)
9246 {
9247 LogThisFunc(("machineState=%s -> %s aUpdateServer=%RTbool\n",
9248 ::stringifyMachineState(mMachineState), ::stringifyMachineState(aMachineState), aUpdateServer));
9249 LogRel(("Console: Machine state changed to '%s'\n", ::stringifyMachineState(aMachineState)));
9250 mMachineState = aMachineState;
9251
9252 /// @todo (dmik)
9253 // possibly, we need to redo onStateChange() using the dedicated
9254 // Event thread, like it is done in VirtualBox. This will make it
9255 // much safer (no deadlocks possible if someone tries to use the
9256 // console from the callback), however, listeners will lose the
9257 // ability to synchronously react to state changes (is it really
9258 // necessary??)
9259 LogFlowThisFunc(("Doing onStateChange()...\n"));
9260 i_onStateChange(aMachineState);
9261 LogFlowThisFunc(("Done onStateChange()\n"));
9262
9263 if (aUpdateServer)
9264 {
9265 /* Server notification MUST be done from under the lock; otherwise
9266 * the machine state here and on the server might go out of sync
9267 * which can lead to various unexpected results (like the machine
9268 * state being >= MachineState_Running on the server, while the
9269 * session state is already SessionState_Unlocked at the same time
9270 * there).
9271 *
9272 * Cross-lock conditions should be carefully watched out: calling
9273 * UpdateState we will require Machine and SessionMachine locks
9274 * (remember that here we're holding the Console lock here, and also
9275 * all locks that have been acquire by the thread before calling
9276 * this method).
9277 */
9278 LogFlowThisFunc(("Doing mControl->UpdateState()...\n"));
9279 hrc = mControl->UpdateState(aMachineState);
9280 LogFlowThisFunc(("mControl->UpdateState()=%Rhrc\n", hrc));
9281 }
9282 }
9283
9284 return hrc;
9285}
9286
9287/**
9288 * Searches for a shared folder with the given logical name
9289 * in the collection of shared folders.
9290 *
9291 * @param strName logical name of the shared folder
9292 * @param aSharedFolder where to return the found object
9293 * @param aSetError whether to set the error info if the folder is
9294 * not found
9295 * @return
9296 * S_OK when found or E_INVALIDARG when not found
9297 *
9298 * @note The caller must lock this object for writing.
9299 */
9300HRESULT Console::i_findSharedFolder(const Utf8Str &strName, ComObjPtr<ConsoleSharedFolder> &aSharedFolder, bool aSetError /* = false */)
9301{
9302 /* sanity check */
9303 AssertReturn(isWriteLockOnCurrentThread(), E_FAIL);
9304
9305 SharedFolderMap::const_iterator it = m_mapSharedFolders.find(strName);
9306 if (it != m_mapSharedFolders.end())
9307 {
9308 aSharedFolder = it->second;
9309 return S_OK;
9310 }
9311
9312 if (aSetError)
9313 setError(VBOX_E_FILE_ERROR, tr("Could not find a shared folder named '%s'."), strName.c_str());
9314 return VBOX_E_FILE_ERROR;
9315}
9316
9317/**
9318 * Fetches the list of global or machine shared folders from the server.
9319 *
9320 * @param aGlobal true to fetch global folders.
9321 *
9322 * @note The caller must lock this object for writing.
9323 */
9324HRESULT Console::i_fetchSharedFolders(BOOL aGlobal)
9325{
9326 /* sanity check */
9327 AssertReturn( getObjectState().getState() == ObjectState::InInit
9328 || isWriteLockOnCurrentThread(), E_FAIL);
9329
9330 LogFlowThisFunc(("Entering\n"));
9331
9332 /* Check if we're online and keep it that way. */
9333 SafeVMPtrQuiet ptrVM(this);
9334 AutoVMCallerQuietWeak autoVMCaller(this);
9335 bool const online = ptrVM.isOk()
9336 && m_pVMMDev
9337 && m_pVMMDev->isShFlActive();
9338
9339 HRESULT hrc = S_OK;
9340
9341 try
9342 {
9343 if (aGlobal)
9344 {
9345 /// @todo grab & process global folders when they are done
9346 }
9347 else
9348 {
9349 SharedFolderDataMap oldFolders;
9350 if (online)
9351 oldFolders = m_mapMachineSharedFolders;
9352
9353 m_mapMachineSharedFolders.clear();
9354
9355 SafeIfaceArray<ISharedFolder> folders;
9356 hrc = mMachine->COMGETTER(SharedFolders)(ComSafeArrayAsOutParam(folders));
9357 if (FAILED(hrc)) throw hrc;
9358
9359 for (size_t i = 0; i < folders.size(); ++i)
9360 {
9361 ComPtr<ISharedFolder> pSharedFolder = folders[i];
9362
9363 Bstr bstr;
9364 hrc = pSharedFolder->COMGETTER(Name)(bstr.asOutParam());
9365 if (FAILED(hrc)) throw hrc;
9366 Utf8Str strName(bstr);
9367
9368 hrc = pSharedFolder->COMGETTER(HostPath)(bstr.asOutParam());
9369 if (FAILED(hrc)) throw hrc;
9370 Utf8Str strHostPath(bstr);
9371
9372 BOOL writable;
9373 hrc = pSharedFolder->COMGETTER(Writable)(&writable);
9374 if (FAILED(hrc)) throw hrc;
9375
9376 BOOL autoMount;
9377 hrc = pSharedFolder->COMGETTER(AutoMount)(&autoMount);
9378 if (FAILED(hrc)) throw hrc;
9379
9380 hrc = pSharedFolder->COMGETTER(AutoMountPoint)(bstr.asOutParam());
9381 if (FAILED(hrc)) throw hrc;
9382 Utf8Str strAutoMountPoint(bstr);
9383
9384 m_mapMachineSharedFolders.insert(std::make_pair(strName,
9385 SharedFolderData(strHostPath, !!writable,
9386 !!autoMount, strAutoMountPoint)));
9387
9388 /* send changes to HGCM if the VM is running */
9389 if (online)
9390 {
9391 SharedFolderDataMap::iterator it = oldFolders.find(strName);
9392 if ( it == oldFolders.end()
9393 || it->second.m_strHostPath != strHostPath)
9394 {
9395 /* a new machine folder is added or
9396 * the existing machine folder is changed */
9397 if (m_mapSharedFolders.find(strName) != m_mapSharedFolders.end())
9398 ; /* the console folder exists, nothing to do */
9399 else
9400 {
9401 /* remove the old machine folder (when changed)
9402 * or the global folder if any (when new) */
9403 if ( it != oldFolders.end()
9404 || m_mapGlobalSharedFolders.find(strName) != m_mapGlobalSharedFolders.end()
9405 )
9406 {
9407 hrc = i_removeSharedFolder(strName);
9408 if (FAILED(hrc)) throw hrc;
9409 }
9410
9411 /* create the new machine folder */
9412 hrc = i_createSharedFolder(strName,
9413 SharedFolderData(strHostPath, !!writable, !!autoMount, strAutoMountPoint));
9414 if (FAILED(hrc)) throw hrc;
9415 }
9416 }
9417 /* forget the processed (or identical) folder */
9418 if (it != oldFolders.end())
9419 oldFolders.erase(it);
9420 }
9421 }
9422
9423 /* process outdated (removed) folders */
9424 if (online)
9425 {
9426 for (SharedFolderDataMap::const_iterator it = oldFolders.begin();
9427 it != oldFolders.end(); ++it)
9428 {
9429 if (m_mapSharedFolders.find(it->first) != m_mapSharedFolders.end())
9430 ; /* the console folder exists, nothing to do */
9431 else
9432 {
9433 /* remove the outdated machine folder */
9434 hrc = i_removeSharedFolder(it->first);
9435 if (FAILED(hrc)) throw hrc;
9436
9437 /* create the global folder if there is any */
9438 SharedFolderDataMap::const_iterator git =
9439 m_mapGlobalSharedFolders.find(it->first);
9440 if (git != m_mapGlobalSharedFolders.end())
9441 {
9442 hrc = i_createSharedFolder(git->first, git->second);
9443 if (FAILED(hrc)) throw hrc;
9444 }
9445 }
9446 }
9447 }
9448 }
9449 }
9450 catch (HRESULT hrc2)
9451 {
9452 hrc = hrc2;
9453 if (online)
9454 i_atVMRuntimeErrorCallbackF(0, "BrokenSharedFolder", N_("Broken shared folder!"));
9455 }
9456
9457 LogFlowThisFunc(("Leaving\n"));
9458
9459 return hrc;
9460}
9461
9462/**
9463 * Searches for a shared folder with the given name in the list of machine
9464 * shared folders and then in the list of the global shared folders.
9465 *
9466 * @param strName Name of the folder to search for.
9467 * @param aIt Where to store the pointer to the found folder.
9468 * @return @c true if the folder was found and @c false otherwise.
9469 *
9470 * @note The caller must lock this object for reading.
9471 */
9472bool Console::i_findOtherSharedFolder(const Utf8Str &strName,
9473 SharedFolderDataMap::const_iterator &aIt)
9474{
9475 /* sanity check */
9476 AssertReturn(isWriteLockOnCurrentThread(), false);
9477
9478 /* first, search machine folders */
9479 aIt = m_mapMachineSharedFolders.find(strName);
9480 if (aIt != m_mapMachineSharedFolders.end())
9481 return true;
9482
9483 /* second, search machine folders */
9484 aIt = m_mapGlobalSharedFolders.find(strName);
9485 if (aIt != m_mapGlobalSharedFolders.end())
9486 return true;
9487
9488 return false;
9489}
9490
9491/**
9492 * Calls the HGCM service to add a shared folder definition.
9493 *
9494 * @param strName Shared folder name.
9495 * @param aData Shared folder data.
9496 *
9497 * @note Must be called from under AutoVMCaller and when mpUVM != NULL!
9498 * @note Doesn't lock anything.
9499 */
9500HRESULT Console::i_createSharedFolder(const Utf8Str &strName, const SharedFolderData &aData)
9501{
9502 Log(("Adding shared folder '%s' -> '%s'\n", strName.c_str(), aData.m_strHostPath.c_str()));
9503
9504 /*
9505 * Sanity checks
9506 */
9507 ComAssertRet(strName.isNotEmpty(), E_FAIL);
9508 ComAssertRet(aData.m_strHostPath.isNotEmpty(), E_FAIL);
9509
9510 AssertReturn(mpUVM, E_FAIL);
9511 AssertReturn(m_pVMMDev && m_pVMMDev->isShFlActive(), E_FAIL);
9512
9513 /*
9514 * Find out whether we should allow symbolic link creation.
9515 */
9516 Bstr bstrValue;
9517 HRESULT hrc = mMachine->GetExtraData(BstrFmt("VBoxInternal2/SharedFoldersEnableSymlinksCreate/%s", strName.c_str()).raw(),
9518 bstrValue.asOutParam());
9519 bool fSymlinksCreate = hrc == S_OK && bstrValue == "1";
9520
9521 /*
9522 * Check whether the path is valid and exists.
9523 */
9524 char szAbsHostPath[RTPATH_MAX];
9525 int vrc = RTPathAbs(aData.m_strHostPath.c_str(), szAbsHostPath, sizeof(szAbsHostPath));
9526 if (RT_FAILURE(vrc))
9527 return setErrorBoth(E_INVALIDARG, vrc, tr("Invalid shared folder path: '%s' (%Rrc)"), aData.m_strHostPath.c_str(), vrc);
9528
9529 /* Check whether the path is full (absolute). ASSUMING a RTPATH_MAX of ~4K
9530 this also checks that the length is within bounds of a SHFLSTRING. */
9531 if (RTPathCompare(aData.m_strHostPath.c_str(), szAbsHostPath) != 0)
9532 return setError(E_INVALIDARG, tr("Shared folder path '%s' is not absolute"), aData.m_strHostPath.c_str());
9533
9534 bool const fMissing = !RTPathExists(szAbsHostPath);
9535
9536 /*
9537 * Check the other two string lengths before converting them all to SHFLSTRINGS.
9538 */
9539 if (strName.length() >= _2K)
9540 return setError(E_INVALIDARG, tr("Shared folder name is too long: %zu bytes", "", strName.length()), strName.length());
9541 if (aData.m_strAutoMountPoint.length() >= RTPATH_MAX)
9542 return setError(E_INVALIDARG, tr("Shared folder mount point too long: %zu bytes", "",
9543 (int)aData.m_strAutoMountPoint.length()),
9544 aData.m_strAutoMountPoint.length());
9545
9546 PSHFLSTRING pHostPath = ShflStringDupUtf8AsUtf16(aData.m_strHostPath.c_str());
9547 PSHFLSTRING pName = ShflStringDupUtf8AsUtf16(strName.c_str());
9548 PSHFLSTRING pAutoMountPoint = ShflStringDupUtf8AsUtf16(aData.m_strAutoMountPoint.c_str());
9549 if (pHostPath && pName && pAutoMountPoint)
9550 {
9551 /*
9552 * Make a SHFL_FN_ADD_MAPPING call to tell the service about folder.
9553 */
9554 VBOXHGCMSVCPARM aParams[SHFL_CPARMS_ADD_MAPPING];
9555 SHFLSTRING_TO_HGMC_PARAM(&aParams[0], pHostPath);
9556 SHFLSTRING_TO_HGMC_PARAM(&aParams[1], pName);
9557 HGCMSvcSetU32(&aParams[2],
9558 (aData.m_fWritable ? SHFL_ADD_MAPPING_F_WRITABLE : 0)
9559 | (aData.m_fAutoMount ? SHFL_ADD_MAPPING_F_AUTOMOUNT : 0)
9560 | (fSymlinksCreate ? SHFL_ADD_MAPPING_F_CREATE_SYMLINKS : 0)
9561 | (fMissing ? SHFL_ADD_MAPPING_F_MISSING : 0));
9562 SHFLSTRING_TO_HGMC_PARAM(&aParams[3], pAutoMountPoint);
9563 HGCMSvcSetU32(&aParams[4], SymlinkPolicy_None);
9564 AssertCompile(SHFL_CPARMS_ADD_MAPPING == 5);
9565
9566 vrc = m_pVMMDev->hgcmHostCall("VBoxSharedFolders", SHFL_FN_ADD_MAPPING, SHFL_CPARMS_ADD_MAPPING, aParams);
9567 if (RT_FAILURE(vrc))
9568 hrc = setErrorBoth(E_FAIL, vrc, tr("Could not create a shared folder '%s' mapped to '%s' (%Rrc)"),
9569 strName.c_str(), aData.m_strHostPath.c_str(), vrc);
9570
9571 else if (fMissing)
9572 hrc = setError(E_INVALIDARG, tr("Shared folder path '%s' does not exist on the host"), aData.m_strHostPath.c_str());
9573 else
9574 hrc = S_OK;
9575 }
9576 else
9577 hrc = E_OUTOFMEMORY;
9578 RTMemFree(pAutoMountPoint);
9579 RTMemFree(pName);
9580 RTMemFree(pHostPath);
9581 return hrc;
9582}
9583
9584/**
9585 * Calls the HGCM service to remove the shared folder definition.
9586 *
9587 * @param strName Shared folder name.
9588 *
9589 * @note Must be called from under AutoVMCaller and when mpUVM != NULL!
9590 * @note Doesn't lock anything.
9591 */
9592HRESULT Console::i_removeSharedFolder(const Utf8Str &strName)
9593{
9594 ComAssertRet(strName.isNotEmpty(), E_FAIL);
9595
9596 /* sanity checks */
9597 AssertReturn(mpUVM, E_FAIL);
9598 AssertReturn(m_pVMMDev && m_pVMMDev->isShFlActive(), E_FAIL);
9599
9600 VBOXHGCMSVCPARM parms;
9601 SHFLSTRING *pMapName;
9602 size_t cbString;
9603
9604 Log(("Removing shared folder '%s'\n", strName.c_str()));
9605
9606 Bstr bstrName(strName);
9607 cbString = (bstrName.length() + 1) * sizeof(RTUTF16);
9608 if (cbString >= UINT16_MAX)
9609 return setError(E_INVALIDARG, tr("The name is too long"));
9610 pMapName = (SHFLSTRING *) RTMemAllocZ(SHFLSTRING_HEADER_SIZE + cbString);
9611 Assert(pMapName);
9612 memcpy(pMapName->String.ucs2, bstrName.raw(), cbString);
9613
9614 pMapName->u16Size = (uint16_t)cbString;
9615 pMapName->u16Length = (uint16_t)(cbString - sizeof(RTUTF16));
9616
9617 parms.type = VBOX_HGCM_SVC_PARM_PTR;
9618 parms.u.pointer.addr = pMapName;
9619 parms.u.pointer.size = ShflStringSizeOfBuffer(pMapName);
9620
9621 int vrc = m_pVMMDev->hgcmHostCall("VBoxSharedFolders", SHFL_FN_REMOVE_MAPPING, 1, &parms);
9622 RTMemFree(pMapName);
9623 if (RT_FAILURE(vrc))
9624 return setErrorBoth(E_FAIL, vrc, tr("Could not remove the shared folder '%s' (%Rrc)"), strName.c_str(), vrc);
9625
9626 return S_OK;
9627}
9628
9629/**
9630 * Retains a reference to the default cryptographic interface.
9631 *
9632 * @returns VBox status code.
9633 * @retval VERR_NOT_SUPPORTED if the VM is not configured for encryption.
9634 * @param ppCryptoIf Where to store the pointer to the cryptographic interface on success.
9635 *
9636 * @note Locks this object for writing.
9637 */
9638int Console::i_retainCryptoIf(PCVBOXCRYPTOIF *ppCryptoIf)
9639{
9640 AssertReturn(ppCryptoIf != NULL, VERR_INVALID_PARAMETER);
9641
9642 int vrc = VINF_SUCCESS;
9643 if (mhLdrModCrypto == NIL_RTLDRMOD)
9644 {
9645#ifdef VBOX_WITH_EXTPACK
9646 /*
9647 * Check that a crypto extension pack name is set and resolve it into a
9648 * library path.
9649 */
9650 HRESULT hrc = S_OK;
9651 Bstr bstrExtPack;
9652
9653 ComPtr<IVirtualBox> pVirtualBox;
9654 hrc = mMachine->COMGETTER(Parent)(pVirtualBox.asOutParam());
9655 ComPtr<ISystemProperties> pSystemProperties;
9656 if (SUCCEEDED(hrc))
9657 hrc = pVirtualBox->COMGETTER(SystemProperties)(pSystemProperties.asOutParam());
9658 if (SUCCEEDED(hrc))
9659 hrc = pSystemProperties->COMGETTER(DefaultCryptoExtPack)(bstrExtPack.asOutParam());
9660 if (FAILED(hrc))
9661 {
9662 setErrorBoth(hrc, VERR_INVALID_PARAMETER,
9663 tr("Failed to query default extension pack name for the cryptographic module"));
9664 return VERR_INVALID_PARAMETER;
9665 }
9666
9667 Utf8Str strExtPack(bstrExtPack);
9668 if (strExtPack.isEmpty())
9669 {
9670 setError(VBOX_E_OBJECT_NOT_FOUND,
9671 tr("Ńo extension pack providing a cryptographic support module could be found"));
9672 return VERR_NOT_FOUND;
9673 }
9674
9675 Utf8Str strCryptoLibrary;
9676 vrc = mptrExtPackManager->i_getCryptoLibraryPathForExtPack(&strExtPack, &strCryptoLibrary);
9677 if (RT_SUCCESS(vrc))
9678 {
9679 RTERRINFOSTATIC ErrInfo;
9680 vrc = SUPR3HardenedLdrLoadPlugIn(strCryptoLibrary.c_str(), &mhLdrModCrypto, RTErrInfoInitStatic(&ErrInfo));
9681 if (RT_SUCCESS(vrc))
9682 {
9683 /* Resolve the entry point and query the pointer to the cryptographic interface. */
9684 PFNVBOXCRYPTOENTRY pfnCryptoEntry = NULL;
9685 vrc = RTLdrGetSymbol(mhLdrModCrypto, VBOX_CRYPTO_MOD_ENTRY_POINT, (void **)&pfnCryptoEntry);
9686 if (RT_SUCCESS(vrc))
9687 {
9688 vrc = pfnCryptoEntry(&mpCryptoIf);
9689 if (RT_FAILURE(vrc))
9690 setErrorBoth(VBOX_E_IPRT_ERROR, vrc,
9691 tr("Failed to query the interface callback table from the cryptographic support module '%s' from extension pack '%s'"),
9692 strCryptoLibrary.c_str(), strExtPack.c_str());
9693 }
9694 else
9695 setErrorBoth(VBOX_E_IPRT_ERROR, vrc,
9696 tr("Failed to resolve the entry point for the cryptographic support module '%s' from extension pack '%s'"),
9697 strCryptoLibrary.c_str(), strExtPack.c_str());
9698
9699 if (RT_FAILURE(vrc))
9700 {
9701 RTLdrClose(mhLdrModCrypto);
9702 mhLdrModCrypto = NIL_RTLDRMOD;
9703 }
9704 }
9705 else
9706 setErrorBoth(VBOX_E_IPRT_ERROR, vrc,
9707 tr("Couldn't load the cryptographic support module '%s' from extension pack '%s' (error: '%s')"),
9708 strCryptoLibrary.c_str(), strExtPack.c_str(), ErrInfo.Core.pszMsg);
9709 }
9710 else
9711 setErrorBoth(VBOX_E_IPRT_ERROR, vrc,
9712 tr("Couldn't resolve the library path of the crpytographic support module for extension pack '%s'"),
9713 strExtPack.c_str());
9714#else
9715 setError(VBOX_E_NOT_SUPPORTED,
9716 tr("The cryptographic support module is not supported in this build because extension packs are not supported"));
9717 vrc = VERR_NOT_SUPPORTED;
9718#endif
9719 }
9720
9721 if (RT_SUCCESS(vrc))
9722 {
9723 ASMAtomicIncU32(&mcRefsCrypto);
9724 *ppCryptoIf = mpCryptoIf;
9725 }
9726
9727 return vrc;
9728}
9729
9730/**
9731 * Releases the reference of the given cryptographic interface.
9732 *
9733 * @returns VBox status code.
9734 * @param pCryptoIf Pointer to the cryptographic interface to release.
9735 *
9736 * @note Locks this object for writing.
9737 */
9738int Console::i_releaseCryptoIf(PCVBOXCRYPTOIF pCryptoIf)
9739{
9740 AssertReturn(pCryptoIf == mpCryptoIf, VERR_INVALID_PARAMETER);
9741
9742 ASMAtomicDecU32(&mcRefsCrypto);
9743 return VINF_SUCCESS;
9744}
9745
9746/**
9747 * Tries to unload any loaded cryptographic support module if it is not in use currently.
9748 *
9749 * @returns COM status code.
9750 *
9751 * @note Locks this object for writing.
9752 */
9753HRESULT Console::i_unloadCryptoIfModule(void)
9754{
9755 AutoCaller autoCaller(this);
9756 AssertComRCReturnRC(autoCaller.hrc());
9757
9758 AutoWriteLock wlock(this COMMA_LOCKVAL_SRC_POS);
9759
9760 if (mcRefsCrypto)
9761 return setError(E_ACCESSDENIED,
9762 tr("The cryptographic support module is in use and can't be unloaded"));
9763
9764 if (mhLdrModCrypto != NIL_RTLDRMOD)
9765 {
9766 int vrc = RTLdrClose(mhLdrModCrypto);
9767 AssertRC(vrc);
9768 mhLdrModCrypto = NIL_RTLDRMOD;
9769 }
9770
9771 return S_OK;
9772}
9773
9774/** @callback_method_impl{FNVMATSTATE}
9775 *
9776 * @note Locks the Console object for writing.
9777 * @remarks The @a pUVM parameter can be NULL in one case where powerUpThread()
9778 * calls after the VM was destroyed.
9779 */
9780/*static*/ DECLCALLBACK(void)
9781Console::i_vmstateChangeCallback(PUVM pUVM, PCVMMR3VTABLE pVMM, VMSTATE enmState, VMSTATE enmOldState, void *pvUser)
9782{
9783 LogFlowFunc(("Changing state from %s to %s (pUVM=%p)\n",
9784 pVMM->pfnVMR3GetStateName(enmOldState), pVMM->pfnVMR3GetStateName(enmState), pUVM));
9785 RT_NOREF(pVMM);
9786
9787 Console *that = static_cast<Console *>(pvUser);
9788 AssertReturnVoid(that);
9789
9790 AutoCaller autoCaller(that);
9791
9792 /* Note that we must let this method proceed even if Console::uninit() has
9793 * been already called. In such case this VMSTATE change is a result of:
9794 * 1) powerDown() called from uninit() itself, or
9795 * 2) VM-(guest-)initiated power off. */
9796 AssertReturnVoid( autoCaller.isOk()
9797 || that->getObjectState().getState() == ObjectState::InUninit);
9798
9799 switch (enmState)
9800 {
9801 /*
9802 * The VM has terminated
9803 */
9804 case VMSTATE_OFF:
9805 {
9806#ifdef VBOX_WITH_GUEST_PROPS
9807 if (that->mfTurnResetIntoPowerOff)
9808 {
9809 Bstr strPowerOffReason;
9810
9811 if (that->mfPowerOffCausedByReset)
9812 strPowerOffReason = Bstr("Reset");
9813 else
9814 strPowerOffReason = Bstr("PowerOff");
9815
9816 that->mMachine->DeleteGuestProperty(Bstr("/VirtualBox/HostInfo/VMPowerOffReason").raw());
9817 that->mMachine->SetGuestProperty(Bstr("/VirtualBox/HostInfo/VMPowerOffReason").raw(),
9818 strPowerOffReason.raw(), Bstr("RDONLYGUEST").raw());
9819 that->mMachine->SaveSettings();
9820 }
9821#endif
9822
9823 AutoWriteLock alock(that COMMA_LOCKVAL_SRC_POS);
9824
9825 if (that->mVMStateChangeCallbackDisabled)
9826 return;
9827
9828 /* Do we still think that it is running? It may happen if this is a
9829 * VM-(guest-)initiated shutdown/poweroff.
9830 */
9831 if ( that->mMachineState != MachineState_Stopping
9832 && that->mMachineState != MachineState_Saving
9833 && that->mMachineState != MachineState_Restoring
9834 && that->mMachineState != MachineState_TeleportingIn
9835 && that->mMachineState != MachineState_TeleportingPausedVM
9836 && !that->mVMIsAlreadyPoweringOff
9837 )
9838 {
9839 LogFlowFunc(("VM has powered itself off but Console still thinks it is running. Notifying.\n"));
9840
9841 /*
9842 * Prevent powerDown() from calling VMR3PowerOff() again if this was called from
9843 * the power off state change.
9844 * When called from the Reset state make sure to call VMR3PowerOff() first.
9845 */
9846 Assert(that->mVMPoweredOff == false);
9847 that->mVMPoweredOff = true;
9848
9849 /*
9850 * request a progress object from the server
9851 * (this will set the machine state to Stopping on the server
9852 * to block others from accessing this machine)
9853 */
9854 ComPtr<IProgress> pProgress;
9855 HRESULT hrc = that->mControl->BeginPoweringDown(pProgress.asOutParam());
9856 AssertComRC(hrc);
9857
9858 /* sync the state with the server */
9859 that->i_setMachineStateLocally(MachineState_Stopping);
9860
9861 /*
9862 * Setup task object and thread to carry out the operation
9863 * asynchronously (if we call powerDown() right here but there
9864 * is one or more mpUVM callers (added with addVMCaller()) we'll
9865 * deadlock).
9866 */
9867 VMPowerDownTask *pTask = NULL;
9868 try
9869 {
9870 pTask = new VMPowerDownTask(that, pProgress);
9871 }
9872 catch (std::bad_alloc &)
9873 {
9874 LogRelFunc(("E_OUTOFMEMORY creating VMPowerDownTask"));
9875 hrc = E_OUTOFMEMORY;
9876 break;
9877 }
9878
9879 /*
9880 * If creating a task failed, this can currently mean one of
9881 * two: either Console::uninit() has been called just a ms
9882 * before (so a powerDown() call is already on the way), or
9883 * powerDown() itself is being already executed. Just do
9884 * nothing.
9885 */
9886 if (pTask->isOk())
9887 {
9888 hrc = pTask->createThread();
9889 pTask = NULL;
9890 if (FAILED(hrc))
9891 LogRelFunc(("Problem with creating thread for VMPowerDownTask.\n"));
9892 }
9893 else
9894 {
9895 LogFlowFunc(("Console is already being uninitialized. (%Rhrc)\n", pTask->hrc()));
9896 delete pTask;
9897 pTask = NULL;
9898 hrc = E_FAIL;
9899 }
9900 }
9901 break;
9902 }
9903
9904 /* The VM has been completely destroyed.
9905 *
9906 * Note: This state change can happen at two points:
9907 * 1) At the end of VMR3Destroy() if it was not called from EMT.
9908 * 2) At the end of vmR3EmulationThread if VMR3Destroy() was
9909 * called by EMT.
9910 */
9911 case VMSTATE_TERMINATED:
9912 {
9913 AutoWriteLock alock(that COMMA_LOCKVAL_SRC_POS);
9914
9915 if (that->mVMStateChangeCallbackDisabled)
9916 break;
9917
9918#ifdef VBOX_WITH_CLOUD_NET
9919 /*
9920 * We stop cloud gateway here because we may have failed to connect to it,
9921 * configure it, or establish a tunnel. We definitely do not want an orphaned
9922 * instance running in the cloud.
9923 */
9924 if (!that->mGateway.mGatewayInstanceId.isEmpty())
9925 {
9926 ComPtr<IVirtualBox> pVirtualBox;
9927 HRESULT hrc = that->mMachine->COMGETTER(Parent)(pVirtualBox.asOutParam());
9928 AssertComRC(hrc);
9929 if (SUCCEEDED(hrc) && !pVirtualBox.isNull())
9930 stopCloudGateway(pVirtualBox, that->mGateway);
9931 }
9932#endif /* VBOX_WITH_CLOUD_NET */
9933 /* Terminate host interface networking. If pUVM is NULL, we've been
9934 * manually called from powerUpThread() either before calling
9935 * VMR3Create() or after VMR3Create() failed, so no need to touch
9936 * networking.
9937 */
9938 if (pUVM)
9939 that->i_powerDownHostInterfaces();
9940
9941 /* From now on the machine is officially powered down or remains in
9942 * the Saved state.
9943 */
9944 switch (that->mMachineState)
9945 {
9946 default:
9947 AssertFailed();
9948 RT_FALL_THRU();
9949 case MachineState_Stopping:
9950 /* successfully powered down */
9951 that->i_setMachineState(MachineState_PoweredOff);
9952 break;
9953 case MachineState_Saving:
9954 /* successfully saved */
9955 that->i_setMachineState(MachineState_Saved);
9956 break;
9957 case MachineState_Starting:
9958 /* failed to start, but be patient: set back to PoweredOff
9959 * (for similarity with the below) */
9960 that->i_setMachineState(MachineState_PoweredOff);
9961 break;
9962 case MachineState_Restoring:
9963 /* failed to load the saved state file, but be patient: set
9964 * to AbortedSaved (to preserve the saved state file) */
9965 that->i_setMachineState(MachineState_AbortedSaved);
9966 break;
9967 case MachineState_TeleportingIn:
9968 /* Teleportation failed or was canceled. Back to powered off. */
9969 that->i_setMachineState(MachineState_PoweredOff);
9970 break;
9971 case MachineState_TeleportingPausedVM:
9972 /* Successfully teleported the VM. */
9973 that->i_setMachineState(MachineState_Teleported);
9974 break;
9975 }
9976 break;
9977 }
9978
9979 case VMSTATE_RESETTING:
9980 /** @todo shouldn't VMSTATE_RESETTING_LS be here? */
9981 {
9982#ifdef VBOX_WITH_GUEST_PROPS
9983 /* Do not take any read/write locks here! */
9984 that->i_guestPropertiesHandleVMReset();
9985#endif
9986 break;
9987 }
9988
9989 case VMSTATE_SOFT_RESETTING:
9990 case VMSTATE_SOFT_RESETTING_LS:
9991 /* Shouldn't do anything here! */
9992 break;
9993
9994 case VMSTATE_SUSPENDED:
9995 {
9996 AutoWriteLock alock(that COMMA_LOCKVAL_SRC_POS);
9997
9998 if (that->mVMStateChangeCallbackDisabled)
9999 break;
10000
10001 switch (that->mMachineState)
10002 {
10003 case MachineState_Teleporting:
10004 that->i_setMachineState(MachineState_TeleportingPausedVM);
10005 break;
10006
10007 case MachineState_LiveSnapshotting:
10008 that->i_setMachineState(MachineState_OnlineSnapshotting);
10009 break;
10010
10011 case MachineState_TeleportingPausedVM:
10012 case MachineState_Saving:
10013 case MachineState_Restoring:
10014 case MachineState_Stopping:
10015 case MachineState_TeleportingIn:
10016 case MachineState_OnlineSnapshotting:
10017 /* The worker thread handles the transition. */
10018 break;
10019
10020 case MachineState_Running:
10021 that->i_setMachineState(MachineState_Paused);
10022 break;
10023
10024 case MachineState_Paused:
10025 /* Nothing to do. */
10026 break;
10027
10028 default:
10029 AssertMsgFailed(("%s\n", ::stringifyMachineState(that->mMachineState)));
10030 }
10031 break;
10032 }
10033
10034 case VMSTATE_SUSPENDED_LS:
10035 case VMSTATE_SUSPENDED_EXT_LS:
10036 {
10037 AutoWriteLock alock(that COMMA_LOCKVAL_SRC_POS);
10038 if (that->mVMStateChangeCallbackDisabled)
10039 break;
10040 switch (that->mMachineState)
10041 {
10042 case MachineState_Teleporting:
10043 that->i_setMachineState(MachineState_TeleportingPausedVM);
10044 break;
10045
10046 case MachineState_LiveSnapshotting:
10047 that->i_setMachineState(MachineState_OnlineSnapshotting);
10048 break;
10049
10050 case MachineState_TeleportingPausedVM:
10051 case MachineState_Saving:
10052 /* ignore */
10053 break;
10054
10055 default:
10056 AssertMsgFailed(("%s/%s -> %s\n", ::stringifyMachineState(that->mMachineState),
10057 pVMM->pfnVMR3GetStateName(enmOldState), pVMM->pfnVMR3GetStateName(enmState) ));
10058 that->i_setMachineState(MachineState_Paused);
10059 break;
10060 }
10061 break;
10062 }
10063
10064 case VMSTATE_RUNNING:
10065 {
10066 if ( enmOldState == VMSTATE_POWERING_ON
10067 || enmOldState == VMSTATE_RESUMING)
10068 {
10069 AutoWriteLock alock(that COMMA_LOCKVAL_SRC_POS);
10070
10071 if (that->mVMStateChangeCallbackDisabled)
10072 break;
10073
10074 Assert( ( ( that->mMachineState == MachineState_Starting
10075 || that->mMachineState == MachineState_Paused)
10076 && enmOldState == VMSTATE_POWERING_ON)
10077 || ( ( that->mMachineState == MachineState_Restoring
10078 || that->mMachineState == MachineState_TeleportingIn
10079 || that->mMachineState == MachineState_Paused
10080 || that->mMachineState == MachineState_Saving
10081 )
10082 && enmOldState == VMSTATE_RESUMING));
10083
10084 that->i_setMachineState(MachineState_Running);
10085 }
10086
10087 break;
10088 }
10089
10090 case VMSTATE_RUNNING_LS:
10091 AssertMsg( that->mMachineState == MachineState_LiveSnapshotting
10092 || that->mMachineState == MachineState_Teleporting,
10093 ("%s/%s -> %s\n", ::stringifyMachineState(that->mMachineState),
10094 pVMM->pfnVMR3GetStateName(enmOldState), pVMM->pfnVMR3GetStateName(enmState) ));
10095 break;
10096
10097 case VMSTATE_FATAL_ERROR:
10098 {
10099 AutoWriteLock alock(that COMMA_LOCKVAL_SRC_POS);
10100
10101 if (that->mVMStateChangeCallbackDisabled)
10102 break;
10103
10104 /* Fatal errors are only for running VMs. */
10105 Assert(Global::IsOnline(that->mMachineState));
10106
10107 /* Note! 'Pause' is used here in want of something better. There
10108 * are currently only two places where fatal errors might be
10109 * raised, so it is not worth adding a new externally
10110 * visible state for this yet. */
10111 that->i_setMachineState(MachineState_Paused);
10112 break;
10113 }
10114
10115 case VMSTATE_GURU_MEDITATION:
10116 {
10117 AutoWriteLock alock(that COMMA_LOCKVAL_SRC_POS);
10118
10119 if (that->mVMStateChangeCallbackDisabled)
10120 break;
10121
10122 /* Guru are only for running VMs */
10123 Assert(Global::IsOnline(that->mMachineState));
10124
10125 that->i_setMachineState(MachineState_Stuck);
10126 break;
10127 }
10128
10129 case VMSTATE_CREATED:
10130 {
10131 /*
10132 * We have to set the secret key helper interface for the VD drivers to
10133 * get notified about missing keys.
10134 */
10135 that->i_initSecretKeyIfOnAllAttachments();
10136 break;
10137 }
10138
10139 default: /* shut up gcc */
10140 break;
10141 }
10142}
10143
10144/**
10145 * Changes the clipboard mode.
10146 *
10147 * @returns VBox status code.
10148 * @param aClipboardMode new clipboard mode.
10149 */
10150int Console::i_changeClipboardMode(ClipboardMode_T aClipboardMode)
10151{
10152#ifdef VBOX_WITH_SHARED_CLIPBOARD
10153 VMMDev *pVMMDev = m_pVMMDev;
10154 AssertPtrReturn(pVMMDev, VERR_INVALID_POINTER);
10155
10156 VBOXHGCMSVCPARM parm;
10157 parm.type = VBOX_HGCM_SVC_PARM_32BIT;
10158
10159 switch (aClipboardMode)
10160 {
10161 default:
10162 case ClipboardMode_Disabled:
10163 LogRel(("Shared Clipboard: Mode: Off\n"));
10164 parm.u.uint32 = VBOX_SHCL_MODE_OFF;
10165 break;
10166 case ClipboardMode_GuestToHost:
10167 LogRel(("Shared Clipboard: Mode: Guest to Host\n"));
10168 parm.u.uint32 = VBOX_SHCL_MODE_GUEST_TO_HOST;
10169 break;
10170 case ClipboardMode_HostToGuest:
10171 LogRel(("Shared Clipboard: Mode: Host to Guest\n"));
10172 parm.u.uint32 = VBOX_SHCL_MODE_HOST_TO_GUEST;
10173 break;
10174 case ClipboardMode_Bidirectional:
10175 LogRel(("Shared Clipboard: Mode: Bidirectional\n"));
10176 parm.u.uint32 = VBOX_SHCL_MODE_BIDIRECTIONAL;
10177 break;
10178 }
10179
10180 int vrc = pVMMDev->hgcmHostCall("VBoxSharedClipboard", VBOX_SHCL_HOST_FN_SET_MODE, 1, &parm);
10181 if (RT_FAILURE(vrc))
10182 LogRel(("Shared Clipboard: Error changing mode: %Rrc\n", vrc));
10183
10184 return vrc;
10185#else
10186 RT_NOREF(aClipboardMode);
10187 return VERR_NOT_IMPLEMENTED;
10188#endif
10189}
10190
10191/**
10192 * Changes the clipboard file transfer mode.
10193 *
10194 * @returns VBox status code.
10195 * @param aEnabled Whether clipboard file transfers are enabled or not.
10196 */
10197int Console::i_changeClipboardFileTransferMode(bool aEnabled)
10198{
10199#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS
10200 VMMDev *pVMMDev = m_pVMMDev;
10201 AssertPtrReturn(pVMMDev, VERR_INVALID_POINTER);
10202
10203 VBOXHGCMSVCPARM parm;
10204 RT_ZERO(parm);
10205
10206 parm.type = VBOX_HGCM_SVC_PARM_32BIT;
10207 parm.u.uint32 = aEnabled ? VBOX_SHCL_TRANSFER_MODE_F_ENABLED : VBOX_SHCL_TRANSFER_MODE_F_NONE;
10208
10209 int vrc = pVMMDev->hgcmHostCall("VBoxSharedClipboard", VBOX_SHCL_HOST_FN_SET_TRANSFER_MODE, 1 /* cParms */, &parm);
10210 if (RT_FAILURE(vrc))
10211 LogRel(("Shared Clipboard: Error changing file transfer mode: %Rrc\n", vrc));
10212
10213 return vrc;
10214#else
10215 RT_NOREF(aEnabled);
10216 return VERR_NOT_IMPLEMENTED;
10217#endif
10218}
10219
10220/**
10221 * Changes the drag and drop mode.
10222 *
10223 * @param aDnDMode new drag and drop mode.
10224 */
10225int Console::i_changeDnDMode(DnDMode_T aDnDMode)
10226{
10227 VMMDev *pVMMDev = m_pVMMDev;
10228 AssertPtrReturn(pVMMDev, VERR_INVALID_POINTER);
10229
10230 VBOXHGCMSVCPARM parm;
10231 RT_ZERO(parm);
10232 parm.type = VBOX_HGCM_SVC_PARM_32BIT;
10233
10234 switch (aDnDMode)
10235 {
10236 default:
10237 case DnDMode_Disabled:
10238 LogRel(("Drag and drop mode: Off\n"));
10239 parm.u.uint32 = VBOX_DRAG_AND_DROP_MODE_OFF;
10240 break;
10241 case DnDMode_GuestToHost:
10242 LogRel(("Drag and drop mode: Guest to Host\n"));
10243 parm.u.uint32 = VBOX_DRAG_AND_DROP_MODE_GUEST_TO_HOST;
10244 break;
10245 case DnDMode_HostToGuest:
10246 LogRel(("Drag and drop mode: Host to Guest\n"));
10247 parm.u.uint32 = VBOX_DRAG_AND_DROP_MODE_HOST_TO_GUEST;
10248 break;
10249 case DnDMode_Bidirectional:
10250 LogRel(("Drag and drop mode: Bidirectional\n"));
10251 parm.u.uint32 = VBOX_DRAG_AND_DROP_MODE_BIDIRECTIONAL;
10252 break;
10253 }
10254
10255 int vrc = pVMMDev->hgcmHostCall("VBoxDragAndDropSvc", DragAndDropSvc::HOST_DND_FN_SET_MODE, 1 /* cParms */, &parm);
10256 if (RT_FAILURE(vrc))
10257 LogRel(("Error changing drag and drop mode: %Rrc\n", vrc));
10258
10259 return vrc;
10260}
10261
10262#ifdef VBOX_WITH_USB
10263/**
10264 * @interface_method_impl{REMOTEUSBIF,pfnQueryRemoteUsbBackend}
10265 */
10266/*static*/ DECLCALLBACK(PREMOTEUSBCALLBACK)
10267Console::i_usbQueryRemoteUsbBackend(void *pvUser, PCRTUUID pUuid, uint32_t idClient)
10268{
10269 Console *pConsole = (Console *)pvUser;
10270
10271 AutoReadLock thatLock(pConsole COMMA_LOCKVAL_SRC_POS);
10272
10273 Guid const uuid(*pUuid);
10274 return (PREMOTEUSBCALLBACK)pConsole->i_consoleVRDPServer()->USBBackendRequestPointer(idClient, &uuid);
10275}
10276
10277
10278/**
10279 * Sends a request to VMM to attach the given host device.
10280 * After this method succeeds, the attached device will appear in the
10281 * mUSBDevices collection.
10282 *
10283 * @param aHostDevice device to attach
10284 *
10285 * @note Synchronously calls EMT.
10286 */
10287HRESULT Console::i_attachUSBDevice(IUSBDevice *aHostDevice, ULONG aMaskedIfs, const Utf8Str &aCaptureFilename)
10288{
10289 AssertReturn(aHostDevice, E_FAIL);
10290 AssertReturn(!isWriteLockOnCurrentThread(), E_FAIL);
10291
10292 HRESULT hrc;
10293
10294 /*
10295 * Get the address and the Uuid, and call the pfnCreateProxyDevice roothub
10296 * method in EMT (using usbAttachCallback()).
10297 */
10298 Bstr bstrAddress;
10299 hrc = aHostDevice->COMGETTER(Address)(bstrAddress.asOutParam());
10300 ComAssertComRCRetRC(hrc);
10301 Utf8Str const Address(bstrAddress);
10302
10303 Bstr id;
10304 hrc = aHostDevice->COMGETTER(Id)(id.asOutParam());
10305 ComAssertComRCRetRC(hrc);
10306 Guid const uuid(id);
10307
10308 BOOL fRemote = FALSE;
10309 hrc = aHostDevice->COMGETTER(Remote)(&fRemote);
10310 ComAssertComRCRetRC(hrc);
10311
10312 Bstr bstrBackend;
10313 hrc = aHostDevice->COMGETTER(Backend)(bstrBackend.asOutParam());
10314 ComAssertComRCRetRC(hrc);
10315 Utf8Str const strBackend(bstrBackend);
10316
10317 /* Get the VM handle. */
10318 SafeVMPtr ptrVM(this);
10319 if (!ptrVM.isOk())
10320 return ptrVM.hrc();
10321
10322 LogFlowThisFunc(("Proxying USB device '%s' {%RTuuid}...\n", Address.c_str(), uuid.raw()));
10323
10324 PCFGMNODE pRemoteCfg = NULL;
10325 if (fRemote)
10326 {
10327 RemoteUSBDevice *pRemoteUSBDevice = static_cast<RemoteUSBDevice *>(aHostDevice);
10328
10329 pRemoteCfg = mpVMM->pfnCFGMR3CreateTree(ptrVM.rawUVM());
10330 if (pRemoteCfg)
10331 {
10332 int vrc = mpVMM->pfnCFGMR3InsertInteger(pRemoteCfg, "ClientId", pRemoteUSBDevice->clientId());
10333 if (RT_FAILURE(vrc))
10334 {
10335 mpVMM->pfnCFGMR3DestroyTree(pRemoteCfg);
10336 return setErrorBoth(E_FAIL, vrc, tr("Failed to create configuration for USB device."));
10337 }
10338 }
10339 else
10340 return setErrorBoth(E_OUTOFMEMORY, VERR_NO_MEMORY, tr("Failed to allocate config tree for USB device."));
10341 }
10342
10343 USBConnectionSpeed_T enmSpeed;
10344 hrc = aHostDevice->COMGETTER(Speed)(&enmSpeed);
10345 AssertComRCReturnRC(hrc);
10346
10347 int vrc = ptrVM.vtable()->pfnVMR3ReqCallWaitU(ptrVM.rawUVM(), 0 /* idDstCpu (saved state, see #6232) */,
10348 (PFNRT)i_usbAttachCallback, 11,
10349 this, ptrVM.rawUVM(), ptrVM.vtable(), aHostDevice, uuid.raw(),
10350 strBackend.c_str(), Address.c_str(), pRemoteCfg, enmSpeed, aMaskedIfs,
10351 aCaptureFilename.isEmpty() ? NULL : aCaptureFilename.c_str());
10352 if (RT_SUCCESS(vrc))
10353 {
10354 /* Create a OUSBDevice and add it to the device list */
10355 ComObjPtr<OUSBDevice> pUSBDevice;
10356 pUSBDevice.createObject();
10357 hrc = pUSBDevice->init(aHostDevice);
10358 AssertComRC(hrc);
10359
10360 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
10361 mUSBDevices.push_back(pUSBDevice);
10362 LogFlowFunc(("Attached device {%RTuuid}\n", pUSBDevice->i_id().raw()));
10363
10364 /* notify callbacks */
10365 alock.release();
10366 i_onUSBDeviceStateChange(pUSBDevice, true /* aAttached */, NULL);
10367 }
10368 else
10369 {
10370 Log1WarningThisFunc(("Failed to create proxy device for '%s' {%RTuuid} (%Rrc)\n", Address.c_str(), uuid.raw(), vrc));
10371 switch (vrc)
10372 {
10373 case VERR_VUSB_NO_PORTS:
10374 hrc = setErrorBoth(E_FAIL, vrc, tr("Failed to attach the USB device. (No available ports on the USB controller)."));
10375 break;
10376 case VERR_VUSB_USBFS_PERMISSION:
10377 hrc = setErrorBoth(E_FAIL, vrc, tr("Not permitted to open the USB device, check usbfs options"));
10378 break;
10379 default:
10380 hrc = setErrorBoth(E_FAIL, vrc, tr("Failed to create a proxy device for the USB device. (Error: %Rrc)"), vrc);
10381 break;
10382 }
10383 }
10384
10385 return hrc;
10386}
10387
10388/**
10389 * USB device attach callback used by AttachUSBDevice().
10390 * Note that AttachUSBDevice() doesn't return until this callback is executed,
10391 * so we don't use AutoCaller and don't care about reference counters of
10392 * interface pointers passed in.
10393 *
10394 * @thread EMT
10395 * @note Locks the console object for writing.
10396 */
10397//static
10398DECLCALLBACK(int)
10399Console::i_usbAttachCallback(Console *that, PUVM pUVM, PCVMMR3VTABLE pVMM, IUSBDevice *aHostDevice, PCRTUUID aUuid,
10400 const char *pszBackend, const char *aAddress, PCFGMNODE pRemoteCfg, USBConnectionSpeed_T aEnmSpeed,
10401 ULONG aMaskedIfs, const char *pszCaptureFilename)
10402{
10403 RT_NOREF(aHostDevice);
10404 LogFlowFuncEnter();
10405 LogFlowFunc(("that={%p} aUuid={%RTuuid}\n", that, aUuid));
10406
10407 AssertReturn(that && aUuid, VERR_INVALID_PARAMETER);
10408 AssertReturn(!that->isWriteLockOnCurrentThread(), VERR_GENERAL_FAILURE);
10409
10410 VUSBSPEED enmSpeed = VUSB_SPEED_UNKNOWN;
10411 switch (aEnmSpeed)
10412 {
10413 case USBConnectionSpeed_Low: enmSpeed = VUSB_SPEED_LOW; break;
10414 case USBConnectionSpeed_Full: enmSpeed = VUSB_SPEED_FULL; break;
10415 case USBConnectionSpeed_High: enmSpeed = VUSB_SPEED_HIGH; break;
10416 case USBConnectionSpeed_Super: enmSpeed = VUSB_SPEED_SUPER; break;
10417 case USBConnectionSpeed_SuperPlus: enmSpeed = VUSB_SPEED_SUPERPLUS; break;
10418 default: AssertFailed(); break;
10419 }
10420
10421 int vrc = pVMM->pfnPDMR3UsbCreateProxyDevice(pUVM, aUuid, pszBackend, aAddress, pRemoteCfg,
10422 enmSpeed, aMaskedIfs, pszCaptureFilename);
10423 LogFlowFunc(("vrc=%Rrc\n", vrc));
10424 LogFlowFuncLeave();
10425 return vrc;
10426}
10427
10428/**
10429 * Sends a request to VMM to detach the given host device. After this method
10430 * succeeds, the detached device will disappear from the mUSBDevices
10431 * collection.
10432 *
10433 * @param aHostDevice device to attach
10434 *
10435 * @note Synchronously calls EMT.
10436 */
10437HRESULT Console::i_detachUSBDevice(const ComObjPtr<OUSBDevice> &aHostDevice)
10438{
10439 AssertReturn(!isWriteLockOnCurrentThread(), E_FAIL);
10440
10441 /* Get the VM handle. */
10442 SafeVMPtr ptrVM(this);
10443 if (!ptrVM.isOk())
10444 return ptrVM.hrc();
10445
10446 /* if the device is attached, then there must at least one USB hub. */
10447 AssertReturn(ptrVM.vtable()->pfnPDMR3UsbHasHub(ptrVM.rawUVM()), E_FAIL);
10448
10449 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
10450 LogFlowThisFunc(("Detaching USB proxy device {%RTuuid}...\n", aHostDevice->i_id().raw()));
10451
10452 /*
10453 * If this was a remote device, release the backend pointer.
10454 * The pointer was requested in usbAttachCallback.
10455 */
10456 BOOL fRemote = FALSE;
10457
10458 HRESULT hrc2 = aHostDevice->COMGETTER(Remote)(&fRemote);
10459 if (FAILED(hrc2))
10460 i_setErrorStatic(hrc2, "GetRemote() failed");
10461
10462 PCRTUUID pUuid = aHostDevice->i_id().raw();
10463 if (fRemote)
10464 {
10465 Guid guid(*pUuid);
10466 i_consoleVRDPServer()->USBBackendReleasePointer(&guid);
10467 }
10468
10469 alock.release();
10470 int vrc = ptrVM.vtable()->pfnVMR3ReqCallWaitU(ptrVM.rawUVM(), 0 /* idDstCpu (saved state, see #6232) */,
10471 (PFNRT)i_usbDetachCallback, 4,
10472 this, ptrVM.rawUVM(), ptrVM.vtable(), pUuid);
10473 if (RT_SUCCESS(vrc))
10474 {
10475 LogFlowFunc(("Detached device {%RTuuid}\n", pUuid));
10476
10477 /* notify callbacks */
10478 i_onUSBDeviceStateChange(aHostDevice, false /* aAttached */, NULL);
10479 }
10480
10481 ComAssertRCRet(vrc, E_FAIL);
10482
10483 return S_OK;
10484}
10485
10486/**
10487 * USB device detach callback used by DetachUSBDevice().
10488 *
10489 * Note that DetachUSBDevice() doesn't return until this callback is executed,
10490 * so we don't use AutoCaller and don't care about reference counters of
10491 * interface pointers passed in.
10492 *
10493 * @thread EMT
10494 */
10495//static
10496DECLCALLBACK(int)
10497Console::i_usbDetachCallback(Console *that, PUVM pUVM, PCVMMR3VTABLE pVMM, PCRTUUID aUuid)
10498{
10499 LogFlowFuncEnter();
10500 LogFlowFunc(("that={%p} aUuid={%RTuuid}\n", that, aUuid));
10501
10502 AssertReturn(that && aUuid, VERR_INVALID_PARAMETER);
10503 AssertReturn(!that->isWriteLockOnCurrentThread(), VERR_GENERAL_FAILURE);
10504
10505 int vrc = pVMM->pfnPDMR3UsbDetachDevice(pUVM, aUuid);
10506
10507 LogFlowFunc(("vrc=%Rrc\n", vrc));
10508 LogFlowFuncLeave();
10509 return vrc;
10510}
10511#endif /* VBOX_WITH_USB */
10512
10513/* Note: FreeBSD needs this whether netflt is used or not. */
10514#if ((defined(RT_OS_LINUX) && !defined(VBOX_WITH_NETFLT)) || defined(RT_OS_FREEBSD))
10515
10516/**
10517 * Helper function to handle host interface device creation and attachment.
10518 *
10519 * @param networkAdapter the network adapter which attachment should be reset
10520 * @return COM status code
10521 *
10522 * @note The caller must lock this object for writing.
10523 *
10524 * @todo Move this back into the driver!
10525 */
10526HRESULT Console::i_attachToTapInterface(INetworkAdapter *networkAdapter)
10527{
10528 LogFlowThisFunc(("\n"));
10529 /* sanity check */
10530 AssertReturn(isWriteLockOnCurrentThread(), E_FAIL);
10531
10532# ifdef VBOX_STRICT
10533 /* paranoia */
10534 NetworkAttachmentType_T attachment;
10535 networkAdapter->COMGETTER(AttachmentType)(&attachment);
10536 Assert(attachment == NetworkAttachmentType_Bridged);
10537# endif /* VBOX_STRICT */
10538
10539 ULONG slot = 0;
10540 HRESULT hrc = networkAdapter->COMGETTER(Slot)(&slot);
10541 AssertComRCReturnRC(hrc);
10542
10543# ifdef RT_OS_LINUX
10544 /*
10545 * Allocate a host interface device
10546 */
10547 int vrc = RTFileOpen(&maTapFD[slot], "/dev/net/tun",
10548 RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_NONE | RTFILE_O_INHERIT);
10549 if (RT_SUCCESS(vrc))
10550 {
10551 /*
10552 * Set/obtain the tap interface.
10553 */
10554 struct ifreq IfReq;
10555 RT_ZERO(IfReq);
10556 /* The name of the TAP interface we are using */
10557 Bstr tapDeviceName;
10558 hrc = networkAdapter->COMGETTER(BridgedInterface)(tapDeviceName.asOutParam());
10559 if (FAILED(hrc))
10560 tapDeviceName.setNull(); /* Is this necessary? */
10561 if (tapDeviceName.isEmpty())
10562 {
10563 LogRel(("No TAP device name was supplied.\n"));
10564 hrc = setError(E_FAIL, tr("No TAP device name was supplied for the host networking interface"));
10565 }
10566
10567 if (SUCCEEDED(hrc))
10568 {
10569 /* If we are using a static TAP device then try to open it. */
10570 Utf8Str str(tapDeviceName);
10571 RTStrCopy(IfReq.ifr_name, sizeof(IfReq.ifr_name), str.c_str()); /** @todo bitch about names which are too long... */
10572 IfReq.ifr_flags = IFF_TAP | IFF_NO_PI;
10573 vrc = ioctl(RTFileToNative(maTapFD[slot]), TUNSETIFF, &IfReq);
10574 if (vrc != 0)
10575 {
10576 LogRel(("Failed to open the host network interface %ls\n", tapDeviceName.raw()));
10577 hrc = setErrorBoth(E_FAIL, vrc, tr("Failed to open the host network interface %ls"), tapDeviceName.raw());
10578 }
10579 }
10580 if (SUCCEEDED(hrc))
10581 {
10582 /*
10583 * Make it pollable.
10584 */
10585 if (fcntl(RTFileToNative(maTapFD[slot]), F_SETFL, O_NONBLOCK) != -1)
10586 {
10587 Log(("i_attachToTapInterface: %RTfile %ls\n", maTapFD[slot], tapDeviceName.raw()));
10588 /*
10589 * Here is the right place to communicate the TAP file descriptor and
10590 * the host interface name to the server if/when it becomes really
10591 * necessary.
10592 */
10593 maTAPDeviceName[slot] = tapDeviceName;
10594 vrc = VINF_SUCCESS;
10595 }
10596 else
10597 {
10598 int iErr = errno;
10599
10600 LogRel(("Configuration error: Failed to configure /dev/net/tun non blocking. Error: %s\n", strerror(iErr)));
10601 vrc = VERR_HOSTIF_BLOCKING;
10602 hrc = setErrorBoth(E_FAIL, vrc, tr("could not set up the host networking device for non blocking access: %s"),
10603 strerror(errno));
10604 }
10605 }
10606 }
10607 else
10608 {
10609 LogRel(("Configuration error: Failed to open /dev/net/tun vrc=%Rrc\n", vrc));
10610 switch (vrc)
10611 {
10612 case VERR_ACCESS_DENIED:
10613 /* will be handled by our caller */
10614 hrc = E_ACCESSDENIED;
10615 break;
10616 default:
10617 hrc = setErrorBoth(E_FAIL, vrc, tr("Could not set up the host networking device: %Rrc"), vrc);
10618 break;
10619 }
10620 }
10621
10622# elif defined(RT_OS_FREEBSD)
10623 /*
10624 * Set/obtain the tap interface.
10625 */
10626 /* The name of the TAP interface we are using */
10627 Bstr tapDeviceName;
10628 hrc = networkAdapter->COMGETTER(BridgedInterface)(tapDeviceName.asOutParam());
10629 if (FAILED(hrc))
10630 tapDeviceName.setNull(); /* Is this necessary? */
10631 if (tapDeviceName.isEmpty())
10632 {
10633 LogRel(("No TAP device name was supplied.\n"));
10634 hrc = setError(E_FAIL, tr("No TAP device name was supplied for the host networking interface"));
10635 }
10636 char szTapdev[1024] = "/dev/";
10637 /* If we are using a static TAP device then try to open it. */
10638 Utf8Str str(tapDeviceName);
10639 if (str.length() + strlen(szTapdev) <= sizeof(szTapdev))
10640 strcat(szTapdev, str.c_str());
10641 else
10642 memcpy(szTapdev + strlen(szTapdev), str.c_str(),
10643 sizeof(szTapdev) - strlen(szTapdev) - 1); /** @todo bitch about names which are too long... */
10644 int vrc = RTFileOpen(&maTapFD[slot], szTapdev,
10645 RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_NONE | RTFILE_O_INHERIT | RTFILE_O_NON_BLOCK);
10646
10647 if (RT_SUCCESS(vrc))
10648 maTAPDeviceName[slot] = tapDeviceName;
10649 else
10650 {
10651 switch (vrc)
10652 {
10653 case VERR_ACCESS_DENIED:
10654 /* will be handled by our caller */
10655 hrc = E_ACCESSDENIED;
10656 break;
10657 default:
10658 hrc = setErrorBoth(E_FAIL, vrc, tr("Failed to open the host network interface %ls"), tapDeviceName.raw());
10659 break;
10660 }
10661 }
10662# else
10663# error "huh?"
10664# endif
10665 /* in case of failure, cleanup. */
10666 if (RT_FAILURE(vrc) && SUCCEEDED(hrc))
10667 {
10668 LogRel(("General failure attaching to host interface\n"));
10669 hrc = setErrorBoth(E_FAIL, vrc, tr("General failure attaching to host interface"));
10670 }
10671 LogFlowThisFunc(("hrc=%Rhrc\n", hrc));
10672 return hrc;
10673}
10674
10675
10676/**
10677 * Helper function to handle detachment from a host interface
10678 *
10679 * @param networkAdapter the network adapter which attachment should be reset
10680 * @return COM status code
10681 *
10682 * @note The caller must lock this object for writing.
10683 *
10684 * @todo Move this back into the driver!
10685 */
10686HRESULT Console::i_detachFromTapInterface(INetworkAdapter *networkAdapter)
10687{
10688 /* sanity check */
10689 LogFlowThisFunc(("\n"));
10690 AssertReturn(isWriteLockOnCurrentThread(), E_FAIL);
10691
10692# ifdef VBOX_STRICT
10693 /* paranoia */
10694 NetworkAttachmentType_T attachment;
10695 networkAdapter->COMGETTER(AttachmentType)(&attachment);
10696 Assert(attachment == NetworkAttachmentType_Bridged);
10697# endif /* VBOX_STRICT */
10698
10699 ULONG slot = 0;
10700 HRESULT hrc = networkAdapter->COMGETTER(Slot)(&slot);
10701 AssertComRCReturnRC(hrc);
10702
10703 /* is there an open TAP device? */
10704 if (maTapFD[slot] != NIL_RTFILE)
10705 {
10706 /*
10707 * Close the file handle.
10708 */
10709 Bstr tapDeviceName, tapTerminateApplication;
10710 bool isStatic = true;
10711 hrc = networkAdapter->COMGETTER(BridgedInterface)(tapDeviceName.asOutParam());
10712 if (FAILED(hrc) || tapDeviceName.isEmpty())
10713 {
10714 /* If the name is empty, this is a dynamic TAP device, so close it now,
10715 so that the termination script can remove the interface. Otherwise we still
10716 need the FD to pass to the termination script. */
10717 isStatic = false;
10718 int vrc = RTFileClose(maTapFD[slot]);
10719 AssertRC(vrc);
10720 maTapFD[slot] = NIL_RTFILE;
10721 }
10722 if (isStatic)
10723 {
10724 /* If we are using a static TAP device, we close it now, after having called the
10725 termination script. */
10726 int vrc = RTFileClose(maTapFD[slot]);
10727 AssertRC(vrc);
10728 }
10729 /* the TAP device name and handle are no longer valid */
10730 maTapFD[slot] = NIL_RTFILE;
10731 maTAPDeviceName[slot] = "";
10732 }
10733 LogFlowThisFunc(("returning %Rhrc\n", hrc));
10734 return hrc;
10735}
10736
10737#endif /* (RT_OS_LINUX || RT_OS_FREEBSD) && !VBOX_WITH_NETFLT */
10738
10739/**
10740 * Called at power down to terminate host interface networking.
10741 *
10742 * @note The caller must lock this object for writing.
10743 */
10744HRESULT Console::i_powerDownHostInterfaces()
10745{
10746 LogFlowThisFunc(("\n"));
10747
10748 /* sanity check */
10749 AssertReturn(isWriteLockOnCurrentThread(), E_FAIL);
10750
10751 /*
10752 * host interface termination handling
10753 */
10754 ComPtr<IVirtualBox> pVirtualBox;
10755 mMachine->COMGETTER(Parent)(pVirtualBox.asOutParam());
10756
10757 ComPtr<IPlatform> pPlatform;
10758 HRESULT hrc = mMachine->COMGETTER(Platform)(pPlatform.asOutParam());
10759 AssertComRC(hrc);
10760
10761 PlatformArchitecture_T platformArch;
10762 hrc = pPlatform->COMGETTER(Architecture)(&platformArch);
10763 AssertComRC(hrc);
10764
10765 ComPtr<IPlatformProperties> pPlatformProperties;
10766 hrc = pVirtualBox->GetPlatformProperties(platformArch, pPlatformProperties.asOutParam());
10767 AssertComRC(hrc);
10768
10769 ChipsetType_T chipsetType = ChipsetType_PIIX3;
10770 pPlatform->COMGETTER(ChipsetType)(&chipsetType);
10771 AssertComRC(hrc);
10772
10773 ULONG maxNetworkAdapters = 0;
10774 hrc = pPlatformProperties->GetMaxNetworkAdapters(chipsetType, &maxNetworkAdapters);
10775 AssertComRC(hrc);
10776
10777 for (ULONG slot = 0; slot < maxNetworkAdapters; slot++)
10778 {
10779 ComPtr<INetworkAdapter> pNetworkAdapter;
10780 hrc = mMachine->GetNetworkAdapter(slot, pNetworkAdapter.asOutParam());
10781 if (FAILED(hrc)) break;
10782
10783 BOOL enabled = FALSE;
10784 pNetworkAdapter->COMGETTER(Enabled)(&enabled);
10785 if (!enabled)
10786 continue;
10787
10788 NetworkAttachmentType_T attachment;
10789 pNetworkAdapter->COMGETTER(AttachmentType)(&attachment);
10790 if (attachment == NetworkAttachmentType_Bridged)
10791 {
10792#if ((defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD)) && !defined(VBOX_WITH_NETFLT))
10793 HRESULT hrc2 = i_detachFromTapInterface(pNetworkAdapter);
10794 if (FAILED(hrc2) && SUCCEEDED(hrc))
10795 hrc = hrc2;
10796#endif /* (RT_OS_LINUX || RT_OS_FREEBSD) && !VBOX_WITH_NETFLT */
10797 }
10798 }
10799
10800 return hrc;
10801}
10802
10803
10804/**
10805 * Process callback handler for VMR3LoadFromFile, VMR3LoadFromStream, VMR3Save
10806 * and VMR3Teleport.
10807 *
10808 * @param pUVM The user mode VM handle.
10809 * @param uPercent Completion percentage (0-100).
10810 * @param pvUser Pointer to an IProgress instance.
10811 * @return VINF_SUCCESS.
10812 */
10813/*static*/
10814DECLCALLBACK(int) Console::i_stateProgressCallback(PUVM pUVM, unsigned uPercent, void *pvUser)
10815{
10816 IProgress *pProgress = static_cast<IProgress *>(pvUser);
10817
10818 /* update the progress object */
10819 if (pProgress)
10820 {
10821 ComPtr<IInternalProgressControl> pProgressControl(pProgress);
10822 AssertReturn(!!pProgressControl, VERR_INVALID_PARAMETER);
10823 pProgressControl->SetCurrentOperationProgress(uPercent);
10824 }
10825
10826 NOREF(pUVM);
10827 return VINF_SUCCESS;
10828}
10829
10830/**
10831 * @copydoc FNVMATERROR
10832 *
10833 * @remarks Might be some tiny serialization concerns with access to the string
10834 * object here...
10835 */
10836/*static*/ DECLCALLBACK(void)
10837Console::i_genericVMSetErrorCallback(PUVM pUVM, void *pvUser, int vrc, RT_SRC_POS_DECL, const char *pszFormat, va_list args)
10838{
10839 RT_SRC_POS_NOREF();
10840 Utf8Str *pErrorText = (Utf8Str *)pvUser;
10841 AssertPtr(pErrorText);
10842
10843 /* We ignore RT_SRC_POS_DECL arguments to avoid confusion of end-users. */
10844 va_list va2;
10845 va_copy(va2, args);
10846
10847 /* Append to any the existing error message. */
10848 try
10849 {
10850 if (pErrorText->length())
10851 pErrorText->appendPrintf(".\n%N (%Rrc)", pszFormat, &va2, vrc, vrc);
10852 else
10853 pErrorText->printf("%N (%Rrc)", pszFormat, &va2, vrc, vrc);
10854 }
10855 catch (std::bad_alloc &)
10856 {
10857 }
10858
10859 va_end(va2);
10860
10861 NOREF(pUVM);
10862}
10863
10864/**
10865 * VM runtime error callback function (FNVMATRUNTIMEERROR).
10866 *
10867 * See VMSetRuntimeError for the detailed description of parameters.
10868 *
10869 * @param pUVM The user mode VM handle. Ignored, so passing NULL
10870 * is fine.
10871 * @param pvUser The user argument, pointer to the Console instance.
10872 * @param fFlags The action flags. See VMSETRTERR_FLAGS_*.
10873 * @param pszErrorId Error ID string.
10874 * @param pszFormat Error message format string.
10875 * @param va Error message arguments.
10876 * @thread EMT.
10877 */
10878/* static */ DECLCALLBACK(void)
10879Console::i_atVMRuntimeErrorCallback(PUVM pUVM, void *pvUser, uint32_t fFlags,
10880 const char *pszErrorId, const char *pszFormat, va_list va)
10881{
10882 bool const fFatal = !!(fFlags & VMSETRTERR_FLAGS_FATAL);
10883 LogFlowFuncEnter();
10884
10885 Console *that = static_cast<Console *>(pvUser);
10886 AssertReturnVoid(that);
10887
10888 Utf8Str message(pszFormat, va);
10889
10890 LogRel(("Console: VM runtime error: fatal=%RTbool, errorID=%s message=\"%s\"\n", fFatal, pszErrorId, message.c_str()));
10891 try
10892 {
10893 that->i_onRuntimeError(BOOL(fFatal), Bstr(pszErrorId).raw(), Bstr(message).raw());
10894 }
10895 catch (std::bad_alloc &)
10896 {
10897 }
10898 LogFlowFuncLeave(); NOREF(pUVM);
10899}
10900
10901/**
10902 * Captures USB devices that match filters of the VM.
10903 * Called at VM startup.
10904 *
10905 * @param pUVM The VM handle.
10906 */
10907HRESULT Console::i_captureUSBDevices(PUVM pUVM)
10908{
10909 RT_NOREF(pUVM);
10910 LogFlowThisFunc(("\n"));
10911
10912 /* sanity check */
10913 AssertReturn(!isWriteLockOnCurrentThread(), E_FAIL);
10914 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
10915
10916 /* If the machine has a USB controller, ask the USB proxy service to
10917 * capture devices */
10918 if (mfVMHasUsbController)
10919 {
10920 /* release the lock before calling Host in VBoxSVC since Host may call
10921 * us back from under its lock (e.g. onUSBDeviceAttach()) which would
10922 * produce an inter-process dead-lock otherwise. */
10923 alock.release();
10924
10925 HRESULT hrc = mControl->AutoCaptureUSBDevices();
10926 ComAssertComRCRetRC(hrc);
10927 }
10928
10929 return S_OK;
10930}
10931
10932
10933/**
10934 * Detach all USB device which are attached to the VM for the
10935 * purpose of clean up and such like.
10936 */
10937void Console::i_detachAllUSBDevices(bool aDone)
10938{
10939 LogFlowThisFunc(("aDone=%RTbool\n", aDone));
10940
10941 /* sanity check */
10942 AssertReturnVoid(!isWriteLockOnCurrentThread());
10943 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
10944
10945 mUSBDevices.clear();
10946
10947 /* release the lock before calling Host in VBoxSVC since Host may call
10948 * us back from under its lock (e.g. onUSBDeviceAttach()) which would
10949 * produce an inter-process dead-lock otherwise. */
10950 alock.release();
10951
10952 mControl->DetachAllUSBDevices(aDone);
10953}
10954
10955/* Make sure that the string is null-terminated and its size is less than cchMax bytes.
10956 * Replace invalid UTF8 bytes with '?'.
10957 */
10958static int validateUtf8String(char *psz, size_t cchMax)
10959{
10960 for (;;)
10961 {
10962 RTUNICP Cp;
10963 int vrc = RTStrGetCpNEx((const char **)&psz, &cchMax, &Cp);
10964 if (RT_SUCCESS(vrc))
10965 {
10966 if (!Cp)
10967 break;
10968 }
10969 else
10970 {
10971 if (!cchMax)
10972 return VERR_END_OF_STRING;
10973
10974 psz[-1] = '?';
10975 }
10976 }
10977 return VINF_SUCCESS;
10978}
10979
10980static int validateRemoteUSBDeviceDesc(VRDEUSBDEVICEDESC const *e, uint32_t cbRemaining, bool fDescExt)
10981{
10982 uint32_t const cbDesc = fDescExt ? sizeof(VRDEUSBDEVICEDESCEXT) : sizeof(VRDEUSBDEVICEDESC);
10983 if (cbDesc > cbRemaining)
10984 return VERR_INVALID_PARAMETER;
10985
10986 if ( e->oNext > cbRemaining /* It is OK for oNext to point to the end of buffer. */
10987 || e->oManufacturer >= cbRemaining
10988 || e->oProduct >= cbRemaining
10989 || e->oSerialNumber >= cbRemaining)
10990 return VERR_INVALID_PARAMETER;
10991
10992 int vrc;
10993 if (e->oManufacturer)
10994 {
10995 vrc = validateUtf8String((char *)e + e->oManufacturer, cbRemaining - e->oManufacturer);
10996 if (RT_FAILURE(vrc))
10997 return VERR_INVALID_PARAMETER;
10998 }
10999 if (e->oProduct)
11000 {
11001 vrc = validateUtf8String((char *)e + e->oProduct, cbRemaining - e->oProduct);
11002 if (RT_FAILURE(vrc))
11003 return VERR_INVALID_PARAMETER;
11004 }
11005 if (e->oSerialNumber)
11006 {
11007 vrc = validateUtf8String((char *)e + e->oSerialNumber, cbRemaining - e->oSerialNumber);
11008 if (RT_FAILURE(vrc))
11009 return VERR_INVALID_PARAMETER;
11010 }
11011
11012 return VINF_SUCCESS;
11013}
11014
11015/**
11016 * @note Locks this object for writing.
11017 */
11018void Console::i_processRemoteUSBDevices(uint32_t u32ClientId, VRDEUSBDEVICEDESC *pDevList, uint32_t cbDevList, bool fDescExt)
11019{
11020 LogFlowThisFuncEnter();
11021 LogFlowThisFunc(("u32ClientId = %d, pDevList=%p, cbDevList = %d, fDescExt = %d\n",
11022 u32ClientId, pDevList, cbDevList, fDescExt));
11023
11024 AutoCaller autoCaller(this);
11025 if (!autoCaller.isOk())
11026 {
11027 /* Console has been already uninitialized, deny request */
11028 AssertMsgFailed(("Console is already uninitialized\n"));
11029 LogFlowThisFunc(("Console is already uninitialized\n"));
11030 LogFlowThisFuncLeave();
11031 return;
11032 }
11033
11034 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
11035
11036 /*
11037 * Mark all existing remote USB devices as dirty.
11038 */
11039 for (RemoteUSBDeviceList::iterator it = mRemoteUSBDevices.begin();
11040 it != mRemoteUSBDevices.end();
11041 ++it)
11042 {
11043 (*it)->dirty(true);
11044 }
11045
11046 /*
11047 * Process the pDevList and add devices those are not already in the mRemoteUSBDevices list.
11048 */
11049 VRDEUSBDEVICEDESC *e = pDevList;
11050 uint32_t cbRemaining = cbDevList;
11051
11052 /* The cbRemaining condition must be checked first, because the function can
11053 * receive pDevList = NULL and cbDevList = 0 on client disconnect.
11054 */
11055 while (cbRemaining >= sizeof(e->oNext) && e->oNext)
11056 {
11057 int const vrc = validateRemoteUSBDeviceDesc(e, cbRemaining, fDescExt);
11058 if (RT_FAILURE(vrc))
11059 break; /* Consider the rest of the list invalid too. */
11060
11061 LogFlowThisFunc(("vendor %04x, product %04x, name = %s\n",
11062 e->idVendor, e->idProduct, e->oProduct ? (char *)e + e->oProduct : ""));
11063
11064 bool fNewDevice = true;
11065
11066 for (RemoteUSBDeviceList::iterator it = mRemoteUSBDevices.begin();
11067 it != mRemoteUSBDevices.end();
11068 ++it)
11069 {
11070 if ( (*it)->devId() == e->id
11071 && (*it)->clientId() == u32ClientId)
11072 {
11073 /* The device is already in the list. */
11074 (*it)->dirty(false);
11075 fNewDevice = false;
11076 break;
11077 }
11078 }
11079
11080 if (fNewDevice)
11081 {
11082 LogRel(("Remote USB: ++++ Vendor %04X. Product %04X. Name = [%s].\n",
11083 e->idVendor, e->idProduct, e->oProduct? (char *)e + e->oProduct: ""));
11084
11085 /* Create the device object and add the new device to list. */
11086 ComObjPtr<RemoteUSBDevice> pUSBDevice;
11087 pUSBDevice.createObject();
11088 pUSBDevice->init(u32ClientId, e, fDescExt);
11089
11090 mRemoteUSBDevices.push_back(pUSBDevice);
11091
11092 /* Check if the device is ok for current USB filters. */
11093 BOOL fMatched = FALSE;
11094 ULONG fMaskedIfs = 0;
11095 HRESULT hrc = mControl->RunUSBDeviceFilters(pUSBDevice, &fMatched, &fMaskedIfs);
11096
11097 AssertComRC(hrc);
11098
11099 LogFlowThisFunc(("USB filters return %d %#x\n", fMatched, fMaskedIfs));
11100
11101 if (fMatched)
11102 {
11103 alock.release();
11104 hrc = i_onUSBDeviceAttach(pUSBDevice, NULL, fMaskedIfs, Utf8Str());
11105 alock.acquire();
11106
11107 /// @todo (r=dmik) warning reporting subsystem
11108
11109 if (hrc == S_OK)
11110 {
11111 LogFlowThisFunc(("Device attached\n"));
11112 pUSBDevice->captured(true);
11113 }
11114 }
11115 }
11116
11117 AssertBreak(cbRemaining >= e->oNext); /* validateRemoteUSBDeviceDesc ensures this. */
11118 cbRemaining -= e->oNext;
11119
11120 e = (VRDEUSBDEVICEDESC *)((uint8_t *)e + e->oNext);
11121 }
11122
11123 /*
11124 * Remove dirty devices, that is those which are not reported by the server anymore.
11125 */
11126 for (;;)
11127 {
11128 ComObjPtr<RemoteUSBDevice> pUSBDevice;
11129
11130 RemoteUSBDeviceList::iterator it = mRemoteUSBDevices.begin();
11131 while (it != mRemoteUSBDevices.end())
11132 {
11133 if ((*it)->dirty())
11134 {
11135 pUSBDevice = *it;
11136 break;
11137 }
11138
11139 ++it;
11140 }
11141
11142 if (!pUSBDevice)
11143 {
11144 break;
11145 }
11146
11147 USHORT vendorId = 0;
11148 pUSBDevice->COMGETTER(VendorId)(&vendorId);
11149
11150 USHORT productId = 0;
11151 pUSBDevice->COMGETTER(ProductId)(&productId);
11152
11153 Bstr product;
11154 pUSBDevice->COMGETTER(Product)(product.asOutParam());
11155
11156 LogRel(("Remote USB: ---- Vendor %04x. Product %04x. Name = [%ls].\n", vendorId, productId, product.raw()));
11157
11158 /* Detach the device from VM. */
11159 if (pUSBDevice->captured())
11160 {
11161 Bstr uuid;
11162 pUSBDevice->COMGETTER(Id)(uuid.asOutParam());
11163 alock.release();
11164 i_onUSBDeviceDetach(uuid.raw(), NULL);
11165 alock.acquire();
11166 }
11167
11168 /* And remove it from the list. */
11169 mRemoteUSBDevices.erase(it);
11170 }
11171
11172 LogFlowThisFuncLeave();
11173}
11174
11175
11176/**
11177 * Worker called by VMPowerUpTask::handler to start the VM (also from saved
11178 * state) and track progress.
11179 *
11180 * @param pTask The power up task.
11181 *
11182 * @note Locks the Console object for writing.
11183 */
11184/*static*/
11185void Console::i_powerUpThreadTask(VMPowerUpTask *pTask)
11186{
11187 LogFlowFuncEnter();
11188
11189 AssertReturnVoid(pTask);
11190 AssertReturnVoid(!pTask->mConsole.isNull());
11191 AssertReturnVoid(!pTask->mProgress.isNull());
11192
11193 VirtualBoxBase::initializeComForThread();
11194
11195 HRESULT hrc = S_OK;
11196 int vrc = VINF_SUCCESS;
11197
11198 /* Set up a build identifier so that it can be seen from core dumps what
11199 * exact build was used to produce the core. */
11200 static char s_szBuildID[48];
11201 RTStrPrintf(s_szBuildID, sizeof(s_szBuildID), "%s%s%s%s VirtualBox %s r%u %s%s%s%s",
11202 "BU", "IL", "DI", "D", RTBldCfgVersion(), RTBldCfgRevision(), "BU", "IL", "DI", "D");
11203
11204 ComObjPtr<Console> pConsole = pTask->mConsole;
11205
11206 /* Note: no need to use AutoCaller because VMPowerUpTask does that */
11207
11208 /* The lock is also used as a signal from the task initiator (which
11209 * releases it only after RTThreadCreate()) that we can start the job */
11210 AutoWriteLock alock(pConsole COMMA_LOCKVAL_SRC_POS);
11211
11212 /* sanity */
11213 Assert(pConsole->mpUVM == NULL);
11214
11215 try
11216 {
11217 // Create the VMM device object, which starts the HGCM thread; do this only
11218 // once for the console, for the pathological case that the same console
11219 // object is used to power up a VM twice.
11220 if (!pConsole->m_pVMMDev)
11221 {
11222 pConsole->m_pVMMDev = new VMMDev(pConsole);
11223 AssertReturnVoid(pConsole->m_pVMMDev);
11224 }
11225
11226 /* wait for auto reset ops to complete so that we can successfully lock
11227 * the attached hard disks by calling LockMedia() below */
11228 for (VMPowerUpTask::ProgressList::const_iterator
11229 it = pTask->hardDiskProgresses.begin();
11230 it != pTask->hardDiskProgresses.end(); ++it)
11231 {
11232 HRESULT hrc2 = (*it)->WaitForCompletion(-1);
11233 AssertComRC(hrc2);
11234
11235 hrc = pTask->mProgress->SetNextOperation(BstrFmt(tr("Disk Image Reset Operation - Immutable Image")).raw(), 1);
11236 AssertComRCReturnVoid(hrc);
11237 }
11238
11239 /*
11240 * Lock attached media. This method will also check their accessibility.
11241 * If we're a teleporter, we'll have to postpone this action so we can
11242 * migrate between local processes.
11243 *
11244 * Note! The media will be unlocked automatically by
11245 * SessionMachine::i_setMachineState() when the VM is powered down.
11246 */
11247 if (!pTask->mTeleporterEnabled)
11248 {
11249 hrc = pConsole->mControl->LockMedia();
11250 if (FAILED(hrc)) throw hrc;
11251 }
11252
11253 /* Create the VRDP server. In case of headless operation, this will
11254 * also create the framebuffer, required at VM creation.
11255 */
11256 ConsoleVRDPServer *server = pConsole->i_consoleVRDPServer();
11257 Assert(server);
11258
11259 /* Does VRDP server call Console from the other thread?
11260 * Not sure (and can change), so release the lock just in case.
11261 */
11262 alock.release();
11263 vrc = server->Launch();
11264 alock.acquire();
11265
11266 if (vrc != VINF_SUCCESS)
11267 {
11268 Utf8Str errMsg = pConsole->VRDPServerErrorToMsg(vrc);
11269 if ( RT_FAILURE(vrc)
11270 && vrc != VERR_NET_ADDRESS_IN_USE) /* not fatal */
11271 throw i_setErrorStaticBoth(E_FAIL, vrc, errMsg.c_str());
11272 }
11273
11274 ComPtr<IMachine> pMachine = pConsole->i_machine();
11275 ULONG cCpus = 1;
11276 pMachine->COMGETTER(CPUCount)(&cCpus);
11277
11278 VMProcPriority_T enmVMPriority = VMProcPriority_Default;
11279 pMachine->COMGETTER(VMProcessPriority)(&enmVMPriority);
11280
11281 /*
11282 * Create the VM
11283 *
11284 * Note! Release the lock since EMT will call Console. It's safe because
11285 * mMachineState is either Starting or Restoring state here.
11286 */
11287 alock.release();
11288
11289 if (enmVMPriority != VMProcPriority_Default)
11290 pConsole->i_onVMProcessPriorityChange(enmVMPriority);
11291
11292 PCVMMR3VTABLE pVMM = pConsole->mpVMM;
11293 PVM pVM = NULL;
11294 vrc = pVMM->pfnVMR3Create(cCpus,
11295 pConsole->mpVmm2UserMethods,
11296 0 /*fFlags*/,
11297 Console::i_genericVMSetErrorCallback,
11298 &pTask->mErrorMsg,
11299 pTask->mpfnConfigConstructor,
11300 static_cast<Console *>(pConsole),
11301 &pVM, NULL);
11302 alock.acquire();
11303 if (RT_SUCCESS(vrc))
11304 {
11305 do /* break "loop" */
11306 {
11307 /*
11308 * Register our load/save state file handlers
11309 */
11310 vrc = pVMM->pfnSSMR3RegisterExternal(pConsole->mpUVM, sSSMConsoleUnit, 0 /*iInstance*/,
11311 CONSOLE_SAVED_STATE_VERSION, 0 /* cbGuess */,
11312 NULL, NULL, NULL,
11313 NULL, i_saveStateFileExec, NULL,
11314 NULL, i_loadStateFileExec, NULL,
11315 static_cast<Console *>(pConsole));
11316 AssertRCBreak(vrc);
11317
11318 vrc = static_cast<Console *>(pConsole)->i_getDisplay()->i_registerSSM(pConsole->mpUVM);
11319 AssertRC(vrc);
11320 if (RT_FAILURE(vrc))
11321 break;
11322
11323 /*
11324 * Synchronize debugger settings
11325 */
11326 MachineDebugger *machineDebugger = pConsole->i_getMachineDebugger();
11327 if (machineDebugger)
11328 machineDebugger->i_flushQueuedSettings();
11329
11330 /*
11331 * Shared Folders
11332 */
11333 if (pConsole->m_pVMMDev->isShFlActive())
11334 {
11335 /* Does the code below call Console from the other thread?
11336 * Not sure, so release the lock just in case. */
11337 alock.release();
11338
11339 for (SharedFolderDataMap::const_iterator it = pTask->mSharedFolders.begin();
11340 it != pTask->mSharedFolders.end();
11341 ++it)
11342 {
11343 const SharedFolderData &d = it->second;
11344 hrc = pConsole->i_createSharedFolder(it->first, d);
11345 if (FAILED(hrc))
11346 {
11347 ErrorInfoKeeper eik;
11348 pConsole->i_atVMRuntimeErrorCallbackF(0, "BrokenSharedFolder",
11349 N_("The shared folder '%s' could not be set up: %ls.\n"
11350 "The shared folder setup will not be complete. It is recommended to power down the virtual "
11351 "machine and fix the shared folder settings while the machine is not running"),
11352 it->first.c_str(), eik.getText().raw());
11353 }
11354 }
11355 if (FAILED(hrc))
11356 hrc = S_OK; // do not fail with broken shared folders
11357
11358 /* acquire the lock again */
11359 alock.acquire();
11360 }
11361
11362#ifdef VBOX_WITH_AUDIO_VRDE
11363 /*
11364 * Attach the VRDE audio driver.
11365 */
11366 if (pConsole->i_getVRDEServer())
11367 {
11368 BOOL fVRDEEnabled = FALSE;
11369 hrc = pConsole->i_getVRDEServer()->COMGETTER(Enabled)(&fVRDEEnabled);
11370 AssertComRCBreak(hrc, RT_NOTHING);
11371
11372 if ( fVRDEEnabled
11373 && pConsole->mAudioVRDE)
11374 pConsole->mAudioVRDE->doAttachDriverViaEmt(pConsole->mpUVM, pVMM, &alock);
11375 }
11376#endif
11377
11378 /*
11379 * Enable client connections to the VRDP server.
11380 */
11381 pConsole->i_consoleVRDPServer()->EnableConnections();
11382
11383 /* Release the lock before a lengthy operation. */
11384 alock.release();
11385
11386#ifdef VBOX_WITH_RECORDING
11387 /*
11388 * Start recording if configured.
11389 */
11390 ComPtr<IRecordingSettings> pRecordingSettings;
11391 hrc = pConsole->mMachine->COMGETTER(RecordingSettings)(pRecordingSettings.asOutParam());
11392 AssertComRCBreak(hrc, RT_NOTHING);
11393
11394 BOOL fRecordingEnabled = FALSE;
11395 hrc = pRecordingSettings->COMGETTER(Enabled)(&fRecordingEnabled);
11396 AssertComRCBreak(hrc, RT_NOTHING);
11397
11398 if (fRecordingEnabled)
11399 {
11400 ComPtr<IProgress> pProgress;
11401 hrc = pRecordingSettings->Start(pProgress.asOutParam());
11402 if (FAILED(hrc))
11403 {
11404 com::ErrorInfoKeeper eik;
11405 ComPtr<IVirtualBoxErrorInfo> pErrorInfo = eik.takeError();
11406 Bstr strMsg;
11407 hrc = pErrorInfo->COMGETTER(Text)(strMsg.asOutParam());
11408 AssertComRCBreak(hrc, RT_NOTHING);
11409 LONG lRc;
11410 hrc = pErrorInfo->COMGETTER(ResultCode)(&lRc);
11411 AssertComRCBreak(hrc, RT_NOTHING);
11412
11413 LogRel(("Recording: Failed to start on VM power up: %ls (%Rrc)\n",
11414 strMsg.raw(), lRc));
11415 }
11416 }
11417#endif
11418 /*
11419 * Capture USB devices.
11420 */
11421 hrc = pConsole->i_captureUSBDevices(pConsole->mpUVM);
11422 if (FAILED(hrc))
11423 {
11424 alock.acquire();
11425 break;
11426 }
11427
11428 /*
11429 * Load saved state?
11430 */
11431 if (pTask->mSavedStateFile.length())
11432 {
11433 LogFlowFunc(("Restoring saved state from '%s'...\n", pTask->mSavedStateFile.c_str()));
11434
11435#ifdef VBOX_WITH_FULL_VM_ENCRYPTION
11436 SsmStream ssmStream(pConsole, pVMM, pTask->m_pKeyStore, pTask->mKeyId, pTask->mKeyStore);
11437
11438 vrc = ssmStream.open(pTask->mSavedStateFile.c_str());
11439 if (RT_SUCCESS(vrc))
11440 {
11441 PCSSMSTRMOPS pStreamOps;
11442 void *pvStreamOpsUser;
11443
11444 vrc = ssmStream.querySsmStrmOps(&pStreamOps, &pvStreamOpsUser);
11445 if (RT_SUCCESS(vrc))
11446 vrc = pVMM->pfnVMR3LoadFromStream(pConsole->mpUVM,
11447 pStreamOps, pvStreamOpsUser,
11448 Console::i_stateProgressCallback,
11449 static_cast<IProgress *>(pTask->mProgress),
11450 false /*fTeleporting*/);
11451 }
11452#else
11453 vrc = pVMM->pfnVMR3LoadFromFile(pConsole->mpUVM,
11454 pTask->mSavedStateFile.c_str(),
11455 Console::i_stateProgressCallback,
11456 static_cast<IProgress *>(pTask->mProgress));
11457#endif
11458 if (RT_SUCCESS(vrc))
11459 {
11460 if (pTask->mStartPaused)
11461 /* done */
11462 pConsole->i_setMachineState(MachineState_Paused);
11463 else
11464 {
11465 /* Start/Resume the VM execution */
11466#ifdef VBOX_WITH_EXTPACK
11467 vrc = pConsole->mptrExtPackManager->i_callAllVmPowerOnHooks(pConsole, pVM, pVMM);
11468#endif
11469 if (RT_SUCCESS(vrc))
11470 vrc = pVMM->pfnVMR3Resume(pConsole->mpUVM, VMRESUMEREASON_STATE_RESTORED);
11471 AssertLogRelRC(vrc);
11472 }
11473 }
11474
11475 /* Power off in case we failed loading or resuming the VM */
11476 if (RT_FAILURE(vrc))
11477 {
11478 int vrc2 = pVMM->pfnVMR3PowerOff(pConsole->mpUVM); AssertLogRelRC(vrc2);
11479#ifdef VBOX_WITH_EXTPACK
11480 pConsole->mptrExtPackManager->i_callAllVmPowerOffHooks(pConsole, pVM, pVMM);
11481#endif
11482 }
11483 }
11484 else if (pTask->mTeleporterEnabled)
11485 {
11486 /* -> ConsoleImplTeleporter.cpp */
11487 bool fPowerOffOnFailure;
11488 hrc = pConsole->i_teleporterTrg(pConsole->mpUVM, pConsole->mpVMM, pMachine, &pTask->mErrorMsg,
11489 pTask->mStartPaused, pTask->mProgress, &fPowerOffOnFailure);
11490 if (FAILED(hrc) && fPowerOffOnFailure)
11491 {
11492 ErrorInfoKeeper eik;
11493 int vrc2 = pVMM->pfnVMR3PowerOff(pConsole->mpUVM); AssertLogRelRC(vrc2);
11494#ifdef VBOX_WITH_EXTPACK
11495 pConsole->mptrExtPackManager->i_callAllVmPowerOffHooks(pConsole, pVM, pVMM);
11496#endif
11497 }
11498 }
11499 else if (pTask->mStartPaused)
11500 /* done */
11501 pConsole->i_setMachineState(MachineState_Paused);
11502 else
11503 {
11504 /* Power on the VM (i.e. start executing) */
11505#ifdef VBOX_WITH_EXTPACK
11506 vrc = pConsole->mptrExtPackManager->i_callAllVmPowerOnHooks(pConsole, pVM, pVMM);
11507#endif
11508 if (RT_SUCCESS(vrc))
11509 vrc = pVMM->pfnVMR3PowerOn(pConsole->mpUVM);
11510 AssertLogRelRC(vrc);
11511 }
11512
11513 /* acquire the lock again */
11514 alock.acquire();
11515 }
11516 while (0);
11517
11518 /* On failure, destroy the VM */
11519 if (FAILED(hrc) || RT_FAILURE(vrc))
11520 {
11521 /* preserve existing error info */
11522 ErrorInfoKeeper eik;
11523
11524 /* powerDown() will call VMR3Destroy() and do all necessary
11525 * cleanup (VRDP, USB devices) */
11526 alock.release();
11527 HRESULT hrc2 = pConsole->i_powerDown();
11528 alock.acquire();
11529 AssertComRC(hrc2);
11530 }
11531 else
11532 {
11533 /*
11534 * Deregister the VMSetError callback. This is necessary as the
11535 * pfnVMAtError() function passed to VMR3Create() is supposed to
11536 * be sticky but our error callback isn't.
11537 */
11538 alock.release();
11539 pVMM->pfnVMR3AtErrorDeregister(pConsole->mpUVM, Console::i_genericVMSetErrorCallback, &pTask->mErrorMsg);
11540 /** @todo register another VMSetError callback? */
11541 alock.acquire();
11542 }
11543 }
11544 else
11545 {
11546 /*
11547 * If VMR3Create() failed it has released the VM memory.
11548 */
11549 if (pConsole->m_pVMMDev)
11550 {
11551 alock.release(); /* just to be on the safe side... */
11552 pConsole->m_pVMMDev->hgcmShutdown(true /*fUvmIsInvalid*/);
11553 alock.acquire();
11554 }
11555 pVMM->pfnVMR3ReleaseUVM(pConsole->mpUVM);
11556 pConsole->mpUVM = NULL;
11557 }
11558
11559 if (SUCCEEDED(hrc) && RT_FAILURE(vrc))
11560 {
11561 /* If VMR3Create() or one of the other calls in this function fail,
11562 * an appropriate error message has been set in pTask->mErrorMsg.
11563 * However since that happens via a callback, the hrc status code in
11564 * this function is not updated.
11565 */
11566 if (!pTask->mErrorMsg.length())
11567 {
11568 /* If the error message is not set but we've got a failure,
11569 * convert the VBox status code into a meaningful error message.
11570 * This becomes unused once all the sources of errors set the
11571 * appropriate error message themselves.
11572 */
11573 AssertMsgFailed(("Missing error message during powerup for status code %Rrc\n", vrc));
11574 pTask->mErrorMsg = Utf8StrFmt(tr("Failed to start VM execution (%Rrc)"), vrc);
11575 }
11576
11577 /* Set the error message as the COM error.
11578 * Progress::notifyComplete() will pick it up later. */
11579 throw i_setErrorStaticBoth(E_FAIL, vrc, pTask->mErrorMsg.c_str());
11580 }
11581 }
11582 catch (HRESULT hrcXcpt) { hrc = hrcXcpt; }
11583
11584 if ( pConsole->mMachineState == MachineState_Starting
11585 || pConsole->mMachineState == MachineState_Restoring
11586 || pConsole->mMachineState == MachineState_TeleportingIn
11587 )
11588 {
11589 /* We are still in the Starting/Restoring state. This means one of:
11590 *
11591 * 1) we failed before VMR3Create() was called;
11592 * 2) VMR3Create() failed.
11593 *
11594 * In both cases, there is no need to call powerDown(), but we still
11595 * need to go back to the PoweredOff/Saved state. Reuse
11596 * vmstateChangeCallback() for that purpose.
11597 */
11598
11599 /* preserve existing error info */
11600 ErrorInfoKeeper eik;
11601
11602 Assert(pConsole->mpUVM == NULL);
11603 i_vmstateChangeCallback(NULL, pConsole->mpVMM, VMSTATE_TERMINATED, VMSTATE_CREATING, pConsole);
11604 }
11605
11606 /*
11607 * Evaluate the final result. Note that the appropriate mMachineState value
11608 * is already set by vmstateChangeCallback() in all cases.
11609 */
11610
11611 /* release the lock, don't need it any more */
11612 alock.release();
11613
11614 if (SUCCEEDED(hrc))
11615 {
11616 /* Notify the progress object of the success */
11617 pTask->mProgress->i_notifyComplete(S_OK);
11618 }
11619 else
11620 {
11621 /* The progress object will fetch the current error info */
11622 pTask->mProgress->i_notifyComplete(hrc);
11623 LogRel(("Power up failed (vrc=%Rrc, hrc=%Rhrc (%#08X))\n", vrc, hrc, hrc));
11624 }
11625
11626 /* Notify VBoxSVC and any waiting openRemoteSession progress object. */
11627 pConsole->mControl->EndPowerUp(hrc);
11628
11629#if defined(RT_OS_WINDOWS)
11630 /* uninitialize COM */
11631 CoUninitialize();
11632#endif
11633
11634 LogFlowFuncLeave();
11635}
11636
11637
11638/**
11639 * Reconfigures a medium attachment (part of taking or deleting an online snapshot).
11640 *
11641 * @param pThis Reference to the console object.
11642 * @param pUVM The VM handle.
11643 * @param pVMM The VMM vtable.
11644 * @param pcszDevice The name of the controller type.
11645 * @param uInstance The instance of the controller.
11646 * @param enmBus The storage bus type of the controller.
11647 * @param fUseHostIOCache Use the host I/O cache (disable async I/O).
11648 * @param fBuiltinIOCache Use the builtin I/O cache.
11649 * @param fInsertDiskIntegrityDrv Flag whether to insert the disk integrity driver into the chain
11650 * for additionalk debugging aids.
11651 * @param fSetupMerge Whether to set up a medium merge
11652 * @param uMergeSource Merge source image index
11653 * @param uMergeTarget Merge target image index
11654 * @param aMediumAtt The medium attachment.
11655 * @param aMachineState The current machine state.
11656 * @param phrc Where to store com error - only valid if we return VERR_GENERAL_FAILURE.
11657 * @return VBox status code.
11658 */
11659/* static */
11660DECLCALLBACK(int) Console::i_reconfigureMediumAttachment(Console *pThis,
11661 PUVM pUVM,
11662 PCVMMR3VTABLE pVMM,
11663 const char *pcszDevice,
11664 unsigned uInstance,
11665 StorageBus_T enmBus,
11666 bool fUseHostIOCache,
11667 bool fBuiltinIOCache,
11668 bool fInsertDiskIntegrityDrv,
11669 bool fSetupMerge,
11670 unsigned uMergeSource,
11671 unsigned uMergeTarget,
11672 IMediumAttachment *aMediumAtt,
11673 MachineState_T aMachineState,
11674 HRESULT *phrc)
11675{
11676 LogFlowFunc(("pUVM=%p aMediumAtt=%p phrc=%p\n", pUVM, aMediumAtt, phrc));
11677
11678 HRESULT hrc;
11679 Bstr bstr;
11680 *phrc = S_OK;
11681#define H() do { if (FAILED(hrc)) { AssertMsgFailed(("hrc=%Rhrc (%#x)\n", hrc, hrc)); *phrc = hrc; return VERR_GENERAL_FAILURE; } } while (0)
11682
11683 /* Ignore attachments other than hard disks, since at the moment they are
11684 * not subject to snapshotting in general. */
11685 DeviceType_T lType;
11686 hrc = aMediumAtt->COMGETTER(Type)(&lType); H();
11687 if (lType != DeviceType_HardDisk)
11688 return VINF_SUCCESS;
11689
11690 /* Update the device instance configuration. */
11691 int vrc = pThis->i_configMediumAttachment(pcszDevice,
11692 uInstance,
11693 enmBus,
11694 fUseHostIOCache,
11695 fBuiltinIOCache,
11696 fInsertDiskIntegrityDrv,
11697 fSetupMerge,
11698 uMergeSource,
11699 uMergeTarget,
11700 aMediumAtt,
11701 aMachineState,
11702 phrc,
11703 true /* fAttachDetach */,
11704 false /* fForceUnmount */,
11705 false /* fHotplug */,
11706 pUVM,
11707 pVMM,
11708 NULL /* paLedDevType */,
11709 NULL /* ppLunL0)*/);
11710 if (RT_FAILURE(vrc))
11711 {
11712 AssertMsgFailed(("vrc=%Rrc\n", vrc));
11713 return vrc;
11714 }
11715
11716#undef H
11717
11718 LogFlowFunc(("Returns success\n"));
11719 return VINF_SUCCESS;
11720}
11721
11722/**
11723 * Thread for powering down the Console.
11724 *
11725 * @param pTask The power down task.
11726 *
11727 * @note Locks the Console object for writing.
11728 */
11729/*static*/
11730void Console::i_powerDownThreadTask(VMPowerDownTask *pTask)
11731{
11732 int vrc = VINF_SUCCESS; /* only used in assertion */
11733 LogFlowFuncEnter();
11734 try
11735 {
11736 if (pTask->isOk() == false)
11737 vrc = VERR_GENERAL_FAILURE;
11738
11739 const ComObjPtr<Console> &that = pTask->mConsole;
11740
11741 /* Note: no need to use AutoCaller to protect Console because VMTask does
11742 * that */
11743
11744 /* wait until the method tat started us returns */
11745 AutoWriteLock thatLock(that COMMA_LOCKVAL_SRC_POS);
11746
11747 /* release VM caller to avoid the powerDown() deadlock */
11748 pTask->releaseVMCaller();
11749
11750 thatLock.release();
11751
11752 that->i_powerDown(pTask->mServerProgress);
11753
11754 /* complete the operation */
11755 that->mControl->EndPoweringDown(S_OK, Bstr().raw());
11756
11757 }
11758 catch (const std::exception &e)
11759 {
11760 AssertMsgFailed(("Exception %s was caught, vrc=%Rrc\n", e.what(), vrc));
11761 NOREF(e); NOREF(vrc);
11762 }
11763
11764 LogFlowFuncLeave();
11765}
11766
11767/**
11768 * @interface_method_impl{VMM2USERMETHODS,pfnSaveState}
11769 */
11770/*static*/ DECLCALLBACK(int)
11771Console::i_vmm2User_SaveState(PCVMM2USERMETHODS pThis, PUVM pUVM)
11772{
11773 Console *pConsole = ((MYVMM2USERMETHODS *)pThis)->pConsole;
11774 NOREF(pUVM);
11775
11776 /*
11777 * For now, just call SaveState. We should probably try notify the GUI so
11778 * it can pop up a progress object and stuff. The progress object created
11779 * by the call isn't returned to anyone and thus gets updated without
11780 * anyone noticing it.
11781 */
11782 ComPtr<IProgress> pProgress;
11783 HRESULT hrc = pConsole->mMachine->SaveState(pProgress.asOutParam());
11784 return SUCCEEDED(hrc) ? VINF_SUCCESS : Global::vboxStatusCodeFromCOM(hrc);
11785}
11786
11787/**
11788 * @interface_method_impl{VMM2USERMETHODS,pfnNotifyEmtInit}
11789 */
11790/*static*/ DECLCALLBACK(void)
11791Console::i_vmm2User_NotifyEmtInit(PCVMM2USERMETHODS pThis, PUVM pUVM, PUVMCPU pUVCpu)
11792{
11793 NOREF(pThis); NOREF(pUVM); NOREF(pUVCpu);
11794 VirtualBoxBase::initializeComForThread();
11795}
11796
11797/**
11798 * @interface_method_impl{VMM2USERMETHODS,pfnNotifyEmtTerm}
11799 */
11800/*static*/ DECLCALLBACK(void)
11801Console::i_vmm2User_NotifyEmtTerm(PCVMM2USERMETHODS pThis, PUVM pUVM, PUVMCPU pUVCpu)
11802{
11803 NOREF(pThis); NOREF(pUVM); NOREF(pUVCpu);
11804 VirtualBoxBase::uninitializeComForThread();
11805}
11806
11807/**
11808 * @interface_method_impl{VMM2USERMETHODS,pfnNotifyPdmtInit}
11809 */
11810/*static*/ DECLCALLBACK(void)
11811Console::i_vmm2User_NotifyPdmtInit(PCVMM2USERMETHODS pThis, PUVM pUVM)
11812{
11813 NOREF(pThis); NOREF(pUVM);
11814 VirtualBoxBase::initializeComForThread();
11815}
11816
11817/**
11818 * @interface_method_impl{VMM2USERMETHODS,pfnNotifyPdmtTerm}
11819 */
11820/*static*/ DECLCALLBACK(void)
11821Console::i_vmm2User_NotifyPdmtTerm(PCVMM2USERMETHODS pThis, PUVM pUVM)
11822{
11823 NOREF(pThis); NOREF(pUVM);
11824 VirtualBoxBase::uninitializeComForThread();
11825}
11826
11827/**
11828 * @interface_method_impl{VMM2USERMETHODS,pfnNotifyResetTurnedIntoPowerOff}
11829 */
11830/*static*/ DECLCALLBACK(void)
11831Console::i_vmm2User_NotifyResetTurnedIntoPowerOff(PCVMM2USERMETHODS pThis, PUVM pUVM)
11832{
11833 Console *pConsole = ((MYVMM2USERMETHODS *)pThis)->pConsole;
11834 NOREF(pUVM);
11835
11836 pConsole->mfPowerOffCausedByReset = true;
11837}
11838
11839/**
11840 * Internal function to get LED set off of Console instance
11841 *
11842 * @returns pointer to PDMLED object
11843 *
11844 * @param iLedSet Index of LED set to fetch
11845 */
11846PPDMLED volatile *
11847Console::i_getLedSet(uint32_t iLedSet)
11848{
11849 AssertReturn(iLedSet < RT_ELEMENTS(maLedSets), NULL);
11850 return maLedSets[iLedSet].papLeds;
11851}
11852
11853/**
11854 * @interface_method_impl{VMM2USERMETHODS,pfnQueryGenericObject}
11855 */
11856/*static*/ DECLCALLBACK(void *)
11857Console::i_vmm2User_QueryGenericObject(PCVMM2USERMETHODS pThis, PUVM pUVM, PCRTUUID pUuid)
11858{
11859 Console *pConsole = ((MYVMM2USERMETHODS *)pThis)->pConsole;
11860 NOREF(pUVM);
11861
11862 /* To simplify comparison we copy the UUID into a com::Guid object. */
11863 com::Guid const UuidCopy(*pUuid);
11864
11865 if (UuidCopy == COM_IIDOF(IConsole))
11866 {
11867 IConsole *pIConsole = static_cast<IConsole *>(pConsole);
11868 return pIConsole;
11869 }
11870
11871 if (UuidCopy == COM_IIDOF(IMachine))
11872 {
11873 IMachine *pIMachine = pConsole->mMachine;
11874 return pIMachine;
11875 }
11876
11877 if (UuidCopy == COM_IIDOF(IKeyboard))
11878 {
11879 IKeyboard *pIKeyboard = pConsole->mKeyboard;
11880 return pIKeyboard;
11881 }
11882
11883 if (UuidCopy == COM_IIDOF(IMouse))
11884 {
11885 IMouse *pIMouse = pConsole->mMouse;
11886 return pIMouse;
11887 }
11888
11889 if (UuidCopy == COM_IIDOF(IDisplay))
11890 {
11891 IDisplay *pIDisplay = pConsole->mDisplay;
11892 return pIDisplay;
11893 }
11894
11895 if (UuidCopy == COM_IIDOF(INvramStore))
11896 {
11897 NvramStore *pNvramStore = static_cast<NvramStore *>(pConsole->mptrNvramStore);
11898 return pNvramStore;
11899 }
11900
11901#ifdef VBOX_WITH_VIRT_ARMV8
11902 if (UuidCopy == COM_IIDOF(IResourceStore))
11903 {
11904 ResourceStore *pResourceStore = static_cast<ResourceStore *>(pConsole->mptrResourceStore);
11905 return pResourceStore;
11906 }
11907#endif
11908
11909 if (UuidCopy == VMMDEV_OID)
11910 return pConsole->m_pVMMDev;
11911
11912 if (UuidCopy == USBCARDREADER_OID)
11913 return pConsole->mUsbCardReader;
11914
11915 if (UuidCopy == COM_IIDOF(ISnapshot))
11916 return ((MYVMM2USERMETHODS *)pThis)->pISnapshot;
11917
11918#ifdef VBOX_WITH_USB
11919 if (UuidCopy == REMOTEUSBIF_OID)
11920 return &pConsole->mRemoteUsbIf;
11921#endif
11922
11923 if (UuidCopy == EMULATEDUSBIF_OID)
11924 return pConsole->mEmulatedUSB->i_getEmulatedUsbIf();
11925
11926 return NULL;
11927}
11928
11929
11930/**
11931 * @interface_method_impl{PDMISECKEY,pfnKeyRetain}
11932 */
11933/*static*/ DECLCALLBACK(int)
11934Console::i_pdmIfSecKey_KeyRetain(PPDMISECKEY pInterface, const char *pszId, const uint8_t **ppbKey, size_t *pcbKey)
11935{
11936 Console *pConsole = ((MYPDMISECKEY *)pInterface)->pConsole;
11937
11938 AutoReadLock thatLock(pConsole COMMA_LOCKVAL_SRC_POS);
11939 SecretKey *pKey = NULL;
11940
11941 int vrc = pConsole->m_pKeyStore->retainSecretKey(Utf8Str(pszId), &pKey);
11942 if (RT_SUCCESS(vrc))
11943 {
11944 *ppbKey = (const uint8_t *)pKey->getKeyBuffer();
11945 *pcbKey = pKey->getKeySize();
11946 }
11947
11948 return vrc;
11949}
11950
11951/**
11952 * @interface_method_impl{PDMISECKEY,pfnKeyRelease}
11953 */
11954/*static*/ DECLCALLBACK(int)
11955Console::i_pdmIfSecKey_KeyRelease(PPDMISECKEY pInterface, const char *pszId)
11956{
11957 Console *pConsole = ((MYPDMISECKEY *)pInterface)->pConsole;
11958
11959 AutoReadLock thatLock(pConsole COMMA_LOCKVAL_SRC_POS);
11960 return pConsole->m_pKeyStore->releaseSecretKey(Utf8Str(pszId));
11961}
11962
11963/**
11964 * @interface_method_impl{PDMISECKEY,pfnPasswordRetain}
11965 */
11966/*static*/ DECLCALLBACK(int)
11967Console::i_pdmIfSecKey_PasswordRetain(PPDMISECKEY pInterface, const char *pszId, const char **ppszPassword)
11968{
11969 Console *pConsole = ((MYPDMISECKEY *)pInterface)->pConsole;
11970
11971 AutoReadLock thatLock(pConsole COMMA_LOCKVAL_SRC_POS);
11972 SecretKey *pKey = NULL;
11973
11974 int vrc = pConsole->m_pKeyStore->retainSecretKey(Utf8Str(pszId), &pKey);
11975 if (RT_SUCCESS(vrc))
11976 *ppszPassword = (const char *)pKey->getKeyBuffer();
11977
11978 return vrc;
11979}
11980
11981/**
11982 * @interface_method_impl{PDMISECKEY,pfnPasswordRelease}
11983 */
11984/*static*/ DECLCALLBACK(int)
11985Console::i_pdmIfSecKey_PasswordRelease(PPDMISECKEY pInterface, const char *pszId)
11986{
11987 Console *pConsole = ((MYPDMISECKEY *)pInterface)->pConsole;
11988
11989 AutoReadLock thatLock(pConsole COMMA_LOCKVAL_SRC_POS);
11990 return pConsole->m_pKeyStore->releaseSecretKey(Utf8Str(pszId));
11991}
11992
11993/**
11994 * @interface_method_impl{PDMISECKEYHLP,pfnKeyMissingNotify}
11995 */
11996/*static*/ DECLCALLBACK(int)
11997Console::i_pdmIfSecKeyHlp_KeyMissingNotify(PPDMISECKEYHLP pInterface)
11998{
11999 Console *pConsole = ((MYPDMISECKEYHLP *)pInterface)->pConsole;
12000
12001 /* Set guest property only, the VM is paused in the media driver calling us. */
12002 pConsole->mMachine->DeleteGuestProperty(Bstr("/VirtualBox/HostInfo/DekMissing").raw());
12003 pConsole->mMachine->SetGuestProperty(Bstr("/VirtualBox/HostInfo/DekMissing").raw(),
12004 Bstr("1").raw(), Bstr("RDONLYGUEST").raw());
12005 pConsole->mMachine->SaveSettings();
12006
12007 return VINF_SUCCESS;
12008}
12009
12010
12011
12012/**
12013 * The Main status driver instance data.
12014 */
12015typedef struct DRVMAINSTATUS
12016{
12017 /** The LED connectors. */
12018 PDMILEDCONNECTORS ILedConnectors;
12019 /** Pointer to the LED ports interface above us. */
12020 PPDMILEDPORTS pLedPorts;
12021 /** Pointer to the array of LED pointers. */
12022 PPDMLED volatile *papLeds;
12023 /** The unit number corresponding to the first entry in the LED array. */
12024 uint32_t iFirstLUN;
12025 /** The unit number corresponding to the last entry in the LED array.
12026 * (The size of the LED array is iLastLUN - iFirstLUN + 1.) */
12027 uint32_t iLastLUN;
12028 /** Pointer to the driver instance. */
12029 PPDMDRVINS pDrvIns;
12030 /** The Media Notify interface. */
12031 PDMIMEDIANOTIFY IMediaNotify;
12032 /** Set if there potentially are medium attachments. */
12033 bool fHasMediumAttachments;
12034 /** Device name+instance for mapping */
12035 char *pszDeviceInstance;
12036 /** Pointer to the Console object, for driver triggered activities. */
12037 Console *pConsole;
12038} DRVMAINSTATUS;
12039/** Pointer the instance data for a Main status driver. */
12040typedef DRVMAINSTATUS *PDRVMAINSTATUS;
12041
12042
12043/**
12044 * Notification about a unit which have been changed.
12045 *
12046 * The driver must discard any pointers to data owned by
12047 * the unit and requery it.
12048 *
12049 * @param pInterface Pointer to the interface structure containing the called function pointer.
12050 * @param iLUN The unit number.
12051 */
12052DECLCALLBACK(void) Console::i_drvStatus_UnitChanged(PPDMILEDCONNECTORS pInterface, unsigned iLUN)
12053{
12054 PDRVMAINSTATUS pThis = RT_FROM_MEMBER(pInterface, DRVMAINSTATUS, ILedConnectors);
12055 if (iLUN >= pThis->iFirstLUN && iLUN <= pThis->iLastLUN)
12056 {
12057 /*
12058 * Query the pointer to the PDMLED field inside the target device
12059 * structure (owned by the virtual hardware device).
12060 */
12061 PPDMLED pLed;
12062 int vrc = pThis->pLedPorts->pfnQueryStatusLed(pThis->pLedPorts, iLUN, &pLed);
12063 if (RT_FAILURE(vrc))
12064 pLed = NULL;
12065
12066 /*
12067 * Update the corresponding papLeds[] entry.
12068 *
12069 * papLeds[] points to the struct PDMLED of each of this driver's
12070 * units. The entries are initialized here, called out of a loop
12071 * in Console::i_drvStatus_Construct(), which previously called
12072 * Console::i_attachStatusDriver() to allocate the array itself.
12073 *
12074 * The arrays (and thus individual LEDs) are eventually read out
12075 * by Console::getDeviceActivity(), which is itself called from
12076 * src/VBox/Frontends/VirtualBox/src/runtime/UIIndicatorsPool.cpp
12077 */
12078 /** @todo acquire Console::mLedLock here in exclusive mode? */
12079 ASMAtomicWritePtr(&pThis->papLeds[iLUN - pThis->iFirstLUN], pLed);
12080 Log(("drvStatus_UnitChanged: iLUN=%d pLed=%p\n", iLUN, pLed));
12081 }
12082}
12083
12084
12085/**
12086 * Notification about a medium eject.
12087 *
12088 * @returns VBox status code.
12089 * @param pInterface Pointer to the interface structure containing the called function pointer.
12090 * @param uLUN The unit number.
12091 */
12092DECLCALLBACK(int) Console::i_drvStatus_MediumEjected(PPDMIMEDIANOTIFY pInterface, unsigned uLUN)
12093{
12094 PDRVMAINSTATUS pThis = RT_FROM_MEMBER(pInterface, DRVMAINSTATUS, IMediaNotify);
12095 LogFunc(("uLUN=%d\n", uLUN));
12096 if (pThis->fHasMediumAttachments)
12097 {
12098 Console * const pConsole = pThis->pConsole;
12099 AutoWriteLock alock(pConsole COMMA_LOCKVAL_SRC_POS);
12100
12101 ComPtr<IMediumAttachment> pMediumAtt;
12102 Utf8Str devicePath = Utf8StrFmt("%s/LUN#%u", pThis->pszDeviceInstance, uLUN);
12103 Console::MediumAttachmentMap::const_iterator end = pConsole->mapMediumAttachments.end();
12104 Console::MediumAttachmentMap::const_iterator it = pConsole->mapMediumAttachments.find(devicePath);
12105 if (it != end)
12106 pMediumAtt = it->second;
12107 Assert(!pMediumAtt.isNull());
12108 if (!pMediumAtt.isNull())
12109 {
12110 IMedium *pMedium = NULL;
12111 HRESULT hrc = pMediumAtt->COMGETTER(Medium)(&pMedium);
12112 AssertComRC(hrc);
12113 if (SUCCEEDED(hrc) && pMedium)
12114 {
12115 BOOL fHostDrive = FALSE;
12116 hrc = pMedium->COMGETTER(HostDrive)(&fHostDrive);
12117 AssertComRC(hrc);
12118 if (!fHostDrive)
12119 {
12120 alock.release();
12121
12122 ComPtr<IMediumAttachment> pNewMediumAtt;
12123 hrc = pThis->pConsole->mControl->EjectMedium(pMediumAtt, pNewMediumAtt.asOutParam());
12124 if (SUCCEEDED(hrc))
12125 {
12126 pThis->pConsole->mMachine->SaveSettings();
12127 ::FireMediumChangedEvent(pThis->pConsole->mEventSource, pNewMediumAtt);
12128 }
12129
12130 alock.acquire();
12131 if (pNewMediumAtt != pMediumAtt)
12132 {
12133 pConsole->mapMediumAttachments.erase(devicePath);
12134 pConsole->mapMediumAttachments.insert(std::make_pair(devicePath, pNewMediumAtt));
12135 }
12136 }
12137 }
12138 }
12139 }
12140 return VINF_SUCCESS;
12141}
12142
12143
12144/**
12145 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
12146 */
12147DECLCALLBACK(void *) Console::i_drvStatus_QueryInterface(PPDMIBASE pInterface, const char *pszIID)
12148{
12149 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
12150 PDRVMAINSTATUS pThis = PDMINS_2_DATA(pDrvIns, PDRVMAINSTATUS);
12151 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
12152 PDMIBASE_RETURN_INTERFACE(pszIID, PDMILEDCONNECTORS, &pThis->ILedConnectors);
12153 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIANOTIFY, &pThis->IMediaNotify);
12154 return NULL;
12155}
12156
12157
12158/**
12159 * Destruct a status driver instance.
12160 *
12161 * @param pDrvIns The driver instance data.
12162 */
12163DECLCALLBACK(void) Console::i_drvStatus_Destruct(PPDMDRVINS pDrvIns)
12164{
12165 PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
12166 PDRVMAINSTATUS pThis = PDMINS_2_DATA(pDrvIns, PDRVMAINSTATUS);
12167 LogFlowFunc(("iInstance=%d\n", pDrvIns->iInstance));
12168
12169 if (pThis->papLeds)
12170 {
12171 unsigned iLed = pThis->iLastLUN - pThis->iFirstLUN + 1;
12172 while (iLed-- > 0)
12173 ASMAtomicWriteNullPtr(&pThis->papLeds[iLed]);
12174 }
12175}
12176
12177
12178/**
12179 * Construct a status driver instance.
12180 *
12181 * @copydoc FNPDMDRVCONSTRUCT
12182 */
12183DECLCALLBACK(int) Console::i_drvStatus_Construct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
12184{
12185 RT_NOREF(fFlags);
12186 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
12187 PDRVMAINSTATUS pThis = PDMINS_2_DATA(pDrvIns, PDRVMAINSTATUS);
12188 LogFlowFunc(("iInstance=%d\n", pDrvIns->iInstance));
12189
12190 /*
12191 * Initialize data.
12192 */
12193 com::Guid ConsoleUuid(COM_IIDOF(IConsole));
12194 IConsole *pIConsole = (IConsole *)PDMDrvHlpQueryGenericUserObject(pDrvIns, ConsoleUuid.raw());
12195 AssertLogRelReturn(pIConsole, VERR_INTERNAL_ERROR_3);
12196 Console *pConsole = static_cast<Console *>(pIConsole);
12197 AssertLogRelReturn(pConsole, VERR_INTERNAL_ERROR_3);
12198
12199 pDrvIns->IBase.pfnQueryInterface = Console::i_drvStatus_QueryInterface;
12200 pThis->ILedConnectors.pfnUnitChanged = Console::i_drvStatus_UnitChanged;
12201 pThis->IMediaNotify.pfnEjected = Console::i_drvStatus_MediumEjected;
12202 pThis->pDrvIns = pDrvIns;
12203 pThis->pConsole = pConsole;
12204 pThis->fHasMediumAttachments = false;
12205 pThis->papLeds = NULL;
12206 pThis->pszDeviceInstance = NULL;
12207
12208 /*
12209 * Validate configuration.
12210 */
12211 PDMDRV_VALIDATE_CONFIG_RETURN(pDrvIns,
12212 "DeviceInstance|"
12213 "iLedSet|"
12214 "HasMediumAttachments|"
12215 "First|"
12216 "Last",
12217 "");
12218 AssertMsgReturn(PDMDrvHlpNoAttach(pDrvIns) == VERR_PDM_NO_ATTACHED_DRIVER,
12219 ("Configuration error: Not possible to attach anything to this driver!\n"),
12220 VERR_PDM_DRVINS_NO_ATTACH);
12221
12222 /*
12223 * Read config.
12224 */
12225 PCPDMDRVHLPR3 const pHlp = pDrvIns->pHlpR3;
12226
12227 uint32_t iLedSet;
12228 int vrc = pHlp->pfnCFGMQueryU32(pCfg, "iLedSet", &iLedSet);
12229 AssertLogRelMsgRCReturn(vrc, ("Configuration error: Failed to query the \"iLedSet\" value! vrc=%Rrc\n", vrc), vrc);
12230 pThis->papLeds = pConsole->i_getLedSet(iLedSet);
12231
12232 vrc = pHlp->pfnCFGMQueryBoolDef(pCfg, "HasMediumAttachments", &pThis->fHasMediumAttachments, false);
12233 AssertLogRelMsgRCReturn(vrc, ("Configuration error: Failed to query the \"HasMediumAttachments\" value! vrc=%Rrc\n", vrc), vrc);
12234
12235 if (pThis->fHasMediumAttachments)
12236 {
12237 vrc = pHlp->pfnCFGMQueryStringAlloc(pCfg, "DeviceInstance", &pThis->pszDeviceInstance);
12238 AssertLogRelMsgRCReturn(vrc, ("Configuration error: Failed to query the \"DeviceInstance\" value! vrc=%Rrc\n", vrc), vrc);
12239 }
12240
12241 vrc = pHlp->pfnCFGMQueryU32Def(pCfg, "First", &pThis->iFirstLUN, 0);
12242 AssertLogRelMsgRCReturn(vrc, ("Configuration error: Failed to query the \"First\" value! vrc=%Rrc\n", vrc), vrc);
12243
12244 vrc = pHlp->pfnCFGMQueryU32Def(pCfg, "Last", &pThis->iLastLUN, 0);
12245 AssertLogRelMsgRCReturn(vrc, ("Configuration error: Failed to query the \"Last\" value! vrc=%Rrc\n", vrc), vrc);
12246
12247 AssertLogRelMsgReturn(pThis->iFirstLUN <= pThis->iLastLUN,
12248 ("Configuration error: Invalid unit range %u-%u\n", pThis->iFirstLUN, pThis->iLastLUN),
12249 VERR_INVALID_PARAMETER);
12250
12251 /*
12252 * Get the ILedPorts interface of the above driver/device and
12253 * query the LEDs we want.
12254 */
12255 pThis->pLedPorts = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMILEDPORTS);
12256 AssertMsgReturn(pThis->pLedPorts, ("Configuration error: No led ports interface above!\n"),
12257 VERR_PDM_MISSING_INTERFACE_ABOVE);
12258
12259 for (unsigned i = pThis->iFirstLUN; i <= pThis->iLastLUN; ++i)
12260 Console::i_drvStatus_UnitChanged(&pThis->ILedConnectors, i);
12261
12262 return VINF_SUCCESS;
12263}
12264
12265
12266/**
12267 * Console status driver (LED) registration record.
12268 */
12269const PDMDRVREG Console::DrvStatusReg =
12270{
12271 /* u32Version */
12272 PDM_DRVREG_VERSION,
12273 /* szName */
12274 "MainStatus",
12275 /* szRCMod */
12276 "",
12277 /* szR0Mod */
12278 "",
12279 /* pszDescription */
12280 "Main status driver (Main as in the API).",
12281 /* fFlags */
12282 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
12283 /* fClass. */
12284 PDM_DRVREG_CLASS_STATUS,
12285 /* cMaxInstances */
12286 ~0U,
12287 /* cbInstance */
12288 sizeof(DRVMAINSTATUS),
12289 /* pfnConstruct */
12290 Console::i_drvStatus_Construct,
12291 /* pfnDestruct */
12292 Console::i_drvStatus_Destruct,
12293 /* pfnRelocate */
12294 NULL,
12295 /* pfnIOCtl */
12296 NULL,
12297 /* pfnPowerOn */
12298 NULL,
12299 /* pfnReset */
12300 NULL,
12301 /* pfnSuspend */
12302 NULL,
12303 /* pfnResume */
12304 NULL,
12305 /* pfnAttach */
12306 NULL,
12307 /* pfnDetach */
12308 NULL,
12309 /* pfnPowerOff */
12310 NULL,
12311 /* pfnSoftReset */
12312 NULL,
12313 /* u32EndVersion */
12314 PDM_DRVREG_VERSION
12315};
12316
12317
12318
12319/* vi: set tabstop=4 shiftwidth=4 expandtab: */
Note: See TracBrowser for help on using the repository browser.

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