~ubuntu-branches/ubuntu/raring/virtualbox-ose/raring

« back to all changes in this revision

Viewing changes to src/VBox/Main/src-client/SessionImpl.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Felix Geyer
  • Date: 2011-01-30 23:27:25 UTC
  • mfrom: (0.3.12 upstream)
  • Revision ID: james.westby@ubuntu.com-20110130232725-2ouajjd2ggdet0zd
Tags: 4.0.2-dfsg-1ubuntu1
* Merge from Debian unstable, remaining changes:
  - Add Apport hook.
    - debian/virtualbox-ose.files/source_virtualbox-ose.py
    - debian/virtualbox-ose.install
  - Drop *-source packages.
* Drop ubuntu-01-fix-build-gcc45.patch, fixed upstream.
* Drop ubuntu-02-as-needed.patch, added to the Debian package.

Show diffs side-by-side

added added

removed removed

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