-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implemented a UDP example to use with NZSmartie.CoAPNet
- Loading branch information
Showing
4 changed files
with
246 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
<Project Sdk="Microsoft.NET.Sdk"> | ||
|
||
<PropertyGroup> | ||
<TargetFramework>netstandard1.4</TargetFramework> | ||
<PackageId>NZSmartie.CoAPNet.Udp</PackageId> | ||
<Version>0.2.3</Version> | ||
<Authors>Roman Vaughan</Authors> | ||
<Company>NZSmartie</Company> | ||
<Description>UDP Socket implementation for NZSmartie.CoAPNet</Description> | ||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild> | ||
<IncludeSource>True</IncludeSource> | ||
<IncludeSymbols>True</IncludeSymbols> | ||
<PackageProjectUrl>https://github.com/NZSmartie/CoAP.Net</PackageProjectUrl> | ||
<RepositoryUrl>https://github.com/NZSmartie/CoAP.Net</RepositoryUrl> | ||
<RepositoryType>git</RepositoryType> | ||
<PackageTags>CoAP IoT sensors devices hardware network protocol udp socket</PackageTags> | ||
<PackageReleaseNotes>v0.2.3 | ||
- Implemented a UDP example to use with NZSmartie.CoAPNet</PackageReleaseNotes> | ||
<AssemblyVersion>0.2.3.0</AssemblyVersion> | ||
<FileVersion>0.2.3.0</FileVersion> | ||
</PropertyGroup> | ||
|
||
<ItemGroup> | ||
<ProjectReference Include="..\CoAPNet\CoAPNet.csproj" /> | ||
</ItemGroup> | ||
|
||
</Project> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
using System; | ||
using System.Diagnostics; | ||
using System.Linq; | ||
using System.Net; | ||
using System.Net.Sockets; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
|
||
namespace CoAPNet.Udp | ||
{ | ||
public class CoapConnectionInformation : ICoapConnectionInformation | ||
{ | ||
public ICoapEndpoint LocalEndpoint { get; set; } | ||
public ICoapEndpoint RemoteEndpoint { get; set; } | ||
} | ||
|
||
public class CoapUdpEndPoint : ICoapEndpoint | ||
{ | ||
private readonly IPEndPoint _endpoint; | ||
private readonly IPAddress _multicastAddressIPv4 = IPAddress.Parse(Coap.MulticastIPv4); | ||
private readonly IPAddress[] _multicastAddressIPv6 = Enumerable.Range(1,13).Select(n => IPAddress.Parse(Coap.GetMulticastIPv6ForScope(n))).ToArray(); | ||
|
||
public IPEndPoint Endpoint => (IPEndPoint)Client?.Client.LocalEndPoint ?? _endpoint; | ||
|
||
public UdpClient Client { get; private set; } | ||
|
||
internal bool Bindable { get; set; } = true; | ||
|
||
public Uri BaseUri { get; } | ||
|
||
public bool CanReceive => Client?.Client.LocalEndPoint != null; | ||
|
||
public bool IsMulticast { get; } | ||
|
||
public bool IsSecure => false; | ||
|
||
public CoapUdpEndPoint(UdpClient udpClient) | ||
{ | ||
Client = udpClient ?? throw new ArgumentNullException(nameof(udpClient)); | ||
_endpoint = (IPEndPoint)Client.Client.LocalEndPoint; | ||
|
||
BaseUri = new UriBuilder() | ||
{ | ||
Scheme = "coap://", | ||
Host = _endpoint.Address.ToString(), | ||
Port = _endpoint.Port != Coap.Port ? _endpoint.Port : -1 | ||
}.Uri; | ||
} | ||
|
||
public CoapUdpEndPoint(IPEndPoint endpoint) | ||
{ | ||
_endpoint = endpoint ?? throw new ArgumentNullException(nameof(endpoint)); | ||
IsMulticast = endpoint.Address.Equals(_multicastAddressIPv4) || _multicastAddressIPv6.Contains(endpoint.Address); | ||
|
||
BaseUri = new UriBuilder() | ||
{ | ||
Scheme = "coap://", | ||
Host = _endpoint.Address.ToString(), | ||
Port = _endpoint.Port != Coap.Port ? _endpoint.Port : -1 | ||
}.Uri; | ||
} | ||
|
||
public Task BindAsync() | ||
{ | ||
if (Client != null) | ||
throw new InvalidOperationException($"Can not bind {nameof(CoapUdpEndPoint)} as it is already bound"); | ||
if(!Bindable) | ||
throw new InvalidOperationException("Can not bind to remote endpoint"); | ||
|
||
Client = new UdpClient(_endpoint) { EnableBroadcast = true }; | ||
return Task.CompletedTask; | ||
} | ||
|
||
public void Dispose() | ||
{ | ||
Client?.Dispose(); | ||
} | ||
|
||
public async Task<CoapPacket> ReceiveAsync(CancellationToken token = default (CancellationToken)) | ||
{ | ||
if (Client == null) | ||
throw new InvalidOperationException(); | ||
|
||
var result = await Client.ReceiveAsync(); | ||
return new CoapPacket | ||
{ | ||
Payload = result.Buffer, | ||
Endpoint = new CoapUdpEndPoint(result.RemoteEndPoint) {Bindable = false}, | ||
}; | ||
} | ||
|
||
public async Task SendAsync(CoapPacket packet, CancellationToken token = default (CancellationToken)) | ||
{ | ||
if (Client == null) | ||
throw new InvalidOperationException(); | ||
|
||
var udpDestEndpoint = packet.Endpoint as CoapUdpEndPoint; | ||
if (udpDestEndpoint == null) | ||
throw new ArgumentException(); | ||
|
||
try | ||
{ | ||
await Client.SendAsync(packet.Payload, packet.Payload.Length, udpDestEndpoint.Endpoint); | ||
} | ||
catch (SocketException se) | ||
{ | ||
Debug.WriteLine($"Failed to send data. {se.GetType().FullName} (0x{se.HResult:x}): {se.Message}"); | ||
} | ||
} | ||
|
||
public override string ToString() | ||
{ | ||
return _endpoint.ToString(); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
using System; | ||
using System.Net.Sockets; | ||
using System.Threading.Tasks; | ||
|
||
namespace CoAPNet.Udp | ||
{ | ||
public class CoapUdpTransportFactory : ICoapTransportFactory | ||
{ | ||
public ICoapTransport Create(ICoapEndpoint endPoint, ICoapHandler handler) | ||
{ | ||
return new CoapUdpTransport(endPoint as CoapUdpEndPoint ?? throw new InvalidOperationException(), handler); | ||
} | ||
} | ||
|
||
public class CoapUdpTransport : ICoapTransport | ||
{ | ||
private CoapUdpEndPoint _endPoint; | ||
|
||
private readonly ICoapHandler _coapHandler; | ||
|
||
private Task _listenTask; | ||
|
||
public CoapUdpTransport(CoapUdpEndPoint endPoint, ICoapHandler coapHandler) | ||
{ | ||
_endPoint = endPoint; | ||
_coapHandler = coapHandler; | ||
} | ||
|
||
public async Task BindAsync() | ||
{ | ||
if(_listenTask != null) | ||
throw new InvalidOperationException($"{nameof(CoapUdpTransport)} has already started"); | ||
|
||
try | ||
{ | ||
await _endPoint.BindAsync().ConfigureAwait(false); | ||
|
||
_listenTask = RunRequestsLoopAsync(); | ||
} | ||
catch (SocketException e) when (e.SocketErrorCode == SocketError.AddressAlreadyInUse) | ||
{ | ||
throw new Exception($"Can not bind to enpoint as address is already in use. {e.Message}", e); | ||
} | ||
} | ||
|
||
public async Task UnbindAsync() | ||
{ | ||
if (_endPoint == null) | ||
return; | ||
|
||
var endPoint = _endPoint; | ||
_endPoint = null; | ||
|
||
endPoint.Dispose(); | ||
await _listenTask.ConfigureAwait(false); | ||
_listenTask = null; | ||
} | ||
|
||
public Task StopAsync() | ||
{ | ||
return Task.CompletedTask; | ||
} | ||
|
||
private async Task RunRequestsLoopAsync() | ||
{ | ||
try | ||
{ | ||
while (true) | ||
{ | ||
var request = await _endPoint.ReceiveAsync(); | ||
_ = _coapHandler.ProcessRequestAsync(new CoapConnectionInformation | ||
{ | ||
LocalEndpoint = _endPoint, | ||
RemoteEndpoint = request.Endpoint, | ||
}, request.Payload); | ||
} | ||
} | ||
catch (Exception) | ||
{ | ||
if (_endPoint != null) | ||
throw; | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters