librats 0.7.2 → 0.9.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 +9 -4
- package/lib/index.d.ts +9 -22
- package/native-src/CMakeLists.txt +132 -50
- package/native-src/cmake/ratsConfig.cmake.in +8 -0
- package/native-src/src/bt_network.cpp +296 -183
- package/native-src/src/bt_network.h +25 -5
- package/native-src/src/crypto/sha256.c +1 -1
- package/native-src/src/dht.cpp +297 -47
- package/native-src/src/dht.h +70 -6
- package/native-src/src/file_transfer.cpp +1185 -1578
- package/native-src/src/file_transfer.h +240 -521
- package/native-src/src/io_poller.cpp +917 -0
- package/native-src/src/io_poller.h +138 -0
- package/native-src/src/krpc.cpp +161 -96
- package/native-src/src/krpc.h +18 -4
- package/native-src/src/librats.cpp +812 -1236
- package/native-src/src/librats.h +207 -208
- package/native-src/src/librats_bittorrent.cpp +1 -5
- package/native-src/src/librats_c.cpp +22 -39
- package/native-src/src/librats_discovery.cpp +377 -0
- package/native-src/src/librats_encryption.cpp +130 -283
- package/native-src/src/librats_file_transfer.cpp +27 -109
- package/native-src/src/librats_gossipsub.cpp +1 -5
- package/native-src/src/librats_ice.cpp +5 -1
- package/native-src/src/librats_log_macros.h +36 -0
- package/native-src/src/librats_logging.cpp +1 -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 +105 -0
- package/native-src/src/socket.cpp +15 -3
- package/package.json +1 -1
- package/scripts/build-librats.js +3 -0
- package/scripts/prepare-package.js +10 -0
- package/src/librats_node.cpp +53 -64
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
|
|
@@ -730,14 +791,6 @@ public:
|
|
|
730
791
|
*/
|
|
731
792
|
void send(const std::string& peer_id, const std::string& message_type, const nlohmann::json& data, SendCallback callback = nullptr);
|
|
732
793
|
|
|
733
|
-
/**
|
|
734
|
-
* Parse a JSON message
|
|
735
|
-
* @param message Raw message string
|
|
736
|
-
* @param out_json Parsed JSON output
|
|
737
|
-
* @return true if parsed successfully
|
|
738
|
-
*/
|
|
739
|
-
bool parse_json_message(const std::string& message, nlohmann::json& out_json);
|
|
740
|
-
|
|
741
794
|
// =========================================================================
|
|
742
795
|
// Encryption Functionality
|
|
743
796
|
// =========================================================================
|
|
@@ -1113,185 +1166,88 @@ public:
|
|
|
1113
1166
|
// =========================================================================
|
|
1114
1167
|
// File Transfer API
|
|
1115
1168
|
// =========================================================================
|
|
1116
|
-
|
|
1169
|
+
//
|
|
1170
|
+
// Streams files and directory trees to connected peers. A transfer is
|
|
1171
|
+
// offered to the peer, who accepts (choosing a destination) or rejects it.
|
|
1172
|
+
// See file_transfer.h for the FileTransferManager that implements it.
|
|
1173
|
+
|
|
1117
1174
|
/**
|
|
1118
|
-
* Get the file transfer manager instance
|
|
1119
|
-
* @return Reference to the file transfer manager
|
|
1175
|
+
* Get the file transfer manager instance.
|
|
1120
1176
|
*/
|
|
1121
1177
|
FileTransferManager& get_file_transfer_manager();
|
|
1122
|
-
|
|
1178
|
+
|
|
1123
1179
|
/**
|
|
1124
|
-
* Check
|
|
1125
|
-
* @return true if file transfer manager is initialized
|
|
1180
|
+
* Check whether the file transfer manager is initialized.
|
|
1126
1181
|
*/
|
|
1127
1182
|
bool is_file_transfer_available() const;
|
|
1128
|
-
|
|
1129
|
-
// Sending and Requesting
|
|
1183
|
+
|
|
1130
1184
|
/**
|
|
1131
|
-
* Send a file to a peer
|
|
1132
|
-
* @param peer_id
|
|
1133
|
-
* @param file_path
|
|
1134
|
-
* @param remote_filename Optional
|
|
1135
|
-
* @return Transfer ID
|
|
1185
|
+
* Send a file to a peer.
|
|
1186
|
+
* @param peer_id Target peer ID
|
|
1187
|
+
* @param file_path Local file to send
|
|
1188
|
+
* @param remote_filename Optional name to present to the peer
|
|
1189
|
+
* @return Transfer ID, or empty string on immediate failure
|
|
1136
1190
|
*/
|
|
1137
|
-
std::string send_file(const std::string& peer_id, const std::string& file_path,
|
|
1138
|
-
|
|
1139
|
-
|
|
1191
|
+
std::string send_file(const std::string& peer_id, const std::string& file_path,
|
|
1192
|
+
const std::string& remote_filename = "");
|
|
1193
|
+
|
|
1140
1194
|
/**
|
|
1141
|
-
* Send
|
|
1142
|
-
* @param peer_id
|
|
1143
|
-
* @param directory_path Local directory
|
|
1144
|
-
* @param
|
|
1145
|
-
* @
|
|
1146
|
-
* @return Transfer ID if successful, empty string if failed
|
|
1195
|
+
* Send a directory tree (recursively) to a peer.
|
|
1196
|
+
* @param peer_id Target peer ID
|
|
1197
|
+
* @param directory_path Local directory to send
|
|
1198
|
+
* @param remote_name Optional name to present to the peer
|
|
1199
|
+
* @return Transfer ID, or empty string on immediate failure
|
|
1147
1200
|
*/
|
|
1148
1201
|
std::string send_directory(const std::string& peer_id, const std::string& directory_path,
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
/**
|
|
1152
|
-
* Request a file from a remote peer
|
|
1153
|
-
* @param peer_id Target peer ID
|
|
1154
|
-
* @param remote_file_path Path to file on remote peer
|
|
1155
|
-
* @param local_path Local path where file should be saved
|
|
1156
|
-
* @return Transfer ID if successful, empty string if failed
|
|
1157
|
-
*/
|
|
1158
|
-
std::string request_file(const std::string& peer_id, const std::string& remote_file_path,
|
|
1159
|
-
const std::string& local_path);
|
|
1160
|
-
|
|
1161
|
-
/**
|
|
1162
|
-
* Request a directory from a remote peer
|
|
1163
|
-
* @param peer_id Target peer ID
|
|
1164
|
-
* @param remote_directory_path Path to directory on remote peer
|
|
1165
|
-
* @param local_directory_path Local path where directory should be saved
|
|
1166
|
-
* @param recursive Whether to include subdirectories (default: true)
|
|
1167
|
-
* @return Transfer ID if successful, empty string if failed
|
|
1168
|
-
*/
|
|
1169
|
-
std::string request_directory(const std::string& peer_id, const std::string& remote_directory_path,
|
|
1170
|
-
const std::string& local_directory_path, bool recursive = true);
|
|
1171
|
-
|
|
1172
|
-
// Accept/Reject Operations
|
|
1202
|
+
const std::string& remote_name = "");
|
|
1203
|
+
|
|
1173
1204
|
/**
|
|
1174
|
-
* Accept an incoming file
|
|
1175
|
-
*
|
|
1176
|
-
* @param local_path Local path where file should be saved
|
|
1177
|
-
* @return true if accepted successfully
|
|
1205
|
+
* Accept an incoming transfer. For a file, local_path is the destination
|
|
1206
|
+
* file path; for a directory, it is the destination directory.
|
|
1178
1207
|
*/
|
|
1179
1208
|
bool accept_file_transfer(const std::string& transfer_id, const std::string& local_path);
|
|
1180
|
-
|
|
1209
|
+
|
|
1181
1210
|
/**
|
|
1182
|
-
* Reject an incoming
|
|
1183
|
-
* @param transfer_id Transfer identifier from request
|
|
1184
|
-
* @param reason Optional reason for rejection
|
|
1185
|
-
* @return true if rejected successfully
|
|
1211
|
+
* Reject an incoming transfer.
|
|
1186
1212
|
*/
|
|
1187
1213
|
bool reject_file_transfer(const std::string& transfer_id, const std::string& reason = "");
|
|
1188
|
-
|
|
1189
|
-
/**
|
|
1190
|
-
* Accept an incoming directory transfer
|
|
1191
|
-
* @param transfer_id Transfer identifier from request
|
|
1192
|
-
* @param local_path Local path where directory should be saved
|
|
1193
|
-
* @return true if accepted successfully
|
|
1194
|
-
*/
|
|
1195
|
-
bool accept_directory_transfer(const std::string& transfer_id, const std::string& local_path);
|
|
1196
|
-
|
|
1197
|
-
/**
|
|
1198
|
-
* Reject an incoming directory transfer
|
|
1199
|
-
* @param transfer_id Transfer identifier from request
|
|
1200
|
-
* @param reason Optional reason for rejection
|
|
1201
|
-
* @return true if rejected successfully
|
|
1202
|
-
*/
|
|
1203
|
-
bool reject_directory_transfer(const std::string& transfer_id, const std::string& reason = "");
|
|
1204
|
-
|
|
1205
|
-
// Transfer Control
|
|
1206
|
-
/**
|
|
1207
|
-
* Pause an active file transfer
|
|
1208
|
-
* @param transfer_id Transfer to pause
|
|
1209
|
-
* @return true if paused successfully
|
|
1210
|
-
*/
|
|
1214
|
+
|
|
1215
|
+
/** Pause an active transfer (either direction). */
|
|
1211
1216
|
bool pause_file_transfer(const std::string& transfer_id);
|
|
1212
|
-
|
|
1213
|
-
/**
|
|
1214
|
-
* Resume a paused file transfer
|
|
1215
|
-
* @param transfer_id Transfer to resume
|
|
1216
|
-
* @return true if resumed successfully
|
|
1217
|
-
*/
|
|
1217
|
+
|
|
1218
|
+
/** Resume a paused transfer. */
|
|
1218
1219
|
bool resume_file_transfer(const std::string& transfer_id);
|
|
1219
|
-
|
|
1220
|
-
/**
|
|
1221
|
-
* Cancel an active or paused file transfer
|
|
1222
|
-
* @param transfer_id Transfer to cancel
|
|
1223
|
-
* @return true if cancelled successfully
|
|
1224
|
-
*/
|
|
1220
|
+
|
|
1221
|
+
/** Cancel an active or paused transfer. */
|
|
1225
1222
|
bool cancel_file_transfer(const std::string& transfer_id);
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
/**
|
|
1229
|
-
* Get file transfer progress information
|
|
1230
|
-
* @param transfer_id Transfer to query
|
|
1231
|
-
* @return Progress information or nullptr if not found
|
|
1232
|
-
*/
|
|
1223
|
+
|
|
1224
|
+
/** Get a progress snapshot, or nullptr if the transfer is unknown. */
|
|
1233
1225
|
std::shared_ptr<FileTransferProgress> get_file_transfer_progress(const std::string& transfer_id) const;
|
|
1234
|
-
|
|
1235
|
-
/**
|
|
1236
|
-
* Get all active file transfers
|
|
1237
|
-
* @return Vector of transfer progress objects
|
|
1238
|
-
*/
|
|
1226
|
+
|
|
1227
|
+
/** Get progress snapshots for all non-finished transfers. */
|
|
1239
1228
|
std::vector<std::shared_ptr<FileTransferProgress>> get_active_file_transfers() const;
|
|
1240
|
-
|
|
1241
|
-
/**
|
|
1242
|
-
* Get file transfer statistics
|
|
1243
|
-
* @return JSON object with transfer statistics
|
|
1244
|
-
*/
|
|
1229
|
+
|
|
1230
|
+
/** Get aggregate file transfer statistics as JSON. */
|
|
1245
1231
|
nlohmann::json get_file_transfer_statistics() const;
|
|
1246
|
-
|
|
1247
|
-
/**
|
|
1248
|
-
* Set file transfer configuration
|
|
1249
|
-
* @param config Transfer configuration settings
|
|
1250
|
-
*/
|
|
1232
|
+
|
|
1233
|
+
/** Replace the file transfer configuration. */
|
|
1251
1234
|
void set_file_transfer_config(const FileTransferConfig& config);
|
|
1252
|
-
|
|
1253
|
-
/**
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
* @param callback Function to call with progress updates
|
|
1263
|
-
*/
|
|
1264
|
-
void on_file_transfer_progress(FileTransferProgressCallback callback);
|
|
1265
|
-
|
|
1266
|
-
/**
|
|
1267
|
-
* Set file transfer completion callback
|
|
1268
|
-
* @param callback Function to call when transfers complete
|
|
1269
|
-
*/
|
|
1270
|
-
void on_file_transfer_completed(FileTransferCompletedCallback callback);
|
|
1271
|
-
|
|
1272
|
-
/**
|
|
1273
|
-
* Set incoming file transfer request callback
|
|
1274
|
-
* @param callback Function to call when receiving transfer requests
|
|
1275
|
-
*/
|
|
1276
|
-
void on_file_transfer_request(FileTransferRequestCallback callback);
|
|
1277
|
-
|
|
1278
|
-
/**
|
|
1279
|
-
* Set directory transfer progress callback
|
|
1280
|
-
* @param callback Function to call with directory transfer progress
|
|
1281
|
-
*/
|
|
1282
|
-
void on_directory_transfer_progress(DirectoryTransferProgressCallback callback);
|
|
1283
|
-
|
|
1284
|
-
/**
|
|
1285
|
-
* Set file request callback (called when receiving file requests)
|
|
1286
|
-
* @param callback Function to call when receiving file requests
|
|
1287
|
-
*/
|
|
1288
|
-
void on_file_request(FileRequestCallback callback);
|
|
1289
|
-
|
|
1235
|
+
|
|
1236
|
+
/** Get the current file transfer configuration. */
|
|
1237
|
+
FileTransferConfig get_file_transfer_config() const;
|
|
1238
|
+
|
|
1239
|
+
/** Set the progress callback (fires for both directions). */
|
|
1240
|
+
void on_file_transfer_progress(TransferProgressCallback callback);
|
|
1241
|
+
|
|
1242
|
+
/** Set the completion callback (fires once per transfer). */
|
|
1243
|
+
void on_file_transfer_completed(TransferCompletedCallback callback);
|
|
1244
|
+
|
|
1290
1245
|
/**
|
|
1291
|
-
* Set
|
|
1292
|
-
*
|
|
1246
|
+
* Set the incoming-offer callback. The handler should call
|
|
1247
|
+
* accept_file_transfer()/reject_file_transfer(). Without it, offers are
|
|
1248
|
+
* auto-rejected.
|
|
1293
1249
|
*/
|
|
1294
|
-
void
|
|
1250
|
+
void on_file_transfer_request(TransferOfferCallback callback);
|
|
1295
1251
|
|
|
1296
1252
|
// =========================================================================
|
|
1297
1253
|
// ICE (NAT Traversal) API
|
|
@@ -1463,7 +1419,7 @@ public:
|
|
|
1463
1419
|
* Get current ICE configuration
|
|
1464
1420
|
* @return Current ICE configuration
|
|
1465
1421
|
*/
|
|
1466
|
-
|
|
1422
|
+
IceConfig get_ice_config() const;
|
|
1467
1423
|
|
|
1468
1424
|
// ICE Lifecycle
|
|
1469
1425
|
/**
|
|
@@ -1959,7 +1915,7 @@ private:
|
|
|
1959
1915
|
// 3. encryption_mutex_ (Encryption settings and keys)
|
|
1960
1916
|
// 4. local_addresses_mutex_ (Local interface addresses)
|
|
1961
1917
|
// 5. peers_mutex_ (Peer management - most frequently locked)
|
|
1962
|
-
// 6.
|
|
1918
|
+
// 6. io_mutex_ (I/O poller and send buffer access)
|
|
1963
1919
|
// 7. message_handlers_mutex_ (Message handler registration)
|
|
1964
1920
|
// 8. reconnect_mutex_ (Reconnection queue management)
|
|
1965
1921
|
// =========================================================================
|
|
@@ -1985,20 +1941,19 @@ private:
|
|
|
1985
1941
|
|
|
1986
1942
|
// [4] Local interface address blocking (protected by local_addresses_mutex_)
|
|
1987
1943
|
mutable std::mutex local_addresses_mutex_; // [4] Protects local interface addresses
|
|
1988
|
-
std::
|
|
1944
|
+
std::unordered_set<std::string> local_interface_addresses_;
|
|
1989
1945
|
|
|
1990
1946
|
// [5] Organized peer management using RatsPeer struct (protected by peers_mutex_)
|
|
1991
1947
|
mutable std::mutex peers_mutex_; // [5] Protects peer data (most frequently locked)
|
|
1992
1948
|
std::unordered_map<std::string, RatsPeer> peers_; // keyed by peer_id
|
|
1993
1949
|
std::unordered_map<socket_t, std::string> socket_to_peer_id_; // for quick socket->peer_id lookup
|
|
1994
1950
|
std::unordered_map<std::string, std::string> address_to_peer_id_; // for duplicate detection (normalized_address->peer_id)
|
|
1951
|
+
std::atomic<int> validated_peer_count_{0}; // Cached count of peers with COMPLETED handshake
|
|
1995
1952
|
|
|
1996
|
-
// [6]
|
|
1997
|
-
|
|
1998
|
-
std::
|
|
1999
|
-
|
|
2000
|
-
// Server and client management
|
|
2001
|
-
std::thread server_thread_;
|
|
1953
|
+
// [6] Async I/O (poller + io thread)
|
|
1954
|
+
std::unique_ptr<IOPoller> poller_;
|
|
1955
|
+
std::mutex io_mutex_; // Protects poller_ and send-buffer writes from non-IO threads
|
|
1956
|
+
std::thread io_thread_;
|
|
2002
1957
|
std::thread management_thread_;
|
|
2003
1958
|
|
|
2004
1959
|
ConnectionCallback connection_callback_;
|
|
@@ -2007,9 +1962,13 @@ private:
|
|
|
2007
1962
|
JsonDataCallback json_data_callback_;
|
|
2008
1963
|
DisconnectCallback disconnect_callback_;
|
|
2009
1964
|
|
|
2010
|
-
// DHT
|
|
1965
|
+
// DHT clients for peer discovery. IPv4 and IPv6 are separate Kademlia networks
|
|
1966
|
+
// (BEP 32), so each family runs its own client. dht_client_ (IPv4) is also the one
|
|
1967
|
+
// shared with the BitTorrent subsystem; dht_client_v6_ is created best-effort when
|
|
1968
|
+
// IPv6 is available.
|
|
2011
1969
|
std::unique_ptr<DhtClient> dht_client_;
|
|
2012
|
-
|
|
1970
|
+
std::unique_ptr<DhtClient> dht_client_v6_;
|
|
1971
|
+
|
|
2013
1972
|
// mDNS client for local network discovery
|
|
2014
1973
|
std::unique_ptr<MdnsClient> mdns_client_;
|
|
2015
1974
|
std::function<void(const std::string&, int, const std::string&)> mdns_callback_;
|
|
@@ -2036,11 +1995,31 @@ private:
|
|
|
2036
1995
|
void initialize_modules();
|
|
2037
1996
|
void destroy_modules();
|
|
2038
1997
|
|
|
2039
|
-
|
|
1998
|
+
// Async I/O loop (single thread for all sockets)
|
|
1999
|
+
void io_loop();
|
|
2040
2000
|
void management_loop();
|
|
2041
|
-
|
|
2001
|
+
|
|
2002
|
+
// I/O event handlers (called from io_loop)
|
|
2003
|
+
void accept_incoming();
|
|
2004
|
+
bool handle_readable(socket_t socket);
|
|
2005
|
+
bool handle_writable(socket_t socket);
|
|
2006
|
+
void handle_disconnect(socket_t socket);
|
|
2007
|
+
|
|
2008
|
+
// Poller registration helpers
|
|
2009
|
+
void poller_add(socket_t fd, uint32_t events);
|
|
2010
|
+
void poller_modify(socket_t fd, uint32_t events);
|
|
2011
|
+
void poller_remove(socket_t fd);
|
|
2012
|
+
|
|
2013
|
+
// Helpers – post-handshake and message routing
|
|
2014
|
+
void handle_post_handshake_completion(socket_t socket, const RatsPeer& peer_copy);
|
|
2015
|
+
void process_message(socket_t socket, const std::vector<uint8_t>& data, const std::string& peer_id);
|
|
2016
|
+
|
|
2017
|
+
// Peer lookup helper (assumes peers_mutex_ is already locked)
|
|
2018
|
+
std::unordered_map<std::string, RatsPeer>::iterator find_peer_by_socket_unlocked(socket_t socket);
|
|
2019
|
+
std::unordered_map<std::string, RatsPeer>::const_iterator find_peer_by_socket_unlocked(socket_t socket) const;
|
|
2020
|
+
|
|
2042
2021
|
void remove_peer(socket_t socket);
|
|
2043
|
-
std::string
|
|
2022
|
+
std::string generate_temporary_peer_id(socket_t socket, const std::string& connection_info);
|
|
2044
2023
|
void handle_dht_peer_discovery(const std::vector<Peer>& peers, const InfoHash& info_hash);
|
|
2045
2024
|
void handle_mdns_service_discovery(const MdnsService& service, bool is_new);
|
|
2046
2025
|
|
|
@@ -2049,31 +2028,62 @@ private:
|
|
|
2049
2028
|
bool parse_message_with_header(const std::vector<uint8_t>& message, MessageHeader& header, std::vector<uint8_t>& payload) const;
|
|
2050
2029
|
|
|
2051
2030
|
// Peer management methods using RatsPeer
|
|
2052
|
-
void add_peer(const RatsPeer& peer);
|
|
2053
2031
|
void add_peer_unlocked(const RatsPeer& peer); // Assumes peers_mutex_ is already locked
|
|
2054
|
-
void remove_peer_by_id(const std::string& peer_id);
|
|
2055
2032
|
void remove_peer_by_id_unlocked(const std::string& peer_id); // Assumes peers_mutex_ is already locked
|
|
2033
|
+
void mark_manual_disconnect(const std::string& peer_id);
|
|
2034
|
+
static std::vector<uint8_t> json_to_binary(const nlohmann::json& data);
|
|
2056
2035
|
bool is_already_connected_to_address(const std::string& normalized_address) const;
|
|
2057
2036
|
std::string normalize_peer_address(const std::string& ip, int port) const;
|
|
2058
2037
|
|
|
2059
|
-
//
|
|
2038
|
+
// Async send – enqueues a framed (length-prefixed) message into the peer's
|
|
2039
|
+
// ChainedSendBuffer and arms PollOut. Thread-safe (acquires io_mutex_).
|
|
2040
|
+
// Returns false if the peer was not found.
|
|
2041
|
+
bool enqueue_message(socket_t socket, const std::vector<uint8_t>& data);
|
|
2042
|
+
// Unlocked variant – caller must hold peers_mutex_
|
|
2043
|
+
bool enqueue_message_unlocked(RatsPeer& peer, const std::vector<uint8_t>& data);
|
|
2044
|
+
|
|
2045
|
+
// Lightweight snapshot of peer data needed for sending (avoids holding peers_mutex_ during enqueue)
|
|
2046
|
+
struct PeerSendTarget {
|
|
2047
|
+
socket_t socket;
|
|
2048
|
+
std::string peer_id;
|
|
2049
|
+
std::shared_ptr<rats::NoiseCipherState> send_cipher;
|
|
2050
|
+
};
|
|
2051
|
+
|
|
2060
2052
|
bool send_binary_to_peer_unlocked(socket_t socket, const std::vector<uint8_t>& data,
|
|
2061
2053
|
MessageDataType message_type,
|
|
2062
|
-
rats::NoiseCipherState
|
|
2054
|
+
std::shared_ptr<rats::NoiseCipherState> send_cipher,
|
|
2063
2055
|
const std::string& peer_id_for_logging);
|
|
2056
|
+
|
|
2057
|
+
// Async Noise handshake – processes one Noise XX message received from peer.
|
|
2058
|
+
// Returns false if peer should be disconnected. Called from handle_readable.
|
|
2059
|
+
bool handle_noise_frame(RatsPeer& peer);
|
|
2060
|
+
// Kick-off: initialises noise_hs and writes first outgoing message if initiator.
|
|
2061
|
+
void start_noise_handshake_async(RatsPeer& peer);
|
|
2064
2062
|
|
|
2065
2063
|
// Local interface address blocking helper functions
|
|
2066
2064
|
void initialize_local_addresses();
|
|
2067
2065
|
bool is_blocked_address(const std::string& ip_address) const;
|
|
2068
2066
|
bool should_ignore_peer(const std::string& ip, int port) const;
|
|
2067
|
+
bool can_connect_to_peer(const std::string& ip, int port) const;
|
|
2069
2068
|
static bool parse_address_string(const std::string& address_str, std::string& out_ip, int& out_port);
|
|
2070
2069
|
|
|
2071
2070
|
// Helper functions that assume mutex is already locked
|
|
2072
2071
|
int get_peer_count_unlocked() const; // Helper that assumes peers_mutex_ is already locked
|
|
2073
2072
|
|
|
2074
|
-
//
|
|
2073
|
+
// Protocol constants
|
|
2075
2074
|
static constexpr const char* RATS_PROTOCOL_VERSION = "1.0";
|
|
2076
2075
|
static constexpr int HANDSHAKE_TIMEOUT_SECONDS = 10;
|
|
2076
|
+
static constexpr int TCP_CONNECT_TIMEOUT_MS = 10000; // 10 second TCP connection timeout
|
|
2077
|
+
static constexpr int IO_POLL_TIMEOUT_MS = 100; // IO poller tick interval (ms)
|
|
2078
|
+
static constexpr size_t MAX_FRAME_SIZE = 100 * 1024 * 1024; // 100 MB max single frame
|
|
2079
|
+
static constexpr int PEER_RECONNECT_DELAY_MS = 100; // Delay before reconnecting saved peers
|
|
2080
|
+
static constexpr int HISTORICAL_RECONNECT_DELAY_MS = 500; // Delay before reconnecting historical peers
|
|
2081
|
+
static constexpr int MANAGEMENT_LOOP_INTERVAL_SECONDS = 2; // Management loop tick interval
|
|
2082
|
+
static constexpr int THREAD_CLEANUP_INTERVAL_SECONDS = 30; // Thread cleanup interval
|
|
2083
|
+
static constexpr int INITIAL_DISCOVERY_DELAY_SECONDS = 5; // DHT bootstrap delay
|
|
2084
|
+
static constexpr int MAX_PEERS_REQUEST_COUNT = 5; // Max peers to request/respond
|
|
2085
|
+
static constexpr int CONTENT_HASH_HEX_LENGTH = 40; // 160-bit hash as hex
|
|
2086
|
+
static constexpr int64_t TIMESTAMP_SKEW_TOLERANCE_MS = 10LL * 60LL * 1000LL; // 10 minutes
|
|
2077
2087
|
|
|
2078
2088
|
struct HandshakeMessage {
|
|
2079
2089
|
std::string protocol;
|
|
@@ -2089,9 +2099,8 @@ private:
|
|
|
2089
2099
|
bool parse_handshake_message(const std::vector<uint8_t>& data, HandshakeMessage& out_msg) const;
|
|
2090
2100
|
bool validate_handshake_message(const HandshakeMessage& msg) const;
|
|
2091
2101
|
bool is_handshake_message(const std::vector<uint8_t>& data) const;
|
|
2092
|
-
bool
|
|
2093
|
-
bool
|
|
2094
|
-
bool handle_handshake_message(socket_t socket, const std::string& peer_hash_id, const std::vector<uint8_t>& data);
|
|
2102
|
+
bool send_handshake_unlocked(RatsPeer& peer, const std::string& our_peer_id); // enqueues via send buffer (peers_mutex_ held)
|
|
2103
|
+
bool handle_handshake_message(socket_t socket, const std::string& initial_peer_id, const std::vector<uint8_t>& data);
|
|
2095
2104
|
void check_handshake_timeouts();
|
|
2096
2105
|
void log_handshake_completion_unlocked(const RatsPeer& peer);
|
|
2097
2106
|
|
|
@@ -2103,12 +2112,12 @@ private:
|
|
|
2103
2112
|
|
|
2104
2113
|
// Message handling system
|
|
2105
2114
|
nlohmann::json create_rats_message(const std::string& type, const nlohmann::json& payload, const std::string& sender_peer_id);
|
|
2106
|
-
void handle_rats_message(socket_t socket, const std::string&
|
|
2115
|
+
void handle_rats_message(socket_t socket, const std::string& peer_id, const nlohmann::json& message);
|
|
2107
2116
|
|
|
2108
2117
|
// Specific message handlers
|
|
2109
|
-
void handle_peer_exchange_message(socket_t socket, const std::string&
|
|
2110
|
-
void handle_peers_request_message(socket_t socket, const std::string&
|
|
2111
|
-
void handle_peers_response_message(socket_t socket, const std::string&
|
|
2118
|
+
void handle_peer_exchange_message(socket_t socket, const std::string& peer_id, const nlohmann::json& payload);
|
|
2119
|
+
void handle_peers_request_message(socket_t socket, const std::string& peer_id, const nlohmann::json& payload);
|
|
2120
|
+
void handle_peers_response_message(socket_t socket, const std::string& peer_id, const nlohmann::json& payload);
|
|
2112
2121
|
|
|
2113
2122
|
// Message creation and broadcasting
|
|
2114
2123
|
nlohmann::json create_peer_exchange_message(const RatsPeer& peer);
|
|
@@ -2118,8 +2127,7 @@ private:
|
|
|
2118
2127
|
std::vector<RatsPeer> get_random_peers(int max_count, const std::string& exclude_peer_id = "") const;
|
|
2119
2128
|
void send_peers_request(socket_t socket, const std::string& our_peer_id);
|
|
2120
2129
|
|
|
2121
|
-
int broadcast_rats_message(const nlohmann::json& message, const std::string& exclude_peer_id = "");
|
|
2122
|
-
int broadcast_rats_message_to_validated_peers(const nlohmann::json& message, const std::string& exclude_peer_id = "");
|
|
2130
|
+
int broadcast_rats_message(const nlohmann::json& message, const std::string& exclude_peer_id = "", bool validated_only = true);
|
|
2123
2131
|
|
|
2124
2132
|
// [7] Message exchange API implementation (protected by message_handlers_mutex_)
|
|
2125
2133
|
mutable std::mutex message_handlers_mutex_; // [7] Protects message handlers
|
|
@@ -2145,10 +2153,6 @@ private:
|
|
|
2145
2153
|
void remove_from_reconnect_queue(const std::string& peer_id);
|
|
2146
2154
|
int get_retry_interval_seconds(int attempt, bool is_stable) const;
|
|
2147
2155
|
|
|
2148
|
-
// Per-socket synchronization helpers
|
|
2149
|
-
std::shared_ptr<std::mutex> get_socket_send_mutex(socket_t socket);
|
|
2150
|
-
void cleanup_socket_send_mutex(socket_t socket);
|
|
2151
|
-
|
|
2152
2156
|
// Configuration persistence helpers
|
|
2153
2157
|
std::string generate_persistent_peer_id() const;
|
|
2154
2158
|
nlohmann::json serialize_peer_for_persistence(const RatsPeer& peer) const;
|
|
@@ -2162,11 +2166,6 @@ private:
|
|
|
2162
2166
|
|
|
2163
2167
|
// Noise Protocol encryption helpers
|
|
2164
2168
|
void initialize_noise_keypair();
|
|
2165
|
-
bool perform_noise_handshake(socket_t socket, const std::string& peer_id, bool is_initiator);
|
|
2166
|
-
bool send_noise_message(socket_t socket, const uint8_t* data, size_t len);
|
|
2167
|
-
bool recv_noise_message(socket_t socket, std::vector<uint8_t>& out_data, int timeout_ms = 10000);
|
|
2168
|
-
bool encrypt_and_send(socket_t socket, const std::string& peer_id, const std::vector<uint8_t>& plaintext);
|
|
2169
|
-
bool receive_and_decrypt(socket_t socket, const std::string& peer_id, std::vector<uint8_t>& plaintext);
|
|
2170
2169
|
};
|
|
2171
2170
|
|
|
2172
2171
|
// 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
|
|