def __init__(self, masterHost='127.0.0.1', baseport=10000, ownIdentifier='x', autoEnter=True): self.__debugOut = DebugOut() self.__applicationList = [] self.__sendDelay = 0 self.__layerDelay = 0 self.__layerPhy = LayerPhy.LayerPhy( ownIdentifier, upperLayerCallbackFunction=self.layer2_incomingPDU, masterHost=masterHost, baseport=baseport, autoEnter=autoEnter) # You may want to change the following part self.__ownIdentifier = ownIdentifier self.outgoingPacketStack = [] self.outgoingPacketStackLock = threading.Lock() #SN TB ETAPE DE L'INITIALISATION DU TOKEN self.initToken = 2 #SN TB compteur -> compteur pour le nombre de slot (couche 2) self.compteur = 2 self.indice = 0 self.paquetRecu = "" self.paquetAEnvoyer = "".encode("UTF-8")
def __init__(self, ownIdentifier, upperLayerCallbackFunction, masterHost='127.0.0.1', baseport=10000, autoEnter=True): ''' Constructor ''' self.__ownIdentifier = ownIdentifier self.__masterHost = masterHost self.__controlPort = baseport - 1 self.__interfaceSendPort = [0, 0] self.__interfaceRecvPort = [0, 0] self.__incomingTcpServer = [None, None] self.__outgoingTcpClient = [None, None] self.__callLinkLayer = upperLayerCallbackFunction self.__debugOut = DebugOut() self.__openControl_connection() if autoEnter: self.API_enter()
def __init__(self, ownIdentifier, masterHost='127.0.0.1', baseport=10000, statusUpdateSeconds=1, autoEnter=True, networkStackNumber=0): self.__ownIdentifier = ownIdentifier self.__masterHost = masterHost self.__baseport = baseport self.__statusUpdateSeconds = statusUpdateSeconds self.__autoEnter = autoEnter self.__networkStackNumber = networkStackNumber if networkStackNumber == 0: self.__networkstack = NetworkStack(self.__masterHost, self.__baseport, ownIdentifier, autoEnter) elif networkStackNumber == 1: self.__networkstack = NetworkStackAlternative( self.__masterHost, self.__baseport, ownIdentifier, autoEnter) self.__appMessageList = [] self.__debugOut = DebugOut() if self.__autoEnter: self.startComputer()
def __init__(self, phyNetwork, ownIdentifier): self.__ownIdentifier = ownIdentifier self.__host = '' # We are listening on any incoming connection self.__phyNetwork = phyNetwork self.__receivedMessage = threading.Condition() self.__debugOut = DebugOut(phyNetwork) self.__globalDebugHistory = [] self.__debugSubscribers = [] self.active = False self.__commandlist = [] try: self.__masterServer = TCPServer( host=self.__host, port=self.__phyNetwork.baseport - 1, callBackReceive=self.__masterListen, callBackConnect=self.__masterConnect, callBackHandleSocketError=self.__masterSocketError) self.active = True except: self.__debugOut.debugOutLayer( self.__ownIdentifier, 1, self.__debugOut.INFO, "PhyMaster : Master Server seems to be already running") if self.active: # This is the serialized dispatch thread self.__dispatchThread = threading.Thread( target=self.__dispatchCommands) self.__dispatchThread.start()
def __init__(self, masterHost='127.0.0.1', baseport=10000, ownIdentifier='x', autoEnter=True): self.__debugOut=DebugOut() self.__applicationList=[] self.__sendDelay=0 self.__layerDelay=0 self.__layerPhy=LayerPhy.LayerPhy(ownIdentifier, upperLayerCallbackFunction=self.layerT1_incomingPDU, masterHost=masterHost, baseport=baseport, autoEnter=autoEnter) # You may want to change the following part self.AppSend=0 self.__ownIdentifier=ownIdentifier self.outgoingPacketStack=[] self.outgoingPacketStackLock=threading.Lock()
class LayerPhy(object): ''' classdocs ''' def __init__(self, ownIdentifier, upperLayerCallbackFunction, masterHost='127.0.0.1', baseport=10000, autoEnter=True): ''' Constructor ''' self.__ownIdentifier = ownIdentifier self.__masterHost = masterHost self.__controlPort = baseport - 1 self.__interfaceSendPort = [0, 0] self.__interfaceRecvPort = [0, 0] self.__incomingTcpServer = [None, None] self.__outgoingTcpClient = [None, None] self.__callLinkLayer = upperLayerCallbackFunction self.__debugOut = DebugOut() self.__openControl_connection() if autoEnter: self.API_enter() def API_enter(self): self.__debugOut.debugOutLayer(self.__ownIdentifier, 1, self.__debugOut.INFO, "Sending ENTER") self.controlTcpClient.send("ENTER\n") def API_leave(self): self.__debugOut.debugOutLayer(self.__ownIdentifier, 1, self.__debugOut.INFO, "Sending LEAVE") self.controlTcpClient.send("LEAVE\n") def API_sendData(self, interfaceNumber=0, data=""): if self.__outgoingTcpClient[interfaceNumber] is not None: self.__debugOut.debugOutLayer( self.__ownIdentifier, 1, self.__debugOut.INFO, "PHY - PhysicalLayer, Interface %d, sending %s" % (interfaceNumber, data)) self.__outgoingTcpClient[interfaceNumber].sendBytes(data) def API_subscribeDebug(self): self.__debugOut.debugOutLayer(self.__ownIdentifier, 1, self.__debugOut.INFO, "Sending SUBSCRIBEDEBUG") self.controlTcpClient.send("SUBSCRIBEDEBUG\n") self.__debugOut.addLocalListenCallback(self.__sendDebugMsg) def __sendDebugMsg(self, eventTime, identifier, source, level, data): message = "DEBUGMSG,%.6f,%s,%s,%s,%s" % (eventTime, identifier, source, level, data) self.controlTcpClient.send(message) def __handleDebugMsg(self, line): (eventTime, separator, line) = line.partition(",") eventTime = float(eventTime) (identifier, separator, line) = line.partition(",") (source, separator, line) = line.partition(",") source = int(source) (level, separator, line) = line.partition(",") level = int(level) self.__debugOut.globaldebugOutSource(eventTime, identifier, source, level, line) def __listenControl_connection(self, tcpClient, __connection, clientAddr, data): while data: (line, separator, data) = data.partition("\n") (command, separator, line) = line.partition(",") if command == "ADDINTERFACE": self.__debugOut.debugOutLayer( self.__ownIdentifier, 1, self.__debugOut.INFO, "PHY %s - __listenControl_connection - received %s" % (clientAddr, line)) (interfacenumber, separator, line) = line.partition(",") (listenport, separator, line) = line.partition(",") self.__addInterface(int(interfacenumber), int(listenport)) self.__debugOut.debugOutLayer( self.__ownIdentifier, 1, self.__debugOut.INFO, "PHY %s done __addInterface" % (clientAddr, )) elif command == "DELINTERFACE": self.__debugOut.debugOutLayer( self.__ownIdentifier, 1, self.__debugOut.INFO, "PHY %s - __listenControl_connection - received %s" % (clientAddr, line)) (interfacenumber, separator, line) = line.partition(",") self.__delInterface(int(interfacenumber)) elif command == "CONNECT": self.__debugOut.debugOutLayer( self.__ownIdentifier, 1, self.__debugOut.INFO, "PHY %s - __listenControl_connection - received %s" % (clientAddr, line)) (interfacenumber, separator, line) = line.partition(",") (ipAddress, separator, line) = line.partition(",") (listenport, separator, line) = line.partition(",") self.__connect(int(interfacenumber), ipAddress, int(listenport)) elif command == "DISCONNECT": self.__debugOut.debugOutLayer( self.__ownIdentifier, 1, self.__debugOut.INFO, "PHY %s - __listenControl_connection - received %s" % (clientAddr, line)) (interfacenumber, separator, line) = line.partition(",") self.__disconnect(int(interfacenumber)) elif command == "DEBUGMSG": self.__handleDebugMsg(line) else: self.__debugOut.debugOutLayer( self.__ownIdentifier, 1, self.__debugOut.INFO, "PHY %s - listenControl_connection - Received unknown command %s." % (clientAddr, command)) def __openControl_connection(self): self.controlTcpClient = TCPClient( host=self.__masterHost, port=self.__controlPort, callBackReceive=self.__listenControl_connection) def __incomingData_connectionInterface0(self, tcpServer, __connection, clientAddr, data): self.__debugOut.debugOutLayer( self.__ownIdentifier, 1, self.__debugOut.INFO, "PHY %s - ListenData_connection on interface 0 received %s" % (clientAddr, data)) self.__callLinkLayer(0, data) def __incomingData_connectionInterface1(self, tcpServer, __connection, clientAddr, data): self.__debugOut.debugOutLayer( self.__ownIdentifier, 1, self.__debugOut.INFO, "PHY %s - ListenData_connection on interface 1 received %s" % (clientAddr, data)) self.__callLinkLayer(1, data) def __sendControl(self, data): self.controlTcpClient.send(data) def __addInterface(self, interfaceNumber=0, listenport=0): self.__debugOut.debugOutLayer( self.__ownIdentifier, 1, self.__debugOut.INFO, "PHY - Adding interface number %d with listenport %d" % (interfaceNumber, listenport)) if self.__incomingTcpServer[interfaceNumber] is None: self.__interfaceRecvPort[interfaceNumber] = listenport if interfaceNumber == 0: self.__incomingTcpServer[0] = TCPServer( host='', port=self.__interfaceRecvPort[0], callBackReceiveBytes=self. __incomingData_connectionInterface0) else: self.__incomingTcpServer[1] = TCPServer( host='', port=self.__interfaceRecvPort[1], callBackReceiveBytes=self. __incomingData_connectionInterface1) self.__debugOut.debugOutLayer( self.__ownIdentifier, 1, self.__debugOut.INFO, 'PHY - Tried to add interface, isServing is : %d' % self.__incomingTcpServer[interfaceNumber].isServing()) if self.__incomingTcpServer[interfaceNumber].isServing(): self.__sendControl("STATUS,ACK\n") else: self.__sendControl("STATUS,NACK,Interface open failed\n") self.__incomingTcpServer[interfaceNumber] = None else: self.__sendControl( "STATUS,NACK,Interface is already __connected\n") def __delInterface(self, interfaceNumber): self.__debugOut.debugOutLayer( self.__ownIdentifier, 1, self.__debugOut.INFO, "Removing interface number %d with listenport %d" % (interfaceNumber, self.__interfaceRecvPort[interfaceNumber])) if self.__incomingTcpServer[interfaceNumber] is None: self.__sendControl("STATUS,NACK,Interface is not active\n") else: self.__incomingTcpServer[interfaceNumber].stopServer() self.__incomingTcpServer[interfaceNumber] = None self.__sendControl("STATUS,ACK\n") def __connect(self, interfaceNumber=0, ipAddress="127.0.0.1", sendport=0): self.__debugOut.debugOutLayer( self.__ownIdentifier, 1, self.__debugOut.INFO, "PHY - __connecting interface %d to ip %s port %d" % (interfaceNumber, ipAddress, sendport)) if self.__outgoingTcpClient[interfaceNumber] is None: self.__interfaceSendPort[interfaceNumber] = sendport self.__outgoingTcpClient[interfaceNumber] = TCPClient( host=ipAddress, port=self.__interfaceSendPort[interfaceNumber], callBackReceiveBytes=None) if self.__outgoingTcpClient[interfaceNumber].isConnected(): self.__sendControl("STATUS,ACK\n") else: self.__sendControl("STATUS,NACK,Interface open failed\n") else: self.__sendControl( "STATUS,NACK,Interface is already __connected\n") def __disconnect(self, interfaceNumber=0): self.__debugOut.debugOutLayer( self.__ownIdentifier, 1, self.__debugOut.INFO, "PHY - disconnecting interface %d from port %d" % (interfaceNumber, self.__interfaceSendPort[interfaceNumber])) if self.__outgoingTcpClient[interfaceNumber] is None: self.__sendControl("STATUS,NACK,Interface is not __connected\n") else: self.__outgoingTcpClient[interfaceNumber].stopClient() self.__outgoingTcpClient[interfaceNumber] = None self.__sendControl("STATUS,ACK\n")
class Computer(object): def __init__(self, ownIdentifier, masterHost='127.0.0.1', baseport=10000, statusUpdateSeconds=1, autoEnter=True, networkStackNumber=0): self.__ownIdentifier = ownIdentifier self.__masterHost = masterHost self.__baseport = baseport self.__statusUpdateSeconds = statusUpdateSeconds self.__autoEnter = autoEnter self.__networkStackNumber = networkStackNumber if networkStackNumber == 0: self.__networkstack = NetworkStack(self.__masterHost, self.__baseport, ownIdentifier, autoEnter) elif networkStackNumber == 1: self.__networkstack = NetworkStackAlternative( self.__masterHost, self.__baseport, ownIdentifier, autoEnter) self.__appMessageList = [] self.__debugOut = DebugOut() if self.__autoEnter: self.startComputer() # The "APP" functions send a message to the other computers given in sendDestinations and counts the number of correctly received packets def appMessageReceived(self, source, applicationPort, message): self.__appThreadLock.acquire() self.__appMessageList.append((source, applicationPort, message)) self.__appThreadLock.release() def appMessageReceive(self): self.__appStartedTime = time.clock() self.__appThreadLock = threading.Lock() self.__networkstack.applicationAddCallback(10, self.appMessageReceived) self.__loopCounter = 0 totalNumber = 0 correct = 0 wrongDestination = 0 wrongApplicationPort = 0 outOfOrder = 0 lastReceived = -1000 while True: self.__loopCounter = self.__loopCounter + 1 self.__appThreadLock.acquire() currentList = self.__appMessageList[:] self.__appMessageList = [] self.__appThreadLock.release() for (source, applicationPort, message) in currentList: self.__debugOut.debugOutSource( self.__ownIdentifier, self.__debugOut.srcApplication, self.__debugOut.INFO, "%s: L'application à reçus le message %d: %s" % (self.__ownIdentifier, totalNumber, message)) totalNumber = totalNumber + 1 thisCorrect = True (messagebody, separator, remainder) = message.partition(",") (messagenumber, separator, remainder) = remainder.partition(",") (messagedestination, separator, remainder) = remainder.partition(",") if applicationPort != 10: wrongApplicationPort = wrongApplicationPort + 1 thisCorrect = False if messagedestination != self.__ownIdentifier: wrongDestination = wrongDestination + 1 thisCorrect = False else: try: messageNumberInt = int(float(messagenumber)) except: messageNumberInt = -2 if lastReceived == -1000: lastReceived = messageNumberInt - 1 if messageNumberInt != lastReceived + 1: outOfOrder = outOfOrder + 1 thisCorrect = False else: lastReceived = lastReceived + 1 if thisCorrect: correct = correct + 1 print(totalNumber) if self.__loopCounter % self.__statusUpdateSeconds == 0: self.__debugOut.debugOutSource( self.__ownIdentifier, self.__debugOut.srcApplication, self.__debugOut.INFO, "%s: === Status de l'ordinateur %s après %.1f secondes:" % (self.__ownIdentifier, self.__ownIdentifier, (time.clock() - self.__appStartedTime))) self.__debugOut.debugOutSource( self.__ownIdentifier, self.__debugOut.srcApplication, self.__debugOut.INFO, "%s: === Reception de %d messages avec %d correcte (%d hors service, %d mauvaise destination, %d mauvaise application)\n" % (self.__ownIdentifier, totalNumber, correct, outOfOrder, wrongDestination, wrongApplicationPort)) time.sleep(1) def appMessageSend(self, destinationIdentifier="B", numberOfMessages=5): self.__debugOut.debugOutSource( self.__ownIdentifier, self.__debugOut.srcComputer, self.__debugOut.INFO, "%s: Envoie %d Messages de %s a %s" % (self.__ownIdentifier, numberOfMessages, self.__ownIdentifier, str(destinationIdentifier))) for i in range(numberOfMessages): for d in destinationIdentifier: thisMessage = "Message n°%d de %s a %s,%s,%s" % ( i, self.__ownIdentifier, d, i, d) #thisMessage="%s Sending Message n°%d to %s,%d,%s" % (self.__ownIdentifier, i,d,i,d) self.__networkstack.applicationSend(d, 10, thisMessage) def debugConfigureNetworkstackDelay(self, sendDelay=None, layerDelay=None): self.__networkstack.configureDelay(sendDelay, layerDelay) # Please Adapt/Change def initiateToken(self): self.__networkstack.initiateToken() def startComputer(self): self.__application_incoming = threading.Thread( target=self.appMessageReceive) self.__application_incoming.start() def stopComputer(self): self.__networkstack.leaveNetwork() def enableGlobalDebug(self): self.__networkstack.enableGlobalDebug()
# We initialize here the debugging framework: # Each part of the computer has a debug source identifier # 0 is reserved for internal communication # 1 Is for general computer messages # 2 is for applications # 11 or layer=1 is used for the Physical Network Layer # 12 or layer=2 is used for the first network layer that is up to you to implement # # Various DebugLevels have been predefined, notably NONE, ERROR, WARNING, INFO, ALL (see Tools/DebugOut for more information) # If you are using MacOS, the tkinter needs to run in the main thread # We could put the setup into another thread that would liberate the main thread thus, this is a workaround for the moment macosTkinterWorkaround = True __debugOut = DebugOut() __debugOut.setDebugLevelForSource(__debugOut.srcComputer, __debugOut.NONE) __debugOut.setDebugLevelForSource(__debugOut.srcApplication, __debugOut.NONE) __debugOut.setDebugLevelForLayer(1, __debugOut.WARNING) # __debugOut.setDebugLevelForLayer(1, __debugOut.INFO) __debugOut.setDebugLevelForLayer(2, __debugOut.INFO) __debugOut.setDebugLevelForLayer(3, __debugOut.INFO) __debugOut.setDebugLevelForLayer(4, __debugOut.INFO) __debugOut.setDebugLevelForLayer(5, __debugOut.INFO) __debugOut.setDebugLevelForLayer(6, __debugOut.INFO) # This starts the graphical user interface # Computers (Nodes) are added automatically unless contained in ignoreComputers # The layerSelection determines the layers that are displayed graphically
class NetworkStack(object): def __init__(self, masterHost='127.0.0.1', baseport=10000, ownIdentifier='x', autoEnter=True): self.__debugOut = DebugOut() self.__applicationList = [] self.__sendDelay = 0 self.__layerDelay = 0 self.__layerPhy = LayerPhy.LayerPhy( ownIdentifier, upperLayerCallbackFunction=self.layer2_incomingPDU, masterHost=masterHost, baseport=baseport, autoEnter=autoEnter) # You may want to change the following part self.__ownIdentifier = ownIdentifier self.outgoingPacketStack = [] self.outgoingPacketStackLock = threading.Lock() def leaveNetwork(self): self.__layerPhy.API_leave() def enableGlobalDebug(self): self.__layerPhy.API_subscribeDebug() def configureDelay(self, sendDelay=None, layerDelay=None): if sendDelay != None: self.__sendDelay = sendDelay if layerDelay != None: self.__layerDelay = layerDelay # Do not change! # This is the application layer protocol part: Each application has its specific port # The application registers a callback function that is called when a packet arrives for that particular application def applicationAddCallback(self, applicationPort, callBack): self.__applicationList.append((applicationPort, callBack)) # Do not change! # The application sends packets which are stored in a buffer before being submitted def applicationSend(self, destination, applicationPort, pdu): self.outgoingPacketStackLock.acquire() self.outgoingPacketStack.insert(0, (destination, applicationPort, pdu)) self.outgoingPacketStackLock.release() ############################################################################################################################################# ############################################################################################################################################# # Please change: This sends the first TOKEN to the ring # In fact, sending a TOKEN requires the creation of a new thread def initiateToken(self): self.__debugOut.debugOutLayer(self.__ownIdentifier, 2, self.__debugOut.INFO, "Initiating TOKEN") tokenThread = threading.Thread( target=self.application_layer_outgoingPDU, args=(True, )) tokenThread.start() # Please adapt if required : This is the top layer that usually sends the data to the application # If pdu is None, the packet is not valid # forceToken determines that the return packet needs to be a TOKEN def application_layer_incomingPDU(self, forceToken, source, pdu): time.sleep(self.__layerDelay) self.__debugOut.debugOutLayer( self.__ownIdentifier, 5, self.__debugOut.INFO, "%s: application_layer_in: received (%s) " % (self.__ownIdentifier, pdu)) if pdu != None: applicationPort = int.from_bytes(pdu[0:1], byteorder="little", signed=False) sdu = pdu[1:] # We deliver the SDU to the application that handles this message for (thisApplicationPort, thisApplication) in self.__applicationList: if thisApplicationPort == applicationPort: thisApplication(source, applicationPort, sdu.decode('UTF-8')) # We dive back down into the network stack self.application_layer_outgoingPDU(forceToken) # Please adapt if required: This is the top layer that retrieves one element from the application layer def application_layer_outgoingPDU(self, forceToken=False): time.sleep(self.__layerDelay) self.outgoingPacketStackLock.acquire() if len(self.outgoingPacketStack) == 0 or forceToken: destination = "X" applicationPort = 20 sdu = "TOKEN" else: destination, applicationPort, sdu = self.outgoingPacketStack.pop() self.outgoingPacketStackLock.release() pdu = applicationPort.to_bytes(1, byteorder="little", signed=False) + sdu.encode("UTF-8") self.__debugOut.debugOutLayer( self.__ownIdentifier, 5, self.__debugOut.INFO, "%s: application_layer_out: sending (%s) " % (self.__ownIdentifier, pdu)) self.layer4_outgoingPDU(destination, applicationPort, pdu) # Please adapt! # Take care: The parameters of incoming (data packets arriving at the computer) and outgoing (data packets leaving from the computer) # should generally agree with one layer difference (i.e. here we treat the applicationPort, an identifier that knows which application # is asked to handle the traffic def layer4_incomingPDU(self, source, pdu): time.sleep(self.__layerDelay) # Let us assume that this is the layer where we determine the applicationPort # We also decide whether we can send immediately send a new packet or whether we need to be friendly and send a TOKEN # We are not friendly and send a packet if our application has one with 100% chance self.__debugOut.debugOutLayer( self.__ownIdentifier, 4, self.__debugOut.INFO, "%s: Layer4_in: Received (%s) from %s " % (self.__ownIdentifier, pdu, source)) self.application_layer_incomingPDU(False, source, pdu) # Please adapt def layer4_outgoingPDU(self, destination, applicationPort, pdu): time.sleep(self.__layerDelay) self.__debugOut.debugOutLayer( self.__ownIdentifier, 4, self.__debugOut.INFO, "%s: Layer4_out: Sending (%s) to %s " % (self.__ownIdentifier, pdu, destination)) self.layer3_outgoingPDU(destination, pdu) # Please adapt! # The current situation is that in this layer, the network stack takes the decision to forcibly keep the packet because it thinkgs that it is destined to this computer # It also authorizes immediately that a new packet can be put onto the network. def layer3_incomingPDU(self, interface, pdu): time.sleep(self.__layerDelay) # In this layer we know that the packet is addressed to us. # It may contain information that is valid or not # This is another point of this obscure network protocol # With a chance of 50%, the packet contains valid data for us # With a chance of 50%, the packet does not contain valid data for us self.__debugOut.debugOutLayer( self.__ownIdentifier, 3, self.__debugOut.INFO, "%s: Layer3_in: Received (%s) on interface %d " % (self.__ownIdentifier, pdu, interface)) if random.randint(0, 1): self.__debugOut.debugOutLayer( self.__ownIdentifier, 3, self.__debugOut.INFO, "%s: Layer3_in: tirage (%s) -> layer4_in\n" % (self.__ownIdentifier, pdu)) # That is, for example that the destination of the packet corresponds to us # We also set here the source of the packet, currently as fixed: "A" self.layer4_incomingPDU("A", pdu) else: self.__debugOut.debugOutLayer( self.__ownIdentifier, 3, self.__debugOut.INFO, "%s: Layer3_in: tirage (%s) -> Packet to be destroyed\n" % (self.__ownIdentifier, pdu)) self.layer4_incomingPDU(None, None) # Please adapt def layer3_outgoingPDU(self, destination, pdu): time.sleep(self.__layerDelay) # Here, we store the packet and wait until an empty token packet arrives self.__debugOut.debugOutLayer( self.__ownIdentifier, 3, self.__debugOut.INFO, "%s: Layer3_out: Sending out (%s) via interface %d " % (self.__ownIdentifier, pdu, 0)) self.layer2_outgoingPDU(0, pdu) # Please adapt def layer2_incomingPDU(self, interface, pdu): time.sleep(self.__layerDelay) self.__debugOut.debugOutLayer( self.__ownIdentifier, 2, self.__debugOut.INFO, "%s: Layer2_in: Received (%s) on Interface %d " % (self.__ownIdentifier, pdu, interface)) if interface == 0: # same ring # Let us assume that here we treat the question whether this packet is addressed to us or not # The answer may be based on some obscure network protocol # With a chance of 50%, we forward the packet # With a chance of 50%, we receive the packet and say that it comes the source "A" if random.randint(0, 1): self.__debugOut.debugOutLayer( self.__ownIdentifier, 2, self.__debugOut.INFO, "%s: Layer2_in: tirage (%s) -> layer2_out\n" % (self.__ownIdentifier, pdu)) self.layer2_outgoingPDU(interface, pdu) else: self.__debugOut.debugOutLayer( self.__ownIdentifier, 2, self.__debugOut.INFO, "%s: Layer2_in: tirage (%s) -> layer3_in\n" % (self.__ownIdentifier, pdu)) self.layer3_incomingPDU(interface, pdu) else: # Another Ring, this is for routing, see later pass def layer2_outgoingPDU(self, interface, pdu): time.sleep(self.__layerDelay) self.__debugOut.debugOutLayer( self.__ownIdentifier, 2, self.__debugOut.INFO, "%s: Layer2_out: Sending out (%s) via interface %d " % (self.__ownIdentifier, pdu, interface)) if self.__sendDelay != 0: self.__debugOut.debugOutLayer( self.__ownIdentifier, 2, self.__debugOut.INFO, "%s: Layer2_out: Sleeping for %ds" % (self.__ownIdentifier, self.__sendDelay)) time.sleep(self.__sendDelay) self.__layerPhy.API_sendData(interface, pdu)
class NetworkStackAlternative(object): def __init__(self, masterHost='127.0.0.1', baseport=10000, ownIdentifier='x', autoEnter=True): self.__debugOut = DebugOut() self.__applicationList = [] self.__sendDelay = 0 self.__layerDelay = 0 self.__layerPhy = LayerPhy.LayerPhy( ownIdentifier, upperLayerCallbackFunction=self.layer2_incomingPDU, masterHost=masterHost, baseport=baseport, autoEnter=autoEnter) # You may want to change the following part self.__ownIdentifier = ownIdentifier self.outgoingPacketStack = [] self.outgoingPacketStackLock = threading.Lock() def leaveNetwork(self): self.__layerPhy.API_leave() def enableGlobalDebug(self): self.__layerPhy.API_subscribeDebug() def configureDelay(self, sendDelay=None, layerDelay=None): if sendDelay != None: self.__sendDelay = sendDelay if layerDelay != None: self.__layerDelay = layerDelay # Do not change! # This is the application layer protocol part: Each application has its specific port # The application registers a callback function that is called when a packet arrives for that particular application def applicationAddCallback(self, applicationPort, callBack): self.__applicationList.append((applicationPort, callBack)) # Do not change! # The application sends packets which are stored in a buffer before being submitted def applicationSend(self, destination, applicationPort, pdu): self.outgoingPacketStackLock.acquire() self.outgoingPacketStack.insert(0, (destination, applicationPort, pdu)) self.outgoingPacketStackLock.release() ############################################################################################################################################# ############################################################################################################################################# # Please change: This sends the first TOKEN to the ring # In fact, sending a TOKEN requires the creation of a new thread def initiateToken(self): self.__debugOut.debugOutLayer(self.__ownIdentifier, 2, self.__debugOut.INFO, "Initiating TOKEN") tokenThread = threading.Thread( target=self.application_layer_outgoingPDU, args=(True, )) tokenThread.start() # Please adapt if required : This is the top layer that usually sends the data to the application # If pdu is None, the packet is not valid # forceToken determines that the return packet needs to be a TOKEN def application_layer_incomingPDU(self, forceToken, source, pdu): time.sleep(self.__layerDelay) self.__debugOut.debugOutLayer( self.__ownIdentifier, 5, self.__debugOut.INFO, "%s: application_layer_in: received (%s) " % (self.__ownIdentifier, pdu)) if pdu != None: applicationPort = int.from_bytes(pdu[0:1], byteorder="little", signed=False) sdu = pdu[1:] # We deliver the SDU to the application that handles this message for (thisApplicationPort, thisApplication) in self.__applicationList: if thisApplicationPort == applicationPort: thisApplication(source, applicationPort, sdu.decode('UTF-8')) # We dive back down into the network stack self.application_layer_outgoingPDU(forceToken) # Please adapt if required: This is the top layer that retrieves one element from the application layer def application_layer_outgoingPDU(self, forceToken=False): time.sleep(self.__layerDelay) self.outgoingPacketStackLock.acquire() if len(self.outgoingPacketStack) == 0 or forceToken: destination = "X" applicationPort = 20 sdu = "TOKEN" else: destination, applicationPort, sdu = self.outgoingPacketStack.pop() self.outgoingPacketStackLock.release() pdu = applicationPort.to_bytes(1, byteorder="little", signed=False) + sdu.encode("UTF-8") self.__debugOut.debugOutLayer( self.__ownIdentifier, 5, self.__debugOut.INFO, "%s: application_layer_out: sending (%s) " % (self.__ownIdentifier, pdu)) self.layer4_outgoingPDU(destination, applicationPort, pdu) # Please adapt! # Take care: The parameters of incoming (data packets arriving at the computer) and outgoing (data packets leaving from the computer) # should generally agree with one layer difference (i.e. here we treat the applicationPort, an identifier that knows which application # is asked to handle the traffic def layer4_incomingPDU(self, source, pdu): time.sleep(self.__layerDelay) self.__debugOut.debugOutLayer( self.__ownIdentifier, 4, self.__debugOut.INFO, "%s: Layer4_in: Received (%s) from %s " % (self.__ownIdentifier, pdu, source)) # Please adapt def layer4_outgoingPDU(self, destination, applicationPort, pdu): time.sleep(self.__layerDelay) self.__debugOut.debugOutLayer( self.__ownIdentifier, 4, self.__debugOut.INFO, "%s: Layer4_out: Sending (%s) to %s " % (self.__ownIdentifier, pdu, destination)) def layer3_incomingPDU(self, interface, pdu): time.sleep(self.__layerDelay) self.__debugOut.debugOutLayer( self.__ownIdentifier, 2, self.__debugOut.INFO, "%s: Layer3_in: tirage (%s) -> layer4_in\n" % (self.__ownIdentifier, pdu)) # Please adapt def layer3_outgoingPDU(self, destination, pdu): time.sleep(self.__layerDelay) self.__debugOut.debugOutLayer( self.__ownIdentifier, 3, self.__debugOut.INFO, "%s: Layer3_out: Sending out (%s) via interface %d " % (self.__ownIdentifier, pdu, 0)) # Please adapt def layer2_incomingPDU(self, interface, pdu): time.sleep(self.__layerDelay) self.__debugOut.debugOutLayer( self.__ownIdentifier, 2, self.__debugOut.INFO, "%s: Layer2_in: Received (%s) on Interface %d " % (self.__ownIdentifier, pdu, interface)) self.layer2_outgoingPDU(interface, pdu) def layer2_outgoingPDU(self, interface, pdu): time.sleep(self.__layerDelay) self.__debugOut.debugOutLayer( self.__ownIdentifier, 2, self.__debugOut.INFO, "%s: Layer2_out: Sending out (%s) via interface %d " % (self.__ownIdentifier, pdu, interface)) if self.__sendDelay != 0: self.__debugOut.debugOutLayer( self.__ownIdentifier, 2, self.__debugOut.INFO, "%s: Layer2_out: Sleeping for %ds" % (self.__ownIdentifier, self.__sendDelay)) time.sleep(self.__sendDelay) self.__layerPhy.API_sendData(interface, pdu)
# ============================================================================ # We initialize here the debugging framework: # Each part of the computer has a debug source identifier # 0 is reserved for internal communication # 1 Is for general computer messages # 2 is for applications # 11 or layer=1 is used for the Physical Network Layer # 12 or layer=2 is used for the first network layer that is up to you to implement # # Various DebugLevels have been predefined, notably NONE, ERROR, WARNING, INFO, ALL (see Tools/DebugOut for more information) # If you are using MacOS, the tkinter needs to run in the main thread macosTkinterWorkaround = True __debugOut = DebugOut() __debugOut.setDebugLevelForSource(__debugOut.srcComputer, __debugOut.NONE) __debugOut.setDebugLevelForSource(__debugOut.srcApplication, __debugOut.NONE) __debugOut.setDebugLevelForLayer(1, __debugOut.WARNING) # __debugOut.setDebugLevelForLayer(1, __debugOut.INFO) __debugOut.setDebugLevelForLayer(2, __debugOut.INFO) __debugOut.setDebugLevelForLayer(3, __debugOut.INFO) __debugOut.setDebugLevelForLayer(4, __debugOut.INFO) __debugOut.setDebugLevelForLayer(5, __debugOut.INFO) __debugOut.setDebugLevelForLayer(6, __debugOut.INFO) # This starts the graphical user interface # Computers (Nodes) are added automatically unless contained in ignoreComputers # The layerSelection determines the layers that are displayed graphically
class NetworkStack(object): def __init__(self, masterHost='127.0.0.1', baseport=10000, ownIdentifier='x', autoEnter=True): self.__debugOut = DebugOut() self.__applicationList = [] self.__sendDelay = 0 self.__layerDelay = 0 self.__layerPhy = LayerPhy.LayerPhy( ownIdentifier, upperLayerCallbackFunction=self.layer2_incomingPDU, masterHost=masterHost, baseport=baseport, autoEnter=autoEnter) # You may want to change the following part self.__ownIdentifier = ownIdentifier self.outgoingPacketStack = [] self.outgoingPacketStackLock = threading.Lock() def leaveNetwork(self): self.__layerPhy.API_leave() def enableGlobalDebug(self): self.__layerPhy.API_subscribeDebug() def configureDelay(self, sendDelay=None, layerDelay=None): if sendDelay != None: self.__sendDelay = sendDelay if layerDelay != None: self.__layerDelay = layerDelay # Do not change! # This is the application layer protocol part: Each application has its specific port # The application registers a callback function that is called when a packet arrives for that particular application def applicationAddCallback(self, applicationPort, callBack): self.__applicationList.append((applicationPort, callBack)) # Do not change! # The application sends packets which are stored in a buffer before being submitted def applicationSend(self, destination, applicationPort, pdu): self.outgoingPacketStackLock.acquire() self.outgoingPacketStack.insert(0, (destination, applicationPort, pdu)) self.outgoingPacketStackLock.release() ############################################################################################################################################# ############################################################################################################################################# # Please change: This sends the first TOKEN to the ring # In fact, sending a TOKEN requires the creation of a new thread def initiateToken(self): # On définit le maître par un envoie d'un token self.__debugOut.debugOutLayer(self.__ownIdentifier, 2, self.__debugOut.INFO, "Initiating TOKEN") tokenThread = threading.Thread( target=self.application_layer_outgoingPDU, args=(0, )) tokenThread.start() # Please adapt if required : This is the top layer that usually sends the data to the application # If pdu is None, the packet is not valid # forceToken determines that the return packet needs to be a TOKEN def application_layer_incomingPDU(self, localtype, source, pdu): # Layer 5 dans l'application (Le premier element du paquet se trouve dedans) # Les données sont toutes seules pour le moment. time.sleep(self.__layerDelay) self.__debugOut.debugOutLayer( self.__ownIdentifier, 5, self.__debugOut.INFO, "%s: application_layer_in: received (%s) " % (self.__ownIdentifier, pdu)) if pdu != None: applicationPort = int.from_bytes(pdu[0:1], byteorder="little", signed=False) sdu = pdu[1:] # We deliver the SDU to the application that handles this message for (thisApplicationPort, thisApplication) in self.__applicationList: if thisApplicationPort == applicationPort: thisApplication(source, applicationPort, sdu.decode('UTF-8')) # We dive back down into the network stack if (localtype == 2): self.application_layer_outgoingPDU(3) # Please adapt if required: This is the top layer that retrieves one element from the application layer def application_layer_outgoingPDU(self, localtype=0): # Layer 5 dans l'application (Le premier element du paquet se trouve dedans) # On récupère les infos de l'application, dont le type de paquet qu'on balance, pour qui, avec les données. time.sleep(self.__layerDelay) self.outgoingPacketStackLock.acquire() if localtype == 0: destination = 1 applicationPort = 20 sdu = "TOKEN" type = 0 else: if (localtype == 1): # Après l'accusé de réception if (len(self.outgoingPacketStack) == 0): # On balance le token destination = 1 applicationPort = 20 sdu = "TOKEN" type = 0 else: destination, applicationPort, sdu = self.outgoingPacketStack.pop( ) type = 2 elif (localtype == 2): # Type message # Il s'agit d'envoyer un message comme quoi elle a bien reçu les données. None elif (localtype == 3): # Il s'agit de recevoir l'accusé de réception. # On balance donc le token des qu'on a reçu l'accusé de reception destination = 1 applicationPort = 20 sdu = "TOKEN" type = 0 self.outgoingPacketStackLock.release() # Data pdu = sdu.encode("UTF-8") #Dest pdu = applicationPort.to_bytes(1, byteorder="little", signed=False) + pdu self.__debugOut.debugOutLayer( self.__ownIdentifier, 5, self.__debugOut.INFO, "%s: application_layer_out: sending (%s) " % (self.__ownIdentifier, pdu)) self.layer7_outgoingPDU(DestinationtoID(destination), ord(self.__ownIdentifier), type, pdu, 255) # --------- ENCAPSULAGE -------- def layer7_outgoingPDU(self, destination, source, type, pdu, TTL=255): # encapsulage du checksum time.sleep(self.__layerDelay) self.__debugOut.debugOutLayer( self.__ownIdentifier, 7, self.__debugOut.INFO, "%s: Layer7_out: Sending (%s) to %s " % (self.__ownIdentifier, pdu, destination)) pdu = HashageAJA(pdu).to_bytes(2, byteorder="little") + pdu self.layer6_outgoingPDU(destination, source, type, pdu, TTL) def layer6_outgoingPDU(self, destination, source, type, pdu, TTL=255): # encapsulage source time.sleep(self.__layerDelay) self.__debugOut.debugOutLayer( self.__ownIdentifier, 6, self.__debugOut.INFO, "%s: Layer6_out: Sending (%s) to %s " % (self.__ownIdentifier, pdu, destination)) pdu = source.to_bytes(1, byteorder="little") + pdu self.layer5_outgoingPDU(destination, type, pdu, TTL) def layer5_outgoingPDU(self, destination, type, pdu, TTL=255): # encapsulage destination time.sleep(self.__layerDelay) self.__debugOut.debugOutLayer( self.__ownIdentifier, 5, self.__debugOut.INFO, "%s: Layer5_out: Sending (%s) to %s " % (self.__ownIdentifier, pdu, destination)) pdu = destination.to_bytes(1, byteorder="little") + pdu self.layer4_outgoingPDU(type, pdu, TTL) def layer4_outgoingPDU(self, type, pdu, TTL=255): # encapsulage TTL time.sleep(self.__layerDelay) self.__debugOut.debugOutLayer( self.__ownIdentifier, 4, self.__debugOut.INFO, "%s: Layer4_out: Sending (%s)" % (self.__ownIdentifier, pdu)) pdu = TTL.to_bytes(1, byteorder="little") + pdu self.layer3_outgoingPDU(type, pdu) def layer3_outgoingPDU(self, type, pdu): # encapsulage Type time.sleep(self.__layerDelay) self.__debugOut.debugOutLayer( self.__ownIdentifier, 3, self.__debugOut.INFO, "%s: Layer3_out: Sending (%s)" % (self.__ownIdentifier, pdu)) pdu = type.to_bytes(1, byteorder="little") + pdu self.layer2_outgoingPDU(0, pdu) #4 -> TTL def layer2_outgoingPDU(self, interface, pdu): # encapsulage Protocol time.sleep(self.__layerDelay) proto = 26 self.__debugOut.debugOutLayer( self.__ownIdentifier, 2, self.__debugOut.INFO, "%s: Layer2_out: Sending (%s) via interface %d " % (self.__ownIdentifier, pdu, interface)) pdu = proto.to_bytes(1, byteorder="little") + pdu if self.__sendDelay != 0: self.__debugOut.debugOutLayer( self.__ownIdentifier, 2, self.__debugOut.INFO, "%s: Layer2_out: Sleeping for %ds" % (self.__ownIdentifier, self.__sendDelay)) time.sleep(self.__sendDelay) self.__layerPhy.API_sendData(interface, pdu) # ----------------------------------- END NEW ------------------ # ------- DECAPSULAGE ------- def layer2_incomingPDU(self, interface, pdu): # On doit décider si le paquet est pour nous ou pas. # On doit pour cela verifier si le protocole est le notre. time.sleep(self.__layerDelay) self.__debugOut.debugOutLayer( self.__ownIdentifier, 2, self.__debugOut.INFO, "%s: Layer2_in: Received (%s) on Interface %d " % (self.__ownIdentifier, pdu, interface)) if interface == 0: # same ring # On doit décapsuler le paquet pour check le protocole. if pdu != None: # On prend le premier octet pour check si c'est notre protocol ! protocol = int.from_bytes(pdu[0:1], byteorder="little", signed=False) pdu = pdu[1:] if protocol == 26: # Numero du protocol AJA self.__debugOut.debugOutLayer( self.__ownIdentifier, 2, self.__debugOut.INFO, "%s: Layer2_in: [AJA] (%s) -> Check Type\n" % (self.__ownIdentifier, pdu)) self.layer3_incomingPDU(pdu) else: self.__debugOut.debugOutLayer( self.__ownIdentifier, 2, self.__debugOut.INFO, "%s: Layer2_in: [Not AJA] (%s) -> layer2_out\n" % (self.__ownIdentifier, pdu)) self.layer2_outgoingPDU(interface, pdu) else: pass def layer3_incomingPDU(self, pdu): # Type time.sleep(self.__layerDelay) self.__debugOut.debugOutLayer( self.__ownIdentifier, 3, self.__debugOut.INFO, "%s: Layer3_in: Received (%s)" % (self.__ownIdentifier, pdu)) if pdu != None: localtype = int.from_bytes(pdu[0:1], byteorder="little", signed=False) pdu = pdu[1:] self.__debugOut.debugOutLayer( self.__ownIdentifier, 3, self.__debugOut.INFO, "%s: Layer3_in: Type: (%s)" % (self.__ownIdentifier, str(localtype))) if localtype == 0: # Token self.layer4_incomingPDU(localtype, pdu) elif localtype == 1: # Type Accusé de reception # Il s'agit de voir si on a fait le tour. self.layer4_incomingPDU(localtype, pdu) elif localtype == 2: # Type Données # Message self.layer4_incomingPDU(localtype, pdu) elif localtype == 3: # accusé message reçu self.layer4_incomingPDU(localtype, pdu) elif localtype == 4: # Type RetId None elif localtype == 5: # Type Update TTL None elif localtype == 6: # Type CountTTl None else: # Type invalide, destruction du paquet. pass def layer4_incomingPDU(self, localtype, pdu): # TTL time.sleep(self.__layerDelay) self.__debugOut.debugOutLayer( self.__ownIdentifier, 4, self.__debugOut.INFO, "%s: Layer4_in: Received (%s) type (%s)" % (self.__ownIdentifier, pdu, str(localtype))) if pdu != None: TTL = int.from_bytes(pdu[0:1], byteorder="little", signed=False) pdu = pdu[1:] self.__debugOut.debugOutLayer( self.__ownIdentifier, 4, self.__debugOut.INFO, "%s: Layer4_in: TTL (%s)" % (self.__ownIdentifier, str(TTL))) if localtype == 0: self.layer5_incomingPDU(localtype, TTL, pdu) elif localtype == 1: # Type Accusé de reception # On decrease le TTL TTL = TTL - 1 self.layer5_incomingPDU(localtype, TTL, pdu) elif localtype == 2: # Type Données # On decrease le TTL TTL = TTL - 1 self.layer5_incomingPDU(localtype, TTL, pdu) elif localtype == 3: TTL = TTL - 1 self.layer5_incomingPDU(localtype, TTL, pdu) elif localtype == 4: # Type RetId None elif localtype == 5: # Type Update TTL None elif localtype == 6: # Type CountTTl None else: # Type invalide, destruction du paquet. pass # self.layer5_outgoingPDU(localtype, pdu, TTL) def layer5_incomingPDU(self, localtype, TTL, pdu): # destination time.sleep(self.__layerDelay) if pdu != None: destination = int.from_bytes(pdu[0:1], byteorder="little", signed=False) pdu = pdu[1:] self.__debugOut.debugOutLayer( self.__ownIdentifier, 5, self.__debugOut.INFO, "%s: Layer5_in: Destination (%s)" % (self.__ownIdentifier, str(destination))) if localtype == 0: self.layer6_incomingPDU(destination, localtype, TTL, pdu) elif localtype == 1: # Type Accusé de reception if destination != ord(self.__ownIdentifier): # Si c'est pas nous alors # On fait tourner. self.layer5_outgoingPDU(destination, localtype, pdu, TTL) else: # On a terminé le tour donc on diffuse un message. self.layer6_incomingPDU(destination, localtype, TTL, pdu) elif localtype == 2: # Type Données # Message if destination != ord(self.__ownIdentifier): # Si c'est pas nous alors # On fait tourner. self.layer5_outgoingPDU(destination, localtype, pdu, TTL) else: # On a terminé le tour donc on diffuse un message. self.layer6_incomingPDU(destination, localtype, TTL, pdu) elif localtype == 3: # Accusé de réception message if destination != ord(self.__ownIdentifier): self.layer5_outgoingPDU(destination, localtype, pdu, TTL) else: self.application_layer_outgoingPDU(0) elif localtype == 4: # Type RetId None elif localtype == 5: # Type Update TTL None elif localtype == 6: # Type CountTTl None else: # Type invalide, destruction du paquet. pass def layer6_incomingPDU(self, destination, localtype, TTL, pdu): # source time.sleep(self.__layerDelay) if pdu != None: source = int.from_bytes(pdu[0:1], byteorder="little", signed=False) pdu = pdu[1:] self.__debugOut.debugOutLayer( self.__ownIdentifier, 6, self.__debugOut.INFO, "%s: Layer6_in: Source (%s)" % (self.__ownIdentifier, str(destination))) if localtype == 0: # On balance un accusé de reception self.layer6_outgoingPDU(DestinationtoID(self.__ownIdentifier), ord(self.__ownIdentifier), 1, pdu, 255) elif localtype == 1: # Type Accusé de reception self.application_layer_outgoingPDU(localtype) elif localtype == 2: # Type Données # Rien de particulier avec la source self.layer7_incomingPDU(localtype, source, pdu) elif localtype == 3: # Reception message accusé None elif localtype == 4: # Type RetId None elif localtype == 5: # Type Update TTL None elif localtype == 6: # Type CountTTl None else: # Type invalide, destruction du paquet. pass def layer7_incomingPDU(self, localtype, source, pdu): time.sleep(self.__layerDelay) if pdu != None: checksum = int.from_bytes(pdu[0:2], byteorder="little", signed=False) pdu = pdu[2:] if (HashageAJA(pdu) == checksum): self.application_layer_incomingPDU(localtype, source, pdu) else: # Destruction du paquet None
class NetworkStack(object): def __init__(self, masterHost='127.0.0.1', baseport=10000, ownIdentifier='x', autoEnter=True): self.__debugOut = DebugOut() self.__applicationList = [] self.__sendDelay = 0 self.__layerDelay = 0 self.__layerPhy = LayerPhy.LayerPhy( ownIdentifier, upperLayerCallbackFunction=self.layer2_incomingPDU, masterHost=masterHost, baseport=baseport, autoEnter=autoEnter) # You may want to change the following part self.__ownIdentifier = ownIdentifier self.outgoingPacketStack = [] self.outgoingPacketStackLock = threading.Lock() #SN TB ETAPE DE L'INITIALISATION DU TOKEN self.initToken = 2 #SN TB compteur -> compteur pour le nombre de slot (couche 2) self.compteur = 2 self.indice = 0 self.paquetRecu = "" self.paquetAEnvoyer = "".encode("UTF-8") def leaveNetwork(self): self.__layerPhy.API_leave() def enableGlobalDebug(self): self.__layerPhy.API_subscribeDebug() def configureDelay(self, sendDelay=None, layerDelay=None): if sendDelay != None: self.__sendDelay = sendDelay if layerDelay != None: self.__layerDelay = layerDelay # Do not change! # This is the application layer protocol part: Each application has its specific port # The application registers a callback function that is called when a packet arrives for that particular application def applicationAddCallback(self, applicationPort, callBack): self.__applicationList.append((applicationPort, callBack)) # Do not change! # The application sends packets which are stored in a buffer before being submitted def applicationSend(self, destination, applicationPort, pdu): self.outgoingPacketStackLock.acquire() self.outgoingPacketStack.insert(0, (destination, applicationPort, pdu)) self.outgoingPacketStackLock.release() ############################################################################################################################################# ############################################################################################################################################# # Please change: This sends the first TOKEN to the ring # In fact, sending a TOKEN requires the creation of a new thread def initiateToken(self): self.__debugOut.debugOutLayer(self.__ownIdentifier, 2, self.__debugOut.INFO, "Initiating TOKEN") tokenThread = threading.Thread( target=self.application_layer_outgoingPDU, args=(True, )) tokenThread.start() # Please adapt if required : This is the top layer that usually sends the data to the application # If pdu is None, the packet is not valid # forceToken determines that the return packet needs to be a TOKEN def application_layer_incomingPDU(self, forceToken, source, pdu): time.sleep(self.__layerDelay) self.__debugOut.debugOutLayer( self.__ownIdentifier, 5, self.__debugOut.INFO, "%s: application_layer_in: received (%s) " % (self.__ownIdentifier, pdu)) if pdu != None: applicationPort = int.from_bytes(pdu[0:1], byteorder="little", signed=False) sdu = pdu[1:] # We deliver the SDU to the application that handles this message for (thisApplicationPort, thisApplication) in self.__applicationList: if thisApplicationPort == applicationPort: thisApplication(source, applicationPort, sdu.decode('UTF-8')) # We dive back down into the network stack self.application_layer_outgoingPDU(forceToken) # Please adapt if required: This is the top layer that retrieves one element from the application layer def application_layer_outgoingPDU(self, forceToken=False): time.sleep(self.__layerDelay) self.outgoingPacketStackLock.acquire() #TB SN on compare le initToken et le ownIdentifier pour initialiser le paquet avec le computeur 'A' if (self.initToken != 0 and self.__ownIdentifier == 'A') or forceToken: destination = "X" applicationPort = 20 sdu = "TOKEN" else: if self.outgoingPacketStack != []: destination, applicationPort, sdu = self.outgoingPacketStack.pop( ) else: destination = "X" applicationPort = 20 sdu = "TOKEN" self.outgoingPacketStackLock.release() pdu = applicationPort.to_bytes(1, byteorder="little", signed=False) + sdu.encode("UTF-8") self.__debugOut.debugOutLayer( self.__ownIdentifier, 5, self.__debugOut.INFO, "%s: application_layer_out: sending (%s) " % (self.__ownIdentifier, pdu)) self.layer4_outgoingPDU(destination, applicationPort, pdu) # Please adapt! # Take care: The parameters of incoming (data packets arriving at the computer) and outgoing (data packets leaving from the computer) # should generally agree with one layer difference (i.e. here we treat the applicationPort, an identifier that knows which application # is asked to handle the traffic def layer4_incomingPDU(self, source, pdu): time.sleep(self.__layerDelay) # Let us assume that this is the layer where we determine the applicationPort # We also decide whether we can send immediately send a new packet or whether we need to be friendly and send a TOKEN # We are not friendly and send a packet if our application has one with 100% chance self.__debugOut.debugOutLayer( self.__ownIdentifier, 4, self.__debugOut.INFO, "%s: Layer4_in: Received (%s) from %s " % (self.__ownIdentifier, pdu, source)) self.application_layer_incomingPDU(False, source, pdu) # Please adapt def layer4_outgoingPDU(self, destination, applicationPort, pdu): time.sleep(self.__layerDelay) self.__debugOut.debugOutLayer( self.__ownIdentifier, 4, self.__debugOut.INFO, "%s: Layer4_out: Sending (%s) to %s " % (self.__ownIdentifier, pdu, destination)) self.layer3_outgoingPDU(destination, pdu) # Please adapt! # The current situation is that in this layer, the network stack takes the decision to forcibly keep the packet because it thinkgs that it is destined to this computer # It also authorizes immediately that a new packet can be put onto the network. def layer3_incomingPDU(self, interface, pdu): time.sleep(self.__layerDelay) #TB SN On va recuperer l'expéditeur et le destinaire du pdu grâce au code fournit dans les annexes expediteur = pdu[0:1].decode('UTF-8') destinataire = pdu[1:2].decode('UTF-8') if destinataire == 'X': self.__debugOut.debugOutLayer( self.__ownIdentifier, 3, self.__debugOut.INFO, "%s: Layer3_in: tirage (%s) -> layer4_in\n" % (self.__ownIdentifier, pdu)) self.layer4_incomingPDU(None, None) #SN TB Test pour savoir si le paquet reçus est celui qu'on à envoyer elif expediteur == self.__ownIdentifier: self.layer4_incomingPDU(None, None) #SN TB Test pour savoir si on est le destinaire elif destinataire == self.__ownIdentifier: print("Nice ca") #SN TB Si oui, on envoie à la couche 4 incoming self.__debugOut.debugOutLayer( self.__ownIdentifier, 3, self.__debugOut.INFO, "%s: Layer3_in: tirage (%s) -> layer4_in\n" % (self.__ownIdentifier, pdu)) self.layer4_incomingPDU(expediteur, pdu[2:]) else: #SN TB Si non, on renvoie le paquet à la couche 2 outgoing pour transmettre le paquet au computer suivant taille = len(pdu) if taille < 10: taille = '0' + str(taille) else: taille = str(len(pdu)) pdu = taille.encode("UTF-8") + pdu self.__debugOut.debugOutLayer( self.__ownIdentifier, 3, self.__debugOut.INFO, "%s: Layer3_in: tirage (%s) -> Packet to be destroyed\n" % (self.__ownIdentifier, pdu)) self.layer2_outgoingPDU(interface, pdu) # Please adapt def layer3_outgoingPDU(self, destination, pdu): time.sleep(self.__layerDelay) # Here, we store the packet and wait until an empty token packet arrives #SN TB On récupère l'expéditeur et la destination, que l'on encode et ajoute au PDU expediteur = self.__ownIdentifier pdu = expediteur.encode("UTF-8") + destination.encode("UTF-8") + pdu #TB SN On récupère la taille et on l'ajoute au pdu taille = len(pdu) if taille < 10: taille = '0' + str(taille) else: taille = str(len(pdu)) pdu = taille.encode("UTF-8") + pdu self.__debugOut.debugOutLayer( self.__ownIdentifier, 3, self.__debugOut.INFO, "%s: Layer3_out: Sending out (%s) via interface %d " % (self.__ownIdentifier, pdu, 0)) self.layer2_outgoingPDU(0, pdu) # Please adapt def layer2_incomingPDU(self, interface, pdu): time.sleep(self.__layerDelay) self.__debugOut.debugOutLayer( self.__ownIdentifier, 2, self.__debugOut.INFO, "%s: Layer2_in: Received (%s) on Interface %d " % (self.__ownIdentifier, pdu, interface)) if interface == 0: # same ring print(pdu) self.paquetRecu = pdu if self.compteur <= 0: self.compteur = 2 self.indice = 0 self.paquetAEnvoyer = "".encode("UTF-8") #self.paquetRecu = pdu taille = self.paquetRecu[self.indice:self.indice + 2] taille = int(taille.decode('UTF-8')) self.indice += 2 pdu = self.paquetRecu[self.indice:self.indice + taille] self.indice += taille self.compteur -= 1 self.__debugOut.debugOutLayer( self.__ownIdentifier, 2, self.__debugOut.INFO, "%s: Layer2_in: tirage (%s) -> layer3_in\n" % (self.__ownIdentifier, pdu)) self.layer3_incomingPDU(interface, pdu) else: # Another Ring, this is for routing, see later pass def layer2_outgoingPDU(self, interface, pdu): if self.initToken > 0 and self.__ownIdentifier == 'A': #TB SN On regarde si on continue d'initialiser le paquet print('lol') if self.initToken >= 2: #TB SN on est pas sur le dernier slot donc on continue d'initialiser self.initToken -= 1 self.paquetAEnvoyer += pdu self.compteur -= 1 self.__debugOut.debugOutLayer( self.__ownIdentifier, 2, self.__debugOut.INFO, "%s: Layer2_out: Sending in (%s) via interface %d " % (self.__ownIdentifier, self.paquetAEnvoyer, interface)) self.application_layer_outgoingPDU(True) #TB SN On initialise le dernier slot du paquet, donc on envoie le paquet initialisé au noeud suivant elif self.initToken == 1: self.initToken -= 1 self.paquetAEnvoyer += pdu self.compteur -= 1 self.__debugOut.debugOutLayer( self.__ownIdentifier, 2, self.__debugOut.INFO, "%s: Layer2_out: Sending in (%s) via interface %d " % (self.__ownIdentifier, self.paquetAEnvoyer, interface)) self.__layerPhy.API_sendData(interface, self.paquetAEnvoyer) #self.layer2_incomingPDU(interface,self.paquetRecu) #SN TB Tant que tous les slots n'ont pas été traités elif self.compteur > 0: self.paquetAEnvoyer += pdu time.sleep(self.__layerDelay) self.__debugOut.debugOutLayer( self.__ownIdentifier, 2, self.__debugOut.INFO, "%s: Layer2_out: Sending out (%s) via interface %d " % (self.__ownIdentifier, self.paquetAEnvoyer, interface)) if self.__sendDelay != 0: self.__debugOut.debugOutLayer( self.__ownIdentifier, 2, self.__debugOut.INFO, "%s: Layer2_out: Sleeping for %ds" % (self.__ownIdentifier, self.__sendDelay)) time.sleep(self.__sendDelay) #SN TB On envoie en couche 2 incoming pour traiter le slot suivant self.layer2_incomingPDU(interface, self.paquetRecu) #SN TB tous les slots ont été traités else: self.paquetAEnvoyer += pdu #SN TB on envoie au noeud suivant self.__layerPhy.API_sendData(interface, self.paquetAEnvoyer)
class PhyMaster(object): ''' classdocs ''' def __init__(self, phyNetwork, ownIdentifier): self.__ownIdentifier = ownIdentifier self.__host = '' # We are listening on any incoming connection self.__phyNetwork = phyNetwork self.__receivedMessage = threading.Condition() self.__debugOut = DebugOut(phyNetwork) self.__globalDebugHistory = [] self.__debugSubscribers = [] self.active = False self.__commandlist = [] try: self.__masterServer = TCPServer( host=self.__host, port=self.__phyNetwork.baseport - 1, callBackReceive=self.__masterListen, callBackConnect=self.__masterConnect, callBackHandleSocketError=self.__masterSocketError) self.active = True except: self.__debugOut.debugOutLayer( self.__ownIdentifier, 1, self.__debugOut.INFO, "PhyMaster : Master Server seems to be already running") if self.active: # This is the serialized dispatch thread self.__dispatchThread = threading.Thread( target=self.__dispatchCommands) self.__dispatchThread.start() def __waitForAcknowledge(self, connection): found = False while not found: index = 0 for (thisConnection, clientAddr, line) in self.__commandlist: if thisConnection == connection: (command, separator, line) = line.partition(",") (result, separator, line) = line.partition(",") if command == "STATUS": found = True self.__commandlist.pop(index) self.__debugOut.debugOutLayer( self.__ownIdentifier, 1, self.__debugOut.INFO, "PhyMaster %s - Waited for Acknowledge and got: %s %s" % (clientAddr, result, line)) if result == "ACK": result = True else: result = False index = index + 1 if not found: numberOfCommandsPriorToWait = len(self.__commandlist) self.__receivedMessage.wait(0.1) # Check for timeout if numberOfCommandsPriorToWait == len(self.__commandlist): result = False break return result def __nodeConnect(self, node, connectNode, clientAddr, listenPort, interfaceNumber): self.__masterServer.sendConnection( connectNode.connection, ('CONNECT,%d,%s,%d\n' % (interfaceNumber, clientAddr[0], listenPort))) retval = False if not self.__waitForAcknowledge(connectNode.connection): self.__debugOut.debugOutLayer( self.__ownIdentifier, 1, self.__debugOut.INFO, "DEBUG: PhyMaster %s - connect for previous node %s failed" % (clientAddr, connectNode.clientAddr)) else: connectNode.sendInterfaceConfig[interfaceNumber] = (clientAddr[0], listenPort) retval = True return retval def __nodeDisconnect(self, node, disconnectNode, interfaceNumber): # We can also safely disconnect the current node self.__masterServer.sendConnection( disconnectNode.connection, ("DISCONNECT,%d\n" % interfaceNumber)) retval = False if not self.__waitForAcknowledge(disconnectNode.connection): self.__debugOut.debugOutLayer( self.__ownIdentifier, 1, self.__debugOut.INFO, "DEBUG: PhyMaster %s - disconnect for current node %s failed" % (node.clientAddr, disconnectNode.clientAddr)) else: disconnectNode.sendInterfaceConfig[interfaceNumber] = ('', 0) retval = True return retval def __nodeAddInterface(self, node, addInterfaceNode, interfaceNumber): (addInterfaceRingNumber, addInterfaceNodeNumber ) = self.__phyNetwork.getNodePositionByConnection( addInterfaceNode.connection) listenPort = self.__phyNetwork.getListenInterfacePort( interfaceNumber, addInterfaceRingNumber, addInterfaceNodeNumber) acknowledge = False while not acknowledge: self.__masterServer.sendConnection(addInterfaceNode.connection, ("ADDINTERFACE,%d,%d\n" % (interfaceNumber, listenPort))) acknowledge = self.__waitForAcknowledge( addInterfaceNode.connection) if not acknowledge: listenPort = listenPort + 1 addInterfaceNode.listenInterfacePorts[interfaceNumber] = listenPort return True def __nodeDelInterface(self, node, delInterfaceNode, interfaceNumber): self.__masterServer.sendConnection( delInterfaceNode.connection, ("DELINTERFACE,%d\n" % interfaceNumber)) retval = False if not self.__waitForAcknowledge(delInterfaceNode.connection): self.__debugOut.debugOutLayer( self.__ownIdentifier, 1, self.__debugOut.INFO, "DEBUG: PhyMaster %s - delinterface for current node %s failed" % (node.clientAddr, delInterfaceNode.clientAddr)) else: delInterfaceNode.listenInterfacePorts[interfaceNumber] = 0 retval = True return retval def __handleLeave(self, connection, clientAddr, assumeDisconnect=False): self.__debugOut.debugOutLayer( self.__ownIdentifier, 1, self.__debugOut.INFO, "LEAVE : Entering configuration section") thisNode = self.__phyNetwork.getNodeByConnection(connection) (ringNumber, nodeNumber ) = self.__phyNetwork.getNodePositionByConnection(connection) (previousNode, previousInterfaceNumber) = self.__phyNetwork.getPreviousNode( ringNumber, nodeNumber) (nextNode, nextInterfaceNumber) = self.__phyNetwork.getNextNode( ringNumber, nodeNumber) ringHandoverNode = None if thisNode is None: self.__debugOut.debugOutLayer( self.__ownIdentifier, 1, self.__debugOut.INFO, "DEBUG: PhyMaster %s received LEAVE request from unknown client" % (clientAddr, )) else: # We first treat interface 0 : Reconnect previous and next node # Assume, B is to be removed from the middle of A and C # We can disconnect the previous node in any case self.__nodeDisconnect(thisNode, previousNode, previousInterfaceNumber) # We can also safely disconnect the current node if not assumeDisconnect: self.__nodeDisconnect(thisNode, thisNode, 0) # We shutdown the current interface 0 which should no longer be connected in any case (even if immediate loop) if not assumeDisconnect: self.__nodeDelInterface(thisNode, thisNode, 0) # Check whether we are the last node on the ring if ringNumber > 0 and self.__phyNetwork.getRingLength( ringNumber) == 1: # then the previousNode (and the nextNode should be the connection to the lower ring if previousInterfaceNumber != 1: self.__debugOut.debugOutLayer( self.__ownIdentifier, 1, self.__debugOut.INFO, "DEBUG: PhyMaster %s - Something is strange, only one node left but previous is not on interface 1" % (clientAddr, )) else: ringHandoverNode = previousNode self.__nodeDelInterface(thisNode, previousNode, previousInterfaceNumber) else: # This is the normal case, we have at least 2 nodes left self.__nodeConnect( thisNode, previousNode, nextNode.clientAddr, nextNode.listenInterfacePorts[nextInterfaceNumber], previousInterfaceNumber) # Check whether we are the uplink node if thisNode.listenInterfacePorts[1] != 0: if self.__phyNetwork.getRingLength(ringNumber) > 1: if previousNode.listenInterfacePorts[1] != 0: self.__debugOut.debugOutLayer( self.__ownIdentifier, 1, self.__debugOut.INFO, "DEBUG: PhyMaster %s - Something is strange, there is a previous node which is an uplink but the current is uplink, too" % (clientAddr, )) else: # We need to do a Ring Handover here: Imagine, we have D2 -> D1 -> A2 with D1 being in Ring 1, the rest in Ring 2 # Then we want to handover from D1 to C1 because we remove D1 if ringHandoverNode == None: ringHandoverNode = previousNode (handoverRingNumber, handoverNodeNumber ) = self.__phyNetwork.getNodePositionByConnection( ringHandoverNode.connection) # We first enable the interface 1 on C1 self.__nodeAddInterface(thisNode, ringHandoverNode, 1) # Now we need to hand over the upper ring to the previous Node predecessorNode = self.__phyNetwork.getNodeByIndex( ringNumber + 1, -1) sucessorNode = self.__phyNetwork.getNodeByIndex( ringNumber + 1, 0) # Then we connect D2 to C1 self.__nodeDisconnect(thisNode, predecessorNode, 0) self.__nodeConnect( thisNode, predecessorNode, ringHandoverNode.clientAddr, ringHandoverNode.listenInterfacePorts[1], 0) # Now we connect C1 to A2 self.__nodeDisconnect(thisNode, thisNode, 1) self.__nodeConnect( thisNode, ringHandoverNode, sucessorNode.clientAddr, sucessorNode.listenInterfacePorts[0], 1) self.__phyNetwork.delNode(ringNumber, nodeNumber) self.__phyNetwork.API_dumpPhyNetworkState() self.__debugOut.debugOutLayer(self.__ownIdentifier, 1, self.__debugOut.INFO, "LEAVE : Leaving configuration section") def __handleEnter(self, connection, clientAddr): self.__phyNetwork.addNode(connection, clientAddr) self.__debugOut.debugOutLayer( self.__ownIdentifier, 1, self.__debugOut.INFO, "ENTER : Entering configuration section") thisNode = self.__phyNetwork.getNodeByConnection(connection) if thisNode is None: self.__debugOut.debugOutLayer( self.__ownIdentifier, 1, self.__debugOut.INFO, "DEBUG: PhyMaster %s received ENTER request from unknown client" % (clientAddr, )) else: (ringNumber, nodeNumber ) = self.__phyNetwork.getNodePositionByConnection(connection) # If this is the first node of a new Ring, we need to connect it downwards by enabling interface 1 of the lowerRing Node if nodeNumber == 0 and ringNumber > 0: lowerRingRouterNode = self.__phyNetwork.getLowerRingRouterNode( ringNumber) (lowerRingNumber, lowerRingNodeNumber ) = self.__phyNetwork.getNodePositionByConnection( lowerRingRouterNode.connection) self.__nodeAddInterface(thisNode, lowerRingRouterNode, 1) # Let's imagine we want to insert B between A and C self.__nodeAddInterface(thisNode, thisNode, 0) (previousNode, previousInterfaceNumber) = self.__phyNetwork.getPreviousNode( ringNumber, nodeNumber) # We are disconnecting A from C self.__nodeDisconnect(thisNode, previousNode, previousInterfaceNumber) # We are connecting A to B self.__nodeConnect(thisNode, previousNode, clientAddr, thisNode.listenInterfacePorts[0], previousInterfaceNumber) # We are connecting B to C (nextNode, nextInterfaceNumber) = self.__phyNetwork.getNextNode( ringNumber, nodeNumber) self.__debugOut.debugOutLayer( self.__ownIdentifier, 1, self.__debugOut.INFO, "Trying to connect %s %d " % (nextNode.clientAddr[0], nextNode.listenInterfacePorts[0])) self.__nodeConnect( thisNode, thisNode, nextNode.clientAddr, nextNode.listenInterfacePorts[nextInterfaceNumber], 0) self.__phyNetwork.API_dumpPhyNetworkState() self.__debugOut.debugOutLayer(self.__ownIdentifier, 1, self.__debugOut.INFO, "ENTER : Leaving configuration section") def __handleDebugMsg(self, connection, clientAddr, line): self.__globalDebugHistory.append(line) for (sendConnection, sendClientAddr) in self.__debugSubscribers: try: self.__masterServer.sendConnection(sendConnection, ("DEBUGMSG," + line)) except socket.error as msg: print("HandleDebugMsg - Exception caught: ", msg) self.__debugSubscribers.remove( (sendConnection, sendClientAddr)) def __handleSubscribeDebug(self, connection, clientAddr): subscribeOk = True for line in self.__globalDebugHistory: try: self.__masterServer.sendConnection(connection, ("DEBUGMSG," + line)) except socket.error as msg: print("HandleDebugMsg - Exception caught: ", msg) subscribeOk = False if subscribeOk: self.__debugSubscribers.append((connection, clientAddr)) def __dispatchCommands(self): while True: self.__receivedMessage.acquire() while len(self.__commandlist) > 0: (connection, clientAddr, thisCommand) = self.__commandlist.pop(0) (command, separator, line) = thisCommand.partition(",") if command == "ENTER": self.__handleEnter(connection, clientAddr) elif command == "LEAVE": self.__handleLeave(connection, clientAddr) elif command == "DEBUGMSG": self.__handleDebugMsg(connection, clientAddr, line) elif command == "SUBSCRIBEDEBUG": self.__handleSubscribeDebug(connection, clientAddr) else: self.__debugOut.debugOutLayer( self.__ownIdentifier, 1, self.__debugOut.INFO, "DEBUG: PhyMaster %s - Unknown Command %s" % (clientAddr, line)) self.__receivedMessage.wait() def __masterListen(self, tcpServer, connection, clientAddr, data): self.__receivedMessage.acquire() while data: (line, separator, data) = data.partition("\n") # self.__debugOut.debugOutLayer(self.__ownIdentifier,1,self.__debugOut.INFO,"DEBUG: PhyMaster %s - received %s" % (clientAddr,line)) self.__commandlist.append((connection, clientAddr, line)) self.__receivedMessage.notify() self.__receivedMessage.release() def __masterConnect(self, tcpServer, connection, clientAddr): self.__debugOut.debugOutLayer( self.__ownIdentifier, 1, self.__debugOut.INFO, "PhyMaster %s - Incoming connection" % (clientAddr, )) def __masterSocketError(self, tcpServer, connection, clientAddr): self.__debugOut.debugOutLayer( self.__ownIdentifier, 1, self.__debugOut.INFO, "PhyMaster %s - Received SocketError assuming disconnect" % (clientAddr, )) self.__receivedMessage.acquire() self.__handleLeave(connection, clientAddr, True) self.__receivedMessage.release()
# ============================================================================ # If you are using MacOS, the tkinter needs to run in the main thread macosTkinterWorkaround = True # We initialize here the debugging framework: # Each part of the computer has a debug source identifier # 0 is reserved for internal communication # 1 Is for general computer messages # 2 is for applications # 11 or layer=1 is used for the Physical Network Layer # 12 or layer=2 is used for the first network layer that is up to you to implement # # Various DebugLevels have been predefined, notably NONE, ERROR, WARNING, INFO, ALL (see Tools/DebugOut for more information) __debugOut = DebugOut() __debugOut.setDebugLevelForSource(__debugOut.srcComputer, __debugOut.NONE) __debugOut.setDebugLevelForSource(__debugOut.srcApplication, __debugOut.NONE) __debugOut.setDebugLevelForLayer(1, __debugOut.WARNING) # __debugOut.setDebugLevelForLayer(1, __debugOut.INFO) __debugOut.setDebugLevelForLayer(2, __debugOut.INFO) __debugOut.setDebugLevelForLayer(3, __debugOut.INFO) __debugOut.setDebugLevelForLayer(4, __debugOut.INFO) __debugOut.setDebugLevelForLayer(5, __debugOut.INFO) __debugOut.setDebugLevelForLayer(6, __debugOut.INFO) # This starts the graphical user interface # Computers (Nodes) are added automatically unless contained in ignoreComputers # The layerSelection determines the layers that are displayed graphically