Ejemplo n.º 1
0
    def on_reception(self, t, received_packet):
        assert received_packet.receiver == self.host
        if self.debug:
            print("t={}: {} received packet {}".format(round(t, 6), self,
                                                       received_packet))

        ### Per-flow receive rate ###
        self.em.log_it('FLOW|{}'.format(self.i),
                       'T|{}|RCVE|{}'.format(t, received_packet.size))

        #
        # OPERATIONS AGNOSTIC TO WHETHER WE'RE ESTABLISHED
        #

        if received_packet.ack_flag:
            # Got an ACK
            # Update window size and send_first_unacked.
            # Retransmit if needed
            if received_packet.ack_number < self.send_first_unacked:
                # TODO is this possible?
                assert False

            elif received_packet.ack_number == self.send_first_unacked:
                if received_packet.size == CONTROL_PACKET_SIZE:
                    # Only non-data packets can be dupacks
                    retransmit, self.window_size = self.cc.dupack(t)
                    self.em.log_it(
                        'FLOW|{}'.format(self.i),
                        'T|{}|WINDOW|{}'.format(t, self.window_size))
                    self.em.log_it('FLOW|{}'.format(self.i),
                                   'T|{}|DUPACK|1'.format(t))
                    if retransmit:
                        old_next = self.send_next
                        old_window_size = self.window_size
                        # Retransmit the lost packet (which is the first unacked packet)
                        # Subtle: invalidate its old ack timeout
                        self.send_next = self.send_first_unacked
                        self.window_size = 1
                        self.em.log_it(
                            'FLOW|{}'.format(self.i),
                            'T|{}|WINDOW|{}'.format(t, self.window_size))
                        self.ack_timeout_events[
                            self.send_first_unacked].invalidate()
                        self.act(t)
                        # Restore previous state
                        self.send_next = old_next
                        self.window_size = old_window_size
                        self.em.log_it(
                            'FLOW|{}'.format(self.i),
                            'T|{}|WINDOW|{}'.format(t, self.window_size))
                        self.act(t)
            else:
                self.em.log_it(
                    'FLOW|{}'.format(self.i), 'T|{}|THROUGHPUT|{}'.format(
                        t,
                        (received_packet.ack_number - self.send_first_unacked)
                        * DATA_PACKET_SIZE))
                self.send_first_unacked = received_packet.ack_number
                self.window_size = self.cc.posack(t)
                self.em.log_it('FLOW|{}'.format(self.i),
                               'T|{}|WINDOW|{}'.format(t, self.window_size))
                self.em.log_it('FLOW|{}'.format(self.i),
                               'T|{}|POSACK|1'.format(t))
                if self.send_first_unacked > self.last_seq_number:
                    # All packets are acked, so this flow is done
                    self.em.flowend_done(self)

            self.clear_redundant_timeouts(received_packet.ack_number)  # clean

            if self.rtt_sample_seq is not None and \
                    received_packet.ack_number > self.rtt_sample_seq:
                # NB: The only case that self.rtt_sample_seq is None is
                # when we get an ACK without ever having sent our own packet.
                # That's when we're the destination getting a SYN+ACK.
                self.on_rtt_sample(received_packet,
                                   t - self.rtt_sample_send_time, t)
                self.rtt_sample_seq = None
                self.rtt_sample_send_time = None

        #
        # OPERATIONS DEPENDING ON WHETHER WE'RE ESTABLISHED
        #

        if not self.is_established():
            # We're always sending a Syn received_packet.
            response_packet = Packet(i=self.flow.get_packet_id(),
                                     flow=self.flow,
                                     sender=self.host,
                                     receiver=self.other_host,
                                     syn_flag=True,
                                     ack_flag=False,
                                     fin_flag=False,
                                     seq_number=self.send_iss,
                                     ack_number=None,
                                     size=CONTROL_PACKET_SIZE)
            # But we also acknowledge the packet we've received if it's Syn.
            # We don't acknowledge data packets.
            if received_packet.syn_flag:
                # Update state
                self.receive_iss = received_packet.seq_number  # syn seq#
                self.receive_next = self.receive_iss + 1
                self.send_next = self.send_iss  # Reset 'next packet' to ISS

                # Modify response packet to change it to SynAck.
                response_packet.ack_flag = True
                response_packet.ack_number = self.receive_next

            self.send_acknowledgeable_packet(t, response_packet)

            # Can't act, since we're not established.

        else:  # We're established. A response is required if Syn or data.
            if received_packet.syn_flag or received_packet.size >= 513:
                if received_packet.syn_flag:  # Set initial sequence number
                    self.receive_iss = received_packet.seq_number
                    self.receive_next = self.receive_iss
                # Update receive_next
                self.received_seqs.add(received_packet.seq_number)
                while self.receive_next in self.received_seqs:
                    self.receive_next += 1

                response_packet = \
                    Packet(i=self.flow.get_packet_id(),
                           flow=self.flow,
                           sender=self.host,
                           receiver=self.other_host,
                           syn_flag=False,
                           ack_flag=True,
                           fin_flag=False,
                           seq_number=self.send_next,
                           ack_number=self.receive_next,
                           size=CONTROL_PACKET_SIZE)

                # Do NOT schedule a timeout, just send the packet.
                self.send(t, response_packet)

                if self.debug:
                    print("t={}: {} sends packet: {}".format(
                        round(t, 6), self, response_packet))

            self.act(t)  # May want to send data here.