1 # al-as.tcl --
2 #
3 # Base class for Announce/Listen Manager implementation in
4 # Active Service Framework.
5 #
6 # Copyright (c) 1998-2002 The Regents of the University of California.
7 # All rights reserved.
8 #
9 # Redistribution and use in source and binary forms, with or without
10 # modification, are permitted provided that the following conditions are met:
11 #
12 # A. Redistributions of source code must retain the above copyright notice,
13 # this list of conditions and the following disclaimer.
14 # B. Redistributions in binary form must reproduce the above copyright notice,
15 # this list of conditions and the following disclaimer in the documentation
16 # and/or other materials provided with the distribution.
17 # C. Neither the names of the copyright holders nor the names of its
18 # contributors may be used to endorse or promote products derived from this
19 # software without specific prior written permission.
20 #
21 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
22 # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 # ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
25 # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27 # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29 # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #
32 # @(#) $Header: /usr/mash/src/repository/mash/mash-1/tcl/as/al-as.tcl,v 1.11 2002/02/26 20:45:11 weitsang Exp $
33
34
35 import AnnounceListenManager Timer/Adaptive/ConstBW
36
37 #----------------------------------------------------------------------
38 # Class:
39 # AnnounceListenManager/AS
40 # Description:
41 # Base class for AnnounceListenManager in Active Service Framework.
42 # Members:
43 # atype_ --
44 # Type of this agent
45 # agentbytype_ --
46 # An array of list of agents, indexed by type (srv, client, hm).
47 # aliveid_ --
48 # ID to the "after" callback check_alive{}.
49 # lastann_ --
50 # An array indexed by agent spec, that contains time the last
51 # announcement was made to the corresponding agent. Time are
52 # stored as absolute time (gettimeofday) and as ascii time (
53 # clock format).
54 # avgdelta_ --
55 # An array indexed by agent spec, that contains average time
56 # between announcement from the corresponding agent.
57 #----------------------------------------------------------------------
58 Class AnnounceListenManager/AS -superclass AnnounceListenManager
59
60
61 #----------------------------------------------------------------------
62 # Method:
63 # AnnounceListenManager/AS init
64 # Description:
65 # Initialize various members and timer.
66 #----------------------------------------------------------------------
67 AnnounceListenManager/AS instproc init { netspec bw atype } {
68 #
69 # FIXME Seed the random number generator (0 means use
70 # a heurstic to derive a seed from system parameters)
71 # This belongs elsewhere.
72 #
73 random 0
74 $self next $netspec 1024
75 $self instvar atype_
76 set atype_ $atype
77
78 $self instvar agentbytype_
79 set agentbytype_(srv) ""
80 set agentbytype_(client) ""
81 set agentbytype_(hm) ""
82
83 # FIXME
84 set t [new Timer/Adaptive/ConstBW $bw 3000]
85 $t randomize
86 $self timer $t
87
88 set o [$self options]
89 $o add_default startupWait 60
90 $self instvar aliveid_
91 set aliveid_ [after [expr [$self get_option startupWait]*1000] "$self check_alive 1"]
92 }
93
94
95 #----------------------------------------------------------------------
96 # Method:
97 # AnnounceListenManager/AS version
98 # Description:
99 # Return the version string of the current Active Service Framework.
100 #----------------------------------------------------------------------
101 AnnounceListenManager/AS proc version {} {
102 return 2.0
103 }
104
105
106 #----------------------------------------------------------------------
107 # Method:
108 # AnnounceListenManager/AS send_announcement
109 # Description:
110 # Construct an announcement, and send it. Since this method is called
111 # periodically, we take this chance to check for liveness in other
112 # agent by calling "check_alive 0" before exiting.
113 #----------------------------------------------------------------------
114 AnnounceListenManager/AS public send_announcement {} {
115 $self instvar atype_
116
117 set o "ASCP v[$class version]\n"
118 append o "$atype_\n"
119 append o "[$self agent_instance]\n"
120 append o "[$self service_name]\n"
121 append o "[$self service_location]\n"
122 append o "[$self service_instance]\n"
123 append o "[$self ssg_port]\n"
124 append o "[$self agent_data]\n"
125
126 $self announce $o
127
128 $self check_alive 0
129 }
130
131
132 #----------------------------------------------------------------------
133 # Method:
134 # AnnounceListenManager/AS announce_death
135 # Description:
136 # Construct a BYE announcement and announce it.
137 #----------------------------------------------------------------------
138 AnnounceListenManager/AS instproc announce_death {} {
139 $self instvar id1_ id2_ atype_
140
141 set o "ASCP v[AnnounceListenManager/AS version]"
142 append o "$atype_\n"
143 append o "[$self agent_instance]\n"
144 append o "bye\n"
145 append o "-\n"
146 append o "-\n"
147 append o "-\n"
148
149 $self announce $o
150 }
151
152
153 #----------------------------------------------------------------------
154 # Method:
155 # AnnounceListenManager/AS agent_instance
156 # Description:
157 # Return a string that represent an instance of the current agent.
158 #----------------------------------------------------------------------
159 AnnounceListenManager/AS public agent_instance {} {
160 return "[pid]@[lookup_host_name [localaddr]]"
161 }
162
163
164 #----------------------------------------------------------------------
165 # Method:
166 # AnnounceListenManager/AS agent_data
167 # Description:
168 # Subclass should overwrite this to return agent specific data.
169 #----------------------------------------------------------------------
170 AnnounceListenManager/AS public agent_data {} {
171 return ""
172 }
173
174
175 #----------------------------------------------------------------------
176 # Method:
177 # AnnounceListenManager/AS ssg_port
178 # Description:
179 # Subclass should overwrite this to return port number to a soft state
180 # gateway.
181 #----------------------------------------------------------------------
182 AnnounceListenManager/AS public ssg_port {} {
183 return "-"
184 }
185
186
187 #----------------------------------------------------------------------
188 # Method:
189 # AnnounceListenManager/AS service_location
190 # Description:
191 # Subclass should overwrite this to return the service location.
192 #----------------------------------------------------------------------
193 AnnounceListenManager/AS instproc service_location {} {
194 return "-"
195 }
196
197
198 #----------------------------------------------------------------------
199 # Method:
200 # AnnounceListenManager/AS destroy
201 # Description:
202 # Cleanup "after" callback.
203 #----------------------------------------------------------------------
204 AnnounceListenManager/AS instproc destroy {} {
205 $self instvar aliveid_
206 after cancel $aliveid_
207
208 $self next
209 }
210
211
212 #----------------------------------------------------------------------
213 # Method:
214 # AnnounceListenManager/AS recv_announcement
215 # Description:
216 # Called when an announcement is received. The announcement is parsed
217 # and special cases are handled (DEATH, BYE, wrong version). The method
218 # "recv_msg {}" is then called to process other general messages.
219 # Arguments:
220 # addr -- The address where this announcement came from.
221 # port -- The port number where this announcement came from.
222 # data -- The data contained in this announcement.
223 # size -- The length of data in bytes.
224 #----------------------------------------------------------------------
225 AnnounceListenManager/AS instproc recv_announcement { addr port data size } {
226 $self instvar lastann_ sdp_ agentbytype_ agenttab_ atype_
227 set t [$self get_timer]
228 $t sample_size $size
229
230 set o [split $data \n]
231 if { [lindex $o 0] != "ASCP v[$class version]" } {
232 # FIXME
233 set msg "$self ($class): received non-ASCP v[$class version] announcement from $addr."
234 if { $atype_ == "hm" } {
235 $self instvar agent_
236 $agent_ log $msg
237 } else {
238 puts stderr $msg
239 }
240
241 return
242 }
243 set atype [lindex $o 1]
244 set aspec [lindex $o 2]
245 set srv_name [lindex $o 3]
246 set srv_loc [lindex $o 4]
247 set srv_inst [lindex $o 5]
248 set ssg_port [lindex $o 6]
249 set ad [join [lrange $o 7 end] \n]
250
251 # Special case death packet.
252 if { $srv_name == "DEATH" } {
253 set msg "Received death packet from $aspec at $addr - exiting."
254 if { $srv_loc == $atype_ } {
255 if { $atype_ == "hm" } {
256 $self instvar agent_
257 $agent_ log $msg
258 } else {
259 puts stderr $msg
260 }
261 $self announce_death
262 exit 0
263 }
264 $self recv_msg $atype $aspec $addr DEATH $srv_loc \
265 $srv_inst $ssg_port "$ad"
266 return
267 }
268 # Synchronous bye
269 if { $srv_name == "bye" } {
270 $self delete_agent $aspec
271 return
272 }
273
274 if ![info exists agenttab_($aspec)] {
275 # new agent
276 $self instvar avgdelta_
277 $self register $atype $aspec $addr $srv_name $srv_inst "$ad"
278 $t incr_nsrcs
279 set timeout [$self get_option startupWait]
280 set avgdelta_($aspec) [expr $timeout / 8]
281 lappend agentbytype_($atype) $aspec
282 } else {
283 set now [gettimeofday]
284 set delta [expr $now - $lastann_($aspec,abs)]
285 $self instvar avgdelta_
286 set avgdelta_($aspec) \
287 [expr 0.875*$avgdelta_($aspec)+0.125*$delta]
288
289 }
290 set agenttab_($aspec) "$addr {$ad} $atype $srv_name $srv_inst"
291 set lastann_($aspec,abs) [gettimeofday]
292 set lastann_($aspec,ascii) [gettimeofday ascii]
293 $self recv_msg $atype $aspec $addr $srv_name $srv_loc $srv_inst \
294 $ssg_port "$ad"
295 }
296
297
298 #----------------------------------------------------------------------
299 # Method:
300 # AnnounceListenManager/AS check_alive
301 # Description:
302 # Go through all agents and delete agents that hasn't been announcing
303 # for a while.
304 # Arguments:
305 # timer --
306 # Specify if this is a one time call (timer == 0), or we are gonna
307 # doing this periodically (timer == 1)
308 #----------------------------------------------------------------------
309 AnnounceListenManager/AS instproc check_alive { timer } {
310 $self instvar lastann_ agenttab_ avgdelta_
311
312 set now [gettimeofday]
313 set aspecs [array names agenttab_]
314 foreach aspec $aspecs {
315 set lastann $lastann_($aspec,abs)
316 set avgdelta $avgdelta_($aspec)
317 #puts " set avgdelta $avgdelta_($aspec)"
318 #puts " set delta [expr $now - $lastann]"
319 set delta [expr $now - $lastann]
320 if { $delta > 8 * $avgdelta } {
321 $self delete_agent $aspec
322 }
323 }
324 $self instvar aliveid_
325 if { $timer } {
326 set t [expr [$self get_option startupWait]*1000]
327 set aliveid_ [after $t "$self check_alive 1"]
328 }
329 }
330
331
332 #----------------------------------------------------------------------
333 # Method:
334 # AnnounceListenManager/AS delete_agent
335 # Description:
336 # Assume that the agent specified by $aspec is dead. Clean up all
337 # states corresponding to that agent.
338 # Arguments:
339 # aspec --
340 # Specification to the agent to be deleted.
341 #----------------------------------------------------------------------
342 AnnounceListenManager/AS instproc delete_agent { aspec } {
343 $self instvar agentbytype_ agenttab_ lastann_ avgdelta_
344 if ![info exists agenttab_($aspec)] {
345 # puts "hm: agent $aspec doesn't exist!"
346 return
347 }
348 set a $agenttab_($aspec)
349
350 set addr [lindex $a 0]
351 set ad [lindex $a 1]
352 set atype [lindex $a 2]
353 set srv_name [lindex $a 3]
354 set srv_inst [lindex $a 4]
355
356 unset agenttab_($aspec)
357 unset lastann_($aspec,abs)
358 unset lastann_($aspec,ascii)
359 unset avgdelta_($aspec)
360
361 set t $agentbytype_($atype)
362 set i [lsearch -exact $t $aspec]
363 set agentbytype_($atype) [lreplace $t $i $i]
364
365 [$self get_timer] incr_nsrcs -1
366
367 $self unregister $atype $aspec $addr $srv_name $srv_inst "$ad"
368 }
369
370
371 #----------------------------------------------------------------------
372 # Method:
373 # AnnounceListenManager/AS agenttab
374 # Description:
375 # Return the agent matching specification $aspec, or return "" if
376 # no such agent can be found.
377 # Arguments:
378 # aspec --
379 # Specification to the agent to be retrieve.
380 #----------------------------------------------------------------------
381 AnnounceListenManager/AS instproc agenttab aspec {
382 $self instvar agenttab_
383 if [info exists agenttab_($aspec)] {
384 return $agenttab_($aspec)
385 }
386 return ""
387 }
388
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.