HostChannel.cpp revision e2a4ff87ea2e2e95350793b5fccb143c1819fadc
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync * Host channel.
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync * Copyright (C) 2012 Oracle Corporation
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync * available from http://www.virtualbox.org. This file is free software;
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync * you can redistribute it and/or modify it under the terms of the GNU
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync * General Public License (GPL) as published by the Free Software
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsyncstatic DECLCALLBACK(void) HostChannelCallbackEvent(void *pvCallbacks, void *pvInstance,
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync uint32_t u32Id, const void *pvEvent, uint32_t cbEvent);
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync/* A registered provider of channels. */
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync RTLISTNODE nodeContext; /* Member of the list of providers in the service context. */
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync/* An established channel. */
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync RTLISTNODE nodeClient; /* In the client, for cleanup when a client disconnects. */
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync RTLISTNODE nodeProvider; /* In the provider, needed for cleanup when the provider is unregistered. */
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync VBOXHOSTCHCLIENT *pClient; /* The client which uses the channel. */
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync VBOXHOSTCHPROVIDER *pProvider; /* NULL if the provider was unregistered. */
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync void *pvChannel; /* Provider's context of the channel. */
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync uint32_t u32Handle; /* handle assigned to the channel by the service. */
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync/* Only one service instance is supported. */
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync * Provider management.
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsyncstatic void vhcProviderDestroy(VBOXHOSTCHPROVIDER *pProvider)
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsyncstatic int32_t vhcProviderAddRef(VBOXHOSTCHPROVIDER *pProvider)
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsyncstatic void vhcProviderRelease(VBOXHOSTCHPROVIDER *pProvider)
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync if (c == 0)
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsyncstatic VBOXHOSTCHPROVIDER *vhcProviderFind(VBOXHOSTCHCTX *pCtx, const char *pszName)
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync RTListForEach(&pCtx->listProviders, pIter, VBOXHOSTCHPROVIDER, nodeContext)
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsyncstatic int vhcProviderRegister(VBOXHOSTCHCTX *pCtx, VBOXHOSTCHPROVIDER *pProvider)
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync /* @todo check a duplicate. */
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync RTListAppend(&pCtx->listProviders, &pProvider->nodeContext);
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsyncstatic int vhcProviderUnregister(VBOXHOSTCHPROVIDER *pProvider)
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync /* @todo check that the provider is in the list. */
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync /* @todo mark the provider as invalid in each instance. also detach channels? */
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync * Select an unique handle for the new channel.
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync * Works under the lock.
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsyncstatic int vhcHandleCreate(VBOXHOSTCHCLIENT *pClient, uint32_t *pu32Handle)
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync bool fOver = false;
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync uint32_t u32Handle = ASMAtomicIncU32(&pClient->u32HandleSrc);
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync RTListForEach(&pClient->listChannels, pIter, VBOXHOSTCHINSTANCE, nodeClient)
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync * Channel instance management.
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsyncstatic void vhcInstanceDestroy(VBOXHOSTCHINSTANCE *pInstance)
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync /* @todo free u32Handle? */
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsyncstatic int32_t vhcInstanceAddRef(VBOXHOSTCHINSTANCE *pInstance)
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsyncstatic void vhcInstanceRelease(VBOXHOSTCHINSTANCE *pInstance)
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync if (c == 0)
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsyncstatic int vhcInstanceCreate(VBOXHOSTCHCLIENT *pClient, VBOXHOSTCHINSTANCE **ppInstance)
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync VBOXHOSTCHINSTANCE *pInstance = (VBOXHOSTCHINSTANCE *)RTMemAllocZ(sizeof(VBOXHOSTCHINSTANCE));
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync rc = vhcHandleCreate(pClient, &pInstance->u32Handle);
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsyncstatic VBOXHOSTCHINSTANCE *vhcInstanceFind(VBOXHOSTCHCLIENT *pClient, uint32_t u32Handle)
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync RTListForEach(&pClient->listChannels, pIter, VBOXHOSTCHINSTANCE, nodeClient)
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsyncstatic VBOXHOSTCHINSTANCE *vhcInstanceFindByChannelPtr(VBOXHOSTCHCLIENT *pClient, void *pvChannel)
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync RTListForEach(&pClient->listChannels, pIter, VBOXHOSTCHINSTANCE, nodeClient)
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsyncstatic void vhcInstanceDetach(VBOXHOSTCHINSTANCE *pInstance)
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync pInstance->pProvider->iface.HostChannelDetach(pInstance->pvChannel);
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync vhcInstanceRelease(pInstance); /* Not in the list anymore. */
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync vhcInstanceRelease(pInstance); /* Not in the list anymore. */
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync * Host channel service functions.
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync RTListForEachSafe(&pCtx->listProviders, pIter, pIterNext, VBOXHOSTCHPROVIDER, nodeContext)
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsyncint vboxHostChannelClientConnect(VBOXHOSTCHCLIENT *pClient)
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync /* A guest client is connecting to the service.
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync * Later the client will use Attach calls to connect to channel providers.
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync * pClient is already zeroed.
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsyncvoid vboxHostChannelClientDisconnect(VBOXHOSTCHCLIENT *pClient)
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync /* If there are attached channels, detach them. */
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync RTListForEachSafe(&pClient->listChannels, pIter, pIterNext, VBOXHOSTCHINSTANCE, nodeClient)
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsyncint vboxHostChannelAttach(VBOXHOSTCHCLIENT *pClient,
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync const char *pszName,
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync HOSTCHLOG(("HostChannel: Attach: (%d) [%s] 0x%08X\n", pClient->u32ClientID, pszName, u32Flags));
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync /* Look if there is a provider. */
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync VBOXHOSTCHPROVIDER *pProvider = vhcProviderFind(pClient->pCtx, pszName);
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync rc = pProvider->iface.HostChannelAttach(pProvider->iface.pvProvider,
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync vhcInstanceAddRef(pInstance); /* Referenced by the list client's channels. */
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync RTListAppend(&pClient->listChannels, &pInstance->nodeClient);
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync vhcInstanceAddRef(pInstance); /* Referenced by the list of provider's channels. */
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync RTListAppend(&pProvider->listChannels, &pInstance->nodeProvider);
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync HOSTCHLOG(("HostChannel: Attach: (%d) handle %d\n", pClient->u32ClientID, pInstance->u32Handle));
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsyncint vboxHostChannelDetach(VBOXHOSTCHCLIENT *pClient,
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync HOSTCHLOG(("HostChannel: Detach: (%d) handle %d\n", pClient->u32ClientID, u32Handle));
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync VBOXHOSTCHINSTANCE *pInstance = vhcInstanceFind(pClient, u32Handle);
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync const void *pvData,
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync HOSTCHLOG(("HostChannel: Send: (%d) handle %d, %d bytes\n", pClient->u32ClientID, u32Handle, cbData));
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync VBOXHOSTCHINSTANCE *pInstance = vhcInstanceFind(pClient, u32Handle);
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync pInstance->pProvider->iface.HostChannelSend(pInstance->pvChannel, pvData, cbData);
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync HOSTCHLOG(("HostChannel: Recv: (%d) handle %d, cbData %d\n", pClient->u32ClientID, u32Handle, cbData));
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync VBOXHOSTCHINSTANCE *pInstance = vhcInstanceFind(pClient, u32Handle);
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync rc = pInstance->pProvider->iface.HostChannelRecv(pInstance->pvChannel, pvData, cbData,
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync HOSTCHLOG(("HostChannel: Recv: (%d) handle %d, rc %Rrc, recv %d, rem %d\n",
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync pClient->u32ClientID, u32Handle, rc, cbData, *pu32SizeReceived, *pu32SizeRemaining));
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsyncint vboxHostChannelControl(VBOXHOSTCHCLIENT *pClient,
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync HOSTCHLOG(("HostChannel: Control: (%d) handle %d, cbData %d\n", pClient->u32ClientID, u32Handle, cbData));
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync VBOXHOSTCHINSTANCE *pInstance = vhcInstanceFind(pClient, u32Handle);
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync pInstance->pProvider->iface.HostChannelControl(pInstance->pvChannel, u32Code,
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync/* This is called under the lock. */
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsyncint vboxHostChannelQueryEvent(VBOXHOSTCHCLIENT *pClient,
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync /* Check if there is something in the client's event queue. */
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync VBOXHOSTCHANNELEVENT *pEvent = RTListGetFirst(&pClient->listEvents, VBOXHOSTCHANNELEVENT, NodeEvent);
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync HOSTCHLOG(("HostChannel: QueryEvent: (%d), event %p\n", pClient->u32ClientID, pEvent));
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync /* Report the event. */
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync uint32_t cbToCopy = RT_MIN(cbParm, pEvent->cbEvent);
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync HOSTCHLOG(("HostChannel: QueryEvent: (%d), cbParm %d, cbEvent %d\n",
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync /* Tell the caller that there is no event. */
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsyncstatic DECLCALLBACK(void) HostChannelCallbackEvent(void *pvCallbacks, void *pvChannel,
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync uint32_t u32Id, const void *pvEvent, uint32_t cbEvent)
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync VBOXHOSTCHCLIENT *pClient = (VBOXHOSTCHCLIENT *)pvCallbacks;
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync VBOXHOSTCHINSTANCE *pInstance = vhcInstanceFindByChannelPtr(pClient, pvChannel);
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync HOSTCHLOG(("HostChannel: CallbackEvent: (%d) instance %p\n",
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync HOSTCHLOG(("HostChannel: CallbackEvent: (%d) handle %d, async %d, cbEvent %d\n",
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync pClient->u32ClientID, u32ChannelHandle, pClient->fAsync, cbEvent));
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync /* Check whether the event is waited. */
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync /* Report the event. */
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync vboxHostChannelReportAsync(pClient, u32ChannelHandle, u32Id, pvEvent, cbEvent);
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync /* Put it to the queue. */
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync VBOXHOSTCHANNELEVENT *pEvent = (VBOXHOSTCHANNELEVENT *)RTMemAlloc(sizeof(VBOXHOSTCHANNELEVENT) + cbEvent);
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync RTListAppend(&pClient->listEvents, &pEvent->NodeEvent);
e2a4ff87ea2e2e95350793b5fccb143c1819fadcvboxsync VBOXHOSTCHPROVIDER *pProvider = (VBOXHOSTCHPROVIDER *)RTMemAllocZ(sizeof(VBOXHOSTCHPROVIDER));