forked from S7NetPlus/s7netplus
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Read TPKT/COTP packets / Read MaxPDU size from PLC
Read responses from the PLS using classes for TPKT and COPT. This makes the communication more robust. It will now handle empty COTP packets that SoftPLS and WinAC based PLCs send out. I use RFC names for functions and classes. Change logic to use COTP and S7Comm reponse codes instead of relying on packet sizes. Read Max PDU size from connection setup. Ref S7NetPlus#21 I did some test on using this limit. But i met a wall when testing against snap7 so i decided to drop changes to read/write size. I have done some tests against WinAC cpu and it seems to handle bigger pdu's if negotiated in the connection setup. This might just be a SNAP7 bug.
- Loading branch information
Showing
4 changed files
with
189 additions
and
21 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,99 @@ | ||
using System; | ||
using System.IO; | ||
using System.Net.Sockets; | ||
|
||
namespace S7.Net | ||
{ | ||
|
||
/// <summary> | ||
/// COTP Protocol functions and types | ||
/// </summary> | ||
internal class COTP | ||
{ | ||
/// <summary> | ||
/// Describes a COTP TPDU (Transport protocol data unit) | ||
/// </summary> | ||
public class TPDU | ||
{ | ||
public byte HeaderLength; | ||
public byte PDUType; | ||
public int TPDUNumber; | ||
public byte[] Data; | ||
public bool LastDataUnit; | ||
|
||
public TPDU(TPKT tPKT) | ||
{ | ||
var br = new BinaryReader(new MemoryStream(tPKT.Data)); | ||
HeaderLength = br.ReadByte(); | ||
if (HeaderLength >= 2) | ||
{ | ||
PDUType = br.ReadByte(); | ||
if (PDUType == 0xf0) //DT Data | ||
{ | ||
var flags = br.ReadByte(); | ||
TPDUNumber = flags & 0x7F; | ||
LastDataUnit = (flags & 0x80) > 0; | ||
Data = br.ReadBytes(tPKT.Length - HeaderLength - 4); //4 = TPKT Size | ||
return; | ||
} | ||
//TODO: Handle other PDUTypes | ||
} | ||
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="socket">The socket to read from</param> | ||
/// <returns>COTP DPDU instance</returns> | ||
public static TPDU Read(Socket socket) | ||
{ | ||
var tpkt = TPKT.Read(socket); | ||
Console.WriteLine(tpkt); | ||
if (tpkt.Length > 0) return new TPDU(tpkt); | ||
return null; | ||
} | ||
|
||
public override string ToString() | ||
{ | ||
return string.Format("Length: {0} PDUType: {1} TPDUNumber: {2} Last: {3} Segment Data: {4}", | ||
HeaderLength, | ||
PDUType, | ||
TPDUNumber, | ||
LastDataUnit, | ||
BitConverter.ToString(Data) | ||
); | ||
} | ||
|
||
} | ||
|
||
/// <summary> | ||
/// Describes a COTP TSDU (Transport service data unit). One TSDU consist of 1 ore more TPDUs | ||
/// </summary> | ||
public class TSDU | ||
{ | ||
/// <summary> | ||
/// Reads the full COTP TSDU (Transport service data unit) | ||
/// See: https://tools.ietf.org/html/rfc905 | ||
/// </summary> | ||
/// <returns>Data in TSDU</returns> | ||
public static byte[] Read(Socket socket) | ||
{ | ||
var segment = TPDU.Read(socket); | ||
|
||
if (segment == null) return null; | ||
|
||
var output = new MemoryStream(segment.Data.Length); | ||
output.Write(segment.Data, 0, segment.Data.Length); | ||
|
||
while (!segment.LastDataUnit) | ||
{ | ||
segment = TPDU.Read(socket); | ||
output.Write(segment.Data, (int)output.Position, segment.Data.Length); | ||
} | ||
return output.GetBuffer(); | ||
} | ||
} | ||
} | ||
} |
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
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
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,49 @@ | ||
using System; | ||
using System.Net.Sockets; | ||
|
||
namespace S7.Net | ||
{ | ||
|
||
/// <summary> | ||
/// Describes a TPKT Packet | ||
/// </summary> | ||
internal class TPKT | ||
{ | ||
public byte Version; | ||
public byte Reserved1; | ||
public int Length; | ||
public byte[] Data; | ||
|
||
/// <summary> | ||
/// Reds a TPKT from the socket | ||
/// </summary> | ||
/// <param name="socket">The socket to read from</param> | ||
/// <returns>TPKT Instace</returns> | ||
public static TPKT Read(Socket socket) | ||
{ | ||
var buf = new byte[4]; | ||
socket.Receive(buf, 4, SocketFlags.None); | ||
var pkt = new TPKT | ||
{ | ||
Version = buf[0], | ||
Reserved1 = buf[1], | ||
Length = buf[2] * 256 + buf[3] //BigEndian | ||
}; | ||
if (pkt.Length > 0) | ||
{ | ||
pkt.Data = new byte[pkt.Length - 4]; | ||
socket.Receive(pkt.Data, pkt.Length - 4, SocketFlags.None); | ||
} | ||
return pkt; | ||
} | ||
|
||
public override string ToString() | ||
{ | ||
return string.Format("Version: {0} Length: {1} Data: {2}", | ||
Version, | ||
Length, | ||
BitConverter.ToString(Data) | ||
); | ||
} | ||
} | ||
} |