mirror of
https://github.com/gnif/LookingGlass.git
synced 2024-11-10 00:28:20 +00:00
[host] initial service framework implemented
This commit is contained in:
parent
941f0f1c16
commit
3dd205bafc
@ -1,3 +1,4 @@
|
||||
#pragma once
|
||||
/*
|
||||
KVMGFX Client - A KVM Client for VGA Passthrough
|
||||
Copyright (C) 2017 Geoffrey McRae <geoff@hostfission.com>
|
||||
@ -16,6 +17,8 @@ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define KVMGFX_HEADER_MAGIC "[[KVMGFXHeader]]"
|
||||
|
||||
typedef enum FrameType
|
||||
|
15
host/CaptureFactory.h
Normal file
15
host/CaptureFactory.h
Normal file
@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#define W32_LEAN_AND_MEAN
|
||||
#include <Windows.h>
|
||||
|
||||
#include "ICapture.h"
|
||||
|
||||
static class CaptureFactory
|
||||
{
|
||||
public:
|
||||
static ICapture * GetCaptureDevice()
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
};
|
14
host/ICapture.h
Normal file
14
host/ICapture.h
Normal file
@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include <common/KVMGFXHeader.h>
|
||||
|
||||
__interface ICapture
|
||||
{
|
||||
public:
|
||||
bool Initialize();
|
||||
bool DeInitialize();
|
||||
enum FrameType GetFrameType();
|
||||
enum FrameComp GetFrameCompression();
|
||||
size_t GetMaxFrameSize();
|
||||
bool GrabFrame(void * buffer, size_t bufferSize, size_t * outLen);
|
||||
};
|
165
host/Service.cpp
Normal file
165
host/Service.cpp
Normal file
@ -0,0 +1,165 @@
|
||||
#include "service.h"
|
||||
#include "ivshmem.h"
|
||||
|
||||
#include <common\debug.h>
|
||||
#include <common\KVMGFXHeader.h>
|
||||
|
||||
#include "CaptureFactory.h"
|
||||
|
||||
Service * Service::m_instance = NULL;
|
||||
|
||||
Service::Service() :
|
||||
m_initialized(false),
|
||||
m_readyEvent(INVALID_HANDLE_VALUE),
|
||||
m_capture(NULL),
|
||||
m_memory(NULL)
|
||||
{
|
||||
m_ivshmem = IVSHMEM::Get();
|
||||
}
|
||||
|
||||
Service::~Service()
|
||||
{
|
||||
}
|
||||
|
||||
bool Service::Initialize()
|
||||
{
|
||||
if (m_initialized)
|
||||
DeInitialize();
|
||||
|
||||
if (!m_ivshmem->Initialize())
|
||||
{
|
||||
DEBUG_ERROR("IVSHMEM failed to initalize");
|
||||
DeInitialize();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_ivshmem->GetSize() < sizeof(KVMGFXHeader))
|
||||
{
|
||||
DEBUG_ERROR("Shared memory is not large enough for the KVMGFXHeader");
|
||||
DeInitialize();
|
||||
return false;
|
||||
}
|
||||
|
||||
m_memory = m_ivshmem->GetMemory();
|
||||
if (!m_memory)
|
||||
{
|
||||
DEBUG_ERROR("Failed to get IVSHMEM memory");
|
||||
DeInitialize();
|
||||
return false;
|
||||
}
|
||||
|
||||
m_readyEvent = m_ivshmem->CreateVectorEvent(0);
|
||||
if (m_readyEvent == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
DEBUG_ERROR("Failed to get event for vector 0");
|
||||
DeInitialize();
|
||||
return false;
|
||||
}
|
||||
|
||||
m_capture = CaptureFactory::GetCaptureDevice();
|
||||
if (!m_capture || !m_capture->Initialize())
|
||||
{
|
||||
DEBUG_ERROR("Failed to initialize capture interface");
|
||||
DeInitialize();
|
||||
return false;
|
||||
}
|
||||
|
||||
KVMGFXHeader * header = static_cast<KVMGFXHeader*>(m_memory);
|
||||
ZeroMemory(header, sizeof(KVMGFXHeader));
|
||||
memcpy(header->magic, KVMGFX_HEADER_MAGIC, sizeof(KVMGFX_HEADER_MAGIC));
|
||||
|
||||
header->version = 2;
|
||||
header->guestID = m_ivshmem->GetPeerID();
|
||||
|
||||
m_initialized = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void Service::DeInitialize()
|
||||
{
|
||||
if (m_capture)
|
||||
{
|
||||
m_capture->DeInitialize();
|
||||
m_capture = NULL;
|
||||
}
|
||||
|
||||
if (m_readyEvent != INVALID_HANDLE_VALUE)
|
||||
CloseHandle(m_readyEvent);
|
||||
|
||||
m_memory = NULL;
|
||||
m_ivshmem->DeInitialize();
|
||||
m_initialized = false;
|
||||
}
|
||||
|
||||
bool Service::Process(HANDLE stopEvent)
|
||||
{
|
||||
if (!m_initialized)
|
||||
return false;
|
||||
|
||||
KVMGFXHeader * header = static_cast<KVMGFXHeader *>(m_memory );
|
||||
void * data = static_cast<void *>(header + 1);
|
||||
const size_t available = m_ivshmem->GetSize() - sizeof(KVMGFXHeader);
|
||||
if (m_capture->GetMaxFrameSize() > available)
|
||||
{
|
||||
DEBUG_ERROR("Frame could exceed buffer size!");
|
||||
return false;
|
||||
}
|
||||
|
||||
// setup the header
|
||||
header->frameType = m_capture->GetFrameType();
|
||||
header->compType = m_capture->GetFrameCompression();
|
||||
|
||||
// capture a frame of data
|
||||
if (!m_capture->GrabFrame(
|
||||
data,
|
||||
m_ivshmem->GetSize() - sizeof(KVMGFXHeader),
|
||||
&header->dataLen))
|
||||
{
|
||||
DEBUG_ERROR("Capture failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
// tell the host where the cursor is
|
||||
POINT cursorPos;
|
||||
GetCursorPos(&cursorPos);
|
||||
header->mouseX = cursorPos.x;
|
||||
header->mouseY = cursorPos.y;
|
||||
|
||||
// wait for the host to notify that is it is ready to proceed
|
||||
ResetEvent(m_readyEvent);
|
||||
while(
|
||||
stopEvent == INVALID_HANDLE_VALUE ||
|
||||
(WaitForSingleObject(stopEvent, 0) == WAIT_OBJECT_0)
|
||||
)
|
||||
{
|
||||
if (!m_ivshmem->RingDoorbell(header->hostID, 0))
|
||||
{
|
||||
DEBUG_ERROR("Failed to ring doorbell");
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (WaitForSingleObject(m_readyEvent, 1000))
|
||||
{
|
||||
case WAIT_ABANDONED:
|
||||
DEBUG_ERROR("Wait abandoned");
|
||||
return false;
|
||||
|
||||
case WAIT_OBJECT_0:
|
||||
return true;
|
||||
|
||||
// if we timed out we just continue to ring until we get an answer or we are stopped
|
||||
case WAIT_TIMEOUT:
|
||||
break;
|
||||
|
||||
case WAIT_FAILED:
|
||||
DEBUG_ERROR("Wait failed");
|
||||
return false;
|
||||
|
||||
default:
|
||||
DEBUG_ERROR("Unknown error");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
35
host/Service.h
Normal file
35
host/Service.h
Normal file
@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
|
||||
#define W32_LEAN_AND_MEAN
|
||||
#include <Windows.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "ivshmem.h"
|
||||
#include "ICapture.h"
|
||||
|
||||
class Service
|
||||
{
|
||||
public:
|
||||
static Service * Get()
|
||||
{
|
||||
if (!m_instance)
|
||||
m_instance = new Service();
|
||||
return m_instance;
|
||||
}
|
||||
|
||||
bool Initialize();
|
||||
void DeInitialize();
|
||||
bool Process(HANDLE stopEvent);
|
||||
|
||||
private:
|
||||
static Service * m_instance;
|
||||
|
||||
Service();
|
||||
~Service();
|
||||
|
||||
bool m_initialized;
|
||||
IVSHMEM * m_ivshmem;
|
||||
HANDLE m_readyEvent;
|
||||
ICapture * m_capture;
|
||||
void * m_memory;
|
||||
};
|
@ -216,4 +216,22 @@ HANDLE IVSHMEM::CreateVectorEvent(UINT16 vector)
|
||||
}
|
||||
|
||||
return event;
|
||||
}
|
||||
|
||||
bool IVSHMEM::RingDoorbell(UINT16 peerID, UINT16 door)
|
||||
{
|
||||
if (!m_initialized)
|
||||
return false;
|
||||
|
||||
IVSHMEM_RING msg;
|
||||
msg.peerID = peerID;
|
||||
msg.vector = door;
|
||||
|
||||
if (!DeviceIoControl(m_handle, IOCTL_IVSHMEM_RING_DOORBELL, &msg, sizeof(IVSHMEM_RING), NULL, 0, NULL, NULL))
|
||||
{
|
||||
DEBUG_ERROR("DeviceIoControl Failed: %d", GetLastError());
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
@ -23,6 +23,7 @@ public:
|
||||
UINT16 GetVectors();
|
||||
void * GetMemory();
|
||||
HANDLE CreateVectorEvent(UINT16 vector);
|
||||
bool RingDoorbell(UINT16 peerID, UINT16 door);
|
||||
|
||||
protected:
|
||||
|
||||
|
@ -154,9 +154,13 @@
|
||||
<ItemGroup>
|
||||
<ClCompile Include="ivshmem.cpp" />
|
||||
<ClCompile Include="main.cpp" />
|
||||
<ClCompile Include="Service.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="CaptureFactory.h" />
|
||||
<ClInclude Include="ICapture.h" />
|
||||
<ClInclude Include="ivshmem.h" />
|
||||
<ClInclude Include="Service.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
|
@ -21,10 +21,22 @@
|
||||
<ClCompile Include="main.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Service.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="ivshmem.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ICapture.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Service.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="CaptureFactory.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
@ -2,7 +2,7 @@
|
||||
#include <tchar.h>
|
||||
#include <common\debug.h>
|
||||
|
||||
#include "ivshmem.h"
|
||||
#include "Service.h"
|
||||
|
||||
#define SERVICE_NAME "kvm-ivshmem-host"
|
||||
|
||||
@ -146,19 +146,18 @@ VOID WINAPI ServiceCtrlHandler(DWORD CtrlCode)
|
||||
|
||||
DWORD WINAPI ServiceWorkerThread(LPVOID lpParam)
|
||||
{
|
||||
IVSHMEM * ivshmem = IVSHMEM::Get();
|
||||
if (!ivshmem->Initialize())
|
||||
Service *svc = svc->Get();
|
||||
if (!svc->Initialize())
|
||||
{
|
||||
DEBUG_ERROR("Failed to initialize IVSHMEM");
|
||||
DEBUG_ERROR("Failed to initialize service");
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
while (WaitForSingleObject(app.serviceStopEvent, 0) != WAIT_OBJECT_0)
|
||||
{
|
||||
Sleep(1000);
|
||||
}
|
||||
if (!svc->Process(app.serviceStopEvent))
|
||||
break;
|
||||
|
||||
ivshmem->DeInitialize();
|
||||
svc->DeInitialize();
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user