/protocols/smpp/src/main/java/org/mobicents/protocols/smpp/net/ReplayLink.java

http://mobicents.googlecode.com/ · Java · 219 lines · 161 code · 24 blank · 34 comment · 19 complexity · 96534905614e456fece0c0aa86b4dd96 MD5 · raw file

  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.smpp.net;
  23. import java.io.EOFException;
  24. import java.io.IOException;
  25. import java.io.InputStream;
  26. import java.util.ArrayList;
  27. import java.util.HashSet;
  28. import java.util.List;
  29. import java.util.Set;
  30. import org.mobicents.protocols.smpp.message.SMPPPacket;
  31. import org.mobicents.protocols.smpp.util.PacketDecoderImpl;
  32. import org.mobicents.protocols.smpp.util.PacketFactory;
  33. import org.mobicents.protocols.smpp.util.SMPPIO;
  34. /**
  35. * An implementation of the SmscLink interface which can be used to replay
  36. * an SMPP session.
  37. * <p>
  38. * This implementation is intended to be used in conjunction with data
  39. * captured from a real SMPP session. All outbound bytes should be captured
  40. * in one location and all inbound bytes in another. This link will
  41. * reconstitute the SMPP packets for the session and provide response
  42. * packets only after it has seen the request packets being sent.
  43. * </p>
  44. * @version $Id: ReplayLink.java 457 2009-01-15 17:37:42Z orank $
  45. *
  46. */
  47. public class ReplayLink implements SmscLink {
  48. private InputStream inPacketSource;
  49. private InputStream outPacketSource;
  50. private int timeout = 0;
  51. private boolean connected;
  52. private PacketFactory packetFactory = new PacketFactory();
  53. private Set<Long> outboundSeqNums = new HashSet<Long>();
  54. private List<SMPPPacket> packetLookahead = new ArrayList<SMPPPacket>();
  55. private byte[] header = new byte[16];
  56. private byte[] packet = new byte[512];
  57. private TestDecoder decoder = new TestDecoder();
  58. public ReplayLink(InputStream inPacketSource, InputStream outPacketSource) {
  59. this.inPacketSource = inPacketSource;
  60. this.outPacketSource = outPacketSource;
  61. }
  62. public void connect() throws IOException {
  63. connected = true;
  64. lookahead(10);
  65. }
  66. public void disconnect() throws IOException {
  67. connected = false;
  68. packetLookahead.clear();
  69. }
  70. public void flush() throws IOException {
  71. }
  72. public int getTimeout() {
  73. return timeout;
  74. }
  75. public void setTimeout(int timeout) {
  76. this.timeout = timeout;
  77. }
  78. public boolean isConnected() {
  79. return connected;
  80. }
  81. public boolean isTimeoutSupported() {
  82. return false;
  83. }
  84. public SMPPPacket getNextOutbound() throws IOException {
  85. synchronized (decoder) {
  86. return readOnePacket(outPacketSource);
  87. }
  88. }
  89. public SMPPPacket read() throws IOException {
  90. if (!connected) {
  91. throw new IllegalStateException("Not connected.");
  92. }
  93. if (packetLookahead.size() < 3) {
  94. lookahead(50);
  95. }
  96. if (packetLookahead.size() == 0) {
  97. throw new EOFException();
  98. }
  99. SMPPPacket entry = packetLookahead.get(0);
  100. Long sequence = new Long(entry.getSequenceNum());
  101. if (entry.isResponse() && !outboundSeqNums.contains(sequence)) {
  102. blockUntilRequestSent(sequence);
  103. }
  104. return packetLookahead.remove(0);
  105. }
  106. public void write(SMPPPacket packet, boolean withOptionalParams)
  107. throws IOException {
  108. if (!connected) {
  109. throw new IllegalStateException("Not connected.");
  110. }
  111. Long seq = new Long(packet.getSequenceNum());
  112. synchronized (this) {
  113. outboundSeqNums.add(seq);
  114. notifyAll();
  115. }
  116. }
  117. private void lookahead(int number) throws IOException {
  118. synchronized (decoder) {
  119. for (int i = 0; i < number; i++) {
  120. SMPPPacket packet = readOnePacket(inPacketSource);
  121. if (packet == null) {
  122. break;
  123. }
  124. packetLookahead.add(packet);
  125. }
  126. }
  127. }
  128. private void blockUntilRequestSent(Long sequence) {
  129. try {
  130. synchronized (this) {
  131. if (!outboundSeqNums.contains(sequence)) {
  132. wait(timeout);
  133. }
  134. if (!outboundSeqNums.contains(sequence)) {
  135. throw new ReadTimeoutException();
  136. }
  137. }
  138. } catch (InterruptedException x) {
  139. }
  140. }
  141. private SMPPPacket readOnePacket(InputStream source) throws IOException {
  142. int count = 0;
  143. while (count < 16) {
  144. int n = source.read(header, 0, 16 - count);
  145. if (n < 0) {
  146. return null;
  147. }
  148. count += n;
  149. }
  150. int length = SMPPIO.readInt4(header, 0);
  151. if (length > packet.length) {
  152. packet = new byte[length];
  153. }
  154. while (count < length) {
  155. int n = source.read(packet, count - 16, length - count);
  156. if (n < 0) {
  157. return null;
  158. }
  159. count += n;
  160. }
  161. int id = SMPPIO.readInt4(header, 4);
  162. SMPPPacket packet = packetFactory.newInstance(id);
  163. decoder.reset(count);
  164. packet.readFrom(decoder);
  165. return packet;
  166. }
  167. private class TestDecoder extends PacketDecoderImpl {
  168. int offset;
  169. int available;
  170. public void reset(int byteCount) {
  171. setBytes(header);
  172. setParsePosition(0);
  173. offset = 0;
  174. available = byteCount;
  175. }
  176. @Override
  177. public int getAvailableBytes() {
  178. return available;
  179. }
  180. @Override
  181. public long readUInt4() {
  182. long val = super.readUInt4();
  183. if (getParsePosition() == 16) {
  184. setBytes(packet);
  185. setParsePosition(0);
  186. offset = 16;
  187. }
  188. return val;
  189. }
  190. @Override
  191. public int getParsePosition() {
  192. return offset + super.getParsePosition();
  193. }
  194. }
  195. }