librats 1.0.2 → 2.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (313) hide show
  1. package/README.md +137 -332
  2. package/binding.gyp +16 -3
  3. package/lib/index.d.ts +271 -696
  4. package/lib/index.js +383 -44
  5. package/native-src/3rdparty/android/ifaddrs-android.c +1 -0
  6. package/native-src/3rdparty/android/ifaddrs-android.h +1 -0
  7. package/native-src/CMakeLists.txt +396 -179
  8. package/native-src/LICENSE +1 -1
  9. package/native-src/src/librats/bindings/rats.cpp +731 -0
  10. package/native-src/src/librats/bindings/rats.h +352 -0
  11. package/native-src/src/librats/bittorrent/bencode.cpp +437 -0
  12. package/native-src/src/librats/bittorrent/bencode.h +176 -0
  13. package/native-src/src/librats/bittorrent/bitfield.cpp +97 -0
  14. package/native-src/src/librats/bittorrent/bitfield.h +76 -0
  15. package/native-src/src/librats/bittorrent/byte_io.h +58 -0
  16. package/native-src/src/librats/bittorrent/choker.cpp +25 -0
  17. package/native-src/src/librats/bittorrent/choker.h +46 -0
  18. package/native-src/src/librats/bittorrent/client.cpp +413 -0
  19. package/native-src/src/librats/bittorrent/client.h +227 -0
  20. package/native-src/src/librats/bittorrent/disk_io.cpp +209 -0
  21. package/native-src/src/librats/bittorrent/disk_io.h +150 -0
  22. package/native-src/src/librats/bittorrent/extensions.cpp +191 -0
  23. package/native-src/src/librats/bittorrent/extensions.h +94 -0
  24. package/native-src/src/librats/bittorrent/file_storage.cpp +77 -0
  25. package/native-src/src/librats/bittorrent/file_storage.h +79 -0
  26. package/native-src/src/librats/bittorrent/log.h +42 -0
  27. package/native-src/src/librats/bittorrent/magnet_uri.cpp +98 -0
  28. package/native-src/src/librats/bittorrent/magnet_uri.h +35 -0
  29. package/native-src/src/librats/bittorrent/peer_connection.cpp +502 -0
  30. package/native-src/src/librats/bittorrent/peer_connection.h +194 -0
  31. package/native-src/src/librats/bittorrent/peer_list.cpp +68 -0
  32. package/native-src/src/librats/bittorrent/peer_list.h +75 -0
  33. package/native-src/src/librats/bittorrent/piece_picker.cpp +352 -0
  34. package/native-src/src/librats/bittorrent/piece_picker.h +201 -0
  35. package/native-src/src/librats/bittorrent/reactor.cpp +97 -0
  36. package/native-src/src/librats/bittorrent/reactor.h +89 -0
  37. package/native-src/src/librats/bittorrent/resume_data.cpp +72 -0
  38. package/native-src/src/librats/bittorrent/resume_data.h +41 -0
  39. package/native-src/src/librats/bittorrent/store_buffer.cpp +48 -0
  40. package/native-src/src/librats/bittorrent/store_buffer.h +47 -0
  41. package/native-src/src/librats/bittorrent/torrent.cpp +870 -0
  42. package/native-src/src/librats/bittorrent/torrent.h +260 -0
  43. package/native-src/src/librats/bittorrent/torrent_creator.cpp +129 -0
  44. package/native-src/src/librats/bittorrent/torrent_creator.h +58 -0
  45. package/native-src/src/librats/bittorrent/torrent_info.cpp +314 -0
  46. package/native-src/src/librats/bittorrent/torrent_info.h +118 -0
  47. package/native-src/src/librats/bittorrent/tracker.cpp +374 -0
  48. package/native-src/src/librats/bittorrent/tracker.h +108 -0
  49. package/native-src/src/librats/bittorrent/types.cpp +206 -0
  50. package/native-src/src/librats/bittorrent/types.h +86 -0
  51. package/native-src/src/librats/core/address.cpp +35 -0
  52. package/native-src/src/librats/core/address.h +78 -0
  53. package/native-src/src/librats/core/bytes.h +69 -0
  54. package/native-src/src/librats/core/chained_send_buffer.cpp +172 -0
  55. package/native-src/src/librats/core/chained_send_buffer.h +183 -0
  56. package/native-src/src/librats/core/endpoint_parse.cpp +41 -0
  57. package/native-src/src/librats/core/endpoint_parse.h +31 -0
  58. package/native-src/src/librats/core/event_bus.h +70 -0
  59. package/native-src/src/librats/core/host_endpoint.h +56 -0
  60. package/native-src/src/{io_poller.cpp → librats/core/io_poller.cpp} +520 -65
  61. package/native-src/src/{io_poller.h → librats/core/io_poller.h} +12 -6
  62. package/native-src/src/librats/core/ip_address.cpp +120 -0
  63. package/native-src/src/librats/core/ip_address.h +109 -0
  64. package/native-src/src/librats/core/mpsc_queue.h +47 -0
  65. package/native-src/src/librats/core/notifier.h +74 -0
  66. package/native-src/src/librats/core/receive_buffer.cpp +219 -0
  67. package/native-src/src/librats/core/receive_buffer.h +171 -0
  68. package/native-src/src/librats/core/service_registry.h +58 -0
  69. package/native-src/src/{socket.cpp → librats/core/socket.cpp} +625 -118
  70. package/native-src/src/librats/core/socket.h +496 -0
  71. package/native-src/src/librats/core/timer_queue.h +105 -0
  72. package/native-src/src/librats/core/types.cpp +42 -0
  73. package/native-src/src/librats/core/types.h +93 -0
  74. package/native-src/src/librats/core/wakeup_pipe.h +83 -0
  75. package/native-src/src/{crypto → librats/crypto}/blake2_endian.h +21 -23
  76. package/native-src/src/{crypto → librats/crypto}/blake2b.c +34 -33
  77. package/native-src/src/{crypto → librats/crypto}/blake2b.h +7 -6
  78. package/native-src/src/{crypto → librats/crypto}/blake2s.c +55 -54
  79. package/native-src/src/{crypto → librats/crypto}/blake2s.h +13 -12
  80. package/native-src/src/{crypto → librats/crypto}/chacha.c +22 -21
  81. package/native-src/src/{crypto → librats/crypto}/chacha.h +14 -13
  82. package/native-src/src/{crypto → librats/crypto}/chachapoly.c +56 -56
  83. package/native-src/src/{crypto → librats/crypto}/chachapoly.h +24 -17
  84. package/native-src/src/{crc32.cpp → librats/crypto/crc32.cpp} +1 -1
  85. package/native-src/src/{crc32.h → librats/crypto/crc32.h} +3 -1
  86. package/native-src/src/{crypto → librats/crypto}/curve25519.c +6 -4
  87. package/native-src/src/{crypto → librats/crypto}/curve25519.h +6 -3
  88. package/native-src/src/librats/crypto/hkdf.c +266 -0
  89. package/native-src/src/{crypto → librats/crypto}/hkdf.h +19 -19
  90. package/native-src/src/{noise.cpp → librats/crypto/noise.cpp} +84 -73
  91. package/native-src/src/{noise.h → librats/crypto/noise.h} +18 -8
  92. package/native-src/src/{crypto → librats/crypto}/poly1305.c +47 -46
  93. package/native-src/src/librats/crypto/poly1305.h +37 -0
  94. package/native-src/src/{sha1.cpp → librats/crypto/sha1.cpp} +33 -1
  95. package/native-src/src/{sha1.h → librats/crypto/sha1.h} +14 -6
  96. package/native-src/src/{crypto → librats/crypto}/sha256.c +15 -14
  97. package/native-src/src/{crypto → librats/crypto}/sha256.h +8 -7
  98. package/native-src/src/{crypto → librats/crypto}/sha512.c +15 -14
  99. package/native-src/src/{crypto → librats/crypto}/sha512.h +8 -7
  100. package/native-src/src/librats/dht/announce.cpp +37 -0
  101. package/native-src/src/librats/dht/announce.h +41 -0
  102. package/native-src/src/librats/dht/bep42.cpp +109 -0
  103. package/native-src/src/librats/dht/bep42.h +48 -0
  104. package/native-src/src/librats/dht/dht.cpp +501 -0
  105. package/native-src/src/librats/dht/dht.h +119 -0
  106. package/native-src/src/librats/dht/dht_runner.cpp +103 -0
  107. package/native-src/src/librats/dht/dht_runner.h +71 -0
  108. package/native-src/src/librats/dht/dos_blocker.cpp +42 -0
  109. package/native-src/src/librats/dht/dos_blocker.h +47 -0
  110. package/native-src/src/librats/dht/find_peers.cpp +52 -0
  111. package/native-src/src/librats/dht/find_peers.h +73 -0
  112. package/native-src/src/librats/dht/id.h +167 -0
  113. package/native-src/src/{krpc.cpp → librats/dht/krpc.cpp} +32 -81
  114. package/native-src/src/{krpc.h → librats/dht/krpc.h} +19 -23
  115. package/native-src/src/librats/dht/log.h +38 -0
  116. package/native-src/src/librats/dht/node.cpp +473 -0
  117. package/native-src/src/librats/dht/node.h +164 -0
  118. package/native-src/src/librats/dht/node_entry.h +81 -0
  119. package/native-src/src/librats/dht/observer.h +72 -0
  120. package/native-src/src/librats/dht/persistence.cpp +90 -0
  121. package/native-src/src/librats/dht/persistence.h +32 -0
  122. package/native-src/src/librats/dht/routing_table.cpp +559 -0
  123. package/native-src/src/librats/dht/routing_table.h +185 -0
  124. package/native-src/src/librats/dht/rpc_manager.cpp +127 -0
  125. package/native-src/src/librats/dht/rpc_manager.h +77 -0
  126. package/native-src/src/librats/dht/storage.cpp +92 -0
  127. package/native-src/src/librats/dht/storage.h +74 -0
  128. package/native-src/src/librats/dht/transport.h +27 -0
  129. package/native-src/src/librats/dht/traversal.cpp +326 -0
  130. package/native-src/src/librats/dht/traversal.h +120 -0
  131. package/native-src/src/librats/dht/udp_transport.cpp +49 -0
  132. package/native-src/src/librats/dht/udp_transport.h +51 -0
  133. package/native-src/src/librats/mdns/log.h +22 -0
  134. package/native-src/src/{mdns.cpp → librats/mdns/mdns.cpp} +75 -40
  135. package/native-src/src/{mdns.h → librats/mdns/mdns.h} +9 -8
  136. package/native-src/src/{natpmp.cpp → librats/nat/natpmp.cpp} +12 -9
  137. package/native-src/src/{natpmp.h → librats/nat/natpmp.h} +3 -3
  138. package/native-src/src/{port_mapping.h → librats/nat/port_mapping.h} +3 -2
  139. package/native-src/src/{stun.cpp → librats/nat/stun.cpp} +4 -4
  140. package/native-src/src/{stun.h → librats/nat/stun.h} +1 -1
  141. package/native-src/src/{upnp.cpp → librats/nat/upnp.cpp} +6 -6
  142. package/native-src/src/{upnp.h → librats/nat/upnp.h} +2 -2
  143. package/native-src/src/librats/node/config.h +110 -0
  144. package/native-src/src/librats/node/dial_service.h +54 -0
  145. package/native-src/src/librats/node/dialer.cpp +264 -0
  146. package/native-src/src/librats/node/dialer.h +188 -0
  147. package/native-src/src/librats/node/host_events.h +26 -0
  148. package/native-src/src/librats/node/identify.cpp +130 -0
  149. package/native-src/src/librats/node/identify.h +71 -0
  150. package/native-src/src/librats/node/nat_status.cpp +103 -0
  151. package/native-src/src/librats/node/nat_status.h +118 -0
  152. package/native-src/src/librats/node/node.cpp +826 -0
  153. package/native-src/src/librats/node/node.h +333 -0
  154. package/native-src/src/librats/node/node_context.h +33 -0
  155. package/native-src/src/librats/node/peer_network.h +91 -0
  156. package/native-src/src/librats/peer/peer.h +49 -0
  157. package/native-src/src/librats/peer/peer_book.cpp +181 -0
  158. package/native-src/src/librats/peer/peer_book.h +88 -0
  159. package/native-src/src/librats/peer/peer_id.cpp +72 -0
  160. package/native-src/src/librats/peer/peer_id.h +62 -0
  161. package/native-src/src/librats/peer/peer_info.h +37 -0
  162. package/native-src/src/librats/peer/peer_table.cpp +137 -0
  163. package/native-src/src/librats/peer/peer_table.h +148 -0
  164. package/native-src/src/librats/security/handshaker.h +66 -0
  165. package/native-src/src/librats/security/identity.h +43 -0
  166. package/native-src/src/librats/security/noise_security.cpp +122 -0
  167. package/native-src/src/librats/security/noise_security.h +37 -0
  168. package/native-src/src/librats/security/plaintext_security.h +106 -0
  169. package/native-src/src/librats/security/session.h +37 -0
  170. package/native-src/src/{storage.cpp → librats/storage/storage.cpp} +369 -522
  171. package/native-src/src/{storage.h → librats/storage/storage.h} +135 -299
  172. package/native-src/src/librats/subsystems/bittorrent.cpp +211 -0
  173. package/native-src/src/librats/subsystems/bittorrent.h +136 -0
  174. package/native-src/src/librats/subsystems/dht_discovery.cpp +202 -0
  175. package/native-src/src/librats/subsystems/dht_discovery.h +123 -0
  176. package/native-src/src/librats/subsystems/dht_service.h +36 -0
  177. package/native-src/src/librats/subsystems/file_transfer.cpp +972 -0
  178. package/native-src/src/librats/subsystems/file_transfer.h +367 -0
  179. package/native-src/src/librats/subsystems/hole_punch.cpp +532 -0
  180. package/native-src/src/librats/subsystems/hole_punch.h +266 -0
  181. package/native-src/src/librats/subsystems/hole_punch_service.h +38 -0
  182. package/native-src/src/librats/subsystems/mdns_discovery.cpp +66 -0
  183. package/native-src/src/librats/subsystems/mdns_discovery.h +55 -0
  184. package/native-src/src/librats/subsystems/message_json.cpp +112 -0
  185. package/native-src/src/librats/subsystems/message_json.h +88 -0
  186. package/native-src/src/librats/subsystems/peer_exchange.cpp +241 -0
  187. package/native-src/src/librats/subsystems/peer_exchange.h +136 -0
  188. package/native-src/src/librats/subsystems/ping_service.cpp +98 -0
  189. package/native-src/src/librats/subsystems/ping_service.h +66 -0
  190. package/native-src/src/librats/subsystems/port_mapping_service.cpp +192 -0
  191. package/native-src/src/librats/subsystems/port_mapping_service.h +84 -0
  192. package/native-src/src/librats/subsystems/pubsub.cpp +567 -0
  193. package/native-src/src/librats/subsystems/pubsub.h +175 -0
  194. package/native-src/src/librats/subsystems/reconnection.cpp +239 -0
  195. package/native-src/src/librats/subsystems/reconnection.h +126 -0
  196. package/native-src/src/librats/transport/connection.cpp +343 -0
  197. package/native-src/src/librats/transport/connection.h +283 -0
  198. package/native-src/src/librats/transport/link.h +96 -0
  199. package/native-src/src/librats/transport/reactor.cpp +540 -0
  200. package/native-src/src/librats/transport/reactor.h +224 -0
  201. package/native-src/src/librats/transport/reactor_pool.h +81 -0
  202. package/native-src/src/librats/transport/tcp_link.cpp +49 -0
  203. package/native-src/src/librats/transport/tcp_link.h +43 -0
  204. package/native-src/src/librats/transport/udp_mux.cpp +617 -0
  205. package/native-src/src/librats/transport/udp_mux.h +363 -0
  206. package/native-src/src/librats/transport/udp_packet.cpp +121 -0
  207. package/native-src/src/librats/transport/udp_packet.h +190 -0
  208. package/native-src/src/librats/transport/udp_stream.cpp +1194 -0
  209. package/native-src/src/librats/transport/udp_stream.h +614 -0
  210. package/native-src/src/librats/util/features.h.in +51 -0
  211. package/native-src/src/{fs.cpp → librats/util/fs.cpp} +51 -3
  212. package/native-src/src/librats/util/fs.h +136 -0
  213. package/native-src/src/librats/util/json.cpp +1002 -0
  214. package/native-src/src/librats/util/json.h +444 -0
  215. package/native-src/src/{logger.cpp → librats/util/logger.cpp} +1 -1
  216. package/native-src/src/{logger.h → librats/util/logger.h} +43 -31
  217. package/native-src/src/{network_monitor.cpp → librats/util/network_monitor.cpp} +12 -4
  218. package/native-src/src/{network_monitor.h → librats/util/network_monitor.h} +2 -1
  219. package/native-src/src/{network_utils.cpp → librats/util/network_utils.cpp} +38 -23
  220. package/native-src/src/{network_utils.h → librats/util/network_utils.h} +15 -8
  221. package/native-src/src/{os.cpp → librats/util/os.cpp} +48 -18
  222. package/native-src/src/librats/util/rats_export.h +69 -0
  223. package/native-src/src/{version.cpp → librats/util/version.cpp} +2 -2
  224. package/native-src/src/{version.h.in → librats/util/version.h.in} +1 -1
  225. package/native-src/src/librats/wire/frame.cpp +76 -0
  226. package/native-src/src/librats/wire/frame.h +110 -0
  227. package/native-src/src/librats/wire/message_router.cpp +45 -0
  228. package/native-src/src/librats/wire/message_router.h +47 -0
  229. package/package.json +5 -4
  230. package/scripts/build-librats.js +1 -0
  231. package/scripts/postinstall.js +3 -3
  232. package/scripts/prepare-package.js +4 -4
  233. package/scripts/verify-installation.js +63 -105
  234. package/src/librats_node.cpp +1042 -1324
  235. package/native-src/src/bencode.cpp +0 -485
  236. package/native-src/src/bencode.h +0 -145
  237. package/native-src/src/bittorrent.cpp +0 -14
  238. package/native-src/src/bittorrent.h +0 -74
  239. package/native-src/src/bt_bitfield.cpp +0 -372
  240. package/native-src/src/bt_bitfield.h +0 -316
  241. package/native-src/src/bt_choker.cpp +0 -228
  242. package/native-src/src/bt_choker.h +0 -147
  243. package/native-src/src/bt_client.cpp +0 -1047
  244. package/native-src/src/bt_client.h +0 -445
  245. package/native-src/src/bt_create_torrent.cpp +0 -677
  246. package/native-src/src/bt_create_torrent.h +0 -473
  247. package/native-src/src/bt_extension.cpp +0 -469
  248. package/native-src/src/bt_extension.h +0 -309
  249. package/native-src/src/bt_file_storage.cpp +0 -261
  250. package/native-src/src/bt_file_storage.h +0 -298
  251. package/native-src/src/bt_handshake.cpp +0 -134
  252. package/native-src/src/bt_handshake.h +0 -157
  253. package/native-src/src/bt_messages.cpp +0 -364
  254. package/native-src/src/bt_messages.h +0 -324
  255. package/native-src/src/bt_network.cpp +0 -1007
  256. package/native-src/src/bt_network.h +0 -417
  257. package/native-src/src/bt_peer_connection.cpp +0 -742
  258. package/native-src/src/bt_peer_connection.h +0 -592
  259. package/native-src/src/bt_piece_picker.cpp +0 -786
  260. package/native-src/src/bt_piece_picker.h +0 -473
  261. package/native-src/src/bt_resume_data.cpp +0 -410
  262. package/native-src/src/bt_resume_data.h +0 -249
  263. package/native-src/src/bt_torrent.cpp +0 -2120
  264. package/native-src/src/bt_torrent.h +0 -641
  265. package/native-src/src/bt_torrent_info.cpp +0 -659
  266. package/native-src/src/bt_torrent_info.h +0 -418
  267. package/native-src/src/bt_types.h +0 -621
  268. package/native-src/src/chained_send_buffer.cpp +0 -75
  269. package/native-src/src/chained_send_buffer.h +0 -137
  270. package/native-src/src/crypto/hkdf.c +0 -266
  271. package/native-src/src/crypto/poly1305.h +0 -36
  272. package/native-src/src/dht.cpp +0 -3311
  273. package/native-src/src/dht.h +0 -717
  274. package/native-src/src/disk_io.cpp +0 -632
  275. package/native-src/src/disk_io.h +0 -315
  276. package/native-src/src/file_transfer.cpp +0 -1415
  277. package/native-src/src/file_transfer.h +0 -286
  278. package/native-src/src/fs.h +0 -108
  279. package/native-src/src/gossipsub.cpp +0 -1139
  280. package/native-src/src/gossipsub.h +0 -403
  281. package/native-src/src/ice.cpp +0 -893
  282. package/native-src/src/ice.h +0 -559
  283. package/native-src/src/json.hpp +0 -25526
  284. package/native-src/src/librats.cpp +0 -2378
  285. package/native-src/src/librats.h +0 -2324
  286. package/native-src/src/librats_bittorrent.cpp +0 -601
  287. package/native-src/src/librats_c.cpp +0 -1557
  288. package/native-src/src/librats_c.h +0 -323
  289. package/native-src/src/librats_discovery.cpp +0 -402
  290. package/native-src/src/librats_encryption.cpp +0 -275
  291. package/native-src/src/librats_file_transfer.cpp +0 -144
  292. package/native-src/src/librats_gossipsub.cpp +0 -289
  293. package/native-src/src/librats_ice.cpp +0 -213
  294. package/native-src/src/librats_log_macros.h +0 -36
  295. package/native-src/src/librats_logging.cpp +0 -173
  296. package/native-src/src/librats_mdns.cpp +0 -166
  297. package/native-src/src/librats_persistence.cpp +0 -796
  298. package/native-src/src/librats_portmap.cpp +0 -419
  299. package/native-src/src/librats_reconnection.cpp +0 -218
  300. package/native-src/src/librats_statistic.cpp +0 -105
  301. package/native-src/src/librats_storage.cpp +0 -189
  302. package/native-src/src/rats_export.h +0 -17
  303. package/native-src/src/receive_buffer.cpp +0 -82
  304. package/native-src/src/receive_buffer.h +0 -127
  305. package/native-src/src/socket.h +0 -228
  306. package/native-src/src/threadmanager.cpp +0 -105
  307. package/native-src/src/threadmanager.h +0 -53
  308. package/native-src/src/tracker.cpp +0 -1264
  309. package/native-src/src/tracker.h +0 -319
  310. package/native-src/src/turn.cpp +0 -762
  311. package/native-src/src/turn.h +0 -460
  312. package/native-src/src/wakeup_pipe.h +0 -60
  313. /package/native-src/src/{os.h → librats/util/os.h} +0 -0
