1 /* 2 * Conditions Of Use 3 * 4 * This software was developed by employees of the National Institute of 5 * Standards and Technology (NIST), an agency of the Federal Government. 6 * Pursuant to title 15 Untied States Code Section 105, works of NIST 7 * employees are not subject to copyright protection in the United States 8 * and are considered to be in the public domain. As a result, a formal 9 * license is not needed to use the software. 10 * 11 * This software is provided by NIST as a service and is expressly 12 * provided "AS IS." NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED 13 * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF 14 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT 15 * AND DATA ACCURACY. NIST does not warrant or make any representations 16 * regarding the use of the software or the results thereof, including but 17 * not limited to the correctness, accuracy, reliability or usefulness of 18 * the software. 19 * 20 * Permission to use this software is contingent upon your acceptance 21 * of the terms of this agreement 22 * 23 * . 24 * 25 */ 26 /**************************************************************************/ 27 /* Product of NIST Advanced Networking Technologies Division */ 28 /**************************************************************************/ 29 package gov.nist.javax.sip.stack; 30 31 import gov.nist.core.InternalErrorHandler; 32 import gov.nist.core.NameValueList; 33 import gov.nist.javax.sip.DialogExt; 34 import gov.nist.javax.sip.ListeningPointImpl; 35 import gov.nist.javax.sip.SipListenerExt; 36 import gov.nist.javax.sip.SipProviderImpl; 37 import gov.nist.javax.sip.Utils; 38 import gov.nist.javax.sip.address.AddressImpl; 39 import gov.nist.javax.sip.address.SipUri; 40 import gov.nist.javax.sip.header.Authorization; 41 import gov.nist.javax.sip.header.CSeq; 42 import gov.nist.javax.sip.header.Contact; 43 import gov.nist.javax.sip.header.ContactList; 44 import gov.nist.javax.sip.header.From; 45 import gov.nist.javax.sip.header.MaxForwards; 46 import gov.nist.javax.sip.header.RAck; 47 import gov.nist.javax.sip.header.RSeq; 48 import gov.nist.javax.sip.header.Reason; 49 import gov.nist.javax.sip.header.RecordRoute; 50 import gov.nist.javax.sip.header.RecordRouteList; 51 import gov.nist.javax.sip.header.Require; 52 import gov.nist.javax.sip.header.Route; 53 import gov.nist.javax.sip.header.RouteList; 54 import gov.nist.javax.sip.header.SIPHeader; 55 import gov.nist.javax.sip.header.TimeStamp; 56 import gov.nist.javax.sip.header.To; 57 import gov.nist.javax.sip.header.Via; 58 import gov.nist.javax.sip.message.MessageFactoryImpl; 59 import gov.nist.javax.sip.message.SIPMessage; 60 import gov.nist.javax.sip.message.SIPRequest; 61 import gov.nist.javax.sip.message.SIPResponse; 62 63 import java.io.IOException; 64 import java.io.PrintWriter; 65 import java.io.Serializable; 66 import java.io.StringWriter; 67 import java.net.InetAddress; 68 import java.text.ParseException; 69 import java.util.ArrayList; 70 import java.util.Iterator; 71 import java.util.LinkedList; 72 import java.util.List; 73 import java.util.ListIterator; 74 import java.util.Set; 75 import java.util.concurrent.CopyOnWriteArraySet; 76 import java.util.concurrent.Semaphore; 77 import java.util.concurrent.TimeUnit; 78 79 import javax.sip.ClientTransaction; 80 import javax.sip.DialogDoesNotExistException; 81 import javax.sip.DialogState; 82 import javax.sip.IOExceptionEvent; 83 import javax.sip.InvalidArgumentException; 84 import javax.sip.ListeningPoint; 85 import javax.sip.ObjectInUseException; 86 import javax.sip.SipException; 87 import javax.sip.Transaction; 88 import javax.sip.TransactionDoesNotExistException; 89 import javax.sip.TransactionState; 90 import javax.sip.address.Address; 91 import javax.sip.address.Hop; 92 import javax.sip.address.SipURI; 93 import javax.sip.header.CallIdHeader; 94 import javax.sip.header.ContactHeader; 95 import javax.sip.header.EventHeader; 96 import javax.sip.header.OptionTag; 97 import javax.sip.header.RAckHeader; 98 import javax.sip.header.RSeqHeader; 99 import javax.sip.header.ReasonHeader; 100 import javax.sip.header.RequireHeader; 101 import javax.sip.header.RouteHeader; 102 import javax.sip.header.SupportedHeader; 103 import javax.sip.header.TimeStampHeader; 104 import javax.sip.message.Request; 105 import javax.sip.message.Response; 106 107 /* 108 * Acknowledgements: 109 * 110 * Bugs in this class were reported by Antonis Karydas, Brad Templeton, Jeff Adams, Alex Rootham , 111 * Martin Le Clerk, Christophe Anzille, Andreas Bystrom, Lebing Xie, Jeroen van Bemmel. Hagai Sela 112 * reported a bug in updating the route set (on RE-INVITE). Jens Tinfors submitted a bug fix and 113 * the .equals method. Jan Schaumloeffel contributed a buf fix ( memory leak was happening when 114 * 180 contained a To tag. 115 * 116 */ 117 118 /** 119 * Tracks dialogs. A dialog is a peer to peer association of communicating SIP entities. For 120 * INVITE transactions, a Dialog is created when a success message is received (i.e. a response 121 * that has a To tag). The SIP Protocol stores enough state in the message structure to extract a 122 * dialog identifier that can be used to retrieve this structure from the SipStack. 123 * 124 * @version 1.2 $Revision: 1.159 $ $Date: 2010/01/08 15:14:12 $ 125 * 126 * @author M. Ranganathan 127 * 128 * 129 */ 130 131 public class SIPDialog implements javax.sip.Dialog, DialogExt { 132 133 private static final long serialVersionUID = -1429794423085204069L; 134 135 private transient boolean dialogTerminatedEventDelivered; // prevent duplicate 136 137 private transient String stackTrace; // for semaphore debugging. 138 139 private String method; 140 141 // delivery of the event 142 private transient boolean isAssigned; 143 144 private boolean reInviteFlag; 145 146 private transient Object applicationData; // Opaque pointer to application data. 147 148 private transient SIPRequest originalRequest; 149 150 // Last response (JvB: either sent or received). 151 private SIPResponse lastResponse; 152 153 // Should be transient, in case the dialog is serialized it will be null 154 // so when a subsequent request will be sent it will be set and a new message channel can be 155 // created 156 private transient SIPTransaction firstTransaction; 157 158 private transient SIPTransaction lastTransaction; 159 160 private String dialogId; 161 162 private transient String earlyDialogId; 163 164 private long localSequenceNumber; 165 166 private long remoteSequenceNumber; 167 168 protected String myTag; 169 170 protected String hisTag; 171 172 private RouteList routeList; 173 174 private transient SIPTransactionStack sipStack; 175 176 private int dialogState; 177 178 protected transient boolean ackSeen; 179 180 private transient SIPRequest lastAckSent; 181 182 private SIPRequest lastAckReceived; 183 184 // could be set on recovery by examining the method looks like a duplicate of ackSeen 185 protected transient boolean ackProcessed; 186 187 protected transient DialogTimerTask timerTask; 188 189 protected transient Long nextSeqno; 190 191 private transient int retransmissionTicksLeft; 192 193 private transient int prevRetransmissionTicks; 194 195 private long originalLocalSequenceNumber; 196 197 // This is for debugging only. 198 private transient int ackLine; 199 200 // Audit tag used by the SIP Stack audit 201 public transient long auditTag = 0; 202 203 // The following fields are extracted from the request that created the 204 // Dialog. 205 206 protected javax.sip.address.Address localParty; 207 208 protected javax.sip.address.Address remoteParty; 209 210 protected CallIdHeader callIdHeader; 211 212 public final static int NULL_STATE = -1; 213 214 public final static int EARLY_STATE = DialogState._EARLY; 215 216 public final static int CONFIRMED_STATE = DialogState._CONFIRMED; 217 218 public final static int TERMINATED_STATE = DialogState._TERMINATED; 219 220 // the amount of time to keep this dialog around before the stack GC's it 221 222 private static final int DIALOG_LINGER_TIME = 8; 223 224 private boolean serverTransactionFlag; 225 226 private transient SipProviderImpl sipProvider; 227 228 private boolean terminateOnBye; 229 230 private transient boolean byeSent; // Flag set when BYE is sent, to disallow new 231 232 // requests 233 234 private Address remoteTarget; 235 236 private EventHeader eventHeader; // for Subscribe notify 237 238 // Stores the last OK for the INVITE 239 // Used in createAck. 240 private transient long lastInviteOkReceived; 241 242 private transient Semaphore ackSem = new Semaphore(1); 243 244 private transient int reInviteWaitTime = 100; 245 246 private transient DialogDeleteTask dialogDeleteTask; 247 248 private transient DialogDeleteIfNoAckSentTask dialogDeleteIfNoAckSentTask; 249 250 private transient boolean isAcknowledged; 251 252 private transient long highestSequenceNumberAcknowledged = -1; 253 254 private boolean isBackToBackUserAgent; 255 256 private boolean sequenceNumberValidation = true; 257 258 // List of event listeners for this dialog 259 private transient Set<SIPDialogEventListener> eventListeners; 260 // added for Issue 248 : https://jain-sip.dev.java.net/issues/show_bug.cgi?id=248 261 private Semaphore timerTaskLock = new Semaphore(1); 262 263 // We store here the useful data from the first transaction without having to 264 // keep the whole transaction object for the duration of the dialog. It also 265 // contains the non-transient information used in the replication of dialogs. 266 protected boolean firstTransactionSecure; 267 protected boolean firstTransactionSeen; 268 protected String firstTransactionMethod; 269 protected String firstTransactionId; 270 protected boolean firstTransactionIsServerTransaction; 271 protected int firstTransactionPort = 5060; 272 protected Contact contactHeader; 273 274 // ////////////////////////////////////////////////////// 275 // Inner classes 276 // ////////////////////////////////////////////////////// 277 278 /** 279 * This task waits till a pending ACK has been recorded and then sends out a re-INVITE. This 280 * is to prevent interleaving INVITEs ( which will result in a 493 from the UA that receives 281 * the out of order INVITE). This is primarily for B2BUA support. A B2BUA may send a delayed 282 * ACK while it does mid call codec renegotiation. In the meanwhile, it cannot send an intervening 283 * re-INVITE otherwise the othr end will respond with a REQUEST_PENDING. We want to avoid this 284 * condition. Hence we wait till the ACK for the previous re-INVITE has been sent before 285 * sending the next re-INVITE. 286 */ 287 public class ReInviteSender implements Runnable, Serializable { 288 private static final long serialVersionUID = 1019346148741070635L; 289 ClientTransaction ctx; 290 291 public void terminate() { 292 try { 293 ctx.terminate(); 294 Thread.currentThread().interrupt(); 295 } catch (ObjectInUseException e) { 296 sipStack.getStackLogger().logError("unexpected error", e); 297 } 298 } 299 300 public ReInviteSender(ClientTransaction ctx) { 301 this.ctx = ctx; 302 } 303 304 public void run() { 305 try { 306 long timeToWait = 0; 307 long startTime = System.currentTimeMillis(); 308 309 if (!SIPDialog.this.takeAckSem()) { 310 /* 311 * Could not send re-INVITE fire a timeout on the INVITE. 312 */ 313 if (sipStack.isLoggingEnabled()) 314 sipStack.getStackLogger().logError( 315 "Could not send re-INVITE time out ClientTransaction"); 316 ((SIPClientTransaction) ctx).fireTimeoutTimer(); 317 /* 318 * Send BYE to the Dialog. 319 */ 320 if ( sipProvider.getSipListener() != null && sipProvider.getSipListener() instanceof SipListenerExt ) { 321 raiseErrorEvent(SIPDialogErrorEvent.DIALOG_REINVITE_TIMEOUT); 322 } else { 323 Request byeRequest = SIPDialog.this.createRequest(Request.BYE); 324 if ( MessageFactoryImpl.getDefaultUserAgentHeader() != null ) { 325 byeRequest.addHeader(MessageFactoryImpl.getDefaultUserAgentHeader()); 326 } 327 ReasonHeader reasonHeader = new Reason(); 328 reasonHeader.setCause(1024); 329 reasonHeader.setText("Timed out waiting to re-INVITE"); 330 byeRequest.addHeader(reasonHeader); 331 ClientTransaction byeCtx = SIPDialog.this.getSipProvider().getNewClientTransaction(byeRequest); 332 SIPDialog.this.sendRequest(byeCtx); 333 return; 334 } 335 } 336 if (getState() != DialogState.TERMINATED) { 337 338 timeToWait = System.currentTimeMillis() - startTime; 339 } 340 341 /* 342 * If we had to wait for ACK then wait for the ACK to actually get to the other 343 * side. Wait for any ACK retransmissions to finish. Then send out the request. 344 * This is a hack in support of some UA that want re-INVITEs to be spaced out in 345 * time ( else they return a 400 error code ). 346 */ 347 try { 348 if (timeToWait != 0) { 349 Thread.sleep(SIPDialog.this.reInviteWaitTime); 350 } 351 } catch (InterruptedException ex) { 352 if (sipStack.isLoggingEnabled()) 353 sipStack.getStackLogger().logDebug("Interrupted sleep"); 354 return; 355 } 356 if (SIPDialog.this.getState() != DialogState.TERMINATED) { 357 SIPDialog.this.sendRequest(ctx, true); 358 } 359 if (sipStack.isLoggingEnabled()) 360 sipStack.getStackLogger().logDebug("re-INVITE successfully sent"); 361 } catch (Exception ex) { 362 sipStack.getStackLogger().logError("Error sending re-INVITE", ex); 363 } finally { 364 this.ctx = null; 365 } 366 } 367 } 368 369 class LingerTimer extends SIPStackTimerTask implements Serializable { 370 371 public LingerTimer() { 372 373 } 374 375 protected void runTask() { 376 SIPDialog dialog = SIPDialog.this; 377 if(eventListeners != null) { 378 eventListeners.clear(); 379 } 380 timerTaskLock = null; 381 sipStack.removeDialog(dialog); 382 } 383 384 } 385 386 class DialogTimerTask extends SIPStackTimerTask implements Serializable { 387 int nRetransmissions; 388 389 SIPServerTransaction transaction; 390 391 public DialogTimerTask(SIPServerTransaction transaction) { 392 this.transaction = transaction; 393 this.nRetransmissions = 0; 394 } 395 396 protected void runTask() { 397 // If I ACK has not been seen on Dialog, 398 // resend last response. 399 SIPDialog dialog = SIPDialog.this; 400 if (sipStack.isLoggingEnabled()) 401 sipStack.getStackLogger().logDebug("Running dialog timer"); 402 nRetransmissions++; 403 SIPServerTransaction transaction = this.transaction; 404 /* 405 * Issue 106. Section 13.3.1.4 RFC 3261 The 2xx response is passed to the transport 406 * with an interval that starts at T1 seconds and doubles for each retransmission 407 * until it reaches T2 seconds If the server retransmits the 2xx response for 64*T1 408 * seconds without receiving an ACK, the dialog is confirmed, but the session SHOULD 409 * be terminated. 410 */ 411 412 if (nRetransmissions > 64 * SIPTransaction.T1) { 413 if (sipProvider.getSipListener() != null && sipProvider.getSipListener() instanceof SipListenerExt ) { 414 raiseErrorEvent(SIPDialogErrorEvent.DIALOG_ACK_NOT_RECEIVED_TIMEOUT); 415 } else { 416 dialog.delete(); 417 } 418 if (transaction != null 419 && transaction.getState() != javax.sip.TransactionState.TERMINATED) { 420 transaction.raiseErrorEvent(SIPTransactionErrorEvent.TIMEOUT_ERROR); 421 } 422 } else if ((!dialog.ackSeen) && (transaction != null)) { 423 // Retransmit to 200 until ack receivedialog. 424 SIPResponse response = transaction.getLastResponse(); 425 if (response.getStatusCode() == 200) { 426 try { 427 428 // resend the last response. 429 if (dialog.toRetransmitFinalResponse(transaction.T2)) 430 transaction.sendMessage(response); 431 432 } catch (IOException ex) { 433 434 raiseIOException(transaction.getPeerAddress(), transaction.getPeerPort(), 435 transaction.getPeerProtocol()); 436 437 } finally { 438 // Need to fire the timer so 439 // transaction will eventually 440 // time out whether or not 441 // the IOException occurs 442 // Note that this firing also 443 // drives Listener timeout. 444 SIPTransactionStack stack = dialog.sipStack; 445 if (stack.isLoggingEnabled()) { 446 stack.getStackLogger().logDebug("resend 200 response from " + dialog); 447 } 448 transaction.fireTimer(); 449 } 450 } 451 } 452 453 // Stop running this timer if the dialog is in the 454 // confirmed state or ack seen if retransmit filter on. 455 if (dialog.isAckSeen() || dialog.dialogState == TERMINATED_STATE) { 456 this.transaction = null; 457 this.cancel(); 458 459 } 460 461 } 462 463 } 464 465 /** 466 * This timer task is used to garbage collect the dialog after some time. 467 * 468 */ 469 470 class DialogDeleteTask extends SIPStackTimerTask implements Serializable { 471 472 protected void runTask() { 473 delete(); 474 } 475 476 } 477 478 /** 479 * This timer task is used to garbage collect the dialog after some time. 480 * 481 */ 482 483 class DialogDeleteIfNoAckSentTask extends SIPStackTimerTask implements Serializable { 484 private long seqno; 485 486 public DialogDeleteIfNoAckSentTask(long seqno) { 487 this.seqno = seqno; 488 } 489 490 protected void runTask() { 491 if (SIPDialog.this.highestSequenceNumberAcknowledged < seqno) { 492 /* 493 * Did not send ACK so we need to delete the dialog. 494 * B2BUA NOTE: we may want to send BYE to the Dialog at this 495 * point. Do we want to make this behavior tailorable? 496 */ 497 dialogDeleteIfNoAckSentTask = null; 498 if ( !SIPDialog.this.isBackToBackUserAgent) { 499 if (sipStack.isLoggingEnabled()) 500 sipStack.getStackLogger().logError("ACK Was not sent. killing dialog"); 501 if ( ((SipProviderImpl)sipProvider).getSipListener() instanceof SipListenerExt ){ 502 raiseErrorEvent(SIPDialogErrorEvent.DIALOG_ACK_NOT_SENT_TIMEOUT); 503 } else { 504 delete(); 505 } 506 } else { 507 if (sipStack.isLoggingEnabled()) 508 sipStack.getStackLogger().logError("ACK Was not sent. Sending BYE"); 509 if ( ((SipProviderImpl)sipProvider).getSipListener() instanceof SipListenerExt ){ 510 raiseErrorEvent(SIPDialogErrorEvent.DIALOG_ACK_NOT_SENT_TIMEOUT); 511 } else { 512 513 /* 514 * Send BYE to the Dialog. 515 * This will be removed for the next spec revision. 516 */ 517 try { 518 Request byeRequest = SIPDialog.this.createRequest(Request.BYE); 519 if ( MessageFactoryImpl.getDefaultUserAgentHeader() != null ) { 520 byeRequest.addHeader(MessageFactoryImpl.getDefaultUserAgentHeader()); 521 } 522 ReasonHeader reasonHeader = new Reason(); 523 reasonHeader.setProtocol("SIP"); 524 reasonHeader.setCause(1025); 525 reasonHeader.setText("Timed out waiting to send ACK"); 526 byeRequest.addHeader(reasonHeader); 527 ClientTransaction byeCtx = SIPDialog.this.getSipProvider().getNewClientTransaction(byeRequest); 528 SIPDialog.this.sendRequest(byeCtx); 529 return; 530 } catch (Exception ex) { 531 SIPDialog.this.delete(); 532 } 533 } 534 } 535 } 536 } 537 538 } 539 540 // /////////////////////////////////////////////////////////// 541 // Constructors. 542 // /////////////////////////////////////////////////////////// 543 /** 544 * Protected Dialog constructor. 545 */ 546 private SIPDialog(SipProviderImpl provider) { 547 this.terminateOnBye = true; 548 this.routeList = new RouteList(); 549 this.dialogState = NULL_STATE; // not yet initialized. 550 localSequenceNumber = 0; 551 remoteSequenceNumber = -1; 552 this.sipProvider = provider; 553 eventListeners = new CopyOnWriteArraySet<SIPDialogEventListener>(); 554 } 555 556 private void recordStackTrace() { 557 StringWriter stringWriter = new StringWriter(); 558 PrintWriter writer = new PrintWriter(stringWriter); 559 new Exception().printStackTrace(writer); 560 this.stackTrace = stringWriter.getBuffer().toString(); 561 } 562 563 /** 564 * Constructor given the first transaction. 565 * 566 * @param transaction is the first transaction. 567 */ 568 public SIPDialog(SIPTransaction transaction) { 569 this(transaction.getSipProvider()); 570 571 SIPRequest sipRequest = (SIPRequest) transaction.getRequest(); 572 this.callIdHeader = sipRequest.getCallId(); 573 this.earlyDialogId = sipRequest.getDialogId(false); 574 if (transaction == null) 575 throw new NullPointerException("Null tx"); 576 this.sipStack = transaction.sipStack; 577 578 // this.defaultRouter = new DefaultRouter((SipStack) sipStack, 579 // sipStack.outboundProxy); 580 581 this.sipProvider = (SipProviderImpl) transaction.getSipProvider(); 582 if (sipProvider == null) 583 throw new NullPointerException("Null Provider!"); 584 this.addTransaction(transaction); 585 if (sipStack.isLoggingEnabled()) { 586 sipStack.getStackLogger().logDebug("Creating a dialog : " + this); 587 sipStack.getStackLogger().logDebug( 588 "provider port = " + this.sipProvider.getListeningPoint().getPort()); 589 sipStack.getStackLogger().logStackTrace(); 590 } 591 this.isBackToBackUserAgent = sipStack.isBackToBackUserAgent; 592 addEventListener(sipStack); 593 } 594 595 /** 596 * Constructor given a transaction and a response. 597 * 598 * @param transaction -- the transaction ( client/server) 599 * @param sipResponse -- response with the appropriate tags. 600 */ 601 public SIPDialog(SIPClientTransaction transaction, SIPResponse sipResponse) { 602 this(transaction); 603 if (sipResponse == null) 604 throw new NullPointerException("Null SipResponse"); 605 this.setLastResponse(transaction, sipResponse); 606 this.isBackToBackUserAgent = sipStack.isBackToBackUserAgent; 607 } 608 609 /** 610 * create a sip dialog with a response ( no tx) 611 */ 612 public SIPDialog(SipProviderImpl sipProvider, SIPResponse sipResponse) { 613 this(sipProvider); 614 this.sipStack = (SIPTransactionStack) sipProvider.getSipStack(); 615 this.setLastResponse(null, sipResponse); 616 this.localSequenceNumber = sipResponse.getCSeq().getSeqNumber(); 617 this.originalLocalSequenceNumber = localSequenceNumber; 618 this.myTag = sipResponse.getFrom().getTag(); 619 this.hisTag = sipResponse.getTo().getTag(); 620 this.localParty = sipResponse.getFrom().getAddress(); 621 this.remoteParty = sipResponse.getTo().getAddress(); 622 this.method = sipResponse.getCSeq().getMethod(); 623 this.callIdHeader = sipResponse.getCallId(); 624 this.serverTransactionFlag = false; 625 if (sipStack.isLoggingEnabled()) { 626 sipStack.getStackLogger().logDebug("Creating a dialog : " + this); 627 sipStack.getStackLogger().logStackTrace(); 628 } 629 this.isBackToBackUserAgent = sipStack.isBackToBackUserAgent; 630 addEventListener(sipStack); 631 } 632 633 // /////////////////////////////////////////////////////////// 634 // Private methods 635 // /////////////////////////////////////////////////////////// 636 /** 637 * A debugging print routine. 638 */ 639 private void printRouteList() { 640 if (sipStack.isLoggingEnabled()) { 641 sipStack.getStackLogger().logDebug("this : " + this); 642 sipStack.getStackLogger().logDebug("printRouteList : " + this.routeList.encode()); 643 } 644 } 645 646 /** 647 * Return true if this is a client dialog. 648 * 649 * @return true if the transaction that created this dialog is a client transaction and false 650 * otherwise. 651 */ 652 private boolean isClientDialog() { 653 SIPTransaction transaction = (SIPTransaction) this.getFirstTransaction(); 654 return transaction instanceof SIPClientTransaction; 655 } 656 657 /** 658 * Raise an io exception for asyncrhonous retransmission of responses 659 * 660 * @param host -- host to where the io was headed 661 * @param port -- remote port 662 * @param protocol -- protocol (udp/tcp/tls) 663 */ 664 private void raiseIOException(String host, int port, String protocol) { 665 // Error occured in retransmitting response. 666 // Deliver the error event to the listener 667 // Kill the dialog. 668 669 IOExceptionEvent ioError = new IOExceptionEvent(this, host, port, protocol); 670 sipProvider.handleEvent(ioError, null); 671 672 setState(SIPDialog.TERMINATED_STATE); 673 } 674 675 /** 676 * Raise a dialog timeout if an ACK has not been sent or received 677 * 678 * @param dialogTimeoutError 679 */ 680 private void raiseErrorEvent(int dialogTimeoutError) { 681 // Error event to send to all listeners 682 SIPDialogErrorEvent newErrorEvent; 683 // Iterator through the list of listeners 684 Iterator<SIPDialogEventListener> listenerIterator; 685 // Next listener in the list 686 SIPDialogEventListener nextListener; 687 688 // Create the error event 689 newErrorEvent = new SIPDialogErrorEvent(this, dialogTimeoutError); 690 691 // Loop through all listeners of this transaction 692 synchronized (eventListeners) { 693 listenerIterator = eventListeners.iterator(); 694 while (listenerIterator.hasNext()) { 695 // Send the event to the next listener 696 nextListener = (SIPDialogEventListener) listenerIterator.next(); 697 nextListener.dialogErrorEvent(newErrorEvent); 698 } 699 } 700 // Clear the event listeners after propagating the error. 701 eventListeners.clear(); 702 // 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 703 // the dialog, either by sending a BYE or by calling delete() on the dialog 704 if(dialogTimeoutError != SIPDialogErrorEvent.DIALOG_ACK_NOT_SENT_TIMEOUT && 705 dialogTimeoutError != SIPDialogErrorEvent.DIALOG_ACK_NOT_RECEIVED_TIMEOUT && 706 dialogTimeoutError != SIPDialogErrorEvent.DIALOG_REINVITE_TIMEOUT ) { 707 delete(); 708 } 709 // we stop the timer in any case 710 stopTimer(); 711 } 712 713 /** 714 * Set the remote party for this Dialog. 715 * 716 * @param sipMessage -- SIP Message to extract the relevant information from. 717 */ 718 private void setRemoteParty(SIPMessage sipMessage) { 719 720 if (!isServer()) { 721 722 this.remoteParty = sipMessage.getTo().getAddress(); 723 } else { 724 this.remoteParty = sipMessage.getFrom().getAddress(); 725 726 } 727 if (sipStack.isLoggingEnabled()) { 728 sipStack.getStackLogger().logDebug("settingRemoteParty " + this.remoteParty); 729 } 730 } 731 732 /** 733 * Add a route list extracted from a record route list. If this is a server dialog then we 734 * assume that the record are added to the route list IN order. If this is a client dialog 735 * then we assume that the record route headers give us the route list to add in reverse 736 * order. 737 * 738 * @param recordRouteList -- the record route list from the incoming message. 739 */ 740 741 private void addRoute(RecordRouteList recordRouteList) { 742 try { 743 if (this.isClientDialog()) { 744 // This is a client dialog so we extract the record 745 // route from the response and reverse its order to 746 // careate a route list. 747 this.routeList = new RouteList(); 748 // start at the end of the list and walk backwards 749 750 ListIterator li = recordRouteList.listIterator(recordRouteList.size()); 751 boolean addRoute = true; 752 while (li.hasPrevious()) { 753 RecordRoute rr = (RecordRoute) li.previous(); 754 755 if (addRoute) { 756 Route route = new Route(); 757 AddressImpl address = ((AddressImpl) ((AddressImpl) rr.getAddress()) 758 .clone()); 759 760 route.setAddress(address); 761 route.setParameters((NameValueList) rr.getParameters().clone()); 762 763 this.routeList.add(route); 764 } 765 } 766 } else { 767 // This is a server dialog. The top most record route 768 // header is the one that is closest to us. We extract the 769 // route list in the same order as the addresses in the 770 // incoming request. 771 this.routeList = new RouteList(); 772 ListIterator li = recordRouteList.listIterator(); 773 boolean addRoute = true; 774 while (li.hasNext()) { 775 RecordRoute rr = (RecordRoute) li.next(); 776 777 if (addRoute) { 778 Route route = new Route(); 779 AddressImpl address = ((AddressImpl) ((AddressImpl) rr.getAddress()) 780 .clone()); 781 route.setAddress(address); 782 route.setParameters((NameValueList) rr.getParameters().clone()); 783 routeList.add(route); 784 } 785 } 786 } 787 } finally { 788 if (sipStack.getStackLogger().isLoggingEnabled()) { 789 Iterator it = routeList.iterator(); 790 791 while (it.hasNext()) { 792 SipURI sipUri = (SipURI) (((Route) it.next()).getAddress().getURI()); 793 if (!sipUri.hasLrParam()) { 794 if (sipStack.isLoggingEnabled()) { 795 sipStack.getStackLogger().logWarning( 796 "NON LR route in Route set detected for dialog : " + this); 797 sipStack.getStackLogger().logStackTrace(); 798 } 799 } 800 } 801 } 802 } 803 } 804 805 /** 806 * Add a route list extacted from the contact list of the incoming message. 807 * 808 * @param contactList -- contact list extracted from the incoming message. 809 * 810 */ 811 812 void setRemoteTarget(ContactHeader contact) { 813 this.remoteTarget = contact.getAddress(); 814 if (sipStack.isLoggingEnabled()) { 815 sipStack.getStackLogger().logDebug("Dialog.setRemoteTarget: " + this.remoteTarget); 816 sipStack.getStackLogger().logStackTrace(); 817 } 818 819 } 820 821 /** 822 * Extract the route information from this SIP Message and add the relevant information to the 823 * route set. 824 * 825 * @param sipMessage is the SIP message for which we want to add the route. 826 */ 827 private synchronized void addRoute(SIPResponse sipResponse) { 828 829 try { 830 if (sipStack.isLoggingEnabled()) { 831 sipStack.getStackLogger().logDebug( 832 "setContact: dialogState: " + this + "state = " + this.getState()); 833 } 834 if (sipResponse.getStatusCode() == 100) { 835 // Do nothing for trying messages. 836 return; 837 } else if (this.dialogState == TERMINATED_STATE) { 838 // Do nothing if the dialog state is terminated. 839 return; 840 } else if (this.dialogState == CONFIRMED_STATE) { 841 // cannot add route list after the dialog is initialized. 842 // Remote target is updated on RE-INVITE but not 843 // the route list. 844 if (sipResponse.getStatusCode() / 100 == 2 && !this.isServer()) { 845 ContactList contactList = sipResponse.getContactHeaders(); 846 if (contactList != null 847 && SIPRequest.isTargetRefresh(sipResponse.getCSeq().getMethod())) { 848 this.setRemoteTarget((ContactHeader) contactList.getFirst()); 849 } 850 } 851 return; 852 } 853 854 // Update route list on response if I am a client dialog. 855 if (!isServer()) { 856 857 // only update the route set if the dialog is not in the confirmed state. 858 if (this.getState() != DialogState.CONFIRMED 859 && this.getState() != DialogState.TERMINATED) { 860 RecordRouteList rrlist = sipResponse.getRecordRouteHeaders(); 861 // Add the route set from the incoming response in reverse 862 // order for record route headers. 863 if (rrlist != null) { 864 this.addRoute(rrlist); 865 } else { 866 // Set the rotue list to the last seen route list. 867 this.routeList = new RouteList(); 868 } 869 } 870 871 ContactList contactList = sipResponse.getContactHeaders(); 872 if (contactList != null) { 873 this.setRemoteTarget((ContactHeader) contactList.getFirst()); 874 } 875 } 876 877 } finally { 878 if (sipStack.isLoggingEnabled()) { 879 sipStack.getStackLogger().logStackTrace(); 880 } 881 } 882 } 883 884 /** 885 * Get a cloned copy of route list for the Dialog. 886 * 887 * @return -- a cloned copy of the dialog route list. 888 */ 889 private synchronized RouteList getRouteList() { 890 if (sipStack.isLoggingEnabled()) 891 sipStack.getStackLogger().logDebug("getRouteList " + this); 892 // Find the top via in the route list. 893 ListIterator li; 894 RouteList retval = new RouteList(); 895 896 retval = new RouteList(); 897 if (this.routeList != null) { 898 li = routeList.listIterator(); 899 while (li.hasNext()) { 900 Route route = (Route) li.next(); 901 retval.add((Route) route.clone()); 902 } 903 } 904 905 if (sipStack.isLoggingEnabled()) { 906 sipStack.getStackLogger().logDebug("----- "); 907 sipStack.getStackLogger().logDebug("getRouteList for " + this); 908 if (retval != null) 909 sipStack.getStackLogger().logDebug("RouteList = " + retval.encode()); 910 if (routeList != null) 911 sipStack.getStackLogger().logDebug("myRouteList = " + routeList.encode()); 912 sipStack.getStackLogger().logDebug("----- "); 913 } 914 return retval; 915 } 916 917 void setRouteList(RouteList routeList) { 918 this.routeList = routeList; 919 } 920 921 /** 922 * Sends ACK Request to the remote party of this Dialogue. 923 * 924 * 925 * @param request the new ACK Request message to send. 926 * @param throwIOExceptionAsSipException - throws SipException if IOEx encountered. Otherwise, 927 * no exception is propagated. 928 * @param releaseAckSem - release ack semaphore. 929 * @throws SipException if implementation cannot send the ACK Request for any other reason 930 * 931 */ 932 private void sendAck(Request request, boolean throwIOExceptionAsSipException) 933 throws SipException { 934 SIPRequest ackRequest = (SIPRequest) request; 935 if (sipStack.isLoggingEnabled()) 936 sipStack.getStackLogger().logDebug("sendAck" + this); 937 938 if (!ackRequest.getMethod().equals(Request.ACK)) 939 throw new SipException("Bad request method -- should be ACK"); 940 if (this.getState() == null || this.getState().getValue() == EARLY_STATE) { 941 if (sipStack.isLoggingEnabled()) { 942 sipStack.getStackLogger().logError( 943 "Bad Dialog State for " + this + " dialogID = " + this.getDialogId()); 944 } 945 throw new SipException("Bad dialog state " + this.getState()); 946 } 947 948 if (!this.getCallId().getCallId().equals(((SIPRequest) request).getCallId().getCallId())) { 949 if (sipStack.isLoggingEnabled()) { 950 sipStack.getStackLogger().logError("CallID " + this.getCallId()); 951 sipStack.getStackLogger().logError( 952 "RequestCallID = " + ackRequest.getCallId().getCallId()); 953 sipStack.getStackLogger().logError("dialog = " + this); 954 } 955 throw new SipException("Bad call ID in request"); 956 } 957 try { 958 if (sipStack.isLoggingEnabled()) { 959 sipStack.getStackLogger().logDebug( 960 "setting from tag For outgoing ACK= " + this.getLocalTag()); 961 sipStack.getStackLogger().logDebug( 962 "setting To tag for outgoing ACK = " + this.getRemoteTag()); 963 sipStack.getStackLogger().logDebug("ack = " + ackRequest); 964 } 965 if (this.getLocalTag() != null) 966 ackRequest.getFrom().setTag(this.getLocalTag()); 967 if (this.getRemoteTag() != null) 968 ackRequest.getTo().setTag(this.getRemoteTag()); 969 } catch (ParseException ex) { 970 throw new SipException(ex.getMessage()); 971 } 972 973 Hop hop = sipStack.getNextHop(ackRequest); 974 // Hop hop = defaultRouter.getNextHop(ackRequest); 975 if (hop == null) 976 throw new SipException("No route!"); 977 try { 978 if (sipStack.isLoggingEnabled()) 979 sipStack.getStackLogger().logDebug("hop = " + hop); 980 ListeningPointImpl lp = (ListeningPointImpl) this.sipProvider.getListeningPoint(hop 981 .getTransport()); 982 if (lp == null) 983 throw new SipException("No listening point for this provider registered at " 984 + hop); 985 InetAddress inetAddress = InetAddress.getByName(hop.getHost()); 986 MessageChannel messageChannel = lp.getMessageProcessor().createMessageChannel( 987 inetAddress, hop.getPort()); 988 boolean releaseAckSem = false; 989 long cseqNo = ((SIPRequest)request).getCSeq().getSeqNumber(); 990 if (!this.isAckSent(cseqNo)) { 991 releaseAckSem = true; 992 } 993 994 this.setLastAckSent(ackRequest); 995 messageChannel.sendMessage(ackRequest); 996 // Sent atleast one ACK. 997 this.isAcknowledged = true; 998 this.highestSequenceNumberAcknowledged = Math.max(this.highestSequenceNumberAcknowledged, 999 ((SIPRequest)ackRequest).getCSeq().getSeqNumber()); 1000 if (releaseAckSem && this.isBackToBackUserAgent) { 1001 this.releaseAckSem(); 1002 } else { 1003 if ( sipStack.isLoggingEnabled() ) { 1004 sipStack.getStackLogger().logDebug("Not releasing ack sem for " + this + " isAckSent " + releaseAckSem ); 1005 } 1006 } 1007 } catch (IOException ex) { 1008 if (throwIOExceptionAsSipException) 1009 throw new SipException("Could not send ack", ex); 1010 this.raiseIOException(hop.getHost(), hop.getPort(), hop.getTransport()); 1011 } catch (SipException ex) { 1012 if (sipStack.isLoggingEnabled()) 1013 sipStack.getStackLogger().logException(ex); 1014 throw ex; 1015 } catch (Exception ex) { 1016 if (sipStack.isLoggingEnabled()) 1017 sipStack.getStackLogger().logException(ex); 1018 throw new SipException("Could not create message channel", ex); 1019 } 1020 if (this.dialogDeleteTask != null) { 1021 this.dialogDeleteTask.cancel(); 1022 this.dialogDeleteTask = null; 1023 } 1024 this.ackSeen = true; 1025 1026 } 1027 1028 // ///////////////////////////////////////////////////////////// 1029 // Package local methods 1030 // ///////////////////////////////////////////////////////////// 1031 1032 /** 1033 * Set the stack address. Prevent us from routing messages to ourselves. 1034 * 1035 * @param sipStack the address of the SIP stack. 1036 * 1037 */ 1038 void setStack(SIPTransactionStack sipStack) { 1039 this.sipStack = sipStack; 1040 1041 } 1042 1043 /** 1044 * Get the stack . 1045 * 1046 * @return sipStack the SIP stack of the dialog. 1047 * 1048 */ 1049 SIPTransactionStack getStack() { 1050 return sipStack; 1051 } 1052 1053 /** 1054 * Return True if this dialog is terminated on BYE. 1055 * 1056 */ 1057 boolean isTerminatedOnBye() { 1058 1059 return this.terminateOnBye; 1060 } 1061 1062 /** 1063 * Mark that the dialog has seen an ACK. 1064 */ 1065 void ackReceived(SIPRequest sipRequest) { 1066 1067 // Suppress retransmission of the final response 1068 if (this.ackSeen) 1069 return; 1070 SIPServerTransaction tr = this.getInviteTransaction(); 1071 if (tr != null) { 1072 if (tr.getCSeq() == sipRequest.getCSeq().getSeqNumber()) { 1073 acquireTimerTaskSem(); 1074 try { 1075 if (this.timerTask != null) { 1076 this.timerTask.cancel(); 1077 this.timerTask = null; 1078 } 1079 } finally { 1080 releaseTimerTaskSem(); 1081 } 1082 this.ackSeen = true; 1083 if (this.dialogDeleteTask != null) { 1084 this.dialogDeleteTask.cancel(); 1085 this.dialogDeleteTask = null; 1086 } 1087 this.setLastAckReceived(sipRequest); 1088 if (sipStack.isLoggingEnabled()) { 1089 sipStack.getStackLogger().logDebug( 1090 "ackReceived for " + ((SIPTransaction) tr).getMethod()); 1091 this.ackLine = sipStack.getStackLogger().getLineCount(); 1092 this.printDebugInfo(); 1093 } 1094 if (this.isBackToBackUserAgent) { 1095 this.releaseAckSem(); 1096 } 1097 this.setState(CONFIRMED_STATE); 1098 } 1099 } 1100 } 1101 1102 /** 1103 * Return true if a terminated event was delivered to the application as a result of the 1104 * dialog termination. 1105 * 1106 */ 1107 synchronized boolean testAndSetIsDialogTerminatedEventDelivered() { 1108 boolean retval = this.dialogTerminatedEventDelivered; 1109 this.dialogTerminatedEventDelivered = true; 1110 return retval; 1111 } 1112 1113 // ///////////////////////////////////////////////////////// 1114 // Public methods 1115 // ///////////////////////////////////////////////////////// 1116 1117 /** 1118 * Adds a new event listener to this dialog. 1119 * 1120 * @param newListener 1121 * Listener to add. 1122 */ 1123 public void addEventListener(SIPDialogEventListener newListener) { 1124 eventListeners.add(newListener); 1125 } 1126 1127 /** 1128 * Removed an event listener from this dialog. 1129 * 1130 * @param oldListener 1131 * Listener to remove. 1132 */ 1133 public void removeEventListener(SIPDialogEventListener oldListener) { 1134 eventListeners.remove(oldListener); 1135 } 1136 1137 /* 1138 * @see javax.sip.Dialog#setApplicationData() 1139 */ 1140 public void setApplicationData(Object applicationData) { 1141 this.applicationData = applicationData; 1142 } 1143 1144 /* 1145 * (non-Javadoc) 1146 * 1147 * @see javax.sip.Dialog#getApplicationData() 1148 */ 1149 public Object getApplicationData() { 1150 return this.applicationData; 1151 } 1152 1153 /** 1154 * Updates the next consumable seqno. 1155 * 1156 */ 1157 public synchronized void requestConsumed() { 1158 this.nextSeqno = Long.valueOf(this.getRemoteSeqNumber() + 1); 1159 1160 if (sipStack.isLoggingEnabled()) { 1161 this.sipStack.getStackLogger().logDebug( 1162 "Request Consumed -- next consumable Request Seqno = " + this.nextSeqno); 1163 } 1164 1165 } 1166 1167 /** 1168 * Return true if this request can be consumed by the dialog. 1169 * 1170 * @param dialogRequest is the request to check with the dialog. 1171 * @return true if the dialogRequest sequence number matches the next consumable seqno. 1172 */ 1173 public synchronized boolean isRequestConsumable(SIPRequest dialogRequest) { 1174 // have not yet set remote seqno - this is a fresh 1175 if (dialogRequest.getMethod().equals(Request.ACK)) 1176 throw new RuntimeException("Illegal method"); 1177 1178 // For loose validation this function is delegated to the application 1179 if (!this.isSequnceNumberValidation()) { 1180 return true; 1181 } 1182 1183 // JvB: Acceptable iff remoteCSeq < cseq. remoteCSeq==-1 1184 // when not defined yet, so that works too 1185 return remoteSequenceNumber < dialogRequest.getCSeq().getSeqNumber(); 1186 } 1187 1188 /** 1189 * This method is called when a forked dialog is created from the client side. It starts a 1190 * timer task. If the timer task expires before an ACK is sent then the dialog is cancelled 1191 * (i.e. garbage collected ). 1192 * 1193 */ 1194 public void doDeferredDelete() { 1195 if (sipStack.getTimer() == null) 1196 this.setState(TERMINATED_STATE); 1197 else { 1198 this.dialogDeleteTask = new DialogDeleteTask(); 1199 // Delete the transaction after the max ack timeout. 1200 sipStack.getTimer().schedule(this.dialogDeleteTask, 1201 SIPTransaction.TIMER_H * SIPTransactionStack.BASE_TIMER_INTERVAL); 1202 } 1203 1204 } 1205 1206 /** 1207 * Set the state for this dialog. 1208 * 1209 * @param state is the state to set for the dialog. 1210 */ 1211 1212 public void setState(int state) { 1213 if (sipStack.isLoggingEnabled()) { 1214 sipStack.getStackLogger().logDebug( 1215 "Setting dialog state for " + this + "newState = " + state); 1216 sipStack.getStackLogger().logStackTrace(); 1217 if (state != NULL_STATE && state != this.dialogState) 1218 if (sipStack.isLoggingEnabled()) { 1219 sipStack.getStackLogger().logDebug( 1220 this + " old dialog state is " + this.getState()); 1221 sipStack.getStackLogger().logDebug( 1222 this + " New dialog state is " + DialogState.getObject(state)); 1223 } 1224 1225 } 1226 this.dialogState = state; 1227 // Dialog is in terminated state set it up for GC. 1228 if (state == TERMINATED_STATE) { 1229 if (sipStack.getTimer() != null) { // may be null after shutdown 1230 sipStack.getTimer().schedule(new LingerTimer(), DIALOG_LINGER_TIME * 1000); 1231 } 1232 this.stopTimer(); 1233 1234 } 1235 } 1236 1237 /** 1238 * Debugging print for the dialog. 1239 */ 1240 public void printDebugInfo() { 1241 if (sipStack.isLoggingEnabled()) { 1242 sipStack.getStackLogger().logDebug("isServer = " + isServer()); 1243 sipStack.getStackLogger().logDebug("localTag = " + getLocalTag()); 1244 sipStack.getStackLogger().logDebug("remoteTag = " + getRemoteTag()); 1245 sipStack.getStackLogger().logDebug("localSequenceNumer = " + getLocalSeqNumber()); 1246 sipStack.getStackLogger().logDebug("remoteSequenceNumer = " + getRemoteSeqNumber()); 1247 sipStack.getStackLogger().logDebug("ackLine:" + this.getRemoteTag() + " " + ackLine); 1248 } 1249 } 1250 1251 /** 1252 * Return true if the dialog has already seen the ack. 1253 * 1254 * @return flag that records if the ack has been seen. 1255 */ 1256 public boolean isAckSeen() { 1257 return this.ackSeen; 1258 } 1259 1260 /** 1261 * Get the last ACK for this transaction. 1262 */ 1263 public SIPRequest getLastAckSent() { 1264 return this.lastAckSent; 1265 } 1266 1267 /** 1268 * Return true if ACK was sent ( for client tx ). For server tx, this is a NO-OP ( we dont 1269 * send ACK). 1270 */ 1271 public boolean isAckSent(long cseqNo) { 1272 if (this.getLastTransaction() == null) 1273 return true; 1274 if (this.getLastTransaction() instanceof ClientTransaction) { 1275 if (this.getLastAckSent() == null) { 1276 return false; 1277 } else { 1278 return cseqNo <=((SIPRequest) this.getLastAckSent()).getCSeq().getSeqNumber(); 1279 } 1280 } else { 1281 return true; 1282 } 1283 } 1284 1285 /** 1286 * Get the transaction that created this dialog. 1287 */ 1288 public Transaction getFirstTransaction() { 1289 return this.firstTransaction; 1290 } 1291 1292 1293 /** 1294 * Gets the route set for the dialog. When acting as an User Agent Server the route set MUST 1295 * be set to the list of URIs in the Record-Route header field from the request, taken in 1296 * order and preserving all URI parameters. When acting as an User Agent Client the route set 1297 * MUST be set to the list of URIs in the Record-Route header field from the response, taken 1298 * in reverse order and preserving all URI parameters. If no Record-Route header field is 1299 * present in the request or response, the route set MUST be set to the empty set. This route 1300 * set, even if empty, overrides any pre-existing route set for future requests in this 1301 * dialog. 1302 * <p> 1303 * Requests within a dialog MAY contain Record-Route and Contact header fields. However, these 1304 * requests do not cause the dialog's route set to be modified. 1305 * <p> 1306 * The User Agent Client uses the remote target and route set to build the Request-URI and 1307 * Route header field of the request. 1308 * 1309 * @return an Iterator containing a list of route headers to be used for forwarding. Empty 1310 * iterator is returned if route has not been established. 1311 */ 1312 public Iterator getRouteSet() { 1313 if (this.routeList == null) { 1314 return new LinkedList().listIterator(); 1315 } else { 1316 return this.getRouteList().listIterator(); 1317 } 1318 } 1319 1320 /** 1321 * Add a Route list extracted from a SIPRequest to this Dialog. 1322 * 1323 * @param sipRequest 1324 */ 1325 public synchronized void addRoute(SIPRequest sipRequest) { 1326 if (sipStack.isLoggingEnabled()) { 1327 sipStack.getStackLogger().logDebug( 1328 "setContact: dialogState: " + this + "state = " + this.getState()); 1329 } 1330 1331 if (this.dialogState == CONFIRMED_STATE 1332 && SIPRequest.isTargetRefresh(sipRequest.getMethod())) { 1333 this.doTargetRefresh(sipRequest); 1334 } 1335 if (this.dialogState == CONFIRMED_STATE || this.dialogState == TERMINATED_STATE) { 1336 return; 1337 } 1338 1339 // Fix for issue #225: mustn't learn Route set from mid-dialog requests 1340 if ( sipRequest.getToTag()!=null ) return; 1341 1342 // Incoming Request has the route list 1343 RecordRouteList rrlist = sipRequest.getRecordRouteHeaders(); 1344 // Add the route set from the incoming response in reverse 1345 // order 1346 if (rrlist != null) { 1347 this.addRoute(rrlist); 1348 } else { 1349 // Set the rotue list to the last seen route list. 1350 this.routeList = new RouteList(); 1351 } 1352 1353 // put the contact header from the incoming request into 1354 // the route set. JvB: some duplication here, ref. doTargetRefresh 1355 ContactList contactList = sipRequest.getContactHeaders(); 1356 if (contactList != null) { 1357 this.setRemoteTarget((ContactHeader) contactList.getFirst()); 1358 } 1359 } 1360 1361 /** 1362 * Set the dialog identifier. 1363 */ 1364 public void setDialogId(String dialogId) { 1365 this.dialogId = dialogId; 1366 } 1367 1368 /** 1369 * Creates a new dialog based on a received NOTIFY. The dialog state is initialized 1370 * appropriately. The NOTIFY differs in the From tag 1371 * 1372 * Made this a separate method to clearly distinguish what's happening here - this is a 1373 * non-trivial case 1374 * 1375 * @param subscribeTx - the transaction started with the SUBSCRIBE that we sent 1376 * @param notifyST - the ServerTransaction created for an incoming NOTIFY 1377 * @return -- a new dialog created from the subscribe original SUBSCRIBE transaction. 1378 * 1379 * 1380 */ 1381 public static SIPDialog createFromNOTIFY(SIPClientTransaction subscribeTx, 1382 SIPTransaction notifyST) { 1383 SIPDialog d = new SIPDialog(notifyST); 1384 // 1385 // The above sets d.firstTransaction to NOTIFY (ST), correct that 1386 // 1387 d.serverTransactionFlag = false; 1388 // they share this one 1389 d.lastTransaction = subscribeTx; 1390 storeFirstTransactionInfo(d, subscribeTx); 1391 d.terminateOnBye = false; 1392 d.localSequenceNumber = subscribeTx.getCSeq(); 1393 SIPRequest not = (SIPRequest) notifyST.getRequest(); 1394 d.remoteSequenceNumber = not.getCSeq().getSeqNumber(); 1395 d.setDialogId(not.getDialogId(true)); 1396 d.setLocalTag(not.getToTag()); 1397 d.setRemoteTag(not.getFromTag()); 1398 // to properly create the Dialog object. 1399 // If not the stack will throw an exception when creating the response. 1400 d.setLastResponse(subscribeTx, subscribeTx.getLastResponse()); 1401 1402 // Dont use setLocal / setRemote here, they make other assumptions 1403 d.localParty = not.getTo().getAddress(); 1404 d.remoteParty = not.getFrom().getAddress(); 1405 1406 // initialize d's route set based on the NOTIFY. Any proxies must have 1407 // Record-Routed 1408 d.addRoute(not); 1409 d.setState(CONFIRMED_STATE); // set state, *after* setting route set! 1410 return d; 1411 } 1412 1413 /** 1414 * Return true if is server. 1415 * 1416 * @return true if is server transaction created this dialog. 1417 */ 1418 public boolean isServer() { 1419 if (this.firstTransactionSeen == false) 1420 return this.serverTransactionFlag; 1421 else 1422 return this.firstTransactionIsServerTransaction; 1423 1424 } 1425 1426 /** 1427 * Return true if this is a re-establishment of the dialog. 1428 * 1429 * @return true if the reInvite flag is set. 1430 */ 1431 protected boolean isReInvite() { 1432 return this.reInviteFlag; 1433 } 1434 1435 /** 1436 * Get the id for this dialog. 1437 * 1438 * @return the string identifier for this dialog. 1439 * 1440 */ 1441 public String getDialogId() { 1442 1443 if (this.dialogId == null && this.lastResponse != null) 1444 this.dialogId = this.lastResponse.getDialogId(isServer()); 1445 1446 return this.dialogId; 1447 } 1448 1449 private static void storeFirstTransactionInfo(SIPDialog dialog, SIPTransaction transaction) { 1450 dialog.firstTransaction = transaction; 1451 dialog.firstTransactionSeen = true; 1452 dialog.firstTransactionIsServerTransaction = transaction.isServerTransaction(); 1453 dialog.firstTransactionSecure = transaction.getRequest().getRequestURI().getScheme() 1454 .equalsIgnoreCase("sips"); 1455 dialog.firstTransactionPort = transaction.getPort(); 1456 dialog.firstTransactionId = transaction.getBranchId(); 1457 dialog.firstTransactionMethod = transaction.getMethod(); 1458 1459 if (dialog.isServer()) { 1460 SIPServerTransaction st = (SIPServerTransaction) transaction; 1461 SIPResponse response = st.getLastResponse(); 1462 dialog.contactHeader = response != null ? response.getContactHeader() : null; 1463 } else { 1464 SIPClientTransaction ct = (SIPClientTransaction) transaction; 1465 if (ct != null){ 1466 SIPRequest sipRequest = ct.getOriginalRequest(); 1467 dialog.contactHeader = sipRequest.getContactHeader(); 1468 } 1469 } 1470 } 1471 /** 1472 * Add a transaction record to the dialog. 1473 * 1474 * @param transaction is the transaction to add to the dialog. 1475 */ 1476 public void addTransaction(SIPTransaction transaction) { 1477 1478 SIPRequest sipRequest = (SIPRequest) transaction.getOriginalRequest(); 1479 1480 // Proessing a re-invite. 1481 if (firstTransactionSeen && !firstTransactionId.equals(transaction.getBranchId()) 1482 && transaction.getMethod().equals(firstTransactionMethod)) { 1483 this.reInviteFlag = true; 1484 } 1485 1486 if (firstTransactionSeen == false) { 1487 // Record the local and remote sequenc 1488 // numbers and the from and to tags for future 1489 // use on this dialog. 1490 storeFirstTransactionInfo(this, transaction); 1491 if (sipRequest.getMethod().equals(Request.SUBSCRIBE)) 1492 this.eventHeader = (EventHeader) sipRequest.getHeader(EventHeader.NAME); 1493 1494 this.setLocalParty(sipRequest); 1495 this.setRemoteParty(sipRequest); 1496 this.setCallId(sipRequest); 1497 if (this.originalRequest == null) { 1498 this.originalRequest = sipRequest; 1499 } 1500 if (this.method == null) { 1501 this.method = sipRequest.getMethod(); 1502 } 1503 1504 if (transaction instanceof SIPServerTransaction) { 1505 this.hisTag = sipRequest.getFrom().getTag(); 1506 // My tag is assigned when sending response 1507 } else { 1508 setLocalSequenceNumber(sipRequest.getCSeq().getSeqNumber()); 1509 this.originalLocalSequenceNumber = localSequenceNumber; 1510 this.myTag = sipRequest.getFrom().getTag(); 1511 if (myTag == null) 1512 if (sipStack.isLoggingEnabled()) 1513 sipStack.getStackLogger().logError( 1514 "The request's From header is missing the required Tag parameter."); 1515 } 1516 } else if (transaction.getMethod().equals(firstTransactionMethod) 1517 && firstTransactionIsServerTransaction != transaction.isServerTransaction()) { 1518 // This case occurs when you are processing a re-invite. 1519 // Switch from client side to server side for re-invite 1520 // (put the other side on hold). 1521 1522 storeFirstTransactionInfo(this, transaction); 1523 1524 this.setLocalParty(sipRequest); 1525 this.setRemoteParty(sipRequest); 1526 this.setCallId(sipRequest); 1527 this.originalRequest = sipRequest; 1528 this.method = sipRequest.getMethod(); 1529 1530 } 1531 if (transaction instanceof SIPServerTransaction) 1532 setRemoteSequenceNumber(sipRequest.getCSeq().getSeqNumber()); 1533 1534 // If this is a server transaction record the remote 1535 // sequence number to avoid re-processing of requests 1536 // with the same sequence number directed towards this 1537 // dialog. 1538 1539 this.lastTransaction = transaction; 1540 // set a back ptr in the incoming dialog. 1541 // CHECKME -- why is this here? 1542 // transaction.setDialog(this,sipRequest); 1543 if (sipStack.isLoggingEnabled()) { 1544 sipStack.getStackLogger() 1545 .logDebug("Transaction Added " + this + myTag + "/" + hisTag); 1546 sipStack.getStackLogger().logDebug( 1547 "TID = " + transaction.getTransactionId() + "/" 1548 + transaction.isServerTransaction()); 1549 sipStack.getStackLogger().logStackTrace(); 1550 } 1551 } 1552 1553 /** 1554 * Set the remote tag. 1555 * 1556 * @param hisTag is the remote tag to set. 1557 */ 1558 private void setRemoteTag(String hisTag) { 1559 if (sipStack.isLoggingEnabled()) { 1560 sipStack.getStackLogger().logDebug( 1561 "setRemoteTag(): " + this + " remoteTag = " + this.hisTag + " new tag = " 1562 + hisTag); 1563 } 1564 if (this.hisTag != null && hisTag != null && !hisTag.equals(this.hisTag)) { 1565 if (this.getState() != DialogState.EARLY) { 1566 if (sipStack.isLoggingEnabled()) 1567 sipStack.getStackLogger().logDebug( 1568 "Dialog is already established -- ignoring remote tag re-assignment"); 1569 return; 1570 } else if (sipStack.isRemoteTagReassignmentAllowed()) { 1571 if (sipStack.isLoggingEnabled()) 1572 sipStack.getStackLogger().logDebug( 1573 "UNSAFE OPERATION ! tag re-assignment " + this.hisTag 1574 + " trying to set to " + hisTag 1575 + " can cause unexpected effects "); 1576 boolean removed = false; 1577 if (this.sipStack.getDialog(dialogId) == this) { 1578 this.sipStack.removeDialog(dialogId); 1579 removed = true; 1580 1581 } 1582 // Force recomputation of Dialog ID; 1583 this.dialogId = null; 1584 this.hisTag = hisTag; 1585 if (removed) { 1586 if (sipStack.isLoggingEnabled()) 1587 sipStack.getStackLogger().logDebug("ReInserting Dialog"); 1588 this.sipStack.putDialog(this); 1589 } 1590 } 1591 } else { 1592 if (hisTag != null) { 1593 this.hisTag = hisTag; 1594 } else { 1595 if (sipStack.isLoggingEnabled()) 1596 sipStack.getStackLogger().logWarning("setRemoteTag : called with null argument "); 1597 } 1598 } 1599 } 1600 1601 /** 1602 * Get the last transaction from the dialog. 1603 */ 1604 public SIPTransaction getLastTransaction() { 1605 return this.lastTransaction; 1606 } 1607 1608 /** 1609 * Get the INVITE transaction (null if no invite transaction). 1610 */ 1611 public SIPServerTransaction getInviteTransaction() { 1612 DialogTimerTask t = this.timerTask; 1613 if (t != null) 1614 return t.transaction; 1615 else 1616 return null; 1617 } 1618 1619 /** 1620 * Set the local sequece number for the dialog (defaults to 1 when the dialog is created). 1621 * 1622 * @param lCseq is the local cseq number. 1623 * 1624 */ 1625 private void setLocalSequenceNumber(long lCseq) { 1626 if (sipStack.isLoggingEnabled()) 1627 sipStack.getStackLogger().logDebug( 1628 "setLocalSequenceNumber: original " + this.localSequenceNumber + " new = " 1629 + lCseq); 1630 if (lCseq <= this.localSequenceNumber) 1631 throw new RuntimeException("Sequence number should not decrease !"); 1632 this.localSequenceNumber = lCseq; 1633 } 1634 1635 /** 1636 * Set the remote sequence number for the dialog. 1637 * 1638 * @param rCseq is the remote cseq number. 1639 * 1640 */ 1641 public void setRemoteSequenceNumber(long rCseq) { 1642 if (sipStack.isLoggingEnabled()) 1643 sipStack.getStackLogger().logDebug("setRemoteSeqno " + this + "/" + rCseq); 1644 this.remoteSequenceNumber = rCseq; 1645 } 1646 1647 /** 1648 * Increment the local CSeq # for the dialog. This is useful for if you want to create a hole 1649 * in the sequence number i.e. route a request outside the dialog and then resume within the 1650 * dialog. 1651 */ 1652 public void incrementLocalSequenceNumber() { 1653 ++this.localSequenceNumber; 1654 } 1655 1656 /** 1657 * Get the remote sequence number (for cseq assignment of outgoing requests within this 1658 * dialog). 1659 * 1660 * @deprecated 1661 * @return local sequence number. 1662 */ 1663 1664 public int getRemoteSequenceNumber() { 1665 return (int) this.remoteSequenceNumber; 1666 } 1667 1668 /** 1669 * Get the local sequence number (for cseq assignment of outgoing requests within this 1670 * dialog). 1671 * 1672 * @deprecated 1673 * @return local sequence number. 1674 */ 1675 1676 public int getLocalSequenceNumber() { 1677 return (int) this.localSequenceNumber; 1678 } 1679 1680 /** 1681 * Get the sequence number for the request that origianlly created the Dialog. 1682 * 1683 * @return -- the original starting sequence number for this dialog. 1684 */ 1685 public long getOriginalLocalSequenceNumber() { 1686 return this.originalLocalSequenceNumber; 1687 } 1688 1689 /* 1690 * (non-Javadoc) 1691 * 1692 * @see javax.sip.Dialog#getLocalSequenceNumberLong() 1693 */ 1694 public long getLocalSeqNumber() { 1695 return this.localSequenceNumber; 1696 } 1697 1698 /* 1699 * (non-Javadoc) 1700 * 1701 * @see javax.sip.Dialog#getRemoteSequenceNumberLong() 1702 */ 1703 public long getRemoteSeqNumber() { 1704 return this.remoteSequenceNumber; 1705 } 1706 1707 /* 1708 * (non-Javadoc) 1709 * 1710 * @see javax.sip.Dialog#getLocalTag() 1711 */ 1712 public String getLocalTag() { 1713 return this.myTag; 1714 } 1715 1716 /* 1717 * (non-Javadoc) 1718 * 1719 * @see javax.sip.Dialog#getRemoteTag() 1720 */ 1721 public String getRemoteTag() { 1722 1723 return hisTag; 1724 } 1725 1726 /** 1727 * Set local tag for the transaction. 1728 * 1729 * @param mytag is the tag to use in From headers client transactions that belong to this 1730 * dialog and for generating To tags for Server transaction requests that belong to 1731 * this dialog. 1732 */ 1733 private void setLocalTag(String mytag) { 1734 if (sipStack.isLoggingEnabled()) { 1735 sipStack.getStackLogger().logDebug("set Local tag " + mytag + " " + this.dialogId); 1736 sipStack.getStackLogger().logStackTrace(); 1737 } 1738 1739 this.myTag = mytag; 1740 1741 } 1742 1743 /* 1744 * (non-Javadoc) 1745 * 1746 * @see javax.sip.Dialog#delete() 1747 */ 1748 1749 public void delete() { 1750 // the reaper will get him later. 1751 this.setState(TERMINATED_STATE); 1752 } 1753 1754 /* 1755 * (non-Javadoc) 1756 * 1757 * @see javax.sip.Dialog#getCallId() 1758 */ 1759 public CallIdHeader getCallId() { 1760 return this.callIdHeader; 1761 } 1762 1763 /** 1764 * set the call id header for this dialog. 1765 */ 1766 private void setCallId(SIPRequest sipRequest) { 1767 this.callIdHeader = sipRequest.getCallId(); 1768 } 1769 1770 /* 1771 * (non-Javadoc) 1772 * 1773 * @see javax.sip.Dialog#getLocalParty() 1774 */ 1775 1776 public javax.sip.address.Address getLocalParty() { 1777 return this.localParty; 1778 } 1779 1780 private void setLocalParty(SIPMessage sipMessage) { 1781 if (!isServer()) { 1782 this.localParty = sipMessage.getFrom().getAddress(); 1783 } else { 1784 this.localParty = sipMessage.getTo().getAddress(); 1785 } 1786 } 1787 1788 /** 1789 * Returns the Address identifying the remote party. This is the value of the To header of 1790 * locally initiated requests in this dialogue when acting as an User Agent Client. 1791 * <p> 1792 * This is the value of the From header of recieved responses in this dialogue when acting as 1793 * an User Agent Server. 1794 * 1795 * @return the address object of the remote party. 1796 */ 1797 public javax.sip.address.Address getRemoteParty() { 1798 1799 if (sipStack.isLoggingEnabled()) { 1800 sipStack.getStackLogger().logDebug("gettingRemoteParty " + this.remoteParty); 1801 } 1802 return this.remoteParty; 1803 1804 } 1805 1806 /* 1807 * (non-Javadoc) 1808 * 1809 * @see javax.sip.Dialog#getRemoteTarget() 1810 */ 1811 public javax.sip.address.Address getRemoteTarget() { 1812 1813 return this.remoteTarget; 1814 } 1815 1816 /* 1817 * (non-Javadoc) 1818 * 1819 * @see javax.sip.Dialog#getState() 1820 */ 1821 public DialogState getState() { 1822 if (this.dialogState == NULL_STATE) 1823 return null; // not yet initialized 1824 return DialogState.getObject(this.dialogState); 1825 } 1826 1827 /** 1828 * Returns true if this Dialog is secure i.e. if the request arrived over TLS, and the 1829 * Request-URI contained a SIPS URI, the "secure" flag is set to TRUE. 1830 * 1831 * @return <code>true</code> if this dialogue was established using a sips URI over TLS, and 1832 * <code>false</code> otherwise. 1833 */ 1834 public boolean isSecure() { 1835 return this.firstTransactionSecure; 1836 } 1837 1838 /* 1839 * (non-Javadoc) 1840 * 1841 * @see javax.sip.Dialog#sendAck(javax.sip.message.Request) 1842 */ 1843 public void sendAck(Request request) throws SipException { 1844 this.sendAck(request, true); 1845 } 1846 1847 /* 1848 * (non-Javadoc) 1849 * 1850 * @see javax.sip.Dialog#createRequest(java.lang.String) 1851 */ 1852 public Request createRequest(String method) throws SipException { 1853 1854 if (method.equals(Request.ACK) || method.equals(Request.PRACK)) { 1855 throw new SipException("Invalid method specified for createRequest:" + method); 1856 } 1857 if (lastResponse != null) 1858 return this.createRequest(method, this.lastResponse); 1859 else 1860 throw new SipException("Dialog not yet established -- no response!"); 1861 } 1862 1863 /** 1864 * The method that actually does the work of creating a request. 1865 * 1866 * @param method 1867 * @param response 1868 * @return 1869 * @throws SipException 1870 */ 1871 private Request createRequest(String method, SIPResponse sipResponse) throws SipException { 1872 /* 1873 * Check if the dialog is in the right state (RFC 3261 section 15). The caller's UA MAY 1874 * send a BYE for either CONFIRMED or EARLY dialogs, and the callee's UA MAY send a BYE on 1875 * CONFIRMED dialogs, but MUST NOT send a BYE on EARLY dialogs. 1876 * 1877 * Throw out cancel request. 1878 */ 1879 1880 if (method == null || sipResponse == null) 1881 throw new NullPointerException("null argument"); 1882 1883 if (method.equals(Request.CANCEL)) 1884 throw new SipException("Dialog.createRequest(): Invalid request"); 1885 1886 if (this.getState() == null 1887 || (this.getState().getValue() == TERMINATED_STATE && !method 1888 .equalsIgnoreCase(Request.BYE)) 1889 || (this.isServer() && this.getState().getValue() == EARLY_STATE && method 1890 .equalsIgnoreCase(Request.BYE))) 1891 throw new SipException("Dialog " + getDialogId() 1892 + " not yet established or terminated " + this.getState()); 1893 1894 SipUri sipUri = null; 1895 if (this.getRemoteTarget() != null) 1896 sipUri = (SipUri) this.getRemoteTarget().getURI().clone(); 1897 else { 1898 sipUri = (SipUri) this.getRemoteParty().getURI().clone(); 1899 sipUri.clearUriParms(); 1900 } 1901 1902 CSeq cseq = new CSeq(); 1903 try { 1904 cseq.setMethod(method); 1905 cseq.setSeqNumber(this.getLocalSeqNumber()); 1906 } catch (Exception ex) { 1907 if (sipStack.isLoggingEnabled()) 1908 sipStack.getStackLogger().logError("Unexpected error"); 1909 InternalErrorHandler.handleException(ex); 1910 } 1911 /* 1912 * Add a via header for the outbound request based on the transport of the message 1913 * processor. 1914 */ 1915 1916 ListeningPointImpl lp = (ListeningPointImpl) this.sipProvider 1917 .getListeningPoint(sipResponse.getTopmostVia().getTransport()); 1918 if (lp == null) { 1919 if (sipStack.isLoggingEnabled()) 1920 sipStack.getStackLogger().logError( 1921 "Cannot find listening point for transport " 1922 + sipResponse.getTopmostVia().getTransport()); 1923 throw new SipException("Cannot find listening point for transport " 1924 + sipResponse.getTopmostVia().getTransport()); 1925 } 1926 Via via = lp.getViaHeader(); 1927 1928 From from = new From(); 1929 from.setAddress(this.localParty); 1930 To to = new To(); 1931 to.setAddress(this.remoteParty); 1932 SIPRequest sipRequest = sipResponse.createRequest(sipUri, via, cseq, from, to); 1933 1934 /* 1935 * The default contact header is obtained from the provider. The application can override 1936 * this. 1937 * 1938 * JvB: Should only do this for target refresh requests, ie not for BYE, PRACK, etc 1939 */ 1940 1941 if (SIPRequest.isTargetRefresh(method)) { 1942 ContactHeader contactHeader = ((ListeningPointImpl) this.sipProvider 1943 .getListeningPoint(lp.getTransport())).createContactHeader(); 1944 1945 ((SipURI) contactHeader.getAddress().getURI()).setSecure(this.isSecure()); 1946 sipRequest.setHeader(contactHeader); 1947 } 1948 1949 try { 1950 /* 1951 * Guess of local sequence number - this is being re-set when the request is actually 1952 * dispatched 1953 */ 1954 cseq = (CSeq) sipRequest.getCSeq(); 1955 cseq.setSeqNumber(this.localSequenceNumber + 1); 1956 1957 } catch (InvalidArgumentException ex) { 1958 InternalErrorHandler.handleException(ex); 1959 } 1960 1961 if (method.equals(Request.SUBSCRIBE)) { 1962 1963 if (eventHeader != null) 1964 sipRequest.addHeader(eventHeader); 1965 1966 } 1967 1968 /* 1969 * RFC3261, section 12.2.1.1: 1970 * 1971 * The URI in the To field of the request MUST be set to the remote URI from the dialog 1972 * state. The tag in the To header field of the request MUST be set to the remote tag of 1973 * the dialog ID. The From URI of the request MUST be set to the local URI from the dialog 1974 * state. The tag in the From header field of the request MUST be set to the local tag of 1975 * the dialog ID. If the value of the remote or local tags is null, the tag parameter MUST 1976 * be omitted from the To or From header fields, respectively. 1977 */ 1978 1979 try { 1980 if (this.getLocalTag() != null) { 1981 from.setTag(this.getLocalTag()); 1982 } else { 1983 from.removeTag(); 1984 } 1985 if (this.getRemoteTag() != null) { 1986 to.setTag(this.getRemoteTag()); 1987 } else { 1988 to.removeTag(); 1989 } 1990 } catch (ParseException ex) { 1991 InternalErrorHandler.handleException(ex); 1992 } 1993 1994 // get the route list from the dialog. 1995 this.updateRequest(sipRequest); 1996 1997 return sipRequest; 1998 1999 } 2000 2001 /* 2002 * (non-Javadoc) 2003 * 2004 * @see javax.sip.Dialog#sendRequest(javax.sip.ClientTransaction) 2005 */ 2006 2007 public void sendRequest(ClientTransaction clientTransactionId) 2008 throws TransactionDoesNotExistException, SipException { 2009 this.sendRequest(clientTransactionId, !this.isBackToBackUserAgent); 2010 } 2011 2012 public void sendRequest(ClientTransaction clientTransactionId, boolean allowInterleaving) 2013 throws TransactionDoesNotExistException, SipException { 2014 2015 if ( (!allowInterleaving) 2016 && clientTransactionId.getRequest().getMethod().equals(Request.INVITE)) { 2017 new Thread((new ReInviteSender(clientTransactionId))).start(); 2018 return; 2019 } 2020 2021 SIPRequest dialogRequest = ((SIPClientTransaction) clientTransactionId) 2022 .getOriginalRequest(); 2023 2024 if (sipStack.isLoggingEnabled()) 2025 sipStack.getStackLogger().logDebug( 2026 "dialog.sendRequest " + " dialog = " + this + "\ndialogRequest = \n" 2027 + dialogRequest); 2028 2029 if (clientTransactionId == null) 2030 throw new NullPointerException("null parameter"); 2031 2032 if (dialogRequest.getMethod().equals(Request.ACK) 2033 || dialogRequest.getMethod().equals(Request.CANCEL)) 2034 throw new SipException("Bad Request Method. " + dialogRequest.getMethod()); 2035 2036 // JvB: added, allow re-sending of BYE after challenge 2037 if (byeSent && isTerminatedOnBye() && !dialogRequest.getMethod().equals(Request.BYE)) { 2038 if (sipStack.isLoggingEnabled()) 2039 sipStack.getStackLogger().logError("BYE already sent for " + this); 2040 throw new SipException("Cannot send request; BYE already sent"); 2041 } 2042 2043 if (dialogRequest.getTopmostVia() == null) { 2044 Via via = ((SIPClientTransaction) clientTransactionId).getOutgoingViaHeader(); 2045 dialogRequest.addHeader(via); 2046 } 2047 if (!this.getCallId().getCallId().equalsIgnoreCase(dialogRequest.getCallId().getCallId())) { 2048 2049 if (sipStack.isLoggingEnabled()) { 2050 sipStack.getStackLogger().logError("CallID " + this.getCallId()); 2051 sipStack.getStackLogger().logError( 2052 "RequestCallID = " + dialogRequest.getCallId().getCallId()); 2053 sipStack.getStackLogger().logError("dialog = " + this); 2054 } 2055 throw new SipException("Bad call ID in request"); 2056 } 2057 2058 // Set the dialog back pointer. 2059 ((SIPClientTransaction) clientTransactionId).setDialog(this, this.dialogId); 2060 2061 this.addTransaction((SIPTransaction) clientTransactionId); 2062 // Enable the retransmission filter for the transaction 2063 2064 ((SIPClientTransaction) clientTransactionId).isMapped = true; 2065 2066 From from = (From) dialogRequest.getFrom(); 2067 To to = (To) dialogRequest.getTo(); 2068 2069 // Caller already did the tag assignment -- check to see if the 2070 // tag assignment is OK. 2071 if (this.getLocalTag() != null && from.getTag() != null 2072 && !from.getTag().equals(this.getLocalTag())) 2073 throw new SipException("From tag mismatch expecting " + this.getLocalTag()); 2074 2075 if (this.getRemoteTag() != null && to.getTag() != null 2076 && !to.getTag().equals(this.getRemoteTag())) { 2077 if (sipStack.isLoggingEnabled()) 2078 this.sipStack.getStackLogger().logWarning( 2079 "To header tag mismatch expecting " + this.getRemoteTag()); 2080 } 2081 /* 2082 * The application is sending a NOTIFY before sending the response of the dialog. 2083 */ 2084 if (this.getLocalTag() == null && dialogRequest.getMethod().equals(Request.NOTIFY)) { 2085 if (!this.getMethod().equals(Request.SUBSCRIBE)) 2086 throw new SipException("Trying to send NOTIFY without SUBSCRIBE Dialog!"); 2087 this.setLocalTag(from.getTag()); 2088 2089 } 2090 2091 try { 2092 if (this.getLocalTag() != null) 2093 from.setTag(this.getLocalTag()); 2094 if (this.getRemoteTag() != null) 2095 to.setTag(this.getRemoteTag()); 2096 2097 } catch (ParseException ex) { 2098 2099 InternalErrorHandler.handleException(ex); 2100 2101 } 2102 2103 Hop hop = ((SIPClientTransaction) clientTransactionId).getNextHop(); 2104 if (sipStack.isLoggingEnabled()) { 2105 sipStack.getStackLogger().logDebug( 2106 "Using hop = " + hop.getHost() + " : " + hop.getPort()); 2107 } 2108 2109 try { 2110 MessageChannel messageChannel = sipStack.createRawMessageChannel(this 2111 .getSipProvider().getListeningPoint(hop.getTransport()).getIPAddress(), 2112 this.firstTransactionPort, hop); 2113 2114 MessageChannel oldChannel = ((SIPClientTransaction) 2115 clientTransactionId).getMessageChannel(); 2116 2117 // Remove this from the connection cache if it is in the 2118 // connection 2119 // cache and is not yet active. 2120 oldChannel.uncache(); 2121 2122 // Not configured to cache client connections. 2123 if (!sipStack.cacheClientConnections) { 2124 oldChannel.useCount--; 2125 if (sipStack.isLoggingEnabled()) 2126 sipStack.getStackLogger().logDebug( 2127 "oldChannel: useCount " + oldChannel.useCount); 2128 2129 } 2130 2131 if (messageChannel == null) { 2132 /* 2133 * At this point the procedures of 8.1.2 and 12.2.1.1 of RFC3261 have been tried 2134 * but the resulting next hop cannot be resolved (recall that the exception thrown 2135 * is caught and ignored in SIPStack.createMessageChannel() so we end up here with 2136 * a null messageChannel instead of the exception handler below). All else 2137 * failing, try the outbound proxy in accordance with 8.1.2, in particular: This 2138 * ensures that outbound proxies that do not add Record-Route header field values 2139 * will drop out of the path of subsequent requests. It allows endpoints that 2140 * cannot resolve the first Route URI to delegate that task to an outbound proxy. 2141 * 2142 * if one considers the 'first Route URI' of a request constructed according to 2143 * 12.2.1.1 to be the request URI when the route set is empty. 2144 */ 2145 if (sipStack.isLoggingEnabled()) 2146 sipStack.getStackLogger().logDebug( 2147 "Null message channel using outbound proxy !"); 2148 Hop outboundProxy = sipStack.getRouter(dialogRequest).getOutboundProxy(); 2149 if (outboundProxy == null) 2150 throw new SipException("No route found! hop=" + hop); 2151 messageChannel = sipStack.createRawMessageChannel(this.getSipProvider() 2152 .getListeningPoint(outboundProxy.getTransport()).getIPAddress(), 2153 this.firstTransactionPort, outboundProxy); 2154 if (messageChannel != null) 2155 ((SIPClientTransaction) clientTransactionId) 2156 .setEncapsulatedChannel(messageChannel); 2157 } else { 2158 ((SIPClientTransaction) clientTransactionId) 2159 .setEncapsulatedChannel(messageChannel); 2160 2161 if (sipStack.isLoggingEnabled()) { 2162 sipStack.getStackLogger().logDebug("using message channel " + messageChannel); 2163 2164 } 2165 2166 } 2167 2168 if (messageChannel != null) messageChannel.useCount++; 2169 2170 // See if we need to release the previously mapped channel. 2171 if ((!sipStack.cacheClientConnections) && oldChannel != null 2172 && oldChannel.useCount <= 0) 2173 oldChannel.close(); 2174 } catch (Exception ex) { 2175 if (sipStack.isLoggingEnabled()) 2176 sipStack.getStackLogger().logException(ex); 2177 throw new SipException("Could not create message channel", ex); 2178 } 2179 2180 try { 2181 // Increment before setting!! 2182 localSequenceNumber++; 2183 dialogRequest.getCSeq().setSeqNumber(getLocalSeqNumber()); 2184 } catch (InvalidArgumentException ex) { 2185 sipStack.getStackLogger().logFatalError(ex.getMessage()); 2186 } 2187 2188 try { 2189 ((SIPClientTransaction) clientTransactionId).sendMessage(dialogRequest); 2190 /* 2191 * Note that if the BYE is rejected then the Dialog should bo back to the ESTABLISHED 2192 * state so we only set state after successful send. 2193 */ 2194 if (dialogRequest.getMethod().equals(Request.BYE)) { 2195 this.byeSent = true; 2196 /* 2197 * Dialog goes into TERMINATED state as soon as BYE is sent. ISSUE 182. 2198 */ 2199 if (isTerminatedOnBye()) { 2200 this.setState(DialogState._TERMINATED); 2201 } 2202 } 2203 } catch (IOException ex) { 2204 throw new SipException("error sending message", ex); 2205 } 2206 2207 } 2208 2209 /** 2210 * Return yes if the last response is to be retransmitted. 2211 */ 2212 private boolean toRetransmitFinalResponse(int T2) { 2213 if (--retransmissionTicksLeft == 0) { 2214 if (2 * prevRetransmissionTicks <= T2) 2215 this.retransmissionTicksLeft = 2 * prevRetransmissionTicks; 2216 else 2217 this.retransmissionTicksLeft = prevRetransmissionTicks; 2218 this.prevRetransmissionTicks = retransmissionTicksLeft; 2219 return true; 2220 } else 2221 return false; 2222 2223 } 2224 2225 protected void setRetransmissionTicks() { 2226 this.retransmissionTicksLeft = 1; 2227 this.prevRetransmissionTicks = 1; 2228 } 2229 2230 /** 2231 * Resend the last ack. 2232 */ 2233 public void resendAck() throws SipException { 2234 // Check for null. 2235 2236 if (this.getLastAckSent() != null) { 2237 if (getLastAckSent().getHeader(TimeStampHeader.NAME) != null 2238 && sipStack.generateTimeStampHeader) { 2239 TimeStamp ts = new TimeStamp(); 2240 try { 2241 ts.setTimeStamp(System.currentTimeMillis()); 2242 getLastAckSent().setHeader(ts); 2243 } catch (InvalidArgumentException e) { 2244 2245 } 2246 } 2247 this.sendAck(getLastAckSent(), false); 2248 } 2249 2250 } 2251 2252 /** 2253 * Get the method of the request/response that resulted in the creation of the Dialog. 2254 * 2255 * @return -- the method of the dialog. 2256 */ 2257 public String getMethod() { 2258 // Method of the request or response used to create this dialog 2259 return this.method; 2260 } 2261 2262 /** 2263 * Start the dialog timer. 2264 * 2265 * @param transaction 2266 */ 2267 2268 protected void startTimer(SIPServerTransaction transaction) { 2269 if (this.timerTask != null && timerTask.transaction == transaction) { 2270 if (sipStack.isLoggingEnabled()) 2271 sipStack.getStackLogger().logDebug("Timer already running for " + getDialogId()); 2272 return; 2273 } 2274 if (sipStack.isLoggingEnabled()) 2275 sipStack.getStackLogger().logDebug("Starting dialog timer for " + getDialogId()); 2276 this.ackSeen = false; 2277 2278 acquireTimerTaskSem(); 2279 try { 2280 if (this.timerTask != null) { 2281 this.timerTask.transaction = transaction; 2282 } else { 2283 this.timerTask = new DialogTimerTask(transaction); 2284 sipStack.getTimer().schedule(timerTask, SIPTransactionStack.BASE_TIMER_INTERVAL, 2285 SIPTransactionStack.BASE_TIMER_INTERVAL); 2286 } 2287 } finally { 2288 releaseTimerTaskSem(); 2289 } 2290 2291 this.setRetransmissionTicks(); 2292 } 2293 2294 /** 2295 * Stop the dialog timer. This is called when the dialog is terminated. 2296 * 2297 */ 2298 protected void stopTimer() { 2299 try { 2300 acquireTimerTaskSem(); 2301 try { 2302 if (this.timerTask != null) { 2303 this.timerTask.cancel(); 2304 this.timerTask = null; 2305 } 2306 } finally { 2307 releaseTimerTaskSem(); 2308 } 2309 } catch (Exception ex) { 2310 } 2311 } 2312 2313 /* 2314 * (non-Javadoc) Retransmissions of the reliable provisional response cease when a matching 2315 * PRACK is received by the UA core. PRACK is like any other request within a dialog, and the 2316 * UAS core processes it according to the procedures of Sections 8.2 and 12.2.2 of RFC 3261. A 2317 * matching PRACK is defined as one within the same dialog as the response, and whose method, 2318 * CSeq-num, and response-num in the RAck header field match, respectively, the method from 2319 * the CSeq, the sequence number from the CSeq, and the sequence number from the RSeq of the 2320 * reliable provisional response. 2321 * 2322 * @see javax.sip.Dialog#createPrack(javax.sip.message.Response) 2323 */ 2324 public Request createPrack(Response relResponse) throws DialogDoesNotExistException, 2325 SipException { 2326 2327 if (this.getState() == null || this.getState().equals(DialogState.TERMINATED)) 2328 throw new DialogDoesNotExistException("Dialog not initialized or terminated"); 2329 2330 if ((RSeq) relResponse.getHeader(RSeqHeader.NAME) == null) { 2331 throw new SipException("Missing RSeq Header"); 2332 } 2333 2334 try { 2335 SIPResponse sipResponse = (SIPResponse) relResponse; 2336 SIPRequest sipRequest = (SIPRequest) this.createRequest(Request.PRACK, 2337 (SIPResponse) relResponse); 2338 String toHeaderTag = sipResponse.getTo().getTag(); 2339 sipRequest.setToTag(toHeaderTag); 2340 RAck rack = new RAck(); 2341 RSeq rseq = (RSeq) relResponse.getHeader(RSeqHeader.NAME); 2342 rack.setMethod(sipResponse.getCSeq().getMethod()); 2343 rack.setCSequenceNumber((int) sipResponse.getCSeq().getSeqNumber()); 2344 rack.setRSequenceNumber(rseq.getSeqNumber()); 2345 sipRequest.setHeader(rack); 2346 return (Request) sipRequest; 2347 } catch (Exception ex) { 2348 InternalErrorHandler.handleException(ex); 2349 return null; 2350 } 2351 2352 } 2353 2354 private void updateRequest(SIPRequest sipRequest) { 2355 2356 RouteList rl = this.getRouteList(); 2357 if (rl.size() > 0) { 2358 sipRequest.setHeader(rl); 2359 } else { 2360 sipRequest.removeHeader(RouteHeader.NAME); 2361 } 2362 if (MessageFactoryImpl.getDefaultUserAgentHeader() != null) { 2363 sipRequest.setHeader(MessageFactoryImpl.getDefaultUserAgentHeader()); 2364 } 2365 2366 } 2367 2368 /* 2369 * (non-Javadoc) The UAC core MUST generate an ACK request for each 2xx received from the 2370 * transaction layer. The header fields of the ACK are constructed in the same way as for any 2371 * request sent within a dialog (see Section 12) with the exception of the CSeq and the header 2372 * fields related to authentication. The sequence number of the CSeq header field MUST be the 2373 * same as the INVITE being acknowledged, but the CSeq method MUST be ACK. The ACK MUST 2374 * contain the same credentials as the INVITE. If the 2xx contains an offer (based on the 2375 * rules above), the ACK MUST carry an answer in its body. If the offer in the 2xx response is 2376 * not acceptable, the UAC core MUST generate a valid answer in the ACK and then send a BYE 2377 * immediately. 2378 * 2379 * Note that for the case of forked requests, you can create multiple outgoing invites each 2380 * with a different cseq and hence you need to supply the invite. 2381 * 2382 * @see javax.sip.Dialog#createAck(long) 2383 */ 2384 public Request createAck(long cseqno) throws InvalidArgumentException, SipException { 2385 2386 // JvB: strictly speaking it is allowed to start a dialog with 2387 // SUBSCRIBE, 2388 // then send INVITE+ACK later on 2389 if (!method.equals(Request.INVITE)) 2390 throw new SipException("Dialog was not created with an INVITE" + method); 2391 2392 if (cseqno <= 0) 2393 throw new InvalidArgumentException("bad cseq <= 0 "); 2394 else if (cseqno > ((((long) 1) << 32) - 1)) 2395 throw new InvalidArgumentException("bad cseq > " + ((((long) 1) << 32) - 1)); 2396 2397 if (this.remoteTarget == null) { 2398 throw new SipException("Cannot create ACK - no remote Target!"); 2399 } 2400 2401 if (this.sipStack.isLoggingEnabled()) { 2402 this.sipStack.getStackLogger().logDebug("createAck " + this + " cseqno " + cseqno); 2403 } 2404 2405 // MUST ack in the same order that the OKs were received. This traps 2406 // out of order ACK sending. Old ACKs seqno's can always be ACKed. 2407 if (lastInviteOkReceived < cseqno) { 2408 if (sipStack.isLoggingEnabled()) { 2409 this.sipStack.getStackLogger().logDebug( 2410 "WARNING : Attempt to crete ACK without OK " + this); 2411 this.sipStack.getStackLogger().logDebug("LAST RESPONSE = " + this.lastResponse); 2412 } 2413 throw new SipException("Dialog not yet established -- no OK response!"); 2414 } 2415 2416 try { 2417 2418 // JvB: Transport from first entry in route set, or remote Contact 2419 // if none 2420 // Only used to find correct LP & create correct Via 2421 SipURI uri4transport = null; 2422 2423 if (this.routeList != null && !this.routeList.isEmpty()) { 2424 Route r = (Route) this.routeList.getFirst(); 2425 uri4transport = ((SipURI) r.getAddress().getURI()); 2426 } else { // should be !=null, checked above 2427 uri4transport = ((SipURI) this.remoteTarget.getURI()); 2428 } 2429 2430 String transport = uri4transport.getTransportParam(); 2431 if (transport == null) { 2432 // JvB fix: also support TLS 2433 transport = uri4transport.isSecure() ? ListeningPoint.TLS : ListeningPoint.UDP; 2434 } 2435 ListeningPointImpl lp = (ListeningPointImpl) sipProvider.getListeningPoint(transport); 2436 if (lp == null) { 2437 if (sipStack.isLoggingEnabled()) { 2438 sipStack.getStackLogger().logError( 2439 "remoteTargetURI " + this.remoteTarget.getURI()); 2440 sipStack.getStackLogger().logError("uri4transport = " + uri4transport); 2441 sipStack.getStackLogger().logError("No LP found for transport=" + transport); 2442 } 2443 throw new SipException( 2444 "Cannot create ACK - no ListeningPoint for transport towards next hop found:" 2445 + transport); 2446 } 2447 SIPRequest sipRequest = new SIPRequest(); 2448 sipRequest.setMethod(Request.ACK); 2449 sipRequest.setRequestURI((SipUri) getRemoteTarget().getURI().clone()); 2450 sipRequest.setCallId(this.callIdHeader); 2451 sipRequest.setCSeq(new CSeq(cseqno, Request.ACK)); 2452 List<Via> vias = new ArrayList<Via>(); 2453 // Via via = lp.getViaHeader(); 2454 // The user may have touched the sentby for the response. 2455 // so use the via header extracted from the response for the ACK => 2456 // https://jain-sip.dev.java.net/issues/show_bug.cgi?id=205 2457 // strip the params from the via of the response and use the params from the 2458 // original request 2459 Via via = this.lastResponse.getTopmostVia(); 2460 via.removeParameters(); 2461 if (originalRequest != null && originalRequest.getTopmostVia() != null) { 2462 NameValueList originalRequestParameters = originalRequest.getTopmostVia() 2463 .getParameters(); 2464 if (originalRequestParameters != null && originalRequestParameters.size() > 0) { 2465 via.setParameters((NameValueList) originalRequestParameters.clone()); 2466 } 2467 } 2468 via.setBranch(Utils.getInstance().generateBranchId()); // new branch 2469 vias.add(via); 2470 sipRequest.setVia(vias); 2471 From from = new From(); 2472 from.setAddress(this.localParty); 2473 from.setTag(this.myTag); 2474 sipRequest.setFrom(from); 2475 To to = new To(); 2476 to.setAddress(this.remoteParty); 2477 if (hisTag != null) 2478 to.setTag(this.hisTag); 2479 sipRequest.setTo(to); 2480 sipRequest.setMaxForwards(new MaxForwards(70)); 2481 2482 if (this.originalRequest != null) { 2483 Authorization authorization = this.originalRequest.getAuthorization(); 2484 if (authorization != null) 2485 sipRequest.setHeader(authorization); 2486 } 2487 2488 // ACKs for 2xx responses 2489 // use the Route values learned from the Record-Route of the 2xx 2490 // responses. 2491 this.updateRequest(sipRequest); 2492 2493 return sipRequest; 2494 } catch (Exception ex) { 2495 InternalErrorHandler.handleException(ex); 2496 throw new SipException("unexpected exception ", ex); 2497 } 2498 2499 } 2500 2501 /** 2502 * Get the provider for this Dialog. 2503 * 2504 * SPEC_REVISION 2505 * 2506 * @return -- the SIP Provider associated with this transaction. 2507 */ 2508 public SipProviderImpl getSipProvider() { 2509 return this.sipProvider; 2510 } 2511 2512 /** 2513 * @param sipProvider the sipProvider to set 2514 */ 2515 public void setSipProvider(SipProviderImpl sipProvider) { 2516 this.sipProvider = sipProvider; 2517 } 2518 2519 /** 2520 * Check the tags of the response against the tags of the Dialog. Return true if the respnse 2521 * matches the tags of the dialog. We do this check wehn sending out a response. 2522 * 2523 * @param sipResponse -- the response to check. 2524 * 2525 */ 2526 public void setResponseTags(SIPResponse sipResponse) { 2527 if (this.getLocalTag() != null || this.getRemoteTag() != null) { 2528 return; 2529 } 2530 String responseFromTag = sipResponse.getFromTag(); 2531 if ( responseFromTag != null ) { 2532 if (responseFromTag.equals(this.getLocalTag())) { 2533 sipResponse.setToTag(this.getRemoteTag()); 2534 } else if (responseFromTag.equals(this.getRemoteTag())) { 2535 sipResponse.setToTag(this.getLocalTag()); 2536 } 2537 } else { 2538 if (sipStack.isLoggingEnabled()) 2539 sipStack.getStackLogger().logWarning("No from tag in response! Not RFC 3261 compatible."); 2540 } 2541 2542 } 2543 2544 /** 2545 * Set the last response for this dialog. This method is called for updating the dialog state 2546 * when a response is either sent or received from within a Dialog. 2547 * 2548 * @param transaction -- the transaction associated with the response 2549 * @param sipResponse -- the last response to set. 2550 */ 2551 public void setLastResponse(SIPTransaction transaction, SIPResponse sipResponse) { 2552 this.callIdHeader = sipResponse.getCallId(); 2553 int statusCode = sipResponse.getStatusCode(); 2554 if (statusCode == 100) { 2555 if (sipStack.isLoggingEnabled()) 2556 sipStack.getStackLogger().logWarning( 2557 "Invalid status code - 100 in setLastResponse - ignoring"); 2558 return; 2559 } 2560 2561 this.lastResponse = sipResponse; 2562 this.setAssigned(); 2563 // Adjust state of the Dialog state machine. 2564 if (sipStack.isLoggingEnabled()) { 2565 sipStack.getStackLogger().logDebug( 2566 "sipDialog: setLastResponse:" + this + " lastResponse = " 2567 + this.lastResponse.getFirstLine()); 2568 } 2569 if (this.getState() == DialogState.TERMINATED) { 2570 if (sipStack.isLoggingEnabled()) { 2571 sipStack.getStackLogger().logDebug( 2572 "sipDialog: setLastResponse -- dialog is terminated - ignoring "); 2573 } 2574 // Capture the OK response for later use in createAck 2575 // This is handy for late arriving OK's that we want to ACK. 2576 if (sipResponse.getCSeq().getMethod().equals(Request.INVITE) && statusCode == 200) { 2577 2578 this.lastInviteOkReceived = Math.max(sipResponse.getCSeq().getSeqNumber(), 2579 this.lastInviteOkReceived); 2580 } 2581 return; 2582 } 2583 String cseqMethod = sipResponse.getCSeq().getMethod(); 2584 if (sipStack.isLoggingEnabled()) { 2585 sipStack.getStackLogger().logStackTrace(); 2586 sipStack.getStackLogger().logDebug("cseqMethod = " + cseqMethod); 2587 sipStack.getStackLogger().logDebug("dialogState = " + this.getState()); 2588 sipStack.getStackLogger().logDebug("method = " + this.getMethod()); 2589 sipStack.getStackLogger().logDebug("statusCode = " + statusCode); 2590 sipStack.getStackLogger().logDebug("transaction = " + transaction); 2591 } 2592 2593 // JvB: don't use "!this.isServer" here 2594 // note that the transaction can be null for forked 2595 // responses. 2596 if (transaction == null || transaction instanceof ClientTransaction) { 2597 if (sipStack.isDialogCreated(cseqMethod)) { 2598 // Make a final tag assignment. 2599 if (getState() == null && (statusCode / 100 == 1)) { 2600 /* 2601 * Guard aginst slipping back into early state from confirmed state. 2602 */ 2603 // Was (sipResponse.getToTag() != null || sipStack.rfc2543Supported) 2604 setState(SIPDialog.EARLY_STATE); 2605 if ((sipResponse.getToTag() != null || sipStack.rfc2543Supported) 2606 && this.getRemoteTag() == null) { 2607 setRemoteTag(sipResponse.getToTag()); 2608 this.setDialogId(sipResponse.getDialogId(false)); 2609 sipStack.putDialog(this); 2610 this.addRoute(sipResponse); 2611 } 2612 } else if (getState() != null && getState().equals(DialogState.EARLY) 2613 && statusCode / 100 == 1) { 2614 /* 2615 * This case occurs for forked dialog responses. The To tag can change as a 2616 * result of the forking. The remote target can also change as a result of the 2617 * forking. 2618 */ 2619 if (cseqMethod.equals(getMethod()) && transaction != null 2620 && (sipResponse.getToTag() != null || sipStack.rfc2543Supported)) { 2621 setRemoteTag(sipResponse.getToTag()); 2622 this.setDialogId(sipResponse.getDialogId(false)); 2623 sipStack.putDialog(this); 2624 this.addRoute(sipResponse); 2625 } 2626 } else if (statusCode / 100 == 2) { 2627 // This is a dialog creating method (such as INVITE). 2628 // 2xx response -- set the state to the confirmed 2629 // state. To tag is MANDATORY for the response. 2630 2631 // Only do this if method equals initial request! 2632 2633 if (cseqMethod.equals(getMethod()) 2634 && (sipResponse.getToTag() != null || sipStack.rfc2543Supported) 2635 && this.getState() != DialogState.CONFIRMED) { 2636 setRemoteTag(sipResponse.getToTag()); 2637 this.setDialogId(sipResponse.getDialogId(false)); 2638 sipStack.putDialog(this); 2639 this.addRoute(sipResponse); 2640 2641 setState(SIPDialog.CONFIRMED_STATE); 2642 } 2643 2644 // Capture the OK response for later use in createAck 2645 if (cseqMethod.equals(Request.INVITE)) { 2646 this.lastInviteOkReceived = Math.max(sipResponse.getCSeq().getSeqNumber(), 2647 this.lastInviteOkReceived); 2648 } 2649 2650 } else if (statusCode >= 300 2651 && statusCode <= 699 2652 && (getState() == null || (cseqMethod.equals(getMethod()) && getState() 2653 .getValue() == SIPDialog.EARLY_STATE))) { 2654 /* 2655 * This case handles 3xx, 4xx, 5xx and 6xx responses. RFC 3261 Section 12.3 - 2656 * dialog termination. Independent of the method, if a request outside of a 2657 * dialog generates a non-2xx final response, any early dialogs created 2658 * through provisional responses to that request are terminated. 2659 */ 2660 setState(SIPDialog.TERMINATED_STATE); 2661 } 2662 2663 /* 2664 * This code is in support of "proxy" servers that are constructed as back to back 2665 * user agents. This could be a dialog in the middle of the call setup path 2666 * somewhere. Hence the incoming invite has record route headers in it. The 2667 * response will have additional record route headers. However, for this dialog 2668 * only the downstream record route headers matter. Ideally proxy servers should 2669 * not be constructed as Back to Back User Agents. Remove all the record routes 2670 * that are present in the incoming INVITE so you only have the downstream Route 2671 * headers present in the dialog. Note that for an endpoint - you will have no 2672 * record route headers present in the original request so the loop will not 2673 * execute. 2674 */ 2675 if ( this.getState() != DialogState.CONFIRMED && this.getState() != DialogState.TERMINATED ) { 2676 if (originalRequest != null) { 2677 RecordRouteList rrList = originalRequest.getRecordRouteHeaders(); 2678 if (rrList != null) { 2679 ListIterator<RecordRoute> it = rrList.listIterator(rrList.size()); 2680 while (it.hasPrevious()) { 2681 RecordRoute rr = (RecordRoute) it.previous(); 2682 Route route = (Route) routeList.getFirst(); 2683 if (route != null && rr.getAddress().equals(route.getAddress())) { 2684 routeList.removeFirst(); 2685 } else 2686 break; 2687 } 2688 } 2689 } 2690 } 2691 2692 } else if (cseqMethod.equals(Request.NOTIFY) 2693 && (this.getMethod().equals(Request.SUBSCRIBE) || this.getMethod().equals( 2694 Request.REFER)) && sipResponse.getStatusCode() / 100 == 2 2695 && this.getState() == null) { 2696 // This is a notify response. 2697 this.setDialogId(sipResponse.getDialogId(true)); 2698 sipStack.putDialog(this); 2699 this.setState(SIPDialog.CONFIRMED_STATE); 2700 2701 } else if (cseqMethod.equals(Request.BYE) && statusCode / 100 == 2 2702 && isTerminatedOnBye()) { 2703 // Dialog will be terminated when the transction is terminated. 2704 setState(SIPDialog.TERMINATED_STATE); 2705 } 2706 } else { 2707 // Processing Server Dialog. 2708 2709 if (cseqMethod.equals(Request.BYE) && statusCode / 100 == 2 2710 && this.isTerminatedOnBye()) { 2711 /* 2712 * Only transition to terminated state when 200 OK is returned for the BYE. Other 2713 * status codes just result in leaving the state in COMPLETED state. 2714 */ 2715 this.setState(SIPDialog.TERMINATED_STATE); 2716 } else { 2717 boolean doPutDialog = false; 2718 2719 if (getLocalTag() == null && sipResponse.getTo().getTag() != null 2720 && sipStack.isDialogCreated(cseqMethod) && cseqMethod.equals(getMethod())) { 2721 setLocalTag(sipResponse.getTo().getTag()); 2722 2723 doPutDialog = true; 2724 } 2725 2726 if (statusCode / 100 != 2) { 2727 if (statusCode / 100 == 1) { 2728 if (doPutDialog) { 2729 2730 setState(SIPDialog.EARLY_STATE); 2731 this.setDialogId(sipResponse.getDialogId(true)); 2732 sipStack.putDialog(this); 2733 } 2734 } else { 2735 /* 2736 * RFC 3265 chapter 3.1.4.1 "Non-200 class final responses indicate that 2737 * no subscription or dialog has been created, and no subsequent NOTIFY 2738 * message will be sent. All non-200 class" + responses (with the 2739 * exception of "489", described herein) have the same meanings and 2740 * handling as described in SIP" 2741 */ 2742 // Bug Fix by Jens tinfors 2743 // see https://jain-sip.dev.java.net/servlets/ReadMsg?list=users&msgNo=797 2744 if (statusCode == 489 2745 && (cseqMethod.equals(Request.NOTIFY) || cseqMethod 2746 .equals(Request.SUBSCRIBE))) { 2747 if (sipStack.isLoggingEnabled()) 2748 sipStack.getStackLogger().logDebug( 2749 "RFC 3265 : Not setting dialog to TERMINATED for 489"); 2750 } else { 2751 // baranowb: simplest fix to 2752 // https://jain-sip.dev.java.net/issues/show_bug.cgi?id=175 2753 // application is responsible for terminating in this case 2754 // see rfc 5057 for better explanation 2755 if (!this.isReInvite() && getState() != DialogState.CONFIRMED) { 2756 this.setState(SIPDialog.TERMINATED_STATE); 2757 } 2758 } 2759 } 2760 2761 } else { 2762 2763 /* 2764 * JvB: RFC4235 says that when sending 2xx on UAS side, state should move to 2765 * CONFIRMED 2766 */ 2767 if (this.dialogState <= SIPDialog.EARLY_STATE 2768 && (cseqMethod.equals(Request.INVITE) 2769 || cseqMethod.equals(Request.SUBSCRIBE) || cseqMethod 2770 .equals(Request.REFER))) { 2771 this.setState(SIPDialog.CONFIRMED_STATE); 2772 } 2773 2774 if (doPutDialog) { 2775 this.setDialogId(sipResponse.getDialogId(true)); 2776 sipStack.putDialog(this); 2777 } 2778 /* 2779 * We put the dialog into the table. We must wait for ACK before re-INVITE is 2780 * sent 2781 */ 2782 if (transaction.getState() != TransactionState.TERMINATED 2783 && sipResponse.getStatusCode() == Response.OK 2784 && cseqMethod.equals(Request.INVITE) 2785 && this.isBackToBackUserAgent) { 2786 /* 2787 * Acquire the flag for re-INVITE so that we cannot re-INVITE before 2788 * ACK is received. 2789 */ 2790 if (!this.takeAckSem()) { 2791 if (sipStack.isLoggingEnabled()) { 2792 sipStack.getStackLogger().logDebug( 2793 "Delete dialog -- cannot acquire ackSem"); 2794 } 2795 this.delete(); 2796 return; 2797 } 2798 2799 } 2800 } 2801 } 2802 2803 } 2804 2805 } 2806 2807 /** 2808 * Start the retransmit timer. 2809 * 2810 * @param sipServerTx -- server transaction on which the response was sent 2811 * @param response - response that was sent. 2812 */ 2813 public void startRetransmitTimer(SIPServerTransaction sipServerTx, Response response) { 2814 if (sipServerTx.getRequest().getMethod().equals(Request.INVITE) 2815 && response.getStatusCode() / 100 == 2) { 2816 this.startTimer(sipServerTx); 2817 } 2818 } 2819 2820 /** 2821 * @return -- the last response associated with the dialog. 2822 */ 2823 public SIPResponse getLastResponse() { 2824 2825 return lastResponse; 2826 } 2827 2828 /** 2829 * Do taget refresh dialog state updates. 2830 * 2831 * RFC 3261: Requests within a dialog MAY contain Record-Route and Contact header fields. 2832 * However, these requests do not cause the dialog's route set to be modified, although they 2833 * may modify the remote target URI. Specifically, requests that are not target refresh 2834 * requests do not modify the dialog's remote target URI, and requests that are target refresh 2835 * requests do. For dialogs that have been established with an 2836 * 2837 * INVITE, the only target refresh request defined is re-INVITE (see Section 14). Other 2838 * extensions may define different target refresh requests for dialogs established in other 2839 * ways. 2840 */ 2841 private void doTargetRefresh(SIPMessage sipMessage) { 2842 2843 ContactList contactList = sipMessage.getContactHeaders(); 2844 2845 /* 2846 * INVITE is the target refresh for INVITE dialogs. SUBSCRIBE is the target refresh for 2847 * subscribe dialogs from the client side. This modifies the remote target URI potentially 2848 */ 2849 if (contactList != null) { 2850 2851 Contact contact = (Contact) contactList.getFirst(); 2852 this.setRemoteTarget(contact); 2853 2854 } 2855 2856 } 2857 2858 private static final boolean optionPresent(ListIterator l, String option) { 2859 while (l.hasNext()) { 2860 OptionTag opt = (OptionTag) l.next(); 2861 if (opt != null && option.equalsIgnoreCase(opt.getOptionTag())) 2862 return true; 2863 } 2864 return false; 2865 } 2866 2867 /* 2868 * (non-Javadoc) 2869 * 2870 * @see javax.sip.Dialog#createReliableProvisionalResponse(int) 2871 */ 2872 public Response createReliableProvisionalResponse(int statusCode) 2873 throws InvalidArgumentException, SipException { 2874 2875 if (!(firstTransactionIsServerTransaction)) { 2876 throw new SipException("Not a Server Dialog!"); 2877 2878 } 2879 /* 2880 * A UAS MUST NOT attempt to send a 100 (Trying) response reliably. Only provisional 2881 * responses numbered 101 to 199 may be sent reliably. If the request did not include 2882 * either a Supported or Require header field indicating this feature, the UAS MUST NOT 2883 * send the provisional response reliably. 2884 */ 2885 if (statusCode <= 100 || statusCode > 199) 2886 throw new InvalidArgumentException("Bad status code "); 2887 SIPRequest request = this.originalRequest; 2888 if (!request.getMethod().equals(Request.INVITE)) 2889 throw new SipException("Bad method"); 2890 2891 ListIterator<SIPHeader> list = request.getHeaders(SupportedHeader.NAME); 2892 if (list == null || !optionPresent(list, "100rel")) { 2893 list = request.getHeaders(RequireHeader.NAME); 2894 if (list == null || !optionPresent(list, "100rel")) { 2895 throw new SipException("No Supported/Require 100rel header in the request"); 2896 } 2897 } 2898 2899 SIPResponse response = request.createResponse(statusCode); 2900 /* 2901 * The provisional response to be sent reliably is constructed by the UAS core according 2902 * to the procedures of Section 8.2.6 of RFC 3261. In addition, it MUST contain a Require 2903 * header field containing the option tag 100rel, and MUST include an RSeq header field. 2904 * The value of the header field for the first reliable provisional response in a 2905 * transaction MUST be between 1 and 2**31 - 1. It is RECOMMENDED that it be chosen 2906 * uniformly in this range. The RSeq numbering space is within a single transaction. This 2907 * means that provisional responses for different requests MAY use the same values for the 2908 * RSeq number. 2909 */ 2910 Require require = new Require(); 2911 try { 2912 require.setOptionTag("100rel"); 2913 } catch (Exception ex) { 2914 InternalErrorHandler.handleException(ex); 2915 } 2916 response.addHeader(require); 2917 RSeq rseq = new RSeq(); 2918 /* 2919 * set an arbitrary sequence number. This is actually set when the response is sent out 2920 */ 2921 rseq.setSeqNumber(1L); 2922 /* 2923 * Copy the record route headers from the request to the response ( Issue 160 ). Note that 2924 * other 1xx headers do not get their Record Route headers copied over but reliable 2925 * provisional responses do. See RFC 3262 Table 2. 2926 */ 2927 RecordRouteList rrl = request.getRecordRouteHeaders(); 2928 if (rrl != null) { 2929 RecordRouteList rrlclone = (RecordRouteList) rrl.clone(); 2930 response.setHeader(rrlclone); 2931 } 2932 2933 return response; 2934 } 2935 2936 /** 2937 * Do the processing necessary for the PRACK 2938 * 2939 * @param prackRequest 2940 * @return true if this is the first time the tx has seen the prack ( and hence needs to be 2941 * passed up to the TU) 2942 */ 2943 public boolean handlePrack(SIPRequest prackRequest) { 2944 /* 2945 * The RAck header is sent in a PRACK request to support reliability of provisional 2946 * responses. It contains two numbers and a method tag. The first number is the value from 2947 * the RSeq header in the provisional response that is being acknowledged. The next 2948 * number, and the method, are copied from the CSeq in the response that is being 2949 * acknowledged. The method name in the RAck header is case sensitive. 2950 */ 2951 if (!this.isServer()) { 2952 if (sipStack.isLoggingEnabled()) 2953 sipStack.getStackLogger().logDebug("Dropping Prack -- not a server Dialog"); 2954 return false; 2955 } 2956 SIPServerTransaction sipServerTransaction = (SIPServerTransaction) this 2957 .getFirstTransaction(); 2958 SIPResponse sipResponse = sipServerTransaction.getReliableProvisionalResponse(); 2959 2960 if (sipResponse == null) { 2961 if (sipStack.isLoggingEnabled()) 2962 sipStack.getStackLogger() 2963 .logDebug("Dropping Prack -- ReliableResponse not found"); 2964 return false; 2965 } 2966 2967 RAck rack = (RAck) prackRequest.getHeader(RAckHeader.NAME); 2968 2969 if (rack == null) { 2970 if (sipStack.isLoggingEnabled()) 2971 sipStack.getStackLogger().logDebug("Dropping Prack -- rack header not found"); 2972 return false; 2973 } 2974 CSeq cseq = (CSeq) sipResponse.getCSeq(); 2975 2976 if (!rack.getMethod().equals(cseq.getMethod())) { 2977 if (sipStack.isLoggingEnabled()) 2978 sipStack.getStackLogger().logDebug( 2979 "Dropping Prack -- CSeq Header does not match PRACK"); 2980 return false; 2981 } 2982 2983 if (rack.getCSeqNumberLong() != cseq.getSeqNumber()) { 2984 if (sipStack.isLoggingEnabled()) 2985 sipStack.getStackLogger().logDebug( 2986 "Dropping Prack -- CSeq Header does not match PRACK"); 2987 return false; 2988 } 2989 2990 RSeq rseq = (RSeq) sipResponse.getHeader(RSeqHeader.NAME); 2991 2992 if (rack.getRSequenceNumber() != rseq.getSeqNumber()) { 2993 if (sipStack.isLoggingEnabled()) 2994 sipStack.getStackLogger().logDebug( 2995 "Dropping Prack -- RSeq Header does not match PRACK"); 2996 return false; 2997 } 2998 2999 return sipServerTransaction.prackRecieved(); 3000 } 3001 3002 /* 3003 * (non-Javadoc) 3004 * 3005 * @see javax.sip.Dialog#sendReliableProvisionalResponse(javax.sip.message.Response) 3006 */ 3007 public void sendReliableProvisionalResponse(Response relResponse) throws SipException { 3008 if (!this.isServer()) { 3009 throw new SipException("Not a Server Dialog"); 3010 } 3011 3012 SIPResponse sipResponse = (SIPResponse) relResponse; 3013 3014 if (relResponse.getStatusCode() == 100) 3015 throw new SipException("Cannot send 100 as a reliable provisional response"); 3016 3017 if (relResponse.getStatusCode() / 100 > 2) 3018 throw new SipException( 3019 "Response code is not a 1xx response - should be in the range 101 to 199 "); 3020 3021 /* 3022 * Do a little checking on the outgoing response. 3023 */ 3024 if (sipResponse.getToTag() == null) { 3025 throw new SipException( 3026 "Badly formatted response -- To tag mandatory for Reliable Provisional Response"); 3027 } 3028 ListIterator requireList = (ListIterator) relResponse.getHeaders(RequireHeader.NAME); 3029 boolean found = false; 3030 3031 if (requireList != null) { 3032 3033 while (requireList.hasNext() && !found) { 3034 RequireHeader rh = (RequireHeader) requireList.next(); 3035 if (rh.getOptionTag().equalsIgnoreCase("100rel")) { 3036 found = true; 3037 } 3038 } 3039 } 3040 3041 if (!found) { 3042 Require require = new Require("100rel"); 3043 relResponse.addHeader(require); 3044 if (sipStack.isLoggingEnabled()) { 3045 sipStack.getStackLogger().logDebug( 3046 "Require header with optionTag 100rel is needed -- adding one"); 3047 } 3048 3049 } 3050 3051 SIPServerTransaction serverTransaction = (SIPServerTransaction) this 3052 .getFirstTransaction(); 3053 /* 3054 * put into the dialog table before sending the response so as to avoid race condition 3055 * with PRACK 3056 */ 3057 this.setLastResponse(serverTransaction, sipResponse); 3058 3059 this.setDialogId(sipResponse.getDialogId(true)); 3060 3061 serverTransaction.sendReliableProvisionalResponse(relResponse); 3062 3063 this.startRetransmitTimer(serverTransaction, relResponse); 3064 3065 } 3066 3067 /* 3068 * (non-Javadoc) 3069 * 3070 * @see javax.sip.Dialog#terminateOnBye(boolean) 3071 */ 3072 public void terminateOnBye(boolean terminateFlag) throws SipException { 3073 3074 this.terminateOnBye = terminateFlag; 3075 } 3076 3077 /** 3078 * Set the "assigned" flag to true. We do this when inserting the dialog into the dialog table 3079 * of the stack. 3080 * 3081 */ 3082 public void setAssigned() { 3083 this.isAssigned = true; 3084 } 3085 3086 /** 3087 * Return true if the dialog has already been mapped to a transaction. 3088 * 3089 */ 3090 3091 public boolean isAssigned() { 3092 return this.isAssigned; 3093 } 3094 3095 /** 3096 * Get the contact header that the owner of this dialog assigned. Subsequent Requests are 3097 * considered to belong to the dialog if the dialog identifier matches and the contact header 3098 * matches the ip address and port on which the request is received. 3099 * 3100 * @return contact header belonging to the dialog. 3101 */ 3102 public Contact getMyContactHeader() { 3103 return contactHeader; 3104 } 3105 3106 /** 3107 * Do the necessary processing to handle an ACK directed at this Dialog. 3108 * 3109 * @param ackTransaction -- the ACK transaction that was directed at this dialog. 3110 * @return -- true if the ACK was successfully consumed by the Dialog and resulted in the 3111 * dialog state being changed. 3112 */ 3113 public boolean handleAck(SIPServerTransaction ackTransaction) { 3114 SIPRequest sipRequest = ackTransaction.getOriginalRequest(); 3115 3116 if (isAckSeen() && getRemoteSeqNumber() == sipRequest.getCSeq().getSeqNumber()) { 3117 3118 if (sipStack.isLoggingEnabled()) { 3119 sipStack.getStackLogger().logDebug( 3120 "ACK already seen by dialog -- dropping Ack" + " retransmission"); 3121 } 3122 acquireTimerTaskSem(); 3123 try { 3124 if (this.timerTask != null) { 3125 this.timerTask.cancel(); 3126 this.timerTask = null; 3127 } 3128 } finally { 3129 releaseTimerTaskSem(); 3130 } 3131 return false; 3132 } else if (this.getState() == DialogState.TERMINATED) { 3133 if (sipStack.isLoggingEnabled()) 3134 sipStack.getStackLogger().logDebug("Dialog is terminated -- dropping ACK"); 3135 return false; 3136 3137 } else { 3138 3139 /* 3140 * This could be a re-invite processing. check to see if the ack matches with the last 3141 * transaction. s 3142 */ 3143 3144 SIPServerTransaction tr = getInviteTransaction(); 3145 3146 SIPResponse sipResponse = (tr != null ? tr.getLastResponse() : null); 3147 3148 // Idiot check for sending ACK from the wrong side! 3149 if (tr != null 3150 && sipResponse != null 3151 && sipResponse.getStatusCode() / 100 == 2 3152 && sipResponse.getCSeq().getMethod().equals(Request.INVITE) 3153 && sipResponse.getCSeq().getSeqNumber() == sipRequest.getCSeq() 3154 .getSeqNumber()) { 3155 3156 ackTransaction.setDialog(this, sipResponse.getDialogId(false)); 3157 /* 3158 * record that we already saw an ACK for this dialog. 3159 */ 3160 3161 ackReceived(sipRequest); 3162 if (sipStack.isLoggingEnabled()) 3163 sipStack.getStackLogger().logDebug("ACK for 2XX response --- sending to TU "); 3164 return true; 3165 3166 } else { 3167 /* 3168 * This happens when the ACK is re-transmitted and arrives too late to be 3169 * processed. 3170 */ 3171 3172 if (sipStack.isLoggingEnabled()) 3173 sipStack.getStackLogger().logDebug( 3174 " INVITE transaction not found -- Discarding ACK"); 3175 return false; 3176 } 3177 } 3178 } 3179 3180 void setEarlyDialogId(String earlyDialogId) { 3181 this.earlyDialogId = earlyDialogId; 3182 } 3183 3184 String getEarlyDialogId() { 3185 return earlyDialogId; 3186 } 3187 3188 /** 3189 * Release the semaphore for ACK processing so the next re-INVITE may proceed. 3190 */ 3191 void releaseAckSem() { 3192 if (this.isBackToBackUserAgent) { 3193 if (sipStack.isLoggingEnabled()) { 3194 sipStack.getStackLogger().logDebug("releaseAckSem]" + this); 3195 } 3196 this.ackSem.release(); 3197 } 3198 3199 } 3200 3201 boolean takeAckSem() { 3202 if (sipStack.isLoggingEnabled()) { 3203 sipStack.getStackLogger().logDebug("[takeAckSem " + this); 3204 } 3205 try { 3206 if (!this.ackSem.tryAcquire(2, TimeUnit.SECONDS)) { 3207 if (sipStack.isLoggingEnabled()) { 3208 sipStack.getStackLogger().logError("Cannot aquire ACK semaphore"); 3209 } 3210 3211 if ( sipStack.isLoggingEnabled() ) { 3212 sipStack.getStackLogger().logDebug("Semaphore previously acquired at " + this.stackTrace); 3213 sipStack.getStackLogger().logStackTrace(); 3214 3215 } 3216 return false; 3217 } 3218 3219 if ( sipStack.isLoggingEnabled() ) { 3220 3221 this.recordStackTrace(); 3222 } 3223 3224 } catch (InterruptedException ex) { 3225 sipStack.getStackLogger().logError("Cannot aquire ACK semaphore"); 3226 return false; 3227 3228 } 3229 return true; 3230 3231 } 3232 3233 /** 3234 * @param lastAckReceived the lastAckReceived to set 3235 */ 3236 private void setLastAckReceived(SIPRequest lastAckReceived) { 3237 this.lastAckReceived = lastAckReceived; 3238 } 3239 3240 /** 3241 * @return the lastAckReceived 3242 */ 3243 protected SIPRequest getLastAckReceived() { 3244 return lastAckReceived; 3245 } 3246 3247 /** 3248 * @param lastAckSent the lastAckSent to set 3249 */ 3250 private void setLastAckSent(SIPRequest lastAckSent) { 3251 this.lastAckSent = lastAckSent; 3252 } 3253 3254 /** 3255 * @return true if an ack was ever sent for this Dialog 3256 */ 3257 public boolean isAtleastOneAckSent() { 3258 return this.isAcknowledged; 3259 } 3260 3261 3262 3263 public boolean isBackToBackUserAgent() { 3264 return this.isBackToBackUserAgent; 3265 } 3266 3267 public synchronized void doDeferredDeleteIfNoAckSent(long seqno) { 3268 if (sipStack.getTimer() == null) { 3269 this.setState(TERMINATED_STATE); 3270 } else if(dialogDeleteIfNoAckSentTask == null){ 3271 // Delete the transaction after the max ack timeout. 3272 dialogDeleteIfNoAckSentTask = new DialogDeleteIfNoAckSentTask(seqno); 3273 sipStack.getTimer().schedule( 3274 dialogDeleteIfNoAckSentTask, 3275 SIPTransaction.TIMER_J 3276 * SIPTransactionStack.BASE_TIMER_INTERVAL); 3277 } 3278 } 3279 3280 /* 3281 * (non-Javadoc) 3282 * @see gov.nist.javax.sip.DialogExt#setBackToBackUserAgent(boolean) 3283 */ 3284 public void setBackToBackUserAgent() { 3285 this.isBackToBackUserAgent = true; 3286 } 3287 3288 /** 3289 * @return the eventHeader 3290 */ 3291 EventHeader getEventHeader() { 3292 return eventHeader; 3293 } 3294 3295 /** 3296 * @param eventHeader the eventHeader to set 3297 */ 3298 void setEventHeader(EventHeader eventHeader) { 3299 this.eventHeader = eventHeader; 3300 } 3301 3302 /** 3303 * @param serverTransactionFlag the serverTransactionFlag to set 3304 */ 3305 void setServerTransactionFlag(boolean serverTransactionFlag) { 3306 this.serverTransactionFlag = serverTransactionFlag; 3307 } 3308 3309 /** 3310 * @param reInviteFlag the reinviteFlag to set 3311 */ 3312 void setReInviteFlag(boolean reInviteFlag) { 3313 this.reInviteFlag = reInviteFlag; 3314 } 3315 3316 3317 public boolean isSequnceNumberValidation() { 3318 return this.sequenceNumberValidation; 3319 } 3320 3321 public void disableSequenceNumberValidation() { 3322 this.sequenceNumberValidation = false; 3323 } 3324 3325 3326 public void acquireTimerTaskSem() { 3327 boolean acquired = false; 3328 try { 3329 acquired = this.timerTaskLock.tryAcquire(10, TimeUnit.SECONDS); 3330 } catch ( InterruptedException ex) { 3331 acquired = false; 3332 } 3333 if(!acquired) { 3334 throw new IllegalStateException("Impossible to acquire the dialog timer task lock"); 3335 } 3336 } 3337 3338 public void releaseTimerTaskSem() { 3339 this.timerTaskLock.release(); 3340 } 3341 3342 3343 } 3344