Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Conditions Of Use
*
* This software was developed by employees of the National Institute of
* Standards and Technology (NIST), an agency of the Federal Government.
* Pursuant to title 15 Untied States Code Section 105, works of NIST
* employees are not subject to copyright protection in the United States
* and are considered to be in the public domain. As a result, a formal
* license is not needed to use the software.
*
* This software is provided by NIST as a service and is expressly
* provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED
* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT
* AND DATA ACCURACY. NIST does not warrant or make any representations
* regarding the use of the software or the results thereof, including but
* not limited to the correctness, accuracy, reliability or usefulness of
* the software.
*
* Permission to use this software is contingent upon your acceptance
* of the terms of this agreement
*
* .
*
*/
package android.gov.nist.javax.sip.stack;
import android.gov.nist.core.CommonLogger;
import android.gov.nist.core.InternalErrorHandler;
import android.gov.nist.core.LogLevels;
import android.gov.nist.core.LogWriter;
import android.gov.nist.core.ServerLogger;
import android.gov.nist.core.StackLogger;
import android.gov.nist.javax.sip.ReleaseReferencesStrategy;
import android.gov.nist.javax.sip.SIPConstants;
import android.gov.nist.javax.sip.SipProviderImpl;
import android.gov.nist.javax.sip.SipStackImpl;
import android.gov.nist.javax.sip.ThreadAffinityTask;
import android.gov.nist.javax.sip.address.AddressFactoryImpl;
import android.gov.nist.javax.sip.header.Via;
import android.gov.nist.javax.sip.message.SIPMessage;
import android.gov.nist.javax.sip.message.SIPRequest;
import android.gov.nist.javax.sip.message.SIPResponse;
import android.gov.nist.javax.sip.stack.SIPClientTransactionImpl.ExpiresTimerTask;
import java.io.IOException;
import java.net.InetAddress;
import java.security.cert.Certificate;
import java.security.cert.CertificateParsingException;
import java.security.cert.X509Certificate;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.ReentrantLock;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.net.ssl.SSLPeerUnverifiedException;
import android.javax.sip.Dialog;
import android.javax.sip.IOExceptionEvent;
import android.javax.sip.TransactionState;
import android.javax.sip.address.SipURI;
import android.javax.sip.message.Request;
import android.javax.sip.message.Response;
/*
* Modifications for TLS Support added by Daniel J. Martinez Manzano
* Bug fixes by Jeroen van Bemmel (JvB) and others.
*/
/**
* Abstract class to support both client and server transactions. Provides an
* encapsulation of a message channel, handles timer events, and creation of the
* Via header for a message.
*
* @author Jeff Keyser
* @author M. Ranganathan
*
*
* @version 1.2 $Revision: 1.100 $ $Date: 2010-12-02 22:04:13 $
*/
public abstract class SIPTransactionImpl implements SIPTransaction {
private static StackLogger logger = CommonLogger.getLogger(SIPTransaction.class);
// Contribution on http://java.net/jira/browse/JSIP-417 from Alexander Saveliev
private static final Pattern EXTRACT_CN = Pattern.compile(".*CN\\s*=\\s*([\\w*\\.\\-_]+).*");
protected boolean toListener; // Flag to indicate that the listener gets
// to see the event.
protected int baseTimerInterval = SIPTransactionStack.BASE_TIMER_INTERVAL;
/**
* 5 sec Maximum duration a message will remain in the network
*/
protected int T4 = 5000 / baseTimerInterval;
/**
* The maximum retransmit interval for non-INVITE requests and INVITE
* responses
*/
protected int T2 = 4000 / baseTimerInterval;
protected int timerI = T4;
protected int timerK = T4;
protected int timerD = 32000 / baseTimerInterval;
// Proposed feature for next release.
protected transient Object applicationData;
protected SIPResponse lastResponse;
// private SIPDialog dialog;
protected boolean isMapped;
private transient TransactionSemaphore semaphore;
// protected boolean eventPending; // indicate that an event is pending
// here.
protected String transactionId; // Transaction Id.
// Audit tag used by the SIP Stack audit
protected long auditTag = 0;
// Parent stack for this transaction
protected transient SIPTransactionStack sipStack;
// Original request that is being handled by this transaction
protected SIPRequest originalRequest;
//jeand we nullify the originalRequest fast to save on mem and help GC
// so we keep only those data instead
protected byte[] originalRequestBytes;
protected long originalRequestCSeqNumber;
protected String originalRequestBranch;
protected boolean originalRequestHasPort;
// Underlying channel being used to send messages for this transaction
protected transient MessageChannel encapsulatedChannel;
protected AtomicBoolean transactionTimerStarted = new AtomicBoolean(false);
// Transaction branch ID
private String branch;
// Method of the Request used to create the transaction.
private String method;
// Current transaction state
private int currentState = -1;
// Number of ticks the retransmission timer was set to last
private transient int retransmissionTimerLastTickCount;
// Number of ticks before the message is retransmitted
private transient int retransmissionTimerTicksLeft;
// Number of ticks before the transaction times out
protected int timeoutTimerTicksLeft;
// List of event listeners for this transaction
private transient Set eventListeners;
// Counter for caching of connections.
// Connection lingers for collectionTime
// after the Transaction goes to terminated state.
protected int collectionTime;
private boolean terminatedEventDelivered;
// aggressive flag to optimize eagerly
private ReleaseReferencesStrategy releaseReferencesStrategy;
// caching flags
private Boolean inviteTransaction = null;
private Boolean dialogCreatingTransaction = null;
// caching fork id
private String forkId = null;
protected String mergeId = null;
public ExpiresTimerTask expiresTimerTask;
// http://java.net/jira/browse/JSIP-420
private MaxTxLifeTimeListener maxTxLifeTimeListener;
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#getBranchId()
*/
@Override
public String getBranchId() {
return this.branch;
}
// [Issue 284] https://jain-sip.dev.java.net/issues/show_bug.cgi?id=284
// JAIN SIP drops 200 OK due to race condition
// Wrapper that uses a semaphore for non reentrant listener
// and a lock for reetrant listener to avoid race conditions
// when 2 responses 180/200 OK arrives at the same time
class TransactionSemaphore {
private static final long serialVersionUID = -1634100711669020804L;
Semaphore sem = null;
ReentrantLock lock = null;
public TransactionSemaphore() {
if(((SipStackImpl)sipStack).isReEntrantListener()) {
lock = new ReentrantLock();
} else {
sem = new Semaphore(1, true);
}
}
public boolean acquire() {
try {
if(((SipStackImpl)sipStack).isReEntrantListener()) {
lock.lock();
} else {
sem.acquire();
}
return true;
} catch (Exception ex) {
logger.logError("Unexpected exception acquiring sem",
ex);
InternalErrorHandler.handleException(ex);
return false;
}
}
public boolean tryAcquire() {
try {
if(((SipStackImpl)sipStack).isReEntrantListener()) {
return lock.tryLock(sipStack.maxListenerResponseTime, TimeUnit.SECONDS);
} else {
return sem.tryAcquire(sipStack.maxListenerResponseTime, TimeUnit.SECONDS);
}
} catch (Exception ex) {
logger.logError("Unexpected exception trying acquiring sem",
ex);
InternalErrorHandler.handleException(ex);
return false;
}
}
public void release() {
try {
if(((SipStackImpl)sipStack).isReEntrantListener()) {
if(lock.isHeldByCurrentThread()) {
lock.unlock();
}
} else {
sem.release();
}
} catch (Exception ex) {
logger.logError("Unexpected exception releasing sem",
ex);
}
}
}
/**
* The linger timer is used to remove the transaction from the transaction
* table after it goes into terminated state. This allows connection caching
* and also takes care of race conditins.
*
*
*/
class LingerTimer extends SIPStackTimerTask {
public LingerTimer() {
if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
SIPTransaction sipTransaction = SIPTransactionImpl.this;
logger.logDebug("LingerTimer : "
+ sipTransaction.getTransactionId());
}
}
public void runTask() {
cleanUp();
}
@Override
public Object getThreadHash() {
Request request = getRequest();
if (request != null && request instanceof SIPRequest) {
return ((SIPRequest)request).getCallIdHeader().getCallId();
} else {
return null;
}
}
}
/**
* http://java.net/jira/browse/JSIP-420
* This timer task will terminate the transaction after a configurable time
*
*/
class MaxTxLifeTimeListener extends SIPStackTimerTask {
SIPTransaction sipTransaction = SIPTransactionImpl.this;
public void runTask() {
try {
if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
logger.logDebug("Fired MaxTxLifeTimeListener for tx " + sipTransaction + " , tx id "+ sipTransaction.getTransactionId() + " , state " + sipTransaction.getState());
}
raiseErrorEvent(SIPTransactionErrorEvent.TIMEOUT_ERROR);
SIPStackTimerTask myTimer = new LingerTimer();
if(sipStack.getConnectionLingerTimer() != 0) {
sipStack.getTimer().schedule(myTimer, sipStack.getConnectionLingerTimer() * 1000);
} else {
myTimer.runTask();
}
maxTxLifeTimeListener = null;
} catch (Exception ex) {
logger.logError("unexpected exception", ex);
}
}
@Override
public Object getThreadHash() {
Request request = getRequest();
if (request != null && request instanceof SIPRequest) {
return ((SIPRequest)request).getCallIdHeader().getCallId();
} else {
return null;
}
}
}
/**
* Transaction constructor.
*
* @param newParentStack
* Parent stack for this transaction.
* @param newEncapsulatedChannel
* Underlying channel for this transaction.
*/
protected SIPTransactionImpl(SIPTransactionStack newParentStack,
MessageChannel newEncapsulatedChannel) {
sipStack = newParentStack;
this.semaphore = new TransactionSemaphore();
encapsulatedChannel = newEncapsulatedChannel;
if (this.isReliable()) {
encapsulatedChannel.useCount++;
if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG))
logger
.logDebug("use count for encapsulated channel"
+ this
+ " "
+ encapsulatedChannel.useCount );
}
this.currentState = -1;
disableRetransmissionTimer();
disableTimeoutTimer();
eventListeners = new CopyOnWriteArraySet();
// Always add the parent stack as a listener
// of this transaction
addEventListener(newParentStack);
releaseReferencesStrategy = sipStack.getReleaseReferencesStrategy();
}
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#cleanUp()
*/
@Override
public abstract void cleanUp();
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#setOriginalRequest(android.gov.nist.javax.sip.message.SIPRequest)
*/
@Override
public void setOriginalRequest(SIPRequest newOriginalRequest) {
// Branch value of topmost Via header
String newBranch;
final String newTransactionId = newOriginalRequest.getTransactionId();
if (this.originalRequest != null
&& (!this.originalRequest.getTransactionId().equals(
newTransactionId))) {
sipStack.removeTransactionHash(this);
}
// This will be cleared later.
this.originalRequest = newOriginalRequest;
this.originalRequestCSeqNumber = newOriginalRequest.getCSeq().getSeqNumber();
final Via topmostVia = newOriginalRequest.getTopmostVia();
this.originalRequestBranch = topmostVia.getBranch();
this.originalRequestHasPort = topmostVia.hasPort();
int originalRequestViaPort = topmostVia.getPort();
if ( originalRequestViaPort == -1 ) {
if (topmostVia.getTransport().equalsIgnoreCase("TLS") ) {
originalRequestViaPort = 5061;
} else {
originalRequestViaPort = 5060;
}
}
// just cache the control information so the
// original request can be released later.
this.method = newOriginalRequest.getMethod();
this.transactionId = newTransactionId;
originalRequest.setTransaction(this);
// If the message has an explicit branch value set,
newBranch = topmostVia.getBranch();
if (newBranch != null) {
if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG))
logger.logDebug("Setting Branch id : " + newBranch);
// Override the default branch with the one
// set by the message
setBranch(newBranch);
} else {
if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG))
logger.logDebug("Branch id is null - compute TID!"
+ newOriginalRequest.encode());
setBranch(newTransactionId);
}
}
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#getOriginalRequest()
*/
@Override
public SIPRequest getOriginalRequest() {
return this.originalRequest;
}
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#getRequest()
*/
@Override
public Request getRequest() {
if(getReleaseReferencesStrategy() != ReleaseReferencesStrategy.None && originalRequest == null && originalRequestBytes != null) {
if(logger.isLoggingEnabled(StackLogger.TRACE_WARN)) {
logger.logWarning("reparsing original request " + originalRequestBytes + " since it was eagerly cleaned up, but beware this is not efficient with the aggressive flag set !");
}
try {
originalRequest = (SIPRequest) sipStack.getMessageParserFactory().createMessageParser(sipStack).parseSIPMessage(originalRequestBytes, true, false, null);
// originalRequestBytes = null;
} catch (ParseException e) {
if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
logger.logDebug("message " + originalRequestBytes + " could not be reparsed !", e);
}
}
}
return (Request) originalRequest;
}
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#isDialogCreatingTransaction()
*/
@Override
public boolean isDialogCreatingTransaction() {
if (dialogCreatingTransaction == null) {
dialogCreatingTransaction = Boolean.valueOf(isInviteTransaction() || getMethod().equals(Request.SUBSCRIBE) || getMethod().equals(Request.REFER));
}
return dialogCreatingTransaction.booleanValue();
}
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#isInviteTransaction()
*/
@Override
public boolean isInviteTransaction() {
if (inviteTransaction == null) {
inviteTransaction = Boolean.valueOf(getMethod().equals(Request.INVITE));
}
return inviteTransaction.booleanValue();
}
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#isCancelTransaction()
*/
@Override
public boolean isCancelTransaction() {
return getMethod().equals(Request.CANCEL);
}
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#isByeTransaction()
*/
@Override
public boolean isByeTransaction() {
return getMethod().equals(Request.BYE);
}
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#getMessageChannel()
*/
@Override
public MessageChannel getMessageChannel() {
return encapsulatedChannel;
}
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#setBranch(java.lang.String)
*/
@Override
public void setBranch(String newBranch) {
branch = newBranch;
}
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#getBranch()
*/
@Override
public String getBranch() {
if (this.branch == null) {
this.branch = originalRequestBranch;
}
return branch;
}
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#getMethod()
*/
@Override
public String getMethod() {
return this.method;
}
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#getCSeq()
*/
@Override
public long getCSeq() {
return this.originalRequestCSeqNumber;
}
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#setState(int)
*/
@Override
public void setState(int newState) {
// PATCH submitted by sribeyron
if (currentState == TransactionState._COMPLETED) {
if (newState != TransactionState._TERMINATED
&& newState != TransactionState._CONFIRMED)
newState = TransactionState._COMPLETED;
}
if (currentState == TransactionState._CONFIRMED) {
if (newState != TransactionState._TERMINATED)
newState = TransactionState._CONFIRMED;
}
if (currentState != TransactionState._TERMINATED) {
currentState = newState;
}
else
newState = currentState;
// END OF PATCH
if(newState == TransactionState._COMPLETED) {
enableTimeoutTimer(TIMER_H); // timer H must be started around now
}
if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
logger.logDebug("Transaction:setState " + newState
+ " " + this + " branchID = " + this.getBranch()
+ " isClient = " + (this instanceof SIPClientTransaction));
logger.logStackTrace();
}
}
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#getInternalState()
*/
@Override
public int getInternalState() {
return this.currentState;
}
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#getState()
*/
@Override
public TransactionState getState() {
if(currentState < 0) {
return null;
}
return TransactionState.getObject(this.currentState);
}
/**
* Enables retransmission timer events for this transaction to begin in one
* tick.
*/
protected void enableRetransmissionTimer() {
enableRetransmissionTimer(1);
}
/**
* Enables retransmission timer events for this transaction to begin after
* the number of ticks passed to this routine.
*
* @param tickCount
* Number of ticks before the next retransmission timer event
* occurs.
*/
protected void enableRetransmissionTimer(int tickCount) {
// For INVITE Client transactions, double interval each time
if (isInviteTransaction() && (this instanceof SIPClientTransaction)) {
retransmissionTimerTicksLeft = tickCount;
} else {
// non-INVITE transactions and 3xx-6xx responses are capped at T2
retransmissionTimerTicksLeft = Math.min(tickCount,
getTimerT2());
}
retransmissionTimerLastTickCount = retransmissionTimerTicksLeft;
}
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#disableRetransmissionTimer()
*/
@Override
public void disableRetransmissionTimer() {
retransmissionTimerTicksLeft = -1;
}
/**
* Enables a timeout event to occur for this transaction after the number of
* ticks passed to this method.
*
* @param tickCount
* Number of ticks before this transaction times out.
*/
protected void enableTimeoutTimer(int tickCount) {
if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG))
logger.logDebug("enableTimeoutTimer " + this
+ " tickCount " + tickCount + " currentTickCount = "
+ timeoutTimerTicksLeft);
timeoutTimerTicksLeft = tickCount;
}
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#disableTimeoutTimer()
*/
@Override
public void disableTimeoutTimer() {
if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) logger.logDebug("disableTimeoutTimer " + this);
timeoutTimerTicksLeft = -1;
}
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#fireTimer()
*/
@Override
public void fireTimer() {
// If the timeout timer is enabled,
if (timeoutTimerTicksLeft != -1) {
// Count down the timer, and if it has run out,
if (--timeoutTimerTicksLeft == 0) {
fireTimeoutTimer();
}
}
// If the retransmission timer is enabled,
if (retransmissionTimerTicksLeft != -1) {
// Count down the timer, and if it has run out,
if (--retransmissionTimerTicksLeft == 0) {
// Enable this timer to fire again after
// twice the original time
enableRetransmissionTimer(retransmissionTimerLastTickCount * 2);
// Fire the timeout timer
fireRetransmissionTimer();
}
}
}
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#isTerminated()
*/
@Override
public boolean isTerminated() {
return currentState == TransactionState._TERMINATED;
}
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#getHost()
*/
@Override
public String getHost() {
return encapsulatedChannel.getHost();
}
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#getKey()
*/
@Override
public String getKey() {
return encapsulatedChannel.getKey();
}
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#getPort()
*/
@Override
public int getPort() {
return encapsulatedChannel.getPort();
}
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#getSIPStack()
*/
@Override
public SIPTransactionStack getSIPStack() {
return (SIPTransactionStack) sipStack;
}
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#getPeerAddress()
*/
@Override
public String getPeerAddress() {
return this.encapsulatedChannel.getPeerAddress();
}
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#getPeerPort()
*/
@Override
public int getPeerPort() {
return this.encapsulatedChannel.getPeerPort();
}
// @@@ hagai
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#getPeerPacketSourcePort()
*/
@Override
public int getPeerPacketSourcePort() {
return this.encapsulatedChannel.getPeerPacketSourcePort();
}
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#getPeerPacketSourceAddress()
*/
@Override
public InetAddress getPeerPacketSourceAddress() {
return this.encapsulatedChannel.getPeerPacketSourceAddress();
}
public InetAddress getPeerInetAddress() {
return this.encapsulatedChannel.getPeerInetAddress();
}
public String getPeerProtocol() {
return this.encapsulatedChannel.getPeerProtocol();
}
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#getTransport()
*/
@Override
public String getTransport() {
return encapsulatedChannel.getTransport();
}
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#isReliable()
*/
@Override
public boolean isReliable() {
return encapsulatedChannel.isReliable();
}
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#getViaHeader()
*/
@Override
public Via getViaHeader() {
// Via header of the encapulated channel
Via channelViaHeader;
// Add the branch parameter to the underlying
// channel's Via header
channelViaHeader = encapsulatedChannel.getViaHeader();
try {
channelViaHeader.setBranch(branch);
} catch (java.text.ParseException ex) {
}
return channelViaHeader;
}
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#sendMessage(android.gov.nist.javax.sip.message.SIPMessage)
*/
@Override
public void sendMessage(final SIPMessage messageToSend) throws IOException {
// Use the peer address, port and transport
// that was specified when the transaction was
// created. Bug was noted by Bruce Evangelder
// soleo communications.
try {
final RawMessageChannel channel = (RawMessageChannel) encapsulatedChannel;
for (MessageProcessor messageProcessor : sipStack
.getMessageProcessors()) {
boolean addrmatch = messageProcessor.getIpAddress().getHostAddress().toString().equals(this.getPeerAddress());
if (addrmatch
&& messageProcessor.getPort() == this.getPeerPort()
&& messageProcessor.getTransport().equalsIgnoreCase(
this.getPeerProtocol())) {
if (channel instanceof TCPMessageChannel) {
try {
ThreadAffinityTask processMessageTask = new ThreadAffinityTask() {
public void run() {
try {
((TCPMessageChannel) channel)
.processMessage((SIPMessage) messageToSend.clone(), getPeerInetAddress());
} catch (Exception ex) {
if (logger.isLoggingEnabled(ServerLogger.TRACE_ERROR)) {
logger.logError("Error self routing TCP message cause by: ", ex);
}
}
}
public Object getThreadHash() {
return messageToSend.getCallId().getCallId();
}
};
getSIPStack().getSelfRoutingThreadpoolExecutor().execute(processMessageTask);
} catch (Exception e) {
logger.logError("Error passing message in self routing TCP", e);
}
if (logger.isLoggingEnabled(LogLevels.TRACE_DEBUG))
logger.logDebug("Self routing message TCP");
return;
}
if (channel instanceof TLSMessageChannel) {
try {
ThreadAffinityTask processMessageTask = new ThreadAffinityTask() {
public void run() {
try {
((TLSMessageChannel) channel)
.processMessage((SIPMessage) messageToSend.clone(), getPeerInetAddress());
} catch (Exception ex) {
if (logger.isLoggingEnabled(ServerLogger.TRACE_ERROR)) {
logger.logError("Error self routing TLS message cause by: ", ex);
}
}
}
public Object getThreadHash() {
return messageToSend.getCallId().getCallId();
}
};
getSIPStack().getSelfRoutingThreadpoolExecutor().execute(processMessageTask);
} catch (Exception e) {
logger.logError("Error passing message in TLS self routing", e);
}
if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG))
logger.logDebug("Self routing message TLS");
return;
}
if (channel instanceof RawMessageChannel) {
try {
ThreadAffinityTask processMessageTask = new ThreadAffinityTask() {
public void run() {
try {
((RawMessageChannel) channel).processMessage((SIPMessage) messageToSend.clone());
} catch (Exception ex) {
if (logger.isLoggingEnabled(ServerLogger.TRACE_ERROR)) {
logger.logError("Error self routing message cause by: ", ex);
}
}
}
public Object getThreadHash() {
return messageToSend.getCallId().getCallId();
}
};
getSIPStack().getSelfRoutingThreadpoolExecutor().execute(processMessageTask);
} catch (Exception e) {
logger.logError("Error passing message in self routing", e);
}
if (logger.isLoggingEnabled(LogLevels.TRACE_DEBUG))
logger.logDebug("Self routing message");
return;
}
}
}
encapsulatedChannel.sendMessage(messageToSend,
this.getPeerInetAddress(), this.getPeerPort());
} finally {
this.startTransactionTimer();
}
}
/**
* Parse the byte array as a message, process it through the transaction,
* and send it to the SIP peer. This is just a placeholder method -- calling
* it will result in an IO exception.
*
* @param messageBytes
* Bytes of the message to send.
* @param receiverAddress
* Address of the target peer.
* @param receiverPort
* Network port of the target peer.
*
* @throws IOException
* If called.
*/
public void sendMessage(byte[] messageBytes,
InetAddress receiverAddress, int receiverPort, boolean retry)
throws IOException {
throw new IOException(
"Cannot send unparsed message through Transaction Channel!");
}
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#addEventListener(android.gov.nist.javax.sip.stack.SIPTransactionEventListener)
*/
@Override
public void addEventListener(SIPTransactionEventListener newListener) {
eventListeners.add(newListener);
}
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#removeEventListener(android.gov.nist.javax.sip.stack.SIPTransactionEventListener)
*/
@Override
public void removeEventListener(SIPTransactionEventListener oldListener) {
eventListeners.remove(oldListener);
}
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#raiseErrorEvent(int)
*/
@Override
public void raiseErrorEvent(int errorEventID) {
// Error event to send to all listeners
SIPTransactionErrorEvent newErrorEvent;
// Iterator through the list of listeners
Iterator listenerIterator;
// Next listener in the list
SIPTransactionEventListener nextListener;
// Create the error event
newErrorEvent = new SIPTransactionErrorEvent(this, errorEventID);
// Loop through all listeners of this transaction
synchronized (eventListeners) {
listenerIterator = eventListeners.iterator();
while (listenerIterator.hasNext()) {
// Send the event to the next listener
nextListener = (SIPTransactionEventListener) listenerIterator
.next();
nextListener.transactionErrorEvent(newErrorEvent);
}
}
// Clear the event listeners after propagating the error.
// Retransmit notifications are just an alert to the
// application (they are not an error).
if (errorEventID != SIPTransactionErrorEvent.TIMEOUT_RETRANSMIT) {
eventListeners.clear();
// Errors always terminate a transaction
this.setState(TransactionState._TERMINATED);
if (this instanceof SIPServerTransaction && this.isByeTransaction()
&& this.getDialog() != null)
((SIPDialog) this.getDialog())
.setState(SIPDialog.TERMINATED_STATE);
}
}
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#isServerTransaction()
*/
@Override
public boolean isServerTransaction() {
return this instanceof SIPServerTransaction;
}
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#getDialog()
*/
@Override
public abstract Dialog getDialog();
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#setDialog(android.gov.nist.javax.sip.stack.SIPDialog, java.lang.String)
*/
@Override
public abstract void setDialog(SIPDialog sipDialog, String dialogId);
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#getRetransmitTimer()
*/
@Override
public int getRetransmitTimer() {
return SIPTransactionStack.BASE_TIMER_INTERVAL;
}
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#getViaHost()
*/
@Override
public String getViaHost() {
return this.getViaHeader().getHost();
}
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#getLastResponse()
*/
@Override
public SIPResponse getLastResponse() {
return this.lastResponse;
}
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#getResponse()
*/
@Override
public Response getResponse() {
return (Response) this.lastResponse;
}
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#getTransactionId()
*/
@Override
public String getTransactionId() {
return this.transactionId;
}
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#hashCode()
*/
@Override
public int hashCode() {
if (this.transactionId == null)
return -1;
else
return this.transactionId.hashCode();
}
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#getViaPort()
*/
@Override
public int getViaPort() {
return this.getViaHeader().getPort();
}
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#doesCancelMatchTransaction(android.gov.nist.javax.sip.message.SIPRequest)
*/
@Override
public boolean doesCancelMatchTransaction(SIPRequest requestToTest) {
// List of Via headers in the message to test
// ViaList viaHeaders;
// Topmost Via header in the list
Via topViaHeader;
// Branch code in the topmost Via header
String messageBranch;
// Flags whether the select message is part of this transaction
boolean transactionMatches;
transactionMatches = false;
final SIPRequest origRequest = getOriginalRequest();
if (origRequest == null
|| this.getMethod().equals(Request.CANCEL))
return false;
// Get the topmost Via header and its branch parameter
topViaHeader = requestToTest.getTopmostVia();
if (topViaHeader != null) {
// topViaHeader = (Via) viaHeaders.getFirst();
messageBranch = topViaHeader.getBranch();
if (messageBranch != null) {
// If the branch parameter exists but
// does not start with the magic cookie,
if (!messageBranch.toLowerCase().startsWith(SIPConstants.BRANCH_MAGIC_COOKIE_LOWER_CASE)) {
// Flags this as old
// (RFC2543-compatible) client
// version
messageBranch = null;
}
}
// If a new branch parameter exists,
if (messageBranch != null && this.getBranch() != null) {
// If the branch equals the branch in
// this message,
if (getBranch().equalsIgnoreCase(messageBranch)
&& topViaHeader.getSentBy().equals(
origRequest.getTopmostVia().getSentBy())) {
transactionMatches = true;
if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG))
logger.logDebug("returning true");
}
} else {
// If this is an RFC2543-compliant message,
// If RequestURI, To tag, From tag,
// CallID, CSeq number, and top Via
// headers are the same,
if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG))
logger.logDebug("testing against "
+ origRequest);
if (origRequest.getRequestURI().equals(
requestToTest.getRequestURI())
&& origRequest.getTo().equals(
requestToTest.getTo())
&& origRequest.getFrom().equals(
requestToTest.getFrom())
&& origRequest.getCallId().getCallId().equals(
requestToTest.getCallId().getCallId())
&& origRequest.getCSeq().getSeqNumber() == requestToTest
.getCSeq().getSeqNumber()
&& topViaHeader.equals(origRequest.getTopmostVia())) {
transactionMatches = true;
}
}
}
return transactionMatches;
}
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#setRetransmitTimer(int)
*/
@Override
public void setRetransmitTimer(int retransmitTimer) {
if (retransmitTimer <= 0)
throw new IllegalArgumentException(
"Retransmit timer must be positive!");
if (this.transactionTimerStarted.get())
throw new IllegalStateException(
"Transaction timer is already started");
baseTimerInterval = retransmitTimer;
// Commented out for Issue 303 since those timers are configured separately now
// T4 = 5000 / BASE_TIMER_INTERVAL;
// T2 = 4000 / BASE_TIMER_INTERVAL;
// TIMER_D = 32000 / BASE_TIMER_INTERVAL;
}
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#close()
*/
@Override
public void close() {
this.encapsulatedChannel.close();
if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG))
logger.logDebug("Closing " + this.encapsulatedChannel);
}
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#isSecure()
*/
@Override
public boolean isSecure() {
return encapsulatedChannel.isSecure();
}
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#getMessageProcessor()
*/
@Override
public MessageProcessor getMessageProcessor() {
return this.encapsulatedChannel.getMessageProcessor();
}
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#setApplicationData(java.lang.Object)
*/
@Override
public void setApplicationData(Object applicationData) {
this.applicationData = applicationData;
}
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#getApplicationData()
*/
@Override
public Object getApplicationData() {
return this.applicationData;
}
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#setEncapsulatedChannel(android.gov.nist.javax.sip.stack.MessageChannel)
*/
@Override
public void setEncapsulatedChannel(MessageChannel messageChannel) {
this.encapsulatedChannel = messageChannel;
if ( this instanceof SIPClientTransaction ) {
this.encapsulatedChannel.setEncapsulatedClientTransaction((SIPClientTransaction) this);
}
}
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#getSipProvider()
*/
@Override
public SipProviderImpl getSipProvider() {
return this.getMessageProcessor().getListeningPoint().getProvider();
}
/**
* This realizes basic requirement form RFC 17.2.4 and 8.1.3.1
* @see android.gov.nist.javax.sip.stack.SIPTransaction#raiseIOExceptionEvent()
*/
@Override
public void raiseIOExceptionEvent() {
setState(TransactionState._TERMINATED);
String host = getPeerAddress();
int port = getPeerPort();
String transport = getTransport();
IOExceptionEvent exceptionEvent = new IOExceptionEvent(this, host,
port, transport);
getSipProvider().handleEvent(exceptionEvent, this);
}
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#acquireSem()
*/
@Override
public boolean acquireSem() {
boolean retval = false;
if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
logger.logDebug("acquireSem [[[[" + this);
logger.logStackTrace();
}
if ( this.sipStack.maxListenerResponseTime == -1 ) {
retval = this.semaphore.acquire();
} else {
retval = this.semaphore.tryAcquire();
}
if ( logger.isLoggingEnabled(LogWriter.TRACE_DEBUG))
logger.logDebug(
"acquireSem() returning : " + retval);
return retval;
}
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#releaseSem()
*/
@Override
public void releaseSem() {
try {
this.toListener = false;
this.semRelease();
} catch (Exception ex) {
logger.logError("Unexpected exception releasing sem",
ex);
}
}
public void semRelease() {
if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
logger.logDebug("semRelease ]]]]" + this);
logger.logStackTrace();
}
this.semaphore.release();
}
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#passToListener()
*/
@Override
public boolean passToListener() {
return toListener;
}
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#setPassToListener()
*/
@Override
public void setPassToListener() {
if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
logger.logDebug("setPassToListener()");
}
this.toListener = true;
}
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#testAndSetTransactionTerminatedEvent()
*/
@Override
public synchronized boolean testAndSetTransactionTerminatedEvent() {
boolean retval = !this.terminatedEventDelivered;
this.terminatedEventDelivered = true;
return retval;
}
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#getCipherSuite()
*/
@Override
public String getCipherSuite() throws UnsupportedOperationException {
if (this.getMessageChannel() instanceof TLSMessageChannel ) {
if ( ((TLSMessageChannel) this.getMessageChannel()).getHandshakeCompletedListener() == null )
return null;
else if ( ((TLSMessageChannel) this.getMessageChannel()).getHandshakeCompletedListener().getHandshakeCompletedEvent() == null)
return null;
else return ((TLSMessageChannel) this.getMessageChannel()).getHandshakeCompletedListener().getHandshakeCompletedEvent().getCipherSuite();
} // Added for https://java.net/jira/browse/JSIP-483
else if (this.getMessageChannel() instanceof NioTlsMessageChannel) {
if ( ((NioTlsMessageChannel) this.getMessageChannel()).getHandshakeCompletedListener() == null )
return null;
else return ((NioTlsMessageChannel) this.getMessageChannel()).getHandshakeCompletedListener().getCipherSuite();
} else throw new UnsupportedOperationException("Not a TLS channel");
}
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#getLocalCertificates()
*/
@Override
public java.security.cert.Certificate[] getLocalCertificates() throws UnsupportedOperationException {
if (this.getMessageChannel() instanceof TLSMessageChannel ) {
if ( ((TLSMessageChannel) this.getMessageChannel()).getHandshakeCompletedListener() == null )
return null;
else if ( ((TLSMessageChannel) this.getMessageChannel()).getHandshakeCompletedListener().getHandshakeCompletedEvent() == null)
return null;
else return ((TLSMessageChannel) this.getMessageChannel()).getHandshakeCompletedListener().getHandshakeCompletedEvent().getLocalCertificates();
} // Added for https://java.net/jira/browse/JSIP-483
else if (this.getMessageChannel() instanceof NioTlsMessageChannel) {
if ( ((NioTlsMessageChannel) this.getMessageChannel()).getHandshakeCompletedListener() == null )
return null;
else return ((NioTlsMessageChannel) this.getMessageChannel()).getHandshakeCompletedListener().getLocalCertificates();
} else throw new UnsupportedOperationException("Not a TLS channel");
}
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#getPeerCertificates()
*/
@Override
public java.security.cert.Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException {
if (this.getMessageChannel() instanceof TLSMessageChannel ) {
if ( ((TLSMessageChannel) this.getMessageChannel()).getHandshakeCompletedListener() == null )
return null;
else if ( ((TLSMessageChannel) this.getMessageChannel()).getHandshakeCompletedListener().getHandshakeCompletedEvent() == null)
return null;
else return ((TLSMessageChannel) this.getMessageChannel()).getHandshakeCompletedListener().getHandshakeCompletedEvent().getPeerCertificates();
} // Added for https://java.net/jira/browse/JSIP-483
else if(this.getMessageChannel() instanceof NioTlsMessageChannel) {
if ( ((NioTlsMessageChannel) this.getMessageChannel()).getHandshakeCompletedListener() == null )
return null;
else return ((NioTlsMessageChannel) this.getMessageChannel()).getHandshakeCompletedListener().getPeerCertificates();
} else throw new UnsupportedOperationException("Not a TLS channel");
}
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#extractCertIdentities()
*/
@Override
public List extractCertIdentities() throws SSLPeerUnverifiedException {
if (this.getMessageChannel() instanceof TLSMessageChannel || this.getMessageChannel() instanceof NioTlsMessageChannel) {
List certIdentities = new ArrayList();
Certificate[] certs = getPeerCertificates();
if (certs == null) {
if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
logger.logDebug("No certificates available");
}
return certIdentities;
}
for (Certificate cert : certs) {
X509Certificate x509cert = (X509Certificate) cert;
Collection> subjAltNames = null;
try {
subjAltNames = x509cert.getSubjectAlternativeNames();
} catch (CertificateParsingException ex) {
if (logger.isLoggingEnabled()) {
logger.logError("Error parsing TLS certificate", ex);
}
}
// subjAltName types are defined in rfc2459
final Integer dnsNameType = 2;
final Integer uriNameType = 6;
if (subjAltNames != null) {
if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
logger.logDebug("found subjAltNames: " + subjAltNames);
}
// First look for a URI in the subjectAltName field
for (List< ? > altName : subjAltNames) {
// 0th position is the alt name type
// 1st position is the alt name data
if (altName.get(0).equals(uriNameType)) {
SipURI altNameUri;
try {
altNameUri = new AddressFactoryImpl().createSipURI((String) altName.get(1));
// only sip URIs are allowed
if(!"sip".equals(altNameUri.getScheme()))
continue;
// user certificates are not allowed
if(altNameUri.getUser() != null)
continue;
String altHostName = altNameUri.getHost();
if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
logger.logDebug(
"found uri " + altName.get(1) + ", hostName " + altHostName);
}
certIdentities.add(altHostName);
} catch (ParseException e) {
if (logger.isLoggingEnabled()) {
logger.logError(
"certificate contains invalid uri: " + altName.get(1));
}
}
}
}
// DNS An implementation MUST accept a domain name system
// identifier as a SIP domain identity if and only if no other
// identity is found that matches the "sip" URI type described
// above.
if (certIdentities.isEmpty()) {
for (List< ? > altName : subjAltNames) {
if (altName.get(0).equals(dnsNameType)) {
if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
logger.logDebug("found dns " + altName.get(1));
}
certIdentities.add(altName.get(1).toString());
}
}
}
} else {
// If and only if the subjectAltName does not appear in the
// certificate, the implementation MAY examine the CN field of the
// certificate. If a valid DNS name is found there, the
// implementation MAY accept this value as a SIP domain identity.
String dname = x509cert.getSubjectDN().getName();
String cname = "";
try {
Matcher matcher = EXTRACT_CN.matcher(dname);
if (matcher.matches()) {
cname = matcher.group(1);
if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
logger.logDebug("found CN: " + cname + " from DN: " + dname);
}
certIdentities.add(cname);
}
} catch (Exception ex) {
if (logger.isLoggingEnabled()) {
logger.logError("exception while extracting CN", ex);
}
}
}
}
return certIdentities;
} else
throw new UnsupportedOperationException("Not a TLS channel");
}
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#isMessagePartOfTransaction(android.gov.nist.javax.sip.message.SIPMessage)
*/
@Override
public abstract boolean isMessagePartOfTransaction(SIPMessage messageToTest);
/*
* (non-Javadoc)
* @see android.gov.nist.javax.sip.DialogExt#isReleaseReferences()
*/
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#isReleaseReferences()
*/
@Override
public ReleaseReferencesStrategy getReleaseReferencesStrategy() {
return releaseReferencesStrategy;
}
/*
* (non-Javadoc)
* @see android.gov.nist.javax.sip.DialogExt#setReleaseReferences(ReleaseReferencesStrategy)
*/
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#setReleaseReferences(ReleaseReferencesStrategy)
*/
@Override
public void setReleaseReferencesStrategy(ReleaseReferencesStrategy releaseReferencesStrategy) {
this.releaseReferencesStrategy = releaseReferencesStrategy;
}
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#getTimerD()
*/
@Override
public int getTimerD() {
return timerD;
}
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#getTimerT2()
*/
@Override
public int getTimerT2() {
return T2;
}
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#getTimerT4()
*/
@Override
public int getTimerT4() {
return T4;
}
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#setTimerD(int)
*/
@Override
public void setTimerD(int interval) {
if(interval < 32000) {
throw new IllegalArgumentException("To be RFC 3261 compliant, the value of Timer D should be at least 32s");
}
timerD = interval / baseTimerInterval;
}
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#setTimerT2(int)
*/
@Override
public void setTimerT2(int interval) {
T2 = interval / baseTimerInterval;
}
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#setTimerT4(int)
*/
@Override
public void setTimerT4(int interval) {
T4 = interval / baseTimerInterval;
timerI = T4;
timerK = T4;
}
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#getBaseTimerInterval()
*/
@Override
public int getBaseTimerInterval() {
return this.baseTimerInterval;
}
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#getT4()
*/
@Override
public int getT4() {
return this.T4;
}
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#getT2()
*/
@Override
public int getT2() {
return this.T2;
}
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#getTimerI()
*/
@Override
public int getTimerI() {
return this.timerI;
}
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#getTimerK()
*/
@Override
public int getTimerK() {
return this.timerK;
}
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#setForkId(java.lang.String)
*/
@Override
public void setForkId(String forkId) {
this.forkId = forkId;
}
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#getForkId()
*/
@Override
public String getForkId() {
return forkId;
}
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#scheduleMaxTxLifeTimeTimer()
*/
@Override
public void scheduleMaxTxLifeTimeTimer() {
if (maxTxLifeTimeListener == null && this.getMethod().equalsIgnoreCase(Request.INVITE) && sipStack.getMaxTxLifetimeInvite() > 0) {
if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
logger.logDebug("Scheduling MaxTxLifeTimeListener for tx " + this + " , tx id "+ this.getTransactionId() + " , state " + this.getState());
}
maxTxLifeTimeListener = new MaxTxLifeTimeListener();
sipStack.getTimer().schedule(maxTxLifeTimeListener,
sipStack.getMaxTxLifetimeInvite() * 1000);
}
if (maxTxLifeTimeListener == null && !this.getMethod().equalsIgnoreCase(Request.INVITE) && sipStack.getMaxTxLifetimeNonInvite() > 0) {
if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
logger.logDebug("Scheduling MaxTxLifeTimeListener for tx " + this + " , tx id "+ this.getTransactionId() + " , state " + this.getState());
}
maxTxLifeTimeListener = new MaxTxLifeTimeListener();
sipStack.getTimer().schedule(maxTxLifeTimeListener,
sipStack.getMaxTxLifetimeNonInvite() * 1000);
}
}
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#cancelMaxTxLifeTimeTimer()
*/
@Override
public void cancelMaxTxLifeTimeTimer() {
if(maxTxLifeTimeListener != null) {
if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
logger.logDebug("Cancelling MaxTxLifeTimeListener for tx " + this + " , tx id "+ this.getTransactionId() + " , state " + this.getState());
}
sipStack.getTimer().cancel(maxTxLifeTimeListener);
maxTxLifeTimeListener = null;
}
}
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#getMergeId()
*/
@Override
public String getMergeId() {
if(mergeId == null) {
return ((SIPRequest)getRequest()).getMergeId();
}
return mergeId;
}
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#getAuditTag()
*/
@Override
public long getAuditTag() {
return auditTag;
}
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#setAuditTag(long)
*/
@Override
public void setAuditTag(long auditTag) {
this.auditTag = auditTag;
}
/**
* @see android.gov.nist.javax.sip.stack.SIPServerTransaction#isTransactionMapped()
*/
@Override
public boolean isTransactionMapped() {
return this.isMapped;
}
/**
* @see android.gov.nist.javax.sip.stack.SIPServerTransaction#setTransactionMapped(boolean)
*/
@Override
public void setTransactionMapped(boolean transactionMapped) {
isMapped = transactionMapped;
}
/**
* @see android.gov.nist.javax.sip.stack.SIPTransaction#setCollectionTime(int)
*/
@Override
public void setCollectionTime(int collectionTime) {
this.collectionTime = collectionTime;
}
}