private void HandleReceiveSequenceNumber(APdu aPdu) { if (acknowledgedSendSequenceNumber != aPdu.GetReceiveSeqNumber()) { if (GetSequenceNumberDifference(aPdu.GetReceiveSeqNumber(), acknowledgedSendSequenceNumber) > GetNumUnconfirmedIPdusSent()) { throw new IOException("Got unexpected receive sequence number: " + aPdu.GetReceiveSeqNumber() + ", expected a number between: " + acknowledgedSendSequenceNumber + " and " + sendSequenceNumber); } if (maxTimeNoAckReceivedFuture != null) { maxTimeNoAckReceivedFuture.Cancel(); maxTimeNoAckReceivedFuture = null; } acknowledgedSendSequenceNumber = aPdu.GetReceiveSeqNumber(); if (sendSequenceNumber != acknowledgedSendSequenceNumber) { ScheduleMaxTimeNoAckReceivedFuture(); } } }
public void Send(ASdu aSdu) { acknowledgedReceiveSequenceNumber = receiveSequenceNumber; var requestAPdu = new APdu(sendSequenceNumber, receiveSequenceNumber, APdu.ApciType.I_FORMAT, aSdu); sendSequenceNumber = (sendSequenceNumber + 1) % 32768; if (maxTimeNoAckSentFuture != null) { maxTimeNoAckSentFuture.Cancel(); maxTimeNoAckSentFuture = null; } if (maxTimeNoAckReceivedFuture == null) { ScheduleMaxTimeNoAckReceivedFuture(); } var length = requestAPdu.Encode(buffer, settings); writer.Write(buffer, 0, length); writer.Flush(); ResetMaxIdleTimeTimer(); }
private void SendSFormatPdu() { var requestAPdu = new APdu(0, receiveSequenceNumber, APdu.ApciType.S_FORMAT, null); requestAPdu.Encode(buffer, settings); writer.Write(buffer, 0, 6); writer.Flush(); acknowledgedReceiveSequenceNumber = receiveSequenceNumber; ResetMaxIdleTimeTimer(); }
public override void Run() { try { var reader = innerConnection.reader; while (true) { if (reader.ReadByte() != 0x68) { throw new IOException("Message does not start with 0x68"); } var aPdu = new APdu(reader, innerConnection.settings); switch (aPdu.GetApciType()) { 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.HandleReceiveSequenceNumber(aPdu); innerConnection.NewASdu?.Invoke(aPdu.GetASdu()); var numUnconfirmedIPdusReceived = innerConnection.GetSequenceNumberDifference( innerConnection.receiveSequenceNumber, innerConnection.acknowledgedReceiveSequenceNumber); if (numUnconfirmedIPdusReceived > innerConnection.settings.MaxUnconfirmedIPdusReceived) { innerConnection.SendSFormatPdu(); if (innerConnection.maxTimeNoAckSentFuture != null) { innerConnection.maxTimeNoAckSentFuture.Cancel(); innerConnection.maxTimeNoAckSentFuture = null; } } else { if (innerConnection.maxTimeNoAckSentFuture == null) { innerConnection.maxTimeNoAckSentFuture = PeriodicTaskFactory.Start(() => { innerConnection.SendSFormatPdu(); innerConnection.maxTimeNoAckSentFuture = null; }, innerConnection.settings.MaxTimeNoAckSent); } } innerConnection.ResetMaxIdleTimeTimer(); break; case APdu.ApciType.STARTDT_CON: innerConnection.startdtConSignal?.CountDown(); innerConnection.ResetMaxIdleTimeTimer(); break; case APdu.ApciType.STARTDT_ACT: innerConnection.startdtactSignal?.CountDown(); break; case APdu.ApciType.S_FORMAT: innerConnection.HandleReceiveSequenceNumber(aPdu); innerConnection.ResetMaxIdleTimeTimer(); break; case APdu.ApciType.TESTFR_ACT: 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: if (innerConnection.maxTimeNoTestConReceivedFuture != null) { innerConnection.maxTimeNoTestConReceivedFuture.Cancel(); innerConnection.maxTimeNoTestConReceivedFuture = null; } innerConnection.ResetMaxIdleTimeTimer(); break; default: throw new IOException("Got unexpected message with APCI Type: " + aPdu.GetApciType()); } } } catch (IOException e) { innerConnection.closedIoException = e; } catch (Exception e) { innerConnection.closedIoException = new IOException(e.Message); } finally { innerConnection.ConnectionClosed?.Invoke(innerConnection.closedIoException); innerConnection.Close(); } }