Merged silc_1_0_branch to trunk.
[silc.git] / lib / silcutil / unix / silcunixnet.c
index d209031a69a02e7073495f40bc7522e6f1ed6e61..d2e52e936a1d75ff444926ab27e8d6e75bbc949d 100644 (file)
@@ -191,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);
@@ -262,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);
@@ -321,11 +338,25 @@ bool silc_net_addr2bin(const char *addr, void *bin, SilcUInt32 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 */
   }