RaspberryIO/Unosquare.Swan/Networking/DnsClient.Response.cs
2019-12-03 18:44:25 +01:00

205 lines
6.2 KiB
C#

using Unosquare.Swan.Formatters;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
namespace Unosquare.Swan.Networking {
/// <summary>
/// DnsClient Response inner class.
/// </summary>
internal partial class DnsClient {
public class DnsClientResponse : IDnsResponse {
private readonly DnsResponse _response;
private readonly Byte[] _message;
internal DnsClientResponse(DnsClientRequest request, DnsResponse response, Byte[] message) {
this.Request = request;
this._message = message;
this._response = response;
}
public DnsClientRequest Request {
get;
}
public Int32 Id {
get => this._response.Id;
set {
}
}
public IList<IDnsResourceRecord> AnswerRecords => this._response.AnswerRecords;
public IList<IDnsResourceRecord> AuthorityRecords =>
new ReadOnlyCollection<IDnsResourceRecord>(this._response.AuthorityRecords);
public IList<IDnsResourceRecord> AdditionalRecords =>
new ReadOnlyCollection<IDnsResourceRecord>(this._response.AdditionalRecords);
public Boolean IsRecursionAvailable {
get => this._response.IsRecursionAvailable;
set {
}
}
public Boolean IsAuthorativeServer {
get => this._response.IsAuthorativeServer;
set {
}
}
public Boolean IsTruncated {
get => this._response.IsTruncated;
set {
}
}
public DnsOperationCode OperationCode {
get => this._response.OperationCode;
set {
}
}
public DnsResponseCode ResponseCode {
get => this._response.ResponseCode;
set {
}
}
public IList<DnsQuestion> Questions => new ReadOnlyCollection<DnsQuestion>(this._response.Questions);
public Int32 Size => this._message.Length;
public Byte[] ToArray() => this._message;
public override String ToString() => this._response.ToString();
}
public class DnsResponse : IDnsResponse {
private DnsHeader _header;
public DnsResponse(
DnsHeader header,
IList<DnsQuestion> questions,
IList<IDnsResourceRecord> answers,
IList<IDnsResourceRecord> authority,
IList<IDnsResourceRecord> additional) {
this._header = header;
this.Questions = questions;
this.AnswerRecords = answers;
this.AuthorityRecords = authority;
this.AdditionalRecords = additional;
}
public IList<DnsQuestion> Questions {
get;
}
public IList<IDnsResourceRecord> AnswerRecords {
get;
}
public IList<IDnsResourceRecord> AuthorityRecords {
get;
}
public IList<IDnsResourceRecord> AdditionalRecords {
get;
}
public Int32 Id {
get => this._header.Id;
set => this._header.Id = value;
}
public Boolean IsRecursionAvailable {
get => this._header.RecursionAvailable;
set => this._header.RecursionAvailable = value;
}
public Boolean IsAuthorativeServer {
get => this._header.AuthorativeServer;
set => this._header.AuthorativeServer = value;
}
public Boolean IsTruncated {
get => this._header.Truncated;
set => this._header.Truncated = value;
}
public DnsOperationCode OperationCode {
get => this._header.OperationCode;
set => this._header.OperationCode = value;
}
public DnsResponseCode ResponseCode {
get => this._header.ResponseCode;
set => this._header.ResponseCode = value;
}
public Int32 Size
=> this._header.Size +
this.Questions.Sum(q => q.Size) +
this.AnswerRecords.Sum(a => a.Size) +
this.AuthorityRecords.Sum(a => a.Size) +
this.AdditionalRecords.Sum(a => a.Size);
public static DnsResponse FromArray(Byte[] message) {
DnsHeader header = DnsHeader.FromArray(message);
Int32 offset = header.Size;
if(!header.Response || header.QuestionCount == 0) {
throw new ArgumentException("Invalid response message");
}
return header.Truncated
? new DnsResponse(header,
DnsQuestion.GetAllFromArray(message, offset, header.QuestionCount),
new List<IDnsResourceRecord>(),
new List<IDnsResourceRecord>(),
new List<IDnsResourceRecord>())
: new DnsResponse(header,
DnsQuestion.GetAllFromArray(message, offset, header.QuestionCount, out offset),
DnsResourceRecordFactory.GetAllFromArray(message, offset, header.AnswerRecordCount, out offset),
DnsResourceRecordFactory.GetAllFromArray(message, offset, header.AuthorityRecordCount, out offset),
DnsResourceRecordFactory.GetAllFromArray(message, offset, header.AdditionalRecordCount, out _));
}
public Byte[] ToArray() {
this.UpdateHeader();
MemoryStream result = new MemoryStream(this.Size);
_ = result
.Append(this._header.ToArray())
.Append(this.Questions.Select(q => q.ToArray()))
.Append(this.AnswerRecords.Select(a => a.ToArray()))
.Append(this.AuthorityRecords.Select(a => a.ToArray()))
.Append(this.AdditionalRecords.Select(a => a.ToArray()));
return result.ToArray();
}
public override String ToString() {
this.UpdateHeader();
return Json.SerializeOnly(
this,
true,
nameof(this.Questions),
nameof(this.AnswerRecords),
nameof(this.AuthorityRecords),
nameof(this.AdditionalRecords));
}
private void UpdateHeader() {
this._header.QuestionCount = this.Questions.Count;
this._header.AnswerRecordCount = this.AnswerRecords.Count;
this._header.AuthorityRecordCount = this.AuthorityRecords.Count;
this._header.AdditionalRecordCount = this.AdditionalRecords.Count;
}
}
}
}