예제 #1
0
        def process_ack(self, ack_seq, ack_bits):
            #from net.settings import IS_CLIENT
            #if not IS_CLIENT:
            #    ipdb.set_trace()
            _DEBUG_RELIABLE_UDP and log.fields(conn=self.conn_info).debug("pre process_ack pending acks ack_seq %d bits %x : %s" % (ack_seq, ack_bits, self.pendingAckQueue))
            if is_seq_more_recent(ack_seq, self.latest_ack_seq):
                self.latest_ack_seq = ack_seq
            if self.pendingAckQueue:
                new_queue = ReliableUDPClientConnection.ReliabilitySystem.PacketQueue()
                for ack_info in self.pendingAckQueue:
                    acked = False
                    #if ack_info.seq == ack_seq and bit_index_for_sequence(ack_info.seq, ack_seq):
                    #    acked = True
                    #el
                    if not is_seq_more_recent(ack_info.seq, ack_seq) or ack_info.seq == ack_seq:
                        bit_index = bit_index_for_sequence(ack_info.seq, ack_seq)
                        if (bit_index <= 31):
                            acked = (ack_bits >> bit_index) & 1

                    if acked:
                        _DEBUG_RELIABLE_UDP and log.fields(conn=self.conn_info).debug("PROCESSED process_ack for packet %d" % ack_info.seq)
                        self.rtt += (ack_info.time - self.rtt) * 0.1
                        self.ackedQueue.insert_sorted(ack_info)
                        self.acks.append(ack_info.seq)
                        self.ackd_packets += 1
                    else:
                        new_queue.append(ack_info)
                self.pendingAckQueue = new_queue
                _DEBUG_RELIABLE_UDP and log.fields(conn=self.conn_info).debug("process_ack pending acks: %s" % self.pendingAckQueue)
예제 #2
0
 def packet_received(self, seq, packet):
     if seq in self.receivedQueue:
         log.fields(conn=self.conn_info).warning("received packet that was already received, seq %d" % (seq))
         #ipdb.set_trace()
         return False
     #TODO: not sure if need to include the packet data
     info = ReliableUDPClientConnection.ReliabilitySystem.PacketData(seq, 0.0, None)
     self.receivedQueue.append(info)
     if is_seq_more_recent(seq, self.remote_seq): #remote_msg_seq > self.remote_seq:
         self.remote_seq = seq
     self.last_gen_ack = -1
     self.cached_ack_bits = -1
     return True
예제 #3
0
    def process_datagram(self, dgram):
        #remote_msg_seq, msg_len, dgram = ReliableHeader.unpack(dgram)
        time_received = network_time(self.network_epoch)
        crc_successful = ReliableHeader.check_crc(dgram)

        if not crc_successful:
            if _DEBUG_RELIABLE_UDP:
                header, dgram = ReliableHeader.unpack(dgram)
                header, dgram = ReliableHeader.unpack(dgram)
                remote_msg_seq = header.seq
                msg_len = header.msg_len
                multi_seq_id = header.multi_seq_id
                _DEBUG_RELIABLE_UDP and log.fields(conn=self.conn_info).info("FAILED CRC (possibly false header data -- remote_seq %d, msg_len %d ts: %f, rtt: %f" % (remote_msg_seq, msg_len, header.timestamp, self.reliability.rtt))
            return # skip reliability system etc so that packet will be resent by sender

        header, dgram = ReliableHeader.unpack(dgram)
        remote_msg_seq = header.seq
        msg_len = header.msg_len
        multi_seq_id = header.multi_seq_id

        self.reliability.packet_received(header.seq, dgram)
        assert(header.timestamp >= 0.0)

        time_diff = time_received - (header.timestamp + self.reliability.rtt)
        _DEBUG_RELIABLE_UDP and log.fields(conn=self.conn_info).debug("recvd dgram, remote_seq %d, msg_len %d ts: %f, rtt: %f timediff: %f" % (remote_msg_seq, msg_len, header.timestamp, self.reliability.rtt, time_diff))
        if __debug__ and ((self.addr, self.port) != (dgram.addr)):
            ipdb.set_trace()
        self.reliability.process_ack(header.ack_seq, header.ack_bits)

        if (msg_len > ReliableHeader.max_usr_len or msg_len < 0):
            _DEBUG_RELIABLE_UDP and log.fields(conn=self.conn_info).debug("processing as multipacket multipacketid: %d", multi_seq_id)
            processed_msg = False
            for pending in self.pending_multipackets:
                if pending.needs_msg(multi_seq_id, remote_msg_seq, msg_len, dgram):
                    processed_msg = True
                    #log.fields(conn=self.conn_info).debug("adding to pending multipackets")
                    if pending.is_complete():
                        #ipdb.set_trace()
                        complete_msg = pending.get_msg()
                        super(ReliableUDPClientConnection, self).process_datagram(complete_msg)
                        self.pending_multipackets.remove(pending)
                        break
            if not processed_msg:
                #log.fields(conn=self.conn_info).debug("new pending multipackets")
                pending_multipacket = PendingMultiPacketMsg(multi_seq_id, remote_msg_seq, msg_len, dgram)
                self.pending_multipackets.append(pending_multipacket)
        else:
            if len(dgram) > 0: # if length zero then it was purely an ack packet
                super(ReliableUDPClientConnection, self).process_datagram(dgram)
