예제 #1
0
        private void SendASDUInternal(ASDU asdu)
        {
            lock (socket) {
                if (running == false)
                {
                    throw new ConnectionException("not connected", new SocketException(10057));
                }

                if (useSendMessageQueue)
                {
                    lock (waitingToBeSent) {
                        waitingToBeSent.Enqueue(asdu);
                    }

                    SendNextWaitingASDU();
                }
                else
                {
                    if (IsSentBufferFull())
                    {
                        throw new ConnectionException("Flow control congestion. Try again later.");
                    }

                    SendIMessageAndUpdateSentASDUs(asdu);
                }
            }
        }
예제 #2
0
        /// <summary>
        /// Enqueues the ASDU to the transmission queue.
        /// </summary>
        /// If an active connection exists the ASDU will be sent to the active client immediately. Otherwhise
        /// the ASDU will be added to the transmission queue for later transmission.
        /// <param name="asdu">ASDU to be sent</param>
        public void EnqueueASDU(ASDU asdu)
        {
            if (serverMode == ServerMode.SINGLE_REDUNDANCY_GROUP)
            {
                asduQueue.EnqueueAsdu(asdu);

                foreach (ServerConnection connection in allOpenConnections)
                {
                    if (connection.IsActive)
                    {
                        connection.ASDUReadyToSend();
                    }
                }
            }
            else
            {
                foreach (ServerConnection connection in allOpenConnections)
                {
                    if (connection.IsActive)
                    {
                        connection.GetASDUQueue().EnqueueAsdu(asdu);
                        connection.ASDUReadyToSend();
                    }
                }
            }
        }
        public void SendACT_CON(ASDU asdu, bool negative)
        {
            asdu.Cot        = CauseOfTransmission.ACTIVATION_CON;
            asdu.IsNegative = negative;

            SendASDU(asdu);
        }
예제 #4
0
        /// <summary>
        /// Enqueues the ASDU to the transmission queue.
        /// 将ASDU加入队列,并同时发送到当前激活的连接中
        /// </summary>
        /// If an active connection exists the ASDU will be sent to the active client immediately. Otherwhise
        /// the ASDU will be added to the transmission queue for later transmission.
        /// <param name="asdu">ASDU to be sent</param>
        public void EnqueueASDU(ASDU asdu)
        {
            if (enqueuedASDUs == null)
            {
                enqueuedASDUs = new Queue <ASDU>();
            }

            if (enqueuedASDUs.Count == maxQueueSize)
            {
                enqueuedASDUs.Dequeue();
            }

            enqueuedASDUs.Enqueue(asdu);

            Console.WriteLine("Queue contains " + enqueuedASDUs.Count + " messages");

            foreach (ServerConnection connection in allOpenConnections)
            {
                //通知当前激活的连接,赶紧读取ASDU
                if (connection.IsActive)
                {
                    connection.ASDUReadyToSend();
                }
            }
        }
        public void SendACT_TERM(ASDU asdu)
        {
            asdu.Cot        = CauseOfTransmission.ACTIVATION_TERMINATION;
            asdu.IsNegative = false;

            SendASDU(asdu);
        }
예제 #6
0
        /// <summary>
        /// Sends a clock synchronization command (C_CS_NA_1 typeID: 103).
        /// </summary>
        /// <param name="ca">Common address</param>
        /// <param name="time">the new time to set</param>
        /// <exception cref="ConnectionException">description</exception>
        public void SendClockSyncCommand(int ca, CP56Time2a time)
        {
            ASDU asdu = new ASDU(parameters, CauseOfTransmission.ACTIVATION, false, false, (byte)parameters.OriginatorAddress, ca, false);

            asdu.AddInformationObject(new ClockSynchronizationCommand(0, time));

            SendASDUInternal(asdu);
        }
예제 #7
0
        /// <summary>
        /// Sends a read command (C_RD_NA_1 typeID: 102).
        /// </summary>
        ///
        /// This will send a read command C_RC_NA_1 (102) to the slave/outstation. The COT is always REQUEST (5).
        /// It is used to implement the cyclical polling of data application function.
        ///
        /// <param name="ca">Common address</param>
        /// <param name="ioa">Information object address</param>
        /// <exception cref="ConnectionException">description</exception>
        public void SendReadCommand(int ca, int ioa)
        {
            ASDU asdu = new ASDU(parameters, CauseOfTransmission.REQUEST, false, false, (byte)parameters.OriginatorAddress, ca, false);

            asdu.AddInformationObject(new ReadCommand(ioa));

            SendASDUInternal(asdu);
        }
예제 #8
0
        /// <summary>
        /// Sends the counter interrogation command (C_CI_NA_1 typeID: 101)
        /// </summary>
        /// <param name="cot">Cause of transmission</param>
        /// <param name="ca">Common address</param>
        /// <param name="qcc">Qualifier of counter interrogation command</param>
        /// <exception cref="ConnectionException">description</exception>
        public void SendCounterInterrogationCommand(CauseOfTransmission cot, int ca, byte qcc)
        {
            ASDU asdu = new ASDU(parameters, cot, false, false, (byte)parameters.OriginatorAddress, ca, false);

            asdu.AddInformationObject(new CounterInterrogationCommand(0, qcc));

            SendASDUInternal(asdu);
        }
