mirror of
https://github.com/Ylianst/MeshAgent
synced 2025-12-10 13:23:41 +00:00
1054 lines
34 KiB
C
1054 lines
34 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 <sys/ipc.h>
|
|
#include <sys/shm.h>
|
|
#include <X11/extensions/XShm.h>
|
|
#include <X11/keysym.h>
|
|
#include <dlfcn.h>
|
|
|
|
#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);
|
|
|
|
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_MouseCursors;
|
|
|
|
|
|
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;
|
|
|
|
ILibQueue g_messageQ;
|
|
|
|
extern void* tilebuffer;
|
|
extern char **environ;
|
|
|
|
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);
|
|
}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);
|
|
}xfixes_struct;
|
|
xfixes_struct *xfixes_exports = NULL;
|
|
|
|
|
|
void kvm_send_error(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);
|
|
|
|
ILibQueue_Lock(g_messageQ);
|
|
ILibQueue_EnQueue(g_messageQ, buffer);
|
|
ILibQueue_UnLock(g_messageQ);
|
|
}
|
|
|
|
void kvm_send_resolution()
|
|
{
|
|
char *buffer = (char*)ILibMemory_SmartAllocate(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
|
|
|
|
ILibQueue_Lock(g_messageQ);
|
|
ILibQueue_EnQueue(g_messageQ, buffer);
|
|
ILibQueue_UnLock(g_messageQ);
|
|
}
|
|
|
|
void kvm_send_display()
|
|
{
|
|
char* buffer = (char*)ILibMemory_SmartAllocate(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
|
|
|
|
ILibQueue_Lock(g_messageQ);
|
|
ILibQueue_EnQueue(g_messageQ, buffer);
|
|
ILibQueue_UnLock(g_messageQ);
|
|
}
|
|
|
|
#define BUFSIZE 65535
|
|
|
|
int kvm_server_inputdata(char* block, int blocklen);
|
|
void* kvm_mainloopinput(void* parm)
|
|
{
|
|
int ptr = 0;
|
|
int ptr2 = 0;
|
|
int len = 0;
|
|
char* pchRequest2[30000];
|
|
ssize_t cbBytesRead = 0;
|
|
|
|
while (!g_shutdown)
|
|
{
|
|
//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) { /*ILIBMESSAGE("KVMBREAK-K1\r\n");*/ 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; }
|
|
// TODO: else move the reminder.
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
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
|
|
|
|
ILibQueue_Lock(g_messageQ);
|
|
ILibQueue_EnQueue(g_messageQ, buffer);
|
|
ILibQueue_UnLock(g_messageQ);
|
|
}
|
|
|
|
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 (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**)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");
|
|
}
|
|
}
|
|
|
|
|
|
sprintf(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(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: // 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]));
|
|
// printf("x:%d, y:%d, b:%d, w:%d\n", x, y, block[5], w);
|
|
if (g_enableEvents) 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);
|
|
|
|
ILibQueue_Lock(g_messageQ);
|
|
ILibQueue_EnQueue(g_messageQ, buffer);
|
|
ILibQueue_UnLock(g_messageQ);
|
|
}
|
|
|
|
void* kvm_server_mainloop(void* parm)
|
|
{
|
|
int x, y, height, width, r, c, count = 0;
|
|
long long desktopsize = 0;
|
|
long long tilesize = 0;
|
|
//long long prev_timestamp = 0;
|
|
//long long cur_timestamp = 0;
|
|
//long long time_diff = 50;
|
|
//struct timeb tp;
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
|
|
g_messageQ = ILibQueue_Create();
|
|
|
|
// 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;
|
|
pthread_create(&kvmthread, NULL, kvm_mainloopinput, parm);
|
|
//fprintf(logFile, "Created the kvmthread.\n"); fflush(logFile);
|
|
|
|
while (!g_shutdown)
|
|
{
|
|
// Check if there are pending messages to be sent
|
|
ILibQueue_Lock(g_messageQ);
|
|
while (ILibQueue_IsEmpty(g_messageQ) == 0)
|
|
{
|
|
if ((buf = (char*)ILibQueue_DeQueue(g_messageQ)) != NULL)
|
|
{
|
|
written = write(slave2master[1], buf, ILibMemory_Size(buf));
|
|
fsync(slave2master[1]);
|
|
ILibMemory_Free(buf);
|
|
}
|
|
}
|
|
ILibQueue_UnLock(g_messageQ);
|
|
|
|
for (r = 0; r < TILE_HEIGHT_COUNT; r++) {
|
|
for (c = 0; c < TILE_WIDTH_COUNT; c++) {
|
|
g_tileInfo[r][c].flag = TILE_TODO;
|
|
}
|
|
}
|
|
//fprintf(logFile, "Before CheckDesktopSwitch.\n"); fflush(logFile);
|
|
CheckDesktopSwitch(1);
|
|
//fprintf(logFile, "After CheckDesktopSwitch.\n"); fflush(logFile);
|
|
|
|
sprintf(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; }
|
|
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
|
|
}
|
|
}
|
|
}
|
|
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;
|
|
int curcursor = KVM_MouseCursor_HELP;
|
|
|
|
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
|
|
char *cursor_image = (char*)xfixes_exports->XFixesGetCursorImage(cursordisplay);
|
|
if (sizeof(void*) == 8)
|
|
{
|
|
unsigned short w = ((unsigned short*)(cursor_image + 4))[0];
|
|
unsigned short h = ((unsigned short*)(cursor_image + 6))[0];
|
|
char *pixels = cursor_image + 24;
|
|
char alpha[65535];
|
|
int i;
|
|
|
|
if ((size_t)(w*h) <= sizeof(alpha))
|
|
{
|
|
for (i = 0; i < (w*h); ++i)
|
|
{
|
|
alpha[i] = pixels[7 + (i * 8)];
|
|
}
|
|
switch (crc32c(0, (unsigned char*)alpha, (uint32_t)(w*h)))
|
|
{
|
|
case 680869104: // FreeBSD
|
|
case 503303936: // openSUSE
|
|
curcursor = KVM_MouseCursor_SIZENS;
|
|
break;
|
|
case 1094213267: // FreeBSD
|
|
case 723082922: // openSUSE
|
|
curcursor = KVM_MouseCursor_SIZEWE;
|
|
break;
|
|
case 318345513: // FreeBSD (Bottom Left)
|
|
case 69513426: // FreeBSD (Upper Right)
|
|
case 152373933: // openSUSE
|
|
curcursor = KVM_MouseCursor_SIZENESW;
|
|
break;
|
|
case (uint32_t)-1187377452: // FreeBSD (Bottom Right)
|
|
case (uint32_t)-600127498: // FreeBSD (Upper Left)
|
|
case (uint32_t)-2000746020: // openSUSE
|
|
curcursor = KVM_MouseCursor_SIZENWSE;
|
|
break;
|
|
case 733076101: // FreeBSD
|
|
case 261159321: // openSUSE
|
|
curcursor = KVM_MouseCursor_SIZEALL;
|
|
break;
|
|
case 728953462: // FreeBSD
|
|
case 310104114: // openSUSE
|
|
curcursor = KVM_MouseCursor_ARROW;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
((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 {
|
|
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; usleep(50000); } else { usleep(height * 1000); height = 0; } }
|
|
}
|
|
|
|
close(slave2master[1]);
|
|
close(master2slave[0]);
|
|
slave2master[1] = 0;
|
|
master2slave[0] = 0;
|
|
|
|
x11_exports->XCloseDisplay(eventdisplay);
|
|
eventdisplay = NULL;
|
|
|
|
if (cursordisplay != NULL)
|
|
{
|
|
x11_exports->XCloseDisplay(cursordisplay);
|
|
cursordisplay = NULL;
|
|
}
|
|
|
|
pthread_join(kvmthread, NULL);
|
|
kvmthread = (pthread_t)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; }
|
|
ILibQueue_Destroy(g_messageQ);
|
|
return (void*)0;
|
|
}
|
|
|
|
void kvm_relay_readSink(ILibProcessPipe_Pipe sender, char *buffer, int bufferLen, int* bytesConsumed)
|
|
{
|
|
ILibKVM_WriteHandler writeHandler = (ILibKVM_WriteHandler)((void**)ILibMemory_Extra(sender))[0];
|
|
void *reserved = ((void**)ILibMemory_Extra(sender))[1];
|
|
unsigned short size;
|
|
|
|
if (bufferLen > 4)
|
|
{
|
|
size = ntohs(((unsigned short*)(buffer))[1]);
|
|
if (size <= bufferLen)
|
|
{
|
|
//printf("KVM Data: %u bytes\n", size);
|
|
*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)); }
|
|
|
|
//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);
|
|
return(NULL);
|
|
}
|
|
else
|
|
{ //master
|
|
close(slave2master[1]);
|
|
close(master2slave[0]);
|
|
logFile = fopen("/tmp/master", "w");
|
|
|
|
// 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);
|
|
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, SIGKILL);
|
|
waitpid(g_slavekvm, &code, 0);
|
|
g_slavekvm = 0;
|
|
}
|
|
g_totalRestartCount = 0;
|
|
}
|