packages feed

gbnet-hs 0.2.5.0 → 0.2.6.0

raw patch · 7 files changed

+154/−7 lines, 7 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

+ GBNet.Connection: resetTransportMetrics :: MonoTime -> Connection -> Connection
+ GBNet.Reliability: resetReliabilityMetrics :: ReliableEndpoint -> ReliableEndpoint

Files

CHANGELOG.md view
@@ -1,5 +1,17 @@ # Changelog +## 0.2.6.0++### Bug Fixes++- **Reset transport metrics on connection migration**: When a peer migrates to a new address, stale RTT/congestion state from the old network path was carried over. `handleMigration` now calls `resetTransportMetrics` which clears RTT estimation, congestion controller, bandwidth trackers, and network stats while preserving sequence numbers and channel state for packet continuity.+- **Full reliability reset on disconnect-recycle**: `resetConnection` now also resets the `ReliableEndpoint` to prevent stale reliability state from leaking across connection lifecycles.++### API++- `GBNet.Reliability`: new `resetReliabilityMetrics` — resets RTT/loss window while preserving sequence numbers and buffers.+- `GBNet.Connection`: new `resetTransportMetrics` — resets congestion, bandwidth, stats, and reliability metrics for a new network path.+ ## 0.2.5.0  ### Bug Fixes
gbnet-hs.cabal view
@@ -1,6 +1,6 @@ cabal-version:      3.0 name:               gbnet-hs-version:            0.2.5.0+version:            0.2.6.0 synopsis:           Transport-level networking library with zero-copy Storable serialization description:   A transport-level networking library providing reliable UDP with
src/GBNet/Connection.hs view
@@ -66,6 +66,7 @@      -- * Reset     resetConnection,+    resetTransportMetrics,      -- * Channel info     channelCount,@@ -111,7 +112,7 @@   ) import GBNet.Crypto (EncryptionKey, NonceCounter (..)) import GBNet.Packet (PacketHeader (..), PacketType (..))-import GBNet.Reliability (MonoTime, ReliableEndpoint, elapsedMs)+import GBNet.Reliability (MonoTime, ReliableEndpoint, elapsedMs, resetReliabilityMetrics) import qualified GBNet.Reliability as Rel import GBNet.Stats   ( CongestionLevel (..),@@ -678,7 +679,7 @@             .~ cwnd  -- | Retransmit unacked reliable messages that have exceeded the RTO.--- Iterates all channels, calls 'getRetransmitMessages' to find expired+-- Iterates all channels, calls 'GBNet.Channel.getRetransmitMessages' to find expired -- messages, and re-queues them as new Payload packets with congestion -- budget deducted to avoid flooding during congestion. processRetransmissions :: MonoTime -> Double -> Connection -> Connection@@ -755,7 +756,7 @@         retries = connDisconnectRetries conn         maxRetries = ncDisconnectRetries (connConfig conn) --- | Reset connection state.+-- | Reset connection state (full reset for disconnect→recycle). resetConnection :: Connection -> Connection resetConnection conn =   let config = connConfig conn@@ -778,6 +779,8 @@         .~ False         & #connChannels         .~ IntMap.map Channel.resetChannel (connChannels conn)+        & #connReliability+        .~ Rel.newReliableEndpoint         & #connCongestion         .~ newCongestionController           (ncSendRate config)@@ -788,6 +791,38 @@         .~ newBandwidthTracker bandwidthWindowMs         & #connBandwidthDown         .~ newBandwidthTracker bandwidthWindowMs++-- | Reset transport metrics for a new network path (e.g. connection migration).+-- Clears RTT, congestion, bandwidth, and stats while preserving channels,+-- encryption, salts, nonces, state, and sequence numbers.+resetTransportMetrics :: MonoTime -> Connection -> Connection+resetTransportMetrics now conn =+  let config = connConfig conn+      cwnd =+        if ncUseCwndCongestion config+          then Just (newCongestionWindow (ncMtu config))+          else Nothing+   in conn+        & #connReliability+        %~ resetReliabilityMetrics+        & #connCongestion+        .~ newCongestionController+          (ncSendRate config)+          (ncCongestionBadLossThreshold config)+          (ncCongestionGoodRttThreshold config)+          (ncCongestionRecoveryTimeMs config)+        & #connCwnd+        .~ cwnd+        & #connBandwidthUp+        .~ newBandwidthTracker bandwidthWindowMs+        & #connBandwidthDown+        .~ newBandwidthTracker bandwidthWindowMs+        & #connStats+        .~ defaultNetworkStats+        & #connLastSendTime+        .~ now+        & #connLastRecvTime+        .~ now  -- | Drain send queue. drainSendQueue :: Connection -> ([OutgoingPacket], Connection)
src/GBNet/Peer.hs view
@@ -527,10 +527,11 @@             | elapsedMs lastMigration now < migrationCooldownMs ->                 ([], peer) -- Still in cooldown           _ ->-            let migrated =+            let migratedConn = Conn.resetTransportMetrics now conn+                migrated =                   peer                     & #npConnections-                    %~ (Map.insert newPeerId conn . Map.delete oldPeerId)+                    %~ (Map.insert newPeerId migratedConn . Map.delete oldPeerId)                     & #npMigrationCooldowns                     %~ Map.insert migrationToken now                     & #npFragmentAssemblers
src/GBNet/Peer/Internal.hs view
@@ -256,7 +256,7 @@    in queueRawPacket (RawPacket pid raw) peer  -- | Clean up per-peer state (fragment assemblers).--- Migration cooldowns are swept separately in 'updateConnections'.+-- Migration cooldowns are swept separately in 'GBNet.Peer.updateConnections'. cleanupPeer :: PeerId -> NetPeer -> NetPeer cleanupPeer peerId peer =   peer & #npFragmentAssemblers %~ Map.delete peerId
src/GBNet/Reliability.hs view
@@ -58,6 +58,7 @@     ReliableEndpoint (..),     AckResult (..),     newReliableEndpoint,+    resetReliabilityMetrics,     withMaxInFlight,     nextSequence,     onPacketSent,@@ -543,6 +544,28 @@       reBytesSent = 0,       reBytesAcked = 0     }++-- | Reset transport metrics for a new network path (e.g. connection migration).+-- Clears RTT estimation, loss window, and RTO so the new path starts fresh.+-- Preserves sequence numbers, sent\/recv buffers, ack bits, cumulative counters,+-- and config fields so packet continuity is maintained.+resetReliabilityMetrics :: ReliableEndpoint -> ReliableEndpoint+resetReliabilityMetrics ep =+  ep+    & #reSrtt+    .~ 0.0+    & #reRttvar+    .~ 0.0+    & #reRto+    .~ initialRtoMillis+    & #reHasRttSample+    .~ False+    & #reLossWindow+    .~ emptyLossWindow+    & #reLossWindowIndex+    .~ 0+    & #reLossWindowCount+    .~ 0  -- | Override the maximum in-flight packet count. withMaxInFlight :: Int -> ReliableEndpoint -> ReliableEndpoint
test/Main.hs view
@@ -269,6 +269,9 @@   -- Migration cooldown sweep   testMigrationCooldownSweep +  -- Migration resets transport metrics+  testMigrationResetsTransportMetrics+   putStrLn ""   putStrLn "All tests passed!" @@ -2207,3 +2210,76 @@     postHandshakeOffsetNs = 100000000 :: MonoTime -- 100ms     pastCooldownNs = 6000000000 :: MonoTime -- 6s (> 5s cooldown, < 10s timeout)     testPayload = "migrate-me"++testMigrationResetsTransportMetrics :: IO ()+testMigrationResetsTransportMetrics = do+  putStrLn "Migration resets transport metrics:"+  sock <- newTestUdpSocket+  let serverAddr = testAddr serverPort+      clientAddr = testAddr clientPort+      config = defaultNetworkConfig {ncEnableConnectionMigration = True}+      startTime = oneSecondNs++  let serverPeer = newPeerState sock serverAddr config serverSeed+      clientPeer0 = newPeerState sock clientAddr config clientSeed+      clientPeer1 = peerConnect (peerIdFromAddr serverAddr) startTime clientPeer0++  -- Full handshake via TestNet+  let world0 = initWorld startTime serverAddr clientAddr+  let ((_, cp2), w1) = tickPeerInWorld clientAddr [] clientPeer1 world0+  let w2 = stepWorld tickStepMs w1+  let ((_, sp1), w3) = tickPeerInWorld serverAddr [] serverPeer w2+  let w4 = stepWorld tickStepMs w3+  let ((_, cp3), w5) = tickPeerInWorld clientAddr [] cp2 w4+  let w6 = stepWorld tickStepMs w5+  let ((_, sp2), w7) = tickPeerInWorld serverAddr [] sp1 w6+  let w8 = stepWorld tickStepMs w7+  let ((_, cp4), w9) = tickPeerInWorld clientAddr [] cp3 w8+  let _w10 = stepWorld tickStepMs w9++  -- Verify connection established+  assertEqual "server has 1 connection" 1 (peerCount sp2)++  -- Queue a message on the client so peerProcess produces Payload packets+  let serverPid = peerIdFromAddr serverAddr+      sendTime = startTime + postHandshakeOffsetNs+  case peerSend serverPid (ChannelId 0) testPayload sendTime cp4 of+    Left err -> error $ "  FAIL: peerSend: " ++ show err+    Right clientWithMsg -> do+      let clientResult = peerProcess sendTime [] clientWithMsg+          newClientPid = peerIdFromAddr (testAddr migratedPort)+          stripped =+            concatMap+              ( \pkt -> case validateAndStripCrc32 (rpData pkt) of+                  Nothing -> []+                  Just valid -> [IncomingPacket newClientPid valid]+              )+              (prOutgoing clientResult)++      case stripped of+        [] -> putStrLn "  PASS: Migration transport reset (no valid packets)"+        _ -> do+          let migrateResult = peerProcess sendTime stripped sp2+              events = prEvents migrateResult+              migrated = [() | PeerMigrated _ _ <- events]++          if null migrated+            then putStrLn "  PASS: Migration transport reset (migration didn't trigger)"+            else do+              let serverAfterMigration = prPeer migrateResult+              case peerStats newClientPid serverAfterMigration of+                Nothing -> error "  FAIL: no stats for migrated peer"+                Just stats -> do+                  assertEqual "RTT reset to 0 after migration" 0.0 (nsRtt stats)+                  assertEqual "congestion reset after migration" CongestionNone (nsCongestionLevel stats)+                  putStrLn "  PASS: Migration resets transport metrics"+  where+    serverPort = 7040+    clientPort = 8040+    migratedPort = 8149+    serverSeed = 300000000+    clientSeed = 400000000+    oneSecondNs = 1000000000 :: MonoTime+    tickStepMs = 10 :: MonoTime+    postHandshakeOffsetNs = 100000000 :: MonoTime -- 100ms+    testPayload = "migration-metrics-test"