Hi,

Can you test the attached patch? It fixes the problrem for me. Without
this patch, I need to set tcp_outgoing_address to force IPv4 for some
sites.
diff -uNrp squid3-3.1.18.orig/src/comm.cc squid3-3.1.18/src/comm.cc
--- squid3-3.1.18.orig/src/comm.cc      2011-12-03 06:18:46.000000000 +0000
+++ squid3-3.1.18/src/comm.cc   2012-01-18 10:03:30.422424903 +0000
@@ -984,8 +984,8 @@ ConnectStateData::commResetFD()
     fde *F = &fd_table[fd];
 
     struct addrinfo *AI = NULL;
-    F->local_addr.GetAddrInfo(AI);
-    int new_family = AI->ai_family;
+    const int new_family = F->sock_family;
+    F->local_addr.GetAddrInfo(AI, new_family);
 
     int fd2 = socket(new_family, AI->ai_socktype, AI->ai_protocol);
 
@@ -1126,22 +1126,31 @@ ConnectStateData::connect()
         callCallback(COMM_OK, 0);
         break;
 
-    case COMM_ERR_PROTOCOL:
+    case COMM_ERR_PROTOCOL: {
         debugs(5, 5, HERE "FD " << fd << ": COMM_ERR_PROTOCOL - try again");
-        /* problem using the desired protocol over this socket.
-         * skip to the next address and hope it's more compatible
-         * but do not mark the current address as bad
+        /* A remote address is incompatible with this socket. If local
+         * address is not wildcard address, skip to the next address
+         * but do not mark the current address as bad.
          */
-        tries++;
-        if (commRetryConnect()) {
+        fde *F = &fd_table[fd];
+        if (F->local_addr.IsAnyAddr()) {
+            struct addrinfo *AI = NULL;
+            S.GetAddrInfo(AI);
+            F->sock_family = AI->ai_family;
+            S.FreeAddrInfo(AI);
+        } else {
+            tries++;
             /* Force an addr cycle to move forward to the next possible 
address */
             ipcacheCycleAddr(host, NULL);
+        } 
+        if (commRetryConnect()) {
             eventAdd("commReconnect", commReconnect, this, this->addrcount == 
1 ? 0.05 : 0.0, 0);
         } else {
             debugs(5, 5, HERE << "FD " << fd << ": COMM_ERR_PROTOCOL - ERR 
tried too many times already.");
             callCallback(COMM_ERR_CONNECT, errno);
         }
         break;
+    }
 
     default:
         debugs(5, 5, HERE "FD " << fd << ": * - try again");
@@ -1243,29 +1252,7 @@ comm_connect_addr(int sock, const IpAddr
 
     debugs(5, 9, "comm_connect_addr: connecting socket " << sock << " to " << 
address << " (want family: " << F->sock_family << ")");
 
-    /* Handle IPv6 over IPv4-only socket case.
-     * this case must presently be handled here since the GetAddrInfo asserts 
on bad mappings.
-     * NP: because commResetFD is private to ConnStateData we have to return 
an error and
-     *     trust its handled properly.
-     */
-    if (F->sock_family == AF_INET && !address.IsIPv4()) {
-        errno = ENETUNREACH;
-        return COMM_ERR_PROTOCOL;
-    }
-
-    /* Handle IPv4 over IPv6-only socket case.
-     * This case is presently handled here as it's both a known case and it's
-     * uncertain what error will be returned by the IPv6 stack in such case. 
It's
-     * possible this will also be handled by the errno checks below after 
connect()
-     * but needs carefull cross-platform verification, and verifying the 
address
-     * condition here is simple.
-     */
-    if (!F->local_addr.IsIPv4() && address.IsIPv4()) {
-        errno = ENETUNREACH;
-        return COMM_ERR_PROTOCOL;
-    }
-
-    address.GetAddrInfo(AI, F->sock_family);
+    address.GetAddrInfo(AI);
 
     /* Establish connection. */
     errno = 0;

Reply via email to