forked from S7NetPlus/s7netplus
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
173 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
using System.ComponentModel; | ||
|
||
namespace System.Runtime.CompilerServices | ||
{ | ||
[EditorBrowsable(EditorBrowsableState.Never)] | ||
internal record IsExternalInit; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
using System; | ||
using System.Buffers; | ||
using System.Collections; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Net; | ||
using System.Net.Sockets; | ||
using System.Threading.Tasks; | ||
|
||
namespace S7.Net.UnitTest; | ||
|
||
internal class CommunicationSequence : IEnumerable<RequestResponsePair> | ||
{ | ||
private readonly List<RequestResponsePair> _requestResponsePairs = new List<RequestResponsePair>(); | ||
|
||
public CommunicationSequence() | ||
{ | ||
|
||
} | ||
|
||
public void Add(string requestPattern, string responsePattern) | ||
{ | ||
_requestResponsePairs.Add(new RequestResponsePair(requestPattern, responsePattern)); | ||
} | ||
|
||
public IEnumerator<RequestResponsePair> GetEnumerator() | ||
{ | ||
return _requestResponsePairs.GetEnumerator(); | ||
} | ||
|
||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); | ||
|
||
public Task Serve(out int port) | ||
{ | ||
var socket = CreateBoundListenSocket(out port); | ||
socket.Listen(0); | ||
|
||
async Task Impl() | ||
{ | ||
await Task.Yield(); | ||
var socketIn = socket.Accept(); | ||
|
||
var buffer = ArrayPool<byte>.Shared.Rent(1024); | ||
try | ||
{ | ||
foreach (var pair in _requestResponsePairs) | ||
{ | ||
var bytesReceived = socketIn.Receive(buffer, SocketFlags.None); | ||
|
||
var received = buffer.Take(bytesReceived).ToArray(); | ||
Console.WriteLine($"=> {BitConverter.ToString(received)}"); | ||
|
||
var response = Responder.Respond(pair, received); | ||
|
||
Console.WriteLine($"<= {BitConverter.ToString(response)}"); | ||
socketIn.Send(response); | ||
} | ||
} | ||
finally | ||
{ | ||
ArrayPool<byte>.Shared.Return(buffer); | ||
} | ||
|
||
socketIn.Close(); | ||
} | ||
|
||
return Impl(); | ||
} | ||
|
||
private static Socket CreateBoundListenSocket(out int port) | ||
{ | ||
var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); | ||
var endpoint = new IPEndPoint(IPAddress.Loopback, 0); | ||
|
||
socket.Bind(endpoint); | ||
|
||
var localEndpoint = (IPEndPoint)socket.LocalEndPoint!; | ||
port = localEndpoint.Port; | ||
|
||
return socket; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
namespace S7.Net.UnitTest; | ||
|
||
internal record RequestResponsePair(string RequestPattern, string ResponsePattern); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Globalization; | ||
using System.IO; | ||
|
||
namespace S7.Net.UnitTest; | ||
|
||
internal static class Responder | ||
{ | ||
private const string Comment = "//"; | ||
private static char[] Space = " ".ToCharArray(); | ||
|
||
public static byte[] Respond(RequestResponsePair pair, byte[] request) | ||
{ | ||
var offset = 0; | ||
var matches = new Dictionary<string, byte>(); | ||
var res = new List<byte>(); | ||
using var requestReader = new StringReader(pair.RequestPattern); | ||
|
||
string line; | ||
while ((line = requestReader.ReadLine()) != null) | ||
{ | ||
var tokens = line.Split(Space, StringSplitOptions.RemoveEmptyEntries); | ||
foreach (var token in tokens) | ||
{ | ||
if (token.StartsWith(Comment)) break; | ||
|
||
if (offset >= request.Length) | ||
{ | ||
throw new Exception("Request pattern has more data than request."); | ||
} | ||
|
||
var received = request[offset]; | ||
|
||
if (token.Length == 2 && byte.TryParse(token, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var value)) | ||
{ | ||
// Number, exact match | ||
if (value != received) | ||
{ | ||
throw new Exception($"Incorrect data at offset {offset}. Expected {value:X2}, received {received:X2}."); | ||
} | ||
} | ||
else | ||
{ | ||
matches[token] = received; | ||
} | ||
|
||
offset++; | ||
} | ||
} | ||
|
||
if (offset != request.Length) throw new Exception("Request contained more data than request pattern."); | ||
|
||
using var responseReader = new StringReader(pair.ResponsePattern); | ||
while ((line = responseReader.ReadLine()) != null) | ||
{ | ||
var tokens = line.Split(Space, StringSplitOptions.RemoveEmptyEntries); | ||
foreach (var token in tokens) | ||
{ | ||
if (token.StartsWith(Comment)) break; | ||
|
||
if (token.Length == 2 && byte.TryParse(token, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var value)) | ||
{ | ||
res.Add(value); | ||
} | ||
else | ||
{ | ||
if (!matches.TryGetValue(token, out var match)) | ||
{ | ||
throw new Exception($"Unmatched token '{token}' in response."); | ||
} | ||
|
||
res.Add(match); | ||
} | ||
} | ||
} | ||
|
||
return res.ToArray(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters