~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Open Mash Cross Reference
mash/tcl/indiva/lib/ascp-client.tcl

Component: ~ [ mash ] ~ [ apps ] ~ [ gsm ] ~ [ lib ] ~ [ otcl ] ~ [ srm ] ~ [ tcl8.3 ] ~ [ tclcl ] ~ [ tk8.3 ] ~ [ tutorials ] ~

  1 # ascp-client.tcl --

  2 #

  3 #       Client side of ASCP protocol.

  4 #

  5 # Copyright (c) 1998-2002 The Regents of the University of California.

  6 # All rights reserved.

  7 #

  8 # Redistribution and use in source and binary forms, with or without

  9 # modification, are permitted provided that the following conditions are met:

 10 #

 11 # A. Redistributions of source code must retain the above copyright notice,

 12 #    this list of conditions and the following disclaimer.

 13 # B. Redistributions in binary form must reproduce the above copyright notice,

 14 #    this list of conditions and the following disclaimer in the documentation

 15 #    and/or other materials provided with the distribution.

 16 # C. Neither the names of the copyright holders nor the names of its

 17 #    contributors may be used to endorse or promote products derived from this

 18 #    software without specific prior written permission.

 19 #

 20 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''

 21 # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE

 22 # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE

 23 # ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR

 24 # ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL

 25 # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR

 26 # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER

 27 # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,

 28 # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE

 29 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

 30 #

 31 # @(#) $Header: /usr/mash/src/repository/mash/mash-1/tcl/indiva/lib/ascp-client.tcl,v 1.4 2002/07/15 22:08:09 weitsang Exp $

 32 
 33 import ASCP
 34 import ASCPPacket
 35 import MashLog
 36 import MashTimer/ConstBW
 37 import MashSoftState
 38 
 39 Class ASCP/Client -superclass ASCP
 40 
 41 #---------------------------------------------------------------------------

 42 # Class:

 43 #   ASCP/Client

 44 # Description:

 45 #   Abstraction for client side of ASCP protocol.  Typically, you create 

 46 #   an instance of this class and call "request start" to initiate a service.

 47 #   In some cases, you may want to intercept various stage of the ASCP 

 48 #   protocol.  To do so, you add various hooks to ASCP/Client so that 

 49 #   they will be called when certain events happen.  e.g. "on_recv_offer", 

 50 #   "on_alive".  An ASCP/client object can only launch one service.

 51 # Members:

 52 #   request_timer_ -- 

 53 #     A Mash/Timer object that sends out request message periodically.

 54 #   alive_timer_ -- 

 55 #     A Mash/Timer object that sends out alive message periodically.

 56 #   service_ -- 

 57 #     A soft-state that remembers we are being served by a service.

 58 #   sev_loc_ -- 

 59 #     Service location for the requested service.

 60 #   precond_ -- 

 61 #     Precondition for the requested service.

 62 #---------------------------------------------------------------------------

 63 
 64 #---------------------------------------------------------------------------

 65 # Method:

 66 #   ASCP/Client init

 67 # Description:

 68 #   Initialize various members.

 69 # Arguments:

 70 #   spec -- 

 71 #     addr/port specification of the active service control session.

 72 #   bw -- 

 73 #     maximum bandwidth of the control session

 74 #   srv_loc -- 

 75 #     where to find the service.

 76 #   precondition -- 

 77 #     precondition which service providers have to pass before launching

 78 #     service.

 79 #---------------------------------------------------------------------------

 80 ASCP/Client public init { spec bw srv_loc precond } {
 81     $self next $spec $bw 
 82     $self instvar srv_loc_ precond_ timeout_
 83     set srv_loc_ $srv_loc
 84     set precond_ $precond
 85     set timeout_ 10000
 86 
 87     $self instvar callback_
 88     set callback_(alive) ""
 89     set callback_(expire) ""
 90     set callback_(destroy) ""
 91 }
 92 
 93 
 94 #---------------------------------------------------------------------------

 95 # Method:

 96 #   ASCP/Client destroy

 97 # Description:

 98 #   Clean-up timers and soft-state. 

 99 #---------------------------------------------------------------------------

100 ASCP/Client instproc destroy {} {
101     $self request stop
102     $self launch stop
103     $self launch_now stop
104     $self alive stop
105 
106     $self instvar service_
107     if [info exists service_] {
108         delete $service_
109         unset service_
110     }
111 
112     $self instvar callback_
113     foreach cb $callback_(destroy) {
114         eval $cb
115     }
116 
117     $self next
118 }
119 
120 
121 #---------------------------------------------------------------------------

