public async Task MaxBufferSendWithRandomDrops()
        {
            SctpDataReceiver receiver = new SctpDataReceiver(1000, 1400, 0);
            SctpDataSender   sender   = new SctpDataSender("dummy", null, 1400, 0, 1000);

            sender._burstPeriodMilliseconds = 1;
            sender._rtoInitialMilliseconds  = 1;
            sender._rtoMinimumMilliseconds  = 1;
            sender.StartSending();

            SctpDataFrame        frame      = SctpDataFrame.Empty;
            ManualResetEventSlim frameReady = new ManualResetEventSlim(false);

            // This local function replicates a data chunk being sent from a data
            // sender to the receiver of a remote peer and the return of the SACK.
            Action <SctpDataChunk> doSend = async(chunk) =>
            {
                if (chunk.SendCount == 1 && Crypto.GetRandomInt(0, 99) % 5 == 0)
                {
                    logger.LogDebug($"Data chunk {chunk.TSN} dropped.");
                }
                else
                {
                    logger.LogDebug($"Data chunk {chunk.TSN} provided to receiver.");
                    var frames = receiver.OnDataChunk(chunk);
                    sender.GotSack(receiver.GetSackChunk());

                    if (frames.Count > 0)
                    {
                        logger.LogDebug($"Receiver got frame of length {frames.First().UserData?.Length}.");
                        frame = frames.First();
                        frameReady.Set();
                    }
                }

                await Task.Delay(1);
            };

            sender._sendDataChunk = doSend;

            byte[] buffer = new byte[RTCSctpTransport.SCTP_DEFAULT_MAX_MESSAGE_SIZE];
            //byte[] buffer = new byte[2000];
            Crypto.GetRandomBytes(buffer);
            string hash = Crypto.GetSHA256Hash(buffer);

            logger.LogDebug($"Max buffer hash {hash}.");

            await Task.Delay(50);

            sender.SendData(0, 0, buffer);

            frameReady.WaitHandle.WaitOne(10000, true);

            Assert.False(frame.IsEmpty());
            Assert.Equal(buffer.Length, frame.UserData.Length);
            Assert.Equal(hash, Crypto.GetSHA256Hash(frame.UserData));
        }
        public void MaxBufferSend()
        {
            uint             arwnd    = SctpAssociation.DEFAULT_ADVERTISED_RECEIVE_WINDOW;
            SctpDataReceiver receiver = new SctpDataReceiver(arwnd, 1400, 0);
            SctpDataSender   sender   = new SctpDataSender("dummy", null, 1400, 0, arwnd);

            sender.StartSending();

            SctpDataFrame        frame      = SctpDataFrame.Empty;
            ManualResetEventSlim frameReady = new ManualResetEventSlim(false);

            // This local function replicates a data chunk being sent from a data
            // sender to the receiver of a remote peer and the return of the SACK.
            Action <SctpDataChunk> doSend = (chunk) =>
            {
                logger.LogDebug($"Data chunk {chunk.TSN} provided to receiver.");
                var frames = receiver.OnDataChunk(chunk);
                sender.GotSack(receiver.GetSackChunk());

                if (frames.Count > 0)
                {
                    logger.LogDebug($"Receiver got frame of length {frames.First().UserData?.Length}.");
                    frame = frames.First();
                    frameReady.Set();
                }
            };

            sender._sendDataChunk = doSend;

            byte[] buffer = new byte[RTCSctpTransport.SCTP_DEFAULT_MAX_MESSAGE_SIZE];
            Crypto.GetRandomBytes(buffer);
            string hash = Crypto.GetSHA256Hash(buffer);

            logger.LogDebug($"Max buffer hash {hash}.");

            sender.SendData(0, 0, buffer);

            frameReady.WaitHandle.WaitOne(10000, true);

            Assert.False(frame.IsEmpty());
            Assert.Equal(RTCSctpTransport.SCTP_DEFAULT_MAX_MESSAGE_SIZE, (uint)frame.UserData.Length);
            Assert.Equal(hash, Crypto.GetSHA256Hash(frame.UserData));
        }
        public void MediumBufferSend()
        {
            ushort           mtu      = 1400;
            SctpDataReceiver receiver = new SctpDataReceiver(1000, mtu, 0);
            SctpDataSender   sender   = new SctpDataSender("dummy", null, mtu, 0, 1000);

            sender.StartSending();

            SctpDataFrame        frame      = SctpDataFrame.Empty;
            ManualResetEventSlim frameReady = new ManualResetEventSlim(false);

            // This local function replicates a data chunk being sent from a data
            // sender to the receiver of a remote peer and the return of the SACK.
            Action <SctpDataChunk> doSend = (chunk) =>
            {
                logger.LogDebug($"Data chunk {chunk.TSN} provided to receiver.");
                var frames = receiver.OnDataChunk(chunk);
                sender.GotSack(receiver.GetSackChunk());

                if (frames.Count > 0)
                {
                    logger.LogDebug($"Receiver got frame of length {frames.First().UserData?.Length}.");
                    frame = frames.First();
                    frameReady.Set();
                }
            };

            sender._sendDataChunk = doSend;

            byte[] buffer = new byte[10 * mtu];
            Crypto.GetRandomBytes(buffer);
            string hash = Crypto.GetSHA256Hash(buffer);

            logger.LogDebug($"Medium buffer hash {hash}.");

            sender.SendData(0, 0, buffer);

            frameReady.WaitHandle.WaitOne(5000, true);

            Assert.False(frame.IsEmpty());
            Assert.Equal(buffer.Length, frame.UserData.Length);
            Assert.Equal(hash, Crypto.GetSHA256Hash(frame.UserData));
        }