VirtualBox

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

Last change on this file since 92154 was 91312, checked in by vboxsync, 3 years ago

Main: bugref:1909: Prepared the API translation engine to using in ExtPacks and VBoxManage. Added using API translation engine in ExtPacks. Allowed VBox compilation with NLS enabled and GUI disabled. Allowed ExtPacks only compilation with NLS translation enabled.

  • 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 91312 2021-09-20 11:06:57Z 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
264 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
265
266#ifndef VBOX_COM_INPROC_API_CLIENT
267 AssertMsgReturn(mType == SessionType_WriteLock && !!mConsole,
268 ("This is not a direct session!\n"),
269 VBOX_E_INVALID_OBJECT_STATE);
270
271 /* return a failure if the session already transitioned to Closing
272 * but the server hasn't processed Machine::OnSessionEnd() yet. */
273 if (mState != SessionState_Locked)
274 return VBOX_E_INVALID_VM_STATE;
275
276 mConsole.queryInterfaceTo(aConsole.asOutParam());
277
278 LogFlowThisFuncLeave();
279
280 return S_OK;
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->init(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", Global::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", Global::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.

© 2023 Oracle
ContactPrivacy policyTerms of Use