librats 0.7.1 → 0.8.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/native-src/CMakeLists.txt +15 -2
- package/native-src/src/bt_client.cpp +18 -5
- package/native-src/src/bt_client.h +3 -1
- package/native-src/src/bt_network.cpp +297 -184
- package/native-src/src/bt_network.h +25 -5
- package/native-src/src/bt_peer_connection.cpp +11 -0
- package/native-src/src/bt_peer_connection.h +6 -0
- package/native-src/src/bt_torrent.cpp +17 -6
- package/native-src/src/bt_torrent.h +1 -0
- package/native-src/src/bt_types.h +287 -20
- package/native-src/src/dht.cpp +26 -8
- package/native-src/src/dht.h +1 -1
- package/native-src/src/ice.cpp +1 -1
- package/native-src/src/io_poller.cpp +910 -0
- package/native-src/src/io_poller.h +138 -0
- package/native-src/src/krpc.cpp +8 -1
- package/native-src/src/krpc.h +3 -2
- package/native-src/src/librats.cpp +824 -1213
- package/native-src/src/librats.h +167 -54
- package/native-src/src/librats_bittorrent.cpp +4 -7
- package/native-src/src/librats_c.cpp +13 -1
- package/native-src/src/librats_c.h +2 -0
- package/native-src/src/librats_discovery.cpp +309 -0
- package/native-src/src/librats_encryption.cpp +130 -283
- package/native-src/src/librats_file_transfer.cpp +2 -6
- package/native-src/src/librats_gossipsub.cpp +1 -5
- package/native-src/src/librats_ice.cpp +1 -1
- package/native-src/src/librats_log_macros.h +36 -0
- package/native-src/src/librats_logging.cpp +10 -7
- package/native-src/src/librats_mdns.cpp +1 -11
- package/native-src/src/librats_persistence.cpp +1 -11
- package/native-src/src/librats_reconnection.cpp +2 -13
- package/native-src/src/librats_statistic.cpp +97 -0
- package/native-src/src/logger.h +40 -4
- package/native-src/src/network_utils.cpp +175 -373
- package/native-src/src/network_utils.h +2 -113
- package/native-src/src/socket.cpp +485 -883
- package/native-src/src/socket.h +36 -130
- package/native-src/src/stun.cpp +3 -5
- package/native-src/src/tracker.cpp +3 -2
- package/native-src/src/turn.cpp +4 -6
- package/package.json +1 -1
package/native-src/src/librats.h
CHANGED
|
@@ -9,6 +9,9 @@
|
|
|
9
9
|
#include "file_transfer.h" // File transfer functionality
|
|
10
10
|
#include "noise.h" // Noise Protocol encryption
|
|
11
11
|
#include "ice.h" // ICE-lite NAT traversal
|
|
12
|
+
#include "io_poller.h" // Platform-optimal I/O multiplexing
|
|
13
|
+
#include "receive_buffer.h" // Efficient receive buffer for async I/O
|
|
14
|
+
#include "chained_send_buffer.h" // Zero-copy chained send buffer
|
|
12
15
|
#ifdef RATS_STORAGE
|
|
13
16
|
#include "storage.h" // Distributed storage functionality
|
|
14
17
|
#endif
|
|
@@ -25,14 +28,32 @@
|
|
|
25
28
|
#include <unordered_map>
|
|
26
29
|
#include <memory>
|
|
27
30
|
#include <chrono>
|
|
28
|
-
#include <
|
|
29
|
-
#include <unordered_set> // Added for unordered_set
|
|
31
|
+
#include <unordered_set>
|
|
30
32
|
#include <cstdint>
|
|
31
33
|
#include <cstring>
|
|
34
|
+
#include <optional>
|
|
32
35
|
#include "rats_export.h"
|
|
33
36
|
|
|
34
37
|
namespace librats {
|
|
35
38
|
|
|
39
|
+
/**
|
|
40
|
+
* PeerIOContext - Per-peer async I/O buffers and framing state
|
|
41
|
+
*
|
|
42
|
+
* Used by the single-threaded IO loop for non-blocking message framing:
|
|
43
|
+
* recv_buffer – incoming bytes from recv(); frames parsed incrementally
|
|
44
|
+
* send_buffer – outgoing frames queued for non-blocking send()
|
|
45
|
+
* noise_hs – transient Noise XX handshake state (only during NOISE_PENDING)
|
|
46
|
+
* noise_step – current step in the 3-message XX pattern
|
|
47
|
+
*/
|
|
48
|
+
struct PeerIOContext {
|
|
49
|
+
ReceiveBuffer recv_buffer{8192};
|
|
50
|
+
ChainedSendBuffer send_buffer;
|
|
51
|
+
|
|
52
|
+
// Async Noise handshake (only valid while handshake_state == NOISE_PENDING)
|
|
53
|
+
std::unique_ptr<rats::NoiseHandshakeState> noise_hs;
|
|
54
|
+
int noise_step = 0; // XX pattern: 0→initial, advances per message
|
|
55
|
+
};
|
|
56
|
+
|
|
36
57
|
/**
|
|
37
58
|
* RatsPeer struct - comprehensive information about a connected rats peer
|
|
38
59
|
*/
|
|
@@ -65,6 +86,9 @@ struct RatsPeer {
|
|
|
65
86
|
std::shared_ptr<rats::NoiseCipherState> recv_cipher; // Cipher for receiving encrypted data
|
|
66
87
|
std::vector<uint8_t> remote_static_key; // Remote peer's static public key (for identity verification)
|
|
67
88
|
|
|
89
|
+
// Async I/O context (per-peer buffers for non-blocking I/O)
|
|
90
|
+
PeerIOContext io_;
|
|
91
|
+
|
|
68
92
|
RatsPeer() : handshake_state(HandshakeState::PENDING),
|
|
69
93
|
encryption_enabled(false),
|
|
70
94
|
noise_handshake_completed(false) {
|
|
@@ -83,6 +107,45 @@ struct RatsPeer {
|
|
|
83
107
|
handshake_start_time = connected_at;
|
|
84
108
|
}
|
|
85
109
|
|
|
110
|
+
// Custom copy: copies all fields except io_ (non-copyable due to unique_ptr).
|
|
111
|
+
// Copies are used for snapshots passed to callbacks – they never need the IO context.
|
|
112
|
+
RatsPeer(const RatsPeer& o)
|
|
113
|
+
: peer_id(o.peer_id), ip(o.ip), port(o.port), socket(o.socket),
|
|
114
|
+
normalized_address(o.normalized_address), connected_at(o.connected_at),
|
|
115
|
+
is_outgoing(o.is_outgoing), handshake_state(o.handshake_state),
|
|
116
|
+
version(o.version), handshake_start_time(o.handshake_start_time),
|
|
117
|
+
encryption_enabled(o.encryption_enabled),
|
|
118
|
+
noise_handshake_completed(o.noise_handshake_completed),
|
|
119
|
+
send_cipher(o.send_cipher), recv_cipher(o.recv_cipher),
|
|
120
|
+
remote_static_key(o.remote_static_key)
|
|
121
|
+
/* io_ default-constructed (fresh, empty) */ {}
|
|
122
|
+
|
|
123
|
+
RatsPeer& operator=(const RatsPeer& o) {
|
|
124
|
+
if (this != &o) {
|
|
125
|
+
peer_id = o.peer_id;
|
|
126
|
+
ip = o.ip;
|
|
127
|
+
port = o.port;
|
|
128
|
+
socket = o.socket;
|
|
129
|
+
normalized_address = o.normalized_address;
|
|
130
|
+
connected_at = o.connected_at;
|
|
131
|
+
is_outgoing = o.is_outgoing;
|
|
132
|
+
handshake_state = o.handshake_state;
|
|
133
|
+
version = o.version;
|
|
134
|
+
handshake_start_time = o.handshake_start_time;
|
|
135
|
+
encryption_enabled = o.encryption_enabled;
|
|
136
|
+
noise_handshake_completed = o.noise_handshake_completed;
|
|
137
|
+
send_cipher = o.send_cipher;
|
|
138
|
+
recv_cipher = o.recv_cipher;
|
|
139
|
+
remote_static_key = o.remote_static_key;
|
|
140
|
+
// io_ left unchanged in the destination (no copy)
|
|
141
|
+
}
|
|
142
|
+
return *this;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Default move operations are fine
|
|
146
|
+
RatsPeer(RatsPeer&&) = default;
|
|
147
|
+
RatsPeer& operator=(RatsPeer&&) = default;
|
|
148
|
+
|
|
86
149
|
// Check if peer has completed Noise handshake and is ready for encrypted communication
|
|
87
150
|
bool is_noise_encrypted() const {
|
|
88
151
|
return noise_handshake_completed && send_cipher && recv_cipher;
|
|
@@ -261,7 +324,6 @@ public:
|
|
|
261
324
|
*/
|
|
262
325
|
bool is_running() const;
|
|
263
326
|
|
|
264
|
-
|
|
265
327
|
// =========================================================================
|
|
266
328
|
// Utility Methods
|
|
267
329
|
// =========================================================================
|
|
@@ -387,7 +449,6 @@ public:
|
|
|
387
449
|
*/
|
|
388
450
|
int get_peer_count() const;
|
|
389
451
|
|
|
390
|
-
|
|
391
452
|
/**
|
|
392
453
|
* Get peer_id for a peer by socket (preferred)
|
|
393
454
|
* @param socket Peer socket
|
|
@@ -423,16 +484,16 @@ public:
|
|
|
423
484
|
/**
|
|
424
485
|
* Get peer information by peer ID
|
|
425
486
|
* @param peer_id The peer ID to look up
|
|
426
|
-
* @return
|
|
487
|
+
* @return Copy of RatsPeer object, or std::nullopt if not found
|
|
427
488
|
*/
|
|
428
|
-
|
|
489
|
+
std::optional<RatsPeer> get_peer_by_id(const std::string& peer_id) const;
|
|
429
490
|
|
|
430
491
|
/**
|
|
431
492
|
* Get peer information by socket
|
|
432
493
|
* @param socket The socket handle to look up
|
|
433
|
-
* @return
|
|
494
|
+
* @return Copy of RatsPeer object, or std::nullopt if not found
|
|
434
495
|
*/
|
|
435
|
-
|
|
496
|
+
std::optional<RatsPeer> get_peer_by_socket(socket_t socket) const;
|
|
436
497
|
|
|
437
498
|
/**
|
|
438
499
|
* Get maximum number of peers
|
|
@@ -476,9 +537,9 @@ public:
|
|
|
476
537
|
|
|
477
538
|
/**
|
|
478
539
|
* Get current reconnection configuration
|
|
479
|
-
* @return
|
|
540
|
+
* @return Copy of current reconnection configuration
|
|
480
541
|
*/
|
|
481
|
-
|
|
542
|
+
ReconnectConfig get_reconnect_config() const;
|
|
482
543
|
|
|
483
544
|
/**
|
|
484
545
|
* Get the number of peers pending reconnection
|
|
@@ -636,6 +697,13 @@ public:
|
|
|
636
697
|
*/
|
|
637
698
|
bool is_automatic_discovery_running() const;
|
|
638
699
|
|
|
700
|
+
/**
|
|
701
|
+
* Calculate discovery interval based on current peer count
|
|
702
|
+
* Uses graduated scaling: more aggressive when fewer peers, less aggressive when nearly full
|
|
703
|
+
* @return Discovery interval in seconds
|
|
704
|
+
*/
|
|
705
|
+
std::chrono::seconds calculate_discovery_interval() const;
|
|
706
|
+
|
|
639
707
|
/**
|
|
640
708
|
* Get the discovery hash for current protocol configuration
|
|
641
709
|
* @return Discovery hash based on current protocol name and version
|
|
@@ -723,14 +791,6 @@ public:
|
|
|
723
791
|
*/
|
|
724
792
|
void send(const std::string& peer_id, const std::string& message_type, const nlohmann::json& data, SendCallback callback = nullptr);
|
|
725
793
|
|
|
726
|
-
/**
|
|
727
|
-
* Parse a JSON message
|
|
728
|
-
* @param message Raw message string
|
|
729
|
-
* @param out_json Parsed JSON output
|
|
730
|
-
* @return true if parsed successfully
|
|
731
|
-
*/
|
|
732
|
-
bool parse_json_message(const std::string& message, nlohmann::json& out_json);
|
|
733
|
-
|
|
734
794
|
// =========================================================================
|
|
735
795
|
// Encryption Functionality
|
|
736
796
|
// =========================================================================
|
|
@@ -1084,6 +1144,20 @@ public:
|
|
|
1084
1144
|
*/
|
|
1085
1145
|
void set_log_retention_count(int count);
|
|
1086
1146
|
|
|
1147
|
+
/**
|
|
1148
|
+
* Enable or disable log rotation on application startup
|
|
1149
|
+
* When enabled, the existing log file will be rotated when logging starts,
|
|
1150
|
+
* so each application run gets a fresh log file
|
|
1151
|
+
* @param enabled Whether to rotate logs on startup (default: false)
|
|
1152
|
+
*/
|
|
1153
|
+
void set_log_rotate_on_startup(bool enabled);
|
|
1154
|
+
|
|
1155
|
+
/**
|
|
1156
|
+
* Check if log rotation on startup is enabled
|
|
1157
|
+
* @return true if rotate on startup is enabled
|
|
1158
|
+
*/
|
|
1159
|
+
bool is_log_rotate_on_startup_enabled() const;
|
|
1160
|
+
|
|
1087
1161
|
/**
|
|
1088
1162
|
* Clear/reset the current log file
|
|
1089
1163
|
*/
|
|
@@ -1233,7 +1307,7 @@ public:
|
|
|
1233
1307
|
* Get current file transfer configuration
|
|
1234
1308
|
* @return Current configuration settings
|
|
1235
1309
|
*/
|
|
1236
|
-
|
|
1310
|
+
FileTransferConfig get_file_transfer_config() const;
|
|
1237
1311
|
|
|
1238
1312
|
// Event Handlers
|
|
1239
1313
|
/**
|
|
@@ -1442,7 +1516,7 @@ public:
|
|
|
1442
1516
|
* Get current ICE configuration
|
|
1443
1517
|
* @return Current ICE configuration
|
|
1444
1518
|
*/
|
|
1445
|
-
|
|
1519
|
+
IceConfig get_ice_config() const;
|
|
1446
1520
|
|
|
1447
1521
|
// ICE Lifecycle
|
|
1448
1522
|
/**
|
|
@@ -1938,7 +2012,7 @@ private:
|
|
|
1938
2012
|
// 3. encryption_mutex_ (Encryption settings and keys)
|
|
1939
2013
|
// 4. local_addresses_mutex_ (Local interface addresses)
|
|
1940
2014
|
// 5. peers_mutex_ (Peer management - most frequently locked)
|
|
1941
|
-
// 6.
|
|
2015
|
+
// 6. io_mutex_ (I/O poller and send buffer access)
|
|
1942
2016
|
// 7. message_handlers_mutex_ (Message handler registration)
|
|
1943
2017
|
// 8. reconnect_mutex_ (Reconnection queue management)
|
|
1944
2018
|
// =========================================================================
|
|
@@ -1964,20 +2038,19 @@ private:
|
|
|
1964
2038
|
|
|
1965
2039
|
// [4] Local interface address blocking (protected by local_addresses_mutex_)
|
|
1966
2040
|
mutable std::mutex local_addresses_mutex_; // [4] Protects local interface addresses
|
|
1967
|
-
std::
|
|
2041
|
+
std::unordered_set<std::string> local_interface_addresses_;
|
|
1968
2042
|
|
|
1969
2043
|
// [5] Organized peer management using RatsPeer struct (protected by peers_mutex_)
|
|
1970
2044
|
mutable std::mutex peers_mutex_; // [5] Protects peer data (most frequently locked)
|
|
1971
2045
|
std::unordered_map<std::string, RatsPeer> peers_; // keyed by peer_id
|
|
1972
2046
|
std::unordered_map<socket_t, std::string> socket_to_peer_id_; // for quick socket->peer_id lookup
|
|
1973
2047
|
std::unordered_map<std::string, std::string> address_to_peer_id_; // for duplicate detection (normalized_address->peer_id)
|
|
2048
|
+
std::atomic<int> validated_peer_count_{0}; // Cached count of peers with COMPLETED handshake
|
|
1974
2049
|
|
|
1975
|
-
// [6]
|
|
1976
|
-
|
|
1977
|
-
std::
|
|
1978
|
-
|
|
1979
|
-
// Server and client management
|
|
1980
|
-
std::thread server_thread_;
|
|
2050
|
+
// [6] Async I/O (poller + io thread)
|
|
2051
|
+
std::unique_ptr<IOPoller> poller_;
|
|
2052
|
+
std::mutex io_mutex_; // Protects poller_ and send-buffer writes from non-IO threads
|
|
2053
|
+
std::thread io_thread_;
|
|
1981
2054
|
std::thread management_thread_;
|
|
1982
2055
|
|
|
1983
2056
|
ConnectionCallback connection_callback_;
|
|
@@ -2015,11 +2088,31 @@ private:
|
|
|
2015
2088
|
void initialize_modules();
|
|
2016
2089
|
void destroy_modules();
|
|
2017
2090
|
|
|
2018
|
-
|
|
2091
|
+
// Async I/O loop (single thread for all sockets)
|
|
2092
|
+
void io_loop();
|
|
2019
2093
|
void management_loop();
|
|
2020
|
-
|
|
2094
|
+
|
|
2095
|
+
// I/O event handlers (called from io_loop)
|
|
2096
|
+
void accept_incoming();
|
|
2097
|
+
bool handle_readable(socket_t socket);
|
|
2098
|
+
bool handle_writable(socket_t socket);
|
|
2099
|
+
void handle_disconnect(socket_t socket);
|
|
2100
|
+
|
|
2101
|
+
// Poller registration helpers
|
|
2102
|
+
void poller_add(socket_t fd, uint32_t events);
|
|
2103
|
+
void poller_modify(socket_t fd, uint32_t events);
|
|
2104
|
+
void poller_remove(socket_t fd);
|
|
2105
|
+
|
|
2106
|
+
// Helpers – post-handshake and message routing
|
|
2107
|
+
void handle_post_handshake_completion(socket_t socket, const RatsPeer& peer_copy);
|
|
2108
|
+
void process_message(socket_t socket, const std::vector<uint8_t>& data, const std::string& peer_id);
|
|
2109
|
+
|
|
2110
|
+
// Peer lookup helper (assumes peers_mutex_ is already locked)
|
|
2111
|
+
std::unordered_map<std::string, RatsPeer>::iterator find_peer_by_socket_unlocked(socket_t socket);
|
|
2112
|
+
std::unordered_map<std::string, RatsPeer>::const_iterator find_peer_by_socket_unlocked(socket_t socket) const;
|
|
2113
|
+
|
|
2021
2114
|
void remove_peer(socket_t socket);
|
|
2022
|
-
std::string
|
|
2115
|
+
std::string generate_temporary_peer_id(socket_t socket, const std::string& connection_info);
|
|
2023
2116
|
void handle_dht_peer_discovery(const std::vector<Peer>& peers, const InfoHash& info_hash);
|
|
2024
2117
|
void handle_mdns_service_discovery(const MdnsService& service, bool is_new);
|
|
2025
2118
|
|
|
@@ -2028,31 +2121,62 @@ private:
|
|
|
2028
2121
|
bool parse_message_with_header(const std::vector<uint8_t>& message, MessageHeader& header, std::vector<uint8_t>& payload) const;
|
|
2029
2122
|
|
|
2030
2123
|
// Peer management methods using RatsPeer
|
|
2031
|
-
void add_peer(const RatsPeer& peer);
|
|
2032
2124
|
void add_peer_unlocked(const RatsPeer& peer); // Assumes peers_mutex_ is already locked
|
|
2033
|
-
void remove_peer_by_id(const std::string& peer_id);
|
|
2034
2125
|
void remove_peer_by_id_unlocked(const std::string& peer_id); // Assumes peers_mutex_ is already locked
|
|
2126
|
+
void mark_manual_disconnect(const std::string& peer_id);
|
|
2127
|
+
static std::vector<uint8_t> json_to_binary(const nlohmann::json& data);
|
|
2035
2128
|
bool is_already_connected_to_address(const std::string& normalized_address) const;
|
|
2036
2129
|
std::string normalize_peer_address(const std::string& ip, int port) const;
|
|
2037
2130
|
|
|
2038
|
-
//
|
|
2131
|
+
// Async send – enqueues a framed (length-prefixed) message into the peer's
|
|
2132
|
+
// ChainedSendBuffer and arms PollOut. Thread-safe (acquires io_mutex_).
|
|
2133
|
+
// Returns false if the peer was not found.
|
|
2134
|
+
bool enqueue_message(socket_t socket, const std::vector<uint8_t>& data);
|
|
2135
|
+
// Unlocked variant – caller must hold peers_mutex_
|
|
2136
|
+
bool enqueue_message_unlocked(RatsPeer& peer, const std::vector<uint8_t>& data);
|
|
2137
|
+
|
|
2138
|
+
// Lightweight snapshot of peer data needed for sending (avoids holding peers_mutex_ during enqueue)
|
|
2139
|
+
struct PeerSendTarget {
|
|
2140
|
+
socket_t socket;
|
|
2141
|
+
std::string peer_id;
|
|
2142
|
+
std::shared_ptr<rats::NoiseCipherState> send_cipher;
|
|
2143
|
+
};
|
|
2144
|
+
|
|
2039
2145
|
bool send_binary_to_peer_unlocked(socket_t socket, const std::vector<uint8_t>& data,
|
|
2040
2146
|
MessageDataType message_type,
|
|
2041
|
-
rats::NoiseCipherState
|
|
2147
|
+
std::shared_ptr<rats::NoiseCipherState> send_cipher,
|
|
2042
2148
|
const std::string& peer_id_for_logging);
|
|
2149
|
+
|
|
2150
|
+
// Async Noise handshake – processes one Noise XX message received from peer.
|
|
2151
|
+
// Returns false if peer should be disconnected. Called from handle_readable.
|
|
2152
|
+
bool handle_noise_frame(RatsPeer& peer);
|
|
2153
|
+
// Kick-off: initialises noise_hs and writes first outgoing message if initiator.
|
|
2154
|
+
void start_noise_handshake_async(RatsPeer& peer);
|
|
2043
2155
|
|
|
2044
2156
|
// Local interface address blocking helper functions
|
|
2045
2157
|
void initialize_local_addresses();
|
|
2046
2158
|
bool is_blocked_address(const std::string& ip_address) const;
|
|
2047
2159
|
bool should_ignore_peer(const std::string& ip, int port) const;
|
|
2160
|
+
bool can_connect_to_peer(const std::string& ip, int port) const;
|
|
2048
2161
|
static bool parse_address_string(const std::string& address_str, std::string& out_ip, int& out_port);
|
|
2049
2162
|
|
|
2050
2163
|
// Helper functions that assume mutex is already locked
|
|
2051
2164
|
int get_peer_count_unlocked() const; // Helper that assumes peers_mutex_ is already locked
|
|
2052
2165
|
|
|
2053
|
-
//
|
|
2166
|
+
// Protocol constants
|
|
2054
2167
|
static constexpr const char* RATS_PROTOCOL_VERSION = "1.0";
|
|
2055
2168
|
static constexpr int HANDSHAKE_TIMEOUT_SECONDS = 10;
|
|
2169
|
+
static constexpr int TCP_CONNECT_TIMEOUT_MS = 10000; // 10 second TCP connection timeout
|
|
2170
|
+
static constexpr int IO_POLL_TIMEOUT_MS = 100; // IO poller tick interval (ms)
|
|
2171
|
+
static constexpr size_t MAX_FRAME_SIZE = 100 * 1024 * 1024; // 100 MB max single frame
|
|
2172
|
+
static constexpr int PEER_RECONNECT_DELAY_MS = 100; // Delay before reconnecting saved peers
|
|
2173
|
+
static constexpr int HISTORICAL_RECONNECT_DELAY_MS = 500; // Delay before reconnecting historical peers
|
|
2174
|
+
static constexpr int MANAGEMENT_LOOP_INTERVAL_SECONDS = 2; // Management loop tick interval
|
|
2175
|
+
static constexpr int THREAD_CLEANUP_INTERVAL_SECONDS = 30; // Thread cleanup interval
|
|
2176
|
+
static constexpr int INITIAL_DISCOVERY_DELAY_SECONDS = 5; // DHT bootstrap delay
|
|
2177
|
+
static constexpr int MAX_PEERS_REQUEST_COUNT = 5; // Max peers to request/respond
|
|
2178
|
+
static constexpr int CONTENT_HASH_HEX_LENGTH = 40; // 160-bit hash as hex
|
|
2179
|
+
static constexpr int64_t TIMESTAMP_SKEW_TOLERANCE_MS = 10LL * 60LL * 1000LL; // 10 minutes
|
|
2056
2180
|
|
|
2057
2181
|
struct HandshakeMessage {
|
|
2058
2182
|
std::string protocol;
|
|
@@ -2068,9 +2192,8 @@ private:
|
|
|
2068
2192
|
bool parse_handshake_message(const std::vector<uint8_t>& data, HandshakeMessage& out_msg) const;
|
|
2069
2193
|
bool validate_handshake_message(const HandshakeMessage& msg) const;
|
|
2070
2194
|
bool is_handshake_message(const std::vector<uint8_t>& data) const;
|
|
2071
|
-
bool
|
|
2072
|
-
bool
|
|
2073
|
-
bool handle_handshake_message(socket_t socket, const std::string& peer_hash_id, const std::vector<uint8_t>& data);
|
|
2195
|
+
bool send_handshake_unlocked(RatsPeer& peer, const std::string& our_peer_id); // enqueues via send buffer (peers_mutex_ held)
|
|
2196
|
+
bool handle_handshake_message(socket_t socket, const std::string& initial_peer_id, const std::vector<uint8_t>& data);
|
|
2074
2197
|
void check_handshake_timeouts();
|
|
2075
2198
|
void log_handshake_completion_unlocked(const RatsPeer& peer);
|
|
2076
2199
|
|
|
@@ -2082,12 +2205,12 @@ private:
|
|
|
2082
2205
|
|
|
2083
2206
|
// Message handling system
|
|
2084
2207
|
nlohmann::json create_rats_message(const std::string& type, const nlohmann::json& payload, const std::string& sender_peer_id);
|
|
2085
|
-
void handle_rats_message(socket_t socket, const std::string&
|
|
2208
|
+
void handle_rats_message(socket_t socket, const std::string& peer_id, const nlohmann::json& message);
|
|
2086
2209
|
|
|
2087
2210
|
// Specific message handlers
|
|
2088
|
-
void handle_peer_exchange_message(socket_t socket, const std::string&
|
|
2089
|
-
void handle_peers_request_message(socket_t socket, const std::string&
|
|
2090
|
-
void handle_peers_response_message(socket_t socket, const std::string&
|
|
2211
|
+
void handle_peer_exchange_message(socket_t socket, const std::string& peer_id, const nlohmann::json& payload);
|
|
2212
|
+
void handle_peers_request_message(socket_t socket, const std::string& peer_id, const nlohmann::json& payload);
|
|
2213
|
+
void handle_peers_response_message(socket_t socket, const std::string& peer_id, const nlohmann::json& payload);
|
|
2091
2214
|
|
|
2092
2215
|
// Message creation and broadcasting
|
|
2093
2216
|
nlohmann::json create_peer_exchange_message(const RatsPeer& peer);
|
|
@@ -2097,8 +2220,7 @@ private:
|
|
|
2097
2220
|
std::vector<RatsPeer> get_random_peers(int max_count, const std::string& exclude_peer_id = "") const;
|
|
2098
2221
|
void send_peers_request(socket_t socket, const std::string& our_peer_id);
|
|
2099
2222
|
|
|
2100
|
-
int broadcast_rats_message(const nlohmann::json& message, const std::string& exclude_peer_id = "");
|
|
2101
|
-
int broadcast_rats_message_to_validated_peers(const nlohmann::json& message, const std::string& exclude_peer_id = "");
|
|
2223
|
+
int broadcast_rats_message(const nlohmann::json& message, const std::string& exclude_peer_id = "", bool validated_only = true);
|
|
2102
2224
|
|
|
2103
2225
|
// [7] Message exchange API implementation (protected by message_handlers_mutex_)
|
|
2104
2226
|
mutable std::mutex message_handlers_mutex_; // [7] Protects message handlers
|
|
@@ -2124,10 +2246,6 @@ private:
|
|
|
2124
2246
|
void remove_from_reconnect_queue(const std::string& peer_id);
|
|
2125
2247
|
int get_retry_interval_seconds(int attempt, bool is_stable) const;
|
|
2126
2248
|
|
|
2127
|
-
// Per-socket synchronization helpers
|
|
2128
|
-
std::shared_ptr<std::mutex> get_socket_send_mutex(socket_t socket);
|
|
2129
|
-
void cleanup_socket_send_mutex(socket_t socket);
|
|
2130
|
-
|
|
2131
2249
|
// Configuration persistence helpers
|
|
2132
2250
|
std::string generate_persistent_peer_id() const;
|
|
2133
2251
|
nlohmann::json serialize_peer_for_persistence(const RatsPeer& peer) const;
|
|
@@ -2141,11 +2259,6 @@ private:
|
|
|
2141
2259
|
|
|
2142
2260
|
// Noise Protocol encryption helpers
|
|
2143
2261
|
void initialize_noise_keypair();
|
|
2144
|
-
bool perform_noise_handshake(socket_t socket, const std::string& peer_id, bool is_initiator);
|
|
2145
|
-
bool send_noise_message(socket_t socket, const uint8_t* data, size_t len);
|
|
2146
|
-
bool recv_noise_message(socket_t socket, std::vector<uint8_t>& out_data, int timeout_ms = 10000);
|
|
2147
|
-
bool encrypt_and_send(socket_t socket, const std::string& peer_id, const std::vector<uint8_t>& plaintext);
|
|
2148
|
-
bool receive_and_decrypt(socket_t socket, const std::string& peer_id, std::vector<uint8_t>& plaintext);
|
|
2149
2262
|
};
|
|
2150
2263
|
|
|
2151
2264
|
// Utility functions
|
|
@@ -4,11 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
#ifdef RATS_SEARCH_FEATURES
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
#define LOG_CLIENT_DEBUG(message) LOG_DEBUG("client", message)
|
|
9
|
-
#define LOG_CLIENT_INFO(message) LOG_INFO("client", message)
|
|
10
|
-
#define LOG_CLIENT_WARN(message) LOG_WARN("client", message)
|
|
11
|
-
#define LOG_CLIENT_ERROR(message) LOG_ERROR("client", message)
|
|
7
|
+
#include "librats_log_macros.h"
|
|
12
8
|
|
|
13
9
|
namespace librats {
|
|
14
10
|
|
|
@@ -248,12 +244,13 @@ void RatsClient::get_torrent_metadata_from_peer(const InfoHash& info_hash,
|
|
|
248
244
|
return;
|
|
249
245
|
}
|
|
250
246
|
|
|
251
|
-
LOG_CLIENT_INFO("Fetching metadata from peer " << peer_ip << ":" << peer_port << " (fast path)");
|
|
247
|
+
LOG_CLIENT_INFO("Fetching metadata from peer " << peer_ip << ":" << peer_port << " (fast path, no DHT)");
|
|
252
248
|
|
|
253
249
|
// Add magnet in metadata-only mode (empty save_path) and immediately add the peer
|
|
250
|
+
// skip_dht_search=true to avoid network-wide DHT queries - we only want this specific peer
|
|
254
251
|
std::string hash_hex = info_hash_to_hex(info_hash);
|
|
255
252
|
std::string magnet = "magnet:?xt=urn:btih:" + hash_hex;
|
|
256
|
-
auto torrent = bittorrent_client_->add_magnet(magnet, "");
|
|
253
|
+
auto torrent = bittorrent_client_->add_magnet(magnet, "", true /* skip_dht_search */);
|
|
257
254
|
|
|
258
255
|
if (!torrent) {
|
|
259
256
|
if (callback) {
|
|
@@ -237,6 +237,18 @@ void rats_set_log_retention_count(rats_client_t handle, int count) {
|
|
|
237
237
|
wrap->client->set_log_retention_count(count);
|
|
238
238
|
}
|
|
239
239
|
|
|
240
|
+
void rats_set_log_rotate_on_startup(rats_client_t handle, int enabled) {
|
|
241
|
+
if (!handle) return;
|
|
242
|
+
rats_client_wrapper* wrap = static_cast<rats_client_wrapper*>(handle);
|
|
243
|
+
wrap->client->set_log_rotate_on_startup(enabled != 0);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
int rats_is_log_rotate_on_startup_enabled(rats_client_t handle) {
|
|
247
|
+
if (!handle) return 0;
|
|
248
|
+
rats_client_wrapper* wrap = static_cast<rats_client_wrapper*>(handle);
|
|
249
|
+
return wrap->client->is_log_rotate_on_startup_enabled() ? 1 : 0;
|
|
250
|
+
}
|
|
251
|
+
|
|
240
252
|
void rats_clear_log_file(rats_client_t handle) {
|
|
241
253
|
if (!handle) return;
|
|
242
254
|
rats_client_wrapper* wrap = static_cast<rats_client_wrapper*>(handle);
|
|
@@ -835,7 +847,7 @@ char* rats_get_peer_info_json(rats_client_t handle, const char* peer_id) {
|
|
|
835
847
|
if (!handle || !peer_id) return nullptr;
|
|
836
848
|
rats_client_wrapper* wrap = static_cast<rats_client_wrapper*>(handle);
|
|
837
849
|
|
|
838
|
-
|
|
850
|
+
auto peer = wrap->client->get_peer_by_id(std::string(peer_id));
|
|
839
851
|
if (!peer) return nullptr;
|
|
840
852
|
|
|
841
853
|
// Create JSON representation of peer info
|
|
@@ -53,6 +53,8 @@ RATS_API void rats_set_log_timestamps_enabled(rats_client_t client, int enabled)
|
|
|
53
53
|
RATS_API int rats_is_log_timestamps_enabled(rats_client_t client);
|
|
54
54
|
RATS_API void rats_set_log_rotation_size(rats_client_t client, size_t max_size_bytes);
|
|
55
55
|
RATS_API void rats_set_log_retention_count(rats_client_t client, int count);
|
|
56
|
+
RATS_API void rats_set_log_rotate_on_startup(rats_client_t client, int enabled);
|
|
57
|
+
RATS_API int rats_is_log_rotate_on_startup_enabled(rats_client_t client);
|
|
56
58
|
RATS_API void rats_clear_log_file(rats_client_t client);
|
|
57
59
|
|
|
58
60
|
// Error codes
|