VirtualBox

source: vbox/trunk/src/VBox/Main/ConsoleImpl.cpp@ 33825

最後變更 在這個檔案從33825是 33825,由 vboxsync 提交於 14 年 前

Main,NAT: Managing port-forwarding at runtime. (xTracker/#4835).

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

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