8
votes

I have a server implementation where I need 2 separate sockets - 1 IPv4 socket socket listening on a particular IPv4 address and server port X, and an IPv6 socket listening on a particular IPv6 address and same server port X. The IPv4 and IPv6 addresses are on the same interface.

    memset(&sin, 0, sizeof(sin));
    sin.sin_family      = AF_INET;
    sin.sin_addr.s_addr = htonl(v4addr);
    sin.sin_port        = htons(tcp_port);

I am using evconnlistener_new_bind to create ipv4 socket and bind to it. For IPv6 listener, the code is as below.

    memset(&sin6, 0, sizeof(sin6));
    sin6.sin6_family      = AF_INET6;
    memcpy(sin6.sin6_addr.s6_addr, v6addr_bytes, IPV6_ADDR_LEN);
    sin6.sin6_port        = htons(tcp_port);

    fd = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
    evutil_make_socket_nonblocking(fd)
    setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (void*)&on, sizeof(on))
    setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (void*)&on, sizeof(on))
    evutil_make_listen_socket_reuseable(fd)   /* Libevent call to set SO_REUSEADDR */
    evutil_make_socket_nonblocking(fd)        /* Libevent call to set fd non-blocking */ 
    bind(fd, (const struct sockaddr *)&sin6, sizeof(sin6))

As I bind my fd to the particular ipv6 address, I see a bind failure intermittently.

bind v6 failed sin6 3ffe::a00:513 - errno 99 - Cannot assign requested address

I tried to gdb in, but every time I gdb in, the bind succeeds.

I am not sure why I am seeing this problem. Can someone please help?

1
Addreses in 3ffe::/16 are not valid. Use a valid IPv6 address instead.Michael Hampton
My interface has a 3ffe::10.1.14.14/120 address. While creating the socket, the prefix mask has no implications right? And why do you say its an invalid address?shrejal
Because it isn't valid. That netblock was obsoleted years ago. And the fact that it's in use at all indicates that something is horribly wrong with your IPv6 setup. Fix that first.Michael Hampton
It works sometimes! I will try a different addressing scheme. But any pointers as to why its invalid would help me understand better.shrejal
@jch It's not invalid per se, but it is filtered in a lot of places. See RFC 3701.Michael Hampton

1 Answers

1
votes

By default, after a socket is bound to a TCP port, the port remains reserved for one minute when the socket is closed — this is called the TCP TIME_WAIT state. TIME_WAIT avoids some race conditions that could cause data corruption, but it is usually safe to ignore TIME_WAIT on the server side.

This is done by setting the SO_REUSEADDR socket option:

int one = 1;
rc = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one))