Chromium Code Reviews| Index: pkg/mdns/lib/src/native_protocol_client.dart |
| diff --git a/pkg/mdns/lib/src/native_protocol_client.dart b/pkg/mdns/lib/src/native_protocol_client.dart |
| index 23854300ee9281e44c4dac70c3755474579346bb..4ee0d00baa44d918d32f6bc4a6f21d03b60f8c48 100644 |
| --- a/pkg/mdns/lib/src/native_protocol_client.dart |
| +++ b/pkg/mdns/lib/src/native_protocol_client.dart |
| @@ -13,6 +13,53 @@ import 'package:mdns/src/constants.dart'; |
| import 'package:mdns/src/lookup_resolver.dart'; |
| import 'package:mdns/src/packet.dart'; |
| +class ResourceRecordCache { |
|
Søren Gjesse
2015/11/06 08:44:48
Maybe explain how this cache works. Any reason for
karlklose
2015/11/06 12:20:00
Done.
The main reason was to control the size of
|
| + final List buffer; |
| + final int size; |
| + int position; |
| + |
| + ResourceRecordCache({int size: 32}) |
| + : buffer = new List(size), |
| + size = size, |
| + position = 0; |
| + |
| + void updateRecords(List<ResourceRecord> records) { |
| + // TODO(karlklose): include flush bit in the record and only flush if |
| + // necessary. |
| + for (int i = position; i < position + size; i++) { |
|
Søren Gjesse
2015/11/06 08:44:48
The clearing could just run from 0 to size, but ma
|
| + ResourceRecord r = buffer[i % size]; |
| + if (r == null) continue; |
| + String name = r.name; |
| + int type = r.type; |
| + for (ResourceRecord record in records) { |
| + if (name == record.name && type == record.type) { |
| + buffer[i % size] = null; |
| + break; |
| + } |
| + } |
| + } |
| + |
| + for (ResourceRecord record in records) { |
| + buffer[position] = record; |
| + position = (position + 1) % size; |
| + } |
| + } |
| + |
| + void lookup(String name, int type, List results) { |
| + int time = new DateTime.now().millisecondsSinceEpoch; |
| + for (int i = position + size; i >= position; i--) { |
| + int index = i % size; |
| + ResourceRecord record = buffer[index]; |
| + if (record == null) continue; |
| + if (record.validUntil < time) { |
| + buffer[index] = null; |
| + } else if (record.name == name && record.type == type) { |
| + results.add(record); |
| + } |
| + } |
| + } |
| +} |
| + |
| // Implementation of mDNS client using the native protocol. |
| class NativeProtocolMDnsClient implements MDnsClient { |
| bool _starting = false; |
| @@ -20,6 +67,7 @@ class NativeProtocolMDnsClient implements MDnsClient { |
| RawDatagramSocket _incoming; |
| final List<RawDatagramSocket> _sockets = <RawDatagramSocket>[]; |
| final LookupResolver _resolver = new LookupResolver(); |
| + ResourceRecordCache cache = new ResourceRecordCache(); |
| /// Start the mDNS client. |
| Future start() async { |
| @@ -62,30 +110,43 @@ class NativeProtocolMDnsClient implements MDnsClient { |
| _started = false; |
| } |
| - Future<InternetAddress> lookup( |
| - String hostname, {Duration timeout: const Duration(seconds: 5)}) { |
| + Stream<InternetAddress> lookup( |
| + int type, |
| + String name, |
| + {Duration timeout: const Duration(seconds: 5)}) { |
| if (!_started) { |
| throw new StateError('mDNS client is not started'); |
| } |
| + // Look for entries in the cache. |
| + List<ResourceRecordCache> cached = <ResourceRecord>[]; |
| + cache.lookup(name, type, cached); |
| + if (cached.isNotEmpty) { |
| + StreamController controller = new StreamController(); |
| + cached.forEach(controller.add); |
| + controller.close(); |
| + return controller.stream; |
| + } |
| + |
| // Add the pending request before sending the query. |
| - var future = _resolver.addPendingRequest(hostname, timeout); |
| + var results = _resolver.addPendingRequest(type, name, timeout); |
| // Send the request on all interfaces. |
| - List<int> packet = encodeMDnsQuery(hostname); |
| + List<int> packet = encodeMDnsQuery(name, type); |
| for (int i = 0; i < _sockets.length; i++) { |
| _sockets[i].send(packet, mDnsAddress, mDnsPort); |
| } |
| - return future; |
| + return results; |
| } |
| // Process incoming datagrams. |
| _handleIncoming(event) { |
| if (event == RawSocketEvent.READ) { |
| - var data = _incoming.receive(); |
| - var response = decodeMDnsResponse(data.data); |
| + Datagram datagram = _incoming.receive(); |
| + List<ResourceRecord> response = decodeMDnsResponse(datagram.data); |
| if (response != null) { |
| + cache.updateRecords(response); |
| _resolver.handleResponse(response); |
| } |
| } |