/* * 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.mobicents.protocols.ss7.m3ua.impl; import javolution.util.FastList; import org.apache.log4j.Logger; import org.mobicents.protocols.ss7.m3ua.Asp; import org.mobicents.protocols.ss7.m3ua.ExchangeType; import org.mobicents.protocols.ss7.m3ua.Functionality; import org.mobicents.protocols.ss7.m3ua.IPSPType; import org.mobicents.protocols.ss7.m3ua.impl.fsm.FSM; import org.mobicents.protocols.ss7.m3ua.impl.fsm.UnknownTransitionException; import org.mobicents.protocols.ss7.m3ua.message.MessageClass; import org.mobicents.protocols.ss7.m3ua.message.MessageType; import org.mobicents.protocols.ss7.m3ua.message.asptm.ASPActive; import org.mobicents.protocols.ss7.m3ua.message.asptm.ASPActiveAck; import org.mobicents.protocols.ss7.m3ua.message.asptm.ASPInactive; import org.mobicents.protocols.ss7.m3ua.message.asptm.ASPInactiveAck; import org.mobicents.protocols.ss7.m3ua.parameter.ErrorCode; import org.mobicents.protocols.ss7.m3ua.parameter.RoutingContext; import org.mobicents.protocols.ss7.m3ua.parameter.TrafficModeType; /** * * @author amit bhayani * */ public class AspTrafficMaintenanceHandler extends MessageHandler { private static final Logger logger = Logger.getLogger(AspTrafficMaintenanceHandler.class); public AspTrafficMaintenanceHandler(AspFactoryImpl aspFactoryImpl) { super(aspFactoryImpl); } private void handleAspInactive(AspImpl aspImpl, ASPInactive aspInactive) { AsImpl appServer = (AsImpl) aspImpl.getAs(); FSM aspPeerFSM = aspImpl.getPeerFSM(); if (aspPeerFSM == null) { logger.error(String.format("Received ASPINACTIVE=%s for ASP=%s. But peer FSM for ASP is null.", aspInactive, this.aspFactoryImpl.getName())); return; } FSM asLocalFSM = appServer.getLocalFSM(); if (asLocalFSM == null) { logger.error(String.format("Received ASPINACTIVE=%s for ASP=%s. But local FSM for AS is null.", aspInactive, this.aspFactoryImpl.getName())); return; } ASPInactiveAck aspInactAck = (ASPInactiveAck) this.aspFactoryImpl.messageFactory.createMessage( MessageClass.ASP_TRAFFIC_MAINTENANCE, MessageType.ASP_INACTIVE_ACK); aspInactAck.setRoutingContext(appServer.getRoutingContext()); this.aspFactoryImpl.write(aspInactAck); try { aspPeerFSM.setAttribute(FSM.ATTRIBUTE_MESSAGE, aspInactive); aspPeerFSM.signal(TransitionState.ASP_INACTIVE); // Signal AS to transition asLocalFSM.setAttribute(AsImpl.ATTRIBUTE_ASP, aspImpl); asLocalFSM.signal(TransitionState.ASP_INACTIVE); } catch (UnknownTransitionException e) { logger.error(e.getMessage(), e); } } private void handleAspActive(AspImpl aspImpl, ASPActive aspActive) { AsImpl appServer = (AsImpl) aspImpl.getAs(); TrafficModeType trfModType = aspActive.getTrafficModeType(); if (appServer.getTrafficModeType() != null) { // AppServer has Traffic Mode Type defined check if it // matches with sent ASP ACTIVE Message if (trfModType != null && appServer.getTrafficModeType().getMode() != trfModType.getMode()) { // Traffic Mode Type mismatch. Send Error. // TODO should send error or drop message? ErrorCode errorCodeObj = this.aspFactoryImpl.parameterFactory .createErrorCode(ErrorCode.Unsupported_Traffic_Mode_Type); this.sendError(appServer.getRoutingContext(), errorCodeObj); return; } // message doesn't have Traffic Mode Type } else { // AppServer Traffic Mode Type is optionally configured via // management config. If not select the first available in // AspUp message if (trfModType == null) { // Asp UP didn't specify the Traffic Mode either. use // default which is loadshare appServer.setDefaultTrafficModeType(); } else { // Set the Traffic Mode Type passed in ASP ACTIVE appServer.setTrafficModeType(trfModType); } } FSM aspPeerFSM = aspImpl.getPeerFSM(); if (aspPeerFSM == null) { logger.error(String.format("Received ASPACTIVE=%s for ASP=%s. But peer FSM for ASP is null.", aspActive, this.aspFactoryImpl.getName())); return; } FSM asLocalFSM = appServer.getLocalFSM(); if (asLocalFSM == null) { logger.error(String.format("Received ASPACTIVE=%s for ASP=%s. But local FSM for AS is null.", aspActive, this.aspFactoryImpl.getName())); return; } ASPActiveAck aspActAck = (ASPActiveAck) this.aspFactoryImpl.messageFactory.createMessage( MessageClass.ASP_TRAFFIC_MAINTENANCE, MessageType.ASP_ACTIVE_ACK); aspActAck.setTrafficModeType(appServer.getTrafficModeType()); aspActAck.setRoutingContext(appServer.getRoutingContext()); this.aspFactoryImpl.write(aspActAck); try { aspPeerFSM.setAttribute(FSM.ATTRIBUTE_MESSAGE, aspActive); aspPeerFSM.signal(TransitionState.ASP_ACTIVE); // Signal AS to transition asLocalFSM.setAttribute(AsImpl.ATTRIBUTE_ASP, aspImpl); asLocalFSM.signal(TransitionState.ASP_ACTIVE); } catch (UnknownTransitionException e) { logger.error(e.getMessage(), e); } } protected void handleAspActive(ASPActive aspActive) { RoutingContext rc = aspActive.getRoutingContext(); 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)) { if (rc == null) { AspImpl aspImpl = this.getAspForNullRc(); if (aspImpl == null) { // Error condition logger.error(String .format("Rx : ASP ACTIVE=%s with null RC for Aspfactory=%s. But no ASP configured for null RC. Sent back Error", aspActive, this.aspFactoryImpl.getName())); return; } handleAspActive(aspImpl, aspActive); } else { long[] rcs = rc.getRoutingContexts(); for (int count = 0; count < rcs.length; count++) { AspImpl aspImpl = this.aspFactoryImpl.getAsp(rcs[count]); if (aspImpl == null) { // this is error. Send back error RoutingContext rcObj = this.aspFactoryImpl.parameterFactory .createRoutingContext(new long[] { rcs[count] }); ErrorCode errorCodeObj = this.aspFactoryImpl.parameterFactory .createErrorCode(ErrorCode.Invalid_Routing_Context); sendError(rcObj, errorCodeObj); logger.error(String .format("Rx : ASPACTIVE=%s with RC=%d for Aspfactory=%s. But no ASP configured for this RC. Sending back Error", aspActive, rcs[count], this.aspFactoryImpl.getName())); continue; } handleAspActive(aspImpl, aspActive); }// for } } else { // TODO : Should we silently drop ASPACTIVE? // ASPUP_ACK is unexpected in this state ErrorCode errorCodeObj = this.aspFactoryImpl.parameterFactory.createErrorCode(ErrorCode.Unexpected_Message); sendError(null, errorCodeObj); } } private void handleAspActiveAck(AspImpl aspImpl, ASPActiveAck aspActiveAck, TrafficModeType trMode) { AsImpl asImpl = (AsImpl) aspImpl.getAs(); if (trMode == null) { trMode = aspImpl.getAs().getDefaultTrafficModeType(); } asImpl.setTrafficModeType(trMode); FSM aspLocalFSM = aspImpl.getLocalFSM(); if (aspLocalFSM == null) { logger.error(String.format("Received ASPACTIVE_ACK=%s for ASP=%s. But local FSM is null.", aspActiveAck, this.aspFactoryImpl.getName())); return; } try { aspLocalFSM.signal(TransitionState.ASP_ACTIVE_ACK); if (aspFactoryImpl.getFunctionality() == Functionality.IPSP) { // If its IPSP, we know NTFY will not be received, // so transition AS FSM here FSM asPeerFSM = asImpl.getPeerFSM(); if (asPeerFSM == null) { logger.error(String.format("Received ASPACTIVE_ACK=%s for ASP=%s. But Peer FSM of AS=%s is null.", aspActiveAck, this.aspFactoryImpl.getName(), asImpl)); return; } asPeerFSM.setAttribute(AsImpl.ATTRIBUTE_ASP, aspImpl); asPeerFSM.signal(TransitionState.AS_STATE_CHANGE_ACTIVE); } } catch (UnknownTransitionException e) { logger.error(e.getMessage(), e); } } protected void handleAspActiveAck(ASPActiveAck aspActiveAck) { if (!this.aspFactoryImpl.started) { // If management stopped this ASP, ignore ASPActiveAck return; } RoutingContext rc = aspActiveAck.getRoutingContext(); 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)) { TrafficModeType trMode = aspActiveAck.getTrafficModeType(); if (rc == null) { AspImpl aspImpl = this.getAspForNullRc(); if (aspImpl == null) { // Error condition logger.error(String .format("Rx : ASP ACTIVE_ACK=%s with null RC for Aspfactory=%s. But no ASP configured for null RC. Sent back Error", aspActiveAck, this.aspFactoryImpl.getName())); return; } handleAspActiveAck(aspImpl, aspActiveAck, trMode); } else { long[] rcs = rc.getRoutingContexts(); for (int count = 0; count < rcs.length; count++) { AspImpl aspImpl = this.aspFactoryImpl.getAsp(rcs[count]); handleAspActiveAck(aspImpl, aspActiveAck, trMode); }// for } } else { // TODO : Should we silently drop ASPACTIVE_ACK? // ASPACTIVE_ACK is unexpected in this state ErrorCode errorCodeObj = this.aspFactoryImpl.parameterFactory.createErrorCode(ErrorCode.Unexpected_Message); sendError(rc, errorCodeObj); } } protected void handleAspInactive(ASPInactive aspInactive) { RoutingContext rc = aspInactive.getRoutingContext(); 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)) { if (rc == null) { AspImpl aspImpl = this.getAspForNullRc(); if (aspImpl == null) { // Error condition logger.error(String .format("Rx : ASPINACTIVE=%s with null RC for Aspfactory=%s. But no ASP configured for null RC. Sent back Error", aspInactive, this.aspFactoryImpl.getName())); return; } handleAspInactive(aspImpl, aspInactive); } else { long[] rcs = rc.getRoutingContexts(); for (int count = 0; count < rcs.length; count++) { AspImpl aspImpl = this.aspFactoryImpl.getAsp(rcs[count]); if (aspImpl == null) { // this is error. Send back error RoutingContext rcObj = this.aspFactoryImpl.parameterFactory .createRoutingContext(new long[] { rcs[count] }); ErrorCode errorCodeObj = this.aspFactoryImpl.parameterFactory .createErrorCode(ErrorCode.Invalid_Routing_Context); sendError(rcObj, errorCodeObj); logger.error(String .format("Rx : ASPINACTIVE=%s with RC=%d for Aspfactory=%s. But no ASP configured for this RC. Sending back Error", aspInactive, rcs[count], this.aspFactoryImpl.getName())); continue; } handleAspInactive(aspImpl, aspInactive); }// for } } else { // TODO : Should we silently drop ASPINACTIVE? // ASPUP_ACK is unexpected in this state ErrorCode errorCodeObj = this.aspFactoryImpl.parameterFactory.createErrorCode(ErrorCode.Unexpected_Message); sendError(null, errorCodeObj); } } protected void handleAspInactiveAck(ASPInactiveAck aspInactiveAck) { if (!this.aspFactoryImpl.started) { // If management stopped this ASP, ignore ASPInactiveAck return; } RoutingContext rc = aspInactiveAck.getRoutingContext(); 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)) { if (rc == null) { AspImpl aspImpl = this.getAspForNullRc(); if (aspImpl == null) { // Error condition logger.error(String .format("Rx : ASPINACTIVE_ACK=%s with null RC for Aspfactory=%s. But no ASP configured for null RC. Sent back Error", aspInactiveAck, this.aspFactoryImpl.getName())); return; } handleAspInactiveAck(aspImpl, aspInactiveAck); } else { long[] rcs = aspInactiveAck.getRoutingContext().getRoutingContexts(); for (int count = 0; count < rcs.length; count++) { AspImpl aspImpl = this.aspFactoryImpl.getAsp(rcs[count]); if (aspImpl == null) { // this is error. Send back error RoutingContext rcObj = this.aspFactoryImpl.parameterFactory .createRoutingContext(new long[] { rcs[count] }); ErrorCode errorCodeObj = this.aspFactoryImpl.parameterFactory .createErrorCode(ErrorCode.Invalid_Routing_Context); sendError(rcObj, errorCodeObj); logger.error(String .format("Rx : ASPINACTIVE_ACK=%s with RC=%d for Aspfactory=%s. But no ASP configured for this RC. Sending back Error", aspInactiveAck, rcs[count], this.aspFactoryImpl.getName())); continue; } handleAspInactiveAck(aspImpl, aspInactiveAck); }// for } } else { // TODO : Should we silently drop ASPINACTIVE_ACK? // ASPINACTIVE_ACK is unexpected in this state ErrorCode errorCodeObj = this.aspFactoryImpl.parameterFactory.createErrorCode(ErrorCode.Unexpected_Message); sendError(rc, errorCodeObj); } } private void handleAspInactiveAck(AspImpl aspImpl, ASPInactiveAck aspInactiveAck) { FSM aspLocalFSM = aspImpl.getLocalFSM(); if (aspLocalFSM == null) { logger.error(String.format("Received ASPINACTIVE_ACK=%s for ASP=%s. But local FSM is null.", aspInactiveAck, this.aspFactoryImpl.getName())); return; } AsImpl asImpl = (AsImpl) aspImpl.getAs(); try { aspLocalFSM.signal(TransitionState.ASP_INACTIVE_ACK); if (this.aspFactoryImpl.getFunctionality() == Functionality.IPSP) { // If its IPSP, we know NTFY will not be received, // so transition AS FSM here FSM asPeerFSM = asImpl.getPeerFSM(); if (asPeerFSM == null) { logger.error(String.format("Received ASPINACTIVE_ACK=%s for ASP=%s. But Peer FSM of AS=%s is null.", aspInactiveAck, this.aspFactoryImpl.getName(), asImpl)); return; } if (asImpl.getTrafficModeType().getMode() == TrafficModeType.Loadshare) { // If it is loadshare and if there is atleast one other ASP // who ACTIVE, dont transition AS to INACTIVE for (FastList.Node<Asp> n = asImpl.appServerProcs.head(), end = asImpl.appServerProcs.tail(); (n = n .getNext()) != end;) { AspImpl remAspImpl = (AspImpl) n.getValue(); FSM aspPeerFSM = remAspImpl.getPeerFSM(); AspState aspState = AspState.getState(aspPeerFSM.getState().getName()); if (aspState == AspState.ACTIVE) { return; } } } // TODO : Check if other ASP are INACTIVE, if yes ACTIVATE them asPeerFSM.setAttribute(AsImpl.ATTRIBUTE_ASP, aspImpl); asPeerFSM.signal(TransitionState.AS_STATE_CHANGE_PENDING); } } catch (UnknownTransitionException e) { logger.error(e.getMessage(), e); } } }