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

« back to all changes in this revision

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