[Solved] IPv6 Compatibility Issues with Low-Level C API’s [closed]


You are NOT supposed to use AF_UNSPEC with socket() at all. You MUST use either AF_INET (IPv4) or AF_INET6 (IPv6).

You can use AF_UNSPEC with the hints input parameter of getaddrinfo() to indicate that you are willing to accept both IPv4 and IPv6 addresses as output. The actual addresses in the output will be either AF_INET or AF_INET6. Or, you can set the hints to AF_INET for IPv4-only output. Or AF_INET6 for IPv6-only output.

You are supposed to loop through the list that is returned by getaddrinfo(). For each address in the list:

  • pass its ai_family, ai_socktype, and ai_protocol fields to socket()
  • then pass its ai_addr and ai_addrlen fields to bind() (servers) or connect() (clients).

Repeat this for all addresses reported for a listening server, and for all addresses reported for a client until one successfully connects.

This way, each socket you create matches the IP version of the address it is working with, and you are passing an appropriate matching sockaddr_in (IPv4) or sockaddr_in6 (IPv6) to bind()/connect().

Once you have successful listening server socket(s), or a successfully connected client socket, if you need to retrieve an IP from a socket using accept(), getsockname() or getpeername(), be sure to pass it a sockaddr_storage struct to fill in. sockaddr_storage is large enough to hold all defined sockaddr-based structures (and there are many). If successful, you can then type-cast it to a sockaddr_in or sockaddr_in6 based on its sa_family field (AF_INET or AF_INET6, respectively). Same goes for other similar functions, like inet_pton() and inet_ntop().


Update: given the client code you have shown, try this instead:

struct addrinfo hints = {0};
hints.ai_family   = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;

NSString* portString = [NSString stringWithFormat:@"%d", _port];

struct addrinfo *ai;
int sockfd = -1;

int status = getaddrinfo([_hostname UTF8String], [portString cStringUsingEncoding:kCFStringEncodingASCII] , &hints, &ai);
if (status == 0) {
    sockfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
    if (sockfd == -1) {
        status = errno;
    }
    else if (connect(sockfd, ai->ai_addr, ai->ai_addrlen) < 0) {
        status = errno;
        close(sockfd);
        sockfd = -1;
    }
    freeaddrinfo(ai);
}

if (sockfd == -1) {
    // handle status error as needed...
}
else {
    // use sockfd as needed...
    close(sockfd);
}

8

solved IPv6 Compatibility Issues with Low-Level C API’s [closed]