VirtualBox

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

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

Main: ISession fully converted to use API wrappers

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 34.5 KB
Line 
1/* $Id: SessionImpl.cpp 52248 2014-07-31 19:00:11Z vboxsync $ */
2/** @file
3 * VBox Client Session COM Class implementation in VBoxC.
4 */
5
6/*
7 * Copyright (C) 2006-2014 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#include "SessionImpl.h"
19#include "ConsoleImpl.h"
20#include "Global.h"
21#include "ClientTokenHolder.h"
22
23#include "AutoCaller.h"
24#include "Logging.h"
25
26#include <VBox/err.h>
27#include <iprt/process.h>
28
29/**
30 * Local macro to check whether the session is open and return an error if not.
31 * @note Don't forget to do |Auto[Reader]Lock alock (this);| before using this
32 * macro.
33 */
34#define CHECK_OPEN() \
35 do { \
36 if (mState != SessionState_Locked) \
37 return setError(E_UNEXPECTED, tr ("The session is not locked (session state: %s)"), \
38 Global::stringifySessionState(mState)); \
39 } while (0)
40
41// constructor / destructor
42/////////////////////////////////////////////////////////////////////////////
43
44Session::Session()
45{
46}
47
48Session::~Session()
49{
50}
51
52HRESULT Session::FinalConstruct()
53{
54 LogFlowThisFunc(("\n"));
55
56 HRESULT rc = init();
57
58 BaseFinalConstruct();
59
60 return rc;
61}
62
63void Session::FinalRelease()
64{
65 LogFlowThisFunc(("\n"));
66
67 uninit();
68
69 BaseFinalRelease();
70}
71
72// public initializer/uninitializer for internal purposes only
73/////////////////////////////////////////////////////////////////////////////
74
75/**
76 * Initializes the Session object.
77 */
78HRESULT Session::init()
79{
80 /* Enclose the state transition NotReady->InInit->Ready */
81 AutoInitSpan autoInitSpan(this);
82 AssertReturn(autoInitSpan.isOk(), E_FAIL);
83
84 LogFlowThisFuncEnter();
85
86 mState = SessionState_Unlocked;
87 mType = SessionType_Null;
88
89 mClientTokenHolder = NULL;
90
91 /* Confirm a successful initialization when it's the case */
92 autoInitSpan.setSucceeded();
93
94 LogFlowThisFuncLeave();
95
96 return S_OK;
97}
98
99/**
100 * Uninitializes the Session object.
101 *
102 * @note Locks this object for writing.
103 */
104void Session::uninit()
105{
106 LogFlowThisFuncEnter();
107
108 /* Enclose the state transition Ready->InUninit->NotReady */
109 AutoUninitSpan autoUninitSpan(this);
110 if (autoUninitSpan.uninitDone())
111 {
112 LogFlowThisFunc(("Already uninitialized.\n"));
113 LogFlowThisFuncLeave();
114 return;
115 }
116
117 /* close() needs write lock */
118 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
119
120 if (mState != SessionState_Unlocked)
121 {
122 Assert(mState == SessionState_Locked ||
123 mState == SessionState_Spawning);
124
125 HRESULT rc = unlockMachine(true /* aFinalRelease */, false /* aFromServer */);
126 AssertComRC(rc);
127 }
128
129 LogFlowThisFuncLeave();
130}
131
132// ISession properties
133/////////////////////////////////////////////////////////////////////////////
134
135HRESULT Session::getState(SessionState_T *aState)
136{
137 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
138
139 *aState = mState;
140
141 return S_OK;
142}
143
144HRESULT Session::getType(SessionType_T *aType)
145{
146 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
147
148 CHECK_OPEN();
149
150 *aType = mType;
151 return S_OK;
152}
153
154HRESULT Session::getMachine(ComPtr<IMachine> &aMachine)
155{
156 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
157
158 CHECK_OPEN();
159
160 HRESULT rc;
161#ifndef VBOX_COM_INPROC_API_CLIENT
162 if (mConsole)
163 rc = mConsole->i_machine().queryInterfaceTo(aMachine.asOutParam());
164 else
165#endif
166 rc = mRemoteMachine.queryInterfaceTo(aMachine.asOutParam());
167 if (FAILED(rc))
168 {
169 /** @todo VBox 3.3: replace E_FAIL with rc here. */
170#ifndef VBOX_COM_INPROC_API_CLIENT
171 if (mConsole)
172 setError(E_FAIL, tr("Failed to query the session machine (%Rhrc)"), rc);
173 else
174#endif
175 if (FAILED_DEAD_INTERFACE(rc))
176 setError(E_FAIL, tr("Peer process crashed"));
177 else
178 setError(E_FAIL, tr("Failed to query the remote session machine (%Rhrc)"), rc);
179 }
180
181 return rc;
182}
183
184HRESULT Session::getConsole(ComPtr<IConsole> &aConsole)
185{
186 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
187
188 CHECK_OPEN();
189
190 HRESULT rc = S_OK;
191#ifndef VBOX_COM_INPROC_API_CLIENT
192 if (mConsole)
193 rc = mConsole.queryInterfaceTo(aConsole.asOutParam());
194 else
195#endif
196 rc = mRemoteConsole.queryInterfaceTo(aConsole.asOutParam());
197
198 if (FAILED(rc))
199 {
200 /** @todo VBox 3.3: replace E_FAIL with rc here. */
201#ifndef VBOX_COM_INPROC_API_CLIENT
202 if (mConsole)
203 setError(E_FAIL, tr("Failed to query the console (%Rhrc)"), rc);
204 else
205#endif
206 if (FAILED_DEAD_INTERFACE(rc))
207 setError(E_FAIL, tr("Peer process crashed"));
208 else
209 setError(E_FAIL, tr("Failed to query the remote console (%Rhrc)"), rc);
210 }
211
212 return rc;
213}
214
215// ISession methods
216/////////////////////////////////////////////////////////////////////////////
217HRESULT Session::unlockMachine()
218{
219 LogFlowThisFunc(("mState=%d, mType=%d\n", mState, mType));
220
221 /* close() needs write lock */
222 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
223
224 CHECK_OPEN();
225
226 return unlockMachine(false /* aFinalRelease */, false /* aFromServer */);
227}
228
229// IInternalSessionControl methods
230/////////////////////////////////////////////////////////////////////////////
231HRESULT Session::getPID(ULONG *aPid)
232{
233 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
234
235 *aPid = (ULONG)RTProcSelf();
236 AssertCompile(sizeof(*aPid) == sizeof(RTPROCESS));
237
238 return S_OK;
239}
240
241HRESULT Session::getRemoteConsole(ComPtr<IConsole> &aConsole)
242{
243 LogFlowThisFuncEnter();
244
245 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
246
247#ifndef VBOX_COM_INPROC_API_CLIENT
248 AssertMsgReturn(mType == SessionType_WriteLock && !!mConsole,
249 ("This is not a direct session!\n"),
250 VBOX_E_INVALID_OBJECT_STATE);
251
252 /* return a failure if the session already transitioned to Closing
253 * but the server hasn't processed Machine::OnSessionEnd() yet. */
254 if (mState != SessionState_Locked)
255 return VBOX_E_INVALID_VM_STATE;
256
257 mConsole.queryInterfaceTo(aConsole.asOutParam());
258
259 LogFlowThisFuncLeave();
260
261 return S_OK;
262
263#else /* VBOX_COM_INPROC_API_CLIENT */
264 AssertFailed();
265 return VBOX_E_INVALID_OBJECT_STATE;
266#endif /* VBOX_COM_INPROC_API_CLIENT */
267}
268
269#ifndef VBOX_WITH_GENERIC_SESSION_WATCHER
270HRESULT Session::assignMachine(const ComPtr<IMachine> &aMachine,
271 LockType_T aLockType,
272 const com::Utf8Str &aTokenId)
273#else
274HRESULT Session::assignMachine(const ComPtr<IMachine> &aMachine,
275 LockType_T aLockType,
276 const ComPtr<IToken> &aToken)
277#endif /* !VBOX_WITH_GENERIC_SESSION_WATCHER */
278{
279 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
280
281 AssertReturn(mState == SessionState_Unlocked, VBOX_E_INVALID_VM_STATE);
282
283 if (!aMachine)
284 {
285 /*
286 * A special case: the server informs us that this session has been
287 * passed to IMachine::launchVMProcess() so this session will become
288 * remote (but not existing) when AssignRemoteMachine() is called.
289 */
290
291 AssertReturn(mType == SessionType_Null, VBOX_E_INVALID_OBJECT_STATE);
292 mType = SessionType_Remote;
293 mState = SessionState_Spawning;
294
295 return S_OK;
296 }
297
298 /* query IInternalMachineControl interface */
299 mControl = aMachine;
300 AssertReturn(!!mControl, E_FAIL);
301
302#ifndef VBOX_COM_INPROC_API_CLIENT
303 HRESULT rc = mConsole.createObject();
304 AssertComRCReturn(rc, rc);
305
306 rc = mConsole->init(aMachine, mControl, aLockType);
307 AssertComRCReturn(rc, rc);
308#else
309 HRESULT rc = S_OK;
310 mRemoteMachine = aMachine;
311#endif
312
313#ifndef VBOX_WITH_GENERIC_SESSION_WATCHER
314 Utf8Str strTokenId(aTokenId);
315 Assert(!strTokenId.isEmpty());
316#else /* VBOX_WITH_GENERIC_SESSION_WATCHER */
317 Assert(!aToken.isNull());
318#endif /* VBOX_WITH_GENERIC_SESSION_WATCHER */
319 /* create the machine client token */
320 try
321 {
322#ifndef VBOX_WITH_GENERIC_SESSION_WATCHER
323 mClientTokenHolder = new ClientTokenHolder(strTokenId);
324#else /* VBOX_WITH_GENERIC_SESSION_WATCHER */
325 mClientTokenHolder = new ClientTokenHolder(aToken);
326#endif /* VBOX_WITH_GENERIC_SESSION_WATCHER */
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#ifndef VBOX_COM_INPROC_API_CLIENT
356 if (!mConsole.isNull())
357 {
358 mConsole->uninit();
359 mConsole.setNull();
360 }
361#endif
362 }
363
364 return rc;
365}
366
367HRESULT Session::assignRemoteMachine(const ComPtr<IMachine> &aMachine,
368 const ComPtr<IConsole> &aConsole)
369
370{
371 AssertReturn(aMachine && aConsole, E_INVALIDARG);
372
373 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
374
375 AssertReturn(mState == SessionState_Unlocked ||
376 mState == SessionState_Spawning, VBOX_E_INVALID_VM_STATE);
377
378 HRESULT rc = E_FAIL;
379
380 /* query IInternalMachineControl interface */
381 mControl = aMachine;
382 AssertReturn(!!mControl, E_FAIL);
383
384 /// @todo (dmik)
385 // currently, the remote session returns the same machine and
386 // console objects as the direct session, thus giving the
387 // (remote) client full control over the direct session. For the
388 // console, it is the desired behavior (the ability to control
389 // VM execution is a must for the remote session). What about
390 // the machine object, we may want to prevent the remote client
391 // from modifying machine data. In this case, we must:
392 // 1) assign the Machine object (instead of the SessionMachine
393 // object that is passed to this method) to mRemoteMachine;
394 // 2) remove GetMachine() property from the IConsole interface
395 // because it always returns the SessionMachine object
396 // (alternatively, we can supply a separate IConsole
397 // implementation that will return the Machine object in
398 // response to GetMachine()).
399
400 mRemoteMachine = aMachine;
401 mRemoteConsole = aConsole;
402
403 /*
404 * Reference the VirtualBox object to ensure the server is up
405 * until the session is closed
406 */
407 rc = aMachine->COMGETTER(Parent)(mVirtualBox.asOutParam());
408
409 if (SUCCEEDED(rc))
410 {
411 /*
412 * RemoteSession type can be already set by AssignMachine() when its
413 * argument is NULL (a special case)
414 */
415 if (mType != SessionType_Remote)
416 mType = SessionType_Shared;
417 else
418 Assert(mState == SessionState_Spawning);
419
420 mState = SessionState_Locked;
421 }
422 else
423 {
424 /* some cleanup */
425 mControl.setNull();
426 mRemoteMachine.setNull();
427 mRemoteConsole.setNull();
428 }
429
430 LogFlowThisFunc(("rc=%08X\n", rc));
431 LogFlowThisFuncLeave();
432
433 return rc;
434}
435
436HRESULT Session::updateMachineState(MachineState_T aMachineState)
437{
438
439 if (getObjectState().getState() != ObjectState::Ready)
440 {
441 /*
442 * We might have already entered Session::uninit() at this point, so
443 * return silently (not interested in the state change during uninit)
444 */
445 LogFlowThisFunc(("Already uninitialized.\n"));
446 return S_OK;
447 }
448
449 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
450
451 if (mState == SessionState_Unlocking)
452 {
453 LogFlowThisFunc(("Already being unlocked.\n"));
454 return S_OK;
455 }
456
457 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
458 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
459
460 AssertReturn(!mControl.isNull(), E_FAIL);
461#ifndef VBOX_COM_INPROC_API_CLIENT
462 AssertReturn(!mConsole.isNull(), E_FAIL);
463
464 return mConsole->i_updateMachineState(aMachineState);
465#else
466 return S_OK;
467#endif
468}
469
470HRESULT Session::uninitialize()
471{
472 LogFlowThisFuncEnter();
473
474 AutoCaller autoCaller(this);
475
476 HRESULT rc = S_OK;
477
478 if (getObjectState().getState() == ObjectState::Ready)
479 {
480 /* close() needs write lock */
481 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
482
483 LogFlowThisFunc(("mState=%s, mType=%d\n", Global::stringifySessionState(mState), mType));
484
485 if (mState == SessionState_Unlocking)
486 {
487 LogFlowThisFunc(("Already being unlocked.\n"));
488 return S_OK;
489 }
490
491 AssertMsgReturn( mState == SessionState_Locked
492 || mState == SessionState_Spawning,
493 ("Session is in wrong state (%ld), expected locked (%ld) or spawning (%ld)\n",
494 mState, SessionState_Locked, SessionState_Spawning),
495 VBOX_E_INVALID_VM_STATE);
496
497 /* close ourselves */
498 rc = unlockMachine(false /* aFinalRelease */, true /* aFromServer */);
499 }
500 else if (getObjectState().getState() == ObjectState::InUninit)
501 {
502 /*
503 * We might have already entered Session::uninit() at this point,
504 * return silently
505 */
506 LogFlowThisFunc(("Already uninitialized.\n"));
507 }
508 else
509 {
510 LogWarningThisFunc(("UNEXPECTED uninitialization!\n"));
511 rc = autoCaller.rc();
512 }
513
514 LogFlowThisFunc(("rc=%08X\n", rc));
515 LogFlowThisFuncLeave();
516
517 return rc;
518}
519
520HRESULT Session::onNetworkAdapterChange(const ComPtr<INetworkAdapter> &aNetworkAdapter,
521 BOOL aChangeAdapter)
522
523{
524 LogFlowThisFunc(("\n"));
525
526 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
527 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
528 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
529#ifndef VBOX_COM_INPROC_API_CLIENT
530 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
531
532 return mConsole->i_onNetworkAdapterChange(aNetworkAdapter, aChangeAdapter);
533#else
534 return S_OK;
535#endif
536}
537
538HRESULT Session::onSerialPortChange(const ComPtr<ISerialPort> &aSerialPort)
539{
540 LogFlowThisFunc(("\n"));
541
542 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
543 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
544 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
545#ifndef VBOX_COM_INPROC_API_CLIENT
546 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
547
548 return mConsole->i_onSerialPortChange(aSerialPort);
549#else
550 return S_OK;
551#endif
552}
553
554HRESULT Session::onParallelPortChange(const ComPtr<IParallelPort> &aParallelPort)
555{
556 LogFlowThisFunc(("\n"));
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#ifndef VBOX_COM_INPROC_API_CLIENT
562 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
563
564 return mConsole->i_onParallelPortChange(aParallelPort);
565#else
566 return S_OK;
567#endif
568}
569
570HRESULT Session::onStorageControllerChange()
571{
572 LogFlowThisFunc(("\n"));
573
574 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
575 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
576 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
577#ifndef VBOX_COM_INPROC_API_CLIENT
578 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
579
580 return mConsole->i_onStorageControllerChange();
581#else
582 return S_OK;
583#endif
584}
585
586HRESULT Session::onMediumChange(const ComPtr<IMediumAttachment> &aMediumAttachment,
587 BOOL aForce)
588{
589 LogFlowThisFunc(("\n"));
590
591 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
592 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
593 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
594#ifndef VBOX_COM_INPROC_API_CLIENT
595 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
596
597 return mConsole->i_onMediumChange(aMediumAttachment, aForce);
598#else
599 return S_OK;
600#endif
601}
602
603HRESULT Session::onCPUChange(ULONG aCpu, BOOL aAdd)
604{
605 LogFlowThisFunc(("\n"));
606
607 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
608 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
609 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
610#ifndef VBOX_COM_INPROC_API_CLIENT
611 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
612
613 return mConsole->i_onCPUChange(aCpu, aAdd);
614#else
615 return S_OK;
616#endif
617}
618
619HRESULT Session::onCPUExecutionCapChange(ULONG aExecutionCap)
620{
621 LogFlowThisFunc(("\n"));
622
623 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
624 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
625 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
626#ifndef VBOX_COM_INPROC_API_CLIENT
627 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
628
629 return mConsole->i_onCPUExecutionCapChange(aExecutionCap);
630#else
631 return S_OK;
632#endif
633}
634
635HRESULT Session::onVRDEServerChange(BOOL aRestart)
636{
637 LogFlowThisFunc(("\n"));
638
639 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
640 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
641 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
642#ifndef VBOX_COM_INPROC_API_CLIENT
643 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
644
645 return mConsole->i_onVRDEServerChange(aRestart);
646#else
647 return S_OK;
648#endif
649}
650
651HRESULT Session::onVideoCaptureChange()
652{
653 LogFlowThisFunc(("\n"));
654
655 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
656 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
657 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
658#ifndef VBOX_COM_INPROC_API_CLIENT
659 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
660
661 return mConsole->i_onVideoCaptureChange();
662#else
663 return S_OK;
664#endif
665}
666
667HRESULT Session::onUSBControllerChange()
668{
669 LogFlowThisFunc(("\n"));
670
671 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
672 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
673 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
674#ifndef VBOX_COM_INPROC_API_CLIENT
675 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
676
677 return mConsole->i_onUSBControllerChange();
678#else
679 return S_OK;
680#endif
681}
682
683HRESULT Session::onSharedFolderChange(BOOL aGlobal)
684{
685 LogFlowThisFunc(("\n"));
686
687 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
688 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
689 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
690#ifndef VBOX_COM_INPROC_API_CLIENT
691 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
692
693 return mConsole->i_onSharedFolderChange(aGlobal);
694#else
695 return S_OK;
696#endif
697}
698
699HRESULT Session::onClipboardModeChange(ClipboardMode_T aClipboardMode)
700{
701 LogFlowThisFunc(("\n"));
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->i_onClipboardModeChange(aClipboardMode);
710#else
711 return S_OK;
712#endif
713}
714
715HRESULT Session::onDnDModeChange(DnDMode_T aDndMode)
716{
717 LogFlowThisFunc(("\n"));
718
719 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
720 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
721#ifndef VBOX_COM_INPROC_API_CLIENT
722 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
723
724 return mConsole->i_onDnDModeChange(aDndMode);
725#else
726 return S_OK;
727#endif
728}
729
730HRESULT Session::onUSBDeviceAttach(const ComPtr<IUSBDevice> &aDevice,
731 const ComPtr<IVirtualBoxErrorInfo> &aError,
732 ULONG aMaskedInterfaces)
733{
734 LogFlowThisFunc(("\n"));
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_onUSBDeviceAttach(aDevice, aError, aMaskedInterfaces);
743#else
744 return S_OK;
745#endif
746}
747
748HRESULT Session::onUSBDeviceDetach(const com::Guid &aId,
749 const ComPtr<IVirtualBoxErrorInfo> &aError)
750{
751 LogFlowThisFunc(("\n"));
752
753 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
754 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
755 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
756#ifndef VBOX_COM_INPROC_API_CLIENT
757 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
758
759 return mConsole->i_onUSBDeviceDetach(aId.toUtf16().raw(), aError);
760#else
761 return S_OK;
762#endif
763}
764
765HRESULT Session::onShowWindow(BOOL aCheck, BOOL *aCanShow, LONG64 *aWinId)
766{
767 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
768
769 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
770#ifndef VBOX_COM_INPROC_API_CLIENT
771 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
772#endif
773
774 if (mState != SessionState_Locked)
775 {
776 /* the call from Machine issued when the session is open can arrive
777 * after the session starts closing or gets closed. Note that when
778 * aCheck is false, we return E_FAIL to indicate that aWinId we return
779 * is not valid */
780 *aCanShow = FALSE;
781 *aWinId = 0;
782 return aCheck ? S_OK : E_FAIL;
783 }
784
785#ifndef VBOX_COM_INPROC_API_CLIENT
786 return mConsole->i_onShowWindow(aCheck, aCanShow, aWinId);
787#else
788 return S_OK;
789#endif
790}
791
792HRESULT Session::onBandwidthGroupChange(const ComPtr<IBandwidthGroup> &aBandwidthGroup)
793{
794 LogFlowThisFunc(("\n"));
795
796 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
797 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
798 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
799#ifndef VBOX_COM_INPROC_API_CLIENT
800 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
801
802 return mConsole->i_onBandwidthGroupChange(aBandwidthGroup);
803#else
804 return S_OK;
805#endif
806}
807
808HRESULT Session::onStorageDeviceChange(const ComPtr<IMediumAttachment> &aMediumAttachment, BOOL aRemove, BOOL aSilent)
809{
810 LogFlowThisFunc(("\n"));
811
812 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
813 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
814 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
815#ifndef VBOX_COM_INPROC_API_CLIENT
816 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
817
818 return mConsole->i_onStorageDeviceChange(aMediumAttachment, aRemove, aSilent);
819#else
820 return S_OK;
821#endif
822}
823
824HRESULT Session::accessGuestProperty(const com::Utf8Str &aName, const com::Utf8Str &aValue, const com::Utf8Str &aFlags,
825 BOOL aIsSetter, com::Utf8Str &aRetValue, LONG64 *aRetTimestamp, com::Utf8Str &aRetFlags)
826{
827#ifdef VBOX_WITH_GUEST_PROPS
828# ifndef VBOX_COM_INPROC_API_CLIENT
829 if (mState != SessionState_Locked)
830 return setError(VBOX_E_INVALID_VM_STATE,
831 tr("Machine is not locked by session (session state: %s)."),
832 Global::stringifySessionState(mState));
833 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
834 if (aName.isEmpty())
835 return E_INVALIDARG;
836 if (!aIsSetter && !VALID_PTR(aRetTimestamp))
837 return E_POINTER;
838
839 /* If this session is not in a VM process fend off the call. The caller
840 * handles this correctly, by doing the operation in VBoxSVC. */
841 if (!mConsole)
842 return E_ACCESSDENIED;
843
844 if (!aIsSetter)
845 {
846 Bstr bstrRetValue;
847 Bstr bstrRetFlags;
848 HRESULT hr = mConsole->i_getGuestProperty(Bstr(aName).raw(),
849 bstrRetValue.asOutParam(), aRetTimestamp, bstrRetFlags.asOutParam());
850 if (SUCCEEDED(hr))
851 {
852 aRetValue = bstrRetValue;
853 aRetFlags = bstrRetFlags;
854 }
855 return hr;
856 }
857 else
858 return mConsole->i_setGuestProperty(Bstr(aName).raw(), Bstr(aValue).raw(), Bstr(aFlags).raw());
859
860# else /* VBOX_COM_INPROC_API_CLIENT */
861 /** @todo This is nonsense, non-VM API users shouldn't need to deal with this
862 * method call, VBoxSVC should be clever enough to see that the
863 * session doesn't have a console! */
864 return E_ACCESSDENIED;
865# endif /* VBOX_COM_INPROC_API_CLIENT */
866
867#else /* VBOX_WITH_GUEST_PROPS */
868 ReturnComNotImplemented();
869#endif /* VBOX_WITH_GUEST_PROPS */
870}
871
872HRESULT Session::enumerateGuestProperties(const com::Utf8Str &aPatterns,
873 std::vector<com::Utf8Str> &aKeys,
874 std::vector<com::Utf8Str> &aValues,
875 std::vector<LONG64> &aTimestamps,
876 std::vector<com::Utf8Str> &aFlags)
877{
878#if defined(VBOX_WITH_GUEST_PROPS) && !defined(VBOX_COM_INPROC_API_CLIENT)
879 if (mState != SessionState_Locked)
880 return setError(VBOX_E_INVALID_VM_STATE,
881 tr("Machine is not locked by session (session state: %s)."),
882 Global::stringifySessionState(mState));
883 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
884
885 /* If this session is not in a VM process fend off the call. The caller
886 * handles this correctly, by doing the operation in VBoxSVC. */
887 if (!mConsole)
888 return E_ACCESSDENIED;
889
890 com::SafeArray<BSTR> arrKeys;
891 com::SafeArray<BSTR> arrValues;
892 com::SafeArray<LONG64> arrTimestamps;
893 com::SafeArray<BSTR> arrFlags;
894
895 HRESULT hrc = mConsole->i_enumerateGuestProperties(Bstr(aPatterns).raw(),
896 ComSafeArrayAsOutParam(arrKeys),
897 ComSafeArrayAsOutParam(arrValues),
898 ComSafeArrayAsOutParam(arrTimestamps),
899 ComSafeArrayAsOutParam(arrFlags));
900
901 size_t i = 0;
902 aKeys.resize(arrKeys.size());
903 for(i = 0; i < arrKeys.size(); ++i)
904 aKeys[i] = arrKeys[i];
905 aValues.resize(arrValues.size());
906 for(i = 0; i < arrValues.size(); ++i)
907 aValues[i] = arrValues[i];
908 aTimestamps.resize(arrTimestamps.size());
909 for(i = 0; i < arrTimestamps.size(); ++i)
910 aTimestamps[i] = arrTimestamps[i];
911 aFlags.resize(arrFlags.size());
912 for(i = 0; i < arrFlags.size(); ++i)
913 aFlags[i] = arrFlags[i];
914
915 return hrc;
916
917#else /* VBOX_WITH_GUEST_PROPS not defined */
918 ReturnComNotImplemented();
919#endif /* VBOX_WITH_GUEST_PROPS not defined */
920}
921
922HRESULT Session::onlineMergeMedium(const ComPtr<IMediumAttachment> &aMediumAttachment, ULONG aSourceIdx,
923 ULONG aTargetIdx, const ComPtr<IProgress> &aProgress)
924{
925 if (mState != SessionState_Locked)
926 return setError(VBOX_E_INVALID_VM_STATE,
927 tr("Machine is not locked by session (session state: %s)."),
928 Global::stringifySessionState(mState));
929#ifndef VBOX_COM_INPROC_API_CLIENT
930 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
931 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
932
933 return mConsole->i_onlineMergeMedium(aMediumAttachment,
934 aSourceIdx, aTargetIdx,
935 aProgress);
936#else
937 AssertFailed();
938 return E_NOTIMPL;
939#endif
940}
941
942HRESULT Session::enableVMMStatistics(BOOL aEnable)
943{
944 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
945 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
946 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
947#ifndef VBOX_COM_INPROC_API_CLIENT
948 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
949
950 mConsole->i_enableVMMStatistics(aEnable);
951
952 return S_OK;
953#else
954 AssertFailed();
955 return E_NOTIMPL;
956#endif
957}
958
959HRESULT Session::pauseWithReason(Reason_T aReason)
960{
961 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
962 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
963 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
964#ifndef VBOX_COM_INPROC_API_CLIENT
965 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
966
967 return mConsole->i_pause(aReason);
968#else
969 AssertFailed();
970 return E_NOTIMPL;
971#endif
972}
973
974HRESULT Session::resumeWithReason(Reason_T aReason)
975{
976 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
977 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
978 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
979#ifndef VBOX_COM_INPROC_API_CLIENT
980 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
981
982 return mConsole->i_resume(aReason);
983#else
984 AssertFailed();
985 return E_NOTIMPL;
986#endif
987}
988
989HRESULT Session::saveStateWithReason(Reason_T aReason, ComPtr<IProgress> &aProgress)
990{
991 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
992 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
993 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
994#ifndef VBOX_COM_INPROC_API_CLIENT
995 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
996
997 return mConsole->i_saveState(aReason, aProgress.asOutParam());
998#else
999 AssertFailed();
1000 return E_NOTIMPL;
1001#endif
1002}
1003
1004// private methods
1005///////////////////////////////////////////////////////////////////////////////
1006
1007/**
1008 * Unlocks a machine associated with the current session.
1009 *
1010 * @param aFinalRelease called as a result of FinalRelease()
1011 * @param aFromServer called as a result of Uninitialize()
1012 *
1013 * @note To be called only from #uninit(), #UnlockMachine() or #Uninitialize().
1014 * @note Locks this object for writing.
1015 */
1016HRESULT Session::unlockMachine(bool aFinalRelease, bool aFromServer)
1017{
1018 LogFlowThisFuncEnter();
1019 LogFlowThisFunc(("aFinalRelease=%d, isFromServer=%d\n",
1020 aFinalRelease, aFromServer));
1021
1022 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1023
1024 LogFlowThisFunc(("mState=%s, mType=%d\n", Global::stringifySessionState(mState), mType));
1025
1026 if (mState != SessionState_Locked)
1027 {
1028 Assert(mState == SessionState_Spawning);
1029
1030 /* The session object is going to be uninitialized before it has been
1031 * assigned a direct console of the machine the client requested to open
1032 * a remote session to using IVirtualBox:: openRemoteSession(). It is OK
1033 * only if this close request comes from the server (for example, it
1034 * detected that the VM process it started terminated before opening a
1035 * direct session). Otherwise, it means that the client is too fast and
1036 * trying to close the session before waiting for the progress object it
1037 * got from IVirtualBox:: openRemoteSession() to complete, so assert. */
1038 Assert(aFromServer);
1039
1040 mState = SessionState_Unlocked;
1041 mType = SessionType_Null;
1042
1043 Assert(!mClientTokenHolder);
1044
1045 LogFlowThisFuncLeave();
1046 return S_OK;
1047 }
1048
1049 /* go to the closing state */
1050 mState = SessionState_Unlocking;
1051
1052 if (mType == SessionType_WriteLock)
1053 {
1054#ifndef VBOX_COM_INPROC_API_CLIENT
1055 if (!mConsole.isNull())
1056 {
1057 mConsole->uninit();
1058 mConsole.setNull();
1059 }
1060#else
1061 mRemoteMachine.setNull();
1062#endif
1063 }
1064 else
1065 {
1066 mRemoteMachine.setNull();
1067 mRemoteConsole.setNull();
1068 }
1069
1070 ComPtr<IProgress> progress;
1071
1072 if (!aFinalRelease && !aFromServer)
1073 {
1074 /*
1075 * We trigger OnSessionEnd() only when the session closes itself using
1076 * Close(). Note that if isFinalRelease = TRUE here, this means that
1077 * the client process has already initialized the termination procedure
1078 * without issuing Close() and the IPC channel is no more operational --
1079 * so we cannot call the server's method (it will definitely fail). The
1080 * server will instead simply detect the abnormal client death (since
1081 * OnSessionEnd() is not called) and reset the machine state to Aborted.
1082 */
1083
1084 /*
1085 * while waiting for OnSessionEnd() to complete one of our methods
1086 * can be called by the server (for example, Uninitialize(), if the
1087 * direct session has initiated a closure just a bit before us) so
1088 * we need to release the lock to avoid deadlocks. The state is already
1089 * SessionState_Closing here, so it's safe.
1090 */
1091 alock.release();
1092
1093 LogFlowThisFunc(("Calling mControl->OnSessionEnd()...\n"));
1094 HRESULT rc = mControl->OnSessionEnd(this, progress.asOutParam());
1095 LogFlowThisFunc(("mControl->OnSessionEnd()=%08X\n", rc));
1096
1097 alock.acquire();
1098
1099 /*
1100 * If we get E_UNEXPECTED this means that the direct session has already
1101 * been closed, we're just too late with our notification and nothing more
1102 *
1103 * bird: Seems E_ACCESSDENIED is what gets returned these days; see
1104 * VirtualBoxBase::addCaller.
1105 */
1106 if (mType != SessionType_WriteLock && (rc == E_UNEXPECTED || rc == E_ACCESSDENIED))
1107 rc = S_OK;
1108
1109#ifndef DEBUG_bird /* I don't want clients crashing on me just because VBoxSVC went belly up. */
1110 AssertComRC(rc);
1111#endif
1112 }
1113
1114 mControl.setNull();
1115
1116 if (mType == SessionType_WriteLock)
1117 {
1118 if (mClientTokenHolder)
1119 {
1120 delete mClientTokenHolder;
1121 mClientTokenHolder = NULL;
1122 }
1123
1124 if (!aFinalRelease && !aFromServer)
1125 {
1126 /*
1127 * Wait for the server to grab the semaphore and destroy the session
1128 * machine (allowing us to open a new session with the same machine
1129 * once this method returns)
1130 */
1131 Assert(!!progress);
1132 if (progress)
1133 progress->WaitForCompletion(-1);
1134 }
1135 }
1136
1137 mState = SessionState_Unlocked;
1138 mType = SessionType_Null;
1139
1140 /* release the VirtualBox instance as the very last step */
1141 mVirtualBox.setNull();
1142
1143 LogFlowThisFuncLeave();
1144 return S_OK;
1145}
1146
1147/* 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