From 11e3f6a6b0c6e5b6e1923e05fa8001d698d86f8d Mon Sep 17 00:00:00 2001 From: runge Date: Sat, 10 Jan 2004 02:52:20 +0000 Subject: [PATCH] x11vnc options -allow, -localhost, -nodragging, -input_skip minimize memory usage under -nofb --- ChangeLog | 4 + contrib/ChangeLog | 8 ++ contrib/x11vnc.c | 194 ++++++++++++++++++++++++++++++++++++++++------ 3 files changed, 181 insertions(+), 25 deletions(-) diff --git a/ChangeLog b/ChangeLog index fef9765..38cc012 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2004-01-09 Karl Runge + * x11vnc options -allow, -localhost, -nodragging, -input_skip + * minimize memory usage under -nofb + 2003-12-08 Karl Runge * add check for XKEYBOARD extension in configure.ac * support XBell events (disable: "-nobell"), "-nofb" in x11vnc diff --git a/contrib/ChangeLog b/contrib/ChangeLog index e52670a..137be5c 100644 --- a/contrib/ChangeLog +++ b/contrib/ChangeLog @@ -1,3 +1,11 @@ +2004-01-09 Karl Runge + * options -allow / -localhost for simple IP based access screening + * option -nodragging to skip all screen updates during mouse drags + (thanks to Michal Sabala) + * option -input_skip to allow users to tune watch_loop dropthru rate + * try to avoid wasting RAM for framebuffer under -nofb + * cleanup wrt bpp vs. depth + 2003-12-08 Karl Runge * add Xbell support using XKEYBOARD extension (disable: -nobell) * add "-nofb" to disable framebuffer, i.e. mouse + keyboard only (!) diff --git a/contrib/x11vnc.c b/contrib/x11vnc.c index b315b26..15bbf6c 100644 --- a/contrib/x11vnc.c +++ b/contrib/x11vnc.c @@ -78,8 +78,8 @@ * their colors messed up. When using 8bpp indexed color, the colormap * 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 8bpp and - * 24bpp visuals will incorrect display the non-default one. + * windows with private colormaps (slow). Displays with mixed depth 8 and + * 24 visuals will incorrect display the non-default one. * * Feature -id can be picky: it can crash for things like the * window not sufficiently mapped into server memory, use of -mouse, etc. @@ -117,7 +117,7 @@ Display *dpy = 0; Visual *visual; Window window, rootwin; int scr; -int bpp; +int bpp, depth; int button_mask = 0; int dpy_x, dpy_y; int off_x, off_y; @@ -168,6 +168,7 @@ hint_t *hint_list; /* various command line options */ int shared = 0; /* share vnc display. */ +char *allow_list = NULL; /* for -allow and -localhost */ int view_only = 0; /* clients can only watch. */ int inetd = 0; /* spawned from inetd(1) */ int connect_once = 1; /* disconnect after first connection session. */ @@ -180,7 +181,10 @@ int nofb = 0; /* do not send any fb updates */ int local_cursor = 1; /* whether the viewer draws a local cursor */ int show_mouse = 0; /* display a cursor for the real mouse */ int show_root_cursor = 0; /* show X when on root background */ -int watch_bell = 1; +int show_dragging = 1; /* process mouse movement events */ +int delay_refresh = 0; /* when buttons are pressed, delay refreshes */ +int ui_dropthru = 10; /* see watchloop. negative means ignore input */ +int watch_bell = 1; /* watch for the bell using XKEYBOARD */ int using_shm = 1; /* whether mit-shm is used */ int flip_byte_order = 0; /* sometimes needed when using_shm = 0 */ @@ -335,14 +339,51 @@ void client_gone(rfbClientPtr client) { } } +int check_access(char *addr) { + int allowed = 0; + char *p, *list; + + if (allow_list == NULL || *allow_list == '\0') { + return 1; + } + if (addr == NULL || *addr == '\0') { + rfbLog("check_access: denying empty host IP address string.\n"); + return 0; + } + + list = strdup(allow_list); + p = strtok(list, ","); + while (p) { + char *q = strstr(addr, p); + if (q == addr) { + rfbLog("check_access: client %s matches pattern %s\n", + addr, p); + allowed = 1; + + } else if(!strcmp(p,"localhost") && !strcmp(addr,"127.0.0.1")) { + /* also do host lookup someday... */ + allowed = 1; + } + p = strtok(NULL, ","); + } + free(list); + return allowed; +} + enum rfbNewClientAction new_client(rfbClientPtr client) { static accepted_client = 0; last_event = last_input = time(0); + + if (! check_access(client->host)) { + rfbLog("denying client: %s does not match %s\n", client->host, + allow_list ? allow_list : "(null)" ); + return(RFB_CLIENT_REFUSE); + } if (connect_once) { if (screen->rfbDontDisconnect && screen->rfbNeverShared) { if (! shared && accepted_client) { - fprintf(stderr, "denying additional client:" - " %s\n", client->host); + rfbLog("denying additional client: %s\n", + client->host); return(RFB_CLIENT_REFUSE); } } @@ -546,6 +587,17 @@ static void pointer(int mask, int x, int y, rfbClientPtr client) { return; } + got_user_input++; + + /* if any button is pressed, then do not refresh the screen */ + if (! show_dragging) { + if (mask) { + delay_refresh = 1; + } else { + delay_refresh = 0; + } + } + X_LOCK; XTestFakeMotionEvent(dpy, scr, x + off_x, y + off_y, CurrentTime); @@ -554,7 +606,6 @@ static void pointer(int mask, int x, int y, rfbClientPtr client) { cursor_y = y; last_event = last_input = time(0); - got_user_input++; for (i=0; i < 5; i++) { if ( (button_mask & (1<host); + fb = XGetImage(dpy, window, 0, 0, dpy_x, dpy_y, AllPlanes, ZPixmap); + screen->frameBuffer = fb->data; + loaded_fb = 1; +} + /* * initialize the rfb framebuffer/screen */ @@ -1174,14 +1242,19 @@ void initialize_screen(int *argc, char **argv, XImage *fb) { = fb->blue_mask >> screen->rfbServerFormat.blueShift; } - screen->frameBuffer = fb->data; + if (nofb) { + screen->frameBuffer = NULL; + screen->displayHook = nofb_hook; + } else { + screen->frameBuffer = fb->data; + } if (inetd) { int fd = dup(0); if (fd < 3) { rfbErr("dup(0) = %d failed.\n", fd); perror("dup"); - exit(1); + clean_up_exit(1); } fclose(stdin); fclose(stdout); @@ -1222,6 +1295,7 @@ void initialize_screen(int *argc, char **argv, XImage *fb) { bytes_per_line = screen->paddedWidthInBytes; bpp = screen->rfbServerFormat.bitsPerPixel; + depth = screen->rfbServerFormat.depth; } /* @@ -1275,11 +1349,15 @@ void shm_create(XShmSegmentInfo *shm, XImage **ximg_ptr, int w, int h, XImage *xim; + if (nofb) { + return; + } + X_LOCK; if (! using_shm) { /* we only need the XImage created */ - xim = XCreateImage(dpy, visual, bpp, ZPixmap, 0, NULL, w, h, + xim = XCreateImage(dpy, visual, depth, ZPixmap, 0, NULL, w, h, BitmapPad(dpy), 0); X_UNLOCK; @@ -1316,7 +1394,7 @@ void shm_create(XShmSegmentInfo *shm, XImage **ximg_ptr, int w, int h, return; } - xim = XShmCreateImage(dpy, visual, bpp, ZPixmap, NULL, shm, w, h); + xim = XShmCreateImage(dpy, visual, depth, ZPixmap, NULL, shm, w, h); if (xim == NULL) { rfbErr("XShmCreateImage(%s) failed.\n", name); @@ -1362,7 +1440,7 @@ void shm_delete(XShmSegmentInfo *shm) { } void shm_clean(XShmSegmentInfo *shm, XImage *xim) { - if (! using_shm) { + if (! using_shm || nofb) { return; } X_LOCK; @@ -1554,6 +1632,7 @@ void tile_updates() { } } + /* * copy_tile() is called on a tile with a known change (from a scanline * diff) or a suspected change (from our various heuristics). @@ -2295,8 +2374,9 @@ void watch_loop(void) { if (! use_threads) { rfbProcessEvents(screen, -1); - if (got_user_input && cnt % 10 != 0) { - /* every 10-th drops thru to code below... */ + if ((got_user_input || ui_dropthru < 0) && + cnt % ui_dropthru != 0) { + /* every n-th drops thru to code below... */ cnt++; XFlush(dpy); continue; @@ -2311,20 +2391,42 @@ void watch_loop(void) { usleep(200 * 1000); continue; } + if (nofb) { continue; } - rfbUndrawCursor(screen); - - scan_for_updates(); - if (watch_bell) { + /* n.b. assumes -nofb folks do not want bell... */ watch_bell_event(); } - usleep(waitms * 1000); + /* + * delay_refresh amounts to delaying rfb screen refreshes. + * During that time, XQueryPointer needs to be called for + * the events to take place on the x server. + */ + if (delay_refresh) { + Window root_w, child_w; + rfbBool ret; + int root_x, root_y, win_x, win_y, which = 0; + unsigned int mask; + + X_LOCK; + if (0) { + XFlush(dpy); + } else { + ret = XQueryPointer(dpy, rootwin, &root_w, + &child_w, &root_x, &root_y, &win_x, &win_y, + &mask); + } + X_UNLOCK; + } else { + rfbUndrawCursor(screen); + scan_for_updates(); + } + usleep(waitms * 1000); cnt++; } } @@ -2367,6 +2469,11 @@ void print_help() { "-shared VNC display is shared (default %s).\n" "-forever Keep listening for more connections rather than exiting\n" " as soon as the first client(s) disconnect. Same as -many\n" +"-allow addr1[,addr2..] Only allow client connections from IP addresses matching\n" +" the comma separated list of numerical addresses. Can be\n" +" a prefix, e.g. \"192.168.100.\" to match a simple subnet,\n" +" for more control build libvncserver with libwrap support.\n" +"-localhost Same as -allow 127.0.0.1\n" "-inetd Launched by inetd(1): stdio instead of listening socket.\n" "-noshm Do not use the MIT-SHM extension for the polling.\n" " remote displays can be polled this way: be careful\n" @@ -2392,6 +2499,15 @@ void print_help() { "-mouse Draw a 2nd cursor at the current X pointer position.\n" "-mouseX As -mouse, but also draw an X on root background.\n" "-X Shorthand for -mouseX -nocursor.\n" +"-nodragging Do not update the display during mouse dragging events.\n" +" Greatly improves response on slow links, but you lose\n" +" all visual feedback for drags and some menu traversals.\n" +"-input_skip n Experimental option difficult to explain! Only active in\n" +" non-threaded mode. See watch_loop() function for info.\n" +" Loop is: rfbProcessEvents, scan display, sleep. If\n" +" there is mouse or keyboard input the scan is skipped\n" +" except every n-th time thru the loop. Default n is 10,\n" +" n<0 means skip even with no user input. Need to improve!\n" "\n" "-defer time Time in ms to wait for updates before sending to\n" " client [rfbDeferUpdateTime] (default %d).\n" @@ -2507,6 +2623,10 @@ int main(int argc, char** argv) { view_only = 1; } else if (!strcmp(argv[i], "-shared")) { shared = 1; + } else if (!strcmp(argv[i], "-allow")) { + allow_list = argv[++i]; + } else if (!strcmp(argv[i], "-localhost")) { + allow_list = "127.0.0.1"; } else if (!strcmp(argv[i], "-many") || !strcmp(argv[i], "-forever")) { connect_once = 0; @@ -2531,6 +2651,11 @@ int main(int argc, char** argv) { } else if (!strcmp(argv[i], "-mouseX")) { show_mouse = 1; show_root_cursor = 1; + } else if (!strcmp(argv[i], "-nodragging")) { + show_dragging = 0; + } else if (!strcmp(argv[i], "-input_skip")) { + ui_dropthru = atoi(argv[++i]); + if (! ui_dropthru) ui_dropthru = 1; } else if (!strcmp(argv[i], "-X")) { show_mouse = 1; show_root_cursor = 1; @@ -2602,6 +2727,8 @@ int main(int argc, char** argv) { if (! quiet) { fprintf(stderr, "viewonly: %d\n", view_only); fprintf(stderr, "shared: %d\n", shared); + fprintf(stderr, "allow: %s\n", allow_list ? allow_list + : "null"); fprintf(stderr, "inetd: %d\n", inetd); fprintf(stderr, "conn_once: %d\n", connect_once); fprintf(stderr, "flashcmap: %d\n", flash_cmap); @@ -2613,6 +2740,8 @@ int main(int argc, char** argv) { fprintf(stderr, "mod_tweak: %d\n", use_modifier_tweak); fprintf(stderr, "loc_curs: %d\n", local_cursor); fprintf(stderr, "mouse: %d\n", show_mouse); + fprintf(stderr, "dragging: %d\n", show_dragging); + fprintf(stderr, "inputskip: %d\n", ui_dropthru); fprintf(stderr, "root_curs: %d\n", show_root_cursor); fprintf(stderr, "defer: %d\n", defer_update); fprintf(stderr, "waitms: %d\n", waitms); @@ -2650,7 +2779,7 @@ int main(int argc, char** argv) { fprintf(stderr, "Display does not support XTest extension.\n"); exit(1); } - if (! XShmQueryExtension(dpy)) { + if (! nofb && ! XShmQueryExtension(dpy)) { if (! using_shm) { fprintf(stderr, "warning: display does not support " "XShm.\n"); @@ -2666,7 +2795,7 @@ int main(int argc, char** argv) { fprintf(stderr, "warning: disabling bell.\n"); watch_bell = 0; } else { - initialize_bell_watch(); + initialize_watch_bell(); } } #endif @@ -2711,11 +2840,26 @@ int main(int argc, char** argv) { set_offset(); } - fb = XGetImage(dpy, window, 0, 0, dpy_x, dpy_y, AllPlanes, ZPixmap); - if (! quiet) fprintf(stderr, "Read initial data from display into framebuffer.\n"); + if (nofb) { + /* + * This does not malloc the framebuffer, so can save a few + * MB of memory in nofb mode. + */ + fb = XCreateImage(dpy, visual, DefaultDepth(dpy, scr), ZPixmap, + 0, NULL, dpy_x, dpy_y, BitmapPad(dpy), 0); + } else { + fb = XGetImage(dpy, window, 0, 0, dpy_x, dpy_y, AllPlanes, + ZPixmap); + } + + if (! quiet) { + fprintf(stderr, "Read initial data from display into" + " framebuffer.\n"); + } if (fb->bits_per_pixel == 24 && ! quiet) { - fprintf(stderr, "warning: 24 bpp may have poor performance.\n"); + fprintf(stderr, "warning: 24 bpp may have poor" + " performance.\n"); } if (! dt) {