Skip to content

Commit

Permalink
[fix]TPKT的长度字段,包含自己的4字节;COTP写入前需要计算好长度,主要是提前计算好参数大小
Browse files Browse the repository at this point in the history
  • Loading branch information
nnhy committed Jan 4, 2024
1 parent 8d259e3 commit 938d978
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 33 deletions.
53 changes: 36 additions & 17 deletions NewLife.Siemens/Protocols/COTP.cs
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,8 @@ public Boolean Write(Stream stream, Object context)
{
case PduType.Data:
{
var len = 2;
var len = 1 + 1;
if (Data != null) len += Data.Total;
stream.WriteByte((Byte)len);
stream.WriteByte((Byte)Type);

Expand All @@ -151,15 +152,23 @@ public Boolean Write(Stream stream, Object context)
case PduType.ConnectionConfirmed:
default:
{
var len = 2;
var ps = Parameters;
var len = 1 + 2 + 2 + 1;
if (ps != null)
{
FixParameters(ps);
foreach (var item in ps)
{
len += 1 + 1 + item.Length;
}
}
writer.WriteByte((Byte)len);
writer.WriteByte((Byte)Type);

writer.Write(Destination);
writer.Write(Source);
writer.WriteByte(Option);

var ps = Parameters;
if (ps != null) WriteParameters(writer, ps);
}
break;
Expand All @@ -168,32 +177,42 @@ public Boolean Write(Stream stream, Object context)
return true;
}

void FixParameters(IList<COTPParameter> parameters)
{
foreach (var item in parameters)
{
item.Length = item.Kind switch
{
COTPParameterKinds.TpduSize => 1,
COTPParameterKinds.SrcTsap => 2,
COTPParameterKinds.DstTsap => 2,
_ => item.Value switch
{
Byte => 1,
UInt16 or Int16 => 2,
UInt32 or Int32 => 4,
Byte[] buf => (Byte)buf.Length,
_ => throw new NotSupportedException(),
},
};
}
}

void WriteParameters(Binary writer, IList<COTPParameter> parameters)
{
foreach (var item in parameters)
{
writer.WriteByte((Byte)item.Kind);
writer.WriteByte(item.Length);

if (item.Value is Byte b)
{
writer.WriteByte(1);
writer.WriteByte(b);
}
else if (item.Value is UInt16 u16)
{
writer.WriteByte(2);
writer.Write(u16);
}
else if (item.Value is UInt32 u32)
{
writer.WriteByte(4);
writer.Write(u32);
}
else if (item.Value is Byte[] buf)
{
writer.WriteByte((Byte)buf.Length);
writer.Write(buf);
}
else
throw new NotSupportedException();
}
Expand All @@ -210,7 +229,7 @@ public Boolean WriteWithTPKT(Stream stream)
var ms = new MemoryStream();
if (!Write(ms, null)) return false;

tpkt.Length = (UInt16)ms.Length;
tpkt.Length = (UInt16)(4 + ms.Length);
tpkt.Write(stream);

ms.Position = 0;
Expand All @@ -232,7 +251,7 @@ public Packet GetBytes(Boolean withTPKT = true)
if (!withTPKT) return pk;

var tpkt = new TPKT { Version = 3, };
tpkt.Length = (UInt16)ms.Length;
tpkt.Length = (UInt16)(4 + ms.Length);

var rs = new Packet(tpkt.ToArray());
rs.Append(pk);
Expand Down
4 changes: 3 additions & 1 deletion NewLife.Siemens/Protocols/S7PLC.cs
Original file line number Diff line number Diff line change
Expand Up @@ -254,9 +254,11 @@ private async Task<COTP> RequestAsync(Stream stream, COTP request, CancellationT
try
{
var pk = request.GetBytes(true);
var buf = pk.ReadBytes();

using var closeOnCancellation = cancellationToken.Register(Close);
await pk.CopyToAsync(stream, cancellationToken);
//await pk.CopyToAsync(stream, cancellationToken);
await stream.WriteAsync(buf, 0, buf.Length, cancellationToken);
return await COTP.ReadAsync(stream, cancellationToken).ConfigureAwait(false);
}
catch (Exception exc)
Expand Down
2 changes: 1 addition & 1 deletion NewLife.Siemens/Protocols/S7Server.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ protected override void OnReceive(ReceivedEventArgs e)
tpkt.Read(ms);

// 足够一帧
if (tpkt.Length > 0 && ms.Position + tpkt.Length <= ms.Length)
if (tpkt.Length > 0 && ms.Position + tpkt.Length - 4 <= ms.Length)
{
var cotp = new COTP();
if (cotp.Read(ms, null))
Expand Down
26 changes: 12 additions & 14 deletions NewLife.Siemens/Protocols/TPKT.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public class TPKT
/// <summary>保留</summary>
public Byte Reserved { get; set; }

/// <summary>长度</summary>
/// <summary>长度。包括当前TPKT头和后续数据</summary>
public UInt16 Length { get; set; }

/// <summary>数据</summary>
Expand All @@ -44,7 +44,7 @@ public void Read(Packet pk)
Reserved = buf[1];
Length = buf.ToUInt16(2, false);

Data = pk.Slice(4, Length);
if (pk.Total > 4) Data = pk.Slice(4, Length);
}

/// <summary>解析数据</summary>
Expand All @@ -66,13 +66,16 @@ public void Write(Stream stream)

if (Data != null)
{
Length = (UInt16)Data.Total;
Length = (UInt16)(4 + Data.Total);
stream.Write(Length.GetBytes(false));

Data?.CopyTo(stream);
}
else
{
if (Length == 0) Length = 4;
stream.Write(Length.GetBytes(false));
}
}

/// <summary>获取字节数组</summary>
Expand All @@ -97,22 +100,17 @@ public static async Task<TPKT> ReadAsync(Stream stream, CancellationToken cancel
var len = await stream.ReadExactAsync(buf, 0, 4, cancellationToken).ConfigureAwait(false);
if (len < 4) throw new TPKTInvalidException("TPKT is incomplete / invalid");

var version = buf[0];
var reserved1 = buf[1];
var length = buf[2] * 256 + buf[3]; // 大端字节序
var tpkt = new TPKT();
tpkt.Read(buf);

// 根据长度读取数据
var data = new Byte[length];
var data = new Byte[tpkt.Length - 4];
len = await stream.ReadExactAsync(data, 0, data.Length, cancellationToken).ConfigureAwait(false);
if (len < data.Length)
throw new TPKTInvalidException("TPKT payload incomplete / invalid");

return new TPKT
(
version: version,
reserved1: reserved1,
length: length,
data: data
);
tpkt.Data = data;

return tpkt;
}
}

0 comments on commit 938d978

Please sign in to comment.