Com-AugustCellars/CoAP-CSharp

Block transfer over DTLS not working for me

Closed this issue · 5 comments

I am having trouble getting block transfer responses to work under DTLS.

I apologize for the length of this code below, but I thought I'd include the whole test so you can see everything I'm doing. The small payload returns perfectly, but the large payload never arrives. What am I doing wrong?

When I disable DTLS, it works fine.

using System;
using System.Text;
using System.Threading;
using Com.AugustCellars.CoAP;
using Com.AugustCellars.CoAP.DTLS;
using Com.AugustCellars.CoAP.Server;
using Com.AugustCellars.CoAP.Server.Resources;
using Com.AugustCellars.COSE;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using PeterO.Cbor;

namespace DtlsReproTest
{
    [TestClass]
    public class UnitTest1
    {
        [TestMethod]
        public void TestMethod1()
        {
            // Set up DTLS pre shared key
            var pskId = "KeyOne";
            var psk = "abcDEFghiJKL";
            var authKey = new OneKey();
            authKey.Add(CoseKeyKeys.KeyType, GeneralValues.KeyType_Octet);
            authKey.Add(CoseKeyKeys.KeyIdentifier, CBORObject.FromObject(Encoding.UTF8.GetBytes(pskId)));
            authKey.Add(CoseKeyParameterKeys.Octet_k, CBORObject.FromObject(Encoding.UTF8.GetBytes(psk)));
            var userKeys = new KeySet();
            userKeys.AddKey(authKey);

            // Create Server
            var server = new CoapServer();
            var endpoint = new DTLSEndPoint(null, userKeys, 5684);
            server.AddEndPoint(endpoint);
            server.Add(new SmallResource("small"));
            server.Add(new LargeResource("large"));
            server.Start();

            Thread.Sleep(500); // let server get spun up

            // Create client DTLS endpoint
            var clientEndpoint = new DTLSClientEndPoint(authKey);
            clientEndpoint.Start();

            // Perform POST to small resource
            var smallRequest = Request.NewPost();
            smallRequest.EndPoint = clientEndpoint;
            smallRequest.URI = new Uri("coaps://localhost/small");
            smallRequest.SetPayload("test payload", MediaType.TextPlain);
            smallRequest.Type = MessageType.CON;
            smallRequest.AckTimeout = -1; // disable retransmission
            smallRequest.Send();

            var smallResponse = smallRequest.WaitForResponse(1000);

            Assert.IsNotNull(smallResponse);  // <==== SUCCEEDS

            // Perform POST to large resource
            var largeRequest = Request.NewPost();
            largeRequest.EndPoint = clientEndpoint;
            largeRequest.URI = new Uri("coaps://localhost/large");
            largeRequest.SetPayload("test payload", MediaType.TextPlain);
            largeRequest.Type = MessageType.CON;
            largeRequest.AckTimeout = -1; // disable retransmission
            largeRequest.Send();

            var largeResponse = largeRequest.WaitForResponse(1000);

            Assert.IsNotNull(largeResponse); // <==== FAILS
        }
    }

    public class SmallResource : Resource
    {
        public SmallResource(string name) : base(name)
        {
        }

        protected override void DoPost(CoapExchange exchange)
        {
            Console.WriteLine("SmallResource received POST");
            exchange.Respond(StatusCode.Content, "small payload");
        }
    }

    public class LargeResource : Resource
    {
        public LargeResource(string name) : base(name)
        {
        }

        protected override void DoPost(CoapExchange exchange)
        {
            Console.WriteLine("LargeResource received POST");
            var largePayload = new StringBuilder()
                .Append("/-------------------------------------------------------------\\\r\n")
                .Append("|                 RESOURCE BLOCK NO. 1 OF 8                   |\r\n")
                .Append("|               [each line contains 64 bytes]                 |\r\n")
                .Append("\\-------------------------------------------------------------/\r\n")
                .Append("/-------------------------------------------------------------\\\r\n")
                .Append("|                 RESOURCE BLOCK NO. 2 OF 8                   |\r\n")
                .Append("|               [each line contains 64 bytes]                 |\r\n")
                .Append("\\-------------------------------------------------------------/\r\n")
                .Append("/-------------------------------------------------------------\\\r\n")
                .Append("|                 RESOURCE BLOCK NO. 3 OF 8                   |\r\n")
                .Append("|               [each line contains 64 bytes]                 |\r\n")
                .Append("\\-------------------------------------------------------------/\r\n")
                .Append("/-------------------------------------------------------------\\\r\n")
                .Append("|                 RESOURCE BLOCK NO. 4 OF 8                   |\r\n")
                .Append("|               [each line contains 64 bytes]                 |\r\n")
                .Append("\\-------------------------------------------------------------/\r\n")
                .Append("/-------------------------------------------------------------\\\r\n")
                .Append("|                 RESOURCE BLOCK NO. 5 OF 8                   |\r\n")
                .Append("|               [each line contains 64 bytes]                 |\r\n")
                .Append("\\-------------------------------------------------------------/\r\n")
                .Append("/-------------------------------------------------------------\\\r\n")
                .Append("|                 RESOURCE BLOCK NO. 6 OF 8                   |\r\n")
                .Append("|               [each line contains 64 bytes]                 |\r\n")
                .Append("\\-------------------------------------------------------------/\r\n")
                .Append("/-------------------------------------------------------------\\\r\n")
                .Append("|                 RESOURCE BLOCK NO. 7 OF 8                   |\r\n")
                .Append("|               [each line contains 64 bytes]                 |\r\n")
                .Append("\\-------------------------------------------------------------/\r\n")
                .Append("/-------------------------------------------------------------\\\r\n")
                .Append("|                 RESOURCE BLOCK NO. 8 OF 8                   |\r\n")
                .Append("|               [each line contains 64 bytes]                 |\r\n")
                .Append("\\-------------------------------------------------------------/\r\n")
                .ToString();

            exchange.Respond(StatusCode.Content, largePayload);
        }
    }
}

I have duplicated this and have found the error. It was introduced by trying to enforce DTLS sessions.

Thanks much for looking into it so quickly. After staring at it all day, I'll be looking forward to seeing what it was when you've fixed it.

Jim, I see you have been working on master and on a NetStandard branch. I'm just wondering what the status of the DTLS block transfer bug is on master currently? Should I be able to pull master and build it locally now and have DTLS block transfer work again, or should I wait a little longer until you get things released?

I will have a release done by the end of the weekend

Fixed