VirtualBox

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

Last change on this file since 92430 was 92274, checked in by vboxsync, 3 years ago

Main/Session::getRemoteConsole: Don't was space on a read-locking in the VBOX_COM_INPROC_API_CLIENT stub.

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