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'} ) {
167 $self->cell_set_args(
168 'host' => $self->{'host'},
169 'port' => $self->{'port'},
170 'server' => $self->{'server'},
173 #print "Sock\n", Dumper( $self ) ;
182 #print "MODE [$self->{connecting}]\n" ;
184 # return if $self->{connecting}++ ;
186 my $host = $self->cell_get_args( 'host' ) || $self->{'host'} ;
187 my $port = $self->cell_get_args( 'port' ) || $self->{'port'} ;
188 my $sync = $self->cell_get_args( 'sync' ) || $self->{'sync'} ;
190 ########################
191 ########################
192 ## handle connect timeouts
193 ########################
194 ########################
196 #TraceStatus "Connecting to $host:$port" ;
198 my $sock_obj = Stem::Socket->new(
205 return $sock_obj unless ref $sock_obj ;
207 $self->{'sock_obj'} = $sock_obj ;
214 my( $self, $connected_sock ) = @_ ;
216 #print "CONNECTED\n" ;
218 $self->{connected} = 1 ;
220 $self->send_status_msg( 'connected' ) ;
222 my $type = $self->{'sock_obj'} ?
223 $self->{'sock_obj'}->type() :
226 my $info = sprintf( <<INFO,
232 $connected_sock->sockhost(),
233 $connected_sock->sockport(),
234 $connected_sock->peerhost(),
235 $connected_sock->peerport(),
238 TraceStatus "\n$info" ;
242 if ( my $log_name = $self->{ 'log_name' } ) {
246 Stem::Log::Entry->new(
248 'text' => "Connected\n$info",
252 $self->cell_set_args(
253 'fh' => $connected_sock,
255 [ 'fh' => $connected_sock ],
259 my $err = $self->cell_trigger() ;
260 # print "TRIGGER ERR [$err]\n" unless ref $err ;
263 # this method is called after the cell is triggered. this cell can be
264 # the original cell or a cloned one.
270 #print "SockMsg triggered\n" ;
271 return if $self->{'connected'} ;
272 return if $self->{'server'} ;
274 # return "SockMsg: can't connect a server socket" if $self->{'server'} ;
276 return $self->connect() ;
279 # we handle the socket close method directly here so we can reconnect
280 # if needed. the other async method callbacks are in Cell.pm
286 # reconnect stuff. should be in Socket.pm
288 # my $sock = $self->cell_get_args( 'fh' ) ;
290 #print "Sock MSG: closed name $self->{'reg_name'}\n" ;
291 # $self->{'sock_obj'}->connect_to() ;
293 $self->send_status_msg( 'disconnected' ) ;
295 if ( my $log_name = $self->{ 'log_name' } ) {
297 Stem::Log::Entry->new(
299 'text' => "Closed\n$self->{'info'}",
303 # TraceStatus "Disconnected" ;
305 $self->cell_set_args( 'info' => 'SockMsg disconnected' ) ;
307 ######################
308 ######################
309 # add support for reconnect.
310 # it has a flag, delay, retry count.
311 ######################
312 ######################
321 #print "SOCKMSG SHUT $self\n", caller(), "\n", dump_data $self ;
323 $self->cell_shut_down() ;
325 unless ( $self->{'connected'} ) {
328 #cluck "SOCKMSG SHUT SERVER $self\n" ;
330 my $sock_obj = $self->{'sock_obj'} ;
332 $sock_obj->shut_down() ;
336 sub send_status_msg {
338 my( $self, $status ) = @_ ;
340 my $status_addr = $self->{status_addr} or return ;
342 my $status_msg = Stem::Msg->new(
344 from => $self->cell_from_addr(),
351 $status_msg->dispatch() ;
359 # print "SOCKMSG DESTROY", caller(), "\n" ;
361 #print $self->_dump( "DESTROY") ;
365 # sub IO::Socket::INET::DESTROY {
366 # my ( $self ) = @_ ;
368 # # print "IO::DESTROY\n", dump_socket( $self ) ;
370 # #warn "L $listener - S $self\n" if $listener == $self ;
372 # # print "SOCKMSG DESTROY", caller(), "\n" ;
373 # #cluck "IO::DESTROY $self\n" ;