mirror of
https://github.com/Ylianst/MeshAgent
synced 2025-12-06 00:13:33 +00:00
1078 lines
37 KiB
C
1078 lines
37 KiB
C
/*
|
|
Copyright 2006 - 2015 Intel Corporation
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
#if defined(_LINKVM)
|
|
|
|
#include <stdio.h>
|
|
#include "kvm.h"
|
|
#include "tile.h"
|
|
#include <signal.h>
|
|
#include "input.h"
|
|
#include <Winuser.h>
|
|
|
|
#include "meshcore/meshdefines.h"
|
|
#include "microstack/ILibParsers.h"
|
|
#include "microstack/ILibAsyncSocket.h"
|
|
#include "microstack/ILibProcessPipe.h"
|
|
#include "microstack/ILibRemoteLogging.h"
|
|
|
|
#if defined(WIN32) && !defined(_WIN32_WCE) && !defined(_MINCORE)
|
|
#define _CRTDBG_MAP_ALLOC
|
|
#include <crtdbg.h>
|
|
#endif
|
|
|
|
// #define KVMDEBUGENABLED 1
|
|
ILibProcessPipe_SpawnTypes gProcessSpawnType = ILibProcessPipe_SpawnTypes_USER;
|
|
|
|
#pragma pack(push, 1)
|
|
typedef struct KVMDebugLog
|
|
{
|
|
unsigned short length;
|
|
unsigned short logType;
|
|
unsigned short logFlags;
|
|
char logData[];
|
|
}KVMDebugLog;
|
|
#pragma pack(pop)
|
|
|
|
|
|
#ifdef KVMDEBUGENABLED
|
|
void KvmCriticalLog(const char* msg, const char* file, int line, int user1, int user2)
|
|
{
|
|
int len;
|
|
HANDLE h;
|
|
int DontDestroy = 0;
|
|
h = OpenMutex(MUTEX_ALL_ACCESS, FALSE, TEXT("MeshAgentKvmLogLock"));
|
|
if (h == NULL)
|
|
{
|
|
if (GetLastError() != ERROR_FILE_NOT_FOUND) return;
|
|
if ((h = CreateMutex(NULL, TRUE, TEXT("MeshAgentKvmLogLock"))) == NULL) return;
|
|
DontDestroy = 1;
|
|
}
|
|
else
|
|
{
|
|
WaitForSingleObject(h, INFINITE);
|
|
}
|
|
len = sprintf_s(ILibScratchPad, sizeof(ILibScratchPad), "\r\n%s:%d (%d,%d) %s", file, line, user1, user2, msg);
|
|
if (len > 0 && len < (int)sizeof(ILibScratchPad)) ILibAppendStringToDiskEx("C:\\Temp\\MeshAgentKvm.log", ILibScratchPad, len);
|
|
ReleaseMutex(h);
|
|
if (DontDestroy == 0) CloseHandle(h);
|
|
}
|
|
#define KVMDEBUG(m,u) { KvmCriticalLog(m, __FILE__, __LINE__, u, GetLastError()); printf("KVMMSG: %s (%d,%d).\r\n", m, (int)u, (int)GetLastError()); }
|
|
#else
|
|
#define KVMDEBUG(m, u)
|
|
#endif
|
|
|
|
int TILE_WIDTH = 0;
|
|
int TILE_HEIGHT = 0;
|
|
int SCREEN_COUNT = -1; // Total number of displays
|
|
int SCREEN_SEL = 0; // Currently selected display (0 = all)
|
|
int SCREEN_SEL_TARGET = 0; // Desired selected display (0 = all)
|
|
int SCREEN_SEL_PROCESS = 0; // In process of changing displays (0 = all)
|
|
int SCREEN_X = 0; // Left most of current screen
|
|
int SCREEN_Y = 0; // Top most of current screen
|
|
int SCREEN_WIDTH = 0; // Width of current screen
|
|
int SCREEN_HEIGHT = 0; // Height of current screen
|
|
int VSCREEN_X = 0; // Left most of virtual screen
|
|
int VSCREEN_Y = 0; // Top most of virtual screen
|
|
int VSCREEN_WIDTH = 0; // Width of virtual screen
|
|
int VSCREEN_HEIGHT = 0; // Height of virtual screen
|
|
int SCALED_WIDTH = 0;
|
|
int SCALED_HEIGHT = 0;
|
|
int PIXEL_SIZE = 0;
|
|
int TILE_WIDTH_COUNT = 0;
|
|
int TILE_HEIGHT_COUNT = 0;
|
|
int COMPRESSION_RATIO = 0;
|
|
int SCALING_FACTOR = 1024; // Scaling factor, 1024 = 100%
|
|
int SCALING_FACTOR_NEW = 1024; // Desired scaling factor, 1024 = 100%
|
|
int FRAME_RATE_TIMER = 0;
|
|
HANDLE kvmthread = NULL;
|
|
int g_shutdown = 999;
|
|
int g_pause = 0;
|
|
int g_remotepause = 1;
|
|
int g_restartcount = 0;
|
|
struct tileInfo_t **tileInfo = NULL;
|
|
int g_slavekvm = 0;
|
|
static ILibProcessPipe_Process gChildProcess;
|
|
int kvm_relay_restart(int paused, void *pipeMgr, char *exePath, ILibKVM_WriteHandler writeHandler, void *reserved);
|
|
|
|
HANDLE hStdOut = INVALID_HANDLE_VALUE;
|
|
HANDLE hStdIn = INVALID_HANDLE_VALUE;
|
|
int ThreadRunning = 0;
|
|
|
|
ILibRemoteLogging gKVMRemoteLogging = NULL;
|
|
#ifdef _WINSERVICE
|
|
void kvm_slave_OnRawForwardLog(ILibRemoteLogging sender, ILibRemoteLogging_Modules module, ILibRemoteLogging_Flags flags, char *buffer, int bufferLen)
|
|
{
|
|
if (flags <= ILibRemoteLogging_Flags_VerbosityLevel_1)
|
|
{
|
|
KVMDebugLog *log = (KVMDebugLog*)buffer;
|
|
log->length = bufferLen + 1;
|
|
log->logType = (unsigned short)module;
|
|
log->logFlags = (unsigned short)flags;
|
|
buffer[bufferLen] = 0;
|
|
|
|
WriteFile(GetStdHandle(STD_ERROR_HANDLE), buffer, log->length, &bufferLen, NULL);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
void kvm_setupSasPermissions()
|
|
{
|
|
DWORD dw = 3;
|
|
HKEY key = NULL;
|
|
|
|
KVMDEBUG("kvm_setupSasPermissions", 0);
|
|
|
|
// SoftwareSASGeneration
|
|
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\System", 0, KEY_ALL_ACCESS, &key) == ERROR_SUCCESS)
|
|
{
|
|
RegSetValueEx(key, "SoftwareSASGeneration", 0, REG_DWORD, (BYTE*)&dw, 4);
|
|
RegCloseKey(key);
|
|
}
|
|
}
|
|
|
|
// Emulate the CTRL-ALT-DEL (Should work on WinXP, not on Vista & Win7)
|
|
DWORD WINAPI kvm_ctrlaltdel(LPVOID Param)
|
|
{
|
|
OSVERSIONINFO osv;
|
|
|
|
UNREFERENCED_PARAMETER( Param );
|
|
|
|
KVMDEBUG("kvm_ctrlaltdel", (int)Param);
|
|
|
|
osv.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
|
if (!GetVersionEx(&osv)) return 0;
|
|
|
|
if (osv.dwMajorVersion < 6)
|
|
{
|
|
// Perform old method (WinXP)
|
|
HWND hwnd = NULL;
|
|
HWINSTA ws;
|
|
HDESK hdesk = NULL;
|
|
|
|
ws = OpenWindowStation("winsta0", FALSE,
|
|
WINSTA_ACCESSCLIPBOARD |
|
|
WINSTA_ACCESSGLOBALATOMS |
|
|
WINSTA_CREATEDESKTOP |
|
|
WINSTA_ENUMDESKTOPS |
|
|
WINSTA_ENUMERATE |
|
|
WINSTA_EXITWINDOWS |
|
|
WINSTA_READATTRIBUTES |
|
|
WINSTA_READSCREEN |
|
|
WINSTA_WRITEATTRIBUTES);
|
|
if (ws != NULL)
|
|
{
|
|
SetProcessWindowStation(ws);
|
|
CloseWindowStation(ws);
|
|
}
|
|
|
|
hdesk = OpenDesktop("Winlogon", 0, FALSE,
|
|
DESKTOP_CREATEMENU |
|
|
DESKTOP_CREATEWINDOW |
|
|
DESKTOP_ENUMERATE |
|
|
DESKTOP_HOOKCONTROL |
|
|
DESKTOP_JOURNALPLAYBACK |
|
|
DESKTOP_JOURNALRECORD |
|
|
DESKTOP_READOBJECTS |
|
|
DESKTOP_SWITCHDESKTOP |
|
|
DESKTOP_WRITEOBJECTS);
|
|
if (hdesk != NULL && SetThreadDesktop(hdesk) == TRUE)
|
|
|
|
hwnd = FindWindow("SAS window class", "SAS window");
|
|
if (hwnd == NULL) hwnd = HWND_BROADCAST;
|
|
SendMessage(hwnd, WM_HOTKEY, 0, MAKELONG(MOD_ALT | MOD_CONTROL, VK_DELETE));
|
|
if (hdesk != NULL) CloseDesktop(hdesk);
|
|
}
|
|
else
|
|
{
|
|
// Perform new method (Vista & Win7)
|
|
typedef VOID (WINAPI *SendSas)(BOOL asUser);
|
|
SendSas sas;
|
|
HMODULE sm = NULL;
|
|
if ((sm = LoadLibrary("sas.dll")) != NULL)
|
|
{
|
|
sas = (SendSas)GetProcAddress(sm, "SendSAS");
|
|
kvm_setupSasPermissions();
|
|
if (sas != NULL) sas(FALSE);
|
|
FreeLibrary(sm);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
BOOL CALLBACK DisplayInfoEnumProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData)
|
|
{
|
|
int w, h, deviceid = 0;
|
|
MONITORINFOEX mi;
|
|
|
|
UNREFERENCED_PARAMETER( hdcMonitor );
|
|
UNREFERENCED_PARAMETER( lprcMonitor );
|
|
UNREFERENCED_PARAMETER( dwData );
|
|
|
|
ZeroMemory(&mi, sizeof(mi));
|
|
mi.cbSize = sizeof(mi);
|
|
|
|
// Get the display information
|
|
if (!GetMonitorInfo(hMonitor, (LPMONITORINFO)&mi)) return TRUE;
|
|
if (sscanf_s(mi.szDevice, "\\\\.\\DISPLAY%d", &deviceid) != 1) return TRUE;
|
|
if (deviceid != SCREEN_SEL_TARGET) return TRUE;
|
|
|
|
// See if anything changed
|
|
w = abs(mi.rcMonitor.left - mi.rcMonitor.right);
|
|
h = abs(mi.rcMonitor.top - mi.rcMonitor.bottom);
|
|
if (SCREEN_X != mi.rcMonitor.left || SCREEN_Y != mi.rcMonitor.top || SCREEN_WIDTH != w || SCREEN_HEIGHT != h || SCALING_FACTOR != SCALING_FACTOR_NEW)
|
|
{
|
|
SCREEN_X = mi.rcMonitor.left;
|
|
SCREEN_Y = mi.rcMonitor.top;
|
|
SCREEN_WIDTH = w;
|
|
SCREEN_HEIGHT = h;
|
|
SCREEN_SEL_PROCESS |= 1; // Force the new resolution to be sent to the client.
|
|
}
|
|
|
|
if (SCREEN_SEL != SCREEN_SEL_TARGET)
|
|
{
|
|
SCREEN_SEL = SCREEN_SEL_TARGET;
|
|
SCREEN_SEL_PROCESS |= 2; // Force the display list to be sent to the client, includes the new display selection
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void kvm_send_display_list(ILibKVM_WriteHandler writeHandler, void *reserved)
|
|
{
|
|
int i;
|
|
|
|
// Not looked at the number of screens yet
|
|
if (SCREEN_COUNT == -1) return;
|
|
|
|
// Send the list of possible displays to remote
|
|
if (SCREEN_COUNT == 0 || SCREEN_COUNT == 1)
|
|
{
|
|
// Only one display, send empty
|
|
((unsigned short*)ILibScratchPad2)[0] = (unsigned short)htons((unsigned short)MNG_KVM_GET_DISPLAYS); // Write the type
|
|
((unsigned short*)ILibScratchPad2)[1] = (unsigned short)htons((unsigned short)(10 + (2 * SCREEN_COUNT))); // Write the size
|
|
((unsigned short*)ILibScratchPad2)[2] = (unsigned short)htons((unsigned short)(0)); // Screen Count
|
|
((unsigned short*)ILibScratchPad2)[2] = (unsigned short)htons((unsigned short)(0)); // Selected Screen
|
|
|
|
writeHandler(ILibScratchPad2, (10 + (2 * SCREEN_COUNT)), reserved);
|
|
}
|
|
else
|
|
{
|
|
// Many displays
|
|
((unsigned short*)ILibScratchPad2)[0] = (unsigned short)htons((unsigned short)MNG_KVM_GET_DISPLAYS); // Write the type
|
|
((unsigned short*)ILibScratchPad2)[1] = (unsigned short)htons((unsigned short)(10 + (2 * SCREEN_COUNT))); // Write the size
|
|
((unsigned short*)ILibScratchPad2)[2] = (unsigned short)htons((unsigned short)(SCREEN_COUNT + 1)); // Screen Count
|
|
((unsigned short*)ILibScratchPad2)[3] = (unsigned short)htons((unsigned short)(-1)); // Possible Screen (ALL)
|
|
for (i = 0; i < SCREEN_COUNT; i++) {
|
|
((unsigned short*)ILibScratchPad2)[4 + i] = (unsigned short)htons((unsigned short)(i + 1)); // Possible Screen
|
|
}
|
|
if (SCREEN_SEL == 0) {
|
|
((unsigned short*)ILibScratchPad2)[4 + i] = (unsigned short)htons((unsigned short)(-1)); // Selected Screen (All)
|
|
} else {
|
|
((unsigned short*)ILibScratchPad2)[4 + i] = (unsigned short)htons((unsigned short)(SCREEN_SEL)); // Selected Screen
|
|
}
|
|
|
|
writeHandler(ILibScratchPad2, (10 + (2 * SCREEN_COUNT)), reserved);
|
|
}
|
|
}
|
|
|
|
void kvm_server_SetResolution();
|
|
int kvm_server_currentDesktopname = 0;
|
|
void CheckDesktopSwitch(int checkres, ILibKVM_WriteHandler writeHandler, void *reserved)
|
|
{
|
|
int x, y, w, h;
|
|
HDESK desktop;
|
|
HDESK desktop2;
|
|
char name[64];
|
|
|
|
// KVMDEBUG("CheckDesktopSwitch", checkres);
|
|
|
|
// Check desktop switch
|
|
if ((desktop2 = GetThreadDesktop(GetCurrentThreadId())) == NULL) { KVMDEBUG("GetThreadDesktop Error", 0); } // CloseDesktop() is not needed
|
|
if ((desktop = OpenInputDesktop(0, TRUE,
|
|
DESKTOP_CREATEMENU |
|
|
DESKTOP_CREATEWINDOW |
|
|
DESKTOP_ENUMERATE |
|
|
DESKTOP_HOOKCONTROL |
|
|
DESKTOP_WRITEOBJECTS |
|
|
DESKTOP_READOBJECTS |
|
|
DESKTOP_SWITCHDESKTOP |
|
|
GENERIC_WRITE)) == NULL) { KVMDEBUG("OpenInputDesktop Error", 0); }
|
|
|
|
if (SetThreadDesktop(desktop) == 0)
|
|
{
|
|
if (CloseDesktop(desktop) == 0) { KVMDEBUG("CloseDesktop1 Error", 0); }
|
|
desktop = desktop2;
|
|
} else {
|
|
CloseDesktop(desktop2);
|
|
}
|
|
|
|
// Check desktop name switch
|
|
if (GetUserObjectInformationA(desktop, UOI_NAME, name, 63, 0))
|
|
{
|
|
//ILibRemoteLogging_printf(gKVMRemoteLogging, ILibRemoteLogging_Modules_Agent_KVM, ILibRemoteLogging_Flags_VerbosityLevel_1, "KVM [SLAVE]: name = %s", name);
|
|
|
|
// KVMDEBUG(name, 0);
|
|
if (kvm_server_currentDesktopname == 0)
|
|
{
|
|
// This is the first time we come here.
|
|
kvm_server_currentDesktopname = ((int*)name)[0];
|
|
}
|
|
else
|
|
{
|
|
// If the desktop name has changed, shutdown.
|
|
if (kvm_server_currentDesktopname != ((int*)name)[0])
|
|
{
|
|
KVMDEBUG("DESKTOP NAME CHANGE DETECTED, triggering shutdown", 0);
|
|
ILibRemoteLogging_printf(gKVMRemoteLogging, ILibRemoteLogging_Modules_Agent_KVM, ILibRemoteLogging_Flags_VerbosityLevel_1, "KVM [SLAVE]: kvm_server_currentDesktop: NAME CHANGE DETECTED...");
|
|
g_shutdown = 1;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
KVMDEBUG("GetUserObjectInformation Error", 0);
|
|
}
|
|
|
|
// See if the number of displays has changed
|
|
x = GetSystemMetrics(SM_CMONITORS);
|
|
if (SCREEN_COUNT != x) { SCREEN_COUNT = x; kvm_send_display_list(writeHandler, reserved); }
|
|
|
|
// Check resolution change
|
|
if (checkres != 0 && g_shutdown == 0)
|
|
{
|
|
VSCREEN_X = GetSystemMetrics(SM_XVIRTUALSCREEN);
|
|
VSCREEN_Y = GetSystemMetrics(SM_YVIRTUALSCREEN);
|
|
VSCREEN_WIDTH = GetSystemMetrics(SM_CXVIRTUALSCREEN);
|
|
VSCREEN_HEIGHT = GetSystemMetrics(SM_CYVIRTUALSCREEN);
|
|
|
|
if (SCREEN_SEL_TARGET == 0)
|
|
{
|
|
if (VSCREEN_WIDTH == 0)
|
|
{
|
|
// Old style, one display only. Added this just in case VIRTUALSCREEN does not work.
|
|
x = 0;
|
|
y = 0;
|
|
w = GetSystemMetrics(SM_CXSCREEN);
|
|
h = GetSystemMetrics(SM_CYSCREEN);
|
|
} else {
|
|
// New style, entire virtual desktop
|
|
x = VSCREEN_X;
|
|
y = VSCREEN_Y;
|
|
w = VSCREEN_WIDTH;
|
|
h = VSCREEN_HEIGHT;
|
|
}
|
|
|
|
if (SCREEN_X != x || SCREEN_Y != y || SCREEN_WIDTH != w || SCREEN_HEIGHT != h || SCALING_FACTOR != SCALING_FACTOR_NEW)
|
|
{
|
|
SCREEN_X = x;
|
|
SCREEN_Y = y;
|
|
SCREEN_WIDTH = w;
|
|
SCREEN_HEIGHT = h;
|
|
kvm_server_SetResolution(writeHandler, reserved);
|
|
}
|
|
|
|
if (SCREEN_SEL_TARGET != SCREEN_SEL) { SCREEN_SEL = SCREEN_SEL_TARGET; kvm_send_display_list(writeHandler, reserved); }
|
|
}
|
|
else
|
|
{
|
|
// Get the list of monitors
|
|
if (SCREEN_SEL_PROCESS == 0)
|
|
{
|
|
if (EnumDisplayMonitors(NULL, NULL, DisplayInfoEnumProc, 0))
|
|
{
|
|
// Set the resolution
|
|
if (SCREEN_SEL_PROCESS & 1) kvm_server_SetResolution(writeHandler, reserved);
|
|
if (SCREEN_SEL_PROCESS & 2) kvm_send_display_list(writeHandler, reserved);
|
|
}
|
|
SCREEN_SEL_PROCESS = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Push keyboard events to the default input desktop
|
|
// Used for remote messaging keyboard input
|
|
void kvm_keyboardInput(char* block, int blocklen)
|
|
{
|
|
int i;
|
|
|
|
KVMDEBUG("kvm_keyboardInput", blocklen);
|
|
|
|
/*
|
|
HWINSTA ws1, ws2;
|
|
HDESK desktop, desktop2;
|
|
|
|
ws2 = GetProcessWindowStation();
|
|
ws1 = OpenWindowStation(_T("winsta0"), FALSE,
|
|
WINSTA_ACCESSCLIPBOARD |
|
|
WINSTA_ACCESSGLOBALATOMS |
|
|
WINSTA_CREATEDESKTOP |
|
|
WINSTA_ENUMDESKTOPS |
|
|
WINSTA_ENUMERATE |
|
|
WINSTA_EXITWINDOWS |
|
|
WINSTA_READATTRIBUTES |
|
|
WINSTA_READSCREEN |
|
|
WINSTA_WRITEATTRIBUTES);
|
|
if (ws1 != NULL) SetProcessWindowStation(ws1);
|
|
|
|
// Check desktop switch
|
|
desktop2 = GetThreadDesktop(GetCurrentThreadId());
|
|
desktop = OpenInputDesktop(0, TRUE,
|
|
DESKTOP_CREATEMENU |
|
|
DESKTOP_CREATEWINDOW |
|
|
DESKTOP_ENUMERATE |
|
|
DESKTOP_HOOKCONTROL |
|
|
DESKTOP_WRITEOBJECTS |
|
|
DESKTOP_READOBJECTS |
|
|
DESKTOP_SWITCHDESKTOP |
|
|
GENERIC_WRITE);
|
|
SetThreadDesktop(desktop);
|
|
*/
|
|
|
|
for (i = 1; i < blocklen; i += 2) KeyAction(block[i], block[i - 1]);
|
|
|
|
/*
|
|
if (ws1 != NULL) { SetProcessWindowStation(ws2); CloseWindowStation(ws1); }
|
|
SetThreadDesktop(desktop2);
|
|
CloseDesktop(desktop);
|
|
*/
|
|
}
|
|
|
|
// Feed network data into the KVM. Return the number of bytes consumed.
|
|
// This method consumes a single command.
|
|
int kvm_server_inputdata(char* block, int blocklen, ILibKVM_WriteHandler writeHandler, void *reserved)
|
|
{
|
|
unsigned short type, size;
|
|
|
|
ILibRemoteLogging_printf(gKVMRemoteLogging, ILibRemoteLogging_Modules_Agent_KVM, ILibRemoteLogging_Flags_VerbosityLevel_2, "KVM [SLAVE]: Handle Input [Len = %d]", blocklen);
|
|
// KVMDEBUG("kvm_server_inputdata", blocklen);
|
|
CheckDesktopSwitch(0, writeHandler, reserved);
|
|
|
|
// Decode the block header
|
|
if (blocklen < 4) return 0;
|
|
type = ntohs(((unsigned short*)(block))[0]);
|
|
size = ntohs(((unsigned short*)(block))[1]);
|
|
|
|
ILibRemoteLogging_printf(gKVMRemoteLogging, ILibRemoteLogging_Modules_Agent_KVM, ILibRemoteLogging_Flags_VerbosityLevel_2, "KVM [SLAVE]: Handle Input [Len = %d, type = %u, size = %u]", blocklen, type, size);
|
|
|
|
if (size > blocklen) return 0;
|
|
|
|
//printf("INPUT: %d, %d\r\n", type, size);
|
|
|
|
switch (type)
|
|
{
|
|
case MNG_KVM_KEY: // Key
|
|
{
|
|
if (size != 6) break;
|
|
KeyAction(block[5], block[4]);
|
|
break;
|
|
}
|
|
case MNG_KVM_MOUSE: // Mouse
|
|
{
|
|
double x, y;
|
|
short w = 0;
|
|
if (size == 10 || size == 12)
|
|
{
|
|
// Get positions and scale correctly
|
|
x = (double)ntohs(((short*)(block))[3]) * 1024 / SCALING_FACTOR;
|
|
y = (double)ntohs(((short*)(block))[4]) * 1024 / SCALING_FACTOR;
|
|
|
|
// Add relative display position
|
|
x += fabs((double)(SCREEN_X - VSCREEN_X));
|
|
y += fabs((double)(SCREEN_Y - VSCREEN_Y));
|
|
|
|
// Scale back to the virtual screen
|
|
x = (x * ((double)SCREEN_WIDTH / (double)VSCREEN_WIDTH)) * (double)65535;
|
|
y = (y * ((double)SCREEN_HEIGHT / (double)VSCREEN_HEIGHT)) * (double)65535;
|
|
|
|
// Perform the mouse movement
|
|
if (size == 12) w = ((short)ntohs(((short*)(block))[5]));
|
|
MouseAction((((double)x / (double)SCREEN_WIDTH)), (((double)y / (double)SCREEN_HEIGHT)), block[5], w);
|
|
}
|
|
break;
|
|
}
|
|
case MNG_KVM_COMPRESSION: // Compression
|
|
{
|
|
if (size >= 10) { int fr = ((int)ntohs(((unsigned short*)(block + 8))[0])); if (fr >= 20 && fr <= 5000) FRAME_RATE_TIMER = fr; }
|
|
if (size >= 8) { int ns = ((int)ntohs(((unsigned short*)(block + 6))[0])); if (ns >= 64 && ns <= 4096) SCALING_FACTOR_NEW = ns; }
|
|
if (size >= 6) { set_tile_compression((int)block[4], (int)block[5]); }
|
|
COMPRESSION_RATIO = 100;
|
|
break;
|
|
}
|
|
case MNG_KVM_REFRESH: // Refresh
|
|
{
|
|
int row, col;
|
|
char buffer[8];
|
|
if (size != 4) break;
|
|
|
|
((unsigned short*)buffer)[0] = (unsigned short)htons((unsigned short)MNG_KVM_SCREEN); // Write the type
|
|
((unsigned short*)buffer)[1] = (unsigned short)htons((unsigned short)8); // Write the size
|
|
((unsigned short*)buffer)[2] = (unsigned short)htons((unsigned short)SCALED_WIDTH); // X position
|
|
((unsigned short*)buffer)[3] = (unsigned short)htons((unsigned short)SCALED_HEIGHT); // Y position
|
|
|
|
writeHandler((char*)buffer, 8, reserved);
|
|
|
|
// Send the list of available displays
|
|
kvm_send_display_list(writeHandler, reserved);
|
|
|
|
// Reset all tile information
|
|
if (tileInfo == NULL) {
|
|
if ((tileInfo = (struct tileInfo_t **) malloc(TILE_HEIGHT_COUNT * sizeof(struct tileInfo_t *))) == NULL) ILIBCRITICALEXIT(254);
|
|
for (row = 0; row < TILE_HEIGHT_COUNT; row++) { if ((tileInfo[row] = (struct tileInfo_t *)malloc(TILE_WIDTH_COUNT * sizeof(struct tileInfo_t))) == NULL) ILIBCRITICALEXIT(254); }
|
|
}
|
|
for (row = 0; row < TILE_HEIGHT_COUNT; row++) { for (col = 0; col < TILE_WIDTH_COUNT; col++) { tileInfo[row][col].crc = 0xFF; tileInfo[row][col].flags = 0; } }
|
|
|
|
break;
|
|
}
|
|
case MNG_KVM_PAUSE: // Pause
|
|
{
|
|
if (size != 5) break;
|
|
g_remotepause = block[4];
|
|
break;
|
|
}
|
|
case MNG_KVM_FRAME_RATE_TIMER:
|
|
{
|
|
int fr = ((int)ntohs(((unsigned short*)(block))[2]));
|
|
if (fr >= 20 && fr <= 5000) FRAME_RATE_TIMER = fr;
|
|
break;
|
|
}
|
|
case MNG_KVM_INIT_TOUCH:
|
|
{
|
|
// Attempt to initialized touch support
|
|
char buffer[6];
|
|
unsigned short r = (unsigned short)TouchInit();
|
|
((unsigned short*)buffer)[0] = (unsigned short)htons((unsigned short)MNG_KVM_INIT_TOUCH); // Write the type
|
|
((unsigned short*)buffer)[1] = (unsigned short)htons((unsigned short)6); // Write the size
|
|
((unsigned short*)buffer)[2] = (unsigned short)htons(r); // Write the return code
|
|
|
|
writeHandler((char*)buffer, 6, reserved);
|
|
break;
|
|
}
|
|
case MNG_KVM_TOUCH:
|
|
{
|
|
int r = 0;
|
|
|
|
if (block[4] == 1) // Version 1 touch structure (Very simple)
|
|
{
|
|
unsigned int flags = (unsigned int)ntohl(((unsigned int*)(block + 6))[0]);
|
|
|
|
// Get positions and scale correctly
|
|
unsigned short x = (unsigned short)(ntohs(((unsigned short*)(block + 10))[0])) * 1024 / (unsigned short)SCALING_FACTOR;
|
|
unsigned short y = (unsigned short)(ntohs(((unsigned short*)(block + 12))[0])) * 1024 / (unsigned short)SCALING_FACTOR;
|
|
|
|
// Add relative display position
|
|
x += (unsigned short)fabs((double)(SCREEN_X - VSCREEN_X));
|
|
y += (unsigned short)fabs((double)(SCREEN_Y - VSCREEN_Y));
|
|
|
|
// Scale back to the virtual screen
|
|
x = (unsigned short)(((double)x * ((double)SCREEN_WIDTH / (double)VSCREEN_WIDTH)) * (double)65535);
|
|
y = (unsigned short)(((double)y * ((double)SCREEN_HEIGHT / (double)VSCREEN_HEIGHT)) * (double)65535);
|
|
|
|
r = TouchAction1(block[5], flags, x, y);
|
|
}
|
|
else if (block[4] == 2) // Version 2 touch structure array
|
|
{
|
|
r = TouchAction2(block + 5, size - 5, SCALING_FACTOR);
|
|
}
|
|
|
|
if (r == 1) {
|
|
// Reset touch
|
|
char buffer[4];
|
|
((unsigned short*)buffer)[0] = (unsigned short)htons((unsigned short)MNG_KVM_TOUCH); // Write the type
|
|
((unsigned short*)buffer)[1] = (unsigned short)htons((unsigned short)4); // Write the size
|
|
|
|
writeHandler((char*)buffer, 4, reserved);
|
|
}
|
|
break;
|
|
}
|
|
case MNG_KVM_GET_DISPLAYS:
|
|
{
|
|
kvm_send_display_list(writeHandler, reserved);
|
|
break;
|
|
}
|
|
case MNG_KVM_SET_DISPLAY:
|
|
{
|
|
// Set the display
|
|
int x = 0;
|
|
if (size < 6) break;
|
|
x = (unsigned short)ntohs(((unsigned short*)(block + 4))[0]);
|
|
if (x == 65535) SCREEN_SEL_TARGET = 0; else SCREEN_SEL_TARGET = x;
|
|
break;
|
|
}
|
|
}
|
|
return size;
|
|
}
|
|
|
|
// Feed network data into the KVM. Return the number of bytes consumed.
|
|
// This method consumes as many input commands as it can.
|
|
int kvm_relay_feeddata(char* buf, int len, ILibKVM_WriteHandler writeHandler, void *reserved)
|
|
{
|
|
#ifdef _WINSERVICE
|
|
if (len >= 2 && ntohs(((unsigned short*)buf)[0]) == MNG_CTRLALTDEL)
|
|
{
|
|
HANDLE ht = CreateThread(NULL, 0, kvm_ctrlaltdel, 0, 0, 0);
|
|
if (ht != NULL) CloseHandle(ht);
|
|
}
|
|
ILibProcessPipe_Process_WriteStdIn(gChildProcess, buf, len, ILibTransport_MemoryOwnership_USER);
|
|
ILibRemoteLogging_printf(ILibChainGetLogger(gILibChain), ILibRemoteLogging_Modules_Microstack_Generic, ILibRemoteLogging_Flags_VerbosityLevel_2, "KVM [Master]: Write Input [Type = %u]", ntohs(((unsigned short*)buf)[0]));
|
|
return len;
|
|
#else
|
|
int len2 = 0;
|
|
int ptr = 0;
|
|
while ((len2 = kvm_server_inputdata(buf + ptr, len - ptr, writeHandler, reserved)) != 0) { ptr += len2; }
|
|
return ptr;
|
|
#endif
|
|
}
|
|
|
|
// Set the KVM pause state
|
|
void kvm_pause(int pause)
|
|
{
|
|
// KVMDEBUG("kvm_pause", pause);
|
|
if (gChildProcess == NULL)
|
|
{
|
|
g_pause = pause;
|
|
}
|
|
else
|
|
{
|
|
if (pause == 0)
|
|
{
|
|
ILibProcessPipe_Pipe_Resume(ILibProcessPipe_Process_GetStdOut(gChildProcess));
|
|
}
|
|
else
|
|
{
|
|
ILibProcessPipe_Pipe_Pause(ILibProcessPipe_Process_GetStdOut(gChildProcess));
|
|
}
|
|
}
|
|
}
|
|
|
|
void kvm_server_SetResolution(ILibKVM_WriteHandler writeHandler, void *reserved)
|
|
{
|
|
char buffer[8];
|
|
int row, col;
|
|
|
|
KVMDEBUG("kvm_server_SetResolution", 0);
|
|
|
|
// Free the tileInfo before you manipulate the TILE_HEIGHT_COUNT
|
|
if (tileInfo != NULL) { for (row = 0; row < TILE_HEIGHT_COUNT; row++) { free(tileInfo[row]); } free(tileInfo); tileInfo = NULL; }
|
|
|
|
// Setup scaling
|
|
SCALING_FACTOR = SCALING_FACTOR_NEW;
|
|
SCALED_WIDTH = (SCREEN_WIDTH * SCALING_FACTOR) / 1024;
|
|
SCALED_HEIGHT = (SCREEN_HEIGHT * SCALING_FACTOR) / 1024;
|
|
|
|
// Compute the tile count
|
|
TILE_WIDTH_COUNT = SCALED_WIDTH / TILE_WIDTH;
|
|
TILE_HEIGHT_COUNT = SCALED_HEIGHT / TILE_HEIGHT;
|
|
if (SCALED_WIDTH % TILE_WIDTH) TILE_WIDTH_COUNT++;
|
|
if (SCALED_HEIGHT % TILE_HEIGHT) TILE_HEIGHT_COUNT++;
|
|
|
|
((unsigned short*)buffer)[0] = (unsigned short)htons((unsigned short)MNG_KVM_SCREEN); // Write the type
|
|
((unsigned short*)buffer)[1] = (unsigned short)htons((unsigned short)8); // Write the size
|
|
((unsigned short*)buffer)[2] = (unsigned short)htons((unsigned short)SCALED_WIDTH); // X position
|
|
((unsigned short*)buffer)[3] = (unsigned short)htons((unsigned short)SCALED_HEIGHT); // Y position
|
|
|
|
writeHandler((char*)buffer, 8, reserved);
|
|
|
|
if ((tileInfo = (struct tileInfo_t **)malloc(TILE_HEIGHT_COUNT * sizeof(struct tileInfo_t *))) == NULL) ILIBCRITICALEXIT(254);
|
|
for (row = 0; row < TILE_HEIGHT_COUNT; row++) {
|
|
if ((tileInfo[row] = (struct tileInfo_t *)malloc(TILE_WIDTH_COUNT * sizeof(struct tileInfo_t))) == NULL) ILIBCRITICALEXIT(254);
|
|
}
|
|
for (row = 0; row < TILE_HEIGHT_COUNT; row++) { for (col = 0; col < TILE_WIDTH_COUNT; col++) { tileInfo[row][col].crc = 0xFF; tileInfo[row][col].flags = 0; } }
|
|
}
|
|
|
|
#define BUFSIZE 65535
|
|
#ifdef _WINSERVICE
|
|
DWORD WINAPI kvm_mainloopinput(LPVOID Param)
|
|
{
|
|
int ptr = 0;
|
|
int ptr2 = 0;
|
|
int len = 0;
|
|
char pchRequest2[30000];
|
|
BOOL fSuccess = FALSE;
|
|
DWORD cbBytesRead = 0;
|
|
ILibKVM_WriteHandler writeHandler = (ILibKVM_WriteHandler)((void**)Param)[0];
|
|
void *reserved = ((void**)Param)[1];
|
|
|
|
KVMDEBUG("kvm_mainloopinput / start", (int)GetCurrentThreadId());
|
|
|
|
ILibRemoteLogging_printf(gKVMRemoteLogging, ILibRemoteLogging_Modules_Agent_KVM, ILibRemoteLogging_Flags_VerbosityLevel_1, "KVM [SLAVE]: (mainloopinput) Starting...");
|
|
|
|
|
|
while (!g_shutdown)
|
|
{
|
|
fSuccess = ReadFile(hStdIn, pchRequest2 + len, 30000 - len, &cbBytesRead, NULL);
|
|
if (!fSuccess || cbBytesRead == 0 || g_shutdown)
|
|
{
|
|
ILibRemoteLogging_printf(gKVMRemoteLogging, ILibRemoteLogging_Modules_Agent_KVM, ILibRemoteLogging_Flags_VerbosityLevel_1, "KVM [SLAVE]: fSuccess/%d cbBytesRead/%d g_shutdown/%d", fSuccess, cbBytesRead, g_shutdown);
|
|
KVMDEBUG("ReadFile() failed", 0); /*ILIBMESSAGE("KVMBREAK-K1\r\n");*/ g_shutdown = 1; break;
|
|
}
|
|
len += cbBytesRead;
|
|
ptr2 = 0;
|
|
while ((ptr2 = kvm_server_inputdata((char*)pchRequest2 + ptr, len - ptr, writeHandler, reserved)) != 0) { ptr += ptr2; }
|
|
if (ptr == len) { len = 0; ptr = 0; }
|
|
// TODO: else move the reminder.
|
|
}
|
|
ILibRemoteLogging_printf(gKVMRemoteLogging, ILibRemoteLogging_Modules_Agent_KVM, ILibRemoteLogging_Flags_VerbosityLevel_1, "KVM [SLAVE]: (mainloopinput) Exiting...");
|
|
ILibRemoteLogging_Destroy(gKVMRemoteLogging);
|
|
gKVMRemoteLogging = NULL;
|
|
|
|
KVMDEBUG("kvm_mainloopinput / end", (int)GetCurrentThreadId());
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
// This is the main KVM pooling loop. It will look at the display and see if any changes occur. [Runs as daemon if Windows Service]
|
|
DWORD WINAPI kvm_server_mainloop(LPVOID parm)
|
|
{
|
|
//long cur_timestamp = 0;
|
|
//long prev_timestamp = 0;
|
|
//long time_diff = 50;
|
|
long long tilesize;
|
|
int width, height = 0;
|
|
void *buf, *desktop;
|
|
long long desktopsize;
|
|
BITMAPINFO bmpInfo;
|
|
int row, col;
|
|
ILibKVM_WriteHandler writeHandler = (ILibKVM_WriteHandler)((void**)parm)[0];
|
|
void *reserved = ((void**)parm)[1];
|
|
|
|
#ifdef _WINSERVICE
|
|
gKVMRemoteLogging = ILibRemoteLogging_Create(NULL);
|
|
ILibRemoteLogging_SetRawForward(gKVMRemoteLogging, sizeof(KVMDebugLog), kvm_slave_OnRawForwardLog);
|
|
ILibRemoteLogging_printf(gKVMRemoteLogging, ILibRemoteLogging_Modules_Agent_KVM, ILibRemoteLogging_Flags_VerbosityLevel_1, "KVM [SLAVE]: Child Processing Running...");
|
|
#endif
|
|
|
|
// This basic lock will prevent 2 thread from running at the same time. Gives time for the first one to fully exit.
|
|
while (ThreadRunning != 0 && height < 200) { height++; Sleep(50); }
|
|
if (height >= 200 && ThreadRunning != 0) return 0;
|
|
ThreadRunning = 1;
|
|
g_shutdown = 0;
|
|
|
|
g_pause = 0;
|
|
g_remotepause = ((int*)&(((void**)parm)[2]))[0];
|
|
|
|
KVMDEBUG("kvm_server_mainloop / start1", (int)GetCurrentThreadId());
|
|
|
|
#ifdef _WINSERVICE
|
|
hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
|
|
hStdIn = GetStdHandle(STD_INPUT_HANDLE);
|
|
#endif
|
|
|
|
KVMDEBUG("kvm_server_mainloop / start2", (int)GetCurrentThreadId());
|
|
|
|
if (!initialize_gdiplus())
|
|
{
|
|
#ifdef _WINSERVICE
|
|
ILibRemoteLogging_printf(gKVMRemoteLogging, ILibRemoteLogging_Modules_Agent_KVM, ILibRemoteLogging_Flags_VerbosityLevel_1, "KVM [SLAVE]: initialize_gdiplus() failed");
|
|
#endif
|
|
KVMDEBUG("kvm_server_mainloop / initialize_gdiplus failed", (int)GetCurrentThreadId()); return 0;
|
|
}
|
|
#ifdef _WINSERVICE
|
|
ILibRemoteLogging_printf(gKVMRemoteLogging, ILibRemoteLogging_Modules_Agent_KVM, ILibRemoteLogging_Flags_VerbosityLevel_1, "KVM [SLAVE]: initialize_gdiplus() SUCCESS");
|
|
#endif
|
|
kvm_server_SetResolution(writeHandler, reserved);
|
|
|
|
#ifdef _WINSERVICE
|
|
g_shutdown = 0;
|
|
kvmthread = CreateThread(NULL, 0, kvm_mainloopinput, parm, 0, 0);
|
|
#endif
|
|
|
|
// Set all CRCs to 0xFF
|
|
for (row = 0; row < TILE_HEIGHT_COUNT; row++) {
|
|
for (col = 0; col < TILE_WIDTH_COUNT; col++) {
|
|
tileInfo[row][col].crc = 0xFF;
|
|
}
|
|
}
|
|
|
|
// Send the list of displays
|
|
kvm_send_display_list(writeHandler, reserved);
|
|
|
|
Sleep(100); // Pausing here seems to fix connection issues, especially with WebRTC. TODO: Investigate why.
|
|
KVMDEBUG("kvm_server_mainloop / start3", (int)GetCurrentThreadId());
|
|
|
|
// Loop and send only when a tile changes.
|
|
while (!g_shutdown)
|
|
{
|
|
/*
|
|
cur_timestamp = util_gettime();
|
|
if (prev_timestamp != 0)
|
|
{
|
|
time_diff = (FRAME_RATE_TIMER - (cur_timestamp - prev_timestamp));
|
|
if (time_diff < 20) { time_diff = 20; }
|
|
}
|
|
printf("%d\r\n", cur_timestamp);
|
|
Sleep(time_diff);
|
|
prev_timestamp = cur_timestamp;
|
|
*/
|
|
|
|
KVMDEBUG("kvm_server_mainloop / loop1", (int)GetCurrentThreadId());
|
|
|
|
// Reset all the flags to TILE_TODO
|
|
for (row = 0; row < TILE_HEIGHT_COUNT; row++) {
|
|
for (col = 0; col < TILE_WIDTH_COUNT; col++) {
|
|
tileInfo[row][col].flags = (char)TILE_TODO;
|
|
}
|
|
}
|
|
CheckDesktopSwitch(1, writeHandler, reserved);
|
|
if (g_shutdown) break;
|
|
|
|
// Scan the desktop
|
|
if (get_desktop_buffer(&desktop, &desktopsize) == 1)
|
|
{
|
|
#ifdef _WINSERVICE
|
|
ILibRemoteLogging_printf(gKVMRemoteLogging, ILibRemoteLogging_Modules_Agent_KVM, ILibRemoteLogging_Flags_VerbosityLevel_1, "KVM [SLAVE]: get_desktop_buffer() failed");
|
|
#endif
|
|
KVMDEBUG("get_desktop_buffer() failed, shutting down", (int)GetCurrentThreadId());
|
|
g_shutdown = 1;
|
|
}
|
|
else {
|
|
bmpInfo = get_bmp_info(TILE_WIDTH, TILE_HEIGHT);
|
|
for (row = 0; row < TILE_HEIGHT_COUNT; row++) {
|
|
for (col = 0; col < TILE_WIDTH_COUNT; col++) {
|
|
height = TILE_HEIGHT * row;
|
|
width = TILE_WIDTH * col;
|
|
|
|
while (!g_shutdown && (g_pause)) { Sleep(50); /*printf(".");*/ } // If the socket is in pause state, wait here. //ToDo: YLIAN!!!!
|
|
|
|
if (g_shutdown || SCALING_FACTOR != SCALING_FACTOR_NEW) { height = SCALED_HEIGHT; width = SCALED_WIDTH; break; }
|
|
|
|
// Skip the tile if it has already been sent or if the CRC is same as before
|
|
if (tileInfo[row][col].flags == (char)TILE_SENT || tileInfo[row][col].flags == (char)TILE_DONT_SEND) { continue; }
|
|
|
|
if (get_tile_at(width, height, &buf, &tilesize, desktop, row, col) == 1)
|
|
{
|
|
// GetTileAt failed, lets not send the tile
|
|
continue;
|
|
}
|
|
if (buf && !g_shutdown)
|
|
{
|
|
switch (writeHandler((char*)buf, (int)tilesize, reserved))
|
|
{
|
|
case ILibTransport_DoneState_INCOMPLETE:
|
|
g_pause = 1;
|
|
ILibRemoteLogging_printf(ILibChainGetLogger(gILibChain), ILibRemoteLogging_Modules_Agent_KVM, ILibRemoteLogging_Flags_VerbosityLevel_2, "Agent KVM: KVM PAUSE");
|
|
break;
|
|
case ILibTransport_DoneState_ERROR:
|
|
g_shutdown = 1;
|
|
height = SCALED_HEIGHT;
|
|
width = SCALED_WIDTH;
|
|
break;
|
|
}
|
|
free(buf);
|
|
}
|
|
}
|
|
}
|
|
|
|
KVMDEBUG("kvm_server_mainloop / loop2", (int)GetCurrentThreadId());
|
|
|
|
if (desktop) free(desktop);
|
|
desktop = NULL;
|
|
desktopsize = 0;
|
|
}
|
|
|
|
KVMDEBUG("kvm_server_mainloop / loop3", (int)GetCurrentThreadId());
|
|
|
|
// We can't go full speed here, we need to slow this down.
|
|
height = FRAME_RATE_TIMER;
|
|
while (!g_shutdown && height > 0) { if (height > 50) { height -= 50; Sleep(50); } else { Sleep(height); height = 0; } }
|
|
}
|
|
|
|
KVMDEBUG("kvm_server_mainloop / end3", (int)GetCurrentThreadId());
|
|
|
|
KVMDEBUG("kvm_server_mainloop / end2", (int)GetCurrentThreadId());
|
|
|
|
// if (kvmthread != NULL) { CloseHandle(kvmthread); kvmthread = NULL; }
|
|
if (tileInfo != NULL) {
|
|
for (row = 0; row < TILE_HEIGHT_COUNT; row++) free(tileInfo[row]);
|
|
free(tileInfo);
|
|
tileInfo = NULL;
|
|
}
|
|
KVMDEBUG("kvm_server_mainloop / end1", (int)GetCurrentThreadId());
|
|
teardown_gdiplus();
|
|
|
|
KVMDEBUG("kvm_server_mainloop / end", (int)GetCurrentThreadId());
|
|
|
|
ILibRemoteLogging_printf(gKVMRemoteLogging, ILibRemoteLogging_Modules_Agent_KVM, ILibRemoteLogging_Flags_VerbosityLevel_1, "KVM [SLAVE]: Process Exiting...");
|
|
|
|
ThreadRunning = 0;
|
|
free(parm);
|
|
return 0;
|
|
}
|
|
|
|
#ifdef _WINSERVICE
|
|
void kvm_relay_ExitHandler(ILibProcessPipe_Process sender, int exitCode, void* user)
|
|
{
|
|
ILibKVM_WriteHandler writeHandler = (ILibKVM_WriteHandler)((void**)user)[0];
|
|
void *reserved = ((void**)user)[1];
|
|
void *pipeMgr = ((void**)user)[2];
|
|
char *exePath = (char*)((void**)user)[3];
|
|
|
|
ILibRemoteLogging_printf(ILibChainGetLogger(gILibChain), ILibRemoteLogging_Modules_Agent_KVM, ILibRemoteLogging_Flags_VerbosityLevel_1, "Agent KVM: KVM Child Process(%d) [EXITED]", g_slavekvm);
|
|
UNREFERENCED_PARAMETER(exitCode);
|
|
UNREFERENCED_PARAMETER(sender);
|
|
|
|
if (g_restartcount < 4)
|
|
{
|
|
kvm_relay_restart(1, pipeMgr, exePath, writeHandler, reserved);
|
|
}
|
|
else
|
|
{
|
|
ILibRemoteLogging_printf(ILibChainGetLogger(gILibChain), ILibRemoteLogging_Modules_Agent_KVM, ILibRemoteLogging_Flags_VerbosityLevel_1, "Agent KVM: g_restartcount = %d, aborting", g_restartcount);
|
|
writeHandler(NULL, 0, reserved);
|
|
}
|
|
|
|
//if (g_shutdown == 3 && g_restartcount < 4)
|
|
//{
|
|
// g_restartcount++;
|
|
// while (--r > 0 && g_shutdown == 3) { Sleep(50); }
|
|
// if (g_shutdown != 3 || kvm_relay_restart(1) == 0) GuardPost_ILibKVMDisconnect();
|
|
//}
|
|
//else
|
|
//{
|
|
// if (g_shutdown == 2) GuardPost_ILibKVMDisconnect();
|
|
//}
|
|
}
|
|
|
|
void kvm_relay_StdOutHandler(ILibProcessPipe_Process sender, char *buffer, int bufferLen, int* bytesConsumed, void* user)
|
|
{
|
|
int ptr = 0;
|
|
unsigned short size = 0;
|
|
unsigned short cmd = 0;
|
|
UNREFERENCED_PARAMETER(sender);
|
|
ILibKVM_WriteHandler writeHandler = (ILibKVM_WriteHandler)((void**)user)[0];
|
|
void *reserved = ((void**)user)[1];
|
|
|
|
while (bufferLen - ptr > 4)
|
|
{
|
|
//type = ntohs(((unsigned short*)(pchRequest + ptr))[0]);
|
|
size = ntohs(((unsigned short*)(buffer + ptr))[1]);
|
|
cmd = ntohs(((unsigned short*)(buffer + ptr))[0]);
|
|
if ((ptr + size > bufferLen) || size == 0) break;
|
|
ptr += size;
|
|
}
|
|
|
|
if (ptr > 0)
|
|
{
|
|
//ILibRemoteLogging_printf(ILibChainGetLogger(gILibChain), ILibRemoteLogging_Modules_Agent_KVM, ILibRemoteLogging_Flags_VerbosityLevel_2, "KVM Data: CMD: %d, Size = %d", cmd, size);
|
|
writeHandler(buffer, ptr, reserved); // stream object will take care of flow control
|
|
*bytesConsumed = ptr;
|
|
}
|
|
else
|
|
{
|
|
*bytesConsumed = 0;
|
|
}
|
|
}
|
|
void kvm_relay_StdErrHandler(ILibProcessPipe_Process sender, char *buffer, int bufferLen, int* bytesConsumed, void* user)
|
|
{
|
|
KVMDebugLog *log = (KVMDebugLog*)buffer;
|
|
|
|
UNREFERENCED_PARAMETER(sender);
|
|
UNREFERENCED_PARAMETER(user);
|
|
|
|
if (bufferLen < sizeof(KVMDebugLog) || bufferLen < log->length) { *bytesConsumed = 0; return; }
|
|
*bytesConsumed = log->length;
|
|
//ILibRemoteLogging_printf(ILibChainGetLogger(gILibChain), (ILibRemoteLogging_Modules)log->logType, (ILibRemoteLogging_Flags)log->logFlags, "%s", log->logData);
|
|
ILibRemoteLogging_printf(ILibChainGetLogger(gILibChain), ILibRemoteLogging_Modules_Microstack_Generic, (ILibRemoteLogging_Flags)log->logFlags, "%s", log->logData);
|
|
|
|
}
|
|
|
|
int kvm_relay_restart(int paused, void *pipeMgr, char *exePath, ILibKVM_WriteHandler writeHandler, void *reserved)
|
|
{
|
|
char * parms0[] = { " -kvm0", NULL };
|
|
char * parms1[] = { " -kvm1", NULL };
|
|
void **user = (void**)ILibMemory_Allocate(4 * sizeof(void*), 0, NULL, NULL);
|
|
user[0] = writeHandler;
|
|
user[1] = reserved;
|
|
user[2] = pipeMgr;
|
|
user[3] = exePath;
|
|
|
|
KVMDEBUG("kvm_relay_restart / start", paused);
|
|
|
|
// If we are re-launching the child process, wait a bit. The computer may be switching desktop, etc.
|
|
if (paused == 0) Sleep(500);
|
|
|
|
ILibRemoteLogging_printf(ILibChainGetLogger(gILibChain), ILibRemoteLogging_Modules_Agent_KVM, ILibRemoteLogging_Flags_VerbosityLevel_1, "KVM [Master]: Spawning Slave as %s", gProcessSpawnType == ILibProcessPipe_SpawnTypes_USER ? "USER":"WIN_LOGON");
|
|
gChildProcess = ILibProcessPipe_Manager_SpawnProcessEx(pipeMgr, exePath, paused == 0 ? parms0 : parms1, gProcessSpawnType);
|
|
gProcessSpawnType = gProcessSpawnType == ILibProcessPipe_SpawnTypes_USER ? ILibProcessPipe_SpawnTypes_WINLOGON : ILibProcessPipe_SpawnTypes_USER;
|
|
|
|
g_slavekvm = ILibProcessPipe_Process_GetPID(gChildProcess);
|
|
ILibProcessPipe_Process_AddHandlers(gChildProcess, 65535, &kvm_relay_ExitHandler, &kvm_relay_StdOutHandler, &kvm_relay_StdErrHandler, NULL, user);
|
|
|
|
KVMDEBUG("kvm_relay_restart() launched child process", g_slavekvm);
|
|
|
|
// Run the relay
|
|
g_shutdown = 0;
|
|
KVMDEBUG("kvm_relay_restart / end", (int)kvmthread);
|
|
|
|
return 1;
|
|
}
|
|
#endif
|
|
|
|
// Setup the KVM session. Return 1 if ok, 0 if it could not be setup.
|
|
int kvm_relay_setup(char *exePath, void *processPipeMgr, ILibKVM_WriteHandler writeHandler, void *reserved)
|
|
{
|
|
#ifdef _WINSERVICE
|
|
// if (kvmthread != NULL || g_slavekvm != 0) { KVMDEBUG("kvm_relay_setup() session already exists", 0); return 0; }
|
|
if (ThreadRunning == 1 && g_shutdown == 0) { KVMDEBUG("kvm_relay_setup() session already exists", 0); return 0; }
|
|
g_restartcount = 0;
|
|
gProcessSpawnType = ILibProcessPipe_SpawnTypes_USER;
|
|
KVMDEBUG("kvm_relay_setup() session starting", 0);
|
|
return kvm_relay_restart(1, processPipeMgr, exePath, writeHandler, reserved);
|
|
#else
|
|
// if (kvmthread != NULL && g_shutdown == 0) return 0;
|
|
void **parms = (void**)ILibMemory_Allocate((2 * sizeof(void*)) + sizeof(int), 0, NULL, NULL);
|
|
parms[0] = writeHandler;
|
|
parms[1] = reserved;
|
|
((int*)(&parms[2]))[0] = 1;
|
|
|
|
if (ThreadRunning == 1 && g_shutdown == 0) { KVMDEBUG("kvm_relay_setup() session already exists", 0); free(parms); return 0; }
|
|
kvmthread = CreateThread(NULL, 0, kvm_server_mainloop, (void*)parms, 0, 0);
|
|
return 1;
|
|
#endif
|
|
}
|
|
|
|
// Force a KVM reset & refresh
|
|
void kvm_relay_reset(ILibKVM_WriteHandler writeHandler, void *reserved)
|
|
{
|
|
char buffer[4];
|
|
KVMDEBUG("kvm_relay_reset", 0);
|
|
((unsigned short*)buffer)[0] = (unsigned short)htons((unsigned short)MNG_KVM_REFRESH); // Write the type
|
|
((unsigned short*)buffer)[1] = (unsigned short)htons((unsigned short)4); // Write the size
|
|
kvm_relay_feeddata(buffer, 4, writeHandler, reserved);
|
|
}
|
|
|
|
// Clean up the KVM session.
|
|
void kvm_cleanup()
|
|
{
|
|
//ILIBMESSAGE("KVMBREAK-CLEAN\r\n");
|
|
KVMDEBUG("kvm_cleanup", 0);
|
|
g_shutdown = 1;
|
|
if (gChildProcess != NULL)
|
|
{
|
|
ILibRemoteLogging_printf(ILibChainGetLogger(gILibChain), ILibRemoteLogging_Modules_Agent_KVM, ILibRemoteLogging_Flags_VerbosityLevel_1, "KVM.c/kvm_cleanup: Attempting to kill child process");
|
|
free(ILibProcessPipe_Process_KillEx(gChildProcess));
|
|
gChildProcess = NULL;
|
|
}
|
|
else
|
|
{
|
|
ILibRemoteLogging_printf(ILibChainGetLogger(gILibChain), ILibRemoteLogging_Modules_Agent_KVM, ILibRemoteLogging_Flags_VerbosityLevel_1, "KVM.c/kvm_cleanup: gChildProcess = NULL");
|
|
}
|
|
}
|
|
|
|
#endif
|