librats 1.0.2 → 2.1.4

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 (313) hide show
  1. package/README.md +137 -332
  2. package/binding.gyp +16 -3
  3. package/lib/index.d.ts +271 -696
  4. package/lib/index.js +383 -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 +396 -179
  8. package/native-src/LICENSE +1 -1
  9. package/native-src/src/librats/bindings/rats.cpp +731 -0
  10. package/native-src/src/librats/bindings/rats.h +352 -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 +42 -0
  73. package/native-src/src/librats/core/types.h +93 -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/config.h +110 -0
  144. package/native-src/src/librats/node/dial_service.h +54 -0
  145. package/native-src/src/librats/node/dialer.cpp +264 -0
  146. package/native-src/src/librats/node/dialer.h +188 -0
  147. package/native-src/src/librats/node/host_events.h +26 -0
  148. package/native-src/src/librats/node/identify.cpp +130 -0
  149. package/native-src/src/librats/node/identify.h +71 -0
  150. package/native-src/src/librats/node/nat_status.cpp +103 -0
  151. package/native-src/src/librats/node/nat_status.h +118 -0
  152. package/native-src/src/librats/node/node.cpp +826 -0
  153. package/native-src/src/librats/node/node.h +333 -0
  154. package/native-src/src/librats/node/node_context.h +33 -0
  155. package/native-src/src/librats/node/peer_network.h +91 -0
  156. package/native-src/src/librats/peer/peer.h +49 -0
  157. package/native-src/src/librats/peer/peer_book.cpp +181 -0
  158. package/native-src/src/librats/peer/peer_book.h +88 -0
  159. package/native-src/src/librats/peer/peer_id.cpp +72 -0
  160. package/native-src/src/librats/peer/peer_id.h +62 -0
  161. package/native-src/src/librats/peer/peer_info.h +37 -0
  162. package/native-src/src/librats/peer/peer_table.cpp +137 -0
  163. package/native-src/src/librats/peer/peer_table.h +148 -0
  164. package/native-src/src/librats/security/handshaker.h +66 -0
  165. package/native-src/src/librats/security/identity.h +43 -0
  166. package/native-src/src/librats/security/noise_security.cpp +122 -0
  167. package/native-src/src/librats/security/noise_security.h +37 -0
  168. package/native-src/src/librats/security/plaintext_security.h +106 -0
  169. package/native-src/src/librats/security/session.h +37 -0
  170. package/native-src/src/{storage.cpp → librats/storage/storage.cpp} +369 -522
  171. package/native-src/src/{storage.h → librats/storage/storage.h} +135 -299
  172. package/native-src/src/librats/subsystems/bittorrent.cpp +211 -0
  173. package/native-src/src/librats/subsystems/bittorrent.h +136 -0
  174. package/native-src/src/librats/subsystems/dht_discovery.cpp +202 -0
  175. package/native-src/src/librats/subsystems/dht_discovery.h +123 -0
  176. package/native-src/src/librats/subsystems/dht_service.h +36 -0
  177. package/native-src/src/librats/subsystems/file_transfer.cpp +972 -0
  178. package/native-src/src/librats/subsystems/file_transfer.h +367 -0
  179. package/native-src/src/librats/subsystems/hole_punch.cpp +532 -0
  180. package/native-src/src/librats/subsystems/hole_punch.h +266 -0
  181. package/native-src/src/librats/subsystems/hole_punch_service.h +38 -0
  182. package/native-src/src/librats/subsystems/mdns_discovery.cpp +66 -0
  183. package/native-src/src/librats/subsystems/mdns_discovery.h +55 -0
  184. package/native-src/src/librats/subsystems/message_json.cpp +112 -0
  185. package/native-src/src/librats/subsystems/message_json.h +88 -0
  186. package/native-src/src/librats/subsystems/peer_exchange.cpp +241 -0
  187. package/native-src/src/librats/subsystems/peer_exchange.h +136 -0
  188. package/native-src/src/librats/subsystems/ping_service.cpp +98 -0
  189. package/native-src/src/librats/subsystems/ping_service.h +66 -0
  190. package/native-src/src/librats/subsystems/port_mapping_service.cpp +192 -0
  191. package/native-src/src/librats/subsystems/port_mapping_service.h +84 -0
  192. package/native-src/src/librats/subsystems/pubsub.cpp +567 -0
  193. package/native-src/src/librats/subsystems/pubsub.h +175 -0
  194. package/native-src/src/librats/subsystems/reconnection.cpp +239 -0
  195. package/native-src/src/librats/subsystems/reconnection.h +126 -0
  196. package/native-src/src/librats/transport/connection.cpp +343 -0
  197. package/native-src/src/librats/transport/connection.h +283 -0
  198. package/native-src/src/librats/transport/link.h +96 -0
  199. package/native-src/src/librats/transport/reactor.cpp +540 -0
  200. package/native-src/src/librats/transport/reactor.h +224 -0
  201. package/native-src/src/librats/transport/reactor_pool.h +81 -0
  202. package/native-src/src/librats/transport/tcp_link.cpp +49 -0
  203. package/native-src/src/librats/transport/tcp_link.h +43 -0
  204. package/native-src/src/librats/transport/udp_mux.cpp +617 -0
  205. package/native-src/src/librats/transport/udp_mux.h +363 -0
  206. package/native-src/src/librats/transport/udp_packet.cpp +121 -0
  207. package/native-src/src/librats/transport/udp_packet.h +190 -0
  208. package/native-src/src/librats/transport/udp_stream.cpp +1194 -0
  209. package/native-src/src/librats/transport/udp_stream.h +614 -0
  210. package/native-src/src/librats/util/features.h.in +51 -0
  211. package/native-src/src/{fs.cpp → librats/util/fs.cpp} +51 -3
  212. package/native-src/src/librats/util/fs.h +136 -0
  213. package/native-src/src/librats/util/json.cpp +1002 -0
  214. package/native-src/src/librats/util/json.h +444 -0
  215. package/native-src/src/{logger.cpp → librats/util/logger.cpp} +1 -1
  216. package/native-src/src/{logger.h → librats/util/logger.h} +43 -31
  217. package/native-src/src/{network_monitor.cpp → librats/util/network_monitor.cpp} +12 -4
  218. package/native-src/src/{network_monitor.h → librats/util/network_monitor.h} +2 -1
  219. package/native-src/src/{network_utils.cpp → librats/util/network_utils.cpp} +38 -23
  220. package/native-src/src/{network_utils.h → librats/util/network_utils.h} +15 -8
  221. package/native-src/src/{os.cpp → librats/util/os.cpp} +48 -18
  222. package/native-src/src/librats/util/rats_export.h +69 -0
  223. package/native-src/src/{version.cpp → librats/util/version.cpp} +2 -2
  224. package/native-src/src/{version.h.in → librats/util/version.h.in} +1 -1
  225. package/native-src/src/librats/wire/frame.cpp +76 -0
  226. package/native-src/src/librats/wire/frame.h +110 -0
  227. package/native-src/src/librats/wire/message_router.cpp +45 -0
  228. package/native-src/src/librats/wire/message_router.h +47 -0
  229. package/package.json +5 -4
  230. package/scripts/build-librats.js +1 -0
  231. package/scripts/postinstall.js +3 -3
  232. package/scripts/prepare-package.js +4 -4
  233. package/scripts/verify-installation.js +63 -105
  234. package/src/librats_node.cpp +1042 -1324
  235. package/native-src/src/bencode.cpp +0 -485
  236. package/native-src/src/bencode.h +0 -145
  237. package/native-src/src/bittorrent.cpp +0 -14
  238. package/native-src/src/bittorrent.h +0 -74
  239. package/native-src/src/bt_bitfield.cpp +0 -372
  240. package/native-src/src/bt_bitfield.h +0 -316
  241. package/native-src/src/bt_choker.cpp +0 -228
  242. package/native-src/src/bt_choker.h +0 -147
  243. package/native-src/src/bt_client.cpp +0 -1047
  244. package/native-src/src/bt_client.h +0 -445
  245. package/native-src/src/bt_create_torrent.cpp +0 -677
  246. package/native-src/src/bt_create_torrent.h +0 -473
  247. package/native-src/src/bt_extension.cpp +0 -469
  248. package/native-src/src/bt_extension.h +0 -309
  249. package/native-src/src/bt_file_storage.cpp +0 -261
  250. package/native-src/src/bt_file_storage.h +0 -298
  251. package/native-src/src/bt_handshake.cpp +0 -134
  252. package/native-src/src/bt_handshake.h +0 -157
  253. package/native-src/src/bt_messages.cpp +0 -364
  254. package/native-src/src/bt_messages.h +0 -324
  255. package/native-src/src/bt_network.cpp +0 -1007
  256. package/native-src/src/bt_network.h +0 -417
  257. package/native-src/src/bt_peer_connection.cpp +0 -742
  258. package/native-src/src/bt_peer_connection.h +0 -592
  259. package/native-src/src/bt_piece_picker.cpp +0 -786
  260. package/native-src/src/bt_piece_picker.h +0 -473
  261. package/native-src/src/bt_resume_data.cpp +0 -410
  262. package/native-src/src/bt_resume_data.h +0 -249
  263. package/native-src/src/bt_torrent.cpp +0 -2120
  264. package/native-src/src/bt_torrent.h +0 -641
  265. package/native-src/src/bt_torrent_info.cpp +0 -659
  266. package/native-src/src/bt_torrent_info.h +0 -418
  267. package/native-src/src/bt_types.h +0 -621
  268. package/native-src/src/chained_send_buffer.cpp +0 -75
  269. package/native-src/src/chained_send_buffer.h +0 -137
  270. package/native-src/src/crypto/hkdf.c +0 -266
  271. package/native-src/src/crypto/poly1305.h +0 -36
  272. package/native-src/src/dht.cpp +0 -3311
  273. package/native-src/src/dht.h +0 -717
  274. package/native-src/src/disk_io.cpp +0 -632
  275. package/native-src/src/disk_io.h +0 -315
  276. package/native-src/src/file_transfer.cpp +0 -1415
  277. package/native-src/src/file_transfer.h +0 -286
  278. package/native-src/src/fs.h +0 -108
  279. package/native-src/src/gossipsub.cpp +0 -1139
  280. package/native-src/src/gossipsub.h +0 -403
  281. package/native-src/src/ice.cpp +0 -893
  282. package/native-src/src/ice.h +0 -559
  283. package/native-src/src/json.hpp +0 -25526
  284. package/native-src/src/librats.cpp +0 -2378
  285. package/native-src/src/librats.h +0 -2324
  286. package/native-src/src/librats_bittorrent.cpp +0 -601
  287. package/native-src/src/librats_c.cpp +0 -1557
  288. package/native-src/src/librats_c.h +0 -323
  289. package/native-src/src/librats_discovery.cpp +0 -402
  290. package/native-src/src/librats_encryption.cpp +0 -275
  291. package/native-src/src/librats_file_transfer.cpp +0 -144
  292. package/native-src/src/librats_gossipsub.cpp +0 -289
  293. package/native-src/src/librats_ice.cpp +0 -213
  294. package/native-src/src/librats_log_macros.h +0 -36
  295. package/native-src/src/librats_logging.cpp +0 -173
  296. package/native-src/src/librats_mdns.cpp +0 -166
  297. package/native-src/src/librats_persistence.cpp +0 -796
  298. package/native-src/src/librats_portmap.cpp +0 -419
  299. package/native-src/src/librats_reconnection.cpp +0 -218
  300. package/native-src/src/librats_statistic.cpp +0 -105
  301. package/native-src/src/librats_storage.cpp +0 -189
  302. package/native-src/src/rats_export.h +0 -17
  303. package/native-src/src/receive_buffer.cpp +0 -82
  304. package/native-src/src/receive_buffer.h +0 -127
  305. package/native-src/src/socket.h +0 -228
  306. package/native-src/src/threadmanager.cpp +0 -105
  307. package/native-src/src/threadmanager.h +0 -53
  308. package/native-src/src/tracker.cpp +0 -1264
  309. package/native-src/src/tracker.h +0 -319
  310. package/native-src/src/turn.cpp +0 -762
  311. package/native-src/src/turn.h +0 -460
  312. package/native-src/src/wakeup_pipe.h +0 -60
  313. /package/native-src/src/{os.h → librats/util/os.h} +0 -0
