added check for connected when triggered method is called. can't trigger
[urisagit/Stem.git] / lib / Stem / SockMsg.pm
CommitLineData
4536f655 1# File: Stem/SockMsg.pm
2
3# This file is part of Stem.
4# Copyright (C) 1999, 2000, 2001 Stem Systems, Inc.
5
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.
10
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.
15
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
19
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:
23
24# Stem Systems, Inc. 781-643-7504
25# 79 Everett St. info@stemsystems.com
26# Arlington, MA 02474
27# USA
28
29package Stem::SockMsg ;
30
31use strict ;
32
33use Data::Dumper ;
34
35use Stem::Socket ;
36use Stem::Trace 'log' => 'stem_status', 'sub' => 'TraceStatus' ;
37use Stem::Trace 'log' => 'stem_error' , 'sub' => 'TraceError' ;
38use Stem::Route qw( :cell ) ;
39use base 'Stem::Cell' ;
40
41use Stem::Debug qw( dump_data dump_socket ) ;
42
43
44my $attr_spec = [
45
46 {
47 'name' => 'reg_name',
48 'help' => <<HELP,
49The registration name for this Cell
50HELP
51 },
52
53 {
54 'name' => 'host',
55 'env' => 'host',
56 'help' => <<HELP,
57Host address to listen on or connect to
58HELP
59 },
60
61 {
62 'name' => 'port',
63 'env' => 'port',
64 'required' => 1,
65 'help' => <<HELP,
66Port address to listen on or connect to
67HELP
68 },
69
70 {
71 'name' => 'server',
72 'type' => 'boolean',
73 'help' => <<HELP,
74Mark this Cell as a server (listens for connections)
75HELP
76 },
77
78 {
79 'name' => 'connect_now',
80 'type' => 'boolean',
81 'help' => <<HELP,
82Connect upon Cell creation
83HELP
84 },
85
86 {
87 'name' => 'status_addr',
88 'type' => 'address',
89 'help' => <<HELP,
90Send status (connect/disconnect) messages to this address.
91HELP
92 },
93
94 {
95 'name' => 'sync',
96 'type' => 'boolean',
97 'default' => 0,
98 'help' => <<HELP,
99Mark this as a synchronously connecting socket. Default is asyncronous
100connections. In both cases the same method callbacks are used.
101HELP
102 },
103
104 {
105 'name' => 'log_name',
106 'help' => <<HELP,
107Log to send connection status to
108HELP
109 },
110
111 {
112 'name' => 'cell_attr',
113 'class' => 'Stem::Cell',
114 'help' => <<HELP,
115Argument list passed to Stem::Cell for this Cell
116HELP
117 },
118
119] ;
120
121#my $listener ;
122
123
124sub new {
125
126 my( $class ) = shift ;
127
128 my $self = Stem::Class::parse_args( $attr_spec, @_ ) ;
129 return $self unless ref $self ;
130
131 if ( $self->{'server'} ) {
132 my $listen_obj = Stem::Socket->new(
133 'object' => $self,
134 'host' => $self->{'host'},
135 'port' => $self->{'port'},
136 'server' => 1,
137 ) ;
138
139 return $listen_obj unless ref $listen_obj ;
140
141 my $host_text = $self->{'host'} ;
142
143 $host_text = 'localhost' unless defined $host_text ;
144
145 my $info = <<INFO ;
146SockMsg
147Type: server
148Local: $host_text:$self->{'port'}
149INFO
150
151 $self->cell_info( $info ) ;
152
153 $self->{'listen_obj'} = $listen_obj ;
154
155#print "LISTEN $listen_obj\n" ;
156#$listener = $listen_obj ;
157
158 $self->cell_activate() ;
159 }
160 elsif ( $self->{'connect_now'} ) {
161
bd113ec4 162#print "NOW\n" ;
163
4536f655 164 $self->connect() ;
165 }
166
167 $self->cell_set_args(
168 'host' => $self->{'host'},
169 'port' => $self->{'port'},
170 'server' => $self->{'server'},
171 ) ;
172
173#print "Sock\n", Dumper( $self ) ;
174
175 return( $self ) ;
176}
177
178sub connect {
179
180 my( $self ) = @_ ;
181
182#print "MODE [$self->{connecting}]\n" ;
183
184# return if $self->{connecting}++ ;
185
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'} ;
189
190########################
191########################
192## handle connect timeouts
193########################
194########################
195
196#TraceStatus "Connecting to $host:$port" ;
197
198 my $sock_obj = Stem::Socket->new(
199 'object' => $self,
200 'host' => $host,
201 'port' => $port,
202 'sync' => $sync,
203 ) ;
204
205 return $sock_obj unless ref $sock_obj ;
206
207 $self->{'sock_obj'} = $sock_obj ;
208
209 return ;
210}
211
212sub connected {
213
214 my( $self, $connected_sock ) = @_ ;
215
216#print "CONNECTED\n" ;
217
218 $self->{connected} = 1 ;
219
220 $self->send_status_msg( 'connected' ) ;
221
222 my $type = $self->{'sock_obj'} ?
223 $self->{'sock_obj'}->type() :
224 'sync connected' ;
225
226 my $info = sprintf( <<INFO,
227SockMsg connected
228Type: $type
229Local: %s:%d
230Remote: %s:%d
231INFO
232 $connected_sock->sockhost(),
233 $connected_sock->sockport(),
234 $connected_sock->peerhost(),
235 $connected_sock->peerport(),
236 ) ;
237
238 TraceStatus "\n$info" ;
239
bd113ec4 240#print "\n$info" ;
241
4536f655 242 if ( my $log_name = $self->{ 'log_name' } ) {
243
244#print "MSG LOG\n" ;
245
246 Stem::Log::Entry->new(
247 'logs' => $log_name,
248 'text' => "Connected\n$info",
249 ) ;
250 }
251
252 $self->cell_set_args(
253 'fh' => $connected_sock,
254 'aio_args' =>
255 [ 'fh' => $connected_sock ],
256 'info' => $info,
257 ) ;
258
259 my $err = $self->cell_trigger() ;
260# print "TRIGGER ERR [$err]\n" unless ref $err ;
261}
262
263# this method is called after the cell is triggered. this cell can be
264# the original cell or a cloned one.
265
266sub triggered_cell {
267
268 my( $self ) = @_ ;
269
270#print "SockMsg triggered\n" ;
bd113ec4 271 return if $self->{'connected'} ;
4536f655 272 return if $self->{'server'} ;
273
274# return "SockMsg: can't connect a server socket" if $self->{'server'} ;
275
276 return $self->connect() ;
277}
278
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
281
282sub async_closed {
283
284 my( $self ) = @_ ;
285
286# reconnect stuff. should be in Socket.pm
287
288# my $sock = $self->cell_get_args( 'fh' ) ;
289# $sock->close() ;
290#print "Sock MSG: closed name $self->{'reg_name'}\n" ;
291# $self->{'sock_obj'}->connect_to() ;
292
293 $self->send_status_msg( 'disconnected' ) ;
294
295 if ( my $log_name = $self->{ 'log_name' } ) {
296
297 Stem::Log::Entry->new(
298 'logs' => $log_name,
299 'text' => "Closed\n$self->{'info'}",
300 )
301 }
302
303# TraceStatus "Disconnected" ;
304
305 $self->cell_set_args( 'info' => 'SockMsg disconnected' ) ;
306
307######################
308######################
309# add support for reconnect.
310# it has a flag, delay, retry count.
311######################
312######################
313
314 $self->shut_down() ;
315}
316
317sub shut_down {
318
319 my( $self ) = @_ ;
320
321#print "SOCKMSG SHUT $self\n", caller(), "\n", dump_data $self ;
322
323 $self->cell_shut_down() ;
324
325 unless ( $self->{'connected'} ) {
326
327use Carp 'cluck' ;
328#cluck "SOCKMSG SHUT SERVER $self\n" ;
329
330 my $sock_obj = $self->{'sock_obj'} ;
331
332 $sock_obj->shut_down() ;
333 }
334}
335
336sub send_status_msg {
337
338 my( $self, $status ) = @_ ;
339
340 my $status_addr = $self->{status_addr} or return ;
341
342 my $status_msg = Stem::Msg->new(
343 to => $status_addr,
344 from => $self->cell_from_addr(),
345 type => 'status',
346 data => {
347 status => $status,
348 },
349 ) ;
350
351 $status_msg->dispatch() ;
352}
353
354
355
356sub DESTROY {
357 my ( $self ) = @_ ;
358
359# print "SOCKMSG DESTROY", caller(), "\n" ;
360
361#print $self->_dump( "DESTROY") ;
362}
363
364
365# sub IO::Socket::INET::DESTROY {
366# my ( $self ) = @_ ;
367
368# # print "IO::DESTROY\n", dump_socket( $self ) ;
369
370# #warn "L $listener - S $self\n" if $listener == $self ;
371
372# # print "SOCKMSG DESTROY", caller(), "\n" ;
373# #cluck "IO::DESTROY $self\n" ;
374# }
375
3761 ;