VirtualBox

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

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

Main/VirtualBox+Machine+Session: separate out the client death detection functionality into separate objects

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