Index: pkg/mdns/lib/mdns.dart |
diff --git a/pkg/mdns/lib/mdns.dart b/pkg/mdns/lib/mdns.dart |
index 55682a7b4ca2c2360d0554cb504ef3c130f4e71f..f707136d4c865cb33b8b6f39c022af0af5fbd5f7 100644 |
--- a/pkg/mdns/lib/mdns.dart |
+++ b/pkg/mdns/lib/mdns.dart |
@@ -1,48 +1,68 @@ |
-// Copyright (c) 2015, the Fletch project authors. Please see the AUTHORS file |
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
// for details. All rights reserved. Use of this source code is governed by a |
-// BSD-style license that can be found in the LICENSE.md file. |
- |
-library mdns; |
+// BSD-style license that can be found in the LICENSE file. |
import 'dart:async'; |
import 'dart:collection'; |
import 'dart:io'; |
import 'dart:typed_data'; |
-import 'package:mdns/src/native_extension_client.dart'; |
-import 'package:mdns/src/native_protocol_client.dart'; |
+import 'package:mdns/src/constants.dart'; |
+import 'package:mdns/src/lookup_resolver.dart'; |
+import 'package:mdns/src/packet.dart'; |
/// Client for DNS lookup using the mDNS protocol. |
/// |
/// This client only support "One-Shot Multicast DNS Queries" as described in |
/// section 5.1 of https://tools.ietf.org/html/rfc6762 |
-abstract class MDnsClient { |
- // Instantiate Client for DNS lookup using the mDNS protocol. |
- // |
- // On Mac OS a native extension is used as the mDNSResponder opens the mDNS |
- // port in exclusive mode. To test the protocol implementation on Mac OS |
- // one can turn off mDNSResponder: |
- // |
- // sudo launchctl unload -w \ |
- // /System/Library/LaunchDaemons/com.apple.mDNSResponder.plist |
- // |
- // And turn it on again: |
- // |
- // sudo launchctl load -w \ |
- // /System/Library/LaunchDaemons/com.apple.mDNSResponder.plist |
- factory MDnsClient() { |
- if (Platform.isMacOS) { |
- return new NativeExtensionMDnsClient(); |
- } else { |
- return new NativeProtocolMDnsClient(); |
- } |
- } |
+class MDnsClient { |
+ bool _starting = false; |
+ bool _started = false; |
+ RawDatagramSocket _incoming; |
+ final List<RawDatagramSocket> _sockets = <RawDatagramSocket>[]; |
+ final LookupResolver _resolver = new LookupResolver(); |
/// Start the mDNS client. |
- Future start(); |
+ Future start() async { |
+ if (_started && _starting) { |
+ throw new StateError('mDNS client already started'); |
+ } |
+ _starting = true; |
+ |
+ // Listen on all addresses. |
+ _incoming = await RawDatagramSocket.bind( |
+ InternetAddress.ANY_IP_V4, mDnsPort, reuseAddress: true); |
+ |
+ // Find all network interfaces with an IPv4 address. |
+ var interfaces = |
+ await NetworkInterface.list(type: InternetAddressType.IP_V4); |
+ for (NetworkInterface interface in interfaces) { |
+ // Create a socket for sending on each adapter. |
+ var socket = await RawDatagramSocket.bind( |
+ interface.addresses[0], mDnsPort, reuseAddress: true); |
+ _sockets.add(socket); |
+ |
+ // Join multicast on this interface. |
+ _incoming.joinMulticast(mDnsAddress, interface); |
+ } |
+ _incoming.listen(_handleIncoming); |
+ |
+ _starting = false; |
+ _started = true; |
+ } |
/// Stop the mDNS client. |
- void stop(); |
+ void stop() { |
+ if (!_started) return; |
+ if (_starting) { |
+ throw new StateError('Cannot stop mDNS client wile it is starting'); |
+ } |
+ |
+ _sockets.forEach((socket) => socket.close()); |
+ _incoming.close(); |
+ |
+ _started = false; |
+ } |
/// Lookup [hostname] using mDNS. |
/// |
@@ -52,14 +72,40 @@ abstract class MDnsClient { |
/// If no answer has been received within the specified [timeout] |
/// this method will complete with the value `null`. |
Future<InternetAddress> lookup( |
- String hostname, {Duration timeout: const Duration(seconds: 5)}); |
+ String hostname, {Duration timeout: const Duration(seconds: 5)}) { |
+ if (!_started) { |
+ throw new StateError('mDNS client is not started'); |
+ } |
+ |
+ // Add the pending request before sending the query. |
+ var future = _resolver.addPendingRequest(hostname, timeout); |
+ |
+ // Send the request on all interfaces. |
+ List<int> packet = encodeMDnsQuery(hostname); |
+ for (int i = 0; i < _sockets.length; i++) { |
+ _sockets[i].send(packet, mDnsAddress, mDnsPort); |
+ } |
+ |
+ return future; |
+ } |
+ |
+ // Process incoming datagrams. |
+ _handleIncoming(event) { |
+ if (event == RawSocketEvent.READ) { |
+ var data = _incoming.receive(); |
+ var response = decodeMDnsResponse(data.data); |
+ if (response != null) { |
+ _resolver.handleResponse(response); |
+ } |
+ } |
+ } |
} |
// Simple standalone test. |
-Future main(List<String> args) async { |
+main() async { |
var client = new MDnsClient(); |
await client.start(); |
- var address = await client.lookup(args[0]); |
+ var address = await client.lookup('raspberrypi.local'); |
client.stop(); |
print(address); |
} |