1600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang/*
2600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Conditions Of Use
3600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
4600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * This software was developed by employees of the National Institute of
5600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Standards and Technology (NIST), an agency of the Federal Government.
6600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Pursuant to title 15 Untied States Code Section 105, works of NIST
7600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * employees are not subject to copyright protection in the United States
8600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * and are considered to be in the public domain.  As a result, a formal
9600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * license is not needed to use the software.
10600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
11600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * This software is provided by NIST as a service and is expressly
12600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * provided "AS IS."  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED
13600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF
14600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT
15600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * AND DATA ACCURACY.  NIST does not warrant or make any representations
16600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * regarding the use of the software or the results thereof, including but
17600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * not limited to the correctness, accuracy, reliability or usefulness of
18600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * the software.
19600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
20600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Permission to use this software is contingent upon your acceptance
21600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * of the terms of this agreement
22600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
23600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * .
24600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
25600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */
26600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangpackage gov.nist.javax.sip.stack;
27600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
28600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.core.Host;
29600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.core.HostPort;
30600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.core.ServerLogger;
31600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.core.StackLogger;
32600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.core.ThreadAuditor;
33600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.core.net.AddressResolver;
34600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.core.net.DefaultNetworkLayer;
35600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.core.net.NetworkLayer;
36600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.DefaultAddressResolver;
37600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.ListeningPointImpl;
38600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.LogRecordFactory;
39600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.SIPConstants;
40600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.SipListenerExt;
41600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.SipProviderImpl;
42600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.SipStackImpl;
43600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.header.Event;
44600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.header.Via;
45600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.header.extensions.JoinHeader;
46600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.header.extensions.ReplacesHeader;
47600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.message.SIPMessage;
48600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.message.SIPRequest;
49600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport gov.nist.javax.sip.message.SIPResponse;
50600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
51600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport java.io.IOException;
52600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport java.net.InetAddress;
53600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport java.net.SocketAddress;
54600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport java.net.UnknownHostException;
55600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport java.util.ArrayList;
56600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport java.util.Collection;
57600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport java.util.HashSet;
58600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport java.util.Iterator;
59600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport java.util.LinkedList;
60600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport java.util.Set;
61600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport java.util.Timer;
62600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport java.util.concurrent.ConcurrentHashMap;
63600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport java.util.concurrent.atomic.AtomicInteger;
64600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
65600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.ClientTransaction;
66600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.Dialog;
67600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.DialogState;
68600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.DialogTerminatedEvent;
69600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.ServerTransaction;
70600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.SipException;
71600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.SipListener;
72600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.TransactionState;
73600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.TransactionTerminatedEvent;
74600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.address.Hop;
75600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.address.Router;
76600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.header.CallIdHeader;
77600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.header.EventHeader;
78600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.message.Request;
79600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangimport javax.sip.message.Response;
80600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
81600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang/*
82600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Jeff Keyser : architectural suggestions and contributions. Pierre De Rop and Thomas Froment :
83600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * Bug reports. Jeyashankher < jai@lucent.com > : bug reports. Jeroen van Bemmel : Bug fixes.
84600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
85600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
86600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */
87600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
88600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang/**
89600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
90600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * This is the sip stack. It is essentially a management interface. It manages the resources for
91600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * the JAIN-SIP implementation. This is the structure that is wrapped by the SipStackImpl.
92600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
93600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @see gov.nist.javax.sip.SipStackImpl
94600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
95600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @author M. Ranganathan <br/>
96600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang *
97600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang * @version 1.2 $Revision: 1.141 $ $Date: 2009/12/17 23:38:27 $
98600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang */
99600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wangpublic abstract class SIPTransactionStack implements SIPTransactionEventListener, SIPDialogEventListener {
100600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
101600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /*
102600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Number of milliseconds between timer ticks (500).
103600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
104600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public static final int BASE_TIMER_INTERVAL = 500;
105600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
106600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /*
107600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Connection linger time (seconds) this is the time (in seconds) for which we linger the TCP
108600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * connection before closing it.
109600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
110600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public static final int CONNECTION_LINGER_TIME = 8;
111600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
112600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /*
113600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Table of retransmission Alert timers.
114600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
115600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected ConcurrentHashMap<String, SIPServerTransaction> retransmissionAlertTransactions;
116600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
117600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    // Table of early dialogs ( to keep identity mapping )
118600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected ConcurrentHashMap<String, SIPDialog> earlyDialogTable;
119600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
120600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    // Table of dialogs.
121600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected ConcurrentHashMap<String, SIPDialog> dialogTable;
122600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
123600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    // A set of methods that result in dialog creations.
124600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected static final Set<String> dialogCreatingMethods = new HashSet<String>();
125600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
126600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    // Global timer. Use this for all timer tasks.
127600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
128600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private Timer timer;
129600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
130600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    // List of pending server transactions
131600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private ConcurrentHashMap<String, SIPServerTransaction> pendingTransactions;
132600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
133600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    // hashtable for fast lookup
134600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private ConcurrentHashMap<String, SIPClientTransaction> clientTransactionTable;
135600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
136600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    // Set to false if you want hiwat and lowat to be consulted.
137600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected boolean unlimitedServerTransactionTableSize = true;
138600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
139600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    // Set to false if you want unlimited size of client trnansactin table.
140600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected boolean unlimitedClientTransactionTableSize = true;
141600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
142600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    // High water mark for ServerTransaction Table
143600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    // after which requests are dropped.
144600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected int serverTransactionTableHighwaterMark = 5000;
145600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
146600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    // Low water mark for Server Tx table size after which
147600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    // requests are selectively dropped
148600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected int serverTransactionTableLowaterMark = 4000;
149600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
150600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    // Hiwater mark for client transaction table. These defaults can be
151600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    // overriden by stack
152600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    // configuration.
153600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected int clientTransactionTableHiwaterMark = 1000;
154600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
155600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    // Low water mark for client tx table.
156600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected int clientTransactionTableLowaterMark = 800;
157600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
158600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private AtomicInteger activeClientTransactionCount = new AtomicInteger(0);
159600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
160600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    // Hashtable for server transactions.
161600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private ConcurrentHashMap<String, SIPServerTransaction> serverTransactionTable;
162600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
163600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    // A table of ongoing transactions indexed by mergeId ( for detecting merged
164600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    // requests.
165600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private ConcurrentHashMap<String, SIPServerTransaction> mergeTable;
166600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
167600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private ConcurrentHashMap<String,SIPServerTransaction> terminatedServerTransactionsPendingAck;
168600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
169600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private ConcurrentHashMap<String,SIPClientTransaction> forkedClientTransactionTable;
170600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
171600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /*
172600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * A wrapper around differnt logging implementations (log4j, commons logging, slf4j, ...) to help log debug.
173600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
174600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private StackLogger stackLogger;
175600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
176600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /*
177600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * ServerLog is used just for logging stack message tracecs.
178600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
179600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected ServerLogger serverLogger;
180600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
181600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /*
182600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * We support UDP on this stack.
183600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
184600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    boolean udpFlag;
185600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
186600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /*
187600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Internal router. Use this for all sip: request routing.
188600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
189600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
190600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected DefaultRouter defaultRouter;
191600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
192600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /*
193600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Global flag that turns logging off
194600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
195600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected boolean needsLogging;
196600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
197600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /*
198600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Flag used for testing TI, bypasses filtering of ACK to non-2xx
199600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
200600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private boolean non2XXAckPassedToListener;
201600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
202600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /*
203600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Class that handles caching of TCP/TLS connections.
204600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
205600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected IOHandler ioHandler;
206600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
207600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /*
208600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Flag that indicates that the stack is active.
209600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
210600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected boolean toExit;
211600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
212600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /*
213600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Name of the stack.
214600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
215600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected String stackName;
216600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
217600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /*
218600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * IP address of stack -- this can be re-written by stun.
219600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
220600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @deprecated
221600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
222600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected String stackAddress;
223600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
224600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /*
225600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * INET address of stack (cached to avoid repeated lookup)
226600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
227600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @deprecated
228600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
229600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected InetAddress stackInetAddress;
230600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
231600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /*
232600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Request factory interface (to be provided by the application)
233600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
234600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected StackMessageFactory sipMessageFactory;
235600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
236600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /*
237600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Router to determine where to forward the request.
238600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
239600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected javax.sip.address.Router router;
240600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
241600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /*
242600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Number of pre-allocated threads for processing udp messages. -1 means no preallocated
243600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * threads ( dynamically allocated threads).
244600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
245600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected int threadPoolSize;
246600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
247600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /*
248600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * max number of simultaneous connections.
249600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
250600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected int maxConnections;
251600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
252600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /*
253600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Close accept socket on completion.
254600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
255600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected boolean cacheServerConnections;
256600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
257600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /*
258600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Close connect socket on Tx termination.
259600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
260600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected boolean cacheClientConnections;
261600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
262600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /*
263600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Use the user supplied router for all out of dialog requests.
264600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
265600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected boolean useRouterForAll;
266600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
267600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /*
268600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Max size of message that can be read from a TCP connection.
269600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
270600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected int maxContentLength;
271600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
272600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /*
273600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Max # of headers that a SIP message can contain.
274600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
275600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected int maxMessageSize;
276600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
277600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /*
278600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * A collection of message processors.
279600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
280600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private Collection<MessageProcessor> messageProcessors;
281600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
282600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /*
283600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Read timeout on TCP incoming sockets -- defines the time between reads for after delivery
284600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * of first byte of message.
285600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
286600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected int readTimeout;
287600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
288600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /*
289600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * The socket factory. Can be overriden by applications that want direct access to the
290600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * underlying socket.
291600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
292600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
293600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected NetworkLayer networkLayer;
294600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
295600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /*
296600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Outbound proxy String ( to be handed to the outbound proxy class on creation).
297600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
298600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected String outboundProxy;
299600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
300600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected String routerPath;
301600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
302600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    // Flag to indicate whether the stack will provide dialog
303600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    // support.
304600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected boolean isAutomaticDialogSupportEnabled;
305600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
306600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    // The set of events for which subscriptions can be forked.
307600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
308600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected HashSet<String> forkedEvents;
309600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
310600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    // Generate a timestamp header for retransmitted requests.
311600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected boolean generateTimeStampHeader;
312600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
313600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected AddressResolver addressResolver;
314600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
315600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    // Max time that the listener is allowed to take to respond to a
316600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    // request. Default is "infinity". This property allows
317600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    // containers to defend against buggy clients (that do not
318600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    // want to respond to requests).
319600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected int maxListenerResponseTime;
320600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
321600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
322600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    // A flag that indicates whether or not RFC 2543 clients are fully supported.
323600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    // If this is set to true, then To tag checking on the Dialog layer is
324600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    // disabled in a few places - resulting in possible breakage of forked dialogs.
325600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected boolean rfc2543Supported = true;
326600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
327600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    // / Provides a mechanism for applications to check the health of threads in
328600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    // the stack
329600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected ThreadAuditor threadAuditor = new ThreadAuditor();
330600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
331600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected LogRecordFactory logRecordFactory;
332600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
333600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    // Set to true if the client CANCEL transaction should be checked before sending
334600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    // it out.
335600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected boolean cancelClientTransactionChecked = true;
336600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
337600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    // Is to tag reassignment allowed.
338600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected boolean remoteTagReassignmentAllowed = true;
339600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
340600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected boolean logStackTraceOnMessageSend = true;
341600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
342600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    // Receive UDP buffer size
343600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected int receiveUdpBufferSize;
344600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
345600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    // Send UDP buffer size
346600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected int sendUdpBufferSize;
347600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
348600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected boolean stackDoesCongestionControl = true;
349600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
350600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected boolean isBackToBackUserAgent = false;
351600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
352600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected boolean checkBranchId;
353600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
354600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang	protected boolean isAutomaticDialogErrorHandlingEnabled = true;
355600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
356600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang	protected boolean isDialogTerminatedEventDeliveredForNullDialog = false;
357600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
358600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang	// Max time for a forked response to arrive. After this time, the original dialog
359600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang	// is not tracked. If you want to track the original transaction you need to specify
360600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang	// the max fork time with a stack init property.
361600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang	protected int maxForkTime = 0;
362600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
363600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
364600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    // / Timer to regularly ping the thread auditor (on behalf of the timer
365600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    // thread)
366600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    class PingTimer extends SIPStackTimerTask {
367600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // / Timer thread handle
368600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        ThreadAuditor.ThreadHandle threadHandle;
369600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
370600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // / Constructor
371600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        public PingTimer(ThreadAuditor.ThreadHandle a_oThreadHandle) {
372600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            threadHandle = a_oThreadHandle;
373600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
374600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
375600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        protected void runTask() {
376600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // Check if we still have a timer (it may be null after shutdown)
377600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (getTimer() != null) {
378600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // Register the timer task if we haven't done so
379600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (threadHandle == null) {
380600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // This happens only once since the thread handle is passed
381600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // to the next scheduled ping timer
382600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    threadHandle = getThreadAuditor().addCurrentThread();
383600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
384600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
385600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // Let the thread auditor know that the timer task is alive
386600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                threadHandle.ping();
387600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
388600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // Schedule the next ping
389600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                getTimer().schedule(new PingTimer(threadHandle),
390600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        threadHandle.getPingIntervalInMillisecs());
391600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
392600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
393600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
394600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
395600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
396600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
397600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    class RemoveForkedTransactionTimerTask extends SIPStackTimerTask {
398600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
399600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        private SIPClientTransaction clientTransaction;
400600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
401600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        public RemoveForkedTransactionTimerTask(SIPClientTransaction sipClientTransaction ) {
402600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            this.clientTransaction = sipClientTransaction;
403600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
404600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
405600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        @Override
406600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        protected void runTask() {
407600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang           forkedClientTransactionTable.remove(clientTransaction.getTransactionId());
408600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
409600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
410600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
411600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
412600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    static {
413600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    	// Standard set of methods that create dialogs.
414600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    	dialogCreatingMethods.add(Request.REFER);
415600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        dialogCreatingMethods.add(Request.INVITE);
416600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        dialogCreatingMethods.add(Request.SUBSCRIBE);
417600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
418600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
419600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
420600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Default constructor.
421600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
422600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected SIPTransactionStack() {
423600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.toExit = false;
424600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.forkedEvents = new HashSet<String>();
425600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // set of events for which subscriptions can be forked.
426600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // Set an infinite thread pool size.
427600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.threadPoolSize = -1;
428600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // Close response socket after infinte time.
429600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // for max performance
430600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.cacheServerConnections = true;
431600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // Close the request socket after infinite time.
432600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // for max performance
433600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.cacheClientConnections = true;
434600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // Max number of simultaneous connections.
435600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.maxConnections = -1;
436600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // Array of message processors.
437600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        messageProcessors = new ArrayList<MessageProcessor>();
438600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // Handle IO for this process.
439600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.ioHandler = new IOHandler(this);
440600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
441600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // The read time out is infinite.
442600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.readTimeout = -1;
443600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
444600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.maxListenerResponseTime = -1;
445600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
446600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // The default (identity) address lookup scheme
447600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
448600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.addressResolver = new DefaultAddressResolver();
449600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
450600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // Notify may or may not create a dialog. This is handled in
451600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // the code.
452600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // Create the transaction collections
453600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
454600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // Dialog dable.
455600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.dialogTable = new ConcurrentHashMap<String, SIPDialog>();
456600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.earlyDialogTable = new ConcurrentHashMap<String, SIPDialog>();
457600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
458600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        clientTransactionTable = new ConcurrentHashMap<String, SIPClientTransaction>();
459600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        serverTransactionTable = new ConcurrentHashMap<String, SIPServerTransaction>();
460600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.terminatedServerTransactionsPendingAck = new ConcurrentHashMap<String, SIPServerTransaction>();
461600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        mergeTable = new ConcurrentHashMap<String, SIPServerTransaction>();
462600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        retransmissionAlertTransactions = new ConcurrentHashMap<String, SIPServerTransaction>();
463600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
464600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // Start the timer event thread.
465600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
466600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.timer = new Timer();
467600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.pendingTransactions = new ConcurrentHashMap<String, SIPServerTransaction>();
468600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
469600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
470600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.forkedClientTransactionTable = new ConcurrentHashMap<String,SIPClientTransaction>();
471600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
472600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (getThreadAuditor().isEnabled()) {
473600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // Start monitoring the timer thread
474600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            timer.schedule(new PingTimer(null), 0);
475600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
476600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
477600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
478600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
479600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Re Initialize the stack instance.
480600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
481600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected void reInit() {
482600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (stackLogger.isLoggingEnabled())
483600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            stackLogger.logDebug("Re-initializing !");
484600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
485600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // Array of message processors.
486600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        messageProcessors = new ArrayList<MessageProcessor>();
487600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // Handle IO for this process.
488600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.ioHandler = new IOHandler(this);
489600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // clientTransactions = new ConcurrentLinkedQueue();
490600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // serverTransactions = new ConcurrentLinkedQueue();
491600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        pendingTransactions = new ConcurrentHashMap<String, SIPServerTransaction>();
492600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        clientTransactionTable = new ConcurrentHashMap<String, SIPClientTransaction>();
493600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        serverTransactionTable = new ConcurrentHashMap<String, SIPServerTransaction>();
494600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        retransmissionAlertTransactions = new ConcurrentHashMap<String, SIPServerTransaction>();
495600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        mergeTable = new ConcurrentHashMap<String, SIPServerTransaction>();
496600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // Dialog dable.
497600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.dialogTable = new ConcurrentHashMap<String, SIPDialog>();
498600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.earlyDialogTable = new ConcurrentHashMap<String, SIPDialog>();
499600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.terminatedServerTransactionsPendingAck = new ConcurrentHashMap<String,SIPServerTransaction>();
500600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.forkedClientTransactionTable = new ConcurrentHashMap<String,SIPClientTransaction>();
501600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
502600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.timer = new Timer();
503600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
504600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.activeClientTransactionCount = new AtomicInteger(0);
505600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
506600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
507600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
508600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
509600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Creates and binds, if necessary, a socket connected to the specified
510600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * destination address and port and then returns its local address.
511600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
512600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param dst the destination address that the socket would need to connect
513600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *            to.
514600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param dstPort the port number that the connection would be established
515600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * with.
516600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param localAddress the address that we would like to bind on
517600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * (null for the "any" address).
518600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param localPort the port that we'd like our socket to bind to (0 for a
519600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * random port).
520600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
521600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return the SocketAddress that this handler would use when connecting to
522600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * the specified destination address and port.
523600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
524600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @throws IOException
525600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
526600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public SocketAddress obtainLocalAddress(InetAddress dst, int dstPort,
527600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    InetAddress localAddress, int localPort)
528600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        throws IOException
529600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    {
530600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return this.ioHandler.obtainLocalAddress(
531600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        dst, dstPort, localAddress, localPort);
532600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
533600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
534600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
535600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
536600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * For debugging -- allows you to disable logging or enable logging selectively.
537600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
538600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
539600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
540600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public void disableLogging() {
541600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.getStackLogger().disableLogging();
542600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
543600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
544600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
545600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Globally enable message logging ( for debugging)
546600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
547600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
548600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public void enableLogging() {
549600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.getStackLogger().enableLogging();
550600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
551600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
552600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
553600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Print the dialog table.
554600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
555600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
556600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public void printDialogTable() {
557600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (isLoggingEnabled()) {
558600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            this.getStackLogger().logDebug("dialog table  = " + this.dialogTable);
559600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            System.out.println("dialog table = " + this.dialogTable);
560600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
561600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
562600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
563600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
564600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Retrieve a transaction from our table of transactions with pending retransmission alerts.
565600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
566600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param dialogId
567600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return -- the RetransmissionAlert enabled transaction corresponding to the given dialog
568600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *         ID.
569600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
570600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public SIPServerTransaction getRetransmissionAlertTransaction(String dialogId) {
571600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return (SIPServerTransaction) this.retransmissionAlertTransactions.get(dialogId);
572600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
573600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
574600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
575600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Return true if extension is supported.
576600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
577600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return true if extension is supported and false otherwise.
578600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
579600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public static boolean isDialogCreated(String method) {
580600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    	return dialogCreatingMethods.contains(method);
581600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
582600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
583600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
584600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Add an extension method.
585600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
586600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param extensionMethod -- extension method to support for dialog creation
587600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
588600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public void addExtensionMethod(String extensionMethod) {
589600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (extensionMethod.equals(Request.NOTIFY)) {
590600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (stackLogger.isLoggingEnabled())
591600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                stackLogger.logDebug("NOTIFY Supported Natively");
592600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } else {
593600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            dialogCreatingMethods.add(extensionMethod.trim().toUpperCase());
594600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
595600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
596600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
597600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
598600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Put a dialog into the dialog table.
599600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
600600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param dialog -- dialog to put into the dialog table.
601600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
602600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
603600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public void putDialog(SIPDialog dialog) {
604600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        String dialogId = dialog.getDialogId();
605600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (dialogTable.containsKey(dialogId)) {
606600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (stackLogger.isLoggingEnabled()) {
607600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                stackLogger.logDebug("putDialog: dialog already exists" + dialogId + " in table = "
608600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        + dialogTable.get(dialogId));
609600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
610600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return;
611600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
612600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (stackLogger.isLoggingEnabled()) {
613600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            stackLogger.logDebug("putDialog dialogId=" + dialogId + " dialog = " + dialog);
614600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
615600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        dialog.setStack(this);
616600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (stackLogger.isLoggingEnabled())
617600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            stackLogger.logStackTrace();
618600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        dialogTable.put(dialogId, dialog);
619600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
620600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
621600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
622600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
623600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Create a dialog and add this transaction to it.
624600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
625600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param transaction -- tx to add to the dialog.
626600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return the newly created Dialog.
627600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
628600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public SIPDialog createDialog(SIPTransaction transaction) {
629600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
630600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        SIPDialog retval = null;
631600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
632600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (transaction instanceof SIPClientTransaction) {
633600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            String dialogId = ((SIPRequest) transaction.getRequest()).getDialogId(false);
634600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (this.earlyDialogTable.get(dialogId) != null) {
635600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                SIPDialog dialog = this.earlyDialogTable.get(dialogId);
636600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (dialog.getState() == null || dialog.getState() == DialogState.EARLY) {
637600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    retval = dialog;
638600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                } else {
639600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    retval = new SIPDialog(transaction);
640600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    this.earlyDialogTable.put(dialogId, retval);
641600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
642600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } else {
643600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                retval = new SIPDialog(transaction);
644600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                this.earlyDialogTable.put(dialogId, retval);
645600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
646600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } else {
647600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            retval = new SIPDialog(transaction);
648600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
649600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
650600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return retval;
651600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
652600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
653600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
654600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
655600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Create a Dialog given a client tx and response.
656600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
657600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param transaction
658600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param sipResponse
659600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return
660600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
661600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
662600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public SIPDialog createDialog(SIPClientTransaction transaction, SIPResponse sipResponse) {
663600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        String dialogId = ((SIPRequest) transaction.getRequest()).getDialogId(false);
664600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        SIPDialog retval = null;
665600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (this.earlyDialogTable.get(dialogId) != null) {
666600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            retval = this.earlyDialogTable.get(dialogId);
667600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (sipResponse.isFinalResponse()) {
668600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                this.earlyDialogTable.remove(dialogId);
669600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
670600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
671600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } else {
672600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            retval = new SIPDialog(transaction, sipResponse);
673600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
674600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return retval;
675600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
676600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
677600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
678600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Create a Dialog given a sip provider and response.
679600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
680600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param sipProvider
681600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param sipResponse
682600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return
683600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
684600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public SIPDialog createDialog(SipProviderImpl sipProvider,
685600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang			SIPResponse sipResponse) {
686600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang		return new SIPDialog(sipProvider, sipResponse);
687600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang	}
688600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
689600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
690600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Remove the dialog from the dialog table.
691600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
692600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param dialog -- dialog to remove.
693600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
694600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public void removeDialog(SIPDialog dialog) {
695600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
696600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        String id = dialog.getDialogId();
697600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
698600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        String earlyId = dialog.getEarlyDialogId();
699600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
700600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (earlyId != null) {
701600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            this.earlyDialogTable.remove(earlyId);
702600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            this.dialogTable.remove(earlyId);
703600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
704600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
705600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (id != null) {
706600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
707600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // FHT: Remove dialog from table only if its associated dialog is the same as the one
708600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // specified
709600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
710600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            Object old = this.dialogTable.get(id);
711600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
712600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (old == dialog) {
713600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                this.dialogTable.remove(id);
714600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
715600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
716600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // We now deliver DTE even when the dialog is not originally present in the Dialog
717600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // Table
718600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // This happens before the dialog state is assigned.
719600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
720600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (!dialog.testAndSetIsDialogTerminatedEventDelivered()) {
721600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                DialogTerminatedEvent event = new DialogTerminatedEvent(dialog.getSipProvider(),
722600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        dialog);
723600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
724600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // Provide notification to the listener that the dialog has
725600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // ended.
726600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                dialog.getSipProvider().handleEvent(event, null);
727600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
728600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
729600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
730600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } else if ( this.isDialogTerminatedEventDeliveredForNullDialog ) {
731600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (!dialog.testAndSetIsDialogTerminatedEventDelivered()) {
732600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                DialogTerminatedEvent event = new DialogTerminatedEvent(dialog.getSipProvider(),
733600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        dialog);
734600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
735600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // Provide notification to the listener that the dialog has
736600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // ended.
737600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                dialog.getSipProvider().handleEvent(event, null);
738600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
739600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
740600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
741600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
742600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
743600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
744600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
745600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Return the dialog for a given dialog ID. If compatibility is enabled then we do not assume
746600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * the presence of tags and hence need to add a flag to indicate whether this is a server or
747600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * client transaction.
748600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
749600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param dialogId is the dialog id to check.
750600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
751600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
752600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public SIPDialog getDialog(String dialogId) {
753600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
754600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        SIPDialog sipDialog = (SIPDialog) dialogTable.get(dialogId);
755600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (stackLogger.isLoggingEnabled()) {
756600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            stackLogger.logDebug("getDialog(" + dialogId + ") : returning " + sipDialog);
757600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
758600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return sipDialog;
759600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
760600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
761600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
762600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
763600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Remove the dialog given its dialog id. This is used for dialog id re-assignment only.
764600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
765600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param dialogId is the dialog Id to remove.
766600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
767600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public void removeDialog(String dialogId) {
768600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (stackLogger.isLoggingEnabled()) {
769600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            stackLogger.logWarning("Silently removing dialog from table");
770600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
771600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        dialogTable.remove(dialogId);
772600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
773600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
774600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
775600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Find a matching client SUBSCRIBE to the incoming notify. NOTIFY requests are matched to
776600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * such SUBSCRIBE requests if they contain the same "Call-ID", a "To" header "tag" parameter
777600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * which matches the "From" header "tag" parameter of the SUBSCRIBE, and the same "Event"
778600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * header field. Rules for comparisons of the "Event" headers are described in section 7.2.1.
779600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * If a matching NOTIFY request contains a "Subscription-State" of "active" or "pending", it
780600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * creates a new subscription and a new dialog (unless they have already been created by a
781600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * matching response, as described above).
782600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
783600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param notifyMessage
784600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return -- the matching ClientTransaction with semaphore aquired or null if no such client
785600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *         transaction can be found.
786600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
787600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public SIPClientTransaction findSubscribeTransaction(SIPRequest notifyMessage,
788600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            ListeningPointImpl listeningPoint) {
789600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        SIPClientTransaction retval = null;
790600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        try {
791600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            Iterator it = clientTransactionTable.values().iterator();
792600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (stackLogger.isLoggingEnabled())
793600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            	stackLogger.logDebug("ct table size = " + clientTransactionTable.size());
794600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            String thisToTag = notifyMessage.getTo().getTag();
795600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (thisToTag == null) {
796600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                return retval;
797600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
798600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            Event eventHdr = (Event) notifyMessage.getHeader(EventHeader.NAME);
799600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (eventHdr == null) {
800600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (stackLogger.isLoggingEnabled()) {
801600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    stackLogger.logDebug("event Header is null -- returning null");
802600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
803600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
804600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                return retval;
805600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
806600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            while (it.hasNext()) {
807600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                SIPClientTransaction ct = (SIPClientTransaction) it.next();
808600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (!ct.getMethod().equals(Request.SUBSCRIBE))
809600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    continue;
810600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
811600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // if ( sipProvider.getListeningPoint(transport) == null)
812600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                String fromTag = ct.from.getTag();
813600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                Event hisEvent = ct.event;
814600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // Event header is mandatory but some slopply clients
815600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // dont include it.
816600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (hisEvent == null)
817600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    continue;
818600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (stackLogger.isLoggingEnabled()) {
819600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    stackLogger.logDebug("ct.fromTag = " + fromTag);
820600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    stackLogger.logDebug("thisToTag = " + thisToTag);
821600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    stackLogger.logDebug("hisEvent = " + hisEvent);
822600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    stackLogger.logDebug("eventHdr " + eventHdr);
823600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
824600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
825600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (  fromTag.equalsIgnoreCase(thisToTag)
826600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                      && hisEvent != null
827600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                      && eventHdr.match(hisEvent)
828600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                      && notifyMessage.getCallId().getCallId().equalsIgnoreCase(
829600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                ct.callId.getCallId())) {
830600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    if (ct.acquireSem())
831600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        retval = ct;
832600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    return retval;
833600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
834600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
835600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
836600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return retval;
837600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } finally {
838600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        	if (stackLogger.isLoggingEnabled())
839600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                stackLogger.logDebug("findSubscribeTransaction : returning " + retval);
840600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
841600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
842600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
843600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
844600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
845600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
846600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Add entry to "Transaction Pending ACK" table.
847600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
848600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param serverTransaction
849600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
850600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public void addTransactionPendingAck(SIPServerTransaction serverTransaction) {
851600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        String branchId = ((SIPRequest)serverTransaction.getRequest()).getTopmostVia().getBranch();
852600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if ( branchId != null ) {
853600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            this.terminatedServerTransactionsPendingAck.put(branchId, serverTransaction);
854600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
855600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
856600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
857600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
858600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
859600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Get entry in the server transaction pending ACK table corresponding to an ACK.
860600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
861600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param ackMessage
862600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return
863600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
864600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public SIPServerTransaction findTransactionPendingAck(SIPRequest ackMessage) {
865600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return this.terminatedServerTransactionsPendingAck.get(ackMessage.getTopmostVia().getBranch());
866600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
867600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
868600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
869600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Remove entry from "Transaction Pending ACK" table.
870600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
871600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param serverTransaction
872600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return
873600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
874600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
875600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public boolean removeTransactionPendingAck(SIPServerTransaction serverTransaction) {
876600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        String branchId = ((SIPRequest)serverTransaction.getRequest()).getTopmostVia().getBranch();
877600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if ( branchId != null && this.terminatedServerTransactionsPendingAck.containsKey(branchId) ) {
878600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            this.terminatedServerTransactionsPendingAck.remove(branchId);
879600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return true;
880600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } else {
881600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return false;
882600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
883600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
884600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
885600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
886600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Check if this entry exists in the "Transaction Pending ACK" table.
887600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
888600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param serverTransaction
889600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return
890600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
891600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public boolean isTransactionPendingAck(SIPServerTransaction serverTransaction) {
892600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        String branchId = ((SIPRequest)serverTransaction.getRequest()).getTopmostVia().getBranch();
893600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return this.terminatedServerTransactionsPendingAck.contains(branchId);
894600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
895600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
896600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
897600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Find the transaction corresponding to a given request.
898600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
899600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param sipMessage request for which to retrieve the transaction.
900600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
901600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param isServer search the server transaction table if true.
902600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
903600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return the transaction object corresponding to the request or null if no such mapping
904600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *         exists.
905600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
906600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public SIPTransaction findTransaction(SIPMessage sipMessage, boolean isServer) {
907600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        SIPTransaction retval = null;
908600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        try {
909600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (isServer) {
910600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                Via via = sipMessage.getTopmostVia();
911600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (via.getBranch() != null) {
912600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    String key = sipMessage.getTransactionId();
913600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
914600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    retval = (SIPTransaction) serverTransactionTable.get(key);
915600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    if (stackLogger.isLoggingEnabled())
916600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        getStackLogger().logDebug(
917600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                "serverTx: looking for key " + key + " existing="
918600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                + serverTransactionTable);
919600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    if (key.startsWith(SIPConstants.BRANCH_MAGIC_COOKIE_LOWER_CASE)) {
920600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        return retval;
921600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    }
922600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
923600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
924600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // Need to scan the table for old style transactions (RFC 2543
925600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // style)
926600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                Iterator<SIPServerTransaction> it = serverTransactionTable.values().iterator();
927600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                while (it.hasNext()) {
928600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    SIPServerTransaction sipServerTransaction = (SIPServerTransaction) it.next();
929600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    if (sipServerTransaction.isMessagePartOfTransaction(sipMessage)) {
930600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        retval = sipServerTransaction;
931600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        return retval;
932600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    }
933600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
934600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
935600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } else {
936600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                Via via = sipMessage.getTopmostVia();
937600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (via.getBranch() != null) {
938600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    String key = sipMessage.getTransactionId();
939600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    if (stackLogger.isLoggingEnabled())
940600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        getStackLogger().logDebug("clientTx: looking for key " + key);
941600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    retval = (SIPTransaction) clientTransactionTable.get(key);
942600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    if (key.startsWith(SIPConstants.BRANCH_MAGIC_COOKIE_LOWER_CASE)) {
943600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        return retval;
944600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    }
945600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
946600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
947600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // Need to scan the table for old style transactions (RFC 2543
948600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // style). This is terribly slow but we need to do this
949600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // for backasswords compatibility.
950600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                Iterator<SIPClientTransaction> it = clientTransactionTable.values().iterator();
951600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                while (it.hasNext()) {
952600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    SIPClientTransaction clientTransaction = (SIPClientTransaction) it.next();
953600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    if (clientTransaction.isMessagePartOfTransaction(sipMessage)) {
954600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        retval = clientTransaction;
955600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        return retval;
956600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    }
957600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
958600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
959600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
960600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } finally {
961600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        	if ( this.getStackLogger().isLoggingEnabled()) {
962600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        	  this.getStackLogger().logDebug("findTransaction: returning  : " + retval);
963600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        	}
964600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
965600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return retval;
966600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
967600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
968600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
969600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
970600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Get the transaction to cancel. Search the server transaction table for a transaction that
971600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * matches the given transaction.
972600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
973600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public SIPTransaction findCancelTransaction(SIPRequest cancelRequest, boolean isServer) {
974600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
975600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (stackLogger.isLoggingEnabled()) {
976600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            stackLogger.logDebug("findCancelTransaction request= \n" + cancelRequest
977600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    + "\nfindCancelRequest isServer=" + isServer);
978600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
979600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
980600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (isServer) {
981600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            Iterator<SIPServerTransaction> li = this.serverTransactionTable.values().iterator();
982600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            while (li.hasNext()) {
983600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                SIPTransaction transaction = (SIPTransaction) li.next();
984600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
985600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                SIPServerTransaction sipServerTransaction = (SIPServerTransaction) transaction;
986600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (sipServerTransaction.doesCancelMatchTransaction(cancelRequest))
987600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    return sipServerTransaction;
988600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
989600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
990600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } else {
991600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            Iterator<SIPClientTransaction> li = this.clientTransactionTable.values().iterator();
992600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            while (li.hasNext()) {
993600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                SIPTransaction transaction = (SIPTransaction) li.next();
994600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
995600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                SIPClientTransaction sipClientTransaction = (SIPClientTransaction) transaction;
996600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (sipClientTransaction.doesCancelMatchTransaction(cancelRequest))
997600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    return sipClientTransaction;
998600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
999600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
1000600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1001600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
1002600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (stackLogger.isLoggingEnabled())
1003600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            stackLogger.logDebug("Could not find transaction for cancel request");
1004600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return null;
1005600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1006600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1007600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
1008600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Construcor for the stack. Registers the request and response factories for the stack.
1009600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
1010600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param messageFactory User-implemented factory for processing messages.
1011600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
1012600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected SIPTransactionStack(StackMessageFactory messageFactory) {
1013600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this();
1014600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.sipMessageFactory = messageFactory;
1015600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1016600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1017600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
1018600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Finds a pending server transaction. Since each request may be handled either statefully or
1019600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * statelessly, we keep a map of pending transactions so that a duplicate transaction is not
1020600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * created if a second request is recieved while the first one is being processed.
1021600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
1022600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param requestReceived
1023600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return -- the pending transaction or null if no such transaction exists.
1024600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
1025600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public SIPServerTransaction findPendingTransaction(SIPRequest requestReceived) {
1026600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (this.stackLogger.isLoggingEnabled()) {
1027600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            this.stackLogger.logDebug("looking for pending tx for :"
1028600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    + requestReceived.getTransactionId());
1029600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
1030600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return (SIPServerTransaction) pendingTransactions.get(requestReceived.getTransactionId());
1031600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1032600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1033600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1034600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
1035600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * See if there is a pending transaction with the same Merge ID as the Merge ID obtained from
1036600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * the SIP Request. The Merge table is for handling the following condition: If the request
1037600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * has no tag in the To header field, the UAS core MUST check the request against ongoing
1038600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * transactions. If the From tag, Call-ID, and CSeq exactly match those associated with an
1039600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * ongoing transaction, but the request does not match that transaction (based on the matching
1040600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * rules in Section 17.2.3), the UAS core SHOULD generate a 482 (Loop Detected) response and
1041600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * pass it to the server transaction.
1042600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
1043600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public SIPServerTransaction findMergedTransaction(SIPRequest sipRequest) {
1044600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (! sipRequest.getMethod().equals(Request.INVITE)) {
1045600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            /*
1046600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang             * Dont need to worry about request merging for Non-INVITE transactions.
1047600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang             */
1048600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return null;
1049600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
1050600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        String mergeId = sipRequest.getMergeId();
1051600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        SIPServerTransaction mergedTransaction = (SIPServerTransaction) this.mergeTable.get(mergeId);
1052600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (mergeId == null ) {
1053600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return null;
1054600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } else if (mergedTransaction != null && !mergedTransaction.isMessagePartOfTransaction(sipRequest) ) {
1055600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return mergedTransaction;
1056600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } else {
1057600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            /*
1058600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang             * Check the server transactions that have resulted in dialogs.
1059600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang             */
1060600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang           for (Dialog dialog: this.dialogTable.values() ) {
1061600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang               SIPDialog sipDialog = (SIPDialog) dialog ;
1062600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang               if (sipDialog.getFirstTransaction()  != null &&
1063600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                   sipDialog.getFirstTransaction() instanceof ServerTransaction) {
1064600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                   SIPServerTransaction serverTransaction = ((SIPServerTransaction) sipDialog.getFirstTransaction());
1065600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                   SIPRequest transactionRequest = ((SIPServerTransaction) sipDialog.getFirstTransaction()).getOriginalRequest();
1066600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                   if ( (! serverTransaction.isMessagePartOfTransaction(sipRequest))
1067600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                           && sipRequest.getMergeId().equals(transactionRequest.getMergeId())) {
1068600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                           return (SIPServerTransaction) sipDialog.getFirstTransaction();
1069600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                   }
1070600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang               }
1071600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang           }
1072600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang           return null;
1073600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
1074600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1075600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1076600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
1077600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Remove a pending Server transaction from the stack. This is called after the user code has
1078600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * completed execution in the listener.
1079600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
1080600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param tr -- pending transaction to remove.
1081600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
1082600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public void removePendingTransaction(SIPServerTransaction tr) {
1083600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (this.stackLogger.isLoggingEnabled()) {
1084600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            this.stackLogger.logDebug("removePendingTx: " + tr.getTransactionId());
1085600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
1086600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.pendingTransactions.remove(tr.getTransactionId());
1087600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1088600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1089600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1090600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
1091600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Remove a transaction from the merge table.
1092600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
1093600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param tr -- the server transaction to remove from the merge table.
1094600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
1095600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
1096600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public void removeFromMergeTable(SIPServerTransaction tr) {
1097600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (stackLogger.isLoggingEnabled()) {
1098600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            this.stackLogger.logDebug("Removing tx from merge table ");
1099600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
1100600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        String key = ((SIPRequest) tr.getRequest()).getMergeId();
1101600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (key != null) {
1102600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            this.mergeTable.remove(key);
1103600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
1104600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1105600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1106600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
1107600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Put this into the merge request table.
1108600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
1109600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param sipTransaction -- transaction to put into the merge table.
1110600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
1111600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
1112600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public void putInMergeTable(SIPServerTransaction sipTransaction, SIPRequest sipRequest) {
1113600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        String mergeKey = sipRequest.getMergeId();
1114600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (mergeKey != null) {
1115600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            this.mergeTable.put(mergeKey, sipTransaction);
1116600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
1117600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1118600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1119600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
1120600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Map a Server transaction (possibly sending out a 100 if the server tx is an INVITE). This
1121600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * actually places it in the hash table and makes it known to the stack.
1122600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
1123600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param transaction -- the server transaction to map.
1124600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
1125600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public void mapTransaction(SIPServerTransaction transaction) {
1126600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (transaction.isMapped)
1127600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return;
1128600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        addTransactionHash(transaction);
1129600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // transaction.startTransactionTimer();
1130600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        transaction.isMapped = true;
1131600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1132600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1133600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
1134600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Handles a new SIP request. It finds a server transaction to handle this message. If none
1135600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * exists, it creates a new transaction.
1136600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
1137600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param requestReceived Request to handle.
1138600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param requestMessageChannel Channel that received message.
1139600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
1140600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return A server transaction.
1141600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
1142600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public ServerRequestInterface newSIPServerRequest(SIPRequest requestReceived,
1143600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            MessageChannel requestMessageChannel) {
1144600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // Iterator through all server transactions
1145600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        Iterator<SIPServerTransaction> transactionIterator;
1146600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // Next transaction in the set
1147600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        SIPServerTransaction nextTransaction;
1148600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // Transaction to handle this request
1149600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        SIPServerTransaction currentTransaction;
1150600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1151600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        String key = requestReceived.getTransactionId();
1152600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1153600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        requestReceived.setMessageChannel(requestMessageChannel);
1154600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1155600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        currentTransaction = (SIPServerTransaction) serverTransactionTable.get(key);
1156600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1157600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // Got to do this for bacasswards compatibility.
1158600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (currentTransaction == null
1159600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                || !currentTransaction.isMessagePartOfTransaction(requestReceived)) {
1160600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1161600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // Loop through all server transactions
1162600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            transactionIterator = serverTransactionTable.values().iterator();
1163600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            currentTransaction = null;
1164600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (!key.toLowerCase().startsWith(SIPConstants.BRANCH_MAGIC_COOKIE_LOWER_CASE)) {
1165600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                while (transactionIterator.hasNext() && currentTransaction == null) {
1166600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1167600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    nextTransaction = (SIPServerTransaction) transactionIterator.next();
1168600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1169600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // If this transaction should handle this request,
1170600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    if (nextTransaction.isMessagePartOfTransaction(requestReceived)) {
1171600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        // Mark this transaction as the one
1172600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        // to handle this message
1173600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        currentTransaction = nextTransaction;
1174600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    }
1175600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
1176600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
1177600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1178600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // If no transaction exists to handle this message
1179600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (currentTransaction == null) {
1180600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                currentTransaction = findPendingTransaction(requestReceived);
1181600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (currentTransaction != null) {
1182600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // Associate the tx with the received request.
1183600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    requestReceived.setTransaction(currentTransaction);
1184600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    if (currentTransaction != null && currentTransaction.acquireSem())
1185600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        return currentTransaction;
1186600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    else
1187600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        return null;
1188600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1189600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
1190600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // Creating a new server tx. May fail under heavy load.
1191600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                currentTransaction = createServerTransaction(requestMessageChannel);
1192600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (currentTransaction != null) {
1193600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // currentTransaction.setPassToListener();
1194600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    currentTransaction.setOriginalRequest(requestReceived);
1195600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // Associate the tx with the received request.
1196600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    requestReceived.setTransaction(currentTransaction);
1197600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
1198600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1199600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
1200600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1201600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
1202600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1203600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // Set ths transaction's encapsulated request
1204600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // interface from the superclass
1205600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (stackLogger.isLoggingEnabled()) {
1206600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            stackLogger.logDebug("newSIPServerRequest( " + requestReceived.getMethod() + ":"
1207600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    + requestReceived.getTopmostVia().getBranch() + "):" + currentTransaction);
1208600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
1209600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1210600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (currentTransaction != null)
1211600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            currentTransaction.setRequestInterface(sipMessageFactory.newSIPServerRequest(
1212600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    requestReceived, currentTransaction));
1213600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1214600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (currentTransaction != null && currentTransaction.acquireSem()) {
1215600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return currentTransaction;
1216600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } else if (currentTransaction != null) {
1217600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            try {
1218600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                /*
1219600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                 * Already processing a message for this transaction.
1220600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                 * SEND a trying ( message already being processed ).
1221600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                 */
1222600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (currentTransaction.isMessagePartOfTransaction(requestReceived) &&
1223600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    currentTransaction.getMethod().equals(requestReceived.getMethod())) {
1224600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    SIPResponse trying = requestReceived.createResponse(Response.TRYING);
1225600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    trying.removeContent();
1226600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    currentTransaction.getMessageChannel().sendMessage(trying);
1227600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
1228600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } catch (Exception ex) {
1229600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            	if (isLoggingEnabled())
1230600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            		stackLogger.logError("Exception occured sending TRYING");
1231600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
1232600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return null;
1233600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } else {
1234600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return null;
1235600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
1236600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1237600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1238600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
1239600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Handles a new SIP response. It finds a client transaction to handle this message. If none
1240600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * exists, it sends the message directly to the superclass.
1241600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
1242600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param responseReceived Response to handle.
1243600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param responseMessageChannel Channel that received message.
1244600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
1245600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return A client transaction.
1246600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
1247600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public ServerResponseInterface newSIPServerResponse(SIPResponse responseReceived,
1248600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            MessageChannel responseMessageChannel) {
1249600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1250600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // Iterator through all client transactions
1251600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        Iterator<SIPClientTransaction> transactionIterator;
1252600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // Next transaction in the set
1253600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        SIPClientTransaction nextTransaction;
1254600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // Transaction to handle this request
1255600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        SIPClientTransaction currentTransaction;
1256600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1257600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        String key = responseReceived.getTransactionId();
1258600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1259600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // Note that for RFC 3261 compliant operation, this lookup will
1260600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // return a tx if one exists and hence no need to search through
1261600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // the table.
1262600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        currentTransaction = (SIPClientTransaction) clientTransactionTable.get(key);
1263600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1264600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (currentTransaction == null
1265600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                || (!currentTransaction.isMessagePartOfTransaction(responseReceived) && !key
1266600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        .startsWith(SIPConstants.BRANCH_MAGIC_COOKIE_LOWER_CASE))) {
1267600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // Loop through all client transactions
1268600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1269600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            transactionIterator = clientTransactionTable.values().iterator();
1270600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            currentTransaction = null;
1271600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            while (transactionIterator.hasNext() && currentTransaction == null) {
1272600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1273600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                nextTransaction = (SIPClientTransaction) transactionIterator.next();
1274600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1275600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // If this transaction should handle this request,
1276600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (nextTransaction.isMessagePartOfTransaction(responseReceived)) {
1277600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1278600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // Mark this transaction as the one to
1279600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // handle this message
1280600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    currentTransaction = nextTransaction;
1281600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1282600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
1283600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1284600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
1285600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1286600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // If no transaction exists to handle this message,
1287600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (currentTransaction == null) {
1288600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // JvB: Need to log before passing the response to the client
1289600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // app, it
1290600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // gets modified!
1291600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (this.stackLogger.isLoggingEnabled(StackLogger.TRACE_INFO)) {
1292600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    responseMessageChannel.logResponse(responseReceived, System
1293600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            .currentTimeMillis(), "before processing");
1294600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
1295600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1296600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // Pass the message directly to the TU
1297600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                return sipMessageFactory.newSIPServerResponse(responseReceived,
1298600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        responseMessageChannel);
1299600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1300600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
1301600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
1302600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1303600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // Aquire the sem -- previous request may still be processing.
1304600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        boolean acquired = currentTransaction.acquireSem();
1305600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // Set ths transaction's encapsulated response interface
1306600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // from the superclass
1307600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (this.stackLogger.isLoggingEnabled(StackLogger.TRACE_INFO)) {
1308600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            currentTransaction.logResponse(responseReceived, System.currentTimeMillis(),
1309600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    "before processing");
1310600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
1311600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1312600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (acquired) {
1313600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            ServerResponseInterface sri = sipMessageFactory.newSIPServerResponse(
1314600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    responseReceived, currentTransaction);
1315600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (sri != null) {
1316600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                currentTransaction.setResponseInterface(sri);
1317600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } else {
1318600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (this.stackLogger.isLoggingEnabled()) {
1319600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    this.stackLogger.logDebug("returning null - serverResponseInterface is null!");
1320600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
1321600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                currentTransaction.releaseSem();
1322600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                return null;
1323600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
1324600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } else {
1325600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        	if (stackLogger.isLoggingEnabled())
1326600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        		this.stackLogger.logDebug("Could not aquire semaphore !!");
1327600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
1328600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1329600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (acquired)
1330600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return currentTransaction;
1331600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        else
1332600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return null;
1333600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1334600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1335600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1336600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
1337600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Creates a client transaction to handle a new request. Gets the real message channel from
1338600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * the superclass, and then creates a new client transaction wrapped around this channel.
1339600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
1340600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param nextHop Hop to create a channel to contact.
1341600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
1342600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public MessageChannel createMessageChannel(SIPRequest request, MessageProcessor mp,
1343600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            Hop nextHop) throws IOException {
1344600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // New client transaction to return
1345600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        SIPTransaction returnChannel;
1346600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1347600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // Create a new client transaction around the
1348600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // superclass' message channel
1349600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // Create the host/port of the target hop
1350600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        Host targetHost = new Host();
1351600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        targetHost.setHostname(nextHop.getHost());
1352600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        HostPort targetHostPort = new HostPort();
1353600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        targetHostPort.setHost(targetHost);
1354600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        targetHostPort.setPort(nextHop.getPort());
1355600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        MessageChannel mc = mp.createMessageChannel(targetHostPort);
1356600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1357600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // Superclass will return null if no message processor
1358600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // available for the transport.
1359600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (mc == null)
1360600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return null;
1361600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1362600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        returnChannel = createClientTransaction(request, mc);
1363600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1364600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        ((SIPClientTransaction) returnChannel).setViaPort(nextHop.getPort());
1365600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        ((SIPClientTransaction) returnChannel).setViaHost(nextHop.getHost());
1366600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        addTransactionHash(returnChannel);
1367600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // clientTransactionTable.put(returnChannel.getTransactionId(),
1368600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // returnChannel);
1369600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // Add the transaction timer for the state machine.
1370600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // returnChannel.startTransactionTimer();
1371600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return returnChannel;
1372600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1373600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1374600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1375600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
1376600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Creates a client transaction that encapsulates a MessageChannel. Useful for implementations
1377600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * that want to subclass the standard
1378600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
1379600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param encapsulatedMessageChannel Message channel of the transport layer.
1380600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
1381600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public SIPClientTransaction createClientTransaction(SIPRequest sipRequest,
1382600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            MessageChannel encapsulatedMessageChannel) {
1383600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        SIPClientTransaction ct = new SIPClientTransaction(this, encapsulatedMessageChannel);
1384600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        ct.setOriginalRequest(sipRequest);
1385600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return ct;
1386600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1387600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1388600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
1389600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Creates a server transaction that encapsulates a MessageChannel. Useful for implementations
1390600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * that want to subclass the standard
1391600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
1392600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param encapsulatedMessageChannel Message channel of the transport layer.
1393600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
1394600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public SIPServerTransaction createServerTransaction(MessageChannel encapsulatedMessageChannel) {
1395600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    	// Issue 256 : be consistent with createClientTransaction, if unlimitedServerTransactionTableSize is true,
1396600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    	// a new Server Transaction is created no matter what
1397600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (unlimitedServerTransactionTableSize) {
1398600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return new SIPServerTransaction(this, encapsulatedMessageChannel);
1399600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } else {
1400600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            float threshold = ((float) (serverTransactionTable.size() - serverTransactionTableLowaterMark))
1401600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    / ((float) (serverTransactionTableHighwaterMark - serverTransactionTableLowaterMark));
1402600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            boolean decision = Math.random() > 1.0 - threshold;
1403600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (decision) {
1404600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                return null;
1405600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } else {
1406600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                return new SIPServerTransaction(this, encapsulatedMessageChannel);
1407600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
1408600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1409600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
1410600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1411600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1412600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1413600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
1414600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Get the size of the client transaction table.
1415600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
1416600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return -- size of the ct table.
1417600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
1418600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public int getClientTransactionTableSize() {
1419600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return this.clientTransactionTable.size();
1420600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1421600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1422600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
1423600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Get the size of the server transaction table.
1424600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
1425600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return -- size of the server table.
1426600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
1427600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public int getServerTransactionTableSize() {
1428600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return this.serverTransactionTable.size();
1429600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1430600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1431600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
1432600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Add a new client transaction to the set of existing transactions. Add it to the top of the
1433600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * list so an incoming response has less work to do in order to find the transaction.
1434600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
1435600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param clientTransaction -- client transaction to add to the set.
1436600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
1437600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public void addTransaction(SIPClientTransaction clientTransaction) {
1438600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (stackLogger.isLoggingEnabled())
1439600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            stackLogger.logDebug("added transaction " + clientTransaction);
1440600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        addTransactionHash(clientTransaction);
1441600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1442600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1443600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1444600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
1445600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Remove transaction. This actually gets the tx out of the search structures which the stack
1446600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * keeps around. When the tx
1447600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
1448600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public void removeTransaction(SIPTransaction sipTransaction) {
1449600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (stackLogger.isLoggingEnabled()) {
1450600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            stackLogger.logDebug("Removing Transaction = " + sipTransaction.getTransactionId()
1451600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    + " transaction = " + sipTransaction);
1452600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
1453600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (sipTransaction instanceof SIPServerTransaction) {
1454600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (stackLogger.isLoggingEnabled())
1455600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                stackLogger.logStackTrace();
1456600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            String key = sipTransaction.getTransactionId();
1457600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            Object removed = serverTransactionTable.remove(key);
1458600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            String method = sipTransaction.getMethod();
1459600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            this.removePendingTransaction((SIPServerTransaction) sipTransaction);
1460600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            this.removeTransactionPendingAck((SIPServerTransaction) sipTransaction);
1461600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (method.equalsIgnoreCase(Request.INVITE)) {
1462600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                this.removeFromMergeTable((SIPServerTransaction) sipTransaction);
1463600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
1464600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // Send a notification to the listener.
1465600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            SipProviderImpl sipProvider = (SipProviderImpl) sipTransaction.getSipProvider();
1466600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (removed != null && sipTransaction.testAndSetTransactionTerminatedEvent()) {
1467600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                TransactionTerminatedEvent event = new TransactionTerminatedEvent(sipProvider,
1468600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        (ServerTransaction) sipTransaction);
1469600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1470600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                sipProvider.handleEvent(event, sipTransaction);
1471600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1472600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
1473600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } else {
1474600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1475600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            String key = sipTransaction.getTransactionId();
1476600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            Object removed = clientTransactionTable.remove(key);
1477600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1478600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (stackLogger.isLoggingEnabled()) {
1479600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                stackLogger.logDebug("REMOVED client tx " + removed + " KEY = " + key);
1480600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if ( removed != null ) {
1481600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                   SIPClientTransaction clientTx = (SIPClientTransaction)removed;
1482600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                   if ( clientTx.getMethod().equals(Request.INVITE) && this.maxForkTime != 0 ) {
1483600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                       RemoveForkedTransactionTimerTask ttask = new RemoveForkedTransactionTimerTask(clientTx);
1484600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                       this.timer.schedule(ttask, this.maxForkTime * 1000);
1485600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                   }
1486600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
1487600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
1488600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1489600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // Send a notification to the listener.
1490600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (removed != null && sipTransaction.testAndSetTransactionTerminatedEvent()) {
1491600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                SipProviderImpl sipProvider = (SipProviderImpl) sipTransaction.getSipProvider();
1492600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                TransactionTerminatedEvent event = new TransactionTerminatedEvent(sipProvider,
1493600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        (ClientTransaction) sipTransaction);
1494600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1495600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                sipProvider.handleEvent(event, sipTransaction);
1496600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
1497600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1498600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
1499600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1500600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1501600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
1502600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Add a new server transaction to the set of existing transactions. Add it to the top of the
1503600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * list so an incoming ack has less work to do in order to find the transaction.
1504600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
1505600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param serverTransaction -- server transaction to add to the set.
1506600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
1507600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public void addTransaction(SIPServerTransaction serverTransaction) throws IOException {
1508600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (stackLogger.isLoggingEnabled())
1509600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            stackLogger.logDebug("added transaction " + serverTransaction);
1510600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        serverTransaction.map();
1511600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1512600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        addTransactionHash(serverTransaction);
1513600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1514600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1515600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1516600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
1517600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Hash table for quick lookup of transactions. Here we wait for room if needed.
1518600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
1519600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private void addTransactionHash(SIPTransaction sipTransaction) {
1520600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        SIPRequest sipRequest = sipTransaction.getOriginalRequest();
1521600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (sipTransaction instanceof SIPClientTransaction) {
1522600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (!this.unlimitedClientTransactionTableSize) {
1523600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (this.activeClientTransactionCount.get() > clientTransactionTableHiwaterMark) {
1524600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    try {
1525600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        synchronized (this.clientTransactionTable) {
1526600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            this.clientTransactionTable.wait();
1527600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            this.activeClientTransactionCount.incrementAndGet();
1528600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        }
1529600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1530600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    } catch (Exception ex) {
1531600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        if (stackLogger.isLoggingEnabled()) {
1532600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                            stackLogger.logError("Exception occured while waiting for room", ex);
1533600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        }
1534600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1535600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    }
1536600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
1537600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } else {
1538600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                this.activeClientTransactionCount.incrementAndGet();
1539600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
1540600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            String key = sipRequest.getTransactionId();
1541600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            clientTransactionTable.put(key, (SIPClientTransaction) sipTransaction);
1542600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1543600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (stackLogger.isLoggingEnabled()) {
1544600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                stackLogger.logDebug(" putTransactionHash : " + " key = " + key);
1545600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
1546600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } else {
1547600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            String key = sipRequest.getTransactionId();
1548600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1549600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (stackLogger.isLoggingEnabled()) {
1550600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                stackLogger.logDebug(" putTransactionHash : " + " key = " + key);
1551600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
1552600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            serverTransactionTable.put(key, (SIPServerTransaction) sipTransaction);
1553600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1554600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
1555600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1556600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1557600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1558600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
1559600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * This method is called when a client tx transitions to the Completed or Terminated state.
1560600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
1561600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
1562600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected void decrementActiveClientTransactionCount() {
1563600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1564600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (this.activeClientTransactionCount.decrementAndGet() <= this.clientTransactionTableLowaterMark
1565600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                && !this.unlimitedClientTransactionTableSize) {
1566600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            synchronized (this.clientTransactionTable) {
1567600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1568600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                clientTransactionTable.notify();
1569600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1570600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
1571600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
1572600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1573600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1574600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
1575600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Remove the transaction from transaction hash.
1576600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
1577600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected void removeTransactionHash(SIPTransaction sipTransaction) {
1578600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        SIPRequest sipRequest = sipTransaction.getOriginalRequest();
1579600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (sipRequest == null)
1580600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return;
1581600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (sipTransaction instanceof SIPClientTransaction) {
1582600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            String key = sipTransaction.getTransactionId();
1583600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (stackLogger.isLoggingEnabled()) {
1584600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                stackLogger.logStackTrace();
1585600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                stackLogger.logDebug("removing client Tx : " + key);
1586600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
1587600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            clientTransactionTable.remove(key);
1588600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1589600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } else if (sipTransaction instanceof SIPServerTransaction) {
1590600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            String key = sipTransaction.getTransactionId();
1591600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            serverTransactionTable.remove(key);
1592600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (stackLogger.isLoggingEnabled()) {
1593600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                stackLogger.logDebug("removing server Tx : " + key);
1594600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
1595600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
1596600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1597600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1598600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
1599600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Invoked when an error has ocurred with a transaction.
1600600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
1601600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param transactionErrorEvent Error event.
1602600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
1603600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public synchronized void transactionErrorEvent(SIPTransactionErrorEvent transactionErrorEvent) {
1604600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        SIPTransaction transaction = (SIPTransaction) transactionErrorEvent.getSource();
1605600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1606600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (transactionErrorEvent.getErrorID() == SIPTransactionErrorEvent.TRANSPORT_ERROR) {
1607600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // Kill scanning of this transaction.
1608600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            transaction.setState(SIPTransaction.TERMINATED_STATE);
1609600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (transaction instanceof SIPServerTransaction) {
1610600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // let the reaper get him
1611600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                ((SIPServerTransaction) transaction).collectionTime = 0;
1612600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
1613600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            transaction.disableTimeoutTimer();
1614600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            transaction.disableRetransmissionTimer();
1615600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // Send a IO Exception to the Listener.
1616600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
1617600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1618600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1619600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /*
1620600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * (non-Javadoc)
1621600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @see gov.nist.javax.sip.stack.SIPDialogEventListener#dialogErrorEvent(gov.nist.javax.sip.stack.SIPDialogErrorEvent)
1622600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
1623600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public synchronized void dialogErrorEvent(SIPDialogErrorEvent dialogErrorEvent) {
1624600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        SIPDialog sipDialog = (SIPDialog) dialogErrorEvent.getSource();
1625600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        SipListener sipListener = ((SipStackImpl)this).getSipListener();
1626600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // if the app is not implementing the SipListenerExt interface we delete the dialog to avoid leaks
1627600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if(sipDialog != null && !(sipListener instanceof SipListenerExt)) {
1628600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        	sipDialog.delete();
1629600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
1630600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1631600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1632600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
1633600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Stop stack. Clear all the timer stuff. Make the stack close all accept connections and
1634600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * return. This is useful if you want to start/stop the stack several times from your
1635600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * application. Caution : use of this function could cause peculiar bugs as messages are
1636600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * prcessed asynchronously by the stack.
1637600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
1638600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public void stopStack() {
1639600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // Prevent NPE on two concurrent stops
1640600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (this.timer != null)
1641600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            this.timer.cancel();
1642600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1643600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // JvB: set it to null, SIPDialog tries to schedule things after stop
1644600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        timer = null;
1645600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.pendingTransactions.clear();
1646600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.toExit = true;
1647600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        synchronized (this) {
1648600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            this.notifyAll();
1649600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
1650600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        synchronized (this.clientTransactionTable) {
1651600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            clientTransactionTable.notifyAll();
1652600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
1653600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1654600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        synchronized (this.messageProcessors) {
1655600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // Threads must periodically check this flag.
1656600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            MessageProcessor[] processorList;
1657600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            processorList = getMessageProcessors();
1658600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            for (int processorIndex = 0; processorIndex < processorList.length; processorIndex++) {
1659600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                removeMessageProcessor(processorList[processorIndex]);
1660600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
1661600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            this.ioHandler.closeAll();
1662600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // Let the processing complete.
1663600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1664600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
1665600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        try {
1666600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1667600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            Thread.sleep(1000);
1668600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1669600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } catch (InterruptedException ex) {
1670600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
1671600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.clientTransactionTable.clear();
1672600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.serverTransactionTable.clear();
1673600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1674600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.dialogTable.clear();
1675600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.serverLogger.closeLogFile();
1676600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1677600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1678600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1679600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
1680600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Put a transaction in the pending transaction list. This is to avoid a race condition when a
1681600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * duplicate may arrive when the application is deciding whether to create a transaction or
1682600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * not.
1683600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
1684600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public void putPendingTransaction(SIPServerTransaction tr) {
1685600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (stackLogger.isLoggingEnabled())
1686600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            stackLogger.logDebug("putPendingTransaction: " + tr);
1687600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1688600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.pendingTransactions.put(tr.getTransactionId(), tr);
1689600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1690600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1691600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1692600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
1693600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Return the network layer (i.e. the interface for socket creation or the socket factory for
1694600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * the stack).
1695600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
1696600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return -- the registered Network Layer.
1697600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
1698600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public NetworkLayer getNetworkLayer() {
1699600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (networkLayer == null) {
1700600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return DefaultNetworkLayer.SINGLETON;
1701600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } else {
1702600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return networkLayer;
1703600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
1704600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1705600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1706600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
1707600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Return true if logging is enabled for this stack.
1708600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
1709600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return true if logging is enabled for this stack instance.
1710600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
1711600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public boolean isLoggingEnabled() {
1712600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return this.stackLogger == null ? false : this.stackLogger.isLoggingEnabled();
1713600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1714600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1715600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
1716600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Get the logger.
1717600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
1718600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return --the logger for the sip stack. Each stack has its own logger instance.
1719600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
1720600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public StackLogger getStackLogger() {
1721600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return this.stackLogger;
1722600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1723600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1724600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
1725600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Server log is the place where we log messages for the signaling trace viewer.
1726600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
1727600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return -- the log file where messages are logged for viewing by the trace viewer.
1728600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
1729600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public ServerLogger getServerLogger() {
1730600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return this.serverLogger;
1731600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1732600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1733600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
1734600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Maximum size of a single TCP message. Limiting the size of a single TCP message prevents
1735600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * flooding attacks.
1736600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
1737600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return the size of a single TCP message.
1738600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
1739600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public int getMaxMessageSize() {
1740600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return this.maxMessageSize;
1741600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1742600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1743600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
1744600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Set the flag that instructs the stack to only start a single thread for sequentially
1745600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * processing incoming udp messages (thus serializing the processing). Same as setting thread
1746600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * pool size to 1.
1747600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
1748600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public void setSingleThreaded() {
1749600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.threadPoolSize = 1;
1750600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1751600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1752600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
1753600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Set the thread pool size for processing incoming UDP messages. Limit the total number of
1754600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * threads for processing udp messages.
1755600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
1756600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param size -- the thread pool size.
1757600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
1758600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
1759600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public void setThreadPoolSize(int size) {
1760600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.threadPoolSize = size;
1761600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1762600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1763600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
1764600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Set the max # of simultaneously handled TCP connections.
1765600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
1766600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param nconnections -- the number of connections to handle.
1767600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
1768600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public void setMaxConnections(int nconnections) {
1769600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.maxConnections = nconnections;
1770600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1771600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1772600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
1773600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Get the default route string.
1774600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
1775600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param sipRequest is the request for which we want to compute the next hop.
1776600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @throws SipException
1777600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
1778600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public Hop getNextHop(SIPRequest sipRequest) throws SipException {
1779600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (this.useRouterForAll) {
1780600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // Use custom router to route all messages.
1781600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (router != null)
1782600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                return router.getNextHop(sipRequest);
1783600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            else
1784600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                return null;
1785600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } else {
1786600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // Also non-SIP request containing Route headers goes to the default
1787600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // router
1788600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (sipRequest.getRequestURI().isSipURI() || sipRequest.getRouteHeaders() != null) {
1789600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                return defaultRouter.getNextHop(sipRequest);
1790600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } else if (router != null) {
1791600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                return router.getNextHop(sipRequest);
1792600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } else
1793600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                return null;
1794600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
1795600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1796600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1797600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
1798600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Set the descriptive name of the stack.
1799600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
1800600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param stackName -- descriptive name of the stack.
1801600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
1802600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public void setStackName(String stackName) {
1803600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.stackName = stackName;
1804600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1805600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1806600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1807600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1808600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
1809600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Set my address.
1810600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
1811600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param stackAddress -- A string containing the stack address.
1812600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
1813600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected void setHostAddress(String stackAddress) throws UnknownHostException {
1814600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (stackAddress.indexOf(':') != stackAddress.lastIndexOf(':')
1815600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                && stackAddress.trim().charAt(0) != '[')
1816600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            this.stackAddress = '[' + stackAddress + ']';
1817600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        else
1818600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            this.stackAddress = stackAddress;
1819600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.stackInetAddress = InetAddress.getByName(stackAddress);
1820600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1821600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1822600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
1823600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Get my address.
1824600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
1825600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return hostAddress - my host address or null if no host address is defined.
1826600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @deprecated
1827600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
1828600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public String getHostAddress() {
1829600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1830600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // JvB: for 1.2 this may return null...
1831600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return this.stackAddress;
1832600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1833600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1834600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
1835600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Set the router algorithm. This is meant for routing messages out of dialog or for non-sip
1836600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * uri's.
1837600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
1838600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param router A class that implements the Router interface.
1839600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
1840600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected void setRouter(Router router) {
1841600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.router = router;
1842600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1843600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1844600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
1845600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Get the router algorithm.
1846600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
1847600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return Router router
1848600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
1849600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public Router getRouter(SIPRequest request) {
1850600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (request.getRequestLine() == null) {
1851600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return this.defaultRouter;
1852600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } else if (this.useRouterForAll) {
1853600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return this.router;
1854600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } else {
1855600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (request.getRequestURI().getScheme().equals("sip")
1856600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    || request.getRequestURI().getScheme().equals("sips")) {
1857600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                return this.defaultRouter;
1858600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            } else {
1859600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (this.router != null)
1860600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    return this.router;
1861600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                else
1862600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    return defaultRouter;
1863600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
1864600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
1865600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1866600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1867600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /*
1868600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * (non-Javadoc)
1869600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
1870600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @see javax.sip.SipStack#getRouter()
1871600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
1872600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public Router getRouter() {
1873600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return this.router;
1874600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1875600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1876600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
1877600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * return the status of the toExit flag.
1878600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
1879600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return true if the stack object is alive and false otherwise.
1880600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
1881600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public boolean isAlive() {
1882600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return !toExit;
1883600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1884600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1885600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
1886600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Adds a new MessageProcessor to the list of running processors for this SIPStack and starts
1887600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * it. You can use this method for dynamic stack configuration.
1888600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
1889600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected void addMessageProcessor(MessageProcessor newMessageProcessor) throws IOException {
1890600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        synchronized (messageProcessors) {
1891600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // Suggested changes by Jeyashankher, jai@lucent.com
1892600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // newMessageProcessor.start() can fail
1893600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // because a local port is not available
1894600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // This throws an IOException.
1895600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // We should not add the message processor to the
1896600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // local list of processors unless the start()
1897600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // call is successful.
1898600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // newMessageProcessor.start();
1899600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            messageProcessors.add(newMessageProcessor);
1900600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1901600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
1902600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1903600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1904600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
1905600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Removes a MessageProcessor from this SIPStack.
1906600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
1907600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param oldMessageProcessor
1908600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
1909600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected void removeMessageProcessor(MessageProcessor oldMessageProcessor) {
1910600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        synchronized (messageProcessors) {
1911600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (messageProcessors.remove(oldMessageProcessor)) {
1912600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                oldMessageProcessor.stop();
1913600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
1914600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
1915600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1916600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1917600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
1918600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Gets an array of running MessageProcessors on this SIPStack. Acknowledgement: Jeff Keyser
1919600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * suggested that applications should have access to the running message processors and
1920600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * contributed this code.
1921600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
1922600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return an array of running message processors.
1923600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
1924600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected MessageProcessor[] getMessageProcessors() {
1925600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        synchronized (messageProcessors) {
1926600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return (MessageProcessor[]) messageProcessors.toArray(new MessageProcessor[0]);
1927600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
1928600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1929600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1930600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
1931600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Creates the equivalent of a JAIN listening point and attaches to the stack.
1932600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
1933600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param ipAddress -- ip address for the listening point.
1934600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param port -- port for the listening point.
1935600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param transport -- transport for the listening point.
1936600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
1937600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected MessageProcessor createMessageProcessor(InetAddress ipAddress, int port,
1938600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            String transport) throws java.io.IOException {
1939600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (transport.equalsIgnoreCase("udp")) {
1940600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            UDPMessageProcessor udpMessageProcessor = new UDPMessageProcessor(ipAddress, this,
1941600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    port);
1942600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            this.addMessageProcessor(udpMessageProcessor);
1943600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            this.udpFlag = true;
1944600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return udpMessageProcessor;
1945600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } else if (transport.equalsIgnoreCase("tcp")) {
1946600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            TCPMessageProcessor tcpMessageProcessor = new TCPMessageProcessor(ipAddress, this,
1947600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    port);
1948600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            this.addMessageProcessor(tcpMessageProcessor);
1949600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // this.tcpFlag = true;
1950600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return tcpMessageProcessor;
1951600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } else if (transport.equalsIgnoreCase("tls")) {
1952600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            TLSMessageProcessor tlsMessageProcessor = new TLSMessageProcessor(ipAddress, this,
1953600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    port);
1954600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            this.addMessageProcessor(tlsMessageProcessor);
1955600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // this.tlsFlag = true;
1956600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            return tlsMessageProcessor;
1957600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } else if (transport.equalsIgnoreCase("sctp")) {
1958600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1959600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        	// Need Java 7 for this, so these classes are packaged in a separate jar
1960600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        	// Try to load it indirectly, if fails report an error
1961600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        	try {
1962600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang				Class<?> mpc = ClassLoader.getSystemClassLoader().loadClass( "gov.nist.javax.sip.stack.sctp.SCTPMessageProcessor" );
1963600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang				MessageProcessor mp = (MessageProcessor) mpc.newInstance();
1964600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang				mp.initialize( ipAddress, port, this );
1965600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang				this.addMessageProcessor(mp);
1966600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang				return mp;
1967600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang			} catch (ClassNotFoundException e) {
1968600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang				throw new IllegalArgumentException("SCTP not supported (needs Java 7 and SCTP jar in classpath)");
1969600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang			} catch ( InstantiationException ie ) {
1970600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang				throw new IllegalArgumentException("Error initializing SCTP", ie);
1971600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang			} catch ( IllegalAccessException ie ) {
1972600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang				throw new IllegalArgumentException("Error initializing SCTP", ie);
1973600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang			}
1974600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } else {
1975600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            throw new IllegalArgumentException("bad transport");
1976600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
1977600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1978600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1979600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1980600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
1981600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Set the message factory.
1982600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
1983600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param messageFactory -- messageFactory to set.
1984600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
1985600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    protected void setMessageFactory(StackMessageFactory messageFactory) {
1986600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.sipMessageFactory = messageFactory;
1987600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
1988600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
1989600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
1990600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Creates a new MessageChannel for a given Hop.
1991600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
1992600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param sourceIpAddress - Ip address of the source of this message.
1993600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
1994600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param sourcePort - source port of the message channel to be created.
1995600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
1996600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param nextHop Hop to create a MessageChannel to.
1997600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
1998600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return A MessageChannel to the specified Hop, or null if no MessageProcessors support
1999600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *         contacting that Hop.
2000600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
2001600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @throws UnknownHostException If the host in the Hop doesn't exist.
2002600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
2003600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public MessageChannel createRawMessageChannel(String sourceIpAddress, int sourcePort,
2004600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            Hop nextHop) throws UnknownHostException {
2005600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        Host targetHost;
2006600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        HostPort targetHostPort;
2007600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        Iterator processorIterator;
2008600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        MessageProcessor nextProcessor;
2009600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        MessageChannel newChannel;
2010600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
2011600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // Create the host/port of the target hop
2012600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        targetHost = new Host();
2013600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        targetHost.setHostname(nextHop.getHost());
2014600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        targetHostPort = new HostPort();
2015600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        targetHostPort.setHost(targetHost);
2016600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        targetHostPort.setPort(nextHop.getPort());
2017600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
2018600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // Search each processor for the correct transport
2019600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        newChannel = null;
2020600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        processorIterator = messageProcessors.iterator();
2021600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        while (processorIterator.hasNext() && newChannel == null) {
2022600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            nextProcessor = (MessageProcessor) processorIterator.next();
2023600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // If a processor that supports the correct
2024600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // transport is found,
2025600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (nextHop.getTransport().equalsIgnoreCase(nextProcessor.getTransport())
2026600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    && sourceIpAddress.equals(nextProcessor.getIpAddress().getHostAddress())
2027600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    && sourcePort == nextProcessor.getPort()) {
2028600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                try {
2029600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // Create a channel to the target
2030600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // host/port
2031600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    newChannel = nextProcessor.createMessageChannel(targetHostPort);
2032600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                } catch (UnknownHostException ex) {
2033600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    if (stackLogger.isLoggingEnabled())
2034600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        stackLogger.logException(ex);
2035600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    throw ex;
2036600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                } catch (IOException e) {
2037600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    if (stackLogger.isLoggingEnabled())
2038600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        stackLogger.logException(e);
2039600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // Ignore channel creation error -
2040600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // try next processor
2041600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
2042600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
2043600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
2044600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // Return the newly-created channel
2045600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return newChannel;
2046600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
2047600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
2048600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
2049600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Return true if a given event can result in a forked subscription. The stack is configured
2050600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * with a set of event names that can result in forked subscriptions.
2051600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
2052600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param ename -- event name to check.
2053600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
2054600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
2055600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public boolean isEventForked(String ename) {
2056600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (stackLogger.isLoggingEnabled()) {
2057600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            stackLogger.logDebug("isEventForked: " + ename + " returning "
2058600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    + this.forkedEvents.contains(ename));
2059600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
2060600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return this.forkedEvents.contains(ename);
2061600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
2062600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
2063600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
2064600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * get the address resolver interface.
2065600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
2066600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return -- the registered address resolver.
2067600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
2068600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public AddressResolver getAddressResolver() {
2069600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return this.addressResolver;
2070600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
2071600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
2072600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
2073600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Set the address resolution interface
2074600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
2075600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param addressResolver -- the address resolver to set.
2076600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
2077600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public void setAddressResolver(AddressResolver addressResolver) {
2078600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.addressResolver = addressResolver;
2079600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
2080600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
2081600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
2082600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Set the logger factory.
2083600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
2084600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param logRecordFactory -- the log record factory to set.
2085600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
2086600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public void setLogRecordFactory(LogRecordFactory logRecordFactory) {
2087600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.logRecordFactory = logRecordFactory;
2088600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
2089600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
2090600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
2091600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * get the thread auditor object
2092600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
2093600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return -- the thread auditor of the stack
2094600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
2095600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public ThreadAuditor getThreadAuditor() {
2096600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return this.threadAuditor;
2097600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
2098600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
2099600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    // /
2100600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    // / Stack Audit methods
2101600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    // /
2102600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
2103600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
2104600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Audits the SIP Stack for leaks
2105600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
2106600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return Audit report, null if no leaks were found
2107600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
2108600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public String auditStack(Set activeCallIDs, long leakedDialogTimer,
2109600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            long leakedTransactionTimer) {
2110600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        String auditReport = null;
2111600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        String leakedDialogs = auditDialogs(activeCallIDs, leakedDialogTimer);
2112600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        String leakedServerTransactions = auditTransactions(serverTransactionTable,
2113600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                leakedTransactionTimer);
2114600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        String leakedClientTransactions = auditTransactions(clientTransactionTable,
2115600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                leakedTransactionTimer);
2116600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (leakedDialogs != null || leakedServerTransactions != null
2117600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                || leakedClientTransactions != null) {
2118600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            auditReport = "SIP Stack Audit:\n" + (leakedDialogs != null ? leakedDialogs : "")
2119600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    + (leakedServerTransactions != null ? leakedServerTransactions : "")
2120600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    + (leakedClientTransactions != null ? leakedClientTransactions : "");
2121600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
2122600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return auditReport;
2123600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
2124600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
2125600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
2126600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Audits SIP dialogs for leaks - Compares the dialogs in the dialogTable with a list of Call
2127600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * IDs passed by the application. - Dialogs that are not known by the application are leak
2128600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * suspects. - Kill the dialogs that are still around after the timer specified.
2129600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
2130600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return Audit report, null if no dialog leaks were found
2131600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
2132600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private String auditDialogs(Set activeCallIDs, long leakedDialogTimer) {
2133600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        String auditReport = "  Leaked dialogs:\n";
2134600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        int leakedDialogs = 0;
2135600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        long currentTime = System.currentTimeMillis();
2136600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
2137600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // Make a shallow copy of the dialog list.
2138600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // This copy will remain intact as leaked dialogs are removed by the
2139600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // stack.
2140600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        LinkedList dialogs;
2141600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        synchronized (dialogTable) {
2142600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            dialogs = new LinkedList(dialogTable.values());
2143600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
2144600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
2145600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // Iterate through the dialogDialog, get the callID of each dialog and
2146600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // check if it's in the
2147600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // list of active calls passed by the application. If it isn't, start
2148600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // the timer on it.
2149600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // If the timer has expired, kill the dialog.
2150600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        Iterator it = dialogs.iterator();
2151600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        while (it.hasNext()) {
2152600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // Get the next dialog
2153600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            SIPDialog itDialog = (SIPDialog) it.next();
2154600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
2155600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // Get the call id associated with this dialog
2156600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            CallIdHeader callIdHeader = (itDialog != null ? itDialog.getCallId() : null);
2157600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            String callID = (callIdHeader != null ? callIdHeader.getCallId() : null);
2158600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
2159600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            // Check if the application knows about this call id
2160600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (itDialog != null && callID != null && !activeCallIDs.contains(callID)) {
2161600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                // Application doesn't know anything about this dialog...
2162600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (itDialog.auditTag == 0) {
2163600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // Mark this dialog as suspect
2164600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    itDialog.auditTag = currentTime;
2165600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                } else {
2166600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // We already audited this dialog before. Check if his
2167600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // time's up.
2168600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    if (currentTime - itDialog.auditTag >= leakedDialogTimer) {
2169600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        // Leaked dialog found
2170600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        leakedDialogs++;
2171600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
2172600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        // Generate report
2173600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        DialogState dialogState = itDialog.getState();
2174600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        String dialogReport = "dialog id: " + itDialog.getDialogId()
2175600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                + ", dialog state: "
2176600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                + (dialogState != null ? dialogState.toString() : "null");
2177600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        auditReport += "    " + dialogReport + "\n";
2178600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
2179600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        // Kill it
2180600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        itDialog.setState(SIPDialog.TERMINATED_STATE);
2181600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        if (stackLogger.isLoggingEnabled())
2182600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        	stackLogger.logDebug("auditDialogs: leaked " + dialogReport);
2183600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    }
2184600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
2185600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
2186600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
2187600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
2188600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // Return final report
2189600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (leakedDialogs > 0) {
2190600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            auditReport += "    Total: " + Integer.toString(leakedDialogs)
2191600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    + " leaked dialogs detected and removed.\n";
2192600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } else {
2193600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            auditReport = null;
2194600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
2195600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return auditReport;
2196600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
2197600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
2198600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
2199600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Audits SIP transactions for leaks
2200600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
2201600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return Audit report, null if no transaction leaks were found
2202600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
2203600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    private String auditTransactions(ConcurrentHashMap transactionsMap,
2204600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            long a_nLeakedTransactionTimer) {
2205600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        String auditReport = "  Leaked transactions:\n";
2206600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        int leakedTransactions = 0;
2207600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        long currentTime = System.currentTimeMillis();
2208600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
2209600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // Make a shallow copy of the transaction list.
2210600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // This copy will remain intact as leaked transactions are removed by
2211600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // the stack.
2212600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        LinkedList transactionsList = new LinkedList(transactionsMap.values());
2213600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
2214600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // Iterate through our copy
2215600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        Iterator it = transactionsList.iterator();
2216600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        while (it.hasNext()) {
2217600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            SIPTransaction sipTransaction = (SIPTransaction) it.next();
2218600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            if (sipTransaction != null) {
2219600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (sipTransaction.auditTag == 0) {
2220600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // First time we see this transaction. Mark it as audited.
2221600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    sipTransaction.auditTag = currentTime;
2222600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                } else {
2223600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // We've seen this transaction before. Check if his time's
2224600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    // up.
2225600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    if (currentTime - sipTransaction.auditTag >= a_nLeakedTransactionTimer) {
2226600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        // Leaked transaction found
2227600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        leakedTransactions++;
2228600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
2229600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        // Generate some report
2230600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        TransactionState transactionState = sipTransaction.getState();
2231600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        SIPRequest origRequest = sipTransaction.getOriginalRequest();
2232600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        String origRequestMethod = (origRequest != null ? origRequest.getMethod()
2233600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                : null);
2234600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        String transactionReport = sipTransaction.getClass().getName()
2235600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                + ", state: "
2236600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                + (transactionState != null ? transactionState.toString()
2237600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                        : "null") + ", OR: "
2238600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                                + (origRequestMethod != null ? origRequestMethod : "null");
2239600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        auditReport += "    " + transactionReport + "\n";
2240600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
2241600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        // Kill it
2242600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        removeTransaction(sipTransaction);
2243600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        if (isLoggingEnabled())
2244600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                        	stackLogger.logDebug("auditTransactions: leaked " + transactionReport);
2245600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    }
2246600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
2247600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
2248600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
2249600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
2250600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // Return final report
2251600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (leakedTransactions > 0) {
2252600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            auditReport += "    Total: " + Integer.toString(leakedTransactions)
2253600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    + " leaked transactions detected and removed.\n";
2254600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } else {
2255600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            auditReport = null;
2256600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
2257600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return auditReport;
2258600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
2259600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
2260600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public void setNon2XXAckPassedToListener(boolean passToListener) {
2261600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.non2XXAckPassedToListener = passToListener;
2262600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
2263600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
2264600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
2265600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return the non2XXAckPassedToListener
2266600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
2267600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public boolean isNon2XXAckPassedToListener() {
2268600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return non2XXAckPassedToListener;
2269600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
2270600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
2271600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
2272600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Get the count of client transactions that is not in the completed or terminated state.
2273600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
2274600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return the activeClientTransactionCount
2275600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
2276600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public int getActiveClientTransactionCount() {
2277600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return activeClientTransactionCount.get();
2278600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
2279600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
2280600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public boolean isRfc2543Supported() {
2281600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
2282600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return this.rfc2543Supported;
2283600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
2284600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
2285600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public boolean isCancelClientTransactionChecked() {
2286600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return this.cancelClientTransactionChecked;
2287600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
2288600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
2289600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public boolean isRemoteTagReassignmentAllowed() {
2290600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return this.remoteTagReassignmentAllowed;
2291600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
2292600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
2293600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
2294600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * This method is slated for addition to the next spec revision.
2295600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
2296600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
2297600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return -- the collection of dialogs that is being managed by the stack.
2298600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
2299600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public Collection<Dialog> getDialogs() {
2300600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        HashSet<Dialog> dialogs = new HashSet<Dialog>();
2301600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        dialogs.addAll(this.dialogTable.values());
2302600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        dialogs.addAll(this.earlyDialogTable.values());
2303600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return dialogs;
2304600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
2305600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
2306600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
2307600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
2308600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return -- the collection of dialogs matching the state that is being managed by the stack.
2309600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
2310600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public Collection<Dialog> getDialogs(DialogState state) {
2311600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        HashSet<Dialog> matchingDialogs = new HashSet<Dialog>();
2312600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (DialogState.EARLY.equals(state)) {
2313600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            matchingDialogs.addAll(this.earlyDialogTable.values());
2314600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        } else {
2315600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            Collection<SIPDialog> dialogs = dialogTable.values();
2316600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            for (SIPDialog dialog : dialogs) {
2317600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                if (dialog.getState() != null && dialog.getState().equals(state)) {
2318600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                    matchingDialogs.add(dialog);
2319600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                }
2320600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            }
2321600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
2322600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return matchingDialogs;
2323600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
2324600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
2325600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
2326600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Get the Replaced Dialog from the stack.
2327600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
2328600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param replacesHeader -- the header that references the dialog being replaced.
2329600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
2330600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public Dialog getReplacesDialog(ReplacesHeader replacesHeader) {
2331600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        String cid = replacesHeader.getCallId();
2332600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        String fromTag = replacesHeader.getFromTag();
2333600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        String toTag = replacesHeader.getToTag();
2334600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
2335600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        StringBuffer dialogId = new StringBuffer(cid);
2336600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
2337600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // retval.append(COLON).append(to.getUserAtHostPort());
2338600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (toTag != null) {
2339600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            dialogId.append(":");
2340600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            dialogId.append(toTag);
2341600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
2342600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // retval.append(COLON).append(from.getUserAtHostPort());
2343600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (fromTag != null) {
2344600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            dialogId.append(":");
2345600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            dialogId.append(fromTag);
2346600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
2347600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        String did = dialogId.toString().toLowerCase();
2348600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (stackLogger.isLoggingEnabled())
2349600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        	stackLogger.logDebug("Looking for dialog " + did);
2350600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        /*
2351600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang         * Check if we can find this dialog in our dialog table.
2352600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang         */
2353600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        Dialog replacesDialog =  this.dialogTable.get(did);
2354600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        /*
2355600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang         * This could be a forked dialog. Search for it.
2356600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang         */
2357600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if ( replacesDialog == null ) {
2358600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang           for ( SIPClientTransaction ctx : this.clientTransactionTable.values()) {
2359600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang               if ( ctx.getDialog(did) != null ) {
2360600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                   replacesDialog = ctx.getDialog(did);
2361600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang                   break;
2362600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang               }
2363600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang           }
2364600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
2365600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
2366600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return replacesDialog;
2367600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
2368600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
2369600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
2370600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Get the Join Dialog from the stack.
2371600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
2372600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param joinHeader -- the header that references the dialog being joined.
2373600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
2374600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public Dialog getJoinDialog(JoinHeader joinHeader) {
2375600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        String cid = joinHeader.getCallId();
2376600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        String fromTag = joinHeader.getFromTag();
2377600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        String toTag = joinHeader.getToTag();
2378600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
2379600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        StringBuffer retval = new StringBuffer(cid);
2380600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
2381600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // retval.append(COLON).append(to.getUserAtHostPort());
2382600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (toTag != null) {
2383600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            retval.append(":");
2384600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            retval.append(toTag);
2385600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
2386600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        // retval.append(COLON).append(from.getUserAtHostPort());
2387600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        if (fromTag != null) {
2388600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            retval.append(":");
2389600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang            retval.append(fromTag);
2390600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        }
2391600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return this.dialogTable.get(retval.toString().toLowerCase());
2392600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
2393600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
2394600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
2395600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param timer the timer to set
2396600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
2397600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public void setTimer(Timer timer) {
2398600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.timer = timer;
2399600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
2400600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
2401600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
2402600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return the timer
2403600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
2404600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public Timer getTimer() {
2405600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return timer;
2406600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
2407600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
2408600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
2409600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
2410600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Size of the receive UDP buffer. This property affects performance under load. Bigger buffer
2411600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * is better under load.
2412600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
2413600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return
2414600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
2415600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang	public int getReceiveUdpBufferSize() {
2416600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang		return receiveUdpBufferSize;
2417600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang	}
2418600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
2419600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
2420600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Size of the receive UDP buffer. This property affects performance under load. Bigger buffer
2421600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * is better under load.
2422600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
2423600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return
2424600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
2425600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang	public void setReceiveUdpBufferSize(int receiveUdpBufferSize) {
2426600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang		this.receiveUdpBufferSize = receiveUdpBufferSize;
2427600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang	}
2428600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
2429600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
2430600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Size of the send UDP buffer. This property affects performance under load. Bigger buffer
2431600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * is better under load.
2432600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
2433600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return
2434600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
2435600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang	public int getSendUdpBufferSize() {
2436600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang		return sendUdpBufferSize;
2437600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang	}
2438600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
2439600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
2440600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * Size of the send UDP buffer. This property affects performance under load. Bigger buffer
2441600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * is better under load.
2442600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     *
2443600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return
2444600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
2445600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang	public void setSendUdpBufferSize(int sendUdpBufferSize) {
2446600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang		this.sendUdpBufferSize = sendUdpBufferSize;
2447600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang	}
2448600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
2449600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang	/**
2450600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang	 * @param stackLogger the stackLogger to set
2451600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang	 */
2452600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang	public void setStackLogger(StackLogger stackLogger) {
2453600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang		this.stackLogger = stackLogger;
2454600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang	}
2455600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
2456600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang	 /**
2457600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang	  * Flag that reqests checking of branch IDs on responses.
2458600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang	  *
2459600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang	  * @return
2460600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang	  */
2461600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang	 public boolean checkBranchId() {
2462600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang	       return this.checkBranchId;
2463600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang	 }
2464600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
2465600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
2466600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @param logStackTraceOnMessageSend the logStackTraceOnMessageSend to set
2467600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
2468600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public void setLogStackTraceOnMessageSend(boolean logStackTraceOnMessageSend) {
2469600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.logStackTraceOnMessageSend = logStackTraceOnMessageSend;
2470600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
2471600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
2472600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    /**
2473600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     * @return the logStackTraceOnMessageSend
2474600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang     */
2475600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public boolean isLogStackTraceOnMessageSend() {
2476600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return logStackTraceOnMessageSend;
2477600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
2478600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
2479600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public void setDeliverDialogTerminatedEventForNullDialog() {
2480600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.isDialogTerminatedEventDeliveredForNullDialog = true;
2481600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
2482600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
2483600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public void addForkedClientTransaction(SIPClientTransaction clientTransaction) {
2484600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        this.forkedClientTransactionTable.put(clientTransaction.getTransactionId(), clientTransaction );
2485600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
2486600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
2487600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    public SIPClientTransaction getForkedTransaction(String transactionId) {
2488600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang        return this.forkedClientTransactionTable.get(transactionId);
2489600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang    }
2490600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
2491600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang
2492600c7a4bbc7348167293eac928192e695b4ad5baChung-yih Wang}
2493