librats 0.5.4 → 0.6.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/lib/index.d.ts +210 -35
- package/native-src/CMakeLists.txt +71 -14
- package/native-src/LICENSE +1 -1
- package/native-src/src/bittorrent.cpp +153 -1
- package/native-src/src/bittorrent.h +25 -0
- package/native-src/src/crc32.cpp +97 -0
- package/native-src/src/crc32.h +129 -0
- package/native-src/src/crypto/blake2_endian.h +57 -0
- package/native-src/src/crypto/blake2b.c +202 -0
- package/native-src/src/crypto/blake2b.h +53 -0
- package/native-src/src/crypto/blake2s.c +266 -0
- package/native-src/src/crypto/blake2s.h +68 -0
- package/native-src/src/crypto/chacha.c +312 -0
- package/native-src/src/crypto/chacha.h +66 -0
- package/native-src/src/crypto/chachapoly.c +214 -0
- package/native-src/src/crypto/chachapoly.h +101 -0
- package/native-src/src/crypto/curve25519.c +863 -0
- package/native-src/src/crypto/curve25519.h +68 -0
- package/native-src/src/crypto/hkdf.c +266 -0
- package/native-src/src/crypto/hkdf.h +141 -0
- package/native-src/src/crypto/poly1305.c +566 -0
- package/native-src/src/crypto/poly1305.h +36 -0
- package/native-src/src/crypto/sha256.c +189 -0
- package/native-src/src/crypto/sha256.h +54 -0
- package/native-src/src/crypto/sha512.c +206 -0
- package/native-src/src/crypto/sha512.h +54 -0
- package/native-src/src/dht.cpp +305 -57
- package/native-src/src/dht.h +46 -4
- package/native-src/src/gossipsub.cpp +5 -3
- package/native-src/src/ice.cpp +654 -1147
- package/native-src/src/ice.h +492 -261
- package/native-src/src/librats.cpp +390 -516
- package/native-src/src/librats.h +502 -319
- package/native-src/src/librats_bittorrent.cpp +54 -0
- package/native-src/src/librats_c.cpp +341 -120
- package/native-src/src/librats_c.h +106 -26
- package/native-src/src/librats_encryption.cpp +365 -65
- package/native-src/src/librats_ice.cpp +146 -452
- package/native-src/src/librats_persistence.cpp +2 -21
- package/native-src/src/librats_storage.cpp +189 -0
- package/native-src/src/noise.cpp +628 -808
- package/native-src/src/noise.h +334 -154
- package/native-src/src/socket.cpp +73 -71
- package/native-src/src/socket.h +7 -0
- package/native-src/src/storage.cpp +1468 -0
- package/native-src/src/storage.h +541 -0
- package/native-src/src/stun.cpp +992 -352
- package/native-src/src/stun.h +450 -311
- package/native-src/src/turn.cpp +764 -0
- package/native-src/src/turn.h +460 -0
- package/package.json +1 -1
- package/scripts/prepare-package.js +2 -2
- package/src/librats_node.cpp +275 -92
- package/native-src/src/encrypted_socket.cpp +0 -817
- package/native-src/src/encrypted_socket.h +0 -239
- package/native-src/src/librats_nat.cpp +0 -571
package/lib/index.d.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* LibRats Node.js Bindings - TypeScript Definitions
|
|
3
3
|
*
|
|
4
4
|
* High-performance peer-to-peer networking library with support for DHT, GossipSub,
|
|
5
|
-
* file transfer,
|
|
5
|
+
* file transfer, and more.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
/**
|
|
@@ -15,22 +15,6 @@ export interface VersionInfo {
|
|
|
15
15
|
build: number;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
/**
|
|
19
|
-
* Connection strategy options for connecting to peers
|
|
20
|
-
*/
|
|
21
|
-
export enum ConnectionStrategy {
|
|
22
|
-
/** Direct connection only, no NAT traversal */
|
|
23
|
-
DIRECT_ONLY = 0,
|
|
24
|
-
/** STUN-assisted connection */
|
|
25
|
-
STUN_ASSISTED = 1,
|
|
26
|
-
/** Full ICE negotiation with STUN and connection checks */
|
|
27
|
-
ICE_FULL = 2,
|
|
28
|
-
/** TURN relay connection */
|
|
29
|
-
TURN_RELAY = 3,
|
|
30
|
-
/** Automatic strategy selection based on network conditions */
|
|
31
|
-
AUTO_ADAPTIVE = 4
|
|
32
|
-
}
|
|
33
|
-
|
|
34
18
|
/**
|
|
35
19
|
* Error codes returned by various operations
|
|
36
20
|
*/
|
|
@@ -53,6 +37,39 @@ export enum ErrorCodes {
|
|
|
53
37
|
JSON_PARSE = -7
|
|
54
38
|
}
|
|
55
39
|
|
|
40
|
+
/**
|
|
41
|
+
* ICE connection states
|
|
42
|
+
*/
|
|
43
|
+
export enum IceConnectionState {
|
|
44
|
+
NEW = 0,
|
|
45
|
+
GATHERING = 1,
|
|
46
|
+
CHECKING = 2,
|
|
47
|
+
CONNECTED = 3,
|
|
48
|
+
COMPLETED = 4,
|
|
49
|
+
FAILED = 5,
|
|
50
|
+
DISCONNECTED = 6,
|
|
51
|
+
CLOSED = 7
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* ICE gathering states
|
|
56
|
+
*/
|
|
57
|
+
export enum IceGatheringState {
|
|
58
|
+
NEW = 0,
|
|
59
|
+
GATHERING = 1,
|
|
60
|
+
COMPLETE = 2
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* ICE candidate types
|
|
65
|
+
*/
|
|
66
|
+
export enum IceCandidateType {
|
|
67
|
+
HOST = 0,
|
|
68
|
+
SRFLX = 1,
|
|
69
|
+
PRFLX = 2,
|
|
70
|
+
RELAY = 3
|
|
71
|
+
}
|
|
72
|
+
|
|
56
73
|
/**
|
|
57
74
|
* Main RatsClient class for peer-to-peer networking
|
|
58
75
|
*/
|
|
@@ -84,15 +101,6 @@ export class RatsClient {
|
|
|
84
101
|
*/
|
|
85
102
|
connect(host: string, port: number): boolean;
|
|
86
103
|
|
|
87
|
-
/**
|
|
88
|
-
* Connect to a peer with a specific connection strategy
|
|
89
|
-
* @param host - IP address or hostname of the peer
|
|
90
|
-
* @param port - Port number of the peer
|
|
91
|
-
* @param strategy - Connection strategy to use
|
|
92
|
-
* @returns true if connection initiated successfully
|
|
93
|
-
*/
|
|
94
|
-
connectWithStrategy(host: string, port: number, strategy: ConnectionStrategy): boolean;
|
|
95
|
-
|
|
96
104
|
/**
|
|
97
105
|
* Disconnect from a peer
|
|
98
106
|
* @param peerId - ID of the peer to disconnect from
|
|
@@ -101,6 +109,12 @@ export class RatsClient {
|
|
|
101
109
|
|
|
102
110
|
// ============ Information ============
|
|
103
111
|
|
|
112
|
+
/**
|
|
113
|
+
* Get the port the client is listening on
|
|
114
|
+
* @returns Listen port number
|
|
115
|
+
*/
|
|
116
|
+
getListenPort(): number;
|
|
117
|
+
|
|
104
118
|
/**
|
|
105
119
|
* Get the number of connected peers
|
|
106
120
|
* @returns Number of connected peers
|
|
@@ -276,6 +290,13 @@ export class RatsClient {
|
|
|
276
290
|
*/
|
|
277
291
|
resumeFileTransfer(transferId: string): boolean;
|
|
278
292
|
|
|
293
|
+
/**
|
|
294
|
+
* Get file transfer progress information as JSON string
|
|
295
|
+
* @param transferId - ID of the transfer to query
|
|
296
|
+
* @returns JSON string with progress info, or null if not found
|
|
297
|
+
*/
|
|
298
|
+
getFileTransferProgress(transferId: string): string | null;
|
|
299
|
+
|
|
279
300
|
// ============ GossipSub ============
|
|
280
301
|
|
|
281
302
|
/**
|
|
@@ -340,6 +361,12 @@ export class RatsClient {
|
|
|
340
361
|
*/
|
|
341
362
|
getTopicPeers(topic: string): string[];
|
|
342
363
|
|
|
364
|
+
/**
|
|
365
|
+
* Get GossipSub statistics as JSON string
|
|
366
|
+
* @returns JSON string with statistics, or null if unavailable
|
|
367
|
+
*/
|
|
368
|
+
getGossipsubStatistics(): string | null;
|
|
369
|
+
|
|
343
370
|
// ============ DHT ============
|
|
344
371
|
|
|
345
372
|
/**
|
|
@@ -395,6 +422,20 @@ export class RatsClient {
|
|
|
395
422
|
*/
|
|
396
423
|
isMdnsRunning(): boolean;
|
|
397
424
|
|
|
425
|
+
/**
|
|
426
|
+
* Query for mDNS services
|
|
427
|
+
* @returns true if query sent successfully
|
|
428
|
+
*/
|
|
429
|
+
queryMdnsServices(): boolean;
|
|
430
|
+
|
|
431
|
+
// ============ Address Blocking ============
|
|
432
|
+
|
|
433
|
+
/**
|
|
434
|
+
* Add an IP address to the ignore list
|
|
435
|
+
* @param ipAddress - IP address to ignore
|
|
436
|
+
*/
|
|
437
|
+
addIgnoredAddress(ipAddress: string): void;
|
|
438
|
+
|
|
398
439
|
// ============ Encryption ============
|
|
399
440
|
|
|
400
441
|
/**
|
|
@@ -411,23 +452,157 @@ export class RatsClient {
|
|
|
411
452
|
isEncryptionEnabled(): boolean;
|
|
412
453
|
|
|
413
454
|
/**
|
|
414
|
-
*
|
|
415
|
-
* @
|
|
455
|
+
* Initialize encryption system
|
|
456
|
+
* @param enable - Whether to enable encryption
|
|
457
|
+
* @returns true if initialized successfully
|
|
416
458
|
*/
|
|
417
|
-
|
|
459
|
+
initializeEncryption(enable: boolean): boolean;
|
|
418
460
|
|
|
419
461
|
/**
|
|
420
|
-
*
|
|
421
|
-
* @param
|
|
462
|
+
* Check if a specific peer connection is encrypted
|
|
463
|
+
* @param peerId - Peer ID to check
|
|
464
|
+
* @returns true if peer connection is encrypted
|
|
465
|
+
*/
|
|
466
|
+
isPeerEncrypted(peerId: string): boolean;
|
|
467
|
+
|
|
468
|
+
/**
|
|
469
|
+
* Set custom Noise Protocol static keypair
|
|
470
|
+
* @param privateKeyHex - 32-byte private key as 64-char hex string
|
|
422
471
|
* @returns true if set successfully
|
|
423
472
|
*/
|
|
424
|
-
|
|
473
|
+
setNoiseStaticKeypair(privateKeyHex: string): boolean;
|
|
474
|
+
|
|
475
|
+
/**
|
|
476
|
+
* Get our Noise Protocol static public key
|
|
477
|
+
* @returns 64-char hex string, or null if not available
|
|
478
|
+
*/
|
|
479
|
+
getNoiseStaticPublicKey(): string | null;
|
|
480
|
+
|
|
481
|
+
/**
|
|
482
|
+
* Get remote peer's Noise static public key
|
|
483
|
+
* @param peerId - Peer ID to query
|
|
484
|
+
* @returns 64-char hex string, or null if not available
|
|
485
|
+
*/
|
|
486
|
+
getPeerNoisePublicKey(peerId: string): string | null;
|
|
487
|
+
|
|
488
|
+
/**
|
|
489
|
+
* Get handshake hash for channel binding
|
|
490
|
+
* @param peerId - Peer ID to query
|
|
491
|
+
* @returns 64-char hex string, or null if not available
|
|
492
|
+
*/
|
|
493
|
+
getPeerHandshakeHash(peerId: string): string | null;
|
|
494
|
+
|
|
495
|
+
// ============ ICE (NAT Traversal) ============
|
|
496
|
+
|
|
497
|
+
/**
|
|
498
|
+
* Check if ICE is available
|
|
499
|
+
* @returns true if ICE is available
|
|
500
|
+
*/
|
|
501
|
+
isIceAvailable(): boolean;
|
|
502
|
+
|
|
503
|
+
/**
|
|
504
|
+
* Add a STUN server for NAT traversal
|
|
505
|
+
* @param host - STUN server hostname or IP
|
|
506
|
+
* @param port - STUN server port (default: 3478)
|
|
507
|
+
*/
|
|
508
|
+
addStunServer(host: string, port?: number): void;
|
|
509
|
+
|
|
510
|
+
/**
|
|
511
|
+
* Add a TURN server for relay-based NAT traversal
|
|
512
|
+
* @param host - TURN server hostname or IP
|
|
513
|
+
* @param port - TURN server port
|
|
514
|
+
* @param username - TURN username
|
|
515
|
+
* @param password - TURN password
|
|
516
|
+
*/
|
|
517
|
+
addTurnServer(host: string, port: number, username: string, password: string): void;
|
|
518
|
+
|
|
519
|
+
/**
|
|
520
|
+
* Clear all ICE (STUN/TURN) servers
|
|
521
|
+
*/
|
|
522
|
+
clearIceServers(): void;
|
|
523
|
+
|
|
524
|
+
/**
|
|
525
|
+
* Start gathering ICE candidates
|
|
526
|
+
* @returns true if gathering started successfully
|
|
527
|
+
*/
|
|
528
|
+
gatherIceCandidates(): boolean;
|
|
529
|
+
|
|
530
|
+
/**
|
|
531
|
+
* Get local ICE candidates as JSON string
|
|
532
|
+
* @returns JSON string of candidates, or null if unavailable
|
|
533
|
+
*/
|
|
534
|
+
getIceCandidates(): string | null;
|
|
535
|
+
|
|
536
|
+
/**
|
|
537
|
+
* Check if ICE candidate gathering is complete
|
|
538
|
+
* @returns true if gathering is complete
|
|
539
|
+
*/
|
|
540
|
+
isIceGatheringComplete(): boolean;
|
|
541
|
+
|
|
542
|
+
/**
|
|
543
|
+
* Get public address discovered via STUN
|
|
544
|
+
* @returns Address string (ip:port), or null if not discovered
|
|
545
|
+
*/
|
|
546
|
+
getPublicAddress(): string | null;
|
|
547
|
+
|
|
548
|
+
/**
|
|
549
|
+
* Perform a simple STUN binding request to discover public address
|
|
550
|
+
* @param stunServer - STUN server hostname (default: "stun.l.google.com")
|
|
551
|
+
* @param port - STUN server port (default: 19302)
|
|
552
|
+
* @param timeoutMs - Timeout in milliseconds (default: 5000)
|
|
553
|
+
* @returns Address string (ip:port), or null on failure
|
|
554
|
+
*/
|
|
555
|
+
discoverPublicAddress(stunServer?: string, port?: number, timeoutMs?: number): string | null;
|
|
556
|
+
|
|
557
|
+
/**
|
|
558
|
+
* Add a remote ICE candidate from SDP
|
|
559
|
+
* @param candidateSdp - SDP candidate string
|
|
560
|
+
*/
|
|
561
|
+
addRemoteIceCandidate(candidateSdp: string): void;
|
|
562
|
+
|
|
563
|
+
/**
|
|
564
|
+
* Signal end of remote ICE candidates (trickle ICE complete)
|
|
565
|
+
*/
|
|
566
|
+
endOfRemoteIceCandidates(): void;
|
|
567
|
+
|
|
568
|
+
/**
|
|
569
|
+
* Start ICE connectivity checks
|
|
570
|
+
*/
|
|
571
|
+
startIceChecks(): void;
|
|
572
|
+
|
|
573
|
+
/**
|
|
574
|
+
* Get current ICE connection state
|
|
575
|
+
* @returns ICE connection state value
|
|
576
|
+
*/
|
|
577
|
+
getIceConnectionState(): number;
|
|
578
|
+
|
|
579
|
+
/**
|
|
580
|
+
* Get ICE gathering state
|
|
581
|
+
* @returns ICE gathering state value
|
|
582
|
+
*/
|
|
583
|
+
getIceGatheringState(): number;
|
|
584
|
+
|
|
585
|
+
/**
|
|
586
|
+
* Check if ICE is connected
|
|
587
|
+
* @returns true if ICE connection is established
|
|
588
|
+
*/
|
|
589
|
+
isIceConnected(): boolean;
|
|
590
|
+
|
|
591
|
+
/**
|
|
592
|
+
* Get the selected ICE candidate pair as JSON string
|
|
593
|
+
* @returns JSON string of selected pair, or null if unavailable
|
|
594
|
+
*/
|
|
595
|
+
getIceSelectedPair(): string | null;
|
|
596
|
+
|
|
597
|
+
/**
|
|
598
|
+
* Close ICE manager and release resources
|
|
599
|
+
*/
|
|
600
|
+
closeIce(): void;
|
|
425
601
|
|
|
426
602
|
/**
|
|
427
|
-
*
|
|
428
|
-
* @returns Hex-encoded encryption key, or null if not set
|
|
603
|
+
* Restart ICE (re-gather candidates and restart checks)
|
|
429
604
|
*/
|
|
430
|
-
|
|
605
|
+
restartIce(): void;
|
|
431
606
|
|
|
432
607
|
// ============ Configuration Persistence ============
|
|
433
608
|
|
|
@@ -82,6 +82,7 @@ option(RATS_CROSSCOMPILING "Force cross-compilation flags" OFF)
|
|
|
82
82
|
option(RATS_SHARED_LIBRARY "Build as shared library" OFF)
|
|
83
83
|
option(RATS_STATIC_LIBRARY "Build as static library" ON)
|
|
84
84
|
option(RATS_SEARCH_FEATURES "Features related to rats-search project (like bittorrent)" OFF)
|
|
85
|
+
option(RATS_STORAGE "Enable distributed storage module" OFF)
|
|
85
86
|
|
|
86
87
|
# Validate library type options
|
|
87
88
|
if(RATS_SHARED_LIBRARY AND RATS_STATIC_LIBRARY)
|
|
@@ -128,30 +129,20 @@ set(LIBRARY_SOURCES
|
|
|
128
129
|
src/krpc.h
|
|
129
130
|
src/librats.cpp
|
|
130
131
|
src/librats_logging.cpp
|
|
132
|
+
src/librats_encryption.cpp
|
|
131
133
|
src/librats_file_transfer.cpp
|
|
132
134
|
src/librats_gossipsub.cpp
|
|
133
|
-
src/librats_nat.cpp
|
|
134
|
-
src/librats_ice.cpp
|
|
135
135
|
src/librats_mdns.cpp
|
|
136
136
|
src/librats_persistence.cpp
|
|
137
|
-
src/librats_encryption.cpp
|
|
138
137
|
src/librats.h
|
|
139
138
|
src/sha1.cpp
|
|
140
139
|
src/sha1.h
|
|
141
140
|
src/os.cpp
|
|
142
141
|
src/os.h
|
|
143
|
-
src/stun.cpp
|
|
144
|
-
src/stun.h
|
|
145
|
-
src/ice.cpp
|
|
146
|
-
src/ice.h
|
|
147
142
|
src/fs.cpp
|
|
148
143
|
src/fs.h
|
|
149
144
|
src/logger.h
|
|
150
145
|
src/logger.cpp
|
|
151
|
-
src/noise.cpp
|
|
152
|
-
src/noise.h
|
|
153
|
-
src/encrypted_socket.cpp
|
|
154
|
-
src/encrypted_socket.h
|
|
155
146
|
src/mdns.cpp
|
|
156
147
|
src/mdns.h
|
|
157
148
|
src/threadmanager.cpp
|
|
@@ -163,6 +154,40 @@ set(LIBRARY_SOURCES
|
|
|
163
154
|
src/version.cpp
|
|
164
155
|
src/rats_export.h
|
|
165
156
|
${PROJECT_BINARY_DIR}/src/version.h
|
|
157
|
+
|
|
158
|
+
# Cypto algorithms including Noise Protocol needed
|
|
159
|
+
src/crypto/curve25519.c
|
|
160
|
+
src/crypto/curve25519.h
|
|
161
|
+
src/crypto/chacha.c
|
|
162
|
+
src/crypto/chacha.h
|
|
163
|
+
src/crypto/poly1305.c
|
|
164
|
+
src/crypto/poly1305.h
|
|
165
|
+
src/crypto/chachapoly.c
|
|
166
|
+
src/crypto/chachapoly.h
|
|
167
|
+
src/crypto/sha256.c
|
|
168
|
+
src/crypto/sha256.h
|
|
169
|
+
src/crypto/sha512.c
|
|
170
|
+
src/crypto/sha512.h
|
|
171
|
+
src/crypto/hkdf.c
|
|
172
|
+
src/crypto/hkdf.h
|
|
173
|
+
src/crypto/blake2s.c
|
|
174
|
+
src/crypto/blake2s.h
|
|
175
|
+
src/crypto/blake2b.c
|
|
176
|
+
src/crypto/blake2b.h
|
|
177
|
+
src/crypto/blake2_endian.h
|
|
178
|
+
|
|
179
|
+
# Noise Protocol implementation
|
|
180
|
+
src/noise.cpp
|
|
181
|
+
src/noise.h
|
|
182
|
+
|
|
183
|
+
# NAT traversal (STUN/TURN/ICE)
|
|
184
|
+
src/stun.cpp
|
|
185
|
+
src/stun.h
|
|
186
|
+
src/turn.cpp
|
|
187
|
+
src/turn.h
|
|
188
|
+
src/ice.cpp
|
|
189
|
+
src/ice.h
|
|
190
|
+
src/librats_ice.cpp
|
|
166
191
|
)
|
|
167
192
|
|
|
168
193
|
# Add BitTorrent sources if RATS_SEARCH_FEATURES is enabled
|
|
@@ -176,6 +201,17 @@ if(RATS_SEARCH_FEATURES)
|
|
|
176
201
|
)
|
|
177
202
|
endif()
|
|
178
203
|
|
|
204
|
+
# Add Storage sources if RATS_STORAGE is enabled
|
|
205
|
+
if(RATS_STORAGE)
|
|
206
|
+
list(APPEND LIBRARY_SOURCES
|
|
207
|
+
src/crc32.cpp
|
|
208
|
+
src/crc32.h
|
|
209
|
+
src/storage.cpp
|
|
210
|
+
src/storage.h
|
|
211
|
+
src/librats_storage.cpp
|
|
212
|
+
)
|
|
213
|
+
endif()
|
|
214
|
+
|
|
179
215
|
if(RATS_BINDINGS)
|
|
180
216
|
list(APPEND LIBRARY_SOURCES
|
|
181
217
|
src/librats_c.cpp
|
|
@@ -200,6 +236,7 @@ set_target_properties(rats PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
|
|
200
236
|
|
|
201
237
|
# Include directories
|
|
202
238
|
target_include_directories(rats PUBLIC ${PROJECT_BINARY_DIR}/src src)
|
|
239
|
+
target_include_directories(rats PUBLIC ${PROJECT_SOURCE_DIR}/src/crypto)
|
|
203
240
|
|
|
204
241
|
# Find and link threading support
|
|
205
242
|
find_package(Threads REQUIRED)
|
|
@@ -235,6 +272,11 @@ if(RATS_SEARCH_FEATURES)
|
|
|
235
272
|
target_compile_definitions(rats PUBLIC RATS_SEARCH_FEATURES)
|
|
236
273
|
endif(RATS_SEARCH_FEATURES)
|
|
237
274
|
|
|
275
|
+
if(RATS_STORAGE)
|
|
276
|
+
message(STATUS "Enable distributed storage module")
|
|
277
|
+
target_compile_definitions(rats PUBLIC RATS_STORAGE)
|
|
278
|
+
endif(RATS_STORAGE)
|
|
279
|
+
|
|
238
280
|
# Create the main executable
|
|
239
281
|
if(RATS_BUILD_EXAMPLES)
|
|
240
282
|
add_executable(rats-client src/main.cpp)
|
|
@@ -311,16 +353,23 @@ if(RATS_BUILD_TESTS)
|
|
|
311
353
|
tests/test_dht.cpp
|
|
312
354
|
tests/test_rats_client.cpp
|
|
313
355
|
tests/test_os.cpp
|
|
314
|
-
tests/test_stun.cpp
|
|
315
|
-
tests/test_ice.cpp
|
|
316
356
|
tests/test_fs.cpp
|
|
317
357
|
tests/test_config_persistence.cpp
|
|
318
358
|
tests/test_main.cpp
|
|
319
359
|
tests/test_message_exchange.cpp
|
|
320
|
-
tests/test_noise.cpp
|
|
321
360
|
tests/test_gossipsub.cpp
|
|
322
361
|
tests/test_logging_api_gtest.cpp
|
|
323
362
|
tests/test_file_transfer.cpp
|
|
363
|
+
# Noise Protocol Crypto tests
|
|
364
|
+
tests/test_crypto_curve25519.cpp
|
|
365
|
+
tests/test_crypto_chacha_poly.cpp
|
|
366
|
+
tests/test_crypto_sha2.cpp
|
|
367
|
+
tests/test_crypto_blake2.cpp
|
|
368
|
+
tests/test_noise.cpp
|
|
369
|
+
# NAT traversal tests (STUN/TURN/ICE)
|
|
370
|
+
tests/test_stun.cpp
|
|
371
|
+
tests/test_turn.cpp
|
|
372
|
+
tests/test_ice.cpp
|
|
324
373
|
)
|
|
325
374
|
|
|
326
375
|
# Add BitTorrent tests if RATS_SEARCH_FEATURES is enabled
|
|
@@ -331,6 +380,14 @@ if(RATS_BUILD_TESTS)
|
|
|
331
380
|
)
|
|
332
381
|
endif()
|
|
333
382
|
|
|
383
|
+
# Add Storage tests if RATS_STORAGE is enabled
|
|
384
|
+
if(RATS_STORAGE)
|
|
385
|
+
list(APPEND TEST_SOURCES
|
|
386
|
+
tests/test_crc32.cpp
|
|
387
|
+
tests/test_storage.cpp
|
|
388
|
+
)
|
|
389
|
+
endif()
|
|
390
|
+
|
|
334
391
|
if(RATS_BINDINGS)
|
|
335
392
|
list(APPEND TEST_SOURCES
|
|
336
393
|
tests/test_librats_c_api.cpp
|
package/native-src/LICENSE
CHANGED
|
@@ -487,12 +487,15 @@ void PeerConnection::connection_loop() {
|
|
|
487
487
|
// Create socket if not already provided (outgoing connection)
|
|
488
488
|
// This is done in the thread to avoid blocking the caller
|
|
489
489
|
if (!is_valid_socket(socket_)) {
|
|
490
|
+
LOG_BT_DEBUG("Creating TCP connection to " << peer_info_.ip << ":" << peer_info_.port << " (5s timeout)");
|
|
490
491
|
socket_ = create_tcp_client(peer_info_.ip, peer_info_.port, 5000); // 5-second timeout for faster failure
|
|
491
492
|
if (!is_valid_socket(socket_)) {
|
|
492
|
-
LOG_BT_ERROR("Failed to create connection to " << peer_info_.ip << ":" << peer_info_.port
|
|
493
|
+
LOG_BT_ERROR("Failed to create connection to " << peer_info_.ip << ":" << peer_info_.port
|
|
494
|
+
<< " - connection timed out or refused");
|
|
493
495
|
state_.store(PeerState::ERROR);
|
|
494
496
|
return;
|
|
495
497
|
}
|
|
498
|
+
LOG_BT_DEBUG("TCP connection established to " << peer_info_.ip << ":" << peer_info_.port);
|
|
496
499
|
}
|
|
497
500
|
|
|
498
501
|
// Perform handshake only if not already completed (for outgoing connections)
|
|
@@ -3566,6 +3569,155 @@ void BitTorrentClient::get_torrent_metadata_by_hash(const std::string& info_hash
|
|
|
3566
3569
|
get_torrent_metadata_by_hash(info_hash, callback);
|
|
3567
3570
|
}
|
|
3568
3571
|
|
|
3572
|
+
void BitTorrentClient::get_torrent_metadata_from_peer(const InfoHash& info_hash,
|
|
3573
|
+
const std::string& peer_ip,
|
|
3574
|
+
uint16_t peer_port,
|
|
3575
|
+
MetadataRetrievalCallback callback) {
|
|
3576
|
+
if (!running_.load()) {
|
|
3577
|
+
LOG_BT_ERROR("BitTorrent client is not running");
|
|
3578
|
+
if (callback) {
|
|
3579
|
+
callback(TorrentInfo(), false, "BitTorrent client is not running");
|
|
3580
|
+
}
|
|
3581
|
+
return;
|
|
3582
|
+
}
|
|
3583
|
+
|
|
3584
|
+
LOG_BT_INFO("Retrieving metadata for hash " << info_hash_to_hex(info_hash)
|
|
3585
|
+
<< " directly from peer " << peer_ip << ":" << peer_port);
|
|
3586
|
+
|
|
3587
|
+
// Check if metadata retrieval already in progress for this hash
|
|
3588
|
+
{
|
|
3589
|
+
std::lock_guard<std::mutex> lock(metadata_mutex_);
|
|
3590
|
+
if (metadata_only_torrents_.find(info_hash) != metadata_only_torrents_.end()) {
|
|
3591
|
+
LOG_BT_DEBUG("Metadata retrieval already in progress for hash: " << info_hash_to_hex(info_hash));
|
|
3592
|
+
// Just add this peer to the existing download attempt
|
|
3593
|
+
auto it = metadata_only_torrents_.find(info_hash);
|
|
3594
|
+
if (it != metadata_only_torrents_.end()) {
|
|
3595
|
+
Peer peer{peer_ip, peer_port};
|
|
3596
|
+
it->second->add_peer(peer);
|
|
3597
|
+
LOG_BT_INFO("Added peer " << peer_ip << ":" << peer_port << " to existing metadata download");
|
|
3598
|
+
}
|
|
3599
|
+
return;
|
|
3600
|
+
}
|
|
3601
|
+
|
|
3602
|
+
// Store the callback
|
|
3603
|
+
metadata_retrieval_callbacks_[info_hash] = callback;
|
|
3604
|
+
}
|
|
3605
|
+
|
|
3606
|
+
// Create a minimal TorrentInfo for metadata exchange
|
|
3607
|
+
TorrentInfo metadata_torrent_info = TorrentInfo::create_for_metadata_exchange(info_hash);
|
|
3608
|
+
|
|
3609
|
+
// Create a temporary torrent download for metadata exchange only
|
|
3610
|
+
auto metadata_torrent = std::make_shared<TorrentDownload>(metadata_torrent_info, ""); // No download path needed
|
|
3611
|
+
|
|
3612
|
+
// Set up metadata completion callback
|
|
3613
|
+
// IMPORTANT: This callback is invoked from within a PeerConnection's thread, so we must NOT
|
|
3614
|
+
// call stop() directly (which would try to join the calling thread, causing a deadlock).
|
|
3615
|
+
// Instead, we defer the cleanup to a detached thread.
|
|
3616
|
+
metadata_torrent->set_metadata_complete_callback([this, info_hash](const TorrentInfo& torrent_info) {
|
|
3617
|
+
LOG_BT_INFO("Metadata retrieval (direct) completed for " << torrent_info.get_name());
|
|
3618
|
+
|
|
3619
|
+
// Capture torrent_info by value since we're deferring to another thread
|
|
3620
|
+
TorrentInfo captured_info = torrent_info;
|
|
3621
|
+
|
|
3622
|
+
// Defer stop() and cleanup to a separate thread to avoid deadlock
|
|
3623
|
+
std::thread([this, info_hash, captured_info]() {
|
|
3624
|
+
MetadataRetrievalCallback user_callback;
|
|
3625
|
+
std::shared_ptr<TorrentDownload> temp_torrent;
|
|
3626
|
+
|
|
3627
|
+
// Get callback and cleanup
|
|
3628
|
+
{
|
|
3629
|
+
std::lock_guard<std::mutex> lock(metadata_mutex_);
|
|
3630
|
+
auto it = metadata_retrieval_callbacks_.find(info_hash);
|
|
3631
|
+
if (it != metadata_retrieval_callbacks_.end()) {
|
|
3632
|
+
user_callback = it->second;
|
|
3633
|
+
metadata_retrieval_callbacks_.erase(it);
|
|
3634
|
+
}
|
|
3635
|
+
|
|
3636
|
+
// Get temporary torrent to stop it
|
|
3637
|
+
auto torrent_it = metadata_only_torrents_.find(info_hash);
|
|
3638
|
+
if (torrent_it != metadata_only_torrents_.end()) {
|
|
3639
|
+
temp_torrent = torrent_it->second;
|
|
3640
|
+
metadata_only_torrents_.erase(torrent_it);
|
|
3641
|
+
}
|
|
3642
|
+
}
|
|
3643
|
+
|
|
3644
|
+
// Stop the temporary torrent
|
|
3645
|
+
if (temp_torrent) {
|
|
3646
|
+
temp_torrent->stop();
|
|
3647
|
+
}
|
|
3648
|
+
|
|
3649
|
+
// Call user callback with success
|
|
3650
|
+
if (user_callback) {
|
|
3651
|
+
user_callback(captured_info, true, "");
|
|
3652
|
+
}
|
|
3653
|
+
}).detach();
|
|
3654
|
+
});
|
|
3655
|
+
|
|
3656
|
+
// Store the temporary torrent
|
|
3657
|
+
{
|
|
3658
|
+
std::lock_guard<std::mutex> lock(metadata_mutex_);
|
|
3659
|
+
metadata_only_torrents_[info_hash] = metadata_torrent;
|
|
3660
|
+
}
|
|
3661
|
+
|
|
3662
|
+
// Start the metadata torrent (just for peer connections)
|
|
3663
|
+
if (!metadata_torrent->start()) {
|
|
3664
|
+
LOG_BT_ERROR("Failed to start metadata retrieval torrent");
|
|
3665
|
+
|
|
3666
|
+
// Cleanup and call callback with error
|
|
3667
|
+
{
|
|
3668
|
+
std::lock_guard<std::mutex> lock(metadata_mutex_);
|
|
3669
|
+
metadata_only_torrents_.erase(info_hash);
|
|
3670
|
+
auto it = metadata_retrieval_callbacks_.find(info_hash);
|
|
3671
|
+
if (it != metadata_retrieval_callbacks_.end()) {
|
|
3672
|
+
if (it->second) {
|
|
3673
|
+
it->second(TorrentInfo(), false, "Failed to start metadata retrieval");
|
|
3674
|
+
}
|
|
3675
|
+
metadata_retrieval_callbacks_.erase(it);
|
|
3676
|
+
}
|
|
3677
|
+
}
|
|
3678
|
+
return;
|
|
3679
|
+
}
|
|
3680
|
+
|
|
3681
|
+
// Directly connect to the specified peer - no DHT search needed!
|
|
3682
|
+
Peer peer{peer_ip, peer_port};
|
|
3683
|
+
LOG_BT_INFO("Connecting directly to peer " << peer_ip << ":" << peer_port << " for metadata exchange");
|
|
3684
|
+
|
|
3685
|
+
if (metadata_torrent->add_peer(peer)) {
|
|
3686
|
+
LOG_BT_INFO("Successfully initiated connection to peer " << peer_ip << ":" << peer_port);
|
|
3687
|
+
} else {
|
|
3688
|
+
LOG_BT_WARN("Failed to add peer " << peer_ip << ":" << peer_port << " - metadata retrieval may fail");
|
|
3689
|
+
// Don't fail immediately - the peer connection might still work
|
|
3690
|
+
}
|
|
3691
|
+
|
|
3692
|
+
LOG_BT_INFO("Metadata retrieval (direct) initiated for hash " << info_hash_to_hex(info_hash));
|
|
3693
|
+
}
|
|
3694
|
+
|
|
3695
|
+
void BitTorrentClient::get_torrent_metadata_from_peer(const std::string& info_hash_hex,
|
|
3696
|
+
const std::string& peer_ip,
|
|
3697
|
+
uint16_t peer_port,
|
|
3698
|
+
MetadataRetrievalCallback callback) {
|
|
3699
|
+
InfoHash info_hash = hex_to_info_hash(info_hash_hex);
|
|
3700
|
+
|
|
3701
|
+
// Validate the parsed hash
|
|
3702
|
+
bool is_zero = true;
|
|
3703
|
+
for (const auto& byte : info_hash) {
|
|
3704
|
+
if (byte != 0) {
|
|
3705
|
+
is_zero = false;
|
|
3706
|
+
break;
|
|
3707
|
+
}
|
|
3708
|
+
}
|
|
3709
|
+
|
|
3710
|
+
if (is_zero && info_hash_hex.length() == 40) {
|
|
3711
|
+
LOG_BT_ERROR("Invalid info hash format: " << info_hash_hex);
|
|
3712
|
+
if (callback) {
|
|
3713
|
+
callback(TorrentInfo(), false, "Invalid info hash format");
|
|
3714
|
+
}
|
|
3715
|
+
return;
|
|
3716
|
+
}
|
|
3717
|
+
|
|
3718
|
+
get_torrent_metadata_from_peer(info_hash, peer_ip, peer_port, callback);
|
|
3719
|
+
}
|
|
3720
|
+
|
|
3569
3721
|
//=============================================================================
|
|
3570
3722
|
// Utility Functions Implementation
|
|
3571
3723
|
//=============================================================================
|
|
@@ -679,6 +679,31 @@ public:
|
|
|
679
679
|
void get_torrent_metadata_by_hash(const InfoHash& info_hash, MetadataRetrievalCallback callback);
|
|
680
680
|
void get_torrent_metadata_by_hash(const std::string& info_hash_hex, MetadataRetrievalCallback callback);
|
|
681
681
|
|
|
682
|
+
/**
|
|
683
|
+
* Get torrent metadata directly from a specific peer (fast path - no DHT search needed)
|
|
684
|
+
* This is more efficient when you already know a peer that has the torrent (e.g., from announce_peer)
|
|
685
|
+
* @param info_hash Info hash of the torrent
|
|
686
|
+
* @param peer_ip IP address of the peer
|
|
687
|
+
* @param peer_port Port of the peer
|
|
688
|
+
* @param callback Function called when metadata is retrieved (torrent_info, success, error_message)
|
|
689
|
+
*/
|
|
690
|
+
void get_torrent_metadata_from_peer(const InfoHash& info_hash,
|
|
691
|
+
const std::string& peer_ip,
|
|
692
|
+
uint16_t peer_port,
|
|
693
|
+
MetadataRetrievalCallback callback);
|
|
694
|
+
|
|
695
|
+
/**
|
|
696
|
+
* Get torrent metadata directly from a specific peer by hex string (fast path)
|
|
697
|
+
* @param info_hash_hex Info hash as 40-character hex string
|
|
698
|
+
* @param peer_ip IP address of the peer
|
|
699
|
+
* @param peer_port Port of the peer
|
|
700
|
+
* @param callback Function called when metadata is retrieved (torrent_info, success, error_message)
|
|
701
|
+
*/
|
|
702
|
+
void get_torrent_metadata_from_peer(const std::string& info_hash_hex,
|
|
703
|
+
const std::string& peer_ip,
|
|
704
|
+
uint16_t peer_port,
|
|
705
|
+
MetadataRetrievalCallback callback);
|
|
706
|
+
|
|
682
707
|
private:
|
|
683
708
|
std::atomic<bool> running_;
|
|
684
709
|
int listen_port_;
|