diff options
Diffstat (limited to 'x11vnc/x11vnc.c')
-rw-r--r-- | x11vnc/x11vnc.c | 362 |
1 files changed, 283 insertions, 79 deletions
diff --git a/x11vnc/x11vnc.c b/x11vnc/x11vnc.c index 6fe5f65..69a8eb2 100644 --- a/x11vnc/x11vnc.c +++ b/x11vnc/x11vnc.c @@ -35,9 +35,8 @@ * To increase portability it is written in plain C. * * The next goal is to improve performance and interactive response. - * The algorithm currently used here to achieve this is that of krfb - * (based on x0rfbserver algorithm). Additional heuristics are also - * applied (currently there are a bit too many of these...) + * The algorithm of x0rfbserver was used as a base. Additional heuristics + * are also applied (currently there are a bit too many of these...) * * To build: * @@ -79,14 +78,15 @@ * is attempted to be followed, but may become out of date. Use the * -flashcmap option to have colormap flashing as the pointer moves * windows with private colormaps (slow). Displays with mixed depth 8 and - * 24 visuals will incorrect display the non-default one. + * 24 visuals will incorrectly display windows using the non-default one. * * Feature -id <windowid> can be picky: it can crash for things like the * window not sufficiently mapped into server memory, use of -mouse, etc. * SaveUnders menus, popups, etc will not be seen. * * Occasionally, a few tile updates can be missed leaving a patch of - * color that needs to be refreshed. + * color that needs to be refreshed. This may only be when threaded, + * which is no longer the default. * * There seems to be a serious bug with simultaneous clients when * threaded, currently the only workaround in this case is -nothreads. @@ -94,10 +94,11 @@ */ /* - * These ' -- filename -- ' comments represent a partial cleanup: they - * are an odd way to indicate how this huge file could be split up someday - * into multiple files. Externs and other things would need to be done, - * but it indicates the breakup, including static keyword for local items. + * These ' -- filename -- ' comments represent a partial cleanup: + * they are an odd way to indicate how this huge file would be split up + * someday into multiple files. Not finished, externs and other things + * would need to be done, but it indicates the breakup, including static + * keyword for local items. * * The primary reason we do not break up this file is for user * convenience: those wanting to use the latest version download a single @@ -131,6 +132,15 @@ #include <X11/XKBlib.h> #endif +#ifdef LIBVNCSERVER_HAVE_SYS_SOCKET_H +#include <sys/socket.h> +#endif +#ifdef LIBVNCSERVER_HAVE_NETINET_IN_H +#include <netinet/in.h> +#include <netinet/tcp.h> +#include <arpa/inet.h> +#endif + /* * Temporary kludge: to run with -xinerama define the following * macro (uncomment) and be sure to link with -lXinerama @@ -146,7 +156,7 @@ #endif /* date +'"lastmod: %Y-%m-%d";' */ -char lastmod[] = "lastmod: 2004-06-05"; +char lastmod[] = "lastmod: 2004-06-11"; /* X display info */ Display *dpy = 0; @@ -188,7 +198,7 @@ typedef struct bout { int x1, y1, x2, y2; } blackout_t; typedef struct tbout { - blackout_t bo[10]; /* hardwired max rectangles. */ + blackout_t bo[16]; /* hardwired max rectangles. */ int cover; int count; } tile_blackout_t; @@ -211,38 +221,21 @@ int got_user_input = 0; int got_pointer_input = 0; int got_keyboard_input = 0; int fb_copy_in_progress = 0; +int shut_down = 0; /* string for the VNC_CONNECT property */ #define VNC_CONNECT_MAX 512 char vnc_connect_str[VNC_CONNECT_MAX+1]; Atom vnc_connect_prop = None; -/* XXX usleep(3) is not thread safe on some older systems... */ -struct timeval _mysleep; -#define usleep2(x) \ - _mysleep.tv_sec = (x) / 1000000; \ - _mysleep.tv_usec = (x) % 1000000; \ - select(0, NULL, NULL, NULL, &_mysleep); -#if !defined(X11VNC_USLEEP) -#undef usleep -#define usleep usleep2 -#endif - -/* - * Not sure why... but when threaded we have to mutex our X11 calls to - * avoid XIO crashes. - */ -MUTEX(x11Mutex); -#define X_LOCK LOCK(x11Mutex) -#define X_UNLOCK UNLOCK(x11Mutex) -#define X_INIT INIT_MUTEX(x11Mutex) - -/* function prototypes */ +/* function prototypes (see filename comment above) */ int all_clients_initialized(void); void blackout_tiles(void); void check_connect_inputs(void); void clean_up_exit(int); +void clear_modifiers(int init); +void clear_keys(void); void copy_screen(void); double dtime(double *); @@ -310,6 +303,7 @@ int flash_cmap = 0; /* follow installed colormaps */ int force_indexed_color = 0; /* whether to force indexed color for 8bpp */ int use_modifier_tweak = 0; /* use the altgr_keyboard modifier tweak */ +int clear_mods = 0; /* -clear_mods (1) and -clear_keys (2) */ int nofb = 0; /* do not send any fb updates */ int subwin = 0; /* -id */ @@ -386,12 +380,44 @@ int got_nevershared = 0; #endif +/* -- util.h -- */ + + +/* XXX usleep(3) is not thread safe on some older systems... */ +struct timeval _mysleep; +#define usleep2(x) \ + _mysleep.tv_sec = (x) / 1000000; \ + _mysleep.tv_usec = (x) % 1000000; \ + select(0, NULL, NULL, NULL, &_mysleep); +#if !defined(X11VNC_USLEEP) +#undef usleep +#define usleep usleep2 +#endif + +/* + * following is based on IsModifierKey in Xutil.h +*/ +#define ismodkey(keysym) \ + ((((KeySym)(keysym) >= XK_Shift_L) && ((KeySym)(keysym) <= XK_Hyper_R) && \ + ((KeySym)(keysym) != XK_Caps_Lock) && ((KeySym)(keysym) != XK_Shift_Lock))) + +/* + * Not sure why... but when threaded we have to mutex our X11 calls to + * avoid XIO crashes. + */ +MUTEX(x11Mutex); +#define X_LOCK LOCK(x11Mutex) +#define X_UNLOCK UNLOCK(x11Mutex) +#define X_INIT INIT_MUTEX(x11Mutex) + + /* -- cleanup.c -- */ /* * Exiting and error handling routines */ static int exit_flag = 0; +int exit_sig = 0; /* * Normal exiting @@ -411,8 +437,14 @@ void clean_up_exit (int ret) { } } + if (clear_mods == 1) { + clear_modifiers(0); + } else if (clear_mods == 2) { + clear_keys(); + } X_LOCK; XTestDiscard(dpy); + XCloseDisplay(dpy); X_UNLOCK; fflush(stderr); @@ -424,6 +456,7 @@ void clean_up_exit (int ret) { */ static void interrupted (int sig) { int i; + exit_sig = sig; if (exit_flag) { exit_flag++; if (use_threads) { @@ -439,6 +472,10 @@ static void interrupted (int sig) { } else { fprintf(stderr, "caught signal: %d\n", sig); } + if (sig == SIGINT) { + shut_down = 1; + return; + } /* * to avoid deadlock, etc, just delete the shm areas and * leave the X stuff hanging. @@ -457,6 +494,11 @@ static void interrupted (int sig) { break; } } + if (clear_mods == 1) { + clear_modifiers(0); + } else if (clear_mods == 2) { + clear_keys(); + } if (sig) { exit(2); } @@ -543,11 +585,15 @@ static int run_user_command(char *cmd, rfbClientPtr client) { static char env_rfb_client_id[100]; static char env_rfb_client_ip[100]; static char env_rfb_client_port[100]; + static char env_rfb_server_ip[100]; + static char env_rfb_server_port[100]; static char env_rfb_x11vnc_pid[100]; static char env_rfb_client_count[100]; char *addr = client->host; - int rc, fromlen, fromport; - struct sockaddr_in from; + int rc; + char *saddr_ip_str = NULL; + int saddr_len, saddr_port; + struct sockaddr_in saddr; if (addr == NULL || addr[0] == '\0') { addr = "unknown-host"; @@ -566,16 +612,38 @@ static int run_user_command(char *cmd, rfbClientPtr client) { putenv(env_rfb_x11vnc_pid); /* set RFB_CLIENT_PORT to peer port for command to use */ - fromlen = sizeof(from); - memset(&from, 0, sizeof(from)); - fromport = -1; - if (!getpeername(client->sock, (struct sockaddr *)&from, &fromlen)) { - fromport = ntohs(from.sin_port); + saddr_len = sizeof(saddr); + memset(&saddr, 0, sizeof(saddr)); + saddr_port = -1; + if (!getpeername(client->sock, (struct sockaddr *)&saddr, &saddr_len)) { + saddr_port = ntohs(saddr.sin_port); } - sprintf(env_rfb_client_port, "RFB_CLIENT_PORT=%d", fromport); + sprintf(env_rfb_client_port, "RFB_CLIENT_PORT=%d", saddr_port); putenv(env_rfb_client_port); /* + * now do RFB_SERVER_IP and RFB_SERVER_PORT (i.e. us!) + * This will establish a 5-tuple (including tcp) the external + * program can potentially use to work out the virtual circuit + * for this connection. + */ + saddr_len = sizeof(saddr); + memset(&saddr, 0, sizeof(saddr)); + saddr_port = -1; + saddr_ip_str = "unknown"; + if (!getsockname(client->sock, (struct sockaddr *)&saddr, &saddr_len)) { + saddr_port = ntohs(saddr.sin_port); +#ifdef LIBVNCSERVER_HAVE_NETINET_IN_H + saddr_ip_str = inet_ntoa(saddr.sin_addr); +#endif + } + sprintf(env_rfb_server_ip, "RFB_SERVER_IP=%s", saddr_ip_str); + putenv(env_rfb_server_ip); + sprintf(env_rfb_server_port, "RFB_SERVER_PORT=%d", saddr_port); + putenv(env_rfb_server_port); + + + /* * Better set DISPLAY to the one we are polling, if they * want something trickier, they can handle on their own * via environment, etc. XXX really should save/restore old. @@ -1497,7 +1565,7 @@ static KeyCode keycodes[0x100]; static KeyCode left_shift_code, right_shift_code, altgr_code; void initialize_modtweak(void) { - KeySym key, *keymap; + KeySym keysym, *keymap; int i, j, minkey, maxkey, syms_per_keycode; memset(modifiers, -1, sizeof(modifiers)); @@ -1511,16 +1579,16 @@ void initialize_modtweak(void) { for (i = minkey; i <= maxkey; i++) { KeySym lower, upper; /* 2nd one */ - key = keymap[(i - minkey) * syms_per_keycode + 1]; - if (key != NoSymbol) { + keysym = keymap[(i - minkey) * syms_per_keycode + 1]; + if (keysym != NoSymbol) { continue; } /* 1st one */ - key = keymap[(i - minkey) * syms_per_keycode + 0]; - if (key == NoSymbol) { + keysym = keymap[(i - minkey) * syms_per_keycode + 0]; + if (keysym == NoSymbol) { continue; } - XConvertCase(key, &lower, &upper); + XConvertCase(keysym, &lower, &upper); if (lower != upper) { keymap[(i - minkey) * syms_per_keycode + 0] = lower; keymap[(i - minkey) * syms_per_keycode + 1] = upper; @@ -1528,11 +1596,11 @@ void initialize_modtweak(void) { } for (i = minkey; i <= maxkey; i++) { for (j = 0; j < syms_per_keycode; j++) { - key = keymap[ (i - minkey) * syms_per_keycode + j ]; - if ( key >= ' ' && key < 0x100 - && i == XKeysymToKeycode(dpy, key) ) { - keycodes[key] = i; - modifiers[key] = j; + keysym = keymap[ (i - minkey) * syms_per_keycode + j ]; + if ( keysym >= ' ' && keysym < 0x100 + && i == XKeysymToKeycode(dpy, keysym) ) { + keycodes[keysym] = i; + modifiers[keysym] = j; } } } @@ -1545,6 +1613,114 @@ void initialize_modtweak(void) { } /* + * Routine to retreive current state keyboard. 1 means down, 0 up. + */ +static void get_keystate(int *keystate) { + int i, k; + char keys[32]; + + /* n.b. caller decides to X_LOCK or not. */ + XQueryKeymap(dpy, keys); + for (i=0; i<32; i++) { + char c = keys[i]; + + for (k=0; k < 8; k++) { + if (c & 0x1) { + keystate[8*i + k] = 1; + } else { + keystate[8*i + k] = 0; + } + c = c >> 1; + } + } +} + +/* + * Try to KeyRelease any non-Lock modifiers that are down. + */ +void clear_modifiers(int init) { + static KeyCode keycodes[256]; + static KeySym keysyms[256]; + static char *keystrs[256]; + static int kcount = 0, first = 1; + int keystate[256]; + int i, j, minkey, maxkey, syms_per_keycode; + KeySym *keymap; + KeySym keysym; + KeyCode keycode; + + /* n.b. caller decides to X_LOCK or not. */ + if (first) { + /* + * we store results in static arrays, to aid interrupted + * case, but modifiers could have changed during session... + */ + XDisplayKeycodes(dpy, &minkey, &maxkey); + + keymap = XGetKeyboardMapping(dpy, minkey, (maxkey - minkey + 1), + &syms_per_keycode); + + for (i = minkey; i <= maxkey; i++) { + for (j = 0; j < syms_per_keycode; j++) { + keysym = keymap[ (i - minkey) * syms_per_keycode + j ]; + if (keysym == NoSymbol || ! ismodkey(keysym)) { + continue; + } + keycode = XKeysymToKeycode(dpy, keysym); + if (keycode == NoSymbol) { + continue; + } + keycodes[kcount] = keycode; + keysyms[kcount] = keysym; + keystrs[kcount] = strdup(XKeysymToString(keysym)); + kcount++; + } + } + XFree((void *) keymap); + first = 0; + } + if (init) { + return; + } + + get_keystate(keystate); + for (i=0; i < kcount; i++) { + keysym = keysyms[i]; + keycode = keycodes[i]; + + if (! keystate[(int) keycode]) { + continue; + } + + if (clear_mods) { + rfbLog("clear_modifiers: up: %-10s (0x%x) " + "keycode=0x%x\n", keystrs[i], keysym, keycode); + } + myXTestFakeKeyEvent(dpy, keycode, False, CurrentTime); + } + XFlush(dpy); +} + +/* + * Attempt to set all keys to Up position. Can mess up typing at the + * physical keyboard so use with caution. + */ +void clear_keys(void) { + int k, keystate[256]; + + /* n.b. caller decides to X_LOCK or not. */ + get_keystate(keystate); + for (k=0; k<256; k++) { + if (keystate[k]) { + KeyCode keycode = (KeyCode) k; + rfbLog("clear_keys: keycode=%d\n", keycode); + myXTestFakeKeyEvent(dpy, keycode, False, CurrentTime); + } + } + XFlush(dpy); +} + +/* * The following is for an experimental -remap option to allow the user * to remap keystrokes. It is currently confusing wrt modifiers... */ @@ -1890,12 +2066,6 @@ MUTEX(pointerMutex); static prtremap_t pointer_map[MAX_BUTTONS+1][MAX_BUTTON_EVENTS]; /* - * following is based on IsModifierKey in Xutil.h -*/ -#define ismodkey(keysym) \ - ((((KeySym)(keysym) >= XK_Shift_L) && ((KeySym)(keysym) <= XK_Hyper_R))) - -/* * For parsing the -buttonmap sections, e.g. "4" or ":Up+Up+Up:" */ static void buttonparse(int from, char **s) { @@ -4585,11 +4755,11 @@ static void copy_tiles(int tx, int ty, int nt) { for (t=1; t <= nt; t++) { first_line[t] = -1; } + /* find the first line with difference: */ w1 = width1 * pixelsize; w2 = width2 * pixelsize; - /* foreach line: */ for (line = 0; line < size_y; line++) { /* foreach horizontal tile: */ @@ -5640,7 +5810,6 @@ void scan_for_updates(void) { */ static int defer_update_nofb = 6; /* defer a shorter time under -nofb */ -static int shut_down = 0; /* * We need to handle user input, particularly pointer input, carefully. @@ -5963,25 +6132,33 @@ static void print_help(void) { "-localhost Same as -allow 127.0.0.1\n" "-viewpasswd string Supply a 2nd password for view-only logins. The -passwd\n" " (full-access) password must also be supplied.\n" -"-passwdfile filename Specify libvncserver -passwd via the first line of the\n" -" file \"filename\" instead of via command line. If a\n" -" second non blank line exists in the file it is taken\n" -" as a view-only password (i.e. -viewpasswd) Note: this\n" -" is a simple plaintext passwd, see also -rfbauth below.\n" -"-accept string Run a command (possibly to prompt the user at the\n" -" X11 display) to decide whether an incoming client\n" -" should be allowed to connect or not. \"string\" is\n" -" an external command run via system(3) (see below for\n" -" special cases). Be sure to quote \"string\" if it\n" -" contains spaces, etc. The RFB_CLIENT_IP environment\n" -" variable will be set to the incoming client IP number\n" -" and the port in RFB_CLIENT_PORT (or -1 if unavailable).\n" -" The x11vnc process id will be in RFB_X11VNC_PID, a\n" -" client id number in RFB_CLIENT_ID and the number of\n" -" other connected clients in RFB_CLIENT_COUNT. If the\n" -" external command returns 0 the client is accepted,\n" -" otherwise the client is rejected. See below for an\n" -" extension to accept a client view-only.\n" +"-passwdfile filename Specify libvncserver -passwd via the first line of\n" +" the file \"filename\" instead of via command line.\n" +" If a second non blank line exists in the file it is\n" +" taken as a view-only password (i.e. -viewpasswd) Note:\n" +" this is a simple plaintext passwd, see also -rfbauth\n" +" and -storepasswd below.\n" +"-storepasswd pass file Store password \"pass\" as the VNC password in the\n" +" file \"file\". Once the password is stored the\n" +" program exits. Use the password via \"-rfbauth file\"\n" +"-accept string Run a command (possibly to prompt the user at the X11\n" +" display) to decide whether an incoming client should be\n" +" allowed to connect or not. \"string\" is an external\n" +" command run via system(3) (see below for special cases).\n" +" Be sure to quote \"string\" if it contains spaces,\n" +" etc. If the external command returns 0 the client is\n" +" accepted, otherwise the client is rejected. See below\n" +" for an extension to accept a client view-only.\n" +"\n" +" Environment: The RFB_CLIENT_IP environment variable will\n" +" be set to the incoming client IP number and the port\n" +" in RFB_CLIENT_PORT (or -1 if unavailable). Similarly,\n" +" RFB_SERVER_IP and RFB_SERVER_PORT (the x11vnc side\n" +" of the connection), are set to allow identification\n" +" of the tcp virtual circuit. The x11vnc process\n" +" id will be in RFB_X11VNC_PID, a client id number in\n" +" RFB_CLIENT_ID, and the number of other connected clients\n" +" in RFB_CLIENT_COUNT.\n" "\n" " If \"string\" is \"popup\" then a builtin popup window\n" " is used. The popup will time out after 120 seconds,\n" @@ -6053,6 +6230,13 @@ static void print_help(void) { "-modtweak Handle AltGr/Shift modifiers for differing languages\n" " between client and host (default %s).\n" "-nomodtweak Send the keysym directly to the X server.\n" +"-clear_mods At startup and exit clear the modifier keys by sending\n" +" KeyRelease for each one. The Lock modifiers are skipped.\n" +" Used to clear the state if the display was accidentally\n" +" left with any pressed down. That should be rare.\n" +"-clear_keys As -clear_mods, except try to release any pressed key.\n" +" Intended for debugging. This option and -clear_mods\n" +" can interfere with typing at the physical keyboard.\n" "-remap string Read keysym remappings from file \"string\". Format is\n" " one pair of keysyms per line (can be name or hex value).\n" " \"string\" can also be of form: key1-key2,key3-key4...\n" @@ -6287,6 +6471,16 @@ int main(int argc, char** argv) { viewonly_passwd = strdup(argv[++i]); } else if (!strcmp(arg, "-passwdfile")) { passwdfile = argv[++i]; + } else if (!strcmp(arg, "-storepasswd")) { + if (i+2 >= argc || vncEncryptAndStorePasswd(argv[i+1], + argv[i+2]) != 0) { + fprintf(stderr, "-storepasswd failed\n"); + exit(1); + } else { + fprintf(stderr, "stored passwd in file %s\n", + argv[i+2]); + exit(0); + } } else if (!strcmp(arg, "-shared")) { shared = 1; } else if (!strcmp(arg, "-auth")) { @@ -6321,6 +6515,10 @@ int main(int argc, char** argv) { use_modifier_tweak = 1; } else if (!strcmp(arg, "-nomodtweak")) { use_modifier_tweak = 0; + } else if (!strcmp(arg, "-clear_mods")) { + clear_mods = 1; + } else if (!strcmp(arg, "-clear_keys")) { + clear_mods = 2; } else if (!strcmp(arg, "-remap")) { remap_file = argv[++i]; } else if (!strcmp(arg, "-blackout")) { @@ -6642,6 +6840,7 @@ int main(int argc, char** argv) { fprintf(stderr, "using_shm: %d\n", using_shm); fprintf(stderr, "flipbytes: %d\n", flip_byte_order); fprintf(stderr, "mod_tweak: %d\n", use_modifier_tweak); + fprintf(stderr, "clearmods: %d\n", clear_mods); fprintf(stderr, "remap: %s\n", remap_file ? remap_file : "null"); fprintf(stderr, "blackout: %s\n", blackout_string @@ -6850,7 +7049,6 @@ int main(int argc, char** argv) { fprintf(stderr, "warning: 24 bpp may have poor" " performance.\n"); } - if (! dt) { static char str[] = "-desktop"; argv2[argc2++] = str; @@ -6881,6 +7079,7 @@ int main(int argc, char** argv) { initialize_signals(); + if (blackouts) { /* blackout fb as needed. */ copy_screen(); } @@ -6893,6 +7092,11 @@ int main(int argc, char** argv) { } initialize_pointer_map(pointer_remap); + clear_modifiers(1); + if (clear_mods == 1) { + clear_modifiers(0); + } + if (! inetd) { if (! screen->rfbPort || screen->rfbListenSock < 0) { rfbLog("Error: could not obtain listening port.\n"); |