@@ -1,9 +0,0 @@ | |||
namespace MQTTnet.Server.Configuration | |||
{ | |||
public class EndpointConfiguration | |||
{ | |||
public int Port { get; set; } = 1883; | |||
public int BacklogSize { get; set; } = 10; | |||
} | |||
} |
@@ -1,4 +1,7 @@ | |||
namespace MQTTnet.Server.Configuration | |||
using System.IO; | |||
using System.Net; | |||
namespace MQTTnet.Server.Configuration | |||
{ | |||
/// <summary> | |||
/// Listen Entry Settings Model | |||
@@ -12,19 +15,142 @@ | |||
{ | |||
} | |||
/// <summary> | |||
/// Path to Certificate | |||
/// </summary> | |||
public string CertificatePath { get; set; } | |||
/// <summary> | |||
/// Enabled / Disable | |||
/// </summary> | |||
public bool Enabled { get; set; } = true; | |||
/// <summary> | |||
/// Listen Address | |||
/// </summary> | |||
public string IPv4 { get; set; } | |||
/// <summary> | |||
/// Listen Address | |||
/// </summary> | |||
public string Address { get; set; } | |||
public string IPv6 { get; set; } | |||
/// <summary> | |||
/// Listen Port | |||
/// </summary> | |||
public int Port { get; set; } | |||
public int Port { get; set; } = 1883; | |||
/// <summary> | |||
/// Read Certificate file | |||
/// </summary> | |||
/// <returns></returns> | |||
public byte[] ReadCertificate() | |||
{ | |||
if (string.IsNullOrEmpty(CertificatePath) || string.IsNullOrWhiteSpace(CertificatePath)) | |||
{ | |||
throw new FileNotFoundException("No path set"); | |||
} | |||
if (!File.Exists(CertificatePath)) | |||
{ | |||
throw new FileNotFoundException($"Could not find Certificate in path: {CertificatePath}"); | |||
} | |||
return File.ReadAllBytes(CertificatePath); | |||
} | |||
/// <summary> | |||
/// Protocol Type | |||
/// Read IPv4 | |||
/// </summary> | |||
public ListenProtocolTypes Protocol { get; set; } = ListenProtocolTypes.HTTP; | |||
/// <returns></returns> | |||
public IPAddress ReafIPv4() | |||
{ | |||
if (IPv4 == "*") | |||
{ | |||
return IPAddress.Parse("0.0.0.0"); | |||
} | |||
if (IPv4 == "localhost") | |||
{ | |||
return IPAddress.Parse("127.0.0.1"); | |||
} | |||
if (IPAddress.TryParse(IPv4, out var ip)) | |||
{ | |||
return ip; | |||
} | |||
throw new System.Exception($"Could not parse IPv4 address: {IPv4}"); | |||
} | |||
/// <summary> | |||
/// Read IPv4 | |||
/// </summary> | |||
/// <returns></returns> | |||
public bool TryReadIPv4(out IPAddress address) | |||
{ | |||
if (IPv4 == "*") | |||
{ | |||
address = IPAddress.Parse("::"); | |||
return true; | |||
} | |||
if (IPv4 == "localhost") | |||
{ | |||
address = IPAddress.Parse("::1"); | |||
return true; | |||
} | |||
if (IPv4 == "disable") | |||
{ | |||
address = null; | |||
return false; | |||
} | |||
if (IPAddress.TryParse(IPv4, out var ip)) | |||
{ | |||
address = ip; | |||
return true; | |||
} | |||
else | |||
{ | |||
throw new System.Exception($"Could not parse IPv4 address: {IPv4}"); | |||
} | |||
} | |||
/// <summary> | |||
/// Read IPv6 | |||
/// </summary> | |||
/// <returns></returns> | |||
public bool TryReadIPv6(out IPAddress address) | |||
{ | |||
if (IPv6 == "*") | |||
{ | |||
address = IPAddress.Parse("::"); | |||
return true; | |||
} | |||
if (IPv6 == "localhost") | |||
{ | |||
address = IPAddress.Parse("::1"); | |||
return true; | |||
} | |||
if (IPv6 == "disable") | |||
{ | |||
address = null; | |||
return false; | |||
} | |||
if (IPAddress.TryParse(IPv6, out var ip)) | |||
{ | |||
address = ip; | |||
return true; | |||
} | |||
else | |||
{ | |||
throw new System.Exception($"Could not parse IPv6 address: {IPv6}"); | |||
} | |||
} | |||
} | |||
} |
@@ -1,23 +0,0 @@ | |||
namespace MQTTnet.Server.Configuration | |||
{ | |||
/// <summary> | |||
/// Listen Protocol Types | |||
/// </summary> | |||
public enum ListenProtocolTypes | |||
{ | |||
/// <summary> | |||
/// HTTP | |||
/// </summary> | |||
HTTP = 0, | |||
/// <summary> | |||
/// HTTPS | |||
/// </summary> | |||
HTTPS = 1, | |||
/// <summary> | |||
/// MQTT | |||
/// </summary> | |||
MQTT = 20 | |||
} | |||
} |
@@ -1,7 +0,0 @@ | |||
namespace MQTTnet.Server.Configuration | |||
{ | |||
public class MqttNetServerConfiguration | |||
{ | |||
} | |||
} |
@@ -1,15 +1,42 @@ | |||
using System.Collections.Generic; | |||
namespace MQTTnet.Server.Configuration | |||
namespace MQTTnet.Server.Configuration | |||
{ | |||
/// <summary> | |||
/// Main Settings Model | |||
/// </summary> | |||
public class SettingsModel | |||
{ | |||
public SettingsModel() | |||
{ | |||
} | |||
/// <summary> | |||
/// Set default connection timeout in seconds | |||
/// </summary> | |||
public int CommunicationTimeout { get; set; } = 15; | |||
/// <summary> | |||
/// Set 0 to disable connection backlogging | |||
/// </summary> | |||
public int ConnectionBacklog { get; set; } | |||
/// <summary> | |||
/// Enable support for persistent sessions | |||
/// </summary> | |||
public bool EnablePersistentSessions { get; set; } = false; | |||
/// <summary> | |||
/// Listen Settings | |||
/// </summary> | |||
public IEnumerable<ListenModel> Listen { get; set; } | |||
public ListenModel Listen { get; set; } = new ListenModel(); | |||
/// <summary> | |||
/// Encryption Listen Settings | |||
/// </summary> | |||
public ListenModel ListenEncryption { get; set; } = new ListenModel(); | |||
/// <summary> | |||
/// Set limit for max pending messages per client | |||
/// </summary> | |||
public int MaxPendingMessagesPerClient { get; set; } = 250; | |||
} | |||
} |
@@ -16,18 +16,19 @@ namespace MQTTnet.Server.Mqtt | |||
{ | |||
private readonly ILogger<MqttServerService> _logger; | |||
private readonly Configuration.SettingsModel _settings; | |||
private readonly MqttApplicationMessageInterceptor _mqttApplicationMessageInterceptor; | |||
private readonly MqttClientConnectedHandler _mqttClientConnectedHandler; | |||
private readonly MqttClientDisconnectedHandler _mqttClientDisconnectedHandler; | |||
private readonly MqttClientSubscribedTopicHandler _mqttClientSubscribedTopicHandler; | |||
private readonly MqttClientUnsubscribedTopicHandler _mqttClientUnsubscribedTopicHandler; | |||
private readonly MqttConnectionValidator _mqttConnectionValidator; | |||
private readonly IMqttServer _mqttServer; | |||
private readonly MqttSubscriptionInterceptor _mqttSubscriptionInterceptor; | |||
private readonly MqttApplicationMessageInterceptor _mqttApplicationMessageInterceptor; | |||
private readonly PythonScriptHostService _pythonScriptHostService; | |||
private readonly IMqttServer _mqttServer; | |||
public MqttServerService( | |||
Configuration.SettingsModel settings, | |||
CustomMqttFactory mqttFactory, | |||
MqttWebSocketServerAdapter webSocketServerAdapter, | |||
MqttClientConnectedHandler mqttClientConnectedHandler, | |||
@@ -40,6 +41,7 @@ namespace MQTTnet.Server.Mqtt | |||
PythonScriptHostService pythonScriptHostService, | |||
ILogger<MqttServerService> logger) | |||
{ | |||
_settings = settings; | |||
_mqttClientConnectedHandler = mqttClientConnectedHandler ?? throw new ArgumentNullException(nameof(mqttClientConnectedHandler)); | |||
_mqttClientDisconnectedHandler = mqttClientDisconnectedHandler ?? throw new ArgumentNullException(nameof(mqttClientDisconnectedHandler)); | |||
_mqttClientSubscribedTopicHandler = mqttClientSubscribedTopicHandler ?? throw new ArgumentNullException(nameof(mqttClientSubscribedTopicHandler)); | |||
@@ -64,19 +66,75 @@ namespace MQTTnet.Server.Mqtt | |||
_pythonScriptHostService.RegisterProxyObject("publish", new Action<PythonDictionary>(Publish)); | |||
var options = new MqttServerOptionsBuilder() | |||
.WithDefaultEndpoint() | |||
.WithDefaultEndpointPort(1883) | |||
.WithMaxPendingMessagesPerClient(_settings.MaxPendingMessagesPerClient) | |||
.WithDefaultCommunicationTimeout(TimeSpan.FromSeconds(_settings.CommunicationTimeout)) | |||
.WithConnectionValidator(_mqttConnectionValidator) | |||
.WithApplicationMessageInterceptor(_mqttApplicationMessageInterceptor) | |||
.WithSubscriptionInterceptor(_mqttSubscriptionInterceptor) | |||
.Build(); | |||
.WithSubscriptionInterceptor(_mqttSubscriptionInterceptor); | |||
// Configure unencrypted connections | |||
if (_settings.Listen.Enabled) | |||
{ | |||
options.WithDefaultEndpoint(); | |||
if (_settings.Listen.TryReadIPv6(out var address4)) | |||
{ | |||
options.WithDefaultEndpointBoundIPAddress(address4); | |||
} | |||
if (_settings.Listen.TryReadIPv6(out var address6)) | |||
{ | |||
options.WithDefaultEndpointBoundIPV6Address(address6); | |||
} | |||
if (_settings.Listen.Port > 0) | |||
{ | |||
options.WithDefaultEndpointPort(_settings.Listen.Port); | |||
} | |||
} | |||
else | |||
{ | |||
options.WithoutDefaultEndpoint(); | |||
} | |||
// Configure encrypted connections | |||
if (_settings.ListenEncryption.Enabled) | |||
{ | |||
options | |||
.WithEncryptedEndpoint() | |||
.WithEncryptionSslProtocol(System.Security.Authentication.SslProtocols.Tls12) | |||
.WithEncryptionCertificate(_settings.ListenEncryption.ReadCertificate()); | |||
if (_settings.ListenEncryption.TryReadIPv6(out var address4)) | |||
{ | |||
options.WithDefaultEndpointBoundIPAddress(address4); | |||
} | |||
if (_settings.ListenEncryption.TryReadIPv6(out var address6)) | |||
{ | |||
options.WithDefaultEndpointBoundIPV6Address(address6); | |||
} | |||
if (_settings.Listen.Port > 0) | |||
{ | |||
options.WithEncryptedEndpointPort(_settings.ListenEncryption.Port); | |||
} | |||
} | |||
else | |||
{ | |||
options.WithoutEncryptedEndpoint(); | |||
} | |||
if (_settings.ConnectionBacklog > 0) | |||
{ | |||
options.WithConnectionBacklog(_settings.ConnectionBacklog); | |||
} | |||
_mqttServer.ClientConnectedHandler = _mqttClientConnectedHandler; | |||
_mqttServer.ClientDisconnectedHandler = _mqttClientDisconnectedHandler; | |||
_mqttServer.ClientSubscribedTopicHandler = _mqttClientSubscribedTopicHandler; | |||
_mqttServer.ClientUnsubscribedTopicHandler = _mqttClientUnsubscribedTopicHandler; | |||
_mqttServer.StartAsync(options).GetAwaiter().GetResult(); | |||
_mqttServer.StartAsync(options.Build()).GetAwaiter().GetResult(); | |||
_logger.LogInformation("MQTT server started."); | |||
} | |||
@@ -127,4 +185,4 @@ namespace MQTTnet.Server.Mqtt | |||
} | |||
} | |||
} | |||
} | |||
} |
@@ -15,11 +15,11 @@ namespace MQTTnet.Server | |||
{ | |||
public Startup(IConfiguration configuration) | |||
{ | |||
//var builder = new ConfigurationBuilder() | |||
// .AddJsonFile("appsettings.json") | |||
// .AddEnvironmentVariables(); | |||
var builder = new ConfigurationBuilder() | |||
.AddJsonFile("appsettings.json") | |||
.AddEnvironmentVariables(); | |||
//Configuration = builder.Build(); | |||
Configuration = builder.Build(); | |||
} | |||
public IConfigurationRoot Configuration { get; } | |||
@@ -52,6 +52,12 @@ namespace MQTTnet.Server | |||
{ | |||
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2); | |||
// Read settings | |||
var settings = new Configuration.SettingsModel(); | |||
Configuration.Bind("MQTTnet", settings); | |||
services.AddSingleton(settings); | |||
// Wire up dependencies | |||
services.AddSingleton<PythonIOStream>(); | |||
services.AddSingleton<PythonScriptHostService>(); | |||
services.AddSingleton<DataSharingService>(); | |||
@@ -1,32 +1,33 @@ | |||
{ | |||
"MQTTnetServer": { | |||
/* | |||
Wildcard Addresses: | |||
* - All local IP addresses | |||
localhost - Localhost only | |||
Supported Protocols: | |||
0 - HTTP | |||
1 - HTTPS | |||
20 - MQTT | |||
*/ | |||
"Listen": [ | |||
{ | |||
"Address": "localhost", | |||
"Port": 5000, | |||
"Protocol": 0 | |||
}, | |||
{ | |||
"Address": "*", | |||
"Port": 1883, | |||
"Protocol": 20 | |||
} | |||
] | |||
}, | |||
"Logging": { | |||
"LogLevel": { | |||
"Default": "Warning" | |||
} | |||
}, | |||
"AllowedHosts": "*" | |||
"MQTTnet": { | |||
/* | |||
Wildcard Addresses: | |||
* - All local IP addresses | |||
localhost - Localhost only | |||
disable - Skip address assignment | |||
*/ | |||
"Listen": { | |||
"Enabled": true, | |||
"IPv4": "localhost", | |||
"IPv6": "localhost", | |||
"Port": 1883 | |||
}, | |||
"ListenEncryption": { | |||
"Enabled": false, | |||
"IPv4": "localhost", | |||
"IPv6": "localhost", | |||
"Port": 8883, | |||
"CertificatePath": "/absolute/path/to/certificate" | |||
}, | |||
"CommunicationTimeout": 15, /* In seconds */ | |||
"ConnectionBacklog": 0, /* Set 0 to disable */ | |||
"EnablePersistentSessions": false, | |||
"MaxPendingMessagesPerClient": 250 | |||
}, | |||
"Logging": { | |||
"LogLevel": { | |||
"Default": "Warning" | |||
} | |||
}, | |||
"AllowedHosts": "*" | |||
} |