Reclaim outbound slots on peer disconnect: - TcpClient_ThreadProc fired on_disconnect but never cleared the outbound slot, closed the fd, joined the io thread, or freed the connection, so a dead peer permanently held its outboundClients[] slot. After MAX_CONS (32) churned connections the node could make no new outbound connections, and leaked fds/threads/memory. (The inbound side already self-reclaimed.) - Add a reaper (Node_ReapDeadOutbound) on the maintenance thread: under outboundLock it detaches dead (disconnect-notified) slots, then joins the io thread and destroys/frees each connection outside the lock. - Guard against use-after-free with a pin count on tcp_connection_t (TcpConnection_Pin/Unpin). The only cross-thread consumer holding a raw connection pointer across a blocking op is the `sync` command (via Node_GetBestOutboundPeer); it now pins the peer and unpins when done, and the reaper skips pinned connections. Discovery's snapshots run on the reaper's own thread, so they need no pin. - Node_GetBestOutboundPeer/GetClientList/GetPeerEndpoints skip disconnect-notified connections so a dead peer is never handed out. - Node_Destroy stops+joins the maintenance thread before tearing down outbound clients, so the reaper can't race shutdown. Strike disconnected peers from the discovery peer list: - Add NodeDiscovery_RemovePeer + Node_HandlePeerDisconnect: on disconnect, remove the peer from the known-peer table once no live connection (inbound or outbound) to its listen endpoint remains (Node_HasLiveConnectionTo; disconnect-notified conns don't count, so both directions dropping at once is handled). Wired into Node_Server_OnDisconnect and Node_Client_OnDisconnect.
34 lines
1.8 KiB
C
34 lines
1.8 KiB
C
#ifndef NODEDISCOVERY_H
|
|
#define NODEDISCOVERY_H
|
|
|
|
#include <nets/net_node.h>
|
|
#include <udpd/udpnode.h>
|
|
|
|
// Create/destroy the peer-discovery state. Owns the known-peer table and its lock.
|
|
node_discovery_t* NodeDiscovery_Create(net_node_t* node, udp_node_t* udpNode);
|
|
void NodeDiscovery_Destroy(node_discovery_t* disc);
|
|
|
|
// Periodic tick (driven by the node maintenance thread): seed currently-connected peers,
|
|
// UDP-ping newly-learned ones, query a couple of connected peers for more, and connect to
|
|
// the reachable peers with the lowest ping until we reach the target connection count.
|
|
void NodeDiscovery_Iterate(node_discovery_t* disc);
|
|
|
|
// UDP latency callbacks (forwarded from the udp node via net_node thunks).
|
|
void NodeDiscovery_OnPong(node_discovery_t* disc, const struct sockaddr_storage* from, uint64_t nonce, uint64_t rttMs);
|
|
void NodeDiscovery_OnPingTimeout(node_discovery_t* disc, const struct sockaddr_storage* dest, uint64_t nonce);
|
|
|
|
// TCP peer-exchange handlers (called from the net_node packet dispatch).
|
|
// Build a PEERS response (a sample of our peers, excluding the requester) and send it over fromConn.
|
|
void NodeDiscovery_OnGetPeers(node_discovery_t* disc, tcp_connection_t* fromConn);
|
|
// Decode a received PEERS payload and fold a couple of its endpoints into the known-peer table.
|
|
void NodeDiscovery_OnPeersReceived(node_discovery_t* disc, tcp_connection_t* fromConn, const unsigned char* payload, size_t payloadLen);
|
|
|
|
// Strike a peer (by its listen endpoint) from the known-peer table. Called when a peer becomes
|
|
// logically disconnected (no remaining connection to it).
|
|
void NodeDiscovery_RemovePeer(node_discovery_t* disc, const struct sockaddr_storage* endpoint);
|
|
|
|
// Dump the known-peer table to stdout (for the CLI `peers` command).
|
|
void NodeDiscovery_PrintPeers(node_discovery_t* disc);
|
|
|
|
#endif
|