VirtualBox

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

Last change on this file since 100347 was 100038, checked in by vboxsync, 2 years ago

Main: Start simple ResourceStore implementation similar to NvramStore but without all the file loading and saving as it will contain only resources created on the fly when the VM is created, bugref:10467

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

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