VirtualBox

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

Last change on this file since 99180 was 98807, checked in by vboxsync, 2 years ago

Some small Solaris-specific build warning fixes:

Main/Console: Remove a duplicate 'HRESULT hrc' declaration (flagged as
'warning: declaration of ‘hrc’ shadows a previous local [-Wshadow]').

Main/PerformanceSolaris: Move global variable ‘g_fNotReported’ behind
'if ARCH_BITS == 32' as it's only used in 32-bit mode (flagged as
'warning: ‘g_fNotReported’ defined but not used [-Wunused-variable]').

HostDrivers/VBoxNetFlt: The vboxNetFltSolarisMuxIdToFd() routine calls
the Solaris STREAMS kernel routine strioctl() which only sets the
seventh argument (int *rvalp) upon success. vboxNetFltSolarisMuxIdToFd()
passes in an 'int *pFd' argument for this returned value and logically
only sets it upon success. The subsequent code ignores 'pFd' upon
failure but the compiler isn't smart enough to figure that out so add in
an initialization for '*pFd' (flagged as 'warning: ‘Ip6MuxFd’ may be used
uninitialized [-Wmaybe-uninitialized]' and similarly for 'Ip4MuxFd' and
'ArpMuxFd').

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

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