comparison tools/python-PE/CompactRouting/Routing.py @ 8:6c40056777be

Initial revision
author fuchita
date Sat, 16 Feb 2008 13:18:02 +0900
parents
children
comparison
equal deleted inserted replaced
7:1809e2b05824 8:6c40056777be
1 import string
2 import struct
3 import time
4
5 import xml.dom.minidom
6 import FederatedLinda
7 import LinkConfiguration
8
9 TUPLE_ID_LINKCONFIG = 1
10 TUPLE_ID_ROUTING = 2
11
12 ROUTING_HEADER_FORMAT = "!I"
13
14 ROUTING_COMMAND_CONNECT = 1
15 ROUTING_COMMAND_DISCONNECT = 2
16 ROUTING_COMMAND_TRANSFER = 3
17 ROUTING_COMMAND_UPDATE_TABLE = 4
18
19 class TSInfo:
20 def __init__(self, tsid, hopnum, ttl, nexthop):
21 self.tsid = tsid # tuple space id, like 'host:port'
22 self.hopnum = hopnum # hop number
23 self.ttl = ttl #
24 self.nexthop = nexthop # next hop (tuple space id)
25
26
27 """ XML format is as follows
28 <RoutingTable name="localhost:10000">
29 <ts hopnum="1" tsid="localhost:10002" ttl="0"/>
30 <ts hopnum="1" tsid="localhost:10001" ttl="256"/>
31 <ts hopnum="0" tsid="localhost:10000" ttl="0"/>
32 </RoutingTable>
33 """
34 class RoutingTable:
35 def __init__(self, name):
36 self.tslist = {}
37 self.name = name
38
39 def register(self, tsid, hopnum, ttl, nexthop):
40 if (self.tslist.has_key(tsid)):
41 del self.tslist[tsid]
42 self.tslist[tsid] = TSInfo(tsid, hopnum, ttl, nexthop)
43
44 def deregister(self, tsid):
45 for t in self.tslist.keys():
46 if self.tslist[t].nexthop == tsid:
47 del self.tslist[t]
48
49 def update(self, xmldoc, ts):
50 rt = xml.dom.minidom.parseString(xmldoc).childNodes[0]
51 tslist = rt.childNodes
52 updateflag = False
53
54 tmplist = []
55
56 # append tuplespace
57 for t in tslist:
58 if t.nodeType == t.ELEMENT_NODE and t.localName == 'ts':
59 tsattr = t.attributes
60 tsid = tsattr['tsid'].nodeValue
61 hopnum = int( tsattr['hopnum'].nodeValue )
62 ttl = int( tsattr['ttl'].nodeValue )
63 nexthop = ts
64
65 tmplist.append(tsid)
66
67 if ((not self.tslist.has_key(tsid)) or
68 (self.tslist[tsid].hopnum > hopnum+1)):
69 self.register(tsid, hopnum+1, ttl, nexthop)
70 updateflag = True
71
72 # delete tuplespace
73 for t in self.tslist.values():
74 if ( not t.tsid in tmplist ):
75 updateflag = True
76 if (t.nexthop == ts):
77 del self.tslist[t.tsid]
78
79 return updateflag
80
81 def getxmldoc(self):
82 doc = xml.dom.minidom.Document()
83 rt = doc.createElement('RoutingTable')
84 rt.setAttribute('name', self.name)
85 for tskey in self.tslist.keys():
86 elem = doc.createElement('ts')
87 elem.setAttribute('tsid', self.tslist[tskey].tsid)
88 elem.setAttribute('hopnum', str(self.tslist[tskey].hopnum))
89 elem.setAttribute('ttl', str(self.tslist[tskey].ttl))
90 rt.appendChild(elem)
91
92 return rt
93
94 def getxml(self):
95 rt = self.getxmldoc()
96 return rt.toxml()
97
98 def printxml(self):
99 rt = self.getxmldoc()
100 print rt.toprettyxml()
101 end = time.time()
102 print "passed time ",end
103
104 def getdstname(self, xmltext):
105 rt = xml.dom.minidom.parseString(xmltext).childNodes[0]
106 return rt.attributes['name'].nodeValue
107
108 class Routing:
109 def __init__(self, headerFormat = ROUTING_HEADER_FORMAT):
110 self.flinda = FederatedLinda.FederatedLinda()
111 self.linda = None
112 self.tsid = None
113 self.neighbors = {} # key is tsid ("host:port"), value is Linda object
114 self.headerFormat = headerFormat # struct.pack's format
115 self.rt = None
116
117 def __del__(self):
118 self.linda.close()
119 for ts in self.neighbors.values():
120 ts.close()
121
122 def connect(self, tsid):
123 host, port = string.split(tsid, ':', 1)
124 ts = self.flinda.open(host, int(port))
125 if not ts:
126 return None
127
128 ts.getid()
129 self.addNeighbor(ts, tsid)
130
131 return ts
132
133 def disconnect(self, tsid):
134 if ( self.neighbors.has_key(tsid) ):
135 self.delNeighbor(tsid)
136
137 def addNeighbor(self, ts, tsid):
138 self.neighbors[tsid] = ts
139 return ts
140
141 def delNeighbor(self, tsid):
142 del self.neighbors[tsid]
143
144 def pack(self, data, cmd):
145 return struct.pack(self.headerFormat, cmd) + data
146
147 def unpack(self, packet):
148 r = struct.unpack(self.headerFormat +
149 str(len(packet)-struct.calcsize(self.headerFormat)) +
150 "s", packet)
151 return r
152
153 def LinkConfig(self, mytsid, packet):
154 self.tsid = mytsid
155 lcparser = LinkConfiguration.LinkConfigParser()
156 linkConfig = lcparser.parseLinkConfig(self.tsid, packet)
157 mydstlist = linkConfig.getDstlist(linkConfig.label)
158
159 for n in mydstlist:
160 tsid = linkConfig.linklist[n].tsid
161 if ( tsid and not self.neighbors.has_key(tsid) ):
162 ts = self.connect(tsid)
163 ts.Out(TUPLE_ID_LINKCONFIG, packet)
164 ts.Out(TUPLE_ID_ROUTING, self.pack(self.tsid, ROUTING_COMMAND_CONNECT))
165 pass
166
167 def RoutingConnect(self, data):
168 print "connect"
169 if ( not self.neighbors.has_key(data) ):
170 ts = self.connect(data)
171 ts.Out(TUPLE_ID_ROUTING, self.pack(self.tsid, ROUTING_COMMAND_CONNECT))
172
173 self.rt.register(data, 1, 16, data)
174 upedxml = self.rt.getxml()
175 # print "Gen XML ",upedxml
176 # print "Neighbors ",self.neighbors
177 for nts in self.neighbors.values():
178 nts.Out(TUPLE_ID_ROUTING, self.pack(upedxml, ROUTING_COMMAND_UPDATE_TABLE))
179 pass
180
181 def RoutingDisconnect(self, data):
182 print "disconnect"
183 if ( self.neighbors.has_key(data) ):
184 ts = self.neighbors[data]
185 ts.Out(TUPLE_ID_ROUTING, self.pack(self.tsid, ROUTING_COMMAND_DISCONNECT))
186 self.disconnect(data)
187
188 self.rt.deregister(data)
189 upedxml = self.rt.getxml()
190 for nts in self.neighbors.values():
191 nts.Out(TUPLE_ID_ROUTING, self.pack(upedxml, ROUTING_COMMAND_UPDATE_TABLE))
192 pass
193
194 def RoutingTransfer(self, data):
195 #print "transfer"
196 # ReplyTuple is "DstTSID,TupleID,SrcTSID,DATA"
197 # Src/DstTSID is "hostname:portnum"
198
199 dsttsid, tid, srctsid, pdata = string.split(data,',',3)
200 print "transfer tuple:"
201 print "dsttsid=>",dsttsid, "tid=>",tid, "srctsid=>",srctsid, "data=>",pdata
202 if ( dsttsid == self.rt.name ):
203 self.linda.Out(int(tid), data)
204 else:
205 dstts = self.neighbors[self.rt.tslist[dsttsid].nexthop]
206 dstts.Out(TUPLE_ID_ROUTING, self.pack(data, ROUTING_COMMAND_TRANSFER))
207 pass
208
209 def RoutingTableUpdate(self, data):
210 print "update"
211 srcname = self.rt.getdstname(data)
212
213 if ( self.rt.update(data, srcname) ):
214 # Send Update Info to Neighbors
215 upedxml = self.rt.getxml()
216 for n in self.neighbors.values():
217 n.Out(TUPLE_ID_ROUTING, self.pack(upedxml, ROUTING_COMMAND_UPDATE_TABLE))
218
219 pass
220
221 def run(self, mytsid):
222 self.tsid = mytsid
223 hostname, port = string.split(mytsid, ':', 1)
224 self.linda = self.flinda.open(hostname, int(port))
225 if not self.linda:
226 return
227
228 self.rt = RoutingTable(mytsid)
229 self.rt.register(self.rt.name, 0, 0, None)
230
231 self.linda.getid() # get client id from Tuple Space (ldserv)
232
233 linkConfigReply = self.linda.In(TUPLE_ID_LINKCONFIG)
234 routingReply = self.linda.In(TUPLE_ID_ROUTING)
235
236 self.flinda.sync()
237
238 while (True):
239 # Link Configuration
240 rep = linkConfigReply.reply()
241 if (rep):
242 linkConfigReply = self.linda.In(TUPLE_ID_LINKCONFIG)
243
244 # Link Configuration main
245 self.LinkConfig(self.tsid, rep)
246
247 # Routing Protocol
248 rep = routingReply.reply()
249 if (rep):
250 routingReply = self.linda.In(TUPLE_ID_ROUTING)
251 cmd , data = self.unpack(rep)
252
253 # connect to other tuplespace
254 if (cmd == ROUTING_COMMAND_CONNECT):
255 # connect main
256 self.RoutingConnect(data)
257
258 # disconnect other tuplespace
259 elif (cmd == ROUTING_COMMAND_DISCONNECT):
260 # disconnect main
261 self.RoutingDisconnect(data)
262
263 # transfer tuple
264 elif (cmd == ROUTING_COMMAND_TRANSFER):
265 # transfer main
266 self.RoutingTransfer(data)
267
268 # update own routing table
269 elif (cmd == ROUTING_COMMAND_UPDATE_TABLE):
270 #routing table main
271 self.RoutingTableUpdate(data)
272 else:
273 pass
274
275 print self.rt.printxml()
276
277 self.flinda.sync()
278 # end while
279
280 if __name__ == '__main__':
281 import sys
282 if (len(sys.argv) != 2) :
283 print "Usage : %s <hostname:portnum>" % sys.argv[0]
284 sys.exit(1)
285
286 mytsid = sys.argv[1]
287
288 routing = Routing()
289 routing.run(mytsid)
290