Chromium Code Reviews| Index: pkg/mdns/lib/mdns.dart |
| diff --git a/pkg/mdns/lib/mdns.dart b/pkg/mdns/lib/mdns.dart |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..1e9594f7fe1cdf49c98a7f802244a8059ef0ce74 |
| --- /dev/null |
| +++ b/pkg/mdns/lib/mdns.dart |
| @@ -0,0 +1,112 @@ |
| +// 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 file. |
| + |
| +import 'dart:async'; |
| +import 'dart:collection'; |
| +import 'dart:io'; |
| +import 'dart:typed_data'; |
| + |
| +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 |
| +class MDNSClient { |
|
karlklose
2015/10/28 10:14:30
I think this should be 'MDnsClient'.
Søren Gjesse
2015/10/28 11:36:57
Yes, you are probably right.
|
| + bool _starting = false; |
| + bool _started = false; |
| + RawDatagramSocket _incoming; |
| + final List<RawDatagramSocket> _sockets = []; |
|
karlklose
2015/10/28 10:14:30
Consider adding a type to the list literal to catc
Søren Gjesse
2015/10/28 11:36:57
Done.
|
| + final LookupResolver _resolver = new LookupResolver(); |
| + final Duration _defaultTimeout = new Duration(seconds: 5); |
|
karlklose
2015/10/28 10:14:30
Does it make sense to remove this field (it cannot
Søren Gjesse
2015/10/28 11:36:57
Absolutely. Done.
|
| + |
| + MDNSClient(); |
|
karlklose
2015/10/28 10:14:30
Not needed.
Søren Gjesse
2015/10/28 11:36:57
Removed.
|
| + |
| + /// Start the mDNS client. |
| + 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); |
| + var socket; |
|
karlklose
2015/10/28 10:14:30
Move declaration to line 45?
Søren Gjesse
2015/10/28 11:36:57
Done.
|
| + for (int i = 0; i < interfaces.length; i++) { |
|
karlklose
2015/10/28 10:14:30
How about:
for (NetworkInterface interface in i
Søren Gjesse
2015/10/28 11:36:57
Sure, done.
|
| + // Create a socket for sending on each adapter. |
| + socket = await RawDatagramSocket.bind( |
| + interfaces[i].addresses[0], mDNSPort, reuseAddress: true); |
| + _sockets.add(socket); |
| + |
| + // Join multicast on this interface. |
| + _incoming.joinMulticast(mDNSAddress, interfaces[i]); |
| + } |
| + _incoming.listen(_handleIncoming); |
| + |
| + _starting = false; |
| + _started = true; |
| + } |
| + |
| + /// Stop the mDNS client. |
| + void stop() { |
| + if (!_started) return; |
|
karlklose
2015/10/28 10:14:30
Should this method throw if '_starting == true'?
Søren Gjesse
2015/10/28 11:36:57
Done.
|
| + |
| + _sockets.forEach((socket) => socket.close()); |
| + _incoming.close(); |
| + |
| + _started = false; |
| + } |
| + |
| + /// Lookup [hostname] using mDNS. |
| + /// |
| + /// The `hostname` must have the form `single-dns-label.local`, |
| + /// e.g. `printer.local`. |
| + /// |
| + /// 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}) { |
| + if (!_started) { |
| + throw new StateError('mDNS client is not started'); |
| + } |
| + |
| + // Add the pending request before sending the query. |
| + var future = _resolver.addPendingRequest( |
| + hostname, timeout != null ? timeout : _defaultTimeout); |
| + |
| + // 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. |
| +main() async { |
| + var client = new MDNSClient(); |
| + await client.start(); |
| + var address = await client.lookup('raspberrypi.local'); |
| + client.stop(); |
| + print(address); |
| +} |