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

« back to all changes in this revision

Viewing changes to src/VBox/Main/src-client/HGCM.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
/** @file
 
2
 *
 
3
 * HGCM (Host-Guest Communication Manager)
 
4
 */
 
5
 
 
6
/*
 
7
 * Copyright (C) 2006-2007 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
#define LOG_GROUP_MAIN_OVERRIDE LOG_GROUP_HGCM
 
19
#include "Logging.h"
 
20
 
 
21
#include "HGCM.h"
 
22
#include "HGCMThread.h"
 
23
 
 
24
#include <VBox/err.h>
 
25
#include <VBox/hgcmsvc.h>
 
26
#include <VBox/vmm/ssm.h>
 
27
#include <VBox/sup.h>
 
28
 
 
29
#include <iprt/alloc.h>
 
30
#include <iprt/alloca.h>
 
31
#include <iprt/avl.h>
 
32
#include <iprt/critsect.h>
 
33
#include <iprt/asm.h>
 
34
#include <iprt/ldr.h>
 
35
#include <iprt/param.h>
 
36
#include <iprt/path.h>
 
37
#include <iprt/string.h>
 
38
#include <iprt/semaphore.h>
 
39
#include <iprt/thread.h>
 
40
 
 
41
#include <VBox/VMMDev.h>
 
42
 
 
43
/**
 
44
 * A service gets one thread, which synchronously delivers messages to
 
45
 * the service. This is good for serialization.
 
46
 *
 
47
 * Some services may want to process messages asynchronously, and will want
 
48
 * a next message to be delivered, while a previous message is still being
 
49
 * processed.
 
50
 *
 
51
 * The dedicated service thread delivers a next message when service
 
52
 * returns after fetching a previous one. The service will call a message
 
53
 * completion callback when message is actually processed. So returning
 
54
 * from the service call means only that the service is processing message.
 
55
 *
 
56
 * 'Message processed' condition is indicated by service, which call the
 
57
 * callback, even if the callback is called synchronously in the dedicated
 
58
 * thread.
 
59
 *
 
60
 * This message completion callback is only valid for Call requests.
 
61
 * Connect and Disconnect are processed synchronously by the service.
 
62
 */
 
63
 
 
64
 
 
65
/* The maximum allowed size of a service name in bytes. */
 
66
#define VBOX_HGCM_SVC_NAME_MAX_BYTES 1024
 
67
 
 
68
struct _HGCMSVCEXTHANDLEDATA
 
69
{
 
70
    char *pszServiceName;
 
71
    /* The service name follows. */
 
72
};
 
73
 
 
74
/** Internal helper service object. HGCM code would use it to
 
75
 *  hold information about services and communicate with services.
 
76
 *  The HGCMService is an (in future) abstract class that implements
 
77
 *  common functionality. There will be derived classes for specific
 
78
 *  service types.
 
79
 */
 
80
 
 
81
class HGCMService
 
82
{
 
83
    private:
 
84
        VBOXHGCMSVCHELPERS m_svcHelpers;
 
85
 
 
86
        static HGCMService *sm_pSvcListHead;
 
87
        static HGCMService *sm_pSvcListTail;
 
88
 
 
89
        static int sm_cServices;
 
90
 
 
91
        HGCMTHREADHANDLE m_thread;
 
92
        friend DECLCALLBACK(void) hgcmServiceThread (HGCMTHREADHANDLE ThreadHandle, void *pvUser);
 
93
 
 
94
        uint32_t volatile m_u32RefCnt;
 
95
 
 
96
        HGCMService *m_pSvcNext;
 
97
        HGCMService *m_pSvcPrev;
 
98
 
 
99
        char *m_pszSvcName;
 
100
        char *m_pszSvcLibrary;
 
101
 
 
102
        RTLDRMOD m_hLdrMod;
 
103
        PFNVBOXHGCMSVCLOAD m_pfnLoad;
 
104
 
 
105
        VBOXHGCMSVCFNTABLE m_fntable;
 
106
 
 
107
        int m_cClients;
 
108
        int m_cClientsAllocated;
 
109
 
 
110
        uint32_t *m_paClientIds;
 
111
 
 
112
#ifdef VBOX_WITH_CRHGSMI
 
113
        uint32_t m_cHandleAcquires;
 
114
#endif
 
115
 
 
116
        HGCMSVCEXTHANDLE m_hExtension;
 
117
 
 
118
        int loadServiceDLL (void);
 
119
        void unloadServiceDLL (void);
 
120
 
 
121
        /*
 
122
         * Main HGCM thread methods.
 
123
         */
 
124
        int instanceCreate (const char *pszServiceLibrary, const char *pszServiceName);
 
125
        void instanceDestroy (void);
 
126
 
 
127
        int saveClientState(uint32_t u32ClientId, PSSMHANDLE pSSM);
 
128
        int loadClientState(uint32_t u32ClientId, PSSMHANDLE pSSM);
 
129
 
 
130
        HGCMService ();
 
131
        ~HGCMService () {};
 
132
 
 
133
        static DECLCALLBACK(void) svcHlpCallComplete (VBOXHGCMCALLHANDLE callHandle, int32_t rc);
 
134
        static DECLCALLBACK(void) svcHlpDisconnectClient (void *pvInstance, uint32_t u32ClientId);
 
135
 
 
136
    public:
 
137
 
 
138
        /*
 
139
         * Main HGCM thread methods.
 
140
         */
 
141
        static int LoadService (const char *pszServiceLibrary, const char *pszServiceName);
 
142
        void UnloadService (void);
 
143
 
 
144
        static void UnloadAll (void);
 
145
 
 
146
        static int ResolveService (HGCMService **ppsvc, const char *pszServiceName);
 
147
        void ReferenceService (void);
 
148
        void ReleaseService (void);
 
149
 
 
150
        static void Reset (void);
 
151
 
 
152
        static int SaveState (PSSMHANDLE pSSM);
 
153
        static int LoadState (PSSMHANDLE pSSM);
 
154
 
 
155
        int CreateAndConnectClient (uint32_t *pu32ClientIdOut, uint32_t u32ClientIdIn);
 
156
        int DisconnectClient (uint32_t u32ClientId, bool fFromService);
 
157
 
 
158
        int HostCall (uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM *paParms);
 
159
 
 
160
#ifdef VBOX_WITH_CRHGSMI
 
161
        int HandleAcquired();
 
162
        int HandleReleased();
 
163
        int HostFastCallAsync (uint32_t u32Function, VBOXHGCMSVCPARM *pParm, PHGCMHOSTFASTCALLCB pfnCompletion, void *pvCompletion);
 
164
#endif
 
165
 
 
166
        uint32_t SizeOfClient (void) { return m_fntable.cbClient; };
 
167
 
 
168
        int RegisterExtension (HGCMSVCEXTHANDLE handle, PFNHGCMSVCEXT pfnExtension, void *pvExtension);
 
169
        void UnregisterExtension (HGCMSVCEXTHANDLE handle);
 
170
 
 
171
        /*
 
172
         * The service thread methods.
 
173
         */
 
174
 
 
175
        int GuestCall (PPDMIHGCMPORT pHGCMPort, PVBOXHGCMCMD pCmd, uint32_t u32ClientId, uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM aParms[]);
 
176
};
 
177
 
 
178
 
 
179
class HGCMClient: public HGCMObject
 
180
{
 
181
    public:
 
182
        HGCMClient () : HGCMObject(HGCMOBJ_CLIENT), pService(NULL),
 
183
                        pvData(NULL) {};
 
184
        ~HGCMClient ();
 
185
 
 
186
        int Init (HGCMService *pSvc);
 
187
 
 
188
        /** Service that the client is connected to. */
 
189
        HGCMService *pService;
 
190
 
 
191
        /** Client specific data. */
 
192
        void *pvData;
 
193
};
 
194
 
 
195
HGCMClient::~HGCMClient ()
 
196
{
 
197
    if (pService->SizeOfClient () > 0)
 
198
        RTMemFree (pvData);
 
199
}
 
200
 
 
201
int HGCMClient::Init (HGCMService *pSvc)
 
202
{
 
203
    pService = pSvc;
 
204
 
 
205
    if (pService->SizeOfClient () > 0)
 
206
    {
 
207
        pvData = RTMemAllocZ (pService->SizeOfClient ());
 
208
 
 
209
        if (!pvData)
 
210
        {
 
211
           return VERR_NO_MEMORY;
 
212
        }
 
213
    }
 
214
 
 
215
    return VINF_SUCCESS;
 
216
}
 
217
 
 
218
 
 
219
#define HGCM_CLIENT_DATA(pService, pClient) (pClient->pvData)
 
220
 
 
221
 
 
222
 
 
223
HGCMService *HGCMService::sm_pSvcListHead = NULL;
 
224
HGCMService *HGCMService::sm_pSvcListTail = NULL;
 
225
int HGCMService::sm_cServices = 0;
 
226
 
 
227
HGCMService::HGCMService ()
 
228
    :
 
229
    m_thread     (0),
 
230
    m_u32RefCnt  (0),
 
231
    m_pSvcNext   (NULL),
 
232
    m_pSvcPrev   (NULL),
 
233
    m_pszSvcName (NULL),
 
234
    m_pszSvcLibrary (NULL),
 
235
    m_hLdrMod    (NIL_RTLDRMOD),
 
236
    m_pfnLoad    (NULL),
 
237
    m_cClients   (0),
 
238
    m_cClientsAllocated (0),
 
239
    m_paClientIds (NULL),
 
240
#ifdef VBOX_WITH_CRHGSMI
 
241
    m_cHandleAcquires (0),
 
242
#endif
 
243
    m_hExtension (NULL)
 
244
{
 
245
    memset (&m_fntable, 0, sizeof (m_fntable));
 
246
}
 
247
 
 
248
 
 
249
static bool g_fResetting = false;
 
250
static bool g_fSaveState = false;
 
251
 
 
252
 
 
253
/** Helper function to load a local service DLL.
 
254
 *
 
255
 *  @return VBox code
 
256
 */
 
257
int HGCMService::loadServiceDLL (void)
 
258
{
 
259
    LogFlowFunc(("m_pszSvcLibrary = %s\n", m_pszSvcLibrary));
 
260
 
 
261
    if (m_pszSvcLibrary == NULL)
 
262
    {
 
263
        return VERR_INVALID_PARAMETER;
 
264
    }
 
265
 
 
266
    RTERRINFOSTATIC ErrInfo;
 
267
    RTErrInfoInitStatic (&ErrInfo);
 
268
 
 
269
    int rc = SUPR3HardenedLdrLoadAppPriv (m_pszSvcLibrary, &m_hLdrMod, RTLDRLOAD_FLAGS_LOCAL, &ErrInfo.Core);
 
270
 
 
271
    if (RT_SUCCESS(rc))
 
272
    {
 
273
        LogFlowFunc(("successfully loaded the library.\n"));
 
274
 
 
275
        m_pfnLoad = NULL;
 
276
 
 
277
        rc = RTLdrGetSymbol (m_hLdrMod, VBOX_HGCM_SVCLOAD_NAME, (void**)&m_pfnLoad);
 
278
 
 
279
        if (RT_FAILURE(rc) || !m_pfnLoad)
 
280
        {
 
281
            Log(("HGCMService::loadServiceDLL: Error resolving the service entry point %s, rc = %d, m_pfnLoad = %p\n", VBOX_HGCM_SVCLOAD_NAME, rc, m_pfnLoad));
 
282
 
 
283
            if (RT_SUCCESS(rc))
 
284
            {
 
285
                /* m_pfnLoad was NULL */
 
286
                rc = VERR_SYMBOL_NOT_FOUND;
 
287
            }
 
288
        }
 
289
 
 
290
        if (RT_SUCCESS(rc))
 
291
        {
 
292
            memset (&m_fntable, 0, sizeof (m_fntable));
 
293
 
 
294
            m_fntable.cbSize     = sizeof (m_fntable);
 
295
            m_fntable.u32Version = VBOX_HGCM_SVC_VERSION;
 
296
            m_fntable.pHelpers   = &m_svcHelpers;
 
297
 
 
298
            rc = m_pfnLoad (&m_fntable);
 
299
 
 
300
            LogFlowFunc(("m_pfnLoad rc = %Rrc\n", rc));
 
301
 
 
302
            if (RT_SUCCESS(rc))
 
303
            {
 
304
                if (   m_fntable.pfnUnload == NULL
 
305
                    || m_fntable.pfnConnect == NULL
 
306
                    || m_fntable.pfnDisconnect == NULL
 
307
                    || m_fntable.pfnCall == NULL
 
308
                   )
 
309
                {
 
310
                    Log(("HGCMService::loadServiceDLL: at least one of function pointers is NULL\n"));
 
311
 
 
312
                    rc = VERR_INVALID_PARAMETER;
 
313
 
 
314
                    if (m_fntable.pfnUnload)
 
315
                    {
 
316
                        m_fntable.pfnUnload (m_fntable.pvService);
 
317
                    }
 
318
                }
 
319
            }
 
320
        }
 
321
    }
 
322
    else
 
323
    {
 
324
        LogRel(("HGCM: Failed to load the service library: [%s], rc = %Rrc - %s. The service will be not available.\n",
 
325
                m_pszSvcLibrary, rc, ErrInfo.Core.pszMsg));
 
326
        m_hLdrMod = NIL_RTLDRMOD;
 
327
    }
 
328
 
 
329
    if (RT_FAILURE(rc))
 
330
    {
 
331
        unloadServiceDLL ();
 
332
    }
 
333
 
 
334
    return rc;
 
335
}
 
336
 
 
337
/** Helper function to free a local service DLL.
 
338
 *
 
339
 *  @return VBox code
 
340
 */
 
341
void HGCMService::unloadServiceDLL (void)
 
342
{
 
343
    if (m_hLdrMod)
 
344
    {
 
345
        RTLdrClose (m_hLdrMod);
 
346
    }
 
347
 
 
348
    memset (&m_fntable, 0, sizeof (m_fntable));
 
349
    m_pfnLoad = NULL;
 
350
    m_hLdrMod = NIL_RTLDRMOD;
 
351
}
 
352
 
 
353
/*
 
354
 * Messages processed by service threads. These threads only call the service entry points.
 
355
 */
 
356
 
 
357
#define SVC_MSG_LOAD       (0)  /* Load the service library and call VBOX_HGCM_SVCLOAD_NAME entry point. */
 
