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
package/native-src/src/turn.cpp
DELETED
|
@@ -1,762 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @file turn.cpp
|
|
3
|
-
* @brief TURN (Traversal Using Relays around NAT) Client Implementation
|
|
4
|
-
*
|
|
5
|
-
* Implements RFC 5766 - TURN protocol for NAT traversal via relay.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
#include "turn.h"
|
|
9
|
-
#include "logger.h"
|
|
10
|
-
#include "network_utils.h"
|
|
11
|
-
#include <cstring>
|
|
12
|
-
#include <algorithm>
|
|
13
|
-
|
|
14
|
-
namespace librats {
|
|
15
|
-
|
|
16
|
-
// ============================================================================
|
|
17
|
-
// Logging Macros
|
|
18
|
-
// ============================================================================
|
|
19
|
-
|
|
20
|
-
#define LOG_TURN_DEBUG(msg) LOG_DEBUG("turn", msg)
|
|
21
|
-
#define LOG_TURN_INFO(msg) LOG_INFO("turn", msg)
|
|
22
|
-
#define LOG_TURN_WARN(msg) LOG_WARN("turn", msg)
|
|
23
|
-
#define LOG_TURN_ERROR(msg) LOG_ERROR("turn", msg)
|
|
24
|
-
|
|
25
|
-
// ============================================================================
|
|
26
|
-
// TurnClient Implementation
|
|
27
|
-
// ============================================================================
|
|
28
|
-
|
|
29
|
-
TurnClient::TurnClient() = default;
|
|
30
|
-
|
|
31
|
-
TurnClient::TurnClient(const TurnClientConfig& config) : config_(config) {}
|
|
32
|
-
|
|
33
|
-
TurnClient::~TurnClient() {
|
|
34
|
-
close();
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
TurnClient::TurnClient(TurnClient&& other) noexcept
|
|
38
|
-
: config_(std::move(other.config_)),
|
|
39
|
-
socket_(other.socket_),
|
|
40
|
-
stun_client_(std::move(other.stun_client_)),
|
|
41
|
-
state_(other.state_),
|
|
42
|
-
allocation_(std::move(other.allocation_)),
|
|
43
|
-
nonce_(std::move(other.nonce_)),
|
|
44
|
-
realm_(std::move(other.realm_)),
|
|
45
|
-
permissions_(std::move(other.permissions_)),
|
|
46
|
-
channels_(std::move(other.channels_)),
|
|
47
|
-
peer_to_channel_(std::move(other.peer_to_channel_)),
|
|
48
|
-
next_channel_(other.next_channel_),
|
|
49
|
-
data_callback_(std::move(other.data_callback_)),
|
|
50
|
-
state_callback_(std::move(other.state_callback_)) {
|
|
51
|
-
other.socket_ = INVALID_SOCKET_VALUE;
|
|
52
|
-
other.state_ = TurnAllocationState::None;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
TurnClient& TurnClient::operator=(TurnClient&& other) noexcept {
|
|
56
|
-
if (this != &other) {
|
|
57
|
-
close();
|
|
58
|
-
config_ = std::move(other.config_);
|
|
59
|
-
socket_ = other.socket_;
|
|
60
|
-
stun_client_ = std::move(other.stun_client_);
|
|
61
|
-
state_ = other.state_;
|
|
62
|
-
allocation_ = std::move(other.allocation_);
|
|
63
|
-
nonce_ = std::move(other.nonce_);
|
|
64
|
-
realm_ = std::move(other.realm_);
|
|
65
|
-
permissions_ = std::move(other.permissions_);
|
|
66
|
-
channels_ = std::move(other.channels_);
|
|
67
|
-
peer_to_channel_ = std::move(other.peer_to_channel_);
|
|
68
|
-
next_channel_ = other.next_channel_;
|
|
69
|
-
data_callback_ = std::move(other.data_callback_);
|
|
70
|
-
state_callback_ = std::move(other.state_callback_);
|
|
71
|
-
other.socket_ = INVALID_SOCKET_VALUE;
|
|
72
|
-
other.state_ = TurnAllocationState::None;
|
|
73
|
-
}
|
|
74
|
-
return *this;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
void TurnClient::set_config(const TurnClientConfig& config) {
|
|
78
|
-
config_ = config;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
void TurnClient::close() {
|
|
82
|
-
stop_refresh_thread();
|
|
83
|
-
|
|
84
|
-
if (is_allocated()) {
|
|
85
|
-
release();
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
if (is_valid_socket(socket_)) {
|
|
89
|
-
close_socket(socket_);
|
|
90
|
-
socket_ = INVALID_SOCKET_VALUE;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
set_state(TurnAllocationState::None);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
bool TurnClient::ensure_socket() {
|
|
97
|
-
if (is_valid_socket(socket_)) {
|
|
98
|
-
return true;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
socket_ = create_udp_socket(0);
|
|
102
|
-
if (!is_valid_socket(socket_)) {
|
|
103
|
-
LOG_TURN_ERROR("Failed to create UDP socket");
|
|
104
|
-
return false;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
return true;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
std::vector<uint8_t> TurnClient::compute_message_integrity_key() const {
|
|
111
|
-
std::string effective_realm = realm_.empty() ? config_.realm : realm_;
|
|
112
|
-
return stun_compute_long_term_key(config_.username, effective_realm, config_.password);
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
void TurnClient::set_state(TurnAllocationState new_state) {
|
|
116
|
-
if (state_ != new_state) {
|
|
117
|
-
state_ = new_state;
|
|
118
|
-
if (state_callback_) {
|
|
119
|
-
state_callback_(new_state);
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
std::string TurnClient::peer_key(const StunMappedAddress& peer) const {
|
|
125
|
-
return peer.address + ":" + std::to_string(peer.port);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
// ============================================================================
|
|
129
|
-
// Allocation Management
|
|
130
|
-
// ============================================================================
|
|
131
|
-
|
|
132
|
-
TurnResult TurnClient::allocate() {
|
|
133
|
-
LOG_TURN_INFO("Requesting TURN allocation from " << config_.server << ":" << config_.port);
|
|
134
|
-
|
|
135
|
-
if (!ensure_socket()) {
|
|
136
|
-
return TurnResult::Error("Failed to create socket");
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
set_state(TurnAllocationState::Allocating);
|
|
140
|
-
|
|
141
|
-
// First request without credentials to get nonce and realm
|
|
142
|
-
auto result = send_allocate_request(false);
|
|
143
|
-
|
|
144
|
-
if (!result.success && result.error) {
|
|
145
|
-
if (result.error->code == StunErrorCode::Unauthorized) {
|
|
146
|
-
// Expected - server sends 401 with nonce and realm
|
|
147
|
-
// Retry with credentials
|
|
148
|
-
LOG_TURN_DEBUG("Got 401 response, retrying with credentials");
|
|
149
|
-
result = send_allocate_request(true);
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
if (result.success) {
|
|
154
|
-
set_state(TurnAllocationState::Allocated);
|
|
155
|
-
LOG_TURN_INFO("TURN allocation successful: " << allocation_.relay_address.to_string());
|
|
156
|
-
|
|
157
|
-
if (config_.auto_refresh) {
|
|
158
|
-
start_refresh_thread();
|
|
159
|
-
}
|
|
160
|
-
} else {
|
|
161
|
-
set_state(TurnAllocationState::Failed);
|
|
162
|
-
LOG_TURN_ERROR("TURN allocation failed: " << result.error_message);
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
return result;
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
TurnResult TurnClient::send_allocate_request(bool with_credentials) {
|
|
169
|
-
StunMessage request(StunMessageType::AllocateRequest);
|
|
170
|
-
request.add_requested_transport(TURN_TRANSPORT_UDP);
|
|
171
|
-
request.add_lifetime(config_.requested_lifetime);
|
|
172
|
-
|
|
173
|
-
if (!config_.software.empty()) {
|
|
174
|
-
request.add_software(config_.software);
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
if (with_credentials && !config_.username.empty()) {
|
|
178
|
-
request.add_username(config_.username);
|
|
179
|
-
std::string effective_realm = realm_.empty() ? config_.realm : realm_;
|
|
180
|
-
if (!effective_realm.empty()) {
|
|
181
|
-
request.add_realm(effective_realm);
|
|
182
|
-
}
|
|
183
|
-
if (!nonce_.empty()) {
|
|
184
|
-
request.add_nonce(nonce_);
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
std::vector<uint8_t> data;
|
|
189
|
-
if (with_credentials && !config_.password.empty()) {
|
|
190
|
-
auto key = compute_message_integrity_key();
|
|
191
|
-
data = request.serialize_with_integrity(std::string(key.begin(), key.end()));
|
|
192
|
-
} else {
|
|
193
|
-
data = request.serialize();
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
auto response = stun_client_.send_request(socket_, request, config_.server,
|
|
197
|
-
config_.port, config_.timeout_ms);
|
|
198
|
-
|
|
199
|
-
if (!response) {
|
|
200
|
-
return TurnResult::Error("Request timed out");
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
// Extract nonce and realm from any response
|
|
204
|
-
if (auto new_nonce = response->get_nonce()) {
|
|
205
|
-
nonce_ = *new_nonce;
|
|
206
|
-
}
|
|
207
|
-
if (auto new_realm = response->get_realm()) {
|
|
208
|
-
realm_ = *new_realm;
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
if (response->is_error_response()) {
|
|
212
|
-
auto error = response->get_error();
|
|
213
|
-
if (error) {
|
|
214
|
-
return TurnResult::Error(error->code, error->reason);
|
|
215
|
-
}
|
|
216
|
-
return TurnResult::Error("Unknown error");
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
if (response->is_success_response()) {
|
|
220
|
-
// Parse allocation response
|
|
221
|
-
auto relay_addr = response->get_xor_relayed_address();
|
|
222
|
-
auto mapped_addr = response->get_xor_mapped_address();
|
|
223
|
-
auto lifetime = response->get_lifetime();
|
|
224
|
-
|
|
225
|
-
if (!relay_addr || !lifetime) {
|
|
226
|
-
return TurnResult::Error("Invalid allocation response");
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
allocation_.relay_address = *relay_addr;
|
|
230
|
-
if (mapped_addr) {
|
|
231
|
-
allocation_.mapped_address = *mapped_addr;
|
|
232
|
-
}
|
|
233
|
-
allocation_.lifetime = *lifetime;
|
|
234
|
-
allocation_.allocated_at = std::chrono::steady_clock::now();
|
|
235
|
-
allocation_.expires_at = allocation_.allocated_at +
|
|
236
|
-
std::chrono::seconds(allocation_.lifetime);
|
|
237
|
-
|
|
238
|
-
return TurnResult::Success();
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
return TurnResult::Error("Unexpected response type");
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
TurnResult TurnClient::refresh(uint32_t lifetime) {
|
|
245
|
-
if (!is_allocated()) {
|
|
246
|
-
return TurnResult::Error("No active allocation");
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
LOG_TURN_DEBUG("Refreshing TURN allocation");
|
|
250
|
-
set_state(TurnAllocationState::Refreshing);
|
|
251
|
-
|
|
252
|
-
auto result = send_refresh_request(lifetime == 0 ? config_.requested_lifetime : lifetime);
|
|
253
|
-
|
|
254
|
-
if (result.success) {
|
|
255
|
-
set_state(TurnAllocationState::Allocated);
|
|
256
|
-
} else {
|
|
257
|
-
set_state(TurnAllocationState::Failed);
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
return result;
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
TurnResult TurnClient::send_refresh_request(uint32_t lifetime) {
|
|
264
|
-
StunMessage request(StunMessageType::RefreshRequest);
|
|
265
|
-
request.add_lifetime(lifetime);
|
|
266
|
-
request.add_username(config_.username);
|
|
267
|
-
|
|
268
|
-
std::string effective_realm = realm_.empty() ? config_.realm : realm_;
|
|
269
|
-
if (!effective_realm.empty()) {
|
|
270
|
-
request.add_realm(effective_realm);
|
|
271
|
-
}
|
|
272
|
-
if (!nonce_.empty()) {
|
|
273
|
-
request.add_nonce(nonce_);
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
auto key = compute_message_integrity_key();
|
|
277
|
-
auto data = request.serialize_with_integrity(std::string(key.begin(), key.end()));
|
|
278
|
-
|
|
279
|
-
auto response = stun_client_.send_request(socket_, request, config_.server,
|
|
280
|
-
config_.port, config_.timeout_ms);
|
|
281
|
-
|
|
282
|
-
if (!response) {
|
|
283
|
-
return TurnResult::Error("Refresh request timed out");
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
// Update nonce if changed
|
|
287
|
-
if (auto new_nonce = response->get_nonce()) {
|
|
288
|
-
nonce_ = *new_nonce;
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
if (response->is_error_response()) {
|
|
292
|
-
auto error = response->get_error();
|
|
293
|
-
if (error) {
|
|
294
|
-
if (error->code == StunErrorCode::StaleNonce) {
|
|
295
|
-
// Retry with new nonce
|
|
296
|
-
return send_refresh_request(lifetime);
|
|
297
|
-
}
|
|
298
|
-
return TurnResult::Error(error->code, error->reason);
|
|
299
|
-
}
|
|
300
|
-
return TurnResult::Error("Unknown error");
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
if (response->is_success_response()) {
|
|
304
|
-
auto new_lifetime = response->get_lifetime();
|
|
305
|
-
if (new_lifetime) {
|
|
306
|
-
allocation_.lifetime = *new_lifetime;
|
|
307
|
-
allocation_.expires_at = std::chrono::steady_clock::now() +
|
|
308
|
-
std::chrono::seconds(allocation_.lifetime);
|
|
309
|
-
LOG_TURN_DEBUG("Allocation refreshed, new lifetime: " << allocation_.lifetime);
|
|
310
|
-
}
|
|
311
|
-
return TurnResult::Success();
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
return TurnResult::Error("Unexpected response type");
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
TurnResult TurnClient::release() {
|
|
318
|
-
if (!is_allocated()) {
|
|
319
|
-
return TurnResult::Success(); // Already released
|
|
320
|
-
}
|
|
321
|
-
|
|
322
|
-
LOG_TURN_INFO("Releasing TURN allocation");
|
|
323
|
-
stop_refresh_thread();
|
|
324
|
-
|
|
325
|
-
auto result = send_refresh_request(0); // Lifetime 0 = release
|
|
326
|
-
|
|
327
|
-
allocation_ = TurnAllocation();
|
|
328
|
-
set_state(TurnAllocationState::None);
|
|
329
|
-
|
|
330
|
-
return result;
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
// ============================================================================
|
|
334
|
-
// Permission Management
|
|
335
|
-
// ============================================================================
|
|
336
|
-
|
|
337
|
-
TurnResult TurnClient::create_permission(const std::string& peer_address) {
|
|
338
|
-
StunMappedAddress peer(StunAddressFamily::IPv4, peer_address, 0);
|
|
339
|
-
return create_permission(peer);
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
TurnResult TurnClient::create_permission(const StunMappedAddress& peer) {
|
|
343
|
-
return create_permissions({peer.address});
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
TurnResult TurnClient::create_permissions(const std::vector<std::string>& peer_addresses) {
|
|
347
|
-
if (!is_allocated()) {
|
|
348
|
-
return TurnResult::Error("No active allocation");
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
std::vector<StunMappedAddress> peers;
|
|
352
|
-
for (const auto& addr : peer_addresses) {
|
|
353
|
-
peers.emplace_back(StunAddressFamily::IPv4, addr, 0);
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
return send_create_permission_request(peers);
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
TurnResult TurnClient::send_create_permission_request(const std::vector<StunMappedAddress>& peers) {
|
|
360
|
-
StunMessage request(StunMessageType::CreatePermissionRequest);
|
|
361
|
-
|
|
362
|
-
for (const auto& peer : peers) {
|
|
363
|
-
request.add_xor_peer_address(peer);
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
request.add_username(config_.username);
|
|
367
|
-
std::string effective_realm = realm_.empty() ? config_.realm : realm_;
|
|
368
|
-
if (!effective_realm.empty()) {
|
|
369
|
-
request.add_realm(effective_realm);
|
|
370
|
-
}
|
|
371
|
-
if (!nonce_.empty()) {
|
|
372
|
-
request.add_nonce(nonce_);
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
auto key = compute_message_integrity_key();
|
|
376
|
-
auto data = request.serialize_with_integrity(std::string(key.begin(), key.end()));
|
|
377
|
-
|
|
378
|
-
auto response = stun_client_.send_request(socket_, request, config_.server,
|
|
379
|
-
config_.port, config_.timeout_ms);
|
|
380
|
-
|
|
381
|
-
if (!response) {
|
|
382
|
-
return TurnResult::Error("CreatePermission request timed out");
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
if (auto new_nonce = response->get_nonce()) {
|
|
386
|
-
nonce_ = *new_nonce;
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
if (response->is_error_response()) {
|
|
390
|
-
auto error = response->get_error();
|
|
391
|
-
if (error) {
|
|
392
|
-
if (error->code == StunErrorCode::StaleNonce) {
|
|
393
|
-
return send_create_permission_request(peers);
|
|
394
|
-
}
|
|
395
|
-
return TurnResult::Error(error->code, error->reason);
|
|
396
|
-
}
|
|
397
|
-
return TurnResult::Error("Unknown error");
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
if (response->is_success_response()) {
|
|
401
|
-
std::lock_guard<std::mutex> lock(mutex_);
|
|
402
|
-
auto expires_at = std::chrono::steady_clock::now() + std::chrono::minutes(5);
|
|
403
|
-
|
|
404
|
-
for (const auto& peer : peers) {
|
|
405
|
-
TurnPermission perm;
|
|
406
|
-
perm.peer_address = peer.address;
|
|
407
|
-
perm.expires_at = expires_at;
|
|
408
|
-
permissions_[peer.address] = perm;
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
LOG_TURN_DEBUG("Created permissions for " << peers.size() << " peers");
|
|
412
|
-
return TurnResult::Success();
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
return TurnResult::Error("Unexpected response type");
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
bool TurnClient::has_permission(const std::string& peer_address) const {
|
|
419
|
-
std::lock_guard<std::mutex> lock(mutex_);
|
|
420
|
-
auto it = permissions_.find(peer_address);
|
|
421
|
-
if (it == permissions_.end()) return false;
|
|
422
|
-
return !it->second.is_expired();
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
// ============================================================================
|
|
426
|
-
// Channel Binding
|
|
427
|
-
// ============================================================================
|
|
428
|
-
|
|
429
|
-
uint16_t TurnClient::bind_channel(const StunMappedAddress& peer) {
|
|
430
|
-
if (!is_allocated()) {
|
|
431
|
-
return 0;
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
std::string key = peer_key(peer);
|
|
435
|
-
|
|
436
|
-
{
|
|
437
|
-
std::lock_guard<std::mutex> lock(mutex_);
|
|
438
|
-
auto it = peer_to_channel_.find(key);
|
|
439
|
-
if (it != peer_to_channel_.end()) {
|
|
440
|
-
auto& binding = channels_[it->second];
|
|
441
|
-
if (!binding.is_expired()) {
|
|
442
|
-
return it->second; // Already bound
|
|
443
|
-
}
|
|
444
|
-
}
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
uint16_t channel;
|
|
448
|
-
{
|
|
449
|
-
std::lock_guard<std::mutex> lock(mutex_);
|
|
450
|
-
channel = next_channel_++;
|
|
451
|
-
if (next_channel_ > TURN_CHANNEL_MAX) {
|
|
452
|
-
next_channel_ = TURN_CHANNEL_MIN;
|
|
453
|
-
}
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
auto result = send_channel_bind_request(channel, peer);
|
|
457
|
-
if (!result.success) {
|
|
458
|
-
LOG_TURN_ERROR("Channel binding failed: " << result.error_message);
|
|
459
|
-
return 0;
|
|
460
|
-
}
|
|
461
|
-
|
|
462
|
-
{
|
|
463
|
-
std::lock_guard<std::mutex> lock(mutex_);
|
|
464
|
-
TurnChannelBinding binding;
|
|
465
|
-
binding.channel_number = channel;
|
|
466
|
-
binding.peer_address = peer;
|
|
467
|
-
binding.expires_at = std::chrono::steady_clock::now() + std::chrono::minutes(10);
|
|
468
|
-
|
|
469
|
-
channels_[channel] = binding;
|
|
470
|
-
peer_to_channel_[key] = channel;
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
LOG_TURN_DEBUG("Bound channel " << channel << " to " << peer.to_string());
|
|
474
|
-
return channel;
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
TurnResult TurnClient::send_channel_bind_request(uint16_t channel, const StunMappedAddress& peer) {
|
|
478
|
-
StunMessage request(StunMessageType::ChannelBindRequest);
|
|
479
|
-
request.add_channel_number(channel);
|
|
480
|
-
request.add_xor_peer_address(peer);
|
|
481
|
-
|
|
482
|
-
request.add_username(config_.username);
|
|
483
|
-
std::string effective_realm = realm_.empty() ? config_.realm : realm_;
|
|
484
|
-
if (!effective_realm.empty()) {
|
|
485
|
-
request.add_realm(effective_realm);
|
|
486
|
-
}
|
|
487
|
-
if (!nonce_.empty()) {
|
|
488
|
-
request.add_nonce(nonce_);
|
|
489
|
-
}
|
|
490
|
-
|
|
491
|
-
auto key = compute_message_integrity_key();
|
|
492
|
-
auto data = request.serialize_with_integrity(std::string(key.begin(), key.end()));
|
|
493
|
-
|
|
494
|
-
auto response = stun_client_.send_request(socket_, request, config_.server,
|
|
495
|
-
config_.port, config_.timeout_ms);
|
|
496
|
-
|
|
497
|
-
if (!response) {
|
|
498
|
-
return TurnResult::Error("ChannelBind request timed out");
|
|
499
|
-
}
|
|
500
|
-
|
|
501
|
-
if (auto new_nonce = response->get_nonce()) {
|
|
502
|
-
nonce_ = *new_nonce;
|
|
503
|
-
}
|
|
504
|
-
|
|
505
|
-
if (response->is_error_response()) {
|
|
506
|
-
auto error = response->get_error();
|
|
507
|
-
if (error) {
|
|
508
|
-
if (error->code == StunErrorCode::StaleNonce) {
|
|
509
|
-
return send_channel_bind_request(channel, peer);
|
|
510
|
-
}
|
|
511
|
-
return TurnResult::Error(error->code, error->reason);
|
|
512
|
-
}
|
|
513
|
-
return TurnResult::Error("Unknown error");
|
|
514
|
-
}
|
|
515
|
-
|
|
516
|
-
if (response->is_success_response()) {
|
|
517
|
-
return TurnResult::Success();
|
|
518
|
-
}
|
|
519
|
-
|
|
520
|
-
return TurnResult::Error("Unexpected response type");
|
|
521
|
-
}
|
|
522
|
-
|
|
523
|
-
uint16_t TurnClient::get_channel(const StunMappedAddress& peer) const {
|
|
524
|
-
std::lock_guard<std::mutex> lock(mutex_);
|
|
525
|
-
std::string key = peer_key(peer);
|
|
526
|
-
auto it = peer_to_channel_.find(key);
|
|
527
|
-
if (it == peer_to_channel_.end()) return 0;
|
|
528
|
-
|
|
529
|
-
auto ch_it = channels_.find(it->second);
|
|
530
|
-
if (ch_it == channels_.end() || ch_it->second.is_expired()) return 0;
|
|
531
|
-
|
|
532
|
-
return it->second;
|
|
533
|
-
}
|
|
534
|
-
|
|
535
|
-
std::optional<StunMappedAddress> TurnClient::get_channel_peer(uint16_t channel) const {
|
|
536
|
-
std::lock_guard<std::mutex> lock(mutex_);
|
|
537
|
-
auto it = channels_.find(channel);
|
|
538
|
-
if (it == channels_.end() || it->second.is_expired()) {
|
|
539
|
-
return std::nullopt;
|
|
540
|
-
}
|
|
541
|
-
return it->second.peer_address;
|
|
542
|
-
}
|
|
543
|
-
|
|
544
|
-
TurnResult TurnClient::refresh_channel(uint16_t channel) {
|
|
545
|
-
std::optional<StunMappedAddress> peer;
|
|
546
|
-
{
|
|
547
|
-
std::lock_guard<std::mutex> lock(mutex_);
|
|
548
|
-
auto it = channels_.find(channel);
|
|
549
|
-
if (it != channels_.end()) {
|
|
550
|
-
peer = it->second.peer_address;
|
|
551
|
-
}
|
|
552
|
-
}
|
|
553
|
-
|
|
554
|
-
if (!peer) {
|
|
555
|
-
return TurnResult::Error("Channel not found");
|
|
556
|
-
}
|
|
557
|
-
|
|
558
|
-
auto result = send_channel_bind_request(channel, *peer);
|
|
559
|
-
if (result.success) {
|
|
560
|
-
std::lock_guard<std::mutex> lock(mutex_);
|
|
561
|
-
auto it = channels_.find(channel);
|
|
562
|
-
if (it != channels_.end()) {
|
|
563
|
-
it->second.expires_at = std::chrono::steady_clock::now() + std::chrono::minutes(10);
|
|
564
|
-
}
|
|
565
|
-
}
|
|
566
|
-
|
|
567
|
-
return result;
|
|
568
|
-
}
|
|
569
|
-
|
|
570
|
-
// ============================================================================
|
|
571
|
-
// Data Transfer
|
|
572
|
-
// ============================================================================
|
|
573
|
-
|
|
574
|
-
bool TurnClient::send_data(const StunMappedAddress& peer, const std::vector<uint8_t>& data) {
|
|
575
|
-
uint16_t channel = get_channel(peer);
|
|
576
|
-
if (channel != 0) {
|
|
577
|
-
return send_channel_data(channel, data);
|
|
578
|
-
}
|
|
579
|
-
return send_indication(peer, data);
|
|
580
|
-
}
|
|
581
|
-
|
|
582
|
-
bool TurnClient::send_indication(const StunMappedAddress& peer, const std::vector<uint8_t>& data) {
|
|
583
|
-
if (!is_allocated()) {
|
|
584
|
-
return false;
|
|
585
|
-
}
|
|
586
|
-
|
|
587
|
-
// Ensure permission exists
|
|
588
|
-
if (!has_permission(peer.address)) {
|
|
589
|
-
auto result = create_permission(peer);
|
|
590
|
-
if (!result.success) {
|
|
591
|
-
LOG_TURN_ERROR("Failed to create permission for " << peer.address);
|
|
592
|
-
return false;
|
|
593
|
-
}
|
|
594
|
-
}
|
|
595
|
-
|
|
596
|
-
StunMessage indication;
|
|
597
|
-
indication.type = StunMessageType::SendIndication;
|
|
598
|
-
indication.generate_transaction_id();
|
|
599
|
-
indication.add_xor_peer_address(peer);
|
|
600
|
-
indication.add_data(data);
|
|
601
|
-
|
|
602
|
-
auto msg_data = indication.serialize();
|
|
603
|
-
int sent = send_udp_data(socket_, msg_data, config_.server, config_.port);
|
|
604
|
-
|
|
605
|
-
return sent > 0;
|
|
606
|
-
}
|
|
607
|
-
|
|
608
|
-
bool TurnClient::send_channel_data(uint16_t channel, const std::vector<uint8_t>& data) {
|
|
609
|
-
if (!is_allocated()) {
|
|
610
|
-
return false;
|
|
611
|
-
}
|
|
612
|
-
|
|
613
|
-
// Channel data format: 2-byte channel + 2-byte length + data (padded to 4 bytes)
|
|
614
|
-
std::vector<uint8_t> msg;
|
|
615
|
-
msg.reserve(TURN_CHANNEL_HEADER_SIZE + data.size() + 3);
|
|
616
|
-
|
|
617
|
-
msg.push_back(static_cast<uint8_t>(channel >> 8));
|
|
618
|
-
msg.push_back(static_cast<uint8_t>(channel));
|
|
619
|
-
msg.push_back(static_cast<uint8_t>(data.size() >> 8));
|
|
620
|
-
msg.push_back(static_cast<uint8_t>(data.size()));
|
|
621
|
-
msg.insert(msg.end(), data.begin(), data.end());
|
|
622
|
-
|
|
623
|
-
// Pad to 4-byte boundary
|
|
624
|
-
while (msg.size() % 4 != 0) {
|
|
625
|
-
msg.push_back(0);
|
|
626
|
-
}
|
|
627
|
-
|
|
628
|
-
int sent = send_udp_data(socket_, msg, config_.server, config_.port);
|
|
629
|
-
return sent > 0;
|
|
630
|
-
}
|
|
631
|
-
|
|
632
|
-
std::optional<std::pair<StunMappedAddress, std::vector<uint8_t>>> TurnClient::receive_data(int timeout_ms) {
|
|
633
|
-
if (!is_valid_socket(socket_)) {
|
|
634
|
-
return std::nullopt;
|
|
635
|
-
}
|
|
636
|
-
|
|
637
|
-
Peer sender;
|
|
638
|
-
auto data = receive_udp_data(socket_, STUN_MAX_MESSAGE_SIZE, sender, timeout_ms);
|
|
639
|
-
|
|
640
|
-
if (data.empty()) {
|
|
641
|
-
return std::nullopt;
|
|
642
|
-
}
|
|
643
|
-
|
|
644
|
-
// Check if it's a STUN message (Data indication)
|
|
645
|
-
if (StunMessage::is_stun_message(data)) {
|
|
646
|
-
auto msg = StunMessage::deserialize(data);
|
|
647
|
-
if (msg && msg->type == StunMessageType::DataIndication) {
|
|
648
|
-
auto peer_addr = msg->get_xor_peer_address();
|
|
649
|
-
auto payload = msg->get_data();
|
|
650
|
-
|
|
651
|
-
if (peer_addr && payload) {
|
|
652
|
-
return std::make_pair(*peer_addr, *payload);
|
|
653
|
-
}
|
|
654
|
-
}
|
|
655
|
-
return std::nullopt;
|
|
656
|
-
}
|
|
657
|
-
|
|
658
|
-
// Check if it's channel data
|
|
659
|
-
if (data.size() >= TURN_CHANNEL_HEADER_SIZE) {
|
|
660
|
-
uint16_t channel = (static_cast<uint16_t>(data[0]) << 8) | data[1];
|
|
661
|
-
|
|
662
|
-
if (channel >= TURN_CHANNEL_MIN && channel <= TURN_CHANNEL_MAX) {
|
|
663
|
-
uint16_t length = (static_cast<uint16_t>(data[2]) << 8) | data[3];
|
|
664
|
-
|
|
665
|
-
if (data.size() >= TURN_CHANNEL_HEADER_SIZE + length) {
|
|
666
|
-
auto peer = get_channel_peer(channel);
|
|
667
|
-
if (peer) {
|
|
668
|
-
std::vector<uint8_t> payload(data.begin() + TURN_CHANNEL_HEADER_SIZE,
|
|
669
|
-
data.begin() + TURN_CHANNEL_HEADER_SIZE + length);
|
|
670
|
-
return std::make_pair(*peer, payload);
|
|
671
|
-
}
|
|
672
|
-
}
|
|
673
|
-
}
|
|
674
|
-
}
|
|
675
|
-
|
|
676
|
-
return std::nullopt;
|
|
677
|
-
}
|
|
678
|
-
|
|
679
|
-
void TurnClient::set_data_callback(TurnDataCallback callback) {
|
|
680
|
-
data_callback_ = std::move(callback);
|
|
681
|
-
}
|
|
682
|
-
|
|
683
|
-
void TurnClient::set_state_callback(TurnStateCallback callback) {
|
|
684
|
-
state_callback_ = std::move(callback);
|
|
685
|
-
}
|
|
686
|
-
|
|
687
|
-
void TurnClient::process_incoming() {
|
|
688
|
-
auto result = receive_data(0); // Non-blocking
|
|
689
|
-
if (result && data_callback_) {
|
|
690
|
-
data_callback_(result->first, result->second);
|
|
691
|
-
}
|
|
692
|
-
}
|
|
693
|
-
|
|
694
|
-
// ============================================================================
|
|
695
|
-
// Refresh Thread
|
|
696
|
-
// ============================================================================
|
|
697
|
-
|
|
698
|
-
void TurnClient::start_refresh_thread() {
|
|
699
|
-
if (refresh_running_) return;
|
|
700
|
-
|
|
701
|
-
refresh_running_ = true;
|
|
702
|
-
refresh_thread_ = std::thread(&TurnClient::refresh_loop, this);
|
|
703
|
-
}
|
|
704
|
-
|
|
705
|
-
void TurnClient::stop_refresh_thread() {
|
|
706
|
-
refresh_running_ = false;
|
|
707
|
-
if (refresh_thread_.joinable()) {
|
|
708
|
-
refresh_thread_.join();
|
|
709
|
-
}
|
|
710
|
-
}
|
|
711
|
-
|
|
712
|
-
void TurnClient::refresh_loop() {
|
|
713
|
-
LOG_TURN_DEBUG("Refresh thread started");
|
|
714
|
-
|
|
715
|
-
while (refresh_running_) {
|
|
716
|
-
// Sleep for a bit
|
|
717
|
-
for (int i = 0; i < 10 && refresh_running_; i++) {
|
|
718
|
-
std::this_thread::sleep_for(std::chrono::seconds(1));
|
|
719
|
-
}
|
|
720
|
-
|
|
721
|
-
if (!refresh_running_) break;
|
|
722
|
-
|
|
723
|
-
// Check if allocation needs refresh (refresh at 80% of lifetime)
|
|
724
|
-
if (is_allocated()) {
|
|
725
|
-
auto remaining = allocation_.remaining_lifetime();
|
|
726
|
-
auto threshold = allocation_.lifetime * 0.2; // Refresh when 20% remaining
|
|
727
|
-
|
|
728
|
-
if (remaining <= threshold) {
|
|
729
|
-
LOG_TURN_DEBUG("Allocation lifetime low (" << remaining << "s), refreshing");
|
|
730
|
-
refresh();
|
|
731
|
-
}
|
|
732
|
-
}
|
|
733
|
-
|
|
734
|
-
// Refresh permissions and channels
|
|
735
|
-
{
|
|
736
|
-
std::lock_guard<std::mutex> lock(mutex_);
|
|
737
|
-
|
|
738
|
-
// Clean up expired permissions
|
|
739
|
-
for (auto it = permissions_.begin(); it != permissions_.end();) {
|
|
740
|
-
if (it->second.is_expired()) {
|
|
741
|
-
it = permissions_.erase(it);
|
|
742
|
-
} else {
|
|
743
|
-
++it;
|
|
744
|
-
}
|
|
745
|
-
}
|
|
746
|
-
|
|
747
|
-
// Clean up expired channels
|
|
748
|
-
for (auto it = channels_.begin(); it != channels_.end();) {
|
|
749
|
-
if (it->second.is_expired()) {
|
|
750
|
-
peer_to_channel_.erase(peer_key(it->second.peer_address));
|
|
751
|
-
it = channels_.erase(it);
|
|
752
|
-
} else {
|
|
753
|
-
++it;
|
|
754
|
-
}
|
|
755
|
-
}
|
|
756
|
-
}
|
|
757
|
-
}
|
|
758
|
-
|
|
759
|
-
LOG_TURN_DEBUG("Refresh thread stopped");
|
|
760
|
-
}
|
|
761
|
-
|
|
762
|
-
} // namespace librats
|