File Coverage

blib/lib/IO/Socket/INET.pm
Criterion Covered Total %
statement 96 147 65.3
branch 57 126 45.2
condition 35 65 53.8
subroutine 15 22 68.1
pod 8 10 80.0
total 211 370 57.0


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