Commit 9f6d8874 authored by Robert Ricci's avatar Robert Ricci

Add a througput sensor that uses the TCP timestamps sent by the other

side to determine inter-packet arrival time at the receiver. This
should get us a more accurate throughput measurement. Eyeballing it,
it seems to return reasonable numbers, but it needs more testing.
parent 7dedfd3b
// TSThroughputSensor.cc
#include "lib.h"
#include "TSThroughputSensor.h"
#include "PacketSensor.h"
#include "StateSensor.h"
using namespace std;
TSThroughputSensor::TSThroughputSensor(PacketSensor const * newPacketHistory,
StateSensor const * newState)
: lastAckTS(0), packetHistory(newPacketHistory), state(newState)
{
}
int TSThroughputSensor::getThroughputInKbps(void) const
{
if (ackValid)
{
return throughputInKbps;
}
else
{
logWrite(ERROR,
"ThroughputSensor::getThroughputInKbps() "
"called with invalid data");
return 0;
}
}
void TSThroughputSensor::localSend(PacketInfo *)
{
ackValid = false;
sendValid = true;
}
void TSThroughputSensor::localAck(PacketInfo * packet)
{
sendValid = false;
if (state->isAckValid() && packetHistory->isAckValid() &&
state->getState() == StateSensor::ESTABLISHED)
{
/*
* Find the time the other end of this connection says it sent this
* ACK
*/
uint32_t currentAckTS = 0;
list<Option>::iterator opt;
for (opt = packet->tcpOptions->begin();
opt != packet->tcpOptions->end();
++opt) {
if (opt->type == TCPOPT_TIMESTAMP) {
const uint32_t *stamps = reinterpret_cast<const uint32_t*>(opt->buffer);
/*
* stamps[0] is TSval (the sending node's timestamp)
* stamps[1] is TSecr (the timestamp the sending node is echoing)
*/
currentAckTS = htonl(stamps[0]);
}
}
/*
* It would be nice if we could fall back to regular timing instead of
* bailing, maybe that's a feature for someday...
*/
if (currentAckTS == 0) {
logWrite(ERROR,"TSThroughputSensor::localAck() got a packet without a "
"timestamp");
ackValid = false;
throughputInKbps = 0;
lastAckTS = 0;
return;
}
if (lastAckTS != 0 && currentAckTS < lastAckTS) {
logWrite(ERROR,"TSThroughputSensor::localAck() got timestamps in reverse "
"order: o=%u,n=%u",lastAckTS,currentAckTS);
ackValid = false;
throughputInKbps = 0;
lastAckTS = 0;
return;
}
if (lastAckTS != 0)
{
ackValid = true;
/*
* period is in arbitrary units decided on by the other end - we assume
* they are in milliseconds XXX: Verify this
*/
int period = currentAckTS - lastAckTS;
double kilobits = packetHistory->getAckedSize() * (8.0/1000.0);
int latest = static_cast<int>(kilobits/(period / 1000.0));
throughputInKbps = latest;
maxThroughput = latest;
logWrite(SENSOR, "TSTHROUGHPUT: %d kbps (period=%i,kbits=%f)",
latest,period,kilobits);
}
else
{
throughputInKbps = 0;
ackValid = false;
}
lastAckTS = currentAckTS;
}
else
{
throughputInKbps = 0;
lastAckTS = 0;
ackValid = false;
}
}
/*
* TSThroughputSensor.h
* NOTE: This file is very similar to ThroughputSensor.h - however, it uses
* TCP timestamps, instead of packet times stamped by the kernel, for its
* inter-packet timing mechanism
* Technically, what we're doing here isn't legal - ie. the only thing you're
* supposed to use TSVal for is to echo it back to the other side with your
* ACKs. There are no universal units for TSVal, so we are relying on the other
* side of the connections using the same units for timestamps
*/
#ifndef TSTHROUGHPUT_SENSOR_H_STUB_2
#define TSTHROUGHPUT_SENSOR_H_STUB_2
#include "Sensor.h"
#include "ThroughputSensor.h"
class PacketSensor;
class StateSensor;
class TSThroughputSensor : public Sensor
{
public:
TSThroughputSensor(PacketSensor const * newPacketHistory,
StateSensor const * newState);
int getThroughputInKbps(void) const;
protected:
virtual void localSend(PacketInfo * packet);
virtual void localAck(PacketInfo * packet);
private:
int throughputInKbps;
int maxThroughput;
uint32_t lastAckTS;
PacketSensor const * packetHistory;
StateSensor const * state;
};
#endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment