First stab at timeout estimation
This commit is contained in:
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user