开放一个方法
nnhy authored at 2012-06-25 18:27:24
14.97 KiB
X
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text;
using NewLife.Reflection;
using NewLife.Serialization;

namespace NewLife.Net.DNS
{
    /// <summary>DNS实体类基类</summary>
    /// <remarks>
    /// 参考博客园 @看那边的人 <a target="_blank" href="http://www.cnblogs.com/topdog/archive/2011/11/15/2250185.html">DIY一个DNS查询器:了解DNS协议</a> <a target="_blank" href="http://www.cnblogs.com/topdog/archive/2011/11/21/2257597.html">DIY一个DNS查询器:程序实现</a>
    /// </remarks>
    public class DNSEntity : IAccessor
    {
        #region 属性
        private DNSHeader _Header = new DNSHeader();
        /// <summary>头部</summary>
        public DNSHeader Header { get { return _Header; } set { _Header = value; } }

        [FieldSize("_Header._Questions")]
        private DNSRecord[] _Questions;
        /// <summary>请求段</summary>
        public DNSRecord[] Questions { get { return _Questions; } set { _Questions = value; } }

        [FieldSize("_Header._Answers")]
        private DNSRecord[] _Answers;
        /// <summary>回答段</summary>
        public DNSRecord[] Answers { get { return _Answers; } set { _Answers = value; } }

        [FieldSize("_Header._Authorities")]
        private DNSRecord[] _Authoritis;
        /// <summary>授权段</summary>
        public DNSRecord[] Authoritis { get { return _Authoritis; } set { _Authoritis = value; } }

        [FieldSize("_Header._Additionals")]
        private DNSRecord[] _Additionals;
        /// <summary>附加段</summary>
        public DNSRecord[] Additionals { get { return _Additionals; } set { _Additionals = value; } }
        #endregion

        #region 扩展属性
        /// <summary>是否响应</summary>
        public Boolean Response { get { return Header.Response; } set { Header.Response = value; } }

        DNSRecord Question
        {
            get
            {
                if (Questions == null || Questions.Length < 1) Questions = new DNSRecord[] { new DNSRecord() };

                return Questions[0];
            }
        }

        /// <summary>名称</summary>
        public virtual String Name { get { return Question.Name; } set { Question.Name = value; } }

        /// <summary>查询类型</summary>
        public virtual DNSQueryType Type { get { return Question.Type; } set { Question.Type = value; } }

        /// <summary>协议组</summary>
        public virtual DNSQueryClass Class { get { return Question.Class; } set { Question.Class = value; } }

        /// <summary>获取响应</summary>
        /// <param name="create"></param>
        /// <returns></returns>
        internal protected DNSRecord GetAnswer(Boolean create = false)
        {
            var type = Question.Type;
            if (Answers == null || Answers.Length < 1)
            {
                if (!create) return null;

                Answers = new DNSRecord[] { CreateRecord(type) };
            }

            foreach (var item in Answers)
            {
                if (item.Type == type) return item;
            }

            return Answers[0];
        }
        #endregion

        #region 读写
        /// <summary>把当前对象写入到数据流中去</summary>
        /// <param name="stream"></param>
        /// <param name="forTcp">是否是Tcp,Tcp需要增加整个流长度</param>
        public void Write(Stream stream, Boolean forTcp = false)
        {
            if (forTcp)
            {
                var ms = new MemoryStream();
                WriteRaw(ms);

                Byte[] data = BitConverter.GetBytes((Int16)ms.Length);
                Array.Reverse(data);
                stream.Write(data, 0, data.Length);
                ms.WriteTo(stream);
            }
            else
                WriteRaw(stream);
        }

        /// <summary>把当前对象写入到数据流中去</summary>
        /// <param name="stream"></param>
        public void WriteRaw(Stream stream)
        {
            BinaryWriterX writer = new BinaryWriterX();
            writer.Settings.IsLittleEndian = false;
            writer.Settings.UseObjRef = false;
            writer.Settings.Encoding = Encoding.Default;
            writer.Stream = stream;
#if DEBUG
            //if (NetHelper.Debug)
            //{
            //    writer.Debug = true;
            //    writer.EnableTraceStream();
            //}
#endif
            writer.WriteObject(this);
        }

        /// <summary>获取当前对象的数据流</summary>
        /// <param name="forTcp">是否是Tcp,Tcp需要增加整个流长度</param>
        /// <returns></returns>
        public Stream GetStream(Boolean forTcp = false)
        {
            var ms = new MemoryStream();
            Write(ms, forTcp);
            ms.Position = 0;

            return ms;
        }