예제 #4
0
    def update(self, dt, rtt, percent_unacked):
        if self.mode == FlowControl.Mode.Good:
            if rtt > FlowControl.RTT_THRESHOLD or percent_unacked > FlowControl.UNACKED_THRESHOLD_END:
                self.mode = FlowControl.Mode.Bad
                _DEBUG_RELIABLE_UDP and log.fields(conn=self.conn_info).info("flow control: dropping to bad mode")
                if self.good_conditions_time < 10.0 and self.penalty_time < 60.0:
                    self.penalty_time *= 2.0
                    if self.penalty_time > 60.0:
                        self.penalty_time = 60.0
                    self.good_conditions_time = 0.0
                    self.penalty_reduction_accumulator = 0.0
                    return

            self.good_conditions_time += dt
            self.penalty_reduction_accumulator += dt

            if self.penalty_reduction_accumulator > 10.0 and self.penalty_time > 1.0:
                self.penalty_time /= 2.0
                if self.penalty_time < 1.0:
                    self.penalty_time = 1.0

                _DEBUG_RELIABLE_UDP and log.fields(conn=self.conn_info).debug("flow control: penalty time reduced to %f" % self.penalty_time)
                self.penalty_accumulator = 0.0

        elif self.mode == FlowControl.Mode.Bad:
            if rtt <= FlowControl.RTT_THRESHOLD and percent_unacked < FlowControl.UNACKED_THRESHOLD_START:
                self.good_conditions_time += dt
            else:
                self.good_conditions_time = 0.0

            if self.good_conditions_time > self.penalty_time:
                _DEBUG_RELIABLE_UDP and log.fields(conn=self.conn_info).info("flow control: upgrading to good mode")
                self.good_conditions_time = 0.0
                self.penalty_reduction_accumulator = 0.0
                self.mode = FlowControl.Mode.Good
                return
        else:
            assert(False)
예제 #5
0
        def update_queues(self):
            while self.sentQueue and (self.sentQueue[0].time > (self.rtt_max + self.EPSILON) ):
                sent = self.sentQueue.pop(0)
                _DEBUG_RELIABLE_UDP and log.fields(conn=self.conn_info).debug("SENTQUEUE: removing seq %d" % sent.seq)

            if self.receivedQueue:
                last_seq = self.receivedQueue[-1].seq
                if last_seq >= 34:
                    min_seq = last_seq - 34
                else:
                    min_seq = self.max_seq - (34 - last_seq)

                while self.receivedQueue and not is_seq_more_recent(self.receivedQueue[-1].seq, min_seq):
                    recd = self.receivedQueue.pop(0)
                    _DEBUG_RELIABLE_UDP and log.fields(conn=self.conn_info).debug("RECDQUEUE: removing seq %d" % recd.seq)

            while self.ackedQueue and self.ackedQueue[-1].time > (self.rtt_max * 2 - self.EPSILON):
                ackd = self.ackedQueue.pop(0)
                _DEBUG_RELIABLE_UDP and log.fields(conn=self.conn_info).debug("ACKDQUEUE: removing seq %d" % ackd.seq)

            while self.pendingAckQueue and self.pendingAckQueue[-1].time > (self.rtt_max + self.EPSILON):
                packd = self.pendingAckQueue.pop(0)
                _DEBUG_RELIABLE_UDP and log.fields(conn=self.conn_info).debug("PACKDQUEUE: removing seq %d" % packd.seq)
                self.lost_packets += 1