예제 #9
0
        /// <summary>
        /// Sends a test command (C_TS_NA_1 typeID: 104).
        /// </summary>
        ///
        /// Not required and supported by IEC 60870-5-104.
        ///
        /// <param name="ca">Common address</param>
        /// <exception cref="ConnectionException">description</exception>
        public void SendTestCommand(int ca)
        {
            ASDU asdu = new ASDU(parameters, CauseOfTransmission.ACTIVATION, false, false, (byte)parameters.OriginatorAddress, ca, false);

            asdu.AddInformationObject(new TestCommand());

            SendASDUInternal(asdu);
        }
예제 #10
0
        /// <summary>
        /// Sends a reset process command (C_RP_NA_1 typeID: 105).
        /// </summary>
        /// <param name="cot">Cause of transmission</param>
        /// <param name="ca">Common address</param>
        /// <param name="qrp">Qualifier of reset process command</param>
        /// <exception cref="ConnectionException">description</exception>
        public void SendResetProcessCommand(CauseOfTransmission cot, int ca, byte qrp)
        {
            ASDU asdu = new ASDU(parameters, CauseOfTransmission.ACTIVATION, false, false, (byte)parameters.OriginatorAddress, ca, false);

            asdu.AddInformationObject(new ResetProcessCommand(0, qrp));

            SendASDUInternal(asdu);
        }
예제 #11
0
        /// <summary>
        /// Sends a test command with CP56Time2a time (C_TS_TA_1 typeID: 107).
        /// </summary>
        /// <param name="ca">Common address</param>
        /// <param name="tsc">test sequence number</param>
        /// <param name="time">test timestamp</param>
        /// <exception cref="ConnectionException">description</exception>
        public void SendTestCommandWithCP56Time2a(int ca, ushort tsc, CP56Time2a time)
        {
            ASDU asdu = new ASDU(parameters, CauseOfTransmission.ACTIVATION, false, false, (byte)parameters.OriginatorAddress, ca, false);

            asdu.AddInformationObject(new TestCommandWithCP56Time2a(tsc, time));

            SendASDUInternal(asdu);
        }
예제 #12
0
        /// <summary>
        /// Sends the control command.
        /// </summary>
        ///
        /// The type ID has to match the type of the InformationObject!
        ///
        /// C_SC_NA_1 -> SingleCommand
        /// C_DC_NA_1 -> DoubleCommand
        /// C_RC_NA_1 -> StepCommand
        /// C_SC_TA_1 -> SingleCommandWithCP56Time2a
        /// C_SE_NA_1 -> SetpointCommandNormalized
        /// C_SE_NB_1 -> SetpointCommandScaled
        /// C_SE_NC_1 -> SetpointCommandShort
        /// C_BO_NA_1 -> Bitstring32Command
        ///
        /// <param name="cot">Cause of transmission (use ACTIVATION to start a control sequence)</param>
        /// <param name="ca">Common address</param>
        /// <param name="sc">Information object of the command</param>
        /// <exception cref="ConnectionException">description</exception>
        public void SendControlCommand(CauseOfTransmission cot, int ca, InformationObject sc)
        {
            ASDU controlCommand = new ASDU(parameters, cot, false, false, (byte)parameters.OriginatorAddress, ca, false);

            controlCommand.AddInformationObject(sc);

            SendASDUInternal(controlCommand);
        }
예제 #13
0
        /// <summary>
        /// Sends a delay acquisition command (C_CD_NA_1 typeID: 106).
        /// </summary>
        /// <param name="cot">Cause of transmission</param>
        /// <param name="ca">Common address</param>
        /// <param name="delay">delay for acquisition</param>
        /// <exception cref="ConnectionException">description</exception>
        public void SendDelayAcquisitionCommand(CauseOfTransmission cot, int ca, CP16Time2a delay)
        {
            ASDU asdu = new ASDU(parameters, CauseOfTransmission.ACTIVATION, false, false, (byte)parameters.OriginatorAddress, ca, false);

            asdu.AddInformationObject(new DelayAcquisitionCommand(0, delay));

            SendASDUInternal(asdu);
        }
예제 #14
0
        /// <summary>
        /// 发送激活确认报文(镜像报文)
        /// </summary>
        /// <param name="asdu">原报文</param>
        /// <param name="negative"></param>
        public void SendACT_CON(ASDU asdu, bool negative)
        {
            //传送原因改下
            asdu.Cot = CauseOfTransmission.ACTIVATION_CON;
            //肯定/否定激活改进去
            asdu.IsNegative = negative;

            SendASDU(asdu);
        }
예제 #15
0
        /// <summary>
        /// 发送ASDU
        /// </summary>
        /// <param name="asdu"></param>
        public void SendASDU(ASDU asdu)
        {
            Frame frame = new T104Frame();

            asdu.Encode(frame, parameters);

            //发送I帧
            sendIMessage(frame);
        }
예제 #16
0
        /// <summary>
        /// 检查服务端的ASDU并发送??
        /// </summary>
        private void checkServerQueue()
        {
            ASDU asdu = server.DequeueASDU();

            if (asdu != null)
            {
                SendASDU(asdu);
            }
        }
 /// <summary>
 /// Send a response ASDU over this connection
 /// </summary>
 /// <exception cref="ConnectionException">Throws an exception if the connection is no longer active (e.g. because it has been closed by the other side).</exception>
 /// <param name="asdu">The ASDU to send</param>
 public void SendASDU(ASDU asdu)
 {
     if (isActive)
     {
         SendASDUInternal(asdu);
     }
     else
     {
         throw new ConnectionException("Connection not active");
     }
 }
예제 #18
0
        /// <summary>
        /// 准备发送ASDU,为啥这里要发送一次?难道是镜像报文?还需要再读读。。。
        /// </summary>
        public void ASDUReadyToSend()
        {
            if (isActive)
            {
                ASDU asdu = server.DequeueASDU();

                if (asdu != null)
                {
                    SendASDU(asdu);
                }
            }
        }
예제 #19
0
        /// <summary>
        /// Enqueues the ASDU to the transmission queue.
        /// </summary>
        /// If an active connection exists the ASDU will be sent to the active client immediately. Otherwhise
        /// the ASDU will be added to the transmission queue for later transmission.
        /// <param name="asdu">ASDU to be sent</param>
        public void EnqueueASDU(ASDU asdu)
        {
            if (enqueuedASDUs != null)
            {
                lock (enqueuedASDUs) {
                    if (oldestQueueEntry == -1)
                    {
                        oldestQueueEntry    = 0;
                        latestQueueEntry    = 0;
                        numberOfAsduInQueue = 1;

                        enqueuedASDUs [0].asdu.ResetFrame();
                        asdu.Encode(enqueuedASDUs [0].asdu, parameters);

                        enqueuedASDUs [0].entryTimestamp = SystemUtils.currentTimeMillis();
                        enqueuedASDUs [0].state          = QueueEntryState.WAITING_FOR_TRANSMISSION;
                    }
                    else
                    {
                        latestQueueEntry = (latestQueueEntry + 1) % maxQueueSize;

                        if (latestQueueEntry == oldestQueueEntry)
                        {
                            oldestQueueEntry = (oldestQueueEntry + 1) % maxQueueSize;
                        }
                        else
                        {
                            numberOfAsduInQueue++;
                        }

                        enqueuedASDUs [latestQueueEntry].asdu.ResetFrame();
                        asdu.Encode(enqueuedASDUs [latestQueueEntry].asdu, parameters);

                        enqueuedASDUs [latestQueueEntry].entryTimestamp = SystemUtils.currentTimeMillis();
                        enqueuedASDUs [latestQueueEntry].state          = QueueEntryState.WAITING_FOR_TRANSMISSION;
                    }
                }

                DebugLog("Queue contains " + numberOfAsduInQueue + " messages (oldest: " + oldestQueueEntry + " latest: " + latestQueueEntry + ")");

                foreach (ServerConnection connection in allOpenConnections)
                {
                    if (connection.IsActive)
                    {
                        connection.ASDUReadyToSend();
                    }
                }
            }
        }
        private void SendASDUInternal(ASDU asdu)
        {
            if (isActive)
            {
                lock (waitingASDUsHighPrio) {
                    BufferFrame frame = new BufferFrame(new byte[256], 6);

                    asdu.Encode(frame, parameters);

                    waitingASDUsHighPrio.Enqueue(frame);
                }

                SendWaitingASDUs();
            }
        }
예제 #21
0
        private int SendIMessage(ASDU asdu)
        {
            BufferFrame frame = new BufferFrame(new byte[260], 6);             /* reserve space for ACPI */

            asdu.Encode(frame, parameters);

            byte[] buffer = frame.GetBuffer();

            int msgSize = frame.GetMsgSize();              /* ACPI + ASDU */

            buffer [0] = 0x68;

            /* set size field */
            buffer [1] = (byte)(msgSize - 2);

            buffer [2] = (byte)((sendSequenceNumber % 128) * 2);
            buffer [3] = (byte)(sendSequenceNumber / 128);

            buffer [4] = (byte)((receiveSequenceNumber % 128) * 2);
            buffer [5] = (byte)(receiveSequenceNumber / 128);

            if (running)
            {
                socket.NoDelay = true;
                socket.Send(buffer, msgSize, SocketFlags.None);
                sendSequenceNumber = (sendSequenceNumber + 1) % 32768;
                statistics.SentMsgCounter++;
                unconfirmedReceivedIMessages = 0;

                if (sentMessageHandler != null)
                {
                    sentMessageHandler(sentMessageHandlerParameter, buffer, msgSize);
                }

                return(sendSequenceNumber);
            }
            else
            {
                if (lastException != null)
                {
                    throw new ConnectionException(lastException.Message, lastException);
                }
                else
                {
                    throw new ConnectionException("not connected", new SocketException(10057));
                }
            }
        }
예제 #22
0
        public void EnqueueAsdu(ASDU asdu)
        {
            lock (enqueuedASDUs)
            {
                if (oldestQueueEntry == -1)
                {
                    oldestQueueEntry    = 0;
                    latestQueueEntry    = 0;
                    numberOfAsduInQueue = 1;

                    enqueuedASDUs[0].asdu.ResetFrame();
                    asdu.Encode(enqueuedASDUs[0].asdu, parameters);

                    enqueuedASDUs[0].entryTimestamp = SystemUtils.currentTimeMillis();
                    enqueuedASDUs[0].state          = QueueEntryState.WAITING_FOR_TRANSMISSION;
                }
                else
                {
                    latestQueueEntry = (latestQueueEntry + 1) % maxQueueSize;

                    if (latestQueueEntry == oldestQueueEntry)
                    {
                        oldestQueueEntry = (oldestQueueEntry + 1) % maxQueueSize;
                    }
                    else
                    {
                        numberOfAsduInQueue++;
                    }

                    enqueuedASDUs[latestQueueEntry].asdu.ResetFrame();
                    asdu.Encode(enqueuedASDUs[latestQueueEntry].asdu, parameters);

                    enqueuedASDUs[latestQueueEntry].entryTimestamp = SystemUtils.currentTimeMillis();
                    enqueuedASDUs[latestQueueEntry].state          = QueueEntryState.WAITING_FOR_TRANSMISSION;
                }
            }

            DebugLog("Queue contains " + numberOfAsduInQueue + " messages (oldest: " + oldestQueueEntry + " latest: " + latestQueueEntry + ")");
        }
