VirtualBox

Ticket #10605: ConsoleImpl.cpp

File ConsoleImpl.cpp, 327.4 KB (added by Twisted Lincoln, Inc., 12 years ago)

New ConsoleImpl.cpp file with fix added

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy