1 /*
2 Copyright (C) 2002-2010 Karl J. Runge <runge@karlrunge.com>
3 All rights reserved.
4
5 This file is part of x11vnc.
6
7 x11vnc is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or (at
10 your option) any later version.
11
12 x11vnc is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with x11vnc; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA
20 or see <http://www.gnu.org/licenses/>.
21
22 In addition, as a special exception, Karl J. Runge
23 gives permission to link the code of its release of x11vnc with the
24 OpenSSL project's "OpenSSL" library (or with modified versions of it
25 that use the same license as the "OpenSSL" library), and distribute
26 the linked executables. You must obey the GNU General Public License
27 in all respects for all of the code used other than "OpenSSL". If you
28 modify this file, you may extend this exception to your version of the
29 file, but you are not obligated to do so. If you do not wish to do
30 so, delete this exception statement from your version.
31 */
32
33 /* -- util.c -- */
34
35 #include "x11vnc.h"
36 #include "cleanup.h"
37 #include "win_utils.h"
38 #include "unixpw.h"
39 #include "connections.h"
40
41 struct timeval _mysleep;
42
43 /* this is only for debugging mutexes. see util.h */
44 int hxl = 0;
45
46 #ifdef LIBVNCSERVER_HAVE_LIBPTHREAD
47 MUTEX(x11Mutex);
48 MUTEX(scrollMutex);
49 #endif
50
51 int nfix(int i, int n);
52 int nmin(int n, int m);
53 int nmax(int n, int m);
54 int nabs(int n);
55 double dabs(double x);
56 void lowercase(char *str);
57 void uppercase(char *str);
58 char *lblanks(char *str);
59 void strzero(char *str);
60 int scan_hexdec(char *str, unsigned long *num);
61 int parse_geom(char *str, int *wp, int *hp, int *xp, int *yp, int W, int H);
62 void set_env(char *name, char *value);
63 char *bitprint(unsigned int st, int nbits);
64 char *get_user_name(void);
65 char *get_home_dir(void);
66 char *get_shell(void);
67 char *this_host(void);
68
69 int match_str_list(char *str, char **list);
70 char **create_str_list(char *cslist);
71
72 double dtime(double *);
73 double dtime0(double *);
74 double dnow(void);
75 double dnowx(void);
76 double rnow(void);
77 double rfac(void);
78
79 int rfbPE(long usec);
80 void rfbCFD(long usec);
81
82 double rect_overlap(int x1, int y1, int x2, int y2, int X1, int Y1,
83 int X2, int Y2);
84
85 char *choose_title(char *display);
86
87
88 /*
89 * routine to keep 0 <= i < n
90 */
nfix(int i,int n)91 int nfix(int i, int n) {
92 if (i < 0) {
93 i = 0;
94 } else if (i >= n) {
95 i = n - 1;
96 }
97 return i;
98 }
99
nmin(int n,int m)100 int nmin(int n, int m) {
101 if (n < m) {
102 return n;
103 } else {
104 return m;
105 }
106 }
107
nmax(int n,int m)108 int nmax(int n, int m) {
109 if (n > m) {
110 return n;
111 } else {
112 return m;
113 }
114 }
115
nabs(int n)116 int nabs(int n) {
117 if (n < 0) {
118 return -n;
119 } else {
120 return n;
121 }
122 }
123
dabs(double x)124 double dabs(double x) {
125 if (x < 0.0) {
126 return -x;
127 } else {
128 return x;
129 }
130 }
131
lowercase(char * str)132 void lowercase(char *str) {
133 char *p;
134 if (str == NULL) {
135 return;
136 }
137 p = str;
138 while (*p != '\0') {
139 *p = tolower((unsigned char) (*p));
140 p++;
141 }
142 }
143
uppercase(char * str)144 void uppercase(char *str) {
145 char *p;
146 if (str == NULL) {
147 return;
148 }
149 p = str;
150 while (*p != '\0') {
151 *p = toupper((unsigned char) (*p));
152 p++;
153 }
154 }
155
lblanks(char * str)156 char *lblanks(char *str) {
157 char *p = str;
158 while (*p != '\0') {
159 if (! isspace((unsigned char) (*p))) {
160 break;
161 }
162 p++;
163 }
164 return p;
165 }
166
strzero(char * str)167 void strzero(char *str) {
168 char *p = str;
169 if (p != NULL) {
170 while (*p != '\0') {
171 *p = '\0';
172 p++;
173 }
174 }
175 }
176
is_decimal(char * str)177 int is_decimal(char *str) {
178 char *p = str;
179 if (p != NULL) {
180 int first = 1;
181 while (*p != '\0') {
182 if (first && *p == '-') {
183 ;
184 } else if (isdigit((int) *p)) {
185 ;
186 } else {
187 return 0;
188 }
189 first = 0;
190 p++;
191 }
192 return 1;
193 }
194 return 0;
195 }
196
scan_hexdec(char * str,unsigned long * num)197 int scan_hexdec(char *str, unsigned long *num) {
198 if (sscanf(str, "0x%lx", num) != 1) {
199 if (sscanf(str, "%lu", num) != 1) {
200 return 0;
201 }
202 }
203 return 1;
204 }
205
parse_geom(char * str,int * wp,int * hp,int * xp,int * yp,int W,int H)206 int parse_geom(char *str, int *wp, int *hp, int *xp, int *yp, int W, int H) {
207 int w, h, x, y;
208 if (! str) {
209 return 0;
210 }
211 /* handle +/-x and +/-y */
212 if (sscanf(str, "%dx%d+%d+%d", &w, &h, &x, &y) == 4) {
213 ;
214 } else if (sscanf(str, "%dx%d-%d+%d", &w, &h, &x, &y) == 4) {
215 w = nabs(w);
216 x = W - x - w;
217 } else if (sscanf(str, "%dx%d+%d-%d", &w, &h, &x, &y) == 4) {
218 h = nabs(h);
219 y = H - y - h;
220 } else if (sscanf(str, "%dx%d-%d-%d", &w, &h, &x, &y) == 4) {
221 w = nabs(w);
222 h = nabs(h);
223 x = W - x - w;
224 y = H - y - h;
225 } else {
226 return 0;
227 }
228 *wp = w;
229 *hp = h;
230 *xp = x;
231 *yp = y;
232 return 1;
233 }
234
set_env(char * name,char * value)235 void set_env(char *name, char *value) {
236 char *str;
237 if (! name) {
238 return;
239 }
240 if (! value) {
241 value = "";
242 }
243 str = (char *) malloc(strlen(name) + 1 + strlen(value) + 1);
244 sprintf(str, "%s=%s", name, value);
245 putenv(str);
246 }
247
bitprint(unsigned int st,int nbits)248 char *bitprint(unsigned int st, int nbits) {
249 static char str[33];
250 int i, mask;
251 if (nbits > 32) {
252 nbits = 32;
253 }
254 for (i=0; i<nbits; i++) {
255 str[i] = '0';
256 }
257 str[nbits] = '\0';
258 mask = 1;
259 for (i=nbits-1; i>=0; i--) {
260 if (st & mask) {
261 str[i] = '1';
262 }
263 mask = mask << 1;
264 }
265 return str; /* take care to use or copy immediately */
266 }
267
get_user_name(void)268 char *get_user_name(void) {
269 char *user = NULL;
270
271 user = getenv("USER");
272 if (user == NULL) {
273 user = getenv("LOGNAME");
274 }
275
276 #if LIBVNCSERVER_HAVE_PWD_H
277 if (user == NULL) {
278 struct passwd *pw = getpwuid(getuid());
279 if (pw) {
280 user = pw->pw_name;
281 }
282 }
283 #endif
284
285 if (user) {
286 return(strdup(user));
287 } else {
288 return(strdup("unknown-user"));
289 }
290 }
291
get_home_dir(void)292 char *get_home_dir(void) {
293 char *home = NULL;
294
295 home = getenv("HOME");
296
297 #if LIBVNCSERVER_HAVE_PWD_H
298 if (home == NULL) {
299 struct passwd *pw = getpwuid(getuid());
300 if (pw) {
301 home = pw->pw_dir;
302 }
303 }
304 #endif
305
306 if (home) {
307 return(strdup(home));
308 } else {
309 return(strdup("/"));
310 }
311 }
312
get_shell(void)313 char *get_shell(void) {
314 char *shell = NULL;
315
316 shell = getenv("SHELL");
317
318 #if LIBVNCSERVER_HAVE_PWD_H
319 if (shell == NULL) {
320 struct passwd *pw = getpwuid(getuid());
321 if (pw) {
322 shell = pw->pw_shell;
323 }
324 }
325 #endif
326
327 if (shell) {
328 return(strdup(shell));
329 } else {
330 return(strdup("/bin/sh"));
331 }
332 }
333
334 /*
335 * utility to get the current host name
336 */
this_host(void)337 char *this_host(void) {
338 char host[MAXN];
339 #if LIBVNCSERVER_HAVE_GETHOSTNAME
340 if (gethostname(host, MAXN) == 0) {
341 host[MAXN-1] = '\0';
342 return strdup(host);
343 } else if (UT.nodename) {
344 return strdup(UT.nodename);
345 }
346 #endif
347 return NULL;
348 }
349
match_str_list(char * str,char ** list)350 int match_str_list(char *str, char **list) {
351 int i = 0, matched = 0;
352
353 if (! str || ! list) {
354 return 0;
355 }
356 while (list[i] != NULL) {
357 if (!strcmp(list[i], "*")) {
358 matched = 1;
359 break;
360 } else if (strstr(str, list[i])) {
361 matched = 1;
362 break;
363 }
364 i++;
365 }
366 return matched;
367 }
368
create_str_list(char * cslist)369 char **create_str_list(char *cslist) {
370 int i, n;
371 char *p, *str;
372 char **list = NULL;
373
374 if (! cslist) {
375 return NULL;
376 }
377
378 str = strdup(cslist);
379 n = 1;
380 p = str;
381 while (*p != '\0') {
382 if (*p == ',') {
383 n++;
384 }
385 p++;
386 }
387
388 /* the extra last one holds NULL */
389 list = (char **) calloc((n+1)*sizeof(char *), 1);
390
391 p = strtok(str, ",");
392 i = 0;
393 while (p && i < n) {
394 list[i++] = strdup(p);
395 p = strtok(NULL, ",");
396 }
397 free(str);
398
399 return list;
400 }
401
402 /*
403 * simple function for measuring sub-second time differences, using
404 * a double to hold the value.
405 */
dtime(double * t_old)406 double dtime(double *t_old) {
407 /*
408 * usage: call with 0.0 to initialize, subsequent calls give
409 * the time difference since last call.
410 */
411 double t_now, dt;
412 struct timeval now;
413
414 gettimeofday(&now, NULL);
415 t_now = now.tv_sec + ( (double) now.tv_usec/1000000. );
416 if (*t_old == 0.0) {
417 *t_old = t_now;
418 return t_now;
419 }
420 dt = t_now - *t_old;
421 *t_old = t_now;
422 return(dt);
423 }
424
425 /* common dtime() activities: */
dtime0(double * t_old)426 double dtime0(double *t_old) {
427 *t_old = 0.0;
428 return dtime(t_old);
429 }
430
dnow(void)431 double dnow(void) {
432 double t;
433 return dtime0(&t);
434 }
435
dnowx(void)436 double dnowx(void) {
437 return dnow() - x11vnc_start;
438 }
439
rnow(void)440 double rnow(void) {
441 double t = dnow();
442 t = t - ((int) t);
443 if (t > 1.0) {
444 t = 1.0;
445 } else if (t < 0.0) {
446 t = 0.0;
447 }
448 return t;
449 }
450
rfac(void)451 double rfac(void) {
452 double f;
453 static int first = 1;
454
455 if (first) {
456 unsigned int s;
457 if (getenv("RAND_SEED")) {
458 s = (unsigned int) atoi(getenv("RAND_SEED"));
459 } else {
460 s = (unsigned int) ((int) getpid() + 100000 * rnow());
461 }
462 srand(s);
463 first = 0;
464 }
465
466 f = (double) rand();
467 f = f / ((double) RAND_MAX);
468
469 return f;
470 }
471
check_allinput_rate(void)472 void check_allinput_rate(void) {
473 static double last_all_input_check = 0.0;
474 static int set = 0, verb = -1;
475
476 if (use_threads) {
477 return;
478 }
479 if (verb < 0) {
480 verb = 0;
481 if (getenv("RATE_VERB")) verb = 1;
482 }
483 if (! set) {
484 set = 1;
485 last_all_input_check = dnow();
486 } else {
487 int dt = 5;
488 if (x11vnc_current > last_all_input_check + dt) {
489 int n, nq = 0;
490 while ((n = rfbCheckFds(screen, 0))) {
491 nq += n;
492 }
493 if (verb) fprintf(stderr, "nqueued: %d\n", nq);
494 if (getenv("CHECK_RATE") && nq > 18 * dt) {
495 double rate = nq / dt;
496 if (verb) rfbLog("check_allinput_rate:\n");
497 if (verb) rfbLog("Client is sending %.1f extra requests per second for the\n", rate);
498 if (verb) rfbLog("past %d seconds! (queued: %d)\n", dt, nq);
499 if (strstr(getenv("CHECK_RATE"), "allinput") && !all_input && !handle_events_eagerly) {
500 rfbLog("Switching to -allpinput mode.\n");
501 all_input = 1;
502 }
503 }
504 set = 0;
505 }
506 }
507 }
508
do_allinput(long usec)509 static void do_allinput(long usec) {
510 static double last = 0.0;
511 static int meas = 0, verb = -1;
512 int n, f = 1, cnt = 0, m = 0;
513 long usec0;
514 double now;
515 if (!screen || !screen->clientHead) {
516 return;
517 }
518 if (use_threads) {
519 return;
520 }
521 if (usec < 0) {
522 usec = 0;
523 }
524 usec0 = usec;
525 if (last == 0.0) {
526 last = dnow();
527 }
528 if (verb < 0) {
529 verb = 0;
530 if (getenv("RATE_VERB")) verb = 1;
531 }
532 while ((n = rfbCheckFds(screen, usec)) > 0) {
533 if (f) {
534 if (verb) fprintf(stderr, " *");
535 f = 0;
536 }
537 if (cnt++ > 30) {
538 break;
539 }
540 meas += n;
541 m += n;
542 }
543 if (verb) fprintf(stderr, "+%d/%d", cnt, m);
544 now = dnow();
545 if (now > last + 2.0) {
546 double rate = meas / (now - last);
547 if (verb) fprintf(stderr, "\n allinput rate: %.2f ", rate);
548 meas = 0;
549 last = dnow();
550 }
551 }
552
553 /*
554 * utility wrapper to call rfbProcessEvents
555 * checks that we are not in threaded mode.
556 */
557 #define USEC_MAX 999999 /* libvncsever assumes < 1 second */
rfbPE(long usec)558 int rfbPE(long usec) {
559 int uip0 = unixpw_in_progress;
560 static int check_rate = -1;
561 int res = 0;
562 if (! screen) {
563 return res;
564 }
565 if (unixpw && unixpw_in_progress && !unixpw_in_rfbPE) {
566 rfbLog("unixpw_in_rfbPE: skipping rfbPE\n");
567 return res;
568 }
569
570 if (debug_tiles > 2) {
571 double tm = dnow();
572 fprintf(stderr, "rfbPE(%d) t: %.4f\n",
573 (int) usec, tm - x11vnc_start);
574 }
575
576 if (usec > USEC_MAX) {
577 usec = USEC_MAX;
578 }
579 if (! use_threads) {
580 rfbBool r;
581 r = rfbProcessEvents(screen, usec);
582 if (r) {
583 res = 1;
584 }
585 }
586
587 if (unixpw && unixpw_in_progress && !uip0) {
588 if (!unixpw_in_rfbPE) {
589 rfbLog("rfbPE: got new client in non-rfbPE\n");
590 ; /* this is new unixpw client */
591 }
592 }
593
594 if (ipv6_listen) {
595 check_ipv6_listen(usec);
596 }
597 if (unix_sock) {
598 check_unix_sock(usec);
599 }
600 if (check_rate != 0) {
601 if (check_rate < 0) {
602 if (getenv("CHECK_RATE")) {
603 check_rate = 1;
604 } else {
605 check_rate = 0;
606 }
607 }
608 if (check_rate && !all_input && x11vnc_current < last_client + 45) {
609 check_allinput_rate();
610 }
611 }
612 if (all_input) {
613 do_allinput(usec);
614 }
615 return res;
616 }
617
rfbCFD(long usec)618 void rfbCFD(long usec) {
619 int uip0 = unixpw_in_progress;
620 if (! screen) {
621 return;
622 }
623 if (unixpw && unixpw_in_progress && !unixpw_in_rfbPE) {
624 static int msgs = 0;
625 static double last_reset = 0.0;
626 if (dnow() > last_reset + 5.0) {
627 msgs = 0;
628 last_reset = dnow();
629 }
630 if (msgs++ < 10) {
631 rfbLog("unixpw_in_rfbPE: skipping rfbCFD\n");
632 if (msgs == 10) {
633 rfbLog("unixpw_in_rfbPE: skipping rfbCFD ...\n");
634 }
635 }
636 return;
637 }
638 if (usec > USEC_MAX) {
639 usec = USEC_MAX;
640 }
641
642 if (debug_tiles > 2) {
643 double tm = dnow();
644 fprintf(stderr, "rfbCFD(%d) t: %.4f\n",
645 (int) usec, tm - x11vnc_start);
646 }
647
648
649 if (! use_threads) {
650 if (all_input) {
651 do_allinput(usec);
652 } else {
653 if (handle_events_eagerly) {
654 screen->handleEventsEagerly = TRUE;
655 } else {
656 screen->handleEventsEagerly = FALSE;
657 }
658 rfbCheckFds(screen, usec);
659 }
660 }
661
662 if (unixpw && unixpw_in_progress && !uip0) {
663 if (!unixpw_in_rfbPE) {
664 rfbLog("rfbCFD: got new client in non-rfbPE\n");
665 ; /* this is new unixpw client */
666 }
667 }
668 }
669
rect_overlap(int x1,int y1,int x2,int y2,int X1,int Y1,int X2,int Y2)670 double rect_overlap(int x1, int y1, int x2, int y2, int X1, int Y1,
671 int X2, int Y2) {
672 double a, A, o;
673 sraRegionPtr r, R;
674 sraRectangleIterator *iter;
675 sraRect rt;
676
677 a = nabs((x2 - x1) * (y2 - y1));
678 A = nabs((X2 - X1) * (Y2 - Y1));
679
680 if (a == 0 || A == 0) {
681 return 0.0;
682 }
683
684 r = sraRgnCreateRect(x1, y1, x2, y2);
685 R = sraRgnCreateRect(X1, Y1, X2, Y2);
686
687 sraRgnAnd(r, R);
688
689 o = 0.0;
690 iter = sraRgnGetIterator(r);
691 while (sraRgnIteratorNext(iter, &rt)) {
692 o += nabs( (rt.x2 - rt.x1) * (rt.y2 - rt.y1) );
693 }
694 sraRgnReleaseIterator(iter);
695
696 sraRgnDestroy(r);
697 sraRgnDestroy(R);
698
699 if (a < A) {
700 o = o/a;
701 } else {
702 o = o/A;
703 }
704 return o;
705 }
706
707 /*
708 * choose a desktop name
709 */
choose_title(char * display)710 char *choose_title(char *display) {
711 static char title[(MAXN+10)];
712
713 memset(title, 0, sizeof(title));
714 strcpy(title, "x11vnc");
715
716 if (display == NULL) {
717 display = getenv("DISPLAY");
718 }
719
720 #ifdef MACOSX
721 if (display == NULL || strstr(display, "/tmp/") == display) {
722 char *u = get_user_name();
723 char *th = this_host();
724 if (strlen(u) > MAXN/4) {
725 u = "someone";
726 }
727 strcpy(title, u);
728 if (th == NULL && UT.nodename) {
729 th = UT.nodename;
730 }
731 if (th) {
732 strcat(title, "@");
733 strncat(title, th, MAXN - strlen(title));
734 }
735 return title;
736 }
737 #endif
738
739 if (display == NULL) {
740 return title;
741 }
742
743 /* use display: */
744 title[0] = '\0';
745 if (display[0] == ':') {
746 char *th = this_host();
747 if (th != NULL) {
748 strncpy(title, th, MAXN - strlen(title));
749 }
750 }
751 strncat(title, display, MAXN - strlen(title));
752 X_LOCK;
753 if (subwin && dpy && valid_window(subwin, NULL, 0)) {
754 #if !NO_X11
755 char *name = NULL;
756 int do_appshare = getenv("X11VNC_APPSHARE_ACTIVE") ? 1 : 0;
757 if (0 && do_appshare) {
758 title[0] = '\0';
759 }
760 if (XFetchName(dpy, subwin, &name)) {
761 if (name) {
762 if (title[0] != '\0') {
763 strncat(title, " ", MAXN - strlen(title));
764 }
765 strncat(title, name, MAXN - strlen(title));
766 free(name);
767 }
768 }
769 if (do_appshare) {
770 Window c;
771 int x, y;
772 if (xtranslate(subwin, rootwin, 0, 0, &x, &y, &c, 1)) {
773 char tmp[32];
774 if (scaling) {
775 x *= scale_fac_x;
776 y *= scale_fac_y;
777 }
778 sprintf(tmp, " XY=%d,%d", x, y);
779 strncat(title, tmp, MAXN - strlen(title));
780 }
781 rfbLog("appshare title: %s\n", title);
782 }
783 #endif /* NO_X11 */
784 }
785 X_UNLOCK;
786 return title;
787 }
788