From 11e3f6a6b0c6e5b6e1923e05fa8001d698d86f8d Mon Sep 17 00:00:00 2001
From: runge <runge>
Date: Sat, 10 Jan 2004 02:52:20 +0000
Subject:  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 <runge@karlrunge.com>
+	* x11vnc options -allow, -localhost, -nodragging, -input_skip
+	* minimize memory usage under -nofb
+
 2003-12-08  Karl Runge <runge@karlrunge.com>
 	* 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 <runge@karlrunge.com>
+	* 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 <runge@karlrunge.com>
 	* 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 <windowid> 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<<i)) != (mask & (1<<i)) ) {
@@ -580,7 +631,7 @@ static void pointer(int mask, int x, int y, rfbClientPtr client) {
 
 int xkb_base_event_type;
 
-void initialize_bell_watch() {
+void initialize_watch_bell() {
 	int ir, reason;
 	if (! XkbSelectEvents(dpy, XkbUseCoreKbd, XkbBellNotifyMask,
 	    XkbBellNotifyMask) ) {
@@ -1113,6 +1164,23 @@ void set_colormap(void) {
 	first = 0;
 }
 
+/*
+ * Presumably under -nofb the clients will never request the framebuffer.
+ * But we have gotten such a request... so let's just give them the current
+ * view on the display.  n.b. x2vnc requests a 1x1 pixel for some workaround. 
+ */
+void nofb_hook(rfbClientPtr cl) {
+	static int loaded_fb = 0;
+	XImage *fb;
+	if (loaded_fb) {
+		return;
+	}
+	rfbLog("framebuffer requested in -nofb mode by client %s\n", cl->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) {
-- 
cgit v1.2.3

