Skip to content

Commit

Permalink
update Codec and RDataCodecs
Browse files Browse the repository at this point in the history
  • Loading branch information
ethan-tbd committed Apr 17, 2024
1 parent fc9436b commit 8e8d59e
Show file tree
Hide file tree
Showing 8 changed files with 402 additions and 415 deletions.
160 changes: 82 additions & 78 deletions packages/web5/lib/src/dids/did_dht/dns/answer.dart
Original file line number Diff line number Diff line change
Expand Up @@ -65,13 +65,13 @@ class Answer<T extends RData> {

Answer._();

static Codec<Answer> codec = Codec<Answer>(_encode, _decode);
static final codec = _AnswerCodec();

/// Decodes a [Answer] from a byte buffer [buf] starting at the given [offset].
///
/// Throws [FormatException] if the buffer data cannot be decoded into a valid DNS answer.
factory Answer.decode(Uint8List buf, int offset) =>
codec.decode(buf, offset: offset).value;
codec.decode(buf, offset: offset).value as Answer<T>;

Uint8List encode({Uint8List? buf, int offset = 0}) =>
codec.encode(this, input: buf, offset: offset).value;
Expand All @@ -81,96 +81,100 @@ class Answer<T extends RData> {
}
}

Encode<Answer> _encode = (
Answer answer, {
Uint8List? input,
int offset = 0,
}) {
final buf = input ?? Uint8List(answer.encodingLength());
final oldOffset = offset;

final n = RecordName.codec.encode(answer.name, input: buf, offset: offset);
offset += n.offset;

ByteData.view(buf.buffer).setUint16(offset, answer.type.value, Endian.big);

if (answer.type == RecordType.OPT) {
if (answer.name.value != '.') {
throw Exception('OPT name must be root.');
class _AnswerCodec implements Codec<Answer> {
@override
EncodeResult encode(
Answer answer, {
Uint8List? input,
int offset = 0,
}) {
final buf = input ?? Uint8List(answer.encodingLength());
final oldOffset = offset;

final n = RecordName.codec.encode(answer.name, input: buf, offset: offset);
offset += n.offset;

ByteData.view(buf.buffer).setUint16(offset, answer.type.value, Endian.big);

if (answer.type == RecordType.OPT) {
if (answer.name.value != '.') {
throw Exception('OPT name must be root.');
}
ByteData.view(buf.buffer)
.setUint16(offset, answer.udpPayloadSize!, Endian.big);

buf[offset + 4] = answer.extendedRcode!;
buf[offset + 5] = answer.ednsVersion!;

ByteData.view(buf.buffer)
.setUint16(offset + 6, answer.flags ?? 0, Endian.big);

offset += 8;
// TODO: need OptDataCodec here
offset += answer.options.encode(buf, offset) as int;
} else {
final klassValue = answer.flush ? FLUSH_MASK : answer.klass.value;
ByteData.view(buf.buffer).setUint16(offset + 2, klassValue, Endian.big);

ByteData.view(buf.buffer).setUint32(offset + 4, answer.ttl, Endian.big);

offset += 8;

final result = RDataCodecs.encode(
answer.type,
answer.data,
input: buf,
offset: offset,
);
offset += result.offset;
}
ByteData.view(buf.buffer)
.setUint16(offset, answer.udpPayloadSize!, Endian.big);

buf[offset + 4] = answer.extendedRcode!;
buf[offset + 5] = answer.ednsVersion!;

ByteData.view(buf.buffer)
.setUint16(offset + 6, answer.flags ?? 0, Endian.big);

offset += 8;
// TODO: need OptDataCodec here
offset += answer.options.encode(buf, offset) as int;
} else {
final klassValue = answer.flush ? FLUSH_MASK : answer.klass.value;
ByteData.view(buf.buffer).setUint16(offset + 2, klassValue, Endian.big);

ByteData.view(buf.buffer).setUint32(offset + 4, answer.ttl, Endian.big);

offset += 8;

final result = RdataCodecs.encode(
answer.type,
answer.data,
input: buf,
offset: offset,
);
offset += result.offset;
return EncodeResult(buf, offset - oldOffset);
}

return EncodeResult(buf, offset - oldOffset);
};
@override
DecodeResult<Answer> decode(Uint8List buf, {int offset = 0}) {
final originalOffset = offset;

Decode _decode = (Uint8List buf, {int offset = 0}) {
final originalOffset = offset;
final nameResult = RecordName.codec.decode(buf, offset: offset);
offset += nameResult.offset;

final nameResult = RecordName.codec.decode(buf, offset: offset);
offset += nameResult.offset;
final byteData = ByteData.sublistView(buf);

final byteData = ByteData.sublistView(buf);
final rawType = byteData.getUint16(offset, Endian.big);
final type = RecordType.fromValue(rawType);
offset += 2;

final rawType = byteData.getUint16(offset, Endian.big);
final type = RecordType.fromValue(rawType);
offset += 2;
final answer = Answer._();
answer.name = nameResult.value;
answer.type = type;

final answer = Answer._();
answer.name = nameResult.value;
answer.type = type;
if (type == RecordType.OPT) {
answer.udpPayloadSize = byteData.getUint16(offset + 2, Endian.big);
answer.extendedRcode = byteData.getUint8(offset + 4);
answer.ednsVersion = byteData.getUint8(offset + 5);

if (type == RecordType.OPT) {
answer.udpPayloadSize = byteData.getUint16(offset + 2, Endian.big);
answer.extendedRcode = byteData.getUint8(offset + 4);
answer.ednsVersion = byteData.getUint8(offset + 5);
answer.flags = byteData.getUint16(offset + 6, Endian.big);
answer.flagDo = (answer.flags! >> 15) & 0x1 == 1;

answer.flags = byteData.getUint16(offset + 6, Endian.big);
answer.flagDo = (answer.flags! >> 15) & 0x1 == 1;
answer.options = OptionData.decode(buf, offset + 8);

answer.options = OptionData.decode(buf, offset + 8);
offset += (8 + answer.options.numBytes).toInt();
} else {
final rawDnsClass = byteData.getUint16(offset, Endian.big);
answer.klass = RecordClass.fromValue(rawDnsClass & NOT_FLUSH_MASK);

offset += (8 + answer.options.numBytes).toInt();
} else {
final rawDnsClass = byteData.getUint16(offset, Endian.big);
answer.klass = RecordClass.fromValue(rawDnsClass & NOT_FLUSH_MASK);
answer.flush = (rawDnsClass & FLUSH_MASK) != 0;
offset += 2;

answer.flush = (rawDnsClass & FLUSH_MASK) != 0;
offset += 2;
answer.ttl = byteData.getUint32(offset, Endian.big);
offset += 4;

answer.ttl = byteData.getUint32(offset, Endian.big);
offset += 4;
final result = RDataCodecs.decode(type, buf, offset: offset);
answer.data = result.value;
offset += result.offset;
}

final result = RdataCodecs.decode(type, buf);
answer.data = result.value;
offset += result.offset;
return DecodeResult(answer, offset - originalOffset);
}

return DecodeResult(answer, offset - originalOffset);
};
}
20 changes: 4 additions & 16 deletions packages/web5/lib/src/dids/did_dht/dns/codec.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import 'dart:typed_data';

import 'package:web5/src/dids/did_dht/dns/record_type.dart';
abstract interface class Codec<T> {
EncodeResult encode(T value, {Uint8List? input, int offset});
DecodeResult<T> decode(Uint8List buf, {int offset});
}

class EncodeResult {
final Uint8List value;
Expand All @@ -15,18 +18,3 @@ class DecodeResult<T> {

DecodeResult(this.value, this.offset);
}

typedef Decode = DecodeResult<dynamic> Function(Uint8List buf, {int offset});
typedef Encode<T> = EncodeResult Function(
T value, {
Uint8List? input,
int offset,
});

class Codec<T> {
Encode<T> encode;
Decode decode;
RecordType? type;

Codec(this.encode, this.decode, {this.type});
}
126 changes: 63 additions & 63 deletions packages/web5/lib/src/dids/did_dht/dns/header.dart
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ class Header {
required this.arcount,
});

static Codec<Header> codec = Codec<Header>(_encode, _decode);
static final codec = _HeaderCodec();

factory Header.decode(Uint8List buf, {int offset = 0}) =>
codec.decode(buf, offset: offset).value;
Expand All @@ -86,65 +86,65 @@ class Header {
int encodingLength() => numBytes;
}

Encode<Header> _encode = (
Header header, {
Uint8List? input,
int offset = 0,
}) {
final buf = input ?? Uint8List(12);
final byteData = ByteData.sublistView(buf);

byteData.setUint16(offset, header.id, Endian.big);
offset += 2;

final flags = (header.qr ? 1 : 0) << 15 |
(header.opcode.value & 0xF) << 11 |
(header.aa ?? false ? 1 : 0) << 10 |
(header.tc ? 1 : 0) << 9 |
(header.rd ? 1 : 0) << 8 |
(header.ra ?? false ? 1 : 0) << 7 |
(header.z ? 1 : 0) << 6 |
(header.ad ?? false ? 1 : 0) << 5 |
(header.cd ?? false ? 1 : 0) << 4 |
(header.rcode?.value ?? 0) & 0xF;

byteData.setUint16(offset, flags, Endian.big);
offset += 2;

byteData.setUint16(offset, header.qdcount, Endian.big);
offset += 2;
byteData.setUint16(offset, header.ancount, Endian.big);
offset += 2;
byteData.setUint16(offset, header.nscount, Endian.big);
offset += 2;
byteData.setUint16(offset, header.arcount, Endian.big);

return EncodeResult(buf, 12);
};

Decode _decode = (Uint8List buf, {int offset = 0}) {
if (buf.length < 12) throw Exception('Header must be 12 bytes');

final byteData = ByteData.sublistView(buf);
final flags = byteData.getUint16(offset + 2, Endian.big);

final header = Header(
id: byteData.getUint16(offset, Endian.big),
qr: (flags >> 15) & 0x1 == 1,
opcode: OpCode.fromValue((flags >> 11) & 0xf),
aa: (flags >> 10) & 0x1 == 1,
tc: (flags >> 9) & 0x1 == 1,
rd: (flags >> 8) & 0x1 == 1,
ra: (flags >> 7) & 0x1 == 1,
z: (flags >> 6) & 0x1 == 1,
ad: (flags >> 5) & 0x1 == 1,
cd: (flags >> 4) & 0x1 == 1,
rcode: RCode.fromValue(flags & 0xf),
qdcount: byteData.getUint16(offset + 4, Endian.big),
ancount: byteData.getUint16(offset + 6, Endian.big),
nscount: byteData.getUint16(offset + 8, Endian.big),
arcount: byteData.getUint16(offset + 10, Endian.big),
);

return DecodeResult(header, 12);
};
class _HeaderCodec implements Codec<Header> {
@override
EncodeResult encode(Header header, {Uint8List? input, int offset = 0}) {
final buf = input ?? Uint8List(12);
final byteData = ByteData.sublistView(buf);

byteData.setUint16(offset, header.id, Endian.big);
offset += 2;

final flags = (header.qr ? 1 : 0) << 15 |
(header.opcode.value & 0xF) << 11 |
(header.aa ?? false ? 1 : 0) << 10 |
(header.tc ? 1 : 0) << 9 |
(header.rd ? 1 : 0) << 8 |
(header.ra ?? false ? 1 : 0) << 7 |
(header.z ? 1 : 0) << 6 |
(header.ad ?? false ? 1 : 0) << 5 |
(header.cd ?? false ? 1 : 0) << 4 |
(header.rcode?.value ?? 0) & 0xF;

byteData.setUint16(offset, flags, Endian.big);
offset += 2;

byteData.setUint16(offset, header.qdcount, Endian.big);
offset += 2;
byteData.setUint16(offset, header.ancount, Endian.big);
offset += 2;
byteData.setUint16(offset, header.nscount, Endian.big);
offset += 2;
byteData.setUint16(offset, header.arcount, Endian.big);

return EncodeResult(buf, 12);
}

@override
DecodeResult<Header> decode(Uint8List buf, {int offset = 0}) {
if (buf.length < 12) throw Exception('Header must be 12 bytes');

final byteData = ByteData.sublistView(buf);
final flags = byteData.getUint16(offset + 2, Endian.big);

final header = Header(
id: byteData.getUint16(offset, Endian.big),
qr: (flags >> 15) & 0x1 == 1,
opcode: OpCode.fromValue((flags >> 11) & 0xf),
aa: (flags >> 10) & 0x1 == 1,
tc: (flags >> 9) & 0x1 == 1,
rd: (flags >> 8) & 0x1 == 1,
ra: (flags >> 7) & 0x1 == 1,
z: (flags >> 6) & 0x1 == 1,
ad: (flags >> 5) & 0x1 == 1,
cd: (flags >> 4) & 0x1 == 1,
rcode: RCode.fromValue(flags & 0xf),
qdcount: byteData.getUint16(offset + 4, Endian.big),
ancount: byteData.getUint16(offset + 6, Endian.big),
nscount: byteData.getUint16(offset + 8, Endian.big),
arcount: byteData.getUint16(offset + 10, Endian.big),
);

return DecodeResult(header, 12);
}
}
Loading

0 comments on commit 8e8d59e

Please sign in to comment.