VirtualBox

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

Last change on this file since 52901 was 52481, checked in by vboxsync, 10 years ago

6813 - MachineImpl.cpp - IInternalMachineControl changes.

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