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.
- package/README.md +145 -331
- package/binding.gyp +16 -3
- package/lib/index.d.ts +288 -696
- package/lib/index.js +407 -44
- package/native-src/3rdparty/android/ifaddrs-android.c +1 -0
- package/native-src/3rdparty/android/ifaddrs-android.h +1 -0
- package/native-src/CMakeLists.txt +404 -179
- package/native-src/LICENSE +1 -1
- package/native-src/src/librats/bindings/rats.cpp +762 -0
- package/native-src/src/librats/bindings/rats.h +380 -0
- package/native-src/src/librats/bittorrent/bencode.cpp +437 -0
- package/native-src/src/librats/bittorrent/bencode.h +176 -0
- package/native-src/src/librats/bittorrent/bitfield.cpp +97 -0
- package/native-src/src/librats/bittorrent/bitfield.h +76 -0
- package/native-src/src/librats/bittorrent/byte_io.h +58 -0
- package/native-src/src/librats/bittorrent/choker.cpp +25 -0
- package/native-src/src/librats/bittorrent/choker.h +46 -0
- package/native-src/src/librats/bittorrent/client.cpp +413 -0
- package/native-src/src/librats/bittorrent/client.h +227 -0
- package/native-src/src/librats/bittorrent/disk_io.cpp +209 -0
- package/native-src/src/librats/bittorrent/disk_io.h +150 -0
- package/native-src/src/librats/bittorrent/extensions.cpp +191 -0
- package/native-src/src/librats/bittorrent/extensions.h +94 -0
- package/native-src/src/librats/bittorrent/file_storage.cpp +77 -0
- package/native-src/src/librats/bittorrent/file_storage.h +79 -0
- package/native-src/src/librats/bittorrent/log.h +42 -0
- package/native-src/src/librats/bittorrent/magnet_uri.cpp +98 -0
- package/native-src/src/librats/bittorrent/magnet_uri.h +35 -0
- package/native-src/src/librats/bittorrent/peer_connection.cpp +502 -0
- package/native-src/src/librats/bittorrent/peer_connection.h +194 -0
- package/native-src/src/librats/bittorrent/peer_list.cpp +68 -0
- package/native-src/src/librats/bittorrent/peer_list.h +75 -0
- package/native-src/src/librats/bittorrent/piece_picker.cpp +352 -0
- package/native-src/src/librats/bittorrent/piece_picker.h +201 -0
- package/native-src/src/librats/bittorrent/reactor.cpp +97 -0
- package/native-src/src/librats/bittorrent/reactor.h +89 -0
- package/native-src/src/librats/bittorrent/resume_data.cpp +72 -0
- package/native-src/src/librats/bittorrent/resume_data.h +41 -0
- package/native-src/src/librats/bittorrent/store_buffer.cpp +48 -0
- package/native-src/src/librats/bittorrent/store_buffer.h +47 -0
- package/native-src/src/librats/bittorrent/torrent.cpp +870 -0
- package/native-src/src/librats/bittorrent/torrent.h +260 -0
- package/native-src/src/librats/bittorrent/torrent_creator.cpp +129 -0
- package/native-src/src/librats/bittorrent/torrent_creator.h +58 -0
- package/native-src/src/librats/bittorrent/torrent_info.cpp +314 -0
- package/native-src/src/librats/bittorrent/torrent_info.h +118 -0
- package/native-src/src/librats/bittorrent/tracker.cpp +374 -0
- package/native-src/src/librats/bittorrent/tracker.h +108 -0
- package/native-src/src/librats/bittorrent/types.cpp +206 -0
- package/native-src/src/librats/bittorrent/types.h +86 -0
- package/native-src/src/librats/core/address.cpp +35 -0
- package/native-src/src/librats/core/address.h +78 -0
- package/native-src/src/librats/core/bytes.h +69 -0
- package/native-src/src/librats/core/chained_send_buffer.cpp +172 -0
- package/native-src/src/librats/core/chained_send_buffer.h +183 -0
- package/native-src/src/librats/core/endpoint_parse.cpp +41 -0
- package/native-src/src/librats/core/endpoint_parse.h +31 -0
- package/native-src/src/librats/core/event_bus.h +70 -0
- package/native-src/src/librats/core/host_endpoint.h +56 -0
- package/native-src/src/{io_poller.cpp → librats/core/io_poller.cpp} +520 -65
- package/native-src/src/{io_poller.h → librats/core/io_poller.h} +12 -6
- package/native-src/src/librats/core/ip_address.cpp +120 -0
- package/native-src/src/librats/core/ip_address.h +109 -0
- package/native-src/src/librats/core/mpsc_queue.h +47 -0
- package/native-src/src/librats/core/notifier.h +74 -0
- package/native-src/src/librats/core/receive_buffer.cpp +219 -0
- package/native-src/src/librats/core/receive_buffer.h +171 -0
- package/native-src/src/librats/core/service_registry.h +58 -0
- package/native-src/src/{socket.cpp → librats/core/socket.cpp} +625 -118
- package/native-src/src/librats/core/socket.h +496 -0
- package/native-src/src/librats/core/timer_queue.h +105 -0
- package/native-src/src/librats/core/types.cpp +43 -0
- package/native-src/src/librats/core/types.h +103 -0
- package/native-src/src/librats/core/wakeup_pipe.h +83 -0
- package/native-src/src/{crypto → librats/crypto}/blake2_endian.h +21 -23
- package/native-src/src/{crypto → librats/crypto}/blake2b.c +34 -33
- package/native-src/src/{crypto → librats/crypto}/blake2b.h +7 -6
- package/native-src/src/{crypto → librats/crypto}/blake2s.c +55 -54
- package/native-src/src/{crypto → librats/crypto}/blake2s.h +13 -12
- package/native-src/src/{crypto → librats/crypto}/chacha.c +22 -21
- package/native-src/src/{crypto → librats/crypto}/chacha.h +14 -13
- package/native-src/src/{crypto → librats/crypto}/chachapoly.c +56 -56
- package/native-src/src/{crypto → librats/crypto}/chachapoly.h +24 -17
- package/native-src/src/{crc32.cpp → librats/crypto/crc32.cpp} +1 -1
- package/native-src/src/{crc32.h → librats/crypto/crc32.h} +3 -1
- package/native-src/src/{crypto → librats/crypto}/curve25519.c +6 -4
- package/native-src/src/{crypto → librats/crypto}/curve25519.h +6 -3
- package/native-src/src/librats/crypto/hkdf.c +266 -0
- package/native-src/src/{crypto → librats/crypto}/hkdf.h +19 -19
- package/native-src/src/{noise.cpp → librats/crypto/noise.cpp} +84 -73
- package/native-src/src/{noise.h → librats/crypto/noise.h} +18 -8
- package/native-src/src/{crypto → librats/crypto}/poly1305.c +47 -46
- package/native-src/src/librats/crypto/poly1305.h +37 -0
- package/native-src/src/{sha1.cpp → librats/crypto/sha1.cpp} +33 -1
- package/native-src/src/{sha1.h → librats/crypto/sha1.h} +14 -6
- package/native-src/src/{crypto → librats/crypto}/sha256.c +15 -14
- package/native-src/src/{crypto → librats/crypto}/sha256.h +8 -7
- package/native-src/src/{crypto → librats/crypto}/sha512.c +15 -14
- package/native-src/src/{crypto → librats/crypto}/sha512.h +8 -7
- package/native-src/src/librats/dht/announce.cpp +37 -0
- package/native-src/src/librats/dht/announce.h +41 -0
- package/native-src/src/librats/dht/bep42.cpp +109 -0
- package/native-src/src/librats/dht/bep42.h +48 -0
- package/native-src/src/librats/dht/dht.cpp +501 -0
- package/native-src/src/librats/dht/dht.h +119 -0
- package/native-src/src/librats/dht/dht_runner.cpp +103 -0
- package/native-src/src/librats/dht/dht_runner.h +71 -0
- package/native-src/src/librats/dht/dos_blocker.cpp +42 -0
- package/native-src/src/librats/dht/dos_blocker.h +47 -0
- package/native-src/src/librats/dht/find_peers.cpp +52 -0
- package/native-src/src/librats/dht/find_peers.h +73 -0
- package/native-src/src/librats/dht/id.h +167 -0
- package/native-src/src/{krpc.cpp → librats/dht/krpc.cpp} +32 -81
- package/native-src/src/{krpc.h → librats/dht/krpc.h} +19 -23
- package/native-src/src/librats/dht/log.h +38 -0
- package/native-src/src/librats/dht/node.cpp +473 -0
- package/native-src/src/librats/dht/node.h +164 -0
- package/native-src/src/librats/dht/node_entry.h +81 -0
- package/native-src/src/librats/dht/observer.h +72 -0
- package/native-src/src/librats/dht/persistence.cpp +90 -0
- package/native-src/src/librats/dht/persistence.h +32 -0
- package/native-src/src/librats/dht/routing_table.cpp +559 -0
- package/native-src/src/librats/dht/routing_table.h +185 -0
- package/native-src/src/librats/dht/rpc_manager.cpp +127 -0
- package/native-src/src/librats/dht/rpc_manager.h +77 -0
- package/native-src/src/librats/dht/storage.cpp +92 -0
- package/native-src/src/librats/dht/storage.h +74 -0
- package/native-src/src/librats/dht/transport.h +27 -0
- package/native-src/src/librats/dht/traversal.cpp +326 -0
- package/native-src/src/librats/dht/traversal.h +120 -0
- package/native-src/src/librats/dht/udp_transport.cpp +49 -0
- package/native-src/src/librats/dht/udp_transport.h +51 -0
- package/native-src/src/librats/mdns/log.h +22 -0
- package/native-src/src/{mdns.cpp → librats/mdns/mdns.cpp} +75 -40
- package/native-src/src/{mdns.h → librats/mdns/mdns.h} +9 -8
- package/native-src/src/{natpmp.cpp → librats/nat/natpmp.cpp} +12 -9
- package/native-src/src/{natpmp.h → librats/nat/natpmp.h} +3 -3
- package/native-src/src/{port_mapping.h → librats/nat/port_mapping.h} +3 -2
- package/native-src/src/{stun.cpp → librats/nat/stun.cpp} +4 -4
- package/native-src/src/{stun.h → librats/nat/stun.h} +1 -1
- package/native-src/src/{upnp.cpp → librats/nat/upnp.cpp} +6 -6
- package/native-src/src/{upnp.h → librats/nat/upnp.h} +2 -2
- package/native-src/src/librats/node/circuit_service.h +84 -0
- package/native-src/src/librats/node/config.h +110 -0
- package/native-src/src/librats/node/dial_service.h +54 -0
- package/native-src/src/librats/node/dialer.cpp +264 -0
- package/native-src/src/librats/node/dialer.h +188 -0
- package/native-src/src/librats/node/host_events.h +26 -0
- package/native-src/src/librats/node/identify.cpp +130 -0
- package/native-src/src/librats/node/identify.h +71 -0
- package/native-src/src/librats/node/nat_status.cpp +103 -0
- package/native-src/src/librats/node/nat_status.h +118 -0
- package/native-src/src/librats/node/node.cpp +865 -0
- package/native-src/src/librats/node/node.h +344 -0
- package/native-src/src/librats/node/node_context.h +33 -0
- package/native-src/src/librats/node/peer_network.h +91 -0
- package/native-src/src/librats/peer/peer.h +49 -0
- package/native-src/src/librats/peer/peer_book.cpp +181 -0
- package/native-src/src/librats/peer/peer_book.h +88 -0
- package/native-src/src/librats/peer/peer_id.cpp +72 -0
- package/native-src/src/librats/peer/peer_id.h +62 -0
- package/native-src/src/librats/peer/peer_info.h +37 -0
- package/native-src/src/librats/peer/peer_table.cpp +170 -0
- package/native-src/src/librats/peer/peer_table.h +148 -0
- package/native-src/src/librats/security/handshaker.h +66 -0
- package/native-src/src/librats/security/identity.h +43 -0
- package/native-src/src/librats/security/noise_security.cpp +122 -0
- package/native-src/src/librats/security/noise_security.h +37 -0
- package/native-src/src/librats/security/plaintext_security.h +106 -0
- package/native-src/src/librats/security/session.h +37 -0
- package/native-src/src/{storage.cpp → librats/storage/storage.cpp} +369 -522
- package/native-src/src/{storage.h → librats/storage/storage.h} +135 -299
- package/native-src/src/librats/subsystems/bittorrent.cpp +211 -0
- package/native-src/src/librats/subsystems/bittorrent.h +136 -0
- package/native-src/src/librats/subsystems/dht_discovery.cpp +202 -0
- package/native-src/src/librats/subsystems/dht_discovery.h +123 -0
- package/native-src/src/librats/subsystems/dht_service.h +36 -0
- package/native-src/src/librats/subsystems/file_transfer.cpp +972 -0
- package/native-src/src/librats/subsystems/file_transfer.h +367 -0
- package/native-src/src/librats/subsystems/hole_punch.cpp +605 -0
- package/native-src/src/librats/subsystems/hole_punch.h +290 -0
- package/native-src/src/librats/subsystems/hole_punch_service.h +38 -0
- package/native-src/src/librats/subsystems/mdns_discovery.cpp +66 -0
- package/native-src/src/librats/subsystems/mdns_discovery.h +55 -0
- package/native-src/src/librats/subsystems/message_json.cpp +112 -0
- package/native-src/src/librats/subsystems/message_json.h +88 -0
- package/native-src/src/librats/subsystems/peer_exchange.cpp +241 -0
- package/native-src/src/librats/subsystems/peer_exchange.h +136 -0
- package/native-src/src/librats/subsystems/ping_service.cpp +98 -0
- package/native-src/src/librats/subsystems/ping_service.h +66 -0
- package/native-src/src/librats/subsystems/port_mapping_service.cpp +192 -0
- package/native-src/src/librats/subsystems/port_mapping_service.h +84 -0
- package/native-src/src/librats/subsystems/pubsub.cpp +567 -0
- package/native-src/src/librats/subsystems/pubsub.h +175 -0
- package/native-src/src/librats/subsystems/reconnection.cpp +239 -0
- package/native-src/src/librats/subsystems/reconnection.h +126 -0
- package/native-src/src/librats/subsystems/relay.cpp +1142 -0
- package/native-src/src/librats/subsystems/relay.h +211 -0
- package/native-src/src/librats/subsystems/relay_service.h +46 -0
- package/native-src/src/librats/transport/connection.cpp +343 -0
- package/native-src/src/librats/transport/connection.h +283 -0
- package/native-src/src/librats/transport/link.h +96 -0
- package/native-src/src/librats/transport/reactor.cpp +588 -0
- package/native-src/src/librats/transport/reactor.h +262 -0
- package/native-src/src/librats/transport/reactor_pool.h +81 -0
- package/native-src/src/librats/transport/relay_link.cpp +208 -0
- package/native-src/src/librats/transport/relay_link.h +303 -0
- package/native-src/src/librats/transport/tcp_link.cpp +49 -0
- package/native-src/src/librats/transport/tcp_link.h +43 -0
- package/native-src/src/librats/transport/udp_mux.cpp +617 -0
- package/native-src/src/librats/transport/udp_mux.h +363 -0
- package/native-src/src/librats/transport/udp_packet.cpp +121 -0
- package/native-src/src/librats/transport/udp_packet.h +190 -0
- package/native-src/src/librats/transport/udp_stream.cpp +1194 -0
- package/native-src/src/librats/transport/udp_stream.h +614 -0
- package/native-src/src/librats/util/features.h.in +51 -0
- package/native-src/src/{fs.cpp → librats/util/fs.cpp} +51 -3
- package/native-src/src/librats/util/fs.h +136 -0
- package/native-src/src/librats/util/json.cpp +1002 -0
- package/native-src/src/librats/util/json.h +444 -0
- package/native-src/src/{logger.cpp → librats/util/logger.cpp} +1 -1
- package/native-src/src/{logger.h → librats/util/logger.h} +43 -31
- package/native-src/src/{network_monitor.cpp → librats/util/network_monitor.cpp} +12 -4
- package/native-src/src/{network_monitor.h → librats/util/network_monitor.h} +2 -1
- package/native-src/src/{network_utils.cpp → librats/util/network_utils.cpp} +38 -23
- package/native-src/src/{network_utils.h → librats/util/network_utils.h} +15 -8
- package/native-src/src/{os.cpp → librats/util/os.cpp} +48 -18
- package/native-src/src/librats/util/rats_export.h +69 -0
- package/native-src/src/{version.cpp → librats/util/version.cpp} +2 -2
- package/native-src/src/{version.h.in → librats/util/version.h.in} +1 -1
- package/native-src/src/librats/wire/frame.cpp +76 -0
- package/native-src/src/librats/wire/frame.h +111 -0
- package/native-src/src/librats/wire/message_router.cpp +45 -0
- package/native-src/src/librats/wire/message_router.h +47 -0
- package/package.json +5 -4
- package/scripts/build-librats.js +1 -0
- package/scripts/postinstall.js +3 -3
- package/scripts/prepare-package.js +4 -4
- package/scripts/verify-installation.js +63 -105
- package/src/librats_node.cpp +1067 -1323
- package/native-src/src/bencode.cpp +0 -485
- package/native-src/src/bencode.h +0 -145
- package/native-src/src/bittorrent.cpp +0 -14
- package/native-src/src/bittorrent.h +0 -74
- package/native-src/src/bt_bitfield.cpp +0 -372
- package/native-src/src/bt_bitfield.h +0 -316
- package/native-src/src/bt_choker.cpp +0 -228
- package/native-src/src/bt_choker.h +0 -147
- package/native-src/src/bt_client.cpp +0 -1047
- package/native-src/src/bt_client.h +0 -445
- package/native-src/src/bt_create_torrent.cpp +0 -677
- package/native-src/src/bt_create_torrent.h +0 -473
- package/native-src/src/bt_extension.cpp +0 -469
- package/native-src/src/bt_extension.h +0 -309
- package/native-src/src/bt_file_storage.cpp +0 -261
- package/native-src/src/bt_file_storage.h +0 -298
- package/native-src/src/bt_handshake.cpp +0 -134
- package/native-src/src/bt_handshake.h +0 -157
- package/native-src/src/bt_messages.cpp +0 -364
- package/native-src/src/bt_messages.h +0 -324
- package/native-src/src/bt_network.cpp +0 -1007
- package/native-src/src/bt_network.h +0 -417
- package/native-src/src/bt_peer_connection.cpp +0 -742
- package/native-src/src/bt_peer_connection.h +0 -592
- package/native-src/src/bt_piece_picker.cpp +0 -786
- package/native-src/src/bt_piece_picker.h +0 -473
- package/native-src/src/bt_resume_data.cpp +0 -410
- package/native-src/src/bt_resume_data.h +0 -249
- package/native-src/src/bt_torrent.cpp +0 -2120
- package/native-src/src/bt_torrent.h +0 -641
- package/native-src/src/bt_torrent_info.cpp +0 -659
- package/native-src/src/bt_torrent_info.h +0 -418
- package/native-src/src/bt_types.h +0 -621
- package/native-src/src/chained_send_buffer.cpp +0 -75
- package/native-src/src/chained_send_buffer.h +0 -137
- package/native-src/src/crypto/hkdf.c +0 -266
- package/native-src/src/crypto/poly1305.h +0 -36
- package/native-src/src/dht.cpp +0 -3311
- package/native-src/src/dht.h +0 -717
- package/native-src/src/disk_io.cpp +0 -632
- package/native-src/src/disk_io.h +0 -315
- package/native-src/src/file_transfer.cpp +0 -1415
- package/native-src/src/file_transfer.h +0 -286
- package/native-src/src/fs.h +0 -108
- package/native-src/src/gossipsub.cpp +0 -1139
- package/native-src/src/gossipsub.h +0 -403
- package/native-src/src/ice.cpp +0 -893
- package/native-src/src/ice.h +0 -559
- package/native-src/src/json.hpp +0 -25526
- package/native-src/src/librats.cpp +0 -2378
- package/native-src/src/librats.h +0 -2324
- package/native-src/src/librats_bittorrent.cpp +0 -601
- package/native-src/src/librats_c.cpp +0 -1557
- package/native-src/src/librats_c.h +0 -323
- package/native-src/src/librats_discovery.cpp +0 -402
- package/native-src/src/librats_encryption.cpp +0 -275
- package/native-src/src/librats_file_transfer.cpp +0 -144
- package/native-src/src/librats_gossipsub.cpp +0 -289
- package/native-src/src/librats_ice.cpp +0 -213
- package/native-src/src/librats_log_macros.h +0 -36
- package/native-src/src/librats_logging.cpp +0 -173
- package/native-src/src/librats_mdns.cpp +0 -166
- package/native-src/src/librats_persistence.cpp +0 -796
- package/native-src/src/librats_portmap.cpp +0 -419
- package/native-src/src/librats_reconnection.cpp +0 -218
- package/native-src/src/librats_statistic.cpp +0 -105
- package/native-src/src/librats_storage.cpp +0 -189
- package/native-src/src/rats_export.h +0 -17
- package/native-src/src/receive_buffer.cpp +0 -82
- package/native-src/src/receive_buffer.h +0 -127
- package/native-src/src/socket.h +0 -228
- package/native-src/src/threadmanager.cpp +0 -105
- package/native-src/src/threadmanager.h +0 -53
- package/native-src/src/tracker.cpp +0 -1264
- package/native-src/src/tracker.h +0 -319
- package/native-src/src/turn.cpp +0 -762
- package/native-src/src/turn.h +0 -460
- package/native-src/src/wakeup_pipe.h +0 -60
- /package/native-src/src/{os.h → librats/util/os.h} +0 -0
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
#include "librats/peer/peer_book.h"
|
|
2
|
+
#include "librats/util/fs.h"
|
|
3
|
+
#include "librats/util/json.h"
|
|
4
|
+
|
|
5
|
+
#include <algorithm>
|
|
6
|
+
#include <unordered_set>
|
|
7
|
+
|
|
8
|
+
namespace librats {
|
|
9
|
+
|
|
10
|
+
namespace {
|
|
11
|
+
|
|
12
|
+
// "best first" ordering: returns true if a ranks strictly before b.
|
|
13
|
+
bool better(const PeerRecord& a, const PeerRecord& b) {
|
|
14
|
+
const bool ca = a.last_connected > 0, cb = b.last_connected > 0;
|
|
15
|
+
if (ca != cb) return ca; // ever-connected first
|
|
16
|
+
if (a.last_connected != b.last_connected) return a.last_connected > b.last_connected;
|
|
17
|
+
if (a.connect_count != b.connect_count) return a.connect_count > b.connect_count;
|
|
18
|
+
if (a.fail_streak != b.fail_streak) return a.fail_streak < b.fail_streak;
|
|
19
|
+
return a.last_seen > b.last_seen;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
bool is_stale(const PeerRecord& r, uint64_t now, uint64_t max_age_secs) {
|
|
23
|
+
return max_age_secs > 0 && r.last_seen > 0 && now > r.last_seen && (now - r.last_seen) > max_age_secs;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
} // namespace
|
|
27
|
+
|
|
28
|
+
void PeerBook::load() {
|
|
29
|
+
const std::string text = read_file_text_cpp(path_);
|
|
30
|
+
if (text.empty()) return;
|
|
31
|
+
|
|
32
|
+
// Non-throwing parse: a malformed/legacy file simply yields no records
|
|
33
|
+
// rather than crashing startup.
|
|
34
|
+
const Json root = Json::parse(text, nullptr, /*allow_exceptions=*/false);
|
|
35
|
+
if (!root.is_array()) return;
|
|
36
|
+
|
|
37
|
+
std::lock_guard<std::mutex> lock(mutex_);
|
|
38
|
+
for (const auto& j : root) {
|
|
39
|
+
if (!j.is_object()) continue;
|
|
40
|
+
const std::string ip = j.value("ip", std::string());
|
|
41
|
+
const uint16_t port = static_cast<uint16_t>(j.value("port", 0));
|
|
42
|
+
const auto ipaddr = IpAddress::parse(ip);
|
|
43
|
+
if (!ipaddr || port == 0) continue; // need a valid numeric ip + port
|
|
44
|
+
|
|
45
|
+
PeerRecord r;
|
|
46
|
+
r.address = Address{*ipaddr, port};
|
|
47
|
+
// Remaining metadata fields are optional; absent ones keep their defaults.
|
|
48
|
+
const std::string idhex = j.value("id", std::string());
|
|
49
|
+
if (!idhex.empty()) { if (auto id = PeerId::from_hex(idhex)) r.id = *id; }
|
|
50
|
+
r.first_seen = j.value("first_seen", uint64_t{0});
|
|
51
|
+
r.last_seen = j.value("last_seen", uint64_t{0});
|
|
52
|
+
r.last_connected = j.value("last_connected", uint64_t{0});
|
|
53
|
+
r.connect_count = j.value("connect_count", uint32_t{0});
|
|
54
|
+
r.fail_streak = j.value("fail_streak", uint32_t{0});
|
|
55
|
+
records_[r.address] = r;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
void PeerBook::save() const {
|
|
60
|
+
Json arr = Json::array();
|
|
61
|
+
{
|
|
62
|
+
std::lock_guard<std::mutex> lock(mutex_);
|
|
63
|
+
for (const auto& [key, r] : records_) {
|
|
64
|
+
Json j = Json::object();
|
|
65
|
+
j["ip"] = r.address.ip.to_string();
|
|
66
|
+
j["port"] = r.address.port;
|
|
67
|
+
if (!r.id.is_zero()) j["id"] = r.id.to_hex(); // omitted when never connected
|
|
68
|
+
j["first_seen"] = r.first_seen;
|
|
69
|
+
j["last_seen"] = r.last_seen;
|
|
70
|
+
j["last_connected"] = r.last_connected;
|
|
71
|
+
j["connect_count"] = r.connect_count;
|
|
72
|
+
j["fail_streak"] = r.fail_streak;
|
|
73
|
+
arr.push_back(std::move(j));
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
create_file(path_.c_str(), arr.dump(2).c_str());
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
void PeerBook::note_connected(const Address& address, const PeerId& id, uint64_t now) {
|
|
80
|
+
std::lock_guard<std::mutex> lock(mutex_);
|
|
81
|
+
PeerRecord& r = records_[address];
|
|
82
|
+
if (r.first_seen == 0) r.first_seen = now;
|
|
83
|
+
r.address = address;
|
|
84
|
+
if (!id.is_zero()) r.id = id;
|
|
85
|
+
r.last_seen = now;
|
|
86
|
+
r.last_connected = now;
|
|
87
|
+
r.connect_count++;
|
|
88
|
+
r.fail_streak = 0;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
void PeerBook::note_failure(const Address& address, uint64_t /*now*/) {
|
|
92
|
+
std::lock_guard<std::mutex> lock(mutex_);
|
|
93
|
+
auto it = records_.find(address);
|
|
94
|
+
if (it == records_.end()) return; // only track failures for peers we already know
|
|
95
|
+
// Deliberately does NOT refresh last_seen: a peer that only ever fails must
|
|
96
|
+
// still age out (otherwise repeated give-ups would keep it forever "fresh").
|
|
97
|
+
it->second.fail_streak++;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
void PeerBook::note_seen(const Address& address, uint64_t now) {
|
|
101
|
+
std::lock_guard<std::mutex> lock(mutex_);
|
|
102
|
+
PeerRecord& r = records_[address];
|
|
103
|
+
if (r.first_seen == 0) r.first_seen = now;
|
|
104
|
+
r.address = address;
|
|
105
|
+
r.last_seen = now;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
bool PeerBook::remove(const Address& address) {
|
|
109
|
+
std::lock_guard<std::mutex> lock(mutex_);
|
|
110
|
+
return records_.erase(address) > 0;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
std::vector<Address> PeerBook::best(size_t n, uint64_t now, uint64_t max_age_secs) const {
|
|
114
|
+
std::lock_guard<std::mutex> lock(mutex_);
|
|
115
|
+
std::vector<const PeerRecord*> recs;
|
|
116
|
+
recs.reserve(records_.size());
|
|
117
|
+
for (const auto& [key, r] : records_)
|
|
118
|
+
if (!is_stale(r, now, max_age_secs)) recs.push_back(&r);
|
|
119
|
+
|
|
120
|
+
std::sort(recs.begin(), recs.end(),
|
|
121
|
+
[](const PeerRecord* a, const PeerRecord* b) { return better(*a, *b); });
|
|
122
|
+
|
|
123
|
+
std::vector<Address> out;
|
|
124
|
+
for (const PeerRecord* r : recs) {
|
|
125
|
+
if (out.size() >= n) break;
|
|
126
|
+
out.push_back(r->address);
|
|
127
|
+
}
|
|
128
|
+
return out;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
size_t PeerBook::prune(uint64_t now, uint64_t max_age_secs, size_t max_size) {
|
|
132
|
+
std::lock_guard<std::mutex> lock(mutex_);
|
|
133
|
+
const size_t before = records_.size();
|
|
134
|
+
|
|
135
|
+
if (max_age_secs > 0) {
|
|
136
|
+
for (auto it = records_.begin(); it != records_.end();) {
|
|
137
|
+
if (is_stale(it->second, now, max_age_secs)) it = records_.erase(it);
|
|
138
|
+
else ++it;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
if (max_size > 0 && records_.size() > max_size) {
|
|
143
|
+
std::vector<const PeerRecord*> recs;
|
|
144
|
+
recs.reserve(records_.size());
|
|
145
|
+
for (const auto& [key, r] : records_) recs.push_back(&r);
|
|
146
|
+
std::sort(recs.begin(), recs.end(),
|
|
147
|
+
[](const PeerRecord* a, const PeerRecord* b) { return better(*a, *b); });
|
|
148
|
+
std::unordered_set<Address> keep;
|
|
149
|
+
keep.reserve(max_size);
|
|
150
|
+
for (size_t i = 0; i < max_size; ++i) keep.insert(recs[i]->address);
|
|
151
|
+
for (auto it = records_.begin(); it != records_.end();) {
|
|
152
|
+
if (keep.count(it->first)) ++it;
|
|
153
|
+
else it = records_.erase(it);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return before - records_.size();
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
std::vector<Address> PeerBook::all() const {
|
|
161
|
+
std::lock_guard<std::mutex> lock(mutex_);
|
|
162
|
+
std::vector<Address> out;
|
|
163
|
+
out.reserve(records_.size());
|
|
164
|
+
for (const auto& [key, r] : records_) out.push_back(r.address);
|
|
165
|
+
return out;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
std::vector<PeerRecord> PeerBook::records() const {
|
|
169
|
+
std::lock_guard<std::mutex> lock(mutex_);
|
|
170
|
+
std::vector<PeerRecord> out;
|
|
171
|
+
out.reserve(records_.size());
|
|
172
|
+
for (const auto& [key, r] : records_) out.push_back(r);
|
|
173
|
+
return out;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
size_t PeerBook::size() const {
|
|
177
|
+
std::lock_guard<std::mutex> lock(mutex_);
|
|
178
|
+
return records_.size();
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
} // namespace librats
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file peer_book.h
|
|
5
|
+
* @brief Persistent address book of peers worth reconnecting to.
|
|
6
|
+
*
|
|
7
|
+
* Records every peer we have successfully connected to (and addresses we have
|
|
8
|
+
* learned), with light metadata: when we first/last saw it, when we last
|
|
9
|
+
* connected, how many times, and the current consecutive-failure streak. One
|
|
10
|
+
* ranked store serves BOTH needs at once — the "reconnect to recent peers"
|
|
11
|
+
* working set and the "remember everyone we ever met" archive. Callers query
|
|
12
|
+
* best() for the most promising addresses and rely on prune() to age out the
|
|
13
|
+
* long tail.
|
|
14
|
+
*
|
|
15
|
+
* Time is passed in (unix seconds) rather than read here, so the book stays a
|
|
16
|
+
* pure, testable data structure; the wall clock lives at the call site.
|
|
17
|
+
*
|
|
18
|
+
* Thread-safe. Backed by a human-readable JSON file: an array of objects, one
|
|
19
|
+
* per record, e.g.
|
|
20
|
+
* [
|
|
21
|
+
* {"ip":"127.0.0.1","port":4001,"id":"ab..","first_seen":1000,
|
|
22
|
+
* "last_seen":2000,"last_connected":2000,"connect_count":2,"fail_streak":0}
|
|
23
|
+
* ]
|
|
24
|
+
* The "id" field is omitted for peers we have only ever seen, never connected to.
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
#include "librats/util/rats_export.h"
|
|
28
|
+
#include "librats/core/address.h"
|
|
29
|
+
#include "librats/peer/peer_id.h"
|
|
30
|
+
|
|
31
|
+
#include <cstdint>
|
|
32
|
+
#include <mutex>
|
|
33
|
+
#include <string>
|
|
34
|
+
#include <unordered_map>
|
|
35
|
+
#include <vector>
|
|
36
|
+
|
|
37
|
+
namespace librats {
|
|
38
|
+
|
|
39
|
+
struct PeerRecord {
|
|
40
|
+
Address address;
|
|
41
|
+
PeerId id; ///< last known id (is_zero() if we never connected)
|
|
42
|
+
uint64_t first_seen = 0; ///< unix seconds first added/seen
|
|
43
|
+
uint64_t last_seen = 0; ///< unix seconds last seen (added / learned / connected)
|
|
44
|
+
uint64_t last_connected = 0; ///< unix seconds of last successful connection (0 = never)
|
|
45
|
+
uint32_t connect_count = 0; ///< successful connections
|
|
46
|
+
uint32_t fail_streak = 0; ///< consecutive failed dials since the last success
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
class RATS_API PeerBook {
|
|
50
|
+
public:
|
|
51
|
+
explicit PeerBook(std::string path) : path_(std::move(path)) {}
|
|
52
|
+
|
|
53
|
+
/// Load records from the backing file (no-op if it does not exist).
|
|
54
|
+
void load();
|
|
55
|
+
/// Persist the current records to the backing file.
|
|
56
|
+
void save() const;
|
|
57
|
+
|
|
58
|
+
/// A successful connection: refresh timestamps, bump connect_count, clear fails.
|
|
59
|
+
void note_connected(const Address& address, const PeerId& id, uint64_t now);
|
|
60
|
+
/// A failed dial to a known peer: bump its failure streak. Does NOT refresh
|
|
61
|
+
/// last_seen (so a peer that only ever fails still ages out). No-op if unknown.
|
|
62
|
+
void note_failure(const Address& address, uint64_t now);
|
|
63
|
+
/// Learned / manually added an address without (yet) connecting to it.
|
|
64
|
+
void note_seen(const Address& address, uint64_t now);
|
|
65
|
+
|
|
66
|
+
/// Remove an address entirely. Returns true if it was present.
|
|
67
|
+
bool remove(const Address& address);
|
|
68
|
+
|
|
69
|
+
/// Up to n most promising addresses (last seen within max_age_secs, or all if
|
|
70
|
+
/// max_age_secs == 0), best first: ever-connected before never-connected, then
|
|
71
|
+
/// most-recently-connected, then most connects, then fewest recent failures.
|
|
72
|
+
std::vector<Address> best(size_t n, uint64_t now, uint64_t max_age_secs) const;
|
|
73
|
+
|
|
74
|
+
/// Drop records last seen longer ago than max_age_secs (0 = no aging), then cap
|
|
75
|
+
/// to max_size (0 = no cap) keeping the best. Returns the number removed.
|
|
76
|
+
size_t prune(uint64_t now, uint64_t max_age_secs, size_t max_size);
|
|
77
|
+
|
|
78
|
+
std::vector<Address> all() const;
|
|
79
|
+
std::vector<PeerRecord> records() const;
|
|
80
|
+
size_t size() const;
|
|
81
|
+
|
|
82
|
+
private:
|
|
83
|
+
std::string path_;
|
|
84
|
+
mutable std::mutex mutex_;
|
|
85
|
+
std::unordered_map<Address, PeerRecord> records_; ///< keyed by the peer Address
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
} // namespace librats
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
#include "librats/peer/peer_id.h"
|
|
2
|
+
|
|
3
|
+
extern "C" {
|
|
4
|
+
#include "librats/crypto/sha256.h"
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
#include <cstring>
|
|
8
|
+
|
|
9
|
+
namespace librats {
|
|
10
|
+
|
|
11
|
+
namespace {
|
|
12
|
+
constexpr char kHexDigits[] = "0123456789abcdef";
|
|
13
|
+
|
|
14
|
+
int hex_value(char c) {
|
|
15
|
+
if (c >= '0' && c <= '9') return c - '0';
|
|
16
|
+
if (c >= 'a' && c <= 'f') return c - 'a' + 10;
|
|
17
|
+
if (c >= 'A' && c <= 'F') return c - 'A' + 10;
|
|
18
|
+
return -1;
|
|
19
|
+
}
|
|
20
|
+
} // namespace
|
|
21
|
+
|
|
22
|
+
PeerId PeerId::from_public_key(const uint8_t* key, size_t len) {
|
|
23
|
+
PeerId id;
|
|
24
|
+
rats_sha256_hash(id.bytes_.data(), key, len);
|
|
25
|
+
return id;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
std::optional<PeerId> PeerId::from_bytes(ByteView raw) {
|
|
29
|
+
if (raw.size() != kSize) return std::nullopt;
|
|
30
|
+
PeerId id;
|
|
31
|
+
std::memcpy(id.bytes_.data(), raw.data(), kSize);
|
|
32
|
+
return id;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
std::optional<PeerId> PeerId::from_hex(std::string_view hex) {
|
|
36
|
+
if (hex.size() != kSize * 2) return std::nullopt;
|
|
37
|
+
PeerId id;
|
|
38
|
+
for (size_t i = 0; i < kSize; ++i) {
|
|
39
|
+
const int hi = hex_value(hex[2 * i]);
|
|
40
|
+
const int lo = hex_value(hex[2 * i + 1]);
|
|
41
|
+
if (hi < 0 || lo < 0) return std::nullopt;
|
|
42
|
+
id.bytes_[i] = static_cast<uint8_t>((hi << 4) | lo);
|
|
43
|
+
}
|
|
44
|
+
return id;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
std::string PeerId::to_hex() const {
|
|
48
|
+
std::string out(kSize * 2, '0');
|
|
49
|
+
for (size_t i = 0; i < kSize; ++i) {
|
|
50
|
+
out[2 * i] = kHexDigits[bytes_[i] >> 4];
|
|
51
|
+
out[2 * i + 1] = kHexDigits[bytes_[i] & 0x0F];
|
|
52
|
+
}
|
|
53
|
+
return out;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
std::string PeerId::short_hex() const {
|
|
57
|
+
return to_hex().substr(0, 8);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
bool PeerId::is_zero() const noexcept {
|
|
61
|
+
for (uint8_t b : bytes_) if (b != 0) return false;
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
size_t PeerId::Hash::operator()(const PeerId& id) const noexcept {
|
|
66
|
+
// The bytes are already a uniform hash; fold the first word into size_t.
|
|
67
|
+
size_t h = 0;
|
|
68
|
+
std::memcpy(&h, id.bytes_.data(), sizeof(h));
|
|
69
|
+
return h;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
} // namespace librats
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file peer_id.h
|
|
5
|
+
* @brief Self-certifying peer identity.
|
|
6
|
+
*
|
|
7
|
+
* A PeerId is the SHA-256 of a peer's static (Noise) public key. Because the
|
|
8
|
+
* Noise XX handshake proves possession of that key, a completed handshake also
|
|
9
|
+
* proves the remote's PeerId — identity is cryptographically bound to the key
|
|
10
|
+
* and cannot be forged (libp2p uses the same self-certifying scheme).
|
|
11
|
+
*
|
|
12
|
+
* This is a value type: cheap to copy, hashable, and ordered, so it slots
|
|
13
|
+
* straight into unordered_map / set as a key.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
#include "librats/util/rats_export.h"
|
|
17
|
+
#include "librats/core/bytes.h"
|
|
18
|
+
|
|
19
|
+
#include <array>
|
|
20
|
+
#include <cstdint>
|
|
21
|
+
#include <optional>
|
|
22
|
+
#include <string>
|
|
23
|
+
#include <string_view>
|
|
24
|
+
|
|
25
|
+
namespace librats {
|
|
26
|
+
|
|
27
|
+
class RATS_API PeerId {
|
|
28
|
+
public:
|
|
29
|
+
static constexpr size_t kSize = 32; ///< SHA-256 digest length
|
|
30
|
+
|
|
31
|
+
PeerId() = default;
|
|
32
|
+
|
|
33
|
+
/// Derive the PeerId from a raw static public key (SHA-256 of the key).
|
|
34
|
+
static PeerId from_public_key(const uint8_t* key, size_t len);
|
|
35
|
+
static PeerId from_public_key(ByteView key) { return from_public_key(key.data(), key.size()); }
|
|
36
|
+
|
|
37
|
+
/// Wrap raw 32 id-bytes verbatim (NOT hashed). nullopt unless exactly kSize.
|
|
38
|
+
static std::optional<PeerId> from_bytes(ByteView raw);
|
|
39
|
+
|
|
40
|
+
/// Parse a 64-char lowercase/uppercase hex string. nullopt if malformed.
|
|
41
|
+
static std::optional<PeerId> from_hex(std::string_view hex);
|
|
42
|
+
|
|
43
|
+
std::string to_hex() const;
|
|
44
|
+
std::string short_hex() const; ///< first 8 hex chars, for logs
|
|
45
|
+
|
|
46
|
+
const std::array<uint8_t, kSize>& bytes() const noexcept { return bytes_; }
|
|
47
|
+
bool is_zero() const noexcept;
|
|
48
|
+
|
|
49
|
+
bool operator==(const PeerId& o) const noexcept { return bytes_ == o.bytes_; }
|
|
50
|
+
bool operator!=(const PeerId& o) const noexcept { return bytes_ != o.bytes_; }
|
|
51
|
+
bool operator<(const PeerId& o) const noexcept { return bytes_ < o.bytes_; }
|
|
52
|
+
|
|
53
|
+
/// Hash functor for use as an unordered_map/set key.
|
|
54
|
+
struct Hash {
|
|
55
|
+
size_t operator()(const PeerId& id) const noexcept;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
private:
|
|
59
|
+
std::array<uint8_t, kSize> bytes_{};
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
} // namespace librats
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file peer_info.h
|
|
5
|
+
* @brief Addressing/metadata for a peer — the shareable, persistable identity.
|
|
6
|
+
*
|
|
7
|
+
* PeerInfo is the "where / what" of a peer, kept separate from the live
|
|
8
|
+
* transport (Connection) and from the raw identity (PeerId). It is a value type:
|
|
9
|
+
* snapshotted into callbacks and into the PeerTable without touching live state.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
#include "librats/core/types.h" // ConnRole
|
|
13
|
+
#include "librats/core/address.h"
|
|
14
|
+
#include "librats/peer/peer_id.h"
|
|
15
|
+
|
|
16
|
+
#include <vector>
|
|
17
|
+
|
|
18
|
+
namespace librats {
|
|
19
|
+
|
|
20
|
+
/// Transports a peer says it accepts, as a bitmask (see IdentifyMessage). Kept
|
|
21
|
+
/// separate from `transport`, which is the one this connection actually uses.
|
|
22
|
+
enum PeerTransports : uint8_t {
|
|
23
|
+
PeerTransportNone = 0,
|
|
24
|
+
PeerTransportTcp = 1 << 0,
|
|
25
|
+
PeerTransportUdp = 1 << 1,
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
struct PeerInfo {
|
|
29
|
+
PeerId id;
|
|
30
|
+
std::vector<Address> addresses; ///< known dialable addresses
|
|
31
|
+
ConnRole direction = ConnRole::Outbound;
|
|
32
|
+
TransportKind transport = TransportKind::Tcp; ///< wire this connection runs on
|
|
33
|
+
uint8_t supported_transports = PeerTransportNone; ///< what the peer advertised
|
|
34
|
+
std::string agent_version; ///< optional remote agent string
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
} // namespace librats
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
#include "librats/peer/peer_table.h"
|
|
2
|
+
|
|
3
|
+
#include <algorithm> // std::find
|
|
4
|
+
#include <mutex> // std::unique_lock (shared_lock comes from <shared_mutex>)
|
|
5
|
+
|
|
6
|
+
namespace librats {
|
|
7
|
+
|
|
8
|
+
namespace {
|
|
9
|
+
|
|
10
|
+
/// How much a transport is worth when two connections to the same peer have to be
|
|
11
|
+
/// ranked. Both ends see the same pair of transports and apply the same order, so
|
|
12
|
+
/// they converge on the same survivor without exchanging a word.
|
|
13
|
+
///
|
|
14
|
+
/// Udp — one socket, one NAT mapping, a source port that can be dialed back
|
|
15
|
+
/// (see dialer.h). The best link there is.
|
|
16
|
+
/// Tcp — a direct link all the same, just a less useful one to a NAT.
|
|
17
|
+
/// Relay — not a direct link at all: every byte costs a third node bandwidth and
|
|
18
|
+
/// a round trip. Ranked last here for completeness; in practice a relayed
|
|
19
|
+
/// link is settled before this by the rule in add(), which lets ANY direct
|
|
20
|
+
/// link beat it regardless of role.
|
|
21
|
+
int transport_rank(TransportKind t) noexcept {
|
|
22
|
+
switch (t) {
|
|
23
|
+
case TransportKind::Udp: return 2;
|
|
24
|
+
case TransportKind::Tcp: return 1;
|
|
25
|
+
case TransportKind::Relay: return 0;
|
|
26
|
+
}
|
|
27
|
+
return 0;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
} // namespace
|
|
31
|
+
|
|
32
|
+
PeerTable::AddOutcome PeerTable::add(const PeerInfo& info, PeerRoute route,
|
|
33
|
+
bool prefer_outbound) {
|
|
34
|
+
std::unique_lock<std::shared_mutex> lock(mutex_);
|
|
35
|
+
auto [it, inserted] = peers_.try_emplace(info.id, Entry{info, route});
|
|
36
|
+
if (inserted) {
|
|
37
|
+
count_.fetch_add(1, std::memory_order_relaxed);
|
|
38
|
+
return {AddResult::NewPeer, std::nullopt};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
Entry& cur = it->second;
|
|
42
|
+
if (cur.route == route) { // same connection re-registering: refresh only
|
|
43
|
+
cur.info = info;
|
|
44
|
+
return {AddResult::Updated, std::nullopt};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// A different connection already serves this peer, and exactly one may survive.
|
|
48
|
+
// Both ends resolve the same pair, so every rule here must read something that
|
|
49
|
+
// looks identical from either side. Timing does not qualify — "whichever arrived
|
|
50
|
+
// first" gets a different answer at each end, and two ends that each keep the
|
|
51
|
+
// link the other just dropped are left with no link at all.
|
|
52
|
+
//
|
|
53
|
+
// one relayed, one not ⇒ not a race at all but an upgrade (or a late relay
|
|
54
|
+
// arriving under a direct link): the direct one wins,
|
|
55
|
+
// whatever the roles. Ranked FIRST, ahead of the role
|
|
56
|
+
// rule, because a relayed link that won on role would
|
|
57
|
+
// keep costing a third node bandwidth for the life of a
|
|
58
|
+
// peer we can reach ourselves. Both ends see the same
|
|
59
|
+
// pair of transports, so both reach this same verdict.
|
|
60
|
+
// opposite roles ⇒ cross-connect: keep the link started by the smaller id
|
|
61
|
+
// (prefer_outbound, opposite at each end by construction).
|
|
62
|
+
// different wires ⇒ a dial race whose attempts both got through. Both ends
|
|
63
|
+
// see the transports and rank them by the same explicit
|
|
64
|
+
// order (transport_rank above), so neither can rank the
|
|
65
|
+
// same pair differently.
|
|
66
|
+
// same role and wire ⇒ a reconnect, not a simultaneous pair: the old link is
|
|
67
|
+
// stale or already dead, so the newcomer is the live one.
|
|
68
|
+
const bool cur_relayed = cur.info.transport == TransportKind::Relay;
|
|
69
|
+
const bool new_relayed = info.transport == TransportKind::Relay;
|
|
70
|
+
|
|
71
|
+
bool keep_new = true;
|
|
72
|
+
if (cur_relayed != new_relayed) {
|
|
73
|
+
keep_new = !new_relayed;
|
|
74
|
+
} else if (cur.info.direction != info.direction) {
|
|
75
|
+
const ConnRole survivor = prefer_outbound ? ConnRole::Outbound : ConnRole::Inbound;
|
|
76
|
+
keep_new = (info.direction == survivor);
|
|
77
|
+
} else if (cur.info.transport != info.transport) {
|
|
78
|
+
keep_new = transport_rank(info.transport) > transport_rank(cur.info.transport);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (keep_new) {
|
|
82
|
+
const PeerRoute loser = cur.route;
|
|
83
|
+
cur = Entry{info, route};
|
|
84
|
+
return {AddResult::Replaced, loser};
|
|
85
|
+
}
|
|
86
|
+
return {AddResult::Rejected, route}; // existing wins; caller closes the new connection
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
std::vector<Address> PeerTable::add_addresses(const PeerId& id, PeerRoute route,
|
|
90
|
+
const std::vector<Address>& addresses) {
|
|
91
|
+
std::vector<Address> added;
|
|
92
|
+
std::unique_lock<std::shared_mutex> lock(mutex_);
|
|
93
|
+
auto it = peers_.find(id);
|
|
94
|
+
if (it == peers_.end() || it->second.route != route) return added;
|
|
95
|
+
|
|
96
|
+
std::vector<Address>& known = it->second.info.addresses;
|
|
97
|
+
for (const Address& addr : addresses) {
|
|
98
|
+
if (known.size() >= kMaxAddressesPerPeer) break;
|
|
99
|
+
if (std::find(known.begin(), known.end(), addr) != known.end()) continue; // dedup
|
|
100
|
+
known.push_back(addr);
|
|
101
|
+
added.push_back(addr);
|
|
102
|
+
}
|
|
103
|
+
return added;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
std::optional<PeerTable::Destination> PeerTable::destination(const PeerId& id) const {
|
|
107
|
+
std::shared_lock<std::shared_mutex> lock(mutex_);
|
|
108
|
+
auto it = peers_.find(id);
|
|
109
|
+
if (it == peers_.end()) return std::nullopt;
|
|
110
|
+
return Destination{it->second.route, it->second.writable, it->second.owed};
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
bool PeerTable::all_writable() const {
|
|
114
|
+
std::shared_lock<std::shared_mutex> lock(mutex_);
|
|
115
|
+
for (const auto& [id, entry] : peers_)
|
|
116
|
+
if (!entry.writable) return false;
|
|
117
|
+
return true;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
void PeerTable::set_writable(const PeerId& id, PeerRoute route, bool writable) {
|
|
121
|
+
std::unique_lock<std::shared_mutex> lock(mutex_);
|
|
122
|
+
auto it = peers_.find(id);
|
|
123
|
+
if (it == peers_.end() || it->second.route != route) return;
|
|
124
|
+
it->second.writable = writable;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
void PeerTable::set_supported_transports(const PeerId& id, PeerRoute route, uint8_t mask) {
|
|
128
|
+
std::unique_lock<std::shared_mutex> lock(mutex_);
|
|
129
|
+
auto it = peers_.find(id);
|
|
130
|
+
if (it == peers_.end() || it->second.route != route) return;
|
|
131
|
+
it->second.info.supported_transports = mask;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
bool PeerTable::remove(const PeerId& id, PeerRoute route) {
|
|
135
|
+
std::unique_lock<std::shared_mutex> lock(mutex_);
|
|
136
|
+
auto it = peers_.find(id);
|
|
137
|
+
if (it == peers_.end() || it->second.route != route) return false;
|
|
138
|
+
peers_.erase(it);
|
|
139
|
+
count_.fetch_sub(1, std::memory_order_relaxed);
|
|
140
|
+
return true;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
std::optional<PeerRoute> PeerTable::route(const PeerId& id) const {
|
|
144
|
+
std::shared_lock<std::shared_mutex> lock(mutex_);
|
|
145
|
+
auto it = peers_.find(id);
|
|
146
|
+
if (it == peers_.end()) return std::nullopt;
|
|
147
|
+
return it->second.route;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
std::optional<PeerInfo> PeerTable::info(const PeerId& id) const {
|
|
151
|
+
std::shared_lock<std::shared_mutex> lock(mutex_);
|
|
152
|
+
auto it = peers_.find(id);
|
|
153
|
+
if (it == peers_.end()) return std::nullopt;
|
|
154
|
+
return it->second.info;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
bool PeerTable::contains(const PeerId& id) const {
|
|
158
|
+
std::shared_lock<std::shared_mutex> lock(mutex_);
|
|
159
|
+
return peers_.find(id) != peers_.end();
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
std::vector<PeerInfo> PeerTable::snapshot() const {
|
|
163
|
+
std::shared_lock<std::shared_mutex> lock(mutex_);
|
|
164
|
+
std::vector<PeerInfo> out;
|
|
165
|
+
out.reserve(peers_.size());
|
|
166
|
+
for (const auto& [id, entry] : peers_) out.push_back(entry.info);
|
|
167
|
+
return out;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
} // namespace librats
|