122 # Method:

123 #   ASCP/Client agent_type

124 # Description:

125 #   Return the type of this agent: (c)lient/(s)ervice/(m)anager.

126 #---------------------------------------------------------------------------

127 ASCP/Client public agent_type { } {
128     return "c"
129 }
130 
131 
132 #---------------------------------------------------------------------------

133 # Method:

134 #   ASCP/Client service_location

135 # Description:

136 #   Return the service location.

137 #---------------------------------------------------------------------------

138 ASCP/Client public service_location { } {
139     $self instvar srv_loc_
140     return $srv_loc_
141 }
142 
143 
144 #---------------------------------------------------------------------------

145 # Method:

146 #   ASCP/Client precondition.

147 # Description:

148 #   Return the precondition, or set the precondition to the given args.

149 #---------------------------------------------------------------------------

150 ASCP/Client public precondition { args } {
151     $self instvar precond_
152     if {$args == ""} {
153         return $precond_
154     } else {
155         set precond_ [lindex $args 0]
156     }
157 }
158 
159 
160 #---------------------------------------------------------------------------

161 # Method:

162 #   ASCP/Client request

163 # Description:

164 #   "request start" starts the periodic timer that sends a request message.

165 #   "request stop" stop the timer.

166 #---------------------------------------------------------------------------

167 ASCP/Client public request {option args} {
168     $self instvar timeout_
169     #MashLog info "Request $option [$self service_location]"

170     switch $option {
171         start {
172             set packet [new ASCPPacket]
173             $packet from_ascp "request" $self 
174             set str [$packet to_string]
175             delete $packet
176 
177             $self announce $str
178 
179             $self instvar request_timer_
180             set request_timer_ [new MashTimer/ConstBW \
181                 3000 "$self announce \{$str\}" [$self bandwidth]]
182 
183             # If "-block" is specified, we block until offer is received 

184             # in process_packet.  Unless timeout occurs.

185             set si [$self service_instance]
186             if {[lsearch $args "-block"] !=  -1} {
187                 global recv_offer_from_
188                 set recv_offer_from_($si) 0
189                 after $timeout_ "
190                     set recv_offer_from_($si) TIMEOUT
191                 "
192                 vwait recv_offer_from_($si)
193                 if {$recv_offer_from_($si) == "TIMEOUT"} {
194                     $self timeout
195                 }
196 
197                 $self request stop
198 
199                 return $recv_offer_from_($si)
200             }
201         } 
202         stop {
203             $self instvar request_timer_
204             if {[info exists request_timer_]} {
205                 delete $request_timer_
206                 unset request_timer_
207             }
208         }
209         default {
210             error "unknown request option: use start/stop"
211         }
212     }
213 }
214 
215 
216 #---------------------------------------------------------------------------

217 # Method:

218 #   ASCP/Client alive

219 # Description:

220 #   "alive start" starts the periodic timer that sends an alive message.

221 #   "alive stop" stop the timer.  "alive pending" checks if a timer exists.

222 #---------------------------------------------------------------------------

223 ASCP/Client private alive {option} {
224     #MashLog info "Alive $option [$self service_location]"

225     $self instvar alive_timer_
226     switch $option {
227         start {
228             set packet [new ASCPPacket]
229             $packet agent_type [$self agent_type]
230             $packet agent_id   [$self agent_id]
231             $packet operation  "alive"
232             $packet service_instance [$self service_instance]
233             set o [$packet to_string]
234             delete $packet
235 
236             $self announce $o
237 
238             set alive_timer_ [new MashTimer/ConstBW \
239                 1000 "$self announce \{$o\}" [$self bandwidth]]
240             $self add_timer $alive_timer_
241         } 
242         stop {
243             if [info exists alive_timer_] {
244                 $self del_timer $alive_timer_
245                 delete $alive_timer_
246                 unset alive_timer_
247             }
248         }
249         default {
250             error "unknown alive option: use start/stop/pending"
251         }
252     }
253 }
254 
255 
256 #---------------------------------------------------------------------------

257 # Method:

258 #   ASCP/Client process_packet.

259 # Description:

260 #   Handle a packet received by the protocol.  This method (or methods that

261 #   it calls) MUST free $packet when done.

262 #---------------------------------------------------------------------------

