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