VirtualBox

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

Last change on this file since 40712 was 40712, checked in by vboxsync, 13 years ago

NetShaper: Online bandwidth limit setting (#5582)

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

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