Improve socket handling.

This commit is contained in:
Christian Kratky
2020-04-03 22:52:55 +02:00
parent 81b547f386
commit ad128c7889
11 changed files with 438 additions and 194 deletions
@@ -0,0 +1,74 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using MQTTnet.Implementations;
using System;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace MQTTnet.Tests
{
[TestClass]
public class CrossPlatformSocket_Tests
{
[TestMethod]
public async Task Connect_Send_Receive()
{
var crossPlatformSocket = new CrossPlatformSocket();
await crossPlatformSocket.ConnectAsync("www.google.de", 80, CancellationToken.None);
var requestBuffer = Encoding.UTF8.GetBytes("GET / HTTP/1.1\r\nHost: www.google.de\r\n\r\n");
await crossPlatformSocket.SendAsync(new ArraySegment<byte>(requestBuffer), System.Net.Sockets.SocketFlags.None);
var buffer = new byte[1024];
var length = await crossPlatformSocket.ReceiveAsync(new ArraySegment<byte>(buffer), System.Net.Sockets.SocketFlags.None);
crossPlatformSocket.Dispose();
var responseText = Encoding.UTF8.GetString(buffer, 0, length);
Assert.IsTrue(responseText.Contains("HTTP/1.1 200 OK"));
}
[TestMethod]
public async Task Try_Connect_Invalid_Host()
{
var crossPlatformSocket = new CrossPlatformSocket();
var cancellationToken = new CancellationTokenSource(TimeSpan.FromSeconds(3));
cancellationToken.Token.Register(() => crossPlatformSocket.Dispose());
await crossPlatformSocket.ConnectAsync("www.google.de", 1234, CancellationToken.None);
}
//[TestMethod]
//public async Task Use_Disconnected_Socket()
//{
// var crossPlatformSocket = new CrossPlatformSocket();
// await crossPlatformSocket.ConnectAsync("www.google.de", 80);
// var requestBuffer = Encoding.UTF8.GetBytes("GET /wrong_uri HTTP/1.1\r\nConnection: close\r\n\r\n");
// await crossPlatformSocket.SendAsync(new ArraySegment<byte>(requestBuffer), System.Net.Sockets.SocketFlags.None);
// var buffer = new byte[64000];
// var length = await crossPlatformSocket.ReceiveAsync(new ArraySegment<byte>(buffer), System.Net.Sockets.SocketFlags.None);
// await Task.Delay(500);
// await crossPlatformSocket.SendAsync(new ArraySegment<byte>(requestBuffer), System.Net.Sockets.SocketFlags.None);
//}
[TestMethod]
public async Task Set_Options()
{
var crossPlatformSocket = new CrossPlatformSocket();
Assert.IsFalse(crossPlatformSocket.ReuseAddress);
crossPlatformSocket.ReuseAddress = true;
Assert.IsTrue(crossPlatformSocket.ReuseAddress);
Assert.IsFalse(crossPlatformSocket.NoDelay);
crossPlatformSocket.NoDelay = true;
Assert.IsTrue(crossPlatformSocket.NoDelay);
}
}
}
@@ -1,10 +1,10 @@
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using MQTTnet.Implementations;
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using MQTTnet.Implementations;
namespace MQTTnet.Tests
{
@@ -15,7 +15,7 @@ namespace MQTTnet.Tests
public async Task Dispose_Channel_While_Used()
{
var ct = new CancellationTokenSource();
var serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
var serverSocket = new CrossPlatformSocket(AddressFamily.InterNetwork);
try
{
@@ -28,18 +28,18 @@ namespace MQTTnet.Tests
{
while (!ct.IsCancellationRequested)
{
var client = await PlatformAbstractionLayer.AcceptAsync(serverSocket);
var client = await serverSocket.AcceptAsync();
var data = new byte[] { 128 };
await PlatformAbstractionLayer.SendAsync(client, new ArraySegment<byte>(data), SocketFlags.None);
await client.SendAsync(new ArraySegment<byte>(data), SocketFlags.None);
}
}, ct.Token);
var clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
await PlatformAbstractionLayer.ConnectAsync(clientSocket, IPAddress.Loopback, 50001);
var clientSocket = new CrossPlatformSocket(AddressFamily.InterNetwork);
await clientSocket.ConnectAsync("localhost", 50001, CancellationToken.None);
await Task.Delay(100, ct.Token);
var tcpChannel = new MqttTcpChannel(new NetworkStream(clientSocket, true), "test", null);
var tcpChannel = new MqttTcpChannel(clientSocket.GetStream(), "test", null);
var buffer = new byte[1];
await tcpChannel.ReadAsync(buffer, 0, 1, ct.Token);
+17 -16
View File
@@ -904,14 +904,13 @@ namespace MQTTnet.Tests
await testEnvironment.StartServerAsync(serverOptions);
var connectingFailedException = await Assert.ThrowsExceptionAsync<MqttConnectingFailedException>(() => testEnvironment.ConnectClientAsync());
Assert.AreEqual(MqttClientConnectResultCode.NotAuthorized, connectingFailedException.ResultCode);
}
}
Dictionary<string, bool> _connected;
private Dictionary<string, bool> _connected;
private void ConnectionValidationHandler(MqttConnectionValidatorContext eventArgs)
{
if (_connected.ContainsKey(eventArgs.ClientId))
@@ -919,6 +918,7 @@ namespace MQTTnet.Tests
eventArgs.ReasonCode = MqttConnectReasonCode.BadUserNameOrPassword;
return;
}
_connected[eventArgs.ClientId] = true;
eventArgs.ReasonCode = MqttConnectReasonCode.Success;
return;
@@ -1053,6 +1053,12 @@ namespace MQTTnet.Tests
// Connect client with same client ID. Should disconnect existing client.
var c2 = await testEnvironment.ConnectClientAsync(clientOptionsBuilder);
await Task.Delay(500);
flow = string.Join(string.Empty, events);
Assert.AreEqual("cdc", flow);
c2.UseApplicationMessageReceivedHandler(_ =>
{
lock (events)
@@ -1061,15 +1067,10 @@ namespace MQTTnet.Tests
}
});
c2.SubscribeAsync("topic").Wait();
await Task.Delay(500);
flow = string.Join(string.Empty, events);
Assert.AreEqual("cdc", flow);
await c2.SubscribeAsync("topic");
// r
c2.PublishAsync("topic").Wait();
await c2.PublishAsync("topic");
await Task.Delay(500);
@@ -1149,15 +1150,15 @@ namespace MQTTnet.Tests
{
await testEnvironment.StartServerAsync(new MqttServerOptionsBuilder().WithDefaultCommunicationTimeout(TimeSpan.FromSeconds(1)));
var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
await PlatformAbstractionLayer.ConnectAsync(client, "localhost", testEnvironment.ServerPort);
var client = new CrossPlatformSocket(AddressFamily.InterNetwork);
await client.ConnectAsync("localhost", testEnvironment.ServerPort, CancellationToken.None);
// Don't send anything. The server should close the connection.
await Task.Delay(TimeSpan.FromSeconds(3));
try
{
var receivedBytes = await PlatformAbstractionLayer.ReceiveAsync(client, new ArraySegment<byte>(new byte[10]), SocketFlags.Partial);
var receivedBytes = await client.ReceiveAsync(new ArraySegment<byte>(new byte[10]), SocketFlags.Partial);
if (receivedBytes == 0)
{
return;
@@ -1180,17 +1181,17 @@ namespace MQTTnet.Tests
// Send an invalid packet and ensure that the server will close the connection and stay in a waiting state
// forever. This is security related.
var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
await PlatformAbstractionLayer.ConnectAsync(client, "localhost", testEnvironment.ServerPort);
var client = new CrossPlatformSocket(AddressFamily.InterNetwork);
await client.ConnectAsync("localhost", testEnvironment.ServerPort, CancellationToken.None);
var buffer = Encoding.UTF8.GetBytes("Garbage");
client.Send(buffer, buffer.Length, SocketFlags.None);
await client.SendAsync(new ArraySegment<byte>(buffer), SocketFlags.None);
await Task.Delay(TimeSpan.FromSeconds(3));
try
{
var receivedBytes = await PlatformAbstractionLayer.ReceiveAsync(client, new ArraySegment<byte>(new byte[10]), SocketFlags.Partial);
var receivedBytes = await client.ReceiveAsync(new ArraySegment<byte>(new byte[10]), SocketFlags.Partial);
if (receivedBytes == 0)
{
return;