--- /dev/null
+#!perl
+
+# sanity tests for socket functions
+
+BEGIN {
+ chdir 't' if -d 't';
+ @INC = '../lib' if -d '../lib' && -d '../ext';
+
+ require "./test.pl";
+ require Config; import Config;
+
+ skip_all_if_miniperl();
+ for my $needed (qw(d_socket d_getpbyname)) {
+ if ($Config{$needed} ne 'define') {
+ skip_all("-- \$Config{$needed} undefined");
+ }
+ }
+ unless ($Config{extensions} =~ /\bSocket\b/) {
+ skip_all('-- Socket not available');
+ }
+}
+
+use strict;
+use Socket;
+
+$| = 1; # ensure test output is synchronous so processes don't conflict
+
+my $tcp = getprotobyname('tcp')
+ or skip_all("no tcp protocol available ($!)");
+my $udp = getprotobyname('udp')
+ or note "getprotobyname('udp') failed: $!";
+
+my $local = gethostbyname('localhost')
+ or note "gethostbyname('localhost') failed: $!";
+
+my $fork = $Config{d_fork} || $Config{d_pseudofork};
+
+{
+ # basic socket creation
+ socket(my $sock, PF_INET, SOCK_STREAM, $tcp)
+ or skip_all('socket() for tcp failed ($!), nothing else will work');
+ ok(close($sock), "close the socket");
+}
+
+SKIP: {
+ # test it all in TCP
+ $local or skip("No localhost", 2);
+
+ ok(socket(my $serv, PF_INET, SOCK_STREAM, $tcp), "make a tcp socket");
+ my $bind_at = pack_sockaddr_in(0, $local);
+ ok(bind($serv, $bind_at), "bind works")
+ or skip("Couldn't bind to localhost", 3);
+ my $bind_name = getsockname($serv);
+ ok($bind_name, "getsockname() on bound socket");
+ my ($bind_port) = unpack_sockaddr_in($bind_name);
+
+ print "# port $bind_port\n";
+
+ SKIP:
+ {
+ ok(listen($serv, 5), "listen() works")
+ or diag "listen error: $!";
+
+ $fork or skip("No fork", 1);
+ my $pid = fork;
+ my $send_data = "test" x 50_000;
+ if ($pid) {
+ # parent
+ ok(socket(my $accept, PF_INET, SOCK_STREAM, $tcp),
+ "make accept tcp socket");
+ ok(my $addr = accept($accept, $serv), "accept() works")
+ or diag "accept error: $!";
+
+ my $sent_total = 0;
+ while ($sent_total < length $send_data) {
+ my $sent = send($accept, substr($send_data, $sent_total), 0);
+ defined $sent or last;
+ $sent_total += $sent;
+ }
+ my $shutdown = shutdown($accept, 1);
+
+ # wait for the remote to close so data isn't lost in
+ # transit on a certain broken implementation
+ <$accept>;
+ # child tests are printed once we hit eof
+ curr_test(curr_test()+5);
+ waitpid($pid, 0);
+
+ ok($shutdown, "shutdown() works");
+ }
+ elsif (defined $pid) {
+ curr_test(curr_test()+2);
+ #sleep 1;
+ # child
+ ok_child(close($serv), "close server socket in child");
+ ok_child(socket(my $child, PF_INET, SOCK_STREAM, $tcp),
+ "make child tcp socket");
+
+ ok_child(connect($child, $bind_name), "connect() works")
+ or diag "connect error: $!";
+
+ my $buf;
+ my $recv_peer = recv($child, $buf, 1000, 0);
+ # [perl #118843]
+ ok_child($recv_peer eq '' || $recv_peer eq $bind_name,
+ "peer from recv() should be empty or the remote name");
+ while(defined recv($child, my $tmp, 1000, 0)) {
+ last if length $tmp == 0;
+ $buf .= $tmp;
+ }
+ is_child($buf, $send_data, "check we received the data");
+ close($child);
+ end_child();
+
+ exit(0);
+ }
+ else {
+ # failed to fork
+ diag "fork() failed $!";
+ skip("fork() failed", 1);
+ }
+ }
+}
+
+done_testing();
+
+my @child_tests;
+sub ok_child {
+ my ($ok, $note) = @_;
+ push @child_tests, ( $ok ? "ok " : "not ok ") . curr_test() . " - $note\n";
+ curr_test(curr_test()+1);
+}
+
+sub is_child {
+ my ($got, $want, $note) = @_;
+ ok_child($got eq $want, $note);
+}
+
+sub end_child {
+ print @child_tests;
+}