VirtualBox

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

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

Main/Medium: redesign API level medium locking, needed conversions from MediaList to MediumLockLists in several places, forced cleanups elsewhere, too
Main/Token: introduced token objects for controlling the unlocking, will be used as a general concept in the future
Main/Snapshot: snapshot deletion needed significant cleanups as it was still using many shortcuts, directly calling the API to lock media instead of using lock lists. Now much better, and the online snapshot deletion is also a lot cleaner as it no longer passes unnecessary parameters around which are already known in the machine/snapshot code
Main/MediumLock: small improvements, now has a mode which skips locking already locked media, needed by the Snapshot code where we have overlapping lock lists and have to update the original one instead
Main/Console+Session+Machine: follow-up changes for the online snapshot merging parameter passing simplification, plus an unrelated lock order violation fix in Machine which happens only for inaccessible machines
Main/testcase: update correspondingly
doc: update SDK reference

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 36.5 KB
Line 
1/* $Id: SessionImpl.cpp 48297 2013-09-05 09:57:44Z 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 IProgress *aProgress)
983{
984 AutoCaller autoCaller(this);
985 AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
986
987 if (mState != SessionState_Locked)
988 return setError(VBOX_E_INVALID_VM_STATE,
989 tr("Machine is not locked by session (session state: %s)."),
990 Global::stringifySessionState(mState));
991#ifndef VBOX_COM_INPROC_API_CLIENT
992 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
993 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
994 CheckComArgNotNull(aMediumAttachment);
995
996 return mConsole->onlineMergeMedium(aMediumAttachment,
997 aSourceIdx, aTargetIdx,
998 aProgress);
999#else
1000 return E_NOTIMPL;
1001#endif
1002}
1003
1004STDMETHODIMP Session::EnableVMMStatistics(BOOL aEnable)
1005{
1006 AutoCaller autoCaller(this);
1007 AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
1008
1009 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1010 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
1011 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
1012#ifndef VBOX_COM_INPROC_API_CLIENT
1013 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
1014
1015 mConsole->enableVMMStatistics(aEnable);
1016
1017 return S_OK;
1018#else
1019 return E_NOTIMPL;
1020#endif
1021}
1022
1023STDMETHODIMP Session::PauseWithReason(Reason_T aReason)
1024{
1025 AutoCaller autoCaller(this);
1026 AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
1027
1028 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1029 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
1030 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
1031#ifndef VBOX_COM_INPROC_API_CLIENT
1032 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
1033
1034 return mConsole->pause(aReason);
1035#else
1036 return E_NOTIMPL;
1037#endif
1038}
1039
1040STDMETHODIMP Session::ResumeWithReason(Reason_T aReason)
1041{
1042 AutoCaller autoCaller(this);
1043 AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
1044
1045 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1046 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
1047 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
1048#ifndef VBOX_COM_INPROC_API_CLIENT
1049 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
1050
1051 return mConsole->resume(aReason);
1052#else
1053 return E_NOTIMPL;
1054#endif
1055}
1056
1057STDMETHODIMP Session::SaveStateWithReason(Reason_T aReason, IProgress **aProgress)
1058{
1059 AutoCaller autoCaller(this);
1060 AssertComRCReturn(autoCaller.rc(), autoCaller.rc());
1061
1062 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1063 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
1064 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
1065#ifndef VBOX_COM_INPROC_API_CLIENT
1066 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
1067
1068 return mConsole->saveState(aReason, aProgress);
1069#else
1070 return E_NOTIMPL;
1071#endif
1072}
1073
1074// private methods
1075///////////////////////////////////////////////////////////////////////////////
1076
1077/**
1078 * Unlocks a machine associated with the current session.
1079 *
1080 * @param aFinalRelease called as a result of FinalRelease()
1081 * @param aFromServer called as a result of Uninitialize()
1082 *
1083 * @note To be called only from #uninit(), #UnlockMachine() or #Uninitialize().
1084 * @note Locks this object for writing.
1085 */
1086HRESULT Session::unlockMachine(bool aFinalRelease, bool aFromServer)
1087{
1088 LogFlowThisFuncEnter();
1089 LogFlowThisFunc(("aFinalRelease=%d, isFromServer=%d\n",
1090 aFinalRelease, aFromServer));
1091
1092 AutoCaller autoCaller(this);
1093 AssertComRCReturnRC(autoCaller.rc());
1094
1095 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1096
1097 LogFlowThisFunc(("mState=%s, mType=%d\n", Global::stringifySessionState(mState), mType));
1098
1099 if (mState != SessionState_Locked)
1100 {
1101 Assert(mState == SessionState_Spawning);
1102
1103 /* The session object is going to be uninitialized before it has been
1104 * assigned a direct console of the machine the client requested to open
1105 * a remote session to using IVirtualBox:: openRemoteSession(). It is OK
1106 * only if this close request comes from the server (for example, it
1107 * detected that the VM process it started terminated before opening a
1108 * direct session). Otherwise, it means that the client is too fast and
1109 * trying to close the session before waiting for the progress object it
1110 * got from IVirtualBox:: openRemoteSession() to complete, so assert. */
1111 Assert(aFromServer);
1112
1113 mState = SessionState_Unlocked;
1114 mType = SessionType_Null;
1115
1116 Assert(!mClientTokenHolder);
1117
1118 LogFlowThisFuncLeave();
1119 return S_OK;
1120 }
1121
1122 /* go to the closing state */
1123 mState = SessionState_Unlocking;
1124
1125 if (mType == SessionType_WriteLock)
1126 {
1127#ifndef VBOX_COM_INPROC_API_CLIENT
1128 if (!mConsole.isNull())
1129 {
1130 mConsole->uninit();
1131 mConsole.setNull();
1132 }
1133#endif
1134 }
1135 else
1136 {
1137 mRemoteMachine.setNull();
1138#ifndef VBOX_COM_INPROC_API_CLIENT
1139 mRemoteConsole.setNull();
1140#endif
1141 }
1142
1143 ComPtr<IProgress> progress;
1144
1145 if (!aFinalRelease && !aFromServer)
1146 {
1147 /*
1148 * We trigger OnSessionEnd() only when the session closes itself using
1149 * Close(). Note that if isFinalRelease = TRUE here, this means that
1150 * the client process has already initialized the termination procedure
1151 * without issuing Close() and the IPC channel is no more operational --
1152 * so we cannot call the server's method (it will definitely fail). The
1153 * server will instead simply detect the abnormal client death (since
1154 * OnSessionEnd() is not called) and reset the machine state to Aborted.
1155 */
1156
1157 /*
1158 * while waiting for OnSessionEnd() to complete one of our methods
1159 * can be called by the server (for example, Uninitialize(), if the
1160 * direct session has initiated a closure just a bit before us) so
1161 * we need to release the lock to avoid deadlocks. The state is already
1162 * SessionState_Closing here, so it's safe.
1163 */
1164 alock.release();
1165
1166 LogFlowThisFunc(("Calling mControl->OnSessionEnd()...\n"));
1167 HRESULT rc = mControl->OnSessionEnd(this, progress.asOutParam());
1168 LogFlowThisFunc(("mControl->OnSessionEnd()=%08X\n", rc));
1169
1170 alock.acquire();
1171
1172 /*
1173 * If we get E_UNEXPECTED this means that the direct session has already
1174 * been closed, we're just too late with our notification and nothing more
1175 *
1176 * bird: Seems E_ACCESSDENIED is what gets returned these days; see
1177 * VirtualBoxBase::addCaller.
1178 */
1179 if (mType != SessionType_WriteLock && (rc == E_UNEXPECTED || rc == E_ACCESSDENIED))
1180 rc = S_OK;
1181
1182#ifndef DEBUG_bird /* I don't want clients crashing on me just because VBoxSVC went belly up. */
1183 AssertComRC(rc);
1184#endif
1185 }
1186
1187 mControl.setNull();
1188
1189 if (mType == SessionType_WriteLock)
1190 {
1191 if (mClientTokenHolder)
1192 {
1193 delete mClientTokenHolder;
1194 mClientTokenHolder = NULL;
1195 }
1196
1197 if (!aFinalRelease && !aFromServer)
1198 {
1199 /*
1200 * Wait for the server to grab the semaphore and destroy the session
1201 * machine (allowing us to open a new session with the same machine
1202 * once this method returns)
1203 */
1204 Assert(!!progress);
1205 if (progress)
1206 progress->WaitForCompletion(-1);
1207 }
1208 }
1209
1210 mState = SessionState_Unlocked;
1211 mType = SessionType_Null;
1212
1213 /* release the VirtualBox instance as the very last step */
1214 mVirtualBox.setNull();
1215
1216 LogFlowThisFuncLeave();
1217 return S_OK;
1218}
1219
1220/* 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