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