Commits

Anonymous committed 9fca6b7

Fixed handling trace with missing segments

Comments (0)

Files changed (12)

 	uint8_t rdb_byte_hits;
 
 	timeval received_tstamp_pcap;
-	//vector<timeval> sent_tstamp_pcap;  // pcap tstamp for regular packet and retrans
-	vector< pair<timeval, uint8_t> > sent_tstamp_pcap;
+	vector< pair<timeval, uint8_t> > sent_tstamp_pcap; // pcap tstamp for when packet was sent, sent_type {ST_NONE, ST_PKT, ST_RTR, ST_PURE_ACK};
 
 	uint8_t send_tcp_stamp_recv_index; // The index of the element in the tstamps_tcp vector that matches the received tcp time stamp
 	uint32_t received_tstamp_tcp;
 		}
 	}
 
-	inline void increase_sent(uint32_t tstamp_tcp, timeval tstamp_pcap, bool rdb, bool packet_sent=true) {
+	inline void increase_sent(uint32_t tstamp_tcp, timeval tstamp_pcap, bool rdb, sent_type sent_t=ST_PKT) {
 		if (rdb) {
 			rdb_tstamps_tcp.push_back(tstamp_tcp);
 		}
 		else {
 			tstamps_tcp.push_back(tstamp_tcp);
 		}
-		if (packet_sent)
+
+		if (sent_t == ST_PKT)
 			packet_sent_count++;
 
-		sent_count++;
-		sent_tstamp_pcap.push_back(pair<timeval, uint8_t>(tstamp_pcap, packet_sent));
+		if (sent_t == ST_RTR)
+			packet_retrans_count++;
+
+		if (sent_t == ST_PURE_ACK)
+			acked_sent++;
+		else
+			sent_count++;
+
+		sent_tstamp_pcap.push_back(pair<timeval, uint8_t>(tstamp_pcap, sent_t));
 		lost_tstamps_tcp.push_back(pair<uint32_t,timeval>(tstamp_tcp, tstamp_pcap));
 	}
 
 		return split(start, end);
 	}
 
-/*
-	// Split and make a new range at the beginning
-	ByteRange* split_start(uint64_t start, uint64_t end) {
-		startSeq = end + 1;
-		return split(start, end);
-	}
-*/
 	ByteRange* split(uint64_t start, uint64_t end) {
 		ByteRange *new_br = new ByteRange(start, end);
 		new_br->packet_sent_count = 0;
 TARGET_LINK_LIBRARIES (analyseTCP pcap)
 
 # Set compiler flags for all configurations
-SET (CMAKE_CXX_FLAGS "-O3 -lm -Wall -Wno-long-long -Wno-variadic-macros") # -Werror?
+SET (CMAKE_CXX_FLAGS "-lm -Wall -Wno-long-long -Wno-variadic-macros") # -Werror?
 
 # Add NDEBUG only for release version
 # To activate: cmake -DCMAKE_BUILD_TYPE=Release ..
-SET (CMAKE_CXX_FLAGS_RELEASE "-DNDEBUG")
+SET (CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG")
 
 # Set debug compiler flags
 # To activate: cmake -DCMAKE_BUILD_TYPE=Debug ..
 	cs->analysed_end_sec += rm->analyse_time_sec_end;
 	cs->totBytesSent += rm->analysed_bytes_sent;
 	cs->totRetransBytesSent += rm->analysed_bytes_retransmitted;
-	cs->nrPacketsSent += rm->analysed_packet_count;
-	cs->nrPacketsSentFoundInDump += rm->analysed_packet_sent_count;
+	cs->nrPacketsSent += rm->analysed_packet_sent_count;
+	cs->nrPacketsSentFoundInDump += rm->analysed_packet_sent_count_in_dump;
 	cs->nrPacketsReceivedFoundInDump += rm->analysed_packet_received_count;
 	cs->nrDataPacketsSent += rm->analysed_data_packet_count;
 	cs->nrRetrans += rm->analysed_retr_packet_count;
 	cs->bundleCount += rm->analysed_rdb_packet_count;
 	cs->totUniqueBytes += getNumUniqueBytes();
+	cs->totUniqueBytesSent += rm->analysed_bytes_sent_unique;
 	cs->redundantBytes += rm->getRedundantBytes();
 	cs->rdb_bytes_sent += rm->rdb_byte_miss + rm->rdb_byte_hits;
 	cs->ackCount += rm->analysed_ack_count;
 	return dip.str();
 }
 
-void Connection::registerPacketSize(const timeval& first, const timeval& ts, const uint64_t ps) {
+void Connection::registerPacketSize(const timeval& first, const timeval& ts, const uint64_t ps, const uint16_t payloadSize) {
 	const uint64_t relative_ts = TV_TO_MS(ts) - TV_TO_MS(first);
 	const uint64_t sent_time_bucket_idx = relative_ts / GlobOpts::throughputAggrMs;
 
 	while (sent_time_bucket_idx >= packetSizes.size()) {
-		vector< pair<timeval, uint64_t> > empty;
+		vector< PacketSize> empty;
 		packetSizes.push_back(empty);
 	}
-
-	packetSizes[sent_time_bucket_idx].push_back(pair<timeval,uint64_t>(ts, ps));
+	packetSizes[sent_time_bucket_idx].push_back(PacketSize(ts, ps, payloadSize));
 }
 
 void Connection::writePacketByteCountAndITT(ofstream* all_stream, ofstream* conn_stream) {
-	vector<vector<pair<timeval,uint64_t> > >::iterator i;
-	vector<pair<timeval,uint64_t> >::iterator j;
-
-	if (conn_stream) {
-		*conn_stream << "itt,packet_size" << endl;
-	}
+	size_t i, j;
 
 	uint64_t k = 0;
 	while (packetSizes[k].empty()) k++;
 
-	uint64_t prev = TV_TO_MS(packetSizes[k][0].first);
+	uint64_t prev = TV_TO_MS(packetSizes[k][0].time);
 	uint64_t itt, tmp;
-	for (i = packetSizes.begin(); i != packetSizes.end(); ++i) {
-		for (j = i->begin(); j != i->end(); ++j) {
-			if (!j->second)
-				continue;
-
-			tmp = TV_TO_MS(j->first);
+	for (i = 0; i < packetSizes.size(); ++i) {
+		for (j = 0; j < packetSizes[i].size(); ++j) {
+			tmp = TV_TO_MS(packetSizes[i][j].time);
 			itt = tmp - prev;
 			prev = tmp;
 
 			if (all_stream) {
-				*all_stream << itt << "," << j->second << endl;
+				*all_stream << tmp << "," << itt << "," << packetSizes[i][j].payload_size << "," << packetSizes[i][j].packet_size << endl;
 			}
 			if (conn_stream) {
-				*conn_stream << itt << "," << j->second << endl;
+				*conn_stream << tmp << "," << itt << "," << packetSizes[i][j].payload_size << "," << packetSizes[i][j].packet_size << endl;
 			}
 		}
 	}
 #include <math.h>
 #include <netinet/in.h>
 
+struct PacketSize {
+	timeval time;
+	uint16_t packet_size;
+	uint16_t payload_size;
+	PacketSize(timeval t, uint16_t ps, uint16_t pls) : time(t), packet_size(ps), payload_size(pls) {
+	}
+};
+
 /* Represents one connection (srcport/dstport pair) */
 class Connection {
 
 	uint64_t lastLargestAckSeq;
 	uint32_t lastLargestAckSeqAbsolute;
 
-	vector< vector< pair<timeval,uint64_t> > > packetSizes;
-
+	vector< vector<struct PacketSize> > packetSizes;
 
 	timeval firstSendTime;
 	timeval endTime;
 	void calculateRetransAndRDBStats();
 	uint32_t getDuration(bool analyse_range_duration);
 
-	void registerPacketSize(const timeval& first_tstamp_in_dump, const timeval& pkt_tstamp, const uint64_t pkt_size);
+	void registerPacketSize(const timeval& first_tstamp_in_dump, const timeval& pkt_tstamp, const uint64_t pkt_size, const uint16_t payloadSize);
 	void writePacketByteCountAndITT(ofstream* all_stream, ofstream* conn_stream);
 };
 #endif /* CONNECTION_H */
 }
 
 void print_stats_separator(bool final) {
+	char c = '-';
 	if (final)
-		cout << "===============================================================" << endl << endl;
-	else
-		cout << "---------------------------------------------------------------" << endl;
+		c = '=';
+
+	for (int i = 0; i < 63; i++)
+		printf("%c", c);
+
+	printf("\n");
+	if (final)
+		printf("\n");
 }
 
 // Update minimum values
 		aggStats.avg = stats.avg;
 }
 
+void Dump::writeITT(ofstream& stream, vector<struct SentTime>& sent_times) {
+	//ofstream cdf_f;
+	//cdf_f.open((char*)(((GlobOpts::prefix + "itt-range-all.dat").str()).c_str()), ios::out);
+	const uint64_t first_tstamp = TV_TO_MS(first_sent_time);
+	printf("2 first_tstamp: %lu\n", first_tstamp);
+
+	for (size_t i = 0; i < sent_times.size(); i++) {
+		stream << (sent_times[i].time) << "," << sent_times[i].itt << "," << sent_times[i].size << endl;
+	}
+}
+
 
 /* Traverse the pcap dump and call methods for processing the packets
    This generates initial one-pass statistics from sender-side dump. */
 
 	int64_t max_value = (numeric_limits<int64_t>::max)();
 
+	vector<string> itt_fnames;
+	itt_fnames.push_back("itt-all.dat");
+	globStats->prefix_filenames(itt_fnames);
+	ofstream itt_stream;
+	itt_stream.open(itt_fnames[0].c_str(), ios::out);
+	itt_stream << "time,itt,payload_size" << endl;
+
 	// Print stats for each connection or aggregated
 	map<ConnectionMapKey*, Connection*, SortedConnectionKeyComparator> sortedConns;
 	fillWithSortedConns(sortedConns);
 
 		cIt->second->genBytesLatencyStats(&bs);
 
+		//printf("cs->nrPacketsSent: %d\n", cs.nrPacketsSent);
+
+		writeITT(itt_stream, bs.sent_times);
+
 		if (!(GlobOpts::aggOnly)) {
 			colored_printf(YELLOW, "STATS FOR CONN: %s:%u -> %s:%u", cIt->second->getSrcIp().c_str(), cIt->second->srcPort,
 			       cIt->second->getDstIp().c_str(), cIt->second->dstPort);
 				bsAggregated.dupacks[i] += bs.dupacks[i];
 			}
 		}
+		print_stats_separator(true);
 	}
 
 	if (GlobOpts::aggregate) {
 }
 
 
-/* Generate statistics for each connection.
-   update aggregate stats if requested */
-void Dump::printPacketStats(struct connStats *cs, struct byteStats *bs, bool aggregated, struct byteStats* aggregatedMin, struct byteStats* aggregatedMax) {
+void Dump::printPacketStats(connStats *cs, byteStats *bs, bool aggregated, byteStats* aggregatedMin, byteStats* aggregatedMax) {
 	printf("  Duration: %u seconds (%f hours)\n", cs->duration, ((double) cs->duration / 60 / 60));
 
 	if (cs->nrPacketsSent != cs->nrPacketsSentFoundInDump) {
 		printf("  Total packets sent (adj. for fragmentation)   : %10d\n", cs->nrPacketsSent);
 		printf("  Total packets sent (found in dump)            : %10d\n", cs->nrPacketsSentFoundInDump);
 		printf("  Total data packets sent (adj.)                : %10d\n", cs->nrDataPacketsSent);
-		printf("  Total data packets sent (found)               : %10d\n", cs->nrDataPacketsSent- (cs->nrPacketsSent - cs->nrPacketsSentFoundInDump));
+		printf("  Total data packets sent (found)               : %10d\n", cs->nrDataPacketsSent - (cs->nrPacketsSent - cs->nrPacketsSentFoundInDump));
 	}
 	else {
 		printf("  Total packets sent                            : %10d\n", cs->nrPacketsSent);
 	       "  SYN/FIN/RST packets sent                      : %10s\n"	\
 	       "  Number of retransmissions                     : %10d\n"	\
 	       "  Number of packets with bundled segments       : %10d\n"	\
-		   "  Number of received acks                       : %10d\n"    \
+		   "  Number of received acks                       : %10d\n"   \
 	       "  Total bytes sent (payload)                    : %10lu\n"	\
-	       "  Number of unique bytes                        : %10lu\n"	\
+	       "  Number of unique bytes                        : %10lu\n"   \
 	       "  Number of retransmitted bytes                 : %10d\n"	\
 		   "  Redundant bytes (bytes already sent)          : %10lu (%.2f %%)\n",
 		   cs->pureAcksCount, syn_fin_rst,
 		   cs->nrRetrans, cs->bundleCount, cs->ackCount, cs->totBytesSent,
-	       cs->totUniqueBytes, cs->totRetransBytesSent, cs->totBytesSent - cs->totUniqueBytes,
-	       ((double) (cs->totBytesSent - cs->totUniqueBytes) / cs->totBytesSent) * 100);
+	       cs->totUniqueBytesSent, cs->totRetransBytesSent, cs->totBytesSent - cs->totUniqueBytesSent,
+	       ((double) (cs->totBytesSent - cs->totUniqueBytesSent) / cs->totBytesSent) * 100);
+
+	if (cs->totUniqueBytesSent != cs->totUniqueBytes) {
+		colored_printf(RED, "  Trace is missing segments. Bytes missing      : %10d\n", cs->totUniqueBytes - cs->totUniqueBytesSent);
+	}
 
 	if (cs->nrPacketsSent != cs->nrPacketsSentFoundInDump) {
 		printf("  Estimated loss rate based on retransmission\n");
 
 
 void Dump::printStats(string prefix, string unit, struct BaseStats& bs) {
-	printf("  Minimum %s                                      : %7lu %s\n", prefix.c_str(), bs.min, unit.c_str());
-	printf("  Average %s                                      : %7.1f %s\n", prefix.c_str(), bs.avg, unit.c_str());
-	printf("  Maximum %s                                      : %7lu %s\n", prefix.c_str(), bs.max, unit.c_str());
+	printf("  Minimum %10s                            : %7lu %s\n", prefix.c_str(), bs.min, unit.c_str());
+	printf("  Average %10s                            : %7.0f %s\n", prefix.c_str(), bs.avg, unit.c_str());
+	printf("  Maximum %10s                            : %7lu %s\n", prefix.c_str(), bs.max, unit.c_str());
 }
 
 void Dump::printAggStats(string prefix, string unit, struct connStats *cs, struct BaseStats& bs, struct BaseStats& aggregatedMin, struct BaseStats& aggregatedMax) {
 		tmpConn->registerRange(&sd);
 
 	if (GlobOpts::withThroughput) {
-		tmpConn->registerPacketSize(first_sent_time, header->ts, header->len);
+		tmpConn->registerPacketSize(first_sent_time, header->ts, header->len, sd.data.payloadSize);
 	}
 }
 
 				const uint64_t count = conn->second->packetSizes[idx].size();
 				uint64_t bytes = 0;
 
-				vector<pair<timeval, uint64_t> >::iterator it, end;
+				vector<struct PacketSize>::iterator it, end;
 				it = conn->second->packetSizes[idx].begin();
 				end = conn->second->packetSizes[idx].end();
 
 				for (; it != end; ++it) {
-					bytes += it->second;
+					bytes += it->packet_size;
 				}
 
 				const pair<uint64_t,uint64_t>& old = all[idx];
 				const uint64_t count = conn->second->packetSizes[idx].size();
 				uint64_t bytes = 0;
 
-				vector<pair<timeval, uint64_t> >::iterator it, end;
+				vector<struct PacketSize>::iterator it, end;
 				it = conn->second->packetSizes[idx].begin();
 				end = conn->second->packetSizes[idx].end();
 
 				for (; it != end; ++it) {
-					bytes += it->second;
+					bytes += it->packet_size;
 				}
 
 				stream << idx << "," << count << "," << bytes << ",";
 
 void Dump::writeSentTimesAndQueueingDelayVariance() {
 	map<ConnectionMapKey*, Connection*>::iterator it;
-	const uint64_t first_tstamp = (uint64_t) TV_TO_MS(first_sent_time);
+	const uint64_t first_tstamp = TV_TO_MS(first_sent_time);
 
 	ofstream all_stream;
 	all_stream.open((GlobOpts::prefix + "queueing-delay-all.dat").c_str(), ios::out);
 
 	ofstream* all_stream = NULL;
 	ofstream* conn_stream = NULL;
+	string header("timestamp,itt,payload_size,packet_size");
 
 	if (GlobOpts::aggregate) {
 		all_stream = new ofstream;
 		all_stream->open((GlobOpts::prefix + "packet-byte-count-and-itt-all.dat").c_str(), ios::out);
-		*all_stream << "itt,packet_size" << endl;
+		*all_stream << header << endl;
 	}
 
 	for (it = conns.begin(); it != conns.end(); ++it) {
 			string filename (GlobOpts::prefix + "packet-byte-count-and-itt-" + it->second->getConnKey() + ".dat");
 			conn_stream = new ofstream;
 			conn_stream->open(filename.c_str(), ios::out);
+			*conn_stream << header << endl;
 		}
 
 		it->second->writePacketByteCountAndITT(all_stream, conn_stream);
 	void printPacketStats(struct connStats *cs, struct byteStats *bs, bool aggregated, struct byteStats* aggregatedMin, struct byteStats* aggregatedMax);
 	void printBytesLatencyStats(struct connStats *cs, struct byteStats* bs, bool aggregated, struct byteStats* aggregatedMin, struct byteStats* aggregatedMax);
 	void printPacketITTStats(struct connStats *cs, struct byteStats* bs, bool aggregated, struct byteStats* aggregatedMin, struct byteStats* aggregatedMax);
+	void writeITT(ofstream& stream, vector<struct SentTime>& sent_times);
 public:
 	Dump(string src_ip, string dst_ip, string src_port, string dst_port, string fn);
 	uint64_t get_relative_sequence_number(uint32_t ack, uint32_t firstSeq, ulong largestAckSeq, uint32_t largestAckSeqAbsolute, Connection *conn);
 Total bytes sent (payload) and Number of retransmitted bytes might differ slightly (2 bytes) from tcptrace, but according to tshark analysetcp is correct:
 
 ####Example of how to calculate total sum of tcp payload bytes and retransmitted bytes
-    shark -r trace.dump -qz io,stat,0,"ip.addr==10.0.0.10 && tcp.srcport ==\
+    tshark -r trace.dump -qz io,stat,0,"ip.addr==10.0.0.10 && tcp.srcport ==\
     15103","COUNT(tcp.analysis.retransmission)ip.addr==10.0.0.10 && tcp.srcport == 15102 &&\
     tcp.analysis.retransmission","SUM(tcp.len)tcp.len && ip.addr==10.0.0.10 && tcp.srcport ==\
     15102","SUM(tcp.len)tcp.len && ip.addr==10.0.0.10 && tcp.srcport == 15102 && tcp.analysis.retransmission"
 }
 
 void RangeManager::insertReceivedRange(struct sendData *sd) {
-
 	DataSeg tmpSeg;
-
 	tmpSeg.seq = sd->data.seq;
 	tmpSeg.endSeq = sd->data.endSeq;
 	tmpSeg.tstamp_pcap = (sd->data.tstamp_pcap);
 	//if (start_seq >= 21660765)
 	//	exit(0);
 
-	//if (start_seq >= 801 && start_seq <= 1101)
+	//if (start_seq >= 170779 && start_seq <= 170904)
 	//	debug_print = 1;
 	//fprintf(stderr, "level: %d\n", level);
 
 				indent_print2("Create range with 0 len\n");
 			}
 #endif
-
 			last_br = new ByteRange(start_seq, end_seq);
-			last_br->increase_sent(data_seg->tstamp_tcp, data_seg->tstamp_pcap, this_is_rdb_data);
 			last_br->packet_retrans_count += data_seg->retrans;
 			last_br->rdb_count += data_seg->is_rdb;
 			if (data_seg->flags & TH_SYN) {
-				//				printf("SYN 1\n");
 				last_br->syn = 1;
 #ifdef DEBUG
 				if (debug_print) {
 #endif
 			}
 			else {
-				last_br->acked_sent++;
-				//last_br->packet_sent_count--;
+				//last_br->acked_sent++;
 			}
+			last_br->increase_sent(data_seg->tstamp_tcp, data_seg->tstamp_pcap, this_is_rdb_data, (last_br->syn | last_br->rst | last_br->fin) ? ST_PKT : ST_PURE_ACK);
 			ranges.insert(pair<ulong, ByteRange*>(start_seq, last_br));
 			return;
 		}
 					ByteRange *new_br;
 					if (start_matches) {
 						new_br = cur_br->split_end(end_seq + 1, cur_br->endSeq);
-						//cur_br->packet_sent_count++;
 						if (data_seg->flags & TH_FIN) {
 							cur_br->fin += 1;
 						}
 					}
 					else if (end_matches) {
 						new_br = cur_br->split_end(start_seq, cur_br->endSeq);
-						//new_br->packet_sent_count++;
 						if (data_seg->flags & TH_FIN) {
 							new_br->fin = 1;
 						}
 					else if (end_seq < cur_br->endSeq) {
 						// Split in the middle
 						new_br = cur_br->split_end(start_seq, cur_br->endSeq);
-						//new_br->packet_sent_count++;
 						if (data_seg->flags & TH_FIN) {
 							new_br->fin = 1;
 						}
 						ranges.insert(pair<ulong, ByteRange*>(new_last->startSeq, new_last));
 						range_received = new_br;
 					}
-					// New data reaches beyond current range
+					// New data spans beyond current range
 					else {
 						new_br = cur_br->split_end(start_seq, cur_br->endSeq);
-						//new_br->packet_sent_count++;
 						range_received = new_br;
 						insert_more_recursively = 1;
 					}
 					ranges.insert(pair<ulong, ByteRange*>(new_br->startSeq, new_br));
 
 					if (sent) {
-						range_received->increase_sent(data_seg->tstamp_tcp, data_seg->tstamp_pcap, this_is_rdb_data);
+						sent_type type = ST_NONE;
 						if (!level)
-							range_received->packet_retrans_count++;
+							type = ST_RTR;
+
+						range_received->increase_sent(data_seg->tstamp_tcp, data_seg->tstamp_pcap, this_is_rdb_data, type);
 						range_received->data_retrans_count++;
 
 						//printf("data_seg->retrans: %d\n", data_seg->retrans);
 			}
 #endif
 			last_br = new ByteRange(start_seq, new_end_seq);
-			//printf("ByteRange size: %lu\n", sizeof(*last_br));
-
 			last_br->original_payload_size = data_seg->payloadSize;
 			last_br->original_packet_is_rdb = data_seg->is_rdb;
-			if (data_seg->is_rdb) {
-				// Packet sent is already counted on previous range
-				//last_br->packet_sent_count = 0;
-			}
 
-			last_br->increase_sent(data_seg->tstamp_tcp, data_seg->tstamp_pcap, this_is_rdb_data, !data_seg->is_rdb);
+			last_br->increase_sent(data_seg->tstamp_tcp, data_seg->tstamp_pcap, this_is_rdb_data, data_seg->is_rdb ? ST_NONE : ST_PKT);
 			if (data_seg->flags & TH_SYN) {
 				assert("SYN" && 0);
 				last_br->syn = 1;
 					last_br->packet_received_count++;
 				}
 
-				//last_br->increase_sent(data_seg->tstamp_tcp, data_seg->tstamp_pcap, this_is_rdb_data);
 				if (data_seg->flags & TH_SYN) {
 					last_br->syn = 1;
 				}
 				else if (data_seg->flags & TH_FIN) {
 					last_br->fin = 1;
 				}
-
 #ifdef DEBUG
 				assert(data_seg->retrans == 0 && "Shouldn't be retrans!\n");
 				assert(this_is_rdb_data == 0 && "Shouldn't be RDB?!\n");
 				}
 #endif
 				if (sent) {
-					brIt->second->packet_sent_count++;
 					if (data_seg->flags & TH_SYN || data_seg->flags & TH_FIN) {
 						//assert("Exists no payload " && 0);
 						//colored_printf(RED, "SYN: %d, FIN: %d\n", !!(data_seg->flags & TH_SYN), data_seg->flags & TH_FIN);
 						brIt->second->syn += !!(data_seg->flags & TH_SYN);
 						brIt->second->fin += !!(data_seg->flags & TH_FIN);
-						brIt->second->increase_sent(data_seg->tstamp_tcp, data_seg->tstamp_pcap, this_is_rdb_data, false);
-						brIt->second->packet_retrans_count += 1;
+						brIt->second->increase_sent(data_seg->tstamp_tcp, data_seg->tstamp_pcap, this_is_rdb_data, ST_PKT);
 					}
 					else if (data_seg->flags & TH_RST) {
+						brIt->second->increase_sent(data_seg->tstamp_tcp, data_seg->tstamp_pcap, this_is_rdb_data, ST_PKT);
 						brIt->second->rst++;
 					}
 					else {
-						brIt->second->acked_sent += 1;
+						brIt->second->increase_sent(data_seg->tstamp_tcp, data_seg->tstamp_pcap, this_is_rdb_data, ST_PURE_ACK);
 #ifdef DEBUG
 						if (debug_print) {
 							indent_print("Neither SYN nor FIN!, increased acked_sent to %d\n", brIt->second->acked_sent);
 				}
 			}
 
-			// Reaches multiple byte ranges
+			// Spans multiple byte ranges
 			if (brIt->second->endSeq < end_seq) {
 #ifdef DEBUG
 				if (debug_print) {
 				}
 #endif
 				if (sent) {
-					assert("sent_count is 0!" && brIt->second->sent_count > 0);
-
-					brIt->second->increase_sent(data_seg->tstamp_tcp, data_seg->tstamp_pcap, this_is_rdb_data, !level);
-
-					if (!level) {
-						brIt->second->packet_retrans_count += data_seg->retrans;
-						//brIt->second->packet_sent_count++;
-						if (data_seg->flags & TH_FIN) {
-							brIt->second->fin += 1;
+					//assert("sent_count is 0!" && brIt->second->sent_count > 0);
+
+					// This means this has only pure acks registered
+					if (brIt->second->byte_count == 0) {
+						// We are at the last range in the map
+						if (ranges.rbegin()->second == brIt->second) {
+							// The last range in the map only had pure acks, so we hijack this and add the data to it
+							brIt->second->endSeq = end_seq;
+							brIt->second->update_byte_count();
+							brIt->second->original_payload_size = brIt->second->byte_count;
+							brIt->second->increase_sent(data_seg->tstamp_tcp, data_seg->tstamp_pcap, this_is_rdb_data, ST_PKT);
+							return;
 						}
 					}
-					brIt->second->data_retrans_count += data_seg->retrans;
-					brIt->second->rdb_count += data_seg->is_rdb;
-
+					else {
+						sent_type type = ST_NONE;
+						if (!level) {
+							type = data_seg->retrans ? ST_RTR : ST_PKT;
+							if (data_seg->flags & TH_FIN) {
+								brIt->second->fin += 1;
+							}
+						}
+						brIt->second->increase_sent(data_seg->tstamp_tcp, data_seg->tstamp_pcap, this_is_rdb_data, type);
+						brIt->second->data_retrans_count += data_seg->retrans;
+						brIt->second->rdb_count += data_seg->is_rdb;
 #ifdef DEBUG
-					if (debug_print) {
-						indent_print("Adding tcp timestamp 2 to %s : %u\n",  this_is_rdb_data ? "rdb" : "reg", data_seg->tstamp_tcp);
-					}
+						if (debug_print) {
+							indent_print("Adding tcp timestamp 2 to %s : %u\n",  this_is_rdb_data ? "rdb" : "reg", data_seg->tstamp_tcp);
+						}
 
-					if (this_is_rdb_data) {
-						assert(data_seg->retrans == 0 && "Should not be retrans!\n");
-					}
+						if (this_is_rdb_data) {
+							assert(data_seg->retrans == 0 && "Should not be retrans!\n");
++						}
 #endif
+					}
 				}
 				else {
 					brIt->second->increase_received(data_seg->tstamp_tcp, data_seg->tstamp_pcap, data_seg->in_sequence);
 				//printf("Recursive call: brIt->endseq: %lu, endseq: %lu\n", brIt->second->endSeq, end_seq);
 				insert_byte_range(brIt->second->endSeq +1, end_seq, sent, data_seg, level +1);
 			}
-			// Reaches less than the range, split current range
+			// Spans less than the range, split current range
 			else {
 				ByteRange *new_br = brIt->second->split_end(end_seq +1, brIt->second->endSeq);
 #ifdef DEBUG
 				if (debug_print) {
-					indent_print2("Reaches less, split existing Range\n");
+					indent_print2("Spans less, split existing Range\n");
 					indent_print("Existing range : %lu - %lu -> %lu - %lu\n", relative_seq(brIt->second->startSeq), relative_seq(brIt->second->endSeq),
 								 relative_seq(brIt->second->startSeq), relative_seq(end_seq));
 					indent_print("New range      : %lu - %lu\n", relative_seq(new_br->startSeq), relative_seq(new_br->endSeq));
 				}
 #endif
 				if (sent) {
+					sent_type type = ST_NONE;
 					if (!level) {
-						brIt->second->packet_retrans_count += data_seg->retrans;
-						//brIt->second->packet_sent_count++;
+						type = data_seg->retrans ? ST_RTR : ST_PKT;
 						if (data_seg->flags & TH_FIN) {
 							brIt->second->fin += 1;
 						}
 					}
 					brIt->second->data_retrans_count += data_seg->retrans;
 					brIt->second->rdb_count += data_seg->is_rdb;
-					brIt->second->increase_sent(data_seg->tstamp_tcp, data_seg->tstamp_pcap, this_is_rdb_data, !level);
+					brIt->second->increase_sent(data_seg->tstamp_tcp, data_seg->tstamp_pcap, this_is_rdb_data, type);
 #ifdef DEBUG
 					if (this_is_rdb_data) {
 						assert(data_seg->retrans != 0 && "Should not be retrans!\n");
 		else {
 			// The end_seq of the new range correspond to the end-seq of the entry in the map, so it's a duplicate
 			if (sent) {
-				brIt->second->increase_sent(data_seg->tstamp_tcp, data_seg->tstamp_pcap, this_is_rdb_data, !level);
+				sent_type type = ST_NONE;
 				if (!level) {
-					brIt->second->packet_retrans_count += data_seg->retrans;
-					//brIt->second->packet_sent_count++;
+					type = data_seg->retrans ? ST_RTR : ST_PKT;
 					if (data_seg->flags & TH_FIN) {
 						brIt->second->fin += 1;
 					}
 				}
+				brIt->second->increase_sent(data_seg->tstamp_tcp, data_seg->tstamp_pcap, this_is_rdb_data, type);
 				brIt->second->data_retrans_count += data_seg->retrans;
 				brIt->second->rdb_count += data_seg->is_rdb;
 
 			if (debug_print)
 				printf("  Covers more than Range(%lu, %lu)\n", relative_seq(tmpRange->getStartSeq()), relative_seq(tmpRange->getEndSeq()));
 
-
 			if (timercmp(&seg->tstamp_pcap, &(tmpRange->sent_tstamp_pcap[0].first), <)) {
 				printf("ACK TIME IS EARLIER THAN SEND TIME!\n");
 				return false;
 	}
 }
 
-struct SentTime {
-	int64_t time;
-	uint16_t size;
-	SentTime(int t, uint16_t s) : time(t), size(s) {}
-
-	bool operator < (const SentTime& other) const {
-        return (time < other.time);
-    }
-};
-
 
 void RangeManager::genStats(struct byteStats *bs) {
 	map<ulong, ByteRange*>::iterator it, it_end;
 	it = analyse_range_start;
 	it_end = analyse_range_end;
 
-	vector<struct SentTime> sent_times;
 	int64_t latency, tmp_byte_count, itt;
 	bs->latency.min = bs->packet_length.min = bs->itt.min = (numeric_limits<int64_t>::max)();
 	int dupack_count;
 		}
 
 		for (size_t i = 0; i < it->second->sent_tstamp_pcap.size(); i++) {
-			if (it->second->sent_tstamp_pcap[i].second)
-				sent_times.push_back(SentTime(TV_TO_MS(it->second->sent_tstamp_pcap[i].first), tmp_byte_count));
+			if (it->second->sent_tstamp_pcap[i].second) {
+				bs->sent_times.push_back(SentTime(TV_TO_MS(it->second->sent_tstamp_pcap[i].first), tmp_byte_count));
+			}
 		}
 
 		dupack_count = it->second->dupack_count;
 		}
 	}
 
-	std::sort(sent_times.begin(), sent_times.end());
+	std::sort(bs->sent_times.begin(), bs->sent_times.end());
 
-	SentTime prev = sent_times[0];
-	for (size_t i = 1; i < sent_times.size(); i++) {
-		itt = sent_times[i].time - prev.time;
+	SentTime prev = bs->sent_times[0];
+	for (size_t i = 1; i < bs->sent_times.size(); i++) {
+		itt = bs->sent_times[i].time - prev.time;
 		bs->intertransmission_times.push_back(itt);
-		prev = sent_times[i];
+		bs->sent_times[i].itt = itt;
+		prev = bs->sent_times[i];
 		bs->itt.cum += itt;
 
 		if (itt > bs->itt.max)
 		//std::sort(bs->payload_lengths.begin(), bs->payload_lengths.end());
 		//stdev = sqrt(temp / (bs->payload_lengths.size()));
 		//bs->stdevLength = stdev;
-		bs->itt.avg = (double) bs->itt.cum / sent_times.size();
+		bs->itt.avg = (double) bs->itt.cum / bs->sent_times.size();
 		percentiles(&bs->intertransmission_times, &bs->percentiles_lengths);
 	}
 	else
 
 		printf(" %-*lu - %-*lu: snt-pkt: %d, rvc-pkt: %d, sent: %d, rcv: %d, retr-pkt: %d, retr-dta: %d, rdb-cnt: %d, RCV: %s, rdb-miss: %-3d rdb-hit: %-3d",
 		       seq_char_len, relative_seq(it->second->startSeq),
-			   seq_char_len, relative_seq(it->second->endSeq), it->second->packet_sent_count, it->second->packet_received_count,
+			   seq_char_len, relative_seq(it->second->endSeq), (it->second->packet_sent_count + it->second->acked_sent),
+			   it->second->packet_received_count,
 			   it->second->sent_count, it->second->received_count, it->second->packet_retrans_count,
 			   it->second->data_retrans_count, it->second->rdb_count, received_type_str[it->second->recv_type],
 			   it->second->rdb_byte_miss, it->second->rdb_byte_hits);
 
 		if (brIt->second->byte_count) {
 			// Always count 1 for a ByteRange, even though the orignal sent data might have been segmented on the wire.
-			//analysed_data_packet_count += 1 + brIt->second->packet_retrans_count;
-			//if (brIt->second->packet_sent_count)
-			//	printf("SENT COUNT: %d\n", brIt->second->packet_sent_count);
-			//analysed_data_packet_count += (brIt->second->packet_sent_count > 0) + brIt->second->packet_retrans_count;
-			//analysed_data_packet_count += brIt->second->packet_sent_count;
 			analysed_data_packet_count += 1 + brIt->second->packet_retrans_count;
 		}
 
 		analysed_pure_acks_count += brIt->second->acked_sent;
 		analysed_rdb_packet_count += brIt->second->original_packet_is_rdb;
 		analysed_bytes_sent += brIt->second->sent_count * brIt->second->byte_count;
-		analysed_packet_count += 1 + brIt->second->packet_retrans_count; // This is the number of (adjusted) packets sent, which will be greater if segmentation offloading is enabled.
-
-		analysed_packet_count += brIt->second->acked_sent; // Count pure acks
-		analysed_packet_count += brIt->second->rst; // Count rst packets
-
-		// Range with no bytes
-		if (!brIt->second->byte_count) {
-			// This is a pure ack with no data transfered first (special case)
-			// Normally a pure ack is registered on a range with data
-			if (!(brIt->second->syn || brIt->second->fin)) {
-				// We already counted this packet with 1 + acked_sent, so remove 1
-				analysed_packet_count--;
-			}
-		}
+		analysed_bytes_sent_unique += brIt->second->byte_count;
+
+		// This is the number of (adjusted) packets sent, which will be greater if segmentation offloading is enabled.
+		// We count 1 for all ranges with data and where syn or fin is set
+		analysed_packet_sent_count += (brIt->second->syn || brIt->second->fin || brIt->second->byte_count);
+		analysed_packet_sent_count += brIt->second->packet_retrans_count;
+		analysed_packet_sent_count += brIt->second->acked_sent; // Count pure acks
+
+		// THIS MIGHT BE WRONG. REMOVE?
+		analysed_packet_sent_count += brIt->second->rst; // Count rst packets
 
 		/*
 		if (brIt->second->acked_sent) {
 						   brIt->second->startSeq, brIt->second->endSeq, brIt->second->acked_sent);
 		}
 		*/
+
 		analysed_retr_packet_count += brIt->second->packet_retrans_count;
 		analysed_bytes_retransmitted += brIt->second->data_retrans_count * brIt->second->byte_count;
 		analysed_ack_count += brIt->second->ack_count;
-		analysed_packet_sent_count += brIt->second->packet_sent_count;         // This should be the number of packets found in the dump (same as wireshark and tcptrace)
-		analysed_packet_received_count += brIt->second->packet_received_count; // This should be the number of packets found in the dump (same as wireshark and tcptrace)
-
-		if (brIt->second->sent_count != brIt->second->received_count) {
-			analysed_lost_ranges_count += (brIt->second->sent_count - brIt->second->received_count);
-			analysed_lost_bytes += (brIt->second->sent_count - brIt->second->received_count) * brIt->second->byte_count;
-			ulong lost = (brIt->second->sent_count - brIt->second->received_count);
-
-			// Must check if this lost packet is the same packet as for the previous range
-			if (prev_pack_lost) {
-				for (ulong i = 0; i < brIt->second->lost_tstamps_tcp.size(); i++) {
-					for (ulong u = 0; u < prev->lost_tstamps_tcp.size(); u++) {
-						if (brIt->second->lost_tstamps_tcp[i].first == prev->lost_tstamps_tcp[u].first) {
-							lost -= 1;
-							if (!lost) {
-								i = brIt->second->lost_tstamps_tcp.size();
-								u = prev->lost_tstamps_tcp.size();
+
+		// This should be the number of packets found in the dump (same as wireshark and tcptrace)
+		analysed_packet_sent_count_in_dump += brIt->second->packet_sent_count + brIt->second->packet_retrans_count + brIt->second->acked_sent;
+
+		// This should be the number of packets found in the dump (same as wireshark and tcptrace)
+		analysed_packet_received_count += brIt->second->packet_received_count;
+
+		if (GlobOpts::withRecv) {
+			if (brIt->second->sent_count != brIt->second->received_count) {
+				analysed_lost_ranges_count += (brIt->second->sent_count - brIt->second->received_count);
+				analysed_lost_bytes += (brIt->second->sent_count - brIt->second->received_count) * brIt->second->byte_count;
+				ulong lost = (brIt->second->sent_count - brIt->second->received_count);
+
+				// Must check if this lost packet is the same packet as for the previous range
+				if (prev_pack_lost) {
+					for (ulong i = 0; i < brIt->second->lost_tstamps_tcp.size(); i++) {
+						for (ulong u = 0; u < prev->lost_tstamps_tcp.size(); u++) {
+							if (brIt->second->lost_tstamps_tcp[i].first == prev->lost_tstamps_tcp[u].first) {
+								lost -= 1;
+								if (!lost) {
+									i = brIt->second->lost_tstamps_tcp.size();
+									u = prev->lost_tstamps_tcp.size();
+								}
 							}
 						}
 					}
 				}
+				lost_packets += lost;
+				prev_pack_lost = true;
 			}
-			lost_packets += lost;
-			prev_pack_lost = true;
+			else
+				prev_pack_lost = false;
 		}
-		else
-			prev_pack_lost = false;
 
 		if (brIt->second->sent_count > 1)
 			lost_tmp += brIt->second->sent_count - 1;
 	it = analyse_range_start;
 	it_end = analyse_range_end;
 
-	//const long first = TV_TO_MS(ranges[0]->sent_tstamp_pcap[0]);
-
 	for (; it != it_end; it++) {
 		long diff = it->second->getRecvDiff() - lowestRecvDiff;
 		int64_t ts = TV_TO_MS(it->second->sent_tstamp_pcap[it->second->send_tcp_stamp_recv_index].first);
 #include "time_util.h"
 
 enum received_type {DEF, DATA, RDB, RETR};
+enum sent_type {ST_NONE, ST_PKT, ST_RTR, ST_PURE_ACK};
 
 extern const char *received_type_str[4];
 
 	int analysed_sent_ranges_count;
 	uint analysed_lost_bytes;
 	int ack_count;
-	uint64_t analysed_bytes_sent, analysed_bytes_retransmitted, analysed_redundant_bytes;
-	int analysed_packet_count, analysed_retr_packet_count, analysed_rdb_packet_count, analysed_ack_count,
-		analysed_packet_sent_count, analysed_packet_received_count, analysed_ranges_count, analysed_sent_pure_ack_count;
+	uint64_t analysed_bytes_sent, analysed_bytes_sent_unique, analysed_bytes_retransmitted, analysed_redundant_bytes;
+	int analysed_packet_sent_count, analysed_retr_packet_count, analysed_rdb_packet_count, analysed_ack_count,
+		analysed_packet_sent_count_in_dump, analysed_packet_received_count, analysed_ranges_count, analysed_sent_pure_ack_count;
 	int analysed_data_packet_count;
 	int analysed_syn_count, analysed_fin_count, analysed_rst_count, analysed_pure_acks_count;
 
 													  rdb_packet_misses(0), rdb_packet_hits(0), rdb_byte_miss(0),
 													  rdb_byte_hits(0), analysed_lost_ranges_count(0),
 													  analysed_sent_ranges_count(0), analysed_lost_bytes(0),
-													  ack_count(0), analysed_bytes_sent(0), analysed_bytes_retransmitted(0),
-													  analysed_redundant_bytes(0), analysed_packet_count(0),
+													  ack_count(0), analysed_bytes_sent(0), analysed_bytes_sent_unique(0), analysed_bytes_retransmitted(0),
+													  analysed_redundant_bytes(0), analysed_packet_sent_count(0),
 													  analysed_retr_packet_count(0), analysed_rdb_packet_count(0), analysed_ack_count(0),
-													  analysed_packet_sent_count(0), analysed_packet_received_count(0),
+													  analysed_packet_sent_count_in_dump(0), analysed_packet_received_count(0),
 													  analysed_ranges_count(0), analysed_sent_pure_ack_count(0), analysed_data_packet_count(0),
 													  analysed_syn_count(0), analysed_fin_count(0), analysed_rst_count(0), analysed_pure_acks_count(0)
 	{
 
 	parse_cmd_args(argc, argv);
 
+//	cout.sync_with_stdio(false);
+	//setvbuf(stdout, NULL, _IOFBF, 20000);
+
 	if(GlobOpts::debugLevel < 0)
 		cerr << "debugLevel = " << GlobOpts::debugLevel << endl;
 
 	int rstCount;
 	int pureAcksCount;
 	uint64_t totUniqueBytes;
+	uint64_t totUniqueBytesSent;
 	uint64_t redundantBytes;
 	int rdb_packet_hits;
 	int rdb_packet_misses;
 	}
 };
 
+
+struct SentTime {
+	uint64_t time;
+	uint16_t size;
+	uint16_t itt;
+	SentTime(uint64_t t, uint16_t s) : time(t), size(s), itt(0) {}
+
+	bool operator < (const SentTime& other) const {
+        return (time < other.time);
+    }
+};
+
+
 /* Struct used to keep track of bytewise latency stats */
 struct byteStats {
 	int nrRanges;   /* Number of ranges in conn */
 	vector<double> latencies;
 	vector<double> payload_lengths;
 	vector<double> intertransmission_times;
-
+	vector<struct SentTime> sent_times;
 	vector<int> retrans;
 	vector<int> dupacks;
 	byteStats() : nrRanges(0), stdevLength(0) {
 }
 
 
-char* colored_sprintf(int fg_color, char *str, char *format, ...) {
+char* colored_sprintf(int fg_color, char *str, const char *format, ...) {
 	va_list ap;
 	va_start(ap, format);
 	vsprintf(str, format, ap);