VirtualBox

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

Last change on this file since 61009 was 61009, checked in by vboxsync, 9 years ago

Main: big settings cleanup and writing optimization. Moved constructors/equality/default checks into the .cpp file, and write only settings which aren't at the default value. Greatly reduces the effort needed to write everything out, especially when a lot of snapshots have to be dealt with. Move the storage controllers to the hardware settings, where they always belonged. No change to the XML file (yet). Lots of settings related cleanups in the API code.

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