Exemple #1
0
    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
        self.totalQueueingDelay = 0.0
        self.totalPacketsSent = 0
        self.output = False
        self.dynamic = True
        self.proveTimer = False
        # send window; represents the total number of bytes that may
        # be outstanding at one time
        # Step 2
        self.window = window
        # send buffer
        self.send_buffer = SendBuffer()
        # maximum segment size, in bytes
        # self.mss = 1000
        self.mss = min(1000, window)
        # 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.0
        if self.dynamic:
            self.timeout = 3.0
        # estimated rtt
        self.est_rtt = None
        # alpha
        self.alpha = 0.125
        # variation rtt
        self.var_rtt = None  ## TODO: revisit this later
        # beta
        self.beta = 0.25
        ### 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
Exemple #2
0
    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
        self.totalQueueingDelay = 0.0
        self.totalPacketsSent = 0
        self.port = source_port
        self.dynamic = True
        self.output = False
        self.proveTimer = False
        self.proveCong = False
        self.stand_trace = False
        self.seq_plot = False
        self.graph1 = True
        self.graph2 = False   # == This is controlled in the transfer file by Sim.set_debug('Link')
        self.graph3 = False
        self.graph4 = False

        if self.graph2:
            Sim.set_debug('Link')
        # send window; represents the total number of bytes that may
        # be outstanding at one time
        # maximum segment size, in bytes
        self.mss = 1000
        # Step 2
        self.window = self.mss  ######################### This one gets the mess adjusted out of it
        # threshold for slow start
        self.thresh = 100000
        self.inc_sum = 0
        # for fast retransmit
        self.last_ack = 0
        self.dup_counter = 0
        self.drop_next = False
        self.has_dropped = False
        self.dropped_count = 0
        # send buffer
        self.send_buffer = SendBuffer()
        ############################################# (this never gets adjusted)
        #self.mss = min(1000, window) ################ TODO: handle the case where window is bigger than 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.0
        if self.dynamic:
            self.timeout = 3.0
        # estimated rtt
        self.est_rtt = None
        # alpha
        self.alpha = 0.125
        # variation rtt
        self.var_rtt = None  ## TODO: revisit this later
        # beta
        self.beta = 0.25
        ### 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
