/* * 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 gov.nist.javax.sip.stack; import gov.nist.core.CommonLogger; import gov.nist.core.Host; import gov.nist.core.HostPort; import gov.nist.core.InternalErrorHandler; import gov.nist.core.LogWriter; import gov.nist.core.StackLogger; import gov.nist.javax.sip.ListeningPointImpl; import gov.nist.javax.sip.header.Via; import java.io.IOException; import java.net.InetAddress; import java.text.ParseException; import javax.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.20 $ $Date: 2010-12-02 22:04:15 $ * * @author M. Ranganathan <br/> * */ public abstract class MessageProcessor { private static StackLogger logger = CommonLogger.getLogger(MessageProcessor.class); /** * 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 ( logger.isLoggingEnabled()) { this.logger.logError("getListeningPoint" + this + " returning null listeningpoint"); } } return listeningPoint; } public void setListeningPoint(ListeningPointImpl lp) { if ( logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) { this.logger.logDebug("setListeningPoint" + this + " listeningPoint = " + lp); } if ( lp.getPort() != this.getPort()) InternalErrorHandler.handleException ("lp mismatch with provider",logger); 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(); /** * @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; } }