Reap dead outbound connection slots; strike disconnected peers from discovery. Two related connection-lifecycle fixes on top of the SIGPIPE fix.
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.
This commit is contained in:
@@ -31,6 +31,7 @@ int TcpConnection_Init(tcp_connection_t* conn, int sockFd, const struct sockaddr
|
||||
|
||||
conn->closing = false;
|
||||
conn->disconnectedNotified = false;
|
||||
atomic_init(&conn->pinCount, 0);
|
||||
conn->dataBuf = NULL;
|
||||
conn->dataBufLen = 0;
|
||||
conn->dataBufCap = 0;
|
||||
@@ -262,6 +263,20 @@ bool TcpConnection_IsDisconnectNotified(tcp_connection_t* conn) {
|
||||
return notified;
|
||||
}
|
||||
|
||||
void TcpConnection_Pin(tcp_connection_t* conn) {
|
||||
if (!conn) {
|
||||
return;
|
||||
}
|
||||
atomic_fetch_add(&conn->pinCount, 1);
|
||||
}
|
||||
|
||||
void TcpConnection_Unpin(tcp_connection_t* conn) {
|
||||
if (!conn) {
|
||||
return;
|
||||
}
|
||||
atomic_fetch_sub(&conn->pinCount, 1);
|
||||
}
|
||||
|
||||
static int extract_v4(const tcp_connection_t* conn, struct in_addr* v4out) {
|
||||
if (conn->addrFamily == AF_INET6) {
|
||||
const struct sockaddr_in6* a6 = (const struct sockaddr_in6*)&conn->peerAddr;
|
||||
|
||||
Reference in New Issue
Block a user