File Coverage

lib/IOMux/Handler.pm
Criterion Covered Total %
statement 55 92 59.7
branch 9 44 20.4
condition 2 9 22.2
subroutine 17 24 70.8
pod 15 16 93.7
total 98 185 52.9


line stmt bran cond sub pod time code
1             # Copyrights 2011-2020 by [Mark Overmeer ].
2             # For other contributors see ChangeLog.
3             # See the manual pages for details on the licensing terms.
4             # Pod stripped from pm file by OODoc 2.02.
5             # This code is part of distribution IOMux. Meta-POD processed with OODoc
6             # into POD and HTML manual-pages. See README.md
7             # Copyright Mark Overmeer. Licensed under the same terms as Perl itself.
8              
9             package IOMux::Handler;
10 8     8   7141 use vars '$VERSION';
  8         19  
  8         364  
11             $VERSION = '1.01';
12              
13              
14 8     8   40 use warnings;
  8         9  
  8         177  
15 8     8   37 use strict;
  8         13  
  8         146  
16              
17 8     8   426 use Log::Report 'iomux';
  8         86551  
  8         38  
18              
19 8     8   1774 use Scalar::Util 'weaken';
  8         11  
  8         338  
20 8     8   3844 use Time::HiRes 'time';
  8         10343  
  8         30  
21 8     8   5020 use Socket;
  8         25982  
  8         3050  
22 8     8   57 use Fcntl;
  8         10  
  8         9046  
23              
24             my $start_time = time;
25              
26              
27 15     15 1 5036 sub new(@) {my $class = shift; (bless {}, $class)->init( {@_} ) }
  15         98  
28              
29             sub init($)
30 16     16 0 41 { my ($self, $args) = @_;
31 16 50       81 return $self if $self->{IH_name}; # already initialized
32              
33 16   33     131 my $name = $self->{IH_name} = $args->{name} || "$self";
34 16 100       96 if(my $fh = $self->{IH_fh} = $args->{fh})
35 15         202 { $self->{IH_fileno} = $fh->fileno;
36 15         199 $self->{IH_uses_ssl} = UNIVERSAL::isa($fh, 'IO::Socket::SSL');
37             }
38 16         36 $self;
39             }
40              
41              
42 0     0 1 0 sub open() {panic}
43              
44             #-------------------------
45              
46 1     1 1 5 sub name() {shift->{IH_name}}
47 0     0 1 0 sub mux() {shift->{IH_mux}}
48              
49              
50 2     2 1 12 sub fileno() {shift->{IH_fileno}}
51 43     43 1 627 sub fh() {shift->{IH_fh}}
52 0     0 1 0 sub usesSSL(){shift->{IH_uses_ssl}}
53              
54             #-----------------------
55              
56             sub timeout(;$)
57 0     0 1 0 { my $self = shift;
58 0 0       0 @_ or return $self->{IH_timeout};
59              
60 0         0 my $old = $self->{IH_timeout};
61 0         0 my $after = shift;
62 0 0       0 my $when = !$after ? undef
    0          
63             : $after > $start_time ? $after
64             : ($after + time);
65              
66 0         0 $self->{IH_mux}->changeTimeout($self->{IH_fileno}, $old, $when);
67 0         0 $self->{IH_timeout} = $when;
68             }
69              
70              
71             sub close(;$)
72 16     16 1 1729 { my ($self, $cb) = @_;
73 16 100       50 if(my $fh = delete $self->{IH_fh})
74 13 50       43 { if(my $mux = $self->{IH_mux})
75 13         70 { $mux->remove($self->{IH_fileno});
76             }
77 13         101 $fh->close;
78             }
79 16         273 local $!;
80 16 100       131 $cb->($self) if $cb;
81             }
82              
83             #-------------------------
84              
85             sub muxInit($;$)
86 13     13 1 39 { my ($self, $mux, $handler) = @_;
87              
88 13         56 $self->{IH_mux} = $mux;
89 13         58 weaken($self->{IH_mux});
90              
91 13         34 my $fileno = $self->{IH_fileno};
92 13   33     213 $mux->handler($fileno, $handler || $self);
93              
94 13 50       68 if(my $timeout = $self->{IH_timeout})
95 0         0 { $mux->changeTimeout($fileno, undef, $timeout);
96             }
97              
98 13         171 trace "mux add #$fileno, $self->{IH_name}";
99             }
100              
101              
102             sub muxRemove()
103 13     13 1 29 { my $self = shift;
104 13         48 delete $self->{IH_mux};
105             #use Carp 'cluck';
106             #cluck "REMOVE";
107 13         71 trace "mux remove #$self->{IH_fileno}, $self->{IH_name}";
108             }
109              
110              
111             sub muxTimeout()
112 0     0 1 0 { my $self = shift;
113 0         0 error __x"timeout set on {name} but not handled", name => $self->name;
114             }
115              
116             #----------------------
117              
118              
119             #sub muxReadFlagged($) { panic "no input expected on ". shift->name }
120              
121              
122             #sub muxExceptFlagged($) { panic "exception arrived on ". shift->name }
123              
124              
125             #sub muxWriteFlagged($) { shift } # simply ignore write offers
126              
127              
128             #-------------------------
129              
130             sub show()
131 0     0 1 0 { my $self = shift;
132 0         0 my $name = $self->name;
133 0 0       0 my $fh = $self->fh
134             or return "fileno=".$self->fileno." is closed; name=$name";
135              
136 0         0 my $mode = 'unknown';
137 0 0       0 unless($^O eq 'Win32')
138 0 0       0 { my $flags = fcntl $fh, F_GETFL, 0 or fault "fcntl F_GETFL";
139 0 0       0 $mode = ($flags & O_WRONLY) ? 'w'
    0          
    0          
140             : ($flags & O_RDONLY) ? 'r'
141             : ($flags & O_RDWR) ? 'rw'
142             : 'p';
143             }
144              
145 0         0 my @show = ("fileno=".$fh->fileno, "mode=$mode");
146 0 0       0 if(my $sockopts = getsockopt $fh, SOL_SOCKET, SO_TYPE)
147             { # socket
148 0         0 my $type = unpack "i", $sockopts;
149 0 0       0 my $kind = $type==SOCK_DGRAM ? 'UDP' : $type==SOCK_STREAM ? 'TCP'
    0          
150             : 'unknown';
151 0         0 push @show, "sock=$kind";
152             }
153              
154 0         0 join ", ", @show, "name=$name";
155             }
156              
157              
158             sub fdset($$$$)
159 19     19 1 42 { my $self = shift;
160 19         134 $self->{IH_mux}->fdset($self->{IH_fileno}, @_);
161             }
162              
163              
164             sub extractSocket($)
165 0     0 1   { my ($thing, $args) = @_;
166 0   0       my $class = ref $thing || $thing;
167              
168 0           my $socket = delete $args->{socket};
169 0 0         return $socket if $socket;
170              
171 0           my @sockopts = (Blocking => 0);
172             push @sockopts, $_ => $args->{$_}
173 0           for grep /^[A-Z]/, keys %$args;
174              
175             @sockopts
176 0 0         or error __x"pass socket or provide parameters to create one for {pkg}"
177             , pkg => $class;
178              
179 0           my $ssl = delete $args->{use_ssl};
180              
181             # the extension will load these classes
182 0 0         my $make = $ssl ? 'IO::Socket::SSL' : 'IO::Socket::INET';
183 0 0         $socket = $make->new(@sockopts)
184             or fault __x"cannot create {pkg} socket", pkg => $class;
185              
186 0           $socket;
187             }
188              
189             1;