Closed sant123 closed 1 year ago
I attempted to run your snippet both in macOS and in Ubuntu, and I saw it throwing an error as expected in both environments.
$ deno --version
deno 1.29.2 (release, x86_64-unknown-linux-gnu)
v8 10.9.194.5
typescript 4.9.4
$ deno run --allow-net port.ts
{ hostname: "0.0.0.0", port: 4505, transport: "tcp" }
error: Uncaught AddrInUse: Address already in use (os error 98)
const listener2 = Deno.listen({
^
at Object.listen (deno:ext/net/01_net.js:333:33)
at file:///tmp/port.ts:9:24
$ deno --version
deno 1.29.2 (release, aarch64-apple-darwin)
v8 10.9.194.5
typescript 4.9.4
$ deno run --allow-net port.ts
{ hostname: "0.0.0.0", port: 4505, transport: "tcp" }
error: Uncaught AddrInUse: Address already in use (os error 48)
const listener2 = Deno.listen({
^
at Object.listen (deno:ext/net/01_net.js:333:33)
at file:///private/tmp/port.ts:9:24
Interesting, I'm currently using a Fedora 36 machine. Also have the same Deno version as you mentioned earlier.
My hunch is that Fedoras implementation of TCP differs with how SO_REUSEADDR
and SO_REUSEPORT
behaves - https://man7.org/linux/man-pages/man7/socket.7.html
@sant123 you can try to play around with https://github.com/denoland/deno/blob/a6b3910bdfe0183e458015d00a61295779e46eb1/ext/net/ops.rs#L248-L292 locally and see what socket2
and std::net::TcpListener
implementation tell you.
Hey @kamilogorek don't exactly know how to play around with the code above 😅 perhaps could you check the behavior in a Docker container with Fedora please?
I have tested the original snippet using the fedora 36 container, and confirmed that it failed with AddrInUse as expected.
[root@cd48c6b3b08d tmp]# cat /etc/fedora-release
Fedora release 36 (Thirty Six)
[root@cd48c6b3b08d tmp]# cat port.ts
const listener1 = Deno.listen({
port: 4505,
hostname: "0.0.0.0",
transport: "tcp",
});
console.log(listener1.addr);
const listener2 = Deno.listen({
port: 4505,
hostname: "0.0.0.0",
transport: "tcp",
});
console.log(listener2.addr);
[root@cd48c6b3b08d tmp]# deno --version
deno 1.29.3 (release, x86_64-unknown-linux-gnu)
v8 10.9.194.5
typescript 4.9.4
[root@cd48c6b3b08d tmp]# deno run --allow-net port.ts
{ hostname: "0.0.0.0", port: 4505, transport: "tcp" }
error: Uncaught AddrInUse: Address already in use (os error 98)
const listener2 = Deno.listen({
^
at Object.listen (deno:ext/net/01_net.js:333:33)
at file:///tmp/port.ts:9:24
@sant123 I'm wondering what happens if you try to run your code within the container. I would like to check if the issue is because of your OS setup or other. Also, could you run the following python one in your environment? This is to check if the issue happens only with Deno or not.
import socket
sock1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock1.bind(('0.0.0.0', 4505))
sock1.listen(5)
print('sock1 starts listening')
sock2 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock2.bind(('0.0.0.0', 4505))
sock2.listen(5)
print('sock2 starts listening')
In my environment (e.g. macOS, Ubuntu, and Fedora 36 in docker), I got AddrInUse from this python script, which looks like:
[root@cd48c6b3b08d tmp]# python3 --version
Python 3.10.8
[root@cd48c6b3b08d tmp]# python3 port.py
sock1 starts listening
Traceback (most recent call last):
File "/tmp/port.py", line 10, in <module>
sock2.bind(('0.0.0.0', 4505))
OSError: [Errno 98] Address already in use
Oh, actually, the python script I would like you to try is:
import socket
sock1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock1.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock1.bind(('0.0.0.0', 4505))
sock1.listen(5)
print('sock1 starts listening')
sock2 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock2.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock2.bind(('0.0.0.0', 4505))
sock2.listen(5)
print('sock2 starts listening')
This behaves in really similar way to what Deno does internally.
I got the same behavior as in Deno:
😳
And this is from a Fedora 36 container:
docker run -it fedora:36 /bin/bash
Perhaps the tests should be done in a Fedora installation? Because kernel versions in these distros are the most recent ones and since Docker uses the current kernel installed it causes that tests in Fedora containers to mismatch the expected result.
I gave it another try to run Fedora with vagrant (i.e. virtualbox) instead of docker, and got AddrInUse again. What you are seeing is really weird...
I gave it another try to run Fedora with vagrant (i.e. virtualbox) instead of docker, and got AddrInUse again.
What you are seeing is really weird...
I'm curious did you try with Fedora 36 or the latest version? (Currently 37).
I was using this one (Fedora 36) https://app.vagrantup.com/fedora/boxes/36-cloud-base
What is the Kernel of that VM? Mine is 6.0.18-200.fc36.x86_64
Just updated the Kernel of my machine and now everything works as expected. New version is 6.1.5-100.fc36.x86_64
.
That's a nice discovery @sant123. The kernel version I tried was 5.17.5-300.fc36.x86_64
.
I discovered that there is a regression report for Linux kernel which can be found at: https://lore.kernel.org/netdev/CAFsF8vJ3wS-Yoy9tNZD2ZESevGenvYKqieD4F8+UztRsrJ=png@mail.gmail.com/T/
According to this, 6.0.16 to 6.0.18 suffers from this problem, so it's most likely that you ran into this kernel regression.
I'm going to close this issue since it's turned out that this is actually not a issue with Deno. If you have another question or something, feel free to ask :)
Expected behavior
The code should throw according with docs.
Current behavior
The constant
listener2
will have assigned a random port.Also this test is hanging because of this https://github.com/denoland/deno_std/blob/main/http/server_test.ts#L1280