1
0
mirror of https://github.com/Ylianst/MeshAgent synced 2026-01-06 10:34:09 +00:00
Files
MeshAgent/meshcore/KVM/Windows/kvm.c

2466 lines
67 KiB
C

/*
Copyright 2006 - 2018 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)
#pragma warning(disable: 4996)
#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"
#include <sas.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;
int gProcessTSID = -1;
extern int gRemoteMouseRenderDefault;
int gRemoteMouseMoved = 0;
extern int gCurrentCursor;
#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;
int kvmConsoleMode = 0;
ILibQueue gPendingPackets = NULL;
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)
{
UNREFERENCED_PARAMETER( Param );
KVMDEBUG("kvm_ctrlaltdel", (int)Param);
typedef VOID(WINAPI *SendSas)(BOOL asUser);
SendSas sas;
// Perform new method (Vista & Win7)
HMODULE m = LoadLibraryExA("sas.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32);
// We need to dynamically load this, becuase it doesn't exist on Windows Core.
// However, LOAD_LIBRARY_SEARCH_SYSTEM32 does not exist on Windows 7 SP1 / Windows Server 2008 R2 without a MSFT Patch,
// but this patch is no longer available from MSFT, so this fallback case will only affect insecure versions of Windows 7 SP1 / Server 2008 R2
if (m == NULL && GetLastError() == ERROR_INVALID_PARAMETER) { m = LoadLibraryA("sas.dll"); }
if (m != NULL)
{
sas = (SendSas)GetProcAddress(m, "SendSAS");
if (sas != NULL)
{
kvm_setupSasPermissions();
sas(FALSE);
}
FreeLibrary(m);
}
return 0;
}
BOOL CALLBACK DisplayInfoEnumProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData)
{
int w, h, deviceid = 0;
MONITORINFOEX mi;
DWORD *selection = (DWORD*)dwData;
UNREFERENCED_PARAMETER( hdcMonitor );
UNREFERENCED_PARAMETER( lprcMonitor );
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 (--selection[0] > 0) { 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;
char *buffer = ILibMemory_AllocateA((5 + SCREEN_COUNT) * 2);
memset(buffer, 0xFF, ILibMemory_AllocateA_Size(buffer));
// Send the list of possible displays to remote
if (SCREEN_COUNT == 0 || SCREEN_COUNT == 1)
{
// Only one display, send empty
((unsigned short*)buffer)[0] = (unsigned short)htons((unsigned short)MNG_KVM_GET_DISPLAYS); // 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)(0)); // Screen Count
((unsigned short*)buffer)[3] = (unsigned short)htons((unsigned short)(0)); // Selected Screen
writeHandler(buffer, 8, reserved);
}
else
{
// Many displays
((unsigned short*)buffer)[0] = (unsigned short)htons((unsigned short)MNG_KVM_GET_DISPLAYS); // Write the type
((unsigned short*)buffer)[1] = (unsigned short)htons((unsigned short)(10 + (2 * SCREEN_COUNT))); // Write the size
((unsigned short*)buffer)[2] = (unsigned short)htons((unsigned short)(SCREEN_COUNT + 1)); // Screen Count
((unsigned short*)buffer)[3] = (unsigned short)htons((unsigned short)(-1)); // Possible Screen (ALL)
for (i = 0; i < SCREEN_COUNT; i++) {
((unsigned short*)buffer)[4 + i] = (unsigned short)htons((unsigned short)(i + 1)); // Possible Screen
}
if (SCREEN_SEL == 0) {
((unsigned short*)buffer)[4 + i] = (unsigned short)htons((unsigned short)(-1)); // Selected Screen (All)
} else {
((unsigned short*)buffer)[4 + i] = (unsigned short)htons((unsigned short)(SCREEN_SEL)); // Selected Screen
}
writeHandler(buffer, (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)
{
//printf("RESOLUTION CHANGED! (supposedly)\n");
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)
{
DWORD selection = SCREEN_SEL_TARGET;
if (EnumDisplayMonitors(NULL, NULL, DisplayInfoEnumProc, (LPARAM)&selection))
{
// 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);
*/
}
char *kvm_getKeyboardLayoutCode(char *layout, size_t layoutLength)
{
char *val = layout;
char *ret = NULL;
if (layoutLength < 16) { return(NULL); }
switch (((int64_t*)val)[0])
{
case 280568361569: // ar-SA
ret = "00000401";
break;
case 306052949858: // bg-BG
ret = "00000402";
break;
case 357642887523: // ca-ES
ret = "00000403";
break;
case 375074416762: // zh-TW
ret = "00000404";
break;
case 387674108771: // cs-CZ
ret = "00000405";
break;
case 323266371940: // da-DK
ret = "00000406";
break;
case 297496569188: // de-DE
ret = "00000407";
break;
case 353381477477: // el-GR
ret = "00000408";
break;
case 357911326309: // en-US
ret = "00000409";
break;
case 314709993830: // fi-FI
ret = "0000040B";
break;
case 353364701798: // fr-FR
ret = "0000040C";
break;
case 327645226344: // he-IL
ret = "0000040D";
break;
case 366283158888: // hu-HU
ret = "0000040E";
break;
case 357710001001: // is-IS
ret = "0000040F";
break;
case 362004968553: // it-IT
ret = "00000410";
break;
case 344841871722: // ja-JP
ret = "00000411";
break;
case 353448587115: // ko-KR
ret = "00000412";
break;
case 327729114222: // nl-NL
ret = "00000413";
break;
case 340614013550: // nb-NO
ret = "00000414";
break;
case 327762668656: // pl-PL
ret = "00000415";
break;
case 353297593456: // pt-BR
ret = "00000416";
break;
case 310364695922: // rm-CH
ret = "00000417";
break;
case 340681125746: // ro-RO
ret = "00000418";
break;
case 366450931058: // ru-RU
ret = "00000419";
break;
case 353398256232: // hr-HR
ret = "0000041A";
break;
case 323518032755: // sk-SK
ret = "0000041B";
break;
case 327511011699: // sq-AL
ret = "0000041C";
break;
case 297748231795: // sv-SE
ret = "0000041D";
break;
case 310649907316: // th-TH
ret = "0000041E";
break;
case 353599582836: // tr-TR
ret = "0000041F";
break;
case 323467702901: // ur-PK
ret = "00000420";
break;
case 293285487721: // id-ID
ret = "00000421";
break;
case 280601914229: // uk-UA
ret = "00000422";
break;
case 383362360674: // be-BY
ret = "00000423";
break;
case 314928098419: // sl-SI
ret = "00000424";
break;
case 297513350245: // et-EE
ret = "00000425";
break;
case 370645235308: // lv-LV
ret = "00000426";
break;
case 362055300204: // lt-LT
ret = "00000427";
break;
case 353415029094: // fa-IR
ret = "00000429";
break;
case 336453265782: // vi-VN
ret = "0000042A";
break;
case 331805981032: // hy-AM
ret = "0000042B";
break;
case 357642892645: // eu-ES
ret = "0000042D";
break;
case 76159121519464: // hsb-DE
ret = "0000042E";
break;
case 323417369453: // mk-MK
ret = "0000042F";
break;
case 280685802611: // st-ZA
ret = "00000430";
break;
case 280685802356: // ts-ZA
ret = "00000431";
break;
case 280685801076: // tn-ZA
ret = "00000432";
break;
case 280685798774: // ve-ZA
ret = "00000433";
break;
case 280685799544: // xh-ZA
ret = "00000434";
break;
case 280685802874: // zu-ZA
ret = "00000435";
break;
case 280685799009: // af-ZA
ret = "00000436";
break;
case 297546899819: // ka-GE
ret = "00000437";
break;
case 340479799142: // fo-FO
ret = "00000438";
break;
case 336235161960: // hi-IN
ret = "00000439";
break;
case 362072077421: // mt-MT
ret = "0000043A";
break;
case 340614014323: // se-NO
ret = "0000043B";
break;
case 32196334487169401: // yi-Hebr
ret = "0000043D";
break;
case 383546913645: // ms-MY
ret = "0000043E";
break;
case 387808324459: // kk-KZ
ret = "0000043F";
break;
case 306203949419: // ky-KG
ret = "00000440";
break;
case 297614014323: // sw-KE
ret = "00000441";
break;
case 332124744564: // tk-TM
ret = "00000442";
break;
case 366450930804: // tt-RU
ret = "00000444";
break;
case 336235163234: // bn-IN
ret = "00000445";
break;
case 336235159920: // pa-IN
ret = "00000446";
break;
case 336235165031: // gu-IN
ret = "00000447";
break;
case 336235164271: // or-IN
ret = "00000448";
break;
case 336235159924: // ta-IN
ret = "00000449";
break;
case 336235160948: // te-IN
ret = "0000044A";
break;
case 336235163243: // kn-IN
ret = "0000044B";
break;
case 336235162733: // ml-IN
ret = "0000044C";
break;
case 336235164513: // as-IN
ret = "0000044D";
break;
case 336235164269: // mr-IN
ret = "0000044E";
break;
case 336235159923: // sa-IN
ret = "0000044F";
break;
case 336302272109: // mn-MN
ret = "00000450";
break;
case 336134500194: // bo-CN
ret = "00000451";
break;
case 284662004067: // cy-GB
ret = "00000452";
break;
case 310498913643: // km-KH
ret = "00000453";
break;
case 280450920300: // lo-LA
ret = "00000454";
break;
case 332007307629: // my-MM
ret = "00000455";
break;
case 357642890343: // gl-ES
ret = "00000456";
break;
case 86076201594731: // kok-IN
ret = "00000457";
break;
case 86076201463405: // mni-IN
ret = "00000458";
break;
case 98213779634547: // syr-SY
ret = "0000045A";
break;
case 323400591731: // si-LK
ret = "0000045B";
break;
case 361937857889: // am-ET
ret = "0000045E";
break;
case 27691691065308011: // ks-Arab
ret = "00000460";
break;
case 344908981614: // ne-NP
ret = "00000461";
break;
case 327729117542: // fy-NL
ret = "00000462";
break;
case 301741208432: // ps-AF
ret = "00000463";
break;
case 79509196663142: // fil-PH
ret = "00000464";
break;
case 370662012516: // dv-MV
ret = "00000465";
break;
case 78401095231842: // bin-NG
ret = "00000466";
break;
case 78401095759206: // fuv-NG
ret = "00000467";
break;
case 78401094443625: // ibb-NG
ret = "00000469";
break;
case 306254278521: // yo-NG
ret = "0000046A";
break;
case 87145649436017: // quz-BO
ret = "0000046B";
break;
case 71855565140846: // nso-ZA
ret = "0000046C";
break;
case 366450925922: // ba-RU
ret = "0000046D";
break;
case 366350262892: // lb-LU
ret = "0000046E";
break;
case 327611673707: // kl-GL
ret = "0000046F";
break;
case 306254276457: // ig-NG
ret = "00000470";
break;
case 306254279275: // kr-NG
ret = "00000471";
break;
case 361937857903: // om-ET
ret = "00000472";
break;
case 361937856884: // ti-ET
ret = "00000473";
break;
case 383597244007: // gn-PY
ret = "00000474";
break;
case 91625300124008: // haw-US
ret = "00000475";
break;
case 31090208676864364: // la-Latn
ret = "00000476";
break;
case 340697902963: // so-SO
ret = "00000477";
break;
case 336134498665: // ii-CN
ret = "00000478";
break;
case 16099256174666096: // pap-029
ret = "00000479";
break;
case 83851408732769: // arn-CL
ret = "0000047A";
break;
case 71756780433261: // moh-CA
ret = "0000047C";
break;
case 353364701794: // br-FR
ret = "0000047E";
break;
case 336134498165: // ug-CN
ret = "00000480";
break;
case 387858655597: // mi-NZ
ret = "00000481";
break;
case 353364697967: // oc-FR
ret = "00000482";
break;
case 353364701027: // co-FR
ret = "00000483";
break;
case 90461363991399: // gsw-FR
ret = "00000484";
break;
case 93811437494643: // sah-RU
ret = "00000485";
break;
case 92664682018161: // qut-GT
ret = "00000486";
break;
case 375040866162: // rw-RW
ret = "00000487";
break;
case 336402935671: // wo-SN
ret = "00000488";
break;
case 77245749359216: // prs-AF
ret = "0000048C";
break;
case 78396800658544: // plt-MG
ret = "0000048D";
break;
case 284661998695: // gd-GB
ret = "00000491";
break;
case 87149942895985: // quc-CO
ret = "00000493";
break;
case 349120066145: // ar-IQ
ret = "00000801";
break;
case 336134498426: // zh-CN
ret = "00000804";
break;
case 310364693860: // de-CH
ret = "00000807";
break;
case 284662001253: // en-GB
ret = "00000809";
break;
case 379251946341: // es-MX
ret = "0000080A";
break;
case 297463018086: // fr-BE
ret = "0000080C";
break;
case 310364697705: // it-CH
ret = "00000810";
break;
case 297463016558: // nl-BE
ret = "00000813";
break;
case 340614016622: // nn-NO
ret = "00000814";
break;
case 362122409072: // pt-PT
ret = "00000816";
break;
case 293352599410: // ro-MD
ret = "00000818";
break;
case 293352600946: // ru-MD
ret = "00000819";
break;
case 314709997171: // sv-FI
ret = "0000081D";
break;
case 336235164277: // ur-IN
ret = "00000820";
break;
case 76159121519460: // dsb-DE
ret = "0000082E";
break;
case 374772428404: // tn-BW
ret = "00000832";
break;
case 297748227443: // se-SE
ret = "0000083B";
break;
case 297580454247: // ga-IE
ret = "0000083C";
break;
case 336117724013: // ms-BN
ret = "0000083E";
break;
case 293168049762: // bn-BD
ret = "00000845";
break;
case 323400589684: // ta-LK
ret = "00000849";
break;
case 361887526754: // bo-BT
ret = "00000851";
break;
case 27433250048537451: // ks-Deva
ret = "00000860";
break;
case 336235160942: // ne-IN
ret = "00000861";
break;
case 73964394804593: // quz-EC
ret = "0000086B";
break;
case 353347922292: // ti-ER
ret = "00000873";
break;
case 306103284321: // ar-EG
ret = "00000C01";
break;
case 323333482618: // zh-HK
ret = "00000C04";
break;
case 361870746980: // de-AT
ret = "00000C07";
break;
case 366165716581: // en-AU
ret = "00000C09";
break;
case 357642892133: // es-ES
ret = "00000C0A";
break;
case 280299926118: // fr-CA
ret = "00000C0C";
break;
case 314709992819: // se-FI
ret = "00000C3B";
break;
case 361887529572: // dz-BT
ret = "00000C51";
break;
case 71799731285364: // tmz-MA
ret = "00000C5F";
break;
case 76210662700401: // quz-PE
ret = "00000C6b";
break;
case 383530136161: // ar-LY
ret = "00001001";
break;
case 306338162810: // zh-SG
ret = "00001004";
break;
case 366350263652: // de-LU
ret = "00001007";
break;
case 280299925093: // en-CA
ret = "00001009";
break;
case 361971413861: // es-GT
ret = "0000100A";
break;
case 310364697190: // fr-CH
ret = "0000100C";
break;
case 280283148904: // hr-BA
ret = "0000101A";
break;
case 87197187992947: // smj-NO
ret = "0000103B";
break;
case 387690885729: // ar-DZ
ret = "00001401";
break;
case 340597237882: // zh-MO
ret = "00001404";
break;
case 314810656100: // de-LI
ret = "00001407";
break;
case 387858656869: // en-NZ
ret = "00001409";
break;
case 353314370405: // es-CR
ret = "0000140A";
break;
case 366350266982: // fr-LU
ret = "0000140C";
break;
case 76223546551667: // smj-SE
ret = "0000143B";
break;
case 280467698273: // ar-MA
ret = "00001801";
break;
case 297580457573: // en-IE
ret = "00001809";
break;
case 280518030181: // es-PA
ret = "0000180A";
break;
case 289057632870: // fr-MC
ret = "0000180C";
break;
case 87197187403123: // sma-NO
ret = "0000183B";
break;
case 336419713633: // ar-TN
ret = "00001C01";
break;
case 280685801061: // en-ZA
ret = "00001C09";
break;
case 340446245733: // es-DO
ret = "00001C0A";
break;
case 76223545961843: // sma-SE
ret = "00001C3B";
break;
case 332040860257: // ar-OM
ret = "00002001";
break;
case 331956973157: // en-JM
ret = "00002009";
break;
case 297798562661: // es-VE
ret = "0000200A";
break;
case 297731453542: // fr-RE
ret = "0000200C";
break;
case 80565759077747: // sms-FI
ret = "0000203B";
break;
case 297848894049: // ar-YE
ret = "00002401";
break;
case 62887719431781: // en-029
ret = "00002409";
break;
case 340429468517: // es-CO
ret = "0000240A";
break;
case 293184828006: // fr-CD
ret = "0000240C";
break;
case 80565758750067: // smn-FI
ret = "0000243B";
break;
case 383647576673: // ar-SY
ret = "00002801";
break;
case 387657330277: // en-BZ
ret = "00002809";
break;
case 297697899365: // es-PE
ret = "0000280A";
break;
case 336402936422: // fr-SN
ret = "0000280C";
break;
case 340546908769: // ar-JO
ret = "00002C01";
break;
case 362189516389: // en-TT
ret = "00002C09";
break;
case 353280815973: // es-AR
ret = "00002C0A";
break;
case 331839533670: // fr-CM
ret = "00002C0C";
break;
case 284745888353: // ar-LB
ret = "00003001";
break;
case 375175081573: // en-ZW
ret = "00003009";
break;
case 288923415397: // es-EC
ret = "0000300A";
break;
case 314659664486: // fr-CI
ret = "0000300C";
break;
case 374923424353: // ar-KW
ret = "00003401";
break;
case 310582799973: // en-PH
ret = "00003409";
break;
case 327544566629: // es-CL
ret = "0000340A";
break;
case 327712338534: // fr-ML
ret = "0000340C";
break;
case 297446240865: // ar-AE
ret = "00003801";
break;
case 293285490277: // en-ID
ret = "00003809";
break;
case 383681131365: // es-UY
ret = "0000380A";
break;
case 280467698278: // fr-MA
ret = "0000380C";
break;
case 310347919969: // ar-BH
ret = "00003c01";
break;
case 323333484133: // en-HK
ret = "00003c09";
break;
case 383597245285: // es-PY
ret = "00003c0A";
break;
case 361988190822: // fr-HT
ret = "00003c0C";
break;
case 280534807137: // ar-QA
ret = "00004001";
break;
case 336235163237: // en-IN
ret = "00004009";
break;
case 340412691301: // es-BO
ret = "0000400A";
break;
case 383546912357: // en-MY
ret = "00004409";
break;
case 370762675045: // es-SV
ret = "0000440A";
break;
case 58498279633505: // ar-145
ret = "00004801";
break;
case 306338164325: // en-SG
ret = "00004809";
break;
case 336218387301: // es-HN
ret = "0000480A";
break;
case 297446239845: // en-AE
ret = "00004C09";
break;
case 314844214117: // es-NI
ret = "00004C0A";
break;
case 310347918949: // en-BH
ret = "00005009";
break;
case 353532474213: // es-PR
ret = "0000500A";
break;
case 306103283301: // en-EG
ret = "00005409";
break;
case 357911327589: // es-US
ret = "0000540A";
break;
case 340546907749: // en-JO
ret = "00005809";
break;
case 62883491574629: // es-419
ret = "0000580A";
break;
case 374923423333: // en-KW
ret = "00005C09";
break;
case 366199272293: // es-CU
ret = "00005C0A";
break;
case 353599581797: // en-TR
ret = "00006009";
break;
case 297848893029: // en-YE
ret = "00006409";
break;
case 30525162628412258: // bs-Cyrl
ret = "0000641A";
break;
case 31090208676868962: // bs-Latn
ret = "0000681A";
break;
case 30525162628412019: // sr-Cyrl
ret = "00006C1A";
break;
case 31090208676868723: // sr-Latn
ret = "0000701A";
break;
case 7236979: // smn
ret = "0000703B";
break;
case 30525162628414049: // az-Cyrl
ret = "0000742C";
break;
case 7564659: // sms
ret = "0000743B";
break;
case 26746: // zh
ret = "00007804";
break;
case 28270: // nn
ret = "00007814";
break;
case 29538: // bs
ret = "0000781A";
break;
case 31090208676870753: // az-Latn
ret = "0000782C";
break;
case 6385011: // sma
ret = "0000783B";
break;
case 30525162628414069: // uz-Cyrl
ret = "00007843";
break;
case 30525162628410989: // mn-Cyrl
ret = "00007850";
break;
case 32490986339661161: // iu-Cans
ret = "0000785D";
break;
case 32772461400254586: // zh-Hant
ret = "00007C04";
break;
case 25198: // nb
ret = "00007C14";
break;
case 29299: // sr
ret = "00007C1A";
break;
case 30525162628409204: // tg-Cyrl
ret = "00007C28";
break;
case 6452068: // dsb
ret = "00007C2E";
break;
case 6974835: // smj
ret = "00007C3B";
break;
case 31090208676870773: // uz-Latn
ret = "00007C43";
break;
case 27691691065303408: // pa-Arab
ret = "00007C46";
break;
case 29113346916445805: // mn-Mong
ret = "00007C50";
break;
case 27691691065304179: // sd-Arab
ret = "00007C59";
break;
case 31090208676869481: // iu-Latn
ret = "00007C5D";
break;
case 31090208676865638: // ff-Latn
ret = "00007C67";
break;
case 31090208676864360: // ha-Latn
ret = "00007C68";
break;
case 8247321628869751653: // es-ES_tradnl
ret = "0000040A";
break;
case 3273116894335166324: // tg-Cyrl-TJ
ret = "00000428";
break;
case 3273681940383627873: // az-Latn-AZ
ret = "0000042C";
break;
case 3273681940383627893: // uz-Latn-UZ
ret = "00000443";
break;
case 3270024981755290739: // sd-Deva-IN
ret = "00000459";
break;
case 8243109330706131043:
switch (((int64_t*)val)[1])
{
case 0: // chr-Cher
ret = "00007C5C";
break;
case 5461293: // chr-Cher-US
ret = "0000045C";
break;
}
break;
case 3275082718046418281: // iu-Cans-CA
ret = "0000045D";
break;
case 7089072912718461556: // tzm-Arab-MA
ret = "0000045F";
break;
case 3273681940383621480: // ha-Latn-NG
ret = "00000468";
break;
case 5200924699901388922: // zh-yue-HK
ret = "0000048E";
break;
case 7308323309482173556: // tdd-Tale-CN
ret = "0000048F";
break;
case 8461244814088890475: // khb-Talu-CN
ret = "00000490";
break;
case 3270283422772065643: // ku-Arab-IQ
ret = "00000492";
break;
case 7165064761224425585:
switch (((int64_t*)val)[1])
{
case 109: // qps-plocm
ret = "000009FF";
break;
case 97: // qps-ploca
ret = "000005FE";
break;
case 0: // qps-ploc
ret = "00000501";
break;
}
break;
case 7022850504597004643: // ca-ES-valencia
ret = "00000803";
break;
case 3270580265393414506: // ja-Ploc-JP
ret = "00000811";
break;
case 3273681940383625843:
switch (((int64_t*)val)[1])
{
case 17741: // sr-Latn-ME
ret = "00002C1A";
break;
case 21330: // sr-Latn-RS
ret = "0000241A";
break;
case 16706: // sr-Latn-BA
ret = "0000181A";
break;
case 21315: // sr-Latn-CS
ret = "0000081A";
break;
}
break;
case 3273116894335171169: // az-Cyrl-AZ
ret = "0000082C";
break;
case 3273116894335171189: // uz-Cyrl-UZ
ret = "00000843";
break;
case 3270283422772060528: // pa-Arab-PK
ret = "00000846";
break;
case 3271705078623202925:
switch (((int64_t*)val)[1])
{
case 20045: // mn-Mong-MN
ret = "00000C50";
break;
case 20035: // mn-Mong-CN
ret = "00000850";
break;
}
break;
case 3270283422772061299: // sd-Arab-PK
ret = "00000859";
break;
case 3273681940383626601: // iu-Latn-CA
ret = "0000085D";
break;
case 7959093421278067316:
switch (((int64_t*)val)[1])
{
case 0: // tzm-Latn
ret = "00007C5F";
break;
case 5915693: // tzm-Latn-DZ
ret = "0000085F";
break;
}
break;
case 3273681940383622758: // ff-Latn-SN
ret = "00000867";
break;
case 3273116894335169139:
switch (((int64_t*)val)[1])
{
case 17741: // sr-Cyrl-ME
ret = "0000301A";
break;
case 21330: // sr-Cyrl-RS
ret = "0000281A";
break;
case 16706: // sr-Cyrl-BA
ret = "00001C1A";
break;
case 21315: // sr-Cyrl-CS
ret = "00000C1A";
break;
}
break;
case 7453006945070185076:
switch (((int64_t*)val)[1])
{
case 0: // tzm-Tfng
ret = "0000785F";
break;
case 4279597: // tzm-Tfng-MA
ret = "0000105F";
break;
}
break;
case 3273681940383626082: // bs-Latn-BA
ret = "0000141A";
break;
case 3273116894335169378: // bs-Cyrl-BA
ret = "0000201A";
break;
case 3270580265393418849: // ar-Ploc-SA
ret = "00004401";
break;
}
return(ret);
}
// 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;
// Decode the block header
if (blocklen < 4) return 0;
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);
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_WITHLAYOUT:
if (size != 22) { break; }
char *klayout = kvm_getKeyboardLayoutCode(block + 6, 22);
if (klayout != NULL)
{
char current[KL_NAMELENGTH + 1];
if (GetKeyboardLayoutNameA(current) != 0 && strcmp(current, klayout) == 0)
{
// Current keyboard layour matches the intended layout
KeyAction(block[5], block[4]);
}
else
{
HKL kb = LoadKeyboardLayoutA(klayout, KLF_ACTIVATE | KLF_REORDER);
if (kb != NULL)
{
KeyActionEx(block[5], block[4], kb);
UnloadKeyboardLayout(kb);
}
}
}
break;
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;
KVM_MouseCursors curcursor = KVM_MouseCursor_NOCHANGE;
if (size == 10 || size == 12)
{
gRemoteMouseMoved = 1;
// 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)), (int)(unsigned char)(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;
}
typedef struct kvm_data_handler
{
ILibKVM_WriteHandler handler;
void *reserved;
int len;
char buffer[];
}kvm_data_handler;
//void __stdcall kvm_relay_feeddata_ex_APC(ULONG_PTR data)
//{
// kvm_data_handler *k = (kvm_data_handler*)data;
//
// k->handler(k->buffer, k->len, k->reserved);
// free((void*)data);
//}
//ILibTransport_DoneState kvm_relay_feeddata_ex(char *buf, int len, void *reserved)
//{
// kvm_data_handler *data = (kvm_data_handler*)ILibMemory_Allocate(sizeof(kvm_data_handler) + len, 0, NULL, NULL);
// data->handler = (ILibKVM_WriteHandler)((void**)reserved)[0];
// data->reserved = ((void**)reserved)[1];
// data->len = len;
// memcpy_s(data->buffer, len, buf, len);
//
// QueueUserAPC((PAPCFUNC)kvm_relay_feeddata_ex_APC, kvmthread, (ULONG_PTR)data);
//}
// 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)
{
if (gChildProcess != NULL)
{
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, kvm_relay_feeddata_ex, (void*[]) {writeHandler, reserved})) != 0) { ptr += len2; }
while ((len2 = kvm_server_inputdata(buf + ptr, len - ptr, writeHandler, reserved)) != 0) { ptr += len2; }
return ptr;
}
}
// 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_ex(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;
}
DWORD WINAPI kvm_mainloopinput(LPVOID Param)
{
DWORD ret = 0;
if (((int*)&(((void**)Param)[3]))[0] == 1)
{
ILib_DumpEnabledContext winException;
__try
{
ret = kvm_mainloopinput_ex(Param);
}
__except (ILib_WindowsExceptionFilterEx(GetExceptionCode(), GetExceptionInformation(), &winException))
{
ILib_WindowsExceptionDebugEx(&winException);
}
}
else
{
ret = kvm_mainloopinput_ex(Param);
}
return(ret);
}
#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_ex(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];
char *tmoBuffer;
long mouseMove[3] = { 0,0,0 };
int sentHideCursor = 0;
gPendingPackets = ILibQueue_Create();
KVM_InitMouseCursors(gPendingPackets);
#ifdef _WINSERVICE
if (!kvmConsoleMode)
{
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
if (!kvmConsoleMode)
{
hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
hStdIn = GetStdHandle(STD_INPUT_HANDLE);
}
#endif
KVMDEBUG("kvm_server_mainloop / start2", (int)GetCurrentThreadId());
if (!initialize_gdiplus())
{
#ifdef _WINSERVICE
if (!kvmConsoleMode)
{
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
if (!kvmConsoleMode)
{
ILibRemoteLogging_printf(gKVMRemoteLogging, ILibRemoteLogging_Modules_Agent_KVM, ILibRemoteLogging_Flags_VerbosityLevel_1, "KVM [SLAVE]: initialize_gdiplus() SUCCESS");
}
#endif
kvm_server_SetResolution(writeHandler, reserved);
#ifdef _WINSERVICE
if (!kvmConsoleMode)
{
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)
{
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;
#ifdef KVM_ALL_TILES
tileInfo[row][col].crc = 0xFF;
#endif
}
}
CheckDesktopSwitch(1, writeHandler, reserved);
if (g_shutdown) break;
// Enter Alertable State, so we can dispatch any packets if necessary.
// We are doing it here, in case we need to merge any data with the bitmaps
SleepEx(0, TRUE);
mouseMove[0] = 0;
while ((tmoBuffer = ILibQueue_DeQueue(gPendingPackets)) != NULL)
{
if (ntohs(((unsigned short*)tmoBuffer)[0]) == MNG_KVM_MOUSE_MOVE)
{
if (SCREEN_SEL_TARGET == 0)
{
mouseMove[0] = 1;
mouseMove[1] = ((long*)tmoBuffer)[1] - VSCREEN_X;
mouseMove[2] = ((long*)tmoBuffer)[2] - VSCREEN_Y;
}
else
{
if (((long*)tmoBuffer)[1] >= SCREEN_X && ((long*)tmoBuffer)[1] <= (SCREEN_X + SCREEN_WIDTH) &&
((long*)tmoBuffer)[2] >= SCREEN_Y && ((long*)tmoBuffer)[2] <= (SCREEN_Y + SCREEN_HEIGHT))
{
mouseMove[0] = 1;
mouseMove[1] = ((long*)tmoBuffer)[1] - SCREEN_X;
mouseMove[2] = ((long*)tmoBuffer)[2] - SCREEN_Y;
}
}
}
else
{
if (ntohs(((unsigned short*)tmoBuffer)[0]) != MNG_KVM_MOUSE_CURSOR || sentHideCursor==0)
{
writeHandler(tmoBuffer, (int)ILibMemory_Size(tmoBuffer), reserved);
}
}
ILibMemory_Free(tmoBuffer);
}
if (mouseMove[0] == 0 && (gRemoteMouseRenderDefault != 0 || gRemoteMouseMoved == 0))
{
mouseMove[0] = 1;
CURSORINFO info = { 0 };
info.cbSize = sizeof(info);
GetCursorInfo(&info);
if (SCREEN_SEL_TARGET == 0)
{
mouseMove[1] = info.ptScreenPos.x - VSCREEN_X;
mouseMove[2] = info.ptScreenPos.y - VSCREEN_Y;
}
else
{
mouseMove[1] = info.ptScreenPos.x - SCREEN_X;
mouseMove[2] = info.ptScreenPos.y - SCREEN_Y;
}
}
if (mouseMove[0] != 0)
{
if (sentHideCursor == 0)
{
sentHideCursor = 1;
char tmpBuffer[5];
((unsigned short*)tmpBuffer)[0] = (unsigned short)htons((unsigned short)MNG_KVM_MOUSE_CURSOR); // Write the type
((unsigned short*)tmpBuffer)[1] = (unsigned short)htons((unsigned short)5); // Write the size
tmpBuffer[4] = (char)KVM_MouseCursor_NONE; // Cursor Type
writeHandler(tmpBuffer, 5, reserved);
}
}
else
{
if (sentHideCursor != 0)
{
sentHideCursor = 0;
char tmpBuffer[5];
((unsigned short*)tmpBuffer)[0] = (unsigned short)htons((unsigned short)MNG_KVM_MOUSE_CURSOR); // Write the type
((unsigned short*)tmpBuffer)[1] = (unsigned short)htons((unsigned short)5); // Write the size
tmpBuffer[4] = (char)gCurrentCursor; // Cursor Type
writeHandler(tmpBuffer, 5, reserved);
}
}
// Scan the desktop
if (get_desktop_buffer(&desktop, &desktopsize, mouseMove) == 1 || desktop == NULL)
{
#ifdef _WINSERVICE
if (!kvmConsoleMode)
{
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; } SleepEx(0, TRUE); }
}
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());
KVM_UnInitMouseCursors();
while ((tmoBuffer = ILibQueue_DeQueue(gPendingPackets)) != NULL)
{
ILibMemory_Free(tmoBuffer);
}
ILibQueue_Destroy(gPendingPackets);
ILibRemoteLogging_printf(gKVMRemoteLogging, ILibRemoteLogging_Modules_Agent_KVM, ILibRemoteLogging_Flags_VerbosityLevel_1, "KVM [SLAVE]: Process Exiting...");
ThreadRunning = 0;
free(parm);
return 0;
}
DWORD WINAPI kvm_server_mainloop(LPVOID parm)
{
DWORD ret = 0;
if (((int*)&(((void**)parm)[3]))[0] == 1)
{
// Enable Core Dump in KVM Child
ILib_DumpEnabledContext winException;
WCHAR str[_MAX_PATH];
DWORD strLen;
if ((strLen = GetModuleFileNameW(NULL, str, _MAX_PATH)) > 5)
{
str[strLen - 4] = 0; // We're going to convert .exe to _kvm.dmp
g_ILibCrashDump_path = ILibMemory_Allocate((strLen * 2) + 10, 0, NULL, NULL); // Add enough space to add '.dmp' to the end of the path
swprintf_s((wchar_t*)g_ILibCrashDump_path, strLen + 5, L"%s_kvm.dmp", str);
ILibCriticalLogFilename = "KVMSlave.log";
}
__try
{
ret = kvm_server_mainloop_ex(parm);
}
__except (ILib_WindowsExceptionFilterEx(GetExceptionCode(), GetExceptionInformation(), &winException))
{
ILib_WindowsExceptionDebugEx(&winException);
}
}
else
{
// Core Dump not enabled in KVM Child
ret = kvm_server_mainloop_ex(parm);
}
return(ret);
}
#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 && g_shutdown == 0)
{
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);
}
}
void kvm_relay_StdOutHandler(ILibProcessPipe_Process sender, char *buffer, size_t bufferLen, size_t* bytesConsumed, void* user)
{
unsigned short size = 0;
UNREFERENCED_PARAMETER(sender);
ILibKVM_WriteHandler writeHandler = (ILibKVM_WriteHandler)((void**)user)[0];
void *reserved = ((void**)user)[1];
if (bufferLen > 4)
{
if (ntohs(((unsigned short*)(buffer))[0]) == (unsigned short)MNG_JUMBO)
{
if (bufferLen > 8)
{
if (bufferLen >= (size_t)(8 + (int)ntohl(((unsigned int*)(buffer))[1])))
{
*bytesConsumed = 8 + (int)ntohl(((unsigned int*)(buffer))[1]);
writeHandler(buffer, (int)*bytesConsumed, reserved);
return;
}
}
}
else
{
size = ntohs(((unsigned short*)(buffer))[1]);
if (size <= bufferLen)
{
*bytesConsumed = size;
writeHandler(buffer, size, reserved);
return;
}
}
}
*bytesConsumed = 0;
}
void kvm_relay_StdErrHandler(ILibProcessPipe_Process sender, char *buffer, size_t bufferLen, size_t* 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", g_ILibCrashDump_path != NULL ? "-coredump" : NULL, NULL, NULL };
char * parms1[] = { " -kvm1", g_ILibCrashDump_path != NULL ? "-coredump" : NULL, NULL, NULL };
void **user = (void**)ILibMemory_Allocate(4 * sizeof(void*), 0, NULL, NULL);
if (parms0[1] == NULL)
{
parms0[1] = (gRemoteMouseRenderDefault != 0 ? "-remotecursor" : NULL);
parms1[1] = (gRemoteMouseRenderDefault != 0 ? "-remotecursor" : NULL);
}
else
{
parms0[2] = (gRemoteMouseRenderDefault != 0 ? "-remotecursor" : NULL);
parms1[2] = (gRemoteMouseRenderDefault != 0 ? "-remotecursor" : 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);
if (gProcessSpawnType == ILibProcessPipe_SpawnTypes_SPECIFIED_USER && gProcessTSID < 0) { gProcessSpawnType = ILibProcessPipe_SpawnTypes_USER; }
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_SpawnProcessEx3(pipeMgr, exePath, paused == 0 ? parms0 : parms1, gProcessSpawnType, (void*)(ULONG_PTR)gProcessTSID, 0);
gProcessSpawnType = (gProcessSpawnType == ILibProcessPipe_SpawnTypes_SPECIFIED_USER || gProcessSpawnType == ILibProcessPipe_SpawnTypes_USER) ? ILibProcessPipe_SpawnTypes_WINLOGON : (gProcessTSID < 0 ? ILibProcessPipe_SpawnTypes_USER : ILibProcessPipe_SpawnTypes_SPECIFIED_USER);
g_slavekvm = ILibProcessPipe_Process_GetPID(gChildProcess);
char tmp[255];
sprintf_s(tmp, sizeof(tmp), "Child KVM (pid: %d)", g_slavekvm);
ILibProcessPipe_Process_ResetMetadata(gChildProcess, tmp);
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, int tsid)
{
if (processPipeMgr != NULL)
{
#ifdef _WINSERVICE
if (ThreadRunning == 1 && g_shutdown == 0) { KVMDEBUG("kvm_relay_setup() session already exists", 0); return 0; }
g_restartcount = 0;
gProcessSpawnType = ILibProcessPipe_SpawnTypes_SPECIFIED_USER;
gProcessTSID = tsid;
KVMDEBUG("kvm_relay_setup() session starting", 0);
return kvm_relay_restart(1, processPipeMgr, exePath, writeHandler, reserved);
#else
return(0);
#endif
}
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;
kvmConsoleMode = 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;
}
}
// 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");
ILibProcessPipe_Process_SoftKill(gChildProcess);
gChildProcess = NULL;
}
else
{
ILibRemoteLogging_printf(ILibChainGetLogger(gILibChain), ILibRemoteLogging_Modules_Agent_KVM, ILibRemoteLogging_Flags_VerbosityLevel_1, "KVM.c/kvm_cleanup: gChildProcess = NULL");
}
}
////
//// Desktop Duplication API KVM
////
//#include <d3d11.h>
//#include <dxgi1_2.h>
//
//typedef struct D3D11_Functions
//{
// HRESULT(*D3D11CreateDevice)(
// IDXGIAdapter *pAdapter,
// D3D_DRIVER_TYPE DriverType,
// HMODULE Software,
// UINT Flags,
// const D3D_FEATURE_LEVEL *pFeatureLevels,
// UINT FeatureLevels,
// UINT SDKVersion,
// ID3D11Device **ppDevice,
// D3D_FEATURE_LEVEL *pFeatureLevel,
// ID3D11DeviceContext **ppImmediateContext
// );
//}D3D11_Functions;
//void DD_Init()
//{
//int i;
//HRESULT hr;
//ID3D11Device* m_Device;
//ID3D11DeviceContext* m_DeviceContext;
//IDXGIFactory2* m_Factory;
//DWORD m_OcclusionCookie;
//DXGI_OUTDUPL_DESC lOutputDuplDesc;
//ID3D11Texture2D *lGDIImage;
//ID3D11Texture2D *desktopImage;
//ID3D11Texture2D *destinationImage;
//DXGI_OUTDUPL_FRAME_INFO lFrameInfo;
//IDXGIResource *lDesktopResource;
//D3D11_Functions funcs;
//HMODULE _D3D = NULL;
//if ((_D3D = LoadLibraryExA((LPCSTR)"D3D11.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32)) != NULL)
//{
// (FARPROC)funcs.D3D11CreateDevice = GetProcAddress(_D3D, "D3D11CreateDevice");
//}
//D3D_DRIVER_TYPE DriverTypes[] =
//{
// D3D_DRIVER_TYPE_HARDWARE,
// D3D_DRIVER_TYPE_WARP,
// D3D_DRIVER_TYPE_REFERENCE,
//};
//UINT NumDriverTypes = ARRAYSIZE(DriverTypes);
//// Feature levels supported
//D3D_FEATURE_LEVEL FeatureLevels[] =
//{
// D3D_FEATURE_LEVEL_11_0,
// D3D_FEATURE_LEVEL_10_1,
// D3D_FEATURE_LEVEL_10_0,
// D3D_FEATURE_LEVEL_9_1
//};
//UINT NumFeatureLevels = ARRAYSIZE(FeatureLevels);
//D3D_FEATURE_LEVEL FeatureLevel;
//// Create device
//for (UINT DriverTypeIndex = 0; DriverTypeIndex < NumDriverTypes; ++DriverTypeIndex)
//{
// hr = funcs.D3D11CreateDevice(NULL, DriverTypes[DriverTypeIndex], NULL, 0, FeatureLevels, NumFeatureLevels, D3D11_SDK_VERSION, &m_Device, &FeatureLevel, &m_DeviceContext);
// if (SUCCEEDED(hr))
// {
// // Device creation succeeded, no need to loop anymore
// break;
// }
//}
//if (FAILED(hr))
//{
// DebugBreak();
//}
//// Get DXGI factory
//IDXGIDevice* DxgiDevice = NULL;
//hr = m_Device->lpVtbl->QueryInterface(m_Device, &IID_IDXGIDevice, (void**)&DxgiDevice);
//if (FAILED(hr))
//{
// DebugBreak();
//}
//IDXGIAdapter* DxgiAdapter = NULL;
//hr = DxgiDevice->lpVtbl->GetParent(DxgiDevice, &IID_IDXGIAdapter, (void**)&DxgiAdapter);
//DxgiDevice->lpVtbl->Release(DxgiDevice);
//DxgiDevice = NULL;
//if (FAILED(hr))
//{
// DebugBreak();
//}
//hr = DxgiAdapter->lpVtbl->GetParent(DxgiAdapter, &IID_IDXGIFactory2, (void**)&m_Factory);
//DxgiAdapter->lpVtbl->Release(DxgiAdapter);
//DxgiAdapter = NULL;
//if (FAILED(hr))
//{
// DebugBreak();
// //return ProcessFailure(m_Device, L"Failed to get parent DXGI Factory", L"Error", hr, SystemTransitionsExpectedErrors);
//}
//IDXGIOutput1 *DxgiOutput1;
//hr = m_Device->lpVtbl->QueryInterface(m_Device, &IID_IDXGIOutput, (void**)&DxgiOutput1);
//if (FAILED(hr))
//{
// DebugBreak();
//}
//IDXGIOutputDuplication *dupl = NULL;
//DxgiOutput1->lpVtbl->DuplicateOutput(DxgiOutput1, m_Device, &dupl);
//// Create GUI drawing texture
//dupl->lpVtbl->GetDesc(dupl, &lOutputDuplDesc);
//D3D11_TEXTURE2D_DESC desc;
//desc.Width = lOutputDuplDesc.ModeDesc.Width;
//desc.Height = lOutputDuplDesc.ModeDesc.Height;
//desc.Format = lOutputDuplDesc.ModeDesc.Format;
//desc.ArraySize = 1;
//desc.BindFlags = D3D11_BIND_RENDER_TARGET;
//desc.MiscFlags = D3D11_RESOURCE_MISC_GDI_COMPATIBLE;
//desc.SampleDesc.Count = 1;
//desc.SampleDesc.Quality = 0;
//desc.MipLevels = 1;
//desc.CPUAccessFlags = 0;
//desc.Usage = D3D11_USAGE_DEFAULT;
//hr = m_Device->lpVtbl->CreateTexture2D(m_Device, &desc, NULL, &lGDIImage);
//hr = m_Device->lpVtbl->CreateTexture2D(m_Device, &desc, NULL, &destinationImage);
//if (FAILED(hr))
//{
// DebugBreak();
//}
//// Get new frame
//for (i = 0; i < 5; ++i)
//{
// hr = dupl->lpVtbl->AcquireNextFrame(dupl, 250, &lFrameInfo, &lDesktopResource);
// if (hr != DXGI_ERROR_WAIT_TIMEOUT) { break; }
// Sleep(100);
//}
//
//hr = lDesktopResource->lpVtbl->QueryInterface(lDesktopResource, &IID_ID3D11Texture2D, &desktopImage);
//// Copy image into GDI drawing texture
//m_DeviceContext->lpVtbl->CopyResource(m_DeviceContext, lGDIImage, desktopImage);
//// Draw cursor image into GDI drawing texture
//IDXGISurface1 *surface;
//hr = lGDIImage->lpVtbl->QueryInterface(lGDIImage, &IID_IDXGISurface1, &surface);
//// Copy from CPU access texture to bitmap buffer
//D3D11_MAPPED_SUBRESOURCE resource;
//UINT subresource = D3D11CalcSubresource(0, 0, 0);
//m_DeviceContext->lpVtbl->Map(m_DeviceContext, destinationImage, subresource, D3D11_MAP_READ_WRITE, 0, &resource);
//BITMAPINFO lBmpInfo;
//// BMP 32 bpp
//ZeroMemory(&lBmpInfo, sizeof(BITMAPINFO));
//lBmpInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
//lBmpInfo.bmiHeader.biBitCount = 32;
//lBmpInfo.bmiHeader.biCompression = BI_RGB;
//lBmpInfo.bmiHeader.biWidth = lOutputDuplDesc.ModeDesc.Width;
//lBmpInfo.bmiHeader.biHeight = lOutputDuplDesc.ModeDesc.Height;
//lBmpInfo.bmiHeader.biPlanes = 1;
//lBmpInfo.bmiHeader.biSizeImage = lOutputDuplDesc.ModeDesc.Width * lOutputDuplDesc.ModeDesc.Height * 4;
//BYTE* pBuf = (BYTE*)ILibMemory_SmartAllocate(lBmpInfo.bmiHeader.biSizeImage);
//UINT lBmpRowPitch = lOutputDuplDesc.ModeDesc.Width * 4;
//BYTE* sptr = (BYTE*)resource.pData;
//BYTE* dptr = pBuf + lBmpInfo.bmiHeader.biSizeImage - lBmpRowPitch;
//UINT lRowPitch = min(lBmpRowPitch, resource.RowPitch);
//size_t h;
//for (h = 0; h < lOutputDuplDesc.ModeDesc.Height; ++h)
//{
// memcpy_s(dptr, lBmpRowPitch, sptr, lRowPitch);
// sptr += resource.RowPitch;
// dptr -= lBmpRowPitch;
//}
//}
#endif