示例#1
0
文件: tcp.py 项目: nathand8/bene
class TCP(Connection):
    ''' A TCP connection between two hosts.'''
    def __init__(self,
                 transport,
                 source_address,
                 source_port,
                 destination_address,
                 destination_port,
                 app=None,
                 window=1000):
        Connection.__init__(self, transport, source_address, source_port,
                            destination_address, destination_port, app)

        ### Sender functionality

        # send window; represents the total number of bytes that may
        # be outstanding at one time
        self.window = window
        # send buffer
        self.send_buffer = SendBuffer()
        # maximum segment size, in bytes
        self.mss = 1000
        # largest sequence number that has been ACKed so far; represents
        # the next sequence number the client expects to receive
        self.sequence = 0
        # retransmission timer
        self.timer = None
        # timeout duration in seconds
        self.timeout = 1
        # Round trip time in seconds
        self.estimated_rtt = None
        # Deviation of sample rtt from estimated rtt
        self.deviation_rtt = None

        ### Receiver functionality

        # receive buffer
        self.receive_buffer = ReceiveBuffer()
        # ack number to send; represents the largest in-order sequence
        # number not yet received
        self.ack = 0
        # a list of all the queuing delays from the sender to receiver
        self.queueing_delay_list = []

    def trace(self, message):
        ''' Print debugging messages. '''
        Sim.trace("TCP", message)

    def receive_packet(self, packet):
        ''' Receive a packet from the network layer. '''
        if packet.ack_number > 0:
            # handle ACK
            self.handle_ack(packet)
        if packet.length > 0:
            # handle data
            self.handle_data(packet)

    ''' Sender '''

    def send(self, data):
        ''' Send data on the connection. Called by the application. This
            code uses the SendBuffer to send incrementally '''
        self.send_buffer.put(data)
        self.queue_packets()

    def queue_packets(self):
        ''' Send the next set of packets if there's any to send. Limit based
            on window size and the number of outstanding packets '''
        while True:
            if self.send_buffer.available() <= 0:
                break
            if self.send_buffer.outstanding() + self.mss > self.window:
                break
            packet_data = self.send_buffer.get(self.mss)
            self.send_packet(packet_data[0], packet_data[1])

    def send_packet(self, data, sequence):
        packet = TCPPacket(source_address=self.source_address,
                           source_port=self.source_port,
                           destination_address=self.destination_address,
                           destination_port=self.destination_port,
                           body=data,
                           sequence=sequence,
                           ack_number=self.ack,
                           sent_time=Sim.scheduler.current_time())

        # send the packet
        self.trace("%s (%d) sending TCP segment to %d for %d" %
                   (self.node.hostname, self.source_address,
                    self.destination_address, packet.sequence))
        self.transport.send_packet(packet)

        # set a timer
        if not self.timer:
            self.timer = Sim.scheduler.add(delay=self.timeout,
                                           event='retransmit',
                                           handler=self.retransmit)

    def handle_ack(self, packet):
        ''' Handle an incoming ACK. '''

        # Calculate Sample RTT
        sample_rtt = Sim.scheduler.current_time() - packet.sent_time
        self.trace("sample round trip time %f" % sample_rtt)

        # Calculate the new estimated RTT
        alpha = 0.125
        if not self.estimated_rtt:
            self.estimated_rtt = sample_rtt
        else:
            self.estimated_rtt = (
                1 - alpha) * self.estimated_rtt + alpha * sample_rtt

        # Calculate the deviation of the sample RTT
        beta = 0.25
        if not self.deviation_rtt:
            self.deviation_rtt = self.estimated_rtt / 2
        else:
            self.deviation_rtt = (1 - beta) * self.deviation_rtt + beta * abs(
                sample_rtt - self.estimated_rtt)

        # Calculate the Retransmission Timeout (RTO)
        self.timeout = self.estimated_rtt + 4 * self.deviation_rtt
        self.trace("changed the timeout to %f" % self.timeout)

        self.sequence = packet.ack_number
        self.send_buffer.slide(packet.ack_number)
        self.cancel_timer()
        if self.send_buffer.outstanding() or self.send_buffer.available():
            self.timer = Sim.scheduler.add(delay=self.timeout,
                                           event='retransmit',
                                           handler=self.retransmit)
            self.queue_packets()

    def retransmit(self, event):
        ''' Retransmit data. '''
        self.trace("%s (%d) retransmission timer fired" %
                   (self.node.hostname, self.source_address))
        packet_data = self.send_buffer.resend(self.mss)
        self.send_packet(packet_data[0], packet_data[1])
        self.timeout = self.timeout * 2
        self.trace("doubled the timeout to %f" % self.timeout)
        self.timer = Sim.scheduler.add(delay=self.timeout,
                                       event='retransmit',
                                       handler=self.retransmit)

    def cancel_timer(self):
        ''' Cancel the timer. '''
        if not self.timer:
            return
        Sim.scheduler.cancel(self.timer)
        self.timer = None

    ''' Receiver '''

    def handle_data(self, packet):
        ''' Handle incoming data. This code currently gives all data to
            the application, regardless of whether it is in order, and sends
            an ACK.'''
        self.queueing_delay_list.append(packet.queueing_delay)
        self.trace("%s (%d) received TCP segment from %d for %d" %
                   (self.node.hostname, packet.destination_address,
                    packet.source_address, packet.sequence))
        self.receive_buffer.put(packet.body, packet.sequence)
        data = self.receive_buffer.get()
        self.ack = len(data[0]) + data[1]
        self.app.receive_data(data[0])
        self.send_ack(packet.sent_time)

    def send_ack(self, packet_sent_time=0):
        ''' Send an ack. '''
        packet = TCPPacket(source_address=self.source_address,
                           source_port=self.source_port,
                           destination_address=self.destination_address,
                           destination_port=self.destination_port,
                           sequence=self.sequence,
                           ack_number=self.ack,
                           sent_time=packet_sent_time)
        # send the packet
        self.trace("%s (%d) sending TCP ACK to %d for %d" %
                   (self.node.hostname, self.source_address,
                    self.destination_address, packet.ack_number))
        self.transport.send_packet(packet)
