summaryrefslogtreecommitdiffstats
path: root/x11vnc/x11vnc.c
diff options
context:
space:
mode:
authorrunge <runge>2007-09-05 03:39:51 +0000
committerrunge <runge>2007-09-05 03:39:51 +0000
commit6a6d26a74701179672d59bfd153cc1a2e92e96bd (patch)
tree47537dd9d54f9c9e95c01e066435216bbac99ceb /x11vnc/x11vnc.c
parente30552512933e6f0a07b83dd3246a97ff5281503 (diff)
downloadlibtdevnc-6a6d26a74701179672d59bfd153cc1a2e92e96bd.tar.gz
libtdevnc-6a6d26a74701179672d59bfd153cc1a2e92e96bd.zip
x11vnc: -autoport, -finddpy, -xdummy. watch xrandr events. check_redir_services() utilities for Terminal services. Improve Xdummy.
Diffstat (limited to 'x11vnc/x11vnc.c')
-rw-r--r--x11vnc/x11vnc.c628
1 files changed, 626 insertions, 2 deletions
diff --git a/x11vnc/x11vnc.c b/x11vnc/x11vnc.c
index b98ebf1..ca76d8d 100644
--- a/x11vnc/x11vnc.c
+++ b/x11vnc/x11vnc.c
@@ -394,6 +394,574 @@ if (0 && dt > 0.0) fprintf(stderr, "dt: %.5f %.4f\n", dt, dnowx());
return msec;
}
+static int tsdo_timeout_flag;
+
+static void tsdo_timeout (int sig) {
+ tsdo_timeout_flag = 1;
+}
+
+#define TASKMAX 32
+static pid_t ts_tasks[TASKMAX];
+static int ts_taskn = -1;
+
+int tsdo(int port, int lsock, int *conn) {
+ int csock, rsock, i, db = 1;
+ pid_t pid;
+ struct sockaddr_in addr;
+#ifdef __hpux
+ int addrlen = sizeof(addr);
+#else
+ socklen_t addrlen = sizeof(addr);
+#endif
+
+ if (*conn < 0) {
+ signal(SIGALRM, tsdo_timeout);
+ tsdo_timeout_flag = 0;
+
+ alarm(10);
+ csock = accept(lsock, (struct sockaddr *)&addr, &addrlen);
+ alarm(0);
+
+ if (db) rfbLog("tsdo: accept: lsock: %d, csock: %d, port: %d\n", lsock, csock, port);
+
+ if (tsdo_timeout_flag > 0 || csock < 0) {
+ close(csock);
+ *conn = -1;
+ return 1;
+ }
+ *conn = csock;
+ } else {
+ csock = *conn;
+ if (db) rfbLog("tsdo: using exiting csock: %d, port: %d\n", csock, port);
+ }
+
+ rsock = rfbConnectToTcpAddr("127.0.0.1", port);
+ if (rsock < 0) {
+ if (db) rfbLog("tsdo: rfbConnectToTcpAddr(port=%d) failed.\n", port);
+ return 2;
+ }
+
+ pid = fork();
+ if (pid < 0) {
+ close(rsock);
+ return 3;
+ }
+ if (pid > 0) {
+ ts_taskn = (ts_taskn+1) % TASKMAX;
+ ts_tasks[ts_taskn] = pid;
+ close(csock);
+ *conn = -1;
+ close(rsock);
+ return 0;
+ }
+ if (pid == 0) {
+ for (i=0; i<255; i++) {
+ if (i != csock && i != rsock && i != 2) {
+ close(i);
+ }
+ }
+#if LIBVNCSERVER_HAVE_SETSID
+ if (setsid() == -1) {
+ perror("setsid");
+ exit(1);
+ }
+#else
+ if (setpgrp() == -1) {
+ perror("setpgrp");
+ exit(1);
+ }
+#endif /* SETSID */
+ raw_xfer(rsock, csock, csock);
+ exit(0);
+ }
+}
+
+void set_redir_properties(void);
+
+#define TSMAX 32
+#define TSSTK 16
+void terminal_services(char *list) {
+ int i, j, n = 0, db = 1;
+ char *p, *q, *r, *str = strdup(list);
+#if !NO_X11
+ char *tag[TSMAX];
+ int listen[TSMAX], redir[TSMAX][TSSTK], socks[TSMAX], tstk[TSSTK];
+ Atom at, atom[TSMAX];
+ fd_set rd;
+ Window rwin;
+ XErrorHandler old_handler1;
+ XIOErrorHandler old_handler2;
+ char num[32];
+ time_t last_clean = time(NULL);
+
+ if (! dpy) {
+ return;
+ }
+ rwin = RootWindow(dpy, DefaultScreen(dpy));
+
+ at = XInternAtom(dpy, "TS_REDIR_LIST", False);
+ if (at != None) {
+ XChangeProperty(dpy, rwin, at, XA_STRING, 8,
+ PropModeReplace, (unsigned char *)list, strlen(list));
+ XSync(dpy, False);
+ }
+ for (i=0; i<TASKMAX; i++) {
+ ts_tasks[i] = 0;
+ }
+ for (i=0; i<TSMAX; i++) {
+ for (j=0; j<TSSTK; j++) {
+ redir[i][j] = 0;
+ }
+ }
+
+ p = strtok(str, ",");
+ while (p) {
+ int m1, m2;
+ if (db) fprintf(stderr, "item: %s\n", p);
+ q = strrchr(p, ':');
+ if (!q) {
+ p = strtok(NULL, ",");
+ continue;
+ }
+ r = strchr(p, ':');
+ if (!r || r == q) {
+ p = strtok(NULL, ",");
+ continue;
+ }
+
+ m1 = atoi(q+1);
+ *q = '\0';
+ m2 = atoi(r+1);
+ *r = '\0';
+
+ if (m1 <= 0 || m2 <= 0 || m1 >= 0xffff || m2 >= 0xffff) {
+ p = strtok(NULL, ",");
+ continue;
+ }
+
+ redir[n][0] = m1;
+ listen[n] = m2;
+ tag[n] = strdup(p);
+
+ if (db) fprintf(stderr, " %d %d %s\n", redir[n][0], listen[n], tag[n]);
+
+ *r = ':';
+ *q = ':';
+
+ n++;
+ if (n >= TSMAX) {
+ break;
+ }
+ p = strtok(NULL, ",");
+ }
+ free(str);
+
+ if (n==0) {
+ return;
+ }
+
+ at = XInternAtom(dpy, "TS_REDIR_PID", False);
+ if (at != None) {
+ sprintf(num, "%d", getpid());
+ XChangeProperty(dpy, rwin, at, XA_STRING, 8,
+ PropModeReplace, (unsigned char *)num, strlen(num));
+ XSync(dpy, False);
+ }
+
+ for (i=0; i<n; i++) {
+ atom[i] = XInternAtom(dpy, tag[i], False);
+ if (db) fprintf(stderr, "tag: %s atom: %d\n", tag[i], atom[i]);
+ if (atom[i] == None) {
+ continue;
+ }
+ sprintf(num, "%d", redir[i][0]);
+ if (db) fprintf(stderr, " listen: %d redir: %s\n", listen[i], num);
+ XChangeProperty(dpy, rwin, atom[i], XA_STRING, 8,
+ PropModeReplace, (unsigned char *)num, strlen(num));
+ XSync(dpy, False);
+
+ socks[i] = rfbListenOnTCPPort(listen[i], htonl(INADDR_LOOPBACK));
+ }
+
+ if (getenv("TSD_RESTART")) {
+ if (!strcmp(getenv("TSD_RESTART"), "1")) {
+ set_redir_properties();
+ }
+ }
+
+ while (1) {
+ struct timeval tv;
+ int nfd;
+ int fmax = -1;
+
+ tv.tv_sec = 3;
+ tv.tv_usec = 0;
+
+ FD_ZERO(&rd);
+ for (i=0; i<n; i++) {
+ if (socks[i] >= 0) {
+ FD_SET(socks[i], &rd);
+ if (socks[i] > fmax) {
+ fmax = socks[i];
+ }
+ }
+ }
+
+ nfd = select(fmax+1, &rd, NULL, NULL, &tv);
+
+ if (db && 0) fprintf(stderr, "nfd=%d\n", nfd);
+ if (nfd < 0 && errno == EINTR) {
+ XSync(dpy, True);
+ continue;
+ }
+ if (nfd > 0) {
+ for(i=0; i<n; i++) {
+ int k = 0;
+ for (j = 0; j < TSSTK; j++) {
+ tstk[j] = 0;
+ }
+ for (j = 0; j < TSSTK; j++) {
+ if (redir[i][j] != 0) {
+ tstk[k++] = redir[i][j];
+ }
+ }
+ for (j = 0; j < TSSTK; j++) {
+ redir[i][j] = tstk[j];
+if (tstk[j] != 0) fprintf(stderr, "B redir[%d][%d] = %d %s\n", i, j, tstk[j], tag[i]);
+ }
+ }
+ for(i=0; i<n; i++) {
+ int s = socks[i];
+ if (s < 0) {
+ continue;
+ }
+ if (FD_ISSET(s, &rd)) {
+ int p0, p, found = -1, jzero = -1;
+ int conn = -1;
+
+ get_prop(num, 32, atom[i]);
+ p0 = atoi(num);
+
+ for (j = TSSTK-1; j >= 0; j--) {
+ if (redir[i][j] == 0) {
+ jzero = j;
+ continue;
+ }
+ if (p0 > 0 && p0 < 0xffff) {
+ if (redir[i][j] == p0) {
+ found = j;
+ break;
+ }
+ }
+ }
+ if (jzero < 0) {
+ jzero = TSSTK-1;
+ }
+ if (found < 0) {
+ if (p0 > 0 && p0 < 0xffff) {
+ redir[i][jzero] = p0;
+ }
+ }
+ for (j = TSSTK-1; j >= 0; j--) {
+ int rc;
+ p = redir[i][j];
+ if (p <= 0 || p >= 0xffff) {
+ redir[i][j] = 0;
+ continue;
+ }
+ rc = tsdo(p, s, &conn);
+ if (rc == 0) {
+ /* AOK */
+ if (db) fprintf(stderr, "tsdo[%d] OK: %d\n", i, p);
+ if (p != p0) {
+ sprintf(num, "%d", p);
+ XChangeProperty(dpy, rwin, atom[i], XA_STRING, 8,
+ PropModeReplace, (unsigned char *)num, strlen(num));
+ XSync(dpy, False);
+ }
+ break;
+ } else if (rc == 1) {
+ /* accept failed */
+ if (db) fprintf(stderr, "tsdo[%d] accept failed: %d\n", i, p);
+ break;
+ } else if (rc == 2) {
+ /* connect failed */
+ if (db) fprintf(stderr, "tsdo[%d] connect failed: %d\n", i, p);
+ redir[i][j] = 0;
+ continue;
+ } else if (rc == 3) {
+ /* fork failed */
+ usleep(250*1000);
+ break;
+ }
+ }
+ for (j = 0; j < TSSTK; j++) {
+ if (redir[i][j] != 0) fprintf(stderr, "A redir[%d][%d] = %d %s\n", i, j, redir[i][j], tag[i]);
+ }
+ }
+ }
+ }
+ for (i=0; i<TASKMAX; i++) {
+ pid_t p = ts_tasks[i];
+ if (p > 0) {
+ int status;
+ pid_t p2 = waitpid(p, &status, WNOHANG);
+ if (p2 == p) {
+ ts_tasks[i] = 0;
+ }
+ }
+ }
+ /* this is to drop events and exit when X server is gone. */
+ old_handler1 = XSetErrorHandler(trap_xerror);
+ old_handler2 = XSetIOErrorHandler(trap_xioerror);
+ trapped_xerror = 0;
+ trapped_xioerror = 0;
+
+ XSync(dpy, True);
+
+ sprintf(num, "%d", (int) time(NULL));
+ at = XInternAtom(dpy, "TS_REDIR", False);
+ if (at != None) {
+ XChangeProperty(dpy, rwin, at, XA_STRING, 8,
+ PropModeReplace, (unsigned char *)num, strlen(num));
+ XSync(dpy, False);
+ }
+ if (time(NULL) > last_clean + 20 * 60) {
+ int i, j;
+ for(i=0; i<n; i++) {
+ int first = 1;
+ for (j = TSSTK-1; j >= 0; j--) {
+ int s, p = redir[i][j];
+ if (p <= 0 || p >= 0xffff) {
+ redir[i][j] = 0;
+ continue;
+ }
+ s = rfbConnectToTcpAddr("127.0.0.1", p);
+ if (s < 0) {
+ redir[i][j] = 0;
+ if (db) fprintf(stderr, "tsdo[%d][%d] clean: connect failed: %d\n", i, j, p);
+ } else {
+ close(s);
+ if (first) {
+ sprintf(num, "%d", p);
+ XChangeProperty(dpy, rwin, atom[i], XA_STRING, 8,
+ PropModeReplace, (unsigned char *)num, strlen(num));
+ XSync(dpy, False);
+ }
+ first = 0;
+ }
+ usleep(500*1000);
+ }
+ }
+ last_clean = time(NULL);
+ }
+ if (trapped_xerror || trapped_xioerror) {
+ if (db) fprintf(stderr, "Xerror: %d/%d\n", trapped_xerror, trapped_xioerror);
+ exit(0);
+ }
+ XSetErrorHandler(old_handler1);
+ XSetIOErrorHandler(old_handler2);
+ }
+#endif
+}
+
+char *ts_services[][2] = {
+ {"FD_CUPS", "TS_CUPS_REDIR"},
+ {"FD_SMB", "TS_SMB_REDIR"},
+ {"FD_ESD", "TS_ESD_REDIR"},
+ {"FD_NAS", "TS_NAS_REDIR"},
+ {NULL, NULL}
+};
+
+void do_tsd(void) {
+#if !NO_X11
+ Atom a;
+ char prop[513];
+ pid_t pid;
+ char *cmd;
+ int n, sz = 0;
+ char *disp = DisplayString(dpy);
+
+ prop[0] = '\0';
+ a = XInternAtom(dpy, "TS_REDIR_LIST", False);
+ if (a != None) {
+ get_prop(prop, 512, a);
+ }
+
+ if (prop[0] == '\0') {
+ return;
+ }
+
+ if (! program_name) {
+ program_name = "x11vnc";
+ }
+ sz += strlen(program_name) + 1;
+ sz += strlen("-display") + 1;
+ sz += strlen(disp) + 1;
+ sz += strlen("-tsd") + 1;
+ sz += 1 + strlen(prop) + 1 + 1;
+ sz += strlen("-env TSD_RESTART=1") + 1;
+ sz += strlen("</dev/null 1>/dev/null 2>&1") + 1;
+ sz += strlen(" &") + 1;
+
+ cmd = (char *) malloc(sz);
+
+ if (getenv("XAUTHORITY")) {
+ char *xauth = getenv("XAUTHORITY");
+ if (!strcmp(xauth, "") || access(xauth, R_OK) != 0) {
+ *(xauth-2) = '_'; /* yow */
+ }
+ }
+ sprintf(cmd, "%s -display %s -tsd '%s' -env TSD_RESTART=1 </dev/null 1>/dev/null 2>&1 &", program_name, disp, prop);
+ rfbLog("running: %s\n", cmd);
+
+#if LIBVNCSERVER_HAVE_FORK && LIBVNCSERVER_HAVE_SETSID
+ /* fork into the background now */
+ if ((pid = fork()) > 0) {
+ pid_t pidw;
+ int status;
+ double s = dnow();
+
+ while (dnow() < s + 1.5) {
+ pidw = waitpid(pid, &status, WNOHANG);
+ if (pidw == pid) {
+ break;
+ }
+ usleep(100*1000);
+ }
+ return;
+
+ } else if (pid == -1) {
+ system(cmd);
+ } else {
+ setsid();
+ /* adjust our stdio */
+ n = open("/dev/null", O_RDONLY);
+ dup2(n, 0);
+ dup2(n, 1);
+ dup2(n, 2);
+ if (n > 2) {
+ close(n);
+ }
+ system(cmd);
+ exit(0);
+ }
+#else
+ system(cmd);
+#endif
+
+#endif
+}
+
+void set_redir_properties(void) {
+#if !NO_X11
+ char *e, *f, *t;
+ Atom a;
+ char num[32];
+ int i, p;
+
+ if (! dpy) {
+ return;
+ }
+
+ i = 0;
+ while (ts_services[i][0] != NULL) {
+ f = ts_services[i][0];
+ t = ts_services[i][1];
+ e = getenv(f);
+ if (!e || strstr(e, "DAEMON-") != e) {
+ i++;
+ continue;
+ }
+ p = atoi(e + strlen("DAEMON-"));
+ if (p <= 0) {
+ i++;
+ continue;
+ }
+ sprintf(num, "%d", p);
+ a = XInternAtom(dpy, t, False);
+ if (a != None) {
+ Window rwin = RootWindow(dpy, DefaultScreen(dpy));
+fprintf(stderr, "Set: %s %s %s -> %s\n", f, t, e, num);
+ XChangeProperty(dpy, rwin, a, XA_STRING, 8,
+ PropModeReplace, (unsigned char *) num, strlen(num));
+ XSync(dpy, False);
+ }
+ i++;
+ }
+#endif
+}
+
+void check_redir_services(void) {
+#if !NO_X11
+ Atom a;
+ char prop[513];
+ time_t tsd_last;
+ int i, restart = 0;
+ pid_t pid = 0;
+
+ if (! dpy) {
+ return;
+ }
+
+ a = XInternAtom(dpy, "TS_REDIR_PID", False);
+ if (a != None) {
+ prop[0] = '\0';
+ get_prop(prop, 512, a);
+ if (prop[0] != '\0') {
+ pid = (pid_t) atoi(prop);
+ }
+ }
+
+ if (getenv("FD_TAG")) {
+ a = XInternAtom(dpy, "FD_TAG", False);
+ if (a != None) {
+ Window rwin = RootWindow(dpy, DefaultScreen(dpy));
+ char *tag = getenv("FD_TAG");
+ XChangeProperty(dpy, rwin, a, XA_STRING, 8,
+ PropModeReplace, (unsigned char *)tag, strlen(tag));
+ XSync(dpy, False);
+ }
+ }
+
+ prop[0] = '\0';
+ a = XInternAtom(dpy, "TS_REDIR", False);
+ if (a != None) {
+ get_prop(prop, 512, a);
+ }
+ if (prop[0] == '\0') {
+ rfbLog("TS_REDIR is empty, restarting...\n");
+ restart = 1;
+ } else {
+ tsd_last = (time_t) atoi(prop);
+ if (time(NULL) > tsd_last + 30) {
+ rfbLog("TS_REDIR seems dead for: %d sec, restarting...\n",
+ time(NULL) - tsd_last);
+ restart = 1;
+ } else if (pid > 0 && time(NULL) > tsd_last + 6) {
+ if (kill(pid, 0) != 0) {
+ rfbLog("TS_REDIR seems dead via kill(%d, 0), restarting...\n",
+ pid);
+ restart = 1;
+ }
+ }
+ }
+ if (restart) {
+
+ if (pid > 1) {
+ rfbLog("killing TS_REDIR_PID: %d\n", pid);
+ kill(pid, SIGTERM);
+ usleep(500*1000);
+ kill(pid, SIGKILL);
+ }
+ do_tsd();
+ return;
+ }
+
+ set_redir_properties();
+#endif
+}
+
void check_filexfer(void) {
static time_t last_check = 0;
rfbClientIteratorPtr iter;
@@ -646,6 +1214,27 @@ static void watch_loop(void) {
vnc_reflect_process_client();
}
dtime0(&tm);
+
+#if !NO_X11
+ if (xrandr_present && !xrandr && xrandr_maybe) {
+ int delay = 180;
+ /* there may be xrandr right after xsession start */
+ if (tm < x11vnc_start + delay || tm < last_client + delay) {
+ int tw = 20;
+ if (auth_file != NULL) {
+ tw = 120;
+ }
+ X_LOCK;
+ if (tm < x11vnc_start + tw || tm < last_client + tw) {
+ XSync(dpy, False);
+ } else {
+ XFlush_wr(dpy);
+ }
+ X_UNLOCK;
+ }
+ check_xrandr_event("before-scan");
+ }
+#endif
if (use_snapfb) {
int t, tries = 3;
copy_snap();
@@ -1562,7 +2151,7 @@ char msg2[] =
#define SHOW_NO_PASSWORD_WARNING \
(!got_passwd && !got_rfbauth && (!got_passwdfile || !passwd_list) \
&& !query_cmd && !remote_cmd && !unixpw && !got_gui_pw \
- && ! ssl_verify && !inetd)
+ && ! ssl_verify && !inetd && !terminal_services_daemon)
extern int dragum(void);
@@ -1710,18 +2299,36 @@ int main(int argc, char* argv[]) {
}
} else if (!strcmp(arg, "-find")) {
use_dpy = strdup("WAIT:cmd=FINDDISPLAY");
+ } else if (!strcmp(arg, "-finddpy")) {
+ int ic = 0;
+ use_dpy = strdup("WAIT:cmd=FINDDISPLAY-run");
+ if (argc > i+1) {
+ set_env("X11VNC_USER", argv[i+1]);
+ fprintf(stdout, "X11VNC_USER=%s\n", getenv("X11VNC_USER"));
+ }
+ wait_for_client(&ic, NULL, 0);
+ exit(0);
} else if (!strcmp(arg, "-create")) {
use_dpy = strdup("WAIT:cmd=FINDCREATEDISPLAY-Xvfb");
+ } else if (!strcmp(arg, "-xdummy")) {
+ use_dpy = strdup("WAIT:cmd=FINDCREATEDISPLAY-Xdummy");
+ set_env("FD_XDUMMY_NOROOT", "1");
} else if (!strcmp(arg, "-auth") || !strcmp(arg, "-xauth")) {
CHECK_ARGC
auth_file = strdup(argv[++i]);
} else if (!strcmp(arg, "-N")) {
display_N = 1;
+ } else if (!strcmp(arg, "-autoport")) {
+ CHECK_ARGC
+ auto_port = atoi(argv[++i]);
} else if (!strcmp(arg, "-reflect")) {
CHECK_ARGC
raw_fb_str = (char *) malloc(4 + strlen(argv[i]) + 1);
sprintf(raw_fb_str, "vnc:%s", argv[++i]);
shared = 1;
+ } else if (!strcmp(arg, "-tsd")) {
+ CHECK_ARGC
+ terminal_services_daemon = strdup(argv[++i]);
} else if (!strcmp(arg, "-id") || !strcmp(arg, "-sid")) {
CHECK_ARGC
if (!strcmp(arg, "-sid")) {
@@ -1878,6 +2485,13 @@ int main(int argc, char* argv[]) {
users_list = strdup("unixpw=");
use_openssl = 1;
openssl_pem = strdup("SAVE");
+ } else if (!strcmp(arg, "-svc_xdummy")) {
+ use_dpy = strdup("WAIT:cmd=FINDCREATEDISPLAY-Xdummy");
+ unixpw = 1;
+ users_list = strdup("unixpw=");
+ use_openssl = 1;
+ openssl_pem = strdup("SAVE");
+ set_env("FD_XDUMMY_NOROOT", "1");
} else if (!strcmp(arg, "-xdmsvc") || !strcmp(arg, "-xdm_service")) {
use_dpy = strdup("WAIT:cmd=FINDCREATEDISPLAY-Xvfb.xdmcp");
unixpw = 1;
@@ -2095,6 +2709,9 @@ int main(int argc, char* argv[]) {
i++;
}
}
+ } else if (!strcmp(arg, "-noxrandr")) {
+ xrandr = 0;
+ xrandr_maybe = 0;
} else if (!strcmp(arg, "-rotate")) {
CHECK_ARGC
rotating_str = strdup(argv[++i]);
@@ -3328,6 +3945,11 @@ int main(int argc, char* argv[]) {
dpy = XOpenDisplay_wr("");
}
+ if (terminal_services_daemon != NULL) {
+ terminal_services(terminal_services_daemon);
+ exit(0);
+ }
+
#ifdef MACOSX
if (! dpy && ! raw_fb_str) {
raw_fb_str = strdup("console");
@@ -3744,6 +4366,7 @@ int main(int argc, char* argv[]) {
}
xrandr_base_event_type = 0;
xrandr = 0;
+ xrandr_maybe = 0;
xrandr_present = 0;
} else {
xrandr_present = 1;
@@ -3905,7 +4528,8 @@ int main(int argc, char* argv[]) {
}
free(xdmcp_insert);
#endif
- }
+ }
+ check_redir_services();
}