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
, andai_protocol
fields tosocket()
- then pass its
ai_addr
andai_addrlen
fields tobind()
(servers) orconnect()
(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]