using Unosquare.Swan.Formatters; using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.IO; using System.Linq; namespace Unosquare.Swan.Networking { /// /// DnsClient Response inner class. /// 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 AnswerRecords => this._response.AnswerRecords; public IList AuthorityRecords => new ReadOnlyCollection(this._response.AuthorityRecords); public IList AdditionalRecords => new ReadOnlyCollection(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 Questions => new ReadOnlyCollection(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 questions, IList answers, IList authority, IList additional) { this._header = header; this.Questions = questions; this.AnswerRecords = answers; this.AuthorityRecords = authority; this.AdditionalRecords = additional; } public IList Questions { get; } public IList AnswerRecords { get; } public IList AuthorityRecords { get; } public IList 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(), new List(), new List()) : 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; } } } }