view tools/python-PE/CompactRouting/CompactRouting2.py @ 67:264123227f0d

large tuple case (suggestion)
author one
date Sat, 06 Jun 2009 14:33:59 +0900
parents 6c40056777be
children
line wrap: on
line source

import string
import struct

import xml.dom.minidom
import FederatedLinda
import LinkConfiguration


TUPLE_ID_LINKCONFIG = 1
TUPLE_ID_ROUTING = 2

ROUTING_HEADER_FORMAT = "!I"

ROUTING_COMMAND_CONNECT      =  1
ROUTING_COMMAND_DISCONNECT   =  2
ROUTING_COMMAND_TRANSFER     =  3
ROUTING_COMMAND_UPDATE_TABLE =  4

LANDMARKHOPNUM = 2

class TSInfo:
    def __init__(self, tsid, hopnum, ttl, nexthop):
        self.tsid = tsid        # tuple space id, like 'host:port'
        self.hopnum = hopnum    # hop number
        self.ttl = ttl          #
        self.nexthop = nexthop  # next hop (tuple space id)


""" XML format is as follows
<RoutingTable name="localhost:10000">
  <ts hopnum="1" tsid="localhost:10002" ttl="0"/>
  <ts hopnum="1" tsid="localhost:10001" ttl="256"/>
  <ts hopnum="0" tsid="localhost:10000" ttl="0"/>
</RoutingTable>
"""
class RoutingTable:
    def __init__(self, name):
        self.tslist = {}
        self.name = name

    def register(self, tsid, hopnum, ttl, nexthop):
        if (self.tslist.has_key(tsid)):
            del self.tslist[tsid]
        self.tslist[tsid] = TSInfo(tsid, hopnum, ttl, nexthop)

    def deregister(self, tsid):
        for t in self.tslist.keys():
            if self.tslist[t].nexthop == tsid:
                del self.tslist[t]

    def update(self, xmldoc, ts):
        rt = xml.dom.minidom.parseString(xmldoc).childNodes[0]
        tslist = rt.childNodes
        updateflag = False

        tmplist = []

        # append tuplespace
        for t in tslist:
            if t.nodeType == t.ELEMENT_NODE and t.localName == 'ts':
                tsattr  = t.attributes
                tsid    = tsattr['tsid'].nodeValue
                hopnum  = int( tsattr['hopnum'].nodeValue )
                ttl     = int( tsattr['ttl'].nodeValue )
                nexthop = ts

                tmplist.append(tsid)
                
                if ((not self.tslist.has_key(tsid)) or
                    (self.tslist[tsid].hopnum > hopnum+1)):
                    self.register(tsid, hopnum+1, ttl, nexthop)
                    updateflag = True
                
        # delete tuplespace
        for t in self.tslist.values():
            if ( not t.tsid in tmplist ):
                updateflag = True
                if (t.nexthop == ts):
                    del self.tslist[t.tsid]

        return updateflag

    def getxmldoc(self):
        doc = xml.dom.minidom.Document()
        rt = doc.createElement('RoutingTable')
        rt.setAttribute('name', self.name)
        for tskey in self.tslist.keys():
            elem = doc.createElement('ts')
            elem.setAttribute('tsid', self.tslist[tskey].tsid)
            elem.setAttribute('hopnum', str(self.tslist[tskey].hopnum))
            elem.setAttribute('ttl', str(self.tslist[tskey].ttl))
            rt.appendChild(elem)

        return rt
    
    def getxml(self):
        rt = self.getxmldoc()
        return rt.toxml()

    def printxml(self):
        rt = self.getxmldoc()
        print rt.toprettyxml()

    def getdstname(self, xmltext):
        rt = xml.dom.minidom.parseString(xmltext).childNodes[0]
        return rt.attributes['name'].nodeValue

class Routing:
    def __init__(self, headerFormat = ROUTING_HEADER_FORMAT):
        self.flinda = FederatedLinda.FederatedLinda()
        self.linda = None
        self.tsid = None
        self.neighbors = {}    # key is tsid ("host:port"),  value is Linda object
        self.headerFormat = headerFormat # struct.pack's format
        self.rt = None

    def __del__(self):
        self.linda.close()
        for ts in self.neighbors.values():
            ts.close()

    def connect(self, tsid):
        host, port = string.split(tsid, ':', 1)
        ts = self.flinda.open(host, int(port))
        if not ts:
            return None

        ts.getid()
        self.addNeighbor(ts, tsid)

        return ts

    def disconnect(self, tsid):
        if ( self.neighbors.has_key(tsid) ):
             self.delNeighbor(tsid)

    def addNeighbor(self, ts, tsid):
        self.neighbors[tsid] = ts
        return ts

    def delNeighbor(self, tsid):
        del self.neighbors[tsid]

    def pack(self, data, cmd):
        return struct.pack(self.headerFormat, cmd) + data

    def unpack(self, packet):
        r = struct.unpack(self.headerFormat + str(len(packet)-struct.calcsize(self.headerFormat)) +"s", packet)
        return r

    def LinkConfig(self, mytsid, packet):
	self.tsid = mytsid
	lcparser = LinkConfiguration.LinkConfigParser()
	linkConfig = lcparser.parseLinkConfig(self.tsid, packet)
	mydstlist = linkConfig.getDstlist(linkConfig.label)

	for n in mydstlist:
	    tsid = linkConfig.linklist[n].tsid
	    if ( tsid and not self.neighbors.has_key(tsid) ):
		ts = self.connect(tsid)
		ts.Out(TUPLE_ID_LINKCONFIG, packet)
		ts.Out(TUPLE_ID_ROUTING, self.pack(self.tsid, ROUTING_COMMAND_CONNECT))	    
	pass

    def RoutingConnect(self, data):
	print "connect"
	if ( not self.neighbors.has_key(data) ):
	    ts = self.connect(data)
	    ts.Out(TUPLE_ID_ROUTING, self.pack(self.tsid, ROUTING_COMMAND_CONNECT))	    
	    
	self.rt.register(data, 1, LANDMARKHOPNUM, data)
	upedxml = self.rt.getxml()
