Eventually stop retrying port allocation if it fails repeatedly.

R=skybrian@google.com

Review URL: https://codereview.chromium.org//992843002
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 96b81c8..e2b731b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 1.3.2
+
+* Eventually stop retrying port allocation if it fails repeatedly.
+
 ## 1.3.1
 
 * `loopback()` and `loopbackSecure()` recover gracefully if an ephemeral port is
diff --git a/lib/http_multi_server.dart b/lib/http_multi_server.dart
index fc87455..36d583f 100644
--- a/lib/http_multi_server.dart
+++ b/lib/http_multi_server.dart
@@ -128,7 +128,10 @@
   /// [bind] should forward to either [HttpServer.bind] or
   /// [HttpServer.bindSecure].
   static Future<HttpServer> _loopback(int port,
-      Future<HttpServer> bind(InternetAddress address, int port)) {
+      Future<HttpServer> bind(InternetAddress address, int port),
+      [int remainingRetries]) {
+    if (remainingRetries == null) remainingRetries = 5;
+
     return Future.wait([
       supportsIpV6,
       bind(InternetAddress.LOOPBACK_IP_V4, port)
@@ -147,12 +150,13 @@
         if (error is! SocketException) throw error;
         if (error.osError.errno != _addressInUseErrno) throw error;
         if (port != 0) throw error;
+        if (remainingRetries == 0) throw error;
 
         // A port being available on IPv4 doesn't necessarily mean that the same
         // port is available on IPv6. If it's not (which is rare in practice),
         // we try again until we find one that's available on both.
         v4Server.close();
-        return _loopback(port, bind);
+        return _loopback(port, bind, remainingRetries - 1);
       });
     });
   }
diff --git a/pubspec.yaml b/pubspec.yaml
index 8faaace..e549c4b 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,5 +1,5 @@
 name: http_multi_server
-version: 1.3.1
+version: 1.3.2-dev
 author: "Dart Team <misc@dartlang.org>"
 homepage: http://github.com/dart-lang/http_multi_server
 description: