Merge branch 'develop' into test-ConnectionClose

This commit is contained in:
Serge Camille
2021-06-08 22:53:30 +02:00
6 changed files with 40 additions and 111 deletions

View File

@@ -1,14 +1,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using S7.Net;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using S7.Net.Protocol;
using System.Collections;
namespace S7.Net.UnitTest
{
@@ -21,21 +17,17 @@ namespace S7.Net.UnitTest
public async Task TPKT_Read()
{
var m = new MemoryStream(StringToByteArray("0300002902f0803203000000010002001400000401ff0400807710000100000103000000033f8ccccd"));
var t = TPKT.Read(m);
Assert.AreEqual(0x03, t.Version);
Assert.AreEqual(0x29, t.Length);
m.Position = 0;
t = await TPKT.ReadAsync(m, TestContext.CancellationTokenSource.Token);
var t = await TPKT.ReadAsync(m, TestContext.CancellationTokenSource.Token);
Assert.AreEqual(0x03, t.Version);
Assert.AreEqual(0x29, t.Length);
}
[TestMethod]
[ExpectedException(typeof(TPKTInvalidException))]
public void TPKT_ReadShort()
public async Task TPKT_ReadShort()
{
var m = new MemoryStream(StringToByteArray("0300002902f0803203000000010002001400000401ff040080"));
var t = TPKT.Read(m);
var t = await TPKT.ReadAsync(m, CancellationToken.None);
}
@@ -48,14 +40,11 @@ namespace S7.Net.UnitTest
}
[TestMethod]
public void COTP_ReadTSDU()
public async Task COTP_ReadTSDU()
{
var expected = StringToByteArray("320700000400000800080001120411440100ff09000400000000");
var m = new MemoryStream(StringToByteArray("0300000702f0000300000702f0000300002102f080320700000400000800080001120411440100ff09000400000000"));
var t = COTP.TSDU.Read(m);
Assert.IsTrue(expected.SequenceEqual(t));
m.Position = 0;
t = COTP.TSDU.ReadAsync(m, TestContext.CancellationTokenSource.Token).Result;
var t = await COTP.TSDU.ReadAsync(m, TestContext.CancellationTokenSource.Token);
Assert.IsTrue(expected.SequenceEqual(t));
}
@@ -69,14 +58,13 @@ namespace S7.Net.UnitTest
[TestMethod]
public void TestResponseCode()
public async Task TestResponseCode()
{
var expected = StringToByteArray("320700000400000800080001120411440100ff09000400000000");
var m = new MemoryStream(StringToByteArray("0300000702f0000300000702f0000300002102f080320700000400000800080001120411440100ff09000400000000"));
var t = COTP.TSDU.Read(m);
var t = await COTP.TSDU.ReadAsync(m, CancellationToken.None);
Assert.IsTrue(expected.SequenceEqual(t));
// Test all possible byte values. Everything except 0xff should throw an exception.
var testData = Enumerable.Range(0, 256).Select(i => new { StatusCode = (ReadWriteErrorCode)i, ThrowsException = i != (byte)ReadWriteErrorCode.Success });

View File

@@ -935,15 +935,15 @@ namespace S7.Net.UnitTest
{
await plc.WriteBytesAsync(DataType.DataBlock, db, 0, data, cancellationToken);
}
catch(TaskCanceledException)
catch(OperationCanceledException)
{
// everything is good, that is the exception we expect
Console.WriteLine("Task was cancelled as expected.");
Console.WriteLine("Operation was cancelled as expected.");
return;
}
catch(Exception e)
{
Assert.Fail($"Wrong exception type received. Expected {typeof(TaskCanceledException)}, received {e.GetType()}.");
Assert.Fail($"Wrong exception type received. Expected {typeof(OperationCanceledException)}, received {e.GetType()}.");
}
// Depending on how tests run, this can also just succeed without getting cancelled at all. Do nothing in this case.

View File

@@ -2,6 +2,7 @@
using System;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace S7.Net.UnitTest
@@ -15,6 +16,7 @@ namespace S7.Net.UnitTest
{
Data = data;
}
public override bool CanRead => _position < Data.Length;
public override bool CanSeek => throw new NotImplementedException();
@@ -26,21 +28,31 @@ namespace S7.Net.UnitTest
public override long Position { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
public byte[] Data { get; }
int _position = 0;
public override void Flush()
{
throw new NotImplementedException();
}
int _position = 0;
public override int Read(byte[] buffer, int offset, int count)
{
throw new NotImplementedException();
}
public override Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
if (_position >= Data.Length)
{
return 0;
return Task.FromResult(0);
}
buffer[offset] = Data[_position];
++_position;
return 1;
return Task.FromResult(1);
}
public override long Seek(long offset, SeekOrigin origin)
@@ -78,21 +90,21 @@ namespace S7.Net.UnitTest
}
[TestMethod]
public void TPKT_ReadRestrictedStream()
public async Task TPKT_ReadRestrictedStream()
{
var fullMessage = ProtocolUnitTest.StringToByteArray("0300002902f0803203000000010002001400000401ff0400807710000100000103000000033f8ccccd");
var m = new TestStream1BytePerRead(fullMessage);
var t = TPKT.Read(m);
var t = await TPKT.ReadAsync(m, CancellationToken.None);
Assert.AreEqual(fullMessage.Length, t.Length);
Assert.AreEqual(fullMessage.Last(), t.Data.Last());
}
[TestMethod]
public void TPKT_ReadStreamTooShort()
public async Task TPKT_ReadStreamTooShort()
{
var fullMessage = ProtocolUnitTest.StringToByteArray("0300002902f0803203000000010002001400");
var m = new TestStream1BytePerRead(fullMessage);
Assert.ThrowsException<TPKTInvalidException>(() => TPKT.Read(m));
await Assert.ThrowsExceptionAsync<TPKTInvalidException>(() => TPKT.ReadAsync(m, CancellationToken.None));
}
}
}

View File

@@ -50,22 +50,6 @@ namespace S7.Net
Data = new byte[0];
}
/// <summary>
/// Reads COTP TPDU (Transport protocol data unit) from the network stream
/// See: https://tools.ietf.org/html/rfc905
/// </summary>
/// <param name="stream">The socket to read from</param>
/// <returns>COTP DPDU instance</returns>
public static TPDU Read(Stream stream)
{
var tpkt = TPKT.Read(stream);
if (tpkt.Length == 0)
{
throw new TPDUInvalidException("No protocol data received");
}
return new TPDU(tpkt);
}
/// <summary>
/// Reads COTP TPDU (Transport protocol data unit) from the network stream
/// See: https://tools.ietf.org/html/rfc905
@@ -100,36 +84,6 @@ namespace S7.Net
/// </summary>
public class TSDU
{
/// <summary>
/// Reads the full COTP TSDU (Transport service data unit)
/// See: https://tools.ietf.org/html/rfc905
/// </summary>
/// <param name="stream">The stream to read from</param>
/// <returns>Data in TSDU</returns>
public static byte[] Read(Stream stream)
{
var segment = TPDU.Read(stream);
if (segment.LastDataUnit)
{
return segment.Data;
}
// More segments are expected, prepare a buffer to store all data
var buffer = new byte[segment.Data.Length];
Array.Copy(segment.Data, buffer, segment.Data.Length);
while (!segment.LastDataUnit)
{
segment = TPDU.Read(stream);
var previousLength = buffer.Length;
Array.Resize(ref buffer, buffer.Length + segment.Data.Length);
Array.Copy(segment.Data, 0, buffer, previousLength, segment.Data.Length);
}
return buffer;
}
/// <summary>
/// Reads the full COTP TSDU (Transport service data unit)
/// See: https://tools.ietf.org/html/rfc905
@@ -137,7 +91,7 @@ namespace S7.Net
/// <param name="stream">The stream to read from</param>
/// <returns>Data in TSDU</returns>
public static async Task<byte[]> ReadAsync(Stream stream, CancellationToken cancellationToken)
{
{
var segment = await TPDU.ReadAsync(stream, cancellationToken).ConfigureAwait(false);
if (segment.LastDataUnit)

View File

@@ -20,16 +20,19 @@ namespace S7.Net
/// </summary>
public const int DefaultPort = 102;
private readonly TaskQueue queue = new TaskQueue();
/// <summary>
/// The default timeout (in milliseconds) used for <see cref="P:ReadTimeout"/> and <see cref="P:WriteTimeout"/>.
/// </summary>
public const int DefaultTimeout = 10_000;
private const int CONNECTION_TIMED_OUT_ERROR_CODE = 10060;
private readonly TaskQueue queue = new TaskQueue();
//TCP connection to device
private TcpClient? tcpClient;
private NetworkStream? _stream;
private int readTimeout = 0; // default no timeout
private int writeTimeout = 0; // default no timeout
private int readTimeout = DefaultTimeout; // default no timeout
private int writeTimeout = DefaultTimeout; // default no timeout
/// <summary>
/// IP address of the PLC

View File

@@ -25,34 +25,6 @@ namespace S7.Net
Data = data;
}
/// <summary>
/// Reads a TPKT from the socket
/// </summary>
/// <param name="stream">The stream to read from</param>
/// <returns>TPKT Instance</returns>
public static TPKT Read(Stream stream)
{
var buf = new byte[4];
int len = stream.ReadExact(buf, 0, 4);
if (len < 4) throw new TPKTInvalidException($"TPKT header is incomplete / invalid. Received Bytes: {len} expected: {buf.Length}");
var version = buf[0];
var reserved1 = buf[1];
var length = buf[2] * 256 + buf[3]; //BigEndian
var data = new byte[length - 4];
len = stream.ReadExact(data, 0, data.Length);
if (len < data.Length)
throw new TPKTInvalidException($"TPKT payload is incomplete / invalid. Received Bytes: {len} expected: {data.Length}");
return new TPKT
(
version: version,
reserved1: reserved1,
length: length,
data: data
);
}
/// <summary>
/// Reads a TPKT from the socket Async
/// </summary>