armanbilge/epollcat

`EADDRINUSE` when binding a new server at address of previous, closed server

Closed this issue · 1 comments

The following test opens a server, binds it to a local address/port, connects a client, accepts that connection ... and then closes all of those sockets.

Then, it attempts to open a new server at the same address, and it gets java.net.BindException: Address already in use aka EADDRINUSE. This error only happens on Native. The JVM version is able to bind successfully.

test("closing/re-opening a server does not throw BindException: Address already in use") {
val address = new InetSocketAddress("127.0.0.0", 8080)
IOServerSocketChannel.open.evalTap(_.bind(address)).use { server =>
val connect =
IOSocketChannel.open.evalTap(_.connect(address)).surround(IO.sleep(1.second))
val accept = server.accept.surround(IO.sleep(1.second))
connect.both(accept).void
} *> IOServerSocketChannel.open.evalTap(_.bind(address)).use_
}

Hmm 😅

Javadoc for SO_REUSEADDR says:

The default value of this socket option is system dependent.

https://docs.oracle.com/javase/8/docs/api/java/net/StandardSocketOptions.html#SO_REUSEADDR

On Ubuntu I get:

Welcome to Scala 3.1.3 (17.0.4, Java OpenJDK 64-Bit Server VM).
Type in expressions for evaluation. Or try :help.
                                                                                                          
scala> java.nio.channels.AsynchronousServerSocketChannel.open().getOption(java.net.StandardSocketOptions.SO_REUSEADDR)
val res0: Boolean = true

On macOS I get:

Welcome to Scala 3.2.1 (17.0.5, Java OpenJDK 64-Bit Server VM).
Type in expressions for evaluation. Or try :help.

scala> java.nio.channels.AsynchronousServerSocketChannel.open().getOption(java.net.StandardSocketOptions.SO_REUSEADDR)
val res0: Boolean = true

So I think we found our answer 🤔