/protocols/ss7/mtp/mtp-impl/src/main/java/org/mobicents/protocols/ss7/mtp/Mtp3.java
Java | 679 lines | 402 code | 101 blank | 176 comment | 82 complexity | 2fb6b143bf253185381f95b3797efd42 MD5 | raw file
Possible License(s): LGPL-3.0, GPL-3.0, LGPL-2.1, GPL-2.0, CC-BY-SA-3.0, CC0-1.0, Apache-2.0, BSD-3-Clause
- /*
- * JBoss, Home of Professional Open Source
- * Copyright 2011, Red Hat, Inc. 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.mtp;
-
- import java.io.IOException;
- import java.util.ArrayList;
- import java.util.Arrays;
- import java.util.List;
-
- import javolution.util.FastList;
-
- import org.apache.log4j.Level;
- import org.apache.log4j.Logger;
- import org.mobicents.protocols.stream.api.SelectorKey;
- import org.mobicents.protocols.stream.api.SelectorProvider;
- import org.mobicents.protocols.stream.api.StreamSelector;
-
- /**
- *
- * @author kulikov
- * @author baranowb
- */
- public class Mtp3 implements Runnable {
-
- public final static int TIMEOUT_T1_SLTM = 12;
- public final static int TIMEOUT_T2_SLTM = 90;
- private final static int LINK_MANAGEMENT = 0;
- private final static int LINK_TESTING = 1;
- public final static int _SI_SERVICE_SCCP = 3;
- public final static int _SI_SERVICE_ISUP = 5;
-
- private Mtp3Listener mtp3Listener;
- /**
- * Flag indicating if we should notify upper layer
- */
- private boolean l4IsUp = false;
-
- //FIXME: MOVE THIS TO LINKSET?
- protected volatile boolean started = false;
- /** defautl value of SSI */
- public static final int DEFAULT_NI = 2;//NATIONAL, as default.
-
- private int dpc;
- private int opc;
- private int ni=DEFAULT_NI << 2; // << cause its faster for checks.
- /**
- * Local byte[], in which we forge messages.
- */
- private byte[] localFrame = new byte[279];
- private byte[][] localBuffers;
- /** List of signaling channels wrapped with MTP2*/
- private List<Mtp2> links = new ArrayList();
-
- /** Active links */
- private Linkset linkset = new Linkset();
- // ss7 has subservice as 1, q704 shows the same iirc
- //private int subservice = -1;
- //private int service;
-
-
- // //////////////////////////
- // SLTM pattern for inits //
- // //////////////////////////
- private final static byte[] SLTM_PATTERN = new byte[]{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x0F};
-
- protected String name;
- private StreamSelector selector;
-
- private MTPScheduler executor = new MTPScheduler();
-
- private static final Logger logger = Logger.getLogger(Mtp3.class);
-
- //public Mtp3Impl(String name, Mtp1 layer1) {
- public Mtp3(String name) {
- this.name = name;
- try {
- selector = SelectorProvider.getSelector("org.mobicents.ss7.hardware.dahdi.Selector");
- } catch (Exception e) {
- e.printStackTrace();
- }
- this.localBuffers = new byte[300][];
- for(int i=0;i<300;i++)
- {
- this.localBuffers[i] = new byte[i];
- }
- }
-
- /**
- * Assigns originated point code
- *
- * @param opc the originated point code
- */
- public void setOpc(int opc) {
- this.opc = opc;
- }
-
- /**
- * Assigns destination point code.
- *
- * @param dpc destination point code in decimal format.
- */
- public void setDpc(int dpc) {
- this.dpc = dpc;
- }
-
- /**
- * @return the dpc
- */
- public int getDpc() {
- return dpc;
- }
-
- /**
- * @return the opc
- */
- public int getOpc() {
- return opc;
- }
-
-
- /**
- * Sets network indicator to be used as part of SIO( actually SSI). It Accepts 2 bit integer.
- * @param ni
- */
- public void setNetworkIndicator(int ni){
- this.ni = (0x03 & ni) << 2;
- }
-
- public int getNetworkIndicator() {
- return this.ni >> 2;
- }
-
- /** (non-Javadoc)
- * @see org.mobicents.protocols.ss7.mtp.Mtp3#addMtp3Listener(org.mobicents.protocols.ss7.mtp.Mtp3Listener)
- */
- public void addMtp3Listener(Mtp3Listener lst) {
- if (this.mtp3Listener != null) {
- throw new IllegalStateException("Listener already present.");
- }
- this.mtp3Listener = lst;
-
- }
-
- /* (non-Javadoc)
- * @see org.mobicents.protocols.ss7.mtp.Mtp3#removeMtp3Listener(org.mobicents.protocols.ss7.mtp.Mtp3Listener)
- */
- public void removeMtp3Listener(Mtp3Listener lst) {
- if (lst != this.mtp3Listener) {
- throw new IllegalArgumentException("Wrong listener passed. Its not registered in this object!");
- }
- this.mtp3Listener = null;
-
- }
-
- /* (non-Javadoc)
- * @see org.mobicents.protocols.ss7.mtp.Mtp3#setLinks(java.util.List)
- */
- public void setLinks(List<Mtp2> channels) {
- for (Mtp2 link : channels) {
- if (link != null) {
- link.mtp3 = this;
- this.links.add(link);
- }
- }
-
- }
-
- public void addLink(Mtp2 mtp2){
- mtp2.mtp3 = this;
- this.links.add(mtp2);
- }
-
- public void clearLinks(){
- this.links.clear();
- }
-
- /**
- * Starts linkset.
- *
- * @throws java.io.IOException
- */
- public void start() throws IOException {
- //starting links
- for (Mtp2 link : links) {
- link.start();
- }
- }
-
- public void stop() throws IOException {
- started = false;
- for (Mtp2 link : links) {
- //selector.unregister(link);
- link.stop();
- }
- }
-
- public void run() {
- try {
- FastList<SelectorKey> selected = selector.selectNow(StreamSelector.OP_READ, 20);
- for (FastList.Node<SelectorKey> n = selected.head(), end = selected.tail(); (n = n.getNext()) != end;) {
- ((Mtp2)((Mtp1) n.getValue().getStream()).getLink()).doRead();
- }
-
- selected = selector.selectNow(StreamSelector.OP_WRITE, 20);
- for (FastList.Node<SelectorKey> n = selected.head(), end = selected.tail(); (n = n.getNext()) != end;) {
- ((Mtp2)((Mtp1) n.getValue().getStream()).getLink()).doWrite();
- }
-
- this.executor.tick();
-
- for (Mtp2 link : links) {
- link.scheduler.tick();
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
-
- /**
- * This method is called when new MSU is detected.
- *
- * @param sio
- * service information octet.
- * @param msg
- * service information field;
- */
-
- public void onMessage(Mtp2Buffer rxFrame, Mtp2 mtp2)
- {
- // | ----------------------- TO L4 --------------------------- |
- // | --------------------- SIF ------------------------ |
- //FSN BSN LEN SIO DPC/OPC,SLS HEADING LEN
- //b1 b0 0e 01 01 80 00 00 21 70 01 02 03 04 05 06 0f CRC CRC
- int sio = rxFrame.frame[3] & 0xFF;
- int subserviceIndicator = (sio >> 4) & 0x0F;
- int serviceIndicator = sio & 0x0F;
- int ni = (subserviceIndicator & 0x0C) ; //local NI(network Indicator) form msg., 0x0C, since we store it as shifted value.
- // int dpc = (sif[0] & 0xff | ((sif[1] & 0x3f) << 8));
- // int opc = ((sif[1] & 0xC0) >> 6) | ((sif[2] & 0xff) << 2) | ((sif[3]
- // & 0x0f) << 10);
- // int sls = (sif[3] & 0xf0) >>> 4;
- int dpc = dpc(rxFrame.frame, 4); //1 - cause sif contains sio, even though its also passed as arg.
- int opc = opc(rxFrame.frame, 4);
- int sls = sls(rxFrame.frame, 4);
-
- //check SSI, Q.704 Figure 25, seems like if its bad, we discard.
- if(this.ni!=ni)
- {
- if (logger.isEnabledFor(Level.ERROR)) {
- logger.error(
- String.format("(%s) Received MSSU with bad SSI, discarding! [si=" + serviceIndicator + ",ssi=" + subserviceIndicator + ", dpc=" + dpc + ", opc=" + opc + ", sls=" + sls + "] data: ", mtp2.getName()) + Arrays.toString(rxFrame.frame));
- }
- return;
- }
-
-
- switch (serviceIndicator) {
- case LINK_MANAGEMENT:
- int h0 = rxFrame.frame[8] & 0x0f;
- int h1 = (rxFrame.frame[8] & 0xf0) >>> 4;
-
- if (logger.isDebugEnabled()) {
- logger.debug(String.format("(%s) Signalling network management", mtp2.getName()));
- }
-
- if (h0 == 0) {
- if (logger.isDebugEnabled()) {
- logger.debug(String.format("(%s) Changeover management", mtp2.getName()));
- }
- } else if (h0 == 7 && h1 == 1) {
- if (logger.isDebugEnabled()) {
- logger.debug(String.format("(%s) TRA received", mtp2.getName()));
- }
- }
- //FIX ME
- break;
- case LINK_TESTING:
- h0 = rxFrame.frame[8] & 0x0f;
- h1 = (rxFrame.frame[8] & 0xf0) >>> 4;
-
- int len = (rxFrame.frame[9] & 0xf0) >>> 4;
-
- if (h0 == 1 && h1 == 1) {
- if (logger.isDebugEnabled()) {
- logger.debug(String.format("(%s) Received SLTM", mtp2.getName()));
- }
- // receive SLTM from remote end
- // create response
-
- //change order of opc/dpc in SLTA !
- writeRoutingLabel(this.localFrame, sio, this.ni << 2, sls, opc, dpc);
- //slta[0] = (byte) sio;
- this.localFrame[5] = 0x021;
- // +1 cause we copy LEN byte also.
- System.arraycopy(rxFrame.frame, 9, this.localFrame, 6, len + 1);
-
- if (logger.isDebugEnabled()) {
- logger.debug(String.format("(%s) Responding with SLTA", mtp2.getName()));
- }
- mtp2.send( this.localFrame, len+9);
- } else if (h0 == 1 && h1 == 2) {
- // receive SLTA from remote end
- if (logger.isDebugEnabled()) {
- logger.debug(String.format("(%s) Received SLTA", mtp2.getName()));
- }
-
- //checking pattern
- if (checkPattern(rxFrame,len, SLTM_PATTERN)) {
- //test message is acknowledged
- mtp2.sltmTest.ack();
-
- //notify top layer that link is up
- if (!l4IsUp) {
- l4IsUp = true;
- linkUp(mtp2);
- }
- } else {
- if(logger.isEnabledFor(Level.WARN))
- {
- logger.warn("SLTA pattern does not match: \n"+Arrays.toString(rxFrame.frame)+"\n"+Arrays.toString(SLTM_PATTERN));
- }
- }
- } else {
- if(logger.isEnabledFor(Level.WARN))
- {
- logger.warn(String.format("(%s) Unexpected message type", mtp2.getName()));
- }
- }
- break;
- case _SI_SERVICE_SCCP:
- if (logger.isDebugEnabled()) {
- logger.debug("Received SCCP MSU");
- }
-
- if (mtp3Listener != null) {
-
- // | ----------------------- TO L4 --------------------------- |
- // | --------------------- SIF ------------------------ |
- //FSN BSN LEN SIO DPC/OPC,SLS HEADING LEN
- //b1 b0 0e 01 01 80 00 00 21 70 01 02 03 04 05 06 0f CRC CRC
- byte[] messageBuffer = fetchBuffer(rxFrame.len-5); //-5 = FSN(1) + BSN(1) + LEN(1) +2xCRC(1)
- System.arraycopy(rxFrame.frame, 3, messageBuffer, 0, rxFrame.len-5);
- //messageBuffer[0] = (byte) sio;
- try {
- mtp3Listener.receive(messageBuffer);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- break;
- case _SI_SERVICE_ISUP:
- if (logger.isDebugEnabled()) {
- logger.debug("Received ISUP MSU");
-
- }
- if (mtp3Listener != null) {
- byte[] messageBuffer = fetchBuffer(rxFrame.len-5);
- System.arraycopy(rxFrame.frame, 3, messageBuffer, 0, rxFrame.len-5);
- //messageBuffer[0] = (byte) sio;
- try {
- mtp3Listener.receive(messageBuffer);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- break;
- default:
- if (logger.isEnabledFor(Level.WARN) ) {
- logger.warn("Received MSU for UNKNOWN SERVICE!!!!!!!!!!!: " + Utils.dump(rxFrame.frame, rxFrame.len, false));
- }
- break;
- }
- }
-
-
- /**
- * Selects link for transmission using link selection indicator.
- *
- * @param sls signaling link selection indicator.
- * @return selected link.
- */
- private Mtp2 selectLink(byte sls) {
-
- return linkset.select(sls);
- }
-
- public boolean send(byte[] msg, int len) {
- //method expects proper message, lets pray its ok :/ - this is a way to be aligned with dialogic cards.
- //selecting link using sls
- //get sls;
- byte sls = (byte) sls(msg, 1);
- Mtp2 link = this.selectLink(sls);
-
- if (link == null) {
- return false;
- }
-
- return link.send(msg, len);
- }
-
- public void linkInService(Mtp2 link) {
- //restart traffic
- if (logger.isDebugEnabled()) {
- logger.debug(String.format("(%s) Sending TRA(Traffic Restart Allowed) message", link.getName()));
- }
-
- if(link.mtp2Listener != null){
- link.mtp2Listener.linkInService();
- }
-
- restartTraffic(link);
-
- //create and assign Tester;
- if (link.sltmTest == null) {
- SLTMTest tester = new SLTMTest(link);
- link.sltmTest =(tester);
-
- //start tester
- if (logger.isDebugEnabled()) {
- logger.debug(String.format("(%s) Starting link test procedure(SLTM/SLTA)", link.getName()));
- }
- tester.start();
- } else {
- link.sltmTest.start();
- }
- }
-
- /**
- * Notify that link is up.
- * @param link
- */
- private void linkUp(Mtp2 link) {
-
- if(link.mtp2Listener != null){
- link.mtp2Listener.linkUp();
- }
-
- linkset.add(link);
- if (linkset.isActive() && this.mtp3Listener != null) {
- try {
- mtp3Listener.linkUp();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- if (logger.isInfoEnabled()) {
- logger.info(String.format("(%s) Link now IN_SERVICE", link.getName()));
- }
- }
-
- public void linkFailed(Mtp2 link) {
-
- //Call Listener
- if(link.mtp2Listener != null){
- link.mtp2Listener.linkFailed();
- }
-
- //FIXME: add debug or trace?
- //remove this link from list of active links
- linkset.remove(link);
-
- //restart initial alignment after T17 expires
- link.fail();
-
- //notify mtp user part
- if (!linkset.isActive()) {
- l4IsUp = false;
- if (mtp3Listener != null) {
- try {
- mtp3Listener.linkDown();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
- }
-
- /* (non-Javadoc)
- * @see org.mobicents.protocols.ss7.mtp.Mtp2Listener#registerLink(org.mobicents.protocols.ss7.mtp.Mtp2)
- */
- public void registerLink(Mtp2 mtp2) {
- try {
- mtp2.getLayer1().register(selector);
- } catch (IOException ex) {
- ex.printStackTrace();
- }
- }
-
- /* (non-Javadoc)
- * @see org.mobicents.protocols.ss7.mtp.Mtp2Listener#unregisterLink(org.mobicents.protocols.ss7.mtp.Mtp2)
- */
- public void unregisterLink(Mtp2 mtp2) {
- }
-
- private void restartTraffic(Mtp2 link) {
-
- writeRoutingLabel(this.localFrame, 0, this.ni, 0, dpc, opc);
-
- // H0 and H1, see Q.704 section 15.11.2+
- this.localFrame[5] = 0x17;
- link.send(this.localFrame, 6);
- }
-
- private final static int PATTERN_OFFSET = 10;
- private final static int PATTERN_LEN_OFFSET = PATTERN_OFFSET+2; //+2 becuase frame.len contains 2B for CRC
-
- private boolean checkPattern(Mtp2Buffer frame,int sltmLen, byte[] pattern) {
- if (frame.len - PATTERN_LEN_OFFSET != pattern.length) {
- return false;
- }
- for (int i = 0; i < pattern.length; i++) {
- if (frame.frame[ i + PATTERN_OFFSET ] != pattern[i]) {
- return false;
- }
- }
- return true;
- }
-
- /**
- * @param i
- * @return
- */
- private byte[] fetchBuffer(int size) {
- return this.localBuffers[size];
- }
- protected class SLTMTest extends MTPTask {
-
- private Mtp2 link;
- private int tryCount; //SLTM message buffer;
- private byte[] sltm = new byte[7 + SLTM_PATTERN.length]; //this has to be separate, cause its async to Mtp3.send
-
- private SLTMTest(Mtp2 link) {
- this.link = link;
- }
-
- /**
- *
- */
- public void start() {
- //reset count of tries
- tryCount = 0;
-
- //sending test message to the remote terminal
- run();
- }
-
- public void stop() {
- //disable handler
- cancel();
- }
-
- /**
- * This methods should be called to acknowledge that current tests is passed.
- *
- */
- public void ack() {
- //disable current awaiting handler
- cancel();
- //reset number of tryies;
- tryCount = 0;
- //shcedule next ping
- executor.schedule(this, Mtp3.TIMEOUT_T2_SLTM * 1000);
- if (logger.isDebugEnabled()) {
- logger.debug(String.format("(%s) SLTM acknowledged, Link test passed", link.getName()));
- }
- }
-
- /**
- * Sends SLTM message using this link.
- *
- * @param timeout the amount of time in millesecond for awaiting response.
- */
- public void ping(long timeout) {
- //prepearing test message
-
- writeRoutingLabel(sltm, 0x01, ni, link.getSls(), dpc, opc);
- //sltm[0] = (byte) 0x01;
- sltm[5] = 0x11;
- sltm[6] = (byte) (SLTM_PATTERN.length << 4);
- System.arraycopy(SLTM_PATTERN, 0, sltm, 7, SLTM_PATTERN.length);
-
- //sending test message
- link.send(sltm, sltm.length);
-
- //incremeting number of tries.
- tryCount++;
-
- //scheduling timeout
- executor.schedule(this, (int)(timeout * 1000));
- if (logger.isDebugEnabled()) {
- logger.debug(String.format("(%s) SLTM sent, try number = %d", link.getName(), tryCount));
- }
- }
-
- public void perform() {
- switch (tryCount) {
- case 0:
- //sending first test message
- ping(Mtp3.TIMEOUT_T1_SLTM);
- break;
- case 1:
- //first message was not answered, sending second
- ping(Mtp3.TIMEOUT_T1_SLTM);
- break;
- case 2:
- if (logger.isDebugEnabled()) {
- logger.debug(String.format("(%s) SLTM message was not acknowledged, Link failed", link.getName()));
- }
- //second message was not answered, report failure
- linkFailed(link);
- }
- }
- }
-
- // //////////////////
- // Helper methods //
- // //////////////////
- public static final int dpc(byte[] sif, int shift) {
- int dpc = (sif[0 + shift] & 0xff | ((sif[1 + shift] & 0x3f) << 8));
- return dpc;
- }
-
- public static final int opc(byte[] sif, int shift) {
- int opc = ((sif[1 + shift] & 0xC0) >> 6) | ((sif[2 + shift] & 0xff) << 2) | ((sif[3 + shift] & 0x0f) << 10);
- return opc;
- }
-
- public static final int sls(byte[] sif, int shift) {
- int sls = (sif[3 + shift] & 0xf0) >>> 4;
- return sls;
- }
-
- public static final int si(byte[] data) {
-
- int serviceIndicator = data[0] & 0x0f;
- return serviceIndicator;
- }
-
- public static final int ssi(byte[] data) {
- //see Q.704.14.2
- int subserviceIndicator = (data[0] >> 4) & 0x0F;
- return subserviceIndicator;
- }
-
- public static void writeRoutingLabel(byte[] data, int si, int ssi, int sls, int dpc, int opc) {
- //see Q.704.14.2
- writeRoutingLabel(0,data, si, ssi, sls, dpc, opc);
-
- }
- public static void writeRoutingLabel(int shift, byte[] data, int si, int ssi, int sls, int dpc, int opc) {
- //see Q.704.14.2
- data[0+shift] = (byte) (((ssi & 0x0F) << 4) | (si & 0x0F));
- data[1+shift] = (byte) dpc;
- data[2+shift] = (byte) (((dpc >> 8) & 0x3F) | ((opc & 0x03) << 6));
- data[3+shift] = (byte) (opc >> 2);
- data[4+shift] = (byte) (((opc >> 10) & 0x0F) | ((sls & 0x0F) << 4));
-
- }
- }