VirtualBox

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

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

iprt/log.h,SUPDrv: Replaced the 'personal' logging groups with 6 more generic logging levels (7 thru 12) and a 'Warn' level. The 'Warn' level is enabled by 'group.e' together with level 1 logging. Modified the new RTLog[Rel][Get]DefaultInstanceEx functions to only take one 32-bit parameter to minimize call setup time and size. Major support driver version bump. LogAleksey=Log7, LogBird=Log8, LogSunlover=Log9, none of the other personal macros was used. Log*Warning got renamed to Log1*Warning so as to not confuse it with the LogWarn/LogRelWarn macros.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 35.9 KB
Line 
1/* $Id: SessionImpl.cpp 55988 2015-05-20 23:24:44Z vboxsync $ */
2/** @file
3 * VBox Client Session COM Class implementation in VBoxC.
4 */
5
6/*
7 * Copyright (C) 2006-2015 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 = i_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::getName(com::Utf8Str &aName)
155{
156 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
157
158 aName = mName;
159 return S_OK;
160}
161
162HRESULT Session::setName(const com::Utf8Str &aName)
163{
164 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
165
166 if (mState != SessionState_Unlocked)
167 return setError(VBOX_E_INVALID_OBJECT_STATE, tr("Trying to set name for a session which is not in state \"unlocked\""));
168
169 mName = aName;
170 return S_OK;
171}
172
173HRESULT Session::getMachine(ComPtr<IMachine> &aMachine)
174{
175 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
176
177 CHECK_OPEN();
178
179 HRESULT rc;
180#ifndef VBOX_COM_INPROC_API_CLIENT
181 if (mConsole)
182 rc = mConsole->i_machine().queryInterfaceTo(aMachine.asOutParam());
183 else
184#endif
185 rc = mRemoteMachine.queryInterfaceTo(aMachine.asOutParam());
186 if (FAILED(rc))
187 {
188#ifndef VBOX_COM_INPROC_API_CLIENT
189 if (mConsole)
190 setError(rc, tr("Failed to query the session machine"));
191 else
192#endif
193 if (FAILED_DEAD_INTERFACE(rc))
194 setError(rc, tr("Peer process crashed"));
195 else
196 setError(rc, tr("Failed to query the remote session machine"));
197 }
198
199 return rc;
200}
201
202HRESULT Session::getConsole(ComPtr<IConsole> &aConsole)
203{
204 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
205
206 CHECK_OPEN();
207
208 HRESULT rc = S_OK;
209#ifndef VBOX_COM_INPROC_API_CLIENT
210 if (mConsole)
211 rc = mConsole.queryInterfaceTo(aConsole.asOutParam());
212 else
213#endif
214 rc = mRemoteConsole.queryInterfaceTo(aConsole.asOutParam());
215
216 if (FAILED(rc))
217 {
218#ifndef VBOX_COM_INPROC_API_CLIENT
219 if (mConsole)
220 setError(rc, tr("Failed to query the console"));
221 else
222#endif
223 if (FAILED_DEAD_INTERFACE(rc))
224 setError(rc, tr("Peer process crashed"));
225 else
226 setError(rc, tr("Failed to query the remote console"));
227 }
228
229 return rc;
230}
231
232// ISession methods
233/////////////////////////////////////////////////////////////////////////////
234HRESULT Session::unlockMachine()
235{
236 LogFlowThisFunc(("mState=%d, mType=%d\n", mState, mType));
237
238 /* close() needs write lock */
239 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
240
241 CHECK_OPEN();
242
243 return i_unlockMachine(false /* aFinalRelease */, false /* aFromServer */);
244}
245
246// IInternalSessionControl methods
247/////////////////////////////////////////////////////////////////////////////
248HRESULT Session::getPID(ULONG *aPid)
249{
250 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
251
252 *aPid = (ULONG)RTProcSelf();
253 AssertCompile(sizeof(*aPid) == sizeof(RTPROCESS));
254
255 return S_OK;
256}
257
258HRESULT Session::getRemoteConsole(ComPtr<IConsole> &aConsole)
259{
260 LogFlowThisFuncEnter();
261
262 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
263
264#ifndef VBOX_COM_INPROC_API_CLIENT
265 AssertMsgReturn(mType == SessionType_WriteLock && !!mConsole,
266 ("This is not a direct session!\n"),
267 VBOX_E_INVALID_OBJECT_STATE);
268
269 /* return a failure if the session already transitioned to Closing
270 * but the server hasn't processed Machine::OnSessionEnd() yet. */
271 if (mState != SessionState_Locked)
272 return VBOX_E_INVALID_VM_STATE;
273
274 mConsole.queryInterfaceTo(aConsole.asOutParam());
275
276 LogFlowThisFuncLeave();
277
278 return S_OK;
279
280#else /* VBOX_COM_INPROC_API_CLIENT */
281 AssertFailed();
282 return VBOX_E_INVALID_OBJECT_STATE;
283#endif /* VBOX_COM_INPROC_API_CLIENT */
284}
285
286HRESULT Session::getNominalState(MachineState_T *aNominalState)
287{
288 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
289 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
290 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
291#ifndef VBOX_COM_INPROC_API_CLIENT
292 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
293
294 return mConsole->i_getNominalState(*aNominalState);
295#else
296 AssertFailed();
297 return E_NOTIMPL;
298#endif
299}
300
301#ifndef VBOX_WITH_GENERIC_SESSION_WATCHER
302HRESULT Session::assignMachine(const ComPtr<IMachine> &aMachine,
303 LockType_T aLockType,
304 const com::Utf8Str &aTokenId)
305#else
306HRESULT Session::assignMachine(const ComPtr<IMachine> &aMachine,
307 LockType_T aLockType,
308 const ComPtr<IToken> &aToken)
309#endif /* !VBOX_WITH_GENERIC_SESSION_WATCHER */
310{
311 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
312
313 AssertReturn(mState == SessionState_Unlocked, VBOX_E_INVALID_VM_STATE);
314
315 if (!aMachine)
316 {
317 /*
318 * A special case: the server informs us that this session has been
319 * passed to IMachine::launchVMProcess() so this session will become
320 * remote (but not existing) when AssignRemoteMachine() is called.
321 */
322
323 AssertReturn(mType == SessionType_Null, VBOX_E_INVALID_OBJECT_STATE);
324 mType = SessionType_Remote;
325 mState = SessionState_Spawning;
326
327 return S_OK;
328 }
329
330 /* query IInternalMachineControl interface */
331 mControl = aMachine;
332 AssertReturn(!!mControl, E_FAIL);
333
334 HRESULT rc = S_OK;
335#ifndef VBOX_COM_INPROC_API_CLIENT
336 if (aLockType == LockType_VM)
337 {
338 /* This is what is special about VM processes: they have a Console
339 * object which is the root of all VM related activity. */
340 rc = mConsole.createObject();
341 AssertComRCReturn(rc, rc);
342
343 rc = mConsole->init(aMachine, mControl, aLockType);
344 AssertComRCReturn(rc, rc);
345 }
346 else
347 mRemoteMachine = aMachine;
348#else
349 mRemoteMachine = aMachine;
350#endif
351
352#ifndef VBOX_WITH_GENERIC_SESSION_WATCHER
353 Utf8Str strTokenId(aTokenId);
354 Assert(!strTokenId.isEmpty());
355#else /* VBOX_WITH_GENERIC_SESSION_WATCHER */
356 Assert(!aToken.isNull());
357#endif /* VBOX_WITH_GENERIC_SESSION_WATCHER */
358 /* create the machine client token */
359 try
360 {
361#ifndef VBOX_WITH_GENERIC_SESSION_WATCHER
362 mClientTokenHolder = new ClientTokenHolder(strTokenId);
363#else /* VBOX_WITH_GENERIC_SESSION_WATCHER */
364 mClientTokenHolder = new ClientTokenHolder(aToken);
365#endif /* VBOX_WITH_GENERIC_SESSION_WATCHER */
366 if (!mClientTokenHolder->isReady())
367 {
368 delete mClientTokenHolder;
369 mClientTokenHolder = NULL;
370 rc = E_FAIL;
371 }
372 }
373 catch (std::bad_alloc &)
374 {
375 rc = E_OUTOFMEMORY;
376 }
377
378 /*
379 * Reference the VirtualBox object to ensure the server is up
380 * until the session is closed
381 */
382 if (SUCCEEDED(rc))
383 rc = aMachine->COMGETTER(Parent)(mVirtualBox.asOutParam());
384
385 if (SUCCEEDED(rc))
386 {
387 mType = SessionType_WriteLock;
388 mState = SessionState_Locked;
389 }
390 else
391 {
392 /* some cleanup */
393 mControl.setNull();
394#ifndef VBOX_COM_INPROC_API_CLIENT
395 if (!mConsole.isNull())
396 {
397 mConsole->uninit();
398 mConsole.setNull();
399 }
400#endif
401 }
402
403 return rc;
404}
405
406HRESULT Session::assignRemoteMachine(const ComPtr<IMachine> &aMachine,
407 const ComPtr<IConsole> &aConsole)
408
409{
410 AssertReturn(aMachine, E_INVALIDARG);
411
412 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
413
414 AssertReturn(mState == SessionState_Unlocked ||
415 mState == SessionState_Spawning, VBOX_E_INVALID_VM_STATE);
416
417 HRESULT rc = E_FAIL;
418
419 /* query IInternalMachineControl interface */
420 mControl = aMachine;
421 AssertReturn(!!mControl, E_FAIL);
422
423 /// @todo (dmik)
424 // currently, the remote session returns the same machine and
425 // console objects as the direct session, thus giving the
426 // (remote) client full control over the direct session. For the
427 // console, it is the desired behavior (the ability to control
428 // VM execution is a must for the remote session). What about
429 // the machine object, we may want to prevent the remote client
430 // from modifying machine data. In this case, we must:
431 // 1) assign the Machine object (instead of the SessionMachine
432 // object that is passed to this method) to mRemoteMachine;
433 // 2) remove GetMachine() property from the IConsole interface
434 // because it always returns the SessionMachine object
435 // (alternatively, we can supply a separate IConsole
436 // implementation that will return the Machine object in
437 // response to GetMachine()).
438
439 mRemoteMachine = aMachine;
440 mRemoteConsole = aConsole;
441
442 /*
443 * Reference the VirtualBox object to ensure the server is up
444 * until the session is closed
445 */
446 rc = aMachine->COMGETTER(Parent)(mVirtualBox.asOutParam());
447
448 if (SUCCEEDED(rc))
449 {
450 /*
451 * RemoteSession type can be already set by AssignMachine() when its
452 * argument is NULL (a special case)
453 */
454 if (mType != SessionType_Remote)
455 mType = SessionType_Shared;
456 else
457 Assert(mState == SessionState_Spawning);
458
459 mState = SessionState_Locked;
460 }
461 else
462 {
463 /* some cleanup */
464 mControl.setNull();
465 mRemoteMachine.setNull();
466 mRemoteConsole.setNull();
467 }
468
469 LogFlowThisFunc(("rc=%08X\n", rc));
470 LogFlowThisFuncLeave();
471
472 return rc;
473}
474
475HRESULT Session::updateMachineState(MachineState_T aMachineState)
476{
477
478 if (getObjectState().getState() != ObjectState::Ready)
479 {
480 /*
481 * We might have already entered Session::uninit() at this point, so
482 * return silently (not interested in the state change during uninit)
483 */
484 LogFlowThisFunc(("Already uninitialized.\n"));
485 return S_OK;
486 }
487
488 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
489
490 if (mState == SessionState_Unlocking)
491 {
492 LogFlowThisFunc(("Already being unlocked.\n"));
493 return S_OK;
494 }
495
496 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
497 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
498
499 AssertReturn(!mControl.isNull(), E_FAIL);
500#ifndef VBOX_COM_INPROC_API_CLIENT
501 AssertReturn(!mConsole.isNull(), E_FAIL);
502
503 return mConsole->i_updateMachineState(aMachineState);
504#else
505 return S_OK;
506#endif
507}
508
509HRESULT Session::uninitialize()
510{
511 LogFlowThisFuncEnter();
512
513 AutoCaller autoCaller(this);
514
515 HRESULT rc = S_OK;
516
517 if (getObjectState().getState() == ObjectState::Ready)
518 {
519 /* close() needs write lock */
520 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
521
522 LogFlowThisFunc(("mState=%s, mType=%d\n", Global::stringifySessionState(mState), mType));
523
524 if (mState == SessionState_Unlocking)
525 {
526 LogFlowThisFunc(("Already being unlocked.\n"));
527 return S_OK;
528 }
529
530 AssertMsgReturn( mState == SessionState_Locked
531 || mState == SessionState_Spawning,
532 ("Session is in wrong state (%ld), expected locked (%ld) or spawning (%ld)\n",
533 mState, SessionState_Locked, SessionState_Spawning),
534 VBOX_E_INVALID_VM_STATE);
535
536 /* close ourselves */
537 rc = i_unlockMachine(false /* aFinalRelease */, true /* aFromServer */);
538 }
539 else if (getObjectState().getState() == ObjectState::InUninit)
540 {
541 /*
542 * We might have already entered Session::uninit() at this point,
543 * return silently
544 */
545 LogFlowThisFunc(("Already uninitialized.\n"));
546 }
547 else
548 {
549 Log1WarningThisFunc(("UNEXPECTED uninitialization!\n"));
550 rc = autoCaller.rc();
551 }
552
553 LogFlowThisFunc(("rc=%08X\n", rc));
554 LogFlowThisFuncLeave();
555
556 return rc;
557}
558
559HRESULT Session::onNetworkAdapterChange(const ComPtr<INetworkAdapter> &aNetworkAdapter,
560 BOOL aChangeAdapter)
561
562{
563 LogFlowThisFunc(("\n"));
564
565 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
566 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
567 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
568#ifndef VBOX_COM_INPROC_API_CLIENT
569 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
570
571 return mConsole->i_onNetworkAdapterChange(aNetworkAdapter, aChangeAdapter);
572#else
573 return S_OK;
574#endif
575}
576
577HRESULT Session::onSerialPortChange(const ComPtr<ISerialPort> &aSerialPort)
578{
579 LogFlowThisFunc(("\n"));
580
581 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
582 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
583 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
584#ifndef VBOX_COM_INPROC_API_CLIENT
585 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
586
587 return mConsole->i_onSerialPortChange(aSerialPort);
588#else
589 return S_OK;
590#endif
591}
592
593HRESULT Session::onParallelPortChange(const ComPtr<IParallelPort> &aParallelPort)
594{
595 LogFlowThisFunc(("\n"));
596
597 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
598 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
599 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
600#ifndef VBOX_COM_INPROC_API_CLIENT
601 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
602
603 return mConsole->i_onParallelPortChange(aParallelPort);
604#else
605 return S_OK;
606#endif
607}
608
609HRESULT Session::onStorageControllerChange()
610{
611 LogFlowThisFunc(("\n"));
612
613 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
614 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
615 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
616#ifndef VBOX_COM_INPROC_API_CLIENT
617 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
618
619 return mConsole->i_onStorageControllerChange();
620#else
621 return S_OK;
622#endif
623}
624
625HRESULT Session::onMediumChange(const ComPtr<IMediumAttachment> &aMediumAttachment,
626 BOOL aForce)
627{
628 LogFlowThisFunc(("\n"));
629
630 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
631 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
632 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
633#ifndef VBOX_COM_INPROC_API_CLIENT
634 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
635
636 return mConsole->i_onMediumChange(aMediumAttachment, aForce);
637#else
638 return S_OK;
639#endif
640}
641
642HRESULT Session::onCPUChange(ULONG aCpu, BOOL aAdd)
643{
644 LogFlowThisFunc(("\n"));
645
646 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
647 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
648 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
649#ifndef VBOX_COM_INPROC_API_CLIENT
650 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
651
652 return mConsole->i_onCPUChange(aCpu, aAdd);
653#else
654 return S_OK;
655#endif
656}
657
658HRESULT Session::onCPUExecutionCapChange(ULONG aExecutionCap)
659{
660 LogFlowThisFunc(("\n"));
661
662 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
663 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
664 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
665#ifndef VBOX_COM_INPROC_API_CLIENT
666 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
667
668 return mConsole->i_onCPUExecutionCapChange(aExecutionCap);
669#else
670 return S_OK;
671#endif
672}
673
674HRESULT Session::onVRDEServerChange(BOOL aRestart)
675{
676 LogFlowThisFunc(("\n"));
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#ifndef VBOX_COM_INPROC_API_CLIENT
682 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
683
684 return mConsole->i_onVRDEServerChange(aRestart);
685#else
686 return S_OK;
687#endif
688}
689
690HRESULT Session::onVideoCaptureChange()
691{
692 LogFlowThisFunc(("\n"));
693
694 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
695 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
696 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
697#ifndef VBOX_COM_INPROC_API_CLIENT
698 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
699
700 return mConsole->i_onVideoCaptureChange();
701#else
702 return S_OK;
703#endif
704}
705
706HRESULT Session::onUSBControllerChange()
707{
708 LogFlowThisFunc(("\n"));
709
710 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
711 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
712 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
713#ifndef VBOX_COM_INPROC_API_CLIENT
714 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
715
716 return mConsole->i_onUSBControllerChange();
717#else
718 return S_OK;
719#endif
720}
721
722HRESULT Session::onSharedFolderChange(BOOL aGlobal)
723{
724 LogFlowThisFunc(("\n"));
725
726 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
727 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
728 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
729#ifndef VBOX_COM_INPROC_API_CLIENT
730 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
731
732 return mConsole->i_onSharedFolderChange(aGlobal);
733#else
734 return S_OK;
735#endif
736}
737
738HRESULT Session::onClipboardModeChange(ClipboardMode_T aClipboardMode)
739{
740 LogFlowThisFunc(("\n"));
741
742 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
743 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
744 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
745#ifndef VBOX_COM_INPROC_API_CLIENT
746 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
747
748 return mConsole->i_onClipboardModeChange(aClipboardMode);
749#else
750 return S_OK;
751#endif
752}
753
754HRESULT Session::onDnDModeChange(DnDMode_T aDndMode)
755{
756 LogFlowThisFunc(("\n"));
757
758 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
759 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
760#ifndef VBOX_COM_INPROC_API_CLIENT
761 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
762 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
763
764 return mConsole->i_onDnDModeChange(aDndMode);
765#else
766 return S_OK;
767#endif
768}
769
770HRESULT Session::onUSBDeviceAttach(const ComPtr<IUSBDevice> &aDevice,
771 const ComPtr<IVirtualBoxErrorInfo> &aError,
772 ULONG aMaskedInterfaces,
773 const com::Utf8Str &aCaptureFilename)
774{
775 LogFlowThisFunc(("\n"));
776
777 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
778 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
779 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
780#ifndef VBOX_COM_INPROC_API_CLIENT
781 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
782
783 return mConsole->i_onUSBDeviceAttach(aDevice, aError, aMaskedInterfaces, aCaptureFilename);
784#else
785 return S_OK;
786#endif
787}
788
789HRESULT Session::onUSBDeviceDetach(const com::Guid &aId,
790 const ComPtr<IVirtualBoxErrorInfo> &aError)
791{
792 LogFlowThisFunc(("\n"));
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#ifndef VBOX_COM_INPROC_API_CLIENT
798 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
799
800 return mConsole->i_onUSBDeviceDetach(aId.toUtf16().raw(), aError);
801#else
802 return S_OK;
803#endif
804}
805
806HRESULT Session::onShowWindow(BOOL aCheck, BOOL *aCanShow, LONG64 *aWinId)
807{
808 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
809
810 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
811#ifndef VBOX_COM_INPROC_API_CLIENT
812 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
813#endif
814
815 if (mState != SessionState_Locked)
816 {
817 /* the call from Machine issued when the session is open can arrive
818 * after the session starts closing or gets closed. Note that when
819 * aCheck is false, we return E_FAIL to indicate that aWinId we return
820 * is not valid */
821 *aCanShow = FALSE;
822 *aWinId = 0;
823 return aCheck ? S_OK : E_FAIL;
824 }
825
826#ifndef VBOX_COM_INPROC_API_CLIENT
827 return mConsole->i_onShowWindow(aCheck, aCanShow, aWinId);
828#else
829 return S_OK;
830#endif
831}
832
833HRESULT Session::onBandwidthGroupChange(const ComPtr<IBandwidthGroup> &aBandwidthGroup)
834{
835 LogFlowThisFunc(("\n"));
836
837 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
838 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
839 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
840#ifndef VBOX_COM_INPROC_API_CLIENT
841 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
842
843 return mConsole->i_onBandwidthGroupChange(aBandwidthGroup);
844#else
845 return S_OK;
846#endif
847}
848
849HRESULT Session::onStorageDeviceChange(const ComPtr<IMediumAttachment> &aMediumAttachment, BOOL aRemove, BOOL aSilent)
850{
851 LogFlowThisFunc(("\n"));
852
853 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
854 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
855 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
856#ifndef VBOX_COM_INPROC_API_CLIENT
857 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
858
859 return mConsole->i_onStorageDeviceChange(aMediumAttachment, aRemove, aSilent);
860#else
861 return S_OK;
862#endif
863}
864
865HRESULT Session::accessGuestProperty(const com::Utf8Str &aName, const com::Utf8Str &aValue, const com::Utf8Str &aFlags,
866 ULONG aAccessMode, com::Utf8Str &aRetValue, LONG64 *aRetTimestamp, com::Utf8Str &aRetFlags)
867{
868#ifdef VBOX_WITH_GUEST_PROPS
869# ifndef VBOX_COM_INPROC_API_CLIENT
870 if (mState != SessionState_Locked)
871 return setError(VBOX_E_INVALID_VM_STATE,
872 tr("Machine is not locked by session (session state: %s)."),
873 Global::stringifySessionState(mState));
874 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
875 if (aName.isEmpty())
876 return E_INVALIDARG;
877 if (aAccessMode == 0 && !RT_VALID_PTR(aRetTimestamp))
878 return E_POINTER;
879
880 /* If this session is not in a VM process fend off the call. The caller
881 * handles this correctly, by doing the operation in VBoxSVC. */
882 if (!mConsole)
883 return E_ACCESSDENIED;
884
885 HRESULT hr;
886 if (aAccessMode == 2)
887 hr = mConsole->i_deleteGuestProperty(aName);
888 else if (aAccessMode == 1)
889 hr = mConsole->i_setGuestProperty(aName, aValue, aFlags);
890 else if (aAccessMode == 0)
891 hr = mConsole->i_getGuestProperty(aName, &aRetValue, aRetTimestamp, &aRetFlags);
892 else
893 hr = E_INVALIDARG;
894
895 return hr;
896# else /* VBOX_COM_INPROC_API_CLIENT */
897 /** @todo This is nonsense, non-VM API users shouldn't need to deal with this
898 * method call, VBoxSVC should be clever enough to see that the
899 * session doesn't have a console! */
900 return E_ACCESSDENIED;
901# endif /* VBOX_COM_INPROC_API_CLIENT */
902
903#else /* VBOX_WITH_GUEST_PROPS */
904 ReturnComNotImplemented();
905#endif /* VBOX_WITH_GUEST_PROPS */
906}
907
908HRESULT Session::enumerateGuestProperties(const com::Utf8Str &aPatterns,
909 std::vector<com::Utf8Str> &aKeys,
910 std::vector<com::Utf8Str> &aValues,
911 std::vector<LONG64> &aTimestamps,
912 std::vector<com::Utf8Str> &aFlags)
913{
914#if defined(VBOX_WITH_GUEST_PROPS) && !defined(VBOX_COM_INPROC_API_CLIENT)
915 if (mState != SessionState_Locked)
916 return setError(VBOX_E_INVALID_VM_STATE,
917 tr("Machine is not locked by session (session state: %s)."),
918 Global::stringifySessionState(mState));
919 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
920
921 /* If this session is not in a VM process fend off the call. The caller
922 * handles this correctly, by doing the operation in VBoxSVC. */
923 if (!mConsole)
924 return E_ACCESSDENIED;
925
926 return mConsole->i_enumerateGuestProperties(aPatterns, aKeys, aValues, aTimestamps, aFlags);
927
928#else /* VBOX_WITH_GUEST_PROPS not defined */
929 ReturnComNotImplemented();
930#endif /* VBOX_WITH_GUEST_PROPS not defined */
931}
932
933HRESULT Session::onlineMergeMedium(const ComPtr<IMediumAttachment> &aMediumAttachment, ULONG aSourceIdx,
934 ULONG aTargetIdx, const ComPtr<IProgress> &aProgress)
935{
936 if (mState != SessionState_Locked)
937 return setError(VBOX_E_INVALID_VM_STATE,
938 tr("Machine is not locked by session (session state: %s)."),
939 Global::stringifySessionState(mState));
940#ifndef VBOX_COM_INPROC_API_CLIENT
941 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
942 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
943
944 return mConsole->i_onlineMergeMedium(aMediumAttachment,
945 aSourceIdx, aTargetIdx,
946 aProgress);
947#else
948 AssertFailed();
949 return E_NOTIMPL;
950#endif
951}
952
953HRESULT Session::reconfigureMediumAttachments(const std::vector<ComPtr<IMediumAttachment> > &aAttachments)
954{
955 if (mState != SessionState_Locked)
956 return setError(VBOX_E_INVALID_VM_STATE,
957 tr("Machine is not locked by session (session state: %s)."),
958 Global::stringifySessionState(mState));
959#ifndef VBOX_COM_INPROC_API_CLIENT
960 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
961 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
962
963 return mConsole->i_reconfigureMediumAttachments(aAttachments);
964#else
965 AssertFailed();
966 return E_NOTIMPL;
967#endif
968}
969
970HRESULT Session::enableVMMStatistics(BOOL aEnable)
971{
972 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
973 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
974 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
975#ifndef VBOX_COM_INPROC_API_CLIENT
976 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
977
978 mConsole->i_enableVMMStatistics(aEnable);
979
980 return S_OK;
981#else
982 AssertFailed();
983 return E_NOTIMPL;
984#endif
985}
986
987HRESULT Session::pauseWithReason(Reason_T aReason)
988{
989 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
990 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
991 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
992#ifndef VBOX_COM_INPROC_API_CLIENT
993 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
994
995 return mConsole->i_pause(aReason);
996#else
997 AssertFailed();
998 return E_NOTIMPL;
999#endif
1000}
1001
1002HRESULT Session::resumeWithReason(Reason_T aReason)
1003{
1004 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1005 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
1006 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
1007#ifndef VBOX_COM_INPROC_API_CLIENT
1008 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
1009
1010 AutoWriteLock dummyLock(mConsole COMMA_LOCKVAL_SRC_POS);
1011 return mConsole->i_resume(aReason, dummyLock);
1012#else
1013 AssertFailed();
1014 return E_NOTIMPL;
1015#endif
1016}
1017
1018HRESULT Session::saveStateWithReason(Reason_T aReason, const ComPtr<IProgress> &aProgress, const Utf8Str &aStateFilePath, BOOL aPauseVM, BOOL *aLeftPaused)
1019{
1020 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1021 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
1022 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
1023#ifndef VBOX_COM_INPROC_API_CLIENT
1024 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
1025
1026 bool fLeftPaused = false;
1027 HRESULT rc = mConsole->i_saveState(aReason, aProgress, aStateFilePath, !!aPauseVM, fLeftPaused);
1028 if (aLeftPaused)
1029 *aLeftPaused = fLeftPaused;
1030 return rc;
1031#else
1032 AssertFailed();
1033 return E_NOTIMPL;
1034#endif
1035}
1036
1037HRESULT Session::cancelSaveStateWithReason()
1038{
1039 AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
1040 AssertReturn(mState == SessionState_Locked, VBOX_E_INVALID_VM_STATE);
1041 AssertReturn(mType == SessionType_WriteLock, VBOX_E_INVALID_OBJECT_STATE);
1042#ifndef VBOX_COM_INPROC_API_CLIENT
1043 AssertReturn(mConsole, VBOX_E_INVALID_OBJECT_STATE);
1044
1045 return mConsole->i_cancelSaveState();
1046#else
1047 AssertFailed();
1048 return E_NOTIMPL;
1049#endif
1050}
1051
1052// private methods
1053///////////////////////////////////////////////////////////////////////////////
1054
1055/**
1056 * Unlocks a machine associated with the current session.
1057 *
1058 * @param aFinalRelease called as a result of FinalRelease()
1059 * @param aFromServer called as a result of Uninitialize()
1060 *
1061 * @note To be called only from #uninit(), #UnlockMachine() or #Uninitialize().
1062 * @note Locks this object for writing.
1063 */
1064HRESULT Session::i_unlockMachine(bool aFinalRelease, bool aFromServer)
1065{
1066 LogFlowThisFuncEnter();
1067 LogFlowThisFunc(("aFinalRelease=%d, isFromServer=%d\n",
1068 aFinalRelease, aFromServer));
1069
1070 AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);
1071
1072 LogFlowThisFunc(("mState=%s, mType=%d\n", Global::stringifySessionState(mState), mType));
1073
1074 if (mState != SessionState_Locked)
1075 {
1076 Assert(mState == SessionState_Spawning);
1077
1078 /* The session object is going to be uninitialized before it has been
1079 * assigned a direct console of the machine the client requested to open
1080 * a remote session to using IVirtualBox:: openRemoteSession(). It is OK
1081 * only if this close request comes from the server (for example, it
1082 * detected that the VM process it started terminated before opening a
1083 * direct session). Otherwise, it means that the client is too fast and
1084 * trying to close the session before waiting for the progress object it
1085 * got from IVirtualBox:: openRemoteSession() to complete, so assert. */
1086 Assert(aFromServer);
1087
1088 mState = SessionState_Unlocked;
1089 mType = SessionType_Null;
1090
1091 Assert(!mClientTokenHolder);
1092
1093 LogFlowThisFuncLeave();
1094 return S_OK;
1095 }
1096
1097 /* go to the closing state */
1098 mState = SessionState_Unlocking;
1099
1100 if (mType == SessionType_WriteLock)
1101 {
1102#ifndef VBOX_COM_INPROC_API_CLIENT
1103 if (!mConsole.isNull())
1104 {
1105 mConsole->uninit();
1106 mConsole.setNull();
1107 }
1108#else
1109 mRemoteMachine.setNull();
1110#endif
1111 }
1112 else
1113 {
1114 mRemoteMachine.setNull();
1115 mRemoteConsole.setNull();
1116 }
1117
1118 ComPtr<IProgress> progress;
1119
1120 if (!aFinalRelease && !aFromServer)
1121 {
1122 /*
1123 * We trigger OnSessionEnd() only when the session closes itself using
1124 * Close(). Note that if isFinalRelease = TRUE here, this means that
1125 * the client process has already initialized the termination procedure
1126 * without issuing Close() and the IPC channel is no more operational --
1127 * so we cannot call the server's method (it will definitely fail). The
1128 * server will instead simply detect the abnormal client death (since
1129 * OnSessionEnd() is not called) and reset the machine state to Aborted.
1130 */
1131
1132 /*
1133 * while waiting for OnSessionEnd() to complete one of our methods
1134 * can be called by the server (for example, Uninitialize(), if the
1135 * direct session has initiated a closure just a bit before us) so
1136 * we need to release the lock to avoid deadlocks. The state is already
1137 * SessionState_Closing here, so it's safe.
1138 */
1139 alock.release();
1140
1141 LogFlowThisFunc(("Calling mControl->OnSessionEnd()...\n"));
1142 HRESULT rc = mControl->OnSessionEnd(this, progress.asOutParam());
1143 LogFlowThisFunc(("mControl->OnSessionEnd()=%08X\n", rc));
1144
1145 alock.acquire();
1146
1147 /*
1148 * If we get E_UNEXPECTED this means that the direct session has already
1149 * been closed, we're just too late with our notification and nothing more
1150 *
1151 * bird: Seems E_ACCESSDENIED is what gets returned these days; see
1152 * VirtualBoxBase::addCaller.
1153 */
1154 if (mType != SessionType_WriteLock && (rc == E_UNEXPECTED || rc == E_ACCESSDENIED))
1155 rc = S_OK;
1156
1157#ifndef DEBUG_bird /* I don't want clients crashing on me just because VBoxSVC went belly up. */
1158 AssertComRC(rc);
1159#endif
1160 }
1161
1162 mControl.setNull();
1163
1164 if (mType == SessionType_WriteLock)
1165 {
1166 if (mClientTokenHolder)
1167 {
1168 delete mClientTokenHolder;
1169 mClientTokenHolder = NULL;
1170 }
1171
1172 if (!aFinalRelease && !aFromServer)
1173 {
1174 /*
1175 * Wait for the server to grab the semaphore and destroy the session
1176 * machine (allowing us to open a new session with the same machine
1177 * once this method returns)
1178 */
1179 Assert(!!progress);
1180 if (progress)
1181 progress->WaitForCompletion(-1);
1182 }
1183 }
1184
1185 mState = SessionState_Unlocked;
1186 mType = SessionType_Null;
1187
1188 /* release the VirtualBox instance as the very last step */
1189 mVirtualBox.setNull();
1190
1191 LogFlowThisFuncLeave();
1192 return S_OK;
1193}
1194
1195/* vi: set tabstop=4 shiftwidth=4 expandtab: */
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette