[7.0.1] Retry binding to ipv6 localhost (#20903)

Fixes https://github.com/bazelbuild/bazel/issues/20743

Commit
https://github.com/bazelbuild/bazel/commit/1a0b3a0db9f9eab72ddfdd7dbaf6e4801a6126fa

PiperOrigin-RevId: 595935153
Change-Id: I0409552aa92f3886c5abf3bd3ce50d67594dab7e

Co-authored-by: Googler <pcloudy@google.com>
diff --git a/src/main/java/com/google/devtools/build/lib/server/GrpcServerImpl.java b/src/main/java/com/google/devtools/build/lib/server/GrpcServerImpl.java
index 8efb5da..c7c2196 100644
--- a/src/main/java/com/google/devtools/build/lib/server/GrpcServerImpl.java
+++ b/src/main/java/com/google/devtools/build/lib/server/GrpcServerImpl.java
@@ -46,6 +46,7 @@
 import com.google.devtools.build.lib.util.DetailedExitCode;
 import com.google.devtools.build.lib.util.ExitCode;
 import com.google.devtools.build.lib.util.InterruptedFailureDetails;
+import com.google.devtools.build.lib.util.OS;
 import com.google.devtools.build.lib.util.Pair;
 import com.google.devtools.build.lib.util.io.OutErr;
 import com.google.devtools.build.lib.vfs.FileSystemUtils;
@@ -376,6 +377,26 @@
     commandManager.interruptInflightCommands();
   }
 
+  private Server bindIpv6WithRetries(InetSocketAddress address, int maxRetries) throws IOException {
+    Server server = null;
+    for (int attempt = 1; attempt <= maxRetries; attempt++) {
+      try {
+        server =
+            NettyServerBuilder.forAddress(address)
+                .addService(this)
+                .directExecutor()
+                .build()
+                .start();
+        break;
+      } catch (IOException e) {
+        if (attempt == maxRetries) {
+          throw e;
+        }
+      }
+    }
+    return server;
+  }
+
   @Override
   public void serve() throws AbruptExitException {
     Preconditions.checkState(!serving);
@@ -391,8 +412,10 @@
       if (Epoll.isAvailable() && !Socket.isIPv6Preferred()) {
         throw new IOException("ipv6 is not preferred on the system.");
       }
-      server =
-          NettyServerBuilder.forAddress(address).addService(this).directExecutor().build().start();
+      // For some strange reasons, Bazel server sometimes fails to bind to IPv6 localhost when
+      // running in macOS sandbox-exec with internet blocked. Retrying seems to help.
+      // See https://github.com/bazelbuild/bazel/issues/20743
+      server = bindIpv6WithRetries(address, OS.getCurrent() == OS.DARWIN ? 3 : 1);
     } catch (IOException ipv6Exception) {
       address = new InetSocketAddress("127.0.0.1", port);
       try {