All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.restcomm.protocols.ss7.m3ua.impl.AspStateMaintenanceHandler Maven / Gradle / Ivy

/*
 * TeleStax, Open Source Cloud Communications  Copyright 2012.
 * and individual contributors
 * by the @authors tag. See the copyright.txt in the distribution for a
 * full listing of individual contributors.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */
package org.restcomm.protocols.ss7.m3ua.impl;

import javolution.util.FastList;

import org.apache.log4j.Logger;
import org.restcomm.protocols.ss7.m3ua.Asp;
import org.restcomm.protocols.ss7.m3ua.ExchangeType;
import org.restcomm.protocols.ss7.m3ua.Functionality;
import org.restcomm.protocols.ss7.m3ua.IPSPType;
import org.restcomm.protocols.ss7.m3ua.impl.fsm.FSM;
import org.restcomm.protocols.ss7.m3ua.impl.fsm.UnknownTransitionException;
import org.restcomm.protocols.ss7.m3ua.message.MessageClass;
import org.restcomm.protocols.ss7.m3ua.message.MessageType;
import org.restcomm.protocols.ss7.m3ua.message.aspsm.ASPDown;
import org.restcomm.protocols.ss7.m3ua.message.aspsm.ASPDownAck;
import org.restcomm.protocols.ss7.m3ua.message.aspsm.ASPUp;
import org.restcomm.protocols.ss7.m3ua.message.aspsm.ASPUpAck;
import org.restcomm.protocols.ss7.m3ua.message.aspsm.Heartbeat;
import org.restcomm.protocols.ss7.m3ua.message.aspsm.HeartbeatAck;
import org.restcomm.protocols.ss7.m3ua.parameter.ASPIdentifier;
import org.restcomm.protocols.ss7.m3ua.parameter.ErrorCode;
import org.restcomm.protocols.ss7.m3ua.parameter.TrafficModeType;

/**
 *
 * @author amit bhayani
 *
 */
public class AspStateMaintenanceHandler extends MessageHandler {

    private static final Logger logger = Logger.getLogger(AspStateMaintenanceHandler.class);

    public AspStateMaintenanceHandler(AspFactoryImpl aspFactoryImpl) {
        super(aspFactoryImpl);
    }

