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

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

Issue 1426863003: Add a mDNS package (Closed) Base URL: git@github.com:dart-lang/fletch.git@master
Patch Set: Addressed review comments 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
« no previous file with comments | « pkg/mdns/lib/src/lookup_resolver.dart ('k') | pkg/mdns/test/decode_test.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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
3 // BSD-style license that can be found in the LICENSE file.
4
5 library mdns.src.packet;
6
7 import 'dart:convert';
8 import 'dart:io';
9 import 'dart:typed_data';
10
11 import 'package:mdns/src/constants.dart';
12
13 // Encode a mDNS query packet.
14 List<int> encodeMDnsQuery(String hostname) {
15 List parts = hostname.split('.');
16
17 // Calculate the size of the packet.
18 int size = headerSize;
19 for (int i = 0; i < parts.length; i++) {
20 parts[i] = UTF8.encode(parts[i]);
21 size += 1 + parts[i].length;
22 }
23 size += 1; // End with empty part
24 size += 4; // Trailer (QTYPE and QCLASS).
25 Uint8List data = new Uint8List(size);
26 ByteData bd = new ByteData.view(data.buffer);
27 // Query identifier - just use 0.
28 bd.setUint16(idOffset, 0);
29 // Flags - 0 for query.
30 bd.setUint16(flagsOffset, 0);
31 // Query count.
32 bd.setUint16(qdcountOffset, 1);
33 // Number of answers - 0 for query.
34 bd.setUint16(ancountOffset, 0);
35 // Number of name server records - 0 for query.
36 bd.setUint16(nscountOffset, 0);
37 // Number of resource records - 0 for query.
38 bd.setUint16(arcountOffset, 0);
39 int offset = headerSize;
40 for (int i = 0; i < parts.length; i++) {
41 data[offset++] = parts[i].length;
42 data.setRange(offset, offset + parts[i].length, parts[i]);
43 offset += parts[i].length;
44 }
45 data[offset] = 0; // Empty part.
46 offset++;
47 bd.setUint16(offset, 1); // QTYPE.
48 offset += 2;
49 bd.setUint16(offset, 1); // QCLASS.
50
51 return data;
52 }
53
54 /// FQDN and address decoded from response.
55 class DecodeResult {
56 final String name;
57 final InternetAddress address;
58 DecodeResult(this.name, this.address);
59 }
60
61 /// Result of reading a FQDN. The FQDN parts and the bytes consumed.
62 class FQDNReadResult {
63 final List<String> fqdn;
64 final int bytesRead;
65 FQDNReadResult(this.fqdn, this.bytesRead);
66 }
67
68 /// Decode a mDNS package.
69 ///
70 /// If decoding fails (e.g. due to an invalid packet) `null` is returned.
71 ///
72 /// See See https://tools.ietf.org/html/rfc1035 for the format.
karlklose 2015/10/29 10:29:44 'See See' -> 'See'.
73 List<DecodeResult> decodeMDnsResponse(List<int> packet) {
74 int length = packet.length;
75 if (length < headerSize) return null;
76
77 Uint8List data =
78 packet is Uint8List ? packet : new Uint8List.fromList(packet);
79 ByteData bd = new ByteData.view(data.buffer);
80 // Query identifier.
81 int id = bd.getUint16(idOffset);
82 // Flags.
83 int flags = bd.getUint16(flagsOffset);
84
85 if (flags != responseFlags) return;
86 // Query count.
87 int qdcount = bd.getUint16(qdcountOffset);
88 // Number of answers.
89 int ancount = bd.getUint16(ancountOffset);
90 // Number of name server records.
91 int nscount = bd.getUint16(nscountOffset);
92 // Number of resource records.
93 int arcount = bd.getUint16(arcountOffset);
94 int offset = headerSize;
95
96 void checkLength(int required) {
97 if (length < required) throw new MDnsDecodeException(required);
98 }
99
100 // Read a FQDN at the given offset. Returns a pair with the FQDN
101 // parts and the number of bytes consumed.
102 //
103 // If decoding fails (e.g. die to an invalid packet) `null` is returned.
104 FQDNReadResult readFQDN(int offset) {
105 List<String> parts = [];
106 int prevOffset = offset;
107 while (true) {
108 // At least two bytes required.
109 checkLength(offset + 2);
110
111 // Check for compressed.
112 if (data[offset] & 0xc0 == 0xc0) {
113 // A compressed FQDN has a new offset in the lower 14 bits.
114 FQDNReadResult result = readFQDN(bd.getUint16(offset) & ~0xc000);
115 parts.addAll(result.fqdn);
116 offset += 2;
117 break;
118 } else {
119 // A normal FQDN part has a length and a UTF-8 encoded name
120 // part. If the length is 0 this is the end of the FQDN.
121 var partLength = data[offset];
122 offset++;
123 if (partLength != 0) {
124 checkLength(offset + partLength);
125 var partBytes = new Uint8List.view(data.buffer, offset, partLength);
126 offset += partLength;
127 parts.add(UTF8.decode(partBytes));
128 } else {
129 break;
130 }
131 }
132 }
133 return new FQDNReadResult(parts, offset - prevOffset);
134 }
135
136 DecodeResult readAddress() {
137 // First read the FQDN.
138 FQDNReadResult result = readFQDN(offset);
139 var fqdn = result.fqdn.join('.');
140 offset += result.bytesRead;
141 checkLength(offset + 2);
142 int type = bd.getUint16(offset);
143 offset += 2;
144 checkLength(offset + 2);
145 int cls = bd.getUint16(offset);
146 offset += 2;
147 checkLength(offset + 4);
148 int ttl = bd.getInt32(offset);
149 offset += 4;
150 checkLength(offset + 2);
151 int addressLength = bd.getUint16(offset);
152 offset += 2;
153 checkLength(offset + addressLength);
154 var addressBytes = new Uint8List.view(data.buffer, offset, addressLength);
155 offset += addressLength;
156
157 if (type == ipV4AddressType && cls == ipV4Class && addressLength == 4) {
158 String addr = addressBytes.map((n) => n.toString()).join('.');
159 return new DecodeResult(fqdn, new InternetAddress(addr));
160 } else {
161 return null;
162 }
163 }
164
165 // We don't use the number of records - just read through all
166 // resource records and filter.
167 var result = [];
168 try {
169 while (data.length - offset >= 16) {
170 var address = readAddress();
171 if (address != null) result.add(address);
172 }
173 } on MDnsDecodeException catch (e, s) {
174 // If decoding fails return null.
175 return null;
176 }
177
178 return result;
179 }
180
181 /// Exceptions thrown by decoder when the packet is invalid.
182 class MDnsDecodeException implements Exception {
183 /// Exception message.
184 final int offset;
185 const MDnsDecodeException(this.offset);
186 String toString() => 'Decoding error at $offset';
187 }
OLDNEW
« no previous file with comments | « pkg/mdns/lib/src/lookup_resolver.dart ('k') | pkg/mdns/test/decode_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698