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,496 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include "librats/core/address.h"
|
|
4
|
+
#include "librats/core/bytes.h"
|
|
5
|
+
|
|
6
|
+
#include <string>
|
|
7
|
+
#include <functional>
|
|
8
|
+
#include <optional>
|
|
9
|
+
#include <vector>
|
|
10
|
+
#include <cstddef>
|
|
11
|
+
#include <cstdint>
|
|
12
|
+
|
|
13
|
+
#ifdef _WIN32
|
|
14
|
+
#include <winsock2.h>
|
|
15
|
+
#include <ws2tcpip.h>
|
|
16
|
+
#ifdef _MSC_VER
|
|
17
|
+
#pragma comment(lib, "ws2_32.lib")
|
|
18
|
+
#endif
|
|
19
|
+
#else
|
|
20
|
+
#include <sys/socket.h>
|
|
21
|
+
#include <arpa/inet.h>
|
|
22
|
+
#include <netinet/in.h>
|
|
23
|
+
#include <unistd.h>
|
|
24
|
+
#endif
|
|
25
|
+
|
|
26
|
+
namespace librats {
|
|
27
|
+
|
|
28
|
+
/*
|
|
29
|
+
* socket_t and the sentinel values live in the namespace, and the macros carry
|
|
30
|
+
* the RATS_ prefix, because this header is installed: a bare `socket_t` typedef
|
|
31
|
+
* or a bare `closesocket` macro at global scope collides with any other library
|
|
32
|
+
* that installs the same portability shim (and a function-like macro named
|
|
33
|
+
* `closesocket` would silently rewrite the consumer's own calls). Use
|
|
34
|
+
* close_socket() below rather than reintroducing that macro.
|
|
35
|
+
*/
|
|
36
|
+
#ifdef _WIN32
|
|
37
|
+
typedef SOCKET socket_t;
|
|
38
|
+
#define RATS_INVALID_SOCKET INVALID_SOCKET
|
|
39
|
+
#define RATS_SOCKET_ERROR SOCKET_ERROR
|
|
40
|
+
#else
|
|
41
|
+
typedef int socket_t;
|
|
42
|
+
#define RATS_INVALID_SOCKET -1
|
|
43
|
+
#define RATS_SOCKET_ERROR -1
|
|
44
|
+
#endif
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Address family for socket creation
|
|
48
|
+
*/
|
|
49
|
+
enum class AddressFamily {
|
|
50
|
+
IPv4, // IPv4 only
|
|
51
|
+
IPv6, // IPv6 only
|
|
52
|
+
DualStack // IPv6 socket with IPv4 support (default)
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Whether a socket bound with `af` can send to an address of the given family
|
|
57
|
+
* at all.
|
|
58
|
+
*
|
|
59
|
+
* A socket cannot leave its own family: sendto() with a sockaddr of the wrong
|
|
60
|
+
* one is refused outright. On a datagram socket that refusal arrives per packet
|
|
61
|
+
* and says nothing about the destination, so a caller that does not ask this
|
|
62
|
+
* first cannot tell "unreachable" from "not answering yet" — it only finds out
|
|
63
|
+
* once the retransmissions run out.
|
|
64
|
+
*
|
|
65
|
+
* This is the exact inverse of the sockaddr build_udp_dest_addr() produces, and
|
|
66
|
+
* lives next to the family it switches on so the two cannot drift apart.
|
|
67
|
+
*/
|
|
68
|
+
constexpr bool family_can_reach(AddressFamily af, bool dest_is_v6) noexcept {
|
|
69
|
+
switch (af) {
|
|
70
|
+
case AddressFamily::IPv4: return !dest_is_v6;
|
|
71
|
+
case AddressFamily::IPv6: return dest_is_v6; // V6ONLY: no mapped IPv4
|
|
72
|
+
case AddressFamily::DualStack: return true; // IPv4 goes out as ::ffff:a.b.c.d
|
|
73
|
+
}
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Socket Library Initialization
|
|
78
|
+
/**
|
|
79
|
+
* Initialize the socket library
|
|
80
|
+
* @return true if successful, false otherwise
|
|
81
|
+
*/
|
|
82
|
+
bool init_socket_library();
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Cleanup the socket library
|
|
86
|
+
*/
|
|
87
|
+
void cleanup_socket_library();
|
|
88
|
+
|
|
89
|
+
// TCP Socket Functions
|
|
90
|
+
/**
|
|
91
|
+
* Create a TCP client socket and connect to a server using dual stack (IPv6 with IPv4 fallback)
|
|
92
|
+
* @param host The hostname or IP address to connect to
|
|
93
|
+
* @param port The port number to connect to
|
|
94
|
+
* @param timeout_ms Connection timeout in milliseconds (0 for blocking)
|
|
95
|
+
* @return Socket handle, or RATS_INVALID_SOCKET on error
|
|
96
|
+
*/
|
|
97
|
+
socket_t create_tcp_client(const std::string& host, int port, int timeout_ms = 0);
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Begin a non-blocking TCP connect (for use with an IOPoller / reactor).
|
|
101
|
+
*
|
|
102
|
+
* Creates a non-blocking socket and initiates connect() without waiting. The
|
|
103
|
+
* returned socket's connection is typically still in progress: register it for
|
|
104
|
+
* writable, and once it signals writable call tcp_connect_result() to learn the
|
|
105
|
+
* outcome. Prefers IPv6, falls back to IPv4 at resolution time.
|
|
106
|
+
*
|
|
107
|
+
* @param host The hostname or IP address to connect to
|
|
108
|
+
* @param port The port number to connect to
|
|
109
|
+
* @return A non-blocking socket with a connect in progress (or completed), or
|
|
110
|
+
* RATS_INVALID_SOCKET if the socket could not be created/resolved.
|
|
111
|
+
*/
|
|
112
|
+
socket_t tcp_connect_start(const std::string& host, int port);
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Report the result of a non-blocking connect once the socket is writable.
|
|
116
|
+
* @param socket The socket previously returned by tcp_connect_start()
|
|
117
|
+
* @return 0 if the connection succeeded, otherwise the socket error code.
|
|
118
|
+
*/
|
|
119
|
+
int tcp_connect_result(socket_t socket);
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Create a TCP server socket and bind to a port
|
|
123
|
+
* @param port The port number to bind to
|
|
124
|
+
* @param backlog The maximum number of pending connections
|
|
125
|
+
* @param bind_address The interface IP address to bind to (empty for all interfaces)
|
|
126
|
+
* @param af Address family (DualStack by default)
|
|
127
|
+
* @return Socket handle, or RATS_INVALID_SOCKET on error
|
|
128
|
+
*/
|
|
129
|
+
socket_t create_tcp_server(int port, int backlog = 5, const std::string& bind_address = "",
|
|
130
|
+
AddressFamily af = AddressFamily::DualStack);
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Accept a client connection on a server socket
|
|
134
|
+
* @param server_socket The server socket handle
|
|
135
|
+
* @return Client socket handle, or RATS_INVALID_SOCKET on error
|
|
136
|
+
*/
|
|
137
|
+
socket_t accept_client(socket_t server_socket);
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Keep a peer that hung up from killing the process with SIGPIPE.
|
|
141
|
+
*
|
|
142
|
+
* Writing to a socket whose peer has closed raises SIGPIPE, whose default
|
|
143
|
+
* disposition terminates the process. Linux suppresses it per-send with
|
|
144
|
+
* MSG_NOSIGNAL; macOS/BSD have no such flag and suppress it per-socket instead, so
|
|
145
|
+
* every TCP socket we may send on has to carry SO_NOSIGPIPE. Windows has no SIGPIPE
|
|
146
|
+
* at all, and there this is a no-op.
|
|
147
|
+
*
|
|
148
|
+
* The socket helpers here (create_tcp_client / tcp_connect_start / accept_client)
|
|
149
|
+
* already do this. Call it yourself only when you take a socket straight from
|
|
150
|
+
* ::accept() — the option is *not* inherited from the listening socket.
|
|
151
|
+
*/
|
|
152
|
+
void suppress_sigpipe(socket_t socket);
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Get the peer address (IP:port) from a connected socket
|
|
156
|
+
* @param socket The connected socket handle
|
|
157
|
+
* @return Peer address string in format "IP:port", or empty string on error
|
|
158
|
+
*/
|
|
159
|
+
std::string get_peer_address(socket_t socket);
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Get the peer endpoint as a numeric Address, straight from getpeername() with no
|
|
163
|
+
* textual round-trip (IpAddress::from_sockaddr). Returns nullopt on error or an
|
|
164
|
+
* unsupported address family. Note the port is the peer's ephemeral SOURCE port,
|
|
165
|
+
* not its listen port.
|
|
166
|
+
*/
|
|
167
|
+
std::optional<Address> get_peer_endpoint(socket_t socket);
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Send data through a TCP socket
|
|
171
|
+
* @param socket The socket handle
|
|
172
|
+
* @param data The binary data to send
|
|
173
|
+
* @return Number of bytes sent, or -1 on error
|
|
174
|
+
*/
|
|
175
|
+
int send_tcp_data(socket_t socket, const std::vector<uint8_t>& data);
|
|
176
|
+
|
|
177
|
+
/// Most slices send_vectored() will pass to the kernel in one call. Callers size
|
|
178
|
+
/// their slice arrays with this; anything beyond it simply goes out next round.
|
|
179
|
+
///
|
|
180
|
+
/// Sized so the syscall runs out of *bytes* before it runs out of slices. A queued
|
|
181
|
+
/// message costs two slices (its length prefix + its body), so 64 slices would cap a
|
|
182
|
+
/// single send at 32 messages — with small frames that is ~45 KiB, well under what a
|
|
183
|
+
/// socket will take, and a backlog would need more syscalls than a plain contiguous
|
|
184
|
+
/// buffer. 256 slices (4 KiB of ByteView on the stack) keeps the kernel, not this
|
|
185
|
+
/// array, the limiting factor. send_vectored() additionally clamps to IOV_MAX.
|
|
186
|
+
constexpr size_t kMaxSendSlices = 256;
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Scatter/gather send: hand several non-contiguous slices to the kernel in a
|
|
190
|
+
* single syscall (sendmsg on POSIX, WSASend on Windows). A backlog of framed
|
|
191
|
+
* messages then costs one syscall instead of one per message — the reason
|
|
192
|
+
* ChainedSendBuffer::gather() exists.
|
|
193
|
+
*
|
|
194
|
+
* Non-blocking sockets may accept only part of the data, exactly as send() does.
|
|
195
|
+
*
|
|
196
|
+
* @param socket The socket handle
|
|
197
|
+
* @param slices Contiguous runs to send, in order (slices beyond kMaxSendSlices
|
|
198
|
+
* are ignored — the caller sends them on the next round)
|
|
199
|
+
* @param count Number of slices
|
|
200
|
+
* @return Bytes accepted (possibly a partial write), or -1 on error, in which case
|
|
201
|
+
* errno / WSAGetLastError() holds the reason (EWOULDBLOCK when the socket's
|
|
202
|
+
* send buffer is full).
|
|
203
|
+
*/
|
|
204
|
+
std::ptrdiff_t send_vectored(socket_t socket, const ByteView* slices, size_t count);
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Receive data from a TCP socket
|
|
208
|
+
* @param socket The socket handle
|
|
209
|
+
* @param buffer_size Maximum number of bytes to receive
|
|
210
|
+
* @return Received binary data, empty vector on error
|
|
211
|
+
*/
|
|
212
|
+
std::vector<uint8_t> receive_tcp_data(socket_t socket, size_t buffer_size = 1024);
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Send a length-prefixed framed message through a TCP socket
|
|
216
|
+
* @param socket The socket handle
|
|
217
|
+
* @param message The binary message to send
|
|
218
|
+
* @return Total bytes sent (including length prefix), or -1 on error
|
|
219
|
+
*/
|
|
220
|
+
int send_tcp_message(socket_t socket, const std::vector<uint8_t>& message);
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Receive a complete length-prefixed framed message from a TCP socket
|
|
224
|
+
* @param socket The socket handle
|
|
225
|
+
* @return Complete binary message, empty vector on error or connection close
|
|
226
|
+
*/
|
|
227
|
+
std::vector<uint8_t> receive_tcp_message(socket_t socket);
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Send string data through a TCP socket (converts to binary)
|
|
231
|
+
* @param socket The socket handle
|
|
232
|
+
* @param data The string data to send
|
|
233
|
+
* @return Number of bytes sent, or -1 on error
|
|
234
|
+
*/
|
|
235
|
+
int send_tcp_string(socket_t socket, const std::string& data);
|
|
236
|
+
|
|
237
|
+
// UDP Socket Functions
|
|
238
|
+
/**
|
|
239
|
+
* Create a UDP socket and bind to a port
|
|
240
|
+
* @param port The port to bind to (0 for any available port)
|
|
241
|
+
* @param bind_address The interface IP address to bind to (empty for all interfaces)
|
|
242
|
+
* @param af Address family (DualStack by default)
|
|
243
|
+
* @return UDP socket handle, or RATS_INVALID_SOCKET on error
|
|
244
|
+
*/
|
|
245
|
+
socket_t create_udp_socket(int port = 0, const std::string& bind_address = "",
|
|
246
|
+
AddressFamily af = AddressFamily::DualStack);
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Send UDP data to a destination host and port
|
|
250
|
+
* @param socket The UDP socket handle
|
|
251
|
+
* @param data The data to send
|
|
252
|
+
* @param host The destination hostname or IP address
|
|
253
|
+
* @param port The destination port
|
|
254
|
+
* @param af Address family matching the socket (DualStack by default)
|
|
255
|
+
* @return Number of bytes sent, or -1 on error
|
|
256
|
+
*/
|
|
257
|
+
int send_udp_data(socket_t socket, const std::vector<uint8_t>& data, const std::string& host, int port,
|
|
258
|
+
AddressFamily af = AddressFamily::DualStack);
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Send UDP data to a numeric Address. Unlike the host-string overload this does no
|
|
262
|
+
* hostname resolution and no inet_pton — the destination sockaddr is filled straight
|
|
263
|
+
* from the address bytes (an IPv4 address is mapped to ::ffff:x.x.x.x on a
|
|
264
|
+
* DualStack/IPv6 socket). This is the hot path for engines like the DHT that already
|
|
265
|
+
* hold resolved addresses.
|
|
266
|
+
* @return Number of bytes sent, or -1 on error
|
|
267
|
+
*/
|
|
268
|
+
int send_udp_data(socket_t socket, const std::vector<uint8_t>& data, const Address& dest,
|
|
269
|
+
AddressFamily af = AddressFamily::DualStack);
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Ask the kernel for larger socket buffers (SO_RCVBUF / SO_SNDBUF).
|
|
273
|
+
*
|
|
274
|
+
* Matters most for a datagram socket carrying many peers at once: the kernel has
|
|
275
|
+
* nowhere to put a datagram that arrives while the receive buffer is full, so it
|
|
276
|
+
* drops it — and a burst that overruns a small default buffer becomes a
|
|
277
|
+
* retransmission storm rather than a queue. Best effort: the OS may clamp the
|
|
278
|
+
* request, which is fine.
|
|
279
|
+
*
|
|
280
|
+
* @param recv_bytes Requested receive buffer; 0 leaves it alone.
|
|
281
|
+
* @param send_bytes Requested send buffer; 0 leaves it alone.
|
|
282
|
+
* @return true if every requested direction was accepted.
|
|
283
|
+
*/
|
|
284
|
+
bool set_socket_buffer_sizes(socket_t socket, int recv_bytes, int send_bytes);
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Turn Nagle's algorithm off on a TCP socket (TCP_NODELAY).
|
|
288
|
+
*
|
|
289
|
+
* Nagle holds a small write back until the last one is acknowledged, so that
|
|
290
|
+
* several of them can be coalesced into one segment. That is the kernel doing —
|
|
291
|
+
* late, and with no knowledge of what is coming — the batching a sender is
|
|
292
|
+
* better placed to do itself. With the send queue aggregating whole batches of
|
|
293
|
+
* frames into one write (see Connection::send), the coalescing has already
|
|
294
|
+
* happened by the time the kernel sees the bytes, and all Nagle can still add is
|
|
295
|
+
* the delay.
|
|
296
|
+
*
|
|
297
|
+
* Order matters: switching this on *without* that aggregation is a large step
|
|
298
|
+
* backwards, because then Nagle is the only thing merging small frames at all.
|
|
299
|
+
*
|
|
300
|
+
* @return true if the option was accepted.
|
|
301
|
+
*/
|
|
302
|
+
bool set_tcp_nodelay(socket_t socket);
|
|
303
|
+
|
|
304
|
+
/**
|
|
305
|
+
* Send one datagram straight from a raw buffer — no std::vector, no resolution.
|
|
306
|
+
*
|
|
307
|
+
* The allocation-free form of send_udp_data(), for engines that emit a packet per
|
|
308
|
+
* call from a reusable scratch buffer (the reliable-UDP transport builds every
|
|
309
|
+
* header + payload into one stack buffer and hands it here).
|
|
310
|
+
*
|
|
311
|
+
* @return Bytes sent, 0 if the send would block (a full socket send buffer — the
|
|
312
|
+
* datagram is simply dropped, exactly as a congested link would), or -1 on
|
|
313
|
+
* a real error.
|
|
314
|
+
*/
|
|
315
|
+
std::ptrdiff_t send_udp_to(socket_t socket, const void* data, size_t len,
|
|
316
|
+
const Address& dest, AddressFamily af = AddressFamily::DualStack);
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Receive one datagram into a caller-owned buffer, without blocking.
|
|
320
|
+
*
|
|
321
|
+
* The counterpart of send_udp_to() for a socket driven by an IOPoller: it never
|
|
322
|
+
* waits, so the caller loops until it reports "nothing left".
|
|
323
|
+
*
|
|
324
|
+
* @param from Filled with the sender's endpoint on success.
|
|
325
|
+
* @return Bytes received (0 is a legal empty datagram), -1 when nothing is pending
|
|
326
|
+
* (would-block) and -2 on a socket error.
|
|
327
|
+
*/
|
|
328
|
+
constexpr std::ptrdiff_t kUdpRecvWouldBlock = -1;
|
|
329
|
+
constexpr std::ptrdiff_t kUdpRecvError = -2;
|
|
330
|
+
std::ptrdiff_t recv_udp_from(socket_t socket, void* buffer, size_t len, Address& from);
|
|
331
|
+
|
|
332
|
+
// ── Batched datagram I/O ────────────────────────────────────────────────────
|
|
333
|
+
//
|
|
334
|
+
// A reliability layer built on datagrams moves one packet per call, so a bulk
|
|
335
|
+
// transfer at a 1200-byte payload costs tens of thousands of syscalls per
|
|
336
|
+
// megabyte — measurably the single largest cost on that path, well above the
|
|
337
|
+
// framing, the congestion control and the encryption put together. Linux (and
|
|
338
|
+
// the BSDs that copied it) can carry a whole array of datagrams per call;
|
|
339
|
+
// everywhere else these fall back to a loop over the single-datagram forms, so
|
|
340
|
+
// callers need no #ifdef and no second code path.
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* Datagrams one batched call moves. 32 is enough to make the syscall a rounding
|
|
344
|
+
* error against the work of building the packets, while keeping the per-call
|
|
345
|
+
* scratch (one message header, one iovec and one address per slot) small enough
|
|
346
|
+
* to live on the stack.
|
|
347
|
+
*/
|
|
348
|
+
constexpr size_t kUdpBatchMax = 32;
|
|
349
|
+
|
|
350
|
+
// recvmmsg/sendmmsg — one syscall for a whole array of datagrams. Linux has had
|
|
351
|
+
// both since 2.6.33 (bionic exposes them from API 21); everything else takes the
|
|
352
|
+
// loop fallback below. FreeBSD has them too, but only as of 11, and the version
|
|
353
|
+
// guard is not worth the cost of being wrong there.
|
|
354
|
+
#if defined(__linux__) && (!defined(__ANDROID__) || __ANDROID_API__ >= 21)
|
|
355
|
+
#define RATS_HAVE_MMSG 1
|
|
356
|
+
#endif
|
|
357
|
+
|
|
358
|
+
/**
|
|
359
|
+
* Whether a batched call really is one syscall here, or a loop wearing the same
|
|
360
|
+
* interface.
|
|
361
|
+
*
|
|
362
|
+
* Both forms are correct everywhere, so this is not needed to *use* them. It
|
|
363
|
+
* matters to a caller deciding whether to stage datagrams for later: staging pays
|
|
364
|
+
* a copy per datagram to save syscalls, and where the loop fallback is in force
|
|
365
|
+
* there are no syscalls to save — so the copy would be pure loss and the caller
|
|
366
|
+
* should hand each datagram over as it is produced instead.
|
|
367
|
+
*/
|
|
368
|
+
#ifdef RATS_HAVE_MMSG
|
|
369
|
+
constexpr bool kUdpBatchIsOneSyscall = true;
|
|
370
|
+
#else
|
|
371
|
+
constexpr bool kUdpBatchIsOneSyscall = false;
|
|
372
|
+
#endif
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* One datagram in a batch. The payload buffer belongs to the caller — a receive
|
|
376
|
+
* loop reuses the same storage every round and a send path stages into it — so a
|
|
377
|
+
* batch of any size costs no allocation.
|
|
378
|
+
*/
|
|
379
|
+
struct UdpBatchSlot {
|
|
380
|
+
uint8_t* data = nullptr; ///< caller-owned payload buffer
|
|
381
|
+
size_t len = 0; ///< receive in: capacity, out: bytes filled; send: bytes to send
|
|
382
|
+
Address endpoint; ///< receive out: the sender; send in: the destination
|
|
383
|
+
};
|
|
384
|
+
|
|
385
|
+
/**
|
|
386
|
+
* Receive up to `count` datagrams, in one syscall where the platform has one.
|
|
387
|
+
*
|
|
388
|
+
* Each slot must point at a buffer with `len` bytes of room; on return `len` is
|
|
389
|
+
* what actually arrived and `endpoint` is who sent it. A datagram larger than the
|
|
390
|
+
* slot is truncated, exactly as recvfrom() would truncate it.
|
|
391
|
+
*
|
|
392
|
+
* @return Datagrams filled (> 0), kUdpRecvWouldBlock when nothing is pending, or
|
|
393
|
+
* kUdpRecvError. A result shorter than `count` does NOT prove the queue is
|
|
394
|
+
* empty — a per-datagram error truncates the batch too — so a caller that
|
|
395
|
+
* must drain (an edge-triggered poller) loops until kUdpRecvWouldBlock.
|
|
396
|
+
*/
|
|
397
|
+
std::ptrdiff_t recv_udp_batch(socket_t socket, UdpBatchSlot* slots, size_t count);
|
|
398
|
+
|
|
399
|
+
/**
|
|
400
|
+
* Send `count` datagrams, in one syscall where the platform has one.
|
|
401
|
+
*
|
|
402
|
+
* @return How many the socket accepted. The caller must treat the whole batch as
|
|
403
|
+
* spent regardless: a datagram the socket refused (a full send buffer) is
|
|
404
|
+
* indistinguishable from one the path dropped, and retransmission covers
|
|
405
|
+
* both — so the count is for diagnostics, not for a retry.
|
|
406
|
+
*/
|
|
407
|
+
size_t send_udp_batch(socket_t socket, const UdpBatchSlot* slots, size_t count,
|
|
408
|
+
AddressFamily af = AddressFamily::DualStack);
|
|
409
|
+
|
|
410
|
+
/**
|
|
411
|
+
* Receive UDP data with optional timeout
|
|
412
|
+
* @param socket The UDP socket handle
|
|
413
|
+
* @param buffer_size Maximum number of bytes to receive
|
|
414
|
+
* @param sender_peer Output parameter for the sender's peer info
|
|
415
|
+
* @param timeout_ms Timeout in milliseconds (-1 for blocking, 0 for non-blocking, >0 for timeout)
|
|
416
|
+
* @param interrupt_fd Optional second socket to watch; when it becomes readable the
|
|
417
|
+
* call returns immediately with an empty vector (used to wake a
|
|
418
|
+
* blocking receive on shutdown). RATS_INVALID_SOCKET disables it.
|
|
419
|
+
* @param error_out Optional output flag distinguishing the reasons an empty vector can
|
|
420
|
+
* mean: set to true only when select()/recvfrom() failed hard (a dead
|
|
421
|
+
* socket, e.g. EBADF), false for a timeout, an interrupt or an empty
|
|
422
|
+
* datagram. A polling loop needs this to tell "nothing arrived" from
|
|
423
|
+
* "this socket will never deliver again" instead of spinning forever.
|
|
424
|
+
* Errors that concern a signal or one destination rather than the
|
|
425
|
+
* socket (EINTR, ECONNREFUSED / WSAECONNRESET, WSAENETRESET) count as
|
|
426
|
+
* "nothing arrived" — same classification as recv_udp_from().
|
|
427
|
+
* @return Received data, empty vector on timeout, error or interrupt
|
|
428
|
+
*/
|
|
429
|
+
std::vector<uint8_t> receive_udp_data(socket_t socket, size_t buffer_size, Address& sender_peer,
|
|
430
|
+
int timeout_ms = -1,
|
|
431
|
+
socket_t interrupt_fd = RATS_INVALID_SOCKET,
|
|
432
|
+
bool* error_out = nullptr);
|
|
433
|
+
|
|
434
|
+
// Common Socket Functions
|
|
435
|
+
/**
|
|
436
|
+
* Close a socket
|
|
437
|
+
* @param socket The socket handle to close
|
|
438
|
+
* @param force If true, send RST instead of FIN (avoids TIME_WAIT)
|
|
439
|
+
*/
|
|
440
|
+
void close_socket(socket_t socket, bool force = false);
|
|
441
|
+
|
|
442
|
+
/**
|
|
443
|
+
* Check if a socket is valid
|
|
444
|
+
* @param socket The socket handle to check
|
|
445
|
+
* @return true if valid, false otherwise
|
|
446
|
+
*/
|
|
447
|
+
bool is_valid_socket(socket_t socket);
|
|
448
|
+
|
|
449
|
+
/**
|
|
450
|
+
* Set socket to non-blocking mode
|
|
451
|
+
* @param socket The socket handle
|
|
452
|
+
* @return true if successful, false otherwise
|
|
453
|
+
*/
|
|
454
|
+
bool set_socket_nonblocking(socket_t socket);
|
|
455
|
+
|
|
456
|
+
/**
|
|
457
|
+
* Set socket to blocking mode
|
|
458
|
+
* @param socket The socket handle
|
|
459
|
+
* @return true if successful, false otherwise
|
|
460
|
+
*/
|
|
461
|
+
bool set_socket_blocking(socket_t socket);
|
|
462
|
+
|
|
463
|
+
/**
|
|
464
|
+
* Connect to a socket address with timeout
|
|
465
|
+
* @param socket The socket handle (should be non-blocking)
|
|
466
|
+
* @param addr The socket address structure
|
|
467
|
+
* @param addr_len Length of the address structure
|
|
468
|
+
* @param timeout_ms Connection timeout in milliseconds
|
|
469
|
+
* @return true if connected successfully, false on timeout or error
|
|
470
|
+
*/
|
|
471
|
+
bool connect_with_timeout(socket_t socket, struct sockaddr* addr, socklen_t addr_len, int timeout_ms);
|
|
472
|
+
|
|
473
|
+
/**
|
|
474
|
+
* Get the port that a socket is bound to
|
|
475
|
+
* @param socket The socket handle
|
|
476
|
+
* @return The bound port, or 0 on error
|
|
477
|
+
*/
|
|
478
|
+
int get_bound_port(socket_t socket);
|
|
479
|
+
|
|
480
|
+
/**
|
|
481
|
+
* Whether the last socket call in this thread failed because that particular
|
|
482
|
+
* port cannot be had — it is taken (EADDRINUSE / WSAEADDRINUSE), or on Windows
|
|
483
|
+
* it falls in a reserved range (WSAEACCES).
|
|
484
|
+
*
|
|
485
|
+
* Meant for the one caller that has to tell those apart from every other bind
|
|
486
|
+
* failure: they are the only ones worth answering by moving to another port,
|
|
487
|
+
* since the rest — a privileged port, a bind address not on this host, IPv6
|
|
488
|
+
* switched off — fail identically on all 65535 of them. The socket factories
|
|
489
|
+
* above preserve the failing errno across their own cleanup, so this still
|
|
490
|
+
* reports the bind error and not the close() that followed it.
|
|
491
|
+
*
|
|
492
|
+
* @return true if another port would plausibly work
|
|
493
|
+
*/
|
|
494
|
+
bool last_error_was_port_unavailable();
|
|
495
|
+
|
|
496
|
+
} // namespace librats
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file timer_queue.h
|
|
5
|
+
* @brief Deadline-ordered timer set driven by the reactor loop.
|
|
6
|
+
*
|
|
7
|
+
* Backs handshake timeouts, reconnection backoff, keep-alives, etc. The reactor
|
|
8
|
+
* asks next_timeout_ms() to size its poll wait, then calls run_due() once it
|
|
9
|
+
* wakes. Cancellation is lazy (tombstone set) so cancel() is O(1) and never has
|
|
10
|
+
* to find the entry in the heap.
|
|
11
|
+
*
|
|
12
|
+
* Complexity: schedule O(log n), run_due amortised O(log n) per fired timer.
|
|
13
|
+
* A hashed timing wheel can replace this behind the same interface if O(1)
|
|
14
|
+
* scheduling ever becomes necessary; for thousands of timers a heap is ample.
|
|
15
|
+
*
|
|
16
|
+
* Single-threaded: only ever touched by the owning reactor thread.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
#include "librats/core/types.h"
|
|
20
|
+
|
|
21
|
+
#include <algorithm>
|
|
22
|
+
#include <chrono>
|
|
23
|
+
#include <functional>
|
|
24
|
+
#include <unordered_set>
|
|
25
|
+
#include <vector>
|
|
26
|
+
|
|
27
|
+
namespace librats {
|
|
28
|
+
|
|
29
|
+
class TimerQueue {
|
|
30
|
+
public:
|
|
31
|
+
using Clock = std::chrono::steady_clock;
|
|
32
|
+
using Callback = std::function<void()>;
|
|
33
|
+
|
|
34
|
+
/// Schedule `cb` to fire after `delay`. Returns a handle for cancel().
|
|
35
|
+
TimerId schedule(Clock::duration delay, Callback cb) {
|
|
36
|
+
const TimerId id = ++last_id_;
|
|
37
|
+
heap_.push_back(Entry{Clock::now() + delay, id, std::move(cb)});
|
|
38
|
+
std::push_heap(heap_.begin(), heap_.end(), later_first_);
|
|
39
|
+
return id;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/// Cancel a pending timer. Safe even if it has already fired or never existed.
|
|
43
|
+
void cancel(TimerId id) {
|
|
44
|
+
if (id != kInvalidTimerId) cancelled_.insert(id);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/// Milliseconds until the next timer is due, clamped to [0, max_ms].
|
|
48
|
+
int next_timeout_ms(int max_ms) const {
|
|
49
|
+
if (heap_.empty()) return max_ms;
|
|
50
|
+
const auto now = Clock::now();
|
|
51
|
+
const auto due = heap_.front().when;
|
|
52
|
+
if (due <= now) return 0;
|
|
53
|
+
// Round UP: truncating a sub-millisecond remainder to 0 would make the
|
|
54
|
+
// reactor poll with a 0 ms timeout and busy-spin until the deadline
|
|
55
|
+
// instead of sleeping through it. ceil guarantees the wait covers the
|
|
56
|
+
// timer, so it fires on wake rather than after a CPU-burning spin.
|
|
57
|
+
const auto ms = std::chrono::ceil<std::chrono::milliseconds>(due - now).count();
|
|
58
|
+
return static_cast<int>(std::min<long long>(ms, max_ms));
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/// Fire every timer whose deadline has passed (skipping cancelled ones).
|
|
62
|
+
void run_due() {
|
|
63
|
+
const auto now = Clock::now();
|
|
64
|
+
while (!heap_.empty() && heap_.front().when <= now) {
|
|
65
|
+
std::pop_heap(heap_.begin(), heap_.end(), later_first_);
|
|
66
|
+
Entry e = std::move(heap_.back());
|
|
67
|
+
heap_.pop_back();
|
|
68
|
+
|
|
69
|
+
auto it = cancelled_.find(e.id);
|
|
70
|
+
if (it != cancelled_.end()) {
|
|
71
|
+
cancelled_.erase(it);
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
e.cb();
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/// Drop every pending timer, tombstones included. For an owner being torn
|
|
79
|
+
/// down that may be started again: nothing scheduled by one run should still
|
|
80
|
+
/// be due in the next. Ids keep counting up, so a handle held across the gap
|
|
81
|
+
/// can never come to name a timer of the new run.
|
|
82
|
+
void clear() {
|
|
83
|
+
heap_.clear();
|
|
84
|
+
cancelled_.clear();
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
bool empty() const { return heap_.empty(); }
|
|
88
|
+
|
|
89
|
+
private:
|
|
90
|
+
struct Entry {
|
|
91
|
+
Clock::time_point when;
|
|
92
|
+
TimerId id;
|
|
93
|
+
Callback cb;
|
|
94
|
+
};
|
|
95
|
+
// Min-heap on `when`: std::*_heap are max-heaps, so invert the comparison.
|
|
96
|
+
struct LaterFirst {
|
|
97
|
+
bool operator()(const Entry& a, const Entry& b) const { return a.when > b.when; }
|
|
98
|
+
} later_first_;
|
|
99
|
+
|
|
100
|
+
std::vector<Entry> heap_;
|
|
101
|
+
std::unordered_set<TimerId> cancelled_;
|
|
102
|
+
TimerId last_id_ = kInvalidTimerId;
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
} // namespace librats
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
#include "librats/core/types.h"
|
|
2
|
+
|
|
3
|
+
namespace librats {
|
|
4
|
+
|
|
5
|
+
const char* to_string(ConnState s) noexcept {
|
|
6
|
+
switch (s) {
|
|
7
|
+
case ConnState::Connecting: return "Connecting";
|
|
8
|
+
case ConnState::Handshaking: return "Handshaking";
|
|
9
|
+
case ConnState::Established: return "Established";
|
|
10
|
+
case ConnState::Closing: return "Closing";
|
|
11
|
+
case ConnState::Closed: return "Closed";
|
|
12
|
+
}
|
|
13
|
+
return "?";
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const char* to_string(CloseReason r) noexcept {
|
|
17
|
+
switch (r) {
|
|
18
|
+
case CloseReason::LocalClose: return "LocalClose";
|
|
19
|
+
case CloseReason::PeerClosed: return "PeerClosed";
|
|
20
|
+
case CloseReason::PeerReset: return "PeerReset";
|
|
21
|
+
case CloseReason::ConnectFailed: return "ConnectFailed";
|
|
22
|
+
case CloseReason::HandshakeFailed: return "HandshakeFailed";
|
|
23
|
+
case CloseReason::ProtocolError: return "ProtocolError";
|
|
24
|
+
case CloseReason::SlowConsumer: return "SlowConsumer";
|
|
25
|
+
case CloseReason::ReactorShutdown: return "ReactorShutdown";
|
|
26
|
+
case CloseReason::DuplicateConn: return "DuplicateConn";
|
|
27
|
+
case CloseReason::PeerLimit: return "PeerLimit";
|
|
28
|
+
case CloseReason::IdleTimeout: return "IdleTimeout";
|
|
29
|
+
case CloseReason::DialSuperseded: return "DialSuperseded";
|
|
30
|
+
}
|
|
31
|
+
return "?";
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const char* to_string(TransportKind t) noexcept {
|
|
35
|
+
switch (t) {
|
|
36
|
+
case TransportKind::Tcp: return "tcp";
|
|
37
|
+
case TransportKind::Udp: return "udp";
|
|
38
|
+
case TransportKind::Relay: return "relay";
|
|
39
|
+
}
|
|
40
|
+
return "?";
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
} // namespace librats
|