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 */ 26package gov.nist.javax.sip.stack; 27 28import gov.nist.core.InternalErrorHandler; 29import gov.nist.core.NameValueList; 30import gov.nist.javax.sip.SIPConstants; 31import gov.nist.javax.sip.Utils; 32import gov.nist.javax.sip.address.AddressImpl; 33import gov.nist.javax.sip.header.Contact; 34import gov.nist.javax.sip.header.RecordRoute; 35import gov.nist.javax.sip.header.RecordRouteList; 36import gov.nist.javax.sip.header.Route; 37import gov.nist.javax.sip.header.RouteList; 38import gov.nist.javax.sip.header.TimeStamp; 39import gov.nist.javax.sip.header.To; 40import gov.nist.javax.sip.header.Via; 41import gov.nist.javax.sip.header.ViaList; 42import gov.nist.javax.sip.message.SIPMessage; 43import gov.nist.javax.sip.message.SIPRequest; 44import gov.nist.javax.sip.message.SIPResponse; 45 46import java.io.IOException; 47import java.security.cert.X509Certificate; 48import java.text.ParseException; 49import java.util.ListIterator; 50import java.util.TimerTask; 51import java.util.concurrent.ConcurrentHashMap; 52 53import javax.net.ssl.SSLPeerUnverifiedException; 54import javax.sip.Dialog; 55import javax.sip.DialogState; 56import javax.sip.InvalidArgumentException; 57import javax.sip.ObjectInUseException; 58import javax.sip.SipException; 59import javax.sip.Timeout; 60import javax.sip.TimeoutEvent; 61import javax.sip.TransactionState; 62import javax.sip.address.Hop; 63import javax.sip.address.SipURI; 64import javax.sip.header.ExpiresHeader; 65import javax.sip.header.RouteHeader; 66import javax.sip.header.TimeStampHeader; 67import javax.sip.message.Request; 68 69/* 70 * Jeff Keyser -- initial. Daniel J. Martinez Manzano --Added support for TLS message channel. 71 * Emil Ivov -- bug fixes. Chris Beardshear -- bug fix. Andreas Bystrom -- bug fixes. Matt Keller 72 * (Motorolla) -- bug fix. 73 */ 74 75/** 76 * Represents a client transaction. Implements the following state machines. (From RFC 3261) 77 * 78 * <pre> 79 * 80 * 81 * 82 * 83 * 84 * 85 * |INVITE from TU 86 * Timer A fires |INVITE sent 87 * Reset A, V Timer B fires 88 * INVITE sent +-----------+ or Transport Err. 89 * +---------| |---------------+inform TU 90 * | | Calling | | 91 * +-------->| |-------------->| 92 * +-----------+ 2xx | 93 * | | 2xx to TU | 94 * | |1xx | 95 * 300-699 +---------------+ |1xx to TU | 96 * ACK sent | | | 97 * resp. to TU | 1xx V | 98 * | 1xx to TU -----------+ | 99 * | +---------| | | 100 * | | |Proceeding |-------------->| 101 * | +-------->| | 2xx | 102 * | +-----------+ 2xx to TU | 103 * | 300-699 | | 104 * | ACK sent, | | 105 * | resp. to TU| | 106 * | | | NOTE: 107 * | 300-699 V | 108 * | ACK sent +-----------+Transport Err. | transitions 109 * | +---------| |Inform TU | labeled with 110 * | | | Completed |-------------->| the event 111 * | +-------->| | | over the action 112 * | +-----------+ | to take 113 * | ˆ | | 114 * | | | Timer D fires | 115 * +--------------+ | - | 116 * | | 117 * V | 118 * +-----------+ | 119 * | | | 120 * | Terminated|<--------------+ 121 * | | 122 * +-----------+ 123 * 124 * Figure 5: INVITE client transaction 125 * 126 * 127 * |Request from TU 128 * |send request 129 * Timer E V 130 * send request +-----------+ 131 * +---------| |-------------------+ 132 * | | Trying | Timer F | 133 * +-------->| | or Transport Err.| 134 * +-----------+ inform TU | 135 * 200-699 | | | 136 * resp. to TU | |1xx | 137 * +---------------+ |resp. to TU | 138 * | | | 139 * | Timer E V Timer F | 140 * | send req +-----------+ or Transport Err. | 141 * | +---------| | inform TU | 142 * | | |Proceeding |------------------>| 143 * | +-------->| |-----+ | 144 * | +-----------+ |1xx | 145 * | | ˆ |resp to TU | 146 * | 200-699 | +--------+ | 147 * | resp. to TU | | 148 * | | | 149 * | V | 150 * | +-----------+ | 151 * | | | | 152 * | | Completed | | 153 * | | | | 154 * | +-----------+ | 155 * | ˆ | | 156 * | | | Timer K | 157 * +--------------+ | - | 158 * | | 159 * V | 160 * NOTE: +-----------+ | 161 * | | | 162 * transitions | Terminated|<------------------+ 163 * labeled with | | 164 * the event +-----------+ 165 * over the action 166 * to take 167 * 168 * Figure 6: non-INVITE client transaction 169 * 170 * 171 * 172 * 173 * 174 * 175 * </pre> 176 * 177 * 178 * @author M. Ranganathan 179 * 180 * @version 1.2 $Revision: 1.122 $ $Date: 2009/12/17 23:33:52 $ 181 */ 182public class SIPClientTransaction extends SIPTransaction implements ServerResponseInterface, 183 javax.sip.ClientTransaction, gov.nist.javax.sip.ClientTransactionExt { 184 185 // a SIP Client transaction may belong simultaneously to multiple 186 // dialogs in the early state. These dialogs all have 187 // the same call ID and same From tag but different to tags. 188 189 private ConcurrentHashMap<String,SIPDialog> sipDialogs; 190 191 private SIPRequest lastRequest; 192 193 private int viaPort; 194 195 private String viaHost; 196 197 // Real ResponseInterface to pass messages to 198 private transient ServerResponseInterface respondTo; 199 200 private SIPDialog defaultDialog; 201 202 private Hop nextHop; 203 204 private boolean notifyOnRetransmit; 205 206 private boolean timeoutIfStillInCallingState; 207 208 private int callingStateTimeoutCount; 209 210 public class TransactionTimer extends SIPStackTimerTask { 211 212 public TransactionTimer() { 213 214 } 215 216 protected void runTask() { 217 SIPClientTransaction clientTransaction; 218 SIPTransactionStack sipStack; 219 clientTransaction = SIPClientTransaction.this; 220 sipStack = clientTransaction.sipStack; 221 222 // If the transaction has terminated, 223 if (clientTransaction.isTerminated()) { 224 225 if (sipStack.isLoggingEnabled()) { 226 sipStack.getStackLogger().logDebug( 227 "removing = " + clientTransaction + " isReliable " 228 + clientTransaction.isReliable()); 229 } 230 231 sipStack.removeTransaction(clientTransaction); 232 233 try { 234 this.cancel(); 235 236 } catch (IllegalStateException ex) { 237 if (!sipStack.isAlive()) 238 return; 239 } 240 241 // Client transaction terminated. Kill connection if 242 // this is a TCP after the linger timer has expired. 243 // The linger timer is needed to allow any pending requests to 244 // return responses. 245 if ((!sipStack.cacheClientConnections) && clientTransaction.isReliable()) { 246 247 int newUseCount = --clientTransaction.getMessageChannel().useCount; 248 if (newUseCount <= 0) { 249 // Let the connection linger for a while and then close 250 // it. 251 TimerTask myTimer = new LingerTimer(); 252 sipStack.getTimer().schedule(myTimer, 253 SIPTransactionStack.CONNECTION_LINGER_TIME * 1000); 254 } 255 256 } else { 257 // Cache the client connections so dont close the 258 // connection. This keeps the connection open permanently 259 // until the client disconnects. 260 if (sipStack.isLoggingEnabled() && clientTransaction.isReliable()) { 261 int useCount = clientTransaction.getMessageChannel().useCount; 262 if (sipStack.isLoggingEnabled()) 263 sipStack.getStackLogger().logDebug("Client Use Count = " + useCount); 264 } 265 } 266 267 } else { 268 // If this transaction has not 269 // terminated, 270 // Fire the transaction timer. 271 clientTransaction.fireTimer(); 272 273 } 274 275 } 276 277 } 278 279 /** 280 * Creates a new client transaction. 281 * 282 * @param newSIPStack Transaction stack this transaction belongs to. 283 * @param newChannelToUse Channel to encapsulate. 284 * @return the created client transaction. 285 */ 286 protected SIPClientTransaction(SIPTransactionStack newSIPStack, MessageChannel newChannelToUse) { 287 super(newSIPStack, newChannelToUse); 288 // Create a random branch parameter for this transaction 289 // setBranch( SIPConstants.BRANCH_MAGIC_COOKIE + 290 // Integer.toHexString( hashCode( ) ) ); 291 setBranch(Utils.getInstance().generateBranchId()); 292 this.messageProcessor = newChannelToUse.messageProcessor; 293 this.setEncapsulatedChannel(newChannelToUse); 294 this.notifyOnRetransmit = false; 295 this.timeoutIfStillInCallingState = false; 296 297 // This semaphore guards the listener from being 298 // re-entered for this transaction. That is 299 // for a give tx, the listener is called at most 300 // once with an outstanding request. 301 302 if (sipStack.isLoggingEnabled()) { 303 sipStack.getStackLogger().logDebug("Creating clientTransaction " + this); 304 sipStack.getStackLogger().logStackTrace(); 305 } 306 // this.startTransactionTimer(); 307 this.sipDialogs = new ConcurrentHashMap(); 308 } 309 310 /** 311 * Sets the real ResponseInterface this transaction encapsulates. 312 * 313 * @param newRespondTo ResponseInterface to send messages to. 314 */ 315 public void setResponseInterface(ServerResponseInterface newRespondTo) { 316 if (sipStack.isLoggingEnabled()) { 317 sipStack.getStackLogger().logDebug( 318 "Setting response interface for " + this + " to " + newRespondTo); 319 if (newRespondTo == null) { 320 sipStack.getStackLogger().logStackTrace(); 321 sipStack.getStackLogger().logDebug("WARNING -- setting to null!"); 322 } 323 } 324 325 respondTo = newRespondTo; 326 327 } 328 329 /** 330 * Returns this transaction. 331 */ 332 public MessageChannel getRequestChannel() { 333 334 return this; 335 336 } 337 338 /** 339 * Deterines if the message is a part of this transaction. 340 * 341 * @param messageToTest Message to check if it is part of this transaction. 342 * 343 * @return true if the message is part of this transaction, false if not. 344 */ 345 public boolean isMessagePartOfTransaction(SIPMessage messageToTest) { 346 347 // List of Via headers in the message to test 348 ViaList viaHeaders = messageToTest.getViaHeaders(); 349 // Flags whether the select message is part of this transaction 350 boolean transactionMatches; 351 String messageBranch = ((Via) viaHeaders.getFirst()).getBranch(); 352 boolean rfc3261Compliant = getBranch() != null 353 && messageBranch != null 354 && getBranch().toLowerCase().startsWith( 355 SIPConstants.BRANCH_MAGIC_COOKIE_LOWER_CASE) 356 && messageBranch.toLowerCase().startsWith( 357 SIPConstants.BRANCH_MAGIC_COOKIE_LOWER_CASE); 358 359 transactionMatches = false; 360 if (TransactionState.COMPLETED == this.getState()) { 361 if (rfc3261Compliant) { 362 transactionMatches = getBranch().equalsIgnoreCase( 363 ((Via) viaHeaders.getFirst()).getBranch()) 364 && getMethod().equals(messageToTest.getCSeq().getMethod()); 365 } else { 366 transactionMatches = getBranch().equals(messageToTest.getTransactionId()); 367 } 368 } else if (!isTerminated()) { 369 if (rfc3261Compliant) { 370 if (viaHeaders != null) { 371 // If the branch parameter is the 372 // same as this transaction and the method is the same, 373 if (getBranch().equalsIgnoreCase(((Via) viaHeaders.getFirst()).getBranch())) { 374 transactionMatches = getOriginalRequest().getCSeq().getMethod().equals( 375 messageToTest.getCSeq().getMethod()); 376 377 } 378 } 379 } else { 380 // not RFC 3261 compliant. 381 if (getBranch() != null) { 382 transactionMatches = getBranch().equalsIgnoreCase( 383 messageToTest.getTransactionId()); 384 } else { 385 transactionMatches = getOriginalRequest().getTransactionId() 386 .equalsIgnoreCase(messageToTest.getTransactionId()); 387 } 388 389 } 390 391 } 392 return transactionMatches; 393 394 } 395 396 /** 397 * Send a request message through this transaction and onto the client. 398 * 399 * @param messageToSend Request to process and send. 400 */ 401 public void sendMessage(SIPMessage messageToSend) throws IOException { 402 403 try { 404 // Message typecast as a request 405 SIPRequest transactionRequest; 406 407 transactionRequest = (SIPRequest) messageToSend; 408 409 // Set the branch id for the top via header. 410 Via topVia = (Via) transactionRequest.getViaHeaders().getFirst(); 411 // Tack on a branch identifier to match responses. 412 try { 413 topVia.setBranch(getBranch()); 414 } catch (java.text.ParseException ex) { 415 } 416 417 if (sipStack.isLoggingEnabled()) { 418 sipStack.getStackLogger().logDebug("Sending Message " + messageToSend); 419 sipStack.getStackLogger().logDebug("TransactionState " + this.getState()); 420 } 421 // If this is the first request for this transaction, 422 if (TransactionState.PROCEEDING == getState() 423 || TransactionState.CALLING == getState()) { 424 425 // If this is a TU-generated ACK request, 426 if (transactionRequest.getMethod().equals(Request.ACK)) { 427 428 // Send directly to the underlying 429 // transport and close this transaction 430 if (isReliable()) { 431 this.setState(TransactionState.TERMINATED); 432 } else { 433 this.setState(TransactionState.COMPLETED); 434 } 435 // BUGBUG -- This suppresses sending the ACK uncomment this 436 // to 437 // test 4xx retransmission 438 // if (transactionRequest.getMethod() != Request.ACK) 439 super.sendMessage(transactionRequest); 440 return; 441 442 } 443 444 } 445 try { 446 447 // Send the message to the server 448 lastRequest = transactionRequest; 449 if (getState() == null) { 450 // Save this request as the one this transaction 451 // is handling 452 setOriginalRequest(transactionRequest); 453 // Change to trying/calling state 454 // Set state first to avoid race condition.. 455 456 if (transactionRequest.getMethod().equals(Request.INVITE)) { 457 this.setState(TransactionState.CALLING); 458 } else if (transactionRequest.getMethod().equals(Request.ACK)) { 459 // Acks are never retransmitted. 460 this.setState(TransactionState.TERMINATED); 461 } else { 462 this.setState(TransactionState.TRYING); 463 } 464 if (!isReliable()) { 465 enableRetransmissionTimer(); 466 } 467 if (isInviteTransaction()) { 468 enableTimeoutTimer(TIMER_B); 469 } else { 470 enableTimeoutTimer(TIMER_F); 471 } 472 } 473 // BUGBUG This supresses sending ACKS -- uncomment to test 474 // 4xx retransmission. 475 // if (transactionRequest.getMethod() != Request.ACK) 476 super.sendMessage(transactionRequest); 477 478 } catch (IOException e) { 479 480 this.setState(TransactionState.TERMINATED); 481 throw e; 482 483 } 484 } finally { 485 this.isMapped = true; 486 this.startTransactionTimer(); 487 488 } 489 490 } 491 492 /** 493 * Process a new response message through this transaction. If necessary, this message will 494 * also be passed onto the TU. 495 * 496 * @param transactionResponse Response to process. 497 * @param sourceChannel Channel that received this message. 498 */ 499 public synchronized void processResponse(SIPResponse transactionResponse, 500 MessageChannel sourceChannel, SIPDialog dialog) { 501 502 // If the state has not yet been assigned then this is a 503 // spurious response. 504 505 if (getState() == null) 506 return; 507 508 // Ignore 1xx 509 if ((TransactionState.COMPLETED == this.getState() || TransactionState.TERMINATED == this 510 .getState()) 511 && transactionResponse.getStatusCode() / 100 == 1) { 512 return; 513 } 514 515 if (sipStack.isLoggingEnabled()) { 516 sipStack.getStackLogger().logDebug( 517 "processing " + transactionResponse.getFirstLine() + "current state = " 518 + getState()); 519 sipStack.getStackLogger().logDebug("dialog = " + dialog); 520 } 521 522 this.lastResponse = transactionResponse; 523 524 /* 525 * JvB: this is now duplicate with code in the other processResponse 526 * 527 * if (dialog != null && transactionResponse.getStatusCode() != 100 && 528 * (transactionResponse.getTo().getTag() != null || sipStack .isRfc2543Supported())) { // 529 * add the route before you process the response. dialog.setLastResponse(this, 530 * transactionResponse); this.setDialog(dialog, transactionResponse.getDialogId(false)); } 531 */ 532 533 try { 534 if (isInviteTransaction()) 535 inviteClientTransaction(transactionResponse, sourceChannel, dialog); 536 else 537 nonInviteClientTransaction(transactionResponse, sourceChannel, dialog); 538 } catch (IOException ex) { 539 if (sipStack.isLoggingEnabled()) 540 sipStack.getStackLogger().logException(ex); 541 this.setState(TransactionState.TERMINATED); 542 raiseErrorEvent(SIPTransactionErrorEvent.TRANSPORT_ERROR); 543 } 544 } 545 546 /** 547 * Implements the state machine for invite client transactions. 548 * 549 * <pre> 550 * 551 * 552 * 553 * 554 * 555 * |Request from TU 556 * |send request 557 * Timer E V 558 * send request +-----------+ 559 * +---------| |-------------------+ 560 * | | Trying | Timer F | 561 * +-------->| | or Transport Err.| 562 * +-----------+ inform TU | 563 * 200-699 | | | 564 * resp. to TU | |1xx | 565 * +---------------+ |resp. to TU | 566 * | | | 567 * | Timer E V Timer F | 568 * | send req +-----------+ or Transport Err. | 569 * | +---------| | inform TU | 570 * | | |Proceeding |------------------>| 571 * | +-------->| |-----+ | 572 * | +-----------+ |1xx | 573 * | | ˆ |resp to TU | 574 * | 200-699 | +--------+ | 575 * | resp. to TU | | 576 * | | | 577 * | V | 578 * | +-----------+ | 579 * | | | | 580 * | | Completed | | 581 * | | | | 582 * | +-----------+ | 583 * | ˆ | | 584 * | | | Timer K | 585 * +--------------+ | - | 586 * | | 587 * V | 588 * NOTE: +-----------+ | 589 * | | | 590 * transitions | Terminated|<------------------+ 591 * labeled with | | 592 * the event +-----------+ 593 * over the action 594 * to take 595 * 596 * Figure 6: non-INVITE client transaction 597 * 598 * 599 * 600 * 601 * </pre> 602 * 603 * @param transactionResponse -- transaction response received. 604 * @param sourceChannel - source channel on which the response was received. 605 */ 606 private void nonInviteClientTransaction(SIPResponse transactionResponse, 607 MessageChannel sourceChannel, SIPDialog sipDialog) throws IOException { 608 int statusCode = transactionResponse.getStatusCode(); 609 if (TransactionState.TRYING == this.getState()) { 610 if (statusCode / 100 == 1) { 611 this.setState(TransactionState.PROCEEDING); 612 enableRetransmissionTimer(MAXIMUM_RETRANSMISSION_TICK_COUNT); 613 enableTimeoutTimer(TIMER_F); 614 // According to RFC, the TU has to be informed on 615 // this transition. 616 if (respondTo != null) { 617 respondTo.processResponse(transactionResponse, this, sipDialog); 618 } else { 619 this.semRelease(); 620 } 621 } else if (200 <= statusCode && statusCode <= 699) { 622 // Send the response up to the TU. 623 if (respondTo != null) { 624 respondTo.processResponse(transactionResponse, this, sipDialog); 625 } else { 626 this.semRelease(); 627 } 628 if (!isReliable()) { 629 this.setState(TransactionState.COMPLETED); 630 enableTimeoutTimer(TIMER_K); 631 } else { 632 this.setState(TransactionState.TERMINATED); 633 } 634 } 635 } else if (TransactionState.PROCEEDING == this.getState()) { 636 if (statusCode / 100 == 1) { 637 if (respondTo != null) { 638 respondTo.processResponse(transactionResponse, this, sipDialog); 639 } else { 640 this.semRelease(); 641 } 642 } else if (200 <= statusCode && statusCode <= 699) { 643 if (respondTo != null) { 644 respondTo.processResponse(transactionResponse, this, sipDialog); 645 } else { 646 this.semRelease(); 647 } 648 disableRetransmissionTimer(); 649 disableTimeoutTimer(); 650 if (!isReliable()) { 651 this.setState(TransactionState.COMPLETED); 652 enableTimeoutTimer(TIMER_K); 653 } else { 654 this.setState(TransactionState.TERMINATED); 655 } 656 } 657 } else { 658 if (sipStack.isLoggingEnabled()) { 659 sipStack.getStackLogger().logDebug( 660 " Not sending response to TU! " + getState()); 661 } 662 this.semRelease(); 663 } 664 } 665 666 /** 667 * Implements the state machine for invite client transactions. 668 * 669 * <pre> 670 * 671 * 672 * 673 * 674 * 675 * |INVITE from TU 676 * Timer A fires |INVITE sent 677 * Reset A, V Timer B fires 678 * INVITE sent +-----------+ or Transport Err. 679 * +---------| |---------------+inform TU 680 * | | Calling | | 681 * +-------->| |-------------->| 682 * +-----------+ 2xx | 683 * | | 2xx to TU | 684 * | |1xx | 685 * 300-699 +---------------+ |1xx to TU | 686 * ACK sent | | | 687 * resp. to TU | 1xx V | 688 * | 1xx to TU -----------+ | 689 * | +---------| | | 690 * | | |Proceeding |-------------->| 691 * | +-------->| | 2xx | 692 * | +-----------+ 2xx to TU | 693 * | 300-699 | | 694 * | ACK sent, | | 695 * | resp. to TU| | 696 * | | | NOTE: 697 * | 300-699 V | 698 * | ACK sent +-----------+Transport Err. | transitions 699 * | +---------| |Inform TU | labeled with 700 * | | | Completed |-------------->| the event 701 * | +-------->| | | over the action 702 * | +-----------+ | to take 703 * | ˆ | | 704 * | | | Timer D fires | 705 * +--------------+ | - | 706 * | | 707 * V | 708 * +-----------+ | 709 * | | | 710 * | Terminated|<--------------+ 711 * | | 712 * +-----------+ 713 * 714 * 715 * 716 * 717 * </pre> 718 * 719 * @param transactionResponse -- transaction response received. 720 * @param sourceChannel - source channel on which the response was received. 721 */ 722 723 private void inviteClientTransaction(SIPResponse transactionResponse, 724 MessageChannel sourceChannel, SIPDialog dialog) throws IOException { 725 int statusCode = transactionResponse.getStatusCode(); 726 727 if (TransactionState.TERMINATED == this.getState()) { 728 boolean ackAlreadySent = false; 729 if (dialog != null && dialog.isAckSeen() && dialog.getLastAckSent() != null) { 730 if (dialog.getLastAckSent().getCSeq().getSeqNumber() == transactionResponse.getCSeq() 731 .getSeqNumber() 732 && transactionResponse.getFromTag().equals( 733 dialog.getLastAckSent().getFromTag())) { 734 // the last ack sent corresponded to this response 735 ackAlreadySent = true; 736 } 737 } 738 // retransmit the ACK for this response. 739 if (dialog!= null && ackAlreadySent 740 && transactionResponse.getCSeq().getMethod().equals(dialog.getMethod())) { 741 try { 742 // Found the dialog - resend the ACK and 743 // dont pass up the null transaction 744 if (sipStack.isLoggingEnabled()) 745 sipStack.getStackLogger().logDebug("resending ACK"); 746 747 dialog.resendAck(); 748 } catch (SipException ex) { 749 // What to do here ?? kill the dialog? 750 } 751 } 752 753 this.semRelease(); 754 return; 755 } else if (TransactionState.CALLING == this.getState()) { 756 if (statusCode / 100 == 2) { 757 758 // JvB: do this ~before~ calling the application, to avoid 759 // retransmissions 760 // of the INVITE after app sends ACK 761 disableRetransmissionTimer(); 762 disableTimeoutTimer(); 763 this.setState(TransactionState.TERMINATED); 764 765 // 200 responses are always seen by TU. 766 if (respondTo != null) 767 respondTo.processResponse(transactionResponse, this, dialog); 768 else { 769 this.semRelease(); 770 } 771 772 } else if (statusCode / 100 == 1) { 773 disableRetransmissionTimer(); 774 disableTimeoutTimer(); 775 this.setState(TransactionState.PROCEEDING); 776 777 if (respondTo != null) 778 respondTo.processResponse(transactionResponse, this, dialog); 779 else { 780 this.semRelease(); 781 } 782 783 } else if (300 <= statusCode && statusCode <= 699) { 784 // Send back an ACK request 785 786 try { 787 sendMessage((SIPRequest) createErrorAck()); 788 789 } catch (Exception ex) { 790 sipStack.getStackLogger().logError( 791 "Unexpected Exception sending ACK -- sending error AcK ", ex); 792 793 } 794 795 /* 796 * When in either the "Calling" or "Proceeding" states, reception of response with 797 * status code from 300-699 MUST cause the client transaction to transition to 798 * "Completed". The client transaction MUST pass the received response up to the 799 * TU, and the client transaction MUST generate an ACK request. 800 */ 801 802 if (respondTo != null) { 803 respondTo.processResponse(transactionResponse, this, dialog); 804 } else { 805 this.semRelease(); 806 } 807 808 if (this.getDialog() != null && ((SIPDialog)this.getDialog()).isBackToBackUserAgent()) { 809 ((SIPDialog) this.getDialog()).releaseAckSem(); 810 } 811 812 if (!isReliable()) { 813 this.setState(TransactionState.COMPLETED); 814 enableTimeoutTimer(TIMER_D); 815 } else { 816 // Proceed immediately to the TERMINATED state. 817 this.setState(TransactionState.TERMINATED); 818 } 819 } 820 } else if (TransactionState.PROCEEDING == this.getState()) { 821 if (statusCode / 100 == 1) { 822 if (respondTo != null) { 823 respondTo.processResponse(transactionResponse, this, dialog); 824 } else { 825 this.semRelease(); 826 } 827 } else if (statusCode / 100 == 2) { 828 this.setState(TransactionState.TERMINATED); 829 if (respondTo != null) { 830 respondTo.processResponse(transactionResponse, this, dialog); 831 } else { 832 this.semRelease(); 833 } 834 835 } else if (300 <= statusCode && statusCode <= 699) { 836 // Send back an ACK request 837 try { 838 sendMessage((SIPRequest) createErrorAck()); 839 } catch (Exception ex) { 840 InternalErrorHandler.handleException(ex); 841 } 842 843 if (this.getDialog() != null) { 844 ((SIPDialog) this.getDialog()).releaseAckSem(); 845 } 846 // JvB: update state before passing to app 847 if (!isReliable()) { 848 this.setState(TransactionState.COMPLETED); 849 this.enableTimeoutTimer(TIMER_D); 850 } else { 851 this.setState(TransactionState.TERMINATED); 852 } 853 854 // Pass up to the TU for processing. 855 if (respondTo != null) 856 respondTo.processResponse(transactionResponse, this, dialog); 857 else { 858 this.semRelease(); 859 } 860 861 // JvB: duplicate with line 874 862 // if (!isReliable()) { 863 // enableTimeoutTimer(TIMER_D); 864 // } 865 } 866 } else if (TransactionState.COMPLETED == this.getState()) { 867 if (300 <= statusCode && statusCode <= 699) { 868 // Send back an ACK request 869 try { 870 sendMessage((SIPRequest) createErrorAck()); 871 } catch (Exception ex) { 872 InternalErrorHandler.handleException(ex); 873 } finally { 874 this.semRelease(); 875 } 876 } 877 878 } 879 880 } 881 882 /* 883 * (non-Javadoc) 884 * 885 * @see javax.sip.ClientTransaction#sendRequest() 886 */ 887 public void sendRequest() throws SipException { 888 SIPRequest sipRequest = this.getOriginalRequest(); 889 890 if (this.getState() != null) 891 throw new SipException("Request already sent"); 892 893 if (sipStack.isLoggingEnabled()) { 894 sipStack.getStackLogger().logDebug("sendRequest() " + sipRequest); 895 } 896 897 try { 898 sipRequest.checkHeaders(); 899 } catch (ParseException ex) { 900 if (sipStack.isLoggingEnabled()) 901 sipStack.getStackLogger().logError("missing required header"); 902 throw new SipException(ex.getMessage()); 903 } 904 905 if (getMethod().equals(Request.SUBSCRIBE) 906 && sipRequest.getHeader(ExpiresHeader.NAME) == null) { 907 /* 908 * If no "Expires" header is present in a SUBSCRIBE request, the implied default is 909 * defined by the event package being used. 910 * 911 */ 912 if (sipStack.isLoggingEnabled()) 913 sipStack.getStackLogger().logWarning( 914 "Expires header missing in outgoing subscribe --" 915 + " Notifier will assume implied value on event package"); 916 } 917 try { 918 /* 919 * This check is removed because it causes problems for load balancers ( See issue 920 * 136) reported by Raghav Ramesh ( BT ) 921 * 922 */ 923 if (this.getOriginalRequest().getMethod().equals(Request.CANCEL) 924 && sipStack.isCancelClientTransactionChecked()) { 925 SIPClientTransaction ct = (SIPClientTransaction) sipStack.findCancelTransaction( 926 this.getOriginalRequest(), false); 927 if (ct == null) { 928 /* 929 * If the original request has generated a final response, the CANCEL SHOULD 930 * NOT be sent, as it is an effective no-op, since CANCEL has no effect on 931 * requests that have already generated a final response. 932 */ 933 throw new SipException("Could not find original tx to cancel. RFC 3261 9.1"); 934 } else if (ct.getState() == null) { 935 throw new SipException( 936 "State is null no provisional response yet -- cannot cancel RFC 3261 9.1"); 937 } else if (!ct.getMethod().equals(Request.INVITE)) { 938 throw new SipException("Cannot cancel non-invite requests RFC 3261 9.1"); 939 } 940 } else 941 942 if (this.getOriginalRequest().getMethod().equals(Request.BYE) 943 || this.getOriginalRequest().getMethod().equals(Request.NOTIFY)) { 944 SIPDialog dialog = sipStack.getDialog(this.getOriginalRequest() 945 .getDialogId(false)); 946 // I want to behave like a user agent so send the BYE using the 947 // Dialog 948 if (this.getSipProvider().isAutomaticDialogSupportEnabled() && dialog != null) { 949 throw new SipException( 950 "Dialog is present and AutomaticDialogSupport is enabled for " 951 + " the provider -- Send the Request using the Dialog.sendRequest(transaction)"); 952 } 953 } 954 // Only map this after the fist request is sent out. 955 if (this.getMethod().equals(Request.INVITE)) { 956 SIPDialog dialog = this.getDefaultDialog(); 957 958 if (dialog != null && dialog.isBackToBackUserAgent()) { 959 // Block sending re-INVITE till we see the ACK. 960 if ( ! dialog.takeAckSem() ) { 961 throw new SipException ("Failed to take ACK semaphore"); 962 } 963 964 } 965 } 966 this.isMapped = true; 967 this.sendMessage(sipRequest); 968 969 } catch (IOException ex) { 970 this.setState(TransactionState.TERMINATED); 971 throw new SipException("IO Error sending request", ex); 972 973 } 974 975 } 976 977 /** 978 * Called by the transaction stack when a retransmission timer fires. 979 */ 980 protected void fireRetransmissionTimer() { 981 982 try { 983 984 // Resend the last request sent 985 if (this.getState() == null || !this.isMapped) 986 return; 987 988 boolean inv = isInviteTransaction(); 989 TransactionState s = this.getState(); 990 991 // JvB: INVITE CTs only retransmit in CALLING, non-INVITE in both TRYING and 992 // PROCEEDING 993 // Bug-fix for non-INVITE transactions not retransmitted when 1xx response received 994 if ((inv && TransactionState.CALLING == s) 995 || (!inv && (TransactionState.TRYING == s || TransactionState.PROCEEDING == s))) { 996 // If the retransmission filter is disabled then 997 // retransmission of the INVITE is the application 998 // responsibility. 999 1000 if (lastRequest != null) { 1001 if (sipStack.generateTimeStampHeader 1002 && lastRequest.getHeader(TimeStampHeader.NAME) != null) { 1003 long milisec = System.currentTimeMillis(); 1004 TimeStamp timeStamp = new TimeStamp(); 1005 try { 1006 timeStamp.setTimeStamp(milisec); 1007 } catch (InvalidArgumentException ex) { 1008 InternalErrorHandler.handleException(ex); 1009 } 1010 lastRequest.setHeader(timeStamp); 1011 } 1012 super.sendMessage(lastRequest); 1013 if (this.notifyOnRetransmit) { 1014 TimeoutEvent txTimeout = new TimeoutEvent(this.getSipProvider(), this, 1015 Timeout.RETRANSMIT); 1016 this.getSipProvider().handleEvent(txTimeout, this); 1017 } 1018 if (this.timeoutIfStillInCallingState 1019 && this.getState() == TransactionState.CALLING) { 1020 this.callingStateTimeoutCount--; 1021 if (callingStateTimeoutCount == 0) { 1022 TimeoutEvent timeoutEvent = new TimeoutEvent(this.getSipProvider(), 1023 this, Timeout.RETRANSMIT); 1024 this.getSipProvider().handleEvent(timeoutEvent, this); 1025 this.timeoutIfStillInCallingState = false; 1026 } 1027 1028 } 1029 } 1030 1031 } 1032 } catch (IOException e) { 1033 this.raiseIOExceptionEvent(); 1034 raiseErrorEvent(SIPTransactionErrorEvent.TRANSPORT_ERROR); 1035 } 1036 1037 } 1038 1039 /** 1040 * Called by the transaction stack when a timeout timer fires. 1041 */ 1042 protected void fireTimeoutTimer() { 1043 1044 if (sipStack.isLoggingEnabled()) 1045 sipStack.getStackLogger().logDebug("fireTimeoutTimer " + this); 1046 1047 SIPDialog dialog = (SIPDialog) this.getDialog(); 1048 if (TransactionState.CALLING == this.getState() 1049 || TransactionState.TRYING == this.getState() 1050 || TransactionState.PROCEEDING == this.getState()) { 1051 // Timeout occured. If this is asociated with a transaction 1052 // creation then kill the dialog. 1053 if (dialog != null 1054 && (dialog.getState() == null || dialog.getState() == DialogState.EARLY)) { 1055 if (((SIPTransactionStack) getSIPStack()).isDialogCreated(this 1056 .getOriginalRequest().getMethod())) { 1057 // If this is a re-invite we do not delete the dialog even 1058 // if the 1059 // reinvite times out. Else 1060 // terminate the enclosing dialog. 1061 dialog.delete(); 1062 } 1063 } else if (dialog != null) { 1064 // Guard against the case of BYE time out. 1065 1066 if (getOriginalRequest().getMethod().equalsIgnoreCase(Request.BYE) 1067 && dialog.isTerminatedOnBye()) { 1068 // Terminate the associated dialog on BYE Timeout. 1069 dialog.delete(); 1070 } 1071 } 1072 } 1073 if (TransactionState.COMPLETED != this.getState()) { 1074 raiseErrorEvent(SIPTransactionErrorEvent.TIMEOUT_ERROR); 1075 // Got a timeout error on a cancel. 1076 if (this.getOriginalRequest().getMethod().equalsIgnoreCase(Request.CANCEL)) { 1077 SIPClientTransaction inviteTx = (SIPClientTransaction) this.getOriginalRequest() 1078 .getInviteTransaction(); 1079 if (inviteTx != null 1080 && ((inviteTx.getState() == TransactionState.CALLING || inviteTx 1081 .getState() == TransactionState.PROCEEDING)) 1082 && inviteTx.getDialog() != null) { 1083 /* 1084 * A proxy server should have started TIMER C and take care of the Termination 1085 * using transaction.terminate() by itself (i.e. this is not the job of the 1086 * stack at this point but we do it to be nice. 1087 */ 1088 inviteTx.setState(TransactionState.TERMINATED); 1089 1090 } 1091 } 1092 1093 } else { 1094 this.setState(TransactionState.TERMINATED); 1095 } 1096 1097 } 1098 1099 /* 1100 * (non-Javadoc) 1101 * 1102 * @see javax.sip.ClientTransaction#createCancel() 1103 */ 1104 public Request createCancel() throws SipException { 1105 SIPRequest originalRequest = this.getOriginalRequest(); 1106 if (originalRequest == null) 1107 throw new SipException("Bad state " + getState()); 1108 if (!originalRequest.getMethod().equals(Request.INVITE)) 1109 throw new SipException("Only INIVTE may be cancelled"); 1110 1111 if (originalRequest.getMethod().equalsIgnoreCase(Request.ACK)) 1112 throw new SipException("Cannot Cancel ACK!"); 1113 else { 1114 SIPRequest cancelRequest = originalRequest.createCancelRequest(); 1115 cancelRequest.setInviteTransaction(this); 1116 return cancelRequest; 1117 } 1118 } 1119 1120 /* 1121 * (non-Javadoc) 1122 * 1123 * @see javax.sip.ClientTransaction#createAck() 1124 */ 1125 public Request createAck() throws SipException { 1126 SIPRequest originalRequest = this.getOriginalRequest(); 1127 if (originalRequest == null) 1128 throw new SipException("bad state " + getState()); 1129 if (getMethod().equalsIgnoreCase(Request.ACK)) { 1130 throw new SipException("Cannot ACK an ACK!"); 1131 } else if (lastResponse == null) { 1132 throw new SipException("bad Transaction state"); 1133 } else if (lastResponse.getStatusCode() < 200) { 1134 if (sipStack.isLoggingEnabled()) { 1135 sipStack.getStackLogger().logDebug("lastResponse = " + lastResponse); 1136 } 1137 throw new SipException("Cannot ACK a provisional response!"); 1138 } 1139 SIPRequest ackRequest = originalRequest.createAckRequest((To) lastResponse.getTo()); 1140 // Pull the record route headers from the last reesponse. 1141 RecordRouteList recordRouteList = lastResponse.getRecordRouteHeaders(); 1142 if (recordRouteList == null) { 1143 // If the record route list is null then we can 1144 // construct the ACK from the specified contact header. 1145 // Note the 3xx check here because 3xx is a redirect. 1146 // The contact header for the 3xx is the redirected 1147 // location so we cannot use that to construct the 1148 // request URI. 1149 if (lastResponse.getContactHeaders() != null 1150 && lastResponse.getStatusCode() / 100 != 3) { 1151 Contact contact = (Contact) lastResponse.getContactHeaders().getFirst(); 1152 javax.sip.address.URI uri = (javax.sip.address.URI) contact.getAddress().getURI() 1153 .clone(); 1154 ackRequest.setRequestURI(uri); 1155 } 1156 return ackRequest; 1157 } 1158 1159 ackRequest.removeHeader(RouteHeader.NAME); 1160 RouteList routeList = new RouteList(); 1161 // start at the end of the list and walk backwards 1162 ListIterator<RecordRoute> li = recordRouteList.listIterator(recordRouteList.size()); 1163 while (li.hasPrevious()) { 1164 RecordRoute rr = (RecordRoute) li.previous(); 1165 1166 Route route = new Route(); 1167 route.setAddress((AddressImpl) ((AddressImpl) rr.getAddress()).clone()); 1168 route.setParameters((NameValueList) rr.getParameters().clone()); 1169 routeList.add(route); 1170 } 1171 1172 Contact contact = null; 1173 if (lastResponse.getContactHeaders() != null) { 1174 contact = (Contact) lastResponse.getContactHeaders().getFirst(); 1175 } 1176 1177 if (!((SipURI) ((Route) routeList.getFirst()).getAddress().getURI()).hasLrParam()) { 1178 1179 // Contact may not yet be there (bug reported by Andreas B). 1180 1181 Route route = null; 1182 if (contact != null) { 1183 route = new Route(); 1184 route.setAddress((AddressImpl) ((AddressImpl) (contact.getAddress())).clone()); 1185 } 1186 1187 Route firstRoute = (Route) routeList.getFirst(); 1188 routeList.removeFirst(); 1189 javax.sip.address.URI uri = firstRoute.getAddress().getURI(); 1190 ackRequest.setRequestURI(uri); 1191 1192 if (route != null) 1193 routeList.add(route); 1194 1195 ackRequest.addHeader(routeList); 1196 } else { 1197 if (contact != null) { 1198 javax.sip.address.URI uri = (javax.sip.address.URI) contact.getAddress().getURI() 1199 .clone(); 1200 ackRequest.setRequestURI(uri); 1201 ackRequest.addHeader(routeList); 1202 } 1203 } 1204 return ackRequest; 1205 1206 } 1207 1208 /* 1209 * Creates an ACK for an error response, according to RFC3261 section 17.1.1.3 1210 * 1211 * Note that this is different from an ACK for 2xx 1212 */ 1213 private final Request createErrorAck() throws SipException, ParseException { 1214 SIPRequest originalRequest = this.getOriginalRequest(); 1215 if (originalRequest == null) 1216 throw new SipException("bad state " + getState()); 1217 if (!getMethod().equals(Request.INVITE)) { 1218 throw new SipException("Can only ACK an INVITE!"); 1219 } else if (lastResponse == null) { 1220 throw new SipException("bad Transaction state"); 1221 } else if (lastResponse.getStatusCode() < 200) { 1222 if (sipStack.isLoggingEnabled()) { 1223 sipStack.getStackLogger().logDebug("lastResponse = " + lastResponse); 1224 } 1225 throw new SipException("Cannot ACK a provisional response!"); 1226 } 1227 return originalRequest.createErrorAck((To) lastResponse.getTo()); 1228 } 1229 1230 /** 1231 * Set the port of the recipient. 1232 */ 1233 protected void setViaPort(int port) { 1234 this.viaPort = port; 1235 } 1236 1237 /** 1238 * Set the port of the recipient. 1239 */ 1240 protected void setViaHost(String host) { 1241 this.viaHost = host; 1242 } 1243 1244 /** 1245 * Get the port of the recipient. 1246 */ 1247 public int getViaPort() { 1248 return this.viaPort; 1249 } 1250 1251 /** 1252 * Get the host of the recipient. 1253 */ 1254 public String getViaHost() { 1255 return this.viaHost; 1256 } 1257 1258 /** 1259 * get the via header for an outgoing request. 1260 */ 1261 public Via getOutgoingViaHeader() { 1262 return this.getMessageProcessor().getViaHeader(); 1263 } 1264 1265 /** 1266 * This is called by the stack after a non-invite client transaction goes to completed state. 1267 */ 1268 public void clearState() { 1269 // reduce the state to minimum 1270 // This assumes that the application will not need 1271 // to access the request once the transaction is 1272 // completed. 1273 // TODO -- revisit this - results in a null pointer 1274 // occuring occasionally. 1275 // this.lastRequest = null; 1276 // this.originalRequest = null; 1277 // this.lastResponse = null; 1278 } 1279 1280 /** 1281 * Sets a timeout after which the connection is closed (provided the server does not use the 1282 * connection for outgoing requests in this time period) and calls the superclass to set 1283 * state. 1284 */ 1285 public void setState(TransactionState newState) { 1286 // Set this timer for connection caching 1287 // of incoming connections. 1288 if (newState == TransactionState.TERMINATED && this.isReliable() 1289 && (!getSIPStack().cacheClientConnections)) { 1290 // Set a time after which the connection 1291 // is closed. 1292 this.collectionTime = TIMER_J; 1293 1294 } 1295 if (super.getState() != TransactionState.COMPLETED 1296 && (newState == TransactionState.COMPLETED || newState == TransactionState.TERMINATED)) { 1297 sipStack.decrementActiveClientTransactionCount(); 1298 } 1299 super.setState(newState); 1300 } 1301 1302 /** 1303 * Start the timer task. 1304 */ 1305 protected void startTransactionTimer() { 1306 if (this.transactionTimerStarted.compareAndSet(false, true)) { 1307 TimerTask myTimer = new TransactionTimer(); 1308 if ( sipStack.getTimer() != null ) { 1309 sipStack.getTimer().schedule(myTimer, BASE_TIMER_INTERVAL, BASE_TIMER_INTERVAL); 1310 } 1311 } 1312 } 1313 1314 /* 1315 * Terminate a transaction. This marks the tx as terminated The tx scanner will run and remove 1316 * the tx. (non-Javadoc) 1317 * 1318 * @see javax.sip.Transaction#terminate() 1319 */ 1320 public void terminate() throws ObjectInUseException { 1321 this.setState(TransactionState.TERMINATED); 1322 1323 } 1324 1325 /** 1326 * Check if the From tag of the response matches the from tag of the original message. A 1327 * Response with a tag mismatch should be dropped if a Dialog has been created for the 1328 * original request. 1329 * 1330 * @param sipResponse the response to check. 1331 * @return true if the check passes. 1332 */ 1333 public boolean checkFromTag(SIPResponse sipResponse) { 1334 String originalFromTag = ((SIPRequest) this.getRequest()).getFromTag(); 1335 if (this.defaultDialog != null) { 1336 if (originalFromTag == null ^ sipResponse.getFrom().getTag() == null) { 1337 if (sipStack.isLoggingEnabled()) 1338 sipStack.getStackLogger().logDebug("From tag mismatch -- dropping response"); 1339 return false; 1340 } 1341 if (originalFromTag != null 1342 && !originalFromTag.equalsIgnoreCase(sipResponse.getFrom().getTag())) { 1343 if (sipStack.isLoggingEnabled()) 1344 sipStack.getStackLogger().logDebug("From tag mismatch -- dropping response"); 1345 return false; 1346 } 1347 } 1348 return true; 1349 1350 } 1351 1352 /* 1353 * (non-Javadoc) 1354 * 1355 * @see gov.nist.javax.sip.stack.ServerResponseInterface#processResponse(gov.nist.javax.sip.message.SIPResponse, 1356 * gov.nist.javax.sip.stack.MessageChannel) 1357 */ 1358 public void processResponse(SIPResponse sipResponse, MessageChannel incomingChannel) { 1359 1360 // If a dialog has already been created for this response, 1361 // pass it up. 1362 SIPDialog dialog = null; 1363 String method = sipResponse.getCSeq().getMethod(); 1364 String dialogId = sipResponse.getDialogId(false); 1365 if (method.equals(Request.CANCEL) && lastRequest != null) { 1366 // JvB for CANCEL: use invite CT in CANCEL request to get dialog 1367 // (instead of stripping tag) 1368 SIPClientTransaction ict = (SIPClientTransaction) lastRequest.getInviteTransaction(); 1369 if (ict != null) { 1370 dialog = ict.defaultDialog; 1371 } 1372 } else { 1373 dialog = this.getDialog(dialogId); 1374 } 1375 1376 // JvB: Check all conditions required for creating a new Dialog 1377 if (dialog == null) { 1378 int code = sipResponse.getStatusCode(); 1379 if ((code > 100 && code < 300) 1380 /* skip 100 (may have a to tag */ 1381 && (sipResponse.getToTag() != null || sipStack.isRfc2543Supported()) 1382 && sipStack.isDialogCreated(method)) { 1383 1384 /* 1385 * Dialog cannot be found for the response. This must be a forked response. no 1386 * dialog assigned to this response but a default dialog has been assigned. Note 1387 * that if automatic dialog support is configured then a default dialog is always 1388 * created. 1389 */ 1390 1391 synchronized (this) { 1392 /* 1393 * We need synchronization here because two responses may compete for the 1394 * default dialog simultaneously 1395 */ 1396 if (defaultDialog != null) { 1397 if (sipResponse.getFromTag() != null) { 1398 SIPResponse dialogResponse = defaultDialog.getLastResponse(); 1399 String defaultDialogId = defaultDialog.getDialogId(); 1400 if (dialogResponse == null 1401 || (method.equals(Request.SUBSCRIBE) 1402 && dialogResponse.getCSeq().getMethod().equals( 1403 Request.NOTIFY) && defaultDialogId 1404 .equals(dialogId))) { 1405 // The default dialog has not been claimed yet. 1406 defaultDialog.setLastResponse(this, sipResponse); 1407 dialog = defaultDialog; 1408 } else { 1409 /* 1410 * check if we have created one previously (happens in the case of 1411 * REINVITE processing. JvB: should not happen, this.defaultDialog 1412 * should then get set in Dialog#sendRequest line 1662 1413 */ 1414 1415 dialog = sipStack.getDialog(dialogId); 1416 if (dialog == null) { 1417 if (defaultDialog.isAssigned()) { 1418 /* 1419 * Nop we dont have one. so go ahead and allocate a new 1420 * one. 1421 */ 1422 dialog = sipStack.createDialog(this, sipResponse); 1423 1424 } 1425 } 1426 1427 } 1428 if ( dialog != null ) { 1429 this.setDialog(dialog, dialog.getDialogId()); 1430 } else { 1431 sipStack.getStackLogger().logError("dialog is unexpectedly null",new NullPointerException()); 1432 } 1433 } else { 1434 throw new RuntimeException("Response without from-tag"); 1435 } 1436 } else { 1437 // Need to create a new Dialog, this becomes default 1438 // JvB: not sure if this ever gets executed 1439 if (sipStack.isAutomaticDialogSupportEnabled) { 1440 dialog = sipStack.createDialog(this, sipResponse); 1441 this.setDialog(dialog, dialog.getDialogId()); 1442 } 1443 } 1444 } // synchronized 1445 } else { 1446 dialog = defaultDialog; 1447 } 1448 } else { 1449 dialog.setLastResponse(this, sipResponse); 1450 } 1451 this.processResponse(sipResponse, incomingChannel, dialog); 1452 } 1453 1454 /* 1455 * (non-Javadoc) 1456 * 1457 * @see gov.nist.javax.sip.stack.SIPTransaction#getDialog() 1458 */ 1459 public Dialog getDialog() { 1460 // This is for backwards compatibility. 1461 Dialog retval = null; 1462 if (this.lastResponse != null && this.lastResponse.getFromTag() != null 1463 && this.lastResponse.getToTag() != null 1464 && this.lastResponse.getStatusCode() != 100) { 1465 String dialogId = this.lastResponse.getDialogId(false); 1466 retval = (Dialog) getDialog(dialogId); 1467 } 1468 1469 if (retval == null) { 1470 retval = (Dialog) this.defaultDialog; 1471 1472 } 1473 if (sipStack.isLoggingEnabled()) { 1474 sipStack.getStackLogger().logDebug( 1475 " sipDialogs = " + sipDialogs + " default dialog " + this.defaultDialog 1476 + " retval " + retval); 1477 } 1478 return retval; 1479 1480 } 1481 1482 /* 1483 * (non-Javadoc) 1484 * 1485 * @see gov.nist.javax.sip.stack.SIPTransaction#setDialog(gov.nist.javax.sip.stack.SIPDialog, 1486 * gov.nist.javax.sip.message.SIPMessage) 1487 */ 1488 public SIPDialog getDialog(String dialogId) { 1489 SIPDialog retval = (SIPDialog) this.sipDialogs.get(dialogId); 1490 return retval; 1491 1492 } 1493 1494 /* 1495 * (non-Javadoc) 1496 * 1497 * @see gov.nist.javax.sip.stack.SIPTransaction#setDialog(gov.nist.javax.sip.stack.SIPDialog, 1498 * gov.nist.javax.sip.message.SIPMessage) 1499 */ 1500 public void setDialog(SIPDialog sipDialog, String dialogId) { 1501 if (sipStack.isLoggingEnabled()) 1502 sipStack.getStackLogger().logDebug( 1503 "setDialog: " + dialogId + "sipDialog = " + sipDialog); 1504 1505 if (sipDialog == null) { 1506 if (sipStack.isLoggingEnabled()) 1507 sipStack.getStackLogger().logError("NULL DIALOG!!"); 1508 throw new NullPointerException("bad dialog null"); 1509 } 1510 if (this.defaultDialog == null) { 1511 this.defaultDialog = sipDialog; 1512 if ( this.getMethod().equals(Request.INVITE) && this.getSIPStack().maxForkTime != 0) { 1513 this.getSIPStack().addForkedClientTransaction(this); 1514 } 1515 } 1516 if (dialogId != null && sipDialog.getDialogId() != null) { 1517 this.sipDialogs.put(dialogId, sipDialog); 1518 1519 } 1520 1521 } 1522 1523 public SIPDialog getDefaultDialog() { 1524 return this.defaultDialog; 1525 } 1526 1527 /** 1528 * Set the next hop ( if it has already been computed). 1529 * 1530 * @param hop -- the hop that has been previously computed. 1531 */ 1532 public void setNextHop(Hop hop) { 1533 this.nextHop = hop; 1534 1535 } 1536 1537 /** 1538 * Reeturn the previously computed next hop (avoid computing it twice). 1539 * 1540 * @return -- next hop previously computed. 1541 */ 1542 public Hop getNextHop() { 1543 return nextHop; 1544 } 1545 1546 /** 1547 * Set this flag if you want your Listener to get Timeout.RETRANSMIT notifications each time a 1548 * retransmission occurs. 1549 * 1550 * @param notifyOnRetransmit the notifyOnRetransmit to set 1551 */ 1552 public void setNotifyOnRetransmit(boolean notifyOnRetransmit) { 1553 this.notifyOnRetransmit = notifyOnRetransmit; 1554 } 1555 1556 /** 1557 * @return the notifyOnRetransmit 1558 */ 1559 public boolean isNotifyOnRetransmit() { 1560 return notifyOnRetransmit; 1561 } 1562 1563 public void alertIfStillInCallingStateBy(int count) { 1564 this.timeoutIfStillInCallingState = true; 1565 this.callingStateTimeoutCount = count; 1566 } 1567 1568 1569 1570} 1571