Skip to content

Commit

Permalink
Sending multicast CoAP messages are checked appropiately
Browse files Browse the repository at this point in the history
  • Loading branch information
NZSmartie committed Sep 22, 2017
1 parent e131344 commit b8ef59a
Show file tree
Hide file tree
Showing 3 changed files with 164 additions and 13 deletions.
26 changes: 16 additions & 10 deletions src/CoAPNet/CoapClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -266,29 +266,29 @@ public void Dispose()
/// </summary>
/// <param name="message"></param>
/// <returns></returns>
public virtual async Task<int> SendAsync(CoapMessage message) =>
await SendAsync(message, null, CancellationToken.None);
public virtual async Task<int> SendAsync(CoapMessage message)
=> await SendAsync(message, null, CancellationToken.None);

/// <summary>
/// <see cref="SendAsync(CoapMessage, ICoapEndpoint, CancellationToken)"/>
/// </summary>
/// <param name="message"></param>
/// <param name="token"></param>
/// <returns></returns>
public virtual async Task<int> SendAsync(CoapMessage message, CancellationToken token) =>
await SendAsync(message, null, token);
public virtual async Task<int> SendAsync(CoapMessage message, CancellationToken token)
=> await SendAsync(message, null, token);

/// <summary>
/// <see cref="SendAsync(CoapMessage, ICoapEndpoint, CancellationToken)"/>
/// </summary>
/// <param name="message"></param>
/// <param name="endpoint"></param>
/// <returns></returns>
public virtual async Task<int> SendAsync(CoapMessage message, ICoapEndpoint endpoint) =>
await SendAsync(message, endpoint, CancellationToken.None);
public virtual async Task<int> SendAsync(CoapMessage message, ICoapEndpoint endpoint)
=> await SendAsync(message, endpoint, CancellationToken.None);

private int GetNextMessageId() =>
Interlocked.Increment(ref _messageId) & ushort.MaxValue;
private int GetNextMessageId()
=> Interlocked.Increment(ref _messageId) & ushort.MaxValue;

