2

I have a multithreaded Linux server with many simultaneous connections (2 connections per thread) which must bind to a public IP address when responding to a client. From time to time, I get a EADDRINUSE error when binding a UDP socket, even though my logs indicate that the last time a socket was bound to the same address/port AND called shutdown() and close() on the socket was 30 minutes before.

Moreover, I set SO_REUSEADDR, SO_REUSEPORT and IP_TRANSPARENT on these UDP sockets (but not ones that are automatically bound to a local address/port). With these options, even if there were some other UDP socket still bound to the same port on a local address, binding should not fail as per SO_REUSEADDR, but it clearly does happen.

I can find no explanation for this behaviour.

int makeUDPSocket(sockaddr_in *bindTo)
{
    int sock;
    if(-1 == (sock = socket(AF_INET, SOCK_DGRAM | SOCK_NONBLOCK, 0)))
    {
        log("Could not make client UDP socket! Exiting.");
        exit(18);
    }
    if(bindTo)
    {
        int enable = 1;
        if (-1 == setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char*)&enable, sizeof(enable)))
        {
            log("Could not set SO_REUSEADDR on UDP socket; errno=" + std::to_string(errno));
            exit(2);
        }
        if (-1 == setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, (const char*)&enable, sizeof(enable)))
        {
            log("Could not set SO_REUSEPORT on UDP socket; errno=" + std::to_string(errno));
            exit(2);
        }
        if(-1 == setsockopt(sock, SOL_IP, IP_TRANSPARENT, (const char*)&enable, sizeof(enable)))
        {
            log("Could not set IP_TRANSPARENT on UDP socket; errno=" + std::to_string(errno));
            exit(2);
        }
        if(-1 == bind(sock, (sockaddr*)bindTo, sizeof(sockaddr_in)))
        {
            log("Could not bind UDP socket. errno=" + std::to_string(errno) + ". Exiting.");
            exit(19);
        }
    }
    return sock;
}

void myfunc()
{
    int sock0 = makeUDPSocket(NULL);
    int sock1 = makeUDPSocket(&myPubAddr);
    doStuff(sock0, sock1);
    shutdown(sock0, SHUT_RDWR);
    close(sock0);
    shutdown(sock1, SHUT_RDWR);
    close(sock1);
}
Æðelstan
  • 822
  • 12
  • 23
  • This is a VERRYYY long explanation but you will learn a lot. http://stackoverflow.com/questions/14388706/socket-options-so-reuseaddr-and-so-reuseport-how-do-they-differ-do-they-mean-t If you jump to the section on *SO_REUSEADDR* your problem may very well be the fact that you do not enable it for automatically bound locals. – jiveturkey May 16 '17 at 14:45
  • Thank you; actually I have very recently read this answer, but from what I understand `SO_REUSEADDR` does not need to be enabled on the socket previously bound in order to bind a new socket to a different address and same port. – Æðelstan May 16 '17 at 14:52
  • I just found out that on Windows, you are able to have multiple UDP sockets on the same port, for example one socket for the sending and another for the receive threads. But in Linux you are only able to have one socket on any given port number, forcing you to share that same socket between the sending and receiving threads, – Dallas Clarke Feb 25 '20 at 08:15

0 Answers0