VirtualBox

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

最後變更 在這個檔案從96407是 96407,由 vboxsync 提交於 3 年 前

scm copyright and license note update

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

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