Commit 97540de5 authored by runge's avatar runge

classes/ssl: Many improvements to Java SSL applet, onetimekey

          serverCert param, debugging printout, user dialogs, catch
          socket exceptions, autodetect x11vnc for GET=1.
x11vnc: misc/scripts: desktop.cgi, inet6to4, panner.pl.
          X11VNC_HTTPS_DOWNLOAD_WAIT_TIME, -unixpw %xxx documented, and
          can run user cmd in UNIXPW_CMD. FD_XDMCP_IF for create script,
          autodetect dm on udp6 only.  Queries: pointer_x, pointer_y,
          pointer_same, pointer_root.  Switch on -xkd if keysyms per key >
          4 in all cases.  daemon mode improvements for connect_switch,
          inet6to4, ultravnc_repeater.pl.  Dynamic change of -clip do
          not create new fb if WxH is unchanged.
parent edb79ae2
...@@ -137,6 +137,15 @@ Both TightVNC and UltraVNC Java viewers: ...@@ -137,6 +137,15 @@ Both TightVNC and UltraVNC Java viewers:
number, default: 50 number, default: 50
Milliseconds delay Milliseconds delay
PASSWORD
string, default: none
VNC session password in plain text.
ENCPASSWORD
string, default: none
VNC session password in encrypted in DES with KNOWN FIXED
key. It is a hex string. This is like the ~/.vnc/passwd format.
The following are added by x11vnc and/or ssvnc project The following are added by x11vnc and/or ssvnc project
...@@ -173,16 +182,47 @@ Both TightVNC and UltraVNC Java viewers: ...@@ -173,16 +182,47 @@ Both TightVNC and UltraVNC Java viewers:
oneTimeKey oneTimeKey
string, default: none string, default: none
set a special hex "key" to correspond to an SSL X.509 cert. set a special hex "key" to correspond to an SSL X.509 cert+key.
See the 'onetimekey' helper script. Can also be PROMPT to See the 'onetimekey' helper script. Can also be PROMPT to prompt
prompt the user to paste the hex key string in. the user to paste the hex key string in.
This provides a Client-Side cert+key that the client will use to
authenticate itself by SSL To the VNC Server.
This is to try to work around the problem that the Java applet
cannot keep an SSL keystore on disk, etc. E.g. if they log
into an HTTPS website via password they are authenticated and
encrypted, then the website can safely put oneTimeKey=... on the
URL. The Vncviewer authenticates the VNC server with this key.
Note that there is currently a problem in that if x11vnc requires
Client Certificates the user cannot download the index.vnc HTML
and VncViewer.jar from the same x11vnc. Those need to come from
a different x11vnc or from a web server.
Note that the HTTPS website can also put the VNC Password
(e.g. a temporary/one-time one) in the parameter PASSWORD.
The Java Applet will automatically supply this VNC password
instead of prompting.
serverCert
string, default: none
set a special hex "cert" to correspond to an SSL X.509 cert
See the 'onetimekey -certonly' helper script.
This is to try to work around the problem that the Java This provides a Server-Side cert that the client will authenticate
applet cannot keep an SSL keystore on disk, etc. the VNC Server against by SSL.
E.g. if they log into an HTTPS website via password they
are authenticated and encrypted, then the website can This is to try to work around the problem that the Java applet
safely put oneTimeKey=... on the URL. The Vncviewer cannot keep an SSL keystore on disk, etc. E.g. if they log
authenticates the VNC server with this key. into an HTTPS website via password they are authenticated and
encrypted, then the website can safely put serverCert=... on the
URL.
Of course the VNC Server is sending this string to the Java
Applet, so this is only reasonable security if the VNC Viewer
already trusts the HTTPS retrieval of the URL + serverCert param
that it gets. This should be done over HTTPS not HTTP.
proxyHost proxyHost
string, default: none string, default: none
...@@ -238,14 +278,7 @@ TightVNC Java viewer only: ...@@ -238,14 +278,7 @@ TightVNC Java viewer only:
UltraVNC Java viewer only: UltraVNC Java viewer only:
PASSWORD None.
string, default: none
VNC session password in plain text.
ENCPASSWORD
string, default: none
VNC session password in encrypted in DES with KNOWN FIXED
key. It is a hex string. This is like the ~/.vnc/passwd format.
The following are added by x11vnc and/or ssvnc project The following are added by x11vnc and/or ssvnc project
......
#!/bin/sh #!/bin/sh
# #
# usage: onetimekey path/to/mycert.pem # usage: onetimekey path/to/mycert.pem
# onetimekey -certonly path/to/mycert.pem
# #
# Takes an openssl cert+key pem file and turns into a long string # Takes an openssl cert+key pem file and turns into a long string
# for the x11vnc SSL VNC Java Viewer. # for the x11vnc SSL VNC Java Viewer.
...@@ -14,6 +15,19 @@ ...@@ -14,6 +15,19 @@
# in it. Also, as the name implies, an HTTPS server can create # in it. Also, as the name implies, an HTTPS server can create
# a one time key to send to the applet (the user has already # a one time key to send to the applet (the user has already
# logged in via password to the HTTPS server). # logged in via password to the HTTPS server).
#
# Note oneTimeKey is to provide a CLIENT Certificate for the viewer
# to authenticate itself to the VNC Server.
#
# There is also the serverCert=<str> Applet parameter. This is
# a cert to authenticate the VNC server against. To create that
# string with this tool specify -certonly as the first argument.
certonly=""
if [ "X$1" = "X-certonly" ]; then
shift
certonly=1
fi
in=$1 in=$1
der=/tmp/1time$$.der der=/tmp/1time$$.der
...@@ -43,5 +57,9 @@ rm -f "$der" ...@@ -43,5 +57,9 @@ rm -f "$der"
n=`grep -n 'BEGIN CERTIFICATE' $in | awk -F: '{print $1}' | head -1` n=`grep -n 'BEGIN CERTIFICATE' $in | awk -F: '{print $1}' | head -1`
str2=`tail +$n $in | $pbinhex` str2=`tail +$n $in | $pbinhex`
echo "$str1,$str2" if [ "X$certonly" = "X1" ]; then
echo "$str2"
else
echo "$str1,$str2"
fi
rm -f $pbinhex rm -f $pbinhex
2010-03-20 Karl Runge <runge@karlrunge.com>
* classes/ssl: Many improvements to Java SSL applet, onetimekey
serverCert param, debugging printout, user dialogs, catch
socket exceptions, autodetect x11vnc for GET=1.
* x11vnc: misc/scripts: desktop.cgi, inet6to4, panner.pl.
X11VNC_HTTPS_DOWNLOAD_WAIT_TIME, -unixpw %xxx documented, and
can run user cmd in UNIXPW_CMD. FD_XDMCP_IF for create script,
autodetect dm on udp6 only. Queries: pointer_x, pointer_y,
pointer_same, pointer_root. Switch on -xkd if keysyms per key >
4 in all cases. daemon mode improvements for connect_switch,
inet6to4, ultravnc_repeater.pl. Dynamic change of -clip do
not create new fb if WxH is unchanged.
2010-02-22 Karl Runge <runge@karlrunge.com> 2010-02-22 Karl Runge <runge@karlrunge.com>
* classes/ssl: Java SSL applet viewer now works with certificate * classes/ssl: Java SSL applet viewer now works with certificate
chains. chains.
......
This diff is collapsed.
...@@ -908,6 +908,9 @@ static void tree_descend_cursor(int *depth, Window *w, win_str_info_t *winfo) { ...@@ -908,6 +908,9 @@ static void tree_descend_cursor(int *depth, Window *w, win_str_info_t *winfo) {
*(winfo->res_name) = '\0'; *(winfo->res_name) = '\0';
*(winfo->res_class) = '\0'; *(winfo->res_class) = '\0';
for (i=0; i < maxtries; i++) {
wins[i] = None;
}
/* some times a window can go away before we get to it */ /* some times a window can go away before we get to it */
trapped_xerror = 0; trapped_xerror = 0;
......
This diff is collapsed.
...@@ -1114,7 +1114,8 @@ void switch_to_xkb_if_better(void) { ...@@ -1114,7 +1114,8 @@ void switch_to_xkb_if_better(void) {
n = k; n = k;
XFree_wr(keymap); XFree_wr(keymap);
if (missing_noxkb == 0 && syms_gt_4 >= 8) { if (missing_noxkb == 0 && syms_per_keycode > 4 && syms_gt_4 >= 0) {
/* we used to have syms_gt_4 >= 8, now always on. */
if (! raw_fb_str) { if (! raw_fb_str) {
rfbLog("\n"); rfbLog("\n");
rfbLog("XKEYBOARD: number of keysyms per keycode %d is greater\n", syms_per_keycode); rfbLog("XKEYBOARD: number of keysyms per keycode %d is greater\n", syms_per_keycode);
...@@ -1123,6 +1124,7 @@ void switch_to_xkb_if_better(void) { ...@@ -1123,6 +1124,7 @@ void switch_to_xkb_if_better(void) {
rfbLog(" If this makes the key mapping worse you can\n"); rfbLog(" If this makes the key mapping worse you can\n");
rfbLog(" disable it with the \"-noxkb\" option.\n"); rfbLog(" disable it with the \"-noxkb\" option.\n");
rfbLog(" Also, remember \"-remap DEAD\" for accenting characters.\n"); rfbLog(" Also, remember \"-remap DEAD\" for accenting characters.\n");
rfbLog("\n");
} }
use_xkb_modtweak = 1; use_xkb_modtweak = 1;
...@@ -1135,6 +1137,7 @@ void switch_to_xkb_if_better(void) { ...@@ -1135,6 +1137,7 @@ void switch_to_xkb_if_better(void) {
rfbLog(" Not automatically switching to -xkb mode.\n"); rfbLog(" Not automatically switching to -xkb mode.\n");
rfbLog(" If some keys still cannot be typed, try using -xkb.\n"); rfbLog(" If some keys still cannot be typed, try using -xkb.\n");
rfbLog(" Also, remember \"-remap DEAD\" for accenting characters.\n"); rfbLog(" Also, remember \"-remap DEAD\" for accenting characters.\n");
rfbLog("\n");
} }
return; return;
} }
...@@ -1217,6 +1220,7 @@ void switch_to_xkb_if_better(void) { ...@@ -1217,6 +1220,7 @@ void switch_to_xkb_if_better(void) {
rfbLog(" Also, remember \"-remap DEAD\" for accenting" rfbLog(" Also, remember \"-remap DEAD\" for accenting"
" characters.\n"); " characters.\n");
} }
rfbLog("\n");
} }
/* sets up all the keymapping info via Xkb API */ /* sets up all the keymapping info via Xkb API */
......
SUBDIRS = turbovnc SUBDIRS = turbovnc
DIST_SUBDIRS = turbovnc DIST_SUBDIRS = turbovnc
EXTRA_DIST=README blockdpy.c dtVncPopup rx11vnc rx11vnc.pl shm_clear ranfb.pl slide.pl vcinject.pl x11vnc_loop Xdummy ultravnc_repeater.pl connect_switch EXTRA_DIST=README blockdpy.c dtVncPopup rx11vnc rx11vnc.pl shm_clear ranfb.pl slide.pl vcinject.pl x11vnc_loop Xdummy ultravnc_repeater.pl connect_switch panner.pl desktop.cgi inet6to4
...@@ -33,3 +33,14 @@ Misc. scripts: ...@@ -33,3 +33,14 @@ Misc. scripts:
use Xsetup mechanism. use Xsetup mechanism.
Xdummy An LD_PRELOAD kludge to run the Xorg "dummy" device driver Xdummy An LD_PRELOAD kludge to run the Xorg "dummy" device driver
like Xvfb. like Xvfb.
ultravnc_repeater.pl: Unix script to act as UltraVNC repeater proxy.
connect_switch: Share HTTPS, VNC, SSH, etc. through a single port (e.g. 443)
panner.pl Allows a small rectangle to pan around a desktop more or less.
desktop.cgi CGI script for creating multi-user virtual desktops on a
server. Also can do port-redirection to internal machines.
inet6to4 ipv6 to ipv4 relay (i.e. until libvncserver supports ipv6)
This diff is collapsed.
This diff is collapsed.
#!/usr/bin/perl
#
# inet6to4: Act as an ipv6-to-ipv4 relay for tcp applications that
# do not support ipv6.
#
# Usage: inet6to4 <ipv6-listen-port> <ipv4-host:port>
# inet6to4 -r <ipv4-listen-port> <ipv6-host:port>
#
# Examples: inet6to4 5900 localhost:5900
# inet6to4 8080 web1:80
# inet6to4 -r 5900 fe80::217:f2ff:fee6:6f5a%eth0:5900
#
# The -r option reverses the direction of translation (e.g. for ipv4
# clients that need to connect to ipv6 servers.) Reversing is the default
# if this script is named 'inet4to6' (e.g. by a symlink.)
#
# Use Ctrl-C to stop this program.
#
# You can also set env. vars INET6TO4_LOOP=1 or INET6TO4_LOOP=BG
# to have an outer loop restarting this program (BG means do that
# in the background), and INET6TO4_LOGFILE for a log file.
# Also set INET6TO4_VERBOSE to verbosity level and INET6TO4_WAITTIME
# and INET6TO4_PIDFILE (see below.)
#
#-------------------------------------------------------------------------
# Copyright (c) 2010 by Karl J. Runge <runge@karlrunge.com>
#
# inet6to4 is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or (at
# your option) any later version.
#
# inet6to4 is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with inet6to4; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA
# or see <http://www.gnu.org/licenses/>.
#-------------------------------------------------------------------------
# Set up logging:
#
if (exists $ENV{INET6TO4_LOGFILE}) {
close STDOUT;
if (!open(STDOUT, ">>$ENV{INET6TO4_LOGFILE}")) {
die "inet6to4: $ENV{INET6TO4_LOGFILE} $!\n";
}
close STDERR;
open(STDERR, ">&STDOUT");
}
select(STDERR); $| = 1;
select(STDOUT); $| = 1;
# interrupt handler:
#
my $looppid = '';
my $pidfile = '';
my $listen_sock = ''; # declared here for get_out()
#
sub get_out {
print STDERR "$_[0]:\t$$ looppid=$looppid\n";
close $listen_sock if $listen_sock;
if ($looppid) {
kill 'TERM', $looppid;
fsleep(0.2);
}
unlink $pidfile if $pidfile;
exit 0;
}
$SIG{INT} = \&get_out;
$SIG{TERM} = \&get_out;
# pidfile:
#
sub open_pidfile {
if (exists $ENV{INET6TO4_PIDFILE}) {
my $pf = $ENV{INET6TO4_PIDFILE};
if (open(PID, ">$pf")) {
print PID "$$\n";
close PID;
$pidfile = $pf;
} else {
print STDERR "could not open pidfile: $pf - $! - continuing...\n";
}
delete $ENV{INET6TO4_PIDFILE};
}
}
####################################################################
# Set INET6TO4_LOOP=1 to have this script create an outer loop
# restarting itself if it ever exits. Set INET6TO4_LOOP=BG to
# do this in the background as a daemon.
if (exists $ENV{INET6TO4_LOOP}) {
my $csl = $ENV{INET6TO4_LOOP};
if ($csl ne 'BG' && $csl ne '1') {
die "inet6to4: invalid INET6TO4_LOOP.\n";
}
if ($csl eq 'BG') {
# go into bg as "daemon":
setpgrp(0, 0);
my $pid = fork();
if (! defined $pid) {
die "inet6to4: $!\n";
} elsif ($pid) {
wait;
exit 0;
}
if (fork) {
exit 0;
}
setpgrp(0, 0);
close STDIN;
if (! $ENV{INET6TO4_LOGFILE}) {
close STDOUT;
close STDERR;
}
}
delete $ENV{INET6TO4_LOOP};
if (exists $ENV{INET6TO4_PIDFILE}) {
open_pidfile();
}
print STDERR "inet6to4: starting service at ", scalar(localtime), " master-pid=$$\n";
while (1) {
$looppid = fork;
if (! defined $looppid) {
sleep 10;
} elsif ($looppid) {
wait;
} else {
exec $0, @ARGV;
exit 1;
}
print STDERR "inet6to4: re-starting service at ", scalar(localtime), " master-pid=$$\n";
sleep 1;
}
exit 0;
}
if (exists $ENV{INET6TO4_PIDFILE}) {
open_pidfile();
}
use IO::Socket::INET6;
use strict;
use warnings;
# some settings:
#
my $verbose = 1; # set to 0 for no messages, 2 for more.
my $killpid = 1; # does kill(2) at end of connection.
my $waittime = 0.25; # time to wait between connections.
my $reverse = 0; # -r switch (or file named inet4to6)
if (exists $ENV{INET6TO4_VERBOSE}) {
$verbose = $ENV{INET6TO4_VERBOSE};
}
if (exists $ENV{INET6TO4_WAITTIME}) {
$waittime = $ENV{INET6TO4_WAITTIME};
}
# process command line args:
if (! @ARGV || $ARGV[0] =~ '^-+h') { # -help
open(ME, "<$0");
while (<ME>) {
last unless /^#/;
next if /usr.bin.perl/;
$_ =~ s/# ?//;
print;
}
exit;
}
if ($ARGV[0] eq '-r') { # -r
shift;
$reverse = 1;
} elsif ($0 =~ /inet4to6$/) {
$reverse = 1;
}
my $listen_port = shift; # ipv6-listen-port
my $connect_to = shift; # ipv4-host:port
die "no listen port or connect-to-host:port\n" if ! $listen_port || ! $connect_to;
# connect to host:
#
my $host = '';
my $port = '';
if ($connect_to =~ /^(.*):(\d+)$/) {
$host = $1;
$port = $2;
}
die "invalid connect-to-host:port\n" if ! $host || ! $port;
setpgrp(0, 0);
# create listening socket:
#
if (!$reverse) {
$listen_sock = IO::Socket::INET6->new(
Listen => 10,
LocalPort => $listen_port,
Domain => AF_INET6,
ReuseAddr => 1,
Proto => "tcp"
);
} else {
$listen_sock = IO::Socket::INET->new(
Listen => 10,
LocalPort => $listen_port,
ReuseAddr => 1,
Proto => "tcp"
);
}
if (! $listen_sock) {
die "inet6to4: $!\n";
}
# for use by the xfer helper processes' interrupt handlers:
#
my $current_fh1 = '';
my $current_fh2 = '';
# connection counter:
#
my $conn = 0;
# loop forever waiting for connections:
#
while (1) {
$conn++;
print STDERR "listening for connection: $conn\n" if $verbose;
my ($client, $ip) = $listen_sock->accept();
if ($client && !$reverse && $port == $listen_port) {
# This happens on Darwin 'tcp46'
if ($client->peerhost() =~ /^::ffff:/) {
print STDERR "closing client we think is actually us: ",
$client->peerhost(), "\n";
close $client;
$client = undef;
}
}
if (! $client) {
# to throttle runaways
fsleep(2 * $waittime);
next;
}
print STDERR "conn: $conn -- ", $client->peerhost(), " at ", scalar(localtime), "\n" if $verbose;
# spawn helper:
#
my $pid = fork();
if (! defined $pid) {
die "inet6to4: $!\n";
} elsif ($pid) {
wait;
# to throttle runaways
fsleep($waittime);
next;
} else {
# this is to avoid zombies:
close $listen_sock;
if (fork) {
exit 0;
}
setpgrp(0, 0);
handle_conn($client);
}
}
exit 0;
sub handle_conn {
my $client = shift;
my $start = time();
print STDERR "connecting to: $host:$port\n" if $verbose;
my $sock = '';
if (!$reverse) {
$sock = IO::Socket::INET->new(
PeerAddr => $host,
PeerPort => $port,
Proto => "tcp"
);
} else {
$sock = IO::Socket::INET6->new(
PeerAddr => $host,
PeerPort => $port,
Domain => AF_INET6,
Proto => "tcp"
);
}
if (! $sock) {
close $client;
die "inet6to4: $!\n";
}
$current_fh1 = $client;
$current_fh2 = $sock;
# interrupt handler:
#
$SIG{TERM} = sub {print STDERR "got sigterm\[$$]\n" if $verbose; close $current_fh1; close $current_fh2; exit 0};
# spawn another helper and transfer the data:
#
my $parent = $$;
if (my $child = fork()) {
xfer($sock, $client, 'S->C');
if ($killpid) {
fsleep(0.5);
kill 'TERM', $child;
}
} else {
xfer($client, $sock, 'C->S');
if ($killpid) {
fsleep(0.75);
kill 'TERM', $parent;
}
}
# done.
#
if ($verbose > 1) {
my $dt = time() - $start;
print STDERR "dt\[$$]: $dt\n";
}
exit 0;
}
# transfers data in one direction:
#
sub xfer {
my($in, $out, $lab) = @_;
my ($RIN, $WIN, $EIN, $ROUT);
$RIN = $WIN = $EIN = "";
$ROUT = "";
vec($RIN, fileno($in), 1) = 1;
vec($WIN, fileno($in), 1) = 1;
$EIN = $RIN | $WIN;
my $buf;
while (1) {
my $nf = 0;
while (! $nf) {
$nf = select($ROUT=$RIN, undef, undef, undef);
}
my $len = sysread($in, $buf, 8192);
if (! defined($len)) {
next if $! =~ /^Interrupted/;
print STDERR "inet6to4\[$lab/$conn/$$]: $!\n";
last;
} elsif ($len == 0) {
print STDERR "inet6to4\[$lab/$conn/$$]: "
. "Input is EOF.\n";
last;
}
if ($verbose > 4) {
# verbose debugging of data:
syswrite(STDERR , "\n$lab: ", 6);
syswrite(STDERR , $buf, $len);
}
my $offset = 0;
my $quit = 0;
while ($len) {
my $written = syswrite($out, $buf, $len, $offset);
if (! defined $written) {
print STDERR "inet6to4\[$lab/$conn/$$]: "
. "Output is EOF. $!\n";
$quit = 1;
last;
}
$len -= $written;
$offset += $written;
}
last if $quit;
}
close($in);
close($out);
}
# sleep a fraction of a second:
#
sub fsleep {
my ($time) = @_;
select(undef, undef, undef, $time) if $time;
}
#!/usr/bin/perl
#
# panner.pl: start up x11vnc in '-clip' mode viewing a small (WxH)
# rectangular region of the screen. Allow the viewer user
# to 'pan' around the display region by moving the mouse.
#
# Remote interaction with applications, e.g. clicking a
# button though the VNC viewer, will be very difficult.
# This may be useful in a 'demo' mode where the user sitting
# at the physical display is the only one moving the mouse.
# Depending on your usage the following x11vnc options may
# be useful: -nonap
#
# Usage: panner.pl WxH <x11vnc-args> (e.g. -display ...)
# or panner.pl WxH:0.05 <x11vnc-args> (e.g. 0.05 is polling time in secs.)
use strict;
my $WxH = shift;
my $poll_time;
# split off poll time:
#
($WxH, $poll_time) = split(/:/, $WxH);
my ($W, $H) = split(/x/, $WxH);
$poll_time = 0.1 unless $poll_time ne '';
# set to x11vnc command (e.g. full PATH)
#
my $x11vnc = "x11vnc";
# check if display was given:
#
my $query_args = "";
for (my $i=0; $i < @ARGV; $i++) {
if ($ARGV[$i] eq '-display') {
$query_args = "-display $ARGV[$i+1]";
}
}
# find the size of display and the current mouse position:
my %v;
vset("DIRECT:wdpy_x,wdpy_y,pointer_x,pointer_y,pointer_same");
# set a -clip argument based on the above:
#
my $clip = '';
clip_set();
$clip = "${W}x${H}+0+0" unless $v{pointer_same};
# launch x11vnc with -clip in the background:
#
my $cmd = "$x11vnc -clip $clip -bg " . join(" ", @ARGV);
print STDERR "running: $cmd\n";
system $cmd;
# user can hit Ctrl-C or kill this script to quit (and stop x11vnc)
#
sub quit {
system("$x11vnc $query_args -R stop");
exit 0;
}
$SIG{INT} = \&quit;
$SIG{TERM} = \&quit;
# loop forever waiting for mouse position to change, then shift -clip:
#
my $clip_old = $clip;
while (1) {
fsleep($poll_time);
vset("pointer_x,pointer_y,pointer_same");
next unless $v{pointer_same};
clip_set();
if ($clip ne $clip_old) {
system("$x11vnc $query_args -R clip:$clip");
$clip_old = $clip
}
}
exit 0;
# short sleep:
#
sub fsleep {
my ($time) = @_;
select(undef, undef, undef, $time) if $time;
}
# set the -clip string, making sure view doesn't go off edges of display:
#
sub clip_set {
my $x = int($v{pointer_x} - $W/2);
my $y = int($v{pointer_y} - $H/2);
$x = 0 if $x < 0;
$y = 0 if $y < 0;
$x = $v{wdpy_x} - $W if $x + $W > $v{wdpy_x};
$y = $v{wdpy_y} - $H if $y + $H > $v{wdpy_y};
$clip = "${W}x${H}+$x+$y";
}
# query x11vnc for values, put results in the %v hash:
#
sub vset {
my $str = shift;
my $out = `$x11vnc $query_args -Q $str 2>/dev/null`;
chomp $out;
foreach my $pair (split(/,/, $out)) {
$pair =~ s/^a..=//;
my ($k, $v) = split(/:/, $pair, 2);
if ($k ne '' && $v ne '') {
print STDERR "k=$k v=$v\n" if $ENV{DEBUG};
$v{$k} = $v;
}
}
}
#!/usr/bin/env perl #!/usr/bin/env perl
# #
# Copyright (c) 2009 by Karl J. Runge <runge@karlrunge.com> # Copyright (c) 2009-2010 by Karl J. Runge <runge@karlrunge.com>
# #
# ultravnc_repeater.pl is free software; you can redistribute it and/or modify # ultravnc_repeater.pl is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by # it under the terms of the GNU General Public License as published by
...@@ -41,17 +41,137 @@ usage: ultravnc_repeater.pl [-r] [client_port [server_port]] ...@@ -41,17 +41,137 @@ usage: ultravnc_repeater.pl [-r] [client_port [server_port]]
Use -r to refuse new server/client connections with an existing Use -r to refuse new server/client connections with an existing
server/client ID. The default is to close the previous one. server/client ID. The default is to close the previous one.
To write to a log file set the env. var ULTRAVNC_REPEATER_LOGFILE.
To run in a loop restarting the server if it exits set the env. var.
ULTRAVNC_REPEATER_LOOP=1 or ULTRAVNC_REPEATER_LOOP=BG, the latter
forks into the background. Set ULTRAVNC_REPEATER_PIDFILE to a file
to store the master pid in.
Examples: Examples:
ultravnc_repeater.pl
ultravnc_repeater.pl -r ultravnc_repeater.pl -r
ultravnc_repeater.pl 5901 ultravnc_repeater.pl 5901
ultravnc_repeater.pl 5901 5501 ultravnc_repeater.pl 5901 5501
env ULTRAVNC_REPEATER_LOOP=BG ULTRAVNC_REPEATER_LOGFILE=/tmp/u.log ultravnc_repeater.pl ...
'; ';
use warnings;
use strict; use strict;
# Set up logging:
#
if (exists $ENV{ULTRAVNC_REPEATER_LOGFILE}) {
close STDOUT;
if (!open(STDOUT, ">>$ENV{ULTRAVNC_REPEATER_LOGFILE}")) {
die "ultravnc_repeater.pl: $ENV{ULTRAVNC_REPEATER_LOGFILE} $!\n";
}
close STDERR;
open(STDERR, ">&STDOUT");
}
select(STDERR); $| = 1;
select(STDOUT); $| = 1;
# interrupt handler:
#
my $looppid = '';
my $pidfile = '';
#
sub get_out {
print STDERR "$_[0]:\t$$ looppid=$looppid\n";
if ($looppid) {
kill 'TERM', $looppid;
fsleep(0.2);
}
unlink $pidfile if $pidfile;
cleanup();
exit 0;
}
# These are overridden in actual server thread:
#
$SIG{INT} = \&get_out;
$SIG{TERM} = \&get_out;
# pidfile:
#
sub open_pidfile {
if (exists $ENV{ULTRAVNC_REPEATER_PIDFILE}) {
my $pf = $ENV{ULTRAVNC_REPEATER_PIDFILE};
if (open(PID, ">$pf")) {
print PID "$$\n";
close PID;
$pidfile = $pf;
} else {
print STDERR "could not open pidfile: $pf - $! - continuing...\n";
}
delete $ENV{ULTRAVNC_REPEATER_PIDFILE};
}
}
####################################################################
# Set ULTRAVNC_REPEATER_LOOP=1 to have this script create an outer loop
# restarting itself if it ever exits. Set ULTRAVNC_REPEATER_LOOP=BG to
# do this in the background as a daemon.
if (exists $ENV{ULTRAVNC_REPEATER_LOOP}) {
my $csl = $ENV{ULTRAVNC_REPEATER_LOOP};
if ($csl ne 'BG' && $csl ne '1') {
die "ultravnc_repeater.pl: invalid ULTRAVNC_REPEATER_LOOP.\n";
}
if ($csl eq 'BG') {
# go into bg as "daemon":
setpgrp(0, 0);
my $pid = fork();
if (! defined $pid) {
die "ultravnc_repeater.pl: $!\n";
} elsif ($pid) {
wait;
exit 0;
}
if (fork) {
exit 0;
}
setpgrp(0, 0);
close STDIN;
if (! $ENV{ULTRAVNC_REPEATER_LOGFILE}) {
close STDOUT;
close STDERR;
}
}
delete $ENV{ULTRAVNC_REPEATER_LOOP};
if (exists $ENV{ULTRAVNC_REPEATER_PIDFILE}) {
open_pidfile();
}
print STDERR "ultravnc_repeater.pl: starting service at ", scalar(localtime), " master-pid=$$\n";
while (1) {
$looppid = fork;
if (! defined $looppid) {
sleep 10;
} elsif ($looppid) {
wait;
} else {
exec $0, @ARGV;
exit 1;
}
print STDERR "ultravnc_repeater.pl: re-starting service at ", scalar(localtime), " master-pid=$$\n";
sleep 1;
}
exit 0;
}
if (exists $ENV{ULTRAVNC_REPEATER_PIDFILE}) {
open_pidfile();
}
# End of background/daemon stuff.
####################################################################
use warnings;
use IO::Socket::INET; use IO::Socket::INET;
use IO::Select; use IO::Select;
...@@ -85,6 +205,7 @@ my ($RIN, $WIN, $EIN, $ROUT); ...@@ -85,6 +205,7 @@ my ($RIN, $WIN, $EIN, $ROUT);
my $client_listen = IO::Socket::INET->new( my $client_listen = IO::Socket::INET->new(
Listen => 10, Listen => 10,
LocalPort => $client_port, LocalPort => $client_port,
ReuseAddr => 1,
Proto => "tcp" Proto => "tcp"
); );
if (! $client_listen) { if (! $client_listen) {
...@@ -95,6 +216,7 @@ if (! $client_listen) { ...@@ -95,6 +216,7 @@ if (! $client_listen) {
my $server_listen = IO::Socket::INET->new( my $server_listen = IO::Socket::INET->new(
Listen => 10, Listen => 10,
LocalPort => $server_port, LocalPort => $server_port,
ReuseAddr => 1,
Proto => "tcp" Proto => "tcp"
); );
if (! $server_listen) { if (! $server_listen) {
...@@ -103,7 +225,7 @@ if (! $server_listen) { ...@@ -103,7 +225,7 @@ if (! $server_listen) {
} }
my $select = new IO::Select(); my $select = new IO::Select();
if (! select) { if (! $select) {
cleanup(); cleanup();
die "$prog: select $!\n"; die "$prog: select $!\n";
} }
...@@ -120,9 +242,6 @@ my $CURR = ''; ...@@ -120,9 +242,6 @@ my $CURR = '';
print "watching for connections on ports $server_port/server and $client_port/client\n"; print "watching for connections on ports $server_port/server and $client_port/client\n";
select(STDERR); $| = 1;
select(STDOUT); $| = 1;
my $alarm_sock = ''; my $alarm_sock = '';
my $got_alarm = 0; my $got_alarm = 0;
sub alarm_handler { sub alarm_handler {
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
...@@ -47,7 +47,7 @@ int xtrap_base_event_type = 0; ...@@ -47,7 +47,7 @@ int xtrap_base_event_type = 0;
int xdamage_base_event_type = 0; int xdamage_base_event_type = 0;
/* date +'lastmod: %Y-%m-%d' */ /* date +'lastmod: %Y-%m-%d' */
char lastmod[] = "0.9.10 lastmod: 2010-02-21"; char lastmod[] = "0.9.10 lastmod: 2010-03-20";
/* X display info */ /* X display info */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment