VirtualBox

source: vbox/trunk/src/VBox/HostServices/HostChannel/HostChannel.cpp@ 72549

Last change on this file since 72549 was 69500, checked in by vboxsync, 7 years ago

*: scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 25.7 KB
Line 
1/** @file
2 * Host channel.
3 */
4
5/*
6 * Copyright (C) 2012-2017 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
25static DECLCALLBACK(void) HostChannelCallbackEvent(void *pvCallbacks, void *pvInstance,
26 uint32_t u32Id, const void *pvEvent, uint32_t cbEvent);
27static DECLCALLBACK(void) HostChannelCallbackDeleted(void *pvCallbacks, void *pvChannel);
28
29
30/* A registered provider of channels. */
31typedef 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. */
47typedef 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
60struct 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 */
70typedef 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. */
78static VBOXHOSTCHCTX g_ctx = { false };
79
80static VBOXHOSTCHANNELCALLBACKS g_callbacks =
81{
82 HostChannelCallbackEvent,
83 HostChannelCallbackDeleted
84};
85
86
87/*
88 * Provider management.
89 */
90
91static void vhcProviderDestroy(VBOXHOSTCHPROVIDER *pProvider)
92{
93 RTStrFree(pProvider->pszName);
94}
95
96static int32_t vhcProviderAddRef(VBOXHOSTCHPROVIDER *pProvider)
97{
98 return ASMAtomicIncS32(&pProvider->cRefs);
99}
100
101static 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
112static 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
139static 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
160static 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 */
184static 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
229static void vhcInstanceDestroy(VBOXHOSTCHINSTANCE *pInstance)
230{
231 RT_NOREF1(pInstance);
232 HOSTCHLOG(("HostChannel: destroy %p\n", pInstance));
233}
234
235static int32_t vhcInstanceAddRef(VBOXHOSTCHINSTANCE *pInstance)
236{
237 HOSTCHLOG(("INST: %p %d addref\n", pInstance, pInstance->cRefs));
238 return ASMAtomicIncS32(&pInstance->cRefs);
239}
240
241static void vhcInstanceRelease(VBOXHOSTCHINSTANCE *pInstance)
242{
243 int32_t c = ASMAtomicDecS32(&pInstance->cRefs);
244 HOSTCHLOG(("INST: %p %d release\n", pInstance, pInstance->cRefs));
245 Assert(c >= 0);
246 if (c == 0)
247 {
248 vhcInstanceDestroy(pInstance);
249 RTMemFree(pInstance);
250 }
251}
252
253static int vhcInstanceCreate(VBOXHOSTCHCLIENT *pClient, VBOXHOSTCHINSTANCE **ppInstance)
254{
255 int rc = VINF_SUCCESS;
256
257 VBOXHOSTCHINSTANCE *pInstance = (VBOXHOSTCHINSTANCE *)RTMemAllocZ(sizeof(VBOXHOSTCHINSTANCE));
258
259 if (pInstance)
260 {
261 rc = vboxHostChannelLock();
262
263 if (RT_SUCCESS(rc))
264 {
265 rc = vhcHandleCreate(pClient, &pInstance->u32Handle);
266
267 if (RT_SUCCESS(rc))
268 {
269 /* Used by the client, that is in the list of channels. */
270 vhcInstanceAddRef(pInstance);
271 /* Add to the list of created channel instances. It is inactive while pClient is 0. */
272 RTListAppend(&pClient->listChannels, &pInstance->nodeClient);
273
274 /* Return to the caller. */
275 vhcInstanceAddRef(pInstance);
276 *ppInstance = pInstance;
277 }
278
279 vboxHostChannelUnlock();
280 }
281
282 if (RT_FAILURE(rc))
283 {
284 RTMemFree(pInstance);
285 }
286 }
287 else
288 {
289 rc = VERR_NO_MEMORY;
290 }
291
292 return rc;
293}
294
295static VBOXHOSTCHINSTANCE *vhcInstanceFind(VBOXHOSTCHCLIENT *pClient, uint32_t u32Handle)
296{
297 VBOXHOSTCHINSTANCE *pInstance = NULL;
298
299 int rc = vboxHostChannelLock();
300
301 if (RT_SUCCESS(rc))
302 {
303 VBOXHOSTCHINSTANCE *pIter;
304 RTListForEach(&pClient->listChannels, pIter, VBOXHOSTCHINSTANCE, nodeClient)
305 {
306 if ( pIter->pClient
307 && pIter->u32Handle == u32Handle)
308 {
309 pInstance = pIter;
310
311 vhcInstanceAddRef(pInstance);
312
313 break;
314 }
315 }
316
317 vboxHostChannelUnlock();
318 }
319
320 return pInstance;
321}
322
323static VBOXHOSTCHINSTANCE *vhcInstanceFindByChannelPtr(VBOXHOSTCHCLIENT *pClient, void *pvChannel)
324{
325 VBOXHOSTCHINSTANCE *pInstance = NULL;
326
327 if (pvChannel == NULL)
328 {
329 return NULL;
330 }
331
332 int rc = vboxHostChannelLock();
333
334 if (RT_SUCCESS(rc))
335 {
336 VBOXHOSTCHINSTANCE *pIter;
337 RTListForEach(&pClient->listChannels, pIter, VBOXHOSTCHINSTANCE, nodeClient)
338 {
339 if ( pIter->pClient
340 && pIter->pvChannel == pvChannel)
341 {
342 pInstance = pIter;
343
344 vhcInstanceAddRef(pInstance);
345
346 break;
347 }
348 }
349
350 vboxHostChannelUnlock();
351 }
352
353 return pInstance;
354}
355
356static void vhcInstanceDetach(VBOXHOSTCHINSTANCE *pInstance)
357{
358 HOSTCHLOG(("HostChannel: detach %p\n", pInstance));
359
360 if (pInstance->pProvider)
361 {
362 pInstance->pProvider->iface.HostChannelDetach(pInstance->pvChannel);
363 RTListNodeRemove(&pInstance->nodeProvider);
364 vhcProviderRelease(pInstance->pProvider);
365 pInstance->pProvider = NULL;
366 vhcInstanceRelease(pInstance); /* Not in the provider's list anymore. */
367 }
368
369 int rc = vboxHostChannelLock();
370
371 if (RT_SUCCESS(rc))
372 {
373 RTListNodeRemove(&pInstance->nodeClient);
374
375 vboxHostChannelUnlock();
376
377 vhcInstanceRelease(pInstance); /* Not used by the client anymore. */
378 }
379}
380
381/*
382 * Channel callback contexts.
383 */
384static int vhcCallbackCtxCreate(VBOXHOSTCHCLIENT *pClient, VBOXHOSTCHCALLBACKCTX **ppCallbackCtx)
385{
386 int rc = VINF_SUCCESS;
387
388 VBOXHOSTCHCALLBACKCTX *pCallbackCtx = (VBOXHOSTCHCALLBACKCTX *)RTMemAllocZ(sizeof(VBOXHOSTCHCALLBACKCTX));
389
390 if (pCallbackCtx != NULL)
391 {
392 /* The callback context is accessed by the providers threads. */
393 rc = vboxHostChannelLock();
394 if (RT_SUCCESS(rc))
395 {
396 RTListAppend(&pClient->listContexts, &pCallbackCtx->nodeClient);
397 pCallbackCtx->pClient = pClient;
398
399 vboxHostChannelUnlock();
400 }
401 else
402 {
403 RTMemFree(pCallbackCtx);
404 }
405 }
406 else
407 {
408 rc = VERR_NO_MEMORY;
409 }
410
411 if (RT_SUCCESS(rc))
412 {
413 *ppCallbackCtx = pCallbackCtx;
414 }
415
416 return rc;
417}
418
419static int vhcCallbackCtxDelete(VBOXHOSTCHCALLBACKCTX *pCallbackCtx)
420{
421 int rc = vboxHostChannelLock();
422 if (RT_SUCCESS(rc))
423 {
424 VBOXHOSTCHCLIENT *pClient = pCallbackCtx->pClient;
425
426 if (pClient != NULL)
427 {
428 /* The callback is associated with a client.
429 * Check that the callback is in the list and remove it from the list.
430 */
431 bool fFound = false;
432
433 VBOXHOSTCHCALLBACKCTX *pIter;
434 RTListForEach(&pClient->listContexts, pIter, VBOXHOSTCHCALLBACKCTX, nodeClient)
435 {
436 if (pIter == pCallbackCtx)
437 {
438 fFound = true;
439 break;
440 }
441 }
442
443 if (fFound)
444 {
445 RTListNodeRemove(&pCallbackCtx->nodeClient);
446 }
447 else
448 {
449 AssertFailed();
450 rc = VERR_INVALID_PARAMETER;
451 }
452 }
453 else
454 {
455 /* It is not in the clients anymore. May be the client has been disconnected.
456 * Just free the memory.
457 */
458 }
459
460 vboxHostChannelUnlock();
461 }
462
463 if (RT_SUCCESS(rc))
464 {
465 RTMemFree(pCallbackCtx);
466 }
467
468 return rc;
469}
470
471/*
472 * Host channel service functions.
473 */
474
475int vboxHostChannelInit(void)
476{
477 VBOXHOSTCHCTX *pCtx = &g_ctx;
478
479 if (pCtx->fInitialized)
480 {
481 return VERR_NOT_SUPPORTED;
482 }
483
484 pCtx->fInitialized = true;
485 RTListInit(&pCtx->listProviders);
486
487 return VINF_SUCCESS;
488}
489
490void vboxHostChannelDestroy(void)
491{
492 VBOXHOSTCHCTX *pCtx = &g_ctx;
493
494 VBOXHOSTCHPROVIDER *pIter;
495 VBOXHOSTCHPROVIDER *pIterNext;
496 RTListForEachSafe(&pCtx->listProviders, pIter, pIterNext, VBOXHOSTCHPROVIDER, nodeContext)
497 {
498 vhcProviderUnregister(pIter);
499 }
500 pCtx->fInitialized = false;
501}
502
503int vboxHostChannelClientConnect(VBOXHOSTCHCLIENT *pClient)
504{
505 /* A guest client is connecting to the service.
506 * Later the client will use Attach calls to connect to channel providers.
507 * pClient is already zeroed.
508 */
509 pClient->pCtx = &g_ctx;
510
511 RTListInit(&pClient->listChannels);
512 RTListInit(&pClient->listEvents);
513 RTListInit(&pClient->listContexts);
514
515 return VINF_SUCCESS;
516}
517
518void vboxHostChannelClientDisconnect(VBOXHOSTCHCLIENT *pClient)
519{
520 /* Clear the list of contexts and prevent acceess to the client. */
521 int rc = vboxHostChannelLock();
522 if (RT_SUCCESS(rc))
523 {
524 VBOXHOSTCHCALLBACKCTX *pIter;
525 VBOXHOSTCHCALLBACKCTX *pNext;
526 RTListForEachSafe(&pClient->listContexts, pIter, pNext, VBOXHOSTCHCALLBACKCTX, nodeClient)
527 {
528 pIter->pClient = NULL;
529 RTListNodeRemove(&pIter->nodeClient);
530 }
531
532 vboxHostChannelUnlock();
533 }
534
535 /* If there are attached channels, detach them. */
536 VBOXHOSTCHINSTANCE *pIter;
537 VBOXHOSTCHINSTANCE *pIterNext;
538 RTListForEachSafe(&pClient->listChannels, pIter, pIterNext, VBOXHOSTCHINSTANCE, nodeClient)
539 {
540 vhcInstanceDetach(pIter);
541 }
542}
543
544int vboxHostChannelAttach(VBOXHOSTCHCLIENT *pClient,
545 uint32_t *pu32Handle,
546 const char *pszName,
547 uint32_t u32Flags)
548{
549 int rc = VINF_SUCCESS;
550
551 HOSTCHLOG(("HostChannel: Attach: (%d) [%s] 0x%08X\n", pClient->u32ClientID, pszName, u32Flags));
552
553 /* Look if there is a provider. */
554 VBOXHOSTCHPROVIDER *pProvider = vhcProviderFind(pClient->pCtx, pszName);
555
556 if (pProvider)
557 {
558 VBOXHOSTCHINSTANCE *pInstance = NULL;
559
560 rc = vhcInstanceCreate(pClient, &pInstance);
561
562 if (RT_SUCCESS(rc))
563 {
564 VBOXHOSTCHCALLBACKCTX *pCallbackCtx = NULL;
565 rc = vhcCallbackCtxCreate(pClient, &pCallbackCtx);
566
567 if (RT_SUCCESS(rc))
568 {
569 void *pvChannel = NULL;
570 rc = pProvider->iface.HostChannelAttach(pProvider->iface.pvProvider,
571 &pvChannel,
572 u32Flags,
573 &g_callbacks, pCallbackCtx);
574
575 if (RT_SUCCESS(rc))
576 {
577 vhcProviderAddRef(pProvider);
578 pInstance->pProvider = pProvider;
579
580 pInstance->pClient = pClient;
581 pInstance->pvChannel = pvChannel;
582
583 /* It is already in the channels list of the client. */
584
585 vhcInstanceAddRef(pInstance); /* Referenced by the list of provider's channels. */
586 RTListAppend(&pProvider->listChannels, &pInstance->nodeProvider);
587
588 *pu32Handle = pInstance->u32Handle;
589
590 HOSTCHLOG(("HostChannel: Attach: (%d) handle %d\n", pClient->u32ClientID, pInstance->u32Handle));
591 }
592
593 if (RT_FAILURE(rc))
594 {
595 vhcCallbackCtxDelete(pCallbackCtx);
596 }
597 }
598
599 if (RT_FAILURE(rc))
600 {
601 vhcInstanceDetach(pInstance);
602 }
603
604 vhcInstanceRelease(pInstance);
605 }
606
607 vhcProviderRelease(pProvider);
608 }
609 else
610 {
611 rc = VERR_NOT_SUPPORTED;
612 }
613
614 return rc;
615}
616
617int vboxHostChannelDetach(VBOXHOSTCHCLIENT *pClient,
618 uint32_t u32Handle)
619{
620 HOSTCHLOG(("HostChannel: Detach: (%d) handle %d\n", pClient->u32ClientID, u32Handle));
621
622 int rc = VINF_SUCCESS;
623
624 VBOXHOSTCHINSTANCE *pInstance = vhcInstanceFind(pClient, u32Handle);
625
626 if (pInstance)
627 {
628 vhcInstanceDetach(pInstance);
629
630 vhcInstanceRelease(pInstance);
631 }
632 else
633 {
634 rc = VERR_NOT_SUPPORTED;
635 }
636
637 return rc;
638}
639
640int vboxHostChannelSend(VBOXHOSTCHCLIENT *pClient,
641 uint32_t u32Handle,
642 const void *pvData,
643 uint32_t cbData)
644{
645 HOSTCHLOG(("HostChannel: Send: (%d) handle %d, %d bytes\n", pClient->u32ClientID, u32Handle, cbData));
646
647 int rc = VINF_SUCCESS;
648
649 VBOXHOSTCHINSTANCE *pInstance = vhcInstanceFind(pClient, u32Handle);
650
651 if (pInstance)
652 {
653 if (pInstance->pProvider)
654 {
655 pInstance->pProvider->iface.HostChannelSend(pInstance->pvChannel, pvData, cbData);
656 }
657
658 vhcInstanceRelease(pInstance);
659 }
660 else
661 {
662 rc = VERR_NOT_SUPPORTED;
663 }
664
665 return rc;
666}
667
668int vboxHostChannelRecv(VBOXHOSTCHCLIENT *pClient,
669 uint32_t u32Handle,
670 void *pvData,
671 uint32_t cbData,
672 uint32_t *pu32SizeReceived,
673 uint32_t *pu32SizeRemaining)
674{
675 HOSTCHLOG(("HostChannel: Recv: (%d) handle %d, cbData %d\n", pClient->u32ClientID, u32Handle, cbData));
676
677 int rc = VINF_SUCCESS;
678
679 VBOXHOSTCHINSTANCE *pInstance = vhcInstanceFind(pClient, u32Handle);
680
681 if (pInstance)
682 {
683 if (pInstance->pProvider)
684 {
685 rc = pInstance->pProvider->iface.HostChannelRecv(pInstance->pvChannel, pvData, cbData,
686 pu32SizeReceived, pu32SizeRemaining);
687
688 HOSTCHLOG(("HostChannel: Recv: (%d) handle %d, rc %Rrc, cbData %d, recv %d, rem %d\n",
689 pClient->u32ClientID, u32Handle, rc, cbData, *pu32SizeReceived, *pu32SizeRemaining));
690 }
691
692 vhcInstanceRelease(pInstance);
693 }
694 else
695 {
696 rc = VERR_NOT_SUPPORTED;
697 }
698
699 return rc;
700}
701
702int vboxHostChannelControl(VBOXHOSTCHCLIENT *pClient,
703 uint32_t u32Handle,
704 uint32_t u32Code,
705 void *pvParm,
706 uint32_t cbParm,
707 void *pvData,
708 uint32_t cbData,
709 uint32_t *pu32SizeDataReturned)
710{
711 HOSTCHLOG(("HostChannel: Control: (%d) handle %d, cbData %d\n", pClient->u32ClientID, u32Handle, cbData));
712
713 int rc = VINF_SUCCESS;
714
715 VBOXHOSTCHINSTANCE *pInstance = vhcInstanceFind(pClient, u32Handle);
716
717 if (pInstance)
718 {
719 if (pInstance->pProvider)
720 {
721 pInstance->pProvider->iface.HostChannelControl(pInstance->pvChannel, u32Code,
722 pvParm, cbParm,
723 pvData, cbData, pu32SizeDataReturned);
724 }
725
726 vhcInstanceRelease(pInstance);
727 }
728 else
729 {
730 rc = VERR_NOT_SUPPORTED;
731 }
732
733 return rc;
734}
735
736typedef struct VBOXHOSTCHANNELEVENT
737{
738 RTLISTNODE NodeEvent;
739
740 uint32_t u32ChannelHandle;
741
742 uint32_t u32Id;
743 void *pvEvent;
744 uint32_t cbEvent;
745} VBOXHOSTCHANNELEVENT;
746
747int vboxHostChannelEventWait(VBOXHOSTCHCLIENT *pClient,
748 bool *pfEvent,
749 VBOXHGCMCALLHANDLE callHandle,
750 VBOXHGCMSVCPARM *paParms)
751{
752 int rc = vboxHostChannelLock();
753 if (RT_FAILURE(rc))
754 {
755 return rc;
756 }
757
758 if (pClient->fAsync)
759 {
760 /* If there is a wait request already, cancel it. */
761 vboxHostChannelReportAsync(pClient, 0, VBOX_HOST_CHANNEL_EVENT_CANCELLED, NULL, 0);
762 pClient->fAsync = false;
763 }
764
765 /* Check if there is something in the client's event queue. */
766 VBOXHOSTCHANNELEVENT *pEvent = RTListGetFirst(&pClient->listEvents, VBOXHOSTCHANNELEVENT, NodeEvent);
767
768 HOSTCHLOG(("HostChannel: QueryEvent: (%d), event %p\n", pClient->u32ClientID, pEvent));
769
770 if (pEvent)
771 {
772 /* Report the event. */
773 RTListNodeRemove(&pEvent->NodeEvent);
774
775 HOSTCHLOG(("HostChannel: QueryEvent: (%d), cbEvent %d\n",
776 pClient->u32ClientID, pEvent->cbEvent));
777
778 vboxHostChannelEventParmsSet(paParms, pEvent->u32ChannelHandle,
779 pEvent->u32Id, pEvent->pvEvent, pEvent->cbEvent);
780
781 *pfEvent = true;
782
783 RTMemFree(pEvent);
784 }
785 else
786 {
787 /* No event available at the time. Process asynchronously. */
788 pClient->fAsync = true;
789 pClient->async.callHandle = callHandle;
790 pClient->async.paParms = paParms;
791
792 /* Tell the caller that there is no event. */
793 *pfEvent = false;
794 }
795
796 vboxHostChannelUnlock();
797 return rc;
798}
799
800int vboxHostChannelEventCancel(VBOXHOSTCHCLIENT *pClient)
801{
802 int rc = vboxHostChannelLock();
803
804 if (RT_SUCCESS(rc))
805 {
806 if (pClient->fAsync)
807 {
808 /* If there is a wait request alredy, cancel it. */
809 vboxHostChannelReportAsync(pClient, 0, VBOX_HOST_CHANNEL_EVENT_CANCELLED, NULL, 0);
810
811 pClient->fAsync = false;
812 }
813
814 vboxHostChannelUnlock();
815 }
816
817 return rc;
818}
819
820/* @thread provider */
821static DECLCALLBACK(void) HostChannelCallbackEvent(void *pvCallbacks, void *pvChannel,
822 uint32_t u32Id, const void *pvEvent, uint32_t cbEvent)
823{
824 VBOXHOSTCHCALLBACKCTX *pCallbackCtx = (VBOXHOSTCHCALLBACKCTX *)pvCallbacks;
825
826 int rc = vboxHostChannelLock();
827 if (RT_FAILURE(rc))
828 {
829 return;
830 }
831
832 /* Check that the structure is still associated with a client.
833 * The client can disconnect and will be invalid.
834 */
835 VBOXHOSTCHCLIENT *pClient = pCallbackCtx->pClient;
836
837 if (pClient == NULL)
838 {
839 vboxHostChannelUnlock();
840
841 HOSTCHLOG(("HostChannel: CallbackEvent[%p]: client gone.\n", pvEvent));
842
843 /* The client does not exist anymore, skip the event. */
844 return;
845 }
846
847 bool fFound = false;
848
849 VBOXHOSTCHCALLBACKCTX *pIter;
850 RTListForEach(&pClient->listContexts, pIter, VBOXHOSTCHCALLBACKCTX, nodeClient)
851 {
852 if (pIter == pCallbackCtx)
853 {
854 fFound = true;
855 break;
856 }
857 }
858
859 if (!fFound)
860 {
861 AssertFailed();
862
863 vboxHostChannelUnlock();
864
865 HOSTCHLOG(("HostChannel: CallbackEvent[%p]: client does not have the context.\n", pvEvent));
866
867 /* The context is not in the list of contexts. Skip the event. */
868 return;
869 }
870
871 VBOXHOSTCHINSTANCE *pInstance = vhcInstanceFindByChannelPtr(pClient, pvChannel);
872
873 HOSTCHLOG(("HostChannel: CallbackEvent[%p]: (%d) instance %p\n",
874 pCallbackCtx, pClient->u32ClientID, pInstance));
875
876 if (!pInstance)
877 {
878 /* Instance was already detached. Skip the event. */
879 vboxHostChannelUnlock();
880
881 return;
882 }
883
884 uint32_t u32ChannelHandle = pInstance->u32Handle;
885
886 HOSTCHLOG(("HostChannel: CallbackEvent: (%d) handle %d, async %d, cbEvent %d\n",
887 pClient->u32ClientID, u32ChannelHandle, pClient->fAsync, cbEvent));
888
889 /* Check whether the event is waited. */
890 if (pClient->fAsync)
891 {
892 /* Report the event. */
893 vboxHostChannelReportAsync(pClient, u32ChannelHandle, u32Id, pvEvent, cbEvent);
894
895 pClient->fAsync = false;
896 }
897 else
898 {
899 /* Put it to the queue. */
900 VBOXHOSTCHANNELEVENT *pEvent = (VBOXHOSTCHANNELEVENT *)RTMemAlloc(sizeof(VBOXHOSTCHANNELEVENT) + cbEvent);
901
902 if (pEvent)
903 {
904 pEvent->u32ChannelHandle = u32ChannelHandle;
905 pEvent->u32Id = u32Id;
906
907 if (cbEvent)
908 {
909 pEvent->pvEvent = &pEvent[1];
910 memcpy(pEvent->pvEvent, pvEvent, cbEvent);
911 }
912 else
913 {
914 pEvent->pvEvent = NULL;
915 }
916
917 pEvent->cbEvent = cbEvent;
918
919 RTListAppend(&pClient->listEvents, &pEvent->NodeEvent);
920 }
921 }
922
923 vboxHostChannelUnlock();
924
925 vhcInstanceRelease(pInstance);
926}
927
928/* @thread provider */
929static DECLCALLBACK(void) HostChannelCallbackDeleted(void *pvCallbacks, void *pvChannel)
930{
931 RT_NOREF1(pvChannel);
932 vhcCallbackCtxDelete((VBOXHOSTCHCALLBACKCTX *)pvCallbacks);
933}
934
935int vboxHostChannelQuery(VBOXHOSTCHCLIENT *pClient,
936 const char *pszName,
937 uint32_t u32Code,
938 void *pvParm,
939 uint32_t cbParm,
940 void *pvData,
941 uint32_t cbData,
942 uint32_t *pu32SizeDataReturned)
943{
944 HOSTCHLOG(("HostChannel: Query: (%d) name [%s], cbData %d\n", pClient->u32ClientID, pszName, cbData));
945
946 int rc = VINF_SUCCESS;
947
948 /* Look if there is a provider. */
949 VBOXHOSTCHPROVIDER *pProvider = vhcProviderFind(pClient->pCtx, pszName);
950
951 if (pProvider)
952 {
953 pProvider->iface.HostChannelControl(NULL, u32Code,
954 pvParm, cbParm,
955 pvData, cbData, pu32SizeDataReturned);
956
957 vhcProviderRelease(pProvider);
958 }
959 else
960 {
961 rc = VERR_NOT_SUPPORTED;
962 }
963
964 return rc;
965}
966
967int vboxHostChannelRegister(const char *pszName,
968 const VBOXHOSTCHANNELINTERFACE *pInterface,
969 uint32_t cbInterface)
970{
971 RT_NOREF1(cbInterface);
972 int rc = VINF_SUCCESS;
973
974 VBOXHOSTCHCTX *pCtx = &g_ctx;
975
976 VBOXHOSTCHPROVIDER *pProvider = (VBOXHOSTCHPROVIDER *)RTMemAllocZ(sizeof(VBOXHOSTCHPROVIDER));
977
978 if (pProvider)
979 {
980 pProvider->pCtx = pCtx;
981 pProvider->iface = *pInterface;
982
983 RTListInit(&pProvider->listChannels);
984
985 pProvider->pszName = RTStrDup(pszName);
986 if (pProvider->pszName)
987 {
988 vhcProviderAddRef(pProvider);
989 rc = vhcProviderRegister(pCtx, pProvider);
990 }
991 else
992 {
993 RTMemFree(pProvider);
994 rc = VERR_NO_MEMORY;
995 }
996 }
997 else
998 {
999 rc = VERR_NO_MEMORY;
1000 }
1001
1002 return rc;
1003}
1004
1005int vboxHostChannelUnregister(const char *pszName)
1006{
1007 int rc = VINF_SUCCESS;
1008
1009 VBOXHOSTCHCTX *pCtx = &g_ctx;
1010
1011 VBOXHOSTCHPROVIDER *pProvider = vhcProviderFind(pCtx, pszName);
1012
1013 if (pProvider)
1014 {
1015 rc = vhcProviderUnregister(pProvider);
1016 vhcProviderRelease(pProvider);
1017 }
1018
1019 return rc;
1020}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette