librats 0.5.0 → 0.5.2

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.
Files changed (66) hide show
  1. package/README.md +1 -1
  2. package/binding.gyp +1 -0
  3. package/lib/index.d.ts +2 -1
  4. package/native-src/3rdparty/android/ifaddrs-android.c +600 -0
  5. package/native-src/3rdparty/android/ifaddrs-android.h +54 -0
  6. package/native-src/CMakeLists.txt +360 -0
  7. package/native-src/LICENSE +21 -0
  8. package/native-src/src/bencode.cpp +485 -0
  9. package/native-src/src/bencode.h +145 -0
  10. package/native-src/src/bittorrent.cpp +3682 -0
  11. package/native-src/src/bittorrent.h +731 -0
  12. package/native-src/src/dht.cpp +2460 -0
  13. package/native-src/src/dht.h +508 -0
  14. package/native-src/src/encrypted_socket.cpp +817 -0
  15. package/native-src/src/encrypted_socket.h +239 -0
  16. package/native-src/src/file_transfer.cpp +1808 -0
  17. package/native-src/src/file_transfer.h +567 -0
  18. package/native-src/src/fs.cpp +639 -0
  19. package/native-src/src/fs.h +108 -0
  20. package/native-src/src/gossipsub.cpp +1137 -0
  21. package/native-src/src/gossipsub.h +403 -0
  22. package/native-src/src/ice.cpp +1386 -0
  23. package/native-src/src/ice.h +328 -0
  24. package/native-src/src/json.hpp +25526 -0
  25. package/native-src/src/krpc.cpp +558 -0
  26. package/native-src/src/krpc.h +145 -0
  27. package/native-src/src/librats.cpp +2735 -0
  28. package/native-src/src/librats.h +1732 -0
  29. package/native-src/src/librats_bittorrent.cpp +167 -0
  30. package/native-src/src/librats_c.cpp +1333 -0
  31. package/native-src/src/librats_c.h +239 -0
  32. package/native-src/src/librats_encryption.cpp +123 -0
  33. package/native-src/src/librats_file_transfer.cpp +226 -0
  34. package/native-src/src/librats_gossipsub.cpp +293 -0
  35. package/native-src/src/librats_ice.cpp +515 -0
  36. package/native-src/src/librats_logging.cpp +158 -0
  37. package/native-src/src/librats_mdns.cpp +171 -0
  38. package/native-src/src/librats_nat.cpp +571 -0
  39. package/native-src/src/librats_persistence.cpp +815 -0
  40. package/native-src/src/logger.h +412 -0
  41. package/native-src/src/mdns.cpp +1178 -0
  42. package/native-src/src/mdns.h +253 -0
  43. package/native-src/src/network_utils.cpp +598 -0
  44. package/native-src/src/network_utils.h +162 -0
  45. package/native-src/src/noise.cpp +981 -0
  46. package/native-src/src/noise.h +227 -0
  47. package/native-src/src/os.cpp +371 -0
  48. package/native-src/src/os.h +40 -0
  49. package/native-src/src/rats_export.h +17 -0
  50. package/native-src/src/sha1.cpp +163 -0
  51. package/native-src/src/sha1.h +42 -0
  52. package/native-src/src/socket.cpp +1376 -0
  53. package/native-src/src/socket.h +309 -0
  54. package/native-src/src/stun.cpp +484 -0
  55. package/native-src/src/stun.h +349 -0
  56. package/native-src/src/threadmanager.cpp +105 -0
  57. package/native-src/src/threadmanager.h +53 -0
  58. package/native-src/src/tracker.cpp +1110 -0
  59. package/native-src/src/tracker.h +268 -0
  60. package/native-src/src/version.cpp +24 -0
  61. package/native-src/src/version.h.in +45 -0
  62. package/native-src/version.rc.in +31 -0
  63. package/package.json +2 -8
  64. package/scripts/build-librats.js +59 -12
  65. package/scripts/prepare-package.js +133 -37
  66. package/src/librats_node.cpp +46 -1
@@ -0,0 +1,1732 @@
1
+ #pragma once
2
+
3
+ #include "socket.h"
4
+ #include "dht.h"
5
+ #include "stun.h"
6
+ #include "mdns.h"
7
+ #include "ice.h"
8
+ #include "logger.h"
9
+ #include "encrypted_socket.h"
10
+ #include "threadmanager.h"
11
+ #include "gossipsub.h" // For ValidationResult enum and GossipSub types
12
+ #include "file_transfer.h" // File transfer functionality
13
+ #ifdef RATS_SEARCH_FEATURES
14
+ #include "bittorrent.h" // BitTorrent functionality (optional, requires RATS_SEARCH_FEATURES)
15
+ #endif
16
+ #include "json.hpp" // nlohmann::json
17
+ #include <string>
18
+ #include <functional>
19
+ #include <thread>
20
+ #include <vector>
21
+ #include <mutex>
22
+ #include <atomic>
23
+ #include <unordered_map>
24
+ #include <memory>
25
+ #include <chrono>
26
+ #include <condition_variable>
27
+ #include <unordered_set> // Added for unordered_set
28
+ #include <cstdint>
29
+ #include <cstring>
30
+ #include "rats_export.h"
31
+
32
+ namespace librats {
33
+
34
+ // Forward declarations
35
+ class IceAgent;
36
+
37
+ /**
38
+ * RatsPeer struct - comprehensive information about a connected rats peer
39
+ */
40
+ struct RatsPeer {
41
+ std::string peer_id; // Unique hash ID for the peer
42
+ std::string ip; // IP address
43
+ uint16_t port; // Port number
44
+ socket_t socket; // Socket handle
45
+ std::string normalized_address; // Normalized address for duplicate detection (ip:port)
46
+ std::chrono::steady_clock::time_point connected_at; // Connection timestamp
47
+ bool is_outgoing; // True if we initiated the connection, false if incoming
48
+
49
+ // Handshake-related fields
50
+ enum class HandshakeState {
51
+ PENDING, // Handshake not started
52
+ SENT, // Handshake sent, waiting for response
53
+ COMPLETED, // Handshake completed successfully
54
+ FAILED // Handshake failed
55
+ };
56
+
57
+ HandshakeState handshake_state; // Current handshake state
58
+ std::string version; // Protocol version of remote peer
59
+ int peer_count; // Number of peers connected to remote peer
60
+ std::chrono::steady_clock::time_point handshake_start_time; // When handshake started
61
+
62
+ // Encryption-related fields
63
+ bool encryption_enabled; // Whether encryption is enabled for this peer
64
+ bool noise_handshake_completed; // Whether noise handshake is completed
65
+ NoiseKey remote_static_key; // Remote peer's static public key (after handshake)
66
+
67
+ // NAT traversal fields
68
+ bool ice_enabled; // Whether ICE is enabled for this peer
69
+ std::string ice_ufrag; // ICE username fragment
70
+ std::string ice_pwd; // ICE password
71
+ std::vector<IceCandidate> ice_candidates; // ICE candidates for this peer
72
+ IceConnectionState ice_state; // Current ICE connection state
73
+ NatType detected_nat_type; // Detected NAT type for this peer
74
+ std::string connection_method; // How connection was established (direct, stun, turn, ice)
75
+
76
+ // Connection quality metrics
77
+ uint32_t rtt_ms; // Round-trip time in milliseconds
78
+ uint32_t packet_loss_percent; // Packet loss percentage
79
+ std::string transport_protocol; // UDP, TCP, etc.
80
+
81
+ RatsPeer() : handshake_state(HandshakeState::PENDING),
82
+ peer_count(0), encryption_enabled(false), noise_handshake_completed(false),
83
+ ice_enabled(false), ice_state(IceConnectionState::NEW),
84
+ detected_nat_type(NatType::UNKNOWN), rtt_ms(0), packet_loss_percent(0),
85
+ transport_protocol("UDP") {
86
+ connected_at = std::chrono::steady_clock::now();
87
+ handshake_start_time = connected_at;
88
+ }
89
+
90
+ RatsPeer(const std::string& id, const std::string& peer_ip, uint16_t peer_port,
91
+ socket_t sock, const std::string& norm_addr, bool outgoing)
92
+ : peer_id(id), ip(peer_ip), port(peer_port), socket(sock),
93
+ normalized_address(norm_addr), is_outgoing(outgoing),
94
+ handshake_state(HandshakeState::PENDING), peer_count(0),
95
+ encryption_enabled(false), noise_handshake_completed(false),
96
+ ice_enabled(false), ice_state(IceConnectionState::NEW),
97
+ detected_nat_type(NatType::UNKNOWN), rtt_ms(0), packet_loss_percent(0),
98
+ transport_protocol("UDP") {
99
+ connected_at = std::chrono::steady_clock::now();
100
+ handshake_start_time = connected_at;
101
+ }
102
+
103
+ // Helper methods
104
+ bool is_handshake_completed() const { return handshake_state == HandshakeState::COMPLETED; }
105
+ bool is_handshake_failed() const { return handshake_state == HandshakeState::FAILED; }
106
+ bool is_ice_connected() const {
107
+ return ice_state == IceConnectionState::CONNECTED ||
108
+ ice_state == IceConnectionState::COMPLETED;
109
+ }
110
+ bool is_fully_connected() const {
111
+ return is_handshake_completed() && (!ice_enabled || is_ice_connected());
112
+ }
113
+ };
114
+
115
+ // NAT Traversal Configuration
116
+ struct NatTraversalConfig {
117
+ bool enable_ice; // Enable ICE for NAT traversal
118
+ bool enable_upnp; // Enable UPnP for port mapping
119
+ bool enable_hole_punching; // Enable UDP/TCP hole punching
120
+ bool enable_turn_relay; // Enable TURN relay as last resort
121
+ bool prefer_ipv6; // Prefer IPv6 connections when available
122
+
123
+ // ICE configuration
124
+ std::vector<std::string> stun_servers;
125
+ std::vector<std::string> turn_servers;
126
+ std::vector<std::string> turn_usernames;
127
+ std::vector<std::string> turn_passwords;
128
+
129
+ // Timeouts and limits
130
+ int ice_gathering_timeout_ms;
131
+ int ice_connectivity_timeout_ms;
132
+ int hole_punch_attempts;
133
+ int turn_allocation_timeout_ms;
134
+
135
+ // Priority settings
136
+ int host_candidate_priority;
137
+ int server_reflexive_priority;
138
+ int relay_candidate_priority;
139
+
140
+ NatTraversalConfig()
141
+ : enable_ice(true), enable_upnp(false), enable_hole_punching(true),
142
+ enable_turn_relay(true), prefer_ipv6(false),
143
+ ice_gathering_timeout_ms(10000), ice_connectivity_timeout_ms(30000),
144
+ hole_punch_attempts(5), turn_allocation_timeout_ms(10000),
145
+ host_candidate_priority(65535), server_reflexive_priority(65534),
146
+ relay_candidate_priority(65533) {
147
+
148
+ // Default STUN servers
149
+ stun_servers.push_back("stun.l.google.com:19302");
150
+ stun_servers.push_back("stun1.l.google.com:19302");
151
+ stun_servers.push_back("stun.stunprotocol.org:3478");
152
+ }
153
+ };
154
+
155
+ // Connection establishment strategies
156
+ enum class ConnectionStrategy {
157
+ DIRECT_ONLY, // Try direct connection only
158
+ STUN_ASSISTED, // Use STUN for public IP discovery
159
+ ICE_FULL, // Full ICE with candidate gathering
160
+ TURN_RELAY, // Force TURN relay usage
161
+ AUTO_ADAPTIVE // Automatically choose best strategy
162
+ };
163
+
164
+ // Connection attempt result
165
+ struct ConnectionAttemptResult {
166
+ bool success;
167
+ std::string method; // "direct", "stun", "ice", "turn", "hole_punch"
168
+ std::chrono::milliseconds duration;
169
+ std::string error_message;
170
+ NatType local_nat_type;
171
+ NatType remote_nat_type;
172
+ std::vector<IceCandidate> used_candidates;
173
+ };
174
+
175
+ // Enhanced connection callbacks
176
+ using AdvancedConnectionCallback = std::function<void(socket_t, const std::string&, const ConnectionAttemptResult&)>;
177
+ using NatTraversalProgressCallback = std::function<void(const std::string&, const std::string&)>; // peer_id, status
178
+ using IceCandidateDiscoveredCallback = std::function<void(const std::string&, const IceCandidate&)>; // peer_id, candidate
179
+
180
+ /**
181
+ * Message data types for librats message headers
182
+ */
183
+ enum class MessageDataType : uint8_t {
184
+ BINARY = 0x01, // Raw binary data
185
+ STRING = 0x02, // UTF-8 string data
186
+ JSON = 0x03 // JSON formatted data
187
+ };
188
+
189
+ /**
190
+ * Message header structure for librats messages
191
+ * Fixed 8-byte header format:
192
+ * [0-3]: Magic number "RATS" (4 bytes)
193
+ * [4]: Message data type (1 byte)
194
+ * [5-7]: Reserved for future use (3 bytes)
195
+ */
196
+ struct MessageHeader {
197
+ static constexpr uint32_t MAGIC_NUMBER = 0x52415453; // "RATS" in ASCII
198
+ static constexpr size_t HEADER_SIZE = 8;
199
+
200
+ uint32_t magic; // Magic number for validation
201
+ MessageDataType type; // Message data type
202
+ uint8_t reserved[3]; // Reserved bytes for future use
203
+
204
+ MessageHeader(MessageDataType data_type) : magic(MAGIC_NUMBER), type(data_type) {
205
+ reserved[0] = reserved[1] = reserved[2] = 0;
206
+ }
207
+
208
+ MessageHeader() : magic(MAGIC_NUMBER), type(MessageDataType::BINARY) {
209
+ reserved[0] = reserved[1] = reserved[2] = 0;
210
+ }
211
+
212
+ // Serialize header to bytes
213
+ std::vector<uint8_t> serialize() const {
214
+ std::vector<uint8_t> data(HEADER_SIZE);
215
+ uint32_t network_magic = htonl(magic);
216
+ memcpy(data.data(), &network_magic, 4);
217
+ data[4] = static_cast<uint8_t>(type);
218
+ data[5] = reserved[0];
219
+ data[6] = reserved[1];
220
+ data[7] = reserved[2];
221
+ return data;
222
+ }
223
+
224
+ // Deserialize header from bytes
225
+ static bool deserialize(const std::vector<uint8_t>& data, MessageHeader& header) {
226
+ if (data.size() < HEADER_SIZE) {
227
+ return false;
228
+ }
229
+
230
+ uint32_t network_magic;
231
+ memcpy(&network_magic, data.data(), 4);
232
+ header.magic = ntohl(network_magic);
233
+
234
+ if (header.magic != MAGIC_NUMBER) {
235
+ return false;
236
+ }
237
+
238
+ header.type = static_cast<MessageDataType>(data[4]);
239
+ header.reserved[0] = data[5];
240
+ header.reserved[1] = data[6];
241
+ header.reserved[2] = data[7];
242
+
243
+ return true;
244
+ }
245
+
246
+ // Validate data type
247
+ bool is_valid_type() const {
248
+ return type == MessageDataType::BINARY ||
249
+ type == MessageDataType::STRING ||
250
+ type == MessageDataType::JSON;
251
+ }
252
+ };
253
+
254
+ /**
255
+ * Enhanced RatsClient with comprehensive NAT traversal capabilities
256
+ */
257
+ class RATS_API RatsClient : public ThreadManager {
258
+ public:
259
+ // =========================================================================
260
+ // Type Definitions and Callbacks
261
+ // =========================================================================
262
+ using ConnectionCallback = std::function<void(socket_t, const std::string&)>;
263
+ using BinaryDataCallback = std::function<void(socket_t, const std::string&, const std::vector<uint8_t>&)>;
264
+ using StringDataCallback = std::function<void(socket_t, const std::string&, const std::string&)>;
265
+ using JsonDataCallback = std::function<void(socket_t, const std::string&, const nlohmann::json&)>;
266
+ using DisconnectCallback = std::function<void(socket_t, const std::string&)>;
267
+ using MessageCallback = std::function<void(const std::string&, const nlohmann::json&)>;
268
+ using SendCallback = std::function<void(bool, const std::string&)>;
269
+
270
+ // =========================================================================
271
+ // Constructor and Destructor
272
+ // =========================================================================
273
+
274
+ /**
275
+ * Constructor
276
+ * @param listen_port Port to listen on for incoming connections
277
+ * @param max_peers Maximum number of concurrent peers (default: 10)
278
+ * @param nat_config NAT traversal configuration
279
+ * @param bind_address Interface IP address to bind to (empty for all interfaces)
280
+ */
281
+ RatsClient(int listen_port, int max_peers = 10, const NatTraversalConfig& nat_config = NatTraversalConfig(), const std::string& bind_address = "");
282
+
283
+ /**
284
+ * Destructor
285
+ */
286
+ ~RatsClient();
287
+
288
+ // =========================================================================
289
+ // Core Lifecycle Management
290
+ // =========================================================================
291
+
292
+ /**
293
+ * Start the RatsClient and begin listening for connections
294
+ * @return true if successful, false otherwise
295
+ */
296
+ bool start();
297
+
298
+ /**
299
+ * Stop the RatsClient and close all connections
300
+ */
301
+ void stop();
302
+
303
+ /**
304
+ * Shutdown all background threads
305
+ */
306
+ void shutdown_all_threads();
307
+
308
+ /**
309
+ * Check if the client is currently running
310
+ * @return true if running, false otherwise
311
+ */
312
+ bool is_running() const;
313
+
314
+
315
+ // =========================================================================
316
+ // Utility Methods
317
+ // =========================================================================
318
+
319
+ int get_listen_port() const;
320
+
321
+ /**
322
+ * Get the bind address being used
323
+ * @return Bind address (empty string if binding to all interfaces)
324
+ */
325
+ std::string get_bind_address() const;
326
+
327
+ // =========================================================================
328
+ // Connection Management
329
+ // =========================================================================
330
+
331
+ /**
332
+ * Connect to a peer with automatic NAT traversal
333
+ * @param host Target host/IP address
334
+ * @param port Target port
335
+ * @param strategy Connection strategy to use
336
+ * @return true if connection initiated successfully
337
+ */
338
+ bool connect_to_peer(const std::string& host, int port,
339
+ ConnectionStrategy strategy = ConnectionStrategy::AUTO_ADAPTIVE);
340
+
341
+ /**
342
+ * Connect to a peer using ICE coordination
343
+ * @param peer_id Target peer ID
344
+ * @param ice_offer ICE offer from remote peer
345
+ * @return true if ICE connection initiated successfully
346
+ */
347
+ bool connect_with_ice(const std::string& peer_id, const nlohmann::json& ice_offer);
348
+
349
+ /**
350
+ * Create ICE offer for a peer
351
+ * @param peer_id Target peer ID
352
+ * @return ICE offer JSON that can be sent to the peer
353
+ */
354
+ nlohmann::json create_ice_offer(const std::string& peer_id);
355
+
356
+ /**
357
+ * Handle ICE answer from a peer
358
+ * @param peer_id Source peer ID
359
+ * @param ice_answer ICE answer from the peer
360
+ * @return true if successfully processed
361
+ */
362
+ bool handle_ice_answer(const std::string& peer_id, const nlohmann::json& ice_answer);
363
+
364
+ /**
365
+ * Disconnect from a specific peer
366
+ * @param socket Peer socket to disconnect
367
+ */
368
+ void disconnect_peer(socket_t socket);
369
+
370
+ /**
371
+ * Disconnect from a peer by peer_id (preferred)
372
+ * @param peer_id Peer ID to disconnect
373
+ */
374
+ void disconnect_peer_by_id(const std::string& peer_id);
375
+
376
+ // =========================================================================
377
+ // Data Transmission Methods
378
+ // =========================================================================
379
+
380
+ // Send to specific peer by socket
381
+ /**
382
+ * Send binary data to a specific peer (primary method)
383
+ * @param socket Target peer socket
384
+ * @param data Binary data to send
385
+ * @param message_type Type of message data (BINARY, STRING, JSON)
386
+ * @return true if sent successfully
387
+ */
388
+ bool send_binary_to_peer(socket_t socket, const std::vector<uint8_t>& data, MessageDataType message_type = MessageDataType::BINARY);
389
+
390
+ /**
391
+ * Send string data to a specific peer
392
+ * @param socket Target peer socket
393
+ * @param data String data to send
394
+ * @return true if sent successfully
395
+ */
396
+ bool send_string_to_peer(socket_t socket, const std::string& data);
397
+
398
+ /**
399
+ * Send JSON data to a specific peer
400
+ * @param socket Target peer socket
401
+ * @param data JSON data to send
402
+ * @return true if sent successfully
403
+ */
404
+ bool send_json_to_peer(socket_t socket, const nlohmann::json& data);
405
+
406
+ // Send to specific peer by ID
407
+ /**
408
+ * Send binary data to a peer by peer_id (preferred)
409
+ * @param peer_id Target peer ID
410
+ * @param data Binary data to send
411
+ * @param message_type Type of message data (BINARY, STRING, JSON)
412
+ * @return true if sent successfully
413
+ */
414
+ bool send_binary_to_peer_id(const std::string& peer_id, const std::vector<uint8_t>& data, MessageDataType message_type = MessageDataType::BINARY);
415
+
416
+ /**
417
+ * Send string data to a peer by peer_id (preferred)
418
+ * @param peer_id Target peer ID
419
+ * @param data String data to send
420
+ * @return true if sent successfully
421
+ */
422
+ bool send_string_to_peer_id(const std::string& peer_id, const std::string& data);
423
+
424
+ /**
425
+ * Send JSON data to a peer by peer_id (preferred)
426
+ * @param peer_id Target peer ID
427
+ * @param data JSON data to send
428
+ * @return true if sent successfully
429
+ */
430
+ bool send_json_to_peer_id(const std::string& peer_id, const nlohmann::json& data);
431
+
432
+ // Broadcast to all peers
433
+ /**
434
+ * Broadcast binary data to all connected peers (primary method)
435
+ * @param data Binary data to broadcast
436
+ * @param message_type Type of message data (BINARY, STRING, JSON)
437
+ * @return Number of peers the data was sent to
438
+ */
439
+ int broadcast_binary_to_peers(const std::vector<uint8_t>& data, MessageDataType message_type = MessageDataType::BINARY);
440
+
441
+ /**
442
+ * Broadcast string data to all connected peers
443
+ * @param data String data to broadcast
444
+ * @return Number of peers the data was sent to
445
+ */
446
+ int broadcast_string_to_peers(const std::string& data);
447
+
448
+ /**
449
+ * Broadcast JSON data to all connected peers
450
+ * @param data JSON data to broadcast
451
+ * @return Number of peers the data was sent to
452
+ */
453
+ int broadcast_json_to_peers(const nlohmann::json& data);
454
+
455
+ // =========================================================================
456
+ // Peer Information and Management
457
+ // =========================================================================
458
+
459
+ /**
460
+ * Get the number of currently connected peers
461
+ * @return Number of connected peers
462
+ */
463
+ int get_peer_count() const;
464
+
465
+
466
+ /**
467
+ * Get peer_id for a peer by socket (preferred)
468
+ * @param socket Peer socket
469
+ * @return Peer ID or empty string if not found
470
+ */
471
+ std::string get_peer_id(socket_t socket) const;
472
+
473
+ /**
474
+ * Get socket for a peer by peer_id (preferred)
475
+ * @param peer_id Peer ID
476
+ * @return Peer socket or INVALID_SOCKET_VALUE if not found
477
+ */
478
+ socket_t get_peer_socket_by_id(const std::string& peer_id) const;
479
+
480
+ /**
481
+ * Get our own peer ID
482
+ * @return Our persistent peer ID
483
+ */
484
+ std::string get_our_peer_id() const;
485
+
486
+ /**
487
+ * Get all connected peers
488
+ * @return Vector of RatsPeer objects
489
+ */
490
+ std::vector<RatsPeer> get_all_peers() const;
491
+
492
+ /**
493
+ * Get all peers that have completed handshake
494
+ * @return Vector of RatsPeer objects with completed handshake
495
+ */
496
+ std::vector<RatsPeer> get_validated_peers() const;
497
+
498
+ /**
499
+ * Get peer information by peer ID
500
+ * @param peer_id The peer ID to look up
501
+ * @return Pointer to RatsPeer object, or nullptr if not found
502
+ */
503
+ const RatsPeer* get_peer_by_id(const std::string& peer_id) const;
504
+
505
+ /**
506
+ * Get peer information by socket
507
+ * @param socket The socket handle to look up
508
+ * @return Pointer to RatsPeer object, or nullptr if not found
509
+ */
510
+ const RatsPeer* get_peer_by_socket(socket_t socket) const;
511
+
512
+ /**
513
+ * Get maximum number of peers
514
+ * @return Maximum peer count
515
+ */
516
+ int get_max_peers() const;
517
+
518
+ /**
519
+ * Set maximum number of peers
520
+ * @param max_peers New maximum peer count
521
+ */
522
+ void set_max_peers(int max_peers);
523
+
524
+ /**
525
+ * Check if peer limit has been reached
526
+ * @return true if at limit, false otherwise
527
+ */
528
+ bool is_peer_limit_reached() const;
529
+
530
+ // =========================================================================
531
+ // Callback Registration
532
+ // =========================================================================
533
+
534
+ /**
535
+ * Set connection callback (called when a new peer connects)
536
+ * @param callback Function to call on new connections
537
+ */
538
+ void set_connection_callback(ConnectionCallback callback);
539
+
540
+ /**
541
+ * Set advanced connection callback with NAT traversal info
542
+ * @param callback Function to call on new connections with detailed info
543
+ */
544
+ void set_advanced_connection_callback(AdvancedConnectionCallback callback);
545
+
546
+ /**
547
+ * Set binary data callback (called when binary data is received)
548
+ * @param callback Function to call when binary data is received
549
+ */
550
+ void set_binary_data_callback(BinaryDataCallback callback);
551
+
552
+ /**
553
+ * Set string data callback (called when string data is received)
554
+ * @param callback Function to call when string data is received
555
+ */
556
+ void set_string_data_callback(StringDataCallback callback);
557
+
558
+ /**
559
+ * Set JSON data callback (called when JSON data is received)
560
+ * @param callback Function to call when JSON data is received
561
+ */
562
+ void set_json_data_callback(JsonDataCallback callback);
563
+
564
+ /**
565
+ * Set disconnect callback (called when a peer disconnects)
566
+ * @param callback Function to call on disconnections
567
+ */
568
+ void set_disconnect_callback(DisconnectCallback callback);
569
+
570
+ /**
571
+ * Set NAT traversal progress callback
572
+ * @param callback Function to call with NAT traversal progress updates
573
+ */
574
+ void set_nat_traversal_progress_callback(NatTraversalProgressCallback callback);
575
+
576
+ /**
577
+ * Set ICE candidate discovered callback
578
+ * @param callback Function to call when ICE candidates are discovered
579
+ */
580
+ void set_ice_candidate_callback(IceCandidateDiscoveredCallback callback);
581
+
582
+ // =========================================================================
583
+ // Peer Discovery Methods
584
+ // =========================================================================
585
+
586
+ // DHT Discovery
587
+ /**
588
+ * Start DHT discovery on specified port
589
+ * @param dht_port Port for DHT communication (default: 6881)
590
+ * @return true if started successfully
591
+ */
592
+ bool start_dht_discovery(int dht_port = 6881);
593
+
594
+ /**
595
+ * Stop DHT discovery
596
+ */
597
+ void stop_dht_discovery();
598
+
599
+ /**
600
+ * Find peers by content hash using DHT
601
+ * @param content_hash Hash to search for (40-character hex string)
602
+ * @param callback Function to call with discovered peers
603
+ * @return true if search initiated successfully
604
+ */
605
+ bool find_peers_by_hash(const std::string& content_hash,
606
+ std::function<void(const std::vector<std::string>&)> callback);
607
+
608
+ /**
609
+ * Announce our presence for a content hash with optional peer discovery callback
610
+ * If callback is provided, peers discovered during DHT traversal will be returned through it
611
+ * @param content_hash Hash to announce for (40-character hex string)
612
+ * @param port Port to announce (default: our listen port)
613
+ * @param callback Optional function to call with discovered peers during traversal
614
+ * @return true if announced successfully
615
+ */
616
+ bool announce_for_hash(const std::string& content_hash, uint16_t port = 0,
617
+ std::function<void(const std::vector<std::string>&)> callback = nullptr);
618
+
619
+ /**
620
+ * Check if DHT is currently running
621
+ * @return true if DHT is running
622
+ */
623
+ bool is_dht_running() const;
624
+
625
+ /**
626
+ * Get the size of the DHT routing table
627
+ * @return Number of nodes in routing table
628
+ */
629
+ size_t get_dht_routing_table_size() const;
630
+
631
+ // mDNS Discovery
632
+ /**
633
+ * Start mDNS service discovery and announcement
634
+ * @param service_instance_name Service instance name (optional)
635
+ * @param txt_records Additional TXT records for service announcement
636
+ * @return true if started successfully
637
+ */
638
+ bool start_mdns_discovery(const std::string& service_instance_name = "",
639
+ const std::map<std::string, std::string>& txt_records = {});
640
+
641
+ /**
642
+ * Stop mDNS discovery
643
+ */
644
+ void stop_mdns_discovery();
645
+
646
+ /**
647
+ * Check if mDNS is currently running
648
+ * @return true if mDNS is running
649
+ */
650
+ bool is_mdns_running() const;
651
+
652
+ /**
653
+ * Set mDNS service discovery callback
654
+ * @param callback Function to call when services are discovered
655
+ */
656
+ void set_mdns_callback(std::function<void(const std::string&, int, const std::string&)> callback);
657
+
658
+ /**
659
+ * Get recently discovered mDNS services
660
+ * @return Vector of discovered services
661
+ */
662
+ std::vector<MdnsService> get_mdns_services() const;
663
+
664
+ /**
665
+ * Manually query for mDNS services
666
+ * @return true if query sent successfully
667
+ */
668
+ bool query_mdns_services();
669
+
670
+ // Automatic Discovery
671
+ /**
672
+ * Start automatic peer discovery
673
+ */
674
+ void start_automatic_peer_discovery();
675
+
676
+ /**
677
+ * Stop automatic peer discovery
678
+ */
679
+ void stop_automatic_peer_discovery();
680
+
681
+ /**
682
+ * Check if automatic discovery is running
683
+ * @return true if automatic discovery is running
684
+ */
685
+ bool is_automatic_discovery_running() const;
686
+
687
+ /**
688
+ * Get the discovery hash for current protocol configuration
689
+ * @return Discovery hash based on current protocol name and version
690
+ */
691
+ std::string get_discovery_hash() const;
692
+
693
+ /**
694
+ * Get the well-known RATS peer discovery hash
695
+ * @return Standard RATS discovery hash
696
+ */
697
+ static std::string get_rats_peer_discovery_hash();
698
+
699
+ // =========================================================================
700
+ // NAT Traversal and STUN Functionality
701
+ // =========================================================================
702
+
703
+ /**
704
+ * Discover public IP address using STUN and add to ignore list
705
+ * @param stun_server STUN server hostname (default: Google STUN)
706
+ * @param stun_port STUN server port (default: 19302)
707
+ * @return true if successful, false otherwise
708
+ */
709
+ bool discover_and_ignore_public_ip(const std::string& stun_server = "stun.l.google.com", int stun_port = 19302);
710
+
711
+ /**
712
+ * Detect NAT type using STUN servers
713
+ * @return Detected NAT type
714
+ */
715
+ NatType detect_nat_type();
716
+
717
+ /**
718
+ * Get detailed NAT characteristics
719
+ * @return Detailed NAT information
720
+ */
721
+ NatTypeInfo get_nat_characteristics();
722
+
723
+ /**
724
+ * Get the discovered public IP address
725
+ * @return Public IP address string or empty if not discovered
726
+ */
727
+ std::string get_public_ip() const;
728
+
729
+ /**
730
+ * Add an IP address to the ignore list
731
+ * @param ip_address IP address to ignore
732
+ */
733
+ void add_ignored_address(const std::string& ip_address);
734
+
735
+ /**
736
+ * Perform coordinated hole punching with a peer
737
+ * @param peer_ip Peer IP address
738
+ * @param peer_port Peer port
739
+ * @param coordination_data Coordination data from peer
740
+ * @return true if successful
741
+ */
742
+ bool coordinate_hole_punching(const std::string& peer_ip, uint16_t peer_port,
743
+ const nlohmann::json& coordination_data);
744
+
745
+ /**
746
+ * Get NAT traversal statistics
747
+ * @return JSON object with NAT traversal statistics
748
+ */
749
+ nlohmann::json get_nat_traversal_statistics() const;
750
+
751
+ // =========================================================================
752
+ // Protocol Configuration
753
+ // =========================================================================
754
+
755
+ /**
756
+ * Set custom protocol name for handshakes and DHT discovery
757
+ * @param protocol_name Custom protocol name (default: "rats")
758
+ */
759
+ void set_protocol_name(const std::string& protocol_name);
760
+
761
+ /**
762
+ * Set custom protocol version for handshakes
763
+ * @param protocol_version Custom protocol version (default: "1.0")
764
+ */
765
+ void set_protocol_version(const std::string& protocol_version);
766
+
767
+ /**
768
+ * Get current protocol name
769
+ * @return Current protocol name
770
+ */
771
+ std::string get_protocol_name() const;
772
+
773
+ /**
774
+ * Get current protocol version
775
+ * @return Current protocol version
776
+ */
777
+ std::string get_protocol_version() const;
778
+
779
+ // =========================================================================
780
+ // Message Exchange API
781
+ // =========================================================================
782
+
783
+ /**
784
+ * Register a persistent message handler
785
+ * @param message_type Type of message to handle
786
+ * @param callback Function to call when message is received
787
+ */
788
+ void on(const std::string& message_type, MessageCallback callback);
789
+
790
+ /**
791
+ * Register a one-time message handler
792
+ * @param message_type Type of message to handle
793
+ * @param callback Function to call when message is received (once only)
794
+ */
795
+ void once(const std::string& message_type, MessageCallback callback);
796
+
797
+ /**
798
+ * Remove all handlers for a message type
799
+ * @param message_type Type of message to stop handling
800
+ */
801
+ void off(const std::string& message_type);
802
+
803
+ /**
804
+ * Send a message to all peers
805
+ * @param message_type Type of message
806
+ * @param data Message data
807
+ * @param callback Optional callback for send result
808
+ */
809
+ void send(const std::string& message_type, const nlohmann::json& data, SendCallback callback = nullptr);
810
+
811
+ /**
812
+ * Send a message to a specific peer
813
+ * @param peer_id Target peer ID
814
+ * @param message_type Type of message
815
+ * @param data Message data
816
+ * @param callback Optional callback for send result
817
+ */
818
+ void send(const std::string& peer_id, const std::string& message_type, const nlohmann::json& data, SendCallback callback = nullptr);
819
+
820
+ /**
821
+ * Parse a JSON message
822
+ * @param message Raw message string
823
+ * @param out_json Parsed JSON output
824
+ * @return true if parsed successfully
825
+ */
826
+ bool parse_json_message(const std::string& message, nlohmann::json& out_json);
827
+
828
+ // =========================================================================
829
+ // Encryption Functionality
830
+ // =========================================================================
831
+
832
+ /**
833
+ * Initialize encryption system
834
+ * @param enable Whether to enable encryption
835
+ * @return true if successful
836
+ */
837
+ bool initialize_encryption(bool enable);
838
+
839
+ /**
840
+ * Set encryption enabled/disabled
841
+ * @param enabled Whether encryption should be enabled
842
+ */
843
+ void set_encryption_enabled(bool enabled);
844
+
845
+ /**
846
+ * Check if encryption is enabled
847
+ * @return true if encryption is enabled
848
+ */
849
+ bool is_encryption_enabled() const;
850
+
851
+ /**
852
+ * Get the encryption key as hex string
853
+ * @return Encryption key in hex format
854
+ */
855
+ std::string get_encryption_key() const;
856
+
857
+ /**
858
+ * Set encryption key from hex string
859
+ * @param key_hex Encryption key in hex format
860
+ * @return true if key was valid and set
861
+ */
862
+ bool set_encryption_key(const std::string& key_hex);
863
+
864
+ /**
865
+ * Generate a new encryption key
866
+ * @return New encryption key in hex format
867
+ */
868
+ std::string generate_new_encryption_key();
869
+
870
+ /**
871
+ * Check if a peer connection is encrypted
872
+ * @param peer_id Peer ID to check
873
+ * @return true if peer connection is encrypted
874
+ */
875
+ bool is_peer_encrypted(const std::string& peer_id) const;
876
+
877
+ // =========================================================================
878
+ // Configuration Persistence
879
+ // =========================================================================
880
+
881
+ /**
882
+ * Load configuration from files
883
+ * @return true if successful, false otherwise
884
+ */
885
+ bool load_configuration();
886
+
887
+ /**
888
+ * Save configuration to files
889
+ * @return true if successful, false otherwise
890
+ */
891
+ bool save_configuration();
892
+
893
+ /**
894
+ * Set directory where data files will be stored
895
+ * @param directory_path Path to directory (default: current folder)
896
+ * @return true if directory is accessible, false otherwise
897
+ */
898
+ bool set_data_directory(const std::string& directory_path);
899
+
900
+ /**
901
+ * Get current data directory path
902
+ * @return Current data directory path
903
+ */
904
+ std::string get_data_directory() const;
905
+
906
+ /**
907
+ * Load saved peers and attempt to reconnect
908
+ * @return Number of connection attempts made
909
+ */
910
+ int load_and_reconnect_peers();
911
+
912
+ /**
913
+ * Load historical peers from a file
914
+ * @return true if successful, false otherwise
915
+ */
916
+ bool load_historical_peers();
917
+
918
+ /**
919
+ * Save current peers to a historical file
920
+ * @return true if successful, false otherwise
921
+ */
922
+ bool save_historical_peers();
923
+
924
+ /**
925
+ * Clear all historical peers
926
+ */
927
+ void clear_historical_peers();
928
+
929
+ /**
930
+ * Get all historical peers
931
+ * @return Vector of RatsPeer objects
932
+ */
933
+ std::vector<RatsPeer> get_historical_peers() const;
934
+
935
+ // =========================================================================
936
+ // Statistics and Information
937
+ // =========================================================================
938
+
939
+ /**
940
+ * Get connection statistics
941
+ * @return JSON object with detailed statistics
942
+ */
943
+ nlohmann::json get_connection_statistics() const;
944
+
945
+ // =========================================================================
946
+ // GossipSub Functionality
947
+ // =========================================================================
948
+
949
+ /**
950
+ * Get GossipSub instance for publish-subscribe messaging
951
+ * @return Reference to GossipSub instance
952
+ */
953
+ GossipSub& get_gossipsub();
954
+
955
+ /**
956
+ * Check if GossipSub is available
957
+ * @return true if GossipSub is initialized
958
+ */
959
+ bool is_gossipsub_available() const;
960
+
961
+ // Topic Management
962
+ /**
963
+ * Subscribe to a GossipSub topic
964
+ * @param topic Topic name to subscribe to
965
+ * @return true if subscription successful
966
+ */
967
+ bool subscribe_to_topic(const std::string& topic);
968
+
969
+ /**
970
+ * Unsubscribe from a GossipSub topic
971
+ * @param topic Topic name to unsubscribe from
972
+ * @return true if unsubscription successful
973
+ */
974
+ bool unsubscribe_from_topic(const std::string& topic);
975
+
976
+ /**
977
+ * Check if subscribed to a GossipSub topic
978
+ * @param topic Topic name to check
979
+ * @return true if subscribed
980
+ */
981
+ bool is_subscribed_to_topic(const std::string& topic) const;
982
+
983
+ /**
984
+ * Get list of subscribed GossipSub topics
985
+ * @return Vector of topic names
986
+ */
987
+ std::vector<std::string> get_subscribed_topics() const;
988
+
989
+ // Publishing
990
+ /**
991
+ * Publish a message to a GossipSub topic
992
+ * @param topic Topic to publish to
993
+ * @param message Message content
994
+ * @return true if published successfully
995
+ */
996
+ bool publish_to_topic(const std::string& topic, const std::string& message);
997
+
998
+ /**
999
+ * Publish a JSON message to a GossipSub topic
1000
+ * @param topic Topic to publish to
1001
+ * @param message JSON message content
1002
+ * @return true if published successfully
1003
+ */
1004
+ bool publish_json_to_topic(const std::string& topic, const nlohmann::json& message);
1005
+
1006
+ // Event Handlers (Unified API)
1007
+ /**
1008
+ * Set a message handler for a GossipSub topic using unified event API pattern
1009
+ * @param topic Topic name
1010
+ * @param callback Function to call when messages are received (peer_id, topic, message_content)
1011
+ */
1012
+ void on_topic_message(const std::string& topic, std::function<void(const std::string&, const std::string&, const std::string&)> callback);
1013
+
1014
+ /**
1015
+ * Set a JSON message handler for a GossipSub topic using unified event API pattern
1016
+ * @param topic Topic name
1017
+ * @param callback Function to call when JSON messages are received (peer_id, topic, json_message)
1018
+ */
1019
+ void on_topic_json_message(const std::string& topic, std::function<void(const std::string&, const std::string&, const nlohmann::json&)> callback);
1020
+
1021
+ /**
1022
+ * Set a peer joined handler for a GossipSub topic using unified event API pattern
1023
+ * @param topic Topic name
1024
+ * @param callback Function to call when peers join the topic
1025
+ */
1026
+ void on_topic_peer_joined(const std::string& topic, std::function<void(const std::string&, const std::string&)> callback);
1027
+
1028
+ /**
1029
+ * Set a peer left handler for a GossipSub topic using unified event API pattern
1030
+ * @param topic Topic name
1031
+ * @param callback Function to call when peers leave the topic
1032
+ */
1033
+ void on_topic_peer_left(const std::string& topic, std::function<void(const std::string&, const std::string&)> callback);
1034
+
1035
+ /**
1036
+ * Set a message validator for a GossipSub topic
1037
+ * @param topic Topic name (empty for global validator)
1038
+ * @param validator Validation function returning ACCEPT, REJECT, or IGNORE_MSG
1039
+ */
1040
+ void set_topic_message_validator(const std::string& topic, std::function<ValidationResult(const std::string&, const std::string&, const std::string&)> validator);
1041
+
1042
+ /**
1043
+ * Remove all event handlers for a GossipSub topic
1044
+ * @param topic Topic name
1045
+ */
1046
+ void off_topic(const std::string& topic);
1047
+
1048
+ // Information
1049
+ /**
1050
+ * Get peers subscribed to a GossipSub topic
1051
+ * @param topic Topic name
1052
+ * @return Vector of peer IDs
1053
+ */
1054
+ std::vector<std::string> get_topic_peers(const std::string& topic) const;
1055
+
1056
+ /**
1057
+ * Get mesh peers for a GossipSub topic
1058
+ * @param topic Topic name
1059
+ * @return Vector of peer IDs in the mesh
1060
+ */
1061
+ std::vector<std::string> get_topic_mesh_peers(const std::string& topic) const;
1062
+
1063
+ /**
1064
+ * Get GossipSub statistics
1065
+ * @return JSON object with comprehensive GossipSub statistics
1066
+ */
1067
+ nlohmann::json get_gossipsub_statistics() const;
1068
+
1069
+ /**
1070
+ * Check if GossipSub is running
1071
+ * @return true if GossipSub service is active
1072
+ */
1073
+ bool is_gossipsub_running() const;
1074
+
1075
+ // =========================================================================
1076
+ // Logging Control API
1077
+ // =========================================================================
1078
+
1079
+ /**
1080
+ * Enable or disable file logging
1081
+ * When enabled, logs will be written to "rats.log" by default
1082
+ * @param enabled Whether to enable file logging
1083
+ */
1084
+ void set_logging_enabled(bool enabled);
1085
+
1086
+ /**
1087
+ * Check if file logging is currently enabled
1088
+ * @return true if file logging is enabled
1089
+ */
1090
+ bool is_logging_enabled() const;
1091
+
1092
+ /**
1093
+ * Set the log file path
1094
+ * @param file_path Path to the log file (default: "rats.log")
1095
+ */
1096
+ void set_log_file_path(const std::string& file_path);
1097
+
1098
+ /**
1099
+ * Get the current log file path
1100
+ * @return Current log file path
1101
+ */
1102
+ std::string get_log_file_path() const;
1103
+
1104
+ /**
1105
+ * Set the minimum log level
1106
+ * @param level Minimum log level (DEBUG=0, INFO=1, WARN=2, ERROR=3)
1107
+ */
1108
+ void set_log_level(LogLevel level);
1109
+
1110
+ /**
1111
+ * Set the minimum log level using string
1112
+ * @param level_str Log level as string ("DEBUG", "INFO", "WARN", "ERROR")
1113
+ */
1114
+ void set_log_level(const std::string& level_str);
1115
+
1116
+ /**
1117
+ * Get the current log level
1118
+ * @return Current minimum log level
1119
+ */
1120
+ LogLevel get_log_level() const;
1121
+
1122
+ /**
1123
+ * Enable or disable colored log output
1124
+ * @param enabled Whether to enable colored output
1125
+ */
1126
+ void set_log_colors_enabled(bool enabled);
1127
+
1128
+ /**
1129
+ * Check if colored log output is enabled
1130
+ * @return true if colors are enabled
1131
+ */
1132
+ bool is_log_colors_enabled() const;
1133
+
1134
+ /**
1135
+ * Enable or disable timestamps in log output
1136
+ * @param enabled Whether to enable timestamps
1137
+ */
1138
+ void set_log_timestamps_enabled(bool enabled);
1139
+
1140
+ /**
1141
+ * Check if timestamps are enabled in log output
1142
+ * @return true if timestamps are enabled
1143
+ */
1144
+ bool is_log_timestamps_enabled() const;
1145
+
1146
+ /**
1147
+ * Set log file rotation size
1148
+ * @param max_size_bytes Maximum size in bytes before log rotation (default: 10MB)
1149
+ */
1150
+ void set_log_rotation_size(size_t max_size_bytes);
1151
+
1152
+ /**
1153
+ * Set the number of log files to retain during rotation
1154
+ * @param count Number of old log files to keep (default: 5)
1155
+ */
1156
+ void set_log_retention_count(int count);
1157
+
1158
+ /**
1159
+ * Clear/reset the current log file
1160
+ */
1161
+ void clear_log_file();
1162
+
1163
+ // =========================================================================
1164
+ // File Transfer API
1165
+ // =========================================================================
1166
+
1167
+ /**
1168
+ * Get the file transfer manager instance
1169
+ * @return Reference to the file transfer manager
1170
+ */
1171
+ FileTransferManager& get_file_transfer_manager();
1172
+
1173
+ /**
1174
+ * Check if file transfer is available
1175
+ * @return true if file transfer manager is initialized
1176
+ */
1177
+ bool is_file_transfer_available() const;
1178
+
1179
+ // Sending and Requesting
1180
+ /**
1181
+ * Send a file to a peer
1182
+ * @param peer_id Target peer ID
1183
+ * @param file_path Local file path to send
1184
+ * @param remote_filename Optional remote filename (default: use local name)
1185
+ * @return Transfer ID if successful, empty string if failed
1186
+ */
1187
+ std::string send_file(const std::string& peer_id, const std::string& file_path,
1188
+ const std::string& remote_filename = "");
1189
+
1190
+ /**
1191
+ * Send an entire directory to a peer
1192
+ * @param peer_id Target peer ID
1193
+ * @param directory_path Local directory path to send
1194
+ * @param remote_directory_name Optional remote directory name
1195
+ * @param recursive Whether to include subdirectories (default: true)
1196
+ * @return Transfer ID if successful, empty string if failed
1197
+ */
1198
+ std::string send_directory(const std::string& peer_id, const std::string& directory_path,
1199
+ const std::string& remote_directory_name = "", bool recursive = true);
1200
+
1201
+ /**
1202
+ * Request a file from a remote peer
1203
+ * @param peer_id Target peer ID
1204
+ * @param remote_file_path Path to file on remote peer
1205
+ * @param local_path Local path where file should be saved
1206
+ * @return Transfer ID if successful, empty string if failed
1207
+ */
1208
+ std::string request_file(const std::string& peer_id, const std::string& remote_file_path,
1209
+ const std::string& local_path);
1210
+
1211
+ /**
1212
+ * Request a directory from a remote peer
1213
+ * @param peer_id Target peer ID
1214
+ * @param remote_directory_path Path to directory on remote peer
1215
+ * @param local_directory_path Local path where directory should be saved
1216
+ * @param recursive Whether to include subdirectories (default: true)
1217
+ * @return Transfer ID if successful, empty string if failed
1218
+ */
1219
+ std::string request_directory(const std::string& peer_id, const std::string& remote_directory_path,
1220
+ const std::string& local_directory_path, bool recursive = true);
1221
+
1222
+ // Accept/Reject Operations
1223
+ /**
1224
+ * Accept an incoming file transfer
1225
+ * @param transfer_id Transfer identifier from request
1226
+ * @param local_path Local path where file should be saved
1227
+ * @return true if accepted successfully
1228
+ */
1229
+ bool accept_file_transfer(const std::string& transfer_id, const std::string& local_path);
1230
+
1231
+ /**
1232
+ * Reject an incoming file transfer
1233
+ * @param transfer_id Transfer identifier from request
1234
+ * @param reason Optional reason for rejection
1235
+ * @return true if rejected successfully
1236
+ */
1237
+ bool reject_file_transfer(const std::string& transfer_id, const std::string& reason = "");
1238
+
1239
+ /**
1240
+ * Accept an incoming directory transfer
1241
+ * @param transfer_id Transfer identifier from request
1242
+ * @param local_path Local path where directory should be saved
1243
+ * @return true if accepted successfully
1244
+ */
1245
+ bool accept_directory_transfer(const std::string& transfer_id, const std::string& local_path);
1246
+
1247
+ /**
1248
+ * Reject an incoming directory transfer
1249
+ * @param transfer_id Transfer identifier from request
1250
+ * @param reason Optional reason for rejection
1251
+ * @return true if rejected successfully
1252
+ */
1253
+ bool reject_directory_transfer(const std::string& transfer_id, const std::string& reason = "");
1254
+
1255
+ // Transfer Control
1256
+ /**
1257
+ * Pause an active file transfer
1258
+ * @param transfer_id Transfer to pause
1259
+ * @return true if paused successfully
1260
+ */
1261
+ bool pause_file_transfer(const std::string& transfer_id);
1262
+
1263
+ /**
1264
+ * Resume a paused file transfer
1265
+ * @param transfer_id Transfer to resume
1266
+ * @return true if resumed successfully
1267
+ */
1268
+ bool resume_file_transfer(const std::string& transfer_id);
1269
+
1270
+ /**
1271
+ * Cancel an active or paused file transfer
1272
+ * @param transfer_id Transfer to cancel
1273
+ * @return true if cancelled successfully
1274
+ */
1275
+ bool cancel_file_transfer(const std::string& transfer_id);
1276
+
1277
+ // Information and Monitoring
1278
+ /**
1279
+ * Get file transfer progress information
1280
+ * @param transfer_id Transfer to query
1281
+ * @return Progress information or nullptr if not found
1282
+ */
1283
+ std::shared_ptr<FileTransferProgress> get_file_transfer_progress(const std::string& transfer_id) const;
1284
+
1285
+ /**
1286
+ * Get all active file transfers
1287
+ * @return Vector of transfer progress objects
1288
+ */
1289
+ std::vector<std::shared_ptr<FileTransferProgress>> get_active_file_transfers() const;
1290
+
1291
+ /**
1292
+ * Get file transfer statistics
1293
+ * @return JSON object with transfer statistics
1294
+ */
1295
+ nlohmann::json get_file_transfer_statistics() const;
1296
+
1297
+ /**
1298
+ * Set file transfer configuration
1299
+ * @param config Transfer configuration settings
1300
+ */
1301
+ void set_file_transfer_config(const FileTransferConfig& config);
1302
+
1303
+ /**
1304
+ * Get current file transfer configuration
1305
+ * @return Current configuration settings
1306
+ */
1307
+ const FileTransferConfig& get_file_transfer_config() const;
1308
+
1309
+ // Event Handlers
1310
+ /**
1311
+ * Set file transfer progress callback
1312
+ * @param callback Function to call with progress updates
1313
+ */
1314
+ void on_file_transfer_progress(FileTransferProgressCallback callback);
1315
+
1316
+ /**
1317
+ * Set file transfer completion callback
1318
+ * @param callback Function to call when transfers complete
1319
+ */
1320
+ void on_file_transfer_completed(FileTransferCompletedCallback callback);
1321
+
1322
+ /**
1323
+ * Set incoming file transfer request callback
1324
+ * @param callback Function to call when receiving transfer requests
1325
+ */
1326
+ void on_file_transfer_request(FileTransferRequestCallback callback);
1327
+
1328
+ /**
1329
+ * Set directory transfer progress callback
1330
+ * @param callback Function to call with directory transfer progress
1331
+ */
1332
+ void on_directory_transfer_progress(DirectoryTransferProgressCallback callback);
1333
+
1334
+ /**
1335
+ * Set file request callback (called when receiving file requests)
1336
+ * @param callback Function to call when receiving file requests
1337
+ */
1338
+ void on_file_request(FileRequestCallback callback);
1339
+
1340
+ /**
1341
+ * Set directory request callback (called when receiving directory requests)
1342
+ * @param callback Function to call when receiving directory requests
1343
+ */
1344
+ void on_directory_request(DirectoryRequestCallback callback);
1345
+
1346
+ #ifdef RATS_SEARCH_FEATURES
1347
+ // =========================================================================
1348
+ // BitTorrent API (requires RATS_SEARCH_FEATURES)
1349
+ // =========================================================================
1350
+
1351
+ /**
1352
+ * Enable BitTorrent functionality
1353
+ * @param listen_port Port to listen for BitTorrent connections (default: 6881)
1354
+ * @return true if BitTorrent was successfully enabled
1355
+ */
1356
+ bool enable_bittorrent(int listen_port = 6881);
1357
+
1358
+ /**
1359
+ * Disable BitTorrent functionality
1360
+ */
1361
+ void disable_bittorrent();
1362
+
1363
+ /**
1364
+ * Check if BitTorrent is enabled
1365
+ * @return true if BitTorrent is active
1366
+ */
1367
+ bool is_bittorrent_enabled() const;
1368
+
1369
+ /**
1370
+ * Add a torrent from a file
1371
+ * @param torrent_file Path to the .torrent file
1372
+ * @param download_path Directory where files will be downloaded
1373
+ * @return Shared pointer to TorrentDownload object, or nullptr on failure
1374
+ */
1375
+ std::shared_ptr<TorrentDownload> add_torrent(const std::string& torrent_file,
1376
+ const std::string& download_path);
1377
+
1378
+ /**
1379
+ * Add a torrent from TorrentInfo
1380
+ * @param torrent_info TorrentInfo object with torrent metadata
1381
+ * @param download_path Directory where files will be downloaded
1382
+ * @return Shared pointer to TorrentDownload object, or nullptr on failure
1383
+ */
1384
+ std::shared_ptr<TorrentDownload> add_torrent(const TorrentInfo& torrent_info,
1385
+ const std::string& download_path);
1386
+
1387
+ /**
1388
+ * Add a torrent by info hash (magnet link style - uses DHT to find peers)
1389
+ * @param info_hash Info hash of the torrent
1390
+ * @param download_path Directory where files will be downloaded
1391
+ * @return Shared pointer to TorrentDownload object, or nullptr on failure
1392
+ * @note Requires DHT to be running. Will discover peers via DHT.
1393
+ */
1394
+ std::shared_ptr<TorrentDownload> add_torrent_by_hash(const InfoHash& info_hash,
1395
+ const std::string& download_path);
1396
+
1397
+ /**
1398
+ * Add a torrent by info hash hex string (magnet link style - uses DHT to find peers)
1399
+ * @param info_hash_hex Info hash as 40-character hex string
1400
+ * @param download_path Directory where files will be downloaded
1401
+ * @return Shared pointer to TorrentDownload object, or nullptr on failure
1402
+ * @note Requires DHT to be running. Will discover peers via DHT.
1403
+ */
1404
+ std::shared_ptr<TorrentDownload> add_torrent_by_hash(const std::string& info_hash_hex,
1405
+ const std::string& download_path);
1406
+
1407
+ /**
1408
+ * Remove a torrent by info hash
1409
+ * @param info_hash Info hash of the torrent to remove
1410
+ * @return true if torrent was removed successfully
1411
+ */
1412
+ bool remove_torrent(const InfoHash& info_hash);
1413
+
1414
+ /**
1415
+ * Get a torrent by info hash
1416
+ * @param info_hash Info hash of the torrent
1417
+ * @return Shared pointer to TorrentDownload object, or nullptr if not found
1418
+ */
1419
+ std::shared_ptr<TorrentDownload> get_torrent(const InfoHash& info_hash);
1420
+
1421
+ /**
1422
+ * Get all active torrents
1423
+ * @return Vector of all active torrent downloads
1424
+ */
1425
+ std::vector<std::shared_ptr<TorrentDownload>> get_all_torrents();
1426
+
1427
+ /**
1428
+ * Get the number of active torrents
1429
+ * @return Number of active torrents
1430
+ */
1431
+ size_t get_active_torrents_count() const;
1432
+
1433
+ /**
1434
+ * Get BitTorrent statistics (downloaded and uploaded bytes)
1435
+ * @return Pair of (downloaded_bytes, uploaded_bytes)
1436
+ */
1437
+ std::pair<uint64_t, uint64_t> get_bittorrent_stats() const;
1438
+
1439
+ /**
1440
+ * Get torrent metadata without downloading (requires DHT to be running)
1441
+ * @param info_hash Info hash of the torrent
1442
+ * @param callback Function called when metadata is retrieved (torrent_info, success, error_message)
1443
+ * @note This only retrieves metadata via BEP 9, it does not start downloading
1444
+ */
1445
+ void get_torrent_metadata(const InfoHash& info_hash,
1446
+ std::function<void(const TorrentInfo&, bool, const std::string&)> callback);
1447
+
1448
+ /**
1449
+ * Get torrent metadata without downloading by hex string (requires DHT to be running)
1450
+ * @param info_hash_hex Info hash as 40-character hex string
1451
+ * @param callback Function called when metadata is retrieved (torrent_info, success, error_message)
1452
+ * @note This only retrieves metadata via BEP 9, it does not start downloading
1453
+ */
1454
+ void get_torrent_metadata(const std::string& info_hash_hex,
1455
+ std::function<void(const TorrentInfo&, bool, const std::string&)> callback);
1456
+ #endif // RATS_SEARCH_FEATURES
1457
+
1458
+ private:
1459
+ int listen_port_;
1460
+ std::string bind_address_;
1461
+ int max_peers_;
1462
+ socket_t server_socket_;
1463
+ std::atomic<bool> running_;
1464
+
1465
+ // NAT traversal configuration
1466
+ NatTraversalConfig nat_config_;
1467
+
1468
+ // =========================================================================
1469
+ // MUTEX LOCKING ORDER - CRITICAL FOR DEADLOCK PREVENTION
1470
+ // =========================================================================
1471
+ // When acquiring multiple mutexes, ALWAYS follow this strict order:
1472
+ //
1473
+ // 1. config_mutex_ (Configuration and peer ID)
1474
+ // 2. protocol_config_mutex_ (Protocol name and version)
1475
+ // 3. encryption_mutex_ (Encryption settings and keys)
1476
+ // 4. nat_mutex_ (NAT detection and characteristics)
1477
+ // 5. public_ip_mutex_ (Public IP address)
1478
+ // 6. local_addresses_mutex_ (Local interface addresses)
1479
+ // 7. ice_coordination_mutex_ (ICE coordination tracking)
1480
+ // 8. connection_attempts_mutex_ (Connection attempt history)
1481
+ // 9. peers_mutex_ (Peer management - most frequently locked)
1482
+ // 10. socket_send_mutexes_mutex_ (Socket send mutex management)
1483
+ // 11. message_handlers_mutex_ (Message handler registration)
1484
+ // =========================================================================
1485
+
1486
+ // Configuration persistence
1487
+ std::string our_peer_id_; // Our persistent peer ID
1488
+ std::string data_directory_; // Directory where data files are stored
1489
+ mutable std::mutex config_mutex_; // [1] Protects configuration data
1490
+ static const std::string CONFIG_FILE_NAME; // "config.json"
1491
+ static const std::string PEERS_FILE_NAME; // "peers.rats"
1492
+ static const std::string PEERS_EVER_FILE_NAME; // "peers_ever.rats"
1493
+
1494
+ // Encryption state
1495
+ NoiseKey static_encryption_key_; // Our static encryption key
1496
+ bool encryption_enabled_; // Whether encryption is enabled
1497
+ mutable std::mutex encryption_mutex_; // [3] Protects encryption state
1498
+
1499
+ // ICE and NAT traversal
1500
+ std::unique_ptr<IceAgent> ice_agent_; // ICE agent for NAT traversal
1501
+ std::unique_ptr<AdvancedNatDetector> nat_detector_; // Advanced NAT type detection
1502
+ NatType detected_nat_type_; // Our detected NAT type
1503
+ NatTypeInfo nat_characteristics_; // Detailed NAT information
1504
+ mutable std::mutex nat_mutex_; // [4] Protects NAT-related data
1505
+
1506
+ // ICE coordination tracking to prevent duplicate attempts
1507
+ std::unordered_set<std::string> ice_coordination_in_progress_; // Set of peer_ids having ICE coordination
1508
+ mutable std::mutex ice_coordination_mutex_; // [7] Protects ICE coordination state
1509
+
1510
+ // Connection attempt tracking
1511
+ std::unordered_map<std::string, std::vector<ConnectionAttemptResult>> connection_attempts_;
1512
+ mutable std::mutex connection_attempts_mutex_; // [8] Protects connection attempts
1513
+
1514
+ // Organized peer management using RatsPeer struct
1515
+ mutable std::mutex peers_mutex_; // [9] Protects peer data (most frequently locked)
1516
+ std::unordered_map<std::string, RatsPeer> peers_; // keyed by peer_id
1517
+ std::unordered_map<socket_t, std::string> socket_to_peer_id_; // for quick socket->peer_id lookup
1518
+ std::unordered_map<std::string, std::string> address_to_peer_id_; // for duplicate detection (normalized_address->peer_id)
1519
+
1520
+ // Per-socket synchronization for thread-safe message sending
1521
+ mutable std::mutex socket_send_mutexes_mutex_; // [10] Protects socket send mutex map
1522
+ std::unordered_map<socket_t, std::shared_ptr<std::mutex>> socket_send_mutexes_;
1523
+
1524
+ // Server and client management
1525
+ std::thread server_thread_;
1526
+ std::thread management_thread_;
1527
+
1528
+ ConnectionCallback connection_callback_;
1529
+ AdvancedConnectionCallback advanced_connection_callback_;
1530
+ BinaryDataCallback binary_data_callback_;
1531
+ StringDataCallback string_data_callback_;
1532
+ JsonDataCallback json_data_callback_;
1533
+ DisconnectCallback disconnect_callback_;
1534
+ NatTraversalProgressCallback nat_progress_callback_;
1535
+ IceCandidateDiscoveredCallback ice_candidate_callback_;
1536
+
1537
+ // DHT client for peer discovery
1538
+ std::unique_ptr<DhtClient> dht_client_;
1539
+
1540
+ // STUN client for public IP discovery
1541
+ std::unique_ptr<StunClient> stun_client_;
1542
+ std::string public_ip_;
1543
+ mutable std::mutex public_ip_mutex_; // [5] Protects public IP address
1544
+
1545
+ // mDNS client for local network discovery
1546
+ std::unique_ptr<MdnsClient> mdns_client_;
1547
+ std::function<void(const std::string&, int, const std::string&)> mdns_callback_;
1548
+
1549
+ // GossipSub for publish-subscribe messaging
1550
+ std::unique_ptr<GossipSub> gossipsub_;
1551
+
1552
+ // File transfer manager
1553
+ std::unique_ptr<FileTransferManager> file_transfer_manager_;
1554
+
1555
+ #ifdef RATS_SEARCH_FEATURES
1556
+ // BitTorrent client (optional, requires RATS_SEARCH_FEATURES)
1557
+ std::unique_ptr<BitTorrentClient> bittorrent_client_;
1558
+ #endif
1559
+
1560
+ void initialize_modules();
1561
+ void destroy_modules();
1562
+
1563
+ void server_loop();
1564
+ void management_loop();
1565
+ void handle_client(socket_t client_socket, const std::string& peer_hash_id);
1566
+ void remove_peer(socket_t socket);
1567
+ std::string generate_peer_hash_id(socket_t socket, const std::string& connection_info);
1568
+ void handle_dht_peer_discovery(const std::vector<Peer>& peers, const InfoHash& info_hash);
1569
+ void handle_mdns_service_discovery(const MdnsService& service, bool is_new);
1570
+
1571
+ // Message header helpers
1572
+ std::vector<uint8_t> create_message_with_header(const std::vector<uint8_t>& payload, MessageDataType type);
1573
+ bool parse_message_with_header(const std::vector<uint8_t>& message, MessageHeader& header, std::vector<uint8_t>& payload) const;
1574
+
1575
+ // Enhanced connection establishment
1576
+ bool attempt_direct_connection(const std::string& host, int port, ConnectionAttemptResult& result);
1577
+ bool attempt_stun_assisted_connection(const std::string& host, int port, ConnectionAttemptResult& result);
1578
+ bool attempt_ice_connection(const std::string& host, int port, ConnectionAttemptResult& result);
1579
+ bool attempt_turn_relay_connection(const std::string& host, int port, ConnectionAttemptResult& result);
1580
+ bool attempt_hole_punch_connection(const std::string& host, int port, ConnectionAttemptResult& result);
1581
+
1582
+ // ICE coordination helpers
1583
+ void handle_ice_candidate_discovered(const std::string& peer_id, const IceCandidate& candidate);
1584
+ void handle_ice_connection_state_change(const std::string& peer_id, IceConnectionState state);
1585
+ void initiate_ice_with_peer(const std::string& peer_id, const std::string& host, int port);
1586
+
1587
+ // NAT traversal message handlers
1588
+ void handle_ice_offer_message(socket_t socket, const std::string& peer_hash_id, const nlohmann::json& payload);
1589
+ void handle_ice_answer_message(socket_t socket, const std::string& peer_hash_id, const nlohmann::json& payload);
1590
+ void handle_ice_candidate_message(socket_t socket, const std::string& peer_hash_id, const nlohmann::json& payload);
1591
+ void handle_hole_punch_coordination_message(socket_t socket, const std::string& peer_hash_id, const nlohmann::json& payload);
1592
+ void handle_nat_info_exchange_message(socket_t socket, const std::string& peer_hash_id, const nlohmann::json& payload);
1593
+ void send_nat_info_to_peer(socket_t socket, const std::string& peer_id);
1594
+
1595
+ // New peer management methods using RatsPeer
1596
+ void add_peer(const RatsPeer& peer);
1597
+ void add_peer_unlocked(const RatsPeer& peer); // Assumes peers_mutex_ is already locked
1598
+ void remove_peer_by_id(const std::string& peer_id);
1599
+ void remove_peer_by_id_unlocked(const std::string& peer_id); // Assumes peers_mutex_ is already locked
1600
+ bool is_already_connected_to_address(const std::string& normalized_address) const;
1601
+ std::string normalize_peer_address(const std::string& ip, int port) const;
1602
+
1603
+ // Local interface address blocking (ignore list)
1604
+ std::vector<std::string> local_interface_addresses_;
1605
+ mutable std::mutex local_addresses_mutex_; // [6] Protects local interface addresses
1606
+ void initialize_local_addresses();
1607
+ void refresh_local_addresses();
1608
+ bool is_blocked_address(const std::string& ip_address) const;
1609
+ bool should_ignore_peer(const std::string& ip, int port) const;
1610
+ static bool parse_address_string(const std::string& address_str, std::string& out_ip, int& out_port);
1611
+
1612
+ // Helper functions that assume mutex is already locked
1613
+ int get_peer_count_unlocked() const; // Helper that assumes peers_mutex_ is already locked
1614
+
1615
+ // Handshake protocol
1616
+ static constexpr const char* RATS_PROTOCOL_VERSION = "1.0";
1617
+ static constexpr int HANDSHAKE_TIMEOUT_SECONDS = 10;
1618
+
1619
+ // Custom protocol configuration
1620
+ std::string custom_protocol_name_; // Custom protocol name (default: "rats")
1621
+ std::string custom_protocol_version_; // Custom protocol version (default: "1.0")
1622
+ mutable std::mutex protocol_config_mutex_; // [2] Protects protocol configuration
1623
+
1624
+ struct HandshakeMessage {
1625
+ std::string protocol;
1626
+ std::string version;
1627
+ std::string peer_id;
1628
+ std::string message_type;
1629
+ int64_t timestamp;
1630
+ };
1631
+
1632
+ std::string create_handshake_message(const std::string& message_type, const std::string& our_peer_id) const;
1633
+ bool parse_handshake_message(const std::string& message, HandshakeMessage& out_msg) const;
1634
+ bool validate_handshake_message(const HandshakeMessage& msg) const;
1635
+ bool is_handshake_message(const std::string& message) const;
1636
+ bool send_handshake(socket_t socket, const std::string& our_peer_id);
1637
+ bool send_handshake_unlocked(socket_t socket, const std::string& our_peer_id);
1638
+ bool handle_handshake_message(socket_t socket, const std::string& peer_hash_id, const std::string& message);
1639
+ void check_handshake_timeouts();
1640
+ void log_handshake_completion(const RatsPeer& peer);
1641
+ void log_handshake_completion_unlocked(const RatsPeer& peer);
1642
+
1643
+ // Automatic discovery
1644
+ std::atomic<bool> auto_discovery_running_;
1645
+ std::thread auto_discovery_thread_;
1646
+ void automatic_discovery_loop();
1647
+ void announce_rats_peer();
1648
+ void search_rats_peers();
1649
+
1650
+ // Message handling system
1651
+ nlohmann::json create_rats_message(const std::string& type, const nlohmann::json& payload, const std::string& sender_peer_id);
1652
+ void handle_rats_message(socket_t socket, const std::string& peer_hash_id, const nlohmann::json& message);
1653
+
1654
+ // Specific message handlers
1655
+ void handle_peer_exchange_message(socket_t socket, const std::string& peer_hash_id, const nlohmann::json& payload);
1656
+ void handle_peers_request_message(socket_t socket, const std::string& peer_hash_id, const nlohmann::json& payload);
1657
+ void handle_peers_response_message(socket_t socket, const std::string& peer_hash_id, const nlohmann::json& payload);
1658
+
1659
+ // Message creation and broadcasting
1660
+ nlohmann::json create_peer_exchange_message(const RatsPeer& peer);
1661
+ void broadcast_peer_exchange_message(const RatsPeer& new_peer);
1662
+ nlohmann::json create_peers_request_message(const std::string& sender_peer_id);
1663
+ nlohmann::json create_peers_response_message(const std::vector<RatsPeer>& peers, const std::string& sender_peer_id);
1664
+ std::vector<RatsPeer> get_random_peers(int max_count, const std::string& exclude_peer_id = "") const;
1665
+ void send_peers_request(socket_t socket, const std::string& our_peer_id);
1666
+
1667
+ int broadcast_rats_message(const nlohmann::json& message, const std::string& exclude_peer_id = "");
1668
+ int broadcast_rats_message_to_validated_peers(const nlohmann::json& message, const std::string& exclude_peer_id = "");
1669
+ // Message exchange API implementation
1670
+ struct MessageHandler {
1671
+ MessageCallback callback;
1672
+ bool is_once;
1673
+
1674
+ MessageHandler(MessageCallback cb, bool once) : callback(cb), is_once(once) {}
1675
+ };
1676
+
1677
+ std::unordered_map<std::string, std::vector<MessageHandler>> message_handlers_;
1678
+ mutable std::mutex message_handlers_mutex_; // [11] Protects message handlers
1679
+
1680
+ void call_message_handlers(const std::string& message_type, const std::string& peer_id, const nlohmann::json& data);
1681
+ void call_callback_safely(const MessageCallback& callback, const std::string& peer_id, const nlohmann::json& data);
1682
+ void remove_once_handlers(const std::string& message_type);
1683
+
1684
+ // Per-socket synchronization helpers
1685
+ std::shared_ptr<std::mutex> get_socket_send_mutex(socket_t socket);
1686
+ void cleanup_socket_send_mutex(socket_t socket);
1687
+
1688
+ // Configuration persistence helpers
1689
+ std::string generate_persistent_peer_id() const;
1690
+ nlohmann::json serialize_peer_for_persistence(const RatsPeer& peer) const;
1691
+ bool deserialize_peer_from_persistence(const nlohmann::json& json, std::string& ip, int& port, std::string& peer_id) const;
1692
+ std::string get_config_file_path() const;
1693
+ std::string get_peers_file_path() const;
1694
+ std::string get_peers_ever_file_path() const;
1695
+ bool save_peers_to_file();
1696
+ bool append_peer_to_historical_file(const RatsPeer& peer);
1697
+ int load_and_reconnect_historical_peers();
1698
+
1699
+ // NAT traversal helpers
1700
+ void initialize_nat_traversal();
1701
+ void detect_and_cache_nat_type();
1702
+ void update_connection_statistics(const std::string& peer_id, const ConnectionAttemptResult& result);
1703
+ std::string select_best_connection_strategy(const std::string& host, int port);
1704
+ NatType map_characteristics_to_nat_type(const NatTypeInfo& characteristics);
1705
+ void log_nat_detection_results();
1706
+ bool perform_tcp_connection(const std::string& host, int port, ConnectionAttemptResult& result);
1707
+
1708
+ // ICE coordination helpers
1709
+ void initialize_ice_agent();
1710
+ void setup_ice_callbacks();
1711
+ void update_peer_ice_info(socket_t socket, const nlohmann::json& payload);
1712
+ void add_candidate_to_peer(socket_t socket, const IceCandidate& candidate);
1713
+ bool should_initiate_ice_coordination(const std::string& peer_id);
1714
+ void mark_ice_coordination_in_progress(const std::string& peer_id);
1715
+ void remove_ice_coordination_tracking(const std::string& peer_id);
1716
+ void cleanup_ice_coordination_for_peer(const std::string& peer_id);
1717
+ nlohmann::json get_ice_statistics() const;
1718
+ bool is_ice_enabled() const;
1719
+ bool is_peer_ice_connected(const std::string& peer_id) const;
1720
+ void cleanup_ice_resources();
1721
+ };
1722
+
1723
+ // Utility functions
1724
+ std::unique_ptr<RatsClient> create_rats_client(int listen_port);
1725
+
1726
+ // Library version query (stable, binding-friendly)
1727
+ RATS_API const char* rats_get_library_version_string();
1728
+ RATS_API void rats_get_library_version(int* major, int* minor, int* patch, int* build);
1729
+ RATS_API const char* rats_get_library_git_describe();
1730
+ RATS_API uint32_t rats_get_library_abi(); // packed as (major<<16)|(minor<<8)|patch
1731
+
1732
+ } // namespace librats