diff --git a/README.md b/README.md index 5bf5f5f..ac3e63a 100644 --- a/README.md +++ b/README.md @@ -507,6 +507,12 @@ path probe: upload=32768 download=1400 persistent=true `adaptiveSizer` keeps one instance per direction plus two landmarks: `good`, the largest size known to work, and `bad`, the smallest known to fail. +An I/O timeout is different from a size failure. It is a hard tunnel boundary: +the timed-out socket is closed and the error is returned immediately. The client +does not replay that request on the same logical session and does not walk every +smaller record or batch size. The application's next connection creates a new +tunnel. Other non-timeout transport failures can still use the adaptation below. + **On failure** at the current size: * record `bad = min(bad, attempted)`, @@ -1208,9 +1214,10 @@ manual tuning makes things worse. `adaptive download batch: N -> N/2`, the path cannot sustain that depth. * **Streams die mid-transfer, or nothing loads at all.** Set `Reconnect every` to `1` (auto). Auto starts persistent and retries an idempotent request once on - a fresh connection. If reuse itself failed, only that lane switches to one - logical request per connection. This avoids turning one imperfect startup - probe into connection churn for every active tunnel. + a fresh connection for non-timeout failures. An I/O timeout ends the logical + tunnel immediately because replaying an upload whose response was lost can + duplicate data. If reuse itself failed without timing out, only that lane + switches to one logical request per connection. * **Logs show the same transition many times over (`128 -> 64` repeatedly).** Each tunnel adapts independently, so a burst of flows produces a burst of identical lines. The app collapses consecutive duplicates into a counted line; @@ -1225,6 +1232,9 @@ manual tuning makes things worse. * **Frequent `after transport failure` lines.** The network is dropping large records. Lower `Max chunk` to a size the probe already found safe — 1400 is common — so the client stops rediscovering the limit. +* **`i/o timeout`.** The active physical connection is closed and the tunnel + exits immediately. It no longer redials that session or repeats the request at + 512 KiB, 256 KiB, and every smaller size. * **Connection dies periodically, then recovers.** A middlebox is capping requests per connection. Set `Reconnect every` to 8–32. * **High-latency, high-bandwidth link.** Leave `--tcp-buffer` at 0 first. Only for @@ -1263,6 +1273,7 @@ manual tuning makes things worse. | `upload gap: got N expected M` | The same, in the upload direction. Reconnect. | | `server maximum chunk N is below client minimum M` | Raise the server's `--chunk-max` or lower the client's `Min chunk`. | | `download failed at minimum chunk` | Eight consecutive failures at the smallest record size — the path is not passing traffic at all. | +| `i/o timeout` | The physical connection timed out; its tunnel was terminated immediately without replay or a chunk-size retry loop. | | DNS works, QUIC/UDP apps do not | By design: only DNS is carried over UDP (§7.7). | | No IPv6 anywhere | By design: IPv6 is captured and blackholed (§7.4). | | Connections hang instead of failing fast | Expected only for non-SYN packets to unknown flows, which receive an RST. Anything else warrants the logs. | @@ -1282,6 +1293,7 @@ Coverage: * the adaptive record sizer recovering from the minimum rather than latching there, * `reconnectEvery == 0` meaning persistent, +* B and BP timeouts returning after one physical connection without replay, * a pinned batch never growing or shrinking across repeated failures, * a pinned batch surviving the ~1 MiB per-batch cap while an unpinned one is still trimmed by it, diff --git a/SHA256SUMS b/SHA256SUMS index 8199229..6897d93 100644 --- a/SHA256SUMS +++ b/SHA256SUMS @@ -1,6 +1,6 @@ 969e4a020d5475bfff355f38ca809edb68686b5850af8f9709126ed5bb2d13bb *bin/dragontcp-hybrid-server-linux-amd64 eaf2d07d8edf17840ce7bad4b1c81e8f3ccb1504c18397a773ca0aacb2ee72ef *bin/dragontcp-hybrid-server-linux-arm64 -2ac228a78ad918e859a41a90e667e285b0bf4cfbf2e50cd426ad89a706ffb8b2 *bin/dragontcp-hybrid-client-linux-amd64 -b4a37ee8699880ae49ef97e144e9c8fb2cdcb456045a8d41c1e4809de513b994 *android/lib/arm64-v8a/libdragontcp_client.so -3c45f678da399ecd20c28b8acc631d8c6f18151415ac63109f838a8c68a00e68 *android/lib/armeabi-v7a/libdragontcp_client.so -78806799b1c2949835e854635f6c352b572d3b3b526c4a6de877da9dd4e2d98b *android/lib/x86_64/libdragontcp_client.so +a56e8c1bbdee5b81cd4882bc67d97c61e11513c928ff67983c9111478b846a82 *bin/dragontcp-hybrid-client-linux-amd64 +5aed020f3c8d29dc7f9aeaa9546be653de537569dce4e57f6c22b9536d409967 *android/lib/arm64-v8a/libdragontcp_client.so +e1252f0501da62d1daf9eb4624b1eec54adb0380b76b037224dc604d2b95ebf2 *android/lib/armeabi-v7a/libdragontcp_client.so +cdda348cfe7aad548d9a6799594b077f555b2d8acf2364d4109a37ea6a03db46 *android/lib/x86_64/libdragontcp_client.so diff --git a/android/lib/arm64-v8a/libdragontcp_client.so b/android/lib/arm64-v8a/libdragontcp_client.so index 198dfcb..ec28a73 100644 Binary files a/android/lib/arm64-v8a/libdragontcp_client.so and b/android/lib/arm64-v8a/libdragontcp_client.so differ diff --git a/android/lib/armeabi-v7a/libdragontcp_client.so b/android/lib/armeabi-v7a/libdragontcp_client.so index 904fdd8..04b4ab4 100644 Binary files a/android/lib/armeabi-v7a/libdragontcp_client.so and b/android/lib/armeabi-v7a/libdragontcp_client.so differ diff --git a/android/lib/x86_64/libdragontcp_client.so b/android/lib/x86_64/libdragontcp_client.so index 7480431..c090f4e 100644 Binary files a/android/lib/x86_64/libdragontcp_client.so and b/android/lib/x86_64/libdragontcp_client.so differ diff --git a/bin/dragontcp-hybrid-client-linux-amd64 b/bin/dragontcp-hybrid-client-linux-amd64 index cdc341a..baa0465 100644 Binary files a/bin/dragontcp-hybrid-client-linux-amd64 and b/bin/dragontcp-hybrid-client-linux-amd64 differ