File Coverage

lib/IOMux/Handler.pm
Criterion Covered Total %
statement 55 95 57.8
branch 9 44 20.4
condition 2 9 22.2
subroutine 17 27 62.9
pod 18 19 94.7
total 101 194 52.0


line stmt bran cond sub pod time code
1             # Copyrights 2011 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 1.07.
5 8     8   11687 use warnings;
  8         14  
  8         250  
6 8     8   124 use strict;
  8         15  
  8         318  
7              
8             package IOMux::Handler;
9 8     8   57 use vars '$VERSION';
  8         21  
  8         426  
10             $VERSION = '0.12';
11              
12              
13 8     8   725 use Log::Report 'iomux';
  8         125802  
  8         85  
14              
15 8     8   2664 use Scalar::Util 'weaken';
  8         15  
  8         514  
16 8     8   8622 use Time::HiRes 'time';
  8         22587  
  8         46  
17 8     8   22859 use Socket;
  8         41655  
  8         5077  
18 8     8   66 use Fcntl;
  8         17  
  8         11514  
19              
20             my $start_time = time;
21              
22              
23 15     15 1 5130 sub new(@) {my $class = shift; (bless {}, $class)->init( {@_} ) }
  15         117  
24              
25             sub init($)
26 16     16 0 50 { my ($self, $args) = @_;
27 16 50       139 return $self if $self->{IMH_name}; # already initialized
28              
29 16   33     165 my $name = $self->{IMH_name} = $args->{name} || "$self";
30 16 100       143 if(my $fh = $self->{IMH_fh} = $args->{fh})
31 15         396 { $self->{IMH_fileno} = $fh->fileno;
32 15         168 $self->{IMH_uses_ssl} = UNIVERSAL::isa($fh, 'IO::Socket::SSL');
33             }
34 16         56 $self;
35             }
36              
37              
38 0     0 1 0 sub open() {panic}
39              
40             #-------------------------
41              
42 1     1 1 10 sub name() {shift->{IMH_name}}
43 0     0 1 0 sub mux() {shift->{IMH_mux}}
44              
45              
46 2     2 1 56 sub fileno() {shift->{IMH_fileno}}
47 43     43 1 735 sub fh() {shift->{IMH_fh}}
48 0     0 1 0 sub usesSSL(){shift->{IMH_uses_ssl}}
49              
50             #-----------------------
51              
52             sub timeout(;$)
53 0     0 1 0 { my $self = shift;
54 0 0       0 @_ or return $self->{IMH_timeout};
55              
56 0         0 my $old = $self->{IMH_timeout};
57 0         0 my $after = shift;
58 0 0       0 my $when = !$after ? undef
    0          
59             : $after > $start_time ? $after
60             : ($after + time);
61 0         0 $self->{IMH_mux}->changeTimeout($self->{IMH_fileno}, $old, $when);
62 0         0 $self->{IMH_timeout} = $when;
63             }
64              
65              
66             sub close(;$)
67 16     16 1 2080 { my ($self, $cb) = @_;
68 16 100       72 if(my $fh = delete $self->{IMH_fh})
69 13 50       49 { if(my $mux = $self->{IMH_mux})
70 13         106 { $mux->remove($self->{IMH_fileno});
71             }
72 13         103 $fh->close;
73             }
74 16         311 local $!;
75 16 100       170 $cb->($self) if $cb;
76             }
77              
78             #-------------------------
79              
80             sub mux_init($;$)
81 13     13 1 48 { my ($self, $mux, $handler) = @_;
82              
83 13         61 $self->{IMH_mux} = $mux;
84 13         141 weaken($self->{IMH_mux});
85              
86 13         35 my $fileno = $self->{IMH_fileno};
87 13   33     285 $mux->handler($fileno, $handler || $self);
88              
89 13 50       55 if(my $timeout = $self->{IMH_timeout})
90 0         0 { $mux->changeTimeout($fileno, undef, $timeout);
91             }
92              
93 13         209 trace "mux add #$fileno, $self->{IMH_name}";
94             }
95              
96              
97             sub mux_remove()
98 13     13 1 22 { my $self = shift;
99 13         33 delete $self->{IMH_mux};
100 13         93 trace "mux remove #$self->{IMH_fileno}, $self->{IMH_name}";
101             }
102              
103              
104             sub mux_timeout()
105 0     0 1 0 { my $self = shift;
106 0         0 error __x"timeout set on {name} but not handled", name => $self->name;
107             }
108              
109             #----------------------
110              
111              
112 0     0 1 0 sub mux_read_flagged($) { panic "no input expected on ". shift->name }
113              
114              
115 0     0 1 0 sub mux_except_flagged($) { panic "exception arrived on ". shift->name }
116              
117              
118 0     0 1 0 sub mux_write_flagged($) { shift } # simply ignore write offers
119              
120              
121             #-------------------------
122              
123             sub show()
124 0     0 1 0 { my $self = shift;
125 0         0 my $name = $self->name;
126 0 0       0 my $fh = $self->fh
127             or return "fileno=".$self->fileno." is closed; name=$name";
128              
129 0         0 my $mode = 'unknown';
130 0 0       0 unless($^O eq 'Win32')
131 0 0       0 { my $flags = fcntl $fh, F_GETFL, 0 or fault "fcntl F_GETFL";
132 0 0       0 $mode = ($flags & O_WRONLY) ? 'w'
    0          
    0          
133             : ($flags & O_RDONLY) ? 'r'
134             : ($flags & O_RDWR) ? 'rw'
135             : 'p';
136             }
137              
138 0         0 my @show = ("fileno=".$fh->fileno, "mode=$mode");
139 0 0       0 if(my $sockopts = getsockopt $fh, SOL_SOCKET, SO_TYPE)
140             { # socket
141 0         0 my $type = unpack "i", $sockopts;
142 0 0       0 my $kind = $type==SOCK_DGRAM ? 'UDP' : $type==SOCK_STREAM ? 'TCP'
    0          
143             : 'unknown';
144 0         0 push @show, "sock=$kind";
145             }
146              
147 0         0 join ", ", @show, "name=$name";
148             }
149              
150              
151             sub fdset($$$$)
152 19     19 1 36 { my $self = shift;
153 19         157 $self->{IMH_mux}->fdset($self->{IMH_fileno}, @_);
154             }
155              
156              
157             sub extractSocket($)
158 0     0 1   { my ($thing, $args) = @_;
159 0   0       my $class = ref $thing || $thing;
160              
161 0           my $socket = delete $args->{socket};
162 0 0         return $socket if $socket;
163              
164 0           my @sockopts;
165             push @sockopts, $_ => delete $args->{$_}
166 0           for grep /^[A-Z]/, keys %$args;
167              
168             @sockopts
169 0 0         or error __x"pass socket or provide parameters to create one for {pkg}"
170             , pkg => $class;
171              
172 0           my $ssl = delete $args->{use_ssl};
173              
174             # the extension will load these classes
175 0 0         my $make = $ssl ? 'IO::Socket::SSL' : 'IO::Socket::INET';
176 0 0         $socket = $make->new(Blocking => 0, @sockopts)
177             or fault __x"cannot create {pkg} socket", pkg => $class;
178              
179 0           $socket;
180             }
181              
182             1;