358
#define SVC_MSG_UNLOAD     (1)  /* call pfnUnload and unload the service library. */
 
359
#define SVC_MSG_CONNECT    (2)  /* pfnConnect */
 
360
#define SVC_MSG_DISCONNECT (3)  /* pfnDisconnect */
 
361
#define SVC_MSG_GUESTCALL  (4)  /* pfnGuestCall */
 
362
#define SVC_MSG_HOSTCALL   (5)  /* pfnHostCall */
 
363
#define SVC_MSG_LOADSTATE  (6)  /* pfnLoadState. */
 
364
#define SVC_MSG_SAVESTATE  (7)  /* pfnSaveState. */
 
365
#define SVC_MSG_QUIT       (8)  /* Terminate the thread. */
 
366
#define SVC_MSG_REGEXT     (9)  /* pfnRegisterExtension */
 
367
#define SVC_MSG_UNREGEXT   (10) /* pfnRegisterExtension */
 
368
#ifdef VBOX_WITH_CRHGSMI
 
369
# define SVC_MSG_HOSTFASTCALLASYNC (21) /* pfnHostCall */
 
370
#endif
 
371
 
 
372
class HGCMMsgSvcLoad: public HGCMMsgCore
 
373
{
 
374
};
 
375
 
 
376
class HGCMMsgSvcUnload: public HGCMMsgCore
 
377
{
 
378
};
 
379
 
 
380
class HGCMMsgSvcConnect: public HGCMMsgCore
 
381
{
 
382
    public:
 
383
        /* client identifier */
 
384
        uint32_t u32ClientId;
 
385
};
 
386
 
 
387
class HGCMMsgSvcDisconnect: public HGCMMsgCore
 
388
{
 
389
    public:
 
390
        /* client identifier */
 
391
        uint32_t u32ClientId;
 
392
};
 
393
 
 
394
class HGCMMsgHeader: public HGCMMsgCore
 
395
{
 
396
    public:
 
397
        HGCMMsgHeader () : pCmd (NULL), pHGCMPort (NULL) {};
 
398
 
 
399
        /* Command pointer/identifier. */
 
400
        PVBOXHGCMCMD pCmd;
 
401
 
 
402
        /* Port to be informed on message completion. */
 
403
        PPDMIHGCMPORT pHGCMPort;
 
404
};
 
405
 
 
406
 
 
407
class HGCMMsgCall: public HGCMMsgHeader
 
408
{
 
409
    public:
 
410
        /* client identifier */
 
411
        uint32_t u32ClientId;
 
412
 
 
413
        /* function number */
 
414
        uint32_t u32Function;
 
415
 
 
416
        /* number of parameters */
 
417
        uint32_t cParms;
 
418
 
 
419
        VBOXHGCMSVCPARM *paParms;
 
420
};
 
421
 
 
422
class HGCMMsgLoadSaveStateClient: public HGCMMsgCore
 
423
{
 
424
    public:
 
425
        uint32_t    u32ClientId;
 
426
        PSSMHANDLE  pSSM;
 
427
};
 
428
 
 
429
class HGCMMsgHostCallSvc: public HGCMMsgCore
 
430
{
 
431
    public:
 
432
        /* function number */
 
433
        uint32_t u32Function;
 
434
 
 
435
        /* number of parameters */
 
436
        uint32_t cParms;
 
437
 
 
438
        VBOXHGCMSVCPARM *paParms;
 
439
};
 
440
 
 
441
class HGCMMsgSvcRegisterExtension: public HGCMMsgCore
 
442
{
 
443
    public:
 
444
        /* Handle of the extension to be registered. */
 
445
        HGCMSVCEXTHANDLE handle;
 
446
        /* The extension entry point. */
 
447
        PFNHGCMSVCEXT pfnExtension;
 
448
        /* The extension pointer. */
 
449
        void *pvExtension;
 
450
};
 
451
 
 
452
class HGCMMsgSvcUnregisterExtension: public HGCMMsgCore
 
453
{
 
454
    public:
 
455
        /* Handle of the registered extension. */
 
456
        HGCMSVCEXTHANDLE handle;
 
457
};
 
458
 
 
459
#ifdef VBOX_WITH_CRHGSMI
 
460
class HGCMMsgHostFastCallAsyncSvc: public HGCMMsgCore
 
461
{
 
462
    public:
 
463
        /* function number */
 
464
        uint32_t u32Function;
 
465
        /* parameter */
 
466
        VBOXHGCMSVCPARM Param;
 
467
        /* completion info */
 
468
        PHGCMHOSTFASTCALLCB pfnCompletion;
 
469
        void *pvCompletion;
 
470
};
 
471
#endif
 
472
 
 
473
static HGCMMsgCore *hgcmMessageAllocSvc (uint32_t u32MsgId)
 
474
{
 
475
    switch (u32MsgId)
 
476
    {
 
477
#ifdef VBOX_WITH_CRHGSMI
 
478
        case SVC_MSG_HOSTFASTCALLASYNC: return new HGCMMsgHostFastCallAsyncSvc ();
 
479
#endif
 
480
        case SVC_MSG_LOAD:        return new HGCMMsgSvcLoad ();
 
481
        case SVC_MSG_UNLOAD:      return new HGCMMsgSvcUnload ();
 
482
        case SVC_MSG_CONNECT:     return new HGCMMsgSvcConnect ();
 
483
        case SVC_MSG_DISCONNECT:  return new HGCMMsgSvcDisconnect ();
 
484
        case SVC_MSG_HOSTCALL:    return new HGCMMsgHostCallSvc ();
 
485
        case SVC_MSG_GUESTCALL:   return new HGCMMsgCall ();
 
486
        case SVC_MSG_LOADSTATE:
 
487
        case SVC_MSG_SAVESTATE:   return new HGCMMsgLoadSaveStateClient ();
 
488
        case SVC_MSG_REGEXT:      return new HGCMMsgSvcRegisterExtension ();
 
489
        case SVC_MSG_UNREGEXT:    return new HGCMMsgSvcUnregisterExtension ();
 
490
        default:
 
491
            AssertReleaseMsgFailed(("Msg id = %08X\n", u32MsgId));
 
492
    }
 
493
 
 
494
    return NULL;
 
495
}
 
496
 
 
497
/*
 
498
 * The service thread. Loads the service library and calls the service entry points.
 
499
 */
 
500
DECLCALLBACK(void) hgcmServiceThread (HGCMTHREADHANDLE ThreadHandle, void *pvUser)
 
501
{
 
502
    HGCMService *pSvc = (HGCMService *)pvUser;
 
503
    AssertRelease(pSvc != NULL);
 
504
 
 
505
    bool fQuit = false;
 
506
 
 
507
    while (!fQuit)
 
508
    {
 
509
        HGCMMsgCore *pMsgCore;
 
510
        int rc = hgcmMsgGet (ThreadHandle, &pMsgCore);
 
511
 
 
512
        if (RT_FAILURE(rc))
 
513
        {
 
514
            /* The error means some serious unrecoverable problem in the hgcmMsg/hgcmThread layer. */
 
515
            AssertMsgFailed (("%Rrc\n", rc));
 
516
            break;
 
517
        }
 
518
 
 
519
        /* Cache required information to avoid unnecessary pMsgCore access. */
 
520
        uint32_t u32MsgId = pMsgCore->MsgId ();
 
521
 
 
522
        switch (u32MsgId)
 
523
        {
 
524
#ifdef VBOX_WITH_CRHGSMI
 
525
            case SVC_MSG_HOSTFASTCALLASYNC:
 
526
            {
 
527
                HGCMMsgHostFastCallAsyncSvc *pMsg = (HGCMMsgHostFastCallAsyncSvc *)pMsgCore;
 
528
 
 
529
                LogFlowFunc(("SVC_MSG_HOSTFASTCALLASYNC u32Function = %d, pParm = %p\n", pMsg->u32Function, &pMsg->Param));
 
530
 
 
531
                rc = pSvc->m_fntable.pfnHostCall (pSvc->m_fntable.pvService, pMsg->u32Function, 1, &pMsg->Param);
 
532
            } break;
 
533
#endif
 
534
            case SVC_MSG_LOAD:
 
535
            {
 
536
                LogFlowFunc(("SVC_MSG_LOAD\n"));
 
537
                rc = pSvc->loadServiceDLL ();
 
538
            } break;
 
539
 
 
540
            case SVC_MSG_UNLOAD:
 
541
            {
 
542
                LogFlowFunc(("SVC_MSG_UNLOAD\n"));
 
543
                if (pSvc->m_fntable.pfnUnload)
 
544
                {
 
545
                    pSvc->m_fntable.pfnUnload (pSvc->m_fntable.pvService);
 
546
                }
 
547
 
 
548
                pSvc->unloadServiceDLL ();
 
549
                fQuit = true;
 
550
            } break;
 
551
 
 
552
            case SVC_MSG_CONNECT:
 
553
            {
 
554
                HGCMMsgSvcConnect *pMsg = (HGCMMsgSvcConnect *)pMsgCore;
 
555
 
 
556
                LogFlowFunc(("SVC_MSG_CONNECT u32ClientId = %d\n", pMsg->u32ClientId));
 
557
 
 
558
                HGCMClient *pClient = (HGCMClient *)hgcmObjReference (pMsg->u32ClientId, HGCMOBJ_CLIENT);
 
559
 
 
560
                if (pClient)
 
561
                {
 
562
                    rc = pSvc->m_fntable.pfnConnect (pSvc->m_fntable.pvService, pMsg->u32ClientId, HGCM_CLIENT_DATA(pSvc, pClient));
 
563
 
 
564
                    hgcmObjDereference (pClient);
 
565
                }
 
566
                else
 
567
                {
 
568
                    rc = VERR_HGCM_INVALID_CLIENT_ID;
 
569
                }
 
570
            } break;
 
571
 
 
572
            case SVC_MSG_DISCONNECT:
 
573
            {
 
574
                HGCMMsgSvcDisconnect *pMsg = (HGCMMsgSvcDisconnect *)pMsgCore;
 
575
 
 
576
                LogFlowFunc(("SVC_MSG_DISCONNECT u32ClientId = %d\n", pMsg->u32ClientId));
 
577
 
 
578
                HGCMClient *pClient = (HGCMClient *)hgcmObjReference (pMsg->u32ClientId, HGCMOBJ_CLIENT);
 
579
 
 
580
                if (pClient)
 
581
                {
 
582
                    rc = pSvc->m_fntable.pfnDisconnect (pSvc->m_fntable.pvService, pMsg->u32ClientId, HGCM_CLIENT_DATA(pSvc, pClient));
 
583
 
 
584
                    hgcmObjDereference (pClient);
 
585
                }
 
586
                else
 
587
                {
 
588
                    rc = VERR_HGCM_INVALID_CLIENT_ID;
 
589
                }
 
590
            } break;
 
591
 
 
592
            case SVC_MSG_GUESTCALL:
 
593
            {
 
594
                HGCMMsgCall *pMsg = (HGCMMsgCall *)pMsgCore;
 
595
 
 
596
                LogFlowFunc(("SVC_MSG_GUESTCALL u32ClientId = %d, u32Function = %d, cParms = %d, paParms = %p\n",
 
597
                             pMsg->u32ClientId, pMsg->u32Function, pMsg->cParms, pMsg->paParms));
 
598
 
 
599
                HGCMClient *pClient = (HGCMClient *)hgcmObjReference (pMsg->u32ClientId, HGCMOBJ_CLIENT);
 
600
 
 
601
                if (pClient)
 
602
                {
 
603
                    pSvc->m_fntable.pfnCall (pSvc->m_fntable.pvService, (VBOXHGCMCALLHANDLE)pMsg, pMsg->u32ClientId, HGCM_CLIENT_DATA(pSvc, pClient), pMsg->u32Function, pMsg->cParms, pMsg->paParms);
 
604
 
 
605
                    hgcmObjDereference (pClient);
 
606
                }
 
607
                else
 
608
                {
 
609
                    rc = VERR_HGCM_INVALID_CLIENT_ID;
 
610
                }
 
611
            } break;
 
612
 
 
613
            case SVC_MSG_HOSTCALL:
 
614
            {
 
615
                HGCMMsgHostCallSvc *pMsg = (HGCMMsgHostCallSvc *)pMsgCore;
 
616
 
 
617
                LogFlowFunc(("SVC_MSG_HOSTCALL u32Function = %d, cParms = %d, paParms = %p\n", pMsg->u32Function, pMsg->cParms, pMsg->paParms));
 
618
 
 
619
                rc = pSvc->m_fntable.pfnHostCall (pSvc->m_fntable.pvService, pMsg->u32Function, pMsg->cParms, pMsg->paParms);
 
620
            } break;
 
621
 
 
622
            case SVC_MSG_LOADSTATE:
 
623
            {
 
624
                HGCMMsgLoadSaveStateClient *pMsg = (HGCMMsgLoadSaveStateClient *)pMsgCore;
 
625
 
 
626
                LogFlowFunc(("SVC_MSG_LOADSTATE\n"));
 
627
 
 
628
                HGCMClient *pClient = (HGCMClient *)hgcmObjReference (pMsg->u32ClientId, HGCMOBJ_CLIENT);
 
629
 
 
630
                if (pClient)
 
631
                {
 
632
                    if (pSvc->m_fntable.pfnLoadState)
 
633
                    {
 
634
                        rc = pSvc->m_fntable.pfnLoadState (pSvc->m_fntable.pvService, pMsg->u32ClientId, HGCM_CLIENT_DATA(pSvc, pClient), pMsg->pSSM);
 
635
                    }
 
636
 
 
637
                    hgcmObjDereference (pClient);
 
638
                }
 
639
                else
 
640
                {
 
641
                    rc = VERR_HGCM_INVALID_CLIENT_ID;
 
642
                }
 
643
            } break;
 
644
 
 
645
            case SVC_MSG_SAVESTATE:
 
646
            {
 
647
                HGCMMsgLoadSaveStateClient *pMsg = (HGCMMsgLoadSaveStateClient *)pMsgCore;
 
648
 
 
649
                LogFlowFunc(("SVC_MSG_SAVESTATE\n"));
 
650
 
 
651
                HGCMClient *pClient = (HGCMClient *)hgcmObjReference (pMsg->u32ClientId, HGCMOBJ_CLIENT);
 
652
 
 
653
                rc = VINF_SUCCESS;
 
654
 
 
655
                if (pClient)
 
656
                {
 
657
                    if (pSvc->m_fntable.pfnSaveState)
 
658
                    {
 
659
                        g_fSaveState = true;
 
660
                        rc = pSvc->m_fntable.pfnSaveState (pSvc->m_fntable.pvService, pMsg->u32ClientId, HGCM_CLIENT_DATA(pSvc, pClient), pMsg->pSSM);
 
661
                        g_fSaveState = false;
 
662
                    }
 
663
 
 
664
                    hgcmObjDereference (pClient);
 
665
                }
 
666
                else
 
667
                {
 
668
                    rc = VERR_HGCM_INVALID_CLIENT_ID;
 
669
                }
 
670
            } break;
 
671
 
 
672
            case SVC_MSG_REGEXT:
 
673
            {
 
674
                HGCMMsgSvcRegisterExtension *pMsg = (HGCMMsgSvcRegisterExtension *)pMsgCore;
 
675
 
 
676
                LogFlowFunc(("SVC_MSG_REGEXT handle = %p, pfn = %p\n", pMsg->handle, pMsg->pfnExtension));
 
677
 
 
678
                if (pSvc->m_hExtension)
 
679
                {
 
680
                    rc = VERR_NOT_SUPPORTED;
 
681
                }
 
682
                else
 
683
                {
 
684
                    if (pSvc->m_fntable.pfnRegisterExtension)
 
685
                    {
 
686
                        rc = pSvc->m_fntable.pfnRegisterExtension (pSvc->m_fntable.pvService, pMsg->pfnExtension, pMsg->pvExtension);
 
687
                    }
 
688
                    else
 
689
                    {
 
690
                        rc = VERR_NOT_SUPPORTED;
 
691
                    }
 
692
 
 
693
                    if (RT_SUCCESS(rc))
 
694
                    {
 
695
                        pSvc->m_hExtension = pMsg->handle;
 
696
                    }
 
697
                }
 
698
            } break;
 
699
 
 
700
            case SVC_MSG_UNREGEXT:
 
701
            {
 
702
                HGCMMsgSvcUnregisterExtension *pMsg = (HGCMMsgSvcUnregisterExtension *)pMsgCore;
 
703
 
 
704
                LogFlowFunc(("SVC_MSG_UNREGEXT handle = %p\n", pMsg->handle));
 
705
 
 
706
                if (pSvc->m_hExtension != pMsg->handle)
 
707
                {
 
708
                    rc = VERR_NOT_SUPPORTED;
 
709
                }
 
710
                else
 
711
                {
 
712
                    if (pSvc->m_fntable.pfnRegisterExtension)
 
713
                    {
 
714
                        rc = pSvc->m_fntable.pfnRegisterExtension (pSvc->m_fntable.pvService, NULL, NULL);
 
715
                    }
 
716
                    else
 
717
                    {
 
718
                        rc = VERR_NOT_SUPPORTED;
 
719
                    }
 
720
 
 
721
                    pSvc->m_hExtension = NULL;
 
722
                }
 
723
            } break;
 
724
 
 
725
            default:
 
726
            {
 
727
                AssertMsgFailed(("hgcmServiceThread::Unsupported message number %08X\n", u32MsgId));
 
728
                rc = VERR_NOT_SUPPORTED;
 
729
            } break;
 
730
        }
 
731
 
 
732
        if (u32MsgId != SVC_MSG_GUESTCALL)
 
733
        {
 
734
            /* For SVC_MSG_GUESTCALL the service calls the completion helper.
 
735
             * Other messages have to be completed here.
 
736
             */
 
737
            hgcmMsgComplete (pMsgCore, rc);
 
738
        }
 
739
    }
 
740
}
 