示例#2
0
文件: tcp.py 项目: nathand8/bene
class TCP(Connection):
    ''' A TCP connection between two hosts.'''
    def __init__(self,
                 transport,
                 source_address,
                 source_port,
                 destination_address,
                 destination_port,
                 app=None,
                 window=1000,
                 threshold=100000,
                 fast_recovery=False,
                 aiad=False,
                 aimdc=0.5):
        Connection.__init__(self, transport, source_address, source_port,
                            destination_address, destination_port, app)

        ### Sender functionality

        # send window; represents the total number of bytes that may
        # be outstanding at one time (cwnd)
        self.window = window
        # send buffer
        self.send_buffer = SendBuffer()
        # maximum segment size, in bytes
        self.mss = 1000
        # largest sequence number that has been ACKed so far; represents
        # the next sequence number the client expects to receive
        self.sequence = 0
        # retransmission timer
        self.timer = None
        # timeout duration in seconds
        self.timeout = 1
        # Round trip time in seconds
        self.estimated_rtt = None
        # Deviation of sample rtt from estimated rtt
        self.deviation_rtt = None
        # State determines slow start vs. additive increase
        # 0 = slow start
        # 1 = additive increase
        self.state = 0
        # Threshold for slow start
        self.threshold = threshold
        self.trace("Threshold starting at %d" % self.threshold)
        # Same ack count (used for calculating three duplicate acks)
        self.same_ack_count = 0
        # Most recent ack (used for calculating three duplicate acks)
        self.last_ack = None
        # Make sure settings start with slow start
        self.window = self.mss

        # Used when dropping certain packets
        self.dropped_count = 0

        # Fast Recovery (Reno)
        self.fast_recovery = fast_recovery

        # AIAD
        self.aiad = aiad

        # AIMD Constant
        self.aimdc = aimdc

        ### Used to make TCP Sequence Graphs

        self.x = []
        self.y = []
        self.dropX = []
        self.dropY = []
        self.ackX = []
        self.ackY = []

        ### Used to make window size graphs

        self.window_x = []
        self.window_y = []

        ### Receiver functionality

        # receive buffer
        self.receive_buffer = ReceiveBuffer()
        # ack number to send; represents the largest in-order sequence
        # number not yet received
        self.ack = 0
        # a list of all the queuing delays from the sender to receiver
        self.queueing_delay_list = []
        # keep track of when packets were received
        self.packets_received = {}

    def trace(self, message):
        ''' Print debugging messages. '''
        Sim.trace("TCP", message)

    def receive_packet(self, packet):
        ''' Receive a packet from the network layer. '''
        if packet.ack_number > 0:
            # handle ACK
            self.handle_ack(packet)
        if packet.length > 0:
            # handle data
            self.handle_data(packet)

    ''' Sender '''

    # Record the current time and congestion window size
    def recordWindow(self):
        self.window_x.append(Sim.scheduler.current_time())
        self.window_y.append(self.window)

    # Record packets sent for plotting purposes
    def recordPacketSent(self, time, sequence):
        self.x.append(time)
        self.y.append((sequence / 1000) % 50)

    # Record packets dropped for plotting purposes
    def recordPacketDropped(self, time, sequence):
        self.dropX.append(time)
        self.dropY.append((sequence / 1000) % 50)

    # Record acks received for plotting purposes
    def recordAckReceived(self, time, sequence):
        self.ackX.append(time)
        self.ackY.append((sequence / 1000) % 50)

    def send(self, data):
        ''' Send data on the connection. Called by the application. This
            code uses the SendBuffer to send incrementally '''
        self.send_buffer.put(data)
        self.queue_packets()

    def queue_packets(self):
        ''' Send the next set of packets if there's any to send. Limit based
            on window size and the number of outstanding packets '''
        while True:
            if self.send_buffer.available() <= 0:
                break
            open_window_space = self.window - self.send_buffer.outstanding()
            if open_window_space <= 0:
                break
            # Send nice MSS sized packets
            if open_window_space < self.mss:
                break
            packet_size = min(open_window_space, self.mss)
            packet_data = self.send_buffer.get(packet_size)
            self.send_packet(packet_data[0], packet_data[1])

    def send_packet(self, data, sequence):
        packet = TCPPacket(source_address=self.source_address,
                           source_port=self.source_port,
                           destination_address=self.destination_address,
                           destination_port=self.destination_port,
                           body=data,
                           sequence=sequence,
                           ack_number=self.ack,
                           sent_time=Sim.scheduler.current_time())

        # Forced Loss, loss, AIMD dropped packets
        drop_list = []
        #drop_list = [32000] # For a single loss
        #drop_list = [32000, 33000, 34000] # For burst loss
        if sequence in drop_list and self.dropped_count < len(drop_list):
            self.trace("Manually dropping packet %d" % sequence)
            packet.drop = True

        if packet.drop:
            # manually drop packets
            self.dropped_count += 1
            self.recordPacketDropped(Sim.scheduler.current_time(),
                                     packet.sequence)

        else:
            # send the packet
            self.trace("%s (%d) sending TCP segment to %d for %d" %
                       (self.node.hostname, self.source_address,
                        self.destination_address, packet.sequence))
            self.transport.send_packet(packet)
            self.recordPacketSent(Sim.scheduler.current_time(),
                                  packet.sequence)

        # set a timer
        if not self.timer:
            self.timer = Sim.scheduler.add(delay=self.timeout,
                                           event='retransmit',
                                           handler=self.retransmit)

    def slow_start(self, duplicate_acks=False):

        # if the AIAD setting is turned on
        if self.aiad:
            self.window -= self.mss
            self.state = 1

        # otherwise do regular recovery
        else:
            if duplicate_acks and self.fast_recovery:
                # If using fast recovery and three duplicate acks are detected,
                # set the window to self.aimdc (AIMD constant) of the original and
                # keep going with additive increase
                self.window = int(
                    round(self.window * self.aimdc / self.mss) * self.mss)
                self.state = 1
            else:
                # Otherwise reset the window to 1 mss and use slow start
                self.window = self.mss
                self.state = 0
        self.recordWindow()

    def increaseWindow(self, packet):
        # Increase the window
        if self.state == 0:
            # Slow Start
            self.window += packet.ack_packet_length
            self.trace(
                "Slow Start - Incremented window by %d. New window size: %d" %
                (packet.ack_packet_length, self.window))
            # If the window equals or exceeds the threshold, stop slow start
            if self.window >= self.threshold:
                self.trace(
                    "Hit threshold of %d. Switching from slow start to additive increase"
                    % self.threshold)
                self.state = 1
        elif self.state == 1:
            #Additive increase
            # "increment cwnd by MSS*b/cwnd"
            increment = self.mss * packet.ack_packet_length / self.window
            self.window += increment
            self.trace(
                "Additive Increase - Incremented window by %d. New window size: %d"
                % (increment, self.window))
        self.recordWindow()

    def calculateRTO(self, packet):
        # Calculate Sample RTT
        sample_rtt = Sim.scheduler.current_time() - packet.sent_time
        #self.trace("sample round trip time %f" % sample_rtt)

        # Calculate the new estimated RTT
        alpha = 0.125
        if not self.estimated_rtt:
            self.estimated_rtt = sample_rtt
        else:
            self.estimated_rtt = (
                1 - alpha) * self.estimated_rtt + alpha * sample_rtt

        # Calculate the deviation of the sample RTT
        beta = 0.25
        if not self.deviation_rtt:
            self.deviation_rtt = self.estimated_rtt / 2
        else:
            self.deviation_rtt = (1 - beta) * self.deviation_rtt + beta * abs(
                sample_rtt - self.estimated_rtt)

        # Calculate the Retransmission Timeout (RTO)
        self.timeout = self.estimated_rtt + 4 * self.deviation_rtt
        #self.trace("changed the timeout to %f" % self.timeout)

    def slideWindow(self, packet):
        self.sequence = packet.ack_number
        self.send_buffer.slide(packet.ack_number)

    def sendNextBatch(self):
        self.cancel_timer()
        if self.send_buffer.outstanding() or self.send_buffer.available():
            self.timer = Sim.scheduler.add(delay=self.timeout,
                                           event='retransmit',
                                           handler=self.retransmit)
            self.queue_packets()

    def handle_ack(self, packet):
        ''' Handle an incoming ACK. '''

        self.trace("received TCP ACK for %d" % packet.ack_number)

        # For sequence chart plotting
        self.recordAckReceived(Sim.scheduler.current_time(), packet.ack_number)

        # Calculate RTO
        self.calculateRTO(packet)

        # Watch for three duplicate acks
        if self.last_ack != packet.ack_number:
            # If a new ack is received
            self.last_ack = packet.ack_number
            self.same_ack_count = 1
            self.increaseWindow(packet)
            self.slideWindow(packet)
            self.sendNextBatch()
        else:
            # A duplicate ack has been received
            self.same_ack_count += 1
            if self.same_ack_count > 3:
                # When the fourth ack with the same number is received (3 duplicates)
                self.trace(
                    "Three duplicate ACKs. Ignoring duplicate ACKs for same sequence number"
                )
                self.same_ack_count = -100
                self.threshold = max(self.window / 2, self.mss)
                self.trace("Set new threshold to %d" % self.threshold)
                self.cancel_timer()
                self.retransmit({}, duplicate_acks=True)

    def retransmit(self, event, duplicate_acks=False):
        ''' Retransmit data. '''
        if duplicate_acks:
            self.trace("%s (%d) retransmission timer fired" %
                       (self.node.hostname, self.source_address))
        else:
            self.trace(
                "%s (%d) Three duplicate acks detected. Retransmitting immediately"
                % (self.node.hostname, self.source_address))

        self.trace("Slow start initiated")
        self.slow_start(duplicate_acks=duplicate_acks)
        packet_data = self.send_buffer.resend(self.mss)
        self.send_packet(packet_data[0], packet_data[1])
        self.timeout = min(self.timeout * 2,
                           3600)  # should never exceed an hour
        self.trace("doubled the timeout to %f" % self.timeout)
        # CANCEL TIMER BEFORE SETTING A NEW ONE?
        self.cancel_timer()
        open_window_space = self.window - self.send_buffer.outstanding()
        if self.send_buffer.outstanding() or self.send_buffer.available():
            self.timer = Sim.scheduler.add(delay=self.timeout,
                                           event='retransmit',
                                           handler=self.retransmit)

    def cancel_timer(self):
        ''' Cancel the timer. '''
        if not self.timer:
            return
        try:
            Sim.scheduler.cancel(self.timer)
        except ValueError:
            self.trace("Tried to cancel same timer twice")
        self.timer = None

    ''' Receiver '''

    def handle_data(self, packet):
        ''' Handle incoming data. This code currently gives all data to
            the application, regardless of whether it is in order, and sends
            an ACK.'''
        self.queueing_delay_list.append(packet.queueing_delay)
        self.trace("%s (%d) received TCP segment from %d for %d" %
                   (self.node.hostname, packet.destination_address,
                    packet.source_address, packet.sequence))
        self.receive_buffer.put(packet.body, packet.sequence)
        data = self.receive_buffer.get()
        self.ack = len(data[0]) + data[1]
        self.app.receive_data(data[0])
        self.send_ack(packet.sent_time, packet.length)
        self.increase_packet_count()

    def increase_packet_count(self):
        t = Sim.scheduler.current_time()
        t = "{0:0.1f}".format(math.floor(t * 10) / 10.0)
        c = self.packets_received.get(t)
        if not c:
            self.packets_received[t] = 0
        self.packets_received[t] += 1

    def send_ack(self, packet_sent_time=0, packet_length=0):
        ''' Send an ack. '''
        packet = TCPPacket(source_address=self.source_address,
                           source_port=self.source_port,
                           destination_address=self.destination_address,
                           destination_port=self.destination_port,
                           sequence=self.sequence,
                           ack_number=self.ack,
                           sent_time=packet_sent_time,
                           ack_packet_length=packet_length)
        # send the packet
        self.trace("%s (%d) sending TCP ACK to %d for %d" %
                   (self.node.hostname, self.source_address,
                    self.destination_address, packet.ack_number))
        self.transport.send_packet(packet)
示例#3
0
class TCP(Connection):
    """ A TCP connection between two hosts."""
    def __init__(self,
                 transport,
                 source_address,
                 source_port,
                 destination_address,
                 destination_port,
                 app=None,
                 window=1000,
                 fastRetransmit=False):
        Connection.__init__(self, transport, source_address, source_port,
                            destination_address, destination_port, app)

        # -- Sender functionality

        # send window; represents the total number of bytes that may
        # be outstanding at one time
        self.window = window
        # send buffer
        self.send_buffer = SendBuffer()
        # maximum segment size, in bytes
        self.mss = 1000
        # largest sequence number that has been ACKed so far; represents
        # the next sequence number the client expects to receive
        self.sequence = 0
        # retransmission timer
        self.timer = None
        # timeout duration in seconds
        self.timeout = 1

        # -- Receiver functionality
        self.fastRetransmit = fastRetransmit
        self.sameAcks = 0
        # receive buffer
        self.receive_buffer = ReceiveBuffer()
        # ack number to send; represents the largest in-order sequence
        # number not yet received
        self.ack = 0

    def trace(self, message):
        """ Print debugging messages. """
        Sim.trace("TCP", message)

    def receive_packet(self, packet):
        """ Receive a packet from the network layer. """
        if packet.ack_number > 0:
            # handle ACK
            self.handle_ack(packet)
        if packet.length > 0:
            # handle data
            self.handle_data(packet)

    ''' Sender '''

    # make sure timer hasn't been added already
    def send(self, data):
        """ Send data on the connection. Called by the application. This
            code currently sends all data immediately. """
        self.send_buffer.put(data)
        self.sendFullWindow()
        self.maybe_start_timer()

    def send_packet(self, data, sequence):
        packet = TCPPacket(source_address=self.source_address,
                           source_port=self.source_port,
                           destination_address=self.destination_address,
                           destination_port=self.destination_port,
                           body=data,
                           sequence=sequence,
                           ack_number=self.ack)

        # send the packet
        self.trace("%s (%d) sending TCP segment to %d for %d" %
                   (self.node.hostname, self.source_address,
                    self.destination_address, packet.sequence))
        self.transport.send_packet(packet)

# TODO: might have broken this by commenting it out.
# # set a timer
# if not self.timer:
#     self.timer = Sim.scheduler.add(delay=self.timeout, event='retransmit', handler=self.retransmit)

    def handle_ack(self, packet):
        """ Handle an incoming ACK. """
        self.trace("%s (%d) received TCP ACK from %d for %d current seq %d" %
                   (self.node.hostname, packet.destination_address,
                    packet.source_address, packet.ack_number, self.sequence))
        if packet.ack_number > self.sequence:
            self.sequence = packet.ack_number
            self.cancel_timer()
            self.send_buffer.slide(self.sequence)
            self.maybe_start_timer()
            self.sendFullWindow()
            self.sameAcks = 1
        elif self.fastRetransmit and packet.ack_number == self.sequence:
            self.sameAcks += 1
            if self.sameAcks == 4:
                self.trace('retransmitting')
                self.cancel_timer()
                self.resetWindow()

    def resetWindow(self):
        """ resets the window and sends all data available in the window """
        (data, sequence) = self.send_buffer.resend(self.mss)
        if len(data) > 0:
            self.maybe_start_timer()
            self.send_packet(data, sequence)

    def sendFullWindow(self):
        """ sends all data left in the window """
        while self.send_buffer.outstanding() < self.window:
            (data, seq) = self.send_buffer.get(self.mss)
            if len(data) == 0:
                return
            self.send_packet(data, seq)

# modify this code

    def retransmit(self, event):
        """ Retransmit data. """
        self.trace("%s (%d) retransmission timer fired" %
                   (self.node.hostname, self.source_address))
        self.timer = None
        self.resetWindow()

# should work

    def cancel_timer(self):
        """ Cancel the timer. """
        self.trace('canceling timer')
        if not self.timer:
            return
        Sim.scheduler.cancel(self.timer)
        self.timer = None

    def maybe_start_timer(self):
        """ Starts timer if it doesn't exist """
        self.trace('maybe starting timer')
        if not self.timer and self.send_buffer.dataRemaining():
            self.trace('starting timer')
            self.timer = Sim.scheduler.add(delay=self.timeout,
                                           event='retransmit',
                                           handler=self.retransmit)
        else:
            self.trace('timer not started')

    ''' Receiver '''

    # get this to work correctly
    def handle_data(self, packet):
        """ Handle incoming data. This code currently gives all data to
            the application, regardless of whether it is in order, and sends
            an ACK."""
        self.trace("%s (%d) received TCP segment from %d for %d" %
                   (self.node.hostname, packet.destination_address,
                    packet.source_address, packet.sequence))
        self.receive_buffer.put(packet.body, packet.sequence)
        (data, seq) = self.receive_buffer.get()
        if len(data) > 0:
            self.app.receive_data(data)
            self.ack += len(data)
        self.send_ack()

