3 # This file is part of Stem.
4 # Copyright (C) 1999, 2000, 2001 Stem Systems, Inc.
6 # Stem is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
11 # Stem is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with Stem; if not, write to the Free Software
18 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 # For a license to use the Stem under conditions other than those
21 # described here, to purchase support for this software, or to purchase a
22 # commercial warranty contract, please contact Stem Systems at:
24 # Stem Systems, Inc. 781-643-7504
25 # 79 Everett St. info@stemsystems.com
29 package Stem::UDPMsg ;
41 The registration name for this Cell
46 'name' => 'bind_host',
48 The UDP socket is bound to this host for receiving or sending packets
53 'name' => 'bind_port',
55 The UDP socket is bound to this port for receiving or sending packets
59 'name' => 'send_host',
61 The UDP packet is sent to this host if the send message has no host
65 'name' => 'send_port',
67 The UDP packet is sent to this port if the send message has no port
71 'name' => 'bind_port',
73 The UDP socket is bound to this port for receiving or sending packets
80 Marks this socket as a server and it expect to receive UDP packets
84 'name' => 'max_recv_size',
87 Maximum size of received UDP packets.
92 'name' => 'data_addr',
94 Send received UDP packets as 'udp_data' type messages to this address
98 'name' => 'error_addr',
100 Send received UDP errors as 'udp_error' type messages to this address
104 'name' => 'timeout_addr',
106 Send UDP timeouts as 'udp_timeout' type messages to this address
112 This object will get the callbacks
118 This sets the timeout period to wait for UDP data. If no data has been
119 received since the timer started, a timeout message or callback will
124 'name' => 'recv_method',
125 'default' => 'udp_received',
127 This method will be called in the object when a UDP packet has been received
131 'name' => 'error_method',
132 'default' => 'udp_error',
134 This method will be called in the object when a UDP had been detected
138 'name' => 'timeout_method',
139 'default' => 'udp_timeout',
141 This method will be called in the object when no UDP data has been received
142 after the timeout period.
146 'name' => 'log_name',
148 Log to send store sent and received messages
156 my( $class ) = shift ;
158 my $self = Stem::Class::parse_args( $attr_spec, @_ ) ;
159 return $self unless ref $self ;
163 my $socket = IO::Socket::INET->new( 'Proto' => 'udp' ) ;
164 $self->{'socket'} = $socket ;
166 if ( my $bind_port = $self->{'bind_port'} ) {
168 $info_text .= "Port: $bind_port\n" ;
171 my $bind_host = $self->{'bind_host'} ;
173 if ( length $bind_host ) {
175 $bind_ip = inet_aton( $bind_host ) ;
176 $info_text .= "Host: $bind_host\n" ;
180 $bind_ip = INADDR_ANY ;
181 $info_text .= "Host: INADDR_ANY\n" ;
184 $socket->bind( $bind_port, $bind_ip ) ;
187 my @timeout_args = ( $self->{'timeout'} ) ?
188 ( 'timeout' => $self->{'timeout'} ) : () ;
191 if ( $self->{'server'} ) {
193 $self->{'read_event'} = Stem::Event::Read->new(
200 my $reg_name = $self->{'reg_name'} || 'NONE' ;
201 my $sock_host = $socket->sockhost ;
202 my $sock_port = $socket->sockport ;
204 $self->{'info'} = <<INFO ;
205 ---------------------
212 ---------------------
223 return $self->{'info'} ;
231 #print "UDP readable\n" ;
235 my $udp_addr = $self->{'socket'}->recv( $udp_data,
236 $self->{'max_recv_size'} ) ;
238 #print "UDP READ [$udp_data]\n" ;
242 unless( defined( $udp_addr ) ) {
244 if ( my $error_addr = $self->{'error_addr'} ) {
246 my $msg = Stem::Msg->new(
248 'from' => $self->{'from_addr'},
249 'type' => 'udp_error',
253 #print $msg->dump( 'UDP error' ) ;
258 # send the data via a callback
260 if ( my $obj = $self->{'object'} ) {
262 my $method = $self->{'error_method'} ;
263 $obj->$method( \"$!" ) ;
269 my( $from_port, $from_host ) = unpack_sockaddr_in( $udp_addr ) ;
271 $from_host = inet_ntoa( $from_host ) ;
273 # send out the data as a stem message
275 #print "ADDR [$self->{'data_addr'}]\n" ;
277 if ( my $data_addr = $self->{'data_addr'} ) {
279 my $msg = Stem::Msg->new(
281 'from' => $self->{'reg_name'},
282 'type' => 'udp_data',
284 'data' => \$udp_data,
285 'from_port' => $from_port,
286 'from_host' => $from_host,
290 #print $msg->dump( 'UDP recv' ) ;
295 # send the data via a callback
297 if ( my $obj = $self->{'object'} ) {
299 my $method = $self->{'recv_method'} ;
300 $obj->$method( \$udp_data, $from_port, $from_host ) ;
310 #print "UDP timeout\n" ;
312 # send out the timeout as a stem message
314 if ( my $timeout_addr = $self->{'timeout_addr'} ) {
316 my $msg = Stem::Msg->new(
317 'to' => $timeout_addr,
318 'from' => $self->{'reg_name'},
319 'type' => 'udp_timeout',
322 #print $msg->dump( 'UDP timeout' ) ;
327 # send the timeout via a callback
329 if ( my $obj = $self->{'object'} ) {
331 my $method = $self->{'timeout_method'} ;
341 my ( $self, $msg ) = @_ ;
343 #print $msg->dump( 'UDP send' ) ;
344 my $msg_data = $msg->data() ;
346 my $send_port = $msg_data->{'send_port'} || $self->{'send_port'} ;
347 my $send_host = $msg_data->{'send_host'} || $self->{'send_host'} ;
349 my $udp_data = $msg_data->{'data'} ;
351 return $self->_send( $udp_data, $send_port, $send_host ) ;
356 my ( $self, $data, %args ) = @_ ;
358 my $send_port = $args{'send_port'} || $self->{'send_port'} ;
359 my $send_host = $args{'send_host'} || $self->{'send_host'} ;
361 return $self->_send( $data, $send_port, $send_host ) ;
366 my( $self, $data, $port, $host ) = @_ ;
368 $host or return "Missing send_host for UDP send" ;
369 $port or return "Missing send_port for UDP send" ;
371 #print "P $port H $host\n" ;
373 my $host_ip = inet_aton( $host ) ;
374 $host_ip or return "Bad host '$host'" ;
376 my $send_addr = pack_sockaddr_in( $port, $host_ip ) ;
378 $data = $$data if ref $data ;
380 my $byte_cnt = $self->{'socket'}->send( $data, 0, $send_addr ) ;
382 #print "BYTES [$byte_cnt]\n" ;
384 return "send error: $!" unless defined $byte_cnt ;
391 my ( $self, $msg ) = @_ ;
393 #print $msg->dump( 'SHUT' ) ;
404 if ( my $read_event = delete $self->{'read_event'} ) {
406 $read_event->cancel() ;
409 delete $self->{'object'} ;
411 my $socket = delete $self->{'socket'} ;