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;
/* 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;
}
/* 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);
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;
/* 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;
}
/* 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);
/* 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;
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 */
}