コード例 #1
0
    def _trySendingFrame(self):
        """Send the next frame waiting in the sendBuffer, if there is any."""
        if self._transmitting:
            # Another frame is currently being transmitted. Wait for next call.
            return
        if not self._transmitQueue:
            # Nothing to transmit.
            return

        type, sn = self._transmitQueue.pop(0)
        if type == self.ACK or type == self.SREJ:
            # Create a new Ack frame and send it.
            ack = self._newFrame()
            ack.SN = self._SNmax  # Allowed since payload is empty
            ack.RN = sn
            if type == self.SREJ:
                ack.SREJ = 1
                ACTIVITY_INDICATION(self, "tx",
                                    "Send SREJ RN=%s" % str(ack.RN), "red", 0,
                                    0)
            else:
                ACTIVITY_INDICATION(self, "tx", "Send ACK RN=%s" % str(ack.RN),
                                    "grey", 0, 0)
            checksum = crc32(ack.serialize()[:-4]) & ((1L << 32) - 1)
            ack.FCS = checksum
            self._transmitting = True
            self._device.phy.send(ack.serialize())

        else:
            assert (type == self.FIRSTTR or type == self.RETR)
            # Create a new data packet and send it
            bitstream = self._sendBuffer[sn]
            frame = self._newFrame()
            frame.SN = sn
            frame.RN = self._VR
            frame.data = bitstream
            checksum = crc32(frame.serialize()[:-4]) & ((1L << 32) - 1)
            frame.FCS = checksum

            # Set the retransmission timer
            if sn in self._retransmissionTimer:
                timer = self._retransmissionTimer.pop(sn)
                CANCEL(timer)
            self._retransmissionTimer[sn] = SCHEDULE(
                self.retransmissionTimeout, self._timeout, (sn, ))

            # Send the frame and update the statistics
            if type == self.RETR:
                self.packetRetransmissions += 1
                ACTIVITY_INDICATION(self, "tx", "Retr SN=%s" % str(frame.SN),
                                    "orange", 0, 0)

            else:
                ACTIVITY_INDICATION(self, "tx", "Send SN=%s" % str(frame.SN),
                                    "yellow", 0, 0)
            self.packetsSent += 1
            self._transmitting = True
            self._device.phy.send(frame.serialize())
コード例 #2
0
 def _checkAck(self, frame):
     """Look if the frame contains an ACK and handle it."""
     if self._outstandingFrame != None:  # We are waiting for an ACK
         if frame.RN == (self._VS[frame.SrcAddr] + 1) % 2:
             # POSITIVE ACKNOWLEDGEMENT
             ACTIVITY_INDICATION(self, "rx", "ACK ok")
             self._outstandingFrame = None
             if self._retransmissionTimer:
                 CANCEL(self._retransmissionTimer)
             self._retransmissionTimer = None
             self._VS[frame.SrcAddr] = frame.RN
             self._trySendingFrame()
コード例 #3
0
    def _retransmit(self):
        """Retransmits the current frame.

        Called either because of a negative ack or by a retransmission timeout.
        """
        ACTIVITY_INDICATION(self, "tx", "Retransmit", "orange", 0, 0)
        if self._retransmissionTimer:
            CANCEL(self._retransmissionTimer)
        self._retransmissionTimer = SCHEDULE(self.retransmissionTimeout,
                                             self._timeout)
        self.packetRetransmissions += 1
        self.packetsSent += 1
        self._device.phy.send(self._sendBuffer.serialize())
コード例 #4
0
    def _retransmit(self, sn):
        """Cancel all waiting frame transmissions and resent the whole window.
        """
        # Only keep waiting acknowledgements in the transmit queue.
        self._transmitQueue = [
            el for el in self._transmitQueue if el[0] == self.ACK
        ]
        for timer in self._retransmissionTimer.values():
            CANCEL(timer)
        self._retransmissionTimer = {}

        # Place the whole window into the transmission queue
        for sn in self._sendBuffer.keys():
            bisect.insort(self._transmitQueue, (self.RETR, sn))
        self._trySendingFrame()
コード例 #5
0
    def _checkAck(self, frame):
        """Look if the frame contains an ACK or SREJ and handle it."""

        if self._SNmin == self._SNmax:
            # We do not expect a new ack.
            return

        RN = frame.RN
        if frame.SREJ:
            # This is a selective repeat request. Retransmit RN
            # if the window allows it
            if ((RN - self._SNmin) % self._SN_MOD <
                (self._SNmax - self._SNmin) % self._SN_MOD):
                ACTIVITY_INDICATION(self, "rx", "SREJ RN=%s" % str(RN))
                self._retransmit(RN)
                return

        if ((RN - self._SNmin) % self._SN_MOD >
            (self._SNmax - self._SNmin) % self._SN_MOD):
            # ACK outside window. Do nothing
            ACTIVITY_INDICATION(self, "rx", "DupACK RN=%s" % str(RN))
            return

        # RN is inside the window. In contrast to Go-back-n, it only
        # acknowledges one packet, not all packets before RN
        ACTIVITY_INDICATION(self, "rx", "Rcv ACK RN=%s" % str(RN))
        bitstream = self._sendBuffer.pop(RN, None)
        if bitstream:
            if (self.RETR, RN) in self._transmitQueue:
                self._transmitQueue.remove((self.RETR, RN))
            timer = self._retransmissionTimer.pop(RN, None)
            if timer:
                CANCEL(timer)

            # Let's see if we can move the window. Move it up to the first non
            # acknowledged packet.
            while (self._SNmin != self._SNmax
                   and self._SNmin not in self._sendBuffer):
                assert ((self.FIRSTTR, self._SNmin) not in self._transmitQueue)
                # Move the left window edge and see if we can accept new frames
                self._SNmin = (self._SNmin + 1) % self._SN_MOD
                if (self._SNmax - self._SNmin) % self._SN_MOD < self._winSize:
                    self._device.XOFF = False

            # Inform the upper layer that it can sent the next packet
            # @@@ FIXME: this is not clean. Better provide a queue
            for upperLayer in self._upperLayers:
                upperLayer.sendStatus(0, bitstream)
コード例 #6
0
    def _checkAck(self, frame):
        """Look if the frame contains an ACK and handle it."""
        if self._outstandingFrame != None:  # We are waiting for an ACK
            if frame.RN == (self._VS[frame.SrcAddr] + 1) % 2:
                # POSITIVE ACKNOWLEDGEMENT
                ACTIVITY_INDICATION(self, "rx", "ACK ok")
                self._outstandingFrame = None
                if self._retransmissionTimer:
                    CANCEL(self._retransmissionTimer)
                self._retransmissionTimer = None
                self._VS[frame.SrcAddr] = frame.RN

                # Do a backoff. *** COLLISION AVOIDANCE ***
                self._backingOff = True
                SCHEDULE(self._computeBackoff(), self._endBackoff)
                ACTIVITY_INDICATION(self, "tx", "CA backoff", "darkblue", 1, 2)
コード例 #7
0
 def _checkAck(self, frame):
     """Look if the frame contains an ACK and handle it."""
     if self._sendBuffer != None:  # We are waiting for an ACK
         if frame.RN == self._VS:
             # POSITIVE ACKNOWLEDGEMENT
             ACTIVITY_INDICATION(self, "rx", "ACK")
             bitstream = self._sendBuffer.data
             self._sendBuffer = None
             CANCEL(self._retransmissionTimer)
             self._retransmissionTimer = None
             self._device.XOFF = False  # Allow the next packet to be sent
             # Inform the upper layer that it can sent the next packet
             # @@@ FIXME: this is not clean. Better provide a queuing layer
             for upperLayer in self._upperLayers:
                 upperLayer.sendStatus(0, bitstream)
         else:
             # NEGATIVE ACKNOWLEDGEMENT. Retransmit the packet.
             ACTIVITY_INDICATION(self, "rx", "NAK")
             self._retransmit()
コード例 #8
0
    def send(self, bitstream):
        """Accept a block of data and simulate transmission on the medium.

        Called by the MAC layer to transmit a block of data. Can be called
        multiple times while Phy.transmitting is active (). In this case, if the
        previous block has not yet been completely transmitted onto the medium,
        the remaining data is discarded and the transmission continues with the
        new data. Therefore, the MAC should call this method only after having
        received a MAC.sendStatus notification or if a collision
        has been detected and the MAC wants to stop the transmission of data
        and continue with a jam signal.

        Arguments:
          bitstream:Bitstream -- Block of data to transmit onto the medium.
        Return value: None.
        """
        if self._transmitting == False:
            raise RuntimeError("Attempt to transmit without previously "
                               "activating transmission on NIU: " +
                               self._niu._node.hostname + "." +
                               self._niu.devicename + ".phy")
        if self._transmittedData == None:
            # New transmission
            self._transmittedData = bitstream
            self._transmitStartTime = TIME()
            self._niu.medium.startTransmission(self._niu)

            transmissionDelay = len(bitstream) * 8 / self._dataRate
            self._completeTxEventId = SCHEDULE(transmissionDelay,
                                               self._completeTransmission)

            if self._receiveActivities > 0:
                self._niu.mac.collisionDetect()
        else:
            # Interrupt current transmission and send new data
            bytelen = int(
                ((TIME() - self._transmitStartTime) * self._dataRate + 0.05) /
                8)
            self._transmittedData = self._transmittedData[0:bytelen] + bitstream
            CANCEL(self._completeTxEventId)
            transmissionDelay = len(bitstream) * 8 / self._dataRate
            self._completeTxEventId = SCHEDULE(transmissionDelay,
                                               self._completeTransmission)
コード例 #9
0
    def _checkAck(self, frame):
        """Look if the frame contains an ACK and handle it."""
        RN = frame.RN

        # Test if the RN is inside the window
        if self._SNmin == self._SNmax:
            # We do not expect a new ack.
            return

        if ((RN - self._SNmin) % self._SN_MOD >
            (self._SNmax - self._SNmin) % self._SN_MOD):
            # ACK outside window. Do nothing
            ACTIVITY_INDICATION(self, "rx", "DupACK RN=%s" % str(RN))
            return

        # RN is inside the window and acknowledges all frames before RN.
        # Remove the acknowledged frames from the window, transmission
        # queue and cancel the timers.
        ACTIVITY_INDICATION(self, "rx", "Rcv ACK RN=%s" % str(RN))
        while self._SNmin != RN:
            assert ((self.FIRSTTR, self._SNmin) not in self._transmitQueue)
            if (self.RETR, self._SNmin) in self._transmitQueue:
                self._transmitQueue.remove((self.RETR, self._SNmin))
            bitstream = self._sendBuffer.pop(self._SNmin)
            timer = self._retransmissionTimer.pop(self._SNmin, None)
            if timer:
                CANCEL(timer)
            # Move the left window edge and see if we can accept new frames.
            self._SNmin = (self._SNmin + 1) % self._SN_MOD
            if (self._SNmax - self._SNmin) % self._SN_MOD < self._winSize:
                self._device.XOFF = False

            # Inform the upper layer that it can sent the next packet
            # @@@ FIXME: this is not clean. Better provide a queue
            for upperLayer in self._upperLayers:
                upperLayer.sendStatus(0, bitstream)