Now we meet a case that the IP address list returned by DNS server contains IPv6 address and IPv4 address. The IPv6 address is at the beginning of the list. In fact, it is invalid to connect. In this case, we need to find a valid IP address from the list. But the time spent in finding should be not too long.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <netdb.h>
#include <errno.h>
#include <sys/ioctl.h>
#define INIT_ADDR(dest4,dest6,dest,_ip,_port,addrlen) \
memset(&dest4, 0, sizeof(dest4));\
memset(&dest6, 0, sizeof(dest6));\
if(af_family == AF_INET){\
dest4.sin_family = AF_INET;\
dest4.sin_addr.s_addr = inet_addr(_ip);\
dest4.sin_port = htons(_port);\
dest = (struct sockaddr *)&dest4;\
addrlen = sizeof(dest4);\
}\
else if(af_family == AF_INET6){\
dest6.sin6_family = AF_INET6;\
inet_pton(AF_INET6, _ip, &dest6.sin6_addr);\
dest6.sin6_port = htons(_port);\
dest = (struct sockaddr *)&dest6;\
addrlen = sizeof(dest6);\
}
char ipaddr[128];
int check_service(int af_family, char *ipaddr, int portno)
{
int local_sockfd=0;
struct sockaddr_in dest4;
struct sockaddr_in6 dest6;
struct sockaddr *dest;
int addrlen;
unsigned long fc=1;
int retval, errlen, error;
struct timeval timeout;
fd_set fds;
INIT_ADDR(dest4,dest6,dest,ipaddr,portno,addrlen);
if ((local_sockfd=socket(af_family, SOCK_STREAM, 0)) == -1) {
fprintf(stderr, "Socket Error:%s\a\n", strerror(errno));
return 0;
}
if (ioctl(local_sockfd, FIONBIO, &fc) == -1) {
printf("ioctl error.\n");
return 0;
}
if (connect(local_sockfd, dest, addrlen) == -1) {
if (errno != EINPROGRESS) {
printf("Network is unreachable.\n");
return 0;
}
errlen = sizeof(int);
FD_ZERO(&fds);
FD_SET(local_sockfd, &fds);
timeout.tv_sec = 2;
timeout.tv_usec = 0;
if ((retval = select(local_sockfd + 1, NULL, &fds, NULL, &timeout)) > 0) {
getsockopt(local_sockfd, SOL_SOCKET, SO_ERROR, &error, (socklen_t *)&errlen);
if (error == 0) {
printf("OK\n");
}
else {
printf("error\n");
return 0;
}
}
else {
printf("Connect Timeout\n");
return 0;
}
}
close(local_sockfd);
return 1;
}
int main(int argc, const char *argv[])
{
char host_buf[128]={"www.baidu.com"};
struct addrinfo hints;
struct addrinfo *res = NULL;
memset(&hints, 0, sizeof(hints));
hints.ai_socktype = SOCK_STREAM;
getaddrinfo(host_buf, NULL, &hints, &res);
while (res) {
if (res->ai_family == AF_INET) {
inet_ntop(AF_INET, &((struct sockaddr_in *)res->ai_addr)->sin_addr, ipaddr, ACS_IP_LEN);
if (check_service(AF_INET, ipaddr, 80)) {
break;
}
}
else if (res->ai_family == AF_INET6) {
inet_ntop(AF_INET6, &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr, ipaddr, ACS_IP_LEN);
if (check_service(AF_INET6, ipaddr, 80)) {
break;
}
}
res = res->ai_next;
}
return 0;
}