First stab at timeout estimation

This commit is contained in:
Keith Winstein
2011-08-10 01:51:40 -04:00
parent 79e2898052
commit db2fa133cf
5 changed files with 86 additions and 32 deletions
+2 -2
View File
@@ -4,8 +4,8 @@ repos = templates.rpo
executables = parse termemu ntester encrypt decrypt executables = parse termemu ntester encrypt decrypt
CXX = g++ CXX = g++
CXXFLAGS = -g --std=c++0x -pedantic -Werror -Wall -Wextra -Weffc++ -fno-implicit-templates -fno-default-inline -pipe -D_FILE_OFFSET_BITS=64 -D_XOPEN_SOURCE=500 -D_GNU_SOURCE -D_BSD_SOURCE CXXFLAGS = -g -O2 --std=c++0x -pedantic -Werror -Wall -Wextra -Weffc++ -fno-implicit-templates -fno-default-inline -pipe -D_FILE_OFFSET_BITS=64 -D_XOPEN_SOURCE=500 -D_GNU_SOURCE -D_BSD_SOURCE
LIBS = -lutil -lssl -lrt LIBS = -lutil -lssl -lrt -lm
all: $(executables) all: $(executables)
+67 -5
View File
@@ -3,6 +3,7 @@
#include <netinet/in.h> #include <netinet/in.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <assert.h> #include <assert.h>
#include <endian.h>
#include "dos_assert.hpp" #include "dos_assert.hpp"
#include "network.hpp" #include "network.hpp"
@@ -16,6 +17,8 @@ using namespace Crypto;
Packet::Packet( string coded_packet, Session *session ) Packet::Packet( string coded_packet, Session *session )
: seq( -1 ), : seq( -1 ),
direction( TO_SERVER ), direction( TO_SERVER ),
timestamp( -1 ),
timestamp_reply( -1 ),
payload() payload()
{ {
Message message = session->decrypt( coded_packet ); Message message = session->decrypt( coded_packet );
@@ -23,7 +26,13 @@ Packet::Packet( string coded_packet, Session *session )
direction = (message.nonce.val() & 0x8000000000000000) ? TO_CLIENT : TO_SERVER; direction = (message.nonce.val() & 0x8000000000000000) ? TO_CLIENT : TO_SERVER;
seq = message.nonce.val() & 0x7FFFFFFFFFFFFFFF; seq = message.nonce.val() & 0x7FFFFFFFFFFFFFFF;
payload = message.text; assert( message.text.size() >= 2 * sizeof( uint64_t ) );
uint64_t *data = (uint64_t *)message.text.data();
timestamp = be64toh( data[ 0 ] );
timestamp_reply = be64toh( data[ 1 ] );
payload = string( message.text.begin() + 2 * sizeof( uint64_t ), message.text.end() );
} }
/* Output coded string from packet */ /* Output coded string from packet */
@@ -31,12 +40,20 @@ string Packet::tostring( Session *session )
{ {
uint64_t direction_seq = (uint64_t( direction == TO_CLIENT ) << 63) | (seq & 0x7FFFFFFFFFFFFFFF); uint64_t direction_seq = (uint64_t( direction == TO_CLIENT ) << 63) | (seq & 0x7FFFFFFFFFFFFFFF);
return session->encrypt( Message( Nonce( direction_seq ), payload ) ); uint64_t ts_net[ 2 ] = { htobe64( timestamp ), htobe64( timestamp_reply ) };
string timestamps = string( (char *)ts_net, 2 * sizeof( uint64_t ) );
return session->encrypt( Message( Nonce( direction_seq ), timestamps + payload ) );
} }
Packet Connection::new_packet( string &s_payload ) Packet Connection::new_packet( string &s_payload )
{ {
return Packet( next_seq++, direction, s_payload ); Packet p( next_seq++, direction, timestamp(), saved_timestamp, s_payload );
saved_timestamp = -1;
return p;
} }
void Connection::setup( void ) void Connection::setup( void )
@@ -74,7 +91,11 @@ Connection::Connection() /* server */
key(), key(),
session( key ), session( key ),
direction( TO_CLIENT ), direction( TO_CLIENT ),
next_seq( 0 ) next_seq( 0 ),
saved_timestamp( -1 ),
RTT_hit( false ),
SRTT( 1 ),
RTTVAR( .5 )
{ {
setup(); setup();
} }
@@ -88,7 +109,11 @@ Connection::Connection( const char *key_str, const char *ip, int port ) /* clien
key( key_str ), key( key_str ),
session( key ), session( key ),
direction( TO_SERVER ), direction( TO_SERVER ),
next_seq( 0 ) next_seq( 0 ),
saved_timestamp( -1 ),
RTT_hit( false ),
SRTT( 1 ),
RTTVAR( .5 )
{ {
setup(); setup();
@@ -170,6 +195,28 @@ string Connection::recv( void )
Packet p( string( buf, received_len ), &session ); Packet p( string( buf, received_len ), &session );
if ( p.timestamp != uint64_t(-1) ) {
saved_timestamp = p.timestamp;
}
if ( p.timestamp_reply != uint64_t(-1) ) {
uint64_t now = timestamp();
assert( now >= p.timestamp_reply );
const double R = now - p.timestamp_reply;
if ( !RTT_hit ) { /* first measurement */
SRTT = R;
RTTVAR = R / 2;
RTT_hit = true;
} else {
const double alpha = 1.0 / 8.0;
const double beta = 1.0 / 4.0;
RTTVAR = (1 - beta) * RTTVAR + ( beta * fabs( SRTT - R ) );
SRTT = (1 - alpha) * SRTT + ( alpha * R );
}
}
dos_assert( p.direction == (server ? TO_SERVER : TO_CLIENT) ); /* prevent malicious playback to sender */ dos_assert( p.direction == (server ? TO_SERVER : TO_CLIENT) ); /* prevent malicious playback to sender */
/* server auto-adjusts to client */ /* server auto-adjusts to client */
@@ -199,3 +246,18 @@ int Connection::port( void )
return ntohs( local_addr.sin_port ); return ntohs( local_addr.sin_port );
} }
uint64_t Network::timestamp( void )
{
struct timespec tp;
if ( clock_gettime( CLOCK_MONOTONIC, &tp ) < 0 ) {
throw NetworkException( "clock_gettime", errno );
}
uint64_t millis = tp.tv_nsec / 1000000;
millis += uint64_t( tp.tv_sec ) * 1000000;
return millis;
}
+16 -2
View File
@@ -6,6 +6,7 @@
#include <sys/socket.h> #include <sys/socket.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <string> #include <string>
#include <math.h>
#include "crypto.hpp" #include "crypto.hpp"
@@ -13,6 +14,8 @@ using namespace std;
using namespace Crypto; using namespace Crypto;
namespace Network { namespace Network {
uint64_t timestamp( void );
class MTUException { class MTUException {
public: public:
int MTU; int MTU;
@@ -35,10 +38,13 @@ namespace Network {
public: public:
uint64_t seq; uint64_t seq;
Direction direction; Direction direction;
uint64_t timestamp, timestamp_reply;
string payload; string payload;
Packet( uint64_t s_seq, Direction s_direction, string s_payload ) Packet( uint64_t s_seq, Direction s_direction,
: seq( s_seq ), direction( s_direction ), payload( s_payload ) uint64_t s_timestamp, uint64_t s_timestamp_reply, string s_payload )
: seq( s_seq ), direction( s_direction ),
timestamp( s_timestamp ), timestamp_reply( s_timestamp_reply ), payload( s_payload )
{} {}
Packet( string coded_packet, Session *session ); Packet( string coded_packet, Session *session );
@@ -67,6 +73,12 @@ namespace Network {
Direction direction; Direction direction;
uint64_t next_seq; uint64_t next_seq;
uint64_t saved_timestamp;
bool RTT_hit;
double SRTT;
double RTTVAR;
Packet new_packet( string &s_payload ); Packet new_packet( string &s_payload );
public: public:
@@ -81,6 +93,8 @@ namespace Network {
int port( void ); int port( void );
string get_key( void ) { return key.printable_key(); } string get_key( void ) { return key.printable_key(); }
bool get_attached( void ) { return attached; } bool get_attached( void ) { return attached; }
int timeout( void ) { return (int)lrint( ceil( SRTT + 4 * RTTVAR ) ); }
}; };
} }
+1 -18
View File
@@ -6,21 +6,6 @@
using namespace Network; using namespace Network;
using namespace std; using namespace std;
template <class MyState, class RemoteState>
uint64_t Transport<MyState, RemoteState>::timestamp( void )
{
struct timespec tp;
if ( clock_gettime( CLOCK_MONOTONIC, &tp ) < 0 ) {
throw NetworkException( "clock_gettime", errno );
}
uint64_t millis = tp.tv_nsec / 1000000;
millis += uint64_t( tp.tv_sec ) * 1000000;
return millis;
}
template <class MyState, class RemoteState> template <class MyState, class RemoteState>
Transport<MyState, RemoteState>::Transport( MyState &initial_state, RemoteState &initial_remote ) Transport<MyState, RemoteState>::Transport( MyState &initial_state, RemoteState &initial_remote )
: connection(), : connection(),
@@ -28,7 +13,6 @@ Transport<MyState, RemoteState>::Transport( MyState &initial_state, RemoteState
current_state( initial_state ), current_state( initial_state ),
sent_states( 1, TimestampedState<MyState>( timestamp(), 0, initial_state ) ), sent_states( 1, TimestampedState<MyState>( timestamp(), 0, initial_state ) ),
assumed_receiver_state( sent_states.begin() ), assumed_receiver_state( sent_states.begin() ),
timeout( INITIAL_TIMEOUT ),
received_states( 1, TimestampedState<RemoteState>( timestamp(), 0, initial_remote ) ) received_states( 1, TimestampedState<RemoteState>( timestamp(), 0, initial_remote ) )
{ {
/* server */ /* server */
@@ -42,7 +26,6 @@ Transport<MyState, RemoteState>::Transport( MyState &initial_state, RemoteState
current_state( initial_state ), current_state( initial_state ),
sent_states( 1, TimestampedState<MyState>( timestamp(), 0, initial_state ) ), sent_states( 1, TimestampedState<MyState>( timestamp(), 0, initial_state ) ),
assumed_receiver_state( sent_states.begin() ), assumed_receiver_state( sent_states.begin() ),
timeout( INITIAL_TIMEOUT ),
received_states( 1, TimestampedState<RemoteState>( timestamp(), 0, initial_remote ) ) received_states( 1, TimestampedState<RemoteState>( timestamp(), 0, initial_remote ) )
{ {
/* client */ /* client */
@@ -190,7 +173,7 @@ void Transport<MyState, RemoteState>::update_assumed_receiver_state( void )
i++ ) { i++ ) {
assert( now >= i->timestamp ); assert( now >= i->timestamp );
if ( now - i->timestamp < int64_t(timeout) ) { if ( int(now - i->timestamp) < connection.timeout() ) {
assumed_receiver_state = i; assumed_receiver_state = i;
} }
} }
-5
View File
@@ -48,7 +48,6 @@ namespace Network {
class Transport class Transport
{ {
private: private:
static const int INITIAL_TIMEOUT = 1000; /* ms, same as TCP */
static const int SEND_INTERVAL = 20; /* ms between frames */ static const int SEND_INTERVAL = 20; /* ms between frames */
static const int ACK_INTERVAL = 1000; /* ms between empty acks */ static const int ACK_INTERVAL = 1000; /* ms between empty acks */
static const int HEADER_LEN = 100; static const int HEADER_LEN = 100;
@@ -65,8 +64,6 @@ namespace Network {
Connection connection; Connection connection;
bool server; bool server;
uint64_t timestamp( void );
/* sender */ /* sender */
MyState current_state; MyState current_state;
@@ -77,8 +74,6 @@ namespace Network {
typename list< TimestampedState<MyState> >::iterator assumed_receiver_state; typename list< TimestampedState<MyState> >::iterator assumed_receiver_state;
int timeout;
/* simple receiver */ /* simple receiver */
list< TimestampedState<RemoteState> > received_states; list< TimestampedState<RemoteState> > received_states;