VirtualBox

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

Last change on this file since 105010 was 105006, checked in by vboxsync, 5 months ago

Video Recording: Big revamp to improve overall performance. We now don't rely on the periodic display refresh callback anymore to render the entire framebuffer but now rely on delta updates ("dirty rectangles"). Also, we now only encode new frames when an area has changed. This also needed cursor position + change change notifications, as we render the cursor on the host side if mouse integration is enabled (requires 7.1 Guest Additions as of now). Optimized the BGRA32->YUV IV420 color space conversion as well as the overall amount of pixel data shuffled forth and back. Added a new testcase for the cropping/centering code. bugref:10650

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

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