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
@@ -1,1264 +0,0 @@
1
- #include "tracker.h"
2
- #include "bencode.h"
3
- #include "logger.h"
4
- #include <sstream>
5
- #include <iomanip>
6
- #include <random>
7
- #include <algorithm>
8
- #include <cstring>
9
- #include <thread>
10
- #include <atomic>
11
-
12
- #define LOG_TRACKER_DEBUG(message) LOG_DEBUG("tracker", message)
13
- #define LOG_TRACKER_INFO(message) LOG_INFO("tracker", message)
14
- #define LOG_TRACKER_WARN(message) LOG_WARN("tracker", message)
15
- #define LOG_TRACKER_ERROR(message) LOG_ERROR("tracker", message)
16
-
17
- namespace librats {
18
-
19
- //=============================================================================
20
- // Utility Functions
21
- //=============================================================================
22
-
23
- std::string tracker_event_to_string(TrackerEvent event) {
24
- switch (event) {
25
- case TrackerEvent::STARTED: return "started";
26
- case TrackerEvent::STOPPED: return "stopped";
27
- case TrackerEvent::COMPLETED: return "completed";
28
- case TrackerEvent::NONE:
29
- default: return "";
30
- }
31
- }
32
-
33
- TrackerEvent string_to_tracker_event(const std::string& event_str) {
34
- if (event_str == "started") return TrackerEvent::STARTED;
35
- if (event_str == "stopped") return TrackerEvent::STOPPED;
36
- if (event_str == "completed") return TrackerEvent::COMPLETED;
37
- return TrackerEvent::NONE;
38
- }
39
-
40
- //=============================================================================
41
- // HttpTrackerClient Implementation
42
- //=============================================================================
43
-
44
- HttpTrackerClient::HttpTrackerClient(const std::string& tracker_url)
45
- : tracker_url_(tracker_url), interval_(1800), is_working_(true) {
46
- LOG_TRACKER_INFO("Created HTTP tracker client for: " << tracker_url_);
47
- }
48
-
49
- HttpTrackerClient::~HttpTrackerClient() = default;
50
-
51
- bool HttpTrackerClient::announce(const TrackerRequest& request, TrackerResponseCallback callback) {
52
- LOG_TRACKER_INFO("Announcing to HTTP tracker: " << tracker_url_);
53
-
54
- std::string announce_url = build_announce_url(request);
55
-
56
- try {
57
- std::vector<uint8_t> response_data = http_get(announce_url);
58
-
59
- if (response_data.empty()) {
60
- LOG_TRACKER_ERROR("Empty response from tracker: " << tracker_url_);
61
- is_working_ = false;
62
-
63
- TrackerResponse error_response;
64
- error_response.success = false;
65
- error_response.failure_reason = "Empty response from tracker";
66
- if (callback) callback(error_response, tracker_url_);
67
- return false;
68
- }
69
-
70
- TrackerResponse response = parse_response(response_data);
71
-
72
- if (response.success) {
73
- last_announce_time_ = std::chrono::steady_clock::now();
74
- interval_ = response.interval;
75
- if (!response.tracker_id.empty()) {
76
- tracker_id_ = response.tracker_id;
77
- }
78
- is_working_ = true;
79
-
80
- LOG_TRACKER_INFO("Announce successful. Peers: " << response.peers.size()
81
- << ", Seeders: " << response.complete
82
- << ", Leechers: " << response.incomplete);
83
- } else {
84
- LOG_TRACKER_ERROR("Tracker announce failed: " << response.failure_reason);
85
- is_working_ = false;
86
- }
87
-
88
- if (callback) {
89
- callback(response, tracker_url_);
90
- }
91
-
92
- return response.success;
93
-
94
- } catch (const std::exception& e) {
95
- LOG_TRACKER_ERROR("Exception during announce: " << e.what());
96
- is_working_ = false;
97
-
98
- TrackerResponse error_response;
99
- error_response.success = false;
100
- error_response.failure_reason = std::string("Exception: ") + e.what();
101
- if (callback) callback(error_response, tracker_url_);
102
-
103
- return false;
104
- }
105
- }
106
-
107
- bool HttpTrackerClient::scrape(const std::vector<InfoHash>& info_hashes, TrackerResponseCallback callback) {
108
- LOG_TRACKER_INFO("Scraping HTTP tracker: " << tracker_url_);
109
-
110
- std::string scrape_url = build_scrape_url(info_hashes);
111
- if (scrape_url.empty()) {
112
- LOG_TRACKER_WARN("Cannot build scrape URL for tracker: " << tracker_url_);
113
- return false;
114
- }
115
-
116
- try {
117
- std::vector<uint8_t> response_data = http_get(scrape_url);
118
-
119
- if (response_data.empty()) {
120
- LOG_TRACKER_ERROR("Empty scrape response from tracker: " << tracker_url_);
121
- return false;
122
- }
123
-
124
- TrackerResponse response = parse_response(response_data);
125
-
126
- if (callback) {
127
- callback(response, tracker_url_);
128
- }
129
-
130
- return response.success;
131
-
132
- } catch (const std::exception& e) {
133
- LOG_TRACKER_ERROR("Exception during scrape: " << e.what());
134
- return false;
135
- }
136
- }
137
-
138
- std::string HttpTrackerClient::build_announce_url(const TrackerRequest& request) {
139
- std::ostringstream url;
140
- url << tracker_url_;
141
-
142
- // Add query separator
143
- if (tracker_url_.find('?') == std::string::npos) {
144
- url << "?";
145
- } else {
146
- url << "&";
147
- }
148
-
149
- // Required parameters
150
- url << "info_hash=" << url_encode_binary(request.info_hash.data(), request.info_hash.size());
151
- url << "&peer_id=" << url_encode_binary(request.peer_id.data(), request.peer_id.size());
152
- url << "&port=" << request.port;
153
- url << "&uploaded=" << request.uploaded;
154
- url << "&downloaded=" << request.downloaded;
155
- url << "&left=" << request.left;
156
- url << "&compact=1"; // Request compact peer list (BEP 23)
157
-
158
- // Optional parameters
159
- if (request.event != TrackerEvent::NONE) {
160
- url << "&event=" << tracker_event_to_string(request.event);
161
- }
162
-
163
- if (!request.ip.empty()) {
164
- url << "&ip=" << url_encode(request.ip);
165
- }
166
-
167
- if (request.numwant > 0) {
168
- url << "&numwant=" << request.numwant;
169
- }
170
-
171
- if (!request.tracker_id.empty()) {
172
- url << "&trackerid=" << url_encode(request.tracker_id);
173
- } else if (!tracker_id_.empty()) {
174
- url << "&trackerid=" << url_encode(tracker_id_);
175
- }
176
-
177
- return url.str();
178
- }
179
-
180
- std::string HttpTrackerClient::build_scrape_url(const std::vector<InfoHash>& info_hashes) {
181
- // Convert announce URL to scrape URL by replacing "announce" with "scrape"
182
- std::string scrape_url = tracker_url_;
183
-
184
- size_t announce_pos = scrape_url.find("announce");
185
- if (announce_pos == std::string::npos) {
186
- return ""; // Cannot build scrape URL
187
- }
188
-
189
- scrape_url.replace(announce_pos, 8, "scrape");
190
-
191
- // Add info_hash parameters
192
- bool first = true;
193
- for (const auto& info_hash : info_hashes) {
194
- if (first) {
195
- scrape_url += "?";
196
- first = false;
197
- } else {
198
- scrape_url += "&";
199
- }
200
- scrape_url += "info_hash=" + url_encode_binary(info_hash.data(), info_hash.size());
201
- }
202
-
203
- return scrape_url;
204
- }
205
-
206
- TrackerResponse HttpTrackerClient::parse_response(const std::vector<uint8_t>& data) {
207
- TrackerResponse response;
208
-
209
- try {
210
- BencodeValue tracker_response = bencode::decode(data);
211
-
212
- if (!tracker_response.is_dict()) {
213
- response.failure_reason = "Invalid tracker response format";
214
- return response;
215
- }
216
-
217
- // Check for failure reason
218
- if (tracker_response.has_key("failure reason")) {
219
- response.failure_reason = tracker_response["failure reason"].as_string();
220
- response.success = false;
221
- return response;
222
- }
223
-
224
- // Parse warning message
225
- if (tracker_response.has_key("warning message")) {
226
- response.warning_message = tracker_response["warning message"].as_string();
227
- LOG_TRACKER_WARN("Tracker warning: " << response.warning_message);
228
- }
229
-
230
- // Parse interval
231
- if (tracker_response.has_key("interval")) {
232
- response.interval = static_cast<uint32_t>(tracker_response["interval"].as_integer());
233
- }
234
-
235
- // Parse min interval
236
- if (tracker_response.has_key("min interval")) {
237
- response.min_interval = static_cast<uint32_t>(tracker_response["min interval"].as_integer());
238
- }
239
-
240
- // Parse tracker ID
241
- if (tracker_response.has_key("tracker id")) {
242
- response.tracker_id = tracker_response["tracker id"].as_string();
243
- }
244
-
245
- // Parse complete (seeders)
246
- if (tracker_response.has_key("complete")) {
247
- response.complete = static_cast<uint32_t>(tracker_response["complete"].as_integer());
248
- }
249
-
250
- // Parse incomplete (leechers)
251
- if (tracker_response.has_key("incomplete")) {
252
- response.incomplete = static_cast<uint32_t>(tracker_response["incomplete"].as_integer());
253
- }
254
-
255
- // Parse peers
256
- if (tracker_response.has_key("peers")) {
257
- const auto& peers_value = tracker_response["peers"];
258
-
259
- if (peers_value.is_string()) {
260
- // Compact peer list (BEP 23)
261
- response.peers = parse_compact_peers(peers_value.as_string());
262
- } else if (peers_value.is_list()) {
263
- // Dictionary peer list
264
- response.peers = parse_dict_peers(peers_value);
265
- }
266
- }
267
-
268
- response.success = true;
269
-
270
- } catch (const std::exception& e) {
271
- LOG_TRACKER_ERROR("Failed to parse tracker response: " << e.what());
272
- response.failure_reason = std::string("Parse error: ") + e.what();
273
- response.success = false;
274
- }
275
-
276
- return response;
277
- }
278
-
279
- std::vector<Peer> HttpTrackerClient::parse_compact_peers(const std::string& peer_data) {
280
- std::vector<Peer> peers;
281
-
282
- // Each peer is 6 bytes: 4 bytes IP + 2 bytes port
283
- if (peer_data.length() % 6 != 0) {
284
- LOG_TRACKER_WARN("Invalid compact peer list length: " << peer_data.length());
285
- return peers;
286
- }
287
-
288
- for (size_t i = 0; i < peer_data.length(); i += 6) {
289
- const uint8_t* peer_bytes = reinterpret_cast<const uint8_t*>(peer_data.data() + i);
290
-
291
- // Extract IP address
292
- std::ostringstream ip_stream;
293
- ip_stream << static_cast<int>(peer_bytes[0]) << "."
294
- << static_cast<int>(peer_bytes[1]) << "."
295
- << static_cast<int>(peer_bytes[2]) << "."
296
- << static_cast<int>(peer_bytes[3]);
297
-
298
- // Extract port (big-endian)
299
- uint16_t port = (peer_bytes[4] << 8) | peer_bytes[5];
300
-
301
- peers.emplace_back(ip_stream.str(), port);
302
- }
303
-
304
- LOG_TRACKER_DEBUG("Parsed " << peers.size() << " compact peers");
305
- return peers;
306
- }
307
-
308
- std::vector<Peer> HttpTrackerClient::parse_dict_peers(const BencodeValue& peers_list) {
309
- std::vector<Peer> peers;
310
-
311
- for (size_t i = 0; i < peers_list.size(); ++i) {
312
- const auto& peer_dict = peers_list[i];
313
-
314
- if (!peer_dict.is_dict()) {
315
- continue;
316
- }
317
-
318
- if (!peer_dict.has_key("ip") || !peer_dict.has_key("port")) {
319
- continue;
320
- }
321
-
322
- std::string ip = peer_dict["ip"].as_string();
323
- uint16_t port = static_cast<uint16_t>(peer_dict["port"].as_integer());
324
-
325
- peers.emplace_back(ip, port);
326
- }
327
-
328
- LOG_TRACKER_DEBUG("Parsed " << peers.size() << " dictionary peers");
329
- return peers;
330
- }
331
-
332
- std::vector<uint8_t> HttpTrackerClient::http_get(const std::string& url) {
333
- LOG_TRACKER_DEBUG("HTTP GET: " << url);
334
-
335
- // Parse URL to extract host, port, and path
336
- std::string protocol, host, path;
337
- uint16_t port = 80;
338
-
339
- size_t protocol_end = url.find("://");
340
- if (protocol_end != std::string::npos) {
341
- protocol = url.substr(0, protocol_end);
342
- size_t host_start = protocol_end + 3;
343
- size_t path_start = url.find('/', host_start);
344
-
345
- if (path_start != std::string::npos) {
346
- std::string host_port = url.substr(host_start, path_start - host_start);
347
- path = url.substr(path_start);
348
-
349
- size_t port_pos = host_port.find(':');
350
- if (port_pos != std::string::npos) {
351
- host = host_port.substr(0, port_pos);
352
- port = static_cast<uint16_t>(std::stoi(host_port.substr(port_pos + 1)));
353
- } else {
354
- host = host_port;
355
- port = (protocol == "https") ? 443 : 80;
356
- }
357
- } else {
358
- host = url.substr(host_start);
359
- path = "/";
360
- }
361
- } else {
362
- LOG_TRACKER_ERROR("Invalid URL format: " << url);
363
- return std::vector<uint8_t>();
364
- }
365
-
366
- // Create TCP connection
367
- socket_t socket = create_tcp_client(host, port, 15000); // 15 second timeout
368
- if (!is_valid_socket(socket)) {
369
- LOG_TRACKER_ERROR("Failed to connect to tracker: " << host << ":" << port);
370
- return std::vector<uint8_t>();
371
- }
372
-
373
- // Build HTTP request
374
- std::ostringstream request;
375
- request << "GET " << path << " HTTP/1.0\r\n";
376
- request << "Host: " << host << "\r\n";
377
- request << "User-Agent: librats/1.0\r\n";
378
- request << "Accept: */*\r\n";
379
- request << "Connection: close\r\n";
380
- request << "\r\n";
381
-
382
- std::string request_str = request.str();
383
-
384
- // Send request
385
- if (send_tcp_string(socket, request_str) <= 0) {
386
- LOG_TRACKER_ERROR("Failed to send HTTP request");
387
- close_socket(socket);
388
- return std::vector<uint8_t>();
389
- }
390
-
391
- // Receive response
392
- std::vector<uint8_t> response_data;
393
- bool headers_complete = false;
394
- size_t content_start = 0;
395
-
396
- while (true) {
397
- std::vector<uint8_t> chunk = receive_tcp_data(socket, 4096);
398
- if (chunk.empty()) {
399
- break; // Connection closed or error
400
- }
401
-
402
- response_data.insert(response_data.end(), chunk.begin(), chunk.end());
403
-
404
- // Find end of headers
405
- if (!headers_complete) {
406
- std::string response_str(response_data.begin(), response_data.end());
407
- size_t header_end = response_str.find("\r\n\r\n");
408
- if (header_end != std::string::npos) {
409
- headers_complete = true;
410
- content_start = header_end + 4;
411
- }
412
- }
413
- }
414
-
415
- close_socket(socket);
416
-
417
- if (!headers_complete || content_start >= response_data.size()) {
418
- LOG_TRACKER_ERROR("Invalid HTTP response");
419
- return std::vector<uint8_t>();
420
- }
421
-
422
- // Extract body
423
- std::vector<uint8_t> body(response_data.begin() + content_start, response_data.end());
424
-
425
- LOG_TRACKER_DEBUG("HTTP response body size: " << body.size() << " bytes");
426
- return body;
427
- }
428
-
429
- std::string HttpTrackerClient::url_encode(const std::string& str) {
430
- std::ostringstream escaped;
431
- escaped.fill('0');
432
- escaped << std::hex;
433
-
434
- for (char c : str) {
435
- // Keep alphanumeric and other safe characters
436
- if (isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~') {
437
- escaped << c;
438
- } else {
439
- // Percent-encode
440
- escaped << '%' << std::setw(2) << int(static_cast<unsigned char>(c));
441
- }
442
- }
443
-
444
- return escaped.str();
445
- }
446
-
447
- std::string HttpTrackerClient::url_encode_binary(const uint8_t* data, size_t len) {
448
- std::ostringstream escaped;
449
- escaped.fill('0');
450
- escaped << std::hex << std::uppercase;
451
-
452
- for (size_t i = 0; i < len; ++i) {
453
- uint8_t c = data[i];
454
- // Keep alphanumeric and other safe characters
455
- if (isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~') {
456
- escaped << static_cast<char>(c);
457
- } else {
458
- // Percent-encode
459
- escaped << '%' << std::setw(2) << static_cast<int>(c);
460
- }
461
- }
462
-
463
- return escaped.str();
464
- }
465
-
466
- //=============================================================================
467
- // UdpTrackerClient Implementation
468
- //=============================================================================
469
-
470
- UdpTrackerClient::UdpTrackerClient(const std::string& tracker_url)
471
- : tracker_url_(tracker_url), port_(0), socket_(INVALID_SOCKET_VALUE),
472
- interval_(1800), is_working_(true), connection_id_(0) {
473
-
474
- if (parse_url()) {
475
- LOG_TRACKER_INFO("Created UDP tracker client for: " << hostname_ << ":" << port_);
476
- } else {
477
- LOG_TRACKER_ERROR("Failed to parse UDP tracker URL: " << tracker_url_);
478
- is_working_ = false;
479
- }
480
- }
481
-
482
- UdpTrackerClient::~UdpTrackerClient() {
483
- std::lock_guard<std::mutex> lock(socket_mutex_);
484
- if (is_valid_socket(socket_)) {
485
- close_socket(socket_);
486
- socket_ = INVALID_SOCKET_VALUE;
487
- }
488
- }
489
-
490
- bool UdpTrackerClient::parse_url() {
491
- // Parse udp://hostname:port
492
- if (tracker_url_.substr(0, 6) != "udp://") {
493
- return false;
494
- }
495
-
496
- std::string host_port = tracker_url_.substr(6);
497
- size_t colon_pos = host_port.find(':');
498
-
499
- if (colon_pos == std::string::npos) {
500
- return false;
501
- }
502
-
503
- hostname_ = host_port.substr(0, colon_pos);
504
-
505
- // Extract port and remove any path
506
- std::string port_str = host_port.substr(colon_pos + 1);
507
- size_t slash_pos = port_str.find('/');
508
- if (slash_pos != std::string::npos) {
509
- port_str = port_str.substr(0, slash_pos);
510
- }
511
-
512
- try {
513
- port_ = static_cast<uint16_t>(std::stoi(port_str));
514
- } catch (const std::exception&) {
515
- return false;
516
- }
517
-
518
- return true;
519
- }
520
-
521
- bool UdpTrackerClient::connect() {
522
- // Create UDP socket if needed (protected by mutex)
523
- {
524
- std::lock_guard<std::mutex> lock(socket_mutex_);
525
- if (!is_valid_socket(socket_)) {
526
- socket_ = create_udp_socket();
527
- if (!is_valid_socket(socket_)) {
528
- LOG_TRACKER_ERROR("Failed to create UDP socket for tracker");
529
- return false;
530
- }
531
- }
532
- }
533
-
534
- LOG_TRACKER_DEBUG("Connecting to UDP tracker: " << hostname_ << ":" << port_);
535
-
536
- uint32_t transaction_id = generate_transaction_id();
537
- std::vector<uint8_t> connect_request = build_connect_request(transaction_id);
538
-
539
- // Send connect request and receive response (send_request handles its own locking)
540
- std::vector<uint8_t> response = send_request(connect_request, 15000);
541
-
542
- if (response.empty()) {
543
- LOG_TRACKER_ERROR("No response from UDP tracker");
544
- return false;
545
- }
546
-
547
- if (!parse_connect_response(response, transaction_id)) {
548
- LOG_TRACKER_ERROR("Failed to parse connect response");
549
- return false;
550
- }
551
-
552
- // Connection is valid for 1 minute
553
- connection_expire_time_ = std::chrono::steady_clock::now() + std::chrono::seconds(60);
554
-
555
- LOG_TRACKER_INFO("Successfully connected to UDP tracker");
556
- return true;
557
- }
558
-
559
- bool UdpTrackerClient::is_connection_valid() {
560
- return connection_id_ != 0 &&
561
- std::chrono::steady_clock::now() < connection_expire_time_;
562
- }
563
-
564
- bool UdpTrackerClient::announce(const TrackerRequest& request, TrackerResponseCallback callback) {
565
- LOG_TRACKER_INFO("Announcing to UDP tracker: " << tracker_url_);
566
-
567
- // Connect if needed
568
- if (!is_connection_valid()) {
569
- if (!connect()) {
570
- is_working_ = false;
571
-
572
- TrackerResponse error_response;
573
- error_response.success = false;
574
- error_response.failure_reason = "Failed to connect to UDP tracker";
575
- if (callback) callback(error_response, tracker_url_);
576
-
577
- return false;
578
- }
579
- }
580
-
581
- uint32_t transaction_id = generate_transaction_id();
582
- std::vector<uint8_t> announce_request = build_announce_request(request, transaction_id);
583
-
584
- // Send announce request
585
- std::vector<uint8_t> response = send_request(announce_request, 15000);
586
-
587
- if (response.empty()) {
588
- LOG_TRACKER_ERROR("No response from UDP tracker announce");
589
- is_working_ = false;
590
-
591
- TrackerResponse error_response;
592
- error_response.success = false;
593
- error_response.failure_reason = "No response from tracker";
594
- if (callback) callback(error_response, tracker_url_);
595
-
596
- return false;
597
- }
598
-
599
- // Check for error response
600
- if (response.size() >= 8) {
601
- uint32_t action = read_uint32_be(response.data());
602
- if (action == ACTION_ERROR) {
603
- std::string error_msg = parse_error_response(response);
604
- LOG_TRACKER_ERROR("UDP tracker error: " << error_msg);
605
- is_working_ = false;
606
-
607
- TrackerResponse error_response;
608
- error_response.success = false;
609
- error_response.failure_reason = error_msg;
610
- if (callback) callback(error_response, tracker_url_);
611
-
612
- return false;
613
- }
614
- }
615
-
616
- TrackerResponse tracker_response = parse_announce_response(response, transaction_id);
617
-
618
- if (tracker_response.success) {
619
- last_announce_time_ = std::chrono::steady_clock::now();
620
- interval_ = tracker_response.interval;
621
- is_working_ = true;
622
-
623
- LOG_TRACKER_INFO("UDP announce successful. Peers: " << tracker_response.peers.size()
624
- << ", Seeders: " << tracker_response.complete
625
- << ", Leechers: " << tracker_response.incomplete);
626
- } else {
627
- LOG_TRACKER_ERROR("UDP tracker announce failed: " << tracker_response.failure_reason);
628
- is_working_ = false;
629
- }
630
-
631
- if (callback) {
632
- callback(tracker_response, tracker_url_);
633
- }
634
-
635
- return tracker_response.success;
636
- }
637
-
638
- bool UdpTrackerClient::scrape(const std::vector<InfoHash>& info_hashes, TrackerResponseCallback callback) {
639
- LOG_TRACKER_INFO("Scraping UDP tracker: " << tracker_url_);
640
-
641
- // Connect if needed
642
- if (!is_connection_valid()) {
643
- if (!connect()) {
644
- return false;
645
- }
646
- }
647
-
648
- uint32_t transaction_id = generate_transaction_id();
649
- std::vector<uint8_t> scrape_request = build_scrape_request(info_hashes, transaction_id);
650
-
651
- // Send scrape request
652
- std::vector<uint8_t> response = send_request(scrape_request, 15000);
653
-
654
- if (response.empty()) {
655
- LOG_TRACKER_ERROR("No response from UDP tracker scrape");
656
- return false;
657
- }
658
-
659
- TrackerResponse tracker_response = parse_scrape_response(response, transaction_id);
660
-
661
- if (callback) {
662
- callback(tracker_response, tracker_url_);
663
- }
664
-
665
- return tracker_response.success;
666
- }
667
-
668
- std::vector<uint8_t> UdpTrackerClient::send_request(const std::vector<uint8_t>& request, int timeout_ms) {
669
- std::lock_guard<std::mutex> lock(socket_mutex_);
670
-
671
- if (!is_valid_socket(socket_)) {
672
- return std::vector<uint8_t>();
673
- }
674
-
675
- // Send request
676
- if (send_udp_data(socket_, request, hostname_, port_) <= 0) {
677
- return std::vector<uint8_t>();
678
- }
679
-
680
- // Receive response with timeout
681
- Peer sender;
682
- std::vector<uint8_t> response = receive_udp_data(socket_, 2048, sender, timeout_ms);
683
-
684
- return response;
685
- }
686
-
687
- std::vector<uint8_t> UdpTrackerClient::build_connect_request(uint32_t transaction_id) {
688
- std::vector<uint8_t> request(16);
689
-
690
- // Protocol ID (64-bit)
691
- write_int64_be(request.data(), PROTOCOL_ID);
692
-
693
- // Action: connect (32-bit)
694
- write_uint32_be(request.data() + 8, ACTION_CONNECT);
695
-
696
- // Transaction ID (32-bit)
697
- write_uint32_be(request.data() + 12, transaction_id);
698
-
699
- return request;
700
- }
701
-
702
- std::vector<uint8_t> UdpTrackerClient::build_announce_request(const TrackerRequest& request, uint32_t transaction_id) {
703
- std::vector<uint8_t> announce_req(98);
704
-
705
- size_t offset = 0;
706
-
707
- // Connection ID (64-bit)
708
- write_int64_be(announce_req.data() + offset, connection_id_);
709
- offset += 8;
710
-
711
- // Action: announce (32-bit)
712
- write_uint32_be(announce_req.data() + offset, ACTION_ANNOUNCE);
713
- offset += 4;
714
-
715
- // Transaction ID (32-bit)
716
- write_uint32_be(announce_req.data() + offset, transaction_id);
717
- offset += 4;
718
-
719
- // Info hash (20 bytes)
720
- std::memcpy(announce_req.data() + offset, request.info_hash.data(), 20);
721
- offset += 20;
722
-
723
- // Peer ID (20 bytes)
724
- std::memcpy(announce_req.data() + offset, request.peer_id.data(), 20);
725
- offset += 20;
726
-
727
- // Downloaded (64-bit)
728
- write_int64_be(announce_req.data() + offset, request.downloaded);
729
- offset += 8;
730
-
731
- // Left (64-bit)
732
- write_int64_be(announce_req.data() + offset, request.left);
733
- offset += 8;
734
-
735
- // Uploaded (64-bit)
736
- write_int64_be(announce_req.data() + offset, request.uploaded);
737
- offset += 8;
738
-
739
- // Event (32-bit)
740
- write_uint32_be(announce_req.data() + offset, static_cast<uint32_t>(request.event));
741
- offset += 4;
742
-
743
- // IP address (32-bit, 0 for default)
744
- write_uint32_be(announce_req.data() + offset, 0);
745
- offset += 4;
746
-
747
- // Key (32-bit, random)
748
- write_uint32_be(announce_req.data() + offset, generate_transaction_id());
749
- offset += 4;
750
-
751
- // Num want (32-bit, -1 for default)
752
- write_uint32_be(announce_req.data() + offset, request.numwant > 0 ? request.numwant : 50);
753
- offset += 4;
754
-
755
- // Port (16-bit)
756
- announce_req[offset] = (request.port >> 8) & 0xFF;
757
- announce_req[offset + 1] = request.port & 0xFF;
758
-
759
- return announce_req;
760
- }
761
-
762
- std::vector<uint8_t> UdpTrackerClient::build_scrape_request(const std::vector<InfoHash>& info_hashes, uint32_t transaction_id) {
763
- std::vector<uint8_t> scrape_req(16 + info_hashes.size() * 20);
764
-
765
- size_t offset = 0;
766
-
767
- // Connection ID (64-bit)
768
- write_int64_be(scrape_req.data() + offset, connection_id_);
769
- offset += 8;
770
-
771
- // Action: scrape (32-bit)
772
- write_uint32_be(scrape_req.data() + offset, ACTION_SCRAPE);
773
- offset += 4;
774
-
775
- // Transaction ID (32-bit)
776
- write_uint32_be(scrape_req.data() + offset, transaction_id);
777
- offset += 4;
778
-
779
- // Info hashes (20 bytes each)
780
- for (const auto& info_hash : info_hashes) {
781
- std::memcpy(scrape_req.data() + offset, info_hash.data(), 20);
782
- offset += 20;
783
- }
784
-
785
- return scrape_req;
786
- }
787
-
788
- bool UdpTrackerClient::parse_connect_response(const std::vector<uint8_t>& data, uint32_t expected_transaction_id) {
789
- if (data.size() < 16) {
790
- LOG_TRACKER_ERROR("Invalid connect response size: " << data.size());
791
- return false;
792
- }
793
-
794
- uint32_t action = read_uint32_be(data.data());
795
- uint32_t transaction_id = read_uint32_be(data.data() + 4);
796
-
797
- if (action != ACTION_CONNECT) {
798
- LOG_TRACKER_ERROR("Invalid action in connect response: " << action);
799
- return false;
800
- }
801
-
802
- if (transaction_id != expected_transaction_id) {
803
- LOG_TRACKER_ERROR("Transaction ID mismatch in connect response");
804
- return false;
805
- }
806
-
807
- connection_id_ = read_int64_be(data.data() + 8);
808
-
809
- LOG_TRACKER_DEBUG("Received connection ID: " << connection_id_);
810
- return true;
811
- }
812
-
813
- TrackerResponse UdpTrackerClient::parse_announce_response(const std::vector<uint8_t>& data, uint32_t expected_transaction_id) {
814
- TrackerResponse response;
815
-
816
- if (data.size() < 20) {
817
- response.failure_reason = "Invalid announce response size";
818
- return response;
819
- }
820
-
821
- uint32_t action = read_uint32_be(data.data());
822
- uint32_t transaction_id = read_uint32_be(data.data() + 4);
823
-
824
- if (action != ACTION_ANNOUNCE) {
825
- response.failure_reason = "Invalid action in announce response";
826
- return response;
827
- }
828
-
829
- if (transaction_id != expected_transaction_id) {
830
- response.failure_reason = "Transaction ID mismatch";
831
- return response;
832
- }
833
-
834
- // Parse response fields
835
- response.interval = read_uint32_be(data.data() + 8);
836
- response.incomplete = read_uint32_be(data.data() + 12);
837
- response.complete = read_uint32_be(data.data() + 16);
838
-
839
- // Parse peer list (6 bytes per peer: 4 bytes IP + 2 bytes port)
840
- size_t peers_offset = 20;
841
- while (peers_offset + 6 <= data.size()) {
842
- const uint8_t* peer_data = data.data() + peers_offset;
843
-
844
- std::ostringstream ip_stream;
845
- ip_stream << static_cast<int>(peer_data[0]) << "."
846
- << static_cast<int>(peer_data[1]) << "."
847
- << static_cast<int>(peer_data[2]) << "."
848
- << static_cast<int>(peer_data[3]);
849
-
850
- uint16_t port = (peer_data[4] << 8) | peer_data[5];
851
-
852
- response.peers.emplace_back(ip_stream.str(), port);
853
- peers_offset += 6;
854
- }
855
-
856
- response.success = true;
857
- return response;
858
- }
859
-
860
- TrackerResponse UdpTrackerClient::parse_scrape_response(const std::vector<uint8_t>& data, uint32_t expected_transaction_id) {
861
- TrackerResponse response;
862
-
863
- if (data.size() < 8) {
864
- response.failure_reason = "Invalid scrape response size";
865
- return response;
866
- }
867
-
868
- uint32_t action = read_uint32_be(data.data());
869
- uint32_t transaction_id = read_uint32_be(data.data() + 4);
870
-
871
- if (action != ACTION_SCRAPE) {
872
- response.failure_reason = "Invalid action in scrape response";
873
- return response;
874
- }
875
-
876
- if (transaction_id != expected_transaction_id) {
877
- response.failure_reason = "Transaction ID mismatch";
878
- return response;
879
- }
880
-
881
- // Parse scrape data (12 bytes per torrent)
882
- if (data.size() >= 20) {
883
- response.complete = read_uint32_be(data.data() + 8);
884
- response.downloaded = read_uint32_be(data.data() + 12);
885
- response.incomplete = read_uint32_be(data.data() + 16);
886
- }
887
-
888
- response.success = true;
889
- return response;
890
- }
891
-
892
- std::string UdpTrackerClient::parse_error_response(const std::vector<uint8_t>& data) {
893
- if (data.size() < 8) {
894
- return "Unknown error";
895
- }
896
-
897
- // Error message starts at offset 8
898
- std::string error_msg(data.begin() + 8, data.end());
899
- return error_msg;
900
- }
901
-
902
- uint32_t UdpTrackerClient::generate_transaction_id() {
903
- static std::random_device rd;
904
- static std::mt19937 gen(rd());
905
- static std::uniform_int_distribution<uint32_t> dis;
906
- return dis(gen);
907
- }
908
-
909
- uint32_t UdpTrackerClient::read_uint32_be(const uint8_t* data) {
910
- return (static_cast<uint32_t>(data[0]) << 24) |
911
- (static_cast<uint32_t>(data[1]) << 16) |
912
- (static_cast<uint32_t>(data[2]) << 8) |
913
- static_cast<uint32_t>(data[3]);
914
- }
915
-
916
- void UdpTrackerClient::write_uint32_be(uint8_t* data, uint32_t value) {
917
- data[0] = (value >> 24) & 0xFF;
918
- data[1] = (value >> 16) & 0xFF;
919
- data[2] = (value >> 8) & 0xFF;
920
- data[3] = value & 0xFF;
921
- }
922
-
923
- int64_t UdpTrackerClient::read_int64_be(const uint8_t* data) {
924
- return (static_cast<int64_t>(data[0]) << 56) |
925
- (static_cast<int64_t>(data[1]) << 48) |
926
- (static_cast<int64_t>(data[2]) << 40) |
927
- (static_cast<int64_t>(data[3]) << 32) |
928
- (static_cast<int64_t>(data[4]) << 24) |
929
- (static_cast<int64_t>(data[5]) << 16) |
930
- (static_cast<int64_t>(data[6]) << 8) |
931
- static_cast<int64_t>(data[7]);
932
- }
933
-
934
- void UdpTrackerClient::write_int64_be(uint8_t* data, int64_t value) {
935
- data[0] = (value >> 56) & 0xFF;
936
- data[1] = (value >> 48) & 0xFF;
937
- data[2] = (value >> 40) & 0xFF;
938
- data[3] = (value >> 32) & 0xFF;
939
- data[4] = (value >> 24) & 0xFF;
940
- data[5] = (value >> 16) & 0xFF;
941
- data[6] = (value >> 8) & 0xFF;
942
- data[7] = value & 0xFF;
943
- }
944
-
945
- //=============================================================================
946
- // TrackerManager Implementation
947
- //=============================================================================
948
-
949
- TrackerManager::TrackerManager(const TorrentInfo& torrent_info)
950
- : info_hash_(torrent_info.info_hash()), announce_interval_(1800) {
951
-
952
- LOG_TRACKER_INFO("Creating tracker manager for torrent: " << torrent_info.name());
953
-
954
- // Add primary announce URL
955
- if (!torrent_info.announce().empty()) {
956
- add_tracker(torrent_info.announce());
957
- }
958
-
959
- // Add announce list (each tier is a vector of tracker URLs)
960
- for (const auto& tier : torrent_info.announce_list()) {
961
- for (const auto& tracker_url : tier) {
962
- if (tracker_url != torrent_info.announce()) {
963
- add_tracker(tracker_url);
964
- }
965
- }
966
- }
967
-
968
- LOG_TRACKER_INFO("Tracker manager initialized with " << trackers_.size() << " trackers");
969
- }
970
-
971
- TrackerManager::~TrackerManager() = default;
972
-
973
- bool TrackerManager::add_tracker(const std::string& tracker_url) {
974
- if (tracker_url.empty()) {
975
- return false;
976
- }
977
-
978
- std::lock_guard<std::mutex> lock(trackers_mutex_);
979
-
980
- // Check if tracker already exists
981
- for (const auto& tracker : trackers_) {
982
- if (tracker->get_url() == tracker_url) {
983
- return false;
984
- }
985
- }
986
-
987
- auto tracker_client = create_tracker_client(tracker_url);
988
- if (tracker_client) {
989
- trackers_.push_back(tracker_client);
990
- LOG_TRACKER_INFO("Added tracker: " << tracker_url);
991
- return true;
992
- }
993
-
994
- return false;
995
- }
996
-
997
- void TrackerManager::announce(const TrackerRequest& request, TrackerResponseCallback callback) {
998
- std::lock_guard<std::mutex> lock(trackers_mutex_);
999
-
1000
- LOG_TRACKER_INFO("Announcing to all trackers (" << trackers_.size() << " trackers)");
1001
-
1002
- for (auto& tracker : trackers_) {
1003
- // Skip non-working trackers
1004
- if (!tracker->is_working()) {
1005
- continue;
1006
- }
1007
-
1008
- // Announce in separate thread to avoid blocking
1009
- std::thread([tracker, request, callback]() {
1010
- tracker->announce(request, callback);
1011
- }).detach();
1012
- }
1013
-
1014
- last_announce_time_ = std::chrono::steady_clock::now();
1015
- }
1016
-
1017
- void TrackerManager::announce_to_best(const TrackerRequest& request, TrackerResponseCallback callback) {
1018
- std::lock_guard<std::mutex> lock(trackers_mutex_);
1019
-
1020
- // Sort trackers by priority
1021
- sort_trackers_by_priority();
1022
-
1023
- // Announce to first working tracker
1024
- for (auto& tracker : trackers_) {
1025
- if (tracker->is_working()) {
1026
- LOG_TRACKER_INFO("Announcing to best tracker: " << tracker->get_url());
1027
-
1028
- std::thread([tracker, request, callback]() {
1029
- tracker->announce(request, callback);
1030
- }).detach();
1031
-
1032
- last_announce_time_ = std::chrono::steady_clock::now();
1033
- return;
1034
- }
1035
- }
1036
-
1037
- LOG_TRACKER_WARN("No working trackers available for announce");
1038
- }
1039
-
1040
- void TrackerManager::scrape(TrackerResponseCallback callback) {
1041
- std::lock_guard<std::mutex> lock(trackers_mutex_);
1042
-
1043
- LOG_TRACKER_INFO("Scraping all trackers");
1044
-
1045
- for (auto& tracker : trackers_) {
1046
- if (!tracker->is_working()) {
1047
- continue;
1048
- }
1049
-
1050
- std::thread([tracker, callback, this]() {
1051
- tracker->scrape({info_hash_}, callback);
1052
- }).detach();
1053
- }
1054
- }
1055
-
1056
- size_t TrackerManager::get_working_tracker_count() const {
1057
- std::lock_guard<std::mutex> lock(trackers_mutex_);
1058
-
1059
- size_t count = 0;
1060
- for (const auto& tracker : trackers_) {
1061
- if (tracker->is_working()) {
1062
- ++count;
1063
- }
1064
- }
1065
-
1066
- return count;
1067
- }
1068
-
1069
- std::vector<std::string> TrackerManager::get_tracker_urls() const {
1070
- std::lock_guard<std::mutex> lock(trackers_mutex_);
1071
-
1072
- std::vector<std::string> urls;
1073
- for (const auto& tracker : trackers_) {
1074
- urls.push_back(tracker->get_url());
1075
- }
1076
-
1077
- return urls;
1078
- }
1079
-
1080
- bool TrackerManager::should_announce() const {
1081
- auto now = std::chrono::steady_clock::now();
1082
- auto time_since_last = std::chrono::duration_cast<std::chrono::seconds>(now - last_announce_time_).count();
1083
- return time_since_last >= announce_interval_;
1084
- }
1085
-
1086
- std::chrono::steady_clock::time_point TrackerManager::get_next_announce_time() const {
1087
- return last_announce_time_ + std::chrono::seconds(announce_interval_);
1088
- }
1089
-
1090
- std::shared_ptr<TrackerClient> TrackerManager::create_tracker_client(const std::string& tracker_url) {
1091
- if (tracker_url.substr(0, 4) == "http") {
1092
- // HTTP or HTTPS tracker
1093
- return std::make_shared<HttpTrackerClient>(tracker_url);
1094
- } else if (tracker_url.substr(0, 6) == "udp://") {
1095
- // UDP tracker
1096
- return std::make_shared<UdpTrackerClient>(tracker_url);
1097
- }
1098
-
1099
- LOG_TRACKER_WARN("Unsupported tracker protocol: " << tracker_url);
1100
- return nullptr;
1101
- }
1102
-
1103
- void TrackerManager::sort_trackers_by_priority() {
1104
- // Sort: working trackers first, then by last announce time
1105
- std::sort(trackers_.begin(), trackers_.end(),
1106
- [](const std::shared_ptr<TrackerClient>& a, const std::shared_ptr<TrackerClient>& b) {
1107
- if (a->is_working() != b->is_working()) {
1108
- return a->is_working();
1109
- }
1110
- return a->get_last_announce_time() < b->get_last_announce_time();
1111
- });
1112
- }
1113
-
1114
- //=============================================================================
1115
- // Simple Scrape API Implementation
1116
- //=============================================================================
1117
-
1118
- std::vector<std::string> get_default_trackers() {
1119
- // Common open trackers that support UDP scrape
1120
- return {
1121
- "udp://tracker.opentrackr.org:1337/announce",
1122
- "udp://tracker.openbittorrent.com:6969/announce",
1123
- "udp://open.stealth.si:80/announce",
1124
- "udp://tracker.torrent.eu.org:451/announce",
1125
- "udp://exodus.desync.com:6969/announce",
1126
- "udp://tracker.tiny-vps.com:6969/announce",
1127
- "udp://tracker.moeking.me:6969/announce",
1128
- "udp://opentracker.i2p.rocks:6969/announce"
1129
- };
1130
- }
1131
-
1132
- void scrape_tracker(const std::string& tracker_url,
1133
- const std::string& info_hash_hex,
1134
- ScrapeCallback callback,
1135
- int timeout_ms) {
1136
- ScrapeResult result;
1137
- result.tracker = tracker_url;
1138
-
1139
- // Validate hash
1140
- if (info_hash_hex.length() != 40) {
1141
- result.error = "Invalid hash length (expected 40 hex characters)";
1142
- if (callback) callback(result);
1143
- return;
1144
- }
1145
-
1146
- // Convert hex to InfoHash
1147
- InfoHash info_hash = hex_to_info_hash(info_hash_hex);
1148
-
1149
- // Check if hash conversion was successful
1150
- bool all_zero = true;
1151
- for (auto b : info_hash) {
1152
- if (b != 0) {
1153
- all_zero = false;
1154
- break;
1155
- }
1156
- }
1157
- if (all_zero) {
1158
- result.error = "Invalid hash format";
1159
- if (callback) callback(result);
1160
- return;
1161
- }
1162
-
1163
- // Create appropriate tracker client
1164
- std::shared_ptr<TrackerClient> client;
1165
-
1166
- if (tracker_url.substr(0, 6) == "udp://") {
1167
- client = std::make_shared<UdpTrackerClient>(tracker_url);
1168
- } else if (tracker_url.substr(0, 4) == "http") {
1169
- client = std::make_shared<HttpTrackerClient>(tracker_url);
1170
- } else {
1171
- result.error = "Unsupported tracker protocol";
1172
- if (callback) callback(result);
1173
- return;
1174
- }
1175
-
1176
- // Perform scrape
1177
- std::vector<InfoHash> hashes = {info_hash};
1178
-
1179
- bool success = client->scrape(hashes, [&result, callback](const TrackerResponse& response, const std::string& url) {
1180
- result.tracker = url;
1181
- if (response.success) {
1182
- result.seeders = response.complete;
1183
- result.leechers = response.incomplete;
1184
- result.completed = response.downloaded;
1185
- result.success = true;
1186
- } else {
1187
- result.error = response.failure_reason.empty() ? "Scrape failed" : response.failure_reason;
1188
- }
1189
- });
1190
-
1191
- if (!success && !result.success) {
1192
- if (result.error.empty()) {
1193
- result.error = "Failed to scrape tracker";
1194
- }
1195
- }
1196
-
1197
- if (callback) callback(result);
1198
- }
1199
-
1200
- void scrape_multiple_trackers(const std::string& info_hash_hex,
1201
- ScrapeCallback callback,
1202
- int timeout_ms) {
1203
- // Validate hash first
1204
- if (info_hash_hex.length() != 40) {
1205
- ScrapeResult result;
1206
- result.error = "Invalid hash length (expected 40 hex characters)";
1207
- if (callback) callback(result);
1208
- return;
1209
- }
1210
-
1211
- std::vector<std::string> trackers = get_default_trackers();
1212
-
1213
- if (trackers.empty()) {
1214
- ScrapeResult result;
1215
- result.error = "No trackers available";
1216
- if (callback) callback(result);
1217
- return;
1218
- }
1219
-
1220
- // Track best result
1221
- ScrapeResult best_result;
1222
- std::mutex result_mutex;
1223
- std::atomic<int> pending{static_cast<int>(trackers.size())};
1224
- std::atomic<bool> has_success{false};
1225
-
1226
- // Create threads to scrape each tracker concurrently
1227
- std::vector<std::thread> threads;
1228
- threads.reserve(trackers.size());
1229
-
1230
- for (const auto& tracker_url : trackers) {
1231
- threads.emplace_back([&, tracker_url]() {
1232
- scrape_tracker(tracker_url, info_hash_hex, [&](const ScrapeResult& result) {
1233
- std::lock_guard<std::mutex> lock(result_mutex);
1234
-
1235
- // Update best result if this one is better
1236
- if (result.success) {
1237
- if (!has_success.load() || result.seeders > best_result.seeders) {
1238
- best_result = result;
1239
- has_success.store(true);
1240
- }
1241
- }
1242
-
1243
- pending--;
1244
- }, timeout_ms);
1245
- });
1246
- }
1247
-
1248
- // Wait for all threads to complete
1249
- for (auto& t : threads) {
1250
- if (t.joinable()) {
1251
- t.join();
1252
- }
1253
- }
1254
-
1255
- // Return best result
1256
- if (!has_success.load()) {
1257
- best_result.error = "No tracker responded successfully";
1258
- }
1259
-
1260
- if (callback) callback(best_result);
1261
- }
1262
-
1263
- } // namespace librats
1264
-