VirtualBox

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

Last change on this file since 51797 was 51612, checked in by vboxsync, 10 years ago

6813 Use of server side API wrapper code - ConsoleImpl.cpp

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