x11vnc: X11VNC_DISABLE_SSL_CLIENT_MODE option to disable SSL

client role in reverse connections.  Improvements to logging in
          ultravnc_repeater, ULTRAVNC_REPEATER_NO_RFB option.  Increase
          SSL timeout and print message if 'repeater' mode is detected for
          reverse SSL connection.  Fix RECORD scroll XCopyArea detection
          with recent gtk/gdk library; set X11VNC_SCROLL_MUST_EQUAL
          to disable.  Limit logging of RECORD error messages.
pull/1/head
runge 15 years ago
parent 8d79a63d3c
commit 59c0ae4093

@ -1,3 +1,12 @@
2010-05-01 Karl Runge <runge@karlrunge.com>
* x11vnc: X11VNC_DISABLE_SSL_CLIENT_MODE option to disable SSL
client role in reverse connections. Improvements to logging in
ultravnc_repeater, ULTRAVNC_REPEATER_NO_RFB option. Increase
SSL timeout and print message if 'repeater' mode is detected for
reverse SSL connection. Fix RECORD scroll XCopyArea detection
with recent gtk/gdk library; set X11VNC_SCROLL_MUST_EQUAL
to disable. Limit logging of RECORD error messages.
2010-04-25 Karl Runge <runge@karlrunge.com> 2010-04-25 Karl Runge <runge@karlrunge.com>
* x11vnc: incorporate new ultravnc_dsm_helper.c, add pointer_mask * x11vnc: incorporate new ultravnc_dsm_helper.c, add pointer_mask
remote control query. Cut openssl default -ping delay. remote control query. Cut openssl default -ping delay.

@ -2,7 +2,7 @@
Copyright (C) 2002-2010 Karl J. Runge <runge@karlrunge.com> Copyright (C) 2002-2010 Karl J. Runge <runge@karlrunge.com>
All rights reserved. All rights reserved.
x11vnc README file Date: Fri Apr 23 00:36:17 EDT 2010 x11vnc README file Date: Fri Apr 30 00:43:58 EDT 2010
The following information is taken from these URLs: The following information is taken from these URLs:
@ -34,7 +34,8 @@ x11vnc: a VNC server for real X displays
advertising; and TightVNC and UltraVNC file-transfer. It has also been advertising; and TightVNC and UltraVNC file-transfer. It has also been
extended to work with non-X devices: natively on Mac OS X Aqua/Quartz, extended to work with non-X devices: natively on Mac OS X Aqua/Quartz,
webcams and TV tuner capture devices, and embedded Linux systems such webcams and TV tuner capture devices, and embedded Linux systems such
as Qtopia Core. More features are described here. as Qtopia Core. Full IPv6 support is provided. More features are
described here.
It also provides an encrypted Terminal Services mode (-create, -svc, It also provides an encrypted Terminal Services mode (-create, -svc,
or -xdmsvc options) based on Unix usernames and Unix passwords where or -xdmsvc options) based on Unix usernames and Unix passwords where
@ -56,14 +57,10 @@ x11vnc: a VNC server for real X displays
to many problems; and interesting applications, but nevertheless to many problems; and interesting applications, but nevertheless
please feel free to contact me if you have problems or questions (and please feel free to contact me if you have problems or questions (and
if I save you time or expense by giving you some of my time, please if I save you time or expense by giving you some of my time, please
consider a PayPal Donation.) consider a PayPal Donation.) Do check the FAQ and this page first; I
realize the pages are massive, but you can often use your browser's
Do check the FAQ and this page first; I realize the pages are massive, find-in-page search action using a keyword to find the answer to your
but you can often use your browser's find-in-page search action using problem or question.
a keyword to find the answer to your problem or question.
Please help test the performance speedup feature using viewer-side
pixel caching "ncache".
SSVNC: An x11vnc side-project provides an Enhanced TightVNC Viewer SSVNC: An x11vnc side-project provides an Enhanced TightVNC Viewer
package (SSVNC) for Unix, Windows, and Mac OS X with automatic SSL package (SSVNC) for Unix, Windows, and Mac OS X with automatic SSL
@ -948,14 +945,16 @@ make
from being downloaded successfully in single-port HTTPS/VNC inetd from being downloaded successfully in single-port HTTPS/VNC inetd
mode. The env. var. X11VNC_HTTPS_DOWNLOAD_WAIT_TIME can be used to mode. The env. var. X11VNC_HTTPS_DOWNLOAD_WAIT_TIME can be used to
adjust for how many seconds a -inetd or -https httpd download is adjust for how many seconds a -inetd or -https httpd download is
waited for (default 15 seconds.) waited for (default 15 seconds.) The applet will now autodetect
* The TightVNC sercurity type (TightVNC features enabler) now works x11vnc and use GET=1 for faster connecting. Many other
improvements and fixes.
* The TightVNC security type (TightVNC features enabler) now works
for RFB version 3.8. for RFB version 3.8.
* The X property X11VNC_TRAP_XRANDR can be set on a desktop to force * The X property X11VNC_TRAP_XRANDR can be set on a desktop to force
x11vnc to use the -xrandr screen size change trapping code. x11vnc to use the -xrandr screen size change trapping code.
* New remote control query options: pointer_x, pointer_y, * New remote control query options: pointer_x, pointer_y,
pointer_same, and pointer_root. A demo script using them pointer_same, pointer_root, and pointer_mask. A demo script using
misc/panner.pl is provided. them misc/panner.pl is provided.
* The -sslScripts option prints out the SSL certificate management * The -sslScripts option prints out the SSL certificate management
scripts. scripts.
@ -1567,7 +1566,9 @@ LAY
* Using -threads can expose some bugs/crashes in libvncserver. * Using -threads can expose some bugs/crashes in libvncserver.
Please feel free to contact me if you have any questions, problems, or Please feel free to contact me if you have any questions, problems, or
comments about x11vnc, etc. comments about x11vnc, etc. Please be polite, thorough, and not
demanding (sadly, the number of people contacting me that are rude and
demanding is increasing dramatically.)
Also, some people ask if they can make a donation, see this link for Also, some people ask if they can make a donation, see this link for
that. that.
@ -2234,8 +2235,8 @@ libssl.so libcrypto.so libcrypt.so
This is most likely due to you not having a working build environment This is most likely due to you not having a working build environment
for the XTEST client library libXtst.so. The library is probably for the XTEST client library libXtst.so. The library is probably
present on your system, but the package installing the development present on your system, but the package installing the build header
header file is missing. file is missing.
If you were watching carefully while configure was running you would If you were watching carefully while configure was running you would
have seen: have seen:
@ -12078,7 +12079,7 @@ x11vnc: a VNC server for real X displays
Here are all of x11vnc command line options: Here are all of x11vnc command line options:
% x11vnc -opts (see below for -help long descriptions) % x11vnc -opts (see below for -help long descriptions)
x11vnc: allow VNC connections to real X11 displays. 0.9.10 lastmod: 2010-04-22 x11vnc: allow VNC connections to real X11 displays. 0.9.10 lastmod: 2010-04-28
x11vnc options: x11vnc options:
-display disp -auth file -N -display disp -auth file -N
@ -12208,7 +12209,7 @@ libvncserver-tight-extension options:
% x11vnc -help % x11vnc -help
x11vnc: allow VNC connections to real X11 displays. 0.9.10 lastmod: 2010-04-22 x11vnc: allow VNC connections to real X11 displays. 0.9.10 lastmod: 2010-04-28
(type "x11vnc -opts" to just list the options.) (type "x11vnc -opts" to just list the options.)
@ -12786,6 +12787,28 @@ Options:
See also the -proxy option below for additional ways See also the -proxy option below for additional ways
to plumb reverse connections. to plumb reverse connections.
Reverse SSL: using -connect in -ssl mode makes x11vnc
act as an SSL client (initiates SSL connection) rather
than an SSL server. The idea is x11vnc might be
connecting to stunnel on the viewer side with the
viewer in listening mode. If you do not want this
behavior, use -env X11VNC_DISABLE_SSL_CLIENT_MODE=1.
With this the viewer side can act as the SSL client
as it normally does for forward connections.
Reverse SSL Repeater mode: This will work, but note
that if the VNC Client does any sort of a 'Fetch Cert'
action before connecting, then the Repeater will
likely drop the connection and both sides will need
to restart. Consider the use of -connect_or_exit
and -loop300,2 to have x11vnc reconnect once to the
repeater after the fetch. You will probably also want
to supply -sslonly to avoid x11vnc thinking the delay
in response means the connection is VeNCrypt. The env
var X11VNC_DISABLE_SSL_CLIENT_MODE=1 discussed above
may also be useful (i.e. the viewer can do a forward
connection as it normally does.)
IPv6: as of x11vnc 0.9.10 the -connect option should IPv6: as of x11vnc 0.9.10 the -connect option should
connect to IPv6 hosts properly. If there are problems connect to IPv6 hosts properly. If there are problems
you can disable IPv6 by setting -DX11VNC_IPV6=0 you can disable IPv6 by setting -DX11VNC_IPV6=0

