VirtualBox

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

Last change on this file since 54994 was 54994, checked in by vboxsync, 10 years ago

Preserve error messages before calling i_clearDiskEncryptionKeysOnAllAttachmentsWithKeyId()

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