Exemple #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):
        Connection.__init__(self,transport,source_address,source_port,
                            destination_address,destination_port,app)

        ### Sender functionality
        self.totalQueueingDelay = 0.0
        self.totalPacketsSent = 0
        self.port = source_port
        self.dynamic = True
        self.output = False
        self.proveTimer = False
        self.proveCong = False
        self.stand_trace = False
        self.seq_plot = False
        self.graph1 = True
        self.graph2 = False   # == This is controlled in the transfer file by Sim.set_debug('Link')
        self.graph3 = False
        self.graph4 = False

        if self.graph2:
            Sim.set_debug('Link')
        # send window; represents the total number of bytes that may
        # be outstanding at one time
        # maximum segment size, in bytes
        self.mss = 1000
        # Step 2
        self.window = self.mss  ######################### This one gets the mess adjusted out of it
        # threshold for slow start
        self.thresh = 100000
        self.inc_sum = 0
        # for fast retransmit
        self.last_ack = 0
        self.dup_counter = 0
        self.drop_next = False
        self.has_dropped = False
        self.dropped_count = 0
        # send buffer
        self.send_buffer = SendBuffer()
        ############################################# (this never gets adjusted)
        #self.mss = min(1000, window) ################ TODO: handle the case where window is bigger than 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.0
        if self.dynamic:
            self.timeout = 3.0
        # estimated rtt
        self.est_rtt = None
        # alpha
        self.alpha = 0.125
        # variation rtt
        self.var_rtt = None  ## TODO: revisit this later
        # beta
        self.beta = 0.25
        ### 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)
            self.totalQueueingDelay += packet.queueing_delay

    ''' Sender '''

    ''' Send data on the connection. Called by the application. This
        code currently sends all data immediately. '''
    ''' 1 '''
    def send(self,data):
        # Step 1
        if self.output:
            print "received data of size:" + str(len(data))
        self.send_buffer.put(data)
        self.send_max()
        

    def send_max(self):
        # Step 3
        while (self.send_buffer.next - self.send_buffer.base) < self.window \
            and (self.send_buffer.last - self.send_buffer.next) > 0:

            dataSize = min((self.window - (self.send_buffer.next - self.send_buffer.base)), self.mss)
            dataToSend, sequenceToSend = self.send_buffer.get(dataSize)
            if self.output:
                # print "sending this data: " + str(dataToSend)
                # print "the sequence of that data :" + str(sequenceToSend)
                # print "the size of that data :" + str(len(dataToSend))

                print "send buffer next: " +  str(self.send_buffer.next)
                print "send buffer base: " +  str(self.send_buffer.base)

            self.send_packet(dataToSend, sequenceToSend)

        if self.output:
            print "breaking out of the loop"

    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,
                           time_stamp=Sim.scheduler.current_time())

        # send the packet
        if self.stand_trace:
            self.trace("%s (%d) sending TCP segment to %d for %d" % (self.node.hostname,self.source_address,self.destination_address,packet.sequence))
        if self.seq_plot:
            self.trace("%d T" % (packet.sequence))
        if self.graph4:
            self.trace(str(self.port) + " " + str(packet.sequence) + " T")

        self.transport.send_packet(packet)

        # Step 4
        # set a timer
        if not self.timer:
            if self.proveTimer:
                print "Starting timer with timeout of: " + str(self.timeout)
            self.timer = Sim.scheduler.add(delay=self.timeout, event='retransmit', handler=self.retransmit)

    def handle_ack(self,packet):
        ''' Handle an incoming ACK. '''
        ''' Do elements 5, 6, and 7 '''
        ''' Also adjust the timer somewhere...'''
        if self.output:
            print "About to check ack_number > sequence: " + str(packet.ack_number) + " ? " + str(self.sequence)
        if self.seq_plot:
            self.trace("%d A" % (packet.ack_number))
        if self.graph4:
            self.trace(str(self.port) + " " + str(packet.ack_number) + " A")

        # handle duplicate acks
        if packet.ack_number == self.last_ack:
            if self.seq_plot:
                self.trace("%d A" % (packet.ack_number))
            if self.graph4:
                self.trace(str(self.port) + " " + str(packet.ack_number) + " A")
            if self.proveCong:
                print "We have 1 duplicate of " + str(self.last_ack)
            self.dup_counter += 1
            if self.dup_counter == 3:
                if self.proveCong:
                    print "We have 3 duplicate ACKs"
                self.cancel_timer()
                self.retransmit('3_dups')

        # handle new data
        if packet.ack_number > self.sequence:   # we have received new data
            self.last_ack = packet.ack_number
            self.dup_counter = 0
            # dynamic retransmission timer
            sample_rtt = Sim.scheduler.current_time() - packet.time_stamp
            self.restart_timer()
            if self.dynamic:
                self.adjust_timeout(sample_rtt)

            # adjusting the window for slow start
            newBytes = packet.ack_number - self.sequence
            if self.proveCong:
                print "\nWT: Window: " + str(self.window) + "  Threshold: " + str(self.thresh)

            if self.window < self.thresh:   # exponential increase
                if self.proveCong:
                    print "EI: setting window to " + str(self.window) + " += " + str(packet.ack_number) + " - " + str(self.sequence)
                self.window += self.mss
                if self.graph3:
                    self.trace(str(self.port) + " " + str(self.window))
            else:                           # additive increase
                #"""
                self.inc_sum += (self.mss * newBytes) / self.window     # gather increase until > mss
                mss_count = int(self.inc_sum / self.mss)                # how many mss's do we have
                self.inc_sum = self.inc_sum % self.mss                  # how much is left over (save that)
                if self.proveCong:
                    print "AI: setting window to " + str(self.window) + " += " + str(self.mss) + " * " + str(mss_count)
                    print "AI: remaining inc_sum is " + str(self.inc_sum)
                self.window += self.mss * mss_count                     # adjust window
                if self.graph3:
                    self.trace(str(self.port) + " " + str(self.window))

            # == UNCOMMENT THIS FOR DROPPING 3 PACKETS (as well as the code around line 130)
            # if self.window == 28000:
            #     self.drop_next = True


            # normal ack handling
            self.sequence = packet.ack_number
            if self.output:
                print "Handling Ack with an ack number of: " + str(packet.ack_number)
            if not self.send_buffer.slide(self.sequence):
                self.cancel_timer()
            if self.output:
                print "After handling the ack, our buffer base is " + str(self.send_buffer.base) + " and next is " + str(self.send_buffer.next)
            self.send_max()
        elif self.send_buffer.base >= self.send_buffer.last:
            self.cancel_timer()

    def retransmit(self,event):
        ''' Retransmit data. '''
        ''' 8 and 9 '''
        self.timer = None
        #print str(event)
        if self.dynamic:    # dynamic retransmission timer
            self.timeout *= 2
            if self.proveTimer:
                print "**Timer expired. Doubled timeout to " + str(self.timeout)

        # multiplicative decrease
        self.thresh = int(max(self.window/2, self.mss))
        #additive decrease
        #self.thresh = self.thresh - self.mss
        self.window = self.mss
        if self.graph3:
            self.trace(str(self.port) + " " + str(self.window))
        self.inc_sum = 0

        # actually retransmit
        dataToRetransmit, sequenceToRetransmit = self.send_buffer.resend(self.mss)

        if self.seq_plot:
            self.trace("%d X" % (sequenceToRetransmit))
        if self.graph4:
            self.trace(str(self.port) + " " + str(sequenceToRetransmit) + " X")

        self.send_packet(dataToRetransmit, sequenceToRetransmit)

        if self.stand_trace:
            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

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

    ''' 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.'''
        ''' R1 '''
        if self.stand_trace:
            self.trace("%s (%d) received TCP segment from %d for %d" % (self.node.hostname,packet.destination_address,packet.source_address,packet.sequence))
        if self.graph1:
            self.trace(str(self.port))#"%d" % (packet.sequence))
        self.receive_buffer.put(packet.body,packet.sequence)
        data, start = self.receive_buffer.get()
        self.ack = start + len(data)
        self.app.receive_data(data)
        #old self.app.receive_data(packet.body)
        self.send_ack(packet.time_stamp)

    def send_ack(self, time_stamp):
        ''' Send an ack. '''
        ''' R2 '''
        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,
                           time_stamp=time_stamp)
        # send the packet
        if self.stand_trace:
            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)

    def adjust_timeout(self,sample_rtt):
        if self.proveTimer:
            print "Received ACK with RTT of: " + str(sample_rtt)
        if not self.est_rtt:
            self.est_rtt = sample_rtt
        else:
            self.est_rtt = ((1 - self.alpha) * self.est_rtt) + (self.alpha * sample_rtt)
        if not self.var_rtt:
            self.var_rtt = sample_rtt/2
        else:
            self.var_rtt = ((1 - self.beta) * self.var_rtt) + (self.beta * abs(sample_rtt - self.est_rtt))
        before = self.timeout

        self.timeout = self.est_rtt + max(1.0, 4.0*self.var_rtt)
        if self.proveTimer:
            print "Timeout adjusted from " + str(before) + " to " + str(self.timeout)
