PageRenderTime 41ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/protocols/ss7/mtp/mtp-impl/src/main/java/org/mobicents/protocols/ss7/mtp/Mtp3.java

http://mobicents.googlecode.com/
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
  1. /*
  2. * JBoss, Home of Professional Open Source
  3. * Copyright 2011, Red Hat, Inc. and individual contributors
  4. * by the @authors tag. See the copyright.txt in the distribution for a
  5. * full listing of individual contributors.
  6. *
  7. * This is free software; you can redistribute it and/or modify it
  8. * under the terms of the GNU Lesser General Public License as
  9. * published by the Free Software Foundation; either version 2.1 of
  10. * the License, or (at your option) any later version.
  11. *
  12. * This software is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * Lesser General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Lesser General Public
  18. * License along with this software; if not, write to the Free
  19. * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
  20. * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
  21. */
  22. package org.mobicents.protocols.ss7.mtp;
  23. import java.io.IOException;
  24. import java.util.ArrayList;
  25. import java.util.Arrays;
  26. import java.util.List;
  27. import javolution.util.FastList;
  28. import org.apache.log4j.Level;
  29. import org.apache.log4j.Logger;
  30. import org.mobicents.protocols.stream.api.SelectorKey;
  31. import org.mobicents.protocols.stream.api.SelectorProvider;
  32. import org.mobicents.protocols.stream.api.StreamSelector;
  33. /**
  34. *
  35. * @author kulikov
  36. * @author baranowb
  37. */
  38. public class Mtp3 implements Runnable {
  39. public final static int TIMEOUT_T1_SLTM = 12;
  40. public final static int TIMEOUT_T2_SLTM = 90;
  41. private final static int LINK_MANAGEMENT = 0;
  42. private final static int LINK_TESTING = 1;
  43. public final static int _SI_SERVICE_SCCP = 3;
  44. public final static int _SI_SERVICE_ISUP = 5;
  45. private Mtp3Listener mtp3Listener;
  46. /**
  47. * Flag indicating if we should notify upper layer
  48. */
  49. private boolean l4IsUp = false;
  50. //FIXME: MOVE THIS TO LINKSET?
  51. protected volatile boolean started = false;
  52. /** defautl value of SSI */
  53. public static final int DEFAULT_NI = 2;//NATIONAL, as default.
  54. private int dpc;
  55. private int opc;
  56. private int ni=DEFAULT_NI << 2; // << cause its faster for checks.
  57. /**
  58. * Local byte[], in which we forge messages.
  59. */
  60. private byte[] localFrame = new byte[279];
  61. private byte[][] localBuffers;
  62. /** List of signaling channels wrapped with MTP2*/
  63. private List<Mtp2> links = new ArrayList();
  64. /** Active links */
  65. private Linkset linkset = new Linkset();
  66. // ss7 has subservice as 1, q704 shows the same iirc
  67. //private int subservice = -1;
  68. //private int service;
  69. // //////////////////////////
  70. // SLTM pattern for inits //
  71. // //////////////////////////
  72. private final static byte[] SLTM_PATTERN = new byte[]{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x0F};
  73. protected String name;
  74. private StreamSelector selector;
  75. private MTPScheduler executor = new MTPScheduler();
  76. private static final Logger logger = Logger.getLogger(Mtp3.class);
  77. //public Mtp3Impl(String name, Mtp1 layer1) {
  78. public Mtp3(String name) {
  79. this.name = name;
  80. try {
  81. selector = SelectorProvider.getSelector("org.mobicents.ss7.hardware.dahdi.Selector");
  82. } catch (Exception e) {
  83. e.printStackTrace();
  84. }
  85. this.localBuffers = new byte[300][];
  86. for(int i=0;i<300;i++)
  87. {
  88. this.localBuffers[i] = new byte[i];
  89. }
  90. }
  91. /**
  92. * Assigns originated point code
  93. *
  94. * @param opc the originated point code
  95. */
  96. public void setOpc(int opc) {
  97. this.opc = opc;
  98. }
  99. /**
  100. * Assigns destination point code.
  101. *
  102. * @param dpc destination point code in decimal format.
  103. */
  104. public void setDpc(int dpc) {
  105. this.dpc = dpc;
  106. }
  107. /**
  108. * @return the dpc
  109. */
  110. public int getDpc() {
  111. return dpc;
  112. }
  113. /**
  114. * @return the opc
  115. */
  116. public int getOpc() {
  117. return opc;
  118. }
  119. /**
  120. * Sets network indicator to be used as part of SIO( actually SSI). It Accepts 2 bit integer.
  121. * @param ni
  122. */
  123. public void setNetworkIndicator(int ni){
  124. this.ni = (0x03 & ni) << 2;
  125. }
  126. public int getNetworkIndicator() {
  127. return this.ni >> 2;
  128. }
  129. /** (non-Javadoc)
  130. * @see org.mobicents.protocols.ss7.mtp.Mtp3#addMtp3Listener(org.mobicents.protocols.ss7.mtp.Mtp3Listener)
  131. */
  132. public void addMtp3Listener(Mtp3Listener lst) {
  133. if (this.mtp3Listener != null) {
  134. throw new IllegalStateException("Listener already present.");
  135. }
  136. this.mtp3Listener = lst;
  137. }
  138. /* (non-Javadoc)
  139. * @see org.mobicents.protocols.ss7.mtp.Mtp3#removeMtp3Listener(org.mobicents.protocols.ss7.mtp.Mtp3Listener)
  140. */
  141. public void removeMtp3Listener(Mtp3Listener lst) {
  142. if (lst != this.mtp3Listener) {
  143. throw new IllegalArgumentException("Wrong listener passed. Its not registered in this object!");
  144. }
  145. this.mtp3Listener = null;
  146. }
  147. /* (non-Javadoc)
  148. * @see org.mobicents.protocols.ss7.mtp.Mtp3#setLinks(java.util.List)
  149. */
  150. public void setLinks(List<Mtp2> channels) {
  151. for (Mtp2 link : channels) {
  152. if (link != null) {
  153. link.mtp3 = this;
  154. this.links.add(link);
  155. }
  156. }
  157. }
  158. public void addLink(Mtp2 mtp2){
  159. mtp2.mtp3 = this;
  160. this.links.add(mtp2);
  161. }
  162. public void clearLinks(){
  163. this.links.clear();
  164. }
  165. /**
  166. * Starts linkset.
  167. *
  168. * @throws java.io.IOException
  169. */
  170. public void start() throws IOException {
  171. //starting links
  172. for (Mtp2 link : links) {
  173. link.start();
  174. }
  175. }
  176. public void stop() throws IOException {
  177. started = false;
  178. for (Mtp2 link : links) {
  179. //selector.unregister(link);
  180. link.stop();
  181. }
  182. }
  183. public void run() {
  184. try {
  185. FastList<SelectorKey> selected = selector.selectNow(StreamSelector.OP_READ, 20);
  186. for (FastList.Node<SelectorKey> n = selected.head(), end = selected.tail(); (n = n.getNext()) != end;) {
  187. ((Mtp2)((Mtp1) n.getValue().getStream()).getLink()).doRead();
  188. }
  189. selected = selector.selectNow(StreamSelector.OP_WRITE, 20);
  190. for (FastList.Node<SelectorKey> n = selected.head(), end = selected.tail(); (n = n.getNext()) != end;) {
  191. ((Mtp2)((Mtp1) n.getValue().getStream()).getLink()).doWrite();
  192. }
  193. this.executor.tick();
  194. for (Mtp2 link : links) {
  195. link.scheduler.tick();
  196. }
  197. } catch (Exception e) {
  198. e.printStackTrace();
  199. }
  200. }
  201. /**
  202. * This method is called when new MSU is detected.
  203. *
  204. * @param sio
  205. * service information octet.
  206. * @param msg
  207. * service information field;
  208. */
  209. public void onMessage(Mtp2Buffer rxFrame, Mtp2 mtp2)
  210. {
  211. // | ----------------------- TO L4 --------------------------- |
  212. // | --------------------- SIF ------------------------ |
  213. //FSN BSN LEN SIO DPC/OPC,SLS HEADING LEN
  214. //b1 b0 0e 01 01 80 00 00 21 70 01 02 03 04 05 06 0f CRC CRC
  215. int sio = rxFrame.frame[3] & 0xFF;
  216. int subserviceIndicator = (sio >> 4) & 0x0F;
  217. int serviceIndicator = sio & 0x0F;
  218. int ni = (subserviceIndicator & 0x0C) ; //local NI(network Indicator) form msg., 0x0C, since we store it as shifted value.
  219. // int dpc = (sif[0] & 0xff | ((sif[1] & 0x3f) << 8));
  220. // int opc = ((sif[1] & 0xC0) >> 6) | ((sif[2] & 0xff) << 2) | ((sif[3]
  221. // & 0x0f) << 10);
  222. // int sls = (sif[3] & 0xf0) >>> 4;
  223. int dpc = dpc(rxFrame.frame, 4); //1 - cause sif contains sio, even though its also passed as arg.
  224. int opc = opc(rxFrame.frame, 4);
  225. int sls = sls(rxFrame.frame, 4);
  226. //check SSI, Q.704 Figure 25, seems like if its bad, we discard.
  227. if(this.ni!=ni)
  228. {
  229. if (logger.isEnabledFor(Level.ERROR)) {
  230. logger.error(
  231. 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));
  232. }
  233. return;
  234. }
  235. switch (serviceIndicator) {
  236. case LINK_MANAGEMENT:
  237. int h0 = rxFrame.frame[8] & 0x0f;
  238. int h1 = (rxFrame.frame[8] & 0xf0) >>> 4;
  239. if (logger.isDebugEnabled()) {
  240. logger.debug(String.format("(%s) Signalling network management", mtp2.getName()));
  241. }
  242. if (h0 == 0) {
  243. if (logger.isDebugEnabled()) {
  244. logger.debug(String.format("(%s) Changeover management", mtp2.getName()));
  245. }
  246. } else if (h0 == 7 && h1 == 1) {
  247. if (logger.isDebugEnabled()) {
  248. logger.debug(String.format("(%s) TRA received", mtp2.getName()));
  249. }
  250. }
  251. //FIX ME
  252. break;
  253. case LINK_TESTING:
  254. h0 = rxFrame.frame[8] & 0x0f;
  255. h1 = (rxFrame.frame[8] & 0xf0) >>> 4;
  256. int len = (rxFrame.frame[9] & 0xf0) >>> 4;
  257. if (h0 == 1 && h1 == 1) {
  258. if (logger.isDebugEnabled()) {
  259. logger.debug(String.format("(%s) Received SLTM", mtp2.getName()));
  260. }
  261. // receive SLTM from remote end
  262. // create response
  263. //change order of opc/dpc in SLTA !
  264. writeRoutingLabel(this.localFrame, sio, this.ni << 2, sls, opc, dpc);
  265. //slta[0] = (byte) sio;
  266. this.localFrame[5] = 0x021;
  267. // +1 cause we copy LEN byte also.
  268. System.arraycopy(rxFrame.frame, 9, this.localFrame, 6, len + 1);
  269. if (logger.isDebugEnabled()) {
  270. logger.debug(String.format("(%s) Responding with SLTA", mtp2.getName()));
  271. }
  272. mtp2.send( this.localFrame, len+9);
  273. } else if (h0 == 1 && h1 == 2) {
  274. // receive SLTA from remote end
  275. if (logger.isDebugEnabled()) {
  276. logger.debug(String.format("(%s) Received SLTA", mtp2.getName()));
  277. }
  278. //checking pattern
  279. if (checkPattern(rxFrame,len, SLTM_PATTERN)) {
  280. //test message is acknowledged
  281. mtp2.sltmTest.ack();
  282. //notify top layer that link is up
  283. if (!l4IsUp) {
  284. l4IsUp = true;
  285. linkUp(mtp2);
  286. }
  287. } else {
  288. if(logger.isEnabledFor(Level.WARN))
  289. {
  290. logger.warn("SLTA pattern does not match: \n"+Arrays.toString(rxFrame.frame)+"\n"+Arrays.toString(SLTM_PATTERN));
  291. }
  292. }
  293. } else {
  294. if(logger.isEnabledFor(Level.WARN))
  295. {
  296. logger.warn(String.format("(%s) Unexpected message type", mtp2.getName()));
  297. }
  298. }
  299. break;
  300. case _SI_SERVICE_SCCP:
  301. if (logger.isDebugEnabled()) {
  302. logger.debug("Received SCCP MSU");
  303. }
  304. if (mtp3Listener != null) {
  305. // | ----------------------- TO L4 --------------------------- |
  306. // | --------------------- SIF ------------------------ |
  307. //FSN BSN LEN SIO DPC/OPC,SLS HEADING LEN
  308. //b1 b0 0e 01 01 80 00 00 21 70 01 02 03 04 05 06 0f CRC CRC
  309. byte[] messageBuffer = fetchBuffer(rxFrame.len-5); //-5 = FSN(1) + BSN(1) + LEN(1) +2xCRC(1)
  310. System.arraycopy(rxFrame.frame, 3, messageBuffer, 0, rxFrame.len-5);
  311. //messageBuffer[0] = (byte) sio;
  312. try {
  313. mtp3Listener.receive(messageBuffer);
  314. } catch (Exception e) {
  315. e.printStackTrace();
  316. }
  317. }
  318. break;
  319. case _SI_SERVICE_ISUP:
  320. if (logger.isDebugEnabled()) {
  321. logger.debug("Received ISUP MSU");
  322. }
  323. if (mtp3Listener != null) {
  324. byte[] messageBuffer = fetchBuffer(rxFrame.len-5);
  325. System.arraycopy(rxFrame.frame, 3, messageBuffer, 0, rxFrame.len-5);
  326. //messageBuffer[0] = (byte) sio;
  327. try {
  328. mtp3Listener.receive(messageBuffer);
  329. } catch (Exception e) {
  330. e.printStackTrace();
  331. }
  332. }
  333. break;
  334. default:
  335. if (logger.isEnabledFor(Level.WARN) ) {
  336. logger.warn("Received MSU for UNKNOWN SERVICE!!!!!!!!!!!: " + Utils.dump(rxFrame.frame, rxFrame.len, false));
  337. }
  338. break;
  339. }
  340. }
  341. /**
  342. * Selects link for transmission using link selection indicator.
  343. *
  344. * @param sls signaling link selection indicator.
  345. * @return selected link.
  346. */
  347. private Mtp2 selectLink(byte sls) {
  348. return linkset.select(sls);
  349. }
  350. public boolean send(byte[] msg, int len) {
  351. //method expects proper message, lets pray its ok :/ - this is a way to be aligned with dialogic cards.
  352. //selecting link using sls
  353. //get sls;
  354. byte sls = (byte) sls(msg, 1);
  355. Mtp2 link = this.selectLink(sls);
  356. if (link == null) {
  357. return false;
  358. }
  359. return link.send(msg, len);
  360. }
  361. public void linkInService(Mtp2 link) {
  362. //restart traffic
  363. if (logger.isDebugEnabled()) {
  364. logger.debug(String.format("(%s) Sending TRA(Traffic Restart Allowed) message", link.getName()));
  365. }
  366. if(link.mtp2Listener != null){
  367. link.mtp2Listener.linkInService();
  368. }
  369. restartTraffic(link);
  370. //create and assign Tester;
  371. if (link.sltmTest == null) {
  372. SLTMTest tester = new SLTMTest(link);
  373. link.sltmTest =(tester);
  374. //start tester
  375. if (logger.isDebugEnabled()) {
  376. logger.debug(String.format("(%s) Starting link test procedure(SLTM/SLTA)", link.getName()));
  377. }
  378. tester.start();
  379. } else {
  380. link.sltmTest.start();
  381. }
  382. }
  383. /**
  384. * Notify that link is up.
  385. * @param link
  386. */
  387. private void linkUp(Mtp2 link) {
  388. if(link.mtp2Listener != null){
  389. link.mtp2Listener.linkUp();
  390. }
  391. linkset.add(link);
  392. if (linkset.isActive() && this.mtp3Listener != null) {
  393. try {
  394. mtp3Listener.linkUp();
  395. } catch (Exception e) {
  396. e.printStackTrace();
  397. }
  398. }
  399. if (logger.isInfoEnabled()) {
  400. logger.info(String.format("(%s) Link now IN_SERVICE", link.getName()));
  401. }
  402. }
  403. public void linkFailed(Mtp2 link) {
  404. //Call Listener
  405. if(link.mtp2Listener != null){
  406. link.mtp2Listener.linkFailed();
  407. }
  408. //FIXME: add debug or trace?
  409. //remove this link from list of active links
  410. linkset.remove(link);
  411. //restart initial alignment after T17 expires
  412. link.fail();
  413. //notify mtp user part
  414. if (!linkset.isActive()) {
  415. l4IsUp = false;
  416. if (mtp3Listener != null) {
  417. try {
  418. mtp3Listener.linkDown();
  419. } catch (Exception e) {
  420. e.printStackTrace();
  421. }
  422. }
  423. }
  424. }
  425. /* (non-Javadoc)
  426. * @see org.mobicents.protocols.ss7.mtp.Mtp2Listener#registerLink(org.mobicents.protocols.ss7.mtp.Mtp2)
  427. */
  428. public void registerLink(Mtp2 mtp2) {
  429. try {
  430. mtp2.getLayer1().register(selector);
  431. } catch (IOException ex) {
  432. ex.printStackTrace();
  433. }
  434. }
  435. /* (non-Javadoc)
  436. * @see org.mobicents.protocols.ss7.mtp.Mtp2Listener#unregisterLink(org.mobicents.protocols.ss7.mtp.Mtp2)
  437. */
  438. public void unregisterLink(Mtp2 mtp2) {
  439. }
  440. private void restartTraffic(Mtp2 link) {
  441. writeRoutingLabel(this.localFrame, 0, this.ni, 0, dpc, opc);
  442. // H0 and H1, see Q.704 section 15.11.2+
  443. this.localFrame[5] = 0x17;
  444. link.send(this.localFrame, 6);
  445. }
  446. private final static int PATTERN_OFFSET = 10;
  447. private final static int PATTERN_LEN_OFFSET = PATTERN_OFFSET+2; //+2 becuase frame.len contains 2B for CRC
  448. private boolean checkPattern(Mtp2Buffer frame,int sltmLen, byte[] pattern) {
  449. if (frame.len - PATTERN_LEN_OFFSET != pattern.length) {
  450. return false;
  451. }
  452. for (int i = 0; i < pattern.length; i++) {
  453. if (frame.frame[ i + PATTERN_OFFSET ] != pattern[i]) {
  454. return false;
  455. }
  456. }
  457. return true;
  458. }
  459. /**
  460. * @param i
  461. * @return
  462. */
  463. private byte[] fetchBuffer(int size) {
  464. return this.localBuffers[size];
  465. }
  466. protected class SLTMTest extends MTPTask {
  467. private Mtp2 link;
  468. private int tryCount; //SLTM message buffer;
  469. private byte[] sltm = new byte[7 + SLTM_PATTERN.length]; //this has to be separate, cause its async to Mtp3.send
  470. private SLTMTest(Mtp2 link) {
  471. this.link = link;
  472. }
  473. /**
  474. *
  475. */
  476. public void start() {
  477. //reset count of tries
  478. tryCount = 0;
  479. //sending test message to the remote terminal
  480. run();
  481. }
  482. public void stop() {
  483. //disable handler
  484. cancel();
  485. }
  486. /**
  487. * This methods should be called to acknowledge that current tests is passed.
  488. *
  489. */
  490. public void ack() {
  491. //disable current awaiting handler
  492. cancel();
  493. //reset number of tryies;
  494. tryCount = 0;
  495. //shcedule next ping
  496. executor.schedule(this, Mtp3.TIMEOUT_T2_SLTM * 1000);
  497. if (logger.isDebugEnabled()) {
  498. logger.debug(String.format("(%s) SLTM acknowledged, Link test passed", link.getName()));
  499. }
  500. }
  501. /**
  502. * Sends SLTM message using this link.
  503. *
  504. * @param timeout the amount of time in millesecond for awaiting response.
  505. */
  506. public void ping(long timeout) {
  507. //prepearing test message
  508. writeRoutingLabel(sltm, 0x01, ni, link.getSls(), dpc, opc);
  509. //sltm[0] = (byte) 0x01;
  510. sltm[5] = 0x11;
  511. sltm[6] = (byte) (SLTM_PATTERN.length << 4);
  512. System.arraycopy(SLTM_PATTERN, 0, sltm, 7, SLTM_PATTERN.length);
  513. //sending test message
  514. link.send(sltm, sltm.length);
  515. //incremeting number of tries.
  516. tryCount++;
  517. //scheduling timeout
  518. executor.schedule(this, (int)(timeout * 1000));
  519. if (logger.isDebugEnabled()) {
  520. logger.debug(String.format("(%s) SLTM sent, try number = %d", link.getName(), tryCount));
  521. }
  522. }
  523. public void perform() {
  524. switch (tryCount) {
  525. case 0:
  526. //sending first test message
  527. ping(Mtp3.TIMEOUT_T1_SLTM);
  528. break;
  529. case 1:
  530. //first message was not answered, sending second
  531. ping(Mtp3.TIMEOUT_T1_SLTM);
  532. break;
  533. case 2:
  534. if (logger.isDebugEnabled()) {
  535. logger.debug(String.format("(%s) SLTM message was not acknowledged, Link failed", link.getName()));
  536. }
  537. //second message was not answered, report failure
  538. linkFailed(link);
  539. }
  540. }
  541. }
  542. // //////////////////
  543. // Helper methods //
  544. // //////////////////
  545. public static final int dpc(byte[] sif, int shift) {
  546. int dpc = (sif[0 + shift] & 0xff | ((sif[1 + shift] & 0x3f) << 8));
  547. return dpc;
  548. }
  549. public static final int opc(byte[] sif, int shift) {
  550. int opc = ((sif[1 + shift] & 0xC0) >> 6) | ((sif[2 + shift] & 0xff) << 2) | ((sif[3 + shift] & 0x0f) << 10);
  551. return opc;
  552. }
  553. public static final int sls(byte[] sif, int shift) {
  554. int sls = (sif[3 + shift] & 0xf0) >>> 4;
  555. return sls;
  556. }
  557. public static final int si(byte[] data) {
  558. int serviceIndicator = data[0] & 0x0f;
  559. return serviceIndicator;
  560. }
  561. public static final int ssi(byte[] data) {
  562. //see Q.704.14.2
  563. int subserviceIndicator = (data[0] >> 4) & 0x0F;
  564. return subserviceIndicator;
  565. }
  566. public static void writeRoutingLabel(byte[] data, int si, int ssi, int sls, int dpc, int opc) {
  567. //see Q.704.14.2
  568. writeRoutingLabel(0,data, si, ssi, sls, dpc, opc);
  569. }
  570. public static void writeRoutingLabel(int shift, byte[] data, int si, int ssi, int sls, int dpc, int opc) {
  571. //see Q.704.14.2
  572. data[0+shift] = (byte) (((ssi & 0x0F) << 4) | (si & 0x0F));
  573. data[1+shift] = (byte) dpc;
  574. data[2+shift] = (byte) (((dpc >> 8) & 0x3F) | ((opc & 0x03) << 6));
  575. data[3+shift] = (byte) (opc >> 2);
  576. data[4+shift] = (byte) (((opc >> 10) & 0x0F) | ((sls & 0x0F) << 4));
  577. }
  578. }