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

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: 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
(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 bd.setUint16(idOffset, 0);
28 bd.setUint16(flagsOffset, 0);
29 bd.setUint16(qdcountOffset, 1);
karlklose 2015/10/28 10:14:30 Maybe add comments to describe the meaning of the
Søren Gjesse 2015/10/28 11:36:57 Done.
30 bd.setUint16(ancountOffset, 0);
31 bd.setUint16(nscountOffset, 0);
32 bd.setUint16(arcountOffset, 0);
33 int offset = headerSize;
34 for (int i = 0; i < parts.length; i++) {
35 data[offset++] = parts[i].length;
36 data.setRange(offset, offset + parts[i].length, parts[i]);
37 offset += parts[i].length;
38 }
39 data[offset] = 0; // Empty part.
40 offset++;
41 bd.setUint16(offset, 1); // QTYPE.
42 offset += 2;
43 bd.setUint16(offset, 1); // QCLASS.
44
45 return data;
46 }
47
48 /// FQDN and address decoded from response.
49 class DecodeResult {
50 final String name;
51 final InternetAddress address;
52 DecodeResult(this.name, this.address);
53 }
54
55 /// Decode a mDNS package.
56 ///
57 /// If decoding fails (e.g. die to an invalid packet) `null` is returned.
karlklose 2015/10/28 10:14:31 'die' -> 'due'.
Søren Gjesse 2015/10/28 11:36:57 Done.
58 List<DecodeResult> decodeMDNSResponse(List<int> packet) {
59 int length = packet.length;
60 if (length < headerSize) return null;
61
62 Uint8List data =
63 packet is Uint8List ? packet : new Uint8List.fromList(packet);
64 ByteData bd = new ByteData.view(data.buffer);
65 int id = bd.getUint16(idOffset);
66 int flags = bd.getUint16(flagsOffset);
67
68 if (flags != responseFlags) return;
69 int qdcount = bd.getUint16(qdcountOffset);
70 int ancount = bd.getUint16(ancountOffset);
71 int nscount = bd.getUint16(nscountOffset);
72 int arcount = bd.getUint16(arcountOffset);
73 int offset = headerSize;
74
75 void checkLength(int required) {
76 if (length < required) throw new MDNSDecodeException(required);
77 }
78
79 // Read a FQDN at the given offset. Returns a pair with the FQDN
80 // parts and the number of bytes consumed.
81 //
82 // If decoding fails (e.g. die to an invalid packet) `null` is returned.
83 List readFQDN(int offset) {
karlklose 2015/10/28 10:14:30 I would prefer a few more type annotations on/in t
Søren Gjesse 2015/10/28 11:36:57 Added a type FQDNReadResult instead of using a two
84 var parts = [];
85 int prevOffset = offset;
86 while (true) {
87 // At least two bytes required.
88 checkLength(offset + 2);
89
90 // Check for compressed.
91 if (data[offset] & 0xc0 == 0xc0) {
92 // A compressed FQDN has a new offset in the lower 14 bits.
93 var pair = readFQDN(bd.getUint16(offset) & ~0xc000);
94 parts.addAll(pair[0]);
95 offset += 2;
96 break;
97 } else {
98 // A normal FQDN part has a length and a UTF-8 encoded name
99 // part. If the length is 0 this is the end of the FQDN.
100 var partLength = data[offset];
101 offset++;
102 if (partLength != 0) {
103 checkLength(offset + partLength);
104 var partBytes = new Uint8List.view(data.buffer, offset, partLength);
105 offset += partLength;
106 parts.add(UTF8.decode(partBytes));
107 } else {
108 break;
109 }
110 }
111 }
112 return [parts, offset - prevOffset];
113 }
114
115 DecodeResult readAddress() {
116 // First read the FQDN.
117 var pair = readFQDN(offset);
118 var fqdn = pair[0].join('.');
119 offset += pair[1];
120 checkLength(offset + 2);
121 int type = bd.getUint16(offset);
122 offset += 2;
123 checkLength(offset + 2);
124 int cls = bd.getUint16(offset);
125 offset += 2;
126 checkLength(offset + 4);
127 int ttl = bd.getInt32(offset);
128 offset += 4;
129 checkLength(offset + 2);
130 int addressLength = bd.getUint16(offset);
131 offset += 2;
132 checkLength(offset + addressLength);
133 var addressBytes = new Uint8List.view(data.buffer, offset, addressLength);
134 offset += addressLength;
135
136 if (type == ipV4AddressType && cls == ipV4Class && addressLength == 4) {
137 String addr = addressBytes.map((n) => n.toString()).join('.');
138 return new DecodeResult(fqdn, new InternetAddress(addr));
139 } else {
140 return null;
141 }
142 }
143
144 var result = [];
145 try {
146 while (data.length - offset >= 16) {
147 var address = readAddress();
148 if (address != null) result.add(address);
149 }
150 } on MDNSDecodeException catch (e, s) {
151 // If decoding fails return null.
152 return null;
153 }
154
155 return result;
156 }
157
158 /// Exceptions thrown by decoder when the packet is invalid.
159 class MDNSDecodeException implements Exception {
160 /// Exception message.
161 final int offset;
162 const MDNSDecodeException(this.offset);
163 String toString() => 'Decoding error at $offset';
164 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698