content: /*
  * Conditions Of Use
  *
  * This software was developed by employees of the National Institute of
  * Standards and Technology (NIST), an agency of the Federal Government.
  * Pursuant to title 15 Untied States Code Section 105, works of NIST
  * employees are not subject to copyright protection in the United States
  * and are considered to be in the public domain.  As a result, a formal
  * license is not needed to use the software.
  *
  * This software is provided by NIST as a service and is expressly
  * provided "AS IS."  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED
  * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF
  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT
  * AND DATA ACCURACY.  NIST does not warrant or make any representations
  * regarding the use of the software or the results thereof, including but
  * not limited to the correctness, accuracy, reliability or usefulness of
  * the software.
  *
  * Permission to use this software is contingent upon your acceptance
  * of the terms of this agreement
  *
  * .
  *
  */
  package gov2.nist.javax2.sip.stack;
  
  import gov2.nist.core.Host;
  import gov2.nist.core.HostPort;
  import gov2.nist.core.InternalErrorHandler;
  import gov2.nist.javax2.sip.ListeningPointImpl;
  import gov2.nist.javax2.sip.header.Via;
  
  import java.io.IOException;
  import java.net.InetAddress;
  import java.text.ParseException;
  
  import javax2.sip.InvalidArgumentException;
  
  /**
   * This is the Stack abstraction for the active object that waits for messages
   * to appear on the wire and processes these messages by calling the
   * MessageFactory interface to create a ServerRequest or ServerResponse object.
   * The main job of the message processor is to instantiate message channels for
   * the given transport.
   *
   * @version 1.2 $Revision: 1.18 $ $Date: 2009/10/16 22:58:41 $
   *
   * @author M. Ranganathan <br/>
   *
   */
  public abstract class MessageProcessor implements Runnable {
      /**
       * A string containing the 0.0.0.0 IPv4 ANY address.
       */
      protected static final String IN_ADDR_ANY = "0.0.0.0";
  
      /**
       * A string containing the ::0 IPv6 ANY address.
       */
      protected static final String IN6_ADDR_ANY = "::0";
      /**
       * My Sent by string ( which I use to set the outgoing via header)
       */
      private  String sentBy;
  
      private HostPort sentByHostPort;
  
      /*
       * The IP Address that was originally assigned ( Can be ANY )
       */
  
      private String savedIpAddress;
  
      /**
       * The IP address where I am listening.
       */
      private InetAddress ipAddress;
  
      /**
       * The port where I am listening
       */
      private int port;
  
      /**
       * The transport where I am listening
       */
      protected String transport;
  
      /**
       * The Listening Point to which I am assigned.
       */
      private ListeningPointImpl listeningPoint;
  
      private boolean sentBySet;
  
      /**
       * Our stack (that created us).
       */
      protected SIPTransactionStack sipStack;
      
      protected MessageProcessor( String transport ) {
      	this.transport = transport;
      }
      
      /**
       * Constructor
       *
       * @param ipAddress -- ip address where I am listening for incoming requests.
       * @param port -- port where i am listening for incoming requests.
       * @param transport -- transport to use for the message processor (UDP/TCP/TLS).
       */
      protected MessageProcessor( InetAddress ipAddress, int port, String transport,
      							SIPTransactionStack transactionStack ) {
      	this( transport );
      	this.initialize(ipAddress, port, transactionStack);
      }
  
      /**
       * Initializes this MessageProcessor. Needed for extensions
       * that use classloading
       * 
       * @param ipAddress2
       * @param transactionStack
       * @param port2
       */
  	public final void initialize( InetAddress ipAddress, int port,
  			SIPTransactionStack transactionStack ) {
  		
  		this.sipStack = transactionStack;
          this.savedIpAddress = ipAddress.getHostAddress();
          this.ipAddress = ipAddress;
          this.port = port;
          this.sentByHostPort = new HostPort();
          this.sentByHostPort.setHost(new Host(ipAddress.getHostAddress()));
          this.sentByHostPort.setPort(port);		
  	}
      
      /**
       * Get the transport string.
       *
       * @return A string that indicates the transport. (i.e. "tcp" or "udp")
       */
      public String getTransport() {
          return this.transport;
      }
  
      /**
       * Get the port identifier.
       *
       * @return the port for this message processor. This is where you receive
       *         messages.
       */
      public int getPort() {
          return this.port;
      }
  
      /**
       * Get the Via header to assign for this message processor. The topmost via
       * header of the outoging messages use this.
       *
       * @return the ViaHeader to be used by the messages sent via this message processor.
       */
      public Via getViaHeader() {
          try {
              Via via = new Via();
              if (this.sentByHostPort != null) {
                  via.setSentBy(sentByHostPort);
                  via.setTransport(this.getTransport());
              } else {
                  Host host = new Host();
                  host.setHostname(this.getIpAddress().getHostAddress());
                  via.setHost(host);
                  via.setPort(this.getPort());
                  via.setTransport(this.getTransport());
              }
              return via;
          } catch (ParseException ex) {
              ex.printStackTrace();
              return null;
          } catch (InvalidArgumentException ex) {
              ex.printStackTrace();
              return null;
          }
      }
      public ListeningPointImpl getListeningPoint() {
          if ( listeningPoint == null )  {
              if ( this.getSIPStack().isLoggingEnabled()) {
                  this.getSIPStack().getStackLogger().logError("getListeningPoint" + this +
                          " returning null listeningpoint");
  
              }
          }
          return listeningPoint;
      }
  
      public void setListeningPoint(ListeningPointImpl lp) {
          if ( this.getSIPStack().isLoggingEnabled()) {
              this.getSIPStack().getStackLogger().logDebug("setListeningPoint" + this +
                      " listeningPoint = " + lp);
  
          }
          if ( lp.getPort() != this.getPort())
              InternalErrorHandler.handleException
              ("lp mismatch with provider",getSIPStack().getStackLogger());
          this.listeningPoint = lp;
  
      }
  
      /**
       * Get the saved IP Address.
       */
      public String getSavedIpAddress() {
          return this.savedIpAddress;
      }
      /**
       * @return the ip address for this message processor.
       */
      public InetAddress getIpAddress() {
            return this.ipAddress;
      }
      /**
       * @param ipAddress the ipAddress to set
       */
      protected void setIpAddress(InetAddress ipAddress) {
          this.sentByHostPort.setHost( new Host(ipAddress.getHostAddress()));
          this.ipAddress = ipAddress;
      }
  
      /**
       * Set the sentby string. This is used for stamping outgoing messages sent
       * from this listening point.
       *
       * @param sentBy
       */
      public void setSentBy(String sentBy) throws ParseException {
  
          int ind = sentBy.indexOf(":");
          if (ind == -1) {
              this.sentByHostPort = new HostPort();
              this.sentByHostPort.setHost(new Host(sentBy));
          } else {
              this.sentByHostPort = new HostPort();
              this.sentByHostPort.setHost(new Host(sentBy.substring(0, ind)));
              String portStr = sentBy.substring(ind + 1);
              try {
                  int port = Integer.parseInt(portStr);
                  this.sentByHostPort.setPort(port);
              } catch (NumberFormatException ex) {
                  throw new ParseException("Bad format encountered at ", ind);
              }
          }
          this.sentBySet = true;
          this.sentBy = sentBy;
  
      }
  
      /**
       * Get the sentby string.
       *
       */
      public String getSentBy() {
          if ( this.sentBy == null && this.sentByHostPort != null) {
              this.sentBy = this.sentByHostPort.toString();
          }
          return this.sentBy;
      }
  
      ////////////////////////////////////////////////////////////////////////////////////////
      // Abstract methods
      ///////////////////////////////////////////////////////////////////////////////////////
      /**
       * Get the SIP Stack.
       *
       * @return the sip stack.
       */
      public abstract SIPTransactionStack getSIPStack();
  
      /**
       * Create a message channel for the specified host/port.
       *
       * @return New MessageChannel for this processor.
       */
      public abstract MessageChannel createMessageChannel(HostPort targetHostPort)
              throws IOException;
  
      /**
       * Create a message channel for the specified host/port.
       *
       * @return New MessageChannel for this processor.
       */
      public abstract MessageChannel createMessageChannel(InetAddress targetHost,
              int port) throws IOException;
  
  
      /**
       * Start our thread.
       */
      public abstract void start() throws IOException;
  
      /**
       * Stop method.
       */
      public abstract void stop();
  
      /**
       * Default target port used by this processor. This is 5060 for TCP / UDP
       */
      public abstract int getDefaultTargetPort();
  
      /**
       * Flags whether this processor is secure or not.
       */
      public abstract boolean isSecure();
  
      /**
       * Maximum number of bytes that this processor can handle.
       */
      public abstract int getMaximumMessageSize();
  
      /**
       * Return true if there are pending messages to be processed (which prevents
       * the message channel from being closed).
       */
      public abstract boolean inUse();
  
  
  
      /**
       * Run method.
       */
      public abstract void run();
  
      /**
       * @return Returns the sentBySet.
       */
      public boolean isSentBySet() {
          return sentBySet;
      }
  
  
      /**
       * Get the defalt port for the message processor.
       *
       * @param transport
       * @return -- the default port for the message processor.
       */
  
      public static int getDefaultPort(String transport) {
  
          return transport.equalsIgnoreCase("TLS")?5061:5060;
      }
  
  
  
  }
  