File Coverage

blib/lib/POE/Component/Server/Echo.pm
Criterion Covered Total %
statement 84 87 96.5
branch 18 36 50.0
condition 5 15 33.3
subroutine 18 19 94.7
pod 3 3 100.0
total 128 160 80.0


line stmt bran cond sub pod time code
1             # $Id: Echo.pm,v 1.3 2005/01/27 08:37:22 chris Exp $
2             #
3             # POE::Component::Server::Echo, by Chris 'BinGOs' Williams
4             #
5             # This module may be used, modified, and distributed under the same
6             # terms as Perl itself. Please see the license that came with your Perl
7             # distribution for details.
8             #
9              
10             package POE::Component::Server::Echo;
11             $POE::Component::Server::Echo::VERSION = '1.66';
12             #ABSTRACT: A POE component that implements an RFC 862 Echo server.
13              
14 2     2   31868 use strict;
  2         4  
  2         58  
15 2     2   7 use warnings;
  2         2  
  2         63  
16 2         11 use POE qw( Wheel::SocketFactory Wheel::ReadWrite Driver::SysRW
17 2     2   1089 Filter::Line );
  2         69243  
18 2     2   109056 use Carp;
  2         5  
  2         90  
19 2     2   7 use Socket;
  2         4  
  2         807  
20 2     2   10 use IO::Socket::INET;
  2         1  
  2         23  
21              
22 2     2   1321 use constant DATAGRAM_MAXLEN => 1024;
  2         3  
  2         141  
23 2     2   8 use constant DEFAULT_PORT => 7;
  2         2  
  2         1425  
