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 package gov.nist.javax.sip.stack; 27 28 import gov.nist.core.InternalErrorHandler; 29 import gov.nist.javax.sip.SIPConstants; 30 import gov.nist.javax.sip.ServerTransactionExt; 31 import gov.nist.javax.sip.SipProviderImpl; 32 import gov.nist.javax.sip.Utils; 33 import gov.nist.javax.sip.header.Expires; 34 import gov.nist.javax.sip.header.ParameterNames; 35 import gov.nist.javax.sip.header.RSeq; 36 import gov.nist.javax.sip.header.Via; 37 import gov.nist.javax.sip.header.ViaList; 38 import gov.nist.javax.sip.message.SIPMessage; 39 import gov.nist.javax.sip.message.SIPRequest; 40 import gov.nist.javax.sip.message.SIPResponse; 41 42 import java.io.IOException; 43 import java.text.ParseException; 44 import java.util.TimerTask; 45 import java.util.concurrent.Semaphore; 46 import java.util.concurrent.TimeUnit; 47 48 import javax.sip.Dialog; 49 import javax.sip.DialogState; 50 import javax.sip.DialogTerminatedEvent; 51 import javax.sip.ObjectInUseException; 52 import javax.sip.SipException; 53 import javax.sip.Timeout; 54 import javax.sip.TimeoutEvent; 55 import javax.sip.TransactionState; 56 import javax.sip.address.Hop; 57 import javax.sip.header.ContactHeader; 58 import javax.sip.header.ExpiresHeader; 59 import javax.sip.header.RSeqHeader; 60 import javax.sip.message.Request; 61 import javax.sip.message.Response; 62 63 /* 64 * Bug fixes / enhancements:Emil Ivov, Antonis Karydas, Daniel J. Martinez Manzano, Daniel, Hagai 65 * Sela, Vazques-Illa, Bill Roome, Thomas Froment and Pierre De Rop, Christophe Anzille and Jeroen 66 * van Bemmel, Frank Reif. 67 * Carolyn Beeton ( Avaya ). 68 * 69 */ 70 71 /** 72 * Represents a server transaction. Implements the following state machines. 73 * 74 * <pre> 75 * 76 * 77 * 78 * |INVITE 79 * |pass INV to TU 80 * INVITE V send 100 if TU won't in 200ms 81 * send response+-----------+ 82 * +--------| |--------+101-199 from TU 83 * | | Proceeding| |send response 84 * +------->| |<-------+ 85 * | | Transport Err. 86 * | | Inform TU 87 * | |--------------->+ 88 * +-----------+ | 89 * 300-699 from TU | |2xx from TU | 90 * send response | |send response | 91 * | +------------------>+ 92 * | | 93 * INVITE V Timer G fires | 94 * send response+-----------+ send response | 95 * +--------| |--------+ | 96 * | | Completed | | | 97 * +------->| |<-------+ | 98 * +-----------+ | 99 * | | | 100 * ACK | | | 101 * - | +------------------>+ 102 * | Timer H fires | 103 * V or Transport Err.| 104 * +-----------+ Inform TU | 105 * | | | 106 * | Confirmed | | 107 * | | | 108 * +-----------+ | 109 * | | 110 * |Timer I fires | 111 * |- | 112 * | | 113 * V | 114 * +-----------+ | 115 * | | | 116 * | Terminated|<---------------+ 117 * | | 118 * +-----------+ 119 * 120 * Figure 7: INVITE server transaction 121 * Request received 122 * |pass to TU 123 * 124 * V 125 * +-----------+ 126 * | | 127 * | Trying |-------------+ 128 * | | | 129 * +-----------+ |200-699 from TU 130 * | |send response 131 * |1xx from TU | 132 * |send response | 133 * | | 134 * Request V 1xx from TU | 135 * send response+-----------+send response| 136 * +--------| |--------+ | 137 * | | Proceeding| | | 138 * +------->| |<-------+ | 139 * +<--------------| | | 140 * |Trnsprt Err +-----------+ | 141 * |Inform TU | | 142 * | | | 143 * | |200-699 from TU | 144 * | |send response | 145 * | Request V | 146 * | send response+-----------+ | 147 * | +--------| | | 148 * | | | Completed |<------------+ 149 * | +------->| | 150 * +<--------------| | 151 * |Trnsprt Err +-----------+ 152 * |Inform TU | 153 * | |Timer J fires 154 * | |- 155 * | | 156 * | V 157 * | +-----------+ 158 * | | | 159 * +-------------->| Terminated| 160 * | | 161 * +-----------+ 162 * 163 * 164 * 165 * 166 * 167 * </pre> 168 * 169 * @version 1.2 $Revision: 1.118 $ $Date: 2010/01/10 00:13:14 $ 170 * @author M. Ranganathan 171 * 172 */ 173 public class SIPServerTransaction extends SIPTransaction implements ServerRequestInterface, 174 javax.sip.ServerTransaction, ServerTransactionExt { 175 176 // force the listener to see transaction 177 178 private int rseqNumber; 179 180 // private LinkedList pendingRequests; 181 182 // Real RequestInterface to pass messages to 183 private transient ServerRequestInterface requestOf; 184 185 private SIPDialog dialog; 186 187 // the unacknowledged SIPResponse 188 189 private SIPResponse pendingReliableResponse; 190 191 // The pending reliable Response Timer 192 private ProvisionalResponseTask provisionalResponseTask; 193 194 private boolean retransmissionAlertEnabled; 195 196 private RetransmissionAlertTimerTask retransmissionAlertTimerTask; 197 198 protected boolean isAckSeen; 199 200 private SIPClientTransaction pendingSubscribeTransaction; 201 202 private SIPServerTransaction inviteTransaction; 203 204 private Semaphore provisionalResponseSem = new Semaphore(1); 205 206 /** 207 * This timer task is used for alerting the application to send retransmission alerts. 208 * 209 * 210 */ 211 class RetransmissionAlertTimerTask extends SIPStackTimerTask { 212 213 String dialogId; 214 215 int ticks; 216 217 int ticksLeft; 218 RetransmissionAlertTimerTask(String dialogId)219 public RetransmissionAlertTimerTask(String dialogId) { 220 221 this.ticks = SIPTransaction.T1; 222 this.ticksLeft = this.ticks; 223 } 224 runTask()225 protected void runTask() { 226 SIPServerTransaction serverTransaction = SIPServerTransaction.this; 227 ticksLeft--; 228 if (ticksLeft == -1) { 229 serverTransaction.fireRetransmissionTimer(); 230 this.ticksLeft = 2 * ticks; 231 } 232 233 } 234 235 } 236 237 class ProvisionalResponseTask extends SIPStackTimerTask { 238 239 int ticks; 240 241 int ticksLeft; 242 ProvisionalResponseTask()243 public ProvisionalResponseTask() { 244 this.ticks = SIPTransaction.T1; 245 this.ticksLeft = this.ticks; 246 } 247 runTask()248 protected void runTask() { 249 SIPServerTransaction serverTransaction = SIPServerTransaction.this; 250 /* 251 * The reliable provisional response is passed to the transaction layer periodically 252 * with an interval that starts at T1 seconds and doubles for each retransmission (T1 253 * is defined in Section 17 of RFC 3261). Once passed to the server transaction, it is 254 * added to an internal list of unacknowledged reliable provisional responses. The 255 * transaction layer will forward each retransmission passed from the UAS core. 256 * 257 * This differs from retransmissions of 2xx responses, whose intervals cap at T2 258 * seconds. This is because retransmissions of ACK are triggered on receipt of a 2xx, 259 * but retransmissions of PRACK take place independently of reception of 1xx. 260 */ 261 // If the transaction has terminated, 262 if (serverTransaction.isTerminated()) { 263 264 this.cancel(); 265 266 } else { 267 ticksLeft--; 268 if (ticksLeft == -1) { 269 serverTransaction.fireReliableResponseRetransmissionTimer(); 270 this.ticksLeft = 2 * ticks; 271 this.ticks = this.ticksLeft; 272 // timer H MUST be set to fire in 64*T1 seconds for all transports. Timer H 273 // determines when the server 274 // transaction abandons retransmitting the response 275 if (this.ticksLeft >= SIPTransaction.TIMER_H) { 276 this.cancel(); 277 setState(TERMINATED_STATE); 278 fireTimeoutTimer(); 279 } 280 } 281 282 } 283 284 } 285 286 } 287 288 /** 289 * This timer task will terminate the transaction if the listener does not respond in a 290 * pre-determined time period. This helps prevent buggy listeners (who fail to respond) from 291 * causing memory leaks. This allows a container to protect itself from buggy code ( that 292 * fails to respond to a server transaction). 293 * 294 */ 295 class ListenerExecutionMaxTimer extends SIPStackTimerTask { 296 SIPServerTransaction serverTransaction = SIPServerTransaction.this; 297 ListenerExecutionMaxTimer()298 ListenerExecutionMaxTimer() { 299 } 300 runTask()301 protected void runTask() { 302 try { 303 if (serverTransaction.getState() == null) { 304 serverTransaction.terminate(); 305 SIPTransactionStack sipStack = serverTransaction.getSIPStack(); 306 sipStack.removePendingTransaction(serverTransaction); 307 sipStack.removeTransaction(serverTransaction); 308 309 } 310 } catch (Exception ex) { 311 sipStack.getStackLogger().logError("unexpected exception", ex); 312 } 313 } 314 } 315 316 /** 317 * This timer task is for INVITE server transactions. It will send a trying in 200 ms. if the 318 * TU does not do so. 319 * 320 */ 321 class SendTrying extends SIPStackTimerTask { 322 SendTrying()323 protected SendTrying() { 324 if (sipStack.isLoggingEnabled()) 325 sipStack.getStackLogger().logDebug("scheduled timer for " + SIPServerTransaction.this); 326 327 } 328 runTask()329 protected void runTask() { 330 SIPServerTransaction serverTransaction = SIPServerTransaction.this; 331 332 TransactionState realState = serverTransaction.getRealState(); 333 334 if (realState == null || TransactionState.TRYING == realState) { 335 if (sipStack.isLoggingEnabled()) 336 sipStack.getStackLogger().logDebug(" sending Trying current state = " 337 + serverTransaction.getRealState()); 338 try { 339 serverTransaction.sendMessage(serverTransaction.getOriginalRequest() 340 .createResponse(100, "Trying")); 341 if (sipStack.isLoggingEnabled()) 342 sipStack.getStackLogger().logDebug(" trying sent " 343 + serverTransaction.getRealState()); 344 } catch (IOException ex) { 345 if (sipStack.isLoggingEnabled()) 346 sipStack.getStackLogger().logError("IO error sending TRYING"); 347 } 348 } 349 350 } 351 } 352 353 class TransactionTimer extends SIPStackTimerTask { 354 TransactionTimer()355 public TransactionTimer() { 356 if (sipStack.isLoggingEnabled()) { 357 sipStack.getStackLogger().logDebug("TransactionTimer() : " + getTransactionId()); 358 } 359 360 } 361 runTask()362 protected void runTask() { 363 // If the transaction has terminated, 364 if (isTerminated()) { 365 // Keep the transaction hanging around in the transaction table 366 // to catch the incoming ACK -- this is needed for tcp only. 367 // Note that the transaction record is actually removed in 368 // the connection linger timer. 369 try { 370 this.cancel(); 371 } catch (IllegalStateException ex) { 372 if (!sipStack.isAlive()) 373 return; 374 } 375 376 // Oneshot timer that garbage collects the SeverTransaction 377 // after a scheduled amount of time. The linger timer allows 378 // the client side of the tx to use the same connection to 379 // send an ACK and prevents a race condition for creation 380 // of new server tx 381 TimerTask myTimer = new LingerTimer(); 382 383 sipStack.getTimer().schedule(myTimer, 384 SIPTransactionStack.CONNECTION_LINGER_TIME * 1000); 385 386 } else { 387 // Add to the fire list -- needs to be moved 388 // outside the synchronized block to prevent 389 // deadlock. 390 fireTimer(); 391 392 } 393 } 394 395 } 396 397 /** 398 * Send a response. 399 * 400 * @param transactionResponse -- the response to send 401 * 402 */ 403 sendResponse(SIPResponse transactionResponse)404 private void sendResponse(SIPResponse transactionResponse) throws IOException { 405 406 try { 407 // RFC18.2.2. Sending Responses 408 // The server transport uses the value of the top Via header field 409 // in 410 // order 411 // to determine where to send a response. 412 // It MUST follow the following process: 413 // If the "sent-protocol" is a reliable transport 414 // protocol such as TCP or SCTP, 415 // or TLS over those, the response MUST be 416 // sent using the existing connection 417 // to the source of the original request 418 // that created the transaction, if that connection is still open. 419 if (isReliable()) { 420 421 getMessageChannel().sendMessage(transactionResponse); 422 423 // TODO If that connection attempt fails, the server SHOULD 424 // use SRV 3263 procedures 425 // for servers in order to determine the IP address 426 // and port to open the connection and send the response to. 427 428 } else { 429 Via via = transactionResponse.getTopmostVia(); 430 String transport = via.getTransport(); 431 if (transport == null) 432 throw new IOException("missing transport!"); 433 // @@@ hagai Symmetric NAT support 434 int port = via.getRPort(); 435 if (port == -1) 436 port = via.getPort(); 437 if (port == -1) { 438 if (transport.equalsIgnoreCase("TLS")) 439 port = 5061; 440 else 441 port = 5060; 442 } 443 444 // Otherwise, if the Via header field value contains a 445 // "maddr" parameter, the response MUST be forwarded to 446 // the address listed there, using the port indicated in 447 // "sent-by", 448 // or port 5060 if none is present. If the address is a 449 // multicast 450 // address, the response SHOULD be sent using 451 // the TTL indicated in the "ttl" parameter, or with a 452 // TTL of 1 if that parameter is not present. 453 String host = null; 454 if (via.getMAddr() != null) { 455 host = via.getMAddr(); 456 } else { 457 // Otherwise (for unreliable unicast transports), 458 // if the top Via has a "received" parameter, the response 459 // MUST 460 // be sent to the 461 // address in the "received" parameter, using the port 462 // indicated 463 // in the 464 // "sent-by" value, or using port 5060 if none is specified 465 // explicitly. 466 host = via.getParameter(Via.RECEIVED); 467 if (host == null) { 468 // Otherwise, if it is not receiver-tagged, the response 469 // MUST be 470 // sent to the address indicated by the "sent-by" value, 471 // using the procedures in Section 5 472 // RFC 3263 PROCEDURE TO BE DONE HERE 473 host = via.getHost(); 474 } 475 } 476 477 Hop hop = sipStack.addressResolver.resolveAddress(new HopImpl(host, port, 478 transport)); 479 480 MessageChannel messageChannel = ((SIPTransactionStack) getSIPStack()) 481 .createRawMessageChannel(this.getSipProvider().getListeningPoint( 482 hop.getTransport()).getIPAddress(), this.getPort(), hop); 483 if (messageChannel != null) 484 messageChannel.sendMessage(transactionResponse); 485 else 486 throw new IOException("Could not create a message channel for " + hop); 487 488 } 489 } finally { 490 this.startTransactionTimer(); 491 } 492 } 493 494 /** 495 * Creates a new server transaction. 496 * 497 * @param sipStack Transaction stack this transaction belongs to. 498 * @param newChannelToUse Channel to encapsulate. 499 */ SIPServerTransaction(SIPTransactionStack sipStack, MessageChannel newChannelToUse)500 protected SIPServerTransaction(SIPTransactionStack sipStack, MessageChannel newChannelToUse) { 501 502 super(sipStack, newChannelToUse); 503 504 if (sipStack.maxListenerResponseTime != -1) { 505 sipStack.getTimer().schedule(new ListenerExecutionMaxTimer(), 506 sipStack.maxListenerResponseTime * 1000); 507 } 508 509 this.rseqNumber = (int) (Math.random() * 1000); 510 // Only one outstanding request for a given server tx. 511 512 if (sipStack.isLoggingEnabled()) { 513 sipStack.getStackLogger().logDebug("Creating Server Transaction" + this.getBranchId()); 514 sipStack.getStackLogger().logStackTrace(); 515 } 516 517 } 518 519 /** 520 * Sets the real RequestInterface this transaction encapsulates. 521 * 522 * @param newRequestOf RequestInterface to send messages to. 523 */ setRequestInterface(ServerRequestInterface newRequestOf)524 public void setRequestInterface(ServerRequestInterface newRequestOf) { 525 526 requestOf = newRequestOf; 527 528 } 529 530 /** 531 * Returns this transaction. 532 */ getResponseChannel()533 public MessageChannel getResponseChannel() { 534 535 return this; 536 537 } 538 539 540 541 /** 542 * Determines if the message is a part of this transaction. 543 * 544 * @param messageToTest Message to check if it is part of this transaction. 545 * 546 * @return True if the message is part of this transaction, false if not. 547 */ isMessagePartOfTransaction(SIPMessage messageToTest)548 public boolean isMessagePartOfTransaction(SIPMessage messageToTest) { 549 550 // List of Via headers in the message to test 551 ViaList viaHeaders; 552 // Topmost Via header in the list 553 Via topViaHeader; 554 // Branch code in the topmost Via header 555 String messageBranch; 556 // Flags whether the select message is part of this transaction 557 boolean transactionMatches; 558 559 transactionMatches = false; 560 561 String method = messageToTest.getCSeq().getMethod(); 562 // Invite Server transactions linger in the terminated state in the 563 // transaction 564 // table and are matched to compensate for 565 // http://bugs.sipit.net/show_bug.cgi?id=769 566 if ((method.equals(Request.INVITE) || !isTerminated())) { 567 568 // Get the topmost Via header and its branch parameter 569 viaHeaders = messageToTest.getViaHeaders(); 570 if (viaHeaders != null) { 571 572 topViaHeader = (Via) viaHeaders.getFirst(); 573 messageBranch = topViaHeader.getBranch(); 574 if (messageBranch != null) { 575 576 // If the branch parameter exists but 577 // does not start with the magic cookie, 578 if (!messageBranch.toLowerCase().startsWith( 579 SIPConstants.BRANCH_MAGIC_COOKIE_LOWER_CASE)) { 580 581 // Flags this as old 582 // (RFC2543-compatible) client 583 // version 584 messageBranch = null; 585 586 } 587 588 } 589 590 // If a new branch parameter exists, 591 if (messageBranch != null && this.getBranch() != null) { 592 if (method.equals(Request.CANCEL)) { 593 // Cancel is handled as a special case because it 594 // shares the same same branch id of the invite 595 // that it is trying to cancel. 596 transactionMatches = this.getMethod().equals(Request.CANCEL) 597 && getBranch().equalsIgnoreCase(messageBranch) 598 && topViaHeader.getSentBy().equals( 599 ((Via) getOriginalRequest().getViaHeaders().getFirst()) 600 .getSentBy()); 601 602 } else { 603 // Matching server side transaction with only the 604 // branch parameter. 605 transactionMatches = getBranch().equalsIgnoreCase(messageBranch) 606 && topViaHeader.getSentBy().equals( 607 ((Via) getOriginalRequest().getViaHeaders().getFirst()) 608 .getSentBy()); 609 610 } 611 612 } else { 613 // This is an RFC2543-compliant message; this code is here 614 // for backwards compatibility. 615 // It is a weak check. 616 // If RequestURI, To tag, From tag, CallID, CSeq number, and 617 // top Via headers are the same, the 618 // SIPMessage matches this transaction. An exception is for 619 // a CANCEL request, which is not deemed 620 // to be part of an otherwise-matching INVITE transaction. 621 String originalFromTag = super.fromTag; 622 623 String thisFromTag = messageToTest.getFrom().getTag(); 624 625 boolean skipFrom = (originalFromTag == null || thisFromTag == null); 626 627 String originalToTag = super.toTag; 628 629 String thisToTag = messageToTest.getTo().getTag(); 630 631 boolean skipTo = (originalToTag == null || thisToTag == null); 632 boolean isResponse = (messageToTest instanceof SIPResponse); 633 // Issue #96: special case handling for a CANCEL request - 634 // the CSeq method of the original request must 635 // be CANCEL for it to have a chance at matching. 636 if (messageToTest.getCSeq().getMethod().equalsIgnoreCase(Request.CANCEL) 637 && !getOriginalRequest().getCSeq().getMethod().equalsIgnoreCase( 638 Request.CANCEL)) { 639 transactionMatches = false; 640 } else if ((isResponse || getOriginalRequest().getRequestURI().equals( 641 ((SIPRequest) messageToTest).getRequestURI())) 642 && (skipFrom || originalFromTag != null && originalFromTag.equalsIgnoreCase(thisFromTag)) 643 && (skipTo || originalToTag != null && originalToTag.equalsIgnoreCase(thisToTag)) 644 && getOriginalRequest().getCallId().getCallId().equalsIgnoreCase( 645 messageToTest.getCallId().getCallId()) 646 && getOriginalRequest().getCSeq().getSeqNumber() == messageToTest 647 .getCSeq().getSeqNumber() 648 && ((!messageToTest.getCSeq().getMethod().equals(Request.CANCEL)) || getOriginalRequest() 649 .getMethod().equals(messageToTest.getCSeq().getMethod())) 650 && topViaHeader.equals(getOriginalRequest().getViaHeaders() 651 .getFirst())) { 652 653 transactionMatches = true; 654 } 655 656 } 657 658 } 659 660 } 661 return transactionMatches; 662 663 } 664 665 /** 666 * Send out a trying response (only happens when the transaction is mapped). Otherwise the 667 * transaction is not known to the stack. 668 */ map()669 protected void map() { 670 // note that TRYING is a pseudo-state for invite transactions 671 672 TransactionState realState = getRealState(); 673 674 if (realState == null || realState == TransactionState.TRYING) { 675 // JvB: Removed the condition 'dialog!=null'. Trying should also 676 // be 677 // sent by intermediate proxies. This fixes some TCK tests 678 // null check added as the stack may be stopped. 679 if (isInviteTransaction() && !this.isMapped && sipStack.getTimer() != null) { 680 this.isMapped = true; 681 // Schedule a timer to fire in 200 ms if the 682 // TU did not send a trying in that time. 683 sipStack.getTimer().schedule(new SendTrying(), 200); 684 685 } else { 686 isMapped = true; 687 } 688 } 689 690 // Pull it out of the pending transactions list. 691 sipStack.removePendingTransaction(this); 692 } 693 694 /** 695 * Return true if the transaction is known to stack. 696 */ isTransactionMapped()697 public boolean isTransactionMapped() { 698 return this.isMapped; 699 } 700 701 /** 702 * Process a new request message through this transaction. If necessary, this message will 703 * also be passed onto the TU. 704 * 705 * @param transactionRequest Request to process. 706 * @param sourceChannel Channel that received this message. 707 */ processRequest(SIPRequest transactionRequest, MessageChannel sourceChannel)708 public void processRequest(SIPRequest transactionRequest, MessageChannel sourceChannel) { 709 boolean toTu = false; 710 711 // Can only process a single request directed to the 712 // transaction at a time. For a given server transaction 713 // the listener sees only one event at a time. 714 715 if (sipStack.isLoggingEnabled()) { 716 sipStack.getStackLogger().logDebug("processRequest: " + transactionRequest.getFirstLine()); 717 sipStack.getStackLogger().logDebug("tx state = " + this.getRealState()); 718 } 719 720 try { 721 722 // If this is the first request for this transaction, 723 if (getRealState() == null) { 724 // Save this request as the one this 725 // transaction is handling 726 setOriginalRequest(transactionRequest); 727 this.setState(TransactionState.TRYING); 728 toTu = true; 729 this.setPassToListener(); 730 731 // Rsends the TRYING on retransmission of the request. 732 if (isInviteTransaction() && this.isMapped) { 733 // JvB: also 734 // proxies need 735 // to do this 736 737 // Has side-effect of setting 738 // state to "Proceeding" 739 sendMessage(transactionRequest.createResponse(100, "Trying")); 740 741 } 742 // If an invite transaction is ACK'ed while in 743 // the completed state, 744 } else if (isInviteTransaction() && TransactionState.COMPLETED == getRealState() 745 && transactionRequest.getMethod().equals(Request.ACK)) { 746 747 // @jvB bug fix 748 this.setState(TransactionState.CONFIRMED); 749 disableRetransmissionTimer(); 750 if (!isReliable()) { 751 enableTimeoutTimer(TIMER_I); 752 753 } else { 754 755 this.setState(TransactionState.TERMINATED); 756 757 } 758 759 // JvB: For the purpose of testing a TI, added a property to 760 // pass it anyway 761 if (sipStack.isNon2XXAckPassedToListener()) { 762 // This is useful for test applications that want to see 763 // all messages. 764 requestOf.processRequest(transactionRequest, this); 765 } else { 766 // According to RFC3261 Application should not Ack in 767 // CONFIRMED state 768 if (sipStack.isLoggingEnabled()) { 769 sipStack.getStackLogger().logDebug("ACK received for server Tx " 770 + this.getTransactionId() + " not delivering to application!"); 771 772 } 773 774 this.semRelease(); 775 } 776 return; 777 778 // If we receive a retransmission of the original 779 // request, 780 } else if (transactionRequest.getMethod().equals(getOriginalRequest().getMethod())) { 781 782 if (TransactionState.PROCEEDING == getRealState() 783 || TransactionState.COMPLETED == getRealState()) { 784 this.semRelease(); 785 // Resend the last response to 786 // the client 787 if (lastResponse != null) { 788 789 // Send the message to the client 790 super.sendMessage(lastResponse); 791 792 } 793 } else if (transactionRequest.getMethod().equals(Request.ACK)) { 794 // This is passed up to the TU to suppress 795 // retransmission of OK 796 if (requestOf != null) 797 requestOf.processRequest(transactionRequest, this); 798 else 799 this.semRelease(); 800 } 801 if (sipStack.isLoggingEnabled()) 802 sipStack.getStackLogger().logDebug("completed processing retransmitted request : " 803 + transactionRequest.getFirstLine() + this + " txState = " 804 + this.getState() + " lastResponse = " + this.getLastResponse()); 805 return; 806 807 } 808 809 // Pass message to the TU 810 if (TransactionState.COMPLETED != getRealState() 811 && TransactionState.TERMINATED != getRealState() && requestOf != null) { 812 if (getOriginalRequest().getMethod().equals(transactionRequest.getMethod())) { 813 // Only send original request to TU once! 814 if (toTu) { 815 requestOf.processRequest(transactionRequest, this); 816 } else 817 this.semRelease(); 818 } else { 819 if (requestOf != null) 820 requestOf.processRequest(transactionRequest, this); 821 else 822 this.semRelease(); 823 } 824 } else { 825 // This seems like a common bug so I am allowing it through! 826 if (((SIPTransactionStack) getSIPStack()).isDialogCreated(getOriginalRequest() 827 .getMethod()) 828 && getRealState() == TransactionState.TERMINATED 829 && transactionRequest.getMethod().equals(Request.ACK) 830 && requestOf != null) { 831 SIPDialog thisDialog = (SIPDialog) this.dialog; 832 833 if (thisDialog == null || !thisDialog.ackProcessed) { 834 // Filter out duplicate acks 835 if (thisDialog != null) { 836 thisDialog.ackReceived(transactionRequest); 837 thisDialog.ackProcessed = true; 838 } 839 requestOf.processRequest(transactionRequest, this); 840 } else { 841 this.semRelease(); 842 } 843 844 } else if (transactionRequest.getMethod().equals(Request.CANCEL)) { 845 if (sipStack.isLoggingEnabled()) 846 sipStack.getStackLogger().logDebug("Too late to cancel Transaction"); 847 this.semRelease(); 848 // send OK and just ignore the CANCEL. 849 try { 850 this.sendMessage(transactionRequest.createResponse(Response.OK)); 851 } catch (IOException ex) { 852 // Transaction is already terminated 853 // just ignore the IOException. 854 } 855 } 856 if (sipStack.isLoggingEnabled()) 857 sipStack.getStackLogger().logDebug("Dropping request " + getRealState()); 858 } 859 860 } catch (IOException e) { 861 if (sipStack.isLoggingEnabled()) 862 sipStack.getStackLogger().logError("IOException " ,e); 863 this.semRelease(); 864 this.raiseIOExceptionEvent(); 865 } 866 867 } 868 869 /** 870 * Send a response message through this transactionand onto the client. The response drives 871 * the state machine. 872 * 873 * @param messageToSend Response to process and send. 874 */ sendMessage(SIPMessage messageToSend)875 public void sendMessage(SIPMessage messageToSend) throws IOException { 876 try { 877 // Message typecast as a response 878 SIPResponse transactionResponse; 879 // Status code of the response being sent to the client 880 int statusCode; 881 882 // Get the status code from the response 883 transactionResponse = (SIPResponse) messageToSend; 884 statusCode = transactionResponse.getStatusCode(); 885 886 try { 887 // Provided we have set the banch id for this we set the BID for 888 // the 889 // outgoing via. 890 if (this.getOriginalRequest().getTopmostVia().getBranch() != null) 891 transactionResponse.getTopmostVia().setBranch(this.getBranch()); 892 else 893 transactionResponse.getTopmostVia().removeParameter(ParameterNames.BRANCH); 894 895 // Make the topmost via headers match identically for the 896 // transaction rsponse. 897 if (!this.getOriginalRequest().getTopmostVia().hasPort()) 898 transactionResponse.getTopmostVia().removePort(); 899 } catch (ParseException ex) { 900 ex.printStackTrace(); 901 } 902 903 // Method of the response does not match the request used to 904 // create the transaction - transaction state does not change. 905 if (!transactionResponse.getCSeq().getMethod().equals( 906 getOriginalRequest().getMethod())) { 907 sendResponse(transactionResponse); 908 return; 909 } 910 911 // If the TU sends a provisional response while in the 912 // trying state, 913 914 if (getRealState() == TransactionState.TRYING) { 915 if (statusCode / 100 == 1) { 916 this.setState(TransactionState.PROCEEDING); 917 } else if (200 <= statusCode && statusCode <= 699) { 918 // INVITE ST has TRYING as a Pseudo state 919 // (See issue 76). We are using the TRYING 920 // pseudo state invite Transactions 921 // to signal if the application 922 // has sent trying or not and hence this 923 // check is necessary. 924 if (!isInviteTransaction()) { 925 if (!isReliable()) { 926 // Linger in the completed state to catch 927 // retransmissions if the transport is not 928 // reliable. 929 this.setState(TransactionState.COMPLETED); 930 // Note that Timer J is only set for Unreliable 931 // transports -- see Issue 75. 932 /* 933 * From RFC 3261 Section 17.2.2 (non-invite server transaction) 934 * 935 * When the server transaction enters the "Completed" state, it MUST 936 * set Timer J to fire in 64*T1 seconds for unreliable transports, and 937 * zero seconds for reliable transports. While in the "Completed" 938 * state, the server transaction MUST pass the final response to the 939 * transport layer for retransmission whenever a retransmission of the 940 * request is received. Any other final responses passed by the TU to 941 * the server transaction MUST be discarded while in the "Completed" 942 * state. The server transaction remains in this state until Timer J 943 * fires, at which point it MUST transition to the "Terminated" state. 944 */ 945 enableTimeoutTimer(TIMER_J); 946 } else { 947 this.setState(TransactionState.TERMINATED); 948 } 949 } else { 950 // This is the case for INVITE server transactions. 951 // essentially, it duplicates the code in the 952 // PROCEEDING case below. There is no TRYING state for INVITE 953 // transactions in the RFC. We are using it to signal whether the 954 // application has sent a provisional response or not. Hence 955 // this is treated the same as as Proceeding. 956 if (statusCode / 100 == 2) { 957 // Status code is 2xx means that the 958 // transaction transitions to TERMINATED 959 // for both Reliable as well as unreliable 960 // transports. Note that the dialog layer 961 // takes care of retransmitting 2xx final 962 // responses. 963 /* 964 * RFC 3261 Section 13.3.1.4 Note, however, that the INVITE server 965 * transaction will be destroyed as soon as it receives this final 966 * response and passes it to the transport. Therefore, it is necessary 967 * to periodically pass the response directly to the transport until 968 * the ACK arrives. The 2xx response is passed to the transport with 969 * an interval that starts at T1 seconds and doubles for each 970 * retransmission until it reaches T2 seconds (T1 and T2 are defined 971 * in Section 17). Response retransmissions cease when an ACK request 972 * for the response is received. This is independent of whatever 973 * transport protocols are used to send the response. 974 */ 975 this.disableRetransmissionTimer(); 976 this.disableTimeoutTimer(); 977 this.collectionTime = TIMER_J; 978 this.setState(TransactionState.TERMINATED); 979 if (this.dialog != null) 980 this.dialog.setRetransmissionTicks(); 981 } else { 982 // This an error final response. 983 this.setState(TransactionState.COMPLETED); 984 if (!isReliable()) { 985 /* 986 * RFC 3261 987 * 988 * While in the "Proceeding" state, if the TU passes a response 989 * with status code from 300 to 699 to the server transaction, the 990 * response MUST be passed to the transport layer for 991 * transmission, and the state machine MUST enter the "Completed" 992 * state. For unreliable transports, timer G is set to fire in T1 993 * seconds, and is not set to fire for reliable transports. 994 */ 995 996 enableRetransmissionTimer(); 997 998 } 999 enableTimeoutTimer(TIMER_H); 1000 } 1001 } 1002 1003 } 1004 1005 // If the transaction is in the proceeding state, 1006 } else if (getRealState() == TransactionState.PROCEEDING) { 1007 1008 if (isInviteTransaction()) { 1009 1010 // If the response is a failure message, 1011 if (statusCode / 100 == 2) { 1012 // Set up to catch returning ACKs 1013 // The transaction lingers in the 1014 // terminated state for some time 1015 // to catch retransmitted INVITEs 1016 this.disableRetransmissionTimer(); 1017 this.disableTimeoutTimer(); 1018 this.collectionTime = TIMER_J; 1019 this.setState(TransactionState.TERMINATED); 1020 if (this.dialog != null) 1021 this.dialog.setRetransmissionTicks(); 1022 1023 } else if (300 <= statusCode && statusCode <= 699) { 1024 1025 // Set up to catch returning ACKs 1026 this.setState(TransactionState.COMPLETED); 1027 if (!isReliable()) { 1028 /* 1029 * While in the "Proceeding" state, if the TU passes a response with 1030 * status code from 300 to 699 to the server transaction, the response 1031 * MUST be passed to the transport layer for transmission, and the 1032 * state machine MUST enter the "Completed" state. For unreliable 1033 * transports, timer G is set to fire in T1 seconds, and is not set to 1034 * fire for reliable transports. 1035 */ 1036 1037 enableRetransmissionTimer(); 1038 1039 } 1040 enableTimeoutTimer(TIMER_H); 1041 1042 } 1043 1044 // If the transaction is not an invite transaction 1045 // and this is a final response, 1046 } else if (200 <= statusCode && statusCode <= 699) { 1047 // This is for Non-invite server transactions. 1048 1049 // Set up to retransmit this response, 1050 // or terminate the transaction 1051 this.setState(TransactionState.COMPLETED); 1052 if (!isReliable()) { 1053 1054 disableRetransmissionTimer(); 1055 enableTimeoutTimer(TIMER_J); 1056 1057 } else { 1058 1059 this.setState(TransactionState.TERMINATED); 1060 1061 } 1062 1063 } 1064 1065 // If the transaction has already completed, 1066 } else if (TransactionState.COMPLETED == this.getRealState()) { 1067 1068 return; 1069 } 1070 1071 try { 1072 // Send the message to the client. 1073 // Record the last message sent out. 1074 if (sipStack.isLoggingEnabled()) { 1075 sipStack.getStackLogger().logDebug( 1076 "sendMessage : tx = " + this + " getState = " + this.getState()); 1077 } 1078 lastResponse = transactionResponse; 1079 this.sendResponse(transactionResponse); 1080 1081 } catch (IOException e) { 1082 1083 this.setState(TransactionState.TERMINATED); 1084 this.collectionTime = 0; 1085 throw e; 1086 1087 } 1088 } finally { 1089 this.startTransactionTimer(); 1090 } 1091 1092 } 1093 getViaHost()1094 public String getViaHost() { 1095 1096 return getMessageChannel().getViaHost(); 1097 1098 } 1099 getViaPort()1100 public int getViaPort() { 1101 1102 return getMessageChannel().getViaPort(); 1103 1104 } 1105 1106 /** 1107 * Called by the transaction stack when a retransmission timer fires. This retransmits the 1108 * last response when the retransmission filter is enabled. 1109 */ fireRetransmissionTimer()1110 protected void fireRetransmissionTimer() { 1111 1112 try { 1113 if (sipStack.isLoggingEnabled()) { 1114 sipStack.getStackLogger().logDebug("fireRetransmissionTimer() -- "); 1115 } 1116 // Resend the last response sent by this transaction 1117 if (isInviteTransaction() && lastResponse != null) { 1118 // null can happen if this is terminating when the timer fires. 1119 if (!this.retransmissionAlertEnabled || sipStack.isTransactionPendingAck(this) ) { 1120 // Retransmit last response until ack. 1121 if (lastResponse.getStatusCode() / 100 > 2 && !this.isAckSeen) 1122 super.sendMessage(lastResponse); 1123 } else { 1124 // alert the application to retransmit the last response 1125 SipProviderImpl sipProvider = (SipProviderImpl) this.getSipProvider(); 1126 TimeoutEvent txTimeout = new TimeoutEvent(sipProvider, this, 1127 Timeout.RETRANSMIT); 1128 sipProvider.handleEvent(txTimeout, this); 1129 } 1130 1131 } 1132 } catch (IOException e) { 1133 if (sipStack.isLoggingEnabled()) 1134 sipStack.getStackLogger().logException(e); 1135 raiseErrorEvent(SIPTransactionErrorEvent.TRANSPORT_ERROR); 1136 1137 } 1138 1139 } 1140 fireReliableResponseRetransmissionTimer()1141 private void fireReliableResponseRetransmissionTimer() { 1142 try { 1143 1144 super.sendMessage(this.pendingReliableResponse); 1145 1146 } catch (IOException e) { 1147 if (sipStack.isLoggingEnabled()) 1148 sipStack.getStackLogger().logException(e); 1149 this.setState(TransactionState.TERMINATED); 1150 raiseErrorEvent(SIPTransactionErrorEvent.TRANSPORT_ERROR); 1151 1152 } 1153 } 1154 1155 /** 1156 * Called by the transaction stack when a timeout timer fires. 1157 */ fireTimeoutTimer()1158 protected void fireTimeoutTimer() { 1159 1160 if (sipStack.isLoggingEnabled()) 1161 sipStack.getStackLogger().logDebug("SIPServerTransaction.fireTimeoutTimer this = " + this 1162 + " current state = " + this.getRealState() + " method = " 1163 + this.getOriginalRequest().getMethod()); 1164 1165 if ( this.getMethod().equals(Request.INVITE) && sipStack.removeTransactionPendingAck(this) ) { 1166 if ( sipStack.isLoggingEnabled() ) { 1167 sipStack.getStackLogger().logDebug("Found tx pending ACK - returning"); 1168 } 1169 return; 1170 1171 } 1172 SIPDialog dialog = (SIPDialog) this.dialog; 1173 if (((SIPTransactionStack) getSIPStack()).isDialogCreated(this.getOriginalRequest() 1174 .getMethod()) 1175 && (TransactionState.CALLING == this.getRealState() || TransactionState.TRYING == this 1176 .getRealState())) { 1177 dialog.setState(SIPDialog.TERMINATED_STATE); 1178 } else if (getOriginalRequest().getMethod().equals(Request.BYE)) { 1179 if (dialog != null && dialog.isTerminatedOnBye()) 1180 dialog.setState(SIPDialog.TERMINATED_STATE); 1181 } 1182 1183 if (TransactionState.COMPLETED == this.getRealState() && isInviteTransaction()) { 1184 raiseErrorEvent(SIPTransactionErrorEvent.TIMEOUT_ERROR); 1185 this.setState(TransactionState.TERMINATED); 1186 sipStack.removeTransaction(this); 1187 1188 } else if (TransactionState.COMPLETED == this.getRealState() && !isInviteTransaction()) { 1189 this.setState(TransactionState.TERMINATED); 1190 sipStack.removeTransaction(this); 1191 1192 } else if (TransactionState.CONFIRMED == this.getRealState() && isInviteTransaction()) { 1193 // TIMER_I should not generate a timeout 1194 // exception to the application when the 1195 // Invite transaction is in Confirmed state. 1196 // Just transition to Terminated state. 1197 this.setState(TransactionState.TERMINATED); 1198 sipStack.removeTransaction(this); 1199 } else if (!isInviteTransaction() 1200 && (TransactionState.COMPLETED == this.getRealState() || TransactionState.CONFIRMED == this 1201 .getRealState())) { 1202 this.setState(TransactionState.TERMINATED); 1203 } else if (isInviteTransaction() && TransactionState.TERMINATED == this.getRealState()) { 1204 // This state could be reached when retransmitting 1205 1206 raiseErrorEvent(SIPTransactionErrorEvent.TIMEOUT_ERROR); 1207 if (dialog != null) 1208 dialog.setState(SIPDialog.TERMINATED_STATE); 1209 } 1210 1211 } 1212 1213 /** 1214 * Get the last response. 1215 */ getLastResponse()1216 public SIPResponse getLastResponse() { 1217 return this.lastResponse; 1218 } 1219 1220 /** 1221 * Set the original request. 1222 */ setOriginalRequest(SIPRequest originalRequest)1223 public void setOriginalRequest(SIPRequest originalRequest) { 1224 super.setOriginalRequest(originalRequest); 1225 1226 } 1227 1228 /* 1229 * (non-Javadoc) 1230 * 1231 * @see javax.sip.ServerTransaction#sendResponse(javax.sip.message.Response) 1232 */ sendResponse(Response response)1233 public void sendResponse(Response response) throws SipException { 1234 SIPResponse sipResponse = (SIPResponse) response; 1235 1236 SIPDialog dialog = this.dialog; 1237 if (response == null) 1238 throw new NullPointerException("null response"); 1239 1240 try { 1241 sipResponse.checkHeaders(); 1242 } catch (ParseException ex) { 1243 throw new SipException(ex.getMessage()); 1244 } 1245 1246 // check for meaningful response. 1247 if (!sipResponse.getCSeq().getMethod().equals(this.getMethod())) { 1248 throw new SipException( 1249 "CSeq method does not match Request method of request that created the tx."); 1250 } 1251 1252 /* 1253 * 200-class responses to SUBSCRIBE requests also MUST contain an "Expires" header. The 1254 * period of time in the response MAY be shorter but MUST NOT be longer than specified in 1255 * the request. 1256 */ 1257 if (this.getMethod().equals(Request.SUBSCRIBE) && response.getStatusCode() / 100 == 2) { 1258 1259 if (response.getHeader(ExpiresHeader.NAME) == null) { 1260 throw new SipException("Expires header is mandatory in 2xx response of SUBSCRIBE"); 1261 } else { 1262 Expires requestExpires = (Expires) this.getOriginalRequest().getExpires(); 1263 Expires responseExpires = (Expires) response.getExpires(); 1264 /* 1265 * If no "Expires" header is present in a SUBSCRIBE request, the implied default 1266 * is defined by the event package being used. 1267 */ 1268 if (requestExpires != null 1269 && responseExpires.getExpires() > requestExpires.getExpires()) { 1270 throw new SipException( 1271 "Response Expires time exceeds request Expires time : See RFC 3265 3.1.1"); 1272 } 1273 } 1274 1275 } 1276 1277 // Check for mandatory header. 1278 if (sipResponse.getStatusCode() == 200 1279 && sipResponse.getCSeq().getMethod().equals(Request.INVITE) 1280 && sipResponse.getHeader(ContactHeader.NAME) == null) 1281 throw new SipException("Contact Header is mandatory for the OK to the INVITE"); 1282 1283 if (!this.isMessagePartOfTransaction((SIPMessage) response)) { 1284 throw new SipException("Response does not belong to this transaction."); 1285 } 1286 1287 // Fix up the response if the dialog has already been established. 1288 try { 1289 /* 1290 * The UAS MAY send a final response to the initial request before 1291 * having received PRACKs for all unacknowledged reliable provisional responses, 1292 * unless the final response is 2xx and any of the unacknowledged reliable provisional 1293 * responses contained a session description. In that case, it MUST NOT send a final 1294 * response until those provisional responses are acknowledged. 1295 */ 1296 if (this.pendingReliableResponse != null 1297 && this.getDialog() != null 1298 && this.getState() != TransactionState.TERMINATED 1299 && ((SIPResponse)response).getContentTypeHeader() != null 1300 && response.getStatusCode() / 100 == 2 1301 && ((SIPResponse)response).getContentTypeHeader().getContentType() 1302 .equalsIgnoreCase("application") 1303 && ((SIPResponse)response).getContentTypeHeader().getContentSubType() 1304 .equalsIgnoreCase("sdp")) { 1305 try { 1306 boolean acquired = this.provisionalResponseSem.tryAcquire(1,TimeUnit.SECONDS); 1307 if (!acquired ) { 1308 throw new SipException("cannot send response -- unacked povisional"); 1309 } 1310 } catch (Exception ex) { 1311 this.sipStack.getStackLogger().logError("Could not acquire PRACK sem ", ex); 1312 } 1313 } else { 1314 // Sending the final response cancels the 1315 // pending response task. 1316 if (this.pendingReliableResponse != null && sipResponse.isFinalResponse()) { 1317 this.provisionalResponseTask.cancel(); 1318 this.provisionalResponseTask = null; 1319 } 1320 } 1321 1322 // Dialog checks. These make sure that the response 1323 // being sent makes sense. 1324 if (dialog != null) { 1325 if (sipResponse.getStatusCode() / 100 == 2 1326 && sipStack.isDialogCreated(sipResponse.getCSeq().getMethod())) { 1327 if (dialog.getLocalTag() == null && sipResponse.getTo().getTag() == null) { 1328 // Trying to send final response and user forgot to set 1329 // to 1330 // tag on the response -- be nice and assign the tag for 1331 // the user. 1332 sipResponse.getTo().setTag(Utils.getInstance().generateTag()); 1333 } else if (dialog.getLocalTag() != null && sipResponse.getToTag() == null) { 1334 sipResponse.setToTag(dialog.getLocalTag()); 1335 } else if (dialog.getLocalTag() != null && sipResponse.getToTag() != null 1336 && !dialog.getLocalTag().equals(sipResponse.getToTag())) { 1337 throw new SipException("Tag mismatch dialogTag is " 1338 + dialog.getLocalTag() + " responseTag is " 1339 + sipResponse.getToTag()); 1340 } 1341 } 1342 1343 if (!sipResponse.getCallId().getCallId().equals(dialog.getCallId().getCallId())) { 1344 throw new SipException("Dialog mismatch!"); 1345 } 1346 } 1347 1348 1349 1350 // Backward compatibility slippery slope.... 1351 // Only set the from tag in the response when the 1352 // incoming request has a from tag. 1353 String fromTag = ((SIPRequest) this.getRequest()).getFrom().getTag(); 1354 if (fromTag != null && sipResponse.getFromTag() != null 1355 && !sipResponse.getFromTag().equals(fromTag)) { 1356 throw new SipException("From tag of request does not match response from tag"); 1357 } else if (fromTag != null) { 1358 sipResponse.getFrom().setTag(fromTag); 1359 } else { 1360 if (sipStack.isLoggingEnabled()) 1361 sipStack.getStackLogger().logDebug("WARNING -- Null From tag in request!!"); 1362 } 1363 1364 1365 1366 // See if the dialog needs to be inserted into the dialog table 1367 // or if the state of the dialog needs to be changed. 1368 if (dialog != null && response.getStatusCode() != 100) { 1369 dialog.setResponseTags(sipResponse); 1370 DialogState oldState = dialog.getState(); 1371 dialog.setLastResponse(this, (SIPResponse) response); 1372 if (oldState == null && dialog.getState() == DialogState.TERMINATED) { 1373 DialogTerminatedEvent event = new DialogTerminatedEvent(dialog 1374 .getSipProvider(), dialog); 1375 1376 // Provide notification to the listener that the dialog has 1377 // ended. 1378 dialog.getSipProvider().handleEvent(event, this); 1379 1380 } 1381 1382 } else if (dialog == null && this.getMethod().equals(Request.INVITE) 1383 && this.retransmissionAlertEnabled 1384 && this.retransmissionAlertTimerTask == null 1385 && response.getStatusCode() / 100 == 2) { 1386 String dialogId = ((SIPResponse) response).getDialogId(true); 1387 1388 this.retransmissionAlertTimerTask = new RetransmissionAlertTimerTask(dialogId); 1389 sipStack.retransmissionAlertTransactions.put(dialogId, this); 1390 sipStack.getTimer().schedule(this.retransmissionAlertTimerTask, 0, 1391 SIPTransactionStack.BASE_TIMER_INTERVAL); 1392 1393 } 1394 1395 // Send message after possibly inserting the Dialog 1396 // into the dialog table to avoid a possible race condition. 1397 1398 this.sendMessage((SIPResponse) response); 1399 1400 if ( dialog != null ) { 1401 dialog.startRetransmitTimer(this, (SIPResponse)response); 1402 } 1403 1404 } catch (IOException ex) { 1405 if (sipStack.isLoggingEnabled()) 1406 sipStack.getStackLogger().logException(ex); 1407 this.setState(TransactionState.TERMINATED); 1408 raiseErrorEvent(SIPTransactionErrorEvent.TRANSPORT_ERROR); 1409 throw new SipException(ex.getMessage()); 1410 } catch (java.text.ParseException ex1) { 1411 if (sipStack.isLoggingEnabled()) 1412 sipStack.getStackLogger().logException(ex1); 1413 this.setState(TransactionState.TERMINATED); 1414 throw new SipException(ex1.getMessage()); 1415 } 1416 } 1417 1418 /** 1419 * Return the book-keeping information that we actually use. 1420 */ getRealState()1421 private TransactionState getRealState() { 1422 return super.getState(); 1423 } 1424 1425 /** 1426 * Return the current transaction state according to the RFC 3261 transaction state machine. 1427 * Invite transactions do not have a trying state. We just use this as a pseudo state for 1428 * processing requests. 1429 * 1430 * @return the state of the transaction. 1431 */ getState()1432 public TransactionState getState() { 1433 // Trying is a pseudo state for INVITE transactions. 1434 if (this.isInviteTransaction() && TransactionState.TRYING == super.getState()) 1435 return TransactionState.PROCEEDING; 1436 else 1437 return super.getState(); 1438 } 1439 1440 /** 1441 * Sets a timeout after which the connection is closed (provided the server does not use the 1442 * connection for outgoing requests in this time period) and calls the superclass to set 1443 * state. 1444 */ setState(TransactionState newState)1445 public void setState(TransactionState newState) { 1446 // Set this timer for connection caching 1447 // of incoming connections. 1448 if (newState == TransactionState.TERMINATED && this.isReliable() 1449 && (!getSIPStack().cacheServerConnections)) { 1450 // Set a time after which the connection 1451 // is closed. 1452 this.collectionTime = TIMER_J; 1453 } 1454 1455 super.setState(newState); 1456 1457 } 1458 1459 /** 1460 * Start the timer task. 1461 */ startTransactionTimer()1462 protected void startTransactionTimer() { 1463 if (this.transactionTimerStarted.compareAndSet(false, true)) { 1464 if (sipStack.getTimer() != null) { 1465 // The timer is set to null when the Stack is 1466 // shutting down. 1467 TimerTask myTimer = new TransactionTimer(); 1468 sipStack.getTimer().schedule(myTimer, BASE_TIMER_INTERVAL, BASE_TIMER_INTERVAL); 1469 } 1470 } 1471 } 1472 equals(Object other)1473 public boolean equals(Object other) { 1474 if (!other.getClass().equals(this.getClass())) { 1475 return false; 1476 } 1477 SIPServerTransaction sst = (SIPServerTransaction) other; 1478 return this.getBranch().equalsIgnoreCase(sst.getBranch()); 1479 } 1480 1481 /* 1482 * (non-Javadoc) 1483 * 1484 * @see gov.nist.javax.sip.stack.SIPTransaction#getDialog() 1485 */ getDialog()1486 public Dialog getDialog() { 1487 1488 return this.dialog; 1489 } 1490 1491 /* 1492 * (non-Javadoc) 1493 * 1494 * @see gov.nist.javax.sip.stack.SIPTransaction#setDialog(gov.nist.javax.sip.stack.SIPDialog, 1495 * gov.nist.javax.sip.message.SIPMessage) 1496 */ setDialog(SIPDialog sipDialog, String dialogId)1497 public void setDialog(SIPDialog sipDialog, String dialogId) { 1498 if (sipStack.isLoggingEnabled()) 1499 sipStack.getStackLogger().logDebug("setDialog " + this + " dialog = " + sipDialog); 1500 this.dialog = sipDialog; 1501 if (dialogId != null) 1502 this.dialog.setAssigned(); 1503 if (this.retransmissionAlertEnabled && this.retransmissionAlertTimerTask != null) { 1504 this.retransmissionAlertTimerTask.cancel(); 1505 if (this.retransmissionAlertTimerTask.dialogId != null) { 1506 sipStack.retransmissionAlertTransactions 1507 .remove(this.retransmissionAlertTimerTask.dialogId); 1508 } 1509 this.retransmissionAlertTimerTask = null; 1510 } 1511 1512 this.retransmissionAlertEnabled = false; 1513 1514 } 1515 1516 /* 1517 * (non-Javadoc) 1518 * 1519 * @see javax.sip.Transaction#terminate() 1520 */ terminate()1521 public void terminate() throws ObjectInUseException { 1522 this.setState(TransactionState.TERMINATED); 1523 if (this.retransmissionAlertTimerTask != null) { 1524 this.retransmissionAlertTimerTask.cancel(); 1525 if (retransmissionAlertTimerTask.dialogId != null) { 1526 this.sipStack.retransmissionAlertTransactions 1527 .remove(retransmissionAlertTimerTask.dialogId); 1528 } 1529 this.retransmissionAlertTimerTask = null; 1530 1531 } 1532 1533 } 1534 sendReliableProvisionalResponse(Response relResponse)1535 protected void sendReliableProvisionalResponse(Response relResponse) throws SipException { 1536 1537 /* 1538 * After the first reliable provisional response for a request has been acknowledged, the 1539 * UAS MAY send additional reliable provisional responses. The UAS MUST NOT send a second 1540 * reliable provisional response until the first is acknowledged. 1541 */ 1542 if (this.pendingReliableResponse != null) { 1543 throw new SipException("Unacknowledged response"); 1544 1545 } else 1546 this.pendingReliableResponse = (SIPResponse) relResponse; 1547 /* 1548 * In addition, it MUST contain a Require header field containing the option tag 100rel, 1549 * and MUST include an RSeq header field. 1550 */ 1551 RSeq rseq = (RSeq) relResponse.getHeader(RSeqHeader.NAME); 1552 if (relResponse.getHeader(RSeqHeader.NAME) == null) { 1553 rseq = new RSeq(); 1554 relResponse.setHeader(rseq); 1555 } 1556 1557 try { 1558 this.rseqNumber++; 1559 rseq.setSeqNumber(this.rseqNumber); 1560 1561 // start the timer task which will retransmit the reliable response 1562 // until the PRACK is received 1563 this.lastResponse = (SIPResponse) relResponse; 1564 if ( this.getDialog() != null ) { 1565 boolean acquired = this.provisionalResponseSem.tryAcquire(1, TimeUnit.SECONDS); 1566 if (!acquired) { 1567 throw new SipException("Unacknowledged response"); 1568 } 1569 } 1570 this.sendMessage((SIPMessage) relResponse); 1571 this.provisionalResponseTask = new ProvisionalResponseTask(); 1572 this.sipStack.getTimer().schedule(provisionalResponseTask, 0, 1573 SIPTransactionStack.BASE_TIMER_INTERVAL); 1574 1575 1576 } catch (Exception ex) { 1577 InternalErrorHandler.handleException(ex); 1578 } 1579 1580 } 1581 getReliableProvisionalResponse()1582 public SIPResponse getReliableProvisionalResponse() { 1583 1584 return this.pendingReliableResponse; 1585 } 1586 1587 /** 1588 * Cancel the retransmit timer for the provisional response task. 1589 * 1590 * @return true if the tx has seen the prack for the first time and false otherwise. 1591 * 1592 */ prackRecieved()1593 public boolean prackRecieved() { 1594 1595 if (this.pendingReliableResponse == null) 1596 return false; 1597 if(provisionalResponseTask != null) 1598 this.provisionalResponseTask.cancel(); 1599 this.pendingReliableResponse = null; 1600 this.provisionalResponseSem.release(); 1601 return true; 1602 } 1603 1604 /* 1605 * (non-Javadoc) 1606 * 1607 * @see javax.sip.ServerTransaction#enableRetransmissionAlerts() 1608 */ 1609 enableRetransmissionAlerts()1610 public void enableRetransmissionAlerts() throws SipException { 1611 if (this.getDialog() != null) 1612 throw new SipException("Dialog associated with tx"); 1613 1614 else if (!this.getMethod().equals(Request.INVITE)) 1615 throw new SipException("Request Method must be INVITE"); 1616 1617 this.retransmissionAlertEnabled = true; 1618 1619 } 1620 isRetransmissionAlertEnabled()1621 public boolean isRetransmissionAlertEnabled() { 1622 return this.retransmissionAlertEnabled; 1623 } 1624 1625 /** 1626 * Disable retransmission Alerts and cancel associated timers. 1627 * 1628 */ disableRetransmissionAlerts()1629 public void disableRetransmissionAlerts() { 1630 if (this.retransmissionAlertTimerTask != null && this.retransmissionAlertEnabled) { 1631 this.retransmissionAlertTimerTask.cancel(); 1632 this.retransmissionAlertEnabled = false; 1633 1634 String dialogId = this.retransmissionAlertTimerTask.dialogId; 1635 if (dialogId != null) { 1636 sipStack.retransmissionAlertTransactions.remove(dialogId); 1637 } 1638 this.retransmissionAlertTimerTask = null; 1639 } 1640 } 1641 1642 /** 1643 * This is book-keeping for retransmission filter management. 1644 */ setAckSeen()1645 public void setAckSeen() { 1646 this.isAckSeen = true; 1647 } 1648 1649 /** 1650 * This is book-keeping for retransmission filter management. 1651 */ ackSeen()1652 public boolean ackSeen() { 1653 return this.isAckSeen; 1654 } 1655 setMapped(boolean b)1656 public void setMapped(boolean b) { 1657 this.isMapped = true; 1658 1659 } 1660 setPendingSubscribe(SIPClientTransaction pendingSubscribeClientTx)1661 public void setPendingSubscribe(SIPClientTransaction pendingSubscribeClientTx) { 1662 this.pendingSubscribeTransaction = pendingSubscribeClientTx; 1663 1664 } 1665 releaseSem()1666 public void releaseSem() { 1667 if (this.pendingSubscribeTransaction != null) { 1668 /* 1669 * When a notify is being processed we take a lock on the subscribe to avoid racing 1670 * with the OK of the subscribe. 1671 */ 1672 pendingSubscribeTransaction.releaseSem(); 1673 } else if (this.inviteTransaction != null && this.getMethod().equals(Request.CANCEL)) { 1674 /* 1675 * When a CANCEL is being processed we take a nested lock on the associated INVITE 1676 * server tx. 1677 */ 1678 this.inviteTransaction.releaseSem(); 1679 } 1680 super.releaseSem(); 1681 } 1682 1683 /** 1684 * The INVITE Server Transaction corresponding to a CANCEL Server Transaction. 1685 * 1686 * @param st -- the invite server tx corresponding to the cancel server transaction. 1687 */ setInviteTransaction(SIPServerTransaction st)1688 public void setInviteTransaction(SIPServerTransaction st) { 1689 this.inviteTransaction = st; 1690 1691 } 1692 1693 /** 1694 * TODO -- this method has to be added to the api. 1695 * 1696 * @return 1697 */ getCanceledInviteTransaction()1698 public SIPServerTransaction getCanceledInviteTransaction() { 1699 return this.inviteTransaction; 1700 } 1701 scheduleAckRemoval()1702 public void scheduleAckRemoval() throws IllegalStateException { 1703 if (this.getMethod() == null || !this.getMethod().equals(Request.ACK)) { 1704 throw new IllegalStateException("Method is null[" + (getMethod() == null) 1705 + "] or method is not ACK[" + this.getMethod() + "]"); 1706 } 1707 1708 this.startTransactionTimer(); 1709 } 1710 1711 } 1712