-
Notifications
You must be signed in to change notification settings - Fork 3
fix: force TCP binding to send the data immediately #23
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
Thanks @Angelmmiguel 😃 happy to merge this. I just finished adding CI tests to the repo - would you mind merging/rebasing on the latest Also, not a blocker to merge this, but if we can somehow reproduce the previous delayed behaviour in a test to prove that this fixes it, that would be excellent. |
Sure! I will rebase the changes.
Let me try to create a test for this behavior 👍 |
77e648c to
eca4f22
Compare
|
@gregnr I added a test to reproduce the issue. If you can enable the workflow, I will uncomment the solution in a separate commit to confirm it fixes the delay. Thanks! |
|
@Angelmmiguel nice, looks like they're failing without the fix 🔥 Feel free to uncomment! |
Amazing! I've just applied the fix again 😄 |
|
Interesting, it seems Let me increase the threshold for testing on the CI. |
|
It worked! 😄 |
|
The fact that they were all around 100ms makes me suspicious that this time is limited by our lwIP interval: tcpip.js/packages/tcpip/src/stack.ts Lines 191 to 194 in b82738b
This actually makes sense, since I see you are using the default loopback interface in that test for the TCP connection. For context, lwIP will queue loopback packets instead of invoking their callback immediately due to reentrancy issues. They require you to regularly process these queued packets which we do above via To make this test more accurate though, we can use a tun interface instead and send the packets between 2 stacks: test('tcp packets are sent immediately without delay', async () => {
const stack1 = await createStack();
const stack2 = await createStack();
const tun1 = await stack1.createTunInterface({
ip: '192.168.1.1/24',
});
const tun2 = await stack2.createTunInterface({
ip: '192.168.1.2/24',
});
// Connect the two interfaces
tun1.readable.pipeTo(tun2.writable);
tun2.readable.pipeTo(tun1.writable);
const listener = await stack2.listenTcp({
port: 8080,
});
const [outbound, inbound] = await Promise.all([
stack1.connectTcp({
host: '192.168.1.2',
port: 8080,
}),
nextValue(listener),
]);
const data = new Uint8Array([0x01, 0x02, 0x03, 0x04]);
const inboundReader = inbound.readable.getReader();
const outboundWriter = outbound.writable.getWriter();
// Record start time
const startTime = performance.now();
// Write and read immediately
await outboundWriter.write(data);
const received = await inboundReader.read();
// Record end time
const endTime = performance.now();
expect(received.value).toStrictEqual(data);
// Check timing - with tcp_output enabled, this should be very fast
// Without tcp_output, there would be a significant delay (~300ms)
const elapsed = endTime - startTime;
expect(elapsed).toBeCloseTo(0, -1);
});This should avoid the need to wait on the interval since tun interfaces don't queue packets. |
This is quite interesting, thank you for the context. Maybe it could be a configuration parameter for the
That makes perfect sense. I updated the tests and confirmed they fail without the change I introduced: |
|
Thanks again for this @Angelmmiguel + including a test. Great work! This is now released on v0.3.3. |
Amazing!! Thank you for the fast review and release 😄 |
Force the
send_tcp_chunkmethod to send the data immediately. It avoids waiting for some timeouts when packets are small.Refs #6