VirtualBox

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

Last change on this file since 105266 was 105266, checked in by vboxsync, 2 months ago

Recording: Implemented support for a dedicated progress object, which is exposed to API clients. This can be used for better tracking the recording progress as well as for error reporting. The RecordingSettings API also now has a dedicated start() method to start recording, as well as support for attaching to an already ongoing recording by retrieving the progress object at a later time. Adapted FE/Qt (draft, see @todos), FE/VBoxManage and the Validation Kit testdriver to the new APIs. VBoxManage also can attach to an ongoing recording now. The recording progress object also will have multiple operations to get the recording progress for convenience. bugref:10718

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 41.4 KB
Line 
1/* $Id: SessionImpl.cpp 105266 2024-07-11 07:49:37Z 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::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);
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);
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