Only update timestamp and targeting on higher sequence number
This commit is contained in:
+40
-33
@@ -93,6 +93,7 @@ Connection::Connection() /* server */
|
|||||||
direction( TO_CLIENT ),
|
direction( TO_CLIENT ),
|
||||||
next_seq( 0 ),
|
next_seq( 0 ),
|
||||||
saved_timestamp( -1 ),
|
saved_timestamp( -1 ),
|
||||||
|
expected_receiver_seq( 0 ),
|
||||||
RTT_hit( false ),
|
RTT_hit( false ),
|
||||||
SRTT( 1000 ),
|
SRTT( 1000 ),
|
||||||
RTTVAR( 500 )
|
RTTVAR( 500 )
|
||||||
@@ -111,6 +112,7 @@ Connection::Connection( const char *key_str, const char *ip, int port ) /* clien
|
|||||||
direction( TO_SERVER ),
|
direction( TO_SERVER ),
|
||||||
next_seq( 0 ),
|
next_seq( 0 ),
|
||||||
saved_timestamp( -1 ),
|
saved_timestamp( -1 ),
|
||||||
|
expected_receiver_seq( 0 ),
|
||||||
RTT_hit( false ),
|
RTT_hit( false ),
|
||||||
SRTT( 1000 ),
|
SRTT( 1000 ),
|
||||||
RTTVAR( 500 )
|
RTTVAR( 500 )
|
||||||
@@ -213,46 +215,51 @@ string Connection::recv( void )
|
|||||||
|
|
||||||
Packet p( string( buf, received_len ), &session );
|
Packet p( string( buf, received_len ), &session );
|
||||||
|
|
||||||
if ( p.timestamp != uint64_t(-1) ) {
|
dos_assert( p.direction == (server ? TO_SERVER : TO_CLIENT) ); /* prevent malicious playback to sender */
|
||||||
saved_timestamp = p.timestamp;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( p.timestamp_reply != uint64_t(-1) ) {
|
if ( p.seq >= expected_receiver_seq ) { /* don't use out-of-order packets for timestamp or targeting */
|
||||||
uint64_t now = timestamp();
|
expected_receiver_seq = p.seq + 1; /* this is security-sensitive because a replay attack could otherwise
|
||||||
assert( now >= p.timestamp_reply );
|
screw up the timestamp and targeting */
|
||||||
double R = now - p.timestamp_reply;
|
|
||||||
|
|
||||||
if ( R < 5000 ) { /* ignore large values, e.g. server was Ctrl-Zed */
|
if ( p.timestamp != uint64_t(-1) ) {
|
||||||
if ( !RTT_hit ) { /* first measurement */
|
saved_timestamp = p.timestamp;
|
||||||
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 ) );
|
if ( p.timestamp_reply != uint64_t(-1) ) {
|
||||||
SRTT = (1 - alpha) * SRTT + ( alpha * R );
|
uint64_t now = timestamp();
|
||||||
|
assert( now >= p.timestamp_reply );
|
||||||
|
double R = now - p.timestamp_reply;
|
||||||
|
|
||||||
|
if ( R < 5000 ) { /* ignore large values, e.g. server was Ctrl-Zed */
|
||||||
|
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 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* server auto-adjusts to client */
|
||||||
|
if ( server ) {
|
||||||
|
attached = true;
|
||||||
|
|
||||||
|
if ( (remote_addr.sin_addr.s_addr != packet_remote_addr.sin_addr.s_addr)
|
||||||
|
|| (remote_addr.sin_port != packet_remote_addr.sin_port) ) {
|
||||||
|
remote_addr = packet_remote_addr;
|
||||||
|
fprintf( stderr, "Server now attached to client at %s:%d\n",
|
||||||
|
inet_ntoa( remote_addr.sin_addr ),
|
||||||
|
ntohs( remote_addr.sin_port ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dos_assert( p.direction == (server ? TO_SERVER : TO_CLIENT) ); /* prevent malicious playback to sender */
|
return p.payload; /* we do return out-of-order or duplicated packets to caller */
|
||||||
|
|
||||||
/* server auto-adjusts to client */
|
|
||||||
if ( server ) {
|
|
||||||
attached = true;
|
|
||||||
|
|
||||||
if ( (remote_addr.sin_addr.s_addr != packet_remote_addr.sin_addr.s_addr)
|
|
||||||
|| (remote_addr.sin_port != packet_remote_addr.sin_port) ) {
|
|
||||||
remote_addr = packet_remote_addr;
|
|
||||||
fprintf( stderr, "Server now attached to client at %s:%d\n",
|
|
||||||
inet_ntoa( remote_addr.sin_addr ),
|
|
||||||
ntohs( remote_addr.sin_port ) );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return p.payload;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int Connection::port( void )
|
int Connection::port( void )
|
||||||
|
|||||||
@@ -74,6 +74,7 @@ namespace Network {
|
|||||||
Direction direction;
|
Direction direction;
|
||||||
uint64_t next_seq;
|
uint64_t next_seq;
|
||||||
uint64_t saved_timestamp;
|
uint64_t saved_timestamp;
|
||||||
|
uint64_t expected_receiver_seq;
|
||||||
|
|
||||||
bool RTT_hit;
|
bool RTT_hit;
|
||||||
double SRTT;
|
double SRTT;
|
||||||
|
|||||||
@@ -196,7 +196,7 @@ void Transport<MyState, RemoteState>::recv( void )
|
|||||||
|
|
||||||
if ( !found ) {
|
if ( !found ) {
|
||||||
// fprintf( stderr, "Ignoring out-of-order packet. Reference state %d has been discarded or hasn't yet been received.\n", int(inst.old_num) );
|
// fprintf( stderr, "Ignoring out-of-order packet. Reference state %d has been discarded or hasn't yet been received.\n", int(inst.old_num) );
|
||||||
return;
|
return; /* this is security-sensitive and part of how we enforce idempotency */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* apply diff to reference state */
|
/* apply diff to reference state */
|
||||||
|
|||||||
Reference in New Issue
Block a user