mirror of
https://github.com/gnif/LookingGlass.git
synced 2024-12-22 21:43:40 +00:00
[porthole] added connection state support
This commit is contained in:
parent
968b313993
commit
453b8e6a4d
@ -24,13 +24,20 @@ Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
typedef struct PortholeDev *PortholeDev;
|
||||
typedef int PortholeID;
|
||||
typedef enum PortholeState
|
||||
{
|
||||
PH_STATE_NEW_SESSION,
|
||||
PH_STATE_CONNECTED,
|
||||
PH_STATE_DISCONNECTED
|
||||
}
|
||||
PortholeState;
|
||||
|
||||
/**
|
||||
* Open the porthole device
|
||||
*
|
||||
* @param handle The returned handle if successful, otherwise undefined
|
||||
* @param vendor_id The subsystem vendor and device id to match
|
||||
* @returns true on success
|
||||
* @param handle The returned handle if successful, otherwise undefined
|
||||
* @param vendor_id The subsystem vendor and device id to match
|
||||
* @return true on success
|
||||
*
|
||||
* If successful the handle must be closed to free resources when finished.
|
||||
*/
|
||||
@ -45,14 +52,38 @@ bool porthole_dev_open(PortholeDev *handle, const uint32_t vendor_id);
|
||||
*/
|
||||
void porthole_dev_close(PortholeDev *handle);
|
||||
|
||||
/**
|
||||
* Get the state of the porthole device
|
||||
*
|
||||
* @param handle The porthole device handle obtained form porthole_dev_open
|
||||
* @return The current state of the connection
|
||||
*
|
||||
* This method will return the current state of the porthole device
|
||||
*
|
||||
* * PH_STATE_NEW_SESSION = The client has connected
|
||||
* * PH_STATE_CONNECTED = The client is still connected
|
||||
* * PH_STATE_DISCONNECTED = There is no client connection
|
||||
*/
|
||||
PortholeState porthole_dev_get_state(PortholeDev handle);
|
||||
|
||||
/**
|
||||
* Wait for the specified state
|
||||
*
|
||||
* @param handle The porthole device handle obtained from porthole_dev_open
|
||||
* @param state The state to wait for
|
||||
* @param timeout The maximum amount of time to wait in milliseconds for the state (0 = infinite)
|
||||
* @return true on success, false on timeout
|
||||
*/
|
||||
bool porthole_dev_wait_state(PortholeDev handle, const PortholeState state, const unsigned int timeout);
|
||||
|
||||
/**
|
||||
* Share the provided buffer over the porthole device
|
||||
*
|
||||
* @param handle The porthole device
|
||||
* @param type The type
|
||||
* @param buffer The buffer to share
|
||||
* @param size The size of the buffer
|
||||
* @returns the porthole mapping ID, or -1 on failure
|
||||
* @param handle The porthole device
|
||||
* @param type The type
|
||||
* @param buffer The buffer to share
|
||||
* @param size The size of the buffer
|
||||
* @return the porthole mapping ID, or -1 on failure
|
||||
*
|
||||
* This function locks the supplied buffer in RAM via the porthole device
|
||||
* driver and is then shared with the device for use outside the guest.
|
||||
@ -73,9 +104,9 @@ PortholeID porthole_dev_map(PortholeDev handle, const uint32_t type, void *buffe
|
||||
/**
|
||||
* Unmap a previously shared buffer
|
||||
*
|
||||
* @param handle The porthole device
|
||||
* @param id The porthole map id returned by porthole_dev_share
|
||||
* @returns true on success
|
||||
* @param handle The porthole device
|
||||
* @param id The porthole map id returned by porthole_dev_share
|
||||
* @return true on success
|
||||
*
|
||||
* Unmaps a previously shared buffer. Once this has been done the buffer can
|
||||
* be freed or re-used. The client application should no longer attempt to
|
||||
|
@ -28,7 +28,9 @@ Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
struct PortholeDev
|
||||
{
|
||||
HANDLE dev;
|
||||
HANDLE dev;
|
||||
bool connected;
|
||||
PortholeEvents events;
|
||||
};
|
||||
|
||||
bool porthole_dev_open(PortholeDev *handle, const uint32_t vendor_id)
|
||||
@ -113,6 +115,22 @@ bool porthole_dev_open(PortholeDev *handle, const uint32_t vendor_id)
|
||||
|
||||
(*handle)->dev = dev;
|
||||
|
||||
/* create the events and register them */
|
||||
(*handle)->events.connect = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
(*handle)->events.disconnect = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
|
||||
DWORD returned;
|
||||
if (!DeviceIoControl(dev, IOCTL_PORTHOLE_REGISTER_EVENTS, &(*handle)->events, sizeof(PortholeEvents), NULL, 0, &returned, NULL))
|
||||
{
|
||||
DEBUG_ERROR("Failed to register the events");
|
||||
CloseHandle((*handle)->events.connect );
|
||||
CloseHandle((*handle)->events.disconnect);
|
||||
CloseHandle(dev);
|
||||
free(*handle);
|
||||
*handle = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -120,11 +138,89 @@ void porthole_dev_close(PortholeDev *handle)
|
||||
{
|
||||
assert(handle && *handle);
|
||||
|
||||
CloseHandle((*handle)->events.connect );
|
||||
CloseHandle((*handle)->events.disconnect);
|
||||
CloseHandle((*handle)->dev);
|
||||
free(*handle);
|
||||
*handle = NULL;
|
||||
}
|
||||
|
||||
static PortholeState get_state(PortholeDev handle, unsigned int timeout)
|
||||
{
|
||||
if (handle->connected)
|
||||
{
|
||||
switch(WaitForSingleObject(handle->events.disconnect, timeout))
|
||||
{
|
||||
case WAIT_OBJECT_0:
|
||||
handle->connected = false;
|
||||
return PH_STATE_DISCONNECTED;
|
||||
|
||||
case WAIT_TIMEOUT:
|
||||
return PH_STATE_CONNECTED;
|
||||
|
||||
default:
|
||||
DEBUG_FATAL("Error waiting on disconnect event");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch(WaitForSingleObject(handle->events.connect, timeout))
|
||||
{
|
||||
case WAIT_OBJECT_0:
|
||||
handle->connected = true;
|
||||
return PH_STATE_NEW_SESSION;
|
||||
|
||||
case WAIT_TIMEOUT:
|
||||
return PH_STATE_DISCONNECTED;
|
||||
|
||||
default:
|
||||
DEBUG_FATAL("Error waiting on connection event");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
PortholeState porthole_dev_get_state(PortholeDev handle)
|
||||
{
|
||||
return get_state(handle, 0);
|
||||
}
|
||||
|
||||
bool porthole_dev_wait_state(PortholeDev handle, const PortholeState state, const unsigned int timeout)
|
||||
{
|
||||
const DWORD to = (timeout == 0) ? INFINITE : timeout;
|
||||
PortholeState lastState = get_state(handle, 0);
|
||||
|
||||
if (state == lastState)
|
||||
return true;
|
||||
|
||||
while(true)
|
||||
{
|
||||
PortholeState nextState;
|
||||
switch(lastState)
|
||||
{
|
||||
case PH_STATE_DISCONNECTED:
|
||||
nextState = PH_STATE_NEW_SESSION;
|
||||
break;
|
||||
|
||||
case PH_STATE_NEW_SESSION:
|
||||
nextState = PH_STATE_CONNECTED;
|
||||
break;
|
||||
|
||||
case PH_STATE_CONNECTED:
|
||||
nextState = PH_STATE_DISCONNECTED;
|
||||
break;
|
||||
}
|
||||
|
||||
PortholeState newState = get_state(handle, to);
|
||||
if (newState == lastState || newState != nextState)
|
||||
return false;
|
||||
|
||||
if (newState == state)
|
||||
return true;
|
||||
|
||||
lastState = newState;
|
||||
}
|
||||
}
|
||||
|
||||
PortholeID porthole_dev_map(PortholeDev handle, const uint32_t type, void *buffer, size_t size)
|
||||
{
|
||||
assert(handle);
|
||||
|
Loading…
Reference in New Issue
Block a user