1 # udpserver.tcl --
2 #
3 # FIXME: This file needs a description here.
4 #
5 # Copyright (c) 1996-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/net/udpserver.tcl,v 1.10 2002/02/03 04:28:06 lim Exp $
32
33
34 import UDPChannel
35
36 # UDPChannel that maintains list of unicast
37 # address/port pairs and optionally also a single mcast address/port;
38 # all are sent data when 'send' is called.
39 # It automatically times out addrs that haven't been refreshed in
40 # 'timeout_' seconds (if timeout_ == 0 they persist forever);
41 # the list can also be manually manipulated via
42 # 'addAddr' and 'rmAddr' and 'timeoutAddrs'
43 #
44 Class UDPServer -superclass UDPChannel
45
46 # spec indicates the port number to listen on; additionally,
47 # if spec is a multicast addr, it is used in addition to unicast addrs
48 # as a location to send 'announce' messages
49 #
50 UDPServer public init { {spec ""} {mtu 1024} } {
51 $self instvar replyToList_ mcastAddr_ port_ child_ timeout_
52
53 set timeout_ 60 ; # default timeout is 60 secs
54 set replyToList_ ""
55 set replyTimeList_ ""
56
57 if [regexp {^[0-9]*$} $spec] {
58 set port_ $spec
59 set addr ""
60 } else {
61 set port_ [lindex [split $spec "/"] 1]
62 set addr [lindex [split $spec "/"] 0]
63 # if spec includes a name, turn it into IP addr
64 set firstchar [string index $spec 0]
65 if [string match \[a-zA-Z\] $firstchar] {
66 set n [lindex [split $spec "/"] 0]
67 set s [gethostbyname $n]
68 if { $s == "" } {
69 puts "cannot find address for '$n'"
70 exit
71 }
72 set addr $s
73 }
74
75 }
76 # addressblocks only allow even ports -- emulate this
77 if {$port_ % 2 != 0} {
78 puts "WARNING: you specified an odd port: decrementing 1"
79 incr port_ -1
80 }
81
82 if {$addr != ""} {
83 if [in_multicast $addr] {
84 $self next $spec $mtu
85 set mcastAddr_ $addr/$port_
86 set child_ [new UDPServerChild $self $port_]
87 } else {
88 set mcastAddr_ -1
89 set child_ [new UDPServerChild $self $addr/$port_]
90 }
91 } else {
92 set mcastAddr_ -1
93 set child_ [new UDPServerChild $self $port_]
94 }
95
96 }
97
98 # add addr and/or refresh last update time
99 # for addrspec in replyToList_
100 UDPServer public addAddr {addrspec} {
101 $self instvar replyToList_ replyTimeList_
102
103 set l [lsearch $replyToList_ $addrspec]
104 if {$l == -1} {
105 lappend replyToList_ $addrspec
106 lappend replyTimeList_ [clock seconds]
107 } else {
108 set replyTimeList_ [lreplace $replyTimeList_ $l $l [clock seconds]]
109 }
110 }
111
112 # remove addr from replyTo list
113 UDPServer public rmAddr {addrspec} {
114 $self instvar replyToList_ replyTimeList_
115
116 set loc [lsearch $replyToList_ $addrspec]
117 if {$loc != -1} {
118 set replyToList_ [lreplace $replyToList_ $loc $loc]
119 set replyTimeList_ [lreplace $replyTimeList_ $loc $loc]
120 } else {
121 puts "UDPServer: Tried to remove addr not in reply list: `$addrspec'"
122 }
123 }
124
125 # remove any addr not updated in last <em>timeout</em> seconds
126 #
127 UDPServer public timeoutAddrs {timeout} {
128 $self instvar replyToList_ replyTimeList_
129
130 if {$replyToList_ == ""} {return}
131 set t [clock seconds]
132 if {[llength $replyToList_] != [llength $replyTimeList_]} {
133 puts "Error: reply lists lengths are different! \
134 [llength $replyToList_] != [llength $replyTimeList_]"
135 }
136 set cnt 0
137 foreach i $replyTimeList_ {
138 if {[expr $t - $i] > $timeout} {
139 $self rmAddr [lindex $replyToList_ $cnt]
140 }
141 incr cnt
142 }
143 }
144
145 # send <em>data</em> to everyone
146 #
147 UDPServer public announce {data} {
148 $self instvar replyToList_ mcastAddr_ port_ timeout_
149
150 if {$timeout_ > 0} {
151 $self timeoutAddrs $timeout_
152 }
153
154 foreach i $replyToList_ {
155 #puts "$i: $data"
156 set sender [new UDPChannel $i]
157 $sender send "$data"
158 delete $sender
159 after 50
160 }
161 if {$mcastAddr_ != -1} {
162 $self send "$data"
163 }
164
165 # FIXME backward compatability: for clients that listen on the port
166 # number they send to (i.e., well-known rather than ephemeral)
167 regsub -all "/" "$replyToList_" " " tmp
168 array set addrsOnly $tmp
169 foreach i [array names addrsOnly] {
170 set sender [new UDPChannel $i/$port_]
171 $sender send "$data"
172 delete $sender
173 }
174 }
175
176 # set new timeout value
177 UDPServer public timeout {t} {
178 $self instvar timeout_
179 set timeout_ $t
180 }
181
182 # Receive Stub: should be extended by subclasses
183 UDPServer private recv {addr port data len} {
184 puts "Msg from $addr/$port \[$len\]: $data"
185 }
186
187
188 # -----------
189
190 # UDPServerChild is a UDPServer helper class: it simply monitors a
191 # unicast address and passes along received packets to the parent
192 # after adding the addresses to the replyTo list
193 Class UDPServerChild -superclass UDPChannel
194
195 #
196 UDPServerChild instproc init {parent spec {mtu 1024}} {
197 #puts "listening to unicast $spec"
198 $self next $spec $mtu
199 $self instvar parent_
200 set parent_ $parent
201 }
202
203 #
204 UDPServerChild instproc recv {addr port data size} {
205 #puts "UDPServerChild::recv"
206 $self instvar parent_
207 $parent_ addAddr $addr/$port
208 $parent_ recv $addr $port "$data" $size
209 }
210
211
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.