VirtualBox

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

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

USB: Integrate USB sniffer. Make it possible to specify a file to dump the traffic to when attaching a USB device with VBoxManage

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 33.5 KB
Line 
1/* $Id: SessionImpl.cpp 53062 2014-10-15 12:34:18Z 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 const com::Utf8Str &aCaptureFilename)
734{
735 LogFlowThisFunc(("\n"));
736
737 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
738 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
739 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
740#ifndef VBOX_COM_INPROC_API_CLIENT
741 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
742
743 return mConsole->i_onUSBDeviceAttach(aDevice, aError, aMaskedInterfaces, aCaptureFilename);
744#else
745 return S_OK;
746#endif
747}
748
749HRESULT Session::onUSBDeviceDetach(const com::Guid &aId,
750 const ComPtr<IVirtualBoxErrorInfo> &aError)
751{
752 LogFlowThisFunc(("\n"));
753
754 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
755 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
756 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
757#ifndef VBOX_COM_INPROC_API_CLIENT
758 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
759
760 return mConsole->i_onUSBDeviceDetach(aId.toUtf16().raw(), aError);
761#else
762 return S_OK;
763#endif
764}
765
766HRESULT Session::onShowWindow(BOOL aCheck, BOOL *aCanShow, LONG64 *aWinId)
767{
768 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
769
770 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
771#ifndef VBOX_COM_INPROC_API_CLIENT
772 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
773#endif
774
775 if (mState != SessionState_Locked)
776 {
777 /* the call from Machine issued when the session is open can arrive
778 * after the session starts closing or gets closed. Note that when
779 * aCheck is false, we return E_FAIL to indicate that aWinId we return
780 * is not valid */
781 *aCanShow = FALSE;
782 *aWinId = 0;
783 return aCheck ? S_OK : E_FAIL;
784 }
785
786#ifndef VBOX_COM_INPROC_API_CLIENT
787 return mConsole->i_onShowWindow(aCheck, aCanShow, aWinId);
788#else
789 return S_OK;
790#endif
791}
792
793HRESULT Session::onBandwidthGroupChange(const ComPtr<IBandwidthGroup> &aBandwidthGroup)
794{
795 LogFlowThisFunc(("\n"));
796
797 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
798 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
799 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
800#ifndef VBOX_COM_INPROC_API_CLIENT
801 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
802
803 return mConsole->i_onBandwidthGroupChange(aBandwidthGroup);
804#else
805 return S_OK;
806#endif
807}
808
809HRESULT Session::onStorageDeviceChange(const ComPtr<IMediumAttachment> &aMediumAttachment, BOOL aRemove, BOOL aSilent)
810{
811 LogFlowThisFunc(("\n"));
812
813 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
814 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
815 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
816#ifndef VBOX_COM_INPROC_API_CLIENT
817 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
818
819 return mConsole->i_onStorageDeviceChange(aMediumAttachment, aRemove, aSilent);
820#else
821 return S_OK;
822#endif
823}
824
825HRESULT Session::accessGuestProperty(const com::Utf8Str &aName, const com::Utf8Str &aValue, const com::Utf8Str &aFlags,
826 ULONG aAccessMode, com::Utf8Str &aRetValue, LONG64 *aRetTimestamp, com::Utf8Str &aRetFlags)
827{
828#ifdef VBOX_WITH_GUEST_PROPS
829# ifndef VBOX_COM_INPROC_API_CLIENT
830 if (mState != SessionState_Locked)
831 return setError(VBOX_E_INVALID_VM_STATE,
832 tr("Machine is not locked by session (session state: %s)."),
833 Global::stringifySessionState(mState));
834 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
835 if (aName.isEmpty())
836 return E_INVALIDARG;
837 if (aAccessMode == 0 && !RT_VALID_PTR(aRetTimestamp))
838 return E_POINTER;
839
840 /* If this session is not in a VM process fend off the call. The caller
841 * handles this correctly, by doing the operation in VBoxSVC. */
842 if (!mConsole)
843 return E_ACCESSDENIED;
844
845 HRESULT hr;
846 if (aAccessMode == 2)
847 hr = mConsole->i_deleteGuestProperty(aName);
848 else if (aAccessMode == 1)
849 hr = mConsole->i_setGuestProperty(aName, aValue, aFlags);
850 else if (aAccessMode == 0)
851 hr = mConsole->i_getGuestProperty(aName, &aRetValue, aRetTimestamp, &aRetFlags);
852 else
853 hr = E_INVALIDARG;
854
855 return hr;
856# else /* VBOX_COM_INPROC_API_CLIENT */
857 /** @todo This is nonsense, non-VM API users shouldn't need to deal with this
858 * method call, VBoxSVC should be clever enough to see that the
859 * session doesn't have a console! */
860 return E_ACCESSDENIED;
861# endif /* VBOX_COM_INPROC_API_CLIENT */
862
863#else /* VBOX_WITH_GUEST_PROPS */
864 ReturnComNotImplemented();
865#endif /* VBOX_WITH_GUEST_PROPS */
866}
867
868HRESULT Session::enumerateGuestProperties(const com::Utf8Str &aPatterns,
869 std::vector<com::Utf8Str> &aKeys,
870 std::vector<com::Utf8Str> &aValues,
871 std::vector<LONG64> &aTimestamps,
872 std::vector<com::Utf8Str> &aFlags)
873{
874#if defined(VBOX_WITH_GUEST_PROPS) && !defined(VBOX_COM_INPROC_API_CLIENT)
875 if (mState != SessionState_Locked)
876 return setError(VBOX_E_INVALID_VM_STATE,
877 tr("Machine is not locked by session (session state: %s)."),
878 Global::stringifySessionState(mState));
879 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
880
881 /* If this session is not in a VM process fend off the call. The caller
882 * handles this correctly, by doing the operation in VBoxSVC. */
883 if (!mConsole)
884 return E_ACCESSDENIED;
885
886 return mConsole->i_enumerateGuestProperties(aPatterns, aKeys, aValues, aTimestamps, aFlags);
887
888#else /* VBOX_WITH_GUEST_PROPS not defined */
889 ReturnComNotImplemented();
890#endif /* VBOX_WITH_GUEST_PROPS not defined */
891}
892
893HRESULT Session::onlineMergeMedium(const ComPtr<IMediumAttachment> &aMediumAttachment, ULONG aSourceIdx,
894 ULONG aTargetIdx, const ComPtr<IProgress> &aProgress)
895{
896 if (mState != SessionState_Locked)
897 return setError(VBOX_E_INVALID_VM_STATE,
898 tr("Machine is not locked by session (session state: %s)."),
899 Global::stringifySessionState(mState));
900#ifndef VBOX_COM_INPROC_API_CLIENT
901 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
902 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
903
904 return mConsole->i_onlineMergeMedium(aMediumAttachment,
905 aSourceIdx, aTargetIdx,
906 aProgress);
907#else
908 AssertFailed();
909 return E_NOTIMPL;
910#endif
911}
912
913HRESULT Session::enableVMMStatistics(BOOL aEnable)
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#ifndef VBOX_COM_INPROC_API_CLIENT
919 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
920
921 mConsole->i_enableVMMStatistics(aEnable);
922
923 return S_OK;
924#else
925 AssertFailed();
926 return E_NOTIMPL;
927#endif
928}
929
930HRESULT Session::pauseWithReason(Reason_T aReason)
931{
932 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
933 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
934 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
935#ifndef VBOX_COM_INPROC_API_CLIENT
936 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
937
938 return mConsole->i_pause(aReason);
939#else
940 AssertFailed();
941 return E_NOTIMPL;
942#endif
943}
944
945HRESULT Session::resumeWithReason(Reason_T aReason)
946{
947 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
948 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
949 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
950#ifndef VBOX_COM_INPROC_API_CLIENT
951 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
952
953 return mConsole->i_resume(aReason);
954#else
955 AssertFailed();
956 return E_NOTIMPL;
957#endif
958}
959
960HRESULT Session::saveStateWithReason(Reason_T aReason, ComPtr<IProgress> &aProgress)
961{
962 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
963 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
964 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
965#ifndef VBOX_COM_INPROC_API_CLIENT
966 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
967
968 return mConsole->i_saveState(aReason, aProgress.asOutParam());
969#else
970 AssertFailed();
971 return E_NOTIMPL;
972#endif
973}
974
975// private methods
976///////////////////////////////////////////////////////////////////////////////
977
978/**
979 * Unlocks a machine associated with the current session.
980 *
981 * @param aFinalRelease called as a result of FinalRelease()
982 * @param aFromServer called as a result of Uninitialize()
983 *
984 * @note To be called only from #uninit(), #UnlockMachine() or #Uninitialize().
985 * @note Locks this object for writing.
986 */
987HRESULT Session::unlockMachine(bool aFinalRelease, bool aFromServer)
988{
989 LogFlowThisFuncEnter();
990 LogFlowThisFunc(("aFinalRelease=%d, isFromServer=%d\n",
991 aFinalRelease, aFromServer));
992
993 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
994
995 LogFlowThisFunc(("mState=%s, mType=%d\n", Global::stringifySessionState(mState), mType));
996
997 if (mState != SessionState_Locked)
998 {
999 Assert(mState == SessionState_Spawning);
1000
1001 /* The session object is going to be uninitialized before it has been
1002 * assigned a direct console of the machine the client requested to open
1003 * a remote session to using IVirtualBox:: openRemoteSession(). It is OK
1004 * only if this close request comes from the server (for example, it
1005 * detected that the VM process it started terminated before opening a
1006 * direct session). Otherwise, it means that the client is too fast and
1007 * trying to close the session before waiting for the progress object it
1008 * got from IVirtualBox:: openRemoteSession() to complete, so assert. */
1009 Assert(aFromServer);
1010
1011 mState = SessionState_Unlocked;
1012 mType = SessionType_Null;
1013
1014 Assert(!mClientTokenHolder);
1015
1016 LogFlowThisFuncLeave();
1017 return S_OK;
1018 }
1019
1020 /* go to the closing state */
1021 mState = SessionState_Unlocking;
1022
1023 if (mType == SessionType_WriteLock)
1024 {
1025#ifndef VBOX_COM_INPROC_API_CLIENT
1026 if (!mConsole.isNull())
1027 {
1028 mConsole->uninit();
1029 mConsole.setNull();
1030 }
1031#else
1032 mRemoteMachine.setNull();
1033#endif
1034 }
1035 else
1036 {
1037 mRemoteMachine.setNull();
1038 mRemoteConsole.setNull();
1039 }
1040
1041 ComPtr<IProgress> progress;
1042
1043 if (!aFinalRelease && !aFromServer)
1044 {
1045 /*
1046 * We trigger OnSessionEnd() only when the session closes itself using
1047 * Close(). Note that if isFinalRelease = TRUE here, this means that
1048 * the client process has already initialized the termination procedure
1049 * without issuing Close() and the IPC channel is no more operational --
1050 * so we cannot call the server's method (it will definitely fail). The
1051 * server will instead simply detect the abnormal client death (since
1052 * OnSessionEnd() is not called) and reset the machine state to Aborted.
1053 */
1054
1055 /*
1056 * while waiting for OnSessionEnd() to complete one of our methods
1057 * can be called by the server (for example, Uninitialize(), if the
1058 * direct session has initiated a closure just a bit before us) so
1059 * we need to release the lock to avoid deadlocks. The state is already
1060 * SessionState_Closing here, so it's safe.
1061 */
1062 alock.release();
1063
1064 LogFlowThisFunc(("Calling mControl->OnSessionEnd()...\n"));
1065 HRESULT rc = mControl->OnSessionEnd(this, progress.asOutParam());
1066 LogFlowThisFunc(("mControl->OnSessionEnd()=%08X\n", rc));
1067
1068 alock.acquire();
1069
1070 /*
1071 * If we get E_UNEXPECTED this means that the direct session has already
1072 * been closed, we're just too late with our notification and nothing more
1073 *
1074 * bird: Seems E_ACCESSDENIED is what gets returned these days; see
1075 * VirtualBoxBase::addCaller.
1076 */
1077 if (mType != SessionType_WriteLock && (rc == E_UNEXPECTED || rc == E_ACCESSDENIED))
1078 rc = S_OK;
1079
1080#ifndef DEBUG_bird /* I don't want clients crashing on me just because VBoxSVC went belly up. */
1081 AssertComRC(rc);
1082#endif
1083 }
1084
1085 mControl.setNull();
1086
1087 if (mType == SessionType_WriteLock)
1088 {
1089 if (mClientTokenHolder)
1090 {
1091 delete mClientTokenHolder;
1092 mClientTokenHolder = NULL;
1093 }
1094
1095 if (!aFinalRelease && !aFromServer)
1096 {
1097 /*
1098 * Wait for the server to grab the semaphore and destroy the session
1099 * machine (allowing us to open a new session with the same machine
1100 * once this method returns)
1101 */
1102 Assert(!!progress);
1103 if (progress)
1104 progress->WaitForCompletion(-1);
1105 }
1106 }
1107
1108 mState = SessionState_Unlocked;
1109 mType = SessionType_Null;
1110
1111 /* release the VirtualBox instance as the very last step */
1112 mVirtualBox.setNull();
1113
1114 LogFlowThisFuncLeave();
1115 return S_OK;
1116}
1117
1118/* 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