All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.easydiameter.application.DiameterStack Maven / Gradle / Ivy

package com.easydiameter.application;

import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;

import org.apache.log4j.Logger;

import com.easydiameter.exception.DiameterParseException;
import com.easydiameter.packet.message.DiameterMessage;
import com.easydiameter.util.BufferUtilities;
import com.easydiameter.util.ProtocolDefinitions;
import com.easydiameter.util.ProtocolUtilities;

public class DiameterStack {

   /* return codes from the stack */
   public static final int       RC_SUCCESS         = 0;
   public static final int       RC_CONNECT_TIMEOUT = 1;
   public static final int       RC_UNKNOWN_HOST    = 2;
   public static final int       RC_IO_EXCEPTION    = 3;

   /* stack working mode */
   public static final int       WM_NONE            = 0;
   public static final int       WM_SERVER          = 1;
   public static final int       WM_CLIENT          = 2;

   private static Logger         LOGGER             = Logger.getLogger(DiameterStack.class);

   protected int                 connectTimeout     = 2000;
   protected int                 workingMode        = WM_NONE;

   /* local IP */
   protected String              localAddressStr;
   protected int                 listenPort;

   protected Acceptor            acceptor;
   protected Receiver            receiver;

   /* after connection establishment */
   protected Socket              connectionSocket;
   protected int                 localPort;
   protected int                 remotePort;
   protected InetAddress         localAddress;
   protected InetAddress         remoteAddress;
   protected DiameterApplication application;

   public DiameterStack(DiameterApplication application, String ipAddress, int listenPort) {
      this.application = application;
      this.localAddressStr = ipAddress;
      this.listenPort = listenPort;
   }

   public DiameterStack(DiameterApplication application) {
      this.application = application;
   }

   public void setConnectTimeout(int timeout) {
      this.connectTimeout = timeout;
   }

   public int getConnectTimeout() {
      return this.connectTimeout;
   }

   public void shutdown() {
      if (this.acceptor != null) {
         this.acceptor.stop();
      }
      if (this.receiver != null) {
         this.receiver.stop();
      }
   }

   public void startWithListening() throws IOException {
      this.acceptor = new Acceptor(this.localAddressStr, this.listenPort, true, this);
      this.localPort = this.acceptor.bind();
      this.workingMode = WM_SERVER;
      new Thread(this.acceptor, "Acceptor").start();
   }

   /* Accepts remote-address and port Return 0 if success Return 0 if success */
   public int startWithAttempt(String remoteAddress, int remotePort, String localAddress, int localPort) {
      int result = RC_SUCCESS;
      long start = 0;
      try {
         this.remoteAddress = InetAddress.getByName(remoteAddress);
         this.remotePort = remotePort;
         start = System.currentTimeMillis();

         SocketAddress sockaddr = new InetSocketAddress(this.remoteAddress, this.remotePort);
         SocketAddress sockaddr2 = new InetSocketAddress(localAddress, localPort);

         this.connectionSocket = new Socket();
         if (localAddress != null && localPort != 0) {
            this.connectionSocket.bind(sockaddr2);
         }
         this.connectionSocket.connect(sockaddr, this.connectTimeout);

         this.workingMode = WM_CLIENT;

         this.localAddress = this.connectionSocket.getLocalAddress();
         this.localPort = this.connectionSocket.getLocalPort();

         LOGGER.info("Connection is attempted successfuly: Local Address = " + this.localAddress.getHostAddress() + ":" + this.localPort
               + " - " + "Remote Address = " + this.remoteAddress.getHostAddress() + ":" + this.remotePort);
         if (this.application != null) {
            this.application.onConnectionSuccess(this.localAddressStr, this.localPort, this.remoteAddress.getHostAddress(),
                  this.remotePort);
         }
         this.receiver = new Receiver(this.connectionSocket, this);
         new Thread(this.receiver, ("Receiver-" + ProtocolUtilities.receiverCounter.getAndIncrement())).start();
      } catch (SocketTimeoutException sot) {
         LOGGER.error("ConnectTimeout: Time = " + (System.currentTimeMillis() - start));
         result = RC_CONNECT_TIMEOUT;
      } catch (UnknownHostException e) {
         if (this.application != null) {
            this.application.onConnectionFail(this.remoteAddress.getHostAddress(), this.remotePort);
         }
         LOGGER.error("Unknown-Host --> " + e);
         result = RC_UNKNOWN_HOST;
      } catch (IOException e) {
         if (this.application != null) {
            this.application.onConnectionFail(this.remoteAddress.getHostAddress(), this.remotePort);
         }
         LOGGER.error("IO Problem --> " + e);
         result = RC_IO_EXCEPTION;
      }
      return result;
   }

