1 # File: Stem/SockMsg.pm
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::SockMsg ;
36 use Stem::Trace 'log' => 'stem_status', 'sub' => 'TraceStatus' ;
37 use Stem::Trace 'log' => 'stem_error' , 'sub' => 'TraceError' ;
38 use Stem::Route qw( :cell ) ;
39 use base 'Stem::Cell' ;
41 use Stem::Debug qw( dump_data dump_socket ) ;
49 The registration name for this Cell
57 Host address to listen on or connect to
66 Port address to listen on or connect to
74 Mark this Cell as a server (listens for connections)
79 'name' => 'connect_now',
82 Connect upon Cell creation
87 'name' => 'status_addr',
90 Send status (connect/disconnect) messages to this address.
99 Mark this as a synchronously connecting socket. Default is asyncronous
100 connections. In both cases the same method callbacks are used.
105 'name' => 'log_name',
107 Log to send connection status to
112 'name' => 'cell_attr',
113 'class' => 'Stem::Cell',
115 Argument list passed to Stem::Cell for this Cell
126 my( $class ) = shift ;
128 my $self = Stem::Class::parse_args( $attr_spec, @_ ) ;
129 return $self unless ref $self ;
131 if ( $self->{'server'} ) {
132 my $listen_obj = Stem::Socket->new(
134 'host' => $self->{'host'},
135 'port' => $self->{'port'},
139 return $listen_obj unless ref $listen_obj ;
141 my $host_text = $self->{'host'} ;
143 $host_text = 'localhost' unless defined $host_text ;
148 Local: $host_text:$self->{'port'}
151 $self->cell_info( $info ) ;
153 $self->{'listen_obj'} = $listen_obj ;
155 #print "LISTEN $listen_obj\n" ;
156 #$listener = $listen_obj ;
158 $self->cell_activate() ;
160 elsif ( $self->{'connect_now'} ) {
165 $self->cell_set_args(
166 'host' => $self->{'host'},
167 'port' => $self->{'port'},
168 'server' => $self->{'server'},
171 #print "Sock\n", Dumper( $self ) ;
180 #print "MODE [$self->{connecting}]\n" ;
182 # return if $self->{connecting}++ ;
184 my $host = $self->cell_get_args( 'host' ) || $self->{'host'} ;
185 my $port = $self->cell_get_args( 'port' ) || $self->{'port'} ;
186 my $sync = $self->cell_get_args( 'sync' ) || $self->{'sync'} ;
188 ########################
189 ########################
190 ## handle connect timeouts
191 ########################
192 ########################
194 #TraceStatus "Connecting to $host:$port" ;
196 my $sock_obj = Stem::Socket->new(
203 return $sock_obj unless ref $sock_obj ;
205 $self->{'sock_obj'} = $sock_obj ;
212 my( $self, $connected_sock ) = @_ ;
214 #print "CONNECTED\n" ;
216 $self->{connected} = 1 ;
218 $self->send_status_msg( 'connected' ) ;
220 my $type = $self->{'sock_obj'} ?
221 $self->{'sock_obj'}->type() :
224 my $info = sprintf( <<INFO,
230 $connected_sock->sockhost(),
231 $connected_sock->sockport(),
232 $connected_sock->peerhost(),
233 $connected_sock->peerport(),
236 TraceStatus "\n$info" ;
238 if ( my $log_name = $self->{ 'log_name' } ) {
242 Stem::Log::Entry->new(
244 'text' => "Connected\n$info",
248 $self->cell_set_args(
249 'fh' => $connected_sock,
251 [ 'fh' => $connected_sock ],
255 my $err = $self->cell_trigger() ;
256 # print "TRIGGER ERR [$err]\n" unless ref $err ;
259 # this method is called after the cell is triggered. this cell can be
260 # the original cell or a cloned one.
266 #print "SockMsg triggered\n" ;
267 return if $self->{'server'} ;
269 # return "SockMsg: can't connect a server socket" if $self->{'server'} ;
271 return $self->connect() ;
274 # we handle the socket close method directly here so we can reconnect
275 # if needed. the other async method callbacks are in Cell.pm
281 # reconnect stuff. should be in Socket.pm
283 # my $sock = $self->cell_get_args( 'fh' ) ;
285 #print "Sock MSG: closed name $self->{'reg_name'}\n" ;
286 # $self->{'sock_obj'}->connect_to() ;
288 $self->send_status_msg( 'disconnected' ) ;
290 if ( my $log_name = $self->{ 'log_name' } ) {
292 Stem::Log::Entry->new(
294 'text' => "Closed\n$self->{'info'}",
298 # TraceStatus "Disconnected" ;
300 $self->cell_set_args( 'info' => 'SockMsg disconnected' ) ;
302 ######################
303 ######################
304 # add support for reconnect.
305 # it has a flag, delay, retry count.
306 ######################
307 ######################
316 #print "SOCKMSG SHUT $self\n", caller(), "\n", dump_data $self ;
318 $self->cell_shut_down() ;
320 unless ( $self->{'connected'} ) {
323 #cluck "SOCKMSG SHUT SERVER $self\n" ;
325 my $sock_obj = $self->{'sock_obj'} ;
327 $sock_obj->shut_down() ;
331 sub send_status_msg {
333 my( $self, $status ) = @_ ;
335 my $status_addr = $self->{status_addr} or return ;
337 my $status_msg = Stem::Msg->new(
339 from => $self->cell_from_addr(),
346 $status_msg->dispatch() ;
354 # print "SOCKMSG DESTROY", caller(), "\n" ;
356 #print $self->_dump( "DESTROY") ;
360 # sub IO::Socket::INET::DESTROY {
361 # my ( $self ) = @_ ;
363 # # print "IO::DESTROY\n", dump_socket( $self ) ;
365 # #warn "L $listener - S $self\n" if $listener == $self ;
367 # # print "SOCKMSG DESTROY", caller(), "\n" ;
368 # #cluck "IO::DESTROY $self\n" ;