[fix]修正UdpServer在接收广播时连续启动接收的错误,在StarAgent中,此时可能收到广播包,SocketFlags是Broadcast,需要清空,否则报错“参考的对象类型不支持尝试的操作”; 无需设置SocketOptionName.PacketInformation,在ReceiveMessageFromAsync时会自动设置,并且支持ipv6;
石头 编写于 2024-10-10 00:36:00 石头 提交于 2024-10-10 00:45:43
X
using System;
using System.IO;
//using System.Security.Cryptography;

namespace NewLife.Security
{

    /// <summary>CRC32校验</summary>
    /// <remarks>
    /// Generate a table for a byte-wise 32-bit CRC calculation on the polynomial:
    /// x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1.
    ///
    /// Polynomials over GF(2) are represented in binary, one bit per coefficient,
    /// with the lowest powers in the most significant bit.  Then adding polynomials
    /// is just exclusive-or, and multiplying a polynomial by x is a right shift by
    /// one.  If we call the above polynomial p, and represent a byte as the
    /// polynomial q, also with the lowest power in the most significant bit (so the
    /// byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p,
    /// where a mod b means the remainder after dividing a by b.
    ///
    /// This calculation is done using the shift-register method of multiplying and
    /// taking the remainder.  The register is initialized to zero, and for each
    /// incoming bit, x^32 is added mod p to the register if the bit is a one (where
    /// x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by
    /// x (which is shifting right by one and adding x^32 mod p if the bit shifted
    /// out is a one).  We start with the highest power (least significant bit) of
    /// q and repeat for all eight bits of q.
    ///
    /// The table is simply the CRC of all possible eight bit values.  This is all
    /// the information needed to generate CRC's on data a byte at a time for all
    /// combinations of CRC register values and incoming bytes.
    /// </remarks>
    public sealed class Crc32 //: HashAlgorithm
    {
        const UInt32 CrcSeed = 0xFFFFFFFF;

        #region 数据表
        /// <summary>校验表</summary>
        public readonly static UInt32[] Table;

        static Crc32()
        {
            Table = new UInt32[256];
            const UInt32 kPoly = 0xEDB88320;
            for (UInt32 i = 0; i < 256; i++)
            {
                var r = i;
                for (var j = 0; j < 8; j++)
                    if ((r & 1) != 0)
                        r = (r >> 1) ^ kPoly;
                    else
                        r >>= 1;
                Table[i] = r;
            }
        }
        #endregion

        //internal static uint ComputeCrc32(uint oldCrc, byte value)
        //{
        //    return (uint)(Table[(oldCrc ^ value) & 0xFF] ^ (oldCrc >> 8));
        //}

        /// <summary>校验值</summary>
        UInt32 crc = CrcSeed;
        /// <summary>校验值</summary>
        public UInt32 Value { get { return crc ^ CrcSeed; } set { crc = value ^ CrcSeed; } }

        /// <summary>重置清零</summary>
        public Crc32 Reset() { crc = CrcSeed; return this; }

        /// <summary>添加整数进行校验</summary>
        /// <param name = "value">
        /// the byte is taken as the lower 8 bits of value
        /// </param>
        public Crc32 Update(Int32 value)
        {
            crc = Table[(crc ^ value) & 0xFF] ^ (crc >> 8);

            return this;
        }

        /// <summary>添加字节数组进行校验</summary>
        /// <param name = "buffer">
        /// The buffer which contains the data
        /// </param>
        /// <param name = "offset">
        /// The offset in the buffer where the data starts
        /// </param>
        /// <param name = "count">
        /// The number of data bytes to update the CRC with.
        /// </param>
        public Crc32 Update(Byte[] buffer, Int32 offset = 0, Int32 count = -1)
        {
            if (buffer == null) throw new ArgumentNullException(nameof(buffer));
            //if (count < 0) throw new ArgumentOutOfRangeException("count", "Count不能小于0!");
            if (count <= 0) count = buffer.Length;
            if (offset < 0 || offset + count > buffer.Length) throw new ArgumentOutOfRangeException(nameof(offset));

            while (--count >= 0)
            {
                crc = Table[(crc ^ buffer[offset++]) & 0xFF] ^ (crc >> 8);
            }

            return this;
        }

        /// <summary>添加数据流进行校验</summary>
        /// <param name="stream"></param>
        /// <param name="count">数量</param>
        public Crc32 Update(Stream stream, Int64 count = -1)
        {
            if (stream == null) throw new ArgumentNullException(nameof(stream));
            //if (count < 0) throw new ArgumentOutOfRangeException("count", "Count不能小于0!");
            if (count <= 0) count = Int64.MaxValue;

            while (--count >= 0)
            {
                var b = stream.ReadByte();
                if (b == -1) break;

                crc = Table[(crc ^ b) & 0xFF] ^ (crc >> 8);
            }

            return this;
        }

        /// <summary>计算校验码</summary>
        /// <param name="buf"></param>
        /// <param name="offset"></param>
        /// <param name="count"></param>
        /// <returns></returns>
        public static UInt32 Compute(Byte[] buf, Int32 offset = 0, Int32 count = -1)
        {
            var crc = new Crc32();
            crc.Update(buf, offset, count);
            return crc.Value;
        }

        /// <summary>计算数据流校验码</summary>
        /// <param name="stream"></param>
        /// <param name="count"></param>
        /// <returns></returns>
        public static UInt32 Compute(Stream stream, Int32 count = -1)
        {
            var crc = new Crc32();
            crc.Update(stream, count);
            return crc.Value;
        }

        /// <summary>计算数据流校验码,指定起始位置和字节数偏移量</summary>
        /// <remarks>
        /// 一般用于计算数据包校验码,需要回过头去开始校验,并且可能需要跳过最后的校验码长度。
        /// position小于0时,数据流从当前位置开始计算校验;
        /// position大于等于0时,数据流移到该位置开始计算校验,最后由count决定可能差几个字节不参与计算;
        /// </remarks>
        /// <param name="stream"></param>
        /// <param name="position">如果大于等于0,则表示从该位置开始计算</param>
        /// <param name="count">字节数偏移量,一般用负数表示</param>
        /// <returns></returns>
        public static UInt32 ComputeRange(Stream stream, Int64 position = -1, Int32 count = -1)
        {
            if (position >= 0)
            {
                if (count > 0) count = -count;
                count += (Int32)(stream.Position - position);
                if (count == 0) return 0;

                stream.Position = position;
            }

            var crc = new Crc32();
            crc.Update(stream, count);
            return crc.Value;
        }

        //#region 抽象实现
        ///// <summary>哈希核心</summary>
        ///// <param name="array"></param>
        ///// <param name="ibStart"></param>
        ///// <param name="cbSize"></param>
        //protected override void HashCore(byte[] array, int ibStart, int cbSize)
        //{
        //    while (--cbSize >= 0)
        //    {
        //        crc = Table[(crc ^ array[ibStart++]) & 0xFF] ^ (crc >> 8);
        //    }
        //}

        ///// <summary>最后哈希</summary>
        ///// <returns></returns>
        //protected override byte[] HashFinal() { return BitConverter.GetBytes(Value); }

        ///// <summary>初始化</summary>
        //public override void Initialize() { }
        //#endregion
    }
}