VirtualBox

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

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

Main/Machine+USBController+StorageController: Mix of deleting useless functionality, fixing of missing sanity checks and adding some additional functionality. The removed functionality is the possibility to specify patters of guest properties which will trigger notifications, which wasn't useful as it is per VM, sabotaging other API clients (e.g. the VM process assumes it gets the notifications it needs). The storage controller setters were lacking a lot of state and consistency sanity checking, which is now fixed. Both the USB and storage controllers can now be renamed (no API client uses this functionality though), all with very pessimistic assumptions (only when the VM is powered off).

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