[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 */
|
---|
| 41 | static 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 |
|
---|
| 60 | HRESULT Session::FinalConstruct()
|
---|
| 61 | {
|
---|
[21878] | 62 | LogFlowThisFunc(("\n"));
|
---|
[1] | 63 |
|
---|
| 64 | return init();
|
---|
| 65 | }
|
---|
| 66 |
|
---|
| 67 | void 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 | */
|
---|
| 80 | HRESULT 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 | */
|
---|
| 116 | void 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 |
|
---|
| 148 | STDMETHODIMP 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 |
|
---|
| 162 | STDMETHODIMP 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 |
|
---|
| 177 | STDMETHODIMP 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 |
|
---|
| 199 | STDMETHODIMP 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 |
|
---|
| 224 | STDMETHODIMP 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 |
|
---|
| 242 | STDMETHODIMP 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 |
|
---|
| 257 | STDMETHODIMP 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 |
|
---|
| 284 | STDMETHODIMP 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 |
|
---|
| 353 | STDMETHODIMP 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 |
|
---|
| 426 | STDMETHODIMP 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 |
|
---|
| 457 | STDMETHODIMP 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] | 504 | STDMETHODIMP 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] | 518 | STDMETHODIMP 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] | 532 | STDMETHODIMP 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] | 546 | STDMETHODIMP 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] | 560 | STDMETHODIMP 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] | 574 | STDMETHODIMP 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 |
|
---|
| 588 | STDMETHODIMP 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] | 602 | STDMETHODIMP 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] | 616 | STDMETHODIMP 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] | 632 | STDMETHODIMP 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] | 647 | STDMETHODIMP 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] | 670 | STDMETHODIMP 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] | 704 | STDMETHODIMP 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 | */
|
---|
| 751 | HRESULT 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() */
|
---|
| 876 | HRESULT 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() */
|
---|
| 993 | void 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 */
|
---|
| 1053 | DECLCALLBACK(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 */
|
---|
| 1103 | DECLCALLBACK(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: */
|
---|