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,183 @@
1
+ #pragma once
2
+
3
+ /**
4
+ * @file chained_send_buffer.h
5
+ * @brief Outbound byte queue: a chain of heap chunks drained with gather I/O.
6
+ *
7
+ * A socket accepts what it accepts; whatever is left over has to wait for the next
8
+ * writable event. Rather than keeping that backlog in one contiguous buffer (where
9
+ * every partial write costs an O(n) erase of the sent prefix, and every message
10
+ * costs a copy into it), the queue is a chain of chunks:
11
+ *
12
+ * chunks_: [ sent | pending ] → [ pending ] → [ pending ]
13
+ * ^ head_.sent
14
+ *
15
+ * - pop_front() after a send just advances a cursor and drops whole chunks: O(1)
16
+ * amortised, no memmove.
17
+ * - append(Bytes) takes ownership of a buffer someone else already built, so a
18
+ * message the caller allocated (an encrypted frame, a piece read from disk) is
19
+ * never copied.
20
+ * - gather() exposes the chain as a slice list for writev()/WSASend(), so a
21
+ * backlog of N queued messages leaves in ONE syscall instead of N.
22
+ *
23
+ * Three things keep small messages cheap, since a chunk-per-message would otherwise
24
+ * mean a malloc per 5-byte keep-alive:
25
+ * - copy-appends are packed into the spare capacity of the tail chunk
26
+ * (libtorrent's allocate_appendix), so a burst of small messages costs one
27
+ * allocation, not one per message;
28
+ * - the last fully-sent small chunk is kept and re-used, so a steady drip of
29
+ * small messages settles into allocating nothing at all;
30
+ * - the chain itself is a std::vector + a head index, not a std::deque. A deque
31
+ * allocates a fresh block every `block_size/sizeof(Chunk)` push_backs (libstdc++:
32
+ * one per 16 chunks; MSVC: one per *chunk*, since its block holds a single
33
+ * element for any type over 8 bytes) — so the recycled chunk above would hand
34
+ * back the payload buffer while the queue kept mallocing the slot to put it in.
35
+ * A vector amortises the slots away entirely, and re-uses its storage across
36
+ * drains.
37
+ *
38
+ * Memory is accounted two ways: size() is what still has to go out, while
39
+ * allocated() is what the chain actually holds — larger, because a partially sent
40
+ * chunk keeps its whole allocation and a packed chunk keeps its spare room. A
41
+ * send high-water mark should watch allocated(): that is the memory a peer who
42
+ * stops reading can make us carry.
43
+ *
44
+ * Not thread-safe: owned and touched by exactly one reactor thread.
45
+ *
46
+ * Usage:
47
+ * buf.append(std::move(frame)); // queue, no copy
48
+ * ByteView slices[kMaxSendSlices];
49
+ * const size_t n = buf.gather(slices, kMaxSendSlices);
50
+ * const auto sent = send_vectored(sock, slices, n); // one syscall
51
+ * if (sent > 0) buf.pop_front(size_t(sent)); // O(1)
52
+ */
53
+
54
+ #include "librats/util/rats_export.h"
55
+ #include "librats/core/bytes.h"
56
+
57
+ #include <cstddef>
58
+ #include <cstdint>
59
+ #include <type_traits>
60
+ #include <utility>
61
+ #include <vector>
62
+
63
+ namespace librats {
64
+
65
+ class RATS_API ChainedSendBuffer {
66
+ public:
67
+ /// Capacity of a chunk opened for a small copy-append. Sized so a run of
68
+ /// protocol chatter (keep-alives, HAVEs, REQUESTs, ACKs) packs into one.
69
+ static constexpr size_t kScratchCapacity = 1024;
70
+
71
+ /// Chunks up to this size are kept for re-use when they drain; larger ones
72
+ /// (payload buffers) are released, so the queue never squats on real memory.
73
+ static constexpr size_t kMaxRecycledCapacity = 4 * 1024;
74
+
75
+ ChainedSendBuffer() = default;
76
+
77
+ /// Moving leaves the source empty. A defaulted move would carry pending_ and
78
+ /// allocated_ over to a source whose chunks_ had been emptied, leaving it claiming
79
+ /// bytes it no longer holds (empty() false, front() empty — a flush() that never
80
+ /// finishes).
81
+ ChainedSendBuffer(ChainedSendBuffer&& other) noexcept { *this = std::move(other); }
82
+ ChainedSendBuffer& operator=(ChainedSendBuffer&& other) noexcept;
83
+ ChainedSendBuffer(const ChainedSendBuffer&) = delete;
84
+ ChainedSendBuffer& operator=(const ChainedSendBuffer&) = delete;
85
+
86
+ // ── Queueing ────────────────────────────────────────────────────────────
87
+
88
+ /// Queue `data`, taking ownership — the bytes are never copied. Prefer this for
89
+ /// anything the caller already had to allocate (a framed message, disk block…).
90
+ void append(Bytes data);
91
+
92
+ /// Queue a copy of `bytes`. Small copies land in the tail chunk's spare capacity
93
+ /// when they fit, so headers and short control messages don't each cost a malloc.
94
+ void append(ByteView bytes);
95
+
96
+ // ── Draining ────────────────────────────────────────────────────────────
97
+
98
+ /// Bytes gather() will describe in one go unless told otherwise. A socket accepts
99
+ /// what fits in its send buffer — a few hundred KiB at most — and every slice past
100
+ /// that is an iovec entry the kernel copies in and then ignores. Under a backlog
101
+ /// (the case gather() exists for) the flush loop re-gathers after every partial
102
+ /// write, so that waste is paid on every syscall, not once. libtorrent bounds its
103
+ /// build_iovec() by a byte quota for the same reason.
104
+ static constexpr size_t kMaxGatherBytes = 1024 * 1024;
105
+
106
+ /// Fill `out` with up to `max_slices` contiguous runs covering the front of the
107
+ /// queue, in order, stopping once they cover `max_bytes` (the slice that crosses
108
+ /// the limit is still included whole, so a single chunk larger than the limit is
109
+ /// described rather than dropped). Returns the number of slices written. The views
110
+ /// stay valid until the next pop_front()/clear() — append() never invalidates them,
111
+ /// because a slice points at a chunk's *heap buffer*, which a vector growth moves
112
+ /// the owning Chunk around but never reallocates.
113
+ size_t gather(ByteView* out, size_t max_slices, size_t max_bytes = kMaxGatherBytes) const;
114
+
115
+ /// The first contiguous run — the single-slice form of gather(), for a plain
116
+ /// send(). Empty when the queue is empty.
117
+ ByteView front() const noexcept;
118
+
119
+ /// Drop `bytes` from the front after a successful send. Must not exceed size().
120
+ void pop_front(size_t bytes);
121
+
122
+ // ── State ───────────────────────────────────────────────────────────────
123
+
124
+ bool empty() const noexcept { return pending_ == 0; }
125
+ /// Bytes still waiting to go out — what a send high-water mark should watch.
126
+ size_t size() const noexcept { return pending_; }
127
+ /// Heap actually held by the chain: pending bytes, the already-sent prefix of a
128
+ /// partially sent chunk, spare capacity, and the recycled chunk.
129
+ size_t allocated() const noexcept { return allocated_ + recycled_.capacity(); }
130
+ size_t chunk_count() const noexcept { return chunks_.size() - head_; }
131
+
132
+ /// Drop everything and release all chunks.
133
+ void clear() noexcept;
134
+
135
+ private:
136
+ struct Chunk {
137
+ Bytes data;
138
+ size_t sent = 0; ///< bytes of `data` already handed to the socket
139
+
140
+ size_t remaining() const noexcept { return data.size() - sent; }
141
+ const uint8_t* head() const noexcept { return data.data() + sent; }
142
+ };
143
+
144
+ // A gather() slice points into a chunk's heap buffer, and append() may grow
145
+ // chunks_ while those slices are outstanding. That is only safe because a vector
146
+ // growth *moves* each Chunk — carrying the heap buffer's address across untouched.
147
+ // Were the move throwing, vector would fall back to copying: every chunk would get
148
+ // a fresh buffer, the originals would be freed, and every outstanding slice would
149
+ // dangle. The guarantee is load-bearing, so assert it rather than assume it.
150
+ static_assert(std::is_nothrow_move_constructible<Chunk>::value,
151
+ "Chunk must move on vector growth, or gather()'s slices would dangle");
152
+
153
+ /// The tail chunk if `bytes` fit in its spare capacity (so appending to it
154
+ /// cannot reallocate, and therefore cannot invalidate outstanding slices).
155
+ Bytes* coalescable_tail(size_t bytes) noexcept;
156
+
157
+ /// A chunk with at least `bytes` of capacity: the recycled one if it fits,
158
+ /// otherwise a fresh allocation.
159
+ Bytes take_chunk(size_t bytes);
160
+
161
+ /// Offer a drained chunk back for re-use.
162
+ void recycle(Bytes&& chunk) noexcept;
163
+
164
+ /// Drop the drained prefix of `chunks_` so the vector cannot creep forever under a
165
+ /// backlog that never fully empties. Amortised O(1): only ever runs when at least
166
+ /// half the vector is dead.
167
+ void reclaim_drained_slots();
168
+
169
+ /// Slots kept across a full drain. Above this the vector hands the memory back —
170
+ /// an 8 MiB backlog of 1 KiB chunks would otherwise leave 8192 slots resident.
171
+ static constexpr size_t kMaxRetainedSlots = 64;
172
+
173
+ /// Live chunks are `chunks_[head_ .. end)`. A vector + head index rather than a
174
+ /// deque: see the header comment — a deque mallocs a block per N chunks (N == 1 on
175
+ /// MSVC), which is exactly the allocation `recycled_` exists to avoid.
176
+ std::vector<Chunk> chunks_;
177
+ size_t head_ = 0; ///< index of the first live chunk
178
+ size_t pending_ = 0; ///< sum of remaining() over the live chunks
179
+ size_t allocated_ = 0; ///< sum of data.capacity() over the live chunks
180
+ Bytes recycled_; ///< one drained small chunk, kept for re-use
181
+ };
182
+
183
+ } // namespace librats
@@ -0,0 +1,41 @@
1
+ #include "librats/core/endpoint_parse.h"
2
+
3
+ namespace librats {
4
+
5
+ std::optional<uint16_t> parse_port(std::string_view text) {
6
+ if (text.empty()) return std::nullopt;
7
+ unsigned long port = 0;
8
+ for (char c : text) {
9
+ if (c < '0' || c > '9') return std::nullopt;
10
+ port = port * 10 + static_cast<unsigned>(c - '0');
11
+ if (port > 65535) return std::nullopt;
12
+ }
13
+ if (port == 0) return std::nullopt;
14
+ return static_cast<uint16_t>(port);
15
+ }
16
+
17
+ std::optional<std::pair<std::string_view, uint16_t>> split_host_port(std::string_view text) {
18
+ if (!text.empty() && text.front() == '[') {
19
+ // Bracketed IPv6: [ip]:port
20
+ const auto close = text.find(']');
21
+ if (close == std::string_view::npos || close + 1 >= text.size() || text[close + 1] != ':')
22
+ return std::nullopt;
23
+ const auto host = text.substr(1, close - 1);
24
+ if (host.empty()) return std::nullopt;
25
+ const auto port = parse_port(text.substr(close + 2));
26
+ if (!port) return std::nullopt;
27
+ return std::make_pair(host, *port);
28
+ }
29
+ const auto colon = text.rfind(':');
30
+ if (colon == std::string_view::npos || colon == 0 || colon + 1 == text.size())
31
+ return std::nullopt;
32
+ const auto host = text.substr(0, colon);
33
+ // A bare IPv6 literal carries its own colons; without brackets the port is
34
+ // ambiguous, so reject it rather than guess.
35
+ if (host.find(':') != std::string_view::npos) return std::nullopt;
36
+ const auto port = parse_port(text.substr(colon + 1));
37
+ if (!port) return std::nullopt;
38
+ return std::make_pair(host, *port);
39
+ }
40
+
41
+ } // namespace librats
@@ -0,0 +1,31 @@
1
+ #pragma once
2
+
3
+ /**
4
+ * @file endpoint_parse.h
5
+ * @brief Shared textual "host:port" parsing for Address and HostEndpoint.
6
+ *
7
+ * Both the numeric Address and the unresolved HostEndpoint accept exactly the same
8
+ * surface syntax — "host:port" or bracketed "[ipv6]:port" — and reject the same
9
+ * malformed inputs (missing/invalid port, empty host, a bare unbracketed IPv6 whose
10
+ * own colons make the port ambiguous). The only difference is what each does with
11
+ * the host afterwards (parse it as a numeric literal vs. keep it verbatim), so the
12
+ * structural split lives here once instead of being copy-pasted into each parse().
13
+ */
14
+
15
+ #include <cstdint>
16
+ #include <optional>
17
+ #include <string_view>
18
+ #include <utility>
19
+
20
+ namespace librats {
21
+
22
+ /// Parse a 1..65535 decimal port. nullopt on empty/non-digit/out-of-range/zero.
23
+ std::optional<uint16_t> parse_port(std::string_view text);
24
+
25
+ /// Split "host:port" or "[ipv6]:port" into (host, port). Returns nullopt for a
26
+ /// missing/invalid port, an empty host, or a bare (unbracketed) IPv6 literal whose
27
+ /// colons make the port ambiguous. The returned host view points into `text` and is
28
+ /// valid for its lifetime (brackets, if any, are stripped).
29
+ std::optional<std::pair<std::string_view, uint16_t>> split_host_port(std::string_view text);
30
+
31
+ } // namespace librats
@@ -0,0 +1,70 @@
1
+ #pragma once
2
+
3
+ /**
4
+ * @file event_bus.h
5
+ * @brief A tiny typed publish/subscribe hub for decoupled module notifications.
6
+ *
7
+ * The "something happened" half of inter-module communication: a publisher emits
8
+ * an event *value* and every subscriber registered for that event type is invoked.
9
+ * The publisher neither knows nor names its subscribers — which is exactly what
10
+ * keeps modules from acquiring direct references to one another (the road back to
11
+ * a god-class). For the "do X / give me Y" half — a targeted call with a return
12
+ * value — use ServiceRegistry instead.
13
+ *
14
+ * An event type is any value type; subscription and dispatch are keyed by it:
15
+ *
16
+ * struct NetworkChanged { std::vector<std::string> addresses; };
17
+ * bus.on<NetworkChanged>([](const NetworkChanged& e){ ... }); // subscribe
18
+ * bus.emit(NetworkChanged{addrs}); // publish → all handlers
19
+ *
20
+ * Threading: handlers run synchronously on the thread that calls emit(). The bus
21
+ * itself is thread-safe (on/emit may be called concurrently), but a handler must
22
+ * not block that thread for long — if emit() is driven from a latency-sensitive
23
+ * thread, offload slow work. emit() snapshots the handler list under the lock and
24
+ * invokes it unlocked, so a handler may itself emit() or on() without deadlocking.
25
+ *
26
+ * Convention: subscribe during a subsystem's attach() (single-threaded, before any
27
+ * reactor runs), the same "configure before start" rule the rest of the node uses.
28
+ */
29
+
30
+ #include <functional>
31
+ #include <mutex>
32
+ #include <typeindex>
33
+ #include <typeinfo>
34
+ #include <unordered_map>
35
+ #include <utility>
36
+ #include <vector>
37
+
38
+ namespace librats {
39
+
40
+ class EventBus {
41
+ public:
42
+ /// Register a handler for events of type E. Additive: multiple handlers may
43
+ /// coexist and all fire (in registration order) for each emitted event.
44
+ template <class E>
45
+ void on(std::function<void(const E&)> handler) {
46
+ std::lock_guard<std::mutex> lock(mutex_);
47
+ handlers_[std::type_index(typeid(E))].push_back(
48
+ [h = std::move(handler)](const void* e) { h(*static_cast<const E*>(e)); });
49
+ }
50
+
51
+ /// Publish an event to every handler registered for its type.
52
+ template <class E>
53
+ void emit(const E& event) {
54
+ std::vector<ErasedHandler> snapshot;
55
+ {
56
+ std::lock_guard<std::mutex> lock(mutex_);
57
+ auto it = handlers_.find(std::type_index(typeid(E)));
58
+ if (it == handlers_.end()) return;
59
+ snapshot = it->second; // copy under lock, then invoke unlocked
60
+ }
61
+ for (auto& h : snapshot) h(&event);
62
+ }
63
+
64
+ private:
65
+ using ErasedHandler = std::function<void(const void*)>;
66
+ std::mutex mutex_;
67
+ std::unordered_map<std::type_index, std::vector<ErasedHandler>> handlers_;
68
+ };
69
+
70
+ } // namespace librats
@@ -0,0 +1,56 @@
1
+ #pragma once
2
+
3
+ /**
4
+ * @file host_endpoint.h
5
+ * @brief An unresolved dial target: a host (name OR literal) plus a port.
6
+ *
7
+ * The textual counterpart to Address. Where Address is a strictly numeric,
8
+ * already-resolved endpoint you can hand to a socket, a HostEndpoint is what a
9
+ * user (or a config file) supplies: "router.bittorrent.com:6881", a STUN server,
10
+ * a tracker host. Its `host` may be a DNS name or an IP literal; it carries no
11
+ * bytes and does nothing but hold the two fields until the resolver turns it into
12
+ * one or more Address at the network boundary.
13
+ *
14
+ * Keeping this separate is deliberate (see CLAUDE.md): it keeps hostnames — and
15
+ * the allocation/ambiguity they bring — out of the hot-path Address, which stays
16
+ * a small trivially-copyable value.
17
+ */
18
+
19
+ #include "librats/core/endpoint_parse.h"
20
+
21
+ #include <cstdint>
22
+ #include <optional>
23
+ #include <string>
24
+ #include <string_view>
25
+ #include <utility>
26
+
27
+ namespace librats {
28
+
29
+ struct HostEndpoint {
30
+ std::string host;
31
+ uint16_t port = 0;
32
+
33
+ HostEndpoint() = default;
34
+ HostEndpoint(std::string host, uint16_t port) : host(std::move(host)), port(port) {}
35
+
36
+ /// Parse "host:port" or "[ipv6]:port". Accepts hostnames and IP literals alike;
37
+ /// only the port is validated here (resolution happens later). Returns nullopt
38
+ /// if the port is missing/invalid or the host is empty.
39
+ static std::optional<HostEndpoint> parse(std::string_view text) {
40
+ const auto hp = split_host_port(text);
41
+ if (!hp) return std::nullopt;
42
+ return HostEndpoint{std::string(hp->first), hp->second};
43
+ }
44
+
45
+ /// Bracket a host that looks like an IPv6 literal (contains ':'), else plain.
46
+ std::string to_string() const {
47
+ if (host.find(':') != std::string::npos)
48
+ return "[" + host + "]:" + std::to_string(port);
49
+ return host + ":" + std::to_string(port);
50
+ }
51
+
52
+ bool operator==(const HostEndpoint& o) const { return port == o.port && host == o.host; }
53
+ bool operator!=(const HostEndpoint& o) const { return !(*this == o); }
54
+ };
55
+
56
+ } // namespace librats