Skip to content

[multicast_dns] MDnsClient::listen supports onError callback #8888

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Apr 2, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions packages/multicast_dns/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 0.3.3

* Adds an optional error callback for `MDnsClient::start` to prevent uncaught exceptions.

## 0.3.2+8

* Fixes stack overflows ocurring during the parsing of domain names in MDNS messages.
Expand Down
10 changes: 9 additions & 1 deletion packages/multicast_dns/lib/multicast_dns.dart
Original file line number Diff line number Diff line change
Expand Up @@ -84,13 +84,18 @@ class MDnsClient {
/// for the mDNS query. If not provided, defaults to either `224.0.0.251` or
/// or `FF02::FB`.
///
/// If provided, [onError] will be called in case of a stream error. If
/// omitted any errors on the stream are considered unhandled, and will be
/// passed to the current [Zone]'s error handler.
///
/// Subsequent calls to this method are ignored while the mDNS client is in
/// started state.
Future<void> start({
InternetAddress? listenAddress,
NetworkInterfacesFactory? interfacesFactory,
int mDnsPort = mDnsPort,
InternetAddress? mDnsAddress,
Function? onError,
}) async {
listenAddress ??= InternetAddress.anyIPv4;
interfacesFactory ??= allInterfacesFactory;
Expand Down Expand Up @@ -152,7 +157,10 @@ class MDnsClient {
// Join multicast on this interface.
incoming.joinMulticast(_mDnsAddress!, interface);
}
incoming.listen((RawSocketEvent event) => _handleIncoming(event, incoming));
incoming.listen(
(RawSocketEvent event) => _handleIncoming(event, incoming),
onError: onError,
);
_started = true;
_starting = false;
}
Expand Down
2 changes: 1 addition & 1 deletion packages/multicast_dns/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: multicast_dns
description: Dart package for performing mDNS queries (e.g. Bonjour, Avahi).
repository: https://github.com/flutter/packages/tree/main/packages/multicast_dns
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+multicast_dns%22
version: 0.3.2+8
version: 0.3.3

environment:
sdk: ^3.4.0
Expand Down
50 changes: 50 additions & 0 deletions packages/multicast_dns/test/client_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,35 @@ void main() {
});
}
});

test('Calls onError callback in case of socket error', () async {
final FakeRawDatagramSocketThatSendsError datagramSocket =
FakeRawDatagramSocketThatSendsError();
final MDnsClient client = MDnsClient(
rawDatagramSocketFactory: (
dynamic host,
int port, {
bool reuseAddress = true,
bool reusePort = true,
int ttl = 1,
}) async {
return datagramSocket;
},
);

final Completer<void> onErrorCalledCompleter = Completer<void>();
await client.start(
mDnsPort: 1234,
interfacesFactory: (InternetAddressType type) async =>
<NetworkInterface>[],
onError: (Object e) {
expect(e, 'Error');
onErrorCalledCompleter.complete();
},
);

await onErrorCalledCompleter.future.timeout(const Duration(seconds: 5));
});
}

class FakeRawDatagramSocket extends Fake implements RawDatagramSocket {
Expand Down Expand Up @@ -196,6 +225,27 @@ class FakeRawDatagramSocket extends Fake implements RawDatagramSocket {
}
}

class FakeRawDatagramSocketThatSendsError extends Fake
implements RawDatagramSocket {
@override
InternetAddress address = InternetAddress.anyIPv4;

@override
StreamSubscription<RawSocketEvent> listen(
void Function(RawSocketEvent event)? onData, {
Function? onError,
void Function()? onDone,
bool? cancelOnError,
}) {
return Stream<RawSocketEvent>.error('Error').listen(
onData,
onError: onError,
cancelOnError: cancelOnError,
onDone: onDone,
);
}
}

class FakeNetworkInterface implements NetworkInterface {
FakeNetworkInterface(this._name, this._addresses, this._index);

Expand Down