@@ -0,0 +1,148 @@
1
+ #pragma once
2
+
3
+ /**
4
+ * @file peer_table.h
5
+ * @brief Control-plane registry: PeerId → route + metadata.
6
+ *
7
+ * This is the only shared peer structure in the redesign, and it is deliberately
8
+ * **off the per-byte data path**: it is touched on connect/disconnect and on
9
+ * explicit by-id lookups (send-by-id, peers()), never per inbound/outbound frame
10
+ * (those use the route carried in the Connection/Peer handle). It is therefore
11
+ * read-mostly and guarded by a shared_mutex with short critical sections — a
12
+ * world away from the old global peers_mutex_ held across recv/send.
13
+ */
14
+
15
+ #include "librats/util/rats_export.h"
16
+ #include "librats/core/types.h" // ConnId
17
+ #include "librats/peer/peer_id.h"
18
+ #include "librats/peer/peer_info.h"
19
+
20
+ #include <atomic>
21
+ #include <cstdint>
22
+ #include <memory>
23
+ #include <optional>
24
+ #include <shared_mutex>
25
+ #include <unordered_map>
26
+ #include <vector>
27
+
28
+ namespace librats {
29
+
30
+ /// Where a peer's live connection lives: which reactor owns it, and its ConnId.
31
+ /// (reactor, conn) identifies a connection globally and is never reused while it
32
+ /// is alive, so it is the stable key for matching a teardown to a directory entry.
33
+ struct PeerRoute {
34
+ uint8_t reactor = 0;
35
+ ConnId conn = kInvalidConnId;
36
+
37
+ bool operator==(const PeerRoute& o) const noexcept { return reactor == o.reactor && conn == o.conn; }
38
+ bool operator!=(const PeerRoute& o) const noexcept { return !(*this == o); }
39
+ };
40
+
41
+ class RATS_API PeerTable {
42
+ public:
43
+ enum class AddResult {
44
+ NewPeer, ///< First connection to this peer — caller should fire "connected".
45
+ Updated, ///< Same connection re-registered; metadata refreshed only.
46
+ Replaced, ///< A previous connection was superseded (`close` holds its route).
47
+ Rejected, ///< An existing connection was kept; the new one (`close`) must close.
48
+ };
49
+ struct AddOutcome {
50
+ AddResult result = AddResult::NewPeer;
51
+ std::optional<PeerRoute> close; ///< Loser of a duplicate race; tear it down.
52
+ };
53
+
54
+ /// Register a connection for a peer, resolving duplicates deterministically.
55
+ /// Both ends resolve the same pair of connections independently, so each rule
56
+ /// reads only what looks identical from either side — never arrival order:
57
+ /// - opposite roles ⇒ a simultaneous cross-connect. `prefer_outbound` (which
58
+ /// BOTH peers compute identically from a symmetric rule over their ids)
59
+ /// picks the surviving link, so both converge on the same one.
60
+ /// - same role, different transports ⇒ a dial race whose attempts both got
61
+ /// through; the datagram link wins at both ends.
62
+ /// - same role and transport ⇒ a reconnect, so the newcomer wins.
63
+ /// Taken together these are a total order, mirrored at the two ends, which is
64
+ /// what makes the verdict independent of the order connections arrive in. See
65
+ /// peer_table.cpp for why each rule is the one it is.
66
+ /// The loser's route is returned in `close`. Write lock.
67
+ AddOutcome add(const PeerInfo& info, PeerRoute route, bool prefer_outbound);
68
+
69
+ /// Drop a peer, but only if its current route matches `route` — so a stale
70
+ /// connection's teardown cannot evict a newer one that replaced it. Write lock.
71
+ /// Returns true iff an entry was actually removed.
72
+ bool remove(const PeerId& id, PeerRoute route);
73
+
74
+ /// Route to a peer's live connection, if connected. Read lock.
75
+ std::optional<PeerRoute> route(const PeerId& id) const;
76
+
77
+ /// Merge dialable addresses into a peer's metadata, de-duplicated and bounded
78
+ /// to kMaxAddressesPerPeer. Applies only if `route` is still the peer's live
79
+ /// route (a stale connection's late identify cannot mutate a newer link).
80
+ /// Returns the addresses actually added (i.e. not already known). Write lock.
81
+ std::vector<Address> add_addresses(const PeerId& id, PeerRoute route,
82
+ const std::vector<Address>& addresses);
83
+
84
+ /// Record which transports a peer advertised in its identify message. Applies
85
+ /// only while `route` is still the peer's live route. Write lock.
86
+ void set_supported_transports(const PeerId& id, PeerRoute route, uint8_t mask);
87
+
88
+ /// A peer's live route together with whether its send queue has room, in one
89
+ /// lookup — the send path needs both and should not pay for two.
90
+ struct Destination {
91
+ PeerRoute route;
92
+ bool writable = true;
93
+ /// The peer's in-transit counter (see Entry::owed). Shared, not copied,
94
+ /// so the caller charges the same counter the reactor task discharges.
95
+ std::shared_ptr<std::atomic<size_t>> owed;
96
+ };
97
+ std::optional<Destination> destination(const PeerId& id) const;
98
+
99
+ /// Whether every connected peer's send queue has room — what broadcast()
100
+ /// answers, since "may I send more?" to a fan-out is only usefully answered
101
+ /// by its slowest recipient.
102
+ bool all_writable() const;
103
+
104
+ /// Record that a peer's send queue filled up or drained. Applies only while
105
+ /// `route` is still the peer's live route. Write lock, but only ever taken
106
+ /// when the mark is actually crossed, which is rare.
107
+ void set_writable(const PeerId& id, PeerRoute route, bool writable);
108
+
109
+ /// Upper bound on stored addresses per peer — caps memory and stops a peer
110
+ /// from flooding us with bogus addresses via the identify/PEX path.
111
+ static constexpr size_t kMaxAddressesPerPeer = 32;
112
+
113
+ /// Metadata snapshot for a peer. Read lock.
114
+ std::optional<PeerInfo> info(const PeerId& id) const;
115
+
116
+ bool contains(const PeerId& id) const;
117
+
118
+ /// Snapshot of all known peers (for the public API / persistence). Read lock.
119
+ std::vector<PeerInfo> snapshot() const;
120
+
121
+ size_t size() const noexcept { return count_.load(std::memory_order_relaxed); }
122
+
123
+ private:
124
+ struct Entry {
125
+ PeerInfo info;
126
+ PeerRoute route;
127
+ /// Whether this peer's send queue has room. Maintained by the reactor as
128
+ /// the queue crosses its low-water mark, read by send() so a caller on
129
+ /// any thread gets an answer without having to reach into a connection it
130
+ /// does not own. Advisory by nature — it is a snapshot of a queue that is
131
+ /// draining as it is read, which is exactly what a backpressure hint is.
132
+ bool writable = true;
133
+ /// Bytes handed to the owning reactor by send() that it has not taken up
134
+ /// yet. The queue itself lives on the reactor thread and `writable` above
135
+ /// only ever reports what the reactor has already seen — so a caller in a
136
+ /// tight loop could hand over megabytes before a single one of them was
137
+ /// counted. This is that backlog, incremented by the caller and decremented
138
+ /// by the reactor task, so the answer covers both halves.
139
+ std::shared_ptr<std::atomic<size_t>> owed =
140
+ std::make_shared<std::atomic<size_t>>(0);
141
+ };
142
+
143
+ mutable std::shared_mutex mutex_;
144
+ std::unordered_map<PeerId, Entry, PeerId::Hash> peers_;
145
+ std::atomic<size_t> count_{0};
146
+ };
147
+
148
+ } // namespace librats
@@ -0,0 +1,66 @@
1
+ #pragma once
2
+
3
+ /**
4
+ * @file handshaker.h
5
+ * @brief Secure-channel handshake driver and the provider that creates one.
6
+ *
7
+ * A Handshaker is fed handshake messages until it yields a Session and the
8
+ * remote PeerId (or fails). It is transport-agnostic: the Connection frames its
9
+ * `out` bytes as Handshake frames and feeds inbound Handshake payloads back in.
10
+ *
11
+ * A SecurityProvider configures the whole node (one keypair / policy) and mints
12
+ * a fresh Handshaker per connection. Swapping NoiseSecurity ⇄ PlaintextSecurity
13
+ * changes the entire security posture without touching the transport.
14
+ */
15
+
16
+ #include "librats/util/rats_export.h"
17
+ #include "librats/core/bytes.h"
18
+ #include "librats/core/types.h" // ConnRole
19
+ #include "librats/peer/peer_id.h"
20
+ #include "librats/security/session.h"
21
+
22
+ #include <memory>
23
+ #include <string>
24
+
25
+ namespace librats {
26
+
27
+ /// Canonical bytes identifying an application protocol. Bound into the handshake
28
+ /// — as the Noise prologue, or exchanged-and-checked in the plaintext handshake —
29
+ /// so peers whose protocol differs cannot connect. The protocol string is an
30
+ /// opaque identity compared for exact equality; by convention it is "<name>/
31
+ /// <version>" (e.g. "librats/1.0"), but any difference at all is a distinct
32
+ /// protocol. A fixed context tag namespaces it away from other prologue uses.
33
+ inline std::string protocol_id(const std::string& protocol) {
34
+ return std::string("librats-proto\x1f", 14) + protocol; // tag + opaque id
35
+ }
36
+
37
+ class RATS_API Handshaker {
38
+ public:
39
+ struct Outcome {
40
+ enum Status { NeedMore, Done, Failed } status = NeedMore;
41
+ std::unique_ptr<Session> session; ///< valid iff status == Done
42
+ PeerId remote_id; ///< valid iff status == Done
43
+ };
44
+
45
+ virtual ~Handshaker() = default;
46
+
47
+ /// Called once when the transport is up. Appends the initial message, if
48
+ /// any (e.g. the initiator's first Noise message), to `out`. False on error.
49
+ virtual bool start(Bytes& out) = 0;
50
+
51
+ /// Consume one received handshake message; append any reply to `out`.
52
+ virtual Outcome consume(ByteView incoming, Bytes& out) = 0;
53
+ };
54
+
55
+ class RATS_API SecurityProvider {
56
+ public:
57
+ virtual ~SecurityProvider() = default;
58
+
59
+ /// Create a handshaker for a new connection in the given role.
60
+ virtual std::unique_ptr<Handshaker> create(ConnRole role) = 0;
61
+
62
+ /// This node's own identity.
63
+ virtual const PeerId& local_id() const = 0;
64
+ };
65
+
66
+ } // namespace librats
@@ -0,0 +1,43 @@
1
+ #pragma once
2
+
3
+ /**
4
+ * @file identity.h
5
+ * @brief A node's cryptographic identity: a static keypair and its derived PeerId.
6
+ *
7
+ * The PeerId is SHA-256 of the static public key, so identity travels with the
8
+ * key. Generate a fresh identity for an ephemeral node, or rebuild one from a
9
+ * persisted private key to keep a stable PeerId across restarts.
10
+ */
11
+
12
+ #include "librats/util/rats_export.h"
13
+ #include "librats/peer/peer_id.h"
14
+ #include "librats/crypto/noise.h"
15
+
16
+ #include <cstring>
17
+
18
+ namespace librats {
19
+
20
+ struct RATS_API Identity {
21
+ librats::NoiseKeyPair static_keypair;
22
+ PeerId id;
23
+
24
+ /// Create a brand-new random identity.
25
+ static Identity generate() {
26
+ Identity ident;
27
+ librats::noise_generate_keypair(ident.static_keypair);
28
+ ident.id = PeerId::from_public_key(ident.static_keypair.public_key, librats::NOISE_DH_SIZE);
29
+ return ident;
30
+ }
31
+
32
+ /// Rebuild a stable identity from a persisted 32-byte private key.
33
+ static Identity from_private_key(const uint8_t private_key[librats::NOISE_DH_SIZE]) {
34
+ Identity ident;
35
+ std::memcpy(ident.static_keypair.private_key, private_key, librats::NOISE_DH_SIZE);
36
+ librats::noise_derive_public_key(private_key, ident.static_keypair.public_key);
37
+ ident.static_keypair.has_keys = true;
38
+ ident.id = PeerId::from_public_key(ident.static_keypair.public_key, librats::NOISE_DH_SIZE);
39
+ return ident;
40
+ }
41
+ };
42
+
43
+ } // namespace librats
@@ -0,0 +1,122 @@
1
+ #include "librats/security/noise_security.h"
2
+ #include "librats/crypto/noise.h"
3
+ #include "librats/util/logger.h"
4
+
5
+ namespace librats {
6
+ namespace {
7
+
8
+ // Human-readable Noise failure reason for handshake diagnostics. Kept local: the
9
+ // crypto layer deliberately exposes only the enum, and this is its sole logger.
10
+ const char* noise_error_name(librats::NoiseError e) {
11
+ switch (e) {
12
+ case librats::NoiseError::OK: return "ok";
13
+ case librats::NoiseError::INVALID_STATE: return "invalid-state";
14
+ case librats::NoiseError::DECRYPT_FAILED: return "decrypt-failed";
15
+ case librats::NoiseError::MESSAGE_TOO_LARGE: return "message-too-large";
16
+ case librats::NoiseError::HANDSHAKE_NOT_COMPLETE: return "handshake-not-complete";
17
+ case librats::NoiseError::HANDSHAKE_ALREADY_COMPLETE: return "handshake-already-complete";
18
+ case librats::NoiseError::INVALID_KEY: return "invalid-key";
19
+ case librats::NoiseError::INTERNAL_ERROR: return "internal-error";
20
+ }
21
+ return "unknown";
22
+ }
23
+
24
+ /// Session backed by a completed librats::NoiseSession (owns its transport ciphers).
25
+ class NoiseSessionAdapter final : public Session {
26
+ public:
27
+ NoiseSessionAdapter(std::unique_ptr<librats::NoiseSession> session, PeerId remote)
28
+ : session_(std::move(session)), remote_id_(remote) {}
29
+
30
+ bool encrypt(ByteView plain, Bytes& out) override {
31
+ out.resize(plain.size() + librats::NOISE_TAG_SIZE);
32
+ const size_t n = session_->encrypt(plain.data(), plain.size(), out.data());
33
+ if (n == 0 && plain.size() != 0) return false;
34
+ out.resize(n);
35
+ return true;
36
+ }
37
+
38
+ bool decrypt(ByteView cipher, Bytes& out) override {
39
+ if (cipher.size() < librats::NOISE_TAG_SIZE) return false;
40
+ out.resize(cipher.size()); // plaintext is always shorter than ciphertext
41
+ const size_t n = session_->decrypt(cipher.data(), cipher.size(), out.data());
42
+ if (n == librats::NOISE_DECRYPT_FAILED) return false; // 0 is a valid (empty) frame
43
+ out.resize(n);
44
+ return true;
45
+ }
46
+
47
+ const PeerId& remote_id() const override { return remote_id_; }
48
+ bool is_secure() const override { return true; }
49
+
50
+ private:
51
+ std::unique_ptr<librats::NoiseSession> session_;
52
+ PeerId remote_id_;
53
+ };
54
+
55
+ /// Drives the Noise XX message exchange via librats::NoiseSession::handshake_step.
56
+ class NoiseHandshaker final : public Handshaker {
57
+ public:
58
+ NoiseHandshaker(const Identity& identity, bool initiator, ByteView prologue)
59
+ : session_(std::make_unique<librats::NoiseSession>()), initiator_(initiator) {
60
+ session_->start(initiator, &identity.static_keypair,
61
+ prologue.empty() ? nullptr : prologue.data(), prologue.size());
62
+ }
63
+
64
+ bool start(Bytes& out) override {
65
+ if (!initiator_) return true; // responder waits for the first message
66
+ return step(nullptr, 0, out);
67
+ }
68
+
69
+ Outcome consume(ByteView incoming, Bytes& out) override {
70
+ Outcome oc;
71
+ if (!step(incoming.data(), incoming.size(), out)) {
72
+ oc.status = Outcome::Failed;
73
+ return oc;
74
+ }
75
+ if (session_->is_handshake_complete()) {
76
+ oc.remote_id = PeerId::from_public_key(session_->get_remote_static_public(),
77
+ librats::NOISE_DH_SIZE);
78
+ oc.session = std::make_unique<NoiseSessionAdapter>(std::move(session_), oc.remote_id);
79
+ oc.status = Outcome::Done;
80
+ }
81
+ return oc;
82
+ }
83
+
84
+ private:
85
+ // Run one handshake step; append the outgoing message (if any) to `out`.
86
+ bool step(const uint8_t* received, size_t received_len, Bytes& out) {
87
+ // A Noise transport message is capped at 65535 bytes; reject anything
88
+ // larger before it reaches the state machine. Defense in depth: the
89
+ // block layer admits frames up to kMaxBlockSize (64 MB), so without
90
+ // this an oversized handshake frame would be fed straight in.
91
+ if (received_len > librats::NOISE_MAX_MESSAGE_SIZE) {
92
+ LOG_DEBUG("noise", "Rejecting oversized handshake message (" << received_len << " B)");
93
+ return false;
94
+ }
95
+
96
+ uint8_t buffer[librats::NOISE_MAX_MESSAGE_SIZE];
97
+ size_t len = sizeof(buffer);
98
+ bool need_to_send = false;
99
+ const auto err = session_->handshake_step(received, received_len, buffer, &len, &need_to_send);
100
+ if (err != librats::NoiseError::OK) {
101
+ LOG_DEBUG("noise", "Handshake step failed: " << noise_error_name(err)
102
+ << " (" << (initiator_ ? "initiator" : "responder") << ")");
103
+ return false;
104
+ }
105
+ if (need_to_send) out.insert(out.end(), buffer, buffer + len);
106
+ return true;
107
+ }
108
+
109
+ std::unique_ptr<librats::NoiseSession> session_;
110
+ bool initiator_;
111
+ };
112
+
113
+ } // namespace
114
+
115
+ NoiseSecurity::NoiseSecurity(Identity identity, std::string protocol)
116
+ : identity_(identity), prologue_(protocol_id(protocol)) {}
117
+
118
+ std::unique_ptr<Handshaker> NoiseSecurity::create(ConnRole role) {
119
+ return std::make_unique<NoiseHandshaker>(identity_, role == ConnRole::Outbound, ByteView(prologue_));
120
+ }
121
+
122
+ } // namespace librats
@@ -0,0 +1,37 @@
1
+ #pragma once
2
+
3
+ /**
4
+ * @file noise_security.h
5
+ * @brief Noise_XX_25519_ChaChaPoly_SHA256 secure channel with self-certifying ids.
6
+ *
7
+ * Wraps the existing librats::NoiseSession (src/noise.h) behind the
8
+ * SecurityProvider/Handshaker/Session contract. The XX pattern mutually
9
+ * authenticates both static keys, and each side derives the other's PeerId from
10
+ * the static key it proved — so a completed handshake is also identity proof.
11
+ */
12
+
13
+ #include "librats/util/rats_export.h"
14
+ #include "librats/security/handshaker.h"
15
+ #include "librats/security/identity.h"
16
+
17
+ #include <memory>
18
+ #include <string>
19
+
20
+ namespace librats {
21
+
22
+ class RATS_API NoiseSecurity final : public SecurityProvider {
23
+ public:
24
+ /// @param protocol Application protocol id, bound into the Noise handshake
25
+ /// prologue. Peers whose protocol differs cannot complete a handshake
26
+ /// — cross-application isolation, enforced cryptographically (a
27
+ /// mismatch fails the handshake MAC). By convention "<name>/<version>".
28
+ explicit NoiseSecurity(Identity identity, std::string protocol = "librats/1.0");
29
+ std::unique_ptr<Handshaker> create(ConnRole role) override;
30
+ const PeerId& local_id() const override { return identity_.id; }
31
+
32
+ private:
33
+ Identity identity_;
34
+ std::string prologue_; ///< length-prefixed name+version, mixed into every handshake
35
+ };
36
+
37
+ } // namespace librats
@@ -0,0 +1,106 @@
1
+ #pragma once
2
+
3
+ /**
4
+ * @file plaintext_security.h
5
+ * @brief Unencrypted "secure channel": exchanges PeerIds, encrypts nothing.
6
+ *
7
+ * Useful for local/testing setups and as the trivial reference implementation
8
+ * of the SecurityProvider/Handshaker/Session contract. The handshake exchanges
9
+ * one message each way carrying the protocol id and the PeerId; the resulting
10
+ * Session is a passthrough. Note the identity here is NOT authenticated (no key
11
+ * proof) — that is the inherent trade-off of running without encryption.
12
+ *
13
+ * The protocol id is still checked (so two apps with different protocol can't
14
+ * cross-connect even unencrypted), but unlike the Noise prologue it is not
15
+ * cryptographically bound — a plaintext peer can claim any protocol. That is
16
+ * acceptable for the plaintext mode's trusted/testing use cases.
17
+ *
18
+ * Handshake message: [proto_len:u16][protocol id][peer id: 32 bytes].
19
+ */
20
+
21
+ #include "librats/security/handshaker.h"
22
+ #include "librats/security/identity.h"
23
+
24
+ #include <cstring>
25
+ #include <memory>
26
+ #include <string>
27
+
28
+ namespace librats {
29
+
30
+ /// Passthrough session: encrypt/decrypt just copy the bytes.
31
+ class PlaintextSession final : public Session {
32
+ public:
33
+ explicit PlaintextSession(PeerId remote) : remote_id_(remote) {}
34
+ bool encrypt(ByteView plain, Bytes& out) override { out.assign(plain.begin(), plain.end()); return true; }
35
+ bool decrypt(ByteView cipher, Bytes& out) override { out.assign(cipher.begin(), cipher.end()); return true; }
36
+ const PeerId& remote_id() const override { return remote_id_; }
37
+ bool is_secure() const override { return false; }
38
+ private:
39
+ PeerId remote_id_;
40
+ };
41
+
42
+ /// One-message-each exchange of [protocol id][PeerId].
43
+ class PlaintextHandshaker final : public Handshaker {
44
+ public:
45
+ PlaintextHandshaker(PeerId local, bool initiator, std::string proto)
46
+ : local_(local), proto_(std::move(proto)), initiator_(initiator) {}
47
+
48
+ bool start(Bytes& out) override {
49
+ if (initiator_) append_message(out); // initiator announces first
50
+ return true;
51
+ }
52
+
53
+ Outcome consume(ByteView incoming, Bytes& out) override {
54
+ Outcome oc;
55
+ const uint8_t* p = incoming.data();
56
+ const size_t n = incoming.size();
57
+ if (n < 2) { oc.status = Outcome::Failed; return oc; }
58
+
59
+ const size_t proto_len = (static_cast<size_t>(p[0]) << 8) | p[1];
60
+ if (n < 2 + proto_len + PeerId::kSize) { oc.status = Outcome::Failed; return oc; }
61
+
62
+ // Reject a peer announcing a different protocol id.
63
+ if (proto_len != proto_.size() ||
64
+ std::memcmp(p + 2, proto_.data(), proto_len) != 0) {
65
+ oc.status = Outcome::Failed;
66
+ return oc;
67
+ }
68
+
69
+ auto remote = PeerId::from_bytes(ByteView(p + 2 + proto_len, PeerId::kSize));
70
+ if (!remote) { oc.status = Outcome::Failed; return oc; }
71
+
72
+ if (!initiator_) append_message(out); // responder replies
73
+ oc.status = Outcome::Done;
74
+ oc.remote_id = *remote;
75
+ oc.session = std::make_unique<PlaintextSession>(*remote);
76
+ return oc;
77
+ }
78
+
79
+ private:
80
+ void append_message(Bytes& out) {
81
+ out.push_back(static_cast<uint8_t>((proto_.size() >> 8) & 0xFF));
82
+ out.push_back(static_cast<uint8_t>(proto_.size() & 0xFF));
83
+ out.insert(out.end(), proto_.begin(), proto_.end());
84
+ const auto& b = local_.bytes();
85
+ out.insert(out.end(), b.begin(), b.end());
86
+ }
87
+
88
+ PeerId local_;
89
+ std::string proto_;
90
+ bool initiator_;
91
+ };
92
+
93
+ class PlaintextSecurity final : public SecurityProvider {
94
+ public:
95
+ explicit PlaintextSecurity(Identity identity, std::string protocol = "librats/1.0")
96
+ : identity_(identity), proto_(protocol_id(protocol)) {}
97
+ std::unique_ptr<Handshaker> create(ConnRole role) override {
98
+ return std::make_unique<PlaintextHandshaker>(identity_.id, role == ConnRole::Outbound, proto_);
99
+ }
100
+ const PeerId& local_id() const override { return identity_.id; }
101
+ private:
102
+ Identity identity_;
103
+ std::string proto_;
104
+ };
105
+
106
+ } // namespace librats
@@ -0,0 +1,37 @@
1
+ #pragma once
2
+
3
+ /**
4
+ * @file session.h
5
+ * @brief Post-handshake symmetric session: encrypts/decrypts transport frames.
6
+ *
7
+ * A Session is produced by a Handshaker once the secure channel is established.
8
+ * The Connection holds it and runs every outbound frame through encrypt() and
9
+ * every inbound frame through decrypt(). The plaintext mode supplies a
10
+ * passthrough Session so the Connection code path is identical with or without
11
+ * encryption — no `if (encrypted)` scattered through the hot path.
12
+ */
13
+
14
+ #include "librats/util/rats_export.h"
15
+ #include "librats/core/bytes.h"
16
+ #include "librats/peer/peer_id.h"
17
+
18
+ namespace librats {
19
+
20
+ class RATS_API Session {
21
+ public:
22
+ virtual ~Session() = default;
23
+
24
+ /// Encrypt `plain` into `out` (resized to fit). Returns false on failure.
25
+ virtual bool encrypt(ByteView plain, Bytes& out) = 0;
26
+
27
+ /// Decrypt `cipher` into `out` (resized to fit). Returns false on failure.
28
+ virtual bool decrypt(ByteView cipher, Bytes& out) = 0;
29
+
30
+ /// The remote peer's identity, proven during the handshake.
31
+ virtual const PeerId& remote_id() const = 0;
32
+
33
+ /// True if traffic is actually encrypted (false for the plaintext passthrough).
34
+ virtual bool is_secure() const = 0;
35
+ };
36
+
37
+ } // namespace librats