OLD | NEW |
---|---|
(Empty) | |
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | |
2 // for details. All rights reserved. Use of this source code is governed by a | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 import 'dart:async'; | |
6 import 'dart:collection'; | |
7 import 'dart:io'; | |
8 import 'dart:typed_data'; | |
9 | |
10 import 'package:mdns/src/constants.dart'; | |
11 import 'package:mdns/src/lookup_resolver.dart'; | |
12 import 'package:mdns/src/packet.dart'; | |
13 | |
14 /// Client for DNS lookup using the mDNS protocol. | |
15 /// | |
16 /// This client only support "One-Shot Multicast DNS Queries" as described in | |
17 /// section 5.1 of https://tools.ietf.org/html/rfc6762 | |
18 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.
| |
19 bool _starting = false; | |
20 bool _started = false; | |
21 RawDatagramSocket _incoming; | |
22 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.
| |
23 final LookupResolver _resolver = new LookupResolver(); | |
24 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.
| |
25 | |
26 MDNSClient(); | |
karlklose
2015/10/28 10:14:30
Not needed.
Søren Gjesse
2015/10/28 11:36:57
Removed.
| |
27 | |
28 /// Start the mDNS client. | |
29 Future start() async { | |
30 if (_started && _starting) { | |
31 throw new StateError('mDNS client already started'); | |
32 } | |
33 _starting = true; | |
34 | |
35 // Listen on all addresses. | |
36 _incoming = await RawDatagramSocket.bind( | |
37 InternetAddress.ANY_IP_V4, mDNSPort, reuseAddress: true); | |
38 | |
39 // Find all network interfaces with an IPv4 address. | |
40 var interfaces = | |
41 await NetworkInterface.list(type: InternetAddressType.IP_V4); | |
42 var socket; | |
karlklose
2015/10/28 10:14:30
Move declaration to line 45?
Søren Gjesse
2015/10/28 11:36:57
Done.
| |
43 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.
| |
44 // Create a socket for sending on each adapter. | |
45 socket = await RawDatagramSocket.bind( | |
46 interfaces[i].addresses[0], mDNSPort, reuseAddress: true); | |
47 _sockets.add(socket); | |
48 | |
49 // Join multicast on this interface. | |
50 _incoming.joinMulticast(mDNSAddress, interfaces[i]); | |
51 } | |
52 _incoming.listen(_handleIncoming); | |
53 | |
54 _starting = false; | |
55 _started = true; | |
56 } | |
57 | |
58 /// Stop the mDNS client. | |
59 void stop() { | |
60 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.
| |
61 | |
62 _sockets.forEach((socket) => socket.close()); | |
63 _incoming.close(); | |
64 | |
65 _started = false; | |
66 } | |
67 | |
68 /// Lookup [hostname] using mDNS. | |
69 /// | |
70 /// The `hostname` must have the form `single-dns-label.local`, | |
71 /// e.g. `printer.local`. | |
72 /// | |
73 /// If no answer has been received within the specified [timeout] | |
74 /// this method will complete with the value `null`. | |
75 Future<InternetAddress> lookup(String hostname, {Duration timeout}) { | |
76 if (!_started) { | |
77 throw new StateError('mDNS client is not started'); | |
78 } | |
79 | |
80 // Add the pending request before sending the query. | |
81 var future = _resolver.addPendingRequest( | |
82 hostname, timeout != null ? timeout : _defaultTimeout); | |
83 | |
84 // Send the request on all interfaces. | |
85 List<int> packet = encodeMDNSQuery(hostname); | |
86 for (int i = 0; i < _sockets.length; i++) { | |
87 _sockets[i].send(packet, mDNSAddress, mDNSPort); | |
88 } | |
89 | |
90 return future; | |
91 } | |
92 | |
93 // Process incoming datagrams. | |
94 _handleIncoming(event) { | |
95 if (event == RawSocketEvent.READ) { | |
96 var data = _incoming.receive(); | |
97 var response = decodeMDNSResponse(data.data); | |
98 if (response != null) { | |
99 _resolver.handleResponse(response); | |
100 } | |
101 } | |
102 } | |
103 } | |
104 | |
105 // Simple standalone test. | |
106 main() async { | |
107 var client = new MDNSClient(); | |
108 await client.start(); | |
109 var address = await client.lookup('raspberrypi.local'); | |
110 client.stop(); | |
111 print(address); | |
112 } | |
OLD | NEW |