   /*
    * Called from application to send message through the established
    * connection/socket established connection/socket
    */
   public int sendMessage(byte[] msg, int len) {
      int result = 0;

      if (this.connectionSocket == null) {
         result = startWithAttempt(this.remoteAddress.getHostAddress(), this.remotePort, null, 0);
         if (result != 0) {
            LOGGER.error("Cannot connect to remote with address = " + this.remoteAddress.getHostAddress() + ":" + this.remotePort);
         }
      }
      try {
         OutputStream output = this.connectionSocket.getOutputStream();
         output.write(msg);
         /* TODO: Call back onMessageSend from owner/application */
         if (this.application != null) {
            this.application.onSendMessage();
         }
      } catch (IOException e) {
         LOGGER.error("IO Problem: " + e);
      }
      return result;
   }

   public int sendMessage(byte[] msg) {
      return sendMessage(msg, msg.length);
   }

   /*
    * Callbacks from Acceptor and Receiver
    */

   /* called from Acceptor in the case of a connection accepted */
   public void connectionAccepted(Socket sock) {
      this.connectionSocket = sock;
      this.localPort = sock.getLocalPort();
      this.remotePort = sock.getPort();
      this.localAddress = sock.getLocalAddress();
      this.remoteAddress = sock.getInetAddress();

      LOGGER.debug("Connection is accepted: Local Address = " + this.localAddress.getHostAddress() + ":" + this.localPort + " | "
            + "Remote Address = " + this.remoteAddress.getHostAddress() + ":" + this.remotePort);
      if (this.application != null) {
         this.application.onConnectionSuccess(this.localAddressStr, this.listenPort, this.remoteAddress.getHostAddress(), this.remotePort);
      }
      this.receiver = new Receiver(this.connectionSocket, this);
      new Thread(this.receiver, "Receiver").start();
   }

   /* called from receiver */
   public byte[] messageReceived(byte[] buffer, int length) {
      byte[] rawmsg = buffer;
      byte[] remaining = null;
      int rawLength = length;

      StringBuilder sb = new StringBuilder();
      BufferUtilities.printMessageBuffer(sb, rawmsg, 0, rawLength);
      LOGGER.debug("Received DIAMETER RAW message --> \n" + sb.toString());

      while (true) {

         // Message Checks

         if (rawmsg[0] != 1) {
            LOGGER.warn("Unexpected version --> " + rawmsg[0]);
            byte[] rem = new byte[rawmsg.length - 1];
            System.arraycopy(rawmsg, 1, rem, 0, rawmsg.length - 1);
            return rem;
         }

         if (rawLength < ProtocolDefinitions.DIAMETER_MSG_HDR_LEN) {
            /* no enough bytes even for header */
            remaining = rawmsg;
            break;
         }

         int msgLength = BufferUtilities.get3Bytes(rawmsg, 1); // First index is Diameter Version
         if (rawLength < msgLength) {
            /* no enough bytes for message */
            remaining = rawmsg;
            break;
         }

         int rl = rawLength - msgLength;
         if (rl > 0) {
            /*
             * we have some additional bytes which are belong to another message. Keep them
             * in remaining to retry in next loop
             */
            remaining = new byte[rl];
            System.arraycopy(rawmsg, msgLength, remaining, 0, rl);
            LOGGER.debug("There are remaining bytes in Diameter messageReceived with length = " + remaining.length);
         }

         DiameterMessage message = null;

         try {
            message = DiameterMessage.decodePacket(rawmsg);
         } catch (DiameterParseException e) {
            e.printStackTrace();
         }

         if (message != null) {
            // Pass the message to application level
            application.receiveMessage(this, message);
         } else {
            StringBuilder sb1 = new StringBuilder();
            BufferUtilities.printMessageBuffer(sb1, rawmsg, 0, rawLength);
            LOGGER.warn("Cannot produce a Diameter Message from received bytes ===> \n" + sb1.toString());
         }

         if (remaining == null) {
            // LOGGER.debug("Breaking from Diameter messageReceived since there is no
            // remaining.");
            break;
         } else {
            /* continue with the remaining bytes */
            rawmsg = remaining;
            rawLength = rawmsg.length;
            remaining = null;
            LOGGER.debug("Continue with remaining bytes with length = " + rawLength);
         }
      }
      return remaining;
   }

   /* called from receiver */
   public void connectionDisconnected(Socket sock) {
      LOGGER.info("Connection disconnected");
      if (this.application != null) {
         this.application.onDisconnect(0);
      }
   }

   public void setRemoteIp(String remIP) {
      try {
         this.remoteAddress = InetAddress.getByName(remIP);
      } catch (UnknownHostException e) {
         LOGGER.error("Unknown host problem: " + e);
      }
   }

   public String getRemoteIP() {
      return this.remoteAddress.getHostAddress();
   }

   public void setRemotePort(int port) {
      this.remotePort = port;
   }

   public int getRemotePort() {
      return this.remotePort;
   }

   public int getLocalPort() {
      return localPort;
   }

   public Socket getConnectionSocket() {
      return this.connectionSocket;
   }

   public boolean isConnected() {
      return (this.connectionSocket != null);
   }

   public void setReceiver(Receiver receiver) {
      this.receiver = receiver;
   }

   public int getWorkingMode() {
      return this.workingMode;
   }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy