File Coverage

blib/lib/POE/Component/Server/Ident.pm
Criterion Covered Total %
statement 123 145 84.8
branch 28 48 58.3
condition 9 24 37.5
subroutine 21 25 84.0
pod 7 7 100.0
total 188 249 75.5


line stmt bran cond sub pod time code
1             package POE::Component::Server::Ident;
2             $POE::Component::Server::Ident::VERSION = '1.18';
3             #ABSTRACT: A POE component that provides non-blocking ident services to your sessions.
4              
5 5     5   77428 use 5.006;
  5         10  
6 5     5   19 use strict;
  5         7  
  5         110  
7 5     5   18 use warnings;
  5         8  
  5         167  
8 5         30 use POE qw( Wheel::SocketFactory Wheel::ReadWrite Driver::SysRW
9 5     5   2568 Filter::Line );
  5         164282  
10 5     5   294051 use Carp;
  5         11  
  5         260  
11 5     5   22 use Socket;
  5         6  
  5         9373  
12              
13             sub spawn {
14 5     5 1 73 my $package = shift;
15 5         29 my %opts = @_;
16 5         50 $opts{lc $_} = delete $opts{$_} for keys %opts;
17              
18 5 50       21 $opts{bindport} = 113 unless defined $opts{bindport};
19 5 100       19 $opts{multiple} = 0 unless $opts{multiple};
20 5 50       26 $opts{timeout} = 60 unless $opts{timeout};
21 5 100       17 $opts{random} = 0 unless $opts{random};
22              
23 5         13 my $self = bless \%opts, $package;
24              
25             $self->{session_id} = POE::Session->create (
26             object_states => [
27             $self => { _start => '_server_start',
28             'shutdown' => '_server_close',
29 5         13 map { ( $_ => '_' . $_ ) } qw(accept_new_client accept_failed),
  10         81  
30             },
31             $self => [ qw(register unregister) ],
32             ],
33             )->ID();
34 5         651 return $self;
35             }
36              
37             sub session_id {
38 0     0 1 0 return $_[0]->{session_id};
39             }
40              
41             sub getsockname {
42 5     5 1 3728 my $self = shift;
43 5         20 return $self->{listener}->getsockname();
44             }
45              
46             sub _server_start {
47 5     5   1208 my ($kernel,$self,$session) = @_[KERNEL,OBJECT,SESSION];
48 5         16 $self->{session_id} = $session->ID();
49              
50 5 50       46 $kernel->alias_set( $self->{alias} ) if $self->{alias};
51 5 50       151 $kernel->refcount_increment( $self->{session_id}, __PACKAGE__ ) unless $self->{alias};
52              
53             $self->{listener} = POE::Wheel::SocketFactory->new (
54             BindPort => $self->{bindport},
55 5 50       64 ( $self->{bindaddr} ? (BindAddr => $self->{bindaddr}) : () ),
56             Reuse => 'on',
57             SuccessEvent => 'accept_new_client',
58             FailureEvent => 'accept_failed',
59             );
60 5         1907 undef;
61             }
62              
63             sub _server_close {
64 5     5   317 my ($kernel,$self) = @_[KERNEL,OBJECT];
65 5         15 $kernel->alias_remove( $_ ) for $kernel->alias_list();
66 5 50       268 $kernel->refcount_decrement( $self->{session_id}, __PACKAGE__ ) unless $self->{alias};
67 5         9 $kernel->post( $_, 'client_timeout' ) for %{ $self->{clients} };
  5         22  
68 5         42 delete $self->{listener};
69 5         675 $kernel->refcount_decrement( $_, __PACKAGE__ ) for keys %{ $self->{sessions} };
  5         27  
70 5         126 undef;
71             }
72              
73             sub _accept_new_client {
74 5     5   7866 my ($kernel,$self,$socket,$peeraddr,$peerport) = @_[KERNEL,OBJECT,ARG0 .. ARG2];
75 5         39 $peeraddr = inet_ntoa($peeraddr);
76              
77             POE::Session->create (
78             object_states => [
79             $self => { _start => '_client_start',
80             _stop => '_client_stop',
81 5         23 map { ( $_ => '_' . $_ ) } qw(client_input client_error client_done client_timeout client_default),
  25         92  
82             },
83             $self => [ qw(ident_server_reply ident_server_error) ],
84             ],
85             args => [ $socket, $peeraddr, $peerport ],
86             );
87 5         425 undef;
88             }
89              
90             sub _accept_failed {
91 0     0   0 my ($kernel,$self,$function,$error) = @_[KERNEL,OBJECT,ARG0,ARG2];
92 0         0 my $package = ref $self;
93              
94 0         0 $kernel->call ( $self->{session_id}, 'shutdown' );
95              
96 0         0 warn "$package: call to $function() failed: $error";
97 0         0 undef;
98             }
99              
100             sub register {
101 5     5 1 470 my ($kernel,$self,$sender,$session) = @_[KERNEL,OBJECT,SENDER,SESSION];
102 5         20 $sender = $sender->ID();
103 5         23 $session = $session->ID();
104              
105 5         21 $self->{sessions}->{ $sender }++;
106             $kernel->refcount_increment( $sender => __PACKAGE__ )
107 5 50 33     60 if $self->{sessions}->{ $sender } == 1 and $sender ne $session;
108 5         137 undef;
109             }
110              
111              
112             sub unregister {
113 4     4 1 7385 my ($kernel,$self,$sender,$session) = @_[KERNEL,OBJECT,SENDER,SESSION];
114 4         10 my $thing = delete $self->{sessions}->{ $sender };
115 4 50 33     21 $kernel->refcount_decrement( $sender => __PACKAGE__ )
116             if $thing and $sender ne $session;
117 4         13 return;
118             }
119              
120             sub _client_start {
121 5     5   803 my ($kernel,$session,$self,$socket,$peeraddr,$peerport) = @_[KERNEL,SESSION,OBJECT,ARG0,ARG1,ARG2];
122 5         16 my $session_id = $session->ID();
123              
124 5         24 $self->{clients}->{ $session_id }->{PeerAddr} = $peeraddr;
125 5         12 $self->{clients}->{ $session_id }->{PeerPort} = $peerport;
126              
127             $self->{clients}->{ $session_id }->{readwrite} =
128             POE::Wheel::ReadWrite->new(
129             Handle => $socket,
130             Filter => POE::Filter::Line->new( Literal => "\x0D\x0A" ),
131             InputEvent => 'client_input',
132             ErrorEvent => 'client_error',
133 5 100       27 ( $self->{'multiple'} ? () : ( FlushedEvent => 'client_timeout' ) ),
134             );
135              
136             # Set a delay to close the connection if we are idle for 60 seconds.
137 5         1440 $kernel->delay ( 'client_timeout' => $self->{'timeout'} );
138 5         387 undef;
139             }
140              
141             sub _client_stop {
142 5     5   657 my ($kernel,$self,$session) = @_[KERNEL,OBJECT,SESSION];
143              
144 5         18 $kernel->delay ( 'client_timeout' => undef );
145 5         179 delete $self->{clients}->{ $session->ID };
146 5         33 undef;
147             }
148              
149             sub _client_input {
150 5     5   6435 my ($kernel,$self,$session,$input) = @_[KERNEL,OBJECT,SESSION,ARG0];
151 5         107 my $session_id = $session->ID();
152              
153             # Parse what is passed. We want , or nothing.
154              
155 5 100 66     107 if ( $input =~ /^\s*([0-9]+)\s*,\s*([0-9]+)\s*$/ and _valid_ports($1,$2) ) {
156 4         7 my $port1 = $1; my $port2 = $2;
  4         9  
157 4         11 $self->{clients}->{ $session_id }->{'Port1'} = $port1;
158 4         8 $self->{clients}->{ $session_id }->{'Port2'} = $port2;
159             # Okay got a sort of valid query. Send it to all interested sessions.
160 4         5 $kernel->call( $_ => 'identd_request' => $self->{clients}->{ $session_id }->{PeerAddr} => $port1 => $port2 ) for keys %{ $self->{sessions} };
  4         35  
161 4         1531 $kernel->delay ( 'client_default' => 10 );
162             } else {
163             # Client sent us rubbish.
164 1         3 $self->{clients}->{ $session_id }->{readwrite}->put("0 , 0 : ERROR : INVALID-PORT");
165             }
166 5 100       306 $kernel->delay ( 'client_timeout' => $self->{'timeout'} ) if $self->{'multiple'};
167 5         94 undef;
168             }
169              
170             sub _client_done {
171 0     0   0 my ($kernel,$self,$session) = @_[KERNEL,OBJECT,SESSION];
172 0         0 $kernel->delay ( 'client_timeout' => undef );
173 0         0 delete $self->{clients}->{ $session->ID };
174 0         0 undef;
175             }
176              
177             sub _client_error {
178 1     1   1433 my ($kernel,$self,$session) = @_[KERNEL,OBJECT,SESSION];
179 1         3 $kernel->delay ( 'client_timeout' => undef );
180 1         51 delete $self->{clients}->{ $session->ID }->{readwrite};
181 1         170 undef;
182             }
183              
184             sub _client_timeout {
185 4     4   1204 my ($kernel,$self,$session) = @_[KERNEL,OBJECT,SESSION];
186 4         20 $kernel->delay ( 'client_timeout' => undef );
187 4         337 $kernel->delay ( 'client_default' => undef );
188 4         136 delete $self->{clients}->{ $session->ID }->{readwrite};
189 4         959 undef;
190             }
191              
192             sub _client_default {
193 3     3   30026961 my ($kernel,$self,$session) = @_[KERNEL,OBJECT,SESSION];
194 3         14 my $session_id = $session->ID();
195              
196 3         27 my $reply = $self->{clients}->{ $session_id }->{'Port1'} . " , " . $self->{clients}->{ $session_id }->{'Port2'};
197             SWITCH: {
198 3 100       5 if ( $self->{'default'} ) {
  3         16  
199 1         15 $reply .= " : USERID : UNIX : " . $self->{'default'};
200 1         3 last SWITCH;
201             }
202 2 100       22 if ( $self->{'random'} ) {
203 1         7 srand( $session_id * $$ );
204 1         3 my @numbers;
205 1         16 push @numbers, int rand (26) for 1 .. 8;
206 1         4 my $user_id = join '', map { chr($_+97) } @numbers;
  8         21  
207 1         5 $reply .= " : USERID : UNIX : $user_id";
208 1         5 last SWITCH;
209             }
210 1         14 $reply .= " : ERROR : HIDDEN-USER";
211             }
212 3 50       45 $self->{clients}->{ $session_id }->{readwrite}->put($reply) if defined $self->{clients}->{ $session_id }->{readwrite};
213 3 50       311 $kernel->delay ( 'client_timeout' => $self->{'timeout'} ) if $self->{'multiple'};
214 3         13 undef;
215             }
216              
217             sub ident_server_reply {
218 1     1 1 553 my ($kernel,$self,$session) = @_[KERNEL,OBJECT,SESSION];
219 1         3 my $session_id = $session->ID();
220              
221 1         4 my ($opsys,$userid) = @_[ARG0 .. ARG1];
222              
223 1 50       3 $opsys = "UNIX" unless defined ( $opsys );
224              
225 1         4 my $reply = $self->{clients}->{ $session_id }->{'Port1'} . " , " . $self->{clients}->{ $session_id }->{'Port2'} . " : USERID : " . $opsys . " : " . $userid;
226              
227 1 50       5 $self->{clients}->{ $session_id }->{readwrite}->put($reply) if $self->{clients}->{ $session_id }->{readwrite};
228 1 50       49 $kernel->delay ( 'client_timeout' => $self->{'timeout'} ) if $self->{'multiple'};
229 1         8 $kernel->delay ( 'client_default' => undef );
230 1         39 undef;
231             }
232              
233             sub ident_server_error {
234 0     0 1 0 my ($kernel,$self,$session,$error_type) = @_[KERNEL,OBJECT,SESSION,ARG0];
235 0         0 my $session_id = $session->ID();
236 0         0 $error_type = uc $error_type;
237              
238 0 0       0 unless ( grep {$_ eq $error_type} qw(INVALID-PORT NO-USER HIDDEN-USER UNKNOWN-ERROR) ) {
  0         0  
239 0         0 $error_type = 'UNKNOWN-ERROR';
240             }
241              
242 0         0 my $reply = $self->{clients}->{ $session_id }->{'Port1'} . " , " . $self->{clients}->{ $session_id }->{'Port2'} . " : ERROR : " . $error_type;
243              
244 0 0       0 $self->{clients}->{ $session_id }->{readwrite}->put($reply) if $self->{clients}->{ $session_id }->{readwrite};
245 0 0       0 $kernel->delay ( 'client_timeout' => $self->{'timeout'} ) if $self->{'multiple'};
246 0         0 $kernel->delay ( 'client_default' => undef );
247 0         0 undef;
248             }
249              
250             sub _valid_ports {
251 4     4   14 my ($port1,$port2) = @_;
252              
253 4 50 33     77 return 1 if ( defined ( $port1 ) and defined ( $port2 ) ) and ( $port1 >= 1 and $port1 <= 65535 ) and ( $port2 >= 1 and $port2 <= 65535 );
      33        
      33        
      33        
      33        
254 0           return 0;
255             }
256              
257             qq{Papers, please};
258              
259             __END__