VirtualBox

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

Last change on this file since 93931 was 93444, checked in by vboxsync, 3 years ago

VMM,Main,HostServices: Use a function table for accessing the VBoxVMM.dll/so/dylib functionality, and load it dynamically when the Console object is initialized. Also converted a few drivers in Main to use device helpers to get config values and such. bugref:10074

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