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

Open Mash Cross Reference
mash/tcl/dc/common/dc-link.tcl

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

  1 # dc-link.tcl --
  2 #
  3 #       Contains CLink and CLinkManager, basic building blocks of DC
  4 #       Service Discovery Service.
  5 #
  6 # Copyright (c) 2000-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 Class CLinkManager
 33 #-----------------------------------------------------------------------------
 34 #
 35 # Class CLinkManager
 36 #
 37 # Purpose:
 38 #   Maintains a list of links between self and remote processes.
 39 # Members:
 40 #   m_socketServer - server socket of self
 41 #   m_lLink - a list of CLink objects
 42 #   m_lAttach - a list of class attached to this object so that 
 43 #               they can receive notification whenever a new connection
 44 #               arrive.  (Can't we use the Observable/Observer pattern?)
 45 #
 46 #-----------------------------------------------------------------------------
 47 
 48 
 49 #-----------------------------------------------------------------------------
 50 #
 51 # CLinkManager constructor
 52 #
 53 # Input:
 54 #   iPort - port to listen to for connection request
 55 #
 56 # Description:
 57 #   Creates a socket and listen to client's request.  Initialize members
 58 #   to empty.
 59 #
 60 #-----------------------------------------------------------------------------
 61 CLinkManager public init { iPort }  {
 62     $self instvar m_socketServer
 63     $self instvar m_lLink
 64 
 65     set m_lLink ""
 66 
 67     if {[catch {socket -server "$self NewConnection" $iPort} m_socketServer]} {
 68         return -code error "LinkManager: Couldn't create server socket" 
 69     }
 70 }
 71 
 72 
 73 #-----------------------------------------------------------------------------
 74 #
 75 # CLinkManager destructor
 76 #
 77 # Input:
 78 #   none
 79 #
 80 # Description:
 81 #   close the server, and delete each links
 82 #
 83 #-----------------------------------------------------------------------------
 84 CLinkManager public destroy { } {
 85     $self instvar m_socketServer
 86     $self instvar m_lLink
 87 
 88     if {[catch {close $m_socketServer} err]} {
 89         puts "CLinkManager: Unable to close socket."
 90     }
 91 
 92     if {$m_lLink != ""} {
 93         foreach link $m_lLink {
 94             delete $link
 95         }
 96     }
 97 }
 98 
 99 CLinkManager public Attach { objAttach } {
100     $self instvar m_lAttach
101 
102     lappend m_lAttach $objAttach
103 }
104 
105 
106 #-----------------------------------------------------------------------------
107 #
108 # CLinkManager NewConnection
109 #
110 # Input:
111 #   newSocket, inetAddr, iPort - socket, address and port number of 
112 #   the new connection.
113 #
114 # Description:
115 #   This is the callback that is executed when a client connects to 
116 #   this server.
117 #
118 #-----------------------------------------------------------------------------
119 CLinkManager private NewConnection { newSocket inetAddr iPort } {
120     $self instvar m_lLink m_lAttach
121 
122     # create the new link with the socket
123     set link [new CLink $newSocket $inetAddr $iPort]
124     foreach a $m_lAttach {
125         set result [$a NewConnection $link]
126         if {$result != 0} {
127             break
128         }
129     }
130 
131     # stick it into a list so that we can cleanup afterwards
132     lappend m_lLink $link
133 }
134 
135 #-----------------------------------------------------------------------------
136 #
137 #    I don't think NewLink is called anywhere.. - weitsang
138 #
139 #-----------------------------------------------------------------------------
140 #CLinkManager instproc NewLink { inetRemoteAddr iRemotePort } {
141 #    set sock [socket $inetRemoteAddr $iRemotePort]
142 #
143 #    if { $sock <= 0 } {
144 #       puts "CLinkManager: NewLink couldn't connect socket to host"
145 #       return 0
146 #    }
147 #
148 #    set link [new CLink $sock $inetRemoteAddr $iRemotePort]
149 #
150 #    return $link
151 #}
152 
153 #-----------------------------------------------------------------------------
154 #
155 # CLinkManager GetSpec
156 #
157 # Description:
158 #   Returns a textual information about the current socket.  Return
159 #   string starts with the local address and is followed by socket 
160 #   information.
161 #
162 #-----------------------------------------------------------------------------
163 CLinkManager instproc GetSpec {} {
164     $self instvar m_socketServer
165 
166     if {[catch {fconfigure $m_socketServer -sockname} socketInfo]} {
167         return "[localaddr]: no socket info"
168     }
169     return "[localaddr] [lindex $socketInfo 2]"
170 }
171 
172 
173 #-----------------------------------------------------------------------------
174 #
175 # Class CLink 
176 #
177 #   CLink provides an abstraction for a connection between the client 
178 #   and a service.
179 # 
180 #   Members-
181 #     m_socket - socket for this connection
182 #     m_aMessageMap - an array of object/methods pair indexed by 
183 #                     messages. When a message is received, the 
184 #                     corresponding method is executed.
185 #     m_bufferRead  - buffer of messages for reading
186 #
187 #-----------------------------------------------------------------------------
188 Class CLink
189 
190 
191 #-----------------------------------------------------------------------------
192 #
193 # CLink constructor
194 #
195 # Input:
196 #   socket - socket for this connection
197 #
198 #-----------------------------------------------------------------------------
199 CLink private init { sock } {
200     $self instvar m_socket
201     $self instvar m_aMessageMap
202     $self instvar m_bufferRead
203 
204     set m_bufferRead ""
205 
206     set m_socket $sock
207 
208     # set the socket to be non-blocking
209     if {[catch {fconfigure $m_socket -blocking 0}]} {
210         puts "CLink: Unable to configure socket"
211         return
212     }
213 
214     # handle the event when the socket has something to read
215     if {[catch {fileevent $m_socket readable "$self Receive"}]} {
216         puts "CLink: fileevent readable failed"
217     }
218 }
219 
220 
221 #-----------------------------------------------------------------------------
222 #
223 # CLink destructor
224 #
225 # Purpose:
226 #   close the socket association with this link
227 #
228 #-----------------------------------------------------------------------------
229 CLink public destroy { } {
230     $self CloseLink
231 }
232 
233 
234 #-----------------------------------------------------------------------------
235 #
236 # CLink MapMessage
237 #
238 # Input:
239 #   strMessage, obj, fnMethod
240 # 
241 # Purpose:
242 #   Add the method $fnMethod of object $obj to the list of callbacks to
243 #   run when the message $strMessage is received.
244 #
245 #-----------------------------------------------------------------------------
246 CLink public MapMessage { strMessage obj fnMethod } {
247     $self instvar m_aMessageMap
248 
249     # the the current list of
250     if { ![info exist m_aMessageMap($strMessage)] } {
251         set m_aMessageMap($strMessage) ""
252     } 
253 
254     # now add the new map in
255     append m_aMessageMap($strMessage) " " [concat $obj $fnMethod]
256 }
257 
258 
259 #-----------------------------------------------------------------------------
260 #
261 # CLink UnmapMessage
262 #
263 # Input:
264 #   strMessage, obj, fnMethod
265 # 
266 # Purpose:
267 #   Remove the method $fnMethod of object $obj from the list of callbacks to
268 #   run when the message $strMessage is received.
269 #
270 #-----------------------------------------------------------------------------
271 CLink public UnmapMessage { strMessage obj fnMethod } {
272     $self instvar m_aMessageMap
273 
274     if { [info exist m_aMessageMap($strMessage)] } {
275         set map $m_aMessageMap($strMessage)
276     } else {
277         return
278     }
279 
280     # now the delete map in the map
281     set newMap ""
282     foreach { objMap fnMethodMap } $map {
283         if { $objMap != $obj || $fnMethodMap != $fnMethod } {
284             lappend newMap $objMap $fnMethod
285         }
286     }
287 
288     set m_aMessageMap($strMessage) $newMap
289 }
290 
291 
292 #-----------------------------------------------------------------------------
293 #
294 # CLink SocketRead
295 #
296 # Purpose:
297 #   Fileevent readable callback for the connection to the service.   
298 #
299 #-----------------------------------------------------------------------------
300 CLink private Receive { } {
301     $self instvar m_socket
302     $self instvar m_bufferRead
303 
304     # check that the socket is ok
305     if { [catch {eof $m_socket} status] } {
306         puts "CLink: Unable to check socket's status, closing all links."
307         $self CloseLink
308         return
309     }
310     if {$status == 1} {
311         $self CloseLink
312         return
313     }
314 
315     if {[catch {gets $m_socket line} n]} { 
316         # If we get an exception reading from the socket,
317         # reset and give up
318         puts "CLink: Unable to read a line from socket"
319         return
320     }
321     while { $n > 0 } {
322         # check if the line is the end of message signal
323         if { $line == "__END_OF_MESSAGE" } {
324             # if so then process the buffer
325             $self ProcessMessage $m_bufferRead
326             set m_bufferRead ""
327         } else {
328             # else it's part of a message to add it to the read buffer
329             set m_bufferRead "$m_bufferRead \n$line"
330         }
331         # read the next line
332         if {[catch {gets $m_socket line} n]} { 
333             # If we get an exception reading from the socket,
334             # reset and give up
335             puts "CLink: Unable to read a line from socket. Giving up."
336             set m_bufferRead ""
337             return
338         }
339     }
340 }
341 
342 CLink private ProcessMessage { cmd } {
343     $self instvar m_aMessageMap
344 
345     # get the first word of the cmd and use the message map to see who
346     # to send it to
347 
348     set message [lindex $cmd 0]
349     set arguments [lrange $cmd 1 end]
350 
351     # if the message isn't mapped then just return
352     if { ![info exists m_aMessageMap($message)] } {
353         return 0
354     }
355 
356     set lInvoke $m_aMessageMap($message)
357     foreach { obj fnMethod } $lInvoke {
358         eval "$obj $fnMethod $self $arguments"
359     }
360 }
361 
362 CLink public Send { message args } {
363     $self instvar m_socket
364 
365     # for now just block on write
366     if {[catch {puts $m_socket "$message $args \n__END_OF_MESSAGE"} err]} {
367         puts "CLink: Unable to write to socket"
368     }
369     if {[catch {flush $m_socket} err]} {
370         puts "CLink: Unable to flush socket"
371     }   
372 }
373 
374 
375 CLink public CloseLink { } {
376     $self instvar m_socket
377 
378     if {[catch {close $m_socket} err]} {
379         puts "CLink: Unable to close socket"
380     }
381 
382     # notify the user that we've closed the socket
383     $self ProcessMessage {CLOSE_LINK {}}
384 }
385 

~ [ 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.