예제 #6
0
    def _internal_queue_outgoing(self, header, msg_data, priority): #outgoing_dgram, priority):
        self.last_msg_dt = 0.0
        header.seq = self.reliability.local_seq
        header.ack_seq = self.reliability.remote_seq
        header.ack_bits = self.reliability.generate_ack_bits(header.ack_seq)
        header.timestamp = network_time(self.network_epoch)
        _DEBUG_RELIABLE_UDP and log.fields(conn=self.conn_info).debug("_internal_queue_outgoing, sending msg seq %d multi_seq %d msg_len %d network time %f" % (header.seq, header.multi_seq_id, header.msg_len, header.timestamp))
        full_data = header.to_data(msg_data)
        outgoing_dgram = Datagram(full_data, (self.addr, self.port))
        self.reliability.packet_sent(self.reliability.local_seq, outgoing_dgram)

        #log.fields(conn=self.conn_info).debug("_internal_queue_outgoing, presend count %d" % len(self.parent.outgoing))
        #from net.settings import IS_CLIENT
        #if not IS_CLIENT:
        #    ipdb.set_trace()

        # - calling parent queue outgoing
        super(ReliableUDPClientConnection, self).queue_outgoing(outgoing_dgram, priority)

        #log.fields(conn=self.conn_info).debug("_internal_queue_outgoing, postsend count %d" % len(self.parent.outgoing))
        self.set_writable(True)
예제 #7
0
    def queue_outgoing(self, msg, priority=5, reliable_header = None):
        if isinstance(msg, Datagram):
            dgram = msg
        else:
            dgram = Datagram(msg, (self.addr, self.port))

        #break our datagram into multiple if larger than the allowed size
        total_bytes = len(dgram) #TODO: check this is getting the right length
        #assert(total_bytes <= ReliableHeader.max_msg_len)
        curr_start_idx = 0
        curr_end_idx = 0
        curr_len = 0
        packet_count = 0
        multi_packet_seq = -1
        max_msg_bytes = ReliableHeader.max_usr_len
        if total_bytes > ReliableHeader.max_usr_len:
            multi_packet_seq = self.multi_packet_seq
            self.multi_packet_seq = seq_add(self.multi_packet_seq, 1)
            max_msg_bytes = ReliableHeader.max_multi_usr_len
            if _DEBUG_RELIABLE_UDP and __debug__:
                num_packets = ReliableHeader.calc_num_packets(total_bytes)
                log.fields(conn=self.conn_info).info("gen header multi_seq: %d msg_len %d" % (multi_packet_seq, num_packets))


        while True: #do while curr_end_idx < total_bytes:

            curr_len = total_bytes - curr_end_idx
            if (curr_len > max_msg_bytes):
                curr_len = max_msg_bytes
            _DEBUG_RELIABLE_UDP and log.fields(conn=self.conn_info).debug("curr len %d" % curr_len)

            curr_end_idx = curr_start_idx + curr_len

            msg_bytes = dgram[curr_start_idx:curr_end_idx]

            if packet_count > 0:
                msg_len_field = -packet_count
            else:
                msg_len_field = total_bytes

            _DEBUG_RELIABLE_UDP and log.fields(conn=self.conn_info).debug("gen header multi_seq: %d msg_len %d" % (multi_packet_seq, msg_len_field))
            #ack_seq = self.reliability.remote_seq
            #header = ReliableHeader()
            #header_bytes = ReliableHeader.generate_header(self.reliability.local_seq, msg_len_field, ack_seq, self.reliability.generate_ack_bits(ack_seq), multi_packet_seq)
            header = ReliableHeader(-1, msg_len_field, -1, -1, multi_packet_seq)
            #self.reliability.local_seq = seq_add(self.reliability.local_seq, 1) #self.local_seq + 1
            #assert(len(header_bytes + msg_bytes) <= ReliableHeader.max_msg_len)
            #outgoing_dgram = Datagram(header_bytes + msg_bytes, dgram.addr)
            #log.fields(conn=self.conn_info).debug("dgram: %s", outgoing_dgram)

            curr_start_idx = curr_end_idx
            packet_count = packet_count + 1

            #self.reliability.packet_sent(curr_packet_seq, outgoing_dgram)
            #super(ReliableUDPClientConnection, self).queue_outgoing(outgoing_dgram, priority)

            #self._internal_queue_outgoing(outgoing_dgram, priority)
            #self._internal_queue_msg(outgoing_dgram, priority)
            #self.unsent_queue.put(outgoing_dgram)
            #self.unsent_queue.inp.append(outgoing_dgram)
            self._internal_queue_msg(header, msg_bytes)

            #DO WHILE
            if curr_end_idx >= total_bytes:
                break