24              
25             sub spawn {
26 2     2 1 24 my $package = shift;
27 2 50       8 croak "$package requires an even number of parameters" if @_ & 1;
28              
29 2         8 my %parms = @_;
30              
31 2 50 33     13 $parms{'Alias'} = 'Echo-Server' unless defined $parms{'Alias'} and $parms{'Alias'};
32 2 50 33     9 $parms{'tcp'} = 1 unless defined $parms{'tcp'} and $parms{'tcp'} == 0;
33 2 50 33     9 $parms{'udp'} = 1 unless defined $parms{'udp'} and $parms{'udp'} == 0;
34              
35 2         4 my $self = bless( { }, $package );
36              
37 2         9 $self->{CONFIG} = \%parms;
38              
39             POE::Session->create(
40             object_states => [
41             $self => { _start => '_server_start',
42             _stop => '_server_stop',
43             shutdown => '_server_close' },
44             $self => [ qw(_accept_new_client _accept_failed _client_input _client_error _get_datagram) ],
45             ],
46 2 50       30 ( ref $parms{'options'} eq 'HASH' ? ( options => $parms{'options'} ) : () ),
47             );
48              
49 2         253 return $self;
50             }
51              
52             sub _server_start {
53 2     2   462 my ($kernel,$self) = @_[KERNEL,OBJECT];
54              
55 2         9 $kernel->alias_set( $self->{CONFIG}->{Alias} );
56              
57 2 50       67 if ( $self->{CONFIG}->{tcp} ) {
58             $self->{Listener} = POE::Wheel::SocketFactory->new(
59             ( defined ( $self->{CONFIG}->{BindAddress} ) ? ( BindAddress => $self->{CONFIG}->{BindAddress} ) : () ),
60 2 50       25 ( defined ( $self->{CONFIG}->{BindPort} ) ? ( BindPort => $self->{CONFIG}->{BindPort} ) : ( BindPort => DEFAULT_PORT ) ),
    50          
61             SuccessEvent => '_accept_new_client',
62             FailureEvent => '_accept_failed',
63             SocketDomain => AF_INET, # Sets the socket() domain
64             SocketType => SOCK_STREAM, # Sets the socket() type
65             SocketProtocol => 'tcp', # Sets the socket() protocol
66             Reuse => 'on', # Lets the port be reused
67             );
68             }
69 2 50       783 if ( $self->{CONFIG}->{udp} ) {
70 2         769 my $proto = getprotobyname('udp');
71 2 50       14 my $port = defined ( $self->{CONFIG}->{BindPort} ) ? $self->{CONFIG}->{BindPort} : DEFAULT_PORT;
72 2         12 my $paddr = sockaddr_in($port, INADDR_ANY);
73 2 50       55 socket( my $socket, PF_INET, SOCK_DGRAM, $proto) || die "socket: $!";
74 2 50       16 bind( $socket, $paddr) || die "bind: $!";
75 2         4 $self->{udp_socket} = $socket;
76 2         6 $kernel->select_read( $self->{udp_socket}, "_get_datagram" );
77             }
78 2         109 undef;
79             }
80              
81             sub _server_stop {
82 2     2   148 my ($kernel,$self) = @_[KERNEL,OBJECT];
83 2         5 undef;
84             }
85              
86             sub _server_close {
87 2     2   758 my ($kernel,$self) = @_[KERNEL,OBJECT];
88              
89 2         28 delete $self->{Listener};
90 2         225 delete $self->{Clients};
91 2         6 $kernel->select( $self->{udp_socket} );
92 2         128 delete $self->{udp_socket};
93 2         9 $kernel->alias_remove( $self->{CONFIG}->{Alias} );
94 2         61 undef;
95             }
96              
97             sub _accept_new_client {
98 1     1   644 my ($kernel,$self,$socket,$peeraddr,$peerport) = @_[KERNEL,OBJECT,ARG0 .. ARG2];
99 1         6 $peeraddr = inet_ntoa($peeraddr);
100              
101 1         9 my $wheel = POE::Wheel::ReadWrite->new (
102             Handle => $socket,
103             Filter => POE::Filter::Line->new(),
104             InputEvent => '_client_input',
105             ErrorEvent => '_client_error',
106             );
107              
108 1         269 my $wheel_id = $wheel->ID();
109 1         19 $self->{Clients}->{ $wheel_id }->{Wheel} = $wheel;
110 1         3 $self->{Clients}->{ $wheel_id }->{peeraddr} = $peeraddr;
111 1         2 $self->{Clients}->{ $wheel_id }->{peerport} = $peerport;
112 1         2 undef;
113             }
114              
115             sub _accept_failed {
116 0     0   0 my ($kernel,$self) = @_[KERNEL,OBJECT];
117 0         0 $kernel->yield( 'shutdown' );
118 0         0 undef;
119             }
120              
121             sub _client_input {
122 1     1   1287 my ($kernel,$self,$input,$wheel_id) = @_[KERNEL,OBJECT,ARG0,ARG1];
123              
124 1 50 33     7 if ( defined ( $self->{Clients}->{ $wheel_id } ) and defined ( $self->{Clients}->{ $wheel_id }->{Wheel} ) ) {
125 1         6 $self->{Clients}->{ $wheel_id }->{Wheel}->put($input);
126             }
127 1         40 undef;
128             }
129              
130             sub _client_error {
131 1     1   1062 my ($self,$wheel_id) = @_[OBJECT,ARG3];
132 1         4 delete $self->{Clients}->{ $wheel_id };
133 1         121 undef;
134             }
135              
136             sub _get_datagram {
137 1     1   605 my ( $kernel, $socket ) = @_[ KERNEL, ARG0 ];
138              
139 1         17 my $remote_address = recv( $socket, my $message = "", DATAGRAM_MAXLEN, 0 );
140 1 50       3 return unless defined $remote_address;
141              
142 1 50       19 send( $socket, $message, 0, $remote_address ) == length($message)
143             or warn "Trouble sending response: $!";
144 1         4 undef;
145             }
146              
147             sub sockname_tcp {
148 1     1 1 793 my $self = shift;
149 1         2 my $name;
150 1 50       6 $name = $self->{Listener}->getsockname() if $self->{CONFIG}->{tcp};
151 1 50       19 return unless $name;
152 1         3 return sockaddr_in($name);
153             }
154              
155             sub sockname_udp {
156 1     1 1 494 my $self = shift;
157 1 50 33     6 return unless $self->{CONFIG}->{udp} and $self->{udp_socket};
158 1         9 return sockaddr_in( getsockname $self->{udp_socket} );
159             }
160              
161             qq[ECHO! ECHO...ECHO...ECHO...ECHO...ECHO...ECHO...ECHo...ECho...Echo...echo];
162              
163             __END__