From 3961141f38e31a2dcc649112cf92f9048764b54b Mon Sep 17 00:00:00 2001 From: minhdtb Date: Sat, 6 Feb 2016 21:42:18 +0700 Subject: [PATCH] fix bugs --- IEC60870/Connection/Connection.cs | 96 +++++++++++++++++++++---------- IEC60870/Object/APdu.cs | 6 +- TestApp/Program.cs | 7 ++- 3 files changed, 75 insertions(+), 34 deletions(-) diff --git a/IEC60870/Connection/Connection.cs b/IEC60870/Connection/Connection.cs index 6d864af..262a2c4 100644 --- a/IEC60870/Connection/Connection.cs +++ b/IEC60870/Connection/Connection.cs @@ -11,20 +11,17 @@ namespace IEC60870.Connections { public class Connection { - private static readonly byte[] TestfrConBuffer = {0x68, 0x04, 0x83, 0x00, 0x00, 0x00}; - private static readonly byte[] TestfrActBuffer = {0x68, 0x04, 0x43, 0x00, 0x00, 0x00}; - private static readonly byte[] StartdtActBuffer = {0x68, 0x04, 0x07, 0x00, 0x00, 0x00}; - private static readonly byte[] StartdtConBuffer = {0x68, 0x04, 0x0b, 0x00, 0x00, 0x00}; + private static readonly byte[] TestfrActBuffer = { 0x68, 0x04, 0x43, 0x00, 0x00, 0x00 }; + private static readonly byte[] TestfrConBuffer = { 0x68, 0x04, 0x83, 0x00, 0x00, 0x00 }; + private static readonly byte[] StartdtActBuffer = { 0x68, 0x04, 0x07, 0x00, 0x00, 0x00 }; + private static readonly byte[] StartdtConBuffer = { 0x68, 0x04, 0x0b, 0x00, 0x00, 0x00 }; private readonly byte[] buffer = new byte[255]; private readonly BinaryReader reader; private readonly ConnectionSettings settings; - private readonly CountDownLatch startdtactSignal; private readonly BinaryWriter writer; - private int acknowledgedReceiveSequenceNumber; - private int acknowledgedSendSequenceNumber; private bool closed; private IOException closedIoException; @@ -40,10 +37,15 @@ public class Connection public ConnectionEventListener.NewASdu NewASdu = null; - private int originatorAddress; - private int receiveSequenceNumber; + private int originatorAddress = 0; + + private int receiveSequenceNumber = 0; + private int sendSequenceNumber = 0; - private int sendSequenceNumber; + private int acknowledgedReceiveSequenceNumber = 0; + private int acknowledgedSendSequenceNumber = 0; + + private readonly CountDownLatch startdtactSignal; private CountDownLatch startdtConSignal; public Connection(Socket socket, ConnectionSettings settings) @@ -51,6 +53,7 @@ public Connection(Socket socket, ConnectionSettings settings) this.settings = settings; var ns = new NetworkStream(socket); + writer = new BinaryWriter(ns); reader = new BinaryReader(ns); @@ -95,8 +98,15 @@ public void StartDataTransfer(int timeout = 0) startdtConSignal = new CountDownLatch(1); - writer.Write(StartdtActBuffer, 0, StartdtActBuffer.Length); - writer.Flush(); + try + { + writer.Write(StartdtActBuffer, 0, StartdtActBuffer.Length); + writer.Flush(); + } + catch (Exception e) + { + throw new IOException(e.Message); + } if (timeout == 0) { @@ -124,8 +134,15 @@ public void WaitForStartDT(int timeout = 0) startdtactSignal.Wait(timeout); } - writer.Write(StartdtConBuffer, 0, StartdtConBuffer.Length); - writer.Flush(); + try + { + writer.Write(StartdtConBuffer, 0, StartdtConBuffer.Length); + writer.Flush(); + } + catch (Exception e) + { + throw new IOException(e.Message); + } ResetMaxIdleTimeTimer(); } @@ -133,8 +150,8 @@ public void WaitForStartDT(int timeout = 0) public void Send(ASdu aSdu) { acknowledgedReceiveSequenceNumber = receiveSequenceNumber; - var requestAPdu = new APdu(sendSequenceNumber, receiveSequenceNumber, APdu.ApciType.FORMAT, aSdu); - sendSequenceNumber = (sendSequenceNumber + 1)%32768; + var requestAPdu = new APdu(sendSequenceNumber, receiveSequenceNumber, APdu.ApciType.I_FORMAT, aSdu); + sendSequenceNumber = (sendSequenceNumber + 1) % 32768; if (maxTimeNoAckSentFuture != null) { @@ -167,6 +184,7 @@ private void SendSFormatPdu() ResetMaxIdleTimeTimer(); } + #region COMMANDS public void SendConfirmation(ASdu aSdu) { var cot = aSdu.GetCauseOfTransmission(); @@ -380,7 +398,7 @@ public void BitStringCommandWithTimeTag(int commonAddress, CauseOfTransmission c public void Interrogation(int commonAddress, CauseOfTransmission cot, IeQualifierOfInterrogation qualifier) { var aSdu = new ASdu(TypeId.C_IC_NA_1, false, cot, false, false, originatorAddress, commonAddress, - new[] {new InformationObject(0, new[] {new InformationElement[] {qualifier}})}); + new[] { new InformationObject(0, new[] { new InformationElement[] { qualifier } }) }); Send(aSdu); } @@ -389,7 +407,7 @@ public void CounterInterrogation(int commonAddress, CauseOfTransmission cot, IeQualifierOfCounterInterrogation qualifier) { var aSdu = new ASdu(TypeId.C_CI_NA_1, false, cot, false, false, originatorAddress, commonAddress, - new[] {new InformationObject(0, new[] {new InformationElement[] {qualifier}})}); + new[] { new InformationObject(0, new[] { new InformationElement[] { qualifier } }) }); Send(aSdu); } @@ -408,9 +426,9 @@ public void ReadCommand(int commonAddress, int informationObjectAddress) public void SynchronizeClocks(int commonAddress, IeTime56 time) { - var io = new InformationObject(0, new[] {new InformationElement[] {time}}); + var io = new InformationObject(0, new[] { new InformationElement[] { time } }); - InformationObject[] ios = {io}; + InformationObject[] ios = { io }; var aSdu = new ASdu(TypeId.C_CS_NA_1, false, CauseOfTransmission.ACTIVATION, false, false, originatorAddress, commonAddress, ios); @@ -456,7 +474,7 @@ public void ResetProcessCommand(int commonAddress, IeQualifierOfResetProcessComm public void DelayAcquisitionCommand(int commonAddress, CauseOfTransmission cot, IeTime16 time) { var aSdu = new ASdu(TypeId.C_CD_NA_1, false, cot, false, false, originatorAddress, commonAddress, - new[] {new InformationObject(0, new[] {new InformationElement[] {time}})}); + new[] { new InformationObject(0, new[] { new InformationElement[] { time } }) }); Send(aSdu); } @@ -621,6 +639,9 @@ public void QueryLog(int commonAddress, int informationObjectAddress, IeNameOfFi Send(aSdu); } + #endregion + #region HELPER + public void SetOriginatorAddress(int address) { if (address < 0 || address > 255) @@ -655,6 +676,8 @@ public int GetOriginatorAddress() return originatorAddress; } + #endregion + private void HandleReceiveSequenceNumber(APdu aPdu) { if (acknowledgedSendSequenceNumber != aPdu.GetReceiveSeqNumber()) @@ -697,10 +720,11 @@ private void ResetMaxIdleTimeTimer() writer.Write(TestfrActBuffer, 0, TestfrActBuffer.Length); writer.Flush(); } - catch (Exception) + catch (Exception e) { - // ignored + throw new IOException(e.Message); } + ScheduleMaxTimeNoTestConReceivedFuture(); }, settings.MaxIdleTime); } @@ -756,6 +780,7 @@ public override void Run() var reader = innerConnection.reader; while (true) { + if (reader.ReadByte() != 0x68) { throw new IOException("Message does not start with 0x68"); @@ -764,7 +789,7 @@ public override void Run() var aPdu = new APdu(reader, innerConnection.settings); switch (aPdu.GetApciType()) { - case APdu.ApciType.FORMAT: + case APdu.ApciType.I_FORMAT: if (innerConnection.receiveSequenceNumber != aPdu.GetSendSeqNumber()) { throw new IOException("Got unexpected send sequence number: " + @@ -772,7 +797,7 @@ public override void Run() + ", expected: " + innerConnection.receiveSequenceNumber); } - innerConnection.receiveSequenceNumber = (aPdu.GetSendSeqNumber() + 1)%32768; + innerConnection.receiveSequenceNumber = (aPdu.GetSendSeqNumber() + 1) % 32768; innerConnection.HandleReceiveSequenceNumber(aPdu); innerConnection.NewASdu?.Invoke(aPdu.GetASdu()); @@ -794,8 +819,11 @@ public override void Run() if (innerConnection.maxTimeNoAckSentFuture == null) { innerConnection.maxTimeNoAckSentFuture = - PeriodicTaskFactory.Start(() => { innerConnection.SendSFormatPdu(); }, - innerConnection.settings.MaxTimeNoAckSent); + PeriodicTaskFactory.Start(() => + { + innerConnection.SendSFormatPdu(); + innerConnection.maxTimeNoAckSentFuture = null; + }, innerConnection.settings.MaxTimeNoAckSent); } } @@ -813,8 +841,16 @@ public override void Run() innerConnection.ResetMaxIdleTimeTimer(); break; case APdu.ApciType.TESTFR_ACT: - innerConnection.writer.Write(TestfrConBuffer, 0, TestfrConBuffer.Length); - innerConnection.writer.Flush(); + try + { + innerConnection.writer.Write(TestfrConBuffer, 0, TestfrConBuffer.Length); + innerConnection.writer.Flush(); + } + catch (Exception e) + { + throw new IOException(e.Message); + } + innerConnection.ResetMaxIdleTimeTimer(); break; case APdu.ApciType.TESTFR_CON: @@ -827,6 +863,7 @@ public override void Run() break; default: throw new IOException("Got unexpected message with APCI Type: " + aPdu.GetApciType()); + } } } @@ -841,7 +878,6 @@ public override void Run() finally { innerConnection.ConnectionClosed?.Invoke(innerConnection.closedIoException); - innerConnection.Close(); } } diff --git a/IEC60870/Object/APdu.cs b/IEC60870/Object/APdu.cs index 9644a01..2fea7ce 100644 --- a/IEC60870/Object/APdu.cs +++ b/IEC60870/Object/APdu.cs @@ -7,7 +7,7 @@ public class APdu { public enum ApciType { - FORMAT, + I_FORMAT, S_FORMAT, TESTFR_CON, TESTFR_ACT, @@ -46,7 +46,7 @@ public APdu(BinaryReader reader, ConnectionSettings settings) if ((aPduHeader[0] & 0x01) == 0) { - apciType = ApciType.FORMAT; + apciType = ApciType.I_FORMAT; sendSeqNum = ((aPduHeader[0] & 0xfe) >> 1) + ((aPduHeader[1] & 0xff) << 7); receiveSeqNum = ((aPduHeader[2] & 0xfe) >> 1) + ((aPduHeader[3] & 0xff) << 7); @@ -92,7 +92,7 @@ public int Encode(byte[] buffer, ConnectionSettings settings) var length = 4; - if (apciType == ApciType.FORMAT) + if (apciType == ApciType.I_FORMAT) { buffer[2] = (byte) (sendSeqNum << 1); buffer[3] = (byte) (sendSeqNum >> 7); diff --git a/TestApp/Program.cs b/TestApp/Program.cs index 957b3b6..a5a9e7d 100644 --- a/TestApp/Program.cs +++ b/TestApp/Program.cs @@ -13,8 +13,13 @@ private static void Main(string[] args) var server = new ServerSAP("127.0.0.1", 2405); client.NewASdu += asdu => { - server.SendASdu(asdu); Console.WriteLine(asdu); + server.SendASdu(asdu); + }; + + client.ConnectionClosed += e => + { + Console.WriteLine(e); }; client.Connect();