# should work

    def send_ack(self):
        """ Send an ack. """
        packet = TCPPacket(source_address=self.source_address,
                           source_port=self.source_port,
                           destination_address=self.destination_address,
                           destination_port=self.destination_port,
                           sequence=self.sequence,
                           ack_number=self.ack)
        # send the packet
        self.transport.send_packet(packet)
        self.trace("%s (%d) sending TCP ACK to %d for %d" %
                   (self.node.hostname, self.source_address,
                    self.destination_address, packet.ack_number))
示例#4
0
文件: tcpaiad.py 项目: StevenC4/bene
class TCP(Connection):
    """ A TCP connection between two hosts."""

    def __init__(
        self,
        transport,
        source_address,
        source_port,
        destination_address,
        destination_port,
        app=None,
        window=1000,
        dynamic_rto=True,
        type="Tahoe",
        window_size_plot=False,
        sequence_plot=False,
        receiver_flow_plot=False,
    ):
        Connection.__init__(self, transport, source_address, source_port, destination_address, destination_port, app)

        ### Sender functionality

        # send window; represents the total number of bytes that may
        # be outstanding at one time
        self.window = default_mss
        # send buffer
        self.send_buffer = SendBuffer()
        # maximum segment size, in bytes
        self.mss = default_mss
        # largest sequence number that has been ACKed so far; represents
        # the next sequence number the client expects to receive
        self.sequence = 0
        # retransmission timer
        self.timer = None
        # timeout duration in seconds
        self.timeout = 1

        self.threshold = 100000

        self.ack_received_count = {}
        self.wait_for_timeout = False

        self.reno_fast_recovery = type == "Reno"

        # constants
        self.k = 4
        self.g = 0.1
        self.alpha = 1 / 8
        self.beta = 1 / 4

        self.dynamic_rto = dynamic_rto
        self.rto = 3
        self.srtt = None
        self.rttvar = None

        ### Receiver functionality

        # receive buffer
        self.receive_buffer = ReceiveBuffer()
        # ack number to send; represents the largest in-order sequence
        # number not yet received
        self.ack = 0

        self.window_size_plot = window_size_plot
        self.sequence_plot = sequence_plot
        self.receiver_flow_plot = receiver_flow_plot

        self.decisecond_received = 0
        self.decisecond_bytes = []

    def trace(self, message):
        """ Print debugging messages. """
        Sim.trace("TCP", message)

    def receive_packet(self, packet):
        """ Receive a packet from the network layer. """
        if packet.ack_number > 0:
            # handle ACK
            self.handle_ack(packet)
        if packet.length > 0:
            # handle data
            self.handle_data(packet)

    """ Sender """

    def send(self, data):
        """ Send data on the connection. Called by the application. This
            code currently sends all data immediately. """
        self.send_buffer.put(data)
        self.send_packets_if_possible()

    def send_packets_if_possible(self):
        # if self.send_buffer.outstanding() < self.window:
        while self.send_buffer.outstanding() < self.window and self.send_buffer.available():
            data_length = min(self.window - self.send_buffer.outstanding(), self.mss)
            data_tuple = self.send_buffer.get(data_length)
            data = data_tuple[0]
            self.sequence = data_tuple[1]
            self.send_packet(data, self.sequence)

    def send_packet(self, data, sequence):
        packet = TCPPacket(
            source_address=self.source_address,
            source_port=self.source_port,
            destination_address=self.destination_address,
            destination_port=self.destination_port,
            body=data,
            sequence=sequence,
            ack_number=self.ack,
        )
        packet.created = Sim.scheduler.current_time()

        # Store data for plotting
        if self.sequence_plot:
            self.app.add_plot_data(Sim.scheduler.current_time(), sequence, "Transmitted")

        # send the packet
        self.trace(
            "%s (%d) sending TCP segment to %d for %d"
            % (self.node.hostname, self.source_address, self.destination_address, packet.sequence)
        )
        self.transport.send_packet(packet)

        # set a timer
        if not self.timer:
            self.timer = Sim.scheduler.add(delay=self.rto, event="retransmit", handler=self.retransmit)

    def handle_ack(self, packet):
        """ Handle an incoming ACK. """

        r = Sim.scheduler.current_time() - packet.created
        if not self.srtt and not self.rttvar:
            self.srtt = r
            self.rttvar = r / 2
        else:
            self.rttvar = (1 - self.beta) * self.rttvar + (self.beta * abs(self.srtt - r))
            self.srtt = (1 - self.alpha) * self.srtt + (self.alpha * r)
        self.rto = self.srtt + max(self.g, self.k * self.rttvar)

        self.trace(
            "%s (%d) receiving TCP ACK from %d for %d"
            % (self.node.hostname, self.source_address, self.destination_address, packet.ack_number)
        )

        self.cancel_timer()

        # Slide the buffer and get the number of new bytes acked - only if the ack number is >= the base of the send buffer
        old_unacked = self.send_buffer.outstanding()
        if packet.ack_number < self.send_buffer.base:
            return

        self.send_buffer.slide(packet.ack_number)
        new_unacked = self.send_buffer.outstanding()
        new_acked_data = max(old_unacked - new_unacked, 0)

        if packet.ack_number not in self.ack_received_count:
            self.ack_received_count[packet.ack_number] = 0
        self.ack_received_count[packet.ack_number] += 1

        # If this is the fourth ack with the same number that you are receiving, fast retransmit
        if self.ack_received_count[packet.ack_number] == 4 and not self.wait_for_timeout:
            # Sim.scheduler.cancel(self.timer)
            self.wait_for_timeout = True
            self.retransmit(True, True)
        # Otherwise, if the window is less than the threshold, slow start increase the window size
        elif self.window < self.threshold:
            self.window += new_acked_data
            # Store data for plotting
            if self.sequence_plot:
                self.app.add_plot_data(Sim.scheduler.current_time(), packet.ack_number, "Acked")
        # Otherwise, additive increase the window size
        else:
            self.window += (self.mss * new_acked_data) / self.window
            if self.sequence_plot:
                self.app.add_plot_data(Sim.scheduler.current_time(), packet.ack_number, "Acked")

        if self.window_size_plot:
            self.app.add_plot_data(Sim.scheduler.current_time(), self.window, "WindowSize")

        self.send_packets_if_possible()

        if self.send_buffer.outstanding() and not self.timer:
            self.timer = Sim.scheduler.add(delay=self.rto, event="retransmit", handler=self.retransmit)

    def retransmit(self, event, duplicate_ack=False):
        """ Retransmit data. """

        self.threshold = max(self.threshold - self.mss, self.mss)
        self.window = self.mss

        self.timer = None
        self.trace("%s (%d) entering fast retransmission" % (self.node.hostname, self.source_address))
        data_tuple = self.send_buffer.resend(self.window)  # TODO: Make this bigger, I think
        data = data_tuple[0]

        if data:
            self.sequence = data_tuple[1]

            # Store data for plotting
            if self.sequence_plot:
                self.app.add_plot_data(Sim.scheduler.current_time(), self.sequence, "Dropped")

            self.timer = Sim.scheduler.add(delay=self.rto, event="retransmit", handler=self.retransmit)
            self.send_packet(data, self.sequence)

    def cancel_timer(self):
        """ Cancel the timer. """
        if not self.timer:
            return
        Sim.scheduler.cancel(self.timer)
        self.timer = None

    """ Receiver """

    def handle_data(self, packet):
        """ Handle incoming data. This code currently gives all data to
            the application, regardless of whether it is in order, and sends
            an ACK."""
        self.trace(
            "%s (%d) received TCP segment from %d for %d"
            % (self.node.hostname, packet.destination_address, packet.source_address, packet.sequence)
        )
        self.receive_buffer.put(packet.body, packet.sequence)

        # For throughput
        self.decisecond_received += len(packet.body)

        data_tuple = self.receive_buffer.get()
        data = data_tuple[0]
        sequence = data_tuple[1]
        if data:
            self.app.receive_data(data)
            self.ack = sequence + len(data)

        self.send_ack(packet.created)

    def spur_plot_data_submission(self):
        if not self.receiver_flow_plot:
            return

        self.decisecond_bytes.append(self.decisecond_received)
        self.decisecond_received = 0
        if len(self.decisecond_bytes) >= 10:
            total_bytes_previous_second = sum(
                self.decisecond_bytes[(len(self.decisecond_bytes) - 10) : len(self.decisecond_bytes)]
            )
        else:
            total_bytes_previous_second = sum(self.decisecond_bytes)
        self.app.add_plot_data(Sim.scheduler.current_time(), total_bytes_previous_second, "ReceiverRate")

    def send_ack(self, created):
        """ Send an ack. """
        packet = TCPPacket(
            source_address=self.source_address,
            source_port=self.source_port,
            destination_address=self.destination_address,
            destination_port=self.destination_port,
            sequence=self.sequence,
            ack_number=self.ack,
        )
        packet.created = created
        # send the packet
        self.trace(
            "%s (%d) sending TCP ACK to %d for %d"
            % (self.node.hostname, self.source_address, self.destination_address, packet.ack_number)
        )
        self.transport.send_packet(packet)