        /// <summary>从数据中读取对象</summary>
        /// <param name="data"></param>
        /// <param name="forTcp">是否是Tcp,Tcp需要增加整个流长度</param>
        /// <returns></returns>
        public static DNSEntity Read(Byte[] data, Boolean forTcp = false)
        {
            if (data == null || data.Length < 1) return null;

            return Read(new MemoryStream(data), forTcp);
        }

        /// <summary>从数据流中读取对象,返回<see cref="DNS_A"/>、<see cref="DNS_PTR"/>等真实对象</summary>
        /// <param name="stream"></param>
        /// <param name="forTcp">是否是Tcp,Tcp需要增加整个流长度</param>
        /// <returns></returns>
        public static DNSEntity Read(Stream stream, Boolean forTcp = false)
        {
            // 跳过2个字节的长度
            if (forTcp)
            {
                //stream.Seek(2, SeekOrigin.Current);
                // 必须全部先读出来,否则内部的字符串映射位移不正确
                Byte[] data = new Byte[2];
                stream.Read(data, 0, data.Length);
                // 网络序变为主机序
                Array.Reverse(data);
                var len = BitConverter.ToInt16(data, 0);
                data = new Byte[len];
                stream.Read(data, 0, data.Length);

                stream = new MemoryStream(data);
            }

            // 先读取
            return ReadRaw(stream);
        }

        /// <summary>从数据流中读取对象,返回DNSEntity对象</summary>
        /// <param name="stream"></param>
        /// <returns></returns>
        public static DNSEntity ReadRaw(Stream stream)
        {
            BinaryReaderX reader = new BinaryReaderX();
            reader.Settings.IsLittleEndian = false;
            reader.Settings.UseObjRef = false;
            reader.Settings.Encoding = Encoding.Default;
            reader.Stream = stream;
#if DEBUG
            //if (NetHelper.Debug)
            //{
            //    reader.Debug = true;
            //    reader.EnableTraceStream();
            //}
#endif
            return reader.ReadObject<DNSEntity>();
        }
        #endregion

        #region 注册子类型
        static Dictionary<DNSQueryType, Type> entitytypes = new Dictionary<DNSQueryType, Type>();
        static DNSEntity()
        {
            foreach (var item in AssemblyX.FindAllPlugins(typeof(DNSRecord)))
            {
                if (item == typeof(DNSRecord)) continue;

                var dr = TypeX.CreateInstance(item) as DNSRecord;
                if (dr != null) entitytypes.Add(dr.Type, item);
            }
        }

        /// <summary>创建指定类型的记录</summary>
        /// <param name="qt"></param>
        /// <returns></returns>
        public static DNSRecord CreateRecord(DNSQueryType qt)
        {
            Type type = null;
            if (!entitytypes.TryGetValue(qt, out type) || type == null) return null;

            return TypeX.CreateInstance(type) as DNSRecord;
        }
        #endregion

        #region IAccessor 成员
        /// <summary>从读取器中读取数据到对象。接口实现者可以在这里完全自定义行为(返回true),也可以通过设置事件来影响行为(返回false)</summary>
        /// <param name="reader">读取器</param>
        /// <returns>是否读取成功,若返回成功读取器将不再读取该对象</returns>
        public virtual bool Read(IReader reader)
        {
            reader.OnMemberReading += new EventHandler<ReadMemberEventArgs>(reader_OnMemberReading);
            reader.OnItemReading += new EventHandler<ReadItemEventArgs>(reader_OnItemReading);
            return false;
        }

        void reader_OnItemReading(object sender, ReadItemEventArgs e)
        {
            if (e.Type == typeof(DNSRecord))
            {
                var reader = sender as IReader;
                var p = reader.Stream.Position;
                String name = GetNameAccessor(reader).Read(reader.Stream, 0);
                DNSQueryType qt = (DNSQueryType)reader.ReadValue(typeof(DNSQueryType));
                // 退回去,让序列化自己读
                reader.Stream.Position = p;
                //Type type = null;
                //if (entitytypes.TryGetValue(qt, out type) && type != null) e.Type = type;
                //var value = TypeX.CreateInstance(e.Type) as DNSRecord;
                var value = CreateRecord(qt);
                if (value != null)
                    e.Type = value.GetType();
                else
                    value = new DNSRecord();
                value.Name = name;
                //value.Type = qt;
                e.Value = value;
            }
        }