741
 
 
742
/* static */ DECLCALLBACK(void) HGCMService::svcHlpCallComplete (VBOXHGCMCALLHANDLE callHandle, int32_t rc)
 
743
{
 
744
   HGCMMsgCore *pMsgCore = (HGCMMsgCore *)callHandle;
 
745
 
 
746
   if (pMsgCore->MsgId () == SVC_MSG_GUESTCALL)
 
747
   {
 
748
       /* Only call the completion for these messages. The helper
 
749
        * is called by the service, and the service does not get
 
750
        * any other messages.
 
751
        */
 
752
       hgcmMsgComplete (pMsgCore, rc);
 
753
   }
 
754
   else
 
755
   {
 
756
       AssertFailed ();
 
757
   }
 
758
}
 
759
 
 
760
/* static */ DECLCALLBACK(void) HGCMService::svcHlpDisconnectClient (void *pvInstance, uint32_t u32ClientId)
 
761
{
 
762
     HGCMService *pService = static_cast <HGCMService *> (pvInstance);
 
763
 
 
764
     if (pService)
 
765
     {
 
766
         pService->DisconnectClient (u32ClientId, true);
 
767
     }
 
768
}
 
769
 
 
770
static DECLCALLBACK(void) hgcmMsgCompletionCallback (int32_t result, HGCMMsgCore *pMsgCore)
 
771
{
 
772
    /* Call the VMMDev port interface to issue IRQ notification. */
 
773
    HGCMMsgHeader *pMsgHdr = (HGCMMsgHeader *)pMsgCore;
 
774
 
 
775
    LogFlow(("MAIN::hgcmMsgCompletionCallback: message %p\n", pMsgCore));
 
776
 
 
777
    if (pMsgHdr->pHGCMPort && !g_fResetting)
 
778
    {
 
779
        pMsgHdr->pHGCMPort->pfnCompleted (pMsgHdr->pHGCMPort, g_fSaveState? VINF_HGCM_SAVE_STATE: result, pMsgHdr->pCmd);
 
780
    }
 
781
}
 
782
 
 
783
/*
 
784
 * The main HGCM methods of the service.
 
785
 */
 
786
 
 
787
int HGCMService::instanceCreate (const char *pszServiceLibrary, const char *pszServiceName)
 
788
{
 
789
    LogFlowFunc(("name %s, lib %s\n", pszServiceName, pszServiceLibrary));
 
790
 
 
791
    /* The maximum length of the thread name, allowed by the RT is 15. */
 
792
    char achThreadName[16];
 
793
 
 
794
    strncpy (achThreadName, pszServiceName, 15);
 
795
    achThreadName[15] = 0;
 
796
 
 
797
    int rc = hgcmThreadCreate (&m_thread, achThreadName, hgcmServiceThread, this);
 
798
 
 
799
    if (RT_SUCCESS(rc))
 
800
    {
 
801
        m_pszSvcName    = RTStrDup (pszServiceName);
 
802
        m_pszSvcLibrary = RTStrDup (pszServiceLibrary);
 
803
 
 
804
        if (!m_pszSvcName || !m_pszSvcLibrary)
 
805
        {
 
806
            RTStrFree (m_pszSvcLibrary);
 
807
            m_pszSvcLibrary = NULL;
 
808
 
 
809
            RTStrFree (m_pszSvcName);
 
810
            m_pszSvcName = NULL;
 
811
 
 
812
            rc = VERR_NO_MEMORY;
 
813
        }
 
814
        else
 
815
        {
 
816
            /* Initialize service helpers table. */
 
817
            m_svcHelpers.pfnCallComplete     = svcHlpCallComplete;
 
818
            m_svcHelpers.pvInstance          = this;
 
819
            m_svcHelpers.pfnDisconnectClient = svcHlpDisconnectClient;
 
820
 
 
821
            /* Execute the load request on the service thread. */
 
822
            HGCMMSGHANDLE hMsg;
 
823
            rc = hgcmMsgAlloc (m_thread, &hMsg, SVC_MSG_LOAD, hgcmMessageAllocSvc);
 
824
 
 
825
            if (RT_SUCCESS(rc))
 
826
            {
 
827
                rc = hgcmMsgSend (hMsg);
 
828
            }
 
829
        }
 
830
    }
 
831
 
 
832
    if (RT_FAILURE(rc))
 
833
    {
 
834
        instanceDestroy ();
 
835
    }
 
836
 
 
837
    LogFlowFunc(("rc = %Rrc\n", rc));
 
838
    return rc;
 
839
}
 
840
 
 
841
void HGCMService::instanceDestroy (void)
 
842
{
 
843
    LogFlowFunc(("%s\n", m_pszSvcName));
 
844
 
 
845
    HGCMMSGHANDLE hMsg;
 
846
    int rc = hgcmMsgAlloc (m_thread, &hMsg, SVC_MSG_UNLOAD, hgcmMessageAllocSvc);
 
847
 
 
848
    if (RT_SUCCESS(rc))
 
849
    {
 
850
        rc = hgcmMsgSend (hMsg);
 
851
 
 
852
        if (RT_SUCCESS(rc))
 
853
        {
 
854
            hgcmThreadWait (m_thread);
 
855
        }
 
856
    }
 
857
 
 
858
    RTStrFree (m_pszSvcLibrary);
 
859
    m_pszSvcLibrary = NULL;
 
860
 
 
861
    RTStrFree (m_pszSvcName);
 
862
    m_pszSvcName = NULL;
 
863
}
 
864
 
 
865
int HGCMService::saveClientState(uint32_t u32ClientId, PSSMHANDLE pSSM)
 
