| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | # | 
| 2 |  |  |  |  |  |  | # This file is part of IO-Socket-Timeout | 
| 3 |  |  |  |  |  |  | # | 
| 4 |  |  |  |  |  |  | # This software is copyright (c) 2013 by Damien "dams" Krotkine. | 
| 5 |  |  |  |  |  |  | # | 
| 6 |  |  |  |  |  |  | # This is free software; you can redistribute it and/or modify it under | 
| 7 |  |  |  |  |  |  | # the same terms as the Perl 5 programming language system itself. | 
| 8 |  |  |  |  |  |  | # | 
| 9 |  |  |  |  |  |  | package IO::Socket::Timeout; | 
| 10 |  |  |  |  |  |  | $IO::Socket::Timeout::VERSION = '0.32'; | 
| 11 | 5 |  |  | 5 |  | 133591 | use strict; | 
|  | 5 |  |  |  |  | 11 |  | 
|  | 5 |  |  |  |  | 129 |  | 
| 12 | 5 |  |  | 5 |  | 25 | use warnings; | 
|  | 5 |  |  |  |  | 8 |  | 
|  | 5 |  |  |  |  | 130 |  | 
| 13 | 5 |  |  | 5 |  | 21 | use Config; | 
|  | 5 |  |  |  |  | 11 |  | 
|  | 5 |  |  |  |  | 153 |  | 
| 14 | 5 |  |  | 5 |  | 22 | use Carp; | 
|  | 5 |  |  |  |  | 9 |  | 
|  | 5 |  |  |  |  | 2367 |  | 
| 15 |  |  |  |  |  |  |  | 
| 16 |  |  |  |  |  |  |  | 
| 17 |  |  |  |  |  |  | # ABSTRACT: IO::Socket with read/write timeout | 
| 18 |  |  |  |  |  |  |  | 
| 19 |  |  |  |  |  |  |  | 
| 20 |  |  |  |  |  |  | sub import { | 
| 21 | 5 |  |  | 5 |  | 42 | shift; | 
| 22 | 5 |  |  |  |  | 4421 | foreach (@_) { | 
| 23 | 2 |  |  |  |  | 7 | _create_composed_class( $_, 'IO::Socket::Timeout::Role::SetSockOpt'); | 
| 24 | 2 |  |  |  |  | 4 | _create_composed_class( $_, 'IO::Socket::Timeout::Role::PerlIO'); | 
| 25 |  |  |  |  |  |  | } | 
| 26 |  |  |  |  |  |  | } | 
| 27 |  |  |  |  |  |  |  | 
| 28 |  |  |  |  |  |  |  | 
| 29 |  |  |  |  |  |  | sub enable_timeouts_on { | 
| 30 | 8 |  |  | 8 | 1 | 265854 | my ($class, $socket) = @_; | 
| 31 | 8 | 50 |  |  |  | 84 | defined $socket | 
| 32 |  |  |  |  |  |  | or return; | 
| 33 | 8 | 50 |  |  |  | 132 | $socket->isa('IO::Socket') | 
| 34 |  |  |  |  |  |  | or croak 'make_timeouts_aware can be used only on instances that inherit from IO::Socket'; | 
| 35 |  |  |  |  |  |  |  | 
| 36 | 8 |  |  |  |  | 527 | my $osname = $Config{osname}; | 
| 37 | 8 | 100 | 33 |  |  | 234 | if ( ! $ENV{PERL_IO_SOCKET_TIMEOUT_FORCE_SELECT} | 
|  |  |  | 66 |  |  |  |  | 
| 38 |  |  |  |  |  |  | && ( $osname eq 'darwin' || $osname eq 'linux' || $osname eq 'freebsd' ) ) { | 
| 39 | 5 |  |  |  |  | 60 | _compose_roles($socket, 'IO::Socket::Timeout::Role::SetSockOpt'); | 
| 40 |  |  |  |  |  |  | } else { | 
| 41 | 3 |  |  |  |  | 105 | require PerlIO::via::Timeout; | 
| 42 | 3 |  |  | 1 |  | 255 | binmode($socket, ':via(Timeout)'); | 
|  | 1 |  |  |  |  | 10 |  | 
|  | 1 |  |  |  |  | 2 |  | 
|  | 1 |  |  |  |  | 41 |  | 
| 43 | 3 |  |  |  |  | 45143 | _compose_roles($socket, 'IO::Socket::Timeout::Role::PerlIO'); | 
| 44 |  |  |  |  |  |  | } | 
| 45 |  |  |  |  |  |  |  | 
| 46 | 8 |  |  |  |  | 176 | $socket->enable_timeout; | 
| 47 | 8 |  |  |  |  | 140 | return $socket; | 
| 48 |  |  |  |  |  |  | } | 
| 49 |  |  |  |  |  |  |  | 
| 50 |  |  |  |  |  |  | sub _create_composed_class { | 
| 51 | 12 |  |  | 12 |  | 44 | my ($class, @roles) = @_; | 
| 52 | 12 |  |  |  |  | 118 | my $composed_class = $class . '__with__' . join('__and__', @roles); | 
| 53 | 12 |  |  |  |  | 43 | my $path = $composed_class; $path =~ s|::|/|g; $path .= '.pm'; | 
|  | 12 |  |  |  |  | 232 |  | 
|  | 12 |  |  |  |  | 47 |  | 
| 54 | 12 | 100 |  |  |  | 101 | if ( ! exists $INC{$path}) { | 
| 55 | 5 |  |  | 5 |  | 26 | no strict 'refs'; | 
|  | 5 |  |  |  |  | 10 |  | 
|  | 5 |  |  |  |  | 1573 |  | 
| 56 | 8 |  |  |  |  | 34 | *{"${composed_class}::ISA"} = [ $class, @roles ]; | 
|  | 8 |  |  |  |  | 1109 |  | 
| 57 | 8 |  |  |  |  | 39 | $INC{$path} = __FILE__; | 
| 58 |  |  |  |  |  |  | } | 
| 59 | 12 |  |  |  |  | 93954 | return $composed_class; | 
| 60 |  |  |  |  |  |  | } | 
| 61 |  |  |  |  |  |  |  | 
| 62 |  |  |  |  |  |  | sub _compose_roles { | 
| 63 | 8 |  |  | 8 |  | 61 | my ($instance, @roles) = @_; | 
| 64 | 8 |  |  |  |  | 98 | bless $instance, _create_composed_class(ref $instance, @roles); | 
| 65 |  |  |  |  |  |  | } | 
| 66 |  |  |  |  |  |  |  | 
| 67 |  |  |  |  |  |  | # sysread FILEHANDLE,SCALAR,LENGTH,OFFSET | 
| 68 |  |  |  |  |  |  | BEGIN { | 
| 69 | 5 |  |  | 5 |  | 47 | my $osname = $Config{osname}; | 
| 70 | 5 | 100 | 33 |  |  | 2820 | if ( $ENV{PERL_IO_SOCKET_TIMEOUT_FORCE_SELECT} || | 
|  |  |  | 33 |  |  |  |  | 
|  |  |  | 66 |  |  |  |  | 
| 71 |  |  |  |  |  |  | $osname ne 'darwin' && $osname ne 'linux' && $osname ne 'freebsd' | 
| 72 |  |  |  |  |  |  | ) { | 
| 73 |  |  |  |  |  |  | # this variable avoids infinite recursion, because | 
| 74 |  |  |  |  |  |  | # PerlIO::via::Timeout->READ calls sysread. | 
| 75 | 1 |  |  |  |  | 16 | my $_prevent_deep_recursion; | 
| 76 |  |  |  |  |  |  | *CORE::GLOBAL::sysread = sub { | 
| 77 | 31 |  |  |  |  | 24354 | my $args_count = scalar(@_); | 
| 78 | 31 | 100 | 100 |  |  | 295 | $_prevent_deep_recursion | 
|  |  | 100 | 66 |  |  |  |  | 
| 79 |  |  |  |  |  |  | || ! PerlIO::via::Timeout::has_timeout_layer($_[0]) | 
| 80 |  |  |  |  |  |  | || ! PerlIO::via::Timeout::timeout_enabled($_[0]) | 
| 81 |  |  |  |  |  |  | and return (  $args_count == 4 ? CORE::sysread($_[0], $_[1], $_[2], $_[3]) | 
| 82 |  |  |  |  |  |  | :                    CORE::sysread($_[0], $_[1], $_[2]) | 
| 83 |  |  |  |  |  |  | ); | 
| 84 | 15 |  |  |  |  | 481 | $_prevent_deep_recursion = 1; | 
| 85 | 15 |  |  |  |  | 92 | my $ret_val = PerlIO::via::Timeout->READ($_[1], $_[2], $_[0]); | 
| 86 | 15 |  |  |  |  | 200530 | $_prevent_deep_recursion = 0; | 
| 87 | 15 |  |  |  |  | 40 | return $ret_val; | 
| 88 |  |  |  |  |  |  | } | 
| 89 | 1 |  |  |  |  | 180 | } | 
| 90 |  |  |  |  |  |  | } | 
| 91 |  |  |  |  |  |  |  | 
| 92 |  |  |  |  |  |  | # syswrite FILEHANDLE,SCALAR,LENGTH,OFFSET | 
| 93 |  |  |  |  |  |  | BEGIN { | 
| 94 | 5 |  |  | 5 |  | 35 | my $osname = $Config{osname}; | 
| 95 | 5 | 100 | 33 |  |  | 228 | if ( $ENV{PERL_IO_SOCKET_TIMEOUT_FORCE_SELECT} || | 
|  |  |  | 33 |  |  |  |  | 
|  |  |  | 66 |  |  |  |  | 
| 96 |  |  |  |  |  |  | $osname ne 'darwin' && $osname ne 'linux' && $osname ne 'freebsd' | 
| 97 |  |  |  |  |  |  | ) { | 
| 98 |  |  |  |  |  |  | # this variable avoids infinite recursion, because | 
| 99 |  |  |  |  |  |  | # PerlIO::via::Timeout->WRITE calls syswrite. | 
| 100 | 1 |  |  |  |  | 2 | my $_prevent_deep_recursion; | 
| 101 |  |  |  |  |  |  | *CORE::GLOBAL::syswrite = sub { | 
| 102 | 12 |  |  |  |  | 11657 | my $args_count = scalar(@_); | 
| 103 | 12 | 0 | 66 |  |  | 456 | $_prevent_deep_recursion | 
|  |  | 50 | 66 |  |  |  |  | 
|  |  | 50 |  |  |  |  |  | 
| 104 |  |  |  |  |  |  | || ! PerlIO::via::Timeout::has_timeout_layer($_[0]) | 
| 105 |  |  |  |  |  |  | || ! PerlIO::via::Timeout::timeout_enabled($_[0]) | 
| 106 |  |  |  |  |  |  | and return(   $args_count == 4 ? CORE::syswrite($_[0], $_[1], $_[2], $_[3]) | 
| 107 |  |  |  |  |  |  | : $args_count == 3 ? CORE::syswrite($_[0], $_[1], $_[2]) | 
| 108 |  |  |  |  |  |  | :                    CORE::syswrite($_[0], $_[1]) | 
| 109 |  |  |  |  |  |  | ); | 
| 110 | 6 |  |  |  |  | 244 | $_prevent_deep_recursion = 1; | 
| 111 | 6 |  |  |  |  | 67 | my $ret_val = PerlIO::via::Timeout->WRITE($_[1], $_[0]); | 
| 112 | 6 |  |  |  |  | 61 | $_prevent_deep_recursion = 0; | 
| 113 | 6 |  |  |  |  | 18 | return $ret_val; | 
| 114 |  |  |  |  |  |  | } | 
| 115 | 1 |  |  |  |  | 42 | } | 
| 116 |  |  |  |  |  |  | } | 
| 117 |  |  |  |  |  |  |  | 
| 118 |  |  |  |  |  |  | package IO::Socket::Timeout::Role::SetSockOpt; | 
| 119 |  |  |  |  |  |  | $IO::Socket::Timeout::Role::SetSockOpt::VERSION = '0.32'; | 
| 120 | 5 |  |  | 5 |  | 25 | use Carp; | 
|  | 5 |  |  |  |  | 11 |  | 
|  | 5 |  |  |  |  | 621 |  | 
| 121 | 5 |  |  | 5 |  | 2572 | use Socket; | 
|  | 5 |  |  |  |  | 14074 |  | 
|  | 5 |  |  |  |  | 6222 |  | 
| 122 |  |  |  |  |  |  |  | 
| 123 |  |  |  |  |  |  | sub _check_attributes { | 
| 124 | 7 |  |  | 38 |  | 21 | my ($self) = @_; | 
| 125 | 7 | 50 |  |  |  | 45 | grep { $_ < 0 } grep { defined } map { ${*$self}{$_} } qw(ReadTimeout WriteTimeout) | 
|  | 10 |  |  |  |  | 74 |  | 
|  | 14 |  |  |  |  | 45 |  | 
|  | 14 |  |  |  |  | 29 |  | 
|  | 14 |  |  |  |  | 78 |  | 
| 126 |  |  |  |  |  |  | and croak "if defined, 'ReadTimeout' and 'WriteTimeout' attributes should be >= 0"; | 
| 127 |  |  |  |  |  |  | } | 
| 128 |  |  |  |  |  |  |  | 
| 129 |  |  |  |  |  |  | sub read_timeout { | 
| 130 | 4 |  |  | 16 |  | 107 | my ($self) = @_; | 
| 131 | 4 | 50 |  |  |  | 40 | @_ > 1 and ${*$self}{ReadTimeout} = $_[1], $self->_check_attributes, $self->_set_sock_opt; | 
|  | 4 |  |  |  |  | 73 |  | 
| 132 | 4 |  |  |  |  | 15 | ${*$self}{ReadTimeout} | 
| 133 | 4 |  |  |  |  | 37 | } | 
| 134 |  |  |  |  |  |  |  | 
| 135 |  |  |  |  |  |  | sub write_timeout { | 
| 136 | 3 |  |  | 3 |  | 36 | my ($self) = @_; | 
| 137 | 3 | 50 |  |  |  | 14 | @_ > 1 and ${*$self}{WriteTimeout} = $_[1], $self->_check_attributes, $self->_set_sock_opt; | 
|  | 3 |  |  |  |  | 26 |  | 
| 138 | 3 |  |  |  |  | 14 | ${*$self}{WriteTimeout} | 
| 139 | 3 |  |  |  |  | 25 | } | 
| 140 |  |  |  |  |  |  |  | 
| 141 | 5 |  |  | 5 |  | 67 | sub enable_timeout { $_[0]->timeout_enabled(1) } | 
| 142 | 0 |  |  | 0 |  | 0 | sub disable_timeout { $_[0]->timeout_enabled(0) } | 
| 143 |  |  |  |  |  |  | sub timeout_enabled { | 
| 144 | 5 |  |  | 5 |  | 14 | my ($self) = @_; | 
| 145 | 5 | 50 |  |  |  | 30 | @_ > 1 and ${*$self}{TimeoutEnabled} = !!$_[1], $self->_set_sock_opt; | 
|  | 5 |  |  |  |  | 111 |  | 
| 146 | 5 |  |  |  |  | 15 | ${*$self}{TimeoutEnabled} | 
| 147 | 5 |  |  |  |  | 70 | } | 
| 148 |  |  |  |  |  |  |  | 
| 149 |  |  |  |  |  |  | sub _set_sock_opt { | 
| 150 | 12 |  |  | 12 |  | 23 | my ($self) = @_; | 
| 151 | 12 |  |  |  |  | 130 | my $read_seconds; | 
| 152 |  |  |  |  |  |  | my $read_useconds; | 
| 153 | 0 |  |  |  |  | 0 | my $write_seconds; | 
| 154 | 0 |  |  |  |  | 0 | my $write_useconds; | 
| 155 | 12 | 50 |  |  |  | 20 | if (${*$self}{TimeoutEnabled}) { | 
|  | 12 |  |  |  |  | 47 |  | 
| 156 | 12 |  | 100 |  |  | 15 | my $read_timeout = ${*$self}{ReadTimeout} || 0; | 
| 157 | 12 |  |  |  |  | 29 | $read_seconds  = int( $read_timeout ); | 
| 158 | 12 |  |  |  |  | 31 | $read_useconds = int( 1_000_000 * ( $read_timeout - $read_seconds )); | 
| 159 | 12 |  | 100 |  |  | 18 | my $write_timeout = ${*$self}{WriteTimeout} || 0; | 
| 160 | 12 |  |  |  |  | 19 | $write_seconds  = int( $write_timeout ); | 
| 161 | 12 |  |  |  |  | 29 | $write_useconds = int( 1_000_000 * ( $write_timeout - $write_seconds )); | 
| 162 |  |  |  |  |  |  | } else { | 
| 163 | 0 |  |  |  |  | 0 | $read_seconds  = 0; $read_useconds  = 0; | 
|  | 0 |  |  |  |  | 0 |  | 
| 164 | 0 |  |  |  |  | 0 | $write_seconds = 0; $write_useconds = 0; | 
|  | 0 |  |  |  |  | 0 |  | 
| 165 |  |  |  |  |  |  | } | 
| 166 | 12 |  |  |  |  | 85 | my $read_struct  = pack( 'l!l!', $read_seconds, $read_useconds ); | 
| 167 | 12 |  |  |  |  | 36 | my $write_struct = pack( 'l!l!', $write_seconds, $write_useconds ); | 
| 168 |  |  |  |  |  |  |  | 
| 169 | 12 | 50 |  |  |  | 97 | $self->setsockopt( SOL_SOCKET, SO_RCVTIMEO, $read_struct ) | 
| 170 |  |  |  |  |  |  | or croak "setsockopt(SO_RCVTIMEO): $!"; | 
| 171 |  |  |  |  |  |  |  | 
| 172 | 12 | 50 |  |  |  | 195 | $self->setsockopt( SOL_SOCKET, SO_SNDTIMEO, $write_struct ) | 
| 173 |  |  |  |  |  |  | or croak "setsockopt(SO_SNDTIMEO): $!"; | 
| 174 |  |  |  |  |  |  | } | 
| 175 |  |  |  |  |  |  |  | 
| 176 |  |  |  |  |  |  | package IO::Socket::Timeout::Role::PerlIO; | 
| 177 |  |  |  |  |  |  | $IO::Socket::Timeout::Role::PerlIO::VERSION = '0.32'; | 
| 178 | 5 |  |  | 5 |  | 4042 | use PerlIO::via::Timeout; | 
|  | 5 |  |  |  |  | 25106 |  | 
|  | 5 |  |  |  |  | 683 |  | 
| 179 |  |  |  |  |  |  |  | 
| 180 | 2 |  |  | 2 |  | 114 | sub read_timeout    { goto &PerlIO::via::Timeout::read_timeout    } | 
| 181 | 0 |  |  | 0 |  | 0 | sub write_timeout   { goto &PerlIO::via::Timeout::write_timeout   } | 
| 182 | 3 |  |  | 3 |  | 119 | sub enable_timeout  { goto &PerlIO::via::Timeout::enable_timeout  } | 
| 183 | 0 |  |  | 0 |  | 0 | sub disable_timeout { goto &PerlIO::via::Timeout::disable_timeout } | 
| 184 | 0 |  |  | 0 |  | 0 | sub timeout_enabled { goto &PerlIO::via::Timeout::timeout_enabled } | 
| 185 |  |  |  |  |  |  |  | 
| 186 |  |  |  |  |  |  | 1; | 
| 187 |  |  |  |  |  |  |  | 
| 188 |  |  |  |  |  |  | __END__ |