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