librats 1.0.2 → 2.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (319) hide show
  1. package/README.md +145 -331
  2. package/binding.gyp +16 -3
  3. package/lib/index.d.ts +288 -696
  4. package/lib/index.js +407 -44
  5. package/native-src/3rdparty/android/ifaddrs-android.c +1 -0
  6. package/native-src/3rdparty/android/ifaddrs-android.h +1 -0
  7. package/native-src/CMakeLists.txt +404 -179
  8. package/native-src/LICENSE +1 -1
  9. package/native-src/src/librats/bindings/rats.cpp +762 -0
  10. package/native-src/src/librats/bindings/rats.h +380 -0
  11. package/native-src/src/librats/bittorrent/bencode.cpp +437 -0
  12. package/native-src/src/librats/bittorrent/bencode.h +176 -0
  13. package/native-src/src/librats/bittorrent/bitfield.cpp +97 -0
  14. package/native-src/src/librats/bittorrent/bitfield.h +76 -0
  15. package/native-src/src/librats/bittorrent/byte_io.h +58 -0
  16. package/native-src/src/librats/bittorrent/choker.cpp +25 -0
  17. package/native-src/src/librats/bittorrent/choker.h +46 -0
  18. package/native-src/src/librats/bittorrent/client.cpp +413 -0
  19. package/native-src/src/librats/bittorrent/client.h +227 -0
  20. package/native-src/src/librats/bittorrent/disk_io.cpp +209 -0
  21. package/native-src/src/librats/bittorrent/disk_io.h +150 -0
  22. package/native-src/src/librats/bittorrent/extensions.cpp +191 -0
  23. package/native-src/src/librats/bittorrent/extensions.h +94 -0
  24. package/native-src/src/librats/bittorrent/file_storage.cpp +77 -0
  25. package/native-src/src/librats/bittorrent/file_storage.h +79 -0
  26. package/native-src/src/librats/bittorrent/log.h +42 -0
  27. package/native-src/src/librats/bittorrent/magnet_uri.cpp +98 -0
  28. package/native-src/src/librats/bittorrent/magnet_uri.h +35 -0
  29. package/native-src/src/librats/bittorrent/peer_connection.cpp +502 -0
  30. package/native-src/src/librats/bittorrent/peer_connection.h +194 -0
  31. package/native-src/src/librats/bittorrent/peer_list.cpp +68 -0
  32. package/native-src/src/librats/bittorrent/peer_list.h +75 -0
  33. package/native-src/src/librats/bittorrent/piece_picker.cpp +352 -0
  34. package/native-src/src/librats/bittorrent/piece_picker.h +201 -0
  35. package/native-src/src/librats/bittorrent/reactor.cpp +97 -0
  36. package/native-src/src/librats/bittorrent/reactor.h +89 -0
  37. package/native-src/src/librats/bittorrent/resume_data.cpp +72 -0
  38. package/native-src/src/librats/bittorrent/resume_data.h +41 -0
  39. package/native-src/src/librats/bittorrent/store_buffer.cpp +48 -0
  40. package/native-src/src/librats/bittorrent/store_buffer.h +47 -0
  41. package/native-src/src/librats/bittorrent/torrent.cpp +870 -0
  42. package/native-src/src/librats/bittorrent/torrent.h +260 -0
  43. package/native-src/src/librats/bittorrent/torrent_creator.cpp +129 -0
  44. package/native-src/src/librats/bittorrent/torrent_creator.h +58 -0
  45. package/native-src/src/librats/bittorrent/torrent_info.cpp +314 -0
  46. package/native-src/src/librats/bittorrent/torrent_info.h +118 -0
  47. package/native-src/src/librats/bittorrent/tracker.cpp +374 -0
  48. package/native-src/src/librats/bittorrent/tracker.h +108 -0
  49. package/native-src/src/librats/bittorrent/types.cpp +206 -0
  50. package/native-src/src/librats/bittorrent/types.h +86 -0
  51. package/native-src/src/librats/core/address.cpp +35 -0
  52. package/native-src/src/librats/core/address.h +78 -0
  53. package/native-src/src/librats/core/bytes.h +69 -0
  54. package/native-src/src/librats/core/chained_send_buffer.cpp +172 -0
  55. package/native-src/src/librats/core/chained_send_buffer.h +183 -0
  56. package/native-src/src/librats/core/endpoint_parse.cpp +41 -0
  57. package/native-src/src/librats/core/endpoint_parse.h +31 -0
  58. package/native-src/src/librats/core/event_bus.h +70 -0
  59. package/native-src/src/librats/core/host_endpoint.h +56 -0
  60. package/native-src/src/{io_poller.cpp → librats/core/io_poller.cpp} +520 -65
  61. package/native-src/src/{io_poller.h → librats/core/io_poller.h} +12 -6
  62. package/native-src/src/librats/core/ip_address.cpp +120 -0
  63. package/native-src/src/librats/core/ip_address.h +109 -0
  64. package/native-src/src/librats/core/mpsc_queue.h +47 -0
  65. package/native-src/src/librats/core/notifier.h +74 -0
  66. package/native-src/src/librats/core/receive_buffer.cpp +219 -0
  67. package/native-src/src/librats/core/receive_buffer.h +171 -0
  68. package/native-src/src/librats/core/service_registry.h +58 -0
  69. package/native-src/src/{socket.cpp → librats/core/socket.cpp} +625 -118
  70. package/native-src/src/librats/core/socket.h +496 -0
  71. package/native-src/src/librats/core/timer_queue.h +105 -0
  72. package/native-src/src/librats/core/types.cpp +43 -0
  73. package/native-src/src/librats/core/types.h +103 -0
  74. package/native-src/src/librats/core/wakeup_pipe.h +83 -0
  75. package/native-src/src/{crypto → librats/crypto}/blake2_endian.h +21 -23
  76. package/native-src/src/{crypto → librats/crypto}/blake2b.c +34 -33
  77. package/native-src/src/{crypto → librats/crypto}/blake2b.h +7 -6
  78. package/native-src/src/{crypto → librats/crypto}/blake2s.c +55 -54
  79. package/native-src/src/{crypto → librats/crypto}/blake2s.h +13 -12
  80. package/native-src/src/{crypto → librats/crypto}/chacha.c +22 -21
  81. package/native-src/src/{crypto → librats/crypto}/chacha.h +14 -13
  82. package/native-src/src/{crypto → librats/crypto}/chachapoly.c +56 -56
  83. package/native-src/src/{crypto → librats/crypto}/chachapoly.h +24 -17
  84. package/native-src/src/{crc32.cpp → librats/crypto/crc32.cpp} +1 -1
  85. package/native-src/src/{crc32.h → librats/crypto/crc32.h} +3 -1
  86. package/native-src/src/{crypto → librats/crypto}/curve25519.c +6 -4
  87. package/native-src/src/{crypto → librats/crypto}/curve25519.h +6 -3
  88. package/native-src/src/librats/crypto/hkdf.c +266 -0
  89. package/native-src/src/{crypto → librats/crypto}/hkdf.h +19 -19
  90. package/native-src/src/{noise.cpp → librats/crypto/noise.cpp} +84 -73
  91. package/native-src/src/{noise.h → librats/crypto/noise.h} +18 -8
  92. package/native-src/src/{crypto → librats/crypto}/poly1305.c +47 -46
  93. package/native-src/src/librats/crypto/poly1305.h +37 -0
  94. package/native-src/src/{sha1.cpp → librats/crypto/sha1.cpp} +33 -1
  95. package/native-src/src/{sha1.h → librats/crypto/sha1.h} +14 -6
  96. package/native-src/src/{crypto → librats/crypto}/sha256.c +15 -14
  97. package/native-src/src/{crypto → librats/crypto}/sha256.h +8 -7
  98. package/native-src/src/{crypto → librats/crypto}/sha512.c +15 -14
  99. package/native-src/src/{crypto → librats/crypto}/sha512.h +8 -7
  100. package/native-src/src/librats/dht/announce.cpp +37 -0
  101. package/native-src/src/librats/dht/announce.h +41 -0
  102. package/native-src/src/librats/dht/bep42.cpp +109 -0
  103. package/native-src/src/librats/dht/bep42.h +48 -0
  104. package/native-src/src/librats/dht/dht.cpp +501 -0
  105. package/native-src/src/librats/dht/dht.h +119 -0
  106. package/native-src/src/librats/dht/dht_runner.cpp +103 -0
  107. package/native-src/src/librats/dht/dht_runner.h +71 -0
  108. package/native-src/src/librats/dht/dos_blocker.cpp +42 -0
  109. package/native-src/src/librats/dht/dos_blocker.h +47 -0
  110. package/native-src/src/librats/dht/find_peers.cpp +52 -0
  111. package/native-src/src/librats/dht/find_peers.h +73 -0
  112. package/native-src/src/librats/dht/id.h +167 -0
  113. package/native-src/src/{krpc.cpp → librats/dht/krpc.cpp} +32 -81
  114. package/native-src/src/{krpc.h → librats/dht/krpc.h} +19 -23
  115. package/native-src/src/librats/dht/log.h +38 -0
  116. package/native-src/src/librats/dht/node.cpp +473 -0
  117. package/native-src/src/librats/dht/node.h +164 -0
  118. package/native-src/src/librats/dht/node_entry.h +81 -0
  119. package/native-src/src/librats/dht/observer.h +72 -0
  120. package/native-src/src/librats/dht/persistence.cpp +90 -0
  121. package/native-src/src/librats/dht/persistence.h +32 -0
  122. package/native-src/src/librats/dht/routing_table.cpp +559 -0
  123. package/native-src/src/librats/dht/routing_table.h +185 -0
  124. package/native-src/src/librats/dht/rpc_manager.cpp +127 -0
  125. package/native-src/src/librats/dht/rpc_manager.h +77 -0
  126. package/native-src/src/librats/dht/storage.cpp +92 -0
  127. package/native-src/src/librats/dht/storage.h +74 -0
  128. package/native-src/src/librats/dht/transport.h +27 -0
  129. package/native-src/src/librats/dht/traversal.cpp +326 -0
  130. package/native-src/src/librats/dht/traversal.h +120 -0
  131. package/native-src/src/librats/dht/udp_transport.cpp +49 -0
  132. package/native-src/src/librats/dht/udp_transport.h +51 -0
  133. package/native-src/src/librats/mdns/log.h +22 -0
  134. package/native-src/src/{mdns.cpp → librats/mdns/mdns.cpp} +75 -40
  135. package/native-src/src/{mdns.h → librats/mdns/mdns.h} +9 -8
  136. package/native-src/src/{natpmp.cpp → librats/nat/natpmp.cpp} +12 -9
  137. package/native-src/src/{natpmp.h → librats/nat/natpmp.h} +3 -3
  138. package/native-src/src/{port_mapping.h → librats/nat/port_mapping.h} +3 -2
  139. package/native-src/src/{stun.cpp → librats/nat/stun.cpp} +4 -4
  140. package/native-src/src/{stun.h → librats/nat/stun.h} +1 -1
  141. package/native-src/src/{upnp.cpp → librats/nat/upnp.cpp} +6 -6
  142. package/native-src/src/{upnp.h → librats/nat/upnp.h} +2 -2
  143. package/native-src/src/librats/node/circuit_service.h +84 -0
  144. package/native-src/src/librats/node/config.h +110 -0
  145. package/native-src/src/librats/node/dial_service.h +54 -0
  146. package/native-src/src/librats/node/dialer.cpp +264 -0
  147. package/native-src/src/librats/node/dialer.h +188 -0
  148. package/native-src/src/librats/node/host_events.h +26 -0
  149. package/native-src/src/librats/node/identify.cpp +130 -0
  150. package/native-src/src/librats/node/identify.h +71 -0
  151. package/native-src/src/librats/node/nat_status.cpp +103 -0
  152. package/native-src/src/librats/node/nat_status.h +118 -0
  153. package/native-src/src/librats/node/node.cpp +865 -0
  154. package/native-src/src/librats/node/node.h +344 -0
  155. package/native-src/src/librats/node/node_context.h +33 -0
  156. package/native-src/src/librats/node/peer_network.h +91 -0
  157. package/native-src/src/librats/peer/peer.h +49 -0
  158. package/native-src/src/librats/peer/peer_book.cpp +181 -0
  159. package/native-src/src/librats/peer/peer_book.h +88 -0
  160. package/native-src/src/librats/peer/peer_id.cpp +72 -0
  161. package/native-src/src/librats/peer/peer_id.h +62 -0
  162. package/native-src/src/librats/peer/peer_info.h +37 -0
  163. package/native-src/src/librats/peer/peer_table.cpp +170 -0
  164. package/native-src/src/librats/peer/peer_table.h +148 -0
  165. package/native-src/src/librats/security/handshaker.h +66 -0
  166. package/native-src/src/librats/security/identity.h +43 -0
  167. package/native-src/src/librats/security/noise_security.cpp +122 -0
  168. package/native-src/src/librats/security/noise_security.h +37 -0
  169. package/native-src/src/librats/security/plaintext_security.h +106 -0
  170. package/native-src/src/librats/security/session.h +37 -0
  171. package/native-src/src/{storage.cpp → librats/storage/storage.cpp} +369 -522
  172. package/native-src/src/{storage.h → librats/storage/storage.h} +135 -299
  173. package/native-src/src/librats/subsystems/bittorrent.cpp +211 -0
  174. package/native-src/src/librats/subsystems/bittorrent.h +136 -0
  175. package/native-src/src/librats/subsystems/dht_discovery.cpp +202 -0
  176. package/native-src/src/librats/subsystems/dht_discovery.h +123 -0
  177. package/native-src/src/librats/subsystems/dht_service.h +36 -0
  178. package/native-src/src/librats/subsystems/file_transfer.cpp +972 -0
  179. package/native-src/src/librats/subsystems/file_transfer.h +367 -0
  180. package/native-src/src/librats/subsystems/hole_punch.cpp +605 -0
  181. package/native-src/src/librats/subsystems/hole_punch.h +290 -0
  182. package/native-src/src/librats/subsystems/hole_punch_service.h +38 -0
  183. package/native-src/src/librats/subsystems/mdns_discovery.cpp +66 -0
  184. package/native-src/src/librats/subsystems/mdns_discovery.h +55 -0
  185. package/native-src/src/librats/subsystems/message_json.cpp +112 -0
  186. package/native-src/src/librats/subsystems/message_json.h +88 -0
  187. package/native-src/src/librats/subsystems/peer_exchange.cpp +241 -0
  188. package/native-src/src/librats/subsystems/peer_exchange.h +136 -0
  189. package/native-src/src/librats/subsystems/ping_service.cpp +98 -0
  190. package/native-src/src/librats/subsystems/ping_service.h +66 -0
  191. package/native-src/src/librats/subsystems/port_mapping_service.cpp +192 -0
  192. package/native-src/src/librats/subsystems/port_mapping_service.h +84 -0
  193. package/native-src/src/librats/subsystems/pubsub.cpp +567 -0
  194. package/native-src/src/librats/subsystems/pubsub.h +175 -0
  195. package/native-src/src/librats/subsystems/reconnection.cpp +239 -0
  196. package/native-src/src/librats/subsystems/reconnection.h +126 -0
  197. package/native-src/src/librats/subsystems/relay.cpp +1142 -0
  198. package/native-src/src/librats/subsystems/relay.h +211 -0
  199. package/native-src/src/librats/subsystems/relay_service.h +46 -0
  200. package/native-src/src/librats/transport/connection.cpp +343 -0
  201. package/native-src/src/librats/transport/connection.h +283 -0
  202. package/native-src/src/librats/transport/link.h +96 -0
  203. package/native-src/src/librats/transport/reactor.cpp +588 -0
  204. package/native-src/src/librats/transport/reactor.h +262 -0
  205. package/native-src/src/librats/transport/reactor_pool.h +81 -0
  206. package/native-src/src/librats/transport/relay_link.cpp +208 -0
  207. package/native-src/src/librats/transport/relay_link.h +303 -0
  208. package/native-src/src/librats/transport/tcp_link.cpp +49 -0
  209. package/native-src/src/librats/transport/tcp_link.h +43 -0
  210. package/native-src/src/librats/transport/udp_mux.cpp +617 -0
  211. package/native-src/src/librats/transport/udp_mux.h +363 -0
  212. package/native-src/src/librats/transport/udp_packet.cpp +121 -0
  213. package/native-src/src/librats/transport/udp_packet.h +190 -0
  214. package/native-src/src/librats/transport/udp_stream.cpp +1194 -0
  215. package/native-src/src/librats/transport/udp_stream.h +614 -0
  216. package/native-src/src/librats/util/features.h.in +51 -0
  217. package/native-src/src/{fs.cpp → librats/util/fs.cpp} +51 -3
  218. package/native-src/src/librats/util/fs.h +136 -0
  219. package/native-src/src/librats/util/json.cpp +1002 -0
  220. package/native-src/src/librats/util/json.h +444 -0
  221. package/native-src/src/{logger.cpp → librats/util/logger.cpp} +1 -1
  222. package/native-src/src/{logger.h → librats/util/logger.h} +43 -31
  223. package/native-src/src/{network_monitor.cpp → librats/util/network_monitor.cpp} +12 -4
  224. package/native-src/src/{network_monitor.h → librats/util/network_monitor.h} +2 -1
  225. package/native-src/src/{network_utils.cpp → librats/util/network_utils.cpp} +38 -23
  226. package/native-src/src/{network_utils.h → librats/util/network_utils.h} +15 -8
  227. package/native-src/src/{os.cpp → librats/util/os.cpp} +48 -18
  228. package/native-src/src/librats/util/rats_export.h +69 -0
  229. package/native-src/src/{version.cpp → librats/util/version.cpp} +2 -2
  230. package/native-src/src/{version.h.in → librats/util/version.h.in} +1 -1
  231. package/native-src/src/librats/wire/frame.cpp +76 -0
  232. package/native-src/src/librats/wire/frame.h +111 -0
  233. package/native-src/src/librats/wire/message_router.cpp +45 -0
  234. package/native-src/src/librats/wire/message_router.h +47 -0
  235. package/package.json +5 -4
  236. package/scripts/build-librats.js +1 -0
  237. package/scripts/postinstall.js +3 -3
  238. package/scripts/prepare-package.js +4 -4
  239. package/scripts/verify-installation.js +63 -105
  240. package/src/librats_node.cpp +1067 -1323
  241. package/native-src/src/bencode.cpp +0 -485
  242. package/native-src/src/bencode.h +0 -145
  243. package/native-src/src/bittorrent.cpp +0 -14
  244. package/native-src/src/bittorrent.h +0 -74
  245. package/native-src/src/bt_bitfield.cpp +0 -372
  246. package/native-src/src/bt_bitfield.h +0 -316
  247. package/native-src/src/bt_choker.cpp +0 -228
  248. package/native-src/src/bt_choker.h +0 -147
  249. package/native-src/src/bt_client.cpp +0 -1047
  250. package/native-src/src/bt_client.h +0 -445
  251. package/native-src/src/bt_create_torrent.cpp +0 -677
  252. package/native-src/src/bt_create_torrent.h +0 -473
  253. package/native-src/src/bt_extension.cpp +0 -469
  254. package/native-src/src/bt_extension.h +0 -309
  255. package/native-src/src/bt_file_storage.cpp +0 -261
  256. package/native-src/src/bt_file_storage.h +0 -298
  257. package/native-src/src/bt_handshake.cpp +0 -134
  258. package/native-src/src/bt_handshake.h +0 -157
  259. package/native-src/src/bt_messages.cpp +0 -364
  260. package/native-src/src/bt_messages.h +0 -324
  261. package/native-src/src/bt_network.cpp +0 -1007
  262. package/native-src/src/bt_network.h +0 -417
  263. package/native-src/src/bt_peer_connection.cpp +0 -742
  264. package/native-src/src/bt_peer_connection.h +0 -592
  265. package/native-src/src/bt_piece_picker.cpp +0 -786
  266. package/native-src/src/bt_piece_picker.h +0 -473
  267. package/native-src/src/bt_resume_data.cpp +0 -410
  268. package/native-src/src/bt_resume_data.h +0 -249
  269. package/native-src/src/bt_torrent.cpp +0 -2120
  270. package/native-src/src/bt_torrent.h +0 -641
  271. package/native-src/src/bt_torrent_info.cpp +0 -659
  272. package/native-src/src/bt_torrent_info.h +0 -418
  273. package/native-src/src/bt_types.h +0 -621
  274. package/native-src/src/chained_send_buffer.cpp +0 -75
  275. package/native-src/src/chained_send_buffer.h +0 -137
  276. package/native-src/src/crypto/hkdf.c +0 -266
  277. package/native-src/src/crypto/poly1305.h +0 -36
  278. package/native-src/src/dht.cpp +0 -3311
  279. package/native-src/src/dht.h +0 -717
  280. package/native-src/src/disk_io.cpp +0 -632
  281. package/native-src/src/disk_io.h +0 -315
  282. package/native-src/src/file_transfer.cpp +0 -1415
  283. package/native-src/src/file_transfer.h +0 -286
  284. package/native-src/src/fs.h +0 -108
  285. package/native-src/src/gossipsub.cpp +0 -1139
  286. package/native-src/src/gossipsub.h +0 -403
  287. package/native-src/src/ice.cpp +0 -893
  288. package/native-src/src/ice.h +0 -559
  289. package/native-src/src/json.hpp +0 -25526
  290. package/native-src/src/librats.cpp +0 -2378
  291. package/native-src/src/librats.h +0 -2324
  292. package/native-src/src/librats_bittorrent.cpp +0 -601
  293. package/native-src/src/librats_c.cpp +0 -1557
  294. package/native-src/src/librats_c.h +0 -323
  295. package/native-src/src/librats_discovery.cpp +0 -402
  296. package/native-src/src/librats_encryption.cpp +0 -275
  297. package/native-src/src/librats_file_transfer.cpp +0 -144
  298. package/native-src/src/librats_gossipsub.cpp +0 -289
  299. package/native-src/src/librats_ice.cpp +0 -213
  300. package/native-src/src/librats_log_macros.h +0 -36
  301. package/native-src/src/librats_logging.cpp +0 -173
  302. package/native-src/src/librats_mdns.cpp +0 -166
  303. package/native-src/src/librats_persistence.cpp +0 -796
  304. package/native-src/src/librats_portmap.cpp +0 -419
  305. package/native-src/src/librats_reconnection.cpp +0 -218
  306. package/native-src/src/librats_statistic.cpp +0 -105
  307. package/native-src/src/librats_storage.cpp +0 -189
  308. package/native-src/src/rats_export.h +0 -17
  309. package/native-src/src/receive_buffer.cpp +0 -82
  310. package/native-src/src/receive_buffer.h +0 -127
  311. package/native-src/src/socket.h +0 -228
  312. package/native-src/src/threadmanager.cpp +0 -105
  313. package/native-src/src/threadmanager.h +0 -53
  314. package/native-src/src/tracker.cpp +0 -1264
  315. package/native-src/src/tracker.h +0 -319
  316. package/native-src/src/turn.cpp +0 -762
  317. package/native-src/src/turn.h +0 -460
  318. package/native-src/src/wakeup_pipe.h +0 -60
  319. /package/native-src/src/{os.h → librats/util/os.h} +0 -0
@@ -0,0 +1,614 @@
1
+ #pragma once
2
+
3
+ /**
4
+ * @file udp_stream.h
5
+ * @brief An ordered, reliable byte stream over datagrams — TCP's guarantees, in
6
+ * user space, on a socket shared by every peer.
7
+ *
8
+ * ── Why ──────────────────────────────────────────────────────────────────────
9
+ * For a peer-to-peer node UDP is the better default wire: a single socket serves
10
+ * every peer (so a NAT keeps one mapping open, and hole punching has something to
11
+ * punch), the port a peer sees is the port we listen on, and nothing in the path
12
+ * has to hold per-connection kernel state. What UDP does not give is what every
13
+ * layer above needs — order, reliability and congestion control. That is this
14
+ * file. Above it, nothing knows the difference: the same block framing, the same
15
+ * Noise handshake and the same Session run unchanged over TCP or over this.
16
+ *
17
+ * ── The protocol ─────────────────────────────────────────────────────────────
18
+ * Wire format lives in udp_packet.h. The stream itself is a compact, standard
19
+ * design — deliberately familiar rather than novel, because a transport is the
20
+ * wrong place to be clever:
21
+ *
22
+ * - Packet-numbered, not byte-numbered. Syn, Data and Fin each consume exactly
23
+ * one sequence number; a pure Ack consumes none. That single rule is what
24
+ * makes the retransmission queue a plain deque whose i-th entry is always
25
+ * `front().seq + i`, so a selective ack resolves to an index instead of a
26
+ * search.
27
+ * - Cumulative ack + a 32-bit selective-ack bitmap, so one lost packet is
28
+ * repaired without stalling everything queued behind it.
29
+ * - RFC 6298 retransmission timing (SRTT/RTTVAR → RTO, doubling on each
30
+ * timeout, Karn's rule so a retransmitted packet never poisons the estimate),
31
+ * plus fast retransmit on the third duplicate ack.
32
+ * - Reno-style congestion control: slow start to `ssthresh`, then additive
33
+ * increase; multiplicative decrease on loss. Flow control is separate and
34
+ * absolute — the receiver advertises, in packets, how much more it will
35
+ * buffer, and the sender never exceeds it.
36
+ * - No Nagle: a partial packet goes out rather than waiting for company, which
37
+ * is what keeps a request/response exchange from paying a round trip per
38
+ * turn. What stands in for it is write() itself — it tops up the tail packet
39
+ * while it has room, so consecutive small frames share one datagram anyway,
40
+ * and UdpMux then hands the socket a whole batch of them per syscall. The
41
+ * packing catches everything a reactor turn produced, because Connection
42
+ * aggregates a turn's frames and writes them once rather than flushing each
43
+ * — which is where most of the per-message cost used to go.
44
+ * - Paced: the window says how much may be outstanding, not how fast it may
45
+ * leave, so transmissions are metered at `gain * cwnd / srtt` rather than
46
+ * released in a burst. HyStart++ ends slow start on a rising round trip
47
+ * instead of on a loss, and a window nobody has validated for a round trip
48
+ * is given back (RFC 2861) rather than believed.
49
+ * - A tail loss is probed, not timed out: the last packet of a burst has
50
+ * nothing behind it to produce duplicate acknowledgements, so silence is
51
+ * answered with a question (RFC 8985) before it is treated as congestion.
52
+ *
53
+ * ── Ownership and threading ──────────────────────────────────────────────────
54
+ * A stream is owned by the UdpMux and touched only by the reactor thread that
55
+ * drives it — no locks, no atomics, like everything else on this path. It reaches
56
+ * the wire and reports events through UdpStreamHost, and never sees the socket,
57
+ * the reactor or the Connection directly. Events are *recorded* by the host, not
58
+ * delivered inline, so a stream is never destroyed underneath the call that is
59
+ * still running inside it.
60
+ */
61
+
62
+ #include "librats/core/address.h"
63
+ #include "librats/core/bytes.h"
64
+ #include "librats/core/receive_buffer.h"
65
+ #include "librats/core/types.h"
66
+ #include "librats/transport/udp_packet.h"
67
+
68
+ #include <chrono>
69
+ #include <cstdint>
70
+ #include <deque>
71
+ #include <optional>
72
+ #include <unordered_map>
73
+ #include <vector>
74
+
75
+ namespace librats {
76
+
77
+ class UdpStream;
78
+
79
+ /// What a stream needs from its owner: a way to the wire, and somewhere to leave
80
+ /// the events its connection should see.
81
+ class UdpStreamHost {
82
+ public:
83
+ virtual ~UdpStreamHost() = default;
84
+
85
+ /// Emit one datagram. Best effort by design — a datagram the socket refuses is
86
+ /// indistinguishable from one the path drops, and retransmission covers both.
87
+ virtual void send_datagram(const Address& to, const uint8_t* data, size_t len) = 0;
88
+
89
+ /// Record poll-equivalent events (PollIn/PollOut/PollErr) for the connection
90
+ /// that owns `stream`. Implementations must only *record*: the events are
91
+ /// dispatched once the current batch of packets or timers is done, so a
92
+ /// handler that tears the connection down cannot pull the stream out from
93
+ /// under the code that is still walking it. Repeated events for one stream
94
+ /// within a batch are expected — a stream raises PollIn per packet delivered —
95
+ /// and an implementation is free to coalesce them into one dispatch.
96
+ virtual void stream_events(UdpStream& stream, uint32_t events) = 0;
97
+ };
98
+
99
+ class UdpStream {
100
+ public:
101
+ using Clock = std::chrono::steady_clock;
102
+
103
+ // ── Tunables ────────────────────────────────────────────────────────────
104
+
105
+ /// Bytes the stream will take from the connection before it says "no more".
106
+ /// The connection keeps the rest in its own send queue, where the existing
107
+ /// high-water mark governs it, so this only bounds what the transport itself
108
+ /// holds — roughly a full window plus room to keep the pipe fed.
109
+ ///
110
+ /// It has to stay comfortably above a full window (kMaxWindowPackets *
111
+ /// kMaxPayload ≈ 1.2 MiB), because it caps `sent_` and `unsent_` *together*:
112
+ /// set at or below the window it, not the window, becomes the throughput
113
+ /// ceiling, and the pipe drains between acks because nothing is queued behind
114
+ /// what is in flight.
115
+ static constexpr size_t kSendQueueLimit = 2 * 1024 * 1024;
116
+
117
+ /// Packet buffers kept for reuse after their packet is acknowledged. The send
118
+ /// path allocates one buffer per packet, and in a bulk transfer that is one
119
+ /// allocation per 1200 bytes shipped; recycling turns the steady state into no
120
+ /// allocation at all. Small on purpose — creation and retirement run at the
121
+ /// same rate once a transfer is going, so a handful covers the churn, and an
122
+ /// idle stream should not sit on memory it is not using.
123
+ static constexpr size_t kMaxSpareBuffers = 8;
124
+
125
+ /// Initial congestion window. Four packets is the classic conservative start
126
+ /// (RFC 3390 territory) — enough to get an RTT sample and trigger fast
127
+ /// retransmit on an early loss, without a burst into an unknown path.
128
+ static constexpr uint32_t kInitialCwnd = 4 * rudp::kMaxPayload;
129
+ static constexpr uint32_t kMinCwnd = 2 * rudp::kMaxPayload;
130
+ /// A full window. Growing the congestion window past what the receiver will
131
+ /// ever hold buys nothing: the packet-count check in can_transmit() would stop
132
+ /// the sender first, and a cwnd that has run away above the real limit takes a
133
+ /// spurious loss with it when it is finally halved.
134
+ static constexpr uint32_t kMaxCwnd = rudp::kMaxWindowPackets * rudp::kMaxPayload;
135
+
136
+ static constexpr std::chrono::milliseconds kInitialRto{500};
137
+ static constexpr std::chrono::milliseconds kMinRto{100};
138
+ static constexpr std::chrono::milliseconds kMaxRto{6000};
139
+
140
+ /// Transmissions of the Syn before an unanswered dial is called failed. Three
141
+ /// attempts at a doubling 500 ms RTO give up after ~3.5 s — fast enough that a
142
+ /// node on a UDP-blocking network falls back to TCP promptly (see the dialer),
143
+ /// and slow enough to ride out a genuinely lossy path.
144
+ static constexpr int kSynMaxAttempts = 3;
145
+ /// Transmissions of one packet on an established stream before the peer is
146
+ /// declared gone. With RTO doubling to its 6 s cap this is a bit over a minute.
147
+ static constexpr int kMaxRetransmits = 12;
148
+
149
+ /// How long an acknowledgement may wait for a packet to ride along on. Only
150
+ /// ever delays a *pure* ack: an out-of-order packet, a Syn or a Fin is
151
+ /// acknowledged at once, and any outgoing packet carries the ack for free.
152
+ static constexpr std::chrono::milliseconds kDelayedAck{20};
153
+ /// Packets a single acknowledgement may repair. Bounds the burst one ack can
154
+ /// provoke, so a window that was mostly lost is rebuilt over a few acks
155
+ /// instead of being dumped back onto a path that just proved it is congested.
156
+ static constexpr int kMaxRepairsPerAck = 8;
157
+
158
+ /// Minimum gap between two transmissions of the same packet. Selective acks
159
+ /// arrive several times per round trip, and without this floor each of them
160
+ /// would re-send the same not-yet-repaired packet — turning a single loss into
161
+ /// a flood. It also stands in for the round-trip estimate on a path (loopback,
162
+ /// LAN) whose RTT is too small to space anything out.
163
+ static constexpr std::chrono::milliseconds kMinRepairSpacing{10};
164
+
165
+ // ── Pacing ──────────────────────────────────────────────────────────────
166
+ //
167
+ // A congestion window is permission to have N bytes *outstanding*, not
168
+ // permission to put them on the wire back to back. Emitting a whole window
169
+ // at line rate is what turns a queue that was merely full into a queue that
170
+ // dropped a hundred packets at once — and it happens even when the window is
171
+ // well under what the path can hold, because the burst arrives faster than
172
+ // the bottleneck can drain it. So transmissions are released at the rate the
173
+ // window implies rather than as fast as the loop can produce them.
174
+ //
175
+ // The rate is `gain * cwnd / srtt`. The gain is above 1 on purpose: slow
176
+ // start has to deliver a *doubling* window within one round trip, so pacing
177
+ // it at exactly cwnd/srtt would hold growth back by a factor of two, and in
178
+ // congestion avoidance a little headroom keeps an ack-clocked sender from
179
+ // being throttled by its own estimate. These are the gains RFC 9002 (7.7)
180
+ // recommends and Linux uses.
181
+ static constexpr uint32_t kPaceGainSlowStartNum = 2;
182
+ static constexpr uint32_t kPaceGainSlowStartDen = 1;
183
+ static constexpr uint32_t kPaceGainSteadyNum = 5; ///< 1.25x
184
+ static constexpr uint32_t kPaceGainSteadyDen = 4;
185
+
186
+ /// Burst the pacer tolerates, expressed as time rather than packets: it is
187
+ /// what accrues at the current rate over one wake-up of the reactor. Below
188
+ /// this there is nothing to gain — the timer cannot space packets finer than
189
+ /// it can wake — and pacing every packet against a 1 ms clock would cap a
190
+ /// stream at one packet per millisecond. Above it the smoothing is thrown
191
+ /// away. So the pacer does not remove bursts, it bounds them to one clock
192
+ /// tick's worth of data, which is what the queue can absorb.
193
+ static constexpr std::chrono::milliseconds kPaceQuantum{1};
194
+ /// Floor for that burst. Two packets is the classic allowance (a delayed ack
195
+ /// releases two at a time), and it keeps a stream on a very slow path from
196
+ /// pacing itself below one packet per round trip.
197
+ static constexpr size_t kPaceMinBurst = 2 * rudp::kMaxPayload;
198
+
199
+ // ── HyStart++ (RFC 9406): leaving slow start before the loss ─────────────
200
+ //
201
+ // Slow start doubles the window every round trip and, left alone, stops only
202
+ // when something is dropped — which means it always overshoots the path by
203
+ // roughly a factor of two and pays for the discovery with a lost window.
204
+ // HyStart++ watches the *minimum* round-trip time per round instead: a queue
205
+ // building in front of the bottleneck raises it well before it overflows.
206
+ // When it rises past a threshold the sender leaves exponential growth for a
207
+ // cautious phase (CSS), and if the rise turns out to be noise it goes back.
208
+ static constexpr std::chrono::milliseconds kHyMinRttThresh{4};
209
+ static constexpr std::chrono::milliseconds kHyMaxRttThresh{16};
210
+ /// Round-trip samples a round needs before its minimum is worth comparing.
211
+ static constexpr int kHyRttSamples = 8;
212
+ /// Growth divisor in the cautious phase: a quarter of slow start, so the
213
+ /// window still probes upward but cannot double while the verdict is out.
214
+ static constexpr uint32_t kHyCssGrowthDivisor = 4;
215
+ /// Rounds the cautious phase lasts before the exit is believed.
216
+ static constexpr int kHyCssRounds = 5;
217
+
218
+ // ── Tail loss probe (RFC 8985 / RFC 9002 §6.2) ──────────────────────────
219
+ //
220
+ // A loss is normally noticed by what arrives *after* it: duplicate
221
+ // acknowledgements, or a selective ack naming the hole. Neither exists when
222
+ // the packet that went missing was the last one — the receiver has nothing
223
+ // further to acknowledge and simply falls silent. Left to the retransmission
224
+ // timeout, that costs kMinRto (100 ms) *and* collapses the congestion window
225
+ // to one packet, on a stream where nothing is actually congested.
226
+ //
227
+ // For request/response traffic — which is most of what a peer-to-peer node
228
+ // does — the tail is not an edge case, it is every message. So the first one
229
+ // or two expiries are treated as a question rather than a verdict: re-send
230
+ // the packet the peer has gone quiet on, leave the window alone, and only
231
+ // escalate to the real timeout if the silence persists.
232
+ static constexpr int kMaxTailProbes = 2;
233
+ /// Floor for the probe timer. Well under kMinRto — that floor exists to keep
234
+ /// a *timeout* from firing spuriously, and a spurious timeout is expensive
235
+ /// where a spurious probe costs one packet — but still above the delayed
236
+ /// acknowledgement it must not race.
237
+ static constexpr std::chrono::milliseconds kMinProbeTimeout{30};
238
+
239
+ /// Times a re-opened receive window is announced before the matter is left to
240
+ /// the keep-alive. A window update rides on a bare acknowledgement, and nothing
241
+ /// retransmits one — while the sender it is meant for is stopped and produces
242
+ /// no traffic for a second copy to ride on. So a single dropped update would
243
+ /// cost that sender a full keep-alive interval of silence over one lost packet.
244
+ /// Repeating it on the retransmission timeout makes the common recovery a round
245
+ /// trip instead, and the keep-alive remains the backstop behind these.
246
+ static constexpr int kMaxWindowAnnounces = 4;
247
+
248
+ /// Idle gap after which an ack is sent purely to prove we are still here.
249
+ static constexpr std::chrono::seconds kKeepAlive{10};
250
+ /// Silence from the peer that ends the stream. Comfortably more than four
251
+ /// keep-alive intervals, so only real loss of contact trips it.
252
+ static constexpr std::chrono::seconds kIdleTimeout{45};
253
+
254
+ /// @param profile How hard an OUTBOUND dial tries (see DialProfile). Ignored
255
+ /// for an inbound stream, which never sends a Syn. The default is the
256
+ /// ordinary dial; a hole punch passes DialProfile::punch().
257
+ UdpStream(UdpStreamHost& host, const Address& remote, uint32_t recv_id, uint32_t send_id,
258
+ ConnRole role, Clock::time_point now, DialProfile profile = {});
259
+
260
+ UdpStream(const UdpStream&) = delete;
261
+ UdpStream& operator=(const UdpStream&) = delete;
262
+
263
+ // ── Identity ────────────────────────────────────────────────────────────
264
+
265
+ /// The id peers put in packets addressed to this stream (our demux key).
266
+ uint32_t recv_id() const noexcept { return recv_id_; }
267
+ /// The id we put in packets we send (the peer's demux key).
268
+ uint32_t send_id() const noexcept { return send_id_; }
269
+ const Address& remote() const noexcept { return remote_; }
270
+ ConnRole role() const noexcept { return role_; }
271
+
272
+ /// The connection this stream belongs to, once the reactor has adopted it.
273
+ ConnId conn_id() const noexcept { return conn_id_; }
274
+ void set_conn_id(ConnId id) noexcept { conn_id_ = id; }
275
+
276
+ // ── Driven by the mux ───────────────────────────────────────────────────
277
+
278
+ /// Feed one decoded datagram addressed to this stream.
279
+ void on_packet(const rudp::Packet& p, Clock::time_point now);
280
+
281
+ /// Periodic work: retransmission, delayed acks, keep-alive, idle death.
282
+ void tick(Clock::time_point now);
283
+
284
+ /// When tick() next has something to do — the earliest of the retransmission
285
+ /// timeout, an owed acknowledgement, the keep-alive and the idle deadline.
286
+ ///
287
+ /// This is what lets the mux schedule streams instead of sweeping them: a
288
+ /// stream that is merely connected wants to be visited once per keep-alive
289
+ /// (10 s), not fifty times a second, and a node with no streams at all wants
290
+ /// no timer whatsoever. Every mutating entry point re-reads this, so a
291
+ /// deadline can never move earlier without the owner being told.
292
+ ///
293
+ /// Two values are special:
294
+ /// - `nullopt` — never; only a dead stream, which the mux drops rather than
295
+ /// services.
296
+ /// - the clock epoch — *now*. An acknowledgement owed with no deadline (see
297
+ /// `ack_due_`) is one that must go out at the first opportunity, because
298
+ /// the peer it is meant for is stopped on a zero window and will send
299
+ /// nothing for it to ride on.
300
+ std::optional<Clock::time_point> next_deadline() const noexcept;
301
+
302
+ // ── Driven by the Link / Connection ─────────────────────────────────────
303
+
304
+ /// Copy up to `len` bytes of in-order stream data out. 0 means nothing is
305
+ /// ready (check eof() to tell "not yet" from "never again").
306
+ size_t read(uint8_t* into, size_t len);
307
+
308
+ /// Queue `count` slices for the peer, taking as much as the send queue will
309
+ /// hold. Returns the bytes accepted; 0 means the queue is full and the caller
310
+ /// should ask to be told when it drains (see want_write).
311
+ size_t write(const ByteView* slices, size_t count, Clock::time_point now);
312
+
313
+ /// Ask to be given a writable event when the send queue drains again.
314
+ void want_write(bool on) noexcept { want_write_ = on; }
315
+
316
+ /// Orderly shutdown: queue a Fin behind everything already written, so the
317
+ /// peer sees every byte we owe it and then a clean end of stream.
318
+ void begin_close(Clock::time_point now);
319
+
320
+ /// Abrupt shutdown: tell the peer the stream is gone and stop. Used when
321
+ /// there is nothing worth flushing, or when the stream has already failed.
322
+ void abort(Clock::time_point now);
323
+
324
+ // ── State ───────────────────────────────────────────────────────────────
325
+
326
+ bool connecting() const noexcept { return state_ == State::SynSent; }
327
+ bool connected() const noexcept { return state_ == State::Connected; }
328
+ bool dead() const noexcept { return state_ == State::Dead; }
329
+
330
+ /// The peer finished sending AND everything it sent has been read out.
331
+ bool eof() const noexcept { return peer_fin_ && inbox_.empty(); }
332
+
333
+ /// Why the stream died (only meaningful once dead()).
334
+ CloseReason close_reason() const noexcept { return close_reason_; }
335
+
336
+ /// Nothing left to deliver: every packet we queued has been acknowledged.
337
+ /// The condition the mux lingers a released stream until.
338
+ bool flushed() const noexcept { return sent_.empty() && unsent_.empty(); }
339
+
340
+ // — diagnostics (tests, logging) —
341
+ uint32_t cwnd() const noexcept { return cwnd_; }
342
+ /// Where slow start stops. Starts at the ceiling and comes down either when
343
+ /// HyStart++ sees the round-trip time rise or when something is lost — which
344
+ /// of the two happened is the whole question F2 asks.
345
+ uint32_t ssthresh() const noexcept { return ssthresh_; }
346
+ size_t bytes_in_flight() const noexcept { return flight_bytes_; }
347
+ size_t queued_bytes() const noexcept { return queued_bytes_; }
348
+ uint32_t retransmits() const noexcept { return retransmits_; }
349
+ /// Tail probes sent since the last acknowledgement (diagnostics, tests).
350
+ int tail_probes() const noexcept { return tail_probes_; }
351
+ /// Times the congestion window has been reduced. One per loss *episode* is the
352
+ /// invariant that keeps a single lost packet from walking the window to the
353
+ /// floor over the many acks that report it — see enter_recovery().
354
+ uint32_t window_reductions() const noexcept { return window_reductions_; }
355
+
356
+ private:
357
+ enum class State {
358
+ SynSent, ///< outbound: the Syn is in flight, nothing else may go yet
359
+ Connected, ///< both directions open (a Fin may still be queued)
360
+ Dead, ///< finished or failed; the mux will drop it
361
+ };
362
+
363
+ /// One packet occupying exactly one sequence number.
364
+ ///
365
+ /// `buf` is the datagram itself, laid out as
366
+ ///
367
+ /// [ kMaxHeaderSize bytes of headroom ][ payload ]
368
+ ///
369
+ /// so transmit() writes the header into the tail of the headroom, directly in
370
+ /// front of the payload, and hands the socket one contiguous range. The
371
+ /// alternative — payload in its own buffer, copied into a scratch datagram
372
+ /// behind a freshly built header — costs a full payload copy on every send
373
+ /// *and* every retransmission, on the hottest path this transport has.
374
+ struct OutPacket {
375
+ Bytes buf; ///< headroom + payload; only headroom for Syn/Fin
376
+ uint32_t seq = 0;
377
+ rudp::PacketType type = rudp::PacketType::Data;
378
+ Clock::time_point sent_at{};
379
+ int sends = 0; ///< transmissions so far (0 = still unsent)
380
+ bool acked = false; ///< selectively acknowledged, awaiting the cumulative ack
381
+ /// This packet's bytes are counted in flight_bytes_ right now. Set by the
382
+ /// transmission that put them on the wire, cleared when they are either
383
+ /// acknowledged or declared lost — because a packet a retransmission
384
+ /// timeout has given up on is no longer occupying the path, and leaving it
385
+ /// counted is what would stop the sender from ever refilling the pipe.
386
+ bool in_flight = false;
387
+
388
+ /// Payload bytes — what the accounting (flight_bytes_, queued_bytes_) counts.
389
+ size_t size() const noexcept {
390
+ return buf.size() > rudp::kMaxHeaderSize ? buf.size() - rudp::kMaxHeaderSize : 0;
391
+ }
392
+ /// Room left in a partially filled tail packet (only meaningful while unsent).
393
+ size_t space() const noexcept { return rudp::kMaxPayload - size(); }
394
+ };
395
+
396
+ /// A packet held out of order, waiting for the gap in front of it to fill.
397
+ struct InPacket {
398
+ Bytes payload;
399
+ bool fin = false;
400
+ };
401
+
402
+ // — outbound —
403
+ OutPacket new_packet(rudp::PacketType type);
404
+ void recycle(OutPacket& p);
405
+ void transmit(OutPacket& p, Clock::time_point now);
406
+ void send_control(rudp::PacketType type, Clock::time_point now);
407
+ void pump(Clock::time_point now);
408
+ void retransmit_lost(Clock::time_point now);
409
+ bool can_transmit() const noexcept;
410
+ /// Everything can_transmit() checks *except* the pacer: the state machine,
411
+ /// the peer's window and our own. Split out because pump() has to tell "the
412
+ /// pacer is holding this back" — which a timer resolves — from "a window is",
413
+ /// which only an acknowledgement can.
414
+ bool window_allows() const noexcept;
415
+ bool cwnd_allows(size_t bytes) const noexcept;
416
+ void fill_common(rudp::Packet& p) const;
417
+ uint16_t advertised_window() const noexcept;
418
+
419
+ // — pacing —
420
+ /// The window the pacer meters against: cwnd scaled by the phase's gain.
421
+ /// Zero means "not pacing" (no round-trip estimate yet, so no rate to pace at).
422
+ uint64_t pace_window() const noexcept;
423
+ /// Bytes the pacer may release over `dt` at the current rate.
424
+ uint64_t pace_bytes_over(Clock::duration dt) const noexcept;
425
+ /// Hand the token bucket whatever has accrued since it was last topped up.
426
+ void pace_accrue(Clock::time_point now);
427
+ /// Whether `bytes` may go out now. Always true when nothing is in flight —
428
+ /// the lone packet a recovering stream is allowed and the first packet after
429
+ /// an idle period must never be held back by a rate derived from an empty
430
+ /// pipe. A receiver's zero window is not this check's business: it stops the
431
+ /// packet earlier, in window_allows().
432
+ bool pace_allows(size_t bytes) const noexcept;
433
+ /// How long until `bytes` could be released. Zero when they can go now.
434
+ Clock::duration pace_wait(size_t bytes) const noexcept;
435
+
436
+ // — window validation after an idle period (RFC 2861) —
437
+ void restart_after_idle(Clock::time_point now);
438
+
439
+ // — HyStart++ (RFC 9406) —
440
+ void hystart_reset();
441
+ void hystart_sample(Clock::duration rtt);
442
+ void hystart_on_ack(uint32_t ack);
443
+ bool in_slow_start() const noexcept { return cwnd_ < ssthresh_; }
444
+
445
+ // — inbound —
446
+ void handle_ack(const rudp::Packet& p, Clock::time_point now);
447
+ void handle_retry(const rudp::Packet& p, Clock::time_point now);
448
+ void repair_sacked_holes(Clock::time_point now);
449
+ void handle_sequenced(const rudp::Packet& p);
450
+ void deliver(ByteView payload, bool fin);
451
+ void drain_reorder();
452
+ uint32_t sack_bitmap() const noexcept;
453
+
454
+ // — timing / congestion —
455
+ void on_rto(Clock::time_point now);
456
+ /// How long to wait before asking whether the tail got through. A round trip
457
+ /// plus what the peer may sit on an acknowledgement for, doubled per
458
+ /// consecutive unanswered probe.
459
+ Clock::duration probe_timeout() const noexcept;
460
+ /// What the one loss-detection timer should be set to right now: the probe
461
+ /// interval while there are probes left to spend, the retransmission timeout
462
+ /// once there are not. One timer, two meanings — which is how RFC 9002 models
463
+ /// it too, and why arming it in one place keeps the two from disagreeing.
464
+ Clock::duration loss_timeout() const noexcept;
465
+ void sample_rtt(Clock::duration rtt);
466
+ void enter_recovery();
467
+ void on_loss(bool timeout);
468
+ void grow_window(size_t acked_bytes);
469
+
470
+ void die(CloseReason reason);
471
+ void raise(uint32_t events) noexcept { events_ |= events; }
472
+ void flush_events();
473
+
474
+ UdpStreamHost& host_;
475
+ Address remote_;
476
+ uint32_t recv_id_;
477
+ uint32_t send_id_;
478
+ ConnRole role_;
479
+ ConnId conn_id_ = kInvalidConnId;
480
+
481
+ State state_;
482
+ CloseReason close_reason_ = CloseReason::PeerClosed;
483
+ bool peer_fin_ = false; ///< peer's Fin delivered in order
484
+ bool fin_queued_ = false; ///< our Fin is in the send queue
485
+ bool want_write_ = false;
486
+ /// A Retry has already been answered on this stream. The responder is entitled
487
+ /// to ask us to prove our address once; honouring a second one would let anyone
488
+ /// who can forge a datagram from the peer keep the dial going round forever.
489
+ bool retried_ = false;
490
+ uint32_t events_ = 0; ///< pending PollIn/PollOut/PollErr
491
+
492
+ // — send side —
493
+ // `sent_` holds transmitted-but-unacknowledged packets in strictly
494
+ // consecutive sequence order, which is the whole reason a selective ack can
495
+ // be resolved by index rather than by search: sent_[i].seq == sent_[0].seq + i.
496
+ std::deque<OutPacket> sent_;
497
+ std::deque<OutPacket> unsent_;
498
+ std::vector<Bytes> spare_; ///< retired packet buffers, kept for reuse
499
+ uint32_t next_seq_ = 1; ///< sequence number for the next packet created
500
+ size_t flight_bytes_ = 0; ///< payload bytes transmitted and not yet acked
501
+ size_t queued_bytes_ = 0; ///< payload bytes held by sent_ + unsent_
502
+ uint32_t cwnd_ = kInitialCwnd;
503
+ uint32_t ssthresh_ = kMaxCwnd;
504
+ uint16_t peer_window_ = rudp::kMaxWindowPackets;
505
+ /// The cumulative acknowledgement `peer_window_` came in on. What orders two
506
+ /// windows in time: a peer's ack never moves backwards, so a packet carrying
507
+ /// one that has is a packet from the past, and the window on it with it.
508
+ uint32_t window_ack_ = 0;
509
+ uint32_t last_ack_recv_ = 0;
510
+ int dup_acks_ = 0;
511
+ uint32_t retransmits_ = 0;
512
+ uint32_t window_reductions_ = 0;
513
+ /// Consecutive tail probes sent with nothing acknowledged in between. Reset by
514
+ /// any acknowledgement that covers new data, so it counts a single episode of
515
+ /// silence rather than the life of the stream.
516
+ int tail_probes_ = 0;
517
+
518
+ // Loss episodes. A window is reduced once per episode, not once per ack that
519
+ // happens to repair something — several acks arrive per round trip, and each
520
+ // of them halving again is what turns two losses in a window into a collapse
521
+ // to the floor. `recover_seq_` is the NewReno recovery point: the highest
522
+ // sequence number outstanding when the episode began, so the episode ends
523
+ // exactly when the cumulative ack has covered everything that was in flight
524
+ // when the loss was detected.
525
+ bool in_recovery_ = false;
526
+ uint32_t recover_seq_ = 0;
527
+ /// A retransmission timeout has given up on packets still sitting in `sent_`,
528
+ /// so retransmit_lost() has work to do. Purely a hint that keeps it from
529
+ /// scanning the whole queue on every acknowledgement of a healthy transfer.
530
+ bool have_lost_ = false;
531
+
532
+ // — pacing —
533
+ /// Bytes the pacer will currently let through, and when the bucket was last
534
+ /// topped up. Kept in bytes rather than packets so a partly filled tail
535
+ /// packet costs what it actually weighs.
536
+ uint64_t pace_tokens_ = 0;
537
+ Clock::time_point pace_last_{};
538
+ /// When the pacer expects to have enough for the packet it is holding back
539
+ /// (epoch = it is holding nothing). This is a deadline like any other: the
540
+ /// mux wakes the stream on it, and pump() re-arms or clears it.
541
+ Clock::time_point pace_due_{};
542
+ /// When data — not a bare acknowledgement — last went out. The keep-alive
543
+ /// writes last_send_ every ten seconds, so it cannot answer "has this stream
544
+ /// been sending?", which is exactly what the idle-restart rule needs to know.
545
+ Clock::time_point last_data_send_{};
546
+
547
+ // — HyStart++ —
548
+ /// Cautious phase: slow start has seen the round-trip time rise and is
549
+ /// probing gently until the rise is confirmed or withdrawn.
550
+ bool css_ = false;
551
+ int css_rounds_ = 0;
552
+ Clock::duration css_baseline_rtt_{};
553
+ /// Lowest round-trip time seen in this round and in the one before it. The
554
+ /// *minimum* is what matters: a queue building in front of the bottleneck
555
+ /// lifts even the luckiest packet's round trip, where an average would just
556
+ /// as easily be moved by one straggler.
557
+ Clock::duration round_min_rtt_{};
558
+ Clock::duration prev_round_min_rtt_{};
559
+ int round_samples_ = 0;
560
+ /// Highest sequence number outstanding when this round began; the round ends
561
+ /// when the cumulative acknowledgement reaches it.
562
+ uint32_t round_end_ = 0;
563
+
564
+ // — receive side —
565
+ ReceiveBuffer inbox_; ///< in-order bytes awaiting read()
566
+ std::unordered_map<uint32_t, InPacket> reorder_; ///< packets past a gap
567
+ uint32_t recv_next_ = 1; ///< next sequence number expected
568
+ bool need_ack_ = false;
569
+ int unacked_packets_ = 0;
570
+ /// Announcements left of a receive window that has just re-opened, and when the
571
+ /// next one is due (the epoch = at once). Zero means there is nothing to
572
+ /// announce, which is what arms this: the peer is stopped and sends nothing for
573
+ /// an update to ride on, so this is the only clock either side has for it.
574
+ int window_announces_ = 0;
575
+ Clock::time_point window_due_{};
576
+ /// Cached selective-ack bitmap, rebuilt only when the reorder buffer or the
577
+ /// expected sequence number moves. Every outgoing packet carries this field,
578
+ /// so deriving it from 32 hash lookups per *packet* — during loss recovery,
579
+ /// when packets are at their most frequent — was pure repeated work: it can
580
+ /// only change when one of the two things it is derived from changes.
581
+ mutable uint32_t sack_bits_ = 0;
582
+ mutable bool sack_dirty_ = false;
583
+
584
+ // — timing —
585
+ Clock::duration srtt_{};
586
+ Clock::duration rttvar_{};
587
+ bool have_rtt_ = false;
588
+ Clock::duration rto_ = kInitialRto;
589
+ // How the dial (and only the dial) is retried — see DialProfile. Kept as plain
590
+ // members rather than a stored profile so the SynSent path costs no indirection,
591
+ // and clamped in the constructor so a caller cannot ask for zero attempts or an
592
+ // interval outside what the timer can honour.
593
+ int syn_attempts_ = kSynMaxAttempts;
594
+ bool syn_backoff_ = true;
595
+ Clock::time_point last_recv_;
596
+ Clock::time_point last_send_;
597
+ /// When an owed acknowledgement must go out. The epoch means "no deadline",
598
+ /// which with need_ack_ set is not "never" but "at once": read() leaves it that
599
+ /// way to ask for a window update, because a peer stopped on a zero window sends
600
+ /// nothing for the ack to ride on. Every other owed ack arms a real deadline.
601
+ Clock::time_point ack_due_{};
602
+ /// When the retransmission timeout fires (epoch = the timer is not running).
603
+ ///
604
+ /// One deadline for the stream, not one per packet — RFC 6298's model. It is
605
+ /// started by a transmission that finds it idle, restarted whenever an
606
+ /// acknowledgement covers new data, and turned off once nothing is outstanding.
607
+ /// Deriving it instead from `sent_.front().sent_at` (the obvious shortcut) is
608
+ /// wrong after a timeout: the packets behind the one that was resent still
609
+ /// carry their original timestamps, so every one of them looks instantly
610
+ /// overdue and the window is driven back to the floor on every tick.
611
+ Clock::time_point rto_deadline_{};
612
+ };
613
+
614
+ } // namespace librats