VirtualBox

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

Last change on this file since 106297 was 106061, checked in by vboxsync, 3 months ago

Copyright year updates by scm.

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