fix(client): survive the review findings on the thread-flood fix
Review of the capacity work surfaced three real defects and two gaps: - A peer dribbling bytes re-armed the 10s handshake read timeout on every read and held its accept permit forever; 128 such sockets wedged the accept loop for good. The handshake now has one deadline across all reads, plus a 4 KiB cap on buffered handshake bytes. - A capacity refusal was logged and swallowed, leaving the refused peer's queued downloads stuck until the caller's own timeout. Both registration paths now fail those downloads so the caller gets a verdict, and the listener only announces PeerConnected when the registration actually happened. - The transfer-claim was undone by the worker thread writing Queued back over it; that write is gone, so a replayed TransferResponse can no longer start a second writer on the same .part file. - Offered uploads and queue waiters joined the eviction-protected set, and the browse protection window matches the minutes a real share listing takes rather than one. Regression tests: the broker-timeout sweep failing a queued download end to end, the replay guard observed over a real socket, and the handshake deadline against a dribbling and an oversized peer.
This commit is contained in:
@@ -214,28 +214,36 @@ impl Client {
|
||||
ConnectionType::P => {
|
||||
let username = peer.username;
|
||||
|
||||
let context = match client_context.read_safe() {
|
||||
Ok(c) => c,
|
||||
Err(e) => {
|
||||
error!("[client] connect_to_peer read: {}", e);
|
||||
return;
|
||||
let refused = {
|
||||
let context = match client_context.read_safe() {
|
||||
Ok(c) => c,
|
||||
Err(e) => {
|
||||
error!("[client] connect_to_peer read: {}", e);
|
||||
return;
|
||||
}
|
||||
};
|
||||
if let Some(ref registry) = context.peer_registry {
|
||||
let protected = context.protected_peers();
|
||||
match registry.register_peer_protected(
|
||||
peer_clone, stream, None, &protected,
|
||||
) {
|
||||
Ok(_) => false,
|
||||
Err(e) => {
|
||||
warn!(
|
||||
"[client] refusing peer connection for \
|
||||
{:?}: {:?}",
|
||||
username, e
|
||||
);
|
||||
true
|
||||
}
|
||||
}
|
||||
} else {
|
||||
trace!("PeerRegistry not initialized");
|
||||
false
|
||||
}
|
||||
};
|
||||
if let Some(ref registry) = context.peer_registry {
|
||||
let protected = context.protected_peers();
|
||||
match registry.register_peer_protected(
|
||||
peer_clone, stream, None, &protected,
|
||||
) {
|
||||
Ok(_) => (),
|
||||
Err(e) => {
|
||||
trace!(
|
||||
"Failed to spawn peer actor for {:?}: {:?}",
|
||||
username, e
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
trace!("PeerRegistry not initialized");
|
||||
if refused {
|
||||
Self::fail_queued_downloads(&client_context, &username);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user