1#!/usr/bin/perl 2 3use warnings; 4use strict; 5 6use File::Temp qw(tempdir); 7use File::Spec::Functions; 8use IO::Socket; 9use IO::Socket::UNIX; 10use Socket; 11use Config; 12use Test::More; 13 14plan skip_all => "UNIX domain sockets not implemented on $^O" 15 if ($^O =~ m/^(?:qnx|nto|vos|MSWin32|VMS)$/); 16 17my $socketpath = catfile(tempdir( CLEANUP => 1 ), 'testsock'); 18 19# check the socketpath fits in sun_path. 20# 21# pack_sockaddr_un() just truncates the path, this may change, but how 22# it will handle such a condition is undetermined (and we might need 23# to work with older versions of Socket outside of a perl build) 24# https://rt.cpan.org/Ticket/Display.html?id=116819 25 26my $name = eval { pack_sockaddr_un($socketpath) }; 27if (defined $name) { 28 my ($packed_name) = eval { unpack_sockaddr_un($name) }; 29 if (!defined $packed_name || $packed_name ne $socketpath) { 30 plan skip_all => "socketpath too long for sockaddr_un"; 31 } 32} 33 34plan tests => 15; 35 36# start testing stream sockets: 37my $listener = IO::Socket::UNIX->new(Type => SOCK_STREAM, 38 Listen => 1, 39 Local => $socketpath); 40ok(defined($listener), 'stream socket created'); 41 42my $p = $listener->protocol(); 43{ 44 # the value of protocol isn't well defined for AF_UNIX, when we 45 # create the socket we supply 0, which leaves it up to the implementation 46 # to select a protocol, so we (now) don't save a 0 protocol during socket 47 # creation. This test then breaks if the implementation doesn't support 48 # SO_SOCKET (at least on AF_UNIX). 49 # This specifically includes NetBSD, Darwin and cygwin. 50 # This is a TODO instead of a skip so if these ever implement SO_PROTOCOL 51 # we'll be notified about the passing TODO so the test can be updated. 52 local $TODO = "$^O doesn't support SO_PROTOCOL on AF_UNIX" 53 if $^O =~ /^(netbsd|darwin|cygwin|hpux|solaris|dragonfly|os390)$/; 54 ok(defined($p), 'protocol defined'); 55} 56my $d = $listener->sockdomain(); 57ok(defined($d), 'domain defined'); 58my $s = $listener->socktype(); 59ok(defined($s), 'type defined'); 60 61SKIP: { 62 skip "fork not available", 4 63 unless $Config{d_fork} || $Config{d_pseudofork}; 64 65 my $cpid = fork(); 66 if (0 == $cpid) { 67 # the child: 68 sleep(1); 69 my $connector = IO::Socket::UNIX->new(Peer => $socketpath); 70 exit(0); 71 } else { 72 ok(defined($cpid), 'spawned a child'); 73 } 74 75 my $new = $listener->accept(); 76 77 is($new->sockdomain(), $d, 'domain match'); 78 SKIP: { 79 skip "no Socket::SO_PROTOCOL", 1 if !defined(eval { Socket::SO_PROTOCOL }); 80 skip "SO_PROTOCOL defined but not implemented", 1 81 if !defined $new->sockopt(Socket::SO_PROTOCOL); 82 is($new->protocol(), $p, 'protocol match'); 83 } 84 SKIP: { 85 skip "no Socket::SO_TYPE", 1 if !defined(eval { Socket::SO_TYPE }); 86 skip "SO_TYPE defined but not implemented", 1 87 if !defined $new->sockopt(Socket::SO_TYPE); 88 is($new->socktype(), $s, 'type match'); 89 } 90 91 unlink($socketpath); 92 wait(); 93} 94 95undef $TODO; 96SKIP: { 97 skip "datagram unix sockets not supported on $^O", 7 98 if $^O eq "haiku"; 99 # now test datagram sockets: 100 $listener = IO::Socket::UNIX->new(Type => SOCK_DGRAM, 101 Local => $socketpath); 102 ok(defined($listener), 'datagram socket created'); 103 104 $p = $listener->protocol(); 105 { 106 # see comment above 107 local $TODO = "$^O doesn't support SO_PROTOCOL on AF_UNIX" 108 if $^O =~ /^(netbsd|darwin|cygwin|hpux|solaris|dragonfly|os390)$/; 109 ok(defined($p), 'protocol defined'); 110 } 111 $d = $listener->sockdomain(); 112 ok(defined($d), 'domain defined'); 113 $s = $listener->socktype(); 114 ok(defined($s), 'type defined'); 115 116 my $new = IO::Socket::UNIX->new_from_fd($listener->fileno(), 'r+'); 117 118 is($new->sockdomain(), $d, 'domain match'); 119 SKIP: { 120 skip "no Socket::SO_PROTOCOL", 1 if !defined(eval { Socket::SO_PROTOCOL }); 121 skip "SO_PROTOCOL defined but not implemented", 1 122 if !defined $new->sockopt(Socket::SO_PROTOCOL); 123 skip "SO_PROTOCOL returns chosen protocol on OpenBSD", 1 124 if $^O eq 'openbsd'; 125 is($new->protocol(), $p, 'protocol match'); 126 } 127 SKIP: { 128 skip "AIX: getsockopt(SO_TYPE) is badly broken on UDP/UNIX sockets", 1 129 if $^O eq "aix"; 130 skip "no Socket::SO_TYPE", 1 if !defined(eval { Socket::SO_TYPE }); 131 skip "SO_TYPE defined but not implemented", 1 132 if !defined $new->sockopt(Socket::SO_TYPE); 133 is($new->socktype(), $s, 'type match'); 134 } 135} 136unlink($socketpath); 137