librats 1.0.2 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +145 -331
- package/binding.gyp +16 -3
- package/lib/index.d.ts +288 -696
- package/lib/index.js +407 -44
- package/native-src/3rdparty/android/ifaddrs-android.c +1 -0
- package/native-src/3rdparty/android/ifaddrs-android.h +1 -0
- package/native-src/CMakeLists.txt +404 -179
- package/native-src/LICENSE +1 -1
- package/native-src/src/librats/bindings/rats.cpp +762 -0
- package/native-src/src/librats/bindings/rats.h +380 -0
- package/native-src/src/librats/bittorrent/bencode.cpp +437 -0
- package/native-src/src/librats/bittorrent/bencode.h +176 -0
- package/native-src/src/librats/bittorrent/bitfield.cpp +97 -0
- package/native-src/src/librats/bittorrent/bitfield.h +76 -0
- package/native-src/src/librats/bittorrent/byte_io.h +58 -0
- package/native-src/src/librats/bittorrent/choker.cpp +25 -0
- package/native-src/src/librats/bittorrent/choker.h +46 -0
- package/native-src/src/librats/bittorrent/client.cpp +413 -0
- package/native-src/src/librats/bittorrent/client.h +227 -0
- package/native-src/src/librats/bittorrent/disk_io.cpp +209 -0
- package/native-src/src/librats/bittorrent/disk_io.h +150 -0
- package/native-src/src/librats/bittorrent/extensions.cpp +191 -0
- package/native-src/src/librats/bittorrent/extensions.h +94 -0
- package/native-src/src/librats/bittorrent/file_storage.cpp +77 -0
- package/native-src/src/librats/bittorrent/file_storage.h +79 -0
- package/native-src/src/librats/bittorrent/log.h +42 -0
- package/native-src/src/librats/bittorrent/magnet_uri.cpp +98 -0
- package/native-src/src/librats/bittorrent/magnet_uri.h +35 -0
- package/native-src/src/librats/bittorrent/peer_connection.cpp +502 -0
- package/native-src/src/librats/bittorrent/peer_connection.h +194 -0
- package/native-src/src/librats/bittorrent/peer_list.cpp +68 -0
- package/native-src/src/librats/bittorrent/peer_list.h +75 -0
- package/native-src/src/librats/bittorrent/piece_picker.cpp +352 -0
- package/native-src/src/librats/bittorrent/piece_picker.h +201 -0
- package/native-src/src/librats/bittorrent/reactor.cpp +97 -0
- package/native-src/src/librats/bittorrent/reactor.h +89 -0
- package/native-src/src/librats/bittorrent/resume_data.cpp +72 -0
- package/native-src/src/librats/bittorrent/resume_data.h +41 -0
- package/native-src/src/librats/bittorrent/store_buffer.cpp +48 -0
- package/native-src/src/librats/bittorrent/store_buffer.h +47 -0
- package/native-src/src/librats/bittorrent/torrent.cpp +870 -0
- package/native-src/src/librats/bittorrent/torrent.h +260 -0
- package/native-src/src/librats/bittorrent/torrent_creator.cpp +129 -0
- package/native-src/src/librats/bittorrent/torrent_creator.h +58 -0
- package/native-src/src/librats/bittorrent/torrent_info.cpp +314 -0
- package/native-src/src/librats/bittorrent/torrent_info.h +118 -0
- package/native-src/src/librats/bittorrent/tracker.cpp +374 -0
- package/native-src/src/librats/bittorrent/tracker.h +108 -0
- package/native-src/src/librats/bittorrent/types.cpp +206 -0
- package/native-src/src/librats/bittorrent/types.h +86 -0
- package/native-src/src/librats/core/address.cpp +35 -0
- package/native-src/src/librats/core/address.h +78 -0
- package/native-src/src/librats/core/bytes.h +69 -0
- package/native-src/src/librats/core/chained_send_buffer.cpp +172 -0
- package/native-src/src/librats/core/chained_send_buffer.h +183 -0
- package/native-src/src/librats/core/endpoint_parse.cpp +41 -0
- package/native-src/src/librats/core/endpoint_parse.h +31 -0
- package/native-src/src/librats/core/event_bus.h +70 -0
- package/native-src/src/librats/core/host_endpoint.h +56 -0
- package/native-src/src/{io_poller.cpp → librats/core/io_poller.cpp} +520 -65
- package/native-src/src/{io_poller.h → librats/core/io_poller.h} +12 -6
- package/native-src/src/librats/core/ip_address.cpp +120 -0
- package/native-src/src/librats/core/ip_address.h +109 -0
- package/native-src/src/librats/core/mpsc_queue.h +47 -0
- package/native-src/src/librats/core/notifier.h +74 -0
- package/native-src/src/librats/core/receive_buffer.cpp +219 -0
- package/native-src/src/librats/core/receive_buffer.h +171 -0
- package/native-src/src/librats/core/service_registry.h +58 -0
- package/native-src/src/{socket.cpp → librats/core/socket.cpp} +625 -118
- package/native-src/src/librats/core/socket.h +496 -0
- package/native-src/src/librats/core/timer_queue.h +105 -0
- package/native-src/src/librats/core/types.cpp +43 -0
- package/native-src/src/librats/core/types.h +103 -0
- package/native-src/src/librats/core/wakeup_pipe.h +83 -0
- package/native-src/src/{crypto → librats/crypto}/blake2_endian.h +21 -23
- package/native-src/src/{crypto → librats/crypto}/blake2b.c +34 -33
- package/native-src/src/{crypto → librats/crypto}/blake2b.h +7 -6
- package/native-src/src/{crypto → librats/crypto}/blake2s.c +55 -54
- package/native-src/src/{crypto → librats/crypto}/blake2s.h +13 -12
- package/native-src/src/{crypto → librats/crypto}/chacha.c +22 -21
- package/native-src/src/{crypto → librats/crypto}/chacha.h +14 -13
- package/native-src/src/{crypto → librats/crypto}/chachapoly.c +56 -56
- package/native-src/src/{crypto → librats/crypto}/chachapoly.h +24 -17
- package/native-src/src/{crc32.cpp → librats/crypto/crc32.cpp} +1 -1
- package/native-src/src/{crc32.h → librats/crypto/crc32.h} +3 -1
- package/native-src/src/{crypto → librats/crypto}/curve25519.c +6 -4
- package/native-src/src/{crypto → librats/crypto}/curve25519.h +6 -3
- package/native-src/src/librats/crypto/hkdf.c +266 -0
- package/native-src/src/{crypto → librats/crypto}/hkdf.h +19 -19
- package/native-src/src/{noise.cpp → librats/crypto/noise.cpp} +84 -73
- package/native-src/src/{noise.h → librats/crypto/noise.h} +18 -8
- package/native-src/src/{crypto → librats/crypto}/poly1305.c +47 -46
- package/native-src/src/librats/crypto/poly1305.h +37 -0
- package/native-src/src/{sha1.cpp → librats/crypto/sha1.cpp} +33 -1
- package/native-src/src/{sha1.h → librats/crypto/sha1.h} +14 -6
- package/native-src/src/{crypto → librats/crypto}/sha256.c +15 -14
- package/native-src/src/{crypto → librats/crypto}/sha256.h +8 -7
- package/native-src/src/{crypto → librats/crypto}/sha512.c +15 -14
- package/native-src/src/{crypto → librats/crypto}/sha512.h +8 -7
- package/native-src/src/librats/dht/announce.cpp +37 -0
- package/native-src/src/librats/dht/announce.h +41 -0
- package/native-src/src/librats/dht/bep42.cpp +109 -0
- package/native-src/src/librats/dht/bep42.h +48 -0
- package/native-src/src/librats/dht/dht.cpp +501 -0
- package/native-src/src/librats/dht/dht.h +119 -0
- package/native-src/src/librats/dht/dht_runner.cpp +103 -0
- package/native-src/src/librats/dht/dht_runner.h +71 -0
- package/native-src/src/librats/dht/dos_blocker.cpp +42 -0
- package/native-src/src/librats/dht/dos_blocker.h +47 -0
- package/native-src/src/librats/dht/find_peers.cpp +52 -0
- package/native-src/src/librats/dht/find_peers.h +73 -0
- package/native-src/src/librats/dht/id.h +167 -0
- package/native-src/src/{krpc.cpp → librats/dht/krpc.cpp} +32 -81
- package/native-src/src/{krpc.h → librats/dht/krpc.h} +19 -23
- package/native-src/src/librats/dht/log.h +38 -0
- package/native-src/src/librats/dht/node.cpp +473 -0
- package/native-src/src/librats/dht/node.h +164 -0
- package/native-src/src/librats/dht/node_entry.h +81 -0
- package/native-src/src/librats/dht/observer.h +72 -0
- package/native-src/src/librats/dht/persistence.cpp +90 -0
- package/native-src/src/librats/dht/persistence.h +32 -0
- package/native-src/src/librats/dht/routing_table.cpp +559 -0
- package/native-src/src/librats/dht/routing_table.h +185 -0
- package/native-src/src/librats/dht/rpc_manager.cpp +127 -0
- package/native-src/src/librats/dht/rpc_manager.h +77 -0
- package/native-src/src/librats/dht/storage.cpp +92 -0
- package/native-src/src/librats/dht/storage.h +74 -0
- package/native-src/src/librats/dht/transport.h +27 -0
- package/native-src/src/librats/dht/traversal.cpp +326 -0
- package/native-src/src/librats/dht/traversal.h +120 -0
- package/native-src/src/librats/dht/udp_transport.cpp +49 -0
- package/native-src/src/librats/dht/udp_transport.h +51 -0
- package/native-src/src/librats/mdns/log.h +22 -0
- package/native-src/src/{mdns.cpp → librats/mdns/mdns.cpp} +75 -40
- package/native-src/src/{mdns.h → librats/mdns/mdns.h} +9 -8
- package/native-src/src/{natpmp.cpp → librats/nat/natpmp.cpp} +12 -9
- package/native-src/src/{natpmp.h → librats/nat/natpmp.h} +3 -3
- package/native-src/src/{port_mapping.h → librats/nat/port_mapping.h} +3 -2
- package/native-src/src/{stun.cpp → librats/nat/stun.cpp} +4 -4
- package/native-src/src/{stun.h → librats/nat/stun.h} +1 -1
- package/native-src/src/{upnp.cpp → librats/nat/upnp.cpp} +6 -6
- package/native-src/src/{upnp.h → librats/nat/upnp.h} +2 -2
- package/native-src/src/librats/node/circuit_service.h +84 -0
- package/native-src/src/librats/node/config.h +110 -0
- package/native-src/src/librats/node/dial_service.h +54 -0
- package/native-src/src/librats/node/dialer.cpp +264 -0
- package/native-src/src/librats/node/dialer.h +188 -0
- package/native-src/src/librats/node/host_events.h +26 -0
- package/native-src/src/librats/node/identify.cpp +130 -0
- package/native-src/src/librats/node/identify.h +71 -0
- package/native-src/src/librats/node/nat_status.cpp +103 -0
- package/native-src/src/librats/node/nat_status.h +118 -0
- package/native-src/src/librats/node/node.cpp +865 -0
- package/native-src/src/librats/node/node.h +344 -0
- package/native-src/src/librats/node/node_context.h +33 -0
- package/native-src/src/librats/node/peer_network.h +91 -0
- package/native-src/src/librats/peer/peer.h +49 -0
- package/native-src/src/librats/peer/peer_book.cpp +181 -0
- package/native-src/src/librats/peer/peer_book.h +88 -0
- package/native-src/src/librats/peer/peer_id.cpp +72 -0
- package/native-src/src/librats/peer/peer_id.h +62 -0
- package/native-src/src/librats/peer/peer_info.h +37 -0
- package/native-src/src/librats/peer/peer_table.cpp +170 -0
- package/native-src/src/librats/peer/peer_table.h +148 -0
- package/native-src/src/librats/security/handshaker.h +66 -0
- package/native-src/src/librats/security/identity.h +43 -0
- package/native-src/src/librats/security/noise_security.cpp +122 -0
- package/native-src/src/librats/security/noise_security.h +37 -0
- package/native-src/src/librats/security/plaintext_security.h +106 -0
- package/native-src/src/librats/security/session.h +37 -0
- package/native-src/src/{storage.cpp → librats/storage/storage.cpp} +369 -522
- package/native-src/src/{storage.h → librats/storage/storage.h} +135 -299
- package/native-src/src/librats/subsystems/bittorrent.cpp +211 -0
- package/native-src/src/librats/subsystems/bittorrent.h +136 -0
- package/native-src/src/librats/subsystems/dht_discovery.cpp +202 -0
- package/native-src/src/librats/subsystems/dht_discovery.h +123 -0
- package/native-src/src/librats/subsystems/dht_service.h +36 -0
- package/native-src/src/librats/subsystems/file_transfer.cpp +972 -0
- package/native-src/src/librats/subsystems/file_transfer.h +367 -0
- package/native-src/src/librats/subsystems/hole_punch.cpp +605 -0
- package/native-src/src/librats/subsystems/hole_punch.h +290 -0
- package/native-src/src/librats/subsystems/hole_punch_service.h +38 -0
- package/native-src/src/librats/subsystems/mdns_discovery.cpp +66 -0
- package/native-src/src/librats/subsystems/mdns_discovery.h +55 -0
- package/native-src/src/librats/subsystems/message_json.cpp +112 -0
- package/native-src/src/librats/subsystems/message_json.h +88 -0
- package/native-src/src/librats/subsystems/peer_exchange.cpp +241 -0
- package/native-src/src/librats/subsystems/peer_exchange.h +136 -0
- package/native-src/src/librats/subsystems/ping_service.cpp +98 -0
- package/native-src/src/librats/subsystems/ping_service.h +66 -0
- package/native-src/src/librats/subsystems/port_mapping_service.cpp +192 -0
- package/native-src/src/librats/subsystems/port_mapping_service.h +84 -0
- package/native-src/src/librats/subsystems/pubsub.cpp +567 -0
- package/native-src/src/librats/subsystems/pubsub.h +175 -0
- package/native-src/src/librats/subsystems/reconnection.cpp +239 -0
- package/native-src/src/librats/subsystems/reconnection.h +126 -0
- package/native-src/src/librats/subsystems/relay.cpp +1142 -0
- package/native-src/src/librats/subsystems/relay.h +211 -0
- package/native-src/src/librats/subsystems/relay_service.h +46 -0
- package/native-src/src/librats/transport/connection.cpp +343 -0
- package/native-src/src/librats/transport/connection.h +283 -0
- package/native-src/src/librats/transport/link.h +96 -0
- package/native-src/src/librats/transport/reactor.cpp +588 -0
- package/native-src/src/librats/transport/reactor.h +262 -0
- package/native-src/src/librats/transport/reactor_pool.h +81 -0
- package/native-src/src/librats/transport/relay_link.cpp +208 -0
- package/native-src/src/librats/transport/relay_link.h +303 -0
- package/native-src/src/librats/transport/tcp_link.cpp +49 -0
- package/native-src/src/librats/transport/tcp_link.h +43 -0
- package/native-src/src/librats/transport/udp_mux.cpp +617 -0
- package/native-src/src/librats/transport/udp_mux.h +363 -0
- package/native-src/src/librats/transport/udp_packet.cpp +121 -0
- package/native-src/src/librats/transport/udp_packet.h +190 -0
- package/native-src/src/librats/transport/udp_stream.cpp +1194 -0
- package/native-src/src/librats/transport/udp_stream.h +614 -0
- package/native-src/src/librats/util/features.h.in +51 -0
- package/native-src/src/{fs.cpp → librats/util/fs.cpp} +51 -3
- package/native-src/src/librats/util/fs.h +136 -0
- package/native-src/src/librats/util/json.cpp +1002 -0
- package/native-src/src/librats/util/json.h +444 -0
- package/native-src/src/{logger.cpp → librats/util/logger.cpp} +1 -1
- package/native-src/src/{logger.h → librats/util/logger.h} +43 -31
- package/native-src/src/{network_monitor.cpp → librats/util/network_monitor.cpp} +12 -4
- package/native-src/src/{network_monitor.h → librats/util/network_monitor.h} +2 -1
- package/native-src/src/{network_utils.cpp → librats/util/network_utils.cpp} +38 -23
- package/native-src/src/{network_utils.h → librats/util/network_utils.h} +15 -8
- package/native-src/src/{os.cpp → librats/util/os.cpp} +48 -18
- package/native-src/src/librats/util/rats_export.h +69 -0
- package/native-src/src/{version.cpp → librats/util/version.cpp} +2 -2
- package/native-src/src/{version.h.in → librats/util/version.h.in} +1 -1
- package/native-src/src/librats/wire/frame.cpp +76 -0
- package/native-src/src/librats/wire/frame.h +111 -0
- package/native-src/src/librats/wire/message_router.cpp +45 -0
- package/native-src/src/librats/wire/message_router.h +47 -0
- package/package.json +5 -4
- package/scripts/build-librats.js +1 -0
- package/scripts/postinstall.js +3 -3
- package/scripts/prepare-package.js +4 -4
- package/scripts/verify-installation.js +63 -105
- package/src/librats_node.cpp +1067 -1323
- package/native-src/src/bencode.cpp +0 -485
- package/native-src/src/bencode.h +0 -145
- package/native-src/src/bittorrent.cpp +0 -14
- package/native-src/src/bittorrent.h +0 -74
- package/native-src/src/bt_bitfield.cpp +0 -372
- package/native-src/src/bt_bitfield.h +0 -316
- package/native-src/src/bt_choker.cpp +0 -228
- package/native-src/src/bt_choker.h +0 -147
- package/native-src/src/bt_client.cpp +0 -1047
- package/native-src/src/bt_client.h +0 -445
- package/native-src/src/bt_create_torrent.cpp +0 -677
- package/native-src/src/bt_create_torrent.h +0 -473
- package/native-src/src/bt_extension.cpp +0 -469
- package/native-src/src/bt_extension.h +0 -309
- package/native-src/src/bt_file_storage.cpp +0 -261
- package/native-src/src/bt_file_storage.h +0 -298
- package/native-src/src/bt_handshake.cpp +0 -134
- package/native-src/src/bt_handshake.h +0 -157
- package/native-src/src/bt_messages.cpp +0 -364
- package/native-src/src/bt_messages.h +0 -324
- package/native-src/src/bt_network.cpp +0 -1007
- package/native-src/src/bt_network.h +0 -417
- package/native-src/src/bt_peer_connection.cpp +0 -742
- package/native-src/src/bt_peer_connection.h +0 -592
- package/native-src/src/bt_piece_picker.cpp +0 -786
- package/native-src/src/bt_piece_picker.h +0 -473
- package/native-src/src/bt_resume_data.cpp +0 -410
- package/native-src/src/bt_resume_data.h +0 -249
- package/native-src/src/bt_torrent.cpp +0 -2120
- package/native-src/src/bt_torrent.h +0 -641
- package/native-src/src/bt_torrent_info.cpp +0 -659
- package/native-src/src/bt_torrent_info.h +0 -418
- package/native-src/src/bt_types.h +0 -621
- package/native-src/src/chained_send_buffer.cpp +0 -75
- package/native-src/src/chained_send_buffer.h +0 -137
- package/native-src/src/crypto/hkdf.c +0 -266
- package/native-src/src/crypto/poly1305.h +0 -36
- package/native-src/src/dht.cpp +0 -3311
- package/native-src/src/dht.h +0 -717
- package/native-src/src/disk_io.cpp +0 -632
- package/native-src/src/disk_io.h +0 -315
- package/native-src/src/file_transfer.cpp +0 -1415
- package/native-src/src/file_transfer.h +0 -286
- package/native-src/src/fs.h +0 -108
- package/native-src/src/gossipsub.cpp +0 -1139
- package/native-src/src/gossipsub.h +0 -403
- package/native-src/src/ice.cpp +0 -893
- package/native-src/src/ice.h +0 -559
- package/native-src/src/json.hpp +0 -25526
- package/native-src/src/librats.cpp +0 -2378
- package/native-src/src/librats.h +0 -2324
- package/native-src/src/librats_bittorrent.cpp +0 -601
- package/native-src/src/librats_c.cpp +0 -1557
- package/native-src/src/librats_c.h +0 -323
- package/native-src/src/librats_discovery.cpp +0 -402
- package/native-src/src/librats_encryption.cpp +0 -275
- package/native-src/src/librats_file_transfer.cpp +0 -144
- package/native-src/src/librats_gossipsub.cpp +0 -289
- package/native-src/src/librats_ice.cpp +0 -213
- package/native-src/src/librats_log_macros.h +0 -36
- package/native-src/src/librats_logging.cpp +0 -173
- package/native-src/src/librats_mdns.cpp +0 -166
- package/native-src/src/librats_persistence.cpp +0 -796
- package/native-src/src/librats_portmap.cpp +0 -419
- package/native-src/src/librats_reconnection.cpp +0 -218
- package/native-src/src/librats_statistic.cpp +0 -105
- package/native-src/src/librats_storage.cpp +0 -189
- package/native-src/src/rats_export.h +0 -17
- package/native-src/src/receive_buffer.cpp +0 -82
- package/native-src/src/receive_buffer.h +0 -127
- package/native-src/src/socket.h +0 -228
- package/native-src/src/threadmanager.cpp +0 -105
- package/native-src/src/threadmanager.h +0 -53
- package/native-src/src/tracker.cpp +0 -1264
- package/native-src/src/tracker.h +0 -319
- package/native-src/src/turn.cpp +0 -762
- package/native-src/src/turn.h +0 -460
- package/native-src/src/wakeup_pipe.h +0 -60
- /package/native-src/src/{os.h → librats/util/os.h} +0 -0
|
@@ -0,0 +1,762 @@
|
|
|
1
|
+
#include "librats/bindings/rats.h"
|
|
2
|
+
|
|
3
|
+
#include "librats/node/node.h"
|
|
4
|
+
#include "librats/peer/peer_info.h"
|
|
5
|
+
#include "librats/subsystems/dht_discovery.h"
|
|
6
|
+
#include "librats/subsystems/mdns_discovery.h"
|
|
7
|
+
#include "librats/subsystems/port_mapping_service.h"
|
|
8
|
+
#include "librats/subsystems/hole_punch.h"
|
|
9
|
+
#include "librats/subsystems/relay.h"
|
|
10
|
+
#include "librats/subsystems/pubsub.h"
|
|
11
|
+
#include "librats/subsystems/message_json.h"
|
|
12
|
+
#include "librats/subsystems/file_transfer.h"
|
|
13
|
+
#include "librats/subsystems/ping_service.h"
|
|
14
|
+
#include "librats/subsystems/reconnection.h"
|
|
15
|
+
#ifdef RATS_SEARCH_FEATURES
|
|
16
|
+
#include "librats/subsystems/bittorrent.h"
|
|
17
|
+
#endif
|
|
18
|
+
#include "librats/core/address.h"
|
|
19
|
+
#include "librats/util/network_utils.h"
|
|
20
|
+
#include "librats/util/logger.h"
|
|
21
|
+
#include "librats/util/json.h"
|
|
22
|
+
#include "librats/util/version.h"
|
|
23
|
+
|
|
24
|
+
#include <cstdlib>
|
|
25
|
+
#include <cstring>
|
|
26
|
+
#include <memory>
|
|
27
|
+
#include <string>
|
|
28
|
+
|
|
29
|
+
using namespace librats;
|
|
30
|
+
|
|
31
|
+
namespace {
|
|
32
|
+
|
|
33
|
+
// A C handle is a thin owner of the Node plus non-owning pointers to the
|
|
34
|
+
// subsystems it has enabled (the Node owns those). Subsystems are explicit: each
|
|
35
|
+
// rats_enable_* attaches one before start() and records it here; the *_enabled
|
|
36
|
+
// flags dedup the enables that don't keep a pointer. `started` gates the
|
|
37
|
+
// before-start contract so enables after start() can be rejected cleanly.
|
|
38
|
+
struct RatsHandle {
|
|
39
|
+
std::unique_ptr<Node> node;
|
|
40
|
+
PubSub* pubsub = nullptr;
|
|
41
|
+
MessageJson* messages = nullptr;
|
|
42
|
+
FileTransfer* files = nullptr;
|
|
43
|
+
PingService* ping = nullptr;
|
|
44
|
+
ReconnectionService* reconnect = nullptr;
|
|
45
|
+
HolePunch* punch = nullptr;
|
|
46
|
+
Relay* relay = nullptr;
|
|
47
|
+
#ifdef RATS_SEARCH_FEATURES
|
|
48
|
+
Bittorrent* bittorrent = nullptr;
|
|
49
|
+
#endif
|
|
50
|
+
std::string data_dir; ///< copied from NodeConfig so subsystems can co-locate state
|
|
51
|
+
bool dht_enabled = false;
|
|
52
|
+
bool mdns_enabled = false;
|
|
53
|
+
bool portmap_enabled = false;
|
|
54
|
+
bool started = false;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
// Build a handle around a freshly-constructed Node, remembering the data_dir
|
|
58
|
+
// (the config is moved into the Node, so copy it out first) for subsystems that
|
|
59
|
+
// co-locate persistent state (DHT routing table, reconnection store).
|
|
60
|
+
RatsHandle* make_handle(NodeConfig config) {
|
|
61
|
+
auto* h = new RatsHandle();
|
|
62
|
+
h->data_dir = config.data_dir;
|
|
63
|
+
h->node = std::make_unique<Node>(std::move(config));
|
|
64
|
+
return h;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
RatsHandle* as_handle(rats_t handle) { return static_cast<RatsHandle*>(handle); }
|
|
68
|
+
|
|
69
|
+
// Turn a caller-supplied (host, port) into a numeric Address. A numeric literal is
|
|
70
|
+
// used verbatim; a hostname is resolved here at the API boundary (IPv4 first, then
|
|
71
|
+
// IPv6) so the reconnection subsystem only ever holds resolved endpoints. Returns
|
|
72
|
+
// nullopt if the host is neither a valid literal nor resolvable.
|
|
73
|
+
std::optional<Address> resolve_target(const char* host, uint16_t port) {
|
|
74
|
+
if (auto ip = IpAddress::parse(host)) return Address{*ip, port};
|
|
75
|
+
std::string resolved = network_utils::resolve_hostname(host);
|
|
76
|
+
if (resolved.empty()) resolved = network_utils::resolve_hostname_v6(host);
|
|
77
|
+
if (auto ip = IpAddress::parse(resolved)) return Address{*ip, port};
|
|
78
|
+
return std::nullopt;
|
|
79
|
+
}
|
|
80
|
+
Node* node_of(rats_t handle) { return as_handle(handle)->node.get(); }
|
|
81
|
+
|
|
82
|
+
char* dup_string(const std::string& s) {
|
|
83
|
+
char* out = static_cast<char*>(std::malloc(s.size() + 1));
|
|
84
|
+
if (out) std::memcpy(out, s.c_str(), s.size() + 1);
|
|
85
|
+
return out;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
} // namespace
|
|
89
|
+
|
|
90
|
+
extern "C" {
|
|
91
|
+
|
|
92
|
+
const char* rats_error_str(rats_error_t err) {
|
|
93
|
+
switch (err) {
|
|
94
|
+
case RATS_OK: return "RATS_OK";
|
|
95
|
+
case RATS_ERR_INVALID_ARG: return "RATS_ERR_INVALID_ARG";
|
|
96
|
+
case RATS_ERR_NOT_STARTED: return "RATS_ERR_NOT_STARTED";
|
|
97
|
+
case RATS_ERR_ALREADY_STARTED: return "RATS_ERR_ALREADY_STARTED";
|
|
98
|
+
case RATS_ERR_NOT_ENABLED: return "RATS_ERR_NOT_ENABLED";
|
|
99
|
+
case RATS_ERR_NO_SUCH_PEER: return "RATS_ERR_NO_SUCH_PEER";
|
|
100
|
+
case RATS_ERR_BIND: return "RATS_ERR_BIND";
|
|
101
|
+
case RATS_ERR_INTERNAL: return "RATS_ERR_INTERNAL";
|
|
102
|
+
}
|
|
103
|
+
return "RATS_ERR_UNKNOWN";
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/* — construction / lifecycle — */
|
|
107
|
+
|
|
108
|
+
rats_config_t rats_config_default(void) {
|
|
109
|
+
rats_config_t c;
|
|
110
|
+
c.listen_port = 0;
|
|
111
|
+
c.enable_listen = 1;
|
|
112
|
+
c.bind_address = nullptr;
|
|
113
|
+
c.security = RATS_SECURITY_NOISE;
|
|
114
|
+
c.data_dir = nullptr;
|
|
115
|
+
c.protocol = nullptr;
|
|
116
|
+
c.max_peers = 0;
|
|
117
|
+
c.enable_tcp = 1;
|
|
118
|
+
c.enable_udp = 1;
|
|
119
|
+
c.preferred_transport = RATS_TRANSPORT_UDP;
|
|
120
|
+
c.transport_fallback_ms = 1200;
|
|
121
|
+
return c;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
rats_t rats_create_config(const rats_config_t* cfg) {
|
|
125
|
+
NodeConfig config;
|
|
126
|
+
if (cfg) {
|
|
127
|
+
config.listen_port = cfg->listen_port;
|
|
128
|
+
config.enable_listen = cfg->enable_listen != 0;
|
|
129
|
+
if (cfg->bind_address) config.bind_address = cfg->bind_address;
|
|
130
|
+
config.security = (cfg->security == RATS_SECURITY_PLAINTEXT) ? NodeConfig::Security::Plaintext
|
|
131
|
+
: NodeConfig::Security::Noise;
|
|
132
|
+
if (cfg->data_dir) config.data_dir = cfg->data_dir;
|
|
133
|
+
if (cfg->protocol) config.protocol = cfg->protocol;
|
|
134
|
+
config.max_peers = cfg->max_peers;
|
|
135
|
+
|
|
136
|
+
// Neither transport enabled is not a configuration anyone means — it is a
|
|
137
|
+
// node that can neither dial nor accept, and it fails *silently*: with
|
|
138
|
+
// enable_listen set, start() refuses; without it, the node comes up and
|
|
139
|
+
// then simply never connects to anything. And it is precisely what the
|
|
140
|
+
// commonest way of filling this struct in C produces, because zeroed
|
|
141
|
+
// memory reads as "both off":
|
|
142
|
+
//
|
|
143
|
+
// rats_config_t cfg = {0}; // or a partial designated initialiser
|
|
144
|
+
// cfg.listen_port = 9000;
|
|
145
|
+
//
|
|
146
|
+
// That worked before these two fields existed, so treating 0/0 as "both"
|
|
147
|
+
// is what keeps it working. Anyone who really wants one transport says so
|
|
148
|
+
// by enabling the other.
|
|
149
|
+
const bool any_transport = cfg->enable_tcp != 0 || cfg->enable_udp != 0;
|
|
150
|
+
config.enable_tcp = any_transport ? (cfg->enable_tcp != 0) : true;
|
|
151
|
+
config.enable_udp = any_transport ? (cfg->enable_udp != 0) : true;
|
|
152
|
+
config.preferred_transport = (cfg->preferred_transport == RATS_TRANSPORT_TCP)
|
|
153
|
+
? TransportKind::Tcp
|
|
154
|
+
: TransportKind::Udp;
|
|
155
|
+
config.transport_fallback_ms = cfg->transport_fallback_ms;
|
|
156
|
+
}
|
|
157
|
+
return make_handle(std::move(config));
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
rats_t rats_create(uint16_t listen_port) {
|
|
161
|
+
NodeConfig config;
|
|
162
|
+
config.listen_port = listen_port;
|
|
163
|
+
return make_handle(std::move(config));
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
rats_t rats_create_ex(uint16_t listen_port, int enable_listen,
|
|
167
|
+
const char* bind_address, rats_security_t security) {
|
|
168
|
+
NodeConfig config;
|
|
169
|
+
config.listen_port = listen_port;
|
|
170
|
+
config.enable_listen = enable_listen != 0;
|
|
171
|
+
if (bind_address) config.bind_address = bind_address;
|
|
172
|
+
config.security = (security == RATS_SECURITY_PLAINTEXT) ? NodeConfig::Security::Plaintext
|
|
173
|
+
: NodeConfig::Security::Noise;
|
|
174
|
+
return make_handle(std::move(config));
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
void rats_destroy(rats_t node) { delete as_handle(node); }
|
|
178
|
+
|
|
179
|
+
rats_error_t rats_start(rats_t node) {
|
|
180
|
+
auto* h = as_handle(node);
|
|
181
|
+
if (h->started) return RATS_ERR_ALREADY_STARTED;
|
|
182
|
+
if (!h->node->start()) return RATS_ERR_BIND;
|
|
183
|
+
h->started = true;
|
|
184
|
+
return RATS_OK;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
void rats_stop(rats_t node) {
|
|
188
|
+
auto* h = as_handle(node);
|
|
189
|
+
h->node->stop();
|
|
190
|
+
h->started = false; // allow a subsequent rats_start() to bind again
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
uint16_t rats_listen_port(rats_t node) { return node_of(node)->listen_port(); }
|
|
194
|
+
|
|
195
|
+
uint32_t rats_transports(rats_t node) { return node_of(node)->transports(); }
|
|
196
|
+
|
|
197
|
+
char* rats_local_id(rats_t node) { return dup_string(node_of(node)->local_id().to_hex()); }
|
|
198
|
+
|
|
199
|
+
/* — connections — */
|
|
200
|
+
|
|
201
|
+
rats_error_t rats_connect(rats_t node, const char* host, uint16_t port) {
|
|
202
|
+
if (!host) return RATS_ERR_INVALID_ARG;
|
|
203
|
+
node_of(node)->connect(std::string(host), port);
|
|
204
|
+
return RATS_OK;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
size_t rats_peer_count(rats_t node) { return node_of(node)->peer_count(); }
|
|
208
|
+
|
|
209
|
+
void rats_set_max_peers(rats_t node, size_t max_peers) {
|
|
210
|
+
node_of(node)->set_max_peers(max_peers);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
size_t rats_max_peers(rats_t node) { return node_of(node)->max_peers(); }
|
|
214
|
+
|
|
215
|
+
/* — messaging — */
|
|
216
|
+
|
|
217
|
+
rats_error_t rats_send(rats_t node, const char* peer_id_hex,
|
|
218
|
+
const char* channel, const void* data, size_t len) {
|
|
219
|
+
if (!peer_id_hex || !channel) return RATS_ERR_INVALID_ARG;
|
|
220
|
+
auto id = PeerId::from_hex(peer_id_hex);
|
|
221
|
+
if (!id) return RATS_ERR_INVALID_ARG;
|
|
222
|
+
if (!node_of(node)->peer(*id)) return RATS_ERR_NO_SUCH_PEER;
|
|
223
|
+
node_of(node)->send(*id, channel, ByteView(static_cast<const uint8_t*>(data), len));
|
|
224
|
+
return RATS_OK;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
rats_error_t rats_broadcast(rats_t node, const char* channel, const void* data, size_t len) {
|
|
228
|
+
if (!channel) return RATS_ERR_INVALID_ARG;
|
|
229
|
+
node_of(node)->broadcast(channel, ByteView(static_cast<const uint8_t*>(data), len));
|
|
230
|
+
return RATS_OK;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
rats_error_t rats_on_peer_connected(rats_t node, rats_peer_cb cb, void* user) {
|
|
234
|
+
if (!cb) return RATS_ERR_INVALID_ARG;
|
|
235
|
+
node_of(node)->on_peer_connected([cb, user](const Peer& peer) {
|
|
236
|
+
cb(user, peer.id().to_hex().c_str());
|
|
237
|
+
});
|
|
238
|
+
return RATS_OK;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
rats_error_t rats_on_peer_disconnected(rats_t node, rats_peer_cb cb, void* user) {
|
|
242
|
+
if (!cb) return RATS_ERR_INVALID_ARG;
|
|
243
|
+
node_of(node)->on_peer_disconnected([cb, user](const PeerId& id) {
|
|
244
|
+
cb(user, id.to_hex().c_str());
|
|
245
|
+
});
|
|
246
|
+
return RATS_OK;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
rats_error_t rats_on(rats_t node, const char* channel, rats_message_cb cb, void* user) {
|
|
250
|
+
if (!channel || !cb) return RATS_ERR_INVALID_ARG;
|
|
251
|
+
node_of(node)->on(channel, [cb, user](const Peer& peer, ByteView data) {
|
|
252
|
+
cb(user, peer.id().to_hex().c_str(), data.data(), data.size());
|
|
253
|
+
});
|
|
254
|
+
return RATS_OK;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
/* — discovery / NAT subsystems — */
|
|
258
|
+
|
|
259
|
+
rats_error_t rats_enable_dht(rats_t node, uint16_t dht_port, const char* discovery_key) {
|
|
260
|
+
auto* h = as_handle(node);
|
|
261
|
+
if (h->started) return RATS_ERR_ALREADY_STARTED;
|
|
262
|
+
if (h->dht_enabled) return RATS_OK;
|
|
263
|
+
DhtDiscovery::Config config;
|
|
264
|
+
config.dht_port = dht_port;
|
|
265
|
+
config.data_dir = h->data_dir; // co-locate routing tables with identity (else cwd)
|
|
266
|
+
if (discovery_key) config.discovery_key = discovery_key;
|
|
267
|
+
h->node->add_subsystem(std::make_unique<DhtDiscovery>(std::move(config)));
|
|
268
|
+
h->dht_enabled = true;
|
|
269
|
+
return RATS_OK;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
rats_error_t rats_enable_mdns(rats_t node) {
|
|
273
|
+
auto* h = as_handle(node);
|
|
274
|
+
if (h->started) return RATS_ERR_ALREADY_STARTED;
|
|
275
|
+
if (h->mdns_enabled) return RATS_OK;
|
|
276
|
+
h->node->add_subsystem(std::make_unique<MdnsDiscovery>());
|
|
277
|
+
h->mdns_enabled = true;
|
|
278
|
+
return RATS_OK;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
rats_error_t rats_enable_port_mapping(rats_t node, int enable_upnp, int enable_natpmp) {
|
|
282
|
+
auto* h = as_handle(node);
|
|
283
|
+
if (h->started) return RATS_ERR_ALREADY_STARTED;
|
|
284
|
+
if (h->portmap_enabled) return RATS_OK;
|
|
285
|
+
PortMappingConfig config;
|
|
286
|
+
config.enable_upnp = enable_upnp != 0;
|
|
287
|
+
config.enable_natpmp = enable_natpmp != 0;
|
|
288
|
+
h->node->add_subsystem(std::make_unique<PortMappingService>(config));
|
|
289
|
+
h->portmap_enabled = true;
|
|
290
|
+
return RATS_OK;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
rats_error_t rats_enable_hole_punch(rats_t node, int serve_as_relay) {
|
|
294
|
+
auto* h = as_handle(node);
|
|
295
|
+
if (h->started) return RATS_ERR_ALREADY_STARTED;
|
|
296
|
+
if (!h->punch) {
|
|
297
|
+
HolePunch::Config config;
|
|
298
|
+
config.enable_relay = serve_as_relay != 0;
|
|
299
|
+
h->punch = h->node->add_subsystem(std::make_unique<HolePunch>(config));
|
|
300
|
+
}
|
|
301
|
+
return RATS_OK;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
rats_error_t rats_enable_relay(rats_t node, int serve_as_relay) {
|
|
305
|
+
auto* h = as_handle(node);
|
|
306
|
+
if (h->started) return RATS_ERR_ALREADY_STARTED;
|
|
307
|
+
if (!h->relay) {
|
|
308
|
+
Relay::Config config;
|
|
309
|
+
config.serve = serve_as_relay != 0;
|
|
310
|
+
h->relay = h->node->add_subsystem(std::make_unique<Relay>(config));
|
|
311
|
+
}
|
|
312
|
+
return RATS_OK;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
rats_error_t rats_connect_via_relay(rats_t node, const char* peer_id_hex) {
|
|
316
|
+
if (!peer_id_hex) return RATS_ERR_INVALID_ARG;
|
|
317
|
+
auto* h = as_handle(node);
|
|
318
|
+
if (!h->relay) return RATS_ERR_NOT_ENABLED;
|
|
319
|
+
auto id = PeerId::from_hex(peer_id_hex);
|
|
320
|
+
if (!id) return RATS_ERR_INVALID_ARG;
|
|
321
|
+
// As with punching, every reason an attempt is declined is "nothing to do or
|
|
322
|
+
// nothing to try with" — already connected, already trying, in cooldown, or no
|
|
323
|
+
// peer that could carry it — and none of them is separately actionable.
|
|
324
|
+
return h->relay->connect_via_relay(*id) ? RATS_OK : RATS_ERR_NO_SUCH_PEER;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
rats_error_t rats_punch_peer(rats_t node, const char* peer_id_hex) {
|
|
328
|
+
if (!peer_id_hex) return RATS_ERR_INVALID_ARG;
|
|
329
|
+
auto* h = as_handle(node);
|
|
330
|
+
if (!h->punch) return RATS_ERR_NOT_ENABLED;
|
|
331
|
+
auto id = PeerId::from_hex(peer_id_hex);
|
|
332
|
+
if (!id) return RATS_ERR_INVALID_ARG;
|
|
333
|
+
// Every reason a punch is declined is "there is nothing to do or nothing to try
|
|
334
|
+
// with" — already connected, already punching, in cooldown, or no external
|
|
335
|
+
// endpoint learned yet. None of them is an error the caller can act on
|
|
336
|
+
// differently, so they collapse into one answer.
|
|
337
|
+
return h->punch->punch(*id) ? RATS_OK : RATS_ERR_NO_SUCH_PEER;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
int rats_nat_mapping(rats_t node) {
|
|
341
|
+
switch (node_of(node)->nat_status().udp_mapping()) {
|
|
342
|
+
case NatMapping::Open: return RATS_NAT_OPEN;
|
|
343
|
+
case NatMapping::EndpointIndependent: return RATS_NAT_ENDPOINT_INDEPENDENT;
|
|
344
|
+
case NatMapping::EndpointDependent: return RATS_NAT_ENDPOINT_DEPENDENT;
|
|
345
|
+
case NatMapping::Unknown: break;
|
|
346
|
+
}
|
|
347
|
+
return RATS_NAT_UNKNOWN;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
/* — peer enumeration — */
|
|
351
|
+
|
|
352
|
+
char** rats_peer_ids(rats_t node, size_t* count) {
|
|
353
|
+
auto infos = node_of(node)->peers();
|
|
354
|
+
if (count) *count = infos.size();
|
|
355
|
+
if (infos.empty()) return nullptr;
|
|
356
|
+
char** ids = static_cast<char**>(std::malloc(infos.size() * sizeof(char*)));
|
|
357
|
+
if (!ids) { if (count) *count = 0; return nullptr; }
|
|
358
|
+
for (size_t i = 0; i < infos.size(); ++i) ids[i] = dup_string(infos[i].id.to_hex());
|
|
359
|
+
return ids;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
int rats_peer_transport(rats_t node, const char* peer_id_hex) {
|
|
363
|
+
if (!peer_id_hex) return -1;
|
|
364
|
+
auto id = PeerId::from_hex(peer_id_hex);
|
|
365
|
+
if (!id) return -1;
|
|
366
|
+
for (const PeerInfo& info : node_of(node)->peers()) {
|
|
367
|
+
if (info.id != *id) continue;
|
|
368
|
+
switch (info.transport) {
|
|
369
|
+
case TransportKind::Udp: return RATS_TRANSPORT_UDP;
|
|
370
|
+
case TransportKind::Relay: return RATS_TRANSPORT_RELAY;
|
|
371
|
+
case TransportKind::Tcp: break;
|
|
372
|
+
}
|
|
373
|
+
return RATS_TRANSPORT_TCP;
|
|
374
|
+
}
|
|
375
|
+
return -1;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
int rats_peer_transports(rats_t node, const char* peer_id_hex) {
|
|
379
|
+
if (!peer_id_hex) return -1;
|
|
380
|
+
auto id = PeerId::from_hex(peer_id_hex);
|
|
381
|
+
if (!id) return -1;
|
|
382
|
+
for (const PeerInfo& info : node_of(node)->peers())
|
|
383
|
+
if (info.id == *id) return static_cast<int>(info.supported_transports);
|
|
384
|
+
return -1;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
void rats_free_peer_ids(char** ids, size_t count) {
|
|
388
|
+
if (!ids) return;
|
|
389
|
+
for (size_t i = 0; i < count; ++i) std::free(ids[i]);
|
|
390
|
+
std::free(ids);
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
/* — pub/sub — */
|
|
394
|
+
|
|
395
|
+
rats_error_t rats_enable_pubsub(rats_t node) {
|
|
396
|
+
auto* h = as_handle(node);
|
|
397
|
+
if (h->started) return RATS_ERR_ALREADY_STARTED;
|
|
398
|
+
if (!h->pubsub) h->pubsub = h->node->add_subsystem(std::make_unique<PubSub>());
|
|
399
|
+
return RATS_OK;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
rats_error_t rats_subscribe(rats_t node, const char* topic, rats_topic_cb cb, void* user) {
|
|
403
|
+
if (!topic || !cb) return RATS_ERR_INVALID_ARG;
|
|
404
|
+
auto* h = as_handle(node);
|
|
405
|
+
if (!h->pubsub) return RATS_ERR_NOT_ENABLED;
|
|
406
|
+
h->pubsub->subscribe(topic,
|
|
407
|
+
[cb, user](const PeerId& from, const std::string& t, ByteView data) {
|
|
408
|
+
cb(user, from.to_hex().c_str(), t.c_str(), data.data(), data.size());
|
|
409
|
+
});
|
|
410
|
+
return RATS_OK;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
rats_error_t rats_unsubscribe(rats_t node, const char* topic) {
|
|
414
|
+
if (!topic) return RATS_ERR_INVALID_ARG;
|
|
415
|
+
auto* h = as_handle(node);
|
|
416
|
+
if (!h->pubsub) return RATS_ERR_NOT_ENABLED;
|
|
417
|
+
h->pubsub->unsubscribe(topic);
|
|
418
|
+
return RATS_OK;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
rats_error_t rats_publish(rats_t node, const char* topic, const void* data, size_t len) {
|
|
422
|
+
if (!topic) return RATS_ERR_INVALID_ARG;
|
|
423
|
+
auto* h = as_handle(node);
|
|
424
|
+
if (!h->pubsub) return RATS_ERR_NOT_ENABLED;
|
|
425
|
+
h->pubsub->publish(topic, ByteView(static_cast<const uint8_t*>(data), len));
|
|
426
|
+
return RATS_OK;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
/* — typed JSON messaging — */
|
|
430
|
+
|
|
431
|
+
rats_error_t rats_enable_json(rats_t node) {
|
|
432
|
+
auto* h = as_handle(node);
|
|
433
|
+
if (h->started) return RATS_ERR_ALREADY_STARTED;
|
|
434
|
+
if (!h->messages) h->messages = h->node->add_subsystem(std::make_unique<MessageJson>());
|
|
435
|
+
return RATS_OK;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
rats_error_t rats_on_json(rats_t node, const char* type, rats_json_cb cb, void* user) {
|
|
439
|
+
if (!type || !cb) return RATS_ERR_INVALID_ARG;
|
|
440
|
+
auto* h = as_handle(node);
|
|
441
|
+
if (!h->messages) return RATS_ERR_NOT_ENABLED;
|
|
442
|
+
h->messages->on(type, [cb, user](const PeerId& from, const librats::Json& data) {
|
|
443
|
+
cb(user, from.to_hex().c_str(), data.dump().c_str());
|
|
444
|
+
});
|
|
445
|
+
return RATS_OK;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
rats_error_t rats_once_json(rats_t node, const char* type, rats_json_cb cb, void* user) {
|
|
449
|
+
if (!type || !cb) return RATS_ERR_INVALID_ARG;
|
|
450
|
+
auto* h = as_handle(node);
|
|
451
|
+
if (!h->messages) return RATS_ERR_NOT_ENABLED;
|
|
452
|
+
h->messages->once(type, [cb, user](const PeerId& from, const librats::Json& data) {
|
|
453
|
+
cb(user, from.to_hex().c_str(), data.dump().c_str());
|
|
454
|
+
});
|
|
455
|
+
return RATS_OK;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
rats_error_t rats_off_json(rats_t node, const char* type) {
|
|
459
|
+
if (!type) return RATS_ERR_INVALID_ARG;
|
|
460
|
+
auto* h = as_handle(node);
|
|
461
|
+
if (!h->messages) return RATS_ERR_NOT_ENABLED;
|
|
462
|
+
h->messages->off(type);
|
|
463
|
+
return RATS_OK;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
rats_error_t rats_send_json(rats_t node, const char* peer_id_hex, const char* type, const char* json) {
|
|
467
|
+
if (!peer_id_hex || !type || !json) return RATS_ERR_INVALID_ARG;
|
|
468
|
+
auto* h = as_handle(node);
|
|
469
|
+
if (!h->messages) return RATS_ERR_NOT_ENABLED;
|
|
470
|
+
auto id = PeerId::from_hex(peer_id_hex);
|
|
471
|
+
if (!id) return RATS_ERR_INVALID_ARG;
|
|
472
|
+
auto j = librats::Json::parse(json, nullptr, /*allow_exceptions=*/false);
|
|
473
|
+
if (j.is_discarded()) return RATS_ERR_INVALID_ARG;
|
|
474
|
+
if (!h->node->peer(*id)) return RATS_ERR_NO_SUCH_PEER;
|
|
475
|
+
h->messages->send(*id, type, j);
|
|
476
|
+
return RATS_OK;
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
rats_error_t rats_broadcast_json(rats_t node, const char* type, const char* json) {
|
|
480
|
+
if (!type || !json) return RATS_ERR_INVALID_ARG;
|
|
481
|
+
auto* h = as_handle(node);
|
|
482
|
+
if (!h->messages) return RATS_ERR_NOT_ENABLED;
|
|
483
|
+
auto j = librats::Json::parse(json, nullptr, /*allow_exceptions=*/false);
|
|
484
|
+
if (j.is_discarded()) return RATS_ERR_INVALID_ARG;
|
|
485
|
+
h->messages->send(type, j);
|
|
486
|
+
return RATS_OK;
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
/* — file transfer — */
|
|
490
|
+
|
|
491
|
+
rats_error_t rats_enable_file_transfer(rats_t node, const char* temp_dir) {
|
|
492
|
+
auto* h = as_handle(node);
|
|
493
|
+
if (h->started) return RATS_ERR_ALREADY_STARTED;
|
|
494
|
+
if (!h->files)
|
|
495
|
+
h->files = h->node->add_subsystem(std::make_unique<FileTransfer>(temp_dir ? temp_dir : "."));
|
|
496
|
+
return RATS_OK;
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
rats_error_t rats_on_file_offer(rats_t node, rats_file_offer_cb cb, void* user) {
|
|
500
|
+
if (!cb) return RATS_ERR_INVALID_ARG;
|
|
501
|
+
auto* h = as_handle(node);
|
|
502
|
+
if (!h->files) return RATS_ERR_NOT_ENABLED;
|
|
503
|
+
h->files->on_offer([cb, user](const FileTransfer::Offer& o) {
|
|
504
|
+
cb(user, o.from.to_hex().c_str(), o.id, o.name.c_str(), o.size, o.is_directory ? 1 : 0);
|
|
505
|
+
});
|
|
506
|
+
return RATS_OK;
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
rats_error_t rats_on_file_progress(rats_t node, rats_file_progress_cb cb, void* user) {
|
|
510
|
+
if (!cb) return RATS_ERR_INVALID_ARG;
|
|
511
|
+
auto* h = as_handle(node);
|
|
512
|
+
if (!h->files) return RATS_ERR_NOT_ENABLED;
|
|
513
|
+
h->files->on_progress([cb, user](const FileTransfer::Progress& p) {
|
|
514
|
+
cb(user, p.id, p.peer.to_hex().c_str(), p.bytes_transferred, p.total_bytes,
|
|
515
|
+
static_cast<int>(p.status));
|
|
516
|
+
});
|
|
517
|
+
return RATS_OK;
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
rats_error_t rats_on_file_complete(rats_t node, rats_file_complete_cb cb, void* user) {
|
|
521
|
+
if (!cb) return RATS_ERR_INVALID_ARG;
|
|
522
|
+
auto* h = as_handle(node);
|
|
523
|
+
if (!h->files) return RATS_ERR_NOT_ENABLED;
|
|
524
|
+
h->files->on_complete([cb, user](uint64_t id, bool success, const std::string& path) {
|
|
525
|
+
cb(user, id, success ? 1 : 0, path.c_str());
|
|
526
|
+
});
|
|
527
|
+
return RATS_OK;
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
uint64_t rats_send_file(rats_t node, const char* peer_id_hex, const char* path) {
|
|
531
|
+
if (!peer_id_hex || !path) return 0;
|
|
532
|
+
auto* h = as_handle(node);
|
|
533
|
+
if (!h->files) return 0;
|
|
534
|
+
auto id = PeerId::from_hex(peer_id_hex);
|
|
535
|
+
if (!id) return 0;
|
|
536
|
+
return h->files->send_file(*id, path);
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
uint64_t rats_send_directory(rats_t node, const char* peer_id_hex, const char* dir_path) {
|
|
540
|
+
if (!peer_id_hex || !dir_path) return 0;
|
|
541
|
+
auto* h = as_handle(node);
|
|
542
|
+
if (!h->files) return 0;
|
|
543
|
+
auto id = PeerId::from_hex(peer_id_hex);
|
|
544
|
+
if (!id) return 0;
|
|
545
|
+
return h->files->send_directory(*id, dir_path);
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
rats_error_t rats_accept_file(rats_t node, const char* peer_id_hex, uint64_t transfer_id,
|
|
549
|
+
const char* dest_path) {
|
|
550
|
+
if (!peer_id_hex || !dest_path) return RATS_ERR_INVALID_ARG;
|
|
551
|
+
auto* h = as_handle(node);
|
|
552
|
+
if (!h->files) return RATS_ERR_NOT_ENABLED;
|
|
553
|
+
auto id = PeerId::from_hex(peer_id_hex);
|
|
554
|
+
if (!id) return RATS_ERR_INVALID_ARG;
|
|
555
|
+
h->files->accept(*id, transfer_id, dest_path);
|
|
556
|
+
return RATS_OK;
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
rats_error_t rats_reject_file(rats_t node, const char* peer_id_hex, uint64_t transfer_id) {
|
|
560
|
+
if (!peer_id_hex) return RATS_ERR_INVALID_ARG;
|
|
561
|
+
auto* h = as_handle(node);
|
|
562
|
+
if (!h->files) return RATS_ERR_NOT_ENABLED;
|
|
563
|
+
auto id = PeerId::from_hex(peer_id_hex);
|
|
564
|
+
if (!id) return RATS_ERR_INVALID_ARG;
|
|
565
|
+
h->files->reject(*id, transfer_id);
|
|
566
|
+
return RATS_OK;
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
rats_error_t rats_cancel_file(rats_t node, const char* peer_id_hex, uint64_t transfer_id) {
|
|
570
|
+
if (!peer_id_hex) return RATS_ERR_INVALID_ARG;
|
|
571
|
+
auto* h = as_handle(node);
|
|
572
|
+
if (!h->files) return RATS_ERR_NOT_ENABLED;
|
|
573
|
+
auto id = PeerId::from_hex(peer_id_hex);
|
|
574
|
+
if (!id) return RATS_ERR_INVALID_ARG;
|
|
575
|
+
return h->files->cancel(*id, transfer_id) ? RATS_OK : RATS_ERR_NO_SUCH_PEER;
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
rats_error_t rats_pause_file(rats_t node, const char* peer_id_hex, uint64_t transfer_id) {
|
|
579
|
+
if (!peer_id_hex) return RATS_ERR_INVALID_ARG;
|
|
580
|
+
auto* h = as_handle(node);
|
|
581
|
+
if (!h->files) return RATS_ERR_NOT_ENABLED;
|
|
582
|
+
auto id = PeerId::from_hex(peer_id_hex);
|
|
583
|
+
if (!id) return RATS_ERR_INVALID_ARG;
|
|
584
|
+
return h->files->pause(*id, transfer_id) ? RATS_OK : RATS_ERR_NO_SUCH_PEER;
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
rats_error_t rats_resume_file(rats_t node, const char* peer_id_hex, uint64_t transfer_id) {
|
|
588
|
+
if (!peer_id_hex) return RATS_ERR_INVALID_ARG;
|
|
589
|
+
auto* h = as_handle(node);
|
|
590
|
+
if (!h->files) return RATS_ERR_NOT_ENABLED;
|
|
591
|
+
auto id = PeerId::from_hex(peer_id_hex);
|
|
592
|
+
if (!id) return RATS_ERR_INVALID_ARG;
|
|
593
|
+
return h->files->resume(*id, transfer_id) ? RATS_OK : RATS_ERR_NO_SUCH_PEER;
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
/* — liveness — */
|
|
597
|
+
|
|
598
|
+
rats_error_t rats_enable_ping(rats_t node) {
|
|
599
|
+
auto* h = as_handle(node);
|
|
600
|
+
if (h->started) return RATS_ERR_ALREADY_STARTED;
|
|
601
|
+
if (!h->ping) h->ping = h->node->add_subsystem(std::make_unique<PingService>());
|
|
602
|
+
return RATS_OK;
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
int64_t rats_peer_rtt_ms(rats_t node, const char* peer_id_hex) {
|
|
606
|
+
if (!peer_id_hex) return -1;
|
|
607
|
+
auto* p = as_handle(node)->ping;
|
|
608
|
+
if (!p) return -1;
|
|
609
|
+
auto id = PeerId::from_hex(peer_id_hex);
|
|
610
|
+
if (!id) return -1;
|
|
611
|
+
auto rtt = p->last_rtt(*id);
|
|
612
|
+
return rtt ? static_cast<int64_t>(rtt->count()) : -1;
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
/* — automatic reconnection — */
|
|
616
|
+
|
|
617
|
+
rats_error_t rats_enable_reconnect(rats_t node) {
|
|
618
|
+
auto* h = as_handle(node);
|
|
619
|
+
if (h->started) return RATS_ERR_ALREADY_STARTED;
|
|
620
|
+
if (!h->reconnect) {
|
|
621
|
+
ReconnectionService::Config rc;
|
|
622
|
+
if (!h->data_dir.empty()) rc.store_path = h->data_dir + "/peers.json";
|
|
623
|
+
h->reconnect = h->node->add_subsystem(std::make_unique<ReconnectionService>(rc));
|
|
624
|
+
}
|
|
625
|
+
return RATS_OK;
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
/* — BitTorrent (only functional when built with RATS_SEARCH_FEATURES) — */
|
|
629
|
+
|
|
630
|
+
rats_error_t rats_enable_bittorrent(rats_t node, uint16_t listen_port, const char* download_path) {
|
|
631
|
+
#ifdef RATS_SEARCH_FEATURES
|
|
632
|
+
auto* h = as_handle(node);
|
|
633
|
+
if (h->started) return RATS_ERR_ALREADY_STARTED;
|
|
634
|
+
if (!h->bittorrent) {
|
|
635
|
+
Bittorrent::Config cfg;
|
|
636
|
+
cfg.client.listen_port = listen_port;
|
|
637
|
+
cfg.client.download_path = download_path ? download_path : ".";
|
|
638
|
+
h->bittorrent = h->node->add_subsystem(std::make_unique<Bittorrent>(cfg));
|
|
639
|
+
}
|
|
640
|
+
return RATS_OK;
|
|
641
|
+
#else
|
|
642
|
+
(void)node; (void)listen_port; (void)download_path;
|
|
643
|
+
return RATS_ERR_NOT_ENABLED;
|
|
644
|
+
#endif
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
rats_error_t rats_bt_add_magnet(rats_t node, const char* magnet_uri, const char* save_path) {
|
|
648
|
+
#ifdef RATS_SEARCH_FEATURES
|
|
649
|
+
if (!magnet_uri) return RATS_ERR_INVALID_ARG;
|
|
650
|
+
auto* h = as_handle(node);
|
|
651
|
+
if (!h->bittorrent || !h->bittorrent->is_running()) return RATS_ERR_NOT_ENABLED;
|
|
652
|
+
auto* c = h->bittorrent->client();
|
|
653
|
+
// Mutating the client must happen on its reactor thread.
|
|
654
|
+
c->reactor().post([c, uri = std::string(magnet_uri),
|
|
655
|
+
sp = std::string(save_path ? save_path : "")] { c->add_magnet(uri, sp); });
|
|
656
|
+
return RATS_OK;
|
|
657
|
+
#else
|
|
658
|
+
(void)node; (void)magnet_uri; (void)save_path;
|
|
659
|
+
return RATS_ERR_NOT_ENABLED;
|
|
660
|
+
#endif
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
rats_error_t rats_bt_add_torrent_file(rats_t node, const char* torrent_path, const char* save_path) {
|
|
664
|
+
#ifdef RATS_SEARCH_FEATURES
|
|
665
|
+
if (!torrent_path) return RATS_ERR_INVALID_ARG;
|
|
666
|
+
auto* h = as_handle(node);
|
|
667
|
+
if (!h->bittorrent || !h->bittorrent->is_running()) return RATS_ERR_NOT_ENABLED;
|
|
668
|
+
auto info = bittorrent::TorrentInfo::from_file(torrent_path);
|
|
669
|
+
if (!info) return RATS_ERR_INVALID_ARG;
|
|
670
|
+
auto* c = h->bittorrent->client();
|
|
671
|
+
c->reactor().post([c, info = *info, sp = std::string(save_path ? save_path : "")] {
|
|
672
|
+
c->add_torrent(info, sp);
|
|
673
|
+
});
|
|
674
|
+
return RATS_OK;
|
|
675
|
+
#else
|
|
676
|
+
(void)node; (void)torrent_path; (void)save_path;
|
|
677
|
+
return RATS_ERR_NOT_ENABLED;
|
|
678
|
+
#endif
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
rats_error_t rats_bt_remove_torrent(rats_t node, const char* info_hash_hex) {
|
|
682
|
+
#ifdef RATS_SEARCH_FEATURES
|
|
683
|
+
if (!info_hash_hex) return RATS_ERR_INVALID_ARG;
|
|
684
|
+
auto* h = as_handle(node);
|
|
685
|
+
if (!h->bittorrent || !h->bittorrent->is_running()) return RATS_ERR_NOT_ENABLED;
|
|
686
|
+
auto ih = bittorrent::info_hash_from_hex(info_hash_hex);
|
|
687
|
+
if (!ih) return RATS_ERR_INVALID_ARG;
|
|
688
|
+
auto* c = h->bittorrent->client();
|
|
689
|
+
c->reactor().post([c, ih = *ih] { c->remove_torrent(ih); });
|
|
690
|
+
return RATS_OK;
|
|
691
|
+
#else
|
|
692
|
+
(void)node; (void)info_hash_hex;
|
|
693
|
+
return RATS_ERR_NOT_ENABLED;
|
|
694
|
+
#endif
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
rats_error_t rats_add_reconnect(rats_t node, const char* host, uint16_t port) {
|
|
698
|
+
if (!host) return RATS_ERR_INVALID_ARG;
|
|
699
|
+
auto* h = as_handle(node);
|
|
700
|
+
if (!h->reconnect) return RATS_ERR_NOT_ENABLED;
|
|
701
|
+
const auto target = resolve_target(host, port);
|
|
702
|
+
if (!target) return RATS_ERR_INVALID_ARG; // not a valid literal, and did not resolve
|
|
703
|
+
h->reconnect->add(*target);
|
|
704
|
+
return RATS_OK;
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
rats_error_t rats_remove_reconnect(rats_t node, const char* host, uint16_t port) {
|
|
708
|
+
if (!host) return RATS_ERR_INVALID_ARG;
|
|
709
|
+
auto* h = as_handle(node);
|
|
710
|
+
if (!h->reconnect) return RATS_ERR_NOT_ENABLED;
|
|
711
|
+
const auto target = resolve_target(host, port);
|
|
712
|
+
if (!target) return RATS_ERR_INVALID_ARG;
|
|
713
|
+
h->reconnect->remove(*target);
|
|
714
|
+
return RATS_OK;
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
/* — logging — */
|
|
718
|
+
|
|
719
|
+
void rats_set_log_level(rats_log_level_t level) {
|
|
720
|
+
Logger::getInstance().set_log_level(static_cast<LogLevel>(level));
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
void rats_set_log_file(const char* path) {
|
|
724
|
+
auto& logger = Logger::getInstance();
|
|
725
|
+
if (path && path[0] != '\0') {
|
|
726
|
+
logger.set_log_file_path(path);
|
|
727
|
+
logger.set_file_logging_enabled(true);
|
|
728
|
+
} else {
|
|
729
|
+
logger.set_file_logging_enabled(false);
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
/* — protocol identity (node-scoped) — */
|
|
734
|
+
|
|
735
|
+
char* rats_protocol(rats_t node) {
|
|
736
|
+
return dup_string(node_of(node)->protocol());
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
/* — library info (process-global) — */
|
|
740
|
+
|
|
741
|
+
const char* rats_version_string(void) { return version::STRING; }
|
|
742
|
+
|
|
743
|
+
void rats_version(int* major, int* minor, int* patch, int* build) {
|
|
744
|
+
if (major) *major = version::MAJOR;
|
|
745
|
+
if (minor) *minor = version::MINOR;
|
|
746
|
+
if (patch) *patch = version::PATCH;
|
|
747
|
+
if (build) *build = version::BUILD;
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
const char* rats_git_describe(void) { return version::GIT_DESCRIBE; }
|
|
751
|
+
|
|
752
|
+
uint32_t rats_abi(void) {
|
|
753
|
+
return (static_cast<uint32_t>(version::MAJOR) << 16) |
|
|
754
|
+
(static_cast<uint32_t>(version::MINOR) << 8) |
|
|
755
|
+
(static_cast<uint32_t>(version::PATCH));
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
/* — utility — */
|
|
759
|
+
|
|
760
|
+
void rats_string_free(char* str) { std::free(str); }
|
|
761
|
+
|
|
762
|
+
} // extern "C"
|