v9.6.2017.0808   重构正向工程,基于映射表查找数据库字段类型到实体类型的映射
大石头 编写于 2017-08-08 21:38:06
X
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using NewLife.Messaging;
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 : Message<DNSEntity>
    {
        #region 属性
        private DNSHeader _Header = new DNSHeader();
        /// <summary>头部</summary>
        public DNSHeader Header { get { return _Header; } set { _Header = value; } }

        [FieldSize("_Header._Questions")]
        private DNSQuery[] _Questions;
        /// <summary>请求段</summary>
        public DNSQuery[] 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; } }

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

        //        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 qs = Questions;
            if (qs == null || qs.Length == 0) return null;

            var type = qs.First().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];
        }

        ///// <summary>是否PTR类型</summary>
        //public Boolean IsPTR { get { return Type == DNSQueryType.PTR; } }
        #endregion

        #region 读写
        /// <summary>把当前对象写入到数据流中去</summary>
        /// <param name="stream"></param>
        /// <param name="forTcp">是否是Tcp,Tcp需要增加整个流长度</param>
        public void Write(Stream stream, Boolean forTcp)
        {
            if (forTcp)
            {
                // 必须独立写然后再补长度,否则内部字符串长度偏移不正确
                var ms = new MemoryStream();
                Write(ms, null);

                stream.Write(((Int16)ms.Length).GetBytes(false));
                ms.WriteTo(stream);
            }
            else
                Write(stream, null);
        }

        /// <summary>获取当前对象的数据流</summary>
        /// <param name="forTcp">是否是Tcp,Tcp需要增加整个流长度</param>
        /// <returns></returns>
        public Stream GetStream(Boolean forTcp)
        {
            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)
        {
            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)
        {
            // 跳过2个字节的长度
            if (forTcp)
            {
                // 必须全部先读出来,否则内部的字符串映射位移不正确
                //var 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);
                var len = stream.ReadBytes(2).ToUInt16(0, false);
                var data = stream.ReadBytes(len);

                stream = new MemoryStream(data);
            }

            return Read(stream);
        }

        /// <summary>创建序列化器</summary>
        /// <param name="isRead"></param>
        /// <returns></returns>
        protected override IFormatterX CreateFormatter(Boolean isRead)
        {
            var fm = base.CreateFormatter(isRead);
            fm.Encoding = Encoding.UTF8;
            fm.UseProperty = false;

            var bn = fm as Binary;
            if (bn != null)
            {
                bn.EncodeInt = false;
                bn.UseFieldSize = true;
                bn.UseRef = false;
                bn.AddHandler<BinaryDNS>();
            }

            return fm;
        }
        #endregion

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

                var dr = item.CreateInstance() 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 type.CreateInstance() as DNSRecord;
        }
        #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()
        {
            var rs = Questions;
            if (!Header.Response)
            {
                if (rs != null && rs.Length > 0)
                    return rs[0].ToString();
            }
            else
            {
                var sb = new StringBuilder();

                if (rs != null && rs.Length > 0)
                    sb.AppendFormat("[{0}]", rs[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 sb.ToString();
                //return String.Format("Response {0}", sb);
            }

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