263 ASCP/Client public process_packet { addr packet } {
264 
265     set service_instance [$packet service_instance]
266     if {$service_instance != [$self service_instance]} {
267         #delete $packet

268         return
269     }
270     $self instvar service_
271     
272     set agent_type [$packet agent_type]
273     set agent_id [$packet agent_id]
274     set operation [$packet operation]
275     #delete $packet

276 
277     switch -exact -- $agent_type {
278         "c" {
279             # Ignore packets from other clients.

280         }
281         "m" {
282             switch -exact -- $operation {
283                 # Receive an offer from a host manager.

284                 "offer" {
285                     if {![info exists service_] || [$service_ is_expired]} {
286                         # This is the first offer. Accept it.  All other subsequent offers 

287                         # will be ignored.

288                         MashLog info "recv offer from $agent_id for $service_instance"
289 
290                         $self request stop
291                         global recv_offer_from_
292                         set recv_offer_from_($service_instance) $agent_id
293 
294                     } else {
295                         # Receive multiple offers.

296                         MashLog info "[$self service_location] already being served by [$service_ get_value]"
297                     }
298                 }
299             }
300         }
301         "s" {
302             switch -exact -- $operation {
303                 "alive" {
304 
305                     # Receive an alive message from a service.  If this is the first alive, then we start

306                     # a softsate timer to remember that we are being served by this service.  Otherwise,

307                     # we just refresh the soft-state.

308 
309                     $self instvar service_ launch_timer_ launch_now_timer_
310                     if ![info exists service_] {
311                         if [info exists launch_timer_] {
312                             $self launch stop
313                         } elseif [info exists launch_now_timer_] {
314                             $self launch_now stop
315                         }
316                         set service_ [new MashSoftState/Adaptive $agent_id 5000 "$self service_expire"]
317                         $self instvar alive_timer_
318                         if {![info exists alive_timer_]} { 
319                             $self alive start
320                         }
321                         global recv_alive_from_
322                         set recv_alive_from_($service_instance) $agent_id
323                     } else {
324                         $service_ refresh
325                     }
326 
327 
328                     $self instvar callback_
329                     if {$callback_(alive) != ""} {
330                         eval $callback_(alive)
331                     }
332                 }
333                 "bye" {
334                     if [info exists service_] {
335                         delete $service_
336                     } 
337                     $self request start
338                 }
339             }
340         }
341     }
342 }
343 
344 
345 #---------------------------------------------------------------------------

346 # Method:

347 #   ASCP/Client on_service_expire

348 #   ASCP/Client on_destroy

349 #   ASCP/Client on_timeout

350 #   ASCP/Client on_alive

351 # Description:

352 #   Define callbacks when events happen.

353 #---------------------------------------------------------------------------

354 ASCP/Client public on_service_expire {option callback} {
355     $self on_event expire $option $callback
356 }
357 ASCP/Client public on_destroy {option callback} {
358     $self on_event destroy $option $callback
359 }
360 ASCP/Client public on_timeout {option callback} {
361     $self on_event timeout $option $callback
362 }
363 ASCP/Client public on_alive {option callback} {
364     $self on_event alive $option $callback
365 }
366 
367 
368 #---------------------------------------------------------------------------

369 # Method:

370 #   ASCP/Client on_event

371 # Description:

372 #   Private method that manages the callbacks

373 #---------------------------------------------------------------------------

374 ASCP/Client private on_event {type option callback} {
375     $self instvar callback_
376     switch $option {
377         append {
378             lappend callback_($type) $callback
379         }
380         remove {
381             set pos [lsearch -glob $callback_($type) $callback]
382             set callback_($type) [lreplace $callback_($type) $pos $pos]
383         }
384     }
385 }
386 
387 
388 
389 #---------------------------------------------------------------------------

390 # Method:

391 #   ASCP/Client timeout

392 # Description:

393 #   Call on_timeout callback_, if defined.

394 #   Default is not to do anything

395 #---------------------------------------------------------------------------

396 ASCP/Client public timeout {} {
397     $self instvar callback_
398     if [info exists callback_(timeout)] {
399         foreach c $callback_(timeout) {
400             eval $c
401         }
402     } else {
403         $self instvar srv_loc_
404         MashLog info "TIMEOUT $srv_loc_"
405     }
406     return -code error -errorcode TIMEOUT
407 }
408 
409 
410 
411 #---------------------------------------------------------------------------

412 # Method:

413 #   ASCP/Client relaunch

414 #---------------------------------------------------------------------------

415 ASCP/Client public relaunch {{option ""}} {
416     MashLog info "RELAUNCH $self [$self service_location] [$self precondition]"
417     if {$option == ""} {
418             $self launch start
419     } else {
420         if {$option == "now"} {
421             set agent_id [$self request start -block]
422             set temp [$self precondition]
423             $self precondition "agentid:$agent_id"
424             $self launch_now start
425             $self precondition "$temp"
426         }
427     }
428 }
429 
430 #---------------------------------------------------------------------------