Exemple #4
0
class TCP(Connection):
    ''' A TCP connection between two hosts.'''
    def __init__(self,transport,source_address,source_port,destination_address,destination_port,app=None):
        Connection.__init__(self,transport,source_address,source_port, destination_address,destination_port,app)

        ### RTO Timer Properties
        self.rtt_initialized = False
        self.rto = None
        self.srtt = None
        self.rttvar = None
        self.K = 4
        self.initialize_timer()

        # RTT Cap Seconds
        self.max_rtt = 60
        self.min_rtt = 1

        self.alpha = 0.125
        self.beta = 0.25

        ### Sender functionality

        self.transmission_finished = False

        # send buffer
        self.send_buffer = SendBuffer()
        # maximum segment size, in bytes
        self.mss = 1000
        # send window; represents the total number of bytes that may
        # be outstanding at one time
        self.window = self.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
        # is_retransmitting prevents more duplicate ACKs from triggering another send.
        self.is_retransmitting = False

        self.force_drop = True

        ### Congestion Control

        self.restarting_slow_start = False
        self.threshold = 16000
        self.additive_increase_total = 0

        # Fast Retransmit ACKs
        self.retransmit_acks = [-1] * 3

        ### 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

        ### Testing
        self.is_aiad = False

        ### FILE WRITING
        self.write_to_disk = True
        self.plot_port_number = 2

        self.plot_sequence_on = False
        self.plot_rate_on = True
        self.plot_queue_on = False
        self.plot_window_on = False

        file_name = "output.txt"
        header_message = "## header message ##"

        if self.plot_sequence_on:
            file_name = "sequence_plot.txt"
            header_message = "# Time (seconds) Sequence (number) Dropped (0 or 1) ACK (0 or 1)"
            Sim.set_debug("Link")
        elif self.plot_rate_on:
            file_name = "rate_plot.txt"
            header_message = "# Time (seconds) Size (number)"
        elif self.plot_queue_on:
            file_name = "queue_plot.txt"
            header_message = "# Time (seconds) Queue Size (bytes)"
            Sim.set_debug("Queue")
        elif self.plot_window_on:
            file_name = "window_plot.txt"
            header_message = "# Time (seconds) Congestion Window Size (bytes)"

        if self.write_to_disk:
            file_title,file_extension = file_name.split('.')
            new_file_name = file_title + str(self.plot_port_number) + '.' + file_extension
            self.trace("PRINTING TO: %s" % new_file_name)
            sys.stdout = open(new_file_name, 'w')
            print header_message

    ### Global Methods
    def trace(self,message):
        ''' Print debugging messages. '''
        if self.destination_port != self.plot_port_number:
            return

        if not self.plot_sequence_on and not self.plot_rate_on and not self.plot_queue_on and not self.plot_window_on:
            Sim.trace("TCP",message)

    def plot_sequence(self, sequence_number, isACK = False, dropped=False):
        if self.destination_port != self.plot_port_number:
            return

        message = "%i %i %d" % (sequence_number, dropped, isACK)

        if self.plot_sequence_on:
            Sim.trace("TCP", message)

    def plot_rate(self, size):
        if self.destination_port != self.plot_port_number:
            return

        message = "%i" % size

        if self.plot_rate_on:
            Sim.trace("TCP", message)

    def plot_window(self, size):
        if self.destination_port != self.plot_port_number:
            return

        message = "%i" % size

        if self.plot_window_on:
            Sim.trace("TCP", message)

    ### Congestion Control Methods

    def is_threshold_reached(self):
        self.trace("CURRENT THRESHOLD: %d" % self.threshold)
        return self.window >= self.threshold

    def slowstart_increment_cwnd(self, bytes_acknowledged):
        self.trace("AI -> BYTES ACKed: %d" % bytes_acknowledged)

        if self.restarting_slow_start:
            self.restarting_slow_start = False
            return

        self.window += min(bytes_acknowledged, self.window)
        self.trace("Window (Slow Start) == %d" % self.window)

    def additiveincrease_increment_cwnd(self, bytes_acknowledged):
        additive_increase = self.get_additive_increase(bytes_acknowledged)
        self.window += additive_increase
        self.trace("Window (AI) == %d" % self.window)

    # Add up increase until it's >= self.mss (1000), then return that amount.
    def get_additive_increase(self, bytes_acknowledged):
        increase = (self.mss * bytes_acknowledged / self.window)
        self.additive_increase_total += increase

        if self.additive_increase_total >= self.mss:
            self.additive_increase_total -= self.mss
            return self.mss
        else:
            self.trace("ADDITIVE INCREASE STORED: %d" % increase)
            return 0


    def reset_fastretransmit_acks(self):
        self.retransmit_acks = [-1] * 3

    def is_fast_retransmit(self, ack_num):
        self.retransmit_acks[2] = self.retransmit_acks[1]
        self.retransmit_acks[1] = self.retransmit_acks[0]
        self.retransmit_acks[0] = ack_num

        self.trace("FAST RETRANSMIT: %i, %i, %i" % (self.retransmit_acks[0], self.retransmit_acks[1], self.retransmit_acks[2]))

        return self.retransmit_acks[0] == self.retransmit_acks[1] and self.retransmit_acks[0] == self.retransmit_acks[2]

    def execute_loss_event(self, ack_loss_event=False):
        if not self.is_aiad:
            self.threshold = max(self.window / 2, self.mss)
        else:
            self.threshold -= max(self.threshold - self.mss, 0)

        self.window = self.mss

        self.additive_increase_total = 0
        self.restarting_slow_start = True
        self.trace("NEW WINDOW: %d" % self.window)
        self.trace("NEW THRESHOLD: %d" % self.threshold)

    ### General Methods

    def initialize_timer(self):
        self.rto = 3

    def calculate_rtt(self, rtt):
        if self.rtt_initialized is False:
            self.calculate_first_rtt(rtt)
            self.rtt_initialized = True
        else:
            self.calculate_ongoing_rtt(rtt)

    def calculate_first_rtt(self, new_rtt):
        self.srtt = new_rtt
        self.rttvar = new_rtt / 2
        self.rto = self.srtt + self.K * self.rttvar

    def calculate_ongoing_rtt(self, new_rtt):
        self.rttvar = (1 - self.beta) * self.rttvar + self.beta * abs(self.srtt - new_rtt)
        self.srtt = (1 - self.alpha) * self.srtt + self.alpha * new_rtt
        self.rto = self.srtt + self.K * self.rttvar
        self.validate_timer()

    def backoff_timer(self):
        self.rto *= 2
        self.validate_timer()

    def validate_timer(self):
        if self.rto < self.min_rtt:
            self.rto = self.min_rtt
        elif self.rto > self.max_rtt:
            self.rto = self.max_rtt

    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)

    def halt_if_finished(self):
        if self.send_buffer.available() == 0 and self.send_buffer.outstanding() == 0:
            self.trace("-------> ENDING <-------")
            self.cancel_timer()
            return True
        return False

    ''' 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.trace("Data added to buffer.")
        self.send_next_packet_if_possible()

    def send_next_packet_if_possible(self):
        if self.halt_if_finished():
            return

        while 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)
            self.restart_timer()

    def send_packet(self,data,sequence):
        current_time = Sim.scheduler.current_time()

        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=current_time)

        # if sequence == 32000 and self.force_drop:
        #     self.trace(">>> PACKET DROPPED: %d <<<" % sequence)
        #     self.plot_sequence(packet.sequence, dropped=True)
        #     return
        # elif sequence == 40000 and self.force_drop:
        #     self.trace(">>> PACKET DROPPED: %d <<<" % sequence)
        #     self.plot_sequence(packet.sequence, dropped=True)
        #     return
        # elif sequence == 41000 and self.force_drop:
        #     self.trace(">>> PACKET DROPPED: %d <<<" % sequence)
        #     self.plot_sequence(packet.sequence, dropped=True)
        #     self.force_drop = False
        #     return

        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.plot_sequence(packet.sequence)

    def handle_ack(self,packet):
        rtt = Sim.scheduler.current_time() - packet.sent_time
        self.trace("ACK RECEIVED: %d; RTT: %s" % (packet.ack_number, rtt))
        self.send_buffer.slide(packet.ack_number)

        if self.halt_if_finished():
            return

        self.plot_sequence(packet.ack_number, isACK=True)

        acked_byte_count = packet.ack_number - self.sequence
        self.sequence = packet.ack_number

        if self.is_retransmitting is False and self.is_fast_retransmit(packet.ack_number):
            self.is_retransmitting = True
            self.trace("PACKETS 1: %d; 2: %d; 3: %d" % (self.retransmit_acks[0], self.retransmit_acks[1], self.retransmit_acks[2]))
            self.retransmit(None,ack_loss_event=True)
            return
        elif self.is_retransmitting and acked_byte_count is 0:
            return

        self.is_retransmitting = False

        if self.is_threshold_reached():
            self.trace("---> ACKED BYTE COUNT: %d" % acked_byte_count)
            self.additiveincrease_increment_cwnd(acked_byte_count)
        else:
            self.slowstart_increment_cwnd(acked_byte_count)

        self.plot_window(self.window)

        self.send_next_packet_if_possible()
        self.calculate_rtt(rtt)

        if self.send_buffer.available() >= 0 or self.send_buffer.outstanding() > 0:
            self.restart_timer()
        else:
            self.cancel_timer()

    def retransmit(self,event,ack_loss_event=False):
        if self.halt_if_finished():
            return

        self.trace(">>>> WARNING: Timer expired.")

        self.backoff_timer()
        self.restart_timer(timer_expired=True)
        resend_data, resend_sequence = self.send_buffer.resend(self.mss)
        self.send_packet(resend_data, resend_sequence)

        # Reset for slow start.
        self.reset_fastretransmit_acks()
        self.execute_loss_event(ack_loss_event=ack_loss_event)

        if not event:
            self.trace("%s (%d) retransmission timer fired" % (self.node.hostname,self.source_address))

    def restart_timer(self, timer_expired = False):
        self.trace("WARNING: Restarting timer.")

        if self.send_buffer.available() == 0 and self.send_buffer.outstanding() == 0:
            self.cancel_timer()
        else:
            # self.trace("AVAILBLE: %d; OUTSTANDING: %d" % (self.send_buffer.available(), self.send_buffer.outstanding()))
            self.start_timer(timer_expired)

    def start_timer(self, timer_expired = False):
        # self.trace("WARNING: Starting timer.")
        if timer_expired == False:
            self.cancel_timer()

        self.timer = Sim.scheduler.add(delay=self.rto, event='retransmit', handler=self.retransmit)

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

    ''' Receiver '''

    def handle_data(self,packet):
        self.plot_rate(packet.length)

        self.trace("%s (%d) received TCP segment from %d; Seq: %d, Ack: %d" % (self.node.hostname,packet.destination_address,packet.source_address,packet.sequence,packet.ack_number))
        self.receive_buffer.put(packet.body, packet.sequence)

        # SEND DATA TO APPLICATION
        data, last_sequence_number = self.receive_buffer.get()
        self.ack = last_sequence_number + len(data)
        self.app.receive_data(data)

        self.send_ack(current_time=packet.sent_time, packet_sequence=packet.sequence)

    def send_ack(self, current_time, packet_sequence):
        ''' 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=packet_sequence,
                           ack_number=self.ack,
                           sent_time=current_time)

        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)
