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.javax.sip.SIPConstants; 30import gov.nist.javax.sip.SipProviderImpl; 31import gov.nist.javax.sip.header.CallID; 32import gov.nist.javax.sip.header.Event; 33import gov.nist.javax.sip.header.From; 34import gov.nist.javax.sip.header.To; 35import gov.nist.javax.sip.header.Via; 36import gov.nist.javax.sip.header.ViaList; 37import gov.nist.javax.sip.message.SIPMessage; 38import gov.nist.javax.sip.message.SIPRequest; 39import gov.nist.javax.sip.message.SIPResponse; 40 41import java.io.IOException; 42import java.net.InetAddress; 43import java.util.Collections; 44import java.util.HashSet; 45import java.util.Iterator; 46import java.util.Set; 47import java.util.concurrent.Semaphore; 48import java.util.concurrent.TimeUnit; 49import java.util.concurrent.atomic.AtomicBoolean; 50 51import javax.net.ssl.SSLPeerUnverifiedException; 52import javax.sip.Dialog; 53import javax.sip.IOExceptionEvent; 54import javax.sip.ServerTransaction; 55import javax.sip.TransactionState; 56import javax.sip.message.Request; 57import javax.sip.message.Response; 58 59/* 60 * Modifications for TLS Support added by Daniel J. Martinez Manzano 61 * <dani@dif.um.es> Bug fixes by Jeroen van Bemmel (JvB) and others. 62 */ 63 64/** 65 * Abstract class to support both client and server transactions. Provides an 66 * encapsulation of a message channel, handles timer events, and creation of the 67 * Via header for a message. 68 * 69 * @author Jeff Keyser 70 * @author M. Ranganathan 71 * 72 * 73 * @version 1.2 $Revision: 1.71 $ $Date: 2009/11/29 04:31:29 $ 74 */ 75public abstract class SIPTransaction extends MessageChannel implements 76 javax.sip.Transaction, gov.nist.javax.sip.TransactionExt { 77 78 protected boolean toListener; // Flag to indicate that the listener gets 79 80 // to see the event. 81 82 protected int BASE_TIMER_INTERVAL = SIPTransactionStack.BASE_TIMER_INTERVAL; 83 /** 84 * 5 sec Maximum duration a message will remain in the network 85 */ 86 protected int T4 = 5000 / BASE_TIMER_INTERVAL; 87 88 /** 89 * The maximum retransmit interval for non-INVITE requests and INVITE 90 * responses 91 */ 92 protected int T2 = 4000 / BASE_TIMER_INTERVAL; 93 protected int TIMER_I = T4; 94 95 protected int TIMER_K = T4; 96 97 protected int TIMER_D = 32000 / BASE_TIMER_INTERVAL; 98 99 // protected static final int TIMER_C = 3 * 60 * 1000 / BASE_TIMER_INTERVAL; 100 101 /** 102 * One timer tick. 103 */ 104 protected static final int T1 = 1; 105 106 /** 107 * INVITE request retransmit interval, for UDP only 108 */ 109 protected static final int TIMER_A = 1; 110 111 /** 112 * INVITE transaction timeout timer 113 */ 114 protected static final int TIMER_B = 64; 115 116 protected static final int TIMER_J = 64; 117 118 protected static final int TIMER_F = 64; 119 120 protected static final int TIMER_H = 64; 121 122 // Proposed feature for next release. 123 protected transient Object applicationData; 124 125 protected SIPResponse lastResponse; 126 127 // private SIPDialog dialog; 128 129 protected boolean isMapped; 130 131 private Semaphore semaphore; 132 133 protected boolean isSemaphoreAquired; 134 135 // protected boolean eventPending; // indicate that an event is pending 136 // here. 137 138 protected String transactionId; // Transaction Id. 139 140 // Audit tag used by the SIP Stack audit 141 public long auditTag = 0; 142 143 /** 144 * Initialized but no state assigned. 145 */ 146 public static final TransactionState INITIAL_STATE = null; 147 148 /** 149 * Trying state. 150 */ 151 public static final TransactionState TRYING_STATE = TransactionState.TRYING; 152 153 /** 154 * CALLING State. 155 */ 156 public static final TransactionState CALLING_STATE = TransactionState.CALLING; 157 158 /** 159 * Proceeding state. 160 */ 161 public static final TransactionState PROCEEDING_STATE = TransactionState.PROCEEDING; 162 163 /** 164 * Completed state. 165 */ 166 public static final TransactionState COMPLETED_STATE = TransactionState.COMPLETED; 167 168 /** 169 * Confirmed state. 170 */ 171 public static final TransactionState CONFIRMED_STATE = TransactionState.CONFIRMED; 172 173 /** 174 * Terminated state. 175 */ 176 public static final TransactionState TERMINATED_STATE = TransactionState.TERMINATED; 177 178 /** 179 * Maximum number of ticks between retransmissions. 180 */ 181 protected static final int MAXIMUM_RETRANSMISSION_TICK_COUNT = 8; 182 183 // Parent stack for this transaction 184 protected transient SIPTransactionStack sipStack; 185 186 // Original request that is being handled by this transaction 187 protected SIPRequest originalRequest; 188 189 // Underlying channel being used to send messages for this transaction 190 private transient MessageChannel encapsulatedChannel; 191 192 // Port of peer 193 protected int peerPort; 194 195 // Address of peer 196 protected InetAddress peerInetAddress; 197 198 // Address of peer as a string 199 protected String peerAddress; 200 201 // Protocol of peer 202 protected String peerProtocol; 203 204 // @@@ hagai - NAT changes 205 // Source port extracted from peer packet 206 protected int peerPacketSourcePort; 207 208 protected InetAddress peerPacketSourceAddress; 209 210 protected AtomicBoolean transactionTimerStarted = new AtomicBoolean(false); 211 212 // Transaction branch ID 213 private String branch; 214 215 // Method of the Request used to create the transaction. 216 private String method; 217 218 // Sequence number of request used to create the transaction 219 private long cSeq; 220 221 // Current transaction state 222 private TransactionState currentState; 223 224 // Number of ticks the retransmission timer was set to last 225 private transient int retransmissionTimerLastTickCount; 226 227 // Number of ticks before the message is retransmitted 228 private transient int retransmissionTimerTicksLeft; 229 230 // Number of ticks before the transaction times out 231 protected int timeoutTimerTicksLeft; 232 233 // List of event listeners for this transaction 234 private transient Set<SIPTransactionEventListener> eventListeners; 235 236 // Hang on to these - we clear out the request URI after 237 // transaction goes to final state. Pointers to these are kept around 238 // for transaction matching as long as the transaction is in 239 // the transaction table. 240 protected From from; 241 242 protected To to; 243 244 protected Event event; 245 246 protected CallID callId; 247 248 // Back ptr to the JAIN layer. 249 // private Object wrapper; 250 251 // Counter for caching of connections. 252 // Connection lingers for collectionTime 253 // after the Transaction goes to terminated state. 254 protected int collectionTime; 255 256 protected String toTag; 257 258 protected String fromTag; 259 260 private boolean terminatedEventDelivered; 261 262 public String getBranchId() { 263 return this.branch; 264 } 265 266 /** 267 * The linger timer is used to remove the transaction from the transaction 268 * table after it goes into terminated state. This allows connection caching 269 * and also takes care of race conditins. 270 * 271 * 272 */ 273 class LingerTimer extends SIPStackTimerTask { 274 275 public LingerTimer() { 276 SIPTransaction sipTransaction = SIPTransaction.this; 277 if (sipStack.isLoggingEnabled()) { 278 sipStack.getStackLogger().logDebug("LingerTimer : " 279 + sipTransaction.getTransactionId()); 280 } 281 282 } 283 284 protected void runTask() { 285 SIPTransaction transaction = SIPTransaction.this; 286 // release the connection associated with this transaction. 287 SIPTransactionStack sipStack = transaction.getSIPStack(); 288 289 if (sipStack.isLoggingEnabled()) { 290 sipStack.getStackLogger().logDebug("LingerTimer: run() : " 291 + getTransactionId()); 292 } 293 294 if (transaction instanceof SIPClientTransaction) { 295 sipStack.removeTransaction(transaction); 296 transaction.close(); 297 298 } else if (transaction instanceof ServerTransaction) { 299 // Remove it from the set 300 if (sipStack.isLoggingEnabled()) 301 sipStack.getStackLogger().logDebug("removing" + transaction); 302 sipStack.removeTransaction(transaction); 303 if ((!sipStack.cacheServerConnections) 304 && --transaction.encapsulatedChannel.useCount <= 0) { 305 // Close the encapsulated socket if stack is configured 306 transaction.close(); 307 } else { 308 if (sipStack.isLoggingEnabled() 309 && (!sipStack.cacheServerConnections) 310 && transaction.isReliable()) { 311 int useCount = transaction.encapsulatedChannel.useCount; 312 sipStack.getStackLogger().logDebug("Use Count = " + useCount); 313 } 314 } 315 } 316 317 } 318 } 319 320 /** 321 * Transaction constructor. 322 * 323 * @param newParentStack 324 * Parent stack for this transaction. 325 * @param newEncapsulatedChannel 326 * Underlying channel for this transaction. 327 */ 328 protected SIPTransaction(SIPTransactionStack newParentStack, 329 MessageChannel newEncapsulatedChannel) { 330 331 sipStack = newParentStack; 332 this.semaphore = new Semaphore(1,true); 333 334 encapsulatedChannel = newEncapsulatedChannel; 335 // Record this to check if the address has changed before sending 336 // message to avoid possible race condition. 337 this.peerPort = newEncapsulatedChannel.getPeerPort(); 338 this.peerAddress = newEncapsulatedChannel.getPeerAddress(); 339 this.peerInetAddress = newEncapsulatedChannel.getPeerInetAddress(); 340 // @@@ hagai 341 this.peerPacketSourcePort = newEncapsulatedChannel 342 .getPeerPacketSourcePort(); 343 this.peerPacketSourceAddress = newEncapsulatedChannel 344 .getPeerPacketSourceAddress(); 345 this.peerProtocol = newEncapsulatedChannel.getPeerProtocol(); 346 if (this.isReliable()) { 347 encapsulatedChannel.useCount++; 348 if (sipStack.isLoggingEnabled()) 349 sipStack.getStackLogger() 350 .logDebug("use count for encapsulated channel" 351 + this 352 + " " 353 + encapsulatedChannel.useCount ); 354 } 355 356 this.currentState = null; 357 358 disableRetransmissionTimer(); 359 disableTimeoutTimer(); 360 eventListeners = Collections.synchronizedSet(new HashSet<SIPTransactionEventListener>()); 361 362 // Always add the parent stack as a listener 363 // of this transaction 364 addEventListener(newParentStack); 365 366 } 367 368 /** 369 * Sets the request message that this transaction handles. 370 * 371 * @param newOriginalRequest 372 * Request being handled. 373 */ 374 public void setOriginalRequest(SIPRequest newOriginalRequest) { 375 376 // Branch value of topmost Via header 377 String newBranch; 378 379 if (this.originalRequest != null 380 && (!this.originalRequest.getTransactionId().equals( 381 newOriginalRequest.getTransactionId()))) { 382 sipStack.removeTransactionHash(this); 383 } 384 // This will be cleared later. 385 386 this.originalRequest = newOriginalRequest; 387 388 // just cache the control information so the 389 // original request can be released later. 390 this.method = newOriginalRequest.getMethod(); 391 this.from = (From) newOriginalRequest.getFrom(); 392 this.to = (To) newOriginalRequest.getTo(); 393 // Save these to avoid concurrent modification exceptions! 394 this.toTag = this.to.getTag(); 395 this.fromTag = this.from.getTag(); 396 this.callId = (CallID) newOriginalRequest.getCallId(); 397 this.cSeq = newOriginalRequest.getCSeq().getSeqNumber(); 398 this.event = (Event) newOriginalRequest.getHeader("Event"); 399 this.transactionId = newOriginalRequest.getTransactionId(); 400 401 originalRequest.setTransaction(this); 402 403 // If the message has an explicit branch value set, 404 newBranch = ((Via) newOriginalRequest.getViaHeaders().getFirst()) 405 .getBranch(); 406 if (newBranch != null) { 407 if (sipStack.isLoggingEnabled()) 408 sipStack.getStackLogger().logDebug("Setting Branch id : " + newBranch); 409 410 // Override the default branch with the one 411 // set by the message 412 setBranch(newBranch); 413 414 } else { 415 if (sipStack.isLoggingEnabled()) 416 sipStack.getStackLogger().logDebug("Branch id is null - compute TID!" 417 + newOriginalRequest.encode()); 418 setBranch(newOriginalRequest.getTransactionId()); 419 } 420 } 421 422 /** 423 * Gets the request being handled by this transaction. 424 * 425 * @return -- the original Request associated with this transaction. 426 */ 427 public SIPRequest getOriginalRequest() { 428 return originalRequest; 429 } 430 431 /** 432 * Get the original request but cast to a Request structure. 433 * 434 * @return the request that generated this transaction. 435 */ 436 public Request getRequest() { 437 return (Request) originalRequest; 438 } 439 440 /** 441 * Returns a flag stating whether this transaction is for an INVITE request 442 * or not. 443 * 444 * @return -- true if this is an INVITE request, false if not. 445 */ 446 public final boolean isInviteTransaction() { 447 return getMethod().equals(Request.INVITE); 448 } 449 450 /** 451 * Return true if the transaction corresponds to a CANCEL message. 452 * 453 * @return -- true if the transaciton is a CANCEL transaction. 454 */ 455 public final boolean isCancelTransaction() { 456 return getMethod().equals(Request.CANCEL); 457 } 458 459 /** 460 * Return a flag that states if this is a BYE transaction. 461 * 462 * @return true if the transaciton is a BYE transaction. 463 */ 464 public final boolean isByeTransaction() { 465 return getMethod().equals(Request.BYE); 466 } 467 468 /** 469 * Returns the message channel used for transmitting/receiving messages for 470 * this transaction. Made public in support of JAIN dual transaction model. 471 * 472 * @return Encapsulated MessageChannel. 473 * 474 */ 475 public MessageChannel getMessageChannel() { 476 return encapsulatedChannel; 477 } 478 479 /** 480 * Sets the Via header branch parameter used to identify this transaction. 481 * 482 * @param newBranch 483 * New string used as the branch for this transaction. 484 */ 485 public final void setBranch(String newBranch) { 486 branch = newBranch; 487 } 488 489 /** 490 * Gets the current setting for the branch parameter of this transaction. 491 * 492 * @return Branch parameter for this transaction. 493 */ 494 public final String getBranch() { 495 if (this.branch == null) { 496 this.branch = getOriginalRequest().getTopmostVia().getBranch(); 497 } 498 return branch; 499 } 500 501 /** 502 * Get the method of the request used to create this transaction. 503 * 504 * @return the method of the request for the transaction. 505 */ 506 public final String getMethod() { 507 return this.method; 508 } 509 510 /** 511 * Get the Sequence number of the request used to create the transaction. 512 * 513 * @return the cseq of the request used to create the transaction. 514 */ 515 public final long getCSeq() { 516 return this.cSeq; 517 } 518 519 /** 520 * Changes the state of this transaction. 521 * 522 * @param newState 523 * New state of this transaction. 524 */ 525 public void setState(TransactionState newState) { 526 // PATCH submitted by sribeyron 527 if (currentState == TransactionState.COMPLETED) { 528 if (newState != TransactionState.TERMINATED 529 && newState != TransactionState.CONFIRMED) 530 newState = TransactionState.COMPLETED; 531 } 532 if (currentState == TransactionState.CONFIRMED) { 533 if (newState != TransactionState.TERMINATED) 534 newState = TransactionState.CONFIRMED; 535 } 536 if (currentState != TransactionState.TERMINATED) 537 currentState = newState; 538 else 539 newState = currentState; 540 // END OF PATCH 541 if (sipStack.isLoggingEnabled()) { 542 sipStack.getStackLogger().logDebug("Transaction:setState " + newState 543 + " " + this + " branchID = " + this.getBranch() 544 + " isClient = " + (this instanceof SIPClientTransaction)); 545 sipStack.getStackLogger().logStackTrace(); 546 } 547 } 548 549 /** 550 * Gets the current state of this transaction. 551 * 552 * @return Current state of this transaction. 553 */ 554 public TransactionState getState() { 555 return this.currentState; 556 } 557 558 /** 559 * Enables retransmission timer events for this transaction to begin in one 560 * tick. 561 */ 562 protected final void enableRetransmissionTimer() { 563 enableRetransmissionTimer(1); 564 } 565 566 /** 567 * Enables retransmission timer events for this transaction to begin after 568 * the number of ticks passed to this routine. 569 * 570 * @param tickCount 571 * Number of ticks before the next retransmission timer event 572 * occurs. 573 */ 574 protected final void enableRetransmissionTimer(int tickCount) { 575 // For INVITE Client transactions, double interval each time 576 if (isInviteTransaction() && (this instanceof SIPClientTransaction)) { 577 retransmissionTimerTicksLeft = tickCount; 578 } else { 579 // non-INVITE transactions and 3xx-6xx responses are capped at T2 580 retransmissionTimerTicksLeft = Math.min(tickCount, 581 MAXIMUM_RETRANSMISSION_TICK_COUNT); 582 } 583 retransmissionTimerLastTickCount = retransmissionTimerTicksLeft; 584 } 585 586 /** 587 * Turns off retransmission events for this transaction. 588 */ 589 protected final void disableRetransmissionTimer() { 590 retransmissionTimerTicksLeft = -1; 591 } 592 593 /** 594 * Enables a timeout event to occur for this transaction after the number of 595 * ticks passed to this method. 596 * 597 * @param tickCount 598 * Number of ticks before this transaction times out. 599 */ 600 protected final void enableTimeoutTimer(int tickCount) { 601 if (sipStack.isLoggingEnabled()) 602 sipStack.getStackLogger().logDebug("enableTimeoutTimer " + this 603 + " tickCount " + tickCount + " currentTickCount = " 604 + timeoutTimerTicksLeft); 605 606 timeoutTimerTicksLeft = tickCount; 607 } 608 609 /** 610 * Disabled the timeout timer. 611 */ 612 protected final void disableTimeoutTimer() { 613 timeoutTimerTicksLeft = -1; 614 } 615 616 /** 617 * Fired after each timer tick. Checks the retransmission and timeout timers 618 * of this transaction, and fired these events if necessary. 619 */ 620 final void fireTimer() { 621 // If the timeout timer is enabled, 622 623 if (timeoutTimerTicksLeft != -1) { 624 // Count down the timer, and if it has run out, 625 if (--timeoutTimerTicksLeft == 0) { 626 // Fire the timeout timer 627 fireTimeoutTimer(); 628 } 629 } 630 631 // If the retransmission timer is enabled, 632 if (retransmissionTimerTicksLeft != -1) { 633 // Count down the timer, and if it has run out, 634 if (--retransmissionTimerTicksLeft == 0) { 635 // Enable this timer to fire again after 636 // twice the original time 637 enableRetransmissionTimer(retransmissionTimerLastTickCount * 2); 638 // Fire the timeout timer 639 fireRetransmissionTimer(); 640 } 641 } 642 } 643 644 /** 645 * Tests if this transaction has terminated. 646 * 647 * @return Trus if this transaction is terminated, false if not. 648 */ 649 public final boolean isTerminated() { 650 return getState() == TERMINATED_STATE; 651 } 652 653 public String getHost() { 654 return encapsulatedChannel.getHost(); 655 } 656 657 public String getKey() { 658 return encapsulatedChannel.getKey(); 659 } 660 661 public int getPort() { 662 return encapsulatedChannel.getPort(); 663 } 664 665 public SIPTransactionStack getSIPStack() { 666 return (SIPTransactionStack) sipStack; 667 } 668 669 public String getPeerAddress() { 670 return this.peerAddress; 671 } 672 673 public int getPeerPort() { 674 return this.peerPort; 675 } 676 677 // @@@ hagai 678 public int getPeerPacketSourcePort() { 679 return this.peerPacketSourcePort; 680 } 681 682 public InetAddress getPeerPacketSourceAddress() { 683 return this.peerPacketSourceAddress; 684 } 685 686 protected InetAddress getPeerInetAddress() { 687 return this.peerInetAddress; 688 } 689 690 protected String getPeerProtocol() { 691 return this.peerProtocol; 692 } 693 694 public String getTransport() { 695 return encapsulatedChannel.getTransport(); 696 } 697 698 public boolean isReliable() { 699 return encapsulatedChannel.isReliable(); 700 } 701 702 /** 703 * Returns the Via header for this channel. Gets the Via header of the 704 * underlying message channel, and adds a branch parameter to it for this 705 * transaction. 706 */ 707 public Via getViaHeader() { 708 // Via header of the encapulated channel 709 Via channelViaHeader; 710 711 // Add the branch parameter to the underlying 712 // channel's Via header 713 channelViaHeader = super.getViaHeader(); 714 try { 715 channelViaHeader.setBranch(branch); 716 } catch (java.text.ParseException ex) { 717 } 718 return channelViaHeader; 719 720 } 721 722 /** 723 * Process the message through the transaction and sends it to the SIP peer. 724 * 725 * @param messageToSend 726 * Message to send to the SIP peer. 727 */ 728 public void sendMessage(SIPMessage messageToSend) throws IOException { 729 // Use the peer address, port and transport 730 // that was specified when the transaction was 731 // created. Bug was noted by Bruce Evangelder 732 // soleo communications. 733 try { 734 encapsulatedChannel.sendMessage(messageToSend, 735 this.peerInetAddress, this.peerPort); 736 } finally { 737 this.startTransactionTimer(); 738 } 739 } 740 741 /** 742 * Parse the byte array as a message, process it through the transaction, 743 * and send it to the SIP peer. This is just a placeholder method -- calling 744 * it will result in an IO exception. 745 * 746 * @param messageBytes 747 * Bytes of the message to send. 748 * @param receiverAddress 749 * Address of the target peer. 750 * @param receiverPort 751 * Network port of the target peer. 752 * 753 * @throws IOException 754 * If called. 755 */ 756 protected void sendMessage(byte[] messageBytes, 757 InetAddress receiverAddress, int receiverPort, boolean retry) 758 throws IOException { 759 throw new IOException( 760 "Cannot send unparsed message through Transaction Channel!"); 761 } 762 763 /** 764 * Adds a new event listener to this transaction. 765 * 766 * @param newListener 767 * Listener to add. 768 */ 769 public void addEventListener(SIPTransactionEventListener newListener) { 770 eventListeners.add(newListener); 771 } 772 773 /** 774 * Removed an event listener from this transaction. 775 * 776 * @param oldListener 777 * Listener to remove. 778 */ 779 public void removeEventListener(SIPTransactionEventListener oldListener) { 780 eventListeners.remove(oldListener); 781 } 782 783 /** 784 * Creates a SIPTransactionErrorEvent and sends it to all of the listeners 785 * of this transaction. This method also flags the transaction as 786 * terminated. 787 * 788 * @param errorEventID 789 * ID of the error to raise. 790 */ 791 protected void raiseErrorEvent(int errorEventID) { 792 793 // Error event to send to all listeners 794 SIPTransactionErrorEvent newErrorEvent; 795 // Iterator through the list of listeners 796 Iterator<SIPTransactionEventListener> listenerIterator; 797 // Next listener in the list 798 SIPTransactionEventListener nextListener; 799 800 // Create the error event 801 newErrorEvent = new SIPTransactionErrorEvent(this, errorEventID); 802 803 // Loop through all listeners of this transaction 804 synchronized (eventListeners) { 805 listenerIterator = eventListeners.iterator(); 806 while (listenerIterator.hasNext()) { 807 // Send the event to the next listener 808 nextListener = (SIPTransactionEventListener) listenerIterator 809 .next(); 810 nextListener.transactionErrorEvent(newErrorEvent); 811 } 812 } 813 // Clear the event listeners after propagating the error. 814 // Retransmit notifications are just an alert to the 815 // application (they are not an error). 816 if (errorEventID != SIPTransactionErrorEvent.TIMEOUT_RETRANSMIT) { 817 eventListeners.clear(); 818 819 // Errors always terminate a transaction 820 this.setState(TransactionState.TERMINATED); 821 822 if (this instanceof SIPServerTransaction && this.isByeTransaction() 823 && this.getDialog() != null) 824 ((SIPDialog) this.getDialog()) 825 .setState(SIPDialog.TERMINATED_STATE); 826 } 827 } 828 829 /** 830 * A shortcut way of telling if we are a server transaction. 831 */ 832 protected boolean isServerTransaction() { 833 return this instanceof SIPServerTransaction; 834 } 835 836 /** 837 * Gets the dialog object of this Transaction object. This object returns 838 * null if no dialog exists. A dialog only exists for a transaction when a 839 * session is setup between a User Agent Client and a User Agent Server, 840 * either by a 1xx Provisional Response for an early dialog or a 200OK 841 * Response for a committed dialog. 842 * 843 * @return the Dialog Object of this Transaction object. 844 * @see Dialog 845 */ 846 public abstract Dialog getDialog(); 847 848 /** 849 * set the dialog object. 850 * 851 * @param sipDialog -- 852 * the dialog to set. 853 * @param dialogId -- 854 * the dialog id ot associate with the dialog.s 855 */ 856 public abstract void setDialog(SIPDialog sipDialog, String dialogId); 857 858 /** 859 * Returns the current value of the retransmit timer in milliseconds used to 860 * retransmit messages over unreliable transports. 861 * 862 * @return the integer value of the retransmit timer in milliseconds. 863 */ 864 public int getRetransmitTimer() { 865 return SIPTransactionStack.BASE_TIMER_INTERVAL; 866 } 867 868 /** 869 * Get the host to assign for an outgoing Request via header. 870 */ 871 public String getViaHost() { 872 return this.getViaHeader().getHost(); 873 874 } 875 876 /** 877 * Get the last response. This is used internally by the implementation. 878 * Dont rely on it. 879 * 880 * @return the last response received (for client transactions) or sent (for 881 * server transactions). 882 */ 883 public SIPResponse getLastResponse() { 884 return this.lastResponse; 885 } 886 887 /** 888 * Get the JAIN interface response 889 */ 890 public Response getResponse() { 891 return (Response) this.lastResponse; 892 } 893 894 /** 895 * Get the transaction Id. 896 */ 897 public String getTransactionId() { 898 return this.transactionId; 899 } 900 901 /** 902 * Hashcode method for fast hashtable lookup. 903 */ 904 public int hashCode() { 905 if (this.transactionId == null) 906 return -1; 907 else 908 return this.transactionId.hashCode(); 909 } 910 911 /** 912 * Get the port to assign for the via header of an outgoing message. 913 */ 914 public int getViaPort() { 915 return this.getViaHeader().getPort(); 916 } 917 918 /** 919 * A method that can be used to test if an incoming request belongs to this 920 * transction. This does not take the transaction state into account when 921 * doing the check otherwise it is identical to isMessagePartOfTransaction. 922 * This is useful for checking if a CANCEL belongs to this transaction. 923 * 924 * @param requestToTest 925 * is the request to test. 926 * @return true if the the request belongs to the transaction. 927 * 928 */ 929 public boolean doesCancelMatchTransaction(SIPRequest requestToTest) { 930 931 // List of Via headers in the message to test 932 ViaList viaHeaders; 933 // Topmost Via header in the list 934 Via topViaHeader; 935 // Branch code in the topmost Via header 936 String messageBranch; 937 // Flags whether the select message is part of this transaction 938 boolean transactionMatches; 939 940 transactionMatches = false; 941 942 if (this.getOriginalRequest() == null 943 || this.getOriginalRequest().getMethod().equals(Request.CANCEL)) 944 return false; 945 // Get the topmost Via header and its branch parameter 946 viaHeaders = requestToTest.getViaHeaders(); 947 if (viaHeaders != null) { 948 949 topViaHeader = (Via) viaHeaders.getFirst(); 950 messageBranch = topViaHeader.getBranch(); 951 if (messageBranch != null) { 952 953 // If the branch parameter exists but 954 // does not start with the magic cookie, 955 if (!messageBranch.toLowerCase().startsWith(SIPConstants.BRANCH_MAGIC_COOKIE_LOWER_CASE)) { 956 957 // Flags this as old 958 // (RFC2543-compatible) client 959 // version 960 messageBranch = null; 961 962 } 963 964 } 965 966 // If a new branch parameter exists, 967 if (messageBranch != null && this.getBranch() != null) { 968 969 // If the branch equals the branch in 970 // this message, 971 if (getBranch().equalsIgnoreCase(messageBranch) 972 && topViaHeader.getSentBy().equals( 973 ((Via) getOriginalRequest().getViaHeaders() 974 .getFirst()).getSentBy())) { 975 transactionMatches = true; 976 if (sipStack.isLoggingEnabled()) 977 sipStack.getStackLogger().logDebug("returning true"); 978 } 979 980 } else { 981 // If this is an RFC2543-compliant message, 982 // If RequestURI, To tag, From tag, 983 // CallID, CSeq number, and top Via 984 // headers are the same, 985 if (sipStack.isLoggingEnabled()) 986 sipStack.getStackLogger().logDebug("testing against " 987 + getOriginalRequest()); 988 989 if (getOriginalRequest().getRequestURI().equals( 990 requestToTest.getRequestURI()) 991 && getOriginalRequest().getTo().equals( 992 requestToTest.getTo()) 993 && getOriginalRequest().getFrom().equals( 994 requestToTest.getFrom()) 995 && getOriginalRequest().getCallId().getCallId().equals( 996 requestToTest.getCallId().getCallId()) 997 && getOriginalRequest().getCSeq().getSeqNumber() == requestToTest 998 .getCSeq().getSeqNumber() 999 && topViaHeader.equals(getOriginalRequest() 1000 .getViaHeaders().getFirst())) { 1001 1002 transactionMatches = true; 1003 } 1004 1005 } 1006 1007 } 1008 1009 // JvB: Need to pass the CANCEL to the listener! Retransmitted INVITEs 1010 // set it to false 1011 if (transactionMatches) { 1012 this.setPassToListener(); 1013 } 1014 return transactionMatches; 1015 } 1016 1017 /** 1018 * Sets the value of the retransmit timer to the newly supplied timer value. 1019 * The retransmit timer is expressed in milliseconds and its default value 1020 * is 500ms. This method allows the application to change the transaction 1021 * retransmit behavior for different networks. Take the gateway proxy as an 1022 * example. The internal intranet is likely to be reatively uncongested and 1023 * the endpoints will be relatively close. The external network is the 1024 * general Internet. This functionality allows different retransmit times 1025 * for either side. 1026 * 1027 * @param retransmitTimer - 1028 * the new integer value of the retransmit timer in milliseconds. 1029 */ 1030 public void setRetransmitTimer(int retransmitTimer) { 1031 1032 if (retransmitTimer <= 0) 1033 throw new IllegalArgumentException( 1034 "Retransmit timer must be positive!"); 1035 if (this.transactionTimerStarted.get()) 1036 throw new IllegalStateException( 1037 "Transaction timer is already started"); 1038 BASE_TIMER_INTERVAL = retransmitTimer; 1039 T4 = 5000 / BASE_TIMER_INTERVAL; 1040 1041 T2 = 4000 / BASE_TIMER_INTERVAL; 1042 TIMER_I = T4; 1043 1044 TIMER_K = T4; 1045 1046 TIMER_D = 32000 / BASE_TIMER_INTERVAL; 1047 1048 } 1049 1050 /** 1051 * Close the encapsulated channel. 1052 */ 1053 public void close() { 1054 this.encapsulatedChannel.close(); 1055 if (sipStack.isLoggingEnabled()) 1056 sipStack.getStackLogger().logDebug("Closing " + this.encapsulatedChannel); 1057 1058 } 1059 1060 public boolean isSecure() { 1061 return encapsulatedChannel.isSecure(); 1062 } 1063 1064 public MessageProcessor getMessageProcessor() { 1065 return this.encapsulatedChannel.getMessageProcessor(); 1066 } 1067 1068 /** 1069 * Set the application data pointer. This is un-interpreted by the stack. 1070 * This is provided as a conveniant way of keeping book-keeping data for 1071 * applications. Note that null clears the application data pointer 1072 * (releases it). 1073 * 1074 * @param applicationData -- 1075 * application data pointer to set. null clears the applicationd 1076 * data pointer. 1077 * 1078 */ 1079 1080 public void setApplicationData(Object applicationData) { 1081 this.applicationData = applicationData; 1082 } 1083 1084 /** 1085 * Get the application data associated with this transaction. 1086 * 1087 * @return stored application data. 1088 */ 1089 public Object getApplicationData() { 1090 return this.applicationData; 1091 } 1092 1093 /** 1094 * Set the encapsuated channel. The peer inet address and port are set equal 1095 * to the message channel. 1096 */ 1097 public void setEncapsulatedChannel(MessageChannel messageChannel) { 1098 this.encapsulatedChannel = messageChannel; 1099 this.peerInetAddress = messageChannel.getPeerInetAddress(); 1100 this.peerPort = messageChannel.getPeerPort(); 1101 } 1102 1103 /** 1104 * Return the SipProvider for which the transaction is assigned. 1105 * 1106 * @return the SipProvider for the transaction. 1107 */ 1108 public SipProviderImpl getSipProvider() { 1109 1110 return this.getMessageProcessor().getListeningPoint().getProvider(); 1111 } 1112 1113 /** 1114 * Raise an IO Exception event - this is used for reporting asynchronous IO 1115 * Exceptions that are attributable to this transaction. 1116 * 1117 */ 1118 public void raiseIOExceptionEvent() { 1119 setState(TransactionState.TERMINATED); 1120 String host = getPeerAddress(); 1121 int port = getPeerPort(); 1122 String transport = getTransport(); 1123 IOExceptionEvent exceptionEvent = new IOExceptionEvent(this, host, 1124 port, transport); 1125 getSipProvider().handleEvent(exceptionEvent, this); 1126 } 1127 1128 /** 1129 * A given tx can process only a single outstanding event at a time. This 1130 * semaphore gaurds re-entrancy to the transaction. 1131 * 1132 */ 1133 public boolean acquireSem() { 1134 boolean retval = false; 1135 try { 1136 if (sipStack.getStackLogger().isLoggingEnabled()) { 1137 sipStack.getStackLogger().logDebug("acquireSem [[[[" + this); 1138 sipStack.getStackLogger().logStackTrace(); 1139 } 1140 retval = this.semaphore.tryAcquire(1000, TimeUnit.MILLISECONDS); 1141 if ( sipStack.isLoggingEnabled()) 1142 sipStack.getStackLogger().logDebug( 1143 "acquireSem() returning : " + retval); 1144 return retval; 1145 } catch (Exception ex) { 1146 sipStack.getStackLogger().logError("Unexpected exception acquiring sem", 1147 ex); 1148 InternalErrorHandler.handleException(ex); 1149 return false; 1150 } finally { 1151 this.isSemaphoreAquired = retval; 1152 } 1153 1154 } 1155 1156 /** 1157 * Release the transaction semaphore. 1158 * 1159 */ 1160 public void releaseSem() { 1161 try { 1162 1163 this.toListener = false; 1164 this.semRelease(); 1165 1166 } catch (Exception ex) { 1167 sipStack.getStackLogger().logError("Unexpected exception releasing sem", 1168 ex); 1169 1170 } 1171 1172 } 1173 1174 protected void semRelease() { 1175 try { 1176 if (sipStack.isLoggingEnabled()) { 1177 sipStack.getStackLogger().logDebug("semRelease ]]]]" + this); 1178 sipStack.getStackLogger().logStackTrace(); 1179 } 1180 this.isSemaphoreAquired = false; 1181 this.semaphore.release(); 1182 1183 } catch (Exception ex) { 1184 sipStack.getStackLogger().logError("Unexpected exception releasing sem", 1185 ex); 1186 1187 } 1188 } 1189 1190 /** 1191 * Set true to pass the request up to the listener. False otherwise. 1192 * 1193 */ 1194 1195 public boolean passToListener() { 1196 return toListener; 1197 } 1198 1199 /** 1200 * Set the passToListener flag to true. 1201 */ 1202 public void setPassToListener() { 1203 if (sipStack.isLoggingEnabled()) { 1204 sipStack.getStackLogger().logDebug("setPassToListener()"); 1205 } 1206 this.toListener = true; 1207 1208 } 1209 1210 /** 1211 * Flag to test if the terminated event is delivered. 1212 * 1213 * @return 1214 */ 1215 protected synchronized boolean testAndSetTransactionTerminatedEvent() { 1216 boolean retval = !this.terminatedEventDelivered; 1217 this.terminatedEventDelivered = true; 1218 return retval; 1219 } 1220 1221 public String getCipherSuite() throws UnsupportedOperationException { 1222 if (this.getMessageChannel() instanceof TLSMessageChannel ) { 1223 if ( ((TLSMessageChannel) this.getMessageChannel()).getHandshakeCompletedListener() == null ) 1224 return null; 1225 else if ( ((TLSMessageChannel) this.getMessageChannel()).getHandshakeCompletedListener().getHandshakeCompletedEvent() == null) 1226 return null; 1227 else return ((TLSMessageChannel) this.getMessageChannel()).getHandshakeCompletedListener().getHandshakeCompletedEvent().getCipherSuite(); 1228 } else throw new UnsupportedOperationException("Not a TLS channel"); 1229 1230 } 1231 1232 1233 public java.security.cert.Certificate[] getLocalCertificates() throws UnsupportedOperationException { 1234 if (this.getMessageChannel() instanceof TLSMessageChannel ) { 1235 if ( ((TLSMessageChannel) this.getMessageChannel()).getHandshakeCompletedListener() == null ) 1236 return null; 1237 else if ( ((TLSMessageChannel) this.getMessageChannel()).getHandshakeCompletedListener().getHandshakeCompletedEvent() == null) 1238 return null; 1239 else return ((TLSMessageChannel) this.getMessageChannel()).getHandshakeCompletedListener().getHandshakeCompletedEvent().getLocalCertificates(); 1240 } else throw new UnsupportedOperationException("Not a TLS channel"); 1241 } 1242 1243 1244 public java.security.cert.Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException { 1245 if (this.getMessageChannel() instanceof TLSMessageChannel ) { 1246 if ( ((TLSMessageChannel) this.getMessageChannel()).getHandshakeCompletedListener() == null ) 1247 return null; 1248 else if ( ((TLSMessageChannel) this.getMessageChannel()).getHandshakeCompletedListener().getHandshakeCompletedEvent() == null) 1249 return null; 1250 else return ((TLSMessageChannel) this.getMessageChannel()).getHandshakeCompletedListener().getHandshakeCompletedEvent().getPeerCertificates(); 1251 } else throw new UnsupportedOperationException("Not a TLS channel"); 1252 1253 } 1254 1255 1256 /** 1257 * Start the timer that runs the transaction state machine. 1258 * 1259 */ 1260 1261 protected abstract void startTransactionTimer(); 1262 1263 /** 1264 * Tests a message to see if it is part of this transaction. 1265 * 1266 * @return True if the message is part of this transaction, false if not. 1267 */ 1268 public abstract boolean isMessagePartOfTransaction(SIPMessage messageToTest); 1269 1270 /** 1271 * This method is called when this transaction's retransmission timer has 1272 * fired. 1273 */ 1274 protected abstract void fireRetransmissionTimer(); 1275 1276 /** 1277 * This method is called when this transaction's timeout timer has fired. 1278 */ 1279 protected abstract void fireTimeoutTimer(); 1280 1281} 1282