Skip to content
This repository has been archived by the owner on Sep 28, 2019. It is now read-only.

Commit

Permalink
fix bugs
Browse files Browse the repository at this point in the history
  • Loading branch information
minhdtb committed Feb 6, 2016
1 parent 15cf085 commit 3961141
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 34 deletions.
96 changes: 66 additions & 30 deletions IEC60870/Connection/Connection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -40,17 +37,23 @@ 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)
{
this.settings = settings;

var ns = new NetworkStream(socket);

writer = new BinaryWriter(ns);
reader = new BinaryReader(ns);

Expand Down Expand Up @@ -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)
{
Expand Down Expand Up @@ -124,17 +134,24 @@ 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();
}

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)
{
Expand Down Expand Up @@ -167,6 +184,7 @@ private void SendSFormatPdu()
ResetMaxIdleTimeTimer();
}

#region COMMANDS
public void SendConfirmation(ASdu aSdu)
{
var cot = aSdu.GetCauseOfTransmission();
Expand Down Expand Up @@ -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);
}
Expand All @@ -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);
}
Expand All @@ -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);
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -655,6 +676,8 @@ public int GetOriginatorAddress()
return originatorAddress;
}

#endregion

private void HandleReceiveSequenceNumber(APdu aPdu)
{
if (acknowledgedSendSequenceNumber != aPdu.GetReceiveSeqNumber())
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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");
Expand All @@ -764,15 +789,15 @@ 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: " +
aPdu.GetSendSeqNumber()
+ ", expected: " + innerConnection.receiveSequenceNumber);
}

innerConnection.receiveSequenceNumber = (aPdu.GetSendSeqNumber() + 1)%32768;
innerConnection.receiveSequenceNumber = (aPdu.GetSendSeqNumber() + 1) % 32768;
innerConnection.HandleReceiveSequenceNumber(aPdu);

innerConnection.NewASdu?.Invoke(aPdu.GetASdu());
Expand All @@ -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);
}
}

Expand All @@ -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:
Expand All @@ -827,6 +863,7 @@ public override void Run()
break;
default:
throw new IOException("Got unexpected message with APCI Type: " + aPdu.GetApciType());

}
}
}
Expand All @@ -841,7 +878,6 @@ public override void Run()
finally
{
innerConnection.ConnectionClosed?.Invoke(innerConnection.closedIoException);

innerConnection.Close();
}
}
Expand Down
6 changes: 3 additions & 3 deletions IEC60870/Object/APdu.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ public class APdu
{
public enum ApciType
{
FORMAT,
I_FORMAT,
S_FORMAT,
TESTFR_CON,
TESTFR_ACT,
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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);
Expand Down
7 changes: 6 additions & 1 deletion TestApp/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down

0 comments on commit 3961141

Please sign in to comment.