#!/usr/bin/perl
use strict;
use warnings;
use Socket qw(PF_UNIX SOCK_STREAM SOL_SOCKET SO_REUSEADDR pack_sockaddr_un);
use Errno qw(EADDRINUSE);

my $fail = 0;

sub check {
    my ($ok, $msg) = @_;
    unless ($ok) {
        warn "FAIL: $msg\n";
        $fail++;
    }
}

# === Pathname socket ===
my $path = "./reuseaddr-$$.sock";

socket(my $s1, PF_UNIX, SOCK_STREAM, 0) or die "socket: $!";
bind($s1, pack_sockaddr_un($path)) or die "s1 bind: $!";
print "s1 bound $path\n";

socket(my $s2, PF_UNIX, SOCK_STREAM, 0) or die $!;
setsockopt($s2, SOL_SOCKET, SO_REUSEADDR, pack("i",1));
if (!bind($s2, pack_sockaddr_un($path))) {
    check($!{EADDRINUSE}, "pathname s2 should fail with EADDRINUSE (got $!)");
} else {
    check(0, "pathname s2 unexpectedly succeeded");
}
close $s1; close $s2;
unlink $path;

socket(my $s3, PF_UNIX, SOCK_STREAM, 0) or die $!;
check(bind($s3, pack_sockaddr_un($path)), "pathname s3 should succeed after unlink");
close $s3;
unlink $path;

# === Abstract socket (Linux only) ===
my $abs = "\0reuseaddr-$$";

socket(my $a1, PF_UNIX, SOCK_STREAM, 0) or die $!;
bind($a1, pack_sockaddr_un($abs)) or die "a1 bind: $!";
print "a1 bound abstract\n";

socket(my $a2, PF_UNIX, SOCK_STREAM, 0) or die $!;
setsockopt($a2, SOL_SOCKET, SO_REUSEADDR, pack("i",1));
if (!bind($a2, pack_sockaddr_un($abs))) {
    check($!{EADDRINUSE}, "abstract a2 should fail with EADDRINUSE (got $!)");
} else {
    check(0, "abstract a2 unexpectedly succeeded");
}
close $a1; close $a2;

socket(my $a3, PF_UNIX, SOCK_STREAM, 0) or die $!;
check(bind($a3, pack_sockaddr_un($abs)), "abstract a3 should succeed after close");
close $a3;

print "Total fails: $fail\n";
exit $fail;
