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;
  
  import gov2.nist.core.ServerLogger;
  import gov2.nist.core.StackLogger;
  import gov2.nist.core.net.AddressResolver;
  import gov2.nist.core.net.NetworkLayer;
  import gov2.nist.core.net.SslNetworkLayer;
  import gov2.nist.javax2.sip.clientauthutils.AccountManager;
  import gov2.nist.javax2.sip.clientauthutils.AuthenticationHelper;
  import gov2.nist.javax2.sip.clientauthutils.AuthenticationHelperImpl;
  import gov2.nist.javax2.sip.clientauthutils.SecureAccountManager;
  import gov2.nist.javax2.sip.parser.StringMsgParser;
  import gov2.nist.javax2.sip.stack.DefaultMessageLogFactory;
  import gov2.nist.javax2.sip.stack.DefaultRouter;
  import gov2.nist.javax2.sip.stack.MessageProcessor;
  import gov2.nist.javax2.sip.stack.SIPTransactionStack;
  
  import java.io.BufferedReader;
  import java.io.IOException;
  import java.io.InputStream;
  import java.io.InputStreamReader;
  import java.lang.reflect.Constructor;
  import java.lang.reflect.InvocationTargetException;
  import java.net.InetAddress;
  import java.util.Hashtable;
  import java.util.LinkedList;
  import java.util.Properties;
  import java.util.StringTokenizer;
  import java.util.concurrent.Semaphore;
  import java.util.concurrent.TimeUnit;
  
  import javax2.sip.InvalidArgumentException;
  import javax2.sip.ListeningPoint;
  import javax2.sip.ObjectInUseException;
  import javax2.sip.PeerUnavailableException;
  import javax2.sip.ProviderDoesNotExistException;
  import javax2.sip.SipException;
  import javax2.sip.SipListener;
  import javax2.sip.SipProvider;
  import javax2.sip.SipStack;
  import javax2.sip.TransportNotSupportedException;
  import javax2.sip.address.Router;
  import javax2.sip.header.HeaderFactory;
  import javax2.sip.message.Request;
  
  /**
   * Implementation of SipStack.
   * 
   * The JAIN-SIP stack is initialized by a set of properties (see the JAIN SIP
   * documentation for an explanation of these properties
   * {@link javax2.sip.SipStack} ). In addition to these, the following are
   * meaningful properties for the NIST SIP stack (specify these in the property
   * array when you create the JAIN-SIP statck):
   * <ul>
   * 
   * <li><b>gov2.nist.javax2.sip.TRACE_LEVEL = integer </b><br/>
   * <b> Use of this property is still supported but deprecated. Please use
   * gov2.nist.javax2.sip.STACK_LOGGER and gov2.nist.javax2.sip.SERVER_LOGGER for
   * integration with logging frameworks and for custom formatting of log records.
   * </b> This property is used by the built in log4j based logger. You can use
   * the standard log4j level names here (i.e. ERROR, INFO, WARNING, OFF, DEBUG,
   * TRACE) If this is set to INFO or above, then incoming valid messages are
   * logged in SERVER_LOG. If you set this to 32 and specify a DEBUG_LOG then vast
   * amounts of trace information will be dumped in to the specified DEBUG_LOG.
   * The server log accumulates the signaling trace. <a href="{@docRoot}
   * /tools/tracesviewer/tracesviewer.html"> This can be viewed using the trace
   * viewer tool .</a> Please send us both the server log and debug log when
   * reporting non-obvious problems. You can also use the strings DEBUG or INFO
   * for level 32 and 16 respectively. If the value of this property is set to
   * LOG4J, then the effective log levels are determined from the log4j settings
   * file (e.g. log4j.properties). The logger name for the stack is specified
   * using the gov2.nist.javax2.sip.LOG4J_LOGGER_NAME property. By default log4j
   * logger name for the stack is the same as the stack name. For example, <code>
   * properties.setProperty("gov2.nist.javax2.sip.TRACE_LEVEL", "LOG4J");
   * properties.setProperty("gov2.nist.javax2.sip.LOG4J_LOGGER_NAME", "SIPStackLogger");
   * </code> allows you to now control logging in the stack entirely using log4j
   * facilities.</li>
   * 
   * <li><b>gov2.nist.javax2.sip.LOG_FACTORY = classpath </b> <b> Use of this
   * property is still supported but deprecated. Please use
   * gov2.nist.javax2.sip.STACK_LOGGER and gov2.nist.javax2.sip.SERVER_LOGGER for
   * integration with logging frameworks and for custom formatting of log records.
   * </b> <br/>
   * The fully qualified classpath for an implementation of the MessageLogFactory.
   * The stack calls the MessageLogFactory functions to format the log for
   * messages that are received or sent. This function allows you to log auxiliary
   * information related to the application or environmental conditions into the
   * log stream. The log factory must have a default constructor.</li>
   * 
   * <li><b>gov2.nist.javax2.sip.SERVER_LOG = fileName </b><br/>
   * <b> Use of this property is still supported but deprecated. Please use
   * gov2.nist.javax2.sip.STACK_LOGGER and gov2.nist.javax2.sip.SERVER_LOGGER for
   * integration with logging frameworks and for custom formatting of log records.
   * </b> Log valid incoming messages here. If this is left null AND the
   * TRACE_LEVEL is above INFO (or TRACE) then the messages are printed to stdout.
   * Otherwise messages are logged in a format that can later be viewed using the
   * trace viewer application which is located in the tools/tracesviewer
   * directory. <font color=red> Mail this to us with bug reports. </font></li>
   * 
   * <li><b>gov2.nist.javax2.sip.DEBUG_LOG = fileName </b> <b> Use of this property
   * is still supported but deprecated. Please use gov2.nist.javax2.sip.STACK_LOGGER
   * and gov2.nist.javax2.sip.SERVER_LOGGER for integration with logging frameworks
   * and for custom formatting of log records. </b> <br/>
   * Where the debug log goes. <font color=red> Mail this to us with bug reports.
   * </font></li>
   * 
   * <li><b>gov2.nist.javax2.sip.LOG_MESSAGE_CONTENT = true|false </b><br/>
   * Set true if you want to capture content into the log. Default is false. A bad
   * idea to log content if you are using SIP to push a lot of bytes through TCP.</li>
   * 
   * <li><b>gov2.nist.javax2.sip.LOG_STACK_TRACE_ON_MESSAGE_SEND = true|false </b><br/>
   * Set true if you want to to log a stack trace at INFO level for each message
   * send. This is really handy for debugging.</li>
   * 
   * <li><b>gov2.nist.javax2.sip.STACK_LOGGER = full path name to the class
   * implementing gov2.nist.core.StackLogger interface</b><br/>
   * If this property is defined the sip stack will try to instantiate it through
   * a no arg constructor. This allows to use different logging implementations
   * than the ones provided by default to log what happens within the stack while
   * processing SIP messages. If this property is not defined, the default sip
   * stack LogWriter will be used for logging</li>
   * 
   * <li><b>gov2.nist.javax2.sip.SERVER_LOGGER = full path name to the class
   * implementing gov2.nist.core.ServerLogger interface</b><br/>
   * If this property is defined the sip stack will try to instantiate it through
   * a no arg constructor. This allows to use different logging implementations
   * than the ones provided by default to log sent/received messages by the sip
   * stack. If this property is not defined, the default sip stack ServerLog will
   * be used for logging</li>
   * 
   * <li><b>gov2.nist.javax2.sip.AUTOMATIC_DIALOG_ERROR_HANDLING = [true|false] </b>
   * <br/>
   * Default is <it>true</it>. This is also settable on a per-provider basis. This
   * flag is set to true by default. When set
   * to <it>false</it> the following behaviors are enabled:
   * 
   * 
   * <li>Turn off Merged requests Loop Detection: The following behavior is turned off
   * : If the request has no tag in the To header field, the UAS core MUST check
   * the request against ongoing transactions. If the From tag, Call-ID, and CSeq
   * exactly match those associated with an ongoing transaction, but the request
   * does not match that transaction (based on the matching rules in Section
   * 17.2.3), the UAS core SHOULD generate a 482 (Loop Detected) response and pass
   * it to the server transaction.
   * 
   * </ul>
   * 
   * <li><b>gov2.nist.javax2.sip.IS_BACK_TO_BACK_USER_AGENT = [true|false] </b> <br/>
   * Default is <it>false</it> This property controls a setting on the Dialog
   * objects that the stack manages. Pure B2BUA applications should set this flag
   * to <it>true</it>. This property can also be set on a per-dialog basis.
   * Setting this to <it>true</it> imposes serialization on re-INVITE and makes
   * the sending of re-INVITEs asynchronous. The sending of re-INVITE is
   * controlled as follows : If the previous in-DIALOG request was an invite
   * ClientTransaction then the next re-INVITEs that uses the dialog will wait
   * till an ACK has been sent before admitting the new re-INVITE. If the previous
   * in-DIALOG transaction was a INVITE ServerTransaction then Dialog waits for
   * ACK before re-INVITE is allowed to be sent. If a dialog is not ACKed within
   * 32 seconds, then the dialog is torn down and a BYE sent to the peer.</li>
   * <li><b>gov2.nist.javax2.sip.MAX_MESSAGE_SIZE = integer</b> <br/>
   * Maximum size of content that a TCP connection can read. Must be at least 4K.
   * Default is "infinity" -- ie. no limit. This is to prevent DOS attacks
   * launched by writing to a TCP connection until the server chokes.</li>
   * 
   * <li><b>gov2.nist.javax2.sip.DELIVER_TERMINATED_EVENT_FOR_NULL_DIALOG = [true|false] </b><br/>
   * If set to false (the default), the application does NOT get notified when a Dialog in the
   * NULL state is terminated. ( Dialogs in the NULL state are not associated with an actual SIP Dialog.
   * They are a programming convenience. A Dialog is in the NULL state before the first response for the 
   * Dialog forming Transaction). If set to true, the SipListener will get a DialogTerminatedEvent
   * when a Dialog in the NULL state is terminated. 
   * </li>
   * 
   * <li><b>gov2.nist.javax2.sip.CACHE_SERVER_CONNECTIONS = [true|false] </b> <br/>
   * Default value is true. Setting this to false makes the Stack close the server
   * socket after a Server Transaction goes to the TERMINATED state. This allows a
   * server to protectect against TCP based Denial of Service attacks launched by
   * clients (ie. initiate hundreds of client transactions). If true (default
   * action), the stack will keep the socket open so as to maximize performance at
   * the expense of Thread and memory resources - leaving itself open to DOS
   * attacks.</li>
   * 
   * 
   * <li><b>gov2.nist.javax2.sip.CACHE_CLIENT_CONNECTIONS = [true|false] </b> <br/>
   * Default value is true. Setting this to false makes the Stack close the server
   * socket after a Client Transaction goes to the TERMINATED state. This allows a
   * client release any buffers threads and socket connections associated with a
   * client transaction after the transaction has terminated at the expense of
   * performance.</li>
   * 
   * <li><b>gov2.nist.javax2.sip.THREAD_POOL_SIZE = integer </b> <br/>
   * Concurrency control for number of simultaneous active threads. If
   * unspecificed, the default is "infinity". This feature is useful if you are
   * trying to build a container.
   * <ul>
   * <li>
   * <li>If this is not specified, <b> and the listener is re-entrant</b>, each
   * event delivered to the listener is run in the context of a new thread.</li>
   * <li>If this is specified and the listener is re-entrant, then the stack will
   * run the listener using a thread from the thread pool. This allows you to
   * manage the level of concurrency to a fixed maximum. Threads are pre-allocated
   * when the stack is instantiated.</li>
   * <li>If this is specified and the listener is not re-entrant, then the stack
   * will use the thread pool thread from this pool to parse and manage the state
   * machine but will run the listener in its own thread.</li>
   * </ul>
   * 
   * <li><b>gov2.nist.javax2.sip.REENTRANT_LISTENER = true|false </b> <br/>
   * Default is false. Set to true if the listener is re-entrant. If the listener
   * is re-entrant then the stack manages a thread pool and synchronously calls
   * the listener from the same thread which read the message. Multiple
   * transactions may concurrently receive messages and this will result in
   * multiple threads being active in the listener at the same time. The listener
   * has to be written with this in mind. <b> If you want good performance on a
   * multithreaded machine write your listener to be re-entrant and set this
   * property to be true </b></li>
   * 
   * <li><b>gov2.nist.javax2.sip.MAX_CONNECTIONS = integer </b> <br/>
   * Max number of simultaneous TCP connections handled by stack.</li>
   * 
   * <li><b>gov2.nist.javax2.sip.MAX_SERVER_TRANSACTIONS = integer </b> <br/>
   * Maximum size of server transaction table. The low water mark is 80% of the
   * high water mark. Requests are selectively dropped in the lowater mark to
   * highwater mark range. Requests are unconditionally accepted if the table is
   * smaller than the low water mark. The default highwater mark is 5000</li>
   * 
   * <li><b>gov2.nist.javax2.sip.MAX_CLIENT_TRANSACTIONS = integer </b> <br/>
   * Max number of active client transactions before the caller blocks and waits
   * for the number to drop below a threshold. Default is unlimited, i.e. the
   * caller never blocks and waits for a client transaction to become available
   * (i.e. it does its own resource management in the application).</li>
   * 
   * <li><b>gov2.nist.javax2.sip.PASS_INVITE_NON_2XX_ACK_TO_LISTENER = true|false
   * </b> <br/>
   * If true then the listener will see the ACK for non-2xx responses for server
   * transactions. This is not standard behavior per RFC 3261 (INVITE server
   * transaction state machine) but this is a useful flag for testing. The TCK
   * uses this flag for example.</li>
   * 
   * <li><b>gov2.nist.javax2.sip.MAX_LISTENER_RESPONSE_TIME = Integer </b> <br/>
   * Max time (seconds) before sending a response to a server transaction. If a
   * response is not sent within this time period, the transaction will be deleted
   * by the stack. Default time is "infinity" - i.e. if the listener never
   * responds, the stack will hang on to a reference for the transaction and
   * result in a memory leak.
   * 
   * <li><b>gov2.nist.javax2.sip.DELIVER_TERMINATED_EVENT_FOR_ACK = [true|false]</b>
   * <br/>
   * Default is <it>false</it>. ACK Server Transaction is a Pseuedo-transaction.
   * If you want termination notification on ACK transactions (so all server
   * transactions can be handled uniformly in user code during cleanup), then set
   * this flag to <it>true</it>.</li>
   * 
   * <li><b>gov2.nist.javax2.sip.READ_TIMEOUT = integer </b> <br/>
   * This is relevant for incoming TCP connections to prevent starvation at the
   * server. This defines the timeout in miliseconds between successive reads
   * after the first byte of a SIP message is read by the stack. All the sip
   * headers must be delivered in this interval and each successive buffer must be
   * of the content delivered in this interval. Default value is -1 (ie. the stack
   * is wide open to starvation attacks) and the client can be as slow as it wants
   * to be.</li>
   * 
   * <li><b>gov2.nist.javax2.sip.NETWORK_LAYER = classpath </b> <br/>
   * This is an EXPERIMENTAL property (still under active devlopment). Defines a
   * network layer that allows a client to have control over socket allocations
   * and monitoring of socket activity. A network layer should implement
   * gov2.nist.core.net.NetworkLayer. The default implementation simply acts as a
   * wrapper for the standard java.net socket layer. This functionality is still
   * under active development (may be extended to support security and other
   * features).</li>
   * 
   * <li><b>gov2.nist.javax2.sip.ADDRESS_RESOLVER = classpath </b><br/>
   * The fully qualified class path for an implementation of the AddressResolver
   * interface. The AddressResolver allows you to support lookup schemes for
   * addresses that are not directly resolvable to IP adresses using
   * getHostByName. Specifying your own address resolver allows you to customize
   * address lookup. The default address resolver is a pass-through address
   * resolver (i.e. just returns the input string without doing a resolution). See
   * gov2.nist.javax2.sip.DefaultAddressResolver.</li>
   * 
   * <li><b>gov2.nist.javax2.sip.AUTO_GENERATE_TIMESTAMP= [true| false] </b><br/>
   * (default is false) Automatically generate a getTimeOfDay timestamp for a
   * retransmitted request if the original request contained a timestamp. This is
   * useful for profiling.</li>
   * 
   * <li><b>gov2.nist.javax2.sip.THREAD_AUDIT_INTERVAL_IN_MILLISECS = long </b> <br/>
   * Defines how often the application intends to audit the SIP Stack about the
   * health of its internal threads (the property specifies the time in
   * miliseconds between successive audits). The audit allows the application to
   * detect catastrophic failures like an internal thread terminating because of
   * an exception or getting stuck in a deadlock condition. Events like these will
   * make the stack inoperable and therefore require immediate action from the
   * application layer (e.g., alarms, traps, reboot, failover, etc.) Thread audits
   * are disabled by default. If this property is not specified, audits will
   * remain disabled. An example of how to use this property is in
   * src/examples/threadaudit.</li>
   * 
   * 
   * 
   * <li><b>gov2.nist.javax2.sip.COMPUTE_CONTENT_LENGTH_FROM_MESSAGE_BODY =
   * [true|false] </b> <br/>
   * Default is <it>false</it> If set to <it>true</it>, when you are creating a
   * message from a <it>String</it>, the MessageFactory will compute the content
   * length from the message content and ignore the provided content length
   * parameter in the Message. Otherwise, it will use the content length supplied
   * and generate a parse exception if the content is truncated.
   * 
   * <li><b>gov2.nist.javax2.sip.CANCEL_CLIENT_TRANSACTION_CHECKED = [true|false]
   * </b> <br/>
   * Default is <it>true</it>. This flag is added in support of load balancers or
   * failover managers where you may want to cancel ongoing transactions from a
   * different stack than the original stack. If set to <it>false</it> then the
   * CANCEL client transaction is not checked for the existence of the INVITE or
   * the state of INVITE when you send the CANCEL request. Hence you can CANCEL an
   * INVITE from a different stack than the INVITE. You can also create a CANCEL
   * client transaction late and send it out after the INVITE server transaction
   * has been Terminated. Clearly this will result in protocol errors. Setting the
   * flag to true ( default ) enables you to avoid common protocol errors.</li>
   * 
   * <li><b>gov2.nist.javax2.sip.IS_BACK_TO_BACK_USER_AGENT = [true|false] </b> <br/>
   * Default is <it>false</it> This property controls a setting on the Dialog
   * objects that the stack manages. Pure B2BUA applications should set this flag
   * to <it>true</it>. This property can also be set on a per-dialog basis.
   * Setting this to <it>true</it> imposes serialization on re-INVITE and makes
   * the sending of re-INVITEs asynchronous. The sending of re-INVITE is
   * controlled as follows : If the previous in-DIALOG request was an invite
   * ClientTransaction then the next re-INVITEs that uses the dialog will wait
   * till an ACK has been sent before admitting the new re-INVITE. If the previous
   * in-DIALOG transaction was a INVITE ServerTransaction then Dialog waits for
   * ACK before re-INVITE is allowed to be sent. If a dialog is not ACKed within
   * 32 seconds, then the dialog is torn down and a BYE sent to the peer.</li>
   * 
   * 
   * <li><b>gov2.nist.javax2.sip.RECEIVE_UDP_BUFFER_SIZE = int </b> <br/>
   * Default is <it>8*1024</it>. This property control the size of the UDP buffer
   * used for SIP messages. Under load, if the buffer capacity is overflown the
   * messages are dropped causing retransmissions, further increasing the load and
   * causing even more retransmissions. Good values to this property for servers
   * is a big number in the order of 8*8*1024.</li>
   * 
   * <li><b>gov2.nist.javax2.sip.SEND_UDP_BUFFER_SIZE = int </b> <br/>
   * Default is <it>8*1024</it>. This property control the size of the UDP buffer
   * used for SIP messages. Under load, if the buffer capacity is overflown the
   * messages are dropped causing retransmissions, further increasing the load and
   * causing even more retransmissions. Good values to this property for servers
   * is a big number in the order of 8*8*1024 or higher.</li>
   * 
   * <li><b>gov2.nist.javax2.sip.CONGESTION_CONTROL_ENABLED = boolean </b> Defailt
   * is true. If set to true stack will enforce queue length limitation for UDP.
   * The Max queue size is 5000 messages. The minimum queue size is 2500 messages.
   * </li>
   * 
   * <li><b>gov2.nist.javax2.sip.DELIVER_UNSOLICITED_NOTIFY = [true|false] </b> <br/>
   * Default is <it>false</it>. This flag is added to allow Sip Listeners to
   * receive all NOTIFY requests including those that are not part of a valid
   * dialog.</li>
   * 
   * <li><b>gov2.nist.javax2.sip.REJECT_STRAY_RESPONSES = [true|false] </b> Default
   * is <it>false</it> A flag that checks responses to test whether the response
   * corresponds to a via header that was previously generated by us. Note that
   * setting this flag implies that the stack will take control over setting the
   * VIA header for Sip Requests sent through the stack. The stack will attach a
   * suffix to the VIA header branch and check any response arriving at the stack
   * to see if that response suffix is present. If it is not present, then the
   * stack will silently drop the response.</li>
   * 
   * <li><b>gov2.nist.javax2.sip.MAX_FORK_TIME_SECONDS = integer </b> Maximum time for which the original 
   * transaction for which a forked response is received is tracked. This property
   * is only relevant to Dialog Stateful applications ( User Agents or B2BUA).
   * When a forked response is received in this time interval from when the original
   * INVITE client transaction was sent, the stack will place the original INVITE
   * client transction in the ResponseEventExt and deliver that to the application.
   * The event handler can get the original transaction from this event. </li>
   * 
   *  * <li><b>gov2.nist.javax2.sip.TLS_CLIENT_PROTOCOLS = String </b>
   *  Comma-separated list of protocols to use when creating outgoing TLS connections.
   *  The default is "SSLv3, SSLv2Hello, TLSv1".
   *  Some servers do not support SSLv2Hello, so override to "SSLv3, TLSv1". 
   * </li>
  
   * <li><b>javax2.net.ssl.keyStore = fileName </b> <br/>
   * Default is <it>NULL</it>. If left undefined the keyStore and trustStore will
   * be left to the java runtime defaults. If defined, any TLS sockets created
   * (client and server) will use the key store provided in the fileName. The
   * trust store will default to the same store file. A password must be provided
   * to access the keyStore using the following property: <br>
   * <code>
   * properties.setProperty("javax2.net.ssl.keyStorePassword", "&lt;password&gt;");
   * </code> <br>
   * The trust store can be changed, to a separate file with the following
   * setting: <br>
   * <code>
   * properties.setProperty("javax2.net.ssl.trustStore", "&lt;trustStoreFileName location&gt;");
   * </code> <br>
   * If the trust store property is provided the password on the trust store must
   * be the same as the key store. <br>
   * <br>
   * <b> Note that the stack supports the extensions that are defined in
   * SipStackExt. These will be supported in the next release of JAIN-SIP. You
   * should only use the extensions that are defined in this class. </b>
   * 
   * 
   * @version 1.2 $Revision: 1.115 $ $Date: 2010/01/10 00:13:14 $
   * 
   * @author M. Ranganathan <br/>
   * 
   * 
   * 
   * 
   */
  public class SipStackImpl extends SIPTransactionStack implements
  		javax2.sip.SipStack, SipStackExt {
  
  	private EventScanner eventScanner;
  
  	private Hashtable<String, ListeningPointImpl> listeningPoints;
  
  	private LinkedList<SipProviderImpl> sipProviders;
  
  	/**
  	 * Max datagram size.
  	 */
  	public static final Integer MAX_DATAGRAM_SIZE = 8 * 1024;
  
  	// Flag to indicate that the listener is re-entrant and hence
  	// Use this flag with caution.
  	boolean reEntrantListener;
  
  	SipListener sipListener;
  
  	// If set to true then a transaction terminated event is
  	// delivered for ACK transactions.
  	boolean deliverTerminatedEventForAck = false;
  
  	// If set to true then the application want to receive
  	// unsolicited NOTIFYs, ie NOTIFYs that don't match any dialog
  	boolean deliverUnsolicitedNotify = false;
  
  	// Stack semaphore (global lock).
  	private Semaphore stackSemaphore = new Semaphore(1);
  
  	// RFC3261: TLS_RSA_WITH_AES_128_CBC_SHA MUST be supported
  	// RFC3261: TLS_RSA_WITH_3DES_EDE_CBC_SHA SHOULD be supported for backwards
  	// compat
  	private String[] cipherSuites = {
  			"TLS_RSA_WITH_AES_128_CBC_SHA", // AES difficult to get with
  											// c++/Windows
  			// "TLS_RSA_WITH_3DES_EDE_CBC_SHA", // Unsupported by Sun impl,
  			"SSL_RSA_WITH_3DES_EDE_CBC_SHA", // For backwards comp., C++
  
  			// JvB: patch from Sebastien Mazy, issue with mismatching
  			// ciphersuites
                          // Below ciphersuites are not supported anymore with Android 6.0
                          //"TLS_DH_anon_WITH_AES_128_CBC_SHA",
                          //"SSL_DH_anon_WITH_3DES_EDE_CBC_SHA",
          };
  
  	// Supported protocols for TLS client: can be overridden by application
  	private String[] enabledProtocols = {
  			"SSLv3",
  			"SSLv2Hello",
  			"TLSv1"
  	};
  
  	/**
  	 * Creates a new instance of SipStackImpl.
  	 */
  
  	protected SipStackImpl() {
  		super();
  		NistSipMessageFactoryImpl msgFactory = new NistSipMessageFactoryImpl(
  				this);
  		super.setMessageFactory(msgFactory);
  		this.eventScanner = new EventScanner(this);
  		this.listeningPoints = new Hashtable<String, ListeningPointImpl>();
  		this.sipProviders = new LinkedList<SipProviderImpl>();
  
  	}
  
  	/**
  	 * ReInitialize the stack instance.
  	 */
  	private void reInitialize() {
  		super.reInit();
  		this.eventScanner = new EventScanner(this);
  		this.listeningPoints = new Hashtable<String, ListeningPointImpl>();
  		this.sipProviders = new LinkedList<SipProviderImpl>();
  		this.sipListener = null;
  
  	}
  
  	/**
  	 * Return true if automatic dialog support is enabled for this stack.
  	 * 
  	 * @return boolean, true if automatic dialog support is enabled for this
  	 *         stack
  	 */
  	boolean isAutomaticDialogSupportEnabled() {
  		return super.isAutomaticDialogSupportEnabled;
  	}
  
  	/**
  	 * Constructor for the stack.
  	 * 
  	 * @param configurationProperties
  	 *            -- stack configuration properties including NIST-specific
  	 *            extensions.
  	 * @throws PeerUnavailableException
  	 */
  	public SipStackImpl(Properties configurationProperties)
  			throws PeerUnavailableException {
  		this();
  		String address = configurationProperties
  				.getProperty("javax2.sip.IP_ADDRESS");
  		try {
  			/** Retrieve the stack IP address */
  			if (address != null) {
  				// In version 1.2 of the spec the IP address is
  				// associated with the listening point and
  				// is not madatory.
  				super.setHostAddress(address);
  
  			}
  		} catch (java.net.UnknownHostException ex) {
  			throw new PeerUnavailableException("bad address " + address);
  		}
  
  		/** Retrieve the stack name */
  		String name = configurationProperties
  				.getProperty("javax2.sip.STACK_NAME");
  		if (name == null)
  			throw new PeerUnavailableException("stack name is missing");
  		super.setStackName(name);
  		String stackLoggerClassName = configurationProperties
  				.getProperty("gov2.nist.javax2.sip.STACK_LOGGER");
  		// To log debug messages.
  		if (stackLoggerClassName == null)
  			stackLoggerClassName = "gov2.nist.core.LogWriter";
  			try {
  				Class<?> stackLoggerClass = Class.forName(stackLoggerClassName);
  				Class<?>[] constructorArgs = new Class[0];
  				Constructor<?> cons = stackLoggerClass
  						.getConstructor(constructorArgs);
  				Object[] args = new Object[0];
  				StackLogger stackLogger = (StackLogger) cons.newInstance(args);
  				stackLogger.setStackProperties(configurationProperties);
  				super.setStackLogger(stackLogger);
  			} catch (InvocationTargetException ex1) {
  				throw new IllegalArgumentException(
  						"Cound not instantiate stack logger "
  								+ stackLoggerClassName
  								+ "- check that it is present on the classpath and that there is a no-args constructor defined",
  						ex1);
  			} catch (Exception ex) {
  				throw new IllegalArgumentException(
  						"Cound not instantiate stack logger "
  								+ stackLoggerClassName
  								+ "- check that it is present on the classpath and that there is a no-args constructor defined",
  						ex);
  			}
  
  		String serverLoggerClassName = configurationProperties
  				.getProperty("gov2.nist.javax2.sip.SERVER_LOGGER");
  		// To log debug messages.
  		if (serverLoggerClassName == null)
  			serverLoggerClassName = "gov2.nist.javax2.sip.stack.ServerLog";
  			try {
  				Class<?> serverLoggerClass = Class
  						.forName(serverLoggerClassName);
  				Class<?>[] constructorArgs = new Class[0];
  				Constructor<?> cons = serverLoggerClass
  						.getConstructor(constructorArgs);
  				Object[] args = new Object[0];
  				this.serverLogger = (ServerLogger) cons.newInstance(args);
  				serverLogger.setSipStack(this);
  				serverLogger.setStackProperties(configurationProperties);
  			} catch (InvocationTargetException ex1) {
  				throw new IllegalArgumentException(
  						"Cound not instantiate server logger "
  								+ stackLoggerClassName
  								+ "- check that it is present on the classpath and that there is a no-args constructor defined",
  						ex1);
  			} catch (Exception ex) {
  				throw new IllegalArgumentException(
  						"Cound not instantiate server logger "
  								+ stackLoggerClassName
  								+ "- check that it is present on the classpath and that there is a no-args constructor defined",
  						ex);
  			}
  
  		// Default router -- use this for routing SIP URIs.
  		// Our router does not do DNS lookups.
  		this.outboundProxy = configurationProperties
  				.getProperty("javax2.sip.OUTBOUND_PROXY");
  
  		this.defaultRouter = new DefaultRouter(this, outboundProxy);
  
  		/** Retrieve the router path */
  		String routerPath = configurationProperties
  				.getProperty("javax2.sip.ROUTER_PATH");
  		if (routerPath == null)
  			routerPath = "gov2.nist.javax2.sip.stack.DefaultRouter";
  
  		try {
  			Class<?> routerClass = Class.forName(routerPath);
  			Class<?>[] constructorArgs = new Class[2];
  			constructorArgs[0] = javax2.sip.SipStack.class;
  			constructorArgs[1] = String.class;
  			Constructor<?> cons = routerClass.getConstructor(constructorArgs);
  			Object[] args = new Object[2];
  			args[0] = (SipStack) this;
  			args[1] = outboundProxy;
  			Router router = (Router) cons.newInstance(args);
  			super.setRouter(router);
  		} catch (InvocationTargetException ex1) {
  			getStackLogger()
  					.logError(
  							"could not instantiate router -- invocation target problem",
  							(Exception) ex1.getCause());
  			throw new PeerUnavailableException(
  					"Cound not instantiate router - check constructor", ex1);
  		} catch (Exception ex) {
  			getStackLogger().logError("could not instantiate router",
  					(Exception) ex.getCause());
  			throw new PeerUnavailableException("Could not instantiate router",
  					ex);
  		}
  
  		// The flag that indicates that the default router is to be ignored.
  		String useRouterForAll = configurationProperties
  				.getProperty("javax2.sip.USE_ROUTER_FOR_ALL_URIS");
  		this.useRouterForAll = true;
  		if (useRouterForAll != null) {
  			this.useRouterForAll = "true".equalsIgnoreCase(useRouterForAll);
  		}
  
  		/*
  		 * Retrieve the EXTENSION Methods. These are used for instantiation of
  		 * Dialogs.
  		 */
  		String extensionMethods = configurationProperties
  				.getProperty("javax2.sip.EXTENSION_METHODS");
  
  		if (extensionMethods != null) {
  			java.util.StringTokenizer st = new java.util.StringTokenizer(
  					extensionMethods);
  			while (st.hasMoreTokens()) {
  				String em = st.nextToken(":");
  				if (em.equalsIgnoreCase(Request.BYE)
  						|| em.equalsIgnoreCase(Request.INVITE)
  						|| em.equalsIgnoreCase(Request.SUBSCRIBE)
  						|| em.equalsIgnoreCase(Request.NOTIFY)
  						|| em.equalsIgnoreCase(Request.ACK)
  						|| em.equalsIgnoreCase(Request.OPTIONS))
  					throw new PeerUnavailableException("Bad extension method "
  							+ em);
  				else
  					this.addExtensionMethod(em);
  			}
  		}
  		String keyStoreFile = configurationProperties
  				.getProperty("javax2.net.ssl.keyStore");
  		String trustStoreFile = configurationProperties
  				.getProperty("javax2.net.ssl.trustStore");
  		if (keyStoreFile != null) {
  			if (trustStoreFile == null) {
  				trustStoreFile = keyStoreFile;
  			}
  			String keyStorePassword = configurationProperties
  					.getProperty("javax2.net.ssl.keyStorePassword");
  			try {
  				this.networkLayer = new SslNetworkLayer(trustStoreFile,
  						keyStoreFile, keyStorePassword.toCharArray(),
  						configurationProperties
  								.getProperty("javax2.net.ssl.keyStoreType"));
  			} catch (Exception e1) {
  				getStackLogger().logError(
  						"could not instantiate SSL networking", e1);
  			}
  		}
  
  		// Set the auto dialog support flag.
  		super.isAutomaticDialogSupportEnabled = configurationProperties
  				.getProperty("javax2.sip.AUTOMATIC_DIALOG_SUPPORT", "on")
  				.equalsIgnoreCase("on");
  
  		super.isAutomaticDialogErrorHandlingEnabled = configurationProperties
  					.getProperty("gov2.nist.javax2.sip.AUTOMATIC_DIALOG_ERROR_HANDLING","true")
  					.equals(Boolean.TRUE.toString());
  		if ( super.isAutomaticDialogSupportEnabled ) {
  			super.isAutomaticDialogErrorHandlingEnabled = true;
  		}
  	
  		if (configurationProperties
  				.getProperty("gov2.nist.javax2.sip.MAX_LISTENER_RESPONSE_TIME") != null) {
  			super.maxListenerResponseTime = Integer
  					.parseInt(configurationProperties
  							.getProperty("gov2.nist.javax2.sip.MAX_LISTENER_RESPONSE_TIME"));
  			if (super.maxListenerResponseTime <= 0)
  				throw new PeerUnavailableException(
  						"Bad configuration parameter gov2.nist.javax2.sip.MAX_LISTENER_RESPONSE_TIME : should be positive");
  		} else {
  			super.maxListenerResponseTime = -1;
  		}
  
  		
  
  		this.deliverTerminatedEventForAck = configurationProperties
  				.getProperty(
  						"gov2.nist.javax2.sip.DELIVER_TERMINATED_EVENT_FOR_ACK",
  						"false").equalsIgnoreCase("true");
  
  		this.deliverUnsolicitedNotify = configurationProperties.getProperty(
  				"gov2.nist.javax2.sip.DELIVER_UNSOLICITED_NOTIFY", "false")
  				.equalsIgnoreCase("true");
  
  		String forkedSubscriptions = configurationProperties
  				.getProperty("javax2.sip.FORKABLE_EVENTS");
  		if (forkedSubscriptions != null) {
  			StringTokenizer st = new StringTokenizer(forkedSubscriptions);
  			while (st.hasMoreTokens()) {
  				String nextEvent = st.nextToken();
  				this.forkedEvents.add(nextEvent);
  			}
  		}
  
  		// The following features are unique to the NIST implementation.
  
  		/*
  		 * gets the NetworkLayer implementation, if any. Note that this is a
  		 * NIST only feature.
  		 */
  
  		final String NETWORK_LAYER_KEY = "gov2.nist.javax2.sip.NETWORK_LAYER";
  
  		if (configurationProperties.containsKey(NETWORK_LAYER_KEY)) {
  			String path = configurationProperties
  					.getProperty(NETWORK_LAYER_KEY);
  			try {
  				Class<?> clazz = Class.forName(path);
  				Constructor<?> c = clazz.getConstructor(new Class[0]);
  				networkLayer = (NetworkLayer) c.newInstance(new Object[0]);
  			} catch (Exception e) {
  				throw new PeerUnavailableException(
  						"can't find or instantiate NetworkLayer implementation: "
  								+ path);
  			}
  		}
  
  		final String ADDRESS_RESOLVER_KEY = "gov2.nist.javax2.sip.ADDRESS_RESOLVER";
  
  		if (configurationProperties.containsKey(ADDRESS_RESOLVER_KEY)) {
  			String path = configurationProperties
  					.getProperty(ADDRESS_RESOLVER_KEY);
  			try {
  				Class<?> clazz = Class.forName(path);
  				Constructor<?> c = clazz.getConstructor(new Class[0]);
  				this.addressResolver = (AddressResolver) c
  						.newInstance(new Object[0]);
  			} catch (Exception e) {
  				throw new PeerUnavailableException(
  						"can't find or instantiate AddressResolver implementation: "
  								+ path);
  			}
  		}
  
  		String maxConnections = configurationProperties
  				.getProperty("gov2.nist.javax2.sip.MAX_CONNECTIONS");
  		if (maxConnections != null) {
  			try {
  				this.maxConnections = new Integer(maxConnections).intValue();
  			} catch (NumberFormatException ex) {
  				if (isLoggingEnabled())
  					getStackLogger().logError(
  						"max connections - bad value " + ex.getMessage());
  			}
  		}
  
  		String threadPoolSize = configurationProperties
  				.getProperty("gov2.nist.javax2.sip.THREAD_POOL_SIZE");
  		if (threadPoolSize != null) {
  			try {
  				this.threadPoolSize = new Integer(threadPoolSize).intValue();
  			} catch (NumberFormatException ex) {
  				if (isLoggingEnabled())
  					this.getStackLogger().logError(
  						"thread pool size - bad value " + ex.getMessage());
  			}
  		}
  
  		String serverTransactionTableSize = configurationProperties
  				.getProperty("gov2.nist.javax2.sip.MAX_SERVER_TRANSACTIONS");
  		if (serverTransactionTableSize != null) {
  			try {
  				this.serverTransactionTableHighwaterMark = new Integer(
  						serverTransactionTableSize).intValue();
  				this.serverTransactionTableLowaterMark = this.serverTransactionTableHighwaterMark * 80 / 100;
  				// Lowater is 80% of highwater
  			} catch (NumberFormatException ex) {
  				if (isLoggingEnabled())
  					this.getStackLogger()
  						.logError(
  								"transaction table size - bad value "
  										+ ex.getMessage());
  			}
  		} else {
  			// Issue 256 : consistent with MAX_CLIENT_TRANSACTIONS, if the MAX_SERVER_TRANSACTIONS is not set
  			// we assume the transaction table size can grow unlimited
  			this.unlimitedServerTransactionTableSize = true;
  		}
  
  		String clientTransactionTableSize = configurationProperties
  				.getProperty("gov2.nist.javax2.sip.MAX_CLIENT_TRANSACTIONS");
  		if (clientTransactionTableSize != null) {
  			try {
  				this.clientTransactionTableHiwaterMark = new Integer(
  						clientTransactionTableSize).intValue();
  				this.clientTransactionTableLowaterMark = this.clientTransactionTableLowaterMark * 80 / 100;
  				// Lowater is 80% of highwater
  			} catch (NumberFormatException ex) {
  				if (isLoggingEnabled())
  					this.getStackLogger()
  						.logError(
  								"transaction table size - bad value "
  										+ ex.getMessage());
  			}
  		} else {
  			this.unlimitedClientTransactionTableSize = true;
  		}
  
  		super.cacheServerConnections = true;
  		String flag = configurationProperties
  				.getProperty("gov2.nist.javax2.sip.CACHE_SERVER_CONNECTIONS");
  
  		if (flag != null && "false".equalsIgnoreCase(flag.trim())) {
  			super.cacheServerConnections = false;
  		}
  
  		super.cacheClientConnections = true;
  		String cacheflag = configurationProperties
  				.getProperty("gov2.nist.javax2.sip.CACHE_CLIENT_CONNECTIONS");
  
  		if (cacheflag != null && "false".equalsIgnoreCase(cacheflag.trim())) {
  			super.cacheClientConnections = false;
  		}
  
  		String readTimeout = configurationProperties
  				.getProperty("gov2.nist.javax2.sip.READ_TIMEOUT");
  		if (readTimeout != null) {
  			try {
  
  				int rt = Integer.parseInt(readTimeout);
  				if (rt >= 100) {
  					super.readTimeout = rt;
  				} else {
  					System.err.println("Value too low " + readTimeout);
  				}
  			} catch (NumberFormatException nfe) {
  				// Ignore.
  				if (isLoggingEnabled())
  					getStackLogger().logError("Bad read timeout " + readTimeout);
  			}
  		}
  
  		// Get the address of the stun server.
  
  		String stunAddr = configurationProperties
  				.getProperty("gov2.nist.javax2.sip.STUN_SERVER");
  
  		if (stunAddr != null)
  			if (isLoggingEnabled())
  				this.getStackLogger().logWarning(
  					"Ignoring obsolete property "
  							+ "gov2.nist.javax2.sip.STUN_SERVER");
  
  		String maxMsgSize = configurationProperties
  				.getProperty("gov2.nist.javax2.sip.MAX_MESSAGE_SIZE");
  
  		try {
  			if (maxMsgSize != null) {
  				super.maxMessageSize = new Integer(maxMsgSize).intValue();
  				if (super.maxMessageSize < 4096)
  					super.maxMessageSize = 4096;
  			} else {
  				// Allow for "infinite" size of message
  				super.maxMessageSize = 0;
  			}
  		} catch (NumberFormatException ex) {
  			if (isLoggingEnabled())
  				getStackLogger().logError(
  					"maxMessageSize - bad value " + ex.getMessage());
  		}
  
  		String rel = configurationProperties
  				.getProperty("gov2.nist.javax2.sip.REENTRANT_LISTENER");
  		this.reEntrantListener = (rel != null && "true".equalsIgnoreCase(rel));
  
  		// Check if a thread audit interval is specified
  		String interval = configurationProperties
  				.getProperty("gov2.nist.javax2.sip.THREAD_AUDIT_INTERVAL_IN_MILLISECS");
  		if (interval != null) {
  			try {
  				// Make the monitored threads ping the auditor twice as fast as
  				// the audits
  				getThreadAuditor().setPingIntervalInMillisecs(
  						Long.valueOf(interval).longValue() / 2);
  			} catch (NumberFormatException ex) {
  				if (isLoggingEnabled())
  					getStackLogger().logError(
  						"THREAD_AUDIT_INTERVAL_IN_MILLISECS - bad value ["
  								+ interval + "] " + ex.getMessage());
  			}
  		}
  
  		// JvB: added property for testing
  		this
  				.setNon2XXAckPassedToListener(Boolean
  						.valueOf(
  								configurationProperties
  										.getProperty(
  												"gov2.nist.javax2.sip.PASS_INVITE_NON_2XX_ACK_TO_LISTENER",
  												"false")).booleanValue());
  
  		this.generateTimeStampHeader = Boolean.valueOf(
  				configurationProperties.getProperty(
  						"gov2.nist.javax2.sip.AUTO_GENERATE_TIMESTAMP", "false"))
  				.booleanValue();
  
  		String messageLogFactoryClasspath = configurationProperties
  				.getProperty("gov2.nist.javax2.sip.LOG_FACTORY");
  		if (messageLogFactoryClasspath != null) {
  			try {
  				Class<?> clazz = Class.forName(messageLogFactoryClasspath);
  				Constructor<?> c = clazz.getConstructor(new Class[0]);
  				this.logRecordFactory = (LogRecordFactory) c
  						.newInstance(new Object[0]);
  			} catch (Exception ex) {
  				if (isLoggingEnabled())
  					getStackLogger()
  						.logError(
  								"Bad configuration value for LOG_FACTORY -- using default logger");
  				this.logRecordFactory = new DefaultMessageLogFactory();
  			}
  
  		} else {
  			this.logRecordFactory = new DefaultMessageLogFactory();
  		}
  
  		boolean computeContentLength = configurationProperties.getProperty(
  				"gov2.nist.javax2.sip.COMPUTE_CONTENT_LENGTH_FROM_MESSAGE_BODY",
  				"false").equalsIgnoreCase("true");
  		StringMsgParser
  				.setComputeContentLengthFromMessage(computeContentLength);
  
  		String tlsClientProtocols = configurationProperties.getProperty(
  				"gov2.nist.javax2.sip.TLS_CLIENT_PROTOCOLS");
  		if (tlsClientProtocols != null)
  		{
  			StringTokenizer st = new StringTokenizer(tlsClientProtocols, " ,");
  			String[] protocols = new String[st.countTokens()];
  			
  			int i=0;
  			while (st.hasMoreTokens()) {
  				protocols[i++] = st.nextToken();
  			}
  			this.enabledProtocols = protocols;
  		}
  
  		super.rfc2543Supported = configurationProperties.getProperty(
  				"gov2.nist.javax2.sip.RFC_2543_SUPPORT_ENABLED", "true")
  				.equalsIgnoreCase("true");
  
  		super.cancelClientTransactionChecked = configurationProperties
  				.getProperty(
  						"gov2.nist.javax2.sip.CANCEL_CLIENT_TRANSACTION_CHECKED",
  						"true").equalsIgnoreCase("true");
  		super.logStackTraceOnMessageSend = configurationProperties.getProperty(
  				"gov2.nist.javax2.sip.LOG_STACK_TRACE_ON_MESSAGE_SEND", "false")
  				.equalsIgnoreCase("true");
  		if (isLoggingEnabled())
  			getStackLogger().logDebug(
  				"created Sip stack. Properties = " + configurationProperties);
  		InputStream in = getClass().getResourceAsStream("/TIMESTAMP");
  		if (in != null) {
  			BufferedReader streamReader = new BufferedReader(
  					new InputStreamReader(in));
  
  			try {
  				String buildTimeStamp = streamReader.readLine();
  				if (in != null) {
  					in.close();
  				}
  				getStackLogger().setBuildTimeStamp(buildTimeStamp);
  			} catch (IOException ex) {
  				getStackLogger().logError("Could not open build timestamp.");
  			}
  		}
  
  		String bufferSize = configurationProperties.getProperty(
  				"gov2.nist.javax2.sip.RECEIVE_UDP_BUFFER_SIZE", MAX_DATAGRAM_SIZE
  						.toString());
  		int bufferSizeInteger = new Integer(bufferSize).intValue();
  		super.setReceiveUdpBufferSize(bufferSizeInteger);
  
  		bufferSize = configurationProperties.getProperty(
  				"gov2.nist.javax2.sip.SEND_UDP_BUFFER_SIZE", MAX_DATAGRAM_SIZE
  						.toString());
  		bufferSizeInteger = new Integer(bufferSize).intValue();
  		super.setSendUdpBufferSize(bufferSizeInteger);
  
  		boolean congetstionControlEnabled = Boolean
  				.parseBoolean(configurationProperties.getProperty(
  						"gov2.nist.javax2.sip.CONGESTION_CONTROL_ENABLED",
  						Boolean.TRUE.toString()));
  		super.stackDoesCongestionControl = congetstionControlEnabled;
  
  		super.isBackToBackUserAgent = Boolean
  				.parseBoolean(configurationProperties.getProperty(
  						"gov2.nist.javax2.sip.IS_BACK_TO_BACK_USER_AGENT",
  						Boolean.FALSE.toString()));
  		super.checkBranchId = Boolean.parseBoolean(configurationProperties
  				.getProperty("gov2.nist.javax2.sip.REJECT_STRAY_RESPONSES",
  						Boolean.FALSE.toString()));
  		
  		super.isDialogTerminatedEventDeliveredForNullDialog = (Boolean.parseBoolean(configurationProperties.getProperty("gov2.nist.javax2.sip.DELIVER_TERMINATED_EVENT_FOR_NULL_DIALOG",
  		        Boolean.FALSE.toString())));
  		
  		
  		super.maxForkTime = Integer.parseInt(
  		        configurationProperties.getProperty("gov2.nist.javax2.sip.MAX_FORK_TIME_SECONDS","0"));
  		
  	}
  
  	/*
  	 * (non-Javadoc)
  	 * 
  	 * @see javax2.sip.SipStack#createListeningPoint(java.lang.String, int,
  	 * java.lang.String)
  	 */
  	public synchronized ListeningPoint createListeningPoint(String address,
  			int port, String transport) throws TransportNotSupportedException,
  			InvalidArgumentException {
  		if (isLoggingEnabled())
  			getStackLogger().logDebug(
  				"createListeningPoint : address = " + address + " port = "
  						+ port + " transport = " + transport);
  
  		if (address == null)
  			throw new NullPointerException(
  					"Address for listening point is null!");
  		if (transport == null)
  			throw new NullPointerException("null transport");
  		if (port <= 0)
  			throw new InvalidArgumentException("bad port");
  
  		if (!transport.equalsIgnoreCase("UDP")
  				&& !transport.equalsIgnoreCase("TLS")
  				&& !transport.equalsIgnoreCase("TCP")
  				&& !transport.equalsIgnoreCase("SCTP"))
  			throw new TransportNotSupportedException("bad transport "
  					+ transport);
  
  		/** Reusing an old stack instance */
  		if (!this.isAlive()) {
  			this.toExit = false;
  			this.reInitialize();
  		}
  
  		String key = ListeningPointImpl.makeKey(address, port, transport);
  
  		ListeningPointImpl lip = listeningPoints.get(key);
  		if (lip != null) {
  			return lip;
  		} else {
  			try {
  				InetAddress inetAddr = InetAddress.getByName(address);
  				MessageProcessor messageProcessor = this
  						.createMessageProcessor(inetAddr, port, transport);
  				if (this.isLoggingEnabled()) {
  					this.getStackLogger().logDebug(
  							"Created Message Processor: " + address
  									+ " port = " + port + " transport = "
  									+ transport);
  				}
  				lip = new ListeningPointImpl(this, port, transport);
  				lip.messageProcessor = messageProcessor;
  				messageProcessor.setListeningPoint(lip);
  				this.listeningPoints.put(key, lip);
  				// start processing messages.
  				messageProcessor.start();
  				return (ListeningPoint) lip;
  			} catch (java.io.IOException ex) {
  				if (isLoggingEnabled())
  					getStackLogger().logError(
  						"Invalid argument address = " + address + " port = "
  								+ port + " transport = " + transport);
  				throw new InvalidArgumentException(ex.getMessage(), ex);
  			}
  		}
  	}
  
  	/*
  	 * (non-Javadoc)
  	 * 
  	 * @see javax2.sip.SipStack#createSipProvider(javax2.sip.ListeningPoint)
  	 */
  	public SipProvider createSipProvider(ListeningPoint listeningPoint)
  			throws ObjectInUseException {
  		if (listeningPoint == null)
  			throw new NullPointerException("null listeningPoint");
  		if (this.isLoggingEnabled())
  			this.getStackLogger().logDebug(
  					"createSipProvider: " + listeningPoint);
  		ListeningPointImpl listeningPointImpl = (ListeningPointImpl) listeningPoint;
  		if (listeningPointImpl.sipProvider != null)
  			throw new ObjectInUseException("Provider already attached!");
  
  		SipProviderImpl provider = new SipProviderImpl(this);
  
  		provider.setListeningPoint(listeningPointImpl);
  		listeningPointImpl.sipProvider = provider;
  		this.sipProviders.add(provider);
  		return provider;
  	}
  
  	/*
  	 * (non-Javadoc)
  	 * 
  	 * @see javax2.sip.SipStack#deleteListeningPoint(javax2.sip.ListeningPoint)
  	 */
  	public void deleteListeningPoint(ListeningPoint listeningPoint)
  			throws ObjectInUseException {
  		if (listeningPoint == null)
  			throw new NullPointerException("null listeningPoint arg");
  		ListeningPointImpl lip = (ListeningPointImpl) listeningPoint;
  		// Stop the message processing thread in the listening point.
  		super.removeMessageProcessor(lip.messageProcessor);
  		String key = lip.getKey();
  		this.listeningPoints.remove(key);
  
  	}
  
  	/*
  	 * (non-Javadoc)
  	 * 
  	 * @see javax2.sip.SipStack#deleteSipProvider(javax2.sip.SipProvider)
  	 */
  	public void deleteSipProvider(SipProvider sipProvider)
  			throws ObjectInUseException {
  
  		if (sipProvider == null)
  			throw new NullPointerException("null provider arg");
  		SipProviderImpl sipProviderImpl = (SipProviderImpl) sipProvider;
  
  		// JvB: API doc is not clear, but in_use ==
  		// sipProviderImpl.sipListener!=null
  		// so we should throw if app did not call removeSipListener
  		// sipProviderImpl.sipListener = null;
  		if (sipProviderImpl.getSipListener() != null) {
  			throw new ObjectInUseException(
  					"SipProvider still has an associated SipListener!");
  		}
  
  		sipProviderImpl.removeListeningPoints();
  
  		// Bug reported by Rafael Barriuso
  		sipProviderImpl.stop();
  		sipProviders.remove(sipProvider);
  		if (sipProviders.isEmpty()) {
  			this.stopStack();
  		}
  	}
  
  	/**
  	 * Get the IP Address of the stack.
  	 * 
  	 * @see javax2.sip.SipStack#getIPAddress()
  	 * @deprecated
  	 */
  	public String getIPAddress() {
  		return super.getHostAddress();
  	}
  
  	/*
  	 * (non-Javadoc)
  	 * 
  	 * @see javax2.sip.SipStack#getListeningPoints()
  	 */
  	public java.util.Iterator<ListeningPointImpl> getListeningPoints() {
  		return this.listeningPoints.values().iterator();
  	}
  
  	/**
  	 * Return true if retransmission filter is active.
  	 * 
  	 * @see javax2.sip.SipStack#isRetransmissionFilterActive()
  	 * @deprecated
  	 */
  	public boolean isRetransmissionFilterActive() {
  		return true;
  	}
  
  	/*
  	 * (non-Javadoc)
  	 * 
  	 * @see javax2.sip.SipStack#getSipProviders()
  	 */
  	public java.util.Iterator<SipProviderImpl> getSipProviders() {
  		return this.sipProviders.iterator();
  	}
  
  	/*
  	 * (non-Javadoc)
  	 * 
  	 * @see javax2.sip.SipStack#getStackName()
  	 */
  	public String getStackName() {
  		return this.stackName;
  	}
  
  	/**
  	 * Finalization -- stop the stack on finalization. Exit the transaction
  	 * scanner and release all resources.
  	 * 
  	 * @see java.lang.Object#finalize()
  	 */
  	protected void finalize() {
  		this.stopStack();
  	}
  
  	/**
  	 * This uses the default stack address to create a listening point.
  	 * 
  	 * @see javax2.sip.SipStack#createListeningPoint(java.lang.String, int,
  	 *      java.lang.String)
  	 * @deprecated
  	 */
  	public ListeningPoint createListeningPoint(int port, String transport)
  			throws TransportNotSupportedException, InvalidArgumentException {
  		if (super.stackAddress == null)
  			throw new NullPointerException(
  					"Stack does not have a default IP Address!");
  		return this.createListeningPoint(super.stackAddress, port, transport);
  	}
  
  	/*
  	 * (non-Javadoc)
  	 * 
  	 * @see javax2.sip.SipStack#stop()
  	 */
  	public void stop() {
  		if (isLoggingEnabled()) {
  			getStackLogger().logDebug("stopStack -- stoppping the stack");
  		}
  		this.stopStack();
  		this.sipProviders = new LinkedList<SipProviderImpl>();
  		this.listeningPoints = new Hashtable<String, ListeningPointImpl>();
  		/*
  		 * Check for presence of an event scanner ( may happen if stack is
  		 * stopped before listener is attached ).
  		 */
  		if (this.eventScanner != null)
  			this.eventScanner.forceStop();
  		this.eventScanner = null;
  
  	}
  
  	/*
  	 * (non-Javadoc)
  	 * 
  	 * @see javax2.sip.SipStack#start()
  	 */
  	public void start() throws ProviderDoesNotExistException, SipException {
  		// Start a new event scanner if one does not exist.
  		if (this.eventScanner == null) {
  			this.eventScanner = new EventScanner(this);
  		}
  
  	}
  
  	/**
  	 * Get the listener for the stack. A stack can have only one listener. To
  	 * get an event from a provider, the listener has to be registered with the
  	 * provider. The SipListener is application code.
  	 * 
  	 * @return -- the stack SipListener
  	 * 
  	 */
  	public SipListener getSipListener() {
  		return this.sipListener;
  	}
  
  	/**
  	 * Get the message log factory registered with the stack.
  	 * 
  	 * @return -- the messageLogFactory of the stack.
  	 */
  	public LogRecordFactory getLogRecordFactory() {
  		return super.logRecordFactory;
  	}
  
  	/**
  	 * Set the log appender ( this is useful if you want to specify a particular
  	 * log format or log to something other than a file for example). This method
  	 * is will be removed May 11, 2010 or shortly there after.
  	 * 
  	 * @param Appender
  	 *            - the log4j appender to add.
  	 * @deprecated TODO: remove this method May 11, 2010.
  	 */
          // BEGIN android-deleted
  	/*
          @Deprecated
  	public void addLogAppender(org.apache.log4j.Appender appender) {
  		if (this.getStackLogger() instanceof gov2.nist.core.LogWriter) {
  			((gov2.nist.core.LogWriter) this.getStackLogger()).addAppender(appender);
  		}
  	}
          */
          // END android-deleted
  
  	/**
  	 * Get the log4j logger ( for log stream integration ).
  	 * This method will be removed May 11, 2010 or shortly there after.
  	 * 
  	 * @return  the log4j logger.
  	 * @deprecated TODO: This method will be removed May 11, 2010.
  	 */
  	@Deprecated
          // BEGIN andoird-deleted
          /*
  	public org.apache.log4j.Logger getLogger() {
  		if (this.getStackLogger() instanceof gov2.nist.core.LogWriter) {
  			return ((gov2.nist.core.LogWriter) this.getStackLogger()).getLogger();
  		}
  		return null;
  	}
          */
          // END android-deleted
  
  	public EventScanner getEventScanner() {
  		return eventScanner;
  	}
  
  	/*
  	 * (non-Javadoc)
  	 * 
  	 * @see
  	 * gov2.nist.javax2.sip.SipStackExt#getAuthenticationHelper(gov2.nist.javax2
  	 * .sip.clientauthutils.AccountManager, javax2.sip.header.HeaderFactory)
  	 */
  	public AuthenticationHelper getAuthenticationHelper(
  			AccountManager accountManager, HeaderFactory headerFactory) {
  		return new AuthenticationHelperImpl(this, accountManager, headerFactory);
  	}
  
  	/*
  	 * (non-Javadoc)
  	 * 
  	 * @see
  	 * gov2.nist.javax2.sip.SipStackExt#getAuthenticationHelper(gov2.nist.javax2
  	 * .sip.clientauthutils.AccountManager, javax2.sip.header.HeaderFactory)
  	 */
  	public AuthenticationHelper getSecureAuthenticationHelper(
  			SecureAccountManager accountManager, HeaderFactory headerFactory) {
  		return new AuthenticationHelperImpl(this, accountManager, headerFactory);
  	}
  
  	/**
  	 * Set the list of cipher suites supported by the stack. A stack can have
  	 * only one set of suites. These are not validated against the supported
  	 * cipher suites of the java runtime, so specifying a cipher here does not
  	 * guarantee that it will work.<br>
  	 * The stack has a default cipher suite of:
  	 * <ul>
  	 * <li>TLS_RSA_WITH_AES_128_CBC_SHA</li>
  	 * <li>SSL_RSA_WITH_3DES_EDE_CBC_SHA</li>
  	 * <li>TLS_DH_anon_WITH_AES_128_CBC_SHA</li>
  	 * <li>SSL_DH_anon_WITH_3DES_EDE_CBC_SHA</li>
  	 * </ul>
  	 * 
  	 * <b>NOTE: This function must be called before adding a TLS listener</b>
  	 * 
  	 * @param String
  	 *            [] The new set of ciphers to support.
  	 * @return
  	 * 
  	 */
  	public void setEnabledCipherSuites(String[] newCipherSuites) {
  		cipherSuites = newCipherSuites;
  	}
  
  	/**
  	 * Return the currently enabled cipher suites of the Stack.
  	 * 
  	 * @return The currently enabled cipher suites.
  	 */
  	public String[] getEnabledCipherSuites() {
  		return cipherSuites;
  	}
  
  	/**
  	 * Set the list of protocols supported by the stack for outgoing TLS connections.
  	 * A stack can have only one set of protocols.
  	 * These are not validated against the supported
  	 * protocols of the java runtime, so specifying a protocol here does not
  	 * guarantee that it will work.<br>
  	 * The stack has a default protocol suite of:
  	 * <ul>
  	 * <li>SSLv3</li>
  	 * <li>SSLv2Hello</li>
  	 * <li>TLSv1</li>
  	 * </ul>
  	 * 
  	 * <b>NOTE: This function must be called before creating a TLSMessageChannel.</b>
  	 * 
  	 * @param String
  	 *            [] The new set of protocols to use for outgoing TLS connections.
  	 * @return
  	 * 
  	 */
  	public void setEnabledProtocols(String[] newProtocols) {
  		enabledProtocols = newProtocols;
  	}
  
  	/**
  	 * Return the currently enabled protocols to use when creating TLS connection.
  	 * 
  	 * @return The currently enabled protocols.
  	 */
  	public String[] getEnabledProtocols() {
  		return enabledProtocols;
  	}
  
  	/**
  	 * Set the "back to back User Agent" flag.
  	 * 
  	 * @param flag
  	 *            - boolean flag to set.
  	 * 
  	 */
  	public void setIsBackToBackUserAgent(boolean flag) {
  		super.isBackToBackUserAgent = flag;
  	}
  	
  	/**
  	 * Get the "back to back User Agent" flag.
  	 * 
  	 * return the value of the flag
  	 * 
  	 */
  	public boolean isBackToBackUserAgent() {
  		return super.isBackToBackUserAgent;
  	}
  
  	public boolean isAutomaticDialogErrorHandlingEnabled() {
  		return super.isAutomaticDialogErrorHandlingEnabled;
  	}
  
      public boolean acquireSem() {
          try {
              return this.stackSemaphore.tryAcquire(10, TimeUnit.SECONDS);
          } catch ( InterruptedException ex) {
              return false;
          }
      }
      
      public void releaseSem() {
          this.stackSemaphore.release();
      }
  
  
      
  
  }
  