Recover gracefully if a matching port is unavailable.
R=rnystrom@google.com
BUG=dartbug.com/22673
Review URL: https://codereview.chromium.org//993743002
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f3d79a3..96b81c8 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,8 @@
+## 1.3.1
+
+* `loopback()` and `loopbackSecure()` recover gracefully if an ephemeral port is
+ requested and the located port isn't available on both IPv4 and IPv6.
+
## 1.3.0
* Add support for `HttpServer.autoCompress`.
diff --git a/lib/http_multi_server.dart b/lib/http_multi_server.dart
index 01e3ca8..fc87455 100644
--- a/lib/http_multi_server.dart
+++ b/lib/http_multi_server.dart
@@ -10,6 +10,15 @@
import 'src/multi_headers.dart';
import 'src/utils.dart';
+/// The error code for an error caused by a port already being in use.
+final _addressInUseErrno = _computeAddressInUseErrno();
+int _computeAddressInUseErrno() {
+ if (Platform.isWindows) return 10048;
+ if (Platform.isMacOS) return 48;
+ assert(Platform.isLinux);
+ return 98;
+}
+
/// An implementation of `dart:io`'s [HttpServer] that wraps multiple servers
/// and forwards methods to all of them.
///
@@ -134,6 +143,16 @@
return bind(InternetAddress.LOOPBACK_IP_V6, v4Server.port)
.then((v6Server) {
return new HttpMultiServer([v4Server, v6Server]);
+ }).catchError((error) {
+ if (error is! SocketException) throw error;
+ if (error.osError.errno != _addressInUseErrno) throw error;
+ if (port != 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);
});
});
}
diff --git a/pubspec.yaml b/pubspec.yaml
index b1a294f..8faaace 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,5 +1,5 @@
name: http_multi_server
-version: 1.3.0+1
+version: 1.3.1
author: "Dart Team <misc@dartlang.org>"
homepage: http://github.com/dart-lang/http_multi_server
description: