Example #1
0
bool ConnectionIn::addPacket(Packet& p){
	PacketHeader h;

	if(cc.transform){
		if(!cc.transform->remove(p, buffer.reset())){
			return false; // removal of packet transformation failed.
		}
	}

	Packet& input = cc.transform ? buffer : p;

	if(!h.read(input) || h.version != 0){
		return false; // packet has invalid header / unknown version.
	}

	int packet_age = 0;

	if(packet_history.none()){ // first packet recieved
		cc.seq_num = h.seq_num;
		packet_history[0] = 1;
	} else {
		int16_t seq_dist = static_cast<int16_t>(h.seq_num - cc.seq_num);

		if(abs(seq_dist) >= NRG_CONN_PACKET_HISTORY){
			return true; // packet is out of history range.
		}

		// states need to know about retransmissons of the newest packet
		if(seq_dist < 0 && (h.flags & PKTFLAG_RETRANSMISSION)){
			return true;
		}

		if(seq_dist > 0){ // new packet
			packet_history <<= seq_dist;
			packet_history[0] = 1;
			cc.seq_num = h.seq_num;

			// update ages of reassembly fragments and remove them if they're too old.
			for(auto& i : reassembly_buf){
				if(i.age >= 0) i.age += seq_dist;
				if(i.age > (int)NRG_CONN_PACKET_HISTORY){
					i.age = -1;
					i.data.reset();
				}
			}
		} else {
			if(packet_history[-seq_dist]){ // already recieved this packet.
				return true;
			} else {
				packet_history[-seq_dist] = 1;
				packet_age = -seq_dist;
			}
		}
	}

	if((h.flags & PKTFLAG_FINISHED) && (cc.seq_num != h.seq_num)){
		return false; // packet claims end of stream, but there is a newer one...
	}

	new_packet = true;

	// reconstruct packets that were split into multiple fragments.
	if(h.frag_index > 0 || (h.flags & PKTFLAG_CONTINUED)){

		if(h.frag_index >= reassembly_buf.size()){
			return false;
		}

		ReassemblyInfo& frag = reassembly_buf[h.frag_index];

		if(frag.age >= 0 && packet_age > frag.age){
			new_packet = false;
		} else {
			frag.data.writeArray(input.getPointer(), input.remaining());
			frag.age = packet_age;
			frag.continued = h.flags & PKTFLAG_CONTINUED;

			// check if the newly added fragment completes a full packet.
			for(size_t i = 0; i < reassembly_buf.size(); ++i){
				NRG_DEBUG("Age calc: [%d, %d]\n", (int)i, reassembly_buf[i].age);
				if(reassembly_buf[i].age == -1
				|| (i > 0 && reassembly_buf[i].age != reassembly_buf[i-1].age - 1)){
					new_packet = false;
				}
				if(!reassembly_buf[i].continued) break;
			}
			NRG_DEBUG("Got fragment, idx: %d, continued?: %d, age: %d full?: %d\n",
				h.frag_index, h.flags & PKTFLAG_CONTINUED, packet_age, new_packet
			);
			// write all the fragments out if they do form a full packet.
			if(new_packet){
				latest.reset();

				int age_counter = reassembly_buf[0].age;
				for(auto& i : reassembly_buf){
					if(i.age != age_counter--) break;
					latest.writeArray(i.data.getBasePointer(), i.data.size());
					i.data.reset();
					i.age = -1;
				}
			}
		}
	} else {
		latest.reset().writeArray(input.getPointer(), input.remaining());
	}

	if(cc.seq_num > h.seq_num) h.flags |= PKTFLAG_OUT_OF_ORDER;
	latest_flags = static_cast<PacketFlags>(h.flags);

	return true;
}