Skip to content

Fix relay loop to track closed states independently for left and righ… - #41342

Open
Eamon (Eamon2009) wants to merge 12 commits into
microsoft:masterfrom
Eamon2009:patch-4
Open

Eamon (Eamon2009) wants to merge 12 commits into
microsoft:masterfrom
Eamon2009:patch-4

Conversation

@Eamon2009

@Eamon2009 Eamon (Eamon2009) commented Aug 13, 2026 •

Copy link
Copy Markdown
Contributor

Summary of the Pull Request

Fix relay loop to track closed states independently for left and right handles. Previously, the loop could exit or misbehave if only one handle was null. This update introduces leftReadClosed and rightReadClosed boolean flags to properly manage half-closed connections. The relay loop now correctly continues reading from an open handle and only breaks when both the left and right reads are fully closed.

PR Checklist

  • Closes: Link to issue #xxx
  • Communication: I've discussed this with core contributors already. If work hasn't been agreed, this work might be rejected
  • Tests: Added/updated if needed and all pass
  • Localization: All end user facing strings can be localized
  • Dev docs: Added/updated if needed
  • Documentation updated: If checked, please file a pull request on our docs repo and link it here: #xxx

Detailed Description of the Pull Request / Additional comments

Independent close tracking

The previous relay loop did not distinguish between the left and right handles when detecting read-side closures. If one side closed its write direction (half-close) or its read handle became null, the loop would either exit prematurely or behave unpredictably, dropping data that was still buffered on the open side.

This change introduces two explicit boolean flags -leftReadClosed and rightReadClosed -that are set independently when POLLHUP/POLLERR is detected on each respective handle or when the handle becomes null. This allows the loop to continue relaying data in the direction that is still open.

Break condition

The exit condition is now gated on both flags being true:

if (leftReadClosed && rightReadClosed)
{
    break;
}

This ensures the relay thread stays alive until both directions have been fully drained, preventing data loss during half-closed or asynchronous teardown scenarios.

Validation Steps Performed

…y half-close and ioctl interface name handling

Change || to && in relay loop so both directions drain before exit Null-terminate interface name after memcpy from ifreq
This commit updates the localhost.cpp file by adding new functionality for monitoring TCP sockets, managing relays, and handling socket communication. It also includes error handling improvements and updates to the port tracking mechanism.
Copilot AI lite review requested due to automatic review settings August 13, 2026 10:12
@Eamon2009
Eamon (Eamon2009) requested a review from a team as a code owner August 13, 2026 10:12
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
There may be pipelines that require an authorized user to comment /azp run to run.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the Windows relay implementation to correctly support half-closed bidirectional connections by tracking each side’s read-closure independently, avoiding premature loop termination when only one direction has closed.

Changes:

  • Introduces leftReadClosed / rightReadClosed to track EOF/closure per side independently of handle nullness.
  • Updates the relay loop termination condition to exit only when both read directions are closed.
  • Stops nulling LeftHandle/RightHandle on EOF and instead marks the corresponding read side closed, preserving the ability to continue relaying data in the opposite direction.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@Eamon2009
Eamon (Eamon2009) marked this pull request as ready for review August 13, 2026 10:16
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
There may be pipelines that require an authorized user to comment /azp run to run.

@Eamon2009
Eamon (Eamon2009) marked this pull request as draft August 13, 2026 10:26
@Eamon2009
Eamon (Eamon2009) marked this pull request as ready for review August 13, 2026 10:32
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
There may be pipelines that require an authorized user to comment /azp run to run.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated no new comments.

Suppressed comments (1)

src/windows/common/relay.cpp:321

  • Please add a regression test for this new half-close exit condition. No test currently invokes BidirectionalRelay; a socket-pair test should close one peer's send direction, verify buffered traffic still relays in the opposite direction, then close the second direction and verify the relay thread exits. Without that coverage, the original premature-exit/hang behavior can be reintroduced unnoticed.
        if (leftReadClosed && rightReadClosed)

Copilot AI review requested due to automatic review settings August 14, 2026 16:24

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.

Suppressed comments (1)

src/linux/init/localhost.cpp:327

  • The disconnect regression is not covered. The existing NatLocalhostRelay test only verifies a normal host-to-guest transfer (test/windows/NetworkTests.cpp:2578) and never half-closes a peer or checks that the relay terminates without spinning. Add a regression case that triggers POLLHUP/one-sided EOF, verifies buffered traffic in the opposite direction is preserved, and confirms the worker exits after both reads close.
                        if (pollDescriptors[Index].revents & (POLLIN | POLLERR | POLLHUP))

@Eamon2009
Eamon (Eamon2009) marked this pull request as draft August 14, 2026 16:27
Copilot AI review requested due to automatic review settings August 14, 2026 16:55

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.

Suppressed comments (1)

src/linux/init/localhost.cpp:317

  • Add a regression test that half-closes one relay endpoint, verifies buffered/reverse-direction data still flows, and confirms the worker exits after the second endpoint closes. The existing ValidateLocalhostRelayTraffic test only checks a single host-to-guest transfer and does not exercise the disconnect path fixed here, so both the hang and early-exit behaviors can regress unnoticed.
                    if ((pollDescriptors[0].fd == -1) && (pollDescriptors[1].fd == -1))

@Eamon2009
Eamon (Eamon2009) marked this pull request as ready for review August 14, 2026 17:05
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
There may be pipelines that require an authorized user to comment /azp run to run.

auto& ifRequest = *reinterpret_cast<ifreq*>(ifreqMemory->data());
memcpy(request.InterfaceName, ifRequest.ifr_ifrn.ifrn_name, sizeof(request.InterfaceName));
memcpy(request.InterfaceName, ifRequest.ifr_ifrn.ifrn_name, sizeof(request.InterfaceName) - 1);
request.InterfaceName[sizeof(request.InterfaceName) - 1] = '\0';

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: This can be skipped now that we never write the last byte

@OneBlue

Copy link
Copy Markdown
Collaborator

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The half-close behavior needs regression coverage for reverse traffic and final relay termination.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details
  • Files reviewed: 2/2 changed files
  • Comments generated: 1
  • Review effort level: Balanced

Comment thread src/linux/init/localhost.cpp Resolved

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🔵 Needs a closer look

The new half-close behavior needs regression coverage for continued reverse-direction traffic and final termination.

Review effort: Balanced
Findings: None

Resolved since last review (1)

@OneBlue

Copy link
Copy Markdown
Collaborator

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants