Filename | /usr/lib/x86_64-linux-gnu/perl/5.20/IO/Socket.pm |
Statements | Executed 0 statements in 0s |
Line | State ments |
Time on line |
Calls | Time in subs |
Code |
---|---|---|---|---|---|
1 | # IO::Socket.pm | ||||
2 | # | ||||
3 | # Copyright (c) 1997-8 Graham Barr <gbarr@pobox.com>. 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; | ||||
8 | |||||
9 | require 5.006; | ||||
10 | |||||
11 | use IO::Handle; | ||||
12 | use Socket 1.3; | ||||
13 | use Carp; | ||||
14 | use strict; | ||||
15 | our(@ISA, $VERSION, @EXPORT_OK); | ||||
16 | use Exporter; | ||||
17 | use Errno; | ||||
18 | |||||
19 | # legacy | ||||
20 | |||||
21 | require IO::Socket::INET; | ||||
22 | require IO::Socket::UNIX if ($^O ne 'epoc' && $^O ne 'symbian'); | ||||
23 | |||||
24 | @ISA = qw(IO::Handle); | ||||
25 | |||||
26 | $VERSION = "1.38"; | ||||
27 | |||||
28 | @EXPORT_OK = qw(sockatmark); | ||||
29 | |||||
30 | sub import { | ||||
31 | my $pkg = shift; | ||||
32 | if (@_ && $_[0] eq 'sockatmark') { # not very extensible but for now, fast | ||||
33 | Exporter::export_to_level('IO::Socket', 1, $pkg, 'sockatmark'); | ||||
34 | } else { | ||||
35 | my $callpkg = caller; | ||||
36 | Exporter::export 'Socket', $callpkg, @_; | ||||
37 | } | ||||
38 | } | ||||
39 | |||||
40 | sub new { | ||||
41 | my($class,%arg) = @_; | ||||
42 | my $sock = $class->SUPER::new(); | ||||
43 | |||||
44 | 1 | 27µs | $sock->autoflush(1); # spent 27µs making 1 call to SelectSaver::DESTROY | ||
45 | |||||
46 | ${*$sock}{'io_socket_timeout'} = delete $arg{Timeout}; | ||||
47 | |||||
48 | return scalar(%arg) ? $sock->configure(\%arg) | ||||
49 | : $sock; | ||||
50 | } | ||||
51 | |||||
52 | my @domain2pkg; | ||||
53 | |||||
54 | sub register_domain { | ||||
55 | my($p,$d) = @_; | ||||
56 | $domain2pkg[$d] = $p; | ||||
57 | } | ||||
58 | |||||
59 | sub configure { | ||||
60 | my($sock,$arg) = @_; | ||||
61 | my $domain = delete $arg->{Domain}; | ||||
62 | |||||
63 | croak 'IO::Socket: Cannot configure a generic socket' | ||||
64 | unless defined $domain; | ||||
65 | |||||
66 | croak "IO::Socket: Unsupported socket domain" | ||||
67 | unless defined $domain2pkg[$domain]; | ||||
68 | |||||
69 | croak "IO::Socket: Cannot configure socket in domain '$domain'" | ||||
70 | unless ref($sock) eq "IO::Socket"; | ||||
71 | |||||
72 | bless($sock, $domain2pkg[$domain]); | ||||
73 | $sock->configure($arg); | ||||
74 | } | ||||
75 | |||||
76 | sub socket { | ||||
77 | @_ == 4 or croak 'usage: $sock->socket(DOMAIN, TYPE, PROTOCOL)'; | ||||
78 | my($sock,$domain,$type,$protocol) = @_; | ||||
79 | |||||
80 | socket($sock,$domain,$type,$protocol) or | ||||
81 | return undef; | ||||
82 | |||||
83 | ${*$sock}{'io_socket_domain'} = $domain; | ||||
84 | ${*$sock}{'io_socket_type'} = $type; | ||||
85 | ${*$sock}{'io_socket_proto'} = $protocol; | ||||
86 | |||||
87 | $sock; | ||||
88 | } | ||||
89 | |||||
90 | sub socketpair { | ||||
91 | @_ == 4 || croak 'usage: IO::Socket->socketpair(DOMAIN, TYPE, PROTOCOL)'; | ||||
92 | my($class,$domain,$type,$protocol) = @_; | ||||
93 | my $sock1 = $class->new(); | ||||
94 | my $sock2 = $class->new(); | ||||
95 | |||||
96 | socketpair($sock1,$sock2,$domain,$type,$protocol) or | ||||
97 | return (); | ||||
98 | |||||
99 | ${*$sock1}{'io_socket_type'} = ${*$sock2}{'io_socket_type'} = $type; | ||||
100 | ${*$sock1}{'io_socket_proto'} = ${*$sock2}{'io_socket_proto'} = $protocol; | ||||
101 | |||||
102 | ($sock1,$sock2); | ||||
103 | } | ||||
104 | |||||
105 | sub connect { | ||||
106 | @_ == 2 or croak 'usage: $sock->connect(NAME)'; | ||||
107 | my $sock = shift; | ||||
108 | my $addr = shift; | ||||
109 | my $timeout = ${*$sock}{'io_socket_timeout'}; | ||||
110 | my $err; | ||||
111 | my $blocking; | ||||
112 | |||||
113 | $blocking = $sock->blocking(0) if $timeout; | ||||
114 | if (!connect($sock, $addr)) { | ||||
115 | if (defined $timeout && ($!{EINPROGRESS} || $!{EWOULDBLOCK})) { | ||||
116 | require IO::Select; | ||||
117 | |||||
118 | my $sel = new IO::Select $sock; | ||||
119 | |||||
120 | undef $!; | ||||
121 | my($r,$w,$e) = IO::Select::select(undef,$sel,$sel,$timeout); | ||||
122 | if(@$e[0]) { | ||||
123 | # Windows return from select after the timeout in case of | ||||
124 | # WSAECONNREFUSED(10061) if exception set is not used. | ||||
125 | # This behavior is different from Linux. | ||||
126 | # Using the exception | ||||
127 | # set we now emulate the behavior in Linux | ||||
128 | # - Karthik Rajagopalan | ||||
129 | $err = $sock->getsockopt(SOL_SOCKET,SO_ERROR); | ||||
130 | $@ = "connect: $err"; | ||||
131 | } | ||||
132 | elsif(!@$w[0]) { | ||||
133 | $err = $! || (exists &Errno::ETIMEDOUT ? &Errno::ETIMEDOUT : 1); | ||||
134 | $@ = "connect: timeout"; | ||||
135 | } | ||||
136 | elsif (!connect($sock,$addr) && | ||||
137 | not ($!{EISCONN} || ($^O eq 'MSWin32' && | ||||
138 | ($! == (($] < 5.019004) ? 10022 : Errno::EINVAL)))) | ||||
139 | ) { | ||||
140 | # Some systems refuse to re-connect() to | ||||
141 | # an already open socket and set errno to EISCONN. | ||||
142 | # Windows sets errno to WSAEINVAL (10022) (pre-5.19.4) or | ||||
143 | # EINVAL (22) (5.19.4 onwards). | ||||
144 | $err = $!; | ||||
145 | $@ = "connect: $!"; | ||||
146 | } | ||||
147 | } | ||||
148 | elsif ($blocking || !($!{EINPROGRESS} || $!{EWOULDBLOCK})) { | ||||
149 | $err = $!; | ||||
150 | $@ = "connect: $!"; | ||||
151 | } | ||||
152 | } | ||||
153 | |||||
154 | $sock->blocking(1) if $blocking; | ||||
155 | |||||
156 | $! = $err if $err; | ||||
157 | |||||
158 | $err ? undef : $sock; | ||||
159 | } | ||||
160 | |||||
161 | # Enable/disable blocking IO on sockets. | ||||
162 | # Without args return the current status of blocking, | ||||
163 | # with args change the mode as appropriate, returning the | ||||
164 | # old setting, or in case of error during the mode change | ||||
165 | # undef. | ||||
166 | |||||
167 | sub blocking { | ||||
168 | my $sock = shift; | ||||
169 | |||||
170 | return $sock->SUPER::blocking(@_) | ||||
171 | if $^O ne 'MSWin32' && $^O ne 'VMS'; | ||||
172 | |||||
173 | # Windows handles blocking differently | ||||
174 | # | ||||
175 | # http://groups.google.co.uk/group/perl.perl5.porters/browse_thread/thread/b4e2b1d88280ddff/630b667a66e3509f?#630b667a66e3509f | ||||
176 | # http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winsock/winsock/ioctlsocket_2.asp | ||||
177 | # | ||||
178 | # 0x8004667e is FIONBIO | ||||
179 | # | ||||
180 | # which is used to set blocking behaviour. | ||||
181 | |||||
182 | # NOTE: | ||||
183 | # This is a little confusing, the perl keyword for this is | ||||
184 | # 'blocking' but the OS level behaviour is 'non-blocking', probably | ||||
185 | # because sockets are blocking by default. | ||||
186 | # Therefore internally we have to reverse the semantics. | ||||
187 | |||||
188 | my $orig= !${*$sock}{io_sock_nonblocking}; | ||||
189 | |||||
190 | return $orig unless @_; | ||||
191 | |||||
192 | my $block = shift; | ||||
193 | |||||
194 | if ( !$block != !$orig ) { | ||||
195 | ${*$sock}{io_sock_nonblocking} = $block ? 0 : 1; | ||||
196 | ioctl($sock, 0x8004667e, pack("L!",${*$sock}{io_sock_nonblocking})) | ||||
197 | or return undef; | ||||
198 | } | ||||
199 | |||||
200 | return $orig; | ||||
201 | } | ||||
202 | |||||
203 | sub close { | ||||
204 | @_ == 1 or croak 'usage: $sock->close()'; | ||||
205 | my $sock = shift; | ||||
206 | ${*$sock}{'io_socket_peername'} = undef; | ||||
207 | $sock->SUPER::close(); | ||||
208 | } | ||||
209 | |||||
210 | sub bind { | ||||
211 | @_ == 2 or croak 'usage: $sock->bind(NAME)'; | ||||
212 | my $sock = shift; | ||||
213 | my $addr = shift; | ||||
214 | |||||
215 | return bind($sock, $addr) ? $sock | ||||
216 | : undef; | ||||
217 | } | ||||
218 | |||||
219 | sub listen { | ||||
220 | @_ >= 1 && @_ <= 2 or croak 'usage: $sock->listen([QUEUE])'; | ||||
221 | my($sock,$queue) = @_; | ||||
222 | $queue = 5 | ||||
223 | unless $queue && $queue > 0; | ||||
224 | |||||
225 | return listen($sock, $queue) ? $sock | ||||
226 | : undef; | ||||
227 | } | ||||
228 | |||||
229 | sub accept { | ||||
230 | @_ == 1 || @_ == 2 or croak 'usage $sock->accept([PKG])'; | ||||
231 | my $sock = shift; | ||||
232 | my $pkg = shift || $sock; | ||||
233 | my $timeout = ${*$sock}{'io_socket_timeout'}; | ||||
234 | my $new = $pkg->new(Timeout => $timeout); | ||||
235 | my $peer = undef; | ||||
236 | |||||
237 | if(defined $timeout) { | ||||
238 | require IO::Select; | ||||
239 | |||||
240 | my $sel = new IO::Select $sock; | ||||
241 | |||||
242 | unless ($sel->can_read($timeout)) { | ||||
243 | $@ = 'accept: timeout'; | ||||
244 | $! = (exists &Errno::ETIMEDOUT ? &Errno::ETIMEDOUT : 1); | ||||
245 | return; | ||||
246 | } | ||||
247 | } | ||||
248 | |||||
249 | $peer = accept($new,$sock) | ||||
250 | or return; | ||||
251 | |||||
252 | ${*$new}{$_} = ${*$sock}{$_} for qw( io_socket_domain io_socket_type io_socket_proto ); | ||||
253 | |||||
254 | return wantarray ? ($new, $peer) | ||||
255 | : $new; | ||||
256 | } | ||||
257 | |||||
258 | sub sockname { | ||||
259 | @_ == 1 or croak 'usage: $sock->sockname()'; | ||||
260 | getsockname($_[0]); | ||||
261 | } | ||||
262 | |||||
263 | sub peername { | ||||
264 | @_ == 1 or croak 'usage: $sock->peername()'; | ||||
265 | my($sock) = @_; | ||||
266 | ${*$sock}{'io_socket_peername'} ||= getpeername($sock); | ||||
267 | } | ||||
268 | |||||
269 | sub connected { | ||||
270 | @_ == 1 or croak 'usage: $sock->connected()'; | ||||
271 | my($sock) = @_; | ||||
272 | getpeername($sock); | ||||
273 | } | ||||
274 | |||||
275 | sub send { | ||||
276 | @_ >= 2 && @_ <= 4 or croak 'usage: $sock->send(BUF, [FLAGS, [TO]])'; | ||||
277 | my $sock = $_[0]; | ||||
278 | my $flags = $_[2] || 0; | ||||
279 | my $peer = $_[3] || $sock->peername; | ||||
280 | |||||
281 | croak 'send: Cannot determine peer address' | ||||
282 | unless(defined $peer); | ||||
283 | |||||
284 | my $r = defined(getpeername($sock)) | ||||
285 | ? send($sock, $_[1], $flags) | ||||
286 | : send($sock, $_[1], $flags, $peer); | ||||
287 | |||||
288 | # remember who we send to, if it was successful | ||||
289 | ${*$sock}{'io_socket_peername'} = $peer | ||||
290 | if(@_ == 4 && defined $r); | ||||
291 | |||||
292 | $r; | ||||
293 | } | ||||
294 | |||||
295 | sub recv { | ||||
296 | @_ == 3 || @_ == 4 or croak 'usage: $sock->recv(BUF, LEN [, FLAGS])'; | ||||
297 | my $sock = $_[0]; | ||||
298 | my $len = $_[2]; | ||||
299 | my $flags = $_[3] || 0; | ||||
300 | |||||
301 | # remember who we recv'd from | ||||
302 | ${*$sock}{'io_socket_peername'} = recv($sock, $_[1]='', $len, $flags); | ||||
303 | } | ||||
304 | |||||
305 | sub shutdown { | ||||
306 | @_ == 2 or croak 'usage: $sock->shutdown(HOW)'; | ||||
307 | my($sock, $how) = @_; | ||||
308 | ${*$sock}{'io_socket_peername'} = undef; | ||||
309 | shutdown($sock, $how); | ||||
310 | } | ||||
311 | |||||
312 | sub setsockopt { | ||||
313 | @_ == 4 or croak '$sock->setsockopt(LEVEL, OPTNAME, OPTVAL)'; | ||||
314 | setsockopt($_[0],$_[1],$_[2],$_[3]); | ||||
315 | } | ||||
316 | |||||
317 | my $intsize = length(pack("i",0)); | ||||
318 | |||||
319 | sub getsockopt { | ||||
320 | @_ == 3 or croak '$sock->getsockopt(LEVEL, OPTNAME)'; | ||||
321 | my $r = getsockopt($_[0],$_[1],$_[2]); | ||||
322 | # Just a guess | ||||
323 | $r = unpack("i", $r) | ||||
324 | if(defined $r && length($r) == $intsize); | ||||
325 | $r; | ||||
326 | } | ||||
327 | |||||
328 | sub sockopt { | ||||
329 | my $sock = shift; | ||||
330 | @_ == 1 ? $sock->getsockopt(SOL_SOCKET,@_) | ||||
331 | : $sock->setsockopt(SOL_SOCKET,@_); | ||||
332 | } | ||||
333 | |||||
334 | sub atmark { | ||||
335 | @_ == 1 or croak 'usage: $sock->atmark()'; | ||||
336 | my($sock) = @_; | ||||
337 | sockatmark($sock); | ||||
338 | } | ||||
339 | |||||
340 | sub timeout { | ||||
341 | @_ == 1 || @_ == 2 or croak 'usage: $sock->timeout([VALUE])'; | ||||
342 | my($sock,$val) = @_; | ||||
343 | my $r = ${*$sock}{'io_socket_timeout'}; | ||||
344 | |||||
345 | ${*$sock}{'io_socket_timeout'} = defined $val ? 0 + $val : $val | ||||
346 | if(@_ == 2); | ||||
347 | |||||
348 | $r; | ||||
349 | } | ||||
350 | |||||
351 | sub sockdomain { | ||||
352 | @_ == 1 or croak 'usage: $sock->sockdomain()'; | ||||
353 | my $sock = shift; | ||||
354 | if (!defined(${*$sock}{'io_socket_domain'})) { | ||||
355 | my $addr = $sock->sockname(); | ||||
356 | ${*$sock}{'io_socket_domain'} = sockaddr_family($addr) | ||||
357 | if (defined($addr)); | ||||
358 | } | ||||
359 | ${*$sock}{'io_socket_domain'}; | ||||
360 | } | ||||
361 | |||||
362 | sub socktype { | ||||
363 | @_ == 1 or croak 'usage: $sock->socktype()'; | ||||
364 | my $sock = shift; | ||||
365 | ${*$sock}{'io_socket_type'} = $sock->sockopt(Socket::SO_TYPE) | ||||
366 | if (!defined(${*$sock}{'io_socket_type'}) && defined(eval{Socket::SO_TYPE})); | ||||
367 | ${*$sock}{'io_socket_type'} | ||||
368 | } | ||||
369 | |||||
370 | sub protocol { | ||||
371 | @_ == 1 or croak 'usage: $sock->protocol()'; | ||||
372 | my($sock) = @_; | ||||
373 | ${*$sock}{'io_socket_proto'} = $sock->sockopt(Socket::SO_PROTOCOL) | ||||
374 | if (!defined(${*$sock}{'io_socket_proto'}) && defined(eval{Socket::SO_PROTOCOL})); | ||||
375 | ${*$sock}{'io_socket_proto'}; | ||||
376 | } | ||||
377 | |||||
378 | 1; | ||||
379 | |||||
380 | __END__ | ||||
381 |