~ubuntu-branches/ubuntu/trusty/virtualbox/trusty-proposed

« back to all changes in this revision

Viewing changes to src/VBox/HostServices/HostChannel/HostChannel.cpp

  • Committer: Package Import Robot
  • Author(s): Felix Geyer
  • Date: 2013-03-07 16:38:36 UTC
  • mfrom: (1.1.13) (3.1.20 experimental)
  • Revision ID: package-import@ubuntu.com-20130307163836-p93jpbgx39tp3gb4
Tags: 4.2.8-dfsg-0ubuntu1
* New upstream release. (Closes: #691148)
  - Fixes compatibility with kernel 3.8. (Closes: #700823; LP: #1101867)
* Switch to my @debian.org email address.
* Move package to contrib as virtualbox 4.2 needs a non-free compiler to
  build the BIOS.
* Build-depend on libdevmapper-dev.
* Refresh patches.
  - Drop 36-fix-ftbfs-xserver-112.patch, cve-2012-3221.patch,
    CVE-2013-0420.patch 37-kcompat-3.6.patch and 38-kcompat-3.7.patch.
* Drop all virtualbox-ose transitional packages.
* Drop the virtualbox-fuse package as vdfuse fails to build with
  virtualbox 4.2.
* Update install files and VBox.sh.
* Bump required kbuild version to 0.1.9998svn2577.
* Fix path to VBoxCreateUSBNode.sh in virtualbox.postinst. (Closes: #700479)
* Add an init script to virtuabox-guest-x11 which loads the vboxvideo
  kernel module. The X Server 1.13 doesn't load it anymore. (Closes: #686994)
* Update man pages. (Closes: #680053)
* Add 36-python-multiarch.patch from Rico Tzschichholz to fix detection of
  python in multiarch paths using pkg-config.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/** @file
 
2
 * Host channel.
 
3
 */
 
4
 
 
5
/*
 
6
 * Copyright (C) 2012 Oracle Corporation
 
7
 *
 
8
 * This file is part of VirtualBox Open Source Edition (OSE), as
 
9
 * available from http://www.virtualbox.org. This file is free software;
 
10
 * you can redistribute it and/or modify it under the terms of the GNU
 
11
 * General Public License (GPL) as published by the Free Software
 
12
 * Foundation, in version 2 as it comes in the "COPYING" file of the
 
13
 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
 
14
 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
 
15
 */
 
16
 
 
17
#include <iprt/alloc.h>
 
18
#include <iprt/string.h>
 
19
#include <iprt/asm.h>
 
20
#include <iprt/assert.h>
 
21
 
 
22
#include "HostChannel.h"
 
23
 
 
24
 
 
25
static DECLCALLBACK(void) HostChannelCallbackEvent(void *pvCallbacks, void *pvInstance,
 
26
                                                   uint32_t u32Id, const void *pvEvent, uint32_t cbEvent);
 
27
static DECLCALLBACK(void) HostChannelCallbackDeleted(void *pvCallbacks, void *pvChannel);
 
28
 
 
29
 
 
30
/* A registered provider of channels. */
 
31
typedef struct VBOXHOSTCHPROVIDER
 
32
{
 
33
    int32_t volatile cRefs;
 
34
 
 
35
    RTLISTNODE nodeContext; /* Member of the list of providers in the service context. */
 
36
 
 
37
    VBOXHOSTCHCTX *pCtx;
 
38
 
 
39
    VBOXHOSTCHANNELINTERFACE iface;
 
40
 
 
41
    char *pszName;
 
42
 
 
43
    RTLISTANCHOR listChannels;
 
44
} VBOXHOSTCHPROVIDER;
 
45
 
 
46
/* An established channel. */
 
47
typedef struct VBOXHOSTCHINSTANCE
 
48
{
 
49
    int32_t volatile cRefs;
 
50
 
 
51
    RTLISTNODE nodeClient;    /* In the client, for cleanup when a client disconnects. */
 
52
    RTLISTNODE nodeProvider;  /* In the provider, needed for cleanup when the provider is unregistered. */
 
53
 
 
54
    VBOXHOSTCHCLIENT *pClient; /* The client which uses the channel. */
 
55
    VBOXHOSTCHPROVIDER *pProvider; /* NULL if the provider was unregistered. */
 
56
    void *pvChannel;               /* Provider's context of the channel. */
 
57
    uint32_t u32Handle;        /* handle assigned to the channel by the service. */
 
58
} VBOXHOSTCHINSTANCE;
 
59
 
 
60
struct VBOXHOSTCHCTX
 
61
{
 
62
    bool fInitialized;
 
63
 
 
64
    RTLISTANCHOR listProviders;
 
65
};
 
66
 
 
67
/* The channel callbacks context. The provider passes the pointer as a callback parameter.
 
68
 * Created for the provider and deleted when the provider says so.
 
69
 */
 
70
typedef struct VBOXHOSTCHCALLBACKCTX
 
71
{
 
72
    RTLISTNODE nodeClient;     /* In the client, for cleanup when a client disconnects. */
 
73
 
 
74
    VBOXHOSTCHCLIENT *pClient; /* The client which uses the channel, NULL when the client does not exist. */
 
75
} VBOXHOSTCHCALLBACKCTX;
 
76
 
 
77
/* Only one service instance is supported. */
 
78
static VBOXHOSTCHCTX g_ctx = { false };
 
79
 
 
80
static VBOXHOSTCHANNELCALLBACKS g_callbacks = 
 
81
{
 
82
    HostChannelCallbackEvent,
 
83
    HostChannelCallbackDeleted
 
84
};
 
85
 
 
86
 
 
87
/*
 
88
 * Provider management.
 
89
 */
 
90
 
 
91
static void vhcProviderDestroy(VBOXHOSTCHPROVIDER *pProvider)
 
92
{
 
93
    RTStrFree(pProvider->pszName);
 
94
}
 
95
 
 
96
static int32_t vhcProviderAddRef(VBOXHOSTCHPROVIDER *pProvider)
 
97
{
 
98
    return ASMAtomicIncS32(&pProvider->cRefs);
 
99
}
 
100
 
 
101
static void vhcProviderRelease(VBOXHOSTCHPROVIDER *pProvider)
 
102
{
 
103
    int32_t c = ASMAtomicDecS32(&pProvider->cRefs);
 
104
    Assert(c >= 0);
 
105
    if (c == 0)
 
106
    {
 
107
        vhcProviderDestroy(pProvider);
 
108
        RTMemFree(pProvider);
 
109
    }
 
110
}
 
111
 
 
112
static VBOXHOSTCHPROVIDER *vhcProviderFind(VBOXHOSTCHCTX *pCtx, const char *pszName)
 
113
{
 
114
    VBOXHOSTCHPROVIDER *pProvider = NULL;
 
115
 
 
116
    int rc = vboxHostChannelLock();
 
117
 
 
118
    if (RT_SUCCESS(rc))
 
119
    {
 
120
        VBOXHOSTCHPROVIDER *pIter;
 
121
        RTListForEach(&pCtx->listProviders, pIter, VBOXHOSTCHPROVIDER, nodeContext)
 
122
        {
 
123
            if (RTStrCmp(pIter->pszName, pszName) == 0)
 
124
            {
 
125
                pProvider = pIter;
 
126
 
 
127
                vhcProviderAddRef(pProvider);
 
128
 
 
129
                break;
 
130
            }
 
131
        }
 
132
 
 
133
        vboxHostChannelUnlock();
 
134
    }
 
135
 
 
136
    return pProvider;
 
137
}
 
138
 
 
139
static int vhcProviderRegister(VBOXHOSTCHCTX *pCtx, VBOXHOSTCHPROVIDER *pProvider)
 
140
{
 
141
    int rc = vboxHostChannelLock();
 
142
 
 
143
    if (RT_SUCCESS(rc))
 
144
    {
 
145
        /* @todo check a duplicate. */
 
146
 
 
147
        RTListAppend(&pCtx->listProviders, &pProvider->nodeContext);
 
148
 
 
149
        vboxHostChannelUnlock();
 
150
    }
 
151
 
 
152
    if (RT_FAILURE(rc))
 
153
    {
 
154
        vhcProviderRelease(pProvider);
 
155
    }
 
156
 
 
157
    return rc;
 
158
}
 
159
 
 
160
static int vhcProviderUnregister(VBOXHOSTCHPROVIDER *pProvider)
 
161
{
 
162
    int rc = vboxHostChannelLock();
 
163
 
 
164
    if (RT_SUCCESS(rc))
 
165
    {
 
166
        /* @todo check that the provider is in the list. */
 
167
        /* @todo mark the provider as invalid in each instance. also detach channels? */
 
168
 
 
169
        RTListNodeRemove(&pProvider->nodeContext);
 
170
 
 
171
        vboxHostChannelUnlock();
 
172
 
 
173
        vhcProviderRelease(pProvider);
 
174
    }
 
175
 
 
176
    return rc;
 
177
}
 
178
 
 
179
 
 
180
/*
 
181
 * Select an unique handle for the new channel.
 
182
 * Works under the lock.
 
183
 */
 
184
static int vhcHandleCreate(VBOXHOSTCHCLIENT *pClient, uint32_t *pu32Handle)
 
185
{
 
186
    bool fOver = false;
 
187
 
 
188
    for(;;)
 
189
    {
 
190
        uint32_t u32Handle = ASMAtomicIncU32(&pClient->u32HandleSrc);
 
191
 
 
192
        if (u32Handle == 0)
 
193
        {
 
194
            if (fOver)
 
195
            {
 
196
                return VERR_NOT_SUPPORTED;
 
197
            }
 
198
 
 
199
            fOver = true;
 
200
            continue;
 
201
        }
 
202
 
 
203
        VBOXHOSTCHINSTANCE *pDuplicate = NULL;
 
204
        VBOXHOSTCHINSTANCE *pIter;
 
205
        RTListForEach(&pClient->listChannels, pIter, VBOXHOSTCHINSTANCE, nodeClient)
 
206
        {
 
207
            if (pIter->u32Handle == u32Handle)
 
208
            {
 
209
                pDuplicate = pIter;
 
210
                break;
 
211
            }
 
212
        }
 
213
 
 
214
        if (pDuplicate == NULL)
 
215
        {
 
216
            *pu32Handle = u32Handle;
 
217
            break;
 
218
        }
 
219
    }
 
220
 
 
221
    return VINF_SUCCESS;
 
222
}
 
223
 
 
224
 
 
225
/*
 
226
 * Channel instance management.
 
227
 */
 
228
 
 
229
static void vhcInstanceDestroy(VBOXHOSTCHINSTANCE *pInstance)
 
230
{
 
231
    HOSTCHLOG(("HostChannel: destroy %p\n", pInstance));
 
232
}
 
233
 
 
234
static int32_t vhcInstanceAddRef(VBOXHOSTCHINSTANCE *pInstance)
 
235
{
 
236
    HOSTCHLOG(("INST: %p %d addref\n", pInstance, pInstance->cRefs));
 
237
    return ASMAtomicIncS32(&pInstance->cRefs);
 
238
}
 
239
 
 
240
static void vhcInstanceRelease(VBOXHOSTCHINSTANCE *pInstance)
 
241
{
 
242
    int32_t c = ASMAtomicDecS32(&pInstance->cRefs);
 
243
    HOSTCHLOG(("INST: %p %d release\n", pInstance, pInstance->cRefs));
 
244
    Assert(c >= 0);
 
245
    if (c == 0)
 
246
    {
 
247
        vhcInstanceDestroy(pInstance);
 
248
        RTMemFree(pInstance);
 
249
    }
 
250
}
 
251
 
 
252
static int vhcInstanceCreate(VBOXHOSTCHCLIENT *pClient, VBOXHOSTCHINSTANCE **ppInstance)
 
253
{
 
254
    int rc = VINF_SUCCESS;
 
255
 
 
256
    VBOXHOSTCHINSTANCE *pInstance = (VBOXHOSTCHINSTANCE *)RTMemAllocZ(sizeof(VBOXHOSTCHINSTANCE));
 
257
 
 
258
    if (pInstance)
 
259
    {
 
260
        rc = vboxHostChannelLock();
 
261
 
 
262
        if (RT_SUCCESS(rc))
 
263
        {
 
264
            rc = vhcHandleCreate(pClient, &pInstance->u32Handle);
 
265
 
 
266
            if (RT_SUCCESS(rc))
 
267
            {
 
268
                /* Used by the client, that is in the list of channels. */
 
269
                vhcInstanceAddRef(pInstance);
 
270
                /* Add to the list of created channel instances. It is inactive while pClient is 0. */
 
271
                RTListAppend(&pClient->listChannels, &pInstance->nodeClient);
 
272
 
 
273
                /* Return to the caller. */
 
274
                vhcInstanceAddRef(pInstance);
 
275
                *ppInstance = pInstance;
 
276
            }
 
277
 
 
278
            vboxHostChannelUnlock();
 
279
        }
 
280
 
 
281
        if (RT_FAILURE(rc))
 
282
        {
 
283
            RTMemFree(pInstance);
 
284
        }
 
285
    }
 
286
    else
 
287
    {
 
288
        rc = VERR_NO_MEMORY;
 
289
    }
 
290
 
 
291
    return rc;
 
292
}
 
293
 
 
294
static VBOXHOSTCHINSTANCE *vhcInstanceFind(VBOXHOSTCHCLIENT *pClient, uint32_t u32Handle)
 
295
{
 
296
    VBOXHOSTCHINSTANCE *pInstance = NULL;
 
297
 
 
298
    int rc = vboxHostChannelLock();
 
299
 
 
300
    if (RT_SUCCESS(rc))
 
301
    {
 
302
        VBOXHOSTCHINSTANCE *pIter;
 
303
        RTListForEach(&pClient->listChannels, pIter, VBOXHOSTCHINSTANCE, nodeClient)
 
304
        {
 
305
            if (   pIter->pClient
 
306
                && pIter->u32Handle == u32Handle)
 
307
            {
 
308
                pInstance = pIter;
 
309
 
 
310
                vhcInstanceAddRef(pInstance);
 
311
 
 
312
                break;
 
313
            }
 
314
        }
 
315
 
 
316
        vboxHostChannelUnlock();
 
317
    }
 
318
 
 
319
    return pInstance;
 
320
}
 
321
 
 
322
static VBOXHOSTCHINSTANCE *vhcInstanceFindByChannelPtr(VBOXHOSTCHCLIENT *pClient, void *pvChannel)
 
323
{
 
324
    VBOXHOSTCHINSTANCE *pInstance = NULL;
 
325
 
 
326
    if (pvChannel == NULL)
 
327
    {
 
328
        return NULL;
 
329
    }
 
330
 
 
331
    int rc = vboxHostChannelLock();
 
332
 
 
333
    if (RT_SUCCESS(rc))
 
334
    {
 
335
        VBOXHOSTCHINSTANCE *pIter;
 
336
        RTListForEach(&pClient->listChannels, pIter, VBOXHOSTCHINSTANCE, nodeClient)
 
337
        {
 
338
            if (   pIter->pClient
 
339
                && pIter->pvChannel == pvChannel)
 
340
            {
 
341
                pInstance = pIter;
 
342
 
 
343
                vhcInstanceAddRef(pInstance);
 
344
 
 
345
                break;
 
346
            }
 
347
        }
 
348
 
 
349
        vboxHostChannelUnlock();
 
350
    }
 
351
 
 
352
    return pInstance;
 
353
}
 
354
 
 
355
static void vhcInstanceDetach(VBOXHOSTCHINSTANCE *pInstance)
 
356
{
 
357
    HOSTCHLOG(("HostChannel: detach %p\n", pInstance));
 
358
 
 
359
    if (pInstance->pProvider)
 
360
    {
 
361
        pInstance->pProvider->iface.HostChannelDetach(pInstance->pvChannel);
 
362
        RTListNodeRemove(&pInstance->nodeProvider);
 
363
        vhcProviderRelease(pInstance->pProvider);
 
364
        pInstance->pProvider = NULL;
 
365
        vhcInstanceRelease(pInstance); /* Not in the provider's list anymore. */
 
366
    }
 
367
 
 
368
    int rc = vboxHostChannelLock();
 
369
 
 
370
    if (RT_SUCCESS(rc))
 
371
    {
 
372
        RTListNodeRemove(&pInstance->nodeClient);
 
373
 
 
374
        vboxHostChannelUnlock();
 
375
 
 
376
        vhcInstanceRelease(pInstance); /* Not used by the client anymore. */
 
377
    }
 
378
}
 
379
 
 
380
/*
 
381
 * Channel callback contexts.
 
382
 */
 
383
static int vhcCallbackCtxCreate(VBOXHOSTCHCLIENT *pClient, VBOXHOSTCHCALLBACKCTX **ppCallbackCtx)
 
384
{
 
385
    int rc = VINF_SUCCESS;
 
386
 
 
387
    VBOXHOSTCHCALLBACKCTX *pCallbackCtx = (VBOXHOSTCHCALLBACKCTX *)RTMemAllocZ(sizeof(VBOXHOSTCHCALLBACKCTX));
 
388
 
 
389
    if (pCallbackCtx != NULL)
 
390
    {
 
391
        /* The callback context is accessed by the providers threads. */
 
392
        rc = vboxHostChannelLock();
 
393
        if (RT_SUCCESS(rc))
 
394
        {
 
395
            RTListAppend(&pClient->listContexts, &pCallbackCtx->nodeClient);
 
396
            pCallbackCtx->pClient = pClient;
 
397
 
 
398
            vboxHostChannelUnlock();
 
399
        }
 
400
        else
 
401
        {
 
402
            RTMemFree(pCallbackCtx);
 
403
        }
 
404
    }
 
405
    else
 
406
    {
 
407
        rc = VERR_NO_MEMORY;
 
408
    }
 
409
 
 
410
    if (RT_SUCCESS(rc))
 
411
    {
 
412
        *ppCallbackCtx = pCallbackCtx;
 
413
    }
 
414
 
 
415
    return rc;
 
416
}
 
417
 
 
418
static int vhcCallbackCtxDelete(VBOXHOSTCHCALLBACKCTX *pCallbackCtx)
 
419
{
 
420
    int rc = vboxHostChannelLock();
 
421
    if (RT_SUCCESS(rc))
 
422
    {
 
423
        VBOXHOSTCHCLIENT *pClient = pCallbackCtx->pClient;
 
424
 
 
425
        if (pClient != NULL)
 
426
        {
 
427
            /* The callback is associated with a client.
 
428
             * Check that the callback is in the list and remove it from the list.
 
429
             */
 
430
            bool fFound = false;
 
431
 
 
432
            VBOXHOSTCHCALLBACKCTX *pIter;
 
433
            RTListForEach(&pClient->listContexts, pIter, VBOXHOSTCHCALLBACKCTX, nodeClient)
 
434
            {
 
435
                if (pIter == pCallbackCtx)
 
436
                {
 
437
                    fFound = true;
 
438
                    break;
 
439
                }
 
440
            }
 
441
 
 
442
            if (fFound)
 
443
            {
 
444
                RTListNodeRemove(&pCallbackCtx->nodeClient);
 
445
            }
 
446
            else
 
447
            {
 
448
                AssertFailed();
 
449
                rc = VERR_INVALID_PARAMETER;
 
450
            }
 
451
        }
 
452
        else
 
453
        {
 
454
            /* It is not in the clients anymore. May be the client has been disconnected.
 
455
             * Just free the memory.
 
456
             */
 
457
        }
 
458
 
 
459
        vboxHostChannelUnlock();
 
460
    }
 
461
 
 
462
    if (RT_SUCCESS(rc))
 
463
    {
 
464
        RTMemFree(pCallbackCtx);
 
465
    }
 
466
 
 
467
    return rc;
 
468
}
 
469
 
 
470
/*
 
471
 * Host channel service functions.
 
472
 */
 
473
 
 
474
int vboxHostChannelInit(void)
 
475
{
 
476
    VBOXHOSTCHCTX *pCtx = &g_ctx;
 
477
 
 
478
    if (pCtx->fInitialized)
 
479
    {
 
480
        return VERR_NOT_SUPPORTED;
 
481
    }
 
482
 
 
483
    pCtx->fInitialized = true;
 
484
    RTListInit(&pCtx->listProviders);
 
485
 
 
486
    return VINF_SUCCESS;
 
487
}
 
488
 
 
489
void vboxHostChannelDestroy(void)
 
490
{
 
491
    VBOXHOSTCHCTX *pCtx = &g_ctx;
 
492
 
 
493
    VBOXHOSTCHPROVIDER *pIter;
 
494
    VBOXHOSTCHPROVIDER *pIterNext;
 
495
    RTListForEachSafe(&pCtx->listProviders, pIter, pIterNext, VBOXHOSTCHPROVIDER, nodeContext)
 
496
    {
 
497
        vhcProviderUnregister(pIter);
 
498
    }
 
499
    pCtx->fInitialized = false;
 
500
}
 
501
 
 
502
int vboxHostChannelClientConnect(VBOXHOSTCHCLIENT *pClient)
 
503
{
 
504
    /* A guest client is connecting to the service.
 
505
     * Later the client will use Attach calls to connect to channel providers.
 
506
     * pClient is already zeroed.
 
507
     */
 
508
    pClient->pCtx = &g_ctx;
 
509
 
 
510
    RTListInit(&pClient->listChannels);
 
511
    RTListInit(&pClient->listEvents);
 
512
    RTListInit(&pClient->listContexts);
 
513
 
 
514
    return VINF_SUCCESS;
 
515
}
 
516
 
 
517
void vboxHostChannelClientDisconnect(VBOXHOSTCHCLIENT *pClient)
 
518
{
 
519
    /* Clear the list of contexts and prevent acceess to the client. */
 
520
    int rc = vboxHostChannelLock();
 
521
    if (RT_SUCCESS(rc))
 
522
    {
 
523
        VBOXHOSTCHCALLBACKCTX *pIter;
 
524
        VBOXHOSTCHCALLBACKCTX *pNext;
 
525
        RTListForEachSafe(&pClient->listContexts, pIter, pNext, VBOXHOSTCHCALLBACKCTX, nodeClient)
 
526
        {
 
527
            pIter->pClient = NULL;
 
528
            RTListNodeRemove(&pIter->nodeClient);
 
529
        }
 
530
 
 
531
        vboxHostChannelUnlock();
 
532
    }
 
533
 
 
534
    /* If there are attached channels, detach them. */
 
535
    VBOXHOSTCHINSTANCE *pIter;
 
536
    VBOXHOSTCHINSTANCE *pIterNext;
 
537
    RTListForEachSafe(&pClient->listChannels, pIter, pIterNext, VBOXHOSTCHINSTANCE, nodeClient)
 
538
    {
 
539
        vhcInstanceDetach(pIter);
 
540
    }
 
541
}
 
542
 
 
543
int vboxHostChannelAttach(VBOXHOSTCHCLIENT *pClient,
 
544
                          uint32_t *pu32Handle,
 
545
                          const char *pszName,
 
546
                          uint32_t u32Flags)
 
547
{
 
548
    int rc = VINF_SUCCESS;
 
549
 
 
550
    HOSTCHLOG(("HostChannel: Attach: (%d) [%s] 0x%08X\n", pClient->u32ClientID, pszName, u32Flags));
 
551
 
 
552
    /* Look if there is a provider. */
 
553
    VBOXHOSTCHPROVIDER *pProvider = vhcProviderFind(pClient->pCtx, pszName);
 
554
 
 
555
    if (pProvider)
 
556
    {
 
557
        VBOXHOSTCHINSTANCE *pInstance = NULL;
 
558
 
 
559
        rc = vhcInstanceCreate(pClient, &pInstance);
 
560
 
 
561
        if (RT_SUCCESS(rc))
 
562
        {
 
563
            VBOXHOSTCHCALLBACKCTX *pCallbackCtx = NULL;
 
564
            rc = vhcCallbackCtxCreate(pClient, &pCallbackCtx);
 
565
 
 
566
            if (RT_SUCCESS(rc))
 
567
            {
 
568
                void *pvChannel = NULL;
 
569
                rc = pProvider->iface.HostChannelAttach(pProvider->iface.pvProvider,
 
570
                                                        &pvChannel,
 
571
                                                        u32Flags,
 
572
                                                        &g_callbacks, pCallbackCtx);
 
573
 
 
574
                if (RT_SUCCESS(rc))
 
575
                {
 
576
                    vhcProviderAddRef(pProvider);
 
577
                    pInstance->pProvider = pProvider;
 
578
 
 
579
                    pInstance->pClient = pClient;
 
580
                    pInstance->pvChannel = pvChannel;
 
581
 
 
582
                    /* It is already in the channels list of the client. */
 
583
 
 
584
                    vhcInstanceAddRef(pInstance); /* Referenced by the list of provider's channels. */
 
585
                    RTListAppend(&pProvider->listChannels, &pInstance->nodeProvider);
 
586
 
 
587
                    *pu32Handle = pInstance->u32Handle;
 
588
 
 
589
                    HOSTCHLOG(("HostChannel: Attach: (%d) handle %d\n", pClient->u32ClientID, pInstance->u32Handle));
 
590
                }
 
591
 
 
592
                if (RT_FAILURE(rc))
 
593
                {
 
594
                    vhcCallbackCtxDelete(pCallbackCtx);
 
595
                }
 
596
            }
 
597
 
 
598
            if (RT_FAILURE(rc))
 
599
            {
 
600
                vhcInstanceDetach(pInstance);
 
601
            }
 
602
 
 
603
            vhcInstanceRelease(pInstance);
 
604
        }
 
605
 
 
606
        vhcProviderRelease(pProvider);
 
607
    }
 
608
    else
 
609
    {
 
610
        rc = VERR_NOT_SUPPORTED;
 
611
    }
 
612
 
 
613
    return rc;
 
614
}
 
615
 
 
616
int vboxHostChannelDetach(VBOXHOSTCHCLIENT *pClient,
 
617
                          uint32_t u32Handle)
 
618
{
 
619
    HOSTCHLOG(("HostChannel: Detach: (%d) handle %d\n", pClient->u32ClientID, u32Handle));
 
620
 
 
621
    int rc = VINF_SUCCESS;
 
622
 
 
623
    VBOXHOSTCHINSTANCE *pInstance = vhcInstanceFind(pClient, u32Handle);
 
624
 
 
625
    if (pInstance)
 
626
    {
 
627
        vhcInstanceDetach(pInstance);
 
628
 
 
629
        vhcInstanceRelease(pInstance);
 
630
    }
 
631
    else
 
632
    {
 
633
        rc = VERR_NOT_SUPPORTED;
 
634
    }
 
635
 
 
636
    return rc;
 
637
}
 
638
 
 
639
int vboxHostChannelSend(VBOXHOSTCHCLIENT *pClient,
 
640
                        uint32_t u32Handle,
 
641
                        const void *pvData,
 
642
                        uint32_t cbData)
 
643
{
 
644
    HOSTCHLOG(("HostChannel: Send: (%d) handle %d, %d bytes\n", pClient->u32ClientID, u32Handle, cbData));
 
645
 
 
646
    int rc = VINF_SUCCESS;
 
647
 
 
648
    VBOXHOSTCHINSTANCE *pInstance = vhcInstanceFind(pClient, u32Handle);
 
649
 
 
650
    if (pInstance)
 
651
    {
 
652
        if (pInstance->pProvider)
 
653
        {
 
654
            pInstance->pProvider->iface.HostChannelSend(pInstance->pvChannel, pvData, cbData);
 
655
        }
 
656
 
 
657
        vhcInstanceRelease(pInstance);
 
658
    }
 
659
    else
 
660
    {
 
661
        rc = VERR_NOT_SUPPORTED;
 
662
    }
 
663
 
 
664
    return rc;
 
665
}
 
666
 
 
667
int vboxHostChannelRecv(VBOXHOSTCHCLIENT *pClient,
 
668
                        uint32_t u32Handle,
 
669
                        void *pvData,
 
670
                        uint32_t cbData,
 
671
                        uint32_t *pu32SizeReceived,
 
672
                        uint32_t *pu32SizeRemaining)
 
673
{
 
674
    HOSTCHLOG(("HostChannel: Recv: (%d) handle %d, cbData %d\n", pClient->u32ClientID, u32Handle, cbData));
 
675
 
 
676
    int rc = VINF_SUCCESS;
 
677
 
 
678
    VBOXHOSTCHINSTANCE *pInstance = vhcInstanceFind(pClient, u32Handle);
 
679
 
 
680
    if (pInstance)
 
681
    {
 
682
        if (pInstance->pProvider)
 
683
        {
 
684
            rc = pInstance->pProvider->iface.HostChannelRecv(pInstance->pvChannel, pvData, cbData,
 
685
                                                             pu32SizeReceived, pu32SizeRemaining);
 
686
 
 
687
            HOSTCHLOG(("HostChannel: Recv: (%d) handle %d, rc %Rrc, recv %d, rem %d\n",
 
688
                            pClient->u32ClientID, u32Handle, rc, cbData, *pu32SizeReceived, *pu32SizeRemaining));
 
689
        }
 
690
 
 
691
        vhcInstanceRelease(pInstance);
 
692
    }
 
693
    else
 
694
    {
 
695
        rc = VERR_NOT_SUPPORTED;
 
696
    }
 
697
 
 
698
    return rc;
 
699
}
 
700
 
 
701
int vboxHostChannelControl(VBOXHOSTCHCLIENT *pClient,
 
702
                           uint32_t u32Handle,
 
703
                           uint32_t u32Code,
 
704
                           void *pvParm,
 
705
                           uint32_t cbParm,
 
706
                           void *pvData,
 
707
                           uint32_t cbData,
 
708
                           uint32_t *pu32SizeDataReturned)
 
709
{
 
710
    HOSTCHLOG(("HostChannel: Control: (%d) handle %d, cbData %d\n", pClient->u32ClientID, u32Handle, cbData));
 
711
 
 
712
    int rc = VINF_SUCCESS;
 
713
 
 
714
    VBOXHOSTCHINSTANCE *pInstance = vhcInstanceFind(pClient, u32Handle);
 
715
 
 
716
    if (pInstance)
 
717
    {
 
718
        if (pInstance->pProvider)
 
719
        {
 
720
            pInstance->pProvider->iface.HostChannelControl(pInstance->pvChannel, u32Code,
 
721
                                                           pvParm, cbParm,
 
722
                                                           pvData, cbData, pu32SizeDataReturned);
 
723
        }
 
724
 
 
725
        vhcInstanceRelease(pInstance);
 
726
    }
 
727
    else
 
728
    {
 
729
        rc = VERR_NOT_SUPPORTED;
 
730
    }
 
731
 
 
732
    return rc;
 
733
}
 
734
 
 
735
typedef struct VBOXHOSTCHANNELEVENT
 
736
{
 
737
    RTLISTNODE NodeEvent;
 
738
 
 
739
    uint32_t u32ChannelHandle;
 
740
 
 
741
    uint32_t u32Id;
 
742
    void *pvEvent;
 
743
    uint32_t cbEvent;
 
744
} VBOXHOSTCHANNELEVENT;
 
745
 
 
746
int vboxHostChannelEventWait(VBOXHOSTCHCLIENT *pClient,
 
747
                             bool *pfEvent,
 
748
                             VBOXHGCMCALLHANDLE callHandle,
 
749
                             VBOXHGCMSVCPARM *paParms)
 
750
{
 
751
    int rc = vboxHostChannelLock();
 
752
    if (RT_FAILURE(rc))
 
753
    {
 
754
        return rc;
 
755
    }
 
756
 
 
757
    if (pClient->fAsync)
 
758
    {
 
759
        /* If there is a wait request already, cancel it. */
 
760
        vboxHostChannelReportAsync(pClient, 0, VBOX_HOST_CHANNEL_EVENT_CANCELLED, NULL, 0);
 
761
        pClient->fAsync = false;
 
762
    }
 
763
 
 
764
    /* Check if there is something in the client's event queue. */
 
765
    VBOXHOSTCHANNELEVENT *pEvent = RTListGetFirst(&pClient->listEvents, VBOXHOSTCHANNELEVENT, NodeEvent);
 
766
 
 
767
    HOSTCHLOG(("HostChannel: QueryEvent: (%d), event %p\n", pClient->u32ClientID, pEvent));
 
768
 
 
769
    if (pEvent)
 
770
    {
 
771
        /* Report the event. */
 
772
        RTListNodeRemove(&pEvent->NodeEvent);
 
773
 
 
774
        HOSTCHLOG(("HostChannel: QueryEvent: (%d), cbEvent %d\n",
 
775
                   pClient->u32ClientID, pEvent->cbEvent));
 
776
 
 
777
        vboxHostChannelEventParmsSet(paParms, pEvent->u32ChannelHandle,
 
778
                                     pEvent->u32Id, pEvent->pvEvent, pEvent->cbEvent);
 
779
 
 
780
        *pfEvent = true;
 
781
 
 
782
        RTMemFree(pEvent);
 
783
    }
 
784
    else
 
785
    {
 
786
        /* No event available at the time. Process asynchronously. */
 
787
        pClient->fAsync           = true;
 
788
        pClient->async.callHandle = callHandle;
 
789
        pClient->async.paParms    = paParms;
 
790
 
 
791
        /* Tell the caller that there is no event. */
 
792
        *pfEvent = false;
 
793
    }
 
794
 
 
795
    vboxHostChannelUnlock();
 
796
    return rc;
 
797
}
 
798
 
 
799
int vboxHostChannelEventCancel(VBOXHOSTCHCLIENT *pClient)
 
800
{
 
801
    int rc = vboxHostChannelLock();
 
802
 
 
803
    if (RT_SUCCESS(rc))
 
804
    {
 
805
        if (pClient->fAsync)
 
806
        {
 
807
            /* If there is a wait request alredy, cancel it. */
 
808
            vboxHostChannelReportAsync(pClient, 0, VBOX_HOST_CHANNEL_EVENT_CANCELLED, NULL, 0);
 
809
 
 
810
            pClient->fAsync = false;
 
811
        }
 
812
 
 
813
        vboxHostChannelUnlock();
 
814
    }
 
815
 
 
816
    return rc;
 
817
}
 
818
 
 
819
/* @thread provider */
 
820
static DECLCALLBACK(void) HostChannelCallbackEvent(void *pvCallbacks, void *pvChannel,
 
821
                                                   uint32_t u32Id, const void *pvEvent, uint32_t cbEvent)
 
822
{
 
823
    VBOXHOSTCHCALLBACKCTX *pCallbackCtx = (VBOXHOSTCHCALLBACKCTX *)pvCallbacks;
 
824
 
 
825
    int rc = vboxHostChannelLock();
 
826
    if (RT_FAILURE(rc))
 
827
    {
 
828
        return;
 
829
    }
 
830
 
 
831
    /* Check that the structure is still associated with a client.
 
832
     * The client can disconnect and will be invalid.
 
833
     */
 
834
    VBOXHOSTCHCLIENT *pClient = pCallbackCtx->pClient;
 
835
 
 
836
    if (pClient == NULL)
 
837
    {
 
838
        vboxHostChannelUnlock();
 
839
 
 
840
        HOSTCHLOG(("HostChannel: CallbackEvent[%p]: client gone.\n"));
 
841
 
 
842
        /* The client does not exist anymore, skip the event. */
 
843
        return;
 
844
    }
 
845
 
 
846
    bool fFound = false;
 
847
 
 
848
    VBOXHOSTCHCALLBACKCTX *pIter;
 
849
    RTListForEach(&pClient->listContexts, pIter, VBOXHOSTCHCALLBACKCTX, nodeClient)
 
850
    {
 
851
        if (pIter == pCallbackCtx)
 
852
        {
 
853
            fFound = true;
 
854
            break;
 
855
        }
 
856
    }
 
857
 
 
858
    if (!fFound)
 
859
    {
 
860
        AssertFailed();
 
861
 
 
862
        vboxHostChannelUnlock();
 
863
 
 
864
        HOSTCHLOG(("HostChannel: CallbackEvent[%p]: client does not have the context.\n"));
 
865
 
 
866
        /* The context is not in the list of contexts. Skip the event. */
 
867
        return;
 
868
    }
 
869
 
 
870
    VBOXHOSTCHINSTANCE *pInstance = vhcInstanceFindByChannelPtr(pClient, pvChannel);
 
871
 
 
872
    HOSTCHLOG(("HostChannel: CallbackEvent[%p]: (%d) instance %p\n",
 
873
               pCallbackCtx, pClient->u32ClientID, pInstance));
 
874
 
 
875
    if (!pInstance)
 
876
    {
 
877
        /* Instance was already detached. Skip the event. */
 
878
        vboxHostChannelUnlock();
 
879
 
 
880
        return;
 
881
    }
 
882
 
 
883
    uint32_t u32ChannelHandle = pInstance->u32Handle;
 
884
 
 
885
    HOSTCHLOG(("HostChannel: CallbackEvent: (%d) handle %d, async %d, cbEvent %d\n",
 
886
               pClient->u32ClientID, u32ChannelHandle, pClient->fAsync, cbEvent));
 
887
 
 
888
    /* Check whether the event is waited. */
 
889
    if (pClient->fAsync)
 
890
    {
 
891
        /* Report the event. */
 
892
        vboxHostChannelReportAsync(pClient, u32ChannelHandle, u32Id, pvEvent, cbEvent);
 
893
 
 
894
        pClient->fAsync = false;
 
895
    }
 
896
    else
 
897
    {
 
898
        /* Put it to the queue. */
 
899
        VBOXHOSTCHANNELEVENT *pEvent = (VBOXHOSTCHANNELEVENT *)RTMemAlloc(sizeof(VBOXHOSTCHANNELEVENT) + cbEvent);
 
900
 
 
901
        if (pEvent)
 
902
        {
 
903
            pEvent->u32ChannelHandle = u32ChannelHandle;
 
904
            pEvent->u32Id = u32Id;
 
905
 
 
906
            if (cbEvent)
 
907
            {
 
908
                pEvent->pvEvent = &pEvent[1];
 
909
                memcpy(pEvent->pvEvent, pvEvent, cbEvent);
 
910
            }
 
911
            else
 
912
            {
 
913
                pEvent->pvEvent = NULL;
 
914
            }
 
915
 
 
916
            pEvent->cbEvent = cbEvent;
 
917
 
 
918
            RTListAppend(&pClient->listEvents, &pEvent->NodeEvent);
 
919
        }
 
920
    }
 
921
 
 
922
    vboxHostChannelUnlock();
 
923
 
 
924
    vhcInstanceRelease(pInstance);
 
925
}
 
926
 
 
927
/* @thread provider */
 
928
static DECLCALLBACK(void) HostChannelCallbackDeleted(void *pvCallbacks, void *pvChannel)
 
929
{
 
930
    vhcCallbackCtxDelete((VBOXHOSTCHCALLBACKCTX *)pvCallbacks);
 
931
}
 
932
 
 
933
int vboxHostChannelQuery(VBOXHOSTCHCLIENT *pClient,
 
934
                         const char *pszName,
 
935
                         uint32_t u32Code,
 
936
                         void *pvParm,
 
937
                         uint32_t cbParm,
 
938
                         void *pvData,
 
939
                         uint32_t cbData,
 
940
                         uint32_t *pu32SizeDataReturned)
 
941
{
 
942
    HOSTCHLOG(("HostChannel: Query: (%d) name [%s], cbData %d\n", pClient->u32ClientID, pszName, cbData));
 
943
 
 
944
    int rc = VINF_SUCCESS;
 
945
 
 
946
    /* Look if there is a provider. */
 
947
    VBOXHOSTCHPROVIDER *pProvider = vhcProviderFind(pClient->pCtx, pszName);
 
948
 
 
949
    if (pProvider)
 
950
    {
 
951
        pProvider->iface.HostChannelControl(NULL, u32Code,
 
952
                                            pvParm, cbParm,
 
953
                                            pvData, cbData, pu32SizeDataReturned);
 
954
 
 
955
        vhcProviderRelease(pProvider);
 
956
    }
 
957
    else
 
958
    {
 
959
        rc = VERR_NOT_SUPPORTED;
 
960
    }
 
961
 
 
962
    return rc;
 
963
}
 
964
 
 
965
int vboxHostChannelRegister(const char *pszName,
 
966
                            const VBOXHOSTCHANNELINTERFACE *pInterface,
 
967
                            uint32_t cbInterface)
 
968
{
 
969
    int rc = VINF_SUCCESS;
 
970
 
 
971
    VBOXHOSTCHCTX *pCtx = &g_ctx;
 
972
 
 
973
    VBOXHOSTCHPROVIDER *pProvider = (VBOXHOSTCHPROVIDER *)RTMemAllocZ(sizeof(VBOXHOSTCHPROVIDER));
 
974
 
 
975
    if (pProvider)
 
976
    {
 
977
        pProvider->pCtx = pCtx;
 
978
        pProvider->iface = *pInterface;
 
979
 
 
980
        RTListInit(&pProvider->listChannels);
 
981
 
 
982
        pProvider->pszName = RTStrDup(pszName);
 
983
        if (pProvider->pszName)
 
984
        {
 
985
            vhcProviderAddRef(pProvider);
 
986
            rc = vhcProviderRegister(pCtx, pProvider);
 
987
        }
 
988
        else
 
989
        {
 
990
            RTMemFree(pProvider);
 
991
            rc = VERR_NO_MEMORY;
 
992
        }
 
993
    }
 
994
    else
 
995
    {
 
996
        rc = VERR_NO_MEMORY;
 
997
    }
 
998
 
 
999
    return rc;
 
1000
}
 
1001
 
 
1002
int vboxHostChannelUnregister(const char *pszName)
 
1003
{
 
1004
    int rc = VINF_SUCCESS;
 
1005
 
 
1006
    VBOXHOSTCHCTX *pCtx = &g_ctx;
 
1007
 
 
1008
    VBOXHOSTCHPROVIDER *pProvider = vhcProviderFind(pCtx, pszName);
 
1009
 
 
1010
    if (pProvider)
 
1011
    {
 
1012
        rc = vhcProviderUnregister(pProvider);
 
1013
        vhcProviderRelease(pProvider);
 
1014
    }
 
1015
 
 
1016
    return rc;
 
1017
}