();
+ this.sipDialogs = new ConcurrentHashMap();
}
/**
@@ -325,12 +340,12 @@ protected SIPClientTransaction(SIPTransactionStack newSIPStack, MessageChannel n
* @param newRespondTo ResponseInterface to send messages to.
*/
public void setResponseInterface(ServerResponseInterface newRespondTo) {
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- logger.logDebug(
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
+ sipStack.getStackLogger().logDebug(
"Setting response interface for " + this + " to " + newRespondTo);
if (newRespondTo == null) {
- logger.logStackTrace();
- logger.logDebug("WARNING -- setting to null!");
+ sipStack.getStackLogger().logStackTrace();
+ sipStack.getStackLogger().logDebug("WARNING -- setting to null!");
}
}
@@ -357,10 +372,10 @@ public MessageChannel getRequestChannel() {
public boolean isMessagePartOfTransaction(SIPMessage messageToTest) {
// List of Via headers in the message to test
- Via topMostViaHeader = messageToTest.getTopmostVia();
+ ViaList viaHeaders = messageToTest.getViaHeaders();
// Flags whether the select message is part of this transaction
boolean transactionMatches;
- String messageBranch = topMostViaHeader.getBranch();
+ String messageBranch = ((Via) viaHeaders.getFirst()).getBranch();
boolean rfc3261Compliant = getBranch() != null
&& messageBranch != null
&& getBranch().toLowerCase().startsWith(
@@ -369,21 +384,21 @@ && getBranch().toLowerCase().startsWith(
SIPConstants.BRANCH_MAGIC_COOKIE_LOWER_CASE);
transactionMatches = false;
- if (TransactionState._COMPLETED == this.getInternalState()) {
+ if (TransactionState.COMPLETED == this.getState()) {
if (rfc3261Compliant) {
transactionMatches = getBranch().equalsIgnoreCase(
- topMostViaHeader.getBranch())
+ ((Via) viaHeaders.getFirst()).getBranch())
&& getMethod().equals(messageToTest.getCSeq().getMethod());
} else {
transactionMatches = getBranch().equals(messageToTest.getTransactionId());
}
} else if (!isTerminated()) {
if (rfc3261Compliant) {
- if (topMostViaHeader != null) {
+ if (viaHeaders != null) {
// If the branch parameter is the
// same as this transaction and the method is the same,
- if (getBranch().equalsIgnoreCase(topMostViaHeader.getBranch())) {
- transactionMatches = getMethod().equals(
+ if (getBranch().equalsIgnoreCase(((Via) viaHeaders.getFirst()).getBranch())) {
+ transactionMatches = getOriginalRequest().getCSeq().getMethod().equals(
messageToTest.getCSeq().getMethod());
}
@@ -394,7 +409,7 @@ && getBranch().toLowerCase().startsWith(
transactionMatches = getBranch().equalsIgnoreCase(
messageToTest.getTransactionId());
} else {
- transactionMatches = ((SIPRequest)getRequest()).getTransactionId()
+ transactionMatches = getOriginalRequest().getTransactionId()
.equalsIgnoreCase(messageToTest.getTransactionId());
}
@@ -419,20 +434,20 @@ public void sendMessage(SIPMessage messageToSend) throws IOException {
transactionRequest = (SIPRequest) messageToSend;
// Set the branch id for the top via header.
- Via topVia = (Via) transactionRequest.getTopmostVia();
+ Via topVia = (Via) transactionRequest.getViaHeaders().getFirst();
// Tack on a branch identifier to match responses.
try {
topVia.setBranch(getBranch());
} catch (java.text.ParseException ex) {
}
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- logger.logDebug("Sending Message " + messageToSend);
- logger.logDebug("TransactionState " + this.getState());
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
+ sipStack.getStackLogger().logDebug("Sending Message " + messageToSend);
+ sipStack.getStackLogger().logDebug("TransactionState " + this.getState());
}
// If this is the first request for this transaction,
- if (TransactionState._PROCEEDING == getInternalState()
- || TransactionState._CALLING == getInternalState()) {
+ if (TransactionState.PROCEEDING == getState()
+ || TransactionState.CALLING == getState()) {
// If this is a TU-generated ACK request,
if (transactionRequest.getMethod().equals(Request.ACK)) {
@@ -440,11 +455,10 @@ public void sendMessage(SIPMessage messageToSend) throws IOException {
// Send directly to the underlying
// transport and close this transaction
if (isReliable()) {
- this.setState(TransactionState._TERMINATED);
+ this.setState(TransactionState.TERMINATED);
} else {
- this.setState(TransactionState._COMPLETED);
+ this.setState(TransactionState.COMPLETED);
}
- cleanUpOnTimer();
// BUGBUG -- This suppresses sending the ACK uncomment this
// to
// test 4xx retransmission
@@ -459,7 +473,7 @@ public void sendMessage(SIPMessage messageToSend) throws IOException {
// Send the message to the server
lastRequest = transactionRequest;
- if (getInternalState() < 0) {
+ if (getState() == null) {
// Save this request as the one this transaction
// is handling
setOriginalRequest(transactionRequest);
@@ -467,13 +481,12 @@ public void sendMessage(SIPMessage messageToSend) throws IOException {
// Set state first to avoid race condition..
if (transactionRequest.getMethod().equals(Request.INVITE)) {
- this.setState(TransactionState._CALLING);
+ this.setState(TransactionState.CALLING);
} else if (transactionRequest.getMethod().equals(Request.ACK)) {
// Acks are never retransmitted.
- this.setState(TransactionState._TERMINATED);
- cleanUpOnTimer();
+ this.setState(TransactionState.TERMINATED);
} else {
- this.setState(TransactionState._TRYING);
+ this.setState(TransactionState.TRYING);
}
if (!isReliable()) {
enableRetransmissionTimer();
@@ -491,7 +504,7 @@ public void sendMessage(SIPMessage messageToSend) throws IOException {
} catch (IOException e) {
- this.setState(TransactionState._TERMINATED);
+ this.setState(TransactionState.TERMINATED);
throw e;
}
@@ -516,21 +529,21 @@ public synchronized void processResponse(SIPResponse transactionResponse,
// If the state has not yet been assigned then this is a
// spurious response.
- if (getInternalState() < 0)
+ if (getState() == null)
return;
// Ignore 1xx
- if ((TransactionState._COMPLETED == this.getInternalState() || TransactionState._TERMINATED == this
- .getInternalState())
+ if ((TransactionState.COMPLETED == this.getState() || TransactionState.TERMINATED == this
+ .getState())
&& transactionResponse.getStatusCode() / 100 == 1) {
return;
}
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- logger.logDebug(
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
+ sipStack.getStackLogger().logDebug(
"processing " + transactionResponse.getFirstLine() + "current state = "
+ getState());
- logger.logDebug("dialog = " + dialog);
+ sipStack.getStackLogger().logDebug("dialog = " + dialog);
}
this.lastResponse = transactionResponse;
@@ -550,9 +563,9 @@ public synchronized void processResponse(SIPResponse transactionResponse,
else
nonInviteClientTransaction(transactionResponse, sourceChannel, dialog);
} catch (IOException ex) {
- if (logger.isLoggingEnabled())
- logger.logException(ex);
- this.setState(TransactionState._TERMINATED);
+ if (sipStack.isLoggingEnabled())
+ sipStack.getStackLogger().logException(ex);
+ this.setState(TransactionState.TERMINATED);
raiseErrorEvent(SIPTransactionErrorEvent.TRANSPORT_ERROR);
}
}
@@ -620,9 +633,9 @@ public synchronized void processResponse(SIPResponse transactionResponse,
private void nonInviteClientTransaction(SIPResponse transactionResponse,
MessageChannel sourceChannel, SIPDialog sipDialog) throws IOException {
int statusCode = transactionResponse.getStatusCode();
- if (TransactionState._TRYING == this.getInternalState()) {
- if (statusCode / 100 == 1) {
- this.setState(TransactionState._PROCEEDING);
+ if (TransactionState.TRYING == this.getState()) {
+ if (statusCode / 100 == 1) {
+ this.setState(TransactionState.PROCEEDING);
enableRetransmissionTimer(MAXIMUM_RETRANSMISSION_TICK_COUNT);
enableTimeoutTimer(TIMER_F);
// According to RFC, the TU has to be informed on
@@ -633,25 +646,20 @@ private void nonInviteClientTransaction(SIPResponse transactionResponse,
this.semRelease();
}
} else if (200 <= statusCode && statusCode <= 699) {
- if (!isReliable()) {
- this.setState(TransactionState._COMPLETED);
- scheduleTimerK(TIMER_K);
- } else {
- this.setState(TransactionState._TERMINATED);
- }
// Send the response up to the TU.
if (respondTo != null) {
respondTo.processResponse(transactionResponse, this, sipDialog);
} else {
this.semRelease();
}
- if (isReliable()
- && TransactionState._TERMINATED == getInternalState()) {
- cleanUpOnTerminated();
+ if (!isReliable()) {
+ this.setState(TransactionState.COMPLETED);
+ enableTimeoutTimer(TIMER_K);
+ } else {
+ this.setState(TransactionState.TERMINATED);
}
- cleanUpOnTimer();
}
- } else if (TransactionState._PROCEEDING == this.getInternalState()) {
+ } else if (TransactionState.PROCEEDING == this.getState()) {
if (statusCode / 100 == 1) {
if (respondTo != null) {
respondTo.processResponse(transactionResponse, this, sipDialog);
@@ -659,66 +667,30 @@ private void nonInviteClientTransaction(SIPResponse transactionResponse,
this.semRelease();
}
} else if (200 <= statusCode && statusCode <= 699) {
- disableRetransmissionTimer();
- disableTimeoutTimer();
- if (!isReliable()) {
- this.setState(TransactionState._COMPLETED);
- scheduleTimerK(TIMER_K);
- } else {
- this.setState(TransactionState._TERMINATED);
- }
if (respondTo != null) {
respondTo.processResponse(transactionResponse, this, sipDialog);
} else {
this.semRelease();
}
- if (isReliable()
- && TransactionState._TERMINATED == getInternalState()) {
- cleanUpOnTerminated();
+ disableRetransmissionTimer();
+ disableTimeoutTimer();
+ if (!isReliable()) {
+ this.setState(TransactionState.COMPLETED);
+ enableTimeoutTimer(TIMER_K);
+ } else {
+ this.setState(TransactionState.TERMINATED);
}
- cleanUpOnTimer();
}
} else {
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- logger.logDebug(
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
+ sipStack.getStackLogger().logDebug(
" Not sending response to TU! " + getState());
}
this.semRelease();
}
- }
-
- // avoid re-scheduling the transaction timer every 500ms while we know we have to wait for TIMER_K * 500 ms
- private void scheduleTimerK(long time) {
- if(transactionTimer != null && timerKStarted.compareAndSet(false, true)) {
- synchronized (transactionTimerLock) {
- if(!transactionTimerCancelled) {
- sipStack.getTimer().cancel(transactionTimer);
- transactionTimer = null;
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- logger.logDebug("starting TransactionTimerK() : " + getTransactionId() + " time " + time);
- }
- SIPStackTimerTask task = new SIPStackTimerTask () {
-
- public void runTask() {
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- logger.logDebug("executing TransactionTimerJ() : " + getTransactionId());
- }
- fireTimeoutTimer();
- cleanUpOnTerminated();
- }
- };
- if(time > 0) {
- sipStack.getTimer().schedule(task, time * BASE_TIMER_INTERVAL);
- } else {
- task.runTask();
- }
- transactionTimerCancelled =true;
- }
- }
- }
- }
+ }
- /**
+ /**
* Implements the state machine for invite client transactions.
*
*
@@ -779,7 +751,7 @@ private void inviteClientTransaction(SIPResponse transactionResponse,
MessageChannel sourceChannel, SIPDialog dialog) throws IOException {
int statusCode = transactionResponse.getStatusCode();
- if (TransactionState._TERMINATED == this.getInternalState()) {
+ if (TransactionState.TERMINATED == this.getState()) {
boolean ackAlreadySent = false;
// if (dialog != null && dialog.isAckSeen() && dialog.getLastAckSent() != null)
if ( dialog!= null && dialog.isAckSent(transactionResponse.getCSeq().getSeqNumber())) {
@@ -797,8 +769,8 @@ private void inviteClientTransaction(SIPResponse transactionResponse,
try {
// Found the dialog - resend the ACK and
// dont pass up the null transaction
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG))
- logger.logDebug("resending ACK");
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG))
+ sipStack.getStackLogger().logDebug("resending ACK");
dialog.resendAck();
} catch (SipException ex) {
@@ -808,15 +780,15 @@ private void inviteClientTransaction(SIPResponse transactionResponse,
this.semRelease();
return;
- } else if (TransactionState._CALLING == this.getInternalState()) {
+ } else if (TransactionState.CALLING == this.getState()) {
if (statusCode / 100 == 2) {
// JvB: do this ~before~ calling the application, to avoid
// retransmissions
// of the INVITE after app sends ACK
disableRetransmissionTimer();
- disableTimeoutTimer();
- this.setState(TransactionState._TERMINATED);
+ disableTimeoutTimer();
+ this.setState(TransactionState.TERMINATED);
// 200 responses are always seen by TU.
if (respondTo != null)
@@ -827,8 +799,8 @@ private void inviteClientTransaction(SIPResponse transactionResponse,
} else if (statusCode / 100 == 1) {
disableRetransmissionTimer();
- disableTimeoutTimer();
- this.setState(TransactionState._PROCEEDING);
+ disableTimeoutTimer();
+ this.setState(TransactionState.PROCEEDING);
if (respondTo != null)
respondTo.processResponse(transactionResponse, this, dialog);
@@ -843,7 +815,7 @@ private void inviteClientTransaction(SIPResponse transactionResponse,
sendMessage((SIPRequest) createErrorAck());
} catch (Exception ex) {
- logger.logError(
+ sipStack.getStackLogger().logError(
"Unexpected Exception sending ACK -- sending error AcK ", ex);
}
@@ -855,33 +827,33 @@ private void inviteClientTransaction(SIPResponse transactionResponse,
* TU, and the client transaction MUST generate an ACK request.
*/
+ if (respondTo != null) {
+ respondTo.processResponse(transactionResponse, this, dialog);
+ } else {
+ this.semRelease();
+ }
+
if (this.getDialog() != null && ((SIPDialog)this.getDialog()).isBackToBackUserAgent()) {
((SIPDialog) this.getDialog()).releaseAckSem();
}
- if (!isReliable()) {
- this.setState(TransactionState._COMPLETED);
+ if (!isReliable()) {
+ this.setState(TransactionState.COMPLETED);
enableTimeoutTimer(TIMER_D);
- } else {
- // Proceed immediately to the TERMINATED state.
- this.setState(TransactionState._TERMINATED);
- }
- if (respondTo != null) {
- respondTo.processResponse(transactionResponse, this, dialog);
} else {
- this.semRelease();
+ // Proceed immediately to the TERMINATED state.
+ this.setState(TransactionState.TERMINATED);
}
- cleanUpOnTimer();
}
- } else if (TransactionState._PROCEEDING == this.getInternalState()) {
+ } else if (TransactionState.PROCEEDING == this.getState()) {
if (statusCode / 100 == 1) {
if (respondTo != null) {
respondTo.processResponse(transactionResponse, this, dialog);
} else {
this.semRelease();
}
- } else if (statusCode / 100 == 2) {
- this.setState(TransactionState._TERMINATED);
+ } else if (statusCode / 100 == 2) {
+ this.setState(TransactionState.TERMINATED);
if (respondTo != null) {
respondTo.processResponse(transactionResponse, this, dialog);
} else {
@@ -900,13 +872,12 @@ private void inviteClientTransaction(SIPResponse transactionResponse,
((SIPDialog) this.getDialog()).releaseAckSem();
}
// JvB: update state before passing to app
- if (!isReliable()) {
- this.setState(TransactionState._COMPLETED);
+ if (!isReliable()) {
+ this.setState(TransactionState.COMPLETED);
this.enableTimeoutTimer(TIMER_D);
- } else {
- this.setState(TransactionState._TERMINATED);
+ } else {
+ this.setState(TransactionState.TERMINATED);
}
- cleanUpOnTimer();
// Pass up to the TU for processing.
if (respondTo != null)
@@ -920,7 +891,7 @@ private void inviteClientTransaction(SIPResponse transactionResponse,
// enableTimeoutTimer(TIMER_D);
// }
}
- } else if (TransactionState._COMPLETED == this.getInternalState()) {
+ } else if (TransactionState.COMPLETED == this.getState()) {
if (300 <= statusCode && statusCode <= 699) {
// Send back an ACK request
try {
@@ -944,19 +915,19 @@ private void inviteClientTransaction(SIPResponse transactionResponse,
public void sendRequest() throws SipException {
SIPRequest sipRequest = this.getOriginalRequest();
- if (this.getInternalState() >= 0)
- throw new IllegalTransactionStateException("Request already sent", Reason.RequestAlreadySent);
+ if (this.getState() != null)
+ throw new SipException("Request already sent");
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- logger.logDebug("sendRequest() " + sipRequest);
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
+ sipStack.getStackLogger().logDebug("sendRequest() " + sipRequest);
}
try {
sipRequest.checkHeaders();
} catch (ParseException ex) {
- if (logger.isLoggingEnabled())
- logger.logError("missing required header");
- throw new IllegalTransactionStateException(ex.getMessage(), Reason.MissingRequiredHeader);
+ if (sipStack.isLoggingEnabled())
+ sipStack.getStackLogger().logError("missing required header");
+ throw new SipException(ex.getMessage());
}
if (getMethod().equals(Request.SUBSCRIBE)
@@ -966,8 +937,8 @@ public void sendRequest() throws SipException {
* defined by the event package being used.
*
*/
- if (logger.isLoggingEnabled())
- logger.logWarning(
+ if (sipStack.isLoggingEnabled())
+ sipStack.getStackLogger().logWarning(
"Expires header missing in outgoing subscribe --"
+ " Notifier will assume implied value on event package");
}
@@ -977,7 +948,7 @@ public void sendRequest() throws SipException {
* 136) reported by Raghav Ramesh ( BT )
*
*/
- if (this.getMethod().equals(Request.CANCEL)
+ if (this.getOriginalRequest().getMethod().equals(Request.CANCEL)
&& sipStack.isCancelClientTransactionChecked()) {
SIPClientTransaction ct = (SIPClientTransaction) sipStack.findCancelTransaction(
this.getOriginalRequest(), false);
@@ -988,14 +959,16 @@ public void sendRequest() throws SipException {
* requests that have already generated a final response.
*/
throw new SipException("Could not find original tx to cancel. RFC 3261 9.1");
- } else if (ct.getInternalState() < 0) {
+ } else if (ct.getState() == null) {
throw new SipException(
"State is null no provisional response yet -- cannot cancel RFC 3261 9.1");
- } else if (!ct.isInviteTransaction()) {
+ } else if (!ct.getMethod().equals(Request.INVITE)) {
throw new SipException("Cannot cancel non-invite requests RFC 3261 9.1");
}
- } else if (this.getMethod().equals(Request.BYE)
- || this.getMethod().equals(Request.NOTIFY)) {
+ } else
+
+ if (this.getOriginalRequest().getMethod().equals(Request.BYE)
+ || this.getOriginalRequest().getMethod().equals(Request.NOTIFY)) {
SIPDialog dialog = sipStack.getDialog(this.getOriginalRequest()
.getDialogId(false));
// I want to behave like a user agent so send the BYE using the
@@ -1007,7 +980,7 @@ public void sendRequest() throws SipException {
}
}
// Only map this after the fist request is sent out.
- if (isInviteTransaction()) {
+ if (this.getMethod().equals(Request.INVITE)) {
SIPDialog dialog = this.getDefaultDialog();
if (dialog != null && dialog.isBackToBackUserAgent()) {
@@ -1019,29 +992,23 @@ public void sendRequest() throws SipException {
}
}
this.isMapped = true;
- // Time extracted from the Expires header.
int expiresTime = -1;
-
- if ( sipRequest.getHeader(ExpiresHeader.NAME) != null ) {
+ if ( sipRequest.getHeader(ExpiresHeader.NAME) != null ) {
Expires expires = (Expires) sipRequest.getHeader(ExpiresHeader.NAME);
expiresTime = expires.getExpires();
}
// This is a User Agent. The user has specified an Expires time. Start a timer
// which will check if the tx is terminated by that time.
- if ( this.getDefaultDialog() != null && isInviteTransaction() &&
+ if ( this.getDefaultDialog() != null && getMethod().equals(Request.INVITE) &&
expiresTime != -1 && expiresTimerTask == null ) {
this.expiresTimerTask = new ExpiresTimerTask();
sipStack.getTimer().schedule(expiresTimerTask, expiresTime * 1000);
}
this.sendMessage(sipRequest);
-
} catch (IOException ex) {
- this.setState(TransactionState._TERMINATED);
- if ( this.expiresTimerTask != null ) {
- sipStack.getTimer().cancel(this.expiresTimerTask);
- }
+ this.setState(TransactionState.TERMINATED);
throw new SipException(
ex.getMessage() == null ? "IO Error sending request" : ex.getMessage(),
ex);
@@ -1057,17 +1024,17 @@ protected void fireRetransmissionTimer() {
try {
// Resend the last request sent
- if (this.getInternalState() < 0 || !this.isMapped)
+ if (this.getState() == null || !this.isMapped)
return;
boolean inv = isInviteTransaction();
- int s = this.getInternalState();
+ TransactionState s = this.getState();
// JvB: INVITE CTs only retransmit in CALLING, non-INVITE in both TRYING and
// PROCEEDING
// Bug-fix for non-INVITE transactions not retransmitted when 1xx response received
- if ((inv && TransactionState._CALLING == s)
- || (!inv && (TransactionState._TRYING == s || TransactionState._PROCEEDING == s))) {
+ if ((inv && TransactionState.CALLING == s)
+ || (!inv && (TransactionState.TRYING == s || TransactionState.PROCEEDING == s))) {
// If the retransmission filter is disabled then
// retransmission of the INVITE is the application
// responsibility.
@@ -1091,7 +1058,7 @@ protected void fireRetransmissionTimer() {
this.getSipProvider().handleEvent(txTimeout, this);
}
if (this.timeoutIfStillInCallingState
- && this.getInternalState() == TransactionState._CALLING) {
+ && this.getState() == TransactionState.CALLING) {
this.callingStateTimeoutCount--;
if (callingStateTimeoutCount == 0) {
TimeoutEvent timeoutEvent = new TimeoutEvent(this.getSipProvider(),
@@ -1116,18 +1083,19 @@ protected void fireRetransmissionTimer() {
*/
protected void fireTimeoutTimer() {
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG))
- logger.logDebug("fireTimeoutTimer " + this);
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG))
+ sipStack.getStackLogger().logDebug("fireTimeoutTimer " + this);
SIPDialog dialog = (SIPDialog) this.getDialog();
- if (TransactionState._CALLING == this.getInternalState()
- || TransactionState._TRYING == this.getInternalState()
- || TransactionState._PROCEEDING == this.getInternalState()) {
+ if (TransactionState.CALLING == this.getState()
+ || TransactionState.TRYING == this.getState()
+ || TransactionState.PROCEEDING == this.getState()) {
// Timeout occured. If this is asociated with a transaction
// creation then kill the dialog.
if (dialog != null
&& (dialog.getState() == null || dialog.getState() == DialogState.EARLY)) {
- if (SIPTransactionStack.isDialogCreated(this.getMethod())) {
+ if (((SIPTransactionStack) getSIPStack()).isDialogCreated(this
+ .getOriginalRequest().getMethod())) {
// If this is a re-invite we do not delete the dialog even
// if the
// reinvite times out. Else
@@ -1137,35 +1105,35 @@ protected void fireTimeoutTimer() {
} else if (dialog != null) {
// Guard against the case of BYE time out.
- if (this.getMethod().equalsIgnoreCase(Request.BYE)
+ if (getOriginalRequest().getMethod().equalsIgnoreCase(Request.BYE)
&& dialog.isTerminatedOnBye()) {
// Terminate the associated dialog on BYE Timeout.
dialog.delete();
}
}
}
- if (TransactionState._COMPLETED != this.getInternalState() && TransactionState._TERMINATED != this.getInternalState()) {
+ if (TransactionState.COMPLETED != this.getState()) {
raiseErrorEvent(SIPTransactionErrorEvent.TIMEOUT_ERROR);
// Got a timeout error on a cancel.
- if (this.getMethod().equalsIgnoreCase(Request.CANCEL)) {
+ if (this.getOriginalRequest().getMethod().equalsIgnoreCase(Request.CANCEL)) {
SIPClientTransaction inviteTx = (SIPClientTransaction) this.getOriginalRequest()
.getInviteTransaction();
if (inviteTx != null
- && ((inviteTx.getInternalState() == TransactionState._CALLING || inviteTx
- .getInternalState() == TransactionState._PROCEEDING))
+ && ((inviteTx.getState() == TransactionState.CALLING || inviteTx
+ .getState() == TransactionState.PROCEEDING))
&& inviteTx.getDialog() != null) {
/*
* A proxy server should have started TIMER C and take care of the Termination
* using transaction.terminate() by itself (i.e. this is not the job of the
* stack at this point but we do it to be nice.
*/
- inviteTx.setState(TransactionState._TERMINATED);
+ inviteTx.setState(TransactionState.TERMINATED);
}
}
} else {
- this.setState(TransactionState._TERMINATED);
+ this.setState(TransactionState.TERMINATED);
}
}
@@ -1205,8 +1173,8 @@ public Request createAck() throws SipException {
} else if (lastResponse == null) {
throw new SipException("bad Transaction state");
} else if (lastResponse.getStatusCode() < 200) {
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- logger.logDebug("lastResponse = " + lastResponse);
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
+ sipStack.getStackLogger().logDebug("lastResponse = " + lastResponse);
}
throw new SipException("Cannot ACK a provisional response!");
}
@@ -1288,13 +1256,13 @@ private final Request createErrorAck() throws SipException, ParseException {
SIPRequest originalRequest = this.getOriginalRequest();
if (originalRequest == null)
throw new SipException("bad state " + getState());
- if (!isInviteTransaction()) {
+ if (!getMethod().equals(Request.INVITE)) {
throw new SipException("Can only ACK an INVITE!");
} else if (lastResponse == null) {
throw new SipException("bad Transaction state");
} else if (lastResponse.getStatusCode() < 200) {
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- logger.logDebug("lastResponse = " + lastResponse);
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
+ sipStack.getStackLogger().logDebug("lastResponse = " + lastResponse);
}
throw new SipException("Cannot ACK a provisional response!");
}
@@ -1304,14 +1272,14 @@ private final Request createErrorAck() throws SipException, ParseException {
/**
* Set the port of the recipient.
*/
- public void setViaPort(int port) {
+ protected void setViaPort(int port) {
this.viaPort = port;
}
/**
* Set the port of the recipient.
*/
- public void setViaHost(String host) {
+ protected void setViaHost(String host) {
this.viaHost = host;
}
@@ -1356,18 +1324,18 @@ public void clearState() {
* connection for outgoing requests in this time period) and calls the superclass to set
* state.
*/
- public void setState(int newState) {
+ public void setState(TransactionState newState) {
// Set this timer for connection caching
// of incoming connections.
- if (newState == TransactionState._TERMINATED && this.isReliable()
+ if (newState == TransactionState.TERMINATED && this.isReliable()
&& (!getSIPStack().cacheClientConnections)) {
// Set a time after which the connection
// is closed.
this.collectionTime = TIMER_J;
}
- if (super.getInternalState() != TransactionState._COMPLETED
- && (newState == TransactionState._COMPLETED || newState == TransactionState._TERMINATED)) {
+ if (super.getState() != TransactionState.COMPLETED
+ && (newState == TransactionState.COMPLETED || newState == TransactionState.TERMINATED)) {
sipStack.decrementActiveClientTransactionCount();
}
super.setState(newState);
@@ -1377,14 +1345,10 @@ public void setState(int newState) {
* Start the timer task.
*/
protected void startTransactionTimer() {
- if (this.transactionTimerStarted.compareAndSet(false, true)) {
+ if (this.transactionTimerStarted.compareAndSet(false, true)) {
+ TimerTask myTimer = new TransactionTimer();
if ( sipStack.getTimer() != null ) {
- synchronized (transactionTimerLock) {
- if(!transactionTimerCancelled) {
- transactionTimer = new TransactionTimer();
- sipStack.getTimer().scheduleWithFixedDelay(transactionTimer, BASE_TIMER_INTERVAL, BASE_TIMER_INTERVAL);
- }
- }
+ sipStack.getTimer().schedule(myTimer, BASE_TIMER_INTERVAL, BASE_TIMER_INTERVAL);
}
}
}
@@ -1396,22 +1360,13 @@ protected void startTransactionTimer() {
* @see javax.sip.Transaction#terminate()
*/
public void terminate() throws ObjectInUseException {
- this.setState(TransactionState._TERMINATED);
+ this.setState(TransactionState.TERMINATED);
if(!transactionTimerStarted.get()) {
// if no transaction timer was started just remove the tx without firing a transaction terminated event
testAndSetTransactionTerminatedEvent();
sipStack.removeTransaction(this);
}
- }
-
- /**
- * Stop the ExPIRES timer if it is running.
- */
- public void stopExpiresTimer() {
- if ( this.expiresTimerTask != null ) {
- sipStack.getTimer().cancel(this.expiresTimerTask);
- this.expiresTimerTask = null;
- }
+
}
/**
@@ -1423,17 +1378,17 @@ public void stopExpiresTimer() {
* @return true if the check passes.
*/
public boolean checkFromTag(SIPResponse sipResponse) {
- String originalFromTag = getOriginalRequestFromTag();
+ String originalFromTag = ((SIPRequest) this.getRequest()).getFromTag();
if (this.defaultDialog != null) {
if (originalFromTag == null ^ sipResponse.getFrom().getTag() == null) {
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG))
- logger.logDebug("From tag mismatch -- dropping response");
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG))
+ sipStack.getStackLogger().logDebug("From tag mismatch -- dropping response");
return false;
}
if (originalFromTag != null
&& !originalFromTag.equalsIgnoreCase(sipResponse.getFrom().getTag())) {
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG))
- logger.logDebug("From tag mismatch -- dropping response");
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG))
+ sipStack.getStackLogger().logDebug("From tag mismatch -- dropping response");
return false;
}
}
@@ -1448,21 +1403,7 @@ public boolean checkFromTag(SIPResponse sipResponse) {
* gov.nist.javax.sip.stack.MessageChannel)
*/
public void processResponse(SIPResponse sipResponse, MessageChannel incomingChannel) {
-
- int code = sipResponse.getStatusCode();
- boolean isRetransmission = !responsesReceived.add(Integer.valueOf(code));
- if(code == 183 && isRetransmission) {
- if(lastResponse != null && !sipResponse.toString().equals(lastResponse.toString())) {
- isRetransmission = false;
- }
- }
-
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- logger.logDebug(
- "marking response as retransmission " + isRetransmission + " for ctx " + this);
- }
- sipResponse.setRetransmission(isRetransmission);
-
+
// If a dialog has already been created for this response,
// pass it up.
SIPDialog dialog = null;
@@ -1481,10 +1422,11 @@ public void processResponse(SIPResponse sipResponse, MessageChannel incomingChan
// JvB: Check all conditions required for creating a new Dialog
if (dialog == null) {
+ int code = sipResponse.getStatusCode();
if ((code > 100 && code < 300)
/* skip 100 (may have a to tag */
&& (sipResponse.getToTag() != null || sipStack.isRfc2543Supported())
- && SIPTransactionStack.isDialogCreated(method)) {
+ && sipStack.isDialogCreated(method)) {
/*
* Dialog cannot be found for the response. This must be a forked response. no
@@ -1500,10 +1442,11 @@ public void processResponse(SIPResponse sipResponse, MessageChannel incomingChan
*/
if (defaultDialog != null) {
if (sipResponse.getFromTag() != null) {
+ SIPResponse dialogResponse = defaultDialog.getLastResponse();
String defaultDialogId = defaultDialog.getDialogId();
- if (defaultDialog.getLastResponseMethod() == null
+ if (dialogResponse == null
|| (method.equals(Request.SUBSCRIBE)
- && defaultDialog.getLastResponseMethod().equals(
+ && dialogResponse.getCSeq().getMethod().equals(
Request.NOTIFY) && defaultDialogId
.equals(dialogId))) {
// The default dialog has not been claimed yet.
@@ -1532,7 +1475,7 @@ public void processResponse(SIPResponse sipResponse, MessageChannel incomingChan
if ( dialog != null ) {
this.setDialog(dialog, dialog.getDialogId());
} else {
- logger.logError("dialog is unexpectedly null",new NullPointerException());
+ sipStack.getStackLogger().logError("dialog is unexpectedly null",new NullPointerException());
}
} else {
throw new RuntimeException("Response without from-tag");
@@ -1550,12 +1493,7 @@ public void processResponse(SIPResponse sipResponse, MessageChannel incomingChan
dialog = defaultDialog;
}
} else {
- // Test added to make sure the retrans flag is correct on forked responses
- // this will avoid setting the last response on the dialog and chnage its state
- // before it is passed to the dialogfilter layer where it is done as well
- if(TransactionState._TERMINATED != getInternalState()) {
- dialog.setLastResponse(this, sipResponse);
- }
+ dialog.setLastResponse(this, sipResponse);
}
this.processResponse(sipResponse, incomingChannel, dialog);
}
@@ -1568,23 +1506,20 @@ public void processResponse(SIPResponse sipResponse, MessageChannel incomingChan
public Dialog getDialog() {
// This is for backwards compatibility.
Dialog retval = null;
- // get it in a local variable because the last response can be nullified and the if condition
- // can throw NPE
- SIPResponse localLastResponse = this.lastResponse;
- if(localLastResponse != null && localLastResponse.getFromTag() != null
- && localLastResponse.getToTag() != null
- && localLastResponse.getStatusCode() != 100) {
- String dialogId = localLastResponse.getDialogId(false);
+ if (this.lastResponse != null && this.lastResponse.getFromTag() != null
+ && this.lastResponse.getToTag() != null
+ && this.lastResponse.getStatusCode() != 100) {
+ String dialogId = this.lastResponse.getDialogId(false);
retval = (Dialog) getDialog(dialogId);
}
if (retval == null) {
- retval = (Dialog) this.getDefaultDialog();
+ retval = (Dialog) this.defaultDialog;
}
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- logger.logDebug(
- " sipDialogs = " + sipDialogs + " default dialog " + this.getDefaultDialog()
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
+ sipStack.getStackLogger().logDebug(
+ " sipDialogs = " + sipDialogs + " default dialog " + this.defaultDialog
+ " retval " + retval);
}
return retval;
@@ -1598,13 +1533,7 @@ public Dialog getDialog() {
* gov.nist.javax.sip.message.SIPMessage)
*/
public SIPDialog getDialog(String dialogId) {
- SIPDialog retval = null;
- if(sipDialogs != null && sipDialogs.contains(dialogId)) {
- retval = this.sipStack.getDialog(dialogId);
- if(retval == null) {
- retval = this.sipStack.getEarlyDialog(dialogId);
- }
- }
+ SIPDialog retval = (SIPDialog) this.sipDialogs.get(dialogId);
return retval;
}
@@ -1616,35 +1545,30 @@ public SIPDialog getDialog(String dialogId) {
* gov.nist.javax.sip.message.SIPMessage)
*/
public void setDialog(SIPDialog sipDialog, String dialogId) {
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG))
- logger.logDebug(
- "setDialog: " + dialogId + " sipDialog = " + sipDialog);
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG))
+ sipStack.getStackLogger().logDebug(
+ "setDialog: " + dialogId + "sipDialog = " + sipDialog);
if (sipDialog == null) {
- if (logger.isLoggingEnabled(LogWriter.TRACE_ERROR))
- logger.logError("NULL DIALOG!!");
+ if (sipStack.isLoggingEnabled())
+ sipStack.getStackLogger().logError("NULL DIALOG!!");
throw new NullPointerException("bad dialog null");
}
- if (this.defaultDialog == null && defaultDialogId == null) {
+ if (this.defaultDialog == null) {
this.defaultDialog = sipDialog;
- // We only deal with Forked INVITEs.
- if (isInviteTransaction() && this.getSIPStack().getMaxForkTime() != 0) {
+ if ( this.getMethod().equals(Request.INVITE) && this.getSIPStack().getMaxForkTime() != 0) {
this.getSIPStack().addForkedClientTransaction(this);
}
}
- if (dialogId != null && sipDialog.getDialogId() != null && sipDialogs != null) {
- this.sipDialogs.add(dialogId);
+ if (dialogId != null && sipDialog.getDialogId() != null) {
+ this.sipDialogs.put(dialogId, sipDialog);
+
}
}
public SIPDialog getDefaultDialog() {
- SIPDialog dialog = defaultDialog;
- // jeand if the dialog has been nullified then get the dialog from the saved dialog id
- if(dialog == null && defaultDialogId != null) {
- dialog = this.sipStack.getDialog(defaultDialogId);
- }
- return dialog;
+ return this.defaultDialog;
}
/**
@@ -1688,201 +1612,14 @@ public void alertIfStillInCallingStateBy(int count) {
this.callingStateTimeoutCount = count;
}
- // jeand method use to cleanup eagerly all structures that won't be needed anymore once the tx passed in the COMPLETED state
- protected void cleanUpOnTimer() {
- if(isReleaseReferences()) {
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- logger.logDebug("cleanupOnTimer: "
- + getTransactionId());
- }
- // we release the ref to the dialog asap and just keep the id of the dialog to look it up in the dialog table
- if(defaultDialog != null) {
- String dialogId = defaultDialog.getDialogId();
- // we nullify the ref only if it can be find in the dialog table (not always true if the dialog is in null state, check challenge unittest of the testsuite)
- if(dialogId != null && sipStack.getDialog(dialogId) != null) {
- defaultDialogId = dialogId;
- defaultDialog = null;
- }
- }
- if(originalRequest != null) {
- originalRequest.setTransaction(null);
- originalRequest.setInviteTransaction(null);
- originalRequest.cleanUp();
- // we keep the request in a byte array to be able to recreate it
- // no matter what to keep API backward compatibility
- if(originalRequestBytes == null) {
- originalRequestBytes = originalRequest.encodeAsBytes(this.getTransport());
- }
- if(!getMethod().equalsIgnoreCase(Request.INVITE) && !getMethod().equalsIgnoreCase(Request.CANCEL)) {
- originalRequestFromTag = originalRequest.getFromTag();
- originalRequestCallId = originalRequest.getCallId().getCallId();
- originalRequestEventHeader = (Event) originalRequest.getHeader("Event");
- originalRequestContact = originalRequest.getContactHeader();
- originalRequestScheme = originalRequest.getRequestURI().getScheme();
- originalRequest = null;
- }
- }
- // for subscribe Tx we need to keep the last response longer to be able to create notify from dialog
- if(!getMethod().equalsIgnoreCase(Request.SUBSCRIBE)) {
- lastResponse = null;
- }
- lastRequest = null;
- }
- }
-
- //jeand : cleanup method to clear the state of the tx once it has been removed from the stack
- @Override
- public void cleanUp() {
- if(isReleaseReferences()) {
- // release the connection associated with this transaction.
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- logger.logDebug("cleanup : "
- + getTransactionId());
- }
- if(defaultDialog != null) {
- defaultDialogId = defaultDialog.getDialogId();
- defaultDialog = null;
- }
- // we keep the request in a byte array to be able to recreate it
- // no matter what to keep API backward compatibility
- if(originalRequest != null && originalRequestBytes == null) {
- originalRequestBytes = originalRequest.encodeAsBytes(this.getTransport());
- }
- originalRequest = null;
- cleanUpOnTimer();
- // commented out because the application can hold on a ref to the tx
- // after it has been removed from the stack
- // and want to get the request or branch from it
-// originalRequestBytes = null;
-// originalRequestBranch = null;
- originalRequestCallId = null;
- originalRequestEventHeader = null;
- originalRequestFromTag = null;
- originalRequestContact = null;
- originalRequestScheme = null;
- if(sipDialogs != null) {
- sipDialogs.clear();
- }
- responsesReceived.clear();
- respondTo = null;
- transactionTimer = null;
- lastResponse = null;
- transactionTimerLock = null;
-// transactionTimerStarted = null;
- timerKStarted = null;
- }
+ public void stopExpiresTimer() {
+ if ( this.expiresTimerTask != null ) {
+ this.expiresTimerTask.cancel();
+ this.expiresTimerTask = null;
+ }
}
-
- // jeand cleanup called after the ctx timer or the timer k has fired
- protected void cleanUpOnTerminated() {
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- logger.logDebug(
- "removing = " + this + " isReliable "
- + isReliable());
- }
- if(isReleaseReferences()) {
-
- if(originalRequest == null && originalRequestBytes != null) {
- try {
- originalRequest = (SIPRequest) sipStack.getMessageParserFactory().createMessageParser(sipStack).parseSIPMessage(originalRequestBytes, true, false, null);
-// originalRequestBytes = null;
- } catch (ParseException e) {
- logger.logError("message " + originalRequestBytes + " could not be reparsed !");
- }
- }
- }
-
- sipStack.removeTransaction(this);
-
- // Client transaction terminated. Kill connection if
- // this is a TCP after the linger timer has expired.
- // The linger timer is needed to allow any pending requests to
- // return responses.
- if ((!sipStack.cacheClientConnections) && isReliable()) {
-
- int newUseCount = --getMessageChannel().useCount;
- if (newUseCount <= 0) {
- // Let the connection linger for a while and then close
- // it.
- SIPStackTimerTask myTimer = new LingerTimer();
- sipStack.getTimer().schedule(myTimer,
- SIPTransactionStack.CONNECTION_LINGER_TIME * 1000);
- }
- } else {
- // Cache the client connections so dont close the
- // connection. This keeps the connection open permanently
- // until the client disconnects.
- if (logger.isLoggingEnabled() && isReliable()) {
- int useCount = getMessageChannel().useCount;
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG))
- logger.logDebug("Client Use Count = " + useCount);
- }
- // Let the connection linger for a while and then close
- // it.
- if(((SipStackImpl)getSIPStack()).isReEntrantListener() && isReleaseReferences()) {
- cleanUp();
- }
- // Commented out for Issue 298 : not to break backward compatibility
- // this piece of code was not present before aggressive optimizations
- // see sipx-stable-420 branch
-// else {
-// SIPStackTimerTask myTimer = new LingerTimer();
-// sipStack.getTimer().schedule(myTimer,
-// SIPTransactionStack.CONNECTION_LINGER_TIME * 1000);
-// }
- }
-
- }
-
- /**
- * @return the originalRequestFromTag
- */
- public String getOriginalRequestFromTag() {
- if(originalRequest == null) {
- return originalRequestFromTag;
- }
- return originalRequest.getFromTag();
- }
-
- /**
- * @return the originalRequestFromTag
- */
- public String getOriginalRequestCallId() {
- if(originalRequest == null) {
- return originalRequestCallId;
- }
- return originalRequest.getCallId().getCallId();
- }
-
- /**
- * @return the originalRequestFromTag
- */
- public Event getOriginalRequestEvent() {
- if(originalRequest == null) {
- return originalRequestEventHeader;
- }
- return (Event) originalRequest.getHeader(EventHeader.NAME);
- }
-
- /**
- * @return the originalRequestFromTag
- */
- public Contact getOriginalRequestContact() {
- if(originalRequest == null) {
- return originalRequestContact;
- }
- return originalRequest.getContactHeader();
- }
-
- /**
- * @return the originalRequestFromTag
- */
- public String getOriginalRequestScheme() {
- if(originalRequest == null) {
- return originalRequestScheme;
- }
- return originalRequest.getRequestURI().getScheme();
- }
+
+
}
diff --git a/src/gov/nist/javax/sip/stack/SIPDialog.java b/src/gov/nist/javax/sip/stack/SIPDialog.java
index 9dc0a9a83..d2722427d 100755
--- a/src/gov/nist/javax/sip/stack/SIPDialog.java
+++ b/src/gov/nist/javax/sip/stack/SIPDialog.java
@@ -28,13 +28,11 @@
/**************************************************************************/
package gov.nist.javax.sip.stack;
-import gov.nist.core.CommonLogger;
import gov.nist.core.InternalErrorHandler;
-import gov.nist.core.LogLevels;
import gov.nist.core.LogWriter;
import gov.nist.core.NameValueList;
-import gov.nist.core.StackLogger;
import gov.nist.javax.sip.DialogExt;
+import gov.nist.javax.sip.DialogTimeoutEvent;
import gov.nist.javax.sip.ListeningPointImpl;
import gov.nist.javax.sip.SipListenerExt;
import gov.nist.javax.sip.SipProviderImpl;
@@ -54,6 +52,7 @@
import gov.nist.javax.sip.header.RecordRoute;
import gov.nist.javax.sip.header.RecordRouteList;
import gov.nist.javax.sip.header.Require;
+import gov.nist.javax.sip.header.RetryAfter;
import gov.nist.javax.sip.header.Route;
import gov.nist.javax.sip.header.RouteList;
import gov.nist.javax.sip.header.SIPHeader;
@@ -64,10 +63,6 @@
import gov.nist.javax.sip.message.SIPMessage;
import gov.nist.javax.sip.message.SIPRequest;
import gov.nist.javax.sip.message.SIPResponse;
-import gov.nist.javax.sip.parser.AddressParser;
-import gov.nist.javax.sip.parser.CallIDParser;
-import gov.nist.javax.sip.parser.ContactParser;
-import gov.nist.javax.sip.parser.RecordRouteParser;
import java.io.IOException;
import java.io.PrintWriter;
@@ -76,14 +71,14 @@
import java.net.InetAddress;
import java.text.ParseException;
import java.util.ArrayList;
-import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
-import java.util.Random;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
@@ -105,12 +100,12 @@
import javax.sip.header.ContactHeader;
import javax.sip.header.EventHeader;
import javax.sip.header.OptionTag;
-import javax.sip.header.ProxyAuthorizationHeader;
import javax.sip.header.RAckHeader;
import javax.sip.header.RSeqHeader;
import javax.sip.header.ReasonHeader;
import javax.sip.header.RequireHeader;
import javax.sip.header.RouteHeader;
+import javax.sip.header.ServerHeader;
import javax.sip.header.SupportedHeader;
import javax.sip.header.TimeStampHeader;
import javax.sip.message.Request;
@@ -123,19 +118,17 @@
* Martin Le Clerk, Christophe Anzille, Andreas Bystrom, Lebing Xie, Jeroen van Bemmel. Hagai Sela
* reported a bug in updating the route set (on RE-INVITE). Jens Tinfors submitted a bug fix and
* the .equals method. Jan Schaumloeffel contributed a buf fix ( memory leak was happening when
- * 180 contained a To tag. Bug fixes by Vladimir Ralev (Redhat).
- * Performance enhancements and memory reduction enhancements by Jean Deruelle.
+ * 180 contained a To tag.
*
*/
/**
- * Tracks dialogs. A dialog is a peer to peer association of communicating SIP
- * entities. For INVITE transactions, a Dialog is created when a success message
- * is received (i.e. a response that has a To tag). The SIP Protocol stores
- * enough state in the message structure to extract a dialog identifier that can
- * be used to retrieve this structure from the SipStack.
+ * Tracks dialogs. A dialog is a peer to peer association of communicating SIP entities. For
+ * INVITE transactions, a Dialog is created when a success message is received (i.e. a response
+ * that has a To tag). The SIP Protocol stores enough state in the message structure to extract a
+ * dialog identifier that can be used to retrieve this structure from the SipStack.
*
- * @version 1.2 $Revision: 1.207 $ $Date: 2010-12-02 22:04:14 $
+ * @version 1.2 $Revision: 1.172.2.4 $ $Date: 2010-11-23 19:23:12 $
*
* @author M. Ranganathan
*
@@ -143,48 +136,33 @@
*/
public class SIPDialog implements javax.sip.Dialog, DialogExt {
- private static StackLogger logger = CommonLogger.getLogger(SIPDialog.class);
private static final long serialVersionUID = -1429794423085204069L;
- private transient boolean dialogTerminatedEventDelivered; // prevent
- // duplicate
-
+ private transient boolean dialogTerminatedEventDelivered; // prevent duplicate
+
private transient String stackTrace; // for semaphore debugging.
protected String method;
// delivery of the event
- protected transient boolean isAssigned;
+ private transient boolean isAssigned;
- protected boolean reInviteFlag;
+ private boolean reInviteFlag;
- private transient Object applicationData; // Opaque pointer to application
- // data.
+ private transient Object applicationData; // Opaque pointer to application data.
private transient SIPRequest originalRequest;
- // jeand : avoid keeping the original request ref above for too long (mem
- // saving)
- protected transient String originalRequestRecordRouteHeadersString;
- protected transient RecordRouteList originalRequestRecordRouteHeaders;
// Last response (JvB: either sent or received).
- // jeand replaced the last response with only the data from it needed to
- // save on mem
- protected String lastResponseDialogId;
- private Via lastResponseTopMostVia;
- protected Integer lastResponseStatusCode;
- protected long lastResponseCSeqNumber;
- protected String lastResponseMethod;
- protected String lastResponseFromTag;
- protected String lastResponseToTag;
-
- // jeand: needed for reliable response sending but nullifyed right after the
- // ACK has been received or sent to let go of the ref ASAP
- protected SIPTransaction firstTransaction;
- // jeand needed for checking 491 but nullifyed right after the ACK has been
- // received or sent to let go of the ref ASAP
- protected SIPTransaction lastTransaction;
+ protected SIPResponse lastResponse;
+
+ // Should be transient, in case the dialog is serialized it will be null
+ // so when a subsequent request will be sent it will be set and a new message channel can be
+ // created
+ protected transient SIPTransaction firstTransaction;
+
+ protected transient SIPTransaction lastTransaction;
protected String dialogId;
@@ -203,20 +181,17 @@ public class SIPDialog implements javax.sip.Dialog, DialogExt {
private transient SIPTransactionStack sipStack;
private int dialogState;
-
+
protected transient SIPRequest lastAckSent;
- // jeand : replaced the lastAckReceived message with only the data needed to
- // save on mem
- protected Long lastAckReceivedCSeqNumber;
+ protected SIPRequest lastAckReceived;
- // could be set on recovery by examining the method looks like a duplicate
- // of ackSeen
+ // could be set on recovery by examining the method looks like a duplicate of ackSeen
protected transient boolean ackProcessed;
protected transient DialogTimerTask timerTask;
- protected transient long nextSeqno;
+ protected transient Long nextSeqno;
private transient int retransmissionTicksLeft;
@@ -234,13 +209,10 @@ public class SIPDialog implements javax.sip.Dialog, DialogExt {
// Dialog.
protected javax.sip.address.Address localParty;
- protected String localPartyStringified;
protected javax.sip.address.Address remoteParty;
- protected String remotePartyStringified;
protected CallIdHeader callIdHeader;
- protected String callIdHeaderString;
public final static int NULL_STATE = -1;
@@ -260,13 +232,11 @@ public class SIPDialog implements javax.sip.Dialog, DialogExt {
protected boolean terminateOnBye;
- protected transient boolean byeSent; // Flag set when BYE is sent, to
- // disallow new
+ protected transient boolean byeSent; // Flag set when BYE is sent, to disallow new
// requests
protected Address remoteTarget;
- protected String remoteTargetStringified;
protected EventHeader eventHeader; // for Subscribe notify
@@ -276,97 +246,52 @@ public class SIPDialog implements javax.sip.Dialog, DialogExt {
private transient Semaphore ackSem = new Semaphore(1);
- protected transient int reInviteWaitTime = 100;
+ private transient int reInviteWaitTime = 100;
private transient DialogDeleteTask dialogDeleteTask;
- private transient DialogDeleteIfNoAckSentTask dialogDeleteIfNoAckSentTask;
-
- protected transient boolean isAcknowledged;
-
+ private transient DialogDeleteIfNoAckSentTask dialogDeleteIfNoAckSentTask;
+
+ private transient boolean isAcknowledged;
+
private transient long highestSequenceNumberAcknowledged = -1;
-
+
protected boolean isBackToBackUserAgent;
protected boolean sequenceNumberValidation = true;
// List of event listeners for this dialog
- private transient Set eventListeners;
- // added for Issue 248 :
- // https://jain-sip.dev.java.net/issues/show_bug.cgi?id=248
- private Semaphore timerTaskLock = new Semaphore(1);
-
- // We store here the useful data from the first transaction without having
- // to
- // keep the whole transaction object for the duration of the dialog. It also
- // contains the non-transient information used in the replication of
- // dialogs.
- protected boolean firstTransactionSecure;
- protected boolean firstTransactionSeen;
+ private transient Set eventListeners;
+ // added for Issue 248 : https://jain-sip.dev.java.net/issues/show_bug.cgi?id=248
+ private Semaphore timerTaskLock = new Semaphore(1);
+
+ // We store here the useful data from the first transaction without having to
+ // keep the whole transaction object for the duration of the dialog. It also
+ // contains the non-transient information used in the replication of dialogs.
+ protected boolean firstTransactionSecure;
+ protected boolean firstTransactionSeen;
protected String firstTransactionMethod;
protected String firstTransactionId;
protected boolean firstTransactionIsServerTransaction;
protected String firstTransactionMergeId;
- protected int firstTransactionPort = 5060;
+ protected int firstTransactionPort = 5060;
protected Contact contactHeader;
- protected String contactHeaderStringified;
-
- private boolean pendingRouteUpdateOn202Response;
- protected ProxyAuthorizationHeader proxyAuthorizationHeader; // For
- // subequent
- // requests.
+ private boolean pendingRouteUpdateOn202Response;
- // aggressive flag to optimize eagerly
- private boolean releaseReferences;
-
- private EarlyStateTimerTask earlyStateTimerTask;
-
- private int earlyDialogTimeout = 180;
-
- private int ackSemTakenFor;
- private Set responsesReceivedInForkingCase = new HashSet(0);
// //////////////////////////////////////////////////////
// Inner classes
// //////////////////////////////////////////////////////
- class EarlyStateTimerTask extends SIPStackTimerTask implements Serializable {
-
- public EarlyStateTimerTask() {
-
- }
-
- @Override
- public void runTask() {
- try {
- if (SIPDialog.this.getState().equals(DialogState.EARLY)) {
-
- SIPDialog.this
- .raiseErrorEvent(SIPDialogErrorEvent.EARLY_STATE_TIMEOUT);
- } else {
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- logger.logDebug("EarlyStateTimerTask : Dialog state is " + SIPDialog.this.getState());
- }
- }
- } catch (Exception ex) {
- logger.logError(
- "Unexpected exception delivering event", ex);
- }
- }
-
- }
-
/**
- * This task waits till a pending ACK has been recorded and then sends out a
- * re-INVITE. This is to prevent interleaving INVITEs ( which will result in
- * a 493 from the UA that receives the out of order INVITE). This is
- * primarily for B2BUA support. A B2BUA may send a delayed ACK while it does
- * mid call codec renegotiation. In the meanwhile, it cannot send an
- * intervening re-INVITE otherwise the othr end will respond with a
- * REQUEST_PENDING. We want to avoid this condition. Hence we wait till the
- * ACK for the previous re-INVITE has been sent before sending the next
- * re-INVITE.
+ * This task waits till a pending ACK has been recorded and then sends out a re-INVITE. This
+ * is to prevent interleaving INVITEs ( which will result in a 493 from the UA that receives
+ * the out of order INVITE). This is primarily for B2BUA support. A B2BUA may send a delayed
+ * ACK while it does mid call codec renegotiation. In the meanwhile, it cannot send an intervening
+ * re-INVITE otherwise the othr end will respond with a REQUEST_PENDING. We want to avoid this
+ * condition. Hence we wait till the ACK for the previous re-INVITE has been sent before
+ * sending the next re-INVITE.
*/
public class ReInviteSender implements Runnable, Serializable {
private static final long serialVersionUID = 1019346148741070635L;
@@ -374,81 +299,45 @@ public class ReInviteSender implements Runnable, Serializable {
public void terminate() {
try {
- if ( logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- logger.logDebug("ReInviteSender::terminate: ctx = " + ctx);
- }
-
ctx.terminate();
Thread.currentThread().interrupt();
} catch (ObjectInUseException e) {
- logger.logError("unexpected error", e);
+ sipStack.getStackLogger().logError("unexpected error", e);
}
}
public ReInviteSender(ClientTransaction ctx) {
this.ctx = ctx;
- if ( logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- logger.logDebug("ReInviteSender::ReInviteSender: ctx = " + ctx );
- logger.logStackTrace();
- }
}
public void run() {
try {
long timeToWait = 0;
long startTime = System.currentTimeMillis();
- boolean dialogTimedOut = false;
- boolean busyWait = false;
-
- // If we have an INVITE transaction, make sure that it is TERMINATED
- // before sending a re-INVITE.. Not the cleanest solution but it works.
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- logger.logDebug("SIPDialog::reInviteSender: dialog = " + ctx.getDialog() + " lastTransaction = " + lastTransaction + " lastTransactionState " + lastTransaction.getState());
- }
- while (SIPDialog.this.lastTransaction != null &&
- SIPDialog.this.lastTransaction instanceof SIPServerTransaction &&
- SIPDialog.this.lastTransaction.isInviteTransaction() &&
- SIPDialog.this.lastTransaction.getState() != TransactionState.TERMINATED)
- {
- Thread.sleep(50);
- busyWait = true;
- }
-
- // Wait a bit to grab the ack semaphore just in case the OK got sent.
- if (busyWait) {
- Thread.sleep(50);
- }
if (!SIPDialog.this.takeAckSem()) {
/*
* Could not send re-INVITE fire a timeout on the INVITE.
*/
- if (logger.isLoggingEnabled())
- logger
- .logError(
- "Could not send re-INVITE time out ClientTransaction");
+ if (sipStack.isLoggingEnabled())
+ sipStack.getStackLogger().logError(
+ "Could not send re-INVITE time out ClientTransaction");
((SIPClientTransaction) ctx).fireTimeoutTimer();
/*
- * Send BYE to the Dialog.
+ * Send BYE to the Dialog.
*/
- if (sipProvider.getSipListener() != null
- && sipProvider.getSipListener() instanceof SipListenerExt) {
- dialogTimedOut = true;
+ if ( sipProvider.getSipListener() != null && sipProvider.getSipListener() instanceof SipListenerExt ) {
raiseErrorEvent(SIPDialogErrorEvent.DIALOG_REINVITE_TIMEOUT);
} else {
- Request byeRequest = SIPDialog.this
- .createRequest(Request.BYE);
- if (MessageFactoryImpl.getDefaultUserAgentHeader() != null) {
- byeRequest.addHeader(MessageFactoryImpl
- .getDefaultUserAgentHeader());
+ Request byeRequest = SIPDialog.this.createRequest(Request.BYE);
+ if ( MessageFactoryImpl.getDefaultUserAgentHeader() != null ) {
+ byeRequest.addHeader(MessageFactoryImpl.getDefaultUserAgentHeader());
}
ReasonHeader reasonHeader = new Reason();
reasonHeader.setCause(1024);
reasonHeader.setText("Timed out waiting to re-INVITE");
byeRequest.addHeader(reasonHeader);
- ClientTransaction byeCtx = SIPDialog.this
- .getSipProvider().getNewClientTransaction(
- byeRequest);
+ ClientTransaction byeCtx = SIPDialog.this.getSipProvider().getNewClientTransaction(byeRequest);
SIPDialog.this.sendRequest(byeCtx);
return;
}
@@ -459,50 +348,46 @@ public void run() {
}
/*
- * If we had to wait for ACK then wait for the ACK to actually
- * get to the other side. Wait for any ACK retransmissions to
- * finish. Then send out the request. This is a hack in support
- * of some UA that want re-INVITEs to be spaced out in time (
- * else they return a 400 error code ).
+ * If we had to wait for ACK then wait for the ACK to actually get to the other
+ * side. Wait for any ACK retransmissions to finish. Then send out the request.
+ * This is a hack in support of some UA that want re-INVITEs to be spaced out in
+ * time ( else they return a 400 error code ).
*/
try {
if (timeToWait != 0) {
Thread.sleep(SIPDialog.this.reInviteWaitTime);
}
} catch (InterruptedException ex) {
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG))
- logger.logDebug("Interrupted sleep");
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG))
+ sipStack.getStackLogger().logDebug("Interrupted sleep");
return;
}
- if (SIPDialog.this.getState() != DialogState.TERMINATED && !dialogTimedOut && ctx.getState() != TransactionState.TERMINATED ) {
+ if (SIPDialog.this.getState() != DialogState.TERMINATED) {
SIPDialog.this.sendRequest(ctx, true);
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG))
- logger.logDebug(
- "re-INVITE successfully sent");
}
-
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG))
+ sipStack.getStackLogger().logDebug("re-INVITE successfully sent");
} catch (Exception ex) {
- logger.logError("Error sending re-INVITE",
- ex);
+ sipStack.getStackLogger().logError("Error sending re-INVITE", ex);
} finally {
this.ctx = null;
}
}
}
- class LingerTimer extends SIPStackTimerTask implements Serializable {
+ class LingerTimer extends SIPStackTimerTask implements Serializable {
+
+ public LingerTimer() {
- public void runTask() {
+ }
+
+ protected void runTask() {
SIPDialog dialog = SIPDialog.this;
- sipStack.removeDialog(dialog);
- // Issue 279 :
- // https://jain-sip.dev.java.net/issues/show_bug.cgi?id=279
- // if non reentrant listener is used the event delivery of
- // DialogTerminated
- // can happen after the clean
- if (((SipStackImpl) getStack()).isReEntrantListener()) {
- cleanUp();
+ if(eventListeners != null) {
+ eventListeners.clear();
}
+ timerTaskLock = null;
+ sipStack.removeDialog(dialog);
}
}
@@ -511,58 +396,54 @@ class DialogTimerTask extends SIPStackTimerTask implements Serializable {
int nRetransmissions;
SIPServerTransaction transaction;
-
- // long cseqNumber;
+ long cseqNumber;
public DialogTimerTask(SIPServerTransaction transaction) {
this.transaction = transaction;
this.nRetransmissions = 0;
- }
+ this.cseqNumber = transaction.getLastResponse().getCSeq().getSeqNumber();
+ }
- public void runTask() {
+ protected void runTask() {
// If I ACK has not been seen on Dialog,
// resend last response.
SIPDialog dialog = SIPDialog.this;
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG))
- logger.logDebug("Running dialog timer");
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG))
+ sipStack.getStackLogger().logDebug("Running dialog timer");
nRetransmissions++;
SIPServerTransaction transaction = this.transaction;
/*
- * Issue 106. Section 13.3.1.4 RFC 3261 The 2xx response is passed
- * to the transport with an interval that starts at T1 seconds and
- * doubles for each retransmission until it reaches T2 seconds If
- * the server retransmits the 2xx response for 64T1 seconds without
- * receiving an ACK, the dialog is confirmed, but the session SHOULD
+ * Issue 106. Section 13.3.1.4 RFC 3261 The 2xx response is passed to the transport
+ * with an interval that starts at T1 seconds and doubles for each retransmission
+ * until it reaches T2 seconds If the server retransmits the 2xx response for 64*T1
+ * seconds without receiving an ACK, the dialog is confirmed, but the session SHOULD
* be terminated.
*/
- if (nRetransmissions > sipStack.getAckTimeoutFactor()
- * SIPTransaction.T1) {
- if (SIPDialog.this.getSipProvider().getSipListener() != null
- && SIPDialog.this.getSipProvider().getSipListener() instanceof SipListenerExt) {
- raiseErrorEvent(SIPDialogErrorEvent.DIALOG_ACK_NOT_RECEIVED_TIMEOUT);
- } else {
- SIPDialog.this.delete();
- }
+ if (nRetransmissions > sipStack.getAckTimeoutFactor()* SIPTransaction.T1) {
+ if (SIPDialog.this.getSipProvider().getSipListener() != null && SIPDialog.this.getSipProvider().getSipListener() instanceof SipListenerExt ) {
+ raiseErrorEvent(SIPDialogErrorEvent.DIALOG_ACK_NOT_RECEIVED_TIMEOUT);
+ } else {
+ SIPDialog.this.delete();
+ }
if (transaction != null
&& transaction.getState() != javax.sip.TransactionState.TERMINATED) {
- transaction
- .raiseErrorEvent(SIPTransactionErrorEvent.TIMEOUT_ERROR);
+ transaction.raiseErrorEvent(SIPTransactionErrorEvent.TIMEOUT_ERROR);
}
- } else if ((transaction != null) && (!dialog.isAckSeen())) {
- // Retransmit to 2xx until ack receivedialog.
- if (lastResponseStatusCode.intValue() / 100 == 2) {
+ } else if ( (transaction != null)&& (!dialog.isAckSeen()) ) {
+ // Retransmit to 200 until ack receivedialog.
+ SIPResponse response = transaction.getLastResponse();
+ if (response.getStatusCode() == 200) {
try {
// resend the last response.
- if (dialog.toRetransmitFinalResponse(transaction.T2)) {
- transaction.resendLastResponseAsBytes();
- }
+ if (dialog.toRetransmitFinalResponse(transaction.T2))
+ transaction.sendMessage(response);
+
} catch (IOException ex) {
- raiseIOException(transaction.getPeerAddress(),
- transaction.getPeerPort(), transaction
- .getPeerProtocol());
+ raiseIOException(transaction.getPeerAddress(), transaction.getPeerPort(),
+ transaction.getPeerProtocol());
} finally {
// Need to fire the timer so
@@ -572,9 +453,8 @@ public void runTask() {
// Note that this firing also
// drives Listener timeout.
SIPTransactionStack stack = dialog.sipStack;
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- logger.logDebug(
- "resend 200 response from " + dialog);
+ if (stack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
+ stack.getStackLogger().logDebug("resend 200 response from " + dialog);
}
transaction.fireTimer();
}
@@ -585,20 +465,12 @@ public void runTask() {
// confirmed state or ack seen if retransmit filter on.
if (dialog.isAckSeen() || dialog.dialogState == TERMINATED_STATE) {
this.transaction = null;
- getStack().getTimer().cancel(this);
+ this.cancel();
}
}
- @Override
- public void cleanUpBeforeCancel() {
- transaction = null;
- // lastAckSent = null;
- cleanUpOnAck();
- super.cleanUpBeforeCancel();
- }
-
}
/**
@@ -608,70 +480,62 @@ public void cleanUpBeforeCancel() {
class DialogDeleteTask extends SIPStackTimerTask implements Serializable {
- public void runTask() {
+ protected void runTask() {
delete();
}
}
-
+
/**
* This timer task is used to garbage collect the dialog after some time.
*
*/
- class DialogDeleteIfNoAckSentTask extends SIPStackTimerTask implements
- Serializable {
+ class DialogDeleteIfNoAckSentTask extends SIPStackTimerTask implements Serializable {
private long seqno;
-
+
public DialogDeleteIfNoAckSentTask(long seqno) {
this.seqno = seqno;
}
- public void runTask() {
- if (SIPDialog.this.highestSequenceNumberAcknowledged < seqno) {
+ protected void runTask() {
+ if (SIPDialog.this.highestSequenceNumberAcknowledged < seqno) {
/*
- * Did not send ACK so we need to delete the dialog. B2BUA NOTE:
- * we may want to send BYE to the Dialog at this point. Do we
- * want to make this behavior tailorable?
+ * Did not send ACK so we need to delete the dialog.
+ * B2BUA NOTE: we may want to send BYE to the Dialog at this
+ * point. Do we want to make this behavior tailorable?
*/
- dialogDeleteIfNoAckSentTask = null;
- if (!SIPDialog.this.isBackToBackUserAgent) {
- if (logger.isLoggingEnabled())
- logger.logError(
- "ACK Was not sent. killing dialog " + dialogId);
- if (((SipProviderImpl) sipProvider).getSipListener() instanceof SipListenerExt) {
- raiseErrorEvent(SIPDialogErrorEvent.DIALOG_ACK_NOT_SENT_TIMEOUT);
- } else {
- delete();
- }
+ dialogDeleteIfNoAckSentTask = null;
+ if ( !SIPDialog.this.isBackToBackUserAgent) {
+ if (sipStack.isLoggingEnabled())
+ sipStack.getStackLogger().logError("ACK Was not sent. killing dialog " + dialogId);
+ if ( ((SipProviderImpl)sipProvider).getSipListener() instanceof SipListenerExt ){
+ raiseErrorEvent(SIPDialogErrorEvent.DIALOG_ACK_NOT_SENT_TIMEOUT);
+ } else {
+ delete();
+ }
} else {
- if (logger.isLoggingEnabled())
- logger.logError(
- "ACK Was not sent. Sending BYE " + dialogId);
- if (((SipProviderImpl) sipProvider).getSipListener() instanceof SipListenerExt) {
- raiseErrorEvent(SIPDialogErrorEvent.DIALOG_ACK_NOT_SENT_TIMEOUT);
- } else {
+ if (sipStack.isLoggingEnabled())
+ sipStack.getStackLogger().logError("ACK Was not sent. Sending BYE for dialog " + dialogId);
+ if ( ((SipProviderImpl)sipProvider).getSipListener() instanceof SipListenerExt ){
+ raiseErrorEvent(SIPDialogErrorEvent.DIALOG_ACK_NOT_SENT_TIMEOUT);
+ } else {
/*
- * Send BYE to the Dialog. This will be removed for the
- * next spec revision.
+ * Send BYE to the Dialog.
+ * This will be removed for the next spec revision.
*/
try {
- Request byeRequest = SIPDialog.this
- .createRequest(Request.BYE);
- if (MessageFactoryImpl.getDefaultUserAgentHeader() != null) {
- byeRequest.addHeader(MessageFactoryImpl
- .getDefaultUserAgentHeader());
+ Request byeRequest = SIPDialog.this.createRequest(Request.BYE);
+ if ( MessageFactoryImpl.getDefaultUserAgentHeader() != null ) {
+ byeRequest.addHeader(MessageFactoryImpl.getDefaultUserAgentHeader());
}
ReasonHeader reasonHeader = new Reason();
reasonHeader.setProtocol("SIP");
reasonHeader.setCause(1025);
- reasonHeader
- .setText("Timed out waiting to send ACK " + dialogId);
+ reasonHeader.setText("Timed out waiting to send ACK for dialog " + dialogId);
byeRequest.addHeader(reasonHeader);
- ClientTransaction byeCtx = SIPDialog.this
- .getSipProvider().getNewClientTransaction(
- byeRequest);
+ ClientTransaction byeCtx = SIPDialog.this.getSipProvider().getNewClientTransaction(byeRequest);
SIPDialog.this.sendRequest(byeCtx);
return;
} catch (Exception ex) {
@@ -698,28 +562,23 @@ private SIPDialog(SipProviderImpl provider) {
remoteSequenceNumber = -1;
this.sipProvider = provider;
eventListeners = new CopyOnWriteArraySet();
- this.earlyDialogTimeout = ((SIPTransactionStack) provider.getSipStack())
- .getEarlyDialogTimeout();
}
-
+
private void recordStackTrace() {
- StringWriter stringWriter = new StringWriter();
- PrintWriter writer = new PrintWriter(stringWriter);
- new Exception().printStackTrace(writer);
- String stackTraceSignature = Integer.toString(Math.abs(new Random().nextInt()));
- logger.logDebug("TraceRecord = " + stackTraceSignature);
- this.stackTrace = "TraceRecord = " + stackTraceSignature + ":" + stringWriter.getBuffer().toString();
+ StringWriter stringWriter = new StringWriter();
+ PrintWriter writer = new PrintWriter(stringWriter);
+ new Exception().printStackTrace(writer);
+ this.stackTrace = stringWriter.getBuffer().toString();
}
/**
* Constructor given the first transaction.
*
- * @param transaction
- * is the first transaction.
+ * @param transaction is the first transaction.
*/
public SIPDialog(SIPTransaction transaction) {
this(transaction.getSipProvider());
-
+
SIPRequest sipRequest = (SIPRequest) transaction.getRequest();
this.callIdHeader = sipRequest.getCallId();
this.earlyDialogId = sipRequest.getDialogId(false);
@@ -734,26 +593,22 @@ public SIPDialog(SIPTransaction transaction) {
if (sipProvider == null)
throw new NullPointerException("Null Provider!");
this.isBackToBackUserAgent = sipStack.isBackToBackUserAgent;
-
+
this.addTransaction(transaction);
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- logger.logDebug("Creating a dialog : " + this);
- logger.logDebug(
- "provider port = "
- + this.sipProvider.getListeningPoint().getPort());
- logger.logStackTrace();
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
+ sipStack.getStackLogger().logDebug("Creating a dialog : " + this);
+ sipStack.getStackLogger().logDebug(
+ "provider port = " + this.sipProvider.getListeningPoint().getPort());
+ sipStack.getStackLogger().logStackTrace();
}
addEventListener(sipStack);
- releaseReferences = sipStack.isAggressiveCleanup();
}
/**
* Constructor given a transaction and a response.
*
- * @param transaction
- * -- the transaction ( client/server)
- * @param sipResponse
- * -- response with the appropriate tags.
+ * @param transaction -- the transaction ( client/server)
+ * @param sipResponse -- response with the appropriate tags.
*/
public SIPDialog(SIPClientTransaction transaction, SIPResponse sipResponse) {
this(transaction);
@@ -779,13 +634,12 @@ public SIPDialog(SipProviderImpl sipProvider, SIPResponse sipResponse) {
this.method = sipResponse.getCSeq().getMethod();
this.callIdHeader = sipResponse.getCallId();
this.serverTransactionFlag = false;
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- logger.logDebug("Creating a dialog : " + this);
- logger.logStackTrace();
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
+ sipStack.getStackLogger().logDebug("Creating a dialog : " + this);
+ sipStack.getStackLogger().logStackTrace();
}
this.isBackToBackUserAgent = sipStack.isBackToBackUserAgent;
addEventListener(sipStack);
- releaseReferences = sipStack.isAggressiveCleanup();
}
// ///////////////////////////////////////////////////////////
@@ -795,86 +649,86 @@ public SIPDialog(SipProviderImpl sipProvider, SIPResponse sipResponse) {
* A debugging print routine.
*/
private void printRouteList() {
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- logger.logDebug("this : " + this);
- logger.logDebug(
- "printRouteList : " + this.routeList.encode());
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
+ sipStack.getStackLogger().logDebug("this : " + this);
+ sipStack.getStackLogger().logDebug("printRouteList : " + this.routeList.encode());
}
}
+ /**
+ * Return true if this is a client dialog.
+ *
+ * @return true if the transaction that created this dialog is a client transaction and false
+ * otherwise.
+ */
+ private boolean isClientDialog() {
+ SIPTransaction transaction = (SIPTransaction) this.getFirstTransaction();
+ return transaction instanceof SIPClientTransaction;
+ }
+
/**
* Raise an io exception for asyncrhonous retransmission of responses
*
- * @param host
- * -- host to where the io was headed
- * @param port
- * -- remote port
- * @param protocol
- * -- protocol (udp/tcp/tls)
+ * @param host -- host to where the io was headed
+ * @param port -- remote port
+ * @param protocol -- protocol (udp/tcp/tls)
*/
private void raiseIOException(String host, int port, String protocol) {
// Error occured in retransmitting response.
// Deliver the error event to the listener
// Kill the dialog.
- IOExceptionEvent ioError = new IOExceptionEvent(this, host, port,
- protocol);
+ IOExceptionEvent ioError = new IOExceptionEvent(this, host, port, protocol);
sipProvider.handleEvent(ioError, null);
setState(SIPDialog.TERMINATED_STATE);
}
-
+
/**
* Raise a dialog timeout if an ACK has not been sent or received
*
- * @param dialogTimeoutError
+ * @param dialogTimeoutError
*/
private void raiseErrorEvent(int dialogTimeoutError) {
- // Error event to send to all listeners
- SIPDialogErrorEvent newErrorEvent;
- // Iterator through the list of listeners
- Iterator listenerIterator;
- // Next listener in the list
- SIPDialogEventListener nextListener;
-
- // Create the error event
- newErrorEvent = new SIPDialogErrorEvent(this, dialogTimeoutError);
-
- // Loop through all listeners of this transaction
- synchronized (eventListeners) {
-
- listenerIterator = eventListeners.iterator();
- while (listenerIterator.hasNext()) {
- // Send the event to the next listener
- nextListener = (SIPDialogEventListener) listenerIterator.next();
- nextListener.dialogErrorEvent(newErrorEvent);
- }
- }
- // Clear the event listeners after propagating the error.
- eventListeners.clear();
- // Errors always terminate a dialog except if a timeout has occured
- // because an ACK was not sent or received, then it is the
- // responsibility of the app to terminate
- // the dialog, either by sending a BYE or by calling delete() on the
- // dialog
- if (dialogTimeoutError != SIPDialogErrorEvent.DIALOG_ACK_NOT_SENT_TIMEOUT
- && dialogTimeoutError != SIPDialogErrorEvent.DIALOG_ACK_NOT_RECEIVED_TIMEOUT
- && dialogTimeoutError != SIPDialogErrorEvent.EARLY_STATE_TIMEOUT
- && dialogTimeoutError != SIPDialogErrorEvent.DIALOG_REINVITE_TIMEOUT) {
- delete();
- }
-
- // we stop the timer in any case
- stopTimer();
- }
+ // Error event to send to all listeners
+ SIPDialogErrorEvent newErrorEvent;
+ // Iterator through the list of listeners
+ Iterator listenerIterator;
+ // Next listener in the list
+ SIPDialogEventListener nextListener;
+
+ // Create the error event
+ newErrorEvent = new SIPDialogErrorEvent(this, dialogTimeoutError);
+
+ // Loop through all listeners of this transaction
+ synchronized (eventListeners) {
+ listenerIterator = eventListeners.iterator();
+ while (listenerIterator.hasNext()) {
+ // Send the event to the next listener
+ nextListener = (SIPDialogEventListener) listenerIterator.next();
+ nextListener.dialogErrorEvent(newErrorEvent);
+ }
+ }
+ // Clear the event listeners after propagating the error.
+ eventListeners.clear();
+ // Errors always terminate a dialog except if a timeout has occured because an ACK was not sent or received, then it is the responsibility of the app to terminate
+ // the dialog, either by sending a BYE or by calling delete() on the dialog
+ if( dialogTimeoutError != SIPDialogErrorEvent.DIALOG_ACK_NOT_SENT_TIMEOUT &&
+ dialogTimeoutError != SIPDialogErrorEvent.DIALOG_ACK_NOT_RECEIVED_TIMEOUT &&
+ dialogTimeoutError != SIPDialogErrorEvent.DIALOG_REINVITE_TIMEOUT ) {
+ delete();
+ }
+
+ // we stop the timer in any case
+ stopTimer();
+ }
/**
* Set the remote party for this Dialog.
*
- * @param sipMessage
- * -- SIP Message to extract the relevant information from.
+ * @param sipMessage -- SIP Message to extract the relevant information from.
*/
- protected void setRemoteParty(SIPMessage sipMessage) {
+ private void setRemoteParty(SIPMessage sipMessage) {
if (!isServer()) {
@@ -883,45 +737,41 @@ protected void setRemoteParty(SIPMessage sipMessage) {
this.remoteParty = sipMessage.getFrom().getAddress();
}
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- logger.logDebug(
- "settingRemoteParty " + this.remoteParty);
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
+ sipStack.getStackLogger().logDebug("settingRemoteParty " + this.remoteParty);
}
}
/**
- * Add a route list extracted from a record route list. If this is a server
- * dialog then we assume that the record are added to the route list IN
- * order. If this is a client dialog then we assume that the record route
- * headers give us the route list to add in reverse order.
+ * Add a route list extracted from a record route list. If this is a server dialog then we
+ * assume that the record are added to the route list IN order. If this is a client dialog
+ * then we assume that the record route headers give us the route list to add in reverse
+ * order.
*
- * @param recordRouteList
- * -- the record route list from the incoming message.
+ * @param recordRouteList -- the record route list from the incoming message.
*/
private void addRoute(RecordRouteList recordRouteList) {
try {
- if (!this.isServer()) {
+ if (this.isClientDialog()) {
// This is a client dialog so we extract the record
// route from the response and reverse its order to
// careate a route list.
this.routeList = new RouteList();
// start at the end of the list and walk backwards
- ListIterator li = recordRouteList.listIterator(recordRouteList
- .size());
+ ListIterator li = recordRouteList.listIterator(recordRouteList.size());
boolean addRoute = true;
while (li.hasPrevious()) {
RecordRoute rr = (RecordRoute) li.previous();
if (addRoute) {
Route route = new Route();
- AddressImpl address = ((AddressImpl) ((AddressImpl) rr
- .getAddress()).clone());
+ AddressImpl address = ((AddressImpl) ((AddressImpl) rr.getAddress())
+ .clone());
route.setAddress(address);
- route.setParameters((NameValueList) rr.getParameters()
- .clone());
+ route.setParameters((NameValueList) rr.getParameters().clone());
this.routeList.add(route);
}
@@ -939,34 +789,30 @@ private void addRoute(RecordRouteList recordRouteList) {
if (addRoute) {
Route route = new Route();
- AddressImpl address = ((AddressImpl) ((AddressImpl) rr
- .getAddress()).clone());
- route.setAddress(address);
- route.setParameters((NameValueList) rr.getParameters()
+ AddressImpl address = ((AddressImpl) ((AddressImpl) rr.getAddress())
.clone());
+ route.setAddress(address);
+ route.setParameters((NameValueList) rr.getParameters().clone());
routeList.add(route);
}
}
}
} finally {
- if (logger.isLoggingEnabled()) {
+ if (sipStack.getStackLogger().isLoggingEnabled()) {
Iterator it = routeList.iterator();
while (it.hasNext()) {
- SipURI sipUri = (SipURI) (((Route) it.next()).getAddress()
- .getURI());
- if (!sipUri.hasLrParam()) {
- if (logger.isLoggingEnabled()) {
- logger.logWarning(
- "NON LR route in Route set detected for dialog : "
- + this);
- logger.logStackTrace();
- }
+ SipURI sipUri = (SipURI) (((Route) it.next()).getAddress().getURI());
+ if (!sipUri.hasLrParam()) {
+ if (sipStack.isLoggingEnabled()) {
+ sipStack.getStackLogger().logWarning(
+ "NON LR route in Route set detected for dialog : " + this);
+ sipStack.getStackLogger().logStackTrace();
+ }
} else {
- if (logger.isLoggingEnabled(
- LogWriter.TRACE_DEBUG))
- logger.logDebug(
- "route = " + sipUri);
+ if(sipStack.getStackLogger().isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
+ sipStack.getStackLogger().logDebug("route = " + sipUri);
+ }
}
}
}
@@ -976,35 +822,31 @@ private void addRoute(RecordRouteList recordRouteList) {
/**
* Add a route list extacted from the contact list of the incoming message.
*
- * @param contactList
- * -- contact list extracted from the incoming message.
+ * @param contactList -- contact list extracted from the incoming message.
*
*/
- protected void setRemoteTarget(ContactHeader contact) {
+ void setRemoteTarget(ContactHeader contact) {
this.remoteTarget = contact.getAddress();
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- logger.logDebug(
- "Dialog.setRemoteTarget: " + this.remoteTarget);
- logger.logStackTrace();
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
+ sipStack.getStackLogger().logDebug("Dialog.setRemoteTarget: " + this.remoteTarget);
+ sipStack.getStackLogger().logStackTrace();
}
}
/**
- * Extract the route information from this SIP Message and add the relevant
- * information to the route set.
+ * Extract the route information from this SIP Message and add the relevant information to the
+ * route set.
*
- * @param sipMessage
- * is the SIP message for which we want to add the route.
+ * @param sipMessage is the SIP message for which we want to add the route.
*/
private synchronized void addRoute(SIPResponse sipResponse) {
try {
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- logger.logDebug(
- "setContact: dialogState: " + this + "state = "
- + this.getState());
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
+ sipStack.getStackLogger().logDebug(
+ "setContact: dialogState: " + this + "state = " + this.getState());
}
if (sipResponse.getStatusCode() == 100) {
// Do nothing for trying messages.
@@ -1019,26 +861,21 @@ private synchronized void addRoute(SIPResponse sipResponse) {
if (sipResponse.getStatusCode() / 100 == 2 && !this.isServer()) {
ContactList contactList = sipResponse.getContactHeaders();
if (contactList != null
- && SIPRequest.isTargetRefresh(sipResponse.getCSeq()
- .getMethod())) {
- this.setRemoteTarget((ContactHeader) contactList
- .getFirst());
+ && SIPRequest.isTargetRefresh(sipResponse.getCSeq().getMethod())) {
+ this.setRemoteTarget((ContactHeader) contactList.getFirst());
}
}
- if (!this.pendingRouteUpdateOn202Response)
- return;
+ if (! this.pendingRouteUpdateOn202Response ) return;
}
// Update route list on response if I am a client dialog.
if (!isServer() || this.pendingRouteUpdateOn202Response) {
- // only update the route set if the dialog is not in the
- // confirmed state.
- if ((this.getState() != DialogState.CONFIRMED && this
- .getState() != DialogState.TERMINATED)
- || this.pendingRouteUpdateOn202Response) {
- RecordRouteList rrlist = sipResponse
- .getRecordRouteHeaders();
+ // only update the route set if the dialog is not in the confirmed state.
+ if ((this.getState() != DialogState.CONFIRMED
+ && this.getState() != DialogState.TERMINATED) ||
+ this.pendingRouteUpdateOn202Response ) {
+ RecordRouteList rrlist = sipResponse.getRecordRouteHeaders();
// Add the route set from the incoming response in reverse
// order for record route headers.
if (rrlist != null) {
@@ -1051,15 +888,13 @@ private synchronized void addRoute(SIPResponse sipResponse) {
ContactList contactList = sipResponse.getContactHeaders();
if (contactList != null) {
- this
- .setRemoteTarget((ContactHeader) contactList
- .getFirst());
+ this.setRemoteTarget((ContactHeader) contactList.getFirst());
}
}
} finally {
- if (logger.isLoggingEnabled(LogLevels.TRACE_DEBUG)) {
- logger.logStackTrace();
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
+ sipStack.getStackLogger().logStackTrace();
}
}
}
@@ -1070,8 +905,8 @@ private synchronized void addRoute(SIPResponse sipResponse) {
* @return -- a cloned copy of the dialog route list.
*/
private synchronized RouteList getRouteList() {
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG))
- logger.logDebug("getRouteList " + this);
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG))
+ sipStack.getStackLogger().logDebug("getRouteList " + this);
// Find the top via in the route list.
ListIterator li;
RouteList retval = new RouteList();
@@ -1085,81 +920,65 @@ private synchronized RouteList getRouteList() {
}
}
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- logger.logDebug("----- ");
- logger.logDebug("getRouteList for " + this);
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
+ sipStack.getStackLogger().logDebug("----- ");
+ sipStack.getStackLogger().logDebug("getRouteList for " + this);
if (retval != null)
- logger.logDebug(
- "RouteList = " + retval.encode());
+ sipStack.getStackLogger().logDebug("RouteList = " + retval.encode());
if (routeList != null)
- logger.logDebug(
- "myRouteList = " + routeList.encode());
- logger.logDebug("----- ");
+ sipStack.getStackLogger().logDebug("myRouteList = " + routeList.encode());
+ sipStack.getStackLogger().logDebug("----- ");
}
return retval;
}
-
+
void setRouteList(RouteList routeList) {
- this.routeList = routeList;
+ this.routeList = routeList;
}
/**
* Sends ACK Request to the remote party of this Dialogue.
*
*
- * @param request
- * the new ACK Request message to send.
- * @param throwIOExceptionAsSipException
- * - throws SipException if IOEx encountered. Otherwise, no
- * exception is propagated.
- * @param releaseAckSem
- * - release ack semaphore.
- * @throws SipException
- * if implementation cannot send the ACK Request for any other
- * reason
+ * @param request the new ACK Request message to send.
+ * @param throwIOExceptionAsSipException - throws SipException if IOEx encountered. Otherwise,
+ * no exception is propagated.
+ * @param releaseAckSem - release ack semaphore.
+ * @throws SipException if implementation cannot send the ACK Request for any other reason
*
*/
private void sendAck(Request request, boolean throwIOExceptionAsSipException)
throws SipException {
-
SIPRequest ackRequest = (SIPRequest) request;
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG))
- logger.logDebug("sendAck" + this);
-
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG))
+ sipStack.getStackLogger().logDebug("sendAck" + this);
+
if (!ackRequest.getMethod().equals(Request.ACK))
throw new SipException("Bad request method -- should be ACK");
- if (this.getState() == null
- || this.getState().getValue() == EARLY_STATE) {
- if (logger.isLoggingEnabled(LogWriter.TRACE_ERROR)) {
- logger.logError(
- "Bad Dialog State for " + this + " dialogID = "
- + this.getDialogId());
+ if (this.getState() == null || this.getState().getValue() == EARLY_STATE) {
+ if (sipStack.isLoggingEnabled()) {
+ sipStack.getStackLogger().logError(
+ "Bad Dialog State for " + this + " dialogID = " + this.getDialogId());
}
throw new SipException("Bad dialog state " + this.getState());
}
- if (!this.getCallId().getCallId().equals(
- ((SIPRequest) request).getCallId().getCallId())) {
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- logger
- .logError("CallID " + this.getCallId());
- logger
- .logError(
- "RequestCallID = "
- + ackRequest.getCallId().getCallId());
- logger.logError("dialog = " + this);
+ if (!this.getCallId().getCallId().equals(((SIPRequest) request).getCallId().getCallId())) {
+ if (sipStack.isLoggingEnabled()) {
+ sipStack.getStackLogger().logError("CallID " + this.getCallId());
+ sipStack.getStackLogger().logError(
+ "RequestCallID = " + ackRequest.getCallId().getCallId());
+ sipStack.getStackLogger().logError("dialog = " + this);
}
throw new SipException("Bad call ID in request");
}
try {
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- logger.logDebug(
- "setting from tag For outgoing ACK= "
- + this.getLocalTag());
- logger.logDebug(
- "setting To tag for outgoing ACK = "
- + this.getRemoteTag());
- logger.logDebug("ack = " + ackRequest);
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
+ sipStack.getStackLogger().logDebug(
+ "setting from tag For outgoing ACK= " + this.getLocalTag());
+ sipStack.getStackLogger().logDebug(
+ "setting To tag for outgoing ACK = " + this.getRemoteTag());
+ sipStack.getStackLogger().logDebug("ack = " + ackRequest);
}
if (this.getLocalTag() != null)
ackRequest.getFrom().setTag(this.getLocalTag());
@@ -1174,19 +993,18 @@ private void sendAck(Request request, boolean throwIOExceptionAsSipException)
if (hop == null)
throw new SipException("No route!");
try {
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG))
- logger.logDebug("hop = " + hop);
- ListeningPointImpl lp = (ListeningPointImpl) this.sipProvider
- .getListeningPoint(hop.getTransport());
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG))
+ sipStack.getStackLogger().logDebug("hop = " + hop);
+ ListeningPointImpl lp = (ListeningPointImpl) this.sipProvider.getListeningPoint(hop
+ .getTransport());
if (lp == null)
- throw new SipException(
- "No listening point for this provider registered at "
- + hop);
+ throw new SipException("No listening point for this provider registered at "
+ + hop);
InetAddress inetAddress = InetAddress.getByName(hop.getHost());
- MessageChannel messageChannel = lp.getMessageProcessor()
- .createMessageChannel(inetAddress, hop.getPort());
+ MessageChannel messageChannel = lp.getMessageProcessor().createMessageChannel(
+ inetAddress, hop.getPort());
boolean releaseAckSem = false;
- long cseqNo = ((SIPRequest) request).getCSeq().getSeqNumber();
+ long cseqNo = ((SIPRequest)request).getCSeq().getSeqNumber();
if (!this.isAckSent(cseqNo)) {
releaseAckSem = true;
}
@@ -1195,37 +1013,33 @@ private void sendAck(Request request, boolean throwIOExceptionAsSipException)
messageChannel.sendMessage(ackRequest);
// Sent atleast one ACK.
this.isAcknowledged = true;
- this.highestSequenceNumberAcknowledged = Math.max(
- this.highestSequenceNumberAcknowledged,
- ((SIPRequest) ackRequest).getCSeq().getSeqNumber());
+ this.highestSequenceNumberAcknowledged = Math.max(this.highestSequenceNumberAcknowledged,
+ ((SIPRequest)ackRequest).getCSeq().getSeqNumber());
if (releaseAckSem && this.isBackToBackUserAgent) {
this.releaseAckSem();
} else {
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- logger.logDebug(
- "Not releasing ack sem for " + this + " isAckSent "
- + releaseAckSem);
+ if ( sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG) ) {
+ sipStack.getStackLogger().logDebug("Not releasing ack sem for " + this + " isAckSent " + releaseAckSem );
}
}
} catch (IOException ex) {
if (throwIOExceptionAsSipException)
throw new SipException("Could not send ack", ex);
- this.raiseIOException(hop.getHost(), hop.getPort(), hop
- .getTransport());
+ this.raiseIOException(hop.getHost(), hop.getPort(), hop.getTransport());
} catch (SipException ex) {
- if (logger.isLoggingEnabled())
- logger.logException(ex);
+ if (sipStack.isLoggingEnabled())
+ sipStack.getStackLogger().logException(ex);
throw ex;
} catch (Exception ex) {
- if (logger.isLoggingEnabled())
- logger.logException(ex);
+ if (sipStack.isLoggingEnabled())
+ sipStack.getStackLogger().logException(ex);
throw new SipException("Could not create message channel", ex);
}
if (this.dialogDeleteTask != null) {
- this.getStack().getTimer().cancel(dialogDeleteTask);
+ this.dialogDeleteTask.cancel();
this.dialogDeleteTask = null;
}
-
+
}
// /////////////////////////////////////////////////////////////
@@ -1235,8 +1049,7 @@ private void sendAck(Request request, boolean throwIOExceptionAsSipException)
/**
* Set the stack address. Prevent us from routing messages to ourselves.
*
- * @param sipStack
- * the address of the SIP stack.
+ * @param sipStack the address of the SIP stack.
*
*/
void setStack(SIPTransactionStack sipStack) {
@@ -1266,37 +1079,34 @@ boolean isTerminatedOnBye() {
/**
* Mark that the dialog has seen an ACK.
*/
- void ackReceived(long cseqNumber) {
+ void ackReceived(SIPRequest sipRequest) {
+
// Suppress retransmission of the final response
if (this.isAckSeen()) {
- if (logger.isLoggingEnabled(
- LogWriter.TRACE_DEBUG))
- logger.logDebug(
- "Ack already seen for response -- dropping");
+ sipStack.getStackLogger().logDebug("Ack already seen for response -- dropping");
return;
}
SIPServerTransaction tr = this.getInviteTransaction();
if (tr != null) {
- if (tr.getCSeq() == cseqNumber) {
- acquireTimerTaskSem();
- try {
- if (this.timerTask != null) {
- this.getStack().getTimer().cancel(timerTask);
- this.timerTask = null;
- }
- } finally {
- releaseTimerTaskSem();
- }
+ if (tr.getCSeq() == sipRequest.getCSeq().getSeqNumber()) {
+ acquireTimerTaskSem();
+ try {
+ if (this.timerTask != null) {
+ this.timerTask.cancel();
+ this.timerTask = null;
+ }
+ } finally {
+ releaseTimerTaskSem();
+ }
if (this.dialogDeleteTask != null) {
- this.getStack().getTimer().cancel(dialogDeleteTask);
+ this.dialogDeleteTask.cancel();
this.dialogDeleteTask = null;
}
- lastAckReceivedCSeqNumber = Long.valueOf(cseqNumber);
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- logger.logDebug(
- "ackReceived for "
- + ((SIPTransaction) tr).getMethod());
- this.ackLine = logger.getLineCount();
+ this.setLastAckReceived(sipRequest);
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
+ sipStack.getStackLogger().logDebug(
+ "ackReceived for " + ((SIPTransaction) tr).getMethod());
+ this.ackLine = sipStack.getStackLogger().getLineCount();
this.printDebugInfo();
}
if (this.isBackToBackUserAgent) {
@@ -1305,16 +1115,13 @@ void ackReceived(long cseqNumber) {
this.setState(CONFIRMED_STATE);
}
} else {
- if (logger.isLoggingEnabled(
- LogWriter.TRACE_DEBUG))
- logger.logDebug(
- "tr is null -- not updating the ack state");
+ sipStack.getStackLogger().logDebug("tr is null -- not updating the ack state" );
}
}
/**
- * Return true if a terminated event was delivered to the application as a
- * result of the dialog termination.
+ * Return true if a terminated event was delivered to the application as a result of the
+ * dialog termination.
*
*/
synchronized boolean testAndSetIsDialogTerminatedEventDelivered() {
@@ -1328,25 +1135,25 @@ synchronized boolean testAndSetIsDialogTerminatedEventDelivered() {
// /////////////////////////////////////////////////////////
/**
- * Adds a new event listener to this dialog.
- *
- * @param newListener
- * Listener to add.
- */
- public void addEventListener(SIPDialogEventListener newListener) {
- eventListeners.add(newListener);
- }
-
- /**
- * Removed an event listener from this dialog.
- *
- * @param oldListener
- * Listener to remove.
- */
- public void removeEventListener(SIPDialogEventListener oldListener) {
- eventListeners.remove(oldListener);
- }
-
+ * Adds a new event listener to this dialog.
+ *
+ * @param newListener
+ * Listener to add.
+ */
+ public void addEventListener(SIPDialogEventListener newListener) {
+ eventListeners.add(newListener);
+ }
+
+ /**
+ * Removed an event listener from this dialog.
+ *
+ * @param oldListener
+ * Listener to remove.
+ */
+ public void removeEventListener(SIPDialogEventListener oldListener) {
+ eventListeners.remove(oldListener);
+ }
+
/*
* @see javax.sip.Dialog#setApplicationData()
*/
@@ -1368,12 +1175,11 @@ public Object getApplicationData() {
*
*/
public synchronized void requestConsumed() {
- this.nextSeqno = this.getRemoteSeqNumber() + 1;
+ this.nextSeqno = Long.valueOf(this.getRemoteSeqNumber() + 1);
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- this.logger.logDebug(
- "Request Consumed -- next consumable Request Seqno = "
- + this.nextSeqno);
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
+ this.sipStack.getStackLogger().logDebug(
+ "Request Consumed -- next consumable Request Seqno = " + this.nextSeqno);
}
}
@@ -1381,10 +1187,8 @@ public synchronized void requestConsumed() {
/**
* Return true if this request can be consumed by the dialog.
*
- * @param dialogRequest
- * is the request to check with the dialog.
- * @return true if the dialogRequest sequence number matches the next
- * consumable seqno.
+ * @param dialogRequest is the request to check with the dialog.
+ * @return true if the dialogRequest sequence number matches the next consumable seqno.
*/
public synchronized boolean isRequestConsumable(SIPRequest dialogRequest) {
// have not yet set remote seqno - this is a fresh
@@ -1402,9 +1206,9 @@ public synchronized boolean isRequestConsumable(SIPRequest dialogRequest) {
}
/**
- * This method is called when a forked dialog is created from the client
- * side. It starts a timer task. If the timer task expires before an ACK is
- * sent then the dialog is cancelled (i.e. garbage collected ).
+ * This method is called when a forked dialog is created from the client side. It starts a
+ * timer task. If the timer task expires before an ACK is sent then the dialog is cancelled
+ * (i.e. garbage collected ).
*
*/
public void doDeferredDelete() {
@@ -1413,14 +1217,8 @@ public void doDeferredDelete() {
else {
this.dialogDeleteTask = new DialogDeleteTask();
// Delete the transaction after the max ack timeout.
- if (sipStack.getTimer() != null && sipStack.getTimer().isStarted()) {
- sipStack.getTimer().schedule(
- this.dialogDeleteTask,
- SIPTransaction.TIMER_H
- * SIPTransactionStack.BASE_TIMER_INTERVAL);
- } else {
- this.delete();
- }
+ sipStack.getTimer().schedule(this.dialogDeleteTask,
+ SIPTransaction.TIMER_H * SIPTransactionStack.BASE_TIMER_INTERVAL);
}
}
@@ -1428,36 +1226,28 @@ public void doDeferredDelete() {
/**
* Set the state for this dialog.
*
- * @param state
- * is the state to set for the dialog.
+ * @param state is the state to set for the dialog.
*/
public void setState(int state) {
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- logger.logDebug(
- "SIPDialog::setState:Setting dialog state for " + this + "newState = " + state);
- logger.logStackTrace();
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
+ sipStack.getStackLogger().logDebug(
+ "Setting dialog state for " + this + "newState = " + state);
+ sipStack.getStackLogger().logStackTrace();
if (state != NULL_STATE && state != this.dialogState)
- if (logger.isLoggingEnabled()) {
- logger.logDebug("SIPDialog::setState:" +
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
+ sipStack.getStackLogger().logDebug(
this + " old dialog state is " + this.getState());
- logger.logDebug("SIPDialog::setState:" +
- this + " New dialog state is "
- + DialogState.getObject(state));
+ sipStack.getStackLogger().logDebug(
+ this + " New dialog state is " + DialogState.getObject(state));
}
}
- if ( state == EARLY_STATE ) {
- this.addEventListener(this.getSipProvider());
- }
-
this.dialogState = state;
// Dialog is in terminated state set it up for GC.
if (state == TERMINATED_STATE) {
- this.removeEventListener(this.getSipProvider());
- if (sipStack.getTimer() != null && sipStack.getTimer().isStarted() ) { // may be null after shutdown
- sipStack.getTimer().schedule(new LingerTimer(),
- DIALOG_LINGER_TIME * 1000);
+ if (sipStack.getTimer() != null) { // may be null after shutdown
+ sipStack.getTimer().schedule(new LingerTimer(), DIALOG_LINGER_TIME * 1000);
}
this.stopTimer();
@@ -1468,16 +1258,13 @@ public void setState(int state) {
* Debugging print for the dialog.
*/
public void printDebugInfo() {
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- logger.logDebug("isServer = " + isServer());
- logger.logDebug("localTag = " + getLocalTag());
- logger.logDebug("remoteTag = " + getRemoteTag());
- logger.logDebug(
- "localSequenceNumer = " + getLocalSeqNumber());
- logger.logDebug(
- "remoteSequenceNumer = " + getRemoteSeqNumber());
- logger.logDebug(
- "ackLine:" + this.getRemoteTag() + " " + ackLine);
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
+ sipStack.getStackLogger().logDebug("isServer = " + isServer());
+ sipStack.getStackLogger().logDebug("localTag = " + getLocalTag());
+ sipStack.getStackLogger().logDebug("remoteTag = " + getRemoteTag());
+ sipStack.getStackLogger().logDebug("localSequenceNumer = " + getLocalSeqNumber());
+ sipStack.getStackLogger().logDebug("remoteSequenceNumer = " + getRemoteSeqNumber());
+ sipStack.getStackLogger().logDebug("ackLine:" + this.getRemoteTag() + " " + ackLine);
}
}
@@ -1487,37 +1274,27 @@ public void printDebugInfo() {
* @return flag that records if the ack has been seen.
*/
public boolean isAckSeen() {
-
- if (lastAckReceivedCSeqNumber == null
- && lastResponseStatusCode == Response.OK) {
- if (logger.isLoggingEnabled(
- LogWriter.TRACE_DEBUG)) {
- logger.logDebug(
- this + "lastAckReceived is null -- returning false");
- }
- return false;
- } else if (lastResponseMethod == null) {
- if (logger.isLoggingEnabled(
- LogWriter.TRACE_DEBUG)) {
- logger.logDebug(
- this + "lastResponse is null -- returning false");
- }
- return false;
- } else if (lastAckReceivedCSeqNumber == null
- && lastResponseStatusCode / 100 > 2) {
- if (logger.isLoggingEnabled(
- LogWriter.TRACE_DEBUG)) {
- logger.logDebug(
- this + "lastResponse statusCode "
- + lastResponseStatusCode);
- }
- return true;
- } else {
-
- return this.lastAckReceivedCSeqNumber != null
- && this.lastAckReceivedCSeqNumber >= this
- .getRemoteSeqNumber();
- }
+
+ if (lastAckReceived == null && lastResponse.getStatusCode() == Response.OK ) {
+ if ( sipStack.getStackLogger().isLoggingEnabled(LogWriter.TRACE_DEBUG) ) {
+ sipStack.getStackLogger().logDebug(this + "lastAckReceived is null -- returning false");
+ }
+ return false;
+ } else if (lastResponse == null ) {
+ if ( sipStack.getStackLogger().isLoggingEnabled(LogWriter.TRACE_DEBUG) ) {
+ sipStack.getStackLogger().logDebug(this + "lastResponse is null -- returning false");
+ }
+ return false;
+ } else if ( lastAckReceived == null && lastResponse.getStatusCode() / 100 > 2 ) {
+ if ( sipStack.getStackLogger().isLoggingEnabled(LogWriter.TRACE_DEBUG) ) {
+ sipStack.getStackLogger().logDebug(this + "lastResponse statusCode " + lastResponse.getStatusCode());
+ }
+ return true;
+ } else {
+
+ return this.lastAckReceived != null &&
+ this.lastAckReceived.getCSeq().getSeqNumber() >= this.getRemoteSeqNumber();
+ }
}
/**
@@ -1528,8 +1305,8 @@ public SIPRequest getLastAckSent() {
}
/**
- * Return true if ACK was sent ( for client tx ). For server tx, this is a
- * NO-OP ( we dont send ACK).
+ * Return true if ACK was sent ( for client tx ). For server tx, this is a NO-OP ( we dont
+ * send ACK).
*/
public boolean isAckSent(long cseqNo) {
if (this.getLastTransaction() == null)
@@ -1538,55 +1315,39 @@ public boolean isAckSent(long cseqNo) {
if (this.getLastAckSent() == null) {
return false;
} else {
- return cseqNo <= ((SIPRequest) this.getLastAckSent()).getCSeq()
- .getSeqNumber();
+ return cseqNo <=((SIPRequest) this.getLastAckSent()).getCSeq().getSeqNumber();
}
} else {
return true;
}
}
- @Deprecated
- public Transaction getFirstTransaction() {
- throw new UnsupportedOperationException(
- "This method has been deprecated and is no longer supported");
- }
-
/**
- * This is for internal use only.
- *
+ * Get the transaction that created this dialog.
*/
- public Transaction getFirstTransactionInt() {
- // jeand : we try to avoid keeping the ref around for too long to help
- // the GC
- if (firstTransaction != null) {
- return firstTransaction;
- }
- return this.sipStack.findTransaction(firstTransactionId,
- firstTransactionIsServerTransaction);
+ public Transaction getFirstTransaction() {
+ return this.firstTransaction;
}
+
/**
- * Gets the route set for the dialog. When acting as an User Agent Server
- * the route set MUST be set to the list of URIs in the Record-Route header
- * field from the request, taken in order and preserving all URI parameters.
- * When acting as an User Agent Client the route set MUST be set to the list
- * of URIs in the Record-Route header field from the response, taken in
- * reverse order and preserving all URI parameters. If no Record-Route
- * header field is present in the request or response, the route set MUST be
- * set to the empty set. This route set, even if empty, overrides any
- * pre-existing route set for future requests in this dialog.
+ * Gets the route set for the dialog. When acting as an User Agent Server the route set MUST
+ * be set to the list of URIs in the Record-Route header field from the request, taken in
+ * order and preserving all URI parameters. When acting as an User Agent Client the route set
+ * MUST be set to the list of URIs in the Record-Route header field from the response, taken
+ * in reverse order and preserving all URI parameters. If no Record-Route header field is
+ * present in the request or response, the route set MUST be set to the empty set. This route
+ * set, even if empty, overrides any pre-existing route set for future requests in this
+ * dialog.
*
- * Requests within a dialog MAY contain Record-Route and Contact header
- * fields. However, these requests do not cause the dialog's route set to be
- * modified.
+ * Requests within a dialog MAY contain Record-Route and Contact header fields. However, these
+ * requests do not cause the dialog's route set to be modified.
*
- * The User Agent Client uses the remote target and route set to build the
- * Request-URI and Route header field of the request.
+ * The User Agent Client uses the remote target and route set to build the Request-URI and
+ * Route header field of the request.
*
- * @return an Iterator containing a list of route headers to be used for
- * forwarding. Empty iterator is returned if route has not been
- * established.
+ * @return an Iterator containing a list of route headers to be used for forwarding. Empty
+ * iterator is returned if route has not been established.
*/
public Iterator getRouteSet() {
if (this.routeList == null) {
@@ -1602,25 +1363,22 @@ public Iterator getRouteSet() {
* @param sipRequest
*/
public synchronized void addRoute(SIPRequest sipRequest) {
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- logger.logDebug(
- "setContact: dialogState: " + this + "state = "
- + this.getState());
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
+ sipStack.getStackLogger().logDebug(
+ "setContact: dialogState: " + this + "state = " + this.getState());
}
if (this.dialogState == CONFIRMED_STATE
&& SIPRequest.isTargetRefresh(sipRequest.getMethod())) {
this.doTargetRefresh(sipRequest);
}
- if (this.dialogState == CONFIRMED_STATE
- || this.dialogState == TERMINATED_STATE) {
+ if (this.dialogState == CONFIRMED_STATE || this.dialogState == TERMINATED_STATE) {
return;
}
-
+
// Fix for issue #225: mustn't learn Route set from mid-dialog requests
- if (sipRequest.getToTag() != null)
- return;
-
+ if ( sipRequest.getToTag()!=null ) return;
+
// Incoming Request has the route list
RecordRouteList rrlist = sipRequest.getRecordRouteHeaders();
// Add the route set from the incoming response in reverse
@@ -1644,25 +1402,19 @@ public synchronized void addRoute(SIPRequest sipRequest) {
* Set the dialog identifier.
*/
public void setDialogId(String dialogId) {
- if (firstTransaction != null) {
- firstTransaction.setDialog(this, dialogId);
- }
this.dialogId = dialogId;
}
/**
- * Creates a new dialog based on a received NOTIFY. The dialog state is
- * initialized appropriately. The NOTIFY differs in the From tag
+ * Creates a new dialog based on a received NOTIFY. The dialog state is initialized
+ * appropriately. The NOTIFY differs in the From tag
*
- * Made this a separate method to clearly distinguish what's happening here
- * - this is a non-trivial case
+ * Made this a separate method to clearly distinguish what's happening here - this is a
+ * non-trivial case
*
- * @param subscribeTx
- * - the transaction started with the SUBSCRIBE that we sent
- * @param notifyST
- * - the ServerTransaction created for an incoming NOTIFY
- * @return -- a new dialog created from the subscribe original SUBSCRIBE
- * transaction.
+ * @param subscribeTx - the transaction started with the SUBSCRIBE that we sent
+ * @param notifyST - the ServerTransaction created for an incoming NOTIFY
+ * @return -- a new dialog created from the subscribe original SUBSCRIBE transaction.
*
*
*/
@@ -1728,99 +1480,71 @@ protected boolean isReInvite() {
*/
public String getDialogId() {
- if (this.dialogId == null && this.lastResponseDialogId != null)
- this.dialogId = this.lastResponseDialogId;
+ if (this.dialogId == null && this.lastResponse != null)
+ this.dialogId = this.lastResponse.getDialogId(isServer());
return this.dialogId;
}
- protected void storeFirstTransactionInfo(SIPDialog dialog,
- SIPTransaction transaction) {
-
- dialog.firstTransactionSeen = true;
- dialog.firstTransaction = transaction;
- dialog.firstTransactionIsServerTransaction = transaction
- .isServerTransaction();
- if (dialog.firstTransactionIsServerTransaction) {
- dialog.firstTransactionSecure = transaction.getRequest()
- .getRequestURI().getScheme().equalsIgnoreCase("sips");
- } else {
- dialog.firstTransactionSecure = ((SIPClientTransaction) transaction)
- .getOriginalRequestScheme().equalsIgnoreCase("sips");
- }
- dialog.firstTransactionPort = transaction.getPort();
- dialog.firstTransactionId = transaction.getBranchId();
- dialog.firstTransactionMethod = transaction.getMethod();
- if (transaction instanceof SIPServerTransaction
- && dialog.firstTransactionMethod.equals(Request.INVITE)) {
- sipStack.removeMergeDialog(firstTransactionMergeId);
+ protected void storeFirstTransactionInfo(SIPDialog dialog, SIPTransaction transaction) {
+ dialog.firstTransaction = transaction;
+ dialog.firstTransactionSeen = true;
+ dialog.firstTransactionIsServerTransaction = transaction.isServerTransaction();
+ dialog.firstTransactionSecure = transaction.getRequest().getRequestURI().getScheme()
+ .equalsIgnoreCase("sips");
+ dialog.firstTransactionPort = transaction.getPort();
+ dialog.firstTransactionId = transaction.getBranchId();
+ dialog.firstTransactionMethod = transaction.getMethod();
+ if ( transaction instanceof SIPServerTransaction && dialog.firstTransactionMethod.equals(Request.INVITE) ) {
+ sipStack.removeMergeDialog(firstTransactionMergeId);
dialog.firstTransactionMergeId = ((SIPRequest) transaction.getRequest()).getMergeId();
- sipStack.putMergeDialog(this);
- }
-
- if (transaction.isServerTransaction()) {
+ sipStack.putMergeDialog(this);
+ }
+
+ if (dialog.isServer()) {
SIPServerTransaction st = (SIPServerTransaction) transaction;
SIPResponse response = st.getLastResponse();
- dialog.contactHeader = response != null ? response
- .getContactHeader() : null;
+ dialog.contactHeader = response != null ? response.getContactHeader() : null;
} else {
SIPClientTransaction ct = (SIPClientTransaction) transaction;
- if (ct != null) {
- dialog.contactHeader = ct.getOriginalRequestContact();
+ if (ct != null){
+ SIPRequest sipRequest = ct.getOriginalRequest();
+ dialog.contactHeader = sipRequest.getContactHeader();
}
}
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- logger.logDebug("firstTransaction = " + dialog.firstTransaction);
- logger.logDebug("firstTransactionIsServerTransaction = " + firstTransactionIsServerTransaction);
- logger.logDebug("firstTransactionSecure = " + firstTransactionSecure);
- logger.logDebug("firstTransactionPort = " + firstTransactionPort);
- logger.logDebug("firstTransactionId = " + firstTransactionId);
- logger.logDebug("firstTransactionMethod = " + firstTransactionMethod);
- logger.logDebug("firstTransactionMergeId = " + firstTransactionMergeId);
- }
}
-
/**
* Add a transaction record to the dialog.
*
- * @param transaction
- * is the transaction to add to the dialog.
+ * @param transaction is the transaction to add to the dialog.
*/
- public boolean addTransaction(SIPTransaction transaction) {
+ public boolean addTransaction(SIPTransaction transaction) {
SIPRequest sipRequest = (SIPRequest) transaction.getOriginalRequest();
// Proessing a re-invite.
- if (firstTransactionSeen
- && !firstTransactionId.equals(transaction.getBranchId())
+ if (firstTransactionSeen && !firstTransactionId.equals(transaction.getBranchId())
&& transaction.getMethod().equals(firstTransactionMethod)) {
setReInviteFlag(true);
}
-
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- logger.logDebug(
- "SipDialog.addTransaction() " + this + " transaction = "
- + transaction);
+
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
+ sipStack.getStackLogger().logDebug("SipDialog.addTransaction() " + this + " transaction = " + transaction);
}
if (firstTransactionSeen == false) {
// Record the local and remote sequenc
// numbers and the from and to tags for future
// use on this dialog.
- storeFirstTransactionInfo(this, transaction);
+ storeFirstTransactionInfo(this, transaction);
if (sipRequest.getMethod().equals(Request.SUBSCRIBE))
- this.eventHeader = (EventHeader) sipRequest
- .getHeader(EventHeader.NAME);
+ this.eventHeader = (EventHeader) sipRequest.getHeader(EventHeader.NAME);
this.setLocalParty(sipRequest);
this.setRemoteParty(sipRequest);
this.setCallId(sipRequest);
- if (this.originalRequest == null
- && transaction.isInviteTransaction()) {
+ if (this.originalRequest == null) {
this.originalRequest = sipRequest;
- } else if (originalRequest != null) {
- originalRequestRecordRouteHeaders = sipRequest
- .getRecordRouteHeaders();
}
if (this.method == null) {
this.method = sipRequest.getMethod();
@@ -1834,35 +1558,24 @@ public boolean addTransaction(SIPTransaction transaction) {
this.originalLocalSequenceNumber = localSequenceNumber;
this.setLocalTag(sipRequest.getFrom().getTag());
if (myTag == null)
- if (logger.isLoggingEnabled())
- logger
- .logError(
- "The request's From header is missing the required Tag parameter.");
+ if (sipStack.isLoggingEnabled())
+ sipStack.getStackLogger().logError(
+ "The request's From header is missing the required Tag parameter.");
}
} else if (transaction.getMethod().equals(firstTransactionMethod)
- && firstTransactionIsServerTransaction != transaction
- .isServerTransaction()) {
+ && firstTransactionIsServerTransaction != transaction.isServerTransaction()) {
// This case occurs when you are processing a re-invite.
// Switch from client side to server side for re-invite
// (put the other side on hold).
-
- storeFirstTransactionInfo(this, transaction);
-
+
+ storeFirstTransactionInfo(this, transaction);
+
this.setLocalParty(sipRequest);
this.setRemoteParty(sipRequest);
this.setCallId(sipRequest);
- if (transaction.isInviteTransaction()) {
- this.originalRequest = sipRequest;
- } else {
- originalRequestRecordRouteHeaders = sipRequest
- .getRecordRouteHeaders();
- }
+ this.originalRequest = sipRequest;
this.method = sipRequest.getMethod();
- } else if (firstTransaction == null
- && transaction.isInviteTransaction()) {
- // jeand needed for reinvite reliable processing
- firstTransaction = transaction;
}
if (transaction instanceof SIPServerTransaction) {
setRemoteSequenceNumber(sipRequest.getCSeq().getSeqNumber());
@@ -1872,25 +1585,22 @@ public boolean addTransaction(SIPTransaction transaction) {
// sequence number to avoid re-processing of requests
// with the same sequence number directed towards this
// dialog.
-
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- logger.logDebug(
- "isBackToBackUserAgent = " + this.isBackToBackUserAgent);
- }
- if (transaction.isInviteTransaction()) {
- if ( logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- logger.logDebug("SIPDialog::setLastTransaction:dialog= " + SIPDialog.this + " lastTransaction = " + transaction);
- }
- this.lastTransaction = transaction;
+
+ if ( sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG) ) {
+ sipStack.getStackLogger().logDebug("isBackToBackUserAgent = " + this.isBackToBackUserAgent );
}
-
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- logger.logDebug(
- "Transaction Added " + this + myTag + "/" + hisTag);
- logger.logDebug(
+
+
+
+ this.lastTransaction = transaction;
+
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
+ sipStack.getStackLogger()
+ .logDebug("Transaction Added " + this + myTag + "/" + hisTag);
+ sipStack.getStackLogger().logDebug(
"TID = " + transaction.getTransactionId() + "/"
+ transaction.isServerTransaction());
- logger.logStackTrace();
+ sipStack.getStackLogger().logStackTrace();
}
return true;
}
@@ -1898,31 +1608,26 @@ public boolean addTransaction(SIPTransaction transaction) {
/**
* Set the remote tag.
*
- * @param hisTag
- * is the remote tag to set.
+ * @param hisTag is the remote tag to set.
*/
- protected void setRemoteTag(String hisTag) {
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- logger.logDebug(
- "setRemoteTag(): " + this + " remoteTag = " + this.hisTag
- + " new tag = " + hisTag);
+ private void setRemoteTag(String hisTag) {
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
+ sipStack.getStackLogger().logDebug(
+ "setRemoteTag(): " + this + " remoteTag = " + this.hisTag + " new tag = "
+ + hisTag);
}
- if (this.hisTag != null && hisTag != null
- && !hisTag.equals(this.hisTag)) {
+ if (this.hisTag != null && hisTag != null && !hisTag.equals(this.hisTag)) {
if (this.getState() != DialogState.EARLY) {
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG))
- logger
- .logDebug(
- "Dialog is already established -- ignoring remote tag re-assignment");
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG))
+ sipStack.getStackLogger().logDebug(
+ "Dialog is already established -- ignoring remote tag re-assignment");
return;
} else if (sipStack.isRemoteTagReassignmentAllowed()) {
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG))
- logger
- .logDebug(
- "UNSAFE OPERATION ! tag re-assignment "
- + this.hisTag
- + " trying to set to " + hisTag
- + " can cause unexpected effects ");
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG))
+ sipStack.getStackLogger().logDebug(
+ "UNSAFE OPERATION ! tag re-assignment " + this.hisTag
+ + " trying to set to " + hisTag
+ + " can cause unexpected effects ");
boolean removed = false;
if (this.sipStack.getDialog(dialogId) == this) {
this.sipStack.removeDialog(dialogId);
@@ -1933,9 +1638,8 @@ protected void setRemoteTag(String hisTag) {
this.dialogId = null;
this.hisTag = hisTag;
if (removed) {
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG))
- logger
- .logDebug("ReInserting Dialog");
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG))
+ sipStack.getStackLogger().logDebug("ReInserting Dialog");
this.sipStack.putDialog(this);
}
}
@@ -1943,9 +1647,8 @@ protected void setRemoteTag(String hisTag) {
if (hisTag != null) {
this.hisTag = hisTag;
} else {
- if (logger.isLoggingEnabled())
- logger.logWarning(
- "setRemoteTag : called with null argument ");
+ if (sipStack.isLoggingEnabled())
+ sipStack.getStackLogger().logWarning("setRemoteTag : called with null argument ");
}
}
}
@@ -1969,18 +1672,16 @@ public SIPServerTransaction getInviteTransaction() {
}
/**
- * Set the local sequece number for the dialog (defaults to 1 when the
- * dialog is created).
+ * Set the local sequece number for the dialog (defaults to 1 when the dialog is created).
*
- * @param lCseq
- * is the local cseq number.
+ * @param lCseq is the local cseq number.
*
*/
private void setLocalSequenceNumber(long lCseq) {
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG))
- logger.logDebug(
- "setLocalSequenceNumber: original "
- + this.localSequenceNumber + " new = " + lCseq);
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG))
+ sipStack.getStackLogger().logDebug(
+ "setLocalSequenceNumber: original " + this.localSequenceNumber + " new = "
+ + lCseq);
if (lCseq <= this.localSequenceNumber)
throw new RuntimeException("Sequence number should not decrease !");
this.localSequenceNumber = lCseq;
@@ -1989,29 +1690,27 @@ private void setLocalSequenceNumber(long lCseq) {
/**
* Set the remote sequence number for the dialog.
*
- * @param rCseq
- * is the remote cseq number.
+ * @param rCseq is the remote cseq number.
*
*/
public void setRemoteSequenceNumber(long rCseq) {
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG))
- logger.logDebug(
- "setRemoteSeqno " + this + "/" + rCseq);
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG))
+ sipStack.getStackLogger().logDebug("setRemoteSeqno " + this + "/" + rCseq);
this.remoteSequenceNumber = rCseq;
}
/**
- * Increment the local CSeq # for the dialog. This is useful for if you want
- * to create a hole in the sequence number i.e. route a request outside the
- * dialog and then resume within the dialog.
+ * Increment the local CSeq # for the dialog. This is useful for if you want to create a hole
+ * in the sequence number i.e. route a request outside the dialog and then resume within the
+ * dialog.
*/
public void incrementLocalSequenceNumber() {
++this.localSequenceNumber;
}
/**
- * Get the remote sequence number (for cseq assignment of outgoing requests
- * within this dialog).
+ * Get the remote sequence number (for cseq assignment of outgoing requests within this
+ * dialog).
*
* @deprecated
* @return local sequence number.
@@ -2022,8 +1721,8 @@ public int getRemoteSequenceNumber() {
}
/**
- * Get the local sequence number (for cseq assignment of outgoing requests
- * within this dialog).
+ * Get the local sequence number (for cseq assignment of outgoing requests within this
+ * dialog).
*
* @deprecated
* @return local sequence number.
@@ -2034,8 +1733,7 @@ public int getLocalSequenceNumber() {
}
/**
- * Get the sequence number for the request that origianlly created the
- * Dialog.
+ * Get the sequence number for the request that origianlly created the Dialog.
*
* @return -- the original starting sequence number for this dialog.
*/
@@ -2083,16 +1781,14 @@ public String getRemoteTag() {
/**
* Set local tag for the transaction.
*
- * @param mytag
- * is the tag to use in From headers client transactions that
- * belong to this dialog and for generating To tags for Server
- * transaction requests that belong to this dialog.
+ * @param mytag is the tag to use in From headers client transactions that belong to this
+ * dialog and for generating To tags for Server transaction requests that belong to
+ * this dialog.
*/
- protected void setLocalTag(String mytag) {
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- logger.logDebug(
- "set Local tag " + mytag + " dialog = " + this);
- logger.logStackTrace();
+ private void setLocalTag(String mytag) {
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
+ sipStack.getStackLogger().logDebug("set Local tag " + mytag + " dialog = " + this );
+ sipStack.getStackLogger().logStackTrace();
}
this.myTag = mytag;
@@ -2116,17 +1812,6 @@ public void delete() {
* @see javax.sip.Dialog#getCallId()
*/
public CallIdHeader getCallId() {
- // jeand : we save the header in a string form and reparse it, help GC
- // for dialogs updated not too often
- if (callIdHeader == null && callIdHeaderString != null) {
- try {
- this.callIdHeader = (CallIdHeader) new CallIDParser(
- callIdHeaderString).parse();
- } catch (ParseException e) {
- logger.logError(
- "error reparsing the call id header", e);
- }
- }
return this.callIdHeader;
}
@@ -2144,21 +1829,10 @@ private void setCallId(SIPRequest sipRequest) {
*/
public javax.sip.address.Address getLocalParty() {
- // jeand : we save the address in a string form and reparse it, help GC
- // for dialogs updated not too often
- if (localParty == null && localPartyStringified != null) {
- try {
- this.localParty = (Address) new AddressParser(
- localPartyStringified).address(true);
- } catch (ParseException e) {
- logger.logError(
- "error reparsing the localParty", e);
- }
- }
return this.localParty;
}
- protected void setLocalParty(SIPMessage sipMessage) {
+ private void setLocalParty(SIPMessage sipMessage) {
if (!isServer()) {
this.localParty = sipMessage.getFrom().getAddress();
} else {
@@ -2167,30 +1841,18 @@ protected void setLocalParty(SIPMessage sipMessage) {
}
/**
- * Returns the Address identifying the remote party. This is the value of
- * the To header of locally initiated requests in this dialogue when acting
- * as an User Agent Client.
+ * Returns the Address identifying the remote party. This is the value of the To header of
+ * locally initiated requests in this dialogue when acting as an User Agent Client.
*
- * This is the value of the From header of recieved responses in this
- * dialogue when acting as an User Agent Server.
+ * This is the value of the From header of recieved responses in this dialogue when acting as
+ * an User Agent Server.
*
* @return the address object of the remote party.
*/
public javax.sip.address.Address getRemoteParty() {
- // jeand : we save the address in a string form and reparse it, help GC
- // for dialogs updated not too often
- if (remoteParty == null && remotePartyStringified != null) {
- try {
- this.remoteParty = (Address) new AddressParser(
- remotePartyStringified).address(true);
- } catch (ParseException e) {
- logger.logError(
- "error reparsing the remoteParty", e);
- }
- }
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- logger.logDebug(
- "gettingRemoteParty " + this.remoteParty);
+
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
+ sipStack.getStackLogger().logDebug("gettingRemoteParty " + this.remoteParty);
}
return this.remoteParty;
@@ -2202,17 +1864,7 @@ public javax.sip.address.Address getRemoteParty() {
* @see javax.sip.Dialog#getRemoteTarget()
*/
public javax.sip.address.Address getRemoteTarget() {
- // jeand : we save the address in a string form and reparse it, help GC
- // for dialogs updated not too often
- if (remoteTarget == null && remoteTargetStringified != null) {
- try {
- this.remoteTarget = (Address) new AddressParser(
- remoteTargetStringified).address(true);
- } catch (ParseException e) {
- logger.logError(
- "error reparsing the remoteTarget", e);
- }
- }
+
return this.remoteTarget;
}
@@ -2228,12 +1880,11 @@ public DialogState getState() {
}
/**
- * Returns true if this Dialog is secure i.e. if the request arrived over
- * TLS, and the Request-URI contained a SIPS URI, the "secure" flag is set
- * to TRUE.
+ * Returns true if this Dialog is secure i.e. if the request arrived over TLS, and the
+ * Request-URI contained a SIPS URI, the "secure" flag is set to TRUE.
*
- * @return true
if this dialogue was established using a sips
- * URI over TLS, and false
otherwise.
+ * @return true
if this dialogue was established using a sips URI over TLS, and
+ * false
otherwise.
*/
public boolean isSecure() {
return this.firstTransactionSecure;
@@ -2256,12 +1907,10 @@ public void sendAck(Request request) throws SipException {
public Request createRequest(String method) throws SipException {
if (method.equals(Request.ACK) || method.equals(Request.PRACK)) {
- throw new SipException(
- "Invalid method specified for createRequest:" + method);
+ throw new SipException("Invalid method specified for createRequest:" + method);
}
- if (lastResponseTopMostVia != null)
- return this.createRequest(method, this.lastResponseTopMostVia
- .getTransport());
+ if (lastResponse != null)
+ return this.createRequest(method, this.lastResponse);
else
throw new SipException("Dialog not yet established -- no response!");
}
@@ -2274,18 +1923,16 @@ public Request createRequest(String method) throws SipException {
* @return
* @throws SipException
*/
- private SIPRequest createRequest(String method, String topMostViaTransport)
- throws SipException {
+ private Request createRequest(String method, SIPResponse sipResponse) throws SipException {
/*
- * Check if the dialog is in the right state (RFC 3261 section 15). The
- * caller's UA MAY send a BYE for either CONFIRMED or EARLY dialogs, and
- * the callee's UA MAY send a BYE on CONFIRMED dialogs, but MUST NOT
- * send a BYE on EARLY dialogs.
+ * Check if the dialog is in the right state (RFC 3261 section 15). The caller's UA MAY
+ * send a BYE for either CONFIRMED or EARLY dialogs, and the callee's UA MAY send a BYE on
+ * CONFIRMED dialogs, but MUST NOT send a BYE on EARLY dialogs.
*
* Throw out cancel request.
*/
- if (method == null || topMostViaTransport == null)
+ if (method == null || sipResponse == null)
throw new NullPointerException("null argument");
if (method.equals(Request.CANCEL))
@@ -2294,8 +1941,7 @@ private SIPRequest createRequest(String method, String topMostViaTransport)
if (this.getState() == null
|| (this.getState().getValue() == TERMINATED_STATE && !method
.equalsIgnoreCase(Request.BYE))
- || (this.isServer()
- && this.getState().getValue() == EARLY_STATE && method
+ || (this.isServer() && this.getState().getValue() == EARLY_STATE && method
.equalsIgnoreCase(Request.BYE)))
throw new SipException("Dialog " + getDialogId()
+ " not yet established or terminated " + this.getState());
@@ -2313,55 +1959,52 @@ private SIPRequest createRequest(String method, String topMostViaTransport)
cseq.setMethod(method);
cseq.setSeqNumber(this.getLocalSeqNumber());
} catch (Exception ex) {
- if (logger.isLoggingEnabled())
- logger.logError("Unexpected error");
+ if (sipStack.isLoggingEnabled())
+ sipStack.getStackLogger().logError("Unexpected error");
InternalErrorHandler.handleException(ex);
}
/*
- * Add a via header for the outbound request based on the transport of
- * the message processor.
+ * Add a via header for the outbound request based on the transport of the message
+ * processor.
*/
ListeningPointImpl lp = (ListeningPointImpl) this.sipProvider
- .getListeningPoint(topMostViaTransport);
+ .getListeningPoint(sipResponse.getTopmostVia().getTransport());
if (lp == null) {
- if (logger.isLoggingEnabled())
- logger.logError(
+ if (sipStack.isLoggingEnabled())
+ sipStack.getStackLogger().logError(
"Cannot find listening point for transport "
- + topMostViaTransport);
+ + sipResponse.getTopmostVia().getTransport());
throw new SipException("Cannot find listening point for transport "
- + topMostViaTransport);
+ + sipResponse.getTopmostVia().getTransport());
}
Via via = lp.getViaHeader();
From from = new From();
- from.setAddress(this.getLocalParty());
+ from.setAddress(this.localParty);
To to = new To();
- to.setAddress(this.getRemoteParty());
- SIPRequest sipRequest = createRequest(sipUri, via, cseq, from, to);
+ to.setAddress(this.remoteParty);
+ SIPRequest sipRequest = sipResponse.createRequest(sipUri, via, cseq, from, to);
/*
- * The default contact header is obtained from the provider. The
- * application can override this.
+ * The default contact header is obtained from the provider. The application can override
+ * this.
*
- * JvB: Should only do this for target refresh requests, ie not for BYE,
- * PRACK, etc
+ * JvB: Should only do this for target refresh requests, ie not for BYE, PRACK, etc
*/
if (SIPRequest.isTargetRefresh(method)) {
ContactHeader contactHeader = ((ListeningPointImpl) this.sipProvider
- .getListeningPoint(lp.getTransport()))
- .createContactHeader();
+ .getListeningPoint(lp.getTransport())).createContactHeader();
- ((SipURI) contactHeader.getAddress().getURI()).setSecure(this
- .isSecure());
+ ((SipURI) contactHeader.getAddress().getURI()).setSecure(this.isSecure());
sipRequest.setHeader(contactHeader);
}
try {
/*
- * Guess of local sequence number - this is being re-set when the
- * request is actually dispatched
+ * Guess of local sequence number - this is being re-set when the request is actually
+ * dispatched
*/
cseq = (CSeq) sipRequest.getCSeq();
cseq.setSeqNumber(this.localSequenceNumber + 1);
@@ -2380,14 +2023,12 @@ private SIPRequest createRequest(String method, String topMostViaTransport)
/*
* RFC3261, section 12.2.1.1:
*
- * The URI in the To field of the request MUST be set to the remote URI
- * from the dialog state. The tag in the To header field of the request
- * MUST be set to the remote tag of the dialog ID. The From URI of the
- * request MUST be set to the local URI from the dialog state. The tag
- * in the From header field of the request MUST be set to the local tag
- * of the dialog ID. If the value of the remote or local tags is null,
- * the tag parameter MUST be omitted from the To or From header fields,
- * respectively.
+ * The URI in the To field of the request MUST be set to the remote URI from the dialog
+ * state. The tag in the To header field of the request MUST be set to the remote tag of
+ * the dialog ID. The From URI of the request MUST be set to the local URI from the dialog
+ * state. The tag in the From header field of the request MUST be set to the local tag of
+ * the dialog ID. If the value of the remote or local tags is null, the tag parameter MUST
+ * be omitted from the To or From header fields, respectively.
*/
try {
@@ -2412,80 +2053,6 @@ private SIPRequest createRequest(String method, String topMostViaTransport)
}
- /**
- * Generate a request from a response.
- *
- * @param requestURI
- * -- the request URI to assign to the request.
- * @param via
- * -- the Via header to assign to the request
- * @param cseq
- * -- the CSeq header to assign to the request
- * @param from
- * -- the From header to assign to the request
- * @param to
- * -- the To header to assign to the request
- * @return -- the newly generated sip request.
- */
- public SIPRequest createRequest(SipUri requestURI, Via via, CSeq cseq,
- From from, To to) {
- SIPRequest newRequest = new SIPRequest();
- String method = cseq.getMethod();
-
- newRequest.setMethod(method);
- newRequest.setRequestURI(requestURI);
- this.setBranch(via, method);
- newRequest.setHeader(via);
- newRequest.setHeader(cseq);
- newRequest.setHeader(from);
- newRequest.setHeader(to);
- newRequest.setHeader(getCallId());
-
- try {
- // JvB: all requests need a Max-Forwards
- newRequest.attachHeader(new MaxForwards(70), false);
- } catch (Exception d) {
-
- }
-
- if (MessageFactoryImpl.getDefaultUserAgentHeader() != null) {
- newRequest
- .setHeader(MessageFactoryImpl.getDefaultUserAgentHeader());
- }
- return newRequest;
-
- }
-
- /**
- * Sets the Via branch for CANCEL or ACK requests
- *
- * @param via
- * @param method
- * @throws ParseException
- */
- private final void setBranch(Via via, String method) {
- String branch;
- if (method.equals(Request.ACK)) {
- if (getLastResponseStatusCode().intValue() >= 300) {
- branch = lastResponseTopMostVia.getBranch(); // non-2xx ACK uses
- // same branch
- } else {
- branch = Utils.getInstance().generateBranchId(); // 2xx ACK gets
- // new branch
- }
- } else if (method.equals(Request.CANCEL)) {
- branch = lastResponseTopMostVia.getBranch(); // CANCEL uses same
- // branch
- } else
- return;
-
- try {
- via.setBranch(branch);
- } catch (ParseException e) {
- e.printStackTrace();
- }
- }
-
/*
* (non-Javadoc)
*
@@ -2497,72 +2064,55 @@ public void sendRequest(ClientTransaction clientTransactionId)
this.sendRequest(clientTransactionId, !this.isBackToBackUserAgent);
}
- public void sendRequest(ClientTransaction clientTransactionId,
- boolean allowInterleaving) throws TransactionDoesNotExistException,
- SipException {
+ public void sendRequest(ClientTransaction clientTransactionId, boolean allowInterleaving)
+ throws TransactionDoesNotExistException, SipException {
- if (clientTransactionId == null)
- throw new NullPointerException("null parameter");
-
-
- if ((!allowInterleaving)
- && clientTransactionId.getRequest().getMethod().equals(
- Request.INVITE)) {
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- logger.logDebug("SIPDialog::sendRequest " + this + " clientTransaction = " + clientTransactionId);
- }
- sipStack.getReinviteExecutor().execute(
- (new ReInviteSender(clientTransactionId)));
- return;
- }
+ if ((!allowInterleaving)
+ && clientTransactionId.getRequest().getMethod().equals(Request.INVITE))
+ {
+ sipStack.getReinviteExecutor().execute((new ReInviteSender(clientTransactionId)));
+ return;
+ }
SIPRequest dialogRequest = ((SIPClientTransaction) clientTransactionId)
.getOriginalRequest();
- this.proxyAuthorizationHeader = (ProxyAuthorizationHeader) dialogRequest
- .getHeader(ProxyAuthorizationHeader.NAME);
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG))
+ sipStack.getStackLogger().logDebug(
+ "dialog.sendRequest " + " dialog = " + this + "\ndialogRequest = \n"
+ + dialogRequest);
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG))
- logger.logDebug(
- "SIPDialog::sendRequest:dialog.sendRequest " + " dialog = " + this
- + "\ndialogRequest = \n" + dialogRequest);
+ if (clientTransactionId == null)
+ throw new NullPointerException("null parameter");
if (dialogRequest.getMethod().equals(Request.ACK)
|| dialogRequest.getMethod().equals(Request.CANCEL))
- throw new SipException("Bad Request Method. "
- + dialogRequest.getMethod());
+ throw new SipException("Bad Request Method. " + dialogRequest.getMethod());
// JvB: added, allow re-sending of BYE after challenge
- if (byeSent && isTerminatedOnBye()
- && !dialogRequest.getMethod().equals(Request.BYE)) {
- if (logger.isLoggingEnabled())
- logger.logError(
- "BYE already sent for " + this);
+ if (byeSent && isTerminatedOnBye() && !dialogRequest.getMethod().equals(Request.BYE)) {
+ if (sipStack.isLoggingEnabled())
+ sipStack.getStackLogger().logError("BYE already sent for " + this);
throw new SipException("Cannot send request; BYE already sent");
}
if (dialogRequest.getTopmostVia() == null) {
- Via via = ((SIPClientTransaction) clientTransactionId)
- .getOutgoingViaHeader();
+ Via via = ((SIPClientTransaction) clientTransactionId).getOutgoingViaHeader();
dialogRequest.addHeader(via);
}
- if (!this.getCallId().getCallId().equalsIgnoreCase(
- dialogRequest.getCallId().getCallId())) {
-
- if (logger.isLoggingEnabled()) {
- logger
- .logError("CallID " + this.getCallId());
- logger.logError(
- "SIPDialog::sendRequest:RequestCallID = "
- + dialogRequest.getCallId().getCallId());
- logger.logError("dialog = " + this);
+ if (!this.getCallId().getCallId().equalsIgnoreCase(dialogRequest.getCallId().getCallId())) {
+
+ if (sipStack.isLoggingEnabled()) {
+ sipStack.getStackLogger().logError("CallID " + this.getCallId());
+ sipStack.getStackLogger().logError(
+ "RequestCallID = " + dialogRequest.getCallId().getCallId());
+ sipStack.getStackLogger().logError("dialog = " + this);
}
throw new SipException("Bad call ID in request");
}
// Set the dialog back pointer.
- ((SIPClientTransaction) clientTransactionId).setDialog(this,
- this.dialogId);
+ ((SIPClientTransaction) clientTransactionId).setDialog(this, this.dialogId);
this.addTransaction((SIPTransaction) clientTransactionId);
// Enable the retransmission filter for the transaction
@@ -2576,25 +2126,20 @@ public void sendRequest(ClientTransaction clientTransactionId,
// tag assignment is OK.
if (this.getLocalTag() != null && from.getTag() != null
&& !from.getTag().equals(this.getLocalTag()))
- throw new SipException("From tag mismatch expecting "
- + this.getLocalTag());
+ throw new SipException("From tag mismatch expecting " + this.getLocalTag());
if (this.getRemoteTag() != null && to.getTag() != null
&& !to.getTag().equals(this.getRemoteTag())) {
- if (logger.isLoggingEnabled())
- this.logger.logWarning(
- "SIPDialog::sendRequest:To header tag mismatch expecting "
- + this.getRemoteTag());
+ if (sipStack.isLoggingEnabled())
+ this.sipStack.getStackLogger().logWarning(
+ "To header tag mismatch expecting " + this.getRemoteTag());
}
/*
- * The application is sending a NOTIFY before sending the response of
- * the dialog.
+ * The application is sending a NOTIFY before sending the response of the dialog.
*/
- if (this.getLocalTag() == null
- && dialogRequest.getMethod().equals(Request.NOTIFY)) {
+ if (this.getLocalTag() == null && dialogRequest.getMethod().equals(Request.NOTIFY)) {
if (!this.getMethod().equals(Request.SUBSCRIBE))
- throw new SipException(
- "Trying to send NOTIFY without SUBSCRIBE Dialog!");
+ throw new SipException("Trying to send NOTIFY without SUBSCRIBE Dialog!");
this.setLocalTag(from.getTag());
}
@@ -2612,18 +2157,18 @@ public void sendRequest(ClientTransaction clientTransactionId,
}
Hop hop = ((SIPClientTransaction) clientTransactionId).getNextHop();
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- logger.logDebug(
- "SIPDialog::sendRequest:Using hop = " + hop.getHost() + " : " + hop.getPort());
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
+ sipStack.getStackLogger().logDebug(
+ "Using hop = " + hop.getHost() + " : " + hop.getPort());
}
try {
- MessageChannel messageChannel = sipStack.createRawMessageChannel(
- this.getSipProvider().getListeningPoint(hop.getTransport())
- .getIPAddress(), this.firstTransactionPort, hop);
-
- MessageChannel oldChannel = ((SIPClientTransaction) clientTransactionId)
- .getMessageChannel();
+ MessageChannel messageChannel = sipStack.createRawMessageChannel(this
+ .getSipProvider().getListeningPoint(hop.getTransport()).getIPAddress(),
+ this.firstTransactionPort, hop);
+
+ MessageChannel oldChannel = ((SIPClientTransaction)
+ clientTransactionId).getMessageChannel();
// Remove this from the connection cache if it is in the
// connection
@@ -2633,40 +2178,34 @@ public void sendRequest(ClientTransaction clientTransactionId,
// Not configured to cache client connections.
if (!sipStack.cacheClientConnections) {
oldChannel.useCount--;
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG))
- logger.logDebug(
- "SIPDialog::sendRequest:oldChannel: useCount " + oldChannel.useCount);
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG))
+ sipStack.getStackLogger().logDebug(
+ "oldChannel: useCount " + oldChannel.useCount);
}
if (messageChannel == null) {
/*
- * At this point the procedures of 8.1.2 and 12.2.1.1 of RFC3261
- * have been tried but the resulting next hop cannot be resolved
- * (recall that the exception thrown is caught and ignored in
- * SIPStack.createMessageChannel() so we end up here with a null
- * messageChannel instead of the exception handler below). All
- * else failing, try the outbound proxy in accordance with
- * 8.1.2, in particular: This ensures that outbound proxies that
- * do not add Record-Route header field values will drop out of
- * the path of subsequent requests. It allows endpoints that
- * cannot resolve the first Route URI to delegate that task to
- * an outbound proxy.
+ * At this point the procedures of 8.1.2 and 12.2.1.1 of RFC3261 have been tried
+ * but the resulting next hop cannot be resolved (recall that the exception thrown
+ * is caught and ignored in SIPStack.createMessageChannel() so we end up here with
+ * a null messageChannel instead of the exception handler below). All else
+ * failing, try the outbound proxy in accordance with 8.1.2, in particular: This
+ * ensures that outbound proxies that do not add Record-Route header field values
+ * will drop out of the path of subsequent requests. It allows endpoints that
+ * cannot resolve the first Route URI to delegate that task to an outbound proxy.
*
- * if one considers the 'first Route URI' of a request
- * constructed according to 12.2.1.1 to be the request URI when
- * the route set is empty.
+ * if one considers the 'first Route URI' of a request constructed according to
+ * 12.2.1.1 to be the request URI when the route set is empty.
*/
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG))
- logger.logDebug(
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG))
+ sipStack.getStackLogger().logDebug(
"Null message channel using outbound proxy !");
- Hop outboundProxy = sipStack.getRouter(dialogRequest)
- .getOutboundProxy();
+ Hop outboundProxy = sipStack.getRouter(dialogRequest).getOutboundProxy();
if (outboundProxy == null)
throw new SipException("No route found! hop=" + hop);
- messageChannel = sipStack.createRawMessageChannel(this
- .getSipProvider().getListeningPoint(
- outboundProxy.getTransport()).getIPAddress(),
+ messageChannel = sipStack.createRawMessageChannel(this.getSipProvider()
+ .getListeningPoint(outboundProxy.getTransport()).getIPAddress(),
this.firstTransactionPort, outboundProxy);
if (messageChannel != null)
((SIPClientTransaction) clientTransactionId)
@@ -2675,24 +2214,22 @@ public void sendRequest(ClientTransaction clientTransactionId,
((SIPClientTransaction) clientTransactionId)
.setEncapsulatedChannel(messageChannel);
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- logger.logDebug(
- "SIPDialog::sendRequest:using message channel " + messageChannel);
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
+ sipStack.getStackLogger().logDebug("using message channel " + messageChannel);
}
}
- if (messageChannel != null)
- messageChannel.useCount++;
-
+ if (messageChannel != null) messageChannel.useCount++;
+
// See if we need to release the previously mapped channel.
if ((!sipStack.cacheClientConnections) && oldChannel != null
&& oldChannel.useCount <= 0)
- oldChannel.close();
+ oldChannel.close();
} catch (Exception ex) {
- if (logger.isLoggingEnabled())
- logger.logException(ex);
+ if (sipStack.isLoggingEnabled())
+ sipStack.getStackLogger().logException(ex);
throw new SipException("Could not create message channel", ex);
}
@@ -2701,22 +2238,19 @@ public void sendRequest(ClientTransaction clientTransactionId,
localSequenceNumber++;
dialogRequest.getCSeq().setSeqNumber(getLocalSeqNumber());
} catch (InvalidArgumentException ex) {
- logger.logFatalError(ex.getMessage());
+ sipStack.getStackLogger().logFatalError(ex.getMessage());
}
try {
- ((SIPClientTransaction) clientTransactionId)
- .sendMessage(dialogRequest);
+ ((SIPClientTransaction) clientTransactionId).sendMessage(dialogRequest);
/*
- * Note that if the BYE is rejected then the Dialog should bo back
- * to the ESTABLISHED state so we only set state after successful
- * send.
+ * Note that if the BYE is rejected then the Dialog should bo back to the ESTABLISHED
+ * state so we only set state after successful send.
*/
if (dialogRequest.getMethod().equals(Request.BYE)) {
this.byeSent = true;
/*
- * Dialog goes into TERMINATED state as soon as BYE is sent.
- * ISSUE 182.
+ * Dialog goes into TERMINATED state as soon as BYE is sent. ISSUE 182.
*/
if (isTerminatedOnBye()) {
this.setState(DialogState._TERMINATED);
@@ -2767,17 +2301,12 @@ public void resendAck() throws SipException {
}
}
this.sendAck(getLastAckSent(), false);
- } else {
- if(logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)){
- logger.logDebug("SIPDialog::resendAck:lastAck sent is NULL hence not resending ACK");
- }
}
}
/**
- * Get the method of the request/response that resulted in the creation of
- * the Dialog.
+ * Get the method of the request/response that resulted in the creation of the Dialog.
*
* @return -- the method of the dialog.
*/
@@ -2794,31 +2323,26 @@ public String getMethod() {
protected void startTimer(SIPServerTransaction transaction) {
if (this.timerTask != null && timerTask.transaction == transaction) {
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG))
- logger.logDebug(
- "Timer already running for " + getDialogId());
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG))
+ sipStack.getStackLogger().logDebug("Timer already running for " + getDialogId());
return;
}
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG))
- logger.logDebug(
- "Starting dialog timer for " + getDialogId());
-
- acquireTimerTaskSem();
- try {
- if (this.timerTask != null) {
- this.timerTask.transaction = transaction;
- } else {
- this.timerTask = new DialogTimerTask(transaction);
- if ( sipStack.getTimer() != null && sipStack.getTimer().isStarted()) {
- sipStack.getTimer().scheduleWithFixedDelay(timerTask,
- SIPTransactionStack.BASE_TIMER_INTERVAL,
- SIPTransactionStack.BASE_TIMER_INTERVAL);
- }
- }
- } finally {
- releaseTimerTaskSem();
- }
-
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG))
+ sipStack.getStackLogger().logDebug("Starting dialog timer for " + getDialogId());
+
+ acquireTimerTaskSem();
+ try {
+ if (this.timerTask != null) {
+ this.timerTask.transaction = transaction;
+ } else {
+ this.timerTask = new DialogTimerTask(transaction);
+ sipStack.getTimer().schedule(timerTask, SIPTransactionStack.BASE_TIMER_INTERVAL,
+ SIPTransactionStack.BASE_TIMER_INTERVAL);
+ }
+ } finally {
+ releaseTimerTaskSem();
+ }
+
this.setRetransmissionTicks();
}
@@ -2828,42 +2352,35 @@ protected void startTimer(SIPServerTransaction transaction) {
*/
protected void stopTimer() {
try {
- acquireTimerTaskSem();
- try {
- if (this.timerTask != null) {
- this.getStack().getTimer().cancel(timerTask);
- this.timerTask = null;
- }
- if (this.earlyStateTimerTask != null) {
- this.getStack().getTimer().cancel(this.earlyStateTimerTask);
- this.earlyStateTimerTask = null;
- }
- } finally {
- releaseTimerTaskSem();
- }
+ acquireTimerTaskSem();
+ try {
+ if (this.timerTask != null) {
+ this.timerTask.cancel();
+ this.timerTask = null;
+ }
+ } finally {
+ releaseTimerTaskSem();
+ }
} catch (Exception ex) {
}
}
/*
- * (non-Javadoc) Retransmissions of the reliable provisional response cease
- * when a matching PRACK is received by the UA core. PRACK is like any other
- * request within a dialog, and the UAS core processes it according to the
- * procedures of Sections 8.2 and 12.2.2 of RFC 3261. A matching PRACK is
- * defined as one within the same dialog as the response, and whose method,
- * CSeq-num, and response-num in the RAck header field match, respectively,
- * the method from the CSeq, the sequence number from the CSeq, and the
- * sequence number from the RSeq of the reliable provisional response.
+ * (non-Javadoc) Retransmissions of the reliable provisional response cease when a matching
+ * PRACK is received by the UA core. PRACK is like any other request within a dialog, and the
+ * UAS core processes it according to the procedures of Sections 8.2 and 12.2.2 of RFC 3261. A
+ * matching PRACK is defined as one within the same dialog as the response, and whose method,
+ * CSeq-num, and response-num in the RAck header field match, respectively, the method from
+ * the CSeq, the sequence number from the CSeq, and the sequence number from the RSeq of the
+ * reliable provisional response.
*
* @see javax.sip.Dialog#createPrack(javax.sip.message.Response)
*/
- public Request createPrack(Response relResponse)
- throws DialogDoesNotExistException, SipException {
+ public Request createPrack(Response relResponse) throws DialogDoesNotExistException,
+ SipException {
- if (this.getState() == null
- || this.getState().equals(DialogState.TERMINATED))
- throw new DialogDoesNotExistException(
- "Dialog not initialized or terminated");
+ if (this.getState() == null || this.getState().equals(DialogState.TERMINATED))
+ throw new DialogDoesNotExistException("Dialog not initialized or terminated");
if ((RSeq) relResponse.getHeader(RSeqHeader.NAME) == null) {
throw new SipException("Missing RSeq Header");
@@ -2871,8 +2388,8 @@ public Request createPrack(Response relResponse)
try {
SIPResponse sipResponse = (SIPResponse) relResponse;
- SIPRequest sipRequest = this.createRequest(Request.PRACK,
- sipResponse.getTopmostVia().getTransport());
+ SIPRequest sipRequest = (SIPRequest) this.createRequest(Request.PRACK,
+ (SIPResponse) relResponse);
String toHeaderTag = sipResponse.getTo().getTag();
sipRequest.setToTag(toHeaderTag);
RAck rack = new RAck();
@@ -2881,9 +2398,6 @@ public Request createPrack(Response relResponse)
rack.setCSequenceNumber((int) sipResponse.getCSeq().getSeqNumber());
rack.setRSequenceNumber(rseq.getSeqNumber());
sipRequest.setHeader(rack);
- if (this.proxyAuthorizationHeader != null) {
- sipRequest.addHeader(proxyAuthorizationHeader);
- }
return (Request) sipRequest;
} catch (Exception ex) {
InternalErrorHandler.handleException(ex);
@@ -2901,75 +2415,57 @@ private void updateRequest(SIPRequest sipRequest) {
sipRequest.removeHeader(RouteHeader.NAME);
}
if (MessageFactoryImpl.getDefaultUserAgentHeader() != null) {
- sipRequest
- .setHeader(MessageFactoryImpl.getDefaultUserAgentHeader());
- }
-
- /*
- * Update the request with Proxy auth header if one has been cached.
- */
- if (this.proxyAuthorizationHeader != null
- && sipRequest.getHeader(ProxyAuthorizationHeader.NAME) == null) {
- sipRequest.setHeader(proxyAuthorizationHeader);
+ sipRequest.setHeader(MessageFactoryImpl.getDefaultUserAgentHeader());
}
}
/*
- * (non-Javadoc) The UAC core MUST generate an ACK request for each 2xx
- * received from the transaction layer. The header fields of the ACK are
- * constructed in the same way as for any request sent within a dialog (see
- * Section 12) with the exception of the CSeq and the header fields related
- * to authentication. The sequence number of the CSeq header field MUST be
- * the same as the INVITE being acknowledged, but the CSeq method MUST be
- * ACK. The ACK MUST contain the same credentials as the INVITE. If the 2xx
- * contains an offer (based on the rules above), the ACK MUST carry an
- * answer in its body. If the offer in the 2xx response is not acceptable,
- * the UAC core MUST generate a valid answer in the ACK and then send a BYE
+ * (non-Javadoc) The UAC core MUST generate an ACK request for each 2xx received from the
+ * transaction layer. The header fields of the ACK are constructed in the same way as for any
+ * request sent within a dialog (see Section 12) with the exception of the CSeq and the header
+ * fields related to authentication. The sequence number of the CSeq header field MUST be the
+ * same as the INVITE being acknowledged, but the CSeq method MUST be ACK. The ACK MUST
+ * contain the same credentials as the INVITE. If the 2xx contains an offer (based on the
+ * rules above), the ACK MUST carry an answer in its body. If the offer in the 2xx response is
+ * not acceptable, the UAC core MUST generate a valid answer in the ACK and then send a BYE
* immediately.
*
- * Note that for the case of forked requests, you can create multiple
- * outgoing invites each with a different cseq and hence you need to supply
- * the invite.
+ * Note that for the case of forked requests, you can create multiple outgoing invites each
+ * with a different cseq and hence you need to supply the invite.
*
* @see javax.sip.Dialog#createAck(long)
*/
- public Request createAck(long cseqno) throws InvalidArgumentException,
- SipException {
+ public Request createAck(long cseqno) throws InvalidArgumentException, SipException {
// JvB: strictly speaking it is allowed to start a dialog with
// SUBSCRIBE,
// then send INVITE+ACK later on
if (!method.equals(Request.INVITE))
- throw new SipException("Dialog was not created with an INVITE"
- + method);
+ throw new SipException("Dialog was not created with an INVITE" + method);
if (cseqno <= 0)
throw new InvalidArgumentException("bad cseq <= 0 ");
else if (cseqno > ((((long) 1) << 32) - 1))
- throw new InvalidArgumentException("bad cseq > "
- + ((((long) 1) << 32) - 1));
+ throw new InvalidArgumentException("bad cseq > " + ((((long) 1) << 32) - 1));
- if (this.getRemoteTarget() == null) {
+ if (this.remoteTarget == null) {
throw new SipException("Cannot create ACK - no remote Target!");
}
- if (this.logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- this.logger.logDebug(
- "createAck " + this + " cseqno " + cseqno);
+ if (this.sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
+ this.sipStack.getStackLogger().logDebug("createAck " + this + " cseqno " + cseqno);
}
// MUST ack in the same order that the OKs were received. This traps
// out of order ACK sending. Old ACKs seqno's can always be ACKed.
if (lastInviteOkReceived < cseqno) {
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- this.logger.logDebug(
- "WARNING : Attempt to crete ACK without OK " + this);
- this.logger.logDebug(
- "LAST RESPONSE = " + this.getLastResponseStatusCode());
- }
- throw new SipException(
- "Dialog not yet established -- no OK response!");
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
+ this.sipStack.getStackLogger().logDebug(
+ "WARNING : Attempt to crete ACK without OK " + this);
+ this.sipStack.getStackLogger().logDebug("LAST RESPONSE = " + this.lastResponse);
+ }
+ throw new SipException("Dialog not yet established -- no OK response!");
}
try {
@@ -2983,7 +2479,7 @@ else if (cseqno > ((((long) 1) << 32) - 1))
Route r = (Route) this.routeList.getFirst();
uri4transport = ((SipURI) r.getAddress().getURI());
} else { // should be !=null, checked above
- uri4transport = ((SipURI) this.getRemoteTarget().getURI());
+ uri4transport = ((SipURI) this.remoteTarget.getURI());
}
String transport = uri4transport.getTransportParam();
@@ -3005,13 +2501,13 @@ else if (cseqno > ((((long) 1) << 32) - 1))
}
}
if (lp == null) {
- if (logger.isLoggingEnabled()) {
- logger.logError(
+ if (sipStack.isLoggingEnabled()) {
+ sipStack.getStackLogger().logError(
"remoteTargetURI "
+ this.getRemoteTarget().getURI());
- logger.logError(
+ sipStack.getStackLogger().logError(
"uri4transport = " + uri4transport);
- logger.logError(
+ sipStack.getStackLogger().logError(
"No LP found for transport=" + transport);
}
throw new SipException(
@@ -3020,55 +2516,43 @@ else if (cseqno > ((((long) 1) << 32) - 1))
}
SIPRequest sipRequest = new SIPRequest();
sipRequest.setMethod(Request.ACK);
- sipRequest.setRequestURI((SipUri) getRemoteTarget().getURI()
- .clone());
- sipRequest.setCallId(this.getCallId());
+ sipRequest.setRequestURI((SipUri) getRemoteTarget().getURI().clone());
+ sipRequest.setCallId(this.callIdHeader);
sipRequest.setCSeq(new CSeq(cseqno, Request.ACK));
List vias = new ArrayList();
// Via via = lp.getViaHeader();
// The user may have touched the sentby for the response.
// so use the via header extracted from the response for the ACK =>
// https://jain-sip.dev.java.net/issues/show_bug.cgi?id=205
- // strip the params from the via of the response and use the params
- // from the
+ // strip the params from the via of the response and use the params from the
// original request
- Via via = this.lastResponseTopMostVia;
+ Via via = this.lastResponse.getTopmostVia();
via.removeParameters();
- if (originalRequest != null
- && originalRequest.getTopmostVia() != null) {
- NameValueList originalRequestParameters = originalRequest
- .getTopmostVia().getParameters();
- if (originalRequestParameters != null
- && originalRequestParameters.size() > 0) {
- via.setParameters((NameValueList) originalRequestParameters
- .clone());
+ if (originalRequest != null && originalRequest.getTopmostVia() != null) {
+ NameValueList originalRequestParameters = originalRequest.getTopmostVia()
+ .getParameters();
+ if (originalRequestParameters != null && originalRequestParameters.size() > 0) {
+ via.setParameters((NameValueList) originalRequestParameters.clone());
}
}
via.setBranch(Utils.getInstance().generateBranchId()); // new branch
vias.add(via);
sipRequest.setVia(vias);
From from = new From();
- from.setAddress(this.getLocalParty());
+ from.setAddress(this.localParty);
from.setTag(this.myTag);
sipRequest.setFrom(from);
To to = new To();
- to.setAddress(this.getRemoteParty());
+ to.setAddress(this.remoteParty);
if (hisTag != null)
to.setTag(this.hisTag);
sipRequest.setTo(to);
sipRequest.setMaxForwards(new MaxForwards(70));
if (this.originalRequest != null) {
- Authorization authorization = this.originalRequest
- .getAuthorization();
+ Authorization authorization = this.originalRequest.getAuthorization();
if (authorization != null)
sipRequest.setHeader(authorization);
- // jeand : setting back the original Request to null to avoid
- // keeping references around for too long
- // since it is used only in the dialog setup
- originalRequestRecordRouteHeaders = originalRequest
- .getRecordRouteHeaders();
- originalRequest = null;
}
// ACKs for 2xx responses
@@ -3096,20 +2580,17 @@ public SipProviderImpl getSipProvider() {
}
/**
- * @param sipProvider
- * the sipProvider to set
+ * @param sipProvider the sipProvider to set
*/
public void setSipProvider(SipProviderImpl sipProvider) {
this.sipProvider = sipProvider;
}
/**
- * Check the tags of the response against the tags of the Dialog. Return
- * true if the respnse matches the tags of the dialog. We do this check wehn
- * sending out a response.
+ * Check the tags of the response against the tags of the Dialog. Return true if the respnse
+ * matches the tags of the dialog. We do this check wehn sending out a response.
*
- * @param sipResponse
- * -- the response to check.
+ * @param sipResponse -- the response to check.
*
*/
public void setResponseTags(SIPResponse sipResponse) {
@@ -3117,410 +2598,305 @@ public void setResponseTags(SIPResponse sipResponse) {
return;
}
String responseFromTag = sipResponse.getFromTag();
- if (responseFromTag != null) {
+ if ( responseFromTag != null ) {
if (responseFromTag.equals(this.getLocalTag())) {
sipResponse.setToTag(this.getRemoteTag());
} else if (responseFromTag.equals(this.getRemoteTag())) {
sipResponse.setToTag(this.getLocalTag());
}
} else {
- if (logger.isLoggingEnabled())
- logger.logWarning(
- "No from tag in response! Not RFC 3261 compatible.");
+ if (sipStack.isLoggingEnabled())
+ sipStack.getStackLogger().logWarning("No from tag in response! Not RFC 3261 compatible.");
}
}
/**
- * Set the last response for this dialog. This method is called for updating
- * the dialog state when a response is either sent or received from within a
- * Dialog.
+ * Set the last response for this dialog. This method is called for updating the dialog state
+ * when a response is either sent or received from within a Dialog.
*
- * @param transaction
- * -- the transaction associated with the response
- * @param sipResponse
- * -- the last response to set.
+ * @param transaction -- the transaction associated with the response
+ * @param sipResponse -- the last response to set.
*/
- public void setLastResponse(SIPTransaction transaction,
- SIPResponse sipResponse) {
- this.callIdHeader = sipResponse.getCallId();
- final int statusCode = sipResponse.getStatusCode();
+ public void setLastResponse(SIPTransaction transaction, SIPResponse sipResponse) {
+ this.callIdHeader = sipResponse.getCallId();
+ int statusCode = sipResponse.getStatusCode();
if (statusCode == 100) {
- if (logger.isLoggingEnabled())
- logger
- .logWarning(
- "Invalid status code - 100 in setLastResponse - ignoring");
+ if (sipStack.isLoggingEnabled())
+ sipStack.getStackLogger().logWarning(
+ "Invalid status code - 100 in setLastResponse - ignoring");
return;
}
-
- if ( logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- logger.logStackTrace();
- }
- // this.lastResponse = sipResponse;
- try {
- this.lastResponseStatusCode = Integer.valueOf(statusCode);
- this.lastResponseTopMostVia = sipResponse.getTopmostVia();
- this.lastResponseMethod = sipResponse.getCSeqHeader().getMethod();
- this.lastResponseCSeqNumber = sipResponse.getCSeq().getSeqNumber();
- if (sipResponse.getToTag() != null ) {
- this.lastResponseToTag = sipResponse.getToTag();
- }
- if ( sipResponse.getFromTag() != null ) {
- this.lastResponseFromTag = sipResponse.getFromTag();
- }
- if (transaction != null) {
- this.lastResponseDialogId = sipResponse.getDialogId(transaction
- .isServerTransaction());
- }
- this.setAssigned();
- // Adjust state of the Dialog state machine.
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- logger.logDebug(
- "sipDialog: setLastResponse:" + this
- + " lastResponse = "
- + this.lastResponseStatusCode);
- }
- if (this.getState() == DialogState.TERMINATED) {
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- logger
- .logDebug(
- "sipDialog: setLastResponse -- dialog is terminated - ignoring ");
- }
- // Capture the OK response for later use in createAck
- // This is handy for late arriving OK's that we want to ACK.
- if (lastResponseMethod.equals(Request.INVITE)
- && statusCode == 200) {
-
- this.lastInviteOkReceived = Math.max(
- lastResponseCSeqNumber, this.lastInviteOkReceived);
- }
- return;
- }
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- logger.logStackTrace();
- logger.logDebug(
- "cseqMethod = " + lastResponseMethod);
- logger.logDebug(
- "dialogState = " + this.getState());
- logger.logDebug(
- "method = " + this.getMethod());
- logger
- .logDebug("statusCode = " + statusCode);
- logger.logDebug(
- "transaction = " + transaction);
+
+ this.lastResponse = sipResponse;
+ this.setAssigned();
+ // Adjust state of the Dialog state machine.
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
+ sipStack.getStackLogger().logDebug(
+ "sipDialog: setLastResponse:" + this + " lastResponse = "
+ + this.lastResponse.getFirstLine());
+ }
+ if (this.getState() == DialogState.TERMINATED) {
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
+ sipStack.getStackLogger().logDebug(
+ "sipDialog: setLastResponse -- dialog is terminated - ignoring ");
+ }
+ // Capture the OK response for later use in createAck
+ // This is handy for late arriving OK's that we want to ACK.
+ if (sipResponse.getCSeq().getMethod().equals(Request.INVITE) && statusCode == 200) {
+
+ this.lastInviteOkReceived = Math.max(sipResponse.getCSeq().getSeqNumber(),
+ this.lastInviteOkReceived);
}
-
- // JvB: don't use "!this.isServer" here
- // note that the transaction can be null for forked
- // responses.
- if (transaction == null || transaction instanceof ClientTransaction) {
- if (SIPTransactionStack.isDialogCreated(lastResponseMethod)) {
- // Make a final tag assignment.
- if (getState() == null && (statusCode / 100 == 1)) {
- /*
- * Guard aginst slipping back into early state from
- * confirmed state.
- */
- // Was (sipResponse.getToTag() != null ||
- // sipStack.rfc2543Supported)
- setState(SIPDialog.EARLY_STATE);
- if ((sipResponse.getToTag() != null || sipStack.rfc2543Supported)
- && this.getRemoteTag() == null) {
- setRemoteTag(sipResponse.getToTag());
- this.setDialogId(sipResponse.getDialogId(false));
- sipStack.putDialog(this);
- this.addRoute(sipResponse);
- }
- } else if (getState() != null
- && getState().equals(DialogState.EARLY)
- && statusCode / 100 == 1) {
+ return;
+ }
+ String cseqMethod = sipResponse.getCSeq().getMethod();
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
+ sipStack.getStackLogger().logStackTrace();
+ sipStack.getStackLogger().logDebug("cseqMethod = " + cseqMethod);
+ sipStack.getStackLogger().logDebug("dialogState = " + this.getState());
+ sipStack.getStackLogger().logDebug("method = " + this.getMethod());
+ sipStack.getStackLogger().logDebug("statusCode = " + statusCode);
+ sipStack.getStackLogger().logDebug("transaction = " + transaction);
+ }
+
+ // JvB: don't use "!this.isServer" here
+ // note that the transaction can be null for forked
+ // responses.
+ if (transaction == null || transaction instanceof ClientTransaction) {
+ if (sipStack.isDialogCreated(cseqMethod)) {
+ // Make a final tag assignment.
+ if (getState() == null && (statusCode / 100 == 1)) {
+ /*
+ * Guard aginst slipping back into early state from confirmed state.
+ */
+ // Was (sipResponse.getToTag() != null || sipStack.rfc2543Supported)
+ setState(SIPDialog.EARLY_STATE);
+ if ((sipResponse.getToTag() != null || sipStack.rfc2543Supported)
+ && this.getRemoteTag() == null) {
+ setRemoteTag(sipResponse.getToTag());
+ this.setDialogId(sipResponse.getDialogId(false));
+ sipStack.putDialog(this);
+ this.addRoute(sipResponse);
+ }
+ } else if (getState() != null && getState().equals(DialogState.EARLY)
+ && statusCode / 100 == 1) {
+ /*
+ * This case occurs for forked dialog responses. The To tag can change as a
+ * result of the forking. The remote target can also change as a result of the
+ * forking.
+ */
+ if (cseqMethod.equals(getMethod()) && transaction != null
+ && (sipResponse.getToTag() != null || sipStack.rfc2543Supported)) {
+ setRemoteTag(sipResponse.getToTag());
+ this.setDialogId(sipResponse.getDialogId(false));
+ sipStack.putDialog(this);
+ this.addRoute(sipResponse);
+ }
+ } else if (statusCode / 100 == 2) {
+ // This is a dialog creating method (such as INVITE).
+ // 2xx response -- set the state to the confirmed
+ // state. To tag is MANDATORY for the response.
+
+ // Only do this if method equals initial request!
+ if(sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
+ sipStack.getStackLogger().logDebug("pendingRouteUpdateOn202Response : " + this.pendingRouteUpdateOn202Response);
+ }
+ if (cseqMethod.equals(getMethod())
+ && (sipResponse.getToTag() != null || sipStack.rfc2543Supported)
+ && (this.getState() != DialogState.CONFIRMED ||
+ (this.getState() == DialogState.CONFIRMED
+ && cseqMethod.equals(Request.SUBSCRIBE)
+ && this.pendingRouteUpdateOn202Response
+ && sipResponse.getStatusCode() == Response.ACCEPTED))) {
+ if (this.getState() != DialogState.CONFIRMED) {
+ setRemoteTag(sipResponse.getToTag());
+ this.setDialogId(sipResponse.getDialogId(false));
+ sipStack.putDialog(this);
+ this.addRoute(sipResponse);
+ this.setState(CONFIRMED_STATE);
+ }
+
/*
- * This case occurs for forked dialog responses. The To
- * tag can change as a result of the forking. The remote
- * target can also change as a result of the forking.
+ * Note: Subscribe NOTIFY processing. The route set is computed
+ * only after we get the 202 response but the NOTIFY may come in before
+ * we get the 202 response. So we need to update the route set after
+ * we see the 202 despite the fact that the dialog is in the CONFIRMED
+ * state. We do this only on the dialog forming SUBSCRIBE an not a
+ * resubscribe.
*/
- if (lastResponseMethod.equals(getMethod())
- && transaction != null
- && (sipResponse.getToTag() != null || sipStack.rfc2543Supported)) {
- setRemoteTag(sipResponse.getToTag());
- this.setDialogId(sipResponse.getDialogId(false));
- sipStack.putDialog(this);
- this.addRoute(sipResponse);
- }
- } else if (statusCode / 100 == 2) {
- // This is a dialog creating method (such as INVITE).
- // 2xx response -- set the state to the confirmed
- // state. To tag is MANDATORY for the response.
-
- // Only do this if method equals initial request!
- if (logger.isLoggingEnabled(
- LogWriter.TRACE_DEBUG)) {
- logger
- .logDebug(
- "pendingRouteUpdateOn202Response : "
- + this.pendingRouteUpdateOn202Response);
- }
- if (lastResponseMethod.equals(getMethod())
- && (sipResponse.getToTag() != null || sipStack.rfc2543Supported)
- && (this.getState() != DialogState.CONFIRMED || (this
- .getState() == DialogState.CONFIRMED
- && lastResponseMethod
- .equals(Request.SUBSCRIBE)
- && this.pendingRouteUpdateOn202Response && sipResponse
- .getStatusCode() == Response.ACCEPTED))) {
- if (this.getState() != DialogState.CONFIRMED) {
- setRemoteTag(sipResponse.getToTag());
- this
- .setDialogId(sipResponse
- .getDialogId(false));
- sipStack.putDialog(this);
- this.addRoute(sipResponse);
- this.setState(CONFIRMED_STATE);
- }
-
- /*
- * Note: Subscribe NOTIFY processing. The route set
- * is computed only after we get the 202 response
- * but the NOTIFY may come in before we get the 202
- * response. So we need to update the route set
- * after we see the 202 despite the fact that the
- * dialog is in the CONFIRMED state. We do this only
- * on the dialog forming SUBSCRIBE an not a
- * resubscribe.
- */
-
- if (lastResponseMethod.equals(Request.SUBSCRIBE)
- && sipResponse.getStatusCode() == Response.ACCEPTED
- && this.pendingRouteUpdateOn202Response) {
- setRemoteTag(sipResponse.getToTag());
- this.addRoute(sipResponse);
- this.pendingRouteUpdateOn202Response = false;
- }
- }
-
- // Capture the OK response for later use in createAck
- if (lastResponseMethod.equals(Request.INVITE)) {
- this.lastInviteOkReceived = Math.max(sipResponse
- .getCSeq().getSeqNumber(),
- this.lastInviteOkReceived);
+
+ if ( cseqMethod.equals(Request.SUBSCRIBE)
+ && sipResponse.getStatusCode() == Response.ACCEPTED
+ && this.pendingRouteUpdateOn202Response) {
+ setRemoteTag(sipResponse.getToTag());
+ this.addRoute(sipResponse);
+ this.pendingRouteUpdateOn202Response = false;
}
+ }
- } else if (statusCode >= 300
- && statusCode <= 699
- && (getState() == null || (lastResponseMethod
- .equals(getMethod()) && getState()
- .getValue() == SIPDialog.EARLY_STATE))) {
- /*
- * This case handles 3xx, 4xx, 5xx and 6xx responses.
- * RFC 3261 Section 12.3 - dialog termination.
- * Independent of the method, if a request outside of a
- * dialog generates a non-2xx final response, any early
- * dialogs created through provisional responses to that
- * request are terminated.
- */
- setState(SIPDialog.TERMINATED_STATE);
+ // Capture the OK response for later use in createAck
+ if (cseqMethod.equals(Request.INVITE)) {
+ this.lastInviteOkReceived = Math.max(sipResponse.getCSeq().getSeqNumber(),
+ this.lastInviteOkReceived);
}
+ } else if (statusCode >= 300
+ && statusCode <= 699
+ && (getState() == null || (cseqMethod.equals(getMethod()) && getState()
+ .getValue() == SIPDialog.EARLY_STATE))) {
/*
- * This code is in support of "proxy" servers that are
- * constructed as back to back user agents. This could be a
- * dialog in the middle of the call setup path somewhere.
- * Hence the incoming invite has record route headers in it.
- * The response will have additional record route headers.
- * However, for this dialog only the downstream record route
- * headers matter. Ideally proxy servers should not be
- * constructed as Back to Back User Agents. Remove all the
- * record routes that are present in the incoming INVITE so
- * you only have the downstream Route headers present in the
- * dialog. Note that for an endpoint - you will have no
- * record route headers present in the original request so
- * the loop will not execute.
+ * This case handles 3xx, 4xx, 5xx and 6xx responses. RFC 3261 Section 12.3 -
+ * dialog termination. Independent of the method, if a request outside of a
+ * dialog generates a non-2xx final response, any early dialogs created
+ * through provisional responses to that request are terminated.
*/
- if (this.getState() != DialogState.CONFIRMED
- && this.getState() != DialogState.TERMINATED) {
- if (getOriginalRequestRecordRouteHeaders() != null) {
- ListIterator it = getOriginalRequestRecordRouteHeaders()
- .listIterator(
- getOriginalRequestRecordRouteHeaders()
- .size());
+ setState(SIPDialog.TERMINATED_STATE);
+ }
+
+ /*
+ * This code is in support of "proxy" servers that are constructed as back to back
+ * user agents. This could be a dialog in the middle of the call setup path
+ * somewhere. Hence the incoming invite has record route headers in it. The
+ * response will have additional record route headers. However, for this dialog
+ * only the downstream record route headers matter. Ideally proxy servers should
+ * not be constructed as Back to Back User Agents. Remove all the record routes
+ * that are present in the incoming INVITE so you only have the downstream Route
+ * headers present in the dialog. Note that for an endpoint - you will have no
+ * record route headers present in the original request so the loop will not
+ * execute.
+ */
+ if ( this.getState() != DialogState.CONFIRMED && this.getState() != DialogState.TERMINATED ) {
+ if (originalRequest != null) {
+ RecordRouteList rrList = originalRequest.getRecordRouteHeaders();
+ if (rrList != null) {
+ ListIterator it = rrList.listIterator(rrList.size());
while (it.hasPrevious()) {
RecordRoute rr = (RecordRoute) it.previous();
Route route = (Route) routeList.getFirst();
- if (route != null
- && rr.getAddress().equals(
- route.getAddress())) {
+ if (route != null && rr.getAddress().equals(route.getAddress())) {
routeList.removeFirst();
} else
break;
}
}
}
-
- } else if (lastResponseMethod.equals(Request.NOTIFY)
- && (this.getMethod().equals(Request.SUBSCRIBE) || this
- .getMethod().equals(Request.REFER))
- && sipResponse.getStatusCode() / 100 == 2
- && this.getState() == null) {
- // This is a notify response.
- this.setDialogId(sipResponse.getDialogId(true));
- sipStack.putDialog(this);
- this.setState(SIPDialog.CONFIRMED_STATE);
-
- } else if (lastResponseMethod.equals(Request.BYE)
- && statusCode / 100 == 2 && isTerminatedOnBye()) {
- // Dialog will be terminated when the transction is
- // terminated.
- setState(SIPDialog.TERMINATED_STATE);
}
- } else {
- // Processing Server Dialog.
- if (lastResponseMethod.equals(Request.BYE)
- && statusCode / 100 == 2 && this.isTerminatedOnBye()) {
- /*
- * Only transition to terminated state when 200 OK is
- * returned for the BYE. Other status codes just result in
- * leaving the state in COMPLETED state.
- */
- this.setState(SIPDialog.TERMINATED_STATE);
- } else {
- boolean doPutDialog = false;
-
- if (getLocalTag() == null
- && sipResponse.getTo().getTag() != null
- && SIPTransactionStack.isDialogCreated(lastResponseMethod)
- && lastResponseMethod.equals(getMethod())) {
- setLocalTag(sipResponse.getTo().getTag());
- doPutDialog = true;
- }
+ } else if (cseqMethod.equals(Request.NOTIFY)
+ && (this.getMethod().equals(Request.SUBSCRIBE) || this.getMethod().equals(
+ Request.REFER)) && sipResponse.getStatusCode() / 100 == 2
+ && this.getState() == null) {
+ // This is a notify response.
+ this.setDialogId(sipResponse.getDialogId(true));
+ sipStack.putDialog(this);
+ this.setState(SIPDialog.CONFIRMED_STATE);
- if (statusCode / 100 != 2) {
- if (statusCode / 100 == 1) {
- if (doPutDialog) {
+ } else if (cseqMethod.equals(Request.BYE) && statusCode / 100 == 2
+ && isTerminatedOnBye()) {
+ // Dialog will be terminated when the transction is terminated.
+ setState(SIPDialog.TERMINATED_STATE);
+ }
+ } else {
+ // Processing Server Dialog.
- setState(SIPDialog.EARLY_STATE);
- this.setDialogId(sipResponse.getDialogId(true));
- sipStack.putDialog(this);
- }
- } else {
- /*
- * RFC 3265 chapter 3.1.4.1 "Non-200 class final
- * responses indicate that no subscription or dialog
- * has been created, and no subsequent NOTIFY
- * message will be sent. All non-200 class" +
- * responses (with the exception of "489", described
- * herein) have the same meanings and handling as
- * described in SIP"
- */
- // Bug Fix by Jens tinfors
- // see
- // https://jain-sip.dev.java.net/servlets/ReadMsg?list=users&msgNo=797
- if (statusCode == 489
- && (lastResponseMethod
- .equals(Request.NOTIFY) || lastResponseMethod
- .equals(Request.SUBSCRIBE))) {
- if (logger
- .isLoggingEnabled(LogWriter.TRACE_DEBUG))
- logger
- .logDebug(
- "RFC 3265 : Not setting dialog to TERMINATED for 489");
- } else {
- // baranowb: simplest fix to
- // https://jain-sip.dev.java.net/issues/show_bug.cgi?id=175
- // application is responsible for terminating in
- // this case
- // see rfc 5057 for better explanation
- if (!this.isReInvite()
- && getState() != DialogState.CONFIRMED) {
- this.setState(SIPDialog.TERMINATED_STATE);
- }
- }
- }
+ if (cseqMethod.equals(Request.BYE) && statusCode / 100 == 2
+ && this.isTerminatedOnBye()) {
+ /*
+ * Only transition to terminated state when 200 OK is returned for the BYE. Other
+ * status codes just result in leaving the state in COMPLETED state.
+ */
+ this.setState(SIPDialog.TERMINATED_STATE);
+ } else {
+ boolean doPutDialog = false;
- } else {
+ if (getLocalTag() == null && sipResponse.getTo().getTag() != null
+ && sipStack.isDialogCreated(cseqMethod) && cseqMethod.equals(getMethod())) {
+ setLocalTag(sipResponse.getTo().getTag());
- /*
- * JvB: RFC4235 says that when sending 2xx on UAS side,
- * state should move to CONFIRMED
- */
- if (this.dialogState <= SIPDialog.EARLY_STATE
- && (lastResponseMethod.equals(Request.INVITE)
- || lastResponseMethod
- .equals(Request.SUBSCRIBE) || lastResponseMethod
- .equals(Request.REFER))) {
- this.setState(SIPDialog.CONFIRMED_STATE);
- }
+ doPutDialog = true;
+ }
+ if (statusCode / 100 != 2) {
+ if (statusCode / 100 == 1) {
if (doPutDialog) {
+
+ setState(SIPDialog.EARLY_STATE);
this.setDialogId(sipResponse.getDialogId(true));
sipStack.putDialog(this);
}
+ } else {
/*
- * We put the dialog into the table. We must wait for
- * ACK before re-INVITE is sent.
+ * RFC 3265 chapter 3.1.4.1 "Non-200 class final responses indicate that
+ * no subscription or dialog has been created, and no subsequent NOTIFY
+ * message will be sent. All non-200 class" + responses (with the
+ * exception of "489", described herein) have the same meanings and
+ * handling as described in SIP"
*/
+ // Bug Fix by Jens tinfors
+ // see https://jain-sip.dev.java.net/servlets/ReadMsg?list=users&msgNo=797
+ if (statusCode == 489
+ && (cseqMethod.equals(Request.NOTIFY) || cseqMethod
+ .equals(Request.SUBSCRIBE))) {
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG))
+ sipStack.getStackLogger().logDebug(
+ "RFC 3265 : Not setting dialog to TERMINATED for 489");
+ } else {
+ // baranowb: simplest fix to
+ // https://jain-sip.dev.java.net/issues/show_bug.cgi?id=175
+ // application is responsible for terminating in this case
+ // see rfc 5057 for better explanation
+ if (!this.isReInvite() && getState() != DialogState.CONFIRMED) {
+ this.setState(SIPDialog.TERMINATED_STATE);
+ }
+ }
+ }
- if (transaction.getInternalState() != TransactionState._TERMINATED
- && sipResponse.getStatusCode() == Response.OK
- && lastResponseMethod.equals(Request.INVITE)
- && this.isBackToBackUserAgent) {
+ } else {
+
+ /*
+ * JvB: RFC4235 says that when sending 2xx on UAS side, state should move to
+ * CONFIRMED
+ */
+ if (this.dialogState <= SIPDialog.EARLY_STATE
+ && (cseqMethod.equals(Request.INVITE)
+ || cseqMethod.equals(Request.SUBSCRIBE) || cseqMethod
+ .equals(Request.REFER))) {
+ this.setState(SIPDialog.CONFIRMED_STATE);
+ }
+
+ if (doPutDialog) {
+ this.setDialogId(sipResponse.getDialogId(true));
+ sipStack.putDialog(this);
+ }
+ /*
+ * We put the dialog into the table. We must wait for ACK before re-INVITE is
+ * sent.
+ */
+
+ if (transaction.getState() != TransactionState.TERMINATED
+ && sipResponse.getStatusCode() == Response.OK
+ && cseqMethod.equals(Request.INVITE)
+ && this.isBackToBackUserAgent) {
//
- // Acquire the flag for re-INVITE so that we cannot
- // re-INVITE before
- // ACK is received.
+ // Acquire the flag for re-INVITE so that we cannot re-INVITE before
+ // ACK is received.
//
if (!this.takeAckSem()) {
- if (logger
- .isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- logger
- .logDebug(
- "Delete dialog -- cannot acquire ackSem");
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
+ sipStack.getStackLogger().logDebug(
+ "Delete dialog -- cannot acquire ackSem");
}
- this
- .raiseErrorEvent(SIPDialogErrorEvent.DIALOG_ERROR_INTERNAL_COULD_NOT_TAKE_ACK_SEM);
- logger
- .logError(
- "IntenalError : Ack Sem already acquired ");
+ this.raiseErrorEvent(SIPDialogErrorEvent.DIALOG_ERROR_INTERNAL_COULD_NOT_TAKE_ACK_SEM);
+ this.sipStack.getStackLogger().logError("IntenalError : Ack Sem already acquired ");
return;
}
-
- }
-
-
+
}
+
}
-
}
- } finally {
- if (sipResponse.getCSeq().getMethod().equals(Request.INVITE)
- && transaction instanceof ClientTransaction && this.getState() != DialogState.TERMINATED) {
- this.acquireTimerTaskSem();
- try {
- if (this.getState() == DialogState.EARLY) {
- if (this.earlyStateTimerTask != null) {
- sipStack.getTimer()
- .cancel(this.earlyStateTimerTask);
- }
- logger.logDebug(
- "EarlyStateTimerTask craeted "
- + this.earlyDialogTimeout * 1000);
- this.earlyStateTimerTask = new EarlyStateTimerTask();
- if (sipStack.getTimer() != null && sipStack.getTimer().isStarted() ) {
- sipStack.getTimer().schedule(this.earlyStateTimerTask,
- this.earlyDialogTimeout * 1000);
- }
- } else {
- if (this.earlyStateTimerTask != null) {
- sipStack.getTimer()
- .cancel(this.earlyStateTimerTask);
- this.earlyStateTimerTask = null;
- }
- }
- } finally {
- this.releaseTimerTaskSem();
- }
- }
}
}
@@ -3528,19 +2904,14 @@ && getState() != DialogState.CONFIRMED) {
/**
* Start the retransmit timer.
*
- * @param sipServerTx
- * -- server transaction on which the response was sent
- * @param response
- * - response that was sent.
+ * @param sipServerTx -- server transaction on which the response was sent
+ * @param response - response that was sent.
*/
- public void startRetransmitTimer(SIPServerTransaction sipServerTx,
- Response response) {
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- logger.logDebug(
- "startRetransmitTimer() " + response.getStatusCode()
- + " method " + sipServerTx.getMethod());
- }
- if (sipServerTx.isInviteTransaction()
+ public void startRetransmitTimer(SIPServerTransaction sipServerTx, Response response) {
+ if (sipStack.getStackLogger().isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
+ sipStack.getStackLogger().logDebug("startRetransmitTimer() "+ response.getStatusCode() + " method " + sipServerTx.getRequest().getMethod() );
+ }
+ if (sipServerTx.getRequest().getMethod().equals(Request.INVITE)
&& response.getStatusCode() / 100 == 2) {
this.startTimer(sipServerTx);
}
@@ -3549,32 +2920,31 @@ public void startRetransmitTimer(SIPServerTransaction sipServerTx,
/**
* @return -- the last response associated with the dialog.
*/
- // public SIPResponse getLastResponse() {
- //
- // return lastResponse;
- // }
+ public SIPResponse getLastResponse() {
+
+ return lastResponse;
+ }
+
/**
* Do taget refresh dialog state updates.
*
- * RFC 3261: Requests within a dialog MAY contain Record-Route and Contact
- * header fields. However, these requests do not cause the dialog's route
- * set to be modified, although they may modify the remote target URI.
- * Specifically, requests that are not target refresh requests do not modify
- * the dialog's remote target URI, and requests that are target refresh
+ * RFC 3261: Requests within a dialog MAY contain Record-Route and Contact header fields.
+ * However, these requests do not cause the dialog's route set to be modified, although they
+ * may modify the remote target URI. Specifically, requests that are not target refresh
+ * requests do not modify the dialog's remote target URI, and requests that are target refresh
* requests do. For dialogs that have been established with an
*
- * INVITE, the only target refresh request defined is re-INVITE (see Section
- * 14). Other extensions may define different target refresh requests for
- * dialogs established in other ways.
+ * INVITE, the only target refresh request defined is re-INVITE (see Section 14). Other
+ * extensions may define different target refresh requests for dialogs established in other
+ * ways.
*/
private void doTargetRefresh(SIPMessage sipMessage) {
ContactList contactList = sipMessage.getContactHeaders();
/*
- * INVITE is the target refresh for INVITE dialogs. SUBSCRIBE is the
- * target refresh for subscribe dialogs from the client side. This
- * modifies the remote target URI potentially
+ * INVITE is the target refresh for INVITE dialogs. SUBSCRIBE is the target refresh for
+ * subscribe dialogs from the client side. This modifies the remote target URI potentially
*/
if (contactList != null) {
@@ -3607,11 +2977,10 @@ public Response createReliableProvisionalResponse(int statusCode)
}
/*
- * A UAS MUST NOT attempt to send a 100 (Trying) response reliably. Only
- * provisional responses numbered 101 to 199 may be sent reliably. If
- * the request did not include either a Supported or Require header
- * field indicating this feature, the UAS MUST NOT send the provisional
- * response reliably.
+ * A UAS MUST NOT attempt to send a 100 (Trying) response reliably. Only provisional
+ * responses numbered 101 to 199 may be sent reliably. If the request did not include
+ * either a Supported or Require header field indicating this feature, the UAS MUST NOT
+ * send the provisional response reliably.
*/
if (statusCode <= 100 || statusCode > 199)
throw new InvalidArgumentException("Bad status code ");
@@ -3623,22 +2992,20 @@ public Response createReliableProvisionalResponse(int statusCode)
if (list == null || !optionPresent(list, "100rel")) {
list = request.getHeaders(RequireHeader.NAME);
if (list == null || !optionPresent(list, "100rel")) {
- throw new SipException(
- "No Supported/Require 100rel header in the request");
+ throw new SipException("No Supported/Require 100rel header in the request");
}
}
SIPResponse response = request.createResponse(statusCode);
/*
- * The provisional response to be sent reliably is constructed by the
- * UAS core according to the procedures of Section 8.2.6 of RFC 3261. In
- * addition, it MUST contain a Require header field containing the
- * option tag 100rel, and MUST include an RSeq header field. The value
- * of the header field for the first reliable provisional response in a
- * transaction MUST be between 1 and 231 - 1. It is RECOMMENDED that it
- * be chosen uniformly in this range. The RSeq numbering space is within
- * a single transaction. This means that provisional responses for
- * different requests MAY use the same values for the RSeq number.
+ * The provisional response to be sent reliably is constructed by the UAS core according
+ * to the procedures of Section 8.2.6 of RFC 3261. In addition, it MUST contain a Require
+ * header field containing the option tag 100rel, and MUST include an RSeq header field.
+ * The value of the header field for the first reliable provisional response in a
+ * transaction MUST be between 1 and 2**31 - 1. It is RECOMMENDED that it be chosen
+ * uniformly in this range. The RSeq numbering space is within a single transaction. This
+ * means that provisional responses for different requests MAY use the same values for the
+ * RSeq number.
*/
Require require = new Require();
try {
@@ -3649,15 +3016,13 @@ public Response createReliableProvisionalResponse(int statusCode)
response.addHeader(require);
RSeq rseq = new RSeq();
/*
- * set an arbitrary sequence number. This is actually set when the
- * response is sent out
+ * set an arbitrary sequence number. This is actually set when the response is sent out
*/
rseq.setSeqNumber(1L);
/*
- * Copy the record route headers from the request to the response (
- * Issue 160 ). Note that other 1xx headers do not get their Record
- * Route headers copied over but reliable provisional responses do. See
- * RFC 3262 Table 2.
+ * Copy the record route headers from the request to the response ( Issue 160 ). Note that
+ * other 1xx headers do not get their Record Route headers copied over but reliable
+ * provisional responses do. See RFC 3262 Table 2.
*/
RecordRouteList rrl = request.getRecordRouteHeaders();
if (rrl != null) {
@@ -3672,65 +3037,61 @@ public Response createReliableProvisionalResponse(int statusCode)
* Do the processing necessary for the PRACK
*
* @param prackRequest
- * @return true if this is the first time the tx has seen the prack ( and
- * hence needs to be passed up to the TU)
+ * @return true if this is the first time the tx has seen the prack ( and hence needs to be
+ * passed up to the TU)
*/
public boolean handlePrack(SIPRequest prackRequest) {
/*
- * The RAck header is sent in a PRACK request to support reliability of
- * provisional responses. It contains two numbers and a method tag. The
- * first number is the value from the RSeq header in the provisional
- * response that is being acknowledged. The next number, and the method,
- * are copied from the CSeq in the response that is being acknowledged.
- * The method name in the RAck header is case sensitive.
+ * The RAck header is sent in a PRACK request to support reliability of provisional
+ * responses. It contains two numbers and a method tag. The first number is the value from
+ * the RSeq header in the provisional response that is being acknowledged. The next
+ * number, and the method, are copied from the CSeq in the response that is being
+ * acknowledged. The method name in the RAck header is case sensitive.
*/
if (!this.isServer()) {
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG))
- logger.logDebug(
- "Dropping Prack -- not a server Dialog");
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG))
+ sipStack.getStackLogger().logDebug("Dropping Prack -- not a server Dialog");
return false;
}
SIPServerTransaction sipServerTransaction = (SIPServerTransaction) this
- .getFirstTransactionInt();
- byte[] sipResponse = sipServerTransaction
- .getReliableProvisionalResponse();
+ .getFirstTransaction();
+ SIPResponse sipResponse = sipServerTransaction.getReliableProvisionalResponse();
if (sipResponse == null) {
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG))
- logger.logDebug(
- "Dropping Prack -- ReliableResponse not found");
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG))
+ sipStack.getStackLogger()
+ .logDebug("Dropping Prack -- ReliableResponse not found");
return false;
}
RAck rack = (RAck) prackRequest.getHeader(RAckHeader.NAME);
if (rack == null) {
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG))
- logger.logDebug(
- "Dropping Prack -- rack header not found");
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG))
+ sipStack.getStackLogger().logDebug("Dropping Prack -- rack header not found");
return false;
}
+ CSeq cseq = (CSeq) sipResponse.getCSeq();
- if (!rack.getMethod().equals(
- sipServerTransaction.getPendingReliableResponseMethod())) {
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG))
- logger.logDebug(
+ if (!rack.getMethod().equals(cseq.getMethod())) {
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG))
+ sipStack.getStackLogger().logDebug(
"Dropping Prack -- CSeq Header does not match PRACK");
return false;
}
- if (rack.getCSeqNumberLong() != sipServerTransaction
- .getPendingReliableCSeqNumber()) {
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG))
- logger.logDebug(
+ if (rack.getCSeqNumberLong() != cseq.getSeqNumber()) {
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG))
+ sipStack.getStackLogger().logDebug(
"Dropping Prack -- CSeq Header does not match PRACK");
return false;
}
- if (rack.getRSequenceNumber() != sipServerTransaction
- .getPendingReliableRSeqNumber()) {
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG))
- logger.logDebug(
+ RSeq rseq = (RSeq) sipResponse.getHeader(RSeqHeader.NAME);
+
+ if (rack.getRSequenceNumber() != rseq.getSeqNumber()) {
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG))
+ sipStack.getStackLogger().logDebug(
"Dropping Prack -- RSeq Header does not match PRACK");
return false;
}
@@ -3741,12 +3102,9 @@ public boolean handlePrack(SIPRequest prackRequest) {
/*
* (non-Javadoc)
*
- * @see
- * javax.sip.Dialog#sendReliableProvisionalResponse(javax.sip.message.Response
- * )
+ * @see javax.sip.Dialog#sendReliableProvisionalResponse(javax.sip.message.Response)
*/
- public void sendReliableProvisionalResponse(Response relResponse)
- throws SipException {
+ public void sendReliableProvisionalResponse(Response relResponse) throws SipException {
if (!this.isServer()) {
throw new SipException("Not a Server Dialog");
}
@@ -3754,8 +3112,7 @@ public void sendReliableProvisionalResponse(Response relResponse)
SIPResponse sipResponse = (SIPResponse) relResponse;
if (relResponse.getStatusCode() == 100)
- throw new SipException(
- "Cannot send 100 as a reliable provisional response");
+ throw new SipException("Cannot send 100 as a reliable provisional response");
if (relResponse.getStatusCode() / 100 > 2)
throw new SipException(
@@ -3768,8 +3125,7 @@ public void sendReliableProvisionalResponse(Response relResponse)
throw new SipException(
"Badly formatted response -- To tag mandatory for Reliable Provisional Response");
}
- ListIterator requireList = (ListIterator) relResponse
- .getHeaders(RequireHeader.NAME);
+ ListIterator requireList = (ListIterator) relResponse.getHeaders(RequireHeader.NAME);
boolean found = false;
if (requireList != null) {
@@ -3785,19 +3141,18 @@ public void sendReliableProvisionalResponse(Response relResponse)
if (!found) {
Require require = new Require("100rel");
relResponse.addHeader(require);
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- logger
- .logDebug(
- "Require header with optionTag 100rel is needed -- adding one");
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
+ sipStack.getStackLogger().logDebug(
+ "Require header with optionTag 100rel is needed -- adding one");
}
}
SIPServerTransaction serverTransaction = (SIPServerTransaction) this
- .getFirstTransactionInt();
+ .getFirstTransaction();
/*
- * put into the dialog table before sending the response so as to avoid
- * race condition with PRACK
+ * put into the dialog table before sending the response so as to avoid race condition
+ * with PRACK
*/
this.setLastResponse(serverTransaction, sipResponse);
@@ -3820,8 +3175,8 @@ public void terminateOnBye(boolean terminateFlag) throws SipException {
}
/**
- * Set the "assigned" flag to true. We do this when inserting the dialog
- * into the dialog table of the stack.
+ * Set the "assigned" flag to true. We do this when inserting the dialog into the dialog table
+ * of the stack.
*
*/
public void setAssigned() {
@@ -3838,154 +3193,136 @@ public boolean isAssigned() {
}
/**
- * Get the contact header that the owner of this dialog assigned. Subsequent
- * Requests are considered to belong to the dialog if the dialog identifier
- * matches and the contact header matches the ip address and port on which
- * the request is received.
+ * Get the contact header that the owner of this dialog assigned. Subsequent Requests are
+ * considered to belong to the dialog if the dialog identifier matches and the contact header
+ * matches the ip address and port on which the request is received.
*
* @return contact header belonging to the dialog.
*/
public Contact getMyContactHeader() {
- if (contactHeader == null && contactHeaderStringified != null) {
- try {
- this.contactHeader = (Contact) new ContactParser(
- contactHeaderStringified).parse();
- } catch (ParseException e) {
- logger.logError(
- "error reparsing the contact header", e);
- }
- }
- return contactHeader;
+ return contactHeader;
}
/**
* Do the necessary processing to handle an ACK directed at this Dialog.
*
- * @param ackTransaction
- * -- the ACK transaction that was directed at this dialog.
- * @return -- true if the ACK was successfully consumed by the Dialog and
- * resulted in the dialog state being changed.
+ * @param ackTransaction -- the ACK transaction that was directed at this dialog.
+ * @return -- true if the ACK was successfully consumed by the Dialog and resulted in the
+ * dialog state being changed.
*/
public boolean handleAck(SIPServerTransaction ackTransaction) {
- // SIPRequest sipRequest = ackTransaction.getOriginalRequest();
+ SIPRequest sipRequest = ackTransaction.getOriginalRequest();
- if (isAckSeen() && getRemoteSeqNumber() == ackTransaction.getCSeq()) {
+ if (isAckSeen() && getRemoteSeqNumber() == sipRequest.getCSeq().getSeqNumber()) {
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- logger.logDebug(
- "ACK already seen by dialog -- dropping Ack"
- + " retransmission");
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
+ sipStack.getStackLogger().logDebug(
+ "ACK already seen by dialog -- dropping Ack" + " retransmission");
}
acquireTimerTaskSem();
try {
- if (this.timerTask != null) {
- this.getStack().getTimer().cancel(timerTask);
- this.timerTask = null;
- }
+ if (this.timerTask != null) {
+ this.timerTask.cancel();
+ this.timerTask = null;
+ }
} finally {
- releaseTimerTaskSem();
- }
+ releaseTimerTaskSem();
+ }
return false;
} else if (this.getState() == DialogState.TERMINATED) {
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG))
- logger.logDebug(
- "Dialog is terminated -- dropping ACK");
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG))
+ sipStack.getStackLogger().logDebug("Dialog is terminated -- dropping ACK");
return false;
} else {
- if (lastResponseStatusCode != null
- && lastResponseStatusCode.intValue() / 100 == 2
- && lastResponseMethod.equals(Request.INVITE)
- && lastResponseCSeqNumber == ackTransaction.getCSeq()) {
+ /*
+ * This could be a re-invite processing. check to see if the ack matches with the last
+ * transaction. s
+ */
+
+ SIPServerTransaction tr = getInviteTransaction();
- ackTransaction.setDialog(this, lastResponseDialogId);
+ SIPResponse sipResponse = (tr != null ? tr.getLastResponse() : null);
+
+ // Idiot check for sending ACK from the wrong side!
+ if (tr != null
+ && sipResponse != null
+ && sipResponse.getStatusCode() / 100 == 2
+ && sipResponse.getCSeq().getMethod().equals(Request.INVITE)
+ && sipResponse.getCSeq().getSeqNumber() == sipRequest.getCSeq()
+ .getSeqNumber()) {
+
+ ackTransaction.setDialog(this, sipResponse.getDialogId(false));
/*
* record that we already saw an ACK for this dialog.
*/
- ackReceived(ackTransaction.getCSeq());
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG))
- logger.logDebug(
- "ACK for 2XX response --- sending to TU ");
+
+ ackReceived(sipRequest);
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG))
+ sipStack.getStackLogger().logDebug("ACK for 2XX response --- sending to TU ");
return true;
} else {
- /*
- * This happens when the ACK is re-transmitted and arrives too
- * late to be processed.
+ /*
+ * This happens when the ACK is re-transmitted and arrives too late to be
+ * processed.
*/
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG))
- logger.logDebug(
- " INVITE transaction not found");
- if ( this.isBackToBackUserAgent() ) {
- this.releaseAckSem();
- }
- return true;
-
+
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG))
+ sipStack.getStackLogger().logDebug(
+ " INVITE transaction not found -- Discarding ACK");
+ return false;
}
}
}
+ void setEarlyDialogId(String earlyDialogId) {
+ this.earlyDialogId = earlyDialogId;
+ }
+
String getEarlyDialogId() {
return earlyDialogId;
}
/**
- * Release the semaphore for ACK processing so the next re-INVITE may
- * proceed.
+ * Release the semaphore for ACK processing so the next re-INVITE may proceed.
*/
void releaseAckSem() {
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- logger
- .logDebug("releaseAckSem-enter]]" + this + " sem=" + this.ackSem + " b2bua=" + this.isBackToBackUserAgent);
- logger.logStackTrace();
- }
if (this.isBackToBackUserAgent) {
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- logger
- .logDebug("releaseAckSem]]" + this + " sem=" + this.ackSem);
- logger.logStackTrace();
- }
- if (this.ackSem.availablePermits() == 0 ) {
- this.ackSem.release();
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- logger
- .logDebug("releaseAckSem]]" + this + " sem=" + this.ackSem);
- }
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
+ sipStack.getStackLogger().logDebug("releaseAckSem]" + this);
}
+ this.ackSem.release();
}
+
}
boolean takeAckSem() {
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- logger.logDebug("[takeAckSem " + this + " sem=" + this.ackSem);
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
+ sipStack.getStackLogger().logDebug("[takeAckSem " + this);
}
try {
-
if (!this.ackSem.tryAcquire(2, TimeUnit.SECONDS)) {
- if (logger.isLoggingEnabled()) {
- logger.logError(
- "Cannot aquire ACK semaphore ");
+ if (sipStack.isLoggingEnabled()) {
+ sipStack.getStackLogger().logError("Cannot aquire ACK semaphore");
}
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- logger.logDebug(
- "Semaphore previously acquired at "
- + this.stackTrace + " sem=" + this.ackSem);
- logger.logStackTrace();
-
+ if ( sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG) ) {
+ sipStack.getStackLogger().logDebug("Semaphore previously acquired at " + this.stackTrace);
+ sipStack.getStackLogger().logStackTrace();
+
}
return false;
}
-
- if (logger.isLoggingEnabled(
- StackLogger.TRACE_DEBUG)) {
-
+
+ if ( sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG) ) {
+
this.recordStackTrace();
}
-
+
} catch (InterruptedException ex) {
- logger.logError("Cannot aquire ACK semaphore");
+ sipStack.getStackLogger().logError("Cannot aquire ACK semaphore");
return false;
}
@@ -3994,14 +3331,26 @@ boolean takeAckSem() {
}
/**
- * @param lastAckSent
- * the lastAckSent to set
+ * @param lastAckReceived the lastAckReceived to set
+ */
+ private void setLastAckReceived(SIPRequest lastAckReceived) {
+ this.lastAckReceived = lastAckReceived;
+ }
+
+ /**
+ * @return the lastAckReceived
+ */
+ protected SIPRequest getLastAckReceived() {
+ return lastAckReceived;
+ }
+
+ /**
+ * @param lastAckSent the lastAckSent to set
*/
private void setLastAckSent(SIPRequest lastAckSent) {
this.lastAckSent = lastAckSent;
- this.lastAckSent.setTransaction(null); // null out the associated Tx (release memory)
}
-
+
/**
* @return true if an ack was ever sent for this Dialog
*/
@@ -4009,264 +3358,109 @@ public boolean isAtleastOneAckSent() {
return this.isAcknowledged;
}
+
+
public boolean isBackToBackUserAgent() {
return this.isBackToBackUserAgent;
}
-
+
public synchronized void doDeferredDeleteIfNoAckSent(long seqno) {
- if (sipStack.getTimer() == null) {
- this.setState(TERMINATED_STATE);
- } else if (dialogDeleteIfNoAckSentTask == null) {
- // Delete the transaction after the max ack timeout.
- dialogDeleteIfNoAckSentTask = new DialogDeleteIfNoAckSentTask(seqno);
- if (sipStack.getTimer() != null && sipStack.getTimer().isStarted()) {
- sipStack.getTimer().schedule(
- dialogDeleteIfNoAckSentTask,
- sipStack.getAckTimeoutFactor()
- * SIPTransactionStack.BASE_TIMER_INTERVAL);
- }
- }
- }
+ if (sipStack.getTimer() == null) {
+ this.setState(TERMINATED_STATE);
+ } else if(dialogDeleteIfNoAckSentTask == null){
+ // Delete the transaction after the max ack timeout.
+ dialogDeleteIfNoAckSentTask = new DialogDeleteIfNoAckSentTask(seqno);
+ sipStack.getTimer().schedule(
+ dialogDeleteIfNoAckSentTask,
+ sipStack.getAckTimeoutFactor()
+ * SIPTransactionStack.BASE_TIMER_INTERVAL);
+ }
+ }
/*
* (non-Javadoc)
- *
* @see gov.nist.javax.sip.DialogExt#setBackToBackUserAgent(boolean)
*/
public void setBackToBackUserAgent() {
- this.isBackToBackUserAgent = true;
- }
-
- /**
- * @return the eventHeader
- */
- EventHeader getEventHeader() {
- return eventHeader;
- }
-
- /**
- * @param eventHeader
- * the eventHeader to set
- */
- void setEventHeader(EventHeader eventHeader) {
- this.eventHeader = eventHeader;
- }
-
- /**
- * @param serverTransactionFlag
- * the serverTransactionFlag to set
- */
- void setServerTransactionFlag(boolean serverTransactionFlag) {
- this.serverTransactionFlag = serverTransactionFlag;
- }
-
- /**
- * @param reInviteFlag
- * the reinviteFlag to set
- */
- protected void setReInviteFlag(boolean reInviteFlag) {
- this.reInviteFlag = reInviteFlag;
- }
-
- public boolean isSequnceNumberValidation() {
- return this.sequenceNumberValidation;
- }
-
+ this.isBackToBackUserAgent = true;
+ }
+
+ /**
+ * @return the eventHeader
+ */
+ EventHeader getEventHeader() {
+ return eventHeader;
+ }
+
+ /**
+ * @param eventHeader the eventHeader to set
+ */
+ void setEventHeader(EventHeader eventHeader) {
+ this.eventHeader = eventHeader;
+ }
+
+ /**
+ * @param serverTransactionFlag the serverTransactionFlag to set
+ */
+ void setServerTransactionFlag(boolean serverTransactionFlag) {
+ this.serverTransactionFlag = serverTransactionFlag;
+ }
+
+ /**
+ * @param reInviteFlag the reinviteFlag to set
+ */
+ void setReInviteFlag(boolean reInviteFlag) {
+ this.reInviteFlag = reInviteFlag;
+ }
+
+
+ public boolean isSequnceNumberValidation() {
+ return this.sequenceNumberValidation;
+ }
+
public void disableSequenceNumberValidation() {
this.sequenceNumberValidation = false;
}
-
+
+
public void acquireTimerTaskSem() {
- boolean acquired = false;
+ boolean acquired = false;
try {
acquired = this.timerTaskLock.tryAcquire(10, TimeUnit.SECONDS);
- } catch (InterruptedException ex) {
+ } catch ( InterruptedException ex) {
acquired = false;
}
- if (!acquired) {
- throw new IllegalStateException(
- "Impossible to acquire the dialog timer task lock");
+ if(!acquired) {
+ throw new IllegalStateException("Impossible to acquire the dialog timer task lock");
}
}
-
+
public void releaseTimerTaskSem() {
this.timerTaskLock.release();
}
- public String getMergeId() {
- return this.firstTransactionMergeId;
- }
-
- public void setPendingRouteUpdateOn202Response(SIPRequest sipRequest) {
- this.pendingRouteUpdateOn202Response = true;
- String toTag = sipRequest.getToHeader().getTag();
- if (toTag != null) {
- this.setRemoteTag(toTag);
- }
-
- }
-
- public String getLastResponseMethod() {
- return lastResponseMethod;
- }
-
- public Integer getLastResponseStatusCode() {
- return lastResponseStatusCode;
- }
-
- public long getLastResponseCSeqNumber() {
- return lastResponseCSeqNumber;
- }
-
- // jeand cleanup the dialog from the data not needed anymore upon receiving
- // or sending an ACK
- // to save on mem
- protected void cleanUpOnAck() {
- if (isReleaseReferences()) {
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- logger.logDebug(
- "cleanupOnAck : " + getDialogId());
- }
- if (originalRequest != null) {
- if (originalRequestRecordRouteHeaders != null) {
- originalRequestRecordRouteHeadersString = originalRequestRecordRouteHeaders
- .toString();
- }
- originalRequestRecordRouteHeaders = null;
- originalRequest = null;
- }
- if (firstTransaction != null) {
- if (firstTransaction.getOriginalRequest() != null) {
- firstTransaction.getOriginalRequest().cleanUp();
- }
- firstTransaction = null;
- }
- if (lastTransaction != null) {
- if (lastTransaction.getOriginalRequest() != null) {
- lastTransaction.getOriginalRequest().cleanUp();
- }
- lastTransaction = null;
- }
- if (callIdHeader != null) {
- callIdHeaderString = callIdHeader.toString();
- callIdHeader = null;
- }
- if (contactHeader != null) {
- contactHeaderStringified = contactHeader.toString();
- contactHeader = null;
- }
- if (remoteTarget != null) {
- remoteTargetStringified = remoteTarget.toString();
- remoteTarget = null;
- }
- if (remoteParty != null) {
- remotePartyStringified = remoteParty.toString();
- remoteParty = null;
- }
- if (localParty != null) {
- localPartyStringified = localParty.toString();
- localParty = null;
- }
- }
- }
-
- /**
- * Release references so the GC can clean up dialog state.
- *
- */
- protected void cleanUp() {
- if (isReleaseReferences()) {
- cleanUpOnAck();
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- logger
- .logDebug("dialog cleanup : " + getDialogId());
- }
- if (eventListeners != null) {
- eventListeners.clear();
- }
- timerTaskLock = null;
- ackSem = null;
- contactHeader = null;
- eventHeader = null;
- firstTransactionId = null;
- firstTransactionMethod = null;
- // Cannot clear up the last Ack Sent. until DIALOG is terminated.
-
- // lastAckReceivedCSeqNumber = null;
- lastResponseDialogId = null;
- lastResponseMethod = null;
- lastResponseTopMostVia = null;
- if (originalRequestRecordRouteHeaders != null) {
- originalRequestRecordRouteHeaders.clear();
- originalRequestRecordRouteHeaders = null;
- originalRequestRecordRouteHeadersString = null;
- }
- if (routeList != null) {
- routeList.clear();
- routeList = null;
- }
- responsesReceivedInForkingCase.clear();
- }
- }
-
- protected RecordRouteList getOriginalRequestRecordRouteHeaders() {
- if (originalRequestRecordRouteHeaders == null
- && originalRequestRecordRouteHeadersString != null) {
- try {
- originalRequestRecordRouteHeaders = (RecordRouteList) new RecordRouteParser(
- originalRequestRecordRouteHeadersString).parse();
- } catch (ParseException e) {
- logger
- .logError(
- "error reparsing the originalRequest RecordRoute Headers",
- e);
- }
- originalRequestRecordRouteHeadersString = null;
- }
- return originalRequestRecordRouteHeaders;
- }
-
- /**
- * @return the lastResponseTopMostVia
- */
- public Via getLastResponseTopMostVia() {
- return lastResponseTopMostVia;
- }
-
- /*
- * (non-Javadoc)
- *
- * @see gov.nist.javax.sip.DialogExt#isReleaseReferences()
- */
- public boolean isReleaseReferences() {
- return releaseReferences;
- }
-
- /*
- * (non-Javadoc)
- *
- * @see gov.nist.javax.sip.DialogExt#setReleaseReferences(boolean)
- */
- public void setReleaseReferences(boolean releaseReferences) {
- this.releaseReferences = releaseReferences;
- }
-
- public void setEarlyDialogTimeoutSeconds(int seconds) {
- if (seconds <= 0) {
- throw new IllegalArgumentException("Invalid value " + seconds);
- }
- this.earlyDialogTimeout = seconds;
- }
-
- public void checkRetransmissionForForking(SIPResponse response) {
- final int statusCode = response.getStatusCode();
- final String responseMethod = response.getCSeqHeader().getMethod();
- final long responseCSeqNumber = response.getCSeq().getSeqNumber();
- boolean isRetransmission = !responsesReceivedInForkingCase.add(statusCode + "/" + responseCSeqNumber + "/" + responseMethod);
- response.setRetransmission(isRetransmission);
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- logger.logDebug(
- "marking response as retransmission " + isRetransmission + " for dialog " + this);
- }
- }
+
+
+ public String getMergeId( ) {
+ return this.firstTransactionMergeId;
+ }
+
+ public void setPendingRouteUpdateOn202Response(SIPRequest sipRequest) {
+ this.pendingRouteUpdateOn202Response = true;
+ String toTag = sipRequest.getToHeader().getTag();
+ if ( toTag != null ) {
+ this.setRemoteTag(toTag);
+ }
+
+ }
+
+ /**
+ * @return the lastResponseTopMostVia
+ */
+ public Via getLastResponseTopMostVia() {
+ if(lastResponse == null)
+ return null;
+ return lastResponse.getTopmostVia();
+ }
+
}
diff --git a/src/gov/nist/javax/sip/stack/SIPDialogErrorEvent.java b/src/gov/nist/javax/sip/stack/SIPDialogErrorEvent.java
index d9846c727..5379cd439 100644
--- a/src/gov/nist/javax/sip/stack/SIPDialogErrorEvent.java
+++ b/src/gov/nist/javax/sip/stack/SIPDialogErrorEvent.java
@@ -45,15 +45,10 @@ public class SIPDialogErrorEvent extends EventObject {
*/
public static final int DIALOG_REINVITE_TIMEOUT = 3;
- /*
- * Dialog in early state for too long.
- */
- public static final int EARLY_STATE_TIMEOUT = 4;
-
/*
* This event Id indicates that some internal error happened and the ACK semaphore could not be acquired.
*/
- public static final int DIALOG_ERROR_INTERNAL_COULD_NOT_TAKE_ACK_SEM = 5;
+ public static final int DIALOG_ERROR_INTERNAL_COULD_NOT_TAKE_ACK_SEM = 4;
// ID of this error event
@@ -84,8 +79,6 @@ public SIPDialogErrorEvent (SIPDialog sourceDialog, DialogTimeoutEvent.Reason re
this.errorID = DIALOG_REINVITE_TIMEOUT;
} else if (reason == DialogTimeoutEvent.Reason.CannotAcquireAckSemaphoreForOk) {
this.errorID = DIALOG_ERROR_INTERNAL_COULD_NOT_TAKE_ACK_SEM;
- } else if ( reason == DialogTimeoutEvent.Reason.EarlyStateTimeout) {
- this.errorID = EARLY_STATE_TIMEOUT;
}
}
diff --git a/src/gov/nist/javax/sip/stack/SIPMessageValve.java b/src/gov/nist/javax/sip/stack/SIPMessageValve.java
deleted file mode 100644
index b5e6d9a3b..000000000
--- a/src/gov/nist/javax/sip/stack/SIPMessageValve.java
+++ /dev/null
@@ -1,52 +0,0 @@
-package gov.nist.javax.sip.stack;
-
-import javax.sip.SipStack;
-import javax.sip.message.Request;
-import javax.sip.message.Response;
-
-import gov.nist.javax.sip.message.SIPRequest;
-
-/**
- * This interface has callbacks that are notified for every SIP message arriving at the container.
- * The callbacks occurs before any significant long-lived resources are allocated for this call, thus
- * it gives a chance to the application to pre-process the message and filter based on some
- * application-specific algorithm. Creating and sending a stateless response is also allowed.
- *
- * It is useful for congestion control or header re-writing.
- *
- * @author Vladimir Ralev
- *
- */
-public interface SIPMessageValve {
- /**
- * The callback method that is called for every request before any transaction/dialog mapping
- * or allocation occur.
- *
- * @param request
- * @param messageChannel
- * @return
- */
- public boolean processRequest(SIPRequest request, MessageChannel messageChannel);
-
- /**
- * The callback method that is called for every response before any transaction/dialog mapping
- * or allocation occur.
- *
- * @param response
- * @param messageChannel
- * @return
- */
- public boolean processResponse(Response response, MessageChannel messageChannel);
-
- /**
- * This method is called when the valve is initialized. You can perform any initialization here.
- *
- * @param stack
- */
- public void init(SipStack stack);
-
- /**
- * This method is called when the valve is about to be destroyed. You can perform any cleanup here.
- */
- public void destroy();
-}
diff --git a/src/gov/nist/javax/sip/stack/SIPServerTransaction.java b/src/gov/nist/javax/sip/stack/SIPServerTransaction.java
index c9e32a121..8a22efffe 100755
--- a/src/gov/nist/javax/sip/stack/SIPServerTransaction.java
+++ b/src/gov/nist/javax/sip/stack/SIPServerTransaction.java
@@ -25,12 +25,8 @@
*/
package gov.nist.javax.sip.stack;
-import gov.nist.core.CommonLogger;
-import gov.nist.core.HostPort;
import gov.nist.core.InternalErrorHandler;
import gov.nist.core.LogWriter;
-import gov.nist.core.ServerLogger;
-import gov.nist.core.StackLogger;
import gov.nist.javax.sip.SIPConstants;
import gov.nist.javax.sip.ServerTransactionExt;
import gov.nist.javax.sip.SipProviderImpl;
@@ -39,14 +35,15 @@
import gov.nist.javax.sip.header.ParameterNames;
import gov.nist.javax.sip.header.RSeq;
import gov.nist.javax.sip.header.Via;
+import gov.nist.javax.sip.header.ViaList;
import gov.nist.javax.sip.message.SIPMessage;
import gov.nist.javax.sip.message.SIPRequest;
import gov.nist.javax.sip.message.SIPResponse;
-import gov.nist.javax.sip.stack.IllegalTransactionStateException.Reason;
+import gov.nist.javax.sip.stack.SIPTransaction.LingerTimer;
import java.io.IOException;
-import java.net.InetAddress;
import java.text.ParseException;
+import java.util.TimerTask;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
@@ -60,7 +57,6 @@
import javax.sip.TransactionState;
import javax.sip.address.Hop;
import javax.sip.header.ContactHeader;
-import javax.sip.header.ContentTypeHeader;
import javax.sip.header.ExpiresHeader;
import javax.sip.header.RSeqHeader;
import javax.sip.message.Request;
@@ -172,18 +168,16 @@
*
*
*
- * @version 1.2 $Revision: 1.150 $ $Date: 2010-12-02 22:04:15 $
+ * @version 1.2 $Revision: 1.124.2.2 $ $Date: 2010-11-23 19:23:13 $
* @author M. Ranganathan
*
*/
public class SIPServerTransaction extends SIPTransaction implements ServerRequestInterface,
javax.sip.ServerTransaction, ServerTransactionExt {
- private static StackLogger logger = CommonLogger.getLogger(SIPServerTransaction.class);
- public static final String CONTENT_TYPE_APPLICATION = "application";
- public static final String CONTENT_SUBTYPE_SDP = "sdp";
+
// force the listener to see transaction
- private int rseqNumber = -1;
+ private int rseqNumber;
// private LinkedList pendingRequests;
@@ -191,17 +185,10 @@ public class SIPServerTransaction extends SIPTransaction implements ServerReques
private transient ServerRequestInterface requestOf;
private SIPDialog dialog;
- // jeand needed because we nullify the dialog ref early and keep only the dialogId to save on mem and help GC
- protected String dialogId;
// the unacknowledged SIPResponse
-// private SIPResponse pendingReliableResponse;
- // wondering if the pendingReliableResponseAsBytes could be put into the lastResponseAsBytes
- private byte[] pendingReliableResponseAsBytes;
- private String pendingReliableResponseMethod;
- private long pendingReliableCSeqNumber;
- private long pendingReliableRSeqNumber;
+ private SIPResponse pendingReliableResponse;
// The pending reliable Response Timer
private ProvisionalResponseTask provisionalResponseTask;
@@ -217,23 +204,12 @@ public class SIPServerTransaction extends SIPTransaction implements ServerReques
private SIPClientTransaction pendingSubscribeTransaction;
private SIPServerTransaction inviteTransaction;
-
+
// Experimental.
private static boolean interlockProvisionalResponses = true;
-
+
private Semaphore provisionalResponseSem = new Semaphore(1);
- // jeand we nullify the last response fast to save on mem and help GC, but we keep only the information needed
- private byte[] lastResponseAsBytes;
- private String lastResponseHost;
- private int lastResponsePort;
- private String lastResponseTransport;
-
- private int lastResponseStatusCode;
-
- private HostPort originalRequestSentBy;
- private String originalRequestFromTag;
-
/**
* This timer task is used for alerting the application to send retransmission alerts.
*
@@ -253,7 +229,7 @@ public RetransmissionAlertTimerTask(String dialogId) {
this.ticksLeft = this.ticks;
}
- public void runTask() {
+ protected void runTask() {
SIPServerTransaction serverTransaction = SIPServerTransaction.this;
ticksLeft--;
if (ticksLeft == -1) {
@@ -276,7 +252,7 @@ public ProvisionalResponseTask() {
this.ticksLeft = this.ticks;
}
- public void runTask() {
+ protected void runTask() {
SIPServerTransaction serverTransaction = SIPServerTransaction.this;
/*
* The reliable provisional response is passed to the transaction layer periodically
@@ -292,7 +268,7 @@ public void runTask() {
// If the transaction has terminated,
if (serverTransaction.isTerminated()) {
- sipStack.getTimer().cancel(this);
+ this.cancel();
} else {
ticksLeft--;
@@ -304,8 +280,8 @@ public void runTask() {
// determines when the server
// transaction abandons retransmitting the response
if (this.ticksLeft >= SIPTransaction.TIMER_H) {
- sipStack.getTimer().cancel(this);
- setState(TransactionState._TERMINATED);
+ this.cancel();
+ setState(TERMINATED_STATE);
fireTimeoutTimer();
}
}
@@ -329,23 +305,26 @@ class ListenerExecutionMaxTimer extends SIPStackTimerTask {
ListenerExecutionMaxTimer() {
}
- public void runTask() {
+ protected void runTask() {
try {
- listenerExecutionMaxTimer = null;
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG))
- logger.logDebug("Fired ListenerExecutionMaxTimer for stx " + serverTransaction.getTransactionId() + " state " + serverTransaction.getState());
- if (serverTransaction.getInternalState() <= 1 ||
+ listenerExecutionMaxTimer = null;
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG))
+ sipStack.getStackLogger().logDebug("Fired ListenerExecutionMaxTimer for stx " + serverTransaction.getTransactionId() + " state " + serverTransaction.getState());
+ if (serverTransaction.getState() == null ||
+ serverTransaction.getState().equals(TransactionState.CALLING) ||
+ serverTransaction.getState().equals(TransactionState.TRYING) ||
// may have been forcefully TERMINATED through terminate() method but if the tx timer never got scheduled
// it wouldn't be reaped
- serverTransaction.getInternalState() >= 5) {
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG))
- logger.logDebug("ListenerExecutionMaxTimer : terminating and removing stx " + serverTransaction.getTransactionId());
+ serverTransaction.getState().equals(TransactionState.TERMINATED)) {
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG))
+ sipStack.getStackLogger().logDebug("ListenerExecutionMaxTimer : terminating and removing stx " + serverTransaction.getTransactionId());
serverTransaction.terminate();
SIPTransactionStack sipStack = serverTransaction.getSIPStack();
sipStack.removeTransaction(serverTransaction);
}
+
} catch (Exception ex) {
- logger.logError("unexpected exception", ex);
+ sipStack.getStackLogger().logError("unexpected exception", ex);
}
}
}
@@ -358,29 +337,29 @@ public void runTask() {
class SendTrying extends SIPStackTimerTask {
protected SendTrying() {
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG))
- logger.logDebug("scheduled timer for " + SIPServerTransaction.this);
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG))
+ sipStack.getStackLogger().logDebug("scheduled timer for " + SIPServerTransaction.this);
}
- public void runTask() {
+ protected void runTask() {
SIPServerTransaction serverTransaction = SIPServerTransaction.this;
- int realState = serverTransaction.getRealState();
+ TransactionState realState = serverTransaction.getRealState();
- if (realState < 0 || TransactionState._TRYING == realState) {
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG))
- logger.logDebug(" sending Trying current state = "
+ if (realState == null || TransactionState.TRYING == realState) {
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG))
+ sipStack.getStackLogger().logDebug(" sending Trying current state = "
+ serverTransaction.getRealState());
try {
serverTransaction.sendMessage(serverTransaction.getOriginalRequest()
.createResponse(100, "Trying"));
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG))
- logger.logDebug(" trying sent "
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG))
+ sipStack.getStackLogger().logDebug(" trying sent "
+ serverTransaction.getRealState());
} catch (IOException ex) {
- if (logger.isLoggingEnabled())
- logger.logError("IO error sending TRYING");
+ if (sipStack.isLoggingEnabled())
+ sipStack.getStackLogger().logError("IO error sending TRYING");
}
}
@@ -390,47 +369,45 @@ public void runTask() {
class TransactionTimer extends SIPStackTimerTask {
public TransactionTimer() {
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- logger.logDebug("TransactionTimer() : " + getTransactionId());
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
+ sipStack.getStackLogger().logDebug("TransactionTimer() : " + getTransactionId());
}
}
- public void runTask() {
+ protected void runTask() {
// If the transaction has terminated,
- if (isTerminated()) {
+ if (isTerminated()) {
// Keep the transaction hanging around in the transaction table
// to catch the incoming ACK -- this is needed for tcp only.
// Note that the transaction record is actually removed in
// the connection linger timer.
try {
- sipStack.getTimer().cancel(this);
- if(listenerExecutionMaxTimer != null) {
- sipStack.getTimer().cancel(listenerExecutionMaxTimer);
- }
+ this.cancel();
+ if(listenerExecutionMaxTimer != null) {
+ listenerExecutionMaxTimer.cancel();
+ }
} catch (IllegalStateException ex) {
if (!sipStack.isAlive())
return;
}
-
// Oneshot timer that garbage collects the SeverTransaction
// after a scheduled amount of time. The linger timer allows
// the client side of the tx to use the same connection to
// send an ACK and prevents a race condition for creation
// of new server tx
- SIPStackTimerTask myTimer = new LingerTimer();
+ TimerTask myTimer = new LingerTimer();
sipStack.getTimer().schedule(myTimer,
- SIPTransactionStack.CONNECTION_LINGER_TIME * 1000);
+ SIPTransactionStack.CONNECTION_LINGER_TIME * 1000);
+
} else {
// Add to the fire list -- needs to be moved
// outside the synchronized block to prevent
// deadlock.
fireTimer();
- }
- if(originalRequest != null) {
- originalRequest.cleanUp();
+
}
}
@@ -443,10 +420,8 @@ public void runTask() {
*
*/
- protected void sendResponse(SIPResponse transactionResponse) throws IOException {
- if ( logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- logger.logDebug("sipServerTransaction::sendResponse " + transactionResponse.getFirstLine());
- }
+ private void sendResponse(SIPResponse transactionResponse) throws IOException {
+
try {
// RFC18.2.2. Sending Responses
// The server transport uses the value of the top Via header field
@@ -464,6 +439,10 @@ protected void sendResponse(SIPResponse transactionResponse) throws IOException
getMessageChannel().sendMessage(transactionResponse);
+ // TODO If that connection attempt fails, the server SHOULD
+ // use SRV 3263 procedures
+ // for servers in order to determine the IP address
+ // and port to open the connection and send the response to.
} else {
Via via = transactionResponse.getTopmostVia();
@@ -522,18 +501,13 @@ protected void sendResponse(SIPResponse transactionResponse) throws IOException
hop.getTransport()).getIPAddress(), this.getPort(), hop);
if (messageChannel != null) {
messageChannel.sendMessage(transactionResponse);
- lastResponseHost = host;
- lastResponsePort = port;
- lastResponseTransport = transport;
} else {
throw new IOException("Could not create a message channel for " + hop + " with source IP:Port "+
- this.getSipProvider().getListeningPoint(
+ this.getSipProvider().getListeningPoint(
hop.getTransport()).getIPAddress() + ":" + this.getPort());
}
}
- lastResponseAsBytes = transactionResponse.encodeAsBytes(this.getTransport());
- lastResponse = null;
} finally {
this.startTransactionTimer();
}
@@ -550,14 +524,17 @@ protected SIPServerTransaction(SIPTransactionStack sipStack, MessageChannel newC
super(sipStack, newChannelToUse);
if (sipStack.maxListenerResponseTime != -1) {
- sipStack.getTimer().schedule(new ListenerExecutionMaxTimer(),
+ listenerExecutionMaxTimer = new ListenerExecutionMaxTimer();
+ sipStack.getTimer().schedule(listenerExecutionMaxTimer,
sipStack.maxListenerResponseTime * 1000);
}
+
+ this.rseqNumber = (int) (Math.random() * 1000);
// Only one outstanding request for a given server tx.
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- logger.logDebug("Creating Server Transaction" + this.getBranchId());
- logger.logStackTrace();
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
+ sipStack.getStackLogger().logDebug("Creating Server Transaction" + this.getBranchId());
+ sipStack.getStackLogger().logStackTrace();
}
}
@@ -582,8 +559,8 @@ public MessageChannel getResponseChannel() {
}
-
-
+
+
/**
* Determines if the message is a part of this transaction.
*
@@ -594,25 +571,29 @@ public MessageChannel getResponseChannel() {
public boolean isMessagePartOfTransaction(SIPMessage messageToTest) {
// List of Via headers in the message to test
-// ViaList viaHeaders;
-
+ 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 = false;
- final String method = messageToTest.getCSeq().getMethod();
- SIPRequest origRequest = getOriginalRequest();
+ boolean transactionMatches;
+
+ transactionMatches = false;
+
+ String method = messageToTest.getCSeq().getMethod();
// Invite Server transactions linger in the terminated state in the
// transaction
// table and are matched to compensate for
// http://bugs.sipit.net/show_bug.cgi?id=769
- if (isInviteTransaction() || !isTerminated()) {
+ if ((method.equals(Request.INVITE) || !isTerminated())) {
// Get the topmost Via header and its branch parameter
- final Via topViaHeader = messageToTest.getTopmostVia();
- if (topViaHeader != null) {
+ viaHeaders = messageToTest.getViaHeaders();
+ if (viaHeaders != null) {
-// topViaHeader = (Via) viaHeaders.getFirst();
- // Branch code in the topmost Via header
- String messageBranch = topViaHeader.getBranch();
+ topViaHeader = (Via) viaHeaders.getFirst();
+ messageBranch = topViaHeader.getBranch();
if (messageBranch != null) {
// If the branch parameter exists but
@@ -638,28 +619,20 @@ public boolean isMessagePartOfTransaction(SIPMessage messageToTest) {
transactionMatches = this.getMethod().equals(Request.CANCEL)
&& getBranch().equalsIgnoreCase(messageBranch)
&& topViaHeader.getSentBy().equals(
- origRequest.getTopmostVia()
+ ((Via) getOriginalRequest().getViaHeaders().getFirst())
.getSentBy());
} else {
// Matching server side transaction with only the
// branch parameter.
- if(origRequest != null) {
- transactionMatches = getBranch().equalsIgnoreCase(messageBranch)
+ transactionMatches = getBranch().equalsIgnoreCase(messageBranch)
&& topViaHeader.getSentBy().equals(
- origRequest.getTopmostVia()
+ ((Via) getOriginalRequest().getViaHeaders().getFirst())
.getSentBy());
- } else {
- transactionMatches = getBranch().equalsIgnoreCase(messageBranch)
- && topViaHeader.getSentBy().equals(originalRequestSentBy);
- }
}
} else {
- // force the reparsing only on non RFC 3261 messages
- origRequest = (SIPRequest) getRequest();
-
// This is an RFC2543-compliant message; this code is here
// for backwards compatibility.
// It is a weak check.
@@ -668,13 +641,13 @@ && getBranch().equalsIgnoreCase(messageBranch)
// SIPMessage matches this transaction. An exception is for
// a CANCEL request, which is not deemed
// to be part of an otherwise-matching INVITE transaction.
- String originalFromTag = origRequest.getFromTag();
+ String originalFromTag = super.fromTag;
String thisFromTag = messageToTest.getFrom().getTag();
boolean skipFrom = (originalFromTag == null || thisFromTag == null);
- String originalToTag = origRequest.getToTag();
+ String originalToTag = super.toTag;
String thisToTag = messageToTest.getTo().getTag();
@@ -684,20 +657,21 @@ && getBranch().equalsIgnoreCase(messageBranch)
// the CSeq method of the original request must
// be CANCEL for it to have a chance at matching.
if (messageToTest.getCSeq().getMethod().equalsIgnoreCase(Request.CANCEL)
- && !origRequest.getCSeq().getMethod().equalsIgnoreCase(
+ && !getOriginalRequest().getCSeq().getMethod().equalsIgnoreCase(
Request.CANCEL)) {
transactionMatches = false;
- } else if ((isResponse || origRequest.getRequestURI().equals(
+ } else if ((isResponse || getOriginalRequest().getRequestURI().equals(
((SIPRequest) messageToTest).getRequestURI()))
&& (skipFrom || originalFromTag != null && originalFromTag.equalsIgnoreCase(thisFromTag))
&& (skipTo || originalToTag != null && originalToTag.equalsIgnoreCase(thisToTag))
- && origRequest.getCallId().getCallId().equalsIgnoreCase(
+ && getOriginalRequest().getCallId().getCallId().equalsIgnoreCase(
messageToTest.getCallId().getCallId())
- && origRequest.getCSeq().getSeqNumber() == messageToTest
+ && getOriginalRequest().getCSeq().getSeqNumber() == messageToTest
.getCSeq().getSeqNumber()
- && ((!messageToTest.getCSeq().getMethod().equals(Request.CANCEL)) ||
- getMethod().equals(messageToTest.getCSeq().getMethod()))
- && topViaHeader.equals(origRequest.getTopmostVia())) {
+ && ((!messageToTest.getCSeq().getMethod().equals(Request.CANCEL)) || getOriginalRequest()
+ .getMethod().equals(messageToTest.getCSeq().getMethod()))
+ && topViaHeader.equals(getOriginalRequest().getViaHeaders()
+ .getFirst())) {
transactionMatches = true;
}
@@ -718,12 +692,14 @@ && getBranch().equalsIgnoreCase(messageBranch)
protected void map() {
// note that TRYING is a pseudo-state for invite transactions
- int realState = getRealState();
+ TransactionState realState = getRealState();
- if (realState < 0 || realState == TransactionState._TRYING) {
- // Also sent by intermediate proxies.
- // null check added as the stack may be stopped. TRYING is not sent by reliable transports.
- if (isInviteTransaction() && !this.isMapped && sipStack.getTimer() != null ) {
+ if (realState == null || realState == TransactionState.TRYING) {
+ // JvB: Removed the condition 'dialog!=null'. Trying should also
+ // be
+ // sent by intermediate proxies. This fixes some TCK tests
+ // null check added as the stack may be stopped.
+ if (isInviteTransaction() && !this.isMapped && sipStack.getTimer() != null) {
this.isMapped = true;
// Schedule a timer to fire in 200 ms if the
// TU did not send a trying in that time.
@@ -759,19 +735,19 @@ public void processRequest(SIPRequest transactionRequest, MessageChannel sourceC
// transaction at a time. For a given server transaction
// the listener sees only one event at a time.
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- logger.logDebug("processRequest: " + transactionRequest.getFirstLine());
- logger.logDebug("tx state = " + this.getRealState());
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
+ sipStack.getStackLogger().logDebug("processRequest: " + transactionRequest.getFirstLine());
+ sipStack.getStackLogger().logDebug("tx state = " + this.getRealState());
}
try {
// If this is the first request for this transaction,
- if (getRealState() < 0) {
+ if (getRealState() == null) {
// Save this request as the one this
// transaction is handling
setOriginalRequest(transactionRequest);
- this.setState(TransactionState._TRYING);
+ this.setState(TransactionState.TRYING);
toTu = true;
this.setPassToListener();
@@ -788,22 +764,22 @@ public void processRequest(SIPRequest transactionRequest, MessageChannel sourceC
}
// If an invite transaction is ACK'ed while in
// the completed state,
- } else if (isInviteTransaction() && TransactionState._COMPLETED == getRealState()
+ } else if (isInviteTransaction() && TransactionState.COMPLETED == getRealState()
&& transactionRequest.getMethod().equals(Request.ACK)) {
// @jvB bug fix
- this.setState(TransactionState._CONFIRMED);
+ this.setState(TransactionState.CONFIRMED);
disableRetransmissionTimer();
if (!isReliable()) {
enableTimeoutTimer(TIMER_I);
} else {
- this.setState(TransactionState._TERMINATED);
+ this.setState(TransactionState.TERMINATED);
}
-
+
// JvB: For the purpose of testing a TI, added a property to
// pass it anyway
if (sipStack.isNon2XXAckPassedToListener()) {
@@ -813,8 +789,8 @@ public void processRequest(SIPRequest transactionRequest, MessageChannel sourceC
} else {
// According to RFC3261 Application should not Ack in
// CONFIRMED state
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- logger.logDebug("ACK received for server Tx "
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
+ sipStack.getStackLogger().logDebug("ACK received for server Tx "
+ this.getTransactionId() + " not delivering to application!");
}
@@ -825,15 +801,19 @@ public void processRequest(SIPRequest transactionRequest, MessageChannel sourceC
// If we receive a retransmission of the original
// request,
- } else if (transactionRequest.getMethod().equals(getMethod())) {
+ } else if (transactionRequest.getMethod().equals(getOriginalRequest().getMethod())) {
- if (TransactionState._PROCEEDING == getRealState()
- || TransactionState._COMPLETED == getRealState()) {
+ if (TransactionState.PROCEEDING == getRealState()
+ || TransactionState.COMPLETED == getRealState()) {
this.semRelease();
// Resend the last response to
// the client
- // Send the message to the client
- resendLastResponseAsBytes();
+ if (lastResponse != null) {
+
+ // Send the message to the client
+ super.sendMessage(lastResponse);
+
+ }
} else if (transactionRequest.getMethod().equals(Request.ACK)) {
// This is passed up to the TU to suppress
// retransmission of OK
@@ -842,18 +822,18 @@ public void processRequest(SIPRequest transactionRequest, MessageChannel sourceC
else
this.semRelease();
}
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG))
- logger.logDebug("completed processing retransmitted request : "
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG))
+ sipStack.getStackLogger().logDebug("completed processing retransmitted request : "
+ transactionRequest.getFirstLine() + this + " txState = "
- + this.getState() + " lastResponse = " + this.lastResponseAsBytes);
+ + this.getState() + " lastResponse = " + this.getLastResponse());
return;
}
// Pass message to the TU
- if (TransactionState._COMPLETED != getRealState()
- && TransactionState._TERMINATED != getRealState() && requestOf != null) {
- if (getMethod().equals(transactionRequest.getMethod())) {
+ if (TransactionState.COMPLETED != getRealState()
+ && TransactionState.TERMINATED != getRealState() && requestOf != null) {
+ if (getOriginalRequest().getMethod().equals(transactionRequest.getMethod())) {
// Only send original request to TU once!
if (toTu) {
requestOf.processRequest(transactionRequest, this);
@@ -867,16 +847,17 @@ public void processRequest(SIPRequest transactionRequest, MessageChannel sourceC
}
} else {
// This seems like a common bug so I am allowing it through!
- if (SIPTransactionStack.isDialogCreated(getMethod())
- && getRealState() == TransactionState._TERMINATED
+ if (((SIPTransactionStack) getSIPStack()).isDialogCreated(getOriginalRequest()
+ .getMethod())
+ && getRealState() == TransactionState.TERMINATED
&& transactionRequest.getMethod().equals(Request.ACK)
&& requestOf != null) {
- SIPDialog thisDialog = (SIPDialog) getDialog();
+ SIPDialog thisDialog = (SIPDialog) this.dialog;
if (thisDialog == null || !thisDialog.ackProcessed) {
// Filter out duplicate acks
if (thisDialog != null) {
- thisDialog.ackReceived(transactionRequest.getCSeq().getSeqNumber());
+ thisDialog.ackReceived(transactionRequest);
thisDialog.ackProcessed = true;
}
requestOf.processRequest(transactionRequest, this);
@@ -885,8 +866,8 @@ && getRealState() == TransactionState._TERMINATED
}
} else if (transactionRequest.getMethod().equals(Request.CANCEL)) {
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG))
- logger.logDebug("Too late to cancel Transaction");
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG))
+ sipStack.getStackLogger().logDebug("Too late to cancel Transaction");
this.semRelease();
// send OK and just ignore the CANCEL.
try {
@@ -896,13 +877,13 @@ && getRealState() == TransactionState._TERMINATED
// just ignore the IOException.
}
}
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG))
- logger.logDebug("Dropping request " + getRealState());
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG))
+ sipStack.getStackLogger().logDebug("Dropping request " + getRealState());
}
} catch (IOException e) {
- if (logger.isLoggingEnabled())
- logger.logError("IOException " ,e);
+ if (sipStack.isLoggingEnabled())
+ sipStack.getStackLogger().logError("IOException " ,e);
this.semRelease();
this.raiseIOExceptionEvent();
}
@@ -910,248 +891,240 @@ && getRealState() == TransactionState._TERMINATED
}
/**
- * Send a response message through this transaction and onto the client. The response drives
+ * Send a response message through this transactionand onto the client. The response drives
* the state machine.
*
* @param messageToSend Response to process and send.
*/
public void sendMessage(SIPMessage messageToSend) throws IOException {
- if ( logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- logger.logDebug("sipServerTransaction::sendMessage " + messageToSend.getFirstLine());
- }
- // Message typecast as a response
- final SIPResponse transactionResponse = (SIPResponse) messageToSend;
- // Status code of the response being sent to the client
- final int statusCode = transactionResponse.getStatusCode();
try {
+ // Message typecast as a response
+ SIPResponse transactionResponse;
+ // Status code of the response being sent to the client
+ int statusCode;
+
+ // Get the status code from the response
+ transactionResponse = (SIPResponse) messageToSend;
+ statusCode = transactionResponse.getStatusCode();
try {
// Provided we have set the banch id for this we set the BID for
// the
// outgoing via.
- if (originalRequestBranch != null)
+ if (this.getOriginalRequest().getTopmostVia().getBranch() != null)
transactionResponse.getTopmostVia().setBranch(this.getBranch());
else
transactionResponse.getTopmostVia().removeParameter(ParameterNames.BRANCH);
// Make the topmost via headers match identically for the
// transaction rsponse.
- if (!originalRequestHasPort)
+ if (!this.getOriginalRequest().getTopmostVia().hasPort())
transactionResponse.getTopmostVia().removePort();
} catch (ParseException ex) {
- logger.logError("UnexpectedException",ex);
- throw new IOException("Unexpected exception");
+ ex.printStackTrace();
}
// Method of the response does not match the request used to
// create the transaction - transaction state does not change.
if (!transactionResponse.getCSeq().getMethod().equals(
- getMethod())) {
+ getOriginalRequest().getMethod())) {
sendResponse(transactionResponse);
return;
}
- if(!checkStateTimers(statusCode)) {
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- logger.logDebug("checkStateTimers returned false -- not sending message");
- }
- return;
- }
-
- try {
- // Send the message to the client.
- // Record the last message sent out.
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- logger.logDebug(
- "sendMessage : tx = " + this + " getState = " + this.getState());
- }
- lastResponse = transactionResponse;
- lastResponseStatusCode = transactionResponse.getStatusCode();
-
- this.sendResponse(transactionResponse);
-
- } catch (IOException e) {
+ // If the TU sends a provisional response while in the
+ // trying state,
+
+ if (getRealState() == TransactionState.TRYING) {
+ if (statusCode / 100 == 1) {
+ this.setState(TransactionState.PROCEEDING);
+ } else if (200 <= statusCode && statusCode <= 699) {
+ // INVITE ST has TRYING as a Pseudo state
+ // (See issue 76). We are using the TRYING
+ // pseudo state invite Transactions
+ // to signal if the application
+ // has sent trying or not and hence this
+ // check is necessary.
+ if (!isInviteTransaction()) {
+ if (!isReliable()) {
+ // Linger in the completed state to catch
+ // retransmissions if the transport is not
+ // reliable.
+ this.setState(TransactionState.COMPLETED);
+ // Note that Timer J is only set for Unreliable
+ // transports -- see Issue 75.
+ /*
+ * From RFC 3261 Section 17.2.2 (non-invite server transaction)
+ *
+ * When the server transaction enters the "Completed" state, it MUST
+ * set Timer J to fire in 64*T1 seconds for unreliable transports, and
+ * zero seconds for reliable transports. While in the "Completed"
+ * state, the server transaction MUST pass the final response to the
+ * transport layer for retransmission whenever a retransmission of the
+ * request is received. Any other final responses passed by the TU to
+ * the server transaction MUST be discarded while in the "Completed"
+ * state. The server transaction remains in this state until Timer J
+ * fires, at which point it MUST transition to the "Terminated" state.
+ */
+ enableTimeoutTimer(TIMER_J);
+ } else {
+ this.setState(TransactionState.TERMINATED);
+ }
+ } else {
+ // This is the case for INVITE server transactions.
+ // essentially, it duplicates the code in the
+ // PROCEEDING case below. There is no TRYING state for INVITE
+ // transactions in the RFC. We are using it to signal whether the
+ // application has sent a provisional response or not. Hence
+ // this is treated the same as as Proceeding.
+ if (statusCode / 100 == 2) {
+ // Status code is 2xx means that the
+ // transaction transitions to TERMINATED
+ // for both Reliable as well as unreliable
+ // transports. Note that the dialog layer
+ // takes care of retransmitting 2xx final
+ // responses.
+ /*
+ * RFC 3261 Section 13.3.1.4 Note, however, that the INVITE server
+ * transaction will be destroyed as soon as it receives this final
+ * response and passes it to the transport. Therefore, it is necessary
+ * to periodically pass the response directly to the transport until
+ * the ACK arrives. The 2xx response is passed to the transport with
+ * an interval that starts at T1 seconds and doubles for each
+ * retransmission until it reaches T2 seconds (T1 and T2 are defined
+ * in Section 17). Response retransmissions cease when an ACK request
+ * for the response is received. This is independent of whatever
+ * transport protocols are used to send the response.
+ */
+ this.disableRetransmissionTimer();
+ this.disableTimeoutTimer();
+ this.collectionTime = TIMER_J;
+ this.setState(TransactionState.TERMINATED);
+ if (this.dialog != null)
+ this.dialog.setRetransmissionTicks();
+ } else {
+ // This an error final response.
+ this.setState(TransactionState.COMPLETED);
+ if (!isReliable()) {
+ /*
+ * RFC 3261
+ *
+ * While in the "Proceeding" state, if the TU passes a response
+ * with status code from 300 to 699 to the server transaction, the
+ * response MUST be passed to the transport layer for
+ * transmission, and the state machine MUST enter the "Completed"
+ * state. For unreliable transports, timer G is set to fire in T1
+ * seconds, and is not set to fire for reliable transports.
+ */
+
+ enableRetransmissionTimer();
- this.setState(TransactionState._TERMINATED);
- this.collectionTime = 0;
- throw e;
+ }
+ enableTimeoutTimer(TIMER_H);
+ }
+ }
- }
- } finally {
- this.startTransactionTimer();
- }
+ }
- }
+ // If the transaction is in the proceeding state,
+ } else if (getRealState() == TransactionState.PROCEEDING) {
+ if (isInviteTransaction()) {
- private boolean checkStateTimers(int statusCode) {
- // If the TU sends a provisional response while in the
- // trying state,
-
- if (getRealState() == TransactionState._TRYING) {
- if (statusCode / 100 == 1) {
- this.setState(TransactionState._PROCEEDING);
- } else if (200 <= statusCode && statusCode <= 699) {
- // INVITE ST has TRYING as a Pseudo state
- // (See issue 76). We are using the TRYING
- // pseudo state invite Transactions
- // to signal if the application
- // has sent trying or not and hence this
- // check is necessary.
- if (!isInviteTransaction()) {
- if (!isReliable() && getInternalState() != TransactionState._COMPLETED) {
- // Linger in the completed state to catch
- // retransmissions if the transport is not
- // reliable.
- this.setState(TransactionState._COMPLETED);
- // Note that Timer J is only set for Unreliable
- // transports -- see Issue 75.
- /*
- * From RFC 3261 Section 17.2.2 (non-invite server transaction)
- *
- * When the server transaction enters the "Completed" state, it MUST
- * set Timer J to fire in 64*T1 seconds for unreliable transports, and
- * zero seconds for reliable transports. While in the "Completed"
- * state, the server transaction MUST pass the final response to the
- * transport layer for retransmission whenever a retransmission of the
- * request is received. Any other final responses passed by the TU to
- * the server transaction MUST be discarded while in the "Completed"
- * state. The server transaction remains in this state until Timer J
- * fires, at which point it MUST transition to the "Terminated" state.
- */
- startTransactionTimerJ(TIMER_J);
- cleanUpOnTimer();
- } else {
- cleanUpOnTimer();
- this.setState(TransactionState._TERMINATED);
- startTransactionTimerJ(0);
- }
- } else {
- // This is the case for INVITE server transactions.
- // essentially, it duplicates the code in the
- // PROCEEDING case below. There is no TRYING state for INVITE
- // transactions in the RFC. We are using it to signal whether the
- // application has sent a provisional response or not. Hence
- // this is treated the same as as Proceeding.
+ // If the response is a failure message,
if (statusCode / 100 == 2) {
- // Status code is 2xx means that the
- // transaction transitions to TERMINATED
- // for both Reliable as well as unreliable
- // transports. Note that the dialog layer
- // takes care of retransmitting 2xx final
- // responses.
- /*
- * RFC 3261 Section 13.3.1.4 Note, however, that the INVITE server
- * transaction will be destroyed as soon as it receives this final
- * response and passes it to the transport. Therefore, it is necessary
- * to periodically pass the response directly to the transport until
- * the ACK arrives. The 2xx response is passed to the transport with
- * an interval that starts at T1 seconds and doubles for each
- * retransmission until it reaches T2 seconds (T1 and T2 are defined
- * in Section 17). Response retransmissions cease when an ACK request
- * for the response is received. This is independent of whatever
- * transport protocols are used to send the response.
- */
+ // Set up to catch returning ACKs
+ // The transaction lingers in the
+ // terminated state for some time
+ // to catch retransmitted INVITEs
this.disableRetransmissionTimer();
this.disableTimeoutTimer();
this.collectionTime = TIMER_J;
- cleanUpOnTimer();
- this.setState(TransactionState._TERMINATED);
- if (this.getDialog() != null)
- ((SIPDialog) this.getDialog()).setRetransmissionTicks();
- } else {
- // This an error final response.
- this.setState(TransactionState._COMPLETED);
+ this.setState(TransactionState.TERMINATED);
+ if (this.dialog != null)
+ this.dialog.setRetransmissionTicks();
+
+ } else if (300 <= statusCode && statusCode <= 699) {
+
+ // Set up to catch returning ACKs
+ this.setState(TransactionState.COMPLETED);
if (!isReliable()) {
/*
- * RFC 3261
- *
- * While in the "Proceeding" state, if the TU passes a response
- * with status code from 300 to 699 to the server transaction, the
- * response MUST be passed to the transport layer for
- * transmission, and the state machine MUST enter the "Completed"
- * state. For unreliable transports, timer G is set to fire in T1
- * seconds, and is not set to fire for reliable transports.
+ * While in the "Proceeding" state, if the TU passes a response with
+ * status code from 300 to 699 to the server transaction, the response
+ * MUST be passed to the transport layer for transmission, and the
+ * state machine MUST enter the "Completed" state. For unreliable
+ * transports, timer G is set to fire in T1 seconds, and is not set to
+ * fire for reliable transports.
*/
enableRetransmissionTimer();
}
- cleanUpOnTimer();
enableTimeoutTimer(TIMER_H);
+
}
- }
- }
+ // If the transaction is not an invite transaction
+ // and this is a final response,
+ } else if (200 <= statusCode && statusCode <= 699) {
+ // This is for Non-invite server transactions.
- // If the transaction is in the proceeding state,
- } else if (getRealState() == TransactionState._PROCEEDING) {
-
- if (isInviteTransaction()) {
-
- // If the response is a failure message,
- if (statusCode / 100 == 2) {
- // Set up to catch returning ACKs
- // The transaction lingers in the
- // terminated state for some time
- // to catch retransmitted INVITEs
- this.disableRetransmissionTimer();
- this.disableTimeoutTimer();
- this.collectionTime = TIMER_J;
- cleanUpOnTimer();
- this.setState(TransactionState._TERMINATED);
- if (this.getDialog() != null)
- ((SIPDialog) this.getDialog()).setRetransmissionTicks();
-
- } else if (300 <= statusCode && statusCode <= 699) {
-
- // Set up to catch returning ACKs
- this.setState(TransactionState._COMPLETED);
+ // Set up to retransmit this response,
+ // or terminate the transaction
+ this.setState(TransactionState.COMPLETED);
if (!isReliable()) {
- /*
- * While in the "Proceeding" state, if the TU passes a response with
- * status code from 300 to 699 to the server transaction, the response
- * MUST be passed to the transport layer for transmission, and the
- * state machine MUST enter the "Completed" state. For unreliable
- * transports, timer G is set to fire in T1 seconds, and is not set to
- * fire for reliable transports.
- */
- enableRetransmissionTimer();
+
+ disableRetransmissionTimer();
+ enableTimeoutTimer(TIMER_J);
+
+ } else {
+
+ this.setState(TransactionState.TERMINATED);
+
}
- cleanUpOnTimer();
- enableTimeoutTimer(TIMER_H);
+
}
- // If the transaction is not an invite transaction
- // and this is a final response,
- } else if (200 <= statusCode && statusCode <= 699) {
- // This is for Non-invite server transactions.
- // Set up to retransmit this response,
- // or terminate the transaction
- this.setState(TransactionState._COMPLETED);
- if (!isReliable()) {
- disableRetransmissionTimer();
-// enableTimeoutTimer(TIMER_J);
- startTransactionTimerJ(TIMER_J);
- } else {
- this.setState(TransactionState._TERMINATED);
- startTransactionTimerJ(0);
+ // If the transaction has already completed,
+ } else if (TransactionState.COMPLETED == this.getRealState()) {
+
+ return;
+ }
+
+ try {
+ // Send the message to the client.
+ // Record the last message sent out.
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
+ sipStack.getStackLogger().logDebug(
+ "sendMessage : tx = " + this + " getState = " + this.getState());
}
- cleanUpOnTimer();
+ lastResponse = transactionResponse;
+ this.sendResponse(transactionResponse);
+
+ } catch (IOException e) {
+
+ this.setState(TransactionState.TERMINATED);
+ this.collectionTime = 0;
+ throw e;
+
}
- // If the transaction has already completed,
- } else if (TransactionState._COMPLETED == this.getRealState()) {
- return false;
+ } finally {
+ this.startTransactionTimer();
}
- return true;
+
}
public String getViaHost() {
- return super.getViaHost();
+
+ return getMessageChannel().getViaHost();
+
}
public int getViaPort() {
- return super.getViaPort();
+
+ return getMessageChannel().getViaPort();
+
}
/**
@@ -1161,17 +1134,16 @@ public int getViaPort() {
protected void fireRetransmissionTimer() {
try {
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- logger.logDebug("fireRetransmissionTimer() -- " + this + " state " + getState());
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
+ sipStack.getStackLogger().logDebug("fireRetransmissionTimer() -- ");
}
// Resend the last response sent by this transaction
- if (isInviteTransaction() && (lastResponse != null || lastResponseAsBytes != null)) {
+ if (isInviteTransaction() && lastResponse != null) {
// null can happen if this is terminating when the timer fires.
if (!this.retransmissionAlertEnabled || sipStack.isTransactionPendingAck(this) ) {
// Retransmit last response until ack.
- if (lastResponseStatusCode / 100 >= 2 && !this.isAckSeen) {
- resendLastResponseAsBytes();
- }
+ if (lastResponse.getStatusCode() / 100 > 2 && !this.isAckSeen)
+ super.sendMessage(lastResponse);
} else {
// alert the application to retransmit the last response
SipProviderImpl sipProvider = (SipProviderImpl) this.getSipProvider();
@@ -1182,102 +1154,23 @@ protected void fireRetransmissionTimer() {
}
} catch (IOException e) {
- if (logger.isLoggingEnabled())
- logger.logException(e);
+ if (sipStack.isLoggingEnabled())
+ sipStack.getStackLogger().logException(e);
raiseErrorEvent(SIPTransactionErrorEvent.TRANSPORT_ERROR);
}
}
- // jeand we nullify the last response very fast to save on mem and help GC but we keep it as byte array
- // so this method is used to resend the last response either as a response or byte array depending on if it has been nullified
- public void resendLastResponseAsBytes() throws IOException {
-
- if(lastResponse != null) {
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- logger.logDebug("resend last response " + lastResponse);
- }
- sendMessage(lastResponse);
- } else if (lastResponseAsBytes != null) {
- // Send the message to the client
-// if(!checkStateTimers(lastResponseStatusCode)) {
-// return;
-// }
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- logger.logDebug("resend last response " + new String(lastResponseAsBytes));
- }
-
- if(isReliable()) {
- if (logger.isLoggingEnabled(ServerLogger.TRACE_MESSAGES)) {
- // Issue 343 : we have to log the retransmission
- try {
- SIPResponse lastReparsedResponse = (SIPResponse) sipStack.getMessageParserFactory().createMessageParser(sipStack).parseSIPMessage(lastResponseAsBytes, true, false, null);
-
- lastReparsedResponse.setRemoteAddress(
- this.getPeerInetAddress());
- lastReparsedResponse.setRemotePort(this.getPeerPort());
- lastReparsedResponse.setLocalPort(
- getMessageChannel().getPort());
- lastReparsedResponse.setLocalAddress(
- getMessageChannel()
- .getMessageProcessor().getIpAddress());
-
- getMessageChannel().logMessage(lastReparsedResponse, this.getPeerInetAddress(), this.getPeerPort(), System.currentTimeMillis());
- } catch (ParseException e) {
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- logger.logDebug("couldn't reparse last response " + new String(lastResponseAsBytes));
- }
- }
- }
- getMessageChannel().sendMessage(lastResponseAsBytes, this.getPeerInetAddress(), this.getPeerPort(), false);
- } else {
- Hop hop = sipStack.addressResolver.resolveAddress(new HopImpl(lastResponseHost, lastResponsePort,
- lastResponseTransport));
-
- MessageChannel messageChannel = ((SIPTransactionStack) getSIPStack())
- .createRawMessageChannel(this.getSipProvider().getListeningPoint(
- hop.getTransport()).getIPAddress(), this.getPort(), hop);
- if (messageChannel != null) {
- if (logger.isLoggingEnabled(ServerLogger.TRACE_MESSAGES)) {
- // Issue 343 : we have to log the retransmission
- try {
- SIPResponse lastReparsedResponse = (SIPResponse) sipStack.getMessageParserFactory().createMessageParser(sipStack).parseSIPMessage(lastResponseAsBytes, true, false, null);
-
- lastReparsedResponse.setRemoteAddress(
- this.getPeerInetAddress());
- lastReparsedResponse.setRemotePort
- (this.getPeerPort());
- lastReparsedResponse.setLocalPort(
- getMessageChannel().getPort());
- lastReparsedResponse.setLocalAddress(
- getMessageChannel()
- .getMessageProcessor().getIpAddress());
-
- getMessageChannel().logMessage(lastReparsedResponse, this.getPeerInetAddress(), this.getPeerPort(), System.currentTimeMillis());
- } catch (ParseException e) {
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- logger.logDebug("couldn't reparse last response " + new String(lastResponseAsBytes));
- }
- }
- }
- messageChannel.sendMessage(lastResponseAsBytes, InetAddress.getByName(hop.getHost()), hop.getPort(), false);
- } else {
- throw new IOException("Could not create a message channel for " + hop + " with source IP:Port "+
- this.getSipProvider().getListeningPoint(
- hop.getTransport()).getIPAddress() + ":" + this.getPort());
- }
- }
- }
- }
-
private void fireReliableResponseRetransmissionTimer() {
try {
- resendLastResponseAsBytes();
+
+ super.sendMessage(this.pendingReliableResponse);
+
} catch (IOException e) {
- if (logger.isLoggingEnabled())
- logger.logException(e);
- this.setState(TransactionState._TERMINATED);
+ if (sipStack.isLoggingEnabled())
+ sipStack.getStackLogger().logException(e);
+ this.setState(TransactionState.TERMINATED);
raiseErrorEvent(SIPTransactionErrorEvent.TRANSPORT_ERROR);
}
@@ -1288,55 +1181,52 @@ private void fireReliableResponseRetransmissionTimer() {
*/
protected void fireTimeoutTimer() {
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG))
- logger.logDebug("SIPServerTransaction.fireTimeoutTimer this = " + this
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG))
+ sipStack.getStackLogger().logDebug("SIPServerTransaction.fireTimeoutTimer this = " + this
+ " current state = " + this.getRealState() + " method = "
- + this.getMethod());
+ + this.getOriginalRequest().getMethod());
- if (isInviteTransaction() && sipStack.removeTransactionPendingAck(this) ) {
- if ( logger.isLoggingEnabled(LogWriter.TRACE_DEBUG) ) {
- logger.logDebug("Found tx pending ACK - returning");
+ if ( this.getMethod().equals(Request.INVITE) && sipStack.removeTransactionPendingAck(this) ) {
+ if ( sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG) ) {
+ sipStack.getStackLogger().logDebug("Found tx pending ACK - returning");
}
return;
-
+
}
- SIPDialog dialog = (SIPDialog) getDialog();
-
-
- if (SIPTransactionStack.isDialogCreated(getMethod())
- && (TransactionState._CALLING == this.getRealState() || TransactionState._TRYING == this
+ SIPDialog dialog = (SIPDialog) this.dialog;
+
+
+ if (((SIPTransactionStack) getSIPStack()).isDialogCreated(this.getOriginalRequest()
+ .getMethod())
+ && (TransactionState.CALLING == this.getRealState() || TransactionState.TRYING == this
.getRealState())) {
dialog.setState(SIPDialog.TERMINATED_STATE);
- } else if (getMethod().equals(Request.BYE)) {
+ } else if (getOriginalRequest().getMethod().equals(Request.BYE)) {
if (dialog != null && dialog.isTerminatedOnBye())
dialog.setState(SIPDialog.TERMINATED_STATE);
}
- if (TransactionState._COMPLETED == this.getRealState() && isInviteTransaction()) {
+ if (TransactionState.COMPLETED == this.getRealState() && isInviteTransaction()) {
raiseErrorEvent(SIPTransactionErrorEvent.TIMEOUT_ERROR);
- this.setState(TransactionState._TERMINATED);
+ this.setState(TransactionState.TERMINATED);
sipStack.removeTransaction(this);
- } else if (TransactionState._COMPLETED == this.getRealState() && !isInviteTransaction()) {
- this.setState(TransactionState._TERMINATED);
- if(!getMethod().equals(Request.CANCEL)) {
- cleanUp();
- } else {
- sipStack.removeTransaction(this);
- }
+ } else if (TransactionState.COMPLETED == this.getRealState() && !isInviteTransaction()) {
+ this.setState(TransactionState.TERMINATED);
+ sipStack.removeTransaction(this);
- } else if (TransactionState._CONFIRMED == this.getRealState() && isInviteTransaction()) {
+ } else if (TransactionState.CONFIRMED == this.getRealState() && isInviteTransaction()) {
// TIMER_I should not generate a timeout
// exception to the application when the
// Invite transaction is in Confirmed state.
// Just transition to Terminated state.
- this.setState(TransactionState._TERMINATED);
+ this.setState(TransactionState.TERMINATED);
sipStack.removeTransaction(this);
} else if (!isInviteTransaction()
- && (TransactionState._COMPLETED == this.getRealState() || TransactionState._CONFIRMED == this
+ && (TransactionState.COMPLETED == this.getRealState() || TransactionState.CONFIRMED == this
.getRealState())) {
- this.setState(TransactionState._TERMINATED);
- } else if (isInviteTransaction() && TransactionState._TERMINATED == this.getRealState()) {
+ this.setState(TransactionState.TERMINATED);
+ } else if (isInviteTransaction() && TransactionState.TERMINATED == this.getRealState()) {
// This state could be reached when retransmitting
raiseErrorEvent(SIPTransactionErrorEvent.TIMEOUT_ERROR);
@@ -1348,10 +1238,10 @@ protected void fireTimeoutTimer() {
}
/**
- * Get the last response status code.
+ * Get the last response.
*/
- public int getLastResponseStatusCode() {
- return this.lastResponseStatusCode;
+ public SIPResponse getLastResponse() {
+ return this.lastResponse;
}
/**
@@ -1370,21 +1260,20 @@ public void setOriginalRequest(SIPRequest originalRequest) {
public void sendResponse(Response response) throws SipException {
SIPResponse sipResponse = (SIPResponse) response;
- SIPDialog dialog = (SIPDialog) getDialog();
+ SIPDialog dialog = this.dialog;
if (response == null)
throw new NullPointerException("null response");
try {
sipResponse.checkHeaders();
} catch (ParseException ex) {
- throw new IllegalTransactionStateException(ex.getMessage(), Reason.MissingRequiredHeader);
+ throw new SipException(ex.getMessage());
}
// check for meaningful response.
- final String responseMethod = sipResponse.getCSeq().getMethod();
- if (!responseMethod.equals(this.getMethod())) {
- throw new IllegalTransactionStateException(
- "CSeq method does not match Request method of request that created the tx.", Reason.UnmatchingCSeq);
+ if (!sipResponse.getCSeq().getMethod().equals(this.getMethod())) {
+ throw new SipException(
+ "CSeq method does not match Request method of request that created the tx.");
}
/*
@@ -1392,11 +1281,10 @@ public void sendResponse(Response response) throws SipException {
* period of time in the response MAY be shorter but MUST NOT be longer than specified in
* the request.
*/
- final int statusCode = response.getStatusCode();
- if (this.getMethod().equals(Request.SUBSCRIBE) && statusCode / 100 == 2) {
+ if (this.getMethod().equals(Request.SUBSCRIBE) && response.getStatusCode() / 100 == 2) {
if (response.getHeader(ExpiresHeader.NAME) == null) {
- throw new IllegalTransactionStateException("Expires header is mandatory in 2xx response of SUBSCRIBE", Reason.ExpiresHeaderMandatory);
+ throw new SipException("Expires header is mandatory in 2xx response of SUBSCRIBE");
} else {
Expires requestExpires = (Expires) this.getOriginalRequest().getExpires();
Expires responseExpires = (Expires) response.getExpires();
@@ -1414,10 +1302,10 @@ public void sendResponse(Response response) throws SipException {
}
// Check for mandatory header.
- if (statusCode == 200
- && responseMethod.equals(Request.INVITE)
+ if (sipResponse.getStatusCode() == 200
+ && sipResponse.getCSeq().getMethod().equals(Request.INVITE)
&& sipResponse.getHeader(ContactHeader.NAME) == null)
- throw new IllegalTransactionStateException("Contact Header is mandatory for the OK to the INVITE", Reason.ContactHeaderMandatory);
+ throw new SipException("Contact Header is mandatory for the OK to the INVITE");
if (!this.isMessagePartOfTransaction((SIPMessage) response)) {
throw new SipException("Response does not belong to this transaction.");
@@ -1432,55 +1320,54 @@ public void sendResponse(Response response) throws SipException {
* responses contained a session description. In that case, it MUST NOT send a final
* response until those provisional responses are acknowledged.
*/
- final ContentTypeHeader contentTypeHeader = ((SIPResponse)response).getContentTypeHeader();
- if (this.pendingReliableResponseAsBytes != null
- && this.getDialog() != null
- && this.getInternalState() != TransactionState._TERMINATED
- && statusCode / 100 == 2
- && contentTypeHeader != null
- && contentTypeHeader.getContentType()
- .equalsIgnoreCase(CONTENT_TYPE_APPLICATION)
- && contentTypeHeader.getContentSubType()
- .equalsIgnoreCase(CONTENT_SUBTYPE_SDP)) {
+ if (this.pendingReliableResponse != null
+ && this.getDialog() != null
+ && this.getState() != TransactionState.TERMINATED
+ && ((SIPResponse)response).getContentTypeHeader() != null
+ && response.getStatusCode() / 100 == 2
+ && ((SIPResponse)response).getContentTypeHeader().getContentType()
+ .equalsIgnoreCase("application")
+ && ((SIPResponse)response).getContentTypeHeader().getContentSubType()
+ .equalsIgnoreCase("sdp")) {
if (!interlockProvisionalResponses ) {
- throw new SipException("cannot send response -- unacked provisional");
- } else {
+ throw new SipException("cannot send response -- unacked povisional");
+ } else {
try {
boolean acquired = this.provisionalResponseSem.tryAcquire(1,TimeUnit.SECONDS);
if (!acquired ) {
- throw new SipException("cannot send response -- unacked provisional");
+ throw new SipException("cannot send response -- unacked povisional");
}
} catch (InterruptedException ex) {
- logger.logError ("Interrupted acuqiring PRACK sem");
+ sipStack.getStackLogger().logError ("Interrupted acuqiring PRACK sem");
throw new SipException("Cannot aquire PRACK sem");
}
-
+
}
} else {
// Sending the final response cancels the
// pending response task.
- if (this.pendingReliableResponseAsBytes != null && sipResponse.isFinalResponse()) {
- sipStack.getTimer().cancel(provisionalResponseTask);
+ if (this.pendingReliableResponse != null && sipResponse.isFinalResponse()) {
+ this.provisionalResponseTask.cancel();
this.provisionalResponseTask = null;
- }
+ }
}
// Dialog checks. These make sure that the response
// being sent makes sense.
if (dialog != null) {
- if (statusCode / 100 == 2
- && SIPTransactionStack.isDialogCreated(responseMethod)) {
- if (dialog.getLocalTag() == null && sipResponse.getToTag() == null) {
+ if (sipResponse.getStatusCode() / 100 == 2
+ && sipStack.isDialogCreated(sipResponse.getCSeq().getMethod())) {
+ if (dialog.getLocalTag() == null && sipResponse.getTo().getTag() == null) {
// Trying to send final response and user forgot to set
// to
// tag on the response -- be nice and assign the tag for
// the user.
sipResponse.getTo().setTag(Utils.getInstance().generateTag());
} else if (dialog.getLocalTag() != null && sipResponse.getToTag() == null) {
- if ( logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- logger.logDebug("assigning toTag : serverTransaction = " + this + " dialog "
- + dialog + " tag = " + dialog.getLocalTag());
- }
+ if ( sipStack.getStackLogger().isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
+ sipStack.getStackLogger().logDebug("assigning toTag : serverTransaction = " + this + " dialog "
+ + dialog + " tag = " + dialog.getLocalTag());
+ }
sipResponse.setToTag(dialog.getLocalTag());
} else if (dialog.getLocalTag() != null && sipResponse.getToTag() != null
&& !dialog.getLocalTag().equals(sipResponse.getToTag())) {
@@ -1500,22 +1387,22 @@ public void sendResponse(Response response) throws SipException {
// Backward compatibility slippery slope....
// Only set the from tag in the response when the
// incoming request has a from tag.
- String fromTag = originalRequestFromTag;
- if(getRequest() != null) {
- fromTag = ((SIPRequest) this.getRequest()).getFromTag();
- }
+ String fromTag = ((SIPRequest) this.getRequest()).getFrom().getTag();
if (fromTag != null && sipResponse.getFromTag() != null
&& !sipResponse.getFromTag().equals(fromTag)) {
throw new SipException("From tag of request does not match response from tag");
} else if (fromTag != null) {
sipResponse.getFrom().setTag(fromTag);
} else {
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG))
- logger.logDebug("WARNING -- Null From tag in request!!");
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG))
+ sipStack.getStackLogger().logDebug("WARNING -- Null From tag in request!!");
}
+
+
+
// See if the dialog needs to be inserted into the dialog table
// or if the state of the dialog needs to be changed.
- if (dialog != null && statusCode != 100) {
+ if (dialog != null && response.getStatusCode() != 100) {
dialog.setResponseTags(sipResponse);
DialogState oldState = dialog.getState();
dialog.setLastResponse(this, (SIPResponse) response);
@@ -1529,7 +1416,7 @@ public void sendResponse(Response response) throws SipException {
}
- } else if (dialog == null && isInviteTransaction()
+ } else if (dialog == null && this.getMethod().equals(Request.INVITE)
&& this.retransmissionAlertEnabled
&& this.retransmissionAlertTimerTask == null
&& response.getStatusCode() / 100 == 2) {
@@ -1537,7 +1424,7 @@ public void sendResponse(Response response) throws SipException {
this.retransmissionAlertTimerTask = new RetransmissionAlertTimerTask(dialogId);
sipStack.retransmissionAlertTransactions.put(dialogId, this);
- sipStack.getTimer().scheduleWithFixedDelay(this.retransmissionAlertTimerTask, 0,
+ sipStack.getTimer().schedule(this.retransmissionAlertTimerTask, 0,
SIPTransactionStack.BASE_TIMER_INTERVAL);
}
@@ -1545,34 +1432,31 @@ public void sendResponse(Response response) throws SipException {
// Send message after possibly inserting the Dialog
// into the dialog table to avoid a possible race condition.
-
this.sendMessage((SIPResponse) response);
-
-
-
+
if ( dialog != null ) {
dialog.startRetransmitTimer(this, (SIPResponse)response);
}
} catch (IOException ex) {
- if (logger.isLoggingEnabled())
- logger.logException(ex);
- this.setState(TransactionState._TERMINATED);
+ if (sipStack.isLoggingEnabled())
+ sipStack.getStackLogger().logException(ex);
+ this.setState(TransactionState.TERMINATED);
raiseErrorEvent(SIPTransactionErrorEvent.TRANSPORT_ERROR);
- throw new SipException(ex.getMessage(), ex);
+ throw new SipException(ex.getMessage());
} catch (java.text.ParseException ex1) {
- if (logger.isLoggingEnabled())
- logger.logException(ex1);
- this.setState(TransactionState._TERMINATED);
- throw new SipException(ex1.getMessage(), ex1);
+ if (sipStack.isLoggingEnabled())
+ sipStack.getStackLogger().logException(ex1);
+ this.setState(TransactionState.TERMINATED);
+ throw new SipException(ex1.getMessage());
}
}
/**
* Return the book-keeping information that we actually use.
*/
- protected int getRealState() {
- return super.getInternalState();
+ private TransactionState getRealState() {
+ return super.getState();
}
/**
@@ -1584,7 +1468,7 @@ protected int getRealState() {
*/
public TransactionState getState() {
// Trying is a pseudo state for INVITE transactions.
- if (this.isInviteTransaction() && TransactionState._TRYING == super.getInternalState())
+ if (this.isInviteTransaction() && TransactionState.TRYING == super.getState())
return TransactionState.PROCEEDING;
else
return super.getState();
@@ -1595,10 +1479,10 @@ public TransactionState getState() {
* connection for outgoing requests in this time period) and calls the superclass to set
* state.
*/
- public void setState(int newState) {
+ public void setState(TransactionState newState) {
// Set this timer for connection caching
// of incoming connections.
- if (newState == TransactionState._TERMINATED && this.isReliable()
+ if (newState == TransactionState.TERMINATED && this.isReliable()
&& (!getSIPStack().cacheServerConnections)) {
// Set a time after which the connection
// is closed.
@@ -1613,57 +1497,18 @@ public void setState(int newState) {
* Start the timer task.
*/
protected void startTransactionTimer() {
- if(getMethod().equalsIgnoreCase(Request.INVITE) || getMethod().equalsIgnoreCase(Request.CANCEL) || getMethod().equalsIgnoreCase(Request.ACK)) {
- if (this.transactionTimerStarted.compareAndSet(false, true)) {
- if (sipStack.getTimer() != null && sipStack.getTimer().isStarted() ) {
- // The timer is set to null when the Stack is
- // shutting down.
- SIPStackTimerTask myTimer = new TransactionTimer();
- // Do not schedule when the stack is not alive.
- if (sipStack.getTimer() != null && sipStack.getTimer().isStarted() ) {
- sipStack.getTimer().scheduleWithFixedDelay(myTimer, BASE_TIMER_INTERVAL, BASE_TIMER_INTERVAL);
- }
- myTimer = null;
- }
- }
- }
- }
-
- /**
- * Start the timer task.
- */
- protected void startTransactionTimerJ(long time) {
- if (this.transactionTimerStarted.compareAndSet(false, true)) {
- if (sipStack.getTimer() != null && sipStack.getTimer().isStarted() ) {
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- logger.logDebug("starting TransactionTimerJ() : " + getTransactionId() + " time " + time);
- }
- // The timer is set to null when the Stack is
- // shutting down.
- SIPStackTimerTask task = new SIPStackTimerTask () {
-
- public void runTask() {
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- logger.logDebug("executing TransactionTimerJ() : " + getTransactionId());
- }
- fireTimeoutTimer();
- cleanUp();
- if(originalRequest != null) {
- originalRequest.cleanUp();
- }
- }
- };
- if(time > 0) {
- sipStack.getTimer().schedule(task, time * T1 * BASE_TIMER_INTERVAL);
- } else {
- task.runTask();
- }
- }
+ if (this.transactionTimerStarted.compareAndSet(false, true)) {
+ if (sipStack.getTimer() != null) {
+ // The timer is set to null when the Stack is
+ // shutting down.
+ TimerTask myTimer = new TransactionTimer();
+ sipStack.getTimer().schedule(myTimer, BASE_TIMER_INTERVAL, BASE_TIMER_INTERVAL);
}
+ }
}
public boolean equals(Object other) {
- if(other == null) return false;
+ if(other == null) return false;
if (!other.getClass().equals(this.getClass())) {
return false;
}
@@ -1677,10 +1522,8 @@ public boolean equals(Object other) {
* @see gov.nist.javax.sip.stack.SIPTransaction#getDialog()
*/
public Dialog getDialog() {
- if(dialog == null && dialogId != null) {
- return sipStack.getDialog(dialogId);
- }
- return dialog;
+
+ return this.dialog;
}
/*
@@ -1690,14 +1533,13 @@ public Dialog getDialog() {
* gov.nist.javax.sip.message.SIPMessage)
*/
public void setDialog(SIPDialog sipDialog, String dialogId) {
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG))
- logger.logDebug("setDialog " + this + " dialog = " + sipDialog);
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG))
+ sipStack.getStackLogger().logDebug("setDialog " + this + " dialog = " + sipDialog);
this.dialog = sipDialog;
- this.dialogId = dialogId;
if (dialogId != null)
- sipDialog.setAssigned();
+ this.dialog.setAssigned();
if (this.retransmissionAlertEnabled && this.retransmissionAlertTimerTask != null) {
- sipStack.getTimer().cancel(retransmissionAlertTimerTask);
+ this.retransmissionAlertTimerTask.cancel();
if (this.retransmissionAlertTimerTask.dialogId != null) {
sipStack.retransmissionAlertTransactions
.remove(this.retransmissionAlertTimerTask.dialogId);
@@ -1714,10 +1556,10 @@ public void setDialog(SIPDialog sipDialog, String dialogId) {
*
* @see javax.sip.Transaction#terminate()
*/
- public void terminate() throws ObjectInUseException {
- this.setState(TransactionState._TERMINATED);
+ public void terminate() throws ObjectInUseException {
+ this.setState(TransactionState.TERMINATED);
if (this.retransmissionAlertTimerTask != null) {
- sipStack.getTimer().cancel(retransmissionAlertTimerTask);
+ this.retransmissionAlertTimerTask.cancel();
if (retransmissionAlertTimerTask.dialogId != null) {
this.sipStack.retransmissionAlertTransactions
.remove(retransmissionAlertTimerTask.dialogId);
@@ -1730,6 +1572,7 @@ public void terminate() throws ObjectInUseException {
testAndSetTransactionTerminatedEvent();
sipStack.removeTransaction(this);
}
+
}
protected void sendReliableProvisionalResponse(Response relResponse) throws SipException {
@@ -1739,15 +1582,11 @@ protected void sendReliableProvisionalResponse(Response relResponse) throws SipE
* UAS MAY send additional reliable provisional responses. The UAS MUST NOT send a second
* reliable provisional response until the first is acknowledged.
*/
- if (this.pendingReliableResponseAsBytes != null) {
+ if (this.pendingReliableResponse != null) {
throw new SipException("Unacknowledged response");
- } else {
- SIPResponse reliableResponse = (SIPResponse) relResponse;
- this.pendingReliableResponseAsBytes = reliableResponse.encodeAsBytes(this.getTransport());
- this.pendingReliableResponseMethod = reliableResponse.getCSeq().getMethod();
- this.pendingReliableCSeqNumber = reliableResponse.getCSeq().getSeqNumber();
- }
+ } else
+ this.pendingReliableResponse = (SIPResponse) relResponse;
/*
* In addition, it MUST contain a Require header field containing the option tag 100rel,
* and MUST include an RSeq header field.
@@ -1759,15 +1598,11 @@ protected void sendReliableProvisionalResponse(Response relResponse) throws SipE
}
try {
- if(rseqNumber < 0) {
- this.rseqNumber = (int) (Math.random() * 1000);
- }
this.rseqNumber++;
rseq.setSeqNumber(this.rseqNumber);
- this.pendingReliableRSeqNumber = rseq.getSeqNumber();
// start the timer task which will retransmit the reliable response
- // until the PRACK is received. Cannot send a second provisional.
+ // until the PRACK is received. Cannot send a second provisional.
this.lastResponse = (SIPResponse) relResponse;
if ( this.getDialog() != null && interlockProvisionalResponses ) {
boolean acquired = this.provisionalResponseSem.tryAcquire(1, TimeUnit.SECONDS);
@@ -1775,10 +1610,10 @@ protected void sendReliableProvisionalResponse(Response relResponse) throws SipE
throw new SipException("Unacknowledged reliable response");
}
}
- //moved the task scheduling before the sending of the message to overcome
+ //moved the task scheduling before the sending of the message to overcome
// Issue 265 : https://jain-sip.dev.java.net/issues/show_bug.cgi?id=265
this.provisionalResponseTask = new ProvisionalResponseTask();
- this.sipStack.getTimer().scheduleWithFixedDelay(provisionalResponseTask, 0,
+ this.sipStack.getTimer().schedule(provisionalResponseTask, 0,
SIPTransactionStack.BASE_TIMER_INTERVAL);
this.sendMessage((SIPMessage) relResponse);
} catch (Exception ex) {
@@ -1787,9 +1622,9 @@ protected void sendReliableProvisionalResponse(Response relResponse) throws SipE
}
- public byte[] getReliableProvisionalResponse() {
+ public SIPResponse getReliableProvisionalResponse() {
- return this.pendingReliableResponseAsBytes;
+ return this.pendingReliableResponse;
}
/**
@@ -1800,15 +1635,15 @@ public byte[] getReliableProvisionalResponse() {
*/
public boolean prackRecieved() {
- if (this.pendingReliableResponseAsBytes == null)
+ if (this.pendingReliableResponse == null)
return false;
- if(provisionalResponseTask != null) {
- sipStack.getTimer().cancel(provisionalResponseTask);
- this.provisionalResponseTask = null;
- }
-
- this.pendingReliableResponseAsBytes = null;
- if ( interlockProvisionalResponses && getDialog() != null ) {
+ if(provisionalResponseTask != null) {
+ this.provisionalResponseTask.cancel();
+ this.provisionalResponseTask = null;
+ }
+
+ this.pendingReliableResponse = null;
+ if ( interlockProvisionalResponses && this.dialog != null ) {
this.provisionalResponseSem.release();
}
return true;
@@ -1824,7 +1659,7 @@ public void enableRetransmissionAlerts() throws SipException {
if (this.getDialog() != null)
throw new SipException("Dialog associated with tx");
- else if (!isInviteTransaction())
+ else if (!this.getMethod().equals(Request.INVITE))
throw new SipException("Request Method must be INVITE");
this.retransmissionAlertEnabled = true;
@@ -1841,7 +1676,7 @@ public boolean isRetransmissionAlertEnabled() {
*/
public void disableRetransmissionAlerts() {
if (this.retransmissionAlertTimerTask != null && this.retransmissionAlertEnabled) {
- sipStack.getTimer().cancel(retransmissionAlertTimerTask);
+ this.retransmissionAlertTimerTask.cancel();
this.retransmissionAlertEnabled = false;
String dialogId = this.retransmissionAlertTimerTask.dialogId;
@@ -1868,6 +1703,7 @@ public boolean ackSeen() {
public void setMapped(boolean b) {
this.isMapped = true;
+
}
public void setPendingSubscribe(SIPClientTransaction pendingSubscribeClientTx) {
@@ -1921,154 +1757,5 @@ public void scheduleAckRemoval() throws IllegalStateException {
this.startTransactionTimer();
}
-
- // jeand cleanup the state of the stx to help GC
- public void cleanUp() {
- // Remove it from the set
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG))
- logger.logDebug("removing" + this);
-
- if(isReleaseReferences()) {
-
- // release the connection associated with this transaction.
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- logger.logDebug("cleanup : "
- + getTransactionId());
- }
- // we keep the request in a byte array to be able to recreate it
- // no matter what to keep API backward compatibility
- if(originalRequest == null && originalRequestBytes != null) {
- try {
- originalRequest = (SIPRequest) sipStack.getMessageParserFactory().createMessageParser(sipStack).parseSIPMessage(originalRequestBytes, true, false, null);
-// originalRequestBytes = null;
- } catch (ParseException e) {
- logger.logError("message " + originalRequestBytes + "could not be reparsed !");
- }
- } else if (originalRequest != null && originalRequestBytes == null) {
- originalRequestBytes = originalRequest.encodeAsBytes(this.getTransport());
- }
- sipStack.removeTransaction(this);
- cleanUpOnTimer();
- // commented out because the application can hold on a ref to the tx
- // after it has been removed from the stack
- // and want to get the request or branch from it
-// originalRequestBytes = null;
-// originalRequestBranch = null;
- originalRequestFromTag = null;
- originalRequestSentBy = null;
- // it should be available in the processTxTerminatedEvent, so we can nullify it only here
- if(originalRequest != null) {
- // originalRequestSentBy = originalRequest.getTopmostVia().getSentBy();
- // originalRequestFromTag = originalRequest.getFromTag();
- originalRequest = null;
- }
- if(!isReliable() && inviteTransaction != null) {
- inviteTransaction = null;
- }
- // Application Data has to be cleared by the application
- // applicationData = null;
- lastResponse = null;
- // Issue 318 : (https://jain-sip.dev.java.net/issues/show_bug.cgi?id=318)
- // Re-transmission of 200 to INVITE terminates prematurely :
- // don't nullify since the transaction may be terminated
- // but the ack not received so the 200 retransmissions should continue
-// lastResponseAsBytes = null;
-
- // don't clean up because on sending 200 OK to CANCEL otherwise we try to start the transaction timer
- // but due to timer J it has already been cleaned up
-// transactionTimerStarted = null;
- } else {
- sipStack.removeTransaction(this);
- }
-
- // Uncache the server tx
- if ((!sipStack.cacheServerConnections)
- && --getMessageChannel().useCount <= 0) {
- // Close the encapsulated socket if stack is configured
- close();
- } else {
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)
- && (!sipStack.cacheServerConnections)
- && isReliable()) {
- int useCount = getMessageChannel().useCount;
- logger.logDebug("Use Count = " + useCount);
- }
- }
-
- }
-
- // clean up the state of the stx when it goes to completed or terminated to help GC
- protected void cleanUpOnTimer() {
- if(isReleaseReferences()) {
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- logger.logDebug("cleanup on timer : "
- + getTransactionId());
- }
- if(dialog != null && getMethod().equals(Request.CANCEL)) {
- // used to deal with getting the dialog on cancel tx after the 200 OK to CANCEL has been sent
- dialogId = dialog.getDialogId();
- }
- dialog = null;
- // we don't nullify the inviteTx for CANCEL since the app can get it from getCanceledInviteTransaction
- if(inviteTransaction != null && !getMethod().equals(Request.CANCEL)) {
- // we release the semaphore for Cancel processing
- inviteTransaction.releaseSem();
- inviteTransaction = null;
- }
- if(originalRequest != null) {
- originalRequest.setTransaction(null);
- originalRequest.setInviteTransaction(null);
- if(!getMethod().equalsIgnoreCase(Request.INVITE)) {
- if(originalRequestSentBy == null) {
- originalRequestSentBy = originalRequest.getTopmostVia().getSentBy();
- }
- if(originalRequestFromTag == null) {
- originalRequestFromTag = originalRequest.getFromTag();
- }
- }
- // we keep the request in a byte array to be able to recreate it
- // no matter what to keep API backward compatibility
- if(originalRequestBytes == null) {
- originalRequestBytes = originalRequest.encodeAsBytes(this.getTransport());
- }
- if(!getMethod().equalsIgnoreCase(Request.INVITE) && !getMethod().equalsIgnoreCase(Request.CANCEL)) {
- originalRequest = null;
- }
- }
- if(lastResponse != null) {
- lastResponseAsBytes = lastResponse.encodeAsBytes(this.getTransport());
- lastResponse = null;
- }
- pendingReliableResponseAsBytes = null;
- pendingReliableResponseMethod = null;
- pendingSubscribeTransaction = null;
- provisionalResponseSem = null;
- retransmissionAlertTimerTask = null;
- requestOf = null;
- messageProcessor = null;
- }
- }
-
- /**
- * @return the pendingReliableResponseMethod
- */
- public String getPendingReliableResponseMethod() {
- return pendingReliableResponseMethod;
- }
-
- /**
- * @return the pendingReliableCSeqNumber
- */
- public long getPendingReliableCSeqNumber() {
- return pendingReliableCSeqNumber;
- }
-
- /**
- * @return the pendingReliableRSeqNumber
- */
- public long getPendingReliableRSeqNumber() {
- return pendingReliableRSeqNumber;
- }
-
-
+
}
diff --git a/src/gov/nist/javax/sip/stack/SIPStackTimerTask.java b/src/gov/nist/javax/sip/stack/SIPStackTimerTask.java
index 8e593faba..d74dad42d 100644
--- a/src/gov/nist/javax/sip/stack/SIPStackTimerTask.java
+++ b/src/gov/nist/javax/sip/stack/SIPStackTimerTask.java
@@ -1,13 +1,14 @@
/*
* @author: Brett Buckingham
- * @author: Last modified by: $Author: deruelle_jean $
- * @version: $Date: 2010-05-06 14:08:11 $ $Revision: 1.4 $
+ * @author: Last modified by: $Author: emcho $
+ * @version: $Date: 2009-07-17 18:58:14 $ $Revision: 1.3 $
*
* This source code has been contributed to the public domain.
*/
package gov.nist.javax.sip.stack;
+import java.util.TimerTask;
/**
* A subclass of TimerTask which runs TimerTask code within a try/catch block to
@@ -17,21 +18,18 @@
* @author Brett Buckingham
*
*/
-public abstract class SIPStackTimerTask {
- // the underlying timer task that was scheduled in the Stack SIP timer
- Object timerTask = null;
- // Implements code to be run when the SIPStackTimerTask is executed.
- public abstract void runTask();
-
- public void cleanUpBeforeCancel() {
-
- }
-
- public void setSipTimerTask(Object timer) {
- timerTask = timer;
- }
+public abstract class SIPStackTimerTask extends TimerTask {
+ // / Implements code to be run when the SIPStackTimerTask is executed.
+ protected abstract void runTask();
- public Object getSipTimerTask() {
- return timerTask;
- }
+ // / The run() method is final to ensure that all subclasses inherit the
+ // exception handling.
+ public final void run() {
+ try {
+ runTask();
+ } catch (Throwable e) {
+ System.out.println("SIP stack timer task failed due to exception:");
+ e.printStackTrace();
+ }
+ }
}
diff --git a/src/gov/nist/javax/sip/stack/SIPTransaction.java b/src/gov/nist/javax/sip/stack/SIPTransaction.java
index 92fdae2b6..fd5efb80c 100755
--- a/src/gov/nist/javax/sip/stack/SIPTransaction.java
+++ b/src/gov/nist/javax/sip/stack/SIPTransaction.java
@@ -25,21 +25,21 @@
*/
package gov.nist.javax.sip.stack;
-import gov.nist.core.CommonLogger;
import gov.nist.core.InternalErrorHandler;
-import gov.nist.core.LogLevels;
import gov.nist.core.LogWriter;
+import gov.nist.javax.sip.address.AddressFactoryImpl;
import gov.nist.core.ServerLogger;
-import gov.nist.core.StackLogger;
import gov.nist.javax.sip.SIPConstants;
import gov.nist.javax.sip.SipProviderImpl;
-import gov.nist.javax.sip.SipStackImpl;
-import gov.nist.javax.sip.address.AddressFactoryImpl;
+import gov.nist.javax.sip.header.CallID;
+import gov.nist.javax.sip.header.Event;
+import gov.nist.javax.sip.header.From;
+import gov.nist.javax.sip.header.To;
import gov.nist.javax.sip.header.Via;
+import gov.nist.javax.sip.header.ViaList;
import gov.nist.javax.sip.message.SIPMessage;
import gov.nist.javax.sip.message.SIPRequest;
import gov.nist.javax.sip.message.SIPResponse;
-import gov.nist.javax.sip.stack.SIPClientTransaction.ExpiresTimerTask;
import java.io.IOException;
import java.net.InetAddress;
@@ -49,20 +49,21 @@
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
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 javax.sip.Dialog;
import javax.sip.IOExceptionEvent;
+import javax.sip.ServerTransaction;
import javax.sip.TransactionState;
import javax.sip.address.SipURI;
import javax.sip.message.Request;
@@ -82,11 +83,11 @@
* @author M. Ranganathan
*
*
- * @version 1.2 $Revision: 1.100 $ $Date: 2010-12-02 22:04:13 $
+ * @version 1.2 $Revision: 1.75.2.7 $ $Date: 2010-11-23 19:23:14 $
*/
public abstract class SIPTransaction extends MessageChannel implements
javax.sip.Transaction, gov.nist.javax.sip.TransactionExt {
- private static StackLogger logger = CommonLogger.getLogger(SIPTransaction.class);
+
protected boolean toListener; // Flag to indicate that the listener gets
// to see the event.
@@ -140,7 +141,9 @@ public abstract class SIPTransaction extends MessageChannel implements
protected boolean isMapped;
- private TransactionSemaphore semaphore;
+ private Semaphore semaphore;
+
+ protected boolean isSemaphoreAquired;
// protected boolean eventPending; // indicate that an event is pending
// here.
@@ -195,17 +198,28 @@ public abstract class SIPTransaction extends MessageChannel implements
// 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
private transient MessageChannel encapsulatedChannel;
+ // Port of peer
+ protected int peerPort;
+
+ // Address of peer
+ protected InetAddress peerInetAddress;
+
+ // Address of peer as a string
+ protected String peerAddress;
+
+ // Protocol of peer
+ protected String peerProtocol;
+
+ // @@@ hagai - NAT changes
+ // Source port extracted from peer packet
+ protected int peerPacketSourcePort;
+
+ protected InetAddress peerPacketSourceAddress;
+
protected AtomicBoolean transactionTimerStarted = new AtomicBoolean(false);
// Transaction branch ID
@@ -214,8 +228,11 @@ public abstract class SIPTransaction extends MessageChannel implements
// Method of the Request used to create the transaction.
private String method;
+ // Sequence number of request used to create the transaction
+ private long cSeq;
+
// Current transaction state
- private int currentState = -1;
+ private TransactionState currentState;
// Number of ticks the retransmission timer was set to last
private transient int retransmissionTimerLastTickCount;
@@ -229,96 +246,36 @@ public abstract class SIPTransaction extends MessageChannel implements
// List of event listeners for this transaction
private transient Set eventListeners;
+ // Hang on to these - we clear out the request URI after
+ // transaction goes to final state. Pointers to these are kept around
+ // for transaction matching as long as the transaction is in
+ // the transaction table.
+ protected From from;
+
+ protected To to;
+
+ protected Event event;
+
+ protected CallID callId;
+
+ // Back ptr to the JAIN layer.
+ // private Object wrapper;
// 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 boolean releaseReferences;
-
- // caching flags
- private Boolean inviteTransaction = null;
- private Boolean dialogCreatingTransaction = null;
-
- // caching fork id
- private String forkId = null;
-
- public ExpiresTimerTask expiresTimerTask;
+ protected String toTag;
+
+ protected String fromTag;
+
+ private boolean terminatedEventDelivered;
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)getSIPStack()).isReEntrantListener()) {
- lock = new ReentrantLock();
- } else {
- sem = new Semaphore(1, true);
- }
- }
-
- public boolean acquire() {
- try {
- if(((SipStackImpl)getSIPStack()).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)getSIPStack()).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)getSIPStack()).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
@@ -328,17 +285,48 @@ public void release() {
*/
class LingerTimer extends SIPStackTimerTask {
- public LingerTimer() {
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- SIPTransaction sipTransaction = SIPTransaction.this;
- logger.logDebug("LingerTimer : "
+ public LingerTimer() {
+ SIPTransaction sipTransaction = SIPTransaction.this;
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
+ sipStack.getStackLogger().logDebug("LingerTimer : "
+ sipTransaction.getTransactionId());
}
}
- public void runTask() {
- cleanUp();
+ protected void runTask() {
+ SIPTransaction transaction = SIPTransaction.this;
+ // release the connection associated with this transaction.
+ SIPTransactionStack sipStack = transaction.getSIPStack();
+
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
+ sipStack.getStackLogger().logDebug("LingerTimer: run() : "
+ + getTransactionId());
+ }
+
+ if (transaction instanceof SIPClientTransaction) {
+ sipStack.removeTransaction(transaction);
+ transaction.close();
+
+ } else if (transaction instanceof ServerTransaction) {
+ // Remove it from the set
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG))
+ sipStack.getStackLogger().logDebug("removing" + transaction);
+ sipStack.removeTransaction(transaction);
+ if ((!sipStack.cacheServerConnections)
+ && --transaction.encapsulatedChannel.useCount <= 0) {
+ // Close the encapsulated socket if stack is configured
+ transaction.close();
+ } else {
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)
+ && (!sipStack.cacheServerConnections)
+ && transaction.isReliable()) {
+ int useCount = transaction.encapsulatedChannel.useCount;
+ sipStack.getStackLogger().logDebug("Use Count = " + useCount);
+ }
+ }
+ }
+
}
}
@@ -354,36 +342,43 @@ protected SIPTransaction(SIPTransactionStack newParentStack,
MessageChannel newEncapsulatedChannel) {
sipStack = newParentStack;
- this.semaphore = new TransactionSemaphore();
+ this.semaphore = new Semaphore(1,true);
encapsulatedChannel = newEncapsulatedChannel;
-
+ // Record this to check if the address has changed before sending
+ // message to avoid possible race condition.
+ this.peerPort = newEncapsulatedChannel.getPeerPort();
+ this.peerAddress = newEncapsulatedChannel.getPeerAddress();
+ this.peerInetAddress = newEncapsulatedChannel.getPeerInetAddress();
+ // @@@ hagai
+ this.peerPacketSourcePort = newEncapsulatedChannel
+ .getPeerPacketSourcePort();
+ this.peerPacketSourceAddress = newEncapsulatedChannel
+ .getPeerPacketSourceAddress();
+ this.peerProtocol = newEncapsulatedChannel.getPeerProtocol();
if (this.isReliable()) {
encapsulatedChannel.useCount++;
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG))
- logger
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG))
+ sipStack.getStackLogger()
.logDebug("use count for encapsulated channel"
+ this
+ " "
+ encapsulatedChannel.useCount );
}
- this.currentState = -1;
+ this.currentState = null;
disableRetransmissionTimer();
disableTimeoutTimer();
- eventListeners = new CopyOnWriteArraySet();
+ eventListeners = Collections.synchronizedSet(new HashSet());
// Always add the parent stack as a listener
// of this transaction
addEventListener(newParentStack);
- releaseReferences = sipStack.isAggressiveCleanup();
}
- public abstract void cleanUp();
-
- /**
+ /**
* Sets the request message that this transaction handles.
*
* @param newOriginalRequest
@@ -394,52 +389,46 @@ 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))) {
+ newOriginalRequest.getTransactionId()))) {
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;
+ this.from = (From) newOriginalRequest.getFrom();
+ this.to = (To) newOriginalRequest.getTo();
+ // Save these to avoid concurrent modification exceptions!
+ this.toTag = this.to.getTag();
+ this.fromTag = this.from.getTag();
+ this.callId = (CallID) newOriginalRequest.getCallId();
+ this.cSeq = newOriginalRequest.getCSeq().getSeqNumber();
+ this.event = (Event) newOriginalRequest.getHeader("Event");
+ this.transactionId = newOriginalRequest.getTransactionId();
originalRequest.setTransaction(this);
// If the message has an explicit branch value set,
- newBranch = topmostVia.getBranch();
+ newBranch = ((Via) newOriginalRequest.getViaHeaders().getFirst())
+ .getBranch();
if (newBranch != null) {
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG))
- logger.logDebug("Setting Branch id : " + newBranch);
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG))
+ sipStack.getStackLogger().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!"
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG))
+ sipStack.getStackLogger().logDebug("Branch id is null - compute TID!"
+ newOriginalRequest.encode());
- setBranch(newTransactionId);
+ setBranch(newOriginalRequest.getTransactionId());
}
}
@@ -449,7 +438,7 @@ public void setOriginalRequest(SIPRequest newOriginalRequest) {
* @return -- the original Request associated with this transaction.
*/
public SIPRequest getOriginalRequest() {
- return this.originalRequest;
+ return originalRequest;
}
/**
@@ -458,32 +447,9 @@ public SIPRequest getOriginalRequest() {
* @return the request that generated this transaction.
*/
public Request getRequest() {
- if(isReleaseReferences() && 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) {
- logger.logError("message " + originalRequestBytes + " could not be reparsed !");
- }
- }
return (Request) originalRequest;
}
- /**
- * Returns a flag stating whether this transaction is for a request that creates a dialog.
- *
- * @return -- true if this is a request that creates a dialog, false if not.
- */
- public final boolean isDialogCreatingTransaction() {
- if (dialogCreatingTransaction == null) {
- dialogCreatingTransaction = Boolean.valueOf(isInviteTransaction() || getMethod().equals(Request.SUBSCRIBE) || getMethod().equals(Request.REFER));
- }
- return dialogCreatingTransaction.booleanValue();
- }
-
/**
* Returns a flag stating whether this transaction is for an INVITE request
* or not.
@@ -491,10 +457,7 @@ public final boolean isDialogCreatingTransaction() {
* @return -- true if this is an INVITE request, false if not.
*/
public final boolean isInviteTransaction() {
- if (inviteTransaction == null) {
- inviteTransaction = Boolean.valueOf(getMethod().equals(Request.INVITE));
- }
- return inviteTransaction.booleanValue();
+ return getMethod().equals(Request.INVITE);
}
/**
@@ -543,7 +506,7 @@ public final void setBranch(String newBranch) {
*/
public final String getBranch() {
if (this.branch == null) {
- this.branch = originalRequestBranch;
+ this.branch = getOriginalRequest().getTopmostVia().getBranch();
}
return branch;
}
@@ -563,7 +526,7 @@ public final String getMethod() {
* @return the cseq of the request used to create the transaction.
*/
public final long getCSeq() {
- return this.originalRequestCSeqNumber;
+ return this.cSeq;
}
/**
@@ -572,49 +535,37 @@ public final long getCSeq() {
* @param newState
* New state of this transaction.
*/
- public void setState(int newState) {
+ public void setState(TransactionState newState) {
// PATCH submitted by sribeyron
- if (currentState == TransactionState._COMPLETED) {
- if (newState != TransactionState._TERMINATED
- && newState != TransactionState._CONFIRMED)
- newState = TransactionState._COMPLETED;
+ 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.CONFIRMED) {
+ if (newState != TransactionState.TERMINATED)
+ newState = TransactionState.CONFIRMED;
}
- if (currentState != TransactionState._TERMINATED)
+ if (currentState != TransactionState.TERMINATED)
currentState = newState;
else
newState = currentState;
// END OF PATCH
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- logger.logDebug("Transaction:setState " + newState
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
+ sipStack.getStackLogger().logDebug("Transaction:setState " + newState
+ " " + this + " branchID = " + this.getBranch()
+ " isClient = " + (this instanceof SIPClientTransaction));
- logger.logStackTrace();
+ sipStack.getStackLogger().logStackTrace();
}
}
- /**
- * Gets the current state of this transaction.
- *
- * @return Current state of this transaction.
- */
- public int getInternalState() {
- return this.currentState;
- }
-
/**
* Gets the current state of this transaction.
*
* @return Current state of this transaction.
*/
public TransactionState getState() {
- if(currentState < 0) {
- return null;
- }
- return TransactionState.getObject(this.currentState);
+ return this.currentState;
}
/**
@@ -660,8 +611,8 @@ protected final void disableRetransmissionTimer() {
* Number of ticks before this transaction times out.
*/
protected final void enableTimeoutTimer(int tickCount) {
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG))
- logger.logDebug("enableTimeoutTimer " + this
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG))
+ sipStack.getStackLogger().logDebug("enableTimeoutTimer " + this
+ " tickCount " + tickCount + " currentTickCount = "
+ timeoutTimerTicksLeft);
@@ -709,7 +660,7 @@ final void fireTimer() {
* @return Trus if this transaction is terminated, false if not.
*/
public final boolean isTerminated() {
- return currentState == TransactionState._TERMINATED;
+ return getState() == TERMINATED_STATE;
}
public String getHost() {
@@ -729,28 +680,28 @@ public SIPTransactionStack getSIPStack() {
}
public String getPeerAddress() {
- return this.encapsulatedChannel.getPeerAddress();
+ return this.peerAddress;
}
public int getPeerPort() {
- return this.encapsulatedChannel.getPeerPort();
+ return this.peerPort;
}
// @@@ hagai
public int getPeerPacketSourcePort() {
- return this.encapsulatedChannel.getPeerPacketSourcePort();
+ return this.peerPacketSourcePort;
}
public InetAddress getPeerPacketSourceAddress() {
- return this.encapsulatedChannel.getPeerPacketSourceAddress();
+ return this.peerPacketSourceAddress;
}
protected InetAddress getPeerInetAddress() {
- return this.encapsulatedChannel.getPeerInetAddress();
+ return this.peerInetAddress;
}
protected String getPeerProtocol() {
- return this.encapsulatedChannel.getPeerProtocol();
+ return this.peerProtocol;
}
public String getTransport() {
@@ -811,8 +762,8 @@ public void run() {
((TCPMessageChannel) channel)
.processMessage((SIPMessage) messageToSend.clone(), getPeerInetAddress());
} catch (Exception ex) {
- if (logger.isLoggingEnabled(ServerLogger.TRACE_ERROR)) {
- logger.logError("Error self routing message cause by: ", ex);
+ if (getSIPStack().getStackLogger().isLoggingEnabled(ServerLogger.TRACE_ERROR)) {
+ getSIPStack().getStackLogger().logError("Error self routing message cause by: ", ex);
}
}
}
@@ -820,10 +771,10 @@ public void run() {
getSIPStack().getSelfRoutingThreadpoolExecutor().execute(processMessageTask);
} catch (Exception e) {
- logger.logError("Error passing message in self routing", e);
+ sipStack.getStackLogger().logError("Error passing message in self routing", e);
}
- if (logger.isLoggingEnabled(LogLevels.TRACE_DEBUG))
- logger.logDebug("Self routing message");
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG))
+ sipStack.getStackLogger().logDebug("Self routing message");
return;
}
if (channel instanceof RawMessageChannel) {
@@ -835,25 +786,25 @@ 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);
+ if (getSIPStack().getStackLogger().isLoggingEnabled(ServerLogger.TRACE_ERROR)) {
+ getSIPStack().getStackLogger().logError("Error self routing message cause by: ", ex);
}
}
}
};
getSIPStack().getSelfRoutingThreadpoolExecutor().execute(processMessageTask);
} catch (Exception e) {
- logger.logError("Error passing message in self routing", e);
+ sipStack.getStackLogger().logError("Error passing message in self routing", e);
}
- if (logger.isLoggingEnabled(LogLevels.TRACE_DEBUG))
- logger.logDebug("Self routing message");
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG))
+ sipStack.getStackLogger().logDebug("Self routing message");
return;
}
}
}
encapsulatedChannel.sendMessage(messageToSend,
- this.getPeerInetAddress(), this.getPeerPort());
+ this.peerInetAddress, this.peerPort);
} finally {
this.startTransactionTimer();
}
@@ -938,7 +889,7 @@ protected void raiseErrorEvent(int errorEventID) {
eventListeners.clear();
// Errors always terminate a transaction
- this.setState(TransactionState._TERMINATED);
+ this.setState(TransactionState.TERMINATED);
if (this instanceof SIPServerTransaction && this.isByeTransaction()
&& this.getDialog() != null)
@@ -1050,7 +1001,7 @@ public int getViaPort() {
public boolean doesCancelMatchTransaction(SIPRequest requestToTest) {
// List of Via headers in the message to test
-// ViaList viaHeaders;
+ ViaList viaHeaders;
// Topmost Via header in the list
Via topViaHeader;
// Branch code in the topmost Via header
@@ -1059,15 +1010,15 @@ public boolean doesCancelMatchTransaction(SIPRequest requestToTest) {
boolean transactionMatches;
transactionMatches = false;
- final SIPRequest origRequest = getOriginalRequest();
- if (origRequest == null
- || this.getMethod().equals(Request.CANCEL))
+
+ if (this.getOriginalRequest() == null
+ || this.getOriginalRequest().getMethod().equals(Request.CANCEL))
return false;
// Get the topmost Via header and its branch parameter
- topViaHeader = requestToTest.getTopmostVia();
- if (topViaHeader != null) {
+ viaHeaders = requestToTest.getViaHeaders();
+ if (viaHeaders != null) {
-// topViaHeader = (Via) viaHeaders.getFirst();
+ topViaHeader = (Via) viaHeaders.getFirst();
messageBranch = topViaHeader.getBranch();
if (messageBranch != null) {
@@ -1091,10 +1042,11 @@ public boolean doesCancelMatchTransaction(SIPRequest requestToTest) {
// this message,
if (getBranch().equalsIgnoreCase(messageBranch)
&& topViaHeader.getSentBy().equals(
- origRequest.getTopmostVia().getSentBy())) {
+ ((Via) getOriginalRequest().getViaHeaders()
+ .getFirst()).getSentBy())) {
transactionMatches = true;
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG))
- logger.logDebug("returning true");
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG))
+ sipStack.getStackLogger().logDebug("returning true");
}
} else {
@@ -1102,21 +1054,22 @@ public boolean doesCancelMatchTransaction(SIPRequest requestToTest) {
// 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 (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG))
+ sipStack.getStackLogger().logDebug("testing against "
+ + getOriginalRequest());
- if (origRequest.getRequestURI().equals(
+ if (getOriginalRequest().getRequestURI().equals(
requestToTest.getRequestURI())
- && origRequest.getTo().equals(
+ && getOriginalRequest().getTo().equals(
requestToTest.getTo())
- && origRequest.getFrom().equals(
+ && getOriginalRequest().getFrom().equals(
requestToTest.getFrom())
- && origRequest.getCallId().getCallId().equals(
+ && getOriginalRequest().getCallId().getCallId().equals(
requestToTest.getCallId().getCallId())
- && origRequest.getCSeq().getSeqNumber() == requestToTest
+ && getOriginalRequest().getCSeq().getSeqNumber() == requestToTest
.getCSeq().getSeqNumber()
- && topViaHeader.equals(origRequest.getTopmostVia())) {
+ && topViaHeader.equals(getOriginalRequest()
+ .getViaHeaders().getFirst())) {
transactionMatches = true;
}
@@ -1167,8 +1120,8 @@ public void setRetransmitTimer(int retransmitTimer) {
*/
public void close() {
this.encapsulatedChannel.close();
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG))
- logger.logDebug("Closing " + this.encapsulatedChannel);
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG))
+ sipStack.getStackLogger().logDebug("Closing " + this.encapsulatedChannel);
}
@@ -1213,7 +1166,9 @@ public void setEncapsulatedChannel(MessageChannel messageChannel) {
this.encapsulatedChannel = messageChannel;
if ( this instanceof SIPClientTransaction ) {
this.encapsulatedChannel.setEncapsulatedClientTransaction((SIPClientTransaction) this);
- }
+ }
+ this.peerInetAddress = messageChannel.getPeerInetAddress();
+ this.peerPort = messageChannel.getPeerPort();
}
/**
@@ -1232,7 +1187,7 @@ public SipProviderImpl getSipProvider() {
*
*/
public void raiseIOExceptionEvent() {
- setState(TransactionState._TERMINATED);
+ setState(TransactionState.TERMINATED);
String host = getPeerAddress();
int port = getPeerPort();
String transport = getTransport();
@@ -1248,21 +1203,31 @@ public void raiseIOExceptionEvent() {
*/
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();
+ try {
+ if (sipStack.getStackLogger().isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
+ sipStack.getStackLogger().logDebug("acquireSem [[[[" + this);
+ sipStack.getStackLogger().logStackTrace();
+ }
+ if ( this.sipStack.maxListenerResponseTime == -1 ) {
+ this.semaphore.acquire();
+ retval = true;
+ } else {
+ retval = this.semaphore.tryAcquire(this.sipStack.maxListenerResponseTime, TimeUnit.SECONDS);
+ }
+ if ( sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG))
+ sipStack.getStackLogger().logDebug(
+ "acquireSem() returning : " + retval);
+ return retval;
+ } catch (Exception ex) {
+ sipStack.getStackLogger().logError("Unexpected exception acquiring sem",
+ ex);
+ InternalErrorHandler.handleException(ex);
+ return false;
+ } finally {
+ this.isSemaphoreAquired = retval;
}
- if ( logger.isLoggingEnabled(LogWriter.TRACE_DEBUG))
- logger.logDebug(
- "acquireSem() returning : " + retval);
- return retval;
+
}
-
/**
* Release the transaction semaphore.
@@ -1275,7 +1240,7 @@ public void releaseSem() {
this.semRelease();
} catch (Exception ex) {
- logger.logError("Unexpected exception releasing sem",
+ sipStack.getStackLogger().logError("Unexpected exception releasing sem",
ex);
}
@@ -1283,11 +1248,19 @@ public void releaseSem() {
}
protected void semRelease() {
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- logger.logDebug("semRelease ]]]]" + this);
- logger.logStackTrace();
+ try {
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
+ sipStack.getStackLogger().logDebug("semRelease ]]]]" + this);
+ sipStack.getStackLogger().logStackTrace();
+ }
+ this.isSemaphoreAquired = false;
+ this.semaphore.release();
+
+ } catch (Exception ex) {
+ sipStack.getStackLogger().logError("Unexpected exception releasing sem",
+ ex);
+
}
- this.semaphore.release();
}
/**
@@ -1303,8 +1276,8 @@ public boolean passToListener() {
* Set the passToListener flag to true.
*/
public void setPassToListener() {
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- logger.logDebug("setPassToListener()");
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
+ sipStack.getStackLogger().logDebug("setPassToListener()");
}
this.toListener = true;
@@ -1365,8 +1338,8 @@ public List extractCertIdentities() throws SSLPeerUnverifiedException {
List certIdentities = new ArrayList();
Certificate[] certs = getPeerCertificates();
if (certs == null) {
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- logger.logDebug("No certificates available");
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
+ sipStack.getStackLogger().logDebug("No certificates available");
}
return certIdentities;
}
@@ -1376,16 +1349,16 @@ public List extractCertIdentities() throws SSLPeerUnverifiedException {
try {
subjAltNames = x509cert.getSubjectAlternativeNames();
} catch (CertificateParsingException ex) {
- if (logger.isLoggingEnabled()) {
- logger.logError("Error parsing TLS certificate", ex);
+ if (sipStack.isLoggingEnabled()) {
+ sipStack.getStackLogger().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);
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
+ sipStack.getStackLogger().logDebug("found subjAltNames: " + subjAltNames);
}
// First look for a URI in the subjectAltName field
// as per draft-ietf-sip-domain-certs-04
@@ -1397,14 +1370,14 @@ public List extractCertIdentities() throws SSLPeerUnverifiedException {
try {
altNameUri = new AddressFactoryImpl().createSipURI((String) altName.get(1));
String altHostName = altNameUri.getHost();
- if (logger.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
- logger.logDebug(
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
+ sipStack.getStackLogger().logDebug(
"found uri " + altName.get(1) + ", hostName " + altHostName);
}
certIdentities.add(altHostName);
} catch (ParseException e) {
- if (logger.isLoggingEnabled()) {
- logger.logError(
+ if (sipStack.isLoggingEnabled()) {
+ sipStack.getStackLogger().logError(
"certificate contains invalid uri: " + altName.get(1));
}
}
@@ -1418,8 +1391,8 @@ public List extractCertIdentities() throws SSLPeerUnverifiedException {
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));
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
+ sipStack.getStackLogger().logDebug("found dns " + altName.get(1));
}
certIdentities.add(altName.get(1).toString());
}
@@ -1437,14 +1410,14 @@ public List extractCertIdentities() throws SSLPeerUnverifiedException {
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);
+ if (sipStack.isLoggingEnabled(LogWriter.TRACE_DEBUG)) {
+ sipStack.getStackLogger().logDebug("found CN: " + cname + " from DN: " + dname);
}
certIdentities.add(cname);
}
} catch (Exception ex) {
- if (logger.isLoggingEnabled()) {
- logger.logError("exception while extracting CN", ex);
+ if (sipStack.isLoggingEnabled()) {
+ sipStack.getStackLogger().logError("exception while extracting CN", ex);
}
}
}
@@ -1454,6 +1427,7 @@ public List extractCertIdentities() throws SSLPeerUnverifiedException {
throw new UnsupportedOperationException("Not a TLS channel");
}
+
/**
* Start the timer that runs the transaction state machine.
*
@@ -1479,22 +1453,7 @@ public List extractCertIdentities() throws SSLPeerUnverifiedException {
*/
protected abstract void fireTimeoutTimer();
- /*
- * (non-Javadoc)
- * @see gov.nist.javax.sip.DialogExt#isReleaseReferences()
- */
- public boolean isReleaseReferences() {
- return releaseReferences;
- }
- /*
- * (non-Javadoc)
- * @see gov.nist.javax.sip.DialogExt#setReleaseReferences(boolean)
- */
- public void setReleaseReferences(boolean releaseReferences) {
- this.releaseReferences = releaseReferences;
- }
-
/*
* (non-Javadoc)
* @see gov.nist.javax.sip.TransactionExt#getTimerD()
@@ -1524,9 +1483,9 @@ public int getTimerT4() {
* @see gov.nist.javax.sip.TransactionExt#setTimerD(int)
*/
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");
- }
+ if(interval < 32000) {
+ throw new IllegalArgumentException("To be RFC 3261 compliant, the value of Timer D should be at least 32s");
+ }
TIMER_D = interval / BASE_TIMER_INTERVAL;
}
@@ -1547,21 +1506,4 @@ public void setTimerT4(int interval) {
TIMER_I = T4;
TIMER_K = T4;
}
-
-
- /**
- * Sets the fork id for the transaction.
- * @param forkId
- */
- public void setForkId(String forkId) {
- this.forkId = forkId;
- }
-
- /**
- * Retrieves the fork id for the transaction.
- * @return
- */
- public String getForkId() {
- return forkId;
- }
}
diff --git a/src/gov/nist/javax/sip/stack/SIPTransactionStack.java b/src/gov/nist/javax/sip/stack/SIPTransactionStack.java
index 0aa6f4e2f..8bd93fd9d 100755
--- a/src/gov/nist/javax/sip/stack/SIPTransactionStack.java
+++ b/src/gov/nist/javax/sip/stack/SIPTransactionStack.java
@@ -25,10 +25,8 @@
*/
package gov.nist.javax.sip.stack;
-import gov.nist.core.CommonLogger;
import gov.nist.core.Host;
import gov.nist.core.HostPort;
-import gov.nist.core.LogLevels;
import gov.nist.core.LogWriter;
import gov.nist.core.ServerLogger;
import gov.nist.core.StackLogger;
@@ -51,19 +49,20 @@
import gov.nist.javax.sip.message.SIPRequest;
import gov.nist.javax.sip.message.SIPResponse;
import gov.nist.javax.sip.parser.MessageParserFactory;
-import gov.nist.javax.sip.stack.timers.SipTimer;
import java.io.IOException;
import java.net.InetAddress;
import java.net.SocketAddress;
import java.net.UnknownHostException;
+import java.util.ArrayList;
import java.util.Collection;
+import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Set;
+import java.util.Timer;
import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@@ -94,844 +93,765 @@
*/
/**
- *
+ *
* This is the sip stack. It is essentially a management interface. It manages
* the resources for the JAIN-SIP implementation. This is the structure that is
* wrapped by the SipStackImpl.
- *
+ *
* @see gov.nist.javax.sip.SipStackImpl
- *
+ *
* @author M. Ranganathan
- *
- * @version 1.2 $Revision: 1.180 $ $Date: 2010-12-02 22:04:15 $
+ *
+ * @version 1.2 $Revision: 1.152.2.6 $ $Date: 2010-12-02 01:41:35 $
*/
public abstract class SIPTransactionStack implements
- SIPTransactionEventListener, SIPDialogEventListener {
- private static StackLogger logger = CommonLogger.getLogger(SIPTransactionStack.class);
- /*
- * Number of milliseconds between timer ticks (500).
- */
- public static final int BASE_TIMER_INTERVAL = 500;
-
- /*
- * Connection linger time (seconds) this is the time (in seconds) for which
- * we linger the TCP connection before closing it.
- */
- public static final int CONNECTION_LINGER_TIME = 8;
-
- /*
- * Dialog Early state timeout duration.
- */
- protected int earlyDialogTimeout = 180;
-
+ SIPTransactionEventListener, SIPDialogEventListener {
- /*
- * Table of retransmission Alert timers.
- */
- protected ConcurrentHashMap retransmissionAlertTransactions;
+ /*
+ * Number of milliseconds between timer ticks (500).
+ */
+ public static final int BASE_TIMER_INTERVAL = 500;
- // Table of early dialogs ( to keep identity mapping )
- protected ConcurrentHashMap earlyDialogTable;
+ /*
+ * Connection linger time (seconds) this is the time (in seconds) for which
+ * we linger the TCP connection before closing it.
+ */
+ public static final int CONNECTION_LINGER_TIME = 8;
- // Table of dialogs.
- protected ConcurrentHashMap dialogTable;
+ /*
+ * Table of retransmission Alert timers.
+ */
+ protected ConcurrentHashMap retransmissionAlertTransactions;
- // Table of server dialogs ( for loop detection)
- protected ConcurrentHashMap serverDialogMergeTestTable;
+ // Table of early dialogs ( to keep identity mapping )
+ protected ConcurrentHashMap earlyDialogTable;
- // A set of methods that result in dialog creations.
- protected static final Set dialogCreatingMethods = new HashSet();
+ // Table of dialogs.
+ protected ConcurrentHashMap dialogTable;
- // Global timer. Use this for all timer tasks.
+ // Table of server dialogs ( for loop detection)
+ protected ConcurrentHashMap serverDialogMergeTestTable;
- private SipTimer timer;
+ // A set of methods that result in dialog creations.
+ protected static final Set dialogCreatingMethods = new HashSet();
- // List of pending server transactions
- private ConcurrentHashMap pendingTransactions;
+ // Global timer. Use this for all timer tasks.
- // hashtable for fast lookup
- protected ConcurrentHashMap clientTransactionTable;
+ private Timer timer;
- // Set to false if you want hiwat and lowat to be consulted.
- protected boolean unlimitedServerTransactionTableSize = true;
+ // List of pending server transactions
+ private ConcurrentHashMap pendingTransactions;
- // Set to false if you want unlimited size of client trnansactin table.
- protected boolean unlimitedClientTransactionTableSize = true;
-
- // High water mark for ServerTransaction Table
- // after which requests are dropped.
- protected int serverTransactionTableHighwaterMark = 5000;
-
- // Low water mark for Server Tx table size after which
- // requests are selectively dropped
- protected int serverTransactionTableLowaterMark = 4000;
-
- // Hiwater mark for client transaction table. These defaults can be
- // overriden by stack
- // configuration.
- protected int clientTransactionTableHiwaterMark = 1000;
-
- // Low water mark for client tx table.
- protected int clientTransactionTableLowaterMark = 800;
-
- private AtomicInteger activeClientTransactionCount = new AtomicInteger(0);
-
- // Hashtable for server transactions.
- protected ConcurrentHashMap serverTransactionTable;
-
- // A table of ongoing transactions indexed by mergeId ( for detecting merged
- // requests.
- private ConcurrentHashMap mergeTable;
-
- private ConcurrentHashMap terminatedServerTransactionsPendingAck;
-
- private ConcurrentHashMap forkedClientTransactionTable;
-
- protected boolean deliverRetransmittedAckToListener = false;
-
- /*
- * ServerLog is used just for logging stack message tracecs.
- */
- protected ServerLogger serverLogger;
-
- /*
- * We support UDP on this stack.
- */
- boolean udpFlag;
-
- /*
- * Internal router. Use this for all sip: request routing.
- */
- protected DefaultRouter defaultRouter;
-
- /*
- * Global flag that turns logging off
- */
- protected boolean needsLogging;
-
- /*
- * Flag used for testing TI, bypasses filtering of ACK to non-2xx
- */
- private boolean non2XXAckPassedToListener;
-
- /*
- * Class that handles caching of TCP/TLS connections.
- */
- protected IOHandler ioHandler;
+ // hashtable for fast lookup
+ private ConcurrentHashMap clientTransactionTable;
- /*
- * Flag that indicates that the stack is active.
- */
- protected boolean toExit;
+ // Set to false if you want hiwat and lowat to be consulted.
+ protected boolean unlimitedServerTransactionTableSize = true;
- /*
- * Name of the stack.
- */
- protected String stackName;
+ // Set to false if you want unlimited size of client trnansactin table.
+ protected boolean unlimitedClientTransactionTableSize = true;
- /*
- * IP address of stack -- this can be re-written by stun.
- *
- * @deprecated
- */
- protected String stackAddress;
+ // High water mark for ServerTransaction Table
+ // after which requests are dropped.
+ protected int serverTransactionTableHighwaterMark = 5000;
- /*
- * INET address of stack (cached to avoid repeated lookup)
- *
- * @deprecated
- */
- protected InetAddress stackInetAddress;
-
- /*
- * Request factory interface (to be provided by the application)
- */
- protected StackMessageFactory sipMessageFactory;
-
- /*
- * Router to determine where to forward the request.
- */
- protected javax.sip.address.Router router;
-
- /*
- * Number of pre-allocated threads for processing udp messages. -1 means no
- * preallocated threads ( dynamically allocated threads).
- */
- protected int threadPoolSize;
-
- /*
- * max number of simultaneous connections.
- */
- protected int maxConnections;
-
- /*
- * Close accept socket on completion.
- */
- protected boolean cacheServerConnections;
+ // Low water mark for Server Tx table size after which
+ // requests are selectively dropped
+ protected int serverTransactionTableLowaterMark = 4000;
- /*
- * Close connect socket on Tx termination.
- */
- protected boolean cacheClientConnections;
+ // Hiwater mark for client transaction table. These defaults can be
+ // overriden by stack
+ // configuration.
+ protected int clientTransactionTableHiwaterMark = 1000;
- /*
- * Use the user supplied router for all out of dialog requests.
- */
- protected boolean useRouterForAll;
-
- /*
- * Max size of message that can be read from a TCP connection.
- */
- protected int maxContentLength;
+ // Low water mark for client tx table.
+ protected int clientTransactionTableLowaterMark = 800;
+
+ private AtomicInteger activeClientTransactionCount = new AtomicInteger(0);
+
+ // Hashtable for server transactions.
+ private ConcurrentHashMap serverTransactionTable;
+
+ // A table of ongoing transactions indexed by mergeId ( for detecting merged
+ // requests.
+ private ConcurrentHashMap mergeTable;
+
+ private ConcurrentHashMap terminatedServerTransactionsPendingAck;
+
+ private ConcurrentHashMap forkedClientTransactionTable;
+
+ protected boolean deliverRetransmittedAckToListener = false;
+
+ /*
+ * A wrapper around differnt logging implementations (log4j, commons
+ * logging, slf4j, ...) to help log debug.
+ */
+ private StackLogger stackLogger;
+
+ /*
+ * ServerLog is used just for logging stack message tracecs.
+ */
+ protected ServerLogger serverLogger;
+
+ /*
+ * We support UDP on this stack.
+ */
+ boolean udpFlag;
+
+ /*
+ * Internal router. Use this for all sip: request routing.
+ */
+ protected DefaultRouter defaultRouter;
+
+ /*
+ * Global flag that turns logging off
+ */
+ protected boolean needsLogging;
+
+ /*
+ * Flag used for testing TI, bypasses filtering of ACK to non-2xx
+ */
+ private boolean non2XXAckPassedToListener;
+
+ /*
+ * Class that handles caching of TCP/TLS connections.
+ */
+ protected IOHandler ioHandler;
+
+ /*
+ * Flag that indicates that the stack is active.
+ */
+ protected boolean toExit;
- /*
- * Max # of headers that a SIP message can contain.
- */
- protected int maxMessageSize;
-
- /*
- * A collection of message processors.
- */
- private Collection messageProcessors;
-
- /*
- * Read timeout on TCP incoming sockets -- defines the time between reads
- * for after delivery of first byte of message.
- */
- protected int readTimeout;
-
- /*
- * The socket factory. Can be overriden by applications that want direct
- * access to the underlying socket.
- */
-
- protected NetworkLayer networkLayer;
+ /*
+ * Name of the stack.
+ */
+ protected String stackName;
- /*
- * Outbound proxy String ( to be handed to the outbound proxy class on
- * creation).
- */
- protected String outboundProxy;
+ /*
+ * IP address of stack -- this can be re-written by stun.
+ *
+ * @deprecated
+ */
+ protected String stackAddress;
+
+ /*
+ * INET address of stack (cached to avoid repeated lookup)
+ *
+ * @deprecated
+ */
+ protected InetAddress stackInetAddress;
+
+ /*
+ * Request factory interface (to be provided by the application)
+ */
+ protected StackMessageFactory sipMessageFactory;
+
+ /*
+ * Router to determine where to forward the request.
+ */
+ protected javax.sip.address.Router router;
+
+ /*
+ * Number of pre-allocated threads for processing udp messages. -1 means no
+ * preallocated threads ( dynamically allocated threads).
+ */
+ protected int threadPoolSize;
+
+ /*
+ * max number of simultaneous connections.
+ */
+ protected int maxConnections;
+
+ /*
+ * Close accept socket on completion.
+ */
+ protected boolean cacheServerConnections;
+
+ /*
+ * Close connect socket on Tx termination.
+ */
+ protected boolean cacheClientConnections;
+
+ /*
+ * Use the user supplied router for all out of dialog requests.
+ */
+ protected boolean useRouterForAll;
+
+ /*
+ * Max size of message that can be read from a TCP connection.
+ */
+ protected int maxContentLength;
+
+ /*
+ * Max # of headers that a SIP message can contain.
+ */
+ protected int maxMessageSize;
+
+ /*
+ * A collection of message processors.
+ */
+ private Collection messageProcessors;
+
+ /*
+ * Read timeout on TCP incoming sockets -- defines the time between reads
+ * for after delivery of first byte of message.
+ */
+ protected int readTimeout;
+
+ /*
+ * The socket factory. Can be overriden by applications that want direct
+ * access to the underlying socket.
+ */
+
+ protected NetworkLayer networkLayer;
- protected String routerPath;
+ /*
+ * Outbound proxy String ( to be handed to the outbound proxy class on
+ * creation).
+ */
+ protected String outboundProxy;
- // Flag to indicate whether the stack will provide dialog
- // support.
- protected boolean isAutomaticDialogSupportEnabled;
+ protected String routerPath;
- // The set of events for which subscriptions can be forked.
+ // Flag to indicate whether the stack will provide dialog
+ // support.
+ protected boolean isAutomaticDialogSupportEnabled;
- protected HashSet forkedEvents;
+ // The set of events for which subscriptions can be forked.
- // Generate a timestamp header for retransmitted requests.
- protected boolean generateTimeStampHeader;
+ protected HashSet forkedEvents;
- protected AddressResolver addressResolver;
+ // Generate a timestamp header for retransmitted requests.
+ protected boolean generateTimeStampHeader;
- // Max time that the listener is allowed to take to respond to a
- // request. Default is "infinity". This property allows
- // containers to defend against buggy clients (that do not
- // want to respond to requests).
- protected int maxListenerResponseTime;
+ protected AddressResolver addressResolver;
- // A flag that indicates whether or not RFC 2543 clients are fully
- // supported.
- // If this is set to true, then To tag checking on the Dialog layer is
- // disabled in a few places - resulting in possible breakage of forked
- // dialogs.
- protected boolean rfc2543Supported = true;
+ // Max time that the listener is allowed to take to respond to a
+ // request. Default is "infinity". This property allows
+ // containers to defend against buggy clients (that do not
+ // want to respond to requests).
+ protected int maxListenerResponseTime;
- // / Provides a mechanism for applications to check the health of threads in
- // the stack
- protected ThreadAuditor threadAuditor = new ThreadAuditor();
+ // A flag that indicates whether or not RFC 2543 clients are fully
+ // supported.
+ // If this is set to true, then To tag checking on the Dialog layer is
+ // disabled in a few places - resulting in possible breakage of forked
+ // dialogs.
+ protected boolean rfc2543Supported = true;
- protected LogRecordFactory logRecordFactory;
+ // / Provides a mechanism for applications to check the health of threads in
+ // the stack
+ protected ThreadAuditor threadAuditor = new ThreadAuditor();
- // Set to true if the client CANCEL transaction should be checked before
- // sending
- // it out.
- protected boolean cancelClientTransactionChecked = true;
+ protected LogRecordFactory logRecordFactory;
- // Is to tag reassignment allowed.
- protected boolean remoteTagReassignmentAllowed = true;
+ // Set to true if the client CANCEL transaction should be checked before
+ // sending
+ // it out.
+ protected boolean cancelClientTransactionChecked = true;
- protected boolean logStackTraceOnMessageSend = true;
+ // Is to tag reassignment allowed.
+ protected boolean remoteTagReassignmentAllowed = true;
- // Receive UDP buffer size
- protected int receiveUdpBufferSize;
+ protected boolean logStackTraceOnMessageSend = true;
- // Send UDP buffer size
- protected int sendUdpBufferSize;
+ // Receive UDP buffer size
+ protected int receiveUdpBufferSize;
- protected int stackCongenstionControlTimeout = 0;
+ // Send UDP buffer size
+ protected int sendUdpBufferSize;
- protected boolean isBackToBackUserAgent = false;
+ protected int stackCongestionControlTimeout = 0;
- protected boolean checkBranchId;
+ protected boolean isBackToBackUserAgent = false;
- protected boolean isAutomaticDialogErrorHandlingEnabled = true;
+ protected boolean checkBranchId;
- protected boolean isDialogTerminatedEventDeliveredForNullDialog = false;
+ protected boolean isAutomaticDialogErrorHandlingEnabled = true;
- // Max time for a forked response to arrive. After this time, the original
- // dialog
- // is not tracked. If you want to track the original transaction you need to
- // specify
- // the max fork time with a stack init property.
- protected int maxForkTime = 0;
+ protected boolean isDialogTerminatedEventDeliveredForNullDialog = false;
- // Whether or not to deliver unsolicited NOTIFY
+ // Max time for a forked response to arrive. After this time, the original
+ // dialog
+ // is not tracked. If you want to track the original transaction you need to
+ // specify
+ // the max fork time with a stack init property.
+ protected int maxForkTime = 0;
- private boolean deliverUnsolicitedNotify = false;
+ // Whether or not to deliver unsolicited NOTIFY
- private boolean deliverTerminatedEventForAck = false;
+ private boolean deliverUnsolicitedNotify = false;
- protected ClientAuthType clientAuth = ClientAuthType.Default;
-
- // ThreadPool when parsed SIP messages are processed. Affects the case when many TCP calls use single socket.
- private int tcpPostParsingThreadPoolSize = 0;
-
- // Minimum time between NAT kee alive pings from clients.
- // Any ping that exceeds this time will result in CRLF CRLF going
- // from the UDP message channel.
- protected long minKeepAliveInterval = -1L;
-
- // The time after which a "dialog timeout event" is delivered to a listener.
- protected int dialogTimeoutFactor = 64;
-
- // factory used to create MessageParser objects
- public MessageParserFactory messageParserFactory;
- // factory used to create MessageProcessor objects
- public MessageProcessorFactory messageProcessorFactory;
+ private boolean deliverTerminatedEventForAck = false;
+
+ // ThreadPool when parsed SIP messages are processed. Affects the case when many TCP calls use single socket.
+ private int tcpPostParsingThreadPoolSize = 0;
+
+ // Minimum time between NAT kee alive pings from clients.
+ // Any ping that exceeds this time will result in CRLF CRLF going
+ // from the UDP message channel.
+ protected long minKeepAliveInterval = -1L;
+
+ // The time after which a "dialog timeout event" is delivered to a listener.
+ protected int dialogTimeoutFactor = 64;
+ public SIPEventInterceptor sipEventInterceptor;
+
+ // factory used to create MessageParser objects
+ protected MessageParserFactory messageParserFactory;
+ // factory used to create MessageProcessor objects
+ protected MessageProcessorFactory messageProcessorFactory;
+
+ /**
+ * Executor used to optimise the ReinviteSender Runnable in the sendRequest
+ * of the SipDialog
+ */
+ protected static Executor selfRoutingThreadpoolExecutor;
+
+ private static class SameThreadExecutor implements Executor {
- protected boolean aggressiveCleanup = false;
+ public void execute(Runnable command) {
+ command.run(); // Just run the command is the same thread
+ }
+
+ }
+
+ public Executor getSelfRoutingThreadpoolExecutor() {
+ if(selfRoutingThreadpoolExecutor == null) {
+ if(this.threadPoolSize<=0) {
+ selfRoutingThreadpoolExecutor = new SameThreadExecutor();
+ } else {
+ selfRoutingThreadpoolExecutor = Executors.newFixedThreadPool(this.threadPoolSize);
+ }
+ }
+ return selfRoutingThreadpoolExecutor;
+ }
+
+ /**
+ * Executor used to optimise the ReinviteSender Runnable in the sendRequest
+ * of the SipDialog
+ */
+ private ExecutorService reinviteExecutor = Executors
+ .newCachedThreadPool(new ThreadFactory() {
+ private int threadCount = 0;
+
+ public Thread newThread(Runnable pRunnable) {
+ return new Thread(pRunnable, String.format("%s-%d",
+ "ReInviteSender", threadCount++));
+ }
+ });
- public SIPMessageValve sipMessageValve;
-
- public SIPEventInterceptor sipEventInterceptor;
+ // / Timer to regularly ping the thread auditor (on behalf of the timer
+ // thread)
+ class PingTimer extends SIPStackTimerTask {
+ // / Timer thread handle
+ ThreadAuditor.ThreadHandle threadHandle;
- protected static Executor selfRoutingThreadpoolExecutor;
+ // / Constructor
+ public PingTimer(ThreadAuditor.ThreadHandle a_oThreadHandle) {
+ threadHandle = a_oThreadHandle;
+ }
- private static class SameThreadExecutor implements Executor {
+ protected void runTask() {
+ // Check if we still have a timer (it may be null after shutdown)
+ if (getTimer() != null) {
+ // Register the timer task if we haven't done so
+ if (threadHandle == null) {
+ // This happens only once since the thread handle is passed
+ // to the next scheduled ping timer
+ threadHandle = getThreadAuditor().addCurrentThread();
+ }
- public void execute(Runnable command) {
- command.run(); // Just run the command is the same thread
- }
+ // Let the thread auditor know that the timer task is alive
+ threadHandle.ping();
- }
+ // Schedule the next ping
+ getTimer().schedule(new PingTimer(threadHandle),
+ threadHandle.getPingIntervalInMillisecs());
+ }
+ }
- public Executor getSelfRoutingThreadpoolExecutor() {
- if(selfRoutingThreadpoolExecutor == null) {
- if(this.threadPoolSize<=0) {
- selfRoutingThreadpoolExecutor = new SameThreadExecutor();
- } else {
- selfRoutingThreadpoolExecutor = Executors.newFixedThreadPool(this.threadPoolSize);
- }
- }
- return selfRoutingThreadpoolExecutor;
- }
- /**
- * Executor used to optimise the ReinviteSender Runnable in the sendRequest
- * of the SipDialog
- */
- private ExecutorService reinviteExecutor = Executors
- .newCachedThreadPool(new ThreadFactory() {
- private int threadCount = 0;
-
- public Thread newThread(Runnable pRunnable) {
- return new Thread(pRunnable, String.format("%s-%d",
- "ReInviteSender", threadCount++));
- }
- });
-
- // / Timer to regularly ping the thread auditor (on behalf of the timer
- // thread)
- protected class PingTimer extends SIPStackTimerTask {
- // / Timer thread handle
- ThreadAuditor.ThreadHandle threadHandle;
-
- // / Constructor
- public PingTimer(ThreadAuditor.ThreadHandle a_oThreadHandle) {
- threadHandle = a_oThreadHandle;
- }
-
- public void runTask() {
- // Check if we still have a timer (it may be null after shutdown)
- if (getTimer() != null) {
- // Register the timer task if we haven't done so
- if (threadHandle == null) {
- // This happens only once since the thread handle is passed
- // to the next scheduled ping timer
- threadHandle = getThreadAuditor().addCurrentThread();
- }
-
- // Let the thread auditor know that the timer task is alive
- threadHandle.ping();
-
- // Schedule the next ping
- getTimer().schedule(new PingTimer(threadHandle),
- threadHandle.getPingIntervalInMillisecs());
- }
- }
+ }
- }
+ class RemoveForkedTransactionTimerTask extends SIPStackTimerTask {
+ private SIPClientTransaction clientTransaction;
- class RemoveForkedTransactionTimerTask extends SIPStackTimerTask {
+ public RemoveForkedTransactionTimerTask(
+ SIPClientTransaction sipClientTransaction) {
+ this.clientTransaction = sipClientTransaction;
+ }
- private final String forkId;
+ @Override
+ protected void runTask() {
+ forkedClientTransactionTable.remove(((SIPRequest) clientTransaction
+ .getRequest()).getForkId());
+ }
- public RemoveForkedTransactionTimerTask(String forkId) {
- this.forkId = forkId;
- }
+ }
- @Override
- public void runTask() {
- forkedClientTransactionTable.remove(forkId);
- }
+ static {
+ // Standard set of methods that create dialogs.
+ dialogCreatingMethods.add(Request.REFER);
+ dialogCreatingMethods.add(Request.INVITE);
+ dialogCreatingMethods.add(Request.SUBSCRIBE);
+ }
- }
+ /**
+ * Default constructor.
+ */
+ protected SIPTransactionStack() {
+ this.toExit = false;
+ this.forkedEvents = new HashSet();
+ // set of events for which subscriptions can be forked.
+ // Set an infinite thread pool size.
+ this.threadPoolSize = -1;
+ // Close response socket after infinte time.
+ // for max performance
+ this.cacheServerConnections = true;
+ // Close the request socket after infinite time.
+ // for max performance
+ this.cacheClientConnections = true;
+ // Max number of simultaneous connections.
+ this.maxConnections = -1;
+ // Array of message processors.
+ messageProcessors = new ArrayList();
+ // Handle IO for this process.
+ this.ioHandler = new IOHandler(this);
+
+ // The read time out is infinite.
+ this.readTimeout = -1;
+
+ this.maxListenerResponseTime = -1;
+
+ // The default (identity) address lookup scheme
+
+ this.addressResolver = new DefaultAddressResolver();
+
+ // Notify may or may not create a dialog. This is handled in
+ // the code.
+ // Create the transaction collections
+
+ // Dialog dable.
+ this.dialogTable = new ConcurrentHashMap();
+ this.earlyDialogTable = new ConcurrentHashMap();
+ this.serverDialogMergeTestTable = new ConcurrentHashMap();
+
+ clientTransactionTable = new ConcurrentHashMap();
+ serverTransactionTable = new ConcurrentHashMap();
+ this.terminatedServerTransactionsPendingAck = new ConcurrentHashMap();
+ mergeTable = new ConcurrentHashMap();
+ retransmissionAlertTransactions = new ConcurrentHashMap();
+
+ // Start the timer event thread.
+
+ this.timer = new Timer();
+ this.pendingTransactions = new ConcurrentHashMap();
+
+ this.forkedClientTransactionTable = new ConcurrentHashMap();
+
+ if (getThreadAuditor().isEnabled()) {
+ // Start monitoring the timer thread
+ timer.schedule(new PingTimer(null), 0);
+ }
+ }
- static {
- // Standard set of methods that create dialogs.
- dialogCreatingMethods.add(Request.REFER);
- dialogCreatingMethods.add(Request.INVITE);
- dialogCreatingMethods.add(Request.SUBSCRIBE);
- }
+ /**
+ * Re Initialize the stack instance.
+ */
+ protected void reInit() {
+ if (stackLogger.isLoggingEnabled(LogWriter.TRACE_DEBUG))
+ stackLogger.logDebug("Re-initializing !");
+
+ // Array of message processors.
+ messageProcessors = new ArrayList();
+ // Handle IO for this process.
+ this.ioHandler = new IOHandler(this);
+ // clientTransactions = new ConcurrentLinkedQueue();
+ // serverTransactions = new ConcurrentLinkedQueue();
+ pendingTransactions = new ConcurrentHashMap();
+ clientTransactionTable = new ConcurrentHashMap();
+ serverTransactionTable = new ConcurrentHashMap();
+ retransmissionAlertTransactions = new ConcurrentHashMap();
+ mergeTable = new ConcurrentHashMap();
+ // Dialog dable.
+ this.dialogTable = new ConcurrentHashMap();
+ this.earlyDialogTable = new ConcurrentHashMap();
+ this.serverDialogMergeTestTable = new ConcurrentHashMap();
+ this.terminatedServerTransactionsPendingAck = new ConcurrentHashMap();
+ this.forkedClientTransactionTable = new ConcurrentHashMap();
+
+ this.timer = new Timer();
+
+ this.activeClientTransactionCount = new AtomicInteger(0);
- /**
- * Default constructor.
- */
- protected SIPTransactionStack() {
- this.toExit = false;
- this.forkedEvents = new HashSet();
- // set of events for which subscriptions can be forked.
- // Set an infinite thread pool size.
- this.threadPoolSize = -1;
- // Close response socket after infinte time.
- // for max performance
- this.cacheServerConnections = true;
- // Close the request socket after infinite time.
- // for max performance
- this.cacheClientConnections = true;
- // Max number of simultaneous connections.
- this.maxConnections = -1;
- // Array of message processors.
- // jeand : using concurrent data structure to avoid excessive blocking
- messageProcessors = new CopyOnWriteArrayList