1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244
|
#!./perl -w
my $child;
my $can_fork;
my $has_perlio;
BEGIN {
require Config; import Config;
$can_fork = $Config{'d_fork'} || $Config{'d_pseudofork'};
if ($^O eq "hpux" or $Config{'extensions'} !~ /\bSocket\b/ &&
!(($^O eq 'VMS') && $Config{d_socket})) {
print "1..0\n";
exit 0;
}
}
{
# This was in the BEGIN block, but since Test::More 0.47 added support to
# detect forking, we don't need to fork before Test::More initialises.
# Too many things in this test will hang forever if something is wrong,
# so we need a self destruct timer. And IO can hang despite an alarm.
if( $can_fork) {
my $parent = $$;
$child = fork;
die "Fork failed" unless defined $child;
if (!$child) {
$SIG{INT} = sub {exit 0}; # You have 60 seconds. Your time starts now.
my $must_finish_by = time + 60;
my $remaining;
while (($remaining = $must_finish_by - time) > 0) {
sleep $remaining;
}
warn "Something unexpectedly hung during testing";
kill "INT", $parent or die "Kill failed: $!";
exit 1;
}
}
unless ($has_perlio = PerlIO::Layer->can("find") && PerlIO::Layer->find('perlio')) {
print <<EOF;
# Since you don't have perlio you might get failures with UTF-8 locales.
EOF
}
}
use Socket;
use Test::More;
use strict;
use warnings;
use Errno;
my $skip_reason;
if( !$Config{d_alarm} ) {
plan skip_all => "alarm() not implemented on this platform";
} elsif( !$can_fork ) {
plan skip_all => "fork() not implemented on this platform";
} else {
# This should fail but not die if there is real socketpair
eval {socketpair LEFT, RIGHT, -1, -1, -1};
if ($@ =~ /^Unsupported socket function "socketpair" called/ ||
$! =~ /^The operation requested is not supported./) { # Stratus VOS
plan skip_all => 'No socketpair (real or emulated)';
} else {
eval {AF_UNIX};
if ($@ =~ /^Your vendor has not defined Socket macro AF_UNIX/) {
plan skip_all => 'No AF_UNIX';
} else {
plan tests => 45;
}
}
}
# But we'll install an alarm handler in case any of the races below fail.
$SIG{ALRM} = sub {die "Unexpected alarm during testing"};
ok (socketpair (LEFT, RIGHT, AF_UNIX, SOCK_STREAM, PF_UNSPEC),
"socketpair (LEFT, RIGHT, AF_UNIX, SOCK_STREAM, PF_UNSPEC)")
or print "# \$\! = $!\n";
if ($has_perlio) {
binmode(LEFT, ":bytes");
binmode(RIGHT, ":bytes");
}
my @left = ("hello ", "world\n");
my @right = ("perl ", "rules!"); # Not like I'm trying to bias any survey here.
foreach (@left) {
# is (syswrite (LEFT, $_), length $_, "write " . _qq ($_) . " to left");
is (syswrite (LEFT, $_), length $_, "syswrite to left");
}
foreach (@right) {
# is (syswrite (RIGHT, $_), length $_, "write " . _qq ($_) . " to right");
is (syswrite (RIGHT, $_), length $_, "syswrite to right");
}
# stream socket, so our writes will become joined:
my ($buffer, $expect);
$expect = join '', @right;
undef $buffer;
is (read (LEFT, $buffer, length $expect), length $expect, "read on left");
is ($buffer, $expect, "content what we expected?");
$expect = join '', @left;
undef $buffer;
is (read (RIGHT, $buffer, length $expect), length $expect, "read on right");
is ($buffer, $expect, "content what we expected?");
ok (shutdown(LEFT, SHUT_WR), "shutdown left for writing");
# This will hang forever if eof is buggy, and alarm doesn't interrupt system
# Calls. Hence the child process minder.
SKIP: {
skip "SCO Unixware / OSR have a bug with shutdown",2 if $^O =~ /^(?:svr|sco)/;
local $SIG{ALRM} = sub { warn "EOF on right took over 3 seconds" };
local $TODO = "Known problems with unix sockets on $^O"
if $^O eq 'hpux' || $^O eq 'super-ux';
alarm 3;
$! = 0;
ok (eof RIGHT, "right is at EOF");
local $TODO = "Known problems with unix sockets on $^O"
if $^O eq 'unicos' || $^O eq 'unicosmk';
is ($!, '', 'and $! should report no error');
alarm 60;
}
my $err = $!;
$SIG{PIPE} = 'IGNORE';
{
local $SIG{ALRM} =
sub { warn "syswrite to left didn't fail within 3 seconds" };
alarm 3;
# Split the system call from the is() - is() does IO so
# (say) a flush may do a seek which on a pipe may disturb errno
my $ans = syswrite (LEFT, "void");
$err = $!;
is ($ans, undef, "syswrite to shutdown left should fail");
alarm 60;
}
{
# This may need skipping on some OSes - restoring value saved above
# should help
$! = $err;
ok (($!{EPIPE} or $!{ESHUTDOWN}), '$! should be EPIPE or ESHUTDOWN')
or printf "\$\!=%d(%s)\n", $err, $err;
}
my @gripping = (chr 255, chr 127);
foreach (@gripping) {
is (syswrite (RIGHT, $_), length $_, "syswrite to right");
}
ok (!eof LEFT, "left is not at EOF");
$expect = join '', @gripping;
undef $buffer;
is (read (LEFT, $buffer, length $expect), length $expect, "read on left");
is ($buffer, $expect, "content what we expected?");
ok (close LEFT, "close left");
ok (close RIGHT, "close right");
# And now datagrams
# I suspect we also need a self destruct time-bomb for these, as I don't see any
# guarantee that the stack won't drop a UDP packet, even if it is for localhost.
SKIP: {
skip "No usable SOCK_DGRAM for socketpair", 24 if ($^O =~ /^(MSWin32|os2)\z/);
skip "alarm doesn't interrupt I/O on this Perl", 24 if "$]" < 5.008;
local $TODO = "socketpair not supported on $^O" if $^O eq 'nto';
ok (socketpair (LEFT, RIGHT, AF_UNIX, SOCK_DGRAM, PF_UNSPEC),
"socketpair (LEFT, RIGHT, AF_UNIX, SOCK_DGRAM, PF_UNSPEC)")
or print "# \$\! = $!\n";
if ($has_perlio) {
binmode(LEFT, ":bytes");
binmode(RIGHT, ":bytes");
}
foreach (@left) {
# is (syswrite (LEFT, $_), length $_, "write " . _qq ($_) . " to left");
is (syswrite (LEFT, $_), length $_, "syswrite to left");
}
foreach (@right) {
# is (syswrite (RIGHT, $_), length $_, "write " . _qq ($_) . " to right");
is (syswrite (RIGHT, $_), length $_, "syswrite to right");
}
# stream socket, so our writes will become joined:
my ($total);
$total = join '', @right;
foreach $expect (@right) {
undef $buffer;
is (sysread (LEFT, $buffer, length $total), length $expect, "read on left");
is ($buffer, $expect, "content what we expected?");
}
$total = join '', @left;
foreach $expect (@left) {
undef $buffer;
is (sysread (RIGHT, $buffer, length $total), length $expect, "read on right");
is ($buffer, $expect, "content what we expected?");
}
ok (shutdown(LEFT, 1), "shutdown left for writing");
# eof uses buffering. eof is indicated by a sysread of zero.
# but for a datagram socket there's no way it can know nothing will ever be
# sent
SKIP: {
skip "$^O does length 0 udp reads", 2 if ($^O eq 'os390');
my $alarmed = 0;
local $SIG{ALRM} = sub { $alarmed = 1; };
print "# Approximate forever as 3 seconds. Wait 'forever'...\n";
alarm 3;
undef $buffer;
is (sysread (RIGHT, $buffer, 1), undef,
"read on right should be interrupted");
is ($alarmed, 1, "alarm should have fired");
}
alarm 30;
foreach (@gripping) {
is (syswrite (RIGHT, $_), length $_, "syswrite to right");
}
$total = join '', @gripping;
foreach $expect (@gripping) {
undef $buffer;
is (sysread (LEFT, $buffer, length $total), length $expect, "read on left");
is ($buffer, $expect, "content what we expected?");
}
ok (close LEFT, "close left");
ok (close RIGHT, "close right");
} # end of DGRAM SKIP
kill "INT", $child or warn "Failed to kill child process $child: $!";
exit 0;
|