From 8d081859dadf56862add66209b84711dc3a71b5c Mon Sep 17 00:00:00 2001 From: Michael Croes Date: Sun, 6 Jun 2021 23:19:56 +0200 Subject: [PATCH 1/4] Remove unused sync methods --- S7.Net.UnitTest/ProtocolTests.cs | 21 +++++---------- S7.Net.UnitTest/StreamTests.cs | 26 +++++++++++++----- S7.Net/COTP.cs | 46 -------------------------------- S7.Net/TPKT.cs | 28 ------------------- 4 files changed, 26 insertions(+), 95 deletions(-) diff --git a/S7.Net.UnitTest/ProtocolTests.cs b/S7.Net.UnitTest/ProtocolTests.cs index 2051edb..4cd634d 100644 --- a/S7.Net.UnitTest/ProtocolTests.cs +++ b/S7.Net.UnitTest/ProtocolTests.cs @@ -21,21 +21,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 +44,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,11 +62,11 @@ 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)); diff --git a/S7.Net.UnitTest/StreamTests.cs b/S7.Net.UnitTest/StreamTests.cs index 9cb0969..d5fe2a1 100644 --- a/S7.Net.UnitTest/StreamTests.cs +++ b/S7.Net.UnitTest/StreamTests.cs @@ -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 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(() => TPKT.Read(m)); + await Assert.ThrowsExceptionAsync(() => TPKT.ReadAsync(m, CancellationToken.None)); } } } diff --git a/S7.Net/COTP.cs b/S7.Net/COTP.cs index a7d9fd7..0300295 100644 --- a/S7.Net/COTP.cs +++ b/S7.Net/COTP.cs @@ -50,22 +50,6 @@ namespace S7.Net Data = new byte[0]; } - /// - /// Reads COTP TPDU (Transport protocol data unit) from the network stream - /// See: https://tools.ietf.org/html/rfc905 - /// - /// The socket to read from - /// COTP DPDU instance - 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); - } - /// /// 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 /// public class TSDU { - /// - /// Reads the full COTP TSDU (Transport service data unit) - /// See: https://tools.ietf.org/html/rfc905 - /// - /// The stream to read from - /// Data in TSDU - 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; - } - /// /// Reads the full COTP TSDU (Transport service data unit) /// See: https://tools.ietf.org/html/rfc905 diff --git a/S7.Net/TPKT.cs b/S7.Net/TPKT.cs index e3d26f7..a311dce 100644 --- a/S7.Net/TPKT.cs +++ b/S7.Net/TPKT.cs @@ -25,34 +25,6 @@ namespace S7.Net Data = data; } - /// - /// Reads a TPKT from the socket - /// - /// The stream to read from - /// TPKT Instance - 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 - ); - } - /// /// Reads a TPKT from the socket Async /// From 36b59a2926b6f4fcfbd2bb125f1492f063ec98f0 Mon Sep 17 00:00:00 2001 From: Michael Croes Date: Sun, 6 Jun 2021 23:20:19 +0200 Subject: [PATCH 2/4] Cleanup whitespace, usings --- S7.Net.UnitTest/ProtocolTests.cs | 11 +++-------- S7.Net/COTP.cs | 2 +- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/S7.Net.UnitTest/ProtocolTests.cs b/S7.Net.UnitTest/ProtocolTests.cs index 4cd634d..e63fac6 100644 --- a/S7.Net.UnitTest/ProtocolTests.cs +++ b/S7.Net.UnitTest/ProtocolTests.cs @@ -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 { @@ -69,7 +65,6 @@ namespace S7.Net.UnitTest 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 }); diff --git a/S7.Net/COTP.cs b/S7.Net/COTP.cs index 0300295..3e5abbb 100644 --- a/S7.Net/COTP.cs +++ b/S7.Net/COTP.cs @@ -91,7 +91,7 @@ namespace S7.Net /// The stream to read from /// Data in TSDU public static async Task ReadAsync(Stream stream, CancellationToken cancellationToken) - { + { var segment = await TPDU.ReadAsync(stream, cancellationToken).ConfigureAwait(false); if (segment.LastDataUnit) From 15f94cd7bf2627eb1e0d0f51e5df17d344100558 Mon Sep 17 00:00:00 2001 From: Serge Camille Date: Mon, 7 Jun 2021 14:13:04 +0200 Subject: [PATCH 3/4] Fix Cancellation test. --- S7.Net.UnitTest/S7NetTestsAsync.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/S7.Net.UnitTest/S7NetTestsAsync.cs b/S7.Net.UnitTest/S7NetTestsAsync.cs index 5ebbf4a..f94ddb8 100644 --- a/S7.Net.UnitTest/S7NetTestsAsync.cs +++ b/S7.Net.UnitTest/S7NetTestsAsync.cs @@ -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. From 36c4564f5e40c8dde4a2cb262d9e0c2e22afd173 Mon Sep 17 00:00:00 2001 From: Michael Croes Date: Mon, 7 Jun 2021 22:19:23 +0200 Subject: [PATCH 4/4] Default ReadTimeout and WriteTimeout to 10 seconds --- S7.Net/PLC.cs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/S7.Net/PLC.cs b/S7.Net/PLC.cs index 7cabc88..35d038e 100644 --- a/S7.Net/PLC.cs +++ b/S7.Net/PLC.cs @@ -20,16 +20,19 @@ namespace S7.Net /// public const int DefaultPort = 102; - private readonly TaskQueue queue = new TaskQueue(); + /// + /// The default timeout (in milliseconds) used for and . + /// + 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 /// /// IP address of the PLC