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