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,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