The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
# Before `make install' is performed this script should be runnable with
# `make test'. After `make install' it should work as `perl test.pl'

######################### We start with some black magic to print on failure.
# Change 1..1 below to 1..last_test_to_print .
# (It may become useful if the test is moved to ./t subdirectory.)

BEGIN { $| = 1; print "1..22\n"; }
END {print "not ok 1\n" unless $loaded;}

#use diagnostics;

use Net::NBsocket qw(
	open_listenNB
	connect_NB
	accept_NB
	havesock6
	isupport6
	in6addr_loopback
	AF_INET6
	ipv6_n2x
);

use POSIX qw(EWOULDBLOCK);
require Socket;
import Socket qw(
	SO_ERROR
	SOL_SOCKET
);
$loaded = 1;
print "ok 1\n";
######################### End of black magic.

# Insert your test code below (better if it prints "ok 13"
# (correspondingly "not ok 13") depending on the success of chunk 13
# of the test code):

$test = 2;

my($client,$server);

sub ok {
  my $rv = shift;
  unless ($rv) {
    print "ok $test\n";
    ++$test;
    return;
  }
  elsif ($rv =~ /bug/) {
    print "ok $test	# skipped, $rv\n";
    ++$test;
    return;
  }
  close $client if $client;
  close $server if $server;
  while ($test < 23) {
    print "ok $test     # skipped, $rv\n";
    $rv = 'no IPv6 support';
    $test++;
  }
  exit;
}

ok 'Socket6 not installed'
	unless havesock6();

ok 'no IPv6 support on this host'
	unless isupport6();

umask 027;
foreach my $dir (qw(tmp)) {
  if (-d $dir) {         # clean up previous test runs
    opendir(T,$dir);
    @_ = grep(!/^\./, readdir(T));
    closedir T;
    foreach(@_) {
      unlink "$dir/$_";
    }
    rmdir $dir or die "COULD NOT REMOVE $dir DIRECTORY\n";
  }
  unlink $dir if -e $dir;       # remove files of this name as well
}

my $dir = `pwd`;
do { chop $dir } while ($dir =~ /\s$/);
$dir .= '/tmp';
mkdir $dir,0755;

my $filename = &{sub{(caller())[1]}};

my $uds;

## test 1 - 2	open a listening TCP socket
my $port;
if ($filename =~ /tcp_/) {		# else internet domain socket
  print STDERR "\tTesting IPv6 Internet Domain Sockets\n";
  foreach (10000..10100) {		# find a port to bind to
    if ($server = open_listenNB($_,undef,AF_INET6())) {
      $port = $_;
      last;
    }
  }
} else {				# internet domain socket with designated address
  print STDERR "\tTesting ::1 Sockets\n";
  foreach (10000..10100) {		# find a port to bind to
    if ($server = open_listenNB($_,in6addr_loopback(),AF_INET6())) {
      $port = $_;
      last;
    }
  }
}

ok $server ? '' : 'could not open a listening port for testing';

## test 3
my $filenoS = fileno($server);
ok $filenoS ? '' : 'could not get fileno for $server';

## test 4	open connecton to listening port
$client = connect_NB($port,in6addr_loopback(),AF_INET6());
ok $client ? '' : 'could not connect to server for testing';

my ($rin,$rout,$win,$wout,$clone,$caddr);

my $expire = time + 5;		# timeout in 5 seconds

## test 5
my $filenoC = fileno($client);
ok $filenoC ? '' : 'could not get file numbers for sockets';

## test 6 - 7
my $exp = '0:0:0:0:0:0:0:1';
my $wready = 0;			# ready to write
while(time < $expire) {
  $rin = $win = '';
  vec($rin,$filenoS,1) = 1;
  (vec($win,$filenoC,1) = 1) unless $wready;
  my $nfound = select($rout=$rin,$wout=$win,undef,0.1);
  next unless $nfound > 0;
  my $fail = '';
  if (vec($rout,$filenoS,1)) {		# listner - accept
    ($clone,$caddr) = accept_NB($server);
    unless ($clone) {
      $fail = 'could not accept connection';
    } elsif ( ! $uds && !($caddr = ipv6_n2x($caddr)) ) {
      $fail = "bad connect addr $caddr";
    } elsif ( ! $uds && $caddr ne $exp ) {
      $fail = "perl 'accept' bug\ngot: $caddr\nexp: $exp";
    } elsif ($test != 6) {
      $fail = "wrong test number $test != 6";
    }
    ok $fail;
  } elsif (vec($wout,$filenoC,1)) {	# client connected
    my $status = getsockopt($clone,SOL_SOCKET(),SO_ERROR());
    if ($status eq "\0") {
      print "connection incomplete\nnot ";
    } elsif ($test != 7) {
       print "wrong test number $test != 7\nnot ";
    } else {
      $wready = 1;
    }
    print "ok 7\n"; ++$test;
    last;
  }
}

