VirtualBox

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

Last change on this file since 100561 was 100521, checked in by vboxsync, 23 months ago

Main: separate function for parsing the entries in remote USB device list. bugref:10478

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 409.7 KB
Line 
1/* $Id: ConsoleImpl.cpp 100521 2023-07-11 16:47:42Z 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/* Make sure that the string is null-terminated and its size is less than cchMax bytes.
10768 * Replace invalid UTF8 bytes with '?'.
10769 */
10770static int validateUtf8String(char *psz, size_t cchMax)
10771{
10772 for (;;)
10773 {
10774 RTUNICP Cp;
10775 int vrc = RTStrGetCpNEx((const char **)&psz, &cchMax, &Cp);
10776 if (RT_SUCCESS(vrc))
10777 {
10778 if (!Cp)
10779 break;
10780 }
10781 else
10782 {
10783 if (!cchMax)
10784 return VERR_END_OF_STRING;
10785
10786 psz[-1] = '?';
10787 }
10788 }
10789 return VINF_SUCCESS;
10790}
10791
10792static int validateRemoteUSBDeviceDesc(VRDEUSBDEVICEDESC const *e, uint32_t cbRemaining, bool fDescExt)
10793{
10794 uint32_t const cbDesc = fDescExt ? sizeof(VRDEUSBDEVICEDESCEXT) : sizeof(VRDEUSBDEVICEDESC);
10795 if (cbDesc > cbRemaining)
10796 return VERR_INVALID_PARAMETER;
10797
10798 if ( e->oNext > cbRemaining /* It is OK for oNext to point to the end of buffer. */
10799 || e->oManufacturer >= cbRemaining
10800 || e->oProduct >= cbRemaining
10801 || e->oSerialNumber >= cbRemaining)
10802 return VERR_INVALID_PARAMETER;
10803
10804 int vrc;
10805 if (e->oManufacturer)
10806 {
10807 vrc = validateUtf8String((char *)e + e->oManufacturer, cbRemaining - e->oManufacturer);
10808 if (RT_FAILURE(vrc))
10809 return VERR_INVALID_PARAMETER;
10810 }
10811 if (e->oProduct)
10812 {
10813 vrc = validateUtf8String((char *)e + e->oProduct, cbRemaining - e->oProduct);
10814 if (RT_FAILURE(vrc))
10815 return VERR_INVALID_PARAMETER;
10816 }
10817 if (e->oSerialNumber)
10818 {
10819 vrc = validateUtf8String((char *)e + e->oSerialNumber, cbRemaining - e->oSerialNumber);
10820 if (RT_FAILURE(vrc))
10821 return VERR_INVALID_PARAMETER;
10822 }
10823
10824 return VINF_SUCCESS;
10825}
10826
10827/**
10828 * @note Locks this object for writing.
10829 */
10830void Console::i_processRemoteUSBDevices(uint32_t u32ClientId, VRDEUSBDEVICEDESC *pDevList, uint32_t cbDevList, bool fDescExt)
10831{
10832 LogFlowThisFuncEnter();
10833 LogFlowThisFunc(("u32ClientId = %d, pDevList=%p, cbDevList = %d, fDescExt = %d\n",
10834 u32ClientId, pDevList, cbDevList, fDescExt));
10835
10836 AutoCaller autoCaller(this);
10837 if (!autoCaller.isOk())
10838 {
10839 /* Console has been already uninitialized, deny request */
10840 AssertMsgFailed(("Console is already uninitialized\n"));
10841 LogFlowThisFunc(("Console is already uninitialized\n"));
10842 LogFlowThisFuncLeave();
10843 return;
10844 }
10845
10846 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
10847
10848 /*
10849 * Mark all existing remote USB devices as dirty.
10850 */
10851 for (RemoteUSBDeviceList::iterator it = mRemoteUSBDevices.begin();
10852 it != mRemoteUSBDevices.end();
10853 ++it)
10854 {
10855 (*it)->dirty(true);
10856 }
10857
10858 /*
10859 * Process the pDevList and add devices those are not already in the mRemoteUSBDevices list.
10860 */
10861 VRDEUSBDEVICEDESC *e = pDevList;
10862 uint32_t cbRemaining = cbDevList;
10863
10864 /* The cbRemaining condition must be checked first, because the function can
10865 * receive pDevList = NULL and cbDevList = 0 on client disconnect.
10866 */
10867 while (cbRemaining >= sizeof(e->oNext) && e->oNext)
10868 {
10869 int const vrc = validateRemoteUSBDeviceDesc(e, cbRemaining, fDescExt);
10870 if (RT_FAILURE(vrc))
10871 break; /* Consider the rest of the list invalid too. */
10872
10873 LogFlowThisFunc(("vendor %04x, product %04x, name = %s\n",
10874 e->idVendor, e->idProduct, e->oProduct ? (char *)e + e->oProduct : ""));
10875
10876 bool fNewDevice = true;
10877
10878 for (RemoteUSBDeviceList::iterator it = mRemoteUSBDevices.begin();
10879 it != mRemoteUSBDevices.end();
10880 ++it)
10881 {
10882 if ( (*it)->devId() == e->id
10883 && (*it)->clientId() == u32ClientId)
10884 {
10885 /* The device is already in the list. */
10886 (*it)->dirty(false);
10887 fNewDevice = false;
10888 break;
10889 }
10890 }
10891
10892 if (fNewDevice)
10893 {
10894 LogRel(("Remote USB: ++++ Vendor %04X. Product %04X. Name = [%s].\n",
10895 e->idVendor, e->idProduct, e->oProduct? (char *)e + e->oProduct: ""));
10896
10897 /* Create the device object and add the new device to list. */
10898 ComObjPtr<RemoteUSBDevice> pUSBDevice;
10899 pUSBDevice.createObject();
10900 pUSBDevice->init(u32ClientId, e, fDescExt);
10901
10902 mRemoteUSBDevices.push_back(pUSBDevice);
10903
10904 /* Check if the device is ok for current USB filters. */
10905 BOOL fMatched = FALSE;
10906 ULONG fMaskedIfs = 0;
10907 HRESULT hrc = mControl->RunUSBDeviceFilters(pUSBDevice, &fMatched, &fMaskedIfs);
10908
10909 AssertComRC(hrc);
10910
10911 LogFlowThisFunc(("USB filters return %d %#x\n", fMatched, fMaskedIfs));
10912
10913 if (fMatched)
10914 {
10915 alock.release();
10916 hrc = i_onUSBDeviceAttach(pUSBDevice, NULL, fMaskedIfs, Utf8Str());
10917 alock.acquire();
10918
10919 /// @todo (r=dmik) warning reporting subsystem
10920
10921 if (hrc == S_OK)
10922 {
10923 LogFlowThisFunc(("Device attached\n"));
10924 pUSBDevice->captured(true);
10925 }
10926 }
10927 }
10928
10929 AssertBreak(cbRemaining >= e->oNext); /* validateRemoteUSBDeviceDesc ensures this. */
10930 cbRemaining -= e->oNext;
10931
10932 e = (VRDEUSBDEVICEDESC *)((uint8_t *)e + e->oNext);
10933 }
10934
10935 /*
10936 * Remove dirty devices, that is those which are not reported by the server anymore.
10937 */
10938 for (;;)
10939 {
10940 ComObjPtr<RemoteUSBDevice> pUSBDevice;
10941
10942 RemoteUSBDeviceList::iterator it = mRemoteUSBDevices.begin();
10943 while (it != mRemoteUSBDevices.end())
10944 {
10945 if ((*it)->dirty())
10946 {
10947 pUSBDevice = *it;
10948 break;
10949 }
10950
10951 ++it;
10952 }
10953
10954 if (!pUSBDevice)
10955 {
10956 break;
10957 }
10958
10959 USHORT vendorId = 0;
10960 pUSBDevice->COMGETTER(VendorId)(&vendorId);
10961
10962 USHORT productId = 0;
10963 pUSBDevice->COMGETTER(ProductId)(&productId);
10964
10965 Bstr product;
10966 pUSBDevice->COMGETTER(Product)(product.asOutParam());
10967
10968 LogRel(("Remote USB: ---- Vendor %04x. Product %04x. Name = [%ls].\n", vendorId, productId, product.raw()));
10969
10970 /* Detach the device from VM. */
10971 if (pUSBDevice->captured())
10972 {
10973 Bstr uuid;
10974 pUSBDevice->COMGETTER(Id)(uuid.asOutParam());
10975 alock.release();
10976 i_onUSBDeviceDetach(uuid.raw(), NULL);
10977 alock.acquire();
10978 }
10979
10980 /* And remove it from the list. */
10981 mRemoteUSBDevices.erase(it);
10982 }
10983
10984 LogFlowThisFuncLeave();
10985}
10986
10987
10988/**
10989 * Worker called by VMPowerUpTask::handler to start the VM (also from saved
10990 * state) and track progress.
10991 *
10992 * @param pTask The power up task.
10993 *
10994 * @note Locks the Console object for writing.
10995 */
10996/*static*/
10997void Console::i_powerUpThreadTask(VMPowerUpTask *pTask)
10998{
10999 LogFlowFuncEnter();
11000
11001 AssertReturnVoid(pTask);
11002 AssertReturnVoid(!pTask->mConsole.isNull());
11003 AssertReturnVoid(!pTask->mProgress.isNull());
11004
11005 VirtualBoxBase::initializeComForThread();
11006
11007 HRESULT hrc = S_OK;
11008 int vrc = VINF_SUCCESS;
11009
11010 /* Set up a build identifier so that it can be seen from core dumps what
11011 * exact build was used to produce the core. */
11012 static char s_szBuildID[48];
11013 RTStrPrintf(s_szBuildID, sizeof(s_szBuildID), "%s%s%s%s VirtualBox %s r%u %s%s%s%s",
11014 "BU", "IL", "DI", "D", RTBldCfgVersion(), RTBldCfgRevision(), "BU", "IL", "DI", "D");
11015
11016 ComObjPtr<Console> pConsole = pTask->mConsole;
11017
11018 /* Note: no need to use AutoCaller because VMPowerUpTask does that */
11019
11020 /* The lock is also used as a signal from the task initiator (which
11021 * releases it only after RTThreadCreate()) that we can start the job */
11022 AutoWriteLock alock(pConsole COMMA_LOCKVAL_SRC_POS);
11023
11024 /* sanity */
11025 Assert(pConsole->mpUVM == NULL);
11026
11027 try
11028 {
11029 // Create the VMM device object, which starts the HGCM thread; do this only
11030 // once for the console, for the pathological case that the same console
11031 // object is used to power up a VM twice.
11032 if (!pConsole->m_pVMMDev)
11033 {
11034 pConsole->m_pVMMDev = new VMMDev(pConsole);
11035 AssertReturnVoid(pConsole->m_pVMMDev);
11036 }
11037
11038 /* wait for auto reset ops to complete so that we can successfully lock
11039 * the attached hard disks by calling LockMedia() below */
11040 for (VMPowerUpTask::ProgressList::const_iterator
11041 it = pTask->hardDiskProgresses.begin();
11042 it != pTask->hardDiskProgresses.end(); ++it)
11043 {
11044 HRESULT hrc2 = (*it)->WaitForCompletion(-1);
11045 AssertComRC(hrc2);
11046
11047 hrc = pTask->mProgress->SetNextOperation(BstrFmt(tr("Disk Image Reset Operation - Immutable Image")).raw(), 1);
11048 AssertComRCReturnVoid(hrc);
11049 }
11050
11051 /*
11052 * Lock attached media. This method will also check their accessibility.
11053 * If we're a teleporter, we'll have to postpone this action so we can
11054 * migrate between local processes.
11055 *
11056 * Note! The media will be unlocked automatically by
11057 * SessionMachine::i_setMachineState() when the VM is powered down.
11058 */
11059 if (!pTask->mTeleporterEnabled)
11060 {
11061 hrc = pConsole->mControl->LockMedia();
11062 if (FAILED(hrc)) throw hrc;
11063 }
11064
11065 /* Create the VRDP server. In case of headless operation, this will
11066 * also create the framebuffer, required at VM creation.
11067 */
11068 ConsoleVRDPServer *server = pConsole->i_consoleVRDPServer();
11069 Assert(server);
11070
11071 /* Does VRDP server call Console from the other thread?
11072 * Not sure (and can change), so release the lock just in case.
11073 */
11074 alock.release();
11075 vrc = server->Launch();
11076 alock.acquire();
11077
11078 if (vrc != VINF_SUCCESS)
11079 {
11080 Utf8Str errMsg = pConsole->VRDPServerErrorToMsg(vrc);
11081 if ( RT_FAILURE(vrc)
11082 && vrc != VERR_NET_ADDRESS_IN_USE) /* not fatal */
11083 throw i_setErrorStaticBoth(E_FAIL, vrc, errMsg.c_str());
11084 }
11085
11086 ComPtr<IMachine> pMachine = pConsole->i_machine();
11087 ULONG cCpus = 1;
11088 pMachine->COMGETTER(CPUCount)(&cCpus);
11089
11090 VMProcPriority_T enmVMPriority = VMProcPriority_Default;
11091 pMachine->COMGETTER(VMProcessPriority)(&enmVMPriority);
11092
11093 /*
11094 * Create the VM
11095 *
11096 * Note! Release the lock since EMT will call Console. It's safe because
11097 * mMachineState is either Starting or Restoring state here.
11098 */
11099 alock.release();
11100
11101 if (enmVMPriority != VMProcPriority_Default)
11102 pConsole->i_onVMProcessPriorityChange(enmVMPriority);
11103
11104 PCVMMR3VTABLE pVMM = pConsole->mpVMM;
11105 PVM pVM = NULL;
11106 vrc = pVMM->pfnVMR3Create(cCpus,
11107 pConsole->mpVmm2UserMethods,
11108 0 /*fFlags*/,
11109 Console::i_genericVMSetErrorCallback,
11110 &pTask->mErrorMsg,
11111 pTask->mpfnConfigConstructor,
11112 static_cast<Console *>(pConsole),
11113 &pVM, NULL);
11114 alock.acquire();
11115 if (RT_SUCCESS(vrc))
11116 {
11117 do /* break "loop" */
11118 {
11119 /*
11120 * Register our load/save state file handlers
11121 */
11122 vrc = pVMM->pfnSSMR3RegisterExternal(pConsole->mpUVM, sSSMConsoleUnit, 0 /*iInstance*/,
11123 CONSOLE_SAVED_STATE_VERSION, 0 /* cbGuess */,
11124 NULL, NULL, NULL,
11125 NULL, i_saveStateFileExec, NULL,
11126 NULL, i_loadStateFileExec, NULL,
11127 static_cast<Console *>(pConsole));
11128 AssertRCBreak(vrc);
11129
11130 vrc = static_cast<Console *>(pConsole)->i_getDisplay()->i_registerSSM(pConsole->mpUVM);
11131 AssertRC(vrc);
11132 if (RT_FAILURE(vrc))
11133 break;
11134
11135 /*
11136 * Synchronize debugger settings
11137 */
11138 MachineDebugger *machineDebugger = pConsole->i_getMachineDebugger();
11139 if (machineDebugger)
11140 machineDebugger->i_flushQueuedSettings();
11141
11142 /*
11143 * Shared Folders
11144 */
11145 if (pConsole->m_pVMMDev->isShFlActive())
11146 {
11147 /* Does the code below call Console from the other thread?
11148 * Not sure, so release the lock just in case. */
11149 alock.release();
11150
11151 for (SharedFolderDataMap::const_iterator it = pTask->mSharedFolders.begin();
11152 it != pTask->mSharedFolders.end();
11153 ++it)
11154 {
11155 const SharedFolderData &d = it->second;
11156 hrc = pConsole->i_createSharedFolder(it->first, d);
11157 if (FAILED(hrc))
11158 {
11159 ErrorInfoKeeper eik;
11160 pConsole->i_atVMRuntimeErrorCallbackF(0, "BrokenSharedFolder",
11161 N_("The shared folder '%s' could not be set up: %ls.\n"
11162 "The shared folder setup will not be complete. It is recommended to power down the virtual "
11163 "machine and fix the shared folder settings while the machine is not running"),
11164 it->first.c_str(), eik.getText().raw());
11165 }
11166 }
11167 if (FAILED(hrc))
11168 hrc = S_OK; // do not fail with broken shared folders
11169
11170 /* acquire the lock again */
11171 alock.acquire();
11172 }
11173
11174#ifdef VBOX_WITH_AUDIO_VRDE
11175 /*
11176 * Attach the VRDE audio driver.
11177 */
11178 if (pConsole->i_getVRDEServer())
11179 {
11180 BOOL fVRDEEnabled = FALSE;
11181 hrc = pConsole->i_getVRDEServer()->COMGETTER(Enabled)(&fVRDEEnabled);
11182 AssertComRCBreak(hrc, RT_NOTHING);
11183
11184 if ( fVRDEEnabled
11185 && pConsole->mAudioVRDE)
11186 pConsole->mAudioVRDE->doAttachDriverViaEmt(pConsole->mpUVM, pVMM, &alock);
11187 }
11188#endif
11189
11190 /*
11191 * Enable client connections to the VRDP server.
11192 */
11193 pConsole->i_consoleVRDPServer()->EnableConnections();
11194
11195#ifdef VBOX_WITH_RECORDING
11196 /*
11197 * Enable recording if configured.
11198 */
11199 BOOL fRecordingEnabled = FALSE;
11200 {
11201 ComPtr<IRecordingSettings> ptrRecordingSettings;
11202 hrc = pConsole->mMachine->COMGETTER(RecordingSettings)(ptrRecordingSettings.asOutParam());
11203 AssertComRCBreak(hrc, RT_NOTHING);
11204
11205 hrc = ptrRecordingSettings->COMGETTER(Enabled)(&fRecordingEnabled);
11206 AssertComRCBreak(hrc, RT_NOTHING);
11207 }
11208 if (fRecordingEnabled)
11209 {
11210 vrc = pConsole->i_recordingEnable(fRecordingEnabled, &alock);
11211 if (RT_SUCCESS(vrc))
11212 ::FireRecordingChangedEvent(pConsole->mEventSource);
11213 else
11214 {
11215 LogRel(("Recording: Failed with %Rrc on VM power up\n", vrc));
11216 vrc = VINF_SUCCESS; /* do not fail with broken recording */
11217 }
11218 }
11219#endif
11220
11221 /* release the lock before a lengthy operation */
11222 alock.release();
11223
11224 /*
11225 * Capture USB devices.
11226 */
11227 hrc = pConsole->i_captureUSBDevices(pConsole->mpUVM);
11228 if (FAILED(hrc))
11229 {
11230 alock.acquire();
11231 break;
11232 }
11233
11234 /*
11235 * Load saved state?
11236 */
11237 if (pTask->mSavedStateFile.length())
11238 {
11239 LogFlowFunc(("Restoring saved state from '%s'...\n", pTask->mSavedStateFile.c_str()));
11240
11241#ifdef VBOX_WITH_FULL_VM_ENCRYPTION
11242 SsmStream ssmStream(pConsole, pVMM, pTask->m_pKeyStore, pTask->mKeyId, pTask->mKeyStore);
11243
11244 vrc = ssmStream.open(pTask->mSavedStateFile.c_str());
11245 if (RT_SUCCESS(vrc))
11246 {
11247 PCSSMSTRMOPS pStreamOps;
11248 void *pvStreamOpsUser;
11249
11250 vrc = ssmStream.querySsmStrmOps(&pStreamOps, &pvStreamOpsUser);
11251 if (RT_SUCCESS(vrc))
11252 vrc = pVMM->pfnVMR3LoadFromStream(pConsole->mpUVM,
11253 pStreamOps, pvStreamOpsUser,
11254 Console::i_stateProgressCallback,
11255 static_cast<IProgress *>(pTask->mProgress),
11256 false /*fTeleporting*/);
11257 }
11258#else
11259 vrc = pVMM->pfnVMR3LoadFromFile(pConsole->mpUVM,
11260 pTask->mSavedStateFile.c_str(),
11261 Console::i_stateProgressCallback,
11262 static_cast<IProgress *>(pTask->mProgress));
11263#endif
11264 if (RT_SUCCESS(vrc))
11265 {
11266 if (pTask->mStartPaused)
11267 /* done */
11268 pConsole->i_setMachineState(MachineState_Paused);
11269 else
11270 {
11271 /* Start/Resume the VM execution */
11272#ifdef VBOX_WITH_EXTPACK
11273 vrc = pConsole->mptrExtPackManager->i_callAllVmPowerOnHooks(pConsole, pVM, pVMM);
11274#endif
11275 if (RT_SUCCESS(vrc))
11276 vrc = pVMM->pfnVMR3Resume(pConsole->mpUVM, VMRESUMEREASON_STATE_RESTORED);
11277 AssertLogRelRC(vrc);
11278 }
11279 }
11280
11281 /* Power off in case we failed loading or resuming the VM */
11282 if (RT_FAILURE(vrc))
11283 {
11284 int vrc2 = pVMM->pfnVMR3PowerOff(pConsole->mpUVM); AssertLogRelRC(vrc2);
11285#ifdef VBOX_WITH_EXTPACK
11286 pConsole->mptrExtPackManager->i_callAllVmPowerOffHooks(pConsole, pVM, pVMM);
11287#endif
11288 }
11289 }
11290 else if (pTask->mTeleporterEnabled)
11291 {
11292 /* -> ConsoleImplTeleporter.cpp */
11293 bool fPowerOffOnFailure;
11294 hrc = pConsole->i_teleporterTrg(pConsole->mpUVM, pConsole->mpVMM, pMachine, &pTask->mErrorMsg,
11295 pTask->mStartPaused, pTask->mProgress, &fPowerOffOnFailure);
11296 if (FAILED(hrc) && fPowerOffOnFailure)
11297 {
11298 ErrorInfoKeeper eik;
11299 int vrc2 = pVMM->pfnVMR3PowerOff(pConsole->mpUVM); AssertLogRelRC(vrc2);
11300#ifdef VBOX_WITH_EXTPACK
11301 pConsole->mptrExtPackManager->i_callAllVmPowerOffHooks(pConsole, pVM, pVMM);
11302#endif
11303 }
11304 }
11305 else if (pTask->mStartPaused)
11306 /* done */
11307 pConsole->i_setMachineState(MachineState_Paused);
11308 else
11309 {
11310 /* Power on the VM (i.e. start executing) */
11311#ifdef VBOX_WITH_EXTPACK
11312 vrc = pConsole->mptrExtPackManager->i_callAllVmPowerOnHooks(pConsole, pVM, pVMM);
11313#endif
11314 if (RT_SUCCESS(vrc))
11315 vrc = pVMM->pfnVMR3PowerOn(pConsole->mpUVM);
11316 AssertLogRelRC(vrc);
11317 }
11318
11319 /* acquire the lock again */
11320 alock.acquire();
11321 }
11322 while (0);
11323
11324 /* On failure, destroy the VM */
11325 if (FAILED(hrc) || RT_FAILURE(vrc))
11326 {
11327 /* preserve existing error info */
11328 ErrorInfoKeeper eik;
11329
11330 /* powerDown() will call VMR3Destroy() and do all necessary
11331 * cleanup (VRDP, USB devices) */
11332 alock.release();
11333 HRESULT hrc2 = pConsole->i_powerDown();
11334 alock.acquire();
11335 AssertComRC(hrc2);
11336 }
11337 else
11338 {
11339 /*
11340 * Deregister the VMSetError callback. This is necessary as the
11341 * pfnVMAtError() function passed to VMR3Create() is supposed to
11342 * be sticky but our error callback isn't.
11343 */
11344 alock.release();
11345 pVMM->pfnVMR3AtErrorDeregister(pConsole->mpUVM, Console::i_genericVMSetErrorCallback, &pTask->mErrorMsg);
11346 /** @todo register another VMSetError callback? */
11347 alock.acquire();
11348 }
11349 }
11350 else
11351 {
11352 /*
11353 * If VMR3Create() failed it has released the VM memory.
11354 */
11355 if (pConsole->m_pVMMDev)
11356 {
11357 alock.release(); /* just to be on the safe side... */
11358 pConsole->m_pVMMDev->hgcmShutdown(true /*fUvmIsInvalid*/);
11359 alock.acquire();
11360 }
11361 pVMM->pfnVMR3ReleaseUVM(pConsole->mpUVM);
11362 pConsole->mpUVM = NULL;
11363 }
11364
11365 if (SUCCEEDED(hrc) && RT_FAILURE(vrc))
11366 {
11367 /* If VMR3Create() or one of the other calls in this function fail,
11368 * an appropriate error message has been set in pTask->mErrorMsg.
11369 * However since that happens via a callback, the hrc status code in
11370 * this function is not updated.
11371 */
11372 if (!pTask->mErrorMsg.length())
11373 {
11374 /* If the error message is not set but we've got a failure,
11375 * convert the VBox status code into a meaningful error message.
11376 * This becomes unused once all the sources of errors set the
11377 * appropriate error message themselves.
11378 */
11379 AssertMsgFailed(("Missing error message during powerup for status code %Rrc\n", vrc));
11380 pTask->mErrorMsg = Utf8StrFmt(tr("Failed to start VM execution (%Rrc)"), vrc);
11381 }
11382
11383 /* Set the error message as the COM error.
11384 * Progress::notifyComplete() will pick it up later. */
11385 throw i_setErrorStaticBoth(E_FAIL, vrc, pTask->mErrorMsg.c_str());
11386 }
11387 }
11388 catch (HRESULT hrcXcpt) { hrc = hrcXcpt; }
11389
11390 if ( pConsole->mMachineState == MachineState_Starting
11391 || pConsole->mMachineState == MachineState_Restoring
11392 || pConsole->mMachineState == MachineState_TeleportingIn
11393 )
11394 {
11395 /* We are still in the Starting/Restoring state. This means one of:
11396 *
11397 * 1) we failed before VMR3Create() was called;
11398 * 2) VMR3Create() failed.
11399 *
11400 * In both cases, there is no need to call powerDown(), but we still
11401 * need to go back to the PoweredOff/Saved state. Reuse
11402 * vmstateChangeCallback() for that purpose.
11403 */
11404
11405 /* preserve existing error info */
11406 ErrorInfoKeeper eik;
11407
11408 Assert(pConsole->mpUVM == NULL);
11409 i_vmstateChangeCallback(NULL, pConsole->mpVMM, VMSTATE_TERMINATED, VMSTATE_CREATING, pConsole);
11410 }
11411
11412 /*
11413 * Evaluate the final result. Note that the appropriate mMachineState value
11414 * is already set by vmstateChangeCallback() in all cases.
11415 */
11416
11417 /* release the lock, don't need it any more */
11418 alock.release();
11419
11420 if (SUCCEEDED(hrc))
11421 {
11422 /* Notify the progress object of the success */
11423 pTask->mProgress->i_notifyComplete(S_OK);
11424 }
11425 else
11426 {
11427 /* The progress object will fetch the current error info */
11428 pTask->mProgress->i_notifyComplete(hrc);
11429 LogRel(("Power up failed (vrc=%Rrc, hrc=%Rhrc (%#08X))\n", vrc, hrc, hrc));
11430 }
11431
11432 /* Notify VBoxSVC and any waiting openRemoteSession progress object. */
11433 pConsole->mControl->EndPowerUp(hrc);
11434
11435#if defined(RT_OS_WINDOWS)
11436 /* uninitialize COM */
11437 CoUninitialize();
11438#endif
11439
11440 LogFlowFuncLeave();
11441}
11442
11443
11444/**
11445 * Reconfigures a medium attachment (part of taking or deleting an online snapshot).
11446 *
11447 * @param pThis Reference to the console object.
11448 * @param pUVM The VM handle.
11449 * @param pVMM The VMM vtable.
11450 * @param pcszDevice The name of the controller type.
11451 * @param uInstance The instance of the controller.
11452 * @param enmBus The storage bus type of the controller.
11453 * @param fUseHostIOCache Use the host I/O cache (disable async I/O).
11454 * @param fBuiltinIOCache Use the builtin I/O cache.
11455 * @param fInsertDiskIntegrityDrv Flag whether to insert the disk integrity driver into the chain
11456 * for additionalk debugging aids.
11457 * @param fSetupMerge Whether to set up a medium merge
11458 * @param uMergeSource Merge source image index
11459 * @param uMergeTarget Merge target image index
11460 * @param aMediumAtt The medium attachment.
11461 * @param aMachineState The current machine state.
11462 * @param phrc Where to store com error - only valid if we return VERR_GENERAL_FAILURE.
11463 * @return VBox status code.
11464 */
11465/* static */
11466DECLCALLBACK(int) Console::i_reconfigureMediumAttachment(Console *pThis,
11467 PUVM pUVM,
11468 PCVMMR3VTABLE pVMM,
11469 const char *pcszDevice,
11470 unsigned uInstance,
11471 StorageBus_T enmBus,
11472 bool fUseHostIOCache,
11473 bool fBuiltinIOCache,
11474 bool fInsertDiskIntegrityDrv,
11475 bool fSetupMerge,
11476 unsigned uMergeSource,
11477 unsigned uMergeTarget,
11478 IMediumAttachment *aMediumAtt,
11479 MachineState_T aMachineState,
11480 HRESULT *phrc)
11481{
11482 LogFlowFunc(("pUVM=%p aMediumAtt=%p phrc=%p\n", pUVM, aMediumAtt, phrc));
11483
11484 HRESULT hrc;
11485 Bstr bstr;
11486 *phrc = S_OK;
11487#define H() do { if (FAILED(hrc)) { AssertMsgFailed(("hrc=%Rhrc (%#x)\n", hrc, hrc)); *phrc = hrc; return VERR_GENERAL_FAILURE; } } while (0)
11488
11489 /* Ignore attachments other than hard disks, since at the moment they are
11490 * not subject to snapshotting in general. */
11491 DeviceType_T lType;
11492 hrc = aMediumAtt->COMGETTER(Type)(&lType); H();
11493 if (lType != DeviceType_HardDisk)
11494 return VINF_SUCCESS;
11495
11496 /* Update the device instance configuration. */
11497 int vrc = pThis->i_configMediumAttachment(pcszDevice,
11498 uInstance,
11499 enmBus,
11500 fUseHostIOCache,
11501 fBuiltinIOCache,
11502 fInsertDiskIntegrityDrv,
11503 fSetupMerge,
11504 uMergeSource,
11505 uMergeTarget,
11506 aMediumAtt,
11507 aMachineState,
11508 phrc,
11509 true /* fAttachDetach */,
11510 false /* fForceUnmount */,
11511 false /* fHotplug */,
11512 pUVM,
11513 pVMM,
11514 NULL /* paLedDevType */,
11515 NULL /* ppLunL0)*/);
11516 if (RT_FAILURE(vrc))
11517 {
11518 AssertMsgFailed(("vrc=%Rrc\n", vrc));
11519 return vrc;
11520 }
11521
11522#undef H
11523
11524 LogFlowFunc(("Returns success\n"));
11525 return VINF_SUCCESS;
11526}
11527
11528/**
11529 * Thread for powering down the Console.
11530 *
11531 * @param pTask The power down task.
11532 *
11533 * @note Locks the Console object for writing.
11534 */
11535/*static*/
11536void Console::i_powerDownThreadTask(VMPowerDownTask *pTask)
11537{
11538 int vrc = VINF_SUCCESS; /* only used in assertion */
11539 LogFlowFuncEnter();
11540 try
11541 {
11542 if (pTask->isOk() == false)
11543 vrc = VERR_GENERAL_FAILURE;
11544
11545 const ComObjPtr<Console> &that = pTask->mConsole;
11546
11547 /* Note: no need to use AutoCaller to protect Console because VMTask does
11548 * that */
11549
11550 /* wait until the method tat started us returns */
11551 AutoWriteLock thatLock(that COMMA_LOCKVAL_SRC_POS);
11552
11553 /* release VM caller to avoid the powerDown() deadlock */
11554 pTask->releaseVMCaller();
11555
11556 thatLock.release();
11557
11558 that->i_powerDown(pTask->mServerProgress);
11559
11560 /* complete the operation */
11561 that->mControl->EndPoweringDown(S_OK, Bstr().raw());
11562
11563 }
11564 catch (const std::exception &e)
11565 {
11566 AssertMsgFailed(("Exception %s was caught, vrc=%Rrc\n", e.what(), vrc));
11567 NOREF(e); NOREF(vrc);
11568 }
11569
11570 LogFlowFuncLeave();
11571}
11572
11573/**
11574 * @interface_method_impl{VMM2USERMETHODS,pfnSaveState}
11575 */
11576/*static*/ DECLCALLBACK(int)
11577Console::i_vmm2User_SaveState(PCVMM2USERMETHODS pThis, PUVM pUVM)
11578{
11579 Console *pConsole = ((MYVMM2USERMETHODS *)pThis)->pConsole;
11580 NOREF(pUVM);
11581
11582 /*
11583 * For now, just call SaveState. We should probably try notify the GUI so
11584 * it can pop up a progress object and stuff. The progress object created
11585 * by the call isn't returned to anyone and thus gets updated without
11586 * anyone noticing it.
11587 */
11588 ComPtr<IProgress> pProgress;
11589 HRESULT hrc = pConsole->mMachine->SaveState(pProgress.asOutParam());
11590 return SUCCEEDED(hrc) ? VINF_SUCCESS : Global::vboxStatusCodeFromCOM(hrc);
11591}
11592
11593/**
11594 * @interface_method_impl{VMM2USERMETHODS,pfnNotifyEmtInit}
11595 */
11596/*static*/ DECLCALLBACK(void)
11597Console::i_vmm2User_NotifyEmtInit(PCVMM2USERMETHODS pThis, PUVM pUVM, PUVMCPU pUVCpu)
11598{
11599 NOREF(pThis); NOREF(pUVM); NOREF(pUVCpu);
11600 VirtualBoxBase::initializeComForThread();
11601}
11602
11603/**
11604 * @interface_method_impl{VMM2USERMETHODS,pfnNotifyEmtTerm}
11605 */
11606/*static*/ DECLCALLBACK(void)
11607Console::i_vmm2User_NotifyEmtTerm(PCVMM2USERMETHODS pThis, PUVM pUVM, PUVMCPU pUVCpu)
11608{
11609 NOREF(pThis); NOREF(pUVM); NOREF(pUVCpu);
11610 VirtualBoxBase::uninitializeComForThread();
11611}
11612
11613/**
11614 * @interface_method_impl{VMM2USERMETHODS,pfnNotifyPdmtInit}
11615 */
11616/*static*/ DECLCALLBACK(void)
11617Console::i_vmm2User_NotifyPdmtInit(PCVMM2USERMETHODS pThis, PUVM pUVM)
11618{
11619 NOREF(pThis); NOREF(pUVM);
11620 VirtualBoxBase::initializeComForThread();
11621}
11622
11623/**
11624 * @interface_method_impl{VMM2USERMETHODS,pfnNotifyPdmtTerm}
11625 */
11626/*static*/ DECLCALLBACK(void)
11627Console::i_vmm2User_NotifyPdmtTerm(PCVMM2USERMETHODS pThis, PUVM pUVM)
11628{
11629 NOREF(pThis); NOREF(pUVM);
11630 VirtualBoxBase::uninitializeComForThread();
11631}
11632
11633/**
11634 * @interface_method_impl{VMM2USERMETHODS,pfnNotifyResetTurnedIntoPowerOff}
11635 */
11636/*static*/ DECLCALLBACK(void)
11637Console::i_vmm2User_NotifyResetTurnedIntoPowerOff(PCVMM2USERMETHODS pThis, PUVM pUVM)
11638{
11639 Console *pConsole = ((MYVMM2USERMETHODS *)pThis)->pConsole;
11640 NOREF(pUVM);
11641
11642 pConsole->mfPowerOffCausedByReset = true;
11643}
11644
11645/**
11646 * Internal function to get LED set off of Console instance
11647 *
11648 * @returns pointer to PDMLED object
11649 *
11650 * @param iLedSet Index of LED set to fetch
11651 */
11652PPDMLED volatile *
11653Console::i_getLedSet(uint32_t iLedSet)
11654{
11655 AssertReturn(iLedSet < RT_ELEMENTS(maLedSets), NULL);
11656 return maLedSets[iLedSet].papLeds;
11657}
11658
11659/**
11660 * @interface_method_impl{VMM2USERMETHODS,pfnQueryGenericObject}
11661 */
11662/*static*/ DECLCALLBACK(void *)
11663Console::i_vmm2User_QueryGenericObject(PCVMM2USERMETHODS pThis, PUVM pUVM, PCRTUUID pUuid)
11664{
11665 Console *pConsole = ((MYVMM2USERMETHODS *)pThis)->pConsole;
11666 NOREF(pUVM);
11667
11668 /* To simplify comparison we copy the UUID into a com::Guid object. */
11669 com::Guid const UuidCopy(*pUuid);
11670
11671 if (UuidCopy == COM_IIDOF(IConsole))
11672 {
11673 IConsole *pIConsole = static_cast<IConsole *>(pConsole);
11674 return pIConsole;
11675 }
11676
11677 if (UuidCopy == COM_IIDOF(IMachine))
11678 {
11679 IMachine *pIMachine = pConsole->mMachine;
11680 return pIMachine;
11681 }
11682
11683 if (UuidCopy == COM_IIDOF(IKeyboard))
11684 {
11685 IKeyboard *pIKeyboard = pConsole->mKeyboard;
11686 return pIKeyboard;
11687 }
11688
11689 if (UuidCopy == COM_IIDOF(IMouse))
11690 {
11691 IMouse *pIMouse = pConsole->mMouse;
11692 return pIMouse;
11693 }
11694
11695 if (UuidCopy == COM_IIDOF(IDisplay))
11696 {
11697 IDisplay *pIDisplay = pConsole->mDisplay;
11698 return pIDisplay;
11699 }
11700
11701 if (UuidCopy == COM_IIDOF(INvramStore))
11702 {
11703 NvramStore *pNvramStore = static_cast<NvramStore *>(pConsole->mptrNvramStore);
11704 return pNvramStore;
11705 }
11706
11707#ifdef VBOX_WITH_VIRT_ARMV8
11708 if (UuidCopy == COM_IIDOF(IResourceStore))
11709 {
11710 ResourceStore *pResourceStore = static_cast<ResourceStore *>(pConsole->mptrResourceStore);
11711 return pResourceStore;
11712 }
11713#endif
11714
11715 if (UuidCopy == VMMDEV_OID)
11716 return pConsole->m_pVMMDev;
11717
11718 if (UuidCopy == USBCARDREADER_OID)
11719 return pConsole->mUsbCardReader;
11720
11721 if (UuidCopy == COM_IIDOF(ISnapshot))
11722 return ((MYVMM2USERMETHODS *)pThis)->pISnapshot;
11723
11724 if (UuidCopy == REMOTEUSBIF_OID)
11725 return &pConsole->mRemoteUsbIf;
11726
11727 if (UuidCopy == EMULATEDUSBIF_OID)
11728 return pConsole->mEmulatedUSB->i_getEmulatedUsbIf();
11729
11730 return NULL;
11731}
11732
11733
11734/**
11735 * @interface_method_impl{PDMISECKEY,pfnKeyRetain}
11736 */
11737/*static*/ DECLCALLBACK(int)
11738Console::i_pdmIfSecKey_KeyRetain(PPDMISECKEY pInterface, const char *pszId, const uint8_t **ppbKey, size_t *pcbKey)
11739{
11740 Console *pConsole = ((MYPDMISECKEY *)pInterface)->pConsole;
11741
11742 AutoReadLock thatLock(pConsole COMMA_LOCKVAL_SRC_POS);
11743 SecretKey *pKey = NULL;
11744
11745 int vrc = pConsole->m_pKeyStore->retainSecretKey(Utf8Str(pszId), &pKey);
11746 if (RT_SUCCESS(vrc))
11747 {
11748 *ppbKey = (const uint8_t *)pKey->getKeyBuffer();
11749 *pcbKey = pKey->getKeySize();
11750 }
11751
11752 return vrc;
11753}
11754
11755/**
11756 * @interface_method_impl{PDMISECKEY,pfnKeyRelease}
11757 */
11758/*static*/ DECLCALLBACK(int)
11759Console::i_pdmIfSecKey_KeyRelease(PPDMISECKEY pInterface, const char *pszId)
11760{
11761 Console *pConsole = ((MYPDMISECKEY *)pInterface)->pConsole;
11762
11763 AutoReadLock thatLock(pConsole COMMA_LOCKVAL_SRC_POS);
11764 return pConsole->m_pKeyStore->releaseSecretKey(Utf8Str(pszId));
11765}
11766
11767/**
11768 * @interface_method_impl{PDMISECKEY,pfnPasswordRetain}
11769 */
11770/*static*/ DECLCALLBACK(int)
11771Console::i_pdmIfSecKey_PasswordRetain(PPDMISECKEY pInterface, const char *pszId, const char **ppszPassword)
11772{
11773 Console *pConsole = ((MYPDMISECKEY *)pInterface)->pConsole;
11774
11775 AutoReadLock thatLock(pConsole COMMA_LOCKVAL_SRC_POS);
11776 SecretKey *pKey = NULL;
11777
11778 int vrc = pConsole->m_pKeyStore->retainSecretKey(Utf8Str(pszId), &pKey);
11779 if (RT_SUCCESS(vrc))
11780 *ppszPassword = (const char *)pKey->getKeyBuffer();
11781
11782 return vrc;
11783}
11784
11785/**
11786 * @interface_method_impl{PDMISECKEY,pfnPasswordRelease}
11787 */
11788/*static*/ DECLCALLBACK(int)
11789Console::i_pdmIfSecKey_PasswordRelease(PPDMISECKEY pInterface, const char *pszId)
11790{
11791 Console *pConsole = ((MYPDMISECKEY *)pInterface)->pConsole;
11792
11793 AutoReadLock thatLock(pConsole COMMA_LOCKVAL_SRC_POS);
11794 return pConsole->m_pKeyStore->releaseSecretKey(Utf8Str(pszId));
11795}
11796
11797/**
11798 * @interface_method_impl{PDMISECKEYHLP,pfnKeyMissingNotify}
11799 */
11800/*static*/ DECLCALLBACK(int)
11801Console::i_pdmIfSecKeyHlp_KeyMissingNotify(PPDMISECKEYHLP pInterface)
11802{
11803 Console *pConsole = ((MYPDMISECKEYHLP *)pInterface)->pConsole;
11804
11805 /* Set guest property only, the VM is paused in the media driver calling us. */
11806 pConsole->mMachine->DeleteGuestProperty(Bstr("/VirtualBox/HostInfo/DekMissing").raw());
11807 pConsole->mMachine->SetGuestProperty(Bstr("/VirtualBox/HostInfo/DekMissing").raw(),
11808 Bstr("1").raw(), Bstr("RDONLYGUEST").raw());
11809 pConsole->mMachine->SaveSettings();
11810
11811 return VINF_SUCCESS;
11812}
11813
11814
11815
11816/**
11817 * The Main status driver instance data.
11818 */
11819typedef struct DRVMAINSTATUS
11820{
11821 /** The LED connectors. */
11822 PDMILEDCONNECTORS ILedConnectors;
11823 /** Pointer to the LED ports interface above us. */
11824 PPDMILEDPORTS pLedPorts;
11825 /** Pointer to the array of LED pointers. */
11826 PPDMLED volatile *papLeds;
11827 /** The unit number corresponding to the first entry in the LED array. */
11828 uint32_t iFirstLUN;
11829 /** The unit number corresponding to the last entry in the LED array.
11830 * (The size of the LED array is iLastLUN - iFirstLUN + 1.) */
11831 uint32_t iLastLUN;
11832 /** Pointer to the driver instance. */
11833 PPDMDRVINS pDrvIns;
11834 /** The Media Notify interface. */
11835 PDMIMEDIANOTIFY IMediaNotify;
11836 /** Set if there potentially are medium attachments. */
11837 bool fHasMediumAttachments;
11838 /** Device name+instance for mapping */
11839 char *pszDeviceInstance;
11840 /** Pointer to the Console object, for driver triggered activities. */
11841 Console *pConsole;
11842} DRVMAINSTATUS;
11843/** Pointer the instance data for a Main status driver. */
11844typedef DRVMAINSTATUS *PDRVMAINSTATUS;
11845
11846
11847/**
11848 * Notification about a unit which have been changed.
11849 *
11850 * The driver must discard any pointers to data owned by
11851 * the unit and requery it.
11852 *
11853 * @param pInterface Pointer to the interface structure containing the called function pointer.
11854 * @param iLUN The unit number.
11855 */
11856DECLCALLBACK(void) Console::i_drvStatus_UnitChanged(PPDMILEDCONNECTORS pInterface, unsigned iLUN)
11857{
11858 PDRVMAINSTATUS pThis = RT_FROM_MEMBER(pInterface, DRVMAINSTATUS, ILedConnectors);
11859 if (iLUN >= pThis->iFirstLUN && iLUN <= pThis->iLastLUN)
11860 {
11861 /*
11862 * Query the pointer to the PDMLED field inside the target device
11863 * structure (owned by the virtual hardware device).
11864 */
11865 PPDMLED pLed;
11866 int vrc = pThis->pLedPorts->pfnQueryStatusLed(pThis->pLedPorts, iLUN, &pLed);
11867 if (RT_FAILURE(vrc))
11868 pLed = NULL;
11869
11870 /*
11871 * Update the corresponding papLeds[] entry.
11872 *
11873 * papLeds[] points to the struct PDMLED of each of this driver's
11874 * units. The entries are initialized here, called out of a loop
11875 * in Console::i_drvStatus_Construct(), which previously called
11876 * Console::i_attachStatusDriver() to allocate the array itself.
11877 *
11878 * The arrays (and thus individual LEDs) are eventually read out
11879 * by Console::getDeviceActivity(), which is itself called from
11880 * src/VBox/Frontends/VirtualBox/src/runtime/UIIndicatorsPool.cpp
11881 */
11882 /** @todo acquire Console::mLedLock here in exclusive mode? */
11883 ASMAtomicWritePtr(&pThis->papLeds[iLUN - pThis->iFirstLUN], pLed);
11884 Log(("drvStatus_UnitChanged: iLUN=%d pLed=%p\n", iLUN, pLed));
11885 }
11886}
11887
11888
11889/**
11890 * Notification about a medium eject.
11891 *
11892 * @returns VBox status code.
11893 * @param pInterface Pointer to the interface structure containing the called function pointer.
11894 * @param uLUN The unit number.
11895 */
11896DECLCALLBACK(int) Console::i_drvStatus_MediumEjected(PPDMIMEDIANOTIFY pInterface, unsigned uLUN)
11897{
11898 PDRVMAINSTATUS pThis = RT_FROM_MEMBER(pInterface, DRVMAINSTATUS, IMediaNotify);
11899 LogFunc(("uLUN=%d\n", uLUN));
11900 if (pThis->fHasMediumAttachments)
11901 {
11902 Console * const pConsole = pThis->pConsole;
11903 AutoWriteLock alock(pConsole COMMA_LOCKVAL_SRC_POS);
11904
11905 ComPtr<IMediumAttachment> pMediumAtt;
11906 Utf8Str devicePath = Utf8StrFmt("%s/LUN#%u", pThis->pszDeviceInstance, uLUN);
11907 Console::MediumAttachmentMap::const_iterator end = pConsole->mapMediumAttachments.end();
11908 Console::MediumAttachmentMap::const_iterator it = pConsole->mapMediumAttachments.find(devicePath);
11909 if (it != end)
11910 pMediumAtt = it->second;
11911 Assert(!pMediumAtt.isNull());
11912 if (!pMediumAtt.isNull())
11913 {
11914 IMedium *pMedium = NULL;
11915 HRESULT hrc = pMediumAtt->COMGETTER(Medium)(&pMedium);
11916 AssertComRC(hrc);
11917 if (SUCCEEDED(hrc) && pMedium)
11918 {
11919 BOOL fHostDrive = FALSE;
11920 hrc = pMedium->COMGETTER(HostDrive)(&fHostDrive);
11921 AssertComRC(hrc);
11922 if (!fHostDrive)
11923 {
11924 alock.release();
11925
11926 ComPtr<IMediumAttachment> pNewMediumAtt;
11927 hrc = pThis->pConsole->mControl->EjectMedium(pMediumAtt, pNewMediumAtt.asOutParam());
11928 if (SUCCEEDED(hrc))
11929 {
11930 pThis->pConsole->mMachine->SaveSettings();
11931 ::FireMediumChangedEvent(pThis->pConsole->mEventSource, pNewMediumAtt);
11932 }
11933
11934 alock.acquire();
11935 if (pNewMediumAtt != pMediumAtt)
11936 {
11937 pConsole->mapMediumAttachments.erase(devicePath);
11938 pConsole->mapMediumAttachments.insert(std::make_pair(devicePath, pNewMediumAtt));
11939 }
11940 }
11941 }
11942 }
11943 }
11944 return VINF_SUCCESS;
11945}
11946
11947
11948/**
11949 * @interface_method_impl{PDMIBASE,pfnQueryInterface}
11950 */
11951DECLCALLBACK(void *) Console::i_drvStatus_QueryInterface(PPDMIBASE pInterface, const char *pszIID)
11952{
11953 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
11954 PDRVMAINSTATUS pThis = PDMINS_2_DATA(pDrvIns, PDRVMAINSTATUS);
11955 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
11956 PDMIBASE_RETURN_INTERFACE(pszIID, PDMILEDCONNECTORS, &pThis->ILedConnectors);
11957 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIMEDIANOTIFY, &pThis->IMediaNotify);
11958 return NULL;
11959}
11960
11961
11962/**
11963 * Destruct a status driver instance.
11964 *
11965 * @param pDrvIns The driver instance data.
11966 */
11967DECLCALLBACK(void) Console::i_drvStatus_Destruct(PPDMDRVINS pDrvIns)
11968{
11969 PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
11970 PDRVMAINSTATUS pThis = PDMINS_2_DATA(pDrvIns, PDRVMAINSTATUS);
11971 LogFlowFunc(("iInstance=%d\n", pDrvIns->iInstance));
11972
11973 if (pThis->papLeds)
11974 {
11975 unsigned iLed = pThis->iLastLUN - pThis->iFirstLUN + 1;
11976 while (iLed-- > 0)
11977 ASMAtomicWriteNullPtr(&pThis->papLeds[iLed]);
11978 }
11979}
11980
11981
11982/**
11983 * Construct a status driver instance.
11984 *
11985 * @copydoc FNPDMDRVCONSTRUCT
11986 */
11987DECLCALLBACK(int) Console::i_drvStatus_Construct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
11988{
11989 RT_NOREF(fFlags);
11990 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
11991 PDRVMAINSTATUS pThis = PDMINS_2_DATA(pDrvIns, PDRVMAINSTATUS);
11992 LogFlowFunc(("iInstance=%d\n", pDrvIns->iInstance));
11993
11994 /*
11995 * Initialize data.
11996 */
11997 com::Guid ConsoleUuid(COM_IIDOF(IConsole));
11998 IConsole *pIConsole = (IConsole *)PDMDrvHlpQueryGenericUserObject(pDrvIns, ConsoleUuid.raw());
11999 AssertLogRelReturn(pIConsole, VERR_INTERNAL_ERROR_3);
12000 Console *pConsole = static_cast<Console *>(pIConsole);
12001 AssertLogRelReturn(pConsole, VERR_INTERNAL_ERROR_3);
12002
12003 pDrvIns->IBase.pfnQueryInterface = Console::i_drvStatus_QueryInterface;
12004 pThis->ILedConnectors.pfnUnitChanged = Console::i_drvStatus_UnitChanged;
12005 pThis->IMediaNotify.pfnEjected = Console::i_drvStatus_MediumEjected;
12006 pThis->pDrvIns = pDrvIns;
12007 pThis->pConsole = pConsole;
12008 pThis->fHasMediumAttachments = false;
12009 pThis->papLeds = NULL;
12010 pThis->pszDeviceInstance = NULL;
12011
12012 /*
12013 * Validate configuration.
12014 */
12015 PDMDRV_VALIDATE_CONFIG_RETURN(pDrvIns,
12016 "DeviceInstance|"
12017 "iLedSet|"
12018 "HasMediumAttachments|"
12019 "First|"
12020 "Last",
12021 "");
12022 AssertMsgReturn(PDMDrvHlpNoAttach(pDrvIns) == VERR_PDM_NO_ATTACHED_DRIVER,
12023 ("Configuration error: Not possible to attach anything to this driver!\n"),
12024 VERR_PDM_DRVINS_NO_ATTACH);
12025
12026 /*
12027 * Read config.
12028 */
12029 PCPDMDRVHLPR3 const pHlp = pDrvIns->pHlpR3;
12030
12031 uint32_t iLedSet;
12032 int vrc = pHlp->pfnCFGMQueryU32(pCfg, "iLedSet", &iLedSet);
12033 AssertLogRelMsgRCReturn(vrc, ("Configuration error: Failed to query the \"iLedSet\" value! vrc=%Rrc\n", vrc), vrc);
12034 pThis->papLeds = pConsole->i_getLedSet(iLedSet);
12035
12036 vrc = pHlp->pfnCFGMQueryBoolDef(pCfg, "HasMediumAttachments", &pThis->fHasMediumAttachments, false);
12037 AssertLogRelMsgRCReturn(vrc, ("Configuration error: Failed to query the \"HasMediumAttachments\" value! vrc=%Rrc\n", vrc), vrc);
12038
12039 if (pThis->fHasMediumAttachments)
12040 {
12041 vrc = pHlp->pfnCFGMQueryStringAlloc(pCfg, "DeviceInstance", &pThis->pszDeviceInstance);
12042 AssertLogRelMsgRCReturn(vrc, ("Configuration error: Failed to query the \"DeviceInstance\" value! vrc=%Rrc\n", vrc), vrc);
12043 }
12044
12045 vrc = pHlp->pfnCFGMQueryU32Def(pCfg, "First", &pThis->iFirstLUN, 0);
12046 AssertLogRelMsgRCReturn(vrc, ("Configuration error: Failed to query the \"First\" value! vrc=%Rrc\n", vrc), vrc);
12047
12048 vrc = pHlp->pfnCFGMQueryU32Def(pCfg, "Last", &pThis->iLastLUN, 0);
12049 AssertLogRelMsgRCReturn(vrc, ("Configuration error: Failed to query the \"Last\" value! vrc=%Rrc\n", vrc), vrc);
12050
12051 AssertLogRelMsgReturn(pThis->iFirstLUN <= pThis->iLastLUN,
12052 ("Configuration error: Invalid unit range %u-%u\n", pThis->iFirstLUN, pThis->iLastLUN),
12053 VERR_INVALID_PARAMETER);
12054
12055 /*
12056 * Get the ILedPorts interface of the above driver/device and
12057 * query the LEDs we want.
12058 */
12059 pThis->pLedPorts = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMILEDPORTS);
12060 AssertMsgReturn(pThis->pLedPorts, ("Configuration error: No led ports interface above!\n"),
12061 VERR_PDM_MISSING_INTERFACE_ABOVE);
12062
12063 for (unsigned i = pThis->iFirstLUN; i <= pThis->iLastLUN; ++i)
12064 Console::i_drvStatus_UnitChanged(&pThis->ILedConnectors, i);
12065
12066 return VINF_SUCCESS;
12067}
12068
12069
12070/**
12071 * Console status driver (LED) registration record.
12072 */
12073const PDMDRVREG Console::DrvStatusReg =
12074{
12075 /* u32Version */
12076 PDM_DRVREG_VERSION,
12077 /* szName */
12078 "MainStatus",
12079 /* szRCMod */
12080 "",
12081 /* szR0Mod */
12082 "",
12083 /* pszDescription */
12084 "Main status driver (Main as in the API).",
12085 /* fFlags */
12086 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
12087 /* fClass. */
12088 PDM_DRVREG_CLASS_STATUS,
12089 /* cMaxInstances */
12090 ~0U,
12091 /* cbInstance */
12092 sizeof(DRVMAINSTATUS),
12093 /* pfnConstruct */
12094 Console::i_drvStatus_Construct,
12095 /* pfnDestruct */
12096 Console::i_drvStatus_Destruct,
12097 /* pfnRelocate */
12098 NULL,
12099 /* pfnIOCtl */
12100 NULL,
12101 /* pfnPowerOn */
12102 NULL,
12103 /* pfnReset */
12104 NULL,
12105 /* pfnSuspend */
12106 NULL,
12107 /* pfnResume */
12108 NULL,
12109 /* pfnAttach */
12110 NULL,
12111 /* pfnDetach */
12112 NULL,
12113 /* pfnPowerOff */
12114 NULL,
12115 /* pfnSoftReset */
12116 NULL,
12117 /* u32EndVersion */
12118 PDM_DRVREG_VERSION
12119};
12120
12121
12122
12123/* 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