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 async Task InitialDataChunkDropped()
        {
            uint   arwnd      = 131072;
            ushort mtu        = 1400;
            uint   initialTSN = Crypto.GetRandomUInt(true);

            SctpDataReceiver receiver = new SctpDataReceiver(arwnd, mtu, initialTSN);
            SctpDataSender   sender   = new SctpDataSender("dummy", null, mtu, initialTSN, arwnd);

            sender.StartSending();

            // 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) =>
            {
                if (chunk.TSN == initialTSN && chunk.SendCount == 1)
                {
                    logger.LogDebug($"Data chunk {chunk.TSN} dropped.");
                }
                else
                {
                    receiver.OnDataChunk(chunk);
                    sender.GotSack(receiver.GetSackChunk());
                }
            };

            sender._sendDataChunk = doSend;

            sender.SendData(0, 0, new byte[] { 0x55 });
            Assert.Equal(initialTSN + 1, sender.TSN);
            await Task.Delay(250);

            Assert.Null(receiver.CumulativeAckTSN);

            await Task.Delay(500);

            sender.SendData(0, 0, new byte[] { 0x55 });
            Assert.Equal(initialTSN + 2, sender.TSN);
            await Task.Delay(1250);

            Assert.Equal(initialTSN + 1, receiver.CumulativeAckTSN);

            await Task.Delay(500);

            sender.SendData(0, 0, new byte[] { 0x55 });
            Assert.Equal(initialTSN + 3, sender.TSN);
            await Task.Delay(250);

            Assert.Equal(initialTSN + 2, receiver.CumulativeAckTSN);
        }
        public async Task SACKChunkRetransmit()
        {
            uint   arwnd      = 131072;
            ushort mtu        = 1400;
            uint   initialTSN = Crypto.GetRandomUInt(true);

            SctpDataReceiver receiver = new SctpDataReceiver(arwnd, mtu, initialTSN);
            SctpDataSender   sender   = new SctpDataSender("dummy", null, mtu, initialTSN, arwnd);

            sender.StartSending();

            // 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) =>
            {
                receiver.OnDataChunk(chunk);
                sender.GotSack(receiver.GetSackChunk());
            };

            Action <SctpDataChunk> dontSend = (chunk) => { };

            sender._sendDataChunk = doSend;
            sender.SendData(0, 0, new byte[] { 0x00, 0x01, 0x02 });
            Assert.Equal(initialTSN + 1, sender.TSN);
            await Task.Delay(250);

            Assert.Equal(initialTSN, receiver.CumulativeAckTSN);

            // This send to the receiver is blocked so the receivers ACK TSN should stay the same.
            sender._sendDataChunk = dontSend;
            sender.SendData(0, 0, new byte[] { 0x00, 0x01, 0x02 });
            Assert.Equal(initialTSN + 2, sender.TSN);
            await Task.Delay(250);

            Assert.Equal(initialTSN, receiver.CumulativeAckTSN);

            // Unblock. Receiver's ACK TSN should not advance as it has a missing chunk.
            sender._sendDataChunk = doSend;
            sender.SendData(0, 0, new byte[] { 0x00, 0x01, 0x02 });
            Assert.Equal(initialTSN + 3, sender.TSN);
            await Task.Delay(250);

            Assert.Equal(initialTSN + 2, receiver.CumulativeAckTSN);
        }
        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));
        }
Beispiel #6
0
        public async Task IncreaseCongestionWindowSlowStart()
        {
            uint   arwnd      = SctpAssociation.DEFAULT_ADVERTISED_RECEIVE_WINDOW;
            ushort mtu        = 1400;
            uint   initialTSN = 0;

            SctpDataReceiver receiver = new SctpDataReceiver(arwnd, mtu, initialTSN);
            SctpDataSender   sender   = new SctpDataSender("dummy", null, mtu, initialTSN, arwnd);

            sender._burstPeriodMilliseconds = 1;
            sender._rtoInitialMilliseconds  = 1;
            sender._rtoMinimumMilliseconds  = 1;

            Action <SctpDataChunk> reluctantSender = (chunk) =>
            {
                if (chunk.TSN % 10 == 0)
                {
                    receiver.OnDataChunk(chunk);
                    sender.GotSack(receiver.GetSackChunk());
                }
            };

            sender._sendDataChunk = reluctantSender;
            sender.StartSending();

            Assert.Equal(SctpDataSender.CONGESTION_WINDOW_FACTOR, sender._congestionWindow);

            var buffer = new byte[mtu];

            for (int i = 0; i <= 10; i++)
            {
                sender.SendData(0, 0, buffer);
            }

            await Task.Delay(500);

            Assert.Equal(SctpDataSender.CONGESTION_WINDOW_FACTOR + mtu, sender._congestionWindow);
        }