VirtualBox

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

Last change on this file since 91363 was 91363, checked in by vboxsync, 4 years ago

FE/VBoxSDL+VirtualBox,Main/Console+Machine+VirtualBox.xidl: VMs which
crash while restoring from the 'Saved' state shouldn't lose their saved
state file. bugref:1484

A new machine state named 'AbortedSaved' has been added which a VM will
enter if it crashes when restoring from the 'Saved' state before the
'Running' state has been reached. A VM in the 'AbortedSaved' machine
state will have its saved state file preserved so that the VM can still be
restored once the cause of the failure to powerUp() and reach the
'Running' state has been resolved.

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette