VirtualBox

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

Last change on this file since 56653 was 56450, checked in by vboxsync, 10 years ago

Main: Style

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 36.1 KB
Line 
1/* $Id: SessionImpl.cpp 56450 2015-06-16 13:21:07Z 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 AssertMsgReturn( mState == SessionState_Locked
530 || mState == SessionState_Spawning,
531 ("Session is in wrong state (%ld), expected locked (%ld) or spawning (%ld)\n",
532 mState, SessionState_Locked, SessionState_Spawning),
533 VBOX_E_INVALID_VM_STATE);
534
535 /* close ourselves */
536 rc = i_unlockMachine(false /* aFinalRelease */, true /* aFromServer */, alock);
537 }
538 else if (getObjectState().getState() == ObjectState::InUninit)
539 {
540 /*
541 * We might have already entered Session::uninit() at this point,
542 * return silently
543 */
544 LogFlowThisFunc(("Already uninitialized.\n"));
545 }
546 else
547 {
548 Log1WarningThisFunc(("UNEXPECTED uninitialization!\n"));
549 rc = autoCaller.rc();
550 }
551
552 LogFlowThisFunc(("rc=%08X\n", rc));
553 LogFlowThisFuncLeave();
554
555 return rc;
556}
557
558HRESULT Session::onNetworkAdapterChange(const ComPtr<INetworkAdapter> &aNetworkAdapter,
559 BOOL aChangeAdapter)
560
561{
562 LogFlowThisFunc(("\n"));
563
564 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
565 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
566 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
567#ifndef VBOX_COM_INPROC_API_CLIENT
568 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
569
570 return mConsole->i_onNetworkAdapterChange(aNetworkAdapter, aChangeAdapter);
571#else
572 return S_OK;
573#endif
574}
575
576HRESULT Session::onSerialPortChange(const ComPtr<ISerialPort> &aSerialPort)
577{
578 LogFlowThisFunc(("\n"));
579
580 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
581 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
582 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
583#ifndef VBOX_COM_INPROC_API_CLIENT
584 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
585
586 return mConsole->i_onSerialPortChange(aSerialPort);
587#else
588 return S_OK;
589#endif
590}
591
592HRESULT Session::onParallelPortChange(const ComPtr<IParallelPort> &aParallelPort)
593{
594 LogFlowThisFunc(("\n"));
595
596 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
597 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
598 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
599#ifndef VBOX_COM_INPROC_API_CLIENT
600 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
601
602 return mConsole->i_onParallelPortChange(aParallelPort);
603#else
604 return S_OK;
605#endif
606}
607
608HRESULT Session::onStorageControllerChange()
609{
610 LogFlowThisFunc(("\n"));
611
612 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
613 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
614 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
615#ifndef VBOX_COM_INPROC_API_CLIENT
616 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
617
618 return mConsole->i_onStorageControllerChange();
619#else
620 return S_OK;
621#endif
622}
623
624HRESULT Session::onMediumChange(const ComPtr<IMediumAttachment> &aMediumAttachment,
625 BOOL aForce)
626{
627 LogFlowThisFunc(("\n"));
628
629 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
630 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
631 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
632#ifndef VBOX_COM_INPROC_API_CLIENT
633 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
634
635 return mConsole->i_onMediumChange(aMediumAttachment, aForce);
636#else
637 return S_OK;
638#endif
639}
640
641HRESULT Session::onCPUChange(ULONG aCpu, BOOL aAdd)
642{
643 LogFlowThisFunc(("\n"));
644
645 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
646 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
647 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
648#ifndef VBOX_COM_INPROC_API_CLIENT
649 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
650
651 return mConsole->i_onCPUChange(aCpu, aAdd);
652#else
653 return S_OK;
654#endif
655}
656
657HRESULT Session::onCPUExecutionCapChange(ULONG aExecutionCap)
658{
659 LogFlowThisFunc(("\n"));
660
661 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
662 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
663 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
664#ifndef VBOX_COM_INPROC_API_CLIENT
665 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
666
667 return mConsole->i_onCPUExecutionCapChange(aExecutionCap);
668#else
669 return S_OK;
670#endif
671}
672
673HRESULT Session::onVRDEServerChange(BOOL aRestart)
674{
675 LogFlowThisFunc(("\n"));
676
677 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
678 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
679 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
680#ifndef VBOX_COM_INPROC_API_CLIENT
681 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
682
683 return mConsole->i_onVRDEServerChange(aRestart);
684#else
685 return S_OK;
686#endif
687}
688
689HRESULT Session::onVideoCaptureChange()
690{
691 LogFlowThisFunc(("\n"));
692
693 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
694 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
695 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
696#ifndef VBOX_COM_INPROC_API_CLIENT
697 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
698
699 return mConsole->i_onVideoCaptureChange();
700#else
701 return S_OK;
702#endif
703}
704
705HRESULT Session::onUSBControllerChange()
706{
707 LogFlowThisFunc(("\n"));
708
709 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
710 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
711 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
712#ifndef VBOX_COM_INPROC_API_CLIENT
713 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
714
715 return mConsole->i_onUSBControllerChange();
716#else
717 return S_OK;
718#endif
719}
720
721HRESULT Session::onSharedFolderChange(BOOL aGlobal)
722{
723 LogFlowThisFunc(("\n"));
724
725 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
726 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
727 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
728#ifndef VBOX_COM_INPROC_API_CLIENT
729 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
730
731 return mConsole->i_onSharedFolderChange(aGlobal);
732#else
733 return S_OK;
734#endif
735}
736
737HRESULT Session::onClipboardModeChange(ClipboardMode_T aClipboardMode)
738{
739 LogFlowThisFunc(("\n"));
740
741 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
742 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
743 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
744#ifndef VBOX_COM_INPROC_API_CLIENT
745 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
746
747 return mConsole->i_onClipboardModeChange(aClipboardMode);
748#else
749 return S_OK;
750#endif
751}
752
753HRESULT Session::onDnDModeChange(DnDMode_T aDndMode)
754{
755 LogFlowThisFunc(("\n"));
756
757 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
758 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
759#ifndef VBOX_COM_INPROC_API_CLIENT
760 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
761 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
762
763 return mConsole->i_onDnDModeChange(aDndMode);
764#else
765 return S_OK;
766#endif
767}
768
769HRESULT Session::onUSBDeviceAttach(const ComPtr<IUSBDevice> &aDevice,
770 const ComPtr<IVirtualBoxErrorInfo> &aError,
771 ULONG aMaskedInterfaces,
772 const com::Utf8Str &aCaptureFilename)
773{
774 LogFlowThisFunc(("\n"));
775
776 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
777 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
778 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
779#ifndef VBOX_COM_INPROC_API_CLIENT
780 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
781
782 return mConsole->i_onUSBDeviceAttach(aDevice, aError, aMaskedInterfaces, aCaptureFilename);
783#else
784 return S_OK;
785#endif
786}
787
788HRESULT Session::onUSBDeviceDetach(const com::Guid &aId,
789 const ComPtr<IVirtualBoxErrorInfo> &aError)
790{
791 LogFlowThisFunc(("\n"));
792
793 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
794 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
795 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
796#ifndef VBOX_COM_INPROC_API_CLIENT
797 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
798
799 return mConsole->i_onUSBDeviceDetach(aId.toUtf16().raw(), aError);
800#else
801 return S_OK;
802#endif
803}
804
805HRESULT Session::onShowWindow(BOOL aCheck, BOOL *aCanShow, LONG64 *aWinId)
806{
807 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
808
809 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
810#ifndef VBOX_COM_INPROC_API_CLIENT
811 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
812#endif
813
814 if (mState != SessionState_Locked)
815 {
816 /* the call from Machine issued when the session is open can arrive
817 * after the session starts closing or gets closed. Note that when
818 * aCheck is false, we return E_FAIL to indicate that aWinId we return
819 * is not valid */
820 *aCanShow = FALSE;
821 *aWinId = 0;
822 return aCheck ? S_OK : E_FAIL;
823 }
824
825#ifndef VBOX_COM_INPROC_API_CLIENT
826 return mConsole->i_onShowWindow(aCheck, aCanShow, aWinId);
827#else
828 return S_OK;
829#endif
830}
831
832HRESULT Session::onBandwidthGroupChange(const ComPtr<IBandwidthGroup> &aBandwidthGroup)
833{
834 LogFlowThisFunc(("\n"));
835
836 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
837 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
838 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
839#ifndef VBOX_COM_INPROC_API_CLIENT
840 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
841
842 return mConsole->i_onBandwidthGroupChange(aBandwidthGroup);
843#else
844 return S_OK;
845#endif
846}
847
848HRESULT Session::onStorageDeviceChange(const ComPtr<IMediumAttachment> &aMediumAttachment, BOOL aRemove, BOOL aSilent)
849{
850 LogFlowThisFunc(("\n"));
851
852 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
853 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
854 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
855#ifndef VBOX_COM_INPROC_API_CLIENT
856 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
857
858 return mConsole->i_onStorageDeviceChange(aMediumAttachment, aRemove, aSilent);
859#else
860 return S_OK;
861#endif
862}
863
864HRESULT Session::accessGuestProperty(const com::Utf8Str &aName, const com::Utf8Str &aValue, const com::Utf8Str &aFlags,
865 ULONG aAccessMode, com::Utf8Str &aRetValue, LONG64 *aRetTimestamp, com::Utf8Str &aRetFlags)
866{
867#ifdef VBOX_WITH_GUEST_PROPS
868# ifndef VBOX_COM_INPROC_API_CLIENT
869 if (mState != SessionState_Locked)
870 return setError(VBOX_E_INVALID_VM_STATE,
871 tr("Machine is not locked by session (session state: %s)."),
872 Global::stringifySessionState(mState));
873 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
874 if (aName.isEmpty())
875 return E_INVALIDARG;
876 if (aAccessMode == 0 && !RT_VALID_PTR(aRetTimestamp))
877 return E_POINTER;
878
879 /* If this session is not in a VM process fend off the call. The caller
880 * handles this correctly, by doing the operation in VBoxSVC. */
881 if (!mConsole)
882 return E_ACCESSDENIED;
883
884 HRESULT hr;
885 if (aAccessMode == 2)
886 hr = mConsole->i_deleteGuestProperty(aName);
887 else if (aAccessMode == 1)
888 hr = mConsole->i_setGuestProperty(aName, aValue, aFlags);
889 else if (aAccessMode == 0)
890 hr = mConsole->i_getGuestProperty(aName, &aRetValue, aRetTimestamp, &aRetFlags);
891 else
892 hr = E_INVALIDARG;
893
894 return hr;
895# else /* VBOX_COM_INPROC_API_CLIENT */
896 /** @todo This is nonsense, non-VM API users shouldn't need to deal with this
897 * method call, VBoxSVC should be clever enough to see that the
898 * session doesn't have a console! */
899 return E_ACCESSDENIED;
900# endif /* VBOX_COM_INPROC_API_CLIENT */
901
902#else /* VBOX_WITH_GUEST_PROPS */
903 ReturnComNotImplemented();
904#endif /* VBOX_WITH_GUEST_PROPS */
905}
906
907HRESULT Session::enumerateGuestProperties(const com::Utf8Str &aPatterns,
908 std::vector<com::Utf8Str> &aKeys,
909 std::vector<com::Utf8Str> &aValues,
910 std::vector<LONG64> &aTimestamps,
911 std::vector<com::Utf8Str> &aFlags)
912{
913#if defined(VBOX_WITH_GUEST_PROPS) && !defined(VBOX_COM_INPROC_API_CLIENT)
914 if (mState != SessionState_Locked)
915 return setError(VBOX_E_INVALID_VM_STATE,
916 tr("Machine is not locked by session (session state: %s)."),
917 Global::stringifySessionState(mState));
918 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
919
920 /* If this session is not in a VM process fend off the call. The caller
921 * handles this correctly, by doing the operation in VBoxSVC. */
922 if (!mConsole)
923 return E_ACCESSDENIED;
924
925 return mConsole->i_enumerateGuestProperties(aPatterns, aKeys, aValues, aTimestamps, aFlags);
926
927#else /* VBOX_WITH_GUEST_PROPS not defined */
928 ReturnComNotImplemented();
929#endif /* VBOX_WITH_GUEST_PROPS not defined */
930}
931
932HRESULT Session::onlineMergeMedium(const ComPtr<IMediumAttachment> &aMediumAttachment, ULONG aSourceIdx,
933 ULONG aTargetIdx, const ComPtr<IProgress> &aProgress)
934{
935 if (mState != SessionState_Locked)
936 return setError(VBOX_E_INVALID_VM_STATE,
937 tr("Machine is not locked by session (session state: %s)."),
938 Global::stringifySessionState(mState));
939#ifndef VBOX_COM_INPROC_API_CLIENT
940 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
941 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
942
943 return mConsole->i_onlineMergeMedium(aMediumAttachment,
944 aSourceIdx, aTargetIdx,
945 aProgress);
946#else
947 AssertFailed();
948 return E_NOTIMPL;
949#endif
950}
951
952HRESULT Session::reconfigureMediumAttachments(const std::vector<ComPtr<IMediumAttachment> > &aAttachments)
953{
954 if (mState != SessionState_Locked)
955 return setError(VBOX_E_INVALID_VM_STATE,
956 tr("Machine is not locked by session (session state: %s)."),
957 Global::stringifySessionState(mState));
958#ifndef VBOX_COM_INPROC_API_CLIENT
959 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
960 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
961
962 return mConsole->i_reconfigureMediumAttachments(aAttachments);
963#else
964 AssertFailed();
965 return E_NOTIMPL;
966#endif
967}
968
969HRESULT Session::enableVMMStatistics(BOOL aEnable)
970{
971 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
972 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
973 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
974#ifndef VBOX_COM_INPROC_API_CLIENT
975 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
976
977 mConsole->i_enableVMMStatistics(aEnable);
978
979 return S_OK;
980#else
981 AssertFailed();
982 return E_NOTIMPL;
983#endif
984}
985
986HRESULT Session::pauseWithReason(Reason_T aReason)
987{
988 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
989 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
990 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
991#ifndef VBOX_COM_INPROC_API_CLIENT
992 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
993
994 return mConsole->i_pause(aReason);
995#else
996 AssertFailed();
997 return E_NOTIMPL;
998#endif
999}
1000
1001HRESULT Session::resumeWithReason(Reason_T aReason)
1002{
1003 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1004 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
1005 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
1006#ifndef VBOX_COM_INPROC_API_CLIENT
1007 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
1008
1009 AutoWriteLock dummyLock(mConsole COMMA_LOCKVAL_SRC_POS);
1010 return mConsole->i_resume(aReason, dummyLock);
1011#else
1012 AssertFailed();
1013 return E_NOTIMPL;
1014#endif
1015}
1016
1017HRESULT Session::saveStateWithReason(Reason_T aReason, const ComPtr<IProgress> &aProgress, const Utf8Str &aStateFilePath, BOOL aPauseVM, BOOL *aLeftPaused)
1018{
1019 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1020 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
1021 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
1022#ifndef VBOX_COM_INPROC_API_CLIENT
1023 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
1024
1025 bool fLeftPaused = false;
1026 HRESULT rc = mConsole->i_saveState(aReason, aProgress, aStateFilePath, !!aPauseVM, fLeftPaused);
1027 if (aLeftPaused)
1028 *aLeftPaused = fLeftPaused;
1029 return rc;
1030#else
1031 AssertFailed();
1032 return E_NOTIMPL;
1033#endif
1034}
1035
1036HRESULT Session::cancelSaveStateWithReason()
1037{
1038 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1039 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
1040 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
1041#ifndef VBOX_COM_INPROC_API_CLIENT
1042 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
1043
1044 return mConsole->i_cancelSaveState();
1045#else
1046 AssertFailed();
1047 return E_NOTIMPL;
1048#endif
1049}
1050
1051// private methods
1052///////////////////////////////////////////////////////////////////////////////
1053
1054/**
1055 * Unlocks a machine associated with the current session.
1056 *
1057 * @param aFinalRelease called as a result of FinalRelease()
1058 * @param aFromServer called as a result of Uninitialize()
1059 * @param pLockW The write lock this object is protected with.
1060 * Must be acquired already and will be released
1061 * and later reacquired during the unlocking.
1062 *
1063 * @note To be called only from #uninit(), #UnlockMachine() or #Uninitialize().
1064 */
1065HRESULT Session::i_unlockMachine(bool aFinalRelease, bool aFromServer, AutoWriteLock &aLockW)
1066{
1067 LogFlowThisFuncEnter();
1068 LogFlowThisFunc(("aFinalRelease=%d, isFromServer=%d\n",
1069 aFinalRelease, aFromServer));
1070
1071 LogFlowThisFunc(("mState=%s, mType=%d\n", Global::stringifySessionState(mState), mType));
1072
1073 Assert(aLockW.isWriteLockOnCurrentThread());
1074
1075 if (mState != SessionState_Locked)
1076 {
1077 Assert(mState == SessionState_Spawning);
1078
1079 /* The session object is going to be uninitialized before it has been
1080 * assigned a direct console of the machine the client requested to open
1081 * a remote session to using IVirtualBox:: openRemoteSession(). It is OK
1082 * only if this close request comes from the server (for example, it
1083 * detected that the VM process it started terminated before opening a
1084 * direct session). Otherwise, it means that the client is too fast and
1085 * trying to close the session before waiting for the progress object it
1086 * got from IVirtualBox:: openRemoteSession() to complete, so assert. */
1087 Assert(aFromServer);
1088
1089 mState = SessionState_Unlocked;
1090 mType = SessionType_Null;
1091
1092 Assert(!mClientTokenHolder);
1093
1094 LogFlowThisFuncLeave();
1095 return S_OK;
1096 }
1097
1098 /* go to the closing state */
1099 mState = SessionState_Unlocking;
1100
1101 if (mType == SessionType_WriteLock)
1102 {
1103#ifndef VBOX_COM_INPROC_API_CLIENT
1104 if (!mConsole.isNull())
1105 {
1106 mConsole->uninit();
1107 mConsole.setNull();
1108 }
1109#else
1110 mRemoteMachine.setNull();
1111#endif
1112 }
1113 else
1114 {
1115 mRemoteMachine.setNull();
1116 mRemoteConsole.setNull();
1117 }
1118
1119 ComPtr<IProgress> progress;
1120
1121 if (!aFinalRelease && !aFromServer)
1122 {
1123 /*
1124 * We trigger OnSessionEnd() only when the session closes itself using
1125 * Close(). Note that if isFinalRelease = TRUE here, this means that
1126 * the client process has already initialized the termination procedure
1127 * without issuing Close() and the IPC channel is no more operational --
1128 * so we cannot call the server's method (it will definitely fail). The
1129 * server will instead simply detect the abnormal client death (since
1130 * OnSessionEnd() is not called) and reset the machine state to Aborted.
1131 */
1132
1133 /*
1134 * while waiting for OnSessionEnd() to complete one of our methods
1135 * can be called by the server (for example, Uninitialize(), if the
1136 * direct session has initiated a closure just a bit before us) so
1137 * we need to release the lock to avoid deadlocks. The state is already
1138 * SessionState_Closing here, so it's safe.
1139 */
1140 aLockW.release();
1141
1142 Assert(!aLockW.isWriteLockOnCurrentThread());
1143
1144 LogFlowThisFunc(("Calling mControl->OnSessionEnd()...\n"));
1145 HRESULT rc = mControl->OnSessionEnd(this, progress.asOutParam());
1146 LogFlowThisFunc(("mControl->OnSessionEnd()=%08X\n", rc));
1147
1148 aLockW.acquire();
1149
1150 /*
1151 * If we get E_UNEXPECTED this means that the direct session has already
1152 * been closed, we're just too late with our notification and nothing more
1153 *
1154 * bird: Seems E_ACCESSDENIED is what gets returned these days; see
1155 * VirtualBoxBase::addCaller.
1156 */
1157 if (mType != SessionType_WriteLock && (rc == E_UNEXPECTED || rc == E_ACCESSDENIED))
1158 rc = S_OK;
1159
1160#ifndef DEBUG_bird /* I don't want clients crashing on me just because VBoxSVC went belly up. */
1161 AssertComRC(rc);
1162#endif
1163 }
1164
1165 mControl.setNull();
1166
1167 if (mType == SessionType_WriteLock)
1168 {
1169 if (mClientTokenHolder)
1170 {
1171 delete mClientTokenHolder;
1172 mClientTokenHolder = NULL;
1173 }
1174
1175 if (!aFinalRelease && !aFromServer)
1176 {
1177 /*
1178 * Wait for the server to grab the semaphore and destroy the session
1179 * machine (allowing us to open a new session with the same machine
1180 * once this method returns)
1181 */
1182 Assert(!!progress);
1183 if (progress)
1184 progress->WaitForCompletion(-1);
1185 }
1186 }
1187
1188 mState = SessionState_Unlocked;
1189 mType = SessionType_Null;
1190
1191 /* release the VirtualBox instance as the very last step */
1192 mVirtualBox.setNull();
1193
1194 LogFlowThisFuncLeave();
1195 return S_OK;
1196}
1197
1198/* 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