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,367 @@
1
+ #pragma once
2
+
3
+ /**
4
+ * @file file_transfer.h
5
+ * @brief Stream a file or a whole directory tree to a peer, with integrity,
6
+ * backpressure, pause/resume/cancel, idle-timeout and crash-safe writes.
7
+ *
8
+ * Push model: the sender offers a file/directory; the receiver accepts (choosing
9
+ * a destination) or rejects; the sender streams the data; the receiver verifies a
10
+ * whole-file SHA-256 before moving each temp file into place. All control + data
11
+ * ride on MessageType::FileChunk as compact binary opcodes (no JSON), implemented
12
+ * on the Node/Subsystem plugin model.
13
+ *
14
+ * Integrity: every file ends with its SHA-256, verified end-to-end before the temp
15
+ * file is moved into place; a mismatch (or a disk-write failure) fails the whole
16
+ * transfer. In transit the Noise session already AEAD-authenticates every byte, so
17
+ * no redundant per-chunk checksum rides the wire.
18
+ *
19
+ * Backpressure: the sender keeps at most `window_bytes` un-acked; the receiver
20
+ * acks cumulative progress at least twice per window, so the sender never stalls.
21
+ *
22
+ * Safety: temp file names are derived from the sender's PeerId + the transfer id
23
+ * (never the peer's self-declared name) — the id alone is only unique per sender,
24
+ * so two peers' first transfers would otherwise share a temp file. Every
25
+ * peer-supplied relative path in a directory manifest is validated against path
26
+ * traversal before use, and a manifest file count is checked against the payload
27
+ * size before it is used to size an allocation.
28
+ *
29
+ * Threading: a worker pool runs the blocking send loop (one transfer per worker);
30
+ * receiving + all control handling run on the reactor thread; a maintenance
31
+ * thread reaps idle/timed-out transfers. A finished transfer is erased as it
32
+ * completes, so there is no retention window. Each transfer has its own
33
+ * mutex+condvar; the maps are guarded by mutex_.
34
+ *
35
+ * Wire (MessageType::FileChunk payload, big-endian):
36
+ * OFFER [1][id:u64][flags:u8][total:u64][name_len:u16][name][file_count:u32]
37
+ * { [path_len:u16][path][size:u64] } × file_count
38
+ * RESPONSE [2][id:u64][accept:u8]
39
+ * CHUNK [3][id:u64][file_index:u32][offset:u64][data]
40
+ * FILE_END [4][id:u64][file_index:u32][sha256:32]
41
+ * PROGRESS [5][id:u64][received:u64] (cumulative across all files)
42
+ * COMPLETE [6][id:u64][ok:u8]
43
+ * CANCEL [7][id:u64]
44
+ * PAUSE [8][id:u64]
45
+ * RESUME [9][id:u64]
46
+ */
47
+
48
+ #include "librats/util/rats_export.h"
49
+ #include "librats/node/peer_network.h"
50
+ #include "librats/peer/peer.h"
51
+ #include "librats/core/bytes.h"
52
+ #include "librats/peer/peer_id.h"
53
+ #include "librats/util/fs.h"
54
+
55
+ extern "C" {
56
+ #include "librats/crypto/sha256.h"
57
+ }
58
+
59
+ #include <atomic>
60
+ #include <chrono>
61
+ #include <condition_variable>
62
+ #include <cstdint>
63
+ #include <functional>
64
+ #include <memory>
65
+ #include <mutex>
66
+ #include <queue>
67
+ #include <string>
68
+ #include <thread>
69
+ #include <unordered_map>
70
+ #include <vector>
71
+
72
+ namespace librats {
73
+
74
+ class RATS_API FileTransfer final : public Subsystem {
75
+ public:
76
+ struct Config {
77
+ uint32_t chunk_size = 64 * 1024; ///< payload bytes per chunk
78
+ uint32_t window_bytes = 4 * 1024 * 1024; ///< max un-acked bytes in flight
79
+ uint32_t progress_interval = 256 * 1024; ///< receiver acks every N bytes
80
+ uint32_t transfer_timeout_secs = 60; ///< abort a transfer idle this long
81
+ uint32_t worker_threads = 4; ///< concurrent outgoing transfers
82
+ uint32_t disk_threads = 4; ///< receive-side disk-writer pool size
83
+ bool verify_integrity = true; ///< whole-file SHA-256 end-to-end check
84
+ std::string temp_directory = "."; ///< holds in-progress downloads
85
+ };
86
+
87
+ enum class Status { Pending, Active, Paused, Completed, Failed, Cancelled };
88
+ enum class Direction { Sending, Receiving };
89
+
90
+ /// One file inside a transfer (a single-file transfer has exactly one).
91
+ struct FileEntry {
92
+ std::string relative_path; ///< POSIX path relative to the transfer root
93
+ uint64_t size = 0;
94
+ };
95
+
96
+ /// Delivered to the offer callback so the app can accept() or reject().
97
+ struct Offer {
98
+ PeerId from;
99
+ uint64_t id = 0;
100
+ std::string name; ///< file or directory name
101
+ uint64_t size = 0; ///< total size across all files
102
+ bool is_directory = false;
103
+ std::vector<FileEntry> files; ///< full manifest
104
+ };
105
+
106
+ /// Snapshot passed to the progress callback (both directions).
107
+ struct Progress {
108
+ uint64_t id = 0;
109
+ PeerId peer;
110
+ Direction direction = Direction::Sending;
111
+ Status status = Status::Pending;
112
+ uint64_t bytes_transferred = 0;
113
+ uint64_t total_bytes = 0;
114
+ uint32_t files_completed = 0;
115
+ uint32_t total_files = 0;
116
+
117
+ double transfer_rate_bps = 0.0; ///< recent (smoothed) throughput, bytes/sec
118
+ double average_rate_bps = 0.0; ///< mean throughput since the transfer went live
119
+ std::chrono::milliseconds elapsed{0}; ///< time since it went live
120
+ std::chrono::milliseconds estimated_time_remaining{0}; ///< ETA at the recent rate (0 = unknown)
121
+
122
+ /// Completion in [0, 100].
123
+ double percent() const {
124
+ if (total_bytes == 0) return status == Status::Completed ? 100.0 : 0.0;
125
+ return static_cast<double>(bytes_transferred) / static_cast<double>(total_bytes) * 100.0;
126
+ }
127
+ };
128
+
129
+ /// Aggregate counters.
130
+ struct Stats {
131
+ uint64_t bytes_sent = 0, bytes_received = 0;
132
+ uint64_t completed = 0, failed = 0;
133
+ };
134
+
135
+ using OfferHandler = std::function<void(const Offer&)>;
136
+ using ProgressHandler = std::function<void(const Progress&)>;
137
+ using CompleteHandler = std::function<void(uint64_t id, bool success, const std::string& path)>;
138
+
139
+ explicit FileTransfer(std::string temp_dir = ".");
140
+ explicit FileTransfer(Config config);
141
+ ~FileTransfer() override;
142
+
143
+ void on_offer(OfferHandler handler) { offer_handler_ = std::move(handler); }
144
+ void on_progress(ProgressHandler handler) { progress_handler_ = std::move(handler); }
145
+ void on_complete(CompleteHandler handler) { complete_handler_ = std::move(handler); }
146
+
147
+ /// Offer a single file. Returns the transfer id (0 if the file is unusable).
148
+ uint64_t send_file(const PeerId& to, const std::string& path);
149
+ /// Offer a directory tree. Returns the transfer id (0 if the dir is unusable).
150
+ uint64_t send_directory(const PeerId& to, const std::string& dir_path);
151
+
152
+ /// Accept an offered transfer. For a single file, dest_path is the file path;
153
+ /// for a directory, it is the destination directory. (from, id) names the offer.
154
+ void accept(const PeerId& from, uint64_t id, const std::string& dest_path);
155
+ void reject(const PeerId& from, uint64_t id);
156
+
157
+ /// Control a live transfer (works from either side); (peer, id) names it.
158
+ bool cancel(const PeerId& peer, uint64_t id);
159
+ bool pause(const PeerId& peer, uint64_t id);
160
+ bool resume(const PeerId& peer, uint64_t id);
161
+
162
+ Stats stats() const;
163
+
164
+ /// A relative path from a peer's directory manifest is safe only if it stays
165
+ /// inside the destination: non-empty, not absolute, no drive letter, and no
166
+ /// "."/".." component. Public + static so it can be unit-tested directly.
167
+ static bool is_safe_relative_path(const std::string& p);
168
+
169
+ void attach(NodeContext& ctx) override;
170
+ void start() override;
171
+ void stop() override;
172
+
173
+ private:
174
+ // Smoothed throughput + elapsed/ETA tracking for one transfer. Accessed only
175
+ // under the owning transfer's mutex. The clock starts lazily on the first
176
+ // sample (first byte activity); a long gap (pause/idle) is treated as a
177
+ // discontinuity so it doesn't register as a throughput dip.
178
+ struct RateTracker {
179
+ using clock = std::chrono::steady_clock;
180
+ clock::time_point start{}; ///< first byte activity (transfer went live)
181
+ clock::time_point mark{}; ///< last rate-sample instant
182
+ uint64_t mark_bytes = 0;
183
+ double rate_bps = 0.0; ///< EWMA of recent throughput
184
+
185
+ void sample(uint64_t bytes, clock::time_point now) {
186
+ constexpr int64_t kMinMs = 250, kMaxMs = 2000;
187
+ constexpr double kAlpha = 0.4;
188
+ if (start == clock::time_point{}) { start = mark = now; mark_bytes = bytes; return; }
189
+ const int64_t dt = std::chrono::duration_cast<std::chrono::milliseconds>(now - mark).count();
190
+ if (dt < kMinMs) return; // too soon: hold the prior rate
191
+ if (dt > kMaxMs) { mark = now; mark_bytes = bytes; return; } // gap: reset, don't pollute
192
+ const double inst = static_cast<double>(bytes - mark_bytes) * 1000.0 / static_cast<double>(dt);
193
+ rate_bps = rate_bps <= 0.0 ? inst : kAlpha * inst + (1.0 - kAlpha) * rate_bps;
194
+ mark = now; mark_bytes = bytes;
195
+ }
196
+
197
+ void fill(Progress& p, uint64_t bytes, uint64_t total, clock::time_point now) const {
198
+ if (start == clock::time_point{}) return; // not live yet
199
+ const auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(now - start);
200
+ p.elapsed = ms;
201
+ p.transfer_rate_bps = rate_bps;
202
+ if (ms.count() > 0)
203
+ p.average_rate_bps = static_cast<double>(bytes) * 1000.0 / static_cast<double>(ms.count());
204
+ if (rate_bps > 1.0 && total > bytes)
205
+ p.estimated_time_remaining = std::chrono::milliseconds(
206
+ static_cast<int64_t>(static_cast<double>(total - bytes) / rate_bps * 1000.0));
207
+ }
208
+ };
209
+
210
+ // ── Per-transfer state (held via shared_ptr so workers/handlers keep it
211
+ // alive past map removal) ──────────────────────────────────────────────
212
+ struct Outgoing {
213
+ uint64_t id = 0;
214
+ PeerId peer;
215
+ std::string name;
216
+ std::string root; ///< local source path/dir
217
+ bool is_directory = false;
218
+ std::vector<FileEntry> files; ///< relative_path + size
219
+ std::vector<std::string> sources; ///< absolute source path per file
220
+ uint64_t total_bytes = 0;
221
+
222
+ std::mutex mtx;
223
+ std::condition_variable cv;
224
+ size_t cur_file = 0;
225
+ uint64_t cur_offset = 0;
226
+ uint64_t bytes_done = 0;
227
+ uint64_t acked = 0;
228
+ uint32_t files_done = 0;
229
+ Status status = Status::Pending;
230
+ bool worker_active = false;
231
+ bool finished = false;
232
+ rats_sha256_context_t hash{};
233
+ std::chrono::steady_clock::time_point last_activity{};
234
+ RateTracker rate;
235
+ };
236
+
237
+ struct IncomingFile {
238
+ std::string relative_path;
239
+ uint64_t size = 0;
240
+ std::string final_path;
241
+ std::string temp_path;
242
+ uint64_t enqueued = 0; ///< reactor: bytes handed to the disk writer
243
+ uint64_t received = 0; ///< writer: bytes actually written to disk
244
+ bool temp_created = false;
245
+ bool finalized = false;
246
+ };
247
+
248
+ // A unit of disk work queued by the reactor for the writer pool. A pure data
249
+ // job carries chunk bytes; a file-end job carries the sender's SHA-256 so the
250
+ // writer can verify + finalize once all of the file's data is on disk.
251
+ struct WriteJob {
252
+ uint32_t fidx = 0;
253
+ uint64_t offset = 0;
254
+ Bytes data; ///< chunk bytes (empty for a file-end job)
255
+ bool is_file_end = false;
256
+ uint8_t sha[RATS_SHA256_HASH_SIZE]{};
257
+ };
258
+
259
+ struct Incoming {
260
+ uint64_t id = 0;
261
+ PeerId peer;
262
+ std::string name;
263
+ bool is_directory = false;
264
+ std::string dest_root;
265
+ std::vector<IncomingFile> files;
266
+
267
+ std::mutex mtx;
268
+ size_t recv_file = 0; ///< reactor cursor: file currently accepting chunks
269
+ uint64_t bytes_done = 0; ///< writer: total bytes on disk (drives acks/progress)
270
+ uint64_t last_ack = 0;
271
+ uint32_t files_done = 0;
272
+ Status status = Status::Pending;
273
+ bool finished = false;
274
+ std::chrono::steady_clock::time_point last_activity{};
275
+ RateTracker rate;
276
+
277
+ // ── async disk writer (all fields below the queue are writer-thread only) ─
278
+ std::queue<WriteJob> wq; ///< pending disk jobs (guarded by mtx)
279
+ uint64_t queued_bytes = 0;///< bytes sitting in wq (backpressure)
280
+ bool scheduled = false;///< queued in / owned by the writer pool
281
+ FileStream out; ///< currently open temp file
282
+ size_t out_idx = SIZE_MAX;
283
+ int hashing_file = -1;///< which file `hash` currently covers
284
+ rats_sha256_context_t hash{};
285
+
286
+ ~Incoming(); ///< closes `out` and reclaims any un-finalized temp files
287
+ };
288
+
289
+ // ── message handling (reactor thread) ─────────────────────────────────────
290
+ void on_message(const Peer& peer, ByteView payload);
291
+ void handle_offer(const PeerId& from, uint64_t id, bool is_dir, uint64_t total,
292
+ std::string name, std::vector<FileEntry> files);
293
+ void handle_chunk(const PeerId& from, uint64_t id, uint32_t fidx, uint64_t offset,
294
+ ByteView data);
295
+ void handle_file_end(const PeerId& from, uint64_t id, uint32_t fidx, const uint8_t* sha);
296
+
297
+ // ── sending ──────────────────────────────────────────────────────────────
298
+ uint64_t start_send(std::shared_ptr<Outgoing> t);
299
+ void queue_send(uint64_t id);
300
+ void worker_loop();
301
+ void run_send(const std::shared_ptr<Outgoing>& t);
302
+
303
+ // ── receiving ────────────────────────────────────────────────────────────
304
+ // The reactor thread only validates + copies a chunk into the transfer's write
305
+ // queue; a disk-writer thread does the blocking write, hashing and finalize off
306
+ // the reactor. `schedule_writer` hands a transfer to the pool (call with the
307
+ // transfer's mutex NOT held — pool lock is always taken after the transfer's).
308
+ void schedule_writer(const std::shared_ptr<Incoming>& t);
309
+ void disk_worker_loop();
310
+ void drain_writes(const std::shared_ptr<Incoming>& t);
311
+ void process_data(const std::shared_ptr<Incoming>& t, WriteJob& job);
312
+ void process_file_end(const std::shared_ptr<Incoming>& t, WriteJob& job);
313
+
314
+ // ── lifecycle helpers ─────────────────────────────────────────────────────
315
+ void maintenance_loop();
316
+ void finish_outgoing(const std::shared_ptr<Outgoing>& t, bool success);
317
+ void finish_incoming(const std::shared_ptr<Incoming>& t, bool success, const std::string& error);
318
+ void emit_progress(const std::shared_ptr<Outgoing>& t);
319
+ void emit_progress(const std::shared_ptr<Incoming>& t);
320
+
321
+ std::shared_ptr<Outgoing> find_outgoing(uint64_t id) const;
322
+ std::shared_ptr<Incoming> find_incoming(const PeerId& peer, uint64_t id) const;
323
+
324
+ void send_to(const PeerId& peer, const Bytes& msg) {
325
+ if (network_) network_->send(peer, MessageType::FileChunk, ByteView(msg));
326
+ }
327
+ void send_simple(const PeerId& peer, uint8_t op, uint64_t id);
328
+ void send_complete(const PeerId& peer, uint64_t id, bool ok);
329
+
330
+ PeerNetwork* network_ = nullptr;
331
+ Config config_;
332
+ std::atomic<uint64_t> next_id_{1};
333
+ std::atomic<bool> running_{false};
334
+
335
+ OfferHandler offer_handler_;
336
+ ProgressHandler progress_handler_;
337
+ CompleteHandler complete_handler_;
338
+
339
+ mutable std::mutex mutex_; ///< guards the two maps below
340
+ std::unordered_map<uint64_t, std::shared_ptr<Outgoing>> outgoing_;
341
+ std::unordered_map<PeerId, std::unordered_map<uint64_t, std::shared_ptr<Incoming>>,
342
+ PeerId::Hash> incoming_;
343
+
344
+ // send-side worker pool + send queue
345
+ std::vector<std::thread> workers_;
346
+ std::mutex queue_mutex_;
347
+ std::condition_variable queue_cv_;
348
+ std::queue<uint64_t> send_queue_;
349
+
350
+ // receive-side disk-writer pool + ready queue. A transfer is pushed here when it
351
+ // has pending write jobs; its `scheduled` flag keeps it single-owner so exactly
352
+ // one worker drains a given transfer at a time (preserving chunk order).
353
+ std::vector<std::thread> disk_workers_;
354
+ std::mutex disk_mutex_;
355
+ std::condition_variable disk_cv_;
356
+ std::queue<std::shared_ptr<Incoming>> disk_ready_;
357
+
358
+ // maintenance (idle timeout / purge)
359
+ std::thread maintenance_thread_;
360
+ std::mutex maintenance_mutex_;
361
+ std::condition_variable maintenance_cv_;
362
+
363
+ mutable std::mutex stats_mutex_;
364
+ Stats stats_;
365
+ };
366
+
367
+ } // namespace librats