--- a/t
+++ b/t
@@ -1,4 +1,4 @@
-#! /usr/bin/perl -w
+#! /usr/bin/perl
 
 # Test script for sslh
 
@@ -6,12 +6,16 @@
 # with:
 # cpan Conf::Libconfig
 
+use warnings;
 use strict;
 use IO::Socket::INET6;
 use IO::Socket::INET;
+use IO::Socket qw(SHUT_WR);
 use Socket qw/MSG_DONTWAIT/;
 use Test::More qw/no_plan/;
 use File::Temp qw(tempdir);
+use Data::Dumper qw(Dumper);
+use Carp qw(confess carp);
 # Because nothing else in Debian uses Conf::Libconfig, and I
 # (don@debian.org) don't want to package it, we have hard coded
 # test.cfg
@@ -71,7 +75,7 @@
 my $user = (getpwuid $<)[0]; # Run under current username
 
 # Which tests do we run
-my $SSH_SHY_CNX =       0;
+my $SSH_SHY_CNX =       1;
 my $PROBES_NOFRAG =     1;
 my $PROBES_AGAIN =      1;
 my $SSL_MIX_SSH =       1;
@@ -93,12 +97,12 @@
 
 sub verbose_exec
 {
-    my ($cmd) = @_;
-
-    warn "$cmd\n";
-    if (!fork) {
-        exec $cmd;
+    warn "@_\n";
+    my $pid;
+    if (!($pid = fork)) {
+        exec @_;
     }
+    return $pid;
 }
 
 # We want to keep track of tests to print a report at the
@@ -133,6 +137,8 @@
 # no_frag: don't print byte-per-byte
 sub test_probe {
     my (%opts) = @_;
+    print "test_probe called with";
+    print Dumper(\%opts);
 
     my $cnx = new IO::Socket::INET(PeerHost => "127.0.0.1:$sslh_port");
     warn "Unable to open socket to $sslh_port $!\n" unless $cnx;
@@ -140,26 +146,27 @@
 
     my $pattern = $opts{data};
     if (not defined $pattern) {
-        use Carp qw(confess);
         confess("Pattern not given");
     }
     if ($opts{no_frag}) {
-        syswrite $cnx, $pattern;
+        $cnx->send($pattern);
     } else {
         while (length $pattern) {
-            syswrite $cnx, (substr $pattern, 0, 1, '');
+            $cnx->send(substr $pattern, 0, 1, '');
+            # Timeout for a hundreth of a second
             select undef, undef, undef, .01;
         }
     }
-
+    
     my $data;
-    my $n = sysread $cnx, $data, 1024;
-    if (not defined $data) {
-        use Carp qw(confess);
-        confess("No data received: $opts{binary}:$opts{expected}")
+    my $n = retry_recv($cnx,$data, 1024, MSG_DONTWAIT);
+    if (not defined $data or length($data) == 0) {
+        carp("No data received: $opts{binary}:$opts{expected}");
+        $data = "";
     }
     $data =~ /^(.*?): /;
     my $prefix = $1;
+    $prefix = "" if not defined $prefix;
     $data =~ s/$prefix: //g;
     print "Received $n bytes: protocol $prefix data [$data]\n";
     close $cnx;
@@ -169,6 +176,21 @@
     my_is($data, $opts{data}, "$opts{binary}:$opts{expected}: data shoveled correctly");
 }
 
+sub retry_recv {
+    foreach my $i (0..5) {
+        my $peername = $_[0]->recv(@_[1..$#_]);
+        if (length($_[1]) > 0) {
+            print "Read $_[1] from peer: '$peername'\n";
+            return length($_[1]);
+        }
+        print "Would block, sleeping. Iteration: $i socket: ".\
+            $_[0]->sockhost() . ":" . $_[0]->sockport() ."\n";
+        # some tests need to hit the 10 second timeout.
+        sleep 1 + ($i+1)**2;
+    }
+}
+
+
 # Test all probes, with or without fragmentation
 # options:
 #     no_frag: write test patterns all at once (also
@@ -180,7 +202,7 @@
     my @probes = @{$conf->{"protocols"}};
     foreach my $p (@probes) {
         my %protocols = (
-            'ssh' => { data => "SSH-2.0 tester" },
+            'ssh' => { data => "SSH-2.0 tester\n" },
             'socks5' => { data => "\x05\x04\x01\x02\x03\x04" },
             'http' => { 
                 data => "GET index.html HTTP/1.1",
@@ -263,7 +285,7 @@
         $prefix = make_sni_alpn_name($s);
     }
 
-    verbose_exec "./echosrv --listen $s->{host}:$s->{port} --prefix '$prefix: '";
+    verbose_exec("./echosrv","--listen","$s->{host}:$s->{port}", "--prefix","$prefix: ");
 }
 
 # Write out test.cfg with new unused ports
@@ -338,31 +360,32 @@
 
 # Start sslh with the right plumbing
     my ($sslh_pid, $valgrind);
-    if (!($sslh_pid = fork)) {
+    #if (!($sslh_pid = fork)) {
         my $user = (getpwuid $<)[0]; # Run under current username
-        my $cmd = "./$binary -f -u $user -F test.cfg";
+        my @cmd = ("./$binary", "-f", "-u", $user, "-F", "test.cfg");
         #$valgrind = 1;
         #$cmd = "valgrind --leak-check=full $cmd";
-        verbose_exec $cmd;
-        exit 0;
-    }
+        $sslh_pid = verbose_exec @cmd;
+        #exit 0;
+    #}
     warn "spawned $sslh_pid\n";
     sleep 1; # Give everyone some time to start
     sleep 5 if $valgrind;  # valgrind can be heavy -- wait 5 seconds
 
 
     my $test_data = "hello world\n";
-    my $ssl_test_data =  "\x16\x03\x01\x00\xab\x01\x00\x00\xa7\x03\x03\x89\x22\x33\x95\x43\x7a\xc3\x89\x45\x51\x12\x3c\x28\x24\x1b\x6a\x78\xbf\xbe\x95\xd8\x90\x58\xd7\x65\xf7\xbb\x2d\xb2\x8d\xa0\x75\x00\x00\x38\xc0\x2c\xc0\x30\x00\x9f\xcc\xa9\xcc\xa8\xcc\xaa\xc0\x2b\xc0\x2f\x00\x9e\xc0\x24\xc0\x28\x00\x6b\xc0\x23\xc0\x27\x00\x67\xc0\x0a\xc0\x14\x00\x39\xc0\x09\xc0\x13\x00\x33\x00\x9d\x00\x9c\x00\x3d\x00\x3c\x00\x35\x00\x2f\x00\xff\x01\x00\x00\x46\x00\x0b\x00\x04\x03\x00\x01\x02\x00\x0a\x00\x0a\x00\x08\x00\x1d\x00\x17\x00\x19\x00\x18\x00\x23\x00\x00\x00\x0d\x00\x20\x00\x1e\x06\x01\x06\x02\x06\x03\x05\x01\x05\x02\x05\x03\x04\x01\x04\x02\x04\x03\x03\x01\x03\x02\x03\x03\x02\x01\x02\x02\x02\x03\x00\x16\x00\x00\x00\x17\x00\x00hello tls alone";
+    my $ssl_test_data =  "\x16\x03\x01\x00\xab\x01\x00\x00\xa7\x03\x03\x89\x22\x33\x95\x43\x7a\xc3\x89\x45\x51\x12\x3c\x28\x24\x1b\x6a\x78\xbf\xbe\x95\xd8\x90\x58\xd7\x65\xf7\xbb\x2d\xb2\x8d\xa0\x75\x00\x00\x38\xc0\x2c\xc0\x30\x00\x9f\xcc\xa9\xcc\xa8\xcc\xaa\xc0\x2b\xc0\x2f\x00\x9e\xc0\x24\xc0\x28\x00\x6b\xc0\x23\xc0\x27\x00\x67\xc0\x0a\xc0\x14\x00\x39\xc0\x09\xc0\x13\x00\x33\x00\x9d\x00\x9c\x00\x3d\x00\x3c\x00\x35\x00\x2f\x00\xff\x01\x00\x00\x46\x00\x0b\x00\x04\x03\x00\x01\x02\x00\x0a\x00\x0a\x00\x08\x00\x1d\x00\x17\x00\x19\x00\x18\x00\x23\x00\x00\x00\x0d\x00\x20\x00\x1e\x06\x01\x06\x02\x06\x03\x05\x01\x05\x02\x05\x03\x04\x01\x04\x02\x04\x03\x03\x01\x03\x02\x03\x03\x02\x01\x02\x02\x02\x03\x00\x16\x00\x00\x00\x17\x00\x00hello tls alone\n";
 
 # Test: Shy SSH connection
     if ($SSH_SHY_CNX) {
         print "***Test: Shy SSH connection\n";
-        my $cnx_h = new IO::Socket::INET(PeerHost => "127.0.0.1:$sslh_port");
-        warn "Unable to connect to sslh_port:$sslh_port $!\n" unless $cnx_h;
+        my $cnx_h = new IO::Socket::INET(PeerHost => "127.0.0.1:$sslh_port") or 
+            die "Unable to connect to sslh_port:$sslh_port $IO::Socket::errstr\n";
         if (defined $cnx_h) {
             sleep 13;
-            print $cnx_h $test_data;
-            my $data = <$cnx_h>;
+            $cnx_h->send($test_data);
+            my $data;
+            retry_recv($cnx_h,$data,1024,MSG_DONTWAIT);
             my_is($data, "ssh: $test_data", "$binary: Shy SSH connection");
         }
     }
@@ -370,60 +393,52 @@
 # Test: One SSL half-started then one SSH
     if ($SSL_MIX_SSH) {
         print "***Test: One SSL half-started then one SSH\n";
-        my $cnx_l = new IO::Socket::INET(PeerHost => "127.0.0.1:$sslh_port");
-        warn "Unable to connect to sslh_port $sslh_port: $!\n" unless $cnx_l;
-        if (defined $cnx_l) {
-            print $cnx_l $ssl_test_data;
-            my $cnx_h= new IO::Socket::INET(PeerHost => "127.0.0.1:$sslh_port");
-            warn "Unable to connect to sslh_port $sslh_port: $!\n" unless $cnx_h;
-            if (defined $cnx_h) {
-                warn("going to print data to $cnx_h");
-                $cnx_h->send($test_data);
-                warn("printed data to $cnx_h");
-                # sleep 3;
-                my $data_h = <$cnx_h>;
-                warn("waiting for data at $cnx_h");
-                my_is($data_h, "ssh: $test_data", "$binary: SSH during SSL being established");
-            }
-            my $data;
-            my $n = sysread $cnx_l, $data, 1024;
-            warn("reading data from tls");
-            my_is($data, "tls: $ssl_test_data", "$binary: SSL connection interrupted by SSH");
-        }
+        my $cnx_l = new IO::Socket::INET(PeerHost => "127.0.0.1:$sslh_port") or 
+            die "Unable to connect to sslh_port $sslh_port: $IO::Socket::errstr\n";
+        $cnx_l->send($ssl_test_data);
+        warn("printed data '$ssl_test_data' to ".$cnx_l->sockport());
+        my $cnx_h= new IO::Socket::INET(PeerHost => "127.0.0.1:$sslh_port") or
+            die "Unable to connect to sslh_port $sslh_port: $!\n";
+        warn("going to print data to ".$cnx_h->sockport());
+        $cnx_h->send($test_data);
+        warn("printed data '$test_data' to ".$cnx_h->sockport());
+        my $data_h;
+        retry_recv($cnx_h,$data_h,1024,MSG_DONTWAIT);
+        my_is($data_h, "ssh: $test_data", "$binary: SSH during SSL being established");
+        my $data;
+        retry_recv($cnx_l,$data, 1024,MSG_DONTWAIT);
+        warn("reading data from tls");
+        my_is($data, "tls: $ssl_test_data", "$binary: SSL connection interrupted by SSH");
     }
 
 # Test: One SSH half-started then one SSL
     if ($SSH_MIX_SSL) {
         print "***Test: One SSH half-started then one SSL\n";
-        my $cnx_h = new IO::Socket::INET(PeerHost => "127.0.0.1:$sslh_port");
-        warn "Unable to open sslh_port:$sslh_port $!\n" unless $cnx_h;
-        if (defined $cnx_h) {
-            # sleep 3;
-            my $cnx_l = new IO::Socket::INET(PeerHost => "127.0.0.1:$sslh_port");
-            warn "$!\n" unless $cnx_l;
-            if (defined $cnx_l) {
-                print $cnx_l $ssl_test_data;
-                my $data;
-                my $n = sysread $cnx_l, $data, 1024;
-                my_is($data, "tls: $ssl_test_data", "$binary: SSL during SSH being established");
-            }
-            print $cnx_h $test_data;
-            my $data = <$cnx_h>;
-            my_is($data, "ssh: $test_data", "$binary: SSH connection interrupted by SSL");
-        }
+        my $cnx_h = new IO::Socket::INET(PeerHost => "127.0.0.1:$sslh_port") or 
+            die "Unable to open sslh_port:$sslh_port $!\n";
+        my $cnx_l = new IO::Socket::INET(PeerHost => "127.0.0.1:$sslh_port") or
+            die "Unable to connect to 127.0.0.1:$sslh_port $IO::Socket::errstr";
+        $cnx_l->send($ssl_test_data);
+        my $data;
+        retry_recv($cnx_l,$data, 1024,MSG_DONTWAIT);
+        my_is($data, "tls: $ssl_test_data", "$binary: SSL during SSH being established");
+        $cnx_l->close();
+        $cnx_h->send($test_data);
+        my $data;
+        retry_recv($cnx_h,$data,1024,MSG_DONTWAIT);
+        my_is($data, "ssh: $test_data", "$binary: SSH connection interrupted by SSL");
+        $cnx_h->close();
     }
 
 # Test: Drop connection without writing anything
     if ($DROP_CNX) {
         print "***Test: Connect but don't write anything\n";
-        my $cnx_h = new IO::Socket::INET(PeerHost => "127.0.0.1:$sslh_port");
-        warn "$!\n" unless $cnx_h;
-        if ($cnx_h) {
-            close $cnx_h;
-            my_is(1, "$binary: Connect and write nothing");
-            # The goal of the test is to check sslh doesn't
-            # crash
-        }
+        my $cnx_h = new IO::Socket::INET(PeerHost => "127.0.0.1:$sslh_port") or
+            die "Unable to connect to 127.0.0.1:$sslh_port $IO::Socket::errstr";
+        close $cnx_h;
+        my_is(1, "$binary: Connect and write nothing");
+        # The goal of the test is to check sslh doesn't
+        # crash
     }
 
 
