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
package/native-src/src/dht.h
DELETED
|
@@ -1,717 +0,0 @@
|
|
|
1
|
-
#pragma once
|
|
2
|
-
|
|
3
|
-
#include "socket.h"
|
|
4
|
-
#include "krpc.h"
|
|
5
|
-
#include <string>
|
|
6
|
-
#include <vector>
|
|
7
|
-
#include <array>
|
|
8
|
-
#include <unordered_map>
|
|
9
|
-
#include <unordered_set>
|
|
10
|
-
#include <functional>
|
|
11
|
-
#include <thread>
|
|
12
|
-
#include <mutex>
|
|
13
|
-
#include <atomic>
|
|
14
|
-
#include <chrono>
|
|
15
|
-
#include <memory>
|
|
16
|
-
#include <random>
|
|
17
|
-
#include <condition_variable>
|
|
18
|
-
|
|
19
|
-
// Hash specialization for Peer and NodeId (must be defined before use in unordered_map/set)
|
|
20
|
-
namespace std {
|
|
21
|
-
template<>
|
|
22
|
-
struct hash<librats::Peer> {
|
|
23
|
-
std::size_t operator()(const librats::Peer& peer) const noexcept {
|
|
24
|
-
std::hash<std::string> hasher;
|
|
25
|
-
return hasher(peer.ip + ":" + std::to_string(peer.port));
|
|
26
|
-
}
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
template<>
|
|
30
|
-
struct hash<array<uint8_t, 20>> {
|
|
31
|
-
std::size_t operator()(const array<uint8_t, 20>& id) const noexcept {
|
|
32
|
-
std::size_t seed = 0;
|
|
33
|
-
std::hash<uint8_t> hasher;
|
|
34
|
-
for (const auto& byte : id) {
|
|
35
|
-
seed ^= hasher(byte) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
|
|
36
|
-
}
|
|
37
|
-
return seed;
|
|
38
|
-
}
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
namespace librats {
|
|
43
|
-
|
|
44
|
-
// Constants for Kademlia DHT
|
|
45
|
-
constexpr size_t NODE_ID_SIZE = 20; // 160 bits = 20 bytes
|
|
46
|
-
constexpr size_t K_BUCKET_SIZE = 8; // Maximum nodes per k-bucket
|
|
47
|
-
constexpr size_t ALPHA = 3; // Concurrency parameter
|
|
48
|
-
constexpr int DHT_PORT = 6881; // Standard BitTorrent DHT port
|
|
49
|
-
|
|
50
|
-
using NodeId = std::array<uint8_t, NODE_ID_SIZE>;
|
|
51
|
-
using InfoHash = std::array<uint8_t, NODE_ID_SIZE>;
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* Search node state flags (bitfield)
|
|
55
|
-
* Flags can be combined to track the full history of a node in a search.
|
|
56
|
-
*/
|
|
57
|
-
namespace SearchNodeFlags {
|
|
58
|
-
constexpr uint8_t QUERIED = 1 << 0; // Query has been sent to this node
|
|
59
|
-
constexpr uint8_t SHORT_TIMEOUT = 1 << 1; // Node exceeded short timeout (slot freed, still waiting)
|
|
60
|
-
constexpr uint8_t RESPONDED = 1 << 2; // Node successfully responded
|
|
61
|
-
constexpr uint8_t TIMED_OUT = 1 << 3; // Node fully timed out (failed)
|
|
62
|
-
constexpr uint8_t ABANDONED = 1 << 4; // Node was discarded during search truncation
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* DHT Node information
|
|
67
|
-
* Based on libtorrent's node_entry with fail_count and RTT tracking
|
|
68
|
-
*/
|
|
69
|
-
struct DhtNode {
|
|
70
|
-
NodeId id;
|
|
71
|
-
Peer peer;
|
|
72
|
-
std::chrono::steady_clock::time_point last_seen;
|
|
73
|
-
|
|
74
|
-
// Round-trip time in milliseconds (0xffff = unknown, lower is better)
|
|
75
|
-
uint16_t rtt = 0xffff;
|
|
76
|
-
|
|
77
|
-
// Number of consecutive failures (0xff = never pinged, 0 = confirmed good)
|
|
78
|
-
uint8_t fail_count = 0xff;
|
|
79
|
-
|
|
80
|
-
DhtNode() : id(), last_seen(std::chrono::steady_clock::now()) {}
|
|
81
|
-
DhtNode(const NodeId& id, const Peer& peer)
|
|
82
|
-
: id(id), peer(peer), last_seen(std::chrono::steady_clock::now()) {}
|
|
83
|
-
|
|
84
|
-
// Has this node ever responded to us?
|
|
85
|
-
bool pinged() const { return fail_count != 0xff; }
|
|
86
|
-
|
|
87
|
-
// Is this node confirmed good? (responded with no recent failures)
|
|
88
|
-
bool confirmed() const { return fail_count == 0; }
|
|
89
|
-
|
|
90
|
-
// Mark node as failed (timed out)
|
|
91
|
-
void mark_failed() {
|
|
92
|
-
if (pinged() && fail_count < 0xfe) ++fail_count;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
// Mark node as successful (responded)
|
|
96
|
-
void mark_success() {
|
|
97
|
-
fail_count = 0;
|
|
98
|
-
last_seen = std::chrono::steady_clock::now();
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
// Update RTT with exponential moving average
|
|
102
|
-
void update_rtt(uint16_t new_rtt) {
|
|
103
|
-
if (new_rtt == 0xffff) return;
|
|
104
|
-
if (rtt == 0xffff) {
|
|
105
|
-
rtt = new_rtt;
|
|
106
|
-
} else {
|
|
107
|
-
// Weighted average: 2/3 old + 1/3 new
|
|
108
|
-
rtt = static_cast<uint16_t>(rtt * 2 / 3 + new_rtt / 3);
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
// Compare nodes: "less" means "better" node
|
|
113
|
-
// Priority: confirmed > not confirmed, then lower fail_count, then lower RTT
|
|
114
|
-
bool is_worse_than(const DhtNode& other) const {
|
|
115
|
-
// Nodes with failures are worse
|
|
116
|
-
if (fail_count != other.fail_count) {
|
|
117
|
-
return fail_count > other.fail_count;
|
|
118
|
-
}
|
|
119
|
-
// Higher RTT is worse
|
|
120
|
-
return rtt > other.rtt;
|
|
121
|
-
}
|
|
122
|
-
};
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
/**
|
|
127
|
-
* Peer discovery callback
|
|
128
|
-
*/
|
|
129
|
-
using PeerDiscoveryCallback = std::function<void(const std::vector<Peer>& peers, const InfoHash& info_hash)>;
|
|
130
|
-
|
|
131
|
-
#ifdef RATS_SEARCH_FEATURES
|
|
132
|
-
/**
|
|
133
|
-
* Spider mode callback
|
|
134
|
-
* Called when a peer announces they have a torrent (announce_peer request received)
|
|
135
|
-
* @param info_hash The info hash being announced
|
|
136
|
-
* @param peer The peer that is announcing (with the port they specified)
|
|
137
|
-
*/
|
|
138
|
-
using SpiderAnnounceCallback = std::function<void(const InfoHash& info_hash, const Peer& peer)>;
|
|
139
|
-
#endif // RATS_SEARCH_FEATURES
|
|
140
|
-
|
|
141
|
-
/**
|
|
142
|
-
* Deferred callbacks structure for avoiding deadlock
|
|
143
|
-
* Callbacks are collected while holding the mutex, then invoked after releasing it
|
|
144
|
-
*/
|
|
145
|
-
struct DeferredCallbacks {
|
|
146
|
-
std::vector<PeerDiscoveryCallback> callbacks;
|
|
147
|
-
std::vector<Peer> peers;
|
|
148
|
-
InfoHash info_hash;
|
|
149
|
-
bool should_invoke = false;
|
|
150
|
-
|
|
151
|
-
void invoke() {
|
|
152
|
-
if (should_invoke) {
|
|
153
|
-
for (const auto& cb : callbacks) {
|
|
154
|
-
if (cb) cb(peers, info_hash);
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
};
|
|
159
|
-
|
|
160
|
-
/**
|
|
161
|
-
* DHT Kademlia implementation
|
|
162
|
-
*/
|
|
163
|
-
class DhtClient {
|
|
164
|
-
public:
|
|
165
|
-
/**
|
|
166
|
-
* Constructor
|
|
167
|
-
* @param port The UDP port to bind to (default: 6881)
|
|
168
|
-
* @param bind_address The interface IP address to bind to (empty for all interfaces)
|
|
169
|
-
* @param data_directory Directory for routing-table persistence
|
|
170
|
-
* @param address_family Address family this node operates on. IPv4 and IPv6 form
|
|
171
|
-
* separate Kademlia networks (BEP 32), so each family needs its own DhtClient.
|
|
172
|
-
*/
|
|
173
|
-
DhtClient(int port = DHT_PORT, const std::string& bind_address = "", const std::string& data_directory = "",
|
|
174
|
-
AddressFamily address_family = AddressFamily::IPv4);
|
|
175
|
-
|
|
176
|
-
/**
|
|
177
|
-
* Destructor
|
|
178
|
-
*/
|
|
179
|
-
~DhtClient();
|
|
180
|
-
|
|
181
|
-
/**
|
|
182
|
-
* Start the DHT client
|
|
183
|
-
* @return true if successful, false otherwise
|
|
184
|
-
*/
|
|
185
|
-
bool start();
|
|
186
|
-
|
|
187
|
-
/**
|
|
188
|
-
* Stop the DHT client
|
|
189
|
-
*/
|
|
190
|
-
void stop();
|
|
191
|
-
|
|
192
|
-
/**
|
|
193
|
-
* Trigger immediate shutdown of all background threads
|
|
194
|
-
*/
|
|
195
|
-
void shutdown_immediate();
|
|
196
|
-
|
|
197
|
-
/**
|
|
198
|
-
* Bootstrap the DHT with known nodes
|
|
199
|
-
* @param bootstrap_nodes Vector of bootstrap nodes
|
|
200
|
-
* @return true if successful, false otherwise
|
|
201
|
-
*/
|
|
202
|
-
bool bootstrap(const std::vector<Peer>& bootstrap_nodes);
|
|
203
|
-
|
|
204
|
-
/**
|
|
205
|
-
* Find peers for a specific info hash
|
|
206
|
-
* @param info_hash The info hash to search for
|
|
207
|
-
* @param callback Callback to receive discovered peers
|
|
208
|
-
* @return true if search started successfully, false otherwise
|
|
209
|
-
*/
|
|
210
|
-
bool find_peers(const InfoHash& info_hash, PeerDiscoveryCallback callback);
|
|
211
|
-
|
|
212
|
-
/**
|
|
213
|
-
* Announce that this node is a peer for a specific info hash
|
|
214
|
-
* @param info_hash The info hash to announce
|
|
215
|
-
* @param port The port to announce (0 for DHT port)
|
|
216
|
-
* @param callback Optional callback to receive discovered peers during traversal
|
|
217
|
-
* @return true if announcement started successfully, false otherwise
|
|
218
|
-
*/
|
|
219
|
-
bool announce_peer(const InfoHash& info_hash, uint16_t port = 0, PeerDiscoveryCallback callback = nullptr);
|
|
220
|
-
|
|
221
|
-
/**
|
|
222
|
-
* Cancel an active search or announce for a specific info hash
|
|
223
|
-
* Should be called when a torrent is removed to clean up DHT state.
|
|
224
|
-
* @param info_hash The info hash to cancel search for
|
|
225
|
-
*/
|
|
226
|
-
void cancel_search(const InfoHash& info_hash);
|
|
227
|
-
|
|
228
|
-
/**
|
|
229
|
-
* Get our node ID
|
|
230
|
-
* @return The node ID (returned by value; the ID may be regenerated at runtime
|
|
231
|
-
* when our external IP is learned, see set_external_ip)
|
|
232
|
-
*/
|
|
233
|
-
NodeId get_node_id() const { return node_id_; }
|
|
234
|
-
|
|
235
|
-
/**
|
|
236
|
-
* Set our external (public) IP address and regenerate the node ID from it per BEP 42.
|
|
237
|
-
* IPv4/IPv6 node IDs must be derived from the matching-family external address, so this
|
|
238
|
-
* is a no-op if the address family does not match this instance. Safe to call at runtime;
|
|
239
|
-
* the routing table is re-bucketed against the new ID. Non-public/invalid addresses are ignored.
|
|
240
|
-
* @param ip External IP address as seen by the network (e.g. from STUN or DHT "ip" voting)
|
|
241
|
-
*/
|
|
242
|
-
void set_external_ip(const std::string& ip);
|
|
243
|
-
|
|
244
|
-
/**
|
|
245
|
-
* Get the external address currently used to derive our node ID ("" if none/random).
|
|
246
|
-
*/
|
|
247
|
-
std::string get_external_address() const;
|
|
248
|
-
|
|
249
|
-
/**
|
|
250
|
-
* BEP 42 helpers (public for testing / explicit use).
|
|
251
|
-
* generate_node_id_from_ip: build an IP-derived node ID (random where BEP 42 allows).
|
|
252
|
-
* verify_node_id_for_ip: check whether a node ID is valid for the given source IP
|
|
253
|
-
* (always true for non-public IPs, which cannot be verified).
|
|
254
|
-
*/
|
|
255
|
-
static bool generate_node_id_from_ip(const std::string& ip, NodeId& out, std::mt19937& gen);
|
|
256
|
-
static bool verify_node_id_for_ip(const NodeId& id, const std::string& ip);
|
|
257
|
-
|
|
258
|
-
/**
|
|
259
|
-
* Get number of nodes in routing table
|
|
260
|
-
* @return Number of nodes
|
|
261
|
-
*/
|
|
262
|
-
size_t get_routing_table_size() const;
|
|
263
|
-
|
|
264
|
-
/**
|
|
265
|
-
* Get number of pending ping verifications
|
|
266
|
-
* @return Number of pending ping verifications
|
|
267
|
-
*/
|
|
268
|
-
size_t get_pending_ping_verifications_count() const;
|
|
269
|
-
|
|
270
|
-
/**
|
|
271
|
-
* Check if a search is currently active for an info hash
|
|
272
|
-
* @param info_hash The info hash to check
|
|
273
|
-
* @return true if search is active, false otherwise
|
|
274
|
-
*/
|
|
275
|
-
bool is_search_active(const InfoHash& info_hash) const;
|
|
276
|
-
|
|
277
|
-
/**
|
|
278
|
-
* Check if an announce is currently active for an info hash
|
|
279
|
-
* @param info_hash The info hash to check
|
|
280
|
-
* @return true if announce is active, false otherwise
|
|
281
|
-
*/
|
|
282
|
-
bool is_announce_active(const InfoHash& info_hash) const;
|
|
283
|
-
|
|
284
|
-
/**
|
|
285
|
-
* Get number of active searches
|
|
286
|
-
* @return Number of active searches
|
|
287
|
-
*/
|
|
288
|
-
size_t get_active_searches_count() const;
|
|
289
|
-
|
|
290
|
-
/**
|
|
291
|
-
* Get number of active announces
|
|
292
|
-
* @return Number of active announces
|
|
293
|
-
*/
|
|
294
|
-
size_t get_active_announces_count() const;
|
|
295
|
-
|
|
296
|
-
/**
|
|
297
|
-
* Check if DHT is running
|
|
298
|
-
* @return true if running, false otherwise
|
|
299
|
-
*/
|
|
300
|
-
bool is_running() const { return running_; }
|
|
301
|
-
|
|
302
|
-
/**
|
|
303
|
-
* Actual bound UDP port. May differ from the requested port if it was taken and
|
|
304
|
-
* the client fell back to an ephemeral port (see start()). Use this — not the
|
|
305
|
-
* requested port — when forwarding the DHT port through a router.
|
|
306
|
-
* @return bound port, or 0 if not started
|
|
307
|
-
*/
|
|
308
|
-
uint16_t get_port() const { return static_cast<uint16_t>(port_); }
|
|
309
|
-
|
|
310
|
-
#ifdef RATS_SEARCH_FEATURES
|
|
311
|
-
// ============================================================================
|
|
312
|
-
// SPIDER MODE - Aggressive node discovery and announce collection
|
|
313
|
-
// ============================================================================
|
|
314
|
-
|
|
315
|
-
/**
|
|
316
|
-
* Enable spider mode
|
|
317
|
-
* In spider mode:
|
|
318
|
-
* - Nodes are added to routing table without ping verification
|
|
319
|
-
* - All announce_peer requests from other peers are collected via callback
|
|
320
|
-
* @param enable true to enable spider mode, false to disable
|
|
321
|
-
*/
|
|
322
|
-
void set_spider_mode(bool enable);
|
|
323
|
-
|
|
324
|
-
/**
|
|
325
|
-
* Check if spider mode is enabled
|
|
326
|
-
* @return true if spider mode is enabled
|
|
327
|
-
*/
|
|
328
|
-
bool is_spider_mode() const { return spider_mode_; }
|
|
329
|
-
|
|
330
|
-
/**
|
|
331
|
-
* Set callback for announce_peer requests (spider mode)
|
|
332
|
-
* Called when other peers announce they have a torrent
|
|
333
|
-
* @param callback The callback to invoke
|
|
334
|
-
*/
|
|
335
|
-
void set_spider_announce_callback(SpiderAnnounceCallback callback);
|
|
336
|
-
|
|
337
|
-
/**
|
|
338
|
-
* Set spider ignore mode - when true, incoming requests are not processed
|
|
339
|
-
* Similar to rate limiting in the original spider implementation
|
|
340
|
-
* @param ignore true to ignore incoming requests, false to process them
|
|
341
|
-
*/
|
|
342
|
-
void set_spider_ignore(bool ignore);
|
|
343
|
-
|
|
344
|
-
/**
|
|
345
|
-
* Check if spider ignore mode is enabled
|
|
346
|
-
* @return true if ignoring incoming requests
|
|
347
|
-
*/
|
|
348
|
-
bool is_spider_ignoring() const { return spider_ignore_; }
|
|
349
|
-
|
|
350
|
-
/**
|
|
351
|
-
* Trigger a single spider walk iteration
|
|
352
|
-
* Sends find_node to a random node from the spider pool
|
|
353
|
-
* Should be called from external loop at desired frequency
|
|
354
|
-
*/
|
|
355
|
-
void spider_walk();
|
|
356
|
-
|
|
357
|
-
/**
|
|
358
|
-
* Get the size of the spider node pool
|
|
359
|
-
* @return Number of nodes in spider pool
|
|
360
|
-
*/
|
|
361
|
-
size_t get_spider_pool_size() const;
|
|
362
|
-
|
|
363
|
-
/**
|
|
364
|
-
* Get the number of visited nodes in spider mode
|
|
365
|
-
* @return Number of visited nodes
|
|
366
|
-
*/
|
|
367
|
-
size_t get_spider_visited_count() const;
|
|
368
|
-
|
|
369
|
-
/**
|
|
370
|
-
* Clear spider state (pool and visited nodes)
|
|
371
|
-
* Useful for resetting the spider walk
|
|
372
|
-
*/
|
|
373
|
-
void clear_spider_state();
|
|
374
|
-
#endif // RATS_SEARCH_FEATURES
|
|
375
|
-
|
|
376
|
-
/**
|
|
377
|
-
* Get default BitTorrent DHT bootstrap nodes.
|
|
378
|
-
* Hostnames are resolved per-family at send time, so the same list serves both
|
|
379
|
-
* IPv4 and IPv6 (nodes without an AAAA record are simply skipped on IPv6).
|
|
380
|
-
* @return Vector of bootstrap nodes
|
|
381
|
-
*/
|
|
382
|
-
static std::vector<Peer> get_default_bootstrap_nodes();
|
|
383
|
-
|
|
384
|
-
/**
|
|
385
|
-
* Address family this DHT node operates on.
|
|
386
|
-
*/
|
|
387
|
-
AddressFamily address_family() const { return address_family_; }
|
|
388
|
-
bool is_ipv6() const { return address_family_ == AddressFamily::IPv6; }
|
|
389
|
-
|
|
390
|
-
/**
|
|
391
|
-
* Compute the routing-table persistence file path for this instance.
|
|
392
|
-
* Includes the address family so the IPv4 and IPv6 nodes (which may share a port)
|
|
393
|
-
* never overwrite each other's saved state.
|
|
394
|
-
*/
|
|
395
|
-
std::string routing_table_file_path() const;
|
|
396
|
-
|
|
397
|
-
/**
|
|
398
|
-
* Save routing table to disk
|
|
399
|
-
* @return true if successful, false otherwise
|
|
400
|
-
*/
|
|
401
|
-
bool save_routing_table();
|
|
402
|
-
|
|
403
|
-
/**
|
|
404
|
-
* Load routing table from disk
|
|
405
|
-
* @return true if successful, false otherwise
|
|
406
|
-
*/
|
|
407
|
-
bool load_routing_table();
|
|
408
|
-
|
|
409
|
-
/**
|
|
410
|
-
* Set data directory for persistence
|
|
411
|
-
* @param directory Directory path
|
|
412
|
-
*/
|
|
413
|
-
void set_data_directory(const std::string& directory);
|
|
414
|
-
|
|
415
|
-
private:
|
|
416
|
-
int port_;
|
|
417
|
-
std::string bind_address_;
|
|
418
|
-
std::string data_directory_;
|
|
419
|
-
AddressFamily address_family_; // IPv4 or IPv6 (this node's Kademlia network)
|
|
420
|
-
NodeId node_id_; // protected by routing_table_mutex_ for writes; lock-free reads are benign
|
|
421
|
-
socket_t socket_;
|
|
422
|
-
std::atomic<bool> running_;
|
|
423
|
-
|
|
424
|
-
// BEP 42: external-IP-derived node ID.
|
|
425
|
-
// We learn our external address from the top-level "ip" field other nodes echo back in
|
|
426
|
-
// their responses, and vote across distinct responders before trusting it (so a single
|
|
427
|
-
// malicious node cannot poison our node ID). external_address_/voting are guarded by
|
|
428
|
-
// external_ip_mutex_, which is NEVER held while acquiring any other DHT mutex.
|
|
429
|
-
std::string external_address_; // IP currently used to derive node_id_ ("" = random)
|
|
430
|
-
std::unordered_map<std::string, int> external_ip_votes_;// reported external IP -> vote count
|
|
431
|
-
std::unordered_set<std::string> external_ip_voters_; // responder IPs already counted (dedup)
|
|
432
|
-
mutable std::mutex external_ip_mutex_; // Lock order: independent (never nested with others)
|
|
433
|
-
static constexpr int EXTERNAL_IP_VOTE_THRESHOLD = 5; // distinct responders that must agree
|
|
434
|
-
static constexpr size_t MAX_EXTERNAL_IP_VOTERS = 1000; // cap voter set to bound memory
|
|
435
|
-
|
|
436
|
-
// ============================================================================
|
|
437
|
-
// MUTEX LOCK ORDER - CRITICAL: Always acquire mutexes in this order to avoid deadlocks
|
|
438
|
-
// ============================================================================
|
|
439
|
-
// When acquiring multiple mutexes, ALWAYS follow this order:
|
|
440
|
-
//
|
|
441
|
-
// 1. pending_pings_mutex_ (Ping verification state, nodes_being_replaced_)
|
|
442
|
-
// 2. pending_searches_mutex_ (Search state and transaction mappings)
|
|
443
|
-
// 3. routing_table_mutex_ (core routing data)
|
|
444
|
-
// 4. spider_nodes_mutex_ (Spider mode: node pool and visited tracking) [RATS_SEARCH_FEATURES]
|
|
445
|
-
// 5. announced_peers_mutex_ (Stored peer data)
|
|
446
|
-
// 6. token_secret_mutex_ (DHT write-token secret)
|
|
447
|
-
// 7. shutdown_mutex_ (Lowest priority - can be locked independently)
|
|
448
|
-
//
|
|
449
|
-
// Routing table (k-buckets)
|
|
450
|
-
std::vector<std::vector<DhtNode>> routing_table_;
|
|
451
|
-
mutable std::mutex routing_table_mutex_; // Lock order: 3
|
|
452
|
-
|
|
453
|
-
// DHT write-token secret (BEP 5). Announce tokens are SHA1(secret || querier_ip || info_hash),
|
|
454
|
-
// so they are unforgeable (an attacker does not know the secret) and bound to BOTH the
|
|
455
|
-
// querier's address and the specific info_hash. The secret rotates periodically; we keep the
|
|
456
|
-
// previous secret so tokens handed out shortly before a rotation still verify. This replaces the
|
|
457
|
-
// old, trivially forgeable std::hash("ip:port") scheme. Guarded by token_secret_mutex_, which is
|
|
458
|
-
// a leaf lock (never held while acquiring any other DHT mutex).
|
|
459
|
-
static constexpr int TOKEN_SECRET_ROTATION_MINUTES = 5; // acceptance window ~= 2x this
|
|
460
|
-
std::array<uint8_t, 16> token_secret_;
|
|
461
|
-
std::array<uint8_t, 16> token_secret_prev_;
|
|
462
|
-
std::chrono::steady_clock::time_point token_secret_rotated_at_;
|
|
463
|
-
std::mutex token_secret_mutex_; // Lock order: 6
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
// Pending find_peers tracking (to map transaction IDs to info_hash)
|
|
468
|
-
struct PendingSearch {
|
|
469
|
-
InfoHash info_hash;
|
|
470
|
-
std::chrono::steady_clock::time_point created_at;
|
|
471
|
-
|
|
472
|
-
// Iterative search state - search_nodes is sorted by distance to info_hash (closest first)
|
|
473
|
-
std::vector<DhtNode> search_nodes;
|
|
474
|
-
std::vector<Peer> found_peers; // found peers for this search
|
|
475
|
-
// Single map tracking node states using SearchNodeFlags bitfield
|
|
476
|
-
// A node is "known" if it exists in this map (any flags set or value 0)
|
|
477
|
-
std::unordered_map<NodeId, uint8_t> node_states;
|
|
478
|
-
|
|
479
|
-
int invoke_count; // number of outstanding requests
|
|
480
|
-
int branch_factor; // adaptive concurrency limit (starts at ALPHA)
|
|
481
|
-
bool is_finished; // whether the search is finished
|
|
482
|
-
|
|
483
|
-
// Callbacks to invoke when peers are found (supports multiple concurrent searches for same info_hash)
|
|
484
|
-
std::vector<PeerDiscoveryCallback> callbacks;
|
|
485
|
-
|
|
486
|
-
// Announce support: tokens collected during traversal (BEP 5 compliant)
|
|
487
|
-
// Maps node_id -> write_token received from that node
|
|
488
|
-
std::unordered_map<NodeId, std::string> write_tokens;
|
|
489
|
-
bool is_announce; // true if this search is for announce_peer
|
|
490
|
-
uint16_t announce_port; // port to announce (only valid if is_announce)
|
|
491
|
-
|
|
492
|
-
PendingSearch(const InfoHash& hash)
|
|
493
|
-
: info_hash(hash), created_at(std::chrono::steady_clock::now()),
|
|
494
|
-
invoke_count(0), branch_factor(ALPHA), is_finished(false),
|
|
495
|
-
is_announce(false), announce_port(0) {}
|
|
496
|
-
};
|
|
497
|
-
std::unordered_map<std::string, PendingSearch> pending_searches_; // info_hash (hex) -> PendingSearch
|
|
498
|
-
mutable std::mutex pending_searches_mutex_; // Lock order: 2
|
|
499
|
-
|
|
500
|
-
// Transaction tracking with queried node info for proper responded_nodes tracking
|
|
501
|
-
struct SearchTransaction {
|
|
502
|
-
std::string info_hash_hex;
|
|
503
|
-
NodeId queried_node_id;
|
|
504
|
-
Peer queried_endpoint; // endpoint we actually sent the query to (anti-spoofing)
|
|
505
|
-
std::chrono::steady_clock::time_point sent_at;
|
|
506
|
-
|
|
507
|
-
SearchTransaction() = default;
|
|
508
|
-
SearchTransaction(const std::string& hash, const NodeId& id, const Peer& endpoint)
|
|
509
|
-
: info_hash_hex(hash), queried_node_id(id), queried_endpoint(endpoint),
|
|
510
|
-
sent_at(std::chrono::steady_clock::now()) {}
|
|
511
|
-
};
|
|
512
|
-
std::unordered_map<std::string, SearchTransaction> transaction_to_search_; // transaction_id -> SearchTransaction
|
|
513
|
-
|
|
514
|
-
// Peer announcement storage (BEP 5 compliant)
|
|
515
|
-
struct AnnouncedPeer {
|
|
516
|
-
Peer peer;
|
|
517
|
-
std::chrono::steady_clock::time_point announced_at;
|
|
518
|
-
|
|
519
|
-
AnnouncedPeer(const Peer& p)
|
|
520
|
-
: peer(p), announced_at(std::chrono::steady_clock::now()) {}
|
|
521
|
-
};
|
|
522
|
-
// Map from info_hash (as hex string) to list of announced peers
|
|
523
|
-
std::unordered_map<std::string, std::vector<AnnouncedPeer>> announced_peers_;
|
|
524
|
-
std::mutex announced_peers_mutex_; // Lock order: 5
|
|
525
|
-
|
|
526
|
-
// Ping-before-replace eviction tracking (BEP 5 compliant)
|
|
527
|
-
// When a bucket is full and a new node wants to join:
|
|
528
|
-
// 1. We ping the WORST node in the bucket (highest RTT) to check if it's still alive
|
|
529
|
-
// 2. If old node responds -> keep it, discard candidate
|
|
530
|
-
// 3. If old node times out -> replace it with candidate
|
|
531
|
-
struct PingVerification {
|
|
532
|
-
DhtNode candidate_node; // The new node waiting to be added
|
|
533
|
-
DhtNode old_node; // The existing node we're pinging to verify it's alive
|
|
534
|
-
int bucket_index; // Which bucket this affects
|
|
535
|
-
std::chrono::steady_clock::time_point ping_sent_at;
|
|
536
|
-
|
|
537
|
-
PingVerification(const DhtNode& candidate, const DhtNode& old, int bucket_idx)
|
|
538
|
-
: candidate_node(candidate), old_node(old), bucket_index(bucket_idx),
|
|
539
|
-
ping_sent_at(std::chrono::steady_clock::now()) {}
|
|
540
|
-
};
|
|
541
|
-
std::unordered_map<std::string, PingVerification> pending_pings_; // transaction_id -> PingVerification
|
|
542
|
-
std::unordered_set<NodeId> nodes_being_replaced_; // Track old nodes that have pending ping verifications
|
|
543
|
-
mutable std::mutex pending_pings_mutex_; // Lock order: 1 (protects pending_pings_, nodes_being_replaced_)
|
|
544
|
-
|
|
545
|
-
// Network thread
|
|
546
|
-
std::thread network_thread_;
|
|
547
|
-
std::thread maintenance_thread_;
|
|
548
|
-
|
|
549
|
-
// Conditional variables for immediate shutdown
|
|
550
|
-
std::condition_variable shutdown_cv_;
|
|
551
|
-
std::mutex shutdown_mutex_; // Lock order: 7 (can be locked independently)
|
|
552
|
-
|
|
553
|
-
#ifdef RATS_SEARCH_FEATURES
|
|
554
|
-
// Spider mode state
|
|
555
|
-
std::atomic<bool> spider_mode_{false};
|
|
556
|
-
std::atomic<bool> spider_ignore_{false}; // When true, ignore incoming requests
|
|
557
|
-
SpiderAnnounceCallback spider_announce_callback_;
|
|
558
|
-
std::mutex spider_callbacks_mutex_; // Protects spider callbacks
|
|
559
|
-
|
|
560
|
-
// Spider node tracking - separate from routing table to keep it stable
|
|
561
|
-
std::vector<DhtNode> spider_nodes_; // Pool of nodes for spider walking
|
|
562
|
-
std::unordered_set<NodeId> spider_visited_; // Nodes we've already queried in current session
|
|
563
|
-
mutable std::mutex spider_nodes_mutex_; // Lock order: 4 - Protects spider_nodes_, spider_visited_, spider_transactions_, spider_contacted_ips_
|
|
564
|
-
static constexpr size_t MAX_SPIDER_NODES = 2000; // Max nodes to keep in spider pool
|
|
565
|
-
static constexpr size_t MAX_SPIDER_VISITED = 10000; // Max visited nodes to track
|
|
566
|
-
static constexpr size_t MAX_SPIDER_CONTACTED_IPS = 10000; // Max contacted IPs to track
|
|
567
|
-
|
|
568
|
-
// Track transactions sent in spider mode to ensure responses go to spider pool
|
|
569
|
-
// even if spider_mode_ is disabled between request and response
|
|
570
|
-
std::unordered_map<std::string, std::chrono::steady_clock::time_point> spider_transactions_;
|
|
571
|
-
|
|
572
|
-
// Track IPs we've sent spider requests to
|
|
573
|
-
// Used to decide whether to respond with neighbor_id (spider contact) or real node_id (organic DHT)
|
|
574
|
-
std::unordered_set<std::string> spider_contacted_ips_;
|
|
575
|
-
|
|
576
|
-
// Rate-limit re-bootstrapping in spider_walk to avoid DDOSing bootstrap nodes
|
|
577
|
-
std::chrono::steady_clock::time_point last_spider_bootstrap_{}; // epoch = never bootstrapped
|
|
578
|
-
|
|
579
|
-
// Spider helper methods
|
|
580
|
-
void add_spider_node(const DhtNode& node);
|
|
581
|
-
void add_spider_nodes(const std::vector<DhtNode>& nodes);
|
|
582
|
-
bool is_spider_node_visited(const NodeId& id) const;
|
|
583
|
-
void mark_spider_node_visited(const NodeId& id);
|
|
584
|
-
void cleanup_spider_state();
|
|
585
|
-
void cleanup_stale_spider_transactions();
|
|
586
|
-
void mark_spider_transaction(const std::string& transaction_id);
|
|
587
|
-
bool is_spider_transaction(const std::string& transaction_id); // Also removes if found
|
|
588
|
-
void mark_spider_contacted_ip(const std::string& ip);
|
|
589
|
-
bool is_spider_contacted_ip(const std::string& ip) const;
|
|
590
|
-
#endif // RATS_SEARCH_FEATURES
|
|
591
|
-
|
|
592
|
-
// Helper functions
|
|
593
|
-
void network_loop();
|
|
594
|
-
void maintenance_loop();
|
|
595
|
-
void handle_message(const std::vector<uint8_t>& data, const Peer& sender);
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
// KRPC protocol handlers
|
|
600
|
-
void handle_krpc_message(const KrpcMessage& message, const Peer& sender);
|
|
601
|
-
void handle_krpc_ping(const KrpcMessage& message, const Peer& sender);
|
|
602
|
-
void handle_krpc_find_node(const KrpcMessage& message, const Peer& sender);
|
|
603
|
-
void handle_krpc_get_peers(const KrpcMessage& message, const Peer& sender);
|
|
604
|
-
void handle_krpc_announce_peer(const KrpcMessage& message, const Peer& sender);
|
|
605
|
-
void handle_krpc_response(const KrpcMessage& message, const Peer& sender);
|
|
606
|
-
void handle_krpc_error(const KrpcMessage& message, const Peer& sender);
|
|
607
|
-
|
|
608
|
-
// KRPC protocol sending
|
|
609
|
-
bool send_krpc_message(const KrpcMessage& message, const Peer& peer);
|
|
610
|
-
void send_krpc_ping(const Peer& peer);
|
|
611
|
-
void send_krpc_find_node(const Peer& peer, const NodeId& target);
|
|
612
|
-
void send_krpc_get_peers(const Peer& peer, const InfoHash& info_hash);
|
|
613
|
-
void send_krpc_announce_peer(const Peer& peer, const InfoHash& info_hash, uint16_t port, const std::string& token, bool implied_port = false);
|
|
614
|
-
|
|
615
|
-
void add_node(const DhtNode& node, bool confirmed = true, bool no_verify = false);
|
|
616
|
-
std::vector<DhtNode> find_closest_nodes(const NodeId& target, size_t count = K_BUCKET_SIZE);
|
|
617
|
-
std::vector<DhtNode> find_closest_nodes_unlocked(const NodeId& target, size_t count = K_BUCKET_SIZE);
|
|
618
|
-
int get_bucket_index(const NodeId& id);
|
|
619
|
-
|
|
620
|
-
NodeId generate_node_id();
|
|
621
|
-
// BEP 42 internals
|
|
622
|
-
static bool is_public_address(const std::string& ip);
|
|
623
|
-
void rebuild_routing_table_unlocked(); // re-bucket all nodes after node_id_ changed (routing_table_mutex_ held)
|
|
624
|
-
void maybe_update_external_ip(const std::string& reported_ip, const Peer& responder);
|
|
625
|
-
NodeId xor_distance(const NodeId& a, const NodeId& b);
|
|
626
|
-
bool is_closer(const NodeId& a, const NodeId& b, const NodeId& target);
|
|
627
|
-
|
|
628
|
-
/**
|
|
629
|
-
* Generate a "neighbor" node ID that appears close to the target
|
|
630
|
-
* Spider mode optimization: first 10 bytes from target, last 10 bytes from our ID
|
|
631
|
-
* This makes other nodes think we're close to any target they query
|
|
632
|
-
* @param target The target node ID to appear close to
|
|
633
|
-
* @return A node ID that XOR-distance wise appears close to target
|
|
634
|
-
*/
|
|
635
|
-
NodeId neighbor_id(const NodeId& target) const;
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
// BEP 5 write tokens: bound to the querier address + info_hash and authenticated with a rotating
|
|
639
|
-
// secret. generate_token is called when answering get_peers; verify_token gates announce_peer.
|
|
640
|
-
std::string generate_token(const Peer& peer, const InfoHash& info_hash);
|
|
641
|
-
bool verify_token(const Peer& peer, const InfoHash& info_hash, const std::string& token);
|
|
642
|
-
// Computes SHA1(secret || peer.ip || info_hash) as a hex digest. Port is intentionally excluded
|
|
643
|
-
// (a NAT may present a different source port on the subsequent announce).
|
|
644
|
-
std::string compute_token_with_secret(const Peer& peer, const InfoHash& info_hash,
|
|
645
|
-
const std::array<uint8_t, 16>& secret) const;
|
|
646
|
-
// Rotates the token secret if older than TOKEN_SECRET_ROTATION_MINUTES. Caller holds token_secret_mutex_.
|
|
647
|
-
void maybe_rotate_token_secret_unlocked();
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
void cleanup_stale_nodes();
|
|
652
|
-
void refresh_buckets();
|
|
653
|
-
void print_statistics();
|
|
654
|
-
|
|
655
|
-
// Pending search management
|
|
656
|
-
void cleanup_stale_searches();
|
|
657
|
-
void cleanup_timed_out_search_requests();
|
|
658
|
-
void cleanup_search_node_states();
|
|
659
|
-
void handle_get_peers_response_for_search(const std::string& transaction_id, const Peer& responder, const std::vector<Peer>& peers);
|
|
660
|
-
void handle_get_peers_response_with_nodes(const std::string& transaction_id, const Peer& responder, const std::vector<KrpcNode>& nodes);
|
|
661
|
-
void handle_get_peers_empty_response(const std::string& transaction_id, const Peer& responder);
|
|
662
|
-
void save_write_token(PendingSearch& search, const NodeId& node_id, const std::string& token);
|
|
663
|
-
bool add_search_requests(PendingSearch& search, DeferredCallbacks& deferred);
|
|
664
|
-
void add_node_to_search(PendingSearch& search, const DhtNode& node);
|
|
665
|
-
void send_announce_to_closest_nodes(PendingSearch& search);
|
|
666
|
-
|
|
667
|
-
// Peer announcement storage management
|
|
668
|
-
void store_announced_peer(const InfoHash& info_hash, const Peer& peer);
|
|
669
|
-
std::vector<Peer> get_announced_peers(const InfoHash& info_hash);
|
|
670
|
-
void cleanup_stale_announced_peers();
|
|
671
|
-
|
|
672
|
-
// Ping-before-replace eviction management
|
|
673
|
-
void initiate_ping_verification(const DhtNode& candidate_node, const DhtNode& old_node, int bucket_index);
|
|
674
|
-
void handle_ping_verification_response(const std::string& transaction_id, const NodeId& responder_id, const Peer& responder);
|
|
675
|
-
void cleanup_stale_ping_verifications();
|
|
676
|
-
bool perform_replacement(const DhtNode& candidate_node, const DhtNode& node_to_replace, int bucket_index);
|
|
677
|
-
|
|
678
|
-
// Conversion utilities
|
|
679
|
-
static KrpcNode dht_node_to_krpc_node(const DhtNode& node);
|
|
680
|
-
static DhtNode krpc_node_to_dht_node(const KrpcNode& node);
|
|
681
|
-
static std::vector<KrpcNode> dht_nodes_to_krpc_nodes(const std::vector<DhtNode>& nodes);
|
|
682
|
-
static std::vector<DhtNode> krpc_nodes_to_dht_nodes(const std::vector<KrpcNode>& nodes);
|
|
683
|
-
};
|
|
684
|
-
|
|
685
|
-
/**
|
|
686
|
-
* Utility functions
|
|
687
|
-
*/
|
|
688
|
-
|
|
689
|
-
/**
|
|
690
|
-
* Convert string to NodeId
|
|
691
|
-
* @param str The string to convert (must be 20 bytes)
|
|
692
|
-
* @return NodeId
|
|
693
|
-
*/
|
|
694
|
-
NodeId string_to_node_id(const std::string& str);
|
|
695
|
-
|
|
696
|
-
/**
|
|
697
|
-
* Convert NodeId to string
|
|
698
|
-
* @param id The NodeId to convert
|
|
699
|
-
* @return String representation
|
|
700
|
-
*/
|
|
701
|
-
std::string node_id_to_string(const NodeId& id);
|
|
702
|
-
|
|
703
|
-
/**
|
|
704
|
-
* Convert hex string to NodeId
|
|
705
|
-
* @param hex The hex string to convert (must be 40 characters)
|
|
706
|
-
* @return NodeId
|
|
707
|
-
*/
|
|
708
|
-
NodeId hex_to_node_id(const std::string& hex);
|
|
709
|
-
|
|
710
|
-
/**
|
|
711
|
-
* Convert NodeId to hex string
|
|
712
|
-
* @param id The NodeId to convert
|
|
713
|
-
* @return Hex string representation
|
|
714
|
-
*/
|
|
715
|
-
std::string node_id_to_hex(const NodeId& id);
|
|
716
|
-
|
|
717
|
-
} // namespace librats
|