VirtualBox

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

Last change on this file since 78767 was 78767, checked in by vboxsync, 6 years ago

Console::i_vmstateChangeCallback/VMSTATE_OFF: Same delete NULL scenario as previously, but now with uncaught HRESULT throws on EMT thrown, as it were, into the mix. We should really forbid throwing stuff in Main, it is _clearly_ too difficult to get simple things like this half right. [fix]

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