VirtualBox

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

Last change on this file since 100655 was 100606, checked in by vboxsync, 17 months ago

Shared Clipboard/Main + FE/Qt: Added clipboard error propagation from the host service via a newly added ClipboardErrorEvent. For that we now have a generic (private) Shared Clipboard handling class within Main, which does the HGCM service callback dispatching. The VRDP console object, which was in charge for this before, now is daisy-chained to this new class as a service extension. FE/QT in turn then shows the error(s) via the notification center. bugref:9437

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