/* * 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.sccp.impl.router; import javolution.text.TextBuilder; import javolution.util.FastMap; import javolution.xml.XMLBinding; import javolution.xml.XMLObjectReader; import javolution.xml.XMLObjectWriter; import javolution.xml.stream.XMLStreamException; import org.apache.log4j.Logger; import org.mobicents.protocols.ss7.sccp.LoadSharingAlgorithm; import org.mobicents.protocols.ss7.sccp.LongMessageRule; import org.mobicents.protocols.ss7.sccp.LongMessageRuleType; import org.mobicents.protocols.ss7.sccp.Mtp3ServiceAccessPoint; import org.mobicents.protocols.ss7.sccp.NetworkIdState; import org.mobicents.protocols.ss7.sccp.OriginationType; import org.mobicents.protocols.ss7.sccp.RemoteSignalingPointCode; import org.mobicents.protocols.ss7.sccp.Router; import org.mobicents.protocols.ss7.sccp.Rule; import org.mobicents.protocols.ss7.sccp.RuleType; import org.mobicents.protocols.ss7.sccp.SccpStack; import org.mobicents.protocols.ss7.sccp.impl.congestion.NetworkIdStateImpl; import org.mobicents.protocols.ss7.sccp.impl.congestion.SccpCongestionControl; import org.mobicents.protocols.ss7.sccp.impl.oam.SccpOAMMessage; import org.mobicents.protocols.ss7.sccp.impl.parameter.GlobalTitle0001Impl; import org.mobicents.protocols.ss7.sccp.impl.parameter.GlobalTitle0010Impl; import org.mobicents.protocols.ss7.sccp.impl.parameter.GlobalTitle0011Impl; import org.mobicents.protocols.ss7.sccp.impl.parameter.GlobalTitle0100Impl; import org.mobicents.protocols.ss7.sccp.impl.parameter.NoGlobalTitle; import org.mobicents.protocols.ss7.sccp.impl.parameter.SccpAddressImpl; import org.mobicents.protocols.ss7.sccp.parameter.SccpAddress; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.StringReader; import java.util.Arrays; import java.util.HashMap; import java.util.Map; /** * <p> * The default implementation for the SCCP router. * </p> * * <p> * The SCCP router allows to add/remove/list routing rules and implements persistence for the routing rules. * </p> * <p> * RouterImpl when {@link #start() started} looks for file <tt>sccprouter.xml</tt> containing serialized information of * underlying {@link RuleImpl}. Set the directory path by calling {@link #setPersistDir(String)} to direct RouterImpl to look at * specified directory for underlying serialized file. * </p> * <p> * If directory path is not set, RouterImpl searches for system property <tt>sccprouter.persist.dir</tt> to get the path for * directory * </p> * * <p> * Even if <tt>sccprouter.persist.dir</tt> system property is not set, RouterImpl will look at property <tt>user.dir</tt> * </p> * * <p> * Implementation of SCCP routing mechanism makes routing decisions based on rules. Each rule consists of three elements: * <ul> * <li> * <p> * The <i>pattern</i> determines pattern to which destination address is compared. It has complex structure which looks as * follows: * <ul> * <li> * <p> * <i>translation type</i> (tt) integer numer which is used in a network to indicate the preferred method of global title * analysis * </p> * </li> * <li> * <p> * <i>numbering plan</i> (np) integer value which inidcates which numbering plan will be used for the global title. Its value * aids the routing system in determining the correct network system to route message to. * </p> * </li> * <li> * <p> * <i>nature of address</i> (noa) integer value which indicates address type., Specifically it indicates the scope of the * address value, such as whether it is an international number (i.e. including the country code), a "national" or domestic * number (i.e. without country code), and other formats such as "local" format. * </p> * </li> * <li> * <p> * <i>digits</i> (digits) actual address * </p> * </li> * <li> * <p> * <i>sub-system number</i> (ssn) identifies application in SCCP routing network. * </p> * </li> * </ul> * </p> * </li> * <li> * <p> * The <i>translation</i> determines target for messages which destination address matches pattern. It has exactly the same * structure as pattern . * </p> * </li> * <li> * <p> * The <i>mtpinfo</i> determines mtp layer information. If translation does not indicate local address, this information is used * to send message through MTP layer. It has following structure: * <ul> * <li> * <p> * <i>name</i> (name) identifying one of link sets used by SCCP * </p> * </li> * <li> * <p> * <i>originating point code</i> (opc) local point code used as originating MTP address * </p> * </li> * <li> * <p> * <i>adjacent point code</i> (apc) remote point code used as destination MTP address * </p> * </li> * <li> * <p> * <i>signaling link selection</i> (sls) indentifies link in set * </p> * </li> * </ul> * </p> * </li> * </ul> * </p> * <p> * While the <i>pattern</i> is mandatory, <i>translation</i> and <i>mtpinfo</i> is optional. Following combinations are possible * <ul> * <li> * <p> * <i>pattern</i> and <i>translation</i> : specifies local routing * </p> * </li> * <li> * <p> * <i>pattern</i> and <i>mtpinfo</i> : specifies remote routing using specified mtp routing info and no translation needed * </p> * </li> * <li> * <p> * <i>pattern</i>, <i>translation</i> and <i>mtpinfo</i> specifies remote routing using specified mtp routing info after * applying specified translation * </p> * </li> * </ul> * </p> * * @author amit bhayani * @author kulikov */ public class RouterImpl implements Router { private static final Logger logger = Logger.getLogger(RouterImpl.class); private static final String SCCP_ROUTER_PERSIST_DIR_KEY = "sccprouter.persist.dir"; private static final String USER_DIR_KEY = "user.dir"; private static final String PERSIST_FILE_NAME = "sccprouter2.xml"; private static final String RULE = "rule"; private static final String ROUTING_ADDRESS = "routingAddress"; // private static final String BACKUP_ADDRESS = "backupAddress"; private static final String LONG_MESSAGE_RULE = "longMessageRule"; private static final String MTP3_SERVICE_ACCESS_POINT = "sap"; private final TextBuilder persistFile = TextBuilder.newInstance(); private static final SccpRouterXMLBinding binding = new SccpRouterXMLBinding(); private static final String TAB_INDENT = "\t"; private static final String CLASS_ATTRIBUTE = "type"; private String persistDir = null; private final RuleComparator ruleComparator = new RuleComparator(); // rule list private RuleMap<Integer, Rule> rulesMap = new RuleMap<Integer, Rule>(); private SccpAddressMap<Integer, SccpAddressImpl> routingAddresses = new SccpAddressMap<Integer, SccpAddressImpl>(); // private SccpAddressMap<Integer, SccpAddress> backupAddresses = new SccpAddressMap<Integer, SccpAddress>(); private LongMessageRuleMap<Integer, LongMessageRule> longMessageRules = new LongMessageRuleMap<Integer, LongMessageRule>(); private Mtp3ServiceAccessPointMap<Integer, Mtp3ServiceAccessPoint> saps = new Mtp3ServiceAccessPointMap<Integer, Mtp3ServiceAccessPoint>(); private final String name; private final SccpStack sccpStack; public RouterImpl(String name, SccpStack sccpStack) { this.name = name; this.sccpStack = sccpStack; binding.setAlias(RuleImpl.class, RULE); binding.setClassAttribute(CLASS_ATTRIBUTE); binding.setAlias(Mtp3DestinationMap.class, "mtp3DestinationMap"); binding.setAlias(GlobalTitle0001Impl.class, "GT0001"); binding.setAlias(GlobalTitle0010Impl.class, "GT0010"); binding.setAlias(GlobalTitle0011Impl.class, "GT0011"); binding.setAlias(GlobalTitle0100Impl.class, "GT0100"); binding.setAlias(NoGlobalTitle.class, "NoGlobalTitle"); } public String getName() { return name; } public String getPersistDir() { return persistDir; } public void setPersistDir(String persistDir) { this.persistDir = persistDir; } public void start() { this.persistFile.clear(); if (persistDir != null) { this.persistFile.append(persistDir).append(File.separator).append(this.name).append("_").append(PERSIST_FILE_NAME); } else { persistFile.append(System.getProperty(SCCP_ROUTER_PERSIST_DIR_KEY, System.getProperty(USER_DIR_KEY))) .append(File.separator).append(this.name).append("_").append(PERSIST_FILE_NAME); } logger.info(String.format("SCCP Router configuration file path %s", persistFile.toString())); this.load(); logger.info("Started SCCP Router"); } public void stop() { this.store(); } /** * Looks up rule for translation. * * @param calledParty called party address * @return the rule with match to the called party address */ public Rule findRule(SccpAddress calledParty, SccpAddress callingParty, boolean isMtpOriginated, int msgNetworkId) { for (FastMap.Entry<Integer, Rule> e = this.rulesMap.head(), end = this.rulesMap.tail(); (e = e.getNext()) != end;) { Rule rule = e.getValue(); if (rule.matches(calledParty, callingParty, isMtpOriginated, msgNetworkId)) { return rule; } } return null; } public LongMessageRule findLongMessageRule(int dpc) { for (FastMap.Entry<Integer, LongMessageRule> e = this.longMessageRules.head(), end = this.longMessageRules.tail(); (e = e .getNext()) != end;) { LongMessageRule rule = e.getValue(); if (rule.matches(dpc)) { return rule; } } return null; } public Mtp3ServiceAccessPoint findMtp3ServiceAccessPoint(int dpc, int sls) { for (FastMap.Entry<Integer, Mtp3ServiceAccessPoint> e = this.saps.head(), end = this.saps.tail(); (e = e.getNext()) != end;) { Mtp3ServiceAccessPoint sap = e.getValue(); if (sap.matches(dpc, sls)) { return sap; } } return null; } public Mtp3ServiceAccessPoint findMtp3ServiceAccessPoint(int dpc, int sls, int networkId) { for (FastMap.Entry<Integer, Mtp3ServiceAccessPoint> e = this.saps.head(), end = this.saps.tail(); (e = e.getNext()) != end;) { Mtp3ServiceAccessPoint sap = e.getValue(); if (sap.matches(dpc, sls)) { if (sap.getNetworkId() == networkId) { return sap; } } } return null; } public Mtp3ServiceAccessPoint findMtp3ServiceAccessPointForIncMes(int localPC, int remotePC) { for (FastMap.Entry<Integer, Mtp3ServiceAccessPoint> e = this.saps.head(), end = this.saps.tail(); (e = e.getNext()) != end;) { Mtp3ServiceAccessPoint sap = e.getValue(); if (sap.getOpc() == localPC && sap.matches(remotePC)) { return sap; } } return null; } public Rule getRule(int id) { return this.rulesMap.get(id); } public SccpAddress getRoutingAddress(int id) { return this.routingAddresses.get(id); } // public SccpAddress getBackupAddress(int id) { // return this.backupAddresses.get(id); // } public LongMessageRule getLongMessageRule(int id) { return this.longMessageRules.get(id); } public Mtp3ServiceAccessPoint getMtp3ServiceAccessPoint(int id) { return this.saps.get(id); } public boolean spcIsLocal(int spc) { for (FastMap.Entry<Integer, Mtp3ServiceAccessPoint> e = this.saps.head(), end = this.saps.tail(); (e = e.getNext()) != end;) { Mtp3ServiceAccessPoint sap = e.getValue(); if (sap.getOpc() == spc) { return true; } } return false; } public Map<Integer, Rule> getRules() { Map<Integer, Rule> rulesMapTmp = new HashMap<Integer, Rule>(); rulesMapTmp.putAll(rulesMap); return rulesMapTmp; } public Map<Integer, SccpAddress> getRoutingAddresses() { Map<Integer, SccpAddress> routingAddressesTmp = new HashMap<Integer, SccpAddress>(); routingAddressesTmp.putAll(routingAddresses); return routingAddressesTmp; } // public Map<Integer, SccpAddress> getBackupAddresses() { // return backupAddresses.unmodifiable(); // } public Map<Integer, LongMessageRule> getLongMessageRules() { Map<Integer, LongMessageRule> longMessageRulesTmp = new HashMap<Integer, LongMessageRule>(); longMessageRulesTmp.putAll(longMessageRules); return longMessageRulesTmp; } public Map<Integer, Mtp3ServiceAccessPoint> getMtp3ServiceAccessPoints() { Map<Integer, Mtp3ServiceAccessPoint> sapsTmp = new HashMap<Integer, Mtp3ServiceAccessPoint>(); sapsTmp.putAll(saps); return sapsTmp; } public void addRule(int id, RuleType ruleType, LoadSharingAlgorithm algo, OriginationType originationType, SccpAddress pattern, String mask, int pAddressId, int sAddressId, Integer newCallingPartyAddressAddressId, int networkId, SccpAddress patternCallingAddress) throws Exception { Rule ruleTmp = this.getRule(id); if (ruleTmp != null) { throw new Exception(SccpOAMMessage.RULE_ALREADY_EXIST); } int maskumberOfSecs = (mask.split("/").length - 1); int patternNumberOfSecs = (pattern.getGlobalTitle().getDigits().split("/").length - 1); if (maskumberOfSecs != patternNumberOfSecs) { throw new Exception(SccpOAMMessage.SEC_MISMATCH_PATTERN); } SccpAddress pAddress = this.getRoutingAddress(pAddressId); if (pAddress == null) { throw new Exception(String.format(SccpOAMMessage.NO_PRIMARY_ADDRESS, pAddressId)); } int primAddNumberOfSecs = (pAddress.getGlobalTitle().getDigits().split("/").length - 1); if (maskumberOfSecs != primAddNumberOfSecs) { throw new Exception(SccpOAMMessage.SEC_MISMATCH_PRIMADDRESS); } if (sAddressId != -1) { SccpAddress sAddress = this.getRoutingAddress(sAddressId); if (sAddress == null) { throw new Exception(String.format(SccpOAMMessage.NO_BACKUP_ADDRESS, sAddressId)); } int secAddNumberOfSecs = (sAddress.getGlobalTitle().getDigits().split("/").length - 1); if (maskumberOfSecs != secAddNumberOfSecs) { throw new Exception(SccpOAMMessage.SEC_MISMATCH_SECADDRESS); } } if (sAddressId == -1 && ruleType != RuleType.SOLITARY) { throw new Exception(SccpOAMMessage.RULETYPE_NOT_SOLI_SEC_ADD_MANDATORY); } synchronized (this) { RuleImpl rule = new RuleImpl(ruleType, algo, originationType, pattern, mask, networkId, patternCallingAddress); rule.setPrimaryAddressId(pAddressId); rule.setSecondaryAddressId(sAddressId); rule.setNewCallingPartyAddressId(newCallingPartyAddressAddressId); rule.setRuleId(id); RuleImpl[] rulesArray = new RuleImpl[(this.rulesMap.size() + 1)]; int count = 0; for (FastMap.Entry<Integer, Rule> e = this.rulesMap.head(), end = this.rulesMap.tail(); (e = e.getNext()) != end;) { Integer ruleId = e.getKey(); RuleImpl ruleTemp1 = (RuleImpl) e.getValue(); ruleTemp1.setRuleId(ruleId); rulesArray[count++] = ruleTemp1; } // add latest rule rulesArray[count++] = rule; // Sort Arrays.sort(rulesArray, ruleComparator); RuleMap<Integer, Rule> newRule = new RuleMap<Integer, Rule>(); for (int i = 0; i < rulesArray.length; i++) { RuleImpl ruleTemp = rulesArray[i]; newRule.put(ruleTemp.getRuleId(), ruleTemp); } this.rulesMap = newRule; this.store(); } } public void modifyRule(int id, RuleType ruleType, LoadSharingAlgorithm algo, OriginationType originationType, SccpAddress pattern, String mask, int pAddressId, int sAddressId, Integer newCallingPartyAddressAddressId, int networkId, SccpAddress patternCallingAddress) throws Exception { synchronized (this) { Rule ruleTmp = this.getRule(id); if (ruleTmp == null) { throw new Exception(String.format(SccpOAMMessage.RULE_DOESNT_EXIST, name)); } int maskumberOfSecs = (mask.split("/").length - 1); int patternNumberOfSecs = (pattern.getGlobalTitle().getDigits().split("/").length - 1); if (maskumberOfSecs != patternNumberOfSecs) { throw new Exception(SccpOAMMessage.SEC_MISMATCH_PATTERN); } SccpAddress pAddress = this.getRoutingAddress(pAddressId); if (pAddress == null) { throw new Exception(String.format(SccpOAMMessage.NO_PRIMARY_ADDRESS, pAddressId)); } int primAddNumberOfSecs = (pattern.getGlobalTitle().getDigits().split("/").length - 1); if (maskumberOfSecs != primAddNumberOfSecs) { throw new Exception(SccpOAMMessage.SEC_MISMATCH_PRIMADDRESS); } if (sAddressId != -1) { SccpAddress sAddress = this.getRoutingAddress(sAddressId); if (sAddress == null) { throw new Exception(String.format(SccpOAMMessage.NO_BACKUP_ADDRESS, sAddressId)); } int secAddNumberOfSecs = (pattern.getGlobalTitle().getDigits().split("/").length - 1); if (maskumberOfSecs != secAddNumberOfSecs) { throw new Exception(SccpOAMMessage.SEC_MISMATCH_SECADDRESS); } } if (sAddressId == -1 && ruleType != RuleType.SOLITARY) { throw new Exception(SccpOAMMessage.RULETYPE_NOT_SOLI_SEC_ADD_MANDATORY); } RuleImpl rule = new RuleImpl(ruleType, algo, originationType, pattern, mask, networkId, patternCallingAddress); rule.setPrimaryAddressId(pAddressId); rule.setSecondaryAddressId(sAddressId); rule.setNewCallingPartyAddressId(newCallingPartyAddressAddressId); rule.setRuleId(id); RuleImpl[] rulesArray = new RuleImpl[(this.rulesMap.size())]; int count = 0; // Remove the old rule so that it doesn't overwrite the new modifications this.removeRule( id ); for (FastMap.Entry<Integer, Rule> e = this.rulesMap.head(), end = this.rulesMap.tail(); (e = e.getNext()) != end;) { Integer ruleId = e.getKey(); RuleImpl ruleTemp1 = (RuleImpl) e.getValue(); ruleTemp1.setRuleId(ruleId); rulesArray[count++] = ruleTemp1; } // add latest rule rulesArray[count++] = rule; // Sort Arrays.sort(rulesArray, ruleComparator); RuleMap<Integer, Rule> newRule = new RuleMap<Integer, Rule>(); for (int i = 0; i < rulesArray.length; i++) { RuleImpl ruleTemp = rulesArray[i]; newRule.put(ruleTemp.getRuleId(), ruleTemp); } this.rulesMap = newRule; this.store(); } } public void removeRule(int id) throws Exception { if (this.getRule(id) == null) { throw new Exception(String.format(SccpOAMMessage.RULE_DOESNT_EXIST, name)); } synchronized (this) { RuleMap<Integer, Rule> newRule = new RuleMap<Integer, Rule>(); newRule.putAll(this.rulesMap); newRule.remove(id); this.rulesMap = newRule; this.store(); } } public void addRoutingAddress(int primAddressId, SccpAddress primaryAddress) throws Exception { if (this.getRoutingAddress(primAddressId) != null) { throw new Exception(SccpOAMMessage.ADDRESS_ALREADY_EXIST); } synchronized (this) { SccpAddressMap<Integer, SccpAddressImpl> newPrimaryAddress = new SccpAddressMap<Integer, SccpAddressImpl>(); newPrimaryAddress.putAll(this.routingAddresses); newPrimaryAddress.put(primAddressId, (SccpAddressImpl) primaryAddress); this.routingAddresses = newPrimaryAddress; this.store(); } } public void modifyRoutingAddress(int primAddressId, SccpAddress primaryAddress) throws Exception { if (this.getRoutingAddress(primAddressId) == null) { throw new Exception(String.format(SccpOAMMessage.ADDRESS_DOESNT_EXIST, name)); } synchronized (this) { SccpAddressMap<Integer, SccpAddressImpl> newPrimaryAddress = new SccpAddressMap<Integer, SccpAddressImpl>(); newPrimaryAddress.putAll(this.routingAddresses); newPrimaryAddress.put(primAddressId, (SccpAddressImpl) primaryAddress); this.routingAddresses = newPrimaryAddress; this.store(); } } public void removeRoutingAddress(int id) throws Exception { if (this.getRoutingAddress(id) == null) { throw new Exception(String.format(SccpOAMMessage.ADDRESS_DOESNT_EXIST, name)); } synchronized (this) { SccpAddressMap<Integer, SccpAddressImpl> newPrimaryAddress = new SccpAddressMap<Integer, SccpAddressImpl>(); newPrimaryAddress.putAll(this.routingAddresses); newPrimaryAddress.remove(id); this.routingAddresses = newPrimaryAddress; this.store(); } } // public void addBackupAddress(int id, SccpAddress backupAddress) throws Exception { // // if (this.getBackupAddress(id) != null) { // throw new Exception(SccpOAMMessage.ADDRESS_ALREADY_EXIST); // } // // synchronized (this) { // SccpAddressMap<Integer, SccpAddress> newBackupAddress = new SccpAddressMap<Integer, SccpAddress>(); // newBackupAddress.putAll(this.backupAddresses); // newBackupAddress.put(id, backupAddress); // this.backupAddresses = newBackupAddress; // this.store(); // } // } // // public void modifyBackupAddress(int id, SccpAddress backupAddress) throws Exception { // if (this.getBackupAddress(id) == null) { // throw new Exception(SccpOAMMessage.ADDRESS_DOESNT_EXIST); // } // // synchronized (this) { // SccpAddressMap<Integer, SccpAddress> newBackupAddress = new SccpAddressMap<Integer, SccpAddress>(); // newBackupAddress.putAll(this.backupAddresses); // newBackupAddress.put(id, backupAddress); // this.backupAddresses = newBackupAddress; // this.store(); // } // } // // public void removeBackupAddress(int id) throws Exception { // // if (this.getBackupAddress(id) == null) { // throw new Exception(SccpOAMMessage.ADDRESS_DOESNT_EXIST); // } // // synchronized (this) { // SccpAddressMap<Integer, SccpAddress> newBackupAddress = new SccpAddressMap<Integer, SccpAddress>(); // newBackupAddress.putAll(this.backupAddresses); // newBackupAddress.remove(id); // this.backupAddresses = newBackupAddress; // this.store(); // } // } public void addLongMessageRule(int id, int firstSpc, int lastSpc, LongMessageRuleType ruleType) throws Exception { if (this.getLongMessageRule(id) != null) { throw new Exception(SccpOAMMessage.LMR_ALREADY_EXIST); } LongMessageRuleImpl longMessageRule = new LongMessageRuleImpl(firstSpc, lastSpc, ruleType); synchronized (this) { LongMessageRuleMap<Integer, LongMessageRule> newLongMessageRule = new LongMessageRuleMap<Integer, LongMessageRule>(); newLongMessageRule.putAll(this.longMessageRules); newLongMessageRule.put(id, longMessageRule); this.longMessageRules = newLongMessageRule; this.store(); } } public void modifyLongMessageRule(int id, int firstSpc, int lastSpc, LongMessageRuleType ruleType) throws Exception { if (this.getLongMessageRule(id) == null) { throw new Exception(String.format(SccpOAMMessage.LMR_DOESNT_EXIST, name)); } LongMessageRuleImpl longMessageRule = new LongMessageRuleImpl(firstSpc, lastSpc, ruleType); synchronized (this) { LongMessageRuleMap<Integer, LongMessageRule> newLongMessageRule = new LongMessageRuleMap<Integer, LongMessageRule>(); newLongMessageRule.putAll(this.longMessageRules); newLongMessageRule.put(id, longMessageRule); this.longMessageRules = newLongMessageRule; this.store(); } } public void removeLongMessageRule(int id) throws Exception { if (this.getLongMessageRule(id) == null) { throw new Exception(String.format(SccpOAMMessage.LMR_DOESNT_EXIST, name)); } synchronized (this) { LongMessageRuleMap<Integer, LongMessageRule> newLongMessageRule = new LongMessageRuleMap<Integer, LongMessageRule>(); newLongMessageRule.putAll(this.longMessageRules); newLongMessageRule.remove(id); this.longMessageRules = newLongMessageRule; this.store(); } } public void addMtp3Destination(int sapId, int destId, int firstDpc, int lastDpc, int firstSls, int lastSls, int slsMask) throws Exception { Mtp3ServiceAccessPoint sap = this.getMtp3ServiceAccessPoint(sapId); if (sap == null) { throw new Exception(String.format(SccpOAMMessage.SAP_DOESNT_EXIST, name)); } // TODO Synchronize?? sap.addMtp3Destination(destId, firstDpc, lastDpc, firstSls, lastSls, slsMask); this.store(); } public void modifyMtp3Destination(int sapId, int destId, int firstDpc, int lastDpc, int firstSls, int lastSls, int slsMask) throws Exception { Mtp3ServiceAccessPoint sap = this.getMtp3ServiceAccessPoint(sapId); if (sap == null) { throw new Exception(String.format(SccpOAMMessage.SAP_DOESNT_EXIST, name)); } // TODO Synchronize?? sap.modifyMtp3Destination(destId, firstDpc, lastDpc, firstSls, lastSls, slsMask); this.store(); } public void removeMtp3Destination(int sapId, int destId) throws Exception { Mtp3ServiceAccessPoint sap = this.getMtp3ServiceAccessPoint(sapId); if (sap == null) { throw new Exception(String.format(SccpOAMMessage.SAP_DOESNT_EXIST, name)); } sap.removeMtp3Destination(destId); this.store(); } public void addMtp3ServiceAccessPoint(int id, int mtp3Id, int opc, int ni, int networkId) throws Exception { if (this.getMtp3ServiceAccessPoint(id) != null) { throw new Exception(SccpOAMMessage.SAP_ALREADY_EXIST); } if (this.sccpStack.getMtp3UserPart(mtp3Id) == null) { throw new Exception(SccpOAMMessage.MUP_DOESNT_EXIST); } Mtp3ServiceAccessPointImpl sap = new Mtp3ServiceAccessPointImpl(mtp3Id, opc, ni, this.name, networkId); synchronized (this) { Mtp3ServiceAccessPointMap<Integer, Mtp3ServiceAccessPoint> newSap = new Mtp3ServiceAccessPointMap<Integer, Mtp3ServiceAccessPoint>(); newSap.putAll(this.saps); newSap.put(id, sap); this.saps = newSap; this.store(); } } public void modifyMtp3ServiceAccessPoint(int id, int mtp3Id, int opc, int ni, int networkId) throws Exception { if (this.getMtp3ServiceAccessPoint(id) == null) { throw new Exception(String.format(SccpOAMMessage.SAP_DOESNT_EXIST, name)); } if (this.sccpStack.getMtp3UserPart(mtp3Id) == null) { throw new Exception(SccpOAMMessage.MUP_DOESNT_EXIST); } Mtp3ServiceAccessPointImpl sap = new Mtp3ServiceAccessPointImpl(mtp3Id, opc, ni, this.name, networkId); synchronized (this) { Mtp3ServiceAccessPointMap<Integer, Mtp3ServiceAccessPoint> newSap = new Mtp3ServiceAccessPointMap<Integer, Mtp3ServiceAccessPoint>(); newSap.putAll(this.saps); newSap.put(id, sap); this.saps = newSap; this.store(); } } public void removeMtp3ServiceAccessPoint(int id) throws Exception { if (this.getMtp3ServiceAccessPoint(id) == null) { throw new Exception(String.format(SccpOAMMessage.SAP_DOESNT_EXIST, name)); } synchronized (this) { Mtp3ServiceAccessPointMap<Integer, Mtp3ServiceAccessPoint> newSap = new Mtp3ServiceAccessPointMap<Integer, Mtp3ServiceAccessPoint>(); newSap.putAll(this.saps); newSap.remove(id); this.saps = newSap; this.store(); } } public void removeAllResourses() { synchronized (this) { // if (this.rulesMap.size() == 0 && this.routingAddresses.size() == 0 && this.backupAddresses.size() == 0 // && this.longMessageRules.size() == 0 && this.saps.size() == 0) if (this.rulesMap.size() == 0 && this.routingAddresses.size() == 0 && this.longMessageRules.size() == 0 && this.saps.size() == 0) // no resources allocated - nothing to do return; rulesMap = new RuleMap<Integer, Rule>(); routingAddresses = new SccpAddressMap<Integer, SccpAddressImpl>(); // backupAddresses = new SccpAddressMap<Integer, SccpAddress>(); longMessageRules = new LongMessageRuleMap<Integer, LongMessageRule>(); saps = new Mtp3ServiceAccessPointMap<Integer, Mtp3ServiceAccessPoint>(); // We store the cleared state this.store(); } } public FastMap<Integer, NetworkIdState> getNetworkIdStateList() { return getNetworkIdList(-1); } public FastMap<Integer, NetworkIdState> getNetworkIdList(int affectedPc) { FastMap<Integer, NetworkIdState> res = new FastMap<Integer, NetworkIdState>(); for (FastMap.Entry<Integer, Rule> e = this.rulesMap.head(), end = rulesMap.tail(); (e = e.getNext()) != end;) { Rule rule = e.getValue(); NetworkIdStateImpl networkIdState = getRoutingAddressStatusForRoutingRule(rule, affectedPc); if (networkIdState != null) { NetworkIdState prevNetworkIdState = res.get(rule.getNetworkId()); if (prevNetworkIdState != null) { if (prevNetworkIdState.isAvailavle()) { if (networkIdState.isAvailavle()) { if (prevNetworkIdState.getCongLevel() < networkIdState.getCongLevel()) { res.put(rule.getNetworkId(), networkIdState); } } else { res.put(rule.getNetworkId(), networkIdState); } } } else { res.put(rule.getNetworkId(), networkIdState); } } } return res; } private NetworkIdStateImpl getRoutingAddressStatusForRoutingRule(Rule rule, int affectedPc) { SccpAddress translationAddressPri = getRoutingAddress(rule.getPrimaryAddressId()); NetworkIdStateImpl rspStatusPri = getRoutingAddressStatusForRoutingAddress(translationAddressPri, affectedPc); if (rule.getRuleType() == RuleType.DOMINANT || rule.getRuleType() == RuleType.LOADSHARED) { SccpAddress translationAddressSec = getRoutingAddress(rule.getSecondaryAddressId()); NetworkIdStateImpl rspStatusSec = getRoutingAddressStatusForRoutingAddress(translationAddressSec, affectedPc); if (rspStatusPri.isAffectedByPc() || rspStatusSec.isAffectedByPc()) { if (rule.getRuleType() == RuleType.DOMINANT) { if (rspStatusPri.isAvailavle()) return rspStatusPri; return rspStatusSec; } if (rule.getRuleType() == RuleType.LOADSHARED) { if (rspStatusPri.isAvailavle()) { if (rspStatusSec.isAvailavle()) { if (rspStatusPri.getCongLevel() >= rspStatusSec.getCongLevel()) return rspStatusPri; else return rspStatusSec; } else { return rspStatusPri; } } else { if (rspStatusSec.isAvailavle()) { return rspStatusSec; } else { // both are prohibited - we can select any response return rspStatusPri; } } } } else { return null; } } else { if (rspStatusPri.isAffectedByPc()) return rspStatusPri; else return null; } return null; } private NetworkIdStateImpl getRoutingAddressStatusForRoutingAddress(SccpAddress routingAddress, int affectedPc) { if (routingAddress != null && routingAddress.getAddressIndicator().isPCPresent()) { boolean affectedByPc = true; if ((affectedPc >= 0 && routingAddress.getSignalingPointCode() != affectedPc)) affectedByPc = false; boolean spcIsLocal = spcIsLocal(routingAddress.getSignalingPointCode()); if (spcIsLocal) { return new NetworkIdStateImpl(affectedByPc); } RemoteSignalingPointCode remoteSpc = sccpStack.getSccpResource().getRemoteSpcByPC( routingAddress.getSignalingPointCode()); if (remoteSpc == null) { return new NetworkIdStateImpl(affectedByPc); } if (remoteSpc.isRemoteSpcProhibited()) { return new NetworkIdStateImpl(false, affectedByPc); } int congLevel = SccpCongestionControl.generateSccpUserCongLevel(remoteSpc.getCurrentRestrictionLevel()); if (congLevel > 0) { return new NetworkIdStateImpl(congLevel, affectedByPc); } return new NetworkIdStateImpl(affectedByPc); } // we return here value that this affectedPc does not affect this rule return new NetworkIdStateImpl(false); } /** * Persist */ public void store() { // TODO : Should we keep reference to Objects rather than recreating // everytime? try { XMLObjectWriter writer = XMLObjectWriter.newInstance(new FileOutputStream(persistFile.toString())); writer.setBinding(binding); // Enables cross-references. // writer.setReferenceResolver(new XMLReferenceResolver()); writer.setIndentation(TAB_INDENT); writer.write(rulesMap, RULE, RuleMap.class); writer.write(routingAddresses, ROUTING_ADDRESS, SccpAddressMap.class); // writer.write(backupAddresses, BACKUP_ADDRESS, SccpAddressMap.class); writer.write(longMessageRules, LONG_MESSAGE_RULE, LongMessageRuleMap.class); writer.write(saps, MTP3_SERVICE_ACCESS_POINT, Mtp3ServiceAccessPointMap.class); writer.close(); } catch (Exception e) { logger.error("Error while persisting the Rule state in file", e); } } /** * Load and create LinkSets and Link from persisted file * * @throws Exception */ private void load() { try { File f = new File(persistFile.toString()); if (f.exists()) { // we have V3 config loadVer3(persistFile.toString()); } else { String s1 = persistFile.toString().replace("2.xml", ".xml"); f = new File(s1); if (f.exists()) { if (!loadVer1(s1)) { loadVer2(s1); } } this.store(); f.delete(); } } catch (XMLStreamException ex) { ex.printStackTrace(); logger.error(String.format("Failed to load the SS7 configuration file. \n%s", ex.getMessage())); } catch (FileNotFoundException e) { logger.warn(String.format("Failed to load the SS7 configuration file. \n%s", e.getMessage())); } catch (IOException e) { logger.error(String.format("Failed to load the SS7 configuration file. \n%s", e.getMessage())); } } private void moveBackupToRoutingAddress(SccpAddressMap<Integer, SccpAddress> backupAddresses) { FastMap<Integer, Integer> lstChange = new FastMap<Integer, Integer>(); for (Integer bId : backupAddresses.keySet()) { SccpAddress addr = backupAddresses.get(bId); int i1 = bId + 100; while (true) { if (routingAddresses.get(i1) == null) break; i1++; } routingAddresses.putEntry(i1, (SccpAddressImpl) addr); lstChange.putEntry(bId, i1); } for (Rule rule : rulesMap.values()) { Integer newVal = lstChange.get(rule.getSecondaryAddressId()); if (newVal != null) { ((RuleImpl) rule).setSecondaryAddressId(newVal); } } } private boolean loadVer1(String fn) throws XMLStreamException, IOException { BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(fn))); StringBuilder sb = new StringBuilder(); while (true) { String s1 = br.readLine(); if (s1 == null) break; sb.append(s1); sb.append("\n"); } br.close(); String s2 = sb.toString(); s2 = s2.replace("type=\"org.mobicents.protocols.ss7.sccp.parameter.NoGlobalTitle\"", "type=\"NoGlobalTitle\""); s2 = s2.replace("type=\"rule\"", ""); s2 = s2.replace("pattern type=\"org.mobicents.protocols.ss7.sccp.parameter.SccpAddress\"", "patternSccpAddress"); s2 = s2.replace("ai type=\"org.mobicents.protocols.ss7.indicator.AddressIndicator\" ai=", "ai value="); s2 = s2.replace("gt type=\"org.mobicents.protocols.ss7.sccp.parameter.", "gt type=\""); s2 = s2.replace("Key type=\"java.lang.Integer\"", "id"); s2 = s2.replace("Value", "value"); s2 = s2.replace("/pattern", "/patternSccpAddress"); s2 = s2.replace("value type=\"org.mobicents.protocols.ss7.sccp.parameter.SccpAddress\"", "sccpAddress"); s2 = s2.replace("</value>\r\n</primaryAddress>", "</sccpAddress>\r\n</primaryAddress>"); s2 = s2.replace("</value>\n</primaryAddress>", "</sccpAddress>\n</primaryAddress>"); s2 = s2.replace("</value>\r\n</backupAddress>", "</sccpAddress>\r\n</backupAddress>"); s2 = s2.replace("</value>\n</backupAddress>", "</sccpAddress>\n</backupAddress>"); s2 = s2.replace("type=\"org.mobicents.protocols.ss7.sccp.parameter.", "type=\""); s2 = s2.replace("type=\"org.mobicents.protocols.ss7.sccp.impl.router.Mtp3ServiceAccessPoint\"", ""); s2 = s2.replace("javolution.util.FastMap", "mtp3DestinationMap"); s2 = s2.replace("type=\"org.mobicents.protocols.ss7.sccp.impl.router.Mtp3Destination\"", ""); // s2 = s2.replace("", ""); StringReader sr = new StringReader(s2); XMLObjectReader reader = XMLObjectReader.newInstance(sr); reader.setBinding(binding); // String REMOTE_SSN_V1 = "remoteSsn"; // String REMOTE_SPC_V1 = "remoteSpc"; // String CONCERNED_SPC_V1 = "concernedSpc"; XMLBinding binding2 = new XMLBinding(); binding2.setClassAttribute(CLASS_ATTRIBUTE); String BACKUP_ADDRESS_V2 = "backupAddress"; String ROUTING_ADDRESS_V2 = "primaryAddress"; try { rulesMap = reader.read(RULE, RuleMap.class); } catch (XMLStreamException e) { return false; } routingAddresses = reader.read(ROUTING_ADDRESS_V2, SccpAddressMap.class); SccpAddressMap<Integer, SccpAddress> backupAddresses = reader.read(BACKUP_ADDRESS_V2, SccpAddressMap.class); longMessageRules = reader.read(LONG_MESSAGE_RULE, LongMessageRuleMap.class); saps = reader.read(MTP3_SERVICE_ACCESS_POINT, Mtp3ServiceAccessPointMap.class); for (FastMap.Entry<Integer, Mtp3ServiceAccessPoint> e = this.saps.head(), end = this.saps.tail(); (e = e.getNext()) != end;) { Mtp3ServiceAccessPoint sap = e.getValue(); ((Mtp3ServiceAccessPointImpl)sap).setStackName(name); } reader.close(); moveBackupToRoutingAddress(backupAddresses); return true; } private void loadVer2(String fn) throws XMLStreamException, IOException { BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(fn))); StringBuilder sb = new StringBuilder(); while (true) { String s1 = br.readLine(); if (s1 == null) break; sb.append(s1); sb.append("\n"); } br.close(); String s2 = sb.toString(); s2 = s2.replace("type=\"org.mobicents.protocols.ss7.sccp.parameter.NoGlobalTitle\"", "type=\"NoGlobalTitle\""); StringReader sr = new StringReader(s2); XMLObjectReader reader = XMLObjectReader.newInstance(sr); String ROUTING_ADDRESS_V2 = "primaryAddress"; String BACKUP_ADDRESS_V2 = "backupAddress"; reader.setBinding(binding); rulesMap = reader.read(RULE, RuleMap.class); routingAddresses = reader.read(ROUTING_ADDRESS_V2, SccpAddressMap.class); SccpAddressMap<Integer, SccpAddress> backupAddresses = reader.read(BACKUP_ADDRESS_V2, SccpAddressMap.class); longMessageRules = reader.read(LONG_MESSAGE_RULE, LongMessageRuleMap.class); saps = reader.read(MTP3_SERVICE_ACCESS_POINT, Mtp3ServiceAccessPointMap.class); for (FastMap.Entry<Integer, Mtp3ServiceAccessPoint> e = this.saps.head(), end = this.saps.tail(); (e = e.getNext()) != end;) { Mtp3ServiceAccessPoint sap = e.getValue(); ((Mtp3ServiceAccessPointImpl)sap).setStackName(name); } reader.close(); moveBackupToRoutingAddress(backupAddresses); } private void loadVer3(String fn) throws XMLStreamException, FileNotFoundException { XMLObjectReader reader = XMLObjectReader.newInstance(new FileInputStream(fn)); reader.setBinding(binding); rulesMap = reader.read(RULE, RuleMap.class); routingAddresses = reader.read(ROUTING_ADDRESS, SccpAddressMap.class); longMessageRules = reader.read(LONG_MESSAGE_RULE, LongMessageRuleMap.class); saps = reader.read(MTP3_SERVICE_ACCESS_POINT, Mtp3ServiceAccessPointMap.class); for (FastMap.Entry<Integer, Mtp3ServiceAccessPoint> e = this.saps.head(), end = this.saps.tail(); (e = e.getNext()) != end;) { Mtp3ServiceAccessPoint sap = e.getValue(); ((Mtp3ServiceAccessPointImpl)sap).setStackName(name); } reader.close(); } }