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