@ -2644,7 +2644,9 @@ static int do_reverse_connect(char *str_in) {
} }
/* XXX use header */ /* XXX use header */
#define OPENSSL_REVERSE 6 #define OPENSSL_REVERSE 6
openssl_init(1); if (!getenv("X11VNC_DISABLE_SSL_CLIENT_MODE")) {
openssl_init(1);
}
if (first_conn_timeout > 0) { if (first_conn_timeout > 0) {
set_alarm = 1; set_alarm = 1;

@ -642,6 +642,28 @@ void print_help(int mode) {
" See also the -proxy option below for additional ways\n" " See also the -proxy option below for additional ways\n"
" to plumb reverse connections.\n" " to plumb reverse connections.\n"
"\n" "\n"
" Reverse SSL: using -connect in -ssl mode makes x11vnc\n"
" act as an SSL client (initiates SSL connection) rather\n"
" than an SSL server. The idea is x11vnc might be\n"
" connecting to stunnel on the viewer side with the\n"
" viewer in listening mode. If you do not want this\n"
" behavior, use -env X11VNC_DISABLE_SSL_CLIENT_MODE=1.\n"
" With this the viewer side can act as the SSL client\n"
" as it normally does for forward connections.\n"
"\n"
" Reverse SSL Repeater mode: This will work, but note\n"
" that if the VNC Client does any sort of a 'Fetch Cert'\n"
" action before connecting, then the Repeater will\n"
" likely drop the connection and both sides will need\n"
" to restart. Consider the use of -connect_or_exit\n"
" and -loop300,2 to have x11vnc reconnect once to the\n"
" repeater after the fetch. You will probably also want\n"
" to supply -sslonly to avoid x11vnc thinking the delay\n"
" in response means the connection is VeNCrypt. The env\n"
" var X11VNC_DISABLE_SSL_CLIENT_MODE=1 discussed above\n"
" may also be useful (i.e. the viewer can do a forward\n"
" connection as it normally does.)\n"
"\n"
" IPv6: as of x11vnc 0.9.10 the -connect option should\n" " IPv6: as of x11vnc 0.9.10 the -connect option should\n"
" connect to IPv6 hosts properly. If there are problems\n" " connect to IPv6 hosts properly. If there are problems\n"
" you can disable IPv6 by setting -DX11VNC_IPV6=0\n" " you can disable IPv6 by setting -DX11VNC_IPV6=0\n"

@ -50,6 +50,8 @@ ULTRAVNC_REPEATER_LOOP=1 or ULTRAVNC_REPEATER_LOOP=BG, the latter
forks into the background. Set ULTRAVNC_REPEATER_PIDFILE to a file forks into the background. Set ULTRAVNC_REPEATER_PIDFILE to a file
to store the master pid in. to store the master pid in.
Set ULTRAVNC_REPEATER_NO_RFB=1 to disable sending "RFB 000.000" to
the client. Then this program acts as general TCP rendezvous tool.
Examples: Examples:
@ -83,7 +85,7 @@ my $looppid = '';
my $pidfile = ''; my $pidfile = '';
# #
sub get_out { sub get_out {
print STDERR "$_[0]:\t$$ looppid=$looppid\n"; lprint("$_[0]:\t$$ looppid=$looppid");
if ($looppid) { if ($looppid) {
kill 'TERM', $looppid; kill 'TERM', $looppid;
fsleep(0.2); fsleep(0.2);
@ -93,6 +95,10 @@ sub get_out {
exit 0; exit 0;
} }
sub lprint {
print STDERR scalar(localtime), ": ", @_, "\n";
}
# These are overridden in actual server thread: # These are overridden in actual server thread:
# #
$SIG{INT} = \&get_out; $SIG{INT} = \&get_out;
@ -108,7 +114,7 @@ sub open_pidfile {
close PID; close PID;
$pidfile = $pf; $pidfile = $pf;
} else { } else {
print STDERR "could not open pidfile: $pf - $! - continuing...\n"; lprint("could not open pidfile: $pf - $! - continuing...");
} }
delete $ENV{ULTRAVNC_REPEATER_PIDFILE}; delete $ENV{ULTRAVNC_REPEATER_PIDFILE};
} }
@ -150,7 +156,7 @@ if (exists $ENV{ULTRAVNC_REPEATER_LOOP}) {
open_pidfile(); open_pidfile();
} }
print STDERR "ultravnc_repeater.pl: starting service at ", scalar(localtime), " master-pid=$$\n"; lprint("ultravnc_repeater.pl: starting service. master-pid=$$");
while (1) { while (1) {
$looppid = fork; $looppid = fork;
if (! defined $looppid) { if (! defined $looppid) {
@ -161,7 +167,7 @@ if (exists $ENV{ULTRAVNC_REPEATER_LOOP}) {
exec $0, @ARGV; exec $0, @ARGV;
exit 1; exit 1;
} }
print STDERR "ultravnc_repeater.pl: re-starting service at ", scalar(localtime), " master-pid=$$\n"; lprint("ultravnc_repeater.pl: re-starting service. master-pid=$$");
sleep 1; sleep 1;
} }
exit 0; exit 0;
@ -184,7 +190,7 @@ eval "use IO::Socket::INET6;";
$have_inet6 = 1 if $@ eq ""; $have_inet6 = 1 if $@ eq "";
print "perl module IO::Socket::INET6 not available: no IPv6 support.\n" if ! $have_inet6; print "perl module IO::Socket::INET6 not available: no IPv6 support.\n" if ! $have_inet6;
my $prog = 'ultravnc_repeater.pl'; my $prog = 'ultravnc_repeater';
my %ID; my %ID;
my $refuse = 0; my $refuse = 0;
@ -196,7 +202,7 @@ if (@ARGV && $ARGV[0] =~ /-h/) {
} }
if (@ARGV && $ARGV[0] eq '-r') { if (@ARGV && $ARGV[0] eq '-r') {
$refuse = 1; $refuse = 1;
print "enabling refuse mode (-r).\n"; lprint("enabling refuse mode (-r).");
shift; shift;
} }
@ -285,15 +291,16 @@ my $SOCK1 = '';
my $SOCK2 = ''; my $SOCK2 = '';
my $CURR = ''; my $CURR = '';
print "watching for IPv4 connections on $client_port/client\n" if $client_listen; lprint("$prog: starting up. pid: $$");
print "watching for IPv4 connections on $server_port/server\n" if $server_listen; lprint("watching for IPv4 connections on $client_port/client.") if $client_listen;
print "watching for IPv6 connections on $client_port/client\n" if $client_listen6; lprint("watching for IPv4 connections on $server_port/server.") if $server_listen;
print "watching for IPv6 connections on $server_port/server\n" if $server_listen6; lprint("watching for IPv6 connections on $client_port/client.") if $client_listen6;
lprint("watching for IPv6 connections on $server_port/server.") if $server_listen6;
my $alarm_sock = ''; my $alarm_sock = '';
my $got_alarm = 0; my $got_alarm = 0;
sub alarm_handler { sub alarm_handler {
print "$prog: got sig alarm.\n"; lprint("$prog: got sig alarm.");
if ($alarm_sock ne '') { if ($alarm_sock ne '') {
close $alarm_sock; close $alarm_sock;
} }
@ -303,24 +310,28 @@ sub alarm_handler {
while (my @ready = $select->can_read()) { while (my @ready = $select->can_read()) {
foreach my $fh (@ready) { foreach my $fh (@ready) {
if ($fh == $client_listen || $fh == $client_listen6) { if (($client_listen && $fh == $client_listen) || ($client_listen6 && $fh == $client_listen6)) {
print "new vnc client connecting at ", scalar(localtime), "\n"; lprint("new vnc client connecting.");
} elsif ($fh == $server_listen || $fh == $server_listen6) { } elsif (($server_listen && $fh == $server_listen) || ($server_listen6 && $fh == $server_listen6)) {
print "new vnc server connecting at ", scalar(localtime), "\n"; lprint("new vnc server connecting.");
} }
my $sock = $fh->accept(); my $sock = $fh->accept();
if (! $sock) { if (! $sock) {
print "$prog: accept $!\n"; lprint("$prog: accept $!");
next; next;
} }
if ($fh == $client_listen || $fh == $client_listen6) { if (($client_listen && $fh == $client_listen) || ($client_listen6 && $fh == $client_listen6)) {
my $str = "RFB 000.000\n"; if (exists $ENV{ULTRAVNC_REPEATER_NO_RFB} && $ENV{ULTRAVNC_REPEATER_NO_RFB}) {
my $len = length $str; lprint("ULTRAVNC_REPEATER_NO_RFB: not sending RFB 000.000");
my $n = syswrite($sock, $str, $len, 0); } else {
if ($n != $len) { my $str = "RFB 000.000\n";
print "$prog: bad $str write: $n != $len $!\n"; my $len = length $str;
close $sock; my $n = syswrite($sock, $str, $len, 0);
if ($n != $len) {
lprint("$prog: bad $str write: $n != $len $!");
close $sock;
}
} }
} }
@ -336,15 +347,15 @@ while (my @ready = $select->can_read()) {
alarm(0); alarm(0);
if ($got_alarm) { if ($got_alarm) {
print "$prog: read timed out: $!\n"; lprint("$prog: read timed out: $!");
} elsif (! defined $n) { } elsif (! defined $n) {
print "$prog: read error: $!\n"; lprint("$prog: read error: $!");
} elsif ($repeater_bufsize > 0 && $n != $size) { } elsif ($repeater_bufsize > 0 && $n != $size) {
print "$prog: short read $n != $size $!\n"; lprint("$prog: short read $n != $size $!");
close $sock; close $sock;
} elsif ($fh == $client_listen || $fh == $client_listen6) { } elsif (($client_listen && $fh == $client_listen) || ($client_listen6 && $fh == $client_listen6)) {
do_new_client($sock, $buf); do_new_client($sock, $buf);
} elsif ($fh == $server_listen || $fh == $server_listen6) { } elsif (($server_listen && $fh == $server_listen) || ($server_listen6 && $fh == $server_listen6)) {
do_new_server($sock, $buf); do_new_server($sock, $buf);
} }
} }
@ -355,33 +366,42 @@ sub do_new_client {
if ($buf =~ /^ID:(\w+)/) { if ($buf =~ /^ID:(\w+)/) {
my $id = $1; my $id = $1;
if (exists $ID{$id} && exists $ID{$id}{client} && $ID{$id}{client} eq "0") {
if (!established($ID{$id}{sock})) {
lprint("server socket for ID:$id is no longer established, closing it.");
close $ID{$id}{sock};
delete $ID{$id};
} else {
lprint("server socket for ID:$id is still established.");
}
}
if (exists $ID{$id}) { if (exists $ID{$id}) {
if ($ID{$id}{client}) { if ($ID{$id}{client}) {
my $ref = $refuse; my $ref = $refuse;
if ($ref && !established($ID{$id}{sock})) { if ($ref && !established($ID{$id}{sock})) {
print "socket for ID:$id is no longer established, closing it.\n"; lprint("socket for ID:$id is no longer established, closing it.");
$ref = 0; $ref = 0;
} }
if ($ref) { if ($ref) {
print "refusing extra vnc client for ID:$id\n"; lprint("refusing extra vnc client for ID:$id.");
close $sock; close $sock;
return; return;
} else { } else {
print "closing and deleting previous vnc client with ID:$id\n"; lprint("closing and deleting previous vnc client with ID:$id.");
close $ID{$id}{sock}; close $ID{$id}{sock};
print "storing new vnc client with ID:$id\n"; lprint("storing new vnc client with ID:$id.");
$ID{$id}{client} = 1; $ID{$id}{client} = 1;
$ID{$id}{sock} = $sock; $ID{$id}{sock} = $sock;
} }
} else { } else {
print "hooking up new vnc client with existing vnc server for ID:$id\n"; lprint("hooking up new vnc client with existing vnc server for ID:$id.");
my $sock2 = $ID{$id}{sock}; my $sock2 = $ID{$id}{sock};
delete $ID{$id}; delete $ID{$id};
hookup($sock, $sock2, "ID:$id"); hookup($sock, $sock2, "ID:$id");
} }
} else { } else {
print "storing new vnc client with ID:$id\n"; lprint("storing new vnc client with ID:$id.");
$ID{$id}{client} = 1; $ID{$id}{client} = 1;
$ID{$id}{sock} = $sock; $ID{$id}{sock} = $sock;
} }
@ -400,32 +420,32 @@ sub do_new_client {
} }
if ($port < 0) { if ($port < 0) {
my $pnew = -$port; my $pnew = -$port;
print "resetting port from $port to $pnew\n"; lprint("resetting port from $port to $pnew.");
$port = $pnew; $port = $pnew;
} elsif ($port < 200) { } elsif ($port < 200) {
my $pnew = $port + 5900; my $pnew = $port + 5900;
print "resetting port from $port to $pnew\n"; lprint("resetting port from $port to $pnew.");
$port = $pnew; $port = $pnew;
} }
print "making vnc client connection directly to vnc server host='$host' port='$port'\n"; lprint("making vnc client connection directly to vnc server host='$host' port='$port'.");
my $sock2 = IO::Socket::INET->new( my $sock2 = IO::Socket::INET->new(
PeerAddr => $host, PeerAddr => $host,
PeerPort => $port, PeerPort => $port,
Proto => "tcp" Proto => "tcp"
); );
if (! $sock2 && $have_inet6) { if (! $sock2 && $have_inet6) {
print "IPv4 connect error: $!, trying IPv6 ...\n"; lprint("IPv4 connect error: $!, trying IPv6 ...");
eval{$sock2 = IO::Socket::INET6->new( eval{$sock2 = IO::Socket::INET6->new(
PeerAddr => $host, PeerAddr => $host,
PeerPort => $port, PeerPort => $port,
Proto => "tcp" Proto => "tcp"
);}; );};
print "IPv6 connect error: $!\n" if !$sock2; lprint("IPv6 connect error: $!") if !$sock2;
} else { } else {
print "IPv4 connect error: $!\n" if !$sock2; lprint("IPv4 connect error: $!") if !$sock2;
} }
if (!$sock2) { if (!$sock2) {
print "failed to connect to $host:$port\n"; lprint("failed to connect to $host:$port.");
close $sock; close $sock;
return; return;
} }
@ -439,48 +459,79 @@ sub do_new_server {
if ($buf =~ /^ID:(\w+)/) { if ($buf =~ /^ID:(\w+)/) {
my $id = $1; my $id = $1;
my $store = 1; my $store = 1;
if (exists $ID{$id} && exists $ID{$id}{client} && $ID{$id}{client} eq "1") {
if (!established($ID{$id}{sock})) {
lprint("client socket for ID:$id is no longer established, closing it.");
close $ID{$id}{sock};
delete $ID{$id};
} else {
lprint("client socket for ID:$id is still established.");
}
}
if (exists $ID{$id}) { if (exists $ID{$id}) {
if (! $ID{$id}{client}) { if (! $ID{$id}{client}) {
my $ref = $refuse; my $ref = $refuse;
if ($ref && !established($ID{$id}{sock})) { if ($ref && !established($ID{$id}{sock})) {
print "socket for ID:$id is no longer established, closing it.\n"; lprint("socket for ID:$id is no longer established, closing it.");
$ref = 0; $ref = 0;
} }
if ($ref) { if ($ref) {
print "refusing extra vnc server for ID:$id\n"; lprint("refusing extra vnc server for ID:$id.");
close $sock; close $sock;
return; return;
} else { } else {
print "closing and deleting previous vnc server with ID:$id\n"; lprint("closing and deleting previous vnc server with ID:$id.");
close $ID{$id}{sock}; close $ID{$id}{sock};
print "storing new vnc server with ID:$id\n"; lprint("storing new vnc server with ID:$id.");
$ID{$id}{client} = 0; $ID{$id}{client} = 0;
$ID{$id}{sock} = $sock; $ID{$id}{sock} = $sock;
} }
} else { } else {
print "hooking up new vnc server with existing vnc client for ID:$id\n"; lprint("hooking up new vnc server with existing vnc client for ID:$id.");
my $sock2 = $ID{$id}{sock}; my $sock2 = $ID{$id}{sock};
delete $ID{$id}; delete $ID{$id};
hookup($sock, $sock2, "ID:$id"); hookup($sock, $sock2, "ID:$id");
} }
} else { } else {
print "storing new vnc server with ID:$id\n"; lprint("storing new vnc server with ID:$id.");
$ID{$id}{client} = 0; $ID{$id}{client} = 0;
$ID{$id}{sock} = $sock; $ID{$id}{sock} = $sock;
} }
} else { } else {
print "invalid ID:NNNNN string for vnc server: $buf\n"; lprint("invalid ID:NNNNN string for vnc server: $buf");
close $sock; close $sock;
return; return;
} }
} }
sub established { sub established {
my $fh = shift;
return established_linux_proc($fh);
# not working:
my $est = 1;
my $str = "Z";
my $res;
#$res = recv($fh, $str, 1, MSG_PEEK | MSG_DONTWAIT);
if (defined($res)) {
lprint("established OK: $! '$str'.");
$est = 1;
} else {
# would check for EAGAIN here to decide ...
lprint("established err: $! '$str'.");
$est = 1;
}
return $est;
}
sub established_linux_proc {
# hack for Linux to see if remote side has gone away: # hack for Linux to see if remote side has gone away:
my $fh = shift; my $fh = shift;
# if we can't figure things out, we return true. # if we can't figure things out, we must return true.
if ($uname !~ /Linux/) { if ($uname !~ /Linux/) {
return 1; return 1;
} }
@ -549,7 +600,7 @@ sub established {
} }
sub handler { sub handler {
print STDERR "$prog\[$$/$CURR]: got SIGTERM.\n"; lprint("\[$$/$CURR] got SIGTERM.");
close $SOCK1 if $SOCK1; close $SOCK1 if $SOCK1;
close $SOCK2 if $SOCK2; close $SOCK2 if $SOCK2;
exit; exit;
@ -561,7 +612,7 @@ sub hookup {
my $worker = fork(); my $worker = fork();
if (! defined $worker) { if (! defined $worker) {
print "failed to fork worker: $!\n"; lprint("failed to fork worker: $!");
close $sock1; close $sock1;
close $sock2; close $sock2;
return; return;
@ -604,10 +655,10 @@ sub xfer {
my $len = sysread($in, $buf, 8192); my $len = sysread($in, $buf, 8192);
if (! defined($len)) { if (! defined($len)) {
next if $! =~ /^Interrupted/; next if $! =~ /^Interrupted/;
print STDERR "$prog\[$$/$CURR]: $!\n"; lprint("\[$$/$CURR] $!");
last; last;
} elsif ($len == 0) { } elsif ($len == 0) {
print STDERR "$prog\[$$/$CURR]: Input is EOF.\n"; lprint("\[$$/$CURR] Input is EOF.");
last; last;
} }
my $offset = 0; my $offset = 0;
@ -615,7 +666,7 @@ sub xfer {
while ($len) { while ($len) {
my $written = syswrite($out, $buf, $len, $offset); my $written = syswrite($out, $buf, $len, $offset);
if (! defined $written) { if (! defined $written) {
print STDERR "$prog\[$$/$CURR]: Output is EOF. $!\n"; lprint("\[$$/$CURR] Output is EOF. $!");
$quit = 1; $quit = 1;
last; last;
} }
@ -626,7 +677,7 @@ sub xfer {
} }
close($out); close($out);
close($in); close($in);
print STDERR "$prog\[$$/$CURR]: finished xfer.\n"; lprint("\[$$/$CURR] finished xfer.");
} }
sub xfer_both { sub xfer_both {
@ -637,7 +688,7 @@ sub xfer_both {
my $child = fork(); my $child = fork();
if (! defined $child) { if (! defined $child) {
print STDERR "$prog\[$$/$CURR] failed to fork: $!\n"; lprint("$prog\[$$/$CURR] failed to fork: $!");
return; return;
} }
@ -645,30 +696,30 @@ sub xfer_both {
$SIG{INT} = "handler"; $SIG{INT} = "handler";
if ($child) { if ($child) {
print STDERR "$prog parent[$$/$CURR] 1 -> 2\n"; lprint("[$$/$CURR] parent 1 -> 2.");
xfer($sock1, $sock2); xfer($sock1, $sock2);
select(undef, undef, undef, 0.25); select(undef, undef, undef, 0.25);
if (kill 0, $child) { if (kill 0, $child) {
select(undef, undef, undef, 0.9); select(undef, undef, undef, 0.9);
if (kill 0, $child) { if (kill 0, $child) {
print STDERR "$prog\[$$/$CURR]: kill TERM child $child\n"; lprint("\[$$/$CURR] kill TERM child $child");
kill "TERM", $child; kill "TERM", $child;
} else { } else {
print STDERR "$prog\[$$/$CURR]: child $child gone.\n"; lprint("\[$$/$CURR] child $child gone.");
} }
} }
} else { } else {
select(undef, undef, undef, 0.05); select(undef, undef, undef, 0.05);
print STDERR "$prog child [$$/$CURR] 2 -> 1\n"; lprint("[$$/$CURR] child 2 -> 1.");
xfer($sock2, $sock1); xfer($sock2, $sock1);
select(undef, undef, undef, 0.25); select(undef, undef, undef, 0.25);
if (kill 0, $parent) { if (kill 0, $parent) {
select(undef, undef, undef, 0.8); select(undef, undef, undef, 0.8);
if (kill 0, $parent) { if (kill 0, $parent) {
print STDERR "$prog\[$$/$CURR]: kill TERM parent $parent\n"; lprint("\[$$/$CURR] kill TERM parent $parent.");
kill "TERM", $parent; kill "TERM", $parent;
} else { } else {
print STDERR "$prog\[$$/$CURR]: parent $parent gone.\n"; lprint("\[$$/$CURR] parent $parent gone.");
} }
} }
} }

@ -1923,6 +1923,8 @@ static void pr_ssl_info(int verb) {
static void ssl_timeout (int sig) { static void ssl_timeout (int sig) {
int i; int i;
rfbLog("sig: %d, ssl_init[%d] timed out.\n", sig, getpid()); rfbLog("sig: %d, ssl_init[%d] timed out.\n", sig, getpid());
rfbLog("To increase the SSL initialization timeout use, e.g.:\n");
rfbLog(" -env SSL_INIT_TIMEOUT=120 (for 120 seconds)\n");
for (i=0; i < 256; i++) { for (i=0; i < 256; i++) {
close(i); close(i);
} }
@ -1944,10 +1946,17 @@ static int ssl_init(int s_in, int s_out, int skip_vnc_tls, double last_https) {
if (getenv("SSL_DEBUG")) { if (getenv("SSL_DEBUG")) {
db = atoi(getenv("SSL_DEBUG")); db = atoi(getenv("SSL_DEBUG"));
} }
usleep(100 * 1000);
if (getenv("SSL_INIT_TIMEOUT")) { if (getenv("SSL_INIT_TIMEOUT")) {
timeout = atoi(getenv("SSL_INIT_TIMEOUT")); timeout = atoi(getenv("SSL_INIT_TIMEOUT"));
} else if (client_connect != NULL && strstr(client_connect, "repeater")) {
rfbLog("SSL: ssl_init[%d]: detected 'repeater' in connect string.\n", getpid());
rfbLog("SSL: setting timeout to 1 hour: -env SSL_INIT_TIMEOUT=3600\n");
rfbLog("SSL: use that option to set a different timeout value,\n");
rfbLog("SSL: however note that with Windows UltraVNC repeater it\n");
rfbLog("SSL: may timeout before your setting due to other reasons.\n");
timeout = 3600;
} }
if (db) fprintf(stderr, "ssl_init: %d/%d\n", s_in, s_out);
if (skip_vnc_tls) { if (skip_vnc_tls) {
rfbLog("SSL: ssl_helper[%d]: HTTPS mode, skipping check_vnc_tls_mode()\n", rfbLog("SSL: ssl_helper[%d]: HTTPS mode, skipping check_vnc_tls_mode()\n",
@ -1955,6 +1964,8 @@ static int ssl_init(int s_in, int s_out, int skip_vnc_tls, double last_https) {
} else if (!check_vnc_tls_mode(s_in, s_out, last_https)) { } else if (!check_vnc_tls_mode(s_in, s_out, last_https)) {
return 0; return 0;
} }
rfbLog("SSL: ssl_init[%d]: %d/%d initialization timeout: %d secs.\n",
getpid(), s_in, s_out, timeout);
ssl = SSL_new(ctx); ssl = SSL_new(ctx);
if (ssl == NULL) { if (ssl == NULL) {
@ -2026,32 +2037,32 @@ static int ssl_init(int s_in, int s_out, int skip_vnc_tls, double last_https) {
} else if (err == SSL_ERROR_WANT_READ) { } else if (err == SSL_ERROR_WANT_READ) {
if (db) fprintf(stderr, "got SSL_ERROR_WANT_READ\n"); if (db) fprintf(stderr, "got SSL_ERROR_WANT_READ\n");
rfbLog("SSL: ssl_helper[%d]: SSL_accept() failed for: %s:%d\n", rfbLog("SSL: ssl_helper[%d]: %s() failed for: %s:%d 1\n",
getpid(), name, peerport); getpid(), ssl_client_mode ? "SSL_connect" : "SSL_accept", name, peerport);
pr_ssl_info(1); pr_ssl_info(1);
return 0; return 0;
} else if (err == SSL_ERROR_WANT_WRITE) { } else if (err == SSL_ERROR_WANT_WRITE) {
if (db) fprintf(stderr, "got SSL_ERROR_WANT_WRITE\n"); if (db) fprintf(stderr, "got SSL_ERROR_WANT_WRITE\n");
rfbLog("SSL: ssl_helper[%d]: SSL_accept() failed for: %s:%d\n", rfbLog("SSL: ssl_helper[%d]: %s() failed for: %s:%d 2\n",
getpid(), name, peerport); getpid(), ssl_client_mode ? "SSL_connect" : "SSL_accept", name, peerport);
pr_ssl_info(1); pr_ssl_info(1);
return 0; return 0;
} else if (err == SSL_ERROR_SYSCALL) { } else if (err == SSL_ERROR_SYSCALL) {
if (db) fprintf(stderr, "got SSL_ERROR_SYSCALL\n"); if (db) fprintf(stderr, "got SSL_ERROR_SYSCALL\n");
rfbLog("SSL: ssl_helper[%d]: SSL_accept() failed for: %s:%d\n", rfbLog("SSL: ssl_helper[%d]: %s() failed for: %s:%d 3\n",
getpid(), name, peerport); getpid(), ssl_client_mode ? "SSL_connect" : "SSL_accept", name, peerport);
pr_ssl_info(1); pr_ssl_info(1);
return 0; return 0;
} else if (err == SSL_ERROR_ZERO_RETURN) { } else if (err == SSL_ERROR_ZERO_RETURN) {
if (db) fprintf(stderr, "got SSL_ERROR_ZERO_RETURN\n"); if (db) fprintf(stderr, "got SSL_ERROR_ZERO_RETURN\n");
rfbLog("SSL: ssl_helper[%d]: SSL_accept() failed for: %s:%d\n", rfbLog("SSL: ssl_helper[%d]: %s() failed for: %s:%d 4\n",
getpid(), name, peerport); getpid(), ssl_client_mode ? "SSL_connect" : "SSL_accept", name, peerport);
pr_ssl_info(1); pr_ssl_info(1);
return 0; return 0;
@ -2059,7 +2070,8 @@ static int ssl_init(int s_in, int s_out, int skip_vnc_tls, double last_https) {
unsigned long err; unsigned long err;
int cnt = 0; int cnt = 0;
rfbLog("SSL: ssl_helper[%d]: SSL_accept() *FATAL: %d SSL FAILED\n", getpid(), rc); rfbLog("SSL: ssl_helper[%d]: %s() *FATAL: %d SSL FAILED\n",
getpid(), ssl_client_mode ? "SSL_connect" : "SSL_accept", rc);
while ((err = ERR_get_error()) != 0) { while ((err = ERR_get_error()) != 0) {
rfbLog("SSL: %s\n", ERR_error_string(err, NULL)); rfbLog("SSL: %s\n", ERR_error_string(err, NULL));
if (cnt++ > 100) { if (cnt++ > 100) {
@ -2071,8 +2083,8 @@ static int ssl_init(int s_in, int s_out, int skip_vnc_tls, double last_https) {
} else if (dnow() > start + 3.0) { } else if (dnow() > start + 3.0) {
rfbLog("SSL: ssl_helper[%d]: timeout looping SSL_accept() " rfbLog("SSL: ssl_helper[%d]: timeout looping %s() "
"fatal.\n", getpid()); "fatal.\n", getpid(), ssl_client_mode ? "SSL_connect" : "SSL_accept");
pr_ssl_info(1); pr_ssl_info(1);
return 0; return 0;

@ -2,7 +2,7 @@
.TH X11VNC "1" "April 2010" "x11vnc " "User Commands" .TH X11VNC "1" "April 2010" "x11vnc " "User Commands"
.SH NAME .SH NAME
x11vnc - allow VNC connections to real X11 displays x11vnc - allow VNC connections to real X11 displays
version: 0.9.10, lastmod: 2010-04-22 version: 0.9.10, lastmod: 2010-04-28
.SH SYNOPSIS .SH SYNOPSIS
.B x11vnc .B x11vnc
[OPTION]... [OPTION]...
@ -697,6 +697,28 @@ newline and carriage return. "\\c" is expanded to
See also the \fB-proxy\fR option below for additional ways See also the \fB-proxy\fR option below for additional ways
to plumb reverse connections. to plumb reverse connections.
.IP .IP
Reverse SSL: using \fB-connect\fR in \fB-ssl\fR mode makes x11vnc
act as an SSL client (initiates SSL connection) rather
than an SSL server. The idea is x11vnc might be
connecting to stunnel on the viewer side with the
viewer in listening mode. If you do not want this
behavior, use \fB-env\fR X11VNC_DISABLE_SSL_CLIENT_MODE=1.
With this the viewer side can act as the SSL client
as it normally does for forward connections.
.IP
Reverse SSL Repeater mode: This will work, but note
that if the VNC Client does any sort of a 'Fetch Cert'
action before connecting, then the Repeater will
likely drop the connection and both sides will need
to restart. Consider the use of \fB-connect_or_exit\fR
and \fB-loop300,2\fR to have x11vnc reconnect once to the
repeater after the fetch. You will probably also want
to supply \fB-sslonly\fR to avoid x11vnc thinking the delay
in response means the connection is VeNCrypt. The env
var X11VNC_DISABLE_SSL_CLIENT_MODE=1 discussed above
may also be useful (i.e. the viewer can do a forward
connection as it normally does.)
.IP
IPv6: as of x11vnc 0.9.10 the \fB-connect\fR option should IPv6: as of x11vnc 0.9.10 the \fB-connect\fR option should
connect to IPv6 hosts properly. If there are problems connect to IPv6 hosts properly. If there are problems
you can disable IPv6 by setting \fB-DX11VNC_IPV6=0\fR you can disable IPv6 by setting \fB-DX11VNC_IPV6=0\fR

@ -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-04-22"; char lastmod[] = "0.9.10 lastmod: 2010-04-28";
/* X display info */ /* X display info */

@ -535,12 +535,13 @@ static double xrecord_start = 0.0;
static void record_CA(XPointer ptr, XRecordInterceptData *rec_data) { static void record_CA(XPointer ptr, XRecordInterceptData *rec_data) {
xCopyAreaReq *req; xCopyAreaReq *req;
Window src = None, dst = None, c; Window src = None, dst = None, c;
XWindowAttributes attr; XWindowAttributes attr, attr2;
int src_x, src_y, dst_x, dst_y, rx, ry; int src_x, src_y, dst_x, dst_y, rx, ry, rx2, ry2;
int good = 1, dx, dy, k=0, i; int good = 1, dx = 0, dy = 0, k=0, i;
unsigned int w, h; unsigned int w, h;
int dba = 0, db = debug_scroll; int dba = 0, db = debug_scroll;
int cache_index, next_index, valid; int cache_index, next_index, valid;
static int must_equal = -1;
if (dba || db) { if (dba || db) {
if (rec_data->category == XRecordFromClient) { if (rec_data->category == XRecordFromClient) {
@ -584,6 +585,13 @@ if (db > 1) fprintf(stderr, "record_CA-%d\n", k++);
} }
if (db > 1) fprintf(stderr, "record_CA-%d\n", k++); if (db > 1) fprintf(stderr, "record_CA-%d\n", k++);
if (must_equal < 0) {
must_equal = 0;
if (getenv("X11VNC_SCROLL_MUST_EQUAL")) {
must_equal = 1;
}
}
/* /*
xterm, gnome-terminal, others. xterm, gnome-terminal, others.
@ -618,25 +626,36 @@ short period of time with a painting error: two cursors, one above the other.
h = req->height; h = req->height;
if (w*h < (unsigned int) scrollcopyrect_min_area) { if (w*h < (unsigned int) scrollcopyrect_min_area) {
if (db > 1) fprintf(stderr, "record_CA scroll area too small.\n");
good = 0; good = 0;
} else if (!src || !dst) { } else if (!src || !dst) {
good = 0; if (db > 1) fprintf(stderr, "record_CA null src or dst.\n");
} else if (src != dst) {
good = 0; good = 0;
} else if (scr_ev_cnt >= SCR_EV_MAX) { } else if (scr_ev_cnt >= SCR_EV_MAX) {
if (db > 1) fprintf(stderr, "record_CA null too many scr events.\n");
good = 0;
} else if (must_equal && src != dst) {
if (db > 1) fprintf(stderr, "record_CA src not equal dst.\n");
good = 0; good = 0;
} }
dx = dst_x - src_x; if (src == dst) {
dy = dst_y - src_y; dx = dst_x - src_x;
dy = dst_y - src_y;
if (dx != 0 && dy != 0) { if (dx != 0 && dy != 0) {
good = 0; good = 0;
}
} }
if (!good && (dba || db > 1)) fprintf(stderr, "record_CA-x src_x: %d src_y: %d "
"dst_x: %d dst_y: %d w: %d h: %d scr_ev_cnt: %d 0x%lx/0x%lx\n",
src_x, src_y, dst_x, dst_y, w, h, scr_ev_cnt, src, dst);
if (! good) { if (! good) {
return; return;
} }
if (db > 1) fprintf(stderr, "record_CA-%d\n", k++); if (db > 1) fprintf(stderr, "record_CA-%d\n", k++);
/* /*
@ -687,14 +706,84 @@ if (db > 1) fprintf(stderr, "record_CA-%d\n", k++);
} }
if (! valid) { if (! valid) {
if (db > 1) fprintf(stderr, "record_CA not valid-1.\n");
return; return;
} }
if (db > 1) fprintf(stderr, "record_CA-%d\n", k++); if (db > 1) fprintf(stderr, "record_CA-%d\n", k++);
if (attr.map_state != IsViewable) { if (attr.map_state != IsViewable) {
if (db > 1) fprintf(stderr, "record_CA not viewable-1.\n");
return; return;
} }
/* recent gdk/gtk windows use different src and dst. for compositing? */
if (src != dst) {
if (lookup_attr_cache(dst, &cache_index, &next_index)) {
i = cache_index;
attr2.x = scr_attr_cache[i].x;
attr2.y = scr_attr_cache[i].y;
attr2.width = scr_attr_cache[i].width;
attr2.height = scr_attr_cache[i].height;
attr2.map_state = scr_attr_cache[i].map_state;
rx2 = scr_attr_cache[i].rx;
ry2 = scr_attr_cache[i].ry;
valid = scr_attr_cache[i].valid;
} else {
valid = valid_window(dst, &attr2, 1);
if (valid) {
if (!xtranslate(dst, rootwin, 0, 0, &rx2, &ry2, &c, 1)) {
valid = 0;
}
}
if (next_index >= 0) {
i = next_index;
scr_attr_cache[i].win = dst;
scr_attr_cache[i].fetched = 1;
scr_attr_cache[i].valid = valid;
scr_attr_cache[i].time = dnow();
if (valid) {
scr_attr_cache[i].x = attr2.x;
scr_attr_cache[i].y = attr2.y;
scr_attr_cache[i].width = attr2.width;
scr_attr_cache[i].height = attr2.height;
scr_attr_cache[i].border_width = attr2.border_width;
scr_attr_cache[i].depth = attr2.depth;
scr_attr_cache[i].class = attr2.class;
scr_attr_cache[i].backing_store =
attr2.backing_store;
scr_attr_cache[i].map_state = attr2.map_state;
scr_attr_cache[i].rx = rx2;
scr_attr_cache[i].ry = ry2;
}
}
}
if (dba || db > 1) fprintf(stderr, "record_CA-? src_x: %d src_y: %d "
"dst_x: %d dst_y: %d w: %d h: %d scr_ev_cnt: %d 0x%lx/0x%lx\n",
src_x, src_y, dst_x, dst_y, w, h, scr_ev_cnt, src, dst);
if (! valid) {
if (db > 1) fprintf(stderr, "record_CA not valid-2.\n");
return;
}
if (attr2.map_state != IsViewable) {
if (db > 1) fprintf(stderr, "record_CA not viewable-2.\n");
return;
}
dst_x = dst_x - (rx - rx2);
dst_y = dst_y - (ry - ry2);
dx = dst_x - src_x;
dy = dst_y - src_y;
if (dx != 0 && dy != 0) {
return;
}
}
if (0 || dba || db) { if (0 || dba || db) {
double st, dt; double st, dt;
@ -1546,14 +1635,30 @@ void check_xrecord_reset(int force) {
#endif #endif
} }
#define RECORD_ERROR_MSG \ #define RECORD_ERROR_MSG(tag) \
if (! quiet) { \ if (! quiet) { \
rfbLog("trapped RECORD XError: %s %d/%d/%d (0x%lx)\n", \ static int cnt = 0; \
xerror_string(trapped_record_xerror_event), \ static time_t last = 0; \
(int) trapped_record_xerror_event->error_code, \ int show = 0; \
(int) trapped_record_xerror_event->request_code, \ cnt++; \
(int) trapped_record_xerror_event->minor_code, \ if (debug_scroll || cnt < 20) { \
(int) trapped_record_xerror_event->resourceid); \ show = 1; \
} else if (cnt == 20) { \
last = time(NULL); \
rfbLog("disabling RECORD XError messages for 600s\n"); \
show = 1; \
} else if (time(NULL) > last + 600) { \
cnt = 0; \
show = 1; \
} \
if (show) { \
rfbLog("trapped RECORD XError: %s %s %d/%d/%d (0x%lx)\n", \
tag, xerror_string(trapped_record_xerror_event), \
(int) trapped_record_xerror_event->error_code, \
(int) trapped_record_xerror_event->request_code, \
(int) trapped_record_xerror_event->minor_code, \
(int) trapped_record_xerror_event->resourceid); \
} \
} }
void xrecord_watch(int start, int setby) { void xrecord_watch(int start, int setby) {
@ -1659,7 +1764,7 @@ if (db > 1) fprintf(stderr, "=== shutdown-scroll 0x%lx\n", rc_scroll);
XRecordProcessReplies(rdpy_data); XRecordProcessReplies(rdpy_data);
if (trapped_record_xerror) { if (trapped_record_xerror) {
RECORD_ERROR_MSG; RECORD_ERROR_MSG("shutdown");
last_error = now; last_error = now;
} }
@ -1683,7 +1788,7 @@ if (db > 1) fprintf(stderr, "=== disab-scroll 0x%lx 0x%lx\n", rc_scroll, rcs_scr
XRecordProcessReplies(rdpy_data); XRecordProcessReplies(rdpy_data);
if (trapped_record_xerror) { if (trapped_record_xerror) {
RECORD_ERROR_MSG; RECORD_ERROR_MSG("disable");
shutdown_record_context(rc_scroll, shutdown_record_context(rc_scroll,
0, reopen_dpys); 0, reopen_dpys);
@ -1906,7 +2011,7 @@ if (db > 1) fprintf(stderr, "=-= reg-scroll 0x%lx 0x%lx\n", rc_scroll, rcs_scr
if (db) fprintf(stderr, "rc_scroll: 0x%lx\n", rc_scroll); if (db) fprintf(stderr, "rc_scroll: 0x%lx\n", rc_scroll);
if (trapped_record_xerror) { if (trapped_record_xerror) {
RECORD_ERROR_MSG; RECORD_ERROR_MSG("register");
} }
if (! rc_scroll) { if (! rc_scroll) {
@ -1955,7 +2060,7 @@ if (db) fprintf(stderr, "rc_scroll: 0x%lx\n", rc_scroll);
rfbLog("failed to enable RECORD context " rfbLog("failed to enable RECORD context "
"rc_scroll: 0x%lx rc: %d\n", rc_scroll, rc); "rc_scroll: 0x%lx rc: %d\n", rc_scroll, rc);
if (trapped_record_xerror) { if (trapped_record_xerror) {
RECORD_ERROR_MSG; RECORD_ERROR_MSG("enable-failed");
} }
} }
shutdown_record_context(rc_scroll, 0, reopen_dpys); shutdown_record_context(rc_scroll, 0, reopen_dpys);

Loading…
Cancel
Save