| 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.29'; | 
| 11 | 10 |  |  | 10 |  | 212399 | use strict; | 
|  | 10 |  |  |  |  | 20 |  | 
|  | 10 |  |  |  |  | 296 |  | 
| 12 | 10 |  |  | 10 |  | 37 | use warnings; | 
|  | 10 |  |  |  |  | 15 |  | 
|  | 10 |  |  |  |  | 234 |  | 
| 13 | 10 |  |  | 10 |  | 32 | use Config; | 
|  | 10 |  |  |  |  | 10 |  | 
|  | 10 |  |  |  |  | 276 |  | 
| 14 | 10 |  |  | 10 |  | 31 | use Carp; | 
|  | 10 |  |  |  |  | 14 |  | 
|  | 10 |  |  |  |  | 3064 |  | 
| 15 |  |  |  |  |  |  |  | 
| 16 |  |  |  |  |  |  |  | 
| 17 |  |  |  |  |  |  | # ABSTRACT: IO::Socket with read/write timeout | 
| 18 |  |  |  |  |  |  |  | 
| 19 |  |  |  |  |  |  |  | 
| 20 |  |  |  |  |  |  | sub import { | 
| 21 | 10 |  |  | 10 |  | 72 | shift; | 
| 22 | 10 |  |  |  |  | 19874 | foreach (@_) { | 
| 23 | 2 |  |  |  |  | 4 | _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 | 31 |  |  | 31 | 1 | 17496829 | my ($class, $socket) = @_; | 
| 31 | 31 | 50 |  |  |  | 213 | defined $socket | 
| 32 |  |  |  |  |  |  | or return; | 
| 33 | 31 | 50 |  |  |  | 310 | $socket->isa('IO::Socket') | 
| 34 |  |  |  |  |  |  | or croak 'make_timeouts_aware can be used only on instances that inherit from IO::Socket'; | 
| 35 |  |  |  |  |  |  |  | 
| 36 | 31 |  |  |  |  | 816 | my $osname = $Config{osname}; | 
| 37 | 31 | 100 | 33 |  |  | 556 | if ( ! $ENV{PERL_IO_SOCKET_TIMEOUT_FORCE_SELECT} | 
|  |  |  | 66 |  |  |  |  | 
| 38 |  |  |  |  |  |  | && ( $osname eq 'darwin' || $osname eq 'linux' || $osname eq 'freebsd' ) ) { | 
| 39 | 28 |  |  |  |  | 159 | _compose_roles($socket, 'IO::Socket::Timeout::Role::SetSockOpt'); | 
| 40 |  |  |  |  |  |  | } else { | 
| 41 | 3 |  |  |  |  | 59 | require PerlIO::via::Timeout; | 
| 42 | 3 |  |  | 1 |  | 282 | binmode($socket, ':via(Timeout)'); | 
|  | 1 |  |  |  |  | 17 |  | 
|  | 1 |  |  |  |  | 3 |  | 
|  | 1 |  |  |  |  | 43 |  | 
| 43 | 3 |  |  |  |  | 2075 | _compose_roles($socket, 'IO::Socket::Timeout::Role::PerlIO'); | 
| 44 |  |  |  |  |  |  | } | 
| 45 |  |  |  |  |  |  |  | 
| 46 | 31 |  |  |  |  | 230 | $socket->enable_timeout; | 
| 47 | 31 |  |  |  |  | 180 | return $socket; | 
| 48 |  |  |  |  |  |  | } | 
| 49 |  |  |  |  |  |  |  | 
| 50 |  |  |  |  |  |  | sub _create_composed_class { | 
| 51 | 35 |  |  | 35 |  | 105 | my ($class, @roles) = @_; | 
| 52 | 35 |  |  |  |  | 162 | my $composed_class = $class . '__with__' . join('__and__', @roles); | 
| 53 | 35 |  |  |  |  | 68 | my $path = $composed_class; $path =~ s|::|/|g; $path .= '.pm'; | 
|  | 35 |  |  |  |  | 294 |  | 
|  | 35 |  |  |  |  | 49 |  | 
| 54 | 35 | 100 |  |  |  | 154 | if ( ! exists $INC{$path}) { | 
| 55 | 10 |  |  | 10 |  | 54 | no strict 'refs'; | 
|  | 10 |  |  |  |  | 11 |  | 
|  | 10 |  |  |  |  | 2284 |  | 
| 56 | 13 |  |  |  |  | 21 | *{"${composed_class}::ISA"} = [ $class, @roles ]; | 
|  | 13 |  |  |  |  | 492 |  | 
| 57 | 13 |  |  |  |  | 46 | $INC{$path} = __FILE__; | 
| 58 |  |  |  |  |  |  | } | 
| 59 | 35 |  |  |  |  | 69223 | return $composed_class; | 
| 60 |  |  |  |  |  |  | } | 
| 61 |  |  |  |  |  |  |  | 
| 62 |  |  |  |  |  |  | sub _compose_roles { | 
| 63 | 31 |  |  | 31 |  | 94 | my ($instance, @roles) = @_; | 
| 64 | 31 |  |  |  |  | 122 | bless $instance, _create_composed_class(ref $instance, @roles); | 
| 65 |  |  |  |  |  |  | } | 
| 66 |  |  |  |  |  |  |  | 
| 67 |  |  |  |  |  |  | # sysread FILEHANDLE,SCALAR,LENGTH,OFFSET | 
| 68 |  |  |  |  |  |  | BEGIN { | 
| 69 | 10 |  |  | 10 |  | 95 | my $osname = $Config{osname}; | 
| 70 | 10 | 100 | 33 |  |  | 1326 | 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 |  |  |  |  | 1 | my $_prevent_deep_recursion; | 
| 76 |  |  |  |  |  |  | *CORE::GLOBAL::sysread = sub { | 
| 77 | 31 |  |  |  |  | 12876 | my $args_count = scalar(@_); | 
| 78 | 31 | 100 | 100 |  |  | 195 | $_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 |  |  |  |  | 351 | $_prevent_deep_recursion = 1; | 
| 85 | 15 |  |  |  |  | 56 | my $ret_val = PerlIO::via::Timeout->READ($_[1], $_[2], $_[0]); | 
| 86 | 15 |  |  |  |  | 200442 | $_prevent_deep_recursion = 0; | 
| 87 | 15 |  |  |  |  | 21 | return $ret_val; | 
| 88 |  |  |  |  |  |  | } | 
| 89 | 1 |  |  |  |  | 237 | } | 
| 90 |  |  |  |  |  |  | } | 
| 91 |  |  |  |  |  |  |  | 
| 92 |  |  |  |  |  |  | # syswrite FILEHANDLE,SCALAR,LENGTH,OFFSET | 
| 93 |  |  |  |  |  |  | BEGIN { | 
| 94 | 10 |  |  | 10 |  | 125 | my $osname = $Config{osname}; | 
| 95 | 10 | 100 | 33 |  |  | 398 | 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 |  |  |  |  | 1 | my $_prevent_deep_recursion; | 
| 101 |  |  |  |  |  |  | *CORE::GLOBAL::syswrite = sub { | 
| 102 | 12 |  |  |  |  | 4831 | my $args_count = scalar(@_); | 
| 103 | 12 | 0 | 66 |  |  | 759 | $_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 |  |  |  |  | 142 | $_prevent_deep_recursion = 1; | 
| 111 | 6 |  |  |  |  | 29 | my $ret_val = PerlIO::via::Timeout->WRITE($_[1], $_[0]); | 
| 112 | 6 |  |  |  |  | 52 | $_prevent_deep_recursion = 0; | 
| 113 | 6 |  |  |  |  | 11 | return $ret_val; | 
| 114 |  |  |  |  |  |  | } | 
| 115 | 1 |  |  |  |  | 46 | } | 
| 116 |  |  |  |  |  |  | } | 
| 117 |  |  |  |  |  |  |  | 
| 118 |  |  |  |  |  |  | package IO::Socket::Timeout::Role::SetSockOpt; | 
| 119 |  |  |  |  |  |  | $IO::Socket::Timeout::Role::SetSockOpt::VERSION = '0.29'; | 
| 120 | 10 |  |  | 10 |  | 43 | use Carp; | 
|  | 10 |  |  |  |  | 14 |  | 
|  | 10 |  |  |  |  | 591 |  | 
| 121 | 10 |  |  | 10 |  | 1689 | use Socket; | 
|  | 10 |  |  |  |  | 9481 |  | 
|  | 10 |  |  |  |  | 8463 |  | 
| 122 |  |  |  |  |  |  |  | 
| 123 |  |  |  |  |  |  | sub _check_attributes { | 
| 124 | 41 |  |  | 72 |  | 52 | my ($self) = @_; | 
| 125 | 41 | 50 |  |  |  | 77 | grep { $_ < 0 } grep { defined } map { ${*$self}{$_} } qw(ReadTimeout WriteTimeout) | 
|  | 61 |  |  |  |  | 213 |  | 
|  | 82 |  |  |  |  | 141 |  | 
|  | 82 |  |  |  |  | 75 |  | 
|  | 82 |  |  |  |  | 245 |  | 
| 126 |  |  |  |  |  |  | and croak "if defined, 'ReadTimeout' and 'WriteTimeout' attributes should be >= 0"; | 
| 127 |  |  |  |  |  |  | } | 
| 128 |  |  |  |  |  |  |  | 
| 129 |  |  |  |  |  |  | sub read_timeout { | 
| 130 | 21 |  |  | 33 |  | 193 | my ($self) = @_; | 
| 131 | 21 | 50 |  |  |  | 77 | @_ > 1 and ${*$self}{ReadTimeout} = $_[1], $self->_check_attributes, $self->_set_sock_opt; | 
|  | 21 |  |  |  |  | 252 |  | 
| 132 | 21 |  |  |  |  | 121 | ${*$self}{ReadTimeout} | 
|  | 21 |  |  |  |  | 55 |  | 
| 133 |  |  |  |  |  |  | } | 
| 134 |  |  |  |  |  |  |  | 
| 135 |  |  |  |  |  |  | sub write_timeout { | 
| 136 | 20 |  |  | 20 |  | 108 | my ($self) = @_; | 
| 137 | 20 | 50 |  |  |  | 68 | @_ > 1 and ${*$self}{WriteTimeout} = $_[1], $self->_check_attributes, $self->_set_sock_opt; | 
|  | 20 |  |  |  |  | 108 |  | 
| 138 | 20 |  |  |  |  | 147 | ${*$self}{WriteTimeout} | 
|  | 20 |  |  |  |  | 42 |  | 
| 139 |  |  |  |  |  |  | } | 
| 140 |  |  |  |  |  |  |  | 
| 141 | 28 |  |  | 28 |  | 200 | sub enable_timeout { $_[0]->timeout_enabled(1) } | 
| 142 | 0 |  |  | 0 |  | 0 | sub disable_timeout { $_[0]->timeout_enabled(0) } | 
| 143 |  |  |  |  |  |  | sub timeout_enabled { | 
| 144 | 28 |  |  | 28 |  | 38 | my ($self) = @_; | 
| 145 | 28 | 50 |  |  |  | 100 | @_ > 1 and ${*$self}{TimeoutEnabled} = !!$_[1], $self->_set_sock_opt; | 
|  | 28 |  |  |  |  | 248 |  | 
| 146 | 28 |  |  |  |  | 208 | ${*$self}{TimeoutEnabled} | 
|  | 28 |  |  |  |  | 74 |  | 
| 147 |  |  |  |  |  |  | } | 
| 148 |  |  |  |  |  |  |  | 
| 149 |  |  |  |  |  |  | sub _set_sock_opt { | 
| 150 | 69 |  |  | 69 |  | 82 | my ($self) = @_; | 
| 151 | 69 |  |  |  |  | 221 | my $read_seconds; | 
| 152 |  |  |  |  |  |  | my $read_useconds; | 
| 153 | 0 |  |  |  |  | 0 | my $write_seconds; | 
| 154 | 0 |  |  |  |  | 0 | my $write_useconds; | 
| 155 | 69 | 50 |  |  |  | 66 | if (${*$self}{TimeoutEnabled}) { | 
|  | 69 |  |  |  |  | 179 |  | 
| 156 | 69 |  | 100 |  |  | 48 | my $read_timeout = ${*$self}{ReadTimeout} || 0; | 
| 157 | 69 |  |  |  |  | 106 | $read_seconds  = int( $read_timeout ); | 
| 158 | 69 |  |  |  |  | 117 | $read_useconds = int( 1_000_000 * ( $read_timeout - $read_seconds )); | 
| 159 | 69 |  | 100 |  |  | 81 | my $write_timeout = ${*$self}{WriteTimeout} || 0; | 
| 160 | 69 |  |  |  |  | 71 | $write_seconds  = int( $write_timeout ); | 
| 161 | 69 |  |  |  |  | 82 | $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 | 69 |  |  |  |  | 291 | my $read_struct  = pack( 'l!l!', $read_seconds, $read_useconds ); | 
| 167 | 69 |  |  |  |  | 112 | my $write_struct = pack( 'l!l!', $write_seconds, $write_useconds ); | 
| 168 |  |  |  |  |  |  |  | 
| 169 | 69 | 50 |  |  |  | 348 | $self->setsockopt( SOL_SOCKET, SO_RCVTIMEO, $read_struct ) | 
| 170 |  |  |  |  |  |  | or croak "setsockopt(SO_RCVTIMEO): $!"; | 
| 171 |  |  |  |  |  |  |  | 
| 172 | 69 | 50 |  |  |  | 684 | $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.29'; | 
| 178 | 10 |  |  | 10 |  | 4946 | use PerlIO::via::Timeout; | 
|  | 10 |  |  |  |  | 34194 |  | 
|  | 10 |  |  |  |  | 1179 |  | 
| 179 |  |  |  |  |  |  |  | 
| 180 | 2 |  |  | 2 |  | 87 | 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 |  | 57 | 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__ |