Home | History | Annotate | Download | only in stack
      1 /*
      2  * Conditions Of Use
      3  *
      4  * This software was developed by employees of the National Institute of
      5  * Standards and Technology (NIST), an agency of the Federal Government.
      6  * Pursuant to title 15 Untied States Code Section 105, works of NIST
      7  * employees are not subject to copyright protection in the United States
      8  * and are considered to be in the public domain.  As a result, a formal
      9  * license is not needed to use the software.
     10  *
     11  * This software is provided by NIST as a service and is expressly
     12  * provided "AS IS."  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED
     13  * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF
     14  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT
     15  * AND DATA ACCURACY.  NIST does not warrant or make any representations
     16  * regarding the use of the software or the results thereof, including but
     17  * not limited to the correctness, accuracy, reliability or usefulness of
     18  * the software.
     19  *
     20  * Permission to use this software is contingent upon your acceptance
     21  * of the terms of this agreement
     22  *
     23  * .
     24  *
     25  */
     26 package gov.nist.javax.sip.stack;
     27 
     28 import gov.nist.core.Host;
     29 import gov.nist.core.HostPort;
     30 import gov.nist.core.ServerLogger;
     31 import gov.nist.core.StackLogger;
     32 import gov.nist.core.ThreadAuditor;
     33 import gov.nist.core.net.AddressResolver;
     34 import gov.nist.core.net.DefaultNetworkLayer;
     35 import gov.nist.core.net.NetworkLayer;
     36 import gov.nist.javax.sip.DefaultAddressResolver;
     37 import gov.nist.javax.sip.ListeningPointImpl;
     38 import gov.nist.javax.sip.LogRecordFactory;
     39 import gov.nist.javax.sip.SIPConstants;
     40 import gov.nist.javax.sip.SipListenerExt;
     41 import gov.nist.javax.sip.SipProviderImpl;
     42 import gov.nist.javax.sip.SipStackImpl;
     43 import gov.nist.javax.sip.header.Event;
     44 import gov.nist.javax.sip.header.Via;
     45 import gov.nist.javax.sip.header.extensions.JoinHeader;
     46 import gov.nist.javax.sip.header.extensions.ReplacesHeader;
     47 import gov.nist.javax.sip.message.SIPMessage;
     48 import gov.nist.javax.sip.message.SIPRequest;
     49 import gov.nist.javax.sip.message.SIPResponse;
     50 
     51 import java.io.IOException;
     52 import java.net.InetAddress;
     53 import java.net.SocketAddress;
     54 import java.net.UnknownHostException;
     55 import java.util.ArrayList;
     56 import java.util.Collection;
     57 import java.util.HashSet;
     58 import java.util.Iterator;
     59 import java.util.LinkedList;
     60 import java.util.Set;
     61 import java.util.Timer;
     62 import java.util.concurrent.ConcurrentHashMap;
     63 import java.util.concurrent.atomic.AtomicInteger;
     64 
     65 import javax.sip.ClientTransaction;
     66 import javax.sip.Dialog;
     67 import javax.sip.DialogState;
     68 import javax.sip.DialogTerminatedEvent;
     69 import javax.sip.ServerTransaction;
     70 import javax.sip.SipException;
     71 import javax.sip.SipListener;
     72 import javax.sip.TransactionState;
     73 import javax.sip.TransactionTerminatedEvent;
     74 import javax.sip.address.Hop;
     75 import javax.sip.address.Router;
     76 import javax.sip.header.CallIdHeader;
     77 import javax.sip.header.EventHeader;
     78 import javax.sip.message.Request;
     79 import javax.sip.message.Response;
     80 
     81 /*
     82  * Jeff Keyser : architectural suggestions and contributions. Pierre De Rop and Thomas Froment :
     83  * Bug reports. Jeyashankher < jai (at) lucent.com > : bug reports. Jeroen van Bemmel : Bug fixes.
     84  *
     85  *
     86  */
     87 
     88 /**
     89  *
     90  * This is the sip stack. It is essentially a management interface. It manages the resources for
     91  * the JAIN-SIP implementation. This is the structure that is wrapped by the SipStackImpl.
     92  *
     93  * @see gov.nist.javax.sip.SipStackImpl
     94  *
     95  * @author M. Ranganathan <br/>
     96  *
     97  * @version 1.2 $Revision: 1.141 $ $Date: 2009/12/17 23:38:27 $
     98  */
     99 public abstract class SIPTransactionStack implements SIPTransactionEventListener, SIPDialogEventListener {
    100 
    101     /*
    102      * Number of milliseconds between timer ticks (500).
    103      */
    104     public static final int BASE_TIMER_INTERVAL = 500;
    105 
    106     /*
    107      * Connection linger time (seconds) this is the time (in seconds) for which we linger the TCP
    108      * connection before closing it.
    109      */
    110     public static final int CONNECTION_LINGER_TIME = 8;
    111 
    112     /*
    113      * Table of retransmission Alert timers.
    114      */
    115     protected ConcurrentHashMap<String, SIPServerTransaction> retransmissionAlertTransactions;
    116 
    117     // Table of early dialogs ( to keep identity mapping )
    118     protected ConcurrentHashMap<String, SIPDialog> earlyDialogTable;
    119 
    120     // Table of dialogs.
    121     protected ConcurrentHashMap<String, SIPDialog> dialogTable;
    122 
    123     // A set of methods that result in dialog creations.
    124     protected static final Set<String> dialogCreatingMethods = new HashSet<String>();
    125 
    126     // Global timer. Use this for all timer tasks.
    127 
    128     private Timer timer;
    129 
    130     // List of pending server transactions
    131     private ConcurrentHashMap<String, SIPServerTransaction> pendingTransactions;
    132 
    133     // hashtable for fast lookup
    134     private ConcurrentHashMap<String, SIPClientTransaction> clientTransactionTable;
    135 
    136     // Set to false if you want hiwat and lowat to be consulted.
    137     protected boolean unlimitedServerTransactionTableSize = true;
    138 
    139     // Set to false if you want unlimited size of client trnansactin table.
    140     protected boolean unlimitedClientTransactionTableSize = true;
    141 
    142     // High water mark for ServerTransaction Table
    143     // after which requests are dropped.
    144     protected int serverTransactionTableHighwaterMark = 5000;
    145 
    146     // Low water mark for Server Tx table size after which
    147     // requests are selectively dropped
    148     protected int serverTransactionTableLowaterMark = 4000;
    149 
    150     // Hiwater mark for client transaction table. These defaults can be
    151     // overriden by stack
    152     // configuration.
    153     protected int clientTransactionTableHiwaterMark = 1000;
    154 
    155     // Low water mark for client tx table.
    156     protected int clientTransactionTableLowaterMark = 800;
    157 
    158     private AtomicInteger activeClientTransactionCount = new AtomicInteger(0);
    159 
    160     // Hashtable for server transactions.
    161     private ConcurrentHashMap<String, SIPServerTransaction> serverTransactionTable;
    162 
    163     // A table of ongoing transactions indexed by mergeId ( for detecting merged
    164     // requests.
    165     private ConcurrentHashMap<String, SIPServerTransaction> mergeTable;
    166 
    167     private ConcurrentHashMap<String,SIPServerTransaction> terminatedServerTransactionsPendingAck;
    168 
    169     private ConcurrentHashMap<String,SIPClientTransaction> forkedClientTransactionTable;
    170 
    171     /*
    172      * A wrapper around differnt logging implementations (log4j, commons logging, slf4j, ...) to help log debug.
    173      */
    174     private StackLogger stackLogger;
    175 
    176     /*
    177      * ServerLog is used just for logging stack message tracecs.
    178      */
    179     protected ServerLogger serverLogger;
    180 
    181     /*
    182      * We support UDP on this stack.
    183      */
    184     boolean udpFlag;
    185 
    186     /*
    187      * Internal router. Use this for all sip: request routing.
    188      *
    189      */
    190     protected DefaultRouter defaultRouter;
    191 
    192     /*
    193      * Global flag that turns logging off
    194      */
    195     protected boolean needsLogging;
    196 
    197     /*
    198      * Flag used for testing TI, bypasses filtering of ACK to non-2xx
    199      */
    200     private boolean non2XXAckPassedToListener;
    201 
    202     /*
    203      * Class that handles caching of TCP/TLS connections.
    204      */
    205     protected IOHandler ioHandler;
    206 
    207     /*
    208      * Flag that indicates that the stack is active.
    209      */
    210     protected boolean toExit;
    211 
    212     /*
    213      * Name of the stack.
    214      */
    215     protected String stackName;
    216 
    217     /*
    218      * IP address of stack -- this can be re-written by stun.
    219      *
    220      * @deprecated
    221      */
    222     protected String stackAddress;
    223 
    224     /*
    225      * INET address of stack (cached to avoid repeated lookup)
    226      *
    227      * @deprecated
    228      */
    229     protected InetAddress stackInetAddress;
    230 
    231     /*
    232      * Request factory interface (to be provided by the application)
    233      */
    234     protected StackMessageFactory sipMessageFactory;
    235 
    236     /*
    237      * Router to determine where to forward the request.
    238      */
    239     protected javax.sip.address.Router router;
    240 
    241     /*
    242      * Number of pre-allocated threads for processing udp messages. -1 means no preallocated
    243      * threads ( dynamically allocated threads).
    244      */
    245     protected int threadPoolSize;
    246 
    247     /*
    248      * max number of simultaneous connections.
    249      */
    250     protected int maxConnections;
    251 
    252     /*
    253      * Close accept socket on completion.
    254      */
    255     protected boolean cacheServerConnections;
    256 
    257     /*
    258      * Close connect socket on Tx termination.
    259      */
    260     protected boolean cacheClientConnections;
    261 
    262     /*
    263      * Use the user supplied router for all out of dialog requests.
    264      */
    265     protected boolean useRouterForAll;
    266 
    267     /*
    268      * Max size of message that can be read from a TCP connection.
    269      */
    270     protected int maxContentLength;
    271 
    272     /*
    273      * Max # of headers that a SIP message can contain.
    274      */
    275     protected int maxMessageSize;
    276 
    277     /*
    278      * A collection of message processors.
    279      */
    280     private Collection<MessageProcessor> messageProcessors;
    281 
    282     /*
    283      * Read timeout on TCP incoming sockets -- defines the time between reads for after delivery
    284      * of first byte of message.
    285      */
    286     protected int readTimeout;
    287 
    288     /*
    289      * The socket factory. Can be overriden by applications that want direct access to the
    290      * underlying socket.
    291      */
    292 
    293     protected NetworkLayer networkLayer;
    294 
    295     /*
    296      * Outbound proxy String ( to be handed to the outbound proxy class on creation).
    297      */
    298     protected String outboundProxy;
    299 
    300     protected String routerPath;
    301 
    302     // Flag to indicate whether the stack will provide dialog
    303     // support.
    304     protected boolean isAutomaticDialogSupportEnabled;
    305 
    306     // The set of events for which subscriptions can be forked.
    307 
    308     protected HashSet<String> forkedEvents;
    309 
    310     // Generate a timestamp header for retransmitted requests.
    311     protected boolean generateTimeStampHeader;
    312 
    313     protected AddressResolver addressResolver;
    314 
    315     // Max time that the listener is allowed to take to respond to a
    316     // request. Default is "infinity". This property allows
    317     // containers to defend against buggy clients (that do not
    318     // want to respond to requests).
    319     protected int maxListenerResponseTime;
    320 
    321 
    322     // A flag that indicates whether or not RFC 2543 clients are fully supported.
    323     // If this is set to true, then To tag checking on the Dialog layer is
    324     // disabled in a few places - resulting in possible breakage of forked dialogs.
    325     protected boolean rfc2543Supported = true;
    326 
    327     // / Provides a mechanism for applications to check the health of threads in
    328     // the stack
    329     protected ThreadAuditor threadAuditor = new ThreadAuditor();
    330 
    331     protected LogRecordFactory logRecordFactory;
    332 
    333     // Set to true if the client CANCEL transaction should be checked before sending
    334     // it out.
    335     protected boolean cancelClientTransactionChecked = true;
    336 
    337     // Is to tag reassignment allowed.
    338     protected boolean remoteTagReassignmentAllowed = true;
    339 
    340     protected boolean logStackTraceOnMessageSend = true;
    341 
    342     // Receive UDP buffer size
    343     protected int receiveUdpBufferSize;
    344 
    345     // Send UDP buffer size
    346     protected int sendUdpBufferSize;
    347 
    348     protected boolean stackDoesCongestionControl = true;
    349 
    350     protected boolean isBackToBackUserAgent = false;
    351 
    352     protected boolean checkBranchId;
    353 
    354 	protected boolean isAutomaticDialogErrorHandlingEnabled = true;
    355 
    356 	protected boolean isDialogTerminatedEventDeliveredForNullDialog = false;
    357 
    358 	// Max time for a forked response to arrive. After this time, the original dialog
    359 	// is not tracked. If you want to track the original transaction you need to specify
    360 	// the max fork time with a stack init property.
    361 	protected int maxForkTime = 0;
    362 
    363 
    364     // / Timer to regularly ping the thread auditor (on behalf of the timer
    365     // thread)
    366     class PingTimer extends SIPStackTimerTask {
    367         // / Timer thread handle
    368         ThreadAuditor.ThreadHandle threadHandle;
    369 
    370         // / Constructor
    371         public PingTimer(ThreadAuditor.ThreadHandle a_oThreadHandle) {
    372             threadHandle = a_oThreadHandle;
    373         }
    374 
    375         protected void runTask() {
    376             // Check if we still have a timer (it may be null after shutdown)
    377             if (getTimer() != null) {
    378                 // Register the timer task if we haven't done so
    379                 if (threadHandle == null) {
    380                     // This happens only once since the thread handle is passed
    381                     // to the next scheduled ping timer
    382                     threadHandle = getThreadAuditor().addCurrentThread();
    383                 }
    384 
    385                 // Let the thread auditor know that the timer task is alive
    386                 threadHandle.ping();
    387 
    388                 // Schedule the next ping
    389                 getTimer().schedule(new PingTimer(threadHandle),
    390                         threadHandle.getPingIntervalInMillisecs());
    391             }
    392         }
    393 
    394     }
    395 
    396 
    397     class RemoveForkedTransactionTimerTask extends SIPStackTimerTask {
    398 
    399         private SIPClientTransaction clientTransaction;
    400 
    401         public RemoveForkedTransactionTimerTask(SIPClientTransaction sipClientTransaction ) {
    402             this.clientTransaction = sipClientTransaction;
    403         }
    404 
    405         @Override
    406         protected void runTask() {
    407            forkedClientTransactionTable.remove(clientTransaction.getTransactionId());
    408         }
    409 
    410     }
    411 
    412     static {
    413     	// Standard set of methods that create dialogs.
    414     	dialogCreatingMethods.add(Request.REFER);
    415         dialogCreatingMethods.add(Request.INVITE);
    416         dialogCreatingMethods.add(Request.SUBSCRIBE);
    417     }
    418 
    419     /**
    420      * Default constructor.
    421      */
    422     protected SIPTransactionStack() {
    423         this.toExit = false;
    424         this.forkedEvents = new HashSet<String>();
    425         // set of events for which subscriptions can be forked.
    426         // Set an infinite thread pool size.
    427         this.threadPoolSize = -1;
    428         // Close response socket after infinte time.
    429         // for max performance
    430         this.cacheServerConnections = true;
    431         // Close the request socket after infinite time.
    432         // for max performance
    433         this.cacheClientConnections = true;
    434         // Max number of simultaneous connections.
    435         this.maxConnections = -1;
    436         // Array of message processors.
    437         messageProcessors = new ArrayList<MessageProcessor>();
    438         // Handle IO for this process.
    439         this.ioHandler = new IOHandler(this);
    440 
    441         // The read time out is infinite.
    442         this.readTimeout = -1;
    443 
    444         this.maxListenerResponseTime = -1;
    445 
    446         // The default (identity) address lookup scheme
    447 
    448         this.addressResolver = new DefaultAddressResolver();
    449 
    450         // Notify may or may not create a dialog. This is handled in
    451         // the code.
    452         // Create the transaction collections
    453 
    454         // Dialog dable.
    455         this.dialogTable = new ConcurrentHashMap<String, SIPDialog>();
    456         this.earlyDialogTable = new ConcurrentHashMap<String, SIPDialog>();
    457 
    458         clientTransactionTable = new ConcurrentHashMap<String, SIPClientTransaction>();
    459         serverTransactionTable = new ConcurrentHashMap<String, SIPServerTransaction>();
    460         this.terminatedServerTransactionsPendingAck = new ConcurrentHashMap<String, SIPServerTransaction>();
    461         mergeTable = new ConcurrentHashMap<String, SIPServerTransaction>();
    462         retransmissionAlertTransactions = new ConcurrentHashMap<String, SIPServerTransaction>();
    463 
    464         // Start the timer event thread.
    465 
    466         this.timer = new Timer();
    467         this.pendingTransactions = new ConcurrentHashMap<String, SIPServerTransaction>();
    468 
    469 
    470         this.forkedClientTransactionTable = new ConcurrentHashMap<String,SIPClientTransaction>();
    471 
    472         if (getThreadAuditor().isEnabled()) {
    473             // Start monitoring the timer thread
    474             timer.schedule(new PingTimer(null), 0);
    475         }
    476     }
    477 
    478     /**
    479      * Re Initialize the stack instance.
    480      */
    481     protected void reInit() {
    482         if (stackLogger.isLoggingEnabled())
    483             stackLogger.logDebug("Re-initializing !");
    484 
    485         // Array of message processors.
    486         messageProcessors = new ArrayList<MessageProcessor>();
    487         // Handle IO for this process.
    488         this.ioHandler = new IOHandler(this);
    489         // clientTransactions = new ConcurrentLinkedQueue();
    490         // serverTransactions = new ConcurrentLinkedQueue();
    491         pendingTransactions = new ConcurrentHashMap<String, SIPServerTransaction>();
    492         clientTransactionTable = new ConcurrentHashMap<String, SIPClientTransaction>();
    493         serverTransactionTable = new ConcurrentHashMap<String, SIPServerTransaction>();
    494         retransmissionAlertTransactions = new ConcurrentHashMap<String, SIPServerTransaction>();
    495         mergeTable = new ConcurrentHashMap<String, SIPServerTransaction>();
    496         // Dialog dable.
    497         this.dialogTable = new ConcurrentHashMap<String, SIPDialog>();
    498         this.earlyDialogTable = new ConcurrentHashMap<String, SIPDialog>();
    499         this.terminatedServerTransactionsPendingAck = new ConcurrentHashMap<String,SIPServerTransaction>();
    500         this.forkedClientTransactionTable = new ConcurrentHashMap<String,SIPClientTransaction>();
    501 
    502         this.timer = new Timer();
    503 
    504         this.activeClientTransactionCount = new AtomicInteger(0);
    505 
    506     }
    507 
    508     /**
    509      * Creates and binds, if necessary, a socket connected to the specified
    510      * destination address and port and then returns its local address.
    511      *
    512      * @param dst the destination address that the socket would need to connect
    513      *            to.
    514      * @param dstPort the port number that the connection would be established
    515      * with.
    516      * @param localAddress the address that we would like to bind on
    517      * (null for the "any" address).
    518      * @param localPort the port that we'd like our socket to bind to (0 for a
    519      * random port).
    520      *
    521      * @return the SocketAddress that this handler would use when connecting to
    522      * the specified destination address and port.
    523      *
    524      * @throws IOException
    525      */
    526     public SocketAddress obtainLocalAddress(InetAddress dst, int dstPort,
    527                     InetAddress localAddress, int localPort)
    528         throws IOException
    529     {
    530         return this.ioHandler.obtainLocalAddress(
    531                         dst, dstPort, localAddress, localPort);
    532 
    533     }
    534 
    535     /**
    536      * For debugging -- allows you to disable logging or enable logging selectively.
    537      *
    538      *
    539      */
    540     public void disableLogging() {
    541         this.getStackLogger().disableLogging();
    542     }
    543 
    544     /**
    545      * Globally enable message logging ( for debugging)
    546      *
    547      */
    548     public void enableLogging() {
    549         this.getStackLogger().enableLogging();
    550     }
    551 
    552     /**
    553      * Print the dialog table.
    554      *
    555      */
    556     public void printDialogTable() {
    557         if (isLoggingEnabled()) {
    558             this.getStackLogger().logDebug("dialog table  = " + this.dialogTable);
    559             System.out.println("dialog table = " + this.dialogTable);
    560         }
    561     }
    562 
    563     /**
    564      * Retrieve a transaction from our table of transactions with pending retransmission alerts.
    565      *
    566      * @param dialogId
    567      * @return -- the RetransmissionAlert enabled transaction corresponding to the given dialog
    568      *         ID.
    569      */
    570     public SIPServerTransaction getRetransmissionAlertTransaction(String dialogId) {
    571         return (SIPServerTransaction) this.retransmissionAlertTransactions.get(dialogId);
    572     }
    573 
    574     /**
    575      * Return true if extension is supported.
    576      *
    577      * @return true if extension is supported and false otherwise.
    578      */
    579     public static boolean isDialogCreated(String method) {
    580     	return dialogCreatingMethods.contains(method);
    581     }
    582 
    583     /**
    584      * Add an extension method.
    585      *
    586      * @param extensionMethod -- extension method to support for dialog creation
    587      */
    588     public void addExtensionMethod(String extensionMethod) {
    589         if (extensionMethod.equals(Request.NOTIFY)) {
    590             if (stackLogger.isLoggingEnabled())
    591                 stackLogger.logDebug("NOTIFY Supported Natively");
    592         } else {
    593             dialogCreatingMethods.add(extensionMethod.trim().toUpperCase());
    594         }
    595     }
    596 
    597     /**
    598      * Put a dialog into the dialog table.
    599      *
    600      * @param dialog -- dialog to put into the dialog table.
    601      *
    602      */
    603     public void putDialog(SIPDialog dialog) {
    604         String dialogId = dialog.getDialogId();
    605         if (dialogTable.containsKey(dialogId)) {
    606             if (stackLogger.isLoggingEnabled()) {
    607                 stackLogger.logDebug("putDialog: dialog already exists" + dialogId + " in table = "
    608                         + dialogTable.get(dialogId));
    609             }
    610             return;
    611         }
    612         if (stackLogger.isLoggingEnabled()) {
    613             stackLogger.logDebug("putDialog dialogId=" + dialogId + " dialog = " + dialog);
    614         }
    615         dialog.setStack(this);
    616         if (stackLogger.isLoggingEnabled())
    617             stackLogger.logStackTrace();
    618         dialogTable.put(dialogId, dialog);
    619 
    620     }
    621 
    622     /**
    623      * Create a dialog and add this transaction to it.
    624      *
    625      * @param transaction -- tx to add to the dialog.
    626      * @return the newly created Dialog.
    627      */
    628     public SIPDialog createDialog(SIPTransaction transaction) {
    629 
    630         SIPDialog retval = null;
    631 
    632         if (transaction instanceof SIPClientTransaction) {
    633             String dialogId = ((SIPRequest) transaction.getRequest()).getDialogId(false);
    634             if (this.earlyDialogTable.get(dialogId) != null) {
    635                 SIPDialog dialog = this.earlyDialogTable.get(dialogId);
    636                 if (dialog.getState() == null || dialog.getState() == DialogState.EARLY) {
    637                     retval = dialog;
    638                 } else {
    639                     retval = new SIPDialog(transaction);
    640                     this.earlyDialogTable.put(dialogId, retval);
    641                 }
    642             } else {
    643                 retval = new SIPDialog(transaction);
    644                 this.earlyDialogTable.put(dialogId, retval);
    645             }
    646         } else {
    647             retval = new SIPDialog(transaction);
    648         }
    649 
    650         return retval;
    651 
    652     }
    653 
    654     /**
    655      * Create a Dialog given a client tx and response.
    656      *
    657      * @param transaction
    658      * @param sipResponse
    659      * @return
    660      */
    661 
    662     public SIPDialog createDialog(SIPClientTransaction transaction, SIPResponse sipResponse) {
    663         String dialogId = ((SIPRequest) transaction.getRequest()).getDialogId(false);
    664         SIPDialog retval = null;
    665         if (this.earlyDialogTable.get(dialogId) != null) {
    666             retval = this.earlyDialogTable.get(dialogId);
    667             if (sipResponse.isFinalResponse()) {
    668                 this.earlyDialogTable.remove(dialogId);
    669             }
    670 
    671         } else {
    672             retval = new SIPDialog(transaction, sipResponse);
    673         }
    674         return retval;
    675 
    676     }
    677     /**
    678      * Create a Dialog given a sip provider and response.
    679      *
    680      * @param sipProvider
    681      * @param sipResponse
    682      * @return
    683      */
    684     public SIPDialog createDialog(SipProviderImpl sipProvider,
    685 			SIPResponse sipResponse) {
    686 		return new SIPDialog(sipProvider, sipResponse);
    687 	}
    688 
    689     /**
    690      * Remove the dialog from the dialog table.
    691      *
    692      * @param dialog -- dialog to remove.
    693      */
    694     public void removeDialog(SIPDialog dialog) {
    695 
    696         String id = dialog.getDialogId();
    697 
    698         String earlyId = dialog.getEarlyDialogId();
    699 
    700         if (earlyId != null) {
    701             this.earlyDialogTable.remove(earlyId);
    702             this.dialogTable.remove(earlyId);
    703         }
    704 
    705         if (id != null) {
    706 
    707             // FHT: Remove dialog from table only if its associated dialog is the same as the one
    708             // specified
    709 
    710             Object old = this.dialogTable.get(id);
    711 
    712             if (old == dialog) {
    713                 this.dialogTable.remove(id);
    714             }
    715 
    716             // We now deliver DTE even when the dialog is not originally present in the Dialog
    717             // Table
    718             // This happens before the dialog state is assigned.
    719 
    720             if (!dialog.testAndSetIsDialogTerminatedEventDelivered()) {
    721                 DialogTerminatedEvent event = new DialogTerminatedEvent(dialog.getSipProvider(),
    722                         dialog);
    723 
    724                 // Provide notification to the listener that the dialog has
    725                 // ended.
    726                 dialog.getSipProvider().handleEvent(event, null);
    727 
    728             }
    729 
    730         } else if ( this.isDialogTerminatedEventDeliveredForNullDialog ) {
    731             if (!dialog.testAndSetIsDialogTerminatedEventDelivered()) {
    732                 DialogTerminatedEvent event = new DialogTerminatedEvent(dialog.getSipProvider(),
    733                         dialog);
    734 
    735                 // Provide notification to the listener that the dialog has
    736                 // ended.
    737                 dialog.getSipProvider().handleEvent(event, null);
    738 
    739             }
    740         }
    741 
    742     }
    743 
    744     /**
    745      * Return the dialog for a given dialog ID. If compatibility is enabled then we do not assume
    746      * the presence of tags and hence need to add a flag to indicate whether this is a server or
    747      * client transaction.
    748      *
    749      * @param dialogId is the dialog id to check.
    750      */
    751 
    752     public SIPDialog getDialog(String dialogId) {
    753 
    754         SIPDialog sipDialog = (SIPDialog) dialogTable.get(dialogId);
    755         if (stackLogger.isLoggingEnabled()) {
    756             stackLogger.logDebug("getDialog(" + dialogId + ") : returning " + sipDialog);
    757         }
    758         return sipDialog;
    759 
    760     }
    761 
    762     /**
    763      * Remove the dialog given its dialog id. This is used for dialog id re-assignment only.
    764      *
    765      * @param dialogId is the dialog Id to remove.
    766      */
    767     public void removeDialog(String dialogId) {
    768         if (stackLogger.isLoggingEnabled()) {
    769             stackLogger.logWarning("Silently removing dialog from table");
    770         }
    771         dialogTable.remove(dialogId);
    772     }
    773 
    774     /**
    775      * Find a matching client SUBSCRIBE to the incoming notify. NOTIFY requests are matched to
    776      * such SUBSCRIBE requests if they contain the same "Call-ID", a "To" header "tag" parameter
    777      * which matches the "From" header "tag" parameter of the SUBSCRIBE, and the same "Event"
    778      * header field. Rules for comparisons of the "Event" headers are described in section 7.2.1.
    779      * If a matching NOTIFY request contains a "Subscription-State" of "active" or "pending", it
    780      * creates a new subscription and a new dialog (unless they have already been created by a
    781      * matching response, as described above).
    782      *
    783      * @param notifyMessage
    784      * @return -- the matching ClientTransaction with semaphore aquired or null if no such client
    785      *         transaction can be found.
    786      */
    787     public SIPClientTransaction findSubscribeTransaction(SIPRequest notifyMessage,
    788             ListeningPointImpl listeningPoint) {
    789         SIPClientTransaction retval = null;
    790         try {
    791             Iterator it = clientTransactionTable.values().iterator();
    792             if (stackLogger.isLoggingEnabled())
    793             	stackLogger.logDebug("ct table size = " + clientTransactionTable.size());
    794             String thisToTag = notifyMessage.getTo().getTag();
    795             if (thisToTag == null) {
    796                 return retval;
    797             }
    798             Event eventHdr = (Event) notifyMessage.getHeader(EventHeader.NAME);
    799             if (eventHdr == null) {
    800                 if (stackLogger.isLoggingEnabled()) {
    801                     stackLogger.logDebug("event Header is null -- returning null");
    802                 }
    803 
    804                 return retval;
    805             }
    806             while (it.hasNext()) {
    807                 SIPClientTransaction ct = (SIPClientTransaction) it.next();
    808                 if (!ct.getMethod().equals(Request.SUBSCRIBE))
    809                     continue;
    810 
    811                 // if ( sipProvider.getListeningPoint(transport) == null)
    812                 String fromTag = ct.from.getTag();
    813                 Event hisEvent = ct.event;
    814                 // Event header is mandatory but some slopply clients
    815                 // dont include it.
    816                 if (hisEvent == null)
    817                     continue;
    818                 if (stackLogger.isLoggingEnabled()) {
    819                     stackLogger.logDebug("ct.fromTag = " + fromTag);
    820                     stackLogger.logDebug("thisToTag = " + thisToTag);
    821                     stackLogger.logDebug("hisEvent = " + hisEvent);
    822                     stackLogger.logDebug("eventHdr " + eventHdr);
    823                 }
    824 
    825                 if (  fromTag.equalsIgnoreCase(thisToTag)
    826                       && hisEvent != null
    827                       && eventHdr.match(hisEvent)
    828                       && notifyMessage.getCallId().getCallId().equalsIgnoreCase(
    829                                 ct.callId.getCallId())) {
    830                     if (ct.acquireSem())
    831                         retval = ct;
    832                     return retval;
    833                 }
    834             }
    835 
    836             return retval;
    837         } finally {
    838         	if (stackLogger.isLoggingEnabled())
    839                 stackLogger.logDebug("findSubscribeTransaction : returning " + retval);
    840 
    841         }
    842 
    843     }
    844 
    845     /**
    846      * Add entry to "Transaction Pending ACK" table.
    847      *
    848      * @param serverTransaction
    849      */
    850     public void addTransactionPendingAck(SIPServerTransaction serverTransaction) {
    851         String branchId = ((SIPRequest)serverTransaction.getRequest()).getTopmostVia().getBranch();
    852         if ( branchId != null ) {
    853             this.terminatedServerTransactionsPendingAck.put(branchId, serverTransaction);
    854         }
    855 
    856     }
    857 
    858     /**
    859      * Get entry in the server transaction pending ACK table corresponding to an ACK.
    860      *
    861      * @param ackMessage
    862      * @return
    863      */
    864     public SIPServerTransaction findTransactionPendingAck(SIPRequest ackMessage) {
    865         return this.terminatedServerTransactionsPendingAck.get(ackMessage.getTopmostVia().getBranch());
    866     }
    867 
    868     /**
    869      * Remove entry from "Transaction Pending ACK" table.
    870      *
    871      * @param serverTransaction
    872      * @return
    873      */
    874 
    875     public boolean removeTransactionPendingAck(SIPServerTransaction serverTransaction) {
    876         String branchId = ((SIPRequest)serverTransaction.getRequest()).getTopmostVia().getBranch();
    877         if ( branchId != null && this.terminatedServerTransactionsPendingAck.containsKey(branchId) ) {
    878             this.terminatedServerTransactionsPendingAck.remove(branchId);
    879             return true;
    880         } else {
    881             return false;
    882         }
    883     }
    884 
    885     /**
    886      * Check if this entry exists in the "Transaction Pending ACK" table.
    887      *
    888      * @param serverTransaction
    889      * @return
    890      */
    891     public boolean isTransactionPendingAck(SIPServerTransaction serverTransaction) {
    892         String branchId = ((SIPRequest)serverTransaction.getRequest()).getTopmostVia().getBranch();
    893         return this.terminatedServerTransactionsPendingAck.contains(branchId);
    894     }
    895 
    896     /**
    897      * Find the transaction corresponding to a given request.
    898      *
    899      * @param sipMessage request for which to retrieve the transaction.
    900      *
    901      * @param isServer search the server transaction table if true.
    902      *
    903      * @return the transaction object corresponding to the request or null if no such mapping
    904      *         exists.
    905      */
    906     public SIPTransaction findTransaction(SIPMessage sipMessage, boolean isServer) {
    907         SIPTransaction retval = null;
    908         try {
    909             if (isServer) {
    910                 Via via = sipMessage.getTopmostVia();
    911                 if (via.getBranch() != null) {
    912                     String key = sipMessage.getTransactionId();
    913 
    914                     retval = (SIPTransaction) serverTransactionTable.get(key);
    915                     if (stackLogger.isLoggingEnabled())
    916                         getStackLogger().logDebug(
    917                                 "serverTx: looking for key " + key + " existing="
    918                                 + serverTransactionTable);
    919                     if (key.startsWith(SIPConstants.BRANCH_MAGIC_COOKIE_LOWER_CASE)) {
    920                         return retval;
    921                     }
    922 
    923                 }
    924                 // Need to scan the table for old style transactions (RFC 2543
    925                 // style)
    926                 Iterator<SIPServerTransaction> it = serverTransactionTable.values().iterator();
    927                 while (it.hasNext()) {
    928                     SIPServerTransaction sipServerTransaction = (SIPServerTransaction) it.next();
    929                     if (sipServerTransaction.isMessagePartOfTransaction(sipMessage)) {
    930                         retval = sipServerTransaction;
    931                         return retval;
    932                     }
    933                 }
    934 
    935             } else {
    936                 Via via = sipMessage.getTopmostVia();
    937                 if (via.getBranch() != null) {
    938                     String key = sipMessage.getTransactionId();
    939                     if (stackLogger.isLoggingEnabled())
    940                         getStackLogger().logDebug("clientTx: looking for key " + key);
    941                     retval = (SIPTransaction) clientTransactionTable.get(key);
    942                     if (key.startsWith(SIPConstants.BRANCH_MAGIC_COOKIE_LOWER_CASE)) {
    943                         return retval;
    944                     }
    945 
    946                 }
    947                 // Need to scan the table for old style transactions (RFC 2543
    948                 // style). This is terribly slow but we need to do this
    949                 // for backasswords compatibility.
    950                 Iterator<SIPClientTransaction> it = clientTransactionTable.values().iterator();
    951                 while (it.hasNext()) {
    952                     SIPClientTransaction clientTransaction = (SIPClientTransaction) it.next();
    953                     if (clientTransaction.isMessagePartOfTransaction(sipMessage)) {
    954                         retval = clientTransaction;
    955                         return retval;
    956                     }
    957                 }
    958 
    959             }
    960         } finally {
    961         	if ( this.getStackLogger().isLoggingEnabled()) {
    962         	  this.getStackLogger().logDebug("findTransaction: returning  : " + retval);
    963         	}
    964         }
    965         return retval;
    966 
    967     }
    968 
    969     /**
    970      * Get the transaction to cancel. Search the server transaction table for a transaction that
    971      * matches the given transaction.
    972      */
    973     public SIPTransaction findCancelTransaction(SIPRequest cancelRequest, boolean isServer) {
    974 
    975         if (stackLogger.isLoggingEnabled()) {
    976             stackLogger.logDebug("findCancelTransaction request= \n" + cancelRequest
    977                     + "\nfindCancelRequest isServer=" + isServer);
    978         }
    979 
    980         if (isServer) {
    981             Iterator<SIPServerTransaction> li = this.serverTransactionTable.values().iterator();
    982             while (li.hasNext()) {
    983                 SIPTransaction transaction = (SIPTransaction) li.next();
    984 
    985                 SIPServerTransaction sipServerTransaction = (SIPServerTransaction) transaction;
    986                 if (sipServerTransaction.doesCancelMatchTransaction(cancelRequest))
    987                     return sipServerTransaction;
    988             }
    989 
    990         } else {
    991             Iterator<SIPClientTransaction> li = this.clientTransactionTable.values().iterator();
    992             while (li.hasNext()) {
    993                 SIPTransaction transaction = (SIPTransaction) li.next();
    994 
    995                 SIPClientTransaction sipClientTransaction = (SIPClientTransaction) transaction;
    996                 if (sipClientTransaction.doesCancelMatchTransaction(cancelRequest))
    997                     return sipClientTransaction;
    998 
    999             }
   1000 
   1001         }
   1002         if (stackLogger.isLoggingEnabled())
   1003             stackLogger.logDebug("Could not find transaction for cancel request");
   1004         return null;
   1005     }
   1006 
   1007     /**
   1008      * Construcor for the stack. Registers the request and response factories for the stack.
   1009      *
   1010      * @param messageFactory User-implemented factory for processing messages.
   1011      */
   1012     protected SIPTransactionStack(StackMessageFactory messageFactory) {
   1013         this();
   1014         this.sipMessageFactory = messageFactory;
   1015     }
   1016 
   1017     /**
   1018      * Finds a pending server transaction. Since each request may be handled either statefully or
   1019      * statelessly, we keep a map of pending transactions so that a duplicate transaction is not
   1020      * created if a second request is recieved while the first one is being processed.
   1021      *
   1022      * @param requestReceived
   1023      * @return -- the pending transaction or null if no such transaction exists.
   1024      */
   1025     public SIPServerTransaction findPendingTransaction(SIPRequest requestReceived) {
   1026         if (this.stackLogger.isLoggingEnabled()) {
   1027             this.stackLogger.logDebug("looking for pending tx for :"
   1028                     + requestReceived.getTransactionId());
   1029         }
   1030         return (SIPServerTransaction) pendingTransactions.get(requestReceived.getTransactionId());
   1031 
   1032     }
   1033 
   1034     /**
   1035      * See if there is a pending transaction with the same Merge ID as the Merge ID obtained from
   1036      * the SIP Request. The Merge table is for handling the following condition: If the request
   1037      * has no tag in the To header field, the UAS core MUST check the request against ongoing
   1038      * transactions. If the From tag, Call-ID, and CSeq exactly match those associated with an
   1039      * ongoing transaction, but the request does not match that transaction (based on the matching
   1040      * rules in Section 17.2.3), the UAS core SHOULD generate a 482 (Loop Detected) response and
   1041      * pass it to the server transaction.
   1042      */
   1043     public SIPServerTransaction findMergedTransaction(SIPRequest sipRequest) {
   1044         if (! sipRequest.getMethod().equals(Request.INVITE)) {
   1045             /*
   1046              * Dont need to worry about request merging for Non-INVITE transactions.
   1047              */
   1048             return null;
   1049         }
   1050         String mergeId = sipRequest.getMergeId();
   1051         SIPServerTransaction mergedTransaction = (SIPServerTransaction) this.mergeTable.get(mergeId);
   1052         if (mergeId == null ) {
   1053             return null;
   1054         } else if (mergedTransaction != null && !mergedTransaction.isMessagePartOfTransaction(sipRequest) ) {
   1055             return mergedTransaction;
   1056         } else {
   1057             /*
   1058              * Check the server transactions that have resulted in dialogs.
   1059              */
   1060            for (Dialog dialog: this.dialogTable.values() ) {
   1061                SIPDialog sipDialog = (SIPDialog) dialog ;
   1062                if (sipDialog.getFirstTransaction()  != null &&
   1063                    sipDialog.getFirstTransaction() instanceof ServerTransaction) {
   1064                    SIPServerTransaction serverTransaction = ((SIPServerTransaction) sipDialog.getFirstTransaction());
   1065                    SIPRequest transactionRequest = ((SIPServerTransaction) sipDialog.getFirstTransaction()).getOriginalRequest();
   1066                    if ( (! serverTransaction.isMessagePartOfTransaction(sipRequest))
   1067                            && sipRequest.getMergeId().equals(transactionRequest.getMergeId())) {
   1068                            return (SIPServerTransaction) sipDialog.getFirstTransaction();
   1069                    }
   1070                }
   1071            }
   1072            return null;
   1073         }
   1074     }
   1075 
   1076     /**
   1077      * Remove a pending Server transaction from the stack. This is called after the user code has
   1078      * completed execution in the listener.
   1079      *
   1080      * @param tr -- pending transaction to remove.
   1081      */
   1082     public void removePendingTransaction(SIPServerTransaction tr) {
   1083         if (this.stackLogger.isLoggingEnabled()) {
   1084             this.stackLogger.logDebug("removePendingTx: " + tr.getTransactionId());
   1085         }
   1086         this.pendingTransactions.remove(tr.getTransactionId());
   1087 
   1088     }
   1089 
   1090     /**
   1091      * Remove a transaction from the merge table.
   1092      *
   1093      * @param tr -- the server transaction to remove from the merge table.
   1094      *
   1095      */
   1096     public void removeFromMergeTable(SIPServerTransaction tr) {
   1097         if (stackLogger.isLoggingEnabled()) {
   1098             this.stackLogger.logDebug("Removing tx from merge table ");
   1099         }
   1100         String key = ((SIPRequest) tr.getRequest()).getMergeId();
   1101         if (key != null) {
   1102             this.mergeTable.remove(key);
   1103         }
   1104     }
   1105 
   1106     /**
   1107      * Put this into the merge request table.
   1108      *
   1109      * @param sipTransaction -- transaction to put into the merge table.
   1110      *
   1111      */
   1112     public void putInMergeTable(SIPServerTransaction sipTransaction, SIPRequest sipRequest) {
   1113         String mergeKey = sipRequest.getMergeId();
   1114         if (mergeKey != null) {
   1115             this.mergeTable.put(mergeKey, sipTransaction);
   1116         }
   1117     }
   1118 
   1119     /**
   1120      * Map a Server transaction (possibly sending out a 100 if the server tx is an INVITE). This
   1121      * actually places it in the hash table and makes it known to the stack.
   1122      *
   1123      * @param transaction -- the server transaction to map.
   1124      */
   1125     public void mapTransaction(SIPServerTransaction transaction) {
   1126         if (transaction.isMapped)
   1127             return;
   1128         addTransactionHash(transaction);
   1129         // transaction.startTransactionTimer();
   1130         transaction.isMapped = true;
   1131     }
   1132 
   1133     /**
   1134      * Handles a new SIP request. It finds a server transaction to handle this message. If none
   1135      * exists, it creates a new transaction.
   1136      *
   1137      * @param requestReceived Request to handle.
   1138      * @param requestMessageChannel Channel that received message.
   1139      *
   1140      * @return A server transaction.
   1141      */
   1142     public ServerRequestInterface newSIPServerRequest(SIPRequest requestReceived,
   1143             MessageChannel requestMessageChannel) {
   1144         // Iterator through all server transactions
   1145         Iterator<SIPServerTransaction> transactionIterator;
   1146         // Next transaction in the set
   1147         SIPServerTransaction nextTransaction;
   1148         // Transaction to handle this request
   1149         SIPServerTransaction currentTransaction;
   1150 
   1151         String key = requestReceived.getTransactionId();
   1152 
   1153         requestReceived.setMessageChannel(requestMessageChannel);
   1154 
   1155         currentTransaction = (SIPServerTransaction) serverTransactionTable.get(key);
   1156 
   1157         // Got to do this for bacasswards compatibility.
   1158         if (currentTransaction == null
   1159                 || !currentTransaction.isMessagePartOfTransaction(requestReceived)) {
   1160 
   1161             // Loop through all server transactions
   1162             transactionIterator = serverTransactionTable.values().iterator();
   1163             currentTransaction = null;
   1164             if (!key.toLowerCase().startsWith(SIPConstants.BRANCH_MAGIC_COOKIE_LOWER_CASE)) {
   1165                 while (transactionIterator.hasNext() && currentTransaction == null) {
   1166 
   1167                     nextTransaction = (SIPServerTransaction) transactionIterator.next();
   1168 
   1169                     // If this transaction should handle this request,
   1170                     if (nextTransaction.isMessagePartOfTransaction(requestReceived)) {
   1171                         // Mark this transaction as the one
   1172                         // to handle this message
   1173                         currentTransaction = nextTransaction;
   1174                     }
   1175                 }
   1176             }
   1177 
   1178             // If no transaction exists to handle this message
   1179             if (currentTransaction == null) {
   1180                 currentTransaction = findPendingTransaction(requestReceived);
   1181                 if (currentTransaction != null) {
   1182                     // Associate the tx with the received request.
   1183                     requestReceived.setTransaction(currentTransaction);
   1184                     if (currentTransaction != null && currentTransaction.acquireSem())
   1185                         return currentTransaction;
   1186                     else
   1187                         return null;
   1188 
   1189                 }
   1190                 // Creating a new server tx. May fail under heavy load.
   1191                 currentTransaction = createServerTransaction(requestMessageChannel);
   1192                 if (currentTransaction != null) {
   1193                     // currentTransaction.setPassToListener();
   1194                     currentTransaction.setOriginalRequest(requestReceived);
   1195                     // Associate the tx with the received request.
   1196                     requestReceived.setTransaction(currentTransaction);
   1197                 }
   1198 
   1199             }
   1200 
   1201         }
   1202 
   1203         // Set ths transaction's encapsulated request
   1204         // interface from the superclass
   1205         if (stackLogger.isLoggingEnabled()) {
   1206             stackLogger.logDebug("newSIPServerRequest( " + requestReceived.getMethod() + ":"
   1207                     + requestReceived.getTopmostVia().getBranch() + "):" + currentTransaction);
   1208         }
   1209 
   1210         if (currentTransaction != null)
   1211             currentTransaction.setRequestInterface(sipMessageFactory.newSIPServerRequest(
   1212                     requestReceived, currentTransaction));
   1213 
   1214         if (currentTransaction != null && currentTransaction.acquireSem()) {
   1215             return currentTransaction;
   1216         } else if (currentTransaction != null) {
   1217             try {
   1218                 /*
   1219                  * Already processing a message for this transaction.
   1220                  * SEND a trying ( message already being processed ).
   1221                  */
   1222                 if (currentTransaction.isMessagePartOfTransaction(requestReceived) &&
   1223                     currentTransaction.getMethod().equals(requestReceived.getMethod())) {
   1224                     SIPResponse trying = requestReceived.createResponse(Response.TRYING);
   1225                     trying.removeContent();
   1226                     currentTransaction.getMessageChannel().sendMessage(trying);
   1227                 }
   1228             } catch (Exception ex) {
   1229             	if (isLoggingEnabled())
   1230             		stackLogger.logError("Exception occured sending TRYING");
   1231             }
   1232             return null;
   1233         } else {
   1234             return null;
   1235         }
   1236     }
   1237 
   1238     /**
   1239      * Handles a new SIP response. It finds a client transaction to handle this message. If none
   1240      * exists, it sends the message directly to the superclass.
   1241      *
   1242      * @param responseReceived Response to handle.
   1243      * @param responseMessageChannel Channel that received message.
   1244      *
   1245      * @return A client transaction.
   1246      */
   1247     public ServerResponseInterface newSIPServerResponse(SIPResponse responseReceived,
   1248             MessageChannel responseMessageChannel) {
   1249 
   1250         // Iterator through all client transactions
   1251         Iterator<SIPClientTransaction> transactionIterator;
   1252         // Next transaction in the set
   1253         SIPClientTransaction nextTransaction;
   1254         // Transaction to handle this request
   1255         SIPClientTransaction currentTransaction;
   1256 
   1257         String key = responseReceived.getTransactionId();
   1258 
   1259         // Note that for RFC 3261 compliant operation, this lookup will
   1260         // return a tx if one exists and hence no need to search through
   1261         // the table.
   1262         currentTransaction = (SIPClientTransaction) clientTransactionTable.get(key);
   1263 
   1264         if (currentTransaction == null
   1265                 || (!currentTransaction.isMessagePartOfTransaction(responseReceived) && !key
   1266                         .startsWith(SIPConstants.BRANCH_MAGIC_COOKIE_LOWER_CASE))) {
   1267             // Loop through all client transactions
   1268 
   1269             transactionIterator = clientTransactionTable.values().iterator();
   1270             currentTransaction = null;
   1271             while (transactionIterator.hasNext() && currentTransaction == null) {
   1272 
   1273                 nextTransaction = (SIPClientTransaction) transactionIterator.next();
   1274 
   1275                 // If this transaction should handle this request,
   1276                 if (nextTransaction.isMessagePartOfTransaction(responseReceived)) {
   1277 
   1278                     // Mark this transaction as the one to
   1279                     // handle this message
   1280                     currentTransaction = nextTransaction;
   1281 
   1282                 }
   1283 
   1284             }
   1285 
   1286             // If no transaction exists to handle this message,
   1287             if (currentTransaction == null) {
   1288                 // JvB: Need to log before passing the response to the client
   1289                 // app, it
   1290                 // gets modified!
   1291                 if (this.stackLogger.isLoggingEnabled(StackLogger.TRACE_INFO)) {
   1292                     responseMessageChannel.logResponse(responseReceived, System
   1293                             .currentTimeMillis(), "before processing");
   1294                 }
   1295 
   1296                 // Pass the message directly to the TU
   1297                 return sipMessageFactory.newSIPServerResponse(responseReceived,
   1298                         responseMessageChannel);
   1299 
   1300             }
   1301         }
   1302 
   1303         // Aquire the sem -- previous request may still be processing.
   1304         boolean acquired = currentTransaction.acquireSem();
   1305         // Set ths transaction's encapsulated response interface
   1306         // from the superclass
   1307         if (this.stackLogger.isLoggingEnabled(StackLogger.TRACE_INFO)) {
   1308             currentTransaction.logResponse(responseReceived, System.currentTimeMillis(),
   1309                     "before processing");
   1310         }
   1311 
   1312         if (acquired) {
   1313             ServerResponseInterface sri = sipMessageFactory.newSIPServerResponse(
   1314                     responseReceived, currentTransaction);
   1315             if (sri != null) {
   1316                 currentTransaction.setResponseInterface(sri);
   1317             } else {
   1318                 if (this.stackLogger.isLoggingEnabled()) {
   1319                     this.stackLogger.logDebug("returning null - serverResponseInterface is null!");
   1320                 }
   1321                 currentTransaction.releaseSem();
   1322                 return null;
   1323             }
   1324         } else {
   1325         	if (stackLogger.isLoggingEnabled())
   1326         		this.stackLogger.logDebug("Could not aquire semaphore !!");
   1327         }
   1328 
   1329         if (acquired)
   1330             return currentTransaction;
   1331         else
   1332             return null;
   1333 
   1334     }
   1335 
   1336     /**
   1337      * Creates a client transaction to handle a new request. Gets the real message channel from
   1338      * the superclass, and then creates a new client transaction wrapped around this channel.
   1339      *
   1340      * @param nextHop Hop to create a channel to contact.
   1341      */
   1342     public MessageChannel createMessageChannel(SIPRequest request, MessageProcessor mp,
   1343             Hop nextHop) throws IOException {
   1344         // New client transaction to return
   1345         SIPTransaction returnChannel;
   1346 
   1347         // Create a new client transaction around the
   1348         // superclass' message channel
   1349         // Create the host/port of the target hop
   1350         Host targetHost = new Host();
   1351         targetHost.setHostname(nextHop.getHost());
   1352         HostPort targetHostPort = new HostPort();
   1353         targetHostPort.setHost(targetHost);
   1354         targetHostPort.setPort(nextHop.getPort());
   1355         MessageChannel mc = mp.createMessageChannel(targetHostPort);
   1356 
   1357         // Superclass will return null if no message processor
   1358         // available for the transport.
   1359         if (mc == null)
   1360             return null;
   1361 
   1362         returnChannel = createClientTransaction(request, mc);
   1363 
   1364         ((SIPClientTransaction) returnChannel).setViaPort(nextHop.getPort());
   1365         ((SIPClientTransaction) returnChannel).setViaHost(nextHop.getHost());
   1366         addTransactionHash(returnChannel);
   1367         // clientTransactionTable.put(returnChannel.getTransactionId(),
   1368         // returnChannel);
   1369         // Add the transaction timer for the state machine.
   1370         // returnChannel.startTransactionTimer();
   1371         return returnChannel;
   1372 
   1373     }
   1374 
   1375     /**
   1376      * Creates a client transaction that encapsulates a MessageChannel. Useful for implementations
   1377      * that want to subclass the standard
   1378      *
   1379      * @param encapsulatedMessageChannel Message channel of the transport layer.
   1380      */
   1381     public SIPClientTransaction createClientTransaction(SIPRequest sipRequest,
   1382             MessageChannel encapsulatedMessageChannel) {
   1383         SIPClientTransaction ct = new SIPClientTransaction(this, encapsulatedMessageChannel);
   1384         ct.setOriginalRequest(sipRequest);
   1385         return ct;
   1386     }
   1387 
   1388     /**
   1389      * Creates a server transaction that encapsulates a MessageChannel. Useful for implementations
   1390      * that want to subclass the standard
   1391      *
   1392      * @param encapsulatedMessageChannel Message channel of the transport layer.
   1393      */
   1394     public SIPServerTransaction createServerTransaction(MessageChannel encapsulatedMessageChannel) {
   1395     	// Issue 256 : be consistent with createClientTransaction, if unlimitedServerTransactionTableSize is true,
   1396     	// a new Server Transaction is created no matter what
   1397         if (unlimitedServerTransactionTableSize) {
   1398             return new SIPServerTransaction(this, encapsulatedMessageChannel);
   1399         } else {
   1400             float threshold = ((float) (serverTransactionTable.size() - serverTransactionTableLowaterMark))
   1401                     / ((float) (serverTransactionTableHighwaterMark - serverTransactionTableLowaterMark));
   1402             boolean decision = Math.random() > 1.0 - threshold;
   1403             if (decision) {
   1404                 return null;
   1405             } else {
   1406                 return new SIPServerTransaction(this, encapsulatedMessageChannel);
   1407             }
   1408 
   1409         }
   1410 
   1411     }
   1412 
   1413     /**
   1414      * Get the size of the client transaction table.
   1415      *
   1416      * @return -- size of the ct table.
   1417      */
   1418     public int getClientTransactionTableSize() {
   1419         return this.clientTransactionTable.size();
   1420     }
   1421 
   1422     /**
   1423      * Get the size of the server transaction table.
   1424      *
   1425      * @return -- size of the server table.
   1426      */
   1427     public int getServerTransactionTableSize() {
   1428         return this.serverTransactionTable.size();
   1429     }
   1430 
   1431     /**
   1432      * Add a new client transaction to the set of existing transactions. Add it to the top of the
   1433      * list so an incoming response has less work to do in order to find the transaction.
   1434      *
   1435      * @param clientTransaction -- client transaction to add to the set.
   1436      */
   1437     public void addTransaction(SIPClientTransaction clientTransaction) {
   1438         if (stackLogger.isLoggingEnabled())
   1439             stackLogger.logDebug("added transaction " + clientTransaction);
   1440         addTransactionHash(clientTransaction);
   1441 
   1442     }
   1443 
   1444     /**
   1445      * Remove transaction. This actually gets the tx out of the search structures which the stack
   1446      * keeps around. When the tx
   1447      */
   1448     public void removeTransaction(SIPTransaction sipTransaction) {
   1449         if (stackLogger.isLoggingEnabled()) {
   1450             stackLogger.logDebug("Removing Transaction = " + sipTransaction.getTransactionId()
   1451                     + " transaction = " + sipTransaction);
   1452         }
   1453         if (sipTransaction instanceof SIPServerTransaction) {
   1454             if (stackLogger.isLoggingEnabled())
   1455                 stackLogger.logStackTrace();
   1456             String key = sipTransaction.getTransactionId();
   1457             Object removed = serverTransactionTable.remove(key);
   1458             String method = sipTransaction.getMethod();
   1459             this.removePendingTransaction((SIPServerTransaction) sipTransaction);
   1460             this.removeTransactionPendingAck((SIPServerTransaction) sipTransaction);
   1461             if (method.equalsIgnoreCase(Request.INVITE)) {
   1462                 this.removeFromMergeTable((SIPServerTransaction) sipTransaction);
   1463             }
   1464             // Send a notification to the listener.
   1465             SipProviderImpl sipProvider = (SipProviderImpl) sipTransaction.getSipProvider();
   1466             if (removed != null && sipTransaction.testAndSetTransactionTerminatedEvent()) {
   1467                 TransactionTerminatedEvent event = new TransactionTerminatedEvent(sipProvider,
   1468                         (ServerTransaction) sipTransaction);
   1469 
   1470                 sipProvider.handleEvent(event, sipTransaction);
   1471 
   1472             }
   1473         } else {
   1474 
   1475             String key = sipTransaction.getTransactionId();
   1476             Object removed = clientTransactionTable.remove(key);
   1477 
   1478             if (stackLogger.isLoggingEnabled()) {
   1479                 stackLogger.logDebug("REMOVED client tx " + removed + " KEY = " + key);
   1480                 if ( removed != null ) {
   1481                    SIPClientTransaction clientTx = (SIPClientTransaction)removed;
   1482                    if ( clientTx.getMethod().equals(Request.INVITE) && this.maxForkTime != 0 ) {
   1483                        RemoveForkedTransactionTimerTask ttask = new RemoveForkedTransactionTimerTask(clientTx);
   1484                        this.timer.schedule(ttask, this.maxForkTime * 1000);
   1485                    }
   1486                 }
   1487             }
   1488 
   1489             // Send a notification to the listener.
   1490             if (removed != null && sipTransaction.testAndSetTransactionTerminatedEvent()) {
   1491                 SipProviderImpl sipProvider = (SipProviderImpl) sipTransaction.getSipProvider();
   1492                 TransactionTerminatedEvent event = new TransactionTerminatedEvent(sipProvider,
   1493                         (ClientTransaction) sipTransaction);
   1494 
   1495                 sipProvider.handleEvent(event, sipTransaction);
   1496             }
   1497 
   1498         }
   1499     }
   1500 
   1501     /**
   1502      * Add a new server transaction to the set of existing transactions. Add it to the top of the
   1503      * list so an incoming ack has less work to do in order to find the transaction.
   1504      *
   1505      * @param serverTransaction -- server transaction to add to the set.
   1506      */
   1507     public void addTransaction(SIPServerTransaction serverTransaction) throws IOException {
   1508         if (stackLogger.isLoggingEnabled())
   1509             stackLogger.logDebug("added transaction " + serverTransaction);
   1510         serverTransaction.map();
   1511 
   1512         addTransactionHash(serverTransaction);
   1513 
   1514     }
   1515 
   1516     /**
   1517      * Hash table for quick lookup of transactions. Here we wait for room if needed.
   1518      */
   1519     private void addTransactionHash(SIPTransaction sipTransaction) {
   1520         SIPRequest sipRequest = sipTransaction.getOriginalRequest();
   1521         if (sipTransaction instanceof SIPClientTransaction) {
   1522             if (!this.unlimitedClientTransactionTableSize) {
   1523                 if (this.activeClientTransactionCount.get() > clientTransactionTableHiwaterMark) {
   1524                     try {
   1525                         synchronized (this.clientTransactionTable) {
   1526                             this.clientTransactionTable.wait();
   1527                             this.activeClientTransactionCount.incrementAndGet();
   1528                         }
   1529 
   1530                     } catch (Exception ex) {
   1531                         if (stackLogger.isLoggingEnabled()) {
   1532                             stackLogger.logError("Exception occured while waiting for room", ex);
   1533                         }
   1534 
   1535                     }
   1536                 }
   1537             } else {
   1538                 this.activeClientTransactionCount.incrementAndGet();
   1539             }
   1540             String key = sipRequest.getTransactionId();
   1541             clientTransactionTable.put(key, (SIPClientTransaction) sipTransaction);
   1542 
   1543             if (stackLogger.isLoggingEnabled()) {
   1544                 stackLogger.logDebug(" putTransactionHash : " + " key = " + key);
   1545             }
   1546         } else {
   1547             String key = sipRequest.getTransactionId();
   1548 
   1549             if (stackLogger.isLoggingEnabled()) {
   1550                 stackLogger.logDebug(" putTransactionHash : " + " key = " + key);
   1551             }
   1552             serverTransactionTable.put(key, (SIPServerTransaction) sipTransaction);
   1553 
   1554         }
   1555 
   1556     }
   1557 
   1558     /**
   1559      * This method is called when a client tx transitions to the Completed or Terminated state.
   1560      *
   1561      */
   1562     protected void decrementActiveClientTransactionCount() {
   1563 
   1564         if (this.activeClientTransactionCount.decrementAndGet() <= this.clientTransactionTableLowaterMark
   1565                 && !this.unlimitedClientTransactionTableSize) {
   1566             synchronized (this.clientTransactionTable) {
   1567 
   1568                 clientTransactionTable.notify();
   1569 
   1570             }
   1571         }
   1572     }
   1573 
   1574     /**
   1575      * Remove the transaction from transaction hash.
   1576      */
   1577     protected void removeTransactionHash(SIPTransaction sipTransaction) {
   1578         SIPRequest sipRequest = sipTransaction.getOriginalRequest();
   1579         if (sipRequest == null)
   1580             return;
   1581         if (sipTransaction instanceof SIPClientTransaction) {
   1582             String key = sipTransaction.getTransactionId();
   1583             if (stackLogger.isLoggingEnabled()) {
   1584                 stackLogger.logStackTrace();
   1585                 stackLogger.logDebug("removing client Tx : " + key);
   1586             }
   1587             clientTransactionTable.remove(key);
   1588 
   1589         } else if (sipTransaction instanceof SIPServerTransaction) {
   1590             String key = sipTransaction.getTransactionId();
   1591             serverTransactionTable.remove(key);
   1592             if (stackLogger.isLoggingEnabled()) {
   1593                 stackLogger.logDebug("removing server Tx : " + key);
   1594             }
   1595         }
   1596     }
   1597 
   1598     /**
   1599      * Invoked when an error has ocurred with a transaction.
   1600      *
   1601      * @param transactionErrorEvent Error event.
   1602      */
   1603     public synchronized void transactionErrorEvent(SIPTransactionErrorEvent transactionErrorEvent) {
   1604         SIPTransaction transaction = (SIPTransaction) transactionErrorEvent.getSource();
   1605 
   1606         if (transactionErrorEvent.getErrorID() == SIPTransactionErrorEvent.TRANSPORT_ERROR) {
   1607             // Kill scanning of this transaction.
   1608             transaction.setState(SIPTransaction.TERMINATED_STATE);
   1609             if (transaction instanceof SIPServerTransaction) {
   1610                 // let the reaper get him
   1611                 ((SIPServerTransaction) transaction).collectionTime = 0;
   1612             }
   1613             transaction.disableTimeoutTimer();
   1614             transaction.disableRetransmissionTimer();
   1615             // Send a IO Exception to the Listener.
   1616         }
   1617     }
   1618 
   1619     /*
   1620      * (non-Javadoc)
   1621      * @see gov.nist.javax.sip.stack.SIPDialogEventListener#dialogErrorEvent(gov.nist.javax.sip.stack.SIPDialogErrorEvent)
   1622      */
   1623     public synchronized void dialogErrorEvent(SIPDialogErrorEvent dialogErrorEvent) {
   1624         SIPDialog sipDialog = (SIPDialog) dialogErrorEvent.getSource();
   1625         SipListener sipListener = ((SipStackImpl)this).getSipListener();
   1626         // if the app is not implementing the SipListenerExt interface we delete the dialog to avoid leaks
   1627         if(sipDialog != null && !(sipListener instanceof SipListenerExt)) {
   1628         	sipDialog.delete();
   1629         }
   1630     }
   1631 
   1632     /**
   1633      * Stop stack. Clear all the timer stuff. Make the stack close all accept connections and
   1634      * return. This is useful if you want to start/stop the stack several times from your
   1635      * application. Caution : use of this function could cause peculiar bugs as messages are
   1636      * prcessed asynchronously by the stack.
   1637      */
   1638     public void stopStack() {
   1639         // Prevent NPE on two concurrent stops
   1640         if (this.timer != null)
   1641             this.timer.cancel();
   1642 
   1643         // JvB: set it to null, SIPDialog tries to schedule things after stop
   1644         timer = null;
   1645         this.pendingTransactions.clear();
   1646         this.toExit = true;
   1647         synchronized (this) {
   1648             this.notifyAll();
   1649         }
   1650         synchronized (this.clientTransactionTable) {
   1651             clientTransactionTable.notifyAll();
   1652         }
   1653 
   1654         synchronized (this.messageProcessors) {
   1655             // Threads must periodically check this flag.
   1656             MessageProcessor[] processorList;
   1657             processorList = getMessageProcessors();
   1658             for (int processorIndex = 0; processorIndex < processorList.length; processorIndex++) {
   1659                 removeMessageProcessor(processorList[processorIndex]);
   1660             }
   1661             this.ioHandler.closeAll();
   1662             // Let the processing complete.
   1663 
   1664         }
   1665         try {
   1666 
   1667             Thread.sleep(1000);
   1668 
   1669         } catch (InterruptedException ex) {
   1670         }
   1671         this.clientTransactionTable.clear();
   1672         this.serverTransactionTable.clear();
   1673 
   1674         this.dialogTable.clear();
   1675         this.serverLogger.closeLogFile();
   1676 
   1677     }
   1678 
   1679     /**
   1680      * Put a transaction in the pending transaction list. This is to avoid a race condition when a
   1681      * duplicate may arrive when the application is deciding whether to create a transaction or
   1682      * not.
   1683      */
   1684     public void putPendingTransaction(SIPServerTransaction tr) {
   1685         if (stackLogger.isLoggingEnabled())
   1686             stackLogger.logDebug("putPendingTransaction: " + tr);
   1687 
   1688         this.pendingTransactions.put(tr.getTransactionId(), tr);
   1689 
   1690     }
   1691 
   1692     /**
   1693      * Return the network layer (i.e. the interface for socket creation or the socket factory for
   1694      * the stack).
   1695      *
   1696      * @return -- the registered Network Layer.
   1697      */
   1698     public NetworkLayer getNetworkLayer() {
   1699         if (networkLayer == null) {
   1700             return DefaultNetworkLayer.SINGLETON;
   1701         } else {
   1702             return networkLayer;
   1703         }
   1704     }
   1705 
   1706     /**
   1707      * Return true if logging is enabled for this stack.
   1708      *
   1709      * @return true if logging is enabled for this stack instance.
   1710      */
   1711     public boolean isLoggingEnabled() {
   1712         return this.stackLogger == null ? false : this.stackLogger.isLoggingEnabled();
   1713     }
   1714 
   1715     /**
   1716      * Get the logger.
   1717      *
   1718      * @return --the logger for the sip stack. Each stack has its own logger instance.
   1719      */
   1720     public StackLogger getStackLogger() {
   1721         return this.stackLogger;
   1722     }
   1723 
   1724     /**
   1725      * Server log is the place where we log messages for the signaling trace viewer.
   1726      *
   1727      * @return -- the log file where messages are logged for viewing by the trace viewer.
   1728      */
   1729     public ServerLogger getServerLogger() {
   1730         return this.serverLogger;
   1731     }
   1732 
   1733     /**
   1734      * Maximum size of a single TCP message. Limiting the size of a single TCP message prevents
   1735      * flooding attacks.
   1736      *
   1737      * @return the size of a single TCP message.
   1738      */
   1739     public int getMaxMessageSize() {
   1740         return this.maxMessageSize;
   1741     }
   1742 
   1743     /**
   1744      * Set the flag that instructs the stack to only start a single thread for sequentially
   1745      * processing incoming udp messages (thus serializing the processing). Same as setting thread
   1746      * pool size to 1.
   1747      */
   1748     public void setSingleThreaded() {
   1749         this.threadPoolSize = 1;
   1750     }
   1751 
   1752     /**
   1753      * Set the thread pool size for processing incoming UDP messages. Limit the total number of
   1754      * threads for processing udp messages.
   1755      *
   1756      * @param size -- the thread pool size.
   1757      *
   1758      */
   1759     public void setThreadPoolSize(int size) {
   1760         this.threadPoolSize = size;
   1761     }
   1762 
   1763     /**
   1764      * Set the max # of simultaneously handled TCP connections.
   1765      *
   1766      * @param nconnections -- the number of connections to handle.
   1767      */
   1768     public void setMaxConnections(int nconnections) {
   1769         this.maxConnections = nconnections;
   1770     }
   1771 
   1772     /**
   1773      * Get the default route string.
   1774      *
   1775      * @param sipRequest is the request for which we want to compute the next hop.
   1776      * @throws SipException
   1777      */
   1778     public Hop getNextHop(SIPRequest sipRequest) throws SipException {
   1779         if (this.useRouterForAll) {
   1780             // Use custom router to route all messages.
   1781             if (router != null)
   1782                 return router.getNextHop(sipRequest);
   1783             else
   1784                 return null;
   1785         } else {
   1786             // Also non-SIP request containing Route headers goes to the default
   1787             // router
   1788             if (sipRequest.getRequestURI().isSipURI() || sipRequest.getRouteHeaders() != null) {
   1789                 return defaultRouter.getNextHop(sipRequest);
   1790             } else if (router != null) {
   1791                 return router.getNextHop(sipRequest);
   1792             } else
   1793                 return null;
   1794         }
   1795     }
   1796 
   1797     /**
   1798      * Set the descriptive name of the stack.
   1799      *
   1800      * @param stackName -- descriptive name of the stack.
   1801      */
   1802     public void setStackName(String stackName) {
   1803         this.stackName = stackName;
   1804     }
   1805 
   1806 
   1807 
   1808     /**
   1809      * Set my address.
   1810      *
   1811      * @param stackAddress -- A string containing the stack address.
   1812      */
   1813     protected void setHostAddress(String stackAddress) throws UnknownHostException {
   1814         if (stackAddress.indexOf(':') != stackAddress.lastIndexOf(':')
   1815                 && stackAddress.trim().charAt(0) != '[')
   1816             this.stackAddress = '[' + stackAddress + ']';
   1817         else
   1818             this.stackAddress = stackAddress;
   1819         this.stackInetAddress = InetAddress.getByName(stackAddress);
   1820     }
   1821 
   1822     /**
   1823      * Get my address.
   1824      *
   1825      * @return hostAddress - my host address or null if no host address is defined.
   1826      * @deprecated
   1827      */
   1828     public String getHostAddress() {
   1829 
   1830         // JvB: for 1.2 this may return null...
   1831         return this.stackAddress;
   1832     }
   1833 
   1834     /**
   1835      * Set the router algorithm. This is meant for routing messages out of dialog or for non-sip
   1836      * uri's.
   1837      *
   1838      * @param router A class that implements the Router interface.
   1839      */
   1840     protected void setRouter(Router router) {
   1841         this.router = router;
   1842     }
   1843 
   1844     /**
   1845      * Get the router algorithm.
   1846      *
   1847      * @return Router router
   1848      */
   1849     public Router getRouter(SIPRequest request) {
   1850         if (request.getRequestLine() == null) {
   1851             return this.defaultRouter;
   1852         } else if (this.useRouterForAll) {
   1853             return this.router;
   1854         } else {
   1855             if (request.getRequestURI().getScheme().equals("sip")
   1856                     || request.getRequestURI().getScheme().equals("sips")) {
   1857                 return this.defaultRouter;
   1858             } else {
   1859                 if (this.router != null)
   1860                     return this.router;
   1861                 else
   1862                     return defaultRouter;
   1863             }
   1864         }
   1865     }
   1866 
   1867     /*
   1868      * (non-Javadoc)
   1869      *
   1870      * @see javax.sip.SipStack#getRouter()
   1871      */
   1872     public Router getRouter() {
   1873         return this.router;
   1874     }
   1875 
   1876     /**
   1877      * return the status of the toExit flag.
   1878      *
   1879      * @return true if the stack object is alive and false otherwise.
   1880      */
   1881     public boolean isAlive() {
   1882         return !toExit;
   1883     }
   1884 
   1885     /**
   1886      * Adds a new MessageProcessor to the list of running processors for this SIPStack and starts
   1887      * it. You can use this method for dynamic stack configuration.
   1888      */
   1889     protected void addMessageProcessor(MessageProcessor newMessageProcessor) throws IOException {
   1890         synchronized (messageProcessors) {
   1891             // Suggested changes by Jeyashankher, jai (at) lucent.com
   1892             // newMessageProcessor.start() can fail
   1893             // because a local port is not available
   1894             // This throws an IOException.
   1895             // We should not add the message processor to the
   1896             // local list of processors unless the start()
   1897             // call is successful.
   1898             // newMessageProcessor.start();
   1899             messageProcessors.add(newMessageProcessor);
   1900 
   1901         }
   1902     }
   1903 
   1904     /**
   1905      * Removes a MessageProcessor from this SIPStack.
   1906      *
   1907      * @param oldMessageProcessor
   1908      */
   1909     protected void removeMessageProcessor(MessageProcessor oldMessageProcessor) {
   1910         synchronized (messageProcessors) {
   1911             if (messageProcessors.remove(oldMessageProcessor)) {
   1912                 oldMessageProcessor.stop();
   1913             }
   1914         }
   1915     }
   1916 
   1917     /**
   1918      * Gets an array of running MessageProcessors on this SIPStack. Acknowledgement: Jeff Keyser
   1919      * suggested that applications should have access to the running message processors and
   1920      * contributed this code.
   1921      *
   1922      * @return an array of running message processors.
   1923      */
   1924     protected MessageProcessor[] getMessageProcessors() {
   1925         synchronized (messageProcessors) {
   1926             return (MessageProcessor[]) messageProcessors.toArray(new MessageProcessor[0]);
   1927         }
   1928     }
   1929 
   1930     /**
   1931      * Creates the equivalent of a JAIN listening point and attaches to the stack.
   1932      *
   1933      * @param ipAddress -- ip address for the listening point.
   1934      * @param port -- port for the listening point.
   1935      * @param transport -- transport for the listening point.
   1936      */
   1937     protected MessageProcessor createMessageProcessor(InetAddress ipAddress, int port,
   1938             String transport) throws java.io.IOException {
   1939         if (transport.equalsIgnoreCase("udp")) {
   1940             UDPMessageProcessor udpMessageProcessor = new UDPMessageProcessor(ipAddress, this,
   1941                     port);
   1942             this.addMessageProcessor(udpMessageProcessor);
   1943             this.udpFlag = true;
   1944             return udpMessageProcessor;
   1945         } else if (transport.equalsIgnoreCase("tcp")) {
   1946             TCPMessageProcessor tcpMessageProcessor = new TCPMessageProcessor(ipAddress, this,
   1947                     port);
   1948             this.addMessageProcessor(tcpMessageProcessor);
   1949             // this.tcpFlag = true;
   1950             return tcpMessageProcessor;
   1951         } else if (transport.equalsIgnoreCase("tls")) {
   1952             TLSMessageProcessor tlsMessageProcessor = new TLSMessageProcessor(ipAddress, this,
   1953                     port);
   1954             this.addMessageProcessor(tlsMessageProcessor);
   1955             // this.tlsFlag = true;
   1956             return tlsMessageProcessor;
   1957         } else if (transport.equalsIgnoreCase("sctp")) {
   1958 
   1959         	// Need Java 7 for this, so these classes are packaged in a separate jar
   1960         	// Try to load it indirectly, if fails report an error
   1961         	try {
   1962 				Class<?> mpc = ClassLoader.getSystemClassLoader().loadClass( "gov.nist.javax.sip.stack.sctp.SCTPMessageProcessor" );
   1963 				MessageProcessor mp = (MessageProcessor) mpc.newInstance();
   1964 				mp.initialize( ipAddress, port, this );
   1965 				this.addMessageProcessor(mp);
   1966 				return mp;
   1967 			} catch (ClassNotFoundException e) {
   1968 				throw new IllegalArgumentException("SCTP not supported (needs Java 7 and SCTP jar in classpath)");
   1969 			} catch ( InstantiationException ie ) {
   1970 				throw new IllegalArgumentException("Error initializing SCTP", ie);
   1971 			} catch ( IllegalAccessException ie ) {
   1972 				throw new IllegalArgumentException("Error initializing SCTP", ie);
   1973 			}
   1974         } else {
   1975             throw new IllegalArgumentException("bad transport");
   1976         }
   1977 
   1978     }
   1979 
   1980     /**
   1981      * Set the message factory.
   1982      *
   1983      * @param messageFactory -- messageFactory to set.
   1984      */
   1985     protected void setMessageFactory(StackMessageFactory messageFactory) {
   1986         this.sipMessageFactory = messageFactory;
   1987     }
   1988 
   1989     /**
   1990      * Creates a new MessageChannel for a given Hop.
   1991      *
   1992      * @param sourceIpAddress - Ip address of the source of this message.
   1993      *
   1994      * @param sourcePort - source port of the message channel to be created.
   1995      *
   1996      * @param nextHop Hop to create a MessageChannel to.
   1997      *
   1998      * @return A MessageChannel to the specified Hop, or null if no MessageProcessors support
   1999      *         contacting that Hop.
   2000      *
   2001      * @throws UnknownHostException If the host in the Hop doesn't exist.
   2002      */
   2003     public MessageChannel createRawMessageChannel(String sourceIpAddress, int sourcePort,
   2004             Hop nextHop) throws UnknownHostException {
   2005         Host targetHost;
   2006         HostPort targetHostPort;
   2007         Iterator processorIterator;
   2008         MessageProcessor nextProcessor;
   2009         MessageChannel newChannel;
   2010 
   2011         // Create the host/port of the target hop
   2012         targetHost = new Host();
   2013         targetHost.setHostname(nextHop.getHost());
   2014         targetHostPort = new HostPort();
   2015         targetHostPort.setHost(targetHost);
   2016         targetHostPort.setPort(nextHop.getPort());
   2017 
   2018         // Search each processor for the correct transport
   2019         newChannel = null;
   2020         processorIterator = messageProcessors.iterator();
   2021         while (processorIterator.hasNext() && newChannel == null) {
   2022             nextProcessor = (MessageProcessor) processorIterator.next();
   2023             // If a processor that supports the correct
   2024             // transport is found,
   2025             if (nextHop.getTransport().equalsIgnoreCase(nextProcessor.getTransport())
   2026                     && sourceIpAddress.equals(nextProcessor.getIpAddress().getHostAddress())
   2027                     && sourcePort == nextProcessor.getPort()) {
   2028                 try {
   2029                     // Create a channel to the target
   2030                     // host/port
   2031                     newChannel = nextProcessor.createMessageChannel(targetHostPort);
   2032                 } catch (UnknownHostException ex) {
   2033                     if (stackLogger.isLoggingEnabled())
   2034                         stackLogger.logException(ex);
   2035                     throw ex;
   2036                 } catch (IOException e) {
   2037                     if (stackLogger.isLoggingEnabled())
   2038                         stackLogger.logException(e);
   2039                     // Ignore channel creation error -
   2040                     // try next processor
   2041                 }
   2042             }
   2043         }
   2044         // Return the newly-created channel
   2045         return newChannel;
   2046     }
   2047 
   2048     /**
   2049      * Return true if a given event can result in a forked subscription. The stack is configured
   2050      * with a set of event names that can result in forked subscriptions.
   2051      *
   2052      * @param ename -- event name to check.
   2053      *
   2054      */
   2055     public boolean isEventForked(String ename) {
   2056         if (stackLogger.isLoggingEnabled()) {
   2057             stackLogger.logDebug("isEventForked: " + ename + " returning "
   2058                     + this.forkedEvents.contains(ename));
   2059         }
   2060         return this.forkedEvents.contains(ename);
   2061     }
   2062 
   2063     /**
   2064      * get the address resolver interface.
   2065      *
   2066      * @return -- the registered address resolver.
   2067      */
   2068     public AddressResolver getAddressResolver() {
   2069         return this.addressResolver;
   2070     }
   2071 
   2072     /**
   2073      * Set the address resolution interface
   2074      *
   2075      * @param addressResolver -- the address resolver to set.
   2076      */
   2077     public void setAddressResolver(AddressResolver addressResolver) {
   2078         this.addressResolver = addressResolver;
   2079     }
   2080 
   2081     /**
   2082      * Set the logger factory.
   2083      *
   2084      * @param logRecordFactory -- the log record factory to set.
   2085      */
   2086     public void setLogRecordFactory(LogRecordFactory logRecordFactory) {
   2087         this.logRecordFactory = logRecordFactory;
   2088     }
   2089 
   2090     /**
   2091      * get the thread auditor object
   2092      *
   2093      * @return -- the thread auditor of the stack
   2094      */
   2095     public ThreadAuditor getThreadAuditor() {
   2096         return this.threadAuditor;
   2097     }
   2098 
   2099     // /
   2100     // / Stack Audit methods
   2101     // /
   2102 
   2103     /**
   2104      * Audits the SIP Stack for leaks
   2105      *
   2106      * @return Audit report, null if no leaks were found
   2107      */
   2108     public String auditStack(Set activeCallIDs, long leakedDialogTimer,
   2109             long leakedTransactionTimer) {
   2110         String auditReport = null;
   2111         String leakedDialogs = auditDialogs(activeCallIDs, leakedDialogTimer);
   2112         String leakedServerTransactions = auditTransactions(serverTransactionTable,
   2113                 leakedTransactionTimer);
   2114         String leakedClientTransactions = auditTransactions(clientTransactionTable,
   2115                 leakedTransactionTimer);
   2116         if (leakedDialogs != null || leakedServerTransactions != null
   2117                 || leakedClientTransactions != null) {
   2118             auditReport = "SIP Stack Audit:\n" + (leakedDialogs != null ? leakedDialogs : "")
   2119                     + (leakedServerTransactions != null ? leakedServerTransactions : "")
   2120                     + (leakedClientTransactions != null ? leakedClientTransactions : "");
   2121         }
   2122         return auditReport;
   2123     }
   2124 
   2125     /**
   2126      * Audits SIP dialogs for leaks - Compares the dialogs in the dialogTable with a list of Call
   2127      * IDs passed by the application. - Dialogs that are not known by the application are leak
   2128      * suspects. - Kill the dialogs that are still around after the timer specified.
   2129      *
   2130      * @return Audit report, null if no dialog leaks were found
   2131      */
   2132     private String auditDialogs(Set activeCallIDs, long leakedDialogTimer) {
   2133         String auditReport = "  Leaked dialogs:\n";
   2134         int leakedDialogs = 0;
   2135         long currentTime = System.currentTimeMillis();
   2136 
   2137         // Make a shallow copy of the dialog list.
   2138         // This copy will remain intact as leaked dialogs are removed by the
   2139         // stack.
   2140         LinkedList dialogs;
   2141         synchronized (dialogTable) {
   2142             dialogs = new LinkedList(dialogTable.values());
   2143         }
   2144 
   2145         // Iterate through the dialogDialog, get the callID of each dialog and
   2146         // check if it's in the
   2147         // list of active calls passed by the application. If it isn't, start
   2148         // the timer on it.
   2149         // If the timer has expired, kill the dialog.
   2150         Iterator it = dialogs.iterator();
   2151         while (it.hasNext()) {
   2152             // Get the next dialog
   2153             SIPDialog itDialog = (SIPDialog) it.next();
   2154 
   2155             // Get the call id associated with this dialog
   2156             CallIdHeader callIdHeader = (itDialog != null ? itDialog.getCallId() : null);
   2157             String callID = (callIdHeader != null ? callIdHeader.getCallId() : null);
   2158 
   2159             // Check if the application knows about this call id
   2160             if (itDialog != null && callID != null && !activeCallIDs.contains(callID)) {
   2161                 // Application doesn't know anything about this dialog...
   2162                 if (itDialog.auditTag == 0) {
   2163                     // Mark this dialog as suspect
   2164                     itDialog.auditTag = currentTime;
   2165                 } else {
   2166                     // We already audited this dialog before. Check if his
   2167                     // time's up.
   2168                     if (currentTime - itDialog.auditTag >= leakedDialogTimer) {
   2169                         // Leaked dialog found
   2170                         leakedDialogs++;
   2171 
   2172                         // Generate report
   2173                         DialogState dialogState = itDialog.getState();
   2174                         String dialogReport = "dialog id: " + itDialog.getDialogId()
   2175                                 + ", dialog state: "
   2176                                 + (dialogState != null ? dialogState.toString() : "null");
   2177                         auditReport += "    " + dialogReport + "\n";
   2178 
   2179                         // Kill it
   2180                         itDialog.setState(SIPDialog.TERMINATED_STATE);
   2181                         if (stackLogger.isLoggingEnabled())
   2182                         	stackLogger.logDebug("auditDialogs: leaked " + dialogReport);
   2183                     }
   2184                 }
   2185             }
   2186         }
   2187 
   2188         // Return final report
   2189         if (leakedDialogs > 0) {
   2190             auditReport += "    Total: " + Integer.toString(leakedDialogs)
   2191                     + " leaked dialogs detected and removed.\n";
   2192         } else {
   2193             auditReport = null;
   2194         }
   2195         return auditReport;
   2196     }
   2197 
   2198     /**
   2199      * Audits SIP transactions for leaks
   2200      *
   2201      * @return Audit report, null if no transaction leaks were found
   2202      */
   2203     private String auditTransactions(ConcurrentHashMap transactionsMap,
   2204             long a_nLeakedTransactionTimer) {
   2205         String auditReport = "  Leaked transactions:\n";
   2206         int leakedTransactions = 0;
   2207         long currentTime = System.currentTimeMillis();
   2208 
   2209         // Make a shallow copy of the transaction list.
   2210         // This copy will remain intact as leaked transactions are removed by
   2211         // the stack.
   2212         LinkedList transactionsList = new LinkedList(transactionsMap.values());
   2213 
   2214         // Iterate through our copy
   2215         Iterator it = transactionsList.iterator();
   2216         while (it.hasNext()) {
   2217             SIPTransaction sipTransaction = (SIPTransaction) it.next();
   2218             if (sipTransaction != null) {
   2219                 if (sipTransaction.auditTag == 0) {
   2220                     // First time we see this transaction. Mark it as audited.
   2221                     sipTransaction.auditTag = currentTime;
   2222                 } else {
   2223                     // We've seen this transaction before. Check if his time's
   2224                     // up.
   2225                     if (currentTime - sipTransaction.auditTag >= a_nLeakedTransactionTimer) {
   2226                         // Leaked transaction found
   2227                         leakedTransactions++;
   2228 
   2229                         // Generate some report
   2230                         TransactionState transactionState = sipTransaction.getState();
   2231                         SIPRequest origRequest = sipTransaction.getOriginalRequest();
   2232                         String origRequestMethod = (origRequest != null ? origRequest.getMethod()
   2233                                 : null);
   2234                         String transactionReport = sipTransaction.getClass().getName()
   2235                                 + ", state: "
   2236                                 + (transactionState != null ? transactionState.toString()
   2237                                         : "null") + ", OR: "
   2238                                 + (origRequestMethod != null ? origRequestMethod : "null");
   2239                         auditReport += "    " + transactionReport + "\n";
   2240 
   2241                         // Kill it
   2242                         removeTransaction(sipTransaction);
   2243                         if (isLoggingEnabled())
   2244                         	stackLogger.logDebug("auditTransactions: leaked " + transactionReport);
   2245                     }
   2246                 }
   2247             }
   2248         }
   2249 
   2250         // Return final report
   2251         if (leakedTransactions > 0) {
   2252             auditReport += "    Total: " + Integer.toString(leakedTransactions)
   2253                     + " leaked transactions detected and removed.\n";
   2254         } else {
   2255             auditReport = null;
   2256         }
   2257         return auditReport;
   2258     }
   2259 
   2260     public void setNon2XXAckPassedToListener(boolean passToListener) {
   2261         this.non2XXAckPassedToListener = passToListener;
   2262     }
   2263 
   2264     /**
   2265      * @return the non2XXAckPassedToListener
   2266      */
   2267     public boolean isNon2XXAckPassedToListener() {
   2268         return non2XXAckPassedToListener;
   2269     }
   2270 
   2271     /**
   2272      * Get the count of client transactions that is not in the completed or terminated state.
   2273      *
   2274      * @return the activeClientTransactionCount
   2275      */
   2276     public int getActiveClientTransactionCount() {
   2277         return activeClientTransactionCount.get();
   2278     }
   2279 
   2280     public boolean isRfc2543Supported() {
   2281 
   2282         return this.rfc2543Supported;
   2283     }
   2284 
   2285     public boolean isCancelClientTransactionChecked() {
   2286         return this.cancelClientTransactionChecked;
   2287     }
   2288 
   2289     public boolean isRemoteTagReassignmentAllowed() {
   2290         return this.remoteTagReassignmentAllowed;
   2291     }
   2292 
   2293     /**
   2294      * This method is slated for addition to the next spec revision.
   2295      *
   2296      *
   2297      * @return -- the collection of dialogs that is being managed by the stack.
   2298      */
   2299     public Collection<Dialog> getDialogs() {
   2300         HashSet<Dialog> dialogs = new HashSet<Dialog>();
   2301         dialogs.addAll(this.dialogTable.values());
   2302         dialogs.addAll(this.earlyDialogTable.values());
   2303         return dialogs;
   2304     }
   2305 
   2306     /**
   2307      *
   2308      * @return -- the collection of dialogs matching the state that is being managed by the stack.
   2309      */
   2310     public Collection<Dialog> getDialogs(DialogState state) {
   2311         HashSet<Dialog> matchingDialogs = new HashSet<Dialog>();
   2312         if (DialogState.EARLY.equals(state)) {
   2313             matchingDialogs.addAll(this.earlyDialogTable.values());
   2314         } else {
   2315             Collection<SIPDialog> dialogs = dialogTable.values();
   2316             for (SIPDialog dialog : dialogs) {
   2317                 if (dialog.getState() != null && dialog.getState().equals(state)) {
   2318                     matchingDialogs.add(dialog);
   2319                 }
   2320             }
   2321         }
   2322         return matchingDialogs;
   2323     }
   2324 
   2325     /**
   2326      * Get the Replaced Dialog from the stack.
   2327      *
   2328      * @param replacesHeader -- the header that references the dialog being replaced.
   2329      */
   2330     public Dialog getReplacesDialog(ReplacesHeader replacesHeader) {
   2331         String cid = replacesHeader.getCallId();
   2332         String fromTag = replacesHeader.getFromTag();
   2333         String toTag = replacesHeader.getToTag();
   2334 
   2335         StringBuffer dialogId = new StringBuffer(cid);
   2336 
   2337         // retval.append(COLON).append(to.getUserAtHostPort());
   2338         if (toTag != null) {
   2339             dialogId.append(":");
   2340             dialogId.append(toTag);
   2341         }
   2342         // retval.append(COLON).append(from.getUserAtHostPort());
   2343         if (fromTag != null) {
   2344             dialogId.append(":");
   2345             dialogId.append(fromTag);
   2346         }
   2347         String did = dialogId.toString().toLowerCase();
   2348         if (stackLogger.isLoggingEnabled())
   2349         	stackLogger.logDebug("Looking for dialog " + did);
   2350         /*
   2351          * Check if we can find this dialog in our dialog table.
   2352          */
   2353         Dialog replacesDialog =  this.dialogTable.get(did);
   2354         /*
   2355          * This could be a forked dialog. Search for it.
   2356          */
   2357         if ( replacesDialog == null ) {
   2358            for ( SIPClientTransaction ctx : this.clientTransactionTable.values()) {
   2359                if ( ctx.getDialog(did) != null ) {
   2360                    replacesDialog = ctx.getDialog(did);
   2361                    break;
   2362                }
   2363            }
   2364         }
   2365 
   2366         return replacesDialog;
   2367     }
   2368 
   2369     /**
   2370      * Get the Join Dialog from the stack.
   2371      *
   2372      * @param joinHeader -- the header that references the dialog being joined.
   2373      */
   2374     public Dialog getJoinDialog(JoinHeader joinHeader) {
   2375         String cid = joinHeader.getCallId();
   2376         String fromTag = joinHeader.getFromTag();
   2377         String toTag = joinHeader.getToTag();
   2378 
   2379         StringBuffer retval = new StringBuffer(cid);
   2380 
   2381         // retval.append(COLON).append(to.getUserAtHostPort());
   2382         if (toTag != null) {
   2383             retval.append(":");
   2384             retval.append(toTag);
   2385         }
   2386         // retval.append(COLON).append(from.getUserAtHostPort());
   2387         if (fromTag != null) {
   2388             retval.append(":");
   2389             retval.append(fromTag);
   2390         }
   2391         return this.dialogTable.get(retval.toString().toLowerCase());
   2392     }
   2393 
   2394     /**
   2395      * @param timer the timer to set
   2396      */
   2397     public void setTimer(Timer timer) {
   2398         this.timer = timer;
   2399     }
   2400 
   2401     /**
   2402      * @return the timer
   2403      */
   2404     public Timer getTimer() {
   2405         return timer;
   2406     }
   2407 
   2408 
   2409     /**
   2410      * Size of the receive UDP buffer. This property affects performance under load. Bigger buffer
   2411      * is better under load.
   2412      *
   2413      * @return
   2414      */
   2415 	public int getReceiveUdpBufferSize() {
   2416 		return receiveUdpBufferSize;
   2417 	}
   2418 
   2419     /**
   2420      * Size of the receive UDP buffer. This property affects performance under load. Bigger buffer
   2421      * is better under load.
   2422      *
   2423      * @return
   2424      */
   2425 	public void setReceiveUdpBufferSize(int receiveUdpBufferSize) {
   2426 		this.receiveUdpBufferSize = receiveUdpBufferSize;
   2427 	}
   2428 
   2429     /**
   2430      * Size of the send UDP buffer. This property affects performance under load. Bigger buffer
   2431      * is better under load.
   2432      *
   2433      * @return
   2434      */
   2435 	public int getSendUdpBufferSize() {
   2436 		return sendUdpBufferSize;
   2437 	}
   2438 
   2439     /**
   2440      * Size of the send UDP buffer. This property affects performance under load. Bigger buffer
   2441      * is better under load.
   2442      *
   2443      * @return
   2444      */
   2445 	public void setSendUdpBufferSize(int sendUdpBufferSize) {
   2446 		this.sendUdpBufferSize = sendUdpBufferSize;
   2447 	}
   2448 
   2449 	/**
   2450 	 * @param stackLogger the stackLogger to set
   2451 	 */
   2452 	public void setStackLogger(StackLogger stackLogger) {
   2453 		this.stackLogger = stackLogger;
   2454 	}
   2455 
   2456 	 /**
   2457 	  * Flag that reqests checking of branch IDs on responses.
   2458 	  *
   2459 	  * @return
   2460 	  */
   2461 	 public boolean checkBranchId() {
   2462 	       return this.checkBranchId;
   2463 	 }
   2464 
   2465     /**
   2466      * @param logStackTraceOnMessageSend the logStackTraceOnMessageSend to set
   2467      */
   2468     public void setLogStackTraceOnMessageSend(boolean logStackTraceOnMessageSend) {
   2469         this.logStackTraceOnMessageSend = logStackTraceOnMessageSend;
   2470     }
   2471 
   2472     /**
   2473      * @return the logStackTraceOnMessageSend
   2474      */
   2475     public boolean isLogStackTraceOnMessageSend() {
   2476         return logStackTraceOnMessageSend;
   2477     }
   2478 
   2479     public void setDeliverDialogTerminatedEventForNullDialog() {
   2480         this.isDialogTerminatedEventDeliveredForNullDialog = true;
   2481     }
   2482 
   2483     public void addForkedClientTransaction(SIPClientTransaction clientTransaction) {
   2484         this.forkedClientTransactionTable.put(clientTransaction.getTransactionId(), clientTransaction );
   2485     }
   2486 
   2487     public SIPClientTransaction getForkedTransaction(String transactionId) {
   2488         return this.forkedClientTransactionTable.get(transactionId);
   2489     }
   2490 
   2491 
   2492 }
   2493