Exemple #5
0
    def __init__(self,transport,source_address,source_port,destination_address,destination_port,app=None):
        Connection.__init__(self,transport,source_address,source_port, destination_address,destination_port,app)

        ### RTO Timer Properties
        self.rtt_initialized = False
        self.rto = None
        self.srtt = None
        self.rttvar = None
        self.K = 4
        self.initialize_timer()

        # RTT Cap Seconds
        self.max_rtt = 60
        self.min_rtt = 1

        self.alpha = 0.125
        self.beta = 0.25

        ### Sender functionality

        self.transmission_finished = False

        # send buffer
        self.send_buffer = SendBuffer()
        # maximum segment size, in bytes
        self.mss = 1000
        # send window; represents the total number of bytes that may
        # be outstanding at one time
        self.window = self.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
        # is_retransmitting prevents more duplicate ACKs from triggering another send.
        self.is_retransmitting = False

        self.force_drop = True

        ### Congestion Control

        self.restarting_slow_start = False
        self.threshold = 16000
        self.additive_increase_total = 0

        # Fast Retransmit ACKs
        self.retransmit_acks = [-1] * 3

        ### 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

        ### Testing
        self.is_aiad = False

        ### FILE WRITING
        self.write_to_disk = True
        self.plot_port_number = 2

        self.plot_sequence_on = False
        self.plot_rate_on = True
        self.plot_queue_on = False
        self.plot_window_on = False

        file_name = "output.txt"
        header_message = "## header message ##"

        if self.plot_sequence_on:
            file_name = "sequence_plot.txt"
            header_message = "# Time (seconds) Sequence (number) Dropped (0 or 1) ACK (0 or 1)"
            Sim.set_debug("Link")
        elif self.plot_rate_on:
            file_name = "rate_plot.txt"
            header_message = "# Time (seconds) Size (number)"
        elif self.plot_queue_on:
            file_name = "queue_plot.txt"
            header_message = "# Time (seconds) Queue Size (bytes)"
            Sim.set_debug("Queue")
        elif self.plot_window_on:
            file_name = "window_plot.txt"
            header_message = "# Time (seconds) Congestion Window Size (bytes)"

        if self.write_to_disk:
            file_title,file_extension = file_name.split('.')
            new_file_name = file_title + str(self.plot_port_number) + '.' + file_extension
            self.trace("PRINTING TO: %s" % new_file_name)
            sys.stdout = open(new_file_name, 'w')
            print header_message
