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,1007 +0,0 @@
1
- #include "bt_network.h"
2
- #include "network_utils.h"
3
- #include "logger.h"
4
-
5
- #include <algorithm>
6
- #include <cstring>
7
-
8
- #ifdef _WIN32
9
- #include <winsock2.h>
10
- #include <ws2tcpip.h>
11
- #else
12
- #include <netinet/tcp.h>
13
- #include <fcntl.h>
14
- #include <errno.h>
15
- #endif
16
-
17
- // Module logging macros
18
- #define LOG_NET_DEBUG(msg) LOG_DEBUG("BtNetwork", msg)
19
- #define LOG_NET_INFO(msg) LOG_INFO("BtNetwork", msg)
20
- #define LOG_NET_WARN(msg) LOG_WARN("BtNetwork", msg)
21
- #define LOG_NET_ERROR(msg) LOG_ERROR("BtNetwork", msg)
22
-
23
- namespace librats {
24
-
25
- //=============================================================================
26
- // BtNetworkManager Construction
27
- //=============================================================================
28
-
29
- BtNetworkManager::BtNetworkManager(const BtNetworkConfig& config)
30
- : config_(config)
31
- , running_(false)
32
- , actual_listen_port_(0)
33
- , listen_socket_(INVALID_SOCKET_VALUE) {
34
- }
35
-
36
- BtNetworkManager::~BtNetworkManager() {
37
- stop();
38
- }
39
-
40
- //=============================================================================
41
- // TCP_NODELAY helper
42
- //=============================================================================
43
-
44
- bool BtNetworkManager::set_tcp_nodelay(socket_t sock) {
45
- int flag = 1;
46
- int result = setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
47
- reinterpret_cast<const char*>(&flag), sizeof(flag));
48
- if (result < 0) {
49
- LOG_NET_WARN("Failed to set TCP_NODELAY on socket " + std::to_string(static_cast<int>(sock)));
50
- return false;
51
- }
52
- return true;
53
- }
54
-
55
- //=============================================================================
56
- // Lifecycle
57
- //=============================================================================
58
-
59
- bool BtNetworkManager::start() {
60
- if (running_) return true;
61
-
62
- // Initialize socket library (required on Windows)
63
- if (!init_socket_library()) {
64
- LOG_NET_ERROR("Failed to initialize socket library");
65
- return false;
66
- }
67
-
68
- // Create the I/O poller
69
- poller_ = IOPoller::create();
70
- if (!poller_) {
71
- LOG_NET_ERROR("Failed to create I/O poller");
72
- return false;
73
- }
74
- LOG_NET_INFO("Using I/O backend: " + std::string(poller_->name()));
75
-
76
- // Create listen socket if incoming enabled
77
- if (config_.enable_incoming) {
78
- listen_socket_ = create_tcp_server(config_.listen_port, 50);
79
- if (!is_valid_socket(listen_socket_)) {
80
- LOG_NET_ERROR("Failed to create listen socket on port " +
81
- std::to_string(config_.listen_port));
82
- return false;
83
- }
84
-
85
- // Set non-blocking
86
- if (!set_socket_nonblocking(listen_socket_)) {
87
- LOG_NET_ERROR("Failed to set listen socket non-blocking");
88
- close_socket(listen_socket_);
89
- listen_socket_ = INVALID_SOCKET_VALUE;
90
- return false;
91
- }
92
-
93
- // Get actual port (in case 0 was specified)
94
- actual_listen_port_ = static_cast<uint16_t>(get_bound_port(listen_socket_));
95
- if (actual_listen_port_ == 0) {
96
- actual_listen_port_ = config_.listen_port;
97
- }
98
-
99
- // Register listen socket with poller (interested in incoming connections)
100
- poller_->add(listen_socket_, PollIn);
101
- poller_state_[listen_socket_] = PollIn;
102
-
103
- LOG_NET_INFO("Listening on port " + std::to_string(actual_listen_port_));
104
- }
105
-
106
- running_ = true;
107
-
108
- // Start I/O thread
109
- io_thread_ = std::thread(&BtNetworkManager::io_loop, this);
110
-
111
- LOG_NET_INFO("Network manager started");
112
- return true;
113
- }
114
-
115
- void BtNetworkManager::stop() {
116
- if (!running_) return;
117
-
118
- running_ = false;
119
-
120
- // Wait for I/O thread
121
- if (io_thread_.joinable()) {
122
- io_thread_.join();
123
- }
124
-
125
- std::vector<DisconnectedEvent> disconnected_events;
126
-
127
- {
128
- std::lock_guard<std::mutex> lock(mutex_);
129
-
130
- // Collect disconnected events for all connections
131
- for (auto& [socket, ctx] : connections_) {
132
- if (ctx.connection) {
133
- DisconnectedEvent event;
134
- event.info_hash = ctx.info_hash;
135
- event.connection = ctx.connection;
136
- disconnected_events.push_back(std::move(event));
137
- }
138
- poller_->remove(socket);
139
- close_socket(socket, true);
140
- }
141
- connections_.clear();
142
-
143
- // Close connecting sockets
144
- for (auto& [socket, pending] : connecting_) {
145
- poller_->remove(socket);
146
- close_socket(socket, true);
147
- }
148
- connecting_.clear();
149
-
150
- // Clear pending queue
151
- while (!pending_connects_.empty()) {
152
- pending_connects_.pop();
153
- }
154
-
155
- // Close listen socket
156
- if (is_valid_socket(listen_socket_)) {
157
- poller_->remove(listen_socket_);
158
- close_socket(listen_socket_);
159
- listen_socket_ = INVALID_SOCKET_VALUE;
160
- }
161
-
162
- poller_state_.clear();
163
- poller_.reset();
164
-
165
- LOG_NET_INFO("Network manager stopped");
166
- }
167
-
168
- // Invoke callbacks outside mutex
169
- for (const auto& event : disconnected_events) {
170
- if (on_disconnected_) {
171
- on_disconnected_(event.info_hash, event.connection.get());
172
- }
173
- }
174
- }
175
-
176
- //=============================================================================
177
- // Torrent Registration
178
- //=============================================================================
179
-
180
- void BtNetworkManager::register_torrent(const BtInfoHash& info_hash,
181
- const PeerID& peer_id,
182
- uint32_t num_pieces) {
183
- std::lock_guard<std::mutex> lock(mutex_);
184
-
185
- TorrentRegistration reg;
186
- reg.info_hash = info_hash;
187
- reg.peer_id = peer_id;
188
- reg.num_pieces = num_pieces;
189
-
190
- torrents_[info_hash] = reg;
191
-
192
- LOG_NET_DEBUG("Registered torrent " + info_hash_to_hex(info_hash).substr(0, 8) + "...");
193
- }
194
-
195
- void BtNetworkManager::unregister_torrent(const BtInfoHash& info_hash) {
196
- std::vector<DisconnectedEvent> disconnected_events;
197
-
198
- {
199
- std::lock_guard<std::mutex> lock(mutex_);
200
-
201
- // Close all connections for this torrent
202
- std::vector<socket_t> to_close;
203
- for (auto& [socket, ctx] : connections_) {
204
- if (ctx.info_hash == info_hash) {
205
- to_close.push_back(socket);
206
- }
207
- }
208
-
209
- for (socket_t s : to_close) {
210
- close_connection_internal(s, disconnected_events);
211
- }
212
-
213
- torrents_.erase(info_hash);
214
-
215
- LOG_NET_DEBUG("Unregistered torrent " + info_hash_to_hex(info_hash).substr(0, 8) + "...");
216
- }
217
-
218
- // Invoke callbacks outside mutex
219
- for (const auto& event : disconnected_events) {
220
- if (on_disconnected_) {
221
- on_disconnected_(event.info_hash, event.connection.get());
222
- }
223
- }
224
- }
225
-
226
- //=============================================================================
227
- // Connection Management
228
- //=============================================================================
229
-
230
- bool BtNetworkManager::connect_peer(const std::string& ip, uint16_t port,
231
- const BtInfoHash& info_hash,
232
- const PeerID& peer_id,
233
- uint32_t num_pieces) {
234
- std::lock_guard<std::mutex> lock(mutex_);
235
-
236
- // Check connection limit (include pending queue in the count)
237
- size_t total = connections_.size() + connecting_.size() + pending_connects_.size();
238
- if (total >= config_.max_connections) {
239
- LOG_NET_DEBUG("Connection limit reached, cannot connect to " + ip);
240
- return false;
241
- }
242
-
243
- // Check if already connected/connecting to this peer
244
- for (const auto& [sock, ctx] : connections_) {
245
- if (ctx.connection && ctx.connection->ip() == ip &&
246
- ctx.connection->port() == port) {
247
- LOG_NET_DEBUG("Already connected to " + ip + ":" + std::to_string(port));
248
- return false;
249
- }
250
- }
251
-
252
- for (const auto& [sock, pending] : connecting_) {
253
- if (pending.ip == ip && pending.port == port) {
254
- LOG_NET_DEBUG("Already connecting to " + ip + ":" + std::to_string(port));
255
- return false;
256
- }
257
- }
258
-
259
- // Check pending queue for duplicates
260
- // Note: std::queue doesn't support iteration, so we use a temporary copy
261
- std::queue<PendingConnect> temp_queue = pending_connects_;
262
- while (!temp_queue.empty()) {
263
- const auto& queued = temp_queue.front();
264
- if (queued.ip == ip && queued.port == port) {
265
- LOG_NET_DEBUG("Already queued connection to " + ip + ":" + std::to_string(port));
266
- return false;
267
- }
268
- temp_queue.pop();
269
- }
270
-
271
- // Queue the connection
272
- PendingConnect pending;
273
- pending.ip = ip;
274
- pending.port = port;
275
- pending.info_hash = info_hash;
276
- pending.peer_id = peer_id;
277
- pending.num_pieces = num_pieces;
278
- pending.socket = INVALID_SOCKET_VALUE;
279
- pending.start_time = std::chrono::steady_clock::now();
280
-
281
- pending_connects_.push(std::move(pending));
282
-
283
- LOG_NET_DEBUG("Queued connection to " + ip + ":" + std::to_string(port));
284
- return true;
285
- }
286
-
287
- void BtNetworkManager::close_connection(socket_t socket) {
288
- std::vector<DisconnectedEvent> disconnected_events;
289
-
290
- {
291
- std::lock_guard<std::mutex> lock(mutex_);
292
- close_connection_internal(socket, disconnected_events);
293
- }
294
-
295
- // Invoke callbacks outside mutex
296
- for (const auto& event : disconnected_events) {
297
- if (on_disconnected_) {
298
- on_disconnected_(event.info_hash, event.connection.get());
299
- }
300
- }
301
- }
302
-
303
- bool BtNetworkManager::send_to_peer(socket_t socket, const std::vector<uint8_t>& data) {
304
- std::lock_guard<std::mutex> lock(mutex_);
305
-
306
- auto it = connections_.find(socket);
307
- if (it == connections_.end() || !it->second.connection) {
308
- return false;
309
- }
310
-
311
- auto& send_buf = it->second.connection->send_buffer();
312
-
313
- // Check high water mark
314
- if (send_buf.size() + data.size() > config_.send_buffer_high_water) {
315
- LOG_NET_WARN("Send buffer high water reached for " +
316
- it->second.connection->ip());
317
- return false;
318
- }
319
-
320
- bool was_empty = send_buf.empty();
321
-
322
- // Append directly to connection's send buffer (single source of truth)
323
- send_buf.append(data.data(), data.size());
324
-
325
- // If buffer was empty, we need to start watching for writability.
326
- // Update poller to add PollOut interest.
327
- if (was_empty && poller_) {
328
- uint32_t desired = PollIn | PollOut;
329
- auto ps = poller_state_.find(socket);
330
- if (ps != poller_state_.end() && ps->second != desired) {
331
- poller_->modify(socket, desired);
332
- ps->second = desired;
333
- }
334
- }
335
-
336
- return true;
337
- }
338
-
339
- size_t BtNetworkManager::connection_count() const {
340
- std::lock_guard<std::mutex> lock(mutex_);
341
- return connections_.size();
342
- }
343
-
344
- size_t BtNetworkManager::pending_connect_count() const {
345
- std::lock_guard<std::mutex> lock(mutex_);
346
- return pending_connects_.size() + connecting_.size();
347
- }
348
-
349
- //=============================================================================
350
- // Poller State Sync
351
- //=============================================================================
352
-
353
- void BtNetworkManager::sync_poller() {
354
- // Called under mutex. Ensures poller registrations match current state.
355
- // This is the primary sync point for connections whose send buffer
356
- // state may have changed (e.g., after flush_send_buffer drains it).
357
-
358
- for (auto& [socket, ctx] : connections_) {
359
- // Determine desired events
360
- uint32_t desired = PollIn; // Always interested in reading
361
- if (ctx.connection && !ctx.connection->send_buffer().empty()) {
362
- desired |= PollOut; // Also interested in writing
363
- }
364
-
365
- auto ps = poller_state_.find(socket);
366
- if (ps == poller_state_.end()) {
367
- // Not yet registered (shouldn't happen normally, but be safe)
368
- poller_->add(socket, desired);
369
- poller_state_[socket] = desired;
370
- } else if (ps->second != desired) {
371
- poller_->modify(socket, desired);
372
- ps->second = desired;
373
- }
374
- }
375
-
376
- // Connecting sockets: interested in write (connect complete) + error
377
- for (auto& [socket, pending] : connecting_) {
378
- auto ps = poller_state_.find(socket);
379
- uint32_t desired = PollOut;
380
- if (ps == poller_state_.end()) {
381
- poller_->add(socket, desired);
382
- poller_state_[socket] = desired;
383
- }
384
- // Connecting sockets don't change their interest, no modify needed
385
- }
386
- }
387
-
388
- //=============================================================================
389
- // I/O Loop
390
- //=============================================================================
391
-
392
- void BtNetworkManager::io_loop() {
393
- LOG_NET_DEBUG("I/O loop started");
394
-
395
- // Event vectors for deferred callback invocation (outside mutex)
396
- std::vector<ConnectedEvent> connected_events;
397
- std::vector<DataEvent> data_events;
398
- std::vector<DisconnectedEvent> disconnected_events;
399
-
400
- // Poll results buffer
401
- static constexpr int MAX_POLL_EVENTS = 256;
402
- PollResult poll_results[MAX_POLL_EVENTS];
403
-
404
- while (running_) {
405
- // Clear event vectors for this iteration
406
- connected_events.clear();
407
- data_events.clear();
408
- disconnected_events.clear();
409
-
410
- // Process pending connect queue (adds new sockets to poller)
411
- process_pending_connects();
412
-
413
- // Sync poller state (update write interest based on send buffer state)
414
- {
415
- std::lock_guard<std::mutex> lock(mutex_);
416
- sync_poller();
417
- }
418
-
419
- // Wait for I/O events (NO mutex held — this is the blocking call)
420
- int num_events = poller_->wait(poll_results, MAX_POLL_EVENTS,
421
- config_.poll_timeout_ms);
422
-
423
- if (num_events < 0) {
424
- // Error (EINTR already filtered by poller implementations)
425
- std::this_thread::sleep_for(std::chrono::milliseconds(10));
426
- continue;
427
- }
428
-
429
- if (num_events == 0) {
430
- // Timeout — check for connection timeouts
431
- auto now = std::chrono::steady_clock::now();
432
-
433
- std::lock_guard<std::mutex> lock(mutex_);
434
-
435
- std::vector<socket_t> timed_out;
436
- for (auto& [socket, pending] : connecting_) {
437
- auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
438
- now - pending.start_time).count();
439
- if (elapsed > config_.connect_timeout_ms) {
440
- timed_out.push_back(socket);
441
- }
442
- }
443
-
444
- for (socket_t s : timed_out) {
445
- LOG_NET_DEBUG("Connection timed out to " + connecting_[s].ip);
446
- poller_->remove(s);
447
- poller_state_.erase(s);
448
- close_socket(s);
449
- connecting_.erase(s);
450
- }
451
-
452
- continue;
453
- }
454
-
455
- LOG_NET_DEBUG("I/O poll returned " + std::to_string(num_events) + " events");
456
-
457
- // Process all events under mutex
458
- {
459
- std::lock_guard<std::mutex> lock(mutex_);
460
-
461
- std::vector<socket_t> to_close;
462
-
463
- for (int i = 0; i < num_events; ++i) {
464
- socket_t fd = poll_results[i].fd;
465
- uint32_t events = poll_results[i].events;
466
-
467
- //--------------------------------------------------------------
468
- // Listen socket — accept incoming
469
- //--------------------------------------------------------------
470
- if (fd == listen_socket_) {
471
- if (events & PollIn) {
472
- // NOTE: accept_incoming acquires mutex internally,
473
- // but we are already holding it. We need to call
474
- // the internal version without re-locking.
475
- accept_incoming();
476
- }
477
- continue;
478
- }
479
-
480
- //--------------------------------------------------------------
481
- // Connecting socket — check connect completion
482
- //--------------------------------------------------------------
483
- auto connecting_it = connecting_.find(fd);
484
- if (connecting_it != connecting_.end()) {
485
- auto& pending = connecting_it->second;
486
-
487
- if (events & PollErr) {
488
- // Connection failed
489
- LOG_NET_DEBUG("Connection failed (poll error) to " + pending.ip);
490
- poller_->remove(fd);
491
- poller_state_.erase(fd);
492
- close_socket(fd);
493
- connecting_.erase(connecting_it);
494
- continue;
495
- }
496
-
497
- if (events & PollOut) {
498
- // Check if connection succeeded
499
- int sock_error = 0;
500
- socklen_t len = sizeof(sock_error);
501
- getsockopt(fd, SOL_SOCKET, SO_ERROR,
502
- reinterpret_cast<char*>(&sock_error), &len);
503
-
504
- if (sock_error == 0) {
505
- LOG_NET_INFO("Connected to peer " + pending.ip + ":" +
506
- std::to_string(pending.port));
507
-
508
- // Set TCP_NODELAY for low latency
509
- set_tcp_nodelay(fd);
510
-
511
- // Create connection object
512
- auto conn = std::make_shared<BtPeerConnection>(
513
- pending.info_hash, pending.peer_id, pending.num_pieces);
514
- conn->set_address(pending.ip, pending.port);
515
- conn->set_socket(static_cast<int>(fd));
516
-
517
- // Create socket context
518
- SocketContext ctx;
519
- ctx.socket = fd;
520
- ctx.info_hash = pending.info_hash;
521
- ctx.connection = conn;
522
- ctx.state = NetConnectionState::Handshaking;
523
- ctx.incoming = false;
524
- ctx.connected_at = std::chrono::steady_clock::now();
525
- ctx.last_activity = ctx.connected_at;
526
-
527
- // Send handshake
528
- LOG_NET_DEBUG("Sending handshake (" +
529
- std::to_string(BT_HANDSHAKE_SIZE) + " bytes) to " +
530
- pending.ip);
531
- conn->start_handshake();
532
-
533
- connections_[fd] = std::move(ctx);
534
-
535
- // Update poller: now interested in read (+ write if handshake queued)
536
- uint32_t desired = PollIn;
537
- if (!conn->send_buffer().empty()) {
538
- desired |= PollOut;
539
- }
540
- poller_->modify(fd, desired);
541
- poller_state_[fd] = desired;
542
-
543
- LOG_NET_DEBUG("Handshake queued to " + pending.ip);
544
- } else {
545
- LOG_NET_DEBUG("Connection failed to " + pending.ip + ": " +
546
- std::to_string(sock_error));
547
- poller_->remove(fd);
548
- poller_state_.erase(fd);
549
- close_socket(fd);
550
- }
551
-
552
- connecting_.erase(connecting_it);
553
- }
554
- continue;
555
- }
556
-
557
- //--------------------------------------------------------------
558
- // Active connection — handle read/write/error
559
- //--------------------------------------------------------------
560
- auto conn_it = connections_.find(fd);
561
- if (conn_it == connections_.end()) {
562
- // Unknown fd — remove from poller
563
- poller_->remove(fd);
564
- poller_state_.erase(fd);
565
- continue;
566
- }
567
-
568
- bool should_close = false;
569
-
570
- if (events & PollErr) {
571
- if (conn_it->second.connection) {
572
- LOG_NET_DEBUG("Error on socket for " + conn_it->second.connection->ip());
573
- }
574
- should_close = true;
575
- }
576
-
577
- if (!should_close && (events & PollHup)) {
578
- if (conn_it->second.connection) {
579
- LOG_NET_DEBUG("Peer hung up: " + conn_it->second.connection->ip());
580
- }
581
- should_close = true;
582
- }
583
-
584
- if (!should_close && (events & PollIn)) {
585
- should_close = handle_readable(fd, connected_events, data_events);
586
- }
587
-
588
- if (!should_close && (events & PollOut)) {
589
- should_close = handle_writable(fd);
590
- }
591
-
592
- if (should_close) {
593
- to_close.push_back(fd);
594
- }
595
- }
596
-
597
- // Close connections AFTER processing all events to avoid iterator invalidation
598
- for (socket_t s : to_close) {
599
- close_connection_internal(s, disconnected_events);
600
- }
601
- }
602
-
603
- // Invoke callbacks OUTSIDE the mutex to prevent deadlocks
604
- for (const auto& event : connected_events) {
605
- if (on_connected_) {
606
- on_connected_(event.info_hash, event.connection,
607
- event.socket, event.incoming);
608
- }
609
- }
610
-
611
- for (const auto& event : data_events) {
612
- if (on_data_) {
613
- on_data_(event.info_hash, event.connection.get(), event.socket);
614
- }
615
- }
616
-
617
- for (const auto& event : disconnected_events) {
618
- if (on_disconnected_) {
619
- on_disconnected_(event.info_hash, event.connection.get());
620
- }
621
- }
622
- }
623
-
624
- LOG_NET_DEBUG("I/O loop stopped");
625
- }
626
-
627
- void BtNetworkManager::process_pending_connects() {
628
- std::lock_guard<std::mutex> lock(mutex_);
629
-
630
- // Limit concurrent connects
631
- const size_t max_concurrent = 30;
632
-
633
- while (!pending_connects_.empty() &&
634
- connecting_.size() < max_concurrent &&
635
- connections_.size() + connecting_.size() < config_.max_connections) {
636
-
637
- PendingConnect pending = std::move(pending_connects_.front());
638
- pending_connects_.pop();
639
-
640
- // Create non-blocking socket
641
- socket_t sock = create_connect_socket(pending.ip, pending.port);
642
- if (!is_valid_socket(sock)) {
643
- continue;
644
- }
645
-
646
- pending.socket = sock;
647
- pending.start_time = std::chrono::steady_clock::now();
648
-
649
- // Register with poller: interested in write (connect complete)
650
- poller_->add(sock, PollOut);
651
- poller_state_[sock] = PollOut;
652
-
653
- connecting_[sock] = std::move(pending);
654
- }
655
-
656
- if (!pending_connects_.empty()) {
657
- LOG_NET_DEBUG("process_pending_connects: " +
658
- std::to_string(connecting_.size()) + " pending");
659
- }
660
- }
661
-
662
- socket_t BtNetworkManager::create_connect_socket(const std::string& ip, uint16_t port) {
663
- // Create socket
664
- socket_t sock = socket(AF_INET, SOCK_STREAM, 0);
665
- if (!is_valid_socket(sock)) {
666
- LOG_NET_ERROR("Failed to create socket");
667
- return INVALID_SOCKET_VALUE;
668
- }
669
-
670
- // Set non-blocking
671
- if (!set_socket_nonblocking(sock)) {
672
- LOG_NET_ERROR("Failed to set socket non-blocking");
673
- close_socket(sock);
674
- return INVALID_SOCKET_VALUE;
675
- }
676
-
677
- // Set TCP_NODELAY immediately (before connect)
678
- set_tcp_nodelay(sock);
679
-
680
- // Resolve and connect
681
- std::string resolved = network_utils::resolve_hostname(ip);
682
- if (resolved.empty()) {
683
- LOG_NET_ERROR("Failed to resolve " + ip);
684
- close_socket(sock);
685
- return INVALID_SOCKET_VALUE;
686
- }
687
-
688
- sockaddr_in addr;
689
- std::memset(&addr, 0, sizeof(addr));
690
- addr.sin_family = AF_INET;
691
- addr.sin_port = htons(port);
692
-
693
- if (inet_pton(AF_INET, resolved.c_str(), &addr.sin_addr) <= 0) {
694
- LOG_NET_ERROR("Invalid address: " + resolved);
695
- close_socket(sock);
696
- return INVALID_SOCKET_VALUE;
697
- }
698
-
699
- LOG_NET_DEBUG("Connecting to " + ip + ":" + std::to_string(port));
700
-
701
- int result = connect(sock, reinterpret_cast<sockaddr*>(&addr), sizeof(addr));
702
- if (result < 0) {
703
- #ifdef _WIN32
704
- int err = WSAGetLastError();
705
- if (err != WSAEWOULDBLOCK) {
706
- LOG_NET_DEBUG("Connect failed immediately: " + std::to_string(err));
707
- close_socket(sock);
708
- return INVALID_SOCKET_VALUE;
709
- }
710
- #else
711
- if (errno != EINPROGRESS) {
712
- LOG_NET_DEBUG("Connect failed immediately: " + std::string(strerror(errno)));
713
- close_socket(sock);
714
- return INVALID_SOCKET_VALUE;
715
- }
716
- #endif
717
- }
718
-
719
- return sock;
720
- }
721
-
722
- void BtNetworkManager::accept_incoming() {
723
- // NOTE: called with mutex_ already held from io_loop
724
-
725
- socket_t client = accept_client(listen_socket_);
726
- if (!is_valid_socket(client)) {
727
- return;
728
- }
729
-
730
- // Check connection limit
731
- if (connections_.size() >= config_.max_connections) {
732
- LOG_NET_DEBUG("Connection limit reached, rejecting incoming");
733
- close_socket(client);
734
- return;
735
- }
736
-
737
- // Set non-blocking
738
- if (!set_socket_nonblocking(client)) {
739
- close_socket(client);
740
- return;
741
- }
742
-
743
- // Set TCP_NODELAY for low latency
744
- set_tcp_nodelay(client);
745
-
746
- // Get peer address
747
- std::string peer_addr = get_peer_address(client);
748
- std::string ip;
749
- uint16_t port = 0;
750
-
751
- size_t colon = peer_addr.rfind(':');
752
- if (colon != std::string::npos) {
753
- ip = peer_addr.substr(0, colon);
754
- port = static_cast<uint16_t>(std::stoi(peer_addr.substr(colon + 1)));
755
- }
756
-
757
- LOG_NET_INFO("Accepted incoming connection from " + peer_addr);
758
-
759
- // Create connection object immediately (info_hash unknown until handshake)
760
- auto conn = std::make_shared<BtPeerConnection>(config_.peer_id);
761
- conn->set_address(ip, port);
762
- conn->set_socket(static_cast<int>(client));
763
-
764
- // Set up callback for when handshake reveals the info_hash
765
- conn->set_info_hash_callback([this](BtPeerConnection* peer, const BtInfoHash& info_hash) {
766
- on_incoming_info_hash(peer, info_hash);
767
- });
768
-
769
- SocketContext ctx;
770
- ctx.socket = client;
771
- ctx.state = NetConnectionState::Handshaking;
772
- ctx.incoming = true;
773
- ctx.connected_at = std::chrono::steady_clock::now();
774
- ctx.last_activity = ctx.connected_at;
775
- ctx.connection = conn;
776
-
777
- connections_[client] = std::move(ctx);
778
-
779
- // Register with poller (interested in reading handshake)
780
- poller_->add(client, PollIn);
781
- poller_state_[client] = PollIn;
782
- }
783
-
784
- void BtNetworkManager::on_incoming_info_hash(BtPeerConnection* conn, const BtInfoHash& info_hash) {
785
- // This is called from within process_incoming() when an incoming connection
786
- // receives a handshake and discovers the info_hash. We need to look up the
787
- // torrent and set the correct info.
788
-
789
- // Note: We're already holding the mutex (called from io_loop -> handle_readable -> process_incoming)
790
-
791
- auto torrent_it = torrents_.find(info_hash);
792
- if (torrent_it == torrents_.end()) {
793
- LOG_NET_DEBUG("Unknown info_hash " + info_hash_to_hex(info_hash).substr(0, 8) +
794
- "... from incoming connection " + conn->ip());
795
- // Connection will be closed by BtPeerConnection when set_torrent_info is not called
796
- return;
797
- }
798
-
799
- const auto& reg = torrent_it->second;
800
-
801
- LOG_NET_DEBUG("Routing incoming connection from " + conn->ip() +
802
- " to torrent " + info_hash_to_hex(info_hash).substr(0, 8) + "...");
803
-
804
- // Set the torrent info on the connection
805
- conn->set_torrent_info(info_hash, reg.num_pieces);
806
-
807
- // Update the SocketContext with the info_hash
808
- for (auto& [socket, ctx] : connections_) {
809
- if (ctx.connection.get() == conn) {
810
- ctx.info_hash = info_hash;
811
- break;
812
- }
813
- }
814
- }
815
-
816
- bool BtNetworkManager::handle_readable(socket_t socket,
817
- std::vector<ConnectedEvent>& connected_events,
818
- std::vector<DataEvent>& data_events) {
819
- auto it = connections_.find(socket);
820
- if (it == connections_.end()) return false;
821
-
822
- SocketContext& ctx = it->second;
823
-
824
- // Connection object should always exist now (created in accept_incoming or connect_peer)
825
- if (!ctx.connection) {
826
- LOG_NET_ERROR("handle_readable: no connection object for socket");
827
- return true; // Should close
828
- }
829
-
830
- // Drain all available data from the kernel buffer (loop until EWOULDBLOCK)
831
- auto& recv_buf = ctx.connection->recv_buffer();
832
- bool got_data = false;
833
-
834
- while (true) {
835
- const size_t recv_size = 16384;
836
- recv_buf.ensure_space(recv_size);
837
-
838
- int bytes = recv(socket, reinterpret_cast<char*>(recv_buf.write_ptr()),
839
- static_cast<int>(recv_buf.write_space()), 0);
840
-
841
- if (bytes > 0) {
842
- recv_buf.received(bytes);
843
- got_data = true;
844
-
845
- LOG_NET_DEBUG("handle_readable: recv " + std::to_string(bytes) +
846
- " bytes from " + ctx.connection->ip());
847
- continue; // Try to read more
848
- }
849
-
850
- if (bytes == 0) {
851
- // Peer closed connection gracefully
852
- LOG_NET_DEBUG("Connection closed by peer: " + ctx.connection->ip());
853
- return true; // Should close
854
- }
855
-
856
- // bytes < 0: error
857
- #ifdef _WIN32
858
- int err = WSAGetLastError();
859
- if (err == WSAEWOULDBLOCK) {
860
- break; // No more data available, exit recv loop
861
- }
862
- LOG_NET_DEBUG("Receive error: " + std::to_string(err));
863
- #else
864
- if (errno == EAGAIN || errno == EWOULDBLOCK) {
865
- break; // No more data available, exit recv loop
866
- }
867
- LOG_NET_DEBUG("Receive error: " + std::string(strerror(errno)));
868
- #endif
869
- return true; // Should close on real errors
870
- }
871
-
872
- if (!got_data) {
873
- return false; // Nothing received, no processing needed
874
- }
875
-
876
- ctx.last_activity = std::chrono::steady_clock::now();
877
-
878
- // Process all received data (handshake and messages)
879
- return handle_peer_data(ctx, connected_events, data_events);
880
- }
881
-
882
- bool BtNetworkManager::handle_writable(socket_t socket) {
883
- auto it = connections_.find(socket);
884
- if (it == connections_.end()) return false;
885
-
886
- return flush_send_buffer(it->second);
887
- }
888
-
889
- bool BtNetworkManager::handle_peer_data(SocketContext& ctx,
890
- std::vector<ConnectedEvent>& connected_events,
891
- std::vector<DataEvent>& data_events) {
892
- if (!ctx.connection) return false;
893
-
894
- // Process incoming data (handshake and messages)
895
- // Data is already in connection's recv_buffer - no copy needed!
896
- ctx.connection->process_incoming();
897
-
898
- // Check if connection was closed during processing (e.g., unknown torrent, invalid handshake)
899
- auto conn_state = ctx.connection->state();
900
- if (conn_state == PeerConnectionState::Disconnected ||
901
- conn_state == PeerConnectionState::Closing) {
902
- LOG_NET_DEBUG("Connection closed during processing for " + ctx.connection->ip());
903
- return true; // Should close
904
- }
905
-
906
- if (ctx.state == NetConnectionState::Handshaking) {
907
- // Check if handshake complete
908
- if (ctx.connection->is_connected()) {
909
- ctx.state = NetConnectionState::Connected;
910
-
911
- LOG_NET_DEBUG("Handshake complete with " + ctx.connection->ip() +
912
- ", queueing callback");
913
-
914
- // Queue connected event (callback will be invoked outside mutex)
915
- ConnectedEvent event;
916
- event.info_hash = ctx.info_hash;
917
- event.connection = ctx.connection;
918
- event.socket = ctx.socket;
919
- event.incoming = ctx.incoming;
920
- connected_events.push_back(std::move(event));
921
- }
922
- } else if (ctx.state == NetConnectionState::Connected) {
923
- // Queue data event (callback will be invoked outside mutex)
924
- DataEvent event;
925
- event.info_hash = ctx.info_hash;
926
- event.connection = ctx.connection;
927
- event.socket = ctx.socket;
928
- data_events.push_back(std::move(event));
929
- }
930
-
931
- // Note: send data is already in connection->send_buffer()
932
- // flush_send_buffer() will send it directly - no copy needed!
933
- return false; // Don't close
934
- }
935
-
936
- bool BtNetworkManager::flush_send_buffer(SocketContext& ctx) {
937
- if (!ctx.connection) return false;
938
-
939
- auto& send_buf = ctx.connection->send_buffer();
940
- if (send_buf.empty()) return false;
941
-
942
- // Send directly from connection's buffer - NO COPY!
943
- const uint8_t* data = send_buf.front_data();
944
- size_t to_send = send_buf.front_size();
945
-
946
- if (to_send == 0 || data == nullptr) return false;
947
-
948
- LOG_NET_DEBUG("flush_send_buffer: sending " + std::to_string(to_send) +
949
- " bytes to " + ctx.connection->ip());
950
-
951
- int sent = send(ctx.socket, reinterpret_cast<const char*>(data),
952
- static_cast<int>(to_send), 0);
953
-
954
- if (sent > 0) {
955
- send_buf.pop_front(static_cast<size_t>(sent));
956
- ctx.last_activity = std::chrono::steady_clock::now();
957
-
958
- // If send buffer is now empty, remove PollOut interest to avoid busy-looping
959
- if (send_buf.empty()) {
960
- uint32_t desired = PollIn;
961
- auto ps = poller_state_.find(ctx.socket);
962
- if (ps != poller_state_.end() && ps->second != desired) {
963
- poller_->modify(ctx.socket, desired);
964
- ps->second = desired;
965
- }
966
- }
967
- } else if (sent < 0) {
968
- #ifdef _WIN32
969
- int err = WSAGetLastError();
970
- if (err != WSAEWOULDBLOCK) {
971
- LOG_NET_DEBUG("Send error: " + std::to_string(err));
972
- return true; // Should close
973
- }
974
- #else
975
- if (errno != EAGAIN && errno != EWOULDBLOCK) {
976
- LOG_NET_DEBUG("Send error: " + std::string(strerror(errno)));
977
- return true; // Should close
978
- }
979
- #endif
980
- }
981
- return false; // Don't close
982
- }
983
-
984
- void BtNetworkManager::close_connection_internal(socket_t socket,
985
- std::vector<DisconnectedEvent>& disconnected_events) {
986
- auto it = connections_.find(socket);
987
- if (it == connections_.end()) return;
988
-
989
- SocketContext& ctx = it->second;
990
-
991
- // Queue disconnected event (callback will be invoked outside mutex)
992
- if (ctx.connection) {
993
- DisconnectedEvent event;
994
- event.info_hash = ctx.info_hash;
995
- event.connection = ctx.connection;
996
- disconnected_events.push_back(std::move(event));
997
- }
998
-
999
- // Remove from poller before closing socket
1000
- poller_->remove(socket);
1001
- poller_state_.erase(socket);
1002
-
1003
- close_socket(socket, true);
1004
- connections_.erase(it);
1005
- }
1006
-
1007
- } // namespace librats