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

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

Issue 1416833009: Add multiple results and timeout handling to the Mac OS mDNS native extension (Closed) Base URL: git@github.com:dart-lang/fletch.git@master
Patch Set: Addressed review comments and added new SHA1 for native extension 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
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
81 throw new StateError("'target' is only supported for type SRV."); 81 throw new StateError("'target' is only supported for type SRV.");
82 } 82 }
83 return _data; 83 return _data;
84 } 84 }
85 85
86 toString() => 'RR $type $_data'; 86 toString() => 'RR $type $_data';
87 } 87 }
88 88
89 /// Result of reading a FQDN. 89 /// Result of reading a FQDN.
90 class FQDNReadResult { 90 class FQDNReadResult {
91 final List<String> fqdn; 91 final List<String> fqdnParts;
92 final int bytesRead; 92 final int bytesRead;
93 FQDNReadResult(this.fqdn, this.bytesRead); 93 String get fqdn => fqdnParts.join('.');
94 FQDNReadResult(this.fqdnParts, this.bytesRead);
95 }
96
97 String readFQDN(List<int> packet, [int offset = 0]) {
98 Uint8List data =
99 packet is Uint8List ? packet : new Uint8List.fromList(packet);
100 ByteData bd = new ByteData.view(data.buffer);
101
102 return _readFQDN(data, bd, offset, data.length).fqdn;
103 }
104
105 // Read a FQDN at the given offset. Returns a pair with the FQDN
106 // parts and the number of bytes consumed.
107 //
108 // If decoding fails (e.g. due to an invalid packet) `null` is returned.
109 FQDNReadResult _readFQDN(Uint8List data, ByteData bd, int offset, int length) {
110 void checkLength(int required) {
111 if (length < required) throw new MDnsDecodeException(required);
112 }
113
114 List<String> parts = [];
115 int prevOffset = offset;
116 while (true) {
117 // At least one byte is required.
118 checkLength(offset + 1);
119
120 // Check for compressed.
121 if (data[offset] & 0xc0 == 0xc0) {
122 // At least two bytes are required for a compressed FQDN.
123 checkLength(offset + 2);
124
125 // A compressed FQDN has a new offset in the lower 14 bits.
126 FQDNReadResult result = _readFQDN(
127 data, bd, bd.getUint16(offset) & ~0xc000, length);
128 parts.addAll(result.fqdnParts);
129 offset += 2;
130 break;
131 } else {
132 // A normal FQDN part has a length and a UTF-8 encoded name
133 // part. If the length is 0 this is the end of the FQDN.
134 var partLength = data[offset];
135 offset++;
136 if (partLength != 0) {
137 checkLength(offset + partLength);
138 var partBytes = new Uint8List.view(data.buffer, offset, partLength);
139 offset += partLength;
140 parts.add(UTF8.decode(partBytes));
141 } else {
142 break;
143 }
144 }
145 }
146 return new FQDNReadResult(parts, offset - prevOffset);
94 } 147 }
95 148
96 /// Decode a mDNS package. 149 /// Decode a mDNS package.
97 /// 150 ///
98 /// If decoding fails (e.g. due to an invalid packet) `null` is returned. 151 /// If decoding fails (e.g. due to an invalid packet) `null` is returned.
99 /// 152 ///
100 /// See https://tools.ietf.org/html/rfc1035 for the format. 153 /// See https://tools.ietf.org/html/rfc1035 for the format.
101 List<ResourceRecord> decodeMDnsResponse(List<int> packet) { 154 List<ResourceRecord> decodeMDnsResponse(List<int> packet) {
102 int length = packet.length; 155 int length = packet.length;
103 if (length < headerSize) return null; 156 if (length < headerSize) return null;
(...skipping 14 matching lines...) Expand all
118 // Number of name server records. 171 // Number of name server records.
119 int nscount = bd.getUint16(nscountOffset); 172 int nscount = bd.getUint16(nscountOffset);
120 // Number of resource records. 173 // Number of resource records.
121 int arcount = bd.getUint16(arcountOffset); 174 int arcount = bd.getUint16(arcountOffset);
122 int offset = headerSize; 175 int offset = headerSize;
123 176
124 void checkLength(int required) { 177 void checkLength(int required) {
125 if (length < required) throw new MDnsDecodeException(required); 178 if (length < required) throw new MDnsDecodeException(required);
126 } 179 }
127 180
128 // Read a FQDN at the given offset. Returns a pair with the FQDN
129 // parts and the number of bytes consumed.
130 //
131 // If decoding fails (e.g. due to an invalid packet) `null` is returned.
132 FQDNReadResult readFQDN(int offset) {
133 List<String> parts = [];
134 int prevOffset = offset;
135 while (true) {
136 // At least two bytes required.
137 checkLength(offset + 2);
138
139 // Check for compressed.
140 if (data[offset] & 0xc0 == 0xc0) {
141 // A compressed FQDN has a new offset in the lower 14 bits.
142 FQDNReadResult result = readFQDN(bd.getUint16(offset) & ~0xc000);
143 parts.addAll(result.fqdn);
144 offset += 2;
145 break;
146 } else {
147 // A normal FQDN part has a length and a UTF-8 encoded name
148 // part. If the length is 0 this is the end of the FQDN.
149 var partLength = data[offset];
150 offset++;
151 if (partLength != 0) {
152 checkLength(offset + partLength);
153 var partBytes = new Uint8List.view(data.buffer, offset, partLength);
154 offset += partLength;
155 parts.add(UTF8.decode(partBytes));
156 } else {
157 break;
158 }
159 }
160 }
161 return new FQDNReadResult(parts, offset - prevOffset);
162 }
163
164 ResourceRecord readResourceRecord() { 181 ResourceRecord readResourceRecord() {
165 // First read the FQDN. 182 // First read the FQDN.
166 FQDNReadResult result = readFQDN(offset); 183 FQDNReadResult result = _readFQDN(data, bd, offset, length);
167 var fqdn = result.fqdn.join('.'); 184 var fqdn = result.fqdn;
168 offset += result.bytesRead; 185 offset += result.bytesRead;
169 checkLength(offset + 2); 186 checkLength(offset + 2);
170 int type = bd.getUint16(offset); 187 int type = bd.getUint16(offset);
171 offset += 2; 188 offset += 2;
172 // The first bit of the rrclass field is set to indicate that the answer is 189 // 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 190 // 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. 191 // (RFC 6762, Sec. 10.2). We ignore it for now since we don't cache answers.
175 checkLength(offset + 2); 192 checkLength(offset + 2);
176 int cls = bd.getUint16(offset) & 0x7fff; 193 int cls = bd.getUint16(offset) & 0x7fff;
177 offset += 2; 194 offset += 2;
(...skipping 16 matching lines...) Expand all
194 case RRType.SRV: 211 case RRType.SRV:
195 checkLength(offset + 2); 212 checkLength(offset + 2);
196 int priority = bd.getUint16(offset); 213 int priority = bd.getUint16(offset);
197 offset += 2; 214 offset += 2;
198 checkLength(offset + 2); 215 checkLength(offset + 2);
199 int weight = bd.getUint16(offset); 216 int weight = bd.getUint16(offset);
200 offset += 2; 217 offset += 2;
201 checkLength(offset + 2); 218 checkLength(offset + 2);
202 int port = bd.getUint16(offset); 219 int port = bd.getUint16(offset);
203 offset += 2; 220 offset += 2;
204 FQDNReadResult result = readFQDN(offset); 221 FQDNReadResult result = _readFQDN(data, bd, offset, length);
205 rData = result.fqdn.join('.'); 222 rData = result.fqdn;
206 offset += rDataLength - 6; 223 offset += rDataLength - 6;
207 break; 224 break;
208 case RRType.PTR: 225 case RRType.PTR:
209 checkLength(offset + rDataLength); 226 checkLength(offset + rDataLength);
210 FQDNReadResult result = readFQDN(offset); 227 FQDNReadResult result = _readFQDN(data, bd, offset, length);
211 offset += rDataLength; 228 offset += rDataLength;
212 rData = result.fqdn.join('.'); 229 rData = result.fqdn;
213 break; 230 break;
214 case RRType.TXT: 231 case RRType.TXT:
215 // TODO(karlklose): convert to a String or Map. 232 // TODO(karlklose): convert to a String or Map.
216 default: 233 default:
217 checkLength(offset + rDataLength); 234 checkLength(offset + rDataLength);
218 rData = new Uint8List.view(data.buffer, offset, rDataLength); 235 rData = new Uint8List.view(data.buffer, offset, rDataLength);
219 offset += rDataLength; 236 offset += rDataLength;
220 break; 237 break;
221 } 238 }
222 assert(rData != null); 239 assert(rData != null);
(...skipping 23 matching lines...) Expand all
246 return result; 263 return result;
247 } 264 }
248 265
249 /// Exceptions thrown by decoder when the packet is invalid. 266 /// Exceptions thrown by decoder when the packet is invalid.
250 class MDnsDecodeException implements Exception { 267 class MDnsDecodeException implements Exception {
251 /// Exception message. 268 /// Exception message.
252 final int offset; 269 final int offset;
253 const MDnsDecodeException(this.offset); 270 const MDnsDecodeException(this.offset);
254 String toString() => 'Decoding error at $offset'; 271 String toString() => 'Decoding error at $offset';
255 } 272 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698