VirtualBox

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

Last change on this file since 59341 was 57326, checked in by vboxsync, 9 years ago

Also don't want to crash clients on me because VBoxSVC went nuts.

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