@@ -93,19 +93,18 @@ STAT_STRUCT(Endpoint, ENDPOINT)
9393TokenBucket::TokenBucket (double rate, double burst)
9494 : rate(rate), burst(burst), tokens(burst), last_ts(uv_hrtime()) {}
9595
96- void TokenBucket::InitOnce (double r, double b) {
96+ void TokenBucket::InitOnce (double r, double b, uint64_t now ) {
9797if (last_ts == 0 ) {
9898 rate = r;
9999 burst = b;
100100 tokens = b;
101- last_ts = uv_hrtime () ;
101+ last_ts = now ;
102102 }
103103}
104104
105105// Try to consume one token. Refills based on elapsed time, then
106106// attempts to consume. Returns true if the request is allowed.
107- bool TokenBucket::consume () {
108- uint64_t now = uv_hrtime ();
107+ bool TokenBucket::consume (uint64_t now) {
109108double elapsed = static_cast <double >(now - last_ts) / 1e9 ; // seconds
110109 last_ts = now;
111110 tokens = std::min (burst, tokens + elapsed * rate);
@@ -1026,9 +1025,9 @@ void Endpoint::SendBatch(Packet::Ptr* packets, size_t count) {
10261025 }
10271026}
10281027
1029- void Endpoint::SendRetry (const PathDescriptor& options) {
1028+ void Endpoint::SendRetry (const PathDescriptor& options, uint64_t now ) {
10301029Debug (this , " Sending retry on path %s" , options);
1031- if (!retry_bucket_.consume ()) {
1030+ if (!retry_bucket_.consume (now )) {
10321031Debug (this , " Retry rate limit exceeded (global)" );
10331032STAT_INCREMENT (Stats, retry_rate_limited);
10341033return ;
@@ -1042,9 +1041,10 @@ void Endpoint::SendRetry(const PathDescriptor& options) {
10421041 }
10431042}
10441043
1045- void Endpoint::SendVersionNegotiation (const PathDescriptor& options) {
1044+ void Endpoint::SendVersionNegotiation (const PathDescriptor& options,
1045+ uint64_t now) {
10461046Debug (this , " Sending version negotiation on path %s" , options);
1047- if (!version_negotiation_bucket_.consume ()) {
1047+ if (!version_negotiation_bucket_.consume (now )) {
10481048Debug (this , " Version negotiation rate limit exceeded (global)" );
10491049STAT_INCREMENT (Stats, version_negotiation_rate_limited);
10501050return ;
@@ -1058,7 +1058,8 @@ void Endpoint::SendVersionNegotiation(const PathDescriptor& options) {
10581058}
10591059
10601060bool Endpoint::SendStatelessReset (const PathDescriptor& options,
1061- size_t source_len) {
1061+ size_t source_len,
1062+ uint64_t now) {
10621063if (options_.disable_stateless_reset ) [[unlikely]] {
10631064return false ;
10641065 }
@@ -1067,7 +1068,7 @@ bool Endpoint::SendStatelessReset(const PathDescriptor& options,
10671068 options,
10681069 source_len);
10691070
1070- if (!stateless_reset_bucket_.consume ()) {
1071+ if (!stateless_reset_bucket_.consume (now )) {
10711072Debug (this , " Stateless reset rate limit exceeded (global)" );
10721073STAT_INCREMENT (Stats, stateless_reset_rate_limited);
10731074return false ;
@@ -1087,12 +1088,13 @@ bool Endpoint::SendStatelessReset(const PathDescriptor& options,
10871088}
10881089
10891090void Endpoint::SendImmediateConnectionClose (const PathDescriptor& options,
1090- QuicError reason) {
1091+ QuicError reason,
1092+ uint64_t now) {
10911093Debug (this ,
10921094" Sending immediate connection close on path %s with reason %s" ,
10931095 options,
10941096 reason);
1095- if (!immediate_close_bucket_.consume ()) {
1097+ if (!immediate_close_bucket_.consume (now )) {
10961098Debug (this , " Immediate connection close rate limit exceeded (global)" );
10971099STAT_INCREMENT (Stats, immediate_close_rate_limited);
10981100return ;
@@ -1314,6 +1316,8 @@ void Endpoint::CloseGracefully() {
13141316void Endpoint::Receive (const uint8_t * data,
13151317size_t len,
13161318const SocketAddress& remote_address) {
1319+ const uint64_t now = uv_hrtime ();
1320+
13171321const auto receive = [&](Session* session,
13181322const uint8_t * pkt_data,
13191323size_t pkt_len,
@@ -1328,7 +1332,12 @@ void Endpoint::Receive(const uint8_t* data,
13281332// are generated. The deferred flush via BindingData's uv_check
13291333// callback calls SendPendingData once per dirty session after all
13301334// packets in the burst have been read.
1331- if (session->ReadPacket (pkt_data, pkt_len, local_address, remote_address)) {
1335+ if (session->ReadPacket (pkt_data,
1336+ pkt_len,
1337+ local_address,
1338+ remote_address,
1339+ PacketInfo (),
1340+ now)) {
13321341STAT_INCREMENT_N (Stats, bytes_received, pkt_len);
13331342STAT_INCREMENT (Stats, packets_received);
13341343 }
@@ -1350,10 +1359,10 @@ void Endpoint::Receive(const uint8_t* data,
13501359
13511360// Per-host session creation rate limit. The bucket is initialized
13521361// on first access with the configured rate/burst from options.
1353- auto info = addr_validation_lru_.Upsert (config.remote_address );
1354- info->session_creation_bucket .InitOnce (options_. session_creation_rate ,
1355- options_.session_creation_burst );
1356- if (!info->session_creation_bucket .consume ()) {
1362+ auto info = addr_validation_lru_.Upsert (config.remote_address , now );
1363+ info->session_creation_bucket .InitOnce (
1364+ options_. session_creation_rate , options_.session_creation_burst , now );
1365+ if (!info->session_creation_bucket .consume (now )) {
13571366Debug (this ,
13581367" Session creation rate limit exceeded for %s" ,
13591368 config.remote_address );
@@ -1452,7 +1461,8 @@ void Endpoint::Receive(const uint8_t* data,
14521461if (state_->busy ) STAT_INCREMENT (Stats, server_busy_count);
14531462SendImmediateConnectionClose (
14541463 PathDescriptor{version, dcid, scid, local_address, remote_address},
1455- QuicError::ForTransport (NGTCP2_CONNECTION_REFUSED ));
1464+ QuicError::ForTransport (NGTCP2_CONNECTION_REFUSED ),
1465+ now);
14561466// The packet was successfully processed, even if we did refuse the
14571467// connection.
14581468STAT_INCREMENT (Stats, packets_received);
@@ -1526,7 +1536,8 @@ void Endpoint::Receive(const uint8_t* data,
15261536Debug (this , " Retry token from %s is invalid." , remote_address);
15271537SendImmediateConnectionClose (
15281538 PathDescriptor{version, scid, dcid, local_address, remote_address},
1529- QuicError::ForTransport (NGTCP2_CONNECTION_REFUSED ));
1539+ QuicError::ForTransport (NGTCP2_CONNECTION_REFUSED ),
1540+ now);
15301541STAT_INCREMENT (Stats, packets_received);
15311542return ;
15321543 }
@@ -1542,7 +1553,7 @@ void Endpoint::Receive(const uint8_t* data,
15421553// Mark the address as validated since the retry round-trip proves
15431554// reachability.
15441555Debug (this , " Remote address %s is validated" , remote_address);
1545- addr_validation_lru_.Upsert (remote_address)->validated = true ;
1556+ addr_validation_lru_.Upsert (remote_address, now )->validated = true ;
15461557 }
15471558
15481559// Step 2: Address validation — decide whether to send a Retry or
@@ -1558,13 +1569,15 @@ void Endpoint::Receive(const uint8_t* data,
15581569" Initial packet has no token. Sending retry to %s to start "
15591570" validation" ,
15601571 remote_address);
1561- SendRetry (PathDescriptor{
1562- version,
1563- dcid,
1564- scid,
1565- local_address,
1566- remote_address,
1567- });
1572+ SendRetry (
1573+ PathDescriptor{
1574+ version,
1575+ dcid,
1576+ scid,
1577+ local_address,
1578+ remote_address,
1579+ },
1580+ now);
15681581STAT_INCREMENT (Stats, packets_received);
15691582return ;
15701583 }
@@ -1585,13 +1598,15 @@ void Endpoint::Receive(const uint8_t* data,
15851598Debug (this ,
15861599" Regular token from %s is invalid." ,
15871600 remote_address);
1588- SendRetry (PathDescriptor{
1589- version,
1590- dcid,
1591- scid,
1592- local_address,
1593- remote_address,
1594- });
1601+ SendRetry (
1602+ PathDescriptor{
1603+ version,
1604+ dcid,
1605+ scid,
1606+ local_address,
1607+ remote_address,
1608+ },
1609+ now);
15951610STAT_INCREMENT (Stats, packets_received);
15961611return ;
15971612 }
@@ -1603,20 +1618,22 @@ void Endpoint::Receive(const uint8_t* data,
16031618Debug (this ,
16041619" Initial packet from %s has unknown token type" ,
16051620 remote_address);
1606- SendRetry (PathDescriptor{
1607- version,
1608- dcid,
1609- scid,
1610- local_address,
1611- remote_address,
1612- });
1621+ SendRetry (
1622+ PathDescriptor{
1623+ version,
1624+ dcid,
1625+ scid,
1626+ local_address,
1627+ remote_address,
1628+ },
1629+ now);
16131630STAT_INCREMENT (Stats, packets_received);
16141631return ;
16151632 }
16161633 }
16171634
16181635Debug (this , " Remote address %s is validated" , remote_address);
1619- addr_validation_lru_.Upsert (remote_address)->validated = true ;
1636+ addr_validation_lru_.Upsert (remote_address, now )->validated = true ;
16201637 } else if (hd.tokenlen > 0 ) {
16211638Debug (this ,
16221639" Ignoring initial packet from %s with unexpected token" ,
@@ -1628,13 +1645,15 @@ void Endpoint::Receive(const uint8_t* data,
16281645if (options_.validate_address ) {
16291646Debug (
16301647this , " Sending retry to %s due to 0RTT packet" , remote_address);
1631- SendRetry (PathDescriptor{
1632- version,
1633- dcid,
1634- scid,
1635- local_address,
1636- remote_address,
1637- });
1648+ SendRetry (
1649+ PathDescriptor{
1650+ version,
1651+ dcid,
1652+ scid,
1653+ local_address,
1654+ remote_address,
1655+ },
1656+ now);
16381657STAT_INCREMENT (Stats, packets_received);
16391658return ;
16401659 }
@@ -1743,8 +1762,12 @@ void Endpoint::Receive(const uint8_t* data,
17431762 pversion_cid.version );
17441763CID dcid (pversion_cid.dcid , pversion_cid.dcidlen );
17451764CID scid (pversion_cid.scid , pversion_cid.scidlen );
1746- SendVersionNegotiation (PathDescriptor{
1747- pversion_cid.version , dcid, scid, local_address (), remote_address});
1765+ SendVersionNegotiation (PathDescriptor{pversion_cid.version ,
1766+ dcid,
1767+ scid,
1768+ local_address (),
1769+ remote_address},
1770+ now);
17481771STAT_INCREMENT (Stats, packets_received);
17491772return ;
17501773 }
@@ -1823,7 +1846,8 @@ void Endpoint::Receive(const uint8_t* data,
18231846SendStatelessReset (
18241847 PathDescriptor{
18251848 pversion_cid.version , dcid, scid, addr, remote_address},
1826- len);
1849+ len,
1850+ now);
18271851return ;
18281852 }
18291853
@@ -1885,13 +1909,14 @@ void Endpoint::MemoryInfo(MemoryTracker* tracker) const {
18851909// Endpoint::SocketAddressInfoTraits
18861910
18871911bool Endpoint::SocketAddressInfoTraits::CheckExpired (
1888- const SocketAddress& address, const Type& type) {
1889- return (uv_hrtime () - type.timestamp ) > kSocketAddressInfoTimeout ;
1912+ const SocketAddress& address, const Type& type, uint64_t now ) {
1913+ return (now - type.timestamp ) > kSocketAddressInfoTimeout ;
18901914}
18911915
18921916void Endpoint::SocketAddressInfoTraits::Touch (const SocketAddress& address,
1893- Type* type) {
1894- type->timestamp = uv_hrtime ();
1917+ Type* type,
1918+ uint64_t now) {
1919+ type->timestamp = now;
18951920}
18961921
18971922// ======================================================================================
0 commit comments