## test 8	nb setup complete
if ($test == 8) {
  &ok;
} else {
ok 'accept / connection incomplete';
}

my $filenoX = fileno($clone);

## test 9
ok $filenoX ? '' : 'could not get fileno for $clone';

## test 10	check for sysread error
my $rbuf;
print "unexpected read\nnot "
	if defined sysread($clone,$rbuf,512);
&ok;

## test 11	check error value
print "error is '$!', expected EWOULDBLOCK\nnot "
	unless $! == EWOULDBLOCK;
&ok;

$expire = time + 5;			# timeout in 5 seconds
my $wbuf = 'hello';
while(time < $expire) {
  $rin = $win = '';
  vec($rin,$filenoX,1) = 1;
  (vec($win,$filenoC,1) = 1) if $wready;
  my $nfound = select($rout=$rin,$wout=$win,undef,0.1);
  next unless $nfound > 0;
  if (vec($wout,$filenoC,1)) {
## test 12	write to client
    print "client could not write to clone server\nnot "
	unless syswrite($client,$wbuf,length($wbuf));
    print "ok 12\n"; ++$test;
    $wready = 0;
  } elsif (vec($rout,$filenoX,1)) {
## test 13 - 14		check transmitted data
    print "unknown size of data from client = $_\nnot "
	unless ($_ = sysread($clone,$rbuf,512)) == length($wbuf);
    print "ok 13\n"; ++$test;
    print "got: $rbuf, exp: $wbuf\nnot "
	unless $rbuf eq $wbuf;
    print "ok 14\n"; ++$test;
    last;
  }
}

## test 15	nb client to server complete
print "client write incomplete\nnot " unless $test == 15;
&ok;

$expire = time + 5;                     # timeout in 5 seconds
$wbuf = 'goodbye';
while(time < $expire) {
  $rin = $win = '';
  vec($rin,$filenoC,1) = 1;
  (vec($win,$filenoX,1) = 1) unless $wready;
  my $nfound = select($rout=$rin,$wout=$win,undef,0.1);
  next unless $nfound > 0;
  if (vec($wout,$filenoX,1)) {
## test 16	write back to client
    print "clone could not reply to client\nnot "
	unless syswrite($clone,$wbuf,length($wbuf));
    print "ok 16\n";	++$test;
    $wready = 1;
  } elsif (vec($rout,$filenoC,1)) {
## test 17 - 18	check data from clone
    print "unknown size of data from clone = $_\nnot "
	unless ($_ = sysread($client,$rbuf,512)) == length($wbuf);
    print "ok 17\n";	++$test;
    print "got: $_, exp: $wbuf\nnot "
	unless $rbuf eq $wbuf;
    print "ok 18\n";	++$test;
    last;
  }
}

## test 19	nb clone to client complete
print "clone writeback incomplete\nnot " unless $test == 19;
&ok;

## test 20	check for sysread error
print "unexpected read\nnot "
	if defined sysread($client,$rbuf,512);
&ok;

## test 21	check error value
print "error is '$!', expected EWOULDBLOCK\nnot "
	unless $! == EWOULDBLOCK;
&ok;

close $clone;

## test 22	check for EOF
$wready = 1;
$expire = time + 5;                     # timeout in 5 seconds
while(time < $expire) {
  $rin = $win = '';
  vec($rin,$filenoC,1) = 1;
  my $nfound = select($rout=$rin,$wout=$win,undef,0.1);
  next unless $nfound > 0;
  unless (vec($rout,$filenoC,1)) {
    print "unknown interrupt\nnot ";
  } elsif ($_ = sysread($client,$rbuf,512)) {
    print "unknown string read: $rbuf\nnot ";
  }
  $wready = 0;
  last;
}
print "EOF detection timed out\nnot "
	if $wready;
&ok;
close $server;
close $client;