+18
-1
@@ -203,6 +203,20 @@ const std::vector< int > Connection::fds( void ) const
|
||||
return ret;
|
||||
}
|
||||
|
||||
void Connection::set_MTU( int family )
|
||||
{
|
||||
switch ( family ) {
|
||||
case AF_INET:
|
||||
MTU = DEFAULT_IPV4_MTU - IPV4_HEADER_LEN;
|
||||
break;
|
||||
case AF_INET6:
|
||||
MTU = DEFAULT_IPV6_MTU - IPV6_HEADER_LEN;
|
||||
break;
|
||||
default:
|
||||
throw NetworkException( "Unknown address family", 0 );
|
||||
}
|
||||
}
|
||||
|
||||
class AddrInfo {
|
||||
public:
|
||||
struct addrinfo *res;
|
||||
@@ -319,6 +333,7 @@ bool Connection::try_bind( const char *addr, int port_low, int port_high )
|
||||
}
|
||||
|
||||
if ( bind( sock(), &local_addr.sa, local_addr_len ) == 0 ) {
|
||||
set_MTU( local_addr.sa.sa_family );
|
||||
return true;
|
||||
} else if ( i == search_high ) { /* last port to search */
|
||||
int saved_errno = errno;
|
||||
@@ -379,6 +394,8 @@ Connection::Connection( const char *key_str, const char *ip, const char *port )
|
||||
has_remote_addr = true;
|
||||
|
||||
socks.push_back( Socket( remote_addr.sa.sa_family ) );
|
||||
|
||||
set_MTU( remote_addr.sa.sa_family );
|
||||
}
|
||||
|
||||
void Connection::send( string s )
|
||||
@@ -404,7 +421,7 @@ void Connection::send( string s )
|
||||
send_exception = NetworkException( "sendto", errno );
|
||||
|
||||
if ( errno == EMSGSIZE ) {
|
||||
MTU = 500; /* payload MTU of last resort */
|
||||
MTU = DEFAULT_SEND_MTU; /* payload MTU of last resort */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+33
-2
@@ -101,7 +101,33 @@ namespace Network {
|
||||
|
||||
class Connection {
|
||||
private:
|
||||
static const int DEFAULT_SEND_MTU = 1300;
|
||||
/*
|
||||
* For IPv4, guess the typical (minimum) header length;
|
||||
* fragmentation is not dangerous, just inefficient.
|
||||
*/
|
||||
static const int IPV4_HEADER_LEN = 20 /* base IP header */
|
||||
+ 8 /* UDP */;
|
||||
/*
|
||||
* For IPv6, we don't want to ever have MTU issues, so make a
|
||||
* conservative guess about header size.
|
||||
*/
|
||||
static const int IPV6_HEADER_LEN = 40 /* base IPv6 header */
|
||||
+ 16 /* 2 minimum-sized extension headers */
|
||||
+ 8 /* UDP */;
|
||||
/* Application datagram MTU. For constructors and fallback. */
|
||||
static const int DEFAULT_SEND_MTU = 500;
|
||||
/*
|
||||
* IPv4 MTU. Don't use full Ethernet-derived MTU,
|
||||
* mobile networks have high tunneling overhead.
|
||||
*
|
||||
* About 95% of IPv4 TCP MSS I see are >= 1360.
|
||||
* An IP MTU is 20 bytes larger.
|
||||
* We let smaller MTUs fragment.
|
||||
*/
|
||||
static const int DEFAULT_IPV4_MTU = 1380;
|
||||
/* IPv6 MTU. Use the guaranteed minimum to avoid fragmentation. */
|
||||
static const int DEFAULT_IPV6_MTU = 1280;
|
||||
|
||||
static const uint64_t MIN_RTO = 50; /* ms */
|
||||
static const uint64_t MAX_RTO = 1000; /* ms */
|
||||
|
||||
@@ -139,7 +165,7 @@ namespace Network {
|
||||
|
||||
bool server;
|
||||
|
||||
int MTU;
|
||||
int MTU; /* application datagram MTU */
|
||||
|
||||
Base64Key key;
|
||||
Session session;
|
||||
@@ -175,7 +201,12 @@ namespace Network {
|
||||
|
||||
string recv_one( int sock_to_recv, bool nonblocking );
|
||||
|
||||
void set_MTU( int family );
|
||||
|
||||
public:
|
||||
/* Network transport overhead. */
|
||||
static const int ADDED_BYTES = 8 /* seqno/nonce */ + 4 /* timestamps */;
|
||||
|
||||
Connection( const char *desired_ip, const char *desired_port ); /* server */
|
||||
Connection( const char *key_str, const char *ip, const char *port ); /* client */
|
||||
|
||||
|
||||
@@ -154,8 +154,9 @@ bool Fragment::operator==( const Fragment &x ) const
|
||||
&& ( initialized == x.initialized ) && ( contents == x.contents );
|
||||
}
|
||||
|
||||
vector<Fragment> Fragmenter::make_fragments( const Instruction &inst, int MTU )
|
||||
vector<Fragment> Fragmenter::make_fragments( const Instruction &inst, size_t MTU )
|
||||
{
|
||||
MTU -= Fragment::frag_header_len;
|
||||
if ( (inst.old_num() != last_instruction.old_num())
|
||||
|| (inst.new_num() != last_instruction.new_num())
|
||||
|| (inst.ack_num() != last_instruction.ack_num())
|
||||
@@ -182,9 +183,9 @@ vector<Fragment> Fragmenter::make_fragments( const Instruction &inst, int MTU )
|
||||
string this_fragment;
|
||||
bool final = false;
|
||||
|
||||
if ( int( payload.size() + HEADER_LEN ) > MTU ) {
|
||||
this_fragment = string( payload.begin(), payload.begin() + MTU - HEADER_LEN );
|
||||
payload = string( payload.begin() + MTU - HEADER_LEN, payload.end() );
|
||||
if ( payload.size() > MTU ) {
|
||||
this_fragment = string( payload.begin(), payload.begin() + MTU );
|
||||
payload = string( payload.begin() + MTU, payload.end() );
|
||||
} else {
|
||||
this_fragment = payload;
|
||||
payload.clear();
|
||||
|
||||
@@ -44,14 +44,11 @@ using std::string;
|
||||
using namespace TransportBuffers;
|
||||
|
||||
namespace Network {
|
||||
static const int HEADER_LEN = 66;
|
||||
|
||||
class Fragment
|
||||
{
|
||||
private:
|
||||
public:
|
||||
static const size_t frag_header_len = sizeof( uint64_t ) + sizeof( uint16_t );
|
||||
|
||||
public:
|
||||
uint64_t id;
|
||||
uint16_t fragment_num;
|
||||
bool final;
|
||||
@@ -94,7 +91,7 @@ namespace Network {
|
||||
private:
|
||||
uint64_t next_instruction_id;
|
||||
Instruction last_instruction;
|
||||
int last_MTU;
|
||||
size_t last_MTU;
|
||||
|
||||
public:
|
||||
Fragmenter() : next_instruction_id( 0 ), last_instruction(), last_MTU( -1 )
|
||||
@@ -102,7 +99,7 @@ namespace Network {
|
||||
last_instruction.set_old_num( -1 );
|
||||
last_instruction.set_new_num( -1 );
|
||||
}
|
||||
vector<Fragment> make_fragments( const Instruction &inst, int MTU );
|
||||
vector<Fragment> make_fragments( const Instruction &inst, size_t MTU );
|
||||
uint64_t last_ack_sent( void ) const { return last_instruction.ack_num(); }
|
||||
};
|
||||
|
||||
|
||||
@@ -320,8 +320,9 @@ void TransportSender<MyState>::send_in_fragments( string diff, uint64_t new_num
|
||||
shutdown_tries++;
|
||||
}
|
||||
|
||||
vector<Fragment> fragments = fragmenter.make_fragments( inst, connection->get_MTU() );
|
||||
|
||||
vector<Fragment> fragments = fragmenter.make_fragments( inst, connection->get_MTU()
|
||||
- Network::Connection::ADDED_BYTES
|
||||
- Crypto::Session::ADDED_BYTES );
|
||||
for ( vector<Fragment>::iterator i = fragments.begin();
|
||||
i != fragments.end();
|
||||
i++ ) {
|
||||
|
||||
Reference in New Issue
Block a user