#	print "Gen XML ",upedxml
#	print "Neighbors ",self.neighbors
	for nts in self.neighbors.values():
	    nts.Out(TUPLE_ID_ROUTING, self.pack(upedxml, ROUTING_COMMAND_UPDATE_TABLE))	
	pass

    def RoutingDisconnect(self, data):
	print "disconnect"
	if ( self.neighbors.has_key(data) ):
	    ts = self.neighbors[data]
	    ts.Out(TUPLE_ID_ROUTING, self.pack(self.tsid, ROUTING_COMMAND_DISCONNECT))
	    self.disconnect(data)

	    self.rt.deregister(data)
	    upedxml = self.rt.getxml()
	    for nts in self.neighbors.values():
		nts.Out(TUPLE_ID_ROUTING, self.pack(upedxml, ROUTING_COMMAND_UPDATE_TABLE))
	pass
    
    def RoutingTransfer(self, data):
	#print "transfer"
	# ReplyTuple is "DstTSID,TupleID,SrcTSID,DATA"
	# Src/DstTSID is "hostname:portnum"

	dsttsid, tid, srctsid, pdata = string.split(data,',',3)
	print "transfer tuple:"
	print "dsttsid=>",dsttsid, "tid=>",tid, "srctsid=>",srctsid, "data=>",pdata
	if ( dsttsid == self.rt.name ):
	    self.linda.Out(int(tid), data)
	else:
	    dstts = self.neighbors[self.rt.tslist[dsttsid].nexthop]
	    dstts.Out(TUPLE_ID_ROUTING, self.pack(data, ROUTING_COMMAND_TRANSFER))
	pass
    
    def RoutingTableUpdate(self, data):
	print "update"
	srcname = self.rt.getdstname(data)

	if ( self.rt.update(data, srcname) ):
	    # Send Update Info to Neighbors
	    upedxml = self.rt.getxml()
	    
	    for n in self.neighbors.values():
		n.Out(TUPLE_ID_ROUTING, self.pack(upedxml, ROUTING_COMMAND_UPDATE_TABLE))
	    
	pass

    def run(self, mytsid):
        self.tsid = mytsid
        hostname, port = string.split(mytsid, ':', 1)
        self.linda = self.flinda.open(hostname, int(port))
        if not self.linda:
            return
        
        self.rt = RoutingTable(mytsid)
        self.rt.register(self.rt.name, 0, 0, None)

        self.linda.getid() # get client id from Tuple Space (ldserv)

        linkConfigReply = self.linda.In(TUPLE_ID_LINKCONFIG)
        routingReply = self.linda.In(TUPLE_ID_ROUTING)

        self.flinda.sync()

        while (True):
            # Link Configuration
            rep = linkConfigReply.reply()
            if (rep):
                linkConfigReply = self.linda.In(TUPLE_ID_LINKCONFIG)

		# Link Configuration main
		self.LinkConfig(self.tsid, rep)

            # Routing Protocol
            rep = routingReply.reply()
            if (rep):
                routingReply = self.linda.In(TUPLE_ID_ROUTING)
                cmd , data = self.unpack(rep)

                # connect to other tuplespace
                if (cmd == ROUTING_COMMAND_CONNECT):
		    # connect main
		    self.RoutingConnect(data)
		
                # disconnect other tuplespace
		elif (cmd == ROUTING_COMMAND_DISCONNECT):
		    # disconnect main
		    self.RoutingDisconnect(data)

                # transfer tuple
                elif (cmd == ROUTING_COMMAND_TRANSFER):
		    # transfer main
		    self.RoutingTransfer(data)

                # update own routing table
                elif (cmd == ROUTING_COMMAND_UPDATE_TABLE):
		    #routing table main
		    self.RoutingTableUpdate(data)
                else:
                    pass

                print self.rt.printxml()

            self.flinda.sync()
        # end while

if __name__ == '__main__':
    import sys
    if (len(sys.argv) != 2) :
        print "Usage : %s <hostname:portnum>" % sys.argv[0]
        sys.exit(1)

    mytsid = sys.argv[1]

    routing = Routing()
    routing.run(mytsid)