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,183 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file chained_send_buffer.h
|
|
5
|
+
* @brief Outbound byte queue: a chain of heap chunks drained with gather I/O.
|
|
6
|
+
*
|
|
7
|
+
* A socket accepts what it accepts; whatever is left over has to wait for the next
|
|
8
|
+
* writable event. Rather than keeping that backlog in one contiguous buffer (where
|
|
9
|
+
* every partial write costs an O(n) erase of the sent prefix, and every message
|
|
10
|
+
* costs a copy into it), the queue is a chain of chunks:
|
|
11
|
+
*
|
|
12
|
+
* chunks_: [ sent | pending ] → [ pending ] → [ pending ]
|
|
13
|
+
* ^ head_.sent
|
|
14
|
+
*
|
|
15
|
+
* - pop_front() after a send just advances a cursor and drops whole chunks: O(1)
|
|
16
|
+
* amortised, no memmove.
|
|
17
|
+
* - append(Bytes) takes ownership of a buffer someone else already built, so a
|
|
18
|
+
* message the caller allocated (an encrypted frame, a piece read from disk) is
|
|
19
|
+
* never copied.
|
|
20
|
+
* - gather() exposes the chain as a slice list for writev()/WSASend(), so a
|
|
21
|
+
* backlog of N queued messages leaves in ONE syscall instead of N.
|
|
22
|
+
*
|
|
23
|
+
* Three things keep small messages cheap, since a chunk-per-message would otherwise
|
|
24
|
+
* mean a malloc per 5-byte keep-alive:
|
|
25
|
+
* - copy-appends are packed into the spare capacity of the tail chunk
|
|
26
|
+
* (libtorrent's allocate_appendix), so a burst of small messages costs one
|
|
27
|
+
* allocation, not one per message;
|
|
28
|
+
* - the last fully-sent small chunk is kept and re-used, so a steady drip of
|
|
29
|
+
* small messages settles into allocating nothing at all;
|
|
30
|
+
* - the chain itself is a std::vector + a head index, not a std::deque. A deque
|
|
31
|
+
* allocates a fresh block every `block_size/sizeof(Chunk)` push_backs (libstdc++:
|
|
32
|
+
* one per 16 chunks; MSVC: one per *chunk*, since its block holds a single
|
|
33
|
+
* element for any type over 8 bytes) — so the recycled chunk above would hand
|
|
34
|
+
* back the payload buffer while the queue kept mallocing the slot to put it in.
|
|
35
|
+
* A vector amortises the slots away entirely, and re-uses its storage across
|
|
36
|
+
* drains.
|
|
37
|
+
*
|
|
38
|
+
* Memory is accounted two ways: size() is what still has to go out, while
|
|
39
|
+
* allocated() is what the chain actually holds — larger, because a partially sent
|
|
40
|
+
* chunk keeps its whole allocation and a packed chunk keeps its spare room. A
|
|
41
|
+
* send high-water mark should watch allocated(): that is the memory a peer who
|
|
42
|
+
* stops reading can make us carry.
|
|
43
|
+
*
|
|
44
|
+
* Not thread-safe: owned and touched by exactly one reactor thread.
|
|
45
|
+
*
|
|
46
|
+
* Usage:
|
|
47
|
+
* buf.append(std::move(frame)); // queue, no copy
|
|
48
|
+
* ByteView slices[kMaxSendSlices];
|
|
49
|
+
* const size_t n = buf.gather(slices, kMaxSendSlices);
|
|
50
|
+
* const auto sent = send_vectored(sock, slices, n); // one syscall
|
|
51
|
+
* if (sent > 0) buf.pop_front(size_t(sent)); // O(1)
|
|
52
|
+
*/
|
|
53
|
+
|
|
54
|
+
#include "librats/util/rats_export.h"
|
|
55
|
+
#include "librats/core/bytes.h"
|
|
56
|
+
|
|
57
|
+
#include <cstddef>
|
|
58
|
+
#include <cstdint>
|
|
59
|
+
#include <type_traits>
|
|
60
|
+
#include <utility>
|
|
61
|
+
#include <vector>
|
|
62
|
+
|
|
63
|
+
namespace librats {
|
|
64
|
+
|
|
65
|
+
class RATS_API ChainedSendBuffer {
|
|
66
|
+
public:
|
|
67
|
+
/// Capacity of a chunk opened for a small copy-append. Sized so a run of
|
|
68
|
+
/// protocol chatter (keep-alives, HAVEs, REQUESTs, ACKs) packs into one.
|
|
69
|
+
static constexpr size_t kScratchCapacity = 1024;
|
|
70
|
+
|
|
71
|
+
/// Chunks up to this size are kept for re-use when they drain; larger ones
|
|
72
|
+
/// (payload buffers) are released, so the queue never squats on real memory.
|
|
73
|
+
static constexpr size_t kMaxRecycledCapacity = 4 * 1024;
|
|
74
|
+
|
|
75
|
+
ChainedSendBuffer() = default;
|
|
76
|
+
|
|
77
|
+
/// Moving leaves the source empty. A defaulted move would carry pending_ and
|
|
78
|
+
/// allocated_ over to a source whose chunks_ had been emptied, leaving it claiming
|
|
79
|
+
/// bytes it no longer holds (empty() false, front() empty — a flush() that never
|
|
80
|
+
/// finishes).
|
|
81
|
+
ChainedSendBuffer(ChainedSendBuffer&& other) noexcept { *this = std::move(other); }
|
|
82
|
+
ChainedSendBuffer& operator=(ChainedSendBuffer&& other) noexcept;
|
|
83
|
+
ChainedSendBuffer(const ChainedSendBuffer&) = delete;
|
|
84
|
+
ChainedSendBuffer& operator=(const ChainedSendBuffer&) = delete;
|
|
85
|
+
|
|
86
|
+
// ── Queueing ────────────────────────────────────────────────────────────
|
|
87
|
+
|
|
88
|
+
/// Queue `data`, taking ownership — the bytes are never copied. Prefer this for
|
|
89
|
+
/// anything the caller already had to allocate (a framed message, disk block…).
|
|
90
|
+
void append(Bytes data);
|
|
91
|
+
|
|
92
|
+
/// Queue a copy of `bytes`. Small copies land in the tail chunk's spare capacity
|
|
93
|
+
/// when they fit, so headers and short control messages don't each cost a malloc.
|
|
94
|
+
void append(ByteView bytes);
|
|
95
|
+
|
|
96
|
+
// ── Draining ────────────────────────────────────────────────────────────
|
|
97
|
+
|
|
98
|
+
/// Bytes gather() will describe in one go unless told otherwise. A socket accepts
|
|
99
|
+
/// what fits in its send buffer — a few hundred KiB at most — and every slice past
|
|
100
|
+
/// that is an iovec entry the kernel copies in and then ignores. Under a backlog
|
|
101
|
+
/// (the case gather() exists for) the flush loop re-gathers after every partial
|
|
102
|
+
/// write, so that waste is paid on every syscall, not once. libtorrent bounds its
|
|
103
|
+
/// build_iovec() by a byte quota for the same reason.
|
|
104
|
+
static constexpr size_t kMaxGatherBytes = 1024 * 1024;
|
|
105
|
+
|
|
106
|
+
/// Fill `out` with up to `max_slices` contiguous runs covering the front of the
|
|
107
|
+
/// queue, in order, stopping once they cover `max_bytes` (the slice that crosses
|
|
108
|
+
/// the limit is still included whole, so a single chunk larger than the limit is
|
|
109
|
+
/// described rather than dropped). Returns the number of slices written. The views
|
|
110
|
+
/// stay valid until the next pop_front()/clear() — append() never invalidates them,
|
|
111
|
+
/// because a slice points at a chunk's *heap buffer*, which a vector growth moves
|
|
112
|
+
/// the owning Chunk around but never reallocates.
|
|
113
|
+
size_t gather(ByteView* out, size_t max_slices, size_t max_bytes = kMaxGatherBytes) const;
|
|
114
|
+
|
|
115
|
+
/// The first contiguous run — the single-slice form of gather(), for a plain
|
|
116
|
+
/// send(). Empty when the queue is empty.
|
|
117
|
+
ByteView front() const noexcept;
|
|
118
|
+
|
|
119
|
+
/// Drop `bytes` from the front after a successful send. Must not exceed size().
|
|
120
|
+
void pop_front(size_t bytes);
|
|
121
|
+
|
|
122
|
+
// ── State ───────────────────────────────────────────────────────────────
|
|
123
|
+
|
|
124
|
+
bool empty() const noexcept { return pending_ == 0; }
|
|
125
|
+
/// Bytes still waiting to go out — what a send high-water mark should watch.
|
|
126
|
+
size_t size() const noexcept { return pending_; }
|
|
127
|
+
/// Heap actually held by the chain: pending bytes, the already-sent prefix of a
|
|
128
|
+
/// partially sent chunk, spare capacity, and the recycled chunk.
|
|
129
|
+
size_t allocated() const noexcept { return allocated_ + recycled_.capacity(); }
|
|
130
|
+
size_t chunk_count() const noexcept { return chunks_.size() - head_; }
|
|
131
|
+
|
|
132
|
+
/// Drop everything and release all chunks.
|
|
133
|
+
void clear() noexcept;
|
|
134
|
+
|
|
135
|
+
private:
|
|
136
|
+
struct Chunk {
|
|
137
|
+
Bytes data;
|
|
138
|
+
size_t sent = 0; ///< bytes of `data` already handed to the socket
|
|
139
|
+
|
|
140
|
+
size_t remaining() const noexcept { return data.size() - sent; }
|
|
141
|
+
const uint8_t* head() const noexcept { return data.data() + sent; }
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
// A gather() slice points into a chunk's heap buffer, and append() may grow
|
|
145
|
+
// chunks_ while those slices are outstanding. That is only safe because a vector
|
|
146
|
+
// growth *moves* each Chunk — carrying the heap buffer's address across untouched.
|
|
147
|
+
// Were the move throwing, vector would fall back to copying: every chunk would get
|
|
148
|
+
// a fresh buffer, the originals would be freed, and every outstanding slice would
|
|
149
|
+
// dangle. The guarantee is load-bearing, so assert it rather than assume it.
|
|
150
|
+
static_assert(std::is_nothrow_move_constructible<Chunk>::value,
|
|
151
|
+
"Chunk must move on vector growth, or gather()'s slices would dangle");
|
|
152
|
+
|
|
153
|
+
/// The tail chunk if `bytes` fit in its spare capacity (so appending to it
|
|
154
|
+
/// cannot reallocate, and therefore cannot invalidate outstanding slices).
|
|
155
|
+
Bytes* coalescable_tail(size_t bytes) noexcept;
|
|
156
|
+
|
|
157
|
+
/// A chunk with at least `bytes` of capacity: the recycled one if it fits,
|
|
158
|
+
/// otherwise a fresh allocation.
|
|
159
|
+
Bytes take_chunk(size_t bytes);
|
|
160
|
+
|
|
161
|
+
/// Offer a drained chunk back for re-use.
|
|
162
|
+
void recycle(Bytes&& chunk) noexcept;
|
|
163
|
+
|
|
164
|
+
/// Drop the drained prefix of `chunks_` so the vector cannot creep forever under a
|
|
165
|
+
/// backlog that never fully empties. Amortised O(1): only ever runs when at least
|
|
166
|
+
/// half the vector is dead.
|
|
167
|
+
void reclaim_drained_slots();
|
|
168
|
+
|
|
169
|
+
/// Slots kept across a full drain. Above this the vector hands the memory back —
|
|
170
|
+
/// an 8 MiB backlog of 1 KiB chunks would otherwise leave 8192 slots resident.
|
|
171
|
+
static constexpr size_t kMaxRetainedSlots = 64;
|
|
172
|
+
|
|
173
|
+
/// Live chunks are `chunks_[head_ .. end)`. A vector + head index rather than a
|
|
174
|
+
/// deque: see the header comment — a deque mallocs a block per N chunks (N == 1 on
|
|
175
|
+
/// MSVC), which is exactly the allocation `recycled_` exists to avoid.
|
|
176
|
+
std::vector<Chunk> chunks_;
|
|
177
|
+
size_t head_ = 0; ///< index of the first live chunk
|
|
178
|
+
size_t pending_ = 0; ///< sum of remaining() over the live chunks
|
|
179
|
+
size_t allocated_ = 0; ///< sum of data.capacity() over the live chunks
|
|
180
|
+
Bytes recycled_; ///< one drained small chunk, kept for re-use
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
} // namespace librats
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
#include "librats/core/endpoint_parse.h"
|
|
2
|
+
|
|
3
|
+
namespace librats {
|
|
4
|
+
|
|
5
|
+
std::optional<uint16_t> parse_port(std::string_view text) {
|
|
6
|
+
if (text.empty()) return std::nullopt;
|
|
7
|
+
unsigned long port = 0;
|
|
8
|
+
for (char c : text) {
|
|
9
|
+
if (c < '0' || c > '9') return std::nullopt;
|
|
10
|
+
port = port * 10 + static_cast<unsigned>(c - '0');
|
|
11
|
+
if (port > 65535) return std::nullopt;
|
|
12
|
+
}
|
|
13
|
+
if (port == 0) return std::nullopt;
|
|
14
|
+
return static_cast<uint16_t>(port);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
std::optional<std::pair<std::string_view, uint16_t>> split_host_port(std::string_view text) {
|
|
18
|
+
if (!text.empty() && text.front() == '[') {
|
|
19
|
+
// Bracketed IPv6: [ip]:port
|
|
20
|
+
const auto close = text.find(']');
|
|
21
|
+
if (close == std::string_view::npos || close + 1 >= text.size() || text[close + 1] != ':')
|
|
22
|
+
return std::nullopt;
|
|
23
|
+
const auto host = text.substr(1, close - 1);
|
|
24
|
+
if (host.empty()) return std::nullopt;
|
|
25
|
+
const auto port = parse_port(text.substr(close + 2));
|
|
26
|
+
if (!port) return std::nullopt;
|
|
27
|
+
return std::make_pair(host, *port);
|
|
28
|
+
}
|
|
29
|
+
const auto colon = text.rfind(':');
|
|
30
|
+
if (colon == std::string_view::npos || colon == 0 || colon + 1 == text.size())
|
|
31
|
+
return std::nullopt;
|
|
32
|
+
const auto host = text.substr(0, colon);
|
|
33
|
+
// A bare IPv6 literal carries its own colons; without brackets the port is
|
|
34
|
+
// ambiguous, so reject it rather than guess.
|
|
35
|
+
if (host.find(':') != std::string_view::npos) return std::nullopt;
|
|
36
|
+
const auto port = parse_port(text.substr(colon + 1));
|
|
37
|
+
if (!port) return std::nullopt;
|
|
38
|
+
return std::make_pair(host, *port);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
} // namespace librats
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file endpoint_parse.h
|
|
5
|
+
* @brief Shared textual "host:port" parsing for Address and HostEndpoint.
|
|
6
|
+
*
|
|
7
|
+
* Both the numeric Address and the unresolved HostEndpoint accept exactly the same
|
|
8
|
+
* surface syntax — "host:port" or bracketed "[ipv6]:port" — and reject the same
|
|
9
|
+
* malformed inputs (missing/invalid port, empty host, a bare unbracketed IPv6 whose
|
|
10
|
+
* own colons make the port ambiguous). The only difference is what each does with
|
|
11
|
+
* the host afterwards (parse it as a numeric literal vs. keep it verbatim), so the
|
|
12
|
+
* structural split lives here once instead of being copy-pasted into each parse().
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
#include <cstdint>
|
|
16
|
+
#include <optional>
|
|
17
|
+
#include <string_view>
|
|
18
|
+
#include <utility>
|
|
19
|
+
|
|
20
|
+
namespace librats {
|
|
21
|
+
|
|
22
|
+
/// Parse a 1..65535 decimal port. nullopt on empty/non-digit/out-of-range/zero.
|
|
23
|
+
std::optional<uint16_t> parse_port(std::string_view text);
|
|
24
|
+
|
|
25
|
+
/// Split "host:port" or "[ipv6]:port" into (host, port). Returns nullopt for a
|
|
26
|
+
/// missing/invalid port, an empty host, or a bare (unbracketed) IPv6 literal whose
|
|
27
|
+
/// colons make the port ambiguous. The returned host view points into `text` and is
|
|
28
|
+
/// valid for its lifetime (brackets, if any, are stripped).
|
|
29
|
+
std::optional<std::pair<std::string_view, uint16_t>> split_host_port(std::string_view text);
|
|
30
|
+
|
|
31
|
+
} // namespace librats
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file event_bus.h
|
|
5
|
+
* @brief A tiny typed publish/subscribe hub for decoupled module notifications.
|
|
6
|
+
*
|
|
7
|
+
* The "something happened" half of inter-module communication: a publisher emits
|
|
8
|
+
* an event *value* and every subscriber registered for that event type is invoked.
|
|
9
|
+
* The publisher neither knows nor names its subscribers — which is exactly what
|
|
10
|
+
* keeps modules from acquiring direct references to one another (the road back to
|
|
11
|
+
* a god-class). For the "do X / give me Y" half — a targeted call with a return
|
|
12
|
+
* value — use ServiceRegistry instead.
|
|
13
|
+
*
|
|
14
|
+
* An event type is any value type; subscription and dispatch are keyed by it:
|
|
15
|
+
*
|
|
16
|
+
* struct NetworkChanged { std::vector<std::string> addresses; };
|
|
17
|
+
* bus.on<NetworkChanged>([](const NetworkChanged& e){ ... }); // subscribe
|
|
18
|
+
* bus.emit(NetworkChanged{addrs}); // publish → all handlers
|
|
19
|
+
*
|
|
20
|
+
* Threading: handlers run synchronously on the thread that calls emit(). The bus
|
|
21
|
+
* itself is thread-safe (on/emit may be called concurrently), but a handler must
|
|
22
|
+
* not block that thread for long — if emit() is driven from a latency-sensitive
|
|
23
|
+
* thread, offload slow work. emit() snapshots the handler list under the lock and
|
|
24
|
+
* invokes it unlocked, so a handler may itself emit() or on() without deadlocking.
|
|
25
|
+
*
|
|
26
|
+
* Convention: subscribe during a subsystem's attach() (single-threaded, before any
|
|
27
|
+
* reactor runs), the same "configure before start" rule the rest of the node uses.
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
#include <functional>
|
|
31
|
+
#include <mutex>
|
|
32
|
+
#include <typeindex>
|
|
33
|
+
#include <typeinfo>
|
|
34
|
+
#include <unordered_map>
|
|
35
|
+
#include <utility>
|
|
36
|
+
#include <vector>
|
|
37
|
+
|
|
38
|
+
namespace librats {
|
|
39
|
+
|
|
40
|
+
class EventBus {
|
|
41
|
+
public:
|
|
42
|
+
/// Register a handler for events of type E. Additive: multiple handlers may
|
|
43
|
+
/// coexist and all fire (in registration order) for each emitted event.
|
|
44
|
+
template <class E>
|
|
45
|
+
void on(std::function<void(const E&)> handler) {
|
|
46
|
+
std::lock_guard<std::mutex> lock(mutex_);
|
|
47
|
+
handlers_[std::type_index(typeid(E))].push_back(
|
|
48
|
+
[h = std::move(handler)](const void* e) { h(*static_cast<const E*>(e)); });
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/// Publish an event to every handler registered for its type.
|
|
52
|
+
template <class E>
|
|
53
|
+
void emit(const E& event) {
|
|
54
|
+
std::vector<ErasedHandler> snapshot;
|
|
55
|
+
{
|
|
56
|
+
std::lock_guard<std::mutex> lock(mutex_);
|
|
57
|
+
auto it = handlers_.find(std::type_index(typeid(E)));
|
|
58
|
+
if (it == handlers_.end()) return;
|
|
59
|
+
snapshot = it->second; // copy under lock, then invoke unlocked
|
|
60
|
+
}
|
|
61
|
+
for (auto& h : snapshot) h(&event);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
private:
|
|
65
|
+
using ErasedHandler = std::function<void(const void*)>;
|
|
66
|
+
std::mutex mutex_;
|
|
67
|
+
std::unordered_map<std::type_index, std::vector<ErasedHandler>> handlers_;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
} // namespace librats
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file host_endpoint.h
|
|
5
|
+
* @brief An unresolved dial target: a host (name OR literal) plus a port.
|
|
6
|
+
*
|
|
7
|
+
* The textual counterpart to Address. Where Address is a strictly numeric,
|
|
8
|
+
* already-resolved endpoint you can hand to a socket, a HostEndpoint is what a
|
|
9
|
+
* user (or a config file) supplies: "router.bittorrent.com:6881", a STUN server,
|
|
10
|
+
* a tracker host. Its `host` may be a DNS name or an IP literal; it carries no
|
|
11
|
+
* bytes and does nothing but hold the two fields until the resolver turns it into
|
|
12
|
+
* one or more Address at the network boundary.
|
|
13
|
+
*
|
|
14
|
+
* Keeping this separate is deliberate (see CLAUDE.md): it keeps hostnames — and
|
|
15
|
+
* the allocation/ambiguity they bring — out of the hot-path Address, which stays
|
|
16
|
+
* a small trivially-copyable value.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
#include "librats/core/endpoint_parse.h"
|
|
20
|
+
|
|
21
|
+
#include <cstdint>
|
|
22
|
+
#include <optional>
|
|
23
|
+
#include <string>
|
|
24
|
+
#include <string_view>
|
|
25
|
+
#include <utility>
|
|
26
|
+
|
|
27
|
+
namespace librats {
|
|
28
|
+
|
|
29
|
+
struct HostEndpoint {
|
|
30
|
+
std::string host;
|
|
31
|
+
uint16_t port = 0;
|
|
32
|
+
|
|
33
|
+
HostEndpoint() = default;
|
|
34
|
+
HostEndpoint(std::string host, uint16_t port) : host(std::move(host)), port(port) {}
|
|
35
|
+
|
|
36
|
+
/// Parse "host:port" or "[ipv6]:port". Accepts hostnames and IP literals alike;
|
|
37
|
+
/// only the port is validated here (resolution happens later). Returns nullopt
|
|
38
|
+
/// if the port is missing/invalid or the host is empty.
|
|
39
|
+
static std::optional<HostEndpoint> parse(std::string_view text) {
|
|
40
|
+
const auto hp = split_host_port(text);
|
|
41
|
+
if (!hp) return std::nullopt;
|
|
42
|
+
return HostEndpoint{std::string(hp->first), hp->second};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/// Bracket a host that looks like an IPv6 literal (contains ':'), else plain.
|
|
46
|
+
std::string to_string() const {
|
|
47
|
+
if (host.find(':') != std::string::npos)
|
|
48
|
+
return "[" + host + "]:" + std::to_string(port);
|
|
49
|
+
return host + ":" + std::to_string(port);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
bool operator==(const HostEndpoint& o) const { return port == o.port && host == o.host; }
|
|
53
|
+
bool operator!=(const HostEndpoint& o) const { return !(*this == o); }
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
} // namespace librats
|