431 # Method:

432 #   ASCP/Client expire

433 #---------------------------------------------------------------------------

434 ASCP/Client public service_expire {} {
435 
436     MashLog info "$self service expired"
437 
438     $self instvar service_
439     delete $service_
440     unset service_
441 
442     $self instvar callback_
443     if {$callback_(expire) != ""} {
444         # Make a copy of current callbacks, because $cb might 

445         # append to $callback_($expire), causing infinite loop.

446         set expire_callbacks $callback_(expire)
447         foreach cb $expire_callbacks {
448             #MashLog info "$self service expired $cb"

449             eval $cb
450         }
451     } 
452     #MashLog info "$self service expired DONE"

453 }
454 
455 
456 #---------------------------------------------------------------------------

457 # Method:

458 #   ASCP/Client launch_now

459 # Description:

460 #   "launch start" starts the periodic timer that sends a launch message.

461 #   "launch stop" stop the timer.

462 #---------------------------------------------------------------------------

463 ASCP/Client public launch_now {option args} {
464     $self instvar timeout_
465     switch $option {
466         start {
467             set packet [new ASCPPacket]
468             $packet from_ascp "launch_now" $self
469             set str [$packet to_string]
470             delete $packet
471 
472             $self announce $str
473 
474             $self instvar launch_now_timer_
475             set launch_now_timer_ [new MashTimer/ConstBW \
476                 3000 "$self announce \{$str\}" [$self bandwidth]]
477 
478             if {[lsearch $args "-block"] != -1} {
479                     global recv_alive_from_
480                     set service_instance [$self service_instance]
481                     set recv_alive_from_($service_instance) 0
482                     after $timeout_ "
483                         set recv_alive_from_($service_instance) TIMEOUT
484                     "
485                     vwait recv_alive_from_($service_instance)
486                     if {$recv_alive_from_($service_instance) == "TIMEOUT"} {
487                         $self timeout
488                     }
489                     return $recv_alive_from_($service_instance)
490             } 
491         }
492         stop {
493             $self instvar launch_now_timer_
494             if {[info exists launch_now_timer_]} {
495                 delete $launch_now_timer_
496                 unset launch_now_timer_
497             }
498         }
499         default {
500             error "unknown request option: use start/stop"
501         }
502     }
503 }
504 
505 
506 #---------------------------------------------------------------------------

507 # Method:

508 #   ASCP/Client launch

509 # Description:

510 #   "launch start" starts the periodic timer that sends a launch message.

511 #   "launch stop" stop the timer.

512 #---------------------------------------------------------------------------

513 ASCP/Client public launch {option args} {
514     #MashLog info "Launch $option"

515     switch $option {
516         start {
517             set packet [new ASCPPacket]
518             $packet from_ascp "launch" $self
519             set str [$packet to_string]
520             delete $packet
521 
522             $self announce $str
523 
524             $self instvar launch_timer_
525             set launch_timer_ [new MashTimer/ConstBW \
526                 3000 "$self announce \{$str\}" [$self bandwidth]]
527 
528             if {[lsearch $args "-block"] != -1} {
529                     global recv_alive_from_
530                     set service_instance [$self service_instance]
531                     set recv_alive_from_($service_instance) 0
532                     $self instvar timeout_
533                     after $timeout_ "
534                         set recv_alive_from_($service_instance) TIMEOUT
535                     "
536                     vwait recv_alive_from_($service_instance)
537                     if {$recv_alive_from_($service_instance) == "TIMEOUT"} {
538                         $self timeout
539                     }
540                     return $recv_alive_from_($service_instance)
541             } 
542         } 
543         stop {
544             $self instvar launch_timer_
545             if {[info exists launch_timer_]} {
546                 delete $launch_timer_
547                 unset launch_timer_
548             }
549         }
550         default {
551             error "unknown request option: use start/stop"
552         }
553     }
554 }
555 
556 ASCP/Client public service_instance {}  {
557     return "[pid]@[info hostname]:$self"
558 }
559 
560 
561 ASCP/Client public served_by {}  {
562     $self instvar service_
563     if [info exists service_] {
564         return [$service_ get_value]
565     } else {
566         return ""
567     }
568 }
569 
570 
571 ASCP/Client public service_type {}  {
572     return "Generic"
573 }
574 #vim:ts=8:sw=4:expandtab

575 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.