Exemple #6
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
        self.totalQueueingDelay = 0.0
        self.totalPacketsSent = 0
        self.output = False
        self.dynamic = True
        self.proveTimer = False
        # send window; represents the total number of bytes that may
        # be outstanding at one time
        # Step 2
        self.window = window
        # send buffer
        self.send_buffer = SendBuffer()
        # maximum segment size, in bytes
        # self.mss = 1000
        self.mss = min(1000, window)
        # 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.0
        if self.dynamic:
            self.timeout = 3.0
        # estimated rtt
        self.est_rtt = None
        # alpha
        self.alpha = 0.125
        # variation rtt
        self.var_rtt = None  ## TODO: revisit this later
        # beta
        self.beta = 0.25
        ### 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)
            self.totalQueueingDelay += packet.queueing_delay

    ''' Sender '''
    ''' Send data on the connection. Called by the application. This
        code currently sends all data immediately. '''
    ''' 1 '''

    def send(self, data):
        # Step 1
        if self.output:
            print "received data of size:" + str(len(data))
        self.send_buffer.put(data)
        if self.output:
            print "The end of the send buffer is: " + str(
                self.send_buffer.last)
        self.send_max()

    def send_max(self):
        # Step 3
        while (self.send_buffer.next - self.send_buffer.base) < self.window \
            and (self.send_buffer.last - self.send_buffer.next) > 0:

            dataSize = min((self.window -
                            (self.send_buffer.next - self.send_buffer.base)),
                           self.mss)
            dataToSend, sequenceToSend = self.send_buffer.get(dataSize)
            if self.output:
                # print "sending this data: " + str(dataToSend)
                # print "the sequence of that data :" + str(sequenceToSend)
                # print "the size of that data :" + str(len(dataToSend))

                print "send buffer next: " + str(self.send_buffer.next)
                print "send buffer base: " + str(self.send_buffer.base)

            self.send_packet(dataToSend, sequenceToSend)

        if self.output:
            print "breaking out of the loop"

    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,
                           time_stamp=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)
        self.totalPacketsSent += 1
        # Step 4
        # set a timer
        if not self.timer:
            if self.proveTimer:
                print "Starting timer with timeout of: " + str(self.timeout)
            self.timer = Sim.scheduler.add(delay=self.timeout,
                                           event='retransmit',
                                           handler=self.retransmit)

    def handle_ack(self, packet):
        ''' Handle an incoming ACK. '''
        ''' Do elements 5, 6, and 7 '''
        ''' Also adjust the timer somewhere...'''
        if self.output:
            print "About to check ack_number > sequence: " + str(
                packet.ack_number) + " ? " + str(self.sequence)
        if packet.ack_number > self.sequence:

            sample_rtt = Sim.scheduler.current_time() - packet.time_stamp
            self.restart_timer()

            if self.dynamic:
                self.adjust_timeout(sample_rtt)

            self.sequence = packet.ack_number
            if self.output:
                print "Handling Ack with an ack number of: " + str(
                    packet.ack_number)
            if not self.send_buffer.slide(self.sequence):
                if self.output:
                    print "FINAL TIMER CANCELATION"
                self.cancel_timer()
            if self.output:
                print "After handling the ack, our buffer base is " + str(
                    self.send_buffer.base) + " and next is " + str(
                        self.send_buffer.next)
            self.send_max()

    def retransmit(self, event):
        ''' Retransmit data. '''
        ''' 8 and 9 '''
        self.timer = None
        if self.dynamic:
            self.timeout *= 2
            if self.proveTimer:
                print "**Timer expired. Doubled timeout to " + str(
                    self.timeout)
        dataToRetransmit, sequenceToRetransmit = self.send_buffer.resend(
            self.mss)
        self.send_packet(dataToRetransmit, sequenceToRetransmit)
        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

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

    ''' 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.'''
        ''' R1 '''
        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.ack = start + len(data)
        self.app.receive_data(data)
        #old self.app.receive_data(packet.body)
        self.send_ack(packet.time_stamp)

    def send_ack(self, time_stamp):
        ''' Send an ack. '''
        ''' R2 '''
        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,
                           time_stamp=time_stamp)
        # 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)

    def adjust_timeout(self, sample_rtt):
        if self.proveTimer:
            print "Received ACK with RTT of: " + str(sample_rtt)
        if not self.est_rtt:
            self.est_rtt = sample_rtt
        else:
            self.est_rtt = (
                (1 - self.alpha) * self.est_rtt) + (self.alpha * sample_rtt)
        if not self.var_rtt:
            self.var_rtt = sample_rtt / 2
        else:
            self.var_rtt = ((1 - self.beta) * self.var_rtt) + (
                self.beta * abs(sample_rtt - self.est_rtt))
        before = self.timeout

        self.timeout = self.est_rtt + max(1.0, 4.0 * self.var_rtt)
        if self.proveTimer:
            print "Timeout adjusted from " + str(before) + " to " + str(
                self.timeout)