VirtualBox

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

Last change on this file since 103068 was 98103, checked in by vboxsync, 23 months ago

Copyright year updates by scm.

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