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
|
@@ -1,1007 +0,0 @@
|
|
|
1
|
-
#include "bt_network.h"
|
|
2
|
-
#include "network_utils.h"
|
|
3
|
-
#include "logger.h"
|
|
4
|
-
|
|
5
|
-
#include <algorithm>
|
|
6
|
-
#include <cstring>
|
|
7
|
-
|
|
8
|
-
#ifdef _WIN32
|
|
9
|
-
#include <winsock2.h>
|
|
10
|
-
#include <ws2tcpip.h>
|
|
11
|
-
#else
|
|
12
|
-
#include <netinet/tcp.h>
|
|
13
|
-
#include <fcntl.h>
|
|
14
|
-
#include <errno.h>
|
|
15
|
-
#endif
|
|
16
|
-
|
|
17
|
-
// Module logging macros
|
|
18
|
-
#define LOG_NET_DEBUG(msg) LOG_DEBUG("BtNetwork", msg)
|
|
19
|
-
#define LOG_NET_INFO(msg) LOG_INFO("BtNetwork", msg)
|
|
20
|
-
#define LOG_NET_WARN(msg) LOG_WARN("BtNetwork", msg)
|
|
21
|
-
#define LOG_NET_ERROR(msg) LOG_ERROR("BtNetwork", msg)
|
|
22
|
-
|
|
23
|
-
namespace librats {
|
|
24
|
-
|
|
25
|
-
//=============================================================================
|
|
26
|
-
// BtNetworkManager Construction
|
|
27
|
-
//=============================================================================
|
|
28
|
-
|
|
29
|
-
BtNetworkManager::BtNetworkManager(const BtNetworkConfig& config)
|
|
30
|
-
: config_(config)
|
|
31
|
-
, running_(false)
|
|
32
|
-
, actual_listen_port_(0)
|
|
33
|
-
, listen_socket_(INVALID_SOCKET_VALUE) {
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
BtNetworkManager::~BtNetworkManager() {
|
|
37
|
-
stop();
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
//=============================================================================
|
|
41
|
-
// TCP_NODELAY helper
|
|
42
|
-
//=============================================================================
|
|
43
|
-
|
|
44
|
-
bool BtNetworkManager::set_tcp_nodelay(socket_t sock) {
|
|
45
|
-
int flag = 1;
|
|
46
|
-
int result = setsockopt(sock, IPPROTO_TCP, TCP_NODELAY,
|
|
47
|
-
reinterpret_cast<const char*>(&flag), sizeof(flag));
|
|
48
|
-
if (result < 0) {
|
|
49
|
-
LOG_NET_WARN("Failed to set TCP_NODELAY on socket " + std::to_string(static_cast<int>(sock)));
|
|
50
|
-
return false;
|
|
51
|
-
}
|
|
52
|
-
return true;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
//=============================================================================
|
|
56
|
-
// Lifecycle
|
|
57
|
-
//=============================================================================
|
|
58
|
-
|
|
59
|
-
bool BtNetworkManager::start() {
|
|
60
|
-
if (running_) return true;
|
|
61
|
-
|
|
62
|
-
// Initialize socket library (required on Windows)
|
|
63
|
-
if (!init_socket_library()) {
|
|
64
|
-
LOG_NET_ERROR("Failed to initialize socket library");
|
|
65
|
-
return false;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
// Create the I/O poller
|
|
69
|
-
poller_ = IOPoller::create();
|
|
70
|
-
if (!poller_) {
|
|
71
|
-
LOG_NET_ERROR("Failed to create I/O poller");
|
|
72
|
-
return false;
|
|
73
|
-
}
|
|
74
|
-
LOG_NET_INFO("Using I/O backend: " + std::string(poller_->name()));
|
|
75
|
-
|
|
76
|
-
// Create listen socket if incoming enabled
|
|
77
|
-
if (config_.enable_incoming) {
|
|
78
|
-
listen_socket_ = create_tcp_server(config_.listen_port, 50);
|
|
79
|
-
if (!is_valid_socket(listen_socket_)) {
|
|
80
|
-
LOG_NET_ERROR("Failed to create listen socket on port " +
|
|
81
|
-
std::to_string(config_.listen_port));
|
|
82
|
-
return false;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
// Set non-blocking
|
|
86
|
-
if (!set_socket_nonblocking(listen_socket_)) {
|
|
87
|
-
LOG_NET_ERROR("Failed to set listen socket non-blocking");
|
|
88
|
-
close_socket(listen_socket_);
|
|
89
|
-
listen_socket_ = INVALID_SOCKET_VALUE;
|
|
90
|
-
return false;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
// Get actual port (in case 0 was specified)
|
|
94
|
-
actual_listen_port_ = static_cast<uint16_t>(get_bound_port(listen_socket_));
|
|
95
|
-
if (actual_listen_port_ == 0) {
|
|
96
|
-
actual_listen_port_ = config_.listen_port;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// Register listen socket with poller (interested in incoming connections)
|
|
100
|
-
poller_->add(listen_socket_, PollIn);
|
|
101
|
-
poller_state_[listen_socket_] = PollIn;
|
|
102
|
-
|
|
103
|
-
LOG_NET_INFO("Listening on port " + std::to_string(actual_listen_port_));
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
running_ = true;
|
|
107
|
-
|
|
108
|
-
// Start I/O thread
|
|
109
|
-
io_thread_ = std::thread(&BtNetworkManager::io_loop, this);
|
|
110
|
-
|
|
111
|
-
LOG_NET_INFO("Network manager started");
|
|
112
|
-
return true;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
void BtNetworkManager::stop() {
|
|
116
|
-
if (!running_) return;
|
|
117
|
-
|
|
118
|
-
running_ = false;
|
|
119
|
-
|
|
120
|
-
// Wait for I/O thread
|
|
121
|
-
if (io_thread_.joinable()) {
|
|
122
|
-
io_thread_.join();
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
std::vector<DisconnectedEvent> disconnected_events;
|
|
126
|
-
|
|
127
|
-
{
|
|
128
|
-
std::lock_guard<std::mutex> lock(mutex_);
|
|
129
|
-
|
|
130
|
-
// Collect disconnected events for all connections
|
|
131
|
-
for (auto& [socket, ctx] : connections_) {
|
|
132
|
-
if (ctx.connection) {
|
|
133
|
-
DisconnectedEvent event;
|
|
134
|
-
event.info_hash = ctx.info_hash;
|
|
135
|
-
event.connection = ctx.connection;
|
|
136
|
-
disconnected_events.push_back(std::move(event));
|
|
137
|
-
}
|
|
138
|
-
poller_->remove(socket);
|
|
139
|
-
close_socket(socket, true);
|
|
140
|
-
}
|
|
141
|
-
connections_.clear();
|
|
142
|
-
|
|
143
|
-
// Close connecting sockets
|
|
144
|
-
for (auto& [socket, pending] : connecting_) {
|
|
145
|
-
poller_->remove(socket);
|
|
146
|
-
close_socket(socket, true);
|
|
147
|
-
}
|
|
148
|
-
connecting_.clear();
|
|
149
|
-
|
|
150
|
-
// Clear pending queue
|
|
151
|
-
while (!pending_connects_.empty()) {
|
|
152
|
-
pending_connects_.pop();
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
// Close listen socket
|
|
156
|
-
if (is_valid_socket(listen_socket_)) {
|
|
157
|
-
poller_->remove(listen_socket_);
|
|
158
|
-
close_socket(listen_socket_);
|
|
159
|
-
listen_socket_ = INVALID_SOCKET_VALUE;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
poller_state_.clear();
|
|
163
|
-
poller_.reset();
|
|
164
|
-
|
|
165
|
-
LOG_NET_INFO("Network manager stopped");
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
// Invoke callbacks outside mutex
|
|
169
|
-
for (const auto& event : disconnected_events) {
|
|
170
|
-
if (on_disconnected_) {
|
|
171
|
-
on_disconnected_(event.info_hash, event.connection.get());
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
//=============================================================================
|
|
177
|
-
// Torrent Registration
|
|
178
|
-
//=============================================================================
|
|
179
|
-
|
|
180
|
-
void BtNetworkManager::register_torrent(const BtInfoHash& info_hash,
|
|
181
|
-
const PeerID& peer_id,
|
|
182
|
-
uint32_t num_pieces) {
|
|
183
|
-
std::lock_guard<std::mutex> lock(mutex_);
|
|
184
|
-
|
|
185
|
-
TorrentRegistration reg;
|
|
186
|
-
reg.info_hash = info_hash;
|
|
187
|
-
reg.peer_id = peer_id;
|
|
188
|
-
reg.num_pieces = num_pieces;
|
|
189
|
-
|
|
190
|
-
torrents_[info_hash] = reg;
|
|
191
|
-
|
|
192
|
-
LOG_NET_DEBUG("Registered torrent " + info_hash_to_hex(info_hash).substr(0, 8) + "...");
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
void BtNetworkManager::unregister_torrent(const BtInfoHash& info_hash) {
|
|
196
|
-
std::vector<DisconnectedEvent> disconnected_events;
|
|
197
|
-
|
|
198
|
-
{
|
|
199
|
-
std::lock_guard<std::mutex> lock(mutex_);
|
|
200
|
-
|
|
201
|
-
// Close all connections for this torrent
|
|
202
|
-
std::vector<socket_t> to_close;
|
|
203
|
-
for (auto& [socket, ctx] : connections_) {
|
|
204
|
-
if (ctx.info_hash == info_hash) {
|
|
205
|
-
to_close.push_back(socket);
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
for (socket_t s : to_close) {
|
|
210
|
-
close_connection_internal(s, disconnected_events);
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
torrents_.erase(info_hash);
|
|
214
|
-
|
|
215
|
-
LOG_NET_DEBUG("Unregistered torrent " + info_hash_to_hex(info_hash).substr(0, 8) + "...");
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
// Invoke callbacks outside mutex
|
|
219
|
-
for (const auto& event : disconnected_events) {
|
|
220
|
-
if (on_disconnected_) {
|
|
221
|
-
on_disconnected_(event.info_hash, event.connection.get());
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
//=============================================================================
|
|
227
|
-
// Connection Management
|
|
228
|
-
//=============================================================================
|
|
229
|
-
|
|
230
|
-
bool BtNetworkManager::connect_peer(const std::string& ip, uint16_t port,
|
|
231
|
-
const BtInfoHash& info_hash,
|
|
232
|
-
const PeerID& peer_id,
|
|
233
|
-
uint32_t num_pieces) {
|
|
234
|
-
std::lock_guard<std::mutex> lock(mutex_);
|
|
235
|
-
|
|
236
|
-
// Check connection limit (include pending queue in the count)
|
|
237
|
-
size_t total = connections_.size() + connecting_.size() + pending_connects_.size();
|
|
238
|
-
if (total >= config_.max_connections) {
|
|
239
|
-
LOG_NET_DEBUG("Connection limit reached, cannot connect to " + ip);
|
|
240
|
-
return false;
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
// Check if already connected/connecting to this peer
|
|
244
|
-
for (const auto& [sock, ctx] : connections_) {
|
|
245
|
-
if (ctx.connection && ctx.connection->ip() == ip &&
|
|
246
|
-
ctx.connection->port() == port) {
|
|
247
|
-
LOG_NET_DEBUG("Already connected to " + ip + ":" + std::to_string(port));
|
|
248
|
-
return false;
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
for (const auto& [sock, pending] : connecting_) {
|
|
253
|
-
if (pending.ip == ip && pending.port == port) {
|
|
254
|
-
LOG_NET_DEBUG("Already connecting to " + ip + ":" + std::to_string(port));
|
|
255
|
-
return false;
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
// Check pending queue for duplicates
|
|
260
|
-
// Note: std::queue doesn't support iteration, so we use a temporary copy
|
|
261
|
-
std::queue<PendingConnect> temp_queue = pending_connects_;
|
|
262
|
-
while (!temp_queue.empty()) {
|
|
263
|
-
const auto& queued = temp_queue.front();
|
|
264
|
-
if (queued.ip == ip && queued.port == port) {
|
|
265
|
-
LOG_NET_DEBUG("Already queued connection to " + ip + ":" + std::to_string(port));
|
|
266
|
-
return false;
|
|
267
|
-
}
|
|
268
|
-
temp_queue.pop();
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
// Queue the connection
|
|
272
|
-
PendingConnect pending;
|
|
273
|
-
pending.ip = ip;
|
|
274
|
-
pending.port = port;
|
|
275
|
-
pending.info_hash = info_hash;
|
|
276
|
-
pending.peer_id = peer_id;
|
|
277
|
-
pending.num_pieces = num_pieces;
|
|
278
|
-
pending.socket = INVALID_SOCKET_VALUE;
|
|
279
|
-
pending.start_time = std::chrono::steady_clock::now();
|
|
280
|
-
|
|
281
|
-
pending_connects_.push(std::move(pending));
|
|
282
|
-
|
|
283
|
-
LOG_NET_DEBUG("Queued connection to " + ip + ":" + std::to_string(port));
|
|
284
|
-
return true;
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
void BtNetworkManager::close_connection(socket_t socket) {
|
|
288
|
-
std::vector<DisconnectedEvent> disconnected_events;
|
|
289
|
-
|
|
290
|
-
{
|
|
291
|
-
std::lock_guard<std::mutex> lock(mutex_);
|
|
292
|
-
close_connection_internal(socket, disconnected_events);
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
// Invoke callbacks outside mutex
|
|
296
|
-
for (const auto& event : disconnected_events) {
|
|
297
|
-
if (on_disconnected_) {
|
|
298
|
-
on_disconnected_(event.info_hash, event.connection.get());
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
bool BtNetworkManager::send_to_peer(socket_t socket, const std::vector<uint8_t>& data) {
|
|
304
|
-
std::lock_guard<std::mutex> lock(mutex_);
|
|
305
|
-
|
|
306
|
-
auto it = connections_.find(socket);
|
|
307
|
-
if (it == connections_.end() || !it->second.connection) {
|
|
308
|
-
return false;
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
auto& send_buf = it->second.connection->send_buffer();
|
|
312
|
-
|
|
313
|
-
// Check high water mark
|
|
314
|
-
if (send_buf.size() + data.size() > config_.send_buffer_high_water) {
|
|
315
|
-
LOG_NET_WARN("Send buffer high water reached for " +
|
|
316
|
-
it->second.connection->ip());
|
|
317
|
-
return false;
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
bool was_empty = send_buf.empty();
|
|
321
|
-
|
|
322
|
-
// Append directly to connection's send buffer (single source of truth)
|
|
323
|
-
send_buf.append(data.data(), data.size());
|
|
324
|
-
|
|
325
|
-
// If buffer was empty, we need to start watching for writability.
|
|
326
|
-
// Update poller to add PollOut interest.
|
|
327
|
-
if (was_empty && poller_) {
|
|
328
|
-
uint32_t desired = PollIn | PollOut;
|
|
329
|
-
auto ps = poller_state_.find(socket);
|
|
330
|
-
if (ps != poller_state_.end() && ps->second != desired) {
|
|
331
|
-
poller_->modify(socket, desired);
|
|
332
|
-
ps->second = desired;
|
|
333
|
-
}
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
return true;
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
size_t BtNetworkManager::connection_count() const {
|
|
340
|
-
std::lock_guard<std::mutex> lock(mutex_);
|
|
341
|
-
return connections_.size();
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
size_t BtNetworkManager::pending_connect_count() const {
|
|
345
|
-
std::lock_guard<std::mutex> lock(mutex_);
|
|
346
|
-
return pending_connects_.size() + connecting_.size();
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
//=============================================================================
|
|
350
|
-
// Poller State Sync
|
|
351
|
-
//=============================================================================
|
|
352
|
-
|
|
353
|
-
void BtNetworkManager::sync_poller() {
|
|
354
|
-
// Called under mutex. Ensures poller registrations match current state.
|
|
355
|
-
// This is the primary sync point for connections whose send buffer
|
|
356
|
-
// state may have changed (e.g., after flush_send_buffer drains it).
|
|
357
|
-
|
|
358
|
-
for (auto& [socket, ctx] : connections_) {
|
|
359
|
-
// Determine desired events
|
|
360
|
-
uint32_t desired = PollIn; // Always interested in reading
|
|
361
|
-
if (ctx.connection && !ctx.connection->send_buffer().empty()) {
|
|
362
|
-
desired |= PollOut; // Also interested in writing
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
auto ps = poller_state_.find(socket);
|
|
366
|
-
if (ps == poller_state_.end()) {
|
|
367
|
-
// Not yet registered (shouldn't happen normally, but be safe)
|
|
368
|
-
poller_->add(socket, desired);
|
|
369
|
-
poller_state_[socket] = desired;
|
|
370
|
-
} else if (ps->second != desired) {
|
|
371
|
-
poller_->modify(socket, desired);
|
|
372
|
-
ps->second = desired;
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
// Connecting sockets: interested in write (connect complete) + error
|
|
377
|
-
for (auto& [socket, pending] : connecting_) {
|
|
378
|
-
auto ps = poller_state_.find(socket);
|
|
379
|
-
uint32_t desired = PollOut;
|
|
380
|
-
if (ps == poller_state_.end()) {
|
|
381
|
-
poller_->add(socket, desired);
|
|
382
|
-
poller_state_[socket] = desired;
|
|
383
|
-
}
|
|
384
|
-
// Connecting sockets don't change their interest, no modify needed
|
|
385
|
-
}
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
//=============================================================================
|
|
389
|
-
// I/O Loop
|
|
390
|
-
//=============================================================================
|
|
391
|
-
|
|
392
|
-
void BtNetworkManager::io_loop() {
|
|
393
|
-
LOG_NET_DEBUG("I/O loop started");
|
|
394
|
-
|
|
395
|
-
// Event vectors for deferred callback invocation (outside mutex)
|
|
396
|
-
std::vector<ConnectedEvent> connected_events;
|
|
397
|
-
std::vector<DataEvent> data_events;
|
|
398
|
-
std::vector<DisconnectedEvent> disconnected_events;
|
|
399
|
-
|
|
400
|
-
// Poll results buffer
|
|
401
|
-
static constexpr int MAX_POLL_EVENTS = 256;
|
|
402
|
-
PollResult poll_results[MAX_POLL_EVENTS];
|
|
403
|
-
|
|
404
|
-
while (running_) {
|
|
405
|
-
// Clear event vectors for this iteration
|
|
406
|
-
connected_events.clear();
|
|
407
|
-
data_events.clear();
|
|
408
|
-
disconnected_events.clear();
|
|
409
|
-
|
|
410
|
-
// Process pending connect queue (adds new sockets to poller)
|
|
411
|
-
process_pending_connects();
|
|
412
|
-
|
|
413
|
-
// Sync poller state (update write interest based on send buffer state)
|
|
414
|
-
{
|
|
415
|
-
std::lock_guard<std::mutex> lock(mutex_);
|
|
416
|
-
sync_poller();
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
// Wait for I/O events (NO mutex held — this is the blocking call)
|
|
420
|
-
int num_events = poller_->wait(poll_results, MAX_POLL_EVENTS,
|
|
421
|
-
config_.poll_timeout_ms);
|
|
422
|
-
|
|
423
|
-
if (num_events < 0) {
|
|
424
|
-
// Error (EINTR already filtered by poller implementations)
|
|
425
|
-
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
|
426
|
-
continue;
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
if (num_events == 0) {
|
|
430
|
-
// Timeout — check for connection timeouts
|
|
431
|
-
auto now = std::chrono::steady_clock::now();
|
|
432
|
-
|
|
433
|
-
std::lock_guard<std::mutex> lock(mutex_);
|
|
434
|
-
|
|
435
|
-
std::vector<socket_t> timed_out;
|
|
436
|
-
for (auto& [socket, pending] : connecting_) {
|
|
437
|
-
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
|
|
438
|
-
now - pending.start_time).count();
|
|
439
|
-
if (elapsed > config_.connect_timeout_ms) {
|
|
440
|
-
timed_out.push_back(socket);
|
|
441
|
-
}
|
|
442
|
-
}
|
|
443
|
-
|
|
444
|
-
for (socket_t s : timed_out) {
|
|
445
|
-
LOG_NET_DEBUG("Connection timed out to " + connecting_[s].ip);
|
|
446
|
-
poller_->remove(s);
|
|
447
|
-
poller_state_.erase(s);
|
|
448
|
-
close_socket(s);
|
|
449
|
-
connecting_.erase(s);
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
continue;
|
|
453
|
-
}
|
|
454
|
-
|
|
455
|
-
LOG_NET_DEBUG("I/O poll returned " + std::to_string(num_events) + " events");
|
|
456
|
-
|
|
457
|
-
// Process all events under mutex
|
|
458
|
-
{
|
|
459
|
-
std::lock_guard<std::mutex> lock(mutex_);
|
|
460
|
-
|
|
461
|
-
std::vector<socket_t> to_close;
|
|
462
|
-
|
|
463
|
-
for (int i = 0; i < num_events; ++i) {
|
|
464
|
-
socket_t fd = poll_results[i].fd;
|
|
465
|
-
uint32_t events = poll_results[i].events;
|
|
466
|
-
|
|
467
|
-
//--------------------------------------------------------------
|
|
468
|
-
// Listen socket — accept incoming
|
|
469
|
-
//--------------------------------------------------------------
|
|
470
|
-
if (fd == listen_socket_) {
|
|
471
|
-
if (events & PollIn) {
|
|
472
|
-
// NOTE: accept_incoming acquires mutex internally,
|
|
473
|
-
// but we are already holding it. We need to call
|
|
474
|
-
// the internal version without re-locking.
|
|
475
|
-
accept_incoming();
|
|
476
|
-
}
|
|
477
|
-
continue;
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
//--------------------------------------------------------------
|
|
481
|
-
// Connecting socket — check connect completion
|
|
482
|
-
//--------------------------------------------------------------
|
|
483
|
-
auto connecting_it = connecting_.find(fd);
|
|
484
|
-
if (connecting_it != connecting_.end()) {
|
|
485
|
-
auto& pending = connecting_it->second;
|
|
486
|
-
|
|
487
|
-
if (events & PollErr) {
|
|
488
|
-
// Connection failed
|
|
489
|
-
LOG_NET_DEBUG("Connection failed (poll error) to " + pending.ip);
|
|
490
|
-
poller_->remove(fd);
|
|
491
|
-
poller_state_.erase(fd);
|
|
492
|
-
close_socket(fd);
|
|
493
|
-
connecting_.erase(connecting_it);
|
|
494
|
-
continue;
|
|
495
|
-
}
|
|
496
|
-
|
|
497
|
-
if (events & PollOut) {
|
|
498
|
-
// Check if connection succeeded
|
|
499
|
-
int sock_error = 0;
|
|
500
|
-
socklen_t len = sizeof(sock_error);
|
|
501
|
-
getsockopt(fd, SOL_SOCKET, SO_ERROR,
|
|
502
|
-
reinterpret_cast<char*>(&sock_error), &len);
|
|
503
|
-
|
|
504
|
-
if (sock_error == 0) {
|
|
505
|
-
LOG_NET_INFO("Connected to peer " + pending.ip + ":" +
|
|
506
|
-
std::to_string(pending.port));
|
|
507
|
-
|
|
508
|
-
// Set TCP_NODELAY for low latency
|
|
509
|
-
set_tcp_nodelay(fd);
|
|
510
|
-
|
|
511
|
-
// Create connection object
|
|
512
|
-
auto conn = std::make_shared<BtPeerConnection>(
|
|
513
|
-
pending.info_hash, pending.peer_id, pending.num_pieces);
|
|
514
|
-
conn->set_address(pending.ip, pending.port);
|
|
515
|
-
conn->set_socket(static_cast<int>(fd));
|
|
516
|
-
|
|
517
|
-
// Create socket context
|
|
518
|
-
SocketContext ctx;
|
|
519
|
-
ctx.socket = fd;
|
|
520
|
-
ctx.info_hash = pending.info_hash;
|
|
521
|
-
ctx.connection = conn;
|
|
522
|
-
ctx.state = NetConnectionState::Handshaking;
|
|
523
|
-
ctx.incoming = false;
|
|
524
|
-
ctx.connected_at = std::chrono::steady_clock::now();
|
|
525
|
-
ctx.last_activity = ctx.connected_at;
|
|
526
|
-
|
|
527
|
-
// Send handshake
|
|
528
|
-
LOG_NET_DEBUG("Sending handshake (" +
|
|
529
|
-
std::to_string(BT_HANDSHAKE_SIZE) + " bytes) to " +
|
|
530
|
-
pending.ip);
|
|
531
|
-
conn->start_handshake();
|
|
532
|
-
|
|
533
|
-
connections_[fd] = std::move(ctx);
|
|
534
|
-
|
|
535
|
-
// Update poller: now interested in read (+ write if handshake queued)
|
|
536
|
-
uint32_t desired = PollIn;
|
|
537
|
-
if (!conn->send_buffer().empty()) {
|
|
538
|
-
desired |= PollOut;
|
|
539
|
-
}
|
|
540
|
-
poller_->modify(fd, desired);
|
|
541
|
-
poller_state_[fd] = desired;
|
|
542
|
-
|
|
543
|
-
LOG_NET_DEBUG("Handshake queued to " + pending.ip);
|
|
544
|
-
} else {
|
|
545
|
-
LOG_NET_DEBUG("Connection failed to " + pending.ip + ": " +
|
|
546
|
-
std::to_string(sock_error));
|
|
547
|
-
poller_->remove(fd);
|
|
548
|
-
poller_state_.erase(fd);
|
|
549
|
-
close_socket(fd);
|
|
550
|
-
}
|
|
551
|
-
|
|
552
|
-
connecting_.erase(connecting_it);
|
|
553
|
-
}
|
|
554
|
-
continue;
|
|
555
|
-
}
|
|
556
|
-
|
|
557
|
-
//--------------------------------------------------------------
|
|
558
|
-
// Active connection — handle read/write/error
|
|
559
|
-
//--------------------------------------------------------------
|
|
560
|
-
auto conn_it = connections_.find(fd);
|
|
561
|
-
if (conn_it == connections_.end()) {
|
|
562
|
-
// Unknown fd — remove from poller
|
|
563
|
-
poller_->remove(fd);
|
|
564
|
-
poller_state_.erase(fd);
|
|
565
|
-
continue;
|
|
566
|
-
}
|
|
567
|
-
|
|
568
|
-
bool should_close = false;
|
|
569
|
-
|
|
570
|
-
if (events & PollErr) {
|
|
571
|
-
if (conn_it->second.connection) {
|
|
572
|
-
LOG_NET_DEBUG("Error on socket for " + conn_it->second.connection->ip());
|
|
573
|
-
}
|
|
574
|
-
should_close = true;
|
|
575
|
-
}
|
|
576
|
-
|
|
577
|
-
if (!should_close && (events & PollHup)) {
|
|
578
|
-
if (conn_it->second.connection) {
|
|
579
|
-
LOG_NET_DEBUG("Peer hung up: " + conn_it->second.connection->ip());
|
|
580
|
-
}
|
|
581
|
-
should_close = true;
|
|
582
|
-
}
|
|
583
|
-
|
|
584
|
-
if (!should_close && (events & PollIn)) {
|
|
585
|
-
should_close = handle_readable(fd, connected_events, data_events);
|
|
586
|
-
}
|
|
587
|
-
|
|
588
|
-
if (!should_close && (events & PollOut)) {
|
|
589
|
-
should_close = handle_writable(fd);
|
|
590
|
-
}
|
|
591
|
-
|
|
592
|
-
if (should_close) {
|
|
593
|
-
to_close.push_back(fd);
|
|
594
|
-
}
|
|
595
|
-
}
|
|
596
|
-
|
|
597
|
-
// Close connections AFTER processing all events to avoid iterator invalidation
|
|
598
|
-
for (socket_t s : to_close) {
|
|
599
|
-
close_connection_internal(s, disconnected_events);
|
|
600
|
-
}
|
|
601
|
-
}
|
|
602
|
-
|
|
603
|
-
// Invoke callbacks OUTSIDE the mutex to prevent deadlocks
|
|
604
|
-
for (const auto& event : connected_events) {
|
|
605
|
-
if (on_connected_) {
|
|
606
|
-
on_connected_(event.info_hash, event.connection,
|
|
607
|
-
event.socket, event.incoming);
|
|
608
|
-
}
|
|
609
|
-
}
|
|
610
|
-
|
|
611
|
-
for (const auto& event : data_events) {
|
|
612
|
-
if (on_data_) {
|
|
613
|
-
on_data_(event.info_hash, event.connection.get(), event.socket);
|
|
614
|
-
}
|
|
615
|
-
}
|
|
616
|
-
|
|
617
|
-
for (const auto& event : disconnected_events) {
|
|
618
|
-
if (on_disconnected_) {
|
|
619
|
-
on_disconnected_(event.info_hash, event.connection.get());
|
|
620
|
-
}
|
|
621
|
-
}
|
|
622
|
-
}
|
|
623
|
-
|
|
624
|
-
LOG_NET_DEBUG("I/O loop stopped");
|
|
625
|
-
}
|
|
626
|
-
|
|
627
|
-
void BtNetworkManager::process_pending_connects() {
|
|
628
|
-
std::lock_guard<std::mutex> lock(mutex_);
|
|
629
|
-
|
|
630
|
-
// Limit concurrent connects
|
|
631
|
-
const size_t max_concurrent = 30;
|
|
632
|
-
|
|
633
|
-
while (!pending_connects_.empty() &&
|
|
634
|
-
connecting_.size() < max_concurrent &&
|
|
635
|
-
connections_.size() + connecting_.size() < config_.max_connections) {
|
|
636
|
-
|
|
637
|
-
PendingConnect pending = std::move(pending_connects_.front());
|
|
638
|
-
pending_connects_.pop();
|
|
639
|
-
|
|
640
|
-
// Create non-blocking socket
|
|
641
|
-
socket_t sock = create_connect_socket(pending.ip, pending.port);
|
|
642
|
-
if (!is_valid_socket(sock)) {
|
|
643
|
-
continue;
|
|
644
|
-
}
|
|
645
|
-
|
|
646
|
-
pending.socket = sock;
|
|
647
|
-
pending.start_time = std::chrono::steady_clock::now();
|
|
648
|
-
|
|
649
|
-
// Register with poller: interested in write (connect complete)
|
|
650
|
-
poller_->add(sock, PollOut);
|
|
651
|
-
poller_state_[sock] = PollOut;
|
|
652
|
-
|
|
653
|
-
connecting_[sock] = std::move(pending);
|
|
654
|
-
}
|
|
655
|
-
|
|
656
|
-
if (!pending_connects_.empty()) {
|
|
657
|
-
LOG_NET_DEBUG("process_pending_connects: " +
|
|
658
|
-
std::to_string(connecting_.size()) + " pending");
|
|
659
|
-
}
|
|
660
|
-
}
|
|
661
|
-
|
|
662
|
-
socket_t BtNetworkManager::create_connect_socket(const std::string& ip, uint16_t port) {
|
|
663
|
-
// Create socket
|
|
664
|
-
socket_t sock = socket(AF_INET, SOCK_STREAM, 0);
|
|
665
|
-
if (!is_valid_socket(sock)) {
|
|
666
|
-
LOG_NET_ERROR("Failed to create socket");
|
|
667
|
-
return INVALID_SOCKET_VALUE;
|
|
668
|
-
}
|
|
669
|
-
|
|
670
|
-
// Set non-blocking
|
|
671
|
-
if (!set_socket_nonblocking(sock)) {
|
|
672
|
-
LOG_NET_ERROR("Failed to set socket non-blocking");
|
|
673
|
-
close_socket(sock);
|
|
674
|
-
return INVALID_SOCKET_VALUE;
|
|
675
|
-
}
|
|
676
|
-
|
|
677
|
-
// Set TCP_NODELAY immediately (before connect)
|
|
678
|
-
set_tcp_nodelay(sock);
|
|
679
|
-
|
|
680
|
-
// Resolve and connect
|
|
681
|
-
std::string resolved = network_utils::resolve_hostname(ip);
|
|
682
|
-
if (resolved.empty()) {
|
|
683
|
-
LOG_NET_ERROR("Failed to resolve " + ip);
|
|
684
|
-
close_socket(sock);
|
|
685
|
-
return INVALID_SOCKET_VALUE;
|
|
686
|
-
}
|
|
687
|
-
|
|
688
|
-
sockaddr_in addr;
|
|
689
|
-
std::memset(&addr, 0, sizeof(addr));
|
|
690
|
-
addr.sin_family = AF_INET;
|
|
691
|
-
addr.sin_port = htons(port);
|
|
692
|
-
|
|
693
|
-
if (inet_pton(AF_INET, resolved.c_str(), &addr.sin_addr) <= 0) {
|
|
694
|
-
LOG_NET_ERROR("Invalid address: " + resolved);
|
|
695
|
-
close_socket(sock);
|
|
696
|
-
return INVALID_SOCKET_VALUE;
|
|
697
|
-
}
|
|
698
|
-
|
|
699
|
-
LOG_NET_DEBUG("Connecting to " + ip + ":" + std::to_string(port));
|
|
700
|
-
|
|
701
|
-
int result = connect(sock, reinterpret_cast<sockaddr*>(&addr), sizeof(addr));
|
|
702
|
-
if (result < 0) {
|
|
703
|
-
#ifdef _WIN32
|
|
704
|
-
int err = WSAGetLastError();
|
|
705
|
-
if (err != WSAEWOULDBLOCK) {
|
|
706
|
-
LOG_NET_DEBUG("Connect failed immediately: " + std::to_string(err));
|
|
707
|
-
close_socket(sock);
|
|
708
|
-
return INVALID_SOCKET_VALUE;
|
|
709
|
-
}
|
|
710
|
-
#else
|
|
711
|
-
if (errno != EINPROGRESS) {
|
|
712
|
-
LOG_NET_DEBUG("Connect failed immediately: " + std::string(strerror(errno)));
|
|
713
|
-
close_socket(sock);
|
|
714
|
-
return INVALID_SOCKET_VALUE;
|
|
715
|
-
}
|
|
716
|
-
#endif
|
|
717
|
-
}
|
|
718
|
-
|
|
719
|
-
return sock;
|
|
720
|
-
}
|
|
721
|
-
|
|
722
|
-
void BtNetworkManager::accept_incoming() {
|
|
723
|
-
// NOTE: called with mutex_ already held from io_loop
|
|
724
|
-
|
|
725
|
-
socket_t client = accept_client(listen_socket_);
|
|
726
|
-
if (!is_valid_socket(client)) {
|
|
727
|
-
return;
|
|
728
|
-
}
|
|
729
|
-
|
|
730
|
-
// Check connection limit
|
|
731
|
-
if (connections_.size() >= config_.max_connections) {
|
|
732
|
-
LOG_NET_DEBUG("Connection limit reached, rejecting incoming");
|
|
733
|
-
close_socket(client);
|
|
734
|
-
return;
|
|
735
|
-
}
|
|
736
|
-
|
|
737
|
-
// Set non-blocking
|
|
738
|
-
if (!set_socket_nonblocking(client)) {
|
|
739
|
-
close_socket(client);
|
|
740
|
-
return;
|
|
741
|
-
}
|
|
742
|
-
|
|
743
|
-
// Set TCP_NODELAY for low latency
|
|
744
|
-
set_tcp_nodelay(client);
|
|
745
|
-
|
|
746
|
-
// Get peer address
|
|
747
|
-
std::string peer_addr = get_peer_address(client);
|
|
748
|
-
std::string ip;
|
|
749
|
-
uint16_t port = 0;
|
|
750
|
-
|
|
751
|
-
size_t colon = peer_addr.rfind(':');
|
|
752
|
-
if (colon != std::string::npos) {
|
|
753
|
-
ip = peer_addr.substr(0, colon);
|
|
754
|
-
port = static_cast<uint16_t>(std::stoi(peer_addr.substr(colon + 1)));
|
|
755
|
-
}
|
|
756
|
-
|
|
757
|
-
LOG_NET_INFO("Accepted incoming connection from " + peer_addr);
|
|
758
|
-
|
|
759
|
-
// Create connection object immediately (info_hash unknown until handshake)
|
|
760
|
-
auto conn = std::make_shared<BtPeerConnection>(config_.peer_id);
|
|
761
|
-
conn->set_address(ip, port);
|
|
762
|
-
conn->set_socket(static_cast<int>(client));
|
|
763
|
-
|
|
764
|
-
// Set up callback for when handshake reveals the info_hash
|
|
765
|
-
conn->set_info_hash_callback([this](BtPeerConnection* peer, const BtInfoHash& info_hash) {
|
|
766
|
-
on_incoming_info_hash(peer, info_hash);
|
|
767
|
-
});
|
|
768
|
-
|
|
769
|
-
SocketContext ctx;
|
|
770
|
-
ctx.socket = client;
|
|
771
|
-
ctx.state = NetConnectionState::Handshaking;
|
|
772
|
-
ctx.incoming = true;
|
|
773
|
-
ctx.connected_at = std::chrono::steady_clock::now();
|
|
774
|
-
ctx.last_activity = ctx.connected_at;
|
|
775
|
-
ctx.connection = conn;
|
|
776
|
-
|
|
777
|
-
connections_[client] = std::move(ctx);
|
|
778
|
-
|
|
779
|
-
// Register with poller (interested in reading handshake)
|
|
780
|
-
poller_->add(client, PollIn);
|
|
781
|
-
poller_state_[client] = PollIn;
|
|
782
|
-
}
|
|
783
|
-
|
|
784
|
-
void BtNetworkManager::on_incoming_info_hash(BtPeerConnection* conn, const BtInfoHash& info_hash) {
|
|
785
|
-
// This is called from within process_incoming() when an incoming connection
|
|
786
|
-
// receives a handshake and discovers the info_hash. We need to look up the
|
|
787
|
-
// torrent and set the correct info.
|
|
788
|
-
|
|
789
|
-
// Note: We're already holding the mutex (called from io_loop -> handle_readable -> process_incoming)
|
|
790
|
-
|
|
791
|
-
auto torrent_it = torrents_.find(info_hash);
|
|
792
|
-
if (torrent_it == torrents_.end()) {
|
|
793
|
-
LOG_NET_DEBUG("Unknown info_hash " + info_hash_to_hex(info_hash).substr(0, 8) +
|
|
794
|
-
"... from incoming connection " + conn->ip());
|
|
795
|
-
// Connection will be closed by BtPeerConnection when set_torrent_info is not called
|
|
796
|
-
return;
|
|
797
|
-
}
|
|
798
|
-
|
|
799
|
-
const auto& reg = torrent_it->second;
|
|
800
|
-
|
|
801
|
-
LOG_NET_DEBUG("Routing incoming connection from " + conn->ip() +
|
|
802
|
-
" to torrent " + info_hash_to_hex(info_hash).substr(0, 8) + "...");
|
|
803
|
-
|
|
804
|
-
// Set the torrent info on the connection
|
|
805
|
-
conn->set_torrent_info(info_hash, reg.num_pieces);
|
|
806
|
-
|
|
807
|
-
// Update the SocketContext with the info_hash
|
|
808
|
-
for (auto& [socket, ctx] : connections_) {
|
|
809
|
-
if (ctx.connection.get() == conn) {
|
|
810
|
-
ctx.info_hash = info_hash;
|
|
811
|
-
break;
|
|
812
|
-
}
|
|
813
|
-
}
|
|
814
|
-
}
|
|
815
|
-
|
|
816
|
-
bool BtNetworkManager::handle_readable(socket_t socket,
|
|
817
|
-
std::vector<ConnectedEvent>& connected_events,
|
|
818
|
-
std::vector<DataEvent>& data_events) {
|
|
819
|
-
auto it = connections_.find(socket);
|
|
820
|
-
if (it == connections_.end()) return false;
|
|
821
|
-
|
|
822
|
-
SocketContext& ctx = it->second;
|
|
823
|
-
|
|
824
|
-
// Connection object should always exist now (created in accept_incoming or connect_peer)
|
|
825
|
-
if (!ctx.connection) {
|
|
826
|
-
LOG_NET_ERROR("handle_readable: no connection object for socket");
|
|
827
|
-
return true; // Should close
|
|
828
|
-
}
|
|
829
|
-
|
|
830
|
-
// Drain all available data from the kernel buffer (loop until EWOULDBLOCK)
|
|
831
|
-
auto& recv_buf = ctx.connection->recv_buffer();
|
|
832
|
-
bool got_data = false;
|
|
833
|
-
|
|
834
|
-
while (true) {
|
|
835
|
-
const size_t recv_size = 16384;
|
|
836
|
-
recv_buf.ensure_space(recv_size);
|
|
837
|
-
|
|
838
|
-
int bytes = recv(socket, reinterpret_cast<char*>(recv_buf.write_ptr()),
|
|
839
|
-
static_cast<int>(recv_buf.write_space()), 0);
|
|
840
|
-
|
|
841
|
-
if (bytes > 0) {
|
|
842
|
-
recv_buf.received(bytes);
|
|
843
|
-
got_data = true;
|
|
844
|
-
|
|
845
|
-
LOG_NET_DEBUG("handle_readable: recv " + std::to_string(bytes) +
|
|
846
|
-
" bytes from " + ctx.connection->ip());
|
|
847
|
-
continue; // Try to read more
|
|
848
|
-
}
|
|
849
|
-
|
|
850
|
-
if (bytes == 0) {
|
|
851
|
-
// Peer closed connection gracefully
|
|
852
|
-
LOG_NET_DEBUG("Connection closed by peer: " + ctx.connection->ip());
|
|
853
|
-
return true; // Should close
|
|
854
|
-
}
|
|
855
|
-
|
|
856
|
-
// bytes < 0: error
|
|
857
|
-
#ifdef _WIN32
|
|
858
|
-
int err = WSAGetLastError();
|
|
859
|
-
if (err == WSAEWOULDBLOCK) {
|
|
860
|
-
break; // No more data available, exit recv loop
|
|
861
|
-
}
|
|
862
|
-
LOG_NET_DEBUG("Receive error: " + std::to_string(err));
|
|
863
|
-
#else
|
|
864
|
-
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
|
865
|
-
break; // No more data available, exit recv loop
|
|
866
|
-
}
|
|
867
|
-
LOG_NET_DEBUG("Receive error: " + std::string(strerror(errno)));
|
|
868
|
-
#endif
|
|
869
|
-
return true; // Should close on real errors
|
|
870
|
-
}
|
|
871
|
-
|
|
872
|
-
if (!got_data) {
|
|
873
|
-
return false; // Nothing received, no processing needed
|
|
874
|
-
}
|
|
875
|
-
|
|
876
|
-
ctx.last_activity = std::chrono::steady_clock::now();
|
|
877
|
-
|
|
878
|
-
// Process all received data (handshake and messages)
|
|
879
|
-
return handle_peer_data(ctx, connected_events, data_events);
|
|
880
|
-
}
|
|
881
|
-
|
|
882
|
-
bool BtNetworkManager::handle_writable(socket_t socket) {
|
|
883
|
-
auto it = connections_.find(socket);
|
|
884
|
-
if (it == connections_.end()) return false;
|
|
885
|
-
|
|
886
|
-
return flush_send_buffer(it->second);
|
|
887
|
-
}
|
|
888
|
-
|
|
889
|
-
bool BtNetworkManager::handle_peer_data(SocketContext& ctx,
|
|
890
|
-
std::vector<ConnectedEvent>& connected_events,
|
|
891
|
-
std::vector<DataEvent>& data_events) {
|
|
892
|
-
if (!ctx.connection) return false;
|
|
893
|
-
|
|
894
|
-
// Process incoming data (handshake and messages)
|
|
895
|
-
// Data is already in connection's recv_buffer - no copy needed!
|
|
896
|
-
ctx.connection->process_incoming();
|
|
897
|
-
|
|
898
|
-
// Check if connection was closed during processing (e.g., unknown torrent, invalid handshake)
|
|
899
|
-
auto conn_state = ctx.connection->state();
|
|
900
|
-
if (conn_state == PeerConnectionState::Disconnected ||
|
|
901
|
-
conn_state == PeerConnectionState::Closing) {
|
|
902
|
-
LOG_NET_DEBUG("Connection closed during processing for " + ctx.connection->ip());
|
|
903
|
-
return true; // Should close
|
|
904
|
-
}
|
|
905
|
-
|
|
906
|
-
if (ctx.state == NetConnectionState::Handshaking) {
|
|
907
|
-
// Check if handshake complete
|
|
908
|
-
if (ctx.connection->is_connected()) {
|
|
909
|
-
ctx.state = NetConnectionState::Connected;
|
|
910
|
-
|
|
911
|
-
LOG_NET_DEBUG("Handshake complete with " + ctx.connection->ip() +
|
|
912
|
-
", queueing callback");
|
|
913
|
-
|
|
914
|
-
// Queue connected event (callback will be invoked outside mutex)
|
|
915
|
-
ConnectedEvent event;
|
|
916
|
-
event.info_hash = ctx.info_hash;
|
|
917
|
-
event.connection = ctx.connection;
|
|
918
|
-
event.socket = ctx.socket;
|
|
919
|
-
event.incoming = ctx.incoming;
|
|
920
|
-
connected_events.push_back(std::move(event));
|
|
921
|
-
}
|
|
922
|
-
} else if (ctx.state == NetConnectionState::Connected) {
|
|
923
|
-
// Queue data event (callback will be invoked outside mutex)
|
|
924
|
-
DataEvent event;
|
|
925
|
-
event.info_hash = ctx.info_hash;
|
|
926
|
-
event.connection = ctx.connection;
|
|
927
|
-
event.socket = ctx.socket;
|
|
928
|
-
data_events.push_back(std::move(event));
|
|
929
|
-
}
|
|
930
|
-
|
|
931
|
-
// Note: send data is already in connection->send_buffer()
|
|
932
|
-
// flush_send_buffer() will send it directly - no copy needed!
|
|
933
|
-
return false; // Don't close
|
|
934
|
-
}
|
|
935
|
-
|
|
936
|
-
bool BtNetworkManager::flush_send_buffer(SocketContext& ctx) {
|
|
937
|
-
if (!ctx.connection) return false;
|
|
938
|
-
|
|
939
|
-
auto& send_buf = ctx.connection->send_buffer();
|
|
940
|
-
if (send_buf.empty()) return false;
|
|
941
|
-
|
|
942
|
-
// Send directly from connection's buffer - NO COPY!
|
|
943
|
-
const uint8_t* data = send_buf.front_data();
|
|
944
|
-
size_t to_send = send_buf.front_size();
|
|
945
|
-
|
|
946
|
-
if (to_send == 0 || data == nullptr) return false;
|
|
947
|
-
|
|
948
|
-
LOG_NET_DEBUG("flush_send_buffer: sending " + std::to_string(to_send) +
|
|
949
|
-
" bytes to " + ctx.connection->ip());
|
|
950
|
-
|
|
951
|
-
int sent = send(ctx.socket, reinterpret_cast<const char*>(data),
|
|
952
|
-
static_cast<int>(to_send), 0);
|
|
953
|
-
|
|
954
|
-
if (sent > 0) {
|
|
955
|
-
send_buf.pop_front(static_cast<size_t>(sent));
|
|
956
|
-
ctx.last_activity = std::chrono::steady_clock::now();
|
|
957
|
-
|
|
958
|
-
// If send buffer is now empty, remove PollOut interest to avoid busy-looping
|
|
959
|
-
if (send_buf.empty()) {
|
|
960
|
-
uint32_t desired = PollIn;
|
|
961
|
-
auto ps = poller_state_.find(ctx.socket);
|
|
962
|
-
if (ps != poller_state_.end() && ps->second != desired) {
|
|
963
|
-
poller_->modify(ctx.socket, desired);
|
|
964
|
-
ps->second = desired;
|
|
965
|
-
}
|
|
966
|
-
}
|
|
967
|
-
} else if (sent < 0) {
|
|
968
|
-
#ifdef _WIN32
|
|
969
|
-
int err = WSAGetLastError();
|
|
970
|
-
if (err != WSAEWOULDBLOCK) {
|
|
971
|
-
LOG_NET_DEBUG("Send error: " + std::to_string(err));
|
|
972
|
-
return true; // Should close
|
|
973
|
-
}
|
|
974
|
-
#else
|
|
975
|
-
if (errno != EAGAIN && errno != EWOULDBLOCK) {
|
|
976
|
-
LOG_NET_DEBUG("Send error: " + std::string(strerror(errno)));
|
|
977
|
-
return true; // Should close
|
|
978
|
-
}
|
|
979
|
-
#endif
|
|
980
|
-
}
|
|
981
|
-
return false; // Don't close
|
|
982
|
-
}
|
|
983
|
-
|
|
984
|
-
void BtNetworkManager::close_connection_internal(socket_t socket,
|
|
985
|
-
std::vector<DisconnectedEvent>& disconnected_events) {
|
|
986
|
-
auto it = connections_.find(socket);
|
|
987
|
-
if (it == connections_.end()) return;
|
|
988
|
-
|
|
989
|
-
SocketContext& ctx = it->second;
|
|
990
|
-
|
|
991
|
-
// Queue disconnected event (callback will be invoked outside mutex)
|
|
992
|
-
if (ctx.connection) {
|
|
993
|
-
DisconnectedEvent event;
|
|
994
|
-
event.info_hash = ctx.info_hash;
|
|
995
|
-
event.connection = ctx.connection;
|
|
996
|
-
disconnected_events.push_back(std::move(event));
|
|
997
|
-
}
|
|
998
|
-
|
|
999
|
-
// Remove from poller before closing socket
|
|
1000
|
-
poller_->remove(socket);
|
|
1001
|
-
poller_state_.erase(socket);
|
|
1002
|
-
|
|
1003
|
-
close_socket(socket, true);
|
|
1004
|
-
connections_.erase(it);
|
|
1005
|
-
}
|
|
1006
|
-
|
|
1007
|
-
} // namespace librats
|