Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1030)

Side by Side Diff: pkg/mdns/lib/src/packet.dart

Issue 1412063015: Improve resource record implementation in the mdns package. (Closed) Base URL: https://github.com/dart-lang/fletch.git@master
Patch Set: Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 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 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. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 library mdns.src.packet; 5 library mdns.src.packet;
6 6
7 import 'dart:convert'; 7 import 'dart:convert';
8 import 'dart:io'; 8 import 'dart:io';
9 import 'dart:typed_data'; 9 import 'dart:typed_data';
10 10
11 import 'package:mdns/src/constants.dart'; 11 import 'package:mdns/src/constants.dart';
12 12
13 // Encode a mDNS query packet. 13 // Encode a mDNS query packet.
14 List<int> encodeMDnsQuery(String hostname) { 14 List<int> encodeMDnsQuery(String name, [int type = RRType.A]) {
15 List parts = hostname.split('.'); 15 List parts = name.split('.');
16 16
17 // Calculate the size of the packet. 17 // Calculate the size of the packet.
18 int size = headerSize; 18 int size = headerSize;
19 for (int i = 0; i < parts.length; i++) { 19 for (int i = 0; i < parts.length; i++) {
20 parts[i] = UTF8.encode(parts[i]); 20 parts[i] = UTF8.encode(parts[i]);
21 size += 1 + parts[i].length; 21 size += 1 + parts[i].length;
22 } 22 }
23 size += 1; // End with empty part 23 size += 1; // End with empty part
24 size += 4; // Trailer (QTYPE and QCLASS). 24 size += 4; // Trailer (QTYPE and QCLASS).
25 Uint8List data = new Uint8List(size); 25 Uint8List data = new Uint8List(size);
(...skipping 11 matching lines...) Expand all
37 // Number of resource records - 0 for query. 37 // Number of resource records - 0 for query.
38 bd.setUint16(arcountOffset, 0); 38 bd.setUint16(arcountOffset, 0);
39 int offset = headerSize; 39 int offset = headerSize;
40 for (int i = 0; i < parts.length; i++) { 40 for (int i = 0; i < parts.length; i++) {
41 data[offset++] = parts[i].length; 41 data[offset++] = parts[i].length;
42 data.setRange(offset, offset + parts[i].length, parts[i]); 42 data.setRange(offset, offset + parts[i].length, parts[i]);
43 offset += parts[i].length; 43 offset += parts[i].length;
44 } 44 }
45 data[offset] = 0; // Empty part. 45 data[offset] = 0; // Empty part.
46 offset++; 46 offset++;
47 bd.setUint16(offset, 1); // QTYPE. 47 bd.setUint16(offset, type); // QTYPE.
48 offset += 2; 48 offset += 2;
49 bd.setUint16(offset, 1); // QCLASS. 49 bd.setUint16(offset, RRClass.IN | 0x8000); // QCLASS + QU.
50 50
51 return data; 51 return data;
52 } 52 }
53 53
54 /// FQDN and address decoded from response. 54 /// Partial implementation of DNS resource records (RRs).
55 class DecodeResult { 55 class ResourceRecord {
56 final int type;
56 final String name; 57 final String name;
57 final InternetAddress address; 58 final _data;
58 DecodeResult(this.name, this.address); 59 final int validUntil;
60 // TODO(karlklose): add missing header bits.
61
62 ResourceRecord(this.type, this.name, this._data, this.validUntil);
63
64 InternetAddress get address {
65 if (type != RRType.A) {
66 // TODO(karlklose): add IPv6 address support.
67 throw new StateError("'address' is only supported for type A.");
68 }
69 return _data;
70 }
71
72 String get domainName {
73 if (type != RRType.PTR) {
74 throw new StateError("'domain name' is only supported for type PTR.");
75 }
76 return _data;
77 }
78
79 String get target {
80 if (type != RRType.SRV) {
81 throw new StateError("'target' is only supported for type SRV.");
82 }
83 return _data;
84 }
85
86 toString() => 'RR $type $_data';
59 } 87 }
60 88
61 /// Result of reading a FQDN. The FQDN parts and the bytes consumed. 89 /// Result of reading a FQDN.
62 class FQDNReadResult { 90 class FQDNReadResult {
63 final List<String> fqdn; 91 final List<String> fqdn;
64 final int bytesRead; 92 final int bytesRead;
65 FQDNReadResult(this.fqdn, this.bytesRead); 93 FQDNReadResult(this.fqdn, this.bytesRead);
66 } 94 }
67 95
68 /// Decode a mDNS package. 96 /// Decode a mDNS package.
69 /// 97 ///
70 /// If decoding fails (e.g. due to an invalid packet) `null` is returned. 98 /// If decoding fails (e.g. due to an invalid packet) `null` is returned.
71 /// 99 ///
72 /// See https://tools.ietf.org/html/rfc1035 for the format. 100 /// See https://tools.ietf.org/html/rfc1035 for the format.
73 List<DecodeResult> decodeMDnsResponse(List<int> packet) { 101 List<ResourceRecord> decodeMDnsResponse(List<int> packet) {
74 int length = packet.length; 102 int length = packet.length;
75 if (length < headerSize) return null; 103 if (length < headerSize) return null;
76 104
77 Uint8List data = 105 Uint8List data =
78 packet is Uint8List ? packet : new Uint8List.fromList(packet); 106 packet is Uint8List ? packet : new Uint8List.fromList(packet);
79 ByteData bd = new ByteData.view(data.buffer); 107 ByteData bd = new ByteData.view(data.buffer);
80 // Query identifier. 108 // Query identifier.
81 int id = bd.getUint16(idOffset); 109 int id = bd.getUint16(idOffset);
82 // Flags. 110 // Flags.
83 int flags = bd.getUint16(flagsOffset); 111 int flags = bd.getUint16(flagsOffset);
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
126 offset += partLength; 154 offset += partLength;
127 parts.add(UTF8.decode(partBytes)); 155 parts.add(UTF8.decode(partBytes));
128 } else { 156 } else {
129 break; 157 break;
130 } 158 }
131 } 159 }
132 } 160 }
133 return new FQDNReadResult(parts, offset - prevOffset); 161 return new FQDNReadResult(parts, offset - prevOffset);
134 } 162 }
135 163
136 DecodeResult readAddress() { 164 ResourceRecord readResourceRecord() {
137 // First read the FQDN. 165 // First read the FQDN.
138 FQDNReadResult result = readFQDN(offset); 166 FQDNReadResult result = readFQDN(offset);
139 var fqdn = result.fqdn.join('.'); 167 var fqdn = result.fqdn.join('.');
140 offset += result.bytesRead; 168 offset += result.bytesRead;
141 checkLength(offset + 2); 169 checkLength(offset + 2);
142 int type = bd.getUint16(offset); 170 int type = bd.getUint16(offset);
143 offset += 2; 171 offset += 2;
172 // The first bit of the rrclass field is set to indicate that the answer is
173 // unique and the querier should flush the cached answer for this name
174 // (RFC 6762, Sec. 10.2). We ignore it for now since we don't cache answers.
144 checkLength(offset + 2); 175 checkLength(offset + 2);
145 int cls = bd.getUint16(offset); 176 int cls = bd.getUint16(offset) & 0x7fff;
146 offset += 2; 177 offset += 2;
147 checkLength(offset + 4); 178 checkLength(offset + 4);
148 int ttl = bd.getInt32(offset); 179 int ttl = bd.getInt32(offset);
149 offset += 4; 180 offset += 4;
181
182 var rData;
150 checkLength(offset + 2); 183 checkLength(offset + 2);
151 int addressLength = bd.getUint16(offset); 184 int rDataLength = bd.getUint16(offset);
152 offset += 2; 185 offset += 2;
153 checkLength(offset + addressLength); 186 switch (type) {
154 var addressBytes = new Uint8List.view(data.buffer, offset, addressLength); 187 case RRType.A:
155 offset += addressLength; 188 checkLength(offset + rDataLength);
189 rData = new Uint8List.view(data.buffer, offset, rDataLength);
190 String addr = rData.map((n) => n.toString()).join('.');
191 rData = new InternetAddress(addr);
192 offset += rDataLength;
193 break;
194 case RRType.SRV:
195 checkLength(offset + 2);
196 int priority = bd.getUint16(offset);
197 offset += 2;
198 checkLength(offset + 2);
199 int weight = bd.getUint16(offset);
200 offset += 2;
201 checkLength(offset + 2);
202 int port = bd.getUint16(offset);
203 offset += 2;
204 FQDNReadResult result = readFQDN(offset);
205 rData = result.fqdn.join('.');
206 offset += rDataLength - 6;
207 break;
208 case RRType.PTR:
209 checkLength(offset + rDataLength);
210 FQDNReadResult result = readFQDN(offset);
211 offset += rDataLength;
212 rData = result.fqdn.join('.');
213 break;
214 case RRType.TXT:
215 // TODO(karlklose): convert to a String or Map.
216 default:
217 checkLength(offset + rDataLength);
218 rData = new Uint8List.view(data.buffer, offset, rDataLength);
219 offset += rDataLength;
220 break;
221 }
222 assert(rData != null);
156 223
157 if (type == ipV4AddressType && cls == ipV4Class && addressLength == 4) { 224 if (cls != RRClass.IN) {
158 String addr = addressBytes.map((n) => n.toString()).join('.'); 225 // We do not support other classes at the moment.
159 return new DecodeResult(fqdn, new InternetAddress(addr));
160 } else {
161 return null; 226 return null;
162 } 227 }
228
229 int validUntil = new DateTime.now().millisecondsSinceEpoch +
230 ttl * 1000;
231 return new ResourceRecord(type, fqdn, rData, validUntil);
163 } 232 }
164 233
165 // We don't use the number of records - just read through all 234 List<ResourceRecord> result = <ResourceRecord>[];
166 // resource records and filter.
167 var result = [];
168 try { 235 try {
169 while (data.length - offset >= 16) { 236 for (int i = 0; i < ancount; i++) {
170 var address = readAddress(); 237 ResourceRecord record = readResourceRecord();
171 if (address != null) result.add(address); 238 if (record != null) {
239 result.add(record);
240 }
172 } 241 }
173 } on MDnsDecodeException catch (e, s) { 242 } on MDnsDecodeException catch (e, s) {
174 // If decoding fails return null. 243 // If decoding fails return null.
175 return null; 244 return null;
176 } 245 }
177
178 return result; 246 return result;
179 } 247 }
180 248
181 /// Exceptions thrown by decoder when the packet is invalid. 249 /// Exceptions thrown by decoder when the packet is invalid.
182 class MDnsDecodeException implements Exception { 250 class MDnsDecodeException implements Exception {
183 /// Exception message. 251 /// Exception message.
184 final int offset; 252 final int offset;
185 const MDnsDecodeException(this.offset); 253 const MDnsDecodeException(this.offset);
186 String toString() => 'Decoding error at $offset'; 254 String toString() => 'Decoding error at $offset';
187 } 255 }
OLDNEW
« pkg/mdns/lib/src/native_protocol_client.dart ('K') | « pkg/mdns/lib/src/native_protocol_client.dart ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698