@@ -0,0 +1,260 @@
1
+ #pragma once
2
+
3
+ /**
4
+ * @file torrent.h
5
+ * @brief One active torrent: ties the piece picker, peers, disk and choker
6
+ * together and drives a download (or seed) to completion.
7
+ *
8
+ * A Torrent is a PeerConnection::Observer — every wire event lands here and is
9
+ * turned into picker/disk work. The flow is event-driven, not polled:
10
+ *
11
+ * peer unchokes / has new pieces → refill its request pipeline
12
+ * block arrives → write to disk → (piece done) hash & verify
13
+ * piece verified → mark have, announce `have` to peers
14
+ * peer interested → recompute the choker and (un)choke
15
+ *
16
+ * A 1 s tick only handles periodic chores (connect more peers, re-run the
17
+ * choker). All of this runs on the reactor thread, so there are no locks.
18
+ *
19
+ * Connections are owned by the host (Client); the Torrent holds raw pointers it
20
+ * learns at handshake and drops at close.
21
+ */
22
+
23
+ #include "librats/util/rats_export.h"
24
+ #include "librats/bittorrent/choker.h"
25
+ #include "librats/bittorrent/disk_io.h"
26
+ #include "librats/bittorrent/extensions.h"
27
+ #include "librats/bittorrent/peer_connection.h"
28
+ #include "librats/bittorrent/peer_list.h"
29
+ #include "librats/bittorrent/piece_picker.h"
30
+ #include "librats/bittorrent/reactor.h"
31
+ #include "librats/bittorrent/resume_data.h"
32
+ #include "librats/bittorrent/torrent_info.h"
33
+ #include "librats/bittorrent/tracker.h"
34
+ #include "librats/bittorrent/types.h"
35
+ #include "librats/core/types.h"
36
+
37
+ #include <atomic>
38
+ #include <chrono>
39
+ #include <cstdint>
40
+ #include <functional>
41
+ #include <memory>
42
+ #include <optional>
43
+ #include <string>
44
+ #include <unordered_map>
45
+ #include <unordered_set>
46
+ #include <vector>
47
+
48
+ namespace librats::bittorrent {
49
+
50
+ class Torrent;
51
+
52
+ /// What a Torrent needs from its owning Client: outgoing connects and our id.
53
+ class RATS_API TorrentHost {
54
+ public:
55
+ virtual ~TorrentHost() = default;
56
+ virtual void connect_peer(Torrent& torrent, const std::string& ip, std::uint16_t port) = 0;
57
+ virtual const PeerId& peer_id() const = 0;
58
+ virtual std::uint16_t listen_port() const = 0;
59
+ /// Discover peers for @p info_hash via the DHT (if the host has one); each
60
+ /// found peer is delivered to @p on_peer on the reactor thread. Default no-op.
61
+ virtual void find_peers_via_dht(const InfoHash& /*info_hash*/,
62
+ std::function<void(const std::string& ip, std::uint16_t port)> /*on_peer*/) {}
63
+ /// Announce ourselves to the DHT for @p info_hash on @p port so other clients
64
+ /// doing get_peers can find us (BEP 5). Default no-op (no DHT attached).
65
+ virtual void announce_to_dht(const InfoHash& /*info_hash*/, std::uint16_t /*port*/) {}
66
+ };
67
+
68
+ class RATS_API Torrent final : public PeerConnection::Observer {
69
+ public:
70
+ enum class State { Stopped, Metadata, Checking, Downloading, Seeding };
71
+
72
+ Torrent(Reactor& reactor, TorrentHost& host, TorrentInfo info, std::string save_path);
73
+ ~Torrent() override;
74
+
75
+ Torrent(const Torrent&) = delete;
76
+ Torrent& operator=(const Torrent&) = delete;
77
+
78
+ void start();
79
+ void stop();
80
+
81
+ /// Pause a running torrent: drop its peers and stop dialing/serving, but keep
82
+ /// the piece picker and disk state so resume() does not re-hash. No-op if not
83
+ /// running or already paused.
84
+ void pause();
85
+ /// Resume a paused torrent: start reconnecting to peers again. No-op if not
86
+ /// running or not paused.
87
+ void resume();
88
+ bool is_paused() const noexcept { return paused_; }
89
+
90
+ /// Queue a peer to connect to (deduplicated). Connects promptly if running.
91
+ void add_peer(const std::string& ip, std::uint16_t port);
92
+
93
+ // ---- info / progress ----
94
+ const InfoHash& info_hash() const { return info_.info_hash(); }
95
+ const TorrentInfo& torrent_info()const { return info_; }
96
+ std::uint32_t num_pieces() const { return info_.num_pieces(); }
97
+ State state() const noexcept { return state_; }
98
+ bool is_complete() const { return picker_ && picker_->is_finished(); }
99
+ double progress() const;
100
+ std::size_t num_peers() const noexcept { return peers_.size(); }
101
+ /// Total block requests currently in flight across all peers.
102
+ std::size_t num_outstanding_requests() const noexcept;
103
+ /// Override how long a peer may hold requests without delivering before it is
104
+ /// snubbed and its blocks freed. Defaults to kRequestTimeout (30 s).
105
+ void set_request_timeout(std::chrono::milliseconds t) noexcept { request_timeout_ = t; }
106
+ std::uint64_t bytes_downloaded() const noexcept { return bytes_downloaded_; }
107
+ std::uint64_t bytes_uploaded() const noexcept { return bytes_uploaded_; }
108
+
109
+ /// True once we hold the full metadata (always true unless started from a magnet).
110
+ bool has_metadata() const noexcept { return has_metadata_; }
111
+
112
+ /// Fired once when a download reaches 100% (not for torrents that start complete).
113
+ void set_complete_callback(std::function<void()> cb) { on_complete_ = std::move(cb); }
114
+ /// Fired once when metadata is obtained for a magnet torrent (with the completed info).
115
+ void set_metadata_callback(std::function<void(const TorrentInfo&)> cb) { on_metadata_ = std::move(cb); }
116
+
117
+ // ---- fast resume ----
118
+ /// Apply saved resume state. Call before start(): the recorded have-bitfield
119
+ /// is trusted (those pieces skip the hash check), and an embedded info dict
120
+ /// completes a magnet torrent. Ignored if the info-hash doesn't match.
121
+ void load_resume_data(const ResumeData& rd);
122
+ /// Load resume state from the default on-disk path (see default_resume_path).
123
+ /// Like load_resume_data(), call before start(). Returns false if no resume
124
+ /// file exists or it fails to decode.
125
+ bool try_load_resume_data();
126
+ ResumeData generate_resume_data() const;
127
+ /// Write resume data to @p path (default: {save_path}/.resume/{info_hash}.resume).
128
+ bool save_resume_data() const;
129
+ bool save_resume_data(const std::string& path) const;
130
+
131
+ /// Called by the host when an outgoing connect attempt fails.
132
+ void on_connect_failed(const std::string& ip, std::uint16_t port);
133
+
134
+ // ---- PeerConnection::Observer ----
135
+ void on_handshake(PeerConnection&, const InfoHash&, const PeerId&) override;
136
+ void on_bitfield(PeerConnection&, const Bitfield&) override;
137
+ void on_have(PeerConnection&, std::uint32_t piece) override;
138
+ void on_choke(PeerConnection&, bool peer_choking) override;
139
+ void on_interest(PeerConnection&, bool peer_interested) override;
140
+ void on_request(PeerConnection&, std::uint32_t piece, std::uint32_t offset, std::uint32_t length) override;
141
+ void on_piece(PeerConnection&, std::uint32_t piece, std::uint32_t offset, ByteView data) override;
142
+ void on_extended(PeerConnection&, std::uint8_t ext_id, ByteView payload) override;
143
+ void on_closed(PeerConnection&, const std::string& reason) override;
144
+
145
+ private:
146
+ /// Post @p fn to the reactor, guarded by alive_ so it is dropped if this
147
+ /// torrent has since been destroyed. Disk and tracker completions run on their
148
+ /// own worker threads and marshal back through here; a completion that a worker
149
+ /// posts while stop() is joining it can land in the reactor queue *after* the
150
+ /// torrent is erased, so the raw `this` those callbacks capture would dangle
151
+ /// (use-after-free). The guard is the only thing keeping that pointer live-safe.
152
+ void post(std::function<void()> fn);
153
+
154
+ void on_check_complete(Bitfield have);
155
+
156
+ // Extension protocol / metadata (BEP 10 / BEP 9).
157
+ void send_extended_handshake(PeerConnection& pc);
158
+ void handle_ext_handshake(PeerConnection& pc, ByteView payload);
159
+ void handle_ut_metadata(PeerConnection& pc, ByteView payload);
160
+ void ensure_metadata_buffer(std::uint32_t total_size);
161
+ void request_metadata(PeerConnection& pc);
162
+ void on_metadata_piece(std::uint32_t piece, std::uint32_t total_size, ByteView block);
163
+ void try_complete_metadata();
164
+ void promote_to_downloading();
165
+ void schedule_tick();
166
+ void tick();
167
+ void try_connect();
168
+ void update_interest(PeerConnection& pc);
169
+ void refill(PeerConnection& pc);
170
+ void recompute_choker();
171
+ /// Rotate the optimistic-unchoke slot to give a currently-choked interested
172
+ /// peer a chance to prove itself (so newcomers can bootstrap). ~30 s cadence.
173
+ void rotate_optimistic();
174
+ void handle_pex(PeerConnection& pc, ByteView payload);
175
+ void send_pex();
176
+ std::optional<ext::PexPeer> dialable(PeerConnection& pc) const;
177
+ void announce_trackers(TrackerEvent event);
178
+ TrackerRequest make_tracker_request(TrackerEvent event) const;
179
+ std::string default_resume_path() const;
180
+ /// Free blocks stuck on peers that have made no progress within
181
+ /// kRequestTimeout so other peers can re-request them (prevents a silent /
182
+ /// keep-alive-only peer from stalling pieces forever). Runs on the 1 s tick.
183
+ void check_request_timeouts();
184
+ /// Refill every peer whose pipeline has room (used to resume requesting once
185
+ /// disk write backpressure clears).
186
+ void refill_all();
187
+ void on_block_written(PieceBlock block, bool ok);
188
+ void verify_piece(std::uint32_t piece);
189
+ void on_piece_hashed(std::uint32_t piece, bool ok, std::array<std::uint8_t, 20> hash);
190
+ bool alive(PeerConnection* pc) const;
191
+ void remove_peer(PeerConnection* pc);
192
+
193
+ static constexpr int kPipelineDepth = 16;
194
+ static constexpr std::size_t kMaxPeers = 50;
195
+ /// A peer that holds outstanding requests but delivers no block for this long
196
+ /// is snubbed: its blocks are freed for other peers. Kept well under the 120 s
197
+ /// idle timeout so a keep-alive-only peer can't stall pieces indefinitely.
198
+ static constexpr std::chrono::seconds kRequestTimeout{30};
199
+ std::chrono::milliseconds request_timeout_{kRequestTimeout};
200
+ /// Stop requesting new blocks while the disk has more than this many bytes of
201
+ /// writes still pending, so a fast swarm can't grow the write queue without
202
+ /// bound when the disk is slow (D-2). Requesting resumes as the queue drains.
203
+ static constexpr std::size_t kDiskWriteHighWater = 32 * 1024 * 1024;
204
+
205
+ /// Liveness token shared with every reactor task this torrent posts (directly
206
+ /// or via a disk/tracker completion poster). Cleared in the destructor; the
207
+ /// shared_ptr keeps the flag readable after the torrent is gone, so a task
208
+ /// still queued on the reactor drops itself instead of touching freed memory.
209
+ std::shared_ptr<std::atomic<bool>> alive_ = std::make_shared<std::atomic<bool>>(true);
210
+
211
+ Reactor& reactor_;
212
+ TorrentHost& host_;
213
+ TorrentInfo info_;
214
+ std::string save_path_;
215
+ std::unique_ptr<PiecePicker> picker_;
216
+ std::unique_ptr<DiskIo> disk_;
217
+ std::unique_ptr<TrackerAnnouncer> trackers_;
218
+ Choker choker_;
219
+ State state_ = State::Stopped;
220
+ bool running_ = false;
221
+ bool paused_ = false;
222
+ bool has_metadata_ = false;
223
+ bool completed_announced_ = false;
224
+ bool write_stalled_ = false; ///< requesting paused for disk backpressure
225
+ Bitfield resume_have_; ///< trusted have-set from resume data
226
+
227
+ std::vector<PeerConnection*> peers_;
228
+ std::unordered_map<PeerConnection*, int> outstanding_;
229
+ /// Time of the last progress with each peer (a block received, or the moment
230
+ /// we started waiting on a fresh batch). Drives the request-timeout snub.
231
+ std::unordered_map<PeerConnection*, std::chrono::steady_clock::time_point> request_time_;
232
+ std::unordered_map<PeerConnection*, std::uint64_t> recent_down_; // bytes recv this choke window (leech score)
233
+ std::unordered_map<PeerConnection*, std::uint64_t> recent_up_; // bytes served this choke window (seed score)
234
+ PeerConnection* optimistic_ = nullptr; // current optimistic-unchoke peer
235
+ std::unordered_set<PeerConnection*> seed_peers_; // counted via the picker's O(1) seed counter
236
+ std::unordered_map<PeerConnection*, ext::PeerExtensions> peer_ext_;
237
+ std::unordered_map<PeerConnection*, std::unordered_set<std::string>> pex_sent_;
238
+ std::unordered_map<PeerConnection*, int> pex_last_tick_; ///< tick of last PEX to peer (BEP11 ≥60 s gap)
239
+ PeerList peer_list_;
240
+ int tick_count_ = 0;
241
+ int next_announce_tick_ = 300; ///< tick to re-announce (driven by tracker interval)
242
+ int progress_logged_ = -1; ///< last download %-decile logged at INFO (avoids per-piece spam)
243
+
244
+ // ut_metadata (BEP 9) assembly state, used while we lack metadata.
245
+ Bytes metadata_buf_;
246
+ std::uint32_t metadata_size_ = 0;
247
+ std::uint32_t metadata_pieces_ = 0;
248
+ std::uint32_t metadata_received_ = 0;
249
+ std::vector<bool> metadata_have_;
250
+
251
+ std::uint64_t bytes_downloaded_ = 0; ///< cumulative payload downloaded (tracker stat / resume)
252
+ std::uint64_t bytes_uploaded_ = 0;
253
+ std::uint64_t verified_bytes_ = 0; ///< payload currently present & verified on disk (drives `left`)
254
+
255
+ TimerId tick_timer_ = kInvalidTimerId;
256
+ std::function<void()> on_complete_;
257
+ std::function<void(const TorrentInfo&)> on_metadata_;
258
+ };
259
+
260
+ } // namespace librats::bittorrent
@@ -0,0 +1,129 @@
1
+ #include "librats/bittorrent/torrent_creator.h"
2
+
3
+ #include "librats/bittorrent/bencode.h"
4
+ #include "librats/bittorrent/file_storage.h"
5
+ #include "librats/crypto/sha1.h"
6
+ #include "librats/util/fs.h"
7
+
8
+ #include <ctime>
9
+
10
+ namespace librats::bittorrent {
11
+
12
+ namespace {
13
+
14
+ struct SourceFile {
15
+ std::vector<std::string> components; ///< path relative to the torrent root
16
+ std::int64_t size = 0;
17
+ std::string disk_path; ///< where to read the bytes from
18
+ };
19
+
20
+ /// Recursively collect the regular files under @p dir, accumulating the path
21
+ /// components relative to the torrent root.
22
+ void scan_directory(const std::string& dir, std::vector<std::string> prefix,
23
+ std::vector<SourceFile>& out) {
24
+ std::vector<DirectoryEntry> entries;
25
+ if (!list_directory(dir.c_str(), entries)) return;
26
+ for (const auto& e : entries) {
27
+ if (e.name == "." || e.name == "..") continue;
28
+ std::vector<std::string> comps = prefix;
29
+ comps.push_back(e.name);
30
+ const std::string child = combine_paths(dir, e.name);
31
+ if (e.is_directory) scan_directory(child, std::move(comps), out);
32
+ else out.push_back(SourceFile{std::move(comps), std::int64_t(get_file_size(child.c_str())), child});
33
+ }
34
+ }
35
+
36
+ } // namespace
37
+
38
+ std::optional<TorrentInfo> TorrentCreator::create_from_path(const std::string& path, std::string* error,
39
+ const PieceHashProgress& on_progress) {
40
+ auto fail = [&](const char* m) -> std::optional<TorrentInfo> { if (error) *error = m; return std::nullopt; };
41
+
42
+ const std::string root_name = name_.empty() ? get_filename_from_path(path) : name_;
43
+ if (root_name.empty()) return fail("empty torrent name");
44
+
45
+ // Gather the source files and lay them out (the layout also drives reading).
46
+ std::vector<SourceFile> sources;
47
+ bool single_file = false;
48
+ if (is_directory(path.c_str())) {
49
+ scan_directory(path, {}, sources);
50
+ } else if (is_file(path.c_str())) {
51
+ single_file = true;
52
+ sources.push_back(SourceFile{{root_name}, std::int64_t(get_file_size(path.c_str())), path});
53
+ } else {
54
+ return fail("path is neither a file nor a directory");
55
+ }
56
+ if (sources.empty()) return fail("no files to add");
57
+
58
+ FileStorage layout;
59
+ layout.set_piece_length(piece_length_);
60
+ layout.set_name(root_name);
61
+ std::vector<std::string> disk_paths;
62
+ for (const auto& s : sources) {
63
+ std::string rel = root_name;
64
+ if (!single_file)
65
+ for (const auto& c : s.components) { rel += '/'; rel += c; }
66
+ if (!layout.add_file(rel, s.size)) return fail("file size overflow");
67
+ disk_paths.push_back(s.disk_path);
68
+ }
69
+
70
+ // Hash every piece by reading the bytes it spans across the source files.
71
+ const std::uint32_t total_pieces = layout.num_pieces();
72
+ std::string pieces;
73
+ pieces.reserve(std::size_t(total_pieces) * 20);
74
+ for (std::uint32_t p = 0; p < total_pieces; ++p) {
75
+ Bytes buf;
76
+ buf.reserve(layout.piece_size(p));
77
+ for (const auto& slice : layout.map_block(p, 0, layout.piece_size(p))) {
78
+ Bytes chunk(std::size_t(slice.size));
79
+ if (!read_file_chunk(disk_paths[slice.file_index], std::uint64_t(slice.offset),
80
+ chunk.data(), chunk.size()))
81
+ return fail("failed to read source file");
82
+ buf.insert(buf.end(), chunk.begin(), chunk.end());
83
+ }
84
+ auto h = SHA1::hash_raw(buf.data(), buf.size());
85
+ pieces.append(reinterpret_cast<const char*>(h.data()), 20);
86
+ if (on_progress) on_progress(p + 1, total_pieces);
87
+ }
88
+
89
+ // Build the info dictionary.
90
+ librats::BencodeValue info = librats::BencodeValue::create_dict();
91
+ info["name"] = librats::BencodeValue(root_name);
92
+ info["piece length"] = librats::BencodeValue(std::int64_t(piece_length_));
93
+ info["pieces"] = librats::BencodeValue(pieces);
94
+ if (private_) info["private"] = librats::BencodeValue(std::int64_t(1));
95
+ if (single_file) {
96
+ info["length"] = librats::BencodeValue(std::int64_t(sources[0].size));
97
+ } else {
98
+ librats::BencodeValue files = librats::BencodeValue::create_list();
99
+ for (const auto& s : sources) {
100
+ librats::BencodeValue f = librats::BencodeValue::create_dict();
101
+ f["length"] = librats::BencodeValue(std::int64_t(s.size));
102
+ librats::BencodeValue comps = librats::BencodeValue::create_list();
103
+ for (const auto& c : s.components) comps.push_back(librats::BencodeValue(c));
104
+ f["path"] = comps;
105
+ files.push_back(f);
106
+ }
107
+ info["files"] = files;
108
+ }
109
+
110
+ // Wrap into a full .torrent with the optional top-level fields.
111
+ librats::BencodeValue root = librats::BencodeValue::create_dict();
112
+ if (!trackers_.empty()) {
113
+ root["announce"] = librats::BencodeValue(trackers_.front());
114
+ librats::BencodeValue tier = librats::BencodeValue::create_list();
115
+ for (const auto& t : trackers_) tier.push_back(librats::BencodeValue(t));
116
+ librats::BencodeValue al = librats::BencodeValue::create_list();
117
+ al.push_back(tier);
118
+ root["announce-list"] = al;
119
+ }
120
+ if (!comment_.empty()) root["comment"] = librats::BencodeValue(comment_);
121
+ if (!created_by_.empty()) root["created by"] = librats::BencodeValue(created_by_);
122
+ root["creation date"] = librats::BencodeValue(std::int64_t(std::time(nullptr)));
123
+ root["info"] = info;
124
+
125
+ torrent_bytes_ = root.encode();
126
+ return TorrentInfo::from_bytes(torrent_bytes_);
127
+ }
128
+
129
+ } // namespace librats::bittorrent
@@ -0,0 +1,58 @@
1
+ #pragma once
2
+
3
+ /**
4
+ * @file torrent_creator.h
5
+ * @brief Build a .torrent from files on disk.
6
+ *
7
+ * Point it at a file or directory; it lays the files end-to-end, hashes every
8
+ * piece (SHA-1), and emits both a parsed TorrentInfo and the bencoded .torrent
9
+ * bytes. The resulting metadata is exactly what a downloader would receive, so
10
+ * the creator can immediately seed via Client::add_torrent_for_seeding.
11
+ */
12
+
13
+ #include "librats/bittorrent/torrent_info.h"
14
+ #include "librats/bittorrent/types.h"
15
+ #include "librats/core/bytes.h"
16
+
17
+ #include <cstdint>
18
+ #include <functional>
19
+ #include <optional>
20
+ #include <string>
21
+ #include <vector>
22
+
23
+ namespace librats::bittorrent {
24
+
25
+ /// Reports piece-hashing progress during create_from_path: (pieces_hashed,
26
+ /// total_pieces). Called once per piece as it is hashed; total_pieces is fixed
27
+ /// for the whole run and the final call always has pieces_hashed == total_pieces.
28
+ using PieceHashProgress = std::function<void(std::uint32_t pieces_hashed, std::uint32_t total_pieces)>;
29
+
30
+ class TorrentCreator {
31
+ public:
32
+ void set_piece_length(std::uint32_t length) { piece_length_ = length; }
33
+ void set_name(std::string name) { name_ = std::move(name); }
34
+ void add_tracker(std::string url) { trackers_.push_back(std::move(url)); }
35
+ void set_private(bool is_private) { private_ = is_private; }
36
+ void set_comment(std::string comment) { comment_ = std::move(comment); }
37
+ void set_created_by(std::string creator) { created_by_ = std::move(creator); }
38
+
39
+ /// Hash @p path (a file or directory) and build the torrent. On success the
40
+ /// bencoded form is available via torrent_file(). Returns nullopt (and sets
41
+ /// @p error, if given) on I/O or layout problems. If @p on_progress is set it
42
+ /// is invoked once per hashed piece so callers can drive a progress bar.
43
+ std::optional<TorrentInfo> create_from_path(const std::string& path, std::string* error = nullptr,
44
+ const PieceHashProgress& on_progress = {});
45
+
46
+ const Bytes& torrent_file() const noexcept { return torrent_bytes_; }
47
+
48
+ private:
49
+ std::uint32_t piece_length_ = kDefaultPieceLength;
50
+ std::string name_;
51
+ std::string comment_;
52
+ std::string created_by_;
53
+ bool private_ = false;
54
+ std::vector<std::string> trackers_;
55
+ Bytes torrent_bytes_;
56
+ };
57
+
58
+ } // namespace librats::bittorrent