866
{
 
867
    LogFlowFunc(("%s\n", m_pszSvcName));
 
868
 
 
869
    HGCMMSGHANDLE hMsg;
 
870
    int rc = hgcmMsgAlloc (m_thread, &hMsg, SVC_MSG_SAVESTATE, hgcmMessageAllocSvc);
 
871
 
 
872
    if (RT_SUCCESS(rc))
 
873
    {
 
874
        HGCMMsgLoadSaveStateClient *pMsg = (HGCMMsgLoadSaveStateClient *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
 
875
        AssertRelease(pMsg);
 
876
 
 
877
        pMsg->u32ClientId = u32ClientId;
 
878
        pMsg->pSSM        = pSSM;
 
879
 
 
880
        hgcmObjDereference (pMsg);
 
881
 
 
882
        rc = hgcmMsgSend (hMsg);
 
883
    }
 
884
 
 
885
    LogFlowFunc(("rc = %Rrc\n", rc));
 
886
    return rc;
 
887
}
 
888
 
 
889
int HGCMService::loadClientState (uint32_t u32ClientId, PSSMHANDLE pSSM)
 
890
{
 
891
    LogFlowFunc(("%s\n", m_pszSvcName));
 
892
 
 
893
    HGCMMSGHANDLE hMsg;
 
894
    int rc = hgcmMsgAlloc (m_thread, &hMsg, SVC_MSG_LOADSTATE, hgcmMessageAllocSvc);
 
895
 
 
896
    if (RT_SUCCESS(rc))
 
897
    {
 
898
        HGCMMsgLoadSaveStateClient *pMsg = (HGCMMsgLoadSaveStateClient *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
 
899
 
 
900
        AssertRelease(pMsg);
 
901
 
 
902
        pMsg->u32ClientId = u32ClientId;
 
903
        pMsg->pSSM        = pSSM;
 
904
 
 
905
        hgcmObjDereference (pMsg);
 
906
 
 
907
        rc = hgcmMsgSend (hMsg);
 
908
    }
 
909
 
 
910
    LogFlowFunc(("rc = %Rrc\n", rc));
 
911
    return rc;
 
912
}
 
913
 
 
914
 
 
915
/** The method creates a service and references it.
 
916
 *
 
917
 * @param pszServiceLibrary  The library to be loaded.
 
918
 * @param pszServiceName     The name of the service.
 
919
 * @return VBox rc.
 
920
 * @thread main HGCM
 
921
 */
 
922
/* static */ int HGCMService::LoadService (const char *pszServiceLibrary, const char *pszServiceName)
 
923
{
 
924
    LogFlowFunc(("lib %s, name = %s\n", pszServiceLibrary, pszServiceName));
 
925
 
 
926
    /* Look at already loaded services to avoid double loading. */
 
927
 
 
928
    HGCMService *pSvc;
 
929
    int rc = HGCMService::ResolveService (&pSvc, pszServiceName);
 
930
 
 
931
    if (RT_SUCCESS(rc))
 
932
    {
 
933
        /* The service is already loaded. */
 
934
        pSvc->ReleaseService ();
 
935
        rc = VERR_HGCM_SERVICE_EXISTS;
 
936
    }
 
937
    else
 
938
    {
 
939
        /* Create the new service. */
 
940
        pSvc = new HGCMService ();
 
941
 
 
942
        if (!pSvc)
 
943
        {
 
944
            rc = VERR_NO_MEMORY;
 
945
        }
 
946
        else
 
947
        {
 
948
            /* Load the library and call the initialization entry point. */
 
949
            rc = pSvc->instanceCreate (pszServiceLibrary, pszServiceName);
 
950
 
 
951
            if (RT_SUCCESS(rc))
 
952
            {
 
953
                /* Insert the just created service to list for future references. */
 
954
                pSvc->m_pSvcNext = sm_pSvcListHead;
 
955
                pSvc->m_pSvcPrev = NULL;
 
956
 
 
957
                if (sm_pSvcListHead)
 
958
                {
 
959
                    sm_pSvcListHead->m_pSvcPrev = pSvc;
 
960
                }
 
961
                else
 
962
                {
 
963
                    sm_pSvcListTail = pSvc;
 
964
                }
 
965
 
 
966
                sm_pSvcListHead = pSvc;
 
967
 
 
968
                sm_cServices++;
 
969
 
 
970
                /* Reference the service (for first time) until it is unloaded on HGCM termination. */
 
971
                AssertRelease (pSvc->m_u32RefCnt == 0);
 
972
                pSvc->ReferenceService ();
 
973
 
 
974
                LogFlowFunc(("service %p\n", pSvc));
 
975
            }
 
976
        }
 
977
    }
 
978
 
 
979
    LogFlowFunc(("rc = %Rrc\n", rc));
 
980
    return rc;
 
981
}
 
982
 
 
983
/** The method unloads a service.
 
984
 *
 
985
 * @thread main HGCM
 
986
 */
 
987
void HGCMService::UnloadService (void)
 
988
{
 
989
    LogFlowFunc(("name = %s\n", m_pszSvcName));
 
990
 
 
991
    /* Remove the service from the list. */
 
992
    if (m_pSvcNext)
 
993
    {
 
994
        m_pSvcNext->m_pSvcPrev = m_pSvcPrev;
 
995
    }
 
996
    else
 
997
    {
 
998
        sm_pSvcListTail = m_pSvcPrev;
 
999
    }
 
1000
 
 
1001
    if (m_pSvcPrev)
 
1002
    {
 
1003
        m_pSvcPrev->m_pSvcNext = m_pSvcNext;
 
1004
    }
 
1005
    else
 
1006
    {
 
1007
        sm_pSvcListHead = m_pSvcNext;
 
1008
    }
 
1009
 
 
1010
    sm_cServices--;
 
1011
 
 
1012
    /* The service must be unloaded only if all clients were disconnected. */
 
1013
    LogFlowFunc(("m_u32RefCnt = %d\n", m_u32RefCnt));
 
1014
    AssertRelease (m_u32RefCnt == 1);
 
1015
 
 
1016
    /* Now the service can be released. */
 
1017
    ReleaseService ();
 
1018
}
 
1019
 
 
1020
/** The method unloads all services.
 
1021
 *
 
1022
 * @thread main HGCM
 
1023
 */
 
1024
/* static */ void HGCMService::UnloadAll (void)
 
1025
{
 
1026
    while (sm_pSvcListHead)
 
1027
    {
 
1028
        sm_pSvcListHead->UnloadService ();
 
1029
    }
 
1030
}
 
1031
 
 
1032
/** The method obtains a referenced pointer to the service with
 
1033
 *  specified name. The caller must call ReleaseService when
 
1034
 *  the pointer is no longer needed.
 
1035
 *
 
1036
 * @param ppSvc          Where to store the pointer to the service.
 
1037
 * @param pszServiceName The name of the service.
 
1038
 * @return VBox rc.
 
1039
 * @thread main HGCM
 
1040
 */
 
1041
/* static */ int HGCMService::ResolveService (HGCMService **ppSvc, const char *pszServiceName)
 
1042
{
 
1043
    LogFlowFunc(("ppSvc = %p name = %s\n",
 
1044
                 ppSvc, pszServiceName));
 
1045
 
 
1046
    if (!ppSvc || !pszServiceName)
 
1047
    {
 
1048
        return VERR_INVALID_PARAMETER;
 
1049
    }
 
1050
 
 
1051
    HGCMService *pSvc = sm_pSvcListHead;
 
1052
 
 
1053
    while (pSvc)
 
1054
    {
 
1055
        if (strcmp (pSvc->m_pszSvcName, pszServiceName) == 0)
 
1056
        {
 
1057
            break;
 
1058
        }
 
1059
 
 
1060
        pSvc = pSvc->m_pSvcNext;
 
1061
    }
 
1062
 
 
1063
    LogFlowFunc(("lookup in the list is %p\n", pSvc));
 
1064
 
 
1065
    if (pSvc == NULL)
 
1066
    {
 
1067
        *ppSvc = NULL;
 
1068
        return VERR_HGCM_SERVICE_NOT_FOUND;
 
1069
    }
 
1070
 
 
1071
    pSvc->ReferenceService ();
 
1072
 
 
1073
    *ppSvc = pSvc;
 
1074
 
 
1075
    return VINF_SUCCESS;
 
1076
}
 
1077
 
 
1078
/** The method increases reference counter.
 
1079
 *
 
1080
 * @thread main HGCM
 
1081
 */
 
1082
void HGCMService::ReferenceService (void)
 
1083
{
 
1084
    ASMAtomicIncU32 (&m_u32RefCnt);
 
1085
    LogFlowFunc(("[%s] m_u32RefCnt = %d\n", m_pszSvcName, m_u32RefCnt));
 
1086
}
 
1087
 
 
1088
/** The method dereferences a service and deletes it when no more refs.
 
1089
 *
 
1090
 * @thread main HGCM
 
1091
 */
 
1092
void HGCMService::ReleaseService (void)
 
1093
{
 
1094
    LogFlowFunc(("m_u32RefCnt = %d\n", m_u32RefCnt));
 
1095
    uint32_t u32RefCnt = ASMAtomicDecU32 (&m_u32RefCnt);
 
1096
    AssertRelease(u32RefCnt != ~0U);
 
1097
 
 
1098
    LogFlowFunc(("u32RefCnt = %d, name %s\n", u32RefCnt, m_pszSvcName));
 
1099
 
 
1100
    if (u32RefCnt == 0)
 
1101
    {
 
1102
        instanceDestroy ();
 
1103
        delete this;
 
1104
    }
 
1105
}
 
1106
 
 
1107
/** The method is called when the VM is being reset or terminated
 
1108
 *  and disconnects all clients from all services.
 
1109
 *
 
1110
 * @thread main HGCM
 
1111
 */
 
1112
/* static */ void HGCMService::Reset (void)
 
1113
{
 
1114
    g_fResetting = true;
 
1115
 
 
1116
    HGCMService *pSvc = sm_pSvcListHead;
 
1117
 
 
1118
    while (pSvc)
 
1119
    {
 
1120
        while (pSvc->m_cClients && pSvc->m_paClientIds)
 
1121
        {
 
1122
            LogFlowFunc(("handle %d\n", pSvc->m_paClientIds[0]));
 
1123
            pSvc->DisconnectClient (pSvc->m_paClientIds[0], false);
 
1124
        }
 
1125
 
 
1126
#ifdef VBOX_WITH_CRHGSMI
 
1127
        /* @todo: could this actually happen that the service is destroyed on ReleaseService? */
 
1128
        HGCMService *pNextSvc = pSvc->m_pSvcNext;
 
1129
        while (pSvc->m_cHandleAcquires)
 
1130
        {
 
1131
            pSvc->HandleReleased ();
 
1132
            pSvc->ReleaseService ();
 
1133
        }
 
1134
        pSvc = pNextSvc;
 
1135
#else
 
1136
        pSvc = pSvc->m_pSvcNext;
 
1137
#endif
 
1138
    }
 
1139
 
 
1140
    g_fResetting = false;
 
1141
}
 
1142
 
 
1143
/** The method saves the HGCM state.
 
1144
 *
 
1145
 * @param pSSM  The saved state context.
 
1146
 * @return VBox rc.
 
1147
 * @thread main HGCM
 
1148
 */
 
1149
/* static */ int HGCMService::SaveState (PSSMHANDLE pSSM)
 
1150
{
 
1151
    /* Save the current handle count and restore afterwards to avoid client id conflicts. */
 
1152
    int rc = SSMR3PutU32(pSSM, hgcmObjQueryHandleCount());
 
1153
    AssertRCReturn(rc, rc);
 
1154
 
 
1155
    LogFlowFunc(("%d services to be saved:\n", sm_cServices));
 
1156
 
 
1157
    /* Save number of services. */
 
1158
    rc = SSMR3PutU32(pSSM, sm_cServices);
 
1159
    AssertRCReturn(rc, rc);
 
1160
 
 
1161
    /* Save every service. */
 
1162
    HGCMService *pSvc = sm_pSvcListHead;
 
1163
 
 
1164
    while (pSvc)
 
1165
    {
 
1166
        LogFlowFunc(("Saving service [%s]\n", pSvc->m_pszSvcName));
 
1167
 
 
1168
        /* Save the length of the service name. */
 
1169
        rc = SSMR3PutU32(pSSM, (uint32_t) strlen(pSvc->m_pszSvcName) + 1);
 
1170
        AssertRCReturn(rc, rc);
 
1171
 
 
1172
        /* Save the name of the service. */
 
1173
        rc = SSMR3PutStrZ(pSSM, pSvc->m_pszSvcName);
 
1174
        AssertRCReturn(rc, rc);
 
1175
 
 
1176
        /* Save the number of clients. */
 
1177
        rc = SSMR3PutU32(pSSM, pSvc->m_cClients);
 
1178
        AssertRCReturn(rc, rc);
 
1179
 
 
1180
        /* Call the service for every client. Normally a service must not have
 
1181
         * a global state to be saved: only per client info is relevant.
 
1182
         * The global state of a service is configured during VM startup.
 
1183
         */
 
1184
        int i;
 
1185
 
 
1186
        for (i = 0; i < pSvc->m_cClients; i++)
 
1187
        {
 
1188
            uint32_t u32ClientId = pSvc->m_paClientIds[i];
 
1189
 
 
1190
            Log(("client id 0x%08X\n", u32ClientId));
 
1191
 
 
1192
            /* Save the client id. */
 
1193
            rc = SSMR3PutU32(pSSM, u32ClientId);
 
1194
            AssertRCReturn(rc, rc);
 
1195
 
 
1196
            /* Call the service, so the operation is executed by the service thread. */
 
1197
            rc = pSvc->saveClientState (u32ClientId, pSSM);
 
1198
            AssertRCReturn(rc, rc);
 
1199
        }
 
1200
 
 
1201
        pSvc = pSvc->m_pSvcNext;
 
1202
    }
 
1203
 
 
1204
    return VINF_SUCCESS;
 
1205
}
 
1206
 
 
1207
/** The method loads saved HGCM state.
 
1208
 *
 
1209
 * @param pSSM  The saved state context.
 
1210
 * @return VBox rc.
 
1211
 * @thread main HGCM
 
1212
 */
 
1213
/* static */ int HGCMService::LoadState (PSSMHANDLE pSSM)
 
1214
{
 
1215
    /* Restore handle count to avoid client id conflicts. */
 
1216
    uint32_t u32;
 
1217
 
 
1218
    int rc = SSMR3GetU32(pSSM, &u32);
 
1219
    AssertRCReturn(rc, rc);
 
1220
 
 
1221
    hgcmObjSetHandleCount(u32);
 
1222
 
 
1223
    /* Get the number of services. */
 
1224
    uint32_t cServices;
 
1225
 
 
1226
    rc = SSMR3GetU32(pSSM, &cServices);
 
1227
    AssertRCReturn(rc, rc);
 
1228
 
 
1229
    LogFlowFunc(("%d services to be restored:\n", cServices));
 
1230
 
 
1231
    while (cServices--)
 
1232
    {
 
1233
        /* Get the length of the service name. */
 
1234
        rc = SSMR3GetU32(pSSM, &u32);
 
1235
        AssertRCReturn(rc, rc);
 
1236
        AssertReturn(u32 <= VBOX_HGCM_SVC_NAME_MAX_BYTES, VERR_SSM_UNEXPECTED_DATA);
 
1237
 
 
1238
        char *pszServiceName = (char *)alloca (u32);
 
1239
 
 
1240
        /* Get the service name. */
 
1241
        rc = SSMR3GetStrZ(pSSM, pszServiceName, u32);
 
1242
        AssertRCReturn(rc, rc);
 
1243
 
 
1244
        LogRel(("HGCM: restoring [%s]\n", pszServiceName));
 
1245
 
 
1246
        /* Resolve the service instance. */
 
1247
        HGCMService *pSvc;
 
1248
        rc = ResolveService (&pSvc, pszServiceName);
 
1249
        AssertLogRelMsgReturn(pSvc, ("rc=%Rrc, %s\n", rc, pszServiceName), VERR_SSM_UNEXPECTED_DATA);
 
1250
 
 
1251
        /* Get the number of clients. */
 
1252
        uint32_t cClients;
 
1253
        rc = SSMR3GetU32(pSSM, &cClients);
 
1254
        if (RT_FAILURE(rc))
 
1255
        {
 
1256
            pSvc->ReleaseService ();
 
1257
            AssertFailed();
 
1258
            return rc;
 
1259
        }
 
1260
 
 
1261
        while (cClients--)
 
1262
        {
 
1263
            /* Get the client id. */
 
1264
            uint32_t u32ClientId;
 
1265
            rc = SSMR3GetU32(pSSM, &u32ClientId);
 
1266
            if (RT_FAILURE(rc))
 
1267
            {
 
1268
                pSvc->ReleaseService ();
 
1269
                AssertFailed();
 
1270
                return rc;
 
1271
            }
 
1272
 
 
1273
            /* Connect the client. */
 
1274
            rc = pSvc->CreateAndConnectClient (NULL, u32ClientId);
 
1275
            if (RT_FAILURE(rc))
 
1276
            {
 
1277
                pSvc->ReleaseService ();
 
1278
                AssertLogRelMsgFailed(("rc=%Rrc %s\n", rc, pszServiceName));
 
1279
                return rc;
 
1280
            }
 
1281
 
 
1282
            /* Call the service, so the operation is executed by the service thread. */
 
1283
            rc = pSvc->loadClientState (u32ClientId, pSSM);
 
1284
            if (RT_FAILURE(rc))
 
1285
            {
 
1286
                pSvc->ReleaseService ();
 
1287
                AssertLogRelMsgFailed(("rc=%Rrc %s\n", rc, pszServiceName));
 
1288
                return rc;
 
1289
            }
 
1290
        }
 
1291
 
 
1292
        pSvc->ReleaseService ();
 
1293
    }
 
1294
 
 
1295
    return VINF_SUCCESS;
 
1296
}
 
1297
 
 
1298
/* Create a new client instance and connect it to the service.
 
1299
 *
 
1300
 * @param pu32ClientIdOut If not NULL, then the method must generate a new handle for the client.
 
1301
 *                        If NULL, use the given 'u32ClientIdIn' handle.
 
1302
 * @param u32ClientIdIn   The handle for the client, when 'pu32ClientIdOut' is NULL.
 
1303
 * @return VBox rc.
 
1304
 */
 
1305
int HGCMService::CreateAndConnectClient (uint32_t *pu32ClientIdOut, uint32_t u32ClientIdIn)
 
1306
{
 
1307
    LogFlowFunc(("pu32ClientIdOut = %p, u32ClientIdIn = %d\n", pu32ClientIdOut, u32ClientIdIn));
 
1308
 
 
1309
    /* Allocate a client information structure. */
 
1310
    HGCMClient *pClient = new HGCMClient ();
 
1311
 
 
1312
    if (!pClient)
 
1313
    {
 
1314
        LogWarningFunc(("Could not allocate HGCMClient!!!\n"));
 
1315
        return VERR_NO_MEMORY;
 
1316
    }
 
1317
 
 
1318
    uint32_t handle;
 
1319
 
 
1320
    if (pu32ClientIdOut != NULL)
 
1321
    {
 
1322
        handle = hgcmObjGenerateHandle (pClient);
 
1323
    }
 
1324
    else
 
1325
    {
 
1326
        handle = hgcmObjAssignHandle (pClient, u32ClientIdIn);
 
1327
    }
 
1328
 
 
1329
    LogFlowFunc(("client id = %d\n", handle));
 
1330
 
 
1331
    AssertRelease(handle);
 
1332
 
 
1333
    /* Initialize the HGCM part of the client. */
 
1334
    int rc = pClient->Init (this);
 
1335
 
 
1336
    if (RT_SUCCESS(rc))
 
1337
    {
 
1338
        /* Call the service. */
 
1339
        HGCMMSGHANDLE hMsg;
 
1340
 
 
1341
        rc = hgcmMsgAlloc (m_thread, &hMsg, SVC_MSG_CONNECT, hgcmMessageAllocSvc);
 
1342
 
 
1343
        if (RT_SUCCESS(rc))
 
1344
        {
 
1345
            HGCMMsgSvcConnect *pMsg = (HGCMMsgSvcConnect *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
 
1346
            AssertRelease(pMsg);
 
1347
 
 
1348
            pMsg->u32ClientId = handle;
 
1349
 
 
1350
            hgcmObjDereference (pMsg);
 
1351
 
 
1352
            rc = hgcmMsgSend (hMsg);
 
1353
 
 
1354
            if (RT_SUCCESS(rc))
 
1355
            {
 
1356
                /* Add the client Id to the array. */
 
1357
                if (m_cClients == m_cClientsAllocated)
 
1358
                {
 
1359
                    m_paClientIds = (uint32_t *)RTMemRealloc (m_paClientIds, (m_cClientsAllocated + 64) * sizeof (m_paClientIds[0]));
 
1360
                    Assert(m_paClientIds);
 
1361
                    m_cClientsAllocated += 64;
 
1362
                }
 
1363
 
 
1364
                m_paClientIds[m_cClients] = handle;
 
1365
                m_cClients++;
 
1366
            }
 
1367
        }
 
1368
    }
 
1369
 
 
1370
    if (RT_FAILURE(rc))
 
1371
    {
 
1372
        hgcmObjDeleteHandle (handle);
 
1373
    }
 
1374
    else
 
1375
    {
 
1376
        if (pu32ClientIdOut != NULL)
 
1377
        {
 
1378
            *pu32ClientIdOut = handle;
 
1379
        }
 
1380
 
 
1381
        ReferenceService ();
 
1382
    }
 
1383
 
 
1384
    LogFlowFunc(("rc = %Rrc\n", rc));
 
1385
    return rc;
 
1386
}
 
1387
 
 
1388
/* Disconnect the client from the service and delete the client handle.
 
1389
 *
 
1390
 * @param u32ClientId  The handle of the client.
 
1391
 * @return VBox rc.
 
1392
 */
 
1393
int HGCMService::DisconnectClient (uint32_t u32ClientId, bool fFromService)
 
1394
{
 
1395
    int rc = VINF_SUCCESS;
 
1396
 
 
1397
    LogFlowFunc(("client id = %d, fFromService = %d\n", u32ClientId, fFromService));
 
1398
 
 
1399
    if (!fFromService)
 
1400
    {
 
1401
        /* Call the service. */
 
1402
        HGCMMSGHANDLE hMsg;
 
1403
 
 
1404
        rc = hgcmMsgAlloc (m_thread, &hMsg, SVC_MSG_DISCONNECT, hgcmMessageAllocSvc);
 
1405
 
 
1406
        if (RT_SUCCESS(rc))
 
1407
        {
 
1408
            HGCMMsgSvcDisconnect *pMsg = (HGCMMsgSvcDisconnect *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
 
1409
            AssertRelease(pMsg);
 
1410
 
 
1411
            pMsg->u32ClientId = u32ClientId;
 
1412
 
 
1413
            hgcmObjDereference (pMsg);
 
1414
 
 
1415
            rc = hgcmMsgSend (hMsg);
 
1416
        }
 
1417
        else
 
1418
        {
 
1419
            LogRel(("(%d, %d) [%s] hgcmMsgAlloc(%p, SVC_MSG_DISCONNECT) failed %Rrc\n",
 
1420
                    u32ClientId, fFromService, RT_VALID_PTR(m_pszSvcName)? m_pszSvcName: "", m_thread, rc));
 
1421
        }
 
1422
    }
 
1423
 
 
1424
    /* Remove the client id from the array in any case, rc does not matter. */
 
1425
    int i;
 
1426
 
 
1427
    for (i = 0; i < m_cClients; i++)
 
1428
    {
 
1429
        if (m_paClientIds[i] == u32ClientId)
 
1430
        {
 
1431
            m_cClients--;
 
1432
 
 
1433
            if (m_cClients > i)
 
1434
            {
 
1435
                memmove (&m_paClientIds[i], &m_paClientIds[i + 1], sizeof (m_paClientIds[0]) * (m_cClients - i));
 
1436
            }
 
1437
 
 
1438
            /* Delete the client handle. */
 
1439
            hgcmObjDeleteHandle (u32ClientId);
 
1440
 
 
1441
            /* The service must be released. */
 
1442
            ReleaseService ();
 
1443
 
 
1444
            break;
 
1445
        }
 
1446
    }
 
1447
 
 
1448
    LogFlowFunc(("rc = %Rrc\n", rc));
 
1449
    return rc;
 
1450
}
 
1451
 
 
1452
int HGCMService::RegisterExtension (HGCMSVCEXTHANDLE handle,
 
1453
                                    PFNHGCMSVCEXT pfnExtension,
 
1454
                                    void *pvExtension)
 
1455
{
 
1456
    LogFlowFunc(("%s\n", handle->pszServiceName));
 
1457
 
 
1458
    /* Forward the message to the service thread. */
 
1459
    HGCMMSGHANDLE hMsg = 0;
 
1460
    int rc = hgcmMsgAlloc (m_thread, &hMsg, SVC_MSG_REGEXT, hgcmMessageAllocSvc);
 
1461
 
 
1462
    if (RT_SUCCESS(rc))
 
1463
    {
 
1464
        HGCMMsgSvcRegisterExtension *pMsg = (HGCMMsgSvcRegisterExtension *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
 
1465
        AssertRelease(pMsg);
 
1466
 
 
1467
        pMsg->handle       = handle;
 
1468
        pMsg->pfnExtension = pfnExtension;
 
1469
        pMsg->pvExtension  = pvExtension;
 
1470
 
 
1471
        hgcmObjDereference (pMsg);
 
1472
 
 
1473
        rc = hgcmMsgSend (hMsg);
 
1474
    }
 
1475
 
 
1476
    LogFlowFunc(("rc = %Rrc\n", rc));
 
1477
    return rc;
 
1478
}
 
1479
 
 
1480
void HGCMService::UnregisterExtension (HGCMSVCEXTHANDLE handle)
 
1481
{
 
1482
    /* Forward the message to the service thread. */
 
1483
    HGCMMSGHANDLE hMsg = 0;
 
1484
    int rc = hgcmMsgAlloc (m_thread, &hMsg, SVC_MSG_UNREGEXT, hgcmMessageAllocSvc);
 
1485
 
 
1486
    if (RT_SUCCESS(rc))
 
1487
    {
 
1488
        HGCMMsgSvcUnregisterExtension *pMsg = (HGCMMsgSvcUnregisterExtension *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
 
1489
        AssertRelease(pMsg);
 
1490
 
 
1491
        pMsg->handle = handle;
 
1492
 
 
1493
        hgcmObjDereference (pMsg);
 
1494
 
 
1495
        rc = hgcmMsgSend (hMsg);
 
1496
    }
 
1497
 
 
1498
    LogFlowFunc(("rc = %Rrc\n", rc));
 
1499
}
 
1500
 
 
1501
/* Perform a guest call to the service.
 
1502
 *
 
1503
 * @param pHGCMPort      The port to be used for completion confirmation.
 
1504
 * @param pCmd           The VBox HGCM context.
 
1505
 * @param u32ClientId    The client handle to be disconnected and deleted.
 
1506
 * @param u32Function    The function number.
 
1507
 * @param cParms         Number of parameters.
 
1508
 * @param paParms        Pointer to array of parameters.
 
1509
 * @return VBox rc.
 
1510
 */
 
1511
int HGCMService::GuestCall (PPDMIHGCMPORT pHGCMPort, PVBOXHGCMCMD pCmd, uint32_t u32ClientId, uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM paParms[])
 
1512
{
 
1513
    HGCMMSGHANDLE hMsg = 0;
 
1514
 
 
1515
    LogFlow(("MAIN::HGCMService::Call\n"));
 
1516
 
 
1517
    int rc = hgcmMsgAlloc (m_thread, &hMsg, SVC_MSG_GUESTCALL, hgcmMessageAllocSvc);
 
1518
 
 
1519
    if (RT_SUCCESS(rc))
 
1520
    {
 
1521
        HGCMMsgCall *pMsg = (HGCMMsgCall *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
 
1522
 
 
1523
        AssertRelease(pMsg);
 
1524
 
 
1525
        pMsg->pCmd      = pCmd;
 
1526
        pMsg->pHGCMPort = pHGCMPort;
 
1527
 
 
1528
        pMsg->u32ClientId = u32ClientId;
 
1529
        pMsg->u32Function = u32Function;
 
1530
        pMsg->cParms      = cParms;
 
1531
        pMsg->paParms     = paParms;
 
1532
 
 
1533
        hgcmObjDereference (pMsg);
 
1534
 
 
1535
        rc = hgcmMsgPost (hMsg, hgcmMsgCompletionCallback);
 
1536
    }
 
1537
    else
 
1538
    {
 
1539
        Log(("MAIN::HGCMService::Call: Message allocation failed: %Rrc\n", rc));
 
1540
    }
 
1541
 
 
1542
    LogFlowFunc(("rc = %Rrc\n", rc));
 
1543
    return rc;
 
1544
}
 
1545
 
 
1546
/* Perform a host call the service.
 
1547
 *
 
1548
 * @param u32Function    The function number.
 
1549
 * @param cParms         Number of parameters.
 
1550
 * @param paParms        Pointer to array of parameters.
 
1551
 * @return VBox rc.
 
1552
 */
 
1553
int HGCMService::HostCall (uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM *paParms)
 
1554
{
 
1555
    LogFlowFunc(("%s u32Function = %d, cParms = %d, paParms = %p\n",
 
1556
                 m_pszSvcName, u32Function, cParms, paParms));
 
1557
 
 
1558
    HGCMMSGHANDLE hMsg = 0;
 
1559
    int rc = hgcmMsgAlloc (m_thread, &hMsg, SVC_MSG_HOSTCALL, hgcmMessageAllocSvc);
 
1560
 
 
1561
    if (RT_SUCCESS(rc))
 
1562
    {
 
1563
        HGCMMsgHostCallSvc *pMsg = (HGCMMsgHostCallSvc *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
 
1564
        AssertRelease(pMsg);
 
1565
 
 
1566
        pMsg->u32Function      = u32Function;
 
1567
        pMsg->cParms           = cParms;
 
1568
        pMsg->paParms          = paParms;
 
1569
 
 
1570
        hgcmObjDereference (pMsg);
 
1571
 
 
1572
        rc = hgcmMsgSend (hMsg);
 
1573
    }
 
1574
 
 
1575
    LogFlowFunc(("rc = %Rrc\n", rc));
 
1576
    return rc;
 
1577
}
 
1578
 
 
1579
#ifdef VBOX_WITH_CRHGSMI
 
1580
static DECLCALLBACK(void) hgcmMsgFastCallCompletionCallback (int32_t result, HGCMMsgCore *pMsgCore)
 
1581
{
 
1582
    /* Call the VMMDev port interface to issue IRQ notification. */
 
1583
    LogFlow(("MAIN::hgcmMsgFastCallCompletionCallback: message %p\n", pMsgCore));
 
1584
 
 
1585
    HGCMMsgHostFastCallAsyncSvc *pMsg = (HGCMMsgHostFastCallAsyncSvc *)pMsgCore;
 
1586
    if (pMsg->pfnCompletion)
 
1587
    {
 
1588
        pMsg->pfnCompletion (result, pMsg->u32Function, &pMsg->Param, pMsg->pvCompletion);
 
1589
    }
 
1590
}
 
1591
 
 
1592
int HGCMService::HandleAcquired()
 
1593
{
 
1594
    ++m_cHandleAcquires;
 
1595
    return VINF_SUCCESS;
 
1596
}
 
1597
 
 
1598
int HGCMService::HandleReleased()
 
1599
{
 
1600
    Assert(m_cHandleAcquires);
 
1601
    if (m_cHandleAcquires)
 
1602
    {
 
1603
        --m_cHandleAcquires;
 
1604
        return VINF_SUCCESS;
 
1605
    }
 
1606
    return VERR_INVALID_STATE;
 
1607
}
 
1608
 
 
1609
int HGCMService::HostFastCallAsync (uint32_t u32Function, VBOXHGCMSVCPARM *pParm, PHGCMHOSTFASTCALLCB pfnCompletion, void *pvCompletion)
 
1610
{
 
1611
    LogFlowFunc(("%s u32Function = %d, pParm = %p\n",
 
1612
                 m_pszSvcName, u32Function, pParm));
 
1613
 
 
1614
    HGCMMSGHANDLE hMsg = 0;
 
1615
    int rc = hgcmMsgAlloc (m_thread, &hMsg, SVC_MSG_HOSTFASTCALLASYNC, hgcmMessageAllocSvc);
 
1616
 
 
1617
    if (RT_SUCCESS(rc))
 
1618
    {
 
1619
        HGCMMsgHostFastCallAsyncSvc *pMsg = (HGCMMsgHostFastCallAsyncSvc *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
 
1620
        AssertRelease(pMsg);
 
1621
 
 
1622
        pMsg->u32Function      = u32Function;
 
1623
        pMsg->Param = *pParm;
 
1624
        pMsg->pfnCompletion = pfnCompletion;
 
1625
        pMsg->pvCompletion = pvCompletion;
 
1626
 
 
1627
        hgcmObjDereference (pMsg);
 
1628
 
 
1629
        rc = hgcmMsgPost(hMsg, hgcmMsgFastCallCompletionCallback);
 
1630
    }
 
1631
 
 
1632
    LogFlowFunc(("rc = %Rrc\n", rc));
 
1633
    return rc;
 
1634
}
 
1635
#endif
 
1636
 
 
1637
/*
 
1638
 * Main HGCM thread that manages services.
 
1639
 */
 
1640
 
 
1641
/* Messages processed by the main HGCM thread. */
 
1642
#define HGCM_MSG_CONNECT    (10)  /* Connect a client to a service. */
 
1643
#define HGCM_MSG_DISCONNECT (11)  /* Disconnect the specified client id. */
 
1644
#define HGCM_MSG_LOAD       (12)  /* Load the service. */
 
1645
#define HGCM_MSG_HOSTCALL   (13)  /* Call the service. */
 
1646
#define HGCM_MSG_LOADSTATE  (14)  /* Load saved state for the specified service. */
 
1647
#define HGCM_MSG_SAVESTATE  (15)  /* Save state for the specified service. */
 
1648
#define HGCM_MSG_RESET      (16)  /* Disconnect all clients from the specified service. */
 
1649
#define HGCM_MSG_QUIT       (17)  /* Unload all services and terminate the thread. */
 
1650
#define HGCM_MSG_REGEXT     (18)  /* Register a service extension. */
 
1651
#define HGCM_MSG_UNREGEXT   (19)  /* Unregister a service extension. */
 
1652
#ifdef VBOX_WITH_CRHGSMI
 
1653
# define HGCM_MSG_SVCAQUIRE  (30)  /* Acquire a service handle (for fast host calls) */
 
1654
# define HGCM_MSG_SVCRELEASE (31)  /* Release a service */
 
1655
#endif
 
1656
 
 
1657
class HGCMMsgMainConnect: public HGCMMsgHeader
 
1658
{
 
1659
    public:
 
1660
        /* Service name. */
 
1661
        const char *pszServiceName;
 
1662
        /* Where to store the client handle. */
 
1663
        uint32_t *pu32ClientId;
 
1664
};
 
1665
 
 
1666
class HGCMMsgMainDisconnect: public HGCMMsgHeader
 
1667
{
 
1668
    public:
 
1669
        /* Handle of the client to be disconnected. */
 
1670
        uint32_t u32ClientId;
 
1671
};
 
1672
 
 
1673
class HGCMMsgMainLoad: public HGCMMsgCore
 
1674
{
 
1675
    public:
 
1676
        /* Name of the library to be loaded. */
 
1677
        const char *pszServiceLibrary;
 
1678
        /* Name to be assigned to the service. */
 
1679
        const char *pszServiceName;
 
1680
};
 
1681
 
 
1682
class HGCMMsgMainHostCall: public HGCMMsgCore
 
1683
{
 
1684
    public:
 
1685
        /* Which service to call. */
 
1686
        const char *pszServiceName;
 
1687
        /* Function number. */
 
1688
        uint32_t u32Function;
 
1689
        /* Number of the function parameters. */
 
1690
        uint32_t cParms;
 
1691
        /* Pointer to array of the function parameters. */
 
1692
        VBOXHGCMSVCPARM *paParms;
 
1693
};
 
1694
 
 
1695
class HGCMMsgMainLoadSaveState: public HGCMMsgCore
 
1696
{
 
1697
    public:
 
1698
        /* SSM context. */
 
1699
        PSSMHANDLE pSSM;
 
1700
};
 
1701
 
 
1702
class HGCMMsgMainReset: public HGCMMsgCore
 
1703
{
 
1704
};
 
1705
 
 
1706
class HGCMMsgMainQuit: public HGCMMsgCore
 
1707
{
 
1708
};
 
1709
 
 
1710
class HGCMMsgMainRegisterExtension: public HGCMMsgCore
 
1711
{
 
1712
    public:
 
1713
        /* Returned handle to be used in HGCMMsgMainUnregisterExtension. */
 
1714
        HGCMSVCEXTHANDLE *pHandle;
 
1715
        /* Name of the service. */
 
1716
        const char *pszServiceName;
 
1717
        /* The extension entry point. */
 
1718
        PFNHGCMSVCEXT pfnExtension;
 
1719
        /* The extension pointer. */
 
1720
        void *pvExtension;
 
1721
};
 
1722
 
 
1723
class HGCMMsgMainUnregisterExtension: public HGCMMsgCore
 
1724
{
 
1725
    public:
 
1726
        /* Handle of the registered extension. */
 
1727
        HGCMSVCEXTHANDLE handle;
 
1728
};
 
1729
 
 
1730
#ifdef VBOX_WITH_CRHGSMI
 
1731
class HGCMMsgMainSvcAcquire: public HGCMMsgCore
 
1732
{
 
1733
    public:
 
1734
        /* Which service to call. */
 
1735
        const char *pszServiceName;
 
1736
        /* Returned service. */
 
1737
        HGCMService *pService;
 
1738
};
 
1739
 
 
1740
class HGCMMsgMainSvcRelease: public HGCMMsgCore
 
1741
{
 
1742
    public:
 
1743
        /* Svc . */
 
1744
        HGCMService *pService;
 
1745
};
 
1746
#endif
 
1747
 
 
1748
 
 
1749
static HGCMMsgCore *hgcmMainMessageAlloc (uint32_t u32MsgId)
 
1750
{
 
1751
    switch (u32MsgId)
 
1752
    {
 
1753
        case HGCM_MSG_CONNECT:    return new HGCMMsgMainConnect ();
 
1754
        case HGCM_MSG_DISCONNECT: return new HGCMMsgMainDisconnect ();
 
1755
        case HGCM_MSG_LOAD:       return new HGCMMsgMainLoad ();
 
1756
        case HGCM_MSG_HOSTCALL:   return new HGCMMsgMainHostCall ();
 
1757
        case HGCM_MSG_LOADSTATE:
 
1758
        case HGCM_MSG_SAVESTATE:  return new HGCMMsgMainLoadSaveState ();
 
1759
        case HGCM_MSG_RESET:      return new HGCMMsgMainReset ();
 
1760
        case HGCM_MSG_QUIT:       return new HGCMMsgMainQuit ();
 
1761
        case HGCM_MSG_REGEXT:     return new HGCMMsgMainRegisterExtension ();
 
1762
        case HGCM_MSG_UNREGEXT:   return new HGCMMsgMainUnregisterExtension ();
 
1763
#ifdef VBOX_WITH_CRHGSMI
 
1764
        case HGCM_MSG_SVCAQUIRE: return new HGCMMsgMainSvcAcquire();
 
1765
        case HGCM_MSG_SVCRELEASE: return new HGCMMsgMainSvcRelease();
 
1766
#endif
 
1767
 
 
1768
        default:
 
1769
            AssertReleaseMsgFailed(("Msg id = %08X\n", u32MsgId));
 
1770
    }
 
1771
 
 
1772
    return NULL;
 
1773
}
 
1774
 
 
1775
 
 
1776
/* The main HGCM thread handler. */
 
1777
static DECLCALLBACK(void) hgcmThread (HGCMTHREADHANDLE ThreadHandle, void *pvUser)
 
1778
{
 
1779
    LogFlowFunc(("ThreadHandle = %p, pvUser = %p\n",
 
1780
                 ThreadHandle, pvUser));
 
1781
 
 
1782
    NOREF(pvUser);
 
1783
 
 
1784
    bool fQuit = false;
 
1785
 
 
1786
    while (!fQuit)
 
1787
    {
 
1788
        HGCMMsgCore *pMsgCore;
 
1789
        int rc = hgcmMsgGet (ThreadHandle, &pMsgCore);
 
1790
 
 
1791
        if (RT_FAILURE(rc))
 
1792
        {
 
1793
            /* The error means some serious unrecoverable problem in the hgcmMsg/hgcmThread layer. */
 
1794
            AssertMsgFailed (("%Rrc\n", rc));
 
1795
            break;
 
1796
        }
 
1797
 
 
1798
        uint32_t u32MsgId = pMsgCore->MsgId ();
 
1799
 
 
1800
        switch (u32MsgId)
 
1801
        {
 
1802
            case HGCM_MSG_CONNECT:
 
1803
            {
 
1804
                HGCMMsgMainConnect *pMsg = (HGCMMsgMainConnect *)pMsgCore;
 
1805
 
 
1806
                LogFlowFunc(("HGCM_MSG_CONNECT pszServiceName %s, pu32ClientId %p\n",
 
1807
                             pMsg->pszServiceName, pMsg->pu32ClientId));
 
1808
 
 
1809
                /* Resolve the service name to the pointer to service instance.
 
1810
                 */
 
1811
                HGCMService *pService;
 
1812
                rc = HGCMService::ResolveService (&pService, pMsg->pszServiceName);
 
1813
 
 
1814
                if (RT_SUCCESS(rc))
 
1815
                {
 
1816
                    /* Call the service instance method. */
 
1817
                    rc = pService->CreateAndConnectClient (pMsg->pu32ClientId, 0);
 
1818
 
 
1819
                    /* Release the service after resolve. */
 
1820
                    pService->ReleaseService ();
 
1821
                }
 
1822
            } break;
 
1823
 
 
1824
            case HGCM_MSG_DISCONNECT:
 
1825
            {
 
1826
                HGCMMsgMainDisconnect *pMsg = (HGCMMsgMainDisconnect *)pMsgCore;
 
1827
 
 
1828
                LogFlowFunc(("HGCM_MSG_DISCONNECT u32ClientId = %d\n",
 
1829
                             pMsg->u32ClientId));
 
1830
 
 
1831
                HGCMClient *pClient = (HGCMClient *)hgcmObjReference (pMsg->u32ClientId, HGCMOBJ_CLIENT);
 
1832
 
 
1833
                if (!pClient)
 
1834
                {
 
1835
                    rc = VERR_HGCM_INVALID_CLIENT_ID;
 
1836
                    break;
 
1837
                }
 
1838
 
 
1839
                /* The service the client belongs to. */
 
1840
                HGCMService *pService = pClient->pService;
 
1841
 
 
1842
                /* Call the service instance to disconnect the client. */
 
1843
                rc = pService->DisconnectClient (pMsg->u32ClientId, false);
 
1844
 
 
1845
                hgcmObjDereference (pClient);
 
1846
            } break;
 
1847
 
 
1848
            case HGCM_MSG_LOAD:
 
1849
            {
 
1850
                HGCMMsgMainLoad *pMsg = (HGCMMsgMainLoad *)pMsgCore;
 
1851
 
 
1852
                LogFlowFunc(("HGCM_MSG_LOAD pszServiceName = %s, pMsg->pszServiceLibrary = %s\n",
 
1853
                             pMsg->pszServiceName, pMsg->pszServiceLibrary));
 
1854
 
 
1855
                rc = HGCMService::LoadService (pMsg->pszServiceLibrary, pMsg->pszServiceName);
 
1856
            } break;
 
1857
 
 
1858
            case HGCM_MSG_HOSTCALL:
 
1859
            {
 
1860
                HGCMMsgMainHostCall *pMsg = (HGCMMsgMainHostCall *)pMsgCore;
 
1861
 
 
1862
                LogFlowFunc(("HGCM_MSG_HOSTCALL pszServiceName %s, u32Function %d, cParms %d, paParms %p\n",
 
1863
                             pMsg->pszServiceName, pMsg->u32Function, pMsg->cParms, pMsg->paParms));
 
1864
 
 
1865
                /* Resolve the service name to the pointer to service instance. */
 
1866
                HGCMService *pService;
 
1867
                rc = HGCMService::ResolveService (&pService, pMsg->pszServiceName);
 
1868
 
 
1869
                if (RT_SUCCESS(rc))
 
1870
                {
 
1871
                    rc = pService->HostCall (pMsg->u32Function, pMsg->cParms, pMsg->paParms);
 
1872
 
 
1873
                    pService->ReleaseService ();
 
1874
                }
 
1875
            } break;
 
1876
 
 
1877
#ifdef VBOX_WITH_CRHGSMI
 
1878
            case HGCM_MSG_SVCAQUIRE:
 
1879
            {
 
1880
                HGCMMsgMainSvcAcquire *pMsg = (HGCMMsgMainSvcAcquire *)pMsgCore;
 
1881
 
 
1882
                LogFlowFunc(("HGCM_MSG_SVCAQUIRE pszServiceName %s\n", pMsg->pszServiceName));
 
1883
 
 
1884
                /* Resolve the service name to the pointer to service instance. */
 
1885
                HGCMService *pService;
 
1886
                rc = HGCMService::ResolveService (&pService, pMsg->pszServiceName);
 
1887
                if (RT_SUCCESS(rc))
 
1888
                {
 
1889
                    rc = pService->HandleAcquired ();
 
1890
                    if (RT_SUCCESS(rc))
 
1891
                    {
 
1892
                        pMsg->pService = pService;
 
1893
                    }
 
1894
                    else
 
1895
                    {
 
1896
                        pService->ReleaseService ();
 
1897
                    }
 
1898
                }
 
1899
            } break;
 
1900
 
 
1901
            case HGCM_MSG_SVCRELEASE:
 
1902
            {
 
1903
                HGCMMsgMainSvcRelease *pMsg = (HGCMMsgMainSvcRelease *)pMsgCore;
 
1904
 
 
1905
                LogFlowFunc(("HGCM_MSG_SVCARELEASE pService %p\n", pMsg->pService));
 
1906
 
 
1907
                /* Resolve the service name to the pointer to service instance. */
 
1908
 
 
1909
                rc = pMsg->pService->HandleReleased ();
 
1910
                if (RT_SUCCESS(rc))
 
1911
                {
 
1912
                    pMsg->pService->ReleaseService ();
 
1913
                }
 
1914
            } break;
 
1915
#endif
 
1916
 
 
1917
            case HGCM_MSG_RESET:
 
1918
            {
 
1919
                LogFlowFunc(("HGCM_MSG_RESET\n"));
 
1920
 
 
1921
                HGCMService::Reset ();
 
1922
            } break;
 
1923
 
 
1924
            case HGCM_MSG_LOADSTATE:
 
1925
            {
 
1926
                HGCMMsgMainLoadSaveState *pMsg = (HGCMMsgMainLoadSaveState *)pMsgCore;
 
1927
 
 
1928
                LogFlowFunc(("HGCM_MSG_LOADSTATE\n"));
 
1929
 
 
1930
                rc = HGCMService::LoadState (pMsg->pSSM);
 
1931
            } break;
 
1932
 
 
1933
            case HGCM_MSG_SAVESTATE:
 
1934
            {
 
1935
                HGCMMsgMainLoadSaveState *pMsg = (HGCMMsgMainLoadSaveState *)pMsgCore;
 
1936
 
 
1937
                LogFlowFunc(("HGCM_MSG_SAVESTATE\n"));
 
1938
 
 
1939
                rc = HGCMService::SaveState (pMsg->pSSM);
 
1940
            } break;
 
1941
 
 
1942
            case HGCM_MSG_QUIT:
 
1943
            {
 
1944
                LogFlowFunc(("HGCM_MSG_QUIT\n"));
 
1945
 
 
1946
                HGCMService::UnloadAll ();
 
1947
 
 
1948
                fQuit = true;
 
1949
            } break;
 
1950
 
 
1951
            case HGCM_MSG_REGEXT:
 
1952
            {
 
1953
                HGCMMsgMainRegisterExtension *pMsg = (HGCMMsgMainRegisterExtension *)pMsgCore;
 
1954
 
 
1955
                LogFlowFunc(("HGCM_MSG_REGEXT\n"));
 
1956
 
 
1957
                /* Allocate the handle data. */
 
1958
                HGCMSVCEXTHANDLE handle = (HGCMSVCEXTHANDLE)RTMemAllocZ (sizeof (struct _HGCMSVCEXTHANDLEDATA)
 
1959
                                                                         + strlen (pMsg->pszServiceName)
 
1960
                                                                         + sizeof (char));
 
1961
 
 
1962
                if (handle == NULL)
 
1963
                {
 
1964
                    rc = VERR_NO_MEMORY;
 
1965
                }
 
1966
                else
 
1967
                {
 
1968
                    handle->pszServiceName = (char *)((uint8_t *)handle + sizeof (struct _HGCMSVCEXTHANDLEDATA));
 
1969
                    strcpy (handle->pszServiceName, pMsg->pszServiceName);
 
1970
 
 
1971
                    HGCMService *pService;
 
1972
                    rc = HGCMService::ResolveService (&pService, handle->pszServiceName);
 
1973
 
 
1974
                    if (RT_SUCCESS(rc))
 
1975
                    {
 
1976
                        pService->RegisterExtension (handle, pMsg->pfnExtension, pMsg->pvExtension);
 
1977
 
 
1978
                        pService->ReleaseService ();
 
1979
                    }
 
1980
 
 
1981
                    if (RT_FAILURE(rc))
 
1982
                    {
 
1983
                        RTMemFree (handle);
 
1984
                    }
 
1985
                    else
 
1986
                    {
 
1987
                        *pMsg->pHandle = handle;
 
1988
                    }
 
1989
                }
 
1990
            } break;
 
1991
 
 
1992
            case HGCM_MSG_UNREGEXT:
 
1993
            {
 
1994
                HGCMMsgMainUnregisterExtension *pMsg = (HGCMMsgMainUnregisterExtension *)pMsgCore;
 
1995
 
 
1996
                LogFlowFunc(("HGCM_MSG_UNREGEXT\n"));
 
1997
 
 
1998
                HGCMService *pService;
 
1999
                rc = HGCMService::ResolveService (&pService, pMsg->handle->pszServiceName);
 
2000
 
 
2001
                if (RT_SUCCESS(rc))
 
2002
                {
 
2003
                    pService->UnregisterExtension (pMsg->handle);
 
2004
 
 
2005
                    pService->ReleaseService ();
 
2006
                }
 
2007
 
 
2008
                RTMemFree (pMsg->handle);
 
2009
            } break;
 
2010
 
 
2011
            default:
 
2012
            {
 
2013
                AssertMsgFailed(("hgcmThread: Unsupported message number %08X!!!\n", u32MsgId));
 
2014
                rc = VERR_NOT_SUPPORTED;
 
2015
            } break;
 
2016
        }
 
2017
 
 
2018
        /* Complete the message processing. */
 
2019
        hgcmMsgComplete (pMsgCore, rc);
 
2020
 
 
2021
        LogFlowFunc(("message processed %Rrc\n", rc));
 
2022
    }
 
2023
}
 
2024
 
 
2025
 
 
2026
/*
 
2027
 * The HGCM API.
 
2028
 */
 
2029
 
 
2030
/* The main hgcm thread. */
 
2031
static HGCMTHREADHANDLE g_hgcmThread = 0;
 
2032
 
 
2033
/*
 
2034
 * Public HGCM functions.
 
2035
 *
 
2036
 * hgcmGuest* - called as a result of the guest HGCM requests.
 
2037
 * hgcmHost*  - called by the host.
 
2038
 */
 
2039
 
 
2040
/* Load a HGCM service from the specified library.
 
2041
 * Assign the specified name to the service.
 
2042
 *
 
2043
 * @param pszServiceLibrary  The library to be loaded.
 
2044
 * @param pszServiceName     The name to be assigned to the service.
 
2045
 * @return VBox rc.
 
2046
 */
 
2047
int HGCMHostLoad (const char *pszServiceLibrary,
 
2048
                  const char *pszServiceName)
 
2049
{
 
2050
    LogFlowFunc(("lib = %s, name = %s\n", pszServiceLibrary, pszServiceName));
 
2051
 
 
2052
    if (!pszServiceLibrary || !pszServiceName)
 
2053
    {
 
2054
        return VERR_INVALID_PARAMETER;
 
2055
    }
 
2056
 
 
2057
    /* Forward the request to the main hgcm thread. */
 
2058
    HGCMMSGHANDLE hMsg = 0;
 
2059
 
 
2060
    int rc = hgcmMsgAlloc (g_hgcmThread, &hMsg, HGCM_MSG_LOAD, hgcmMainMessageAlloc);
 
2061
 
 
2062
    if (RT_SUCCESS(rc))
 
2063
    {
 
2064
        /* Initialize the message. Since the message is synchronous, use the supplied pointers. */
 
2065
        HGCMMsgMainLoad *pMsg = (HGCMMsgMainLoad *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
 
2066
        AssertRelease(pMsg);
 
2067
 
 
2068
        pMsg->pszServiceLibrary = pszServiceLibrary;
 
2069
        pMsg->pszServiceName    = pszServiceName;
 
2070
 
 
2071
        hgcmObjDereference (pMsg);
 
2072
 
 
2073
        rc = hgcmMsgSend (hMsg);
 
2074
    }
 
2075
 
 
2076
    LogFlowFunc(("rc = %Rrc\n", rc));
 
2077
    return rc;
 
2078
}
 
2079
 
 
2080
/* Register a HGCM service extension.
 
2081
 *
 
2082
 * @param pHandle            Returned handle for the registered extension.
 
2083
 * @param pszServiceName     The name of the service.
 
2084
 * @param pfnExtension       The extension entry point (callback).
 
2085
 * @param pvExtension        The extension pointer.
 
2086
 * @return VBox rc.
 
2087
 */
 
2088
int HGCMHostRegisterServiceExtension (HGCMSVCEXTHANDLE *pHandle,
 
2089
                                      const char *pszServiceName,
 
2090
                                      PFNHGCMSVCEXT pfnExtension,
 
2091
                                      void *pvExtension)
 
2092
{
 
2093
    LogFlowFunc(("pHandle = %p, name = %s, pfn = %p, rv = %p\n", pHandle, pszServiceName, pfnExtension, pvExtension));
 
2094
 
 
2095
    if (!pHandle || !pszServiceName || !pfnExtension)
 
2096
    {
 
2097
        return VERR_INVALID_PARAMETER;
 
2098
    }
 
2099
 
 
2100
    /* Forward the request to the main hgcm thread. */
 
2101
    HGCMMSGHANDLE hMsg = 0;
 
2102
 
 
2103
    int rc = hgcmMsgAlloc (g_hgcmThread, &hMsg, HGCM_MSG_REGEXT, hgcmMainMessageAlloc);
 
2104
 
 
2105
    if (RT_SUCCESS(rc))
 
2106
    {
 
2107
        /* Initialize the message. Since the message is synchronous, use the supplied pointers. */
 
2108
        HGCMMsgMainRegisterExtension *pMsg = (HGCMMsgMainRegisterExtension *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
 
2109
        AssertRelease(pMsg);
 
2110
 
 
2111
        pMsg->pHandle        = pHandle;
 
2112
        pMsg->pszServiceName = pszServiceName;
 
2113
        pMsg->pfnExtension   = pfnExtension;
 
2114
        pMsg->pvExtension    = pvExtension;
 
2115
 
 
2116
        hgcmObjDereference (pMsg);
 
2117
 
 
2118
        rc = hgcmMsgSend (hMsg);
 
2119
    }
 
2120
 
 
2121
    LogFlowFunc(("*pHandle = %p, rc = %Rrc\n", *pHandle, rc));
 
2122
    return rc;
 
2123
}
 
2124
 
 
2125
void HGCMHostUnregisterServiceExtension (HGCMSVCEXTHANDLE handle)
 
2126
{
 
2127
    LogFlowFunc(("handle = %p\n", handle));
 
2128
 
 
2129
    /* Forward the request to the main hgcm thread. */
 
2130
    HGCMMSGHANDLE hMsg = 0;
 
2131
 
 
2132
    int rc = hgcmMsgAlloc (g_hgcmThread, &hMsg, HGCM_MSG_UNREGEXT, hgcmMainMessageAlloc);
 
2133
 
 
2134
    if (RT_SUCCESS(rc))
 
2135
    {
 
2136
        /* Initialize the message. */
 
2137
        HGCMMsgMainUnregisterExtension *pMsg = (HGCMMsgMainUnregisterExtension *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
 
2138
        AssertRelease(pMsg);
 
2139
 
 
2140
        pMsg->handle = handle;
 
2141
 
 
2142
        hgcmObjDereference (pMsg);
 
2143
 
 
2144
        rc = hgcmMsgSend (hMsg);
 
2145
    }
 
2146
 
 
2147
    LogFlowFunc(("rc = %Rrc\n", rc));
 
2148
    return;
 
2149
}
 
2150
 
 
2151
/* Find a service and inform it about a client connection, create a client handle.
 
2152
 *
 
2153
 * @param pHGCMPort      The port to be used for completion confirmation.
 
2154
 * @param pCmd           The VBox HGCM context.
 
2155
 * @param pszServiceName The name of the service to be connected to.
 
2156
 * @param pu32ClientId   Where the store the created client handle.
 
2157
 * @return VBox rc.
 
2158
 */
 
2159
int HGCMGuestConnect (PPDMIHGCMPORT pHGCMPort,
 
2160
                      PVBOXHGCMCMD pCmd,
 
2161
                      const char *pszServiceName,
 
2162
                      uint32_t *pu32ClientId)
 
2163
{
 
2164
    LogFlowFunc(("pHGCMPort = %p, pCmd = %p, name = %s, pu32ClientId = %p\n",
 
2165
                 pHGCMPort, pCmd, pszServiceName, pu32ClientId));
 
2166
 
 
2167
    if (pHGCMPort == NULL || pCmd == NULL || pszServiceName == NULL || pu32ClientId == NULL)
 
2168
    {
 
2169
        return VERR_INVALID_PARAMETER;
 
2170
    }
 
2171
 
 
2172
    /* Forward the request to the main hgcm thread. */
 
2173
    HGCMMSGHANDLE hMsg = 0;
 
2174
 
 
2175
    int rc = hgcmMsgAlloc (g_hgcmThread, &hMsg, HGCM_MSG_CONNECT, hgcmMainMessageAlloc);
 
2176
 
 
2177
    if (RT_SUCCESS(rc))
 
2178
    {
 
2179
        /* Initialize the message. Since 'pszServiceName' and 'pu32ClientId'
 
2180
         * will not be deallocated by the caller until the message is completed,
 
2181
         * use the supplied pointers.
 
2182
         */
 
2183
        HGCMMsgMainConnect *pMsg = (HGCMMsgMainConnect *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
 
2184
        AssertRelease(pMsg);
 
2185
 
 
2186
        pMsg->pHGCMPort      = pHGCMPort;
 
2187
        pMsg->pCmd           = pCmd;
 
2188
        pMsg->pszServiceName = pszServiceName;
 
2189
        pMsg->pu32ClientId   = pu32ClientId;
 
2190
 
 
2191
        hgcmObjDereference (pMsg);
 
2192
 
 
2193
        rc = hgcmMsgPost (hMsg, hgcmMsgCompletionCallback);
 
2194
    }
 
2195
 
 
2196
    LogFlowFunc(("rc = %Rrc\n", rc));
 
2197
    return rc;
 
2198
}
 
2199
 
 
2200
/* Tell a service that the client is disconnecting, destroy the client handle.
 
2201
 *
 
2202
 * @param pHGCMPort      The port to be used for completion confirmation.
 
2203
 * @param pCmd           The VBox HGCM context.
 
2204
 * @param u32ClientId    The client handle to be disconnected and deleted.
 
2205
 * @return VBox rc.
 
2206
 */
 
2207
int HGCMGuestDisconnect (PPDMIHGCMPORT pHGCMPort,
 
2208
                         PVBOXHGCMCMD pCmd,
 
2209
                         uint32_t u32ClientId)
 
2210
{
 
2211
    LogFlowFunc(("pHGCMPort = %p, pCmd = %p, u32ClientId = %d\n",
 
2212
                  pHGCMPort, pCmd, u32ClientId));
 
2213
 
 
2214
    if (!pHGCMPort || !pCmd || !u32ClientId)
 
2215
    {
 
2216
        return VERR_INVALID_PARAMETER;
 
2217
    }
 
2218
 
 
2219
    /* Forward the request to the main hgcm thread. */
 
2220
    HGCMMSGHANDLE hMsg = 0;
 
2221
 
 
2222
    int rc = hgcmMsgAlloc (g_hgcmThread, &hMsg, HGCM_MSG_DISCONNECT, hgcmMainMessageAlloc);
 
2223
 
 
2224
    if (RT_SUCCESS(rc))
 
2225
    {
 
2226
        /* Initialize the message. */
 
2227
        HGCMMsgMainDisconnect *pMsg = (HGCMMsgMainDisconnect *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
 
2228
        AssertRelease(pMsg);
 
2229
 
 
2230
        pMsg->pCmd        = pCmd;
 
2231
        pMsg->pHGCMPort   = pHGCMPort;
 
2232
        pMsg->u32ClientId = u32ClientId;
 
2233
 
 
2234
        hgcmObjDereference (pMsg);
 
2235
 
 
2236
        rc = hgcmMsgPost (hMsg, hgcmMsgCompletionCallback);
 
2237
    }
 
2238
 
 
2239
    LogFlowFunc(("rc = %Rrc\n", rc));
 
2240
    return rc;
 
2241
}
 
2242
 
 
2243
/* Helper to send either HGCM_MSG_SAVESTATE or HGCM_MSG_LOADSTATE messages to the main HGCM thread.
 
2244
 *
 
2245
 * @param pSSM     The SSM handle.
 
2246
 * @param u32MsgId The message to be sent: HGCM_MSG_SAVESTATE or HGCM_MSG_LOADSTATE.
 
2247
 * @return VBox rc.
 
2248
 */
 
2249
static int hgcmHostLoadSaveState (PSSMHANDLE pSSM,
 
2250
                                  uint32_t u32MsgId)
 
2251
{
 
2252
    LogFlowFunc(("pSSM = %p, u32MsgId = %d\n", pSSM, u32MsgId));
 
2253
 
 
2254
    HGCMMSGHANDLE hMsg = 0;
 
2255
 
 
2256
    int rc = hgcmMsgAlloc (g_hgcmThread, &hMsg, u32MsgId, hgcmMainMessageAlloc);
 
2257
 
 
2258
    if (RT_SUCCESS(rc))
 
2259
    {
 
2260
        HGCMMsgMainLoadSaveState *pMsg = (HGCMMsgMainLoadSaveState *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
 
2261
        AssertRelease(pMsg);
 
2262
 
 
2263
        pMsg->pSSM = pSSM;
 
2264
 
 
2265
        hgcmObjDereference (pMsg);
 
2266
 
 
2267
        rc = hgcmMsgSend (hMsg);
 
2268
    }
 
2269
 
 
2270
    LogFlowFunc(("rc = %Rrc\n", rc));
 
2271
    return rc;
 
2272
}
 
2273
 
 
2274
/* Save the state of services.
 
2275
 *
 
2276
 * @param pSSM     The SSM handle.
 
2277
 * @return VBox rc.
 
2278
 */
 
2279
int HGCMHostSaveState (PSSMHANDLE pSSM)
 
2280
{
 
2281
    return hgcmHostLoadSaveState (pSSM, HGCM_MSG_SAVESTATE);
 
2282
}
 
2283
 
 
2284
/* Load the state of services.
 
2285
 *
 
2286
 * @param pSSM     The SSM handle.
 
2287
 * @return VBox rc.
 
2288
 */
 
2289
int HGCMHostLoadState (PSSMHANDLE pSSM)
 
2290
{
 
2291
    return hgcmHostLoadSaveState (pSSM, HGCM_MSG_LOADSTATE);
 
2292
}
 
2293
 
 
2294
/* The guest calls the service.
 
2295
 *
 
2296
 * @param pHGCMPort      The port to be used for completion confirmation.
 
2297
 * @param pCmd           The VBox HGCM context.
 
2298
 * @param u32ClientId    The client handle to be disconnected and deleted.
 
2299
 * @param u32Function    The function number.
 
2300
 * @param cParms         Number of parameters.
 
2301
 * @param paParms        Pointer to array of parameters.
 
2302
 * @return VBox rc.
 
2303
 */
 
2304
int HGCMGuestCall (PPDMIHGCMPORT pHGCMPort,
 
2305
                   PVBOXHGCMCMD pCmd,
 
2306
                   uint32_t u32ClientId,
 
2307
                   uint32_t u32Function,
 
2308
                   uint32_t cParms,
 
2309
                   VBOXHGCMSVCPARM *paParms)
 
2310
{
 
2311
    LogFlowFunc(("pHGCMPort = %p, pCmd = %p, u32ClientId = %d, u32Function = %d, cParms = %d, paParms = %p\n",
 
2312
                  pHGCMPort, pCmd, u32ClientId, u32Function, cParms, paParms));
 
2313
 
 
2314
    if (!pHGCMPort || !pCmd || u32ClientId == 0)
 
2315
    {
 
2316
        return VERR_INVALID_PARAMETER;
 
2317
    }
 
2318
 
 
2319
    int rc = VERR_HGCM_INVALID_CLIENT_ID;
 
2320
 
 
2321
    /* Resolve the client handle to the client instance pointer. */
 
2322
    HGCMClient *pClient = (HGCMClient *)hgcmObjReference (u32ClientId, HGCMOBJ_CLIENT);
 
2323
 
 
2324
    if (pClient)
 
2325
    {
 
2326
        AssertRelease(pClient->pService);
 
2327
 
 
2328
        /* Forward the message to the service thread. */
 
2329
        rc = pClient->pService->GuestCall (pHGCMPort, pCmd, u32ClientId, u32Function, cParms, paParms);
 
2330
 
 
2331
        hgcmObjDereference (pClient);
 
2332
    }
 
2333
 
 
2334
    LogFlowFunc(("rc = %Rrc\n", rc));
 
2335
    return rc;
 
2336
}
 
2337
 
 
2338
/* The host calls the service.
 
2339
 *
 
2340
 * @param pszServiceName The service name to be called.
 
2341
 * @param u32Function    The function number.
 
2342
 * @param cParms         Number of parameters.
 
2343
 * @param paParms        Pointer to array of parameters.
 
2344
 * @return VBox rc.
 
2345
 */
 
2346
int HGCMHostCall (const char *pszServiceName,
 
2347
                  uint32_t u32Function,
 
2348
                  uint32_t cParms,
 
2349
                  VBOXHGCMSVCPARM *paParms)
 
2350
{
 
2351
    LogFlowFunc(("name = %s, u32Function = %d, cParms = %d, paParms = %p\n",
 
2352
                 pszServiceName, u32Function, cParms, paParms));
 
2353
 
 
2354
    if (!pszServiceName)
 
2355
    {
 
2356
        return VERR_INVALID_PARAMETER;
 
2357
    }
 
2358
 
 
2359
    HGCMMSGHANDLE hMsg = 0;
 
2360
 
 
2361
    /* Host calls go to main HGCM thread that resolves the service name to the
 
2362
     * service instance pointer and then, using the service pointer, forwards
 
2363
     * the message to the service thread.
 
2364
     * So it is slow but host calls are intended mostly for configuration and
 
2365
     * other non-time-critical functions.
 
2366
     */
 
2367
    int rc = hgcmMsgAlloc (g_hgcmThread, &hMsg, HGCM_MSG_HOSTCALL, hgcmMainMessageAlloc);
 
2368
 
 
2369
    if (RT_SUCCESS(rc))
 
2370
    {
 
2371
        HGCMMsgMainHostCall *pMsg = (HGCMMsgMainHostCall *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
 
2372
        AssertRelease(pMsg);
 
2373
 
 
2374
        pMsg->pszServiceName = (char *)pszServiceName;
 
2375
        pMsg->u32Function    = u32Function;
 
2376
        pMsg->cParms         = cParms;
 
2377
        pMsg->paParms        = paParms;
 
2378
 
 
2379
        hgcmObjDereference (pMsg);
 
2380
 
 
2381
        rc = hgcmMsgSend (hMsg);
 
2382
    }
 
2383
 
 
2384
    LogFlowFunc(("rc = %Rrc\n", rc));
 
2385
    return rc;
 
2386
}
 
2387
 
 
2388
#ifdef VBOX_WITH_CRHGSMI
 
2389
int HGCMHostSvcHandleCreate (const char *pszServiceName, HGCMCVSHANDLE * phSvc)
 
2390
{
 
2391
    LogFlowFunc(("name = %s\n", pszServiceName));
 
2392
 
 
2393
    if (!pszServiceName)
 
2394
    {
 
2395
        return VERR_INVALID_PARAMETER;
 
2396
    }
 
2397
 
 
2398
    if (!phSvc)
 
2399
    {
 
2400
        return VERR_INVALID_PARAMETER;
 
2401
    }
 
2402
 
 
2403
    HGCMMSGHANDLE hMsg = 0;
 
2404
 
 
2405
    /* Host calls go to main HGCM thread that resolves the service name to the
 
2406
     * service instance pointer and then, using the service pointer, forwards
 
2407
     * the message to the service thread.
 
2408
     * So it is slow but host calls are intended mostly for configuration and
 
2409
     * other non-time-critical functions.
 
2410
     */
 
2411
    int rc = hgcmMsgAlloc (g_hgcmThread, &hMsg, HGCM_MSG_SVCAQUIRE, hgcmMainMessageAlloc);
 
2412
 
 
2413
    if (RT_SUCCESS(rc))
 
2414
    {
 
2415
        HGCMMsgMainSvcAcquire *pMsg = (HGCMMsgMainSvcAcquire *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
 
2416
        AssertRelease(pMsg);
 
2417
 
 
2418
        pMsg->pszServiceName = (char *)pszServiceName;
 
2419
        pMsg->pService = NULL;
 
2420
 
 
2421
        rc = hgcmMsgSend (hMsg);
 
2422
        if (RT_SUCCESS(rc))
 
2423
        {
 
2424
            /* for simplicity just use a svc ptr as handle for now */
 
2425
            *phSvc = (HGCMCVSHANDLE)pMsg->pService;
 
2426
        }
 
2427
 
 
2428
        hgcmObjDereference (pMsg);
 
2429
    }
 
2430
 
 
2431
    LogFlowFunc(("rc = %Rrc\n", rc));
 
2432
    return rc;
 
2433
}
 
2434
 
 
2435
int HGCMHostSvcHandleDestroy (HGCMCVSHANDLE hSvc)
 
2436
{
 
2437
    LogFlowFunc(("hSvc = %p\n", hSvc));
 
2438
 
 
2439
    if (!hSvc)
 
2440
    {
 
2441
        return VERR_INVALID_PARAMETER;
 
2442
    }
 
2443
 
 
2444
    HGCMMSGHANDLE hMsg = 0;
 
2445
 
 
2446
    /* Host calls go to main HGCM thread that resolves the service name to the
 
2447
     * service instance pointer and then, using the service pointer, forwards
 
2448
     * the message to the service thread.
 
2449
     * So it is slow but host calls are intended mostly for configuration and
 
2450
     * other non-time-critical functions.
 
2451
     */
 
2452
    int rc = hgcmMsgAlloc (g_hgcmThread, &hMsg, HGCM_MSG_SVCRELEASE, hgcmMainMessageAlloc);
 
2453
 
 
2454
    if (RT_SUCCESS(rc))
 
2455
    {
 
2456
        HGCMMsgMainSvcRelease *pMsg = (HGCMMsgMainSvcRelease *)hgcmObjReference (hMsg, HGCMOBJ_MSG);
 
2457
        AssertRelease(pMsg);
 
2458
 
 
2459
        pMsg->pService = (HGCMService *)hSvc;
 
2460
 
 
2461
        hgcmObjDereference (pMsg);
 
2462
 
 
2463
        rc = hgcmMsgSend (hMsg);
 
2464
    }
 
2465
 
 
2466
    LogFlowFunc(("rc = %Rrc\n", rc));
 
2467
    return rc;
 
2468
}
 
2469
 
 
2470
int HGCMHostFastCallAsync (HGCMCVSHANDLE hSvc, uint32_t function, VBOXHGCMSVCPARM *pParm, PHGCMHOSTFASTCALLCB pfnCompletion, void *pvCompletion)
 
2471
{
 
2472
    LogFlowFunc(("hSvc = %p, u32Function = %d, pParm = %p\n",
 
2473
            hSvc, function, pParm));
 
2474
 
 
2475
    if (!hSvc)
 
2476
    {
 
2477
        return VERR_INVALID_PARAMETER;
 
2478
    }
 
2479
 
 
2480
    HGCMService *pService = (HGCMService *)hSvc;
 
2481
    int rc = pService->HostFastCallAsync (function, pParm, pfnCompletion, pvCompletion);
 
2482
 
 
2483
    LogFlowFunc(("rc = %Rrc\n", rc));
 
2484
    return rc;
 
2485
}
 
2486
#endif
 
2487
 
 
2488
int HGCMHostReset (void)
 
2489
{
 
2490
    LogFlowFunc(("\n"));
 
2491
 
 
2492
    /* Disconnect all clients.
 
2493
     */
 
2494
 
 
2495
    HGCMMSGHANDLE hMsg = 0;
 
2496
 
 
2497
    int rc = hgcmMsgAlloc (g_hgcmThread, &hMsg, HGCM_MSG_RESET, hgcmMainMessageAlloc);
 
2498
 
 
2499
    if (RT_SUCCESS(rc))
 
2500
    {
 
2501
        rc = hgcmMsgSend (hMsg);
 
2502
    }
 
2503
 
 
2504
    LogFlowFunc(("rc = %Rrc\n", rc));
 
2505
    return rc;
 
2506
}
 
2507
 
 
2508
int HGCMHostInit (void)
 
2509
{
 
2510
    LogFlowFunc(("\n"));
 
2511
 
 
2512
    int rc = hgcmThreadInit ();
 
2513
 
 
2514
    if (RT_SUCCESS(rc))
 
2515
    {
 
2516
        /*
 
2517
         * Start main HGCM thread.
 
2518
         */
 
2519
 
 
2520
        rc = hgcmThreadCreate (&g_hgcmThread, "MainHGCMthread", hgcmThread, NULL);
 
2521
 
 
2522
        if (RT_FAILURE(rc))
 
2523
        {
 
2524
            LogRel(("Failed to start HGCM thread. HGCM services will be unavailable!!! rc = %Rrc\n", rc));
 
2525
        }
 
2526
    }
 
2527
 
 
2528
    LogFlowFunc(("rc = %Rrc\n", rc));
 
2529
    return rc;
 
2530
}
 
2531
 
 
2532
int HGCMHostShutdown (void)
 
2533
{
 
2534
    LogFlowFunc(("\n"));
 
2535
 
 
2536
    /*
 
2537
     * Do HGCMReset and then unload all services.
 
2538
     */
 
2539
 
 
2540
    int rc = HGCMHostReset ();
 
2541
 
 
2542
    if (RT_SUCCESS(rc))
 
2543
    {
 
2544
        /* Send the quit message to the main hgcmThread. */
 
2545
        HGCMMSGHANDLE hMsg = 0;
 
2546
 
 
2547
        rc = hgcmMsgAlloc (g_hgcmThread, &hMsg, HGCM_MSG_QUIT, hgcmMainMessageAlloc);
 
2548
 
 
2549
        if (RT_SUCCESS(rc))
 
2550
        {
 
2551
            rc = hgcmMsgSend (hMsg);
 
2552
 
 
2553
            if (RT_SUCCESS(rc))
 
2554
            {
 
2555
                /* Wait for the thread termination. */
 
2556
                hgcmThreadWait (g_hgcmThread);
 
2557
                g_hgcmThread = 0;
 
2558
 
 
2559
                hgcmThreadUninit ();
 
2560
            }
 
2561
        }
 
2562
    }
 
2563
 
 
2564
    LogFlowFunc(("rc = %Rrc\n", rc));
 
2565
    return rc;
 
2566
}