예제 #8
0
    def update(self):
        import datetime #__epoce
        #import time
        #send_delay = 0.0
        #send_accumulator = 0.0
        prev_time = datetime.datetime.utcnow() #time.clock()
        send_rate = self.flow_control.send_rate()
        while True:
            #TODO: debug timing slower for now
            #curr_max_wait_time = ReliableUDPConnection.MAX_TIME_BETWEEN_ACKS
            #curr_max_wait_time = (1.0 / send_rate) * 4.0
            #if self.send_delay > 0.0 and curr_max_wait_time > self.send_delay:
            #    diesel.sleep(self.send_delay) # can't send until this delay is completed
            #    curr_max_wait_time -= self.send_delay #NOTE: assuming send delay was approx what we said to sleep for.
            #    if curr_max_wait_time < 0.0:
            #        curr_max_wait_time = 0.0
            #        #ipdb.set_trace()
            #    self.send_delay = 0.0
            #print curr_max_wait_time
            #evt, data = diesel.first(sleep=curr_max_wait_time, waits = [self.pending_resends, self.unsent_queue])
            evt, data = diesel.first(waits = [self.pending_resends, self.unsent_queue])
            #print "send_event wait"
            if not self.send_event.is_set:
                self.waiting_to_send = True
            self.send_event.wait()
            self.send_delay = 0.0
            self.waiting_to_send = False
            #print "send_event wait DONE"
            curr_time = datetime.datetime.utcnow() #time.clock()
            dt = (curr_time - prev_time).total_seconds()
            prev_time = curr_time

            self.reliability.update(dt) #update latest acks etc.
            self.flow_control.update(dt, self.reliability.rtt, len(self.reliability.pendingAckQueue)/32.0 )

            next_msg = None
            priority = None
            if evt == self.pending_resends:
                #print "sending a resend, remaining: %d" % len(self.pending_resends.inp)
                header, next_msg = data
            elif evt == self.unsent_queue:
                header, next_msg = data
                #print "sending unsent msg, remaining %d" % len(self.unsent_queue.inp)

            missing_msgs = self.reliability.process_missing_msgs()
            for msg in missing_msgs:
                #ipdb.set_trace()
                data_dgram = Datagram(msg.data, self.addr)
                header, msgdata = ReliableHeader.unpack(data_dgram)
                prev_seq = header.seq
                #next_seq = self.reliability.local_seq
                #header.seq = next_seq
                #self.reliability.local_seq = seq_add(next_seq, 1)
                #log.fields(conn=self.conn_info).info("resending unacked msg, prev seq: %d, new seq %d len %d" % (prev_seq, next_seq, header.msg_len))
                _DEBUG_RELIABLE_UDP and log.fields(conn=self.conn_info).info("resending unacked msg, prev seq: %d, len %d" % (prev_seq, header.msg_len))
                #dgram = header.to_data() + msgdata
                #self._internal_queue_outgoing(dgram, 1)
                #self._internal_queue_msg(dgram, 1)
                #self.pending_resends.put(dgram)
                self.pending_resends.put((header, msgdata))

            #NOTE: handled above
            #if self.reliability.last_msg_dt > ReliableUDPClientConnection.ReliabilitySystem.MAX_ACK_TIME:
            #    self.queue_outgoing("")

            #self._internal_queue_outgoing(next_msg, priority)
            self._internal_queue_outgoing(header, next_msg, priority)

            per_msg_rate = 1.0 / send_rate
            self.send_accumulator -= per_msg_rate
            send_rate = self.flow_control.send_rate()
            self.send_delay = 0.0
            if self.send_accumulator < per_msg_rate:
                self.send_delay = -(self.send_accumulator - per_msg_rate)
                #ipdb.set_trace()
                assert(self.send_delay > 0.0)
                #print "send_event clear"
                self.send_event.clear()
        ipdb.set_trace()