File Coverage

blib/lib/Win32/Socketpair.pm
Criterion Covered Total %
statement 16 16 100.0
branch 1 2 50.0
condition n/a
subroutine 6 6 100.0
pod n/a
total 23 24 95.8


line stmt bran cond sub pod time code
1             package Win32::Socketpair;
2 1     1   41459 use strict;
  1         4  
  1         38  
3 1     1   5 use warnings;
  1         3  
  1         36  
4 1     1   6 use Carp qw(croak carp);
  1         6  
  1         105  
5 1     1   1407 use Socket;
  1         9894  
  1         877  
6 1     1   1154 use Errno 'EINPROGRESS';
  1         2537  
  1         302  
7              
8             our $VERSION = '0.02';
9              
10             BEGIN {
11 1 50   1   269305 $^O =~ /mswin/i
12             or croak __PACKAGE__ . " can be only used on MSWin32 systems";
13             }
14              
15             require Exporter;
16             our @ISA = qw(Exporter);
17              
18             our %EXPORT_TAGS = ( 'all' => [ qw(winsocketpair winopen2 winopen2_5 ) ] );
19             our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
20              
21             sub winsocketpair {
22             my $proto = getprotobyname('tcp');
23             my $true = 1;
24             my $false = 0;
25              
26             for (1..5) {
27             carp "winsocketpair failed: $!, retrying" unless $_ == 1;
28              
29             socket( my $listener, AF_INET, SOCK_STREAM, $proto ) or return ();
30             socket( my $server, AF_INET, SOCK_STREAM, $proto ) or return ();
31             socket( my $client, AF_INET, SOCK_STREAM, $proto ) or return ();
32              
33             ioctl( $client, 0x8004667e, \$true );
34              
35             my $addr = sockaddr_in( 0, INADDR_LOOPBACK );
36             bind( $listener, $addr ) or return ();
37             listen( $listener, 1 ) or return ();
38             $addr = getsockname( $listener );
39              
40             connect( $client, $addr )
41             or $! == 10035 or $! == EINPROGRESS
42             or next;
43             my $peer = accept( $server, $listener ) or next;
44              
45             ioctl( $client, 0x8004667e, \$false );
46              
47             if( $peer eq getsockname( $client ) ) {
48             return( $server, $client );
49             }
50             }
51             return ();
52             }
53              
54             sub winopen2 {
55             my ($pid, $oldin, $oldout);
56              
57             my ($server, $client) = winsocketpair
58             or return undef;
59              
60             open $oldin, '<&', \*STDIN or return ();
61             open $oldout, '>&', \*STDOUT or return ();
62              
63             if( open( STDIN, '<&', $server )
64             and open( STDOUT, '>&', $server )
65             ) {
66             $pid = eval { system 1, @_ or die "system command failed: $!"};
67             # print STDERR "error: $@\n" if $@;
68             }
69             close STDOUT;
70             open STDOUT, '>&', $oldout
71             or carp "unable to reestablish STDOUT";
72              
73             close STDIN;
74             open STDIN, '<&', $oldin
75             or carp "unable to reestablish STDIN";
76              
77             #printf STDERR "pid %d, fileno %d, stdout %d, stdin %d\n",
78             # $pid, fileno($client), fileno STDOUT, fileno STDIN;
79              
80             return ($pid and $pid > 0) ? ($pid, $client) : ();
81             }
82              
83             sub winopen2_5 {
84             my( $pid, $oldin, $oldout, $olderr );
85              
86             my( $server, $client ) = winsocketpair
87             or return undef;
88              
89             open $oldin, '<&', \*STDIN or return ();
90             open $oldout, '>&', \*STDOUT or return ();
91             open $olderr, '>&', \*STDERR or return ();
92              
93             if( open( STDIN, '<&', $server )
94             and open (STDOUT, '>&', $server)
95             and open (STDERR, '>&', $server)
96             ) {
97             $pid = eval{ system 1, @_ or die "system command failed: $!" };
98             # print STDERR "error: $@\n" if $@;
99             }
100             close STDERR;
101             open STDERR, '>&', $olderr
102             or carp "unable to reestablish STDERR";
103              
104             close STDOUT;
105             open STDOUT, '>&', $oldout
106             or carp "unable to reestablish STDOUT";
107              
108             close STDIN;
109             open STDIN, '<&', $oldin
110             or carp "unable to reestablish STDIN";
111              
112             #printf STDERR "pid %d, fileno %d, stdout %d, stdin %d\n",
113             # $pid, fileno($client), fileno STDOUT, fileno STDIN;
114              
115             return ( $pid and $pid > 0 ) ? ( $pid, $client ) : ();
116             }
117              
118              
119             1;
120              
121             __END__