File Coverage

inc/IO/Socket/INET.pm
Criterion Covered Total %
statement 18 145 12.4
branch 0 126 0.0
condition 0 65 0.0
subroutine 6 22 27.2
pod 7 10 70.0
total 31 368 8.4


line stmt bran cond sub pod time code
1             #line 1
2             # IO::Socket::INET.pm
3             #
4             # Copyright (c) 1997-8 Graham Barr . All rights reserved.
5             # This program is free software; you can redistribute it and/or
6             # modify it under the same terms as Perl itself.
7              
8             package IO::Socket::INET;
9 5     5   17  
  5         7  
  5         213  
10             use strict;
11 5     5   1248 our(@ISA, $VERSION);
  5         7  
  5         15  
12 5     5   26 use IO::Socket;
  5         6  
  5         2843  
13 5     5   23 use Socket;
  5         5  
  5         193  
14 5     5   16 use Carp;
  5         4  
  5         111  
15 5     5   14 use Exporter;
  5         5  
  5         7318  
16             use Errno;
17              
18             @ISA = qw(IO::Socket);
19             $VERSION = "1.31";
20              
21             my $EINVAL = exists(&Errno::EINVAL) ? Errno::EINVAL() : 1;
22              
23             IO::Socket::INET->register_domain( AF_INET );
24              
25             my %socket_type = ( tcp => SOCK_STREAM,
26             udp => SOCK_DGRAM,
27             icmp => SOCK_RAW
28             );
29             my %proto_number;
30             $proto_number{tcp} = Socket::IPPROTO_TCP() if defined &Socket::IPPROTO_TCP;
31             $proto_number{upd} = Socket::IPPROTO_UDP() if defined &Socket::IPPROTO_UDP;
32             $proto_number{icmp} = Socket::IPPROTO_ICMP() if defined &Socket::IPPROTO_ICMP;
33             my %proto_name = reverse %proto_number;
34              
35 0     0 1   sub new {
36 0 0         my $class = shift;
37 0           unshift(@_, "PeerAddr") if @_ == 1;
38             return $class->SUPER::new(@_);
39             }
40              
41 0     0     sub _cache_proto {
42 0           my @proto = @_;
43 0           for (map lc($_), $proto[0], split(' ', $proto[1])) {
44             $proto_number{$_} = $proto[2];
45 0           }
46             $proto_name{$proto[2]} = $proto[0];
47             }
48              
49 0     0     sub _get_proto_number {
50 0 0         my $name = lc(shift);
51 0 0         return undef unless defined $name;
52             return $proto_number{$name} if exists $proto_number{$name};
53 0            
54 0 0         my @proto = getprotobyname($name);
55 0           return undef unless @proto;
56             _cache_proto(@proto);
57 0            
58             return $proto[2];
59             }
60              
61 0     0     sub _get_proto_name {
62 0 0         my $num = shift;
63 0 0         return undef unless defined $num;
64             return $proto_name{$num} if exists $proto_name{$num};
65 0            
66 0 0         my @proto = getprotobynumber($num);
67 0           return undef unless @proto;
68             _cache_proto(@proto);
69 0            
70             return $proto[0];
71             }
72              
73 0     0     sub _sock_info {
74 0           my($addr,$port,$proto) = @_;
75 0           my $origport = $port;
76             my @serv = ();
77 0 0 0        
78             $port = $1
79             if(defined $addr && $addr =~ s,:([\w\(\)/]+)$,,);
80 0 0 0        
81 0           if(defined $proto && $proto =~ /\D/) {
82 0 0         my $num = _get_proto_number($proto);
83 0           unless (defined $num) {
84 0           $@ = "Bad protocol '$proto'";
85             return;
86 0           }
87             $proto = $num;
88             }
89 0 0          
90 0 0         if(defined $port) {
91 0           my $defport = ($port =~ s,\((\d+)\)$,,) ? $1 : undef;
92             my $pnum = ($port =~ m,^(\d+)$,)[0];
93 0 0 0        
94             @serv = getservbyname($port, _get_proto_name($proto) || "")
95             if ($port =~ m,\D,);
96 0   0        
97 0 0         $port = $serv[2] || $defport || $pnum;
98 0           unless (defined $port) {
99 0           $@ = "Bad service '$origport'";
100             return;
101             }
102 0 0 0        
103             $proto = _get_proto_number($serv[3]) if @serv && !$proto;
104             }
105 0   0        
      0        
      0        
106             return ($addr || undef,
107             $port || undef,
108             $proto || undef
109             );
110             }
111              
112 0     0     sub _error {
113 0           my $sock = shift;
114             my $err = shift;
115 0           {
  0            
116 0           local($!);
117 0 0         my $title = ref($sock).": ";
118 0 0         $@ = join("", $_[0] =~ /^$title/ ? "" : $title, @_);
119             $sock->close()
120             if(defined fileno($sock));
121 0           }
122 0           $! = $err;
123             return undef;
124             }
125              
126 0     0     sub _get_addr {
127 0           my($sock,$addr_str, $multi) = @_;
128 0 0 0       my @addr;
129 0           if ($multi && $addr_str !~ /^\d+(?:\.\d+){3}$/) {
130             (undef, undef, undef, undef, @addr) = gethostbyname($addr_str);
131 0           } else {
132 0 0         my $h = inet_aton($addr_str);
133             push(@addr, $h) if defined $h;
134 0           }
135             @addr;
136             }
137              
138 0     0 0   sub configure {
139 0           my($sock,$arg) = @_;
140             my($lport,$rport,$laddr,$raddr,$proto,$type);
141              
142              
143 0 0 0       $arg->{LocalAddr} = $arg->{LocalHost}
144             if exists $arg->{LocalHost} && !exists $arg->{LocalAddr};
145              
146             ($laddr,$lport,$proto) = _sock_info($arg->{LocalAddr},
147             $arg->{LocalPort},
148 0 0         $arg->{Proto})
149             or return _error($sock, $!, $@);
150 0 0          
151             $laddr = defined $laddr ? inet_aton($laddr)
152             : INADDR_ANY;
153 0 0          
154             return _error($sock, $EINVAL, "Bad hostname '",$arg->{LocalAddr},"'")
155             unless(defined $laddr);
156              
157 0 0 0       $arg->{PeerAddr} = $arg->{PeerHost}
158             if exists $arg->{PeerHost} && !exists $arg->{PeerAddr};
159 0 0          
160             unless(exists $arg->{Listen}) {
161             ($raddr,$rport,$proto) = _sock_info($arg->{PeerAddr},
162 0 0         $arg->{PeerPort},
163             $proto)
164             or return _error($sock, $!, $@);
165             }
166 0   0        
167             $proto ||= _get_proto_number('tcp');
168 0   0        
169             $type = $arg->{Type} || $socket_type{lc _get_proto_name($proto)};
170 0            
171             my @raddr = ();
172 0 0          
173 0           if(defined $raddr) {
174 0 0         @raddr = $sock->_get_addr($raddr, $arg->{MultiHomed});
175             return _error($sock, $EINVAL, "Bad hostname '",$arg->{PeerAddr},"'")
176             unless @raddr;
177             }
178 0            
179             while(1) {
180 0 0          
181             $sock->socket(AF_INET, $type, $proto) or
182             return _error($sock, $!, "$!");
183 0 0          
184             if (defined $arg->{Blocking}) {
185 0 0         defined $sock->blocking($arg->{Blocking})
186             or return _error($sock, $!, "$!");
187             }
188 0 0 0        
189 0 0         if ($arg->{Reuse} || $arg->{ReuseAddr}) {
190             $sock->sockopt(SO_REUSEADDR,1) or
191             return _error($sock, $!, "$!");
192             }
193 0 0          
194 0 0         if ($arg->{ReusePort}) {
195             $sock->sockopt(SO_REUSEPORT,1) or
196             return _error($sock, $!, "$!");
197             }
198 0 0          
199 0 0         if ($arg->{Broadcast}) {
200             $sock->sockopt(SO_BROADCAST,1) or
201             return _error($sock, $!, "$!");
202             }
203 0 0 0        
      0        
204 0 0 0       if($lport || ($laddr ne INADDR_ANY) || exists $arg->{Listen}) {
205             $sock->bind($lport || 0, $laddr) or
206             return _error($sock, $!, "$!");
207             }
208 0 0          
209 0 0 0       if(exists $arg->{Listen}) {
210             $sock->listen($arg->{Listen} || 5) or
211 0           return _error($sock, $!, "$!");
212             last;
213             }
214              
215 0 0         # don't try to connect unless we're given a PeerAddr
216             last unless exists($arg->{PeerAddr});
217 0          
218             $raddr = shift @raddr;
219 0 0 0        
      0        
220             return _error($sock, $EINVAL, 'Cannot determine remote port')
221             unless($rport || $type == SOCK_DGRAM || $type == SOCK_RAW);
222              
223 0 0 0       last
224             unless($type == SOCK_STREAM || defined $raddr);
225 0 0          
226             return _error($sock, $EINVAL, "Bad hostname '",$arg->{PeerAddr},"'")
227             unless defined $raddr;
228              
229             # my $timeout = ${*$sock}{'io_socket_timeout'};
230             # my $before = time() if $timeout;
231 0            
232 0 0         undef $@;
233             if ($sock->connect(pack_sockaddr_in($rport, $raddr))) {
234 0           # ${*$sock}{'io_socket_timeout'} = $timeout;
235             return $sock;
236             }
237 0 0 0        
238             return _error($sock, $!, $@ || "Timeout")
239             unless @raddr;
240              
241             # if ($timeout) {
242             # my $new_timeout = $timeout - (time() - $before);
243             # return _error($sock,
244             # (exists(&Errno::ETIMEDOUT) ? Errno::ETIMEDOUT() : $EINVAL),
245             # "Timeout") if $new_timeout <= 0;
246             # ${*$sock}{'io_socket_timeout'} = $new_timeout;
247             # }
248              
249             }
250 0            
251             $sock;
252             }
253              
254 0 0 0 0 0   sub connect {
255             @_ == 2 || @_ == 3 or
256 0           croak 'usage: $sock->connect(NAME) or $sock->connect(PORT, ADDR)';
257 0 0         my $sock = shift;
258             return $sock->SUPER::connect(@_ == 1 ? shift : pack_sockaddr_in(@_));
259             }
260              
261 0 0 0 0 0   sub bind {
262             @_ == 2 || @_ == 3 or
263 0           croak 'usage: $sock->bind(NAME) or $sock->bind(PORT, ADDR)';
264 0 0         my $sock = shift;
265             return $sock->SUPER::bind(@_ == 1 ? shift : pack_sockaddr_in(@_))
266             }
267              
268 0 0   0 1   sub sockaddr {
269 0           @_ == 1 or croak 'usage: $sock->sockaddr()';
270 0           my($sock) = @_;
271 0 0         my $name = $sock->sockname;
272             $name ? (sockaddr_in($name))[1] : undef;
273             }
274              
275 0 0   0 1   sub sockport {
276 0           @_ == 1 or croak 'usage: $sock->sockport()';
277 0           my($sock) = @_;
278 0 0         my $name = $sock->sockname;
279             $name ? (sockaddr_in($name))[0] : undef;
280             }
281              
282 0 0   0 1   sub sockhost {
283 0           @_ == 1 or croak 'usage: $sock->sockhost()';
284 0           my($sock) = @_;
285 0 0         my $addr = $sock->sockaddr;
286             $addr ? inet_ntoa($addr) : undef;
287             }
288              
289 0 0   0 1   sub peeraddr {
290 0           @_ == 1 or croak 'usage: $sock->peeraddr()';
291 0           my($sock) = @_;
292 0 0         my $name = $sock->peername;
293             $name ? (sockaddr_in($name))[1] : undef;
294             }
295              
296 0 0   0 1   sub peerport {
297 0           @_ == 1 or croak 'usage: $sock->peerport()';
298 0           my($sock) = @_;
299 0 0         my $name = $sock->peername;
300             $name ? (sockaddr_in($name))[0] : undef;
301             }
302              
303 0 0   0 1   sub peerhost {
304 0           @_ == 1 or croak 'usage: $sock->peerhost()';
305 0           my($sock) = @_;
306 0 0         my $addr = $sock->peeraddr;
307             $addr ? inet_ntoa($addr) : undef;
308             }
309              
310             1;
311              
312             __END__