        /// <summary>从读取器中读取数据到对象后执行。接口实现者可以在这里取消Read阶段设置的事件</summary>
        /// <param name="reader">读取器</param>
        /// <param name="success">是否读取成功</param>
        /// <returns>是否读取成功</returns>
        public virtual bool ReadComplete(IReader reader, bool success) { return success; }

        /// <summary>把对象数据写入到写入器。接口实现者可以在这里完全自定义行为(返回true),也可以通过设置事件来影响行为(返回false)</summary>
        /// <param name="writer">写入器</param>
        /// <returns>是否写入成功,若返回成功写入器将不再读写入对象</returns>
        public virtual bool Write(IWriter writer)
        {
            writer.OnMemberWriting += new EventHandler<WriteMemberEventArgs>(writer_OnMemberWriting);
            return false;
        }

        /// <summary>把对象数据写入到写入器后执行。接口实现者可以在这里取消Write阶段设置的事件</summary>
        /// <param name="writer">写入器</param>
        /// <param name="success">是否写入成功</param>
        /// <returns>是否写入成功</returns>
        public virtual bool WriteComplete(IWriter writer, bool success) { return success; }
        #endregion

        #region 特殊处理字符串
        void reader_OnMemberReading(object sender, ReadMemberEventArgs e)
        {
            var reader = sender as IReader;
            // TXT记录的Text字段不采用DNS字符串
            if (e.Type == typeof(String) && e.Member.Name != "_Text")
            {
                Object ps = reader.Items["Position"];
                Int64 p = ps is Int64 ? (Int64)ps : 0;
                e.Member[e.Value] = GetNameAccessor(reader).Read(reader.Stream, p);
                //reader.WriteLog("ReadMember", "_Name", "String", e.Member[e.Value]);
                e.Success = true;
            }
            else if (e.Type == typeof(TimeSpan))
            {
                e.Member[e.Value] = new TimeSpan(0, 0, reader.ReadInt32());
                e.Success = true;
            }
        }

        void writer_OnMemberWriting(object sender, WriteMemberEventArgs e)
        {
            var writer = sender as IWriter;
            // TXT记录的Text字段不采用DNS字符串
            if (e.Type == typeof(String) && e.Member.Name != "_Text")
            {
                //writer.WriteLog("WriteMember", "_Name", "String", e.Member[e.Value]);
                Object ps = writer.Items["Position"];
                Int64 p = ps is Int64 ? (Int64)ps : 0;
                p += writer.Stream.Position;
                GetNameAccessor(writer).Write(writer.Stream, (String)e.Member[e.Value], p);
                e.Success = true;
            }
            else if (e.Type == typeof(TimeSpan))
            {
                var ts = (TimeSpan)e.Member[e.Value];
                writer.Write((Int32)ts.TotalSeconds);
                e.Success = true;
            }
        }

        [DebuggerHidden]
        internal static DNSNameAccessor GetNameAccessor(IReaderWriter rw)
        {
            var accessor = rw.Items["Names"] as DNSNameAccessor;
            if (accessor == null) rw.Items.Add("Names", accessor = new DNSNameAccessor());

            return accessor;
        }
        #endregion

        #region 辅助
        /// <summary>复制</summary>
        /// <param name="entity"></param>
        public virtual DNSEntity CloneFrom(DNSEntity entity)
        {
            var de = this;
            de.Header = entity.Header;
            de.Questions = entity.Questions;
            de.Answers = entity.Answers;
            de.Authoritis = entity.Authoritis;
            de.Additionals = entity.Additionals;
            return de;
        }

        /// <summary>已重载。</summary>
        /// <returns></returns>
        [DebuggerHidden]
        public override string ToString()
        {
            if (!Response)
            {
                if (_Questions != null && _Questions.Length > 0)
                    return _Questions[0].ToString();
            }
            else
            {
                StringBuilder sb = new StringBuilder();

                if (_Questions != null && _Questions.Length > 0)
                    sb.AppendFormat("[{0}]", _Questions[0]);

                if (Answers != null && Answers.Length > 0)
                {
                    foreach (var item in Answers)
                    {
                        if (sb.Length > 0) sb.Append(" ");
                        sb.Append(item);
                    }
                }
                else if (Authoritis != null && Authoritis.Length > 0)
                {
                    foreach (var item in Authoritis)
                    {
                        if (sb.Length > 0) sb.Append(" ");
                        sb.Append(item);
                    }
                }
                else if (Header.ResponseCode == DNSRcodeType.NameError)
                    sb.Append("No such name");

                return String.Format("Response {0}", sb);
            }

            return base.ToString();
        }
        #endregion
    }
}