/// <summary>
/// Assigns an incremented message id (if none is already set) and performs a blocking Send operation.
Expand All @@ -309,6 +309,9 @@ public virtual async Task<int> SendAsync(CoapMessage message, ICoapEndpoint endp
if (message.Id == 0)
message.Id = GetNextMessageId();

if (message.IsMulticast && message.Type != CoapMessageType.NonConfirmable)
throw new CoapClientException("Can not send confirmable (CON) CoAP message to a multicast endpoint");

if (message.Type != CoapMessageType.Confirmable)
{
await SendAsyncInternal(message, endpoint, token).ConfigureAwait(false);
Expand Down Expand Up @@ -341,12 +344,15 @@ private async Task SendAsyncInternal(CoapMessage message, ICoapEndpoint remoteEn
{
if(Endpoint == null)
return;

if (remoteEndpoint == null)
remoteEndpoint = new CoapEndpoint
{
BaseUri = new UriBuilder(message.GetUri()) {Path = "/", Fragment = "", Query = ""}.Uri
BaseUri = new UriBuilder(message.GetUri()) { Path = "/", Fragment = "", Query = "" }.Uri,
IsMulticast = message.IsMulticast,
};
else if (message.IsMulticast && !remoteEndpoint.IsMulticast)
throw new CoapClientException("Can not send CoAP multicast message to a non-multicast endpoint");

await Task.Run(async () => await Endpoint.SendAsync(new CoapPacket
{
Expand Down
2 changes: 1 addition & 1 deletion src/CoAPNet/CoapMessage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ public List<CoapOption> Options
/// <summary>
/// Indicates if this CoAP message is received from a multicast endpoint or intended to be sent to a multicast endpoint
/// </summary>
public readonly bool IsMulticast;
public bool IsMulticast { get; set; }

/// <summary>
///
Expand Down
149 changes: 147 additions & 2 deletions tests/CoAPNet.Tests/CoapClientTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -422,7 +422,7 @@ public void TestRejectEmptyNonConfirmableMessage()
// TODO: Test Multicast Message Is Marked Multicast
[Test]
[Category("[RFC7252] Section 8.1")]
public async Task TestMulticastMessagFromMulticastEndpoint()
public async Task TestReceiveMulticastMessagFromMulticastEndpoint()
{
// Arrange
var mockClientEndpoint = new Mock<MockEndpoint> { CallBase = true };
Expand Down Expand Up @@ -467,7 +467,7 @@ public async Task TestMulticastMessagFromMulticastEndpoint()
}
catch (CoapEndpointException)
{
Debug.WriteLine($"Caught CoapEndpointException", nameof(TestMulticastMessagFromMulticastEndpoint));
Debug.WriteLine($"Caught CoapEndpointException", nameof(TestReceiveMulticastMessagFromMulticastEndpoint));
}

await messageReceived.Task;
Expand All @@ -478,6 +478,151 @@ public async Task TestMulticastMessagFromMulticastEndpoint()
Assert.IsTrue(messageReceived.Task.Result, "Message is not marked as Multicast");
}

[Test]
[Category("[RFC7252] Section 8.1")]
public async Task TestSendMulticastMessagToMulticastEndpoint()
{
// Arrange
var mockClientEndpoint = new Mock<MockEndpoint> { CallBase = true };
mockClientEndpoint
// Ensure a multicast placeholder endpoint is used.
.Setup(e => e.SendAsync(It.Is<CoapPacket>(p => p.Endpoint is CoapEndpoint && p.Endpoint.IsMulticast == true)))
.CallBase()
.Verifiable("Message was not sent via multicast endpoint");

var message = new CoapMessage
{
IsMulticast = true,
Type = CoapMessageType.NonConfirmable,
Code = CoapMessageCode.Get,
Options = new System.Collections.Generic.List<CoapOption>
{
new Options.ContentFormat(Options.ContentFormatType.ApplicationLinkFormat)
},
Payload = Encoding.UTF8.GetBytes("</.well-known/core>")
};


// Ack
using (var client = new CoapClient(mockClientEndpoint.Object))
{
var ct = new CancellationTokenSource(MaxTaskTimeout);

await client.SendAsync(message, ct.Token);
}

// Assert
Mock.Verify(mockClientEndpoint);
}

[Test]
[Category("[RFC7252] Section 8.1")]
public async Task TestSendMulticastMessagToExplicitMulticastEndpoint()
{
// Arrange
var mockClientEndpoint = new Mock<MockEndpoint> { CallBase = true };
mockClientEndpoint
.Setup(e => e.SendAsync(It.IsAny<CoapPacket>()))
.CallBase()
.Verifiable("Message was not sent via multicast endpoint");

var destEndpoint = new CoapEndpoint { IsMulticast = true };

var message = new CoapMessage
{
IsMulticast = true,
Type = CoapMessageType.NonConfirmable,
Code = CoapMessageCode.Get,
Options = new System.Collections.Generic.List<CoapOption>
{
new Options.ContentFormat(Options.ContentFormatType.ApplicationLinkFormat)
},
Payload = Encoding.UTF8.GetBytes("</.well-known/core>")
};


// Ack
using (var client = new CoapClient(mockClientEndpoint.Object))
{
var ct = new CancellationTokenSource(MaxTaskTimeout);

await client.SendAsync(message, destEndpoint, ct.Token);
}

// Assert
Mock.Verify(mockClientEndpoint);
}

[Test]
[Category("[RFC7252] Section 8.1")]
public void TestSendConfirmableMulticastMessagThrowsCoapClientException()
{
// Arrange
var mockClientEndpoint = new Mock<MockEndpoint> { CallBase = true };

var destEndpoint = new CoapEndpoint { IsMulticast = true };

var message = new CoapMessage
{
IsMulticast = true,
Type = CoapMessageType.Confirmable,
Code = CoapMessageCode.Get,
Options = new System.Collections.Generic.List<CoapOption>
{
new Options.ContentFormat(Options.ContentFormatType.ApplicationLinkFormat)
},
Payload = Encoding.UTF8.GetBytes("</.well-known/core>")
};

// Ack
AsyncTestDelegate action = async () => {
using (var client = new CoapClient(mockClientEndpoint.Object))
{
var ct = new CancellationTokenSource(MaxTaskTimeout);
await client.SendAsync(message, destEndpoint, ct.Token);
}
};

// Assert
Assert.ThrowsAsync<CoapClientException>(action);
}

[Test]
[Category("[RFC7252] Section 8.1")]
public void TestSendMulticastMessagtoNonMulticastEndpointThrowsCoapClientException()
{
// Arrange
var mockClientEndpoint = new Mock<MockEndpoint> { CallBase = true };

var destEndpoint = new CoapEndpoint { IsMulticast = false };

var message = new CoapMessage
{
IsMulticast = true,
Type = CoapMessageType.NonConfirmable,
Code = CoapMessageCode.Get,
Options = new System.Collections.Generic.List<CoapOption>
{
new Options.ContentFormat(Options.ContentFormatType.ApplicationLinkFormat)
},
Payload = Encoding.UTF8.GetBytes("</.well-known/core>")
};

// Ack
AsyncTestDelegate action = async () => {
using (var client = new CoapClient(mockClientEndpoint.Object))
{
var ct = new CancellationTokenSource(MaxTaskTimeout);
await client.SendAsync(message, destEndpoint, ct.Token);
}
};

// Assert
Assert.ThrowsAsync<CoapClientException>(action);
}

// TODO: Test Multicast Message is Non-Confirmable
[Test]
[Category("[RFC7252] Section 8.1")]
Expand Down

0 comments on commit b8ef59a

Please sign in to comment.