VirtualBox

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

Last change on this file since 52232 was 52232, checked in by vboxsync, 11 years ago

Main: ISession partially converted to use API wrappers

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette