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,103 @@
1
+ #include "librats/dht/dht_runner.h"
2
+ #include "librats/dht/node.h"
3
+ #include "librats/dht/udp_transport.h"
4
+ #include "librats/dht/log.h"
5
+
6
+ #include <chrono>
7
+ #include <utility>
8
+
9
+ namespace librats {
10
+ namespace dht {
11
+
12
+ namespace {
13
+ constexpr int kRecvTimeoutMs = 100; // loop responsiveness
14
+ constexpr std::chrono::milliseconds kTickInterval{1000}; // Node maintenance cadence
15
+ }
16
+
17
+ DhtRunner::DhtRunner(Node& node, UdpTransport& transport)
18
+ : node_(node), transport_(transport) {}
19
+
20
+ DhtRunner::~DhtRunner() {
21
+ stop();
22
+ }
23
+
24
+ void DhtRunner::start(std::function<void()> on_loop_entry) {
25
+ if (running_.exchange(true)) return;
26
+ thread_ = std::thread([this, on_loop_entry = std::move(on_loop_entry)] {
27
+ if (on_loop_entry) on_loop_entry();
28
+ loop();
29
+ });
30
+ }
31
+
32
+ void DhtRunner::stop() {
33
+ // Flip the flag under the queue mutex, so post() can never slip a task past a
34
+ // concurrent stop() and leave it queued to a loop that is already gone.
35
+ {
36
+ std::lock_guard<std::mutex> lock(mutex_);
37
+ if (!running_.exchange(false)) return;
38
+ }
39
+ wakeup_.signal(); // wake the loop now instead of waiting out the recv timeout
40
+ if (thread_.joinable()) thread_.join();
41
+ }
42
+
43
+ bool DhtRunner::post(std::function<void()> task) {
44
+ {
45
+ std::lock_guard<std::mutex> lock(mutex_);
46
+ // Refuse once stopped: no one is left to drain the queue.
47
+ if (!running_.load()) return false;
48
+ tasks_.push_back(std::move(task));
49
+ }
50
+ // The task is queued before we signal, so whenever a wakeup byte exists the task is
51
+ // already visible to drain_tasks() — the loop can never block past a pending task.
52
+ wakeup_.signal();
53
+ return true;
54
+ }
55
+
56
+ void DhtRunner::set_periodic(std::chrono::milliseconds interval, std::function<void()> fn) {
57
+ periodic_interval_ = interval;
58
+ periodic_fn_ = std::move(fn);
59
+ }
60
+
61
+ void DhtRunner::loop() {
62
+ const auto start = std::chrono::steady_clock::now();
63
+ auto last_tick = start;
64
+ auto last_periodic = start; // first periodic fires one full interval in, not at t=0
65
+ while (running_.load()) {
66
+ Address from;
67
+ // recv() returns early (as nullopt) the moment post()/stop() signals the wakeup
68
+ // pipe, so a posted task runs without waiting out kRecvTimeoutMs.
69
+ auto data = transport_.recv(kRecvTimeoutMs, from, wakeup_.fd());
70
+ const auto now = std::chrono::steady_clock::now();
71
+
72
+ // Consume the wakeup byte(s) before processing, so the next recv() blocks again.
73
+ // Draining here (not after drain_tasks) means any task posted during processing
74
+ // leaves an un-drained byte that wakes the following recv() — no lost wakeups.
75
+ wakeup_.drain();
76
+
77
+ if (data) node_.on_datagram(*data, from, now);
78
+
79
+ drain_tasks();
80
+
81
+ if (now - last_tick >= kTickInterval) {
82
+ node_.tick(now);
83
+ last_tick = now;
84
+ }
85
+
86
+ if (periodic_fn_ && periodic_interval_.count() > 0 && now - last_periodic >= periodic_interval_) {
87
+ periodic_fn_();
88
+ last_periodic = now;
89
+ }
90
+ }
91
+ }
92
+
93
+ void DhtRunner::drain_tasks() {
94
+ std::vector<std::function<void()>> pending;
95
+ {
96
+ std::lock_guard<std::mutex> lock(mutex_);
97
+ pending.swap(tasks_);
98
+ }
99
+ for (auto& task : pending) task();
100
+ }
101
+
102
+ } // namespace dht
103
+ } // namespace librats
@@ -0,0 +1,71 @@
1
+ #pragma once
2
+
3
+ /**
4
+ * @file dht_runner.h
5
+ * @brief The single thread that drives a dht::Node over a real socket.
6
+ *
7
+ * This is where real time and threading enter the otherwise pure, single-threaded
8
+ * Node. The loop pumps incoming datagrams into Node::on_datagram, runs Node::tick on
9
+ * a fixed cadence, and executes tasks posted from other threads — all on this one
10
+ * thread, so the Node itself never needs a lock. External callers must reach the Node
11
+ * through post() rather than touching it directly.
12
+ */
13
+
14
+ #include "librats/core/wakeup_pipe.h"
15
+
16
+ #include <atomic>
17
+ #include <chrono>
18
+ #include <functional>
19
+ #include <mutex>
20
+ #include <thread>
21
+ #include <vector>
22
+
23
+ namespace librats {
24
+ namespace dht {
25
+
26
+ class Node;
27
+ class UdpTransport;
28
+
29
+ class DhtRunner {
30
+ public:
31
+ DhtRunner(Node& node, UdpTransport& transport);
32
+ ~DhtRunner();
33
+
34
+ DhtRunner(const DhtRunner&) = delete;
35
+ DhtRunner& operator=(const DhtRunner&) = delete;
36
+
37
+ // `on_loop_entry`, if given, runs on the loop thread before anything else does —
38
+ // the hook for marking that thread as such (see DhtClient), so even the very first
39
+ // callback it runs is already recognisable.
40
+ void start(std::function<void()> on_loop_entry = {});
41
+ void stop();
42
+
43
+ // Run `task` on the loop thread. The only safe way to touch the Node from outside.
44
+ // Returns false (dropping the task) once the runner is stopped: nothing would ever
45
+ // run it, so a caller must not be left believing it was queued.
46
+ bool post(std::function<void()> task);
47
+
48
+ // Register a callback invoked on the loop thread every `interval` (e.g. persisting
49
+ // the routing table). The first invocation is one interval after start(), never at
50
+ // t=0. Must be set before start(); call with a null fn to disable. The runner stays
51
+ // oblivious to what the work is — the I/O concern lives in the caller.
52
+ void set_periodic(std::chrono::milliseconds interval, std::function<void()> fn);
53
+
54
+ private:
55
+ void loop();
56
+ void drain_tasks();
57
+
58
+ Node& node_;
59
+ UdpTransport& transport_;
60
+ std::thread thread_;
61
+ std::atomic<bool> running_{false};
62
+ std::mutex mutex_;
63
+ std::vector<std::function<void()>> tasks_;
64
+ WakeupPipe wakeup_; // lets post()/stop() interrupt the recv() wait immediately
65
+
66
+ std::chrono::milliseconds periodic_interval_{0}; // 0 = disabled
67
+ std::function<void()> periodic_fn_;
68
+ };
69
+
70
+ } // namespace dht
71
+ } // namespace librats
@@ -0,0 +1,42 @@
1
+ #include "librats/dht/dos_blocker.h"
2
+ #include "librats/dht/log.h"
3
+
4
+ namespace librats {
5
+ namespace dht {
6
+
7
+ bool DosBlocker::allow(const IpAddress& ip, TimePoint now) {
8
+ Entry& e = table_[ip];
9
+
10
+ if (e.banned_until > now) return false; // still serving a ban
11
+
12
+ if (now - e.window_start >= kWindow) { // start of a fresh window
13
+ e.window_start = now;
14
+ e.count = 0;
15
+ }
16
+
17
+ if (++e.count > kMaxPerWindow) {
18
+ e.banned_until = now + kBanDuration;
19
+ // Logged once at the ban transition only — the top-of-function early return keeps
20
+ // every subsequent packet from this IP from re-logging. DEBUG (not WARN) on purpose:
21
+ // a spoofed-source flood could otherwise turn one ban per IP into log amplification.
22
+ LOG_DEBUG("dht", "rate-limit ban: " << ip.to_string() << " (" << e.count << " queries in window)");
23
+ return false;
24
+ }
25
+
26
+ if (table_.size() > kMaxTracked) prune(now);
27
+ return true;
28
+ }
29
+
30
+ void DosBlocker::prune(TimePoint now) {
31
+ // Drop idle, unbanned entries; they carry no state worth keeping.
32
+ for (auto it = table_.begin(); it != table_.end();) {
33
+ const Entry& e = it->second;
34
+ if (e.banned_until <= now && now - e.window_start >= kWindow)
35
+ it = table_.erase(it);
36
+ else
37
+ ++it;
38
+ }
39
+ }
40
+
41
+ } // namespace dht
42
+ } // namespace librats
@@ -0,0 +1,47 @@
1
+ #pragma once
2
+
3
+ /**
4
+ * @file dos_blocker.h
5
+ * @brief Per-IP flood protection for the DHT's incoming path.
6
+ *
7
+ * A peer is allowed a burst of packets per short window; cross the threshold and it's
8
+ * banned for a while. Cheap and bounded — a single counter + two timestamps per IP,
9
+ * with the tracking table capped. Consulted before any incoming packet is processed.
10
+ */
11
+
12
+ #include "librats/core/ip_address.h"
13
+ #include "librats/dht/observer.h" // for TimePoint
14
+
15
+ #include <chrono>
16
+ #include <cstddef>
17
+ #include <unordered_map>
18
+
19
+ namespace librats {
20
+ namespace dht {
21
+
22
+ class DosBlocker {
23
+ public:
24
+ static constexpr int kMaxPerWindow = 50; // packets per window before a ban
25
+ static constexpr std::chrono::seconds kWindow{10};
26
+ static constexpr std::chrono::minutes kBanDuration{5};
27
+ static constexpr std::size_t kMaxTracked = 2000; // cap the per-IP table
28
+
29
+ // True if a packet from `ip` should be processed; false if it's being rate-limited.
30
+ bool allow(const IpAddress& ip, TimePoint now);
31
+
32
+ std::size_t tracked() const noexcept { return table_.size(); }
33
+
34
+ private:
35
+ struct Entry {
36
+ int count = 0;
37
+ TimePoint window_start{};
38
+ TimePoint banned_until{};
39
+ };
40
+
41
+ void prune(TimePoint now);
42
+
43
+ std::unordered_map<IpAddress, Entry> table_;
44
+ };
45
+
46
+ } // namespace dht
47
+ } // namespace librats
@@ -0,0 +1,52 @@
1
+ #include "librats/dht/find_peers.h"
2
+ #include "librats/dht/krpc.h"
3
+
4
+ #include <algorithm>
5
+ #include <utility>
6
+
7
+ namespace librats {
8
+ namespace dht {
9
+
10
+ FindPeers::FindPeers(RoutingTable& table, RpcManager& rpc, const NodeId& self,
11
+ const InfoHash& info_hash, PeersCallback on_peers, DoneCallback on_done)
12
+ : Traversal(table, rpc, self, info_hash),
13
+ on_peers_(std::move(on_peers)),
14
+ on_done_(std::move(on_done)) {}
15
+
16
+ void FindPeers::got_peers(const std::vector<Address>& peers) {
17
+ std::vector<Address> fresh;
18
+ for (const auto& p : peers) {
19
+ if (std::find(peers_.begin(), peers_.end(), p) == peers_.end()) {
20
+ peers_.push_back(p);
21
+ fresh.push_back(p);
22
+ }
23
+ }
24
+ if (!fresh.empty() && on_peers_) on_peers_(fresh);
25
+ }
26
+
27
+ void FindPeers::got_token(const NodeId& id, const std::string& token) {
28
+ if (token.empty()) return;
29
+ tokens_.emplace(id, token); // first token from a node wins
30
+ }
31
+
32
+ bool FindPeers::invoke(const ObserverPtr& o, TimePoint now) {
33
+ KrpcMessage msg = KrpcProtocol::create_get_peers_query(/*txn set by rpc*/ "", self_, target());
34
+ msg.want = want_; // BEP 32: ask for our own family's nodes
35
+ return rpc_.invoke(msg, o->endpoint(), o, now);
36
+ }
37
+
38
+ ObserverPtr FindPeers::make_observer(const NodeId& id, const Address& ep) {
39
+ return std::make_shared<FindPeersObserver>(*this, id, ep);
40
+ }
41
+
42
+ void FindPeers::on_complete() {
43
+ if (on_done_) on_done_(peers_);
44
+ }
45
+
46
+ void FindPeersObserver::parse_reply(const KrpcMessage& msg) {
47
+ if (!msg.token.empty()) owner_.got_token(msg.response_id, msg.token);
48
+ if (!msg.peers.empty()) owner_.got_peers(msg.peers);
49
+ }
50
+
51
+ } // namespace dht
52
+ } // namespace librats
@@ -0,0 +1,73 @@
1
+ #pragma once
2
+
3
+ /**
4
+ * @file find_peers.h
5
+ * @brief get_peers lookup: find the peers announced under an info-hash (BEP 5).
6
+ *
7
+ * An iterative lookup toward the info-hash. Along the way it collects peer
8
+ * endpoints from "values" replies (delivered incrementally, then once more in full
9
+ * on completion) and the write tokens nodes hand out — the tokens are what an
10
+ * announce needs, so Announce builds directly on this.
11
+ */
12
+
13
+ #include "librats/dht/id.h"
14
+ #include "librats/dht/observer.h"
15
+ #include "librats/dht/traversal.h"
16
+
17
+ #include <functional>
18
+ #include <map>
19
+ #include <string>
20
+ #include <vector>
21
+
22
+ namespace librats {
23
+ struct KrpcMessage;
24
+
25
+ namespace dht {
26
+
27
+ class FindPeers : public Traversal {
28
+ public:
29
+ // Called with each batch of newly-discovered peers as the lookup runs.
30
+ using PeersCallback = std::function<void(const std::vector<Address>&)>;
31
+ // Called once when the lookup converges, with every peer found.
32
+ using DoneCallback = std::function<void(const std::vector<Address>&)>;
33
+
34
+ FindPeers(RoutingTable& table, RpcManager& rpc, const NodeId& self, const InfoHash& info_hash,
35
+ PeersCallback on_peers, DoneCallback on_done);
36
+
37
+ void got_peers(const std::vector<Address>& peers); // from a values reply
38
+ void got_token(const NodeId& id, const std::string& token); // from a node's reply
39
+
40
+ // BEP 32: which node families to ask for ("n4" / "n6"). Empty = unspecified.
41
+ void set_want(std::vector<std::string> want) { want_ = std::move(want); }
42
+
43
+ protected:
44
+ bool invoke(const ObserverPtr& o, TimePoint now) override;
45
+ ObserverPtr make_observer(const NodeId& id, const Address& ep) override;
46
+ void on_complete() override;
47
+ const char* name() const override { return "find_peers"; }
48
+
49
+ // The write token each responding node gave us, keyed by node id (Announce reads
50
+ // this). std::map avoids needing a NodeId hash; the map only ever holds ~k entries.
51
+ std::map<NodeId, std::string> tokens_;
52
+
53
+ private:
54
+ PeersCallback on_peers_;
55
+ DoneCallback on_done_;
56
+ std::vector<Address> peers_; // all unique peers found
57
+ std::vector<std::string> want_; // BEP 32 family hint for our queries
58
+ };
59
+
60
+ class FindPeersObserver : public TraversalObserver {
61
+ public:
62
+ FindPeersObserver(FindPeers& owner, const NodeId& id, const Address& ep)
63
+ : TraversalObserver(owner, id, ep), owner_(owner) {}
64
+
65
+ protected:
66
+ void parse_reply(const KrpcMessage& msg) override;
67
+
68
+ private:
69
+ FindPeers& owner_;
70
+ };
71
+
72
+ } // namespace dht
73
+ } // namespace librats
@@ -0,0 +1,167 @@
1
+ #pragma once
2
+
3
+ /**
4
+ * @file id.h
5
+ * @brief The 160-bit Kademlia identifier and the pure functions over it.
6
+ *
7
+ * `NodeId` and `InfoHash` share one 160-bit keyspace (BEP 5). Everything here is a
8
+ * header-only, allocation-free leaf primitive — XOR distance, closeness ordering,
9
+ * k-bucket placement, and hex/wire conversions — so the comparators used in the
10
+ * routing table and lookup hot paths can be inlined.
11
+ */
12
+
13
+ #include <algorithm>
14
+ #include <array>
15
+ #include <cstddef>
16
+ #include <cstdint>
17
+ #include <cstring>
18
+ #include <string>
19
+
20
+ #if defined(_MSC_VER)
21
+ #include <intrin.h> // _BitScanReverse for count_leading_zeros
22
+ #endif
23
+
24
+ namespace librats {
25
+ namespace dht {
26
+
27
+ // Count leading zero bits of a non-zero 32-bit word. One hardware instruction where
28
+ // available; a portable loop otherwise. Precondition: x != 0.
29
+ inline int count_leading_zeros32(uint32_t x) noexcept {
30
+ #if defined(__GNUC__) || defined(__clang__)
31
+ return __builtin_clz(x);
32
+ #elif defined(_MSC_VER)
33
+ unsigned long idx;
34
+ _BitScanReverse(&idx, x);
35
+ return 31 - static_cast<int>(idx);
36
+ #else
37
+ int n = 0;
38
+ while ((x & 0x80000000u) == 0) { ++n; x <<= 1; }
39
+ return n;
40
+ #endif
41
+ }
42
+
43
+ // 160-bit identifier space shared by node ids and info-hashes (Kademlia / BEP 5).
44
+ inline constexpr std::size_t kIdSize = 20; // 160 bits
45
+ inline constexpr std::size_t kBucketSize = 8; // "k": max contacts kept per bucket
46
+ inline constexpr std::size_t kAlpha = 3; // lookup concurrency (branch factor)
47
+ inline constexpr int kDefaultPort = 6881; // standard BitTorrent DHT port
48
+ inline constexpr int kBucketCount = static_cast<int>(kIdSize) * 8; // 160
49
+
50
+ using NodeId = std::array<uint8_t, kIdSize>;
51
+ using InfoHash = NodeId; // same keyspace, named for intent at call sites
52
+
53
+ // Hash functor for using a NodeId/InfoHash as an unordered_map/set key. A node id is
54
+ // already a uniformly-distributed 160-bit value (a SHA-1 digest or random id), so the
55
+ // fastest sound hash is to reinterpret its leading bytes as size_t — no mixing needed.
56
+ // This mirrors libtorrent's std::hash<digest32<N>> (sha1_hash.hpp). Note: most DHT
57
+ // id-keyed tables (write tokens, the peer store) deliberately stay std::map — they're
58
+ // small/cold and ordered is fine; reach for this only on hot, large id sets.
59
+ struct NodeIdHash {
60
+ std::size_t operator()(const NodeId& id) const noexcept {
61
+ std::size_t h;
62
+ std::memcpy(&h, id.data(), sizeof(h));
63
+ return h;
64
+ }
65
+ };
66
+
67
+ // XOR distance metric d(a, b) = a ^ b (Kademlia).
68
+ inline NodeId distance(const NodeId& a, const NodeId& b) noexcept {
69
+ NodeId d;
70
+ for (std::size_t i = 0; i < kIdSize; ++i) d[i] = a[i] ^ b[i];
71
+ return d;
72
+ }
73
+
74
+ // True iff `a` is strictly closer to `target` than `b` under the XOR metric.
75
+ // Compares a^target against b^target as 160-bit big-endian numbers without
76
+ // materialising either distance — this is the lookup/sort comparator.
77
+ inline bool closer_to(const NodeId& a, const NodeId& b, const NodeId& target) noexcept {
78
+ for (std::size_t i = 0; i < kIdSize; ++i) {
79
+ const uint8_t da = a[i] ^ target[i];
80
+ const uint8_t db = b[i] ^ target[i];
81
+ if (da != db) return da < db;
82
+ }
83
+ return false; // equal distance is not "strictly closer"
84
+ }
85
+
86
+ // Number of leading bits `a` and `b` share — equivalently, the count of leading
87
+ // zeros of (a ^ b). 0 means they differ in the very first bit (farthest apart);
88
+ // kBucketCount (160) is returned only when the ids are identical. This is the raw
89
+ // keyspace primitive; the routing table caps it to its current bucket count to get
90
+ // an actual bucket index (RoutingTable::bucket_index).
91
+ inline int shared_prefix_bits(const NodeId& a, const NodeId& b) noexcept {
92
+ // Process the 160 bits four bytes at a time (kIdSize == 20 == 5 words). Each word
93
+ // is assembled big-endian so its most significant bit is the earliest id bit, then
94
+ // a single count-leading-zeros pins the first differing bit. Bit-identical to the
95
+ // byte-at-a-time form, ~4x faster: the common case is one word load + one CLZ.
96
+ for (std::size_t i = 0; i < kIdSize; i += 4) {
97
+ const uint32_t d = (static_cast<uint32_t>(a[i] ^ b[i]) << 24)
98
+ | (static_cast<uint32_t>(a[i + 1] ^ b[i + 1]) << 16)
99
+ | (static_cast<uint32_t>(a[i + 2] ^ b[i + 2]) << 8)
100
+ | static_cast<uint32_t>(a[i + 3] ^ b[i + 3]);
101
+ if (d != 0) return static_cast<int>(i) * 8 + count_leading_zeros32(d);
102
+ }
103
+ return kBucketCount; // identical ids share the whole 160-bit prefix
104
+ }
105
+
106
+ // Read `n` bits from `id` starting at bit index `start` (MSB-first: bit 0 is the top
107
+ // bit of id[0]), returned right-aligned. Bits past the end of the id read as 0. Used
108
+ // to classify a node by the handful of sub-prefix bits that follow a bucket's shared
109
+ // prefix, so `n` is always small (<= 7).
110
+ inline uint32_t bits_at(const NodeId& id, int start, int n) noexcept {
111
+ uint32_t v = 0;
112
+ for (int k = 0; k < n; ++k) {
113
+ const int bit = start + k;
114
+ const int b = (bit >= 0 && bit < kBucketCount)
115
+ ? ((id[bit >> 3] >> (7 - (bit & 7))) & 1)
116
+ : 0;
117
+ v = (v << 1) | static_cast<uint32_t>(b);
118
+ }
119
+ return v;
120
+ }
121
+
122
+ // Lowercase 40-char hex. to_hex / from_hex are exact inverses for valid input.
123
+ inline std::string to_hex(const NodeId& id) {
124
+ static constexpr char kDigits[] = "0123456789abcdef";
125
+ std::string out(kIdSize * 2, '0');
126
+ for (std::size_t i = 0; i < kIdSize; ++i) {
127
+ out[i * 2] = kDigits[id[i] >> 4];
128
+ out[i * 2 + 1] = kDigits[id[i] & 0x0f];
129
+ }
130
+ return out;
131
+ }
132
+
133
+ // Parse 40 hex chars. Returns a zero-filled id if the input isn't exactly 40 valid
134
+ // hex characters, so a malformed string can never be mistaken for a real id.
135
+ inline NodeId from_hex(const std::string& hex) {
136
+ NodeId id{};
137
+ if (hex.size() != kIdSize * 2) return id;
138
+ const auto nibble = [](char c) -> int {
139
+ if (c >= '0' && c <= '9') return c - '0';
140
+ if (c >= 'a' && c <= 'f') return c - 'a' + 10;
141
+ if (c >= 'A' && c <= 'F') return c - 'A' + 10;
142
+ return -1;
143
+ };
144
+ for (std::size_t i = 0; i < kIdSize; ++i) {
145
+ const int hi = nibble(hex[i * 2]);
146
+ const int lo = nibble(hex[i * 2 + 1]);
147
+ if (hi < 0 || lo < 0) return NodeId{};
148
+ id[i] = static_cast<uint8_t>((hi << 4) | lo);
149
+ }
150
+ return id;
151
+ }
152
+
153
+ // Raw 20-byte wire form, as carried in KRPC messages. Inverses of each other.
154
+ inline std::string to_bytes(const NodeId& id) {
155
+ return std::string(reinterpret_cast<const char*>(id.data()), kIdSize);
156
+ }
157
+
158
+ // Returns a zero-filled id if `bytes` isn't exactly 20 bytes.
159
+ inline NodeId from_bytes(const std::string& bytes) {
160
+ NodeId id{};
161
+ if (bytes.size() != kIdSize) return id;
162
+ std::copy(bytes.begin(), bytes.end(), id.begin());
163
+ return id;
164
+ }
165
+
166
+ } // namespace dht
167
+ } // namespace librats