예제 #23
0
        private bool SendNextWaitingASDU()
        {
            bool sentAsdu = false;

            if (running == false)
            {
                throw new ConnectionException("connection lost");
            }

            try {
                lock (waitingToBeSent) {
                    while (waitingToBeSent.Count > 0)
                    {
                        if (IsSentBufferFull() == true)
                        {
                            break;
                        }

                        ASDU asdu = waitingToBeSent.Dequeue();

                        if (asdu != null)
                        {
                            SendIMessageAndUpdateSentASDUs(asdu);
                            sentAsdu = true;
                        }
                        else
                        {
                            break;
                        }
                    }
                }
            } catch (Exception) {
                running = false;
                throw new ConnectionException("connection lost");
            }

            return(sentAsdu);
        }
예제 #24
0
        private void SendIMessageAndUpdateSentASDUs(ASDU asdu)
        {
            lock (sentASDUs) {
                int currentIndex = 0;

                if (oldestSentASDU == -1)
                {
                    oldestSentASDU = 0;
                    newestSentASDU = 0;
                }
                else
                {
                    currentIndex = (newestSentASDU + 1) % maxSentASDUs;
                }

                sentASDUs [currentIndex].seqNo    = SendIMessage(asdu);
                sentASDUs [currentIndex].sentTime = SystemUtils.currentTimeMillis();

                newestSentASDU = currentIndex;

                PrintSendBuffer();
            }
        }
예제 #25
0
        private bool checkMessage(Socket socket, byte[] buffer, int msgSize)
        {
            long currentTime = SystemUtils.currentTimeMillis();

            if ((buffer [2] & 1) == 0)               /* I format frame */

            {
                if (firstIMessageReceived == false)
                {
                    firstIMessageReceived = true;
                    lastConfirmationTime  = currentTime;                    /* start timeout T2 */
                }

                if (msgSize < 7)
                {
                    DebugLog("I msg too small!");
                    return(false);
                }

                int frameSendSequenceNumber = ((buffer [3] * 0x100) + (buffer [2] & 0xfe)) / 2;
                int frameRecvSequenceNumber = ((buffer [5] * 0x100) + (buffer [4] & 0xfe)) / 2;

                DebugLog("Received I frame: N(S) = " + frameSendSequenceNumber + " N(R) = " + frameRecvSequenceNumber);

                /* check the receive sequence number N(R) - connection will be closed on an unexpected value */
                if (frameSendSequenceNumber != receiveSequenceNumber)
                {
                    DebugLog("Sequence error: Close connection!");
                    return(false);
                }

                if (CheckSequenceNumber(frameRecvSequenceNumber) == false)
                {
                    return(false);
                }

                receiveSequenceNumber = (receiveSequenceNumber + 1) % 32768;
                unconfirmedReceivedIMessages++;

                try {
                    ASDU asdu = new ASDU(parameters, buffer, 6, msgSize);

                    if (asduReceivedHandler != null)
                    {
                        asduReceivedHandler(asduReceivedHandlerParameter, asdu);
                    }
                }
                catch (ASDUParsingException e) {
                    DebugLog("ASDU parsing failed: " + e.Message);
                    return(false);
                }
            }
            else if ((buffer [2] & 0x03) == 0x01)                 /* S format frame */
            {
                int seqNo = (buffer[4] + buffer[5] * 0x100) / 2;

                DebugLog("Recv S(" + seqNo + ") (own sendcounter = " + sendSequenceNumber + ")");

                if (CheckSequenceNumber(seqNo) == false)
                {
                    return(false);
                }
            }
            else if ((buffer [2] & 0x03) == 0x03)                 /* U format frame */

            {
                uMessageTimeout = 0;

                if (buffer [2] == 0x43)                   // Check for TESTFR_ACT message
                {
                    statistics.RcvdTestFrActCounter++;
                    DebugLog("RCVD TESTFR_ACT");
                    DebugLog("SEND TESTFR_CON");
                    socket.Send(TESTFR_CON_MSG);
                    statistics.SentMsgCounter++;
                }
                else if (buffer [2] == 0x83)                     /* TESTFR_CON */
                {
                    DebugLog("RCVD TESTFR_CON");
                    statistics.RcvdTestFrConCounter++;
                    outStandingTestFRConMessages = 0;
                }
                else if (buffer [2] == 0x07)                     /* STARTDT ACT */
                {
                    DebugLog("RCVD STARTDT_ACT");
                    socket.Send(STARTDT_CON_MSG);
                    statistics.SentMsgCounter++;
                }
                else if (buffer [2] == 0x0b)                     /* STARTDT_CON */
                {
                    DebugLog("RCVD STARTDT_CON");

                    if (connectionHandler != null)
                    {
                        connectionHandler(connectionHandlerParameter, ConnectionEvent.STARTDT_CON_RECEIVED);
                    }
                }
                else if (buffer [2] == 0x23)                     /* STOPDT_CON */
                {
                    DebugLog("RCVD STOPDT_CON");

                    if (connectionHandler != null)
                    {
                        connectionHandler(connectionHandlerParameter, ConnectionEvent.STOPDT_CON_RECEIVED);
                    }
                }
            }
            else
            {
                DebugLog("Unknown message type");
                return(false);
            }

            ResetT3Timeout();

            return(true);
        }
예제 #26
0
 /// <summary>
 /// Sends an arbitrary ASDU to the connected slave
 /// </summary>
 /// <param name="asdu">The ASDU to send</param>
 public void SendASDU(ASDU asdu)
 {
     SendASDUInternal(asdu);
 }
        private void HandleASDU(ASDU asdu)
        {
            DebugLog("Handle received ASDU");

            bool messageHandled = false;

            switch (asdu.TypeId)
            {
            case TypeID.C_IC_NA_1:             /* 100 - interrogation command */

                DebugLog("Rcvd interrogation command C_IC_NA_1");

                if ((asdu.Cot == CauseOfTransmission.ACTIVATION) || (asdu.Cot == CauseOfTransmission.DEACTIVATION))
                {
                    if (server.interrogationHandler != null)
                    {
                        InterrogationCommand irc = (InterrogationCommand)asdu.GetElement(0);

                        if (server.interrogationHandler(server.InterrogationHandlerParameter, this, asdu, irc.QOI))
                        {
                            messageHandled = true;
                        }
                    }
                }
                else
                {
                    asdu.Cot = CauseOfTransmission.UNKNOWN_CAUSE_OF_TRANSMISSION;
                    this.SendASDUInternal(asdu);
                }

                break;

            case TypeID.C_CI_NA_1:             /* 101 - counter interrogation command */

                DebugLog("Rcvd counter interrogation command C_CI_NA_1");

                if ((asdu.Cot == CauseOfTransmission.ACTIVATION) || (asdu.Cot == CauseOfTransmission.DEACTIVATION))
                {
                    if (server.counterInterrogationHandler != null)
                    {
                        CounterInterrogationCommand cic = (CounterInterrogationCommand)asdu.GetElement(0);

                        if (server.counterInterrogationHandler(server.counterInterrogationHandlerParameter, this, asdu, cic.QCC))
                        {
                            messageHandled = true;
                        }
                    }
                }
                else
                {
                    asdu.Cot = CauseOfTransmission.UNKNOWN_CAUSE_OF_TRANSMISSION;
                    this.SendASDUInternal(asdu);
                }

                break;

            case TypeID.C_RD_NA_1:             /* 102 - read command */

                DebugLog("Rcvd read command C_RD_NA_1");

                if (asdu.Cot == CauseOfTransmission.REQUEST)
                {
                    DebugLog("Read request for object: " + asdu.Ca);

                    if (server.readHandler != null)
                    {
                        ReadCommand rc = (ReadCommand)asdu.GetElement(0);

                        if (server.readHandler(server.readHandlerParameter, this, asdu, rc.ObjectAddress))
                        {
                            messageHandled = true;
                        }
                    }
                }
                else
                {
                    asdu.Cot = CauseOfTransmission.UNKNOWN_CAUSE_OF_TRANSMISSION;
                    this.SendASDUInternal(asdu);
                }

                break;

            case TypeID.C_CS_NA_1:             /* 103 - Clock synchronization command */

                DebugLog("Rcvd clock sync command C_CS_NA_1");

                if (asdu.Cot == CauseOfTransmission.ACTIVATION)
                {
                    if (server.clockSynchronizationHandler != null)
                    {
                        ClockSynchronizationCommand csc = (ClockSynchronizationCommand)asdu.GetElement(0);

                        if (server.clockSynchronizationHandler(server.clockSynchronizationHandlerParameter,
                                                               this, asdu, csc.NewTime))
                        {
                            messageHandled = true;
                        }
                    }
                }
                else
                {
                    asdu.Cot = CauseOfTransmission.UNKNOWN_CAUSE_OF_TRANSMISSION;
                    this.SendASDUInternal(asdu);
                }

                break;

            case TypeID.C_TS_NA_1:             /* 104 - test command */

                DebugLog("Rcvd test command C_TS_NA_1");

                if (asdu.Cot != CauseOfTransmission.ACTIVATION)
                {
                    asdu.Cot = CauseOfTransmission.UNKNOWN_CAUSE_OF_TRANSMISSION;
                }
                else
                {
                    asdu.Cot = CauseOfTransmission.ACTIVATION_CON;
                }

                this.SendASDUInternal(asdu);

                messageHandled = true;

                break;

            case TypeID.C_RP_NA_1:             /* 105 - Reset process command */

                DebugLog("Rcvd reset process command C_RP_NA_1");

                if (asdu.Cot == CauseOfTransmission.ACTIVATION)
                {
                    if (server.resetProcessHandler != null)
                    {
                        ResetProcessCommand rpc = (ResetProcessCommand)asdu.GetElement(0);

                        if (server.resetProcessHandler(server.resetProcessHandlerParameter,
                                                       this, asdu, rpc.QRP))
                        {
                            messageHandled = true;
                        }
                    }
                }
                else
                {
                    asdu.Cot = CauseOfTransmission.UNKNOWN_CAUSE_OF_TRANSMISSION;
                    this.SendASDUInternal(asdu);
                }


                break;

            case TypeID.C_CD_NA_1:             /* 106 - Delay acquisition command */

                DebugLog("Rcvd delay acquisition command C_CD_NA_1");

                if ((asdu.Cot == CauseOfTransmission.ACTIVATION) || (asdu.Cot == CauseOfTransmission.SPONTANEOUS))
                {
                    if (server.delayAcquisitionHandler != null)
                    {
                        DelayAcquisitionCommand dac = (DelayAcquisitionCommand)asdu.GetElement(0);

                        if (server.delayAcquisitionHandler(server.delayAcquisitionHandlerParameter,
                                                           this, asdu, dac.Delay))
                        {
                            messageHandled = true;
                        }
                    }
                }
                else
                {
                    asdu.Cot = CauseOfTransmission.UNKNOWN_CAUSE_OF_TRANSMISSION;
                    this.SendASDUInternal(asdu);
                }

                break;
            }

            if ((messageHandled == false) && (server.asduHandler != null))
            {
                if (server.asduHandler(server.asduHandlerParameter, this, asdu))
                {
                    messageHandled = true;
                }
            }

            if (messageHandled == false)
            {
                asdu.Cot = CauseOfTransmission.UNKNOWN_TYPE_ID;
                this.SendASDUInternal(asdu);
            }
        }
예제 #28
0
        /// <summary>
        /// 处理消息
        /// </summary>
        /// <param name="socket"></param>
        /// <param name="buffer"></param>
        /// <param name="msgSize"></param>
        /// <returns></returns>
        private bool HandleMessage(Socket socket, byte[] buffer, int msgSize)
        {
            if ((buffer[2] & 1) == 0)
            {
                if (debugOutput)
                {
                    Console.WriteLine("Received I frame");
                }

                if (msgSize < 7)
                {
                    if (debugOutput)
                    {
                        Console.WriteLine("I msg too small!");
                    }

                    return(false);
                }


                IncreaseReceivedMessageCounters();

                if (isActive)
                {
                    bool messageHandled = false;

                    ASDU asdu = new ASDU(parameters, buffer, msgSize);

                    //根据类型来分别处理
                    switch (asdu.TypeId)
                    {
                    case TypeID.C_IC_NA_1:     /* 100 - interrogation command  总召*/

                        if (debugOutput)
                        {
                            Console.WriteLine("Rcvd interrogation command C_IC_NA_1");
                        }

                        if ((asdu.Cot == CauseOfTransmission.ACTIVATION) || (asdu.Cot == CauseOfTransmission.DEACTIVATION))
                        {
                            if (server.interrogationHandler != null)
                            {
                                InterrogationCommand irc = (InterrogationCommand)asdu.GetElement(0);

                                if (server.interrogationHandler(server.InterrogationHandlerParameter, this, asdu, irc.QOI))
                                {
                                    messageHandled = true;
                                }
                            }
                        }
                        else
                        {
                            asdu.Cot = CauseOfTransmission.UNKNOWN_CAUSE_OF_TRANSMISSION;
                            this.SendASDU(asdu);
                        }

                        break;

                    case TypeID.C_CI_NA_1:     /* 101 - counter interrogation command 累计量总召*/

                        if (debugOutput)
                        {
                            Console.WriteLine("Rcvd counter interrogation command C_CI_NA_1");
                        }

                        if ((asdu.Cot == CauseOfTransmission.ACTIVATION) || (asdu.Cot == CauseOfTransmission.DEACTIVATION))
                        {
                            if (server.counterInterrogationHandler != null)
                            {
                                CounterInterrogationCommand cic = (CounterInterrogationCommand)asdu.GetElement(0);

                                if (server.counterInterrogationHandler(server.counterInterrogationHandlerParameter, this, asdu, cic.QCC))
                                {
                                    messageHandled = true;
                                }
                            }
                        }
                        else
                        {
                            asdu.Cot = CauseOfTransmission.UNKNOWN_CAUSE_OF_TRANSMISSION;
                            this.SendASDU(asdu);
                        }

                        break;

                    case TypeID.C_RD_NA_1:     /* 102 - read command  读命令*/

                        if (debugOutput)
                        {
                            Console.WriteLine("Rcvd read command C_RD_NA_1");
                        }

                        if (asdu.Cot == CauseOfTransmission.REQUEST)
                        {
                            if (debugOutput)
                            {
                                Console.WriteLine("Read request for object: " + asdu.Ca);
                            }

                            if (server.readHandler != null)
                            {
                                ReadCommand rc = (ReadCommand)asdu.GetElement(0);

                                if (server.readHandler(server.readHandlerParameter, this, asdu, rc.ObjectAddress))
                                {
                                    messageHandled = true;
                                }
                            }
                        }
                        else
                        {
                            asdu.Cot = CauseOfTransmission.UNKNOWN_CAUSE_OF_TRANSMISSION;
                            this.SendASDU(asdu);
                        }

                        break;

                    case TypeID.C_CS_NA_1:     /* 103 - Clock synchronization command 时钟同步 */

                        if (debugOutput)
                        {
                            Console.WriteLine("Rcvd clock sync command C_CS_NA_1");
                        }

                        if (asdu.Cot == CauseOfTransmission.ACTIVATION)
                        {
                            if (server.clockSynchronizationHandler != null)
                            {
                                ClockSynchronizationCommand csc = (ClockSynchronizationCommand)asdu.GetElement(0);

                                if (server.clockSynchronizationHandler(server.clockSynchronizationHandlerParameter,
                                                                       this, asdu, csc.NewTime))
                                {
                                    messageHandled = true;
                                }
                            }
                        }
                        else
                        {
                            asdu.Cot = CauseOfTransmission.UNKNOWN_CAUSE_OF_TRANSMISSION;
                            this.SendASDU(asdu);
                        }

                        break;

                    case TypeID.C_TS_NA_1:     /* 104 - test command */

                        if (debugOutput)
                        {
                            Console.WriteLine("Rcvd test command C_TS_NA_1");
                        }

                        //直接处理
                        if (asdu.Cot != CauseOfTransmission.ACTIVATION)
                        {
                            asdu.Cot = CauseOfTransmission.UNKNOWN_CAUSE_OF_TRANSMISSION;
                        }
                        else
                        {
                            asdu.Cot = CauseOfTransmission.ACTIVATION_CON;
                        }

                        this.SendASDU(asdu);

                        messageHandled = true;

                        break;

                    case TypeID.C_RP_NA_1:     /* 105 - Reset process command  复位命令*/

                        if (debugOutput)
                        {
                            Console.WriteLine("Rcvd reset process command C_RP_NA_1");
                        }

                        if (asdu.Cot == CauseOfTransmission.ACTIVATION)
                        {
                            if (server.resetProcessHandler != null)
                            {
                                ResetProcessCommand rpc = (ResetProcessCommand)asdu.GetElement(0);

                                if (server.resetProcessHandler(server.resetProcessHandlerParameter,
                                                               this, asdu, rpc.QRP))
                                {
                                    messageHandled = true;
                                }
                            }
                        }
                        else
                        {
                            asdu.Cot = CauseOfTransmission.UNKNOWN_CAUSE_OF_TRANSMISSION;
                            this.SendASDU(asdu);
                        }


                        break;

                    case TypeID.C_CD_NA_1:     /* 106 - Delay acquisition command 延时获得*/

                        if (debugOutput)
                        {
                            Console.WriteLine("Rcvd delay acquisition command C_CD_NA_1");
                        }

                        if ((asdu.Cot == CauseOfTransmission.ACTIVATION) || (asdu.Cot == CauseOfTransmission.SPONTANEOUS))
                        {
                            if (server.delayAcquisitionHandler != null)
                            {
                                DelayAcquisitionCommand dac = (DelayAcquisitionCommand)asdu.GetElement(0);

                                if (server.delayAcquisitionHandler(server.delayAcquisitionHandlerParameter,
                                                                   this, asdu, dac.Delay))
                                {
                                    messageHandled = true;
                                }
                            }
                        }
                        else
                        {
                            asdu.Cot = CauseOfTransmission.UNKNOWN_CAUSE_OF_TRANSMISSION;
                            this.SendASDU(asdu);
                        }

                        break;
                    }

                    //都没处理,就直接当通用ASDU处理掉了
                    if ((messageHandled == false) && (server.asduHandler != null))
                    {
                        if (server.asduHandler(server.asduHandlerParameter, this, asdu))
                        {
                            messageHandled = true;
                        }
                    }

                    //依旧没处理,那就返回未知
                    if (messageHandled == false)
                    {
                        asdu.Cot = CauseOfTransmission.UNKNOWN_TYPE_ID;
                        this.SendASDU(asdu);
                    }
                }
                else
                {
                    // connection not activated --> skip message
                    if (debugOutput)
                    {
                        Console.WriteLine("Message not activated. Skip I message");
                    }
                }


                return(true);
            }

            // Check for TESTFR_ACT message
            else if ((buffer[2] & 0x43) == 0x43)
            {
                if (debugOutput)
                {
                    Console.WriteLine("Send TESTFR_CON");
                }

                socket.Send(TESTFR_CON_MSG);
            }

            // Check for STARTDT_ACT message
            else if ((buffer[2] & 0x07) == 0x07)
            {
                if (debugOutput)
                {
                    Console.WriteLine("Send STARTDT_CON");
                }

                this.isActive = true;

                socket.Send(STARTDT_CON_MSG);
            }

            // Check for STOPDT_ACT message
            else if ((buffer[2] & 0x13) == 0x13)
            {
                if (debugOutput)
                {
                    Console.WriteLine("Send STOPDT_CON");
                }

                this.isActive = false;

                socket.Send(STOPDT_CON_MSG);
            }

            // S-message  S帧(用于确认对方的接收序号)
            else if (buffer[2] == 0x01)
            {
                int messageCount = (buffer[4] + buffer[5] * 0x100) / 2;

                Console.WriteLine("Recv S(" + messageCount + ") (own sendcounter = " + sendCount + ")");
            }
            else
            {
                Console.WriteLine("Unknown message");

                return(true);
            }

            return(true);
        }
        private bool HandleMessage(byte[] buffer, int msgSize)
        {
            long currentTime = SystemUtils.currentTimeMillis();

            if ((buffer [2] & 1) == 0)
            {
                if (msgSize < 7)
                {
                    DebugLog("I msg too small!");
                    return(false);
                }

                if (firstIMessageReceived == false)
                {
                    firstIMessageReceived = true;
                    lastConfirmationTime  = currentTime;                    /* start timeout T2 */
                }

                int frameSendSequenceNumber = ((buffer [3] * 0x100) + (buffer [2] & 0xfe)) / 2;
                int frameRecvSequenceNumber = ((buffer [5] * 0x100) + (buffer [4] & 0xfe)) / 2;

                DebugLog("Received I frame: N(S) = " + frameSendSequenceNumber + " N(R) = " + frameRecvSequenceNumber);

                /* check the receive sequence number N(R) - connection will be closed on an unexpected value */
                if (frameSendSequenceNumber != receiveCount)
                {
                    DebugLog("Sequence error: Close connection!");
                    return(false);
                }

                if (CheckSequenceNumber(frameRecvSequenceNumber) == false)
                {
                    DebugLog("Sequence number check failed");
                    return(false);
                }

                receiveCount = (receiveCount + 1) % 32768;
                unconfirmedReceivedIMessages++;

                if (isActive)
                {
                    try {
                        ASDU asdu = new ASDU(parameters, buffer, 6, msgSize);

                        // push to handler thread for processing
                        DebugLog("Enqueue received I-message for processing");
                        receivedASDUs.Enqueue(asdu);
                    }
                    catch (ASDUParsingException e) {
                        DebugLog("ASDU parsing failed: " + e.Message);
                        return(false);
                    }
                }
                else
                {
                    // connection not activated --> skip message
                    DebugLog("Connection not activated. Skip I message");
                }
            }

            // Check for TESTFR_ACT message
            else if ((buffer [2] & 0x43) == 0x43)
            {
                DebugLog("Send TESTFR_CON");

                socketStream.Write(TESTFR_CON_MSG, 0, TESTFR_CON_MSG.Length);
            }

            // Check for STARTDT_ACT message
            else if ((buffer [2] & 0x07) == 0x07)
            {
                DebugLog("Send STARTDT_CON");

                this.isActive = true;

                this.server.Activated(this);

                socketStream.Write(STARTDT_CON_MSG, 0, TESTFR_CON_MSG.Length);
            }

            // Check for STOPDT_ACT message
            else if ((buffer [2] & 0x13) == 0x13)
            {
                DebugLog("Send STOPDT_CON");

                this.isActive = false;

                socketStream.Write(STOPDT_CON_MSG, 0, TESTFR_CON_MSG.Length);
            }

            // Check for TESTFR_CON message
            else if ((buffer [2] & 0x83) == 0x83)
            {
                DebugLog("Recv TESTFR_CON");

                outStandingTestFRConMessages = 0;
            }

            // S-message
            else if (buffer [2] == 0x01)
            {
                int seqNo = (buffer[4] + buffer[5] * 0x100) / 2;

                DebugLog("Recv S(" + seqNo + ") (own sendcounter = " + sendCount + ")");

                if (CheckSequenceNumber(seqNo) == false)
                {
                    return(false);
                }
            }
            else
            {
                DebugLog("Unknown message");
            }

            ResetT3Timeout();

            return(true);
        }
예제 #30
0
        /// <summary>
        /// 信息检查,按说每收到一条信息都要来这里检查。。。
        /// </summary>
        /// <param name="socket"></param>
        /// <param name="buffer"></param>
        /// <param name="msgSize"></param>
        /// <returns></returns>
        private bool checkMessage(Socket socket, byte[] buffer, int msgSize)
        {
            //这里检测I帧和U帧,不知道为什么不检测S帧,难道是S帧已经处理过了?
            //update:似乎他这里只需要发送S帧,不主动监测S帧。。。
            if ((buffer[2] & 1) == 0)
            { /* I format frame */
                if (debugOutput)
                {
                    Console.WriteLine("Received I frame");
                }

                if (msgSize < 7)
                {
                    if (debugOutput)
                    {
                        Console.WriteLine("I msg too small!");
                    }

                    return(false);
                }

                receiveCount++;
                unconfirmedMessages++;

                long currentTime = SystemUtils.currentTimeMillis();

                if ((unconfirmedMessages > parameters.W) || checkConfirmTimeout(currentTime))
                {
                    //未确认消息超过W,或者t2超时,则发送S帧
                    lastConfirmationTime = currentTime;

                    unconfirmedMessages = 0;
                    sendSMessage();
                }

                //新建一个ASDU,准备解析
                ASDU asdu = new ASDU(parameters, buffer, msgSize);

                //解析ASDU
                if (asduReceivedHandler != null)
                {
                    asduReceivedHandler(asduReceivedHandlerParameter, asdu);
                }
            }
            else if ((buffer[2] & 0x03) == 0x03)
            {     /* U format frame */
                if (buffer[2] == 0x43)
                { // Check for TESTFR_ACT message
                    //收到了测试命令,回复测试确认
                    socket.Send(TESTFR_CON_MSG);
                }
                else if (buffer[2] == 0x07)
                { /* STARTDT ACT */
                    //收到了开启命令,回复开启命令确认
                    socket.Send(STARTDT_CON_MSG);
                }
                else if (buffer[2] == 0x0b)
                { /* STARTDT_CON */
                    //收到了开启确认,处理[已连接]事件
                    if (connectionHandler != null)
                    {
                        connectionHandler(connectionHandlerParameter, ConnectionEvent.STARTDT_CON_RECEIVED);
                    }
                }
                else if (buffer[2] == 0x23)
                { /* STOPDT_CON */
                    //收到了停止确认,处理[已断开]事件
                    if (connectionHandler != null)
                    {
                        connectionHandler(connectionHandlerParameter, ConnectionEvent.STOPDT_CON_RECEIVED);
                    }
                }
            }

            return(true);
        }