VirtualBox

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

Last change on this file since 55631 was 55214, checked in by vboxsync, 10 years ago

Main/Console+Machine+Session+Snapshot: move the save state and snapshot related methods from IConsole to IMachine, with lots of unavoidable code restructuring and cleanup. Also define two new machine states (so that the "Saving" one is specifically for saving state now) which requires more changes everywhere
Frontends: necessary adjustments
doc/SDK: document the changes

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