示例#5
0
class TCP(Connection):
    """ A TCP connection between two hosts."""

    def __init__(self, transport, source_address, source_port,
                 destination_address, destination_port, app=None, window=1000,drop=[]):
        Connection.__init__(self, transport, source_address, source_port,
                            destination_address, destination_port, app)

        # -- Sender functionality

        # send window; represents the total number of bytes that may
        # be outstanding at one time
        self.window = window
        # send buffer
        self.send_buffer = SendBuffer()
        # maximum segment size, in bytes
        self.mss = 1000
        # largest sequence number that has been ACKed so far; represents
        # the next sequence number the client expects to receive
        self.sequence = 0
        # plot sequence numbers
        self.plot_sequence_header()
        # plot congestion window headers
        self.plot_window_header()
        # packets to drop
        self.drop = drop
        self.dropped = []
        # retransmission timer
        self.timer = None
        # timeout duration in seconds
        self.timeout = 1
        # RTO calculation variables
        self.rto = 1
        self.srtt = 0
        self.rttvar = 0
        # Variables for handling fast retransmit
        self.fast_enable = False
        self.last_ack = 0
        self.same_ack_count = 0
        self.fast_retransmitted = False
        # Congestion control
        self.threshold = 100000
        self.increment = 0

        # -- Receiver functionality

        # receive buffer
        self.receive_buffer = ReceiveBuffer()
        # ack number to send; represents the largest in-order sequence
        # number not yet received
        self.ack = 0

    def trace(self, message):
        """ Print debugging messages. """
        Sim.trace("TCP", message)

    def plot_sequence_header(self):
        if self.node.hostname =='n1':
            Sim.plot('sequence.csv','Time,Sequence Number,Event\n')

    def plot_sequence(self,sequence,event):
        if self.node.hostname =='n1':
            Sim.plot('sequence.csv','%s,%s,%s\n' % (Sim.scheduler.current_time(),sequence,event))

    def plot_window_header(self):
        if self.node.hostname == 'n1':
            Sim.plot('cwnd.csv','Time,Congestion Window,Threshold,Event\n')

    def plot_window(self, event):
        if self.node.hostname == 'n1':
            Sim.plot('cwnd.csv', '%s,%s,%s,%s\n' % (Sim.scheduler.current_time(), self.window, self.threshold, event))

    def receive_packet(self, packet):
        """ Receive a packet from the network layer. """
        if packet.ack_number > 0:
            # handle ACK
            self.handle_ack(packet)
        if packet.length > 0:
            # handle networks
            self.handle_data(packet)

    def set_fast_retransmit_enabled(self, val):
        self.fast_enable = val

    ''' Sender '''

    def send(self, data):
        """ Send networks on the connection. Called by the application. This code puts the
        networks to send in a send buffer that handles when the networks will be sent."""
        # Put the networks in the send buffer
        self.send_buffer.put(data)
        # Check for available bytes to send
        while self.send_buffer.available() != 0 and self.send_buffer.outstanding() < self.window:
            # Only send as many bytes as the window allows
            send_data, sequence = self.send_buffer.get(self.mss)
            self.send_packet(send_data, sequence)
            # set a timer
            if self.timer is None:
                self.timer = Sim.scheduler.add(delay=self.timeout, event='retransmit', handler=self.retransmit)

    def send_packet(self, data, sequence):
        packet = TCPPacket(source_address=self.source_address,
                           source_port=self.source_port,
                           destination_address=self.destination_address,
                           destination_port=self.destination_port,
                           body=data,
                           sequence=sequence, ack_number=self.ack)

        if sequence in self.drop and not sequence in self.dropped:
            self.dropped.append(sequence)
            self.plot_sequence(sequence,'drop')
            self.trace("%s (%d) dropping TCP segment to %d for %d" % (
                self.node.hostname, self.source_address, self.destination_address, packet.sequence))
            return

        # send the packet
        self.plot_sequence(sequence,'send')
        self.trace("%s (%d) sending TCP segment to %d for %d" % (
            self.node.hostname, self.source_address, self.destination_address, packet.sequence))
        self.transport.send_packet(packet)

        # set a timer
        if self.timer is None:
            self.timer = Sim.scheduler.add(delay=self.timeout, event='retransmit', handler=self.retransmit)

    def handle_ack(self, packet):
        """ Handle an incoming ACK. """
        self.plot_sequence(packet.ack_number - 1000,'ack')
        self.trace("%s (%d) received ACK from %d for %d" % (
            self.node.hostname, packet.destination_address, packet.source_address, packet.ack_number))

        # Handle fast retransmit
        if self.fast_enable:
            if packet.ack_number == self.last_ack:
                self.same_ack_count += 1
                if self.same_ack_count == 3 and not self.fast_retransmitted:
                    self.fast_retransmit(packet)
                    return
            else:
                # Reset fast retransmit variables
                self.same_ack_count = 0
                self.last_ack = packet.ack_number
                self.fast_retransmitted = False

        # Congestion control
        if self.window >= self.threshold:
            self.additive_increase(packet.ack_number - self.sequence)
        else:
            self.slow_start(packet.ack_number - self.sequence)


        # Update the send buffer
        self.sequence = packet.ack_number
        self.send_buffer.slide(packet.ack_number)
        # Send additional bytes from the send buffer if there are any
        while self.send_buffer.available() != 0 and self.send_buffer.outstanding() < self.window:
            # Only send as many bytes as the window allows
            send_data, sequence = self.send_buffer.get(self.mss)
            self.send_packet(send_data, sequence)

        # Calculate the SRTT and RTTVAR
        if self.srtt == 0:
            # First estimate
            self.srtt = Sim.scheduler.current_time() - packet.created
            self.rttvar = self.srtt / 2.0
        else:
            r = Sim.scheduler.current_time() - packet.created
            alpha = 0.125
            beta = 0.25
            self.rttvar = (1 - beta) * self.rttvar + beta * abs(self.srtt - r)
            self.srtt = (1 - alpha) * self.srtt + alpha * r
        # Update the RTO
        rto = self.srtt + 4 * self.rttvar
        self.rto = rto if rto >= 1.0 else 1.0

        self.cancel_timer()
        if self.send_buffer.outstanding() != 0:
            self.timer = Sim.scheduler.add(delay=self.timeout, event='retransmit', handler=self.retransmit)

    def fast_retransmit(self, packet):
        """ Retransmit networks. """
        self.trace("%s (%d) sending fast retransmit to %d for %d" % (
            self.node.hostname, packet.destination_address, packet.source_address, packet.ack_number))
        self.cancel_timer()
        self.threshold = max(self.window // 2, self.mss)
        self.threshold = self.threshold - (self.threshold % self.mss)
        self.window = self.mss
        self.increment = 0
        self.plot_window('fast retransmit')
        data, sequence = self.send_buffer.resend(self.window)
        if len(data) == 0:
            return
        self.send_packet(data, sequence)
        if self.timer is None:
            self.timer = Sim.scheduler.add(delay=self.timeout, event='retransmit', handler=self.retransmit)
        self.fast_retransmitted = True

    def retransmit(self, event):
        """ Retransmit networks. """
        self.trace("%s (%d) retransmission timer fired" % (self.node.hostname, self.source_address))
        self.threshold = max(self.window // 2, self.mss)
        self.threshold = self.threshold - (self.threshold % self.mss)
        self.window = self.mss
        self.increment = 0
        self.plot_window('retransmission')
        data, sequence = self.send_buffer.resend(self.window)
        # Handle the case when we get a misfire on retransmission and their isn't any data left
        # in the send buffer
        if len(data) == 0:
            self.cancel_timer()
            return
        self.send_packet(data, sequence)
        self.timer = Sim.scheduler.add(delay=self.rto, event='retransmit', handler=self.retransmit)

    def slow_start(self, bytes):
        self.trace("%s (%d) incrementing slow start" % (self.node.hostname, self.source_address))
        self.window = self.window + (bytes if bytes <= self.mss else self.mss)
        self.plot_window('slow start')

    def additive_increase(self, bytes):
        self.increment = self.increment +  bytes * self.mss / self.window
        if self.increment >= self.mss:
            self.trace("%s (%d) incrementing additive increase" % (self.node.hostname, self.source_address))
            self.window = self.window + self.mss
            self.increment = self.increment - self.mss
            self.plot_window('additive increase')


    def cancel_timer(self):
        """ Cancel the timer. """
        if self.timer is None:
            return
        Sim.scheduler.cancel(self.timer)
        self.timer = None

    ''' Receiver '''

    def handle_data(self, packet):
        """ Handle incoming networks. This code currently gives all networks to
            the application, regardless of whether it is in order, and sends
            an ACK."""
        self.trace("%s (%d) received TCP segment from %d for %d" % (
            self.node.hostname, packet.destination_address, packet.source_address, packet.sequence))
        self.receive_buffer.put(packet.body, packet.sequence)
        data, start_sequence = self.receive_buffer.get()
        self.app.receive_data(data)
        self.ack = start_sequence + len(data)
        self.send_ack()

    def send_ack(self):
        """ Send an ack. """
        packet = TCPPacket(source_address=self.source_address,
                           source_port=self.source_port,
                           destination_address=self.destination_address,
                           destination_port=self.destination_port,
                           sequence=self.sequence, ack_number=self.ack)
        # send the packet
        self.trace("%s (%d) sending TCP ACK to %d for %d" % (
            self.node.hostname, self.source_address, self.destination_address, packet.ack_number))
        self.transport.send_packet(packet)
示例#6
0
文件: tcp.py 项目: StevenC4/bene
class TCP(Connection):
    ''' A TCP connection between two hosts.'''
    def __init__(self,transport,source_address,source_port,
                 destination_address,destination_port,app=None,window=1000,dynamic_rto=True):
        Connection.__init__(self,transport,source_address,source_port,
                            destination_address,destination_port,app)

        ### Sender functionality

        # send window; represents the total number of bytes that may
        # be outstanding at one time
        self.window = window
        # send buffer
        self.send_buffer = SendBuffer()
        # maximum segment size, in bytes
        self.mss = 1000
        # largest sequence number that has been ACKed so far; represents
        # the next sequence number the client expects to receive
        self.sequence = 0
        # retransmission timer
        self.timer = None
        # timeout duration in seconds
        self.timeout = 1

        # constants
        self.k = 4
        self.g = .1
        self.alpha = 1/8
        self.beta = 1/4

        self.dynamic_rto = dynamic_rto
        self.rto = 3
        self.srtt = None
        self.rttvar = None

        ### Receiver functionality

        # receive buffer
        self.receive_buffer = ReceiveBuffer()
        # ack number to send; represents the largest in-order sequence
        # number not yet received
        self.ack = 0

    def trace(self,message):
        ''' Print debugging messages. '''
        Sim.trace("TCP",message)

    def receive_packet(self,packet):
        ''' Receive a packet from the network layer. '''
        if packet.ack_number > 0:
            # handle ACK
            self.handle_ack(packet)
        if packet.length > 0:
            # handle data
            self.handle_data(packet)

    ''' Sender '''

    def send(self,data):
        ''' Send data on the connection. Called by the application. This
            code currently sends all data immediately. '''
        self.send_buffer.put(data)
        self.send_packets_if_possible()

    def send_packets_if_possible(self):
        # if self.send_buffer.outstanding() < self.window:
        while self.send_buffer.outstanding() < self.window and self.send_buffer.available():
            data_length = min(self.window - self.send_buffer.outstanding(), self.mss)
            data_tuple = self.send_buffer.get(data_length)
            data = data_tuple[0]
            self.sequence = data_tuple[1]
            self.send_packet(data,self.sequence)

    def send_packet(self,data,sequence):
        packet = TCPPacket(source_address=self.source_address,
                           source_port=self.source_port,
                           destination_address=self.destination_address,
                           destination_port=self.destination_port,
                           body=data,
                           sequence=sequence,ack_number=self.ack)
        packet.created = Sim.scheduler.current_time()

        # send the packet
        self.trace("%s (%d) sending TCP segment to %d for %d" % (self.node.hostname,self.source_address,self.destination_address,packet.sequence))
        self.transport.send_packet(packet)

        # set a timer
        if not self.timer:
            self.timer = Sim.scheduler.add(delay=self.rto, event='retransmit', handler=self.retransmit)

    def handle_ack(self,packet):
        ''' Handle an incoming ACK. '''

        r = Sim.scheduler.current_time() - packet.created
        if not self.srtt and not self.rttvar:
            self.srtt = r
            self.rttvar = r / 2
        else:
            self.rttvar = (1 - self.beta) * self.rttvar + (self.beta * abs(self.srtt - r))
            self.srtt = (1 - self.alpha) * self.srtt + (self.alpha * r)
        self.rto = self.srtt + max(self.g, self.k * self.rttvar)

        self.trace("%s (%d) receiving TCP ACK from %d for %d" % (self.node.hostname,self.source_address,self.destination_address,packet.ack_number))

        self.cancel_timer()

        self.send_buffer.slide(packet.ack_number)
        self.send_packets_if_possible()

        if self.send_buffer.outstanding() and not self.timer:
            self.timer = Sim.scheduler.add(delay=self.rto, event='retransmit', handler=self.retransmit)

    def retransmit(self,event):
        ''' Retransmit data. '''
        self.timer = None
        self.trace("%s (%d) retransmission timer fired" % (self.node.hostname,self.source_address))
        data_tuple = self.send_buffer.resend(self.mss)
        data = data_tuple[0]
        if data:
            self.sequence = data_tuple[1]
            if self.dynamic_rto:
                self.timer = Sim.scheduler.add(delay=self.rto, event='retransmit', handler=self.retransmit)
            else:
                self.timer = Sim.scheduler.add(delay=self.rto, event='retransmit', handler=self.retransmit)
            self.send_packet(data, self.sequence)

    def cancel_timer(self):
        ''' Cancel the timer. '''
        if not self.timer:
            return
        Sim.scheduler.cancel(self.timer)
        self.timer = None

    ''' Receiver '''

    def handle_data(self,packet):
        ''' Handle incoming data. This code currently gives all data to
            the application, regardless of whether it is in order, and sends
            an ACK.'''
        self.trace("%s (%d) received TCP segment from %d for %d" % (self.node.hostname,packet.destination_address,packet.source_address,packet.sequence))
        self.receive_buffer.put(packet.body, packet.sequence)

        data_tuple = self.receive_buffer.get()
        data = data_tuple[0]
        sequence = data_tuple[1]
        if data:
            self.app.receive_data(data)
            self.ack = sequence + len(data)

        self.send_ack(packet.created)

    def send_ack(self, created):
        ''' Send an ack. '''
        packet = TCPPacket(source_address=self.source_address,
                           source_port=self.source_port,
                           destination_address=self.destination_address,
                           destination_port=self.destination_port,
                           sequence=self.sequence,ack_number=self.ack)
        packet.created = created
        # send the packet
        self.trace("%s (%d) sending TCP ACK to %d for %d" % (self.node.hostname,self.source_address,self.destination_address,packet.ack_number))
        self.transport.send_packet(packet)
示例#7
0
class TCP(Connection):
    """ A TCP connection between two hosts."""
    def __init__(self,
                 transport,
                 source_address,
                 source_port,
                 destination_address,
                 destination_port,
                 app=None,
                 window=1000,
                 fast_retransmit=False):
        Connection.__init__(self, transport, source_address, source_port,
                            destination_address, destination_port, app)

        # -- Sender functionality

        # send window; represents the total number of bytes that may
        # be outstanding at one time
        self.window = window
        # send buffer
        self.send_buffer = SendBuffer()
        # maximum segment size, in bytes
        self.mss = 1000
        # largest sequence number that has been ACKed so far; represents
        # the next sequence number the client expects to receive
        self.sequence = 0
        # retransmission timer
        self.timer = None
        # timeout duration in seconds
        self.timeout = 1
        self.fast_retransmit = fast_retransmit

        # -- Receiver functionality

        # receive buffer
        self.receive_buffer = ReceiveBuffer()
        # ack number to send; represents the largest in-order sequence
        # number not yet received
        self.ack = 0
        self.current_ack_number = None
        self.current_ack_counter = 0
        self.total_packets_received = 0
        self.total_queueing_delay = 0

    def trace(self, message):
        """ Print debugging messages. """
        Sim.trace("TCP", message)

    def receive_packet(self, packet):
        """ Receive a packet from the network layer. """
        if packet.ack_number > 0:
            # handle ACK
            self.handle_ack(packet)
        if packet.length > 0:
            # handle data
            self.handle_data(packet)

    ''' Sender '''

    def send(self, data):
        """ Send data on the connection. Called by the application. This
            code currently sends all data immediately. """
        self.send_buffer.put(data)
        self.send_max_possible()

    def send_max_possible(self):
        if self.send_buffer.available() == 0:
            return
        if self.send_buffer.outstanding() >= self.window:
            return
        data, sequence = self.send_buffer.get(self.mss)
        self.send_packet(data, sequence)
        self.send_max_possible()

    def send_packet(self, data, sequence):
        packet = TCPPacket(source_address=self.source_address,
                           source_port=self.source_port,
                           destination_address=self.destination_address,
                           destination_port=self.destination_port,
                           body=data,
                           sequence=sequence,
                           ack_number=self.ack)

        # send the packet
        self.trace("%s (%d) sending TCP segment to %d for %d" %
                   (self.node.hostname, self.source_address,
                    self.destination_address, packet.sequence))
        self.transport.send_packet(packet)

        # set a timer
        if not self.timer:
            self.start_timer()

    def handle_ack(self, packet):
        """ Handle an incoming ACK. """
        self.trace(
            "%s (%d) handling ACK  %d" %
            (self.node.hostname, self.source_address, packet.ack_number))
        if self.fast_retransmit:
            if packet.ack_number == self.current_ack_number:
                self.current_ack_counter += 1
            else:
                self.current_ack_number = packet.ack_number
                self.current_ack_counter = 1
            if self.current_ack_counter == 4:
                self.current_ack_counter += 1
                self.cancel_timer()
                self.retransmit('retransmit')
                return
        if packet.ack_number > self.sequence:
            self.sequence = packet.ack_number
            self.send_buffer.slide(self.sequence)
            self.cancel_timer()
            self.start_timer()
            self.send_max_possible()

    def retransmit(self, event):
        """ Retransmit data. """
        if (self.send_buffer.outstanding() == 0
                and self.send_buffer.available() == 0):
            return
        data, sequence = self.send_buffer.resend(self.mss)
        self.send_packet(data, sequence)
        self.trace("%s (%d) retransmission timer fired" %
                   (self.node.hostname, self.source_address))
        self.start_timer()

    def start_timer(self):
        self.timer = Sim.scheduler.add(delay=self.timeout,
                                       event='retransmit',
                                       handler=self.retransmit)

    def cancel_timer(self):
        """ Cancel the timer. """
        if not self.timer:
            return
        Sim.scheduler.cancel(self.timer)
        self.timer = None

    ''' Receiver '''

    def handle_data(self, packet):
        """ Handle incoming data. This code currently gives all data to
            the application, regardless of whether it is in order, and sends
            an ACK."""
        self.total_packets_received += 1
        self.total_queueing_delay += packet.queueing_delay
        self.trace("%s (%d) received TCP segment from %d for %d" %
                   (self.node.hostname, packet.destination_address,
                    packet.source_address, packet.sequence))
        self.receive_buffer.put(packet.body, packet.sequence)
        data, start = self.receive_buffer.get()
        self.app.receive_data(data)
        self.ack = start + len(data)
        self.send_ack()

    def send_ack(self):
        """ Send an ack. """
        packet = TCPPacket(source_address=self.source_address,
                           source_port=self.source_port,
                           destination_address=self.destination_address,
                           destination_port=self.destination_port,
                           sequence=self.sequence,
                           ack_number=self.ack)
        # send the packet
        self.trace("%s (%d) sending TCP ACK to %d for %d" %
                   (self.node.hostname, self.source_address,
                    self.destination_address, packet.ack_number))
        self.transport.send_packet(packet)
示例#8
0
文件: tcp.py 项目: nathand8/bene
class TCP(Connection):
    ''' A TCP connection between two hosts.'''
    def __init__(self,transport,source_address,source_port,
                 destination_address,destination_port,app=None,window=1000,
                 threshold=100000,fast_recovery=False):
        Connection.__init__(self,transport,source_address,source_port,
                            destination_address,destination_port,app)

        ### Sender functionality

        # send window; represents the total number of bytes that may
        # be outstanding at one time (cwnd)
        self.window = window
        # send buffer
        self.send_buffer = SendBuffer()
        # maximum segment size, in bytes
        self.mss = 1000
        # largest sequence number that has been ACKed so far; represents
        # the next sequence number the client expects to receive
        self.sequence = 0
        # retransmission timer
        self.timer = None
        # timeout duration in seconds
        self.timeout = 1
        # Round trip time in seconds
        self.estimated_rtt = None
        # Deviation of sample rtt from estimated rtt
        self.deviation_rtt = None
        # State determines slow start vs. additive increase
        # 0 = slow start
        # 1 = additive increase
        self.state = 0
        # Threshold for slow start
        self.threshold = threshold
        self.trace("Threshold starting at %d" % self.threshold)
        # Same ack count (used for calculating three duplicate acks)
        self.same_ack_count = 0
        # Most recent ack (used for calculating three duplicate acks)
        self.last_ack = None
        # Make sure settings start with slow start
        self.window = self.mss

        # Used when dropping certain packets
        self.dropped_count = 0
        
        # Fast Recovery (Reno)
        self.fast_recovery=fast_recovery
        
        ### Used to make TCP Sequence Graphs

        self.x = []
        self.y = []
        self.dropX = []
        self.dropY = []
        self.ackX = []
        self.ackY = []

        ### Receiver functionality

        # receive buffer
        self.receive_buffer = ReceiveBuffer()
        # ack number to send; represents the largest in-order sequence
        # number not yet received
        self.ack = 0
        # a list of all the queuing delays from the sender to receiver
        self.queueing_delay_list = []

    def trace(self,message):
        ''' Print debugging messages. '''
        Sim.trace("TCP",message)

    def receive_packet(self,packet):
        ''' Receive a packet from the network layer. '''
        if packet.ack_number > 0:
            # handle ACK
            self.handle_ack(packet)
        if packet.length > 0:
            # handle data
            self.handle_data(packet)

    ''' Sender '''

    # Record packets sent for plotting purposes
    def recordPacketSent(self, time, sequence):
        self.x.append(time)
        self.y.append((sequence / 1000) % 50)

    # Record packets dropped for plotting purposes
    def recordPacketDropped(self, time, sequence):
        self.dropX.append(time)
        self.dropY.append((sequence / 1000) % 50)

    # Record acks received for plotting purposes
    def recordAckReceived(self, time, sequence):
        self.ackX.append(time)
        self.ackY.append((sequence / 1000) % 50)

    def send(self,data):
        ''' Send data on the connection. Called by the application. This
            code uses the SendBuffer to send incrementally '''
        self.send_buffer.put(data)
        self.queue_packets()

    def queue_packets(self):
        ''' Send the next set of packets if there's any to send. Limit based
            on window size and the number of outstanding packets '''
        while True:
            if self.send_buffer.available() <= 0:
                break
            open_window_space = self.window - self.send_buffer.outstanding() 
            if open_window_space <= 0:
                break
            # Send nice MSS sized packets
            if open_window_space < self.mss:
                break
            packet_size = min(open_window_space, self.mss)
            packet_data = self.send_buffer.get(packet_size)
            self.send_packet(packet_data[0], packet_data[1])

    def send_packet(self,data,sequence):
        packet = TCPPacket(source_address=self.source_address,
                           source_port=self.source_port,
                           destination_address=self.destination_address,
                           destination_port=self.destination_port,
                           body=data,
                           sequence=sequence,ack_number=self.ack,
                           sent_time=Sim.scheduler.current_time())

        # Forced Loss, loss, AIMD dropped packets
        drop_list = []
        #drop_list = [32000] # For a single loss
        #drop_list = [32000, 33000, 34000] # For burst loss
        if sequence in drop_list and self.dropped_count < len(drop_list):
            self.trace("Manually dropping packet %d" % sequence)
            packet.drop = True

        if packet.drop:
            # manually drop packets
            self.dropped_count += 1
            self.recordPacketDropped(Sim.scheduler.current_time(), packet.sequence)

        else:
            # send the packet
            self.trace("%s (%d) sending TCP segment to %d for %d" % (self.node.hostname,self.source_address,self.destination_address,packet.sequence))
            self.transport.send_packet(packet)
            self.recordPacketSent(Sim.scheduler.current_time(), packet.sequence)

        # set a timer
        if not self.timer:
            self.timer = Sim.scheduler.add(delay=self.timeout, event='retransmit', handler=self.retransmit)

    def slow_start(self, duplicate_acks=False):
        if duplicate_acks and self.fast_recovery:
            # If using fast recovery and three duplicate acks are detected,
            # set the window to half the original and 
            # keep going with additive increase
            self.window = int(round(self.window/2 / self.mss) * self.mss)
            self.state = 1
        else:
            # Otherwise reset the window to 1 mss and use slow start
            self.window = self.mss
            self.state = 0

    def increaseWindow(self,packet):
        # Increase the window
        if self.state == 0: 
            # Slow Start
            self.window += packet.ack_packet_length
            self.trace("Slow Start - Incremented window by %d. New window size: %d" % (packet.ack_packet_length, self.window))
            # If the window equals or exceeds the threshold, stop slow start
            if self.window >= self.threshold:
                self.trace("Hit threshold of %d. Switching from slow start to additive increase" % self.threshold)
                self.state = 1
        elif self.state == 1:
            #Additive increase
            # "increment cwnd by MSS*b/cwnd"
            increment = self.mss * packet.ack_packet_length / self.window
            self.window += increment
            self.trace("Additive Increase - Incremented window by %d. New window size: %d" % (increment, self.window))

    def calculateRTO(self, packet):
        # Calculate Sample RTT
        sample_rtt = Sim.scheduler.current_time() - packet.sent_time
        #self.trace("sample round trip time %f" % sample_rtt)

        # Calculate the new estimated RTT
        alpha = 0.125
        if not self.estimated_rtt:
            self.estimated_rtt = sample_rtt
        else:
            self.estimated_rtt = (1 - alpha) * self.estimated_rtt + alpha * sample_rtt

        # Calculate the deviation of the sample RTT
        beta = 0.25
        if not self.deviation_rtt:
            self.deviation_rtt = self.estimated_rtt/2
        else:
            self.deviation_rtt = (1 - beta) * self.deviation_rtt + beta * abs(sample_rtt - self.estimated_rtt)

        # Calculate the Retransmission Timeout (RTO)
        self.timeout = self.estimated_rtt + 4 * self.deviation_rtt
        #self.trace("changed the timeout to %f" % self.timeout)

    def slideWindow(self,packet):
        self.sequence = packet.ack_number
        self.send_buffer.slide(packet.ack_number)

    def sendNextBatch(self):
        self.cancel_timer()
        if self.send_buffer.outstanding() or self.send_buffer.available():
            self.timer = Sim.scheduler.add(delay=self.timeout, event='retransmit', handler=self.retransmit)
            self.queue_packets()

    def handle_ack(self,packet):
        ''' Handle an incoming ACK. '''

        self.trace("received TCP ACK for %d" % packet.ack_number)

        # For sequence chart plotting
        self.recordAckReceived(Sim.scheduler.current_time(), packet.ack_number)

        # Calculate RTO
        self.calculateRTO(packet)

        # Watch for three duplicate acks
        if self.last_ack != packet.ack_number:
            # If a new ack is received
            self.last_ack = packet.ack_number
            self.same_ack_count = 1
            self.increaseWindow(packet)
            self.slideWindow(packet)
            self.sendNextBatch()
        else:
            # A duplicate ack has been received
            self.same_ack_count += 1
            if self.same_ack_count > 3:
                # When the fourth ack with the same number is received (3 duplicates)
                self.trace("Three duplicate ACKs. Ignoring duplicate ACKs for same sequence number")
                self.same_ack_count = -100
                self.threshold = max(self.window/2, self.mss)
                self.trace("Set new threshold to %d" % self.threshold)
                self.cancel_timer()
                self.retransmit({},duplicate_acks=True)

    def retransmit(self,event,duplicate_acks=False):
        ''' Retransmit data. '''
        if duplicate_acks:
            self.trace("%s (%d) retransmission timer fired" % (self.node.hostname,self.source_address))
        else:
            self.trace("%s (%d) Three duplicate acks detected. Retransmitting immediately" % (self.node.hostname,self.source_address))

        self.trace("Slow start initiated")
        self.slow_start(duplicate_acks=duplicate_acks)
        packet_data = self.send_buffer.resend(self.mss)
        self.send_packet(packet_data[0], packet_data[1])
        self.timeout = min(self.timeout * 2, 3600) # should never exceed an hour
        self.trace("doubled the timeout to %f" % self.timeout)
        # CANCEL TIMER BEFORE SETTING A NEW ONE?
        self.cancel_timer()
        open_window_space = self.window - self.send_buffer.outstanding() 
        if self.send_buffer.outstanding() or self.send_buffer.available():
            self.timer = Sim.scheduler.add(delay=self.timeout, event='retransmit', handler=self.retransmit)

    def cancel_timer(self):
        ''' Cancel the timer. '''
        if not self.timer:
            return
        try:
            Sim.scheduler.cancel(self.timer)
        except ValueError:
            self.trace("Tried to cancel same timer twice")
        self.timer = None

    ''' Receiver '''

    def handle_data(self,packet):
        ''' Handle incoming data. This code currently gives all data to
            the application, regardless of whether it is in order, and sends
            an ACK.'''
        self.queueing_delay_list.append(packet.queueing_delay)
        self.trace("%s (%d) received TCP segment from %d for %d" % (self.node.hostname,packet.destination_address,packet.source_address,packet.sequence))
        self.receive_buffer.put(packet.body, packet.sequence)
        data = self.receive_buffer.get()
        self.ack = len(data[0]) + data[1]
        self.app.receive_data(data[0])
        self.send_ack(packet.sent_time, packet.length)

    def send_ack(self, packet_sent_time=0, packet_length=0):
        ''' Send an ack. '''
        packet = TCPPacket(source_address=self.source_address,
                           source_port=self.source_port,
                           destination_address=self.destination_address,
                           destination_port=self.destination_port,
                           sequence=self.sequence,ack_number=self.ack,
                           sent_time=packet_sent_time,ack_packet_length=packet_length)
        # send the packet
        self.trace("%s (%d) sending TCP ACK to %d for %d" % (self.node.hostname,self.source_address,self.destination_address,packet.ack_number))
        self.transport.send_packet(packet)
示例#9
0
class TCP(Connection):
    """ A TCP connection between two hosts."""
    def __init__(self,
                 transport,
                 source_address,
                 source_port,
                 destination_address,
                 destination_port,
                 app=None,
                 drop=[],
                 fast_retransmit=False,
                 measure=False):
        Connection.__init__(self, transport, source_address, source_port,
                            destination_address, destination_port, app)

        # -- Sender functionality

        # send buffer
        self.send_buffer = SendBuffer()
        # maximum segment size, in bytes
        self.mss = 1000
        # initial cwnd is equal to 1mss
        self.cwnd = float(self.mss)
        # boolean flag that indicates if in slow start or additive increase
        self.slow_start = True
        # When cwnd >= ss_thresh, slow start ends
        self.ss_thresh = 100000
        if self.node.hostname == 'n1':
            self.trace("Entering Slow Start: SS Thresh = %s" %
                       (self.ss_thresh))
        # Tracks additive increase - determines when to add another MSS to cwnd
        self.cwnd_inc = 0

        # largest sequence number that has been ACKed so far; represents
        # the next sequence number the client expects to receive
        self.sequence = 0
        # plot sequence numbers
        self.plot_sequence_header()
        self.plot_cwnd_header()
        self.plot_cwnd()
        # packets to drop
        self.drop = drop
        self.dropped = []
        # retransmission timer
        self.timer = None
        # timeout duration in seconds
        self.timeout = 1

        # -- Receiver functionality

        # receive buffer
        self.receive_buffer = ReceiveBuffer()
        # ack number to send; represents the largest in-order sequence
        # number not yet received
        self.ack = 0
        self.fast_retransmit = fast_retransmit
        self.last_ack = 0
        self.last_ack_count = 0

    def trace(self, message):
        """ Print debugging messages. """
        Sim.trace("TCP", message)

    def plot_sequence_header(self):
        if self.node.hostname == 'n1':
            Sim.plot('sequence.csv', 'Time,Sequence Number,Event\n')

    def plot_sequence(self, sequence, event):
        if self.node.hostname == 'n1':
            Sim.plot(
                'sequence.csv',
                '%s,%s,%s\n' % (Sim.scheduler.current_time(), sequence, event))

    def plot_cwnd_header(self):
        if self.node.hostname == 'n1':
            Sim.plot('cwnd.csv', 'Time,Congestion Window\n')

    def plot_cwnd(self):
        if self.node.hostname == 'n1':
            Sim.plot(
                'cwnd.csv',
                '%s,%s\n' % (Sim.scheduler.current_time(), int(self.cwnd)))

    def receive_packet(self, packet):
        """ Receive a packet from the network layer. """
        if packet.ack_number > 0:
            # handle ACK
            self.handle_ack(packet)
        if packet.length > 0:
            # handle data
            self.handle_data(packet)

    ''' Sender '''

    def send(self, data):
        """ Send data on the connection. Called by the application."""

        self.send_buffer.put(data)
        self.send_window()

    def send_window(self):
        while self.send_buffer.outstanding(
        ) < self.cwnd and self.send_buffer.available() > 0:
            (packet_data, self.sequence) = self.send_buffer.get(self.mss)
            self.send_packet(packet_data, self.sequence)

    def send_packet(self, data, sequence):
        packet = TCPPacket(source_address=self.source_address,
                           source_port=self.source_port,
                           destination_address=self.destination_address,
                           destination_port=self.destination_port,
                           body=data,
                           sequence=sequence,
                           ack_number=self.ack)

        if sequence in self.drop and not sequence in self.dropped:
            self.dropped.append(sequence)
            self.plot_sequence(sequence, 'drop')
            self.trace("%s (%d) dropping TCP segment to %d for %d" %
                       (self.node.hostname, self.source_address,
                        self.destination_address, packet.sequence))
            self.trace("PACKET DROPPED CWND IS %s\n" % (self.cwnd))
            return

        # send the packet
        self.plot_sequence(sequence, 'send')
        self.trace("%s (%d) sending TCP segment to %d for %d" %
                   (self.node.hostname, self.source_address,
                    self.destination_address, packet.sequence))
        self.transport.send_packet(packet)

        # set a timer
        if not self.timer:
            self.start_retransmit_timer(self.timeout)

    def handle_ack(self, packet):
        """ Handle an incoming ACK. """
        self.plot_sequence(packet.ack_number - 1000, 'ack')
        prev_out = self.send_buffer.outstanding()
        self.send_buffer.slide(packet.ack_number)
        bytes_acked = prev_out - self.send_buffer.outstanding()
        self.trace("%s (%d) received ACK from %d for %d. %d bytes ACKed" %
                   (self.node.hostname, packet.destination_address,
                    packet.source_address, packet.ack_number, bytes_acked))

        if self.fast_retransmit:
            if self.last_ack == packet.ack_number:
                self.last_ack_count += 1
                if self.last_ack_count == 4:
                    self.retransmit(None)
            elif packet.ack_number > self.last_ack:
                self.last_ack = packet.ack_number
                self.last_ack_count = 1

        if bytes_acked > 0:
            if self.slow_start:
                self.cwnd += self.mss
                self.plot_cwnd()
                if self.cwnd == self.ss_thresh:
                    self.slow_start = False
                    self.trace("Entering Additive Increase: CWND = %s" %
                               (self.cwnd))
            else:
                self.cwnd_inc += self.mss * bytes_acked / self.cwnd
                if self.cwnd_inc > self.mss:
                    self.cwnd += self.mss
                    self.cwnd_inc -= self.mss
                    self.plot_cwnd()

        # self.trace("Window Size: %f" % (self.cwnd))
        self.cancel_timer()
        if not self.send_buffer.outstanding() == 0:
            self.start_retransmit_timer(self.timeout)
        self.send_window()

    def retransmit(self, event):
        """ Retransmit data. """
        self.ss_thresh = max(self.cwnd / 2, self.mss)
        self.ss_thresh -= self.ss_thresh % self.mss
        self.slow_start = True
        self.cwnd = float(self.mss)
        self.trace("Entering Slow Start: SS Thresh = %s CWND = %s" %
                   (self.ss_thresh, self.cwnd))
        self.plot_cwnd()
        self.cwnd_inc = 0.0
        if event:
            self.trace("%s (%d) retransmission timer fired" %
                       (self.node.hostname, self.source_address))
            self.timer = None
        else:
            self.trace("%s (%d) Fast retransmit occured" %
                       (self.node.hostname, self.source_address))

        (data, sequence) = self.send_buffer.resend(size=self.mss, reset=True)
        if len(data) == 0:
            return
        self.send_packet(data, sequence)

    def start_retransmit_timer(self, time):
        self.timer = Sim.scheduler.add(delay=time,
                                       event='retransmit',
                                       handler=self.retransmit)

    def cancel_timer(self):
        """ Cancel the timer. """
        if not self.timer:
            return
        Sim.scheduler.cancel(self.timer)
        self.timer = None

    ''' Receiver '''

    def handle_data(self, packet):
        """ Handle incoming data. This code currently gives all data to
			the application, regardless of whether it is in order, and sends
			an ACK."""
        # self.trace("%s (%d) received TCP segment from %d for %d" % (
        # self.node.hostname, packet.destination_address, packet.source_address, packet.sequence))

        self.receive_buffer.put(packet.body, packet.sequence)
        (buffer_data, sequence_number) = self.receive_buffer.get()
        if len(buffer_data) > 0:
            self.app.receive_data(buffer_data)

        if sequence_number == packet.sequence:
            self.ack = packet.sequence + len(buffer_data)

        self.send_ack()

    def send_ack(self):
        """ Send an ack. """
        packet = TCPPacket(source_address=self.source_address,
                           source_port=self.source_port,
                           destination_address=self.destination_address,
                           destination_port=self.destination_port,
                           sequence=self.sequence,
                           ack_number=self.ack)
        # send the packet
        self.trace("%s (%d) sending TCP ACK to %d for %d" %
                   (self.node.hostname, self.source_address,
                    self.destination_address, packet.ack_number))
        self.transport.send_packet(packet)
示例#10
0
class TCP(Connection):
    ''' A TCP connection between two hosts.'''
    def __init__(self,
                 transport,
                 source_address,
                 source_port,
                 destination_address,
                 destination_port,
                 app=None,
                 window=1000):
        Connection.__init__(self, transport, source_address, source_port,
                            destination_address, destination_port, app)

        ### Sender functionality

        # send window; represents the total number of bytes that may
        # be outstanding at one time
        self.window = window
        # send buffer
        self.send_buffer = SendBuffer()
        # maximum segment size, in bytes
        self.mss = 1000
        # largest sequence number that has been ACKed so far; represents
        # the next sequence number the client expects to receive
        self.sequence = 0
        # retransmission timer
        self.timer = None
        # timeout duration in seconds
        self.timeout = 1

        ### Receiver functionality

        # receive buffer
        self.receive_buffer = ReceiveBuffer()
        # ack number to send; represents the largest in-order sequence
        # number not yet received
        self.ack = 0

    def trace(self, message):
        ''' Print debugging messages. '''
        Sim.trace("TCP", message)

    def receive_packet(self, packet):
        ''' Receive a packet from the network layer. '''
        if packet.ack_number > 0:
            # handle ACK
            self.handle_ack(packet)
        if packet.length > 0:
            # handle data
            self.handle_data(packet)

    ''' Sender '''

    def send(self, data):
        ''' Send data on the connection. Called by the application. This
            code currently sends all data immediately. '''
        self.send_buffer.put(data)
        print "Data added to buffer."

        if self.send_buffer.available() > 0 and self.send_buffer.outstanding(
        ) < self.window:
            new_data, new_sequence = self.send_buffer.get(self.mss)
            # self.send_packet(new_data, new_sequence)
            message = ("Window not full, sent packet: " + str(new_sequence))
            print message

        # self.send_packet(data,self.sequence)
        # self.timer = Sim.scheduler.add(delay=self.timeout, event='retransmit', handler=self.retransmit)

    def send_packet(self, data, sequence):
        packet = TCPPacket(source_address=self.source_address,
                           source_port=self.source_port,
                           destination_address=self.destination_address,
                           destination_port=self.destination_port,
                           body=data,
                           sequence=sequence,
                           ack_number=self.ack)

        # send the packet
        self.trace("%s (%d) sending TCP segment to %d for %d" %
                   (self.node.hostname, self.source_address,
                    self.destination_address, packet.sequence))
        self.transport.send_packet(packet)

        # set a timer
        if not self.timer:
            self.timer = Sim.scheduler.add(delay=self.timeout,
                                           event='retransmit',
                                           handler=self.retransmit)

    def handle_ack(self, packet):
        ''' Handle an incoming ACK. '''
        self.cancel_timer()

    def retransmit(self, event):
        ''' Retransmit data. '''
        self.trace("%s (%d) retransmission timer fired" %
                   (self.node.hostname, self.source_address))

    def cancel_timer(self):
        ''' Cancel the timer. '''
        if not self.timer:
            return
        Sim.scheduler.cancel(self.timer)
        self.timer = None

    ''' Receiver '''

    def handle_data(self, packet):
        ''' Handle incoming data. This code currently gives all data to
            the application, regardless of whether it is in order, and sends
            an ACK.'''
        self.trace("%s (%d) received TCP segment from %d for %d" %
                   (self.node.hostname, packet.destination_address,
                    packet.source_address, packet.sequence))
        self.app.receive_data(packet.body)
        self.send_ack()

    def send_ack(self):
        ''' Send an ack. '''
        packet = TCPPacket(source_address=self.source_address,
                           source_port=self.source_port,
                           destination_address=self.destination_address,
                           destination_port=self.destination_port,
                           sequence=self.sequence,
                           ack_number=self.ack)
        # send the packet
        self.trace("%s (%d) sending TCP ACK to %d for %d" %
                   (self.node.hostname, self.source_address,
                    self.destination_address, packet.ack_number))
        self.transport.send_packet(packet)
示例#11
0
class TCP(Connection):
	""" A TCP connection between two hosts."""

	def __init__(self, transport, source_address, source_port,
				 destination_address, destination_port, app=None, window=1000,drop=[],
				 fast_retransmit=False, measure=False):
		Connection.__init__(self, transport, source_address, source_port,
							destination_address, destination_port, app)

		# -- Sender functionality

		# send window; represents the total number of bytes that may
		# be outstanding at one time
		self.window = window
		# send buffer
		self.send_buffer = SendBuffer()
		# maximum segment size, in bytes
		self.mss = 1000
		# largest sequence number that has been ACKed so far; represents
		# the next sequence number the client expects to receive
		self.sequence = 0
		# plot sequence numbers
		self.plot_sequence_header()
		# packets to drop
		self.drop = drop
		self.dropped = []
		# retransmission timer
		self.timer = None
		# timeout duration in seconds
		self.timeout = 1

		# -- Receiver functionality

		# receive buffer
		self.receive_buffer = ReceiveBuffer()
		# ack number to send; represents the largest in-order sequence
		# number not yet received
		self.ack = 0
		self.fast_retransmit = fast_retransmit
		self.last_ack = 0
		self.last_ack_count = 0
		self.measure = measure
		self.total_queue_delay = 0
		self.packet_count = 0
		self.byte_count = 0

	def trace(self, message):
		""" Print debugging messages. """
		Sim.trace("TCP", message)

	def plot_sequence_header(self):
		if self.node.hostname =='n1':
			Sim.plot('sequence.csv','Time,Sequence Number,Event\n')

	def plot_sequence(self,sequence,event):
		if self.node.hostname =='n1':
			Sim.plot('sequence.csv','%s,%s,%s\n' % (Sim.scheduler.current_time(),sequence,event))

	def receive_packet(self, packet):
		""" Receive a packet from the network layer. """
		if packet.ack_number > 0:
			# handle ACK
			self.handle_ack(packet)
		if packet.length > 0:
			# handle data
			self.handle_data(packet)

	''' Sender '''

	def send(self, data):
		""" Send data on the connection. Called by the application."""
		
		self.send_buffer.put(data)
		self.send_window()

	def send_window(self):
		while self.send_buffer.outstanding() < self.window and self.send_buffer.available() > 0:
			(packet_data, self.sequence) = self.send_buffer.get(self.mss)
			self.send_packet(packet_data, self.sequence)

	def send_packet(self, data, sequence):
		packet = TCPPacket(source_address=self.source_address,
						   source_port=self.source_port,
						   destination_address=self.destination_address,
						   destination_port=self.destination_port,
						   body=data,
						   sequence=sequence, ack_number=self.ack)

		if sequence in self.drop and not sequence in self.dropped:
			self.dropped.append(sequence)
			self.plot_sequence(sequence,'drop')
			self.trace("%s (%d) dropping TCP segment to %d for %d" % (
				self.node.hostname, self.source_address, self.destination_address, packet.sequence))
			return

		# send the packet
		self.plot_sequence(sequence,'send')
		self.trace("%s (%d) sending TCP segment to %d for %d" % (
			self.node.hostname, self.source_address, self.destination_address, packet.sequence))
		self.transport.send_packet(packet)

		# set a timer
		if not self.timer:
			self.start_retransmit_timer(self.timeout)

	def handle_ack(self, packet):
		""" Handle an incoming ACK. """
		self.plot_sequence(packet.ack_number - 1000,'ack')
		self.send_buffer.slide(packet.ack_number)
		self.trace("%s (%d) received ACK from %d for %d" % (
			self.node.hostname, packet.destination_address, packet.source_address, packet.ack_number))

		if self.fast_retransmit:
			if self.last_ack == packet.ack_number:
				self.last_ack_count += 1
				if self.last_ack_count == 4:
					self.retransmit(None)
			elif packet.ack_number > self.last_ack:
				self.last_ack = packet.ack_number
				self.last_ack_count = 1

		self.cancel_timer()
		if not self.send_buffer.outstanding() == 0:
			self.start_retransmit_timer(self.timeout)
		self.send_window()	

	def retransmit(self, event):
		""" Retransmit data. """
		if event:
			self.trace("%s (%d) retransmission timer fired" % (self.node.hostname, self.source_address))
			self.timer = None
		else:
			self.trace("%s (%d) Fast retransmit occured" % (self.node.hostname, self.source_address))
		(data, sequence) = self.send_buffer.resend(self.mss)
		if len(data) == 0:
			return
		self.send_packet(data, sequence)

	def start_retransmit_timer(self, time):
		self.timer = Sim.scheduler.add(delay=time, event='retransmit', handler=self.retransmit)

	def cancel_timer(self):
		""" Cancel the timer. """
		if not self.timer:
			return
		Sim.scheduler.cancel(self.timer)
		self.timer = None

	''' Receiver '''

	def handle_data(self, packet):
		""" Handle incoming data. This code currently gives all data to
			the application, regardless of whether it is in order, and sends
			an ACK."""
		self.trace("%s (%d) received TCP segment from %d for %d" % (
			self.node.hostname, packet.destination_address, packet.source_address, packet.sequence))

		self.receive_buffer.put(packet.body, packet.sequence)
		(buffer_data, sequence_number) = self.receive_buffer.get()
		if len(buffer_data) > 0:
			self.app.receive_data(buffer_data)
		
		if sequence_number == packet.sequence:
			self.ack = packet.sequence + len(buffer_data)
		if self.measure:
			self.total_queue_delay += packet.queueing_delay
			self.packet_count += 1
			self.byte_count += packet.length
			f = open(name="results.txt", mode="w")
			f.write(str(self.total_queue_delay / self.packet_count) + "," + str(self.byte_count / Sim.scheduler.current_time()))
			f.close()
			
		self.send_ack()

	def send_ack(self):
		""" Send an ack. """
		packet = TCPPacket(source_address=self.source_address,
						   source_port=self.source_port,
						   destination_address=self.destination_address,
						   destination_port=self.destination_port,
						   sequence=self.sequence, ack_number=self.ack)
		# send the packet
		self.trace("%s (%d) sending TCP ACK to %d for %d" % (
			self.node.hostname, self.source_address, self.destination_address, packet.ack_number))
		self.transport.send_packet(packet)
示例#12
0
class TCP(Connection):
    ''' A TCP connection between two hosts.'''
    def __init__(self,transport,source_address,source_port,
                 destination_address,destination_port,app=None,window=1000):
        Connection.__init__(self,transport,source_address,source_port,
                            destination_address,destination_port,app)

        ### Sender functionality

        # send window; represents the total number of bytes that may
        # be outstanding at one time
        self.window = window
        # send buffer
        self.send_buffer = SendBuffer()
        # maximum segment size, in bytes
        self.mss = 1000
        # largest sequence number that has been ACKed so far; represents
        # the next sequence number the client expects to receive
        self.sequence = 0
        # retransmission timer
        self.timer = None
        # timeout duration in seconds
        self.timeout = 1

        ### Receiver functionality

        # receive buffer
        self.receive_buffer = ReceiveBuffer()
        # ack number to send; represents the largest in-order sequence
        # number not yet received
        self.ack = 0

    def trace(self,message):
        ''' Print debugging messages. '''
        Sim.trace("TCP",message)

    def receive_packet(self,packet):
        ''' Receive a packet from the network layer. '''
        if packet.ack_number > 0:
            # handle ACK
            self.handle_ack(packet)
        if packet.length > 0:
            # handle data
            self.handle_data(packet)

    ''' Sender '''

    def send(self,data):
        ''' Send data on the connection. Called by the application. This
            code currently sends all data immediately. '''
        self.send_buffer.put(data)
        print "Data added to buffer."

        if self.send_buffer.available() > 0 and self.send_buffer.outstanding() < self.window:
            new_data, new_sequence = self.send_buffer.get(self.mss)
            # self.send_packet(new_data, new_sequence)
            message = ("Window not full, sent packet: " + str(new_sequence))
            print message

        # self.send_packet(data,self.sequence)
        # self.timer = Sim.scheduler.add(delay=self.timeout, event='retransmit', handler=self.retransmit)

    def send_packet(self,data,sequence):
        packet = TCPPacket(source_address=self.source_address,
                           source_port=self.source_port,
                           destination_address=self.destination_address,
                           destination_port=self.destination_port,
                           body=data,
                           sequence=sequence,ack_number=self.ack)

        # send the packet
        self.trace("%s (%d) sending TCP segment to %d for %d" % (self.node.hostname,self.source_address,self.destination_address,packet.sequence))
        self.transport.send_packet(packet)

        # set a timer
        if not self.timer:
            self.timer = Sim.scheduler.add(delay=self.timeout, event='retransmit', handler=self.retransmit)

    def handle_ack(self,packet):
        ''' Handle an incoming ACK. '''
        self.cancel_timer()

    def retransmit(self,event):
        ''' Retransmit data. '''
        self.trace("%s (%d) retransmission timer fired" % (self.node.hostname,self.source_address))

    def cancel_timer(self):
        ''' Cancel the timer. '''
        if not self.timer:
            return
        Sim.scheduler.cancel(self.timer)
        self.timer = None

    ''' Receiver '''

    def handle_data(self,packet):
        ''' Handle incoming data. This code currently gives all data to
            the application, regardless of whether it is in order, and sends
            an ACK.'''
        self.trace("%s (%d) received TCP segment from %d for %d" % (self.node.hostname,packet.destination_address,packet.source_address,packet.sequence))
        self.app.receive_data(packet.body)
        self.send_ack()

    def send_ack(self):
        ''' Send an ack. '''
        packet = TCPPacket(source_address=self.source_address,
                           source_port=self.source_port,
                           destination_address=self.destination_address,
                           destination_port=self.destination_port,
                           sequence=self.sequence,ack_number=self.ack)
        # send the packet
        self.trace("%s (%d) sending TCP ACK to %d for %d" % (self.node.hostname,self.source_address,self.destination_address,packet.ack_number))
        self.transport.send_packet(packet)
示例#13
0
文件: tcp.py 项目: nathand8/bene
class TCP(Connection):
    ''' A TCP connection between two hosts.'''
    def __init__(self,transport,source_address,source_port,
                 destination_address,destination_port,app=None,window=1000):
        Connection.__init__(self,transport,source_address,source_port,
                            destination_address,destination_port,app)

        ### Sender functionality

        # send window; represents the total number of bytes that may
        # be outstanding at one time
        self.window = window
        # send buffer
        self.send_buffer = SendBuffer()
        # maximum segment size, in bytes
        self.mss = 1000
        # largest sequence number that has been ACKed so far; represents
        # the next sequence number the client expects to receive
        self.sequence = 0
        # retransmission timer
        self.timer = None
        # timeout duration in seconds
        self.timeout = 1
        # Round trip time in seconds
        self.estimated_rtt = None
        # Deviation of sample rtt from estimated rtt
        self.deviation_rtt = None

        ### Receiver functionality

        # receive buffer
        self.receive_buffer = ReceiveBuffer()
        # ack number to send; represents the largest in-order sequence
        # number not yet received
        self.ack = 0
        # a list of all the queuing delays from the sender to receiver
        self.queueing_delay_list = []

    def trace(self,message):
        ''' Print debugging messages. '''
        Sim.trace("TCP",message)

    def receive_packet(self,packet):
        ''' Receive a packet from the network layer. '''
        if packet.ack_number > 0:
            # handle ACK
            self.handle_ack(packet)
        if packet.length > 0:
            # handle data
            self.handle_data(packet)

    ''' Sender '''

    def send(self,data):
        ''' Send data on the connection. Called by the application. This
            code uses the SendBuffer to send incrementally '''
        self.send_buffer.put(data)
        self.queue_packets()

    def queue_packets(self):
        ''' Send the next set of packets if there's any to send. Limit based
            on window size and the number of outstanding packets '''
        while True:
            if self.send_buffer.available() <= 0:
                break
            if self.send_buffer.outstanding() + self.mss > self.window:
                break
            packet_data = self.send_buffer.get(self.mss)
            self.send_packet(packet_data[0], packet_data[1])

    def send_packet(self,data,sequence):
        packet = TCPPacket(source_address=self.source_address,
                           source_port=self.source_port,
                           destination_address=self.destination_address,
                           destination_port=self.destination_port,
                           body=data,
                           sequence=sequence,ack_number=self.ack,
                           sent_time=Sim.scheduler.current_time())

        # send the packet
        self.trace("%s (%d) sending TCP segment to %d for %d" % (self.node.hostname,self.source_address,self.destination_address,packet.sequence))
        self.transport.send_packet(packet)

        # set a timer
        if not self.timer:
            self.timer = Sim.scheduler.add(delay=self.timeout, event='retransmit', handler=self.retransmit)

    def handle_ack(self,packet):
        ''' Handle an incoming ACK. '''

        # Calculate Sample RTT
        sample_rtt = Sim.scheduler.current_time() - packet.sent_time
        self.trace("sample round trip time %f" % sample_rtt)

        # Calculate the new estimated RTT
        alpha = 0.125
        if not self.estimated_rtt:
            self.estimated_rtt = sample_rtt
        else:
            self.estimated_rtt = (1 - alpha) * self.estimated_rtt + alpha * sample_rtt

        # Calculate the deviation of the sample RTT
        beta = 0.25
        if not self.deviation_rtt:
            self.deviation_rtt = self.estimated_rtt/2
        else:
            self.deviation_rtt = (1 - beta) * self.deviation_rtt + beta * abs(sample_rtt - self.estimated_rtt)

        # Calculate the Retransmission Timeout (RTO)
        self.timeout = self.estimated_rtt + 4 * self.deviation_rtt
        self.trace("changed the timeout to %f" % self.timeout)

        self.sequence = packet.ack_number
        self.send_buffer.slide(packet.ack_number)
        self.cancel_timer()
        if self.send_buffer.outstanding() or self.send_buffer.available():
            self.timer = Sim.scheduler.add(delay=self.timeout, event='retransmit', handler=self.retransmit)
            self.queue_packets()

    def retransmit(self,event):
        ''' Retransmit data. '''
        self.trace("%s (%d) retransmission timer fired" % (self.node.hostname,self.source_address))
        packet_data = self.send_buffer.resend(self.mss)
        self.send_packet(packet_data[0], packet_data[1])
        self.timeout = self.timeout * 2
        self.trace("doubled the timeout to %f" % self.timeout)
        self.timer = Sim.scheduler.add(delay=self.timeout, event='retransmit', handler=self.retransmit)

    def cancel_timer(self):
        ''' Cancel the timer. '''
        if not self.timer:
            return
        Sim.scheduler.cancel(self.timer)
        self.timer = None

    ''' Receiver '''

    def handle_data(self,packet):
        ''' Handle incoming data. This code currently gives all data to
            the application, regardless of whether it is in order, and sends
            an ACK.'''
        self.queueing_delay_list.append(packet.queueing_delay)
        self.trace("%s (%d) received TCP segment from %d for %d" % (self.node.hostname,packet.destination_address,packet.source_address,packet.sequence))
        self.receive_buffer.put(packet.body, packet.sequence)
        data = self.receive_buffer.get()
        self.ack = len(data[0]) + data[1]
        self.app.receive_data(data[0])
        self.send_ack(packet.sent_time)

    def send_ack(self, packet_sent_time=0):
        ''' Send an ack. '''
        packet = TCPPacket(source_address=self.source_address,
                           source_port=self.source_port,
                           destination_address=self.destination_address,
                           destination_port=self.destination_port,
                           sequence=self.sequence,ack_number=self.ack,
                           sent_time=packet_sent_time)
        # send the packet
        self.trace("%s (%d) sending TCP ACK to %d for %d" % (self.node.hostname,self.source_address,self.destination_address,packet.ack_number))
        self.transport.send_packet(packet)