| Index: pkg/mdns/lib/src/packet.dart
|
| diff --git a/pkg/mdns/lib/src/packet.dart b/pkg/mdns/lib/src/packet.dart
|
| index 123517d890f73d7a7cf434feefe6cb3cfeb77319..8ae3a3907975c9f49a053372468a403442dc6e0d 100644
|
| --- a/pkg/mdns/lib/src/packet.dart
|
| +++ b/pkg/mdns/lib/src/packet.dart
|
| @@ -11,8 +11,8 @@ import 'dart:typed_data';
|
| import 'package:mdns/src/constants.dart';
|
|
|
| // Encode a mDNS query packet.
|
| -List<int> encodeMDnsQuery(String hostname) {
|
| - List parts = hostname.split('.');
|
| +List<int> encodeMDnsQuery(String name, [int type = RRType.A]) {
|
| + List parts = name.split('.');
|
|
|
| // Calculate the size of the packet.
|
| int size = headerSize;
|
| @@ -44,21 +44,49 @@ List<int> encodeMDnsQuery(String hostname) {
|
| }
|
| data[offset] = 0; // Empty part.
|
| offset++;
|
| - bd.setUint16(offset, 1); // QTYPE.
|
| + bd.setUint16(offset, type); // QTYPE.
|
| offset += 2;
|
| - bd.setUint16(offset, 1); // QCLASS.
|
| + bd.setUint16(offset, RRClass.IN | 0x8000); // QCLASS + QU.
|
|
|
| return data;
|
| }
|
|
|
| -/// FQDN and address decoded from response.
|
| -class DecodeResult {
|
| +/// Partial implementation of DNS resource records (RRs).
|
| +class ResourceRecord {
|
| + final int type;
|
| final String name;
|
| - final InternetAddress address;
|
| - DecodeResult(this.name, this.address);
|
| + final _data;
|
| + final int validUntil;
|
| + // TODO(karlklose): add missing header bits.
|
| +
|
| + ResourceRecord(this.type, this.name, this._data, this.validUntil);
|
| +
|
| + InternetAddress get address {
|
| + if (type != RRType.A) {
|
| + // TODO(karlklose): add IPv6 address support.
|
| + throw new StateError("'address' is only supported for type A.");
|
| + }
|
| + return _data;
|
| + }
|
| +
|
| + String get domainName {
|
| + if (type != RRType.PTR) {
|
| + throw new StateError("'domain name' is only supported for type PTR.");
|
| + }
|
| + return _data;
|
| + }
|
| +
|
| + String get target {
|
| + if (type != RRType.SRV) {
|
| + throw new StateError("'target' is only supported for type SRV.");
|
| + }
|
| + return _data;
|
| + }
|
| +
|
| + toString() => 'RR $type $_data';
|
| }
|
|
|
| -/// Result of reading a FQDN. The FQDN parts and the bytes consumed.
|
| +/// Result of reading a FQDN.
|
| class FQDNReadResult {
|
| final List<String> fqdn;
|
| final int bytesRead;
|
| @@ -70,7 +98,7 @@ class FQDNReadResult {
|
| /// If decoding fails (e.g. due to an invalid packet) `null` is returned.
|
| ///
|
| /// See https://tools.ietf.org/html/rfc1035 for the format.
|
| -List<DecodeResult> decodeMDnsResponse(List<int> packet) {
|
| +List<ResourceRecord> decodeMDnsResponse(List<int> packet) {
|
| int length = packet.length;
|
| if (length < headerSize) return null;
|
|
|
| @@ -133,7 +161,7 @@ List<DecodeResult> decodeMDnsResponse(List<int> packet) {
|
| return new FQDNReadResult(parts, offset - prevOffset);
|
| }
|
|
|
| - DecodeResult readAddress() {
|
| + ResourceRecord readResourceRecord() {
|
| // First read the FQDN.
|
| FQDNReadResult result = readFQDN(offset);
|
| var fqdn = result.fqdn.join('.');
|
| @@ -141,40 +169,80 @@ List<DecodeResult> decodeMDnsResponse(List<int> packet) {
|
| checkLength(offset + 2);
|
| int type = bd.getUint16(offset);
|
| offset += 2;
|
| + // The first bit of the rrclass field is set to indicate that the answer is
|
| + // unique and the querier should flush the cached answer for this name
|
| + // (RFC 6762, Sec. 10.2). We ignore it for now since we don't cache answers.
|
| checkLength(offset + 2);
|
| - int cls = bd.getUint16(offset);
|
| + int cls = bd.getUint16(offset) & 0x7fff;
|
| offset += 2;
|
| checkLength(offset + 4);
|
| int ttl = bd.getInt32(offset);
|
| offset += 4;
|
| +
|
| + var rData;
|
| checkLength(offset + 2);
|
| - int addressLength = bd.getUint16(offset);
|
| + int rDataLength = bd.getUint16(offset);
|
| offset += 2;
|
| - checkLength(offset + addressLength);
|
| - var addressBytes = new Uint8List.view(data.buffer, offset, addressLength);
|
| - offset += addressLength;
|
| -
|
| - if (type == ipV4AddressType && cls == ipV4Class && addressLength == 4) {
|
| - String addr = addressBytes.map((n) => n.toString()).join('.');
|
| - return new DecodeResult(fqdn, new InternetAddress(addr));
|
| - } else {
|
| + switch (type) {
|
| + case RRType.A:
|
| + checkLength(offset + rDataLength);
|
| + rData = new Uint8List.view(data.buffer, offset, rDataLength);
|
| + String addr = rData.map((n) => n.toString()).join('.');
|
| + rData = new InternetAddress(addr);
|
| + offset += rDataLength;
|
| + break;
|
| + case RRType.SRV:
|
| + checkLength(offset + 2);
|
| + int priority = bd.getUint16(offset);
|
| + offset += 2;
|
| + checkLength(offset + 2);
|
| + int weight = bd.getUint16(offset);
|
| + offset += 2;
|
| + checkLength(offset + 2);
|
| + int port = bd.getUint16(offset);
|
| + offset += 2;
|
| + FQDNReadResult result = readFQDN(offset);
|
| + rData = result.fqdn.join('.');
|
| + offset += rDataLength - 6;
|
| + break;
|
| + case RRType.PTR:
|
| + checkLength(offset + rDataLength);
|
| + FQDNReadResult result = readFQDN(offset);
|
| + offset += rDataLength;
|
| + rData = result.fqdn.join('.');
|
| + break;
|
| + case RRType.TXT:
|
| + // TODO(karlklose): convert to a String or Map.
|
| + default:
|
| + checkLength(offset + rDataLength);
|
| + rData = new Uint8List.view(data.buffer, offset, rDataLength);
|
| + offset += rDataLength;
|
| + break;
|
| + }
|
| + assert(rData != null);
|
| +
|
| + if (cls != RRClass.IN) {
|
| + // We do not support other classes at the moment.
|
| return null;
|
| }
|
| +
|
| + int validUntil = new DateTime.now().millisecondsSinceEpoch +
|
| + ttl * 1000;
|
| + return new ResourceRecord(type, fqdn, rData, validUntil);
|
| }
|
|
|
| - // We don't use the number of records - just read through all
|
| - // resource records and filter.
|
| - var result = [];
|
| + List<ResourceRecord> result = <ResourceRecord>[];
|
| try {
|
| - while (data.length - offset >= 16) {
|
| - var address = readAddress();
|
| - if (address != null) result.add(address);
|
| + for (int i = 0; i < ancount; i++) {
|
| + ResourceRecord record = readResourceRecord();
|
| + if (record != null) {
|
| + result.add(record);
|
| + }
|
| }
|
| } on MDnsDecodeException catch (e, s) {
|
| // If decoding fails return null.
|
| return null;
|
| }
|
| -
|
| return result;
|
| }
|
|
|
|
|