| 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);
|
| }
|
|
|