File Coverage

blib/lib/POE/Wheel/SocketFactory.pm
Criterion Covered Total %
statement 252 398 63.3
branch 116 252 46.0
condition 21 62 33.8
subroutine 26 28 92.8
pod 6 7 85.7
total 421 747 56.3


line stmt bran cond sub pod time code
1             package POE::Wheel::SocketFactory;
2              
3 23     23   94 use strict;
  23         34  
  23         780  
4              
5 23     23   94 use vars qw($VERSION @ISA);
  23         28  
  23         1231  
6             $VERSION = '1.365'; # NOTE - Should be #.### (three decimal places)
7              
8 23     23   108 use Carp qw( carp croak );
  23         30  
  23         1162  
9 23     23   104 use Symbol qw( gensym );
  23         30  
  23         1046  
10              
11 23     23   114 use Fcntl qw(F_GETFL F_SETFL O_NONBLOCK);
  23         42  
  23         1277  
12 23         1477 use Errno qw(
13             EWOULDBLOCK EADDRNOTAVAIL EINPROGRESS EADDRINUSE ECONNABORTED
14             ESPIPE
15 23     23   116 );
  23         36  
16              
17 23         2222 use Socket qw(
18             AF_INET SOCK_STREAM SOL_SOCKET AF_UNIX PF_UNIX
19             PF_INET SOCK_DGRAM SO_ERROR unpack_sockaddr_in
20             unpack_sockaddr_un PF_UNSPEC SO_REUSEADDR INADDR_ANY
21             pack_sockaddr_in pack_sockaddr_un inet_aton SOMAXCONN
22 23     23   121 );
  23         32  
23              
24 23     23   108 use IO::Handle ();
  23         34  
  23         330  
25 23     23   82 use FileHandle ();
  23         34  
  23         396  
26 23     23   89 use POE qw( Wheel );
  23         28  
  23         141  
27             push @ISA, qw(POE::Wheel);
28              
29 0     0 0 0 sub CRIMSON_SCOPE_HACK ($) { 0 }
30             sub DEBUG () { 0 }
31              
32             sub MY_SOCKET_HANDLE () { 0 }
33             sub MY_UNIQUE_ID () { 1 }
34             sub MY_EVENT_SUCCESS () { 2 }
35             sub MY_EVENT_FAILURE () { 3 }
36             sub MY_SOCKET_DOMAIN () { 4 }
37             sub MY_STATE_ACCEPT () { 5 }
38             sub MY_STATE_CONNECT () { 6 }
39             sub MY_MINE_SUCCESS () { 7 }
40             sub MY_MINE_FAILURE () { 8 }
41             sub MY_SOCKET_PROTOCOL () { 9 }
42             sub MY_SOCKET_TYPE () { 10 }
43             sub MY_STATE_ERROR () { 11 }
44             sub MY_SOCKET_SELECTED () { 12 }
45              
46             # Fletch has subclassed SSLSocketFactory from SocketFactory.
47             # He's added new members after MY_SOCKET_SELECTED. Be sure, if you
48             # extend this, to extend add stuff BEFORE MY_SOCKET_SELECTED or let
49             # Fletch know you've broken his module.
50              
51             # If IPv6 support can't be loaded, then provide dummies so the code at
52             # least compiles. Suggested in rt.cpan.org 27250.
53             BEGIN {
54              
55 23     23   43 eval { Socket->import( qw(getaddrinfo getnameinfo unpack_sockaddr_in6) ) };
  23         741  
56 23 50       89 if ($@) {
57 0         0 *getaddrinfo = sub { Carp::confess("Unable to use IPv6: Socket doesn't provide getaddrinfo()") };
  0         0  
58 0         0 *getnameinfo = sub { Carp::confess("Unable to use IPv6: Socket doesn't provide getnameinfo()") };
  0         0  
59 0         0 *unpack_sockaddr_in6 = sub { Carp::confess("Unable to use IPv6: Socket doesn't provide unpack_sockaddr_in6()") };
  0         0  
60             }
61              
62             # Socket6 provides AF_INET6 and PF_INET6 where earlier Perls' Socket don't.
63 23         35 eval { Socket->import( qw(AF_INET6 PF_INET6) ) };
  23         531  
64 23 50       57594 if ($@) {
65 0         0 eval { require Socket6; Socket6->import( qw(AF_INET6 PF_INET6) ) };
  0         0  
  0         0  
66 0 0       0 if ($@) {
67 0         0 *AF_INET6 = sub { -1 };
  0         0  
68 0         0 *PF_INET6 = sub { -1 };
  0         0  
69             }
70             }
71             }
72              
73             #------------------------------------------------------------------------------
74             # These tables customize the socketfactory. Many protocols share the
75             # same operations, it seems, and this is a way to add new ones with a
76             # minimum of additional code.
77              
78             sub DOM_UNIX () { 'unix' } # UNIX domain socket
79             sub DOM_INET () { 'inet' } # INET domain socket
80             sub DOM_INET6 () { 'inet6' } # INET v6 domain socket
81              
82             # AF_XYZ and PF_XYZ may be different.
83             my %map_family_to_domain = (
84             AF_UNIX, DOM_UNIX, PF_UNIX, DOM_UNIX,
85             AF_INET, DOM_INET, PF_INET, DOM_INET,
86             AF_INET6, DOM_INET6,
87             PF_INET6, DOM_INET6,
88             );
89              
90             sub SVROP_LISTENS () { 'listens' } # connect/listen sockets
91             sub SVROP_NOTHING () { 'nothing' } # connectionless sockets
92              
93             # Map family/protocol pairs to connection or connectionless
94             # operations.
95             my %supported_protocol = (
96             DOM_UNIX, {
97             none => SVROP_LISTENS
98             },
99             DOM_INET, {
100             tcp => SVROP_LISTENS,
101             udp => SVROP_NOTHING,
102             },
103             DOM_INET6, {
104             tcp => SVROP_LISTENS,
105             udp => SVROP_NOTHING,
106             },
107             );
108              
109             # Sane default socket types for each supported protocol. TODO Maybe
110             # this structure can be combined with %supported_protocol?
111             my %default_socket_type = (
112             DOM_UNIX, {
113             none => SOCK_STREAM
114             },
115             DOM_INET, {
116             tcp => SOCK_STREAM,
117             udp => SOCK_DGRAM,
118             },
119             DOM_INET6, {
120             tcp => SOCK_STREAM,
121             udp => SOCK_DGRAM,
122             },
123             );
124              
125             #------------------------------------------------------------------------------
126             # Perform system-dependent translations on Unix addresses, if
127             # necessary.
128              
129             sub _condition_unix_address {
130 4     4   6 my ($address) = @_;
131              
132             # OS/2 would like sockets to use backwhacks, and please place them
133             # in the virtual \socket\ directory. Thank you.
134 4 50       12 if ($^O eq 'os2') {
135 0         0 $address =~ tr[\\][/];
136 0 0       0 if ($address !~ m{^/socket/}) {
137 0         0 $address =~ s{^/?}{/socket/};
138             }
139 0         0 $address =~ tr[/][\\];
140             }
141              
142 4         7 $address;
143             }
144              
145             #------------------------------------------------------------------------------
146             # Define the select handler that will accept connections.
147              
148             sub _define_accept_state {
149 22     22   31 my $self = shift;
150              
151             # We do these stupid closure tricks to avoid putting $self in it
152             # directly. If you include $self in one of the state() closures,
153             # the component will fail to shut down properly: there will be a
154             # circular definition in the closure holding $self alive.
155              
156 22         47 my $domain = $map_family_to_domain{ $self->[MY_SOCKET_DOMAIN] };
157 22 50       54 $domain = '(undef)' unless defined $domain;
158 22         37 my $event_success = \$self->[MY_EVENT_SUCCESS];
159 22         42 my $event_failure = \$self->[MY_EVENT_FAILURE];
160 22         42 my $unique_id = $self->[MY_UNIQUE_ID];
161              
162             $poe_kernel->state(
163             $self->[MY_STATE_ACCEPT] = ref($self) . "($unique_id) -> select accept",
164             sub {
165             # prevents SEGV
166 64     64   74 0 && CRIMSON_SCOPE_HACK('<');
167              
168             # subroutine starts here
169 64         131 my ($k, $me, $handle) = @_[KERNEL, SESSION, ARG0];
170              
171 64         204 my $new_socket = gensym;
172 64         1957 my $peer = accept($new_socket, $handle);
173              
174 64 50 0     146 if ($peer) {
    0 0        
175 64         66 my ($peer_addr, $peer_port);
176 64 100       271 if ( $domain eq DOM_UNIX ) {
    50          
    0          
177 2         2 $peer_port = undef;
178 2         3 eval { $peer_addr = unpack_sockaddr_un($peer) };
  2         19  
179 2 50       6 $peer_addr = undef if length $@;
180             }
181             elsif ( $domain eq DOM_INET ) {
182 62         280 ($peer_port, $peer_addr) = unpack_sockaddr_in($peer);
183             }
184             elsif ( $domain eq DOM_INET6 ) {
185 0         0 ($peer_addr, $peer_port) = unpack_sockaddr_in6($peer);
186             }
187             else {
188 0         0 die "sanity failure: socket domain == $domain";
189             }
190 64         287 $k->call(
191             $me, $$event_success,
192             $new_socket, $peer_addr, $peer_port,
193             $unique_id
194             );
195             }
196             elsif ($! != EWOULDBLOCK and $! != ECONNABORTED and $! != ESPIPE) {
197             # OSX reports ESPIPE, which isn't documented anywhere.
198 0 0       0 $$event_failure && $k->call(
199             $me, $$event_failure,
200             'accept', ($!+0), $!, $unique_id
201             );
202             }
203             }
204 22         266 );
205              
206 22         38 $self->[MY_SOCKET_SELECTED] = 'yes';
207 22         95 $poe_kernel->select_read(
208             $self->[MY_SOCKET_HANDLE],
209             $self->[MY_STATE_ACCEPT]
210             );
211             }
212              
213             #------------------------------------------------------------------------------
214             # Define the select handler that will finalize an established
215             # connection.
216              
217             sub _define_connect_state {
218 77     77   90 my $self = shift;
219              
220             # We do these stupid closure tricks to avoid putting $self in it
221             # directly. If you include $self in one of the state() closures,
222             # the component will fail to shut down properly: there will be a
223             # circular definition in the closure holding $self alive.
224              
225 77         160 my $domain = $map_family_to_domain{ $self->[MY_SOCKET_DOMAIN] };
226 77 50       171 $domain = '(undef)' unless defined $domain;
227 77         102 my $event_success = \$self->[MY_EVENT_SUCCESS];
228 77         106 my $event_failure = \$self->[MY_EVENT_FAILURE];
229 77         118 my $unique_id = $self->[MY_UNIQUE_ID];
230 77         95 my $socket_selected = \$self->[MY_SOCKET_SELECTED];
231              
232 77         98 my $socket_handle = \$self->[MY_SOCKET_HANDLE];
233 77         90 my $state_accept = \$self->[MY_STATE_ACCEPT];
234 77         90 my $state_connect = \$self->[MY_STATE_CONNECT];
235 77         87 my $mine_success = \$self->[MY_MINE_SUCCESS];
236 77         84 my $mine_failure = \$self->[MY_MINE_FAILURE];
237              
238             $poe_kernel->state(
239             $self->[MY_STATE_CONNECT] = (
240             ref($self) . "($unique_id) -> select connect"
241             ),
242             sub {
243             # This prevents SEGV in older versions of Perl.
244 77     77   87 0 && CRIMSON_SCOPE_HACK('<');
245              
246             # Grab some values and stop watching the socket.
247 77         169 my ($k, $me, $handle) = @_[KERNEL, SESSION, ARG0];
248              
249 77         180 _shutdown(
250             $socket_selected, $socket_handle,
251             $state_accept, $state_connect,
252             $mine_success, $event_success,
253             $mine_failure, $event_failure,
254             );
255              
256             # Throw a failure if the connection failed.
257 77         748 $! = unpack('i', getsockopt($handle, SOL_SOCKET, SO_ERROR));
258 77 100       555 if ($!) {
259 3 50       21 (defined $$event_failure) and $k->call(
260             $me, $$event_failure,
261             'connect', ($!+0), $!, $unique_id
262             );
263 3         47 return;
264             }
265              
266             # Get the remote address, or throw an error if that fails.
267 74         218 my $peer = getpeername($handle);
268 74 50       167 if ($!) {
269 0 0       0 (defined $$event_failure) and $k->call(
270             $me, $$event_failure,
271             'getpeername', ($!+0), $!, $unique_id
272             );
273 0         0 return;
274             }
275              
276             # Parse the remote address according to the socket's domain.
277 74         75 my ($peer_addr, $peer_port);
278              
279             # UNIX sockets have some trouble with peer addresses.
280 74 100       204 if ($domain eq DOM_UNIX) {
    50          
    0          
281 2 50       4 if (defined $peer) {
282 2         3 eval { $peer_addr = unpack_sockaddr_un($peer) };
  2         7  
283 2 50       6 $peer_addr = undef if length $@;
284             }
285             }
286              
287             # INET socket stacks tend not to.
288             elsif ($domain eq DOM_INET) {
289 72 50       135 if (defined $peer) {
290 72         81 eval {
291 72         267 ($peer_port, $peer_addr) = unpack_sockaddr_in($peer);
292             };
293 72 50       189 if (length $@) {
294 0         0 $peer_port = $peer_addr = undef;
295             }
296             }
297             }
298              
299             # INET6 socket stacks tend not to.
300             elsif ($domain eq DOM_INET6) {
301 0 0       0 if (defined $peer) {
302 0         0 ((my $error), $peer_addr, $peer_port) = getnameinfo($peer);
303 0 0       0 if ($error) {
304 0         0 warn $error;
305 0         0 $peer_port = $peer_addr = undef;
306             }
307             }
308             }
309              
310             # What are we doing here?
311             else {
312 0         0 die "sanity failure: socket domain == $domain";
313             }
314              
315             # Tell the session it went okay. Also let go of the socket.
316 74         241 $k->call(
317             $me, $$event_success,
318             $handle, $peer_addr, $peer_port, $unique_id
319             );
320             }
321 77         825 );
322              
323             # Cygwin and Windows expect an error state registered to expedite.
324             # This code is nearly identical the stuff above.
325 77 50 33     555 if ($^O eq "cygwin" or $^O eq "MSWin32") {
326             $poe_kernel->state(
327             $self->[MY_STATE_ERROR] = (
328             ref($self) . "($unique_id) -> connect error"
329             ),
330             sub {
331             # This prevents SEGV in older versions of Perl.
332 0     0   0 0 && CRIMSON_SCOPE_HACK('<');
333              
334             # Grab some values and stop watching the socket.
335 0         0 my ($k, $me, $handle) = @_[KERNEL, SESSION, ARG0];
336              
337 0         0 _shutdown(
338             $socket_selected, $socket_handle,
339             $state_accept, $state_connect,
340             $mine_success, $event_success,
341             $mine_failure, $event_failure,
342             );
343              
344             # Throw a failure if the connection failed.
345 0         0 $! = unpack('i', getsockopt($handle, SOL_SOCKET, SO_ERROR));
346 0 0       0 if ($!) {
347 0 0       0 (defined $$event_failure) and $k->call(
348             $me, $$event_failure, 'connect', ($!+0), $!, $unique_id
349             );
350 0         0 return;
351             }
352             }
353 0         0 );
354 0         0 $poe_kernel->select_expedite(
355             $self->[MY_SOCKET_HANDLE],
356             $self->[MY_STATE_ERROR]
357             );
358             }
359              
360 77         121 $self->[MY_SOCKET_SELECTED] = 'yes';
361 77         243 $poe_kernel->select_write(
362             $self->[MY_SOCKET_HANDLE],
363             $self->[MY_STATE_CONNECT]
364             );
365             }
366              
367             #------------------------------------------------------------------------------
368              
369             sub event {
370 101     101 1 123 my $self = shift;
371 101 50       235 push(@_, undef) if (scalar(@_) & 1);
372              
373 101         207 while (@_) {
374 202         306 my ($name, $event) = splice(@_, 0, 2);
375              
376 202 100       407 if ($name eq 'SuccessEvent') {
    50          
377 101 50       155 if (defined $event) {
378 101 50       184 if (ref($event)) {
379 0         0 carp "reference for SuccessEvent will be treated as an event name"
380             }
381 101         134 $self->[MY_EVENT_SUCCESS] = $event;
382 101         212 undef $self->[MY_MINE_SUCCESS];
383             }
384             else {
385 0         0 carp "SuccessEvent requires an event name. ignoring undef";
386             }
387             }
388             elsif ($name eq 'FailureEvent') {
389 101 50       170 if (defined $event) {
390 101 50       180 if (ref($event)) {
391 0         0 carp "reference for FailureEvent will be treated as an event name";
392             }
393 101         116 $self->[MY_EVENT_FAILURE] = $event;
394 101         246 undef $self->[MY_MINE_FAILURE];
395             }
396             else {
397 0         0 carp "FailureEvent requires an event name. ignoring undef";
398             }
399             }
400             else {
401 0         0 carp "ignoring unknown SocketFactory parameter '$name'";
402             }
403             }
404              
405 101         132 $self->[MY_SOCKET_SELECTED] = 'yes';
406 101 100       982 if (defined $self->[MY_STATE_ACCEPT]) {
    50          
407 22         761 $poe_kernel->select_read(
408             $self->[MY_SOCKET_HANDLE],
409             $self->[MY_STATE_ACCEPT]
410             );
411             }
412             elsif (defined $self->[MY_STATE_CONNECT]) {
413 79         217 $poe_kernel->select_write(
414             $self->[MY_SOCKET_HANDLE],
415             $self->[MY_STATE_CONNECT]
416             );
417 79 50 33     1216 if ($^O eq "cygwin" or $^O eq "MSWin32") {
418 0         0 $poe_kernel->select_expedite(
419             $self->[MY_SOCKET_HANDLE],
420             $self->[MY_STATE_ERROR]
421             );
422             }
423             }
424             else {
425 0         0 die "POE developer error - no state defined";
426             }
427             }
428              
429             #------------------------------------------------------------------------------
430              
431             sub getsockname {
432 24     24 1 133 my $self = shift;
433             return undef unless (
434 24 50 33     172 defined $self->[MY_SOCKET_HANDLE] and
435             fileno($self->[MY_SOCKET_HANDLE])
436             );
437 24         215 return getsockname($self->[MY_SOCKET_HANDLE]);
438             }
439              
440             sub ID {
441 10     10 1 59 return $_[0]->[MY_UNIQUE_ID];
442             }
443              
444             #------------------------------------------------------------------------------
445              
446             sub new {
447 103     103 1 397 my $type = shift;
448              
449             # Don't take responsibility for a bad parameter count.
450 103 50       234 croak "$type requires an even number of parameters" if @_ & 1;
451              
452 103         433 my %params = @_;
453              
454             # The calling convention experienced a hard deprecation.
455 103 50 33     440 croak "wheels no longer require a kernel reference as their first parameter"
456             if (@_ && (ref($_[0]) eq 'POE::Kernel'));
457              
458             # Ensure some of the basic things are present.
459 103 50       225 croak "$type requires a working Kernel" unless (defined $poe_kernel);
460 103 50       215 croak 'SuccessEvent required' unless (defined $params{SuccessEvent});
461 103 50       192 croak 'FailureEvent required' unless (defined $params{FailureEvent});
462 103         134 my $event_success = $params{SuccessEvent};
463 103         108 my $event_failure = $params{FailureEvent};
464              
465             # Create the SocketServer. Cache a copy of the socket handle.
466 103         281 my $socket_handle = gensym();
467 103         1254 my $self = bless(
468             [
469             $socket_handle, # MY_SOCKET_HANDLE
470             &POE::Wheel::allocate_wheel_id(), # MY_UNIQUE_ID
471             $event_success, # MY_EVENT_SUCCESS
472             $event_failure, # MY_EVENT_FAILURE
473             undef, # MY_SOCKET_DOMAIN
474             undef, # MY_STATE_ACCEPT
475             undef, # MY_STATE_CONNECT
476             undef, # MY_MINE_SUCCESS
477             undef, # MY_MINE_FAILURE
478             undef, # MY_SOCKET_PROTOCOL
479             undef, # MY_SOCKET_TYPE
480             undef, # MY_STATE_ERROR
481             undef, # MY_SOCKET_SELECTED
482             ],
483             $type
484             );
485              
486             # Default to Internet sockets.
487 103         203 my $domain = delete $params{SocketDomain};
488 103 100       191 if (defined $domain) {
489             # [rt.cpan.org 76314] Untaint the domain.
490 24         147 ($domain) = ($domain =~ /\A(.*)\z/s);
491             }
492             else {
493 79         103 $domain = AF_INET;
494             }
495 103         247 $self->[MY_SOCKET_DOMAIN] = $domain;
496              
497             # Abstract the socket domain into something we don't have to keep
498             # testing duplicates of.
499 103         166 my $abstract_domain = $map_family_to_domain{$self->[MY_SOCKET_DOMAIN]};
500 103 50       232 unless (defined $abstract_domain) {
501 0         0 $poe_kernel->yield(
502             $event_failure,
503             'domain',
504             0,
505             "SocketDomain $domain is currently unsupported on this platform",
506             $self->[MY_UNIQUE_ID]
507             );
508 0         0 return $self;
509             }
510              
511             #---------------#
512             # Create Socket #
513             #---------------#
514              
515             # Declare the protocol name out here; it'll be needed by
516             # getservbyname later.
517 103         96 my $protocol_name;
518              
519             # Unix sockets don't use protocols; warn the programmer, and force
520             # PF_UNSPEC.
521 103 100 33     362 if ($abstract_domain eq DOM_UNIX) {
    50          
522 4 50       9 carp 'SocketProtocol ignored for Unix socket'
523             if defined $params{SocketProtocol};
524 4         5 $self->[MY_SOCKET_PROTOCOL] = PF_UNSPEC;
525 4         7 $protocol_name = 'none';
526             }
527              
528             # Internet sockets use protocols. Default the INET protocol to tcp,
529             # and try to resolve it.
530             elsif (
531             $abstract_domain eq DOM_INET or
532             $abstract_domain eq DOM_INET6
533             ) {
534 99 100       226 my $socket_protocol = (
535             (defined $params{SocketProtocol})
536             ? $params{SocketProtocol}
537             : 'tcp'
538             );
539              
540             # Dance for systems without getprotobyname
541 99         266 my %proto_by_name = (
542             tcp => Socket::IPPROTO_TCP,
543             udp => Socket::IPPROTO_UDP,
544             );
545 99         326 my %proto_by_number = reverse %proto_by_name;
546 99 50       375 if ($socket_protocol !~ /^\d+$/) {
547 99 50 33     321 unless ($socket_protocol = $proto_by_name{$socket_protocol} || eval { getprotobyname($socket_protocol) }) {
548 0         0 $poe_kernel->yield(
549             $event_failure, 'getprotobyname', $!+0, $!, $self->[MY_UNIQUE_ID]
550             );
551 0         0 return $self;
552             }
553             }
554              
555             # Get the protocol's name regardless of what was provided. If the
556             # protocol isn't supported, croak now instead of making the
557             # programmer wonder why things fail later.
558 99   33     197 $protocol_name = $proto_by_number{$socket_protocol} || eval { lc(getprotobynumber($socket_protocol)) };
559 99 50       184 unless ($protocol_name) {
560 0         0 $poe_kernel->yield(
561             $event_failure, 'getprotobynumber', $!+0, $!, $self->[MY_UNIQUE_ID]
562             );
563 0         0 return $self;
564             }
565              
566 99 50       241 unless (defined $supported_protocol{$abstract_domain}->{$protocol_name}) {
567 0         0 croak "SocketFactory does not support Internet $protocol_name sockets";
568             }
569              
570 99         247 $self->[MY_SOCKET_PROTOCOL] = $socket_protocol;
571             }
572             else {
573 0         0 die "Mail this error to the author of POE: Internal consistency error";
574             }
575              
576             # If no SocketType, default it to something appropriate.
577 103 50       206 if (defined $params{SocketType}) {
578 0         0 $self->[MY_SOCKET_TYPE] = $params{SocketType};
579             }
580             else {
581 103 50       248 unless (defined $default_socket_type{$abstract_domain}->{$protocol_name}) {
582 0         0 croak "SocketFactory does not support $abstract_domain $protocol_name";
583             }
584 103         276 $self->[MY_SOCKET_TYPE] =
585             $default_socket_type{$abstract_domain}->{$protocol_name};
586             }
587              
588             # o create a dummy socket
589             # o cache the value of SO_OPENTYPE in $win32_socket_opt
590             # o set the overlapped io attribute
591             # o close dummy socket
592 103         97 my $win32_socket_opt;
593 103 50       247 if ( POE::Kernel::RUNNING_IN_HELL) {
594              
595             # Constants are evaluated first so they exist when the code uses
596             # them.
597 0         0 eval {
598 0         0 *SO_OPENTYPE = sub () { 0x7008 };
599 0         0 *SO_SYNCHRONOUS_ALERT = sub () { 0x10 };
600 0         0 *SO_SYNCHRONOUS_NONALERT = sub () { 0x20 };
601             };
602 0 0       0 die "Could not install SO constants [$@]" if $@;
603              
604             # Turn on socket overlapped IO attribute per MSKB: Q181611.
605              
606 0         0 eval {
607 0 0       0 socket(POE, AF_INET, SOCK_STREAM, Socket::IPPROTO_TCP)
608             or die "socket failed: $!";
609 0         0 my $opt = unpack("I", getsockopt(POE, SOL_SOCKET, SO_OPENTYPE()));
610 0         0 $win32_socket_opt = $opt;
611 0         0 $opt &= ~(SO_SYNCHRONOUS_ALERT()|SO_SYNCHRONOUS_NONALERT());
612 0         0 setsockopt(POE, SOL_SOCKET, SO_OPENTYPE(), $opt);
613 0         0 close POE;
614             };
615              
616 0 0       0 die if $@;
617             }
618              
619             # Create the socket.
620 103 50       2222 unless (
621             socket( $socket_handle, $self->[MY_SOCKET_DOMAIN],
622             $self->[MY_SOCKET_TYPE], $self->[MY_SOCKET_PROTOCOL]
623             )
624             ) {
625 0         0 $poe_kernel->yield(
626             $event_failure, 'socket', $!+0, $!, $self->[MY_UNIQUE_ID]
627             );
628 0         0 return $self;
629             }
630              
631             # o create a dummy socket
632             # o restore previous value of SO_OPENTYPE
633             # o close dummy socket
634             #
635             # This way we'd only be turning on the overlap attribute for
636             # the socket we created... and not all subsequent sockets.
637 103 50       235 if ( POE::Kernel::RUNNING_IN_HELL) {
638 0         0 eval {
639 0 0       0 socket(POE, AF_INET, SOCK_STREAM, Socket::IPPROTO_TCP)
640             or die "socket failed: $!";
641 0         0 setsockopt(POE, SOL_SOCKET, SO_OPENTYPE(), $win32_socket_opt);
642 0         0 close POE;
643             };
644              
645 0 0       0 die if $@;
646             }
647 103         118 DEBUG && warn "socket";
648              
649             #------------------#
650             # Configure Socket #
651             #------------------#
652              
653             # Make the socket binary. It's wrapped in eval{} because tied
654             # filehandle classes may actually die in their binmode methods.
655 103         119 eval { binmode($socket_handle) };
  103         340  
656              
657             # Don't block on socket operations, because the socket will be
658             # driven by a select loop.
659 103         490 $socket_handle->blocking(0);
660              
661             # Make the socket reusable, if requested.
662 103 0 33     374 if (
      66        
663             (defined $params{Reuse})
664             and ( (lc($params{Reuse}) eq 'yes')
665             or (lc($params{Reuse}) eq 'on')
666             or ( ($params{Reuse} =~ /\d+/)
667             and $params{Reuse}
668             )
669             )
670             )
671             {
672 24 50       192 setsockopt($socket_handle, SOL_SOCKET, SO_REUSEADDR, 1) or do {
673 0         0 $poe_kernel->yield(
674             $event_failure,
675             'setsockopt', $!+0, $!, $self->[MY_UNIQUE_ID]
676             );
677 0         0 return $self;
678             };
679             }
680              
681             #-------------#
682             # Bind Socket #
683             #-------------#
684              
685 103         101 my $bind_address;
686              
687             # Check SocketFactory /Bind.*/ parameters in an Internet socket
688             # context, and translate them into parameters that bind()
689             # understands.
690 103 100       224 if ($abstract_domain eq DOM_INET) {
    50          
    50          
691             # Don't bind if the creator doesn't specify a related parameter.
692 99 100 66     461 if ((defined $params{BindAddress}) or (defined $params{BindPort})) {
693              
694             # Set the bind address, or default to INADDR_ANY.
695 24 50       84 $bind_address = (
696             (defined $params{BindAddress})
697             ? $params{BindAddress}
698             : INADDR_ANY
699             );
700              
701             # Need to check lengths in octets, not characters.
702 23 50   23   45 BEGIN { eval { require bytes } and bytes->import; }
  23         810  
703              
704             # Resolve the bind address if it's not already packed.
705 24 50       78 unless (length($bind_address) == 4) {
706 24         1395 $bind_address = inet_aton($bind_address);
707             }
708              
709 24 50       73 unless (defined $bind_address) {
710 0         0 $! = EADDRNOTAVAIL;
711 0         0 $poe_kernel->yield(
712             $event_failure,
713             "inet_aton", $!+0, $!, $self->[MY_UNIQUE_ID]
714             );
715 0         0 return $self;
716             }
717              
718             # Set the bind port, or default to 0 (any) if none specified.
719             # Resolve it to a number, if at all possible.
720 24 50       101 my $bind_port = (defined $params{BindPort}) ? $params{BindPort} : 0;
721 24 50       109 if ($bind_port =~ /[^0-9]/) {
722 0         0 $bind_port = getservbyname($bind_port, $protocol_name);
723 0 0       0 unless (defined $bind_port) {
724 0         0 $! = EADDRNOTAVAIL;
725 0         0 $poe_kernel->yield(
726             $event_failure,
727             'getservbyname', $!+0, $!, $self->[MY_UNIQUE_ID]
728             );
729 0         0 return $self;
730             }
731             }
732              
733 24         90 $bind_address = pack_sockaddr_in($bind_port, $bind_address);
734 24 50       88 unless (defined $bind_address) {
735 0         0 $poe_kernel->yield(
736             $event_failure,
737             "pack_sockaddr_in", $!+0, $!, $self->[MY_UNIQUE_ID]
738             );
739 0         0 return $self;
740             }
741             }
742             }
743              
744             # Check SocketFactory /Bind.*/ parameters in an Internet socket
745             # context, and translate them into parameters that bind()
746             # understands.
747             elsif ($abstract_domain eq DOM_INET6) {
748              
749             # Don't bind if the creator doesn't specify a related parameter.
750 0 0 0     0 if ((defined $params{BindAddress}) or (defined $params{BindPort})) {
751              
752             # Set the bind address, or default to INADDR_ANY.
753 0 0       0 $bind_address = (
754             (defined $params{BindAddress})
755             ? $params{BindAddress}
756             : "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" # XXX - Only Socket6 has?
757             );
758              
759             # Set the bind port, or default to 0 (any) if none specified.
760             # Resolve it to a number, if at all possible.
761 0 0       0 my $bind_port = (defined $params{BindPort}) ? $params{BindPort} : 0;
762 0 0       0 if ($bind_port =~ /[^0-9]/) {
763 0         0 $bind_port = getservbyname($bind_port, $protocol_name);
764 0 0       0 unless (defined $bind_port) {
765 0         0 $! = EADDRNOTAVAIL;
766 0         0 $poe_kernel->yield(
767             $event_failure,
768             'getservbyname', $!+0, $!, $self->[MY_UNIQUE_ID]
769             );
770 0         0 return $self;
771             }
772             }
773              
774             # Need to check lengths in octets, not characters.
775 23 50   23   7575 BEGIN { eval { require bytes } and bytes->import; }
  23         226  
776              
777             # Resolve the bind address.
778 0         0 my ($error, @addresses) = getaddrinfo(
779             $bind_address, $bind_port, {
780             family => $self->[MY_SOCKET_DOMAIN],
781             socktype => $self->[MY_SOCKET_TYPE],
782             }
783             );
784              
785 0 0       0 unless (@addresses) {
786 0 0       0 warn $error if $error;
787              
788 0         0 $! = EADDRNOTAVAIL;
789 0         0 $poe_kernel->yield(
790             $event_failure,
791             "getaddrinfo", $!+0, $!, $self->[MY_UNIQUE_ID]
792             );
793 0         0 return $self;
794             }
795              
796 0         0 $bind_address = $addresses[0]->{addr};
797             }
798             }
799              
800             # Check SocketFactory /Bind.*/ parameters in a Unix context, and
801             # translate them into parameters bind() understands.
802             elsif ($abstract_domain eq DOM_UNIX) {
803 4 50       11 carp 'BindPort ignored for Unix socket' if defined $params{BindPort};
804              
805 4 100       9 if (defined $params{BindAddress}) {
806             # Is this necessary, or will bind() return EADDRINUSE?
807 2 50       5 if (defined $params{RemotePort}) {
808 0         0 $! = EADDRINUSE;
809 0         0 $poe_kernel->yield(
810             $event_failure,
811             'bind', $!+0, $!, $self->[MY_UNIQUE_ID]
812             );
813 0         0 return $self;
814             }
815              
816 2         6 $bind_address = &_condition_unix_address($params{BindAddress});
817 2         15 $bind_address = pack_sockaddr_un($bind_address);
818 2 50       8 unless ($bind_address) {
819 0         0 $poe_kernel->yield(
820             $event_failure,
821             'pack_sockaddr_un', $!+0, $!, $self->[MY_UNIQUE_ID]
822             );
823 0         0 return $self;
824             }
825             }
826             }
827              
828             # This is an internal consistency error, and it should be hard
829             # trapped right away.
830             else {
831 0         0 die "Mail this error to the author of POE: Internal consistency error";
832             }
833              
834             # Perform the actual bind, if there's a bind address to bind to.
835 103 100       220 if (defined $bind_address) {
836 26 50       366 unless (bind($socket_handle, $bind_address)) {
837 0         0 $poe_kernel->yield(
838             $event_failure,
839             'bind', $!+0, $!, $self->[MY_UNIQUE_ID]
840             );
841 0         0 return $self;
842             }
843              
844 26         36 DEBUG && warn "bind";
845             }
846              
847             #---------#
848             # Connect #
849             #---------#
850              
851 103         112 my $connect_address;
852              
853 103 100       192 if (defined $params{RemoteAddress}) {
854              
855             # Check SocketFactory /Remote.*/ parameters in an Internet socket
856             # context, and translate them into parameters that connect()
857             # understands.
858 77 100 66     208 if (
    50          
859             $abstract_domain eq DOM_INET or
860             $abstract_domain eq DOM_INET6
861             ) {
862             # connecting if RemoteAddress
863 75 50       146 croak 'RemotePort required' unless (defined $params{RemotePort});
864 75 50       130 carp 'ListenQueue ignored' if (defined $params{ListenQueue});
865              
866 75         80 my $remote_port = $params{RemotePort};
867 75 50       240 if ($remote_port =~ /[^0-9]/) {
868 0 0       0 unless ($remote_port = getservbyname($remote_port, $protocol_name)) {
869 0         0 $! = EADDRNOTAVAIL;
870 0         0 $poe_kernel->yield(
871             $event_failure,
872             'getservbyname', $!+0, $!, $self->[MY_UNIQUE_ID]
873             );
874 0         0 return $self;
875             }
876             }
877              
878 75         67 my $error_tag;
879 75 50       125 if ($abstract_domain eq DOM_INET) {
    0          
880 75         1314 $connect_address = inet_aton($params{RemoteAddress});
881 75         110 $error_tag = "inet_aton";
882             }
883             elsif ($abstract_domain eq DOM_INET6) {
884 0         0 my ($error, @addresses) = getaddrinfo(
885             $params{RemoteAddress}, $remote_port, {
886             family => $self->[MY_SOCKET_DOMAIN],
887             socktype => $self->[MY_SOCKET_TYPE],
888             },
889             );
890              
891 0 0       0 unless (@addresses) {
892 0 0       0 warn $error if $error;
893 0         0 $connect_address = undef;
894             }
895             else {
896 0         0 $connect_address = $addresses[0]->{addr};
897             }
898              
899 0         0 $error_tag = "getaddrinfo";
900             }
901             else {
902 0         0 die "unknown domain $abstract_domain";
903             }
904              
905             # TODO - If the gethostbyname2() code is removed, then we can
906             # combine the previous code with the following code, and perhaps
907             # remove one of these redundant $connect_address checks. The
908             # 0.29 release should tell us pretty quickly whether it's
909             # needed. If we reach 0.30 without incident, it's probably safe
910             # to remove the old gethostbyname2() code and clean this up.
911 75 50       151 unless (defined $connect_address) {
912 0         0 $! = EADDRNOTAVAIL;
913 0         0 $poe_kernel->yield(
914             $event_failure,
915             $error_tag, $!+0, $!, $self->[MY_UNIQUE_ID]
916             );
917 0         0 return $self;
918             }
919              
920 75 50       127 if ($abstract_domain eq DOM_INET) {
    0          
921 75         169 $connect_address = pack_sockaddr_in($remote_port, $connect_address);
922 75         127 $error_tag = "pack_sockaddr_in";
923             }
924             elsif ($abstract_domain eq DOM_INET6) {
925 0         0 $error_tag = "pack_sockaddr_in6";
926             }
927             else {
928 0         0 die "unknown domain $abstract_domain";
929             }
930              
931 75 50       162 unless ($connect_address) {
932 0         0 $! = EADDRNOTAVAIL;
933 0         0 $poe_kernel->yield(
934             $event_failure,
935             $error_tag, $!+0, $!, $self->[MY_UNIQUE_ID]
936             );
937 0         0 return $self;
938             }
939             }
940              
941             # Check SocketFactory /Remote.*/ parameters in a Unix socket
942             # context, and translate them into parameters connect()
943             # understands.
944             elsif ($abstract_domain eq DOM_UNIX) {
945              
946 2         6 $connect_address = _condition_unix_address($params{RemoteAddress});
947 2         7 $connect_address = pack_sockaddr_un($connect_address);
948 2 50       7 unless (defined $connect_address) {
949 0         0 $poe_kernel->yield(
950             $event_failure,
951             'pack_sockaddr_un', $!+0, $!, $self->[MY_UNIQUE_ID]
952             );
953 0         0 return $self;
954             }
955             }
956              
957             # This is an internal consistency error, and it should be trapped
958             # right away.
959             else {
960 0         0 die "Mail this error to the author of POE: Internal consistency error";
961             }
962             }
963              
964             else {
965 26 50       72 carp "RemotePort ignored without RemoteAddress"
966             if defined $params{RemotePort};
967             }
968              
969             # Perform the actual connection, if a connection was requested. If
970             # the connection can be established, then return the SocketFactory
971             # handle.
972 103 100       230 if (defined $connect_address) {
973 77 100       4606 unless (connect($socket_handle, $connect_address)) {
974 75 50 33     866 if ($! and ($! != EINPROGRESS) and ($! != EWOULDBLOCK)) {
      33        
975 0         0 $poe_kernel->yield(
976             $event_failure,
977             'connect', $!+0, $!, $self->[MY_UNIQUE_ID]
978             );
979 0         0 return $self;
980             }
981             }
982              
983 77         62 DEBUG && warn "connect";
984              
985 77         133 $self->[MY_SOCKET_HANDLE] = $socket_handle;
986 77         222 $self->_define_connect_state();
987 77         224 $self->event(
988             SuccessEvent => $params{SuccessEvent},
989             FailureEvent => $params{FailureEvent},
990             );
991 77         410 return $self;
992             }
993              
994             #---------------------#
995             # Listen, or Whatever #
996             #---------------------#
997              
998             # A connection wasn't requested, so this must be a server socket.
999             # Do whatever it is that needs to be done for whatever type of
1000             # server socket this is.
1001 26 50       73 if (exists $supported_protocol{$abstract_domain}->{$protocol_name}) {
1002 26         56 my $protocol_op = $supported_protocol{$abstract_domain}->{$protocol_name};
1003              
1004 26         25 DEBUG && warn "$abstract_domain + $protocol_name = $protocol_op";
1005              
1006 26 100       69 if ($protocol_op eq SVROP_LISTENS) {
1007 22   50     122 my $listen_queue = $params{ListenQueue} || SOMAXCONN;
1008             # In SocketFactory, you limit the ListenQueue parameter
1009             # to SOMAXCON (or is it SOCONNMAX?)...why?
1010             # ah, here's czth, he'll have more to say on this issue
1011             # not really. just that SOMAXCONN can lie, notably on
1012             # Solaris and reportedly on BSDs too
1013             #
1014             # ($listen_queue > SOMAXCONN) && ($listen_queue = SOMAXCONN);
1015 22 50       279 unless (listen($socket_handle, $listen_queue)) {
1016 0         0 $poe_kernel->yield(
1017             $event_failure,
1018             'listen', $!+0, $!, $self->[MY_UNIQUE_ID]
1019             );
1020 0         0 return $self;
1021             }
1022              
1023 22         30 DEBUG && warn "listen";
1024              
1025 22         43 $self->[MY_SOCKET_HANDLE] = $socket_handle;
1026 22         86 $self->_define_accept_state();
1027 22         94 $self->event(
1028             SuccessEvent => $params{SuccessEvent},
1029             FailureEvent => $params{FailureEvent},
1030             );
1031 22         123 return $self;
1032             }
1033             else {
1034 4 50       7 carp "Ignoring ListenQueue parameter for non-listening socket"
1035             if defined $params{ListenQueue};
1036 4 50       5 if ($protocol_op eq SVROP_NOTHING) {
1037             # Do nothing. Duh. Fire off a success event immediately, and
1038             # return.
1039 4         16 $poe_kernel->yield(
1040             $event_success,
1041             $socket_handle, undef, undef, $self->[MY_UNIQUE_ID]
1042             );
1043 4         18 return $self;
1044             }
1045             else {
1046 0         0 die "Mail this error to the author of POE: Internal consistency error";
1047             }
1048             }
1049             }
1050             else {
1051 0         0 die "SocketFactory doesn't support $abstract_domain $protocol_name socket";
1052             }
1053              
1054 0         0 die "Mail this error to the author of POE: Internal consistency error";
1055             }
1056              
1057             # Pause and resume accept.
1058             sub pause_accept {
1059 24     24 1 37 my $self = shift;
1060 24 50 33     163 if (
      33        
1061             defined $self->[MY_SOCKET_HANDLE] and
1062             defined $self->[MY_STATE_ACCEPT] and
1063             defined $self->[MY_SOCKET_SELECTED]
1064             ) {
1065 24         79 $poe_kernel->select_pause_read($self->[MY_SOCKET_HANDLE]);
1066             }
1067             }
1068              
1069             sub resume_accept {
1070 22     22 1 28 my $self = shift;
1071 22 50 33     138 if (
      33        
1072             defined $self->[MY_SOCKET_HANDLE] and
1073             defined $self->[MY_STATE_ACCEPT] and
1074             defined $self->[MY_SOCKET_SELECTED]
1075             ) {
1076 22         63 $poe_kernel->select_resume_read($self->[MY_SOCKET_HANDLE]);
1077             }
1078             }
1079              
1080             #------------------------------------------------------------------------------
1081             # DESTROY and _shutdown pass things by reference because _shutdown is
1082             # called from the state() closures above. As a result, we can't
1083             # mention $self explicitly, or the wheel won't shut itself down
1084             # properly. Rather, it will form a circular reference on $self.
1085              
1086             sub DESTROY {
1087 103     103   586 my $self = shift;
1088 103         437 _shutdown(
1089             \$self->[MY_SOCKET_SELECTED],
1090             \$self->[MY_SOCKET_HANDLE],
1091             \$self->[MY_STATE_ACCEPT],
1092             \$self->[MY_STATE_CONNECT],
1093             \$self->[MY_MINE_SUCCESS],
1094             \$self->[MY_EVENT_SUCCESS],
1095             \$self->[MY_MINE_FAILURE],
1096             \$self->[MY_EVENT_FAILURE],
1097             );
1098 103         339 &POE::Wheel::free_wheel_id($self->[MY_UNIQUE_ID]);
1099             }
1100              
1101             sub _shutdown {
1102             my (
1103 180     180   271 $socket_selected, $socket_handle,
1104             $state_accept, $state_connect,
1105             $mine_success, $event_success,
1106             $mine_failure, $event_failure,
1107             ) = @_;
1108              
1109 180 100       398 if (defined $$socket_selected) {
1110 99         295 $poe_kernel->select($$socket_handle);
1111 99         164 $$socket_selected = undef;
1112             }
1113              
1114 180 100       366 if (defined $$state_accept) {
1115 22         84 $poe_kernel->state($$state_accept);
1116 22         44 $$state_accept = undef;
1117             }
1118              
1119 180 100       339 if (defined $$state_connect) {
1120 77         213 $poe_kernel->state($$state_connect);
1121 77         100 $$state_connect = undef;
1122             }
1123              
1124 180 50       353 if (defined $$mine_success) {
1125 0         0 $poe_kernel->state($$event_success);
1126 0         0 $$mine_success = $$event_success = undef;
1127             }
1128              
1129 180 50       538 if (defined $$mine_failure) {
1130 0           $poe_kernel->state($$event_failure);
1131 0           $$mine_failure = $$event_failure = undef;
1132             }
1133             }
1134              
1135             1;
1136              
1137             __END__