You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
net raw-upgrade adoption: failed adoption still emits 'upgrade' with an undefined socket; adoption is not routed to the owning agent #11155
Two defects in the raw-upgrade socket adoption that #11105 added. It is on main since merge train 266 (784ed8e). CodeRabbit raised both on #11130 against the pre-rebase diff; that PR does not touch these files. I checked both claims against the code on main. I did not build a JS repro: neither path is reachable from JS on a single-agent host with a working loop. The first needs adoption to fail, and the second needs an HTTP upgrade on a worker agent.
1. A failed adoption still emits 'upgrade', with an undefined socket
adopt_upgraded_tcp_stream (crates/perry-ext-net/src/adopt.rs) returns INVALID_HANDLE when post_to_owner refuses the job (no loop for the agent), and into_std() can also fail. Either way the client still gets an 'upgrade' event and the request reports success. handle_upgrade_event turns handle 0 into undefined, so req.on('upgrade', (res, socket, head) => …) receives socket === undefined and no 'error'. Node would emit 'error' on the request.
Suggested fix: check for INVALID_HANDLE right after adoption and return Some(Err(...)) so the request errors. The server-side path (server/raw_upgrade.rs) should be checked for the same shape.
2. Adoption is not routed to the owning agent
adopt_upgraded_tcp_stream runs on a tokio worker and calls turnloop_io::post_to_owner, which calls perry_ffi::agent_post::post_job with no agent id.
The runtime resolves the target with agent::current_agent(), which is CURRENT_AGENT.unwrap_or(PRIMARY_AGENT). A tokio worker has no CURRENT_AGENT.
So an upgrade on an HTTP server or client owned by a worker agent is posted to the primary agent's loop.
pending_adoptions() is a process-wide map keyed only by socket id, and ensure_adopted_socket_dispatch drains every parked id on whichever loop calls it. One agent can therefore adopt another agent's stream.
The result would be a net.Socket whose events are delivered on the wrong agent's thread and heap.
Suggested fix: capture the owning AgentId where the HTTP transport task is spawned and store it with the parked stream. Then post to that agent explicitly, and have ensure_adopted_socket_dispatch drain only its own agent's entries.
Not verified by execution. Both findings come from reading main at 784ed8e.
Activity
net: adopt upgraded streams on the caller's own loop, never another a…
net: adopt upgraded streams on the caller's own loop, never another a…