1 /* 2 Copyright (C) 2002-2010 Karl J. Runge <runge (at) 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 */ 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 100 int nmin(int n, int m) { 101 if (n < m) { 102 return n; 103 } else { 104 return m; 105 } 106 } 107 108 int nmax(int n, int m) { 109 if (n > m) { 110 return n; 111 } else { 112 return m; 113 } 114 } 115 116 int nabs(int n) { 117 if (n < 0) { 118 return -n; 119 } else { 120 return n; 121 } 122 } 123 124 double dabs(double x) { 125 if (x < 0.0) { 126 return -x; 127 } else { 128 return x; 129 } 130 } 131 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 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 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 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 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 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 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 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 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 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 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 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 */ 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 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 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 */ 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: */ 426 double dtime0(double *t_old) { 427 *t_old = 0.0; 428 return dtime(t_old); 429 } 430 431 double dnow(void) { 432 double t; 433 return dtime0(&t); 434 } 435 436 double dnowx(void) { 437 return dnow() - x11vnc_start; 438 } 439 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 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 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 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 */ 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 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 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 */ 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