VirtualBox

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

Last change on this file since 62517 was 62489, checked in by vboxsync, 8 years ago

(C) 2016

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 25.6 KB
Line 
1/** @file
2 * Host channel.
3 */
4
5/*
6 * Copyright (C) 2012-2016 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 HOSTCHLOG(("HostChannel: destroy %p\n", pInstance));
232}
233
234static int32_t vhcInstanceAddRef(VBOXHOSTCHINSTANCE *pInstance)
235{
236 HOSTCHLOG(("INST: %p %d addref\n", pInstance, pInstance->cRefs));
237 return ASMAtomicIncS32(&pInstance->cRefs);
238}
239
240static 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
252static 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
294static 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
322static 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
355static 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 */
383static 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
418static 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
474int 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
489void 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
502int 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
517void 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
543int 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
616int 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
639int 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
667int 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, cbData %d, 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
701int 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
735typedef 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
746int 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
799int 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 */
820static 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", pvEvent));
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", pvEvent));
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 */
928static DECLCALLBACK(void) HostChannelCallbackDeleted(void *pvCallbacks, void *pvChannel)
929{
930 vhcCallbackCtxDelete((VBOXHOSTCHCALLBACKCTX *)pvCallbacks);
931}
932
933int 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
965int 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
1002int 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}
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