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
|
@@ -1,742 +0,0 @@
|
|
|
1
|
-
#include "bt_peer_connection.h"
|
|
2
|
-
#include "bencode.h"
|
|
3
|
-
#include "logger.h"
|
|
4
|
-
#include <algorithm>
|
|
5
|
-
#include <cstring>
|
|
6
|
-
|
|
7
|
-
namespace librats {
|
|
8
|
-
|
|
9
|
-
//=============================================================================
|
|
10
|
-
// Helpers
|
|
11
|
-
//=============================================================================
|
|
12
|
-
|
|
13
|
-
const char* peer_state_to_string(PeerConnectionState state) {
|
|
14
|
-
switch (state) {
|
|
15
|
-
case PeerConnectionState::Disconnected: return "Disconnected";
|
|
16
|
-
case PeerConnectionState::Connecting: return "Connecting";
|
|
17
|
-
case PeerConnectionState::Handshaking: return "Handshaking";
|
|
18
|
-
case PeerConnectionState::Connected: return "Connected";
|
|
19
|
-
case PeerConnectionState::Closing: return "Closing";
|
|
20
|
-
default: return "Unknown";
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
double PeerStats::download_rate() const {
|
|
25
|
-
// Simple calculation - would need sliding window for accuracy
|
|
26
|
-
auto now = std::chrono::steady_clock::now();
|
|
27
|
-
auto duration = std::chrono::duration_cast<std::chrono::seconds>(now - connected_at).count();
|
|
28
|
-
if (duration <= 0) return 0.0;
|
|
29
|
-
return static_cast<double>(bytes_downloaded) / duration;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
double PeerStats::upload_rate() const {
|
|
33
|
-
auto now = std::chrono::steady_clock::now();
|
|
34
|
-
auto duration = std::chrono::duration_cast<std::chrono::seconds>(now - connected_at).count();
|
|
35
|
-
if (duration <= 0) return 0.0;
|
|
36
|
-
return static_cast<double>(bytes_uploaded) / duration;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
//=============================================================================
|
|
40
|
-
// Constructor/Destructor
|
|
41
|
-
//=============================================================================
|
|
42
|
-
|
|
43
|
-
BtPeerConnection::BtPeerConnection(const BtInfoHash& info_hash,
|
|
44
|
-
const PeerID& our_peer_id,
|
|
45
|
-
uint32_t num_pieces)
|
|
46
|
-
: socket_fd_(-1)
|
|
47
|
-
, port_(0)
|
|
48
|
-
, state_(PeerConnectionState::Disconnected)
|
|
49
|
-
, our_info_hash_(info_hash)
|
|
50
|
-
, our_peer_id_(our_peer_id)
|
|
51
|
-
, num_pieces_(num_pieces)
|
|
52
|
-
, info_hash_known_(true) // Outgoing: info_hash is known
|
|
53
|
-
, peer_info_hash_{}
|
|
54
|
-
, peer_id_{}
|
|
55
|
-
, handshake_received_(false)
|
|
56
|
-
, handshake_sent_(false)
|
|
57
|
-
, extension_handshake_received_(false)
|
|
58
|
-
, peer_metadata_size_(0)
|
|
59
|
-
, peer_ut_metadata_id_(0)
|
|
60
|
-
, am_choking_(true)
|
|
61
|
-
, am_interested_(false)
|
|
62
|
-
, peer_choking_(true)
|
|
63
|
-
, peer_interested_(false)
|
|
64
|
-
, peer_pieces_(num_pieces)
|
|
65
|
-
, peer_has_all_(false)
|
|
66
|
-
, bitfield_received_(false)
|
|
67
|
-
, recv_buffer_(8192) // Initial receive buffer capacity
|
|
68
|
-
, max_pending_requests_(BT_DEFAULT_REQUEST_QUEUE_SIZE) {
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
BtPeerConnection::BtPeerConnection(const PeerID& our_peer_id)
|
|
72
|
-
: socket_fd_(-1)
|
|
73
|
-
, port_(0)
|
|
74
|
-
, state_(PeerConnectionState::Disconnected)
|
|
75
|
-
, our_info_hash_{}
|
|
76
|
-
, our_peer_id_(our_peer_id)
|
|
77
|
-
, num_pieces_(0)
|
|
78
|
-
, info_hash_known_(false) // Incoming: info_hash unknown until handshake
|
|
79
|
-
, peer_info_hash_{}
|
|
80
|
-
, peer_id_{}
|
|
81
|
-
, handshake_received_(false)
|
|
82
|
-
, handshake_sent_(false)
|
|
83
|
-
, extension_handshake_received_(false)
|
|
84
|
-
, peer_metadata_size_(0)
|
|
85
|
-
, peer_ut_metadata_id_(0)
|
|
86
|
-
, am_choking_(true)
|
|
87
|
-
, am_interested_(false)
|
|
88
|
-
, peer_choking_(true)
|
|
89
|
-
, peer_interested_(false)
|
|
90
|
-
, peer_pieces_(0) // Will be resized after set_torrent_info
|
|
91
|
-
, peer_has_all_(false)
|
|
92
|
-
, bitfield_received_(false)
|
|
93
|
-
, recv_buffer_(8192)
|
|
94
|
-
, max_pending_requests_(BT_DEFAULT_REQUEST_QUEUE_SIZE) {
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
BtPeerConnection::~BtPeerConnection() {
|
|
98
|
-
close();
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
BtPeerConnection::BtPeerConnection(BtPeerConnection&& other) noexcept
|
|
102
|
-
: socket_fd_(other.socket_fd_)
|
|
103
|
-
, ip_(std::move(other.ip_))
|
|
104
|
-
, port_(other.port_)
|
|
105
|
-
, state_(other.state_.load())
|
|
106
|
-
, our_info_hash_(std::move(other.our_info_hash_))
|
|
107
|
-
, our_peer_id_(std::move(other.our_peer_id_))
|
|
108
|
-
, num_pieces_(other.num_pieces_)
|
|
109
|
-
, info_hash_known_(other.info_hash_known_)
|
|
110
|
-
, peer_info_hash_(std::move(other.peer_info_hash_))
|
|
111
|
-
, peer_id_(std::move(other.peer_id_))
|
|
112
|
-
, peer_extensions_(other.peer_extensions_)
|
|
113
|
-
, handshake_received_(other.handshake_received_)
|
|
114
|
-
, handshake_sent_(other.handshake_sent_)
|
|
115
|
-
, extension_handshake_received_(other.extension_handshake_received_)
|
|
116
|
-
, peer_metadata_size_(other.peer_metadata_size_)
|
|
117
|
-
, peer_ut_metadata_id_(other.peer_ut_metadata_id_)
|
|
118
|
-
, am_choking_(other.am_choking_)
|
|
119
|
-
, am_interested_(other.am_interested_)
|
|
120
|
-
, peer_choking_(other.peer_choking_)
|
|
121
|
-
, peer_interested_(other.peer_interested_)
|
|
122
|
-
, peer_pieces_(std::move(other.peer_pieces_))
|
|
123
|
-
, peer_has_all_(other.peer_has_all_)
|
|
124
|
-
, bitfield_received_(other.bitfield_received_)
|
|
125
|
-
, recv_buffer_(std::move(other.recv_buffer_))
|
|
126
|
-
, send_buffer_(std::move(other.send_buffer_))
|
|
127
|
-
, pending_requests_(std::move(other.pending_requests_))
|
|
128
|
-
, max_pending_requests_(other.max_pending_requests_)
|
|
129
|
-
, stats_(other.stats_)
|
|
130
|
-
, on_message_(std::move(other.on_message_))
|
|
131
|
-
, on_state_change_(std::move(other.on_state_change_))
|
|
132
|
-
, on_handshake_(std::move(other.on_handshake_))
|
|
133
|
-
, on_error_(std::move(other.on_error_))
|
|
134
|
-
, on_info_hash_(std::move(other.on_info_hash_)) {
|
|
135
|
-
other.socket_fd_ = -1;
|
|
136
|
-
other.state_ = PeerConnectionState::Disconnected;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
BtPeerConnection& BtPeerConnection::operator=(BtPeerConnection&& other) noexcept {
|
|
140
|
-
if (this != &other) {
|
|
141
|
-
close();
|
|
142
|
-
|
|
143
|
-
socket_fd_ = other.socket_fd_;
|
|
144
|
-
ip_ = std::move(other.ip_);
|
|
145
|
-
port_ = other.port_;
|
|
146
|
-
state_ = other.state_.load();
|
|
147
|
-
our_info_hash_ = std::move(other.our_info_hash_);
|
|
148
|
-
our_peer_id_ = std::move(other.our_peer_id_);
|
|
149
|
-
num_pieces_ = other.num_pieces_;
|
|
150
|
-
info_hash_known_ = other.info_hash_known_;
|
|
151
|
-
peer_info_hash_ = std::move(other.peer_info_hash_);
|
|
152
|
-
peer_id_ = std::move(other.peer_id_);
|
|
153
|
-
peer_extensions_ = other.peer_extensions_;
|
|
154
|
-
handshake_received_ = other.handshake_received_;
|
|
155
|
-
handshake_sent_ = other.handshake_sent_;
|
|
156
|
-
extension_handshake_received_ = other.extension_handshake_received_;
|
|
157
|
-
peer_metadata_size_ = other.peer_metadata_size_;
|
|
158
|
-
peer_ut_metadata_id_ = other.peer_ut_metadata_id_;
|
|
159
|
-
am_choking_ = other.am_choking_;
|
|
160
|
-
am_interested_ = other.am_interested_;
|
|
161
|
-
peer_choking_ = other.peer_choking_;
|
|
162
|
-
peer_interested_ = other.peer_interested_;
|
|
163
|
-
peer_pieces_ = std::move(other.peer_pieces_);
|
|
164
|
-
peer_has_all_ = other.peer_has_all_;
|
|
165
|
-
recv_buffer_ = std::move(other.recv_buffer_);
|
|
166
|
-
send_buffer_ = std::move(other.send_buffer_);
|
|
167
|
-
pending_requests_ = std::move(other.pending_requests_);
|
|
168
|
-
max_pending_requests_ = other.max_pending_requests_;
|
|
169
|
-
stats_ = other.stats_;
|
|
170
|
-
on_message_ = std::move(other.on_message_);
|
|
171
|
-
on_state_change_ = std::move(other.on_state_change_);
|
|
172
|
-
on_handshake_ = std::move(other.on_handshake_);
|
|
173
|
-
on_error_ = std::move(other.on_error_);
|
|
174
|
-
on_info_hash_ = std::move(other.on_info_hash_);
|
|
175
|
-
|
|
176
|
-
other.socket_fd_ = -1;
|
|
177
|
-
other.state_ = PeerConnectionState::Disconnected;
|
|
178
|
-
}
|
|
179
|
-
return *this;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
//=============================================================================
|
|
183
|
-
// Connection Management
|
|
184
|
-
//=============================================================================
|
|
185
|
-
|
|
186
|
-
void BtPeerConnection::set_socket(int socket_fd) {
|
|
187
|
-
socket_fd_ = socket_fd;
|
|
188
|
-
// Only transition to Handshaking if currently Disconnected.
|
|
189
|
-
// This prevents accidentally resetting state if set_socket is called
|
|
190
|
-
// after handshake is already complete (e.g., from a callback).
|
|
191
|
-
if (socket_fd >= 0 && state_ == PeerConnectionState::Disconnected) {
|
|
192
|
-
set_state(PeerConnectionState::Handshaking);
|
|
193
|
-
stats_.connected_at = std::chrono::steady_clock::now();
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
void BtPeerConnection::set_address(const std::string& ip, uint16_t port) {
|
|
198
|
-
ip_ = ip;
|
|
199
|
-
port_ = port;
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
void BtPeerConnection::start_handshake() {
|
|
203
|
-
if (handshake_sent_) return;
|
|
204
|
-
|
|
205
|
-
LOG_DEBUG("BtPeerConn", "Sending handshake to " + ip_);
|
|
206
|
-
auto hs = BtHandshake::encode_with_extensions(our_info_hash_, our_peer_id_);
|
|
207
|
-
queue_send(hs);
|
|
208
|
-
handshake_sent_ = true;
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
void BtPeerConnection::close() {
|
|
212
|
-
if (state_ == PeerConnectionState::Disconnected) return;
|
|
213
|
-
|
|
214
|
-
set_state(PeerConnectionState::Closing);
|
|
215
|
-
|
|
216
|
-
// Clear buffers
|
|
217
|
-
recv_buffer_.clear();
|
|
218
|
-
send_buffer_.clear();
|
|
219
|
-
pending_requests_.clear();
|
|
220
|
-
|
|
221
|
-
// Socket closing should be handled by the owner
|
|
222
|
-
socket_fd_ = -1;
|
|
223
|
-
|
|
224
|
-
set_state(PeerConnectionState::Disconnected);
|
|
225
|
-
|
|
226
|
-
// Clear callbacks to prevent dangling pointer issues
|
|
227
|
-
// Important: Must be done AFTER state callbacks are invoked
|
|
228
|
-
on_message_ = nullptr;
|
|
229
|
-
on_state_change_ = nullptr;
|
|
230
|
-
on_handshake_ = nullptr;
|
|
231
|
-
on_error_ = nullptr;
|
|
232
|
-
on_info_hash_ = nullptr;
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
void BtPeerConnection::set_torrent_info(const BtInfoHash& info_hash, uint32_t num_pieces) {
|
|
236
|
-
our_info_hash_ = info_hash;
|
|
237
|
-
num_pieces_ = num_pieces;
|
|
238
|
-
info_hash_known_ = true;
|
|
239
|
-
|
|
240
|
-
// Resize peer_pieces bitfield if needed
|
|
241
|
-
if (peer_pieces_.size() != num_pieces) {
|
|
242
|
-
// If peer sent HaveAll before we had metadata, set all bits now
|
|
243
|
-
if (peer_has_all_) {
|
|
244
|
-
peer_pieces_ = Bitfield(num_pieces);
|
|
245
|
-
peer_pieces_.set_all();
|
|
246
|
-
LOG_DEBUG("BtPeerConn", "Peer " + ip_ + " had sent HaveAll, setting all " +
|
|
247
|
-
std::to_string(num_pieces) + " pieces");
|
|
248
|
-
} else {
|
|
249
|
-
// Peer may have sent a bitfield before we knew num_pieces.
|
|
250
|
-
// The bitfield was decoded with size bf_len*8 which may differ from actual num_pieces.
|
|
251
|
-
// Use resize() to adjust to correct size while preserving existing bit data.
|
|
252
|
-
// This is important: the extra padding bits at the end are meaningless anyway.
|
|
253
|
-
size_t old_size = peer_pieces_.size();
|
|
254
|
-
size_t old_count = peer_pieces_.count();
|
|
255
|
-
peer_pieces_.resize(num_pieces);
|
|
256
|
-
LOG_DEBUG("BtPeerConn", "Peer " + ip_ + " bitfield resized from " +
|
|
257
|
-
std::to_string(old_size) + " to " + std::to_string(num_pieces) +
|
|
258
|
-
" bits (had " + std::to_string(old_count) + " pieces, now " +
|
|
259
|
-
std::to_string(peer_pieces_.count()) + ")");
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
LOG_DEBUG("BtPeerConn", "Set torrent info for " + ip_ +
|
|
264
|
-
": info_hash=" + info_hash_to_hex(info_hash).substr(0, 8) +
|
|
265
|
-
"..., num_pieces=" + std::to_string(num_pieces) +
|
|
266
|
-
", peer_has_all=" + (peer_has_all_ ? "yes" : "no"));
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
void BtPeerConnection::set_state(PeerConnectionState new_state) {
|
|
270
|
-
PeerConnectionState old_state = state_.exchange(new_state);
|
|
271
|
-
if (old_state != new_state && on_state_change_) {
|
|
272
|
-
on_state_change_(this, new_state);
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
//=============================================================================
|
|
277
|
-
// Data Processing
|
|
278
|
-
//=============================================================================
|
|
279
|
-
|
|
280
|
-
void BtPeerConnection::process_incoming() {
|
|
281
|
-
if (recv_buffer_.empty()) return;
|
|
282
|
-
|
|
283
|
-
stats_.last_message_at = std::chrono::steady_clock::now();
|
|
284
|
-
|
|
285
|
-
LOG_DEBUG("BtPeerConn", "process_incoming: " + std::to_string(recv_buffer_.size()) +
|
|
286
|
-
" bytes from " + ip_);
|
|
287
|
-
|
|
288
|
-
// Process handshake first
|
|
289
|
-
if (!handshake_received_) {
|
|
290
|
-
process_handshake();
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
// Then process messages
|
|
294
|
-
if (handshake_received_) {
|
|
295
|
-
process_messages();
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
// Periodically normalize buffer to reclaim space
|
|
299
|
-
if (recv_buffer_.front_waste() > 4096) {
|
|
300
|
-
recv_buffer_.normalize();
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
void BtPeerConnection::process_handshake() {
|
|
305
|
-
if (recv_buffer_.size() < BT_HANDSHAKE_SIZE) {
|
|
306
|
-
LOG_DEBUG("BtPeerConn", "process_handshake: waiting for more data, have " +
|
|
307
|
-
std::to_string(recv_buffer_.size()) + "/" + std::to_string(BT_HANDSHAKE_SIZE) + " bytes");
|
|
308
|
-
return; // Wait for more data
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
auto hs = BtHandshake::decode(recv_buffer_.data(), recv_buffer_.size());
|
|
312
|
-
if (!hs) {
|
|
313
|
-
LOG_ERROR("BtPeerConn", "Invalid handshake from " + ip_);
|
|
314
|
-
if (on_error_) {
|
|
315
|
-
on_error_(this, "Invalid handshake");
|
|
316
|
-
}
|
|
317
|
-
close();
|
|
318
|
-
return;
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
// Store peer info
|
|
322
|
-
peer_info_hash_ = hs->info_hash;
|
|
323
|
-
peer_id_ = hs->peer_id;
|
|
324
|
-
peer_extensions_ = hs->extensions;
|
|
325
|
-
|
|
326
|
-
// For incoming connections, we need to notify about the info_hash first
|
|
327
|
-
// so NetworkManager can look up the torrent and call set_torrent_info()
|
|
328
|
-
if (!info_hash_known_) {
|
|
329
|
-
LOG_DEBUG("BtPeerConn", "Incoming connection: notifying info_hash " +
|
|
330
|
-
info_hash_to_hex(hs->info_hash).substr(0, 8) + "...");
|
|
331
|
-
|
|
332
|
-
if (on_info_hash_) {
|
|
333
|
-
on_info_hash_(this, hs->info_hash);
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
// After callback, info_hash should be set via set_torrent_info()
|
|
337
|
-
// If not, the connection should be closed by the callback handler
|
|
338
|
-
if (!info_hash_known_) {
|
|
339
|
-
LOG_ERROR("BtPeerConn", "Unknown torrent from " + ip_ +
|
|
340
|
-
", info_hash=" + info_hash_to_hex(hs->info_hash).substr(0, 8) + "...");
|
|
341
|
-
if (on_error_) {
|
|
342
|
-
on_error_(this, "Unknown torrent");
|
|
343
|
-
}
|
|
344
|
-
close();
|
|
345
|
-
return;
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
// Verify info hash matches (for outgoing connections, or after set_torrent_info)
|
|
350
|
-
if (hs->info_hash != our_info_hash_) {
|
|
351
|
-
LOG_ERROR("BtPeerConn", "Info hash mismatch from " + ip_);
|
|
352
|
-
if (on_error_) {
|
|
353
|
-
on_error_(this, "Info hash mismatch");
|
|
354
|
-
}
|
|
355
|
-
close();
|
|
356
|
-
return;
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
handshake_received_ = true;
|
|
360
|
-
|
|
361
|
-
// Identify client from peer_id
|
|
362
|
-
peer_client_name_ = identify_client(peer_id_);
|
|
363
|
-
|
|
364
|
-
// Format peer_id for logging (first 8 chars, printable only)
|
|
365
|
-
std::string peer_id_str;
|
|
366
|
-
for (size_t i = 0; i < 8 && i < peer_id_.size(); ++i) {
|
|
367
|
-
char c = static_cast<char>(peer_id_[i]);
|
|
368
|
-
peer_id_str += (c >= 32 && c < 127) ? c : '.';
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
LOG_INFO("BtPeerConn", "Handshake received from " + ip_ + ", peer_id=" + peer_id_str +
|
|
372
|
-
", client=" + peer_client_name_ +
|
|
373
|
-
", ext_protocol=" + (hs->extensions.extension_protocol ? "yes" : "no") +
|
|
374
|
-
", fast=" + (hs->extensions.fast ? "yes" : "no"));
|
|
375
|
-
|
|
376
|
-
// Consume handshake from buffer - O(1) operation!
|
|
377
|
-
recv_buffer_.consume(BT_HANDSHAKE_SIZE);
|
|
378
|
-
|
|
379
|
-
// Notify
|
|
380
|
-
if (on_handshake_) {
|
|
381
|
-
on_handshake_(this, *hs);
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
// If we haven't sent our handshake yet, do it now
|
|
385
|
-
if (!handshake_sent_) {
|
|
386
|
-
start_handshake();
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
// Transition to connected
|
|
390
|
-
set_state(PeerConnectionState::Connected);
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
void BtPeerConnection::process_messages() {
|
|
394
|
-
while (!recv_buffer_.empty()) {
|
|
395
|
-
// Check for complete message
|
|
396
|
-
size_t msg_len = BtMessageDecoder::message_length(
|
|
397
|
-
recv_buffer_.data(), recv_buffer_.size());
|
|
398
|
-
|
|
399
|
-
if (msg_len == 0) {
|
|
400
|
-
break; // Incomplete message
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
// Check for keep-alive
|
|
404
|
-
if (BtMessageDecoder::is_keepalive(recv_buffer_.data(), recv_buffer_.size())) {
|
|
405
|
-
LOG_DEBUG("BtPeerConn", "Received keep-alive from " + ip_);
|
|
406
|
-
recv_buffer_.consume(4); // O(1) operation!
|
|
407
|
-
continue;
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
// Decode message
|
|
411
|
-
auto msg = BtMessageDecoder::decode(
|
|
412
|
-
recv_buffer_.data(), recv_buffer_.size(), num_pieces_);
|
|
413
|
-
|
|
414
|
-
if (msg) {
|
|
415
|
-
handle_message(*msg);
|
|
416
|
-
++stats_.messages_received;
|
|
417
|
-
} else {
|
|
418
|
-
LOG_WARN("BtPeerConn", "Failed to decode message from " + ip_ +
|
|
419
|
-
", msg_len=" + std::to_string(msg_len));
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
// Consume processed message - O(1) operation!
|
|
423
|
-
recv_buffer_.consume(msg_len);
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
void BtPeerConnection::handle_message(const BtMessage& msg) {
|
|
428
|
-
// Log message details based on type
|
|
429
|
-
std::string log_detail;
|
|
430
|
-
switch (msg.type) {
|
|
431
|
-
case BtMessageType::Have:
|
|
432
|
-
log_detail = " piece=" + std::to_string(msg.have_piece);
|
|
433
|
-
break;
|
|
434
|
-
case BtMessageType::Bitfield:
|
|
435
|
-
if (msg.bitfield) {
|
|
436
|
-
log_detail = " bits=" + std::to_string(msg.bitfield->count());
|
|
437
|
-
}
|
|
438
|
-
break;
|
|
439
|
-
case BtMessageType::Request:
|
|
440
|
-
if (msg.request) {
|
|
441
|
-
log_detail = " piece=" + std::to_string(msg.request->piece_index) +
|
|
442
|
-
" begin=" + std::to_string(msg.request->begin) +
|
|
443
|
-
" len=" + std::to_string(msg.request->length);
|
|
444
|
-
}
|
|
445
|
-
break;
|
|
446
|
-
case BtMessageType::Piece:
|
|
447
|
-
if (msg.piece) {
|
|
448
|
-
log_detail = " piece=" + std::to_string(msg.piece->piece_index) +
|
|
449
|
-
" begin=" + std::to_string(msg.piece->begin) +
|
|
450
|
-
" len=" + std::to_string(msg.piece->data.size());
|
|
451
|
-
}
|
|
452
|
-
break;
|
|
453
|
-
case BtMessageType::Extended:
|
|
454
|
-
log_detail = " ext_id=" + std::to_string(msg.extension_id) +
|
|
455
|
-
" payload=" + std::to_string(msg.extension_payload.size()) + " bytes";
|
|
456
|
-
break;
|
|
457
|
-
default:
|
|
458
|
-
break;
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
LOG_DEBUG("BtPeerConn", "handle_message: " + std::string(message_type_to_string(msg.type)) +
|
|
462
|
-
" from " + ip_ + log_detail);
|
|
463
|
-
|
|
464
|
-
switch (msg.type) {
|
|
465
|
-
case BtMessageType::Choke:
|
|
466
|
-
peer_choking_ = true;
|
|
467
|
-
break;
|
|
468
|
-
|
|
469
|
-
case BtMessageType::Unchoke:
|
|
470
|
-
peer_choking_ = false;
|
|
471
|
-
break;
|
|
472
|
-
|
|
473
|
-
case BtMessageType::Interested:
|
|
474
|
-
peer_interested_ = true;
|
|
475
|
-
break;
|
|
476
|
-
|
|
477
|
-
case BtMessageType::NotInterested:
|
|
478
|
-
peer_interested_ = false;
|
|
479
|
-
break;
|
|
480
|
-
|
|
481
|
-
case BtMessageType::Have:
|
|
482
|
-
// Skip if we don't have metadata yet (magnet link scenario)
|
|
483
|
-
if (num_pieces_ == 0) {
|
|
484
|
-
LOG_DEBUG("BtPeerConn", "Ignoring HAVE (no metadata yet) from " + ip_);
|
|
485
|
-
break;
|
|
486
|
-
}
|
|
487
|
-
// Validate piece index
|
|
488
|
-
if (msg.have_piece >= num_pieces_) {
|
|
489
|
-
LOG_WARN("BtPeerConn", "Invalid HAVE index " + std::to_string(msg.have_piece) +
|
|
490
|
-
" >= " + std::to_string(num_pieces_) + " from " + ip_);
|
|
491
|
-
break;
|
|
492
|
-
}
|
|
493
|
-
// Ignore redundant HAVE
|
|
494
|
-
if (peer_pieces_.get_bit(msg.have_piece)) {
|
|
495
|
-
LOG_DEBUG("BtPeerConn", "Redundant HAVE for piece " + std::to_string(msg.have_piece));
|
|
496
|
-
break;
|
|
497
|
-
}
|
|
498
|
-
peer_pieces_.set_bit(msg.have_piece);
|
|
499
|
-
break;
|
|
500
|
-
|
|
501
|
-
case BtMessageType::Bitfield:
|
|
502
|
-
if (msg.bitfield) {
|
|
503
|
-
// Validate bitfield size
|
|
504
|
-
if (num_pieces_ > 0 && msg.bitfield->size() != num_pieces_) {
|
|
505
|
-
LOG_WARN("BtPeerConn", "Invalid bitfield size " + std::to_string(msg.bitfield->size()) +
|
|
506
|
-
" expected " + std::to_string(num_pieces_) + " from " + ip_);
|
|
507
|
-
// Resize to match expected size
|
|
508
|
-
peer_pieces_ = *msg.bitfield;
|
|
509
|
-
peer_pieces_.resize(num_pieces_);
|
|
510
|
-
} else {
|
|
511
|
-
peer_pieces_ = *msg.bitfield;
|
|
512
|
-
}
|
|
513
|
-
peer_has_all_ = false; // Explicit bitfield takes precedence over HaveAll
|
|
514
|
-
bitfield_received_ = true;
|
|
515
|
-
}
|
|
516
|
-
break;
|
|
517
|
-
|
|
518
|
-
case BtMessageType::Piece:
|
|
519
|
-
if (msg.piece) {
|
|
520
|
-
RequestMessage req(msg.piece->piece_index, msg.piece->begin,
|
|
521
|
-
static_cast<uint32_t>(msg.piece->data.size()));
|
|
522
|
-
|
|
523
|
-
// Check if this block was requested
|
|
524
|
-
bool was_requested = has_pending_request(req);
|
|
525
|
-
if (!was_requested) {
|
|
526
|
-
LOG_DEBUG("BtPeerConn", "Received unrequested piece " +
|
|
527
|
-
std::to_string(msg.piece->piece_index) + " from " + ip_);
|
|
528
|
-
// Still process it, but mark as potentially wasteful
|
|
529
|
-
}
|
|
530
|
-
|
|
531
|
-
stats_.bytes_downloaded += msg.piece->data.size();
|
|
532
|
-
stats_.last_piece_at = std::chrono::steady_clock::now();
|
|
533
|
-
++stats_.pieces_received;
|
|
534
|
-
|
|
535
|
-
// Remove from pending requests
|
|
536
|
-
remove_pending_request(req);
|
|
537
|
-
}
|
|
538
|
-
break;
|
|
539
|
-
|
|
540
|
-
case BtMessageType::HaveAll:
|
|
541
|
-
peer_has_all_ = true;
|
|
542
|
-
bitfield_received_ = true;
|
|
543
|
-
// If we have metadata (num_pieces_ > 0), set all bits now
|
|
544
|
-
// Otherwise, we'll resize and set in set_torrent_info()
|
|
545
|
-
if (peer_pieces_.size() > 0) {
|
|
546
|
-
peer_pieces_.set_all();
|
|
547
|
-
}
|
|
548
|
-
break;
|
|
549
|
-
|
|
550
|
-
case BtMessageType::HaveNone:
|
|
551
|
-
peer_has_all_ = false;
|
|
552
|
-
bitfield_received_ = true;
|
|
553
|
-
peer_pieces_.clear_all();
|
|
554
|
-
break;
|
|
555
|
-
|
|
556
|
-
case BtMessageType::Extended:
|
|
557
|
-
// Parse extension handshake (ext_id=0) and store data for late callback registration
|
|
558
|
-
if (msg.extension_id == 0 && !msg.extension_payload.empty()) {
|
|
559
|
-
parse_extension_handshake(msg.extension_payload);
|
|
560
|
-
}
|
|
561
|
-
break;
|
|
562
|
-
|
|
563
|
-
default:
|
|
564
|
-
break;
|
|
565
|
-
}
|
|
566
|
-
|
|
567
|
-
// Notify callback
|
|
568
|
-
if (on_message_) {
|
|
569
|
-
on_message_(this, msg);
|
|
570
|
-
}
|
|
571
|
-
}
|
|
572
|
-
|
|
573
|
-
void BtPeerConnection::parse_extension_handshake(const std::vector<uint8_t>& payload) {
|
|
574
|
-
// Parse the bencoded extension handshake to extract metadata info
|
|
575
|
-
// This data is stored so Torrent can access it even if callback wasn't set yet
|
|
576
|
-
|
|
577
|
-
BencodeValue decoded;
|
|
578
|
-
try {
|
|
579
|
-
decoded = BencodeDecoder::decode(payload);
|
|
580
|
-
} catch (...) {
|
|
581
|
-
LOG_DEBUG("BtPeerConn", "Failed to decode extension handshake from " + ip_);
|
|
582
|
-
return;
|
|
583
|
-
}
|
|
584
|
-
|
|
585
|
-
if (!decoded.is_dict()) {
|
|
586
|
-
return;
|
|
587
|
-
}
|
|
588
|
-
|
|
589
|
-
const auto& dict = decoded.as_dict();
|
|
590
|
-
extension_handshake_received_ = true;
|
|
591
|
-
|
|
592
|
-
// Extract metadata_size if present
|
|
593
|
-
auto metadata_size_it = dict.find("metadata_size");
|
|
594
|
-
if (metadata_size_it != dict.end() && metadata_size_it->second.is_integer()) {
|
|
595
|
-
peer_metadata_size_ = static_cast<size_t>(metadata_size_it->second.as_integer());
|
|
596
|
-
LOG_DEBUG("BtPeerConn", "Peer " + ip_ + " has metadata_size=" +
|
|
597
|
-
std::to_string(peer_metadata_size_));
|
|
598
|
-
}
|
|
599
|
-
|
|
600
|
-
// Extract ut_metadata message ID from 'm' dictionary
|
|
601
|
-
auto m_it = dict.find("m");
|
|
602
|
-
if (m_it != dict.end() && m_it->second.is_dict()) {
|
|
603
|
-
const auto& m = m_it->second.as_dict();
|
|
604
|
-
auto ut_metadata_it = m.find("ut_metadata");
|
|
605
|
-
if (ut_metadata_it != m.end() && ut_metadata_it->second.is_integer()) {
|
|
606
|
-
peer_ut_metadata_id_ = static_cast<uint8_t>(ut_metadata_it->second.as_integer());
|
|
607
|
-
LOG_DEBUG("BtPeerConn", "Peer " + ip_ + " ut_metadata_id=" +
|
|
608
|
-
std::to_string(peer_ut_metadata_id_));
|
|
609
|
-
}
|
|
610
|
-
}
|
|
611
|
-
|
|
612
|
-
// Extract client version string from 'v' field
|
|
613
|
-
auto v_it = dict.find("v");
|
|
614
|
-
if (v_it != dict.end() && v_it->second.is_string()) {
|
|
615
|
-
peer_client_name_ = v_it->second.as_string();
|
|
616
|
-
LOG_INFO("BtPeerConn", "Peer " + ip_ + " client: " + peer_client_name_);
|
|
617
|
-
}
|
|
618
|
-
}
|
|
619
|
-
|
|
620
|
-
void BtPeerConnection::queue_send(const std::vector<uint8_t>& data) {
|
|
621
|
-
send_buffer_.append(data.data(), data.size());
|
|
622
|
-
LOG_DEBUG("BtPeerConn", "queue_send: " + std::to_string(data.size()) + " bytes to " + ip_ +
|
|
623
|
-
", buffer now " + std::to_string(send_buffer_.size()) + " bytes");
|
|
624
|
-
}
|
|
625
|
-
|
|
626
|
-
//=============================================================================
|
|
627
|
-
// Protocol State
|
|
628
|
-
//=============================================================================
|
|
629
|
-
|
|
630
|
-
bool BtPeerConnection::peer_has_piece(uint32_t piece) const {
|
|
631
|
-
return peer_pieces_.get_bit(piece);
|
|
632
|
-
}
|
|
633
|
-
|
|
634
|
-
//=============================================================================
|
|
635
|
-
// Sending Messages
|
|
636
|
-
//=============================================================================
|
|
637
|
-
|
|
638
|
-
void BtPeerConnection::send_choke() {
|
|
639
|
-
LOG_DEBUG("BtPeerConn", "send_choke to " + ip_);
|
|
640
|
-
am_choking_ = true;
|
|
641
|
-
queue_send(BtMessageEncoder::encode_choke());
|
|
642
|
-
++stats_.messages_sent;
|
|
643
|
-
}
|
|
644
|
-
|
|
645
|
-
void BtPeerConnection::send_unchoke() {
|
|
646
|
-
LOG_DEBUG("BtPeerConn", "send_unchoke to " + ip_);
|
|
647
|
-
am_choking_ = false;
|
|
648
|
-
queue_send(BtMessageEncoder::encode_unchoke());
|
|
649
|
-
++stats_.messages_sent;
|
|
650
|
-
}
|
|
651
|
-
|
|
652
|
-
void BtPeerConnection::send_interested() {
|
|
653
|
-
LOG_DEBUG("BtPeerConn", "send_interested to " + ip_);
|
|
654
|
-
am_interested_ = true;
|
|
655
|
-
queue_send(BtMessageEncoder::encode_interested());
|
|
656
|
-
++stats_.messages_sent;
|
|
657
|
-
}
|
|
658
|
-
|
|
659
|
-
void BtPeerConnection::send_not_interested() {
|
|
660
|
-
LOG_DEBUG("BtPeerConn", "send_not_interested to " + ip_);
|
|
661
|
-
am_interested_ = false;
|
|
662
|
-
queue_send(BtMessageEncoder::encode_not_interested());
|
|
663
|
-
++stats_.messages_sent;
|
|
664
|
-
}
|
|
665
|
-
|
|
666
|
-
void BtPeerConnection::send_have(uint32_t piece_index) {
|
|
667
|
-
LOG_DEBUG("BtPeerConn", "send_have piece=" + std::to_string(piece_index) + " to " + ip_);
|
|
668
|
-
queue_send(BtMessageEncoder::encode_have(piece_index));
|
|
669
|
-
++stats_.messages_sent;
|
|
670
|
-
}
|
|
671
|
-
|
|
672
|
-
void BtPeerConnection::send_bitfield(const Bitfield& bitfield) {
|
|
673
|
-
LOG_DEBUG("BtPeerConn", "send_bitfield bits=" + std::to_string(bitfield.count()) + " to " + ip_);
|
|
674
|
-
queue_send(BtMessageEncoder::encode_bitfield(bitfield));
|
|
675
|
-
++stats_.messages_sent;
|
|
676
|
-
}
|
|
677
|
-
|
|
678
|
-
void BtPeerConnection::send_request(uint32_t piece, uint32_t begin, uint32_t length) {
|
|
679
|
-
LOG_DEBUG("BtPeerConn", "send_request piece=" + std::to_string(piece) +
|
|
680
|
-
" begin=" + std::to_string(begin) + " len=" + std::to_string(length) + " to " + ip_);
|
|
681
|
-
queue_send(BtMessageEncoder::encode_request(piece, begin, length));
|
|
682
|
-
++stats_.messages_sent;
|
|
683
|
-
|
|
684
|
-
add_pending_request(RequestMessage(piece, begin, length));
|
|
685
|
-
}
|
|
686
|
-
|
|
687
|
-
void BtPeerConnection::send_piece(uint32_t piece, uint32_t begin,
|
|
688
|
-
const uint8_t* data, size_t length) {
|
|
689
|
-
LOG_DEBUG("BtPeerConn", "send_piece piece=" + std::to_string(piece) +
|
|
690
|
-
" begin=" + std::to_string(begin) + " len=" + std::to_string(length) + " to " + ip_);
|
|
691
|
-
queue_send(BtMessageEncoder::encode_piece(piece, begin, data, length));
|
|
692
|
-
stats_.bytes_uploaded += length;
|
|
693
|
-
++stats_.pieces_sent;
|
|
694
|
-
++stats_.messages_sent;
|
|
695
|
-
}
|
|
696
|
-
|
|
697
|
-
void BtPeerConnection::send_cancel(uint32_t piece, uint32_t begin, uint32_t length) {
|
|
698
|
-
LOG_DEBUG("BtPeerConn", "send_cancel piece=" + std::to_string(piece) +
|
|
699
|
-
" begin=" + std::to_string(begin) + " len=" + std::to_string(length) + " to " + ip_);
|
|
700
|
-
queue_send(BtMessageEncoder::encode_cancel(piece, begin, length));
|
|
701
|
-
++stats_.messages_sent;
|
|
702
|
-
|
|
703
|
-
remove_pending_request(RequestMessage(piece, begin, length));
|
|
704
|
-
}
|
|
705
|
-
|
|
706
|
-
void BtPeerConnection::send_keepalive() {
|
|
707
|
-
LOG_DEBUG("BtPeerConn", "send_keepalive to " + ip_);
|
|
708
|
-
queue_send(BtMessageEncoder::encode_keepalive());
|
|
709
|
-
}
|
|
710
|
-
|
|
711
|
-
void BtPeerConnection::send_extended(uint8_t extension_id,
|
|
712
|
-
const std::vector<uint8_t>& payload) {
|
|
713
|
-
LOG_DEBUG("BtPeerConn", "send_extended ext_id=" + std::to_string(extension_id) +
|
|
714
|
-
" payload=" + std::to_string(payload.size()) + " bytes to " + ip_);
|
|
715
|
-
queue_send(BtMessageEncoder::encode_extended(extension_id, payload));
|
|
716
|
-
++stats_.messages_sent;
|
|
717
|
-
}
|
|
718
|
-
|
|
719
|
-
//=============================================================================
|
|
720
|
-
// Request Tracking
|
|
721
|
-
//=============================================================================
|
|
722
|
-
|
|
723
|
-
void BtPeerConnection::add_pending_request(const RequestMessage& req) {
|
|
724
|
-
// Avoid duplicates
|
|
725
|
-
auto it = std::find(pending_requests_.begin(), pending_requests_.end(), req);
|
|
726
|
-
if (it == pending_requests_.end()) {
|
|
727
|
-
pending_requests_.push_back(req);
|
|
728
|
-
}
|
|
729
|
-
}
|
|
730
|
-
|
|
731
|
-
void BtPeerConnection::remove_pending_request(const RequestMessage& req) {
|
|
732
|
-
auto it = std::find(pending_requests_.begin(), pending_requests_.end(), req);
|
|
733
|
-
if (it != pending_requests_.end()) {
|
|
734
|
-
pending_requests_.erase(it);
|
|
735
|
-
}
|
|
736
|
-
}
|
|
737
|
-
|
|
738
|
-
void BtPeerConnection::clear_pending_requests() {
|
|
739
|
-
pending_requests_.clear();
|
|
740
|
-
}
|
|
741
|
-
|
|
742
|
-
} // namespace librats
|