I'm trying to understand the details of SO_REUSEADDR behaviour. I think I've found some inconsistencies in how bind conflicts are handled. In particular, TCP and UDP behaviour seems to differ.
Let’s start with simplest TCP cases. Case 1: * Socket A: bound to 0.0.0.0 tcp/1234; SO_REUSEADDR absent * Socket B: bound to 127.0.0.1 tcp/1234; SO_REUSEADDR present (doesn't matter if both servers belong to the same uid or not) Result: bind() fails with EADDRINUSE This seems desired. Ok. Case 2: What if both sockets have SO_REUSEADDR? * Socket A: bound to 0.0.0.0 tcp/1234; SO_REUSEADDR present * Socket B: bound to 127.0.0.1 tcp/1234; SO_REUSEADDR present Result: bind() fails with EADDRINUSE This seems somewhat confusing. I would expect this one to work, unless I’m mistaken in my reading of the socket(7) man page: SO_REUSEADDR Indicates that the rules used in validating addresses supplied in a bind(2) call should allow reuse of local addresses. For AF_INET sockets this means that a socket may bind, except when there is an active listening socket bound to the address. When the listening socket is bound to INADDR_ANY with a specific port then it is not possible to bind to this port for any local address. does "except when there is an active listening socket bound to the address" cover also the case when a socket is bound to 0.0.0.0 and another one is bound to 127.0.0.1? More questions arise if we repeat the same experiment with UDP sockets. Case 3: * Socket A: bound to 0.0.0.0 udp/1234; SO_REUSEADDR absent * Socket B: bound 127.0.0.1 udp/1234; SO_REUSEADDR present Result: bind() fails with EADDRINUSE Case 4: * Socket A: 0.0.0.0 udp/1234; SO_REUSEADDR present * Socket B: 127.0.0.1 udp/1234; SO_REUSEADDR present Result: bind() succeeds! In practice this leads to a situation where: * the INADDR_ANY server receives all the datagrams for for port 1234 except the ones directed to 127.0.0.1 * the INADDR_LOOPBACK server receives all the datagrams for 127.0.0.1 why is UDP behaviour different from TCP? Another confusing case: case 5: * Socket A: 0.0.0.0 udp/1234; SO_REUSEADDR present * Socket B: 0.0.0.0 udp/1234; SO_REUSEADDR present Result: bind() succeeds! In this case all the datagrams go to the latest server that has been started. This looks more like a bug, but again, I'd like first to understand the exact desired semantics of SO_REUSEADDR with regard to bind conflicts. Thanks, gilberto