service.cpp revision f675364bced7de2a98408e697da210bc6e6ddb2a
/* $Id$ */
/* @file
* Host Channel: Host service entry points.
*/
/*
* Copyright (C) 2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*/
/*
* The HostChannel host service provides a generic proxy between a host's
* channel provider and a client running in the guest.
*
* Host providers must register via a HostCall.
*
*
* GuestCalls:
* * Attach - attach to a host channel
* * Detach - completely detach from a channel
* * Send - send data from the guest to the channel
* * Recv - non blocking read of available data from the channel
* * Control - generic channel specific command exchange
* * EventWait - wait for a host event
* * EventCancel - make the blocking EventWait call to return
* HostCalls:
* * Register - register a host channel
* * Unregister - unregister it
*
* The guest HGCM client connects to the service. The client can attach multiple channels.
*
*/
#include <iprt/critsect.h>
#include "HostChannel.h"
{
}
{
{
return VINF_SUCCESS;
}
AssertFailed();
return VERR_INVALID_PARAMETER;
}
{
}
{
{
return VINF_SUCCESS;
}
AssertFailed();
return VERR_INVALID_PARAMETER;
}
static RTCRITSECT g_critsect;
/*
* Helpers.
*/
int vboxHostChannelLock(void)
{
return RTCritSectEnter(&g_critsect);
}
void vboxHostChannelUnlock(void)
{
}
/* This is called under the lock. */
const void *pvEvent,
{
if (cbEvent > 0)
{
if (cbToCopy > 0)
{
}
}
LogRelFlow(("svcCall: CallComplete for pending\n"));
}
/*
* Service entry points.
*/
{
return VINF_SUCCESS;
}
{
return VINF_SUCCESS;
}
{
int rc = VINF_SUCCESS;
/* Register the client. */
return rc;
}
void *pvClient,
{
int rc = VINF_SUCCESS;
LogRel2(("svcCall: u32ClientID = %d, fn = %d, cParms = %d, pparms = %d\n",
bool fAsynchronousProcessing = false;
#ifdef DEBUG
uint32_t i;
for (i = 0; i < cParms; i++)
{
/** @todo parameters other than 32 bit */
}
#endif
switch (u32Function)
{
{
LogRel2(("svcCall: VBOX_HOST_CHANNEL_FN_ATTACH\n"));
if (cParms != 3)
{
}
)
{
}
else
{
void *pvName;
if (RT_SUCCESS(rc))
{
if (RT_SUCCESS(rc))
{
/* @todo make sure that pvName is a nul terminated */
if (RT_SUCCESS(rc))
{
}
}
}
}
} break;
{
LogRel2(("svcCall: VBOX_HOST_CHANNEL_FN_DETACH\n"));
if (cParms != 1)
{
}
)
{
}
else
{
if (RT_SUCCESS(rc))
{
}
}
} break;
{
LogRel2(("svcCall: VBOX_HOST_CHANNEL_FN_SEND\n"));
if (cParms != 2)
{
}
)
{
}
else
{
void *pvData;
if (RT_SUCCESS (rc))
{
if (RT_SUCCESS (rc))
{
}
}
}
} break;
{
LogRel2(("svcCall: VBOX_HOST_CHANNEL_FN_RECV\n"));
if (cParms != 4)
{
}
)
{
}
else
{
void *pvData;
if (RT_SUCCESS (rc))
{
if (RT_SUCCESS (rc))
{
uint32_t u32SizeReceived = 0;
uint32_t u32SizeRemaining = 0;
if (RT_SUCCESS(rc))
{
}
}
}
}
} break;
{
LogRel2(("svcCall: VBOX_HOST_CHANNEL_FN_CONTROL\n"));
if (cParms != 5)
{
}
)
{
}
else
{
void *pvParm;
void *pvData;
if (RT_SUCCESS (rc))
{
if (RT_SUCCESS (rc))
{
if (RT_SUCCESS (rc))
{
if (RT_SUCCESS (rc))
{
if (RT_SUCCESS(rc))
{
}
}
}
}
}
}
} break;
{
LogRel2(("svcCall: VBOX_HOST_CHANNEL_FN_EVENT_WAIT\n"));
if (cParms != 4)
{
}
)
{
}
else
{
void *pvParm;
if (RT_SUCCESS(rc))
{
/* This is accessed from the SVC thread and other threads. */
rc = vboxHostChannelLock();
if (RT_SUCCESS(rc))
{
{
/* If there is a wait request already, cancel it. */
}
bool fEvent = false;
if (RT_SUCCESS(rc))
{
if (fEvent)
{
}
else
{
/* No event available at the time. Process asynchronously. */
fAsynchronousProcessing = true;
LogRel2(("svcCall: async.\n"));
}
}
}
}
}
} break;
{
LogRel2(("svcCall: VBOX_HOST_CHANNEL_FN_EVENT_CANCEL\n"));
if (cParms != 0)
{
}
else
{
/* This is accessed from the SVC thread and other threads. */
rc = vboxHostChannelLock();
if (RT_SUCCESS(rc))
{
{
/* If there is a wait request alredy, cancel it. */
}
}
}
} break;
{
LogRel2(("svcCall: VBOX_HOST_CHANNEL_FN_QUERY\n"));
if (cParms != 5)
{
}
)
{
}
else
{
void *pvName;
void *pvParm;
void *pvData;
if (RT_SUCCESS (rc))
{
if (RT_SUCCESS (rc))
{
if (RT_SUCCESS (rc))
{
if (RT_SUCCESS (rc))
{
/* @todo make sure that pvName is a nul terminated */
if (RT_SUCCESS(rc))
{
}
}
}
}
}
}
} break;
default:
{
}
}
if (!fAsynchronousProcessing)
{
}
}
{
int rc = VINF_SUCCESS;
LogRel2(("svcHostCall: fn = %d, cParms = %d, pparms = %d\n",
switch (u32Function)
{
{
LogRel2(("svcCall: VBOX_HOST_CHANNEL_HOST_FN_REGISTER\n"));
if (cParms != 2)
{
}
)
{
}
else
{
void *pvName;
void *pvInterface;
if (RT_SUCCESS(rc))
{
if (RT_SUCCESS(rc))
{
}
}
}
} break;
{
LogRel2(("svcCall: VBOX_HOST_CHANNEL_HOST_FN_UNREGISTER\n"));
if (cParms != 1)
{
}
)
{
}
else
{
void *pvName;
if (RT_SUCCESS(rc))
{
}
}
} break;
default:
break;
}
return rc;
}
#if 0
/** If the client in the guest is waiting for a read operation to complete
* then complete it, otherwise return. See the protocol description in the
* shared clipboard module description. */
{
bool fReadPending = false;
if (vboxSvcClipboardLock()) /* if not can we do anything useful? */
{
pClient->fReadPending = false;
}
if (fReadPending)
{
}
}
/**
* SSM descriptor table for the VBOXHOSTCHCLIENT structure.
*/
static SSMFIELD const g_aClipboardClientDataFields[] =
{
};
static DECLCALLBACK(int) svcSaveState(void *pvService, uint32_t u32ClientID, void *pvClient, PSSMHANDLE pSSM)
{
/* If there are any pending requests, they must be completed here. Since
* the service is single threaded, there could be only requests
* which the service itself has postponed.
*
* HGCM knows that the state is being saved and that the pfnComplete
* calls are just clean ups. These requests are saved by the VMMDev.
*
* When the state will be restored, these requests will be reissued
* by VMMDev. The service therefore must save state as if there were no
* pending request.
*/
/* This field used to be the length. We're using it as a version field
with the high bit set. */
int rc = SSMR3PutStructEx (pSSM, pClient, sizeof(*pClient), 0 /*fFlags*/, &g_aClipboardClientDataFields[0], NULL);
{
g_pHelpers->pfnCallComplete (pClient->async.callHandle, VINF_SUCCESS /* error code is not important here. */);
}
return VINF_SUCCESS;
}
/**
* This structure corresponds to the original layout of the
* VBOXHOSTCHCLIENT structure. As the structure was saved as a whole
* when saving state, we need to remember it forever in order to preserve
* compatibility.
*
* (Starting with 3.1 this is no longer used.)
*
* @remarks Putting this outside svcLoadState to avoid visibility warning caused
* by -Wattributes.
*/
typedef struct CLIPSAVEDSTATEDATA
{
struct CLIPSAVEDSTATEDATA *pNext;
struct CLIPSAVEDSTATEDATA *pPrev;
bool fMsgQuit: 1;
bool fMsgReadData: 1;
bool fMsgFormats: 1;
struct {
} async;
struct {
void *pv;
} data;
static DECLCALLBACK(int) svcLoadState(void *, uint32_t u32ClientID, void *pvClient, PSSMHANDLE pSSM)
{
/* Existing client can not be in async state yet. */
/* Save the client ID for data validation. */
/** @todo isn't this the same as u32ClientID? Playing safe for now... */
/* Restore the client data. */
{
rc = SSMR3GetStructEx (pSSM, pClient, sizeof(*pClient), 0 /*fFlags*/, &g_aClipboardClientDataFields[0], NULL);
}
{
/**
* SSM descriptor table for the CLIPSAVEDSTATEDATA structure.
*/
static SSMFIELD const s_aClipSavedStateDataFields30[] =
{
SSMFIELD_ENTRY_CUSTOM(fMsgQuit+fMsgReadData+fMsgFormats, RT_OFFSETOF(CLIPSAVEDSTATEDATA, u32ClientID) + 4, 4),
};
}
else
{
}
/* Verify the client ID. */
{
}
/* Actual host data are to be reported to guest (SYNC). */
return VINF_SUCCESS;
}
#endif
static int svcInit(void)
{
if (RT_SUCCESS (rc))
{
rc = vboxHostChannelInit();
/* Clean up on failure, because 'svnUnload' will not be called
* if the 'svcInit' returns an error.
*/
if (RT_FAILURE(rc))
{
}
}
return rc;
}
{
int rc = VINF_SUCCESS;
if (!pTable)
{
}
else
{
LogRel2(("VBoxHGCMSvcLoad: pTable->cbSize = %d, pTable->u32Version = 0x%08X\n",
{
}
else
{
/* Service specific initialization. */
}
}
return rc;
}