mirror of
https://github.com/Ylianst/MeshAgent
synced 2025-12-10 13:23:41 +00:00
1507 lines
48 KiB
C
1507 lines
48 KiB
C
/*
|
|
Copyright 2010 - 2011 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.
|
|
*/
|
|
|
|
#include "linux_kvm.h"
|
|
#include "meshcore/meshdefines.h"
|
|
#include "microstack/ILibParsers.h"
|
|
#include "microstack/ILibAsyncSocket.h"
|
|
#include "microstack/ILibAsyncServerSocket.h"
|
|
#include "microstack/ILibProcessPipe.h"
|
|
#include <sys/wait.h>
|
|
#include <limits.h>
|
|
#include <time.h>
|
|
|
|
#include <sys/ipc.h>
|
|
#include <sys/shm.h>
|
|
#include <X11/extensions/XShm.h>
|
|
#include <X11/keysym.h>
|
|
#include <X11/Xlib.h>
|
|
#include <dlfcn.h>
|
|
|
|
#if !defined(_FREEBSD)
|
|
#include <sys/prctl.h>
|
|
#endif
|
|
|
|
#include "linux_events.h"
|
|
#include "linux_compression.h"
|
|
|
|
#define EXIT_SUCCESS 0
|
|
#define EXIT_FAILURE 1
|
|
extern uint32_t crc32c(uint32_t crc, const unsigned char* buf, uint32_t len);
|
|
extern char* g_ILibCrashDump_path;
|
|
|
|
typedef struct kvm_keydata
|
|
{
|
|
int delay;
|
|
uint8_t up;
|
|
uint16_t data;
|
|
}kvm_keydata;
|
|
|
|
typedef enum KVM_MouseCursors
|
|
{
|
|
KVM_MouseCursor_NOCHANGE = -1,
|
|
KVM_MouseCursor_ARROW = 0,
|
|
KVM_MouseCursor_APPSTARTING = 1,
|
|
KVM_MouseCursor_CROSS = 2,
|
|
KVM_MouseCursor_HAND = 3,
|
|
KVM_MouseCursor_HELP = 4,
|
|
KVM_MouseCursor_IBEAM = 5,
|
|
KVM_MouseCursor_NO = 6,
|
|
KVM_MouseCursor_SIZEALL = 7,
|
|
KVM_MouseCursor_SIZENESW = 8,
|
|
KVM_MouseCursor_SIZENS = 9,
|
|
KVM_MouseCursor_SIZENWSE = 10,
|
|
KVM_MouseCursor_SIZEWE = 11,
|
|
KVM_MouseCursor_UPARROW = 12,
|
|
KVM_MouseCursor_WAIT = 13,
|
|
KVM_MouseCursor_NONE = 14,
|
|
KVM_MouseCursor_NOTALLOWED = 15
|
|
}KVM_MouseCursors;
|
|
|
|
int curcursor = KVM_MouseCursor_HELP;
|
|
int SLAVELOG = 0;
|
|
|
|
int SCREEN_NUM = 0;
|
|
int SCREEN_WIDTH = 0;
|
|
int SCREEN_HEIGHT = 0;
|
|
int SCREEN_DEPTH = 0;
|
|
int TILE_WIDTH = 0;
|
|
int TILE_HEIGHT = 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;
|
|
struct tileInfo_t **g_tileInfo = NULL;
|
|
pthread_t kvmthread = (pthread_t)NULL;
|
|
Display *eventdisplay = NULL;
|
|
int g_remotepause = 0;
|
|
int g_pause = 0;
|
|
int g_restartcount = 0;
|
|
int g_totalRestartCount = 0;
|
|
int g_shutdown = 0;
|
|
int change_display = 0;
|
|
unsigned short current_display = 0;
|
|
pid_t g_slavekvm = 0;
|
|
int master2slave[2];
|
|
int slave2master[2];
|
|
|
|
FILE *logFile = NULL;
|
|
int g_enableEvents = 0;
|
|
extern int gRemoteMouseRenderDefault;
|
|
|
|
int remoteMouseX = 0, remoteMouseY = 0;
|
|
|
|
extern void* tilebuffer;
|
|
extern char **environ;
|
|
struct timespec inputtime;
|
|
uint32_t inputcounter = 0;
|
|
|
|
typedef struct x11ext_struct
|
|
{
|
|
void *xext_lib;
|
|
Bool(*XShmDetach)(Display *d, XShmSegmentInfo *si);
|
|
Bool(*XShmGetImage)(Display *dis, Drawable d, XImage *image, int x, int y, unsigned long plane_mask);
|
|
Bool(*XShmAttach)(Display *d, XShmSegmentInfo *si);
|
|
XImage*(*XShmCreateImage)(Display *display, Visual *visual, unsigned int depth, int format, char *data, XShmSegmentInfo *shminfo, unsigned int width, unsigned int height);
|
|
}x11ext_struct;
|
|
x11ext_struct *x11ext_exports = NULL;
|
|
extern x11tst_struct *x11tst_exports;
|
|
|
|
typedef struct x11_struct
|
|
{
|
|
void *x11_lib;
|
|
Display*(*XOpenDisplay)(char *display_name);
|
|
int(*XCloseDisplay)(Display *d);
|
|
int(*XFlush)(Display *d);
|
|
KeyCode(*XKeysymToKeycode)(Display *d, KeySym keysym);
|
|
Bool(*XQueryExtension)(Display *d, char *name, int* maj, int *firstev, int *firsterr);
|
|
|
|
int(*XConnectionNumber)(Display *d);
|
|
char*(*XGetAtomName)(Display *d, Atom atom);
|
|
void(*XNextEvent)(Display *d, XEvent *event_return);
|
|
int(*XPending)(Display *d);
|
|
Window(*XRootWindow)(Display *d, int screen_number);
|
|
void(*XSync)(Display *d, Bool discard);
|
|
void(*XFree)(void *data);
|
|
void(*XSelectInput)(Display *d, Window w, long mask);
|
|
int(*XGetWindowAttributes)(Display *d, Window w, XWindowAttributes *a);
|
|
void(*XChangeWindowAttributes)(Display *d, Window w, unsigned long valuemask, XSetWindowAttributes *a);
|
|
int(*XQueryPointer)(Display *d, Window w, Window *rr, Window *cr, int *rx, int *ry, int *wx, int *wy, unsigned int *mr);
|
|
int(*XDisplayKeycodes)(Display *display, int *min_keycodes_return, int *max_keycodes_return);
|
|
KeySym(*XGetKeyboardMapping)(Display *display, KeyCode first_keycode, int keycode_count, int *keysyms_per_keycode_return);
|
|
KeySym(*XStringToKeysym)(char *string);
|
|
int(*XChangeKeyboardMapping)(Display *display, int first_keycode, int keysyms_per_keycode, KeySym *keysyms, int num_codes);
|
|
}x11_struct;
|
|
x11_struct *x11_exports = NULL;
|
|
|
|
typedef struct xfixes_struct
|
|
{
|
|
void *xfixes_lib;
|
|
Bool(*XFixesSelectCursorInput)(Display *d, Window w, int i);
|
|
Bool(*XFixesQueryExtension)(Display *d, int *eventbase, int *errorbase);
|
|
void*(*XFixesGetCursorImage)(Display *d);
|
|
void*(*XFixesGetCursorImageAndName)(Display *d);
|
|
}xfixes_struct;
|
|
xfixes_struct *xfixes_exports = NULL;
|
|
|
|
void kvm_keyboard_unmap_unicode_key(Display *display, int keycode)
|
|
{
|
|
// Delete a keymapping that we created previously
|
|
KeySym keysym_list[] = { 0 };
|
|
x11_exports->XChangeKeyboardMapping(display, keycode, 1, keysym_list, 1);
|
|
x11_exports->XSync(display, 0);
|
|
}
|
|
int kvm_keyboard_update_map_unicode_key(Display *display, uint16_t unicode, int keycode)
|
|
{
|
|
char unicodestring[6];
|
|
|
|
// Convert the unicode character to something xorg will understand
|
|
if (sprintf_s(unicodestring, sizeof(unicodestring), "U%04X", unicode) < 0) { return(keycode); }
|
|
|
|
// Map the unicode character to one of the unused keys above
|
|
KeySym sym = x11_exports->XStringToKeysym(unicodestring);
|
|
KeySym keysym_list[] = { sym, sym };
|
|
x11_exports->XChangeKeyboardMapping(display, keycode, 2, keysym_list, 1);
|
|
x11_exports->XSync(display, 0);
|
|
return(keycode);
|
|
}
|
|
int kvm_keyboard_map_unicode_key(Display *display, uint16_t unicode, int *alreadyExists)
|
|
{
|
|
KeySym *keysyms = NULL;
|
|
int keysyms_per_keycode = 0;
|
|
int keycode_low, keycode_high;
|
|
int empty_keycode = 0;
|
|
int i, j, keycodeIndex;
|
|
char unicodestring[6];
|
|
if (alreadyExists != NULL) { *alreadyExists = 0; }
|
|
|
|
// Convert the unicode character to something xorg will understand
|
|
if (sprintf_s(unicodestring, sizeof(unicodestring), "U%04X", unicode) < 0) { return(-1); }
|
|
KeySym sym = x11_exports->XStringToKeysym(unicodestring);
|
|
//ILIBLOGMESSAGEX("UNICODE SYM: %X", sym);
|
|
|
|
// Get the keycode range that is supported on this platform
|
|
x11_exports->XDisplayKeycodes(display, &keycode_low, &keycode_high);
|
|
keysyms = x11_exports->XGetKeyboardMapping(display, keycode_low, keycode_high - keycode_low, &keysyms_per_keycode);
|
|
|
|
if (alreadyExists != NULL)
|
|
{
|
|
int foundCode = x11_exports->XKeysymToKeycode(display, sym);
|
|
if (foundCode != 0)
|
|
{
|
|
// Check to see if this mapping is the primary mapping
|
|
keycodeIndex = (foundCode - keycode_low) * keysyms_per_keycode;
|
|
if (keysyms[keycodeIndex] == sym)
|
|
{
|
|
// We have a match!
|
|
//ILIBLOGMESSAGEX(" Already mapped at: %d", foundCode);
|
|
empty_keycode = foundCode;
|
|
*alreadyExists = 1;
|
|
}
|
|
else
|
|
{
|
|
// No match!
|
|
//ILIBLOGMESSAGEX(" Already mapped at: %d, but is not PRIMARY", foundCode);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if (empty_keycode == 0)
|
|
{
|
|
// Find an unmapped key
|
|
for (i = keycode_low; i <= keycode_high; ++i)
|
|
{
|
|
int empty = 1;
|
|
for (j = 0; j < keysyms_per_keycode; ++j)
|
|
{
|
|
keycodeIndex = (i - keycode_low) * keysyms_per_keycode + j;
|
|
if (keysyms[keycodeIndex] != 0) { empty = 0; }
|
|
else { break; }
|
|
}
|
|
if (empty) { empty_keycode = i; break; } // Found it!
|
|
}
|
|
|
|
|
|
// Map the unicode character to one of the unused keys above
|
|
KeySym keysym_list[] = { sym, sym };
|
|
x11_exports->XChangeKeyboardMapping(display, empty_keycode, 2, keysym_list, 1);
|
|
x11_exports->XSync(display, 0);
|
|
|
|
}
|
|
|
|
x11_exports->XFree(keysyms);
|
|
return(empty_keycode);
|
|
}
|
|
|
|
void kvm_send_error(char *msg)
|
|
{
|
|
int msgLen = strnlen_s(msg, 255);
|
|
char buffer[512];
|
|
|
|
((unsigned short*)buffer)[0] = (unsigned short)htons((unsigned short)MNG_ERROR); // Write the type
|
|
((unsigned short*)buffer)[1] = (unsigned short)htons((unsigned short)(msgLen + 4)); // Write the size
|
|
memcpy_s(buffer + 4, msgLen, msg, msgLen);
|
|
ignore_result(write(slave2master[1], buffer, msgLen + 2));
|
|
}
|
|
|
|
KVM_MouseCursors kvm_fetch_currentCursor(Display *cursordisplay)
|
|
{
|
|
// Name was NULL, so as a last ditch effort, lets try to look at the XFixesCursorImage
|
|
char *cursor_image = (char*)xfixes_exports->XFixesGetCursorImage(cursordisplay);
|
|
KVM_MouseCursors ret = KVM_MouseCursor_HELP;
|
|
|
|
unsigned short w = ((unsigned short*)(cursor_image + 4))[0];
|
|
unsigned short h = ((unsigned short*)(cursor_image + 6))[0];
|
|
char *pixels = cursor_image + (sizeof(void*) == 8 ? 24 : 16);
|
|
char alpha[65535];
|
|
int i;
|
|
|
|
if (((size_t)(w*h) <= sizeof(alpha)) && ((size_t)(w*h) > 6))
|
|
{
|
|
for (i = 0; i < (w*h); ++i)
|
|
{
|
|
alpha[i] = pixels[(sizeof(void*)==8?(3 + (i * 8)):(3 + (i * 4)))];
|
|
}
|
|
switch (crc32c(0, (unsigned char*)alpha+6, (uint32_t)((w*h)-6)))
|
|
{
|
|
case 2788757291: // Ubuntu 20
|
|
case 1722092522: // Ubuntu 9/10 (Top)
|
|
case 2893151230: // Ubuntu 9/10 (Bottom)
|
|
case 3911022957: // Ubuntu/Peppermint (Top)
|
|
case 315617398: // Ubuntu/Peppermint (Bottom)
|
|
case 313635327: // FreeBSD
|
|
case 399455764: // openSUSE
|
|
case 3867633865: // PuppyLinux (Top)
|
|
case 2405141328: // PuppyLinux (Bottom)
|
|
case 2017738775: // Raspian/CentOS (Top)
|
|
case 1820008802: // Raspian/CentOS (Bottom)
|
|
ret = KVM_MouseCursor_SIZENS;
|
|
break;
|
|
|
|
case 2098355412: // Ubuntu 20 (Left)
|
|
case 1870927140: // Ubuntu 20 (Right)
|
|
case 3756583870: // Ubuntu 9/10 (Left)
|
|
case 2797106708: // Ubuntu 9/10 (Right)
|
|
case 1206496159: // Ubuntu (Left)
|
|
case 3947249005: // Ubuntu (Right)
|
|
case 2065486748: // FreeBSD
|
|
case 3817177836: // openSUSE
|
|
case 2760825997: // PuppyLinux (Left)
|
|
case 222646089: // PuppyLinux (Right)
|
|
case 1924105758: // Raspian (Left)
|
|
case 18444308: // Raspian (Right)
|
|
ret = KVM_MouseCursor_SIZEWE;
|
|
break;
|
|
|
|
case 1022545981: // Ubuntu 20 (Bottom Left)
|
|
case 587249781: // Ubuntu 20 (Upper Right)
|
|
case 465233379: // Ubuntu 9/10 (Bottom Left)
|
|
case 1129233427: // Ubuntu 9/10 (Upper Right)
|
|
case 305612954: // Ubuntu (Bottom Left)
|
|
case 1245488815: // Ubuntu (Upper Right)
|
|
case 169817074: // FreeBSD + PuppyLinux (Bottom Left)
|
|
case 482480649: // FreeBSD + PuppyLinux (Upper Right)
|
|
case 1405624986: // openSUSE
|
|
case 2989878302: // Raspian (Bottom Left)
|
|
case 21344493: // Raspian (Upper Right)
|
|
ret = KVM_MouseCursor_SIZENESW;
|
|
break;
|
|
|
|
|
|
case 1016474413: // Ubuntu 20 (Upper Left)
|
|
case 2912730571: // Ubuntu 20 (Bottom Right)
|
|
case 1292166613: // Ubuntu 9/10 (Upper Left)
|
|
case 4017655526: // Ubuntu 9/10 (Bottom Right)
|
|
case 799529566: // Ubuntu (Upper Left)
|
|
case 4056118275: // Ubuntu (Bottom Right)
|
|
case 2757619196: // FreeBSD + PuppyLinux (Bottom Right)
|
|
case 3302778157: // FreeBSD + PuppyLinux (Upper Left)
|
|
case 924333740: // openSUSE
|
|
case 2843753620: // Raspian (Upper Left)
|
|
case 4110212903: // Raspian (Bottom Right)
|
|
ret = KVM_MouseCursor_SIZENWSE;
|
|
break;
|
|
|
|
case 177740762: // Deepin 20
|
|
case 3606431443: // Ubuntu 20
|
|
case 3694153785: // Ubuntu 9/10
|
|
case 2280086639: // Ubuntu
|
|
case 920009133: // FreeBSD + PuppyLinux
|
|
case 2321998854: // openSUSE
|
|
case 926331252: // Raspian
|
|
ret = KVM_MouseCursor_SIZEALL;
|
|
break;
|
|
|
|
case 539866054: // Deepin 20 (Normal)
|
|
case 1802968862: // Deepin 20 (Large)
|
|
case 2550770000: // Ubuntu 20
|
|
case 3097204904: // Ubuntu 9/10
|
|
case 3546300886: // Ubuntu
|
|
case 1038978227: // FreeBSD + PuppyLinux + openSUSE
|
|
case 4237429080: // Raspian
|
|
ret = KVM_MouseCursor_ARROW;
|
|
break;
|
|
|
|
case 4197067144: // Ubuntu 20
|
|
case 2170379861: // Ubuntu 9/10
|
|
case 1176251007: // Ubuntu
|
|
case 3320936845: // FreeBSD
|
|
case 795881928: // PuppyLinux
|
|
case 134935791: // Raspian
|
|
ret = KVM_MouseCursor_IBEAM;
|
|
break;
|
|
|
|
case 3805997719: // Deepin 20
|
|
case 1393241229: // Ubuntu 20
|
|
case 990896914: // Ubuntu 9/10
|
|
case 3673902152: // Ubuntu
|
|
case 27109234: // Raspian
|
|
case (uint32_t)-1421461853: // PuppyLinux
|
|
ret = KVM_MouseCursor_HAND;
|
|
break;
|
|
|
|
case 3503643429: // Deepin 20
|
|
case 620546299: // Ubuntu 20
|
|
case 3463742778: // Ubuntu
|
|
ret = KVM_MouseCursor_WAIT;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
return(ret);
|
|
}
|
|
void kvm_send_resolution()
|
|
{
|
|
char buffer[8];
|
|
((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)SCREEN_WIDTH); // X position
|
|
((unsigned short*)buffer)[3] = (unsigned short)htons((unsigned short)SCREEN_HEIGHT); // Y position
|
|
|
|
ignore_result(write(slave2master[1], buffer, sizeof(buffer)));
|
|
}
|
|
|
|
void kvm_send_display()
|
|
{
|
|
char buffer[5];
|
|
((unsigned short*)buffer)[0] = (unsigned short)htons((unsigned short)MNG_KVM_SET_DISPLAY); // Write the type
|
|
((unsigned short*)buffer)[1] = (unsigned short)htons((unsigned short)5); // Write the size
|
|
buffer[4] = current_display; // Display number
|
|
|
|
ignore_result(write(slave2master[1], buffer, sizeof(buffer)));
|
|
}
|
|
|
|
#define BUFSIZE 65535
|
|
|
|
int kvm_server_inputdata(char* block, int blocklen);
|
|
|
|
int lockfileCheckFn(const struct dirent *ent) {
|
|
if (ent == NULL) {
|
|
return 0;
|
|
}
|
|
|
|
if (!strncmp(ent->d_name, ".X", 2) && strcmp(ent->d_name, ".X11-unix") && strcmp(ent->d_name, ".XIM-unix")) {
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void getAvailableDisplays(unsigned short **array, int *len) {
|
|
DIR *dir = NULL;
|
|
struct dirent **ent = NULL;
|
|
int i;
|
|
*array = NULL;
|
|
*len = 0;
|
|
|
|
dir = opendir("/tmp/");
|
|
if (dir != NULL) {
|
|
*len = scandir("/tmp/", &ent, lockfileCheckFn, alphasort);
|
|
|
|
if ((*array = (unsigned short *)malloc((*len)*sizeof(unsigned short))) == NULL) ILIBCRITICALEXIT(254);
|
|
|
|
for (i = 0; i < *len; i++) {
|
|
int dispNo = 0;
|
|
|
|
sscanf(ent[i]->d_name, ".X%d-lock", &dispNo);
|
|
(*array)[i] = (unsigned short)dispNo;
|
|
}
|
|
}
|
|
}
|
|
|
|
int getNextDisplay() {
|
|
DIR *dir = NULL;
|
|
struct dirent **ent = NULL;
|
|
int i, dispNo;
|
|
|
|
dir = opendir("/tmp/");
|
|
if (dir != NULL) {
|
|
int numDisplays = scandir("/tmp/", &ent, lockfileCheckFn, alphasort);
|
|
if (numDisplays == 0) { return -1; }
|
|
|
|
for (i = 0; i < numDisplays; i++) {
|
|
|
|
sscanf(ent[i]->d_name, ".X%d-lock", &dispNo);
|
|
|
|
if (dispNo == (int)current_display) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (i == numDisplays) {
|
|
i = 0;
|
|
}
|
|
else {
|
|
i = (i + 1) % numDisplays;
|
|
}
|
|
|
|
sscanf(ent[i]->d_name, ".X%d-lock", &dispNo);
|
|
current_display = (unsigned short) dispNo;
|
|
closedir(dir);
|
|
}
|
|
else {
|
|
current_display = 0;
|
|
}
|
|
|
|
//fprintf(logFile, "getNextDisplay() => %d\n", current_display);
|
|
return 0;
|
|
}
|
|
|
|
void kvm_send_display_list()
|
|
{
|
|
unsigned short *displays = NULL;
|
|
int len = 0;
|
|
char* buffer;
|
|
int totalSize = 0;
|
|
int i;
|
|
|
|
getAvailableDisplays(&displays, &len);
|
|
totalSize = 2 /*Type*/ + 2 /*length of packet*/ + 2 /*length of data*/ + (len * 2) /*Data*/ + 2 /* Current display */;
|
|
buffer = (char*)ILibMemory_SmartAllocate(totalSize);
|
|
|
|
((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)totalSize); // Write the size
|
|
((unsigned short*)buffer)[2] = (unsigned short)htons((unsigned short)len); // Length
|
|
for (i = 0; i < len; i++) {
|
|
((unsigned short*)buffer)[i + 3] = (unsigned short)htons(displays[i]);
|
|
}
|
|
((unsigned short*)buffer)[i + 3] = (unsigned short)htons((unsigned short)current_display); // Current display
|
|
|
|
ignore_result(write(slave2master[1], buffer, ILibMemory_Size(buffer)));
|
|
}
|
|
|
|
char Location_X11LIB[NAME_MAX];
|
|
char Location_X11TST[NAME_MAX];
|
|
char Location_X11EXT[NAME_MAX];
|
|
char Location_X11FIXES[NAME_MAX];
|
|
void kvm_set_x11_locations(char *libx11, char *libx11tst, char *libx11ext, char *libxfixes)
|
|
{
|
|
if (libx11 != NULL) { strcpy_s(Location_X11LIB, sizeof(Location_X11LIB), libx11); } else { strcpy_s(Location_X11LIB, sizeof(Location_X11LIB), "libX11.so"); }
|
|
if (libx11tst != NULL) { strcpy_s(Location_X11TST, sizeof(Location_X11TST), libx11tst); } else { strcpy_s(Location_X11TST, sizeof(Location_X11TST), "libXtst.so"); }
|
|
if (libx11ext != NULL) { strcpy_s(Location_X11EXT, sizeof(Location_X11EXT), libx11ext); } else { strcpy_s(Location_X11EXT, sizeof(Location_X11EXT), "libXext.so"); }
|
|
if (libxfixes != NULL) { strcpy_s(Location_X11FIXES, sizeof(Location_X11FIXES), libxfixes); } else { strcpy_s(Location_X11FIXES, sizeof(Location_X11FIXES), "libXfixes.so"); }
|
|
}
|
|
|
|
int kvm_init(int displayNo)
|
|
{
|
|
//fprintf(logFile, "kvm_init called\n"); fflush(logFile);
|
|
int old_height_count = TILE_HEIGHT_COUNT;
|
|
int count = 0;
|
|
int dummy1, dummy2, dummy3;
|
|
char displayString[256] = "";
|
|
|
|
if (clock_gettime(CLOCK_MONOTONIC, &inputtime) != 0) { memset(&inputtime, 0, sizeof(inputtime)); }
|
|
|
|
if (x11ext_exports == NULL)
|
|
{
|
|
x11ext_exports = ILibMemory_SmartAllocate(sizeof(x11ext_struct));
|
|
x11ext_exports->xext_lib = dlopen(Location_X11EXT, RTLD_NOW);
|
|
if (x11ext_exports->xext_lib)
|
|
{
|
|
((void**)x11ext_exports)[1] = (void*)dlsym(x11ext_exports->xext_lib, "XShmDetach");
|
|
((void**)x11ext_exports)[2] = (void*)dlsym(x11ext_exports->xext_lib, "XShmGetImage");
|
|
((void**)x11ext_exports)[3] = (void*)dlsym(x11ext_exports->xext_lib, "XShmAttach");
|
|
((void**)x11ext_exports)[4] = (void*)dlsym(x11ext_exports->xext_lib, "XShmCreateImage");
|
|
}
|
|
}
|
|
if (x11tst_exports == NULL)
|
|
{
|
|
x11tst_exports = ILibMemory_SmartAllocate(sizeof(x11tst_struct));
|
|
x11tst_exports->x11tst_lib = dlopen(Location_X11TST, RTLD_NOW);
|
|
if (x11tst_exports->x11tst_lib)
|
|
{
|
|
((void**)x11tst_exports)[1] = (void*)dlsym(x11tst_exports->x11tst_lib, "XTestFakeMotionEvent");
|
|
((void**)x11tst_exports)[2] = (void*)dlsym(x11tst_exports->x11tst_lib, "XTestFakeButtonEvent");
|
|
((void**)x11tst_exports)[3] = (void*)dlsym(x11tst_exports->x11tst_lib, "XTestFakeKeyEvent");
|
|
}
|
|
}
|
|
if (x11_exports == NULL)
|
|
{
|
|
x11_exports = ILibMemory_SmartAllocate(sizeof(x11_struct));
|
|
x11_exports->x11_lib = dlopen(Location_X11LIB, RTLD_NOW);
|
|
if (x11_exports->x11_lib)
|
|
{
|
|
((void**)x11_exports)[1] = (void*)dlsym(x11_exports->x11_lib, "XOpenDisplay");
|
|
((void**)x11_exports)[2] = (void*)dlsym(x11_exports->x11_lib, "XCloseDisplay");
|
|
((void**)x11_exports)[3] = (void*)dlsym(x11_exports->x11_lib, "XFlush");
|
|
((void**)x11_exports)[4] = (void*)dlsym(x11_exports->x11_lib, "XKeysymToKeycode");
|
|
((void**)x11_exports)[5] = (void*)dlsym(x11_exports->x11_lib, "XQueryExtension");
|
|
|
|
((void**)x11_exports)[6] = (void*)dlsym(x11_exports->x11_lib, "XConnectionNumber");
|
|
((void**)x11_exports)[7] = (void*)dlsym(x11_exports->x11_lib, "XGetAtomName");
|
|
((void**)x11_exports)[8] = (void*)dlsym(x11_exports->x11_lib, "XNextEvent");
|
|
((void**)x11_exports)[9] = (void*)dlsym(x11_exports->x11_lib, "XPending");
|
|
((void**)x11_exports)[10] = (void*)dlsym(x11_exports->x11_lib, "XRootWindow");
|
|
((void**)x11_exports)[11] = (void*)dlsym(x11_exports->x11_lib, "XSync");
|
|
((void**)x11_exports)[12] = (void*)dlsym(x11_exports->x11_lib, "XFree");
|
|
((void**)x11_exports)[13] = (void*)dlsym(x11_exports->x11_lib, "XSelectInput");
|
|
((void**)x11_exports)[14] = (void*)dlsym(x11_exports->x11_lib, "XGetWindowAttributes");
|
|
((void**)x11_exports)[15] = (void*)dlsym(x11_exports->x11_lib, "XChangeWindowAttributes");
|
|
((void**)x11_exports)[16] = (void*)dlsym(x11_exports->x11_lib, "XQueryPointer");
|
|
((void**)x11_exports)[17] = (void*)dlsym(x11_exports->x11_lib, "XDisplayKeycodes");
|
|
((void**)x11_exports)[18] = (void*)dlsym(x11_exports->x11_lib, "XGetKeyboardMapping");
|
|
((void**)x11_exports)[19] = (void*)dlsym(x11_exports->x11_lib, "XStringToKeysym");
|
|
((void**)x11_exports)[20] = (void*)dlsym(x11_exports->x11_lib, "XChangeKeyboardMapping");
|
|
|
|
((void**)x11tst_exports)[4] = (void*)x11_exports->XFlush;
|
|
((void**)x11tst_exports)[5] = (void*)x11_exports->XKeysymToKeycode;
|
|
}
|
|
}
|
|
if (xfixes_exports == NULL)
|
|
{
|
|
xfixes_exports = ILibMemory_SmartAllocate(sizeof(xfixes_struct));
|
|
xfixes_exports->xfixes_lib = dlopen(Location_X11FIXES, RTLD_NOW);
|
|
if (xfixes_exports->xfixes_lib)
|
|
{
|
|
((void**)xfixes_exports)[1] = (void*)dlsym(xfixes_exports->xfixes_lib, "XFixesSelectCursorInput");
|
|
((void**)xfixes_exports)[2] = (void*)dlsym(xfixes_exports->xfixes_lib, "XFixesQueryExtension");
|
|
((void**)xfixes_exports)[3] = (void*)dlsym(xfixes_exports->xfixes_lib, "XFixesGetCursorImage");
|
|
((void**)xfixes_exports)[4] = (void*)dlsym(xfixes_exports->xfixes_lib, "XFixesGetCursorImageAndName");
|
|
}
|
|
}
|
|
|
|
|
|
sprintf_s(displayString, sizeof(displayString), ":%d", (int)displayNo);
|
|
|
|
if (count == 10) { return -1; }
|
|
count = 0;
|
|
eventdisplay = x11_exports->XOpenDisplay(displayString);
|
|
if (logFile) { fprintf(logFile, "XAUTHORITY is %s\n", getenv("XAUTHORITY")); fflush(logFile); }
|
|
if (logFile) { fprintf(logFile, "DisplayString is %s\n", displayString); fflush(logFile); }
|
|
|
|
if (eventdisplay == NULL)
|
|
{
|
|
char tmpBuff[1024];
|
|
sprintf_s(tmpBuff, sizeof(tmpBuff), "XOpenDisplay(%s) failed, using XAUTHORITY: %s", displayString, getenv("XAUTHORITY"));
|
|
//fprintf(logFile, "DisplayString=%s\n", displayString);
|
|
//fprintf(logFile, "XAUTHORITY is %s", getenv("XAUTHORITY")); fflush(logFile);
|
|
//fprintf(logFile, "Error calling XOpenDisplay()\n"); fflush(logFile);
|
|
kvm_send_error(tmpBuff);
|
|
}
|
|
|
|
if (eventdisplay != NULL) { current_display = (unsigned short)displayNo; }
|
|
|
|
while (eventdisplay == NULL && count++ < 100)
|
|
{
|
|
if (getNextDisplay() == -1) { return -1; }
|
|
sprintf_s(displayString, sizeof(displayString), ":%d", (int)current_display);
|
|
eventdisplay = x11_exports->XOpenDisplay(displayString);
|
|
}
|
|
|
|
if (count == 100 && eventdisplay == NULL) { return -1; }
|
|
|
|
g_enableEvents = x11_exports->XQueryExtension(eventdisplay, "XTEST", &dummy1, &dummy2, &dummy3)? 1 : 0;
|
|
if (!g_enableEvents) { printf("FATAL::::Fake motion is not supported.\n\n\n"); }
|
|
|
|
SCREEN_NUM = DefaultScreen(eventdisplay);
|
|
SCREEN_HEIGHT = DisplayHeight(eventdisplay, SCREEN_NUM);
|
|
SCREEN_WIDTH = DisplayWidth(eventdisplay, SCREEN_NUM);
|
|
SCREEN_DEPTH = DefaultDepth(eventdisplay, SCREEN_NUM);
|
|
|
|
if (SCREEN_DEPTH < 15) {
|
|
// fprintf(stderr, "kvm_init: We do not support display depth < 15.");
|
|
return -1;
|
|
}
|
|
|
|
// Some magic numbers.
|
|
TILE_WIDTH = 32;
|
|
TILE_HEIGHT = 32;
|
|
COMPRESSION_RATIO = 50;
|
|
FRAME_RATE_TIMER = 100;
|
|
|
|
TILE_HEIGHT_COUNT = SCREEN_HEIGHT / TILE_HEIGHT;
|
|
TILE_WIDTH_COUNT = SCREEN_WIDTH / TILE_WIDTH;
|
|
if (SCREEN_WIDTH % TILE_WIDTH) { TILE_WIDTH_COUNT++; }
|
|
if (SCREEN_HEIGHT % TILE_HEIGHT) { TILE_HEIGHT_COUNT++; }
|
|
|
|
kvm_send_resolution();
|
|
kvm_send_display();
|
|
|
|
reset_tile_info(old_height_count);
|
|
|
|
return 0;
|
|
}
|
|
|
|
void CheckDesktopSwitch(int checkres)
|
|
{
|
|
if (change_display) {
|
|
kvm_init(current_display);
|
|
change_display = 0;
|
|
return;
|
|
}
|
|
}
|
|
|
|
int kvm_server_inputdata(char* block, int blocklen)
|
|
{
|
|
unsigned short type, size;
|
|
CheckDesktopSwitch(0);
|
|
|
|
// Decode the block header
|
|
if (blocklen < 4) return 0;
|
|
type = ntohs(((unsigned short*)(block))[0]);
|
|
size = ntohs(((unsigned short*)(block))[1]);
|
|
if (size > blocklen) return 0;
|
|
|
|
switch (type)
|
|
{
|
|
case MNG_KVM_KEY_UNICODE: // Unicode Key
|
|
if (size != 7) break;
|
|
if (g_enableEvents && block[4] == 0)
|
|
{
|
|
KeyActionUnicode(((((unsigned char)block[5]) << 8) + ((unsigned char)block[6])), block[4], eventdisplay);
|
|
}
|
|
break;
|
|
case MNG_KVM_KEY: // Key
|
|
{
|
|
if (size != 6) break;
|
|
if (g_enableEvents)
|
|
{
|
|
KeyAction(block[5], block[4], eventdisplay);
|
|
}
|
|
break;
|
|
}
|
|
case MNG_KVM_MOUSE: // Mouse
|
|
{
|
|
int x, y;
|
|
short w = 0;
|
|
if (size == 10 || size == 12)
|
|
{
|
|
x = ((int)ntohs(((unsigned short*)(block))[3]));
|
|
y = ((int)ntohs(((unsigned short*)(block))[4]));
|
|
if (size == 12) w = ((short)ntohs(((short*)(block))[5]));
|
|
if (logFile) { fprintf(logFile, "RemoteMouseMove: (%d, %d)\n", x, y); }
|
|
// printf("x:%d, y:%d, b:%d, w:%d\n", x, y, block[5], w);
|
|
if (g_enableEvents)
|
|
{
|
|
remoteMouseX = x, remoteMouseY = y;
|
|
MouseAction(x, y, (int)(unsigned char)(block[5]), w, eventdisplay);
|
|
}
|
|
}
|
|
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
|
|
{
|
|
kvm_send_resolution();
|
|
|
|
int row, col;
|
|
if (size != 4) break;
|
|
if (g_tileInfo == NULL) {
|
|
if ((g_tileInfo = (struct tileInfo_t **) malloc(TILE_HEIGHT_COUNT * sizeof(struct tileInfo_t *))) == NULL) ILIBCRITICALEXIT(254);
|
|
for (row = 0; row < TILE_HEIGHT_COUNT; row++) {
|
|
if ((g_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++) {
|
|
g_tileInfo[row][col].crc = 0xFF;
|
|
g_tileInfo[row][col].flag = 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_GET_DISPLAYS:
|
|
{
|
|
kvm_send_display_list();
|
|
break;
|
|
}
|
|
case MNG_KVM_SET_DISPLAY:
|
|
{
|
|
if (ntohs(((unsigned short*)(block))[2]) == current_display) { break; } // Don't do anything
|
|
current_display = ntohs(((unsigned short*)(block))[2]);
|
|
change_display = 1;
|
|
break;
|
|
}
|
|
}
|
|
return size;
|
|
}
|
|
|
|
|
|
int kvm_relay_feeddata(char* buf, int len)
|
|
{
|
|
ssize_t written = 0;
|
|
|
|
// Write the reply to the pipe.
|
|
//fprintf(logFile, "Writing to slave in kvm_relay_feeddata\n");
|
|
written = write(
|
|
master2slave[1], // handle to pipe
|
|
buf, // buffer to write from
|
|
len);
|
|
fsync(master2slave[1]);
|
|
//fprintf(logFile, "Written %d bytes to slave in kvm_relay_feeddata\n", written);
|
|
|
|
if (written == -1) return 0;
|
|
if (len != (int)written) return written;
|
|
return len;
|
|
}
|
|
|
|
// Set the KVM pause state
|
|
void kvm_pause(int pause)
|
|
{
|
|
g_pause = pause;
|
|
}
|
|
|
|
void kvm_server_jpegerror(char *msg)
|
|
{
|
|
int msgLen = strnlen_s(msg, 255);
|
|
char *buffer = (char*)ILibMemory_SmartAllocate(msgLen + 4);
|
|
|
|
((unsigned short*)buffer)[0] = (unsigned short)htons((unsigned short)MNG_ERROR); // Write the type
|
|
((unsigned short*)buffer)[1] = (unsigned short)htons((unsigned short)(msgLen + 4)); // Write the size
|
|
memcpy_s(buffer + 4, msgLen, msg, msgLen);
|
|
|
|
ignore_result(write(slave2master[1], buffer, ILibMemory_Size(buffer)));
|
|
}
|
|
|
|
#pragma pack(push, 1)
|
|
typedef struct bitmapdata
|
|
{
|
|
int a;
|
|
int r;
|
|
int g;
|
|
int b;
|
|
}bitmapdata;
|
|
|
|
typedef struct bitmapdata2
|
|
{
|
|
unsigned char b;
|
|
unsigned char g;
|
|
unsigned char r;
|
|
unsigned char a;
|
|
}bitmapdata2;
|
|
#pragma pack(pop)
|
|
|
|
void kvm_test_disaplymatrix(char *source, int width, int height)
|
|
{
|
|
int i;
|
|
int row = 0, column = 0;
|
|
for (i = 0; i < (width*height); ++i)
|
|
{
|
|
printf("[%d, %d, %d, %d] ", ((bitmapdata*)source)[i].a, ((bitmapdata*)source)[i].r, ((bitmapdata*)source)[i].g, ((bitmapdata*)source)[i].b);
|
|
if (++column == width)
|
|
{
|
|
column = 0;
|
|
++row;
|
|
printf("\n");
|
|
}
|
|
}
|
|
}
|
|
|
|
int kvm_createrect(char *sourcebitmap, int source_width, int source_height, int rx, int ry, int rw, int rh, char *buffer, int bufferSize)
|
|
{
|
|
int i, len = rh * sizeof(bitmapdata*);
|
|
if (bufferSize < len || buffer == NULL) { return(len); }
|
|
memset(buffer, 0, len);
|
|
|
|
bitmapdata **rows = (bitmapdata**)buffer;
|
|
for (i = ry; (i - ry) < rh; ++i)
|
|
{
|
|
rows[i - ry] = (bitmapdata*)(sourcebitmap + (i*source_width * sizeof(bitmapdata)));
|
|
}
|
|
|
|
bitmapdata **rr = (bitmapdata**)buffer;
|
|
for (i = 0; i < rh; ++i)
|
|
{
|
|
rr[i] = &(rr[i][rx]);
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
int kvm_createrect3(unsigned long *sourcebitmap, int source_width, int source_height, int rx, int ry, int rw, int rh, char *buffer, int bufferSize)
|
|
{
|
|
int i, len = (rw * rh * sizeof(bitmapdata2)) + (rh * sizeof(bitmapdata2*));
|
|
if (bufferSize < len || buffer == NULL) { return(len); }
|
|
memset(buffer, 0, len);
|
|
|
|
bitmapdata2 **ret = (bitmapdata2**)buffer;
|
|
bitmapdata2 *data = (bitmapdata2*)(buffer + (sizeof(bitmapdata2*) * rh));
|
|
|
|
int row = 0, col = 0;
|
|
|
|
for (i = 0; i < rh; ++i)
|
|
{
|
|
ret[i] = (bitmapdata2*)((char*)data + (i * rw * sizeof(bitmapdata2)));
|
|
}
|
|
|
|
for (i = 0; i < source_width*source_height; ++i, ++col)
|
|
{
|
|
if (col >= source_width) { col = 0; ++row; }
|
|
if (row >= ry && row < (ry + rh) &&
|
|
col >= rx && col < (rx + rw))
|
|
{
|
|
ret[row - rx][col - ry].a = (sourcebitmap[i] >> 24) & 0xFF;
|
|
ret[row - rx][col - ry].r = (sourcebitmap[i] >> 16) & 0xFF;
|
|
ret[row - rx][col - ry].g = (sourcebitmap[i] >> 8) & 0xFF;
|
|
ret[row - rx][col - ry].b = (sourcebitmap[i] >> 0) & 0xFF;
|
|
}
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
int kvm_createrect2(char *sourcebitmap, int source_width, int source_height, int rx, int ry, int rw, int rh, char *buffer, int bufferSize)
|
|
{
|
|
int i, len = rh * sizeof(bitmapdata2*);
|
|
if (bufferSize < len || buffer == NULL) { return(len); }
|
|
memset(buffer, 0, len);
|
|
|
|
bitmapdata2 **rows = (bitmapdata2**)buffer;
|
|
|
|
for (i = 0; i < rh; ++i)
|
|
{
|
|
rows[i] = (bitmapdata2*)(sourcebitmap + ((i + ry)*source_width * sizeof(bitmapdata2)) + (rx * sizeof(bitmapdata2)));
|
|
}
|
|
|
|
return(0);
|
|
}
|
|
void bitblt(char *sourcebitmap, int source_width, int source_height, int sx, int sy, int rw, int rh, char *destbitmap, int dest_width, int dest_height, int dx, int dy, int rmode)
|
|
{
|
|
int x, y;
|
|
char *srect, *drect;
|
|
int srectLen = kvm_createrect3((unsigned long*)sourcebitmap, source_width, source_height, sx, sy, rw, rh, NULL, 0);
|
|
int drectLen = kvm_createrect2(destbitmap, dest_width, dest_height, dx, dy, rw, rh, NULL, 0);
|
|
|
|
srect = ILibMemory_SmartAllocate(srectLen);
|
|
drect = ILibMemory_SmartAllocate(drectLen);
|
|
|
|
kvm_createrect3((unsigned long*)sourcebitmap, source_width, source_height, sx, sy, rw, rh, srect, srectLen);
|
|
kvm_createrect2(destbitmap, dest_width, dest_height, dx, dy, rw, rh, drect, drectLen);
|
|
|
|
for (y = 0; y < rh; ++y)
|
|
{
|
|
for (x = 0; x < rw; ++x)
|
|
{
|
|
if (((bitmapdata2**)srect)[y][x].a > 128)
|
|
{
|
|
((bitmapdata2**)drect)[y][x].r = (255 - ((bitmapdata2**)srect)[y][x].r);
|
|
((bitmapdata2**)drect)[y][x].g = (255 - ((bitmapdata2**)srect)[y][x].g);
|
|
((bitmapdata2**)drect)[y][x].b = (255 - ((bitmapdata2**)srect)[y][x].b);
|
|
}
|
|
}
|
|
}
|
|
|
|
ILibMemory_Free(srect);
|
|
ILibMemory_Free(drect);
|
|
}
|
|
|
|
void kvm_server_sighandler(int signum, siginfo_t *info, void *context)
|
|
{
|
|
g_shutdown = 1;
|
|
}
|
|
void* kvm_server_mainloop(void* parm)
|
|
{
|
|
int maxsleep;
|
|
Window rr, cr;
|
|
int rx, ry, wx, wy, rs;
|
|
unsigned int mr;
|
|
char *cimage;
|
|
|
|
int x, y, height, width, r, c, count = 0;
|
|
int sentHideCursor = 0;
|
|
long long desktopsize = 0;
|
|
long long tilesize = 0;
|
|
|
|
void *desktop = NULL;
|
|
XImage *image = NULL;
|
|
eventdisplay = NULL;
|
|
Display *imagedisplay = NULL, *cursordisplay = NULL;
|
|
void *buf = NULL;
|
|
char displayString[256] = "";
|
|
int event_base = 0, error_base = 0, cursor_descriptor = -1;
|
|
int screen_height, screen_width, screen_depth, screen_num;
|
|
ssize_t written;
|
|
XShmSegmentInfo shminfo;
|
|
default_JPEG_error_handler = kvm_server_jpegerror;
|
|
|
|
struct timeval tv;
|
|
fd_set readset;
|
|
fd_set errorset;
|
|
fd_set writeset;
|
|
XEvent XE;
|
|
|
|
if (logFile) { fprintf(logFile, "Checking $DISPLAY\n"); fflush(logFile); }
|
|
for (char **env = environ; *env; ++env)
|
|
{
|
|
int envLen = (int)strnlen_s(*env, INT_MAX);
|
|
int i = ILibString_IndexOf(*env, envLen, "=", 1);
|
|
if (i > 0)
|
|
{
|
|
if (i == 7 && strncmp("DISPLAY", *env, 7) == 0)
|
|
{
|
|
current_display = (unsigned short)atoi(*env + i + 2);
|
|
if (logFile) { fprintf(logFile, "ENV[DISPLAY] = %s\n", *env + i + 2); fflush(logFile); }
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Init the kvm
|
|
//fprintf(logFile, "Before kvm_init.\n"); fflush(logFile);
|
|
if (kvm_init(current_display) != 0) { return (void*)-1; }
|
|
kvm_send_display_list();
|
|
//fprintf(logFile, "After kvm_init.\n"); fflush(logFile);
|
|
|
|
g_shutdown = 0;
|
|
|
|
struct sigaction action;
|
|
memset(&action, 0, sizeof(action));
|
|
action.sa_sigaction = kvm_server_sighandler;
|
|
sigemptyset(&action.sa_mask);
|
|
action.sa_flags = SA_SIGINFO;
|
|
ignore_result(sigaction(SIGTERM, &action, NULL));
|
|
|
|
//pthread_create(&kvmthread, NULL, kvm_mainloopinput, parm);
|
|
//fprintf(logFile, "Created the kvmthread.\n"); fflush(logFile);
|
|
|
|
int ptr = 0;
|
|
int ptr2 = 0;
|
|
int len = 0;
|
|
char pchRequest2[30000];
|
|
ssize_t cbBytesRead = 0;
|
|
kvm_keydata *keydata;
|
|
|
|
while (!g_shutdown)
|
|
{
|
|
for (r = 0; r < TILE_HEIGHT_COUNT; r++)
|
|
{
|
|
for (c = 0; c < TILE_WIDTH_COUNT; c++)
|
|
{
|
|
g_tileInfo[r][c].flag = TILE_TODO;
|
|
#ifdef KVM_ALL_TILES
|
|
g_tileInfo[r][c].crc = 0xFF;
|
|
#endif
|
|
}
|
|
}
|
|
//fprintf(logFile, "Before CheckDesktopSwitch.\n"); fflush(logFile);
|
|
CheckDesktopSwitch(1);
|
|
//fprintf(logFile, "After CheckDesktopSwitch.\n"); fflush(logFile);
|
|
|
|
sprintf_s(displayString, sizeof(displayString), ":%d", (int)current_display);
|
|
imagedisplay = x11_exports->XOpenDisplay(displayString);
|
|
|
|
count = 0;
|
|
|
|
if (imagedisplay == NULL && count++ < 100)
|
|
{
|
|
change_display = 1;
|
|
if (getNextDisplay() == -1) { return (void*)-1; }
|
|
//fprintf(logFile, "Before kvm_init1.\n"); fflush(logFile);
|
|
kvm_init(current_display);
|
|
//fprintf(logFile, "After kvm_init1.\n"); fflush(logFile);
|
|
change_display = 0;
|
|
if (image != NULL) { XDestroyImage(image); image = NULL; }
|
|
continue;
|
|
}
|
|
|
|
if (count == 100 && imagedisplay == NULL) { g_shutdown = 1; break; }
|
|
FD_ZERO(&readset);
|
|
FD_ZERO(&errorset);
|
|
FD_ZERO(&writeset);
|
|
tv.tv_sec = 0;
|
|
tv.tv_usec = 0;
|
|
FD_SET(master2slave[0], &readset);
|
|
if (select(FD_SETSIZE, &readset, &writeset, &errorset, &tv) > 0 && FD_ISSET(master2slave[0], &readset))
|
|
{
|
|
|
|
//fprintf(logFile, "Reading from master in kvm_mainloopinput\n");
|
|
cbBytesRead = read(master2slave[0], pchRequest2 + len, 30000 - len);
|
|
//fprintf(logFile, "Read %d bytes from master in kvm_mainloopinput\n", cbBytesRead);
|
|
if (cbBytesRead == -1 || cbBytesRead == 0 || g_shutdown)
|
|
{
|
|
g_shutdown = 1;
|
|
break;
|
|
}
|
|
len += cbBytesRead;
|
|
ptr2 = 0;
|
|
while ((ptr2 = kvm_server_inputdata((char*)pchRequest2 + ptr, cbBytesRead - ptr)) != 0) { ptr += ptr2; }
|
|
if (ptr == len) { len = 0; ptr = 0; }
|
|
}
|
|
|
|
if (cursordisplay == NULL)
|
|
{
|
|
if ((cursordisplay = x11_exports->XOpenDisplay(displayString)))
|
|
{
|
|
Window rootwin = x11_exports->XRootWindow(cursordisplay, 0);
|
|
if (xfixes_exports->XFixesQueryExtension(cursordisplay, &event_base, &error_base))
|
|
{
|
|
xfixes_exports->XFixesSelectCursorInput(cursordisplay, rootwin, 1); // Register for Cursor Change Notifications
|
|
x11_exports->XSync(cursordisplay, 0); // Sync with XServer
|
|
cursor_descriptor = x11_exports->XConnectionNumber(cursordisplay); // Get the FD to use in select
|
|
}
|
|
|
|
curcursor = kvm_fetch_currentCursor(cursordisplay); // Cursor Type
|
|
}
|
|
}
|
|
else if (cursor_descriptor > 0)
|
|
{
|
|
FD_ZERO(&readset);
|
|
FD_ZERO(&errorset);
|
|
FD_ZERO(&writeset);
|
|
tv.tv_sec = 0;
|
|
tv.tv_usec = 0;
|
|
FD_SET(cursor_descriptor, &readset);
|
|
if (select(FD_SETSIZE, &readset, &writeset, &errorset, &tv) > 0 && FD_ISSET(cursor_descriptor, &readset))
|
|
{
|
|
// We have a waiting event
|
|
while (x11_exports->XPending(cursordisplay))
|
|
{
|
|
x11_exports->XNextEvent(cursordisplay, &XE);
|
|
if (XE.type == (event_base + 1))
|
|
{
|
|
char buffer[8];
|
|
char *name = NULL;
|
|
|
|
if (sizeof(void*) == 8)
|
|
{
|
|
// 64bit
|
|
if (((uint64_t*)((char*)&XE + 64))[0] != 0)
|
|
{
|
|
name = x11_exports->XGetAtomName(cursordisplay, ((Atom*)((char*)&XE + 64))[0]);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// 32bit
|
|
if (((uint32_t*)((char*)&XE + 32))[0] != 0)
|
|
{
|
|
name = x11_exports->XGetAtomName(cursordisplay, ((Atom*)((char*)&XE + 32))[0]);
|
|
}
|
|
}
|
|
|
|
if (name != NULL)
|
|
{
|
|
if (strcmp(name, "bottom_left_corner") == 0 || strcmp(name, "sw-resize") == 0) { curcursor = KVM_MouseCursor_SIZENESW; }
|
|
if (strcmp(name, "bottom_right_corner") == 0 || strcmp(name, "se-resize") == 0) { curcursor = KVM_MouseCursor_SIZENWSE; }
|
|
if (strcmp(name, "bottom_side") == 0) { curcursor = KVM_MouseCursor_SIZENS; }
|
|
if (strcmp(name, "fleur") == 0) { curcursor = KVM_MouseCursor_SIZEALL; }
|
|
if (strcmp(name, "hand1") == 0 || strcmp(name, "pointer")==0) { curcursor = KVM_MouseCursor_HAND; }
|
|
if (strcmp(name, "hand2") == 0) { curcursor = KVM_MouseCursor_HAND; }
|
|
if (strcmp(name, "left_ptr") == 0) { curcursor = KVM_MouseCursor_ARROW; }
|
|
if (strcmp(name, "left_side") == 0 || strcmp(name, "w-resize") == 0 || strcmp(name, "e-resize") == 0) { curcursor = KVM_MouseCursor_SIZEWE; }
|
|
if (strcmp(name, "right_side") == 0) { curcursor = KVM_MouseCursor_SIZEWE; }
|
|
if (strcmp(name, "top_left_corner") == 0 || strcmp(name, "nw-resize") == 0) { curcursor = KVM_MouseCursor_SIZENWSE; }
|
|
if (strcmp(name, "top_right_corner") == 0 || strcmp(name, "ne-resize") == 0) { curcursor = KVM_MouseCursor_SIZENESW; }
|
|
if (strcmp(name, "top_side") == 0) { curcursor = KVM_MouseCursor_SIZENS; }
|
|
if (strcmp(name, "watch") == 0) { curcursor = KVM_MouseCursor_WAIT; }
|
|
if (strcmp(name, "top_side") == 0 || strcmp(name, "n-resize") == 0 || strcmp(name, "s-resize") == 0) { curcursor = KVM_MouseCursor_SIZENS; }
|
|
if (strcmp(name, "xterm") == 0 || strcmp(name, "ibeam") == 0 || strcmp(name, "text") == 0) { curcursor = KVM_MouseCursor_IBEAM; }
|
|
x11_exports->XFree(name);
|
|
}
|
|
else
|
|
{
|
|
// Name was NULL, so as a last ditch effort, lets try to look at the XFixesCursorImage
|
|
curcursor = kvm_fetch_currentCursor(cursordisplay);
|
|
}
|
|
|
|
if (sentHideCursor == 0)
|
|
{
|
|
((unsigned short*)buffer)[0] = (unsigned short)htons((unsigned short)MNG_KVM_MOUSE_CURSOR); // Write the type
|
|
((unsigned short*)buffer)[1] = (unsigned short)htons((unsigned short)5); // Write the size
|
|
buffer[4] = (char)curcursor; // Cursor Type
|
|
written = write(slave2master[1], buffer, 5);
|
|
fsync(slave2master[1]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
screen_num = DefaultScreen(imagedisplay);
|
|
screen_height = DisplayHeight(imagedisplay, screen_num);
|
|
screen_width = DisplayWidth(imagedisplay, screen_num);
|
|
screen_depth = DefaultDepth(imagedisplay, screen_num);
|
|
|
|
if (screen_depth <= 15) {
|
|
//fprintf(logFile, "We do not support display depth %d < 15.\n", screen_depth); fflush(logFile);
|
|
//fprintf(stderr, "We do not support display depth <= 15.");
|
|
break;
|
|
}
|
|
|
|
if ((SCREEN_HEIGHT != screen_height || SCREEN_WIDTH != screen_width || SCREEN_DEPTH != screen_depth || SCREEN_NUM != screen_num))
|
|
{
|
|
kvm_init(current_display);
|
|
if (image != NULL) { XDestroyImage(image); image = NULL; }
|
|
continue;
|
|
}
|
|
|
|
|
|
image = x11ext_exports->XShmCreateImage(imagedisplay,
|
|
DefaultVisual(imagedisplay, screen_num), // Use a correct visual. Omitted for brevity
|
|
screen_depth,
|
|
ZPixmap, NULL, &shminfo, screen_width, screen_height);
|
|
shminfo.shmid = shmget(IPC_PRIVATE,
|
|
image->bytes_per_line * image->height,
|
|
IPC_CREAT | 0777);
|
|
shminfo.shmaddr = image->data = shmat(shminfo.shmid, 0, 0);
|
|
shminfo.readOnly = False;
|
|
x11ext_exports->XShmAttach(imagedisplay, &shminfo);
|
|
|
|
x11ext_exports->XShmGetImage(imagedisplay,
|
|
RootWindowOfScreen(DefaultScreenOfDisplay(imagedisplay)),
|
|
image,
|
|
0,
|
|
0,
|
|
AllPlanes);
|
|
|
|
//image = XGetImage(imagedisplay,
|
|
// RootWindowOfScreen(DefaultScreenOfDisplay(imagedisplay))
|
|
// , 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, AllPlanes, ZPixmap);
|
|
|
|
|
|
if (image == NULL) {
|
|
g_shutdown = 1;
|
|
}
|
|
else
|
|
{
|
|
rs = x11_exports->XQueryPointer(imagedisplay, RootWindowOfScreen(DefaultScreenOfDisplay(imagedisplay)),
|
|
&rr, &cr, &rx, &ry, &wx, &wy, &mr);
|
|
if (rs == 1 && cursordisplay != NULL)
|
|
{
|
|
if (gRemoteMouseRenderDefault != 0 || (remoteMouseX != rx && remoteMouseY != ry))
|
|
{
|
|
cimage = (char*)xfixes_exports->XFixesGetCursorImage(cursordisplay);
|
|
unsigned short w = ((unsigned short*)(cimage + 4))[0];
|
|
unsigned short h = ((unsigned short*)(cimage + 6))[0];
|
|
unsigned short xhot = ((unsigned short*)(cimage + 8))[0];
|
|
unsigned short yhot = ((unsigned short*)(cimage + 10))[0];
|
|
unsigned short mx = rx - xhot, my = ry - yhot;
|
|
char *pixels = cimage + (sizeof(void*) == 8 ? 24 : 16);
|
|
|
|
//if (logFile) { fprintf(logFile, "BBP: %d, pad: %d, unit: %d, BPP: %d, F: %d, XO: %d: PW: %d\n", image->bytes_per_line, image->bitmap_pad, image->bitmap_unit, image->bits_per_pixel, image->format, image->xoffset, (adjust_screen_size(SCREEN_WIDTH) - image->width) * 3); fflush(logFile); }
|
|
//if (logFile) { fprintf(logFile, "[%d/ %d x %d] (%d, %d) => (%d, %d | %u, %u)\n", image->bits_per_pixel, xa.width, xa.height, screen_width, screen_height, rx, ry,w , h); fflush(logFile); }
|
|
|
|
if (xhot > rx) { mx = 0; } else if ((mx + w) > screen_width) { mx = screen_width - w; }
|
|
if (yhot > ry) { my = 0; } else if ((my + h) > screen_height) { my = screen_height - h; }
|
|
|
|
bitblt(pixels, (int)w, (int)h, 0, 0, (int)w, (int)h, image->data, screen_width, screen_height, mx, my, 1);
|
|
|
|
if (sentHideCursor == 0)
|
|
{
|
|
char tmpbuffer[8];
|
|
sentHideCursor = 1;
|
|
((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
|
|
written = write(slave2master[1], tmpbuffer, 5);
|
|
fsync(slave2master[1]);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (sentHideCursor != 0)
|
|
{
|
|
char tmpbuffer[8];
|
|
sentHideCursor = 1;
|
|
((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)curcursor; // Cursor Type
|
|
written = write(slave2master[1], tmpbuffer, 5);
|
|
fsync(slave2master[1]);
|
|
}
|
|
sentHideCursor = 0;
|
|
}
|
|
}
|
|
getScreenBuffer((char **)&desktop, &desktopsize, image);
|
|
|
|
for (y = 0; y < TILE_HEIGHT_COUNT; y++) {
|
|
for (x = 0; x < TILE_WIDTH_COUNT; x++) {
|
|
height = TILE_HEIGHT * y;
|
|
width = TILE_WIDTH * x;
|
|
|
|
if (g_shutdown) { x = TILE_WIDTH_COUNT; y = TILE_HEIGHT_COUNT; break; }
|
|
|
|
if (g_tileInfo[y][x].flag == TILE_SENT || g_tileInfo[y][x].flag == TILE_DONT_SEND) {
|
|
continue;
|
|
}
|
|
|
|
getTileAt(width, height, &buf, &tilesize, desktop, desktopsize, y, x);
|
|
|
|
if (buf && !g_shutdown)
|
|
{
|
|
// Write the reply to the pipe.
|
|
//fprintf(logFile, "Writing to master in kvm_server_mainloop\n");
|
|
written = write(slave2master[1], buf, tilesize);
|
|
fsync(slave2master[1]);
|
|
//fprintf(logFile, "Wrote %d bytes to master in kvm_server_mainloop\n", written);
|
|
free(buf);
|
|
if (written == -1) { /*ILIBMESSAGE("KVMBREAK-K2\r\n");*/ g_shutdown = 1; height = SCREEN_HEIGHT; width = SCREEN_WIDTH; break; }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
x11ext_exports->XShmDetach(imagedisplay, &shminfo);
|
|
XDestroyImage(image); image = NULL;
|
|
shmdt(shminfo.shmaddr);
|
|
shmctl(shminfo.shmid, IPC_RMID, 0);
|
|
|
|
if (imagedisplay != NULL)
|
|
{
|
|
x11_exports->XCloseDisplay(imagedisplay);
|
|
imagedisplay = NULL;
|
|
}
|
|
|
|
// 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;
|
|
maxsleep = 50000;
|
|
}
|
|
else
|
|
{
|
|
maxsleep = height * 1000;
|
|
height = 0;
|
|
}
|
|
|
|
usleep(maxsleep);
|
|
}
|
|
}
|
|
|
|
close(slave2master[1]);
|
|
close(master2slave[0]);
|
|
slave2master[1] = 0;
|
|
master2slave[0] = 0;
|
|
|
|
KeyActionUnicode_UNMAP_ALL(eventdisplay);
|
|
x11_exports->XCloseDisplay(eventdisplay);
|
|
eventdisplay = NULL;
|
|
|
|
if (cursordisplay != NULL)
|
|
{
|
|
x11_exports->XCloseDisplay(cursordisplay);
|
|
cursordisplay = NULL;
|
|
}
|
|
|
|
if (g_tileInfo != NULL)
|
|
{
|
|
for (r = 0; r < TILE_HEIGHT_COUNT; r++) { free(g_tileInfo[r]); }
|
|
free(g_tileInfo);
|
|
g_tileInfo = NULL;
|
|
}
|
|
if(tilebuffer != NULL) { free(tilebuffer); tilebuffer = NULL; }
|
|
return (void*)0;
|
|
}
|
|
|
|
void kvm_relay_readSink(ILibProcessPipe_Pipe sender, char *buffer, size_t bufferLen, size_t* bytesConsumed)
|
|
{
|
|
ILibKVM_WriteHandler writeHandler = (ILibKVM_WriteHandler)((void**)ILibMemory_Extra(sender))[0];
|
|
void *reserved = ((void**)ILibMemory_Extra(sender))[1];
|
|
unsigned short size;
|
|
|
|
if (bufferLen > 4)
|
|
{
|
|
if (ntohs(((unsigned short*)(buffer))[0]) == (unsigned short)MNG_JUMBO)
|
|
{
|
|
if (bufferLen > 8)
|
|
{
|
|
if (bufferLen >= (8 + (int)ntohl(((unsigned int*)(buffer))[1])))
|
|
{
|
|
*bytesConsumed = 8 + (int)ntohl(((unsigned int*)(buffer))[1]);
|
|
writeHandler(buffer, *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_brokenPipeSink(ILibProcessPipe_Pipe sender)
|
|
{
|
|
ILibKVM_WriteHandler writeHandler = (ILibKVM_WriteHandler)((void**)ILibMemory_Extra(sender))[0];
|
|
void *reserved = ((void**)ILibMemory_Extra(sender))[1];
|
|
|
|
char msg[] = "KVM Child process has unexpectedly exited";
|
|
char buffer[4096];
|
|
|
|
((unsigned short*)buffer)[0] = (unsigned short)htons((unsigned short)MNG_ERROR); // Write the type
|
|
((unsigned short*)buffer)[1] = (unsigned short)htons((unsigned short)(sizeof(msg) + 3));// Write the size
|
|
memcpy_s(buffer + 4, sizeof(msg)-1, msg, sizeof(msg)-1);
|
|
|
|
writeHandler(buffer, sizeof(msg) + 3, reserved);
|
|
|
|
}
|
|
|
|
void* kvm_relay_restart(int paused, void *processPipeMgr, ILibKVM_WriteHandler writeHandler, void *reserved, int uid, char* authToken, char *dispid)
|
|
{
|
|
int r;
|
|
int count = 0;
|
|
ILibProcessPipe_Pipe slave_out;
|
|
|
|
if (g_slavekvm != 0)
|
|
{
|
|
kill(g_slavekvm, SIGKILL);
|
|
waitpid(g_slavekvm, &r, 0);
|
|
g_slavekvm = 0;
|
|
}
|
|
|
|
r = pipe(slave2master);
|
|
r = pipe(master2slave);
|
|
|
|
// Two Phase is ok here, because all our fork/vfork calls always happen on the same thread
|
|
fcntl(slave2master[0], F_SETFD, FD_CLOEXEC);
|
|
fcntl(slave2master[1], F_SETFD, FD_CLOEXEC);
|
|
fcntl(master2slave[0], F_SETFD, FD_CLOEXEC);
|
|
fcntl(master2slave[1], F_SETFD, FD_CLOEXEC);
|
|
|
|
slave_out = ILibProcessPipe_Pipe_CreateFromExistingWithExtraMemory(processPipeMgr, slave2master[0], 2 * sizeof(void*));
|
|
((void**)ILibMemory_Extra(slave_out))[0] = writeHandler;
|
|
((void**)ILibMemory_Extra(slave_out))[1] = reserved;
|
|
|
|
UNREFERENCED_PARAMETER(r);
|
|
do
|
|
{
|
|
g_slavekvm = fork();
|
|
if (g_slavekvm == -1 && paused == 0) sleep(2); // If we can't launch the child process, retry in a little while.
|
|
}
|
|
while (g_slavekvm == -1 && paused == 0 && ++count < 10);
|
|
if (g_slavekvm == -1) return(NULL);
|
|
|
|
if (g_slavekvm == 0) //slave
|
|
{
|
|
close(slave2master[0]);
|
|
close(master2slave[1]);
|
|
|
|
if (SLAVELOG != 0) { logFile = fopen("/tmp/slave", "w"); }
|
|
if (uid != 0) { ignore_result(setuid(uid)); }
|
|
|
|
if (g_ILibCrashDump_path != NULL)
|
|
{
|
|
#if !defined(_FREEBSD)
|
|
prctl(PR_SET_DUMPABLE, 1);
|
|
if (logFile) { fprintf(logFile, "SLAVE/KVM DUMPABLE: %s\n", prctl(PR_GET_DUMPABLE, 0)?"YES":"NO"); fflush(logFile); }
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
if (logFile) { fprintf(logFile, "SLAVE/KVM CoreDumps DISABLED\n"); fflush(logFile); }
|
|
}
|
|
|
|
|
|
//fprintf(logFile, "Starting kvm_server_mainloop\n");
|
|
if (authToken != NULL) { setenv("XAUTHORITY", authToken, 1); }
|
|
if (dispid != NULL) { setenv("DISPLAY", dispid, 1); }
|
|
|
|
kvm_server_mainloop((void*)0);
|
|
exit(0);
|
|
return(NULL);
|
|
}
|
|
else
|
|
{ //master
|
|
close(slave2master[1]);
|
|
close(master2slave[0]);
|
|
logFile = fopen("/tmp/master", "w");
|
|
char tmp[255];
|
|
sprintf_s(tmp, sizeof(tmp), "Child KVM (pid=%d)", g_slavekvm);
|
|
|
|
// We will asyncronously read from the pipe, so we can just return
|
|
ILibProcessPipe_Pipe_AddPipeReadHandler(slave_out, 65535, kvm_relay_readSink);
|
|
ILibProcessPipe_Pipe_SetBrokenPipeHandler(slave_out, kvm_relay_brokenPipeSink);
|
|
ILibProcessPipe_Pipe_ResetMetadata(slave_out, tmp);
|
|
return(slave_out);
|
|
}
|
|
}
|
|
|
|
|
|
// Setup the KVM session. Return 1 if ok, 0 if it could not be setup.
|
|
void* kvm_relay_setup(void *processPipeMgr, ILibKVM_WriteHandler writeHandler, void *reserved, int uid, char *authToken, char *dispid)
|
|
{
|
|
if (kvmthread != (pthread_t)NULL || g_slavekvm != 0) return 0;
|
|
g_restartcount = 0;
|
|
return kvm_relay_restart(1, processPipeMgr, writeHandler, reserved, uid, authToken, dispid);
|
|
}
|
|
|
|
// Force a KVM reset & refresh
|
|
void kvm_relay_reset()
|
|
{
|
|
char buffer[4];
|
|
((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);
|
|
}
|
|
|
|
// Clean up the KVM session.
|
|
void kvm_cleanup()
|
|
{
|
|
int code;
|
|
g_shutdown = 1;
|
|
|
|
if (master2slave[1] != 0 && g_slavekvm != 0)
|
|
{
|
|
kill(g_slavekvm, SIGTERM);
|
|
waitpid(g_slavekvm, &code, 0);
|
|
g_slavekvm = 0;
|
|
}
|
|
g_totalRestartCount = 0;
|
|
}
|