VirtualBox

source: vbox/trunk/src/VBox/Main/src-client/SessionImpl.cpp@ 49644

Last change on this file since 49644 was 49453, checked in by vboxsync, 11 years ago

Main/SessionImpl.cpp: Refined assertion for Session::Uninitialize().

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 37.7 KB
Line 
1/* $Id: SessionImpl.cpp 49453 2013-11-12 13:24:14Z vboxsync $ */
2/** @file
3 * VBox Client Session COM Class implementation in VBoxC.
4 */
5
6/*
7 * Copyright (C) 2006-2013 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#include "SessionImpl.h"
19#include "ConsoleImpl.h"
20#include "Global.h"
21#include "ClientTokenHolder.h"
22
23#include "AutoCaller.h"
24#include "Logging.h"
25
26#include <VBox/err.h>
27#include <iprt/process.h>
28
29/**
30 * Local macro to check whether the session is open and return an error if not.
31 * @note Don't forget to do |Auto[Reader]Lock alock (this);| before using this
32 * macro.
33 */
34#define CHECK_OPEN() \
35 do { \
36 if (mState != SessionState_Locked) \
37 return setError(E_UNEXPECTED, tr ("The session is not locked (session state: %s)"), Global::stringifySessionState(mState)); \
38 } while (0)
39
40// constructor / destructor
41/////////////////////////////////////////////////////////////////////////////
42
43HRESULT Session::FinalConstruct()
44{
45 LogFlowThisFunc(("\n"));
46
47 HRESULT rc = init();
48
49 BaseFinalConstruct();
50
51 return rc;
52}
53
54void Session::FinalRelease()
55{
56 LogFlowThisFunc(("\n"));
57
58 uninit();
59
60 BaseFinalRelease();
61}
62
63// public initializer/uninitializer for internal purposes only
64/////////////////////////////////////////////////////////////////////////////
65
66/**
67 * Initializes the Session object.
68 */
69HRESULT Session::init()
70{
71 /* Enclose the state transition NotReady->InInit->Ready */
72 AutoInitSpan autoInitSpan(this);
73 AssertReturn(autoInitSpan.isOk(), E_FAIL);
74
75 LogFlowThisFuncEnter();
76
77 mState = SessionState_Unlocked;
78 mType = SessionType_Null;
79
80 mClientTokenHolder = NULL;
81
82 /* Confirm a successful initialization when it's the case */
83 autoInitSpan.setSucceeded();
84
85 LogFlowThisFuncLeave();
86
87 return S_OK;
88}
89
90/**
91 * Uninitializes the Session object.
92 *
93 * @note Locks this object for writing.
94 */
95void Session::uninit()
96{
97 LogFlowThisFuncEnter();
98
99 /* Enclose the state transition Ready->InUninit->NotReady */
100 AutoUninitSpan autoUninitSpan(this);
101 if (autoUninitSpan.uninitDone())
102 {
103 LogFlowThisFunc(("Already uninitialized.\n"));
104 LogFlowThisFuncLeave();
105 return;
106 }
107
108 /* close() needs write lock */
109 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
110
111 if (mState != SessionState_Unlocked)
112 {
113 Assert(mState == SessionState_Locked ||
114 mState == SessionState_Spawning);
115
116 HRESULT rc = unlockMachine(true /* aFinalRelease */, false /* aFromServer */);
117 AssertComRC(rc);
118 }
119
120 LogFlowThisFuncLeave();
121}
122
123// ISession properties
124/////////////////////////////////////////////////////////////////////////////
125
126STDMETHODIMP Session::COMGETTER(State)(SessionState_T *aState)
127{
128 CheckComArgOutPointerValid(aState);
129
130 AutoCaller autoCaller(this);
131 if (FAILED(autoCaller.rc())) return autoCaller.rc();
132
133 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
134
135 *aState = mState;
136
137 return S_OK;
138}
139
140STDMETHODIMP Session::COMGETTER(Type)(SessionType_T *aType)
141{
142 CheckComArgOutPointerValid(aType);
143
144 AutoCaller autoCaller(this);
145 if (FAILED(autoCaller.rc())) return autoCaller.rc();
146
147 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
148
149 CHECK_OPEN();
150
151 *aType = mType;
152 return S_OK;
153}
154
155STDMETHODIMP Session::COMGETTER(Machine)(IMachine **aMachine)
156{
157 CheckComArgOutPointerValid(aMachine);
158
159 AutoCaller autoCaller(this);
160 if (FAILED(autoCaller.rc())) return autoCaller.rc();
161
162 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
163
164 CHECK_OPEN();
165
166 HRESULT rc;
167#ifndef VBOX_COM_INPROC_API_CLIENT
168 if (mConsole)
169 rc = mConsole->machine().queryInterfaceTo(aMachine);
170 else
171#endif
172 rc = mRemoteMachine.queryInterfaceTo(aMachine);
173 if (FAILED(rc))
174 {
175 /** @todo VBox 3.3: replace E_FAIL with rc here. */
176#ifndef VBOX_COM_INPROC_API_CLIENT
177 if (mConsole)
178 setError(E_FAIL, tr("Failed to query the session machine (%Rhrc)"), rc);
179 else
180#endif
181 if (FAILED_DEAD_INTERFACE(rc))
182 setError(E_FAIL, tr("Peer process crashed"));
183 else
184 setError(E_FAIL, tr("Failed to query the remote session machine (%Rhrc)"), rc);
185 }
186
187 return rc;
188}
189
190STDMETHODIMP Session::COMGETTER(Console)(IConsole **aConsole)
191{
192 CheckComArgOutPointerValid(aConsole);
193
194 AutoCaller autoCaller(this);
195 if (FAILED(autoCaller.rc())) return autoCaller.rc();
196
197 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
198
199 CHECK_OPEN();
200
201 HRESULT rc;
202#ifndef VBOX_COM_INPROC_API_CLIENT
203 if (mConsole)
204 rc = mConsole.queryInterfaceTo(aConsole);
205 else
206#endif
207 rc = mRemoteConsole.queryInterfaceTo(aConsole);
208
209 if (FAILED(rc))
210 {
211 /** @todo VBox 3.3: replace E_FAIL with rc here. */
212#ifndef VBOX_COM_INPROC_API_CLIENT
213 if (mConsole)
214 setError(E_FAIL, tr("Failed to query the console (%Rhrc)"), rc);
215 else
216#endif
217 if (FAILED_DEAD_INTERFACE(rc))
218 setError(E_FAIL, tr("Peer process crashed"));
219 else
220 setError(E_FAIL, tr("Failed to query the remote console (%Rhrc)"), rc);
221 }
222
223 return rc;
224}
225
226// ISession methods
227/////////////////////////////////////////////////////////////////////////////
228
229STDMETHODIMP Session::UnlockMachine()
230{
231 LogFlowThisFunc(("mState=%d, mType=%d\n", mState, mType));
232
233 AutoCaller autoCaller(this);
234 if (FAILED(autoCaller.rc())) return autoCaller.rc();
235
236 /* close() needs write lock */
237 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
238
239 CHECK_OPEN();
240
241 return unlockMachine(false /* aFinalRelease */, false /* aFromServer */);
242}
243
244// IInternalSessionControl methods
245/////////////////////////////////////////////////////////////////////////////
246
247STDMETHODIMP Session::GetPID(ULONG *aPid)
248{
249 AssertReturn(aPid, E_POINTER);
250
251 AutoCaller autoCaller(this);
252 AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
253
254 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
255
256 *aPid = (ULONG)RTProcSelf();
257 AssertCompile(sizeof(*aPid) == sizeof(RTPROCESS));
258
259 return S_OK;
260}
261
262STDMETHODIMP Session::GetRemoteConsole(IConsole **aConsole)
263{
264 LogFlowThisFuncEnter();
265 AssertReturn(aConsole, E_POINTER);
266
267 AutoCaller autoCaller(this);
268 AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
269
270 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
271
272 AssertReturn(mState != SessionState_Unlocked, VBOX_E_INVALID_VM_STATE);
273
274#ifndef VBOX_COM_INPROC_API_CLIENT
275 AssertMsgReturn(mType == SessionType_WriteLock && !!mConsole,
276 ("This is not a direct session!\n"),
277 VBOX_E_INVALID_OBJECT_STATE);
278
279 /* return a failure if the session already transitioned to Closing
280 * but the server hasn't processed Machine::OnSessionEnd() yet. */
281 if (mState != SessionState_Locked)
282 return VBOX_E_INVALID_VM_STATE;
283
284 mConsole.queryInterfaceTo(aConsole);
285
286 LogFlowThisFuncLeave();
287
288 return S_OK;
289
290#else /* VBOX_COM_INPROC_API_CLIENT */
291 AssertFailed();
292 return VBOX_E_INVALID_OBJECT_STATE;
293#endif /* VBOX_COM_INPROC_API_CLIENT */
294}
295
296#ifndef VBOX_WITH_GENERIC_SESSION_WATCHER
297STDMETHODIMP Session::AssignMachine(IMachine *aMachine, LockType_T aLockType,
298 IN_BSTR aTokenId)
299#else /* VBOX_WITH_GENERIC_SESSION_WATCHER */
300STDMETHODIMP Session::AssignMachine(IMachine *aMachine, LockType_T aLockType,
301 IToken *aToken)
302#endif /* VBOX_WITH_GENERIC_SESSION_WATCHER */
303{
304 LogFlowThisFuncEnter();
305 LogFlowThisFunc(("aMachine=%p\n", aMachine));
306
307 AutoCaller autoCaller(this);
308 AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
309
310 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
311
312 AssertReturn(mState == SessionState_Unlocked, VBOX_E_INVALID_VM_STATE);
313
314 if (!aMachine)
315 {
316 /*
317 * A special case: the server informs us that this session has been
318 * passed to IMachine::launchVMProcess() so this session will become
319 * remote (but not existing) when AssignRemoteMachine() is called.
320 */
321
322 AssertReturn(mType == SessionType_Null, VBOX_E_INVALID_OBJECT_STATE);
323 mType = SessionType_Remote;
324 mState = SessionState_Spawning;
325
326 LogFlowThisFuncLeave();
327 return S_OK;
328 }
329
330 /* query IInternalMachineControl interface */
331 mControl = aMachine;
332 AssertReturn(!!mControl, E_FAIL);
333
334#ifndef VBOX_COM_INPROC_API_CLIENT
335 HRESULT rc = mConsole.createObject();
336 AssertComRCReturn(rc, rc);
337
338 rc = mConsole->init(aMachine, mControl, aLockType);
339 AssertComRCReturn(rc, rc);
340#else
341 HRESULT rc = S_OK;
342 mRemoteMachine = aMachine;
343#endif
344
345#ifndef VBOX_WITH_GENERIC_SESSION_WATCHER
346 Utf8Str strTokenId(aTokenId);
347 Assert(!strTokenId.isEmpty());
348#else /* VBOX_WITH_GENERIC_SESSION_WATCHER */
349 AssertPtr(aToken);
350#endif /* VBOX_WITH_GENERIC_SESSION_WATCHER */
351 /* create the machine client token */
352 try
353 {
354#ifndef VBOX_WITH_GENERIC_SESSION_WATCHER
355 mClientTokenHolder = new ClientTokenHolder(strTokenId);
356#else /* VBOX_WITH_GENERIC_SESSION_WATCHER */
357 mClientTokenHolder = new ClientTokenHolder(aToken);
358#endif /* VBOX_WITH_GENERIC_SESSION_WATCHER */
359 if (!mClientTokenHolder->isReady())
360 {
361 delete mClientTokenHolder;
362 mClientTokenHolder = NULL;
363 rc = E_FAIL;
364 }
365 }
366 catch (std::bad_alloc &)
367 {
368 rc = E_OUTOFMEMORY;
369 }
370
371 /*
372 * Reference the VirtualBox object to ensure the server is up
373 * until the session is closed
374 */
375 if (SUCCEEDED(rc))
376 rc = aMachine->COMGETTER(Parent)(mVirtualBox.asOutParam());
377
378 if (SUCCEEDED(rc))
379 {
380 mType = SessionType_WriteLock;
381 mState = SessionState_Locked;
382 }
383 else
384 {
385 /* some cleanup */
386 mControl.setNull();
387#ifndef VBOX_COM_INPROC_API_CLIENT
388 if (!mConsole.isNull())
389 {
390 mConsole->uninit();
391 mConsole.setNull();
392 }
393#endif
394 }
395
396 LogFlowThisFunc(("rc=%08X\n", rc));
397 LogFlowThisFuncLeave();
398
399 return rc;
400}
401
402STDMETHODIMP Session::AssignRemoteMachine(IMachine *aMachine, IConsole *aConsole)
403{
404 LogFlowThisFuncEnter();
405 LogFlowThisFunc(("aMachine=%p, aConsole=%p\n", aMachine, aConsole));
406
407 AssertReturn(aMachine && aConsole, E_INVALIDARG);
408
409 AutoCaller autoCaller(this);
410 AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
411
412 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
413
414 AssertReturn(mState == SessionState_Unlocked ||
415 mState == SessionState_Spawning, VBOX_E_INVALID_VM_STATE);
416
417 HRESULT rc = E_FAIL;
418
419 /* query IInternalMachineControl interface */
420 mControl = aMachine;
421 AssertReturn(!!mControl, E_FAIL);
422
423 /// @todo (dmik)
424 // currently, the remote session returns the same machine and
425 // console objects as the direct session, thus giving the
426 // (remote) client full control over the direct session. For the
427 // console, it is the desired behavior (the ability to control
428 // VM execution is a must for the remote session). What about
429 // the machine object, we may want to prevent the remote client
430 // from modifying machine data. In this case, we must:
431 // 1) assign the Machine object (instead of the SessionMachine
432 // object that is passed to this method) to mRemoteMachine;
433 // 2) remove GetMachine() property from the IConsole interface
434 // because it always returns the SessionMachine object
435 // (alternatively, we can supply a separate IConsole
436 // implementation that will return the Machine object in
437 // response to GetMachine()).
438
439 mRemoteMachine = aMachine;
440 mRemoteConsole = aConsole;
441
442 /*
443 * Reference the VirtualBox object to ensure the server is up
444 * until the session is closed
445 */
446 rc = aMachine->COMGETTER(Parent)(mVirtualBox.asOutParam());
447
448 if (SUCCEEDED(rc))
449 {
450 /*
451 * RemoteSession type can be already set by AssignMachine() when its
452 * argument is NULL (a special case)
453 */
454 if (mType != SessionType_Remote)
455 mType = SessionType_Shared;
456 else
457 Assert(mState == SessionState_Spawning);
458
459 mState = SessionState_Locked;
460 }
461 else
462 {
463 /* some cleanup */
464 mControl.setNull();
465 mRemoteMachine.setNull();
466 mRemoteConsole.setNull();
467 }
468
469 LogFlowThisFunc(("rc=%08X\n", rc));
470 LogFlowThisFuncLeave();
471
472 return rc;
473}
474
475STDMETHODIMP Session::UpdateMachineState(MachineState_T aMachineState)
476{
477 AutoCaller autoCaller(this);
478
479 if (autoCaller.state() != Ready)
480 {
481 /*
482 * We might have already entered Session::uninit() at this point, so
483 * return silently (not interested in the state change during uninit)
484 */
485 LogFlowThisFunc(("Already uninitialized.\n"));
486 return S_OK;
487 }
488
489 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
490
491 if (mState == SessionState_Unlocking)
492 {
493 LogFlowThisFunc(("Already being unlocked.\n"));
494 return S_OK;
495 }
496
497 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
498 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
499
500 AssertReturn(!mControl.isNull(), E_FAIL);
501#ifndef VBOX_COM_INPROC_API_CLIENT
502 AssertReturn(!mConsole.isNull(), E_FAIL);
503
504 return mConsole->updateMachineState(aMachineState);
505#else
506 return S_OK;
507#endif
508}
509
510STDMETHODIMP Session::Uninitialize()
511{
512 LogFlowThisFuncEnter();
513
514 AutoCaller autoCaller(this);
515
516 HRESULT rc = S_OK;
517
518 if (autoCaller.state() == Ready)
519 {
520 /* close() needs write lock */
521 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
522
523 LogFlowThisFunc(("mState=%s, mType=%d\n", Global::stringifySessionState(mState), mType));
524
525 if (mState == SessionState_Unlocking)
526 {
527 LogFlowThisFunc(("Already being unlocked.\n"));
528 return S_OK;
529 }
530
531 AssertMsgReturn( mState == SessionState_Locked
532 || mState == SessionState_Spawning,
533 ("Session is in wrong state (%ld), expected locked (%ld) or spawning (%ld)\n",
534 mState, SessionState_Locked, SessionState_Spawning),
535 VBOX_E_INVALID_VM_STATE);
536
537 /* close ourselves */
538 rc = unlockMachine(false /* aFinalRelease */, true /* aFromServer */);
539 }
540 else if (autoCaller.state() == InUninit)
541 {
542 /*
543 * We might have already entered Session::uninit() at this point,
544 * return silently
545 */
546 LogFlowThisFunc(("Already uninitialized.\n"));
547 }
548 else
549 {
550 LogWarningThisFunc(("UNEXPECTED uninitialization!\n"));
551 rc = autoCaller.rc();
552 }
553
554 LogFlowThisFunc(("rc=%08X\n", rc));
555 LogFlowThisFuncLeave();
556
557 return rc;
558}
559
560STDMETHODIMP Session::OnNetworkAdapterChange(INetworkAdapter *networkAdapter, BOOL changeAdapter)
561{
562 LogFlowThisFunc(("\n"));
563
564 AutoCaller autoCaller(this);
565 AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
566
567 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
568 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
569 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
570#ifndef VBOX_COM_INPROC_API_CLIENT
571 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
572
573 return mConsole->onNetworkAdapterChange(networkAdapter, changeAdapter);
574#else
575 return S_OK;
576#endif
577}
578
579STDMETHODIMP Session::OnSerialPortChange(ISerialPort *serialPort)
580{
581 LogFlowThisFunc(("\n"));
582
583 AutoCaller autoCaller(this);
584 AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
585
586 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
587 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
588 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
589#ifndef VBOX_COM_INPROC_API_CLIENT
590 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
591
592 return mConsole->onSerialPortChange(serialPort);
593#else
594 return S_OK;
595#endif
596}
597
598STDMETHODIMP Session::OnParallelPortChange(IParallelPort *parallelPort)
599{
600 LogFlowThisFunc(("\n"));
601
602 AutoCaller autoCaller(this);
603 AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
604
605 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
606 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
607 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
608#ifndef VBOX_COM_INPROC_API_CLIENT
609 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
610
611 return mConsole->onParallelPortChange(parallelPort);
612#else
613 return S_OK;
614#endif
615}
616
617STDMETHODIMP Session::OnStorageControllerChange()
618{
619 LogFlowThisFunc(("\n"));
620
621 AutoCaller autoCaller(this);
622 AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
623
624 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
625 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
626 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
627#ifndef VBOX_COM_INPROC_API_CLIENT
628 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
629
630 return mConsole->onStorageControllerChange();
631#else
632 return S_OK;
633#endif
634}
635
636STDMETHODIMP Session::OnMediumChange(IMediumAttachment *aMediumAttachment, BOOL aForce)
637{
638 LogFlowThisFunc(("\n"));
639
640 AutoCaller autoCaller(this);
641 AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
642
643 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
644 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
645 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
646#ifndef VBOX_COM_INPROC_API_CLIENT
647 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
648
649 return mConsole->onMediumChange(aMediumAttachment, aForce);
650#else
651 return S_OK;
652#endif
653}
654
655STDMETHODIMP Session::OnCPUChange(ULONG aCPU, BOOL aRemove)
656{
657 LogFlowThisFunc(("\n"));
658
659 AutoCaller autoCaller(this);
660 AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
661
662 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
663 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
664 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
665#ifndef VBOX_COM_INPROC_API_CLIENT
666 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
667
668 return mConsole->onCPUChange(aCPU, aRemove);
669#else
670 return S_OK;
671#endif
672}
673
674STDMETHODIMP Session::OnCPUExecutionCapChange(ULONG aExecutionCap)
675{
676 LogFlowThisFunc(("\n"));
677
678 AutoCaller autoCaller(this);
679 AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
680
681 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
682 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
683 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
684#ifndef VBOX_COM_INPROC_API_CLIENT
685 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
686
687 return mConsole->onCPUExecutionCapChange(aExecutionCap);
688#else
689 return S_OK;
690#endif
691}
692
693STDMETHODIMP Session::OnVRDEServerChange(BOOL aRestart)
694{
695 LogFlowThisFunc(("\n"));
696
697 AutoCaller autoCaller(this);
698 AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
699
700 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
701 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
702 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
703#ifndef VBOX_COM_INPROC_API_CLIENT
704 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
705
706 return mConsole->onVRDEServerChange(aRestart);
707#else
708 return S_OK;
709#endif
710}
711
712STDMETHODIMP Session::OnVideoCaptureChange()
713{
714 LogFlowThisFunc(("\n"));
715
716 AutoCaller autoCaller(this);
717 AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
718
719 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
720 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
721 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
722#ifndef VBOX_COM_INPROC_API_CLIENT
723 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
724
725 return mConsole->onVideoCaptureChange();
726#else
727 return S_OK;
728#endif
729}
730
731STDMETHODIMP Session::OnUSBControllerChange()
732{
733 LogFlowThisFunc(("\n"));
734
735 AutoCaller autoCaller(this);
736 AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
737
738 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
739 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
740 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
741#ifndef VBOX_COM_INPROC_API_CLIENT
742 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
743
744 return mConsole->onUSBControllerChange();
745#else
746 return S_OK;
747#endif
748}
749
750STDMETHODIMP Session::OnSharedFolderChange(BOOL aGlobal)
751{
752 LogFlowThisFunc(("\n"));
753
754 AutoCaller autoCaller(this);
755 AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
756
757 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
758 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
759 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
760#ifndef VBOX_COM_INPROC_API_CLIENT
761 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
762
763 return mConsole->onSharedFolderChange(aGlobal);
764#else
765 return S_OK;
766#endif
767}
768
769STDMETHODIMP Session::OnClipboardModeChange(ClipboardMode_T aClipboardMode)
770{
771 LogFlowThisFunc(("\n"));
772
773 AutoCaller autoCaller(this);
774 AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
775
776 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
777 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
778 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
779#ifndef VBOX_COM_INPROC_API_CLIENT
780 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
781
782 return mConsole->onClipboardModeChange(aClipboardMode);
783#else
784 return S_OK;
785#endif
786}
787
788STDMETHODIMP Session::OnDragAndDropModeChange(DragAndDropMode_T aDragAndDropMode)
789{
790 LogFlowThisFunc(("\n"));
791
792 AutoCaller autoCaller(this);
793 AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
794
795 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
796 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
797#ifndef VBOX_COM_INPROC_API_CLIENT
798 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
799
800 return mConsole->onDragAndDropModeChange(aDragAndDropMode);
801#else
802 return S_OK;
803#endif
804}
805
806STDMETHODIMP Session::OnUSBDeviceAttach(IUSBDevice *aDevice,
807 IVirtualBoxErrorInfo *aError,
808 ULONG aMaskedIfs)
809{
810 LogFlowThisFunc(("\n"));
811
812 AutoCaller autoCaller(this);
813 AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
814
815 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
816 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
817 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
818#ifndef VBOX_COM_INPROC_API_CLIENT
819 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
820
821 return mConsole->onUSBDeviceAttach(aDevice, aError, aMaskedIfs);
822#else
823 return S_OK;
824#endif
825}
826
827STDMETHODIMP Session::OnUSBDeviceDetach(IN_BSTR aId,
828 IVirtualBoxErrorInfo *aError)
829{
830 LogFlowThisFunc(("\n"));
831
832 AutoCaller autoCaller(this);
833 AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
834
835 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
836 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
837 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
838#ifndef VBOX_COM_INPROC_API_CLIENT
839 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
840
841 return mConsole->onUSBDeviceDetach(aId, aError);
842#else
843 return S_OK;
844#endif
845}
846
847STDMETHODIMP Session::OnShowWindow(BOOL aCheck, BOOL *aCanShow, LONG64 *aWinId)
848{
849 AutoCaller autoCaller(this);
850 AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
851
852 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
853
854 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
855#ifndef VBOX_COM_INPROC_API_CLIENT
856 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
857#endif
858
859 if (mState != SessionState_Locked)
860 {
861 /* the call from Machine issued when the session is open can arrive
862 * after the session starts closing or gets closed. Note that when
863 * aCheck is false, we return E_FAIL to indicate that aWinId we return
864 * is not valid */
865 *aCanShow = FALSE;
866 *aWinId = 0;
867 return aCheck ? S_OK : E_FAIL;
868 }
869
870#ifndef VBOX_COM_INPROC_API_CLIENT
871 return mConsole->onShowWindow(aCheck, aCanShow, aWinId);
872#else
873 return S_OK;
874#endif
875}
876
877STDMETHODIMP Session::OnBandwidthGroupChange(IBandwidthGroup *aBandwidthGroup)
878{
879 LogFlowThisFunc(("\n"));
880
881 AutoCaller autoCaller(this);
882 AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
883
884 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
885 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
886 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
887#ifndef VBOX_COM_INPROC_API_CLIENT
888 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
889
890 return mConsole->onBandwidthGroupChange(aBandwidthGroup);
891#else
892 return S_OK;
893#endif
894}
895
896STDMETHODIMP Session::OnStorageDeviceChange(IMediumAttachment *aMediumAttachment, BOOL aRemove, BOOL aSilent)
897{
898 LogFlowThisFunc(("\n"));
899
900 AutoCaller autoCaller(this);
901 AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
902
903 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
904 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
905 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
906#ifndef VBOX_COM_INPROC_API_CLIENT
907 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
908
909 return mConsole->onStorageDeviceChange(aMediumAttachment, aRemove, aSilent);
910#else
911 return S_OK;
912#endif
913}
914
915STDMETHODIMP Session::AccessGuestProperty(IN_BSTR aName, IN_BSTR aValue, IN_BSTR aFlags,
916 BOOL aIsSetter, BSTR *aRetValue, LONG64 *aRetTimestamp, BSTR *aRetFlags)
917{
918#ifdef VBOX_WITH_GUEST_PROPS
919# ifndef VBOX_COM_INPROC_API_CLIENT
920 AutoCaller autoCaller(this);
921 AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
922
923 if (mState != SessionState_Locked)
924 return setError(VBOX_E_INVALID_VM_STATE,
925 tr("Machine is not locked by session (session state: %s)."),
926 Global::stringifySessionState(mState));
927 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
928 CheckComArgStrNotEmptyOrNull(aName);
929 if (!aIsSetter && !VALID_PTR(aRetValue))
930 return E_POINTER;
931 if (!aIsSetter && !VALID_PTR(aRetTimestamp))
932 return E_POINTER;
933 if (!aIsSetter && !VALID_PTR(aRetFlags))
934 return E_POINTER;
935 /* aValue can be NULL for a setter call if the property is to be deleted. */
936 if (aIsSetter && (aValue != NULL) && !VALID_PTR(aValue))
937 return setError(E_INVALIDARG, tr("Invalid value pointer"));
938 /* aFlags can be null if it is to be left as is */
939 if (aIsSetter && (aFlags != NULL) && !VALID_PTR(aFlags))
940 return setError(E_INVALIDARG, tr("Invalid flags pointer"));
941
942 /* If this session is not in a VM process fend off the call. The caller
943 * handles this correctly, by doing the operation in VBoxSVC. */
944 if (!mConsole)
945 return E_ACCESSDENIED;
946
947 if (!aIsSetter)
948 return mConsole->getGuestProperty(aName, aRetValue, aRetTimestamp, aRetFlags);
949 else
950 return mConsole->setGuestProperty(aName, aValue, aFlags);
951
952# else /* VBOX_COM_INPROC_API_CLIENT */
953 /** @todo This is nonsense, non-VM API users shouldn't need to deal with this
954 * method call, VBoxSVC should be clever enough to see that the
955 * session doesn't have a console! */
956 return E_ACCESSDENIED;
957# endif /* VBOX_COM_INPROC_API_CLIENT */
958
959#else /* VBOX_WITH_GUEST_PROPS */
960 ReturnComNotImplemented();
961#endif /* VBOX_WITH_GUEST_PROPS */
962}
963
964STDMETHODIMP Session::EnumerateGuestProperties(IN_BSTR aPatterns,
965 ComSafeArrayOut(BSTR, aNames),
966 ComSafeArrayOut(BSTR, aValues),
967 ComSafeArrayOut(LONG64, aTimestamps),
968 ComSafeArrayOut(BSTR, aFlags))
969{
970#if defined(VBOX_WITH_GUEST_PROPS) && !defined(VBOX_COM_INPROC_API_CLIENT)
971 AutoCaller autoCaller(this);
972 AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
973
974 if (mState != SessionState_Locked)
975 return setError(VBOX_E_INVALID_VM_STATE,
976 tr("Machine is not locked by session (session state: %s)."),
977 Global::stringifySessionState(mState));
978 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
979 if (!VALID_PTR(aPatterns) && (aPatterns != NULL))
980 return E_POINTER;
981 if (ComSafeArrayOutIsNull(aNames))
982 return E_POINTER;
983 if (ComSafeArrayOutIsNull(aValues))
984 return E_POINTER;
985 if (ComSafeArrayOutIsNull(aTimestamps))
986 return E_POINTER;
987 if (ComSafeArrayOutIsNull(aFlags))
988 return E_POINTER;
989
990 /* If this session is not in a VM process fend off the call. The caller
991 * handles this correctly, by doing the operation in VBoxSVC. */
992 if (!mConsole)
993 return E_ACCESSDENIED;
994
995 return mConsole->enumerateGuestProperties(aPatterns,
996 ComSafeArrayOutArg(aNames),
997 ComSafeArrayOutArg(aValues),
998 ComSafeArrayOutArg(aTimestamps),
999 ComSafeArrayOutArg(aFlags));
1000#else /* VBOX_WITH_GUEST_PROPS not defined */
1001 ReturnComNotImplemented();
1002#endif /* VBOX_WITH_GUEST_PROPS not defined */
1003}
1004
1005STDMETHODIMP Session::OnlineMergeMedium(IMediumAttachment *aMediumAttachment,
1006 ULONG aSourceIdx, ULONG aTargetIdx,
1007 IProgress *aProgress)
1008{
1009 AutoCaller autoCaller(this);
1010 AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
1011
1012 if (mState != SessionState_Locked)
1013 return setError(VBOX_E_INVALID_VM_STATE,
1014 tr("Machine is not locked by session (session state: %s)."),
1015 Global::stringifySessionState(mState));
1016#ifndef VBOX_COM_INPROC_API_CLIENT
1017 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
1018 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
1019 CheckComArgNotNull(aMediumAttachment);
1020
1021 return mConsole->onlineMergeMedium(aMediumAttachment,
1022 aSourceIdx, aTargetIdx,
1023 aProgress);
1024#else
1025 AssertFailed();
1026 return E_NOTIMPL;
1027#endif
1028}
1029
1030STDMETHODIMP Session::EnableVMMStatistics(BOOL aEnable)
1031{
1032 AutoCaller autoCaller(this);
1033 AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
1034
1035 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1036 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
1037 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
1038#ifndef VBOX_COM_INPROC_API_CLIENT
1039 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
1040
1041 mConsole->enableVMMStatistics(aEnable);
1042
1043 return S_OK;
1044#else
1045 AssertFailed();
1046 return E_NOTIMPL;
1047#endif
1048}
1049
1050STDMETHODIMP Session::PauseWithReason(Reason_T aReason)
1051{
1052 AutoCaller autoCaller(this);
1053 AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
1054
1055 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1056 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
1057 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
1058#ifndef VBOX_COM_INPROC_API_CLIENT
1059 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
1060
1061 return mConsole->pause(aReason);
1062#else
1063 AssertFailed();
1064 return E_NOTIMPL;
1065#endif
1066}
1067
1068STDMETHODIMP Session::ResumeWithReason(Reason_T aReason)
1069{
1070 AutoCaller autoCaller(this);
1071 AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
1072
1073 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1074 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
1075 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
1076#ifndef VBOX_COM_INPROC_API_CLIENT
1077 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
1078
1079 return mConsole->resume(aReason);
1080#else
1081 AssertFailed();
1082 return E_NOTIMPL;
1083#endif
1084}
1085
1086STDMETHODIMP Session::SaveStateWithReason(Reason_T aReason, IProgress **aProgress)
1087{
1088 AutoCaller autoCaller(this);
1089 AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
1090
1091 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1092 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
1093 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
1094#ifndef VBOX_COM_INPROC_API_CLIENT
1095 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
1096
1097 return mConsole->saveState(aReason, aProgress);
1098#else
1099 AssertFailed();
1100 return E_NOTIMPL;
1101#endif
1102}
1103
1104// private methods
1105///////////////////////////////////////////////////////////////////////////////
1106
1107/**
1108 * Unlocks a machine associated with the current session.
1109 *
1110 * @param aFinalRelease called as a result of FinalRelease()
1111 * @param aFromServer called as a result of Uninitialize()
1112 *
1113 * @note To be called only from #uninit(), #UnlockMachine() or #Uninitialize().
1114 * @note Locks this object for writing.
1115 */
1116HRESULT Session::unlockMachine(bool aFinalRelease, bool aFromServer)
1117{
1118 LogFlowThisFuncEnter();
1119 LogFlowThisFunc(("aFinalRelease=%d, isFromServer=%d\n",
1120 aFinalRelease, aFromServer));
1121
1122 AutoCaller autoCaller(this);
1123 AssertComRCReturnRC(autoCaller.rc());
1124
1125 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1126
1127 LogFlowThisFunc(("mState=%s, mType=%d\n", Global::stringifySessionState(mState), mType));
1128
1129 if (mState != SessionState_Locked)
1130 {
1131 Assert(mState == SessionState_Spawning);
1132
1133 /* The session object is going to be uninitialized before it has been
1134 * assigned a direct console of the machine the client requested to open
1135 * a remote session to using IVirtualBox:: openRemoteSession(). It is OK
1136 * only if this close request comes from the server (for example, it
1137 * detected that the VM process it started terminated before opening a
1138 * direct session). Otherwise, it means that the client is too fast and
1139 * trying to close the session before waiting for the progress object it
1140 * got from IVirtualBox:: openRemoteSession() to complete, so assert. */
1141 Assert(aFromServer);
1142
1143 mState = SessionState_Unlocked;
1144 mType = SessionType_Null;
1145
1146 Assert(!mClientTokenHolder);
1147
1148 LogFlowThisFuncLeave();
1149 return S_OK;
1150 }
1151
1152 /* go to the closing state */
1153 mState = SessionState_Unlocking;
1154
1155 if (mType == SessionType_WriteLock)
1156 {
1157#ifndef VBOX_COM_INPROC_API_CLIENT
1158 if (!mConsole.isNull())
1159 {
1160 mConsole->uninit();
1161 mConsole.setNull();
1162 }
1163#else
1164 mRemoteMachine.setNull();
1165#endif
1166 }
1167 else
1168 {
1169 mRemoteMachine.setNull();
1170 mRemoteConsole.setNull();
1171 }
1172
1173 ComPtr<IProgress> progress;
1174
1175 if (!aFinalRelease && !aFromServer)
1176 {
1177 /*
1178 * We trigger OnSessionEnd() only when the session closes itself using
1179 * Close(). Note that if isFinalRelease = TRUE here, this means that
1180 * the client process has already initialized the termination procedure
1181 * without issuing Close() and the IPC channel is no more operational --
1182 * so we cannot call the server's method (it will definitely fail). The
1183 * server will instead simply detect the abnormal client death (since
1184 * OnSessionEnd() is not called) and reset the machine state to Aborted.
1185 */
1186
1187 /*
1188 * while waiting for OnSessionEnd() to complete one of our methods
1189 * can be called by the server (for example, Uninitialize(), if the
1190 * direct session has initiated a closure just a bit before us) so
1191 * we need to release the lock to avoid deadlocks. The state is already
1192 * SessionState_Closing here, so it's safe.
1193 */
1194 alock.release();
1195
1196 LogFlowThisFunc(("Calling mControl->OnSessionEnd()...\n"));
1197 HRESULT rc = mControl->OnSessionEnd(this, progress.asOutParam());
1198 LogFlowThisFunc(("mControl->OnSessionEnd()=%08X\n", rc));
1199
1200 alock.acquire();
1201
1202 /*
1203 * If we get E_UNEXPECTED this means that the direct session has already
1204 * been closed, we're just too late with our notification and nothing more
1205 *
1206 * bird: Seems E_ACCESSDENIED is what gets returned these days; see
1207 * VirtualBoxBase::addCaller.
1208 */
1209 if (mType != SessionType_WriteLock && (rc == E_UNEXPECTED || rc == E_ACCESSDENIED))
1210 rc = S_OK;
1211
1212#ifndef DEBUG_bird /* I don't want clients crashing on me just because VBoxSVC went belly up. */
1213 AssertComRC(rc);
1214#endif
1215 }
1216
1217 mControl.setNull();
1218
1219 if (mType == SessionType_WriteLock)
1220 {
1221 if (mClientTokenHolder)
1222 {
1223 delete mClientTokenHolder;
1224 mClientTokenHolder = NULL;
1225 }
1226
1227 if (!aFinalRelease && !aFromServer)
1228 {
1229 /*
1230 * Wait for the server to grab the semaphore and destroy the session
1231 * machine (allowing us to open a new session with the same machine
1232 * once this method returns)
1233 */
1234 Assert(!!progress);
1235 if (progress)
1236 progress->WaitForCompletion(-1);
1237 }
1238 }
1239
1240 mState = SessionState_Unlocked;
1241 mType = SessionType_Null;
1242
1243 /* release the VirtualBox instance as the very last step */
1244 mVirtualBox.setNull();
1245
1246 LogFlowThisFuncLeave();
1247 return S_OK;
1248}
1249
1250/* vi: set tabstop=4 shiftwidth=4 expandtab: */
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