The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
use strict;
use warnings;

use Test::More tests => 8;
use Socket;
use IO::EventMux::Socket::MsgHdr;

sub send_emu($$;$$$) { # we allow optional flags
  my (%msg, $flags);
  my $s = shift;

  $msg{buf}     = shift;
  $flags        = shift if @_;
  $msg{name}    = shift if @_;
  my $m = new IO::EventMux::Socket::MsgHdr(%msg);

  $m->cmsghdr(@{shift(@_)}) if @_;

  return sendmsg($s, $m, $flags);
}

sub send_test($$;$) {
  my ($msg, $flags, $cmsg) = @_;
  my $buf;
  local (*Rd, *Wr);

  socketpair(Rd, Wr, AF_UNIX, SOCK_STREAM, PF_UNSPEC)
    or die "socketpair: $!\n";

  if (ref $cmsg eq 'ARRAY') {
    send_emu(\*Wr, $msg, $flags, undef, $cmsg) or die "sendmsg: $!\n";
  } else {
    send_emu(\*Wr, $msg, $flags) or die "sendmsg: $!\n";
  }
  return (defined recv(\*Rd, $buf, 8192, 0) && $buf eq $msg);
}

sub sendto_test($$) {
  my ($msg, $flags) = @_;
  my $buf;
  local (*Rd, *Wr);

  for (\*Rd, \*Wr) {
    socket($_, AF_INET, SOCK_DGRAM, 0) or die "socket: $!\n";
  }
  bind(Rd, sockaddr_in(0, inet_aton('127.0.0.01')))
    or die "bind: $!\n";

  my $name = getsockname(Rd)
     or die "getsockname: $!\n";

  send_emu(\*Wr, $msg, $flags, $name) or die "sendmsg: $!\n";
  return (defined recv(\*Rd, $buf, 8192, 0) and $buf eq $msg);
}



# 1..2
ok(send_test("foobarbaz", 0), "plain send emulation");
ok(sendto_test("foobarbaz", 0), "plain sendto emulation");

# 2..4
SKIP: {
  no strict 'subs';
  eval { &MSG_NOSIGNAL; }; # autoloaded, may not be defined yet
  skip "msg_nosignal not defined", 2 if $@;
  ok(send_test("msg_nosignal", MSG_NOSIGNAL),
     "send(msg_nosignal) emulation");
  ok(sendto_test("msg_nosignal", MSG_NOSIGNAL),
     "sendto(msg_nosignal) emulation");
};

# 5..6
SKIP: {
  no strict 'subs';
  eval { &MSG_DONTWAIT; }; # autoloaded, may not be defined yet
  skip "msg_dontwait not defined", 2 if $@;
  ok(send_test("msg_dontwait", MSG_DONTWAIT),
     "send(msg_dontwait) emulation");
  ok(sendto_test("msg_nosignal", MSG_DONTWAIT),
     "sendto(msg_dontwait) emulation");
};

# 7
eval { defined sendmsg(\*STDIN, new IO::EventMux::Socket::MsgHdr(buf=>"fail")) 
       or die "sendmsg: $!\n"; }; # ENOTSOCK
ok($@, "sendmsg() undef on failure");

# 8
SKIP: {
  no strict 'subs';
  eval { &SOL_SOCKET; &SCM_RIGHTS; };
  skip "fd passing: SOL_SOCKET/SCM_RIGHTS unavailable", 1 if $@;
  skip "fd passing: where's STDIN?", 1 unless defined fileno(STDIN);

  my $control = [SOL_SOCKET, SCM_RIGHTS, pack('i', fileno STDIN)];

  ok(send_test("fileno STDIN on the way", 0, $control),
     "fd passing test");

};