Search code examples
socketsnetwork-programmingwinsockwinsock2

SO_EXCLUSIVEADDRUSE and SO_REUSEADDR confusion


(Running on VS2017, Win7 x64)

I am confused about the point of SO_REUSEADDR and SO_EXCLUSIVEADDRUSE. And yes, I've read the MSDN documentation, but I'm obviously not getting it.

I have the following simple code in two separate processes. As expected, because I enable SO_REUSEADDR on both sockets, the second process's bind succeeds. If I don't enable this on any one of these sockets, the second bind will not succeed.

#define PORT 5150
SOCKET sockListen;
if ((sockListen = WSASocket(AF_INET, SOCK_STREAM, 0, NULL, 0, WSA_FLAG_OVERLAPPED)) == INVALID_SOCKET)
{
    printf("WSASocket() failed with error %d\n", WSAGetLastError());
    return 1;
}

int optval = 1;
if (setsockopt(sockListen, SOL_SOCKET, `SO_REUSEADDR`, (char*)&optval, sizeof(optval)) == -1)
    return -1;

SOCKADDR_IN InternetAddr;
InternetAddr.sin_family = AF_INET;
InternetAddr.sin_addr.s_addr = inet_addr("10.15.20.97");
InternetAddr.sin_port = htons(PORT);

if (::bind(sockListen, (PSOCKADDR)&InternetAddr, sizeof(InternetAddr)) == SOCKET_ERROR)
{
    printf("bind() failed with error %d\n", WSAGetLastError());
    return 1;
}

So doesn't having to enable SO_REUSEADDR for both sockets make SO_EXCLUSIVEADDRUSE unnecessary - if I don't want anyone to foricibly bind to my port, I just don't enable SO_REUSEADDR in that process?

The only difference I can see is that if I enable SO_EXCLUSIVEADDRUSE in the first process, then attempt a bind in the second process, that second bind will fail with

a) WSAEADDRINUSE if I don't enable SO_REUSEADDR in that second process

b) WSAEACCES if I do enable SO_REUSEADDR in that second process

So I tried enabling both SO_EXCLUSIVEADDRUSE and SO_REUSEADDR in the first process but found that whichever one I attempted second failed with WSAEINVAL.

Note also that I have read this past question but what that says isn't what I'm seeing: it states

A socket with SO_REUSEADDR can always bind to exactly the same source address and port as an already bound socket, even if the other socket did not have this option set when it was bound

Now if that were the case then I can definitely see the need for SO_EXCLUSIVEADDRUSE.

I'm pretty sure I'm doing something wrong but I cannot see it; can someone clarify please?


Solution

  • As stated in the docs, SO_EXCLUSIVEADDRUSE became available on Windows NT4 SP4; before that there was only SO_REUSEADDR. So both being present has (also) historical reasons.

    I think of SO_REUSEADDR as the intention to share an address (which is only really useful for UDP multicast. For unicast or TCP it really doesn´t do much since the bahaviour is non-deterministic for both sockets).

    SO_EXCLUSIVEADDRUSE is a security measure to avoid my (server) application´s traffic being hijacked / rendered useless by a later binding to the same IP/port.

    As I see it, you need SO_REUSEADDR for UDP multicats, and you need SO_EXCLUSIVEADDRUSE as a security measure for server applications.