From db2fa133cf21f38aaee813f4f6b45ed5e142b9a1 Mon Sep 17 00:00:00 2001 From: Keith Winstein Date: Wed, 10 Aug 2011 01:51:40 -0400 Subject: [PATCH] First stab at timeout estimation --- Makefile | 4 +-- network.cpp | 72 +++++++++++++++++++++++++++++++++++++++++--- network.hpp | 18 +++++++++-- networktransport.cpp | 19 +----------- networktransport.hpp | 5 --- 5 files changed, 86 insertions(+), 32 deletions(-) diff --git a/Makefile b/Makefile index 6d745f0..765d83e 100644 --- a/Makefile +++ b/Makefile @@ -4,8 +4,8 @@ repos = templates.rpo executables = parse termemu ntester encrypt decrypt 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 -LIBS = -lutil -lssl -lrt +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 -lm all: $(executables) diff --git a/network.cpp b/network.cpp index 9cee3de..ac9e5cf 100644 --- a/network.cpp +++ b/network.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include "dos_assert.hpp" #include "network.hpp" @@ -16,6 +17,8 @@ using namespace Crypto; Packet::Packet( string coded_packet, Session *session ) : seq( -1 ), direction( TO_SERVER ), + timestamp( -1 ), + timestamp_reply( -1 ), payload() { 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; 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 */ @@ -31,12 +40,20 @@ string Packet::tostring( Session *session ) { 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 ) { - 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 ) @@ -74,7 +91,11 @@ Connection::Connection() /* server */ key(), session( key ), direction( TO_CLIENT ), - next_seq( 0 ) + next_seq( 0 ), + saved_timestamp( -1 ), + RTT_hit( false ), + SRTT( 1 ), + RTTVAR( .5 ) { setup(); } @@ -88,7 +109,11 @@ Connection::Connection( const char *key_str, const char *ip, int port ) /* clien key( key_str ), session( key ), direction( TO_SERVER ), - next_seq( 0 ) + next_seq( 0 ), + saved_timestamp( -1 ), + RTT_hit( false ), + SRTT( 1 ), + RTTVAR( .5 ) { setup(); @@ -170,6 +195,28 @@ string Connection::recv( void ) 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 */ /* server auto-adjusts to client */ @@ -199,3 +246,18 @@ int Connection::port( void ) 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; +} + diff --git a/network.hpp b/network.hpp index 1a1d873..f59c600 100644 --- a/network.hpp +++ b/network.hpp @@ -6,6 +6,7 @@ #include #include #include +#include #include "crypto.hpp" @@ -13,6 +14,8 @@ using namespace std; using namespace Crypto; namespace Network { + uint64_t timestamp( void ); + class MTUException { public: int MTU; @@ -35,10 +38,13 @@ namespace Network { public: uint64_t seq; Direction direction; + uint64_t timestamp, timestamp_reply; string payload; - Packet( uint64_t s_seq, Direction s_direction, string s_payload ) - : seq( s_seq ), direction( s_direction ), payload( s_payload ) + Packet( uint64_t s_seq, Direction s_direction, + 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 ); @@ -67,6 +73,12 @@ namespace Network { Direction direction; uint64_t next_seq; + uint64_t saved_timestamp; + + bool RTT_hit; + double SRTT; + double RTTVAR; + Packet new_packet( string &s_payload ); public: @@ -81,6 +93,8 @@ namespace Network { int port( void ); string get_key( void ) { return key.printable_key(); } bool get_attached( void ) { return attached; } + + int timeout( void ) { return (int)lrint( ceil( SRTT + 4 * RTTVAR ) ); } }; } diff --git a/networktransport.cpp b/networktransport.cpp index 12315f7..37b6bec 100644 --- a/networktransport.cpp +++ b/networktransport.cpp @@ -6,21 +6,6 @@ using namespace Network; using namespace std; -template -uint64_t Transport::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 Transport::Transport( MyState &initial_state, RemoteState &initial_remote ) : connection(), @@ -28,7 +13,6 @@ Transport::Transport( MyState &initial_state, RemoteState current_state( initial_state ), sent_states( 1, TimestampedState( timestamp(), 0, initial_state ) ), assumed_receiver_state( sent_states.begin() ), - timeout( INITIAL_TIMEOUT ), received_states( 1, TimestampedState( timestamp(), 0, initial_remote ) ) { /* server */ @@ -42,7 +26,6 @@ Transport::Transport( MyState &initial_state, RemoteState current_state( initial_state ), sent_states( 1, TimestampedState( timestamp(), 0, initial_state ) ), assumed_receiver_state( sent_states.begin() ), - timeout( INITIAL_TIMEOUT ), received_states( 1, TimestampedState( timestamp(), 0, initial_remote ) ) { /* client */ @@ -190,7 +173,7 @@ void Transport::update_assumed_receiver_state( void ) i++ ) { assert( now >= i->timestamp ); - if ( now - i->timestamp < int64_t(timeout) ) { + if ( int(now - i->timestamp) < connection.timeout() ) { assumed_receiver_state = i; } } diff --git a/networktransport.hpp b/networktransport.hpp index 464999e..fc34736 100644 --- a/networktransport.hpp +++ b/networktransport.hpp @@ -48,7 +48,6 @@ namespace Network { class Transport { private: - static const int INITIAL_TIMEOUT = 1000; /* ms, same as TCP */ static const int SEND_INTERVAL = 20; /* ms between frames */ static const int ACK_INTERVAL = 1000; /* ms between empty acks */ static const int HEADER_LEN = 100; @@ -65,8 +64,6 @@ namespace Network { Connection connection; bool server; - uint64_t timestamp( void ); - /* sender */ MyState current_state; @@ -77,8 +74,6 @@ namespace Network { typename list< TimestampedState >::iterator assumed_receiver_state; - int timeout; - /* simple receiver */ list< TimestampedState > received_states;