VirtualBox

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

Last change on this file since 400 was 358, checked in by vboxsync, 18 years ago

Main: Hard disk consistensy errors such as UUID mismatch are now also returned through the lastAccessError property, not through the HRESULT of getAccessible() (because such conditions are not fatal and can be retried later).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 241.0 KB
Line 
1/** @file
2 *
3 * VBox Console COM Class implementation
4 */
5
6/*
7 * Copyright (C) 2006 InnoTek Systemberatung GmbH
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License as published by the Free Software Foundation,
13 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
14 * distribution. VirtualBox OSE is distributed in the hope that it will
15 * be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * If you received this file as part of a commercial VirtualBox
18 * distribution, then only the terms of your commercial VirtualBox
19 * license agreement apply instead of the previous paragraph.
20 */
21
22#if defined(__WIN__)
23#elif defined(__LINUX__)
24# include <errno.h>
25# include <sys/ioctl.h>
26# include <sys/poll.h>
27# include <sys/fcntl.h>
28# include <net/if.h>
29# include <linux/if_tun.h>
30#endif
31
32#include "ConsoleImpl.h"
33#include "GuestImpl.h"
34#include "KeyboardImpl.h"
35#include "MouseImpl.h"
36#include "DisplayImpl.h"
37#include "MachineDebuggerImpl.h"
38#include "USBDeviceImpl.h"
39#include "RemoteUSBDeviceImpl.h"
40#include "SharedFolderImpl.h"
41#include "AudioSnifferInterface.h"
42#include "ConsoleVRDPServer.h"
43#include "VMMDev.h"
44
45// generated header
46#include "SchemaDefs.h"
47
48#include "Logging.h"
49
50#include <iprt/string.h>
51#include <iprt/asm.h>
52#include <iprt/file.h>
53#include <iprt/path.h>
54#include <iprt/dir.h>
55#include <iprt/process.h>
56#include <iprt/ldr.h>
57
58#include <VBox/vmapi.h>
59#include <VBox/err.h>
60#include <VBox/param.h>
61#include <VBox/vusb.h>
62#include <VBox/mm.h>
63#include <VBox/ssm.h>
64#include <VBox/version.h>
65
66#include <VBox/VBoxDev.h>
67
68#include <VBox/HostServices/VBoxClipboardSvc.h>
69
70#include <set>
71#include <algorithm>
72#include <memory> // for auto_ptr
73
74
75// VMTask and friends
76////////////////////////////////////////////////////////////////////////////////
77
78/**
79 * Task structure for asynchronous VM operations.
80 *
81 * Once created, the task structure adds itself as a Console caller.
82 * This means:
83 *
84 * 1. The user must check for #rc() before using the created structure
85 * (e.g. passing it as a thread function argument). If #rc() returns a
86 * failure, the Console object may not be used by the task (see
87 Console::addCaller() for more details).
88 * 2. On successful initialization, the structure keeps the Console caller
89 * until destruction (to ensure Console remains in the Ready state and won't
90 * be accidentially uninitialized). Forgetting to delete the created task
91 * will lead to Console::uninit() stuck waiting for releasing all added
92 * callers.
93 *
94 * If \a aUsesVMPtr parameter is true, the task structure will also add itself
95 * as a Console::mpVM caller with the same meaning as above. See
96 * Console::addVMCaller() for more info.
97 */
98struct VMTask
99{
100 VMTask (Console *aConsole, bool aUsesVMPtr)
101 : mConsole (aConsole), mCallerAdded (false), mVMCallerAdded (false)
102 {
103 AssertReturnVoid (aConsole);
104 mRC = aConsole->addCaller();
105 if (SUCCEEDED (mRC))
106 {
107 mCallerAdded = true;
108 if (aUsesVMPtr)
109 {
110 mRC = aConsole->addVMCaller();
111 if (SUCCEEDED (mRC))
112 mVMCallerAdded = true;
113 }
114 }
115 }
116
117 ~VMTask()
118 {
119 if (mVMCallerAdded)
120 mConsole->releaseVMCaller();
121 if (mCallerAdded)
122 mConsole->releaseCaller();
123 }
124
125 HRESULT rc() const { return mRC; }
126 bool isOk() const { return SUCCEEDED (rc()); }
127
128 /** Releases the Console caller before destruction. Not normally necessary. */
129 void releaseCaller()
130 {
131 AssertReturnVoid (mCallerAdded);
132 mConsole->releaseCaller();
133 mCallerAdded = false;
134 }
135
136 /** Releases the VM caller before destruction. Not normally necessary. */
137 void releaseVMCaller()
138 {
139 AssertReturnVoid (mVMCallerAdded);
140 mConsole->releaseVMCaller();
141 mVMCallerAdded = false;
142 }
143
144 const ComObjPtr <Console> mConsole;
145
146private:
147
148 HRESULT mRC;
149 bool mCallerAdded : 1;
150 bool mVMCallerAdded : 1;
151};
152
153struct VMProgressTask : public VMTask
154{
155 VMProgressTask (Console *aConsole, Progress *aProgress, bool aUsesVMPtr)
156 : VMTask (aConsole, aUsesVMPtr), mProgress (aProgress) {}
157
158 const ComObjPtr <Progress> mProgress;
159};
160
161struct VMPowerUpTask : public VMProgressTask
162{
163 VMPowerUpTask (Console *aConsole, Progress *aProgress)
164 : VMProgressTask (aConsole, aProgress, false /* aUsesVMPtr */)
165 , mSetVMErrorCallback (NULL), mConfigConstructor (NULL) {}
166
167 PFNVMATERROR mSetVMErrorCallback;
168 PFNCFGMCONSTRUCTOR mConfigConstructor;
169 Utf8Str mSavedStateFile;
170 std::map <Bstr, ComPtr <ISharedFolder> > mSharedFolders;
171};
172
173struct VMSaveTask : public VMProgressTask
174{
175 VMSaveTask (Console *aConsole, Progress *aProgress)
176 : VMProgressTask (aConsole, aProgress, true /* aUsesVMPtr */)
177 , mIsSnapshot (false)
178 , mLastMachineState (MachineState_InvalidMachineState) {}
179
180 bool mIsSnapshot;
181 Utf8Str mSavedStateFile;
182 MachineState_T mLastMachineState;
183 ComPtr <IProgress> mServerProgress;
184};
185
186
187// constructor / desctructor
188/////////////////////////////////////////////////////////////////////////////
189
190Console::Console()
191 : mSavedStateDataLoaded (false)
192 , mConsoleVRDPServer (NULL)
193 , mpVM (NULL)
194 , mVMCallers (0)
195 , mVMZeroCallersSem (NIL_RTSEMEVENT)
196 , mVMDestroying (false)
197 , meDVDState (DriveState_NotMounted)
198 , meFloppyState (DriveState_NotMounted)
199 , mVMMDev (NULL)
200 , mAudioSniffer (NULL)
201 , mVMStateChangeCallbackDisabled (false)
202 , mMachineState (MachineState_PoweredOff)
203{}
204
205Console::~Console()
206{}
207
208HRESULT Console::FinalConstruct()
209{
210 LogFlowThisFunc (("\n"));
211
212 memset(mapFDLeds, 0, sizeof(mapFDLeds));
213 memset(mapIDELeds, 0, sizeof(mapIDELeds));
214 memset(mapNetworkLeds, 0, sizeof(mapNetworkLeds));
215
216#ifdef __LINUX__
217 Assert(ELEMENTS(maTapFD) == ELEMENTS(maTAPDeviceName));
218 Assert(ELEMENTS(maTapFD) >= SchemaDefs::NetworkAdapterCount);
219 for (unsigned i = 0; i < ELEMENTS(maTapFD); i++)
220 {
221 maTapFD[i] = NIL_RTFILE;
222 maTAPDeviceName[i] = "";
223 }
224#endif
225
226 return S_OK;
227}
228
229void Console::FinalRelease()
230{
231 LogFlowThisFunc (("\n"));
232
233 uninit();
234}
235
236// public initializer/uninitializer for internal purposes only
237/////////////////////////////////////////////////////////////////////////////
238
239HRESULT Console::init (IMachine *aMachine, IInternalMachineControl *aControl)
240{
241 AssertReturn (aMachine && aControl, E_INVALIDARG);
242
243 /* Enclose the state transition NotReady->InInit->Ready */
244 AutoInitSpan autoInitSpan (this);
245 AssertReturn (autoInitSpan.isOk(), E_UNEXPECTED);
246
247 LogFlowThisFuncEnter();
248 LogFlowThisFunc(("aMachine=%p, aControl=%p\n", aMachine, aControl));
249
250 HRESULT rc = E_FAIL;
251
252 unconst (mMachine) = aMachine;
253 unconst (mControl) = aControl;
254
255 /* Cache essential properties and objects */
256
257 rc = mMachine->COMGETTER(State) (&mMachineState);
258 AssertComRCReturn (rc, rc);
259
260 rc = mMachine->COMGETTER(VRDPServer) (unconst (mVRDPServer).asOutParam());
261 AssertComRCReturn (rc, rc);
262
263 rc = mMachine->COMGETTER(DVDDrive) (unconst (mDVDDrive).asOutParam());
264 AssertComRCReturn (rc, rc);
265
266 rc = mMachine->COMGETTER(FloppyDrive) (unconst (mFloppyDrive).asOutParam());
267 AssertComRCReturn (rc, rc);
268
269 /* Create associated child COM objects */
270
271 unconst (mGuest).createObject();
272 rc = mGuest->init (this);
273 AssertComRCReturn (rc, rc);
274
275 unconst (mKeyboard).createObject();
276 rc = mKeyboard->init (this);
277 AssertComRCReturn (rc, rc);
278
279 unconst (mMouse).createObject();
280 rc = mMouse->init (this);
281 AssertComRCReturn (rc, rc);
282
283 unconst (mDisplay).createObject();
284 rc = mDisplay->init (this);
285 AssertComRCReturn (rc, rc);
286
287 unconst (mRemoteDisplayInfo).createObject();
288 rc = mRemoteDisplayInfo->init (this);
289 AssertComRCReturn (rc, rc);
290
291 /* Create other child objects */
292
293 unconst (mConsoleVRDPServer) = new ConsoleVRDPServer (this);
294 AssertReturn (mConsoleVRDPServer, E_FAIL);
295
296#ifdef VRDP_MC
297 m_cAudioRefs = 0;
298#endif /* VRDP_MC */
299
300 unconst (mVMMDev) = new VMMDev(this);
301 AssertReturn (mVMMDev, E_FAIL);
302
303 unconst (mAudioSniffer) = new AudioSniffer(this);
304 AssertReturn (mAudioSniffer, E_FAIL);
305
306 /* Confirm a successful initialization when it's the case */
307 autoInitSpan.setSucceeded();
308
309 LogFlowThisFuncLeave();
310
311 return S_OK;
312}
313
314/**
315 * Uninitializes the Console object.
316 */
317void Console::uninit()
318{
319 LogFlowThisFuncEnter();
320
321 /* Enclose the state transition Ready->InUninit->NotReady */
322 AutoUninitSpan autoUninitSpan (this);
323 if (autoUninitSpan.uninitDone())
324 {
325 LogFlowThisFunc (("Already uninitialized.\n"));
326 LogFlowThisFuncLeave();
327 return;
328 }
329
330 LogFlowThisFunc (("initFailed()=%d\n", autoUninitSpan.initFailed()));
331
332 /*
333 * Uninit all children that ise addDependentChild()/removeDependentChild()
334 * in their init()/uninit() methods.
335 */
336 uninitDependentChildren();
337
338 /* This should be the first, since this may cause detaching remote USB devices. */
339 if (mConsoleVRDPServer)
340 {
341 delete mConsoleVRDPServer;
342 unconst (mConsoleVRDPServer) = NULL;
343 }
344
345 /* power down the VM if necessary */
346 if (mpVM)
347 {
348 powerDown();
349 Assert (mpVM == NULL);
350 }
351
352 if (mVMZeroCallersSem != NIL_RTSEMEVENT)
353 {
354 RTSemEventDestroy (mVMZeroCallersSem);
355 mVMZeroCallersSem = NIL_RTSEMEVENT;
356 }
357
358 if (mAudioSniffer)
359 {
360 delete mAudioSniffer;
361 unconst (mAudioSniffer) = NULL;
362 }
363
364 if (mVMMDev)
365 {
366 delete mVMMDev;
367 unconst (mVMMDev) = NULL;
368 }
369
370 mSharedFolders.clear();
371 mRemoteUSBDevices.clear();
372 mUSBDevices.clear();
373
374 if (mRemoteDisplayInfo)
375 {
376 mRemoteDisplayInfo->uninit();
377 unconst (mRemoteDisplayInfo).setNull();;
378 }
379
380 if (mDebugger)
381 {
382 mDebugger->uninit();
383 unconst (mDebugger).setNull();
384 }
385
386 if (mDisplay)
387 {
388 mDisplay->uninit();
389 unconst (mDisplay).setNull();
390 }
391
392 if (mMouse)
393 {
394 mMouse->uninit();
395 unconst (mMouse).setNull();
396 }
397
398 if (mKeyboard)
399 {
400 mKeyboard->uninit();
401 unconst (mKeyboard).setNull();;
402 }
403
404 if (mGuest)
405 {
406 mGuest->uninit();
407 unconst (mGuest).setNull();;
408 }
409
410 unconst (mFloppyDrive).setNull();
411 unconst (mDVDDrive).setNull();
412 unconst (mVRDPServer).setNull();
413
414 unconst (mControl).setNull();
415 unconst (mMachine).setNull();
416
417 // Release all callbacks. Do this after uninitializing the components,
418 // as some of them are well-behaved and unregister their callbacks.
419 // These would trigger error messages complaining about trying to
420 // unregister a non-registered callback.
421 mCallbacks.clear();
422
423 LogFlowThisFuncLeave();
424}
425
426#ifdef VRDP_MC
427DECLCALLBACK(int) Console::vrdp_ClientLogon (void *pvUser,
428 uint32_t u32ClientId,
429 const char *pszUser,
430 const char *pszPassword,
431 const char *pszDomain)
432#else
433DECLCALLBACK(int) Console::vrdp_ClientLogon (void *pvUser, const char *pszUser,
434 const char *pszPassword,
435 const char *pszDomain)
436#endif /* VRDP_MC */
437{
438 LogFlowFuncEnter();
439#ifdef VRDP_MC
440 LogFlowFunc (("%d, %s, %s, %s\n", u32ClientId, pszUser, pszPassword, pszDomain));
441#else
442 LogFlowFunc (("%s, %s, %s\n", pszUser, pszPassword, pszDomain));
443#endif /* VRDP_MC */
444
445 Console *console = static_cast <Console *> (pvUser);
446 AssertReturn (console, VERR_INVALID_POINTER);
447
448 AutoCaller autoCaller (console);
449 if (!autoCaller.isOk())
450 {
451 /* Console has been already uninitialized, deny request */
452 LogRel(("VRDPAUTH: Access denied (Console uninitialized).\n"));
453 LogFlowFuncLeave();
454 return VERR_ACCESS_DENIED;
455 }
456
457 Guid uuid;
458 HRESULT hrc = console->mMachine->COMGETTER (Id) (uuid.asOutParam());
459 AssertComRCReturn (hrc, VERR_ACCESS_DENIED);
460
461 VRDPAuthType_T authType = VRDPAuthType_VRDPAuthNull;
462 hrc = console->mVRDPServer->COMGETTER(AuthType) (&authType);
463 AssertComRCReturn (hrc, VERR_ACCESS_DENIED);
464
465 ULONG authTimeout = 0;
466 hrc = console->mVRDPServer->COMGETTER(AuthTimeout) (&authTimeout);
467 AssertComRCReturn (hrc, VERR_ACCESS_DENIED);
468
469 VRDPAuthResult result = VRDPAuthAccessDenied;
470 VRDPAuthGuestJudgement guestJudgement = VRDPAuthGuestNotAsked;
471
472 LogFlowFunc(("Auth type %d\n", authType));
473
474 LogRel (("VRDPAUTH: User: [%s]. Domain: [%s]. Authentication type: [%s]\n",
475 pszUser, pszDomain,
476 authType == VRDPAuthType_VRDPAuthNull?
477 "null":
478 (authType == VRDPAuthType_VRDPAuthExternal?
479 "external":
480 (authType == VRDPAuthType_VRDPAuthGuest?
481 "guest":
482 "INVALID"
483 )
484 )
485 ));
486
487 switch (authType)
488 {
489 case VRDPAuthType_VRDPAuthNull:
490 {
491 result = VRDPAuthAccessGranted;
492 break;
493 }
494
495 case VRDPAuthType_VRDPAuthExternal:
496 {
497 /* Call the external library. */
498 result = console->mConsoleVRDPServer->Authenticate (uuid, guestJudgement, pszUser, pszPassword, pszDomain);
499
500 if (result != VRDPAuthDelegateToGuest)
501 {
502 break;
503 }
504
505 LogRel(("VRDPAUTH: Delegated to guest.\n"));
506
507 LogFlowFunc (("External auth asked for guest judgement\n"));
508 } /* pass through */
509
510 case VRDPAuthType_VRDPAuthGuest:
511 {
512 guestJudgement = VRDPAuthGuestNotReacted;
513
514 if (console->mVMMDev)
515 {
516 /* Issue the request to guest. Assume that the call does not require EMT. It should not. */
517
518 /* Ask the guest to judge these credentials. */
519 uint32_t u32GuestFlags = VMMDEV_SETCREDENTIALS_JUDGE;
520
521 int rc = console->mVMMDev->getVMMDevPort()->pfnSetCredentials (console->mVMMDev->getVMMDevPort(),
522 pszUser, pszPassword, pszDomain, u32GuestFlags);
523
524 if (VBOX_SUCCESS (rc))
525 {
526 /* Wait for guest. */
527 rc = console->mVMMDev->WaitCredentialsJudgement (authTimeout, &u32GuestFlags);
528
529 if (VBOX_SUCCESS (rc))
530 {
531 switch (u32GuestFlags & (VMMDEV_CREDENTIALS_JUDGE_OK | VMMDEV_CREDENTIALS_JUDGE_DENY | VMMDEV_CREDENTIALS_JUDGE_NOJUDGEMENT))
532 {
533 case VMMDEV_CREDENTIALS_JUDGE_DENY: guestJudgement = VRDPAuthGuestAccessDenied; break;
534 case VMMDEV_CREDENTIALS_JUDGE_NOJUDGEMENT: guestJudgement = VRDPAuthGuestNoJudgement; break;
535 case VMMDEV_CREDENTIALS_JUDGE_OK: guestJudgement = VRDPAuthGuestAccessGranted; break;
536 default:
537 LogFlowFunc (("Invalid guest flags %08X!!!\n", u32GuestFlags)); break;
538 }
539 }
540 else
541 {
542 LogFlowFunc (("Wait for credentials judgement rc = %Vrc!!!\n", rc));
543 }
544
545 LogFlowFunc (("Guest judgement %d\n", guestJudgement));
546 }
547 else
548 {
549 LogFlowFunc (("Could not set credentials rc = %Vrc!!!\n", rc));
550 }
551 }
552
553 if (authType == VRDPAuthType_VRDPAuthExternal)
554 {
555 LogRel(("VRDPAUTH: Guest judgement %d.\n", guestJudgement));
556 LogFlowFunc (("External auth called again with guest judgement = %d\n", guestJudgement));
557 result = console->mConsoleVRDPServer->Authenticate (uuid, guestJudgement, pszUser, pszPassword, pszDomain);
558 }
559 else
560 {
561 switch (guestJudgement)
562 {
563 case VRDPAuthGuestAccessGranted:
564 result = VRDPAuthAccessGranted;
565 break;
566 default:
567 result = VRDPAuthAccessDenied;
568 break;
569 }
570 }
571 } break;
572
573 default:
574 AssertFailed();
575 }
576
577 LogFlowFunc (("Result = %d\n", result));
578 LogFlowFuncLeave();
579
580 if (result == VRDPAuthAccessGranted)
581 {
582 LogRel(("VRDPAUTH: Access granted.\n"));
583 return VINF_SUCCESS;
584 }
585
586 /* Reject. */
587 LogRel(("VRDPAUTH: Access denied.\n"));
588 return VERR_ACCESS_DENIED;
589}
590
591#ifdef VRDP_MC
592DECLCALLBACK(void) Console::vrdp_ClientConnect (void *pvUser,
593 uint32_t u32ClientId)
594#else
595DECLCALLBACK(void) Console::vrdp_ClientConnect (void *pvUser,
596 uint32_t fu32SupportedOrders)
597#endif /* VRDP_MC */
598{
599 LogFlowFuncEnter();
600
601 Console *console = static_cast <Console *> (pvUser);
602 AssertReturnVoid (console);
603
604 AutoCaller autoCaller (console);
605 AssertComRCReturnVoid (autoCaller.rc());
606
607#ifdef VBOX_VRDP
608#ifdef VRDP_MC
609 NOREF(u32ClientId);
610 console->mDisplay->VideoAccelVRDP (true);
611#else
612 console->mDisplay->VideoAccelVRDP (true, fu32SupportedOrders);
613#endif /* VRDP_MC */
614#endif /* VBOX_VRDP */
615
616 LogFlowFuncLeave();
617 return;
618}
619
620#ifdef VRDP_MC
621DECLCALLBACK(void) Console::vrdp_ClientDisconnect (void *pvUser,
622 uint32_t u32ClientId,
623 uint32_t fu32Intercepted)
624#else
625DECLCALLBACK(void) Console::vrdp_ClientDisconnect (void *pvUser)
626#endif /* VRDP_MC */
627{
628 LogFlowFuncEnter();
629
630 Console *console = static_cast <Console *> (pvUser);
631 AssertReturnVoid (console);
632
633 AutoCaller autoCaller (console);
634 AssertComRCReturnVoid (autoCaller.rc());
635
636 AssertReturnVoid (console->mConsoleVRDPServer);
637
638#ifdef VBOX_VRDP
639#ifdef VRDP_MC
640 console->mDisplay->VideoAccelVRDP (false);
641#else
642 console->mDisplay->VideoAccelVRDP (false, 0);
643#endif /* VRDP_MC */
644#endif /* VBOX_VRDP */
645
646#ifdef VRDP_MC
647 if (fu32Intercepted & VRDP_CLIENT_INTERCEPT_USB)
648 {
649 console->mConsoleVRDPServer->USBBackendDelete (u32ClientId);
650 }
651#else
652 console->mConsoleVRDPServer->DeleteUSBBackend ();
653#endif /* VRDP_MC */
654
655#ifdef VBOX_VRDP
656#ifdef VRDP_MC
657 if (fu32Intercepted & VRDP_CLIENT_INTERCEPT_AUDIO)
658 {
659 console->m_cAudioRefs--;
660
661 if (console->m_cAudioRefs <= 0)
662 {
663 if (console->mAudioSniffer)
664 {
665 PPDMIAUDIOSNIFFERPORT port = console->mAudioSniffer->getAudioSnifferPort();
666 if (port)
667 {
668 port->pfnSetup (port, false, false);
669 }
670 }
671 }
672 }
673#else
674 if (console->mAudioSniffer)
675 {
676 PPDMIAUDIOSNIFFERPORT port = console->mAudioSniffer->getAudioSnifferPort();
677 if (port)
678 {
679 port->pfnSetup (port, false, false);
680 }
681 }
682#endif /* VRDP_MC */
683#endif /* VBOX_VRDP */
684
685 LogFlowFuncLeave();
686 return;
687}
688
689#ifdef VRDP_MC
690DECLCALLBACK(void) Console::vrdp_InterceptAudio (void *pvUser,
691 uint32_t u32ClientId)
692#else
693DECLCALLBACK(void) Console::vrdp_InterceptAudio (void *pvUser, bool fKeepHostAudio)
694#endif /* VRDP_MC */
695{
696 LogFlowFuncEnter();
697
698 Console *console = static_cast <Console *> (pvUser);
699 AssertReturnVoid (console);
700
701 AutoCaller autoCaller (console);
702 AssertComRCReturnVoid (autoCaller.rc());
703
704#ifdef VRDP_MC
705 LogFlowFunc (("mAudioSniffer %p, u32ClientId %d.\n",
706 console->mAudioSniffer, u32ClientId));
707 NOREF(u32ClientId);
708#else
709 LogFlowFunc (("mAudioSniffer %p, keepHostAudio %d.\n",
710 console->mAudioSniffer, fKeepHostAudio));
711#endif /* VRDP_MC */
712
713#ifdef VBOX_VRDP
714#ifdef VRDP_MC
715 console->m_cAudioRefs++;
716
717 if (console->m_cAudioRefs == 1)
718 {
719 if (console->mAudioSniffer)
720 {
721 PPDMIAUDIOSNIFFERPORT port = console->mAudioSniffer->getAudioSnifferPort();
722 if (port)
723 {
724 port->pfnSetup (port, true, true);
725 }
726 }
727 }
728#else
729 if (console->mAudioSniffer)
730 {
731 PPDMIAUDIOSNIFFERPORT port = console->mAudioSniffer->getAudioSnifferPort();
732 if (port)
733 {
734 port->pfnSetup (port, true, !!fKeepHostAudio);
735 }
736 }
737#endif /* VRDP_MC */
738#endif
739
740 LogFlowFuncLeave();
741 return;
742}
743
744#ifdef VRDP_MC
745DECLCALLBACK(void) Console::vrdp_InterceptUSB (void *pvUser,
746 uint32_t u32ClientId,
747 PFNVRDPUSBCALLBACK *ppfn,
748 void **ppv)
749#else
750DECLCALLBACK(void) Console::vrdp_InterceptUSB (void *pvUser, PFNVRDPUSBCALLBACK *ppfn, void **ppv)
751#endif /* VRDP_MC */
752{
753 LogFlowFuncEnter();
754
755 Console *console = static_cast <Console *> (pvUser);
756 AssertReturnVoid (console);
757
758 AutoCaller autoCaller (console);
759 AssertComRCReturnVoid (autoCaller.rc());
760
761 AssertReturnVoid (console->mConsoleVRDPServer);
762
763#ifdef VRDP_MC
764 console->mConsoleVRDPServer->USBBackendCreate (u32ClientId, ppfn, ppv);
765#else
766 console->mConsoleVRDPServer->CreateUSBBackend (ppfn, ppv);
767#endif /* VRDP_MC */
768
769 LogFlowFuncLeave();
770 return;
771}
772
773// static
774VRDPSERVERCALLBACK Console::sVrdpServerCallback =
775{
776 vrdp_ClientLogon,
777 vrdp_ClientConnect,
778 vrdp_ClientDisconnect,
779 vrdp_InterceptAudio,
780 vrdp_InterceptUSB
781};
782
783//static
784char *Console::sSSMConsoleUnit = "ConsoleData";
785//static
786uint32_t Console::sSSMConsoleVer = 0x00010000;
787
788/**
789 * Loads various console data stored in the saved state file.
790 * This method does validation of the state file and returns an error info
791 * when appropriate.
792 *
793 * The method does nothing if the machine is not in the Saved file or if
794 * console data from it has already been loaded.
795 *
796 * @note The caller must lock this object for writing.
797 */
798HRESULT Console::loadDataFromSavedState()
799{
800 if (mMachineState != MachineState_Saved || mSavedStateDataLoaded)
801 return S_OK;
802
803 Bstr savedStateFile;
804 HRESULT rc = mMachine->COMGETTER(StateFilePath) (savedStateFile.asOutParam());
805 if (FAILED (rc))
806 return rc;
807
808 PSSMHANDLE ssm;
809 int vrc = SSMR3Open (Utf8Str(savedStateFile), 0, &ssm);
810 if (VBOX_SUCCESS (vrc))
811 {
812 uint32_t version = 0;
813 vrc = SSMR3Seek (ssm, sSSMConsoleUnit, 0 /* iInstance */, &version);
814 if (version == sSSMConsoleVer)
815 {
816 if (VBOX_SUCCESS (vrc))
817 vrc = loadStateFileExec (ssm, this, 0);
818 else if (vrc == VERR_SSM_UNIT_NOT_FOUND)
819 vrc = VINF_SUCCESS;
820 }
821 else
822 vrc = VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION;
823
824 SSMR3Close (ssm);
825 }
826
827 if (VBOX_FAILURE (vrc))
828 rc = setError (E_FAIL,
829 tr ("The saved state file '%ls' is invalid (%Vrc). "
830 "Discard the saved state and try again"),
831 savedStateFile.raw(), vrc);
832
833 mSavedStateDataLoaded = true;
834
835 return rc;
836}
837
838/**
839 * Callback handler to save various console data to the state file,
840 * called when the user saves the VM state.
841 *
842 * @param pvUser pointer to Console
843 *
844 * @note Locks the Console object for reading.
845 */
846//static
847DECLCALLBACK(void)
848Console::saveStateFileExec (PSSMHANDLE pSSM, void *pvUser)
849{
850 LogFlowFunc (("\n"));
851
852 Console *that = static_cast <Console *> (pvUser);
853 AssertReturnVoid (that);
854
855 AutoCaller autoCaller (that);
856 AssertComRCReturnVoid (autoCaller.rc());
857
858 AutoReaderLock alock (that);
859
860 int vrc = SSMR3PutU32 (pSSM, that->mSharedFolders.size());
861 AssertRC (vrc);
862
863 for (SharedFolderList::const_iterator it = that->mSharedFolders.begin();
864 it != that->mSharedFolders.end();
865 ++ it)
866 {
867 ComObjPtr <SharedFolder> folder = (*it);
868 AutoLock folderLock (folder);
869
870 Utf8Str name = folder->name();
871 vrc = SSMR3PutU32 (pSSM, name.length() + 1 /* term. 0 */);
872 AssertRC (vrc);
873 vrc = SSMR3PutStrZ (pSSM, name);
874 AssertRC (vrc);
875
876 Utf8Str hostPath = folder->hostPath();
877 vrc = SSMR3PutU32 (pSSM, hostPath.length() + 1 /* term. 0 */);
878 AssertRC (vrc);
879 vrc = SSMR3PutStrZ (pSSM, hostPath);
880 AssertRC (vrc);
881 }
882
883 return;
884}
885
886/**
887 * Callback handler to load various console data from the state file.
888 * When \a u32Version is 0, this method is called from #loadDataFromSavedState,
889 * otherwise it is called when the VM is being restored from the saved state.
890 *
891 * @param pvUser pointer to Console
892 * @param u32Version Console unit version.
893 * When not 0, should match sSSMConsoleVer.
894 *
895 * @note Locks the Console object for writing.
896 */
897//static
898DECLCALLBACK(int)
899Console::loadStateFileExec (PSSMHANDLE pSSM, void *pvUser, uint32_t u32Version)
900{
901 LogFlowFunc (("\n"));
902
903 if (u32Version != 0 && u32Version != sSSMConsoleVer)
904 return VERR_VERSION_MISMATCH;
905
906 if (u32Version != 0)
907 {
908 /* currently, nothing to do when we've been called from VMR3Load */
909 return VINF_SUCCESS;
910 }
911
912 Console *that = static_cast <Console *> (pvUser);
913 AssertReturn (that, VERR_INVALID_PARAMETER);
914
915 AutoCaller autoCaller (that);
916 AssertComRCReturn (autoCaller.rc(), VERR_ACCESS_DENIED);
917
918 AutoLock alock (that);
919
920 AssertReturn (that->mSharedFolders.size() == 0, VERR_INTERNAL_ERROR);
921
922 uint32_t size = 0;
923 int vrc = SSMR3GetU32 (pSSM, &size);
924 AssertRCReturn (vrc, vrc);
925
926 for (uint32_t i = 0; i < size; ++ i)
927 {
928 Bstr name;
929 Bstr hostPath;
930
931 uint32_t szBuf = 0;
932 char *buf = NULL;
933
934 vrc = SSMR3GetU32 (pSSM, &szBuf);
935 AssertRCReturn (vrc, vrc);
936 buf = new char [szBuf];
937 vrc = SSMR3GetStrZ (pSSM, buf, szBuf);
938 AssertRC (vrc);
939 name = buf;
940 delete[] buf;
941
942 vrc = SSMR3GetU32 (pSSM, &szBuf);
943 AssertRCReturn (vrc, vrc);
944 buf = new char [szBuf];
945 vrc = SSMR3GetStrZ (pSSM, buf, szBuf);
946 AssertRC (vrc);
947 hostPath = buf;
948 delete[] buf;
949
950 ComObjPtr <SharedFolder> sharedFolder;
951 sharedFolder.createObject();
952 HRESULT rc = sharedFolder->init (that, name, hostPath);
953 AssertComRCReturn (rc, VERR_INTERNAL_ERROR);
954 if (FAILED (rc))
955 return rc;
956
957 that->mSharedFolders.push_back (sharedFolder);
958 }
959
960 return VINF_SUCCESS;
961}
962
963// IConsole properties
964/////////////////////////////////////////////////////////////////////////////
965
966STDMETHODIMP Console::COMGETTER(Machine) (IMachine **aMachine)
967{
968 if (!aMachine)
969 return E_POINTER;
970
971 AutoCaller autoCaller (this);
972 CheckComRCReturnRC (autoCaller.rc());
973
974 /* mMachine is constant during life time, no need to lock */
975 mMachine.queryInterfaceTo (aMachine);
976
977 return S_OK;
978}
979
980STDMETHODIMP Console::COMGETTER(State) (MachineState_T *aMachineState)
981{
982 if (!aMachineState)
983 return E_POINTER;
984
985 AutoCaller autoCaller (this);
986 CheckComRCReturnRC (autoCaller.rc());
987
988 AutoReaderLock alock (this);
989
990 /* we return our local state (since it's always the same as on the server) */
991 *aMachineState = mMachineState;
992
993 return S_OK;
994}
995
996STDMETHODIMP Console::COMGETTER(Guest) (IGuest **aGuest)
997{
998 if (!aGuest)
999 return E_POINTER;
1000
1001 AutoCaller autoCaller (this);
1002 CheckComRCReturnRC (autoCaller.rc());
1003
1004 /* mGuest is constant during life time, no need to lock */
1005 mGuest.queryInterfaceTo (aGuest);
1006
1007 return S_OK;
1008}
1009
1010STDMETHODIMP Console::COMGETTER(Keyboard) (IKeyboard **aKeyboard)
1011{
1012 if (!aKeyboard)
1013 return E_POINTER;
1014
1015 AutoCaller autoCaller (this);
1016 CheckComRCReturnRC (autoCaller.rc());
1017
1018 /* mKeyboard is constant during life time, no need to lock */
1019 mKeyboard.queryInterfaceTo (aKeyboard);
1020
1021 return S_OK;
1022}
1023
1024STDMETHODIMP Console::COMGETTER(Mouse) (IMouse **aMouse)
1025{
1026 if (!aMouse)
1027 return E_POINTER;
1028
1029 AutoCaller autoCaller (this);
1030 CheckComRCReturnRC (autoCaller.rc());
1031
1032 /* mMouse is constant during life time, no need to lock */
1033 mMouse.queryInterfaceTo (aMouse);
1034
1035 return S_OK;
1036}
1037
1038STDMETHODIMP Console::COMGETTER(Display) (IDisplay **aDisplay)
1039{
1040 if (!aDisplay)
1041 return E_POINTER;
1042
1043 AutoCaller autoCaller (this);
1044 CheckComRCReturnRC (autoCaller.rc());
1045
1046 /* mDisplay is constant during life time, no need to lock */
1047 mDisplay.queryInterfaceTo (aDisplay);
1048
1049 return S_OK;
1050}
1051
1052STDMETHODIMP Console::COMGETTER(Debugger) (IMachineDebugger **aDebugger)
1053{
1054 if (!aDebugger)
1055 return E_POINTER;
1056
1057 AutoCaller autoCaller (this);
1058 CheckComRCReturnRC (autoCaller.rc());
1059
1060 /* we need a write lock because of the lazy mDebugger initialization*/
1061 AutoLock alock (this);
1062
1063 /* check if we have to create the debugger object */
1064 if (!mDebugger)
1065 {
1066 unconst (mDebugger).createObject();
1067 mDebugger->init (this);
1068 }
1069
1070 mDebugger.queryInterfaceTo (aDebugger);
1071
1072 return S_OK;
1073}
1074
1075STDMETHODIMP Console::COMGETTER(USBDevices) (IUSBDeviceCollection **aUSBDevices)
1076{
1077 if (!aUSBDevices)
1078 return E_POINTER;
1079
1080 AutoCaller autoCaller (this);
1081 CheckComRCReturnRC (autoCaller.rc());
1082
1083 AutoReaderLock alock (this);
1084
1085 ComObjPtr <USBDeviceCollection> collection;
1086 collection.createObject();
1087 collection->init (mUSBDevices);
1088 collection.queryInterfaceTo (aUSBDevices);
1089
1090 return S_OK;
1091}
1092
1093STDMETHODIMP Console::COMGETTER(RemoteUSBDevices) (IHostUSBDeviceCollection **aRemoteUSBDevices)
1094{
1095 if (!aRemoteUSBDevices)
1096 return E_POINTER;
1097
1098 AutoCaller autoCaller (this);
1099 CheckComRCReturnRC (autoCaller.rc());
1100
1101 AutoReaderLock alock (this);
1102
1103 ComObjPtr <RemoteUSBDeviceCollection> collection;
1104 collection.createObject();
1105 collection->init (mRemoteUSBDevices);
1106 collection.queryInterfaceTo (aRemoteUSBDevices);
1107
1108 return S_OK;
1109}
1110
1111STDMETHODIMP Console::COMGETTER(RemoteDisplayInfo) (IRemoteDisplayInfo **aRemoteDisplayInfo)
1112{
1113 if (!aRemoteDisplayInfo)
1114 return E_POINTER;
1115
1116 AutoCaller autoCaller (this);
1117 CheckComRCReturnRC (autoCaller.rc());
1118
1119 /* mDisplay is constant during life time, no need to lock */
1120 mRemoteDisplayInfo.queryInterfaceTo (aRemoteDisplayInfo);
1121
1122 return S_OK;
1123}
1124
1125STDMETHODIMP
1126Console::COMGETTER(SharedFolders) (ISharedFolderCollection **aSharedFolders)
1127{
1128 if (!aSharedFolders)
1129 return E_POINTER;
1130
1131 AutoCaller autoCaller (this);
1132 CheckComRCReturnRC (autoCaller.rc());
1133
1134 /* loadDataFromSavedState() needs a write lock */
1135 AutoLock alock (this);
1136
1137 /* Read console data stored in the saved state file (if not yet done) */
1138 HRESULT rc = loadDataFromSavedState();
1139 CheckComRCReturnRC (rc);
1140
1141 ComObjPtr <SharedFolderCollection> coll;
1142 coll.createObject();
1143 coll->init (mSharedFolders);
1144 coll.queryInterfaceTo (aSharedFolders);
1145
1146 return S_OK;
1147}
1148
1149// IConsole methods
1150/////////////////////////////////////////////////////////////////////////////
1151
1152STDMETHODIMP Console::PowerUp (IProgress **aProgress)
1153{
1154 LogFlowThisFuncEnter();
1155 LogFlowThisFunc (("mMachineState=%d\n", mMachineState));
1156
1157 AutoCaller autoCaller (this);
1158 CheckComRCReturnRC (autoCaller.rc());
1159
1160 AutoLock alock (this);
1161
1162 if (mMachineState >= MachineState_Running)
1163 return setError(E_FAIL, tr ("Cannot power up the machine as it is already running. (Machine state: %d)"), mMachineState);
1164
1165 /*
1166 * First check whether all disks are accessible. This is not a 100%
1167 * bulletproof approach (race condition, it might become inaccessible
1168 * right after the check) but it's convenient as it will cover 99.9%
1169 * of the cases and here, we're able to provide meaningful error
1170 * information.
1171 */
1172 ComPtr<IHardDiskAttachmentCollection> coll;
1173 mMachine->COMGETTER(HardDiskAttachments)(coll.asOutParam());
1174 ComPtr<IHardDiskAttachmentEnumerator> enumerator;
1175 coll->Enumerate(enumerator.asOutParam());
1176 BOOL fHasMore;
1177 while (SUCCEEDED(enumerator->HasMore(&fHasMore)) && fHasMore)
1178 {
1179 ComPtr<IHardDiskAttachment> attach;
1180 enumerator->GetNext(attach.asOutParam());
1181 ComPtr<IHardDisk> hdd;
1182 attach->COMGETTER(HardDisk)(hdd.asOutParam());
1183 Assert(hdd);
1184 BOOL fAccessible;
1185 HRESULT rc = hdd->COMGETTER(AllAccessible)(&fAccessible);
1186 CheckComRCReturnRC (rc);
1187 if (!fAccessible)
1188 {
1189 Bstr loc;
1190 hdd->COMGETTER(Location) (loc.asOutParam());
1191 Bstr errMsg;
1192 hdd->COMGETTER(LastAccessError) (errMsg.asOutParam());
1193 return setError (E_FAIL,
1194 tr ("VM cannot start because the hard disk '%ls' is not accessible "
1195 "(%ls)"),
1196 loc.raw(), errMsg.raw());
1197 }
1198 }
1199
1200 /* now perform the same check if a ISO is mounted */
1201 ComPtr<IDVDDrive> dvdDrive;
1202 mMachine->COMGETTER(DVDDrive)(dvdDrive.asOutParam());
1203 ComPtr<IDVDImage> dvdImage;
1204 dvdDrive->GetImage(dvdImage.asOutParam());
1205 if (dvdImage)
1206 {
1207 BOOL fAccessible;
1208 HRESULT rc = dvdImage->COMGETTER(Accessible)(&fAccessible);
1209 CheckComRCReturnRC (rc);
1210 if (!fAccessible)
1211 {
1212 Bstr filePath;
1213 dvdImage->COMGETTER(FilePath)(filePath.asOutParam());
1214 /// @todo (r=dmik) grab the last access error once
1215 // IDVDImage::lastAccessError is there
1216 return setError (E_FAIL,
1217 tr ("VM cannot start because the DVD image '%ls' is not accessible"),
1218 filePath.raw());
1219 }
1220 }
1221
1222 /* now perform the same check if a floppy is mounted */
1223 ComPtr<IFloppyDrive> floppyDrive;
1224 mMachine->COMGETTER(FloppyDrive)(floppyDrive.asOutParam());
1225 ComPtr<IFloppyImage> floppyImage;
1226 floppyDrive->GetImage(floppyImage.asOutParam());
1227 if (floppyImage)
1228 {
1229 BOOL fAccessible;
1230 HRESULT rc = floppyImage->COMGETTER(Accessible)(&fAccessible);
1231 CheckComRCReturnRC (rc);
1232 if (!fAccessible)
1233 {
1234 Bstr filePath;
1235 floppyImage->COMGETTER(FilePath)(filePath.asOutParam());
1236 /// @todo (r=dmik) grab the last access error once
1237 // IDVDImage::lastAccessError is there
1238 return setError (E_FAIL,
1239 tr ("VM cannot start because the floppy image '%ls' is not accessible"),
1240 filePath.raw());
1241 }
1242 }
1243
1244 /* now the network cards will undergo a quick consistency check */
1245 for (ULONG slot = 0; slot < SchemaDefs::NetworkAdapterCount; slot ++)
1246 {
1247 ComPtr<INetworkAdapter> adapter;
1248 mMachine->GetNetworkAdapter (slot, adapter.asOutParam());
1249 BOOL enabled = FALSE;
1250 adapter->COMGETTER(Enabled) (&enabled);
1251 if (!enabled)
1252 continue;
1253
1254 NetworkAttachmentType_T netattach;
1255 adapter->COMGETTER(AttachmentType)(&netattach);
1256 switch (netattach)
1257 {
1258 case NetworkAttachmentType_HostInterfaceNetworkAttachment:
1259 {
1260#ifdef __WIN__
1261 /* a valid host interface must have been set */
1262 Bstr hostif;
1263 adapter->COMGETTER(HostInterface)(hostif.asOutParam());
1264 if (!hostif)
1265 {
1266 return setError (E_FAIL,
1267 tr ("VM cannot start because host interface networking "
1268 "requires a host interface name to be set"));
1269 }
1270 ComPtr<IVirtualBox> virtualBox;
1271 mMachine->COMGETTER(Parent)(virtualBox.asOutParam());
1272 ComPtr<IHost> host;
1273 virtualBox->COMGETTER(Host)(host.asOutParam());
1274 ComPtr<IHostNetworkInterfaceCollection> coll;
1275 host->COMGETTER(NetworkInterfaces)(coll.asOutParam());
1276 ComPtr<IHostNetworkInterface> hostInterface;
1277 if (!SUCCEEDED(coll->FindByName(hostif, hostInterface.asOutParam())))
1278 {
1279 return setError (E_FAIL,
1280 tr ("VM cannot start because the host interface '%ls' "
1281 "does not exist"),
1282 hostif.raw());
1283 }
1284#endif /* __WIN__ */
1285 break;
1286 }
1287 default:
1288 break;
1289 }
1290 }
1291
1292 /* Read console data stored in the saved state file (if not yet done) */
1293 {
1294 HRESULT rc = loadDataFromSavedState();
1295 CheckComRCReturnRC (rc);
1296 }
1297
1298 /* Check all types of shared folders and compose a single list */
1299 std::map <Bstr, ComPtr <ISharedFolder> > sharedFolders;
1300 {
1301 /// @todo (dmik) check and add globally shared folders when they are
1302 // done
1303
1304 ComPtr <ISharedFolderCollection> coll;
1305 HRESULT rc = mMachine->COMGETTER(SharedFolders) (coll.asOutParam());
1306 CheckComRCReturnRC (rc);
1307 ComPtr <ISharedFolderEnumerator> en;
1308 rc = coll->Enumerate (en.asOutParam());
1309 CheckComRCReturnRC (rc);
1310
1311 BOOL hasMore = FALSE;
1312 while (SUCCEEDED (en->HasMore (&hasMore)) && hasMore)
1313 {
1314 ComPtr <ISharedFolder> folder;
1315 en->GetNext (folder.asOutParam());
1316
1317 Bstr name;
1318 rc = folder->COMGETTER(Name) (name.asOutParam());
1319 CheckComRCReturnRC (rc);
1320
1321 BOOL accessible = FALSE;
1322 rc = folder->COMGETTER(Accessible) (&accessible);
1323 CheckComRCReturnRC (rc);
1324
1325 if (!accessible)
1326 {
1327 Bstr hostPath;
1328 folder->COMGETTER(HostPath) (hostPath.asOutParam());
1329 return setError (E_FAIL,
1330 tr ("Host path '%ls' of the shared folder '%ls' is not accessible"),
1331 hostPath.raw(), name.raw());
1332 }
1333
1334 sharedFolders.insert (std::make_pair (name, folder));
1335 /// @todo (dmik) later, do this:
1336// if (!sharedFolders.insert (std::pair <name, folder>).second)
1337// return setError (E_FAIL,
1338// tr ("Could not accept a permanently shared folder named '%ls' "
1339// "because a globally shared folder with the same name "
1340// "already exists"),
1341// name.raw());
1342 }
1343
1344 for (SharedFolderList::const_iterator it = mSharedFolders.begin();
1345 it != mSharedFolders.end(); ++ it)
1346 {
1347 ComPtr <ISharedFolder> folder = static_cast <SharedFolder *> (*it);
1348
1349 if (!sharedFolders.insert (std::make_pair ((*it)->name(), folder)).second)
1350 return setError (E_FAIL,
1351 tr ("Could not create a transient shared folder named '%ls' "
1352 "because a global or a permanent shared folder with "
1353 "the same name already exists"),
1354 (*it)->name().raw());
1355 }
1356 }
1357
1358 Bstr savedStateFile;
1359
1360 /*
1361 * Saved VMs will have to prove that their saved states are kosher.
1362 */
1363 if (mMachineState == MachineState_Saved)
1364 {
1365 HRESULT rc = mMachine->COMGETTER(StateFilePath) (savedStateFile.asOutParam());
1366 CheckComRCReturnRC (rc);
1367 ComAssertRet (!!savedStateFile, E_FAIL);
1368 int vrc = SSMR3ValidateFile (Utf8Str (savedStateFile));
1369 if (VBOX_FAILURE (vrc))
1370 return setError (E_FAIL,
1371 tr ("VM cannot start because the saved state file '%ls' is invalid (%Vrc). "
1372 "Discard the saved state prior to starting the VM"),
1373 savedStateFile.raw(), vrc);
1374 }
1375
1376 /* create an IProgress object to track progress of this operation */
1377 ComObjPtr <Progress> progress;
1378 progress.createObject();
1379 Bstr progressDesc;
1380 if (mMachineState == MachineState_Saved)
1381 progressDesc = tr ("Restoring the virtual machine");
1382 else
1383 progressDesc = tr ("Starting the virtual machine");
1384 progress->init ((IConsole *) this, progressDesc, FALSE /* aCancelable */);
1385
1386 /* pass reference to caller if requested */
1387 if (aProgress)
1388 progress.queryInterfaceTo (aProgress);
1389
1390 /* setup task object and thread to carry out the operation asynchronously */
1391 std::auto_ptr <VMPowerUpTask> task (new VMPowerUpTask (this, progress));
1392 ComAssertComRCRetRC (task->rc());
1393
1394 task->mSetVMErrorCallback = setVMErrorCallback;
1395 task->mConfigConstructor = configConstructor;
1396 task->mSharedFolders = sharedFolders;
1397 if (mMachineState == MachineState_Saved)
1398 task->mSavedStateFile = savedStateFile;
1399
1400 int vrc = RTThreadCreate (NULL, Console::powerUpThread, (void *) task.get(),
1401 0, RTTHREADTYPE_MAIN_WORKER, 0, "VMPowerUp");
1402
1403 ComAssertMsgRCRet (vrc, ("Could not create VMPowerUp thread (%Vrc)\n", vrc),
1404 E_FAIL);
1405
1406 /* task is now owned by powerUpThread(), so release it */
1407 task.release();
1408
1409 if (mMachineState == MachineState_Saved)
1410 setMachineState (MachineState_Restoring);
1411 else
1412 setMachineState (MachineState_Starting);
1413
1414 LogFlowThisFunc (("mMachineState=%d\n", mMachineState));
1415 LogFlowThisFuncLeave();
1416 return S_OK;
1417}
1418
1419STDMETHODIMP Console::PowerDown()
1420{
1421 LogFlowThisFuncEnter();
1422 LogFlowThisFunc (("mMachineState=%d\n", mMachineState));
1423
1424 AutoCaller autoCaller (this);
1425 CheckComRCReturnRC (autoCaller.rc());
1426
1427 AutoLock alock (this);
1428
1429 if (mMachineState != MachineState_Running &&
1430 mMachineState != MachineState_Paused)
1431 {
1432 /* extra nice error message for a common case */
1433 if (mMachineState == MachineState_Saved)
1434 return setError(E_FAIL, tr ("Cannot power off a saved machine"));
1435 else
1436 return setError(E_FAIL, tr ("Cannot power off the machine as it is not running or paused. (Machine state: %d)"), mMachineState);
1437 }
1438
1439 LogFlowThisFunc (("Sending SHUTDOWN request...\n"));
1440
1441 HRESULT rc = powerDown();
1442
1443 LogFlowThisFunc (("mMachineState=%d, rc=%08X\n", mMachineState, rc));
1444 LogFlowThisFuncLeave();
1445 return rc;
1446}
1447
1448STDMETHODIMP Console::Reset()
1449{
1450 LogFlowThisFuncEnter();
1451 LogFlowThisFunc (("mMachineState=%d\n", mMachineState));
1452
1453 AutoCaller autoCaller (this);
1454 CheckComRCReturnRC (autoCaller.rc());
1455
1456 AutoLock alock (this);
1457
1458 if (mMachineState != MachineState_Running)
1459 return setError(E_FAIL, tr ("Cannot reset the machine as it is not running. (Machine state: %d)"), mMachineState);
1460
1461 /* protect mpVM */
1462 AutoVMCaller autoVMCaller (this);
1463 CheckComRCReturnRC (autoVMCaller.rc());
1464
1465 /* leave the lock before a VMR3* call (EMT will call us back)! */
1466 alock.leave();
1467
1468 int vrc = VMR3Reset (mpVM);
1469
1470 HRESULT rc = VBOX_SUCCESS (vrc) ? S_OK :
1471 setError (E_FAIL, tr ("Could not reset the machine. (Error: %Vrc)"), vrc);
1472
1473 LogFlowThisFunc (("mMachineState=%d, rc=%08X\n", mMachineState, rc));
1474 LogFlowThisFuncLeave();
1475 return rc;
1476}
1477
1478STDMETHODIMP Console::Pause()
1479{
1480 LogFlowThisFuncEnter();
1481
1482 AutoCaller autoCaller (this);
1483 CheckComRCReturnRC (autoCaller.rc());
1484
1485 AutoLock alock (this);
1486
1487 if (mMachineState != MachineState_Running)
1488 return setError (E_FAIL, tr ("Cannot pause the machine as it is not running. (Machine state: %d)"), mMachineState);
1489
1490 /* protect mpVM */
1491 AutoVMCaller autoVMCaller (this);
1492 CheckComRCReturnRC (autoVMCaller.rc());
1493
1494 LogFlowThisFunc (("Sending PAUSE request...\n"));
1495
1496 /* leave the lock before a VMR3* call (EMT will call us back)! */
1497 alock.leave();
1498
1499 int vrc = VMR3Suspend (mpVM);
1500
1501 HRESULT rc = VBOX_SUCCESS (vrc) ? S_OK :
1502 setError (E_FAIL,
1503 tr ("Could not suspend the machine execution. (Error: %Vrc)"), vrc);
1504
1505 LogFlowThisFunc (("rc=%08X\n", rc));
1506 LogFlowThisFuncLeave();
1507 return rc;
1508}
1509
1510STDMETHODIMP Console::Resume()
1511{
1512 LogFlowThisFuncEnter();
1513
1514 AutoCaller autoCaller (this);
1515 CheckComRCReturnRC (autoCaller.rc());
1516
1517 AutoLock alock (this);
1518
1519 if (mMachineState != MachineState_Paused)
1520 return setError (E_FAIL, tr ("Cannot resume the machine as it is not paused. (Machine state: %d)"), mMachineState);
1521
1522 /* protect mpVM */
1523 AutoVMCaller autoVMCaller (this);
1524 CheckComRCReturnRC (autoVMCaller.rc());
1525
1526 LogFlowThisFunc (("Sending RESUME request...\n"));
1527
1528 /* leave the lock before a VMR3* call (EMT will call us back)! */
1529 alock.leave();
1530
1531 int vrc = VMR3Resume (mpVM);
1532
1533 HRESULT rc = VBOX_SUCCESS (vrc) ? S_OK :
1534 setError (E_FAIL,
1535 tr ("Could not resume the machine execution. (Error: %Vrc)"), vrc);
1536
1537 LogFlowThisFunc (("rc=%08X\n", rc));
1538 LogFlowThisFuncLeave();
1539 return rc;
1540}
1541
1542STDMETHODIMP Console::PowerButton()
1543{
1544 LogFlowThisFuncEnter();
1545
1546 AutoCaller autoCaller (this);
1547 CheckComRCReturnRC (autoCaller.rc());
1548
1549 AutoLock lock (this);
1550
1551 if (mMachineState != MachineState_Running)
1552 return setError (E_FAIL, tr ("Cannot power off the machine as it is not running. (Machine state: %d)"), mMachineState);
1553
1554 /* protect mpVM */
1555 AutoVMCaller autoVMCaller (this);
1556 CheckComRCReturnRC (autoVMCaller.rc());
1557
1558 PPDMIBASE pBase;
1559 int vrc = PDMR3QueryDeviceLun (mpVM, "acpi", 0, 0, &pBase);
1560 if (VBOX_SUCCESS (vrc))
1561 {
1562 Assert (pBase);
1563 PPDMIACPIPORT pPort =
1564 (PPDMIACPIPORT) pBase->pfnQueryInterface(pBase, PDMINTERFACE_ACPI_PORT);
1565 vrc = pPort ? pPort->pfnPowerButtonPress(pPort) : VERR_INVALID_POINTER;
1566 }
1567
1568 HRESULT rc = VBOX_SUCCESS (vrc) ? S_OK :
1569 setError (E_FAIL,
1570 tr ("Controlled power off failed. (Error: %Vrc)"), vrc);
1571
1572 LogFlowThisFunc (("rc=%08X\n", rc));
1573 LogFlowThisFuncLeave();
1574 return rc;
1575}
1576
1577STDMETHODIMP Console::SaveState (IProgress **aProgress)
1578{
1579 LogFlowThisFuncEnter();
1580 LogFlowThisFunc (("mMachineState=%d\n", mMachineState));
1581
1582 if (!aProgress)
1583 return E_POINTER;
1584
1585 AutoCaller autoCaller (this);
1586 CheckComRCReturnRC (autoCaller.rc());
1587
1588 AutoLock alock (this);
1589
1590 if (mMachineState != MachineState_Running &&
1591 mMachineState != MachineState_Paused)
1592 {
1593 return setError (E_FAIL,
1594 tr ("Cannot save the machine state as the machine is not running or paused. (Machine state: %d)"), mMachineState);
1595 }
1596
1597 /* memorize the current machine state */
1598 MachineState_T lastMachineState = mMachineState;
1599
1600 if (mMachineState == MachineState_Running)
1601 {
1602 HRESULT rc = Pause();
1603 CheckComRCReturnRC (rc);
1604 }
1605
1606 HRESULT rc = S_OK;
1607
1608 /* create a progress object to track operation completion */
1609 ComObjPtr <Progress> progress;
1610 progress.createObject();
1611 progress->init ((IConsole *) this,
1612 Bstr (tr ("Saving the execution state of the virtual machine")),
1613 FALSE /* aCancelable */);
1614
1615 bool beganSavingState = false;
1616 bool taskCreationFailed = false;
1617
1618 do
1619 {
1620 /* create a task object early to ensure mpVM protection is successful */
1621 std::auto_ptr <VMSaveTask> task (new VMSaveTask (this, progress));
1622 rc = task->rc();
1623 /*
1624 * If we fail here it means a PowerDown() call happened on another
1625 * thread while we were doing Pause() (which leaves the Console lock).
1626 * We assign PowerDown() a higher precendence than SaveState(),
1627 * therefore just return the error to the caller.
1628 */
1629 if (FAILED (rc))
1630 {
1631 taskCreationFailed = true;
1632 break;
1633 }
1634
1635 Bstr stateFilePath;
1636
1637 /*
1638 * request a saved state file path from the server
1639 * (this will set the machine state to Saving on the server to block
1640 * others from accessing this machine)
1641 */
1642 rc = mControl->BeginSavingState (progress, stateFilePath.asOutParam());
1643 CheckComRCBreakRC (rc);
1644
1645 beganSavingState = true;
1646
1647 /* sync the state with the server */
1648 setMachineStateLocally (MachineState_Saving);
1649
1650 /* ensure the directory for the saved state file exists */
1651 {
1652 Utf8Str dir = stateFilePath;
1653 RTPathStripFilename (dir.mutableRaw());
1654 if (!RTDirExists (dir))
1655 {
1656 int vrc = RTDirCreateFullPath (dir, 0777);
1657 if (VBOX_FAILURE (vrc))
1658 {
1659 rc = setError (E_FAIL,
1660 tr ("Could not create a directory '%s' to save the state to. (Error: %Vrc)"),
1661 dir.raw(), vrc);
1662 break;
1663 }
1664 }
1665 }
1666
1667 /* setup task object and thread to carry out the operation asynchronously */
1668 task->mIsSnapshot = false;
1669 task->mSavedStateFile = stateFilePath;
1670 /* set the state the operation thread will restore when it is finished */
1671 task->mLastMachineState = lastMachineState;
1672
1673 /* create a thread to wait until the VM state is saved */
1674 int vrc = RTThreadCreate (NULL, Console::saveStateThread, (void *) task.get(),
1675 0, RTTHREADTYPE_MAIN_WORKER, 0, "VMSave");
1676
1677 ComAssertMsgRCBreak (vrc, ("Could not create VMSave thread (%Vrc)\n", vrc),
1678 rc = E_FAIL);
1679
1680 /* task is now owned by saveStateThread(), so release it */
1681 task.release();
1682
1683 /* return the progress to the caller */
1684 progress.queryInterfaceTo (aProgress);
1685 }
1686 while (0);
1687
1688 if (FAILED (rc) && !taskCreationFailed)
1689 {
1690 /* fetch any existing error info */
1691 ErrorInfo ei;
1692
1693 if (beganSavingState)
1694 {
1695 /*
1696 * cancel the requested save state procedure.
1697 * This will reset the machine state to the state it had right
1698 * before calling mControl->BeginSavingState().
1699 */
1700 mControl->EndSavingState (FALSE);
1701 }
1702
1703 if (lastMachineState == MachineState_Running)
1704 {
1705 /* restore the paused state if appropriate */
1706 setMachineStateLocally (MachineState_Paused);
1707 /* restore the running state if appropriate */
1708 Resume();
1709 }
1710 else
1711 setMachineStateLocally (lastMachineState);
1712
1713 /* restore fetched error info */
1714 setError (ei);
1715 }
1716
1717 LogFlowThisFunc (("rc=%08X\n", rc));
1718 LogFlowThisFuncLeave();
1719 return rc;
1720}
1721
1722STDMETHODIMP Console::DiscardSavedState()
1723{
1724 AutoCaller autoCaller (this);
1725 CheckComRCReturnRC (autoCaller.rc());
1726
1727 AutoLock alock (this);
1728
1729 if (mMachineState != MachineState_Saved)
1730 return setError (E_FAIL,
1731 tr ("Cannot discard the machine state as the machine is not in the saved state. (Machine state: %d"), mMachineState);
1732
1733 /*
1734 * Saved -> PoweredOff transition will be detected in the SessionMachine
1735 * and properly handled.
1736 */
1737 setMachineState (MachineState_PoweredOff);
1738
1739 return S_OK;
1740}
1741
1742/** read the value of a LEd. */
1743inline uint32_t readAndClearLed(PPDMLED pLed)
1744{
1745 if (!pLed)
1746 return 0;
1747 uint32_t u32 = pLed->Actual.u32 | pLed->Asserted.u32;
1748 pLed->Asserted.u32 = 0;
1749 return u32;
1750}
1751
1752STDMETHODIMP Console::GetDeviceActivity (DeviceType_T aDeviceType,
1753 DeviceActivity_T *aDeviceActivity)
1754{
1755 if (!aDeviceActivity)
1756 return E_INVALIDARG;
1757
1758 AutoCaller autoCaller (this);
1759 CheckComRCReturnRC (autoCaller.rc());
1760
1761 /*
1762 * Note: we don't lock the console object here because
1763 * readAndClearLed() should be thread safe.
1764 */
1765
1766 /* Get LED array to read */
1767 PDMLEDCORE SumLed = {0};
1768 switch (aDeviceType)
1769 {
1770 case DeviceType_FloppyDevice:
1771 {
1772 for (unsigned i = 0; i < ELEMENTS(mapFDLeds); i++)
1773 SumLed.u32 |= readAndClearLed(mapFDLeds[i]);
1774 break;
1775 }
1776
1777 case DeviceType_DVDDevice:
1778 SumLed.u32 |= readAndClearLed(mapIDELeds[2]);
1779 break;
1780
1781 case DeviceType_HardDiskDevice:
1782 SumLed.u32 |= readAndClearLed(mapIDELeds[0]);
1783 SumLed.u32 |= readAndClearLed(mapIDELeds[1]);
1784 SumLed.u32 |= readAndClearLed(mapIDELeds[3]);
1785 break;
1786
1787 case DeviceType_NetworkDevice:
1788 {
1789 for (unsigned i = 0; i < ELEMENTS(mapNetworkLeds); i++)
1790 SumLed.u32 |= readAndClearLed(mapNetworkLeds[i]);
1791 break;
1792 }
1793
1794 default:
1795 return setError (E_INVALIDARG,
1796 tr ("Invalid device type: %d"), aDeviceType);
1797 }
1798
1799 /* Compose the result */
1800 switch (SumLed.u32 & (PDMLED_READING | PDMLED_WRITING))
1801 {
1802 case 0:
1803 *aDeviceActivity = DeviceActivity_DeviceIdle;
1804 break;
1805 case PDMLED_READING:
1806 *aDeviceActivity = DeviceActivity_DeviceReading;
1807 break;
1808 case PDMLED_WRITING:
1809 case PDMLED_READING | PDMLED_WRITING:
1810 *aDeviceActivity = DeviceActivity_DeviceWriting;
1811 break;
1812 }
1813
1814 return S_OK;
1815}
1816
1817STDMETHODIMP Console::AttachUSBDevice (INPTR GUIDPARAM aId)
1818{
1819 AutoCaller autoCaller (this);
1820 CheckComRCReturnRC (autoCaller.rc());
1821
1822 AutoLock alock (this);
1823
1824 /// @todo (r=dmik) is it legal to attach USB devices when the machine is
1825 // Paused, Starting, Saving, Stopping, etc? if not, we should make a
1826 // stricter check (mMachineState != MachineState_Running).
1827 if (mMachineState < MachineState_Running)
1828 return setError (E_FAIL, tr ("Cannot attach a USB device to a machine which is not running. (Machine state: %d)"), mMachineState);
1829
1830 /* protect mpVM */
1831 AutoVMCaller autoVMCaller (this);
1832 CheckComRCReturnRC (autoVMCaller.rc());
1833
1834 /* Don't proceed unless we've found the usb controller. */
1835 PPDMIBASE pBase = NULL;
1836 int vrc = PDMR3QueryLun (mpVM, "usb-ohci", 0, 0, &pBase);
1837 if (VBOX_FAILURE (vrc))
1838 return setError (E_FAIL, tr ("The virtual machine does not have a USB controller."));
1839
1840 PVUSBIRHCONFIG pRhConfig = (PVUSBIRHCONFIG) pBase->
1841 pfnQueryInterface (pBase, PDMINTERFACE_VUSB_RH_CONFIG);
1842 ComAssertRet (pRhConfig, E_FAIL);
1843
1844 /// @todo (dmik) REMOTE_USB
1845 // when remote USB devices are ready, first search for a device with the
1846 // given UUID in mRemoteUSBDevices. If found, request a capture from
1847 // a remote client. If not found, search it on the local host as done below
1848
1849 /*
1850 * Try attach the given host USB device (a proper errror message should
1851 * be returned in case of error).
1852 */
1853 ComPtr <IUSBDevice> hostDevice;
1854 HRESULT hrc = mControl->CaptureUSBDevice (aId, hostDevice.asOutParam());
1855 CheckComRCReturnRC (hrc);
1856
1857 return attachUSBDevice (hostDevice, true /* aManual */, pRhConfig);
1858}
1859
1860STDMETHODIMP Console::DetachUSBDevice (INPTR GUIDPARAM aId, IUSBDevice **aDevice)
1861{
1862 if (!aDevice)
1863 return E_POINTER;
1864
1865 AutoCaller autoCaller (this);
1866 CheckComRCReturnRC (autoCaller.rc());
1867
1868 AutoLock alock (this);
1869
1870 /* Find it. */
1871 ComObjPtr <USBDevice> device;
1872 USBDeviceList::iterator it = mUSBDevices.begin();
1873 while (it != mUSBDevices.end())
1874 {
1875 if ((*it)->id() == aId)
1876 {
1877 device = *it;
1878 break;
1879 }
1880 ++ it;
1881 }
1882
1883 if (!device)
1884 return setError (E_INVALIDARG,
1885 tr ("Cannot detach the USB device (UUID: %s) as it is not attached here."),
1886 Guid (aId).toString().raw());
1887
1888 /* protect mpVM */
1889 AutoVMCaller autoVMCaller (this);
1890 CheckComRCReturnRC (autoVMCaller.rc());
1891
1892 PPDMIBASE pBase = NULL;
1893 int vrc = PDMR3QueryLun (mpVM, "usb-ohci", 0, 0, &pBase);
1894
1895 /* if the device is attached, then there must be a USB controller */
1896 ComAssertRCRet (vrc, E_FAIL);
1897
1898 PVUSBIRHCONFIG pRhConfig = (PVUSBIRHCONFIG) pBase->
1899 pfnQueryInterface (pBase, PDMINTERFACE_VUSB_RH_CONFIG);
1900 ComAssertRet (pRhConfig, E_FAIL);
1901
1902 Guid Uuid(aId);
1903
1904 LogFlowThisFunc (("Detaching USB proxy device {%Vuuid}...\n", Uuid.raw()));
1905
1906 /* leave the lock before a VMR3* call (EMT will call us back)! */
1907 alock.leave();
1908
1909 PVMREQ pReq = NULL;
1910 vrc = VMR3ReqCall (mpVM, &pReq, RT_INDEFINITE_WAIT,
1911 (PFNRT) usbDetachCallback, 5,
1912 this, &it, true /* aManual */, pRhConfig, Uuid.raw());
1913 if (VBOX_SUCCESS (vrc))
1914 vrc = pReq->iStatus;
1915 VMR3ReqFree (pReq);
1916
1917 HRESULT hrc = S_OK;
1918
1919 if (VBOX_SUCCESS (vrc))
1920 device.queryInterfaceTo (aDevice);
1921 else
1922 hrc = setError (E_FAIL,
1923 tr ("Error detaching the USB device. (Failed to destroy the USB proxy device: %Vrc)"), vrc);
1924
1925 return hrc;
1926}
1927
1928STDMETHODIMP
1929Console::CreateSharedFolder (INPTR BSTR aName, INPTR BSTR aHostPath)
1930{
1931 if (!aName || !aHostPath)
1932 return E_INVALIDARG;
1933
1934 AutoCaller autoCaller (this);
1935 CheckComRCReturnRC (autoCaller.rc());
1936
1937 AutoLock alock (this);
1938
1939 if (mMachineState == MachineState_Saved)
1940 return setError (E_FAIL,
1941 tr ("Cannot create a transient shared folder on a "
1942 "machine in the saved state."));
1943
1944 /// @todo (dmik) check globally shared folders when they are done
1945
1946 /* check machine's shared folders */
1947 {
1948 ComPtr <ISharedFolderCollection> coll;
1949 HRESULT rc = mMachine->COMGETTER(SharedFolders) (coll.asOutParam());
1950 if (FAILED (rc))
1951 return rc;
1952
1953 ComPtr <ISharedFolder> machineSharedFolder;
1954 rc = coll->FindByName (aName, machineSharedFolder.asOutParam());
1955 if (SUCCEEDED (rc))
1956 return setError (E_FAIL,
1957 tr ("A permanent shared folder named '%ls' already "
1958 "exists."), aName);
1959 }
1960
1961 ComObjPtr <SharedFolder> sharedFolder;
1962 HRESULT rc = findSharedFolder (aName, sharedFolder, false /* aSetError */);
1963 if (SUCCEEDED (rc))
1964 return setError (E_FAIL,
1965 tr ("A shared folder named '%ls' already exists."), aName);
1966
1967 sharedFolder.createObject();
1968 rc = sharedFolder->init (this, aName, aHostPath);
1969 CheckComRCReturnRC (rc);
1970
1971 BOOL accessible = FALSE;
1972 rc = sharedFolder->COMGETTER(Accessible) (&accessible);
1973 CheckComRCReturnRC (rc);
1974
1975 if (!accessible)
1976 return setError (E_FAIL,
1977 tr ("The shared folder path '%ls' on the host is not accessible."), aHostPath);
1978
1979 /* protect mpVM */
1980 AutoVMCaller autoVMCaller (this);
1981 CheckComRCReturnRC (autoVMCaller.rc());
1982
1983 /// @todo (r=sander?) should move this into the shared folder class */
1984 if (mpVM && mVMMDev->getShFlClientId())
1985 {
1986 /*
1987 * if the VM is online and supports shared folders, share this folde
1988 * under the specified name. On error, return it to the caller.
1989 */
1990 VBOXHGCMSVCPARM parms[2];
1991 SHFLSTRING *pFolderName, *pMapName;
1992 int cbString;
1993
1994 Log(("Add shared folder %ls -> %ls\n", aName, aHostPath));
1995
1996 cbString = (RTStrUcs2Len(aHostPath) + 1) * sizeof(RTUCS2);
1997 pFolderName = (SHFLSTRING *)RTMemAllocZ(sizeof(SHFLSTRING) + cbString);
1998 Assert(pFolderName);
1999 memcpy(pFolderName->String.ucs2, aHostPath, cbString);
2000
2001 pFolderName->u16Size = cbString;
2002 pFolderName->u16Length = cbString - sizeof(RTUCS2);
2003
2004 parms[0].type = VBOX_HGCM_SVC_PARM_PTR;
2005 parms[0].u.pointer.addr = pFolderName;
2006 parms[0].u.pointer.size = sizeof(SHFLSTRING) + cbString;
2007
2008 cbString = (RTStrUcs2Len(aName) + 1) * sizeof(RTUCS2);
2009 pMapName = (SHFLSTRING *)RTMemAllocZ(sizeof(SHFLSTRING) + cbString);
2010 Assert(pMapName);
2011 memcpy(pMapName->String.ucs2, aName, cbString);
2012
2013 pMapName->u16Size = cbString;
2014 pMapName->u16Length = cbString - sizeof(RTUCS2);
2015
2016 parms[1].type = VBOX_HGCM_SVC_PARM_PTR;
2017 parms[1].u.pointer.addr = pMapName;
2018 parms[1].u.pointer.size = sizeof(SHFLSTRING) + cbString;
2019
2020 rc = mVMMDev->hgcmHostCall("VBoxSharedFolders", SHFL_FN_ADD_MAPPING, 2, &parms[0]);
2021 RTMemFree(pFolderName);
2022 RTMemFree(pMapName);
2023 if (rc != VINF_SUCCESS)
2024 return setError (E_FAIL, tr ("Unable to add mapping %ls to %ls."), aHostPath, aName);
2025 }
2026
2027 mSharedFolders.push_back (sharedFolder);
2028 return S_OK;
2029}
2030
2031STDMETHODIMP Console::RemoveSharedFolder (INPTR BSTR aName)
2032{
2033 if (!aName)
2034 return E_INVALIDARG;
2035
2036 AutoCaller autoCaller (this);
2037 CheckComRCReturnRC (autoCaller.rc());
2038
2039 AutoLock alock (this);
2040
2041 if (mMachineState == MachineState_Saved)
2042 return setError (E_FAIL,
2043 tr ("Cannot remove a transient shared folder when the "
2044 "machine is in the saved state."));
2045
2046 ComObjPtr <SharedFolder> sharedFolder;
2047 HRESULT rc = findSharedFolder (aName, sharedFolder, true /* aSetError */);
2048 CheckComRCReturnRC (rc);
2049
2050 /* protect mpVM */
2051 AutoVMCaller autoVMCaller (this);
2052 CheckComRCReturnRC (autoVMCaller.rc());
2053
2054 if (mpVM && mVMMDev->getShFlClientId())
2055 {
2056 /*
2057 * if the VM is online and supports shared folders, UNshare this folder.
2058 * On error, return it to the caller.
2059 */
2060 VBOXHGCMSVCPARM parms;
2061 SHFLSTRING *pMapName;
2062 int cbString;
2063
2064 cbString = (RTStrUcs2Len(aName) + 1) * sizeof(RTUCS2);
2065 pMapName = (SHFLSTRING *)RTMemAllocZ(sizeof(SHFLSTRING) + cbString);
2066 Assert(pMapName);
2067 memcpy(pMapName->String.ucs2, aName, cbString);
2068
2069 pMapName->u16Size = cbString;
2070 pMapName->u16Length = cbString - sizeof(RTUCS2);
2071
2072 parms.type = VBOX_HGCM_SVC_PARM_PTR;
2073 parms.u.pointer.addr = pMapName;
2074 parms.u.pointer.size = sizeof(SHFLSTRING) + cbString;
2075
2076 rc = mVMMDev->hgcmHostCall("VBoxSharedFolders", SHFL_FN_REMOVE_MAPPING, 1, &parms);
2077 RTMemFree(pMapName);
2078 if (rc != VINF_SUCCESS)
2079 rc = setError (E_FAIL, tr ("Unable to remove the mapping %ls."), aName);
2080 }
2081
2082 mSharedFolders.remove (sharedFolder);
2083 return rc;
2084}
2085
2086STDMETHODIMP Console::TakeSnapshot (INPTR BSTR aName, INPTR BSTR aDescription,
2087 IProgress **aProgress)
2088{
2089 LogFlowThisFuncEnter();
2090 LogFlowThisFunc (("aName='%ls' mMachineState=%08X\n", aName, mMachineState));
2091
2092 if (!aName)
2093 return E_INVALIDARG;
2094 if (!aProgress)
2095 return E_POINTER;
2096
2097 AutoCaller autoCaller (this);
2098 CheckComRCReturnRC (autoCaller.rc());
2099
2100 AutoLock alock (this);
2101
2102 if (mMachineState > MachineState_Running &&
2103 mMachineState != MachineState_Paused)
2104 {
2105 return setError (E_FAIL,
2106 tr ("Cannot take a snapshot of a machine while it is changing state. (Machine state: %d)"), mMachineState);
2107 }
2108
2109 /* memorize the current machine state */
2110 MachineState_T lastMachineState = mMachineState;
2111
2112 if (mMachineState == MachineState_Running)
2113 {
2114 HRESULT rc = Pause();
2115 CheckComRCReturnRC (rc);
2116 }
2117
2118 HRESULT rc = S_OK;
2119
2120 bool takingSnapshotOnline = mMachineState == MachineState_Paused;
2121
2122 /*
2123 * create a descriptionless VM-side progress object
2124 * (only when creating a snapshot online)
2125 */
2126 ComObjPtr <Progress> saveProgress;
2127 if (takingSnapshotOnline)
2128 {
2129 saveProgress.createObject();
2130 rc = saveProgress->init (FALSE, 1, Bstr (tr ("Saving the execution state")));
2131 AssertComRCReturn (rc, rc);
2132 }
2133
2134 bool beganTakingSnapshot = false;
2135 bool taskCreationFailed = false;
2136
2137 do
2138 {
2139 /* create a task object early to ensure mpVM protection is successful */
2140 std::auto_ptr <VMSaveTask> task;
2141 if (takingSnapshotOnline)
2142 {
2143 task.reset (new VMSaveTask (this, saveProgress));
2144 rc = task->rc();
2145 /*
2146 * If we fail here it means a PowerDown() call happened on another
2147 * thread while we were doing Pause() (which leaves the Console lock).
2148 * We assign PowerDown() a higher precendence than TakeSnapshot(),
2149 * therefore just return the error to the caller.
2150 */
2151 if (FAILED (rc))
2152 {
2153 taskCreationFailed = true;
2154 break;
2155 }
2156 }
2157
2158 Bstr stateFilePath;
2159 ComPtr <IProgress> serverProgress;
2160
2161 /*
2162 * request taking a new snapshot object on the server
2163 * (this will set the machine state to Saving on the server to block
2164 * others from accessing this machine)
2165 */
2166 rc = mControl->BeginTakingSnapshot (this, aName, aDescription,
2167 saveProgress, stateFilePath.asOutParam(),
2168 serverProgress.asOutParam());
2169 if (FAILED (rc))
2170 break;
2171
2172 /*
2173 * state file is non-null only when the VM is paused
2174 * (i.e. createing a snapshot online)
2175 */
2176 ComAssertBreak (
2177 (!stateFilePath.isNull() && takingSnapshotOnline) ||
2178 (stateFilePath.isNull() && !takingSnapshotOnline),
2179 rc = E_FAIL);
2180
2181 beganTakingSnapshot = true;
2182
2183 /* sync the state with the server */
2184 setMachineStateLocally (MachineState_Saving);
2185
2186 /*
2187 * create a combined VM-side progress object and start the save task
2188 * (only when creating a snapshot online)
2189 */
2190 ComObjPtr <CombinedProgress> combinedProgress;
2191 if (takingSnapshotOnline)
2192 {
2193 combinedProgress.createObject();
2194 rc = combinedProgress->init ((IConsole *) this,
2195 Bstr (tr ("Taking snapshot of virtual machine")),
2196 serverProgress, saveProgress);
2197 AssertComRCBreakRC (rc);
2198
2199 /* setup task object and thread to carry out the operation asynchronously */
2200 task->mIsSnapshot = true;
2201 task->mSavedStateFile = stateFilePath;
2202 task->mServerProgress = serverProgress;
2203 /* set the state the operation thread will restore when it is finished */
2204 task->mLastMachineState = lastMachineState;
2205
2206 /* create a thread to wait until the VM state is saved */
2207 int vrc = RTThreadCreate (NULL, Console::saveStateThread, (void *) task.get(),
2208 0, RTTHREADTYPE_MAIN_WORKER, 0, "VMTakeSnap");
2209
2210 ComAssertMsgRCBreak (vrc, ("Could not create VMTakeSnap thread (%Vrc)\n", vrc),
2211 rc = E_FAIL);
2212
2213 /* task is now owned by saveStateThread(), so release it */
2214 task.release();
2215 }
2216
2217 if (SUCCEEDED (rc))
2218 {
2219 /* return the correct progress to the caller */
2220 if (combinedProgress)
2221 combinedProgress.queryInterfaceTo (aProgress);
2222 else
2223 serverProgress.queryInterfaceTo (aProgress);
2224 }
2225 }
2226 while (0);
2227
2228 if (FAILED (rc) && !taskCreationFailed)
2229 {
2230 /* fetch any existing error info */
2231 ErrorInfo ei;
2232
2233 if (beganTakingSnapshot && takingSnapshotOnline)
2234 {
2235 /*
2236 * cancel the requested snapshot (only when creating a snapshot
2237 * online, otherwise the server will cancel the snapshot itself).
2238 * This will reset the machine state to the state it had right
2239 * before calling mControl->BeginTakingSnapshot().
2240 */
2241 mControl->EndTakingSnapshot (FALSE);
2242 }
2243
2244 if (lastMachineState == MachineState_Running)
2245 {
2246 /* restore the paused state if appropriate */
2247 setMachineStateLocally (MachineState_Paused);
2248 /* restore the running state if appropriate */
2249 Resume();
2250 }
2251 else
2252 setMachineStateLocally (lastMachineState);
2253
2254 /* restore fetched error info */
2255 setError (ei);
2256 }
2257
2258 LogFlowThisFunc (("rc=%08X\n", rc));
2259 LogFlowThisFuncLeave();
2260 return rc;
2261}
2262
2263STDMETHODIMP Console::DiscardSnapshot (INPTR GUIDPARAM aId, IProgress **aProgress)
2264{
2265 if (Guid (aId).isEmpty())
2266 return E_INVALIDARG;
2267 if (!aProgress)
2268 return E_POINTER;
2269
2270 AutoCaller autoCaller (this);
2271 CheckComRCReturnRC (autoCaller.rc());
2272
2273 AutoLock alock (this);
2274
2275 if (mMachineState >= MachineState_Running)
2276 return setError (E_FAIL,
2277 tr ("Cannot discard a snapshot on a running machine (Machine state: %d)"), mMachineState);
2278
2279 MachineState_T machineState = MachineState_InvalidMachineState;
2280 HRESULT rc = mControl->DiscardSnapshot (this, aId, &machineState, aProgress);
2281 CheckComRCReturnRC (rc);
2282
2283 setMachineStateLocally (machineState);
2284 return S_OK;
2285}
2286
2287STDMETHODIMP Console::DiscardCurrentState (IProgress **aProgress)
2288{
2289 AutoCaller autoCaller (this);
2290 CheckComRCReturnRC (autoCaller.rc());
2291
2292 AutoLock alock (this);
2293
2294 if (mMachineState >= MachineState_Running)
2295 return setError (E_FAIL,
2296 tr ("Cannot discard the current state of a running machine. (Machine state: %d)"), mMachineState);
2297
2298 MachineState_T machineState = MachineState_InvalidMachineState;
2299 HRESULT rc = mControl->DiscardCurrentState (this, &machineState, aProgress);
2300 CheckComRCReturnRC (rc);
2301
2302 setMachineStateLocally (machineState);
2303 return S_OK;
2304}
2305
2306STDMETHODIMP Console::DiscardCurrentSnapshotAndState (IProgress **aProgress)
2307{
2308 AutoCaller autoCaller (this);
2309 CheckComRCReturnRC (autoCaller.rc());
2310
2311 AutoLock alock (this);
2312
2313 if (mMachineState >= MachineState_Running)
2314 return setError (E_FAIL,
2315 tr ("Cannot discard the current snapshot and state on a running machine. (Machine state: %d)"), mMachineState);
2316
2317 MachineState_T machineState = MachineState_InvalidMachineState;
2318 HRESULT rc =
2319 mControl->DiscardCurrentSnapshotAndState (this, &machineState, aProgress);
2320 CheckComRCReturnRC (rc);
2321
2322 setMachineStateLocally (machineState);
2323 return S_OK;
2324}
2325
2326STDMETHODIMP Console::RegisterCallback (IConsoleCallback *aCallback)
2327{
2328 if (!aCallback)
2329 return E_INVALIDARG;
2330
2331 AutoCaller autoCaller (this);
2332 CheckComRCReturnRC (autoCaller.rc());
2333
2334 AutoLock alock (this);
2335
2336 mCallbacks.push_back (CallbackList::value_type (aCallback));
2337 return S_OK;
2338}
2339
2340STDMETHODIMP Console::UnregisterCallback (IConsoleCallback *aCallback)
2341{
2342 if (!aCallback)
2343 return E_INVALIDARG;
2344
2345 AutoCaller autoCaller (this);
2346 CheckComRCReturnRC (autoCaller.rc());
2347
2348 AutoLock alock (this);
2349
2350 CallbackList::iterator it;
2351 it = std::find (mCallbacks.begin(),
2352 mCallbacks.end(),
2353 CallbackList::value_type (aCallback));
2354 if (it == mCallbacks.end())
2355 return setError (E_INVALIDARG,
2356 tr ("The given callback handler is not registered"));
2357
2358 mCallbacks.erase (it);
2359 return S_OK;
2360}
2361
2362// Non-interface public methods
2363/////////////////////////////////////////////////////////////////////////////
2364
2365/**
2366 * Called by IInternalSessionControl::OnDVDDriveChange().
2367 *
2368 * @note Locks this object for reading.
2369 */
2370HRESULT Console::onDVDDriveChange()
2371{
2372 LogFlowThisFunc (("\n"));
2373
2374 AutoCaller autoCaller (this);
2375 AssertComRCReturnRC (autoCaller.rc());
2376
2377 AutoReaderLock alock (this);
2378
2379 /* Ignore callbacks when there's no VM around */
2380 if (!mpVM)
2381 return S_OK;
2382
2383 /* protect mpVM */
2384 AutoVMCaller autoVMCaller (this);
2385 CheckComRCReturnRC (autoVMCaller.rc());
2386
2387 /* Get the current DVD state */
2388 HRESULT rc;
2389 DriveState_T eState;
2390
2391 rc = mDVDDrive->COMGETTER (State) (&eState);
2392 ComAssertComRCRetRC (rc);
2393
2394 /* Paranoia */
2395 if ( eState == DriveState_NotMounted
2396 && meDVDState == DriveState_NotMounted)
2397 {
2398 LogFlowThisFunc (("Returns (NotMounted -> NotMounted)\n"));
2399 return S_OK;
2400 }
2401
2402 /* Get the path string and other relevant properties */
2403 Bstr Path;
2404 bool fPassthrough = false;
2405 switch (eState)
2406 {
2407 case DriveState_ImageMounted:
2408 {
2409 ComPtr <IDVDImage> ImagePtr;
2410 rc = mDVDDrive->GetImage (ImagePtr.asOutParam());
2411 if (SUCCEEDED (rc))
2412 rc = ImagePtr->COMGETTER(FilePath) (Path.asOutParam());
2413 break;
2414 }
2415
2416 case DriveState_HostDriveCaptured:
2417 {
2418 ComPtr <IHostDVDDrive> DrivePtr;
2419 BOOL enabled;
2420 rc = mDVDDrive->GetHostDrive (DrivePtr.asOutParam());
2421 if (SUCCEEDED (rc))
2422 rc = DrivePtr->COMGETTER (Name) (Path.asOutParam());
2423 if (SUCCEEDED (rc))
2424 rc = mDVDDrive->COMGETTER (Passthrough) (&enabled);
2425 if (SUCCEEDED (rc))
2426 fPassthrough = !!enabled;
2427 break;
2428 }
2429
2430 case DriveState_NotMounted:
2431 break;
2432
2433 default:
2434 AssertMsgFailed (("Invalid DriveState: %d\n", eState));
2435 rc = E_FAIL;
2436 break;
2437 }
2438
2439 AssertComRC (rc);
2440 if (FAILED (rc))
2441 {
2442 LogFlowThisFunc (("Returns %#x\n", rc));
2443 return rc;
2444 }
2445
2446 return doDriveChange ("piix3ide", 0, 2, eState, &meDVDState,
2447 Utf8Str (Path).raw(), fPassthrough);
2448}
2449
2450
2451/**
2452 * Called by IInternalSessionControl::OnFloppyDriveChange().
2453 *
2454 * @note Locks this object for reading.
2455 */
2456HRESULT Console::onFloppyDriveChange()
2457{
2458 LogFlowThisFunc (("\n"));
2459
2460 AutoCaller autoCaller (this);
2461 AssertComRCReturnRC (autoCaller.rc());
2462
2463 AutoReaderLock alock (this);
2464
2465 /* Ignore callbacks when there's no VM around */
2466 if (!mpVM)
2467 return S_OK;
2468
2469 /* protect mpVM */
2470 AutoVMCaller autoVMCaller (this);
2471 CheckComRCReturnRC (autoVMCaller.rc());
2472
2473 /* Get the current floppy state */
2474 HRESULT rc;
2475 DriveState_T eState;
2476
2477 /* If the floppy drive is disabled, we're not interested */
2478 BOOL fEnabled;
2479 rc = mFloppyDrive->COMGETTER (Enabled) (&fEnabled);
2480 ComAssertComRCRetRC (rc);
2481
2482 if (!fEnabled)
2483 return S_OK;
2484
2485 rc = mFloppyDrive->COMGETTER (State) (&eState);
2486 ComAssertComRCRetRC (rc);
2487
2488 Log2 (("onFloppyDriveChange: eState=%d meFloppyState=%d\n", eState, meFloppyState));
2489
2490
2491 /* Paranoia */
2492 if ( eState == DriveState_NotMounted
2493 && meFloppyState == DriveState_NotMounted)
2494 {
2495 LogFlowThisFunc (("Returns (NotMounted -> NotMounted)\n"));
2496 return S_OK;
2497 }
2498
2499 /* Get the path string and other relevant properties */
2500 Bstr Path;
2501 switch (eState)
2502 {
2503 case DriveState_ImageMounted:
2504 {
2505 ComPtr <IFloppyImage> ImagePtr;
2506 rc = mFloppyDrive->GetImage (ImagePtr.asOutParam());
2507 if (SUCCEEDED (rc))
2508 rc = ImagePtr->COMGETTER(FilePath) (Path.asOutParam());
2509 break;
2510 }
2511
2512 case DriveState_HostDriveCaptured:
2513 {
2514 ComPtr <IHostFloppyDrive> DrivePtr;
2515 rc = mFloppyDrive->GetHostDrive (DrivePtr.asOutParam());
2516 if (SUCCEEDED (rc))
2517 rc = DrivePtr->COMGETTER (Name) (Path.asOutParam());
2518 break;
2519 }
2520
2521 case DriveState_NotMounted:
2522 break;
2523
2524 default:
2525 AssertMsgFailed (("Invalid DriveState: %d\n", eState));
2526 rc = E_FAIL;
2527 break;
2528 }
2529
2530 AssertComRC (rc);
2531 if (FAILED (rc))
2532 {
2533 LogFlowThisFunc (("Returns %#x\n", rc));
2534 return rc;
2535 }
2536
2537 return doDriveChange ("i82078", 0, 0, eState, &meFloppyState,
2538 Utf8Str (Path).raw(), false);
2539}
2540
2541
2542/**
2543 * Process a floppy or dvd change.
2544 *
2545 * @returns COM status code.
2546 *
2547 * @param pszDevice The PDM device name.
2548 * @param uInstance The PDM device instance.
2549 * @param uLun The PDM LUN number of the drive.
2550 * @param eState The new state.
2551 * @param peState Pointer to the variable keeping the actual state of the drive.
2552 * This will be both read and updated to eState or other appropriate state.
2553 * @param pszPath The path to the media / drive which is now being mounted / captured.
2554 * If NULL no media or drive is attached and the lun will be configured with
2555 * the default block driver with no media. This will also be the state if
2556 * mounting / capturing the specified media / drive fails.
2557 * @param fPassthrough Enables using passthrough mode of the host DVD drive if applicable.
2558 *
2559 * @note Locks this object for reading.
2560 */
2561HRESULT Console::doDriveChange (const char *pszDevice, unsigned uInstance, unsigned uLun, DriveState_T eState,
2562 DriveState_T *peState, const char *pszPath, bool fPassthrough)
2563{
2564 LogFlowThisFunc (("pszDevice=%p:{%s} uInstance=%u uLun=%u eState=%d "
2565 "peState=%p:{%d} pszPath=%p:{%s} fPassthrough=%d\n",
2566 pszDevice, pszDevice, uInstance, uLun, eState,
2567 peState, *peState, pszPath, pszPath, fPassthrough));
2568
2569 AutoCaller autoCaller (this);
2570 AssertComRCReturnRC (autoCaller.rc());
2571
2572 AutoReaderLock alock (this);
2573
2574 /* protect mpVM */
2575 AutoVMCaller autoVMCaller (this);
2576 CheckComRCReturnRC (autoVMCaller.rc());
2577
2578 /*
2579 * Call worker in EMT, that's faster and safer than doing everything
2580 * using VM3ReqCall. Note that we separate VMR3ReqCall from VMR3ReqWait
2581 * here to make requests from under the lock in order to serialize them.
2582 */
2583 PVMREQ pReq;
2584 int vrc = VMR3ReqCall (mpVM, &pReq, 0 /* no wait! */,
2585 (PFNRT) Console::changeDrive, 8,
2586 this, pszDevice, uInstance, uLun, eState, peState,
2587 pszPath, fPassthrough);
2588 /// @todo (r=dmik) bird, it would be nice to have a special VMR3Req method
2589 // for that purpose, that doesn't return useless VERR_TIMEOUT
2590 if (vrc == VERR_TIMEOUT)
2591 vrc = VINF_SUCCESS;
2592
2593 /* leave the lock before waiting for a result (EMT will call us back!) */
2594 alock.leave();
2595
2596 if (VBOX_SUCCESS (vrc))
2597 {
2598 vrc = VMR3ReqWait (pReq, RT_INDEFINITE_WAIT);
2599 AssertRC (vrc);
2600 if (VBOX_SUCCESS (vrc))
2601 vrc = pReq->iStatus;
2602 }
2603 VMR3ReqFree (pReq);
2604
2605 if (VBOX_SUCCESS (vrc))
2606 {
2607 LogFlowThisFunc (("Returns S_OK\n"));
2608 return S_OK;
2609 }
2610
2611 if (pszPath)
2612 return setError (E_FAIL,
2613 tr ("Could not mount the media/drive '%s' (%Vrc)"), pszPath, vrc);
2614
2615 return setError (E_FAIL,
2616 tr ("Could not unmount the currently mounted media/drive (%Vrc)"), vrc);
2617}
2618
2619
2620/**
2621 * Performs the Floppy/DVD change in EMT.
2622 *
2623 * @returns VBox status code.
2624 *
2625 * @param pThis Pointer to the Console object.
2626 * @param pszDevice The PDM device name.
2627 * @param uInstance The PDM device instance.
2628 * @param uLun The PDM LUN number of the drive.
2629 * @param eState The new state.
2630 * @param peState Pointer to the variable keeping the actual state of the drive.
2631 * This will be both read and updated to eState or other appropriate state.
2632 * @param pszPath The path to the media / drive which is now being mounted / captured.
2633 * If NULL no media or drive is attached and the lun will be configured with
2634 * the default block driver with no media. This will also be the state if
2635 * mounting / capturing the specified media / drive fails.
2636 * @param fPassthrough Enables using passthrough mode of the host DVD drive if applicable.
2637 *
2638 * @thread EMT
2639 * @note Locks the Console object for writing
2640 */
2641DECLCALLBACK(int) Console::changeDrive (Console *pThis, const char *pszDevice, unsigned uInstance, unsigned uLun,
2642 DriveState_T eState, DriveState_T *peState,
2643 const char *pszPath, bool fPassthrough)
2644{
2645 LogFlowFunc (("pThis=%p pszDevice=%p:{%s} uInstance=%u uLun=%u eState=%d "
2646 "peState=%p:{%d} pszPath=%p:{%s} fPassthrough=%d\n",
2647 pThis, pszDevice, pszDevice, uInstance, uLun, eState,
2648 peState, *peState, pszPath, pszPath, fPassthrough));
2649
2650 AssertReturn (pThis, VERR_INVALID_PARAMETER);
2651
2652 AssertMsg ( (!strcmp (pszDevice, "i82078") && uLun == 0 && uInstance == 0)
2653 || (!strcmp (pszDevice, "piix3ide") && uLun == 2 && uInstance == 0),
2654 ("pszDevice=%s uLun=%d uInstance=%d\n", pszDevice, uLun, uInstance));
2655
2656 AutoCaller autoCaller (pThis);
2657 AssertComRCReturn (autoCaller.rc(), VERR_ACCESS_DENIED);
2658
2659 /*
2660 * Locking the object before doing VMR3* calls is quite safe here,
2661 * since we're on EMT. Write lock is necessary because we're indirectly
2662 * modify the meDVDState/meFloppyState members (pointed to by peState).
2663 */
2664 AutoLock alock (pThis);
2665
2666 /* protect mpVM */
2667 AutoVMCaller autoVMCaller (pThis);
2668 CheckComRCReturnRC (autoVMCaller.rc());
2669
2670 PVM pVM = pThis->mpVM;
2671
2672 /*
2673 * Suspend the VM first.
2674 *
2675 * The VM must not be running since it might have pending I/O to
2676 * the drive which is being changed.
2677 */
2678 bool fResume;
2679 VMSTATE enmVMState = VMR3GetState (pVM);
2680 switch (enmVMState)
2681 {
2682 case VMSTATE_RESETTING:
2683 case VMSTATE_RUNNING:
2684 {
2685 LogFlowFunc (("Suspending the VM...\n"));
2686 /* disable the callback to prevent Console-level state change */
2687 pThis->mVMStateChangeCallbackDisabled = true;
2688 int rc = VMR3Suspend (pVM);
2689 pThis->mVMStateChangeCallbackDisabled = false;
2690 AssertRCReturn (rc, rc);
2691 fResume = true;
2692 break;
2693 }
2694
2695 case VMSTATE_SUSPENDED:
2696 case VMSTATE_CREATED:
2697 case VMSTATE_OFF:
2698 fResume = false;
2699 break;
2700
2701 default:
2702 AssertMsgFailedReturn (("enmVMState=%d\n", enmVMState), VERR_ACCESS_DENIED);
2703 }
2704
2705 int rc = VINF_SUCCESS;
2706 int rcRet = VINF_SUCCESS;
2707
2708 do
2709 {
2710 /*
2711 * Unmount existing media / detach host drive.
2712 */
2713 PPDMIMOUNT pIMount = NULL;
2714 switch (*peState)
2715 {
2716
2717 case DriveState_ImageMounted:
2718 {
2719 /*
2720 * Resolve the interface.
2721 */
2722 PPDMIBASE pBase;
2723 rc = PDMR3QueryLun (pVM, pszDevice, uInstance, uLun, &pBase);
2724 if (VBOX_FAILURE (rc))
2725 {
2726 if (rc == VERR_PDM_LUN_NOT_FOUND)
2727 rc = VINF_SUCCESS;
2728 AssertRC (rc);
2729 break;
2730 }
2731
2732 pIMount = (PPDMIMOUNT) pBase->pfnQueryInterface (pBase, PDMINTERFACE_MOUNT);
2733 AssertBreak (pIMount, rc = VERR_INVALID_POINTER);
2734
2735 /*
2736 * Unmount the media.
2737 */
2738 rc = pIMount->pfnUnmount (pIMount);
2739 if (rc == VERR_PDM_MEDIA_NOT_MOUNTED)
2740 rc = VINF_SUCCESS;
2741 break;
2742 }
2743
2744 case DriveState_HostDriveCaptured:
2745 {
2746 rc = PDMR3DeviceDetach (pVM, pszDevice, uInstance, uLun);
2747 if (rc == VINF_PDM_NO_DRIVER_ATTACHED_TO_LUN)
2748 rc = VINF_SUCCESS;
2749 AssertRC (rc);
2750 break;
2751 }
2752
2753 case DriveState_NotMounted:
2754 break;
2755
2756 default:
2757 AssertMsgFailed (("Invalid *peState: %d\n", peState));
2758 break;
2759 }
2760
2761 if (VBOX_FAILURE (rc))
2762 {
2763 rcRet = rc;
2764 break;
2765 }
2766
2767 /*
2768 * Nothing is currently mounted.
2769 */
2770 *peState = DriveState_NotMounted;
2771
2772
2773 /*
2774 * Process the HostDriveCaptured state first, as the fallback path
2775 * means mounting the normal block driver without media.
2776 */
2777 if (eState == DriveState_HostDriveCaptured)
2778 {
2779 /*
2780 * Detach existing driver chain (block).
2781 */
2782 int rc = PDMR3DeviceDetach (pVM, pszDevice, uInstance, uLun);
2783 if (VBOX_FAILURE (rc))
2784 {
2785 if (rc == VERR_PDM_LUN_NOT_FOUND)
2786 rc = VINF_SUCCESS;
2787 AssertReleaseRC (rc);
2788 break; /* we're toast */
2789 }
2790 pIMount = NULL;
2791
2792 /*
2793 * Construct a new driver configuration.
2794 */
2795 PCFGMNODE pInst = CFGMR3GetChildF (CFGMR3GetRoot (pVM), "Devices/%s/%d/", pszDevice, uInstance);
2796 AssertRelease (pInst);
2797 /* nuke anything which might have been left behind. */
2798 CFGMR3RemoveNode (CFGMR3GetChildF (pInst, "LUN#%d", uLun));
2799
2800 /* create a new block driver config */
2801 PCFGMNODE pLunL0;
2802 PCFGMNODE pCfg;
2803 if ( VBOX_SUCCESS (rc = CFGMR3InsertNodeF (pInst, &pLunL0, "LUN#%u", uLun))
2804 && VBOX_SUCCESS (rc = CFGMR3InsertString (pLunL0, "Driver", !strcmp (pszDevice, "i82078") ? "HostFloppy" : "HostDVD"))
2805 && VBOX_SUCCESS (rc = CFGMR3InsertNode (pLunL0, "Config", &pCfg))
2806 && VBOX_SUCCESS (rc = CFGMR3InsertString (pCfg, "Path", pszPath))
2807 && VBOX_SUCCESS (rc = !strcmp (pszDevice, "i82078") ? VINF_SUCCESS : CFGMR3InsertInteger(pCfg, "Passthrough", fPassthrough)))
2808 {
2809 /*
2810 * Attempt to attach the driver.
2811 */
2812 rc = PDMR3DeviceAttach (pVM, pszDevice, uInstance, uLun, NULL);
2813 AssertRC (rc);
2814 }
2815 if (VBOX_FAILURE (rc))
2816 rcRet = rc;
2817 }
2818
2819 /*
2820 * Process the ImageMounted, NotMounted and failed HostDriveCapture cases.
2821 */
2822 rc = VINF_SUCCESS;
2823 switch (eState)
2824 {
2825#define RC_CHECK() do { if (VBOX_FAILURE (rc)) { AssertReleaseRC (rc); break; } } while (0)
2826
2827 case DriveState_HostDriveCaptured:
2828 if (VBOX_SUCCESS (rcRet))
2829 break;
2830 /* fallback: umounted block driver. */
2831 pszPath = NULL;
2832 eState = DriveState_NotMounted;
2833 /* fallthru */
2834 case DriveState_ImageMounted:
2835 case DriveState_NotMounted:
2836 {
2837 /*
2838 * Resolve the drive interface / create the driver.
2839 */
2840 if (!pIMount)
2841 {
2842 PPDMIBASE pBase;
2843 rc = PDMR3QueryLun (pVM, pszDevice, uInstance, uLun, &pBase);
2844 if (rc == VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN)
2845 {
2846 /*
2847 * We have to create it, so we'll do the full config setup and everything.
2848 */
2849 PCFGMNODE pIdeInst = CFGMR3GetChildF (CFGMR3GetRoot (pVM), "Devices/%s/%d/", pszDevice, uInstance);
2850 AssertRelease (pIdeInst);
2851
2852 /* nuke anything which might have been left behind. */
2853 CFGMR3RemoveNode (CFGMR3GetChildF (pIdeInst, "LUN#%d", uLun));
2854
2855 /* create a new block driver config */
2856 PCFGMNODE pLunL0;
2857 rc = CFGMR3InsertNodeF (pIdeInst, &pLunL0, "LUN#%d", uLun); RC_CHECK();
2858 rc = CFGMR3InsertString (pLunL0, "Driver", "Block"); RC_CHECK();
2859 PCFGMNODE pCfg;
2860 rc = CFGMR3InsertNode (pLunL0, "Config", &pCfg); RC_CHECK();
2861 rc = CFGMR3InsertString (pCfg, "Type", !strcmp (pszDevice, "i82078") ? "Floppy 1.44" : "DVD");
2862 RC_CHECK();
2863 rc = CFGMR3InsertInteger (pCfg, "Mountable", 1); RC_CHECK();
2864
2865 /*
2866 * Attach the driver.
2867 */
2868 rc = PDMR3DeviceAttach (pVM, pszDevice, uInstance, uLun, &pBase);
2869 RC_CHECK();
2870 }
2871 else if (VBOX_FAILURE(rc))
2872 {
2873 AssertRC (rc);
2874 return rc;
2875 }
2876
2877 pIMount = (PPDMIMOUNT) pBase->pfnQueryInterface (pBase, PDMINTERFACE_MOUNT);
2878 if (!pIMount)
2879 {
2880 AssertFailed();
2881 return rc;
2882 }
2883 }
2884
2885 /*
2886 * If we've got an image, let's mount it.
2887 */
2888 if (pszPath && *pszPath)
2889 {
2890 rc = pIMount->pfnMount (pIMount, pszPath, strcmp (pszDevice, "i82078") ? "MediaISO" : "RawImage");
2891 if (VBOX_FAILURE (rc))
2892 eState = DriveState_NotMounted;
2893 }
2894 break;
2895 }
2896
2897 default:
2898 AssertMsgFailed (("Invalid eState: %d\n", eState));
2899 break;
2900
2901#undef RC_CHECK
2902 }
2903
2904 if (VBOX_FAILURE (rc) && VBOX_SUCCESS (rcRet))
2905 rcRet = rc;
2906
2907 *peState = eState;
2908 }
2909 while (0);
2910
2911 /*
2912 * Resume the VM if necessary.
2913 */
2914 if (fResume)
2915 {
2916 LogFlowFunc (("Resuming the VM...\n"));
2917 /* disable the callback to prevent Console-level state change */
2918 pThis->mVMStateChangeCallbackDisabled = true;
2919 rc = VMR3Resume (pVM);
2920 pThis->mVMStateChangeCallbackDisabled = false;
2921 AssertRC (rc);
2922 if (VBOX_FAILURE (rc))
2923 {
2924 /* too bad, we failed. try to sync the console state with the VMM state */
2925 vmstateChangeCallback (pVM, VMSTATE_SUSPENDED, enmVMState, pThis);
2926 }
2927 /// @todo (r=dmik) if we failed with drive mount, then the VMR3Resume
2928 // error (if any) will be hidden from the caller. For proper reporting
2929 // of such multiple errors to the caller we need to enhance the
2930 // IVurtualBoxError interface. For now, give the first error the higher
2931 // priority.
2932 if (VBOX_SUCCESS (rcRet))
2933 rcRet = rc;
2934 }
2935
2936 LogFlowFunc (("Returning %Vrc\n", rcRet));
2937 return rcRet;
2938}
2939
2940
2941/**
2942 * Called by IInternalSessionControl::OnNetworkAdapterChange().
2943 *
2944 * @note Locks this object for writing.
2945 */
2946HRESULT Console::onNetworkAdapterChange(INetworkAdapter *networkAdapter)
2947{
2948 LogFlowThisFunc (("\n"));
2949
2950 AutoCaller autoCaller (this);
2951 AssertComRCReturnRC (autoCaller.rc());
2952
2953 AutoLock alock (this);
2954
2955 /* Don't do anything if the VM isn't running */
2956 if (!mpVM)
2957 return S_OK;
2958
2959 /* protect mpVM */
2960 AutoVMCaller autoVMCaller (this);
2961 CheckComRCReturnRC (autoVMCaller.rc());
2962
2963 /* Get the properties we need from the adapter */
2964 BOOL fCableConnected;
2965 HRESULT rc = networkAdapter->COMGETTER(CableConnected)(&fCableConnected);
2966 AssertComRC(rc);
2967 if (SUCCEEDED(rc))
2968 {
2969 ULONG ulInstance;
2970 rc = networkAdapter->COMGETTER(Slot)(&ulInstance);
2971 AssertComRC(rc);
2972 if (SUCCEEDED(rc))
2973 {
2974 /*
2975 * Find the pcnet instance, get the config interface and update the link state.
2976 */
2977 PPDMIBASE pBase;
2978 int rcVBox = PDMR3QueryDeviceLun(mpVM, "pcnet", (unsigned)ulInstance, 0, &pBase);
2979 ComAssertRC(rcVBox);
2980 if (VBOX_SUCCESS(rcVBox))
2981 {
2982 Assert(pBase);
2983 PPDMINETWORKCONFIG pINetCfg = (PPDMINETWORKCONFIG)pBase->pfnQueryInterface(pBase, PDMINTERFACE_NETWORK_CONFIG);
2984 if (pINetCfg)
2985 {
2986 Log(("Console::onNetworkAdapterChange: setting link state to %d\n", fCableConnected));
2987 rcVBox = pINetCfg->pfnSetLinkState(pINetCfg, fCableConnected ? PDMNETWORKLINKSTATE_UP : PDMNETWORKLINKSTATE_DOWN);
2988 ComAssertRC(rcVBox);
2989 }
2990 }
2991 }
2992 }
2993
2994 LogFlowThisFunc (("Leaving rc=%#x\n", rc));
2995 return rc;
2996}
2997
2998/**
2999 * Called by IInternalSessionControl::OnVRDPServerChange().
3000 *
3001 * @note Locks this object for writing.
3002 */
3003HRESULT Console::onVRDPServerChange()
3004{
3005 AutoCaller autoCaller (this);
3006 AssertComRCReturnRC (autoCaller.rc());
3007
3008 AutoLock alock (this);
3009
3010 HRESULT rc = S_OK;
3011
3012 if (mVRDPServer && mMachineState == MachineState_Running)
3013 {
3014 BOOL vrdpEnabled = FALSE;
3015
3016 rc = mVRDPServer->COMGETTER(Enabled) (&vrdpEnabled);
3017 ComAssertComRCRetRC (rc);
3018
3019 if (vrdpEnabled)
3020 {
3021 // If there was no VRDP server started the 'stop' will do nothing.
3022 // However if a server was started and this notification was called,
3023 // we have to restart the server.
3024 mConsoleVRDPServer->Stop ();
3025
3026 if (VBOX_FAILURE(mConsoleVRDPServer->Launch ()))
3027 {
3028 rc = E_FAIL;
3029 }
3030 else
3031 {
3032 mConsoleVRDPServer->SetCallback ();
3033 }
3034 }
3035 else
3036 {
3037 mConsoleVRDPServer->Stop ();
3038 }
3039 }
3040
3041 return rc;
3042}
3043
3044/**
3045 * Called by IInternalSessionControl::OnUSBControllerChange().
3046 *
3047 * @note Locks this object for writing.
3048 */
3049HRESULT Console::onUSBControllerChange()
3050{
3051 LogFlowThisFunc (("\n"));
3052
3053 AutoCaller autoCaller (this);
3054 AssertComRCReturnRC (autoCaller.rc());
3055
3056 AutoLock alock (this);
3057
3058 /* Ignore if no VM is running yet. */
3059 if (!mpVM)
3060 return S_OK;
3061
3062/// @todo (dmik)
3063// check for the Enabled state and disable virtual USB controller??
3064// Anyway, if we want to query the machine's USB Controller we need to cache
3065// it to to mUSBController in #init() (as it is done with mDVDDrive).
3066//
3067// bird: While the VM supports hot-plugging, I doubt any guest can handle it at this time... :-)
3068//
3069// /* protect mpVM */
3070// AutoVMCaller autoVMCaller (this);
3071// CheckComRCReturnRC (autoVMCaller.rc());
3072
3073 return S_OK;
3074}
3075
3076/**
3077 * Called by IInternalSessionControl::OnUSBDeviceAttach() or locally by
3078 * processRemoteUSBDevices() after IInternalMachineControl::RunUSBDeviceFilters()
3079 * returns TRUE for a given remote USB device.
3080 *
3081 * @return S_OK if the device was attached to the VM.
3082 * @return failure if not attached.
3083 *
3084 * @param aDevice
3085 * The device in question.
3086 *
3087 * @note Locks this object for writing.
3088 */
3089HRESULT Console::onUSBDeviceAttach (IUSBDevice *aDevice)
3090{
3091 LogFlowThisFunc (("aDevice=%p\n", aDevice));
3092
3093 AutoCaller autoCaller (this);
3094 ComAssertComRCRetRC (autoCaller.rc());
3095
3096 AutoLock alock (this);
3097
3098 /* VM might have been stopped when this message arrives */
3099 if (mMachineState < MachineState_Running)
3100 {
3101 LogFlowThisFunc (("Attach request ignored (mMachineState=%d).\n",
3102 mMachineState));
3103 return E_FAIL;
3104 }
3105
3106 /* protect mpVM */
3107 AutoVMCaller autoVMCaller (this);
3108 CheckComRCReturnRC (autoVMCaller.rc());
3109
3110 /* Don't proceed unless we've found the usb controller. */
3111 PPDMIBASE pBase = NULL;
3112 int vrc = PDMR3QueryLun (mpVM, "usb-ohci", 0, 0, &pBase);
3113 if (VBOX_FAILURE (vrc))
3114 {
3115 LogFlowThisFunc (("Attach request ignored (no USB controller).\n"));
3116 return E_FAIL;
3117 }
3118
3119 PVUSBIRHCONFIG pRhConfig = (PVUSBIRHCONFIG) pBase->
3120 pfnQueryInterface (pBase, PDMINTERFACE_VUSB_RH_CONFIG);
3121 ComAssertRet (pRhConfig, E_FAIL);
3122
3123 return attachUSBDevice (aDevice, false /* aManual */, pRhConfig);
3124}
3125
3126/**
3127 * Called by IInternalSessionControl::OnUSBDeviceDetach() and locally by
3128 * processRemoteUSBDevices().
3129 *
3130 * @note Locks this object for writing.
3131 */
3132HRESULT Console::onUSBDeviceDetach (INPTR GUIDPARAM aId)
3133{
3134 Guid Uuid (aId);
3135 LogFlowThisFunc (("aId={%Vuuid}\n", Uuid.raw()));
3136
3137 AutoCaller autoCaller (this);
3138 AssertComRCReturnRC (autoCaller.rc());
3139
3140 AutoLock alock (this);
3141
3142 /* Find the device. */
3143 ComObjPtr <USBDevice> device;
3144 USBDeviceList::iterator it = mUSBDevices.begin();
3145 while (it != mUSBDevices.end())
3146 {
3147 LogFlowThisFunc (("it={%Vuuid}\n", (*it)->id().raw()));
3148 if ((*it)->id() == Uuid)
3149 {
3150 device = *it;
3151 break;
3152 }
3153 ++ it;
3154 }
3155
3156 /* VM might have been stopped when this message arrives */
3157 if (device.isNull())
3158 {
3159 LogFlowThisFunc (("Device not found.\n"));
3160 if (mMachineState < MachineState_Running)
3161 {
3162 LogFlowThisFunc (("Detach request ignored (mMachineState=%d).\n",
3163 mMachineState));
3164 return E_FAIL;
3165 }
3166 /* the device must be in the list */
3167 AssertFailedReturn (E_FAIL);
3168 }
3169
3170 /* protect mpVM */
3171 AutoVMCaller autoVMCaller (this);
3172 CheckComRCReturnRC (autoVMCaller.rc());
3173
3174 PPDMIBASE pBase = NULL;
3175 int vrc = PDMR3QueryLun (mpVM, "usb-ohci", 0, 0, &pBase);
3176
3177 /* if the device is attached, then there must be a USB controller */
3178 AssertRCReturn (vrc, E_FAIL);
3179
3180 PVUSBIRHCONFIG pRhConfig = (PVUSBIRHCONFIG) pBase->
3181 pfnQueryInterface (pBase, PDMINTERFACE_VUSB_RH_CONFIG);
3182 AssertReturn (pRhConfig, E_FAIL);
3183
3184 LogFlowThisFunc (("Detaching USB proxy device {%Vuuid}...\n", Uuid.raw()));
3185
3186 /* leave the lock before a VMR3* call (EMT will call us back)! */
3187 alock.leave();
3188
3189 PVMREQ pReq;
3190 vrc = VMR3ReqCall (mpVM, &pReq, RT_INDEFINITE_WAIT,
3191 (PFNRT) usbDetachCallback, 5,
3192 this, &it, false /* aManual */, pRhConfig, Uuid.raw());
3193 if (VBOX_SUCCESS (vrc))
3194 vrc = pReq->iStatus;
3195 VMR3ReqFree (pReq);
3196
3197 AssertRC (vrc);
3198
3199 return VBOX_SUCCESS (vrc) ? S_OK : E_FAIL;
3200}
3201
3202/**
3203 * Gets called by Session::UpdateMachineState()
3204 * (IInternalSessionControl::updateMachineState()).
3205 *
3206 * Must be called only in certain cases (see the implementation).
3207 *
3208 * @note Locks this object for writing.
3209 */
3210HRESULT Console::updateMachineState (MachineState_T aMachineState)
3211{
3212 AutoCaller autoCaller (this);
3213 AssertComRCReturnRC (autoCaller.rc());
3214
3215 AutoLock alock (this);
3216
3217 AssertReturn (mMachineState == MachineState_Saving ||
3218 mMachineState == MachineState_Discarding,
3219 E_FAIL);
3220
3221 return setMachineStateLocally (aMachineState);
3222}
3223
3224/**
3225 * @note Locks this object for reading.
3226 */
3227void Console::onMousePointerShapeChange(bool fVisible, bool fAlpha,
3228 uint32_t xHot, uint32_t yHot,
3229 uint32_t width, uint32_t height,
3230 void *pShape)
3231{
3232 LogFlowThisFunc (("fVisible=%d, fAlpha=%d, xHot = %d, yHot = %d, width=%d, "
3233 "height=%d, shape=%p\n",
3234 fVisible, fAlpha, xHot, yHot, width, height, pShape));
3235
3236 AutoReaderLock alock (this);
3237
3238 CallbackList::iterator it = mCallbacks.begin();
3239 while (it != mCallbacks.end())
3240 (*it++)->OnMousePointerShapeChange(fVisible, fAlpha, xHot, yHot, width, height, (ULONG)pShape);
3241}
3242
3243/**
3244 * @note Locks this object for reading.
3245 */
3246void Console::onMouseCapabilityChange (BOOL supportsAbsolute, BOOL needsHostCursor)
3247{
3248 LogFlowThisFunc (("supportsAbsolute=%d needsHostCursor=%d\n",
3249 supportsAbsolute, needsHostCursor));
3250
3251 AutoCaller autoCaller (this);
3252 AssertComRCReturnVoid (autoCaller.rc());
3253
3254 AutoReaderLock alock (this);
3255
3256 CallbackList::iterator it = mCallbacks.begin();
3257 while (it != mCallbacks.end())
3258 {
3259 Log2(("Console::onMouseCapabilityChange: calling %p\n", (void*)*it));
3260 (*it++)->OnMouseCapabilityChange (supportsAbsolute, needsHostCursor);
3261 }
3262}
3263
3264/**
3265 * @note Locks this object for reading.
3266 */
3267void Console::onStateChange (MachineState_T machineState)
3268{
3269 AutoCaller autoCaller (this);
3270 AssertComRCReturnVoid (autoCaller.rc());
3271
3272 AutoReaderLock alock (this);
3273
3274 CallbackList::iterator it = mCallbacks.begin();
3275 while (it != mCallbacks.end())
3276 (*it++)->OnStateChange (machineState);
3277}
3278
3279/**
3280 * @note Locks this object for reading.
3281 */
3282void Console::onAdditionsStateChange()
3283{
3284 AutoCaller autoCaller (this);
3285 AssertComRCReturnVoid (autoCaller.rc());
3286
3287 AutoReaderLock alock (this);
3288
3289 CallbackList::iterator it = mCallbacks.begin();
3290 while (it != mCallbacks.end())
3291 (*it++)->OnAdditionsStateChange();
3292}
3293
3294/**
3295 * @note Locks this object for reading.
3296 */
3297void Console::onAdditionsOutdated()
3298{
3299 AutoCaller autoCaller (this);
3300 AssertComRCReturnVoid (autoCaller.rc());
3301
3302 AutoReaderLock alock (this);
3303
3304 /** @todo Use the On-Screen Display feature to report the fact.
3305 * The user should be told to install additions that are
3306 * provided with the current VBox build:
3307 * VBOX_VERSION_MAJOR.VBOX_VERSION_MINOR.VBOX_VERSION_BUILD
3308 */
3309}
3310
3311/**
3312 * @note Locks this object for reading.
3313 */
3314void Console::onKeyboardLedsChange(bool fNumLock, bool fCapsLock, bool fScrollLock)
3315{
3316 AutoCaller autoCaller (this);
3317 AssertComRCReturnVoid (autoCaller.rc());
3318
3319 AutoReaderLock alock (this);
3320
3321 CallbackList::iterator it = mCallbacks.begin();
3322 while (it != mCallbacks.end())
3323 (*it++)->OnKeyboardLedsChange(fNumLock, fCapsLock, fScrollLock);
3324}
3325
3326/**
3327 * @note Locks this object for reading.
3328 */
3329void Console::onRuntimeError (BOOL aFatal, INPTR BSTR aErrorID, INPTR BSTR aMessage)
3330{
3331 AutoCaller autoCaller (this);
3332 AssertComRCReturnVoid (autoCaller.rc());
3333
3334 AutoReaderLock alock (this);
3335
3336 CallbackList::iterator it = mCallbacks.begin();
3337 while (it != mCallbacks.end())
3338 (*it++)->OnRuntimeError (aFatal, aErrorID, aMessage);
3339}
3340
3341// private mehtods
3342////////////////////////////////////////////////////////////////////////////////
3343
3344/**
3345 * Increases the usage counter of the mpVM pointer. Guarantees that
3346 * VMR3Destroy() will not be called on it at least until releaseVMCaller()
3347 * is called.
3348 *
3349 * If this method returns a failure, the caller is not allowed to use mpVM
3350 * and may return the failed result code to the upper level. This method sets
3351 * the extended error info on failure if \a aQuiet is false.
3352 *
3353 * Setting \a aQuiet to true is useful for methods that don't want to return
3354 * the failed result code to the caller when this method fails (e.g. need to
3355 * silently check for the mpVM avaliability).
3356 *
3357 * When mpVM is NULL but \a aAllowNullVM is true, a corresponding error will be
3358 * returned instead of asserting. Having it false is intended as a sanity check
3359 * for methods that have checked mMachineState and expect mpVM *NOT* to be NULL.
3360 *
3361 * @param aQuiet true to suppress setting error info
3362 * @param aAllowNullVM true to accept mpVM being NULL and return a failure
3363 * (otherwise this method will assert if mpVM is NULL)
3364 *
3365 * @note Locks this object for writing.
3366 */
3367HRESULT Console::addVMCaller (bool aQuiet /* = false */,
3368 bool aAllowNullVM /* = false */)
3369{
3370 AutoCaller autoCaller (this);
3371 AssertComRCReturnRC (autoCaller.rc());
3372
3373 AutoLock alock (this);
3374
3375 if (mVMDestroying)
3376 {
3377 /* powerDown() is waiting for all callers to finish */
3378 return aQuiet ? E_ACCESSDENIED : setError (E_ACCESSDENIED,
3379 tr ("Virtual machine is being powered down"));
3380 }
3381
3382 if (mpVM == NULL)
3383 {
3384 Assert (aAllowNullVM == true);
3385
3386 /* The machine is not powered up */
3387 return aQuiet ? E_ACCESSDENIED : setError (E_ACCESSDENIED,
3388 tr ("Virtual machine is not powered up"));
3389 }
3390
3391 ++ mVMCallers;
3392
3393 return S_OK;
3394}
3395
3396/**
3397 * Decreases the usage counter of the mpVM pointer. Must always complete
3398 * the addVMCaller() call after the mpVM pointer is no more necessary.
3399 *
3400 * @note Locks this object for writing.
3401 */
3402void Console::releaseVMCaller()
3403{
3404 AutoCaller autoCaller (this);
3405 AssertComRCReturnVoid (autoCaller.rc());
3406
3407 AutoLock alock (this);
3408
3409 AssertReturnVoid (mpVM != NULL);
3410
3411 Assert (mVMCallers > 0);
3412 -- mVMCallers;
3413
3414 if (mVMCallers == 0 && mVMDestroying)
3415 {
3416 /* inform powerDown() there are no more callers */
3417 RTSemEventSignal (mVMZeroCallersSem);
3418 }
3419}
3420
3421/**
3422 * Internal power off worker routine.
3423 *
3424 * This method may be called only at certain places with the folliwing meaning
3425 * as shown below:
3426 *
3427 * - if the machine state is either Running or Paused, a normal
3428 * Console-initiated powerdown takes place (e.g. PowerDown());
3429 * - if the machine state is Saving, saveStateThread() has successfully
3430 * done its job;
3431 * - if the machine state is Starting or Restoring, powerUpThread() has
3432 * failed to start/load the VM;
3433 * - if the machine state is Stopping, the VM has powered itself off
3434 * (i.e. not as a result of the powerDown() call).
3435 *
3436 * Calling it in situations other than the above will cause unexpected
3437 * behavior.
3438 *
3439 * Note that this method should be the only one that destroys mpVM and sets
3440 * it to NULL.
3441 *
3442 * @note Locks this object for writing.
3443 *
3444 * @note Never call this method from a thread that called addVMCaller() or
3445 * instantiated an AutoVMCaller object; first call releaseVMCaller() or
3446 * release(). Otherwise it will deadlock.
3447 */
3448HRESULT Console::powerDown()
3449{
3450 LogFlowThisFuncEnter();
3451
3452 AutoCaller autoCaller (this);
3453 AssertComRCReturnRC (autoCaller.rc());
3454
3455 AutoLock alock (this);
3456
3457 /* sanity */
3458 AssertReturn (mVMDestroying == false, E_FAIL);
3459
3460 LogRel (("Console::powerDown(): a request to power off the VM has been issued "
3461 "(mMachineState=%d, InUninit=%d)\n",
3462 mMachineState, autoCaller.state() == InUninit));
3463
3464 /* First, wait for all mpVM callers to finish their work if necessary */
3465 if (mVMCallers > 0)
3466 {
3467 /* go to the destroying state to prevent from adding new callers */
3468 mVMDestroying = true;
3469
3470 /* lazy creation */
3471 if (mVMZeroCallersSem == NIL_RTSEMEVENT)
3472 RTSemEventCreate (&mVMZeroCallersSem);
3473
3474 LogFlowThisFunc (("Waiting for mpVM callers (%d) to drop to zero...\n",
3475 mVMCallers));
3476
3477 alock.leave();
3478
3479 RTSemEventWait (mVMZeroCallersSem, RT_INDEFINITE_WAIT);
3480
3481 alock.enter();
3482 }
3483
3484 AssertReturn (mpVM, E_FAIL);
3485
3486 AssertMsg (mMachineState == MachineState_Running ||
3487 mMachineState == MachineState_Paused ||
3488 mMachineState == MachineState_Saving ||
3489 mMachineState == MachineState_Starting ||
3490 mMachineState == MachineState_Restoring ||
3491 mMachineState == MachineState_Stopping,
3492 ("Invalid machine state: %d\n", mMachineState));
3493
3494 HRESULT rc = S_OK;
3495 int vrc = VINF_SUCCESS;
3496
3497 /*
3498 * Power off the VM if not already done that. In case of Stopping, the VM
3499 * has powered itself off and notified Console in vmstateChangeCallback().
3500 * In case of Starting or Restoring, powerUpThread() is calling us on
3501 * failure, so the VM is already off at that point.
3502 */
3503 if (mMachineState != MachineState_Stopping &&
3504 mMachineState != MachineState_Starting &&
3505 mMachineState != MachineState_Restoring)
3506 {
3507 /*
3508 * don't go from Saving to Stopping, vmstateChangeCallback needs it
3509 * to set the state to Saved on VMSTATE_TERMINATED.
3510 */
3511 if (mMachineState != MachineState_Saving)
3512 setMachineState (MachineState_Stopping);
3513
3514 LogFlowThisFunc (("Powering off the VM...\n"));
3515
3516 /* Leave the lock since EMT will call us back on VMR3PowerOff() */
3517 alock.leave();
3518
3519 vrc = VMR3PowerOff (mpVM);
3520 /*
3521 * Note that VMR3PowerOff() may fail here (invalid VMSTATE) if the
3522 * VM-(guest-)initiated power off happened in parallel a ms before
3523 * this call. So far, we let this error pop up on the user's side.
3524 */
3525
3526 alock.enter();
3527 }
3528
3529 LogFlowThisFunc (("Ready for VM destruction\n"));
3530
3531 /*
3532 * If we are called from Console::uninit(), then try to destroy the VM
3533 * even on failure (this will most likely fail too, but what to do?..)
3534 */
3535 if (VBOX_SUCCESS (vrc) || autoCaller.state() == InUninit)
3536 {
3537 /*
3538 * Stop the VRDP server and release all USB device.
3539 * (When called from uninit mConsoleVRDPServer is already destroyed.)
3540 */
3541 if (mConsoleVRDPServer)
3542 {
3543 LogFlowThisFunc (("Stopping VRDP server...\n"));
3544 mConsoleVRDPServer->Stop();
3545 }
3546
3547 releaseAllUSBDevices();
3548
3549 /*
3550 * Now we've got to destroy the VM as well. (mpVM is not valid
3551 * beyond this point). We leave the lock before calling VMR3Destroy()
3552 * because it will result into calling destructors of drivers
3553 * associated with Console children which may in turn try to lock
3554 * Console (e.g. by instantiating SafeVMPtr to access mpVM). It's safe
3555 * here because mVMDestroying is set which should prevent any activity.
3556 */
3557
3558 /*
3559 * Set mpVM to NULL early just in case if some old code is not using
3560 * addVMCaller()/releaseVMCaller().
3561 */
3562 PVM pVM = mpVM;
3563 mpVM = NULL;
3564
3565 LogFlowThisFunc (("Destroying the VM...\n"));
3566
3567 alock.leave();
3568
3569 vrc = VMR3Destroy (pVM);
3570
3571 /* take the lock again */
3572 alock.enter();
3573
3574 if (VBOX_SUCCESS (vrc))
3575 {
3576 LogFlowThisFunc (("Machine has been destroyed (mMachineState=%d)\n",
3577 mMachineState));
3578 /*
3579 * Note: the Console-level machine state change happens on the
3580 * VMSTATE_TERMINATE state change in vmstateChangeCallback(). If
3581 * powerDown() is called from EMT (i.e. from vmstateChangeCallback()
3582 * on receiving VM-initiated VMSTATE_OFF), VMSTATE_TERMINATE hasn't
3583 * occured yet. This is okay, because mMachineState is already
3584 * Stopping in this case, so any other attempt to call PowerDown()
3585 * will be rejected.
3586 */
3587 }
3588 else
3589 {
3590 /* bad bad bad, but what to do? */
3591 mpVM = pVM;
3592 rc = setError (E_FAIL,
3593 tr ("Could not destroy the machine. (Error: %Vrc)"), vrc);
3594 }
3595 }
3596 else
3597 {
3598 rc = setError (E_FAIL,
3599 tr ("Could not power off the machine. (Error: %Vrc)"), vrc);
3600 }
3601
3602 /*
3603 * Finished with destruction. Note that if something impossible happened
3604 * and we've failed to destroy the VM, mVMDestroying will remain false and
3605 * mMachineState will be something like Stopping, so most Console methods
3606 * will return an error to the caller.
3607 */
3608 if (mpVM == NULL)
3609 mVMDestroying = false;
3610
3611 LogFlowThisFuncLeave();
3612 return rc;
3613}
3614
3615/**
3616 * @note Locks this object for writing.
3617 */
3618HRESULT Console::setMachineState (MachineState_T aMachineState,
3619 bool aUpdateServer /* = true */)
3620{
3621 AutoCaller autoCaller (this);
3622 AssertComRCReturnRC (autoCaller.rc());
3623
3624 AutoLock alock (this);
3625
3626 HRESULT rc = S_OK;
3627
3628 if (mMachineState != aMachineState)
3629 {
3630 LogFlowThisFunc (("machineState=%d\n", aMachineState));
3631 mMachineState = aMachineState;
3632
3633 /// @todo (dmik)
3634 // possibly, we need to redo onStateChange() using the dedicated
3635 // Event thread, like it is done in VirtualBox. This will make it
3636 // much safer (no deadlocks possible if someone tries to use the
3637 // console from the callback), however, listeners will lose the
3638 // ability to synchronously react to state changes (is it really
3639 // necessary??)
3640 LogFlowThisFunc (("Doing onStateChange()...\n"));
3641 onStateChange (aMachineState);
3642 LogFlowThisFunc (("Done onStateChange()\n"));
3643
3644 if (aUpdateServer)
3645 {
3646 /*
3647 * Server notification MUST be done from under the lock; otherwise
3648 * the machine state here and on the server might go out of sync, that
3649 * can lead to various unexpected results (like the machine state being
3650 * >= MachineState_Running on the server, while the session state is
3651 * already SessionState_SessionClosed at the same time there).
3652 *
3653 * Cross-lock conditions should be carefully watched out: calling
3654 * UpdateState we will require Machine and SessionMachine locks
3655 * (remember that here we're holding the Console lock here, and
3656 * also all locks that have been entered by the thread before calling
3657 * this method).
3658 */
3659 LogFlowThisFunc (("Doing mControl->UpdateState()...\n"));
3660 rc = mControl->UpdateState (aMachineState);
3661 LogFlowThisFunc (("mControl->UpdateState()=%08X\n", rc));
3662 }
3663 }
3664
3665 return rc;
3666}
3667
3668/**
3669 * Searches for a shared folder with the given logical name
3670 * in the collection of shared folders.
3671 *
3672 * @param aName logical name of the shared folder
3673 * @param aSharedFolder where to return the found object
3674 * @param aSetError whether to set the error info if the folder is
3675 * not found
3676 * @return
3677 * S_OK when found or E_INVALIDARG when not found
3678 *
3679 * @note The caller must lock this object for writing.
3680 */
3681HRESULT Console::findSharedFolder (const BSTR aName,
3682 ComObjPtr <SharedFolder> &aSharedFolder,
3683 bool aSetError /* = false */)
3684{
3685 /* sanity check */
3686 AssertReturn (isLockedOnCurrentThread(), E_FAIL);
3687
3688 bool found = false;
3689 for (SharedFolderList::const_iterator it = mSharedFolders.begin();
3690 !found && it != mSharedFolders.end();
3691 ++ it)
3692 {
3693 AutoLock alock (*it);
3694 found = (*it)->name() == aName;
3695 if (found)
3696 aSharedFolder = *it;
3697 }
3698
3699 HRESULT rc = found ? S_OK : E_INVALIDARG;
3700
3701 if (aSetError && !found)
3702 setError (rc, tr ("Could not find a shared folder named '%ls'."), aName);
3703
3704 return rc;
3705}
3706
3707/**
3708 * VM state callback function. Called by the VMM
3709 * using its state machine states.
3710 *
3711 * Primarily used to handle VM initiated power off, suspend and state saving,
3712 * but also for doing termination completed work (VMSTATE_TERMINATE).
3713 *
3714 * In general this function is called in the context of the EMT.
3715 *
3716 * @param aVM The VM handle.
3717 * @param aState The new state.
3718 * @param aOldState The old state.
3719 * @param aUser The user argument (pointer to the Console object).
3720 *
3721 * @note Locks the Console object for writing.
3722 */
3723DECLCALLBACK(void)
3724Console::vmstateChangeCallback (PVM aVM, VMSTATE aState, VMSTATE aOldState,
3725 void *aUser)
3726{
3727 LogFlowFunc (("Changing state from %d to %d (aVM=%p)\n",
3728 aOldState, aState, aVM));
3729
3730 Console *that = static_cast <Console *> (aUser);
3731 AssertReturnVoid (that);
3732
3733 AutoCaller autoCaller (that);
3734 /*
3735 * Note that we must let this method proceed even if Console::uninit() has
3736 * been already called. In such case this VMSTATE change is a result of:
3737 * 1) powerDown() called from uninit() itself, or
3738 * 2) VM-(guest-)initiated power off.
3739 */
3740 AssertReturnVoid (autoCaller.isOk() ||
3741 autoCaller.state() == InUninit);
3742
3743 switch (aState)
3744 {
3745 /*
3746 * The VM has terminated
3747 */
3748 case VMSTATE_OFF:
3749 {
3750 AutoLock alock (that);
3751
3752 if (that->mVMStateChangeCallbackDisabled)
3753 break;
3754
3755 /*
3756 * Do we still think that it is running? It may happen if this is
3757 * a VM-(guest-)initiated shutdown/poweroff.
3758 */
3759 if (that->mMachineState != MachineState_Stopping &&
3760 that->mMachineState != MachineState_Saving &&
3761 that->mMachineState != MachineState_Restoring)
3762 {
3763 LogFlowFunc (("VM has powered itself off but Console still "
3764 "thinks it is running. Notifying.\n"));
3765
3766 /* prevent powerDown() from calling VMR3PowerOff() again */
3767 that->setMachineState (MachineState_Stopping);
3768
3769 /*
3770 * Setup task object and thread to carry out the operation
3771 * asynchronously (if we call powerDown() right here but there
3772 * is one or more mpVM callers (added with addVMCaller()) we'll
3773 * deadlock.
3774 */
3775 std::auto_ptr <VMTask> task (new VMTask (that, true /* aUsesVMPtr */));
3776 /*
3777 * If creating a task is falied, this can currently mean one
3778 * of two: either Console::uninit() has been called just a ms
3779 * before (so a powerDown() call is already on the way), or
3780 * powerDown() itself is being already executed. Just do
3781 * nothing .
3782 */
3783 if (!task->isOk())
3784 {
3785 LogFlowFunc (("Console is already being uninitialized.\n"));
3786 break;
3787 }
3788
3789 int vrc = RTThreadCreate (NULL, Console::powerDownThread,
3790 (void *) task.get(), 0,
3791 RTTHREADTYPE_MAIN_WORKER, 0,
3792 "VMPowerDowm");
3793
3794 AssertMsgRC (vrc, ("Could not create VMPowerUp thread (%Vrc)\n", vrc));
3795 if (VBOX_FAILURE (vrc))
3796 break;
3797
3798 /* task is now owned by powerDownThread(), so release it */
3799 task.release();
3800 }
3801 break;
3802 }
3803
3804 /*
3805 * The VM has been completely destroyed.
3806 *
3807 * Note: This state change can happen at two points:
3808 * 1) At the end of VMR3Destroy() if it was not called from EMT.
3809 * 2) At the end of vmR3EmulationThread if VMR3Destroy() was
3810 * called by EMT.
3811 */
3812 case VMSTATE_TERMINATED:
3813 {
3814 AutoLock alock (that);
3815
3816 if (that->mVMStateChangeCallbackDisabled)
3817 break;
3818
3819 /*
3820 * Terminate host interface networking. If aVM is NULL, we've been
3821 * manually called from powerUpThread() either before calling
3822 * VMR3Create() or after VMR3Create() failed, so no need to touch
3823 * networking.
3824 */
3825 if (aVM)
3826 that->powerDownHostInterfaces();
3827
3828 /*
3829 * From now on the machine is officially powered down or
3830 * remains in the Saved state.
3831 */
3832 switch (that->mMachineState)
3833 {
3834 default:
3835 AssertFailed();
3836 /* fall through */
3837 case MachineState_Stopping:
3838 /* successfully powered down */
3839 that->setMachineState (MachineState_PoweredOff);
3840 break;
3841 case MachineState_Saving:
3842 /*
3843 * successfully saved (note that the machine is already
3844 * in the Saved state on the server due to EndSavingState()
3845 * called from saveStateThread(), so only change the local
3846 * state)
3847 */
3848 that->setMachineStateLocally (MachineState_Saved);
3849 break;
3850 case MachineState_Starting:
3851 /*
3852 * failed to start, but be patient: set back to PoweredOff
3853 * (for similarity with the below)
3854 */
3855 that->setMachineState (MachineState_PoweredOff);
3856 break;
3857 case MachineState_Restoring:
3858 /*
3859 * failed to load the saved state file, but be patient:
3860 * set back to Saved (to preserve the saved state file)
3861 */
3862 that->setMachineState (MachineState_Saved);
3863 break;
3864 }
3865
3866 break;
3867 }
3868
3869 case VMSTATE_SUSPENDED:
3870 {
3871 if (aOldState == VMSTATE_RUNNING)
3872 {
3873 AutoLock alock (that);
3874
3875 if (that->mVMStateChangeCallbackDisabled)
3876 break;
3877
3878 /* Change the machine state from Running to Paused */
3879 Assert (that->mMachineState == MachineState_Running);
3880 that->setMachineState (MachineState_Paused);
3881 }
3882 }
3883
3884 case VMSTATE_RUNNING:
3885 {
3886 if (aOldState == VMSTATE_CREATED ||
3887 aOldState == VMSTATE_SUSPENDED)
3888 {
3889 AutoLock alock (that);
3890
3891 if (that->mVMStateChangeCallbackDisabled)
3892 break;
3893
3894 /*
3895 * Change the machine state from Starting, Restoring or Paused
3896 * to Running
3897 */
3898 Assert ((that->mMachineState == MachineState_Starting &&
3899 aOldState == VMSTATE_CREATED) ||
3900 ((that->mMachineState == MachineState_Restoring ||
3901 that->mMachineState == MachineState_Paused) &&
3902 aOldState == VMSTATE_SUSPENDED));
3903
3904 that->setMachineState (MachineState_Running);
3905 }
3906 }
3907
3908 default: /* shut up gcc */
3909 break;
3910 }
3911}
3912
3913/**
3914 * Sends a request to VMM to attach the given host device.
3915 * After this method succeeds, the attached device will appear in the
3916 * mUSBDevices collection.
3917 *
3918 * If \a aManual is true and a failure occures, the given device
3919 * will be returned back to the USB proxy manager.
3920 *
3921 * @param aHostDevice device to attach
3922 * @param aManual true if device is being manually attached
3923 *
3924 * @note Locks this object for writing.
3925 * @note Synchronously calls EMT.
3926 */
3927HRESULT Console::attachUSBDevice (IUSBDevice *aHostDevice, bool aManual,
3928 PVUSBIRHCONFIG aConfig)
3929{
3930 AssertReturn (aHostDevice && aConfig, E_FAIL);
3931
3932 AutoLock alock (this);
3933
3934 HRESULT hrc;
3935
3936 /*
3937 * Get the address and the Uuid, and call the pfnCreateProxyDevice roothub
3938 * method in EMT (using usbAttachCallback()).
3939 */
3940 Bstr BstrAddress;
3941 hrc = aHostDevice->COMGETTER (Address) (BstrAddress.asOutParam());
3942 ComAssertComRCRetRC (hrc);
3943
3944 Utf8Str Address (BstrAddress);
3945
3946 Guid Uuid;
3947 hrc = aHostDevice->COMGETTER (Id) (Uuid.asOutParam());
3948 ComAssertComRCRetRC (hrc);
3949
3950 BOOL fRemote = FALSE;
3951 void *pvRemote = NULL;
3952
3953 hrc = aHostDevice->COMGETTER (Remote) (&fRemote);
3954 ComAssertComRCRetRC (hrc);
3955
3956#ifndef VRDP_MC
3957 if (fRemote)
3958 {
3959 pvRemote = mConsoleVRDPServer->GetUSBBackendPointer ();
3960 ComAssertRet (pvRemote, E_FAIL);
3961 }
3962#endif /* !VRDP_MC */
3963
3964 /* protect mpVM */
3965 AutoVMCaller autoVMCaller (this);
3966 CheckComRCReturnRC (autoVMCaller.rc());
3967
3968 LogFlowThisFunc (("Proxying USB device '%s' {%Vuuid}...\n",
3969 Address.raw(), Uuid.ptr()));
3970
3971 /* leave the lock before a VMR3* call (EMT will call us back)! */
3972 alock.leave();
3973
3974 PVMREQ pReq = NULL;
3975 int vrc = VMR3ReqCall (mpVM, &pReq, RT_INDEFINITE_WAIT,
3976 (PFNRT) usbAttachCallback, 7,
3977 this, aHostDevice,
3978 aConfig, Uuid.ptr(), fRemote, Address.raw(), pvRemote);
3979 if (VBOX_SUCCESS (vrc))
3980 vrc = pReq->iStatus;
3981 VMR3ReqFree (pReq);
3982
3983 /* restore the lock */
3984 alock.enter();
3985
3986 /* hrc is S_OK here */
3987
3988 if (VBOX_FAILURE (vrc))
3989 {
3990 LogWarningThisFunc (("Failed to create proxy device for '%s' {%Vuuid} (%Vrc)\n",
3991 Address.raw(), Uuid.ptr(), vrc));
3992
3993 if (aManual)
3994 {
3995 /*
3996 * Neither SessionMachine::ReleaseUSBDevice() nor Host::releaseUSBDevice()
3997 * should call the Console back, so keep the lock to provide atomicity
3998 * (to protect Host reapplying USB filters)
3999 */
4000 hrc = mControl->ReleaseUSBDevice (Uuid);
4001 AssertComRC (hrc);
4002 }
4003
4004 switch (vrc)
4005 {
4006 case VERR_VUSB_NO_PORTS:
4007 hrc = setError (E_FAIL,
4008 tr ("Failed to attach the USB device. (No available ports on the USB controller)."));
4009 break;
4010 case VERR_VUSB_USBFS_PERMISSION:
4011 hrc = setError (E_FAIL,
4012 tr ("Not permitted to open the USB device, check usbfs options"));
4013 break;
4014 default:
4015 hrc = setError (E_FAIL,
4016 tr ("Failed to create a proxy device for the USB device. (Error: %Vrc)"), vrc);
4017 break;
4018 }
4019 }
4020
4021 return hrc;
4022}
4023
4024/**
4025 * USB device attack callback used by AttachUSBDevice().
4026 * Note that AttachUSBDevice() doesn't return until this callback is executed,
4027 * so we don't use AutoCaller and don't care about reference counters of
4028 * interface pointers passed in.
4029 *
4030 * @thread EMT
4031 * @note Locks the console object for writing.
4032 */
4033//static
4034DECLCALLBACK(int)
4035Console::usbAttachCallback (Console *that, IUSBDevice *aHostDevice,
4036 PVUSBIRHCONFIG aConfig, PCRTUUID aUuid, bool aRemote,
4037 const char *aAddress, void *aRemoteBackend)
4038{
4039 LogFlowFuncEnter();
4040 LogFlowFunc (("that={%p}\n", that));
4041
4042 AssertReturn (that && aConfig && aUuid, VERR_INVALID_PARAMETER);
4043
4044#ifdef VRDP_MC
4045 if (aRemote)
4046 {
4047 /* @todo aRemoteBackend input parameter is not needed. */
4048 Assert (aRemoteBackend == NULL);
4049
4050 RemoteUSBDevice *pRemoteUSBDevice = static_cast <RemoteUSBDevice *> (aHostDevice);
4051
4052 Guid guid (*aUuid);
4053
4054 aRemoteBackend = that->consoleVRDPServer ()->USBBackendRequestPointer (pRemoteUSBDevice->clientId (), &guid);
4055
4056 if (aRemoteBackend == NULL)
4057 {
4058 /* The clientId is invalid then. */
4059 return VERR_INVALID_PARAMETER;
4060 }
4061 }
4062#endif /* VRDP_MC */
4063
4064 int vrc = aConfig->pfnCreateProxyDevice (aConfig, aUuid, aRemote, aAddress,
4065 aRemoteBackend);
4066
4067 if (VBOX_SUCCESS (vrc))
4068 {
4069 /* Create a USBDevice and add it to the device list */
4070 ComObjPtr <USBDevice> device;
4071 device.createObject();
4072 HRESULT hrc = device->init (aHostDevice);
4073 AssertComRC (hrc);
4074
4075 AutoLock alock (that);
4076 that->mUSBDevices.push_back (device);
4077 LogFlowFunc (("Attached device {%Vuuid}\n", device->id().raw()));
4078 }
4079
4080 LogFlowFunc (("vrc=%Vrc\n", vrc));
4081 LogFlowFuncLeave();
4082 return vrc;
4083}
4084
4085/**
4086 * USB device attack callback used by AttachUSBDevice().
4087 * Note that AttachUSBDevice() doesn't return until this callback is executed,
4088 * so we don't use AutoCaller and don't care about reference counters of
4089 * interface pointers passed in.
4090 *
4091 * @thread EMT
4092 * @note Locks the console object for writing.
4093 */
4094//static
4095DECLCALLBACK(int)
4096Console::usbDetachCallback (Console *that, USBDeviceList::iterator *aIt,
4097 bool aManual, PVUSBIRHCONFIG aConfig, PCRTUUID aUuid)
4098{
4099 LogFlowFuncEnter();
4100 LogFlowFunc (("that={%p}\n", that));
4101
4102 AssertReturn (that && aConfig && aUuid, VERR_INVALID_PARAMETER);
4103
4104#ifdef VRDP_MC
4105 /*
4106 * If that was a remote device, release the backend pointer.
4107 * The pointer was requested in usbAttachCallback.
4108 */
4109 BOOL fRemote = FALSE;
4110
4111 HRESULT hrc2 = (**aIt)->COMGETTER (Remote) (&fRemote);
4112 ComAssertComRC (hrc2);
4113
4114 if (fRemote)
4115 {
4116 Guid guid (*aUuid);
4117 that->consoleVRDPServer ()->USBBackendReleasePointer (&guid);
4118 }
4119#endif /* VRDP_MC */
4120
4121 int vrc = aConfig->pfnDestroyProxyDevice (aConfig, aUuid);
4122
4123 if (VBOX_SUCCESS (vrc))
4124 {
4125 AutoLock alock (that);
4126
4127 /* Remove the device from the collection */
4128 that->mUSBDevices.erase (*aIt);
4129 LogFlowFunc (("Detached device {%Vuuid}\n", (**aIt)->id().raw()));
4130
4131 /// @todo (dmik) REMOTE_USB
4132 // if the device is remote, notify a remote client that we have
4133 // detached the device
4134
4135 /* If it's a manual detach, give it back to the USB Proxy */
4136 if (aManual)
4137 {
4138 /*
4139 * Neither SessionMachine::ReleaseUSBDevice() nor Host::releaseUSBDevice()
4140 * should call the Console back, so keep the lock to provide atomicity
4141 * (to protect Host reapplying USB filters)
4142 */
4143 LogFlowFunc (("Giving it back it to USB proxy...\n"));
4144 HRESULT hrc = that->mControl->ReleaseUSBDevice (Guid (*aUuid));
4145 AssertComRC (hrc);
4146 vrc = SUCCEEDED (hrc) ? VINF_SUCCESS : VERR_GENERAL_FAILURE;
4147 }
4148 }
4149
4150 LogFlowFunc (("vrc=%Vrc\n", vrc));
4151 LogFlowFuncLeave();
4152 return vrc;
4153}
4154
4155/**
4156 * Construct the VM configuration tree (CFGM).
4157 *
4158 * This is a callback for VMR3Create() call. It is called from CFGMR3Init()
4159 * in the emulation thread (EMT). Any per thread COM/XPCOM initialization
4160 * is done here.
4161 *
4162 * @param pVM VM handle.
4163 * @param pvTask Pointer to the VMPowerUpTask object.
4164 * @return VBox status code.
4165 *
4166 * @note Locks the Console object for writing.
4167 */
4168DECLCALLBACK(int) Console::configConstructor(PVM pVM, void *pvTask)
4169{
4170 LogFlowFuncEnter();
4171
4172 /* Note: the task pointer is owned by powerUpThread() */
4173 VMPowerUpTask *task = static_cast <VMPowerUpTask *> (pvTask);
4174 AssertReturn (task, VERR_GENERAL_FAILURE);
4175
4176#if defined(__WIN__)
4177 {
4178 /* initialize COM */
4179 HRESULT hrc = CoInitializeEx(NULL,
4180 COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE |
4181 COINIT_SPEED_OVER_MEMORY);
4182 LogFlow (("Console::configConstructor(): CoInitializeEx()=%08X\n", hrc));
4183 AssertComRCReturn (hrc, VERR_GENERAL_FAILURE);
4184 }
4185#endif
4186
4187 ComObjPtr <Console> pConsole = task->mConsole;
4188
4189 AutoCaller autoCaller (pConsole);
4190 AssertComRCReturn (autoCaller.rc(), VERR_ACCESS_DENIED);
4191
4192 /* lock the console because we widely use internal fields and methods */
4193 AutoLock alock (pConsole);
4194
4195 ComPtr <IMachine> pMachine = pConsole->machine();
4196
4197 int rc;
4198 HRESULT hrc;
4199 char *psz = NULL;
4200 BSTR str = NULL;
4201 ULONG cRamMBs;
4202 unsigned i;
4203
4204#define STR_CONV() do { rc = RTStrUcs2ToUtf8(&psz, str); RC_CHECK(); } while (0)
4205#define STR_FREE() do { if (str) { SysFreeString(str); str = NULL; } if (psz) { RTStrFree(psz); psz = NULL; } } while (0)
4206#define RC_CHECK() do { if (VBOX_FAILURE(rc)) { AssertMsgFailed(("rc=%Vrc\n", rc)); STR_FREE(); return rc; } } while (0)
4207#define H() do { if (FAILED(hrc)) { AssertMsgFailed(("hrc=%#x\n", hrc)); STR_FREE(); return VERR_GENERAL_FAILURE; } } while (0)
4208
4209 /* Get necessary objects */
4210
4211 ComPtr<IVirtualBox> virtualBox;
4212 hrc = pMachine->COMGETTER(Parent)(virtualBox.asOutParam()); H();
4213
4214 ComPtr<IHost> host;
4215 hrc = virtualBox->COMGETTER(Host)(host.asOutParam()); H();
4216
4217 ComPtr <ISystemProperties> systemProperties;
4218 hrc = virtualBox->COMGETTER(SystemProperties)(systemProperties.asOutParam()); H();
4219
4220 ComPtr<IBIOSSettings> biosSettings;
4221 hrc = pMachine->COMGETTER(BIOSSettings)(biosSettings.asOutParam()); H();
4222
4223
4224 /*
4225 * Get root node first.
4226 * This is the only node in the tree.
4227 */
4228 PCFGMNODE pRoot = CFGMR3GetRoot(pVM);
4229 Assert(pRoot);
4230
4231 /*
4232 * Set the root level values.
4233 */
4234 hrc = pMachine->COMGETTER(Name)(&str); H();
4235 STR_CONV();
4236 rc = CFGMR3InsertString(pRoot, "Name", psz); RC_CHECK();
4237 STR_FREE();
4238 hrc = pMachine->COMGETTER(MemorySize)(&cRamMBs); H();
4239 rc = CFGMR3InsertInteger(pRoot, "RamSize", cRamMBs * _1M); RC_CHECK();
4240 rc = CFGMR3InsertInteger(pRoot, "TimerMillies", 10); RC_CHECK();
4241 rc = CFGMR3InsertInteger(pRoot, "RawR3Enabled", 1); /* boolean */ RC_CHECK();
4242 rc = CFGMR3InsertInteger(pRoot, "RawR0Enabled", 1); /* boolean */ RC_CHECK();
4243 /** @todo Config: RawR0, PATMEnabled and CASMEnabled needs attention later. */
4244 rc = CFGMR3InsertInteger(pRoot, "PATMEnabled", 1); /* boolean */ RC_CHECK();
4245 rc = CFGMR3InsertInteger(pRoot, "CSAMEnabled", 1); /* boolean */ RC_CHECK();
4246
4247 /* hardware virtualization extensions */
4248 TriStateBool_T hwVirtExEnabled;
4249 BOOL fHWVirtExEnabled;
4250 hrc = pMachine->COMGETTER(HWVirtExEnabled)(&hwVirtExEnabled); H();
4251 if (hwVirtExEnabled == TriStateBool_Default)
4252 {
4253 /* check the default value */
4254 hrc = systemProperties->COMGETTER(HWVirtExEnabled)(&fHWVirtExEnabled); H();
4255 }
4256 else
4257 fHWVirtExEnabled = (hwVirtExEnabled == TriStateBool_True);
4258 if (fHWVirtExEnabled)
4259 {
4260 PCFGMNODE pHWVirtExt;
4261 rc = CFGMR3InsertNode(pRoot, "HWVirtExt", &pHWVirtExt); RC_CHECK();
4262 rc = CFGMR3InsertInteger(pHWVirtExt, "Enabled", 1); RC_CHECK();
4263 }
4264
4265 BOOL fIOAPIC;
4266 hrc = biosSettings->COMGETTER(IOAPICEnabled)(&fIOAPIC); H();
4267
4268 /*
4269 * PDM config.
4270 * Load drivers in VBoxC.[so|dll]
4271 */
4272 PCFGMNODE pPDM;
4273 PCFGMNODE pDrivers;
4274 PCFGMNODE pMod;
4275 rc = CFGMR3InsertNode(pRoot, "PDM", &pPDM); RC_CHECK();
4276 rc = CFGMR3InsertNode(pPDM, "Drivers", &pDrivers); RC_CHECK();
4277 rc = CFGMR3InsertNode(pDrivers, "VBoxC", &pMod); RC_CHECK();
4278#ifdef __LINUX__
4279 // VBoxC is located in the components subdirectory
4280 char szPathProgram[RTPATH_MAX + sizeof("/components/VBoxC")];
4281 rc = RTPathProgram(szPathProgram, RTPATH_MAX); AssertRC(rc);
4282 strcat(szPathProgram, "/components/VBoxC");
4283 rc = CFGMR3InsertString(pMod, "Path", szPathProgram); RC_CHECK();
4284#else
4285 rc = CFGMR3InsertString(pMod, "Path", "VBoxC"); RC_CHECK();
4286#endif
4287
4288 /*
4289 * Devices
4290 */
4291 PCFGMNODE pDevices = NULL; /* /Devices */
4292 PCFGMNODE pDev = NULL; /* /Devices/Dev/ */
4293 PCFGMNODE pInst = NULL; /* /Devices/Dev/0/ */
4294 PCFGMNODE pCfg = NULL; /* /Devices/Dev/.../Config/ */
4295 PCFGMNODE pLunL0 = NULL; /* /Devices/Dev/0/LUN#0/ */
4296 PCFGMNODE pLunL1 = NULL; /* /Devices/Dev/0/LUN#0/AttachedDriver/ */
4297 rc = CFGMR3InsertNode(pRoot, "Devices", &pDevices); RC_CHECK();
4298
4299 /*
4300 * PC Arch.
4301 */
4302 rc = CFGMR3InsertNode(pDevices, "pcarch", &pDev); RC_CHECK();
4303 rc = CFGMR3InsertNode(pDev, "0", &pInst); RC_CHECK();
4304 rc = CFGMR3InsertInteger(pInst, "Trusted", 1); /* boolean */ RC_CHECK();
4305 rc = CFGMR3InsertNode(pInst, "Config", &pCfg); RC_CHECK();
4306
4307 /*
4308 * PC Bios.
4309 */
4310 rc = CFGMR3InsertNode(pDevices, "pcbios", &pDev); RC_CHECK();
4311 rc = CFGMR3InsertNode(pDev, "0", &pInst); RC_CHECK();
4312 rc = CFGMR3InsertInteger(pInst, "Trusted", 1); /* boolean */ RC_CHECK();
4313 rc = CFGMR3InsertNode(pInst, "Config", &pCfg); RC_CHECK();
4314 rc = CFGMR3InsertInteger(pCfg, "RamSize", cRamMBs * _1M); RC_CHECK();
4315 rc = CFGMR3InsertString(pCfg, "HardDiskDevice", "piix3ide"); RC_CHECK();
4316 rc = CFGMR3InsertString(pCfg, "FloppyDevice", "i82078"); RC_CHECK();
4317
4318 DeviceType_T bootDevice;
4319 if (SchemaDefs::MaxBootPosition > 9)
4320 {
4321 AssertMsgFailed (("Too many boot devices %d\n",
4322 SchemaDefs::MaxBootPosition));
4323 return VERR_INVALID_PARAMETER;
4324 }
4325
4326 for (ULONG pos = 1; pos <= SchemaDefs::MaxBootPosition; pos ++)
4327 {
4328 hrc = pMachine->GetBootOrder(pos, &bootDevice); H();
4329
4330 char szParamName[] = "BootDeviceX";
4331 szParamName[sizeof (szParamName) - 2] = ((char (pos - 1)) + '0');
4332
4333 const char *pszBootDevice;
4334 switch (bootDevice)
4335 {
4336 case DeviceType_NoDevice:
4337 pszBootDevice = "NONE";
4338 break;
4339 case DeviceType_HardDiskDevice:
4340 pszBootDevice = "IDE";
4341 break;
4342 case DeviceType_DVDDevice:
4343 pszBootDevice = "DVD";
4344 break;
4345 case DeviceType_FloppyDevice:
4346 pszBootDevice = "FLOPPY";
4347 break;
4348 case DeviceType_NetworkDevice:
4349 pszBootDevice = "LAN";
4350 break;
4351 default:
4352 AssertMsgFailed(("Invalid bootDevice=%d\n", bootDevice));
4353 return VERR_INVALID_PARAMETER;
4354 }
4355 rc = CFGMR3InsertString(pCfg, szParamName, pszBootDevice); RC_CHECK();
4356 }
4357
4358 /*
4359 * BIOS logo
4360 */
4361 BOOL fFadeIn;
4362 hrc = biosSettings->COMGETTER(LogoFadeIn)(&fFadeIn); H();
4363 rc = CFGMR3InsertInteger(pCfg, "FadeIn", fFadeIn ? 1 : 0); RC_CHECK();
4364 BOOL fFadeOut;
4365 hrc = biosSettings->COMGETTER(LogoFadeOut)(&fFadeOut); H();
4366 rc = CFGMR3InsertInteger(pCfg, "FadeOut", fFadeOut ? 1: 0); RC_CHECK();
4367 ULONG logoDisplayTime;
4368 hrc = biosSettings->COMGETTER(LogoDisplayTime)(&logoDisplayTime); H();
4369 rc = CFGMR3InsertInteger(pCfg, "LogoTime", logoDisplayTime); RC_CHECK();
4370 Bstr logoImagePath;
4371 hrc = biosSettings->COMGETTER(LogoImagePath)(logoImagePath.asOutParam()); H();
4372 rc = CFGMR3InsertString(pCfg, "LogoFile", logoImagePath ? Utf8Str(logoImagePath) : ""); RC_CHECK();
4373
4374 /*
4375 * Boot menu
4376 */
4377 BIOSBootMenuMode_T bootMenuMode;
4378 int value;
4379 biosSettings->COMGETTER(BootMenuMode)(&bootMenuMode);
4380 switch (bootMenuMode)
4381 {
4382 case BIOSBootMenuMode_Disabled:
4383 value = 0;
4384 break;
4385 case BIOSBootMenuMode_MenuOnly:
4386 value = 1;
4387 break;
4388 default:
4389 value = 2;
4390 }
4391 rc = CFGMR3InsertInteger(pCfg, "ShowBootMenu", value); RC_CHECK();
4392
4393 /*
4394 * ACPI
4395 */
4396 BOOL fACPI;
4397 hrc = biosSettings->COMGETTER(ACPIEnabled)(&fACPI); H();
4398 if (fACPI)
4399 {
4400 rc = CFGMR3InsertNode(pDevices, "acpi", &pDev); RC_CHECK();
4401 rc = CFGMR3InsertNode(pDev, "0", &pInst); RC_CHECK();
4402 rc = CFGMR3InsertInteger(pInst, "Trusted", 1); /* boolean */ RC_CHECK();
4403 rc = CFGMR3InsertNode(pInst, "Config", &pCfg); RC_CHECK();
4404 rc = CFGMR3InsertInteger(pCfg, "RamSize", cRamMBs * _1M); RC_CHECK();
4405 rc = CFGMR3InsertInteger(pCfg, "IOAPIC", fIOAPIC); RC_CHECK();
4406 rc = CFGMR3InsertInteger(pInst, "PCIDeviceNo", 7); RC_CHECK();
4407 rc = CFGMR3InsertInteger(pInst, "PCIFunctionNo", 0); RC_CHECK();
4408
4409 rc = CFGMR3InsertNode(pInst, "LUN#0", &pLunL0); RC_CHECK();
4410 rc = CFGMR3InsertString(pLunL0, "Driver", "ACPIHost"); RC_CHECK();
4411 rc = CFGMR3InsertNode(pLunL0, "Config", &pCfg); RC_CHECK();
4412 }
4413
4414 /*
4415 * DMA
4416 */
4417 rc = CFGMR3InsertNode(pDevices, "8237A", &pDev); RC_CHECK();
4418 rc = CFGMR3InsertNode(pDev, "0", &pInst); RC_CHECK();
4419 rc = CFGMR3InsertInteger(pInst, "Trusted", 1); /* boolean */ RC_CHECK();
4420
4421 /*
4422 * PCI bus.
4423 */
4424 rc = CFGMR3InsertNode(pDevices, "pci", &pDev); /* piix3 */ RC_CHECK();
4425 rc = CFGMR3InsertNode(pDev, "0", &pInst); RC_CHECK();
4426 rc = CFGMR3InsertInteger(pInst, "Trusted", 1); /* boolean */ RC_CHECK();
4427 rc = CFGMR3InsertNode(pInst, "Config", &pCfg); RC_CHECK();
4428 rc = CFGMR3InsertInteger(pCfg, "IOAPIC", fIOAPIC); RC_CHECK();
4429
4430 /*
4431 * PS/2 keyboard & mouse.
4432 */
4433 rc = CFGMR3InsertNode(pDevices, "pckbd", &pDev); RC_CHECK();
4434 rc = CFGMR3InsertNode(pDev, "0", &pInst); RC_CHECK();
4435 rc = CFGMR3InsertInteger(pInst, "Trusted", 1); /* boolean */ RC_CHECK();
4436 rc = CFGMR3InsertNode(pInst, "Config", &pCfg); RC_CHECK();
4437
4438 rc = CFGMR3InsertNode(pInst, "LUN#0", &pLunL0); RC_CHECK();
4439 rc = CFGMR3InsertString(pLunL0, "Driver", "KeyboardQueue"); RC_CHECK();
4440 rc = CFGMR3InsertNode(pLunL0, "Config", &pCfg); RC_CHECK();
4441 rc = CFGMR3InsertInteger(pCfg, "QueueSize", 64); RC_CHECK();
4442
4443 rc = CFGMR3InsertNode(pLunL0, "AttachedDriver", &pLunL1); RC_CHECK();
4444 rc = CFGMR3InsertString(pLunL1, "Driver", "MainKeyboard"); RC_CHECK();
4445 rc = CFGMR3InsertNode(pLunL1, "Config", &pCfg); RC_CHECK();
4446 Keyboard *pKeyboard = pConsole->mKeyboard;
4447 rc = CFGMR3InsertInteger(pCfg, "Object", (uintptr_t)pKeyboard); RC_CHECK();
4448
4449 rc = CFGMR3InsertNode(pInst, "LUN#1", &pLunL0); RC_CHECK();
4450 rc = CFGMR3InsertString(pLunL0, "Driver", "MouseQueue"); RC_CHECK();
4451 rc = CFGMR3InsertNode(pLunL0, "Config", &pCfg); RC_CHECK();
4452 rc = CFGMR3InsertInteger(pCfg, "QueueSize", 128); RC_CHECK();
4453
4454 rc = CFGMR3InsertNode(pLunL0, "AttachedDriver", &pLunL1); RC_CHECK();
4455 rc = CFGMR3InsertString(pLunL1, "Driver", "MainMouse"); RC_CHECK();
4456 rc = CFGMR3InsertNode(pLunL1, "Config", &pCfg); RC_CHECK();
4457 Mouse *pMouse = pConsole->mMouse;
4458 rc = CFGMR3InsertInteger(pCfg, "Object", (uintptr_t)pMouse); RC_CHECK();
4459
4460 /*
4461 * i82078 Floppy drive controller
4462 */
4463 ComPtr<IFloppyDrive> floppyDrive;
4464 hrc = pMachine->COMGETTER(FloppyDrive)(floppyDrive.asOutParam()); H();
4465 BOOL fFloppyEnabled;
4466 hrc = floppyDrive->COMGETTER(Enabled)(&fFloppyEnabled); H();
4467 if (fFloppyEnabled)
4468 {
4469 rc = CFGMR3InsertNode(pDevices, "i82078", &pDev); RC_CHECK();
4470 rc = CFGMR3InsertNode(pDev, "0", &pInst); RC_CHECK();
4471 rc = CFGMR3InsertInteger(pInst, "Trusted", 1); RC_CHECK();
4472 rc = CFGMR3InsertNode(pInst, "Config", &pCfg); RC_CHECK();
4473 rc = CFGMR3InsertInteger(pCfg, "IRQ", 6); RC_CHECK();
4474 rc = CFGMR3InsertInteger(pCfg, "DMA", 2); RC_CHECK();
4475 rc = CFGMR3InsertInteger(pCfg, "MemMapped", 0 ); RC_CHECK();
4476 rc = CFGMR3InsertInteger(pCfg, "IOBase", 0x3f0); RC_CHECK();
4477
4478 /* Attach the status driver */
4479 rc = CFGMR3InsertNode(pInst, "LUN#999", &pLunL0); RC_CHECK();
4480 rc = CFGMR3InsertString(pLunL0, "Driver", "MainStatus"); RC_CHECK();
4481 rc = CFGMR3InsertNode(pLunL0, "Config", &pCfg); RC_CHECK();
4482 rc = CFGMR3InsertInteger(pCfg, "papLeds", (uintptr_t)&pConsole->mapFDLeds[0]); RC_CHECK();
4483 rc = CFGMR3InsertInteger(pCfg, "First", 0); RC_CHECK();
4484 rc = CFGMR3InsertInteger(pCfg, "Last", 0); RC_CHECK();
4485
4486 rc = CFGMR3InsertNode(pInst, "LUN#0", &pLunL0); RC_CHECK();
4487
4488 ComPtr<IFloppyImage> floppyImage;
4489 hrc = floppyDrive->GetImage(floppyImage.asOutParam()); H();
4490 if (floppyImage)
4491 {
4492 pConsole->meFloppyState = DriveState_ImageMounted;
4493 rc = CFGMR3InsertString(pLunL0, "Driver", "Block"); RC_CHECK();
4494 rc = CFGMR3InsertNode(pLunL0, "Config", &pCfg); RC_CHECK();
4495 rc = CFGMR3InsertString(pCfg, "Type", "Floppy 1.44"); RC_CHECK();
4496 rc = CFGMR3InsertInteger(pCfg, "Mountable", 1); RC_CHECK();
4497
4498 rc = CFGMR3InsertNode(pLunL0, "AttachedDriver", &pLunL1); RC_CHECK();
4499 rc = CFGMR3InsertString(pLunL1, "Driver", "RawImage"); RC_CHECK();
4500 rc = CFGMR3InsertNode(pLunL1, "Config", &pCfg); RC_CHECK();
4501 hrc = floppyImage->COMGETTER(FilePath)(&str); H();
4502 STR_CONV();
4503 rc = CFGMR3InsertString(pCfg, "Path", psz); RC_CHECK();
4504 STR_FREE();
4505 }
4506 else
4507 {
4508 ComPtr<IHostFloppyDrive> hostFloppyDrive;
4509 hrc = floppyDrive->GetHostDrive(hostFloppyDrive.asOutParam()); H();
4510 if (hostFloppyDrive)
4511 {
4512 pConsole->meFloppyState = DriveState_HostDriveCaptured;
4513 rc = CFGMR3InsertString(pLunL0, "Driver", "HostFloppy"); RC_CHECK();
4514 rc = CFGMR3InsertNode(pLunL0, "Config", &pCfg); RC_CHECK();
4515 hrc = hostFloppyDrive->COMGETTER(Name)(&str); H();
4516 STR_CONV();
4517 rc = CFGMR3InsertString(pCfg, "Path", psz); RC_CHECK();
4518 STR_FREE();
4519 }
4520 else
4521 {
4522 pConsole->meFloppyState = DriveState_NotMounted;
4523 rc = CFGMR3InsertString(pLunL0, "Driver", "Block"); RC_CHECK();
4524 rc = CFGMR3InsertNode(pLunL0, "Config", &pCfg); RC_CHECK();
4525 rc = CFGMR3InsertString(pCfg, "Type", "Floppy 1.44"); RC_CHECK();
4526 rc = CFGMR3InsertInteger(pCfg, "Mountable", 1); RC_CHECK();
4527 }
4528 }
4529 }
4530
4531 /*
4532 * i8254 Programmable Interval Timer And Dummy Speaker
4533 */
4534 rc = CFGMR3InsertNode(pDevices, "i8254", &pDev); RC_CHECK();
4535 rc = CFGMR3InsertNode(pDev, "0", &pInst); RC_CHECK();
4536 rc = CFGMR3InsertNode(pInst, "Config", &pCfg); RC_CHECK();
4537#ifdef DEBUG
4538 rc = CFGMR3InsertInteger(pInst, "Trusted", 1); /* boolean */ RC_CHECK();
4539#endif
4540
4541 /*
4542 * i8259 Programmable Interrupt Controller.
4543 */
4544 rc = CFGMR3InsertNode(pDevices, "i8259", &pDev); RC_CHECK();
4545 rc = CFGMR3InsertNode(pDev, "0", &pInst); RC_CHECK();
4546 rc = CFGMR3InsertInteger(pInst, "Trusted", 1); /* boolean */ RC_CHECK();
4547 rc = CFGMR3InsertNode(pInst, "Config", &pCfg); RC_CHECK();
4548
4549 /*
4550 * Advanced Programmable Interrupt Controller.
4551 */
4552 rc = CFGMR3InsertNode(pDevices, "apic", &pDev); RC_CHECK();
4553 rc = CFGMR3InsertNode(pDev, "0", &pInst); RC_CHECK();
4554 rc = CFGMR3InsertInteger(pInst, "Trusted", 1); /* boolean */ RC_CHECK();
4555 rc = CFGMR3InsertNode(pInst, "Config", &pCfg); RC_CHECK();
4556
4557 if (fIOAPIC)
4558 {
4559 /*
4560 * I/O Advanced Programmable Interrupt Controller.
4561 */
4562 rc = CFGMR3InsertNode(pDevices, "ioapic", &pDev); RC_CHECK();
4563 rc = CFGMR3InsertNode(pDev, "0", &pInst); RC_CHECK();
4564 rc = CFGMR3InsertInteger(pInst, "Trusted", 1); /* boolean */ RC_CHECK();
4565 rc = CFGMR3InsertNode(pInst, "Config", &pCfg); RC_CHECK();
4566 }
4567
4568 /*
4569 * RTC MC146818.
4570 */
4571 rc = CFGMR3InsertNode(pDevices, "mc146818", &pDev); RC_CHECK();
4572 rc = CFGMR3InsertNode(pDev, "0", &pInst); RC_CHECK();
4573 rc = CFGMR3InsertNode(pInst, "Config", &pCfg); RC_CHECK();
4574
4575#if 0
4576 /*
4577 * Serial ports
4578 */
4579 rc = CFGMR3InsertNode(pDevices, "serial", &pDev); RC_CHECK();
4580 rc = CFGMR3InsertNode(pDev, "0", &pInst); RC_CHECK();
4581 rc = CFGMR3InsertNode(pInst, "Config", &pCfg); RC_CHECK();
4582 rc = CFGMR3InsertInteger(pCfg, "IRQ", 4); RC_CHECK();
4583 rc = CFGMR3InsertInteger(pCfg, "IOBase", 0x3f8); RC_CHECK();
4584
4585 rc = CFGMR3InsertNode(pDev, "1", &pInst); RC_CHECK();
4586 rc = CFGMR3InsertNode(pInst, "Config", &pCfg); RC_CHECK();
4587 rc = CFGMR3InsertInteger(pCfg, "IRQ", 3); RC_CHECK();
4588 rc = CFGMR3InsertInteger(pCfg, "IOBase", 0x2f8); RC_CHECK();
4589#endif
4590
4591 /*
4592 * VGA.
4593 */
4594 rc = CFGMR3InsertNode(pDevices, "vga", &pDev); RC_CHECK();
4595 rc = CFGMR3InsertNode(pDev, "0", &pInst); RC_CHECK();
4596 rc = CFGMR3InsertInteger(pInst, "Trusted", 1); /* boolean */ RC_CHECK();
4597 rc = CFGMR3InsertInteger(pInst, "PCIDeviceNo", 2); RC_CHECK();
4598 rc = CFGMR3InsertInteger(pInst, "PCIFunctionNo", 0); RC_CHECK();
4599 rc = CFGMR3InsertNode(pInst, "Config", &pCfg); RC_CHECK();
4600 hrc = pMachine->COMGETTER(VRAMSize)(&cRamMBs); H();
4601 rc = CFGMR3InsertInteger(pCfg, "VRamSize", cRamMBs * _1M); RC_CHECK();
4602
4603 /* Custom VESA mode list */
4604 unsigned cModes = 0;
4605 for (unsigned iMode = 1; iMode <= 16; iMode++)
4606 {
4607 char szExtraDataKey[sizeof("CustomVideoModeXX")];
4608 RTStrPrintf(szExtraDataKey, sizeof(szExtraDataKey), "CustomVideoMode%d", iMode);
4609 hrc = pMachine->GetExtraData(Bstr(szExtraDataKey), &str); H();
4610 if (!str || !*str)
4611 break;
4612 STR_CONV();
4613 rc = CFGMR3InsertString(pCfg, szExtraDataKey, psz);
4614 STR_FREE();
4615 cModes++;
4616 }
4617 rc = CFGMR3InsertInteger(pCfg, "CustomVideoModes", cModes);
4618
4619 /* VESA height reduction */
4620 ULONG ulHeightReduction;
4621 IFramebuffer *pFramebuffer = pConsole->getDisplay()->getFramebuffer();
4622 hrc = pFramebuffer->COMGETTER(HeightReduction)(&ulHeightReduction); H();
4623 rc = CFGMR3InsertInteger(pCfg, "HeightReduction", ulHeightReduction); RC_CHECK();
4624
4625 /* Attach the display. */
4626 rc = CFGMR3InsertNode(pInst, "LUN#0", &pLunL0); RC_CHECK();
4627 rc = CFGMR3InsertString(pLunL0, "Driver", "MainDisplay"); RC_CHECK();
4628 rc = CFGMR3InsertNode(pLunL0, "Config", &pCfg); RC_CHECK();
4629 Display *pDisplay = pConsole->mDisplay;
4630 rc = CFGMR3InsertInteger(pCfg, "Object", (uintptr_t)pDisplay); RC_CHECK();
4631
4632 /*
4633 * IDE (update this when the main interface changes)
4634 */
4635 rc = CFGMR3InsertNode(pDevices, "piix3ide", &pDev); /* piix3 */ RC_CHECK();
4636 rc = CFGMR3InsertNode(pDev, "0", &pInst); RC_CHECK();
4637 rc = CFGMR3InsertInteger(pInst, "Trusted", 1); /* boolean */ RC_CHECK();
4638 rc = CFGMR3InsertInteger(pInst, "PCIDeviceNo", 1); RC_CHECK();
4639 rc = CFGMR3InsertInteger(pInst, "PCIFunctionNo", 1); RC_CHECK();
4640 rc = CFGMR3InsertNode(pInst, "Config", &pCfg); RC_CHECK();
4641
4642 /* Attach the status driver */
4643 rc = CFGMR3InsertNode(pInst, "LUN#999", &pLunL0); RC_CHECK();
4644 rc = CFGMR3InsertString(pLunL0, "Driver", "MainStatus"); RC_CHECK();
4645 rc = CFGMR3InsertNode(pLunL0, "Config", &pCfg); RC_CHECK();
4646 rc = CFGMR3InsertInteger(pCfg, "papLeds", (uintptr_t)&pConsole->mapIDELeds[0]);RC_CHECK();
4647 rc = CFGMR3InsertInteger(pCfg, "First", 0); RC_CHECK();
4648 rc = CFGMR3InsertInteger(pCfg, "Last", 3); RC_CHECK();
4649
4650 /* Attach the harddisks */
4651 ComPtr<IHardDiskAttachmentCollection> hdaColl;
4652 hrc = pMachine->COMGETTER(HardDiskAttachments)(hdaColl.asOutParam()); H();
4653 ComPtr<IHardDiskAttachmentEnumerator> hdaEnum;
4654 hrc = hdaColl->Enumerate(hdaEnum.asOutParam()); H();
4655
4656 BOOL fMore = FALSE;
4657 while ( SUCCEEDED(hrc = hdaEnum->HasMore(&fMore))
4658 && fMore)
4659 {
4660 ComPtr<IHardDiskAttachment> hda;
4661 hrc = hdaEnum->GetNext(hda.asOutParam()); H();
4662 ComPtr<IHardDisk> hardDisk;
4663 hrc = hda->COMGETTER(HardDisk)(hardDisk.asOutParam()); H();
4664 DiskControllerType_T enmCtl;
4665 hrc = hda->COMGETTER(Controller)(&enmCtl); H();
4666 LONG lDev;
4667 hrc = hda->COMGETTER(DeviceNumber)(&lDev); H();
4668
4669 switch (enmCtl)
4670 {
4671 case DiskControllerType_IDE0Controller:
4672 i = 0;
4673 break;
4674 case DiskControllerType_IDE1Controller:
4675 i = 2;
4676 break;
4677 default:
4678 AssertMsgFailed(("invalid disk controller type: %d\n", enmCtl));
4679 return VERR_GENERAL_FAILURE;
4680 }
4681
4682 if (lDev < 0 || lDev >= 2)
4683 {
4684 AssertMsgFailed(("invalid controller device number: %d\n", lDev));
4685 return VERR_GENERAL_FAILURE;
4686 }
4687
4688 i = i + lDev;
4689
4690 char szLUN[16];
4691 RTStrPrintf(szLUN, sizeof(szLUN), "LUN#%d", i);
4692 rc = CFGMR3InsertNode(pInst, szLUN, &pLunL0); RC_CHECK();
4693 rc = CFGMR3InsertString(pLunL0, "Driver", "Block"); RC_CHECK();
4694 rc = CFGMR3InsertNode(pLunL0, "Config", &pCfg); RC_CHECK();
4695 rc = CFGMR3InsertString(pCfg, "Type", "HardDisk"); RC_CHECK();
4696 rc = CFGMR3InsertInteger(pCfg, "Mountable", 0); RC_CHECK();
4697
4698 HardDiskStorageType_T hddType;
4699 hardDisk->COMGETTER(StorageType)(&hddType);
4700 if (hddType == HardDiskStorageType_VirtualDiskImage)
4701 {
4702 rc = CFGMR3InsertNode(pLunL0, "AttachedDriver", &pLunL1); RC_CHECK();
4703 rc = CFGMR3InsertString(pLunL1, "Driver", "VBoxHDD"); RC_CHECK();
4704 rc = CFGMR3InsertNode(pLunL1, "Config", &pCfg); RC_CHECK();
4705 /// @todo (dmik) we temporarily use the location property to
4706 // determine the image file name. This is subject to change
4707 // when iSCSI disks are here (we should either query a
4708 // storage-specific interface from IHardDisk, or "standardize"
4709 // the location property)
4710 hrc = hardDisk->COMGETTER(Location)(&str); H();
4711 STR_CONV();
4712 rc = CFGMR3InsertString(pCfg, "Path", psz); RC_CHECK();
4713 STR_FREE();
4714
4715 /* Create an inversed tree of parents. */
4716 ComPtr<IHardDisk> parentHardDisk = hardDisk;
4717 for (PCFGMNODE pParent = pCfg;;)
4718 {
4719 ComPtr<IHardDisk> curHardDisk;
4720 hrc = parentHardDisk->COMGETTER(Parent)(curHardDisk.asOutParam()); H();
4721 if (!curHardDisk)
4722 break;
4723
4724 PCFGMNODE pCur;
4725 rc = CFGMR3InsertNode(pParent, "Parent", &pCur); RC_CHECK();
4726 /// @todo (dmik) we temporarily use the location property to
4727 // determine the image file name. This is subject to change
4728 // when iSCSI disks are here (we should either query a
4729 // storage-specific interface from IHardDisk, or "standardize"
4730 // the location property)
4731 hrc = curHardDisk->COMGETTER(Location)(&str); H();
4732 STR_CONV();
4733 rc = CFGMR3InsertString(pCur, "Path", psz); RC_CHECK();
4734 STR_FREE();
4735
4736 /* next */
4737 pParent = pCur;
4738 parentHardDisk = curHardDisk;
4739 }
4740 }
4741 else if (hddType == HardDiskStorageType_ISCSIHardDisk)
4742 {
4743 ComPtr<IISCSIHardDisk> iSCSIDisk = hardDisk;
4744
4745 rc = CFGMR3InsertNode(pLunL0, "AttachedDriver", &pLunL1); RC_CHECK();
4746 rc = CFGMR3InsertString(pLunL1, "Driver", "iSCSI"); RC_CHECK();
4747 rc = CFGMR3InsertNode(pLunL1, "Config", &pCfg); RC_CHECK();
4748
4749 /* Set up the iSCSI initiator driver configuration. */
4750 hrc = iSCSIDisk->COMGETTER(Target)(&str); H();
4751 STR_CONV();
4752 rc = CFGMR3InsertString(pCfg, "TargetName", psz); RC_CHECK();
4753 STR_FREE();
4754
4755 // @todo currently there is no Initiator name config.
4756 rc = CFGMR3InsertString(pCfg, "InitiatorName", "iqn.2006-02.de.innotek.initiator"); RC_CHECK();
4757
4758 ULONG64 lun;
4759 hrc = iSCSIDisk->COMGETTER(Lun)(&lun); H();
4760 rc = CFGMR3InsertInteger(pCfg, "LUN", lun); RC_CHECK();
4761
4762 hrc = iSCSIDisk->COMGETTER(Server)(&str); H();
4763 STR_CONV();
4764 USHORT port;
4765 hrc = iSCSIDisk->COMGETTER(Port)(&port); H();
4766 if (port != 0)
4767 {
4768 char *pszTN;
4769 RTStrAPrintf(&pszTN, "%s:%u", psz, port);
4770 rc = CFGMR3InsertString(pCfg, "TargetAddress", pszTN); RC_CHECK();
4771 RTStrFree(pszTN);
4772 }
4773 else
4774 {
4775 rc = CFGMR3InsertString(pCfg, "TargetAddress", psz); RC_CHECK();
4776 }
4777 STR_FREE();
4778
4779 hrc = iSCSIDisk->COMGETTER(UserName)(&str); H();
4780 if (str)
4781 {
4782 STR_CONV();
4783 rc = CFGMR3InsertString(pCfg, "InitiatorUsername", psz); RC_CHECK();
4784 STR_FREE();
4785 }
4786
4787 hrc = iSCSIDisk->COMGETTER(Password)(&str); H();
4788 if (str)
4789 {
4790 STR_CONV();
4791 rc = CFGMR3InsertString(pCfg, "InitiatorSecret", psz); RC_CHECK();
4792 STR_FREE();
4793 }
4794
4795 // @todo currently there is no target username config.
4796 //rc = CFGMR3InsertString(pCfg, "TargetUsername", ""); RC_CHECK();
4797
4798 // @todo currently there is no target password config.
4799 //rc = CFGMR3InsertString(pCfg, "TargetSecret", ""); RC_CHECK();
4800
4801 /* The iSCSI initiator needs an attached iSCSI transport driver. */
4802 PCFGMNODE pLunL2 = NULL; /* /Devices/Dev/0/LUN#0/AttachedDriver/AttachedDriver */
4803 rc = CFGMR3InsertNode(pLunL1, "AttachedDriver", &pLunL2); RC_CHECK();
4804 rc = CFGMR3InsertString(pLunL2, "Driver", "iSCSITCP"); RC_CHECK();
4805 /* Currently the transport driver has no config options. */
4806 }
4807 else
4808 AssertFailed();
4809 }
4810 H();
4811
4812 ComPtr<IDVDDrive> dvdDrive;
4813 hrc = pMachine->COMGETTER(DVDDrive)(dvdDrive.asOutParam()); H();
4814 if (dvdDrive)
4815 {
4816 // ASSUME: DVD drive is always attached to LUN#2 (i.e. secondary IDE master)
4817 rc = CFGMR3InsertNode(pInst, "LUN#2", &pLunL0); RC_CHECK();
4818 ComPtr<IHostDVDDrive> hostDvdDrive;
4819 hrc = dvdDrive->GetHostDrive(hostDvdDrive.asOutParam()); H();
4820 if (hostDvdDrive)
4821 {
4822 pConsole->meDVDState = DriveState_HostDriveCaptured;
4823 rc = CFGMR3InsertString(pLunL0, "Driver", "HostDVD"); RC_CHECK();
4824 rc = CFGMR3InsertNode(pLunL0, "Config", &pCfg); RC_CHECK();
4825 hrc = hostDvdDrive->COMGETTER(Name)(&str); H();
4826 STR_CONV();
4827 rc = CFGMR3InsertString(pCfg, "Path", psz); RC_CHECK();
4828 STR_FREE();
4829 BOOL fPassthrough;
4830 hrc = dvdDrive->COMGETTER(Passthrough)(&fPassthrough); H();
4831 rc = CFGMR3InsertInteger(pCfg, "Passthrough", !!fPassthrough); RC_CHECK();
4832 }
4833 else
4834 {
4835 pConsole->meDVDState = DriveState_NotMounted;
4836 rc = CFGMR3InsertString(pLunL0, "Driver", "Block"); RC_CHECK();
4837 rc = CFGMR3InsertNode(pLunL0, "Config", &pCfg); RC_CHECK();
4838 rc = CFGMR3InsertString(pCfg, "Type", "DVD"); RC_CHECK();
4839 rc = CFGMR3InsertInteger(pCfg, "Mountable", 1); RC_CHECK();
4840
4841 ComPtr<IDVDImage> dvdImage;
4842 hrc = dvdDrive->GetImage(dvdImage.asOutParam()); H();
4843 if (dvdImage)
4844 {
4845 pConsole->meDVDState = DriveState_ImageMounted;
4846 rc = CFGMR3InsertNode(pLunL0, "AttachedDriver", &pLunL1); RC_CHECK();
4847 rc = CFGMR3InsertString(pLunL1, "Driver", "MediaISO"); RC_CHECK();
4848 rc = CFGMR3InsertNode(pLunL1, "Config", &pCfg); RC_CHECK();
4849 hrc = dvdImage->COMGETTER(FilePath)(&str); H();
4850 STR_CONV();
4851 rc = CFGMR3InsertString(pCfg, "Path", psz); RC_CHECK();
4852 STR_FREE();
4853 }
4854 }
4855 }
4856
4857 /*
4858 * Network adapters
4859 */
4860 rc = CFGMR3InsertNode(pDevices, "pcnet", &pDev); RC_CHECK();
4861 //rc = CFGMR3InsertNode(pDevices, "ne2000", &pDev); RC_CHECK();
4862 for (ULONG ulInstance = 0; ulInstance < SchemaDefs::NetworkAdapterCount; ulInstance++)
4863 {
4864 ComPtr<INetworkAdapter> networkAdapter;
4865 hrc = pMachine->GetNetworkAdapter(ulInstance, networkAdapter.asOutParam()); H();
4866 BOOL fEnabled = FALSE;
4867 hrc = networkAdapter->COMGETTER(Enabled)(&fEnabled); H();
4868 if (!fEnabled)
4869 continue;
4870
4871 char szInstance[4]; Assert(ulInstance <= 999);
4872 RTStrPrintf(szInstance, sizeof(szInstance), "%lu", ulInstance);
4873 rc = CFGMR3InsertNode(pDev, szInstance, &pInst); RC_CHECK();
4874 rc = CFGMR3InsertInteger(pInst, "Trusted", 1); /* boolean */ RC_CHECK();
4875 /* the first network card gets the PCI ID 3, the followings starting from 8 */
4876 rc = CFGMR3InsertInteger(pInst, "PCIDeviceNo", !ulInstance ? 3 : ulInstance - 1 + 8); RC_CHECK();
4877 rc = CFGMR3InsertInteger(pInst, "PCIFunctionNo", 0); RC_CHECK();
4878 rc = CFGMR3InsertNode(pInst, "Config", &pCfg); RC_CHECK();
4879
4880 /*
4881 * The virtual hardware type.
4882 */
4883 NetworkAdapterType_T adapterType;
4884 hrc = networkAdapter->COMGETTER(AdapterType)(&adapterType); H();
4885 switch (adapterType)
4886 {
4887 case NetworkAdapterType_NetworkAdapterAm79C970A:
4888 rc = CFGMR3InsertInteger(pCfg, "Am79C973", 0); RC_CHECK();
4889 break;
4890 case NetworkAdapterType_NetworkAdapterAm79C973:
4891 rc = CFGMR3InsertInteger(pCfg, "Am79C973", 1); RC_CHECK();
4892 break;
4893 default:
4894 AssertMsgFailed(("Invalid network adapter type '%d' for slot '%d'",
4895 adapterType, ulInstance));
4896 return VERR_GENERAL_FAILURE;
4897 }
4898
4899 /*
4900 * Get the MAC address and convert it to binary representation
4901 */
4902 Bstr macAddr;
4903 hrc = networkAdapter->COMGETTER(MACAddress)(macAddr.asOutParam()); H();
4904 Assert(macAddr);
4905 Utf8Str macAddrUtf8 = macAddr;
4906 char *macStr = (char*)macAddrUtf8.raw();
4907 Assert(strlen(macStr) == 12);
4908 PDMMAC Mac;
4909 memset(&Mac, 0, sizeof(Mac));
4910 char *pMac = (char*)&Mac;
4911 for (uint32_t i = 0; i < 6; i++)
4912 {
4913 char c1 = *macStr++ - '0';
4914 if (c1 > 9)
4915 c1 -= 7;
4916 char c2 = *macStr++ - '0';
4917 if (c2 > 9)
4918 c2 -= 7;
4919 *pMac++ = ((c1 & 0x0f) << 4) | (c2 & 0x0f);
4920 }
4921 rc = CFGMR3InsertBytes(pCfg, "MAC", &Mac, sizeof(Mac)); RC_CHECK();
4922
4923 /*
4924 * Check if the cable is supposed to be unplugged
4925 */
4926 BOOL fCableConnected;
4927 hrc = networkAdapter->COMGETTER(CableConnected)(&fCableConnected); H();
4928 rc = CFGMR3InsertInteger(pCfg, "CableConnected", fCableConnected ? 1 : 0); RC_CHECK();
4929
4930 /*
4931 * Attach the status driver.
4932 */
4933 rc = CFGMR3InsertNode(pInst, "LUN#999", &pLunL0); RC_CHECK();
4934 rc = CFGMR3InsertString(pLunL0, "Driver", "MainStatus"); RC_CHECK();
4935 rc = CFGMR3InsertNode(pLunL0, "Config", &pCfg); RC_CHECK();
4936 rc = CFGMR3InsertInteger(pCfg, "papLeds", (uintptr_t)&pConsole->mapNetworkLeds[ulInstance]); RC_CHECK();
4937
4938 /*
4939 * Enable the packet sniffer if requested.
4940 */
4941 BOOL fSniffer;
4942 hrc = networkAdapter->COMGETTER(TraceEnabled)(&fSniffer); H();
4943 if (fSniffer)
4944 {
4945 /* insert the sniffer filter driver. */
4946 rc = CFGMR3InsertNode(pInst, "LUN#0", &pLunL0); RC_CHECK();
4947 rc = CFGMR3InsertString(pLunL0, "Driver", "NetSniffer"); RC_CHECK();
4948 rc = CFGMR3InsertNode(pLunL0, "Config", &pCfg); RC_CHECK();
4949 hrc = networkAdapter->COMGETTER(TraceFile)(&str); H();
4950 if (str) /* check convention for indicating default file. */
4951 {
4952 STR_CONV();
4953 rc = CFGMR3InsertString(pCfg, "File", psz); RC_CHECK();
4954 STR_FREE();
4955 }
4956 }
4957
4958 NetworkAttachmentType_T networkAttachment;
4959 hrc = networkAdapter->COMGETTER(AttachmentType)(&networkAttachment); H();
4960 switch (networkAttachment)
4961 {
4962 case NetworkAttachmentType_NoNetworkAttachment:
4963 break;
4964
4965 case NetworkAttachmentType_NATNetworkAttachment:
4966 {
4967 if (fSniffer)
4968 {
4969 rc = CFGMR3InsertNode(pLunL0, "AttachedDriver", &pLunL0); RC_CHECK();
4970 }
4971 else
4972 {
4973 rc = CFGMR3InsertNode(pInst, "LUN#0", &pLunL0); RC_CHECK();
4974 }
4975 rc = CFGMR3InsertString(pLunL0, "Driver", "NAT"); RC_CHECK();
4976 rc = CFGMR3InsertNode(pLunL0, "Config", &pCfg); RC_CHECK();
4977 /* (Port forwarding goes here.) */
4978 break;
4979 }
4980
4981 case NetworkAttachmentType_HostInterfaceNetworkAttachment:
4982 {
4983 /*
4984 * Perform the attachment if required (don't return on error!)
4985 */
4986 hrc = pConsole->attachToHostInterface(networkAdapter);
4987 if (SUCCEEDED(hrc))
4988 {
4989#ifdef __LINUX__
4990 Assert (pConsole->maTapFD[ulInstance] >= 0);
4991 if (pConsole->maTapFD[ulInstance] >= 0)
4992 {
4993 if (fSniffer)
4994 {
4995 rc = CFGMR3InsertNode(pLunL0, "AttachedDriver", &pLunL0); RC_CHECK();
4996 }
4997 else
4998 {
4999 rc = CFGMR3InsertNode(pInst, "LUN#0", &pLunL0); RC_CHECK();
5000 }
5001 rc = CFGMR3InsertString(pLunL0, "Driver", "HostInterface"); RC_CHECK();
5002 rc = CFGMR3InsertNode(pLunL0, "Config", &pCfg); RC_CHECK();
5003 rc = CFGMR3InsertInteger(pCfg, "FileHandle", pConsole->maTapFD[ulInstance]); RC_CHECK();
5004 }
5005#else /* !__LINUX__ */
5006 if (fSniffer)
5007 {
5008 rc = CFGMR3InsertNode(pLunL0, "AttachedDriver", &pLunL0); RC_CHECK();
5009 }
5010 else
5011 {
5012 rc = CFGMR3InsertNode(pInst, "LUN#0", &pLunL0); RC_CHECK();
5013 }
5014 Bstr hostInterfaceName;
5015 hrc = networkAdapter->COMGETTER(HostInterface)(hostInterfaceName.asOutParam()); H();
5016 ComPtr<IHostNetworkInterfaceCollection> coll;
5017 hrc = host->COMGETTER(NetworkInterfaces)(coll.asOutParam()); H();
5018 ComPtr<IHostNetworkInterface> hostInterface;
5019 rc = coll->FindByName(hostInterfaceName, hostInterface.asOutParam());
5020 if (!SUCCEEDED(rc))
5021 {
5022 AssertMsgFailed(("Cannot get GUID for host interface '%ls'\n", hostInterfaceName));
5023 hrc = networkAdapter->Detach(); H();
5024 }
5025 else
5026 {
5027 rc = CFGMR3InsertString(pLunL0, "Driver", "HostInterface"); RC_CHECK();
5028 rc = CFGMR3InsertNode(pLunL0, "Config", &pCfg); RC_CHECK();
5029 rc = CFGMR3InsertString(pCfg, "HostInterfaceName", Utf8Str(hostInterfaceName)); RC_CHECK();
5030 Guid hostIFGuid;
5031 hrc = hostInterface->COMGETTER(Id)(hostIFGuid.asOutParam()); H();
5032 char szDriverGUID[256] = {0};
5033 /* add curly brackets */
5034 szDriverGUID[0] = '{';
5035 strcpy(szDriverGUID + 1, hostIFGuid.toString().raw());
5036 strcat(szDriverGUID, "}");
5037 rc = CFGMR3InsertBytes(pCfg, "GUID", szDriverGUID, sizeof(szDriverGUID)); RC_CHECK();
5038 }
5039#endif /* !__LINUX__ */
5040 }
5041 else
5042 {
5043 switch (hrc)
5044 {
5045#ifdef __LINUX__
5046 case VERR_ACCESS_DENIED:
5047 return VMSetError(pVM, VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_(
5048 "Failed to open '/dev/net/tun' for read/write access. Please check the "
5049 "permissions of that node. Either do 'chmod 0666 /dev/net/tun' or "
5050 "change the group of that node and get member of that group. Make "
5051 "sure that these changes are permanently in particular if you are "
5052 "using udev"));
5053#endif /* __LINUX__ */
5054 default:
5055 AssertMsgFailed(("Could not attach to host interface! Bad!\n"));
5056 return VMSetError(pVM, VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_(
5057 "Failed to initialize Host Interface Networking"));
5058 }
5059 }
5060 break;
5061 }
5062
5063 case NetworkAttachmentType_InternalNetworkAttachment:
5064 {
5065 hrc = networkAdapter->COMGETTER(InternalNetwork)(&str); H();
5066 STR_CONV();
5067 if (psz && *psz)
5068 {
5069 if (fSniffer)
5070 {
5071 rc = CFGMR3InsertNode(pLunL0, "AttachedDriver", &pLunL0); RC_CHECK();
5072 }
5073 else
5074 {
5075 rc = CFGMR3InsertNode(pInst, "LUN#0", &pLunL0); RC_CHECK();
5076 }
5077 rc = CFGMR3InsertString(pLunL0, "Driver", "IntNet"); RC_CHECK();
5078 rc = CFGMR3InsertNode(pLunL0, "Config", &pCfg); RC_CHECK();
5079 rc = CFGMR3InsertString(pCfg, "Network", psz); RC_CHECK();
5080 }
5081 STR_FREE();
5082 break;
5083 }
5084
5085 default:
5086 AssertMsgFailed(("should not get here!\n"));
5087 break;
5088 }
5089 }
5090
5091 /*
5092 * VMM Device
5093 */
5094 rc = CFGMR3InsertNode(pDevices, "VMMDev", &pDev); RC_CHECK();
5095 rc = CFGMR3InsertNode(pDev, "0", &pInst); RC_CHECK();
5096 rc = CFGMR3InsertNode(pInst, "Config", &pCfg); RC_CHECK();
5097 rc = CFGMR3InsertInteger(pInst, "Trusted", 1); /* boolean */ RC_CHECK();
5098 rc = CFGMR3InsertInteger(pInst, "PCIDeviceNo", 4); RC_CHECK();
5099 rc = CFGMR3InsertInteger(pInst, "PCIFunctionNo", 0); RC_CHECK();
5100
5101 /* the VMM device's Main driver */
5102 rc = CFGMR3InsertNode(pInst, "LUN#0", &pLunL0); RC_CHECK();
5103 rc = CFGMR3InsertString(pLunL0, "Driver", "MainVMMDev"); RC_CHECK();
5104 rc = CFGMR3InsertNode(pLunL0, "Config", &pCfg); RC_CHECK();
5105 VMMDev *pVMMDev = pConsole->mVMMDev;
5106 rc = CFGMR3InsertInteger(pCfg, "Object", (uintptr_t)pVMMDev); RC_CHECK();
5107
5108 /*
5109 * Audio Sniffer Device
5110 */
5111 rc = CFGMR3InsertNode(pDevices, "AudioSniffer", &pDev); RC_CHECK();
5112 rc = CFGMR3InsertNode(pDev, "0", &pInst); RC_CHECK();
5113 rc = CFGMR3InsertNode(pInst, "Config", &pCfg); RC_CHECK();
5114
5115 /* the Audio Sniffer device's Main driver */
5116 rc = CFGMR3InsertNode(pInst, "LUN#0", &pLunL0); RC_CHECK();
5117 rc = CFGMR3InsertString(pLunL0, "Driver", "MainAudioSniffer"); RC_CHECK();
5118 rc = CFGMR3InsertNode(pLunL0, "Config", &pCfg); RC_CHECK();
5119 AudioSniffer *pAudioSniffer = pConsole->mAudioSniffer;
5120 rc = CFGMR3InsertInteger(pCfg, "Object", (uintptr_t)pAudioSniffer); RC_CHECK();
5121
5122 /*
5123 * AC'97 ICH audio
5124 */
5125 ComPtr<IAudioAdapter> audioAdapter;
5126 hrc = pMachine->COMGETTER(AudioAdapter)(audioAdapter.asOutParam()); H();
5127 BOOL enabled = FALSE;
5128 if (audioAdapter)
5129 {
5130 hrc = audioAdapter->COMGETTER(Enabled)(&enabled); H();
5131 }
5132 if (enabled)
5133 {
5134 rc = CFGMR3InsertNode(pDevices, "ichac97", &pDev); /* ichac97 */
5135 rc = CFGMR3InsertNode(pDev, "0", &pInst);
5136 rc = CFGMR3InsertInteger(pInst, "Trusted", 1); /* boolean */ RC_CHECK();
5137 rc = CFGMR3InsertInteger(pInst, "PCIDeviceNo", 5); RC_CHECK();
5138 rc = CFGMR3InsertInteger(pInst, "PCIFunctionNo", 0); RC_CHECK();
5139 rc = CFGMR3InsertNode(pInst, "Config", &pCfg);
5140
5141 /* the Audio driver */
5142 rc = CFGMR3InsertNode(pInst, "LUN#0", &pLunL0); RC_CHECK();
5143 rc = CFGMR3InsertString(pLunL0, "Driver", "AUDIO"); RC_CHECK();
5144 rc = CFGMR3InsertNode(pLunL0, "Config", &pCfg); RC_CHECK();
5145 AudioDriverType_T audioDriver;
5146 hrc = audioAdapter->COMGETTER(AudioDriver)(&audioDriver); H();
5147 switch (audioDriver)
5148 {
5149 case AudioDriverType_NullAudioDriver:
5150 {
5151 rc = CFGMR3InsertString(pCfg, "AudioDriver", "null"); RC_CHECK();
5152 break;
5153 }
5154#ifdef __WIN__
5155 case AudioDriverType_WINMMAudioDriver:
5156 {
5157 rc = CFGMR3InsertString(pCfg, "AudioDriver", "winmm"); RC_CHECK();
5158 break;
5159 }
5160 case AudioDriverType_DSOUNDAudioDriver:
5161 {
5162 rc = CFGMR3InsertString(pCfg, "AudioDriver", "dsound"); RC_CHECK();
5163 break;
5164 }
5165#else /* !__WIN__ */
5166 case AudioDriverType_OSSAudioDriver:
5167 {
5168 rc = CFGMR3InsertString(pCfg, "AudioDriver", "oss"); RC_CHECK();
5169 break;
5170 }
5171#ifdef VBOX_WITH_ALSA
5172 case AudioDriverType_ALSAAudioDriver:
5173 {
5174 rc = CFGMR3InsertString(pCfg, "AudioDriver", "alsa"); RC_CHECK();
5175 break;
5176 }
5177#endif
5178#endif /* !__WIN__ */
5179 }
5180 }
5181
5182 /*
5183 * The USB Controller.
5184 */
5185 ComPtr<IUSBController> USBCtlPtr;
5186 hrc = pMachine->COMGETTER(USBController)(USBCtlPtr.asOutParam());
5187 if (USBCtlPtr)
5188 {
5189 BOOL fEnabled;
5190 hrc = USBCtlPtr->COMGETTER(Enabled)(&fEnabled); H();
5191 if (fEnabled)
5192 {
5193 rc = CFGMR3InsertNode(pDevices, "usb-ohci", &pDev); RC_CHECK();
5194 rc = CFGMR3InsertNode(pDev, "0", &pInst); RC_CHECK();
5195 rc = CFGMR3InsertNode(pInst, "Config", &pCfg); RC_CHECK();
5196 rc = CFGMR3InsertInteger(pInst, "Trusted", 1); /* boolean */ RC_CHECK();
5197 rc = CFGMR3InsertInteger(pInst, "PCIDeviceNo", 6); RC_CHECK();
5198 rc = CFGMR3InsertInteger(pInst, "PCIFunctionNo", 0); RC_CHECK();
5199
5200 rc = CFGMR3InsertNode(pInst, "LUN#0", &pLunL0); RC_CHECK();
5201 rc = CFGMR3InsertString(pLunL0, "Driver", "VUSBRootHub"); RC_CHECK();
5202 rc = CFGMR3InsertNode(pLunL0, "Config", &pCfg); RC_CHECK();
5203 }
5204 }
5205
5206 /*
5207 * Clipboard
5208 */
5209 {
5210 ClipboardMode_T mode = ClipboardMode_ClipDisabled;
5211 hrc = pMachine->COMGETTER(ClipboardMode) (&mode); H();
5212
5213 if (mode != ClipboardMode_ClipDisabled)
5214 {
5215 /* Load the service */
5216 rc = pConsole->mVMMDev->hgcmLoadService ("VBoxSharedClipboard", "VBoxSharedClipboard");
5217
5218 if (VBOX_FAILURE (rc))
5219 {
5220 LogRel(("VBoxSharedClipboard is not available. rc = %Vrc\n", rc));
5221 /* That is not a fatal failure. */
5222 rc = VINF_SUCCESS;
5223 }
5224 else
5225 {
5226 /* Setup the service. */
5227 VBOXHGCMSVCPARM parm;
5228
5229 parm.type = VBOX_HGCM_SVC_PARM_32BIT;
5230
5231 switch (mode)
5232 {
5233 default:
5234 case ClipboardMode_ClipDisabled:
5235 {
5236 LogRel(("VBoxSharedClipboard mode: Off\n"));
5237 parm.u.uint32 = VBOX_SHARED_CLIPBOARD_MODE_OFF;
5238 break;
5239 }
5240 case ClipboardMode_ClipGuestToHost:
5241 {
5242 LogRel(("VBoxSharedClipboard mode: Guest to Host\n"));
5243 parm.u.uint32 = VBOX_SHARED_CLIPBOARD_MODE_GUEST_TO_HOST;
5244 break;
5245 }
5246 case ClipboardMode_ClipHostToGuest:
5247 {
5248 LogRel(("VBoxSharedClipboard mode: Host to Guest\n"));
5249 parm.u.uint32 = VBOX_SHARED_CLIPBOARD_MODE_HOST_TO_GUEST;
5250 break;
5251 }
5252 case ClipboardMode_ClipBidirectional:
5253 {
5254 LogRel(("VBoxSharedClipboard mode: Bidirectional\n"));
5255 parm.u.uint32 = VBOX_SHARED_CLIPBOARD_MODE_BIDIRECTIONAL;
5256 break;
5257 }
5258 }
5259
5260 pConsole->mVMMDev->hgcmHostCall ("VBoxSharedClipboard", VBOX_SHARED_CLIPBOARD_HOST_FN_SET_MODE, 1, &parm);
5261
5262 Log(("Set VBoxSharedClipboard mode\n"));
5263 }
5264 }
5265 }
5266
5267 /*
5268 * CFGM overlay handling.
5269 *
5270 * Here we check the extra data entries for CFGM values
5271 * and create the nodes and insert the values on the fly. Existing
5272 * values will be removed and reinserted. If a value is a valid number,
5273 * it will be inserted as a number, otherwise as a string.
5274 *
5275 * We first perform a run on global extra data, then on the machine
5276 * extra data to support global settings with local overrides.
5277 *
5278 */
5279 Bstr strExtraDataKey;
5280 bool fGlobalExtraData = true;
5281 for (;;)
5282 {
5283 Bstr strNextExtraDataKey;
5284 Bstr strExtraDataValue;
5285
5286 /* get the next key */
5287 if (fGlobalExtraData)
5288 hrc = virtualBox->GetNextExtraDataKey(strExtraDataKey, strNextExtraDataKey.asOutParam(),
5289 strExtraDataValue.asOutParam());
5290 else
5291 hrc = pMachine->GetNextExtraDataKey(strExtraDataKey, strNextExtraDataKey.asOutParam(),
5292 strExtraDataValue.asOutParam());
5293
5294 /* stop if for some reason there's nothing more to request */
5295 if (FAILED(hrc) || !strNextExtraDataKey)
5296 {
5297 /* if we're out of global keys, continue with machine, otherwise we're done */
5298 if (fGlobalExtraData)
5299 {
5300 fGlobalExtraData = false;
5301 strExtraDataKey.setNull();
5302 continue;
5303 }
5304 break;
5305 }
5306
5307 strExtraDataKey = strNextExtraDataKey;
5308 Utf8Str strExtraDataKeyUtf8 = Utf8Str(strExtraDataKey);
5309
5310 /* we only care about keys starting with "VBoxInternal/" */
5311 if (strncmp(strExtraDataKeyUtf8.raw(), "VBoxInternal/", 13) != 0)
5312 continue;
5313 char *pszExtraDataKey = (char*)strExtraDataKeyUtf8.raw() + 13;
5314
5315 /* the key will be in the format "Node1/Node2/Value" */
5316 char *pszCFGMValueName = strrchr(pszExtraDataKey, '/');
5317 if (!pszCFGMValueName)
5318 continue;
5319 /* terminate the node and advance to the value */
5320 *pszCFGMValueName = '\0';
5321 pszCFGMValueName++;
5322
5323 PCFGMNODE pNode;
5324 /* does the node already exist? */
5325 pNode = CFGMR3GetChild(pRoot, pszExtraDataKey);
5326 if (pNode)
5327 {
5328 /* the value might already exist, remove it to be safe */
5329 CFGMR3RemoveValue(pNode, pszCFGMValueName);
5330 }
5331 else
5332 {
5333 /* create the node */
5334 rc = CFGMR3InsertNode(pRoot, pszExtraDataKey, &pNode);
5335 AssertMsgRC(rc, ("failed to insert node '%s'\n", pszExtraDataKey));
5336 if (VBOX_FAILURE(rc) || !pNode)
5337 continue;
5338 }
5339 /* now let's have a look at the value */
5340 Utf8Str strCFGMValueUtf8 = Utf8Str(strExtraDataValue);
5341 const char *pszCFGMValue = strCFGMValueUtf8.raw();
5342 /* empty value means remove value which we've already done */
5343 if (pszCFGMValue && *pszCFGMValue)
5344 {
5345 /* if it's a valid number, we'll insert it as such, otherwise string */
5346 uint64_t u64Value;
5347 if (RTStrToUInt64Ex(pszCFGMValue, NULL, 0, &u64Value) == VINF_SUCCESS)
5348 {
5349 rc = CFGMR3InsertInteger(pNode, pszCFGMValueName, u64Value);
5350 }
5351 else
5352 {
5353 rc = CFGMR3InsertString(pNode, pszCFGMValueName, pszCFGMValue);
5354 }
5355 AssertMsgRC(rc, ("failed to insert CFGM value '%s' to key '%s'\n", pszCFGMValue, pszExtraDataKey));
5356 }
5357 }
5358
5359#undef H
5360#undef RC_CHECK
5361#undef STR_FREE
5362#undef STR_CONV
5363
5364 /* Register VM state change handler */
5365 int rc2 = VMR3AtStateRegister (pVM, Console::vmstateChangeCallback, pConsole);
5366 AssertRC (rc2);
5367 if (VBOX_SUCCESS (rc))
5368 rc = rc2;
5369
5370 /* Register VM runtime error handler */
5371 rc2 = VMR3AtRuntimeErrorRegister (pVM, Console::setVMRuntimeErrorCallback, pConsole);
5372 AssertRC (rc2);
5373 if (VBOX_SUCCESS (rc))
5374 rc = rc2;
5375
5376 /* Save the VM pointer in the machine object */
5377 pConsole->mpVM = pVM;
5378
5379 LogFlowFunc (("vrc = %Vrc\n", rc));
5380 LogFlowFuncLeave();
5381
5382 return rc;
5383}
5384
5385/**
5386 * Helper function to handle host interface device creation and attachment.
5387 *
5388 * @param networkAdapter the network adapter which attachment should be reset
5389 * @return COM status code
5390 *
5391 * @note The caller must lock this object for writing.
5392 */
5393HRESULT Console::attachToHostInterface(INetworkAdapter *networkAdapter)
5394{
5395 /* sanity check */
5396 AssertReturn (isLockedOnCurrentThread(), E_FAIL);
5397
5398#ifdef DEBUG
5399 /* paranoia */
5400 NetworkAttachmentType_T attachment;
5401 networkAdapter->COMGETTER(AttachmentType)(&attachment);
5402 Assert(attachment == NetworkAttachmentType_HostInterfaceNetworkAttachment);
5403#endif /* DEBUG */
5404
5405 HRESULT rc = S_OK;
5406
5407#ifdef __LINUX__
5408 ULONG slot = 0;
5409 rc = networkAdapter->COMGETTER(Slot)(&slot);
5410 AssertComRC(rc);
5411
5412 /*
5413 * Try get the FD.
5414 */
5415 LONG ltapFD;
5416 rc = networkAdapter->COMGETTER(TAPFileDescriptor)(&ltapFD);
5417 if (SUCCEEDED(rc))
5418 maTapFD[slot] = (RTFILE)ltapFD;
5419 else
5420 maTapFD[slot] = NIL_RTFILE;
5421
5422 /*
5423 * Are we supposed to use an existing TAP interface?
5424 */
5425 if (maTapFD[slot] != NIL_RTFILE)
5426 {
5427 /* nothing to do */
5428 Assert(ltapFD >= 0);
5429 Assert((LONG)maTapFD[slot] == ltapFD);
5430 rc = S_OK;
5431 }
5432 else
5433#endif /* __LINUX */
5434 {
5435 /*
5436 * Allocate a host interface device
5437 */
5438#ifdef __WIN__
5439 /* nothing to do */
5440 int rcVBox = VINF_SUCCESS;
5441#elif defined(__LINUX__)
5442 int rcVBox = RTFileOpen(&maTapFD[slot], "/dev/net/tun",
5443 RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_NONE | RTFILE_O_INHERIT);
5444 if (VBOX_SUCCESS(rcVBox))
5445 {
5446 /*
5447 * Set/obtain the tap interface.
5448 */
5449 struct ifreq IfReq;
5450 memset(&IfReq, 0, sizeof(IfReq));
5451 Bstr tapDeviceName;
5452 rc = networkAdapter->COMGETTER(HostInterface)(tapDeviceName.asOutParam());
5453 if (FAILED(rc) || tapDeviceName.isEmpty())
5454 strcpy(IfReq.ifr_name, "tap%d");
5455 else
5456 {
5457 Utf8Str str(tapDeviceName);
5458 if (str.length() <= sizeof(IfReq.ifr_name))
5459 strcpy(IfReq.ifr_name, str.raw());
5460 else
5461 memcpy(IfReq.ifr_name, str.raw(), sizeof(IfReq.ifr_name) - 1); /** @todo bitch about names which are too long... */
5462 }
5463 IfReq.ifr_flags = IFF_TAP | IFF_NO_PI;
5464 rcVBox = ioctl(maTapFD[slot], TUNSETIFF, &IfReq);
5465 if (!rcVBox)
5466 {
5467 /*
5468 * Make it pollable.
5469 */
5470 if (fcntl(maTapFD[slot], F_SETFL, O_NONBLOCK) != -1)
5471 {
5472 tapDeviceName = IfReq.ifr_name;
5473 if (tapDeviceName)
5474 {
5475 Log(("attachToHostInterface: %RTfile %ls\n", maTapFD[slot], tapDeviceName.raw()));
5476
5477 /*
5478 * Here is the right place to communicate the TAP file descriptor and
5479 * the host interface name to the server if/when it becomes really
5480 * necessary.
5481 */
5482 maTAPDeviceName[slot] = tapDeviceName;
5483 rcVBox = VINF_SUCCESS;
5484 rc = S_OK;
5485 }
5486 else
5487 rcVBox = VERR_NO_MEMORY;
5488 }
5489 else
5490 {
5491 AssertMsgFailed(("Configuration error: Failed to configure /dev/net/tun non blocking. errno=%d\n", errno));
5492 rcVBox = VERR_HOSTIF_BLOCKING;
5493 rc = setError(E_FAIL, "Failed to set /dev/net/tun to non blocking. errno=%d\n", errno);
5494 }
5495 }
5496 else
5497 {
5498 AssertMsgFailed(("Configuration error: Failed to configure /dev/net/tun. errno=%d\n", errno));
5499 rcVBox = VERR_HOSTIF_IOCTL;
5500 rc = setError(E_FAIL, "Failed to configure /dev/net/tun. errno = %d\n", errno);
5501 }
5502 }
5503 else
5504 {
5505 AssertMsgFailed(("Configuration error: Failed to open /dev/net/tun rc=%Vrc\n", rcVBox));
5506 switch (rcVBox)
5507 {
5508 case VERR_ACCESS_DENIED:
5509 /* will be handled by our caller */
5510 LogRel(("HERE\n"));
5511 rc = rcVBox;
5512 break;
5513 default:
5514 rc = setError(E_FAIL, "Failed to open /dev/net/tun rc = %Vrc\n", rcVBox);
5515 break;
5516 }
5517 }
5518#elif
5519#error "Unknown host OS"
5520#endif
5521 /* in case of failure, cleanup. */
5522 if (VBOX_FAILURE(rcVBox) && SUCCEEDED(rc))
5523 {
5524 rc = setError(E_FAIL, tr ("General failure attaching to host interface"));
5525 }
5526 }
5527#ifdef __LINUX__
5528 if (SUCCEEDED(rc))
5529 {
5530 /*
5531 * Call the initialization program.
5532 *
5533 * The initialization program is passed the device name as the first param.
5534 * The second parameter is the decimal value of the file handle of the device
5535 * which it inherits.
5536 */
5537 Bstr tapSetupApplication;
5538 networkAdapter->COMGETTER(TAPSetupApplication)(tapSetupApplication.asOutParam());
5539 if (tapSetupApplication)
5540 {
5541 /*
5542 * Create the argument list.
5543 */
5544 const char *apszArgs[4];
5545 /* 0. The program name. */
5546 Utf8Str tapSetupApp(tapSetupApplication);
5547 apszArgs[0] = tapSetupApp.raw();
5548
5549 /* 1. The file descriptor. */
5550 char szFD[32];
5551 RTStrPrintf(szFD, sizeof(szFD), "%RTfile", maTapFD[slot]);
5552 apszArgs[1] = szFD;
5553
5554 /* 2. The device name (optional). */
5555 apszArgs[2] = maTAPDeviceName[slot].isEmpty() ? NULL : maTAPDeviceName[slot].raw();
5556
5557 /* 3. The end. */
5558 apszArgs[3] = NULL;
5559
5560 /*
5561 * Create the process and wait for it to complete.
5562 */
5563 RTPROCESS Process;
5564 int rcVBox = RTProcCreate(apszArgs[0], &apszArgs[0], NULL, 0, &Process);
5565 if (VBOX_SUCCESS(rcVBox))
5566 {
5567 /* wait for the process to exit */
5568 RTPROCSTATUS ProcStatus;
5569 rcVBox = RTProcWait(Process, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus);
5570 AssertRC(rcVBox);
5571 if (VBOX_SUCCESS(rcVBox))
5572 {
5573 if ( ProcStatus.enmReason == RTPROCEXITREASON_NORMAL
5574 && ProcStatus.iStatus == 0)
5575 rcVBox = VINF_SUCCESS;
5576 else
5577 rcVBox = VMSetError(mpVM, VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_("Failed to initialize Host Interface Networking"));
5578 }
5579 }
5580 else
5581 {
5582 AssertMsgFailed(("Configuration error: Failed to start init program \"%s\", rc=%Vra\n", tapSetupApp.raw(), rcVBox));
5583 rc = setError(E_FAIL, "Failed to start init program \"%s\", rc = %Vra\n", tapSetupApp.raw(), rcVBox);
5584 }
5585
5586 /* in case of failure, cleanup. */
5587 if (VBOX_FAILURE(rcVBox) && SUCCEEDED(rc))
5588 {
5589 rc = setError(E_FAIL, tr ("General failure configuring Host Interface Networking"));
5590 }
5591 }
5592 }
5593#endif /* __LINUX__ */
5594 return rc;
5595}
5596
5597/**
5598 * Helper function to handle detachment from a host interface
5599 *
5600 * @param networkAdapter the network adapter which attachment should be reset
5601 * @return COM status code
5602 *
5603 * @note The caller must lock this object for writing.
5604 */
5605HRESULT Console::detachFromHostInterface(INetworkAdapter *networkAdapter)
5606{
5607 /* sanity check */
5608 AssertReturn (isLockedOnCurrentThread(), E_FAIL);
5609
5610 HRESULT rc = S_OK;
5611#ifdef DEBUG
5612 /* paranoia */
5613 NetworkAttachmentType_T attachment;
5614 networkAdapter->COMGETTER(AttachmentType)(&attachment);
5615 Assert(attachment == NetworkAttachmentType_HostInterfaceNetworkAttachment);
5616#endif /* DEBUG */
5617
5618#ifdef __LINUX__
5619
5620 ULONG slot = 0;
5621 rc = networkAdapter->COMGETTER(Slot)(&slot);
5622 AssertComRC(rc);
5623
5624 /* is there an open TAP device? */
5625 if (maTapFD[slot] != NIL_RTFILE)
5626 {
5627 /*
5628 * Execute term command and close the file handle.
5629 */
5630 Bstr tapTerminateApplication;
5631 networkAdapter->COMGETTER(TAPTerminateApplication)(tapTerminateApplication.asOutParam());
5632 if (tapTerminateApplication)
5633 {
5634 /*
5635 * Create the argument list
5636 */
5637 const char *apszArgs[4];
5638 /* 0. The program name. */
5639 Utf8Str tapTermAppUtf8(tapTerminateApplication);
5640 apszArgs[0] = tapTermAppUtf8.raw();
5641
5642 /* 1. The file descriptor. */
5643 char szFD[32];
5644 RTStrPrintf(szFD, sizeof(szFD), "%RTfile", maTapFD[slot]);
5645 apszArgs[1] = szFD;
5646
5647 /* 2. Device name (optional). */
5648 apszArgs[2] = maTAPDeviceName[slot].isEmpty() ? NULL : maTAPDeviceName[slot].raw();
5649
5650 /* 3. The end. */
5651 apszArgs[3] = NULL;
5652
5653 /*
5654 * Create the process and wait for it to complete.
5655 */
5656 RTPROCESS Process;
5657 int rcVBox = RTProcCreate(apszArgs[0], &apszArgs[0], NULL, 0, &Process);
5658 if (VBOX_SUCCESS(rcVBox))
5659 {
5660 /* wait for the process to exit */
5661 RTPROCSTATUS ProcStatus;
5662 rcVBox = RTProcWait(Process, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus);
5663 AssertRC(rcVBox);
5664 /* ignore return code? */
5665 }
5666 else
5667 AssertMsgFailed(("Configuration error: Failed to start terminate program \"%s\", rc=%Vra\n", apszArgs[0], rcVBox)); /** @todo last error candidate. */
5668 if (VBOX_FAILURE(rcVBox))
5669 rc = E_FAIL;
5670 }
5671
5672 /*
5673 * Now we can close the file handle.
5674 */
5675 int rcVBox = RTFileClose(maTapFD[slot]);
5676 AssertRC(rcVBox);
5677 /* the TAP device name and handle are no longer valid */
5678 maTapFD[slot] = NIL_RTFILE;
5679 maTAPDeviceName[slot] = "";
5680 }
5681#endif
5682 return rc;
5683}
5684
5685
5686/**
5687 * Called at power down to terminate host interface networking.
5688 *
5689 * @note The caller must lock this object for writing.
5690 */
5691HRESULT Console::powerDownHostInterfaces()
5692{
5693 LogFlowThisFunc (("\n"));
5694
5695 /* sanity check */
5696 AssertReturn (isLockedOnCurrentThread(), E_FAIL);
5697
5698 /*
5699 * host interface termination handling
5700 */
5701 HRESULT rc;
5702 for (ULONG slot = 0; slot < SchemaDefs::NetworkAdapterCount; slot ++)
5703 {
5704 ComPtr<INetworkAdapter> networkAdapter;
5705 rc = mMachine->GetNetworkAdapter(slot, networkAdapter.asOutParam());
5706 CheckComRCBreakRC (rc);
5707
5708 BOOL enabled = FALSE;
5709 networkAdapter->COMGETTER(Enabled) (&enabled);
5710 if (!enabled)
5711 continue;
5712
5713 NetworkAttachmentType_T attachment;
5714 networkAdapter->COMGETTER(AttachmentType)(&attachment);
5715 if (attachment == NetworkAttachmentType_HostInterfaceNetworkAttachment)
5716 {
5717 HRESULT rc2 = detachFromHostInterface(networkAdapter);
5718 if (FAILED(rc2) && SUCCEEDED(rc))
5719 rc = rc2;
5720 }
5721 }
5722
5723 return rc;
5724}
5725
5726
5727/**
5728 * Process callback handler for VMR3Load and VMR3Save.
5729 *
5730 * @param pVM The VM handle.
5731 * @param uPercent Completetion precentage (0-100).
5732 * @param pvUser Pointer to the VMProgressTask structure.
5733 * @return VINF_SUCCESS.
5734 */
5735/*static*/ DECLCALLBACK (int)
5736Console::stateProgressCallback (PVM pVM, unsigned uPercent, void *pvUser)
5737{
5738 VMProgressTask *task = static_cast <VMProgressTask *> (pvUser);
5739 AssertReturn (task, VERR_INVALID_PARAMETER);
5740
5741 /* update the progress object */
5742 if (task->mProgress)
5743 task->mProgress->notifyProgress (uPercent);
5744
5745 return VINF_SUCCESS;
5746}
5747
5748/**
5749 * VM error callback function. Called by the various VM components.
5750 *
5751 * @param pVM The VM handle. Can be NULL if an error occurred before
5752 * successfully creating a VM.
5753 * @param pvUser Pointer to the VMProgressTask structure.
5754 * @param rc VBox status code.
5755 * @param pszFormat The error message.
5756 * @thread EMT.
5757 */
5758/* static */ DECLCALLBACK (void)
5759Console::setVMErrorCallback (PVM pVM, void *pvUser, int rc, RT_SRC_POS_DECL,
5760 const char *pszFormat, va_list args)
5761{
5762 VMProgressTask *task = static_cast <VMProgressTask *> (pvUser);
5763 AssertReturnVoid (task);
5764
5765 /* we ignore RT_SRC_POS_DECL arguments to avoid confusion of end-users */
5766 HRESULT hrc = setError (E_FAIL, tr ("%N.\n"
5767 "VBox status code: %d (%Vrc)"),
5768 tr (pszFormat), &args,
5769 rc, rc);
5770 task->mProgress->notifyComplete (hrc);
5771}
5772
5773/**
5774 * VM runtime error callback function.
5775 * See VMSetRuntimeError for the detailed description of parameters.
5776 *
5777 * @param pVM The VM handle.
5778 * @param pvUser The user argument.
5779 * @param fFatal Whether it is a fatal error or not.
5780 * @param pszErrorID Error ID string.
5781 * @param pszFormat Error message format string.
5782 * @param args Error message arguments.
5783 * @thread EMT.
5784 */
5785/* static */ DECLCALLBACK(void)
5786Console::setVMRuntimeErrorCallback (PVM pVM, void *pvUser, bool fFatal,
5787 const char *pszErrorID,
5788 const char *pszFormat, va_list args)
5789{
5790 LogFlowFuncEnter();
5791
5792 Console *that = static_cast <Console *> (pvUser);
5793 AssertReturnVoid (that);
5794
5795 Utf8Str message = Utf8StrFmt (pszFormat, args);
5796
5797 LogRel (("Console: VM runtime error: fatal=%RTbool, "
5798 "errorID=%s message=\"%s\"\n",
5799 fFatal, pszErrorID, message.raw()));
5800
5801 that->onRuntimeError (BOOL (fFatal), Bstr (pszErrorID), Bstr (message));
5802
5803 LogFlowFuncLeave();
5804}
5805
5806/**
5807 * Captures and attaches USB devices to a newly created VM.
5808 *
5809 * @param pVM The VM handle.
5810 *
5811 * @note The caller must lock this object for writing.
5812 */
5813HRESULT Console::captureUSBDevices (PVM pVM)
5814{
5815 LogFlowThisFunc (("\n"));
5816
5817 /* sanity check */
5818 ComAssertRet (isLockedOnCurrentThread(), E_FAIL);
5819
5820 /*
5821 * If the machine has an USB controller, capture devices and attach
5822 * them to it.
5823 */
5824 PPDMIBASE pBase;
5825 int vrc = PDMR3QueryLun (pVM, "usb-ohci", 0, 0, &pBase);
5826 if (VBOX_SUCCESS (vrc))
5827 {
5828 PVUSBIRHCONFIG pRhConfig = (PVUSBIRHCONFIG) pBase->
5829 pfnQueryInterface (pBase, PDMINTERFACE_VUSB_RH_CONFIG);
5830 ComAssertRet (pRhConfig, E_FAIL);
5831
5832 /*
5833 * Get the list of USB devices that should be captured and attached to
5834 * the newly created machine.
5835 */
5836 ComPtr <IUSBDeviceCollection> coll;
5837 HRESULT hrc = mControl->AutoCaptureUSBDevices (coll.asOutParam());
5838 ComAssertComRCRetRC (hrc);
5839
5840 /*
5841 * Enumerate the devices and attach them.
5842 * Failing to attach an device is currently ignored and the device
5843 * released.
5844 */
5845 ComPtr <IUSBDeviceEnumerator> en;
5846 hrc = coll->Enumerate (en.asOutParam());
5847 ComAssertComRCRetRC (hrc);
5848
5849 BOOL hasMore = FALSE;
5850 while (SUCCEEDED (en->HasMore (&hasMore)) && hasMore)
5851 {
5852 ComPtr <IUSBDevice> hostDevice;
5853 hrc = en->GetNext (hostDevice.asOutParam());
5854 ComAssertComRCRetRC (hrc);
5855 ComAssertRet (!hostDevice.isNull(), E_FAIL);
5856
5857 hrc = attachUSBDevice (hostDevice, true /* aManual */, pRhConfig);
5858
5859 /// @todo (r=dmik) warning reporting subsystem
5860 }
5861 }
5862 else if ( vrc == VERR_PDM_DEVICE_NOT_FOUND
5863 || vrc == VERR_PDM_DEVICE_INSTANCE_NOT_FOUND)
5864 vrc = VINF_SUCCESS;
5865 else
5866 AssertRC (vrc);
5867
5868 return VBOX_SUCCESS (vrc) ? S_OK : E_FAIL;
5869}
5870
5871
5872/**
5873 * Releases all USB device which is attached to the VM for the
5874 * purpose of clean up and such like.
5875 *
5876 * @note The caller must lock this object for writing.
5877 */
5878void Console::releaseAllUSBDevices (void)
5879{
5880 LogFlowThisFunc (("\n"));
5881
5882 /* sanity check */
5883 AssertReturnVoid (isLockedOnCurrentThread());
5884
5885 mControl->ReleaseAllUSBDevices();
5886 mUSBDevices.clear();
5887}
5888
5889/**
5890 * @note Locks this object for writing.
5891 */
5892#ifdef VRDP_MC
5893void Console::processRemoteUSBDevices (uint32_t u32ClientId, VRDPUSBDEVICEDESC *pDevList, uint32_t cbDevList)
5894#else
5895void Console::processRemoteUSBDevices (VRDPUSBDEVICEDESC *pDevList, uint32_t cbDevList)
5896#endif /* VRDP_MC */
5897{
5898 LogFlowThisFuncEnter();
5899#ifdef VRDP_MC
5900 LogFlowThisFunc (("u32ClientId = %d, pDevList=%p, cbDevList = %d\n", u32ClientId, pDevList, cbDevList));
5901#else
5902 LogFlowThisFunc (("pDevList=%p, cbDevList = %d\n", pDevList, cbDevList));
5903#endif /* VRDP_MC */
5904
5905 AutoCaller autoCaller (this);
5906 if (!autoCaller.isOk())
5907 {
5908 /* Console has been already uninitialized, deny request */
5909 AssertMsgFailed (("Temporary assertion to prove that it happens, "
5910 "please report to dmik\n"));
5911 LogFlowThisFunc (("Console is already uninitialized\n"));
5912 LogFlowThisFuncLeave();
5913 return;
5914 }
5915
5916 AutoLock alock (this);
5917
5918 /*
5919 * Mark all existing remote USB devices as dirty.
5920 */
5921 RemoteUSBDeviceList::iterator it = mRemoteUSBDevices.begin();
5922 while (it != mRemoteUSBDevices.end())
5923 {
5924 (*it)->dirty (true);
5925 ++ it;
5926 }
5927
5928 /*
5929 * Process the pDevList and add devices those are not already in the mRemoteUSBDevices list.
5930 */
5931 /** @todo (sunlover) REMOTE_USB Strict validation of the pDevList. */
5932 VRDPUSBDEVICEDESC *e = pDevList;
5933
5934 /* The cbDevList condition must be checked first, because the function can
5935 * receive pDevList = NULL and cbDevList = 0 on client disconnect.
5936 */
5937 while (cbDevList >= 2 && e->oNext)
5938 {
5939 LogFlowThisFunc (("vendor %04X, product %04X, name = %s\n",
5940 e->idVendor, e->idProduct,
5941 e->oProduct? (char *)e + e->oProduct: ""));
5942
5943 bool fNewDevice = true;
5944
5945 it = mRemoteUSBDevices.begin();
5946 while (it != mRemoteUSBDevices.end())
5947 {
5948#ifdef VRDP_MC
5949 if ((*it)->devId () == e->id
5950 && (*it)->clientId () == u32ClientId)
5951#else
5952 if ((*it)->devId () == e->id)
5953#endif /* VRDP_MC */
5954 {
5955 /* The device is already in the list. */
5956 (*it)->dirty (false);
5957 fNewDevice = false;
5958 break;
5959 }
5960
5961 ++ it;
5962 }
5963
5964 if (fNewDevice)
5965 {
5966 LogRel(("Remote USB: ++++ Vendor %04X. Product %04X. Name = [%s].\n",
5967 e->idVendor, e->idProduct, e->oProduct? (char *)e + e->oProduct: ""
5968 ));
5969
5970 /* Create the device object and add the new device to list. */
5971 ComObjPtr <RemoteUSBDevice> device;
5972 device.createObject();
5973#ifdef VRDP_MC
5974 device->init (u32ClientId, e);
5975#else
5976 device->init (e);
5977#endif /* VRDP_MC */
5978
5979 mRemoteUSBDevices.push_back (device);
5980
5981 /* Check if the device is ok for current USB filters. */
5982 BOOL fMatched = FALSE;
5983
5984 HRESULT hrc = mControl->RunUSBDeviceFilters(device, &fMatched);
5985
5986 AssertComRC (hrc);
5987
5988 LogFlowThisFunc (("USB filters return %d\n", fMatched));
5989
5990 if (fMatched)
5991 {
5992 hrc = onUSBDeviceAttach(device);
5993
5994 /// @todo (r=dmik) warning reporting subsystem
5995
5996 if (hrc == S_OK)
5997 {
5998 LogFlowThisFunc (("Device attached\n"));
5999 device->captured (true);
6000 }
6001 }
6002 }
6003
6004 if (cbDevList < e->oNext)
6005 {
6006 LogWarningThisFunc (("cbDevList %d > oNext %d\n",
6007 cbDevList, e->oNext));
6008 break;
6009 }
6010
6011 cbDevList -= e->oNext;
6012
6013 e = (VRDPUSBDEVICEDESC *)((uint8_t *)e + e->oNext);
6014 }
6015
6016 /*
6017 * Remove dirty devices, that is those which are not reported by the server anymore.
6018 */
6019 for (;;)
6020 {
6021 ComObjPtr <RemoteUSBDevice> device;
6022
6023 RemoteUSBDeviceList::iterator it = mRemoteUSBDevices.begin();
6024 while (it != mRemoteUSBDevices.end())
6025 {
6026 if ((*it)->dirty ())
6027 {
6028 device = *it;
6029 break;
6030 }
6031
6032 ++ it;
6033 }
6034
6035 if (!device)
6036 {
6037 break;
6038 }
6039
6040 USHORT vendorId = 0;
6041 device->COMGETTER(VendorId) (&vendorId);
6042
6043 USHORT productId = 0;
6044 device->COMGETTER(ProductId) (&productId);
6045
6046 Bstr product;
6047 device->COMGETTER(Product) (product.asOutParam());
6048
6049 LogRel(("Remote USB: ---- Vendor %04X. Product %04X. Name = [%ls].\n",
6050 vendorId, productId, product.raw ()
6051 ));
6052
6053 /* Detach the device from VM. */
6054 if (device->captured ())
6055 {
6056 Guid uuid;
6057 device->COMGETTER (Id) (uuid.asOutParam());
6058 onUSBDeviceDetach (uuid);
6059 }
6060
6061 /* And remove it from the list. */
6062 mRemoteUSBDevices.erase (it);
6063 }
6064
6065 LogFlowThisFuncLeave();
6066}
6067
6068
6069
6070/**
6071 * Thread function which starts the VM (also from saved state) and
6072 * track progress.
6073 *
6074 * @param Thread The thread id.
6075 * @param pvUser Pointer to a VMPowerUpTask structure.
6076 * @return VINF_SUCCESS (ignored).
6077 *
6078 * @note Locks the Console object for writing.
6079 */
6080/*static*/
6081DECLCALLBACK (int) Console::powerUpThread (RTTHREAD Thread, void *pvUser)
6082{
6083 LogFlowFuncEnter();
6084
6085 std::auto_ptr <VMPowerUpTask> task (static_cast <VMPowerUpTask *> (pvUser));
6086 AssertReturn (task.get(), VERR_INVALID_PARAMETER);
6087
6088 AssertReturn (!task->mConsole.isNull(), VERR_INVALID_PARAMETER);
6089 AssertReturn (!task->mProgress.isNull(), VERR_INVALID_PARAMETER);
6090
6091#if defined(__WIN__)
6092 {
6093 /* initialize COM */
6094 HRESULT hrc = CoInitializeEx (NULL,
6095 COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE |
6096 COINIT_SPEED_OVER_MEMORY);
6097 LogFlowFunc (("CoInitializeEx()=%08X\n", hrc));
6098 }
6099#endif
6100
6101 HRESULT hrc = S_OK;
6102 int vrc = VINF_SUCCESS;
6103
6104 ComObjPtr <Console> console = task->mConsole;
6105
6106 /* Note: no need to use addCaller() because VMPowerUpTask does that */
6107
6108 AutoLock alock (console);
6109
6110 /* sanity */
6111 Assert (console->mpVM == NULL);
6112
6113 do
6114 {
6115 /*
6116 * Initialize the release logging facility. In case something
6117 * goes wrong, there will be no release logging. Maybe in the future
6118 * we can add some logic to use different file names in this case.
6119 * Note that the logic must be in sync with Machine::DeleteSettings().
6120 */
6121
6122 Bstr logFolder;
6123 hrc = console->mControl->GetLogFolder (logFolder.asOutParam());
6124 CheckComRCBreakRC (hrc);
6125
6126 Utf8Str logDir = logFolder;
6127
6128 /* make sure the Logs folder exists */
6129 Assert (!logDir.isEmpty());
6130 if (!RTDirExists (logDir))
6131 RTDirCreateFullPath (logDir, 0777);
6132
6133 Utf8Str logFile = Utf8StrFmt ("%s%cVBox.log",
6134 logDir.raw(), RTPATH_DELIMITER);
6135
6136 /*
6137 * Age the old log files
6138 * Rename .2 to .3, .1 to .2 and the last log file to .1
6139 * Overwrite target files in case they exist;
6140 */
6141 for (int i = 2; i >= 0; i--)
6142 {
6143 Utf8Str oldName;
6144 if (i > 0)
6145 oldName = Utf8StrFmt ("%s.%d", logFile.raw(), i);
6146 else
6147 oldName = logFile;
6148 Utf8Str newName = Utf8StrFmt ("%s.%d", logFile.raw(), i + 1);
6149 RTFileRename(oldName.raw(), newName.raw(), RTFILEMOVE_FLAGS_REPLACE);
6150 }
6151
6152 PRTLOGGER loggerRelease;
6153 static const char * const s_apszGroups[] = VBOX_LOGGROUP_NAMES;
6154 vrc = RTLogCreate(&loggerRelease, RTLOGFLAGS_PREFIX_TIME_PROG, "all",
6155 "VBOX_RELEASE_LOG", ELEMENTS(s_apszGroups), s_apszGroups,
6156 RTLOGDEST_FILE, logFile.raw());
6157 if (VBOX_SUCCESS(vrc))
6158 {
6159 /* some introductory information */
6160 RTTIMESPEC timeSpec;
6161 char nowUct[64];
6162 RTTimeSpecToString(RTTimeNow(&timeSpec), nowUct, sizeof(nowUct));
6163 RTLogRelLogger(loggerRelease, 0, ~0U,
6164 "VirtualBox %d.%d.%d (%s %s) release log\n"
6165 "Log opened %s\n",
6166 VBOX_VERSION_MAJOR, VBOX_VERSION_MINOR, VBOX_VERSION_BUILD,
6167 __DATE__, __TIME__,
6168 nowUct);
6169
6170 /* register this logger as the release logger */
6171 RTLogRelSetDefaultInstance(loggerRelease);
6172 }
6173 else
6174 {
6175 hrc = setError (E_FAIL,
6176 tr ("Failed to open release log file '%s' (%Vrc)"),
6177 logFile.raw(), vrc);
6178 break;
6179 }
6180
6181#ifdef VBOX_VRDP
6182 if (VBOX_SUCCESS (vrc))
6183 {
6184 /* Create the VRDP server. In case of headless operation, this will
6185 * also create the framebuffer, required at VM creation.
6186 */
6187 ConsoleVRDPServer *server = console->consoleVRDPServer();
6188 Assert (server);
6189 /// @todo (dmik)
6190 // does VRDP server call Console from the other thread?
6191 // Not sure, so leave the lock just in case
6192 alock.leave();
6193 vrc = server->Launch();
6194 alock.enter();
6195 if (VBOX_FAILURE (vrc))
6196 {
6197 Utf8Str errMsg;
6198 switch (vrc)
6199 {
6200 case VERR_NET_ADDRESS_IN_USE:
6201 {
6202 ULONG port = 0;
6203 console->mVRDPServer->COMGETTER(Port) (&port);
6204 errMsg = Utf8StrFmt (tr ("VRDP server port %d is already in use"),
6205 port);
6206 break;
6207 }
6208 default:
6209 errMsg = Utf8StrFmt (tr ("Failed to launch VRDP server (%Vrc)"),
6210 vrc);
6211 }
6212 LogRel (("Failed to launch VRDP server (%Vrc), error message: '%s'\n",
6213 vrc, errMsg.raw()));
6214 hrc = setError (E_FAIL, errMsg);
6215 break;
6216 }
6217 }
6218#endif /* VBOX_VRDP */
6219
6220 /*
6221 * Create the VM
6222 */
6223 PVM pVM;
6224 /*
6225 * leave the lock since EMT will call Console. It's safe because
6226 * mMachineState is either Starting or Restoring state here.
6227 */
6228 alock.leave();
6229
6230 vrc = VMR3Create (task->mSetVMErrorCallback, task.get(),
6231 task->mConfigConstructor, task.get(),
6232 &pVM);
6233
6234 alock.enter();
6235
6236#ifdef VBOX_VRDP
6237 {
6238 /* Enable client connections to the server. */
6239 ConsoleVRDPServer *server = console->consoleVRDPServer();
6240 server->SetCallback ();
6241 }
6242#endif /* VBOX_VRDP */
6243
6244 if (VBOX_SUCCESS (vrc))
6245 {
6246 do
6247 {
6248 /*
6249 * Register our load/save state file handlers
6250 */
6251 vrc = SSMR3RegisterExternal (pVM,
6252 sSSMConsoleUnit, 0 /* iInstance */, sSSMConsoleVer,
6253 0 /* cbGuess */,
6254 NULL, saveStateFileExec, NULL, NULL, loadStateFileExec, NULL,
6255 static_cast <Console *> (console));
6256 AssertRC (vrc);
6257 if (VBOX_FAILURE (vrc))
6258 break;
6259
6260 /*
6261 * Synchronize debugger settings
6262 */
6263 MachineDebugger *machineDebugger = console->getMachineDebugger();
6264 if (machineDebugger)
6265 {
6266 machineDebugger->flushQueuedSettings();
6267 }
6268
6269 if (console->getVMMDev()->getShFlClientId())
6270 {
6271 /// @todo (dmik)
6272 // does the code below call Console from the other thread?
6273 // Not sure, so leave the lock just in case
6274 alock.leave();
6275
6276 /*
6277 * Shared Folders
6278 */
6279 for (std::map <Bstr, ComPtr <ISharedFolder> >::const_iterator
6280 it = task->mSharedFolders.begin();
6281 it != task->mSharedFolders.end();
6282 ++ it)
6283 {
6284 Bstr name = (*it).first;
6285 ComPtr <ISharedFolder> folder = (*it).second;
6286
6287 Bstr hostPath;
6288 hrc = folder->COMGETTER(HostPath) (hostPath.asOutParam());
6289 CheckComRCBreakRC (hrc);
6290
6291 LogFlowFunc (("Adding shared folder '%ls' -> '%ls'\n",
6292 name.raw(), hostPath.raw()));
6293 ComAssertBreak (!name.isEmpty() && !hostPath.isEmpty(),
6294 hrc = E_FAIL);
6295
6296 /** @todo should move this into the shared folder class */
6297 VBOXHGCMSVCPARM parms[2];
6298 SHFLSTRING *pFolderName, *pMapName;
6299 int cbString;
6300
6301 cbString = (hostPath.length() + 1) * sizeof(RTUCS2);
6302 pFolderName = (SHFLSTRING *)RTMemAllocZ(sizeof(SHFLSTRING) + cbString);
6303 Assert(pFolderName);
6304 memcpy(pFolderName->String.ucs2, hostPath.raw(), cbString);
6305
6306 pFolderName->u16Size = cbString;
6307 pFolderName->u16Length = cbString - sizeof(RTUCS2);
6308
6309 parms[0].type = VBOX_HGCM_SVC_PARM_PTR;
6310 parms[0].u.pointer.addr = pFolderName;
6311 parms[0].u.pointer.size = sizeof(SHFLSTRING) + cbString;
6312
6313 cbString = (name.length() + 1) * sizeof(RTUCS2);
6314 pMapName = (SHFLSTRING *)RTMemAllocZ(sizeof(SHFLSTRING) + cbString);
6315 Assert(pMapName);
6316 memcpy(pMapName->String.ucs2, name.raw(), cbString);
6317
6318 pMapName->u16Size = cbString;
6319 pMapName->u16Length = cbString - sizeof(RTUCS2);
6320
6321 parms[1].type = VBOX_HGCM_SVC_PARM_PTR;
6322 parms[1].u.pointer.addr = pMapName;
6323 parms[1].u.pointer.size = sizeof(SHFLSTRING) + cbString;
6324
6325 vrc = console->getVMMDev()->hgcmHostCall("VBoxSharedFolders",
6326 SHFL_FN_ADD_MAPPING, 2, &parms[0]);
6327
6328 RTMemFree(pFolderName);
6329 RTMemFree(pMapName);
6330
6331 if (VBOX_FAILURE (vrc))
6332 {
6333 hrc = setError (E_FAIL,
6334 tr ("Unable to add mapping '%ls' to '%ls' (%Vrc)"),
6335 hostPath.raw(), name.raw(), vrc);
6336 break;
6337 }
6338 }
6339
6340 /* enter the lock again */
6341 alock.enter();
6342
6343 CheckComRCBreakRC (hrc);
6344 }
6345
6346 /*
6347 * Capture USB devices.
6348 */
6349 hrc = console->captureUSBDevices (pVM);
6350 CheckComRCBreakRC (hrc);
6351
6352 /* leave the lock before a lengthy operation */
6353 alock.leave();
6354
6355 /* Load saved state? */
6356 if (!!task->mSavedStateFile)
6357 {
6358 LogFlowFunc (("Restoring saved state from '%s'...\n",
6359 task->mSavedStateFile.raw()));
6360
6361 vrc = VMR3Load (pVM, task->mSavedStateFile,
6362 Console::stateProgressCallback,
6363 static_cast <VMProgressTask *> (task.get()));
6364
6365 /* Start/Resume the VM execution */
6366 if (VBOX_SUCCESS (vrc))
6367 {
6368 vrc = VMR3Resume (pVM);
6369 AssertRC (vrc);
6370 }
6371
6372 /* Power off in case we failed loading or resuming the VM */
6373 if (VBOX_FAILURE (vrc))
6374 {
6375 int vrc2 = VMR3PowerOff (pVM);
6376 AssertRC (vrc2);
6377 }
6378 }
6379 else
6380 {
6381 /* Power on the VM (i.e. start executing) */
6382 vrc = VMR3PowerOn(pVM);
6383 AssertRC (vrc);
6384 }
6385
6386 /* enter the lock again */
6387 alock.enter();
6388 }
6389 while (0);
6390
6391 /* On failure, destroy the VM */
6392 if (FAILED (hrc) || VBOX_FAILURE (vrc))
6393 {
6394 /* preserve the current error info */
6395 ErrorInfo ei;
6396
6397 /*
6398 * powerDown() will call VMR3Destroy() and do all necessary
6399 * cleanup (VRDP, USB devices)
6400 */
6401 HRESULT hrc2 = console->powerDown();
6402 AssertComRC (hrc2);
6403
6404 setError (ei);
6405 }
6406 }
6407 else
6408 {
6409 /*
6410 * If VMR3Create() failed it has released the VM memory.
6411 */
6412 console->mpVM = NULL;
6413 }
6414
6415 if (SUCCEEDED (hrc) && VBOX_FAILURE (vrc))
6416 {
6417 /*
6418 * If VMR3Create() or one of the other calls in this function fail,
6419 * an appropriate error message has been already set. However since
6420 * that happens via a callback, the status code in this function is
6421 * not updated.
6422 */
6423 if (!task->mProgress->completed())
6424 {
6425 /*
6426 * If the COM error info is not yet set but we've got a
6427 * failure, convert the VBox status code into a meaningful
6428 * error message. This becomes unused once all the sources of
6429 * errors set the appropriate error message themselves.
6430 * Note that we don't use VMSetError() below because pVM is
6431 * either invalid or NULL here.
6432 */
6433 AssertMsgFailed (("Missing error message during powerup for "
6434 "status code %Vrc\n", vrc));
6435 hrc = setError (E_FAIL,
6436 tr ("Failed to start VM execution (%Vrc)"), vrc);
6437 }
6438 else
6439 hrc = task->mProgress->resultCode();
6440
6441 Assert (FAILED (hrc));
6442 break;
6443 }
6444 }
6445 while (0);
6446
6447 if (console->mMachineState == MachineState_Starting ||
6448 console->mMachineState == MachineState_Restoring)
6449 {
6450 /*
6451 * We are still in the Starting/Restoring state. This means one of:
6452 * 1) we failed before VMR3Create() was called;
6453 * 2) VMR3Create() failed.
6454 * In both cases, there is no need to call powerDown(), but we still
6455 * need to go back to the PoweredOff/Saved state. Reuse
6456 * vmstateChangeCallback() for that purpose.
6457 */
6458
6459 /* preserve the current error info */
6460 ErrorInfo ei;
6461
6462 Assert (console->mpVM == NULL);
6463 vmstateChangeCallback (NULL, VMSTATE_TERMINATED, VMSTATE_CREATING,
6464 console);
6465 setError (ei);
6466 }
6467
6468 /*
6469 * Evaluate the final result.
6470 * Note that the appropriate mMachineState value is already set by
6471 * vmstateChangeCallback() in all cases.
6472 */
6473
6474 /* leave the lock, don't need it any more */
6475 alock.leave();
6476
6477 if (SUCCEEDED (hrc))
6478 {
6479 /* Notify the progress object of the success */
6480 task->mProgress->notifyComplete (S_OK);
6481 }
6482 else
6483 {
6484 if (!task->mProgress->completed())
6485 {
6486 /* The progress object will fetch the current error info. This
6487 * gets the errors signalled by using setError(). The ones
6488 * signalled via VMSetError() immediately notify the progress
6489 * object that the operation is completed. */
6490 task->mProgress->notifyComplete (hrc);
6491 }
6492
6493 LogRel (("Power up failed (vrc=%Vrc, hrc=0x%08X)\n", vrc, hrc));
6494 }
6495
6496#if defined(__WIN__)
6497 /* uninitialize COM */
6498 CoUninitialize();
6499#endif
6500
6501 LogFlowFuncLeave();
6502
6503 return VINF_SUCCESS;
6504}
6505
6506
6507/**
6508 * Reconfigures a VDI.
6509 *
6510 * @param pVM The VM handle.
6511 * @param hda The harddisk attachment.
6512 * @param phrc Where to store com error - only valid if we return VERR_GENERAL_FAILURE.
6513 * @return VBox status code.
6514 */
6515static DECLCALLBACK(int) reconfigureVDI(PVM pVM, IHardDiskAttachment *hda, HRESULT *phrc)
6516{
6517 LogFlowFunc (("pVM=%p hda=%p phrc=%p\n", pVM, hda, phrc));
6518
6519 int rc;
6520 HRESULT hrc;
6521 char *psz = NULL;
6522 BSTR str = NULL;
6523 *phrc = S_OK;
6524#define STR_CONV() do { rc = RTStrUcs2ToUtf8(&psz, str); RC_CHECK(); } while (0)
6525#define STR_FREE() do { if (str) { SysFreeString(str); str = NULL; } if (psz) { RTStrFree(psz); psz = NULL; } } while (0)
6526#define RC_CHECK() do { if (VBOX_FAILURE(rc)) { AssertMsgFailed(("rc=%Vrc\n", rc)); STR_FREE(); return rc; } } while (0)
6527#define H() do { if (FAILED(hrc)) { AssertMsgFailed(("hrc=%#x\n", hrc)); STR_FREE(); *phrc = hrc; return VERR_GENERAL_FAILURE; } } while (0)
6528
6529 /*
6530 * Figure out which IDE device this is.
6531 */
6532 ComPtr<IHardDisk> hardDisk;
6533 hrc = hda->COMGETTER(HardDisk)(hardDisk.asOutParam()); H();
6534 DiskControllerType_T enmCtl;
6535 hrc = hda->COMGETTER(Controller)(&enmCtl); H();
6536 LONG lDev;
6537 hrc = hda->COMGETTER(DeviceNumber)(&lDev); H();
6538
6539 int i;
6540 switch (enmCtl)
6541 {
6542 case DiskControllerType_IDE0Controller:
6543 i = 0;
6544 break;
6545 case DiskControllerType_IDE1Controller:
6546 i = 2;
6547 break;
6548 default:
6549 AssertMsgFailed(("invalid disk controller type: %d\n", enmCtl));
6550 return VERR_GENERAL_FAILURE;
6551 }
6552
6553 if (lDev < 0 || lDev >= 2)
6554 {
6555 AssertMsgFailed(("invalid controller device number: %d\n", lDev));
6556 return VERR_GENERAL_FAILURE;
6557 }
6558
6559 i = i + lDev;
6560
6561 /*
6562 * Is there an existing LUN? If not create it.
6563 * We ASSUME that this will NEVER collide with the DVD.
6564 */
6565 PCFGMNODE pCfg;
6566 PCFGMNODE pLunL1 = CFGMR3GetChildF(CFGMR3GetRoot(pVM), "Devices/piix3ide/0/LUN#%d/AttachedDriver/", i);
6567 if (!pLunL1)
6568 {
6569 PCFGMNODE pInst = CFGMR3GetChild(CFGMR3GetRoot(pVM), "Devices/piix3ide/0/");
6570 AssertReturn(pInst, VERR_INTERNAL_ERROR);
6571
6572 PCFGMNODE pLunL0;
6573 rc = CFGMR3InsertNodeF(pInst, &pLunL0, "LUN#%d", i); RC_CHECK();
6574 rc = CFGMR3InsertString(pLunL0, "Driver", "Block"); RC_CHECK();
6575 rc = CFGMR3InsertNode(pLunL0, "Config", &pCfg); RC_CHECK();
6576 rc = CFGMR3InsertString(pCfg, "Type", "HardDisk"); RC_CHECK();
6577 rc = CFGMR3InsertInteger(pCfg, "Mountable", 0); RC_CHECK();
6578
6579 rc = CFGMR3InsertNode(pLunL0, "AttachedDriver", &pLunL1); RC_CHECK();
6580 rc = CFGMR3InsertString(pLunL1, "Driver", "VBoxHDD"); RC_CHECK();
6581 rc = CFGMR3InsertNode(pLunL1, "Config", &pCfg); RC_CHECK();
6582 }
6583 else
6584 {
6585#ifdef VBOX_STRICT
6586 char *pszDriver;
6587 rc = CFGMR3QueryStringAlloc(pLunL1, "Driver", &pszDriver); RC_CHECK();
6588 Assert(!strcmp(pszDriver, "VBoxHDD"));
6589 MMR3HeapFree(pszDriver);
6590#endif
6591
6592 /*
6593 * Check if things has changed.
6594 */
6595 pCfg = CFGMR3GetChild(pLunL1, "Config");
6596 AssertReturn(pCfg, VERR_INTERNAL_ERROR);
6597
6598 /* the image */
6599 /// @todo (dmik) we temporarily use the location property to
6600 // determine the image file name. This is subject to change
6601 // when iSCSI disks are here (we should either query a
6602 // storage-specific interface from IHardDisk, or "standardize"
6603 // the location property)
6604 hrc = hardDisk->COMGETTER(Location)(&str); H();
6605 STR_CONV();
6606 char *pszPath;
6607 rc = CFGMR3QueryStringAlloc(pCfg, "Path", &pszPath); RC_CHECK();
6608 if (!strcmp(psz, pszPath))
6609 {
6610 /* parent images. */
6611 ComPtr<IHardDisk> parentHardDisk = hardDisk;
6612 for (PCFGMNODE pParent = pCfg;;)
6613 {
6614 MMR3HeapFree(pszPath);
6615 pszPath = NULL;
6616 STR_FREE();
6617
6618 /* get parent */
6619 ComPtr<IHardDisk> curHardDisk;
6620 hrc = parentHardDisk->COMGETTER(Parent)(curHardDisk.asOutParam()); H();
6621 PCFGMNODE pCur;
6622 pCur = CFGMR3GetChild(pParent, "Parent");
6623 if (!pCur && !curHardDisk)
6624 {
6625 /* no change */
6626 LogFlowFunc (("No change!\n"));
6627 return VINF_SUCCESS;
6628 }
6629 if (!pCur || !curHardDisk)
6630 break;
6631
6632 /* compare paths. */
6633 /// @todo (dmik) we temporarily use the location property to
6634 // determine the image file name. This is subject to change
6635 // when iSCSI disks are here (we should either query a
6636 // storage-specific interface from IHardDisk, or "standardize"
6637 // the location property)
6638 hrc = curHardDisk->COMGETTER(Location)(&str); H();
6639 STR_CONV();
6640 rc = CFGMR3QueryStringAlloc(pCfg, "Path", &pszPath); RC_CHECK();
6641 if (strcmp(psz, pszPath))
6642 break;
6643
6644 /* next */
6645 pParent = pCur;
6646 parentHardDisk = curHardDisk;
6647 }
6648
6649 }
6650 else
6651 LogFlowFunc (("LUN#%d: old leaf image '%s'\n", i, pszPath));
6652
6653 MMR3HeapFree(pszPath);
6654 STR_FREE();
6655
6656 /*
6657 * Detach the driver and replace the config node.
6658 */
6659 rc = PDMR3DeviceDetach(pVM, "piix3ide", 0, i); RC_CHECK();
6660 CFGMR3RemoveNode(pCfg);
6661 rc = CFGMR3InsertNode(pLunL1, "Config", &pCfg); RC_CHECK();
6662 }
6663
6664 /*
6665 * Create the driver configuration.
6666 */
6667 /// @todo (dmik) we temporarily use the location property to
6668 // determine the image file name. This is subject to change
6669 // when iSCSI disks are here (we should either query a
6670 // storage-specific interface from IHardDisk, or "standardize"
6671 // the location property)
6672 hrc = hardDisk->COMGETTER(Location)(&str); H();
6673 STR_CONV();
6674 LogFlowFunc (("LUN#%d: leaf image '%s'\n", i, psz));
6675 rc = CFGMR3InsertString(pCfg, "Path", psz); RC_CHECK();
6676 STR_FREE();
6677 /* Create an inversed tree of parents. */
6678 ComPtr<IHardDisk> parentHardDisk = hardDisk;
6679 for (PCFGMNODE pParent = pCfg;;)
6680 {
6681 ComPtr<IHardDisk> curHardDisk;
6682 hrc = parentHardDisk->COMGETTER(Parent)(curHardDisk.asOutParam()); H();
6683 if (!curHardDisk)
6684 break;
6685
6686 PCFGMNODE pCur;
6687 rc = CFGMR3InsertNode(pParent, "Parent", &pCur); RC_CHECK();
6688 /// @todo (dmik) we temporarily use the location property to
6689 // determine the image file name. This is subject to change
6690 // when iSCSI disks are here (we should either query a
6691 // storage-specific interface from IHardDisk, or "standardize"
6692 // the location property)
6693 hrc = curHardDisk->COMGETTER(Location)(&str); H();
6694 STR_CONV();
6695 rc = CFGMR3InsertString(pCur, "Path", psz); RC_CHECK();
6696 STR_FREE();
6697
6698 /* next */
6699 pParent = pCur;
6700 parentHardDisk = curHardDisk;
6701 }
6702
6703 /*
6704 * Attach the new driver.
6705 */
6706 rc = PDMR3DeviceAttach(pVM, "piix3ide", 0, i, NULL); RC_CHECK();
6707
6708 LogFlowFunc (("Returns success\n"));
6709 return rc;
6710}
6711
6712
6713/**
6714 * Thread for executing the saved state operation.
6715 *
6716 * @param Thread The thread handle.
6717 * @param pvUser Pointer to a VMSaveTask structure.
6718 * @return VINF_SUCCESS (ignored).
6719 *
6720 * @note Locks the Console object for writing.
6721 */
6722/*static*/
6723DECLCALLBACK (int) Console::saveStateThread (RTTHREAD Thread, void *pvUser)
6724{
6725 LogFlowFuncEnter();
6726
6727 std::auto_ptr <VMSaveTask> task (static_cast <VMSaveTask *> (pvUser));
6728 AssertReturn (task.get(), VERR_INVALID_PARAMETER);
6729
6730 Assert (!task->mSavedStateFile.isNull());
6731 Assert (!task->mProgress.isNull());
6732
6733 const ComObjPtr <Console> &that = task->mConsole;
6734
6735 /*
6736 * Note: no need to use addCaller() to protect Console or addVMCaller() to
6737 * protect mpVM because VMSaveTask does that
6738 */
6739
6740 Utf8Str errMsg;
6741 HRESULT rc = S_OK;
6742
6743 if (task->mIsSnapshot)
6744 {
6745 Assert (!task->mServerProgress.isNull());
6746 LogFlowFunc (("Waiting until the server creates differencing VDIs...\n"));
6747
6748 rc = task->mServerProgress->WaitForCompletion (-1);
6749 if (SUCCEEDED (rc))
6750 {
6751 HRESULT result = S_OK;
6752 rc = task->mServerProgress->COMGETTER(ResultCode) (&result);
6753 if (SUCCEEDED (rc))
6754 rc = result;
6755 }
6756 }
6757
6758 if (SUCCEEDED (rc))
6759 {
6760 LogFlowFunc (("Saving the state to '%s'...\n", task->mSavedStateFile.raw()));
6761
6762 int vrc = VMR3Save (that->mpVM, task->mSavedStateFile,
6763 Console::stateProgressCallback,
6764 static_cast <VMProgressTask *> (task.get()));
6765 if (VBOX_FAILURE (vrc))
6766 {
6767 errMsg = Utf8StrFmt (
6768 Console::tr ("Failed to save the machine state to '%s' (%Vrc)"),
6769 task->mSavedStateFile.raw(), vrc);
6770 rc = E_FAIL;
6771 }
6772 }
6773
6774 /* lock the console sonce we're going to access it */
6775 AutoLock thatLock (that);
6776
6777 if (SUCCEEDED (rc))
6778 {
6779 if (task->mIsSnapshot)
6780 do
6781 {
6782 LogFlowFunc (("Reattaching new differencing VDIs...\n"));
6783
6784 ComPtr <IHardDiskAttachmentCollection> hdaColl;
6785 rc = that->mMachine->COMGETTER(HardDiskAttachments) (hdaColl.asOutParam());
6786 if (FAILED (rc))
6787 break;
6788 ComPtr <IHardDiskAttachmentEnumerator> hdaEn;
6789 rc = hdaColl->Enumerate (hdaEn.asOutParam());
6790 if (FAILED (rc))
6791 break;
6792 BOOL more = FALSE;
6793 while (SUCCEEDED (rc = hdaEn->HasMore (&more)) && more)
6794 {
6795 ComPtr <IHardDiskAttachment> hda;
6796 rc = hdaEn->GetNext (hda.asOutParam());
6797 if (FAILED (rc))
6798 break;
6799
6800 PVMREQ pReq;
6801 IHardDiskAttachment *pHda = hda;
6802 /*
6803 * don't leave the lock since reconfigureVDI isn't going to
6804 * access Console.
6805 */
6806 int vrc = VMR3ReqCall (that->mpVM, &pReq, RT_INDEFINITE_WAIT,
6807 (PFNRT)reconfigureVDI, 3, that->mpVM,
6808 pHda, &rc);
6809 if (VBOX_SUCCESS (rc))
6810 rc = pReq->iStatus;
6811 VMR3ReqFree (pReq);
6812 if (FAILED (rc))
6813 break;
6814 if (VBOX_FAILURE (vrc))
6815 {
6816 errMsg = Utf8StrFmt (Console::tr ("%Vrc"), vrc);
6817 rc = E_FAIL;
6818 break;
6819 }
6820 }
6821 }
6822 while (0);
6823 }
6824
6825 /* finalize the procedure regardless of the result */
6826 if (task->mIsSnapshot)
6827 {
6828 /*
6829 * finalize the requested snapshot object.
6830 * This will reset the machine state to the state it had right
6831 * before calling mControl->BeginTakingSnapshot().
6832 */
6833 that->mControl->EndTakingSnapshot (SUCCEEDED (rc));
6834 }
6835 else
6836 {
6837 /*
6838 * finalize the requested save state procedure.
6839 * In case of success, the server will set the machine state to Saved;
6840 * in case of failure it will reset the it to the state it had right
6841 * before calling mControl->BeginSavingState().
6842 */
6843 that->mControl->EndSavingState (SUCCEEDED (rc));
6844 }
6845
6846 /* synchronize the state with the server */
6847 if (task->mIsSnapshot || FAILED (rc))
6848 {
6849 if (task->mLastMachineState == MachineState_Running)
6850 {
6851 /* restore the paused state if appropriate */
6852 that->setMachineStateLocally (MachineState_Paused);
6853 /* restore the running state if appropriate */
6854 that->Resume();
6855 }
6856 else
6857 that->setMachineStateLocally (task->mLastMachineState);
6858 }
6859 else
6860 {
6861 /*
6862 * The machine has been successfully saved, so power it down
6863 * (vmstateChangeCallback() will set state to Saved on success).
6864 * Note: we release the task's VM caller, otherwise it will
6865 * deadlock.
6866 */
6867 task->releaseVMCaller();
6868
6869 rc = that->powerDown();
6870 }
6871
6872 /* notify the progress object about operation completion */
6873 if (SUCCEEDED (rc))
6874 task->mProgress->notifyComplete (S_OK);
6875 else
6876 {
6877 if (!errMsg.isNull())
6878 task->mProgress->notifyComplete (rc,
6879 COM_IIDOF(IConsole), Console::getComponentName(), errMsg);
6880 else
6881 task->mProgress->notifyComplete (rc);
6882 }
6883
6884 LogFlowFuncLeave();
6885 return VINF_SUCCESS;
6886}
6887
6888/**
6889 * Thread for powering down the Console.
6890 *
6891 * @param Thread The thread handle.
6892 * @param pvUser Pointer to the VMTask structure.
6893 * @return VINF_SUCCESS (ignored).
6894 *
6895 * @note Locks the Console object for writing.
6896 */
6897/*static*/
6898DECLCALLBACK (int) Console::powerDownThread (RTTHREAD Thread, void *pvUser)
6899{
6900 LogFlowFuncEnter();
6901
6902 std::auto_ptr <VMTask> task (static_cast <VMTask *> (pvUser));
6903 AssertReturn (task.get(), VERR_INVALID_PARAMETER);
6904
6905 AssertReturn (task->isOk(), VERR_GENERAL_FAILURE);
6906
6907 const ComObjPtr <Console> &that = task->mConsole;
6908
6909 /*
6910 * Note: no need to use addCaller() to protect Console
6911 * because VMTask does that
6912 */
6913
6914 /* release VM caller to let powerDown() proceed */
6915 task->releaseVMCaller();
6916
6917 HRESULT rc = that->powerDown();
6918 AssertComRC (rc);
6919
6920 LogFlowFuncLeave();
6921 return VINF_SUCCESS;
6922}
6923
6924/**
6925 * The Main status driver instance data.
6926 */
6927typedef struct DRVMAINSTATUS
6928{
6929 /** The LED connectors. */
6930 PDMILEDCONNECTORS ILedConnectors;
6931 /** Pointer to the LED ports interface above us. */
6932 PPDMILEDPORTS pLedPorts;
6933 /** Pointer to the array of LED pointers. */
6934 PPDMLED *papLeds;
6935 /** The unit number corresponding to the first entry in the LED array. */
6936 RTUINT iFirstLUN;
6937 /** The unit number corresponding to the last entry in the LED array.
6938 * (The size of the LED array is iLastLUN - iFirstLUN + 1.) */
6939 RTUINT iLastLUN;
6940} DRVMAINSTATUS, *PDRVMAINSTATUS;
6941
6942
6943/**
6944 * Notification about a unit which have been changed.
6945 *
6946 * The driver must discard any pointers to data owned by
6947 * the unit and requery it.
6948 *
6949 * @param pInterface Pointer to the interface structure containing the called function pointer.
6950 * @param iLUN The unit number.
6951 */
6952DECLCALLBACK(void) Console::drvStatus_UnitChanged(PPDMILEDCONNECTORS pInterface, unsigned iLUN)
6953{
6954 PDRVMAINSTATUS pData = (PDRVMAINSTATUS)(void *)pInterface;
6955 if (iLUN >= pData->iFirstLUN && iLUN <= pData->iLastLUN)
6956 {
6957 PPDMLED pLed;
6958 int rc = pData->pLedPorts->pfnQueryStatusLed(pData->pLedPorts, iLUN, &pLed);
6959 if (VBOX_FAILURE(rc))
6960 pLed = NULL;
6961 ASMAtomicXchgPtr((void * volatile *)&pData->papLeds[iLUN - pData->iFirstLUN], pLed);
6962 Log(("drvStatus_UnitChanged: iLUN=%d pLed=%p\n", iLUN, pLed));
6963 }
6964}
6965
6966
6967/**
6968 * Queries an interface to the driver.
6969 *
6970 * @returns Pointer to interface.
6971 * @returns NULL if the interface was not supported by the driver.
6972 * @param pInterface Pointer to this interface structure.
6973 * @param enmInterface The requested interface identification.
6974 */
6975DECLCALLBACK(void *) Console::drvStatus_QueryInterface(PPDMIBASE pInterface, PDMINTERFACE enmInterface)
6976{
6977 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
6978 PDRVMAINSTATUS pDrv = PDMINS2DATA(pDrvIns, PDRVMAINSTATUS);
6979 switch (enmInterface)
6980 {
6981 case PDMINTERFACE_BASE:
6982 return &pDrvIns->IBase;
6983 case PDMINTERFACE_LED_CONNECTORS:
6984 return &pDrv->ILedConnectors;
6985 default:
6986 return NULL;
6987 }
6988}
6989
6990
6991/**
6992 * Destruct a status driver instance.
6993 *
6994 * @returns VBox status.
6995 * @param pDrvIns The driver instance data.
6996 */
6997DECLCALLBACK(void) Console::drvStatus_Destruct(PPDMDRVINS pDrvIns)
6998{
6999 PDRVMAINSTATUS pData = PDMINS2DATA(pDrvIns, PDRVMAINSTATUS);
7000 LogFlowFunc(("iInstance=%d\n", pDrvIns->iInstance));
7001 if (pData->papLeds)
7002 {
7003 unsigned iLed = pData->iLastLUN - pData->iFirstLUN + 1;
7004 while (iLed-- > 0)
7005 ASMAtomicXchgPtr((void * volatile *)&pData->papLeds[iLed], NULL);
7006 }
7007}
7008
7009
7010/**
7011 * Construct a status driver instance.
7012 *
7013 * @returns VBox status.
7014 * @param pDrvIns The driver instance data.
7015 * If the registration structure is needed, pDrvIns->pDrvReg points to it.
7016 * @param pCfgHandle Configuration node handle for the driver. Use this to obtain the configuration
7017 * of the driver instance. It's also found in pDrvIns->pCfgHandle, but like
7018 * iInstance it's expected to be used a bit in this function.
7019 */
7020DECLCALLBACK(int) Console::drvStatus_Construct(PPDMDRVINS pDrvIns, PCFGMNODE pCfgHandle)
7021{
7022 PDRVMAINSTATUS pData = PDMINS2DATA(pDrvIns, PDRVMAINSTATUS);
7023 LogFlowFunc(("iInstance=%d\n", pDrvIns->iInstance));
7024
7025 /*
7026 * Validate configuration.
7027 */
7028 if (!CFGMR3AreValuesValid(pCfgHandle, "papLeds\0First\0Last\0"))
7029 return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;
7030 PPDMIBASE pBaseIgnore;
7031 int rc = pDrvIns->pDrvHlp->pfnAttach(pDrvIns, &pBaseIgnore);
7032 if (rc != VERR_PDM_NO_ATTACHED_DRIVER)
7033 {
7034 AssertMsgFailed(("Configuration error: Not possible to attach anything to this driver!\n"));
7035 return VERR_PDM_DRVINS_NO_ATTACH;
7036 }
7037
7038 /*
7039 * Data.
7040 */
7041 pDrvIns->IBase.pfnQueryInterface = Console::drvStatus_QueryInterface;
7042 pData->ILedConnectors.pfnUnitChanged = Console::drvStatus_UnitChanged;
7043
7044 /*
7045 * Read config.
7046 */
7047 rc = CFGMR3QueryPtr(pCfgHandle, "papLeds", (void **)&pData->papLeds);
7048 if (VBOX_FAILURE(rc))
7049 {
7050 AssertMsgFailed(("Configuration error: Failed to query the \"papLeds\" value! rc=%Vrc\n", rc));
7051 return rc;
7052 }
7053
7054 rc = CFGMR3QueryU32(pCfgHandle, "First", &pData->iFirstLUN);
7055 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
7056 pData->iFirstLUN = 0;
7057 else if (VBOX_FAILURE(rc))
7058 {
7059 AssertMsgFailed(("Configuration error: Failed to query the \"First\" value! rc=%Vrc\n", rc));
7060 return rc;
7061 }
7062
7063 rc = CFGMR3QueryU32(pCfgHandle, "Last", &pData->iLastLUN);
7064 if (rc == VERR_CFGM_VALUE_NOT_FOUND)
7065 pData->iLastLUN = 0;
7066 else if (VBOX_FAILURE(rc))
7067 {
7068 AssertMsgFailed(("Configuration error: Failed to query the \"Last\" value! rc=%Vrc\n", rc));
7069 return rc;
7070 }
7071 if (pData->iFirstLUN > pData->iLastLUN)
7072 {
7073 AssertMsgFailed(("Configuration error: Invalid unit range %u-%u\n", pData->iFirstLUN, pData->iLastLUN));
7074 return VERR_GENERAL_FAILURE;
7075 }
7076
7077 /*
7078 * Get the ILedPorts interface of the above driver/device and
7079 * query the LEDs we want.
7080 */
7081 pData->pLedPorts = (PPDMILEDPORTS)pDrvIns->pUpBase->pfnQueryInterface(pDrvIns->pUpBase, PDMINTERFACE_LED_PORTS);
7082 if (!pData->pLedPorts)
7083 {
7084 AssertMsgFailed(("Configuration error: No led ports interface above!\n"));
7085 return VERR_PDM_MISSING_INTERFACE_ABOVE;
7086 }
7087
7088 for (unsigned i = pData->iFirstLUN; i <= pData->iLastLUN; i++)
7089 Console::drvStatus_UnitChanged(&pData->ILedConnectors, i);
7090
7091 return VINF_SUCCESS;
7092}
7093
7094
7095/**
7096 * Keyboard driver registration record.
7097 */
7098const PDMDRVREG Console::DrvStatusReg =
7099{
7100 /* u32Version */
7101 PDM_DRVREG_VERSION,
7102 /* szDriverName */
7103 "MainStatus",
7104 /* pszDescription */
7105 "Main status driver (Main as in the API).",
7106 /* fFlags */
7107 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
7108 /* fClass. */
7109 PDM_DRVREG_CLASS_STATUS,
7110 /* cMaxInstances */
7111 ~0,
7112 /* cbInstance */
7113 sizeof(DRVMAINSTATUS),
7114 /* pfnConstruct */
7115 Console::drvStatus_Construct,
7116 /* pfnDestruct */
7117 Console::drvStatus_Destruct,
7118 /* pfnIOCtl */
7119 NULL,
7120 /* pfnPowerOn */
7121 NULL,
7122 /* pfnReset */
7123 NULL,
7124 /* pfnSuspend */
7125 NULL,
7126 /* pfnResume */
7127 NULL,
7128 /* pfnDetach */
7129 NULL
7130};
7131
Note: See TracBrowser for help on using the repository browser.

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