VirtualBox

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

Last change on this file since 48282 was 48282, checked in by vboxsync, 12 years ago

32-bit main API on 64-bit solaris.

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