VirtualBox

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

Last change on this file since 103415 was 98262, checked in by vboxsync, 23 months ago

Main: rc() -> hrc()/vrc(). bugref:10223

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 40.9 KB
Line 
1/* $Id: SessionImpl.cpp 98262 2023-01-24 01:42:14Z vboxsync $ */
2/** @file
3 * VBox Client Session COM Class implementation in VBoxC.
4 */
5
6/*
7 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.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.hrc();
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::onGuestDebugControlChange(const ComPtr<IGuestDebugControl> &aGuestDebugControl)
877{
878 LogFlowThisFunc(("\n"));
879
880 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
881 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
882 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
883#ifndef VBOX_COM_INPROC_API_CLIENT
884 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
885
886 return mConsole->i_onGuestDebugControlChange(aGuestDebugControl);
887#else
888 RT_NOREF(aGuestDebugControl);
889 return S_OK;
890#endif
891}
892
893HRESULT Session::onUSBDeviceAttach(const ComPtr<IUSBDevice> &aDevice,
894 const ComPtr<IVirtualBoxErrorInfo> &aError,
895 ULONG aMaskedInterfaces,
896 const com::Utf8Str &aCaptureFilename)
897{
898 LogFlowThisFunc(("\n"));
899
900 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
901 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
902 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
903#ifndef VBOX_COM_INPROC_API_CLIENT
904 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
905
906 return mConsole->i_onUSBDeviceAttach(aDevice, aError, aMaskedInterfaces, aCaptureFilename);
907#else
908 RT_NOREF(aDevice, aError, aMaskedInterfaces, aCaptureFilename);
909 return S_OK;
910#endif
911}
912
913HRESULT Session::onUSBDeviceDetach(const com::Guid &aId,
914 const ComPtr<IVirtualBoxErrorInfo> &aError)
915{
916 LogFlowThisFunc(("\n"));
917
918 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
919 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
920 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
921#ifndef VBOX_COM_INPROC_API_CLIENT
922 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
923
924 return mConsole->i_onUSBDeviceDetach(aId.toUtf16().raw(), aError);
925#else
926 RT_NOREF(aId, aError);
927 return S_OK;
928#endif
929}
930
931HRESULT Session::onShowWindow(BOOL aCheck, BOOL *aCanShow, LONG64 *aWinId)
932{
933 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
934
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#endif
939
940 if (mState != SessionState_Locked)
941 {
942 /* the call from Machine issued when the session is open can arrive
943 * after the session starts closing or gets closed. Note that when
944 * aCheck is false, we return E_FAIL to indicate that aWinId we return
945 * is not valid */
946 *aCanShow = FALSE;
947 *aWinId = 0;
948 return aCheck ? S_OK : E_FAIL;
949 }
950
951#ifndef VBOX_COM_INPROC_API_CLIENT
952 return mConsole->i_onShowWindow(aCheck, aCanShow, aWinId);
953#else
954 return S_OK;
955#endif
956}
957
958HRESULT Session::onBandwidthGroupChange(const ComPtr<IBandwidthGroup> &aBandwidthGroup)
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_onBandwidthGroupChange(aBandwidthGroup);
969#else
970 RT_NOREF(aBandwidthGroup);
971 return S_OK;
972#endif
973}
974
975HRESULT Session::onStorageDeviceChange(const ComPtr<IMediumAttachment> &aMediumAttachment, BOOL aRemove, BOOL aSilent)
976{
977 LogFlowThisFunc(("\n"));
978
979 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
980 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
981 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
982#ifndef VBOX_COM_INPROC_API_CLIENT
983 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
984
985 return mConsole->i_onStorageDeviceChange(aMediumAttachment, aRemove, aSilent);
986#else
987 RT_NOREF(aMediumAttachment, aRemove, aSilent);
988 return S_OK;
989#endif
990}
991
992HRESULT Session::accessGuestProperty(const com::Utf8Str &aName, const com::Utf8Str &aValue, const com::Utf8Str &aFlags,
993 ULONG aAccessMode, com::Utf8Str &aRetValue, LONG64 *aRetTimestamp, com::Utf8Str &aRetFlags)
994{
995#ifdef VBOX_WITH_GUEST_PROPS
996# ifndef 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 if (aName.isEmpty())
1003 return E_INVALIDARG;
1004 if (aAccessMode == 0 && !RT_VALID_PTR(aRetTimestamp))
1005 return E_POINTER;
1006
1007 /* If this session is not in a VM process fend off the call. The caller
1008 * handles this correctly, by doing the operation in VBoxSVC. */
1009 if (!mConsole)
1010 return E_ACCESSDENIED;
1011
1012 HRESULT hr;
1013 if (aAccessMode == 2)
1014 hr = mConsole->i_deleteGuestProperty(aName);
1015 else if (aAccessMode == 1)
1016 hr = mConsole->i_setGuestProperty(aName, aValue, aFlags);
1017 else if (aAccessMode == 0)
1018 hr = mConsole->i_getGuestProperty(aName, &aRetValue, aRetTimestamp, &aRetFlags);
1019 else
1020 hr = E_INVALIDARG;
1021
1022 return hr;
1023# else /* VBOX_COM_INPROC_API_CLIENT */
1024 /** @todo This is nonsense, non-VM API users shouldn't need to deal with this
1025 * method call, VBoxSVC should be clever enough to see that the
1026 * session doesn't have a console! */
1027 RT_NOREF(aName, aValue, aFlags, aAccessMode, aRetValue, aRetTimestamp, aRetFlags);
1028 return E_ACCESSDENIED;
1029# endif /* VBOX_COM_INPROC_API_CLIENT */
1030
1031#else /* VBOX_WITH_GUEST_PROPS */
1032 ReturnComNotImplemented();
1033#endif /* VBOX_WITH_GUEST_PROPS */
1034}
1035
1036HRESULT Session::enumerateGuestProperties(const com::Utf8Str &aPatterns,
1037 std::vector<com::Utf8Str> &aKeys,
1038 std::vector<com::Utf8Str> &aValues,
1039 std::vector<LONG64> &aTimestamps,
1040 std::vector<com::Utf8Str> &aFlags)
1041{
1042#if defined(VBOX_WITH_GUEST_PROPS) && !defined(VBOX_COM_INPROC_API_CLIENT)
1043 if (mState != SessionState_Locked)
1044 return setError(VBOX_E_INVALID_VM_STATE,
1045 tr("Machine is not locked by session (session state: %s)."),
1046 Global::stringifySessionState(mState));
1047 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
1048
1049 /* If this session is not in a VM process fend off the call. The caller
1050 * handles this correctly, by doing the operation in VBoxSVC. */
1051 if (!mConsole)
1052 return E_ACCESSDENIED;
1053
1054 return mConsole->i_enumerateGuestProperties(aPatterns, aKeys, aValues, aTimestamps, aFlags);
1055
1056#else /* VBOX_WITH_GUEST_PROPS not defined */
1057 RT_NOREF(aPatterns, aKeys, aValues, aTimestamps, aFlags);
1058 ReturnComNotImplemented();
1059#endif /* VBOX_WITH_GUEST_PROPS not defined */
1060}
1061
1062HRESULT Session::onlineMergeMedium(const ComPtr<IMediumAttachment> &aMediumAttachment, ULONG aSourceIdx,
1063 ULONG aTargetIdx, const ComPtr<IProgress> &aProgress)
1064{
1065 if (mState != SessionState_Locked)
1066 return setError(VBOX_E_INVALID_VM_STATE,
1067 tr("Machine is not locked by session (session state: %s)."),
1068 Global::stringifySessionState(mState));
1069#ifndef VBOX_COM_INPROC_API_CLIENT
1070 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
1071 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
1072
1073 return mConsole->i_onlineMergeMedium(aMediumAttachment,
1074 aSourceIdx, aTargetIdx,
1075 aProgress);
1076#else
1077 RT_NOREF(aMediumAttachment, aSourceIdx, aTargetIdx, aProgress);
1078 AssertFailed();
1079 return E_NOTIMPL;
1080#endif
1081}
1082
1083HRESULT Session::reconfigureMediumAttachments(const std::vector<ComPtr<IMediumAttachment> > &aAttachments)
1084{
1085 if (mState != SessionState_Locked)
1086 return setError(VBOX_E_INVALID_VM_STATE,
1087 tr("Machine is not locked by session (session state: %s)."),
1088 Global::stringifySessionState(mState));
1089#ifndef VBOX_COM_INPROC_API_CLIENT
1090 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
1091 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
1092
1093 return mConsole->i_reconfigureMediumAttachments(aAttachments);
1094#else
1095 RT_NOREF(aAttachments);
1096 AssertFailed();
1097 return E_NOTIMPL;
1098#endif
1099}
1100
1101HRESULT Session::enableVMMStatistics(BOOL aEnable)
1102{
1103 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1104 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
1105 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
1106#ifndef VBOX_COM_INPROC_API_CLIENT
1107 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
1108
1109 mConsole->i_enableVMMStatistics(aEnable);
1110
1111 return S_OK;
1112#else
1113 RT_NOREF(aEnable);
1114 AssertFailed();
1115 return E_NOTIMPL;
1116#endif
1117}
1118
1119HRESULT Session::pauseWithReason(Reason_T aReason)
1120{
1121 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1122 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
1123 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
1124#ifndef VBOX_COM_INPROC_API_CLIENT
1125 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
1126
1127 return mConsole->i_pause(aReason);
1128#else
1129 RT_NOREF(aReason);
1130 AssertFailed();
1131 return E_NOTIMPL;
1132#endif
1133}
1134
1135HRESULT Session::resumeWithReason(Reason_T aReason)
1136{
1137 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1138 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
1139 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
1140#ifndef VBOX_COM_INPROC_API_CLIENT
1141 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
1142
1143 AutoWriteLock dummyLock(mConsole COMMA_LOCKVAL_SRC_POS);
1144 return mConsole->i_resume(aReason, dummyLock);
1145#else
1146 RT_NOREF(aReason);
1147 AssertFailed();
1148 return E_NOTIMPL;
1149#endif
1150}
1151
1152HRESULT Session::saveStateWithReason(Reason_T aReason,
1153 const ComPtr<IProgress> &aProgress,
1154 const ComPtr<ISnapshot> &aSnapshot,
1155 const Utf8Str &aStateFilePath,
1156 BOOL aPauseVM, BOOL *aLeftPaused)
1157{
1158 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1159 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
1160 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
1161#ifndef VBOX_COM_INPROC_API_CLIENT
1162 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
1163
1164 bool fLeftPaused = false;
1165 HRESULT hrc = mConsole->i_saveState(aReason, aProgress, aSnapshot, aStateFilePath, !!aPauseVM, fLeftPaused);
1166 if (aLeftPaused)
1167 *aLeftPaused = fLeftPaused;
1168 return hrc;
1169#else
1170 RT_NOREF(aReason, aProgress, aSnapshot, aStateFilePath, aPauseVM, aLeftPaused);
1171 AssertFailed();
1172 return E_NOTIMPL;
1173#endif
1174}
1175
1176HRESULT Session::cancelSaveStateWithReason()
1177{
1178 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1179 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
1180 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
1181#ifndef VBOX_COM_INPROC_API_CLIENT
1182 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
1183
1184 return mConsole->i_cancelSaveState();
1185#else
1186 AssertFailed();
1187 return E_NOTIMPL;
1188#endif
1189}
1190
1191// private methods
1192///////////////////////////////////////////////////////////////////////////////
1193
1194/**
1195 * Unlocks a machine associated with the current session.
1196 *
1197 * @param aFinalRelease called as a result of FinalRelease()
1198 * @param aFromServer called as a result of Uninitialize()
1199 * @param aLockW The write lock this object is protected with.
1200 * Must be acquired already and will be released
1201 * and later reacquired during the unlocking.
1202 *
1203 * @note To be called only from #uninit(), ISession::UnlockMachine() or
1204 * ISession::Uninitialize().
1205 */
1206HRESULT Session::i_unlockMachine(bool aFinalRelease, bool aFromServer, AutoWriteLock &aLockW)
1207{
1208 LogFlowThisFuncEnter();
1209 LogFlowThisFunc(("aFinalRelease=%d, isFromServer=%d\n",
1210 aFinalRelease, aFromServer));
1211
1212 LogFlowThisFunc(("mState=%s, mType=%d\n", ::stringifySessionState(mState), mType));
1213
1214 Assert(aLockW.isWriteLockOnCurrentThread());
1215
1216 if (mState != SessionState_Locked)
1217 {
1218 Assert(mState == SessionState_Spawning);
1219
1220 /* The session object is going to be uninitialized before it has been
1221 * assigned a direct console of the machine the client requested to open
1222 * a remote session to using IVirtualBox:: openRemoteSession(). It is OK
1223 * only if this close request comes from the server (for example, it
1224 * detected that the VM process it started terminated before opening a
1225 * direct session). Otherwise, it means that the client is too fast and
1226 * trying to close the session before waiting for the progress object it
1227 * got from IVirtualBox:: openRemoteSession() to complete, so assert. */
1228 Assert(aFromServer);
1229
1230 mState = SessionState_Unlocked;
1231 mType = SessionType_Null;
1232
1233 Assert(!mClientTokenHolder);
1234
1235 LogFlowThisFuncLeave();
1236 return S_OK;
1237 }
1238
1239 /* go to the closing state */
1240 mState = SessionState_Unlocking;
1241
1242 if (mType == SessionType_WriteLock)
1243 {
1244#ifndef VBOX_COM_INPROC_API_CLIENT
1245 if (!mConsole.isNull())
1246 {
1247 mConsole->uninit();
1248 mConsole.setNull();
1249 }
1250#else
1251 mRemoteMachine.setNull();
1252#endif
1253 }
1254 else
1255 {
1256 mRemoteMachine.setNull();
1257 mRemoteConsole.setNull();
1258 }
1259
1260 ComPtr<IProgress> progress;
1261
1262 if (!aFinalRelease && !aFromServer)
1263 {
1264 /*
1265 * We trigger OnSessionEnd() only when the session closes itself using
1266 * Close(). Note that if isFinalRelease = TRUE here, this means that
1267 * the client process has already initialized the termination procedure
1268 * without issuing Close() and the IPC channel is no more operational --
1269 * so we cannot call the server's method (it will definitely fail). The
1270 * server will instead simply detect the abnormal client death (since
1271 * OnSessionEnd() is not called) and reset the machine state to Aborted.
1272 */
1273
1274 /*
1275 * while waiting for OnSessionEnd() to complete one of our methods
1276 * can be called by the server (for example, Uninitialize(), if the
1277 * direct session has initiated a closure just a bit before us) so
1278 * we need to release the lock to avoid deadlocks. The state is already
1279 * SessionState_Closing here, so it's safe.
1280 */
1281 aLockW.release();
1282
1283 Assert(!aLockW.isWriteLockOnCurrentThread());
1284
1285 LogFlowThisFunc(("Calling mControl->OnSessionEnd()...\n"));
1286 HRESULT hrc = mControl->OnSessionEnd(this, progress.asOutParam());
1287 LogFlowThisFunc(("mControl->OnSessionEnd()=%08X\n", hrc));
1288
1289 aLockW.acquire();
1290
1291 /*
1292 * If we get E_UNEXPECTED this means that the direct session has already
1293 * been closed, we're just too late with our notification and nothing more
1294 *
1295 * bird: Seems E_ACCESSDENIED is what gets returned these days; see
1296 * ObjectState::addCaller.
1297 */
1298 if (mType != SessionType_WriteLock && (hrc == E_UNEXPECTED || hrc == E_ACCESSDENIED))
1299 hrc = S_OK;
1300
1301#if !defined(DEBUG_bird) && !defined(DEBUG_andy) /* I don't want clients crashing on me just because VBoxSVC went belly up. */
1302 AssertComRC(hrc);
1303#endif
1304 }
1305
1306 mControl.setNull();
1307
1308 if (mType == SessionType_WriteLock)
1309 {
1310 if (mClientTokenHolder)
1311 {
1312 delete mClientTokenHolder;
1313 mClientTokenHolder = NULL;
1314 }
1315
1316 if (!aFinalRelease && !aFromServer)
1317 {
1318 /*
1319 * Wait for the server to grab the semaphore and destroy the session
1320 * machine (allowing us to open a new session with the same machine
1321 * once this method returns)
1322 */
1323 Assert(!!progress);
1324 if (progress)
1325 progress->WaitForCompletion(-1);
1326 }
1327 }
1328
1329 mState = SessionState_Unlocked;
1330 mType = SessionType_Null;
1331
1332 /* release the VirtualBox instance as the very last step */
1333 mVirtualBox.setNull();
1334
1335 LogFlowThisFuncLeave();
1336 return S_OK;
1337}
1338
1339/* 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