[ DDS ] Handle case where requested DDS port is already in use
Instead of hanging with no output to the console, a useful error message
is output to the console before shutting down the VM process.
Fixes https://github.com/dart-lang/sdk/issues/48160
Change-Id: Ib37c0cdf8b1bae6f164abff4a3b3100e944d8a3c
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/228961
Reviewed-by: Ryan Macnak <rmacnak@google.com>
Commit-Queue: Ben Konyi <bkonyi@google.com>
diff --git a/pkg/dartdev/lib/src/commands/run.dart b/pkg/dartdev/lib/src/commands/run.dart
index 457f673..2ce7fbc 100644
--- a/pkg/dartdev/lib/src/commands/run.dart
+++ b/pkg/dartdev/lib/src/commands/run.dart
@@ -333,11 +333,16 @@
stderrSub.cancel();
completer.complete();
} else {
+ stderrSub.cancel();
final error = result['error'] ?? event;
final stacktrace = result['stacktrace'] ?? '';
- stderrSub.cancel();
- completer.completeError(
- 'Could not start Observatory HTTP server:\n$error\n$stacktrace\n');
+ String message = 'Could not start the VM service: ';
+ if (error.contains('Failed to create server socket')) {
+ message += '$host:$port is already in use.\n';
+ } else {
+ message += '$error\n$stacktrace\n';
+ }
+ completer.completeError(message);
}
});
try {
diff --git a/pkg/dartdev/test/smoke/smoke_test.dart b/pkg/dartdev/test/smoke/smoke_test.dart
index 7b1c688..38dd049 100644
--- a/pkg/dartdev/test/smoke/smoke_test.dart
+++ b/pkg/dartdev/test/smoke/smoke_test.dart
@@ -51,6 +51,24 @@
}
});
+ test('dart run --enable-vm-service smoke.dart with used port', () async {
+ final server = await HttpServer.bind(InternetAddress.anyIPv4, 0);
+ final result = await Process.run(
+ Platform.executable,
+ [
+ 'run',
+ '--enable-vm-service=${server.port}',
+ script,
+ ],
+ );
+ expect(
+ result.stderr,
+ 'Could not start Observatory HTTP server: localhost:${server.port} is already in use.\n',
+ );
+ expect(result.stdout, isEmpty);
+ server.close();
+ });
+
// This test verifies that an error isn't thrown when a valid experiment
// is passed.
// Experiments are lists here:
diff --git a/pkg/dds/lib/src/dds_impl.dart b/pkg/dds/lib/src/dds_impl.dart
index 1d76900..000a15b 100644
--- a/pkg/dds/lib/src/dds_impl.dart
+++ b/pkg/dds/lib/src/dds_impl.dart
@@ -152,14 +152,30 @@
// Start the DDS server. Run in an error Zone to ensure that asynchronous
// exceptions encountered during request handling are handled, as exceptions
// thrown during request handling shouldn't take down the entire service.
- _server = await runZonedGuarded(
- () async => await io.serve(handler, host, port),
+ late String errorMessage;
+ final tmpServer = await runZonedGuarded(
+ () async {
+ try {
+ return await io.serve(handler, host, port);
+ } on SocketException catch (e) {
+ errorMessage = e.message;
+ if (e.osError != null) {
+ errorMessage += ' (${e.osError!.message})';
+ }
+ errorMessage += ': ${e.address?.host}:${e.port}';
+ return null;
+ }
+ },
(error, stack) {
if (shouldLogRequests) {
print('Asynchronous error: $error\n$stack');
}
},
- )!;
+ );
+ if (tmpServer == null) {
+ throw DartDevelopmentServiceException.connectionIssue(errorMessage);
+ }
+ _server = tmpServer;
final tmpUri = Uri(
scheme: 'http',