    protected void handleAspUp(ASPUp aspUp) {

        if (aspFactoryImpl.getFunctionality() == Functionality.SGW
                || (aspFactoryImpl.getFunctionality() == Functionality.AS && aspFactoryImpl.getExchangeType() == ExchangeType.DE)
                || (aspFactoryImpl.getFunctionality() == Functionality.IPSP && aspFactoryImpl.getExchangeType() == ExchangeType.DE)
                || (aspFactoryImpl.getFunctionality() == Functionality.IPSP
                        && aspFactoryImpl.getExchangeType() == ExchangeType.SE && aspFactoryImpl.getIpspType() == IPSPType.SERVER)) {

            ASPUpAck aspUpAck = (ASPUpAck) this.aspFactoryImpl.messageFactory.createMessage(MessageClass.ASP_STATE_MAINTENANCE,
                    MessageType.ASP_UP_ACK);

            ASPIdentifier aspId = aspUp.getASPIdentifier();
            aspUpAck.setASPIdentifier(aspId);
            this.aspFactoryImpl.write(aspUpAck);

            // If an ASP Up message is received and, internally, the remote ASP
            // is in the ASP-ACTIVE state, an ASP Up Ack message is returned, as
            // well as an Error message ("Unexpected Message"). In addition, the
            // remote ASP state is changed to ASP-INACTIVE in all relevant
            // Application Servers, and all registered Routing Keys are
            // considered deregistered.

            for (FastList.Node n = this.aspFactoryImpl.aspList.head(), end = this.aspFactoryImpl.aspList.tail(); (n = n
                    .getNext()) != end;) {
                AspImpl aspImpl = (AspImpl) n.getValue();

                // Set the ASPIdentifier for each ASP
                aspImpl.setASPIdentifier(aspUp.getASPIdentifier());

                FSM aspPeerFSM = aspImpl.getPeerFSM();
                if (aspPeerFSM == null) {
                    logger.error(String.format("Received ASPUP=%s for ASP=%s. But peer FSM is null.", aspUp,
                            this.aspFactoryImpl.getName()));
                    return;
                }

                if (AspState.getState(aspPeerFSM.getState().getName()) == AspState.ACTIVE) {
                    // Check if ASP is in ACTIVE, its error state

                    ErrorCode errorCodeObj = this.aspFactoryImpl.parameterFactory.createErrorCode(ErrorCode.Unexpected_Message);

                    this.sendError(aspImpl.getAs().getRoutingContext(), errorCodeObj);
                    // break;
                }

                try {
                    // Signal ASP about state change
                    aspPeerFSM.setAttribute(FSM.ATTRIBUTE_MESSAGE, aspUp);
                    aspPeerFSM.signal(TransitionState.ASP_UP);

                    // Signal corresponding AS about ASP's state transition
                    FSM asLocalFSM = ((AsImpl) aspImpl.getAs()).getLocalFSM();

                    asLocalFSM.setAttribute(AsImpl.ATTRIBUTE_ASP, aspImpl);
                    asLocalFSM.signal(TransitionState.ASP_UP);
                } catch (UnknownTransitionException e) {
                    logger.error(e.getMessage(), e);
                }
            }
        } else {
            // TODO : Should we silently drop ASPUP_ACK?

            // ASPUP_ACK is unexpected in this state
            ErrorCode errorCodeObj = this.aspFactoryImpl.parameterFactory.createErrorCode(ErrorCode.Unexpected_Message);
            sendError(null, errorCodeObj);
        }

    }

    protected void handleAspUpAck(ASPUpAck aspUpAck) {

        if (!this.aspFactoryImpl.started) {
            // If management stopped this ASP, ignore ASPUpAck
            return;
        }

        if (aspFactoryImpl.getFunctionality() == Functionality.AS
                || (aspFactoryImpl.getFunctionality() == Functionality.SGW && aspFactoryImpl.getExchangeType() == ExchangeType.DE)
                || (aspFactoryImpl.getFunctionality() == Functionality.IPSP && aspFactoryImpl.getExchangeType() == ExchangeType.DE)
                || (aspFactoryImpl.getFunctionality() == Functionality.IPSP
                        && aspFactoryImpl.getExchangeType() == ExchangeType.SE && aspFactoryImpl.getIpspType() == IPSPType.CLIENT)) {

            for (FastList.Node n = this.aspFactoryImpl.aspList.head(), end = this.aspFactoryImpl.aspList.tail(); (n = n
                    .getNext()) != end;) {
                AspImpl aspImpl = (AspImpl) n.getValue();

                FSM aspLocalFSM = aspImpl.getLocalFSM();
                if (aspLocalFSM == null) {
                    logger.error(String.format("Received ASPUP_ACK=%s for ASP=%s. But local FSM is null.", aspUpAck,
                            this.aspFactoryImpl.getName()));
                    return;
                }

                boolean transToActive = this.activate(aspImpl);

                if (!transToActive) {
                    // Transition to INACTIVE
                    try {
                        aspLocalFSM.signal(TransitionState.ASP_INACTIVE);
                    } catch (UnknownTransitionException e) {
                        logger.error(e.getMessage(), e);
                    }
                } else {
                    // Transition to ACTIVE_SENT
                    try {
                        aspLocalFSM.signal(TransitionState.ASP_ACTIVE_SENT);

                        if (aspFactoryImpl.getFunctionality() == Functionality.IPSP) {
                            // If its IPSP, we know NTFY will not be received,
                            // so transition AS FSM here
                            AsImpl asImpl = (AsImpl) aspImpl.getAs();
                            FSM asPeerFSM = asImpl.getPeerFSM();

                            if (asPeerFSM == null) {
                                logger.error(String.format("Received ASPUP_ACK=%s for ASP=%s. But Peer FSM of AS=%s is null.",
                                        aspUpAck, this.aspFactoryImpl.getName(), asImpl));
                                return;
                            }

                            AsState asPeerFSMState = AsState.getState(asPeerFSM.getState().getName());
                            if (AsState.DOWN == asPeerFSMState) {
                                // Transition to INACTIVE only if its DOWN
                                asPeerFSM.setAttribute(AsImpl.ATTRIBUTE_ASP, aspImpl);
                                asPeerFSM.signal(TransitionState.AS_STATE_CHANGE_INACTIVE);
                            }
                        }
                    } catch (UnknownTransitionException e) {
                        logger.error(e.getMessage(), e);
                    }
                }// if..else
            }// for

        } else {
            // TODO : Should we silently drop ASPUP_ACK?

            // ASPUP_ACK is unexpected in this state
            ErrorCode errorCodeObj = this.aspFactoryImpl.parameterFactory.createErrorCode(ErrorCode.Unexpected_Message);
            sendError(null, errorCodeObj);
        }
    }

    protected void handleAspDown(ASPDown aspDown) {

        if (aspFactoryImpl.getFunctionality() == Functionality.SGW
                || (aspFactoryImpl.getFunctionality() == Functionality.AS && aspFactoryImpl.getExchangeType() == ExchangeType.DE)
                || (aspFactoryImpl.getFunctionality() == Functionality.IPSP && aspFactoryImpl.getExchangeType() == ExchangeType.DE)
                || (aspFactoryImpl.getFunctionality() == Functionality.IPSP
                        && aspFactoryImpl.getExchangeType() == ExchangeType.SE && aspFactoryImpl.getIpspType() == IPSPType.SERVER)) {

            ASPDownAck aspDwnAck = (ASPDownAck) this.aspFactoryImpl.messageFactory.createMessage(
                    MessageClass.ASP_STATE_MAINTENANCE, MessageType.ASP_DOWN_ACK);
            this.aspFactoryImpl.write(aspDwnAck);

            // ASPSM should be given to all ASP's
            for (FastList.Node n = this.aspFactoryImpl.aspList.head(), end = this.aspFactoryImpl.aspList.tail(); (n = n
                    .getNext()) != end;) {
                AspImpl aspImpl = (AspImpl) n.getValue();

                FSM aspPeerFSM = aspImpl.getPeerFSM();
                if (aspPeerFSM == null) {
                    logger.error(String.format("Received ASPDOWN=%s for ASP=%s. But peer FSM is null.", aspDown,
                            this.aspFactoryImpl.getName()));
                    return;
                }

                try {
                    // Signal ASP about state change
                    aspPeerFSM.setAttribute(FSM.ATTRIBUTE_MESSAGE, aspDown);
                    aspPeerFSM.signal(TransitionState.ASP_DOWN);

                    // Signal corresponding AS about ASP's state transition
                    FSM asLocalFSM = ((AsImpl) aspImpl.getAs()).getLocalFSM();

                    asLocalFSM.setAttribute(AsImpl.ATTRIBUTE_ASP, aspImpl);
                    asLocalFSM.signal(TransitionState.ASP_DOWN);

                } catch (UnknownTransitionException e) {
                    logger.error(e.getMessage(), e);
                }

            }

        } else {
            // TODO : Should we silently drop ASPUP_ACK?

            // ASPUP_ACK is unexpected in this state
            ErrorCode errorCodeObj = this.aspFactoryImpl.parameterFactory.createErrorCode(ErrorCode.Unexpected_Message);
            sendError(null, errorCodeObj);
        }
    }

    protected void handleAspDownAck(ASPDownAck aspUpAck) {

        if (!this.aspFactoryImpl.started) {

            boolean stopAssociation = true;

            for (FastList.Node n = this.aspFactoryImpl.aspList.head(), end = this.aspFactoryImpl.aspList.tail(); (n = n
                    .getNext()) != end;) {
                AspImpl aspImpl = (AspImpl) n.getValue();
                FSM fsm = aspImpl.getLocalFSM();
                if (fsm == null) {
                    logger.error(String.format("Received ASPDOWN_ACK=%s for ASP=%s. But local FSM is null.", aspUpAck,
                            this.aspFactoryImpl.getName()));
                    continue;
                }

                FSM fsmPeer = aspImpl.getPeerFSM();

                // If ASP's peer FSM is not null and it's state is not DOWN,
                // don't stop the underlying Association
                if (fsmPeer != null) {
                    AspState aspPeerState = AspState.getState(fsmPeer.getState().getName());

                    if (aspPeerState != AspState.DOWN) {
                        stopAssociation = false;
                    }
                }

                try {
                    fsm.signal(TransitionState.ASP_DOWN_ACK);
                } catch (UnknownTransitionException e) {
                    logger.error(e.getMessage(), e);
                }
            }// for

            if (!stopAssociation) {
                logger.error(String
                        .format("Ungracefully stopping the underlying Association=%s for AspFactory=%s. Atleast one of the ASP's is Double Exchange and Peer ASP state is still not down",
                                this.aspFactoryImpl.association.getName(), this.aspFactoryImpl.getName()));
            }

            try {
                if (this.aspFactoryImpl.aspFactoryStopTimer != null) {
                    this.aspFactoryImpl.aspFactoryStopTimer.cancel();
                }
                this.aspFactoryImpl.transportManagement.stopAssociation(this.aspFactoryImpl.association.getName());
            } catch (Exception e) {
                logger.error(
                        String.format("Exception while starting the Association=%s", this.aspFactoryImpl.association.getName()),
                        e);
            }
        } else {
            logger.error(String.format("Received ASPDOWN_ACK=%s for ASPFactory=%s. But Aspfactory is down.", aspUpAck,
                    this.aspFactoryImpl.getName()));
        }
    }

    /**
     * If we receive Heartbeat, we send back response
     *
     * @param hrtBeat
     */
    public void handleHeartbeat(Heartbeat hrtBeat) {
        HeartbeatAck hrtBeatAck = (HeartbeatAck) this.aspFactoryImpl.messageFactory.createMessage(
                MessageClass.ASP_STATE_MAINTENANCE, MessageType.HEARTBEAT_ACK);
        hrtBeatAck.setHeartbeatData(hrtBeat.getHeartbeatData());
        this.aspFactoryImpl.write(hrtBeatAck);

    }

    private boolean activate(AspImpl aspImpl) {
        // If its loadshare, we want to send ASP_ACTIVE else if its
        // Override and there is already one ACTIVE, we leave this one
        // as INACTIVE

        AsImpl asImpl = (AsImpl) aspImpl.getAs();

        // By default we assume Traffic Mode is Loadshare
        if (asImpl.getTrafficModeType() == null || asImpl.getTrafficModeType().getMode() == TrafficModeType.Loadshare) {
            // Activate this ASP
            this.aspFactoryImpl.sendAspActive(asImpl);
            return true;
        } else if (asImpl.getTrafficModeType().getMode() == TrafficModeType.Override) {

            for (FastList.Node n = asImpl.appServerProcs.head(), end = asImpl.appServerProcs.tail(); (n = n.getNext()) != end;) {
                AspImpl asptemp = (AspImpl) n.getValue();
                FSM fsm = asptemp.getLocalFSM();
                AspState aspState = AspState.getState(fsm.getState().getName());

                if (!asptemp.getName().equals(aspImpl.getName())
                        && (aspState == AspState.ACTIVE_SENT || aspState == AspState.ACTIVE)) {
                    return false;
                }
            }// for

            this.aspFactoryImpl.sendAspActive(asImpl);
            return true;

        }
        return false;
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy