VirtualBox

source: vbox/trunk/src/VBox/Main/SessionImpl.cpp@ 25275

Last change on this file since 25275 was 25149, checked in by vboxsync, 15 years ago

Main: cleanup: remove all CheckComRC* macros (no functional change)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 34.1 KB
RevLine 
[1]1/** @file
2 *
3 * VBox Client Session COM Class implementation
4 */
5
6/*
[8155]7 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
[1]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
[5999]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.
[8155]16 *
17 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
[1]20 */
21
[606]22#ifdef VBOX_WITH_SYS_V_IPC_SESSION_WATCHER
[1]23# include <errno.h>
24# include <sys/types.h>
25# include <sys/stat.h>
26# include <sys/ipc.h>
27# include <sys/sem.h>
28#endif
29
30#include "SessionImpl.h"
31#include "ConsoleImpl.h"
[23675]32#include "Global.h"
[1]33
34#include "Logging.h"
35
36#include <VBox/err.h>
37#include <iprt/process.h>
38
[3668]39#if defined(RT_OS_WINDOWS) || defined (RT_OS_OS2)
[1]40/** VM IPC mutex holder thread */
41static DECLCALLBACK(int) IPCMutexHolderThread (RTTHREAD Thread, void *pvUser);
42#endif
43
44/**
45 * Local macro to check whether the session is open and return an error if not.
46 * @note Don't forget to do |Auto[Reader]Lock alock (this);| before using this
47 * macro.
48 */
49#define CHECK_OPEN() \
50 do { \
[7207]51 if (mState != SessionState_Open) \
[1]52 return setError (E_UNEXPECTED, \
[23675]53 tr ("The session is not open (session state: %s)"), \
54 Global::stringifySessionState(mState)); \
[1]55 } while (0)
56
57// constructor / destructor
58/////////////////////////////////////////////////////////////////////////////
59
60HRESULT Session::FinalConstruct()
61{
[21878]62 LogFlowThisFunc(("\n"));
[1]63
64 return init();
65}
66
67void Session::FinalRelease()
68{
[21878]69 LogFlowThisFunc(("\n"));
[1]70
71 uninit (true /* aFinalRelease */);
72}
73
74// public initializer/uninitializer for internal purposes only
75/////////////////////////////////////////////////////////////////////////////
76
77/**
78 * Initializes the Session object.
79 */
80HRESULT Session::init()
81{
82 /* Enclose the state transition NotReady->InInit->Ready */
[21878]83 AutoInitSpan autoInitSpan(this);
84 AssertReturn(autoInitSpan.isOk(), E_FAIL);
[1]85
86 LogFlowThisFuncEnter();
87
[7207]88 mState = SessionState_Closed;
89 mType = SessionType_Null;
[1]90
[3668]91#if defined(RT_OS_WINDOWS)
[1]92 mIPCSem = NULL;
93 mIPCThreadSem = NULL;
[3668]94#elif defined(RT_OS_OS2)
[3480]95 mIPCThread = NIL_RTTHREAD;
96 mIPCThreadSem = NIL_RTSEMEVENT;
[606]97#elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER)
[1]98 mIPCSem = -1;
[3480]99#else
100# error "Port me!"
[1]101#endif
102
103 /* Confirm a successful initialization when it's the case */
104 autoInitSpan.setSucceeded();
105
106 LogFlowThisFuncLeave();
107
108 return S_OK;
109}
110
111/**
112 * Uninitializes the Session object.
113 *
114 * @note Locks this object for writing.
115 */
116void Session::uninit (bool aFinalRelease)
117{
118 LogFlowThisFuncEnter();
[21878]119 LogFlowThisFunc(("aFinalRelease=%d\n", aFinalRelease));
[1]120
121 /* Enclose the state transition Ready->InUninit->NotReady */
[21878]122 AutoUninitSpan autoUninitSpan(this);
[1]123 if (autoUninitSpan.uninitDone())
124 {
[21878]125 LogFlowThisFunc(("Already uninitialized.\n"));
[1]126 LogFlowThisFuncLeave();
127 return;
128 }
129
[8057]130 /* close() needs write lock */
[21878]131 AutoWriteLock alock(this);
[1]132
[7207]133 if (mState != SessionState_Closed)
[1]134 {
[7207]135 Assert (mState == SessionState_Open ||
136 mState == SessionState_Spawning);
[1]137
138 HRESULT rc = close (aFinalRelease, false /* aFromServer */);
139 AssertComRC (rc);
140 }
141
142 LogFlowThisFuncLeave();
143}
144
145// ISession properties
146/////////////////////////////////////////////////////////////////////////////
147
148STDMETHODIMP Session::COMGETTER(State) (SessionState_T *aState)
149{
[14972]150 CheckComArgOutPointerValid(aState);
[1]151
[21878]152 AutoCaller autoCaller(this);
[25149]153 if (FAILED(autoCaller.rc())) return autoCaller.rc();
[1]154
[21878]155 AutoReadLock alock(this);
[1]156
157 *aState = mState;
158
159 return S_OK;
160}
161
162STDMETHODIMP Session::COMGETTER(Type) (SessionType_T *aType)
163{
[14972]164 CheckComArgOutPointerValid(aType);
[1]165
[21878]166 AutoCaller autoCaller(this);
[25149]167 if (FAILED(autoCaller.rc())) return autoCaller.rc();
[1]168
[21878]169 AutoReadLock alock(this);
[1]170
171 CHECK_OPEN();
172
173 *aType = mType;
174 return S_OK;
175}
176
177STDMETHODIMP Session::COMGETTER(Machine) (IMachine **aMachine)
178{
[14972]179 CheckComArgOutPointerValid(aMachine);
[1]180
[21878]181 AutoCaller autoCaller(this);
[25149]182 if (FAILED(autoCaller.rc())) return autoCaller.rc();
[1]183
[21878]184 AutoReadLock alock(this);
[1]185
186 CHECK_OPEN();
187
188 HRESULT rc = E_FAIL;
189
190 if (mConsole)
[21878]191 rc = mConsole->machine().queryInterfaceTo(aMachine);
[1]192 else
[21878]193 rc = mRemoteMachine.queryInterfaceTo(aMachine);
[1]194 ComAssertComRC (rc);
195
196 return rc;
197}
198
199STDMETHODIMP Session::COMGETTER(Console) (IConsole **aConsole)
200{
[14972]201 CheckComArgOutPointerValid(aConsole);
[1]202
[21878]203 AutoCaller autoCaller(this);
[25149]204 if (FAILED(autoCaller.rc())) return autoCaller.rc();
[1]205
[21878]206 AutoReadLock alock(this);
[1]207
208 CHECK_OPEN();
209
210 HRESULT rc = E_FAIL;
211
212 if (mConsole)
[21878]213 rc = mConsole.queryInterfaceTo(aConsole);
[1]214 else
[21878]215 rc = mRemoteConsole.queryInterfaceTo(aConsole);
[1]216 ComAssertComRC (rc);
217
218 return rc;
219}
220
221// ISession methods
222/////////////////////////////////////////////////////////////////////////////
223
224STDMETHODIMP Session::Close()
225{
[21878]226 LogFlowThisFunc(("mState=%d, mType=%d\n", mState, mType));
[1]227
[21878]228 AutoCaller autoCaller(this);
[25149]229 if (FAILED(autoCaller.rc())) return autoCaller.rc();
[1]230
231 /* close() needs write lock */
[21878]232 AutoWriteLock alock(this);
[1]233
234 CHECK_OPEN();
235
236 return close (false /* aFinalRelease */, false /* aFromServer */);
237}
238
239// IInternalSessionControl methods
240/////////////////////////////////////////////////////////////////////////////
241
242STDMETHODIMP Session::GetPID (ULONG *aPid)
243{
[21878]244 AssertReturn(aPid, E_POINTER);
[1]245
[21878]246 AutoCaller autoCaller(this);
[1]247 AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
248
[21878]249 AutoReadLock alock(this);
[1]250
251 *aPid = (ULONG) RTProcSelf();
[630]252 AssertCompile (sizeof (*aPid) == sizeof (RTPROCESS));
[1]253
254 return S_OK;
255}
256
257STDMETHODIMP Session::GetRemoteConsole (IConsole **aConsole)
258{
[20274]259 LogFlowThisFuncEnter();
[21878]260 AssertReturn(aConsole, E_POINTER);
[1]261
[21878]262 AutoCaller autoCaller(this);
[1]263 AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
264
[21878]265 AutoReadLock alock(this);
[1]266
[21878]267 AssertReturn(mState != SessionState_Closed, VBOX_E_INVALID_VM_STATE);
[1]268
[7207]269 AssertMsgReturn (mType == SessionType_Direct && !!mConsole,
[15834]270 ("This is not a direct session!\n"), VBOX_E_INVALID_OBJECT_STATE);
[1]271
[12658]272 /* return a failure if the session already transitioned to Closing
273 * but the server hasn't processed Machine::OnSessionEnd() yet. */
274 if (mState != SessionState_Open)
[15834]275 return VBOX_E_INVALID_VM_STATE;
[12658]276
[21878]277 mConsole.queryInterfaceTo(aConsole);
[1]278
[20274]279 LogFlowThisFuncLeave();
280
[1]281 return S_OK;
282}
283
284STDMETHODIMP Session::AssignMachine (IMachine *aMachine)
285{
286 LogFlowThisFuncEnter();
[21878]287 LogFlowThisFunc(("aMachine=%p\n", aMachine));
[1]288
[21878]289 AutoCaller autoCaller(this);
[1]290 AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
291
[21878]292 AutoWriteLock alock(this);
[1]293
[21878]294 AssertReturn(mState == SessionState_Closed, VBOX_E_INVALID_VM_STATE);
[1]295
296 if (!aMachine)
297 {
298 /*
299 * A special case: the server informs us that this session has been
300 * passed to IVirtualBox::OpenRemoteSession() so this session will
301 * become remote (but not existing) when AssignRemoteMachine() is
302 * called.
303 */
304
[21878]305 AssertReturn(mType == SessionType_Null, VBOX_E_INVALID_OBJECT_STATE);
[7207]306 mType = SessionType_Remote;
307 mState = SessionState_Spawning;
[1]308
309 LogFlowThisFuncLeave();
310 return S_OK;
311 }
312
313 HRESULT rc = E_FAIL;
314
315 /* query IInternalMachineControl interface */
316 mControl = aMachine;
[21878]317 AssertReturn(!!mControl, E_FAIL);
[1]318
319 rc = mConsole.createObject();
320 AssertComRCReturn (rc, rc);
321
322 rc = mConsole->init (aMachine, mControl);
323 AssertComRCReturn (rc, rc);
324
325 rc = grabIPCSemaphore();
326
327 /*
328 * Reference the VirtualBox object to ensure the server is up
329 * until the session is closed
330 */
[21878]331 if (SUCCEEDED(rc))
[1]332 rc = aMachine->COMGETTER(Parent) (mVirtualBox.asOutParam());
333
[21878]334 if (SUCCEEDED(rc))
[25149]335 {
[7207]336 mType = SessionType_Direct;
337 mState = SessionState_Open;
[1]338 }
339 else
340 {
341 /* some cleanup */
342 mControl.setNull();
343 mConsole->uninit();
344 mConsole.setNull();
345 }
346
[21878]347 LogFlowThisFunc(("rc=%08X\n", rc));
[1]348 LogFlowThisFuncLeave();
349
350 return rc;
351}
352
353STDMETHODIMP Session::AssignRemoteMachine (IMachine *aMachine, IConsole *aConsole)
354{
355 LogFlowThisFuncEnter();
[21878]356 LogFlowThisFunc(("aMachine=%p, aConsole=%p\n", aMachine, aConsole));
[1]357
[21878]358 AssertReturn(aMachine && aConsole, E_INVALIDARG);
[1]359
[21878]360 AutoCaller autoCaller(this);
[1]361 AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
362
[21878]363 AutoWriteLock alock(this);
[1]364
[21878]365 AssertReturn(mState == SessionState_Closed ||
[15834]366 mState == SessionState_Spawning, VBOX_E_INVALID_VM_STATE);
[1]367
368 HRESULT rc = E_FAIL;
369
370 /* query IInternalMachineControl interface */
371 mControl = aMachine;
[21878]372 AssertReturn(!!mControl, E_FAIL); // This test appears to be redundant --JS
[1]373
374 /// @todo (dmik)
375 // currently, the remote session returns the same machine and
376 // console objects as the direct session, thus giving the
377 // (remote) client full control over the direct session. For the
378 // console, it is the desired behavior (the ability to control
379 // VM execution is a must for the remote session). What about
380 // the machine object, we may want to prevent the remote client
381 // from modifying machine data. In this case, we must:
382 // 1) assign the Machine object (instead of the SessionMachine
383 // object that is passed to this method) to mRemoteMachine;
384 // 2) remove GetMachine() property from the IConsole interface
385 // because it always returns the SessionMachine object
386 // (alternatively, we can supply a separate IConsole
387 // implementation that will return the Machine object in
388 // response to GetMachine()).
389
390 mRemoteMachine = aMachine;
391 mRemoteConsole = aConsole;
392
393 /*
394 * Reference the VirtualBox object to ensure the server is up
395 * until the session is closed
396 */
397 rc = aMachine->COMGETTER(Parent) (mVirtualBox.asOutParam());
398
[21878]399 if (SUCCEEDED(rc))
[1]400 {
401 /*
402 * RemoteSession type can be already set by AssignMachine() when its
403 * argument is NULL (a special case)
404 */
[7207]405 if (mType != SessionType_Remote)
406 mType = SessionType_Existing;
[1]407 else
[7207]408 Assert (mState == SessionState_Spawning);
[1]409
[7207]410 mState = SessionState_Open;
[1]411 }
412 else
413 {
414 /* some cleanup */
415 mControl.setNull();
416 mRemoteMachine.setNull();
417 mRemoteConsole.setNull();
418 }
419
[21878]420 LogFlowThisFunc(("rc=%08X\n", rc));
[1]421 LogFlowThisFuncLeave();
422
423 return rc;
424}
425
426STDMETHODIMP Session::UpdateMachineState (MachineState_T aMachineState)
427{
[21878]428 AutoCaller autoCaller(this);
[1]429
430 if (autoCaller.state() != Ready)
431 {
432 /*
433 * We might have already entered Session::uninit() at this point, so
434 * return silently (not interested in the state change during uninit)
435 */
[21878]436 LogFlowThisFunc(("Already uninitialized.\n"));
[1]437 return S_OK;
438 }
439
[21878]440 AutoReadLock alock(this);
[1]441
[7207]442 if (mState == SessionState_Closing)
[1]443 {
[21878]444 LogFlowThisFunc(("Already being closed.\n"));
[1]445 return S_OK;
446 }
447
[21878]448 AssertReturn(mState == SessionState_Open, VBOX_E_INVALID_VM_STATE);
449 AssertReturn(mType == SessionType_Direct, VBOX_E_INVALID_OBJECT_STATE);
[1]450
[21878]451 AssertReturn(!mControl.isNull(), E_FAIL);
452 AssertReturn(!mConsole.isNull(), E_FAIL);
[1]453
454 return mConsole->updateMachineState (aMachineState);
455}
456
457STDMETHODIMP Session::Uninitialize()
458{
459 LogFlowThisFuncEnter();
460
[21878]461 AutoCaller autoCaller(this);
[1]462
463 HRESULT rc = S_OK;
464
465 if (autoCaller.state() == Ready)
466 {
[8057]467 /* close() needs write lock */
[21878]468 AutoWriteLock alock(this);
[1]469
[23675]470 LogFlowThisFunc(("mState=%s, mType=%d\n", Global::stringifySessionState(mState), mType));
[1]471
[7207]472 if (mState == SessionState_Closing)
[1]473 {
[21878]474 LogFlowThisFunc(("Already being closed.\n"));
[1]475 return S_OK;
476 }
477
[21878]478 AssertReturn(mState == SessionState_Open ||
[15834]479 mState == SessionState_Spawning, VBOX_E_INVALID_VM_STATE);
[1]480
481 /* close ourselves */
482 rc = close (false /* aFinalRelease */, true /* aFromServer */);
483 }
484 else if (autoCaller.state() == InUninit)
485 {
486 /*
487 * We might have already entered Session::uninit() at this point,
488 * return silently
489 */
[21878]490 LogFlowThisFunc(("Already uninitialized.\n"));
[1]491 }
492 else
493 {
[21878]494 LogWarningThisFunc(("UNEXPECTED uninitialization!\n"));
[1]495 rc = autoCaller.rc();
496 }
497
[21878]498 LogFlowThisFunc(("rc=%08X\n", rc));
[1]499 LogFlowThisFuncLeave();
500
501 return rc;
502}
503
[23223]504STDMETHODIMP Session::OnNetworkAdapterChange(INetworkAdapter *networkAdapter, BOOL changeAdapter)
[1]505{
[21878]506 LogFlowThisFunc(("\n"));
[1]507
[21878]508 AutoCaller autoCaller(this);
[1]509 AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
510
[21878]511 AutoReadLock alock(this);
512 AssertReturn(mState == SessionState_Open, VBOX_E_INVALID_VM_STATE);
513 AssertReturn(mType == SessionType_Direct, VBOX_E_INVALID_OBJECT_STATE);
[1]514
[23223]515 return mConsole->onNetworkAdapterChange(networkAdapter, changeAdapter);
[1]516}
517
[23223]518STDMETHODIMP Session::OnSerialPortChange(ISerialPort *serialPort)
[1]519{
[21878]520 LogFlowThisFunc(("\n"));
[1]521
[21878]522 AutoCaller autoCaller(this);
[1]523 AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
524
[21878]525 AutoReadLock alock(this);
526 AssertReturn(mState == SessionState_Open, VBOX_E_INVALID_VM_STATE);
527 AssertReturn(mType == SessionType_Direct, VBOX_E_INVALID_OBJECT_STATE);
[1]528
[23223]529 return mConsole->onSerialPortChange(serialPort);
[1]530}
531
[23223]532STDMETHODIMP Session::OnParallelPortChange(IParallelPort *parallelPort)
[1]533{
[21878]534 LogFlowThisFunc(("\n"));
[1]535
[21878]536 AutoCaller autoCaller(this);
[1]537 AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
538
[21878]539 AutoReadLock alock(this);
540 AssertReturn(mState == SessionState_Open, VBOX_E_INVALID_VM_STATE);
541 AssertReturn(mType == SessionType_Direct, VBOX_E_INVALID_OBJECT_STATE);
[1]542
[23223]543 return mConsole->onParallelPortChange(parallelPort);
[1]544}
545
[23223]546STDMETHODIMP Session::OnStorageControllerChange()
[3494]547{
[21878]548 LogFlowThisFunc(("\n"));
[3494]549
[21878]550 AutoCaller autoCaller(this);
[3494]551 AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
552
[21878]553 AutoReadLock alock(this);
554 AssertReturn(mState == SessionState_Open, VBOX_E_INVALID_VM_STATE);
555 AssertReturn(mType == SessionType_Direct, VBOX_E_INVALID_OBJECT_STATE);
[3494]556
[23223]557 return mConsole->onStorageControllerChange();
[3494]558}
559
[24493]560STDMETHODIMP Session::OnMediumChange(IMediumAttachment *aMediumAttachment, BOOL aForce)
[3652]561{
[21878]562 LogFlowThisFunc(("\n"));
[3652]563
[21878]564 AutoCaller autoCaller(this);
[3652]565 AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
566
[21878]567 AutoReadLock alock(this);
568 AssertReturn(mState == SessionState_Open, VBOX_E_INVALID_VM_STATE);
569 AssertReturn(mType == SessionType_Direct, VBOX_E_INVALID_OBJECT_STATE);
[3652]570
[24493]571 return mConsole->onMediumChange(aMediumAttachment, aForce);
[3652]572}
573
[1]574STDMETHODIMP Session::OnVRDPServerChange()
575{
[21878]576 LogFlowThisFunc(("\n"));
[1]577
[21878]578 AutoCaller autoCaller(this);
[1]579 AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
580
[21878]581 AutoReadLock alock(this);
582 AssertReturn(mState == SessionState_Open, VBOX_E_INVALID_VM_STATE);
583 AssertReturn(mType == SessionType_Direct, VBOX_E_INVALID_OBJECT_STATE);
[1]584
585 return mConsole->onVRDPServerChange();
586}
587
588STDMETHODIMP Session::OnUSBControllerChange()
589{
[21878]590 LogFlowThisFunc(("\n"));
[1]591
[21878]592 AutoCaller autoCaller(this);
[1]593 AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
594
[21878]595 AutoReadLock alock(this);
596 AssertReturn(mState == SessionState_Open, VBOX_E_INVALID_VM_STATE);
597 AssertReturn(mType == SessionType_Direct, VBOX_E_INVALID_OBJECT_STATE);
[1]598
599 return mConsole->onUSBControllerChange();
600}
601
[4041]602STDMETHODIMP Session::OnSharedFolderChange (BOOL aGlobal)
603{
[21878]604 LogFlowThisFunc(("\n"));
[4041]605
[21878]606 AutoCaller autoCaller(this);
[4041]607 AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
608
[21878]609 AutoReadLock alock(this);
610 AssertReturn(mState == SessionState_Open, VBOX_E_INVALID_VM_STATE);
611 AssertReturn(mType == SessionType_Direct, VBOX_E_INVALID_OBJECT_STATE);
[4041]612
613 return mConsole->onSharedFolderChange (aGlobal);
614}
615
[3001]616STDMETHODIMP Session::OnUSBDeviceAttach (IUSBDevice *aDevice,
[5713]617 IVirtualBoxErrorInfo *aError,
618 ULONG aMaskedIfs)
[1]619{
[21878]620 LogFlowThisFunc(("\n"));
[1]621
[21878]622 AutoCaller autoCaller(this);
[1]623 AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
624
[21878]625 AutoReadLock alock(this);
626 AssertReturn(mState == SessionState_Open, VBOX_E_INVALID_VM_STATE);
627 AssertReturn(mType == SessionType_Direct, VBOX_E_INVALID_OBJECT_STATE);
[1]628
[5713]629 return mConsole->onUSBDeviceAttach (aDevice, aError, aMaskedIfs);
[1]630}
631
[19239]632STDMETHODIMP Session::OnUSBDeviceDetach (IN_BSTR aId,
[3001]633 IVirtualBoxErrorInfo *aError)
[1]634{
[21878]635 LogFlowThisFunc(("\n"));
[1]636
[21878]637 AutoCaller autoCaller(this);
[1]638 AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
639
[21878]640 AutoReadLock alock(this);
641 AssertReturn(mState == SessionState_Open, VBOX_E_INVALID_VM_STATE);
642 AssertReturn(mType == SessionType_Direct, VBOX_E_INVALID_OBJECT_STATE);
[1]643
[3001]644 return mConsole->onUSBDeviceDetach (aId, aError);
[1]645}
646
[2540]647STDMETHODIMP Session::OnShowWindow (BOOL aCheck, BOOL *aCanShow, ULONG64 *aWinId)
[2463]648{
[21878]649 AutoCaller autoCaller(this);
[2463]650 AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
651
[21878]652 AutoReadLock alock(this);
[2463]653
[21878]654 AssertReturn(mType == SessionType_Direct, VBOX_E_INVALID_OBJECT_STATE);
[11918]655
[12014]656 if (mState != SessionState_Open)
[11918]657 {
658 /* the call from Machine issued when the session is open can arrive
659 * after the session starts closing or gets closed. Note that when
660 * aCheck is false, we return E_FAIL to indicate that aWinId we return
661 * is not valid */
662 *aCanShow = FALSE;
663 *aWinId = 0;
664 return aCheck ? S_OK : E_FAIL;
665 }
666
[2540]667 return mConsole->onShowWindow (aCheck, aCanShow, aWinId);
[2463]668}
669
[15051]670STDMETHODIMP Session::AccessGuestProperty (IN_BSTR aName, IN_BSTR aValue, IN_BSTR aFlags,
[11083]671 BOOL aIsSetter, BSTR *aRetValue, ULONG64 *aRetTimestamp, BSTR *aRetFlags)
[10233]672{
[10797]673#ifdef VBOX_WITH_GUEST_PROPS
[21878]674 AutoCaller autoCaller(this);
[10233]675 AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
676
677 if (mState != SessionState_Open)
[15140]678 return setError (VBOX_E_INVALID_VM_STATE,
[23675]679 tr ("Machine session is not open (session state: %s)."),
680 Global::stringifySessionState(mState));
[21878]681 AssertReturn(mType == SessionType_Direct, VBOX_E_INVALID_OBJECT_STATE);
[14972]682 CheckComArgNotNull(aName);
[10305]683 if (!aIsSetter && !VALID_PTR (aRetValue))
[10233]684 return E_POINTER;
[11083]685 if (!aIsSetter && !VALID_PTR (aRetTimestamp))
686 return E_POINTER;
687 if (!aIsSetter && !VALID_PTR (aRetFlags))
688 return E_POINTER;
[10233]689 /* aValue can be NULL for a setter call if the property is to be deleted. */
[10305]690 if (aIsSetter && (aValue != NULL) && !VALID_PTR (aValue))
691 return E_INVALIDARG;
[11083]692 /* aFlags can be null if it is to be left as is */
693 if (aIsSetter && (aFlags != NULL) && !VALID_PTR (aFlags))
694 return E_INVALIDARG;
[10305]695 if (!aIsSetter)
[11083]696 return mConsole->getGuestProperty (aName, aRetValue, aRetTimestamp, aRetFlags);
[10233]697 else
[11083]698 return mConsole->setGuestProperty (aName, aValue, aFlags);
[10797]699#else /* VBOX_WITH_GUEST_PROPS not defined */
[14715]700 ReturnComNotImplemented();
[10797]701#endif /* VBOX_WITH_GUEST_PROPS not defined */
[10233]702}
703
[15051]704STDMETHODIMP Session::EnumerateGuestProperties (IN_BSTR aPatterns,
[11041]705 ComSafeArrayOut(BSTR, aNames),
706 ComSafeArrayOut(BSTR, aValues),
707 ComSafeArrayOut(ULONG64, aTimestamps),
708 ComSafeArrayOut(BSTR, aFlags))
709{
710#ifdef VBOX_WITH_GUEST_PROPS
[21878]711 AutoCaller autoCaller(this);
[11041]712 AssertComRCReturn (autoCaller.rc(), autoCaller.rc());
713
714 if (mState != SessionState_Open)
[15834]715 return setError (VBOX_E_INVALID_VM_STATE,
[23675]716 tr ("Machine session is not open (session state: %s)."),
717 Global::stringifySessionState(mState));
[21878]718 AssertReturn(mType == SessionType_Direct, VBOX_E_INVALID_OBJECT_STATE);
[11041]719 if (!VALID_PTR (aPatterns) && (aPatterns != NULL))
720 return E_POINTER;
[21878]721 if (ComSafeArrayOutIsNull(aNames))
[11041]722 return E_POINTER;
[21878]723 if (ComSafeArrayOutIsNull(aValues))
[11041]724 return E_POINTER;
[21878]725 if (ComSafeArrayOutIsNull(aTimestamps))
[11041]726 return E_POINTER;
[21878]727 if (ComSafeArrayOutIsNull(aFlags))
[11041]728 return E_POINTER;
729 return mConsole->enumerateGuestProperties(aPatterns,
730 ComSafeArrayOutArg(aNames),
731 ComSafeArrayOutArg(aValues),
732 ComSafeArrayOutArg(aTimestamps),
733 ComSafeArrayOutArg(aFlags));
734#else /* VBOX_WITH_GUEST_PROPS not defined */
[14715]735 ReturnComNotImplemented();
[11041]736#endif /* VBOX_WITH_GUEST_PROPS not defined */
737}
738
[1]739// private methods
740///////////////////////////////////////////////////////////////////////////////
741
742/**
743 * Closes the current session.
744 *
745 * @param aFinalRelease called as a result of FinalRelease()
746 * @param aFromServer called as a result of Uninitialize()
747 *
748 * @note To be called only from #uninit(), #Close() or #Uninitialize().
749 * @note Locks this object for writing.
750 */
751HRESULT Session::close (bool aFinalRelease, bool aFromServer)
752{
753 LogFlowThisFuncEnter();
[21878]754 LogFlowThisFunc(("aFinalRelease=%d, isFromServer=%d\n",
[1]755 aFinalRelease, aFromServer));
756
[21878]757 AutoCaller autoCaller(this);
758 AssertComRCReturnRC(autoCaller.rc());
[1]759
[21878]760 AutoWriteLock alock(this);
[1]761
[23675]762 LogFlowThisFunc(("mState=%s, mType=%d\n", Global::stringifySessionState(mState), mType));
[1]763
[7207]764 if (mState != SessionState_Open)
[1]765 {
[7207]766 Assert (mState == SessionState_Spawning);
[1]767
[13431]768 /* The session object is going to be uninitialized before it has been
769 * assigned a direct console of the machine the client requested to open
770 * a remote session to using IVirtualBox:: openRemoteSession(). It is OK
771 * only if this close reqiest comes from the server (for example, it
772 * detected that the VM process it started terminated before opening a
773 * direct session). Otherwise, it means that the client is too fast and
774 * trying to close the session before waiting for the progress object it
775 * got from IVirtualBox:: openRemoteSession() to complete, so assert. */
776 Assert (aFromServer);
[1]777
[7207]778 mState = SessionState_Closed;
779 mType = SessionType_Null;
[3668]780#if defined(RT_OS_WINDOWS)
[1]781 Assert (!mIPCSem && !mIPCThreadSem);
[3668]782#elif defined(RT_OS_OS2)
[3480]783 Assert (mIPCThread == NIL_RTTHREAD &&
784 mIPCThreadSem == NIL_RTSEMEVENT);
[606]785#elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER)
[1]786 Assert (mIPCSem == -1);
[3480]787#else
788# error "Port me!"
[1]789#endif
790 LogFlowThisFuncLeave();
791 return S_OK;
792 }
793
794 /* go to the closing state */
[24079]795 mState = SessionState_Closing;
[1]796
[7207]797 if (mType == SessionType_Direct)
[1]798 {
799 mConsole->uninit();
800 mConsole.setNull();
801 }
802 else
803 {
804 mRemoteMachine.setNull();
805 mRemoteConsole.setNull();
806 }
807
[21878]808 ComPtr<IProgress> progress;
[1]809
810 if (!aFinalRelease && !aFromServer)
811 {
812 /*
813 * We trigger OnSessionEnd() only when the session closes itself using
814 * Close(). Note that if isFinalRelease = TRUE here, this means that
815 * the client process has already initialized the termination procedure
816 * without issuing Close() and the IPC channel is no more operational --
817 * so we cannot call the server's method (it will definitely fail). The
818 * server will instead simply detect the abnormal client death (since
819 * OnSessionEnd() is not called) and reset the machine state to Aborted.
820 */
821
822 /*
823 * while waiting for OnSessionEnd() to complete one of our methods
824 * can be called by the server (for example, Uninitialize(), if the
825 * direct session has initiated a closure just a bit before us) so
826 * we need to release the lock to avoid deadlocks. The state is already
[7207]827 * SessionState_Closing here, so it's safe.
[1]828 */
829 alock.leave();
830
[21878]831 LogFlowThisFunc(("Calling mControl->OnSessionEnd()...\n"));
[1]832 HRESULT rc = mControl->OnSessionEnd (this, progress.asOutParam());
[21878]833 LogFlowThisFunc(("mControl->OnSessionEnd()=%08X\n", rc));
[1]834
835 alock.enter();
836
837 /*
838 * If we get E_UNEXPECTED this means that the direct session has already
839 * been closed, we're just too late with our notification and nothing more
840 */
[7207]841 if (mType != SessionType_Direct && rc == E_UNEXPECTED)
[1]842 rc = S_OK;
843
844 AssertComRC (rc);
845 }
846
847 mControl.setNull();
848
[7207]849 if (mType == SessionType_Direct)
[1]850 {
851 releaseIPCSemaphore();
852 if (!aFinalRelease && !aFromServer)
853 {
854 /*
855 * Wait for the server to grab the semaphore and destroy the session
856 * machine (allowing us to open a new session with the same machine
857 * once this method returns)
858 */
859 Assert (!!progress);
860 if (progress)
861 progress->WaitForCompletion (-1);
862 }
863 }
864
[7207]865 mState = SessionState_Closed;
866 mType = SessionType_Null;
[1]867
868 /* release the VirtualBox instance as the very last step */
869 mVirtualBox.setNull();
870
871 LogFlowThisFuncLeave();
872 return S_OK;
873}
874
875/** @note To be called only from #AssignMachine() */
876HRESULT Session::grabIPCSemaphore()
877{
878 HRESULT rc = E_FAIL;
879
880 /* open the IPC semaphore based on the sessionId and try to grab it */
881 Bstr ipcId;
882 rc = mControl->GetIPCId (ipcId.asOutParam());
[21878]883 AssertComRCReturnRC(rc);
[1]884
[21878]885 LogFlowThisFunc(("ipcId='%ls'\n", ipcId.raw()));
[1]886
[3668]887#if defined(RT_OS_WINDOWS)
[1]888
889 /*
890 * Since Session is an MTA object, this method can be executed on
891 * any thread, and this thread will not necessarily match the thread on
892 * which close() will be called later. Therefore, we need a separate
893 * thread to hold the IPC mutex and then release it in close().
894 */
895
896 mIPCThreadSem = ::CreateEvent (NULL, FALSE, FALSE, NULL);
897 AssertMsgReturn (mIPCThreadSem,
898 ("Cannot create an event sem, err=%d", ::GetLastError()),
899 E_FAIL);
900
901 void *data [3];
902 data [0] = (void *) (BSTR) ipcId;
903 data [1] = (void *) mIPCThreadSem;
904 data [2] = 0; /* will get an output from the thread */
905
[3480]906 /* create a thread to hold the IPC mutex until signalled to release it */
[1]907 RTTHREAD tid;
908 int vrc = RTThreadCreate (&tid, IPCMutexHolderThread, (void *) data,
909 0, RTTHREADTYPE_MAIN_WORKER, 0, "IPCHolder");
910 AssertRCReturn (vrc, E_FAIL);
911
912 /* wait until thread init is completed */
913 DWORD wrc = ::WaitForSingleObject (mIPCThreadSem, INFINITE);
[3480]914 AssertMsg (wrc == WAIT_OBJECT_0, ("Wait failed, err=%d\n", ::GetLastError()));
[1]915 Assert (data [2]);
916
917 if (wrc == WAIT_OBJECT_0 && data [2])
918 {
919 /* memorize the event sem we should signal in close() */
920 mIPCSem = (HANDLE) data [2];
921 rc = S_OK;
922 }
923 else
924 {
925 ::CloseHandle (mIPCThreadSem);
926 mIPCThreadSem = NULL;
927 rc = E_FAIL;
928 }
929
[3668]930#elif defined(RT_OS_OS2)
[3480]931
932 /* We use XPCOM where any message (including close()) can arrive on any
933 * worker thread (which will not necessarily match this thread that opens
934 * the mutex). Therefore, we need a separate thread to hold the IPC mutex
935 * and then release it in close(). */
936
937 int vrc = RTSemEventCreate (&mIPCThreadSem);
938 AssertRCReturn (vrc, E_FAIL);
939
940 void *data [3];
941 data [0] = (void *) ipcId.raw();
942 data [1] = (void *) mIPCThreadSem;
943 data [2] = (void *) false; /* will get the thread result here */
944
945 /* create a thread to hold the IPC mutex until signalled to release it */
946 vrc = RTThreadCreate (&mIPCThread, IPCMutexHolderThread, (void *) data,
947 0, RTTHREADTYPE_MAIN_WORKER, 0, "IPCHolder");
948 AssertRCReturn (vrc, E_FAIL);
949
950 /* wait until thread init is completed */
951 vrc = RTThreadUserWait (mIPCThread, RT_INDEFINITE_WAIT);
[21878]952 AssertReturn(RT_SUCCESS(vrc) || vrc == VERR_INTERRUPTED, E_FAIL);
[3480]953
954 /* the thread must succeed */
[21878]955 AssertReturn((bool) data [2], E_FAIL);
[3480]956
[606]957#elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER)
[1]958
[17180]959# ifdef VBOX_WITH_NEW_SYS_V_KEYGEN
960 Utf8Str ipcKey = ipcId;
961 key_t key = RTStrToUInt32(ipcKey.raw());
962 AssertMsgReturn (key != 0,
963 ("Key value of 0 is not valid for IPC semaphore"),
964 E_FAIL);
965# else /* !VBOX_WITH_NEW_SYS_V_KEYGEN */
[1]966 Utf8Str semName = ipcId;
967 char *pszSemName = NULL;
968 RTStrUtf8ToCurrentCP (&pszSemName, semName);
[16244]969 key_t key = ::ftok (pszSemName, 'V');
[1]970 RTStrFree (pszSemName);
[17180]971# endif /* !VBOX_WITH_NEW_SYS_V_KEYGEN */
[1]972
973 mIPCSem = ::semget (key, 0, 0);
974 AssertMsgReturn (mIPCSem >= 0,
975 ("Cannot open IPC semaphore, errno=%d", errno),
976 E_FAIL);
977
978 /* grab the semaphore */
979 ::sembuf sop = { 0, -1, SEM_UNDO };
980 int rv = ::semop (mIPCSem, &sop, 1);
981 AssertMsgReturn (rv == 0,
982 ("Cannot grab IPC semaphore, errno=%d", errno),
983 E_FAIL);
984
[3480]985#else
986# error "Port me!"
[1]987#endif
988
989 return rc;
990}
991
992/** @note To be called only from #close() */
993void Session::releaseIPCSemaphore()
994{
995 /* release the IPC semaphore */
[3668]996#if defined(RT_OS_WINDOWS)
[3480]997
[1]998 if (mIPCSem && mIPCThreadSem)
999 {
1000 /*
[3480]1001 * tell the thread holding the IPC mutex to release it;
[1]1002 * it will close mIPCSem handle
1003 */
1004 ::SetEvent (mIPCSem);
1005 /* wait for the thread to finish */
1006 ::WaitForSingleObject (mIPCThreadSem, INFINITE);
1007 ::CloseHandle (mIPCThreadSem);
[17600]1008
1009 mIPCThreadSem = NULL;
1010 mIPCSem = NULL;
[1]1011 }
[3480]1012
[3668]1013#elif defined(RT_OS_OS2)
[3480]1014
1015 if (mIPCThread != NIL_RTTHREAD)
1016 {
1017 Assert (mIPCThreadSem != NIL_RTSEMEVENT);
1018
1019 /* tell the thread holding the IPC mutex to release it */
1020 int vrc = RTSemEventSignal (mIPCThreadSem);
1021 AssertRC (vrc == NO_ERROR);
1022
1023 /* wait for the thread to finish */
1024 vrc = RTThreadUserWait (mIPCThread, RT_INDEFINITE_WAIT);
[21878]1025 Assert (RT_SUCCESS(vrc) || vrc == VERR_INTERRUPTED);
[3480]1026
1027 mIPCThread = NIL_RTTHREAD;
1028 }
1029
1030 if (mIPCThreadSem != NIL_RTSEMEVENT)
1031 {
1032 RTSemEventDestroy (mIPCThreadSem);
1033 mIPCThreadSem = NIL_RTSEMEVENT;
1034 }
1035
[606]1036#elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER)
[3480]1037
[1]1038 if (mIPCSem >= 0)
1039 {
1040 ::sembuf sop = { 0, 1, SEM_UNDO };
1041 ::semop (mIPCSem, &sop, 1);
[17600]1042
1043 mIPCSem = -1;
[1]1044 }
[3480]1045
1046#else
1047# error "Port me!"
[1]1048#endif
1049}
1050
[3668]1051#if defined(RT_OS_WINDOWS)
[1]1052/** VM IPC mutex holder thread */
1053DECLCALLBACK(int) IPCMutexHolderThread (RTTHREAD Thread, void *pvUser)
1054{
1055 LogFlowFuncEnter();
1056
1057 Assert (pvUser);
1058 void **data = (void **) pvUser;
1059
1060 BSTR sessionId = (BSTR) data [0];
1061 HANDLE initDoneSem = (HANDLE) data [1];
1062
1063 HANDLE ipcMutex = ::OpenMutex (MUTEX_ALL_ACCESS, FALSE, sessionId);
[3480]1064 AssertMsg (ipcMutex, ("cannot open IPC mutex, err=%d\n", ::GetLastError()));
[1]1065
1066 if (ipcMutex)
1067 {
1068 /* grab the mutex */
1069 DWORD wrc = ::WaitForSingleObject (ipcMutex, 0);
1070 AssertMsg (wrc == WAIT_OBJECT_0, ("cannot grab IPC mutex, err=%d\n", wrc));
1071 if (wrc == WAIT_OBJECT_0)
1072 {
1073 HANDLE finishSem = ::CreateEvent (NULL, FALSE, FALSE, NULL);
1074 AssertMsg (finishSem, ("cannot create event sem, err=%d\n", ::GetLastError()));
1075 if (finishSem)
1076 {
1077 data [2] = (void *) finishSem;
1078 /* signal we're done with init */
1079 ::SetEvent (initDoneSem);
1080 /* wait until we're signaled to release the IPC mutex */
1081 ::WaitForSingleObject (finishSem, INFINITE);
1082 /* release the IPC mutex */
1083 LogFlow (("IPCMutexHolderThread(): releasing IPC mutex...\n"));
1084 BOOL success = ::ReleaseMutex (ipcMutex);
1085 AssertMsg (success, ("cannot release mutex, err=%d\n", ::GetLastError()));
1086 ::CloseHandle (ipcMutex);
1087 ::CloseHandle (finishSem);
1088 }
1089 }
1090 }
1091
1092 /* signal we're done */
1093 ::SetEvent (initDoneSem);
1094
1095 LogFlowFuncLeave();
1096
1097 return 0;
1098}
1099#endif
1100
[5713]1101#if defined(RT_OS_OS2)
[3480]1102/** VM IPC mutex holder thread */
1103DECLCALLBACK(int) IPCMutexHolderThread (RTTHREAD Thread, void *pvUser)
1104{
1105 LogFlowFuncEnter();
1106
1107 Assert (pvUser);
1108 void **data = (void **) pvUser;
1109
1110 Utf8Str ipcId = (BSTR) data [0];
1111 RTSEMEVENT finishSem = (RTSEMEVENT) data [1];
1112
1113 LogFlowFunc (("ipcId='%s', finishSem=%p\n", ipcId.raw(), finishSem));
1114
1115 HMTX ipcMutex = NULLHANDLE;
1116 APIRET arc = ::DosOpenMutexSem ((PSZ) ipcId.raw(), &ipcMutex);
1117 AssertMsg (arc == NO_ERROR, ("cannot open IPC mutex, arc=%ld\n", arc));
1118
1119 if (arc == NO_ERROR)
1120 {
1121 /* grab the mutex */
1122 LogFlowFunc (("grabbing IPC mutex...\n"));
1123 arc = ::DosRequestMutexSem (ipcMutex, SEM_IMMEDIATE_RETURN);
1124 AssertMsg (arc == NO_ERROR, ("cannot grab IPC mutex, arc=%ld\n", arc));
1125 if (arc == NO_ERROR)
1126 {
1127 /* store the answer */
1128 data [2] = (void *) true;
1129 /* signal we're done */
1130 int vrc = RTThreadUserSignal (Thread);
1131 AssertRC (vrc);
1132
1133 /* wait until we're signaled to release the IPC mutex */
1134 LogFlowFunc (("waiting for termination signal..\n"));
1135 vrc = RTSemEventWait (finishSem, RT_INDEFINITE_WAIT);
1136 Assert (arc == ERROR_INTERRUPT || ERROR_TIMEOUT);
1137
1138 /* release the IPC mutex */
1139 LogFlowFunc (("releasing IPC mutex...\n"));
1140 arc = ::DosReleaseMutexSem (ipcMutex);
1141 AssertMsg (arc == NO_ERROR, ("cannot release mutex, arc=%ld\n", arc));
1142 }
[3497]1143
1144 ::DosCloseMutexSem (ipcMutex);
[3480]1145 }
1146
1147 /* store the answer */
1148 data [1] = (void *) false;
1149 /* signal we're done */
1150 int vrc = RTThreadUserSignal (Thread);
1151 AssertRC (vrc);
1152
1153 LogFlowFuncLeave();
1154
1155 return 0;
1156}
1157#endif
[14772]1158/* vi: set tabstop=4 shiftwidth=4 expandtab: */
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use