X-Git-Url: http://git.silcnet.org/gitweb/?a=blobdiff_plain;f=lib%2Fsilcutil%2Funix%2Fsilcunixnet.c;h=d2e52e936a1d75ff444926ab27e8d6e75bbc949d;hb=c257b555225193e54d85daf541d29578b3c93882;hp=d1f6384ce7aa3d7f1158fd3f164694fc7b1e15ea;hpb=e4b63806b89601e4e787c239b39b1bee33e46f7e;p=silc.git diff --git a/lib/silcutil/unix/silcunixnet.c b/lib/silcutil/unix/silcunixnet.c index d1f6384c..d2e52e93 100644 --- a/lib/silcutil/unix/silcunixnet.c +++ b/lib/silcutil/unix/silcunixnet.c @@ -155,11 +155,13 @@ int silc_net_create_connection(const char *local_ip, int port, int sock, rval; char ip_addr[64]; SilcSockaddr desthost; + bool prefer_ipv6 = TRUE; SILC_LOG_DEBUG(("Creating connection to host %s port %d", host, port)); /* Do host lookup */ - if (!silc_net_gethostbyname(host, ip_addr, sizeof(ip_addr))) { + retry: + if (!silc_net_gethostbyname(host, prefer_ipv6, ip_addr, sizeof(ip_addr))) { SILC_LOG_ERROR(("Network (%s) unreachable: could not resolve the " "IP address", host)); return -1; @@ -172,6 +174,13 @@ int silc_net_create_connection(const char *local_ip, int port, /* Create the connection socket */ sock = socket(desthost.sin.sin_family, SOCK_STREAM, 0); if (sock < 0) { + /* If address is IPv6, then fallback to IPv4 and see whether we can do + better with that on socket creation. */ + if (prefer_ipv6 && silc_net_is_ip6(ip_addr)) { + prefer_ipv6 = FALSE; + goto retry; + } + SILC_LOG_ERROR(("Cannot create socket: %s", strerror(errno))); return -1; } @@ -182,12 +191,20 @@ int silc_net_create_connection(const char *local_ip, int port, /* Set sockaddr for local listener, and try to bind it. */ if (silc_net_set_sockaddr(&local, local_ip, 0)) - bind(sock, &local.sa, sizeof(local)); + bind(sock, &local.sa, SIZEOF_SOCKADDR(local)); } /* Connect to the host */ - rval = connect(sock, &desthost.sa, sizeof(desthost)); + rval = connect(sock, &desthost.sa, SIZEOF_SOCKADDR(desthost)); if (rval < 0) { + /* retry using an IPv4 adress, if IPv6 didn't work */ + if (prefer_ipv6 && silc_net_is_ip6(ip_addr)) { + shutdown(sock, 2); + close(sock); + + prefer_ipv6 = FALSE; + goto retry; + } SILC_LOG_ERROR(("Cannot connect to remote host: %s", strerror(errno))); shutdown(sock, 2); close(sock); @@ -216,12 +233,14 @@ int silc_net_create_connection_async(const char *local_ip, int port, int sock, rval; char ip_addr[64]; SilcSockaddr desthost; + bool prefer_ipv6 = TRUE; SILC_LOG_DEBUG(("Creating connection (async) to host %s port %d", host, port)); /* Do host lookup */ - if (!silc_net_gethostbyname(host, ip_addr, sizeof(ip_addr))) { + retry: + if (!silc_net_gethostbyname(host, prefer_ipv6, ip_addr, sizeof(ip_addr))) { SILC_LOG_ERROR(("Network (%s) unreachable: could not resolve the " "IP address", host)); return -1; @@ -234,6 +253,13 @@ int silc_net_create_connection_async(const char *local_ip, int port, /* Create the connection socket */ sock = socket(desthost.sin.sin_family, SOCK_STREAM, 0); if (sock < 0) { + /* If address is IPv6, then fallback to IPv4 and see whether we can do + better with that on socket creation. */ + if (prefer_ipv6 && silc_net_is_ip6(ip_addr)) { + prefer_ipv6 = FALSE; + goto retry; + } + SILC_LOG_ERROR(("Cannot create socket: %s", strerror(errno))); return -1; } @@ -244,16 +270,25 @@ int silc_net_create_connection_async(const char *local_ip, int port, /* Set sockaddr for local listener, and try to bind it. */ if (silc_net_set_sockaddr(&local, local_ip, 0)) - bind(sock, &local.sa, sizeof(local)); + bind(sock, &local.sa, SIZEOF_SOCKADDR(local)); } /* Set the socket to non-blocking mode */ silc_net_set_socket_nonblock(sock); /* Connect to the host */ - rval = connect(sock, &desthost.sa, sizeof(desthost)); + rval = connect(sock, &desthost.sa, SIZEOF_SOCKADDR(desthost)); if (rval < 0) { if (errno != EINPROGRESS) { + /* retry using an IPv4 adress, if IPv6 didn't work */ + if (prefer_ipv6 && silc_net_is_ip6(ip_addr)) { + shutdown(sock, 2); + close(sock); + + prefer_ipv6 = FALSE; + goto retry; + } + SILC_LOG_ERROR(("Cannot connect to remote host: %s", strerror(errno))); shutdown(sock, 2); close(sock); @@ -289,7 +324,7 @@ int silc_net_set_socket_nonblock(int sock) /* Converts the IP number string from numbers-and-dots notation to binary form. */ -bool silc_net_addr2bin(const char *addr, void *bin, uint32 bin_len) +bool silc_net_addr2bin(const char *addr, void *bin, SilcUInt32 bin_len) { int ret = 0; @@ -303,11 +338,25 @@ bool silc_net_addr2bin(const char *addr, void *bin, uint32 bin_len) memcpy(bin, (unsigned char *)&tmp.s_addr, 4); #ifdef HAVE_IPV6 } else { + struct addrinfo hints, *ai; + SilcSockaddr *s; + /* IPv6 address */ if (bin_len < 16) return FALSE; - ret = inet_pton(AF_INET6, addr, &bin); + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET6; + if (getaddrinfo(addr, NULL, &hints, &ai)) + return FALSE; + + if (ai) { + s = (SilcSockaddr *)ai->ai_addr; + memcpy(bin, &s->sin6.sin6_addr, sizeof(s->sin6.sin6_addr)); + freeaddrinfo(ai); + } + + ret = TRUE; #endif /* HAVE_IPV6 */ }