VirtualBox

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

Last change on this file since 67914 was 67914, checked in by vboxsync, 7 years ago

src-client: Define LOG_GROUP according to interface or similar.

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